仓库目录结构
./grammar 语法文件
./ts 解析器源码
./ts/toAST 到 AST 的转换源码
-----decorated-nasl-ast 给 NASL 增加了一些必要的中间态字段定义
-----builtin-namespace 目前是内置函数定义
-----to-nasl-xxx 语法树到 AST 的初始转换
-----resolve-global-bindings 收集类型函数等的全局定义
-----resolve-local-bindings 处理逻辑局部的 name resolution
-----process-annotations 处理注解
./examples/unit ----- e2e 单测的 NASL 文件
----apps 整个应用的 e2e 的 NASL 文件
----enums 枚举的 e2e 的 NASL 文件
----structs 数据类型的 e2e 的 NASL 文件
----logics的 逻辑的 e2e 的 NASL 文件
./tests/e2e
---- logics e2e 单测的 .spec.ts 文件,远端不存储,每次测试重新生成
---- controlled e2e 单测的 控制组 nasl.json 文件
---- real e2e 单测的 实际 nasl.json 文件,远端不存储,每次测试重新生成
./tests/semantics 一些语义测试,会执行 toAST
./tests/unambiguous-grammar 大量语法测试,不执行 toAST,主要检测语法是否正确,语法树是否唯一
package.json 命令
- 编译语法和 ts 文件:
npm run build
- 运行所有测试文件:
npm run test-all
- 快速测试:
npm run test-parse
,会运行 ts/testParse.ts
文件,解析里面的 testCode 字符串,更换字符串内容即可测试
ts/index.ts
里面有个 parseToNaslJson
函数,接受字符串,产出 nasl JSON 的字符串,可作为接口调用。
gen-predicate
:一个过时的东西,之后会尽快替换掉。
测试用例摘取(特性和语法)
用例 1
namespace app {
namespace dataSources {
namespace defaultDS {
namespace entities {
entity LCAPUserDeptMapping() {
let userId: Integer;
let deptId: Integer;
}
}
}
}
}
using app::dataSources::defaultDS::entities; // 引入了 LCAPUserDeptMapping
// 这是一段注释
@(
description = "这是一段描述",
)
logic aiTest1(list: List<Integer>) => result {
let userDeptMapList: List<LCAPUserDeptMapping>
result = null
if (list.length == 0) {
result = null
} else {
result = ListSum(list) / list.length
}
}
用例 2
// 这是一段注释
@(
description = "这是一段描述",
)
logic aiTest1(list: List<Integer>) => result {
let userDeptMapList: List<app::dataSources::defaultDS::entities::LCAPUserDeptMapping> // 直接使用类型全称,硬编码支持
result = null
if (list.length == 0) {
result = null
} else {
result = ListSum(list) / list.length // 内置函数硬编码支持,调用优先解析到内置函数
}
end
}
用例 3
@(
description = "获取所有的角色名称",
)
logic LCAPGetRoleNameList(roleName: String) => result {
let search: List<app::structures::LCAPRole>
if (HasValue(search)) {
result = ListTransform(search, { item => item.name })
} else {
result = []: List<String>
}
result = ListTransform(result, { item => ToLower(item) })
if (HasValue(roleName)) {
if (Contains(result, ToLower(roleName))) {
Add(result, roleName);
} else {
}
} else {
}
ListDistinct(result)
}
用例 4
namespace app {
namespace enums {
@(description = '这不是一个有用的枚举')
enum MyEnumInt {
@(label = 'nmb')
case 0;
@(label = '2333')
case 1;
}
}
}
namespace WhatEverDoesNotMatter {
@(description = '这是一个垃圾枚举')
enum MyEnumStr {
@(label = '值J')
case J;
@(label = '值K')
case K;
}
}
using app::enums;
using WhatEverDoesNotMatter;
@(
transactional = false,
)
logic enumRef() {
let variable1: MyEnumInt;
let variable2;
let variable3;
let variable4;
let variable5;
let variable6;
let variable7;
variable1 = MyEnumInt::0
variable2 = MyEnumInt::1
variable3 = MyEnumStr::J
variable4 = MyEnumStr::K
variable5 = EnumItemToStructure(MyEnumStr::J)
variable6 = EnumItemToText(MyEnumInt::0)
end
}
用例 5
logic newComp() {
let variable1;
let variable2;
variable1 = app::structures::SS1 ( // 暂时用 () 不用 {},构造器会生成到 New + 连线
property1=null,
property2=111,
)
variable2 = app::dataSources::defaultDS::entities::Entity1 ( // 暂时用 () 不用 {},构造器会生成到 New + 连线
id=222,
createdTime=null,
updatedTime=null,
createdBy='fanzheng',
updatedBy='bushini',
property1='fanzheng1',
property2='bushini1',
)
end
}
用例 6
@(
description = '请输入数据结构描述'
)
struct SS2 {
let property1: Integer = 0;
let property2: app::structures::SS1;
}
struct SS1 {
let property1: app::structures::SS2;
let property2: Decimal = 0.1;
}
添加测试用例
e2e 用例
examples/unit/???/
文件夹下添加 nasl 文件
tests/e2e/???/controlled
文件夹下添加正确的 json 文件
ts/prepare-tests.ts
文件里添加测试用例名
npm run test-all
看效果
举例:
examples/unit/logics/asgn.nasl
tests/e2e/logics/controlled/asgn.json
ts/prepare-tests.ts
文件里的 logicUTNames
数组里添加 asgn
- 运行
注意,现在 NASL 各种 undefined
、null
、[]
在各个节点表现不同,很难弄一致,还有很多脏数据,除了手动控制用例外,还可以修改 ts/nasl-json-util.ts
里面的配置,跳过一些属性的对比。
解析器 parser 用例
写一个 .spec.ts
文件放到 tests/unambiguous-grammar/
文件夹下即可,文件格式直接参考其他用例
toAST 语义分析用例
写一个 .spec.ts
文件放到 tests/semantics/
文件夹下即可,文件格式直接参考其他用例。
报错
报错?2 周写的东西,报错是不存在的。语法有问题直接群里找开发者吧。