@cleocode/nexus 2026.9.8 → 2026.9.10

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 (68) hide show
  1. package/dist/src/code/parser.d.ts +19 -1
  2. package/dist/src/code/parser.d.ts.map +1 -1
  3. package/dist/src/code/parser.js +61 -1
  4. package/dist/src/code/parser.js.map +1 -1
  5. package/dist/src/intelligence/impact.d.ts +9 -0
  6. package/dist/src/intelligence/impact.d.ts.map +1 -1
  7. package/dist/src/intelligence/impact.js +25 -13
  8. package/dist/src/intelligence/impact.js.map +1 -1
  9. package/dist/src/pipeline/call-processor.d.ts +4 -1
  10. package/dist/src/pipeline/call-processor.d.ts.map +1 -1
  11. package/dist/src/pipeline/call-processor.js +43 -3
  12. package/dist/src/pipeline/call-processor.js.map +1 -1
  13. package/dist/src/pipeline/community-processor.d.ts.map +1 -1
  14. package/dist/src/pipeline/community-processor.js +6 -27
  15. package/dist/src/pipeline/community-processor.js.map +1 -1
  16. package/dist/src/pipeline/extractors/typescript-extractor.d.ts +27 -35
  17. package/dist/src/pipeline/extractors/typescript-extractor.d.ts.map +1 -1
  18. package/dist/src/pipeline/extractors/typescript-extractor.js +100 -213
  19. package/dist/src/pipeline/extractors/typescript-extractor.js.map +1 -1
  20. package/dist/src/pipeline/filesystem-walker.d.ts +9 -5
  21. package/dist/src/pipeline/filesystem-walker.d.ts.map +1 -1
  22. package/dist/src/pipeline/filesystem-walker.js +154 -79
  23. package/dist/src/pipeline/filesystem-walker.js.map +1 -1
  24. package/dist/src/pipeline/heritage-processor.d.ts.map +1 -1
  25. package/dist/src/pipeline/heritage-processor.js +29 -4
  26. package/dist/src/pipeline/heritage-processor.js.map +1 -1
  27. package/dist/src/pipeline/import-processor.d.ts +28 -6
  28. package/dist/src/pipeline/import-processor.d.ts.map +1 -1
  29. package/dist/src/pipeline/import-processor.js +68 -45
  30. package/dist/src/pipeline/import-processor.js.map +1 -1
  31. package/dist/src/pipeline/index.d.ts +32 -20
  32. package/dist/src/pipeline/index.d.ts.map +1 -1
  33. package/dist/src/pipeline/index.js +173 -148
  34. package/dist/src/pipeline/index.js.map +1 -1
  35. package/dist/src/pipeline/knowledge-graph.d.ts +3 -1
  36. package/dist/src/pipeline/knowledge-graph.d.ts.map +1 -1
  37. package/dist/src/pipeline/knowledge-graph.js +36 -2
  38. package/dist/src/pipeline/knowledge-graph.js.map +1 -1
  39. package/dist/src/pipeline/lexical-scope.d.ts +60 -0
  40. package/dist/src/pipeline/lexical-scope.d.ts.map +1 -0
  41. package/dist/src/pipeline/lexical-scope.js +362 -0
  42. package/dist/src/pipeline/lexical-scope.js.map +1 -0
  43. package/dist/src/pipeline/parse-loop.d.ts +49 -2
  44. package/dist/src/pipeline/parse-loop.d.ts.map +1 -1
  45. package/dist/src/pipeline/parse-loop.js +346 -144
  46. package/dist/src/pipeline/parse-loop.js.map +1 -1
  47. package/dist/src/pipeline/processors/access-processor.d.ts +27 -14
  48. package/dist/src/pipeline/processors/access-processor.d.ts.map +1 -1
  49. package/dist/src/pipeline/processors/access-processor.js +106 -27
  50. package/dist/src/pipeline/processors/access-processor.js.map +1 -1
  51. package/dist/src/pipeline/structure-processor.d.ts.map +1 -1
  52. package/dist/src/pipeline/structure-processor.js +1 -0
  53. package/dist/src/pipeline/structure-processor.js.map +1 -1
  54. package/dist/src/pipeline/symbol-table.d.ts +41 -3
  55. package/dist/src/pipeline/symbol-table.d.ts.map +1 -1
  56. package/dist/src/pipeline/symbol-table.js +104 -2
  57. package/dist/src/pipeline/symbol-table.js.map +1 -1
  58. package/dist/src/pipeline/workers/parse-worker.d.ts +29 -92
  59. package/dist/src/pipeline/workers/parse-worker.d.ts.map +1 -1
  60. package/dist/src/pipeline/workers/parse-worker.js +49 -1110
  61. package/dist/src/pipeline/workers/parse-worker.js.map +1 -1
  62. package/dist/src/pipeline/workers/worker-pool.d.ts +6 -4
  63. package/dist/src/pipeline/workers/worker-pool.d.ts.map +1 -1
  64. package/dist/src/pipeline/workers/worker-pool.js +112 -22
  65. package/dist/src/pipeline/workers/worker-pool.js.map +1 -1
  66. package/dist/tsconfig.build.tsbuildinfo +1 -1
  67. package/dist/tsconfig.tsbuildinfo +1 -1
  68. package/package.json +3 -2
@@ -1,1127 +1,66 @@
1
1
  /**
2
- * Parse worker thread script for parallel multi-file TypeScript/JavaScript parsing.
3
- *
4
- * Runs in a Node.js Worker thread spawned by the worker pool. Receives file
5
- * batches via structured IPC, parses each file with tree-sitter, extracts
6
- * symbols/imports/heritage/calls using the CLEO TypeScript extractor, and
7
- * returns accumulated results via a flush message.
8
- *
9
- * IPC protocol (mirrors GitNexus parse-worker.ts):
10
- * Incoming: { type: 'sub-batch', files: ParseWorkerInput[] }
11
- * | { type: 'flush' }
12
- * Outgoing: { type: 'sub-batch-done' }
13
- * | { type: 'result', data: ParseWorkerResult }
14
- * | { type: 'progress', filesProcessed: number }
15
- * | { type: 'error', error: string }
16
- *
17
- * @task T540
18
- * @module pipeline/workers/parse-worker
2
+ * Owned parser executable for worker-thread and process IPC transports.
3
+ * Calls the per-file extractor directly; never re-enters the pipeline or pool.
4
+ * @task T12262
19
5
  */
