Skip to content

Latest commit

 

History

History
294 lines (261 loc) · 14.4 KB

File metadata and controls

294 lines (261 loc) · 14.4 KB

NASL 逻辑 - 基本知识

变量声明、表达式和运算

/**

  • 变量声明,只支持使用let关键字进行变量声明,需要指定变量类型
  • @example let a: Integer = 1;
  • @example let b: Decimal = 1.0;
  • @example let d: { a: String, b: Decimal, c: Integer } = { a: 'str', b: 0.0, c: 0 }; */

/**

  • 相等判定,采用'=='运算符进行判定
  • 对于Integer、Decimal、Boolean、String、Date、Time、DateTime类型,进行值比较;对于List、Map类型,进行引用比较
  • @example
  • str == 'abc' // 判断str是否等于'abc'
  • number == 123 // 判断number是否等于123
  • date == '2024-01-01' // 判断date是否等于'2024-01-01' */

/**

  • 基本数学运算
  • NASL支持的基本数学运算包括加法、减法、乘法、除法和取余运算
  • 加法:+,减法:-,乘法:*,除法:/,取余:%
  • 运算结果类型:
    • 对于加法、减法、乘法、取余,结果类型与操作数类型相同
    • 对于除法,结果类型为Decimal */

/**

  • 枚举类型定义和类型表示
  • @example
  • namespace app.enums {
  • export class OrderStatus extends BaseEnum {
  •   static readonly PENDING = new OrderStatus('PENDING', '待支付');
    
  •   static readonly PAID = new OrderStatus('PAID', '已支付');
    
  • }
  • export class ProductCategory extends BaseEnum {
  •   static readonly 0 = new ProductCategory(0, '电子产品');
    
  •   static readonly 1 = new ProductCategory(1, '服装');
    
  • }
  • export class ApprovalStatus extends BaseEnum {
  •   static readonly 0 = new ApprovalStatus(0, '待提交');
    
  •   static readonly 1 = new ApprovalStatus(1, '审批中');
    
  • }
  • // 0开头数字字符串枚举示例
  • export class TaskPriority extends BaseEnum {
  •   static readonly '001' = new TaskPriority('001', '高');
    
  •   static readonly '002' = new TaskPriority('002', '中');
    
  •   static readonly '003' = new TaskPriority('003', '低');
    
  • }
  • }
  • @attention 枚举项等号左边的键 "VALUE0" 与 new 的第1个参数值 "VALUE0" 必须相同
  • @attention 数字字符串的枚举项等号左边的键 "001" 与 new 的第1个参数值 "001" 必须相同,取值时用 ['001'] 的方式
  • @example let status: app.enums.OrderStatus = app.enums.OrderStatus['PENDING'];
  • @example let category: app.enums.ProductCategory = app.enums.ProductCategory[0];
  • @example let status: app.enums.ApprovalStatus = app.enums.ApprovalStatus[0]
  • @example let priority: app.enums.TaskPriority = app.enums.TaskPriority['001'] */ declare class BaseEnum<V extends String | Integer> {}

循环语句

/**

  • for...of 语句
  • 用于遍历列表中的元素,禁止使用for循环语句的其他形式。语法如下:
  • for (const [index, item] of ListEntries(list, start, end)) {}
  • 其中:
    • index: Long,当前索引
    • item: T,当前元素
  • @note [index, item] 为解构赋值,顺序不可颠倒
  • @note index和item可以替换为其他变量名,但不能用下划线(_)作为变量名
  • ListEntries 仅用于for...of循环,声明为: function ListEntries(list: List, start?: Long, end?: Long): List<[Long, T]>;
  • @param list: List,需要遍历的列表,必填
  • @param start: Long,开始索引,默认值 0
  • @param end: Long,结束索引,默认值 list.length
  • ListEntries([1, 2, 3]) => [[0, 1], [1, 2], [2, 3]]
  • ListEntries([1, 2, 3], 1, 2) => [[1, 2]]
  • @note ListEntries不在任何namespace下定义,可以直接使用
  • @note 遍历列表
  • @example for (const [index, item] of ListEntries(list, start, end)) {} // 遍历列表, 从start到end
  • @example for (const [index, item] of ListEntries(list, start)) {} // 遍历列表, 从start到列表末尾
  • @example for (const [index, item] of ListEntries(list)) {} // 遍历列表, 从0到列表末尾
  • @note 配合ListRange, 可实现特定范围的遍历功能
  • @example for (const [index, item] of ListEntries(nasl.util.ListRange(10))) {} // 遍历从0到9的整数
  • @example for (const [index, item] of ListEntries(nasl.util.ListRange(2, 5, 1))) {} // 遍历从2到4的整数
  • @note 配合ListRange的step参数,可以实现反向遍历
  • @example for (const [index, item] of ListEntries(nasl.util.ListRange(10, 0, -2))) {} // 遍历从10到1的偶数
  • @example for (const [index, item] of ListEntries(nasl.util.ListRange(nasl.util.Length(list_var)-1, -1, -1))) {} // 遍历列表反向的位置索引
  • @note 配合Split函数,可以实现按字符遍历字符串
  • @example for (const [index, item] of ListEntries(nasl.util.Split(str, ''))) {} // 按字符遍历字符串
  • @example for (const [index, item] of ListEntries(nasl.util.Split(str, ' '))) {} // 按单词遍历字符串
  • @note 错误示例
  • @example for (const [_, _] of ListEntries(list)) {} // 错误示例,使用了下划线作为变量名
  • @example for (const [, item] of ListEntries(list)) {} // 错误示例,索引必须要有变量名 */

