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);
}
ScriptContext
Pre-registered Plugins in 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(),
});
}
}
SharpPagesFeature
Pre-registered Plugins in 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 })
/each
Which 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 |