@ezetgalaxy/titan 26.9.1 → 26.9.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. package/README.md +17 -5
  2. package/index.js +177 -112
  3. package/package.json +19 -5
  4. package/templates/common/app/titan.d.ts +87 -0
  5. package/templates/extension/node_modules/.bin/esbuild +16 -0
  6. package/templates/extension/node_modules/.bin/esbuild.cmd +17 -0
  7. package/templates/extension/node_modules/.bin/esbuild.ps1 +28 -0
  8. package/templates/extension/node_modules/.bin/titanpl-sdk +16 -0
  9. package/templates/extension/node_modules/.bin/titanpl-sdk.cmd +17 -0
  10. package/templates/extension/node_modules/.bin/titanpl-sdk.ps1 +28 -0
  11. package/templates/extension/node_modules/.package-lock.json +111 -0
  12. package/templates/extension/node_modules/@esbuild/win32-x64/README.md +3 -0
  13. package/templates/extension/node_modules/@esbuild/win32-x64/esbuild.exe +0 -0
  14. package/templates/extension/node_modules/@esbuild/win32-x64/package.json +20 -0
  15. package/templates/extension/node_modules/@titanpl/core/LICENSE +15 -0
  16. package/templates/extension/node_modules/@titanpl/core/README.md +127 -0
  17. package/templates/extension/node_modules/@titanpl/core/globals.d.ts +17 -0
  18. package/templates/extension/node_modules/@titanpl/core/index.js +250 -0
  19. package/templates/extension/node_modules/@titanpl/core/native/target/release/titan_core.dll +0 -0
  20. package/templates/extension/node_modules/@titanpl/core/package.json +41 -0
  21. package/templates/extension/node_modules/@titanpl/core/titan.json +115 -0
  22. package/templates/extension/node_modules/chokidar/LICENSE +21 -0
  23. package/templates/extension/node_modules/chokidar/README.md +305 -0
  24. package/templates/extension/node_modules/chokidar/handler.d.ts +90 -0
  25. package/templates/extension/node_modules/chokidar/handler.js +632 -0
  26. package/templates/extension/node_modules/chokidar/index.d.ts +217 -0
  27. package/templates/extension/node_modules/chokidar/index.js +822 -0
  28. package/templates/extension/node_modules/chokidar/package.json +63 -0
  29. package/templates/extension/node_modules/esbuild/LICENSE.md +21 -0
  30. package/templates/extension/node_modules/esbuild/README.md +3 -0
  31. package/templates/extension/node_modules/esbuild/bin/esbuild +223 -0
  32. package/templates/extension/node_modules/esbuild/install.js +289 -0
  33. package/templates/extension/node_modules/esbuild/lib/main.d.ts +716 -0
  34. package/templates/extension/node_modules/esbuild/lib/main.js +2242 -0
  35. package/templates/extension/node_modules/esbuild/package.json +49 -0
  36. package/templates/extension/node_modules/readdirp/LICENSE +21 -0
  37. package/templates/extension/node_modules/readdirp/README.md +120 -0
  38. package/templates/extension/node_modules/readdirp/index.d.ts +108 -0
  39. package/templates/extension/node_modules/readdirp/index.js +272 -0
  40. package/templates/extension/node_modules/readdirp/package.json +66 -0
  41. package/templates/extension/node_modules/titanpl-sdk/LICENSE +15 -0
  42. package/templates/extension/node_modules/titanpl-sdk/README.md +109 -0
  43. package/templates/extension/node_modules/titanpl-sdk/assets/titanpl-sdk.png +0 -0
  44. package/templates/extension/node_modules/titanpl-sdk/bin/run.js +251 -0
  45. package/templates/extension/node_modules/titanpl-sdk/index.d.ts +46 -0
  46. package/templates/extension/node_modules/titanpl-sdk/index.js +5 -0
  47. package/templates/extension/node_modules/titanpl-sdk/package.json +33 -0
  48. package/templates/{rust-js → extension/node_modules/titanpl-sdk/templates}/Dockerfile +4 -17
  49. package/templates/extension/node_modules/titanpl-sdk/templates/app/actions/hello.js +5 -0
  50. package/templates/extension/node_modules/titanpl-sdk/templates/app/app.js +10 -0
  51. package/templates/extension/node_modules/titanpl-sdk/templates/jsconfig.json +19 -0
  52. package/templates/extension/node_modules/titanpl-sdk/templates/server/Cargo.lock +2839 -0
  53. package/templates/extension/node_modules/titanpl-sdk/templates/server/Cargo.toml +27 -0
  54. package/templates/extension/node_modules/titanpl-sdk/templates/server/src/action_management.rs +131 -0
  55. package/templates/extension/node_modules/titanpl-sdk/templates/server/src/errors.rs +10 -0
  56. package/templates/extension/node_modules/titanpl-sdk/templates/server/src/extensions.rs +640 -0
  57. package/templates/extension/node_modules/titanpl-sdk/templates/server/src/main.rs +345 -0
  58. package/templates/extension/node_modules/titanpl-sdk/templates/server/src/utils.rs +33 -0
  59. package/templates/extension/node_modules/titanpl-sdk/templates/titan/bundle.js +65 -0
  60. package/templates/extension/node_modules/titanpl-sdk/templates/titan/dev.js +113 -0
  61. package/templates/extension/node_modules/titanpl-sdk/templates/titan/titan.js +98 -0
  62. package/templates/extension/package-lock.json +522 -0
  63. package/templates/extension/package.json +4 -3
  64. package/templates/rust-ts/app/actions/hello.ts +1 -1
  65. package/templates/rust-ts/titan/runtime.d.ts +1 -0
  66. package/templates/rust-ts/titan/runtime.js +1 -0
  67. package/templates/rust-ts/titan/titan.d.ts +117 -117
  68. package/templates/rust-ts/titan/titan.js +1 -1
  69. package/templates/ts/app/actions/hello.ts +1 -1
  70. package/templates/ts/titan/builder.js +121 -121
  71. package/templates/ts/titan/runtime.d.ts +1 -0
  72. package/templates/ts/titan/runtime.js +1 -1
  73. package/templates/ts/titan/titan.d.ts +117 -117
  74. package/templates/ts/titan/titan.js +1 -1
  75. package/titanpl-sdk/node_modules/.package-lock.json +17 -0
  76. package/titanpl-sdk/node_modules/@titanpl/core/LICENSE +15 -0
  77. package/titanpl-sdk/node_modules/@titanpl/core/README.md +127 -0
  78. package/titanpl-sdk/node_modules/@titanpl/core/globals.d.ts +17 -0
  79. package/titanpl-sdk/node_modules/@titanpl/core/index.js +250 -0
  80. package/titanpl-sdk/node_modules/@titanpl/core/native/target/release/titan_core.dll +0 -0
  81. package/titanpl-sdk/node_modules/@titanpl/core/package.json +41 -0
  82. package/titanpl-sdk/node_modules/@titanpl/core/titan.json +115 -0
  83. package/titanpl-sdk/package-lock.json +28 -0
  84. package/titanpl-sdk/package.json +6 -3
  85. package/templates/rust-js/_gitignore +0 -38
  86. package/templates/rust-js/app/titan.d.ts +0 -101
  87. package/templates/rust-ts/Dockerfile +0 -66
  88. package/templates/rust-ts/_dockerignore +0 -3
  89. package/templates/rust-ts/_gitignore +0 -38
  90. package/templates/ts/Dockerfile +0 -40
  91. package/templates/ts/_dockerignore +0 -3
  92. package/templates/ts/_gitignore +0 -38
  93. /package/templates/{js → common}/Dockerfile +0 -0
  94. /package/templates/{js → common}/_dockerignore +0 -0
  95. /package/templates/{js → common}/_gitignore +0 -0
  96. /package/templates/{rust-js/_dockerignore → extension/node_modules/titanpl-sdk/templates/.dockerignore} +0 -0
  97. /package/templates/{js → extension/node_modules/titanpl-sdk/templates}/app/titan.d.ts +0 -0
