@nasl/cli 0.2.1 → 0.2.3
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/dist/bin/nasl.mjs +84 -8
- package/dist/bin/nasl.mjs.map +1 -1
- package/dist/bin/naslc.mjs +14 -4
- package/dist/bin/naslc.mjs.map +1 -1
- package/dist/index.mjs +81 -5
- package/dist/index.mjs.map +1 -1
- package/out/apis/createAxios.js +2 -2
- package/out/apis/createAxios.js.map +1 -1
- package/out/bin/nasl.js +2 -2
- package/out/bin/nasl.js.map +1 -1
- package/out/commands/check.d.ts.map +1 -1
- package/out/commands/check.js +10 -0
- package/out/commands/check.js.map +1 -1
- package/out/commands/createAppInIde.js +2 -2
- package/out/commands/createAppInIde.js.map +1 -1
- package/out/services/compose.d.ts.map +1 -1
- package/out/services/compose.js +11 -1
- package/out/services/compose.js.map +1 -1
- package/out/types/api.d.ts +4 -0
- package/out/types/api.d.ts.map +1 -1
- package/out/utils/errorMapper.d.ts +14 -0
- package/out/utils/errorMapper.d.ts.map +1 -0
- package/out/utils/errorMapper.js +60 -0
- package/out/utils/errorMapper.js.map +1 -0
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -114,7 +114,10 @@ function validateNormalFile(file, nameFromPath, namespace, errors) {
|
|
|
114
114
|
function composeToString(files) {
|
|
115
115
|
files.sort((a, b) => sorter(a.path, b.path));
|
|
116
116
|
const errors = [];
|
|
117
|
+
let currentLine = 1;
|
|
117
118
|
const result = files.map((file) => {
|
|
119
|
+
// 记录这个文件的开始行号
|
|
120
|
+
file.startLine = currentLine;
|
|
118
121
|
const arr = file.path.split('.');
|
|
119
122
|
const ext = arr.pop();
|
|
120
123
|
const nameFromPath = arr.pop();
|
|
@@ -140,7 +143,14 @@ function composeToString(files) {
|
|
|
140
143
|
else if (isThemeCss) {
|
|
141
144
|
content = ` $theme\`${content}\`;`;
|
|
142
145
|
}
|
|
143
|
-
|
|
146
|
+
const fileContent = `namespace ${namespace} {\n${content}\n}\n`;
|
|
147
|
+
// 计算这个文件占用的行数(末尾 \n 导致 split 多一个空元素,减 1 得到实际行数)
|
|
148
|
+
const lineCount = fileContent.split('\n').length - 1;
|
|
149
|
+
// 记录这个文件的结束行号
|
|
150
|
+
file.endLine = currentLine + lineCount - 1;
|
|
151
|
+
// +1 是 join('\n') 在文件之间插入的换行符
|
|
152
|
+
currentLine = file.endLine + 2;
|
|
153
|
+
return fileContent;
|
|
144
154
|
})
|
|
145
155
|
.join('\n');
|
|
146
156
|
if (errors.length > 0) {
|
|
@@ -34817,7 +34827,7 @@ async function generateCompleteHeaders(options) {
|
|
|
34817
34827
|
async function createAxios(options) {
|
|
34818
34828
|
// 如果需要鉴权,拼接 /openapi/v3/nasl;否则使用原始 URL
|
|
34819
34829
|
const serverBaseURL = new URL(options.serverBaseURL).origin;
|
|
34820
|
-
const baseURL = options.useOPENAPI ? `${serverBaseURL}/openapi/v3/nasl` : `${serverBaseURL}/api/v1/nasl`;
|
|
34830
|
+
const baseURL = options.serverBaseURL.endsWith('app-ai-creator') ? options.serverBaseURL : options.useOPENAPI ? `${serverBaseURL}/openapi/v3/nasl` : `${serverBaseURL}/api/v1/nasl`;
|
|
34821
34831
|
// 如果需要鉴权,生成完整的认证头;否则只使用基础 headers
|
|
34822
34832
|
const headers = options.useOPENAPI ? await generateCompleteHeaders(options) : { 'Content-Type': 'application/json' };
|
|
34823
34833
|
console.log('本次服务调用方为:', baseURL);
|
|
@@ -34830,7 +34840,7 @@ async function createAxios(options) {
|
|
|
34830
34840
|
instance.post = async (url, data, config) => {
|
|
34831
34841
|
return oldPost(url, data, config).then((res) => {
|
|
34832
34842
|
const data = res.data;
|
|
34833
|
-
if (data.code !== 200)
|
|
34843
|
+
if (data.code !== 200 && data.success !== true)
|
|
34834
34844
|
throw new Error(JSON.stringify(data));
|
|
34835
34845
|
return res;
|
|
34836
34846
|
}).catch((err) => {
|
|
@@ -34982,6 +34992,63 @@ async function tryCompile(entry, options) {
|
|
|
34982
34992
|
}
|
|
34983
34993
|
}
|
|
34984
34994
|
|
|
34995
|
+
/**
|
|
34996
|
+
* 将错误信息中的行号映射回原始文件
|
|
34997
|
+
* 直接替换错误头中的文件路径和行号,并调整代码片段中的行号
|
|
34998
|
+
*/
|
|
34999
|
+
function mapErrorToSourceFile(options) {
|
|
35000
|
+
const { errorMessage, collectedFiles } = options;
|
|
35001
|
+
// 构建行号到文件的映射
|
|
35002
|
+
const lineToFileMap = new Map();
|
|
35003
|
+
collectedFiles.forEach((file) => {
|
|
35004
|
+
if (file.startLine !== undefined && file.endLine !== undefined) {
|
|
35005
|
+
for (let i = file.startLine; i <= file.endLine; i++) {
|
|
35006
|
+
const lineInFile = i - file.startLine;
|
|
35007
|
+
lineToFileMap.set(i, { file, lineInFile });
|
|
35008
|
+
}
|
|
35009
|
+
}
|
|
35010
|
+
});
|
|
35011
|
+
// 处理单个错误块:替换路径、行号,调整代码片段行号
|
|
35012
|
+
function processBlock(block) {
|
|
35013
|
+
// 匹配错误头: 可选的 "N. " 前缀 + "filepath: message (line:col)"
|
|
35014
|
+
const headerMatch = block.match(/^((?:\d+\.\s+)?)(.*?):\s+(.*?)\((\d+):(\d+)\)/);
|
|
35015
|
+
if (!headerMatch)
|
|
35016
|
+
return block;
|
|
35017
|
+
const [fullHeader, prefix, , message, lineStr, colStr] = headerMatch;
|
|
35018
|
+
const originalLine = parseInt(lineStr, 10);
|
|
35019
|
+
const fileInfo = lineToFileMap.get(originalLine);
|
|
35020
|
+
if (!fileInfo)
|
|
35021
|
+
return block;
|
|
35022
|
+
const { file, lineInFile } = fileInfo;
|
|
35023
|
+
const lineOffset = originalLine - lineInFile;
|
|
35024
|
+
// 替换错误头中的路径和行号
|
|
35025
|
+
let mapped = block.replace(fullHeader, `${prefix}${file.path}: ${message}(${lineInFile}:${colStr})`);
|
|
35026
|
+
// 收集代码片段中所有行号并计算映射后的值
|
|
35027
|
+
const snippetNumbers = [];
|
|
35028
|
+
const collectRegex = /^([> ]*?)(\d+)(\s*\|)/gm;
|
|
35029
|
+
let m;
|
|
35030
|
+
while ((m = collectRegex.exec(mapped)) !== null) {
|
|
35031
|
+
snippetNumbers.push(parseInt(m[2], 10) - lineOffset);
|
|
35032
|
+
}
|
|
35033
|
+
// 替换代码片段中的行号,保持对齐
|
|
35034
|
+
if (snippetNumbers.length > 0) {
|
|
35035
|
+
const maxWidth = Math.max(...snippetNumbers.map((n) => String(n).length));
|
|
35036
|
+
let idx = 0;
|
|
35037
|
+
mapped = mapped.replace(/^([> ]*?)(\d+)(\s*\|)/gm, (fullMatch, lead) => {
|
|
35038
|
+
const newNum = snippetNumbers[idx++];
|
|
35039
|
+
if (newNum <= 0)
|
|
35040
|
+
return fullMatch;
|
|
35041
|
+
const paddedNum = String(newNum).padStart(maxWidth);
|
|
35042
|
+
return lead.includes('>') ? `> ${paddedNum} |` : ` ${paddedNum} |`;
|
|
35043
|
+
});
|
|
35044
|
+
}
|
|
35045
|
+
return mapped;
|
|
35046
|
+
}
|
|
35047
|
+
// 按编号前缀分割为独立错误块,分别处理
|
|
35048
|
+
const parts = errorMessage.split(/(?=^\d+\.\s)/m);
|
|
35049
|
+
return parts.map(processBlock).join('');
|
|
35050
|
+
}
|
|
35051
|
+
|
|
34985
35052
|
/**
|
|
34986
35053
|
* 检查命令 - 检查 NASL 代码的语法和语义
|
|
34987
35054
|
*/
|
|
@@ -35003,6 +35070,13 @@ async function check(entry, options) {
|
|
|
35003
35070
|
}
|
|
35004
35071
|
if (!result && fullNaturalTS) {
|
|
35005
35072
|
result = (await checkApi(fullNaturalTS, config)).trim();
|
|
35073
|
+
// 如果有错误,尝试映射回原始文件
|
|
35074
|
+
if (result) {
|
|
35075
|
+
result = mapErrorToSourceFile({
|
|
35076
|
+
errorMessage: result,
|
|
35077
|
+
collectedFiles,
|
|
35078
|
+
});
|
|
35079
|
+
}
|
|
35006
35080
|
}
|
|
35007
35081
|
const checkResult = {
|
|
35008
35082
|
success: !result,
|
|
@@ -35012,6 +35086,8 @@ async function check(entry, options) {
|
|
|
35012
35086
|
fastLogToFile(entry || '*', `check_${checkResult.success ? 'success' : 'error'}.log`, result + '\n================================================\n\n================================================\n' + fullNaturalTS);
|
|
35013
35087
|
if (!checkResult.success)
|
|
35014
35088
|
logger.error('\n' + checkResult.result);
|
|
35089
|
+
else
|
|
35090
|
+
logger.success('发现 0 个错误,检查通过!');
|
|
35015
35091
|
return checkResult;
|
|
35016
35092
|
}
|
|
35017
35093
|
|
|
@@ -35300,10 +35376,10 @@ async function createAppInIde(entry, options) {
|
|
|
35300
35376
|
const projectRoot = getProjectRoot();
|
|
35301
35377
|
const firstSpecFolderName = getFirstSpecFolderName(projectRoot);
|
|
35302
35378
|
const suffix = dayjs().format('MMDDHHmmss');
|
|
35303
|
-
|
|
35304
|
-
let cleaned = firstSpecFolderName.replace(/[^a-zA-Z0-9]/g, '').replace(/^\d+/, '');
|
|
35379
|
+
let cleaned = firstSpecFolderName.replace(/[^a-zA-Z0-9]/g, '').replace(/^\d+/, '').slice(0, 12);
|
|
35305
35380
|
if (!cleaned)
|
|
35306
35381
|
cleaned = 'app';
|
|
35382
|
+
const appName = `${cleaned}_${suffix}`;
|
|
35307
35383
|
const packageName = `${cleaned}${suffix}`;
|
|
35308
35384
|
logger.info(`应用名称: ${appName}`);
|
|
35309
35385
|
logger.info(`包名: ${packageName}`);
|