@nasl/cli 0.1.18 → 0.1.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -1
- package/dist/bin/nasl.mjs +130 -37
- package/dist/bin/nasl.mjs.map +1 -1
- package/dist/bin/naslc.mjs +130 -37
- package/dist/bin/naslc.mjs.map +1 -1
- package/dist/index.mjs +129 -36
- package/dist/index.mjs.map +1 -1
- package/out/services/compose.d.ts +1 -1
- package/out/services/compose.d.ts.map +1 -1
- package/out/services/compose.js +66 -18
- package/out/services/compose.js.map +1 -1
- package/out/services/resolve.d.ts.map +1 -1
- package/out/services/resolve.js +30 -5
- package/out/services/resolve.js.map +1 -1
- package/out/utils/config.d.ts.map +1 -1
- package/out/utils/config.js +16 -13
- package/out/utils/config.js.map +1 -1
- package/out/utils/file.d.ts +12 -0
- package/out/utils/file.d.ts.map +1 -1
- package/out/utils/file.js +18 -0
- package/out/utils/file.js.map +1 -1
- package/package.json +1 -1
package/dist/bin/naslc.mjs
CHANGED
|
@@ -8308,26 +8308,29 @@ function loadConfig(configDir) {
|
|
|
8308
8308
|
defaultLogger.error('配置文件格式不正确,缺少必需的 srcDir 或 outDir 字段');
|
|
8309
8309
|
return defaultLogger.exit(1);
|
|
8310
8310
|
}
|
|
8311
|
+
// 环境变量优先级高于配置文件
|
|
8312
|
+
// ideVersion: 环境变量优先,如果都没有则报错
|
|
8313
|
+
if (process.env.NASL_IDE_VERSION)
|
|
8314
|
+
config.ideVersion = process.env.NASL_IDE_VERSION;
|
|
8311
8315
|
if (!config.ideVersion) {
|
|
8312
|
-
|
|
8313
|
-
|
|
8314
|
-
defaultLogger.error('缺少配置 ideVersion,请在配置文件中添加,或在环境变量中配置 NASL_IDE_VERSION');
|
|
8315
|
-
return defaultLogger.exit(1);
|
|
8316
|
-
}
|
|
8316
|
+
defaultLogger.error('缺少配置 ideVersion,请在配置文件中添加,或在环境变量中配置 NASL_IDE_VERSION');
|
|
8317
|
+
return defaultLogger.exit(1);
|
|
8317
8318
|
}
|
|
8319
|
+
// serverBaseURL: 环境变量优先,如果都没有则报错
|
|
8320
|
+
if (process.env.NASL_SERVER_BASE_URL)
|
|
8321
|
+
config.serverBaseURL = process.env.NASL_SERVER_BASE_URL;
|
|
8318
8322
|
if (!config.serverBaseURL) {
|
|
8319
|
-
|
|
8320
|
-
|
|
8321
|
-
defaultLogger.error('缺少配置 serverBaseURL,请在配置文件中添加,或在环境变量中配置 NASL_SERVER_BASE_URL');
|
|
8322
|
-
return defaultLogger.exit(1);
|
|
8323
|
-
}
|
|
8323
|
+
defaultLogger.error('缺少配置 serverBaseURL,请在配置文件中添加,或在环境变量中配置 NASL_SERVER_BASE_URL');
|
|
8324
|
+
return defaultLogger.exit(1);
|
|
8324
8325
|
}
|
|
8325
|
-
|
|
8326
|
+
// 环境变量优先
|
|
8327
|
+
if (process.env.USE_LCAP_OPENAPI !== undefined)
|
|
8326
8328
|
config.useOPENAPI = process.env.USE_LCAP_OPENAPI === 'true';
|
|
8327
|
-
if (
|
|
8329
|
+
if (process.env.LCAP_OPENAPI_AK)
|
|
8328
8330
|
config.OPENAPI_AK = process.env.LCAP_OPENAPI_AK;
|
|
8329
|
-
if (
|
|
8331
|
+
if (process.env.LCAP_OPENAPI_SK)
|
|
8330
8332
|
config.OPENAPI_SK = process.env.LCAP_OPENAPI_SK;
|
|
8333
|
+
// 如果启用了 OpenAPI,验证必需的 AK 和 SK
|
|
8331
8334
|
if (config.useOPENAPI) {
|
|
8332
8335
|
if (!config.OPENAPI_AK || !config.OPENAPI_SK) {
|
|
8333
8336
|
defaultLogger.error(`配置了 useOPENAPI,但缺少配置 OPENAPI_AK 和 OPENAPI_SK:
|
|
@@ -8382,6 +8385,23 @@ function writeFileWithLog(filePath, content, logger) {
|
|
|
8382
8385
|
throw error;
|
|
8383
8386
|
}
|
|
8384
8387
|
}
|
|
8388
|
+
/**
|
|
8389
|
+
* 判断文件路径是否为已知的 NASL 文件类型
|
|
8390
|
+
* 支持的类型:
|
|
8391
|
+
* - 枚举 (enums)
|
|
8392
|
+
* - 实体 (entities)
|
|
8393
|
+
* - 数据结构 (structures)
|
|
8394
|
+
* - 逻辑 (logics)
|
|
8395
|
+
* - 页面 (views)
|
|
8396
|
+
* - 前端/服务端全局变量 (variables)
|
|
8397
|
+
* - 依赖库 (extensions)
|
|
8398
|
+
*/
|
|
8399
|
+
function isKnownFileType(filePath) {
|
|
8400
|
+
return (/\.(enums|entities|structures|logics|views)\.\w+\.(ts|tsx)$/.test(filePath) || // 枚举、实体、数据结构、逻辑、页面
|
|
8401
|
+
/^app\..*\.variables\.ts$/.test(filePath) || // 前端/服务端全局变量 (以app开头,以variables.ts结尾)
|
|
8402
|
+
/^extensions\.\w+\.(ts|tsx)$/.test(filePath) // 依赖库
|
|
8403
|
+
);
|
|
8404
|
+
}
|
|
8385
8405
|
|
|
8386
8406
|
/**
|
|
8387
8407
|
* Create a bound version of a function with a specified `this` context
|
|
@@ -29142,6 +29162,56 @@ function createSorter() {
|
|
|
29142
29162
|
};
|
|
29143
29163
|
}
|
|
29144
29164
|
const sorter = createSorter();
|
|
29165
|
+
/**
|
|
29166
|
+
* 验证 variables 文件
|
|
29167
|
+
*/
|
|
29168
|
+
function validateVariablesFile(file, errors) {
|
|
29169
|
+
const matchArr = Array.from(file.content.matchAll(/^(export\s+)(declare\s+)?(const|let)\s+(\w+)/gm));
|
|
29170
|
+
if (matchArr.length === 0) {
|
|
29171
|
+
errors.push(`${file.path} (variables文件) 必须包含至少一个 export const 或 export let 声明`);
|
|
29172
|
+
}
|
|
29173
|
+
for (const match of matchArr) {
|
|
29174
|
+
const [, isExport] = match;
|
|
29175
|
+
if (!isExport)
|
|
29176
|
+
errors.push(`${file.path} 所有声明必须使用 export,错误代码:${match[0]}`);
|
|
29177
|
+
}
|
|
29178
|
+
}
|
|
29179
|
+
/**
|
|
29180
|
+
* 验证 extensions 文件
|
|
29181
|
+
*/
|
|
29182
|
+
function validateExtensionsFile(file, errors) {
|
|
29183
|
+
const matchArr = Array.from(file.content.matchAll(/^(export\s+)(namespace)\s+(\w+)/gm));
|
|
29184
|
+
if (matchArr.length === 0) {
|
|
29185
|
+
errors.push(`${file.path} (extensions文件) 必须包含至少一个 export namespace 声明`);
|
|
29186
|
+
}
|
|
29187
|
+
for (const match of matchArr) {
|
|
29188
|
+
const [, isExport] = match;
|
|
29189
|
+
if (!isExport)
|
|
29190
|
+
errors.push(`${file.path} 所有 namespace 必须使用 export,错误代码:${match[0]}`);
|
|
29191
|
+
}
|
|
29192
|
+
}
|
|
29193
|
+
/**
|
|
29194
|
+
* 验证普通文件(枚举、实体、数据结构、逻辑、页面)
|
|
29195
|
+
*/
|
|
29196
|
+
function validateNormalFile(file, nameFromPath, namespace, errors) {
|
|
29197
|
+
const matchArr = Array.from(file.content.matchAll(/^(export\s+)?(declare\s+)?(function|class|interface)\s+(\w+)/gm));
|
|
29198
|
+
if (matchArr.length === 0)
|
|
29199
|
+
errors.push(`${file.path} 必须有一个函数或类,错误代码:${file.content}`);
|
|
29200
|
+
else if (matchArr.length > 1)
|
|
29201
|
+
errors.push(`${file.path} 只能有一个函数或类,错误代码:${matchArr.map((match) => match[0]).join('\n')}
|
|
29202
|
+
你可以将该文件中所有函数合并,或者将其他函数拆到多个文件中。`);
|
|
29203
|
+
for (const match of matchArr) {
|
|
29204
|
+
const [, isExport, isDeclare, type, name] = match;
|
|
29205
|
+
if (!isExport)
|
|
29206
|
+
errors.push(`${file.path} 必须使用 export,错误代码:${match[0]}`);
|
|
29207
|
+
if (name !== nameFromPath)
|
|
29208
|
+
errors.push(`${file.path} 的函数或类名必须与文件名一致,错误代码:${match[0]}`);
|
|
29209
|
+
if (/\.(entities|enums|structures)/.test(namespace) && type !== 'class')
|
|
29210
|
+
errors.push(`${file.path} 实体、数据结构和枚举只能使用 class 定义,错误代码:${match[0]}`);
|
|
29211
|
+
if (/\.(logics|views)/.test(namespace) && type !== 'function')
|
|
29212
|
+
errors.push(`${file.path} 逻辑和页面只能使用 function 定义,错误代码:${match[0]}`);
|
|
29213
|
+
}
|
|
29214
|
+
}
|
|
29145
29215
|
function composeToString(files) {
|
|
29146
29216
|
files.sort((a, b) => sorter(a.path, b.path));
|
|
29147
29217
|
const errors = [];
|
|
@@ -29149,28 +29219,26 @@ function composeToString(files) {
|
|
|
29149
29219
|
const arr = file.path.split('.');
|
|
29150
29220
|
const ext = arr.pop();
|
|
29151
29221
|
const nameFromPath = arr.pop();
|
|
29152
|
-
|
|
29222
|
+
// 判断是否是特殊文件类型(variables 或 extensions)
|
|
29223
|
+
const isVariablesFile = nameFromPath === 'variables';
|
|
29224
|
+
const isExtensionsFile = arr[0] === 'extensions';
|
|
29225
|
+
const isSpecialFile = isVariablesFile || isExtensionsFile;
|
|
29226
|
+
// 特殊文件的 namespace 包含文件名,普通文件不包含
|
|
29227
|
+
const namespace = isSpecialFile ? [...arr, nameFromPath].join('.') : arr.join('.');
|
|
29153
29228
|
if (['ts', 'tsx'].includes(ext)) {
|
|
29154
|
-
|
|
29155
|
-
|
|
29156
|
-
|
|
29157
|
-
else if (
|
|
29158
|
-
|
|
29159
|
-
|
|
29160
|
-
|
|
29161
|
-
|
|
29162
|
-
if (!isExport)
|
|
29163
|
-
errors.push(`${file.path} 必须使用 export,错误代码:${match[0]}`);
|
|
29164
|
-
if (name !== nameFromPath)
|
|
29165
|
-
errors.push(`${file.path} 的函数或类名必须与文件名一致,错误代码:${match[0]}`);
|
|
29166
|
-
if (/\.(entities|enums|structures)/.test(namespace) && type !== 'class')
|
|
29167
|
-
errors.push(`${file.path} 实体、数据结构和枚举只能使用 class 定义,错误代码:${match[0]}`);
|
|
29168
|
-
if (/\.(logics|views)/.test(namespace) && type !== 'function')
|
|
29169
|
-
errors.push(`${file.path} 逻辑和页面只能使用 function 定义,错误代码:${match[0]}`);
|
|
29229
|
+
if (isVariablesFile) {
|
|
29230
|
+
validateVariablesFile(file, errors);
|
|
29231
|
+
}
|
|
29232
|
+
else if (isExtensionsFile) {
|
|
29233
|
+
validateExtensionsFile(file, errors);
|
|
29234
|
+
}
|
|
29235
|
+
else {
|
|
29236
|
+
validateNormalFile(file, nameFromPath, namespace, errors);
|
|
29170
29237
|
}
|
|
29171
29238
|
}
|
|
29172
29239
|
return `namespace ${namespace} {\n${file.content}\n}\n`;
|
|
29173
|
-
})
|
|
29240
|
+
})
|
|
29241
|
+
.join('\n');
|
|
29174
29242
|
if (errors.length > 0) {
|
|
29175
29243
|
throw new Error(errors.join('\n============\n'));
|
|
29176
29244
|
}
|
|
@@ -37731,11 +37799,13 @@ async function scanEntryFiles(projectRoot, patterns, logger) {
|
|
|
37731
37799
|
*/
|
|
37732
37800
|
function extractDeps(content) {
|
|
37733
37801
|
const deps = new Set();
|
|
37734
|
-
//
|
|
37802
|
+
// 预处理:移除注释和字符串字面量,避免它们影响依赖分析
|
|
37735
37803
|
let processedContent = content
|
|
37736
37804
|
.replace(/\/\/.*$/gm, '') // 移除单行注释 // ...
|
|
37737
|
-
.replace(/\/\*[\s\S]*?\*\//g, '')
|
|
37738
|
-
|
|
37805
|
+
.replace(/\/\*[\s\S]*?\*\//g, '') // 移除多行注释 /* ... */
|
|
37806
|
+
.replace(/'(?:[^'\\]|\\.)*'/g, '') // 移除单引号字符串 'xxx'
|
|
37807
|
+
.replace(/"(?:[^"\\]|\\.)*"/g, ''); // 移除双引号字符串 "xxx"
|
|
37808
|
+
const allMatches = processedContent.matchAll(/(app|extensions)\.\w+\.[\w.]+/g); // 起码要2个点,支持 app.* 和 extensions.*
|
|
37739
37809
|
for (const match of allMatches) {
|
|
37740
37810
|
let dep = match[0];
|
|
37741
37811
|
if (/Entity$|Entity\./.test(dep)) {
|
|
@@ -37744,6 +37814,14 @@ function extractDeps(content) {
|
|
|
37744
37814
|
else if (/\.enums\.(\w+)\.(\w+)/.test(dep)) {
|
|
37745
37815
|
dep = dep.replace(/\.enums\.(\w+).+$/, '.enums.$1');
|
|
37746
37816
|
}
|
|
37817
|
+
else if (/\.variables\.(\w+)/.test(dep)) {
|
|
37818
|
+
// 处理 variables 依赖:app.backend.variables.xxx -> app.backend.variables
|
|
37819
|
+
dep = dep.replace(/\.variables\..+$/, '.variables');
|
|
37820
|
+
}
|
|
37821
|
+
else if (/^extensions\.\w+\.\w+/.test(dep)) {
|
|
37822
|
+
// 处理 extensions 依赖:extensions.lcap_auth.xxx -> extensions.lcap_auth
|
|
37823
|
+
dep = dep.replace(/^(extensions\.\w+)\..+$/, '$1');
|
|
37824
|
+
}
|
|
37747
37825
|
else if (/app\.dataSources\.\w+\.entities\.\w+\.\w+$/.test(dep)) {
|
|
37748
37826
|
continue; // 应该是写法有问题,跳过让后面的 checker 做检查
|
|
37749
37827
|
}
|
|
@@ -37865,7 +37943,12 @@ async function collectDeps(patterns, projectRoot, srcDir, logger, verbose) {
|
|
|
37865
37943
|
while (filesToProcess.length > 0) {
|
|
37866
37944
|
const pathRelativeToSrc = filesToProcess.shift();
|
|
37867
37945
|
if (processedFileMap.has(pathRelativeToSrc))
|
|
37868
|
-
continue; // 跳过已处理的文件
|
|
37946
|
+
continue; // 跳过已处理的文件
|
|
37947
|
+
// 检查文件类型是否支持
|
|
37948
|
+
if (!isKnownFileType(pathRelativeToSrc)) {
|
|
37949
|
+
logger.warn(`跳过不支持的文件类型: ${pathRelativeToSrc}`);
|
|
37950
|
+
continue;
|
|
37951
|
+
}
|
|
37869
37952
|
try {
|
|
37870
37953
|
const { fileInfo, newDeps } = processFileDeps(pathRelativeToSrc, srcDir, matchedFileSet, processedFileMap, depNotFoundList, logger, verbose);
|
|
37871
37954
|
result.push(fileInfo);
|
|
@@ -37943,8 +38026,18 @@ async function resolveNASLFiles(entry, logger, depMode, verbose) {
|
|
|
37943
38026
|
}
|
|
37944
38027
|
logger.info(`找到 ${collectedFiles.length} 个 NASL 文件`);
|
|
37945
38028
|
}
|
|
38029
|
+
// 统一过滤掉不支持的文件类型
|
|
38030
|
+
const filteredFiles = [];
|
|
38031
|
+
collectedFiles.forEach((file) => {
|
|
38032
|
+
if (isKnownFileType(file.path)) {
|
|
38033
|
+
filteredFiles.push(file);
|
|
38034
|
+
}
|
|
38035
|
+
else {
|
|
38036
|
+
logger.warn(`跳过不支持的文件类型: ${file.path}`);
|
|
38037
|
+
}
|
|
38038
|
+
});
|
|
37946
38039
|
return {
|
|
37947
|
-
collectedFiles,
|
|
38040
|
+
collectedFiles: filteredFiles,
|
|
37948
38041
|
config,
|
|
37949
38042
|
projectRoot,
|
|
37950
38043
|
srcDir,
|
|
@@ -37993,7 +38086,7 @@ async function tryCompile(entry, options) {
|
|
|
37993
38086
|
}
|
|
37994
38087
|
}
|
|
37995
38088
|
|
|
37996
|
-
var version = "0.1.
|
|
38089
|
+
var version = "0.1.19";
|
|
37997
38090
|
var pkg = {
|
|
37998
38091
|
version: version};
|
|
37999
38092
|
|