@@ -0,0 +1,822 @@
1
+ /*! chokidar - MIT License (c) 2012 Paul Miller (paulmillr.com) */
2
+ import { EventEmitter } from 'node:events';
3
+ import { stat as statcb, Stats } from 'node:fs';
4
+ import { readdir, stat } from 'node:fs/promises';
5
+ import * as sp from 'node:path';
6
+ import { readdirp, ReaddirpStream } from 'readdirp';
7
+ import { EMPTY_FN, EVENTS as EV, isIBMi, isWindows, NodeFsHandler, STR_CLOSE, STR_END, } from './handler.js';
8
+ const SLASH = '/';
9
+ const SLASH_SLASH = '//';
10
+ const ONE_DOT = '.';
11
+ const TWO_DOTS = '..';
12
+ const STRING_TYPE = 'string';
13
+ const BACK_SLASH_RE = /\\/g;
14
+ const DOUBLE_SLASH_RE = /\/\//g;
15
+ const DOT_RE = /\..*\.(sw[px])$|~$|\.subl.*\.tmp/;
16
+ const REPLACER_RE = /^\.[/\\]/;
17
+ function arrify(item) {
18
+ return Array.isArray(item) ? item : [item];
19
+ }
20
+ const isMatcherObject = (matcher) => typeof matcher === 'object' && matcher !== null && !(matcher instanceof RegExp);
21
+ function createPattern(matcher) {
22
+ if (typeof matcher === 'function')
23
+ return matcher;
24
+ if (typeof matcher === 'string')
25
+ return (string) => matcher === string;
26
+ if (matcher instanceof RegExp)
27
+ return (string) => matcher.test(string);
28
+ if (typeof matcher === 'object' && matcher !== null) {
29
+ return (string) => {
30
+ if (matcher.path === string)
31
+ return true;
32
+ if (matcher.recursive) {
33
+ const relative = sp.relative(matcher.path, string);
34
+ if (!relative) {
35
+ return false;
36
+ }
37
+ return !relative.startsWith('..') && !sp.isAbsolute(relative);
38
+ }
39
+ return false;
40
+ };
41
+ }
42
+ return () => false;
43
+ }
44
+ function normalizePath(path) {
45
+ if (typeof path !== 'string')
46
+ throw new Error('string expected');
47
+ path = sp.normalize(path);
48
+ path = path.replace(/\\/g, '/');
49
+ let prepend = false;
50
+ if (path.startsWith('//'))
51
+ prepend = true;
52
+ path = path.replace(DOUBLE_SLASH_RE, '/');
53
+ if (prepend)
54
+ path = '/' + path;
55
+ return path;
56
+ }
57
+ function matchPatterns(patterns, testString, stats) {
58
+ const path = normalizePath(testString);
59
+ for (let index = 0; index < patterns.length; index++) {
60
+ const pattern = patterns[index];
61
+ if (pattern(path, stats)) {
62
+ return true;
63
+ }
64
+ }
65
+ return false;
66
+ }
67
+ function anymatch(matchers, testString) {
68
+ if (matchers == null) {
69
+ throw new TypeError('anymatch: specify first argument');
70
+ }
71
+ // Early cache for matchers.
72
+ const matchersArray = arrify(matchers);
73
+ const patterns = matchersArray.map((matcher) => createPattern(matcher));
74
+ if (testString == null) {
75
+ return (testString, stats) => {
76
+ return matchPatterns(patterns, testString, stats);
77
+ };
78
+ }
79
+ return matchPatterns(patterns, testString);
80
+ }
81
+ const unifyPaths = (paths_) => {
82
+ const paths = arrify(paths_).flat();
83
+ if (!paths.every((p) => typeof p === STRING_TYPE)) {
84
+ throw new TypeError(`Non-string provided as watch path: ${paths}`);
85
+ }
86
+ return paths.map(normalizePathToUnix);
87
+ };
88
+ // If SLASH_SLASH occurs at the beginning of path, it is not replaced
89
+ // because "//StoragePC/DrivePool/Movies" is a valid network path
90
+ const toUnix = (string) => {
91
+ let str = string.replace(BACK_SLASH_RE, SLASH);
92
+ let prepend = false;
93
+ if (str.startsWith(SLASH_SLASH)) {
94
+ prepend = true;
95
+ }
96
+ str = str.replace(DOUBLE_SLASH_RE, SLASH);
97
+ if (prepend) {
98
+ str = SLASH + str;
99
+ }
100
+ return str;
101
+ };
102
+ // Our version of upath.normalize
103
+ // TODO: this is not equal to path-normalize module - investigate why
104
+ const normalizePathToUnix = (path) => toUnix(sp.normalize(toUnix(path)));
105
+ // TODO: refactor
106
+ const normalizeIgnored = (cwd = '') => (path) => {
107
+ if (typeof path === 'string') {
108
+ return normalizePathToUnix(sp.isAbsolute(path) ? path : sp.join(cwd, path));
109
+ }
110
+ else {
111
+ return path;
112
+ }
113
+ };
114
+ const getAbsolutePath = (path, cwd) => {
115
+ if (sp.isAbsolute(path)) {
116
+ return path;
117
+ }
118
+ return sp.join(cwd, path);
119
+ };
120
+ const EMPTY_SET = Object.freeze(new Set());
121
+ /**
122
+ * Directory entry.
123
+ */
124
+ class DirEntry {
125
+ path;
126
+ _removeWatcher;
127
+ items;
128
+ constructor(dir, removeWatcher) {
129
+ this.path = dir;
130
+ this._removeWatcher = removeWatcher;
131
+ this.items = new Set();
132
+ }
133
+ add(item) {
134
+ const { items } = this;
135
+ if (!items)
136
+ return;
137
+ if (item !== ONE_DOT && item !== TWO_DOTS)
138
+ items.add(item);
139
+ }
140
+ async remove(item) {
141
+ const { items } = this;
142
+ if (!items)
143
+ return;
144
+ items.delete(item);
145
+ if (items.size > 0)
146
+ return;
147
+ const dir = this.path;
148
+ try {
149
+ await readdir(dir);
150
+ }
151
+ catch (err) {
152
+ if (this._removeWatcher) {
153
+ this._removeWatcher(sp.dirname(dir), sp.basename(dir));
154
+ }
155
+ }
156
+ }
157
+ has(item) {
158
+ const { items } = this;
159
+ if (!items)
160
+ return;
161
+ return items.has(item);
162
+ }
163
+ getChildren() {
164
+ const { items } = this;
165
+ if (!items)
166
+ return [];
167
+ return [...items.values()];
168
+ }
169
+ dispose() {
170
+ this.items.clear();
171
+ this.path = '';
172
+ this._removeWatcher = EMPTY_FN;
173
+ this.items = EMPTY_SET;
174
+ Object.freeze(this);
175
+ }
176
+ }
177
+ const STAT_METHOD_F = 'stat';
178
+ const STAT_METHOD_L = 'lstat';
179
+ export class WatchHelper {
180
+ fsw;
181
+ path;
182
+ watchPath;
183
+ fullWatchPath;
184
+ dirParts;
185
+ followSymlinks;
186
+ statMethod;
187
+ constructor(path, follow, fsw) {
188
+ this.fsw = fsw;
189
+ const watchPath = path;
190
+ this.path = path = path.replace(REPLACER_RE, '');
191
+ this.watchPath = watchPath;
192
+ this.fullWatchPath = sp.resolve(watchPath);
193
+ this.dirParts = [];
194
+ this.dirParts.forEach((parts) => {
195
+ if (parts.length > 1)
196
+ parts.pop();
197
+ });
198
+ this.followSymlinks = follow;
199
+ this.statMethod = follow ? STAT_METHOD_F : STAT_METHOD_L;
200
+ }
201
+ entryPath(entry) {
202
+ return sp.join(this.watchPath, sp.relative(this.watchPath, entry.fullPath));
203
+ }
204
+ filterPath(entry) {
205
+ const { stats } = entry;
206
+ if (stats && stats.isSymbolicLink())
207
+ return this.filterDir(entry);
208
+ const resolvedPath = this.entryPath(entry);
209
+ // TODO: what if stats is undefined? remove !
210
+ return this.fsw._isntIgnored(resolvedPath, stats) && this.fsw._hasReadPermissions(stats);
211
+ }
212
+ filterDir(entry) {
213
+ return this.fsw._isntIgnored(this.entryPath(entry), entry.stats);
214
+ }
215
+ }
216
+ /**
217
+ * Watches files & directories for changes. Emitted events:
218
+ * `add`, `addDir`, `change`, `unlink`, `unlinkDir`, `all`, `error`
219
+ *
220
+ * new FSWatcher()
221
+ * .add(directories)
222
+ * .on('add', path => log('File', path, 'was added'))
223
+ */
224
+ export class FSWatcher extends EventEmitter {
225
+ closed;
226
+ options;
227
+ _closers;
228
+ _ignoredPaths;
229
+ _throttled;
230
+ _streams;
231
+ _symlinkPaths;
232
+ _watched;
233
+ _pendingWrites;
234
+ _pendingUnlinks;
235
+ _readyCount;
236
+ _emitReady;
237
+ _closePromise;
238
+ _userIgnored;
239
+ _readyEmitted;
240
+ _emitRaw;
241
+ _boundRemove;
242
+ _nodeFsHandler;
243
+ // Not indenting methods for history sake; for now.
244
+ constructor(_opts = {}) {
245
+ super();
246
+ this.closed = false;
247
+ this._closers = new Map();
248
+ this._ignoredPaths = new Set();
249
+ this._throttled = new Map();
250
+ this._streams = new Set();
251
+ this._symlinkPaths = new Map();
252
+ this._watched = new Map();
253
+ this._pendingWrites = new Map();
254
+ this._pendingUnlinks = new Map();
255
+ this._readyCount = 0;
256
+ this._readyEmitted = false;
257
+ const awf = _opts.awaitWriteFinish;
258
+ const DEF_AWF = { stabilityThreshold: 2000, pollInterval: 100 };
259
+ const opts = {
260
+ // Defaults
261
+ persistent: true,
262
+ ignoreInitial: false,
263
+ ignorePermissionErrors: false,
264
+ interval: 100,
265
+ binaryInterval: 300,
266
+ followSymlinks: true,
267
+ usePolling: false,
268
+ // useAsync: false,
269
+ atomic: true, // NOTE: overwritten later (depends on usePolling)
270
+ ..._opts,
271
+ // Change format
272
+ ignored: _opts.ignored ? arrify(_opts.ignored) : arrify([]),
273
+ awaitWriteFinish: awf === true ? DEF_AWF : typeof awf === 'object' ? { ...DEF_AWF, ...awf } : false,
274
+ };
275
+ // Always default to polling on IBM i because fs.watch() is not available on IBM i.
276
+ if (isIBMi)
277
+ opts.usePolling = true;
278
+ // Editor atomic write normalization enabled by default with fs.watch
279
+ if (opts.atomic === undefined)
280
+ opts.atomic = !opts.usePolling;
281
+ // opts.atomic = typeof _opts.atomic === 'number' ? _opts.atomic : 100;
282
+ // Global override. Useful for developers, who need to force polling for all
283
+ // instances of chokidar, regardless of usage / dependency depth
284
+ const envPoll = process.env.CHOKIDAR_USEPOLLING;
285
+ if (envPoll !== undefined) {
286
+ const envLower = envPoll.toLowerCase();
287
+ if (envLower === 'false' || envLower === '0')
288
+ opts.usePolling = false;
289
+ else if (envLower === 'true' || envLower === '1')
290
+ opts.usePolling = true;
291
+ else
292
+ opts.usePolling = !!envLower;
293
+ }
294
+ const envInterval = process.env.CHOKIDAR_INTERVAL;
295
+ if (envInterval)
296
+ opts.interval = Number.parseInt(envInterval, 10);
297
+ // This is done to emit ready only once, but each 'add' will increase that?
298
+ let readyCalls = 0;
299
+ this._emitReady = () => {
300
+ readyCalls++;
301
+ if (readyCalls >= this._readyCount) {
302
+ this._emitReady = EMPTY_FN;
303
+ this._readyEmitted = true;
304
+ // use process.nextTick to allow time for listener to be bound
305
+ process.nextTick(() => this.emit(EV.READY));
306
+ }
307
+ };
308
+ this._emitRaw = (...args) => this.emit(EV.RAW, ...args);
309
+ this._boundRemove = this._remove.bind(this);
310
+ this.options = opts;
311
+ this._nodeFsHandler = new NodeFsHandler(this);
312
+ // You’re frozen when your heart’s not open.
313
+ Object.freeze(opts);
314
+ }
315
+ _addIgnoredPath(matcher) {
316
+ if (isMatcherObject(matcher)) {
317
+ // return early if we already have a deeply equal matcher object
318
+ for (const ignored of this._ignoredPaths) {
319
+ if (isMatcherObject(ignored) &&
320
+ ignored.path === matcher.path &&
321
+ ignored.recursive === matcher.recursive) {
322
+ return;
323
+ }
324
+ }
325
+ }
326
+ this._ignoredPaths.add(matcher);
327
+ }
328
+ _removeIgnoredPath(matcher) {
329
+ this._ignoredPaths.delete(matcher);
330
+ // now find any matcher objects with the matcher as path
331
+ if (typeof matcher === 'string') {
332
+ for (const ignored of this._ignoredPaths) {
333
+ // TODO (43081j): make this more efficient.
334
+ // probably just make a `this._ignoredDirectories` or some
335
+ // such thing.
336
+ if (isMatcherObject(ignored) && ignored.path === matcher) {
337
+ this._ignoredPaths.delete(ignored);
338
+ }
339
+ }
340
+ }
341
+ }
342
+ // Public methods
343
+ /**
344
+ * Adds paths to be watched on an existing FSWatcher instance.
345
+ * @param paths_ file or file list. Other arguments are unused
346
+ */
347
+ add(paths_, _origAdd, _internal) {
348
+ const { cwd } = this.options;
349
+ this.closed = false;
350
+ this._closePromise = undefined;
351
+ let paths = unifyPaths(paths_);
352
+ if (cwd) {
353
+ paths = paths.map((path) => {
354
+ const absPath = getAbsolutePath(path, cwd);
355
+ // Check `path` instead of `absPath` because the cwd portion can't be a glob
356
+ return absPath;
357
+ });
358
+ }
359
+ paths.forEach((path) => {
360
+ this._removeIgnoredPath(path);
361
+ });
362
+ this._userIgnored = undefined;
363
+ if (!this._readyCount)
364
+ this._readyCount = 0;
365
+ this._readyCount += paths.length;
366
+ Promise.all(paths.map(async (path) => {
367
+ const res = await this._nodeFsHandler._addToNodeFs(path, !_internal, undefined, 0, _origAdd);
368
+ if (res)
369
+ this._emitReady();
370
+ return res;
371
+ })).then((results) => {
372
+ if (this.closed)
373
+ return;
374
+ results.forEach((item) => {
375
+ if (item)
376
+ this.add(sp.dirname(item), sp.basename(_origAdd || item));
377
+ });
378
+ });
379
+ return this;
380
+ }
381
+ /**
382
+ * Close watchers or start ignoring events from specified paths.
383
+ */
384
+ unwatch(paths_) {
385
+ if (this.closed)
386
+ return this;
387
+ const paths = unifyPaths(paths_);
388
+ const { cwd } = this.options;
389
+ paths.forEach((path) => {
390
+ // convert to absolute path unless relative path already matches
391
+ if (!sp.isAbsolute(path) && !this._closers.has(path)) {
392
+ if (cwd)
393
+ path = sp.join(cwd, path);
394
+ path = sp.resolve(path);
395
+ }
396
+ this._closePath(path);
397
+ this._addIgnoredPath(path);
398
+ if (this._watched.has(path)) {
399
+ this._addIgnoredPath({
400
+ path,
401
+ recursive: true,
402
+ });
403
+ }
404
+ // reset the cached userIgnored anymatch fn
405
+ // to make ignoredPaths changes effective
406
+ this._userIgnored = undefined;
407
+ });
408
+ return this;
409
+ }
410
+ /**
411
+ * Close watchers and remove all listeners from watched paths.
412
+ */
413
+ close() {
414
+ if (this._closePromise) {
415
+ return this._closePromise;
416
+ }
417
+ this.closed = true;
418
+ // Memory management.
419
+ this.removeAllListeners();
420
+ const closers = [];
421
+ this._closers.forEach((closerList) => closerList.forEach((closer) => {
422
+ const promise = closer();
423
+ if (promise instanceof Promise)
424
+ closers.push(promise);
425
+ }));
426
+ this._streams.forEach((stream) => stream.destroy());
427
+ this._userIgnored = undefined;
428
+ this._readyCount = 0;
429
+ this._readyEmitted = false;
430
+ this._watched.forEach((dirent) => dirent.dispose());
431
+ this._closers.clear();
432
+ this._watched.clear();
433
+ this._streams.clear();
434
+ this._symlinkPaths.clear();
435
+ this._throttled.clear();
436
+ this._closePromise = closers.length
437
+ ? Promise.all(closers).then(() => undefined)
438
+ : Promise.resolve();
439
+ return this._closePromise;
440
+ }
441
+ /**
442
+ * Expose list of watched paths
443
+ * @returns for chaining
444
+ */
445
+ getWatched() {
446
+ const watchList = {};
447
+ this._watched.forEach((entry, dir) => {
448
+ const key = this.options.cwd ? sp.relative(this.options.cwd, dir) : dir;
449
+ const index = key || ONE_DOT;
450
+ watchList[index] = entry.getChildren().sort();
451
+ });
452
+ return watchList;
453
+ }
454
+ emitWithAll(event, args) {
455
+ this.emit(event, ...args);
456
+ if (event !== EV.ERROR)
457
+ this.emit(EV.ALL, event, ...args);
458
+ }
459
+ // Common helpers
460
+ // --------------
461
+ /**
462
+ * Normalize and emit events.
463
+ * Calling _emit DOES NOT MEAN emit() would be called!
464
+ * @param event Type of event
465
+ * @param path File or directory path
466
+ * @param stats arguments to be passed with event
467
+ * @returns the error if defined, otherwise the value of the FSWatcher instance's `closed` flag
468
+ */
469
+ async _emit(event, path, stats) {
470
+ if (this.closed)
471
+ return;
472
+ const opts = this.options;
473
+ if (isWindows)
474
+ path = sp.normalize(path);
475
+ if (opts.cwd)
476
+ path = sp.relative(opts.cwd, path);
477
+ const args = [path];
478
+ if (stats != null)
479
+ args.push(stats);
480
+ const awf = opts.awaitWriteFinish;
481
+ let pw;
482
+ if (awf && (pw = this._pendingWrites.get(path))) {
483
+ pw.lastChange = new Date();
484
+ return this;
485
+ }
486
+ if (opts.atomic) {
487
+ if (event === EV.UNLINK) {
488
+ this._pendingUnlinks.set(path, [event, ...args]);
489
+ setTimeout(() => {
490
+ this._pendingUnlinks.forEach((entry, path) => {
491
+ this.emit(...entry);
492
+ this.emit(EV.ALL, ...entry);
493
+ this._pendingUnlinks.delete(path);
494
+ });
495
+ }, typeof opts.atomic === 'number' ? opts.atomic : 100);
496
+ return this;
497
+ }
498
+ if (event === EV.ADD && this._pendingUnlinks.has(path)) {
499
+ event = EV.CHANGE;
500
+ this._pendingUnlinks.delete(path);
501
+ }
502
+ }
503
+ if (awf && (event === EV.ADD || event === EV.CHANGE) && this._readyEmitted) {
504
+ const awfEmit = (err, stats) => {
505
+ if (err) {
506
+ event = EV.ERROR;
507
+ args[0] = err;
508
+ this.emitWithAll(event, args);
509
+ }
510
+ else if (stats) {
511
+ // if stats doesn't exist the file must have been deleted
512
+ if (args.length > 1) {
513
+ args[1] = stats;
514
+ }
515
+ else {
516
+ args.push(stats);
517
+ }
518
+ this.emitWithAll(event, args);
519
+ }
520
+ };
521
+ this._awaitWriteFinish(path, awf.stabilityThreshold, event, awfEmit);
522
+ return this;
523
+ }
524
+ if (event === EV.CHANGE) {
525
+ const isThrottled = !this._throttle(EV.CHANGE, path, 50);
526
+ if (isThrottled)
527
+ return this;
528
+ }
529
+ if (opts.alwaysStat &&
530
+ stats === undefined &&
531
+ (event === EV.ADD || event === EV.ADD_DIR || event === EV.CHANGE)) {
532
+ const fullPath = opts.cwd ? sp.join(opts.cwd, path) : path;
533
+ let stats;
534
+ try {
535
+ stats = await stat(fullPath);
536
+ }
537
+ catch (err) {
538
+ // do nothing
539
+ }
540
+ // Suppress event when fs_stat fails, to avoid sending undefined 'stat'
541
+ if (!stats || this.closed)
542
+ return;
543
+ args.push(stats);
544
+ }
545
+ this.emitWithAll(event, args);
546
+ return this;
547
+ }
548
+ /**
549
+ * Common handler for errors
550
+ * @returns The error if defined, otherwise the value of the FSWatcher instance's `closed` flag
551
+ */
552
+ _handleError(error) {
553
+ const code = error && error.code;
554
+ if (error &&
555
+ code !== 'ENOENT' &&
556
+ code !== 'ENOTDIR' &&
557
+ (!this.options.ignorePermissionErrors || (code !== 'EPERM' && code !== 'EACCES'))) {
558
+ this.emit(EV.ERROR, error);
559
+ }
560
+ return error || this.closed;
561
+ }
562
+ /**
563
+ * Helper utility for throttling
564
+ * @param actionType type being throttled
565
+ * @param path being acted upon
566
+ * @param timeout duration of time to suppress duplicate actions
567
+ * @returns tracking object or false if action should be suppressed
568
+ */
569
+ _throttle(actionType, path, timeout) {
570
+ if (!this._throttled.has(actionType)) {
571
+ this._throttled.set(actionType, new Map());
572
+ }
573
+ const action = this._throttled.get(actionType);
574
+ if (!action)
575
+ throw new Error('invalid throttle');
576
+ const actionPath = action.get(path);
577
+ if (actionPath) {
578
+ actionPath.count++;
579
+ return false;
580
+ }
581
+ // eslint-disable-next-line prefer-const
582
+ let timeoutObject;
583
+ const clear = () => {
584
+ const item = action.get(path);
585
+ const count = item ? item.count : 0;
586
+ action.delete(path);
587
+ clearTimeout(timeoutObject);
588
+ if (item)
589
+ clearTimeout(item.timeoutObject);
590
+ return count;
591
+ };
592
+ timeoutObject = setTimeout(clear, timeout);
593
+ const thr = { timeoutObject, clear, count: 0 };
594
+ action.set(path, thr);
595
+ return thr;
596
+ }
597
+ _incrReadyCount() {
598
+ return this._readyCount++;
599
+ }
600
+ /**
601
+ * Awaits write operation to finish.
602
+ * Polls a newly created file for size variations. When files size does not change for 'threshold' milliseconds calls callback.
603
+ * @param path being acted upon
604
+ * @param threshold Time in milliseconds a file size must be fixed before acknowledging write OP is finished
605
+ * @param event
606
+ * @param awfEmit Callback to be called when ready for event to be emitted.
607
+ */
608
+ _awaitWriteFinish(path, threshold, event, awfEmit) {
609
+ const awf = this.options.awaitWriteFinish;
610
+ if (typeof awf !== 'object')
611
+ return;
612
+ const pollInterval = awf.pollInterval;
613
+ let timeoutHandler;
614
+ let fullPath = path;
615
+ if (this.options.cwd && !sp.isAbsolute(path)) {
616
+ fullPath = sp.join(this.options.cwd, path);
617
+ }
618
+ const now = new Date();
619
+ const writes = this._pendingWrites;
620
+ function awaitWriteFinishFn(prevStat) {
621
+ statcb(fullPath, (err, curStat) => {
622
+ if (err || !writes.has(path)) {
623
+ if (err && err.code !== 'ENOENT')
624
+ awfEmit(err);
625
+ return;
626
+ }
627
+ const now = Number(new Date());
628
+ if (prevStat && curStat.size !== prevStat.size) {
629
+ writes.get(path).lastChange = now;
630
+ }
631
+ const pw = writes.get(path);
632
+ const df = now - pw.lastChange;
633
+ if (df >= threshold) {
634
+ writes.delete(path);
635
+ awfEmit(undefined, curStat);
636
+ }
637
+ else {
638
+ timeoutHandler = setTimeout(awaitWriteFinishFn, pollInterval, curStat);
639
+ }
640
+ });
641
+ }
642
+ if (!writes.has(path)) {
643
+ writes.set(path, {
644
+ lastChange: now,
645
+ cancelWait: () => {
646
+ writes.delete(path);
647
+ clearTimeout(timeoutHandler);
648
+ return event;
649
+ },
650
+ });
651
+ timeoutHandler = setTimeout(awaitWriteFinishFn, pollInterval);
652
+ }
653
+ }
654
+ /**
655
+ * Determines whether user has asked to ignore this path.
656
+ */
657
+ _isIgnored(path, stats) {
658
+ if (this.options.atomic && DOT_RE.test(path))
659
+ return true;
660
+ if (!this._userIgnored) {
661
+ const { cwd } = this.options;
662
+ const ign = this.options.ignored;
663
+ const ignored = (ign || []).map(normalizeIgnored(cwd));
664
+ const ignoredPaths = [...this._ignoredPaths];
665
+ const list = [...ignoredPaths.map(normalizeIgnored(cwd)), ...ignored];
666
+ this._userIgnored = anymatch(list, undefined);
667
+ }
668
+ return this._userIgnored(path, stats);
669
+ }
670
+ _isntIgnored(path, stat) {
671
+ return !this._isIgnored(path, stat);
672
+ }
673
+ /**
674
+ * Provides a set of common helpers and properties relating to symlink handling.
675
+ * @param path file or directory pattern being watched
676
+ */
677
+ _getWatchHelpers(path) {
678
+ return new WatchHelper(path, this.options.followSymlinks, this);
679
+ }
680
+ // Directory helpers
681
+ // -----------------
682
+ /**
683
+ * Provides directory tracking objects
684
+ * @param directory path of the directory
685
+ */
686
+ _getWatchedDir(directory) {
687
+ const dir = sp.resolve(directory);
688
+ if (!this._watched.has(dir))
689
+ this._watched.set(dir, new DirEntry(dir, this._boundRemove));
690
+ return this._watched.get(dir);
691
+ }
692
+ // File helpers
693
+ // ------------
694
+ /**
695
+ * Check for read permissions: https://stackoverflow.com/a/11781404/1358405
696
+ */
697
+ _hasReadPermissions(stats) {
698
+ if (this.options.ignorePermissionErrors)
699
+ return true;
700
+ return Boolean(Number(stats.mode) & 0o400);
701
+ }
702
+ /**
703
+ * Handles emitting unlink events for
704
+ * files and directories, and via recursion, for
705
+ * files and directories within directories that are unlinked
706
+ * @param directory within which the following item is located
707
+ * @param item base path of item/directory
708
+ */
709
+ _remove(directory, item, isDirectory) {
710
+ // if what is being deleted is a directory, get that directory's paths
711
+ // for recursive deleting and cleaning of watched object
712
+ // if it is not a directory, nestedDirectoryChildren will be empty array
713
+ const path = sp.join(directory, item);
714
+ const fullPath = sp.resolve(path);
715
+ isDirectory =
716
+ isDirectory != null ? isDirectory : this._watched.has(path) || this._watched.has(fullPath);
717
+ // prevent duplicate handling in case of arriving here nearly simultaneously
718
+ // via multiple paths (such as _handleFile and _handleDir)
719
+ if (!this._throttle('remove', path, 100))
720
+ return;
721
+ // if the only watched file is removed, watch for its return
722
+ if (!isDirectory && this._watched.size === 1) {
723
+ this.add(directory, item, true);
724
+ }
725
+ // This will create a new entry in the watched object in either case
726
+ // so we got to do the directory check beforehand
727
+ const wp = this._getWatchedDir(path);
728
+ const nestedDirectoryChildren = wp.getChildren();
729
+ // Recursively remove children directories / files.
730
+ nestedDirectoryChildren.forEach((nested) => this._remove(path, nested));
731
+ // Check if item was on the watched list and remove it
732
+ const parent = this._getWatchedDir(directory);
733
+ const wasTracked = parent.has(item);
734
+ parent.remove(item);
735
+ // Fixes issue #1042 -> Relative paths were detected and added as symlinks
736
+ // (https://github.com/paulmillr/chokidar/blob/e1753ddbc9571bdc33b4a4af172d52cb6e611c10/lib/nodefs-handler.js#L612),
737
+ // but never removed from the map in case the path was deleted.
738
+ // This leads to an incorrect state if the path was recreated:
739
+ // https://github.com/paulmillr/chokidar/blob/e1753ddbc9571bdc33b4a4af172d52cb6e611c10/lib/nodefs-handler.js#L553
740
+ if (this._symlinkPaths.has(fullPath)) {
741
+ this._symlinkPaths.delete(fullPath);
742
+ }
743
+ // If we wait for this file to be fully written, cancel the wait.
744
+ let relPath = path;
745
+ if (this.options.cwd)
746
+ relPath = sp.relative(this.options.cwd, path);
747
+ if (this.options.awaitWriteFinish && this._pendingWrites.has(relPath)) {
748
+ const event = this._pendingWrites.get(relPath).cancelWait();
749
+ if (event === EV.ADD)
750
+ return;
751
+ }
752
+ // The Entry will either be a directory that just got removed
753
+ // or a bogus entry to a file, in either case we have to remove it
754
+ this._watched.delete(path);
755
+ this._watched.delete(fullPath);
756
+ const eventName = isDirectory ? EV.UNLINK_DIR : EV.UNLINK;
757
+ if (wasTracked && !this._isIgnored(path))
758
+ this._emit(eventName, path);
759
+ // Avoid conflicts if we later create another file with the same name
760
+ this._closePath(path);
761
+ }
762
+ /**
763
+ * Closes all watchers for a path
764
+ */
765
+ _closePath(path) {
766
+ this._closeFile(path);
767
+ const dir = sp.dirname(path);
768
+ this._getWatchedDir(dir).remove(sp.basename(path));
769
+ }
770
+ /**
771
+ * Closes only file-specific watchers
772
+ */
773
+ _closeFile(path) {
774
+ const closers = this._closers.get(path);
775
+ if (!closers)
776
+ return;
777
+ closers.forEach((closer) => closer());
778
+ this._closers.delete(path);
779
+ }
780
+ _addPathCloser(path, closer) {
781
+ if (!closer)
782
+ return;
783
+ let list = this._closers.get(path);
784
+ if (!list) {
785
+ list = [];
786
+ this._closers.set(path, list);
787
+ }
788
+ list.push(closer);
789
+ }
790
+ _readdirp(root, opts) {
791
+ if (this.closed)
792
+ return;
793
+ const options = { type: EV.ALL, alwaysStat: true, lstat: true, ...opts, depth: 0 };
794
+ let stream = readdirp(root, options);
795
+ this._streams.add(stream);
796
+ stream.once(STR_CLOSE, () => {
797
+ stream = undefined;
798
+ });
799
+ stream.once(STR_END, () => {
800
+ if (stream) {
801
+ this._streams.delete(stream);
802
+ stream = undefined;
803
+ }
804
+ });
805
+ return stream;
806
+ }
807
+ }
808
+ /**
809
+ * Instantiates watcher with paths to be tracked.
810
+ * @param paths file / directory paths
811
+ * @param options opts, such as `atomic`, `awaitWriteFinish`, `ignored`, and others
812
+ * @returns an instance of FSWatcher for chaining.
813
+ * @example
814
+ * const watcher = watch('.').on('all', (event, path) => { console.log(event, path); });
815
+ * watch('.', { atomic: true, awaitWriteFinish: true, ignored: (f, stats) => stats?.isFile() && !f.endsWith('.js') })
816
+ */
817
+ export function watch(paths, options = {}) {
818
+ const watcher = new FSWatcher(options);
819
+ watcher.add(paths);
820
+ return watcher;
821
+ }
822
+ export default { watch: watch, FSWatcher: FSWatcher };