20
- import { createRequire } from 'node:module';
6
+ import { getHeapStatistics } from 'node:v8';
21
7
  import { parentPort } from 'node:worker_threads';
22
- if (!parentPort) {
23
- throw new Error('parse-worker.ts must be run as a Worker thread, not directly.');
24
- }
25
- // ---------------------------------------------------------------------------
26
- // Tree-sitter setup (native require — must use createRequire in ESM workers)
27
- // ---------------------------------------------------------------------------
28
- const _require = createRequire(import.meta.url);
29
- let _parser = null;
30
- /**
31
- * Sanitize source content for tree-sitter parsing.
32
- *
33
- * tree-sitter 0.21.x Node.js bindings throw `Error: Invalid argument`
34
- * when source strings contain non-ASCII Unicode characters (e.g. em-dash
35
- * `—`, curly quotes, etc.) in comments. Since all structural elements that
36
- * nexus cares about (function names, export specifiers, import paths) are
37
- * ASCII, replacing non-ASCII characters with spaces is safe and preserves
38
- * line/column positions for line number reporting.
39
- *
40
- * @param content - Raw file content read from disk
41
- * @returns Content with non-ASCII characters replaced by spaces
42
- */
43
- function sanitizeForParsing(content) {
44
- // eslint-disable-next-line no-control-regex
45
- return content.replace(/[^\x00-\x7F]/g, ' ');
46
- }
47
- /**
48
- * Hard limit for tree-sitter 0.21.x: native code uses a 15-bit byte-offset
49
- * counter that overflows at 32768 characters, causing `Error: Invalid argument`.
50
- * Files larger than this threshold use the regex-based fallback extractor.
51
- */
52
- const TREE_SITTER_MAX_CHARS = 32_767;
53
- /**
54
- * Regex-based import extractor for files that exceed the tree-sitter 32K char limit.
55
- *
56
- * Extracts named import bindings from `import { ... } from '...'` statements.
57
- * Used to populate the namedImportMap so barrel tracing can fire for callers
58
- * in large files (e.g. `@cleocode/core/internal` consumers).
59
- *
60
- * @param content - Raw file content
61
- * @param filePath - File path relative to repo root
62
- * @param language - Language key (for the language field)
63
- * @param imports - Accumulator array to push results into
64
- */
65
- function extractImportsRegex(content, filePath, language, imports) {
66
- const lines = content.split('\n');
67
- let i = 0;
68
- while (i < lines.length) {
69
- const line = lines[i].trim();
70
- // Check for `import { ... } from '...'` (may span multiple lines)
71
- if (/^import\s*\{/.test(line) || /^import\s+type\s*\{/.test(line)) {
72
- let block = line;
73
- let j = i + 1;
74
- // Gather continuation lines until we have closing `}` and `from`
75
- while ((!block.includes('}') || !block.includes('from')) && j < lines.length) {
76
- block += ' ' + lines[j].trim();
77
- j++;
78
- }
79
- const fromMatch = /from\s+['"]([^'"]+)['"]/m.exec(block);
80
- if (fromMatch) {
81
- const rawImportPath = fromMatch[1];
82
- const namedBindings = [];
83
- const innerMatch = /\{([^}]+)\}/.exec(block);
84
- if (innerMatch) {
85
- const inner = innerMatch[1];
86
- const specifiers = inner
87
- .split(',')
88
- .map((s) => s.trim())
89
- .filter(Boolean);
90
- for (const spec of specifiers) {
91
- // Remove `type ` prefix from `import { type Foo }`
92
- const cleanSpec = spec.replace(/^type\s+/, '').trim();
93
- const asMatch = /^(\w+)\s+as\s+(\w+)$/.exec(cleanSpec);
94
- if (asMatch) {
95
- namedBindings.push({ local: asMatch[2], exported: asMatch[1] });
96
- }
97
- else if (/^\w+$/.test(cleanSpec)) {
98
- namedBindings.push({ local: cleanSpec, exported: cleanSpec });
99
- }
100
- }
101
- }
102
- if (namedBindings.length > 0) {
103
- imports.push({
104
- filePath,
105
- rawImportPath,
106
- language,
107
- namedBindings,
108
- });
109
- }
110
- }
111
- i = j;
112
- continue;
113
- }
114
- i++;
115
- }
116
- }
117
- /**
118
- * Reserved words and common non-call identifiers that must never be emitted as
119
- * call targets during the regex fallback.
120
- *
121
- * These appear in source with `identifier(` syntax (e.g. `if (cond)`, `for (let i`)
122
- * but are control-flow keywords, not function calls.
123
- *
124
- * Note: JavaScript built-ins (Number, String, Boolean, etc.) and type guards
125
- * (typeof, instanceof) are also excluded. This list is conservative — false
126
- * negatives (missed calls) are preferred over false positives (spurious edges).
127
- */
128
- const REGEX_CALL_RESERVED = new Set([
129
- // Control flow keywords
130
- 'if',
131
- 'else',
132
- 'for',
133
- 'while',
134
- 'do',
135
- 'switch',
136
- 'case',
137
- 'catch',
138
- 'try',
139
- 'return',
140
- 'throw',
141
- 'typeof',
142
- 'instanceof',
143
- 'in',
144
- 'of',
145
- 'new',
146
- 'delete',
147
- 'void',
148
- 'await',
149
- 'yield',
150
- 'async',
151
- 'function',
152
- 'class',
153
- 'const',
154
- 'let',
155
- 'var',
156
- 'import',
157
- 'export',
158
- 'from',
159
- 'as',
160
- 'type',
161
- 'interface',
162
- 'enum',
163
- 'default',
164
- 'break',
165
- 'continue',
166
- 'debugger',
167
- 'this',
168
- 'super',
169
- 'null',
170
- 'undefined',
171
- 'true',
172
- 'false',
173
- 'Infinity',
174
- 'NaN',
175
- // JS built-ins commonly appearing with parens (kept narrow to avoid missing
176
- // real user-defined calls with these names — shadowing is rare)
177
- 'Promise',
178
- 'Array',
179
- 'Object',
180
- 'String',
181
- 'Number',
182
- 'Boolean',
183
- 'Symbol',
184
- 'Map',
185
- 'Set',
186
- 'Date',
187
- 'RegExp',
188
- 'Error',
189
- 'Math',
190
- ]);
191
- /**
192
- * Regex-based free-call extractor for files that exceed the tree-sitter 32K char limit.
193
- *
194
- * Extracts bare identifier call sites of the form `<name>(` so that barrel-traced
195
- * named imports (T617) can still be resolved to target CALLS edges. This enables
196
- * callers from oversized files (engine files, large barrels) to register against
197
- * functions like `findTasks`, `endSession`, etc.
198
- *
199
- * Limitations:
200
- * - Only free calls are extracted; member calls (`x.foo(`) and constructor calls
201
- * (`new Foo(`) are skipped. Free calls are sufficient for named-import CALLS edges.
202
- * - The enclosing function is unknown without an AST, so `sourceId` is set to
203
- * the file node (`file:<path>`). This produces file→function CALLS edges that
204
- * `cleo nexus context` renders correctly.
205
- * - Identifiers in strings and comments may produce false positives; the guard
206
- * against common reserved words mitigates this.
207
- * - Arguments are not counted; `argCount` is omitted so Tier 3 arity filtering
208
- * does not discard valid matches.
209
- *
210
- * @param content - Raw file content
211
- * @param filePath - File path relative to repo root
212
- * @param calls - Accumulator array to push results into
213
- */
214
- function extractCallsRegex(content, filePath, calls) {
215
- // Strip single-line comments to reduce false positives. We leave block
216
- // comments alone because stripping them changes line numbers; free-call
217
- // matches in block comments are rare and will fail resolution downstream.
218
- const sanitized = content.replace(/\/\/.*$/gm, '');
219
- // The enclosing function is unknown without an AST, so the source is the
220
- // File node. Structure-processor emits File nodes with ID = relative path
221
- // (no prefix) — match that format exactly so the CALLS edge resolves.
222
- const sourceId = filePath;
223
- const seen = new Set();
224
- // Match: word-boundary identifier followed by '('. The negative lookbehind
225
- // for '.' rules out member calls (foo.bar(). We also skip if the preceding
226
- // non-space char is a letter/digit (which would indicate a longer identifier
227
- // or keyword already consumed).
228
- const pattern = /(?<![.\w$])([A-Za-z_$][\w$]*)\s*\(/g;
229
- let match = pattern.exec(sanitized);
230
- while (match !== null) {
231
- const name = match[1];
232
- if (!REGEX_CALL_RESERVED.has(name)) {
233
- // Deduplicate per-file: emit at most one call edge per (file, name)
234
- // pair. The downstream resolver would emit duplicate edges otherwise
235
- // since the file-level sourceId is shared.
236
- if (!seen.has(name)) {
237
- seen.add(name);
238
- calls.push({
239
- filePath,
240
- sourceId,
241
- calledName: name,
242
- callForm: 'free',
243
- });
244
- }
245
- }
246
- match = pattern.exec(sanitized);
247
- }
248
- }
249
- /**
250
- * Regex-based re-export extractor for files that exceed the tree-sitter 32K char limit.
251
- *
252
- * Handles the three re-export forms we care about:
253
- * - `export { Foo, Bar as Baz } from './source'`
254
- * - `export * from './source'`
255
- * - `export type { Foo } from './source'` (types only — skipped for barrel tracing)
256
- *
257
- * This is intentionally simple: we only care about re-export path resolution,
258
- * not full AST correctness. False negatives (missed exports) are acceptable
259
- * since this is a fallback for unusually large barrel files.
260
- *
261
- * @param content - File content (may include non-ASCII chars — only used on lines)
262
- * @param filePath - File path relative to repo root
263
- * @param reExports - Accumulator array to push results into
264
- */
265
- function extractReExportsRegex(content, filePath, reExports) {
266
- // Matches: export { ... } from 'path'
267
- // Also handles: export type { ... } from 'path' (we skip these — types aren't call targets)
268
- // Also handles: export * from 'path'
269
- const lines = content.split('\n');
270
- // We need to handle multi-line export { ... } from '...' blocks.
271
- // Strategy: detect `export` lines and collect continuation lines until we see `from '...'`.
272
- let i = 0;
273
- while (i < lines.length) {
274
- const line = lines[i].trim();
275
- // Wildcard re-export: `export * from '...'`
276
- const wildcardMatch = /^export\s+\*\s+from\s+['"]([^'"]+)['"]/m.exec(line);
277
- if (wildcardMatch) {
278
- reExports.push({
279
- filePath,
280
- rawSourcePath: wildcardMatch[1],
281
- exportedName: null,
282
- localName: null,
283
- });
284
- i++;
285
- continue;
286
- }
287
- // Named re-export: `export { Foo, Bar as Baz } from '...'`
288
- // May span multiple lines — collect until closing `}`
289
- if (/^export\s*\{/.test(line) && !line.startsWith('export type')) {
290
- let block = line;
291
- let j = i + 1;
292
- // If block doesn't have closing `}` yet, gather continuation lines
293
- while (!block.includes('}') && j < lines.length) {
294
- block += ' ' + lines[j].trim();
295
- j++;
296
- }
297
- // Check if it has a `from '...'` clause
298
- const fromMatch = /from\s+['"]([^'"]+)['"]/m.exec(block);
299
- if (fromMatch) {
300
- const rawSourcePath = fromMatch[1];
301
- // Extract specifiers between { and }
302
- const innerMatch = /\{([^}]+)\}/.exec(block);
303
- if (innerMatch) {
304
- const inner = innerMatch[1];
305
- const specifiers = inner
306
- .split(',')
307
- .map((s) => s.trim())
308
- .filter(Boolean);
309
- for (const spec of specifiers) {
310
- // Handle `Foo as Bar` alias
311
- const asMatch = /^(\w+)\s+as\s+(\w+)$/.exec(spec);
312
- if (asMatch) {
313
- reExports.push({
314
- filePath,
315
- rawSourcePath,
316
- exportedName: asMatch[2],
317
- localName: asMatch[1],
318
- });
319
- }
320
- else if (/^\w+$/.test(spec)) {
321
- reExports.push({
322
- filePath,
323
- rawSourcePath,
324
- exportedName: spec,
325
- localName: spec,
326
- });
327
- }
328
- }
329
- }
330
- }
331
- i = j;
332
- continue;
333
- }
334
- i++;
335
- }
336
- }
337
- function getParser() {
338
- if (_parser)
339
- return _parser;
340
- try {
341
- const ParserClass = _require('tree-sitter');
342
- _parser = new ParserClass();
343
- return _parser;
344
- }
345
- catch {
346
- return null;
347
- }
348
- }
349
- // ---------------------------------------------------------------------------
350
- // Grammar loading
351
- // ---------------------------------------------------------------------------
352
- const grammarCache = new Map();
353
- function loadGrammar(langKey) {
354
- if (grammarCache.has(langKey))
355
- return grammarCache.get(langKey) ?? null;
356
- try {
357
- if (langKey === 'typescript') {
358
- const mod = _require('tree-sitter-typescript');
359
- grammarCache.set('typescript', mod.typescript ?? null);
360
- grammarCache.set('tsx', mod.tsx ?? null);
361
- return mod.typescript ?? null;
362
- }
363
- if (langKey === 'tsx') {
364
- const mod = _require('tree-sitter-typescript');
365
- grammarCache.set('typescript', mod.typescript ?? null);
366
- grammarCache.set('tsx', mod.tsx ?? null);
367
- return mod.tsx ?? null;
368
- }
369
- if (langKey === 'javascript') {
370
- const mod = _require('tree-sitter-javascript');
371
- grammarCache.set('javascript', mod);
372
- return mod;
373
- }
374
- grammarCache.set(langKey, null);
375
- return null;
376
- }
377
- catch {
378
- grammarCache.set(langKey, null);
379
- return null;
380
- }
381
- }
382
- function grammarKeyForPath(filePath) {
383
- if (filePath.endsWith('.tsx'))
384
- return 'tsx';
385
- if (filePath.endsWith('.ts') || filePath.endsWith('.mts') || filePath.endsWith('.cts'))
386
- return 'typescript';
387
- if (filePath.endsWith('.js') ||
388
- filePath.endsWith('.mjs') ||
389
- filePath.endsWith('.cjs') ||
390
- filePath.endsWith('.jsx'))
391
- return 'javascript';
392
- return null;
393
- }
394
- // ---------------------------------------------------------------------------
395
- // Extraction helpers — pure functions, no module-level state
396
- // ---------------------------------------------------------------------------
397
- /** Convert 0-based tree-sitter row to 1-based line number. */
398
- function toLine(row) {
399
- return row + 1;
400
- }
401
- /** Derive a stable node ID from file path and symbol name. */
402
- function mkNodeId(filePath, name) {
403
- return `${filePath}::${name}`;
404
- }
405
- /** Check whether a node carries an `export` keyword or has an export_statement parent. */
406
- function isExported(node) {
407
- for (let i = 0; i < node.children.length; i++) {
408
- const child = node.children[i];
409
- if (child && !child.isNamed && child.text === 'export')
410
- return true;
411
- }
412
- return node.parent !== null && node.parent.type === 'export_statement';
413
- }
414
- /** Extract first JSDoc/line comment preceding a node. */
415
- function extractDocSummary(node) {
416
- let sibling = node.previousSibling;
417
- while (sibling?.type === 'decorator') {
418
- sibling = sibling.previousSibling;
419
- }
420
- if (!sibling || sibling.type !== 'comment')
421
- return undefined;
422
- const raw = sibling.text;
423
- if (!raw.startsWith('/**') && !raw.startsWith('//'))
424
- return undefined;
425
- const lines = raw
426
- .replace(/^\/\*\*/, '')
427
- .replace(/\*\/$/, '')
428
- .split('\n')
429
- .map((l) => l.replace(/^\s*\*\s?/, '').trim())
430
- .filter((l) => l.length > 0 && !l.startsWith('@'));
431
- return lines[0];
432
- }
433
- /** Extract parameter names from a `formal_parameters` or `parameters` node. */
434
- function extractParamNames(paramsNode) {
435
- const names = [];
436
- for (let i = 0; i < paramsNode.namedChildCount; i++) {
437
- const param = paramsNode.namedChild(i);
438
- if (!param)
439
- continue;
440
- const patternNode = param.childForFieldName('pattern') ?? param.childForFieldName('name') ?? param;
441
- const text = patternNode.text;
442
- if (text)
443
- names.push(text);
444
- }
445
- return names;
446
- }
447
- /** Read a return type annotation from a function or method node. */
448
- function extractReturnType(funcNode) {
449
- const retTypeNode = funcNode.childForFieldName('return_type');
450
- if (!retTypeNode)
451
- return undefined;
452
- const text = retTypeNode.text.replace(/^:\s*/, '').trim();
453
- return text || undefined;
454
- }
455
- // ---------------------------------------------------------------------------
456
- // Definition extraction
457
- // ---------------------------------------------------------------------------
458
- const CONTAINER_TYPES = new Set([
459
- 'program',
460
- 'module',
461
- 'namespace',
462
- 'internal_module',
463
- 'module_declaration',
464
- ]);
465
- const EXPORTABLE_DECL_TYPES = new Set([
466
- 'function_declaration',
467
- 'generator_function_declaration',
468
- 'class_declaration',
469
- 'abstract_class_declaration',
470
- 'interface_declaration',
471
- 'type_alias_declaration',
472
- 'enum_declaration',
473
- 'lexical_declaration',
474
- 'variable_declaration',
475
- ]);
476
- function walkDefinitions(node, filePath, language, symbols) {
477
- switch (node.type) {
478
- case 'function_declaration':
479
- case 'generator_function_declaration': {
480
- const nameNode = node.childForFieldName('name');
481
- if (nameNode?.text) {
482
- const paramsNode = node.childForFieldName('parameters') ?? node.childForFieldName('formal_parameters');
483
- symbols.push({
484
- id: mkNodeId(filePath, nameNode.text),
485
- kind: 'function',
486
- name: nameNode.text,
487
- filePath,
488
- startLine: toLine(node.startPosition.row),
489
- endLine: toLine(node.endPosition.row),
490
- language,
491
- exported: isExported(node),
492
- parameters: paramsNode ? extractParamNames(paramsNode) : [],
493
- returnType: extractReturnType(node),
494
- docSummary: extractDocSummary(node),
495
- });
496
- }
497
- break;
498
- }
499
- case 'class_declaration':
500
- case 'abstract_class_declaration': {
501
- const nameNode = node.childForFieldName('name');
502
- if (nameNode?.text) {
503
- const className = nameNode.text;
504
- const classId = mkNodeId(filePath, className);
505
- symbols.push({
506
- id: classId,
507
- kind: 'class',
508
- name: className,
509
- filePath,
510
- startLine: toLine(node.startPosition.row),
511
- endLine: toLine(node.endPosition.row),
512
- language,
513
- exported: isExported(node),
514
- docSummary: extractDocSummary(node),
515
- });
516
- // Extract methods and properties from class body
517
- const bodyNode = node.childForFieldName('body');
518
- if (bodyNode) {
519
- for (let i = 0; i < bodyNode.namedChildCount; i++) {
520
- const member = bodyNode.namedChild(i);
521
- if (!member)
522
- continue;
523
- if (member.type === 'method_definition' || member.type === 'method_signature') {
524
- const mNameNode = member.childForFieldName('name');
525
- if (mNameNode?.text) {
526
- const mParamsNode = member.childForFieldName('parameters');
527
- symbols.push({
528
- id: mkNodeId(filePath, `${className}.${mNameNode.text}`),
529
- kind: 'method',
530
- name: mNameNode.text,
531
- filePath,
532
- startLine: toLine(member.startPosition.row),
533
- endLine: toLine(member.endPosition.row),
534
- language,
535
- exported: false,
536
- parameters: mParamsNode ? extractParamNames(mParamsNode) : [],
537
- returnType: extractReturnType(member),
538
- parent: classId,
539
- });
540
- }
541
- }
542
- else if (member.type === 'public_field_definition' ||
543
- member.type === 'field_definition') {
544
- const fNameNode = member.childForFieldName('name');
545
- if (fNameNode?.text) {
546
- symbols.push({
547
- id: mkNodeId(filePath, `${className}.${fNameNode.text}`),
548
- kind: 'property',
549
- name: fNameNode.text,
550
- filePath,
551
- startLine: toLine(member.startPosition.row),
552
- endLine: toLine(member.endPosition.row),
553
- language,
554
- exported: false,
555
- parent: classId,
556
- });
557
- }
558
- }
559
- }
560
- }
561
- }
562
- break;
563
- }
564
- case 'interface_declaration': {
565
- const nameNode = node.childForFieldName('name');
566
- if (nameNode?.text) {
567
- symbols.push({
568
- id: mkNodeId(filePath, nameNode.text),
569
- kind: 'interface',
570
- name: nameNode.text,
571
- filePath,
572
- startLine: toLine(node.startPosition.row),
573
- endLine: toLine(node.endPosition.row),
574
- language,
575
- exported: isExported(node),
576
- docSummary: extractDocSummary(node),
577
- });
578
- }
579
- break;
580
- }
581
- case 'type_alias_declaration': {
582
- const nameNode = node.childForFieldName('name');
583
- if (nameNode?.text) {
584
- symbols.push({
585
- id: mkNodeId(filePath, nameNode.text),
586
- kind: 'type_alias',
587
- name: nameNode.text,
588
- filePath,
589
- startLine: toLine(node.startPosition.row),
590
- endLine: toLine(node.endPosition.row),
591
- language,
592
- exported: isExported(node),
593
- docSummary: extractDocSummary(node),
594
- });
595
- }
596
- break;
597
- }
598
- case 'enum_declaration': {
599
- const nameNode = node.childForFieldName('name');
600
- if (nameNode?.text) {
601
- symbols.push({
602
- id: mkNodeId(filePath, nameNode.text),
603
- kind: 'enum',
604
- name: nameNode.text,
605
- filePath,
606
- startLine: toLine(node.startPosition.row),
607
- endLine: toLine(node.endPosition.row),
608
- language,
609
- exported: isExported(node),
610
- docSummary: extractDocSummary(node),
611
- });
612
- }
613
- break;
614
- }
615
- case 'export_statement': {
616
- for (let i = 0; i < node.namedChildCount; i++) {
617
- const child = node.namedChild(i);
618
- if (child && EXPORTABLE_DECL_TYPES.has(child.type)) {
619
- walkDefinitions(child, filePath, language, symbols);
620
- }
621
- }
622
- break;
623
- }
624
- case 'lexical_declaration':
625
- case 'variable_declaration': {
626
- for (let i = 0; i < node.namedChildCount; i++) {
627
- const declarator = node.namedChild(i);
628
- if (!declarator || declarator.type !== 'variable_declarator')
629
- continue;
630
- const nameNode = declarator.childForFieldName('name');
631
- const valueNode = declarator.childForFieldName('value');
632
- if (!nameNode?.text || !valueNode)
633
- continue;
634
- if (valueNode.type !== 'arrow_function' && valueNode.type !== 'function_expression')
635
- continue;
636
- const paramsNode = valueNode.childForFieldName('parameters') ??
637
- valueNode.childForFieldName('formal_parameters');
638
- symbols.push({
639
- id: mkNodeId(filePath, nameNode.text),
640
- kind: 'function',
641
- name: nameNode.text,
642
- filePath,
643
- startLine: toLine(node.startPosition.row),
644
- endLine: toLine(node.endPosition.row),
645
- language,
646
- exported: isExported(node),
647
- parameters: paramsNode ? extractParamNames(paramsNode) : [],
648
- returnType: extractReturnType(valueNode),
649
- docSummary: extractDocSummary(node),
650
- });
651
- }
652
- break;
653
- }
654
- default:
655
- break;
656
- }
657
- if (CONTAINER_TYPES.has(node.type)) {
658
- for (let i = 0; i < node.namedChildCount; i++) {
659
- const child = node.namedChild(i);
660
- if (child)
661
- walkDefinitions(child, filePath, language, symbols);
662
- }
663
- }
664
- }
665
- // ---------------------------------------------------------------------------
666
- // Import extraction
667
- // ---------------------------------------------------------------------------
668
- function extractImports(rootNode, filePath, language, imports) {
669
- for (let i = 0; i < rootNode.namedChildCount; i++) {
670
- const stmt = rootNode.namedChild(i);
671
- if (!stmt || stmt.type !== 'import_statement')
672
- continue;
673
- const sourceNode = stmt.childForFieldName('source');
674
- if (!sourceNode)
675
- continue;
676
- let raw = sourceNode.text;
677
- if ((raw.startsWith('"') && raw.endsWith('"')) || (raw.startsWith("'") && raw.endsWith("'"))) {
678
- raw = raw.slice(1, -1);
679
- }
680
- if (!raw)
681
- continue;
682
- // Extract named bindings for Tier 2a resolution (T617).
683
- // `import_clause` is a regular (unnamed field) child of `import_statement`
684
- // in the tree-sitter TypeScript grammar — NOT a named field — so
685
- // `childForFieldName('clause')` always returns null. Find it by type.
686
- const namedBindings = [];
687
- const importClause = stmt.children.find((c) => c.type === 'import_clause') ?? null;
688
- if (importClause) {
689
- for (let j = 0; j < importClause.namedChildCount; j++) {
690
- const clauseChild = importClause.namedChild(j);
691
- if (!clauseChild)
692
- continue;
693
- if (clauseChild.type === 'named_imports') {
694
- for (let k = 0; k < clauseChild.namedChildCount; k++) {
695
- const specifier = clauseChild.namedChild(k);
696
- if (!specifier || specifier.type !== 'import_specifier')
697
- continue;
698
- const nameNode = specifier.childForFieldName('name');
699
- const aliasNode = specifier.childForFieldName('alias');
700
- if (nameNode?.text) {
701
- const exported = nameNode.text;
702
- const local = aliasNode?.text ?? exported;
703
- namedBindings.push({ local, exported });
704
- }
705
- }
706
- }
707
- // Namespace import: `import * as X from '...'`
708
- if (clauseChild.type === 'namespace_import') {
709
- const aliasNode = clauseChild.namedChild(0);
710
- if (aliasNode?.text) {
711
- namedBindings.push({ local: aliasNode.text, exported: '*' });
712
- }
713
- }
714
- // Default import: `import Foo from '...'`
715
- if (clauseChild.type === 'identifier') {
716
- const local = clauseChild.text;
717
- if (local) {
718
- namedBindings.push({ local, exported: 'default' });
719
- }
720
- }
721
- }
722
- }
723
- imports.push({
724
- filePath,
725
- rawImportPath: raw,
726
- language,
727
- namedBindings: namedBindings.length > 0 ? namedBindings : undefined,
728
- });
729
- }
730
- }
731
- // ---------------------------------------------------------------------------
732
- // Re-export extraction (barrel files — T617)
733
- // ---------------------------------------------------------------------------
734
- function extractReExports(rootNode, filePath, reExports) {
735
- for (let i = 0; i < rootNode.namedChildCount; i++) {
736
- const stmt = rootNode.namedChild(i);
737
- if (!stmt || stmt.type !== 'export_statement')
738
- continue;
739
- // Only care about re-exports: `export ... from '...'`
740
- const sourceNode = stmt.childForFieldName('source');
741
- if (!sourceNode)
742
- continue;
743
- const rawSource = sourceNode.text.replace(/^['"]|['"]$/g, '');
744
- if (!rawSource)
745
- continue;
746
- // Detect `export * from '...'` vs `export { ... } from '...'`
747
- let isWildcard = false;
748
- let hasNamespace = false;
749
- for (let j = 0; j < stmt.children.length; j++) {
750
- const child = stmt.children[j];
751
- if (!child)
752
- continue;
753
- if (!child.isNamed && child.text === '*')
754
- isWildcard = true;
755
- if (child.type === 'namespace_export')
756
- hasNamespace = true;
757
- }
758
- if (isWildcard && !hasNamespace) {
759
- reExports.push({ filePath, rawSourcePath: rawSource, exportedName: null, localName: null });
760
- continue;
761
- }
762
- if (hasNamespace)
763
- continue; // `export * as ns from '...'` — skip
764
- // Named re-exports: `export { Foo, Bar as Baz } from '...'`
765
- for (let j = 0; j < stmt.namedChildCount; j++) {
766
- const child = stmt.namedChild(j);
767
- if (!child)
768
- continue;
769
- if (child.type !== 'export_clause' && child.type !== 'named_exports')
770
- continue;
771
- for (let k = 0; k < child.namedChildCount; k++) {
772
- const specifier = child.namedChild(k);
773
- if (!specifier || specifier.type !== 'export_specifier')
774
- continue;
775
- const nameNode = specifier.childForFieldName('name');
776
- const aliasNode = specifier.childForFieldName('alias');
777
- if (!nameNode)
778
- continue;
779
- const localName = nameNode.text;
780
- const exportedName = aliasNode?.text ?? localName;
781
- if (localName && exportedName) {
782
- reExports.push({ filePath, rawSourcePath: rawSource, exportedName, localName });
783
- }
784
- }
785
- }
786
- }
787
- }
788
- // ---------------------------------------------------------------------------
789
- // Heritage extraction
790
- // ---------------------------------------------------------------------------
791
- function extractHeritage(rootNode, filePath, heritage, symbols) {
792
- function walk(node) {
793
- if (node.type === 'class_declaration' || node.type === 'abstract_class_declaration') {
794
- const nameNode = node.childForFieldName('name');
795
- const className = nameNode?.text;
796
- if (className) {
797
- const typeNodeId = mkNodeId(filePath, className);
798
- const clauseNode = node.childForFieldName('type_parameters')
799
- ? node.childForFieldName('heritage')
800
- : null;
801
- // Walk children for heritage clauses
802
- for (let i = 0; i < node.namedChildCount; i++) {
803
- const child = node.namedChild(i);
804
- if (!child)
805
- continue;
806
- if (child.type === 'class_heritage') {
807
- for (let j = 0; j < child.namedChildCount; j++) {
808
- const clause = child.namedChild(j);
809
- if (!clause)
810
- continue;
811
- if (clause.type === 'extends_clause') {
812
- for (let k = 0; k < clause.namedChildCount; k++) {
813
- const parent = clause.namedChild(k);
814
- if (parent?.text) {
815
- // Strip type parameters e.g., Base<T> -> Base
816
- const parentName = parent.text.replace(/<.*>$/, '').trim();
817
- if (parentName) {
818
- heritage.push({
819
- filePath,
820
- typeName: className,
821
- typeNodeId,
822
- kind: 'extends',
823
- parentName,
824
- });
825
- }
826
- }
827
- }
828
- }
829
- else if (clause.type === 'implements_clause') {
830
- for (let k = 0; k < clause.namedChildCount; k++) {
831
- const iface = clause.namedChild(k);
832
- if (iface?.text) {
833
- const parentName = iface.text.replace(/<.*>$/, '').trim();
834
- if (parentName) {
835
- heritage.push({
836
- filePath,
837
- typeName: className,
838
- typeNodeId,
839
- kind: 'implements',
840
- parentName,
841
- });
842
- }
843
- }
844
- }
845
- }
846
- }
847
- }
848
- }
849
- void clauseNode; // referenced to suppress unused warning
850
- }
851
- }
852
- if (node.type === 'interface_declaration') {
853
- const nameNode = node.childForFieldName('name');
854
- const ifaceName = nameNode?.text;
855
- if (ifaceName) {
856
- const typeNodeId = mkNodeId(filePath, ifaceName);
857
- for (let i = 0; i < node.namedChildCount; i++) {
858
- const child = node.namedChild(i);
859
- if (!child || child.type !== 'extends_type_clause')
860
- continue;
861
- for (let j = 0; j < child.namedChildCount; j++) {
862
- const parent = child.namedChild(j);
863
- if (parent?.text) {
864
- const parentName = parent.text.replace(/<.*>$/, '').trim();
865
- if (parentName) {
866
- heritage.push({
867
- filePath,
868
- typeName: ifaceName,
869
- typeNodeId,
870
- kind: 'extends',
871
- parentName,
872
- });
873
- }
874
- }
875
- }
876
- }
877
- }
878
- }
879
- for (let i = 0; i < node.namedChildCount; i++) {
880
- const child = node.namedChild(i);
881
- if (child)
882
- walk(child);
883
- }
884
- }
885
- walk(rootNode);
886
- void symbols; // available for future enrichment
887
- }
888
- // ---------------------------------------------------------------------------
889
- // Call extraction (lightweight — calledName only)
890
- // ---------------------------------------------------------------------------
891
- function extractCalls(rootNode, filePath, symbols, calls) {
892
- // Build a list of callable symbols (functions/methods) for enclosing resolution
893
- const callableSymbols = symbols.filter((s) => s.kind === 'function' || s.kind === 'method');
894
- function findEnclosingId(row) {
895
- // Find deepest callable that contains this row (smallest line span)
896
- let best = null;
897
- for (const sym of callableSymbols) {
898
- if (sym.filePath === filePath && sym.startLine <= row + 1 && sym.endLine >= row + 1) {
899
- if (!best || sym.endLine - sym.startLine < best.endLine - best.startLine) {
900
- best = sym;
901
- }
902
- }
903
- }
904
- return best?.id ?? mkNodeId(filePath, '__file__');
905
- }
906
- function walk(node) {
907
- if (node.type === 'call_expression') {
908
- const funcNode = node.childForFieldName('function');
909
- if (funcNode) {
910
- let calledName = null;
911
- let callForm = 'free';
912
- let receiverName;
913
- if (funcNode.type === 'identifier') {
914
- calledName = funcNode.text;
915
- callForm = 'free';
916
- }
917
- else if (funcNode.type === 'member_expression') {
918
- const propNode = funcNode.childForFieldName('property');
919
- const objNode = funcNode.childForFieldName('object');
920
- if (propNode?.type === 'property_identifier') {
921
- calledName = propNode.text;
922
- callForm = 'member';
923
- if (objNode?.type === 'identifier') {
924
- receiverName = objNode.text;
925
- }
926
- }
927
- }
928
- if (calledName && calledName.length > 0) {
929
- const sourceId = findEnclosingId(node.startPosition.row);
930
- const entry = { filePath, sourceId, calledName, callForm };
931
- if (receiverName !== undefined)
932
- entry.receiverName = receiverName;
933
- calls.push(entry);
934
- }
935
- }
936
- }
937
- // new Foo() — constructor calls
938
- if (node.type === 'new_expression') {
939
- const constructorNode = node.childForFieldName('constructor');
940
- if (constructorNode?.type === 'identifier' && constructorNode.text) {
941
- const sourceId = findEnclosingId(node.startPosition.row);
942
- calls.push({
943
- filePath,
944
- sourceId,
945
- calledName: constructorNode.text,
946
- callForm: 'constructor',
947
- });
948
- }
949
- }
950
- for (let i = 0; i < node.namedChildCount; i++) {
951
- const child = node.namedChild(i);
952
- if (child)
953
- walk(child);
954
- }
955
- }
956
- walk(rootNode);
957
- }
958
- // ---------------------------------------------------------------------------
959
- // Process a batch of files
960
- // ---------------------------------------------------------------------------
961
- function processBatch(files, onProgress) {
962
- const result = {
8
+ import { extractOriginalSource } from '../parse-loop.js';
9
+ if (!parentPort && !process.send)
10
+ throw new Error('Parser requires owned IPC transport');
11
+ function send(message) {
12
+ if (parentPort)
13
+ parentPort.postMessage(message);
14
+ else
15
+ process.send?.(message);
16
+ }
17
+ function emptyResult() {
18
+ return {
19
+ reports: [],
963
20
  symbols: [],
964
21
  imports: [],
965
22
  heritage: [],
966
23
  calls: [],
967
24
  reExports: [],
25
+ accesses: [],
968
26
  fileCount: 0,
969
27
  skippedCount: 0,
970
28
  };
971
- const parser = getParser();
972
- if (!parser) {
973
- result.skippedCount = files.length;
974
- return result;
29
+ }
30
+ let accumulated = emptyResult();
31
+ function receive(message) {
32
+ if (message.type === 'flush') {
33
+ send({ type: 'result', data: accumulated });
34
+ accumulated = emptyResult();
35
+ return;
975
36
  }
976
- let processed = 0;
977
- let lastReported = 0;
978
- const PROGRESS_INTERVAL = 100;
979
- for (const file of files) {
980
- const grammarKey = grammarKeyForPath(file.path);
981
- if (!grammarKey) {
982
- result.skippedCount++;
983
- continue;
984
- }
985
- const grammar = loadGrammar(grammarKey);
986
- if (!grammar) {
987
- result.skippedCount++;
988
- continue;
989
- }
990
- // tree-sitter 0.21.x has a hard limit of 32767 chars per file (15-bit offset counter).
991
- // Files larger than this threshold are handled with a regex fallback for imports
992
- // and re-exports (the data structures we need for barrel tracing).
993
- const sanitized = sanitizeForParsing(file.content);
994
- const useTreeSitter = sanitized.length <= TREE_SITTER_MAX_CHARS;
995
- if (!useTreeSitter) {
996
- // Regex-based fallback: extract re-exports, imports, and free calls for
997
- // barrel tracing (T617). Symbol definitions are still skipped — tree-sitter
998
- // is required for accurate scope and parent tracking. Free calls use the
999
- // file node as sourceId so CALLS edges can still be emitted against
1000
- // barrel-resolved named-import targets.
1001
- const reExportsBefore = result.reExports.length;
1002
- const importsBefore = result.imports.length;
1003
- const callsBefore = result.calls.length;
1004
- try {
1005
- extractReExportsRegex(file.content, file.path, result.reExports);
1006
- // Basic import extraction via regex for namedImportMap population
1007
- extractImportsRegex(file.content, file.path, grammarKey, result.imports);
1008
- // Free-call extraction so tier2a barrel-resolved calls emit CALLS edges
1009
- // even for oversized files (e.g. task-engine.ts @ 67K chars).
1010
- extractCallsRegex(file.content, file.path, result.calls);
1011
- }
1012
- catch {
1013
- // Skip errors in regex fallback — continue to next file
1014
- }
1015
- if (process.env['CLEO_BARREL_DEBUG']) {
1016
- const reAdded = result.reExports.length - reExportsBefore;
1017
- const impAdded = result.imports.length - importsBefore;
1018
- const callsAdded = result.calls.length - callsBefore;
1019
- process.stderr.write(`[worker-regex] ${file.path} bytes=${file.content.length} reExports=+${reAdded} imports=+${impAdded} calls=+${callsAdded}\n`);
1020
- }
1021
- result.fileCount++;
1022
- processed++;
1023
- if (onProgress && processed - lastReported >= PROGRESS_INTERVAL) {
1024
- lastReported = processed;
1025
- onProgress(processed);
1026
- }
1027
- continue;
1028
- }
1029
- let rootNode;
37
+ for (const file of message.files) {
1030
38
  try {
1031
- parser.setLanguage(grammar);
1032
- const tree = parser.parse(sanitized);
1033
- rootNode = tree.rootNode;
1034
- }
1035
- catch {
1036
- result.skippedCount++;
1037
- continue;
1038
- }
1039
- const language = grammarKey === 'tsx' ? 'typescript' : grammarKey;
1040
- const fileSymbols = [];
1041
- try {
1042
- walkDefinitions(rootNode, file.path, language, fileSymbols);
1043
- for (const s of fileSymbols)
1044
- result.symbols.push(s);
1045
- extractImports(rootNode, file.path, language, result.imports);
1046
- extractReExports(rootNode, file.path, result.reExports);
1047
- extractHeritage(rootNode, file.path, result.heritage, fileSymbols);
1048
- extractCalls(rootNode, file.path, fileSymbols, result.calls);
1049
- }
1050
- catch {
1051
- // Skip extraction errors — file was still parseable
1052
- }
1053
- result.fileCount++;
1054
- processed++;
1055
- if (onProgress && processed - lastReported >= PROGRESS_INTERVAL) {
1056
- lastReported = processed;
1057
- onProgress(processed);
1058
- }
1059
- }
1060
- return result;
1061
- }
1062
- // ---------------------------------------------------------------------------
1063
- // Accumulated result (persists across sub-batches)
1064
- // ---------------------------------------------------------------------------
1065
- let accumulated = {
1066
- symbols: [],
1067
- imports: [],
1068
- heritage: [],
1069
- calls: [],
1070
- reExports: [],
1071
- fileCount: 0,
1072
- skippedCount: 0,
1073
- };
1074
- let cumulativeProcessed = 0;
1075
- function mergeResult(target, src) {
1076
- for (const s of src.symbols)
1077
- target.symbols.push(s);
1078
- for (const i of src.imports)
1079
- target.imports.push(i);
1080
- for (const h of src.heritage)
1081
- target.heritage.push(h);
1082
- for (const c of src.calls)
1083
- target.calls.push(c);
1084
- for (const r of src.reExports)
1085
- target.reExports.push(r);
1086
- target.fileCount += src.fileCount;
1087
- target.skippedCount += src.skippedCount;
1088
- }
1089
- // ---------------------------------------------------------------------------
1090
- // Message handler
1091
- // ---------------------------------------------------------------------------
1092
- parentPort.on('message', (msg) => {
1093
- try {
1094
- if (msg.type === 'sub-batch') {
1095
- const result = processBatch(msg.files, (filesProcessed) => {
1096
- parentPort.postMessage({
1097
- type: 'progress',
1098
- filesProcessed: cumulativeProcessed + filesProcessed,
1099
- });
39
+ const extracted = extractOriginalSource(file.content, file.path, file.limits, file.publicationGeneration);
40
+ accumulated.symbols.push(...extracted.definitions);
41
+ accumulated.imports.push(...extracted.imports);
42
+ accumulated.heritage.push(...extracted.heritage);
43
+ accumulated.calls.push(...extracted.calls);
44
+ accumulated.reExports.push(...(extracted.reExports ?? []));
45
+ accumulated.accesses.push(...(extracted.accesses ?? []));
46
+ accumulated.reports.push({ path: file.path, status: 'analyzed' });
47
+ accumulated.fileCount++;
48
+ }
49
+ catch (error) {
50
+ accumulated.reports.push({
51
+ path: file.path,
52
+ status: 'failed',
53
+ reason: error instanceof Error ? error.message : String(error),
1100
54
  });
1101
- cumulativeProcessed += result.fileCount;
1102
- mergeResult(accumulated, result);
1103
- parentPort.postMessage({ type: 'sub-batch-done' });
1104
- return;
1105
- }
1106
- if (msg.type === 'flush') {
1107
- parentPort.postMessage({ type: 'result', data: accumulated });
1108
- // Reset for reuse
1109
- accumulated = {
1110
- symbols: [],
1111
- imports: [],
1112
- heritage: [],
1113
- calls: [],
1114
- reExports: [],
1115
- fileCount: 0,
1116
- skippedCount: 0,
1117
- };
1118
- cumulativeProcessed = 0;
1119
- return;
55
+ accumulated.skippedCount++;
1120
56
  }
1121
57
  }
1122
- catch (err) {
1123
- const message = err instanceof Error ? err.message : String(err);
1124
- parentPort.postMessage({ type: 'error', error: message });
1125
- }
1126
- });
58
+ send({ type: 'progress', filesProcessed: accumulated.fileCount + accumulated.skippedCount });
59
+ send({ type: 'sub-batch-done' });
60
+ }
61
+ if (parentPort)
62
+ parentPort.on('message', receive);
63
+ else
64
+ process.on('message', receive);
65
+ send({ type: 'ready', heapBytes: getHeapStatistics().heap_size_limit });
1127
66
  //# sourceMappingURL=parse-worker.js.map