agentic-compaction 0.0.3 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -74,11 +74,12 @@ hooks: useState(2), useEffect([user]):18, useAuth
74
74
  ```
75
75
 
76
76
  The skeleton captures:
77
- - **Imports** (local paths shown, externals counted)
77
+ - **Imports** (deduplicated local paths shown, externals counted)
78
78
  - **Exports** (default marked with `*`)
79
- - **Components** (PascalCase functions, HOC-wrapped)
80
- - **Functions** (with line numbers)
81
- - **Hooks** (counts, useEffect deps, custom hooks)
79
+ - **Components** (top-level PascalCase functions, HOC-wrapped)
80
+ - **Functions** (top-level only, with line numbers)
81
+ - **Hooks** (only from top-level components: counts, useEffect deps, custom hooks)
82
+ - **Constants** (top-level only)
82
83
  - **Classes, interfaces, types** (TS)
83
84
  - **Python**: imports, classes (with bases/decorators), functions, constants
84
85
 
@@ -86,9 +87,9 @@ The skeleton captures:
86
87
 
87
88
  | Language | Parser | Extensions |
88
89
  |----------|--------|------------|
89
- | JavaScript | `@babel/parser` | `.js`, `.jsx`, `.mjs`, `.cjs` |
90
- | TypeScript | `@babel/parser` | `.ts`, `.tsx`, `.mts`, `.cts` |
91
- | Python | Regex-based (zero deps) | `.py` |
90
+ | JavaScript | `@babel/parser` (top-level only) | `.js`, `.jsx`, `.mjs`, `.cjs` |
91
+ | TypeScript | `@babel/parser` (top-level only) | `.ts`, `.tsx`, `.mts`, `.cts` |
92
+ | Python | Regex-based (top-level only, zero deps) | `.py` |
92
93
 
93
94
  ## Skipped Directories
94
95
 
@@ -0,0 +1,37 @@
1
+ ## src/cli.js
2
+ imports: 3 ext, ./index.js, ./formatter.js
3
+ fn: getDateStamp():9, pad(n):11
4
+ const: now, args, targetPath, jsonOutput, i +5 more
5
+ ## src/formatter.js
6
+ imports: ./parsers/python.js, ./parsers/babel.js, ./parsers/python.js
7
+ fn: estimateTokens(text)+:5, formatTokenCount(count)+:10, formatOutput(results)+:16
8
+ const: lines, output
9
+ ## src/index.js
10
+ imports: 1 ext, ./walker.js, ./formatter.js, ./parsers/babel.js, ./parsers/python.js
11
+ fn: compactFile(filePath, content)+:17, compactProject(rootPath, options = ...)+:38
12
+ const: skeleton, formatted, files, results, rawTokens +4 more
13
+ ## src/parsers/babel.js
14
+ imports: 2 ext
15
+ fn: isBabelParseable(path)+:9, isPascalCase(name):13, getReactHOCInfo(node):17, isCreateContext(node):52, extractDependencyArray(node):69, getParamsString(params):97, getTypeName(typeAnnotation):127, getReturnType(node):145, extractSignatures(code, filePath = ...)+:150, extractSkeleton(code, filePath = ...)+:246, formatSignaturesForPrompt(signatures)+:438, formatSkeletonForPrompt(skeleton)+:443
16
+ const: traverse, BABEL_EXTENSIONS, callee, hocType, method +75 more
17
+ ## src/parsers/python.js
18
+ fn: isPythonParseable(path)+:3, extractSkeleton(code, filePath = ...)+:14, formatSkeletonForPrompt(skeleton)+:148
19
+ const: PYTHON_EXTENSIONS, lines, skeleton, pendingDecorators, i +25 more
20
+ ## src/walker.js
21
+ imports: 2 ext, ./parsers/babel.js, ./parsers/python.js
22
+ fn: collectFiles(dir, rootDir = ..., files = ...)+:24, SKIP_DIRS_OR_DOT(name):48, isParseable(path):52
23
+ const: SKIP_DIRECTORIES, fullPath, relativePath
24
+ ## test/fixtures/sample.js
25
+ imports: 1 ext, ./api
26
+ components: MyComponent({ id })*:6
27
+ fn: helper(x):16
28
+ const: API_URL
29
+ hooks: useState: data, useEffect([id])
30
+ ## test/fixtures/sample.py
31
+ imports: 4 ext
32
+ classes: BaseProcessor:9, Config @dataclass (BaseProcessor):13
33
+ fn: process_data(items, timeout=30):17, fetch_remote(url, **kwargs):20, @app.route api_handler(request):24
34
+ const: MAX_RETRIES, DEFAULT_TIMEOUT
35
+ ## test/test.js
36
+ imports: 5 ext, ../src/index.js, ../src/parsers/babel.js, ../src/parsers/python.js, ../src/walker.js
37
+ const: __dirname, fixturesDir, code, skeleton, code +14 more
@@ -0,0 +1,37 @@
1
+ ## src/cli.js
2
+ imports: 3 ext, ./index.js, ./formatter.js
3
+ fn: getDateStamp():9, pad(n):11
4
+ const: now, args, targetPath, jsonOutput, i +5 more
5
+ ## src/formatter.js
6
+ imports: ./parsers/python.js, ./parsers/babel.js, ./parsers/python.js
7
+ fn: estimateTokens(text)+:5, formatTokenCount(count)+:10, formatOutput(results)+:16
8
+ const: lines, output
9
+ ## src/index.js
10
+ imports: 1 ext, ./walker.js, ./formatter.js, ./parsers/babel.js, ./parsers/python.js
11
+ fn: compactFile(filePath, content)+:17, compactProject(rootPath, options = ...)+:38
12
+ const: skeleton, formatted, files, results, rawTokens +4 more
13
+ ## src/parsers/babel.js
14
+ imports: 2 ext
15
+ fn: isBabelParseable(path)+:9, isPascalCase(name):13, getReactHOCInfo(node):17, isCreateContext(node):52, extractDependencyArray(node):69, getParamsString(params):97, getTypeName(typeAnnotation):127, getReturnType(node):145, extractSignatures(code, filePath = ...)+:150, extractSkeleton(code, filePath = ...)+:246, formatSignaturesForPrompt(signatures)+:438, formatSkeletonForPrompt(skeleton)+:443
16
+ const: traverse, BABEL_EXTENSIONS, callee, hocType, method +75 more
17
+ ## src/parsers/python.js
18
+ fn: isPythonParseable(path)+:3, extractSkeleton(code, filePath = ...)+:14, formatSkeletonForPrompt(skeleton)+:148
19
+ const: PYTHON_EXTENSIONS, lines, skeleton, pendingDecorators, i +25 more
20
+ ## src/walker.js
21
+ imports: 2 ext, ./parsers/babel.js, ./parsers/python.js
22
+ fn: collectFiles(dir, rootDir = ..., files = ...)+:24, SKIP_DIRS_OR_DOT(name):48, isParseable(path):52
23
+ const: SKIP_DIRECTORIES, fullPath, relativePath
24
+ ## test/fixtures/sample.js
25
+ imports: 1 ext, ./api
26
+ components: MyComponent({ id })*:6
27
+ fn: helper(x):16
28
+ const: API_URL
29
+ hooks: useState: data, useEffect([id])
30
+ ## test/fixtures/sample.py
31
+ imports: 4 ext
32
+ classes: BaseProcessor:9, Config @dataclass (BaseProcessor):13
33
+ fn: process_data(items, timeout=30):17, fetch_remote(url, **kwargs):20, @app.route api_handler(request):24
34
+ const: MAX_RETRIES, DEFAULT_TIMEOUT
35
+ ## test/test.js
36
+ imports: 5 ext, ../src/index.js, ../src/parsers/babel.js, ../src/parsers/python.js, ../src/walker.js
37
+ const: __dirname, fixturesDir, code, skeleton, code +14 more
@@ -0,0 +1,35 @@
1
+ ## src/cli.js
2
+ imports: 3 ext, ./index.js, ./formatter.js
3
+ fn: getDateStamp():9
4
+ const: args, targetPath, jsonOutput, dirName, filename +2 more
5
+ ## src/formatter.js
6
+ imports: ./parsers/python.js, ./parsers/babel.js
7
+ fn: estimateTokens(text)+:5, formatTokenCount(count)+:10, formatOutput(results)+:16
8
+ ## src/index.js
9
+ imports: 1 ext, ./walker.js, ./formatter.js, ./parsers/babel.js, ./parsers/python.js
10
+ fn: compactFile(filePath, content)+:17, compactProject(rootPath, options = ...)+:38
11
+ ## src/parsers/babel.js
12
+ imports: 2 ext
13
+ fn: isBabelParseable(path)+:9, isPascalCase(name):13, getReactHOCInfo(node):17, isCreateContext(node):52, extractDependencyArray(node):69, getParamsString(params):97, getTypeName(typeAnnotation):127, getReturnType(node):145, extractSignatures(code, filePath = ...)+:150, extractSkeleton(code, filePath = ...)+:246, formatSignaturesForPrompt(signatures)+:444, formatSkeletonForPrompt(skeleton)+:449
14
+ const: traverse, BABEL_EXTENSIONS
15
+ ## src/parsers/python.js
16
+ fn: isPythonParseable(path)+:3, extractSkeleton(code, filePath = ...)+:14, formatSkeletonForPrompt(skeleton)+:148
17
+ const: PYTHON_EXTENSIONS
18
+ ## src/walker.js
19
+ imports: 2 ext, ./parsers/babel.js, ./parsers/python.js
20
+ fn: collectFiles(dir, rootDir = ..., files = ...)+:24, SKIP_DIRS_OR_DOT(name):48, isParseable(path):52
21
+ const: SKIP_DIRECTORIES
22
+ ## test/fixtures/sample.js
23
+ imports: 1 ext, ./api
24
+ components: MyComponent({ id })*:6
25
+ fn: helper(x):16
26
+ const: API_URL
27
+ hooks: useState: data, useEffect([id])
28
+ ## test/fixtures/sample.py
29
+ imports: 4 ext
30
+ classes: BaseProcessor:9, Config @dataclass (BaseProcessor):13
31
+ fn: process_data(items, timeout=30):17, fetch_remote(url, **kwargs):20, @app.route api_handler(request):24
32
+ const: MAX_RETRIES, DEFAULT_TIMEOUT
33
+ ## test/test.js
34
+ imports: 5 ext, ../src/index.js, ../src/parsers/babel.js, ../src/parsers/python.js, ../src/walker.js
35
+ const: __dirname, fixturesDir
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentic-compaction",
3
- "version": "0.0.3",
3
+ "version": "0.0.5",
4
4
  "description": "Walk a project directory and output a compact structural skeleton of the entire codebase",
5
5
  "type": "module",
6
6
  "main": "./src/index.js",
@@ -111,7 +111,11 @@ const getParamsString = (params) => {
111
111
  return `...${param.argument?.name || 'args'}`;
112
112
  }
113
113
  if (param.type === 'ObjectPattern') {
114
- return '{ ... }';
114
+ const keys = param.properties.map(p => {
115
+ if (p.type === 'RestElement') return `...${p.argument?.name || 'rest'}`;
116
+ return p.key?.name || '?';
117
+ });
118
+ return `{ ${keys.join(', ')} }`;
115
119
  }
116
120
  if (param.type === 'ArrayPattern') {
117
121
  return '[ ... ]';
@@ -265,16 +269,18 @@ export const extractSkeleton = (code, filePath = '') => {
265
269
 
266
270
  const skeleton = {
267
271
  imports: [],
268
- exports: [],
269
272
  components: [],
270
273
  functions: [],
271
- hooks: { useState: 0, useEffect: [], useCallback: 0, useMemo: 0, useRef: 0, custom: [] },
272
- constants: 0,
274
+ hooks: { useState: [], useEffect: [], useCallback: 0, useMemo: 0, useRef: 0, custom: [] },
275
+ constants: [],
273
276
  classes: [],
274
277
  interfaces: [],
275
278
  types: [],
276
279
  };
277
280
 
281
+ // Collect export info: name -> 'default' | 'named'
282
+ const exportMap = new Map();
283
+
278
284
  traverse(ast, {
279
285
  ImportDeclaration(path) {
280
286
  const source = path.node.source.value;
@@ -289,9 +295,9 @@ export const extractSkeleton = (code, filePath = '') => {
289
295
  ExportDefaultDeclaration(path) {
290
296
  const decl = path.node.declaration;
291
297
  if (decl.type === 'Identifier') {
292
- skeleton.exports.push({ name: decl.name, type: 'default' });
298
+ exportMap.set(decl.name, 'default');
293
299
  } else if (decl.type === 'FunctionDeclaration' && decl.id) {
294
- skeleton.exports.push({ name: decl.id.name, type: 'default' });
300
+ exportMap.set(decl.id.name, 'default');
295
301
  }
296
302
  },
297
303
 
@@ -299,50 +305,65 @@ export const extractSkeleton = (code, filePath = '') => {
299
305
  if (path.node.declaration) {
300
306
  const decl = path.node.declaration;
301
307
  if (decl.type === 'FunctionDeclaration' && decl.id) {
302
- skeleton.exports.push({ name: decl.id.name, type: 'named' });
308
+ exportMap.set(decl.id.name, 'named');
303
309
  } else if (decl.type === 'VariableDeclaration') {
304
310
  decl.declarations.forEach(d => {
305
311
  if (d.id?.name) {
306
- skeleton.exports.push({ name: d.id.name, type: 'named' });
312
+ exportMap.set(d.id.name, 'named');
307
313
  }
308
314
  });
309
315
  }
310
316
  }
311
317
  if (path.node.specifiers) {
312
318
  path.node.specifiers.forEach(s => {
313
- skeleton.exports.push({ name: s.exported?.name || s.local.name, type: 'named' });
319
+ exportMap.set(s.exported?.name || s.local.name, 'named');
314
320
  });
315
321
  }
316
322
  },
317
323
 
318
324
  FunctionDeclaration(path) {
325
+ if (path.parent.type !== 'Program' && path.parent.type !== 'ExportNamedDeclaration' && path.parent.type !== 'ExportDefaultDeclaration') return;
319
326
  const name = path.node.id?.name;
320
327
  if (!name) return;
321
328
 
329
+ const params = getParamsString(path.node.params);
330
+ const isAsync = path.node.async || false;
331
+ const entry = { name, line: path.node.loc?.start?.line || 0, params, async: isAsync };
332
+
322
333
  if (isPascalCase(name)) {
323
- skeleton.components.push({ name, line: path.node.loc?.start?.line || 0 });
334
+ skeleton.components.push(entry);
324
335
  } else {
325
- skeleton.functions.push({ name, line: path.node.loc?.start?.line || 0 });
336
+ skeleton.functions.push(entry);
326
337
  }
327
338
  },
328
339
 
329
340
  VariableDeclarator(path) {
341
+ const declParent = path.parentPath?.parent;
342
+ if (declParent?.type !== 'Program' && declParent?.type !== 'ExportNamedDeclaration' && declParent?.type !== 'ExportDefaultDeclaration') return;
330
343
  const name = path.node.id?.name;
331
344
  const init = path.node.init;
332
345
  if (!name || !init) return;
333
346
 
334
347
  if (init.type === 'ArrowFunctionExpression' || init.type === 'FunctionExpression') {
348
+ const params = getParamsString(init.params);
349
+ const isAsync = init.async || false;
350
+ const entry = { name, line: path.node.loc?.start?.line || 0, params, async: isAsync };
351
+
335
352
  if (isPascalCase(name)) {
336
- skeleton.components.push({ name, line: path.node.loc?.start?.line || 0 });
353
+ skeleton.components.push(entry);
337
354
  } else {
338
- skeleton.functions.push({ name, line: path.node.loc?.start?.line || 0 });
355
+ skeleton.functions.push(entry);
339
356
  }
340
357
  return;
341
358
  }
342
359
 
343
360
  const hocInfo = getReactHOCInfo(init);
344
361
  if (hocInfo) {
345
- skeleton.components.push({ name, line: path.node.loc?.start?.line || 0, hoc: hocInfo.type });
362
+ let params = '?';
363
+ if (hocInfo.innerFn) {
364
+ params = getParamsString(hocInfo.innerFn.params);
365
+ }
366
+ skeleton.components.push({ name, line: path.node.loc?.start?.line || 0, hoc: hocInfo.type, params, async: false });
346
367
  return;
347
368
  }
348
369
 
@@ -352,16 +373,30 @@ export const extractSkeleton = (code, filePath = '') => {
352
373
  return;
353
374
  }
354
375
 
355
- skeleton.constants++;
376
+ skeleton.constants.push(name);
356
377
  },
357
378
 
358
379
  CallExpression(path) {
359
380
  const callee = path.node.callee;
360
381
  if (callee.type === 'Identifier' && callee.name.startsWith('use')) {
382
+ // Only capture hooks inside top-level functions (components)
383
+ const funcScope = path.scope.getFunctionParent();
384
+ if (funcScope && funcScope.parent?.block?.type !== 'Program') return;
361
385
  const hookName = callee.name;
362
386
  const line = path.node.loc?.start?.line || 0;
363
387
 
364
- if (hookName === 'useEffect') {
388
+ if (hookName === 'useState') {
389
+ // Extract destructured variable name from parent: const [name, setName] = useState(...)
390
+ let varName = null;
391
+ const parent = path.parent;
392
+ if (parent?.type === 'VariableDeclarator' && parent.id?.type === 'ArrayPattern') {
393
+ const first = parent.id.elements[0];
394
+ if (first?.type === 'Identifier') {
395
+ varName = first.name;
396
+ }
397
+ }
398
+ skeleton.hooks.useState.push(varName || '?');
399
+ } else if (hookName === 'useEffect') {
365
400
  const deps = extractDependencyArray(path.node.arguments[1]);
366
401
  skeleton.hooks.useEffect.push({ line, deps });
367
402
  } else if (skeleton.hooks[hookName] !== undefined) {
@@ -396,6 +431,13 @@ export const extractSkeleton = (code, filePath = '') => {
396
431
  },
397
432
  });
398
433
 
434
+ // Apply export markers to components, functions, classes
435
+ for (const entry of [...skeleton.components, ...skeleton.functions, ...skeleton.classes]) {
436
+ const exportType = exportMap.get(entry.name);
437
+ if (exportType === 'default') entry.exportMarker = '*';
438
+ else if (exportType === 'named') entry.exportMarker = '+';
439
+ }
440
+
399
441
  return skeleton;
400
442
  };
401
443
 
@@ -414,17 +456,17 @@ export const formatSkeletonForPrompt = (skeleton) => {
414
456
  const extCount = skeleton.imports.length - local.length;
415
457
  const parts = [];
416
458
  if (extCount > 0) parts.push(`${extCount} ext`);
417
- parts.push(...local.map(i => i.source));
459
+ parts.push(...[...new Set(local.map(i => i.source))]);
418
460
  lines.push(`imports: ${parts.join(', ')}`);
419
461
  }
420
462
 
421
- if (skeleton.exports.length > 0) {
422
- const exportNames = skeleton.exports.map(e => e.type === 'default' ? `${e.name}*` : e.name).join(', ');
423
- lines.push(`exports: ${exportNames}`);
424
- }
425
-
426
463
  if (skeleton.components.length > 0) {
427
- const componentList = skeleton.components.map(c => c.hoc ? `${c.name}(${c.hoc}):${c.line}` : `${c.name}:${c.line}`).join(', ');
464
+ const componentList = skeleton.components.map(c => {
465
+ const marker = c.exportMarker || '';
466
+ const params = c.params !== undefined ? `(${c.params})` : '';
467
+ const hoc = c.hoc ? `(${c.hoc})` : '';
468
+ return `${c.name}${hoc}${params}${marker}:${c.line}`;
469
+ }).join(', ');
428
470
  lines.push(`components: ${componentList}`);
429
471
  }
430
472
 
@@ -433,11 +475,26 @@ export const formatSkeletonForPrompt = (skeleton) => {
433
475
  }
434
476
 
435
477
  if (skeleton.functions.length > 0) {
436
- lines.push(`fn: ${skeleton.functions.map(f => `${f.name}:${f.line}`).join(', ')}`);
478
+ const funcList = skeleton.functions.map(f => {
479
+ const marker = f.exportMarker || '';
480
+ const asyncPrefix = f.async ? 'async ' : '';
481
+ const params = f.params !== undefined ? `(${f.params})` : '';
482
+ return `${asyncPrefix}${f.name}${params}${marker}:${f.line}`;
483
+ }).join(', ');
484
+ lines.push(`fn: ${funcList}`);
485
+ }
486
+
487
+ if (skeleton.constants.length > 0) {
488
+ const names = skeleton.constants;
489
+ if (names.length > 5) {
490
+ lines.push(`const: ${names.slice(0, 5).join(', ')} +${names.length - 5} more`);
491
+ } else {
492
+ lines.push(`const: ${names.join(', ')}`);
493
+ }
437
494
  }
438
495
 
439
496
  const hookParts = [];
440
- if (skeleton.hooks.useState > 0) hookParts.push(`useState(${skeleton.hooks.useState})`);
497
+ if (skeleton.hooks.useState.length > 0) hookParts.push(`useState: ${skeleton.hooks.useState.join(', ')}`);
441
498
  if (skeleton.hooks.useCallback > 0) hookParts.push(`useCallback(${skeleton.hooks.useCallback})`);
442
499
  if (skeleton.hooks.useMemo > 0) hookParts.push(`useMemo(${skeleton.hooks.useMemo})`);
443
500
  if (skeleton.hooks.useRef > 0) hookParts.push(`useRef(${skeleton.hooks.useRef})`);
@@ -445,9 +502,9 @@ export const formatSkeletonForPrompt = (skeleton) => {
445
502
 
446
503
  if (skeleton.hooks.useEffect.length > 0) {
447
504
  const effects = skeleton.hooks.useEffect.map(eff => {
448
- if (eff.deps === null) return `useEffect(∞):${eff.line}`;
449
- if (eff.deps === '?') return `useEffect(?):${eff.line}`;
450
- return `useEffect([${eff.deps.join(',')}]):${eff.line}`;
505
+ if (eff.deps === null) return `useEffect(∞)`;
506
+ if (eff.deps === '?') return `useEffect(?)`;
507
+ return `useEffect([${eff.deps.join(',')}])`;
451
508
  });
452
509
  hookParts.push(...effects);
453
510
  }
@@ -457,7 +514,11 @@ export const formatSkeletonForPrompt = (skeleton) => {
457
514
  }
458
515
 
459
516
  if (skeleton.classes.length > 0) {
460
- lines.push(`classes: ${skeleton.classes.map(c => `${c.name}:${c.line}`).join(', ')}`);
517
+ const classList = skeleton.classes.map(c => {
518
+ const marker = c.exportMarker || '';
519
+ return `${c.name}${marker}:${c.line}`;
520
+ }).join(', ');
521
+ lines.push(`classes: ${classList}`);
461
522
  }
462
523
 
463
524
  if (skeleton.interfaces.length > 0 || skeleton.types.length > 0) {
@@ -17,7 +17,7 @@ export const extractSkeleton = (code, filePath = '') => {
17
17
  imports: [],
18
18
  functions: [],
19
19
  classes: [],
20
- constants: 0,
20
+ constants: [],
21
21
  };
22
22
 
23
23
  // Collect decorators as we scan
@@ -126,9 +126,9 @@ export const extractSkeleton = (code, filePath = '') => {
126
126
  }
127
127
 
128
128
  // Top-level assignments (constants)
129
- const assignMatch = line.match(/^[A-Za-z_]\w*\s*[=:]/) || line.match(/^[A-Za-z_]\w*\s*:/);
129
+ const assignMatch = line.match(/^([A-Za-z_]\w*)\s*[=:]/);
130
130
  if (assignMatch) {
131
- skeleton.constants++;
131
+ skeleton.constants.push(assignMatch[1]);
132
132
  pendingDecorators = [];
133
133
  continue;
134
134
  }
@@ -172,10 +172,20 @@ export const formatSkeletonForPrompt = (skeleton) => {
172
172
  if (skeleton.functions.length > 0) {
173
173
  const funcList = skeleton.functions.map(f => {
174
174
  const deco = f.decorators.length > 0 ? `@${f.decorators[0]} ` : '';
175
- return `${deco}${f.name}:${f.line}`;
175
+ const params = f.params ? `(${f.params})` : '()';
176
+ return `${deco}${f.name}${params}:${f.line}`;
176
177
  }).join(', ');
177
178
  lines.push(`fn: ${funcList}`);
178
179
  }
179
180
 
181
+ if (skeleton.constants.length > 0) {
182
+ const names = skeleton.constants;
183
+ if (names.length > 5) {
184
+ lines.push(`const: ${names.slice(0, 5).join(', ')} +${names.length - 5} more`);
185
+ } else {
186
+ lines.push(`const: ${names.join(', ')}`);
187
+ }
188
+ }
189
+
180
190
  return lines.join('\n');
181
191
  };
package/test/test.js CHANGED
@@ -21,7 +21,7 @@ describe('babel parser', () => {
21
21
  assert.ok(skeleton.imports.length > 0);
22
22
  assert.ok(skeleton.components.length > 0);
23
23
  assert.ok(skeleton.functions.length > 0);
24
- assert.strictEqual(skeleton.hooks.useState, 1);
24
+ assert.deepStrictEqual(skeleton.hooks.useState, ['data']);
25
25
  assert.strictEqual(skeleton.hooks.useEffect.length, 1);
26
26
  });
27
27
  });
@@ -35,7 +35,7 @@ describe('python parser', () => {
35
35
  assert.strictEqual(skeleton.imports.length, 4);
36
36
  assert.strictEqual(skeleton.functions.length, 3);
37
37
  assert.strictEqual(skeleton.classes.length, 2);
38
- assert.ok(skeleton.constants >= 2);
38
+ assert.ok(skeleton.constants.length >= 2);
39
39
  });
40
40
 
41
41
  it('parses decorators', () => {