UNPKG

@lcap/nasl

Version:

NetEase Application Specific Language

860 lines (846 loc) 216 kB
"use strict"; 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 __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; 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; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.NaslServer = exports.getDisplayString2Type = void 0; const config_1 = require("../config"); const Messager_1 = __importDefault(require("../common/Messager")); const oql_cache_1 = require("./OQL/oql-cache"); const initial_1 = require("../service/initial"); const set_1 = require("mnemonist/set"); const sqlFunctions_json_1 = __importDefault(require("./OQL/sqlFunctions.json")); const sqlCategory_json_1 = __importDefault(require("./OQL/sqlCategory.json")); /// #if process.env.BUILD_TARGET === 'node' const fs = __importStar(require("fs-extra")); const path = __importStar(require("path")); const worker_threads_1 = require("worker_threads"); /// #endif const concepts_1 = require("../concepts"); // import { validator, VusionValidator } from '@lcap/nasl-concepts'; const asserts_1 = require("@lcap/nasl-concepts/asserts"); const service_1 = require("@lcap/nasl-concepts/service"); const utils = __importStar(require("../utils")); const memory_optimization_1 = require("../generator/release-body/memory-optimization"); const createUiTs_1 = __importStar(require("./createUiTs")); const translator_1 = require("../translator"); const translator_2 = require("./translator"); const common_1 = require("../common"); const diagnostic_1 = require("../manager/diagnostic"); const naslStdlibMap_1 = __importDefault(require("./naslStdlibMap")); const decorators_1 = require("../decorators"); const nasl_concepts_1 = require("@lcap/nasl-concepts"); const nasl_language_server_core_1 = require("@lcap/nasl-language-server-core"); const findReference_1 = require("./findReference"); const nasl_server_client_1 = require("./client/nasl-server-client"); // naslStdlib文件缓存;作为全局变量给多实例用复用 const __naslStdlibFileCacheMap = new Map(); function transformDiagnosticMapToRecords(diagnosticMap) { const records = []; diagnosticMap.forEach((diagnostics, fileNode) => { records.push(...nasl_language_server_core_1.checker.transformDiagnosticsToRecords(fileNode, diagnostics)); }); return records; } // 联合类型切割取出类型 function getDisplayString2Type(displayString) { const targetString = displayString.match(/value:\s(\S+)\)/)?.[1]; let targetType = null; if (targetString?.startsWith('nasl.core.')) { targetType = targetString.slice(10); } // 取出匹配的内容 const reg = /<([^()]+)>/g; // 解决extends 导致类型缺失的问题 displayString = displayString?.replace('T extends ', '') || ''; const types = reg.exec(displayString); // 取出提示的类型,组成是数组 const typeList = (types?.[1].split(' | ') ?? []).map((item) => { if (/<([^()]+)>/g.exec(item)) { return item; } if (item.includes(' ')) { const strs = item.split(' '); const type = strs[strs.length - 1]; return type; } if (item.includes('.')) { const strs = item.split('.'); const type = strs[strs.length - 1]; return type; } return item; }); if (targetType) { return typeList.filter((item) => item !== targetType); } return typeList; } exports.getDisplayString2Type = getDisplayString2Type; function isCoreDateTimeType(n) { return n?.expression?.__TypeAnnotation?.typeName === 'DateTime' && n?.expression?.__TypeAnnotation?.typeNamespace === 'nasl.core'; } function isFunctionWithFixedTimeZoneParam(calleeName) { const fns = ['CurrDateTime', 'CurrDate', 'CurrTime', 'FormatDateTime']; return fns.includes(calleeName); } const createWorker = async (link, options) => { const blob = await fetch(link).then((res) => res.blob()); const instance = globalThis.window; const electron = instance.electron; if (electron?.createWorker) { return electron?.createWorker?.(await blob.arrayBuffer(), options); } const url = URL.createObjectURL(blob); const worker = new worker_threads_1.Worker(url, options); URL.revokeObjectURL(url); return worker; }; // FIXME wudengke 移动位置,放到nasl-language-server-core中 const oqlDefsStr = ` declare namespace nasl.oql { // 一次平铺的查询视为一次Query,FROM查询的依据为实体Entity // RecordList需要形如 any[]。而目前extends约束会参与求解;因此加上这个约束,会将 RecordList 解成 any[],导致单测挂掉 function checkUniqueKeys<RecordList>(...args: RecordList): CheckUniqueKeys<RecordList>; export class Query<Record extends Array<any>> { FROM_0<R>(): Query<[R]>; FROM_1<JoinRecord extends Array<any>>(query: Query<JoinRecord>): Query<[...Record, ...JoinRecord]>; FROM_SUBQUERY<JoinRecord extends Array<any>>(query: Query<JoinRecord>): Query<[...JoinRecord]>; PARTITION(expr: (...record: Record) => any): Query<Record>; INDEXHIT(expr: (...record: Record) => any): Query<Record>; JOIN_0<Record>(): Query<[Record]>; JOIN_1<JoinRecord extends Array<any>>(query: Query<JoinRecord>): Query<[...Record, ...JoinRecord]>; USING(...expr: Array<(...record: Record) => any>): Query<Record>; ON(expr: (...record: Record) => nasl.core.Boolean): Query<Record>; // UNION<T2 extends Array<any>>(union: Query<T2> & IfEquals<Record, T2>): Query<Record>; UNION<UnionRecord extends Array<any>>(union: Query<UnionRecord>): Query<Record>; WHERE(...expr: Array<(...record: Record) => nasl.core.Boolean>): Query<Record>; GROUP_BY(...expr: Array<(...record: Record) => any>): Query<Record>; HAVING(...expr: Array<(...record: Record) => nasl.core.Boolean>): Query<Record>; SELECT<SelectRecord>(expr: (...record: Record) => SelectRecord, check?: (...record: Record) => true, check2?: void): Query<[SelectRecord]>; // 内存临时表 SELECT_WITH_TEMP_TABLE<SelectRecord>(expr: (...record: Record) => SelectRecord): Query<[SelectRecord, ...Record]>; SELECT_SUBQUERY_EXPR<SelectRecord>(expr: (...record: Record) => SelectRecord): SelectRecord; ORDER_BY(...expr: Array<(...record: Record) => any>): Query<Record>; LIMIT_OFFSET(limit: nasl.core.Long, offset?: nasl.core.Long): Query<Record>; PAGINATE(page: nasl.core.Long, size: nasl.core.Long): Query<Record>; DynamicIfJoinExpr<JoinRecord extends Array<any>>(testExpr: nasl.core.Boolean, sqlExpr: Query<JoinRecord>): Query<[...Record, ...JoinRecord]>; GET_NO_LIST(_: nasl.core.Boolean): nasl.oql.InternalGetQueryNoListResult<Record>; GET_LIST(_: nasl.core.Boolean): nasl.oql.InternalGetQueryListResult<Record>; } // String functions export function ASCII(str: nasl.core.String ): nasl.core.String; export function BIN(expr: nasl.core.Long ): nasl.core.String; export function BIT_LENGTH(str: nasl.core.String ): nasl.core.Long; export function CHAR(charset?: nasl.core.String , ...exprs: Array<any>): nasl.core.String; export function CHAR_LENGTH(str: nasl.core.String ): nasl.core.Long; export function CONCAT(...strs: Array<any>): nasl.core.String; export function CONCAT_WS(seperator: nasl.core.String , ...strs: Array<nasl.core.String >): nasl.core.String; export function ELT(expr: nasl.core.Long, ...strs: Array<nasl.core.String >): nasl.core.String; export function EXPORT_SET(bits: nasl.core.Long, on: nasl.core.String , off: nasl.core.String , separator?: nasl.core.String , number_of_bits?: nasl.core.Long): nasl.core.String; export function FIELD(str: nasl.core.String , ...strs: Array<nasl.core.String >): nasl.core.Long; export function FIND_IN_SET(str: nasl.core.String , strs: nasl.core.String ): nasl.core.Long; export function FORMAT(expr1: nasl.core.Long | nasl.core.Decimal, expr2: nasl.core.Long, locale?: nasl.core.String ): nasl.core.String; export function FROM_BASE64(str: nasl.core.String ): nasl.core.String; export function HEX(expr: nasl.core.String ): nasl.core.String; export function INSERT(str: nasl.core.String , pos: nasl.core.Long, len: nasl.core.Long, newStr: nasl.core.String ): nasl.core.String; export function INSTR(str: nasl.core.String , newStr: nasl.core.String ): nasl.core.Long; export function LCASE(str: nasl.core.String ): nasl.core.String; export function LEFT(str: nasl.core.String | nasl.core.Date, len: nasl.core.Long): nasl.core.String; export function LENGTH(str: nasl.core.String ): nasl.core.Long; export function LOAD_FILE(fileName: nasl.core.String ): nasl.core.String; export function LOCATE(subStr: nasl.core.String , str: nasl.core.String, pos?: nasl.core.Long): nasl.core.Long; export function LOWER(str: nasl.core.String ): nasl.core.String; export function LPAD(str: nasl.core.String , len: nasl.core.Long, padStr: nasl.core.String ): nasl.core.String; export function LTRIM(str: nasl.core.String ): nasl.core.String; export function MAKE_SET(bits: nasl.core.Long, ...strs: Array<nasl.core.String >): nasl.core.String; export function MID(str: nasl.core.String , pos: nasl.core.Long, len: nasl.core.Long): nasl.core.String; export function OCT(expr: nasl.core.Long ): nasl.core.String; export function OCTET_LENGTH(str: nasl.core.String ): nasl.core.Long; export function ORD(str: nasl.core.String ): nasl.core.Long; export function POSITION(subStr: nasl.core.String , str: nasl.core.String ): nasl.core.Long; export function QUOTE(str: nasl.core.String ): nasl.core.String; export function REPEAT(str: nasl.core.String , count: nasl.core.Long): nasl.core.String; export function REPLACE(str: nasl.core.String , fromStr: nasl.core.String , toStr: nasl.core.String ): nasl.core.String; export function REVERSE(str: nasl.core.String ): nasl.core.String; export function RIGHT(str: nasl.core.String , len: nasl.core.Long): nasl.core.String; export function RPAD(str: nasl.core.String , len: nasl.core.Long, padStr: nasl.core.String ): nasl.core.String; export function RTRIM(str: nasl.core.String ): nasl.core.String; export function SOUNDEX(str: nasl.core.String ): nasl.core.String; export function SOUNDES_LIKE(str1: nasl.core.String , str2: nasl.core.String ): nasl.core.Boolean; export function SPACE(expr: nasl.core.Long): nasl.core.Long; export function SUBSTR(str: nasl.core.String , pos: nasl.core.Long, len?: nasl.core.Long): nasl.core.String; export function SUBSTRING(str: nasl.core.String , pos: nasl.core.Long, len?: nasl.core.Long): nasl.core.String; export function SUBSTRING_INDEX(str: nasl.core.String , delim: nasl.core.String, count: nasl.core.Long): nasl.core.String; export function TO_BASE64(str: nasl.core.String ): nasl.core.String; export function TRIM(remStr: nasl.core.String , str: nasl.core.String ): nasl.core.String; export function UCASE(str: nasl.core.String ): nasl.core.String; export function UNHEX(str: nasl.core.String ): nasl.core.String; export function UPPER(str: nasl.core.String ): nasl.core.String; export function WEIGHT_STRING(str: nasl.core.String , as: 'CHAR' | 'BINARY', ...level: Array<nasl.core.Long>): nasl.core.String; // String comparison functions export function LIKE(str1: nasl.core.String , str2: nasl.core.String , escape?: nasl.core.String ): nasl.core.Boolean; export function NOT_LIKE(str1: nasl.core.String , str2: nasl.core.String , escape?: nasl.core.String ): nasl.core.Boolean; export function STRCMP(str1: nasl.core.String , str2: nasl.core.String ): nasl.core.Boolean; // Regular Expressions export function REGEXP(str1: nasl.core.String , str2: nasl.core.String ): nasl.core.Boolean; export function NOT_REGEXP(str1: nasl.core.String , str2: nasl.core.String ): nasl.core.Boolean; export function RLIKE(str1: nasl.core.String , str2: nasl.core.String ): nasl.core.Boolean; // Character Set and Collation of Function Results // Mathematical Functions export function ABS(expr: nasl.core.Long): nasl.core.Long; export function ABS(expr: nasl.core.Long): nasl.core.Long; export function ABS(expr: nasl.core.Decimal): nasl.core.Decimal; export function ABS(expr: nasl.core.Decimal): nasl.core.Decimal; export function ACOS(expr: nasl.core.Long ): nasl.core.Decimal; export function ACOS(expr: nasl.core.Decimal): nasl.core.Decimal; export function ASIN(expr: nasl.core.Long ): nasl.core.Decimal; export function ASIN(expr: nasl.core.Decimal): nasl.core.Decimal; export function ATAN(expr: nasl.core.Long ): nasl.core.Decimal; export function ATAN(expr: nasl.core.Decimal): nasl.core.Decimal; export function ATAN(expr1: nasl.core.Long | nasl.core.Decimal, expr2: nasl.core.Long | nasl.core.Decimal): nasl.core.Decimal; export function ATAN(expr1: nasl.core.Long | nasl.core.Decimal, expr2: nasl.core.Decimal): nasl.core.Decimal; export function ATAN(expr1: nasl.core.Decimal, expr2: nasl.core.Long | nasl.core.Decimal): nasl.core.Decimal; export function ATAN2(expr1: nasl.core.Long | nasl.core.Decimal, expr2: nasl.core.Long | nasl.core.Decimal): nasl.core.Decimal; export function ATAN2(expr1: nasl.core.Long | nasl.core.Decimal, expr2: nasl.core.Decimal): nasl.core.Decimal; export function ATAN2(expr1: nasl.core.Decimal, expr2: nasl.core.Long | nasl.core.Decimal): nasl.core.Decimal; export function CEIL(expr1: nasl.core.Long | nasl.core.Decimal): nasl.core.Long; export function CEILING(expr1: nasl.core.Long | nasl.core.Decimal): nasl.core.Long; export function CONV(expr1: nasl.core.Long | nasl.core.String, expr2: nasl.core.Long, expr3: nasl.core.Long): nasl.core.String; export function COS(expr1: nasl.core.Long | nasl.core.Decimal): nasl.core.Decimal; export function COS(expr1: nasl.core.Decimal): nasl.core.Decimal; export function COT(expr1: nasl.core.Long | nasl.core.Decimal): nasl.core.Decimal; export function COT(expr1: nasl.core.Decimal): nasl.core.Decimal; export function CRC32(expr1: nasl.core.String): nasl.core.Long; export function DEGREES(expr1: nasl.core.Long | nasl.core.Decimal): nasl.core.Decimal; export function DEGREES(expr1: nasl.core.Decimal): nasl.core.Decimal; export function EXP(expr1: nasl.core.Long | nasl.core.Decimal): nasl.core.Decimal; export function EXP(expr1: nasl.core.Decimal): nasl.core.Decimal; export function FLOOR(expr1: nasl.core.Long | nasl.core.Decimal): nasl.core.Long; export function LN(expr1: nasl.core.Long | nasl.core.Decimal): nasl.core.Decimal; export function LN(expr1: nasl.core.Decimal): nasl.core.Decimal; export function LOG(expr1: nasl.core.Decimal): nasl.core.Decimal; export function LOG(expr1: nasl.core.Long | nasl.core.Decimal): nasl.core.Decimal; export function LOG(expr1: nasl.core.Long | nasl.core.Decimal, expr2: nasl.core.Long | nasl.core.Decimal): nasl.core.Decimal; export function LOG(expr1: nasl.core.Decimal, expr2: nasl.core.Long | nasl.core.Decimal): nasl.core.Decimal; export function LOG(expr1: nasl.core.Long | nasl.core.Decimal, expr2: nasl.core.Decimal): nasl.core.Decimal; export function LOG2(expr1: nasl.core.Decimal): nasl.core.Decimal; export function LOG2(expr1: nasl.core.Long | nasl.core.Decimal): nasl.core.Decimal; export function LOG10(expr1: nasl.core.Decimal): nasl.core.Decimal; export function LOG10(expr1: nasl.core.Long | nasl.core.Decimal): nasl.core.Decimal; export function MOD(expr1: nasl.core.Long | nasl.core.Decimal, expr2: nasl.core.Long | nasl.core.Decimal): nasl.core.Decimal; export function MOD(expr1: nasl.core.Decimal, expr2: nasl.core.Long | nasl.core.Decimal): nasl.core.Decimal; export function MOD(expr1: nasl.core.Long | nasl.core.Decimal, expr2: nasl.core.Decimal): nasl.core.Decimal; export function PI(): nasl.core.Decimal; export function POW(expr1: nasl.core.Long , expr2: nasl.core.Long ): nasl.core.Long; export function POW(expr1: nasl.core.Long , expr2: nasl.core.Decimal): nasl.core.Decimal; export function POW(expr1: nasl.core.Decimal, expr2: nasl.core.Long | nasl.core.Decimal): nasl.core.Decimal; export function POWER(expr1: nasl.core.Long , expr2: nasl.core.Long ): nasl.core.Long; export function POWER(expr1: nasl.core.Long , expr2: nasl.core.Decimal): nasl.core.Decimal; export function POWER(expr1: nasl.core.Decimal, expr2: nasl.core.Long | nasl.core.Decimal): nasl.core.Decimal; export function RADIANS(expr1: nasl.core.Long | nasl.core.Decimal): nasl.core.Decimal; export function RAND(expr1?: nasl.core.Long | nasl.core.Decimal): nasl.core.Decimal; export function RAND(expr1: nasl.core.Decimal): nasl.core.Decimal; export function ROUND(expr1: nasl.core.Long | nasl.core.Decimal): nasl.core.Long; export function ROUND(expr1: nasl.core.Long | nasl.core.Decimal, expr2: nasl.core.Long | nasl.core.Decimal): nasl.core.Decimal; export function SIGN(expr1: nasl.core.Long | nasl.core.Decimal): nasl.core.Long; export function SIN(expr1: nasl.core.Long | nasl.core.Decimal): nasl.core.Decimal; export function SQRT(expr1: nasl.core.Long | nasl.core.Decimal): nasl.core.Decimal; export function TAN(expr1: nasl.core.Long | nasl.core.Decimal): nasl.core.Decimal; export function TRUNCATE(expr1: nasl.core.Long | nasl.core.Decimal, expr2: nasl.core.Long | nasl.core.Decimal): nasl.core.Decimal; // Date and Time Functions type TIME_UNIT = 'MICROSECOND' | 'SECOND' | 'MINUTE' | 'HOUR' | 'DAY' | 'WEEK' | 'MONTH' | 'QUARTER' | 'YEAR' | 'SECOND_MICROSECOND' | 'MINUTE_MICROSECOND' | 'MINUTE_SECOND' | 'HOUR_MICROSECOND' | 'HOUR_SECOND' | 'HOUR_MINUTE' | 'DAY_MICROSECOND' | 'DAY_SECOND' | 'DAY_MINUTE' | 'DAY_HOUR' | 'YEAR_MONTH'; type fsp = 0 | 1 | 2 | 3 | 4 | 5 | 6; // fractional seconds precision export function DATE_ADD(date: nasl.core.Date, interval: "INTERVAL", expr: nasl.core.Long, unit: 'YEAR' | 'MONTH' | 'DAY'): nasl.core.Date; export function DATE_ADD(date: nasl.core.DateTime, interval: "INTERVAL", expr: nasl.core.Long, unit: TIME_UNIT): nasl.core.DateTime; export function DATE_ADD(date: nasl.core.Date, interval: "INTERVAL", expr: nasl.core.String, unit: 'YEAR' | 'MONTH' | 'DAY'): nasl.core.Date; export function DATE_ADD(date: nasl.core.DateTime, interval: "INTERVAL", expr: nasl.core.String, unit: TIME_UNIT): nasl.core.DateTime; export function DATE_SUB(date: nasl.core.Date, interval: "INTERVAL", expr: nasl.core.Long, unit: 'YEAR' | 'MONTH' | 'DAY'): nasl.core.Date; export function DATE_SUB(date: nasl.core.DateTime, interval: "INTERVAL", expr: nasl.core.Long, unit: TIME_UNIT): nasl.core.DateTime; export function DATE_SUB(date: nasl.core.Date, interval: "INTERVAL", expr: nasl.core.String, unit: 'YEAR' | 'MONTH' | 'DAY'): nasl.core.Date; export function DATE_SUB(date: nasl.core.DateTime, interval: "INTERVAL", expr: nasl.core.String, unit: TIME_UNIT): nasl.core.DateTime; export function ADDDATE(date: nasl.core.Date, interval: "INTERVAL", expr: nasl.core.Long, unit: 'YEAR' | 'MONTH' | 'DAY'): nasl.core.Date; export function ADDDATE(date: nasl.core.DateTime, interval: "INTERVAL", expr: nasl.core.Long, unit: TIME_UNIT): nasl.core.DateTime; export function ADDDATE(date: nasl.core.Date, interval: "INTERVAL", expr: nasl.core.String, unit: 'YEAR' | 'MONTH' | 'DAY'): nasl.core.Date; export function ADDDATE(date: nasl.core.DateTime, interval: "INTERVAL", expr: nasl.core.String, unit: TIME_UNIT): nasl.core.DateTime; export function ADDDATE(date: nasl.core.Date, expr: nasl.core.Long): nasl.core.Date; export function ADDDATE(date: nasl.core.DateTime, expr: nasl.core.Long): nasl.core.DateTime; export function ADDTIME(expr1: nasl.core.DateTime, expr: nasl.core.Time): nasl.core.DateTime; export function ADDTIME(expr1: nasl.core.Time, expr: nasl.core.Time): nasl.core.Time; export function CONVERT_TZ(expr1: nasl.core.DateTime, fromTz: nasl.core.String, toTz: nasl.core.String): nasl.core.DateTime; export function CURDATE(): nasl.core.Date; export function CURRENT_DATE(): nasl.core.Date; export function CURTIME(): nasl.core.Time; export function CURTIME(fsp: fsp): nasl.core.Decimal; export function CURRENT_TIME(): nasl.core.Time; export function CURRENT_TIME(fsp: fsp): nasl.core.Decimal; export function DATE(expr: nasl.core.Date | nasl.core.DateTime): nasl.core.Date; export function DATEDIFF(expr1: nasl.core.Date | nasl.core.DateTime, expr2: nasl.core.Date | nasl.core.DateTime): nasl.core.Long; export function DATE_FORMAT(expr1: nasl.core.Date | nasl.core.DateTime | nasl.core.Time, format: nasl.core.String): nasl.core.String; export function DAY(expr1: nasl.core.Date | nasl.core.DateTime): nasl.core.Long; export function DAYNAME(expr1: nasl.core.Date | nasl.core.DateTime): nasl.core.String; export function DAYOFMONTH(expr1: nasl.core.Date | nasl.core.DateTime): nasl.core.Long; export function DAYOFWEEK(expr1: nasl.core.Date | nasl.core.DateTime): nasl.core.Long; export function EXTRACT(unit: TIME_UNIT, expr1: nasl.core.Date | nasl.core.DateTime): nasl.core.Long; export function FROM_DAYS(days: nasl.core.Long): nasl.core.Date; export function FROM_UNIXTIME(timestamp: nasl.core.Long, format?: nasl.core.String): nasl.core.DateTime; export function GET_FORMAT(str1: 'DATE' | 'TIME' | 'DATETIME', str2: 'EUR' | 'USA' | 'JIS' | 'ISO' | 'INTERNAL'): nasl.core.String; export function LAST_DAY(date: nasl.core.Date | nasl.core.DateTime): nasl.core.Date; export function LOCALTIME(): nasl.core.DateTime; export function LOCALTIMESTAMP(): nasl.core.DateTime; export function MAKEDATE(year: nasl.core.Long, dayOfYear: nasl.core.Long): nasl.core.Date; export function MAKETIME(hour: nasl.core.Long, minute: nasl.core.Long, second: nasl.core.Long): nasl.core.Time; export function MICROSECOND(expr: nasl.core.Time | nasl.core.DateTime): nasl.core.Long; export function MINUTE(expr: nasl.core.Time | nasl.core.DateTime): nasl.core.Long; export function MONTH(expr: nasl.core.Date | nasl.core.DateTime): nasl.core.Long; export function MONTHNAME(expr: nasl.core.Date | nasl.core.DateTime): nasl.core.String; export function PERIOD_ADD(expr1: nasl.core.Long, expr2: nasl.core.Long): nasl.core.Long; export function PERIOD_DIFF(expr1: nasl.core.Long, expr2: nasl.core.Long): nasl.core.Long; export function QUARTER(expr1: nasl.core.Date | nasl.core.DateTime): nasl.core.Long; export function SECOND(expr1: nasl.core.Time | nasl.core.DateTime): nasl.core.Long; export function SEC_TO_TIME(expr1: nasl.core.Long): nasl.core.Time; export function STR_TO_DATE(str: nasl.core.String, format: nasl.core.String): nasl.core.DateTime; export function SUBDATE(date: nasl.core.Date, interval: "INTERVAL", expr: nasl.core.Long, unit: 'YEAR' | 'MONTH' | 'DAY'): nasl.core.Date; export function SUBDATE(date: nasl.core.DateTime, interval: "INTERVAL", expr: nasl.core.Long, unit: TIME_UNIT): nasl.core.DateTime; export function SUBDATE(date: nasl.core.Date, interval: "INTERVAL", expr: nasl.core.String, unit: 'YEAR' | 'MONTH' | 'DAY'): nasl.core.Date; export function SUBDATE(date: nasl.core.DateTime, interval: "INTERVAL", expr: nasl.core.String, unit: TIME_UNIT): nasl.core.DateTime; export function SUBDATE(date: nasl.core.Date, expr: nasl.core.Long): nasl.core.Date; export function SUBDATE(date: nasl.core.DateTime, expr: nasl.core.Long): nasl.core.DateTime; export function SUBTIME(expr1: nasl.core.DateTime, expr2: nasl.core.Time): nasl.core.DateTime; export function SUBTIME(expr1: nasl.core.Time, expr2: nasl.core.Time): nasl.core.Time; export function TIME(expr: nasl.core.Time | nasl.core.DateTime): nasl.core.Time; export function TIMEDIFF(expr1: nasl.core.Time | nasl.core.DateTime, expr2: nasl.core.Time | nasl.core.DateTime): nasl.core.Time; export function TO_DAYS(expr: nasl.core.Date | nasl.core.DateTime): nasl.core.Long; export function TO_SECONDS(expr: nasl.core.Date | nasl.core.DateTime): nasl.core.Long; export function UNIX_TIMESTAMP(date?: nasl.core.DateTime): nasl.core.Long; export function UTC_DATE(): nasl.core.Date; export function UTC_TIME(): nasl.core.Time; export function UTC_TIMESTAMP(): nasl.core.DateTime; export function WEEK(date: nasl.core.Date | nasl.core.DateTime, mode?: nasl.core.Long): nasl.core.Long; export function WEEKDAY(date: nasl.core.Date | nasl.core.DateTime): nasl.core.Long; export function DAYOFYEAR(date: nasl.core.Date | nasl.core.DateTime): nasl.core.Long export function WEEKOFYEAR(date: nasl.core.Date | nasl.core.DateTime): nasl.core.Long; export function YEAR(date: nasl.core.Date | nasl.core.DateTime): nasl.core.Long; export function YEARWEEK(date: nasl.core.Date, mode?: nasl.core.Long): nasl.core.Long; export function HOUR(date: nasl.core.Date | nasl.core.DateTime): nasl.core.Long; export function NOW(): nasl.core.DateTime; // Comparison Functions export function INTERVAL(...value: Array<nasl.core.Long>): nasl.core.Long; export function GREATEST(...value: Array<nasl.core.Long>): nasl.core.Long; export function GREATEST(...value: Array<nasl.core.Long>): nasl.core.Long; export function GREATEST(...value: Array<nasl.core.Decimal>): nasl.core.Decimal; export function GREATEST(...value: Array<nasl.core.Decimal>): nasl.core.Decimal; export function GREATEST(...value: Array<nasl.core.String>): nasl.core.String; export function LEAST(...value: Array<nasl.core.Long>): nasl.core.Long; export function LEAST(...value: Array<nasl.core.Long>): nasl.core.Long; export function LEAST(...value: Array<nasl.core.Decimal>): nasl.core.Decimal; export function LEAST(...value: Array<nasl.core.Decimal>): nasl.core.Decimal; export function LEAST(...value: Array<nasl.core.String>): nasl.core.String; // Miscellaneous Functions export function ANY_VALUE<T>(arg: T): T; // nonAggregateWindowedFunction export function CUME_DIST(): nasl.core.Decimal; export function DENSE_RANK(): nasl.core.Long; export function PERCENT_RANK(): nasl.core.Decimal; export function RANK(): nasl.core.Long; export function ROW_NUMBER(): nasl.core.Long; // aggregateWindowedFunction export function COUNT(...value: Array<any>): nasl.core.Long; export function SUM(value: nasl.core.Long): nasl.core.Long; export function SUM(value: nasl.core.Decimal): nasl.core.Decimal; export function SUM(value: nasl.core.Boolean): nasl.core.Long; export function AVG(value: nasl.core.Long | nasl.core.Decimal): nasl.core.Decimal; export function MAX(value: nasl.core.Long): nasl.core.Long; export function MAX(value: nasl.core.Decimal): nasl.core.Decimal; export function MAX(value: nasl.core.Date): nasl.core.Date; export function MAX(value: nasl.core.DateTime): nasl.core.DateTime; export function MAX(value: nasl.core.Time): nasl.core.Time; export function MAX(value: nasl.core.Boolean): nasl.core.Boolean; export function MIN(value: nasl.core.Long): nasl.core.Long; export function MIN(value: nasl.core.Decimal): nasl.core.Decimal; export function MIN(value: nasl.core.Date): nasl.core.Date; export function MIN(value: nasl.core.DateTime): nasl.core.DateTime; export function MIN(value: nasl.core.Time): nasl.core.Time; export function MIN(value: nasl.core.Boolean): nasl.core.Boolean; // self export function STARTWITH(str1: nasl.core.String, str2: nasl.core.String): nasl.core.Boolean; export function ENDWITH(str1: nasl.core.String, str2: nasl.core.String): nasl.core.Boolean; export function IN<T>(value: T, list: nasl.collection.List<T>): nasl.core.Boolean; export function IN<T>(value: T, ...array: Array<T>): nasl.core.Boolean; export function IN_SUBQUERY<SelectRecord, T>(value: T, expr: Query<[SelectRecord]>): nasl.core.Boolean; export function COMPARE_SUBQUERY<SelectRecord, T extends SelectRecord>(value: T, expr: Query<[SelectRecord]>): nasl.core.Boolean; export function ISNULL(value: any): nasl.core.Boolean; export function IFNULL<T extends nasl.core.Long | nasl.core.Decimal>(expr1: T, expr2: nasl.core.Decimal): nasl.core.Decimal; export function IFNULL<T extends nasl.core.Decimal | nasl.core.Long>(expr1: nasl.core.Decimal, expr2: T): nasl.core.Decimal; export function IFNULL<T1, T2>(expr1: T1, expr2: T2): T1 | T2; export function CASE_WHEN<THEN>(caseCase: any, ...caseWhen: Array<[() => any, () => THEN]>): THEN; export function CASE_WHEN<THEN>(caseCase: any, caseElse: THEN, ...caseWhen: Array<[() => any, () => THEN]>): THEN; export function BETWEEN_AND<T>(value: T, between: T, and: T): nasl.core.Boolean; export function GROUP_CONCAT(...value: Array<any>): nasl.core.String; export function IF<THEN, ELSE>(expr1: nasl.core.Boolean, expr2: THEN, expr3: ELSE): THEN | ELSE; export function ISBOOLEAN(value: nasl.core.Boolean): nasl.core.Boolean; export function COMPARE<T>(left: T, right: T): nasl.core.Boolean; export function CAST<T>(value: any, dataType: T): T; export function CONVERT<T>(value: any, dataType: T): T; export function CONVERT<T>(value: T): T; export function EXISTS_EXPR<Record extends Array<any>>(value: Query<Record>): nasl.core.Boolean; export function COALESCE<T>(...args: Array<T>): T // others export let NULL: never export function DynamicIfExpr<Record>(testExpr: nasl.core.Boolean, sqlExpr: Record): Record; export function checkDynamicReference(...expr1: Array<any>): void; // 单项查询 export function SINGLE_SELECT_ELEMENT<Record>(query: Record): Record; } `; const allComponent = {}; class NaslServer { constructor(opt) { /** naslStdlib文件缓存 */ this.naslStdlibFileCacheMap = __naslStdlibFileCacheMap; /** * 按道理 fileSourceMap: new Map<string, SourceMap>() 比较合理, * 但是要多维护一层 vertex 增删 -> file 增删的关系问题, * 先用挂在点上面,简单的方法实现,后期再考虑解耦 */ this.file2NodeMap = new Map(); /** TS 翻译的源码 */ this.tsFiles = new Map(); /// #if process.env.NODE_ENV === 'development' /** * 调试时是否储存 ts 文件 */ this.openDebugEmbedded = true; /// #endif this.elementsLogic = {}; // 待处理的变化事件 this.changeStackList = []; // 需要检查的文件节点 this.typerCheckFiles = new Set(); // 删除的精确节点,这个不一定是文件级别的节点 this.typerRemoveNodes = new Set(); // 创建的节点 this.typerCreateNodes = new Set(); // 临时 hack:OQL 需要删除的节点(NASL 节点重命名,老名字对应的 TS 节点需删除 this.oqlRemoveNodesTsPath = new Set(); // 临时 hack:删除的连接器中的文件级别的节点 this.removedConnectors = new Set(); // 变动的原始目标节点,带有 proxy,用于触发响应式更新:事件树,子逻辑树等 this.originProxyTargetNodes = new Set(); this.typerErrRecords = []; // 确保首屏检查没有"传统艺能"、"时序问题" this.cachedEventPayloadValues = []; // 当前重命名模式:rename-only: 只重命名,update: 更新引用 this.currentRenameMode = null; this.oqlDisaster = false; this.isFirstScreen = true; // 优化首屏 getAncestor 热点代码 /** * 语言服务运行完毕 * * @description 初始化以及每次修改内容时都会重置 */ this.lsRunEnd = Promise.resolve(); /** * 语言服务运行完毕标记 * * @description `lsRunEnd`属性的内部状态 */ this._lsRunEndSwitch = () => void 0; this.flags = { /** * 是否启用性能分析模式 */ profileMode: false, /** * 是否启用 TypeScript 语言服务 * 默认启用,可以通过在 url 中添加 oql-check=true 来关闭 tss,使用 NASL 的OQL类型检查器 */ tssEnabled: true, /** * 是否为智能应用生成开发模式。如果是,那么有一些特殊的类型检查规则。 */ creatorDevMode: false, }; this.uiTsInitedResolve = null; // 检查共享数据是否有更新 this._latestVersionsOfSharedApp = []; this.firstScreenEndWork = undefined; // 用户点击"查找引用" this.findReferenceAndRender = (nd) => (0, findReference_1.findReferenceAndRender)(this.semEnv, nd); /** * 根据入参准备并往 TS Server 写入需要校验的 ts 文件 * @param chkFiles 需要校验的文件 * @param removedNodes 需要删除的文件 * @param oqlRemoveNodesTsPath 需要删除的文件路径 * @returns 需要校验的文件名 */ this.prepareAndWriteTsFilesToCheck = async (oqlFiles, removedNodes, oqlRemoveNodesTsPath) => { if (!this.flags.tssEnabled) { const self = this; try { await Promise.all([...oqlFiles].map(x => { return self.waitOqlQueryComponentChildrenFinish(x); })); } catch (error) { console.error(error); } return { tsFilePathsToCheck: new Set() }; } function getETSFilePath(fileNode) { try { return fileNode.getEmbeddedFilePath(); } catch (err) { return null; } } async function removeETSFile(filePath) { if (!filePath) { return; } await self.writeFiles([ { file: filePath, fileContent: '', }, ]); } const self = this; for (const nd of removedNodes) { await removeETSFile(getETSFilePath(nd)); } for (const filePath of oqlRemoveNodesTsPath) { await removeETSFile(filePath); } const tsFilePathsToCheck = new Set(); for (const fileNode of oqlFiles) { let tsFilePath; try { tsFilePath = fileNode.getEmbeddedFilePath(); } catch (err) { this.logger.error(err); // TODO wudengke 或许需要 continue } let tsFile; // 3.14 需要改成后端大逻辑涉及 OQL 改动时则收集一下(可能要跑 OQL 的 toTS) // TODO: 可能可以用 fileNodeRaw 当输入,提速 5x,现在的 typer 已经有不触发 vue 渲染更新的情况了,可以考虑统一解决 await utils.timeSlicingWithGenerator(this.semData.updateSemanticCtxAsPer(fileNode)); // 用 raw 的话,很多响应式更新都失效了。几个,几十个的单子,实在是修补过来,慢慢修或者等 nasl worker 吧。 tsFile = await utils.timeSlicingWithGenerator(fileNode.toEmbeddedTSFile()); await this.writeFiles([{ file: tsFile.filePath, fileContent: tsFile.code, }]); tsFilePathsToCheck.add(tsFilePath); // 如果当前没有生成tsFile if (!tsFile?.sourceMap) { continue; } // 修改触发修改文件 this._debugInFileStorage(fileNode, [{ file: tsFile.filePath, fileContent: tsFile.code, }]); // @ts-ignore fileNode.sourceMap = tsFile.sourceMap; // 麻了,查了半天是没 set 这里 this.file2NodeMap.set(tsFile.filePath, fileNode); } if (utils.isDebugMode) { console.info('TS 校验以下文件', Array.from(oqlFiles).map((item) => item.getEmbeddedFilePath())); } utils.isDebugMode && console.timeEnd('TS 文件变更'); return { tsFilePathsToCheck }; }; this.getProxyNode = (nd) => { return this.getProxyApp()?.findNodeByPath(nd.nodePath); }; // 初始化 uiTsInited Promise 并保存 resolve 函数 this.uiTsInited = new Promise((resolve) => { this.uiTsInitedResolve = resolve; }); this.promise = this.launch(opt); } async start() { await this.promise; if (this.flags.tssEnabled) { return this.messager.requestCommand('start'); } } terminate() { if (this.worker) { this.worker.terminate(); this.worker = null; } } loadFlags(flags) { if (flags) { Object.keys(flags).forEach((k) => { const v = flags[k]; if (v !== undefined) { this.flags[k] = v; } }); } } synthesisFlagsFromUrl() { if (utils.isBrowser) { function isOQLCheckEnabled() { if (/[?&]oql-check=false/.test(location.search)) { return false; } else if (/[?&]oql-check=true/.test(location.search)) { return true; } else { // 测试环境默认打开。 return /lcap\.codewave-test\.163yun\.com/.test(location.host); } } function isCreatorDevModeEnabled() { return !!/[?&]creator-dev-mode=true/.test(location.search); } return { tssEnabled: !isOQLCheckEnabled(), creatorDevMode: isCreatorDevModeEnabled(), }; } return undefined; } async launch(opt) { const flags = opt.flags ?? this.synthesisFlagsFromUrl(); if (flags) { this.loadFlags(flags); } // 根据特性开关控制是否创建TypeScript Worker if (this.flags.tssEnabled) { /// #if process.env.BUILD_TARGET === 'node' if (globalThis.process) // For TS build // this.worker = new Worker(require.resolve('@lcap/nasl-typescript-worker/src/index.js')); this.worker = new worker_threads_1.Worker(require.resolve('../../ts-worker/src/index.js')); /// #endif /// #if process.env.BUILD_TARGET !== 'node' if (globalThis.window) { // const source = require('!!raw-loader!@lcap/nasl-typescript-worker/dist/index.js').default; this.worker = await (async () => { if (process.env.NODE_ENV === 'development') { const source = require('!!raw-loader!../../ts-worker/bundle.js').default; const url = URL.createObjectURL(new Blob([source])); const worker = new window.Worker(url); URL.revokeObjectURL(url); return worker; } const instance = globalThis.window; const baseIdePath = instance?.baseIdePath; const hash = process.env.COMMIT_HASH || ''; const filename = instance?.electron?.createWorker ? 'tsserver.electron.js' : 'tsserver.js'; // @ts-ignore const link = `${baseIdePath}/js/${filename}?${hash}`; const options = { name: 'typescript-server' }; return createWorker(link, options); })(); } /// #endif } this.http = opt.http; this.isAnnotationMode = opt?.isAnnotationMode ?? false; this.logger = opt.logger ?? utils.internalLogger; this.diagnosticManager = new diagnostic_1.DiagnosticManager(); this.handlePublishDiagnostics = async ({ data }) => { console.timeEnd('wait-tss'); console.time('ls-typecheck'); if (!data || data.event !== 'publishDiagnostics') { return; } console.debug(`[NaslServer] flags: ${JSON.stringify(this.flags ?? {})}`); // getDiagnosticRecordsAndPushAll 最终通过 ts 回调走到这里 const tsDiagnostics = this.flags.tssEnabled ? (await this._resolveDiagnosticRecords(data.records, data.versions) ?? []) : []; if (!this.isAnnotationMode) { // 让出CPU,让浏览器关闭骨架屏 await utils.delay(500); if (this.flags.tssEnabled) { await utils.timeSlicingWithGenerator(this._incrementalAnnotationJSONWithGenerator(data.records)); } if (this.isFirstScreen) { // 首屏时,语言服务初始化 await this.languageServerInitiate(); } console.time("等待uiTsInited"); (await this.uiTsInited)?.(); console.timeEnd("等待uiTsInited"); // 已经和 NASL 节点配对的诊断信息 const isProfileMode = this.flags.profileMode; if (this.isFirstScreen) { utils.isDebugMode && console.time('\x1b[44m\x1b[97m 用户体感首屏检查耗时 \x1b[0m'); // 对OQL节点加载来自TS的错误 tsDiagnostics.forEach(({ node, message }) => { if (node.errorsFromTSServer) { node.errorsFromTSServer.push({ message }); } else { node.errorsFromTSServer = [{ message }]; } }); if (isProfileMode) { console.profile('check'); } let fixAllUseBeforeAssignTasks = []; const rawApp = NaslServer.toRaw(this.getProxyApp()); // 让事件逻辑显示出来 this._getAllElementLogicRoots(); try { // 目前里面包含所有定义、逻辑、业务组件、前端全局变量等 fixAllUseBeforeAssignTasks = await (0, nasl_language_server_core_1.firstScreenCheckAndCompare)(this.semEnv, rawApp); // 类型检查完才能收集引用 this.semEnv.refMgr.buildSymbolRefsForApp(this.semEnv, rawApp); } catch (err) { this.semEnv.logger.fatal('\x1b[44m\x1b[97m 类型检查出错了,估计没标完 \x1b[0m'); this.semEnv.logger.fatal(err); } if (isProfileMode) { console.profileEnd('check'); } if (isProfileMode) { console.profile('diag'); } // Use performance measurement to accurately track time in time-sliced execution const diagAppStartTime = performance.now(); await utils.runGeneratorAsync(this.semEnv.errorDiagnoser.diagnosticApp()); const diagAppEndTime = performance.now(); console.info(`\x1b[44m\x1b[97m Diagnostic App \x1b[0m: ${((diagAppEndTime - diagAppStartTime) / 1000).toFixed(3)}s`); const diagnosticMap = this.semEnv.errorDiagnoser.getAllDiagnostics(); const transformStartTime = performance.now(); const records = transformDiagnosticMapToRecords(diagnosticMap); await this.diagnosticManager.setInitialDiagData(records); const transformEndTime = performance.now(); console.info(`\x1b[44m\x1b[97m Transform Diagnostic Map To Records \x1b[0m: ${((transformEndTime - transformStartTime) / 1000).toFixed(3)}s`); // 首屏和增量通路不同,首屏时需要手动调用lsRunEndSwitch;增量时则在增量代码中调用 this._lsRunEndSwitch(); this.isFirstScreen = false; rawApp.emit('collect:start', { actionMsg: 'v3.14 v4.0 新 LS 修复变量先使用后赋值的场景' }); // 🪝,放在前面的话有时序问题,容易多很多重复报错 fixAllUseBeforeAssignTasks.forEach(task => task()); rawApp.emit('collect:end'); this.semData.isFirstScreen = false; this.semEnv.allocatedVEQNames.forEach(n => { this.semEnv.refMgr.gQNameDefs.delete(n); }); this.semEnv.allocatedVEQNames.length = 0; for (const value of this.cachedEventPayloadValues) { this.embeddedTSEmitter.emit('change', { value }); } this.cachedEventPayloadValues.length = 0; if (isProfileMode) { console.profileEnd('diag'); } utils.isDebugMode && console.timeEnd('\x1b[44m\x1b[97m 用户体感首屏检查耗时 \x1b[0m'); } /** * @warning 不放在这里无法起到加速效果,且读到的 cache 为空,抛出 undefined 值 * 放在这里的话好像是有些“时序”问题? */ this.semData.recoverSlowGetters(); this.semData.clearSemanticData(); (0, nasl_language_server_core_1.clearFileNodeCache)(); } this.notifyPublishDiagnosticsEnd(tsDiagnostics); console.timeEnd("ls-typecheck"); if (this.firstScreenEndWork) { this.firstScreenEndWork(); this.firstScreenEndWork = undefined; } }; // 只有在tssEnabled时才创建messager if (this.flags.tssEnabled) { this.messager = new Messager_1.default({ protocol: 'ts-worker', sender: 'ide', context: this, timeout: 420000, getReceiver: () => this.worker, getSender: () => this.worker, // @ts-expect-error FIXME 看不懂,等高人修复 handleMessage: this.handlePublishDiagnostics }); } // 监听所有改变操作 this.embeddedTSEmitter = new concepts_1.EventEmitter(); if (!this.isAnnotationMode) { this.embeddedTSEmitter.on('change', ({ value: eventValue }) => { if (this.isFirstScreen) { this.cachedEventPayloadValues.push(eventValue); return; } const itemEventPtr = new Array(); eventValue.forEach((item) => { if (concepts_1.asserts.isDirectory(item.originEvent?.currentTarget) || concepts_1.asserts.isReferredDefinition(item.originEvent?.currentTarget)) return; // 查找引用无法处理合并后的请求,需要拦截后缓存数据 item.originEvent && itemEventPtr.push({ action: item.originEvent.action, objNasl: item.originEvent.objNasl, oldObjNasl: item.originEvent.oldObjNasl, field: item.originEvent.field, // 判断是否是 rename target: item.originEvent.target, // rename 专用 ctxProcess: item.originEvent.ctxProcess // 流程特殊情况:更新流程关联的 view }); /** * 多个行为进行合并 * 合并规则是 * 1.[a,b,c,c] 在cc的时候,在已有一个c,又来一个c的时候,file级别的节点 * 就可以前面的内容去掉,只保留最后一个, 但是如果前面那个有携带file * 2.[a,b,c,b,c] 在bc已存在,又来了bc 这就都要保留,因为可能顺序有相关性,不能去掉 * 理论上只处理同时几个操作 合并, * 3.有field的也直接保留 */ try { const changeEvent = item.originEvent; // 设置国际化相关内容传标识过来,不需要进入语言服务 if (changeEvent?.field === 'setI18n') return; const changeNode = changeEvent.target; // FIXME: 验证完成后需要移除 const { fileNode: fileNode2 } = NaslServer.getCurrentSource(changeNode); const fileNode = (0, service_1.getFileNode)(changeNode); if (NaslServer.toRaw(fileNode) !== NaslServer.toRaw(fileNode2)) { this.logger.error('\x1b[41m