@nasl/cli 0.1.6 → 0.1.8

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 CHANGED
@@ -1,16 +1,16 @@
1
1
  #!/usr/bin/env node
2
2
  #!/usr/bin/env node
3
3
  import require$$0$1, { EventEmitter } from 'events';
4
- import require$$1, { spawnSync } from 'child_process';
5
- import * as path$1 from 'path';
6
- import path__default from 'path';
7
- import require$$0$2 from 'fs';
4
+ import require$$1, { spawn, spawnSync } from 'child_process';
5
+ import * as sysPath from 'path';
6
+ import sysPath__default from 'path';
7
+ import require$$0$2, { unwatchFile, watchFile, watch as watch$1, stat as stat$3 } from 'fs';
8
8
  import require$$4 from 'process';
9
9
  import require$$0$3 from 'constants';
10
10
  import stream$4, { Readable } from 'stream';
11
11
  import require$$0$4 from 'util';
12
12
  import require$$5 from 'assert';
13
- import require$$0$5 from 'os';
13
+ import require$$0$5, { type as type$1 } from 'os';
14
14
  import require$$1$1 from 'tty';
15
15
  import require$$3 from 'http';
16
16
  import require$$4$1 from 'https';
@@ -18,6 +18,10 @@ import require$$0$6 from 'url';
18
18
  import require$$8 from 'crypto';
19
19
  import http2 from 'http2';
20
20
  import zlib from 'zlib';
21
+ import { realpath as realpath$1, stat as stat$2, lstat as lstat$1, open, readdir as readdir$1 } from 'fs/promises';
22
+ import { lstat, stat as stat$1, readdir, realpath } from 'node:fs/promises';
23
+ import { Readable as Readable$1 } from 'node:stream';
24
+ import { resolve, join, relative, sep } from 'node:path';
21
25
 
22
26
  var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
23
27
 
