@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/bin/nasl.mjs
CHANGED
|
@@ -29125,7 +29125,7 @@ async function generateCompleteHeaders(options) {
|
|
|
29125
29125
|
async function createAxios(options) {
|
|
29126
29126
|
// 如果需要鉴权,拼接 /openapi/v3/nasl;否则使用原始 URL
|
|
29127
29127
|
const serverBaseURL = new URL(options.serverBaseURL).origin;
|
|
29128
|
-
const baseURL = options.useOPENAPI ? `${serverBaseURL}/openapi/v3/nasl` : `${serverBaseURL}/api/v1/nasl`;
|
|
29128
|
+
const baseURL = options.serverBaseURL.endsWith('app-ai-creator') ? options.serverBaseURL : options.useOPENAPI ? `${serverBaseURL}/openapi/v3/nasl` : `${serverBaseURL}/api/v1/nasl`;
|
|
29129
29129
|
// 如果需要鉴权,生成完整的认证头;否则只使用基础 headers
|
|
29130
29130
|
const headers = options.useOPENAPI ? await generateCompleteHeaders(options) : { 'Content-Type': 'application/json' };
|
|
29131
29131
|
console.log('本次服务调用方为:', baseURL);
|
|
@@ -29138,7 +29138,7 @@ async function createAxios(options) {
|
|
|
29138
29138
|
instance.post = async (url, data, config) => {
|
|
29139
29139
|
return oldPost(url, data, config).then((res) => {
|
|
29140
29140
|
const data = res.data;
|
|
29141
|
-
if (data.code !== 200)
|
|
29141
|
+
if (data.code !== 200 && data.success !== true)
|
|
29142
29142
|
throw new Error(JSON.stringify(data));
|
|
29143
29143
|
return res;
|
|
29144
29144
|
}).catch((err) => {
|
|
@@ -29326,7 +29326,10 @@ function validateNormalFile(file, nameFromPath, namespace, errors) {
|
|
|
29326
29326
|
function composeToString(files) {
|
|
29327
29327
|
files.sort((a, b) => sorter(a.path, b.path));
|
|
29328
29328
|
const errors = [];
|
|
29329
|
+
let currentLine = 1;
|
|
29329
29330
|
const result = files.map((file) => {
|
|
29331
|
+
// 记录这个文件的开始行号
|
|
29332
|
+
file.startLine = currentLine;
|
|
29330
29333
|
const arr = file.path.split('.');
|
|
29331
29334
|
const ext = arr.pop();
|
|
29332
29335
|
const nameFromPath = arr.pop();
|
|
@@ -29352,7 +29355,14 @@ function composeToString(files) {
|
|
|
29352
29355
|
else if (isThemeCss) {
|
|
29353
29356
|
content = ` $theme\`${content}\`;`;
|
|
29354
29357
|
}
|
|
29355
|
-
|
|
29358
|
+
const fileContent = `namespace ${namespace} {\n${content}\n}\n`;
|
|
29359
|
+
// 计算这个文件占用的行数(末尾 \n 导致 split 多一个空元素,减 1 得到实际行数)
|
|
29360
|
+
const lineCount = fileContent.split('\n').length - 1;
|
|
29361
|
+
// 记录这个文件的结束行号
|
|
29362
|
+
file.endLine = currentLine + lineCount - 1;
|
|
29363
|
+
// +1 是 join('\n') 在文件之间插入的换行符
|
|
29364
|
+
currentLine = file.endLine + 2;
|
|
29365
|
+
return fileContent;
|
|
29356
29366
|
})
|
|
29357
29367
|
.join('\n');
|
|
29358
29368
|
if (errors.length > 0) {
|
|
@@ -38312,6 +38322,63 @@ async function tryCompile(entry, options) {
|
|
|
38312
38322
|
}
|
|
38313
38323
|
}
|
|
38314
38324
|
|
|
38325
|
+
/**
|
|
38326
|
+
* 将错误信息中的行号映射回原始文件
|
|
38327
|
+
* 直接替换错误头中的文件路径和行号,并调整代码片段中的行号
|
|
38328
|
+
*/
|
|
38329
|
+
function mapErrorToSourceFile(options) {
|
|
38330
|
+
const { errorMessage, collectedFiles } = options;
|
|
38331
|
+
// 构建行号到文件的映射
|
|
38332
|
+
const lineToFileMap = new Map();
|
|
38333
|
+
collectedFiles.forEach((file) => {
|
|
38334
|
+
if (file.startLine !== undefined && file.endLine !== undefined) {
|
|
38335
|
+
for (let i = file.startLine; i <= file.endLine; i++) {
|
|
38336
|
+
const lineInFile = i - file.startLine;
|
|
38337
|
+
lineToFileMap.set(i, { file, lineInFile });
|
|
38338
|
+
}
|
|
38339
|
+
}
|
|
38340
|
+
});
|
|
38341
|
+
// 处理单个错误块:替换路径、行号,调整代码片段行号
|
|
38342
|
+
function processBlock(block) {
|
|
38343
|
+
// 匹配错误头: 可选的 "N. " 前缀 + "filepath: message (line:col)"
|
|
38344
|
+
const headerMatch = block.match(/^((?:\d+\.\s+)?)(.*?):\s+(.*?)\((\d+):(\d+)\)/);
|
|
38345
|
+
if (!headerMatch)
|
|
38346
|
+
return block;
|
|
38347
|
+
const [fullHeader, prefix, , message, lineStr, colStr] = headerMatch;
|
|
38348
|
+
const originalLine = parseInt(lineStr, 10);
|
|
38349
|
+
const fileInfo = lineToFileMap.get(originalLine);
|
|
38350
|
+
if (!fileInfo)
|
|
38351
|
+
return block;
|
|
38352
|
+
const { file, lineInFile } = fileInfo;
|
|
38353
|
+
const lineOffset = originalLine - lineInFile;
|
|
38354
|
+
// 替换错误头中的路径和行号
|
|
38355
|
+
let mapped = block.replace(fullHeader, `${prefix}${file.path}: ${message}(${lineInFile}:${colStr})`);
|
|
38356
|
+
// 收集代码片段中所有行号并计算映射后的值
|
|
38357
|
+
const snippetNumbers = [];
|
|
38358
|
+
const collectRegex = /^([> ]*?)(\d+)(\s*\|)/gm;
|
|
38359
|
+
let m;
|
|
38360
|
+
while ((m = collectRegex.exec(mapped)) !== null) {
|
|
38361
|
+
snippetNumbers.push(parseInt(m[2], 10) - lineOffset);
|
|
38362
|
+
}
|
|
38363
|
+
// 替换代码片段中的行号,保持对齐
|
|
38364
|
+
if (snippetNumbers.length > 0) {
|
|
38365
|
+
const maxWidth = Math.max(...snippetNumbers.map((n) => String(n).length));
|
|
38366
|
+
let idx = 0;
|
|
38367
|
+
mapped = mapped.replace(/^([> ]*?)(\d+)(\s*\|)/gm, (fullMatch, lead) => {
|
|
38368
|
+
const newNum = snippetNumbers[idx++];
|
|
38369
|
+
if (newNum <= 0)
|
|
38370
|
+
return fullMatch;
|
|
38371
|
+
const paddedNum = String(newNum).padStart(maxWidth);
|
|
38372
|
+
return lead.includes('>') ? `> ${paddedNum} |` : ` ${paddedNum} |`;
|
|
38373
|
+
});
|
|
38374
|
+
}
|
|
38375
|
+
return mapped;
|
|
38376
|
+
}
|
|
38377
|
+
// 按编号前缀分割为独立错误块,分别处理
|
|
38378
|
+
const parts = errorMessage.split(/(?=^\d+\.\s)/m);
|
|
38379
|
+
return parts.map(processBlock).join('');
|
|
38380
|
+
}
|
|
38381
|
+
|
|
38315
38382
|
/**
|
|
38316
38383
|
* 检查命令 - 检查 NASL 代码的语法和语义
|
|
38317
38384
|
*/
|
|
@@ -38333,6 +38400,13 @@ async function check(entry, options) {
|
|
|
38333
38400
|
}
|
|
38334
38401
|
if (!result && fullNaturalTS) {
|
|
38335
38402
|
result = (await checkApi(fullNaturalTS, config)).trim();
|
|
38403
|
+
// 如果有错误,尝试映射回原始文件
|
|
38404
|
+
if (result) {
|
|
38405
|
+
result = mapErrorToSourceFile({
|
|
38406
|
+
errorMessage: result,
|
|
38407
|
+
collectedFiles,
|
|
38408
|
+
});
|
|
38409
|
+
}
|
|
38336
38410
|
}
|
|
38337
38411
|
const checkResult = {
|
|
38338
38412
|
success: !result,
|
|
@@ -38342,6 +38416,8 @@ async function check(entry, options) {
|
|
|
38342
38416
|
fastLogToFile(entry || '*', `check_${checkResult.success ? 'success' : 'error'}.log`, result + '\n================================================\n\n================================================\n' + fullNaturalTS);
|
|
38343
38417
|
if (!checkResult.success)
|
|
38344
38418
|
logger.error('\n' + checkResult.result);
|
|
38419
|
+
else
|
|
38420
|
+
logger.success('发现 0 个错误,检查通过!');
|
|
38345
38421
|
return checkResult;
|
|
38346
38422
|
}
|
|
38347
38423
|
|
|
@@ -38630,10 +38706,10 @@ async function createAppInIde(entry, options) {
|
|
|
38630
38706
|
const projectRoot = getProjectRoot();
|
|
38631
38707
|
const firstSpecFolderName = getFirstSpecFolderName(projectRoot);
|
|
38632
38708
|
const suffix = dayjs().format('MMDDHHmmss');
|
|
38633
|
-
|
|
38634
|
-
let cleaned = firstSpecFolderName.replace(/[^a-zA-Z0-9]/g, '').replace(/^\d+/, '');
|
|
38709
|
+
let cleaned = firstSpecFolderName.replace(/[^a-zA-Z0-9]/g, '').replace(/^\d+/, '').slice(0, 12);
|
|
38635
38710
|
if (!cleaned)
|
|
38636
38711
|
cleaned = 'app';
|
|
38712
|
+
const appName = `${cleaned}_${suffix}`;
|
|
38637
38713
|
const packageName = `${cleaned}${suffix}`;
|
|
38638
38714
|
logger.info(`应用名称: ${appName}`);
|
|
38639
38715
|
logger.info(`包名: ${packageName}`);
|
|
@@ -38763,7 +38839,7 @@ async function transform(transformType, entry, options) {
|
|
|
38763
38839
|
await transformFn(entry, options);
|
|
38764
38840
|
}
|
|
38765
38841
|
|
|
38766
|
-
var version = "0.2.
|
|
38842
|
+
var version = "0.2.3";
|
|
38767
38843
|
var pkg = {
|
|
38768
38844
|
version: version};
|
|
38769
38845
|
|
|
@@ -38780,7 +38856,7 @@ function askForConfirmation(question) {
|
|
|
38780
38856
|
rl.question(question, (answer) => {
|
|
38781
38857
|
rl.close();
|
|
38782
38858
|
const normalizedAnswer = answer.trim().toLowerCase();
|
|
38783
|
-
resolve(normalizedAnswer === 'y' || normalizedAnswer === 'yes' || normalizedAnswer === '是');
|
|
38859
|
+
resolve(!normalizedAnswer || normalizedAnswer === 'y' || normalizedAnswer === 'yes' || normalizedAnswer === '是');
|
|
38784
38860
|
});
|
|
38785
38861
|
});
|
|
38786
38862
|
}
|
|
@@ -38873,7 +38949,7 @@ program
|
|
|
38873
38949
|
if (!options?.quiet) {
|
|
38874
38950
|
defaultLogger.newLine();
|
|
38875
38951
|
defaultLogger.info('即将在 IDE 中创建新的应用,此操作将调用远程接口。');
|
|
38876
|
-
const confirmed = await askForConfirmation('请确认是否继续?(
|
|
38952
|
+
const confirmed = await askForConfirmation('请确认是否继续?(Y/n): ');
|
|
38877
38953
|
if (!confirmed) {
|
|
38878
38954
|
defaultLogger.info('已取消操作');
|
|
38879
38955
|
process.exit(0);
|