@nasl/cli 0.1.6 → 0.1.7

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/index.mjs CHANGED
@@ -1,8 +1,8 @@
1
- import * as path$1 from 'path';
2
- import path__default from 'path';
3
- import require$$0$3 from 'fs';
1
+ import * as sysPath from 'path';
2
+ import sysPath__default from 'path';
3
+ import require$$0$3, { unwatchFile, watchFile, watch as watch$1, stat as stat$3 } from 'fs';
4
4
  import stream$4, { Readable } from 'stream';
5
- import require$$0$1 from 'os';
5
+ import require$$0$1, { type as type$1 } from 'os';
6
6
  import require$$0$2 from 'util';
7
7
  import require$$0$4, { EventEmitter } from 'events';
8
8
  import require$$1 from 'tty';
@@ -10,11 +10,15 @@ import require$$0$5 from 'constants';
10
10
  import require$$5 from 'assert';
11
11
  import require$$3 from 'http';
12
12
  import require$$4 from 'https';
13
- import require$$0$6 from 'url';
13
+ import require$$0$6, { URL as URL$1 } from 'url';
14
14
  import require$$8 from 'crypto';
15
15
  import http2 from 'http2';
16
16
  import zlib from 'zlib';
17
- import { spawnSync } from 'child_process';
17
+ import { spawn, spawnSync } from 'child_process';
18
+ import { realpath as realpath$1, stat as stat$2, lstat as lstat$1, open, readdir as readdir$1 } from 'fs/promises';
19
+ import { lstat, stat as stat$1, readdir, realpath } from 'node:fs/promises';
20
+ import { Readable as Readable$1 } from 'node:stream';
21
+ import { resolve, join, relative, sep } from 'node:path';
18
22
 
19
23
  /**
20
24
  * 默认配置
@@ -354,7 +358,7 @@ function requirePath () {
354
358
  Object.defineProperty(path, "__esModule", { value: true });
355
359
  path.convertPosixPathToPattern = path.convertWindowsPathToPattern = path.convertPathToPattern = path.escapePosixPath = path.escapeWindowsPath = path.escape = path.removeLeadingDotSegment = path.makeAbsolute = path.unixify = void 0;
356
360
  const os = require$$0$1;
357
- const path$1 = path__default;
361
+ const path$1 = sysPath__default;
358
362
  const IS_WINDOWS_PLATFORM = os.platform() === 'win32';
359
363
  const LEADING_DOT_SEGMENT_CHARACTERS_COUNT = 2; // ./ or .\\
360
364
  /**
@@ -619,7 +623,7 @@ function requireGlobParent () {
619
623
  hasRequiredGlobParent = 1;
620
624
 
621
625
  var isGlob = requireIsGlob();
622
- var pathPosixDirname = path__default.posix.dirname;
626
+ var pathPosixDirname = sysPath__default.posix.dirname;
623
627
  var isWin32 = require$$0$1.platform() === 'win32';
624
628
 
625
629
  var slash = '/';
@@ -2191,7 +2195,7 @@ function requireConstants$1 () {
2191
2195
  if (hasRequiredConstants$1) return constants$1;
2192
2196
  hasRequiredConstants$1 = 1;
2193
2197
 
2194
- const path = path__default;
2198
+ const path = sysPath__default;
2195
2199
  const WIN_SLASH = '\\\\/';
2196
2200
  const WIN_NO_SLASH = `[^${WIN_SLASH}]`;
2197
2201
 
@@ -2378,7 +2382,7 @@ function requireUtils$4 () {
2378
2382
  hasRequiredUtils$4 = 1;
2379
2383
  (function (exports$1) {
2380
2384
 
2381
- const path = path__default;
2385
+ const path = sysPath__default;
2382
2386
  const win32 = process.platform === 'win32';
2383
2387
  const {
2384
2388
  REGEX_BACKSLASH,
@@ -3949,7 +3953,7 @@ function requirePicomatch$1 () {
3949
3953
  if (hasRequiredPicomatch$1) return picomatch_1;
3950
3954
  hasRequiredPicomatch$1 = 1;
3951
3955
 
3952
- const path = path__default;
3956
+ const path = sysPath__default;
3953
3957
  const scan = requireScan();
3954
3958
  const parse = requireParse();
3955
3959
  const utils = requireUtils$4();
@@ -4792,7 +4796,7 @@ function requirePattern () {
4792
4796
  hasRequiredPattern = 1;
4793
4797
  Object.defineProperty(pattern, "__esModule", { value: true });
4794
4798
  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;
4795
- const path = path__default;
4799
+ const path = sysPath__default;
4796
4800
  const globParent = requireGlobParent();
4797
4801
  const micromatch = requireMicromatch();
4798
4802
  const GLOBSTAR = '**';
@@ -5746,7 +5750,7 @@ function requireSettings$2 () {
5746
5750
  if (hasRequiredSettings$2) return settings$2;
5747
5751
  hasRequiredSettings$2 = 1;
5748
5752
  Object.defineProperty(settings$2, "__esModule", { value: true });
5749
- const path = path__default;
5753
+ const path = sysPath__default;
5750
5754
  const fsStat = requireOut$3();
5751
5755
  const fs = requireFs$1();
5752
5756
  class Settings {
@@ -6508,7 +6512,7 @@ function requireSettings$1 () {
6508
6512
  if (hasRequiredSettings$1) return settings$1;
6509
6513
  hasRequiredSettings$1 = 1;
6510
6514
  Object.defineProperty(settings$1, "__esModule", { value: true });
6511
- const path = path__default;
6515
+ const path = sysPath__default;
6512
6516
  const fsScandir = requireOut$2();
6513
6517
  class Settings {
6514
6518
  constructor(_options = {}) {
@@ -6584,7 +6588,7 @@ function requireReader () {
6584
6588
  if (hasRequiredReader) return reader;
6585
6589
  hasRequiredReader = 1;
6586
6590
  Object.defineProperty(reader, "__esModule", { value: true });
6587
- const path = path__default;
6591
+ const path = sysPath__default;
6588
6592
  const fsStat = requireOut$3();
6589
6593
  const utils = requireUtils$3();
6590
6594
  class Reader {
@@ -7057,7 +7061,7 @@ function requireProvider () {
7057
7061
  if (hasRequiredProvider) return provider;
7058
7062
  hasRequiredProvider = 1;
7059
7063
  Object.defineProperty(provider, "__esModule", { value: true });
7060
- const path = path__default;
7064
+ const path = sysPath__default;
7061
7065
  const deep_1 = requireDeep();
7062
7066
  const entry_1 = requireEntry$1();
7063
7067
  const error_1 = requireError();
@@ -7497,7 +7501,7 @@ var hasRequiredDirGlob;
7497
7501
  function requireDirGlob () {
7498
7502
  if (hasRequiredDirGlob) return dirGlob.exports;
7499
7503
  hasRequiredDirGlob = 1;
7500
- const path = path__default;
7504
+ const path = sysPath__default;
7501
7505
  const pathType = requirePathType();
7502
7506
 
7503
7507
  const getExtensions = extensions => extensions.length > 1 ? `{${extensions.join(',')}}` : extensions[0];
@@ -8247,7 +8251,7 @@ function requireGitignore () {
8247
8251
  hasRequiredGitignore = 1;
8248
8252
  const {promisify} = require$$0$2;
8249
8253
  const fs = require$$0$3;
8250
- const path = path__default;
8254
+ const path = sysPath__default;
8251
8255
  const fastGlob = requireOut();
8252
8256
  const gitIgnore = requireIgnore();
8253
8257
  const slash = requireSlash();
@@ -11758,7 +11762,7 @@ var hasRequiredUtils$1;
11758
11762
  function requireUtils$1 () {
11759
11763
  if (hasRequiredUtils$1) return utils$3;
11760
11764
  hasRequiredUtils$1 = 1;
11761
- const path = path__default;
11765
+ const path = sysPath__default;
11762
11766
 
11763
11767
  // https://github.com/nodejs/node/issues/8987
11764
11768
  // https://github.com/libuv/libuv/pull/1088
@@ -11904,7 +11908,7 @@ function requireStat () {
11904
11908
  hasRequiredStat = 1;
11905
11909
 
11906
11910
  const fs = /*@__PURE__*/ requireFs();
11907
- const path = path__default;
11911
+ const path = sysPath__default;
11908
11912
  const u = requireUniversalify().fromPromise;
11909
11913
 