/**

  • while语句
  • 用于循环执行一段代码,直到指定条件不满足。
  • @example while (condition) {} */

/**

  • 循环语句内关键字 break/continue
  • break: 终止循环
  • continue: 跳过当前循环,继续下一个循环
  • 可以在for...of和while语句中使用
  • @note for...of和while循环内,禁止使用return语句,请使用break语句跳出循环再返回 */

服务端获取当前用户(必须遵守)

禁止在服务端 Logic 中使用前端变量

  • 必须使用app.backend.variables.currentUser.userIdnasl.auth.getCurrentUser()
  • 禁止使用nasl.auth.userInfo(前端变量,服务端无法访问)
// ✅ 正确
if (nasl.util.HasValue(app.backend.variables.currentUser.userId)) {
    let userId = app.backend.variables.currentUser.userId;
}

// ❌ 错误
// let userName = nasl.auth.userInfo.UserName;

命名约定(必须遵守)

  • 在 for、ListTransform、ListFilter、ListSort、ListGroupBy、ORDER_BY 等回调或循环中,禁止使用 NASL 系统关键字作为参数名(如 role、element、event、length、list、map 等)。
  • 统一使用:单回调用 itemresultItem,多回调用 itemitem1item2,for...of 用 [index, item]

Http 相关类型

  • httpRequest 对象,可在逻辑中使用,用于获取当前请求的属性,例如:cookie、header、ip等
  • httpResponse 对象,可用于全局逻辑中,可返回header、cookie等
  • 低代码默认处理好了 http 的很多机制,这些是高级用法,需要 HTTP 特殊定制时才使用

扩展库的逻辑和数据结构的使用示例

扩展库

let nameObj: extensions.strUtils.structures.NameStructure;
nameObj = extensions.strUtils.logics.splitName('John Doe');

API 接口的使用示例

let queryResult: List<apis.someService.structures.QueryResult>;
queryResult = apis.someService.interfaces.queryPhoneNumbers('John Doe');

连接器的逻辑和数据结构的使用示例

let variable1: List<connectors.QQ_email_connector.structures.MailBody>;
variable1 = connectors.QQ_email_connector.connect('defaultConn').getEmail(10);
variable2 = connectors.QQ_email_connector.namespace2.someFunc(10, 'test');

提醒:更多扩展库、接口、连接器的定义和使用说明,需要调用【LoadKnowledge】工具,传入{ useBackendDependencies: true }加载【相关知识】

注意

  • 如果需求和技术设计中提到的扩展库、API 接口、连接器确实存在,请认真使用并实现相关功能;
  • 如果确实不存在,不要硬写,你也无法自行补充。简单模拟实现和返回即可,并在逻辑中注释说明情况。

服务端全局变量定义示例

$BackendVariable({ description: '服务端全局变量1' }) export let backendVariable1: String = '123';

服务端逻辑示例

// 每个逻辑的命名规则如下:[逻辑的用途名][引用的组件名][根据情况唯一标识(可选)]

