Script Plugins
Similar to using Plugins in ServiceStack to easily add functionality
to a ServiceStack AppHost, you can encapsulate a suite of functionality that can be easily added to extend a
ScriptContext with related functionality, e.g: You can add Markdown functionality to your scripts with:
var context = new ScriptContext {
Plugins = {
new MarkdownScriptPlugin {
RegisterPageFormat = false
}
}
}.Init();Which will register Markdown filter transformers, script method and script block with our ScriptContext:
public class MarkdownScriptPlugin : IScriptPlugin
{
public bool RegisterPageFormat { get; set; } = true;
public void Register(ScriptContext context)
{
if (RegisterPageFormat)
context.PageFormats.Add(new MarkdownPageFormat());
context.FilterTransformers["markdown"] = MarkdownPageFormat.TransformToHtml;
context.ScriptMethods.Add(new MarkdownScriptMethods());
context.ScriptBlocks.Add(new MarkdownScriptBlock());
}
}Creating Plugins
Plugin are simply classes that implement IScriptPlugin interface and its Register() method to extend the ScriptContext
with additional functionality we want to make available:
public interface IScriptPlugin
{
void Register(ScriptContext context);
}Plugins can implement the interfaces below if they need to run custom logic before and after plugins are registered:
// Run before plugins are loaded:
public interface IScriptPluginBefore
{
void BeforePluginsLoaded(ScriptContext context);
}
// Run after plugins are loaded:
public interface IScriptPluginAfter
{
void AfterPluginsLoaded(ScriptContext context);
}
Pre-registered Plugins in ScriptContext
Pre-registered plugins are useful when you want to easily remove a pre-registered suite of functionality, e.g:
var context = new ScriptContext {
//...
}
.RemovePlugins(x => x is DefaultScriptBlocks) // Remove default blocks
.RemovePlugins(x => x is HtmlScriptBlocks) // Remove all html blocks
.Init();DefaultScriptBlocks
The Default Script Blocks contain all the statement functionality in #Script which includes:
public class DefaultScriptBlocks : IScriptPlugin
{
public void Register(ScriptContext context)
{
context.ScriptBlocks.AddRange(new ScriptBlock[] {
new IfScriptBlock(),
new EachScriptBlock(),
new RawScriptBlock(),
new CaptureScriptBlock(),
new PartialScriptBlock(),
new WithScriptBlock(),
new NoopScriptBlock(),
new KeyValuesScriptBlock(),
new CsvScriptBlock(),
new FunctionScriptBlock(),
new WhileScriptBlock(),
});
}
}HtmlScriptBlocks
The purpose of the HTML Script Blocks is to pack a suite of generically useful functionality commonly used when generating html. All html blocks inherit the same functionality with blocks registered for the most popular HTML elements, currently:
public class HtmlScriptBlocks : IScriptPlugin
{
/// <summary>
/// Usages: {{#ul {each:items, class:'nav'} }} <li>{{it}}</li> {{/ul}}
/// </summary>
public void Register(ScriptContext context)
{
context.ScriptBlocks.AddRange(new ScriptBlock[] {
new ScriptUlBlock(),
new ScriptOlBlock(),
new ScriptLiBlock(),
new ScriptDivBlock(),
new ScriptPBlock(),
new ScriptFormBlock(),
new ScriptInputBlock(),
new ScriptSelectBlock(),
new ScriptOptionBlock(),
new ScriptTextAreaBlock(),
new ScriptButtonBlock(),
new ScriptTableBlock(),
new ScriptTrBlock(),
new ScriptTdBlock(),
new ScriptTHeadBlock(),
new ScriptTBodyBlock(),
new ScriptTFootBlock(),
new ScriptDlBlock(),
new ScriptDtBlock(),
new ScriptDdBlock(),
new ScriptSpanBlock(),
new ScriptABlock(),
new ScriptImgBlock(),
new ScriptEmBlock(),
new ScriptBBlock(),
new ScriptIBlock(),
new ScriptStrongBlock(),
new ScriptScriptBlock(),
new ScriptStyleBlock(),
new ScriptLinkBlock(),
new ScriptMetaBlock(),
});
}
}
Pre-registered Plugins in SharpPagesFeature
The SharpPagesFeature in ServiceStack.dll has access to more dependencies than ScriptContext and
is able to pre-register more functionality by default including:
ServiceStackScriptBlocks
Containing the {{#minifyjs}}{{/minifyjs}}, {{#minifycss}}{{/minifycss}} and {{#minifyhtml}}{{/minifyhtml}} for minifying
its contents:
public class ServiceStackScriptBlocks : IScriptPlugin
{
public void Register(ScriptContext context)
{
context.ScriptBlocks.AddRange(new ScriptBlock[] {
new MinifyJsScriptBlock(),
new MinifyCssScriptBlock(),
new MinifyHtmlScriptBlock(),
new SvgScriptBlock(),
});
}
}MarkdownScriptPlugin
Adds Markdown supports to #Script Pages by default:
public class MarkdownScriptPlugin : IScriptPlugin
{
public bool RegisterPageFormat { get; set; } = true;
public void Register(ScriptContext context)
{
if (RegisterPageFormat)
context.PageFormats.Add(new MarkdownPageFormat());
context.FilterTransformers["markdown"] = MarkdownPageFormat.TransformToHtml;
context.ScriptMethods.Add(new MarkdownScriptMethods());
context.ScriptBlocks.Add(new MarkdownScriptBlock());
}
}Added using:
Plugins.Add(new MarkdownScriptPlugin { RegisterPageFormat = false });Available Plugins
List of available plugins that's not pre-registered anywhere include:
ProtectedScriptBlocks
public class ProtectedScriptBlocks : IScriptPlugin
{
public void Register(ScriptContext context)
{
context.ScriptBlocks.AddRange(new ScriptBlock[] {
new EvalScriptBlock(), // evalScript has same functionality and is registered by default
});
}
}Although generally not required as evalTemplate script method registered by default has equivalent functionality.
GitHubPlugin
ServiceStack's available GitHub integration can be used in your #Script by adding GitHubPlugin to your ScriptContext or SharpPagesFeature:
new ScriptContext {
Plugins = { new GitHubPlugin() },
}.Init();This is enabled by default in the web and app dotnet tools so they can be used in #Script .ss scripts.
Checkout GitHubScripts.cs
for the full API available. Here's GitHub's Gist API example of creating gists in #Script:
githubGateway('GITHUB_GIST_TOKEN'.envVariable()) |> to => gateway
{{ gateway.githubCreateGist('Hello World Examples', {
'hello_world_ruby.txt': 'Run `ruby hello_world.rb` to print Hello World',
'hello_world_python.txt': 'Run `python hello_world.py` to print Hello World',
})
|> to => newGist }}
{ ...newGist, Files: null, Owner: null } |> textDump({ caption: 'new gist' })View Gist files and metadata example:
gateway.githubGist(gistId) |> to => gist
{ ...gist, Files: null, Owner: null } |> textDump({ caption: 'gist' })
`#### Gist Files`
#each file in gist.Files.Keys
gist.Files[file] |> textDump({ caption: file })
/eachWhich renders the following GitHub Flavored Markdown output:
| gist | |
|---|---|
| Node Id | MDQ6R2lzdDRjNWQ5NWVjNGIyNTk0YjRjZGQyMzg5ODdmZTdhMTVh |
| Git Pull Url | https://gist.github.com/4c5d95ec4b2594b4cdd238987fe7a15a.git |
| Git Push Url | https://gist.github.com/4c5d95ec4b2594b4cdd238987fe7a15a.git |
| Forks Url | https://api.github.com/gists/4c5d95ec4b2594b4cdd238987fe7a15a/forks |
| Commits Url | https://api.github.com/gists/4c5d95ec4b2594b4cdd238987fe7a15a/commits |
| Comments | 0 |
| Comments Url | https://api.github.com/gists/4c5d95ec4b2594b4cdd238987fe7a15a/comments |
| Truncated | False |
| Owner | |
| Id | 4c5d95ec4b2594b4cdd238987fe7a15a |
| Url | https://api.github.com/gists/4c5d95ec4b2594b4cdd238987fe7a15a |
| Html Url | https://gist.github.com/4c5d95ec4b2594b4cdd238987fe7a15a |
| Files | |
| Public | True |
| Created at | 2019-06-15 |
| Updated At | 2019-06-15 |
| Description | Hello World Examples |
| User Id |
Gist Files
| hello_world_python.txt | |
|---|---|
| Filename | hello_world_python.txt |
| Type | text/plain |
| Language | Text |
| Raw Url | https://gist.githubusercontent.com/gistlyn/.../hello_world_python.txt |
| Size | 48 |
| Truncated | False |
| Content | Run python hello_world.py to print Hello World |
| hello_world_ruby.txt | |
|---|---|
| Filename | hello_world_ruby.txt |
| Type | text/plain |
| Language | Text |
| Raw Url | https://gist.githubusercontent.com/gistlyn/.../hello_world_ruby.txt |
| Size | 46 |
| Truncated | False |
| Content | Run ruby hello_world.rb to print Hello World |