UNPKG

@lcap/nasl-parser

Version:

Take Nasl text to Nasl AST with the help of generalized parsing.

487 lines (486 loc) 19.3 kB
"use strict"; // @ts-nocheck var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.tryAddToNaslDataSource = void 0; const nasl = __importStar(require("./decorated-nasl-ast")); const asserts_1 = require("@lcap/nasl-concepts/asserts"); const common_util_1 = require("./common-util"); const process_annotations_1 = require("./process-annotations"); /** 已支持: * @Entity(...) 注解支持以下参数 * source = "defaultDS", * name = "person", * table = "sql_School", // 数据库表名,或者日后用 @table("sql_School") * description = "学校", // 实体描述 * origin = "ide", // 实体来源, * @createdTime, @createdTime(true), @createdTime() 前两种等价 * @updatedTime(false), 没实现 updatedTime=updatedTime(false) 这种语法 * @createdBy, * @updatedBy, 目前以上四个字段,有注解才会生成,不会默认生成 * @id, 自动生成 Id * 用 @Entity(...) 标记一个 struct 后,struct 的 @Column(...) 属性的注解只能是以下注解的组合 * @required * @primaryKey * @name * @label * @description * @type * @generationRule * @display * @rules * @sequence */ /** * 没实现的 column 注解 TODO: * relationNamespace * relationEntity * relationProperty * deleteRule */ const SOURCE = 'source'; const ENTITY = 'Entity'; const COLUMN = 'Column'; const supportedEntityAnnArgs = [SOURCE, 'name', 'table', 'description', 'origin', 'createdTime', 'updatedTime', 'createdBy', 'updatedBy', 'id']; // 后五个去掉也行,因为类似 id = @id 的语法还没实现 const supportedColumnAnnArgs = ['name', 'label', 'description', 'type', 'generationRule', 'display', 'rules', 'sequence', 'required', 'primaryKey']; // 后两个去掉也行,因为类似 required = @required 的语法还没实现 const isSpecificAnnArg = (name) => (arg) => arg.name === name; const isSpecificAnnArgVal = (name) => (arg) => (0, common_util_1.projectIdentifier)(arg.value.name) === name; // 几个特殊注解,不用 key = val(...) 而用 @val(...) 语法 const isCreatedTime = isSpecificAnnArgVal('createdTime'); const isUpdatedTime = isSpecificAnnArgVal('updatedTime'); const isCreatedBy = isSpecificAnnArgVal('createdBy'); const isUpdatedBy = isSpecificAnnArgVal('updatedBy'); const isId = isSpecificAnnArgVal('id'); const isRequired = isSpecificAnnArgVal('required'); const isPrimaryKey = isSpecificAnnArgVal('primaryKey'); const isColumnName = isSpecificAnnArg('name'); const isLabel = isSpecificAnnArg('label'); const isDescription = isSpecificAnnArg('description'); const isDatabaseTypeAnnotation = isSpecificAnnArg('type'); const isGenerationRule = isSpecificAnnArg('generationRule'); const isDisplay = isSpecificAnnArg('display'); const isRules = isSpecificAnnArg('rules'); const isSequence = isSpecificAnnArg('sequence'); const tryAddToNaslDataSource = (dss) => (ns) => { if (!(0, asserts_1.isStructure)(ns)) { return ns; } const anns = ns.annotations; if (anns) { anns.forEach((ann) => { // const nameSpace: string = isEmpty(ann.name.namespace) ? null : ann.name.namespace.join(NAMESPACE_SEP); if (ann.type === 'Builtin') { if (!isValidEntityAnn(ann)) { throw new Error('invalid entity annotation'); } const dsArg = ann.args.find(arg => arg.name === SOURCE); let targetDs = dss.find(ds => ds.name === (0, process_annotations_1.forceToString)(dsArg.val)); // DANGEROUS if (!targetDs) { targetDs = new nasl.DataSource({ name: (0, process_annotations_1.forceToString)(dsArg.val), // DANGEROUS description: (0, process_annotations_1.forceToString)(ann.args.find(arg => arg.name === 'description').val), // DANGEROUS entities: [], }); dss.push(targetDs); } addToSpecificNaslDataSource(ns, targetDs); } // if (ann.name.name === ENTITY) { // } }); } return ns; }; exports.tryAddToNaslDataSource = tryAddToNaslDataSource; function addToSpecificNaslDataSource(ns, ds) { const anns = ns.annotations; const dsAnn = anns.find(ann => ann.args.find(arg => arg.name === SOURCE)); const ne = new nasl.Entity({ name: (0, process_annotations_1.forceToString)(dsAnn.args.find(arg => arg.name === 'name').val), // DANGEROUS description: (0, process_annotations_1.forceToString)(dsAnn.args.find(arg => arg.name === 'description').val), // DANGEROUS tableName: (0, process_annotations_1.forceToString)(dsAnn.args.find(arg => arg.name === 'table').val), // DANGEROUS // @ts-ignore origin: dsAnn.args.find(arg => arg.name === 'origin') ? (0, process_annotations_1.forceToString)(dsAnn.args.find(arg => arg.name === 'origin').val) : 'ide', // DANGEROUS properties: ns.properties.map(toNaslDataEntity), }); // 几个特殊属性(注解) const maybeCtp = maybeCreatedTimeProp(dsAnn.args.find(isCreatedTime)); if (maybeCtp) { ne.properties.push(maybeCtp); } const maybeUtp = maybeUpdatedTimeProp(dsAnn.args.find(isUpdatedTime)); if (maybeUtp) { ne.properties.push(maybeUtp); } const maybeCbp = maybeCreatedByProp(dsAnn.args.find(isCreatedBy)); if (maybeCbp) { ne.properties.push(maybeCbp); } const maybeUbp = maybeUpdatedByProp(dsAnn.args.find(isUpdatedBy)); if (maybeUbp) { ne.properties.push(maybeUbp); } const maybeId = maybeIdProp(dsAnn.args.find(isId)); if (maybeId) { ne.properties.push(maybeId); } if (!ds.entities) { ds.entities = new Array(); } ds.entities.push(ne); } function processColumnAnnotation(nep, ann) { ann.args.forEach(arg => { if (isColumnName(arg)) { nep.columnName = (0, process_annotations_1.forceToString)(arg.val); } if (isLabel(arg)) { nep.label = (0, process_annotations_1.forceToString)(arg.val); } if (isDescription(arg)) { nep.description = (0, process_annotations_1.forceToString)(arg.val); } if (isGenerationRule(arg)) { if (arg.val) { if (['auto', 'autoIncrement', 'manual'].includes((0, process_annotations_1.forceToString)(arg.val))) { // @ts-ignore nep.generationRule = (0, process_annotations_1.forceToString)(arg.val); } else { throw new Error('invalid generationRule annotation argument'); } } else { nep.generationRule = 'auto'; } } if (isSequence(arg)) { nep.sequence = (0, process_annotations_1.forceToString)(arg.val); } if (isRequired(arg)) { nep.required = true; } if (isPrimaryKey(arg)) { nep.primaryKey = true; } if (isDatabaseTypeAnnotation(arg)) { nep.databaseTypeAnnotation = processAnnArgValForDatabaseTypeAnnotation(arg.val); if (isCustomAnnotation(arg.val) && (0, common_util_1.projectIdentifier)(arg.val.name) === 'decimal') { nep.rules.push(`scale(${arg.val.args[1].val})`); // decimal(31, 2), scale = 2 } } if (isDisplay(arg) && isMapLit(arg.val)) { nep.display = processAnnArgValForDisplay(arg.val); } if (isRules(arg)) { if (isMapLit(arg.val)) { nep.rules = processAnnArgValForRules(arg.val); } } }); } const toNaslDataEntity = (nsp) => { const normalizeColName = (input) => input.replace(/([A-Z])/g, '_$1').toLowerCase().replace(/^_/, ''); const nep = new nasl.EntityProperty({ name: nsp.name, typeAnnotation: nsp.typeAnnotation, defaultValue: nsp.defaultValue, columnName: normalizeColName(nsp.name), label: "", description: "", display: genDisplay(true, true, true, true), rules: [], generationRule: "manual", sequence: undefined, required: undefined, primaryKey: undefined, databaseTypeAnnotation: undefined }); const anns = nsp.annotations; anns.forEach(ann => { if (!isCustomAnnotation(ann)) { return; } if ((0, common_util_1.projectIdentifier)(ann.name) === COLUMN) { if (!isValidColumnAnn(ann)) { throw new Error('invalid column annotation'); } processColumnAnnotation(nep, ann); } }); return nep; }; // 如返回 "max(100)" function processAnnArgValForRules(aav) { if (isAnnotation(aav)) { return isCustomAnnotation(aav) ? [`${(0, common_util_1.projectIdentifier)(aav.name)}(${processAnnArgValForRules(aav.args[0].val)})`] : null; } else if (isMapLit(aav)) { return aav.entries.map(e => `${e.key}=${e.val}`); } else if (isArrayLit(aav)) { return aav.elems.flatMap(toString); } else { return [aav.val.toString()]; } } /** * 支持语法:@A@A(true) 或 @A(false) * 支持注解:@detail, @filter, @form, @table, * @detail 返回 "detail": true, * @filter(true) 返回 "detail": true, * @form(false) 返回 "form": false, */ function processAnnArgValForDisplay(aav) { if (isCustomAnnotation(aav)) { if (aav.args.length > 0) { return { [aav.name.name]: (0, process_annotations_1.forceToBoolean)(aav.args[0].val) }; } else { return { [aav.name.name]: true }; } } else if (isMapLit(aav)) { const res = {}; aav.entries.forEach(e => { if (isUnaryExpr(e.key.expr) && isStringLit(e.key.expr.expr) && isUnaryExpr(e.val.expr) && isStringLit(e.val.expr.expr)) { res[e.key.expr.expr.val] = e.key.expr.expr.val; } }); return res; } else { throw new Error('should not reach here in processAnnArgValForDisplay'); } } function processAnnArgValForDatabaseTypeAnnotation(aav) { if (isCustomAnnotation(aav)) { const nlc = (0, common_util_1.projectIdentifier)(aav.name).toLowerCase(); const numFirstArg = (0, process_annotations_1.forceToNumber)(aav.args[0].val); if (['varchar', 'char'].includes(nlc)) { // console.log('🐔', nlc, numFirstArg) const b = new nasl.DatabaseTypeAnnotation({ typeName: (0, common_util_1.projectIdentifier)(aav.name), // 这里使用 new Map() 会导致 toJSON 时丢失数据,所以改用普通对象 //@ts-ignore arguments: { 'length': numFirstArg.toString() }, }); // b.arguments.set() console.log(b.arguments); return b; } if (['int', 'tinyint', 'smallint', 'mediumint', 'bigint'].includes(nlc)) { return new nasl.DatabaseTypeAnnotation({ typeName: (0, common_util_1.projectIdentifier)(aav.name), //@ts-ignore arguments: { 'displayWidth': numFirstArg.toString() }, }); } if (['decimal'].includes(nlc)) { return new nasl.DatabaseTypeAnnotation({ typeName: (0, common_util_1.projectIdentifier)(aav.name), //@ts-ignore arguments: { 'precision': numFirstArg.toString() }, }); } if (['date'].includes(nlc)) { return new nasl.DatabaseTypeAnnotation({ typeName: (0, common_util_1.projectIdentifier)(aav.name), }); } if (['time'].includes(nlc)) { return new nasl.DatabaseTypeAnnotation({ typeName: (0, common_util_1.projectIdentifier)(aav.name), }); } if (['datetime', 'timestamp'].includes(nlc)) { return new nasl.DatabaseTypeAnnotation({ typeName: (0, common_util_1.projectIdentifier)(aav.name), }); } if (['text', 'tinytext', 'mediumtext', 'longtext'].includes(nlc)) { return new nasl.DatabaseTypeAnnotation({ typeName: (0, common_util_1.projectIdentifier)(aav.name), }); } } throw new Error('Unsupported database type annotations. in processAnnArgValForDatabaseTypeAnnotation'); } // CreatedTime function maybeCreatedTimeProp(ct) { if (ct && isAnnotation(ct.val)) { let aav = ct.val; const shouldGenerate = aav?.args?.length === 0 || (0, process_annotations_1.forceToBoolean)(aav?.args?.[0]?.val) === true; // @createdTime(true) if (shouldGenerate) { return new nasl.EntityProperty({ name: 'createdTime', columnName: 'created_time', label: '创建时间', description: '创建时间', typeAnnotation: naslCoreTypeAnn('DateTime'), display: genDisplay(true, false, false, false), generationRule: 'auto', }); } } return undefined; } // UpdatedTime function maybeUpdatedTimeProp(ut) { if (ut && isAnnotation(ut.val)) { let aav = ut.val; const shouldGenerate = aav?.args?.length === 0 || (0, process_annotations_1.forceToBoolean)(aav?.args?.[0]?.val) === true; // @updatedTime(true) if (shouldGenerate) { return new nasl.EntityProperty({ name: 'updatedTime', columnName: 'updated_time', label: '更新时间', description: '更新时间', typeAnnotation: naslCoreTypeAnn('DateTime'), display: genDisplay(true, false, false, false), generationRule: 'auto', }); } } return undefined; } // CreatedBy function maybeCreatedByProp(cb) { if (cb && isAnnotation(cb.val)) { let aav = cb.val; const shouldGenerate = aav?.args?.length === 0 || (0, process_annotations_1.forceToBoolean)(aav?.args?.[0]?.val) === true; // @createdBy(true) if (shouldGenerate) { return new nasl.EntityProperty({ name: 'createdBy', columnName: 'created_by', label: '创建者', description: '创建者', typeAnnotation: naslCoreTypeAnn('String'), display: genDisplay(false, false, false, false), generationRule: 'auto', }); } } return undefined; } // UpdatedBy function maybeUpdatedByProp(ub) { if (ub && isAnnotation(ub.val)) { let aav = ub.val; const shouldGenerate = aav?.args?.length === 0 || (0, process_annotations_1.forceToBoolean)(aav?.args?.[0]?.val) === true; // @updatedBy(true) if (shouldGenerate) { return new nasl.EntityProperty({ name: 'updatedBy', columnName: 'updated_by', label: '更新者', description: '更新者', typeAnnotation: naslCoreTypeAnn('String'), display: genDisplay(false, false, false, false), generationRule: 'auto', }); } } return undefined; } // Id function maybeIdProp(id) { if (id && !id.name && isAnnotation(id.val)) { let aav = id.val; const shouldGenerate = aav?.args?.length === 0 || (0, process_annotations_1.forceToBoolean)(aav?.args?.[0]?.val) === true; // @id(true) if (shouldGenerate) { return new nasl.EntityProperty({ name: 'id', columnName: "id", label: "主键", description: "主键", primaryKey: true, // 主键默认在哪都不展示 display: genDisplay(false, false, false, false), generationRule: 'auto' }); } } return undefined; } // const extractBooleanArg0FromAnnArg(aa : AnnArg): boolean => forceToBoolean((aa.val as Annotation).args[0].val) const isValidEntityAnnArg = (aa) => { let isNameValid = aa && supportedEntityAnnArgs.includes(aa.name); // (@SomeAnnotation) 也是合法的,这里省略了 name = 部分,所以 aa.name 为空,aa.val 又是一个 annotation if (!aa.name && isCustomAnnotation(aa.val)) { let aav = aa.val; if (['createdTime', 'updatedTime', 'createdBy', 'updatedBy', 'id'].includes(aav?.name?.name)) { // @SomeAnnotation 和 @SomeAnnotation(true) 和 @SomeAnnotation(false) return !(aav.args?.[0]) || isBooleanLit(aav.args?.[0].val); } } return isNameValid; }; const isValidColumnAnnArg = (aa) => { let isNameValid = aa && supportedColumnAnnArgs.includes(aa.name); if (!aa.name && isCustomAnnotation(aa.val)) { let aav = aa.val; if (['required', 'primaryKey'].includes(aav?.name?.name)) { return !(aav.args?.[0]) || isBooleanLit(aav.args?.[0].val); } } return isNameValid; }; const isValidEntityAnn = (ann) => isCustomAnnotation(ann) ? ann.name.name === ENTITY && ann.args.every(isValidEntityAnnArg) : ann.args.every(isValidEntityAnnArg); const isValidColumnAnn = (ann) => isCustomAnnotation(ann) ? ann.name.name === COLUMN && ann.args.every(isValidColumnAnnArg) : ann.args.every(isValidColumnAnnArg); const genDisplay = (inDetail, inFilter, inForm, inTable) => { return { 'inDetail': inDetail, 'inFilter': inFilter, 'inForm': inForm, 'inTable': inTable, }; }; const naslCoreTypeAnn = (n) => new nasl.TypeAnnotation({ "concept": "TypeAnnotation", "typeKind": "primitive", "typeNamespace": common_util_1.NASL_CORE_NL, "typeName": n, "typeArguments": null, "returnType": null, "properties": null }); //# sourceMappingURL=process-annotations-entity.js.map