$Logic({ title: '获取学生列表', description: '从数据库中获取学生列表', returnDescription: '学生列表分页结果', directory: 'student_management(学生管理)' }) export function loadStudent_eltable1( /** 页码 */ page: Integer, /** 每页条数 */ size: Integer, /** 排序字段 */ sort: String, /** 排序方向 */ order: String, /** 学生过滤条件 */ filter: app.dataSources.defaultDS.entities.Student, /** 学校名称过滤 */ filterSchoolName: String ): { /** 学生和学校关联列表 */ list: List<{ /** 学生信息 */ student: app.dataSources.defaultDS.entities.Student, /** 学校信息 */ school: app.dataSources.defaultDS.entities.School }>, /** 总条数 */ total: Integer } { $Return({ description: '学生列表分页结果', autoInferType: true }) let result; result = PAGINATE(FROM(app.dataSources.defaultDS.entities.StudentEntity, Student => $() .LEFT_JOIN(app.dataSources.defaultDS.entities.SchoolEntity, School => ON(Student.schoolId == School.id) .WHERE(LIKE(Student.name, filter.name) && Student.age == filter.age && LIKE(School.name == filterSchoolName) .SELECT({ student: Student, school: School, }) .ORDER_BY((resultItem) => [[resultItem[sort], order]]) )), page, size); return result; } $Logic({ title: '获取书籍作者列表', description: '获取书籍作者列表并排序', returnDescription: '书籍作者列表排序结果', directory: 'book_management(书籍管理)' }) export function getSortedAuthors( /** 书籍作者 Map(书名 -> 作者名) */ bookAuthorMap: Map ): List { $Return({ description: '书籍作者列表排序结果', autoInferType: true }) let authors: List; authors = nasl.util.MapValues(bookAuthorMap); authors = nasl.util.ListSort(authors, (item) => ({ by: item, asc: true })); return authors; } - In NASL language, the return type of the function can only be one type; - 不要写 async 和 Promise 类型,语言底层都是异步实现了; - tuple can be treated as a list; - Structure operations of data structures such as List/Map should use functions in nasl.util; - NASL language NOT SUPPORTS: - try-catch, raise, or exception handling;语言底层自动做了异常处理; - bitwise operation, such as `&`, `|`, `^`, `~`, `<<`, `>>` - Only template string syntax can be used for concatenation between variables and strings, it will automatically convert the variable to a string; - NASL language is a statically typed language, please convert type explicitly. - It is not allowed to use `Any` type in parameter or return type of user-defined functions, please specify the exact type. - DO NOT use `char` as a variable name, use `character` instead. - In NASL language, `==` is value comparison for basic types and string types, and reference comparison for other types. - NASL language is a statically typed language, use `nasl.util.Convert(value)` to convert basic types. - Consider the boundary case processing of the input when writing code to ensure the robustness of the code, such as empty lists, empty strings, empty Maps, etc. - Unless explicitly required to print, the results should be returned as return values. - 变量一般不用初始化,基础类型默认为 undefined,复合类型默认会 new。 - **Decimal 类型赋值**:所有需要 Decimal 类型的场景(变量初始化、对象字面量字段、列表元素添加、三元 fallback 等),整数字面量必须写成 `0.0` 而非 `0`,避免产生 `Decimal | Integer` 混合类型。✅ `let total: Decimal = 0.0` / `{ amount: 0.0 }` / `HasValue(x) ? x : 0.0` / `ListAdd(decimalList, 0.0)`,❌ `let total: Decimal = 0` / `{ amount: 0 }` / `HasValue(x) ? x : 0` - **禁止使用 union 类型**:函数参数、局部变量(`let`)、函数返回类型中均不得使用 `A | B | C` 形式的 union 类型,List 泛型参数同样禁止(`List` ❌)。可空字段统一改用可选字段语法 `field?: T`,适用于所有类型(`Integer | null` → `field?: Integer`,`DateTime | null` → `field?: DateTime`,不只是 String)。多实体场景应将对象拆分为多个独立字段(如 `typeADetail?: EntityA`、`typeBDetail?: EntityB`),各分支只赋值对应字段,而非用 union 类型汇聚到同一字段。 - 【特别注意】变量、参数、页面名、属性名等取名,不要与以下关键字冲突: - JS、TS 和 Java 的关键字,如 package, import, class, constructor 等等 - 禁止使用 char, current, event 作为变量名,这些是保留字。 - 实体名称不能与常用数据库的关键字冲突,如 select, where, join 等等 NASL 关键字请参考 nasl-book/K001-nasl--keywords.md 文件 - NASL Natural TS 中变量不是块级作用域,页面、逻辑、lambda 函数、for 循环的参数和变量请尽量区别开。如: function unwrapList(list1: List<{ student: app.structures.Student }>) { let item: app.structures.Student; // item 用于某在一种地方 let list2 = ListTransform(list1, (item2) => item2.student); // 用 item2 去区别 ... } - 在服务端逻辑中调用其他逻辑,必须要写 app.logics.xxx();在页面中调用页面逻辑,不要写 app.logics 前缀,如 viewLogic()。 - 【特别注意】逻辑的实现过程中,**尽量添加注释**,讲述你的实现思路,方便后续维护。 - httpRequest, httpResponse, currentUser 为服务端只读全局变量,不可修改,只可使用 - `currentUser` 的字段含义、与 `nasl.auth.getCurrentUser()` / 前端 `nasl.auth.userInfo` 的端侧区分见 nasl-book/K011-nasl--current-user-and-nasl-auth.md - **NASL 基础类型**:请参考 nasl-book/K002-nasl--types.md 文件 - **当前用户与 nasl.auth(服务端 currentUser / getCurrentUser)**:请参考 nasl-book/K011-nasl--current-user-and-nasl-auth.md 文件 - **NASL 逻辑 - 分页、实体方法和数据查询**:请参考 nasl-book/K005-backend-logic--paginate-entity-method-data-query.md 文件 - **NASL 逻辑 - 内置工具函数**:请参考 nasl-book/K006-backend-logic--utils.md 文件 - **NASL 自定义配置**:请参考 nasl-book/K011-nasl--configuration.md 文件