@@ -1166,7 +1170,7 @@ function requireCommand () {
1166
1170
  hasRequiredCommand = 1;
1167
1171
  const EventEmitter = require$$0$1.EventEmitter;
1168
1172
  const childProcess = require$$1;
1169
- const path = path__default;
1173
+ const path = sysPath__default;
1170
1174
  const fs = require$$0$2;
1171
1175
  const process = require$$4;
1172
1176
 
@@ -4576,7 +4580,7 @@ var hasRequiredUtils$5;
4576
4580
  function requireUtils$5 () {
4577
4581
  if (hasRequiredUtils$5) return utils$7;
4578
4582
  hasRequiredUtils$5 = 1;
4579
- const path = path__default;
4583
+ const path = sysPath__default;
4580
4584
 
4581
4585
  // https://github.com/nodejs/node/issues/8987
4582
4586
  // https://github.com/libuv/libuv/pull/1088
@@ -4722,7 +4726,7 @@ function requireStat () {
4722
4726
  hasRequiredStat = 1;
4723
4727
 
4724
4728
  const fs = /*@__PURE__*/ requireFs$4();
4725
- const path = path__default;
4729
+ const path = sysPath__default;
4726
4730
  const u = requireUniversalify().fromPromise;
4727
4731
 
4728
4732
  function getStats (src, dest, opts) {
@@ -4926,7 +4930,7 @@ function requireCopy$1 () {
4926
4930
  hasRequiredCopy$1 = 1;
4927
4931
 
4928
4932
  const fs = /*@__PURE__*/ requireFs$4();
4929
- const path = path__default;
4933
+ const path = sysPath__default;
4930
4934
  const { mkdirs } = /*@__PURE__*/ requireMkdirs();
4931
4935
  const { pathExists } = /*@__PURE__*/ requirePathExists();
4932
4936
  const { utimesMillis } = /*@__PURE__*/ requireUtimes();
@@ -5109,7 +5113,7 @@ function requireCopySync () {
5109
5113
  hasRequiredCopySync = 1;
5110
5114
 
5111
5115
  const fs = requireGracefulFs();
5112
- const path = path__default;
5116
+ const path = sysPath__default;
5113
5117
  const mkdirsSync = /*@__PURE__*/ requireMkdirs().mkdirsSync;
5114
5118
  const utimesMillisSync = /*@__PURE__*/ requireUtimes().utimesMillisSync;
5115
5119
  const stat = /*@__PURE__*/ requireStat();
@@ -5329,7 +5333,7 @@ function requireEmpty () {
5329
5333
 
5330
5334
  const u = requireUniversalify().fromPromise;
5331
5335
  const fs = /*@__PURE__*/ requireFs$4();
5332
- const path = path__default;
5336
+ const path = sysPath__default;
5333
5337
  const mkdir = /*@__PURE__*/ requireMkdirs();
5334
5338
  const remove = /*@__PURE__*/ requireRemove();
5335
5339
 
@@ -5375,7 +5379,7 @@ function requireFile () {
5375
5379
  hasRequiredFile = 1;
5376
5380
 
5377
5381
  const u = requireUniversalify().fromPromise;
5378
- const path = path__default;
5382
+ const path = sysPath__default;
5379
5383
  const fs = /*@__PURE__*/ requireFs$4();
5380
5384
  const mkdir = /*@__PURE__*/ requireMkdirs();
5381
5385
 
@@ -5449,7 +5453,7 @@ function requireLink () {
5449
5453
  hasRequiredLink = 1;
5450
5454
 
5451
5455
  const u = requireUniversalify().fromPromise;
5452
- const path = path__default;
5456
+ const path = sysPath__default;
5453
5457
  const fs = /*@__PURE__*/ requireFs$4();
5454
5458
  const mkdir = /*@__PURE__*/ requireMkdirs();
5455
5459
  const { pathExists } = /*@__PURE__*/ requirePathExists();
@@ -5520,7 +5524,7 @@ function requireSymlinkPaths () {
5520
5524
  if (hasRequiredSymlinkPaths) return symlinkPaths_1;
5521
5525
  hasRequiredSymlinkPaths = 1;
5522
5526
 
5523
- const path = path__default;
5527
+ const path = sysPath__default;
5524
5528
  const fs = /*@__PURE__*/ requireFs$4();
5525
5529
  const { pathExists } = /*@__PURE__*/ requirePathExists();
5526
5530
 
@@ -5672,7 +5676,7 @@ function requireSymlink () {
5672
5676
  hasRequiredSymlink = 1;
5673
5677
 
5674
5678
  const u = requireUniversalify().fromPromise;
5675
- const path = path__default;
5679
+ const path = sysPath__default;
5676
5680
  const fs = /*@__PURE__*/ requireFs$4();
5677
5681
 
5678
5682
  const { mkdirs, mkdirsSync } = /*@__PURE__*/ requireMkdirs();
@@ -5918,7 +5922,7 @@ function requireOutputFile () {
5918
5922
 
5919
5923
  const u = requireUniversalify().fromPromise;
5920
5924
  const fs = /*@__PURE__*/ requireFs$4();
5921
- const path = path__default;
5925
+ const path = sysPath__default;
5922
5926
  const mkdir = /*@__PURE__*/ requireMkdirs();
5923
5927
  const pathExists = /*@__PURE__*/ requirePathExists().pathExists;
5924
5928
 
@@ -6020,7 +6024,7 @@ function requireMove$1 () {
6020
6024
  hasRequiredMove$1 = 1;
6021
6025
 
6022
6026
  const fs = /*@__PURE__*/ requireFs$4();
6023
- const path = path__default;
6027
+ const path = sysPath__default;
6024
6028
  const { copy } = /*@__PURE__*/ requireCopy();
6025
6029
  const { remove } = /*@__PURE__*/ requireRemove();
6026
6030
  const { mkdirp } = /*@__PURE__*/ requireMkdirs();
@@ -6087,7 +6091,7 @@ function requireMoveSync () {
6087
6091
  hasRequiredMoveSync = 1;
6088
6092
 
6089
6093
  const fs = requireGracefulFs();
6090
- const path = path__default;
6094
+ const path = sysPath__default;
6091
6095
  const copySync = /*@__PURE__*/ requireCopy().copySync;
6092
6096
  const removeSync = /*@__PURE__*/ requireRemove().removeSync;
6093
6097
  const mkdirpSync = /*@__PURE__*/ requireMkdirs().mkdirpSync;
@@ -8187,15 +8191,15 @@ var dayjs = /*@__PURE__*/getDefaultExportFromCjs(dayjs_minExports);
8187
8191
 
8188
8192
  function fastLogToFile(entry, suffix, content) {
8189
8193
  if (process.env.NASL_CLI_LOG_DIR) {
8190
- const logDir = path$1.resolve(process.env.NASL_CLI_LOG_DIR);
8194
+ const logDir = sysPath.resolve(process.env.NASL_CLI_LOG_DIR);
8191
8195
  libExports.ensureDirSync(logDir);
8192
8196
  const timeInDir = (process.env.NASL_CLI_LOG_DIR.match(/\d{6,8}_(\d{6})-/)?.[1] || '00');
8193
8197
  const now = dayjs();
8194
8198
  const hourInDir = parseInt(timeInDir.slice(0, 2), 10);
8195
8199
  // 跨天则累加 24 小时
8196
8200
  const hourStr = (now.hour() >= hourInDir ? now.hour() : Math.ceil(hourInDir / 24) * 24 + now.hour()).toString().padStart(2, '0');
8197
- const entryName = path$1.basename(Array.isArray(entry) ? entry[0] || '*' : entry).replace(/[\[\]\(\)\{\}\*\+\-\?\|\^\$\,\/\#\:\\\s]+/g, '_');
8198
- const filePath = path$1.resolve(logDir, `${hourStr}${now.format('mmss_SSS')}-${entryName}-${suffix}`);
8201
+ const entryName = sysPath.basename(Array.isArray(entry) ? entry[0] || '*' : entry).replace(/[\[\]\(\)\{\}\*\+\-\?\|\^\$\,\/\#\:\\\s]+/g, '_');
8202
+ const filePath = sysPath.resolve(logDir, `${hourStr}${now.format('mmss_SSS')}-${entryName}-${suffix}`);
8199
8203
  libExports.outputFileSync(filePath, content);
8200
8204
  }
8201
8205
  }
@@ -8226,16 +8230,16 @@ class BaseLogger {
8226
8230
  }
8227
8231
  debugToFile(topic, ...args) {
8228
8232
  if (process.env.DEBUG_TO_FILE) {
8229
- const baseDir = path$1.join(process.cwd(), '.nasl');
8233
+ const baseDir = sysPath.join(process.cwd(), '.nasl');
8230
8234
  const currentHour = dayjs().format('YYYYMMDD_HH');
8231
8235
  const prevHour = dayjs().subtract(1, 'hour').format('YYYYMMDD_HH');
8232
8236
  let subdir = `${topic}_${currentHour}`;
8233
8237
  const prevSubdir = `${topic}_${prevHour}`;
8234
8238
  // 判断如果有上一个小时的 subdir,则自己汇聚到上一个小时的 subdir 中
8235
- if (libExports.existsSync(path$1.join(baseDir, prevSubdir)))
8239
+ if (libExports.existsSync(sysPath.join(baseDir, prevSubdir)))
8236
8240
  subdir = prevSubdir;
8237
8241
  const fileName = `${topic}_${dayjs().format('YYYYMMDD_HHmmss')}.log`;
8238
- const filePath = path$1.join(baseDir, subdir, fileName);
8242
+ const filePath = sysPath.join(baseDir, subdir, fileName);
8239
8243
  libExports.outputFileSync(filePath, args.join(' '));
8240
8244
  }
8241
8245
  }
@@ -8283,6 +8287,13 @@ class ConsoleLogger extends BaseLogger {
8283
8287
  process.exit(code);
8284
8288
  }
8285
8289
  }
8290
+ class ConsoleLoggerWithoutExit extends ConsoleLogger {
8291
+ exit(code) {
8292
+ if (code)
8293
+ throw new Error(`Error with code: ${code}`);
8294
+ return undefined;
8295
+ }
8296
+ }
8286
8297
  const defaultLogger = new ConsoleLogger();
8287
8298
 
8288
8299
  /**
@@ -8293,11 +8304,11 @@ function findConfigDir(startDir = process.cwd()) {
8293
8304
  let currentDir = startDir;
8294
8305
  // eslint-disable-next-line no-constant-condition
8295
8306
  while (true) {
8296
- const configPath = path$1.join(currentDir, CONFIG_FILE_NAME);
8307
+ const configPath = sysPath.join(currentDir, CONFIG_FILE_NAME);
8297
8308
  if (libExports.existsSync(configPath)) {
8298
8309
  return currentDir;
8299
8310
  }
8300
- const parentDir = path$1.dirname(currentDir);
8311
+ const parentDir = sysPath.dirname(currentDir);
8301
8312
  // 已经到达根目录
8302
8313
  if (parentDir === currentDir) {
8303
8314
  return null;
@@ -8314,7 +8325,7 @@ function loadConfig(configDir) {
8314
8325
  defaultLogger.error(`未找到配置文件 ${CONFIG_FILE_NAME},请先运行 nasl-init 初始化配置`);
8315
8326
  return defaultLogger.exit(1);
8316
8327
  }
8317
- const configPath = path$1.join(dir, CONFIG_FILE_NAME);
8328
+ const configPath = sysPath.join(dir, CONFIG_FILE_NAME);
8318
8329
  try {
8319
8330
  const content = libExports.readFileSync(configPath, 'utf-8');
8320
8331
  const config = JSON.parse(content);
@@ -8359,7 +8370,7 @@ function readFileWithLog(filePath, logger) {
8359
8370
  */
8360
8371
  function writeFileWithLog(filePath, content, logger) {
8361
8372
  try {
8362
- const dir = path$1.dirname(filePath);
8373
+ const dir = sysPath.dirname(filePath);
8363
8374
  libExports.ensureDirSync(dir);
8364
8375
  libExports.writeFileSync(filePath, content, 'utf-8');
8365
8376
  }
@@ -8374,7 +8385,7 @@ function writeFileWithLog(filePath, content, logger) {
8374
8385
  */
8375
8386
  function init() {
8376
8387
  const cwd = process.cwd();
8377
- const configPath = path$1.join(cwd, CONFIG_FILE_NAME);
8388
+ const configPath = sysPath.join(cwd, CONFIG_FILE_NAME);
8378
8389
  // 检查配置文件是否已存在
8379
8390
  if (libExports.existsSync(configPath)) {
8380
8391
  defaultLogger.warn(`配置文件已存在: ${configPath}`);
@@ -8388,7 +8399,7 @@ function init() {
8388
8399
  defaultLogger.info('\n配置内容:');
8389
8400
  defaultLogger.info(JSON.stringify(DEFAULT_CONFIG, null, 2));
8390
8401
  // 创建源代码目录
8391
- const srcDirPath = path$1.join(cwd, DEFAULT_CONFIG.srcDir);
8402
+ const srcDirPath = sysPath.join(cwd, DEFAULT_CONFIG.srcDir);
8392
8403
  libExports.ensureDirSync(srcDirPath);
8393
8404
  defaultLogger.success(`源代码目录已创建: ${srcDirPath}`);
8394
8405
  defaultLogger.info('\n提示:');
@@ -20380,7 +20391,7 @@ function requireMimeTypes () {
20380
20391
  */
20381
20392
 
20382
20393
  var db = requireMimeDb();
20383
- var extname = path__default.extname;
20394
+ var extname = sysPath__default.extname;
20384
20395
 
20385
20396
  /**
20386
20397
  * Module variables.
@@ -22121,7 +22132,7 @@ function requireForm_data () {
22121
22132
 
22122
22133
  var CombinedStream = requireCombined_stream();
22123
22134
  var util = require$$0$4;
22124
- var path = path__default;
22135
+ var path = sysPath__default;
22125
22136
  var http = require$$3;
22126
22137
  var https = require$$4$1;
22127
22138
  var parseUrl = require$$0$6.parse;
@@ -26888,7 +26899,7 @@ var httpAdapter = isHttpAdapterSupported && function httpAdapter(config) {
26888
26899
  } else {
26889
26900
  options.hostname = parsed.hostname.startsWith("[") ? parsed.hostname.slice(1, -1) : parsed.hostname;
26890
26901
  options.port = parsed.port;
26891
- setProxy(options, config.proxy, protocol + '//' + parsed.hostname + (parsed.port ? ':' + parsed.port : '') + options.path);
26902
+ setProxy(options, config.proxy, protocol + '//' + parsed.hostname + (parsed.port ? ':' + parsed.port : parsed.protocol === 'https:' ? '443' : '') + options.path);
26892
26903
  }
26893
26904
 
26894
26905
  let transport;
@@ -29204,7 +29215,7 @@ function requirePath () {
29204
29215
  Object.defineProperty(path, "__esModule", { value: true });
29205
29216
  path.convertPosixPathToPattern = path.convertWindowsPathToPattern = path.convertPathToPattern = path.escapePosixPath = path.escapeWindowsPath = path.escape = path.removeLeadingDotSegment = path.makeAbsolute = path.unixify = void 0;
29206
29217
  const os = require$$0$5;
29207
- const path$1 = path__default;
29218
+ const path$1 = sysPath__default;
29208
29219
  const IS_WINDOWS_PLATFORM = os.platform() === 'win32';
29209
29220
  const LEADING_DOT_SEGMENT_CHARACTERS_COUNT = 2; // ./ or .\\
29210
29221
  /**
@@ -29469,7 +29480,7 @@ function requireGlobParent () {
29469
29480
  hasRequiredGlobParent = 1;
29470
29481
 
29471
29482
  var isGlob = requireIsGlob();
29472
- var pathPosixDirname = path__default.posix.dirname;
29483
+ var pathPosixDirname = sysPath__default.posix.dirname;
29473
29484
  var isWin32 = require$$0$5.platform() === 'win32';
29474
29485
 
29475
29486
  var slash = '/';
@@ -31041,7 +31052,7 @@ function requireConstants$1 () {
31041
31052
  if (hasRequiredConstants$1) return constants$1;
31042
31053
  hasRequiredConstants$1 = 1;
31043
31054
 
31044
- const path = path__default;
31055
+ const path = sysPath__default;
31045
31056
  const WIN_SLASH = '\\\\/';
31046
31057
  const WIN_NO_SLASH = `[^${WIN_SLASH}]`;
31047
31058
 
@@ -31228,7 +31239,7 @@ function requireUtils$2 () {
31228
31239
  hasRequiredUtils$2 = 1;
31229
31240
  (function (exports$1) {
31230
31241
 
31231
- const path = path__default;
31242
+ const path = sysPath__default;
31232
31243
  const win32 = process.platform === 'win32';
31233
31244
  const {
31234
31245
  REGEX_BACKSLASH,
@@ -32799,7 +32810,7 @@ function requirePicomatch$1 () {
32799
32810
  if (hasRequiredPicomatch$1) return picomatch_1;
32800
32811
  hasRequiredPicomatch$1 = 1;
32801
32812
 
32802
- const path = path__default;
32813
+ const path = sysPath__default;
32803
32814
  const scan = requireScan();
32804
32815
  const parse = requireParse();
32805
32816
  const utils = requireUtils$2();
@@ -33642,7 +33653,7 @@ function requirePattern () {
33642
33653
  hasRequiredPattern = 1;
33643
33654
  Object.defineProperty(pattern, "__esModule", { value: true });
33644
33655
  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;
33645
- const path = path__default;
33656
+ const path = sysPath__default;
33646
33657
  const globParent = requireGlobParent();
33647
33658
  const micromatch = requireMicromatch();
33648
33659
  const GLOBSTAR = '**';
@@ -34596,7 +34607,7 @@ function requireSettings$2 () {
34596
34607
  if (hasRequiredSettings$2) return settings$2;
34597
34608
  hasRequiredSettings$2 = 1;
34598
34609
  Object.defineProperty(settings$2, "__esModule", { value: true });
34599
- const path = path__default;
34610
+ const path = sysPath__default;
34600
34611
  const fsStat = requireOut$3();
34601
34612
  const fs = requireFs();
34602
34613
  class Settings {
@@ -35358,7 +35369,7 @@ function requireSettings$1 () {
35358
35369
  if (hasRequiredSettings$1) return settings$1;
35359
35370
  hasRequiredSettings$1 = 1;
35360
35371
  Object.defineProperty(settings$1, "__esModule", { value: true });
35361
- const path = path__default;
35372
+ const path = sysPath__default;
35362
35373
  const fsScandir = requireOut$2();
35363
35374
  class Settings {
35364
35375
  constructor(_options = {}) {
@@ -35434,7 +35445,7 @@ function requireReader () {
35434
35445
  if (hasRequiredReader) return reader;
35435
35446
  hasRequiredReader = 1;
35436
35447
  Object.defineProperty(reader, "__esModule", { value: true });
35437
- const path = path__default;
35448
+ const path = sysPath__default;
35438
35449
  const fsStat = requireOut$3();
35439
35450
  const utils = requireUtils$1();
35440
35451
  class Reader {
@@ -35907,7 +35918,7 @@ function requireProvider () {
35907
35918
  if (hasRequiredProvider) return provider;
35908
35919
  hasRequiredProvider = 1;
35909
35920
  Object.defineProperty(provider, "__esModule", { value: true });
35910
- const path = path__default;
35921
+ const path = sysPath__default;
35911
35922
  const deep_1 = requireDeep();
35912
35923
  const entry_1 = requireEntry$1();
35913
35924
  const error_1 = requireError();
@@ -36347,7 +36358,7 @@ var hasRequiredDirGlob;
36347
36358
  function requireDirGlob () {
36348
36359
  if (hasRequiredDirGlob) return dirGlob.exports;
36349
36360
  hasRequiredDirGlob = 1;
36350
- const path = path__default;
36361
+ const path = sysPath__default;
36351
36362
  const pathType = requirePathType();
36352
36363
 
36353
36364
  const getExtensions = extensions => extensions.length > 1 ? `{${extensions.join(',')}}` : extensions[0];
@@ -37097,7 +37108,7 @@ function requireGitignore () {
37097
37108
  hasRequiredGitignore = 1;
37098
37109
  const {promisify} = require$$0$4;
37099
37110
  const fs = require$$0$2;
37100
- const path = path__default;
37111
+ const path = sysPath__default;
37101
37112
  const fastGlob = requireOut();
37102
37113
  const gitIgnore = requireIgnore();
37103
37114
  const slash = requireSlash();
@@ -37533,7 +37544,7 @@ function replaceViewAsSignature(content) {
37533
37544
  * @returns 文件信息和新发现的依赖文件列表
37534
37545
  */
37535
37546
  function processFileDeps(pathRelativeToSrc, srcDir, matchedFileSet, processedFileMap, depNotFoundList, logger, verbose) {
37536
- const absoluteFilePath = path$1.join(srcDir, pathRelativeToSrc);
37547
+ const absoluteFilePath = sysPath.join(srcDir, pathRelativeToSrc);
37537
37548
  const fileInfo = { path: pathRelativeToSrc, content: '' };
37538
37549
  try {
37539
37550
  fileInfo.content = readFileWithLog(absoluteFilePath, logger);
@@ -37597,15 +37608,15 @@ async function collectDeps(patterns, projectRoot, srcDir, logger, verbose) {
37597
37608
  throw new Error('未找到匹配的入口文件');
37598
37609
  }
37599
37610
  logger.info(`找到 ${matchedFiles.length} 个入口文件`);
37600
- const absoluteSrcDir = path$1.resolve(srcDir);
37611
+ const absoluteSrcDir = sysPath.resolve(srcDir);
37601
37612
  const matchedFileSet = new Set();
37602
37613
  matchedFiles.forEach((pathRelativeToRoot) => {
37603
37614
  // 统一使用相对于 src 的路径
37604
- const absoluteFilePath = path$1.resolve(projectRoot, pathRelativeToRoot);
37615
+ const absoluteFilePath = sysPath.resolve(projectRoot, pathRelativeToRoot);
37605
37616
  // 判断 file 是否超出 srcDir 目录(支持相对路径和绝对路径)
37606
37617
  if (!absoluteFilePath.startsWith(absoluteSrcDir))
37607
37618
  throw new Error(`入口文件 ${absoluteFilePath} 超出了源代码目录 ${srcDir}`);
37608
- const pathRelativeToSrc = path$1.relative(srcDir, absoluteFilePath);
37619
+ const pathRelativeToSrc = sysPath.relative(srcDir, absoluteFilePath);
37609
37620
  filesToProcess.push(pathRelativeToSrc);
37610
37621
  matchedFileSet.add(pathRelativeToSrc);
37611
37622
  });
@@ -37654,7 +37665,7 @@ async function resolveNASLFiles(entry, logger, depMode, verbose) {
37654
37665
  const projectRoot = getProjectRoot();
37655
37666
  logger.info(`项目根目录: ${projectRoot}`);
37656
37667
  logger.info(`源代码目录: ${config.srcDir}`);
37657
- const srcDir = path$1.join(projectRoot, config.srcDir);
37668
+ const srcDir = sysPath.join(projectRoot, config.srcDir);
37658
37669
  // 收集需要处理的文件
37659
37670
  let collectedFiles = [];
37660
37671
  if (Array.isArray(entry) && !entry.length) {
@@ -37688,7 +37699,7 @@ async function resolveNASLFiles(entry, logger, depMode, verbose) {
37688
37699
  filePaths.sort(sorter);
37689
37700
  collectedFiles = filePaths.map((filePath) => ({
37690
37701
  path: filePath,
37691
- content: readFileWithLog(path$1.join(srcDir, filePath), logger),
37702
+ content: readFileWithLog(sysPath.join(srcDir, filePath), logger),
37692
37703
  }));
37693
37704
  if (collectedFiles.length === 0) {
37694
37705
  logger.warn('未找到 NASL 文件');
@@ -37713,7 +37724,7 @@ async function compile(entry, options) {
37713
37724
  // 收集需要编译的文件
37714
37725
  const { collectedFiles, config, projectRoot } = await resolveNASLFiles(entry, logger, false, options?.verbose);
37715
37726
  logger.info(`输出目录: ${config.outDir}`);
37716
- const outDir = path$1.join(projectRoot, config.outDir);
37727
+ const outDir = sysPath.join(projectRoot, config.outDir);
37717
37728
  // 调用编译 API
37718
37729
  logger.newLine();
37719
37730
  logger.info('正在调用编译服务...');
@@ -37726,7 +37737,7 @@ async function compile(entry, options) {
37726
37737
  logger.success('编译成功!');
37727
37738
  // 写入输出文件
37728
37739
  for (const file of outputFiles) {
37729
- const outputPath = path$1.join(outDir, file.path);
37740
+ const outputPath = sysPath.join(outDir, file.path);
37730
37741
  writeFileWithLog(outputPath, file.content, logger);
37731
37742
  }
37732
37743
  logger.info(`输出 ${outputFiles.length} 个文件`);
@@ -37739,11 +37750,11 @@ async function compile(entry, options) {
37739
37750
  return { config, outDir };
37740
37751
  }
37741
37752
  async function tryCompile(entry, options) {
37742
- const logger = options?.logger || defaultLogger;
37743
37753
  try {
37744
37754
  await compile(entry, options);
37745
37755
  }
37746
37756
  catch (error) {
37757
+ const logger = options?.logger || defaultLogger;
37747
37758
  logger.error(`编译过程发生错误:${error.message}`);
37748
37759
  logger.exit(1);
37749
37760
  }
@@ -37794,24 +37805,189 @@ async function dep(entry, options) {
37794
37805
  return resolveNASLFiles(entry, logger, true, true);
37795
37806
  }
37796
37807
 
37797
- function justExecCommandSync(command, cwd) {
37798
- console.log(command);
37799
- const result = spawnSync(command, { shell: true, stdio: 'inherit', cwd });
37800
- if (result.status) {
37801
- console.error(String(result.stderr || result.stdout));
37808
+ /**
37809
+ * 编译命令 - 将 NASL 编译为 Vue 和 JS
37810
+ */
37811
+ async function dev(entry, options) {
37812
+ const logger = options?.logger || new ConsoleLoggerWithoutExit();
37813
+ // 获取项目根目录和配置
37814
+ const projectRoot = process.cwd();
37815
+ const configPath = sysPath.join(projectRoot, 'nasl.config.json');
37816
+ if (!libExports.existsSync(configPath)) {
37817
+ logger.error('未找到 nasl.config.json 配置文件,请先初始化项目');
37802
37818
  process.exit(1);
37803
37819
  }
37820
+ const configContent = libExports.readFileSync(configPath, 'utf-8');
37821
+ const config = JSON.parse(configContent);
37822
+ const srcDir = sysPath.join(projectRoot, config.srcDir);
37823
+ const outDir = sysPath.join(projectRoot, config.outDir);
37824
+ // 检查是否存在 src 目录
37825
+ const hasSrcDir = libExports.existsSync(srcDir) && libExports.statSync(srcDir).isDirectory();
37826
+ let lastCompileSuccess = false;
37827
+ if (hasSrcDir) {
37828
+ // 有 src 目录,先进行一次初始编译
37829
+ logger.info('检测到 src 目录,开始初始编译...');
37830
+ try {
37831
+ await compile(entry);
37832
+ lastCompileSuccess = true;
37833
+ logger.success('初始编译成功!');
37834
+ }
37835
+ catch (error) {
37836
+ logger.error(`初始编译失败:${error.message}`);
37837
+ // 即使编译失败,也要尝试启动服务(可能 out 目录已有旧文件)
37838
+ lastCompileSuccess = false;
37839
+ }
37840
+ }
37841
+ else {
37842
+ logger.info('未检测到 src 目录,将监听 src 目录的创建');
37843
+ }
37844
+ // 确保 out 目录存在
37845
+ if (!libExports.existsSync(outDir)) {
37846
+ logger.info('out 目录不存在,创建空的 out 目录');
37847
+ libExports.ensureDirSync(outDir);
37848
+ }
37849
+ // 启动 webpack 开发服务器
37850
+ const webpackProcess = await startWebpackDevServer(outDir, options, logger);
37851
+ const { default: chokidar } = await Promise.resolve().then(function () { return index$1; });
37852
+ // 监听 src 目录下的文件变化(即使目录不存在也可以监听)
37853
+ logger.info(`正在监听 src 目录: ${srcDir}`);
37854
+ const watcher = chokidar.watch(srcDir, {
37855
+ ignored: /(^|[\/\\])\../, // 忽略隐藏文件
37856
+ ignoreInitial: true,
37857
+ persistent: true,
37858
+ awaitWriteFinish: {
37859
+ stabilityThreshold: 100,
37860
+ pollInterval: 10,
37861
+ },
37862
+ });
37863
+ // 只监听 ts/tsx/nasl 文件的变化
37864
+ const shouldHandleFile = (filePath) => {
37865
+ return /\.(ts|tsx|nasl|css)$/.test(filePath);
37866
+ };
37867
+ let isCompiling = false;
37868
+ let pendingCompile = false;
37869
+ const handleFileChange = async (filePath) => {
37870
+ // 过滤非目标文件类型
37871
+ if (!shouldHandleFile(filePath))
37872
+ return;
37873
+ logger.info(`检测到文件变化: ${sysPath.relative(projectRoot, filePath)}`);
37874
+ if (isCompiling) {
37875
+ pendingCompile = true;
37876
+ return;
37877
+ }
37878
+ isCompiling = true;
37879
+ pendingCompile = false;
37880
+ try {
37881
+ logger.newLine();
37882
+ logger.info('开始重新编译...');
37883
+ await compile(entry);
37884
+ logger.success('重新编译成功!');
37885
+ lastCompileSuccess = true;
37886
+ }
37887
+ catch (error) {
37888
+ logger.error(`重新编译失败:${error.message}`);
37889
+ logger.info('继续使用上次成功的编译结果提供服务');
37890
+ // 不重启 webpack,继续使用旧的 out 目录
37891
+ }
37892
+ finally {
37893
+ isCompiling = false;
37894
+ if (pendingCompile) {
37895
+ // 如果在编译期间有新的文件变化,立即处理
37896
+ setTimeout(() => handleFileChange(filePath), 0);
37897
+ }
37898
+ }
37899
+ };
37900
+ watcher.on('change', handleFileChange);
37901
+ watcher.on('add', handleFileChange);
37902
+ watcher.on('unlink', handleFileChange);
37903
+ // 监听 src 目录本身的创建
37904
+ watcher.on('addDir', async (dirPath) => {
37905
+ // 当 src 目录本身被创建时触发编译
37906
+ if (dirPath === srcDir) {
37907
+ logger.info('检测到 src 目录被创建');
37908
+ if (isCompiling) {
37909
+ pendingCompile = true;
37910
+ return;
37911
+ }
37912
+ isCompiling = true;
37913
+ pendingCompile = false;
37914
+ try {
37915
+ logger.newLine();
37916
+ logger.info('开始编译...');
37917
+ await compile(entry);
37918
+ logger.success('编译成功!');
37919
+ lastCompileSuccess = true;
37920
+ }
37921
+ catch (error) {
37922
+ logger.error(`编译失败:${error.message}`);
37923
+ }
37924
+ finally {
37925
+ isCompiling = false;
37926
+ if (pendingCompile) {
37927
+ setTimeout(() => handleFileChange(''), 0);
37928
+ }
37929
+ }
37930
+ }
37931
+ });
37932
+ // 监听 out 目录的删除,以便在 out 目录被删除时重新编译
37933
+ const outWatcher = chokidar.watch(outDir, {
37934
+ ignoreInitial: true,
37935
+ persistent: true,
37936
+ depth: 0, // 只监听 out 目录本身,不监听子目录
37937
+ });
37938
+ outWatcher.on('unlinkDir', async (deletedPath) => {
37939
+ if (deletedPath === outDir) {
37940
+ logger.warn('检测到 out 目录被删除');
37941
+ // 检查是否存在 src 目录
37942
+ const hasSrc = libExports.existsSync(srcDir) && libExports.statSync(srcDir).isDirectory();
37943
+ if (hasSrc) {
37944
+ logger.info('检测到 src 目录存在,开始重新编译...');
37945
+ if (isCompiling) {
37946
+ pendingCompile = true;
37947
+ return;
37948
+ }
37949
+ isCompiling = true;
37950
+ pendingCompile = false;
37951
+ try {
37952
+ // 确保 out 目录存在
37953
+ libExports.ensureDirSync(outDir);
37954
+ await compile(entry);
37955
+ logger.success('重新编译成功!out 目录已恢复');
37956
+ lastCompileSuccess = true;
37957
+ }
37958
+ catch (error) {
37959
+ logger.error(`重新编译失败:${error.message}`);
37960
+ }
37961
+ finally {
37962
+ isCompiling = false;
37963
+ if (pendingCompile) {
37964
+ setTimeout(() => handleFileChange(''), 0);
37965
+ }
37966
+ }
37967
+ }
37968
+ else {
37969
+ logger.warn('未检测到 src 目录,无法重新编译');
37970
+ }
37971
+ }
37972
+ });
37973
+ // 处理进程退出
37974
+ const cleanup = () => {
37975
+ if (webpackProcess) {
37976
+ webpackProcess.kill();
37977
+ }
37978
+ watcher.close().catch(() => { });
37979
+ outWatcher.close().catch(() => { });
37980
+ };
37981
+ process.on('SIGINT', cleanup);
37982
+ process.on('SIGTERM', cleanup);
37804
37983
  }
37805
-
37806
37984
  /**
37807
- * 编译命令 - 将 NASL 编译为 Vue 和 JS
37985
+ * 启动 webpack 开发服务器
37808
37986
  */
37809
- async function dev(entry, options) {
37810
- const logger = options?.logger || defaultLogger;
37811
- const { outDir } = await compile(entry);
37812
- logger.newLine();
37813
- logger.info('正在启动开发服务...');
37814
- const configRelativePath = path$1.relative(outDir, path$1.resolve(__dirname, '../../build/webpack.config.js'));
37987
+ async function startWebpackDevServer(outDir, options, logger) {
37988
+ logger?.newLine();
37989
+ logger?.info('正在启动开发服务...');
37990
+ const configRelativePath = sysPath.relative(outDir, sysPath.resolve(__dirname, '../../build/webpack.config.js'));
37815
37991
  // 构建 webpack-cli 参数
37816
37992
  let webpackArgs = `${require.resolve('.bin/webpack-cli')} serve --config ${configRelativePath}`;
37817
37993
  if (options?.port)
@@ -37822,7 +37998,26 @@ async function dev(entry, options) {
37822
37998
  webpackArgs += ' --open';
37823
37999
  if (options?.hot)
37824
38000
  webpackArgs += ' --hot';
37825
- await justExecCommandSync(webpackArgs, outDir);
38001
+ // 使用 spawn 而不是 spawnSync,以便进程可以常驻
38002
+ const webpackProcess = spawn(webpackArgs, {
38003
+ shell: true,
38004
+ stdio: 'inherit',
38005
+ cwd: outDir,
38006
+ });
38007
+ webpackProcess.on('error', (error) => {
38008
+ logger?.error(`Webpack 开发服务器启动失败: ${error.message}`);
38009
+ process.exit(1);
38010
+ });
38011
+ return webpackProcess;
38012
+ }
38013
+
38014
+ function justExecCommandSync(command, cwd) {
38015
+ console.log(command);
38016
+ const result = spawnSync(command, { shell: true, stdio: 'inherit', cwd });
38017
+ if (result.status) {
38018
+ console.error(String(result.stderr || result.stdout));
38019
+ process.exit(1);
38020
+ }
37826
38021
  }
37827
38022
 
37828
38023
  /**
@@ -37833,14 +38028,14 @@ async function build(entry, options) {
37833
38028
  const { outDir } = await compile(entry);
37834
38029
  logger.newLine();
37835
38030
  logger.info('正在构建项目...');
37836
- const configRelativePath = path$1.relative(outDir, path$1.resolve(__dirname, '../../build/webpack.config.js'));
38031
+ const configRelativePath = sysPath.relative(outDir, sysPath.resolve(__dirname, '../../build/webpack.config.js'));
37837
38032
  const mode = options?.mode || 'production';
37838
38033
  // 构建 webpack-cli 参数
37839
38034
  let webpackArgs = `${require.resolve('.bin/webpack-cli')} build --config ${configRelativePath} --mode ${mode}`;
37840
38035
  await justExecCommandSync(webpackArgs, outDir);
37841
38036
  }
37842
38037
 
37843
- var version = "0.1.6";
38038
+ var version = "0.1.8";
37844
38039
  var pkg = {
37845
38040
  version: version};
37846
38041
 
@@ -37927,4 +38122,1669 @@ program.parse(process.argv);
37927
38122
  if (!process.argv.slice(2).length) {
37928
38123
  program.outputHelp();
37929
38124
  }
38125
+
38126
+ const EntryTypes = {
38127
+ FILE_TYPE: 'files',
38128
+ DIR_TYPE: 'directories',
38129
+ FILE_DIR_TYPE: 'files_directories',
38130
+ EVERYTHING_TYPE: 'all',
38131
+ };
38132
+ const defaultOptions = {
38133
+ root: '.',
38134
+ fileFilter: (_entryInfo) => true,
38135
+ directoryFilter: (_entryInfo) => true,
38136
+ type: EntryTypes.FILE_TYPE,
38137
+ lstat: false,
38138
+ depth: 2147483648,
38139
+ alwaysStat: false,
38140
+ highWaterMark: 4096,
38141
+ };
38142
+ Object.freeze(defaultOptions);
38143
+ const RECURSIVE_ERROR_CODE = 'READDIRP_RECURSIVE_ERROR';
38144
+ const NORMAL_FLOW_ERRORS = new Set(['ENOENT', 'EPERM', 'EACCES', 'ELOOP', RECURSIVE_ERROR_CODE]);
38145
+ const ALL_TYPES = [
38146
+ EntryTypes.DIR_TYPE,
38147
+ EntryTypes.EVERYTHING_TYPE,
38148
+ EntryTypes.FILE_DIR_TYPE,
38149
+ EntryTypes.FILE_TYPE,
38150
+ ];
38151
+ const DIR_TYPES = new Set([
38152
+ EntryTypes.DIR_TYPE,
38153
+ EntryTypes.EVERYTHING_TYPE,
38154
+ EntryTypes.FILE_DIR_TYPE,
38155
+ ]);
38156
+ const FILE_TYPES = new Set([
38157
+ EntryTypes.EVERYTHING_TYPE,
38158
+ EntryTypes.FILE_DIR_TYPE,
38159
+ EntryTypes.FILE_TYPE,
38160
+ ]);
38161
+ const isNormalFlowError = (error) => NORMAL_FLOW_ERRORS.has(error.code);
38162
+ const wantBigintFsStats = process.platform === 'win32';
38163
+ const emptyFn = (_entryInfo) => true;
38164
+ const normalizeFilter = (filter) => {
38165
+ if (filter === undefined)
38166
+ return emptyFn;
38167
+ if (typeof filter === 'function')
38168
+ return filter;
38169
+ if (typeof filter === 'string') {
38170
+ const fl = filter.trim();
38171
+ return (entry) => entry.basename === fl;
38172
+ }
38173
+ if (Array.isArray(filter)) {
38174
+ const trItems = filter.map((item) => item.trim());
38175
+ return (entry) => trItems.some((f) => entry.basename === f);
38176
+ }
38177
+ return emptyFn;
38178
+ };
38179
+ /** Readable readdir stream, emitting new files as they're being listed. */
38180
+ class ReaddirpStream extends Readable$1 {
38181
+ constructor(options = {}) {
38182
+ super({
38183
+ objectMode: true,
38184
+ autoDestroy: true,
38185
+ highWaterMark: options.highWaterMark,
38186
+ });
38187
+ const opts = { ...defaultOptions, ...options };
38188
+ const { root, type } = opts;
38189
+ this._fileFilter = normalizeFilter(opts.fileFilter);
38190
+ this._directoryFilter = normalizeFilter(opts.directoryFilter);
38191
+ const statMethod = opts.lstat ? lstat : stat$1;
38192
+ // Use bigint stats if it's windows and stat() supports options (node 10+).
38193
+ if (wantBigintFsStats) {
38194
+ this._stat = (path) => statMethod(path, { bigint: true });
38195
+ }
38196
+ else {
38197
+ this._stat = statMethod;
38198
+ }
38199
+ this._maxDepth = opts.depth ?? defaultOptions.depth;
38200
+ this._wantsDir = type ? DIR_TYPES.has(type) : false;
38201
+ this._wantsFile = type ? FILE_TYPES.has(type) : false;
38202
+ this._wantsEverything = type === EntryTypes.EVERYTHING_TYPE;
38203
+ this._root = resolve(root);
38204
+ this._isDirent = !opts.alwaysStat;
38205
+ this._statsProp = this._isDirent ? 'dirent' : 'stats';
38206
+ this._rdOptions = { encoding: 'utf8', withFileTypes: this._isDirent };
38207
+ // Launch stream with one parent, the root dir.
38208
+ this.parents = [this._exploreDir(root, 1)];
38209
+ this.reading = false;
38210
+ this.parent = undefined;
38211
+ }
38212
+ async _read(batch) {
38213
+ if (this.reading)
38214
+ return;
38215
+ this.reading = true;
38216
+ try {
38217
+ while (!this.destroyed && batch > 0) {
38218
+ const par = this.parent;
38219
+ const fil = par && par.files;
38220
+ if (fil && fil.length > 0) {
38221
+ const { path, depth } = par;
38222
+ const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent, path));
38223
+ const awaited = await Promise.all(slice);
38224
+ for (const entry of awaited) {
38225
+ if (!entry)
38226
+ continue;
38227
+ if (this.destroyed)
38228
+ return;
38229
+ const entryType = await this._getEntryType(entry);
38230
+ if (entryType === 'directory' && this._directoryFilter(entry)) {
38231
+ if (depth <= this._maxDepth) {
38232
+ this.parents.push(this._exploreDir(entry.fullPath, depth + 1));
38233
+ }
38234
+ if (this._wantsDir) {
38235
+ this.push(entry);
38236
+ batch--;
38237
+ }
38238
+ }
38239
+ else if ((entryType === 'file' || this._includeAsFile(entry)) &&
38240
+ this._fileFilter(entry)) {
38241
+ if (this._wantsFile) {
38242
+ this.push(entry);
38243
+ batch--;
38244
+ }
38245
+ }
38246
+ }
38247
+ }
38248
+ else {
38249
+ const parent = this.parents.pop();
38250
+ if (!parent) {
38251
+ this.push(null);
38252
+ break;
38253
+ }
38254
+ this.parent = await parent;
38255
+ if (this.destroyed)
38256
+ return;
38257
+ }
38258
+ }
38259
+ }
38260
+ catch (error) {
38261
+ this.destroy(error);
38262
+ }
38263
+ finally {
38264
+ this.reading = false;
38265
+ }
38266
+ }
38267
+ async _exploreDir(path, depth) {
38268
+ let files;
38269
+ try {
38270
+ files = await readdir(path, this._rdOptions);
38271
+ }
38272
+ catch (error) {
38273
+ this._onError(error);
38274
+ }
38275
+ return { files, depth, path };
38276
+ }
38277
+ async _formatEntry(dirent, path) {
38278
+ let entry;
38279
+ const basename = this._isDirent ? dirent.name : dirent;
38280
+ try {
38281
+ const fullPath = resolve(join(path, basename));
38282
+ entry = { path: relative(this._root, fullPath), fullPath, basename };
38283
+ entry[this._statsProp] = this._isDirent ? dirent : await this._stat(fullPath);
38284
+ }
38285
+ catch (err) {
38286
+ this._onError(err);
38287
+ return;
38288
+ }
38289
+ return entry;
38290
+ }
38291
+ _onError(err) {
38292
+ if (isNormalFlowError(err) && !this.destroyed) {
38293
+ this.emit('warn', err);
38294
+ }
38295
+ else {
38296
+ this.destroy(err);
38297
+ }
38298
+ }
38299
+ async _getEntryType(entry) {
38300
+ // entry may be undefined, because a warning or an error were emitted
38301
+ // and the statsProp is undefined
38302
+ if (!entry && this._statsProp in entry) {
38303
+ return '';
38304
+ }
38305
+ const stats = entry[this._statsProp];
38306
+ if (stats.isFile())
38307
+ return 'file';
38308
+ if (stats.isDirectory())
38309
+ return 'directory';
38310
+ if (stats && stats.isSymbolicLink()) {
38311
+ const full = entry.fullPath;
38312
+ try {
38313
+ const entryRealPath = await realpath(full);
38314
+ const entryRealPathStats = await lstat(entryRealPath);
38315
+ if (entryRealPathStats.isFile()) {
38316
+ return 'file';
38317
+ }
38318
+ if (entryRealPathStats.isDirectory()) {
38319
+ const len = entryRealPath.length;
38320
+ if (full.startsWith(entryRealPath) && full.substr(len, 1) === sep) {
38321
+ const recursiveError = new Error(`Circular symlink detected: "${full}" points to "${entryRealPath}"`);
38322
+ // @ts-ignore
38323
+ recursiveError.code = RECURSIVE_ERROR_CODE;
38324
+ return this._onError(recursiveError);
38325
+ }
38326
+ return 'directory';
38327
+ }
38328
+ }
38329
+ catch (error) {
38330
+ this._onError(error);
38331
+ return '';
38332
+ }
38333
+ }
38334
+ }
38335
+ _includeAsFile(entry) {
38336
+ const stats = entry && entry[this._statsProp];
38337
+ return stats && this._wantsEverything && !stats.isDirectory();
38338
+ }
38339
+ }
38340
+ /**
38341
+ * Streaming version: Reads all files and directories in given root recursively.
38342
+ * Consumes ~constant small amount of RAM.
38343
+ * @param root Root directory
38344
+ * @param options Options to specify root (start directory), filters and recursion depth
38345
+ */
38346
+ function readdirp(root, options = {}) {
38347
+ // @ts-ignore
38348
+ let type = options.entryType || options.type;
38349
+ if (type === 'both')
38350
+ type = EntryTypes.FILE_DIR_TYPE; // backwards-compatibility
38351
+ if (type)
38352
+ options.type = type;
38353
+ if (!root) {
38354
+ throw new Error('readdirp: root argument is required. Usage: readdirp(root, options)');
38355
+ }
38356
+ else if (typeof root !== 'string') {
38357
+ throw new TypeError('readdirp: root argument must be a string. Usage: readdirp(root, options)');
38358
+ }
38359
+ else if (type && !ALL_TYPES.includes(type)) {
38360
+ throw new Error(`readdirp: Invalid type passed. Use one of ${ALL_TYPES.join(', ')}`);
38361
+ }
38362
+ options.root = root;
38363
+ return new ReaddirpStream(options);
38364
+ }
38365
+
38366
+ const STR_DATA = 'data';
38367
+ const STR_END = 'end';
38368
+ const STR_CLOSE = 'close';
38369
+ const EMPTY_FN = () => { };
38370
+ const pl = process.platform;
38371
+ const isWindows = pl === 'win32';
38372
+ const isMacos = pl === 'darwin';
38373
+ const isLinux = pl === 'linux';
38374
+ const isFreeBSD = pl === 'freebsd';
38375
+ const isIBMi = type$1() === 'OS400';
38376
+ const EVENTS = {
38377
+ ALL: 'all',
38378
+ READY: 'ready',
38379
+ ADD: 'add',
38380
+ CHANGE: 'change',
38381
+ ADD_DIR: 'addDir',
38382
+ UNLINK: 'unlink',
38383
+ UNLINK_DIR: 'unlinkDir',
38384
+ RAW: 'raw',
38385
+ ERROR: 'error',
38386
+ };
38387
+ const EV = EVENTS;
38388
+ const THROTTLE_MODE_WATCH = 'watch';
38389
+ const statMethods = { lstat: lstat$1, stat: stat$2 };
38390
+ const KEY_LISTENERS = 'listeners';
38391
+ const KEY_ERR = 'errHandlers';
38392
+ const KEY_RAW = 'rawEmitters';
38393
+ const HANDLER_KEYS = [KEY_LISTENERS, KEY_ERR, KEY_RAW];
38394
+ // prettier-ignore
38395
+ const binaryExtensions = new Set([
38396
+ '3dm', '3ds', '3g2', '3gp', '7z', 'a', 'aac', 'adp', 'afdesign', 'afphoto', 'afpub', 'ai',
38397
+ 'aif', 'aiff', 'alz', 'ape', 'apk', 'appimage', 'ar', 'arj', 'asf', 'au', 'avi',
38398
+ 'bak', 'baml', 'bh', 'bin', 'bk', 'bmp', 'btif', 'bz2', 'bzip2',
38399
+ 'cab', 'caf', 'cgm', 'class', 'cmx', 'cpio', 'cr2', 'cur', 'dat', 'dcm', 'deb', 'dex', 'djvu',
38400
+ 'dll', 'dmg', 'dng', 'doc', 'docm', 'docx', 'dot', 'dotm', 'dra', 'DS_Store', 'dsk', 'dts',
38401
+ 'dtshd', 'dvb', 'dwg', 'dxf',
38402
+ 'ecelp4800', 'ecelp7470', 'ecelp9600', 'egg', 'eol', 'eot', 'epub', 'exe',
38403
+ 'f4v', 'fbs', 'fh', 'fla', 'flac', 'flatpak', 'fli', 'flv', 'fpx', 'fst', 'fvt',
38404
+ 'g3', 'gh', 'gif', 'graffle', 'gz', 'gzip',
38405
+ 'h261', 'h263', 'h264', 'icns', 'ico', 'ief', 'img', 'ipa', 'iso',
38406
+ 'jar', 'jpeg', 'jpg', 'jpgv', 'jpm', 'jxr', 'key', 'ktx',
38407
+ 'lha', 'lib', 'lvp', 'lz', 'lzh', 'lzma', 'lzo',
38408
+ 'm3u', 'm4a', 'm4v', 'mar', 'mdi', 'mht', 'mid', 'midi', 'mj2', 'mka', 'mkv', 'mmr', 'mng',
38409
+ 'mobi', 'mov', 'movie', 'mp3',
38410
+ 'mp4', 'mp4a', 'mpeg', 'mpg', 'mpga', 'mxu',
38411
+ 'nef', 'npx', 'numbers', 'nupkg',
38412
+ 'o', 'odp', 'ods', 'odt', 'oga', 'ogg', 'ogv', 'otf', 'ott',
38413
+ 'pages', 'pbm', 'pcx', 'pdb', 'pdf', 'pea', 'pgm', 'pic', 'png', 'pnm', 'pot', 'potm',
38414
+ 'potx', 'ppa', 'ppam',
38415
+ 'ppm', 'pps', 'ppsm', 'ppsx', 'ppt', 'pptm', 'pptx', 'psd', 'pya', 'pyc', 'pyo', 'pyv',
38416
+ 'qt',
38417
+ 'rar', 'ras', 'raw', 'resources', 'rgb', 'rip', 'rlc', 'rmf', 'rmvb', 'rpm', 'rtf', 'rz',
38418
+ 's3m', 's7z', 'scpt', 'sgi', 'shar', 'snap', 'sil', 'sketch', 'slk', 'smv', 'snk', 'so',
38419
+ 'stl', 'suo', 'sub', 'swf',
38420
+ 'tar', 'tbz', 'tbz2', 'tga', 'tgz', 'thmx', 'tif', 'tiff', 'tlz', 'ttc', 'ttf', 'txz',
38421
+ 'udf', 'uvh', 'uvi', 'uvm', 'uvp', 'uvs', 'uvu',
38422
+ 'viv', 'vob',
38423
+ 'war', 'wav', 'wax', 'wbmp', 'wdp', 'weba', 'webm', 'webp', 'whl', 'wim', 'wm', 'wma',
38424
+ 'wmv', 'wmx', 'woff', 'woff2', 'wrm', 'wvx',
38425
+ 'xbm', 'xif', 'xla', 'xlam', 'xls', 'xlsb', 'xlsm', 'xlsx', 'xlt', 'xltm', 'xltx', 'xm',
38426
+ 'xmind', 'xpi', 'xpm', 'xwd', 'xz',
38427
+ 'z', 'zip', 'zipx',
38428
+ ]);
38429
+ const isBinaryPath = (filePath) => binaryExtensions.has(sysPath.extname(filePath).slice(1).toLowerCase());
38430
+ // TODO: emit errors properly. Example: EMFILE on Macos.
38431
+ const foreach = (val, fn) => {
38432
+ if (val instanceof Set) {
38433
+ val.forEach(fn);
38434
+ }
38435
+ else {
38436
+ fn(val);
38437
+ }
38438
+ };
38439
+ const addAndConvert = (main, prop, item) => {
38440
+ let container = main[prop];
38441
+ if (!(container instanceof Set)) {
38442
+ main[prop] = container = new Set([container]);
38443
+ }
38444
+ container.add(item);
38445
+ };
38446
+ const clearItem = (cont) => (key) => {
38447
+ const set = cont[key];
38448
+ if (set instanceof Set) {
38449
+ set.clear();
38450
+ }
38451
+ else {
38452
+ delete cont[key];
38453
+ }
38454
+ };
38455
+ const delFromSet = (main, prop, item) => {
38456
+ const container = main[prop];
38457
+ if (container instanceof Set) {
38458
+ container.delete(item);
38459
+ }
38460
+ else if (container === item) {
38461
+ delete main[prop];
38462
+ }
38463
+ };
38464
+ const isEmptySet = (val) => (val instanceof Set ? val.size === 0 : !val);
38465
+ const FsWatchInstances = new Map();
38466
+ /**
38467
+ * Instantiates the fs_watch interface
38468
+ * @param path to be watched
38469
+ * @param options to be passed to fs_watch
38470
+ * @param listener main event handler
38471
+ * @param errHandler emits info about errors
38472
+ * @param emitRaw emits raw event data
38473
+ * @returns {NativeFsWatcher}
38474
+ */
38475
+ function createFsWatchInstance(path, options, listener, errHandler, emitRaw) {
38476
+ const handleEvent = (rawEvent, evPath) => {
38477
+ listener(path);
38478
+ emitRaw(rawEvent, evPath, { watchedPath: path });
38479
+ // emit based on events occurring for files from a directory's watcher in
38480
+ // case the file's watcher misses it (and rely on throttling to de-dupe)
38481
+ if (evPath && path !== evPath) {
38482
+ fsWatchBroadcast(sysPath.resolve(path, evPath), KEY_LISTENERS, sysPath.join(path, evPath));
38483
+ }
38484
+ };
38485
+ try {
38486
+ return watch$1(path, {
38487
+ persistent: options.persistent,
38488
+ }, handleEvent);
38489
+ }
38490
+ catch (error) {
38491
+ errHandler(error);
38492
+ return undefined;
38493
+ }
38494
+ }
38495
+ /**
38496
+ * Helper for passing fs_watch event data to a collection of listeners
38497
+ * @param fullPath absolute path bound to fs_watch instance
38498
+ */
38499
+ const fsWatchBroadcast = (fullPath, listenerType, val1, val2, val3) => {
38500
+ const cont = FsWatchInstances.get(fullPath);
38501
+ if (!cont)
38502
+ return;
38503
+ foreach(cont[listenerType], (listener) => {
38504
+ listener(val1, val2, val3);
38505
+ });
38506
+ };
38507
+ /**
38508
+ * Instantiates the fs_watch interface or binds listeners
38509
+ * to an existing one covering the same file system entry
38510
+ * @param path
38511
+ * @param fullPath absolute path
38512
+ * @param options to be passed to fs_watch
38513
+ * @param handlers container for event listener functions
38514
+ */
38515
+ const setFsWatchListener = (path, fullPath, options, handlers) => {
38516
+ const { listener, errHandler, rawEmitter } = handlers;
38517
+ let cont = FsWatchInstances.get(fullPath);
38518
+ let watcher;
38519
+ if (!options.persistent) {
38520
+ watcher = createFsWatchInstance(path, options, listener, errHandler, rawEmitter);
38521
+ if (!watcher)
38522
+ return;
38523
+ return watcher.close.bind(watcher);
38524
+ }
38525
+ if (cont) {
38526
+ addAndConvert(cont, KEY_LISTENERS, listener);
38527
+ addAndConvert(cont, KEY_ERR, errHandler);
38528
+ addAndConvert(cont, KEY_RAW, rawEmitter);
38529
+ }
38530
+ else {
38531
+ watcher = createFsWatchInstance(path, options, fsWatchBroadcast.bind(null, fullPath, KEY_LISTENERS), errHandler, // no need to use broadcast here
38532
+ fsWatchBroadcast.bind(null, fullPath, KEY_RAW));
38533
+ if (!watcher)
38534
+ return;
38535
+ watcher.on(EV.ERROR, async (error) => {
38536
+ const broadcastErr = fsWatchBroadcast.bind(null, fullPath, KEY_ERR);
38537
+ if (cont)
38538
+ cont.watcherUnusable = true; // documented since Node 10.4.1
38539
+ // Workaround for https://github.com/joyent/node/issues/4337
38540
+ if (isWindows && error.code === 'EPERM') {
38541
+ try {
38542
+ const fd = await open(path, 'r');
38543
+ await fd.close();
38544
+ broadcastErr(error);
38545
+ }
38546
+ catch (err) {
38547
+ // do nothing
38548
+ }
38549
+ }
38550
+ else {
38551
+ broadcastErr(error);
38552
+ }
38553
+ });
38554
+ cont = {
38555
+ listeners: listener,
38556
+ errHandlers: errHandler,
38557
+ rawEmitters: rawEmitter,
38558
+ watcher,
38559
+ };
38560
+ FsWatchInstances.set(fullPath, cont);
38561
+ }
38562
+ // const index = cont.listeners.indexOf(listener);
38563
+ // removes this instance's listeners and closes the underlying fs_watch
38564
+ // instance if there are no more listeners left
38565
+ return () => {
38566
+ delFromSet(cont, KEY_LISTENERS, listener);
38567
+ delFromSet(cont, KEY_ERR, errHandler);
38568
+ delFromSet(cont, KEY_RAW, rawEmitter);
38569
+ if (isEmptySet(cont.listeners)) {
38570
+ // Check to protect against issue gh-730.
38571
+ // if (cont.watcherUnusable) {
38572
+ cont.watcher.close();
38573
+ // }
38574
+ FsWatchInstances.delete(fullPath);
38575
+ HANDLER_KEYS.forEach(clearItem(cont));
38576
+ // @ts-ignore
38577
+ cont.watcher = undefined;
38578
+ Object.freeze(cont);
38579
+ }
38580
+ };
38581
+ };
38582
+ // fs_watchFile helpers
38583
+ // object to hold per-process fs_watchFile instances
38584
+ // (may be shared across chokidar FSWatcher instances)
38585
+ const FsWatchFileInstances = new Map();
38586
+ /**
38587
+ * Instantiates the fs_watchFile interface or binds listeners
38588
+ * to an existing one covering the same file system entry
38589
+ * @param path to be watched
38590
+ * @param fullPath absolute path
38591
+ * @param options options to be passed to fs_watchFile
38592
+ * @param handlers container for event listener functions
38593
+ * @returns closer
38594
+ */
38595
+ const setFsWatchFileListener = (path, fullPath, options, handlers) => {
38596
+ const { listener, rawEmitter } = handlers;
38597
+ let cont = FsWatchFileInstances.get(fullPath);
38598
+ // let listeners = new Set();
38599
+ // let rawEmitters = new Set();
38600
+ const copts = cont && cont.options;
38601
+ if (copts && (copts.persistent < options.persistent || copts.interval > options.interval)) {
38602
+ // "Upgrade" the watcher to persistence or a quicker interval.
38603
+ // This creates some unlikely edge case issues if the user mixes
38604
+ // settings in a very weird way, but solving for those cases
38605
+ // doesn't seem worthwhile for the added complexity.
38606
+ // listeners = cont.listeners;
38607
+ // rawEmitters = cont.rawEmitters;
38608
+ unwatchFile(fullPath);
38609
+ cont = undefined;
38610
+ }
38611
+ if (cont) {
38612
+ addAndConvert(cont, KEY_LISTENERS, listener);
38613
+ addAndConvert(cont, KEY_RAW, rawEmitter);
38614
+ }
38615
+ else {
38616
+ // TODO
38617
+ // listeners.add(listener);
38618
+ // rawEmitters.add(rawEmitter);
38619
+ cont = {
38620
+ listeners: listener,
38621
+ rawEmitters: rawEmitter,
38622
+ options,
38623
+ watcher: watchFile(fullPath, options, (curr, prev) => {
38624
+ foreach(cont.rawEmitters, (rawEmitter) => {
38625
+ rawEmitter(EV.CHANGE, fullPath, { curr, prev });
38626
+ });
38627
+ const currmtime = curr.mtimeMs;
38628
+ if (curr.size !== prev.size || currmtime > prev.mtimeMs || currmtime === 0) {
38629
+ foreach(cont.listeners, (listener) => listener(path, curr));
38630
+ }
38631
+ }),
38632
+ };
38633
+ FsWatchFileInstances.set(fullPath, cont);
38634
+ }
38635
+ // const index = cont.listeners.indexOf(listener);
38636
+ // Removes this instance's listeners and closes the underlying fs_watchFile
38637
+ // instance if there are no more listeners left.
38638
+ return () => {
38639
+ delFromSet(cont, KEY_LISTENERS, listener);
38640
+ delFromSet(cont, KEY_RAW, rawEmitter);
38641
+ if (isEmptySet(cont.listeners)) {
38642
+ FsWatchFileInstances.delete(fullPath);
38643
+ unwatchFile(fullPath);
38644
+ cont.options = cont.watcher = undefined;
38645
+ Object.freeze(cont);
38646
+ }
38647
+ };
38648
+ };
38649
+ /**
38650
+ * @mixin
38651
+ */
38652
+ class NodeFsHandler {
38653
+ constructor(fsW) {
38654
+ this.fsw = fsW;
38655
+ this._boundHandleError = (error) => fsW._handleError(error);
38656
+ }
38657
+ /**
38658
+ * Watch file for changes with fs_watchFile or fs_watch.
38659
+ * @param path to file or dir
38660
+ * @param listener on fs change
38661
+ * @returns closer for the watcher instance
38662
+ */
38663
+ _watchWithNodeFs(path, listener) {
38664
+ const opts = this.fsw.options;
38665
+ const directory = sysPath.dirname(path);
38666
+ const basename = sysPath.basename(path);
38667
+ const parent = this.fsw._getWatchedDir(directory);
38668
+ parent.add(basename);
38669
+ const absolutePath = sysPath.resolve(path);
38670
+ const options = {
38671
+ persistent: opts.persistent,
38672
+ };
38673
+ if (!listener)
38674
+ listener = EMPTY_FN;
38675
+ let closer;
38676
+ if (opts.usePolling) {
38677
+ const enableBin = opts.interval !== opts.binaryInterval;
38678
+ options.interval = enableBin && isBinaryPath(basename) ? opts.binaryInterval : opts.interval;
38679
+ closer = setFsWatchFileListener(path, absolutePath, options, {
38680
+ listener,
38681
+ rawEmitter: this.fsw._emitRaw,
38682
+ });
38683
+ }
38684
+ else {
38685
+ closer = setFsWatchListener(path, absolutePath, options, {
38686
+ listener,
38687
+ errHandler: this._boundHandleError,
38688
+ rawEmitter: this.fsw._emitRaw,
38689
+ });
38690
+ }
38691
+ return closer;
38692
+ }
38693
+ /**
38694
+ * Watch a file and emit add event if warranted.
38695
+ * @returns closer for the watcher instance
38696
+ */
38697
+ _handleFile(file, stats, initialAdd) {
38698
+ if (this.fsw.closed) {
38699
+ return;
38700
+ }
38701
+ const dirname = sysPath.dirname(file);
38702
+ const basename = sysPath.basename(file);
38703
+ const parent = this.fsw._getWatchedDir(dirname);
38704
+ // stats is always present
38705
+ let prevStats = stats;
38706
+ // if the file is already being watched, do nothing
38707
+ if (parent.has(basename))
38708
+ return;
38709
+ const listener = async (path, newStats) => {
38710
+ if (!this.fsw._throttle(THROTTLE_MODE_WATCH, file, 5))
38711
+ return;
38712
+ if (!newStats || newStats.mtimeMs === 0) {
38713
+ try {
38714
+ const newStats = await stat$2(file);
38715
+ if (this.fsw.closed)
38716
+ return;
38717
+ // Check that change event was not fired because of changed only accessTime.
38718
+ const at = newStats.atimeMs;
38719
+ const mt = newStats.mtimeMs;
38720
+ if (!at || at <= mt || mt !== prevStats.mtimeMs) {
38721
+ this.fsw._emit(EV.CHANGE, file, newStats);
38722
+ }
38723
+ if ((isMacos || isLinux || isFreeBSD) && prevStats.ino !== newStats.ino) {
38724
+ this.fsw._closeFile(path);
38725
+ prevStats = newStats;
38726
+ const closer = this._watchWithNodeFs(file, listener);
38727
+ if (closer)
38728
+ this.fsw._addPathCloser(path, closer);
38729
+ }
38730
+ else {
38731
+ prevStats = newStats;
38732
+ }
38733
+ }
38734
+ catch (error) {
38735
+ // Fix issues where mtime is null but file is still present
38736
+ this.fsw._remove(dirname, basename);
38737
+ }
38738
+ // add is about to be emitted if file not already tracked in parent
38739
+ }
38740
+ else if (parent.has(basename)) {
38741
+ // Check that change event was not fired because of changed only accessTime.
38742
+ const at = newStats.atimeMs;
38743
+ const mt = newStats.mtimeMs;
38744
+ if (!at || at <= mt || mt !== prevStats.mtimeMs) {
38745
+ this.fsw._emit(EV.CHANGE, file, newStats);
38746
+ }
38747
+ prevStats = newStats;
38748
+ }
38749
+ };
38750
+ // kick off the watcher
38751
+ const closer = this._watchWithNodeFs(file, listener);
38752
+ // emit an add event if we're supposed to
38753
+ if (!(initialAdd && this.fsw.options.ignoreInitial) && this.fsw._isntIgnored(file)) {
38754
+ if (!this.fsw._throttle(EV.ADD, file, 0))
38755
+ return;
38756
+ this.fsw._emit(EV.ADD, file, stats);
38757
+ }
38758
+ return closer;
38759
+ }
38760
+ /**
38761
+ * Handle symlinks encountered while reading a dir.
38762
+ * @param entry returned by readdirp
38763
+ * @param directory path of dir being read
38764
+ * @param path of this item
38765
+ * @param item basename of this item
38766
+ * @returns true if no more processing is needed for this entry.
38767
+ */
38768
+ async _handleSymlink(entry, directory, path, item) {
38769
+ if (this.fsw.closed) {
38770
+ return;
38771
+ }
38772
+ const full = entry.fullPath;
38773
+ const dir = this.fsw._getWatchedDir(directory);
38774
+ if (!this.fsw.options.followSymlinks) {
38775
+ // watch symlink directly (don't follow) and detect changes
38776
+ this.fsw._incrReadyCount();
38777
+ let linkPath;
38778
+ try {
38779
+ linkPath = await realpath$1(path);
38780
+ }
38781
+ catch (e) {
38782
+ this.fsw._emitReady();
38783
+ return true;
38784
+ }
38785
+ if (this.fsw.closed)
38786
+ return;
38787
+ if (dir.has(item)) {
38788
+ if (this.fsw._symlinkPaths.get(full) !== linkPath) {
38789
+ this.fsw._symlinkPaths.set(full, linkPath);
38790
+ this.fsw._emit(EV.CHANGE, path, entry.stats);
38791
+ }
38792
+ }
38793
+ else {
38794
+ dir.add(item);
38795
+ this.fsw._symlinkPaths.set(full, linkPath);
38796
+ this.fsw._emit(EV.ADD, path, entry.stats);
38797
+ }
38798
+ this.fsw._emitReady();
38799
+ return true;
38800
+ }
38801
+ // don't follow the same symlink more than once
38802
+ if (this.fsw._symlinkPaths.has(full)) {
38803
+ return true;
38804
+ }
38805
+ this.fsw._symlinkPaths.set(full, true);
38806
+ }
38807
+ _handleRead(directory, initialAdd, wh, target, dir, depth, throttler) {
38808
+ // Normalize the directory name on Windows
38809
+ directory = sysPath.join(directory, '');
38810
+ throttler = this.fsw._throttle('readdir', directory, 1000);
38811
+ if (!throttler)
38812
+ return;
38813
+ const previous = this.fsw._getWatchedDir(wh.path);
38814
+ const current = new Set();
38815
+ let stream = this.fsw._readdirp(directory, {
38816
+ fileFilter: (entry) => wh.filterPath(entry),
38817
+ directoryFilter: (entry) => wh.filterDir(entry),
38818
+ });
38819
+ if (!stream)
38820
+ return;
38821
+ stream
38822
+ .on(STR_DATA, async (entry) => {
38823
+ if (this.fsw.closed) {
38824
+ stream = undefined;
38825
+ return;
38826
+ }
38827
+ const item = entry.path;
38828
+ let path = sysPath.join(directory, item);
38829
+ current.add(item);
38830
+ if (entry.stats.isSymbolicLink() &&
38831
+ (await this._handleSymlink(entry, directory, path, item))) {
38832
+ return;
38833
+ }
38834
+ if (this.fsw.closed) {
38835
+ stream = undefined;
38836
+ return;
38837
+ }
38838
+ // Files that present in current directory snapshot
38839
+ // but absent in previous are added to watch list and
38840
+ // emit `add` event.
38841
+ if (item === target || (!target && !previous.has(item))) {
38842
+ this.fsw._incrReadyCount();
38843
+ // ensure relativeness of path is preserved in case of watcher reuse
38844
+ path = sysPath.join(dir, sysPath.relative(dir, path));
38845
+ this._addToNodeFs(path, initialAdd, wh, depth + 1);
38846
+ }
38847
+ })
38848
+ .on(EV.ERROR, this._boundHandleError);
38849
+ return new Promise((resolve, reject) => {
38850
+ if (!stream)
38851
+ return reject();
38852
+ stream.once(STR_END, () => {
38853
+ if (this.fsw.closed) {
38854
+ stream = undefined;
38855
+ return;
38856
+ }
38857
+ const wasThrottled = throttler ? throttler.clear() : false;
38858
+ resolve(undefined);
38859
+ // Files that absent in current directory snapshot
38860
+ // but present in previous emit `remove` event
38861
+ // and are removed from @watched[directory].
38862
+ previous
38863
+ .getChildren()
38864
+ .filter((item) => {
38865
+ return item !== directory && !current.has(item);
38866
+ })
38867
+ .forEach((item) => {
38868
+ this.fsw._remove(directory, item);
38869
+ });
38870
+ stream = undefined;
38871
+ // one more time for any missed in case changes came in extremely quickly
38872
+ if (wasThrottled)
38873
+ this._handleRead(directory, false, wh, target, dir, depth, throttler);
38874
+ });
38875
+ });
38876
+ }
38877
+ /**
38878
+ * Read directory to add / remove files from `@watched` list and re-read it on change.
38879
+ * @param dir fs path
38880
+ * @param stats
38881
+ * @param initialAdd
38882
+ * @param depth relative to user-supplied path
38883
+ * @param target child path targeted for watch
38884
+ * @param wh Common watch helpers for this path
38885
+ * @param realpath
38886
+ * @returns closer for the watcher instance.
38887
+ */
38888
+ async _handleDir(dir, stats, initialAdd, depth, target, wh, realpath) {
38889
+ const parentDir = this.fsw._getWatchedDir(sysPath.dirname(dir));
38890
+ const tracked = parentDir.has(sysPath.basename(dir));
38891
+ if (!(initialAdd && this.fsw.options.ignoreInitial) && !target && !tracked) {
38892
+ this.fsw._emit(EV.ADD_DIR, dir, stats);
38893
+ }
38894
+ // ensure dir is tracked (harmless if redundant)
38895
+ parentDir.add(sysPath.basename(dir));
38896
+ this.fsw._getWatchedDir(dir);
38897
+ let throttler;
38898
+ let closer;
38899
+ const oDepth = this.fsw.options.depth;
38900
+ if ((oDepth == null || depth <= oDepth) && !this.fsw._symlinkPaths.has(realpath)) {
38901
+ if (!target) {
38902
+ await this._handleRead(dir, initialAdd, wh, target, dir, depth, throttler);
38903
+ if (this.fsw.closed)
38904
+ return;
38905
+ }
38906
+ closer = this._watchWithNodeFs(dir, (dirPath, stats) => {
38907
+ // if current directory is removed, do nothing
38908
+ if (stats && stats.mtimeMs === 0)
38909
+ return;
38910
+ this._handleRead(dirPath, false, wh, target, dir, depth, throttler);
38911
+ });
38912
+ }
38913
+ return closer;
38914
+ }
38915
+ /**
38916
+ * Handle added file, directory, or glob pattern.
38917
+ * Delegates call to _handleFile / _handleDir after checks.
38918
+ * @param path to file or ir
38919
+ * @param initialAdd was the file added at watch instantiation?
38920
+ * @param priorWh depth relative to user-supplied path
38921
+ * @param depth Child path actually targeted for watch
38922
+ * @param target Child path actually targeted for watch
38923
+ */
38924
+ async _addToNodeFs(path, initialAdd, priorWh, depth, target) {
38925
+ const ready = this.fsw._emitReady;
38926
+ if (this.fsw._isIgnored(path) || this.fsw.closed) {
38927
+ ready();
38928
+ return false;
38929
+ }
38930
+ const wh = this.fsw._getWatchHelpers(path);
38931
+ if (priorWh) {
38932
+ wh.filterPath = (entry) => priorWh.filterPath(entry);
38933
+ wh.filterDir = (entry) => priorWh.filterDir(entry);
38934
+ }
38935
+ // evaluate what is at the path we're being asked to watch
38936
+ try {
38937
+ const stats = await statMethods[wh.statMethod](wh.watchPath);
38938
+ if (this.fsw.closed)
38939
+ return;
38940
+ if (this.fsw._isIgnored(wh.watchPath, stats)) {
38941
+ ready();
38942
+ return false;
38943
+ }
38944
+ const follow = this.fsw.options.followSymlinks;
38945
+ let closer;
38946
+ if (stats.isDirectory()) {
38947
+ const absPath = sysPath.resolve(path);
38948
+ const targetPath = follow ? await realpath$1(path) : path;
38949
+ if (this.fsw.closed)
38950
+ return;
38951
+ closer = await this._handleDir(wh.watchPath, stats, initialAdd, depth, target, wh, targetPath);
38952
+ if (this.fsw.closed)
38953
+ return;
38954
+ // preserve this symlink's target path
38955
+ if (absPath !== targetPath && targetPath !== undefined) {
38956
+ this.fsw._symlinkPaths.set(absPath, targetPath);
38957
+ }
38958
+ }
38959
+ else if (stats.isSymbolicLink()) {
38960
+ const targetPath = follow ? await realpath$1(path) : path;
38961
+ if (this.fsw.closed)
38962
+ return;
38963
+ const parent = sysPath.dirname(wh.watchPath);
38964
+ this.fsw._getWatchedDir(parent).add(wh.watchPath);
38965
+ this.fsw._emit(EV.ADD, wh.watchPath, stats);
38966
+ closer = await this._handleDir(parent, stats, initialAdd, depth, path, wh, targetPath);
38967
+ if (this.fsw.closed)
38968
+ return;
38969
+ // preserve this symlink's target path
38970
+ if (targetPath !== undefined) {
38971
+ this.fsw._symlinkPaths.set(sysPath.resolve(path), targetPath);
38972
+ }
38973
+ }
38974
+ else {
38975
+ closer = this._handleFile(wh.watchPath, stats, initialAdd);
38976
+ }
38977
+ ready();
38978
+ if (closer)
38979
+ this.fsw._addPathCloser(path, closer);
38980
+ return false;
38981
+ }
38982
+ catch (error) {
38983
+ if (this.fsw._handleError(error)) {
38984
+ ready();
38985
+ return path;
38986
+ }
38987
+ }
38988
+ }
38989
+ }
38990
+
38991
+ /*! chokidar - MIT License (c) 2012 Paul Miller (paulmillr.com) */
38992
+ const SLASH = '/';
38993
+ const SLASH_SLASH = '//';
38994
+ const ONE_DOT = '.';
38995
+ const TWO_DOTS = '..';
38996
+ const STRING_TYPE = 'string';
38997
+ const BACK_SLASH_RE = /\\/g;
38998
+ const DOUBLE_SLASH_RE = /\/\//;
38999
+ const DOT_RE = /\..*\.(sw[px])$|~$|\.subl.*\.tmp/;
39000
+ const REPLACER_RE = /^\.[/\\]/;
39001
+ function arrify(item) {
39002
+ return Array.isArray(item) ? item : [item];
39003
+ }
39004
+ const isMatcherObject = (matcher) => typeof matcher === 'object' && matcher !== null && !(matcher instanceof RegExp);
39005
+ function createPattern(matcher) {
39006
+ if (typeof matcher === 'function')
39007
+ return matcher;
39008
+ if (typeof matcher === 'string')
39009
+ return (string) => matcher === string;
39010
+ if (matcher instanceof RegExp)
39011
+ return (string) => matcher.test(string);
39012
+ if (typeof matcher === 'object' && matcher !== null) {
39013
+ return (string) => {
39014
+ if (matcher.path === string)
39015
+ return true;
39016
+ if (matcher.recursive) {
39017
+ const relative = sysPath.relative(matcher.path, string);
39018
+ if (!relative) {
39019
+ return false;
39020
+ }
39021
+ return !relative.startsWith('..') && !sysPath.isAbsolute(relative);
39022
+ }
39023
+ return false;
39024
+ };
39025
+ }
39026
+ return () => false;
39027
+ }
39028
+ function normalizePath(path) {
39029
+ if (typeof path !== 'string')
39030
+ throw new Error('string expected');
39031
+ path = sysPath.normalize(path);
39032
+ path = path.replace(/\\/g, '/');
39033
+ let prepend = false;
39034
+ if (path.startsWith('//'))
39035
+ prepend = true;
39036
+ const DOUBLE_SLASH_RE = /\/\//;
39037
+ while (path.match(DOUBLE_SLASH_RE))
39038
+ path = path.replace(DOUBLE_SLASH_RE, '/');
39039
+ if (prepend)
39040
+ path = '/' + path;
39041
+ return path;
39042
+ }
39043
+ function matchPatterns(patterns, testString, stats) {
39044
+ const path = normalizePath(testString);
39045
+ for (let index = 0; index < patterns.length; index++) {
39046
+ const pattern = patterns[index];
39047
+ if (pattern(path, stats)) {
39048
+ return true;
39049
+ }
39050
+ }
39051
+ return false;
39052
+ }
39053
+ function anymatch(matchers, testString) {
39054
+ if (matchers == null) {
39055
+ throw new TypeError('anymatch: specify first argument');
39056
+ }
39057
+ // Early cache for matchers.
39058
+ const matchersArray = arrify(matchers);
39059
+ const patterns = matchersArray.map((matcher) => createPattern(matcher));
39060
+ {
39061
+ return (testString, stats) => {
39062
+ return matchPatterns(patterns, testString, stats);
39063
+ };
39064
+ }
39065
+ }
39066
+ const unifyPaths = (paths_) => {
39067
+ const paths = arrify(paths_).flat();
39068
+ if (!paths.every((p) => typeof p === STRING_TYPE)) {
39069
+ throw new TypeError(`Non-string provided as watch path: ${paths}`);
39070
+ }
39071
+ return paths.map(normalizePathToUnix);
39072
+ };
39073
+ // If SLASH_SLASH occurs at the beginning of path, it is not replaced
39074
+ // because "//StoragePC/DrivePool/Movies" is a valid network path
39075
+ const toUnix = (string) => {
39076
+ let str = string.replace(BACK_SLASH_RE, SLASH);
39077
+ let prepend = false;
39078
+ if (str.startsWith(SLASH_SLASH)) {
39079
+ prepend = true;
39080
+ }
39081
+ while (str.match(DOUBLE_SLASH_RE)) {
39082
+ str = str.replace(DOUBLE_SLASH_RE, SLASH);
39083
+ }
39084
+ if (prepend) {
39085
+ str = SLASH + str;
39086
+ }
39087
+ return str;
39088
+ };
39089
+ // Our version of upath.normalize
39090
+ // TODO: this is not equal to path-normalize module - investigate why
39091
+ const normalizePathToUnix = (path) => toUnix(sysPath.normalize(toUnix(path)));
39092
+ // TODO: refactor
39093
+ const normalizeIgnored = (cwd = '') => (path) => {
39094
+ if (typeof path === 'string') {
39095
+ return normalizePathToUnix(sysPath.isAbsolute(path) ? path : sysPath.join(cwd, path));
39096
+ }
39097
+ else {
39098
+ return path;
39099
+ }
39100
+ };
39101
+ const getAbsolutePath = (path, cwd) => {
39102
+ if (sysPath.isAbsolute(path)) {
39103
+ return path;
39104
+ }
39105
+ return sysPath.join(cwd, path);
39106
+ };
39107
+ const EMPTY_SET = Object.freeze(new Set());
39108
+ /**
39109
+ * Directory entry.
39110
+ */
39111
+ class DirEntry {
39112
+ constructor(dir, removeWatcher) {
39113
+ this.path = dir;
39114
+ this._removeWatcher = removeWatcher;
39115
+ this.items = new Set();
39116
+ }
39117
+ add(item) {
39118
+ const { items } = this;
39119
+ if (!items)
39120
+ return;
39121
+ if (item !== ONE_DOT && item !== TWO_DOTS)
39122
+ items.add(item);
39123
+ }
39124
+ async remove(item) {
39125
+ const { items } = this;
39126
+ if (!items)
39127
+ return;
39128
+ items.delete(item);
39129
+ if (items.size > 0)
39130
+ return;
39131
+ const dir = this.path;
39132
+ try {
39133
+ await readdir$1(dir);
39134
+ }
39135
+ catch (err) {
39136
+ if (this._removeWatcher) {
39137
+ this._removeWatcher(sysPath.dirname(dir), sysPath.basename(dir));
39138
+ }
39139
+ }
39140
+ }
39141
+ has(item) {
39142
+ const { items } = this;
39143
+ if (!items)
39144
+ return;
39145
+ return items.has(item);
39146
+ }
39147
+ getChildren() {
39148
+ const { items } = this;
39149
+ if (!items)
39150
+ return [];
39151
+ return [...items.values()];
39152
+ }
39153
+ dispose() {
39154
+ this.items.clear();
39155
+ this.path = '';
39156
+ this._removeWatcher = EMPTY_FN;
39157
+ this.items = EMPTY_SET;
39158
+ Object.freeze(this);
39159
+ }
39160
+ }
39161
+ const STAT_METHOD_F = 'stat';
39162
+ const STAT_METHOD_L = 'lstat';
39163
+ class WatchHelper {
39164
+ constructor(path, follow, fsw) {
39165
+ this.fsw = fsw;
39166
+ const watchPath = path;
39167
+ this.path = path = path.replace(REPLACER_RE, '');
39168
+ this.watchPath = watchPath;
39169
+ this.fullWatchPath = sysPath.resolve(watchPath);
39170
+ this.dirParts = [];
39171
+ this.dirParts.forEach((parts) => {
39172
+ if (parts.length > 1)
39173
+ parts.pop();
39174
+ });
39175
+ this.followSymlinks = follow;
39176
+ this.statMethod = follow ? STAT_METHOD_F : STAT_METHOD_L;
39177
+ }
39178
+ entryPath(entry) {
39179
+ return sysPath.join(this.watchPath, sysPath.relative(this.watchPath, entry.fullPath));
39180
+ }
39181
+ filterPath(entry) {
39182
+ const { stats } = entry;
39183
+ if (stats && stats.isSymbolicLink())
39184
+ return this.filterDir(entry);
39185
+ const resolvedPath = this.entryPath(entry);
39186
+ // TODO: what if stats is undefined? remove !
39187
+ return this.fsw._isntIgnored(resolvedPath, stats) && this.fsw._hasReadPermissions(stats);
39188
+ }
39189
+ filterDir(entry) {
39190
+ return this.fsw._isntIgnored(this.entryPath(entry), entry.stats);
39191
+ }
39192
+ }
39193
+ /**
39194
+ * Watches files & directories for changes. Emitted events:
39195
+ * `add`, `addDir`, `change`, `unlink`, `unlinkDir`, `all`, `error`
39196
+ *
39197
+ * new FSWatcher()
39198
+ * .add(directories)
39199
+ * .on('add', path => log('File', path, 'was added'))
39200
+ */
39201
+ class FSWatcher extends EventEmitter {
39202
+ // Not indenting methods for history sake; for now.
39203
+ constructor(_opts = {}) {
39204
+ super();
39205
+ this.closed = false;
39206
+ this._closers = new Map();
39207
+ this._ignoredPaths = new Set();
39208
+ this._throttled = new Map();
39209
+ this._streams = new Set();
39210
+ this._symlinkPaths = new Map();
39211
+ this._watched = new Map();
39212
+ this._pendingWrites = new Map();
39213
+ this._pendingUnlinks = new Map();
39214
+ this._readyCount = 0;
39215
+ this._readyEmitted = false;
39216
+ const awf = _opts.awaitWriteFinish;
39217
+ const DEF_AWF = { stabilityThreshold: 2000, pollInterval: 100 };
39218
+ const opts = {
39219
+ // Defaults
39220
+ persistent: true,
39221
+ ignoreInitial: false,
39222
+ ignorePermissionErrors: false,
39223
+ interval: 100,
39224
+ binaryInterval: 300,
39225
+ followSymlinks: true,
39226
+ usePolling: false,
39227
+ // useAsync: false,
39228
+ atomic: true, // NOTE: overwritten later (depends on usePolling)
39229
+ ..._opts,
39230
+ // Change format
39231
+ ignored: _opts.ignored ? arrify(_opts.ignored) : arrify([]),
39232
+ awaitWriteFinish: awf === true ? DEF_AWF : typeof awf === 'object' ? { ...DEF_AWF, ...awf } : false,
39233
+ };
39234
+ // Always default to polling on IBM i because fs.watch() is not available on IBM i.
39235
+ if (isIBMi)
39236
+ opts.usePolling = true;
39237
+ // Editor atomic write normalization enabled by default with fs.watch
39238
+ if (opts.atomic === undefined)
39239
+ opts.atomic = !opts.usePolling;
39240
+ // opts.atomic = typeof _opts.atomic === 'number' ? _opts.atomic : 100;
39241
+ // Global override. Useful for developers, who need to force polling for all
39242
+ // instances of chokidar, regardless of usage / dependency depth
39243
+ const envPoll = process.env.CHOKIDAR_USEPOLLING;
39244
+ if (envPoll !== undefined) {
39245
+ const envLower = envPoll.toLowerCase();
39246
+ if (envLower === 'false' || envLower === '0')
39247
+ opts.usePolling = false;
39248
+ else if (envLower === 'true' || envLower === '1')
39249
+ opts.usePolling = true;
39250
+ else
39251
+ opts.usePolling = !!envLower;
39252
+ }
39253
+ const envInterval = process.env.CHOKIDAR_INTERVAL;
39254
+ if (envInterval)
39255
+ opts.interval = Number.parseInt(envInterval, 10);
39256
+ // This is done to emit ready only once, but each 'add' will increase that?
39257
+ let readyCalls = 0;
39258
+ this._emitReady = () => {
39259
+ readyCalls++;
39260
+ if (readyCalls >= this._readyCount) {
39261
+ this._emitReady = EMPTY_FN;
39262
+ this._readyEmitted = true;
39263
+ // use process.nextTick to allow time for listener to be bound
39264
+ process.nextTick(() => this.emit(EVENTS.READY));
39265
+ }
39266
+ };
39267
+ this._emitRaw = (...args) => this.emit(EVENTS.RAW, ...args);
39268
+ this._boundRemove = this._remove.bind(this);
39269
+ this.options = opts;
39270
+ this._nodeFsHandler = new NodeFsHandler(this);
39271
+ // You’re frozen when your heart’s not open.
39272
+ Object.freeze(opts);
39273
+ }
39274
+ _addIgnoredPath(matcher) {
39275
+ if (isMatcherObject(matcher)) {
39276
+ // return early if we already have a deeply equal matcher object
39277
+ for (const ignored of this._ignoredPaths) {
39278
+ if (isMatcherObject(ignored) &&
39279
+ ignored.path === matcher.path &&
39280
+ ignored.recursive === matcher.recursive) {
39281
+ return;
39282
+ }
39283
+ }
39284
+ }
39285
+ this._ignoredPaths.add(matcher);
39286
+ }
39287
+ _removeIgnoredPath(matcher) {
39288
+ this._ignoredPaths.delete(matcher);
39289
+ // now find any matcher objects with the matcher as path
39290
+ if (typeof matcher === 'string') {
39291
+ for (const ignored of this._ignoredPaths) {
39292
+ // TODO (43081j): make this more efficient.
39293
+ // probably just make a `this._ignoredDirectories` or some
39294
+ // such thing.
39295
+ if (isMatcherObject(ignored) && ignored.path === matcher) {
39296
+ this._ignoredPaths.delete(ignored);
39297
+ }
39298
+ }
39299
+ }
39300
+ }
39301
+ // Public methods
39302
+ /**
39303
+ * Adds paths to be watched on an existing FSWatcher instance.
39304
+ * @param paths_ file or file list. Other arguments are unused
39305
+ */
39306
+ add(paths_, _origAdd, _internal) {
39307
+ const { cwd } = this.options;
39308
+ this.closed = false;
39309
+ this._closePromise = undefined;
39310
+ let paths = unifyPaths(paths_);
39311
+ if (cwd) {
39312
+ paths = paths.map((path) => {
39313
+ const absPath = getAbsolutePath(path, cwd);
39314
+ // Check `path` instead of `absPath` because the cwd portion can't be a glob
39315
+ return absPath;
39316
+ });
39317
+ }
39318
+ paths.forEach((path) => {
39319
+ this._removeIgnoredPath(path);
39320
+ });
39321
+ this._userIgnored = undefined;
39322
+ if (!this._readyCount)
39323
+ this._readyCount = 0;
39324
+ this._readyCount += paths.length;
39325
+ Promise.all(paths.map(async (path) => {
39326
+ const res = await this._nodeFsHandler._addToNodeFs(path, !_internal, undefined, 0, _origAdd);
39327
+ if (res)
39328
+ this._emitReady();
39329
+ return res;
39330
+ })).then((results) => {
39331
+ if (this.closed)
39332
+ return;
39333
+ results.forEach((item) => {
39334
+ if (item)
39335
+ this.add(sysPath.dirname(item), sysPath.basename(_origAdd || item));
39336
+ });
39337
+ });
39338
+ return this;
39339
+ }
39340
+ /**
39341
+ * Close watchers or start ignoring events from specified paths.
39342
+ */
39343
+ unwatch(paths_) {
39344
+ if (this.closed)
39345
+ return this;
39346
+ const paths = unifyPaths(paths_);
39347
+ const { cwd } = this.options;
39348
+ paths.forEach((path) => {
39349
+ // convert to absolute path unless relative path already matches
39350
+ if (!sysPath.isAbsolute(path) && !this._closers.has(path)) {
39351
+ if (cwd)
39352
+ path = sysPath.join(cwd, path);
39353
+ path = sysPath.resolve(path);
39354
+ }
39355
+ this._closePath(path);
39356
+ this._addIgnoredPath(path);
39357
+ if (this._watched.has(path)) {
39358
+ this._addIgnoredPath({
39359
+ path,
39360
+ recursive: true,
39361
+ });
39362
+ }
39363
+ // reset the cached userIgnored anymatch fn
39364
+ // to make ignoredPaths changes effective
39365
+ this._userIgnored = undefined;
39366
+ });
39367
+ return this;
39368
+ }
39369
+ /**
39370
+ * Close watchers and remove all listeners from watched paths.
39371
+ */
39372
+ close() {
39373
+ if (this._closePromise) {
39374
+ return this._closePromise;
39375
+ }
39376
+ this.closed = true;
39377
+ // Memory management.
39378
+ this.removeAllListeners();
39379
+ const closers = [];
39380
+ this._closers.forEach((closerList) => closerList.forEach((closer) => {
39381
+ const promise = closer();
39382
+ if (promise instanceof Promise)
39383
+ closers.push(promise);
39384
+ }));
39385
+ this._streams.forEach((stream) => stream.destroy());
39386
+ this._userIgnored = undefined;
39387
+ this._readyCount = 0;
39388
+ this._readyEmitted = false;
39389
+ this._watched.forEach((dirent) => dirent.dispose());
39390
+ this._closers.clear();
39391
+ this._watched.clear();
39392
+ this._streams.clear();
39393
+ this._symlinkPaths.clear();
39394
+ this._throttled.clear();
39395
+ this._closePromise = closers.length
39396
+ ? Promise.all(closers).then(() => undefined)
39397
+ : Promise.resolve();
39398
+ return this._closePromise;
39399
+ }
39400
+ /**
39401
+ * Expose list of watched paths
39402
+ * @returns for chaining
39403
+ */
39404
+ getWatched() {
39405
+ const watchList = {};
39406
+ this._watched.forEach((entry, dir) => {
39407
+ const key = this.options.cwd ? sysPath.relative(this.options.cwd, dir) : dir;
39408
+ const index = key || ONE_DOT;
39409
+ watchList[index] = entry.getChildren().sort();
39410
+ });
39411
+ return watchList;
39412
+ }
39413
+ emitWithAll(event, args) {
39414
+ this.emit(event, ...args);
39415
+ if (event !== EVENTS.ERROR)
39416
+ this.emit(EVENTS.ALL, event, ...args);
39417
+ }
39418
+ // Common helpers
39419
+ // --------------
39420
+ /**
39421
+ * Normalize and emit events.
39422
+ * Calling _emit DOES NOT MEAN emit() would be called!
39423
+ * @param event Type of event
39424
+ * @param path File or directory path
39425
+ * @param stats arguments to be passed with event
39426
+ * @returns the error if defined, otherwise the value of the FSWatcher instance's `closed` flag
39427
+ */
39428
+ async _emit(event, path, stats) {
39429
+ if (this.closed)
39430
+ return;
39431
+ const opts = this.options;
39432
+ if (isWindows)
39433
+ path = sysPath.normalize(path);
39434
+ if (opts.cwd)
39435
+ path = sysPath.relative(opts.cwd, path);
39436
+ const args = [path];
39437
+ if (stats != null)
39438
+ args.push(stats);
39439
+ const awf = opts.awaitWriteFinish;
39440
+ let pw;
39441
+ if (awf && (pw = this._pendingWrites.get(path))) {
39442
+ pw.lastChange = new Date();
39443
+ return this;
39444
+ }
39445
+ if (opts.atomic) {
39446
+ if (event === EVENTS.UNLINK) {
39447
+ this._pendingUnlinks.set(path, [event, ...args]);
39448
+ setTimeout(() => {
39449
+ this._pendingUnlinks.forEach((entry, path) => {
39450
+ this.emit(...entry);
39451
+ this.emit(EVENTS.ALL, ...entry);
39452
+ this._pendingUnlinks.delete(path);
39453
+ });
39454
+ }, typeof opts.atomic === 'number' ? opts.atomic : 100);
39455
+ return this;
39456
+ }
39457
+ if (event === EVENTS.ADD && this._pendingUnlinks.has(path)) {
39458
+ event = EVENTS.CHANGE;
39459
+ this._pendingUnlinks.delete(path);
39460
+ }
39461
+ }
39462
+ if (awf && (event === EVENTS.ADD || event === EVENTS.CHANGE) && this._readyEmitted) {
39463
+ const awfEmit = (err, stats) => {
39464
+ if (err) {
39465
+ event = EVENTS.ERROR;
39466
+ args[0] = err;
39467
+ this.emitWithAll(event, args);
39468
+ }
39469
+ else if (stats) {
39470
+ // if stats doesn't exist the file must have been deleted
39471
+ if (args.length > 1) {
39472
+ args[1] = stats;
39473
+ }
39474
+ else {
39475
+ args.push(stats);
39476
+ }
39477
+ this.emitWithAll(event, args);
39478
+ }
39479
+ };
39480
+ this._awaitWriteFinish(path, awf.stabilityThreshold, event, awfEmit);
39481
+ return this;
39482
+ }
39483
+ if (event === EVENTS.CHANGE) {
39484
+ const isThrottled = !this._throttle(EVENTS.CHANGE, path, 50);
39485
+ if (isThrottled)
39486
+ return this;
39487
+ }
39488
+ if (opts.alwaysStat &&
39489
+ stats === undefined &&
39490
+ (event === EVENTS.ADD || event === EVENTS.ADD_DIR || event === EVENTS.CHANGE)) {
39491
+ const fullPath = opts.cwd ? sysPath.join(opts.cwd, path) : path;
39492
+ let stats;
39493
+ try {
39494
+ stats = await stat$2(fullPath);
39495
+ }
39496
+ catch (err) {
39497
+ // do nothing
39498
+ }
39499
+ // Suppress event when fs_stat fails, to avoid sending undefined 'stat'
39500
+ if (!stats || this.closed)
39501
+ return;
39502
+ args.push(stats);
39503
+ }
39504
+ this.emitWithAll(event, args);
39505
+ return this;
39506
+ }
39507
+ /**
39508
+ * Common handler for errors
39509
+ * @returns The error if defined, otherwise the value of the FSWatcher instance's `closed` flag
39510
+ */
39511
+ _handleError(error) {
39512
+ const code = error && error.code;
39513
+ if (error &&
39514
+ code !== 'ENOENT' &&
39515
+ code !== 'ENOTDIR' &&
39516
+ (!this.options.ignorePermissionErrors || (code !== 'EPERM' && code !== 'EACCES'))) {
39517
+ this.emit(EVENTS.ERROR, error);
39518
+ }
39519
+ return error || this.closed;
39520
+ }
39521
+ /**
39522
+ * Helper utility for throttling
39523
+ * @param actionType type being throttled
39524
+ * @param path being acted upon
39525
+ * @param timeout duration of time to suppress duplicate actions
39526
+ * @returns tracking object or false if action should be suppressed
39527
+ */
39528
+ _throttle(actionType, path, timeout) {
39529
+ if (!this._throttled.has(actionType)) {
39530
+ this._throttled.set(actionType, new Map());
39531
+ }
39532
+ const action = this._throttled.get(actionType);
39533
+ if (!action)
39534
+ throw new Error('invalid throttle');
39535
+ const actionPath = action.get(path);
39536
+ if (actionPath) {
39537
+ actionPath.count++;
39538
+ return false;
39539
+ }
39540
+ // eslint-disable-next-line prefer-const
39541
+ let timeoutObject;
39542
+ const clear = () => {
39543
+ const item = action.get(path);
39544
+ const count = item ? item.count : 0;
39545
+ action.delete(path);
39546
+ clearTimeout(timeoutObject);
39547
+ if (item)
39548
+ clearTimeout(item.timeoutObject);
39549
+ return count;
39550
+ };
39551
+ timeoutObject = setTimeout(clear, timeout);
39552
+ const thr = { timeoutObject, clear, count: 0 };
39553
+ action.set(path, thr);
39554
+ return thr;
39555
+ }
39556
+ _incrReadyCount() {
39557
+ return this._readyCount++;
39558
+ }
39559
+ /**
39560
+ * Awaits write operation to finish.
39561
+ * Polls a newly created file for size variations. When files size does not change for 'threshold' milliseconds calls callback.
39562
+ * @param path being acted upon
39563
+ * @param threshold Time in milliseconds a file size must be fixed before acknowledging write OP is finished
39564
+ * @param event
39565
+ * @param awfEmit Callback to be called when ready for event to be emitted.
39566
+ */
39567
+ _awaitWriteFinish(path, threshold, event, awfEmit) {
39568
+ const awf = this.options.awaitWriteFinish;
39569
+ if (typeof awf !== 'object')
39570
+ return;
39571
+ const pollInterval = awf.pollInterval;
39572
+ let timeoutHandler;
39573
+ let fullPath = path;
39574
+ if (this.options.cwd && !sysPath.isAbsolute(path)) {
39575
+ fullPath = sysPath.join(this.options.cwd, path);
39576
+ }
39577
+ const now = new Date();
39578
+ const writes = this._pendingWrites;
39579
+ function awaitWriteFinishFn(prevStat) {
39580
+ stat$3(fullPath, (err, curStat) => {
39581
+ if (err || !writes.has(path)) {
39582
+ if (err && err.code !== 'ENOENT')
39583
+ awfEmit(err);
39584
+ return;
39585
+ }
39586
+ const now = Number(new Date());
39587
+ if (prevStat && curStat.size !== prevStat.size) {
39588
+ writes.get(path).lastChange = now;
39589
+ }
39590
+ const pw = writes.get(path);
39591
+ const df = now - pw.lastChange;
39592
+ if (df >= threshold) {
39593
+ writes.delete(path);
39594
+ awfEmit(undefined, curStat);
39595
+ }
39596
+ else {
39597
+ timeoutHandler = setTimeout(awaitWriteFinishFn, pollInterval, curStat);
39598
+ }
39599
+ });
39600
+ }
39601
+ if (!writes.has(path)) {
39602
+ writes.set(path, {
39603
+ lastChange: now,
39604
+ cancelWait: () => {
39605
+ writes.delete(path);
39606
+ clearTimeout(timeoutHandler);
39607
+ return event;
39608
+ },
39609
+ });
39610
+ timeoutHandler = setTimeout(awaitWriteFinishFn, pollInterval);
39611
+ }
39612
+ }
39613
+ /**
39614
+ * Determines whether user has asked to ignore this path.
39615
+ */
39616
+ _isIgnored(path, stats) {
39617
+ if (this.options.atomic && DOT_RE.test(path))
39618
+ return true;
39619
+ if (!this._userIgnored) {
39620
+ const { cwd } = this.options;
39621
+ const ign = this.options.ignored;
39622
+ const ignored = (ign || []).map(normalizeIgnored(cwd));
39623
+ const ignoredPaths = [...this._ignoredPaths];
39624
+ const list = [...ignoredPaths.map(normalizeIgnored(cwd)), ...ignored];
39625
+ this._userIgnored = anymatch(list);
39626
+ }
39627
+ return this._userIgnored(path, stats);
39628
+ }
39629
+ _isntIgnored(path, stat) {
39630
+ return !this._isIgnored(path, stat);
39631
+ }
39632
+ /**
39633
+ * Provides a set of common helpers and properties relating to symlink handling.
39634
+ * @param path file or directory pattern being watched
39635
+ */
39636
+ _getWatchHelpers(path) {
39637
+ return new WatchHelper(path, this.options.followSymlinks, this);
39638
+ }
39639
+ // Directory helpers
39640
+ // -----------------
39641
+ /**
39642
+ * Provides directory tracking objects
39643
+ * @param directory path of the directory
39644
+ */
39645
+ _getWatchedDir(directory) {
39646
+ const dir = sysPath.resolve(directory);
39647
+ if (!this._watched.has(dir))
39648
+ this._watched.set(dir, new DirEntry(dir, this._boundRemove));
39649
+ return this._watched.get(dir);
39650
+ }
39651
+ // File helpers
39652
+ // ------------
39653
+ /**
39654
+ * Check for read permissions: https://stackoverflow.com/a/11781404/1358405
39655
+ */
39656
+ _hasReadPermissions(stats) {
39657
+ if (this.options.ignorePermissionErrors)
39658
+ return true;
39659
+ return Boolean(Number(stats.mode) & 0o400);
39660
+ }
39661
+ /**
39662
+ * Handles emitting unlink events for
39663
+ * files and directories, and via recursion, for
39664
+ * files and directories within directories that are unlinked
39665
+ * @param directory within which the following item is located
39666
+ * @param item base path of item/directory
39667
+ */
39668
+ _remove(directory, item, isDirectory) {
39669
+ // if what is being deleted is a directory, get that directory's paths
39670
+ // for recursive deleting and cleaning of watched object
39671
+ // if it is not a directory, nestedDirectoryChildren will be empty array
39672
+ const path = sysPath.join(directory, item);
39673
+ const fullPath = sysPath.resolve(path);
39674
+ isDirectory =
39675
+ isDirectory != null ? isDirectory : this._watched.has(path) || this._watched.has(fullPath);
39676
+ // prevent duplicate handling in case of arriving here nearly simultaneously
39677
+ // via multiple paths (such as _handleFile and _handleDir)
39678
+ if (!this._throttle('remove', path, 100))
39679
+ return;
39680
+ // if the only watched file is removed, watch for its return
39681
+ if (!isDirectory && this._watched.size === 1) {
39682
+ this.add(directory, item, true);
39683
+ }
39684
+ // This will create a new entry in the watched object in either case
39685
+ // so we got to do the directory check beforehand
39686
+ const wp = this._getWatchedDir(path);
39687
+ const nestedDirectoryChildren = wp.getChildren();
39688
+ // Recursively remove children directories / files.
39689
+ nestedDirectoryChildren.forEach((nested) => this._remove(path, nested));
39690
+ // Check if item was on the watched list and remove it
39691
+ const parent = this._getWatchedDir(directory);
39692
+ const wasTracked = parent.has(item);
39693
+ parent.remove(item);
39694
+ // Fixes issue #1042 -> Relative paths were detected and added as symlinks
39695
+ // (https://github.com/paulmillr/chokidar/blob/e1753ddbc9571bdc33b4a4af172d52cb6e611c10/lib/nodefs-handler.js#L612),
39696
+ // but never removed from the map in case the path was deleted.
39697
+ // This leads to an incorrect state if the path was recreated:
39698
+ // https://github.com/paulmillr/chokidar/blob/e1753ddbc9571bdc33b4a4af172d52cb6e611c10/lib/nodefs-handler.js#L553
39699
+ if (this._symlinkPaths.has(fullPath)) {
39700
+ this._symlinkPaths.delete(fullPath);
39701
+ }
39702
+ // If we wait for this file to be fully written, cancel the wait.
39703
+ let relPath = path;
39704
+ if (this.options.cwd)
39705
+ relPath = sysPath.relative(this.options.cwd, path);
39706
+ if (this.options.awaitWriteFinish && this._pendingWrites.has(relPath)) {
39707
+ const event = this._pendingWrites.get(relPath).cancelWait();
39708
+ if (event === EVENTS.ADD)
39709
+ return;
39710
+ }
39711
+ // The Entry will either be a directory that just got removed
39712
+ // or a bogus entry to a file, in either case we have to remove it
39713
+ this._watched.delete(path);
39714
+ this._watched.delete(fullPath);
39715
+ const eventName = isDirectory ? EVENTS.UNLINK_DIR : EVENTS.UNLINK;
39716
+ if (wasTracked && !this._isIgnored(path))
39717
+ this._emit(eventName, path);
39718
+ // Avoid conflicts if we later create another file with the same name
39719
+ this._closePath(path);
39720
+ }
39721
+ /**
39722
+ * Closes all watchers for a path
39723
+ */
39724
+ _closePath(path) {
39725
+ this._closeFile(path);
39726
+ const dir = sysPath.dirname(path);
39727
+ this._getWatchedDir(dir).remove(sysPath.basename(path));
39728
+ }
39729
+ /**
39730
+ * Closes only file-specific watchers
39731
+ */
39732
+ _closeFile(path) {
39733
+ const closers = this._closers.get(path);
39734
+ if (!closers)
39735
+ return;
39736
+ closers.forEach((closer) => closer());
39737
+ this._closers.delete(path);
39738
+ }
39739
+ _addPathCloser(path, closer) {
39740
+ if (!closer)
39741
+ return;
39742
+ let list = this._closers.get(path);
39743
+ if (!list) {
39744
+ list = [];
39745
+ this._closers.set(path, list);
39746
+ }
39747
+ list.push(closer);
39748
+ }
39749
+ _readdirp(root, opts) {
39750
+ if (this.closed)
39751
+ return;
39752
+ const options = { type: EVENTS.ALL, alwaysStat: true, lstat: true, ...opts, depth: 0 };
39753
+ let stream = readdirp(root, options);
39754
+ this._streams.add(stream);
39755
+ stream.once(STR_CLOSE, () => {
39756
+ stream = undefined;
39757
+ });
39758
+ stream.once(STR_END, () => {
39759
+ if (stream) {
39760
+ this._streams.delete(stream);
39761
+ stream = undefined;
39762
+ }
39763
+ });
39764
+ return stream;
39765
+ }
39766
+ }
39767
+ /**
39768
+ * Instantiates watcher with paths to be tracked.
39769
+ * @param paths file / directory paths
39770
+ * @param options opts, such as `atomic`, `awaitWriteFinish`, `ignored`, and others
39771
+ * @returns an instance of FSWatcher for chaining.
39772
+ * @example
39773
+ * const watcher = watch('.').on('all', (event, path) => { console.log(event, path); });
39774
+ * watch('.', { atomic: true, awaitWriteFinish: true, ignored: (f, stats) => stats?.isFile() && !f.endsWith('.js') })
39775
+ */
39776
+ function watch(paths, options = {}) {
39777
+ const watcher = new FSWatcher(options);
39778
+ watcher.add(paths);
39779
+ return watcher;
39780
+ }
39781
+ var index = { watch, FSWatcher };
39782
+
39783
+ var index$1 = /*#__PURE__*/Object.freeze({
39784
+ __proto__: null,
39785
+ FSWatcher: FSWatcher,
39786
+ WatchHelper: WatchHelper,
39787
+ default: index,
39788
+ watch: watch
39789
+ });
37930
39790
  //# sourceMappingURL=nasl.mjs.map