#Script Code
Code statements is an alternative language dialect which allows us to invert #Script
from "Template Mode"
where all text is emitted as-is with only Template Expressions {{ ... }}
being evaluated and changed it to "Code Mode" where all code
statements are evaluated as JS Expression statements.
This is akin to Razor's statement blocks which inverts Razor's mode of emitting text to treating text inside statement blocks as code, e.g:
@{
var a = 1;
var b = 2;
}
Basic Calc
a + b = @(a + b)
The equivalent in #Script
using code
language blocks:
```code
var a = 1
var b = 2
```
Basic Calc
a + b = {{a + b}}
Which is useful in reducing boilerplate when you need to evaluate code blocks with 2+ or more lines without the distracting boilerplate of wrapping
each expression within a {{ ... }}
Template Expression.
Syntax
Effectively you can think of Code Statements as #Script
without template expressions since the code within a Template Expressions {{ ... }}
are both evaluated as JS Expressions.
One difference between them is that each line in a code statement block must be a complete expression, any expressions that spans multiple lines need to be wrapped withing Template Expressions where-by the source code for both Template and Code blocks remain exactly the same, e.g:
The difference between them is that whitespace and indentation in code statement blocks are inert whereas they're emitted in Templates so these examples are equivalent:
```code
#if test.isEven()
`${test} is even`
else
`${test} is odd`
/if
```
Whilst code statements can effectively be thought of as "#Script without Template Expressions", you can view the LINQ examples in each to see how they compare:
Executing #Script Code in .NET
All #Script
languages are executed within a ScriptContext
that defines all functionality available to them, i.e:
var context = new ScriptContext {
Args = { ... }, // Global Arguments available to all Scripts, Pages, Partials, etc
ScriptMethods = { ... }, // Additional Methods
ScriptBlocks = { ... }, // Additional Script Blocks
FilterTransformers = { .. }, // Additional Stream Transformers
PageFormats = { ... }, // Additional Text Document Formats
Plugins = { ... }, // Encapsulated Features e.g. Markdown, Protected or ServiceStack Features
ScanTypes = { ... }, // Auto register Methods, Blocks and Code Page Types
ScanAssemblies = { ... }, // Auto register all Methods, Blocks and Code Page Types in Assembly
}.Init();
Where you can customize the pure sandboxed ScriptContext your Script is executed within by extending it with:
But to render code
statements you'd use RenderCode
instead of RenderScript
, e.g:
// render code statements
var output = context.RenderCode("now |> dateFormat('HH:mm:ss')");
// async
var output = await context.RenderCodeAsync("now |> dateFormat('HH:mm:ss')");
These APIs match the high-level APIs for rendering normal #Script
:
var output = context.RenderScript("{{ now |> dateFormat('HH:mm:ss') }}");
var output = await context.RenderScriptAsync("{{ now |> dateFormat('HH:mm:ss') }}");
Finer grained control
The high-level APIs above wraps the finer-grained functionality below which works by rendering a SharpPage
configured with the code
language in a PageResult
that all languages use:
var context = new ScriptContext().Init();
var dynamicPage = context.CodeSharpPage("now |> dateFormat('HH:mm:ss')"); // render code
//var dynamicPage = context.SharpScriptPage("{{ now |> dateFormat('HH:mm:ss') }}"); // render #Script
var output = new PageResult(dynamicPage).RenderScript();
//async
var output = await new PageResult(dynamicPage).RenderScriptAsync();
If you need the return value instead you can access it from:
var result = new PageResult(dynamicPage).EvaluateResult(out var returnValue)
? ScriptLanguage.UnwrapValue(returnValue)
: null;
If your script source code doesn't change you can re-use dynamicPage
which lets you re-evaluate your source code's cached AST.
Evaluating Script Results
If you instead wanted to access Script return values instead of the code rendered output you would use the EvaluateCode()
APIs:
var result = context.EvaluateCode("return ( 1 + 1 )"); //= 2
The generic overloads below utilizes ServiceStack's Auto Mapping utils to convert the return value into your preferred type, e.g:
double result = context.EvaluateCode<double>("return (1 + 1)"); //= 2.0
string result = context.EvaluateCode<string>("return (1 + 1)"); //= "2"
Which can also be used for more powerful conversions like converting an Object Dictionary into your preferred POCO:
var result = context.EvaluateCode<Customer>("`select * from customer where id=@id` |> dbSingle({id}) |>return"
, new ObjectDictionary {
["id"] = 1
});
Scripting .NET Types
All #Script
languages have the same access to Scripting .NET Types.
Code Scripts
The same functionality in Sharp Scripts is also available in #Script
Code, except instead of using the *.ss
file
extension for executing #Script
you'd use the *.sc
file extension which will allow you to use the
x and app dotnet tools to watch or run code
scripts:
$ x run code.sc
$ x watch code.sc
Watch code
scripts
Here's a quick demo showcasing the same functionality in Sharp Scripts
is also available in *.sc
scripts which provides instant feedback whilst you develop in real-time:
YouTube: youtu.be/TQPOZ0kVpw4