@lcap/nasl-parser
Version:
Take Nasl text to Nasl AST with the help of generalized parsing.
487 lines (486 loc) • 19.3 kB
JavaScript
"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