@sammons/code-outline-cli 2.1.0 → 2.2.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.
Files changed (40) hide show
  1. package/README.md +47 -13
  2. package/dist/cli-argument-parser.d.ts +4 -1
  3. package/dist/cli-argument-parser.d.ts.map +1 -1
  4. package/dist/cli-argument-parser.js +186 -69
  5. package/dist/cli-argument-parser.js.map +1 -1
  6. package/dist/cli-orchestrator.d.ts +10 -3
  7. package/dist/cli-orchestrator.d.ts.map +1 -1
  8. package/dist/cli-orchestrator.js +96 -24
  9. package/dist/cli-orchestrator.js.map +1 -1
  10. package/dist/cli-output-handler.d.ts +4 -3
  11. package/dist/cli-output-handler.d.ts.map +1 -1
  12. package/dist/cli-output-handler.js +7 -9
  13. package/dist/cli-output-handler.js.map +1 -1
  14. package/dist/cli.js +2 -4
  15. package/dist/cli.js.map +1 -1
  16. package/dist/file-processor.d.ts +70 -3
  17. package/dist/file-processor.d.ts.map +1 -1
  18. package/dist/file-processor.js +134 -25
  19. package/dist/file-processor.js.map +1 -1
  20. package/dist/index.d.ts +4 -4
  21. package/dist/index.d.ts.map +1 -1
  22. package/dist/index.js +21 -51
  23. package/dist/index.js.map +1 -1
  24. package/package.json +12 -11
  25. package/dist/cli-orchestrator.unit.test.d.ts +0 -2
  26. package/dist/cli-orchestrator.unit.test.d.ts.map +0 -1
  27. package/dist/cli-orchestrator.unit.test.js +0 -140
  28. package/dist/cli-orchestrator.unit.test.js.map +0 -1
  29. package/dist/cli.integration.test.d.ts +0 -2
  30. package/dist/cli.integration.test.d.ts.map +0 -1
  31. package/dist/cli.integration.test.js +0 -342
  32. package/dist/cli.integration.test.js.map +0 -1
  33. package/dist/cli.unit.test.d.ts +0 -2
  34. package/dist/cli.unit.test.d.ts.map +0 -1
  35. package/dist/cli.unit.test.js +0 -411
  36. package/dist/cli.unit.test.js.map +0 -1
  37. package/dist/test.d.ts +0 -25
  38. package/dist/test.d.ts.map +0 -1
  39. package/dist/test.js +0 -41
  40. package/dist/test.js.map +0 -1
