@nasl/cli 0.2.3 → 0.3.0
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 +516 -126
- package/dist/bin/nasl.mjs.map +1 -1
- package/dist/bin/naslc.mjs +311 -58
- package/dist/bin/naslc.mjs.map +1 -1
- package/dist/index.mjs +11610 -11255
- package/dist/index.mjs.map +1 -1
- package/out/apis/compileApi.d.ts.map +1 -1
- package/out/apis/compileApi.js +3 -2
- package/out/apis/compileApi.js.map +1 -1
- package/out/apis/dependencyApi.d.ts +29 -0
- package/out/apis/dependencyApi.d.ts.map +1 -0
- package/out/apis/dependencyApi.js +17 -0
- package/out/apis/dependencyApi.js.map +1 -0
- package/out/apis/index.d.ts +1 -0
- package/out/apis/index.d.ts.map +1 -1
- package/out/apis/index.js +1 -0
- package/out/apis/index.js.map +1 -1
- package/out/apis/openapi.d.ts +12 -0
- package/out/apis/openapi.d.ts.map +1 -1
- package/out/apis/openapi.js +15 -0
- package/out/apis/openapi.js.map +1 -1
- package/out/apis/transformApi.d.ts.map +1 -1
- package/out/apis/transformApi.js +2 -0
- package/out/apis/transformApi.js.map +1 -1
- package/out/bin/nasl.js +38 -2
- package/out/bin/nasl.js.map +1 -1
- package/out/commands/check.d.ts.map +1 -1
- package/out/commands/check.js +2 -1
- package/out/commands/check.js.map +1 -1
- package/out/commands/compile.d.ts.map +1 -1
- package/out/commands/compile.js +3 -2
- package/out/commands/compile.js.map +1 -1
- package/out/commands/dep.d.ts +4 -2
- package/out/commands/dep.d.ts.map +1 -1
- package/out/commands/dep.js +44 -2
- package/out/commands/dep.js.map +1 -1
- package/out/commands/index.d.ts +1 -0
- package/out/commands/index.d.ts.map +1 -1
- package/out/commands/index.js +1 -0
- package/out/commands/index.js.map +1 -1
- package/out/commands/install.d.ts +9 -0
- package/out/commands/install.d.ts.map +1 -0
- package/out/commands/install.js +123 -0
- package/out/commands/install.js.map +1 -0
- package/out/commands/transform.d.ts.map +1 -1
- package/out/commands/transform.js +3 -2
- package/out/commands/transform.js.map +1 -1
- package/out/constants/nasl-file-types.d.ts.map +1 -1
- package/out/constants/nasl-file-types.js +21 -0
- package/out/constants/nasl-file-types.js.map +1 -1
- package/out/services/compose.d.ts +8 -0
- package/out/services/compose.d.ts.map +1 -1
- package/out/services/compose.js +20 -0
- package/out/services/compose.js.map +1 -1
- package/out/services/resolve.d.ts +18 -0
- package/out/services/resolve.d.ts.map +1 -1
- package/out/services/resolve.js +208 -9
- package/out/services/resolve.js.map +1 -1
- package/out/types/config.d.ts +2 -0
- package/out/types/config.d.ts.map +1 -1
- package/out/types/config.js +1 -0
- package/out/types/config.js.map +1 -1
- package/out/utils/config.d.ts.map +1 -1
- package/out/utils/config.js +2 -0
- package/out/utils/config.js.map +1 -1
- package/package.json +1 -1
package/dist/bin/nasl.mjs
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
#!/usr/bin/env node
|
|
3
2
|
import require$$0$1, { EventEmitter } from 'events';
|
|
4
3
|
import require$$1, { spawn, spawnSync } from 'child_process';
|
|
5
|
-
import * as
|
|
6
|
-
import
|
|
4
|
+
import * as path$1 from 'path';
|
|
5
|
+
import path__default, { join } from 'path';
|
|
7
6
|
import require$$0$2, { promises, unwatchFile, watchFile, watch as watch$1, stat as stat$3 } from 'fs';
|
|
8
7
|
import require$$4 from 'process';
|
|
9
8
|
import require$$0$3 from 'constants';
|
|
@@ -1171,7 +1170,7 @@ function requireCommand () {
|
|
|
1171
1170
|
hasRequiredCommand = 1;
|
|
1172
1171
|
const EventEmitter = require$$0$1.EventEmitter;
|
|
1173
1172
|
const childProcess = require$$1;
|
|
1174
|
-
const path =
|
|
1173
|
+
const path = path__default;
|
|
1175
1174
|
const fs = require$$0$2;
|
|
1176
1175
|
const process = require$$4;
|
|
1177
1176
|
|
|
@@ -4581,7 +4580,7 @@ var hasRequiredUtils$5;
|
|
|
4581
4580
|
function requireUtils$5 () {
|
|
4582
4581
|
if (hasRequiredUtils$5) return utils$7;
|
|
4583
4582
|
hasRequiredUtils$5 = 1;
|
|
4584
|
-
const path =
|
|
4583
|
+
const path = path__default;
|
|
4585
4584
|
|
|
4586
4585
|
// https://github.com/nodejs/node/issues/8987
|
|
4587
4586
|
// https://github.com/libuv/libuv/pull/1088
|
|
@@ -4727,7 +4726,7 @@ function requireStat () {
|
|
|
4727
4726
|
hasRequiredStat = 1;
|
|
4728
4727
|
|
|
4729
4728
|
const fs = /*@__PURE__*/ requireFs$4();
|
|
4730
|
-
const path =
|
|
4729
|
+
const path = path__default;
|
|
4731
4730
|
const u = requireUniversalify().fromPromise;
|
|
4732
4731
|
|
|
4733
4732
|
function getStats (src, dest, opts) {
|
|
@@ -4931,7 +4930,7 @@ function requireCopy$1 () {
|
|
|
4931
4930
|
hasRequiredCopy$1 = 1;
|
|
4932
4931
|
|
|
4933
4932
|
const fs = /*@__PURE__*/ requireFs$4();
|
|
4934
|
-
const path =
|
|
4933
|
+
const path = path__default;
|
|
4935
4934
|
const { mkdirs } = /*@__PURE__*/ requireMkdirs();
|
|
4936
4935
|
const { pathExists } = /*@__PURE__*/ requirePathExists();
|
|
4937
4936
|
const { utimesMillis } = /*@__PURE__*/ requireUtimes();
|
|
@@ -5114,7 +5113,7 @@ function requireCopySync () {
|
|
|
5114
5113
|
hasRequiredCopySync = 1;
|
|
5115
5114
|
|
|
5116
5115
|
const fs = requireGracefulFs();
|
|
5117
|
-
const path =
|
|
5116
|
+
const path = path__default;
|
|
5118
5117
|
const mkdirsSync = /*@__PURE__*/ requireMkdirs().mkdirsSync;
|
|
5119
5118
|
const utimesMillisSync = /*@__PURE__*/ requireUtimes().utimesMillisSync;
|
|
5120
5119
|
const stat = /*@__PURE__*/ requireStat();
|
|
@@ -5334,7 +5333,7 @@ function requireEmpty () {
|
|
|
5334
5333
|
|
|
5335
5334
|
const u = requireUniversalify().fromPromise;
|
|
5336
5335
|
const fs = /*@__PURE__*/ requireFs$4();
|
|
5337
|
-
const path =
|
|
5336
|
+
const path = path__default;
|
|
5338
5337
|
const mkdir = /*@__PURE__*/ requireMkdirs();
|
|
5339
5338
|
const remove = /*@__PURE__*/ requireRemove();
|
|
5340
5339
|
|
|
@@ -5380,7 +5379,7 @@ function requireFile () {
|
|
|
5380
5379
|
hasRequiredFile = 1;
|
|
5381
5380
|
|
|
5382
5381
|
const u = requireUniversalify().fromPromise;
|
|
5383
|
-
const path =
|
|
5382
|
+
const path = path__default;
|
|
5384
5383
|
const fs = /*@__PURE__*/ requireFs$4();
|
|
5385
5384
|
const mkdir = /*@__PURE__*/ requireMkdirs();
|
|
5386
5385
|
|
|
@@ -5454,7 +5453,7 @@ function requireLink () {
|
|
|
5454
5453
|
hasRequiredLink = 1;
|
|
5455
5454
|
|
|
5456
5455
|
const u = requireUniversalify().fromPromise;
|
|
5457
|
-
const path =
|
|
5456
|
+
const path = path__default;
|
|
5458
5457
|
const fs = /*@__PURE__*/ requireFs$4();
|
|
5459
5458
|
const mkdir = /*@__PURE__*/ requireMkdirs();
|
|
5460
5459
|
const { pathExists } = /*@__PURE__*/ requirePathExists();
|
|
@@ -5525,7 +5524,7 @@ function requireSymlinkPaths () {
|
|
|
5525
5524
|
if (hasRequiredSymlinkPaths) return symlinkPaths_1;
|
|
5526
5525
|
hasRequiredSymlinkPaths = 1;
|
|
5527
5526
|
|
|
5528
|
-
const path =
|
|
5527
|
+
const path = path__default;
|
|
5529
5528
|
const fs = /*@__PURE__*/ requireFs$4();
|
|
5530
5529
|
const { pathExists } = /*@__PURE__*/ requirePathExists();
|
|
5531
5530
|
|
|
@@ -5677,7 +5676,7 @@ function requireSymlink () {
|
|
|
5677
5676
|
hasRequiredSymlink = 1;
|
|
5678
5677
|
|
|
5679
5678
|
const u = requireUniversalify().fromPromise;
|
|
5680
|
-
const path =
|
|
5679
|
+
const path = path__default;
|
|
5681
5680
|
const fs = /*@__PURE__*/ requireFs$4();
|
|
5682
5681
|
|
|
5683
5682
|
const { mkdirs, mkdirsSync } = /*@__PURE__*/ requireMkdirs();
|
|
@@ -5923,7 +5922,7 @@ function requireOutputFile () {
|
|
|
5923
5922
|
|
|
5924
5923
|
const u = requireUniversalify().fromPromise;
|
|
5925
5924
|
const fs = /*@__PURE__*/ requireFs$4();
|
|
5926
|
-
const path =
|
|
5925
|
+
const path = path__default;
|
|
5927
5926
|
const mkdir = /*@__PURE__*/ requireMkdirs();
|
|
5928
5927
|
const pathExists = /*@__PURE__*/ requirePathExists().pathExists;
|
|
5929
5928
|
|
|
@@ -6025,7 +6024,7 @@ function requireMove$1 () {
|
|
|
6025
6024
|
hasRequiredMove$1 = 1;
|
|
6026
6025
|
|
|
6027
6026
|
const fs = /*@__PURE__*/ requireFs$4();
|
|
6028
|
-
const path =
|
|
6027
|
+
const path = path__default;
|
|
6029
6028
|
const { copy } = /*@__PURE__*/ requireCopy();
|
|
6030
6029
|
const { remove } = /*@__PURE__*/ requireRemove();
|
|
6031
6030
|
const { mkdirp } = /*@__PURE__*/ requireMkdirs();
|
|
@@ -6092,7 +6091,7 @@ function requireMoveSync () {
|
|
|
6092
6091
|
hasRequiredMoveSync = 1;
|
|
6093
6092
|
|
|
6094
6093
|
const fs = requireGracefulFs();
|
|
6095
|
-
const path =
|
|
6094
|
+
const path = path__default;
|
|
6096
6095
|
const copySync = /*@__PURE__*/ requireCopy().copySync;
|
|
6097
6096
|
const removeSync = /*@__PURE__*/ requireRemove().removeSync;
|
|
6098
6097
|
const mkdirpSync = /*@__PURE__*/ requireMkdirs().mkdirpSync;
|
|
@@ -6198,6 +6197,7 @@ const DEFAULT_CONFIG = {
|
|
|
6198
6197
|
ideVersion: '4.4',
|
|
6199
6198
|
srcDir: 'src',
|
|
6200
6199
|
outDir: 'out',
|
|
6200
|
+
tenantName: 'defaulttenant',
|
|
6201
6201
|
};
|
|
6202
6202
|
/**
|
|
6203
6203
|
* 配置文件名称
|
|
@@ -8192,15 +8192,15 @@ var dayjs = /*@__PURE__*/getDefaultExportFromCjs(dayjs_minExports);
|
|
|
8192
8192
|
|
|
8193
8193
|
function fastLogToFile(entry, suffix, content) {
|
|
8194
8194
|
if (process.env.NASL_CLI_LOG_DIR) {
|
|
8195
|
-
const logDir =
|
|
8195
|
+
const logDir = path$1.resolve(process.env.NASL_CLI_LOG_DIR);
|
|
8196
8196
|
libExports.ensureDirSync(logDir);
|
|
8197
8197
|
const timeInDir = (process.env.NASL_CLI_LOG_DIR.match(/\d{6,8}_(\d{6})-/)?.[1] || '00');
|
|
8198
8198
|
const now = dayjs();
|
|
8199
8199
|
const hourInDir = parseInt(timeInDir.slice(0, 2), 10);
|
|
8200
8200
|
// 跨天则累加 24 小时
|
|
8201
8201
|
const hourStr = (now.hour() >= hourInDir ? now.hour() : Math.ceil(hourInDir / 24) * 24 + now.hour()).toString().padStart(2, '0');
|
|
8202
|
-
const entryName =
|
|
8203
|
-
const filePath =
|
|
8202
|
+
const entryName = path$1.basename(Array.isArray(entry) ? entry[0] || '*' : entry).replace(/[\[\]\(\)\{\}\+\-\*\?\|\^\$\#\:\,\\\/\s]+/g, '_');
|
|
8203
|
+
const filePath = path$1.resolve(logDir, `${hourStr}${now.format('mmss_SSS')}-${entryName}-${suffix}`);
|
|
8204
8204
|
libExports.outputFileSync(filePath, content);
|
|
8205
8205
|
}
|
|
8206
8206
|
}
|
|
@@ -8231,16 +8231,16 @@ class BaseLogger {
|
|
|
8231
8231
|
}
|
|
8232
8232
|
debugToFile(topic, ...args) {
|
|
8233
8233
|
if (process.env.DEBUG_TO_FILE) {
|
|
8234
|
-
const baseDir =
|
|
8234
|
+
const baseDir = path$1.join(process.cwd(), '.nasl');
|
|
8235
8235
|
const currentHour = dayjs().format('YYYYMMDD_HH');
|
|
8236
8236
|
const prevHour = dayjs().subtract(1, 'hour').format('YYYYMMDD_HH');
|
|
8237
8237
|
let subdir = `${topic}_${currentHour}`;
|
|
8238
8238
|
const prevSubdir = `${topic}_${prevHour}`;
|
|
8239
8239
|
// 判断如果有上一个小时的 subdir,则自己汇聚到上一个小时的 subdir 中
|
|
8240
|
-
if (libExports.existsSync(
|
|
8240
|
+
if (libExports.existsSync(path$1.join(baseDir, prevSubdir)))
|
|
8241
8241
|
subdir = prevSubdir;
|
|
8242
8242
|
const fileName = `${topic}_${dayjs().format('YYYYMMDD_HHmmss')}.log`;
|
|
8243
|
-
const filePath =
|
|
8243
|
+
const filePath = path$1.join(baseDir, subdir, fileName);
|
|
8244
8244
|
libExports.outputFileSync(filePath, args.join(' '));
|
|
8245
8245
|
}
|
|
8246
8246
|
}
|
|
@@ -8312,11 +8312,11 @@ function findConfigDir(startDir = process.cwd()) {
|
|
|
8312
8312
|
let currentDir = startDir;
|
|
8313
8313
|
// eslint-disable-next-line no-constant-condition
|
|
8314
8314
|
while (true) {
|
|
8315
|
-
const configPath =
|
|
8315
|
+
const configPath = path$1.join(currentDir, CONFIG_FILE_NAME);
|
|
8316
8316
|
if (libExports.existsSync(configPath)) {
|
|
8317
8317
|
return currentDir;
|
|
8318
8318
|
}
|
|
8319
|
-
const parentDir =
|
|
8319
|
+
const parentDir = path$1.dirname(currentDir);
|
|
8320
8320
|
// 已经到达根目录
|
|
8321
8321
|
if (parentDir === currentDir) {
|
|
8322
8322
|
return null;
|
|
@@ -8333,7 +8333,7 @@ function loadConfig(configDir) {
|
|
|
8333
8333
|
defaultLogger.error(`未找到配置文件 ${CONFIG_FILE_NAME},请先运行 nasl-init 初始化配置`);
|
|
8334
8334
|
return defaultLogger.exit(1);
|
|
8335
8335
|
}
|
|
8336
|
-
const configPath =
|
|
8336
|
+
const configPath = path$1.join(dir, CONFIG_FILE_NAME);
|
|
8337
8337
|
try {
|
|
8338
8338
|
const content = libExports.readFileSync(configPath, 'utf-8');
|
|
8339
8339
|
const config = JSON.parse(content);
|
|
@@ -8364,6 +8364,8 @@ function loadConfig(configDir) {
|
|
|
8364
8364
|
config.OPENAPI_AK = process.env.LCAP_OPENAPI_AK;
|
|
8365
8365
|
if (process.env.LCAP_OPENAPI_SK)
|
|
8366
8366
|
config.OPENAPI_SK = process.env.LCAP_OPENAPI_SK;
|
|
8367
|
+
if (process.env.LCAP_TENANT_NAME)
|
|
8368
|
+
config.tenantName = process.env.LCAP_TENANT_NAME;
|
|
8367
8369
|
// 如果启用了 OpenAPI,验证必需的 AK 和 SK
|
|
8368
8370
|
if (config.useOPENAPI) {
|
|
8369
8371
|
if (!config.OPENAPI_AK || !config.OPENAPI_SK) {
|
|
@@ -8410,7 +8412,7 @@ function readFileWithLog(filePath, logger) {
|
|
|
8410
8412
|
*/
|
|
8411
8413
|
function writeFileWithLog(filePath, content, logger) {
|
|
8412
8414
|
try {
|
|
8413
|
-
const dir =
|
|
8415
|
+
const dir = path$1.dirname(filePath);
|
|
8414
8416
|
libExports.ensureDirSync(dir);
|
|
8415
8417
|
libExports.writeFileSync(filePath, content, 'utf-8');
|
|
8416
8418
|
}
|
|
@@ -8425,7 +8427,7 @@ function writeFileWithLog(filePath, content, logger) {
|
|
|
8425
8427
|
*/
|
|
8426
8428
|
function init() {
|
|
8427
8429
|
const cwd = process.cwd();
|
|
8428
|
-
const configPath =
|
|
8430
|
+
const configPath = path$1.join(cwd, CONFIG_FILE_NAME);
|
|
8429
8431
|
// 检查配置文件是否已存在
|
|
8430
8432
|
if (libExports.existsSync(configPath)) {
|
|
8431
8433
|
defaultLogger.warn(`配置文件已存在: ${configPath}`);
|
|
@@ -8439,7 +8441,7 @@ function init() {
|
|
|
8439
8441
|
defaultLogger.info('\n配置内容:');
|
|
8440
8442
|
defaultLogger.info(JSON.stringify(DEFAULT_CONFIG, null, 2));
|
|
8441
8443
|
// 创建源代码目录
|
|
8442
|
-
const srcDirPath =
|
|
8444
|
+
const srcDirPath = path$1.join(cwd, DEFAULT_CONFIG.srcDir);
|
|
8443
8445
|
libExports.ensureDirSync(srcDirPath);
|
|
8444
8446
|
defaultLogger.success(`源代码目录已创建: ${srcDirPath}`);
|
|
8445
8447
|
defaultLogger.info('\n提示:');
|
|
@@ -20431,7 +20433,7 @@ function requireMimeTypes () {
|
|
|
20431
20433
|
*/
|
|
20432
20434
|
|
|
20433
20435
|
var db = requireMimeDb();
|
|
20434
|
-
var extname =
|
|
20436
|
+
var extname = path__default.extname;
|
|
20435
20437
|
|
|
20436
20438
|
/**
|
|
20437
20439
|
* Module variables.
|
|
@@ -22172,7 +22174,7 @@ function requireForm_data () {
|
|
|
22172
22174
|
|
|
22173
22175
|
var CombinedStream = requireCombined_stream();
|
|
22174
22176
|
var util = require$$0$4;
|
|
22175
|
-
var path =
|
|
22177
|
+
var path = path__default;
|
|
22176
22178
|
var http = require$$3;
|
|
22177
22179
|
var https = require$$4$1;
|
|
22178
22180
|
var parseUrl = require$$0$6.parse;
|
|
@@ -29116,6 +29118,20 @@ async function generateCompleteHeaders(options) {
|
|
|
29116
29118
|
}
|
|
29117
29119
|
return headers;
|
|
29118
29120
|
}
|
|
29121
|
+
/**
|
|
29122
|
+
* 构建请求 headers
|
|
29123
|
+
* 如果 ServerOptions.useOPENAPI 为 true, 意味着接口内部是走的集群,反之则需要走 openapi 调用(本地或者server的场景,透传options相关配置)
|
|
29124
|
+
*/
|
|
29125
|
+
function buildNaslHeaders(options) {
|
|
29126
|
+
return {
|
|
29127
|
+
'Content-Type': 'text/plain',
|
|
29128
|
+
'X-Server-Base-URL': options.serverBaseURL,
|
|
29129
|
+
...(options.OPENAPI_AK && { 'X-OPENAPI-AK': options.OPENAPI_AK }),
|
|
29130
|
+
...(options.OPENAPI_SK && { 'X-OPENAPI-SK': options.OPENAPI_SK }),
|
|
29131
|
+
...(options.tenantName && { 'X-Tenant-Name': options.tenantName }),
|
|
29132
|
+
...(options.useOPENAPI !== undefined && { 'X-Use-OPENAPI': String(!options.useOPENAPI) }),
|
|
29133
|
+
};
|
|
29134
|
+
}
|
|
29119
29135
|
|
|
29120
29136
|
/**
|
|
29121
29137
|
* 创建 Axios 实例
|
|
@@ -29167,7 +29183,7 @@ async function compileApi(fullNaturalTS, options) {
|
|
|
29167
29183
|
// 示例实现:
|
|
29168
29184
|
const axios = await createAxios(options);
|
|
29169
29185
|
const res = await axios.post(`/compile/tsx?ideVersion=${options.ideVersion}&needAnnotation=true`, fullNaturalTS, {
|
|
29170
|
-
headers:
|
|
29186
|
+
headers: buildNaslHeaders(options),
|
|
29171
29187
|
});
|
|
29172
29188
|
const data = res.data;
|
|
29173
29189
|
const { bundle } = data.result;
|
|
@@ -29199,7 +29215,7 @@ window.backendApp = app;
|
|
|
29199
29215
|
async function checkApi(fullNaturalTS, options) {
|
|
29200
29216
|
const axios = await createAxios(options);
|
|
29201
29217
|
const res = await axios.post(`/check/tsx?ideVersion=${options.ideVersion}`, fullNaturalTS, {
|
|
29202
|
-
headers:
|
|
29218
|
+
headers: buildNaslHeaders(options),
|
|
29203
29219
|
});
|
|
29204
29220
|
const result = res.data.result;
|
|
29205
29221
|
const errors = (result.errors || []);
|
|
@@ -29248,6 +29264,17 @@ async function createAppSyncApi(fullNaturalTS, options) {
|
|
|
29248
29264
|
}
|
|
29249
29265
|
}
|
|
29250
29266
|
|
|
29267
|
+
async function installDependenciesApi(dependenciesJSON, options) {
|
|
29268
|
+
const axios = await createAxios(options);
|
|
29269
|
+
const res = await axios.post(`/load/dependencies?ideVersion=${options.ideVersion}`, dependenciesJSON, {
|
|
29270
|
+
headers: buildNaslHeaders(options),
|
|
29271
|
+
});
|
|
29272
|
+
const data = res.data;
|
|
29273
|
+
if (data.code !== 200)
|
|
29274
|
+
throw new Error(data.message);
|
|
29275
|
+
return data.result;
|
|
29276
|
+
}
|
|
29277
|
+
|
|
29251
29278
|
function createSorter() {
|
|
29252
29279
|
const priorityOrder = ['app.dataSources', 'app.enums', 'app.structures', 'app.logics', 'app.frontendTypes'];
|
|
29253
29280
|
// 获取优先级索引
|
|
@@ -29370,6 +29397,25 @@ function composeToString(files) {
|
|
|
29370
29397
|
}
|
|
29371
29398
|
return result;
|
|
29372
29399
|
}
|
|
29400
|
+
/**
|
|
29401
|
+
* 将依赖信息拼接到 fullNaturalTS 顶部
|
|
29402
|
+
* @param fullNaturalTS 组合后的 NASL 代码
|
|
29403
|
+
* @param dependencies mergedDependencies 对象或 JSON 字符串
|
|
29404
|
+
* @returns 拼接后的完整内容
|
|
29405
|
+
*/
|
|
29406
|
+
function prependDependencies(fullNaturalTS, dependencies) {
|
|
29407
|
+
if (!dependencies)
|
|
29408
|
+
return fullNaturalTS;
|
|
29409
|
+
const jsonStr = JSON.stringify(dependencies, null, 2);
|
|
29410
|
+
const header = `/*
|
|
29411
|
+
-----------app.dependencies.json7xdhjutehm.start
|
|
29412
|
+
${jsonStr}
|
|
29413
|
+
-----------app.dependencies.json7xdhjutehm.end
|
|
29414
|
+
*/
|
|
29415
|
+
|
|
29416
|
+
`;
|
|
29417
|
+
return header + fullNaturalTS;
|
|
29418
|
+
}
|
|
29373
29419
|
|
|
29374
29420
|
var globby$1 = {exports: {}};
|
|
29375
29421
|
|
|
@@ -29627,7 +29673,7 @@ function requirePath () {
|
|
|
29627
29673
|
Object.defineProperty(path, "__esModule", { value: true });
|
|
29628
29674
|
path.convertPosixPathToPattern = path.convertWindowsPathToPattern = path.convertPathToPattern = path.escapePosixPath = path.escapeWindowsPath = path.escape = path.removeLeadingDotSegment = path.makeAbsolute = path.unixify = void 0;
|
|
29629
29675
|
const os = require$$0$5;
|
|
29630
|
-
const path$1 =
|
|
29676
|
+
const path$1 = path__default;
|
|
29631
29677
|
const IS_WINDOWS_PLATFORM = os.platform() === 'win32';
|
|
29632
29678
|
const LEADING_DOT_SEGMENT_CHARACTERS_COUNT = 2; // ./ or .\\
|
|
29633
29679
|
/**
|
|
@@ -29892,7 +29938,7 @@ function requireGlobParent () {
|
|
|
29892
29938
|
hasRequiredGlobParent = 1;
|
|
29893
29939
|
|
|
29894
29940
|
var isGlob = requireIsGlob();
|
|
29895
|
-
var pathPosixDirname =
|
|
29941
|
+
var pathPosixDirname = path__default.posix.dirname;
|
|
29896
29942
|
var isWin32 = require$$0$5.platform() === 'win32';
|
|
29897
29943
|
|
|
29898
29944
|
var slash = '/';
|
|
@@ -31464,7 +31510,7 @@ function requireConstants$1 () {
|
|
|
31464
31510
|
if (hasRequiredConstants$1) return constants$1;
|
|
31465
31511
|
hasRequiredConstants$1 = 1;
|
|
31466
31512
|
|
|
31467
|
-
const path =
|
|
31513
|
+
const path = path__default;
|
|
31468
31514
|
const WIN_SLASH = '\\\\/';
|
|
31469
31515
|
const WIN_NO_SLASH = `[^${WIN_SLASH}]`;
|
|
31470
31516
|
|
|
@@ -31651,7 +31697,7 @@ function requireUtils$2 () {
|
|
|
31651
31697
|
hasRequiredUtils$2 = 1;
|
|
31652
31698
|
(function (exports$1) {
|
|
31653
31699
|
|
|
31654
|
-
const path =
|
|
31700
|
+
const path = path__default;
|
|
31655
31701
|
const win32 = process.platform === 'win32';
|
|
31656
31702
|
const {
|
|
31657
31703
|
REGEX_BACKSLASH,
|
|
@@ -33222,7 +33268,7 @@ function requirePicomatch$1 () {
|
|
|
33222
33268
|
if (hasRequiredPicomatch$1) return picomatch_1;
|
|
33223
33269
|
hasRequiredPicomatch$1 = 1;
|
|
33224
33270
|
|
|
33225
|
-
const path =
|
|
33271
|
+
const path = path__default;
|
|
33226
33272
|
const scan = requireScan();
|
|
33227
33273
|
const parse = requireParse();
|
|
33228
33274
|
const utils = requireUtils$2();
|
|
@@ -34065,7 +34111,7 @@ function requirePattern () {
|
|
|
34065
34111
|
hasRequiredPattern = 1;
|
|
34066
34112
|
Object.defineProperty(pattern, "__esModule", { value: true });
|
|
34067
34113
|
pattern.isAbsolute = pattern.partitionAbsoluteAndRelative = pattern.removeDuplicateSlashes = pattern.matchAny = pattern.convertPatternsToRe = pattern.makeRe = pattern.getPatternParts = pattern.expandBraceExpansion = pattern.expandPatternsWithBraceExpansion = pattern.isAffectDepthOfReadingPattern = pattern.endsWithSlashGlobStar = pattern.hasGlobStar = pattern.getBaseDirectory = pattern.isPatternRelatedToParentDirectory = pattern.getPatternsOutsideCurrentDirectory = pattern.getPatternsInsideCurrentDirectory = pattern.getPositivePatterns = pattern.getNegativePatterns = pattern.isPositivePattern = pattern.isNegativePattern = pattern.convertToNegativePattern = pattern.convertToPositivePattern = pattern.isDynamicPattern = pattern.isStaticPattern = void 0;
|
|
34068
|
-
const path =
|
|
34114
|
+
const path = path__default;
|
|
34069
34115
|
const globParent = requireGlobParent();
|
|
34070
34116
|
const micromatch = requireMicromatch();
|
|
34071
34117
|
const GLOBSTAR = '**';
|
|
@@ -35019,7 +35065,7 @@ function requireSettings$2 () {
|
|
|
35019
35065
|
if (hasRequiredSettings$2) return settings$2;
|
|
35020
35066
|
hasRequiredSettings$2 = 1;
|
|
35021
35067
|
Object.defineProperty(settings$2, "__esModule", { value: true });
|
|
35022
|
-
const path =
|
|
35068
|
+
const path = path__default;
|
|
35023
35069
|
const fsStat = requireOut$3();
|
|
35024
35070
|
const fs = requireFs();
|
|
35025
35071
|
class Settings {
|
|
@@ -35781,7 +35827,7 @@ function requireSettings$1 () {
|
|
|
35781
35827
|
if (hasRequiredSettings$1) return settings$1;
|
|
35782
35828
|
hasRequiredSettings$1 = 1;
|
|
35783
35829
|
Object.defineProperty(settings$1, "__esModule", { value: true });
|
|
35784
|
-
const path =
|
|
35830
|
+
const path = path__default;
|
|
35785
35831
|
const fsScandir = requireOut$2();
|
|
35786
35832
|
class Settings {
|
|
35787
35833
|
constructor(_options = {}) {
|
|
@@ -35857,7 +35903,7 @@ function requireReader () {
|
|
|
35857
35903
|
if (hasRequiredReader) return reader;
|
|
35858
35904
|
hasRequiredReader = 1;
|
|
35859
35905
|
Object.defineProperty(reader, "__esModule", { value: true });
|
|
35860
|
-
const path =
|
|
35906
|
+
const path = path__default;
|
|
35861
35907
|
const fsStat = requireOut$3();
|
|
35862
35908
|
const utils = requireUtils$1();
|
|
35863
35909
|
class Reader {
|
|
@@ -36330,7 +36376,7 @@ function requireProvider () {
|
|
|
36330
36376
|
if (hasRequiredProvider) return provider;
|
|
36331
36377
|
hasRequiredProvider = 1;
|
|
36332
36378
|
Object.defineProperty(provider, "__esModule", { value: true });
|
|
36333
|
-
const path =
|
|
36379
|
+
const path = path__default;
|
|
36334
36380
|
const deep_1 = requireDeep();
|
|
36335
36381
|
const entry_1 = requireEntry$1();
|
|
36336
36382
|
const error_1 = requireError();
|
|
@@ -36770,7 +36816,7 @@ var hasRequiredDirGlob;
|
|
|
36770
36816
|
function requireDirGlob () {
|
|
36771
36817
|
if (hasRequiredDirGlob) return dirGlob.exports;
|
|
36772
36818
|
hasRequiredDirGlob = 1;
|
|
36773
|
-
const path =
|
|
36819
|
+
const path = path__default;
|
|
36774
36820
|
const pathType = requirePathType();
|
|
36775
36821
|
|
|
36776
36822
|
const getExtensions = extensions => extensions.length > 1 ? `{${extensions.join(',')}}` : extensions[0];
|
|
@@ -37520,7 +37566,7 @@ function requireGitignore () {
|
|
|
37520
37566
|
hasRequiredGitignore = 1;
|
|
37521
37567
|
const {promisify} = require$$0$4;
|
|
37522
37568
|
const fs = require$$0$2;
|
|
37523
|
-
const path =
|
|
37569
|
+
const path = path__default;
|
|
37524
37570
|
const fastGlob = requireOut();
|
|
37525
37571
|
const gitIgnore = requireIgnore();
|
|
37526
37572
|
const slash = requireSlash();
|
|
@@ -37952,6 +37998,27 @@ const NASL_FILE_TYPES = [
|
|
|
37952
37998
|
codeRefPattern: 'extensions\\.\\w+(?:\\.\\w+)*',
|
|
37953
37999
|
extension: 'ts',
|
|
37954
38000
|
},
|
|
38001
|
+
{
|
|
38002
|
+
name: 'apis',
|
|
38003
|
+
description: 'API',
|
|
38004
|
+
fileNamePattern: 'apis\\.\\w+\\.ts',
|
|
38005
|
+
codeRefPattern: 'apis\\.\\w+(?:\\.\\w+)*',
|
|
38006
|
+
extension: 'ts',
|
|
38007
|
+
},
|
|
38008
|
+
{
|
|
38009
|
+
name: 'connectors',
|
|
38010
|
+
description: '连接器',
|
|
38011
|
+
fileNamePattern: 'connectors\\.\\w+\\.ts',
|
|
38012
|
+
codeRefPattern: 'connectors\\.\\w+(?:\\.\\w+)*',
|
|
38013
|
+
extension: 'ts',
|
|
38014
|
+
},
|
|
38015
|
+
{
|
|
38016
|
+
name: 'uilibs',
|
|
38017
|
+
description: 'UI 库',
|
|
38018
|
+
fileNamePattern: 'uilibs\\.\\w+\\.ts',
|
|
38019
|
+
codeRefPattern: 'uilibs\\.\\w+(?:\\.\\w+)*',
|
|
38020
|
+
extension: 'ts',
|
|
38021
|
+
},
|
|
37955
38022
|
];
|
|
37956
38023
|
/**
|
|
37957
38024
|
* 获取用于验证文件名的正则表达式数组
|
|
@@ -37984,10 +38051,15 @@ const codeRefPatterns = getCodeRefPatterns();
|
|
|
37984
38051
|
*/
|
|
37985
38052
|
function isKnownFileType(filePath) {
|
|
37986
38053
|
// 提取文件名
|
|
37987
|
-
const fileName =
|
|
38054
|
+
const fileName = path$1.basename(filePath);
|
|
37988
38055
|
return fileNamePatterns.some((pattern) => pattern.test(fileName));
|
|
37989
38056
|
}
|
|
37990
38057
|
|
|
38058
|
+
/** 这些前缀的依赖不再向下递归查找 */
|
|
38059
|
+
const EXTERNAL_DEP_PREFIXES = ['extensions.', 'connectors.', 'apis.', 'uilibs.'];
|
|
38060
|
+
function shouldSkipDependencyTraversal(depPath) {
|
|
38061
|
+
return EXTERNAL_DEP_PREFIXES.some((prefix) => depPath.startsWith(prefix));
|
|
38062
|
+
}
|
|
37991
38063
|
/**
|
|
37992
38064
|
* 扫描目录下的所有 NASL 文件
|
|
37993
38065
|
*/
|
|
@@ -38053,6 +38125,15 @@ function extractDeps(content) {
|
|
|
38053
38125
|
if (/^extensions\.\w+\./.test(dep)) {
|
|
38054
38126
|
dep = dep.replace(/^(extensions\.\w+)\..+$/, '$1');
|
|
38055
38127
|
}
|
|
38128
|
+
if (/^apis\.\w+\./.test(dep)) {
|
|
38129
|
+
dep = dep.replace(/^(apis\.\w+)\..+$/, '$1');
|
|
38130
|
+
}
|
|
38131
|
+
if (/^connectors\.\w+\./.test(dep)) {
|
|
38132
|
+
dep = dep.replace(/^(connectors\.\w+)\..+$/, '$1');
|
|
38133
|
+
}
|
|
38134
|
+
if (/^uilibs\.\w+\./.test(dep)) {
|
|
38135
|
+
dep = dep.replace(/^(uilibs\.\w+)\..+$/, '$1');
|
|
38136
|
+
}
|
|
38056
38137
|
// 跳过不合法的实体引用(实体后还有字段的情况)
|
|
38057
38138
|
if (/app\.dataSources\.\w+\.entities\.\w+\.\w+$/.test(dep)) {
|
|
38058
38139
|
continue;
|
|
@@ -38064,6 +38145,152 @@ function extractDeps(content) {
|
|
|
38064
38145
|
}
|
|
38065
38146
|
return Array.from(deps);
|
|
38066
38147
|
}
|
|
38148
|
+
/**
|
|
38149
|
+
* 从文件内容中提取外部依赖引用(extensions/connectors/apis/uilibs)
|
|
38150
|
+
* 用于构建 externalDependencies
|
|
38151
|
+
*/
|
|
38152
|
+
function extractExternalRefs(content) {
|
|
38153
|
+
const refs = {
|
|
38154
|
+
extensions: new Set(),
|
|
38155
|
+
connectors: new Set(),
|
|
38156
|
+
uilibs: new Set(),
|
|
38157
|
+
apis: new Map(),
|
|
38158
|
+
};
|
|
38159
|
+
const processedContent = content
|
|
38160
|
+
.replace(/\/\/.*$/gm, '')
|
|
38161
|
+
.replace(/\/\*[\s\S]*?\*\//g, '')
|
|
38162
|
+
.replace(/'(?:[^'\\]|\\.)*'/g, '')
|
|
38163
|
+
.replace(/"(?:[^"\\]|\\.)*"/g, '');
|
|
38164
|
+
// extensions.xxx, connectors.xxx, uilibs.xxx
|
|
38165
|
+
for (const m of processedContent.matchAll(/\b(extensions|connectors|uilibs)\.(\w+)/g)) {
|
|
38166
|
+
const [, kind, name] = m;
|
|
38167
|
+
if (kind === 'extensions')
|
|
38168
|
+
refs.extensions.add(name);
|
|
38169
|
+
else if (kind === 'connectors')
|
|
38170
|
+
refs.connectors.add(name);
|
|
38171
|
+
else
|
|
38172
|
+
refs.uilibs.add(name);
|
|
38173
|
+
}
|
|
38174
|
+
// apis.xxx.interfaces.yyy
|
|
38175
|
+
for (const m of processedContent.matchAll(/\bapis\.(\w+)\.interfaces\.(\w+)/g)) {
|
|
38176
|
+
const [, apiName, ifaceName] = m;
|
|
38177
|
+
if (!refs.apis.has(apiName))
|
|
38178
|
+
refs.apis.set(apiName, new Set());
|
|
38179
|
+
refs.apis.get(apiName).add(ifaceName);
|
|
38180
|
+
}
|
|
38181
|
+
return refs;
|
|
38182
|
+
}
|
|
38183
|
+
function mergeExternalRefs(into, from) {
|
|
38184
|
+
from.extensions.forEach((x) => into.extensions.add(x));
|
|
38185
|
+
from.connectors.forEach((x) => into.connectors.add(x));
|
|
38186
|
+
from.uilibs.forEach((x) => into.uilibs.add(x));
|
|
38187
|
+
from.apis.forEach((interfaces, apiName) => {
|
|
38188
|
+
if (!into.apis.has(apiName))
|
|
38189
|
+
into.apis.set(apiName, new Set());
|
|
38190
|
+
interfaces.forEach((i) => into.apis.get(apiName).add(i));
|
|
38191
|
+
});
|
|
38192
|
+
}
|
|
38193
|
+
/**
|
|
38194
|
+
* 加载 app.dependencies.json(不存在则返回空对象)
|
|
38195
|
+
*/
|
|
38196
|
+
function loadAppDependencies(srcDir) {
|
|
38197
|
+
const p = path$1.join(srcDir, 'app.dependencies.json');
|
|
38198
|
+
if (!libExports.existsSync(p))
|
|
38199
|
+
return {};
|
|
38200
|
+
try {
|
|
38201
|
+
return libExports.readJsonSync(p);
|
|
38202
|
+
}
|
|
38203
|
+
catch {
|
|
38204
|
+
return {};
|
|
38205
|
+
}
|
|
38206
|
+
}
|
|
38207
|
+
/**
|
|
38208
|
+
* 加载并合并 app.dependencies.json 与 potential.dependencies.json
|
|
38209
|
+
* 用于版本号查找:先查 app,再查 potential
|
|
38210
|
+
*/
|
|
38211
|
+
function loadMergedDependencies(srcDir) {
|
|
38212
|
+
const load = (file) => {
|
|
38213
|
+
const p = path$1.join(srcDir, file);
|
|
38214
|
+
if (!libExports.existsSync(p))
|
|
38215
|
+
return null;
|
|
38216
|
+
try {
|
|
38217
|
+
return libExports.readJsonSync(p);
|
|
38218
|
+
}
|
|
38219
|
+
catch {
|
|
38220
|
+
return null;
|
|
38221
|
+
}
|
|
38222
|
+
};
|
|
38223
|
+
const app = load('app.dependencies.json') ?? {};
|
|
38224
|
+
const potential = load('potential.dependencies.json') ?? {};
|
|
38225
|
+
const merged = {};
|
|
38226
|
+
for (const key of ['extensions', 'uilibs', 'connectors', 'apis']) {
|
|
38227
|
+
merged[key] = { ...(potential[key] ?? {}), ...(app[key] ?? {}) };
|
|
38228
|
+
}
|
|
38229
|
+
return merged;
|
|
38230
|
+
}
|
|
38231
|
+
/**
|
|
38232
|
+
* 将 externalDependencies 补充到 app.dependencies.json(只增不减)
|
|
38233
|
+
*/
|
|
38234
|
+
function mergeDependenciesIntoApp(existing, incoming) {
|
|
38235
|
+
const result = {};
|
|
38236
|
+
for (const key of ['extensions', 'uilibs', 'connectors']) {
|
|
38237
|
+
const existingRecord = existing[key] ?? {};
|
|
38238
|
+
const incomingRecord = incoming[key] ?? {};
|
|
38239
|
+
result[key] = { ...incomingRecord, ...existingRecord };
|
|
38240
|
+
}
|
|
38241
|
+
result.apis = {};
|
|
38242
|
+
if (existing.apis || incoming.apis) {
|
|
38243
|
+
const allApiNames = new Set([...Object.keys(existing.apis ?? {}), ...Object.keys(incoming.apis ?? {})]);
|
|
38244
|
+
for (const apiName of allApiNames) {
|
|
38245
|
+
const existingInterfaces = existing.apis?.[apiName] ?? [];
|
|
38246
|
+
const incomingInterfaces = incoming.apis?.[apiName] ?? [];
|
|
38247
|
+
result.apis[apiName] = [...new Set([...existingInterfaces, ...incomingInterfaces])].sort();
|
|
38248
|
+
}
|
|
38249
|
+
}
|
|
38250
|
+
return result;
|
|
38251
|
+
}
|
|
38252
|
+
/**
|
|
38253
|
+
* 根据收集的外部引用和版本配置,构建 DependenciesJSON
|
|
38254
|
+
* extensions/connectors/uilibs 需要版本号,apis 只需 interfaces 数组
|
|
38255
|
+
*/
|
|
38256
|
+
function buildExternalDependencies(refs, mergedDeps, logger) {
|
|
38257
|
+
const result = {};
|
|
38258
|
+
const errors = [];
|
|
38259
|
+
for (const name of refs.extensions) {
|
|
38260
|
+
const ver = mergedDeps.extensions?.[name];
|
|
38261
|
+
if (!ver) {
|
|
38262
|
+
errors.push(`extensions.${name} 未在 app.dependencies.json 或 potential.dependencies.json 中找到版本号`);
|
|
38263
|
+
}
|
|
38264
|
+
else {
|
|
38265
|
+
(result.extensions ?? (result.extensions = {}))[name] = ver;
|
|
38266
|
+
}
|
|
38267
|
+
}
|
|
38268
|
+
for (const name of refs.connectors) {
|
|
38269
|
+
const ver = mergedDeps.connectors?.[name];
|
|
38270
|
+
if (!ver) {
|
|
38271
|
+
errors.push(`connectors.${name} 未在 app.dependencies.json 或 potential.dependencies.json 中找到版本号`);
|
|
38272
|
+
}
|
|
38273
|
+
else {
|
|
38274
|
+
(result.connectors ?? (result.connectors = {}))[name] = ver;
|
|
38275
|
+
}
|
|
38276
|
+
}
|
|
38277
|
+
for (const name of refs.uilibs) {
|
|
38278
|
+
const ver = mergedDeps.uilibs?.[name];
|
|
38279
|
+
if (!ver) {
|
|
38280
|
+
errors.push(`uilibs.${name} 未在 app.dependencies.json 或 potential.dependencies.json 中找到版本号`);
|
|
38281
|
+
}
|
|
38282
|
+
else {
|
|
38283
|
+
(result.uilibs ?? (result.uilibs = {}))[name] = ver;
|
|
38284
|
+
}
|
|
38285
|
+
}
|
|
38286
|
+
// result.uilibs = mergedDeps.uilibs; // 临时先都加上去
|
|
38287
|
+
refs.apis.forEach((interfaces, apiName) => {
|
|
38288
|
+
(result.apis ?? (result.apis = {}))[apiName] = Array.from(interfaces).sort();
|
|
38289
|
+
});
|
|
38290
|
+
if (errors.length > 0)
|
|
38291
|
+
throw new Error(errors.join('\n'));
|
|
38292
|
+
return result;
|
|
38293
|
+
}
|
|
38067
38294
|
/**
|
|
38068
38295
|
* 提取页面文件的签名,移除函数体
|
|
38069
38296
|
* @param content 页面文件内容
|
|
@@ -38086,7 +38313,7 @@ function replaceViewAsSignature(content, hasSubViews = false) {
|
|
|
38086
38313
|
* @returns 文件信息和新发现的依赖文件列表
|
|
38087
38314
|
*/
|
|
38088
38315
|
function processFileDeps(pathRelativeToSrc, srcDir, matchedFileSet, processedFileMap, depNotFoundList, logger, verbose) {
|
|
38089
|
-
const absoluteFilePath =
|
|
38316
|
+
const absoluteFilePath = path$1.join(srcDir, pathRelativeToSrc);
|
|
38090
38317
|
const fileInfo = { path: pathRelativeToSrc, content: '' };
|
|
38091
38318
|
try {
|
|
38092
38319
|
fileInfo.content = readFileWithLog(absoluteFilePath, logger);
|
|
@@ -38116,7 +38343,9 @@ function processFileDeps(pathRelativeToSrc, srcDir, matchedFileSet, processedFil
|
|
|
38116
38343
|
}
|
|
38117
38344
|
processedFileMap.set(pathRelativeToSrc, fileInfo);
|
|
38118
38345
|
// 提取依赖
|
|
38119
|
-
|
|
38346
|
+
// extensions/connectors/apis/uilibs 作为叶子节点,不再向下递归查找依赖
|
|
38347
|
+
const isExternalDep = shouldSkipDependencyTraversal(pathRelativeToSrc);
|
|
38348
|
+
const deps = isExternalDep ? [] : extractDeps(fileInfo.content);
|
|
38120
38349
|
// 查找依赖文件
|
|
38121
38350
|
if (isView) {
|
|
38122
38351
|
const pathArr = pathRelativeToSrc.split('.');
|
|
@@ -38131,24 +38360,30 @@ function processFileDeps(pathRelativeToSrc, srcDir, matchedFileSet, processedFil
|
|
|
38131
38360
|
} while (true);
|
|
38132
38361
|
}
|
|
38133
38362
|
if (verbose || process.env.DEBUG) {
|
|
38134
|
-
console.log(`${isEntryFile ? chalk.magenta('[Entry]') : chalk.green('[ Dep ]')} ${pathRelativeToSrc}${deps.map((dep) => `\n├── ${dep}`).join('')}`);
|
|
38363
|
+
console.log(`${isEntryFile ? chalk.magenta('[Entry]') : isExternalDep ? chalk.blue('[ External Dep ]') : chalk.green('[ Dep ]')} ${pathRelativeToSrc}${deps.map((dep) => `\n├── ${dep}`).join('')}`);
|
|
38135
38364
|
}
|
|
38136
38365
|
return {
|
|
38137
38366
|
fileInfo,
|
|
38138
38367
|
newDeps: deps.filter((dep) => !processedFileMap.has(dep)),
|
|
38368
|
+
isExternalDep,
|
|
38139
38369
|
};
|
|
38140
38370
|
}
|
|
38141
38371
|
/**
|
|
38142
38372
|
* 收集入口文件及其依赖
|
|
38143
38373
|
* @param patterns 入口文件的 glob 模式数组
|
|
38144
38374
|
* @param srcDir 源代码目录绝对路径
|
|
38145
|
-
* @
|
|
38146
|
-
* @returns 文件信息列表
|
|
38375
|
+
* @returns 文件信息列表和外部依赖引用
|
|
38147
38376
|
*/
|
|
38148
38377
|
async function collectDeps(patterns, projectRoot, srcDir, logger, verbose) {
|
|
38149
38378
|
const processedFileMap = new Map(); // 已处理的文件(相对路径)
|
|
38150
38379
|
const filesToProcess = []; // 待处理的文件队列
|
|
38151
38380
|
const result = [];
|
|
38381
|
+
const externalRefs = {
|
|
38382
|
+
extensions: new Set(),
|
|
38383
|
+
connectors: new Set(),
|
|
38384
|
+
uilibs: new Set(),
|
|
38385
|
+
apis: new Map(),
|
|
38386
|
+
};
|
|
38152
38387
|
// 1. 使用 glob 匹配入口文件
|
|
38153
38388
|
logger.newLine();
|
|
38154
38389
|
logger.info(`匹配入口文件: ${patterns.join(', ')}`);
|
|
@@ -38158,15 +38393,15 @@ async function collectDeps(patterns, projectRoot, srcDir, logger, verbose) {
|
|
|
38158
38393
|
throw new Error('未找到匹配的入口文件');
|
|
38159
38394
|
}
|
|
38160
38395
|
logger.info(`找到 ${matchedFiles.length} 个入口文件`);
|
|
38161
|
-
const absoluteSrcDir =
|
|
38396
|
+
const absoluteSrcDir = path$1.resolve(srcDir);
|
|
38162
38397
|
const matchedFileSet = new Set();
|
|
38163
38398
|
matchedFiles.forEach((pathRelativeToRoot) => {
|
|
38164
38399
|
// 统一使用相对于 src 的路径
|
|
38165
|
-
const absoluteFilePath =
|
|
38400
|
+
const absoluteFilePath = path$1.resolve(projectRoot, pathRelativeToRoot);
|
|
38166
38401
|
// 判断 file 是否超出 srcDir 目录(支持相对路径和绝对路径)
|
|
38167
38402
|
if (!absoluteFilePath.startsWith(absoluteSrcDir))
|
|
38168
38403
|
throw new Error(`入口文件 ${absoluteFilePath} 超出了源代码目录 ${srcDir}`);
|
|
38169
|
-
const pathRelativeToSrc =
|
|
38404
|
+
const pathRelativeToSrc = path$1.relative(srcDir, absoluteFilePath);
|
|
38170
38405
|
filesToProcess.push(pathRelativeToSrc);
|
|
38171
38406
|
matchedFileSet.add(pathRelativeToSrc);
|
|
38172
38407
|
});
|
|
@@ -38184,8 +38419,9 @@ async function collectDeps(patterns, projectRoot, srcDir, logger, verbose) {
|
|
|
38184
38419
|
continue;
|
|
38185
38420
|
}
|
|
38186
38421
|
try {
|
|
38187
|
-
const { fileInfo, newDeps } = processFileDeps(pathRelativeToSrc, srcDir, matchedFileSet, processedFileMap, depNotFoundList, logger, verbose);
|
|
38188
|
-
result.push(fileInfo);
|
|
38422
|
+
const { fileInfo, newDeps, isExternalDep } = processFileDeps(pathRelativeToSrc, srcDir, matchedFileSet, processedFileMap, depNotFoundList, logger, verbose);
|
|
38423
|
+
!isExternalDep && result.push(fileInfo);
|
|
38424
|
+
mergeExternalRefs(externalRefs, extractExternalRefs(fileInfo.content));
|
|
38189
38425
|
filesToProcess.push(...newDeps);
|
|
38190
38426
|
}
|
|
38191
38427
|
catch (error) {
|
|
@@ -38207,7 +38443,7 @@ ${depNotFoundList.map((dep) => `- ${dep}\n`).join('')}
|
|
|
38207
38443
|
}
|
|
38208
38444
|
if (errorMessage)
|
|
38209
38445
|
throw new Error(errorMessage);
|
|
38210
|
-
return result;
|
|
38446
|
+
return { files: result, externalRefs };
|
|
38211
38447
|
}
|
|
38212
38448
|
/**
|
|
38213
38449
|
* 解析需要处理的文件(包含配置加载和目录设置)
|
|
@@ -38215,12 +38451,13 @@ ${depNotFoundList.map((dep) => `- ${dep}\n`).join('')}
|
|
|
38215
38451
|
* @returns 文件信息、配置和目录信息
|
|
38216
38452
|
*/
|
|
38217
38453
|
async function resolveNASLFiles(entry, logger, depMode, verbose) {
|
|
38454
|
+
depMode = true; // !!ensure depMode is true
|
|
38218
38455
|
// 加载配置
|
|
38219
38456
|
const config = loadConfig();
|
|
38220
38457
|
const projectRoot = getProjectRoot();
|
|
38221
38458
|
logger.info(`项目根目录: ${projectRoot}`);
|
|
38222
38459
|
logger.info(`源代码目录: ${config.srcDir}`);
|
|
38223
|
-
const srcDir =
|
|
38460
|
+
const srcDir = path$1.join(projectRoot, config.srcDir);
|
|
38224
38461
|
// 收集需要处理的文件
|
|
38225
38462
|
let collectedFiles = [];
|
|
38226
38463
|
if (Array.isArray(entry) && !entry.length) {
|
|
@@ -38229,10 +38466,12 @@ async function resolveNASLFiles(entry, logger, depMode, verbose) {
|
|
|
38229
38466
|
config,
|
|
38230
38467
|
projectRoot,
|
|
38231
38468
|
srcDir,
|
|
38469
|
+
externalDependencies: undefined,
|
|
38232
38470
|
};
|
|
38233
38471
|
}
|
|
38472
|
+
let externalRefs = null;
|
|
38234
38473
|
if (!entry && depMode)
|
|
38235
|
-
entry = 'src
|
|
38474
|
+
entry = 'src/**/app.*.{ts,tsx,css}';
|
|
38236
38475
|
if (entry) {
|
|
38237
38476
|
// 检查入口路径是否在源代码目录外面
|
|
38238
38477
|
// if (entry.startsWith('..')) throw new Error('入口路径不能在源代码目录外面');
|
|
@@ -38240,7 +38479,9 @@ async function resolveNASLFiles(entry, logger, depMode, verbose) {
|
|
|
38240
38479
|
// 具体路径也转换为 glob 模式统一处理
|
|
38241
38480
|
// 使用依赖分析收集文件
|
|
38242
38481
|
try {
|
|
38243
|
-
|
|
38482
|
+
const { files, externalRefs: refs } = await collectDeps(Array.isArray(entry) ? entry : [entry], projectRoot, srcDir, logger, depMode || verbose);
|
|
38483
|
+
collectedFiles = files;
|
|
38484
|
+
externalRefs = refs;
|
|
38244
38485
|
}
|
|
38245
38486
|
catch (error) {
|
|
38246
38487
|
logger.error(`依赖分析失败:\n${error.message}`);
|
|
@@ -38254,13 +38495,21 @@ async function resolveNASLFiles(entry, logger, depMode, verbose) {
|
|
|
38254
38495
|
filePaths.sort(sorter);
|
|
38255
38496
|
collectedFiles = filePaths.map((filePath) => ({
|
|
38256
38497
|
path: filePath,
|
|
38257
|
-
content: readFileWithLog(
|
|
38498
|
+
content: readFileWithLog(path$1.join(srcDir, filePath), logger),
|
|
38258
38499
|
}));
|
|
38259
38500
|
if (collectedFiles.length === 0) {
|
|
38260
38501
|
logger.warn('未找到 NASL 文件');
|
|
38261
38502
|
logger.exit(1);
|
|
38262
38503
|
}
|
|
38263
38504
|
logger.info(`找到 ${collectedFiles.length} 个 NASL 文件`);
|
|
38505
|
+
// 全量扫描时也从文件中提取外部依赖引用
|
|
38506
|
+
externalRefs = {
|
|
38507
|
+
extensions: new Set(),
|
|
38508
|
+
connectors: new Set(),
|
|
38509
|
+
uilibs: new Set(),
|
|
38510
|
+
apis: new Map(),
|
|
38511
|
+
};
|
|
38512
|
+
collectedFiles.forEach((f) => mergeExternalRefs(externalRefs, extractExternalRefs(f.content)));
|
|
38264
38513
|
}
|
|
38265
38514
|
// 统一过滤掉不支持的文件类型
|
|
38266
38515
|
const filteredFiles = [];
|
|
@@ -38272,11 +38521,24 @@ async function resolveNASLFiles(entry, logger, depMode, verbose) {
|
|
|
38272
38521
|
logger.warn(`跳过不支持的文件类型: ${file.path}`);
|
|
38273
38522
|
}
|
|
38274
38523
|
});
|
|
38524
|
+
// 从分析中构建 externalDependencies(版本号从 app.dependencies.json / potential.dependencies.json 获取)
|
|
38525
|
+
let externalDependencies;
|
|
38526
|
+
let mergedDependencies;
|
|
38527
|
+
if (externalRefs && (externalRefs.extensions.size > 0 || externalRefs.connectors.size > 0 || externalRefs.uilibs.size > 0 || externalRefs.apis.size > 0)) {
|
|
38528
|
+
const mergedDeps = loadMergedDependencies(srcDir);
|
|
38529
|
+
externalDependencies = buildExternalDependencies(externalRefs, mergedDeps);
|
|
38530
|
+
const appDeps = loadAppDependencies(srcDir);
|
|
38531
|
+
mergedDependencies = mergeDependenciesIntoApp(appDeps, externalDependencies);
|
|
38532
|
+
logger.debug('已从分析构建 externalDependencies', externalDependencies);
|
|
38533
|
+
logger.debug('已从分析构建 mergedDependencies', mergedDependencies);
|
|
38534
|
+
}
|
|
38275
38535
|
return {
|
|
38276
38536
|
collectedFiles: filteredFiles,
|
|
38277
38537
|
config,
|
|
38278
38538
|
projectRoot,
|
|
38279
38539
|
srcDir,
|
|
38540
|
+
externalDependencies,
|
|
38541
|
+
mergedDependencies,
|
|
38280
38542
|
};
|
|
38281
38543
|
}
|
|
38282
38544
|
|
|
@@ -38287,19 +38549,20 @@ async function compile(entry, options) {
|
|
|
38287
38549
|
const logger = options?.logger || defaultLogger;
|
|
38288
38550
|
logger.info('开始编译 NASL 代码...');
|
|
38289
38551
|
// 收集需要编译的文件
|
|
38290
|
-
const { collectedFiles, config, projectRoot } = await resolveNASLFiles(entry, logger, false, options?.verbose);
|
|
38552
|
+
const { collectedFiles, config, projectRoot, mergedDependencies } = await resolveNASLFiles(entry, logger, false, options?.verbose);
|
|
38291
38553
|
logger.info(`输出目录: ${config.outDir}`);
|
|
38292
|
-
const outDir =
|
|
38554
|
+
const outDir = path$1.join(projectRoot, config.outDir);
|
|
38293
38555
|
// 调用编译 API
|
|
38294
38556
|
logger.newLine();
|
|
38295
38557
|
logger.info('正在调用编译服务...');
|
|
38296
38558
|
try {
|
|
38297
|
-
|
|
38559
|
+
let fullNaturalTS = composeToString(collectedFiles);
|
|
38560
|
+
fullNaturalTS = prependDependencies(fullNaturalTS, mergedDependencies);
|
|
38298
38561
|
const outputFiles = await compileApi(fullNaturalTS, config);
|
|
38299
38562
|
logger.success('编译成功!');
|
|
38300
38563
|
// 写入输出文件
|
|
38301
38564
|
for (const file of outputFiles) {
|
|
38302
|
-
const outputPath =
|
|
38565
|
+
const outputPath = path$1.join(outDir, file.path);
|
|
38303
38566
|
writeFileWithLog(outputPath, file.content, logger);
|
|
38304
38567
|
}
|
|
38305
38568
|
logger.info(`输出 ${outputFiles.length} 个文件`);
|
|
@@ -38386,7 +38649,7 @@ async function check(entry, options) {
|
|
|
38386
38649
|
const logger = options?.logger || defaultLogger;
|
|
38387
38650
|
logger.info('开始检查 NASL 代码...');
|
|
38388
38651
|
// 收集需要检查的文件
|
|
38389
|
-
const { collectedFiles, config } = await resolveNASLFiles(entry, logger, false, options?.verbose);
|
|
38652
|
+
const { collectedFiles, config, mergedDependencies } = await resolveNASLFiles(entry, logger, false, options?.verbose);
|
|
38390
38653
|
// 调用检查 API
|
|
38391
38654
|
logger.newLine();
|
|
38392
38655
|
logger.info('正在调用检查服务,对语法和语义进行检查...');
|
|
@@ -38394,6 +38657,7 @@ async function check(entry, options) {
|
|
|
38394
38657
|
let result = '';
|
|
38395
38658
|
try {
|
|
38396
38659
|
fullNaturalTS = composeToString(collectedFiles);
|
|
38660
|
+
fullNaturalTS = prependDependencies(fullNaturalTS, mergedDependencies);
|
|
38397
38661
|
}
|
|
38398
38662
|
catch (error) {
|
|
38399
38663
|
result = error.message.trim();
|
|
@@ -38422,12 +38686,19 @@ async function check(entry, options) {
|
|
|
38422
38686
|
}
|
|
38423
38687
|
|
|
38424
38688
|
/**
|
|
38425
|
-
*
|
|
38689
|
+
* 依赖分析命令 - 从入口文件开始进行依赖分析
|
|
38426
38690
|
*/
|
|
38427
38691
|
async function dep(entry, options) {
|
|
38428
|
-
const logger = defaultLogger;
|
|
38692
|
+
const logger = options?.logger || defaultLogger;
|
|
38429
38693
|
logger.info('开始进行依赖分析...');
|
|
38430
|
-
|
|
38694
|
+
const result = await resolveNASLFiles(entry, logger, true, options?.verbose ?? true);
|
|
38695
|
+
if (options?.save && result.mergedDependencies) {
|
|
38696
|
+
const srcDir = path$1.join(result.projectRoot, result.config.srcDir);
|
|
38697
|
+
const appDepsPath = path$1.join(srcDir, 'app.dependencies.json');
|
|
38698
|
+
await libExports.writeJson(appDepsPath, result.mergedDependencies, { spaces: 2 });
|
|
38699
|
+
logger.success(`已将 externalDependencies 补充到 ${appDepsPath}`);
|
|
38700
|
+
}
|
|
38701
|
+
return result;
|
|
38431
38702
|
}
|
|
38432
38703
|
|
|
38433
38704
|
/**
|
|
@@ -38437,15 +38708,15 @@ async function dev(entry, options) {
|
|
|
38437
38708
|
const logger = options?.logger || new ConsoleLoggerWithoutExit();
|
|
38438
38709
|
// 获取项目根目录和配置
|
|
38439
38710
|
const projectRoot = process.cwd();
|
|
38440
|
-
const configPath =
|
|
38711
|
+
const configPath = path$1.join(projectRoot, 'nasl.config.json');
|
|
38441
38712
|
if (!libExports.existsSync(configPath)) {
|
|
38442
38713
|
logger.error('未找到 nasl.config.json 配置文件,请先初始化项目');
|
|
38443
38714
|
process.exit(1);
|
|
38444
38715
|
}
|
|
38445
38716
|
const configContent = libExports.readFileSync(configPath, 'utf-8');
|
|
38446
38717
|
const config = JSON.parse(configContent);
|
|
38447
|
-
const srcDir =
|
|
38448
|
-
const outDir =
|
|
38718
|
+
const srcDir = path$1.join(projectRoot, config.srcDir);
|
|
38719
|
+
const outDir = path$1.join(projectRoot, config.outDir);
|
|
38449
38720
|
// 检查是否存在 src 目录
|
|
38450
38721
|
const hasSrcDir = libExports.existsSync(srcDir) && libExports.statSync(srcDir).isDirectory();
|
|
38451
38722
|
let lastCompileSuccess = false;
|
|
@@ -38495,7 +38766,7 @@ async function dev(entry, options) {
|
|
|
38495
38766
|
// 过滤非目标文件类型
|
|
38496
38767
|
if (!shouldHandleFile(filePath))
|
|
38497
38768
|
return;
|
|
38498
|
-
logger.info(`检测到文件变化: ${
|
|
38769
|
+
logger.info(`检测到文件变化: ${path$1.relative(projectRoot, filePath)}`);
|
|
38499
38770
|
if (isCompiling) {
|
|
38500
38771
|
pendingCompile = true;
|
|
38501
38772
|
return;
|
|
@@ -38612,7 +38883,7 @@ async function dev(entry, options) {
|
|
|
38612
38883
|
async function startWebpackDevServer(outDir, options, logger) {
|
|
38613
38884
|
logger?.newLine();
|
|
38614
38885
|
logger?.info('正在启动开发服务...');
|
|
38615
|
-
const configRelativePath =
|
|
38886
|
+
const configRelativePath = path$1.relative(outDir, path$1.resolve(__dirname, '../../build/webpack.config.js'));
|
|
38616
38887
|
// 构建 webpack-cli 参数
|
|
38617
38888
|
let webpackArgs = `${require.resolve('.bin/webpack-cli')} serve --config ${configRelativePath}`;
|
|
38618
38889
|
if (options?.port)
|
|
@@ -38656,7 +38927,7 @@ async function build(entry, options) {
|
|
|
38656
38927
|
const { outDir } = await compile(entry);
|
|
38657
38928
|
logger.newLine();
|
|
38658
38929
|
logger.info('正在构建项目...');
|
|
38659
|
-
const configRelativePath =
|
|
38930
|
+
const configRelativePath = path$1.relative(outDir, path$1.resolve(__dirname, '../../build/webpack.config.js'));
|
|
38660
38931
|
const mode = options?.mode || 'production';
|
|
38661
38932
|
// 构建 webpack-cli 参数
|
|
38662
38933
|
let webpackArgs = `${require.resolve('.bin/webpack-cli')} build --config ${configRelativePath} --mode ${mode}`;
|
|
@@ -38667,8 +38938,8 @@ async function build(entry, options) {
|
|
|
38667
38938
|
* 获取 specs 下第1个文件夹的名字
|
|
38668
38939
|
*/
|
|
38669
38940
|
function getFirstSpecFolderName(projectRoot) {
|
|
38670
|
-
const dirname =
|
|
38671
|
-
const specsDir =
|
|
38941
|
+
const dirname = path$1.basename(projectRoot);
|
|
38942
|
+
const specsDir = path$1.join(projectRoot, 'specs');
|
|
38672
38943
|
if (!libExports.existsSync(specsDir))
|
|
38673
38944
|
return dirname;
|
|
38674
38945
|
const entries = libExports.readdirSync(specsDir, { withFileTypes: true });
|
|
@@ -38759,6 +39030,8 @@ async function transformJson2FilesApi(json, options) {
|
|
|
38759
39030
|
headers: { 'Content-Type': 'application/json' },
|
|
38760
39031
|
});
|
|
38761
39032
|
const data = res.data;
|
|
39033
|
+
if (data.code !== 200)
|
|
39034
|
+
throw new Error(data.message);
|
|
38762
39035
|
return data.result;
|
|
38763
39036
|
}
|
|
38764
39037
|
|
|
@@ -38769,7 +39042,7 @@ const transformFns = {
|
|
|
38769
39042
|
async files2full(entry, options) {
|
|
38770
39043
|
const logger = options?.logger || defaultLogger;
|
|
38771
39044
|
// 收集需要处理的文件
|
|
38772
|
-
const { collectedFiles, projectRoot } = await resolveNASLFiles(entry, logger, false, options?.verbose);
|
|
39045
|
+
const { collectedFiles, projectRoot, mergedDependencies } = await resolveNASLFiles(entry, logger, false, options?.verbose);
|
|
38773
39046
|
if (collectedFiles.length === 0) {
|
|
38774
39047
|
logger.error('未找到需要转换的文件');
|
|
38775
39048
|
logger.exit(1);
|
|
@@ -38778,11 +39051,12 @@ const transformFns = {
|
|
|
38778
39051
|
// 组合成 fullNaturalTS
|
|
38779
39052
|
logger.newLine();
|
|
38780
39053
|
logger.info('正在组合文件...');
|
|
38781
|
-
|
|
39054
|
+
let fullNaturalTS = composeToString(collectedFiles);
|
|
39055
|
+
fullNaturalTS = prependDependencies(fullNaturalTS, mergedDependencies);
|
|
38782
39056
|
// 确定输出路径
|
|
38783
39057
|
const outputPath = options?.output
|
|
38784
|
-
?
|
|
38785
|
-
:
|
|
39058
|
+
? path$1.resolve(projectRoot, options.output)
|
|
39059
|
+
: path$1.join(projectRoot, './full-natural.ts');
|
|
38786
39060
|
// 写入文件
|
|
38787
39061
|
writeFileWithLog(outputPath, fullNaturalTS, logger);
|
|
38788
39062
|
logger.success(`文件已输出到: ${outputPath}`);
|
|
@@ -38812,7 +39086,7 @@ const transformFns = {
|
|
|
38812
39086
|
}
|
|
38813
39087
|
const files = await transformJson2FilesApi(jsonContent ? JSON.parse(jsonContent) : {}, config);
|
|
38814
39088
|
await Promise.all(files.map(async (file) => {
|
|
38815
|
-
const outputPath =
|
|
39089
|
+
const outputPath = path$1.join(projectRoot, config.srcDir, file.path);
|
|
38816
39090
|
await libExports.writeFile(outputPath, file.content);
|
|
38817
39091
|
}));
|
|
38818
39092
|
logger.success(`JSON 文件已转换为 ${files.length} 个文件,输出到 ${config.srcDir}`);
|
|
@@ -38839,7 +39113,87 @@ async function transform(transformType, entry, options) {
|
|
|
38839
39113
|
await transformFn(entry, options);
|
|
38840
39114
|
}
|
|
38841
39115
|
|
|
38842
|
-
|
|
39116
|
+
async function installAuto(options) {
|
|
39117
|
+
const logger = options?.logger || defaultLogger;
|
|
39118
|
+
const config = loadConfig();
|
|
39119
|
+
const projectRoot = getProjectRoot();
|
|
39120
|
+
const srcDir = path$1.join(projectRoot, config.srcDir);
|
|
39121
|
+
const appDependenciesJsonPath = path$1.join(srcDir, 'app.dependencies.json');
|
|
39122
|
+
const appDependenciesJson = libExports.readJsonSync(appDependenciesJsonPath);
|
|
39123
|
+
logger.info(`开始按照 ${appDependenciesJsonPath} 安装依赖`);
|
|
39124
|
+
return installByJSON(appDependenciesJson, options);
|
|
39125
|
+
}
|
|
39126
|
+
async function installByKind(kind, deps, options) {
|
|
39127
|
+
const logger = options?.logger || defaultLogger;
|
|
39128
|
+
if (!deps || deps.length === 0) {
|
|
39129
|
+
logger.error(`请至少指定一个要安装的 ${kind},例如:nasl install ${kind} aaa@0.1.0`);
|
|
39130
|
+
return logger.exit(1);
|
|
39131
|
+
}
|
|
39132
|
+
const dependencyMap = {};
|
|
39133
|
+
for (const dep of deps) {
|
|
39134
|
+
if (kind === 'api') {
|
|
39135
|
+
const [service, interfaces] = dep.split(':');
|
|
39136
|
+
if (!service || !interfaces) {
|
|
39137
|
+
logger.error(`无效的依赖格式:${dep},请使用 service:api1,api2 格式,例如:some_service:api1,api2`);
|
|
39138
|
+
return logger.exit(1);
|
|
39139
|
+
}
|
|
39140
|
+
dependencyMap[service] = interfaces.split(',');
|
|
39141
|
+
}
|
|
39142
|
+
else {
|
|
39143
|
+
const [name, version] = dep.split('@');
|
|
39144
|
+
if (!name || !version) {
|
|
39145
|
+
logger.error(`无效的依赖格式:${dep},请使用 name@version 格式,例如:aaa@0.1.0`);
|
|
39146
|
+
return logger.exit(1);
|
|
39147
|
+
}
|
|
39148
|
+
dependencyMap[name] = version;
|
|
39149
|
+
}
|
|
39150
|
+
}
|
|
39151
|
+
return installByJSON({ [kind + 's']: dependencyMap }, options);
|
|
39152
|
+
}
|
|
39153
|
+
async function installByJSON(json, options) {
|
|
39154
|
+
const logger = options?.logger || defaultLogger;
|
|
39155
|
+
if (!Object.keys(json).length) {
|
|
39156
|
+
logger.error('没有需要安装的依赖');
|
|
39157
|
+
return;
|
|
39158
|
+
}
|
|
39159
|
+
const config = loadConfig();
|
|
39160
|
+
const projectRoot = getProjectRoot();
|
|
39161
|
+
const srcDir = path$1.join(projectRoot, config.srcDir);
|
|
39162
|
+
const result = await installDependenciesApi(json, config);
|
|
39163
|
+
if (!result.files || result.files.length <= 1)
|
|
39164
|
+
throw new Error(`安装依赖失败,没有生成任何文件:\n${JSON.stringify(result)}`);
|
|
39165
|
+
if (result.errors.length > 0) {
|
|
39166
|
+
logger.error(`某些依赖安装失败:`);
|
|
39167
|
+
for (const error of result.errors)
|
|
39168
|
+
logger.error(error);
|
|
39169
|
+
}
|
|
39170
|
+
// const appDepsFile = result.files.find((f) => f.path === 'app.dependencies.json');
|
|
39171
|
+
const otherFiles = result.files.filter((f) => f.path !== 'app.dependencies.json');
|
|
39172
|
+
const jsonToSave = JSON.parse(JSON.stringify(json));
|
|
39173
|
+
for (const err of result.errors) {
|
|
39174
|
+
const { name, category } = err;
|
|
39175
|
+
const record = jsonToSave[category];
|
|
39176
|
+
if (record && typeof record === 'object') {
|
|
39177
|
+
delete record[name];
|
|
39178
|
+
if (Object.keys(record).length === 0)
|
|
39179
|
+
delete jsonToSave[category];
|
|
39180
|
+
}
|
|
39181
|
+
}
|
|
39182
|
+
if (options?.savePotential) {
|
|
39183
|
+
const potentialPath = path$1.join(srcDir, 'potential.dependencies.json');
|
|
39184
|
+
await libExports.writeJson(potentialPath, jsonToSave, { spaces: 2 });
|
|
39185
|
+
logger.success(`依赖信息已写入: ${path$1.relative(projectRoot, potentialPath)}`);
|
|
39186
|
+
}
|
|
39187
|
+
await Promise.all(otherFiles.map(async (file) => {
|
|
39188
|
+
const filePath = path$1.join(srcDir, file.path);
|
|
39189
|
+
await libExports.outputFile(filePath, file.content, 'utf-8');
|
|
39190
|
+
logger.success(`依赖文件已写入: ${path$1.relative(projectRoot, filePath)}`);
|
|
39191
|
+
}));
|
|
39192
|
+
const writtenCount = otherFiles.length;
|
|
39193
|
+
logger.success(`成功写入 ${writtenCount} 个依赖文件到 ${config.srcDir} 目录`);
|
|
39194
|
+
}
|
|
39195
|
+
|
|
39196
|
+
var version = "0.3.0";
|
|
38843
39197
|
var pkg = {
|
|
38844
39198
|
version: version};
|
|
38845
39199
|
|
|
@@ -38899,15 +39253,51 @@ program
|
|
|
38899
39253
|
program
|
|
38900
39254
|
.command('dep [entry]')
|
|
38901
39255
|
.description('从入口文件开始进行依赖分析')
|
|
38902
|
-
.
|
|
39256
|
+
.option('--save', '将计算出的 externalDependencies 补充到 src/app.dependencies.json')
|
|
39257
|
+
.action(async (entry, options) => {
|
|
38903
39258
|
try {
|
|
38904
|
-
await dep(entry);
|
|
39259
|
+
await dep(entry, options);
|
|
38905
39260
|
}
|
|
38906
39261
|
catch (error) {
|
|
38907
39262
|
defaultLogger.error(`查找依赖过程发生错误:${error.message}`);
|
|
38908
39263
|
process.exit(1);
|
|
38909
39264
|
}
|
|
38910
39265
|
});
|
|
39266
|
+
program
|
|
39267
|
+
.command('install [kind|by-json] [deps...]')
|
|
39268
|
+
.option('--save-potential', '将 app.dependencies.json 写入 potential.dependencies.json')
|
|
39269
|
+
.description(`安装一个或多个 uilib, extension, api 或 connector 依赖,例如:
|
|
39270
|
+
- nasl install uilib some_component@0.1.0 some_component@0.2.0
|
|
39271
|
+
- nasl install extension some_encryption@0.1.0 some_interceptor@0.2.0
|
|
39272
|
+
- nasl install api some_service:api1,api2 some_service:api3,api4
|
|
39273
|
+
- nasl install connector some_connector@0.1.0 some_connector@0.2.0
|
|
39274
|
+
- nasl install by-json '{"uilibs": {"some_component": "0.1.0"}, "extensions": {"some_encryption": "0.1.0", "some_interceptor": "0.2.0"}}'
|
|
39275
|
+
`)
|
|
39276
|
+
.action(async (kind, deps, options) => {
|
|
39277
|
+
try {
|
|
39278
|
+
if (kind === 'by-json') {
|
|
39279
|
+
if (deps.length < 1)
|
|
39280
|
+
throw new Error('请提供一个 JSON 字符串');
|
|
39281
|
+
else if (deps.length > 1)
|
|
39282
|
+
throw new Error('参数过多,JSON 字符串只能有一个');
|
|
39283
|
+
const jsonStr = deps[0];
|
|
39284
|
+
await installByJSON(JSON.parse(jsonStr), options);
|
|
39285
|
+
}
|
|
39286
|
+
else if (kind) {
|
|
39287
|
+
if (!['uilib', 'extension', 'api', 'connector'].includes(kind)) {
|
|
39288
|
+
throw new Error(`无效的依赖类型: ${kind}。\n支持的类型有: uilib, extension, api, connector`);
|
|
39289
|
+
}
|
|
39290
|
+
await installByKind(kind, deps, options);
|
|
39291
|
+
}
|
|
39292
|
+
else {
|
|
39293
|
+
await installAuto(options);
|
|
39294
|
+
}
|
|
39295
|
+
}
|
|
39296
|
+
catch (error) {
|
|
39297
|
+
defaultLogger.error(`安装过程发生错误:${error.message}`);
|
|
39298
|
+
process.exit(1);
|
|
39299
|
+
}
|
|
39300
|
+
});
|
|
38911
39301
|
program
|
|
38912
39302
|
.command('dev [entry]')
|
|
38913
39303
|
.description('启动开发服务')
|
|
@@ -39291,7 +39681,7 @@ const binaryExtensions = new Set([
|
|
|
39291
39681
|
'xmind', 'xpi', 'xpm', 'xwd', 'xz',
|
|
39292
39682
|
'z', 'zip', 'zipx',
|
|
39293
39683
|
]);
|
|
39294
|
-
const isBinaryPath = (filePath) => binaryExtensions.has(
|
|
39684
|
+
const isBinaryPath = (filePath) => binaryExtensions.has(path$1.extname(filePath).slice(1).toLowerCase());
|
|
39295
39685
|
// TODO: emit errors properly. Example: EMFILE on Macos.
|
|
39296
39686
|
const foreach = (val, fn) => {
|
|
39297
39687
|
if (val instanceof Set) {
|
|
@@ -39344,7 +39734,7 @@ function createFsWatchInstance(path, options, listener, errHandler, emitRaw) {
|
|
|
39344
39734
|
// emit based on events occurring for files from a directory's watcher in
|
|
39345
39735
|
// case the file's watcher misses it (and rely on throttling to de-dupe)
|
|
39346
39736
|
if (evPath && path !== evPath) {
|
|
39347
|
-
fsWatchBroadcast(
|
|
39737
|
+
fsWatchBroadcast(path$1.resolve(path, evPath), KEY_LISTENERS, path$1.join(path, evPath));
|
|
39348
39738
|
}
|
|
39349
39739
|
};
|
|
39350
39740
|
try {
|
|
@@ -39527,11 +39917,11 @@ class NodeFsHandler {
|
|
|
39527
39917
|
*/
|
|
39528
39918
|
_watchWithNodeFs(path, listener) {
|
|
39529
39919
|
const opts = this.fsw.options;
|
|
39530
|
-
const directory =
|
|
39531
|
-
const basename =
|
|
39920
|
+
const directory = path$1.dirname(path);
|
|
39921
|
+
const basename = path$1.basename(path);
|
|
39532
39922
|
const parent = this.fsw._getWatchedDir(directory);
|
|
39533
39923
|
parent.add(basename);
|
|
39534
|
-
const absolutePath =
|
|
39924
|
+
const absolutePath = path$1.resolve(path);
|
|
39535
39925
|
const options = {
|
|
39536
39926
|
persistent: opts.persistent,
|
|
39537
39927
|
};
|
|
@@ -39563,8 +39953,8 @@ class NodeFsHandler {
|
|
|
39563
39953
|
if (this.fsw.closed) {
|
|
39564
39954
|
return;
|
|
39565
39955
|
}
|
|
39566
|
-
const dirname =
|
|
39567
|
-
const basename =
|
|
39956
|
+
const dirname = path$1.dirname(file);
|
|
39957
|
+
const basename = path$1.basename(file);
|
|
39568
39958
|
const parent = this.fsw._getWatchedDir(dirname);
|
|
39569
39959
|
// stats is always present
|
|
39570
39960
|
let prevStats = stats;
|
|
@@ -39671,7 +40061,7 @@ class NodeFsHandler {
|
|
|
39671
40061
|
}
|
|
39672
40062
|
_handleRead(directory, initialAdd, wh, target, dir, depth, throttler) {
|
|
39673
40063
|
// Normalize the directory name on Windows
|
|
39674
|
-
directory =
|
|
40064
|
+
directory = path$1.join(directory, '');
|
|
39675
40065
|
throttler = this.fsw._throttle('readdir', directory, 1000);
|
|
39676
40066
|
if (!throttler)
|
|
39677
40067
|
return;
|
|
@@ -39690,7 +40080,7 @@ class NodeFsHandler {
|
|
|
39690
40080
|
return;
|
|
39691
40081
|
}
|
|
39692
40082
|
const item = entry.path;
|
|
39693
|
-
let path =
|
|
40083
|
+
let path = path$1.join(directory, item);
|
|
39694
40084
|
current.add(item);
|
|
39695
40085
|
if (entry.stats.isSymbolicLink() &&
|
|
39696
40086
|
(await this._handleSymlink(entry, directory, path, item))) {
|
|
@@ -39706,7 +40096,7 @@ class NodeFsHandler {
|
|
|
39706
40096
|
if (item === target || (!target && !previous.has(item))) {
|
|
39707
40097
|
this.fsw._incrReadyCount();
|
|
39708
40098
|
// ensure relativeness of path is preserved in case of watcher reuse
|
|
39709
|
-
path =
|
|
40099
|
+
path = path$1.join(dir, path$1.relative(dir, path));
|
|
39710
40100
|
this._addToNodeFs(path, initialAdd, wh, depth + 1);
|
|
39711
40101
|
}
|
|
39712
40102
|
})
|
|
@@ -39751,13 +40141,13 @@ class NodeFsHandler {
|
|
|
39751
40141
|
* @returns closer for the watcher instance.
|
|
39752
40142
|
*/
|
|
39753
40143
|
async _handleDir(dir, stats, initialAdd, depth, target, wh, realpath) {
|
|
39754
|
-
const parentDir = this.fsw._getWatchedDir(
|
|
39755
|
-
const tracked = parentDir.has(
|
|
40144
|
+
const parentDir = this.fsw._getWatchedDir(path$1.dirname(dir));
|
|
40145
|
+
const tracked = parentDir.has(path$1.basename(dir));
|
|
39756
40146
|
if (!(initialAdd && this.fsw.options.ignoreInitial) && !target && !tracked) {
|
|
39757
40147
|
this.fsw._emit(EV.ADD_DIR, dir, stats);
|
|
39758
40148
|
}
|
|
39759
40149
|
// ensure dir is tracked (harmless if redundant)
|
|
39760
|
-
parentDir.add(
|
|
40150
|
+
parentDir.add(path$1.basename(dir));
|
|
39761
40151
|
this.fsw._getWatchedDir(dir);
|
|
39762
40152
|
let throttler;
|
|
39763
40153
|
let closer;
|
|
@@ -39809,7 +40199,7 @@ class NodeFsHandler {
|
|
|
39809
40199
|
const follow = this.fsw.options.followSymlinks;
|
|
39810
40200
|
let closer;
|
|
39811
40201
|
if (stats.isDirectory()) {
|
|
39812
|
-
const absPath =
|
|
40202
|
+
const absPath = path$1.resolve(path);
|
|
39813
40203
|
const targetPath = follow ? await realpath$1(path) : path;
|
|
39814
40204
|
if (this.fsw.closed)
|
|
39815
40205
|
return;
|
|
@@ -39825,7 +40215,7 @@ class NodeFsHandler {
|
|
|
39825
40215
|
const targetPath = follow ? await realpath$1(path) : path;
|
|
39826
40216
|
if (this.fsw.closed)
|
|
39827
40217
|
return;
|
|
39828
|
-
const parent =
|
|
40218
|
+
const parent = path$1.dirname(wh.watchPath);
|
|
39829
40219
|
this.fsw._getWatchedDir(parent).add(wh.watchPath);
|
|
39830
40220
|
this.fsw._emit(EV.ADD, wh.watchPath, stats);
|
|
39831
40221
|
closer = await this._handleDir(parent, stats, initialAdd, depth, path, wh, targetPath);
|
|
@@ -39833,7 +40223,7 @@ class NodeFsHandler {
|
|
|
39833
40223
|
return;
|
|
39834
40224
|
// preserve this symlink's target path
|
|
39835
40225
|
if (targetPath !== undefined) {
|
|
39836
|
-
this.fsw._symlinkPaths.set(
|
|
40226
|
+
this.fsw._symlinkPaths.set(path$1.resolve(path), targetPath);
|
|
39837
40227
|
}
|
|
39838
40228
|
}
|
|
39839
40229
|
else {
|
|
@@ -39879,11 +40269,11 @@ function createPattern(matcher) {
|
|
|
39879
40269
|
if (matcher.path === string)
|
|
39880
40270
|
return true;
|
|
39881
40271
|
if (matcher.recursive) {
|
|
39882
|
-
const relative =
|
|
40272
|
+
const relative = path$1.relative(matcher.path, string);
|
|
39883
40273
|
if (!relative) {
|
|
39884
40274
|
return false;
|
|
39885
40275
|
}
|
|
39886
|
-
return !relative.startsWith('..') && !
|
|
40276
|
+
return !relative.startsWith('..') && !path$1.isAbsolute(relative);
|
|
39887
40277
|
}
|
|
39888
40278
|
return false;
|
|
39889
40279
|
};
|
|
@@ -39893,7 +40283,7 @@ function createPattern(matcher) {
|
|
|
39893
40283
|
function normalizePath(path) {
|
|
39894
40284
|
if (typeof path !== 'string')
|
|
39895
40285
|
throw new Error('string expected');
|
|
39896
|
-
path =
|
|
40286
|
+
path = path$1.normalize(path);
|
|
39897
40287
|
path = path.replace(/\\/g, '/');
|
|
39898
40288
|
let prepend = false;
|
|
39899
40289
|
if (path.startsWith('//'))
|
|
@@ -39953,21 +40343,21 @@ const toUnix = (string) => {
|
|
|
39953
40343
|
};
|
|
39954
40344
|
// Our version of upath.normalize
|
|
39955
40345
|
// TODO: this is not equal to path-normalize module - investigate why
|
|
39956
|
-
const normalizePathToUnix = (path) => toUnix(
|
|
40346
|
+
const normalizePathToUnix = (path) => toUnix(path$1.normalize(toUnix(path)));
|
|
39957
40347
|
// TODO: refactor
|
|
39958
40348
|
const normalizeIgnored = (cwd = '') => (path) => {
|
|
39959
40349
|
if (typeof path === 'string') {
|
|
39960
|
-
return normalizePathToUnix(
|
|
40350
|
+
return normalizePathToUnix(path$1.isAbsolute(path) ? path : path$1.join(cwd, path));
|
|
39961
40351
|
}
|
|
39962
40352
|
else {
|
|
39963
40353
|
return path;
|
|
39964
40354
|
}
|
|
39965
40355
|
};
|
|
39966
40356
|
const getAbsolutePath = (path, cwd) => {
|
|
39967
|
-
if (
|
|
40357
|
+
if (path$1.isAbsolute(path)) {
|
|
39968
40358
|
return path;
|
|
39969
40359
|
}
|
|
39970
|
-
return
|
|
40360
|
+
return path$1.join(cwd, path);
|
|
39971
40361
|
};
|
|
39972
40362
|
const EMPTY_SET = Object.freeze(new Set());
|
|
39973
40363
|
/**
|
|
@@ -39999,7 +40389,7 @@ class DirEntry {
|
|
|
39999
40389
|
}
|
|
40000
40390
|
catch (err) {
|
|
40001
40391
|
if (this._removeWatcher) {
|
|
40002
|
-
this._removeWatcher(
|
|
40392
|
+
this._removeWatcher(path$1.dirname(dir), path$1.basename(dir));
|
|
40003
40393
|
}
|
|
40004
40394
|
}
|
|
40005
40395
|
}
|
|
@@ -40031,7 +40421,7 @@ class WatchHelper {
|
|
|
40031
40421
|
const watchPath = path;
|
|
40032
40422
|
this.path = path = path.replace(REPLACER_RE, '');
|
|
40033
40423
|
this.watchPath = watchPath;
|
|
40034
|
-
this.fullWatchPath =
|
|
40424
|
+
this.fullWatchPath = path$1.resolve(watchPath);
|
|
40035
40425
|
this.dirParts = [];
|
|
40036
40426
|
this.dirParts.forEach((parts) => {
|
|
40037
40427
|
if (parts.length > 1)
|
|
@@ -40041,7 +40431,7 @@ class WatchHelper {
|
|
|
40041
40431
|
this.statMethod = follow ? STAT_METHOD_F : STAT_METHOD_L;
|
|
40042
40432
|
}
|
|
40043
40433
|
entryPath(entry) {
|
|
40044
|
-
return
|
|
40434
|
+
return path$1.join(this.watchPath, path$1.relative(this.watchPath, entry.fullPath));
|
|
40045
40435
|
}
|
|
40046
40436
|
filterPath(entry) {
|
|
40047
40437
|
const { stats } = entry;
|
|
@@ -40197,7 +40587,7 @@ class FSWatcher extends EventEmitter {
|
|
|
40197
40587
|
return;
|
|
40198
40588
|
results.forEach((item) => {
|
|
40199
40589
|
if (item)
|
|
40200
|
-
this.add(
|
|
40590
|
+
this.add(path$1.dirname(item), path$1.basename(_origAdd || item));
|
|
40201
40591
|
});
|
|
40202
40592
|
});
|
|
40203
40593
|
return this;
|
|
@@ -40212,10 +40602,10 @@ class FSWatcher extends EventEmitter {
|
|
|
40212
40602
|
const { cwd } = this.options;
|
|
40213
40603
|
paths.forEach((path) => {
|
|
40214
40604
|
// convert to absolute path unless relative path already matches
|
|
40215
|
-
if (!
|
|
40605
|
+
if (!path$1.isAbsolute(path) && !this._closers.has(path)) {
|
|
40216
40606
|
if (cwd)
|
|
40217
|
-
path =
|
|
40218
|
-
path =
|
|
40607
|
+
path = path$1.join(cwd, path);
|
|
40608
|
+
path = path$1.resolve(path);
|
|
40219
40609
|
}
|
|
40220
40610
|
this._closePath(path);
|
|
40221
40611
|
this._addIgnoredPath(path);
|
|
@@ -40269,7 +40659,7 @@ class FSWatcher extends EventEmitter {
|
|
|
40269
40659
|
getWatched() {
|
|
40270
40660
|
const watchList = {};
|
|
40271
40661
|
this._watched.forEach((entry, dir) => {
|
|
40272
|
-
const key = this.options.cwd ?
|
|
40662
|
+
const key = this.options.cwd ? path$1.relative(this.options.cwd, dir) : dir;
|
|
40273
40663
|
const index = key || ONE_DOT;
|
|
40274
40664
|
watchList[index] = entry.getChildren().sort();
|
|
40275
40665
|
});
|
|
@@ -40295,9 +40685,9 @@ class FSWatcher extends EventEmitter {
|
|
|
40295
40685
|
return;
|
|
40296
40686
|
const opts = this.options;
|
|
40297
40687
|
if (isWindows)
|
|
40298
|
-
path =
|
|
40688
|
+
path = path$1.normalize(path);
|
|
40299
40689
|
if (opts.cwd)
|
|
40300
|
-
path =
|
|
40690
|
+
path = path$1.relative(opts.cwd, path);
|
|
40301
40691
|
const args = [path];
|
|
40302
40692
|
if (stats != null)
|
|
40303
40693
|
args.push(stats);
|
|
@@ -40353,7 +40743,7 @@ class FSWatcher extends EventEmitter {
|
|
|
40353
40743
|
if (opts.alwaysStat &&
|
|
40354
40744
|
stats === undefined &&
|
|
40355
40745
|
(event === EVENTS.ADD || event === EVENTS.ADD_DIR || event === EVENTS.CHANGE)) {
|
|
40356
|
-
const fullPath = opts.cwd ?
|
|
40746
|
+
const fullPath = opts.cwd ? path$1.join(opts.cwd, path) : path;
|
|
40357
40747
|
let stats;
|
|
40358
40748
|
try {
|
|
40359
40749
|
stats = await stat$2(fullPath);
|
|
@@ -40436,8 +40826,8 @@ class FSWatcher extends EventEmitter {
|
|
|
40436
40826
|
const pollInterval = awf.pollInterval;
|
|
40437
40827
|
let timeoutHandler;
|
|
40438
40828
|
let fullPath = path;
|
|
40439
|
-
if (this.options.cwd && !
|
|
40440
|
-
fullPath =
|
|
40829
|
+
if (this.options.cwd && !path$1.isAbsolute(path)) {
|
|
40830
|
+
fullPath = path$1.join(this.options.cwd, path);
|
|
40441
40831
|
}
|
|
40442
40832
|
const now = new Date();
|
|
40443
40833
|
const writes = this._pendingWrites;
|
|
@@ -40508,7 +40898,7 @@ class FSWatcher extends EventEmitter {
|
|
|
40508
40898
|
* @param directory path of the directory
|
|
40509
40899
|
*/
|
|
40510
40900
|
_getWatchedDir(directory) {
|
|
40511
|
-
const dir =
|
|
40901
|
+
const dir = path$1.resolve(directory);
|
|
40512
40902
|
if (!this._watched.has(dir))
|
|
40513
40903
|
this._watched.set(dir, new DirEntry(dir, this._boundRemove));
|
|
40514
40904
|
return this._watched.get(dir);
|
|
@@ -40534,8 +40924,8 @@ class FSWatcher extends EventEmitter {
|
|
|
40534
40924
|
// if what is being deleted is a directory, get that directory's paths
|
|
40535
40925
|
// for recursive deleting and cleaning of watched object
|
|
40536
40926
|
// if it is not a directory, nestedDirectoryChildren will be empty array
|
|
40537
|
-
const path =
|
|
40538
|
-
const fullPath =
|
|
40927
|
+
const path = path$1.join(directory, item);
|
|
40928
|
+
const fullPath = path$1.resolve(path);
|
|
40539
40929
|
isDirectory =
|
|
40540
40930
|
isDirectory != null ? isDirectory : this._watched.has(path) || this._watched.has(fullPath);
|
|
40541
40931
|
// prevent duplicate handling in case of arriving here nearly simultaneously
|
|
@@ -40567,7 +40957,7 @@ class FSWatcher extends EventEmitter {
|
|
|
40567
40957
|
// If we wait for this file to be fully written, cancel the wait.
|
|
40568
40958
|
let relPath = path;
|
|
40569
40959
|
if (this.options.cwd)
|
|
40570
|
-
relPath =
|
|
40960
|
+
relPath = path$1.relative(this.options.cwd, path);
|
|
40571
40961
|
if (this.options.awaitWriteFinish && this._pendingWrites.has(relPath)) {
|
|
40572
40962
|
const event = this._pendingWrites.get(relPath).cancelWait();
|
|
40573
40963
|
if (event === EVENTS.ADD)
|
|
@@ -40588,8 +40978,8 @@ class FSWatcher extends EventEmitter {
|
|
|
40588
40978
|
*/
|
|
40589
40979
|
_closePath(path) {
|
|
40590
40980
|
this._closeFile(path);
|
|
40591
|
-
const dir =
|
|
40592
|
-
this._getWatchedDir(dir).remove(
|
|
40981
|
+
const dir = path$1.dirname(path);
|
|
40982
|
+
this._getWatchedDir(dir).remove(path$1.basename(path));
|
|
40593
40983
|
}
|
|
40594
40984
|
/**
|
|
40595
40985
|
* Closes only file-specific watchers
|