# scriptparser
**Repository Path**: shenguz/scriptparser
## Basic Information
- **Project Name**: scriptparser
- **Description**: 一款在.net环境下,解析执行Javascript的开源组件。
- **Primary Language**: C#
- **License**: MIT
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 90
- **Forks**: 19
- **Created**: 2020-12-01
- **Last Updated**: 2025-06-20
## Categories & Tags
**Categories**: utils
**Tags**: None
## README
# 简介
ScriptParser是一款可以在.net的环境下,解析执行`javascript`语法的开源组件,其主要定位如下:
1. 在.net环境下,动态执行部分业务逻辑,以实现在不修改原生程序的基础上,动态的扩展一些功能。
2. 提供一套可以用`javascript`来控制逻辑的模板机制,以便在.net环境下,可以动态生成文本(比如:某些情况下,代替.aspx生成html页面等)
## 支持语法
目前`ECMAScript 5`的语法,除了`with语法、Property`等个别语法之外,其它的都有支持。
支持的预设类型:`Object、Array、Number、String、Date`,以及部分预设方法:`parseInt、parseFloat、stringify、eval`等。
因为模板的需要,支持几个`ECMAScript 6`的语法:for...of...表达式,箭头表达式,`let、const`语法。
支持对`DataTable`的访问。
支持开发者根据需要,添加需要在`javascript`中调用的类、对象、方法及属性。
## 其它
1. 由于`javascript`对象的特殊性,所有需要传入到`javascript`中去访问的对象、方法,都需要直接或间接的转化成继承于IScriptObject的对象。
> .net中的对象,如果没有特别处理,会使用`ScriptType`、`ScriptNativeObject`、`ScriptNativeArray`、`ScriptNativeFunction`进行包装后,供`javascript`的语句中调用。
2. 该组件的解析和执行过程,使用内存结构来模拟线程栈的操作,以避免解析到恶意嵌套的语法,引发堆栈溢出,从而导致进程中止。
3. 该组件在执行时,有支持暂停执行/继续执行的功能,在批量执行脚本时,可以支持类似于纤程的功能。
> `ScriptParser`在`Execute`时,可以调用`ScriptContext.Pause`方法,此时,会保存上下文环境并退出`Execute`方法,下次可以调用`ScriptContext.Continue`恢复执行。在批量执行脚本时,可以对一些执行时间比较长的方法,执行异步操作(比如:网络语法等),并调用`ScriptContext.Pause`中断执行,在异步回调中,再调用`ScriptContext.Continue`恢复。
# Demo
请参见ScriptTest项目
## JavaScript的解析过程
````C#
//创建执行上下文:ScriptContext
ScriptContext context = new ScriptContext();
//添加变量,以及方法映射
context.AddValue("inc", 100);
//获取执行结果
object result = ScriptUtils.ExecuteScript(context, "var i = 0; return i + inc;");
````
## 模板的解析过程
````C#
//创建执行上下文:ScriptContext
ScriptContext context = new ScriptContext();
//添加变量,以及方法映射
context.AddValue("status", 2);
string template = @"
状态码:
<@switch code="status">
<@case code="1">@{"正常"}@case>
<@case code="2">@{"冻结"}@case>
<@default>其它状态@default>
@switch>
";
string result = ScriptUtils.ExecuteTemplate(context, template);
````
# 模板解析标签
## 标签简介
1. ScriptParser的模板解析过程,是先将带特殊标签的模板,转化成一段可执行的`javascript`脚本,再执行脚本,生成最终的结果。所以,ScriptParser的模板支持在模板中编写`javascript`语法
2. 标签格式:除了写入单值的语法(`@{***}`)之外,所有的逻辑标签都是以`<@***>`开始,以及`@***>`结束
3. 逻辑标签,代表一个`javascript`的关键字(如:if/for/while/switch等),关键字的括号部分(如:`if(***)`、`for(***)`等)的内容,基本上都写在code属性中。只有两个例外:`do{...}while(***)`、`else if(***){}`
## if...else if...else...
1. if/else语法,if/else if/else节点之间,除了空格和换行之外,不能有其它内容
2. else if节点表示为:`<@else if="***">@else>`
````html
<@if code="status==1">
状态:@{"正常"}
@if>
<@else if="statue==2">
状态:@{"冻结"}
@else>
<@else>
@{"其它状态"}
@else>
````
## for(...; ...; ...)
````html
<@for code="var i = 0; i < 100; i++">
计数:@{i}
@for>
````
## for...in
````html
<@for code="var index in list">
元素:@{list[index]}
@for>
````
## for...of
````html
<@for code="var item of list">
元素:@{item}
@for>
````
## while
````html
<@while code="i++ < 10">
i的值:@{i}
@while>
````
## do...while
节点结构:` `
````html
<@do while="i++ < 10">
i的值:@{i}
@do>
````
## switch...case...default...
1. case和default的节点,在生成`javascript`语法时,会自动在最后加上`break;`
2. 如果需要不需要加`break;`,可以将case节点编写为:`<@case code="***" />`,或者:`<@case code="***" ignoreBreak="true">@case>`
````html
<@switch code="status">
<@case code="1">
状态:@{"正常"}
@case>
<@case code="2">
状态:@{"冻结"}
@case>
<@default>
@{"其它状态"}
@default>
@switch>
````
## break/continue
````html
<@while code="true">
<@if code="i<0">
<@break />
@if>
<@else if="i>0">
<@continue />
@else>
<@else>
<@line code="i--" />
@else>
@while>
````
## try...catch...finally...
````html
<@try>
正常执行
@try>
<@catch code="e">
错误信息:@{e}
@catch>
<@finally>
最终执行
@finally>
````
## @{***}
代表将内部的表达式输出来(注意:内部必须是一个表达式)
````html
@{i > 0 ? i : "异常状态"}
````
## `<@line />`
单行语法,在生成`javascript`语法时,会在最后自动加上“;”
````html
<@line code="i++" />
````
## `<@code>...@code>`(`<@>...@>`)
自由语法,可以在节点之间,任意编写`javascript`脚本,这些脚本在生成`javascript`时,会被原封不动的保留下来
````html
<@code>
var i = 0;
var list = [];
for (var i = 0; i < 100; i++) {
list.push(i);
}
@code>
````
## `<@nowrap>...@nowrap>`
不换行节点,这个节点之间的文本(不包括通过`javascript`脚本动态输出的脚本)换行符不输出
````html
<@nowrap>
状态:
<@if code='status==0'>未开始@if>
<@else if='status==1'>已进场@else>
<@else if='status==2'>已出场@else>
<@else>异常离场@else>
@nowrap>
````
# QQ交流群
1. 792893075[](https://jq.qq.com/?_wv=1027&k=DeLntNXe)