@@ -1,37 +1,110 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.CLIOrchestrator = void 0;
4
- const cli_argument_parser_js_1 = require("./cli-argument-parser.js");
5
- const file_processor_js_1 = require("./file-processor.js");
6
- const cli_output_handler_js_1 = require("./cli-output-handler.js");
7
- class CLIOrchestrator {
1
+ import { CLIArgumentParser, CLIArgumentError } from "./cli-argument-parser.js";
2
+ import { FileProcessor, FileProcessorError } from "./file-processor.js";
3
+ import { CLIOutputHandler } from "./cli-output-handler.js";
4
+ export class CLIOrchestrator {
8
5
  argumentParser;
9
6
  fileProcessor;
10
- constructor() {
11
- this.argumentParser = new cli_argument_parser_js_1.CLIArgumentParser();
12
- this.fileProcessor = new file_processor_js_1.FileProcessor();
7
+ outputHandlerFactory;
8
+ exit;
9
+ logError;
10
+ constructor(argumentParser = new CLIArgumentParser(), fileProcessor = new FileProcessor(), outputHandlerFactory = (format, llmtext) => new CLIOutputHandler(format, llmtext), exit = (code) => process.exit(code), logError = (message) => console.error(message)) {
11
+ this.argumentParser = argumentParser;
12
+ this.fileProcessor = fileProcessor;
13
+ this.outputHandlerFactory = outputHandlerFactory;
14
+ this.exit = exit;
15
+ this.logError = logError;
13
16
  }
14
17
  async run() {
15
18
  try {
16
19
  // Parse and validate arguments
17
- const { options, pattern } = this.argumentParser.parse();
18
- // Find matching files
19
- const files = await this.fileProcessor.findFiles(pattern);
20
- // Process files in parallel
21
- const results = await this.fileProcessor.processFiles(files, options.depth, options.namedOnly);
20
+ const { options, patterns } = this.argumentParser.parse();
21
+ // Find matching files for every pattern and union the results, deduped
22
+ // by absolute path (findFiles already resolves to absolute paths). One
23
+ // call per pattern keeps the FileProcessor#findFiles contract at "one
24
+ // pattern in, its matches out" unchanged. A single pattern matching
25
+ // nothing is not fatal on its own -- it is common for one glob among
26
+ // several to legitimately miss -- so only the union being empty across
27
+ // every pattern is reported as "no files found".
28
+ const fileSets = await Promise.all(patterns.map(async (pattern) => {
29
+ try {
30
+ return await this.fileProcessor.findFiles(pattern);
31
+ }
32
+ catch (error) {
33
+ if (error instanceof FileProcessorError) {
34
+ return [];
35
+ }
36
+ throw error;
37
+ }
38
+ }));
39
+ const files = [...new Set(fileSets.flat())];
40
+ if (files.length === 0) {
41
+ throw new FileProcessorError(`No files found matching pattern: ${patterns.join(', ')}`);
42
+ }
43
+ // Process files in parallel. FileProcessor#parseFile returns a typed
44
+ // outcome per file instead of throwing or logging: 'parsed' carries
45
+ // the outline plus hasError, 'parse_failed' carries the reason
46
+ // directly. This replaces the previous console.error-monkeypatching
47
+ // trick (issue #9) that detected failures by intercepting a
48
+ // process-wide method -- the outcome kind is now the sole signal, no
49
+ // global patching anywhere.
50
+ const outcomes = await this.fileProcessor.processFiles(files, options.depth, options.namedOnly);
51
+ const results = outcomes.map((outcome) => outcome.kind === 'parsed'
52
+ ? {
53
+ file: outcome.file,
54
+ outline: outcome.outline,
55
+ hasError: outcome.hasError,
56
+ errorCount: outcome.errorCount,
57
+ }
58
+ : {
59
+ file: outcome.file,
60
+ outline: null,
61
+ hasError: false,
62
+ errorCount: 0,
63
+ });
22
64
  // Format and output results
23
- const outputHandler = new cli_output_handler_js_1.CLIOutputHandler(options.format, options.llmtext);
65
+ const outputHandler = this.outputHandlerFactory(options.format, options.llmtext);
24
66
  outputHandler.formatAndOutput(results);
67
+ // One diagnostic line per problem file, printed after the output so
68
+ // the full (possibly partial) result is always on stdout first. A
69
+ // parse_failed file gets the "Error parsing" line (issue #14's
70
+ // existing contract); a parsed file whose tree recovered from a
71
+ // syntax error gets the new "N syntax error(s)" warning (issue #9) --
72
+ // the two are independent signals and a file can only be one at a
73
+ // time (a thrown parse exception never also produces an outline).
74
+ let hadProblem = false;
75
+ for (const outcome of outcomes) {
76
+ if (outcome.kind === 'parse_failed') {
77
+ hadProblem = true;
78
+ this.logError(`Error parsing ${outcome.file}: ${outcome.reason}`);
79
+ }
80
+ else if (outcome.hasError) {
81
+ hadProblem = true;
82
+ const plural = outcome.errorCount === 1 ? '' : 's';
83
+ this.logError(`warning: ${outcome.file}: ${outcome.errorCount} syntax error${plural}; outline may be incomplete`);
84
+ }
85
+ }
86
+ // The batch's output is still worth keeping when only some files had
87
+ // a problem, but the run as a whole is not a clean success (issue
88
+ // #14, extended to hasError by issue #9). This exits through the same
89
+ // "hint after the error" contract as the CLIArgumentError/
90
+ // FileProcessorError catch arms below so every documented error path
91
+ // in the Exit Codes table prints the hint, not just the two
92
+ // exception-based ones.
93
+ if (hadProblem) {
94
+ this.logError('Run with --help for usage.');
95
+ this.exit(1);
96
+ }
25
97
  }
26
98
  catch (error) {
27
- if (error instanceof cli_argument_parser_js_1.CLIArgumentError) {
28
- console.error(`Error: ${error.message}`);
29
- this.argumentParser.printHelp();
30
- process.exit(1);
99
+ if (error instanceof CLIArgumentError) {
100
+ this.logError(`Error: ${error.message}`);
101
+ this.logError('Run with --help for usage.');
102
+ this.exit(1);
31
103
  }
32
- else if (error instanceof file_processor_js_1.FileProcessorError) {
33
- console.error(error.message);
34
- process.exit(1);
104
+ else if (error instanceof FileProcessorError) {
105
+ this.logError(error.message);
106
+ this.logError('Run with --help for usage.');
107
+ this.exit(1);
35
108
  }
36
109
  else {
37
110
  throw error; // Re-throw unexpected errors
@@ -39,5 +112,4 @@ class CLIOrchestrator {
39
112
  }
40
113
  }
41
114
  }
42
- exports.CLIOrchestrator = CLIOrchestrator;
43
115
  //# sourceMappingURL=cli-orchestrator.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"cli-orchestrator.js","sourceRoot":"","sources":["../src/cli-orchestrator.ts"],"names":[],"mappings":";;;AAAA,qEAA+E;AAC/E,2DAAwE;AACxE,mEAA2D;AAE3D,MAAa,eAAe;IAClB,cAAc,CAAoB;IAClC,aAAa,CAAgB;IAErC;QACE,IAAI,CAAC,cAAc,GAAG,IAAI,0CAAiB,EAAE,CAAC;QAC9C,IAAI,CAAC,aAAa,GAAG,IAAI,iCAAa,EAAE,CAAC;IAC3C,CAAC;IAEM,KAAK,CAAC,GAAG;QACd,IAAI,CAAC;YACH,+BAA+B;YAC/B,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,CAAC;YAEzD,sBAAsB;YACtB,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;YAE1D,4BAA4B;YAC5B,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,YAAY,CACnD,KAAK,EACL,OAAO,CAAC,KAAK,EACb,OAAO,CAAC,SAAS,CAClB,CAAC;YAEF,4BAA4B;YAC5B,MAAM,aAAa,GAAG,IAAI,wCAAgB,CACxC,OAAO,CAAC,MAAM,EACd,OAAO,CAAC,OAAO,CAChB,CAAC;YACF,aAAa,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC;QACzC,CAAC;QAAC,OAAO,KAAc,EAAE,CAAC;YACxB,IAAI,KAAK,YAAY,yCAAgB,EAAE,CAAC;gBACtC,OAAO,CAAC,KAAK,CAAC,UAAU,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;gBACzC,IAAI,CAAC,cAAc,CAAC,SAAS,EAAE,CAAC;gBAChC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;iBAAM,IAAI,KAAK,YAAY,sCAAkB,EAAE,CAAC;gBAC/C,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;gBAC7B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;iBAAM,CAAC;gBACN,MAAM,KAAK,CAAC,CAAC,6BAA6B;YAC5C,CAAC;QACH,CAAC;IACH,CAAC;CACF;AA3CD,0CA2CC"}
1
+ {"version":3,"file":"cli-orchestrator.js","sourceRoot":"","sources":["../src/cli-orchestrator.ts"],"names":[],"mappings":"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"}
@@ -1,8 +1,9 @@
1
1
  import type { OutputFormat } from '@sammons/code-outline-parser';
2
- import type { ProcessedFile } from './file-processor.js';
2
+ import type { ProcessedFile } from './file-processor.ts';
3
3
  export declare class CLIOutputHandler {
4
- private formatter;
5
- constructor(format: OutputFormat, llmtext?: boolean);
4
+ private readonly formatter;
5
+ private readonly log;
6
+ constructor(format: OutputFormat, llmtext?: boolean, log?: (message: string) => void);
6
7
  formatAndOutput(results: ProcessedFile[]): void;
7
8
  }
8
9
  //# sourceMappingURL=cli-output-handler.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"cli-output-handler.d.ts","sourceRoot":"","sources":["../src/cli-output-handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAEjE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEzD,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,SAAS,CAAY;gBAEjB,MAAM,EAAE,YAAY,EAAE,OAAO,CAAC,EAAE,OAAO;IAI5C,eAAe,CAAC,OAAO,EAAE,aAAa,EAAE,GAAG,IAAI;CAIvD"}
1
+ {"version":3,"file":"cli-output-handler.d.ts","sourceRoot":"","sources":["../src/cli-output-handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAEjE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEzD,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAY;IACtC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAA4B;gBAG9C,MAAM,EAAE,YAAY,EACpB,OAAO,CAAC,EAAE,OAAO,EACjB,GAAG,GAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAwC;IAM7D,eAAe,CAAC,OAAO,EAAE,aAAa,EAAE,GAAG,IAAI;CAIvD"}
@@ -1,16 +1,14 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.CLIOutputHandler = void 0;
4
- const code_outline_formatter_1 = require("@sammons/code-outline-formatter");
5
- class CLIOutputHandler {
1
+ import { Formatter } from '@sammons/code-outline-formatter';
2
+ export class CLIOutputHandler {
6
3
  formatter;
7
- constructor(format, llmtext) {
8
- this.formatter = new code_outline_formatter_1.Formatter(format, llmtext);
4
+ log;
5
+ constructor(format, llmtext, log = (message) => console.log(message)) {
6
+ this.formatter = new Formatter(format, llmtext);
7
+ this.log = log;
9
8
  }
10
9
  formatAndOutput(results) {
11
10
  const output = this.formatter.format(results);
12
- console.log(output);
11
+ this.log(output);
13
12
  }
14
13
  }
15
- exports.CLIOutputHandler = CLIOutputHandler;
16
14
  //# sourceMappingURL=cli-output-handler.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"cli-output-handler.js","sourceRoot":"","sources":["../src/cli-output-handler.ts"],"names":[],"mappings":";;;AACA,4EAA4D;AAG5D,MAAa,gBAAgB;IACnB,SAAS,CAAY;IAE7B,YAAY,MAAoB,EAAE,OAAiB;QACjD,IAAI,CAAC,SAAS,GAAG,IAAI,kCAAS,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClD,CAAC;IAEM,eAAe,CAAC,OAAwB;QAC7C,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAC9C,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACtB,CAAC;CACF;AAXD,4CAWC"}
1
+ {"version":3,"file":"cli-output-handler.js","sourceRoot":"","sources":["../src/cli-output-handler.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,iCAAiC,CAAC;AAG5D,MAAM,OAAO,gBAAgB;IACV,SAAS,CAAY;IACrB,GAAG,CAA4B;IAEhD,YACE,MAAoB,EACpB,OAAiB,EACjB,MAAiC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC;QAElE,IAAI,CAAC,SAAS,GAAG,IAAI,SAAS,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAChD,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;IACjB,CAAC;IAEM,eAAe,CAAC,OAAwB;QAC7C,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAC9C,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACnB,CAAC;CACF"}
package/dist/cli.js CHANGED
@@ -1,9 +1,7 @@
1
1
  #!/usr/bin/env node
2
- "use strict";
3
- Object.defineProperty(exports, "__esModule", { value: true });
4
- const cli_orchestrator_js_1 = require("./cli-orchestrator.js");
2
+ import { CLIOrchestrator } from "./cli-orchestrator.js";
5
3
  async function main() {
6
- const orchestrator = new cli_orchestrator_js_1.CLIOrchestrator();
4
+ const orchestrator = new CLIOrchestrator();
7
5
  await orchestrator.run();
8
6
  }
9
7
  main().catch((error) => {
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";;;AAEA,+DAAwD;AAExD,KAAK,UAAU,IAAI;IACjB,MAAM,YAAY,GAAG,IAAI,qCAAe,EAAE,CAAC;IAC3C,MAAM,YAAY,CAAC,GAAG,EAAE,CAAC;AAC3B,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;IAC9B,MAAM,YAAY,GAChB,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,qBAAqB,CAAC;IACjE,OAAO,CAAC,KAAK,CAAC,cAAc,EAAE,YAAY,CAAC,CAAC;IAC5C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAExD,KAAK,UAAU,IAAI;IACjB,MAAM,YAAY,GAAG,IAAI,eAAe,EAAE,CAAC;IAC3C,MAAM,YAAY,CAAC,GAAG,EAAE,CAAC;AAC3B,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;IAC9B,MAAM,YAAY,GAChB,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,qBAAqB,CAAC;IACjE,OAAO,CAAC,KAAK,CAAC,cAAc,EAAE,YAAY,CAAC,CAAC;IAC5C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -1,16 +1,83 @@
1
+ import fg from 'fast-glob';
1
2
  import type { NodeInfo } from '@sammons/code-outline-parser';
3
+ import { Parser } from '@sammons/code-outline-parser';
2
4
  export interface ProcessedFile {
3
5
  file: string;
4
6
  outline: NodeInfo | null;
7
+ hasError: boolean;
8
+ errorCount: number;
5
9
  }
6
10
  export declare class FileProcessorError extends Error {
7
11
  constructor(message: string);
8
12
  }
13
+ /**
14
+ * Per-file outcome of a parse attempt. Replaces the previous console.error
15
+ * monkeypatch (issue #9): a file that throws during parsing reports itself
16
+ * as `parse_failed` with its reason directly, instead of the orchestrator
17
+ * detecting failure by intercepting a global console method.
18
+ */
19
+ export type ParseFileOutcome = {
20
+ kind: 'parsed';
21
+ file: string;
22
+ outline: NodeInfo | null;
23
+ hasError: boolean;
24
+ errorCount: number;
25
+ } | {
26
+ kind: 'parse_failed';
27
+ file: string;
28
+ reason: string;
29
+ };
30
+ /**
31
+ * Converts one line of a root `.gitignore` into fast-glob ignore patterns,
32
+ * anchored to `cwd` where git semantics require anchoring.
33
+ *
34
+ * Scope: only the root `.gitignore` of the current working directory.
35
+ * Nested `.gitignore` files and negation patterns (`!foo`) are out of scope.
36
+ *
37
+ * A bare name with no `/` at all (`dist`) matches at any depth: `dist` and
38
+ * `**\/dist` (as a file or directory) plus their contents — these globs stay
39
+ * relative because depth-independent matching works the same whether the
40
+ * search pattern fast-glob resolves against is absolute or relative.
41
+ *
42
+ * Per real `git check-ignore` semantics, ANY other `/` in the pattern
43
+ * anchors it to the `.gitignore`'s directory: a leading slash (`/dist`) is
44
+ * the explicit form, but a mid-path slash (`src/generated`) anchors just as
45
+ * much — git does not treat it as depth-independent. Anchored patterns are
46
+ * emitted as absolute globs (`${cwd}/pattern`, `${cwd}/pattern/**`) rather
47
+ * than bare relative ones. fast-glob resolves a relative ignore glob against
48
+ * the search pattern's own base, not against `cwd`; when `findFiles` is
49
+ * called with an absolute search pattern (a supported path — see
50
+ * `cli-argument-parser.ts`'s `isAbsolute` check) that base becomes `/` and a
51
+ * relative anchored glob like `vendor` silently stops matching. Prefixing
52
+ * with `cwd` makes the ignore glob resolve correctly regardless of whether
53
+ * the search pattern itself is absolute or relative.
54
+ *
55
+ * A trailing slash (`dist/`) restricts the pattern to directories: git never
56
+ * excludes a file literally named `dist` in that case, so the emitted globs
57
+ * cover only `dist`-as-a-directory (`dist/**`) and never the bare `dist` /
58
+ * `**\/dist` forms that would also match a same-named file.
59
+ *
60
+ * `resolve()` returns OS-native separators (backslashes on Windows), which
61
+ * fast-glob's own docs call out as broken input — glob expressions must use
62
+ * forward slashes (see fast-glob's README, "Bad" example:
63
+ * `path.join(process.cwd(), '**')`; the fix is `fg.convertPathToPattern()`).
64
+ * Anchored globs run through `fg.convertPathToPattern()` before use so
65
+ * ignore matching works the same on Windows as on POSIX.
66
+ */
67
+ export declare const gitignoreLineToGlobs: (line: string, cwd: string) => string[];
68
+ /**
69
+ * Reads the root `.gitignore` at `cwd` (if present) and returns fast-glob
70
+ * ignore patterns for its rules. Blank lines, comments (`#`), and negation
71
+ * lines (`!pattern`) are dropped silently — negation support is out of scope
72
+ * for a root-only reader.
73
+ */
74
+ export declare const readGitignorePatterns: (cwd: string) => string[];
9
75
  export declare class FileProcessor {
10
- private parser;
11
- constructor();
76
+ private readonly parser;
77
+ private readonly glob;
78
+ constructor(parser?: Parser, glob?: typeof fg);
12
79
  findFiles(pattern: string): Promise<string[]>;
13
80
  private parseFile;
14
- processFiles(files: string[], depth: number, namedOnly: boolean): Promise<ProcessedFile[]>;
81
+ processFiles(files: string[], depth: number, namedOnly: boolean): Promise<ParseFileOutcome[]>;
15
82
  }
16
83
  //# sourceMappingURL=file-processor.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"file-processor.d.ts","sourceRoot":"","sources":["../src/file-processor.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AAG7D,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,QAAQ,GAAG,IAAI,CAAC;CAC1B;AAED,qBAAa,kBAAmB,SAAQ,KAAK;gBAC/B,OAAO,EAAE,MAAM;CAI5B;AAED,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAS;;IAMV,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;YAe5C,SAAS;IAsBV,YAAY,CACvB,KAAK,EAAE,MAAM,EAAE,EACf,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,OAAO,GACjB,OAAO,CAAC,aAAa,EAAE,CAAC;CAQ5B"}
1
+ {"version":3,"file":"file-processor.d.ts","sourceRoot":"","sources":["../src/file-processor.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,WAAW,CAAC;AAC3B,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AAC7D,OAAO,EAAE,MAAM,EAAE,MAAM,8BAA8B,CAAC;AAEtD,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,QAAQ,GAAG,IAAI,CAAC;IACzB,QAAQ,EAAE,OAAO,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,qBAAa,kBAAmB,SAAQ,KAAK;gBAC/B,OAAO,EAAE,MAAM;CAI5B;AAED;;;;;GAKG;AACH,MAAM,MAAM,gBAAgB,GACxB;IACE,IAAI,EAAE,QAAQ,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,QAAQ,GAAG,IAAI,CAAC;IACzB,QAAQ,EAAE,OAAO,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACpB,GACD;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAE3D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,eAAO,MAAM,oBAAoB,GAAI,MAAM,MAAM,EAAE,KAAK,MAAM,KAAG,MAAM,EAkCtE,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,GAAI,KAAK,MAAM,KAAG,MAAM,EAsBzD,CAAC;AAEF,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAY;gBAErB,MAAM,GAAE,MAAqB,EAAE,IAAI,GAAE,OAAO,EAAO;IAKlD,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;YAgC5C,SAAS;IA6BV,YAAY,CACvB,KAAK,EAAE,MAAM,EAAE,EACf,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,OAAO,GACjB,OAAO,CAAC,gBAAgB,EAAE,CAAC;CAQ/B"}
@@ -1,48 +1,158 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.FileProcessor = exports.FileProcessorError = void 0;
7
- const node_path_1 = require("node:path");
8
- const fast_glob_1 = __importDefault(require("fast-glob"));
9
- const code_outline_parser_1 = require("@sammons/code-outline-parser");
10
- class FileProcessorError extends Error {
1
+ import { resolve } from 'node:path';
2
+ import { readFileSync } from 'node:fs';
3
+ import fg from 'fast-glob';
4
+ import { Parser } from '@sammons/code-outline-parser';
5
+ export class FileProcessorError extends Error {
11
6
  constructor(message) {
12
7
  super(message);
13
8
  this.name = 'FileProcessorError';
14
9
  }
15
10
  }
16
- exports.FileProcessorError = FileProcessorError;
17
- class FileProcessor {
11
+ /**
12
+ * Converts one line of a root `.gitignore` into fast-glob ignore patterns,
13
+ * anchored to `cwd` where git semantics require anchoring.
14
+ *
15
+ * Scope: only the root `.gitignore` of the current working directory.
16
+ * Nested `.gitignore` files and negation patterns (`!foo`) are out of scope.
17
+ *
18
+ * A bare name with no `/` at all (`dist`) matches at any depth: `dist` and
19
+ * `**\/dist` (as a file or directory) plus their contents — these globs stay
20
+ * relative because depth-independent matching works the same whether the
21
+ * search pattern fast-glob resolves against is absolute or relative.
22
+ *
23
+ * Per real `git check-ignore` semantics, ANY other `/` in the pattern
24
+ * anchors it to the `.gitignore`'s directory: a leading slash (`/dist`) is
25
+ * the explicit form, but a mid-path slash (`src/generated`) anchors just as
26
+ * much — git does not treat it as depth-independent. Anchored patterns are
27
+ * emitted as absolute globs (`${cwd}/pattern`, `${cwd}/pattern/**`) rather
28
+ * than bare relative ones. fast-glob resolves a relative ignore glob against
29
+ * the search pattern's own base, not against `cwd`; when `findFiles` is
30
+ * called with an absolute search pattern (a supported path — see
31
+ * `cli-argument-parser.ts`'s `isAbsolute` check) that base becomes `/` and a
32
+ * relative anchored glob like `vendor` silently stops matching. Prefixing
33
+ * with `cwd` makes the ignore glob resolve correctly regardless of whether
34
+ * the search pattern itself is absolute or relative.
35
+ *
36
+ * A trailing slash (`dist/`) restricts the pattern to directories: git never
37
+ * excludes a file literally named `dist` in that case, so the emitted globs
38
+ * cover only `dist`-as-a-directory (`dist/**`) and never the bare `dist` /
39
+ * `**\/dist` forms that would also match a same-named file.
40
+ *
41
+ * `resolve()` returns OS-native separators (backslashes on Windows), which
42
+ * fast-glob's own docs call out as broken input — glob expressions must use
43
+ * forward slashes (see fast-glob's README, "Bad" example:
44
+ * `path.join(process.cwd(), '**')`; the fix is `fg.convertPathToPattern()`).
45
+ * Anchored globs run through `fg.convertPathToPattern()` before use so
46
+ * ignore matching works the same on Windows as on POSIX.
47
+ */
48
+ export const gitignoreLineToGlobs = (line, cwd) => {
49
+ const isDirectoryOnly = line.endsWith('/');
50
+ const withoutTrailingSlash = isDirectoryOnly ? line.slice(0, -1) : line;
51
+ const isLeadingSlash = withoutTrailingSlash.startsWith('/');
52
+ const pattern = isLeadingSlash
53
+ ? withoutTrailingSlash.slice(1)
54
+ : withoutTrailingSlash;
55
+ if (pattern.length === 0) {
56
+ return [];
57
+ }
58
+ // Per git semantics, any remaining `/` in the pattern (a mid-path slash,
59
+ // e.g. `src/generated`) anchors it to `cwd` just like a leading slash did.
60
+ // Only a pattern with zero slashes anywhere is depth-independent.
61
+ const isRootAnchored = isLeadingSlash || pattern.includes('/');
62
+ if (isRootAnchored) {
63
+ // Convert ONLY the cwd segment: fg.convertPathToPattern escapes every
64
+ // glob metacharacter it sees, so running the joined path through it
65
+ // would turn an intentional wildcard in the .gitignore line (e.g.
66
+ // `src/test-scenarios/*/temp/`) into a literal `\*`. Gitignore patterns
67
+ // are always `/`-separated per git, so joining with `/` is correct on
68
+ // every platform once cwd has been normalized.
69
+ const absoluteCwd = fg.convertPathToPattern(resolve(cwd));
70
+ const absolutePattern = `${absoluteCwd}/${pattern}`;
71
+ return isDirectoryOnly
72
+ ? [`${absolutePattern}/**`]
73
+ : [absolutePattern, `${absolutePattern}/**`];
74
+ }
75
+ return isDirectoryOnly
76
+ ? [`${pattern}/**`, `**/${pattern}/**`]
77
+ : [pattern, `**/${pattern}`, `${pattern}/**`, `**/${pattern}/**`];
78
+ };
79
+ /**
80
+ * Reads the root `.gitignore` at `cwd` (if present) and returns fast-glob
81
+ * ignore patterns for its rules. Blank lines, comments (`#`), and negation
82
+ * lines (`!pattern`) are dropped silently — negation support is out of scope
83
+ * for a root-only reader.
84
+ */
85
+ export const readGitignorePatterns = (cwd) => {
86
+ let contents;
87
+ try {
88
+ contents = readFileSync(resolve(cwd, '.gitignore'), 'utf8');
89
+ }
90
+ catch {
91
+ // Treats every read failure (file absent, EACCES, EISDIR, etc.) as "no
92
+ // .gitignore to honor." The safe default is behaving as if there is no
93
+ // ignore file, so any I/O error collapses to the same empty-array
94
+ // fallback rather than surfacing a distinct error path.
95
+ return [];
96
+ }
97
+ const patterns = [];
98
+ for (const rawLine of contents.split('\n')) {
99
+ const line = rawLine.trim();
100
+ if (line.length === 0 || line.startsWith('#') || line.startsWith('!')) {
101
+ continue;
102
+ }
103
+ patterns.push(...gitignoreLineToGlobs(line, cwd));
104
+ }
105
+ return patterns;
106
+ };
107
+ export class FileProcessor {
18
108
  parser;
19
- constructor() {
20
- this.parser = new code_outline_parser_1.Parser();
109
+ glob;
110
+ constructor(parser = new Parser(), glob = fg) {
111
+ this.parser = parser;
112
+ this.glob = glob;
21
113
  }
22
114
  async findFiles(pattern) {
23
- const files = await (0, fast_glob_1.default)(pattern, {
115
+ const gitignorePatterns = readGitignorePatterns(process.cwd());
116
+ // followSymbolicLinks: false stops fast-glob from descending into
117
+ // symlinked directories at all, so a directory symlink cycle cannot
118
+ // trigger an ELOOP crash. suppressErrors: true is a defense-in-depth
119
+ // backstop for any other per-entry stat/readdir error (permission
120
+ // denied, race with a deleted file) so one bad entry does not crash
121
+ // an otherwise-successful glob.
122
+ const files = await this.glob(pattern, {
24
123
  absolute: true,
25
- ignore: ['**/node_modules/**', '**/dist/**', '**/build/**'],
124
+ ignore: [
125
+ '**/node_modules/**',
126
+ '**/dist/**',
127
+ '**/build/**',
128
+ ...gitignorePatterns,
129
+ ],
130
+ followSymbolicLinks: false,
131
+ suppressErrors: true,
26
132
  });
27
- if (files.length === 0) {
133
+ const sortedFiles = [...files].sort((a, b) => (a < b ? -1 : a > b ? 1 : 0));
134
+ if (sortedFiles.length === 0) {
28
135
  throw new FileProcessorError(`No files found matching pattern: ${pattern}`);
29
136
  }
30
- return files;
137
+ return sortedFiles;
31
138
  }
32
139
  async parseFile(file, depth, namedOnly) {
33
140
  try {
34
- const outline = await this.parser.parseFile(file, depth, namedOnly);
141
+ const { outline, hasError, errorCount } = await this.parser.parseFile(file, depth, namedOnly);
35
142
  return {
36
- file: (0, node_path_1.resolve)(file),
143
+ kind: 'parsed',
144
+ file: resolve(file),
37
145
  outline,
146
+ hasError,
147
+ errorCount,
38
148
  };
39
149
  }
40
150
  catch (error) {
41
- const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
42
- console.error(`Error parsing ${file}:`, errorMessage);
151
+ const reason = error instanceof Error ? error.message : 'Unknown error occurred';
43
152
  return {
44
- file: (0, node_path_1.resolve)(file),
45
- outline: null,
153
+ kind: 'parse_failed',
154
+ file: resolve(file),
155
+ reason,
46
156
  };
47
157
  }
48
158
  }
@@ -52,5 +162,4 @@ class FileProcessor {
52
162
  return await Promise.all(parsePromises);
53
163
  }
54
164
  }
55
- exports.FileProcessor = FileProcessor;
56
165
  //# sourceMappingURL=file-processor.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"file-processor.js","sourceRoot":"","sources":["../src/file-processor.ts"],"names":[],"mappings":";;;;;;AAAA,yCAAoC;AACpC,0DAA2B;AAE3B,sEAAsD;AAOtD,MAAa,kBAAmB,SAAQ,KAAK;IAC3C,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAC;IACnC,CAAC;CACF;AALD,gDAKC;AAED,MAAa,aAAa;IAChB,MAAM,CAAS;IAEvB;QACE,IAAI,CAAC,MAAM,GAAG,IAAI,4BAAM,EAAE,CAAC;IAC7B,CAAC;IAEM,KAAK,CAAC,SAAS,CAAC,OAAe;QACpC,MAAM,KAAK,GAAG,MAAM,IAAA,mBAAE,EAAC,OAAO,EAAE;YAC9B,QAAQ,EAAE,IAAI;YACd,MAAM,EAAE,CAAC,oBAAoB,EAAE,YAAY,EAAE,aAAa,CAAC;SAC5D,CAAC,CAAC;QAEH,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACvB,MAAM,IAAI,kBAAkB,CAC1B,oCAAoC,OAAO,EAAE,CAC9C,CAAC;QACJ,CAAC;QAED,OAAO,KAAK,CAAC;IACf,CAAC;IAEO,KAAK,CAAC,SAAS,CACrB,IAAY,EACZ,KAAa,EACb,SAAkB;QAElB,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC;YACpE,OAAO;gBACL,IAAI,EAAE,IAAA,mBAAO,EAAC,IAAI,CAAC;gBACnB,OAAO;aACR,CAAC;QACJ,CAAC;QAAC,OAAO,KAAc,EAAE,CAAC;YACxB,MAAM,YAAY,GAChB,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,wBAAwB,CAAC;YACpE,OAAO,CAAC,KAAK,CAAC,iBAAiB,IAAI,GAAG,EAAE,YAAY,CAAC,CAAC;YACtD,OAAO;gBACL,IAAI,EAAE,IAAA,mBAAO,EAAC,IAAI,CAAC;gBACnB,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;IACH,CAAC;IAEM,KAAK,CAAC,YAAY,CACvB,KAAe,EACf,KAAa,EACb,SAAkB;QAElB,8CAA8C;QAC9C,MAAM,aAAa,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CACvC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,KAAK,EAAE,SAAS,CAAC,CACvC,CAAC;QAEF,OAAO,MAAM,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;IAC1C,CAAC;CACF;AAxDD,sCAwDC"}
1
+ {"version":3,"file":"file-processor.js","sourceRoot":"","sources":["../src/file-processor.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
- export { CLIOrchestrator } from './cli-orchestrator';
2
- export { CLIArgumentParser } from './cli-argument-parser';
3
- export { FileProcessor } from './file-processor';
4
- export { CLIOutputHandler } from './cli-output-handler';
1
+ export { CLIOrchestrator } from './cli-orchestrator.ts';
2
+ export { CLIArgumentParser } from './cli-argument-parser.ts';
3
+ export { FileProcessor } from './file-processor.ts';
4
+ export { CLIOutputHandler } from './cli-output-handler.ts';
5
5
  export declare function parseFiles(patterns: string | string[], options?: {
6
6
  format?: 'ascii' | 'json' | 'yaml';
7
7
  depth?: number;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAGrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAGxD,wBAAsB,UAAU,CAC9B,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,EAC3B,OAAO,CAAC,EAAE;IACR,MAAM,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,CAAC;IACnC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,GACA,OAAO,CAAC,MAAM,CAAC,CAoCjB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAGxD,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAG3D,wBAAsB,UAAU,CAC9B,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,EAC3B,OAAO,CAAC,EAAE;IACR,MAAM,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,CAAC;IACnC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,GACA,OAAO,CAAC,MAAM,CAAC,CAkDjB"}
package/dist/index.js CHANGED
@@ -1,53 +1,12 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
- Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.CLIOutputHandler = exports.FileProcessor = exports.CLIArgumentParser = exports.CLIOrchestrator = void 0;
37
- exports.parseFiles = parseFiles;
38
1
  // Main orchestrator for programmatic usage
39
- var cli_orchestrator_1 = require("./cli-orchestrator");
40
- Object.defineProperty(exports, "CLIOrchestrator", { enumerable: true, get: function () { return cli_orchestrator_1.CLIOrchestrator; } });
2
+ export { CLIOrchestrator } from "./cli-orchestrator.js";
41
3
  // Individual components
42
- var cli_argument_parser_1 = require("./cli-argument-parser");
43
- Object.defineProperty(exports, "CLIArgumentParser", { enumerable: true, get: function () { return cli_argument_parser_1.CLIArgumentParser; } });
44
- var file_processor_1 = require("./file-processor");
45
- Object.defineProperty(exports, "FileProcessor", { enumerable: true, get: function () { return file_processor_1.FileProcessor; } });
46
- var cli_output_handler_1 = require("./cli-output-handler");
47
- Object.defineProperty(exports, "CLIOutputHandler", { enumerable: true, get: function () { return cli_output_handler_1.CLIOutputHandler; } });
4
+ export { CLIArgumentParser } from "./cli-argument-parser.js";
5
+ export { FileProcessor } from "./file-processor.js";
6
+ export { CLIOutputHandler } from "./cli-output-handler.js";
48
7
  // Convenience function for simple usage
49
- async function parseFiles(patterns, options) {
50
- const { FileProcessor } = await Promise.resolve().then(() => __importStar(require('./file-processor')));
8
+ export async function parseFiles(patterns, options) {
9
+ const { FileProcessor } = await import("./file-processor.js");
51
10
  const fileProcessor = new FileProcessor();
52
11
  const patternArray = Array.isArray(patterns) ? patterns : [patterns];
53
12
  // Find matching files for all patterns
@@ -59,14 +18,25 @@ async function parseFiles(patterns, options) {
59
18
  // Remove duplicates
60
19
  const uniqueFiles = [...new Set(allFiles)];
61
20
  // Process files
62
- const results = await fileProcessor.processFiles(uniqueFiles, options?.depth ?? 10, // Default depth
21
+ const outcomes = await fileProcessor.processFiles(uniqueFiles, options?.depth ?? 10, // Default depth
63
22
  options?.namedOnly ?? false);
64
- // Format output
65
- const { Formatter } = await Promise.resolve().then(() => __importStar(require('@sammons/code-outline-formatter')));
23
+ // Format output. A parse_failed outcome (issue #9) has no outline to
24
+ // show; it renders the same as a legitimately-empty file rather than
25
+ // this convenience wrapper growing its own diagnostic-printing contract
26
+ // -- that contract lives in CLIOrchestrator for the actual CLI entry
27
+ // point, which this function is not.
28
+ const results = outcomes.map((outcome) => outcome.kind === 'parsed'
29
+ ? {
30
+ file: outcome.file,
31
+ outline: outcome.outline,
32
+ hasError: outcome.hasError,
33
+ }
34
+ : { file: outcome.file, outline: null, hasError: false });
35
+ const { Formatter } = await import('@sammons/code-outline-formatter');
66
36
  const formatter = new Formatter(options?.format ?? 'ascii');
67
37
  const output = formatter.format(results);
68
38
  if (options?.output) {
69
- const fs = await Promise.resolve().then(() => __importStar(require('fs')));
39
+ const fs = await import('fs');
70
40
  await fs.promises.writeFile(options.output, output, 'utf-8');
71
41
  return `Results written to ${options.output}`;
72
42
  }