11910
11914
  function getStats (src, dest, opts) {
@@ -12108,7 +12112,7 @@ function requireCopy$1 () {
12108
12112
  hasRequiredCopy$1 = 1;
12109
12113
 
12110
12114
  const fs = /*@__PURE__*/ requireFs();
12111
- const path = path__default;
12115
+ const path = sysPath__default;
12112
12116
  const { mkdirs } = /*@__PURE__*/ requireMkdirs();
12113
12117
  const { pathExists } = /*@__PURE__*/ requirePathExists();
12114
12118
  const { utimesMillis } = /*@__PURE__*/ requireUtimes();
@@ -12291,7 +12295,7 @@ function requireCopySync () {
12291
12295
  hasRequiredCopySync = 1;
12292
12296
 
12293
12297
  const fs = requireGracefulFs();
12294
- const path = path__default;
12298
+ const path = sysPath__default;
12295
12299
  const mkdirsSync = /*@__PURE__*/ requireMkdirs().mkdirsSync;
12296
12300
  const utimesMillisSync = /*@__PURE__*/ requireUtimes().utimesMillisSync;
12297
12301
  const stat = /*@__PURE__*/ requireStat();
@@ -12511,7 +12515,7 @@ function requireEmpty () {
12511
12515
 
12512
12516
  const u = requireUniversalify().fromPromise;
12513
12517
  const fs = /*@__PURE__*/ requireFs();
12514
- const path = path__default;
12518
+ const path = sysPath__default;
12515
12519
  const mkdir = /*@__PURE__*/ requireMkdirs();
12516
12520
  const remove = /*@__PURE__*/ requireRemove();
12517
12521
 
@@ -12557,7 +12561,7 @@ function requireFile () {
12557
12561
  hasRequiredFile = 1;
12558
12562
 
12559
12563
  const u = requireUniversalify().fromPromise;
12560
- const path = path__default;
12564
+ const path = sysPath__default;
12561
12565
  const fs = /*@__PURE__*/ requireFs();
12562
12566
  const mkdir = /*@__PURE__*/ requireMkdirs();
12563
12567
 
@@ -12631,7 +12635,7 @@ function requireLink () {
12631
12635
  hasRequiredLink = 1;
12632
12636
 
12633
12637
  const u = requireUniversalify().fromPromise;
12634
- const path = path__default;
12638
+ const path = sysPath__default;
12635
12639
  const fs = /*@__PURE__*/ requireFs();
12636
12640
  const mkdir = /*@__PURE__*/ requireMkdirs();
12637
12641
  const { pathExists } = /*@__PURE__*/ requirePathExists();
@@ -12702,7 +12706,7 @@ function requireSymlinkPaths () {
12702
12706
  if (hasRequiredSymlinkPaths) return symlinkPaths_1;
12703
12707
  hasRequiredSymlinkPaths = 1;
12704
12708
 
12705
- const path = path__default;
12709
+ const path = sysPath__default;
12706
12710
  const fs = /*@__PURE__*/ requireFs();
12707
12711
  const { pathExists } = /*@__PURE__*/ requirePathExists();
12708
12712
 
@@ -12854,7 +12858,7 @@ function requireSymlink () {
12854
12858
  hasRequiredSymlink = 1;
12855
12859
 
12856
12860
  const u = requireUniversalify().fromPromise;
12857
- const path = path__default;
12861
+ const path = sysPath__default;
12858
12862
  const fs = /*@__PURE__*/ requireFs();
12859
12863
 
12860
12864
  const { mkdirs, mkdirsSync } = /*@__PURE__*/ requireMkdirs();
@@ -13100,7 +13104,7 @@ function requireOutputFile () {
13100
13104
 
13101
13105
  const u = requireUniversalify().fromPromise;
13102
13106
  const fs = /*@__PURE__*/ requireFs();
13103
- const path = path__default;
13107
+ const path = sysPath__default;
13104
13108
  const mkdir = /*@__PURE__*/ requireMkdirs();
13105
13109
  const pathExists = /*@__PURE__*/ requirePathExists().pathExists;
13106
13110
 
@@ -13202,7 +13206,7 @@ function requireMove$1 () {
13202
13206
  hasRequiredMove$1 = 1;
13203
13207
 
13204
13208
  const fs = /*@__PURE__*/ requireFs();
13205
- const path = path__default;
13209
+ const path = sysPath__default;
13206
13210
  const { copy } = /*@__PURE__*/ requireCopy();
13207
13211
  const { remove } = /*@__PURE__*/ requireRemove();
13208
13212
  const { mkdirp } = /*@__PURE__*/ requireMkdirs();
@@ -13269,7 +13273,7 @@ function requireMoveSync () {
13269
13273
  hasRequiredMoveSync = 1;
13270
13274
 
13271
13275
  const fs = requireGracefulFs();
13272
- const path = path__default;
13276
+ const path = sysPath__default;
13273
13277
  const copySync = /*@__PURE__*/ requireCopy().copySync;
13274
13278
  const removeSync = /*@__PURE__*/ requireRemove().removeSync;
13275
13279
  const mkdirpSync = /*@__PURE__*/ requireMkdirs().mkdirpSync;
@@ -13385,15 +13389,15 @@ var dayjs = /*@__PURE__*/getDefaultExportFromCjs(dayjs_minExports);
13385
13389
 
13386
13390
  function fastLogToFile(entry, suffix, content) {
13387
13391
  if (process.env.NASL_CLI_LOG_DIR) {
13388
- const logDir = path$1.resolve(process.env.NASL_CLI_LOG_DIR);
13392
+ const logDir = sysPath.resolve(process.env.NASL_CLI_LOG_DIR);
13389
13393
  libExports.ensureDirSync(logDir);
13390
13394
  const timeInDir = (process.env.NASL_CLI_LOG_DIR.match(/\d{6,8}_(\d{6})-/)?.[1] || '00');
13391
13395
  const now = dayjs();
13392
13396
  const hourInDir = parseInt(timeInDir.slice(0, 2), 10);
13393
13397
  // 跨天则累加 24 小时
13394
13398
  const hourStr = (now.hour() >= hourInDir ? now.hour() : Math.ceil(hourInDir / 24) * 24 + now.hour()).toString().padStart(2, '0');
13395
- const entryName = path$1.basename(Array.isArray(entry) ? entry[0] || '*' : entry).replace(/[\[\]\(\)\{\}\*\+\-\?\|\^\$\,\/\#\:\\\s]+/g, '_');
13396
- const filePath = path$1.resolve(logDir, `${hourStr}${now.format('mmss_SSS')}-${entryName}-${suffix}`);
13399
+ const entryName = sysPath.basename(Array.isArray(entry) ? entry[0] || '*' : entry).replace(/[\[\]\(\)\{\}\*\+\-\?\|\^\$\,\/\#\:\\\s]+/g, '_');
13400
+ const filePath = sysPath.resolve(logDir, `${hourStr}${now.format('mmss_SSS')}-${entryName}-${suffix}`);
13397
13401
  libExports.outputFileSync(filePath, content);
13398
13402
  }
13399
13403
  }
@@ -13424,16 +13428,16 @@ class BaseLogger {
13424
13428
  }
13425
13429
  debugToFile(topic, ...args) {
13426
13430
  if (process.env.DEBUG_TO_FILE) {
13427
- const baseDir = path$1.join(process.cwd(), '.nasl');
13431
+ const baseDir = sysPath.join(process.cwd(), '.nasl');
13428
13432
  const currentHour = dayjs().format('YYYYMMDD_HH');
13429
13433
  const prevHour = dayjs().subtract(1, 'hour').format('YYYYMMDD_HH');
13430
13434
  let subdir = `${topic}_${currentHour}`;
13431
13435
  const prevSubdir = `${topic}_${prevHour}`;
13432
13436
  // 判断如果有上一个小时的 subdir,则自己汇聚到上一个小时的 subdir 中
13433
- if (libExports.existsSync(path$1.join(baseDir, prevSubdir)))
13437
+ if (libExports.existsSync(sysPath.join(baseDir, prevSubdir)))
13434
13438
  subdir = prevSubdir;
13435
13439
  const fileName = `${topic}_${dayjs().format('YYYYMMDD_HHmmss')}.log`;
13436
- const filePath = path$1.join(baseDir, subdir, fileName);
13440
+ const filePath = sysPath.join(baseDir, subdir, fileName);
13437
13441
  libExports.outputFileSync(filePath, args.join(' '));
13438
13442
  }
13439
13443
  }
@@ -13481,6 +13485,13 @@ class ConsoleLogger extends BaseLogger {
13481
13485
  process.exit(code);
13482
13486
  }
13483
13487
  }
13488
+ class ConsoleLoggerWithoutExit extends ConsoleLogger {
13489
+ exit(code) {
13490
+ if (code)
13491
+ throw new Error(`Error with code: ${code}`);
13492
+ return undefined;
13493
+ }
13494
+ }
13484
13495
  /**
13485
13496
  * 内存日志工具类
13486
13497
  * 用于在内存中存储日志
@@ -13530,11 +13541,11 @@ function findConfigDir(startDir = process.cwd()) {
13530
13541
  let currentDir = startDir;
13531
13542
  // eslint-disable-next-line no-constant-condition
13532
13543
  while (true) {
13533
- const configPath = path$1.join(currentDir, CONFIG_FILE_NAME);
13544
+ const configPath = sysPath.join(currentDir, CONFIG_FILE_NAME);
13534
13545
  if (libExports.existsSync(configPath)) {
13535
13546
  return currentDir;
13536
13547
  }
13537
- const parentDir = path$1.dirname(currentDir);
13548
+ const parentDir = sysPath.dirname(currentDir);
13538
13549
  // 已经到达根目录
13539
13550
  if (parentDir === currentDir) {
13540
13551
  return null;
@@ -13551,7 +13562,7 @@ function loadConfig(configDir) {
13551
13562
  defaultLogger.error(`未找到配置文件 ${CONFIG_FILE_NAME},请先运行 nasl-init 初始化配置`);
13552
13563
  return defaultLogger.exit(1);
13553
13564
  }
13554
- const configPath = path$1.join(dir, CONFIG_FILE_NAME);
13565
+ const configPath = sysPath.join(dir, CONFIG_FILE_NAME);
13555
13566
  try {
13556
13567
  const content = libExports.readFileSync(configPath, 'utf-8');
13557
13568
  const config = JSON.parse(content);
@@ -13596,7 +13607,7 @@ function readFileWithLog(filePath, logger) {
13596
13607
  */
13597
13608
  function writeFileWithLog(filePath, content, logger) {
13598
13609
  try {
13599
- const dir = path$1.dirname(filePath);
13610
+ const dir = sysPath.dirname(filePath);
13600
13611
  libExports.ensureDirSync(dir);
13601
13612
  libExports.writeFileSync(filePath, content, 'utf-8');
13602
13613
  }
@@ -13677,7 +13688,7 @@ function replaceViewAsSignature(content) {
13677
13688
  * @returns 文件信息和新发现的依赖文件列表
13678
13689
  */
13679
13690
  function processFileDeps(pathRelativeToSrc, srcDir, matchedFileSet, processedFileMap, depNotFoundList, logger, verbose) {
13680
- const absoluteFilePath = path$1.join(srcDir, pathRelativeToSrc);
13691
+ const absoluteFilePath = sysPath.join(srcDir, pathRelativeToSrc);
13681
13692
  const fileInfo = { path: pathRelativeToSrc, content: '' };
13682
13693
  try {
13683
13694
  fileInfo.content = readFileWithLog(absoluteFilePath, logger);
@@ -13741,15 +13752,15 @@ async function collectDeps(patterns, projectRoot, srcDir, logger, verbose) {
13741
13752
  throw new Error('未找到匹配的入口文件');
13742
13753
  }
13743
13754
  logger.info(`找到 ${matchedFiles.length} 个入口文件`);
13744
- const absoluteSrcDir = path$1.resolve(srcDir);
13755
+ const absoluteSrcDir = sysPath.resolve(srcDir);
13745
13756
  const matchedFileSet = new Set();
13746
13757
  matchedFiles.forEach((pathRelativeToRoot) => {
13747
13758
  // 统一使用相对于 src 的路径
13748
- const absoluteFilePath = path$1.resolve(projectRoot, pathRelativeToRoot);
13759
+ const absoluteFilePath = sysPath.resolve(projectRoot, pathRelativeToRoot);
13749
13760
  // 判断 file 是否超出 srcDir 目录(支持相对路径和绝对路径)
13750
13761
  if (!absoluteFilePath.startsWith(absoluteSrcDir))
13751
13762
  throw new Error(`入口文件 ${absoluteFilePath} 超出了源代码目录 ${srcDir}`);
13752
- const pathRelativeToSrc = path$1.relative(srcDir, absoluteFilePath);
13763
+ const pathRelativeToSrc = sysPath.relative(srcDir, absoluteFilePath);
13753
13764
  filesToProcess.push(pathRelativeToSrc);
13754
13765
  matchedFileSet.add(pathRelativeToSrc);
13755
13766
  });
@@ -13798,7 +13809,7 @@ async function resolveNASLFiles(entry, logger, depMode, verbose) {
13798
13809
  const projectRoot = getProjectRoot();
13799
13810
  logger.info(`项目根目录: ${projectRoot}`);
13800
13811
  logger.info(`源代码目录: ${config.srcDir}`);
13801
- const srcDir = path$1.join(projectRoot, config.srcDir);
13812
+ const srcDir = sysPath.join(projectRoot, config.srcDir);
13802
13813
  // 收集需要处理的文件
13803
13814
  let collectedFiles = [];
13804
13815
  if (Array.isArray(entry) && !entry.length) {
@@ -13832,7 +13843,7 @@ async function resolveNASLFiles(entry, logger, depMode, verbose) {
13832
13843
  filePaths.sort(sorter);
13833
13844
  collectedFiles = filePaths.map((filePath) => ({
13834
13845
  path: filePath,
13835
- content: readFileWithLog(path$1.join(srcDir, filePath), logger),
13846
+ content: readFileWithLog(sysPath.join(srcDir, filePath), logger),
13836
13847
  }));
13837
13848
  if (collectedFiles.length === 0) {
13838
13849
  logger.warn('未找到 NASL 文件');
@@ -13853,7 +13864,7 @@ async function resolveNASLFiles(entry, logger, depMode, verbose) {
13853
13864
  */
13854
13865
  function init() {
13855
13866
  const cwd = process.cwd();
13856
- const configPath = path$1.join(cwd, CONFIG_FILE_NAME);
13867
+ const configPath = sysPath.join(cwd, CONFIG_FILE_NAME);
13857
13868
  // 检查配置文件是否已存在
13858
13869
  if (libExports.existsSync(configPath)) {
13859
13870
  defaultLogger.warn(`配置文件已存在: ${configPath}`);
@@ -13867,7 +13878,7 @@ function init() {
13867
13878
  defaultLogger.info('\n配置内容:');
13868
13879
  defaultLogger.info(JSON.stringify(DEFAULT_CONFIG, null, 2));
13869
13880
  // 创建源代码目录
13870
- const srcDirPath = path$1.join(cwd, DEFAULT_CONFIG.srcDir);
13881
+ const srcDirPath = sysPath.join(cwd, DEFAULT_CONFIG.srcDir);
13871
13882
  libExports.ensureDirSync(srcDirPath);
13872
13883
  defaultLogger.success(`源代码目录已创建: ${srcDirPath}`);
13873
13884
  defaultLogger.info('\n提示:');
@@ -25859,7 +25870,7 @@ function requireMimeTypes () {
25859
25870
  */
25860
25871
 
25861
25872
  var db = requireMimeDb();
25862
- var extname = path__default.extname;
25873
+ var extname = sysPath__default.extname;
25863
25874
 
25864
25875
  /**
25865
25876
  * Module variables.
@@ -27600,7 +27611,7 @@ function requireForm_data () {
27600
27611
 
27601
27612
  var CombinedStream = requireCombined_stream();
27602
27613
  var util = require$$0$2;
27603
- var path = path__default;
27614
+ var path = sysPath__default;
27604
27615
  var http = require$$3;
27605
27616
  var https = require$$4;
27606
27617
  var parseUrl = require$$0$6.parse;
@@ -34301,10 +34312,22 @@ const {
34301
34312
  } = axios;
34302
34313
 
34303
34314
  function createAxios(baseURL) {
34315
+ // 解析 baseURL 提取 hostname 和 port
34316
+ const url = new URL$1(baseURL);
34317
+ const hostname = url.hostname;
34318
+ const protocol = url.protocol;
34319
+ // 确定端口:如果 URL 中没有指定端口,根据协议使用默认端口
34320
+ let port = url.port;
34321
+ if (!port) {
34322
+ port = protocol === 'https:' ? '443' : '80';
34323
+ }
34324
+ // 构建 Host 头:hostname:port
34325
+ const hostHeader = `${hostname}:${port}`;
34304
34326
  return axios.create({
34305
34327
  baseURL,
34306
34328
  headers: {
34307
34329
  'Content-Type': 'application/json',
34330
+ 'Host': hostHeader,
34308
34331
  },
34309
34332
  timeout: 120000,
34310
34333
  });
@@ -34376,7 +34399,7 @@ async function compile(entry, options) {
34376
34399
  // 收集需要编译的文件
34377
34400
  const { collectedFiles, config, projectRoot } = await resolveNASLFiles(entry, logger, false, options?.verbose);
34378
34401
  logger.info(`输出目录: ${config.outDir}`);
34379
- const outDir = path$1.join(projectRoot, config.outDir);
34402
+ const outDir = sysPath.join(projectRoot, config.outDir);
34380
34403
  // 调用编译 API
34381
34404
  logger.newLine();
34382
34405
  logger.info('正在调用编译服务...');
@@ -34389,7 +34412,7 @@ async function compile(entry, options) {
34389
34412
  logger.success('编译成功!');
34390
34413
  // 写入输出文件
34391
34414
  for (const file of outputFiles) {
34392
- const outputPath = path$1.join(outDir, file.path);
34415
+ const outputPath = sysPath.join(outDir, file.path);
34393
34416
  writeFileWithLog(outputPath, file.content, logger);
34394
34417
  }
34395
34418
  logger.info(`输出 ${outputFiles.length} 个文件`);
@@ -34402,11 +34425,11 @@ async function compile(entry, options) {
34402
34425
  return { config, outDir };
34403
34426
  }
34404
34427
  async function tryCompile(entry, options) {
34405
- const logger = options?.logger || defaultLogger;
34406
34428
  try {
34407
34429
  await compile(entry, options);
34408
34430
  }
34409
34431
  catch (error) {
34432
+ const logger = options?.logger || defaultLogger;
34410
34433
  logger.error(`编译过程发生错误:${error.message}`);
34411
34434
  logger.exit(1);
34412
34435
  }
@@ -34457,24 +34480,189 @@ async function dep(entry, options) {
34457
34480
  return resolveNASLFiles(entry, logger, true, true);
34458
34481
  }
34459
34482
 
34460
- function justExecCommandSync(command, cwd) {
34461
- console.log(command);
34462
- const result = spawnSync(command, { shell: true, stdio: 'inherit', cwd });
34463
- if (result.status) {
34464
- console.error(String(result.stderr || result.stdout));
34483
+ /**
34484
+ * 编译命令 - 将 NASL 编译为 Vue 和 JS
34485
+ */
34486
+ async function dev(entry, options) {
34487
+ const logger = options?.logger || new ConsoleLoggerWithoutExit();
34488
+ // 获取项目根目录和配置
34489
+ const projectRoot = process.cwd();
34490
+ const configPath = sysPath.join(projectRoot, 'nasl.config.json');
34491
+ if (!libExports.existsSync(configPath)) {
34492
+ logger.error('未找到 nasl.config.json 配置文件,请先初始化项目');
34465
34493
  process.exit(1);
34466
34494
  }
34495
+ const configContent = libExports.readFileSync(configPath, 'utf-8');
34496
+ const config = JSON.parse(configContent);
34497
+ const srcDir = sysPath.join(projectRoot, config.srcDir);
34498
+ const outDir = sysPath.join(projectRoot, config.outDir);
34499
+ // 检查是否存在 src 目录
34500
+ const hasSrcDir = libExports.existsSync(srcDir) && libExports.statSync(srcDir).isDirectory();
34501
+ let lastCompileSuccess = false;
34502
+ if (hasSrcDir) {
34503
+ // 有 src 目录,先进行一次初始编译
34504
+ logger.info('检测到 src 目录,开始初始编译...');
34505
+ try {
34506
+ await compile(entry);
34507
+ lastCompileSuccess = true;
34508
+ logger.success('初始编译成功!');
34509
+ }
34510
+ catch (error) {
34511
+ logger.error(`初始编译失败:${error.message}`);
34512
+ // 即使编译失败,也要尝试启动服务(可能 out 目录已有旧文件)
34513
+ lastCompileSuccess = false;
34514
+ }
34515
+ }
34516
+ else {
34517
+ logger.info('未检测到 src 目录,将监听 src 目录的创建');
34518
+ }
34519
+ // 确保 out 目录存在
34520
+ if (!libExports.existsSync(outDir)) {
34521
+ logger.info('out 目录不存在,创建空的 out 目录');
34522
+ libExports.ensureDirSync(outDir);
34523
+ }
34524
+ // 启动 webpack 开发服务器
34525
+ const webpackProcess = await startWebpackDevServer(outDir, options, logger);
34526
+ const { default: chokidar } = await Promise.resolve().then(function () { return index$1; });
34527
+ // 监听 src 目录下的文件变化(即使目录不存在也可以监听)
34528
+ logger.info(`正在监听 src 目录: ${srcDir}`);
34529
+ const watcher = chokidar.watch(srcDir, {
34530
+ ignored: /(^|[\/\\])\../, // 忽略隐藏文件
34531
+ ignoreInitial: true,
34532
+ persistent: true,
34533
+ awaitWriteFinish: {
34534
+ stabilityThreshold: 100,
34535
+ pollInterval: 10,
34536
+ },
34537
+ });
34538
+ // 只监听 ts/tsx/nasl 文件的变化
34539
+ const shouldHandleFile = (filePath) => {
34540
+ return /\.(ts|tsx|nasl|css)$/.test(filePath);
34541
+ };
34542
+ let isCompiling = false;
34543
+ let pendingCompile = false;
34544
+ const handleFileChange = async (filePath) => {
34545
+ // 过滤非目标文件类型
34546
+ if (!shouldHandleFile(filePath))
34547
+ return;
34548
+ logger.info(`检测到文件变化: ${sysPath.relative(projectRoot, filePath)}`);
34549
+ if (isCompiling) {
34550
+ pendingCompile = true;
34551
+ return;
34552
+ }
34553
+ isCompiling = true;
34554
+ pendingCompile = false;
34555
+ try {
34556
+ logger.newLine();
34557
+ logger.info('开始重新编译...');
34558
+ await compile(entry);
34559
+ logger.success('重新编译成功!');
34560
+ lastCompileSuccess = true;
34561
+ }
34562
+ catch (error) {
34563
+ logger.error(`重新编译失败:${error.message}`);
34564
+ logger.info('继续使用上次成功的编译结果提供服务');
34565
+ // 不重启 webpack,继续使用旧的 out 目录
34566
+ }
34567
+ finally {
34568
+ isCompiling = false;
34569
+ if (pendingCompile) {
34570
+ // 如果在编译期间有新的文件变化,立即处理
34571
+ setTimeout(() => handleFileChange(filePath), 0);
34572
+ }
34573
+ }
34574
+ };
34575
+ watcher.on('change', handleFileChange);
34576
+ watcher.on('add', handleFileChange);
34577
+ watcher.on('unlink', handleFileChange);
34578
+ // 监听 src 目录本身的创建
34579
+ watcher.on('addDir', async (dirPath) => {
34580
+ // 当 src 目录本身被创建时触发编译
34581
+ if (dirPath === srcDir) {
34582
+ logger.info('检测到 src 目录被创建');
34583
+ if (isCompiling) {
34584
+ pendingCompile = true;
34585
+ return;
34586
+ }
34587
+ isCompiling = true;
34588
+ pendingCompile = false;
34589
+ try {
34590
+ logger.newLine();
34591
+ logger.info('开始编译...');
34592
+ await compile(entry);
34593
+ logger.success('编译成功!');
34594
+ lastCompileSuccess = true;
34595
+ }
34596
+ catch (error) {
34597
+ logger.error(`编译失败:${error.message}`);
34598
+ }
34599
+ finally {
34600
+ isCompiling = false;
34601
+ if (pendingCompile) {
34602
+ setTimeout(() => handleFileChange(''), 0);
34603
+ }
34604
+ }
34605
+ }
34606
+ });
34607
+ // 监听 out 目录的删除,以便在 out 目录被删除时重新编译
34608
+ const outWatcher = chokidar.watch(outDir, {
34609
+ ignoreInitial: true,
34610
+ persistent: true,
34611
+ depth: 0, // 只监听 out 目录本身,不监听子目录
34612
+ });
34613
+ outWatcher.on('unlinkDir', async (deletedPath) => {
34614
+ if (deletedPath === outDir) {
34615
+ logger.warn('检测到 out 目录被删除');
34616
+ // 检查是否存在 src 目录
34617
+ const hasSrc = libExports.existsSync(srcDir) && libExports.statSync(srcDir).isDirectory();
34618
+ if (hasSrc) {
34619
+ logger.info('检测到 src 目录存在,开始重新编译...');
34620
+ if (isCompiling) {
34621
+ pendingCompile = true;
34622
+ return;
34623
+ }
34624
+ isCompiling = true;
34625
+ pendingCompile = false;
34626
+ try {
34627
+ // 确保 out 目录存在
34628
+ libExports.ensureDirSync(outDir);
34629
+ await compile(entry);
34630
+ logger.success('重新编译成功!out 目录已恢复');
34631
+ lastCompileSuccess = true;
34632
+ }
34633
+ catch (error) {
34634
+ logger.error(`重新编译失败:${error.message}`);
34635
+ }
34636
+ finally {
34637
+ isCompiling = false;
34638
+ if (pendingCompile) {
34639
+ setTimeout(() => handleFileChange(''), 0);
34640
+ }
34641
+ }
34642
+ }
34643
+ else {
34644
+ logger.warn('未检测到 src 目录,无法重新编译');
34645
+ }
34646
+ }
34647
+ });
34648
+ // 处理进程退出
34649
+ const cleanup = () => {
34650
+ if (webpackProcess) {
34651
+ webpackProcess.kill();
34652
+ }
34653
+ watcher.close().catch(() => { });
34654
+ outWatcher.close().catch(() => { });
34655
+ };
34656
+ process.on('SIGINT', cleanup);
34657
+ process.on('SIGTERM', cleanup);
34467
34658
  }
34468
-
34469
34659
  /**
34470
- * 编译命令 - 将 NASL 编译为 Vue 和 JS
34660
+ * 启动 webpack 开发服务器
34471
34661
  */
34472
- async function dev(entry, options) {
34473
- const logger = options?.logger || defaultLogger;
34474
- const { outDir } = await compile(entry);
34475
- logger.newLine();
34476
- logger.info('正在启动开发服务...');
34477
- const configRelativePath = path$1.relative(outDir, path$1.resolve(__dirname, '../../build/webpack.config.js'));
34662
+ async function startWebpackDevServer(outDir, options, logger) {
34663
+ logger?.newLine();
34664
+ logger?.info('正在启动开发服务...');
34665
+ const configRelativePath = sysPath.relative(outDir, sysPath.resolve(__dirname, '../../build/webpack.config.js'));
34478
34666
  // 构建 webpack-cli 参数
34479
34667
  let webpackArgs = `${require.resolve('.bin/webpack-cli')} serve --config ${configRelativePath}`;
34480
34668
  if (options?.port)
@@ -34485,7 +34673,26 @@ async function dev(entry, options) {
34485
34673
  webpackArgs += ' --open';
34486
34674
  if (options?.hot)
34487
34675
  webpackArgs += ' --hot';
34488
- await justExecCommandSync(webpackArgs, outDir);
34676
+ // 使用 spawn 而不是 spawnSync,以便进程可以常驻
34677
+ const webpackProcess = spawn(webpackArgs, {
34678
+ shell: true,
34679
+ stdio: 'inherit',
34680
+ cwd: outDir,
34681
+ });
34682
+ webpackProcess.on('error', (error) => {
34683
+ logger?.error(`Webpack 开发服务器启动失败: ${error.message}`);
34684
+ process.exit(1);
34685
+ });
34686
+ return webpackProcess;
34687
+ }
34688
+
34689
+ function justExecCommandSync(command, cwd) {
34690
+ console.log(command);
34691
+ const result = spawnSync(command, { shell: true, stdio: 'inherit', cwd });
34692
+ if (result.status) {
34693
+ console.error(String(result.stderr || result.stdout));
34694
+ process.exit(1);
34695
+ }
34489
34696
  }
34490
34697
 
34491
34698
  /**
@@ -34496,12 +34703,1677 @@ async function build(entry, options) {
34496
34703
  const { outDir } = await compile(entry);
34497
34704
  logger.newLine();
34498
34705
  logger.info('正在构建项目...');
34499
- const configRelativePath = path$1.relative(outDir, path$1.resolve(__dirname, '../../build/webpack.config.js'));
34706
+ const configRelativePath = sysPath.relative(outDir, sysPath.resolve(__dirname, '../../build/webpack.config.js'));
34500
34707
  const mode = options?.mode || 'production';
34501
34708
  // 构建 webpack-cli 参数
34502
34709
  let webpackArgs = `${require.resolve('.bin/webpack-cli')} build --config ${configRelativePath} --mode ${mode}`;
34503
34710
  await justExecCommandSync(webpackArgs, outDir);
34504
34711
  }
34505
34712
 
34506
- export { BaseLogger, CONFIG_FILE_NAME, ConsoleLogger, DEFAULT_CONFIG, MemoryLogger, build, check, compile, composeToString, createSorter, defaultLogger, dep, dev, fastLogToFile, init, resolveNASLFiles, scanEntryFiles, scanNASLFiles, sorter, tryCompile };
34713
+ const EntryTypes = {
34714
+ FILE_TYPE: 'files',
34715
+ DIR_TYPE: 'directories',
34716
+ FILE_DIR_TYPE: 'files_directories',
34717
+ EVERYTHING_TYPE: 'all',
34718
+ };
34719
+ const defaultOptions = {
34720
+ root: '.',
34721
+ fileFilter: (_entryInfo) => true,
34722
+ directoryFilter: (_entryInfo) => true,
34723
+ type: EntryTypes.FILE_TYPE,
34724
+ lstat: false,
34725
+ depth: 2147483648,
34726
+ alwaysStat: false,
34727
+ highWaterMark: 4096,
34728
+ };
34729
+ Object.freeze(defaultOptions);
34730
+ const RECURSIVE_ERROR_CODE = 'READDIRP_RECURSIVE_ERROR';
34731
+ const NORMAL_FLOW_ERRORS = new Set(['ENOENT', 'EPERM', 'EACCES', 'ELOOP', RECURSIVE_ERROR_CODE]);
34732
+ const ALL_TYPES = [
34733
+ EntryTypes.DIR_TYPE,
34734
+ EntryTypes.EVERYTHING_TYPE,
34735
+ EntryTypes.FILE_DIR_TYPE,
34736
+ EntryTypes.FILE_TYPE,
34737
+ ];
34738
+ const DIR_TYPES = new Set([
34739
+ EntryTypes.DIR_TYPE,
34740
+ EntryTypes.EVERYTHING_TYPE,
34741
+ EntryTypes.FILE_DIR_TYPE,
34742
+ ]);
34743
+ const FILE_TYPES = new Set([
34744
+ EntryTypes.EVERYTHING_TYPE,
34745
+ EntryTypes.FILE_DIR_TYPE,
34746
+ EntryTypes.FILE_TYPE,
34747
+ ]);
34748
+ const isNormalFlowError = (error) => NORMAL_FLOW_ERRORS.has(error.code);
34749
+ const wantBigintFsStats = process.platform === 'win32';
34750
+ const emptyFn = (_entryInfo) => true;
34751
+ const normalizeFilter = (filter) => {
34752
+ if (filter === undefined)
34753
+ return emptyFn;
34754
+ if (typeof filter === 'function')
34755
+ return filter;
34756
+ if (typeof filter === 'string') {
34757
+ const fl = filter.trim();
34758
+ return (entry) => entry.basename === fl;
34759
+ }
34760
+ if (Array.isArray(filter)) {
34761
+ const trItems = filter.map((item) => item.trim());
34762
+ return (entry) => trItems.some((f) => entry.basename === f);
34763
+ }
34764
+ return emptyFn;
34765
+ };
34766
+ /** Readable readdir stream, emitting new files as they're being listed. */
34767
+ class ReaddirpStream extends Readable$1 {
34768
+ constructor(options = {}) {
34769
+ super({
34770
+ objectMode: true,
34771
+ autoDestroy: true,
34772
+ highWaterMark: options.highWaterMark,
34773
+ });
34774
+ const opts = { ...defaultOptions, ...options };
34775
+ const { root, type } = opts;
34776
+ this._fileFilter = normalizeFilter(opts.fileFilter);
34777
+ this._directoryFilter = normalizeFilter(opts.directoryFilter);
34778
+ const statMethod = opts.lstat ? lstat : stat$1;
34779
+ // Use bigint stats if it's windows and stat() supports options (node 10+).
34780
+ if (wantBigintFsStats) {
34781
+ this._stat = (path) => statMethod(path, { bigint: true });
34782
+ }
34783
+ else {
34784
+ this._stat = statMethod;
34785
+ }
34786
+ this._maxDepth = opts.depth ?? defaultOptions.depth;
34787
+ this._wantsDir = type ? DIR_TYPES.has(type) : false;
34788
+ this._wantsFile = type ? FILE_TYPES.has(type) : false;
34789
+ this._wantsEverything = type === EntryTypes.EVERYTHING_TYPE;
34790
+ this._root = resolve(root);
34791
+ this._isDirent = !opts.alwaysStat;
34792
+ this._statsProp = this._isDirent ? 'dirent' : 'stats';
34793
+ this._rdOptions = { encoding: 'utf8', withFileTypes: this._isDirent };
34794
+ // Launch stream with one parent, the root dir.
34795
+ this.parents = [this._exploreDir(root, 1)];
34796
+ this.reading = false;
34797
+ this.parent = undefined;
34798
+ }
34799
+ async _read(batch) {
34800
+ if (this.reading)
34801
+ return;
34802
+ this.reading = true;
34803
+ try {
34804
+ while (!this.destroyed && batch > 0) {
34805
+ const par = this.parent;
34806
+ const fil = par && par.files;
34807
+ if (fil && fil.length > 0) {
34808
+ const { path, depth } = par;
34809
+ const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent, path));
34810
+ const awaited = await Promise.all(slice);
34811
+ for (const entry of awaited) {
34812
+ if (!entry)
34813
+ continue;
34814
+ if (this.destroyed)
34815
+ return;
34816
+ const entryType = await this._getEntryType(entry);
34817
+ if (entryType === 'directory' && this._directoryFilter(entry)) {
34818
+ if (depth <= this._maxDepth) {
34819
+ this.parents.push(this._exploreDir(entry.fullPath, depth + 1));
34820
+ }
34821
+ if (this._wantsDir) {
34822
+ this.push(entry);
34823
+ batch--;
34824
+ }
34825
+ }
34826
+ else if ((entryType === 'file' || this._includeAsFile(entry)) &&
34827
+ this._fileFilter(entry)) {
34828
+ if (this._wantsFile) {
34829
+ this.push(entry);
34830
+ batch--;
34831
+ }
34832
+ }
34833
+ }
34834
+ }
34835
+ else {
34836
+ const parent = this.parents.pop();
34837
+ if (!parent) {
34838
+ this.push(null);
34839
+ break;
34840
+ }
34841
+ this.parent = await parent;
34842
+ if (this.destroyed)
34843
+ return;
34844
+ }
34845
+ }
34846
+ }
34847
+ catch (error) {
34848
+ this.destroy(error);
34849
+ }
34850
+ finally {
34851
+ this.reading = false;
34852
+ }
34853
+ }
34854
+ async _exploreDir(path, depth) {
34855
+ let files;
34856
+ try {
34857
+ files = await readdir(path, this._rdOptions);
34858
+ }
34859
+ catch (error) {
34860
+ this._onError(error);
34861
+ }
34862
+ return { files, depth, path };
34863
+ }
34864
+ async _formatEntry(dirent, path) {
34865
+ let entry;
34866
+ const basename = this._isDirent ? dirent.name : dirent;
34867
+ try {
34868
+ const fullPath = resolve(join(path, basename));
34869
+ entry = { path: relative(this._root, fullPath), fullPath, basename };
34870
+ entry[this._statsProp] = this._isDirent ? dirent : await this._stat(fullPath);
34871
+ }
34872
+ catch (err) {
34873
+ this._onError(err);
34874
+ return;
34875
+ }
34876
+ return entry;
34877
+ }
34878
+ _onError(err) {
34879
+ if (isNormalFlowError(err) && !this.destroyed) {
34880
+ this.emit('warn', err);
34881
+ }
34882
+ else {
34883
+ this.destroy(err);
34884
+ }
34885
+ }
34886
+ async _getEntryType(entry) {
34887
+ // entry may be undefined, because a warning or an error were emitted
34888
+ // and the statsProp is undefined
34889
+ if (!entry && this._statsProp in entry) {
34890
+ return '';
34891
+ }
34892
+ const stats = entry[this._statsProp];
34893
+ if (stats.isFile())
34894
+ return 'file';
34895
+ if (stats.isDirectory())
34896
+ return 'directory';
34897
+ if (stats && stats.isSymbolicLink()) {
34898
+ const full = entry.fullPath;
34899
+ try {
34900
+ const entryRealPath = await realpath(full);
34901
+ const entryRealPathStats = await lstat(entryRealPath);
34902
+ if (entryRealPathStats.isFile()) {
34903
+ return 'file';
34904
+ }
34905
+ if (entryRealPathStats.isDirectory()) {
34906
+ const len = entryRealPath.length;
34907
+ if (full.startsWith(entryRealPath) && full.substr(len, 1) === sep) {
34908
+ const recursiveError = new Error(`Circular symlink detected: "${full}" points to "${entryRealPath}"`);
34909
+ // @ts-ignore
34910
+ recursiveError.code = RECURSIVE_ERROR_CODE;
34911
+ return this._onError(recursiveError);
34912
+ }
34913
+ return 'directory';
34914
+ }
34915
+ }
34916
+ catch (error) {
34917
+ this._onError(error);
34918
+ return '';
34919
+ }
34920
+ }
34921
+ }
34922
+ _includeAsFile(entry) {
34923
+ const stats = entry && entry[this._statsProp];
34924
+ return stats && this._wantsEverything && !stats.isDirectory();
34925
+ }
34926
+ }
34927
+ /**
34928
+ * Streaming version: Reads all files and directories in given root recursively.
34929
+ * Consumes ~constant small amount of RAM.
34930
+ * @param root Root directory
34931
+ * @param options Options to specify root (start directory), filters and recursion depth
34932
+ */
34933
+ function readdirp(root, options = {}) {
34934
+ // @ts-ignore
34935
+ let type = options.entryType || options.type;
34936
+ if (type === 'both')
34937
+ type = EntryTypes.FILE_DIR_TYPE; // backwards-compatibility
34938
+ if (type)
34939
+ options.type = type;
34940
+ if (!root) {
34941
+ throw new Error('readdirp: root argument is required. Usage: readdirp(root, options)');
34942
+ }
34943
+ else if (typeof root !== 'string') {
34944
+ throw new TypeError('readdirp: root argument must be a string. Usage: readdirp(root, options)');
34945
+ }
34946
+ else if (type && !ALL_TYPES.includes(type)) {
34947
+ throw new Error(`readdirp: Invalid type passed. Use one of ${ALL_TYPES.join(', ')}`);
34948
+ }
34949
+ options.root = root;
34950
+ return new ReaddirpStream(options);
34951
+ }
34952
+
34953
+ const STR_DATA = 'data';
34954
+ const STR_END = 'end';
34955
+ const STR_CLOSE = 'close';
34956
+ const EMPTY_FN = () => { };
34957
+ const pl = process.platform;
34958
+ const isWindows = pl === 'win32';
34959
+ const isMacos = pl === 'darwin';
34960
+ const isLinux = pl === 'linux';
34961
+ const isFreeBSD = pl === 'freebsd';
34962
+ const isIBMi = type$1() === 'OS400';
34963
+ const EVENTS = {
34964
+ ALL: 'all',
34965
+ READY: 'ready',
34966
+ ADD: 'add',
34967
+ CHANGE: 'change',
34968
+ ADD_DIR: 'addDir',
34969
+ UNLINK: 'unlink',
34970
+ UNLINK_DIR: 'unlinkDir',
34971
+ RAW: 'raw',
34972
+ ERROR: 'error',
34973
+ };
34974
+ const EV = EVENTS;
34975
+ const THROTTLE_MODE_WATCH = 'watch';
34976
+ const statMethods = { lstat: lstat$1, stat: stat$2 };
34977
+ const KEY_LISTENERS = 'listeners';
34978
+ const KEY_ERR = 'errHandlers';
34979
+ const KEY_RAW = 'rawEmitters';
34980
+ const HANDLER_KEYS = [KEY_LISTENERS, KEY_ERR, KEY_RAW];
34981
+ // prettier-ignore
34982
+ const binaryExtensions = new Set([
34983
+ '3dm', '3ds', '3g2', '3gp', '7z', 'a', 'aac', 'adp', 'afdesign', 'afphoto', 'afpub', 'ai',
34984
+ 'aif', 'aiff', 'alz', 'ape', 'apk', 'appimage', 'ar', 'arj', 'asf', 'au', 'avi',
34985
+ 'bak', 'baml', 'bh', 'bin', 'bk', 'bmp', 'btif', 'bz2', 'bzip2',
34986
+ 'cab', 'caf', 'cgm', 'class', 'cmx', 'cpio', 'cr2', 'cur', 'dat', 'dcm', 'deb', 'dex', 'djvu',
34987
+ 'dll', 'dmg', 'dng', 'doc', 'docm', 'docx', 'dot', 'dotm', 'dra', 'DS_Store', 'dsk', 'dts',
34988
+ 'dtshd', 'dvb', 'dwg', 'dxf',
34989
+ 'ecelp4800', 'ecelp7470', 'ecelp9600', 'egg', 'eol', 'eot', 'epub', 'exe',
34990
+ 'f4v', 'fbs', 'fh', 'fla', 'flac', 'flatpak', 'fli', 'flv', 'fpx', 'fst', 'fvt',
34991
+ 'g3', 'gh', 'gif', 'graffle', 'gz', 'gzip',
34992
+ 'h261', 'h263', 'h264', 'icns', 'ico', 'ief', 'img', 'ipa', 'iso',
34993
+ 'jar', 'jpeg', 'jpg', 'jpgv', 'jpm', 'jxr', 'key', 'ktx',
34994
+ 'lha', 'lib', 'lvp', 'lz', 'lzh', 'lzma', 'lzo',
34995
+ 'm3u', 'm4a', 'm4v', 'mar', 'mdi', 'mht', 'mid', 'midi', 'mj2', 'mka', 'mkv', 'mmr', 'mng',
34996
+ 'mobi', 'mov', 'movie', 'mp3',
34997
+ 'mp4', 'mp4a', 'mpeg', 'mpg', 'mpga', 'mxu',
34998
+ 'nef', 'npx', 'numbers', 'nupkg',
34999
+ 'o', 'odp', 'ods', 'odt', 'oga', 'ogg', 'ogv', 'otf', 'ott',
35000
+ 'pages', 'pbm', 'pcx', 'pdb', 'pdf', 'pea', 'pgm', 'pic', 'png', 'pnm', 'pot', 'potm',
35001
+ 'potx', 'ppa', 'ppam',
35002
+ 'ppm', 'pps', 'ppsm', 'ppsx', 'ppt', 'pptm', 'pptx', 'psd', 'pya', 'pyc', 'pyo', 'pyv',
35003
+ 'qt',
35004
+ 'rar', 'ras', 'raw', 'resources', 'rgb', 'rip', 'rlc', 'rmf', 'rmvb', 'rpm', 'rtf', 'rz',
35005
+ 's3m', 's7z', 'scpt', 'sgi', 'shar', 'snap', 'sil', 'sketch', 'slk', 'smv', 'snk', 'so',
35006
+ 'stl', 'suo', 'sub', 'swf',
35007
+ 'tar', 'tbz', 'tbz2', 'tga', 'tgz', 'thmx', 'tif', 'tiff', 'tlz', 'ttc', 'ttf', 'txz',
35008
+ 'udf', 'uvh', 'uvi', 'uvm', 'uvp', 'uvs', 'uvu',
35009
+ 'viv', 'vob',
35010
+ 'war', 'wav', 'wax', 'wbmp', 'wdp', 'weba', 'webm', 'webp', 'whl', 'wim', 'wm', 'wma',
35011
+ 'wmv', 'wmx', 'woff', 'woff2', 'wrm', 'wvx',
35012
+ 'xbm', 'xif', 'xla', 'xlam', 'xls', 'xlsb', 'xlsm', 'xlsx', 'xlt', 'xltm', 'xltx', 'xm',
35013
+ 'xmind', 'xpi', 'xpm', 'xwd', 'xz',
35014
+ 'z', 'zip', 'zipx',
35015
+ ]);
35016
+ const isBinaryPath = (filePath) => binaryExtensions.has(sysPath.extname(filePath).slice(1).toLowerCase());
35017
+ // TODO: emit errors properly. Example: EMFILE on Macos.
35018
+ const foreach = (val, fn) => {
35019
+ if (val instanceof Set) {
35020
+ val.forEach(fn);
35021
+ }
35022
+ else {
35023
+ fn(val);
35024
+ }
35025
+ };
35026
+ const addAndConvert = (main, prop, item) => {
35027
+ let container = main[prop];
35028
+ if (!(container instanceof Set)) {
35029
+ main[prop] = container = new Set([container]);
35030
+ }
35031
+ container.add(item);
35032
+ };
35033
+ const clearItem = (cont) => (key) => {
35034
+ const set = cont[key];
35035
+ if (set instanceof Set) {
35036
+ set.clear();
35037
+ }
35038
+ else {
35039
+ delete cont[key];
35040
+ }
35041
+ };
35042
+ const delFromSet = (main, prop, item) => {
35043
+ const container = main[prop];
35044
+ if (container instanceof Set) {
35045
+ container.delete(item);
35046
+ }
35047
+ else if (container === item) {
35048
+ delete main[prop];
35049
+ }
35050
+ };
35051
+ const isEmptySet = (val) => (val instanceof Set ? val.size === 0 : !val);
35052
+ const FsWatchInstances = new Map();
35053
+ /**
35054
+ * Instantiates the fs_watch interface
35055
+ * @param path to be watched
35056
+ * @param options to be passed to fs_watch
35057
+ * @param listener main event handler
35058
+ * @param errHandler emits info about errors
35059
+ * @param emitRaw emits raw event data
35060
+ * @returns {NativeFsWatcher}
35061
+ */
35062
+ function createFsWatchInstance(path, options, listener, errHandler, emitRaw) {
35063
+ const handleEvent = (rawEvent, evPath) => {
35064
+ listener(path);
35065
+ emitRaw(rawEvent, evPath, { watchedPath: path });
35066
+ // emit based on events occurring for files from a directory's watcher in
35067
+ // case the file's watcher misses it (and rely on throttling to de-dupe)
35068
+ if (evPath && path !== evPath) {
35069
+ fsWatchBroadcast(sysPath.resolve(path, evPath), KEY_LISTENERS, sysPath.join(path, evPath));
35070
+ }
35071
+ };
35072
+ try {
35073
+ return watch$1(path, {
35074
+ persistent: options.persistent,
35075
+ }, handleEvent);
35076
+ }
35077
+ catch (error) {
35078
+ errHandler(error);
35079
+ return undefined;
35080
+ }
35081
+ }
35082
+ /**
35083
+ * Helper for passing fs_watch event data to a collection of listeners
35084
+ * @param fullPath absolute path bound to fs_watch instance
35085
+ */
35086
+ const fsWatchBroadcast = (fullPath, listenerType, val1, val2, val3) => {
35087
+ const cont = FsWatchInstances.get(fullPath);
35088
+ if (!cont)
35089
+ return;
35090
+ foreach(cont[listenerType], (listener) => {
35091
+ listener(val1, val2, val3);
35092
+ });
35093
+ };
35094
+ /**
35095
+ * Instantiates the fs_watch interface or binds listeners
35096
+ * to an existing one covering the same file system entry
35097
+ * @param path
35098
+ * @param fullPath absolute path
35099
+ * @param options to be passed to fs_watch
35100
+ * @param handlers container for event listener functions
35101
+ */
35102
+ const setFsWatchListener = (path, fullPath, options, handlers) => {
35103
+ const { listener, errHandler, rawEmitter } = handlers;
35104
+ let cont = FsWatchInstances.get(fullPath);
35105
+ let watcher;
35106
+ if (!options.persistent) {
35107
+ watcher = createFsWatchInstance(path, options, listener, errHandler, rawEmitter);
35108
+ if (!watcher)
35109
+ return;
35110
+ return watcher.close.bind(watcher);
35111
+ }
35112
+ if (cont) {
35113
+ addAndConvert(cont, KEY_LISTENERS, listener);
35114
+ addAndConvert(cont, KEY_ERR, errHandler);
35115
+ addAndConvert(cont, KEY_RAW, rawEmitter);
35116
+ }
35117
+ else {
35118
+ watcher = createFsWatchInstance(path, options, fsWatchBroadcast.bind(null, fullPath, KEY_LISTENERS), errHandler, // no need to use broadcast here
35119
+ fsWatchBroadcast.bind(null, fullPath, KEY_RAW));
35120
+ if (!watcher)
35121
+ return;
35122
+ watcher.on(EV.ERROR, async (error) => {
35123
+ const broadcastErr = fsWatchBroadcast.bind(null, fullPath, KEY_ERR);
35124
+ if (cont)
35125
+ cont.watcherUnusable = true; // documented since Node 10.4.1
35126
+ // Workaround for https://github.com/joyent/node/issues/4337
35127
+ if (isWindows && error.code === 'EPERM') {
35128
+ try {
35129
+ const fd = await open(path, 'r');
35130
+ await fd.close();
35131
+ broadcastErr(error);
35132
+ }
35133
+ catch (err) {
35134
+ // do nothing
35135
+ }
35136
+ }
35137
+ else {
35138
+ broadcastErr(error);
35139
+ }
35140
+ });
35141
+ cont = {
35142
+ listeners: listener,
35143
+ errHandlers: errHandler,
35144
+ rawEmitters: rawEmitter,
35145
+ watcher,
35146
+ };
35147
+ FsWatchInstances.set(fullPath, cont);
35148
+ }
35149
+ // const index = cont.listeners.indexOf(listener);
35150
+ // removes this instance's listeners and closes the underlying fs_watch
35151
+ // instance if there are no more listeners left
35152
+ return () => {
35153
+ delFromSet(cont, KEY_LISTENERS, listener);
35154
+ delFromSet(cont, KEY_ERR, errHandler);
35155
+ delFromSet(cont, KEY_RAW, rawEmitter);
35156
+ if (isEmptySet(cont.listeners)) {
35157
+ // Check to protect against issue gh-730.
35158
+ // if (cont.watcherUnusable) {
35159
+ cont.watcher.close();
35160
+ // }
35161
+ FsWatchInstances.delete(fullPath);
35162
+ HANDLER_KEYS.forEach(clearItem(cont));
35163
+ // @ts-ignore
35164
+ cont.watcher = undefined;
35165
+ Object.freeze(cont);
35166
+ }
35167
+ };
35168
+ };
35169
+ // fs_watchFile helpers
35170
+ // object to hold per-process fs_watchFile instances
35171
+ // (may be shared across chokidar FSWatcher instances)
35172
+ const FsWatchFileInstances = new Map();
35173
+ /**
35174
+ * Instantiates the fs_watchFile interface or binds listeners
35175
+ * to an existing one covering the same file system entry
35176
+ * @param path to be watched
35177
+ * @param fullPath absolute path
35178
+ * @param options options to be passed to fs_watchFile
35179
+ * @param handlers container for event listener functions
35180
+ * @returns closer
35181
+ */
35182
+ const setFsWatchFileListener = (path, fullPath, options, handlers) => {
35183
+ const { listener, rawEmitter } = handlers;
35184
+ let cont = FsWatchFileInstances.get(fullPath);
35185
+ // let listeners = new Set();
35186
+ // let rawEmitters = new Set();
35187
+ const copts = cont && cont.options;
35188
+ if (copts && (copts.persistent < options.persistent || copts.interval > options.interval)) {
35189
+ // "Upgrade" the watcher to persistence or a quicker interval.
35190
+ // This creates some unlikely edge case issues if the user mixes
35191
+ // settings in a very weird way, but solving for those cases
35192
+ // doesn't seem worthwhile for the added complexity.
35193
+ // listeners = cont.listeners;
35194
+ // rawEmitters = cont.rawEmitters;
35195
+ unwatchFile(fullPath);
35196
+ cont = undefined;
35197
+ }
35198
+ if (cont) {
35199
+ addAndConvert(cont, KEY_LISTENERS, listener);
35200
+ addAndConvert(cont, KEY_RAW, rawEmitter);
35201
+ }
35202
+ else {
35203
+ // TODO
35204
+ // listeners.add(listener);
35205
+ // rawEmitters.add(rawEmitter);
35206
+ cont = {
35207
+ listeners: listener,
35208
+ rawEmitters: rawEmitter,
35209
+ options,
35210
+ watcher: watchFile(fullPath, options, (curr, prev) => {
35211
+ foreach(cont.rawEmitters, (rawEmitter) => {
35212
+ rawEmitter(EV.CHANGE, fullPath, { curr, prev });
35213
+ });
35214
+ const currmtime = curr.mtimeMs;
35215
+ if (curr.size !== prev.size || currmtime > prev.mtimeMs || currmtime === 0) {
35216
+ foreach(cont.listeners, (listener) => listener(path, curr));
35217
+ }
35218
+ }),
35219
+ };
35220
+ FsWatchFileInstances.set(fullPath, cont);
35221
+ }
35222
+ // const index = cont.listeners.indexOf(listener);
35223
+ // Removes this instance's listeners and closes the underlying fs_watchFile
35224
+ // instance if there are no more listeners left.
35225
+ return () => {
35226
+ delFromSet(cont, KEY_LISTENERS, listener);
35227
+ delFromSet(cont, KEY_RAW, rawEmitter);
35228
+ if (isEmptySet(cont.listeners)) {
35229
+ FsWatchFileInstances.delete(fullPath);
35230
+ unwatchFile(fullPath);
35231
+ cont.options = cont.watcher = undefined;
35232
+ Object.freeze(cont);
35233
+ }
35234
+ };
35235
+ };
35236
+ /**
35237
+ * @mixin
35238
+ */
35239
+ class NodeFsHandler {
35240
+ constructor(fsW) {
35241
+ this.fsw = fsW;
35242
+ this._boundHandleError = (error) => fsW._handleError(error);
35243
+ }
35244
+ /**
35245
+ * Watch file for changes with fs_watchFile or fs_watch.
35246
+ * @param path to file or dir
35247
+ * @param listener on fs change
35248
+ * @returns closer for the watcher instance
35249
+ */
35250
+ _watchWithNodeFs(path, listener) {
35251
+ const opts = this.fsw.options;
35252
+ const directory = sysPath.dirname(path);
35253
+ const basename = sysPath.basename(path);
35254
+ const parent = this.fsw._getWatchedDir(directory);
35255
+ parent.add(basename);
35256
+ const absolutePath = sysPath.resolve(path);
35257
+ const options = {
35258
+ persistent: opts.persistent,
35259
+ };
35260
+ if (!listener)
35261
+ listener = EMPTY_FN;
35262
+ let closer;
35263
+ if (opts.usePolling) {
35264
+ const enableBin = opts.interval !== opts.binaryInterval;
35265
+ options.interval = enableBin && isBinaryPath(basename) ? opts.binaryInterval : opts.interval;
35266
+ closer = setFsWatchFileListener(path, absolutePath, options, {
35267
+ listener,
35268
+ rawEmitter: this.fsw._emitRaw,
35269
+ });
35270
+ }
35271
+ else {
35272
+ closer = setFsWatchListener(path, absolutePath, options, {
35273
+ listener,
35274
+ errHandler: this._boundHandleError,
35275
+ rawEmitter: this.fsw._emitRaw,
35276
+ });
35277
+ }
35278
+ return closer;
35279
+ }
35280
+ /**
35281
+ * Watch a file and emit add event if warranted.
35282
+ * @returns closer for the watcher instance
35283
+ */
35284
+ _handleFile(file, stats, initialAdd) {
35285
+ if (this.fsw.closed) {
35286
+ return;
35287
+ }
35288
+ const dirname = sysPath.dirname(file);
35289
+ const basename = sysPath.basename(file);
35290
+ const parent = this.fsw._getWatchedDir(dirname);
35291
+ // stats is always present
35292
+ let prevStats = stats;
35293
+ // if the file is already being watched, do nothing
35294
+ if (parent.has(basename))
35295
+ return;
35296
+ const listener = async (path, newStats) => {
35297
+ if (!this.fsw._throttle(THROTTLE_MODE_WATCH, file, 5))
35298
+ return;
35299
+ if (!newStats || newStats.mtimeMs === 0) {
35300
+ try {
35301
+ const newStats = await stat$2(file);
35302
+ if (this.fsw.closed)
35303
+ return;
35304
+ // Check that change event was not fired because of changed only accessTime.
35305
+ const at = newStats.atimeMs;
35306
+ const mt = newStats.mtimeMs;
35307
+ if (!at || at <= mt || mt !== prevStats.mtimeMs) {
35308
+ this.fsw._emit(EV.CHANGE, file, newStats);
35309
+ }
35310
+ if ((isMacos || isLinux || isFreeBSD) && prevStats.ino !== newStats.ino) {
35311
+ this.fsw._closeFile(path);
35312
+ prevStats = newStats;
35313
+ const closer = this._watchWithNodeFs(file, listener);
35314
+ if (closer)
35315
+ this.fsw._addPathCloser(path, closer);
35316
+ }
35317
+ else {
35318
+ prevStats = newStats;
35319
+ }
35320
+ }
35321
+ catch (error) {
35322
+ // Fix issues where mtime is null but file is still present
35323
+ this.fsw._remove(dirname, basename);
35324
+ }
35325
+ // add is about to be emitted if file not already tracked in parent
35326
+ }
35327
+ else if (parent.has(basename)) {
35328
+ // Check that change event was not fired because of changed only accessTime.
35329
+ const at = newStats.atimeMs;
35330
+ const mt = newStats.mtimeMs;
35331
+ if (!at || at <= mt || mt !== prevStats.mtimeMs) {
35332
+ this.fsw._emit(EV.CHANGE, file, newStats);
35333
+ }
35334
+ prevStats = newStats;
35335
+ }
35336
+ };
35337
+ // kick off the watcher
35338
+ const closer = this._watchWithNodeFs(file, listener);
35339
+ // emit an add event if we're supposed to
35340
+ if (!(initialAdd && this.fsw.options.ignoreInitial) && this.fsw._isntIgnored(file)) {
35341
+ if (!this.fsw._throttle(EV.ADD, file, 0))
35342
+ return;
35343
+ this.fsw._emit(EV.ADD, file, stats);
35344
+ }
35345
+ return closer;
35346
+ }
35347
+ /**
35348
+ * Handle symlinks encountered while reading a dir.
35349
+ * @param entry returned by readdirp
35350
+ * @param directory path of dir being read
35351
+ * @param path of this item
35352
+ * @param item basename of this item
35353
+ * @returns true if no more processing is needed for this entry.
35354
+ */
35355
+ async _handleSymlink(entry, directory, path, item) {
35356
+ if (this.fsw.closed) {
35357
+ return;
35358
+ }
35359
+ const full = entry.fullPath;
35360
+ const dir = this.fsw._getWatchedDir(directory);
35361
+ if (!this.fsw.options.followSymlinks) {
35362
+ // watch symlink directly (don't follow) and detect changes
35363
+ this.fsw._incrReadyCount();
35364
+ let linkPath;
35365
+ try {
35366
+ linkPath = await realpath$1(path);
35367
+ }
35368
+ catch (e) {
35369
+ this.fsw._emitReady();
35370
+ return true;
35371
+ }
35372
+ if (this.fsw.closed)
35373
+ return;
35374
+ if (dir.has(item)) {
35375
+ if (this.fsw._symlinkPaths.get(full) !== linkPath) {
35376
+ this.fsw._symlinkPaths.set(full, linkPath);
35377
+ this.fsw._emit(EV.CHANGE, path, entry.stats);
35378
+ }
35379
+ }
35380
+ else {
35381
+ dir.add(item);
35382
+ this.fsw._symlinkPaths.set(full, linkPath);
35383
+ this.fsw._emit(EV.ADD, path, entry.stats);
35384
+ }
35385
+ this.fsw._emitReady();
35386
+ return true;
35387
+ }
35388
+ // don't follow the same symlink more than once
35389
+ if (this.fsw._symlinkPaths.has(full)) {
35390
+ return true;
35391
+ }
35392
+ this.fsw._symlinkPaths.set(full, true);
35393
+ }
35394
+ _handleRead(directory, initialAdd, wh, target, dir, depth, throttler) {
35395
+ // Normalize the directory name on Windows
35396
+ directory = sysPath.join(directory, '');
35397
+ throttler = this.fsw._throttle('readdir', directory, 1000);
35398
+ if (!throttler)
35399
+ return;
35400
+ const previous = this.fsw._getWatchedDir(wh.path);
35401
+ const current = new Set();
35402
+ let stream = this.fsw._readdirp(directory, {
35403
+ fileFilter: (entry) => wh.filterPath(entry),
35404
+ directoryFilter: (entry) => wh.filterDir(entry),
35405
+ });
35406
+ if (!stream)
35407
+ return;
35408
+ stream
35409
+ .on(STR_DATA, async (entry) => {
35410
+ if (this.fsw.closed) {
35411
+ stream = undefined;
35412
+ return;
35413
+ }
35414
+ const item = entry.path;
35415
+ let path = sysPath.join(directory, item);
35416
+ current.add(item);
35417
+ if (entry.stats.isSymbolicLink() &&
35418
+ (await this._handleSymlink(entry, directory, path, item))) {
35419
+ return;
35420
+ }
35421
+ if (this.fsw.closed) {
35422
+ stream = undefined;
35423
+ return;
35424
+ }
35425
+ // Files that present in current directory snapshot
35426
+ // but absent in previous are added to watch list and
35427
+ // emit `add` event.
35428
+ if (item === target || (!target && !previous.has(item))) {
35429
+ this.fsw._incrReadyCount();
35430
+ // ensure relativeness of path is preserved in case of watcher reuse
35431
+ path = sysPath.join(dir, sysPath.relative(dir, path));
35432
+ this._addToNodeFs(path, initialAdd, wh, depth + 1);
35433
+ }
35434
+ })
35435
+ .on(EV.ERROR, this._boundHandleError);
35436
+ return new Promise((resolve, reject) => {
35437
+ if (!stream)
35438
+ return reject();
35439
+ stream.once(STR_END, () => {
35440
+ if (this.fsw.closed) {
35441
+ stream = undefined;
35442
+ return;
35443
+ }
35444
+ const wasThrottled = throttler ? throttler.clear() : false;
35445
+ resolve(undefined);
35446
+ // Files that absent in current directory snapshot
35447
+ // but present in previous emit `remove` event
35448
+ // and are removed from @watched[directory].
35449
+ previous
35450
+ .getChildren()
35451
+ .filter((item) => {
35452
+ return item !== directory && !current.has(item);
35453
+ })
35454
+ .forEach((item) => {
35455
+ this.fsw._remove(directory, item);
35456
+ });
35457
+ stream = undefined;
35458
+ // one more time for any missed in case changes came in extremely quickly
35459
+ if (wasThrottled)
35460
+ this._handleRead(directory, false, wh, target, dir, depth, throttler);
35461
+ });
35462
+ });
35463
+ }
35464
+ /**
35465
+ * Read directory to add / remove files from `@watched` list and re-read it on change.
35466
+ * @param dir fs path
35467
+ * @param stats
35468
+ * @param initialAdd
35469
+ * @param depth relative to user-supplied path
35470
+ * @param target child path targeted for watch
35471
+ * @param wh Common watch helpers for this path
35472
+ * @param realpath
35473
+ * @returns closer for the watcher instance.
35474
+ */
35475
+ async _handleDir(dir, stats, initialAdd, depth, target, wh, realpath) {
35476
+ const parentDir = this.fsw._getWatchedDir(sysPath.dirname(dir));
35477
+ const tracked = parentDir.has(sysPath.basename(dir));
35478
+ if (!(initialAdd && this.fsw.options.ignoreInitial) && !target && !tracked) {
35479
+ this.fsw._emit(EV.ADD_DIR, dir, stats);
35480
+ }
35481
+ // ensure dir is tracked (harmless if redundant)
35482
+ parentDir.add(sysPath.basename(dir));
35483
+ this.fsw._getWatchedDir(dir);
35484
+ let throttler;
35485
+ let closer;
35486
+ const oDepth = this.fsw.options.depth;
35487
+ if ((oDepth == null || depth <= oDepth) && !this.fsw._symlinkPaths.has(realpath)) {
35488
+ if (!target) {
35489
+ await this._handleRead(dir, initialAdd, wh, target, dir, depth, throttler);
35490
+ if (this.fsw.closed)
35491
+ return;
35492
+ }
35493
+ closer = this._watchWithNodeFs(dir, (dirPath, stats) => {
35494
+ // if current directory is removed, do nothing
35495
+ if (stats && stats.mtimeMs === 0)
35496
+ return;
35497
+ this._handleRead(dirPath, false, wh, target, dir, depth, throttler);
35498
+ });
35499
+ }
35500
+ return closer;
35501
+ }
35502
+ /**
35503
+ * Handle added file, directory, or glob pattern.
35504
+ * Delegates call to _handleFile / _handleDir after checks.
35505
+ * @param path to file or ir
35506
+ * @param initialAdd was the file added at watch instantiation?
35507
+ * @param priorWh depth relative to user-supplied path
35508
+ * @param depth Child path actually targeted for watch
35509
+ * @param target Child path actually targeted for watch
35510
+ */
35511
+ async _addToNodeFs(path, initialAdd, priorWh, depth, target) {
35512
+ const ready = this.fsw._emitReady;
35513
+ if (this.fsw._isIgnored(path) || this.fsw.closed) {
35514
+ ready();
35515
+ return false;
35516
+ }
35517
+ const wh = this.fsw._getWatchHelpers(path);
35518
+ if (priorWh) {
35519
+ wh.filterPath = (entry) => priorWh.filterPath(entry);
35520
+ wh.filterDir = (entry) => priorWh.filterDir(entry);
35521
+ }
35522
+ // evaluate what is at the path we're being asked to watch
35523
+ try {
35524
+ const stats = await statMethods[wh.statMethod](wh.watchPath);
35525
+ if (this.fsw.closed)
35526
+ return;
35527
+ if (this.fsw._isIgnored(wh.watchPath, stats)) {
35528
+ ready();
35529
+ return false;
35530
+ }
35531
+ const follow = this.fsw.options.followSymlinks;
35532
+ let closer;
35533
+ if (stats.isDirectory()) {
35534
+ const absPath = sysPath.resolve(path);
35535
+ const targetPath = follow ? await realpath$1(path) : path;
35536
+ if (this.fsw.closed)
35537
+ return;
35538
+ closer = await this._handleDir(wh.watchPath, stats, initialAdd, depth, target, wh, targetPath);
35539
+ if (this.fsw.closed)
35540
+ return;
35541
+ // preserve this symlink's target path
35542
+ if (absPath !== targetPath && targetPath !== undefined) {
35543
+ this.fsw._symlinkPaths.set(absPath, targetPath);
35544
+ }
35545
+ }
35546
+ else if (stats.isSymbolicLink()) {
35547
+ const targetPath = follow ? await realpath$1(path) : path;
35548
+ if (this.fsw.closed)
35549
+ return;
35550
+ const parent = sysPath.dirname(wh.watchPath);
35551
+ this.fsw._getWatchedDir(parent).add(wh.watchPath);
35552
+ this.fsw._emit(EV.ADD, wh.watchPath, stats);
35553
+ closer = await this._handleDir(parent, stats, initialAdd, depth, path, wh, targetPath);
35554
+ if (this.fsw.closed)
35555
+ return;
35556
+ // preserve this symlink's target path
35557
+ if (targetPath !== undefined) {
35558
+ this.fsw._symlinkPaths.set(sysPath.resolve(path), targetPath);
35559
+ }
35560
+ }
35561
+ else {
35562
+ closer = this._handleFile(wh.watchPath, stats, initialAdd);
35563
+ }
35564
+ ready();
35565
+ if (closer)
35566
+ this.fsw._addPathCloser(path, closer);
35567
+ return false;
35568
+ }
35569
+ catch (error) {
35570
+ if (this.fsw._handleError(error)) {
35571
+ ready();
35572
+ return path;
35573
+ }
35574
+ }
35575
+ }
35576
+ }
35577
+
35578
+ /*! chokidar - MIT License (c) 2012 Paul Miller (paulmillr.com) */
35579
+ const SLASH = '/';
35580
+ const SLASH_SLASH = '//';
35581
+ const ONE_DOT = '.';
35582
+ const TWO_DOTS = '..';
35583
+ const STRING_TYPE = 'string';
35584
+ const BACK_SLASH_RE = /\\/g;
35585
+ const DOUBLE_SLASH_RE = /\/\//;
35586
+ const DOT_RE = /\..*\.(sw[px])$|~$|\.subl.*\.tmp/;
35587
+ const REPLACER_RE = /^\.[/\\]/;
35588
+ function arrify(item) {
35589
+ return Array.isArray(item) ? item : [item];
35590
+ }
35591
+ const isMatcherObject = (matcher) => typeof matcher === 'object' && matcher !== null && !(matcher instanceof RegExp);
35592
+ function createPattern(matcher) {
35593
+ if (typeof matcher === 'function')
35594
+ return matcher;
35595
+ if (typeof matcher === 'string')
35596
+ return (string) => matcher === string;
35597
+ if (matcher instanceof RegExp)
35598
+ return (string) => matcher.test(string);
35599
+ if (typeof matcher === 'object' && matcher !== null) {
35600
+ return (string) => {
35601
+ if (matcher.path === string)
35602
+ return true;
35603
+ if (matcher.recursive) {
35604
+ const relative = sysPath.relative(matcher.path, string);
35605
+ if (!relative) {
35606
+ return false;
35607
+ }
35608
+ return !relative.startsWith('..') && !sysPath.isAbsolute(relative);
35609
+ }
35610
+ return false;
35611
+ };
35612
+ }
35613
+ return () => false;
35614
+ }
35615
+ function normalizePath(path) {
35616
+ if (typeof path !== 'string')
35617
+ throw new Error('string expected');
35618
+ path = sysPath.normalize(path);
35619
+ path = path.replace(/\\/g, '/');
35620
+ let prepend = false;
35621
+ if (path.startsWith('//'))
35622
+ prepend = true;
35623
+ const DOUBLE_SLASH_RE = /\/\//;
35624
+ while (path.match(DOUBLE_SLASH_RE))
35625
+ path = path.replace(DOUBLE_SLASH_RE, '/');
35626
+ if (prepend)
35627
+ path = '/' + path;
35628
+ return path;
35629
+ }
35630
+ function matchPatterns(patterns, testString, stats) {
35631
+ const path = normalizePath(testString);
35632
+ for (let index = 0; index < patterns.length; index++) {
35633
+ const pattern = patterns[index];
35634
+ if (pattern(path, stats)) {
35635
+ return true;
35636
+ }
35637
+ }
35638
+ return false;
35639
+ }
35640
+ function anymatch(matchers, testString) {
35641
+ if (matchers == null) {
35642
+ throw new TypeError('anymatch: specify first argument');
35643
+ }
35644
+ // Early cache for matchers.
35645
+ const matchersArray = arrify(matchers);
35646
+ const patterns = matchersArray.map((matcher) => createPattern(matcher));
35647
+ {
35648
+ return (testString, stats) => {
35649
+ return matchPatterns(patterns, testString, stats);
35650
+ };
35651
+ }
35652
+ }
35653
+ const unifyPaths = (paths_) => {
35654
+ const paths = arrify(paths_).flat();
35655
+ if (!paths.every((p) => typeof p === STRING_TYPE)) {
35656
+ throw new TypeError(`Non-string provided as watch path: ${paths}`);
35657
+ }
35658
+ return paths.map(normalizePathToUnix);
35659
+ };
35660
+ // If SLASH_SLASH occurs at the beginning of path, it is not replaced
35661
+ // because "//StoragePC/DrivePool/Movies" is a valid network path
35662
+ const toUnix = (string) => {
35663
+ let str = string.replace(BACK_SLASH_RE, SLASH);
35664
+ let prepend = false;
35665
+ if (str.startsWith(SLASH_SLASH)) {
35666
+ prepend = true;
35667
+ }
35668
+ while (str.match(DOUBLE_SLASH_RE)) {
35669
+ str = str.replace(DOUBLE_SLASH_RE, SLASH);
35670
+ }
35671
+ if (prepend) {
35672
+ str = SLASH + str;
35673
+ }
35674
+ return str;
35675
+ };
35676
+ // Our version of upath.normalize
35677
+ // TODO: this is not equal to path-normalize module - investigate why
35678
+ const normalizePathToUnix = (path) => toUnix(sysPath.normalize(toUnix(path)));
35679
+ // TODO: refactor
35680
+ const normalizeIgnored = (cwd = '') => (path) => {
35681
+ if (typeof path === 'string') {
35682
+ return normalizePathToUnix(sysPath.isAbsolute(path) ? path : sysPath.join(cwd, path));
35683
+ }
35684
+ else {
35685
+ return path;
35686
+ }
35687
+ };
35688
+ const getAbsolutePath = (path, cwd) => {
35689
+ if (sysPath.isAbsolute(path)) {
35690
+ return path;
35691
+ }
35692
+ return sysPath.join(cwd, path);
35693
+ };
35694
+ const EMPTY_SET = Object.freeze(new Set());
35695
+ /**
35696
+ * Directory entry.
35697
+ */
35698
+ class DirEntry {
35699
+ constructor(dir, removeWatcher) {
35700
+ this.path = dir;
35701
+ this._removeWatcher = removeWatcher;
35702
+ this.items = new Set();
35703
+ }
35704
+ add(item) {
35705
+ const { items } = this;
35706
+ if (!items)
35707
+ return;
35708
+ if (item !== ONE_DOT && item !== TWO_DOTS)
35709
+ items.add(item);
35710
+ }
35711
+ async remove(item) {
35712
+ const { items } = this;
35713
+ if (!items)
35714
+ return;
35715
+ items.delete(item);
35716
+ if (items.size > 0)
35717
+ return;
35718
+ const dir = this.path;
35719
+ try {
35720
+ await readdir$1(dir);
35721
+ }
35722
+ catch (err) {
35723
+ if (this._removeWatcher) {
35724
+ this._removeWatcher(sysPath.dirname(dir), sysPath.basename(dir));
35725
+ }
35726
+ }
35727
+ }
35728
+ has(item) {
35729
+ const { items } = this;
35730
+ if (!items)
35731
+ return;
35732
+ return items.has(item);
35733
+ }
35734
+ getChildren() {
35735
+ const { items } = this;
35736
+ if (!items)
35737
+ return [];
35738
+ return [...items.values()];
35739
+ }
35740
+ dispose() {
35741
+ this.items.clear();
35742
+ this.path = '';
35743
+ this._removeWatcher = EMPTY_FN;
35744
+ this.items = EMPTY_SET;
35745
+ Object.freeze(this);
35746
+ }
35747
+ }
35748
+ const STAT_METHOD_F = 'stat';
35749
+ const STAT_METHOD_L = 'lstat';
35750
+ class WatchHelper {
35751
+ constructor(path, follow, fsw) {
35752
+ this.fsw = fsw;
35753
+ const watchPath = path;
35754
+ this.path = path = path.replace(REPLACER_RE, '');
35755
+ this.watchPath = watchPath;
35756
+ this.fullWatchPath = sysPath.resolve(watchPath);
35757
+ this.dirParts = [];
35758
+ this.dirParts.forEach((parts) => {
35759
+ if (parts.length > 1)
35760
+ parts.pop();
35761
+ });
35762
+ this.followSymlinks = follow;
35763
+ this.statMethod = follow ? STAT_METHOD_F : STAT_METHOD_L;
35764
+ }
35765
+ entryPath(entry) {
35766
+ return sysPath.join(this.watchPath, sysPath.relative(this.watchPath, entry.fullPath));
35767
+ }
35768
+ filterPath(entry) {
35769
+ const { stats } = entry;
35770
+ if (stats && stats.isSymbolicLink())
35771
+ return this.filterDir(entry);
35772
+ const resolvedPath = this.entryPath(entry);
35773
+ // TODO: what if stats is undefined? remove !
35774
+ return this.fsw._isntIgnored(resolvedPath, stats) && this.fsw._hasReadPermissions(stats);
35775
+ }
35776
+ filterDir(entry) {
35777
+ return this.fsw._isntIgnored(this.entryPath(entry), entry.stats);
35778
+ }
35779
+ }
35780
+ /**
35781
+ * Watches files & directories for changes. Emitted events:
35782
+ * `add`, `addDir`, `change`, `unlink`, `unlinkDir`, `all`, `error`
35783
+ *
35784
+ * new FSWatcher()
35785
+ * .add(directories)
35786
+ * .on('add', path => log('File', path, 'was added'))
35787
+ */
35788
+ class FSWatcher extends EventEmitter {
35789
+ // Not indenting methods for history sake; for now.
35790
+ constructor(_opts = {}) {
35791
+ super();
35792
+ this.closed = false;
35793
+ this._closers = new Map();
35794
+ this._ignoredPaths = new Set();
35795
+ this._throttled = new Map();
35796
+ this._streams = new Set();
35797
+ this._symlinkPaths = new Map();
35798
+ this._watched = new Map();
35799
+ this._pendingWrites = new Map();
35800
+ this._pendingUnlinks = new Map();
35801
+ this._readyCount = 0;
35802
+ this._readyEmitted = false;
35803
+ const awf = _opts.awaitWriteFinish;
35804
+ const DEF_AWF = { stabilityThreshold: 2000, pollInterval: 100 };
35805
+ const opts = {
35806
+ // Defaults
35807
+ persistent: true,
35808
+ ignoreInitial: false,
35809
+ ignorePermissionErrors: false,
35810
+ interval: 100,
35811
+ binaryInterval: 300,
35812
+ followSymlinks: true,
35813
+ usePolling: false,
35814
+ // useAsync: false,
35815
+ atomic: true, // NOTE: overwritten later (depends on usePolling)
35816
+ ..._opts,
35817
+ // Change format
35818
+ ignored: _opts.ignored ? arrify(_opts.ignored) : arrify([]),
35819
+ awaitWriteFinish: awf === true ? DEF_AWF : typeof awf === 'object' ? { ...DEF_AWF, ...awf } : false,
35820
+ };
35821
+ // Always default to polling on IBM i because fs.watch() is not available on IBM i.
35822
+ if (isIBMi)
35823
+ opts.usePolling = true;
35824
+ // Editor atomic write normalization enabled by default with fs.watch
35825
+ if (opts.atomic === undefined)
35826
+ opts.atomic = !opts.usePolling;
35827
+ // opts.atomic = typeof _opts.atomic === 'number' ? _opts.atomic : 100;
35828
+ // Global override. Useful for developers, who need to force polling for all
35829
+ // instances of chokidar, regardless of usage / dependency depth
35830
+ const envPoll = process.env.CHOKIDAR_USEPOLLING;
35831
+ if (envPoll !== undefined) {
35832
+ const envLower = envPoll.toLowerCase();
35833
+ if (envLower === 'false' || envLower === '0')
35834
+ opts.usePolling = false;
35835
+ else if (envLower === 'true' || envLower === '1')
35836
+ opts.usePolling = true;
35837
+ else
35838
+ opts.usePolling = !!envLower;
35839
+ }
35840
+ const envInterval = process.env.CHOKIDAR_INTERVAL;
35841
+ if (envInterval)
35842
+ opts.interval = Number.parseInt(envInterval, 10);
35843
+ // This is done to emit ready only once, but each 'add' will increase that?
35844
+ let readyCalls = 0;
35845
+ this._emitReady = () => {
35846
+ readyCalls++;
35847
+ if (readyCalls >= this._readyCount) {
35848
+ this._emitReady = EMPTY_FN;
35849
+ this._readyEmitted = true;
35850
+ // use process.nextTick to allow time for listener to be bound
35851
+ process.nextTick(() => this.emit(EVENTS.READY));
35852
+ }
35853
+ };
35854
+ this._emitRaw = (...args) => this.emit(EVENTS.RAW, ...args);
35855
+ this._boundRemove = this._remove.bind(this);
35856
+ this.options = opts;
35857
+ this._nodeFsHandler = new NodeFsHandler(this);
35858
+ // You’re frozen when your heart’s not open.
35859
+ Object.freeze(opts);
35860
+ }
35861
+ _addIgnoredPath(matcher) {
35862
+ if (isMatcherObject(matcher)) {
35863
+ // return early if we already have a deeply equal matcher object
35864
+ for (const ignored of this._ignoredPaths) {
35865
+ if (isMatcherObject(ignored) &&
35866
+ ignored.path === matcher.path &&
35867
+ ignored.recursive === matcher.recursive) {
35868
+ return;
35869
+ }
35870
+ }
35871
+ }
35872
+ this._ignoredPaths.add(matcher);
35873
+ }
35874
+ _removeIgnoredPath(matcher) {
35875
+ this._ignoredPaths.delete(matcher);
35876
+ // now find any matcher objects with the matcher as path
35877
+ if (typeof matcher === 'string') {
35878
+ for (const ignored of this._ignoredPaths) {
35879
+ // TODO (43081j): make this more efficient.
35880
+ // probably just make a `this._ignoredDirectories` or some
35881
+ // such thing.
35882
+ if (isMatcherObject(ignored) && ignored.path === matcher) {
35883
+ this._ignoredPaths.delete(ignored);
35884
+ }
35885
+ }
35886
+ }
35887
+ }
35888
+ // Public methods
35889
+ /**
35890
+ * Adds paths to be watched on an existing FSWatcher instance.
35891
+ * @param paths_ file or file list. Other arguments are unused
35892
+ */
35893
+ add(paths_, _origAdd, _internal) {
35894
+ const { cwd } = this.options;
35895
+ this.closed = false;
35896
+ this._closePromise = undefined;
35897
+ let paths = unifyPaths(paths_);
35898
+ if (cwd) {
35899
+ paths = paths.map((path) => {
35900
+ const absPath = getAbsolutePath(path, cwd);
35901
+ // Check `path` instead of `absPath` because the cwd portion can't be a glob
35902
+ return absPath;
35903
+ });
35904
+ }
35905
+ paths.forEach((path) => {
35906
+ this._removeIgnoredPath(path);
35907
+ });
35908
+ this._userIgnored = undefined;
35909
+ if (!this._readyCount)
35910
+ this._readyCount = 0;
35911
+ this._readyCount += paths.length;
35912
+ Promise.all(paths.map(async (path) => {
35913
+ const res = await this._nodeFsHandler._addToNodeFs(path, !_internal, undefined, 0, _origAdd);
35914
+ if (res)
35915
+ this._emitReady();
35916
+ return res;
35917
+ })).then((results) => {
35918
+ if (this.closed)
35919
+ return;
35920
+ results.forEach((item) => {
35921
+ if (item)
35922
+ this.add(sysPath.dirname(item), sysPath.basename(_origAdd || item));
35923
+ });
35924
+ });
35925
+ return this;
35926
+ }
35927
+ /**
35928
+ * Close watchers or start ignoring events from specified paths.
35929
+ */
35930
+ unwatch(paths_) {
35931
+ if (this.closed)
35932
+ return this;
35933
+ const paths = unifyPaths(paths_);
35934
+ const { cwd } = this.options;
35935
+ paths.forEach((path) => {
35936
+ // convert to absolute path unless relative path already matches
35937
+ if (!sysPath.isAbsolute(path) && !this._closers.has(path)) {
35938
+ if (cwd)
35939
+ path = sysPath.join(cwd, path);
35940
+ path = sysPath.resolve(path);
35941
+ }
35942
+ this._closePath(path);
35943
+ this._addIgnoredPath(path);
35944
+ if (this._watched.has(path)) {
35945
+ this._addIgnoredPath({
35946
+ path,
35947
+ recursive: true,
35948
+ });
35949
+ }
35950
+ // reset the cached userIgnored anymatch fn
35951
+ // to make ignoredPaths changes effective
35952
+ this._userIgnored = undefined;
35953
+ });
35954
+ return this;
35955
+ }
35956
+ /**
35957
+ * Close watchers and remove all listeners from watched paths.
35958
+ */
35959
+ close() {
35960
+ if (this._closePromise) {
35961
+ return this._closePromise;
35962
+ }
35963
+ this.closed = true;
35964
+ // Memory management.
35965
+ this.removeAllListeners();
35966
+ const closers = [];
35967
+ this._closers.forEach((closerList) => closerList.forEach((closer) => {
35968
+ const promise = closer();
35969
+ if (promise instanceof Promise)
35970
+ closers.push(promise);
35971
+ }));
35972
+ this._streams.forEach((stream) => stream.destroy());
35973
+ this._userIgnored = undefined;
35974
+ this._readyCount = 0;
35975
+ this._readyEmitted = false;
35976
+ this._watched.forEach((dirent) => dirent.dispose());
35977
+ this._closers.clear();
35978
+ this._watched.clear();
35979
+ this._streams.clear();
35980
+ this._symlinkPaths.clear();
35981
+ this._throttled.clear();
35982
+ this._closePromise = closers.length
35983
+ ? Promise.all(closers).then(() => undefined)
35984
+ : Promise.resolve();
35985
+ return this._closePromise;
35986
+ }
35987
+ /**
35988
+ * Expose list of watched paths
35989
+ * @returns for chaining
35990
+ */
35991
+ getWatched() {
35992
+ const watchList = {};
35993
+ this._watched.forEach((entry, dir) => {
35994
+ const key = this.options.cwd ? sysPath.relative(this.options.cwd, dir) : dir;
35995
+ const index = key || ONE_DOT;
35996
+ watchList[index] = entry.getChildren().sort();
35997
+ });
35998
+ return watchList;
35999
+ }
36000
+ emitWithAll(event, args) {
36001
+ this.emit(event, ...args);
36002
+ if (event !== EVENTS.ERROR)
36003
+ this.emit(EVENTS.ALL, event, ...args);
36004
+ }
36005
+ // Common helpers
36006
+ // --------------
36007
+ /**
36008
+ * Normalize and emit events.
36009
+ * Calling _emit DOES NOT MEAN emit() would be called!
36010
+ * @param event Type of event
36011
+ * @param path File or directory path
36012
+ * @param stats arguments to be passed with event
36013
+ * @returns the error if defined, otherwise the value of the FSWatcher instance's `closed` flag
36014
+ */
36015
+ async _emit(event, path, stats) {
36016
+ if (this.closed)
36017
+ return;
36018
+ const opts = this.options;
36019
+ if (isWindows)
36020
+ path = sysPath.normalize(path);
36021
+ if (opts.cwd)
36022
+ path = sysPath.relative(opts.cwd, path);
36023
+ const args = [path];
36024
+ if (stats != null)
36025
+ args.push(stats);
36026
+ const awf = opts.awaitWriteFinish;
36027
+ let pw;
36028
+ if (awf && (pw = this._pendingWrites.get(path))) {
36029
+ pw.lastChange = new Date();
36030
+ return this;
36031
+ }
36032
+ if (opts.atomic) {
36033
+ if (event === EVENTS.UNLINK) {
36034
+ this._pendingUnlinks.set(path, [event, ...args]);
36035
+ setTimeout(() => {
36036
+ this._pendingUnlinks.forEach((entry, path) => {
36037
+ this.emit(...entry);
36038
+ this.emit(EVENTS.ALL, ...entry);
36039
+ this._pendingUnlinks.delete(path);
36040
+ });
36041
+ }, typeof opts.atomic === 'number' ? opts.atomic : 100);
36042
+ return this;
36043
+ }
36044
+ if (event === EVENTS.ADD && this._pendingUnlinks.has(path)) {
36045
+ event = EVENTS.CHANGE;
36046
+ this._pendingUnlinks.delete(path);
36047
+ }
36048
+ }
36049
+ if (awf && (event === EVENTS.ADD || event === EVENTS.CHANGE) && this._readyEmitted) {
36050
+ const awfEmit = (err, stats) => {
36051
+ if (err) {
36052
+ event = EVENTS.ERROR;
36053
+ args[0] = err;
36054
+ this.emitWithAll(event, args);
36055
+ }
36056
+ else if (stats) {
36057
+ // if stats doesn't exist the file must have been deleted
36058
+ if (args.length > 1) {
36059
+ args[1] = stats;
36060
+ }
36061
+ else {
36062
+ args.push(stats);
36063
+ }
36064
+ this.emitWithAll(event, args);
36065
+ }
36066
+ };
36067
+ this._awaitWriteFinish(path, awf.stabilityThreshold, event, awfEmit);
36068
+ return this;
36069
+ }
36070
+ if (event === EVENTS.CHANGE) {
36071
+ const isThrottled = !this._throttle(EVENTS.CHANGE, path, 50);
36072
+ if (isThrottled)
36073
+ return this;
36074
+ }
36075
+ if (opts.alwaysStat &&
36076
+ stats === undefined &&
36077
+ (event === EVENTS.ADD || event === EVENTS.ADD_DIR || event === EVENTS.CHANGE)) {
36078
+ const fullPath = opts.cwd ? sysPath.join(opts.cwd, path) : path;
36079
+ let stats;
36080
+ try {
36081
+ stats = await stat$2(fullPath);
36082
+ }
36083
+ catch (err) {
36084
+ // do nothing
36085
+ }
36086
+ // Suppress event when fs_stat fails, to avoid sending undefined 'stat'
36087
+ if (!stats || this.closed)
36088
+ return;
36089
+ args.push(stats);
36090
+ }
36091
+ this.emitWithAll(event, args);
36092
+ return this;
36093
+ }
36094
+ /**
36095
+ * Common handler for errors
36096
+ * @returns The error if defined, otherwise the value of the FSWatcher instance's `closed` flag
36097
+ */
36098
+ _handleError(error) {
36099
+ const code = error && error.code;
36100
+ if (error &&
36101
+ code !== 'ENOENT' &&
36102
+ code !== 'ENOTDIR' &&
36103
+ (!this.options.ignorePermissionErrors || (code !== 'EPERM' && code !== 'EACCES'))) {
36104
+ this.emit(EVENTS.ERROR, error);
36105
+ }
36106
+ return error || this.closed;
36107
+ }
36108
+ /**
36109
+ * Helper utility for throttling
36110
+ * @param actionType type being throttled
36111
+ * @param path being acted upon
36112
+ * @param timeout duration of time to suppress duplicate actions
36113
+ * @returns tracking object or false if action should be suppressed
36114
+ */
36115
+ _throttle(actionType, path, timeout) {
36116
+ if (!this._throttled.has(actionType)) {
36117
+ this._throttled.set(actionType, new Map());
36118
+ }
36119
+ const action = this._throttled.get(actionType);
36120
+ if (!action)
36121
+ throw new Error('invalid throttle');
36122
+ const actionPath = action.get(path);
36123
+ if (actionPath) {
36124
+ actionPath.count++;
36125
+ return false;
36126
+ }
36127
+ // eslint-disable-next-line prefer-const
36128
+ let timeoutObject;
36129
+ const clear = () => {
36130
+ const item = action.get(path);
36131
+ const count = item ? item.count : 0;
36132
+ action.delete(path);
36133
+ clearTimeout(timeoutObject);
36134
+ if (item)
36135
+ clearTimeout(item.timeoutObject);
36136
+ return count;
36137
+ };
36138
+ timeoutObject = setTimeout(clear, timeout);
36139
+ const thr = { timeoutObject, clear, count: 0 };
36140
+ action.set(path, thr);
36141
+ return thr;
36142
+ }
36143
+ _incrReadyCount() {
36144
+ return this._readyCount++;
36145
+ }
36146
+ /**
36147
+ * Awaits write operation to finish.
36148
+ * Polls a newly created file for size variations. When files size does not change for 'threshold' milliseconds calls callback.
36149
+ * @param path being acted upon
36150
+ * @param threshold Time in milliseconds a file size must be fixed before acknowledging write OP is finished
36151
+ * @param event
36152
+ * @param awfEmit Callback to be called when ready for event to be emitted.
36153
+ */
36154
+ _awaitWriteFinish(path, threshold, event, awfEmit) {
36155
+ const awf = this.options.awaitWriteFinish;
36156
+ if (typeof awf !== 'object')
36157
+ return;
36158
+ const pollInterval = awf.pollInterval;
36159
+ let timeoutHandler;
36160
+ let fullPath = path;
36161
+ if (this.options.cwd && !sysPath.isAbsolute(path)) {
36162
+ fullPath = sysPath.join(this.options.cwd, path);
36163
+ }
36164
+ const now = new Date();
36165
+ const writes = this._pendingWrites;
36166
+ function awaitWriteFinishFn(prevStat) {
36167
+ stat$3(fullPath, (err, curStat) => {
36168
+ if (err || !writes.has(path)) {
36169
+ if (err && err.code !== 'ENOENT')
36170
+ awfEmit(err);
36171
+ return;
36172
+ }
36173
+ const now = Number(new Date());
36174
+ if (prevStat && curStat.size !== prevStat.size) {
36175
+ writes.get(path).lastChange = now;
36176
+ }
36177
+ const pw = writes.get(path);
36178
+ const df = now - pw.lastChange;
36179
+ if (df >= threshold) {
36180
+ writes.delete(path);
36181
+ awfEmit(undefined, curStat);
36182
+ }
36183
+ else {
36184
+ timeoutHandler = setTimeout(awaitWriteFinishFn, pollInterval, curStat);
36185
+ }
36186
+ });
36187
+ }
36188
+ if (!writes.has(path)) {
36189
+ writes.set(path, {
36190
+ lastChange: now,
36191
+ cancelWait: () => {
36192
+ writes.delete(path);
36193
+ clearTimeout(timeoutHandler);
36194
+ return event;
36195
+ },
36196
+ });
36197
+ timeoutHandler = setTimeout(awaitWriteFinishFn, pollInterval);
36198
+ }
36199
+ }
36200
+ /**
36201
+ * Determines whether user has asked to ignore this path.
36202
+ */
36203
+ _isIgnored(path, stats) {
36204
+ if (this.options.atomic && DOT_RE.test(path))
36205
+ return true;
36206
+ if (!this._userIgnored) {
36207
+ const { cwd } = this.options;
36208
+ const ign = this.options.ignored;
36209
+ const ignored = (ign || []).map(normalizeIgnored(cwd));
36210
+ const ignoredPaths = [...this._ignoredPaths];
36211
+ const list = [...ignoredPaths.map(normalizeIgnored(cwd)), ...ignored];
36212
+ this._userIgnored = anymatch(list);
36213
+ }
36214
+ return this._userIgnored(path, stats);
36215
+ }
36216
+ _isntIgnored(path, stat) {
36217
+ return !this._isIgnored(path, stat);
36218
+ }
36219
+ /**
36220
+ * Provides a set of common helpers and properties relating to symlink handling.
36221
+ * @param path file or directory pattern being watched
36222
+ */
36223
+ _getWatchHelpers(path) {
36224
+ return new WatchHelper(path, this.options.followSymlinks, this);
36225
+ }
36226
+ // Directory helpers
36227
+ // -----------------
36228
+ /**
36229
+ * Provides directory tracking objects
36230
+ * @param directory path of the directory
36231
+ */
36232
+ _getWatchedDir(directory) {
36233
+ const dir = sysPath.resolve(directory);
36234
+ if (!this._watched.has(dir))
36235
+ this._watched.set(dir, new DirEntry(dir, this._boundRemove));
36236
+ return this._watched.get(dir);
36237
+ }
36238
+ // File helpers
36239
+ // ------------
36240
+ /**
36241
+ * Check for read permissions: https://stackoverflow.com/a/11781404/1358405
36242
+ */
36243
+ _hasReadPermissions(stats) {
36244
+ if (this.options.ignorePermissionErrors)
36245
+ return true;
36246
+ return Boolean(Number(stats.mode) & 0o400);
36247
+ }
36248
+ /**
36249
+ * Handles emitting unlink events for
36250
+ * files and directories, and via recursion, for
36251
+ * files and directories within directories that are unlinked
36252
+ * @param directory within which the following item is located
36253
+ * @param item base path of item/directory
36254
+ */
36255
+ _remove(directory, item, isDirectory) {
36256
+ // if what is being deleted is a directory, get that directory's paths
36257
+ // for recursive deleting and cleaning of watched object
36258
+ // if it is not a directory, nestedDirectoryChildren will be empty array
36259
+ const path = sysPath.join(directory, item);
36260
+ const fullPath = sysPath.resolve(path);
36261
+ isDirectory =
36262
+ isDirectory != null ? isDirectory : this._watched.has(path) || this._watched.has(fullPath);
36263
+ // prevent duplicate handling in case of arriving here nearly simultaneously
36264
+ // via multiple paths (such as _handleFile and _handleDir)
36265
+ if (!this._throttle('remove', path, 100))
36266
+ return;
36267
+ // if the only watched file is removed, watch for its return
36268
+ if (!isDirectory && this._watched.size === 1) {
36269
+ this.add(directory, item, true);
36270
+ }
36271
+ // This will create a new entry in the watched object in either case
36272
+ // so we got to do the directory check beforehand
36273
+ const wp = this._getWatchedDir(path);
36274
+ const nestedDirectoryChildren = wp.getChildren();
36275
+ // Recursively remove children directories / files.
36276
+ nestedDirectoryChildren.forEach((nested) => this._remove(path, nested));
36277
+ // Check if item was on the watched list and remove it
36278
+ const parent = this._getWatchedDir(directory);
36279
+ const wasTracked = parent.has(item);
36280
+ parent.remove(item);
36281
+ // Fixes issue #1042 -> Relative paths were detected and added as symlinks
36282
+ // (https://github.com/paulmillr/chokidar/blob/e1753ddbc9571bdc33b4a4af172d52cb6e611c10/lib/nodefs-handler.js#L612),
36283
+ // but never removed from the map in case the path was deleted.
36284
+ // This leads to an incorrect state if the path was recreated:
36285
+ // https://github.com/paulmillr/chokidar/blob/e1753ddbc9571bdc33b4a4af172d52cb6e611c10/lib/nodefs-handler.js#L553
36286
+ if (this._symlinkPaths.has(fullPath)) {
36287
+ this._symlinkPaths.delete(fullPath);
36288
+ }
36289
+ // If we wait for this file to be fully written, cancel the wait.
36290
+ let relPath = path;
36291
+ if (this.options.cwd)
36292
+ relPath = sysPath.relative(this.options.cwd, path);
36293
+ if (this.options.awaitWriteFinish && this._pendingWrites.has(relPath)) {
36294
+ const event = this._pendingWrites.get(relPath).cancelWait();
36295
+ if (event === EVENTS.ADD)
36296
+ return;
36297
+ }
36298
+ // The Entry will either be a directory that just got removed
36299
+ // or a bogus entry to a file, in either case we have to remove it
36300
+ this._watched.delete(path);
36301
+ this._watched.delete(fullPath);
36302
+ const eventName = isDirectory ? EVENTS.UNLINK_DIR : EVENTS.UNLINK;
36303
+ if (wasTracked && !this._isIgnored(path))
36304
+ this._emit(eventName, path);
36305
+ // Avoid conflicts if we later create another file with the same name
36306
+ this._closePath(path);
36307
+ }
36308
+ /**
36309
+ * Closes all watchers for a path
36310
+ */
36311
+ _closePath(path) {
36312
+ this._closeFile(path);
36313
+ const dir = sysPath.dirname(path);
36314
+ this._getWatchedDir(dir).remove(sysPath.basename(path));
36315
+ }
36316
+ /**
36317
+ * Closes only file-specific watchers
36318
+ */
36319
+ _closeFile(path) {
36320
+ const closers = this._closers.get(path);
36321
+ if (!closers)
36322
+ return;
36323
+ closers.forEach((closer) => closer());
36324
+ this._closers.delete(path);
36325
+ }
36326
+ _addPathCloser(path, closer) {
36327
+ if (!closer)
36328
+ return;
36329
+ let list = this._closers.get(path);
36330
+ if (!list) {
36331
+ list = [];
36332
+ this._closers.set(path, list);
36333
+ }
36334
+ list.push(closer);
36335
+ }
36336
+ _readdirp(root, opts) {
36337
+ if (this.closed)
36338
+ return;
36339
+ const options = { type: EVENTS.ALL, alwaysStat: true, lstat: true, ...opts, depth: 0 };
36340
+ let stream = readdirp(root, options);
36341
+ this._streams.add(stream);
36342
+ stream.once(STR_CLOSE, () => {
36343
+ stream = undefined;
36344
+ });
36345
+ stream.once(STR_END, () => {
36346
+ if (stream) {
36347
+ this._streams.delete(stream);
36348
+ stream = undefined;
36349
+ }
36350
+ });
36351
+ return stream;
36352
+ }
36353
+ }
36354
+ /**
36355
+ * Instantiates watcher with paths to be tracked.
36356
+ * @param paths file / directory paths
36357
+ * @param options opts, such as `atomic`, `awaitWriteFinish`, `ignored`, and others
36358
+ * @returns an instance of FSWatcher for chaining.
36359
+ * @example
36360
+ * const watcher = watch('.').on('all', (event, path) => { console.log(event, path); });
36361
+ * watch('.', { atomic: true, awaitWriteFinish: true, ignored: (f, stats) => stats?.isFile() && !f.endsWith('.js') })
36362
+ */
36363
+ function watch(paths, options = {}) {
36364
+ const watcher = new FSWatcher(options);
36365
+ watcher.add(paths);
36366
+ return watcher;
36367
+ }
36368
+ var index = { watch, FSWatcher };
36369
+
36370
+ var index$1 = /*#__PURE__*/Object.freeze({
36371
+ __proto__: null,
36372
+ FSWatcher: FSWatcher,
36373
+ WatchHelper: WatchHelper,
36374
+ default: index,
36375
+ watch: watch
36376
+ });
36377
+
36378
+ export { BaseLogger, CONFIG_FILE_NAME, ConsoleLogger, ConsoleLoggerWithoutExit, DEFAULT_CONFIG, MemoryLogger, build, check, compile, composeToString, createSorter, defaultLogger, dep, dev, fastLogToFile, init, resolveNASLFiles, scanEntryFiles, scanNASLFiles, sorter, tryCompile };
34507
36379
  //# sourceMappingURL=index.mjs.map