@adonisjs/assembler 8.0.0 → 8.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -37,7 +37,7 @@ export declare class FileSystem {
37
37
  *
38
38
  * Following patterns are always ignored
39
39
  *
40
- * '.git/**', 'coverage/**', '.github/**'
40
+ * '.git/**', 'coverage/**', '.github/**', '.adonisjs/**', 'tmp/**', 'storage/**', 'build/**'
41
41
  */
42
42
  get excludes(): string[];
43
43
  /**
@@ -1,9 +1,37 @@
1
+ import "../chunk-DF48asd8.js";
1
2
  import { parseImports } from "parse-imports";
3
+ //#region src/helpers.ts
4
+ /**
5
+ * Finds an import reference inside a code snippet by analyzing the import statements
6
+ * and matching against the provided import reference identifier.
7
+ *
8
+ * The function searches through all import statements in the code and matches
9
+ * against default, namespace, or named imports based on the import reference.
10
+ *
11
+ * @param code - The code snippet to search for imports
12
+ * @param importReference - The import reference identifier to find (can include dot notation)
13
+ * @returns Promise that resolves to an Import object or null if not found
14
+ *
15
+ * @example
16
+ * const importInfo = await findImport(code, 'validateUser')
17
+ * if (importInfo) {
18
+ * console.log(importInfo.specifier) // '@/validators/user'
19
+ * }
20
+ */
2
21
  async function findImport(code, importReference) {
3
22
  const importIdentifier = importReference.split(".")[0];
4
23
  for (const $import of await parseImports(code, {})) {
24
+ /**
25
+ * An import without any clause
26
+ */
5
27
  if (!$import.importClause) continue;
28
+ /**
29
+ * An import without any clause
30
+ */
6
31
  if (!$import.moduleSpecifier.value) continue;
32
+ /**
33
+ * Import identifier matches a default import
34
+ */
7
35
  if ($import.importClause.default === importIdentifier) return {
8
36
  specifier: $import.moduleSpecifier.value,
9
37
  isConstant: $import.moduleSpecifier.isConstant,
@@ -12,6 +40,9 @@ async function findImport(code, importReference) {
12
40
  value: importIdentifier
13
41
  }
14
42
  };
43
+ /**
44
+ * Import identifier matches a namespace import
45
+ */
15
46
  if ($import.importClause.namespace === importIdentifier) return {
16
47
  specifier: $import.moduleSpecifier.value,
17
48
  isConstant: $import.moduleSpecifier.isConstant,
@@ -23,6 +54,9 @@ async function findImport(code, importReference) {
23
54
  const namedImport = $import.importClause.named.find(({ binding }) => {
24
55
  return binding === importIdentifier;
25
56
  });
57
+ /**
58
+ * Import identifier matches a named import
59
+ */
26
60
  if (namedImport) return {
27
61
  specifier: $import.moduleSpecifier.value,
28
62
  isConstant: $import.moduleSpecifier.isConstant,
@@ -35,12 +69,64 @@ async function findImport(code, importReference) {
35
69
  }
36
70
  return null;
37
71
  }
72
+ /**
73
+ * Returns a node that represents a TypeScript class or null
74
+ * when unable to find the class.
75
+ *
76
+ * This function searches for class declarations within the provided AST node
77
+ * using ast-grep's pattern matching capabilities.
78
+ *
79
+ * @param node - The AST node to search within for class declarations
80
+ * @returns The SgNode representing the class or null if not found
81
+ *
82
+ * @example
83
+ * const classNode = inspectClass(rootNode)
84
+ * if (classNode) {
85
+ * console.log('Found class:', classNode.text())
86
+ * }
87
+ */
38
88
  function inspectClass(node) {
39
89
  return node.find({ rule: { kind: "class_declaration" } });
40
90
  }
91
+ /**
92
+ * Returns an array of SgNodes for class methods. The input node
93
+ * must represent a class.
94
+ *
95
+ * This function finds all method definitions within a class node,
96
+ * including both regular methods and static methods.
97
+ *
98
+ * @param node - The AST node representing a class to search for methods
99
+ * @returns Array of SgNodes representing method definitions within the class
100
+ *
101
+ * @example
102
+ * const classNode = inspectClass(rootNode)
103
+ * if (classNode) {
104
+ * const methods = inspectClassMethods(classNode)
105
+ * methods.forEach(method => console.log('Method:', method.text()))
106
+ * }
107
+ */
41
108
  function inspectClassMethods(node) {
42
109
  return node.findAll({ rule: { kind: "method_definition" } });
43
110
  }
111
+ /**
112
+ * Converts an SgNode to plain text by removing whitespaces,
113
+ * indentation and comments in between. Tested with the following
114
+ * children nodes only.
115
+ *
116
+ * - MemberExpression
117
+ * - Identifier
118
+ *
119
+ * This function recursively traverses the AST node and extracts only
120
+ * the meaningful text content without any formatting or whitespace.
121
+ *
122
+ * @param node - The AST node to convert to plain text
123
+ * @returns String representation of the node without formatting
124
+ *
125
+ * @example
126
+ * const memberExpression = node.find({ rule: { kind: 'member_expression' } })
127
+ * const plainText = nodeToPlainText(memberExpression)
128
+ * console.log(plainText) // 'user.validate'
129
+ */
44
130
  function nodeToPlainText(node) {
45
131
  let out = [];
46
132
  function toText(one) {
@@ -51,6 +137,26 @@ function nodeToPlainText(node) {
51
137
  toText(node);
52
138
  return out.join("");
53
139
  }
140
+ /**
141
+ * Inspects arguments for one or more method calls. If you want to
142
+ * scope the search within a specific context, then make sure to
143
+ * first narrow down the AST and pass a specific SgNode.
144
+ *
145
+ * For example: In case of validators, we will first find the Controller
146
+ * method for which we want the validation method calls.
147
+ *
148
+ * This function searches for call expressions that match the provided method
149
+ * names and returns their argument nodes for further analysis.
150
+ *
151
+ * @param node - The AST node to search within for method calls
152
+ * @param methodCalls - Array of method call names to search for (supports dot notation)
153
+ * @returns Array of SgNodes representing the arguments of matching method calls
154
+ *
155
+ * @example
156
+ * const controllerMethod = classNode.find({ rule: { kind: 'method_definition' } })
157
+ * const validatorArgs = inspectMethodArguments(controllerMethod, ['validate', 'request.validate'])
158
+ * validatorArgs.forEach(arg => console.log('Validator argument:', arg.text()))
159
+ */
54
160
  function inspectMethodArguments(node, methodCalls) {
55
161
  return node.findAll({ rule: { any: methodCalls.map((methodCall) => {
56
162
  return { pattern: {
@@ -61,12 +167,39 @@ function inspectMethodArguments(node, methodCalls) {
61
167
  return matchingExpression.findAll({ rule: { kind: "arguments" } });
62
168
  });
63
169
  }
170
+ /**
171
+ * Inspect the validator direct usage code snippets. A member expression
172
+ * calling the ".validate" method is considered as direct usage of
173
+ * the validator.
174
+ *
175
+ * This function specifically looks for patterns where validators are called
176
+ * directly with the `.validate()` method, which is common in AdonisJS applications.
177
+ *
178
+ * @param node - The AST node to search within for validator direct usage
179
+ * @returns Array of SgNodes representing validator expressions that call validate method
180
+ *
181
+ * @example
182
+ * const methodNode = classNode.find({ rule: { kind: 'method_definition' } })
183
+ * const validators = searchValidatorDirectUsage(methodNode)
184
+ * validators.forEach(validator => {
185
+ * console.log('Direct validator usage:', nodeToPlainText(validator))
186
+ * })
187
+ */
64
188
  function searchValidatorDirectUsage(node) {
65
189
  return node.findAll({ rule: { pattern: {
66
190
  context: "$$$VALIDATOR.validate($$$)",
67
191
  selector: "call_expression"
68
192
  } } }).flatMap((expression) => {
193
+ /**
194
+ * Since we capture all "$$$.validate" calls, the first node
195
+ * within the call expression will be a member expression
196
+ * and its property identifier will be "validate".
197
+ *
198
+ * What we need is the text of this member expression without the
199
+ * comments
200
+ */
69
201
  return expression.getMultipleMatches("VALIDATOR");
70
202
  });
71
203
  }
204
+ //#endregion
72
205
  export { findImport, inspectClass, inspectClassMethods, inspectMethodArguments, nodeToPlainText, searchValidatorDirectUsage };
@@ -1,29 +1,4 @@
1
- import "../../virtual_file_system-bGeoWsK-.js";
2
- import { t as IndexGeneratorSource } from "../../source-dVeugJ0e.js";
3
- var IndexGenerator = class {
4
- appRoot;
5
- #sources = {};
6
- #cliLogger;
7
- constructor(appRoot, cliLogger) {
8
- this.appRoot = appRoot;
9
- this.#cliLogger = cliLogger;
10
- }
11
- add(name, config) {
12
- this.#sources[name] = new IndexGeneratorSource(name, this.appRoot, this.#cliLogger, config);
13
- return this;
14
- }
15
- async addFile(filePath) {
16
- const sources = Object.values(this.#sources);
17
- for (let source of sources) await source.addFile(filePath);
18
- }
19
- async removeFile(filePath) {
20
- const sources = Object.values(this.#sources);
21
- for (let source of sources) await source.removeFile(filePath);
22
- }
23
- async generate() {
24
- const sources = Object.values(this.#sources);
25
- for (let source of sources) await source.generate();
26
- if (sources.length) this.#cliLogger.info(`codegen: created ${sources.length} file(s)`);
27
- }
28
- };
1
+ import "../../chunk-DF48asd8.js";
2
+ import "../../virtual_file_system-dzfXNwEp.js";
3
+ import { t as IndexGenerator } from "../../main-INOi9swJ.js";
29
4
  export { IndexGenerator };
@@ -1 +1,2 @@
1
+ import "../../chunk-DF48asd8.js";
1
2
  export {};
@@ -40,7 +40,6 @@ export declare function runNode(cwd: string | URL, options: RunScriptOptions): i
40
40
  buffer: false;
41
41
  stdio: "pipe" | "inherit";
42
42
  env: {
43
- TZ?: string | undefined;
44
43
  FORCE_COLOR?: string | undefined;
45
44
  };
46
45
  }>;
@@ -62,7 +61,6 @@ export declare function run(cwd: string | URL, options: Omit<RunScriptOptions, '
62
61
  buffer: false;
63
62
  stdio: "pipe" | "inherit";
64
63
  env: {
65
- TZ?: string | undefined;
66
64
  FORCE_COLOR?: string | undefined;
67
65
  };
68
66
  }>;
@@ -19,8 +19,40 @@ import { fdir } from "fdir";
19
19
  import lodash from "@poppinss/utils/lodash";
20
20
  import { Lang, parse } from "@ast-grep/napi";
21
21
  import picomatch from "picomatch";
22
+ //#region src/debug.ts
23
+ /**
24
+ * Debug logger for the AdonisJS assembler package.
25
+ *
26
+ * This debug instance is configured to log messages under the 'adonisjs:assembler'
27
+ * namespace. Debug messages are only shown when the NODE_DEBUG environment variable
28
+ * includes 'adonisjs:assembler'.
29
+ *
30
+ * @example
31
+ * // Enable debug logging
32
+ * // NODE_DEBUG=adonisjs:assembler node ace serve
33
+ * debug('Starting development server...')
34
+ */
22
35
  var debug_default = debuglog("adonisjs:assembler");
36
+ //#endregion
37
+ //#region src/utils.ts
38
+ /**
39
+ * Default set of args to pass in order to run TypeScript
40
+ * source. Used by "run" and "runNode" scripts
41
+ */
23
42
  const DEFAULT_NODE_ARGS = ["--import=@poppinss/ts-exec", "--enable-source-maps"];
43
+ /**
44
+ * Parses tsconfig.json and prints errors using typescript compiler host
45
+ *
46
+ * This function reads and parses the tsconfig.json file from the given directory,
47
+ * handling diagnostic errors and returning a parsed configuration that can be
48
+ * used by other TypeScript operations.
49
+ *
50
+ * @deprecated While we are experimenting with the readTsConfig method
51
+ *
52
+ * @param cwd - The current working directory URL or string path
53
+ * @param ts - TypeScript module reference
54
+ * @returns Parsed TypeScript configuration or undefined if parsing failed
55
+ */
24
56
  function parseConfig(cwd, ts) {
25
57
  const cwdPath = typeof cwd === "string" ? cwd : fileURLToPath(cwd);
26
58
  const configFile = join$1(cwdPath, "tsconfig.json");
@@ -70,6 +102,17 @@ function readTsConfig(cwd) {
70
102
  return null;
71
103
  }
72
104
  }
105
+ /**
106
+ * Runs a Node.js script as a child process and inherits the stdio streams
107
+ *
108
+ * This function spawns a Node.js child process with TypeScript support enabled
109
+ * by default through ts-exec. It's primarily used for running development
110
+ * servers and test scripts.
111
+ *
112
+ * @param cwd - The current working directory URL or string path
113
+ * @param options - Script execution options including args, environment, etc.
114
+ * @returns Child process instance from execa
115
+ */
73
116
  function runNode(cwd, options) {
74
117
  return execaNode(options.script, options.scriptArgs, {
75
118
  nodeOptions: DEFAULT_NODE_ARGS.concat(options.nodeArgs),
@@ -86,6 +129,16 @@ function runNode(cwd, options) {
86
129
  }
87
130
  });
88
131
  }
132
+ /**
133
+ * Runs a script as a child process and inherits the stdio streams
134
+ *
135
+ * This function spawns a generic child process for running any executable
136
+ * script. Unlike runNode, this doesn't include TypeScript-specific Node.js arguments.
137
+ *
138
+ * @param cwd - The current working directory URL or string path
139
+ * @param options - Script execution options (excluding nodeArgs)
140
+ * @returns Child process instance from execa
141
+ */
89
142
  function run(cwd, options) {
90
143
  return execa(options.script, options.scriptArgs, {
91
144
  preferLocal: true,
@@ -100,24 +153,81 @@ function run(cwd, options) {
100
153
  }
101
154
  });
102
155
  }
156
+ /**
157
+ * Watches the file system using chokidar with the provided options
158
+ *
159
+ * Creates a file system watcher that monitors the current directory
160
+ * for changes, supporting various chokidar options for customization.
161
+ *
162
+ * @param options - Chokidar watch options
163
+ * @returns Chokidar FSWatcher instance
164
+ */
103
165
  function watch(options) {
104
166
  return chokidar.watch(["."], options);
105
167
  }
168
+ /**
169
+ * Returns the port to use after inspecting the dot-env files inside
170
+ * a given directory.
171
+ *
172
+ * A random port is used when the specified port is in use. Following
173
+ * is the logic for finding a specified port:
174
+ *
175
+ * - The "process.env.PORT" value is used if exists.
176
+ * - The dot-env files are loaded using the "EnvLoader" and the PORT
177
+ * value is used by iterating over all the loaded files. The
178
+ * iteration stops after first find.
179
+ * - Falls back to port 3333 if no PORT is found in environment files.
180
+ *
181
+ * @param cwd - The current working directory URL
182
+ * @returns Promise resolving to an available port number
183
+ */
106
184
  async function getPort(cwd) {
185
+ /**
186
+ * Use existing port if exists
187
+ */
107
188
  if (process.env.PORT) return getRandomPort({ port: Number(process.env.PORT) });
189
+ /**
190
+ * Loop over files and use the port from their contents. Stops
191
+ * after first match
192
+ */
108
193
  const files = await new EnvLoader(cwd).load();
109
194
  for (let file of files) {
110
195
  const envVariables = await new EnvParser(file.contents, cwd).parse();
111
196
  if (envVariables.PORT) return getRandomPort({ port: Number(envVariables.PORT) });
112
197
  }
198
+ /**
199
+ * Use 3333 as the port
200
+ */
113
201
  return getRandomPort({ port: 3333 });
114
202
  }
203
+ /**
204
+ * Helper function to copy files from relative paths or glob patterns
205
+ *
206
+ * This function handles copying files and directories while preserving
207
+ * directory structure. It supports both direct file paths and glob patterns,
208
+ * and automatically filters out junk files.
209
+ *
210
+ * @param files - Array of file paths or glob patterns to copy
211
+ * @param cwd - Source directory path
212
+ * @param outDir - Destination directory path
213
+ * @returns Promise resolving when all files are copied
214
+ */
115
215
  async function copyFiles(files, cwd, outDir) {
216
+ /**
217
+ * Looping over files and create a new collection with paths
218
+ * and glob patterns
219
+ */
116
220
  const { paths, patterns } = files.reduce((result, file) => {
221
+ /**
222
+ * If file is a glob pattern, then push it to patterns
223
+ */
117
224
  if (fastGlob.isDynamicPattern(file)) {
118
225
  result.patterns.push(file);
119
226
  return result;
120
227
  }
228
+ /**
229
+ * Otherwise, check if file exists and push it to paths to copy
230
+ */
121
231
  if (existsSync(join$1(cwd, file))) result.paths.push(file);
122
232
  return result;
123
233
  }, {
@@ -125,12 +235,19 @@ async function copyFiles(files, cwd, outDir) {
125
235
  paths: []
126
236
  });
127
237
  debug_default("copyFiles inputs: %O, paths: %O, patterns: %O", files, paths, patterns);
238
+ /**
239
+ * Getting list of relative paths from glob patterns
240
+ */
128
241
  const filePaths = paths.concat(await fastGlob(patterns, {
129
242
  cwd,
130
243
  dot: true
131
244
  })).filter((file) => {
132
245
  return !isJunk(basename(file));
133
246
  });
247
+ /**
248
+ * Finally copy files to the destination by keeping the same
249
+ * directory structure and ignoring junk files
250
+ */
134
251
  debug_default("copying files %O to destination \"%s\"", filePaths, outDir);
135
252
  const copyPromises = filePaths.map(async (file) => {
136
253
  const src = isAbsolute(file) ? file : join$1(cwd, file);
@@ -140,6 +257,17 @@ async function copyFiles(files, cwd, outDir) {
140
257
  });
141
258
  return await Promise.all(copyPromises);
142
259
  }
260
+ /**
261
+ * Memoize a function using an LRU cache. The function must accept
262
+ * only one argument as a string value.
263
+ *
264
+ * This utility provides caching for expensive function calls to improve
265
+ * performance by storing results in memory.
266
+ *
267
+ * @param fn - Function to memoize (only first argument is considered for memoization)
268
+ * @param maxKeys - Optional maximum number of cached keys
269
+ * @returns Memoized version of the function
270
+ */
143
271
  function memoize(fn, maxKeys) {
144
272
  const cache = new Cache({ max: maxKeys });
145
273
  return (input, ...args) => {
@@ -147,9 +275,28 @@ function memoize(fn, maxKeys) {
147
275
  return fn(input, ...args);
148
276
  };
149
277
  }
278
+ /**
279
+ * Returns a boolean telling if the path value is a relative
280
+ * path starting with "./" or "../"
281
+ *
282
+ * @param pathValue - The path string to check
283
+ * @returns True if the path is relative, false otherwise
284
+ */
150
285
  function isRelative(pathValue) {
151
286
  return pathValue.startsWith("./") || pathValue.startsWith("../");
152
287
  }
288
+ /**
289
+ * Imports a selected set of lazy hooks and creates an instance of the
290
+ * Hooks class
291
+ *
292
+ * This function dynamically imports and initializes hooks based on the
293
+ * provided configuration, supporting different types of hooks for various
294
+ * assembler operations.
295
+ *
296
+ * @param rcFileHooks - Hook configuration from the RC file
297
+ * @param names - Array of hook names to load
298
+ * @returns Promise resolving to configured Hooks instance
299
+ */
153
300
  async function loadHooks(rcFileHooks, names) {
154
301
  const groups = names.map((name) => {
155
302
  return {
@@ -162,6 +309,18 @@ async function loadHooks(rcFileHooks, names) {
162
309
  else hooks.add(group, await importDefault(item));
163
310
  return hooks;
164
311
  }
312
+ /**
313
+ * Wraps a function inside another function that throttles the concurrent
314
+ * executions of a function. If the function is called too quickly, then
315
+ * it may result in two invocations at max.
316
+ *
317
+ * This utility prevents overwhelming the system with rapid successive calls
318
+ * by ensuring only one execution happens at a time, with at most one queued call.
319
+ *
320
+ * @param fn - Function to throttle
321
+ * @param name - Optional name for debugging purposes
322
+ * @returns Throttled version of the function
323
+ */
165
324
  function throttle(fn, name) {
166
325
  name = name || "throttled";
167
326
  let isBusy = false;
@@ -187,28 +346,83 @@ function throttle(fn, name) {
187
346
  }
188
347
  return throttled;
189
348
  }
349
+ /**
350
+ * Removes the file extension from a file path
351
+ *
352
+ * @param filePath - The file path with extension
353
+ * @returns The file path without extension
354
+ */
190
355
  function removeExtension(filePath) {
191
356
  return filePath.substring(0, filePath.lastIndexOf("."));
192
357
  }
358
+ //#endregion
359
+ //#region src/virtual_file_system.ts
193
360
  const BYPASS_FN = (input) => input;
194
361
  const DEFAULT_GLOB = [
195
362
  "**/!(*.d).ts",
196
363
  "**/*.tsx",
197
364
  "**/*.js"
198
365
  ];
366
+ /**
367
+ * Virtual file system for managing and tracking files with AST parsing capabilities.
368
+ *
369
+ * The VirtualFileSystem provides an abstraction layer over the physical file system,
370
+ * allowing efficient file scanning, filtering, and AST parsing with caching. It's
371
+ * designed to work with TypeScript/JavaScript files and provides various output
372
+ * formats for different use cases.
373
+ *
374
+ * @example
375
+ * const vfs = new VirtualFileSystem('/src', { glob: ['**\/*.ts'] })
376
+ * await vfs.scan()
377
+ * const fileTree = vfs.asTree()
378
+ * const astNode = await vfs.get('/src/app.ts')
379
+ */
199
380
  var VirtualFileSystem = class {
381
+ /**
382
+ * Absolute path to the source directory from where to read the files.
383
+ * Additionally, a glob pattern or a filter could be specified to
384
+ * narrow down the scanned files list.
385
+ */
200
386
  #source;
387
+ /**
388
+ * Filesystem options
389
+ */
201
390
  #options;
391
+ /**
392
+ * Files collected from the initial scan with pre-computed relative paths
393
+ */
202
394
  #files = /* @__PURE__ */ new Map();
395
+ /**
396
+ * LRU cache storing parsed AST nodes by file path with size limit
397
+ */
203
398
  #astCache = new Cache({ max: 60 });
399
+ /**
400
+ * Matcher is defined when glob is defined via the options
401
+ */
204
402
  #matcher;
403
+ /**
404
+ * Picomatch options used for file pattern matching
405
+ */
205
406
  #picoMatchOptions;
407
+ /**
408
+ * Create a new VirtualFileSystem instance
409
+ *
410
+ * @param source - Absolute path to the source directory
411
+ * @param options - Optional configuration for file filtering and processing
412
+ */
206
413
  constructor(source, options) {
207
414
  this.#source = source;
208
415
  this.#options = options ?? {};
209
416
  this.#picoMatchOptions = { cwd: this.#source };
210
417
  this.#matcher = picomatch(this.#options.glob ?? DEFAULT_GLOB, this.#picoMatchOptions);
211
418
  }
419
+ /**
420
+ * Scans the filesystem to collect the files. Newly files must
421
+ * be added via the ".add" method.
422
+ *
423
+ * This method performs an initial scan of the source directory using
424
+ * the configured glob patterns and populates the internal file list.
425
+ */
212
426
  async scan() {
213
427
  debug_default("fetching entities from source \"%s\"", this.#source);
214
428
  const crawler = new fdir().globWithOptions(this.#options.glob ?? DEFAULT_GLOB, this.#picoMatchOptions).withFullPaths();
@@ -223,11 +437,37 @@ var VirtualFileSystem = class {
223
437
  this.#files.set(filePath, relativePath);
224
438
  }
225
439
  }
440
+ /**
441
+ * Check if a given file is part of the virtual file system. The method
442
+ * checks for the scanned files as well as glob pattern matches.
443
+ *
444
+ * @param filePath - Absolute file path to check
445
+ * @returns True if the file is tracked or matches the configured patterns
446
+ */
226
447
  has(filePath) {
448
+ /**
449
+ * File is already tracked as part of the initial scan
450
+ */
227
451
  if (this.#files.has(filePath)) return true;
452
+ /**
453
+ * Return false if file is not within the source dir
454
+ */
228
455
  if (!filePath.startsWith(this.#source)) return false;
456
+ /**
457
+ * If a match exists, then check if the file matches via the
458
+ * matcher test
459
+ */
229
460
  return this.#matcher(filePath);
230
461
  }
462
+ /**
463
+ * Returns the files as a flat list of key-value pairs
464
+ *
465
+ * Converts the tracked files into a flat object where keys are relative
466
+ * paths (without extensions) and values are absolute file paths.
467
+ *
468
+ * @param options - Optional transformation functions for keys and values
469
+ * @returns Object with file mappings
470
+ */
231
471
  asList(options) {
232
472
  const list = {};
233
473
  const transformKey = options?.transformKey ?? BYPASS_FN;
@@ -235,6 +475,15 @@ var VirtualFileSystem = class {
235
475
  for (const [filePath, relativePath] of this.#files) list[transformKey(relativePath)] = transformValue(filePath);
236
476
  return list;
237
477
  }
478
+ /**
479
+ * Returns the files as a nested tree structure
480
+ *
481
+ * Converts the tracked files into a hierarchical object structure that
482
+ * mirrors the directory structure of the source files.
483
+ *
484
+ * @param options - Optional transformation functions for keys and values
485
+ * @returns Nested object representing the file tree
486
+ */
238
487
  asTree(options) {
239
488
  const list = {};
240
489
  const transformKey = options?.transformKey ?? BYPASS_FN;
@@ -245,6 +494,13 @@ var VirtualFileSystem = class {
245
494
  }
246
495
  return list;
247
496
  }
497
+ /**
498
+ * Add a new file to the virtual file system. File is only added when it
499
+ * matches the pre-defined filters.
500
+ *
501
+ * @param filePath - Absolute path of the file to add
502
+ * @returns True if the file was added, false if it doesn't match filters
503
+ */
248
504
  add(filePath) {
249
505
  if (this.has(filePath)) {
250
506
  debug_default("adding new \"%s\" file to the virtual file system", filePath);
@@ -254,10 +510,26 @@ var VirtualFileSystem = class {
254
510
  }
255
511
  return false;
256
512
  }
513
+ /**
514
+ * Remove a file from the virtual file system
515
+ *
516
+ * @param filePath - Absolute path of the file to remove
517
+ * @returns True if the file was removed, false if it wasn't tracked
518
+ */
257
519
  remove(filePath) {
258
520
  debug_default("removing \"%s\" file from virtual file system", filePath);
259
521
  return this.#files.delete(filePath);
260
522
  }
523
+ /**
524
+ * Returns the file contents as AST-grep node and caches it
525
+ * forever. Use the "invalidate" method to remove it from the cache.
526
+ *
527
+ * This method reads the file content, parses it into an AST using ast-grep,
528
+ * and caches the result for future requests to improve performance.
529
+ *
530
+ * @param filePath - The absolute path to the file to parse
531
+ * @returns Promise resolving to the AST-grep node
532
+ */
261
533
  async get(filePath) {
262
534
  const cached = this.#astCache.get(filePath);
263
535
  if (cached) {
@@ -269,6 +541,14 @@ var VirtualFileSystem = class {
269
541
  this.#astCache.set(filePath, parse(Lang.TypeScript, fileContents).root());
270
542
  return this.#astCache.get(filePath);
271
543
  }
544
+ /**
545
+ * Invalidates AST cache for a single file or all files
546
+ *
547
+ * Use this method when files have been modified to ensure fresh
548
+ * AST parsing on subsequent get() calls.
549
+ *
550
+ * @param filePath - Optional file path to clear. If omitted, clears entire cache
551
+ */
272
552
  invalidate(filePath) {
273
553
  if (filePath) {
274
554
  debug_default("invalidate AST cache \"%s\"", filePath);
@@ -278,8 +558,15 @@ var VirtualFileSystem = class {
278
558
  this.#astCache.clear();
279
559
  }
280
560
  }
561
+ /**
562
+ * Clear all scanned files from memory
563
+ *
564
+ * Removes all tracked files from the internal file list, effectively
565
+ * resetting the virtual file system.
566
+ */
281
567
  clear() {
282
568
  this.#files.clear();
283
569
  }
284
570
  };
571
+ //#endregion
285
572
  export { loadHooks as a, readTsConfig as c, runNode as d, throttle as f, isRelative as i, removeExtension as l, debug_default as m, copyFiles as n, memoize as o, watch as p, getPort as r, parseConfig as s, VirtualFileSystem as t, run as u };