@sammons/code-outline-cli 2.1.1 → 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.
- package/README.md +45 -15
- package/dist/cli-argument-parser.d.ts +1 -1
- package/dist/cli-argument-parser.d.ts.map +1 -1
- package/dist/cli-argument-parser.js +146 -53
- package/dist/cli-argument-parser.js.map +1 -1
- package/dist/cli-orchestrator.d.ts.map +1 -1
- package/dist/cli-orchestrator.js +76 -6
- package/dist/cli-orchestrator.js.map +1 -1
- package/dist/file-processor.d.ts +65 -1
- package/dist/file-processor.d.ts.map +1 -1
- package/dist/file-processor.js +122 -7
- package/dist/file-processor.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +13 -2
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -15,7 +15,7 @@ A CLI tool that parses JavaScript/TypeScript files using tree-sitter and provide
|
|
|
15
15
|
## 📦 Installation
|
|
16
16
|
|
|
17
17
|
```bash
|
|
18
|
-
npm install -g @sammons/code-outline-cli
|
|
18
|
+
npm install -g @sammons/code-outline-cli
|
|
19
19
|
```
|
|
20
20
|
|
|
21
21
|
Or use directly with npx:
|
|
@@ -39,17 +39,25 @@ code-outline "src/**/*.ts"
|
|
|
39
39
|
code-outline "**/*.{js,ts,tsx}"
|
|
40
40
|
```
|
|
41
41
|
|
|
42
|
+
### Multiple Patterns
|
|
43
|
+
|
|
44
|
+
Pass more than one pattern in a single run. The CLI unions the matches from every pattern and dedupes them by absolute path.
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
code-outline "src/**/*.ts" "test/**/*.ts"
|
|
48
|
+
```
|
|
49
|
+
|
|
42
50
|
### Output Formats
|
|
43
51
|
|
|
44
52
|
```bash
|
|
45
|
-
#
|
|
53
|
+
# ASCII tree output (default, great for documentation)
|
|
54
|
+
code-outline src/index.ts --format ascii
|
|
55
|
+
|
|
56
|
+
# JSON output
|
|
46
57
|
code-outline src/index.ts --format json
|
|
47
58
|
|
|
48
59
|
# YAML output
|
|
49
60
|
code-outline src/index.ts --format yaml
|
|
50
|
-
|
|
51
|
-
# ASCII tree output (great for documentation)
|
|
52
|
-
code-outline src/index.ts --format ascii
|
|
53
61
|
```
|
|
54
62
|
|
|
55
63
|
### Depth Control
|
|
@@ -70,19 +78,41 @@ code-outline src/index.ts --named-only
|
|
|
70
78
|
|
|
71
79
|
# Show all nodes including anonymous ones
|
|
72
80
|
code-outline src/index.ts --all
|
|
81
|
+
|
|
82
|
+
# Disable named-only filtering without --all
|
|
83
|
+
code-outline src/index.ts --no-named-only
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### LLM-Optimized Output
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
# Generate LLM-optimized compressed output
|
|
90
|
+
code-outline src/index.ts --llmtext
|
|
91
|
+
|
|
92
|
+
# Errors: --llmtext conflicts with an explicit --format other than llmtext
|
|
93
|
+
code-outline src/index.ts --llmtext --format json
|
|
73
94
|
```
|
|
74
95
|
|
|
75
96
|
## 📋 Command Line Options
|
|
76
97
|
|
|
77
|
-
| Option | Alias | Description
|
|
78
|
-
| ------------------ | ----- |
|
|
79
|
-
| `--format <type>` | `-f` | Output format: `ascii
|
|
80
|
-
| `--depth <number>` | `-d` | Maximum depth to traverse
|
|
81
|
-
| `--named-only` | | Show only named nodes
|
|
82
|
-
| `--all` | `-a` | Show all nodes
|
|
83
|
-
| `--llmtext` | | Generate LLM-optimized compressed output | `false` |
|
|
84
|
-
| `--help` | `-h` | Show help message
|
|
85
|
-
| `--version` | `-v` | Show version number
|
|
98
|
+
| Option | Alias | Description | Default |
|
|
99
|
+
| ------------------ | ----- | ----------------------------------------------------------------------------------------------------------------------------- | ---------- |
|
|
100
|
+
| `--format <type>` | `-f` | Output format: `ascii`, `json`, `yaml`, or `llmtext`. Errors if combined with an explicit `--llmtext` for a different format. | `ascii` |
|
|
101
|
+
| `--depth <number>` | `-d` | Maximum AST depth to traverse. A non-negative integer, or `Infinity`. `0` means top-level only. Non-integers are rejected. | `Infinity` |
|
|
102
|
+
| `--named-only` | | Show only named AST nodes. Disable with `--no-named-only` or `--named-only=false`. | `true` |
|
|
103
|
+
| `--all` | `-a` | Show all nodes, including unnamed ones. Always wins over `--named-only`. | `false` |
|
|
104
|
+
| `--llmtext` | | Generate LLM-optimized compressed output. Errors if combined with an explicit `--format` other than `llmtext`. | `false` |
|
|
105
|
+
| `--help` | `-h` | Show help message | - |
|
|
106
|
+
| `--version` | `-v` | Show version number | - |
|
|
107
|
+
|
|
108
|
+
## 🚦 Exit Codes
|
|
109
|
+
|
|
110
|
+
| Code | Meaning |
|
|
111
|
+
| ---- | ------------------------------------------------------------------------------------------------------------------------------------ |
|
|
112
|
+
| `0` | Success, or `-h`/`--help`/`-v`/`--version` requested |
|
|
113
|
+
| `1` | Any error: unknown option, invalid flag value, no pattern given, no files matched, a file that failed to parse, or conflicting flags |
|
|
114
|
+
|
|
115
|
+
Errors print one diagnostic line per failure to stderr, then a one-line usage hint (`Run with --help for usage.`). Most errors (an unknown option, no files matched) print exactly one diagnostic line; a batch with multiple files that failed to parse prints one `Error parsing <file>: ...` line per failed file. The help banner prints to stdout only on `-h`/`--help`.
|
|
86
116
|
|
|
87
117
|
## 📖 Examples
|
|
88
118
|
|
|
@@ -210,7 +240,7 @@ code-outline "**/*.ts" | jq '[.[] | .outline.children[] | select(.type == "funct
|
|
|
210
240
|
|
|
211
241
|
## 🔧 Requirements
|
|
212
242
|
|
|
213
|
-
- Node.js >=
|
|
243
|
+
- Node.js >= 26.0.0
|
|
214
244
|
- npm or pnpm
|
|
215
245
|
|
|
216
246
|
## 📚 Programmatic Usage
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli-argument-parser.d.ts","sourceRoot":"","sources":["../src/cli-argument-parser.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"cli-argument-parser.d.ts","sourceRoot":"","sources":["../src/cli-argument-parser.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AA2BjE,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,YAAY,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,UAAU,CAAC;IACpB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,qBAAa,gBAAiB,SAAQ,KAAK;gBAC7B,OAAO,EAAE,MAAM;CAI5B;AAsED,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAiB;IACtC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAA4B;gBAG9C,IAAI,GAAE,MAAM,MAAM,EAAuB,EACzC,GAAG,GAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAwC;IAOpE,OAAO,CAAC,gBAAgB;IAaxB,OAAO,CAAC,gBAAgB;IAajB,SAAS,IAAI,IAAI;IAmEjB,YAAY,IAAI,IAAI;IAIpB,KAAK,IAAI,UAAU;CAuK3B"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { parseArgs } from 'node:util';
|
|
2
2
|
import { isAbsolute } from 'node:path';
|
|
3
3
|
import { existsSync } from 'node:fs';
|
|
4
|
-
import { validateFormat
|
|
4
|
+
import { validateFormat } from '@sammons/code-outline-parser';
|
|
5
5
|
import { readFileSync } from 'node:fs';
|
|
6
6
|
import { join } from 'node:path';
|
|
7
7
|
// Read the version at runtime rather than importing package.json. A JSON import
|
|
@@ -31,6 +31,45 @@ export class CLIArgumentError extends Error {
|
|
|
31
31
|
this.name = 'CLIArgumentError';
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
|
+
const extractNamedOnlyOverride = (args) => {
|
|
35
|
+
const remainingArgs = [];
|
|
36
|
+
let namedOnlyOverride;
|
|
37
|
+
for (const arg of args) {
|
|
38
|
+
if (arg === '--no-named-only') {
|
|
39
|
+
namedOnlyOverride = false;
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
if (arg === '--named-only=true') {
|
|
43
|
+
namedOnlyOverride = true;
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
if (arg === '--named-only=false') {
|
|
47
|
+
namedOnlyOverride = false;
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
remainingArgs.push(arg);
|
|
51
|
+
}
|
|
52
|
+
return { remainingArgs, namedOnlyOverride };
|
|
53
|
+
};
|
|
54
|
+
const validateDepthFlag = (raw) => {
|
|
55
|
+
if (raw === 'Infinity') {
|
|
56
|
+
return { success: true, value: Infinity };
|
|
57
|
+
}
|
|
58
|
+
if (!/^-?\d+$/.test(raw)) {
|
|
59
|
+
return {
|
|
60
|
+
success: false,
|
|
61
|
+
error: `Depth must be a non-negative integer or "Infinity", got "${raw}"`,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
const parsed = Number.parseInt(raw, 10);
|
|
65
|
+
if (parsed < 0) {
|
|
66
|
+
return {
|
|
67
|
+
success: false,
|
|
68
|
+
error: `Depth must be a non-negative integer or "Infinity", got "${raw}"`,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
return { success: true, value: parsed };
|
|
72
|
+
};
|
|
34
73
|
export class CLIArgumentParser {
|
|
35
74
|
argv;
|
|
36
75
|
log;
|
|
@@ -63,30 +102,50 @@ export class CLIArgumentParser {
|
|
|
63
102
|
🌳 Code Outline CLI - Parse and analyze JavaScript/TypeScript files
|
|
64
103
|
|
|
65
104
|
Usage:
|
|
66
|
-
code-outline <pattern
|
|
105
|
+
code-outline <pattern>... [options]
|
|
67
106
|
|
|
68
107
|
Arguments:
|
|
69
|
-
<pattern
|
|
108
|
+
<pattern>... One or more glob patterns to match files (e.g., "src/**/*.ts", "*.js").
|
|
109
|
+
Matches from every pattern are unioned and deduped by absolute path.
|
|
70
110
|
|
|
71
111
|
Options:
|
|
72
112
|
-f, --format <type> Output format: ascii, json, yaml, or llmtext (default: ascii)
|
|
73
|
-
-d, --depth <n> Maximum AST depth to traverse
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
--
|
|
113
|
+
-d, --depth <n> Maximum AST depth to traverse: a non-negative integer, or
|
|
114
|
+
"Infinity" (default: Infinity). 0 means top-level only.
|
|
115
|
+
-a, --all Show all nodes, including unnamed ones. Implies --no-named-only.
|
|
116
|
+
--named-only Show only named entities (default: true). Accepts
|
|
117
|
+
--no-named-only or --named-only=false to disable; --all
|
|
118
|
+
disables it too. Mutually exclusive with --all in the
|
|
119
|
+
"widen" direction: --all always wins.
|
|
120
|
+
--llmtext Use LLM-optimized compressed text format. Errors if combined
|
|
121
|
+
with an explicit --format other than llmtext.
|
|
77
122
|
-h, --help Show this help message
|
|
78
123
|
-v, --version Show version number
|
|
79
124
|
|
|
125
|
+
Exit Codes:
|
|
126
|
+
0 Success, or -h/--help/-v/--version requested
|
|
127
|
+
1 Any error: unknown option, invalid flag value, no pattern given, no files
|
|
128
|
+
matched, a file that failed to parse, or conflicting flags
|
|
129
|
+
|
|
80
130
|
Output Formats:
|
|
81
131
|
ascii Tree-like visualization with color-coded syntax (default)
|
|
82
132
|
json Structured JSON output for programmatic processing
|
|
83
133
|
yaml Human-readable YAML format
|
|
84
134
|
llmtext Compressed text format optimized for LLM consumption
|
|
85
135
|
|
|
136
|
+
Position Numbering:
|
|
137
|
+
ascii and llmtext print [line:col] using 1-based line and 1-based column.
|
|
138
|
+
json and yaml keep tree-sitter's native start/end row and column, which
|
|
139
|
+
are 0-based, so a node at row 0, column 0 prints as [1:1] in ascii and
|
|
140
|
+
llmtext but as {"row": 0, "column": 0} in json and yaml.
|
|
141
|
+
|
|
86
142
|
Examples:
|
|
87
143
|
# Parse all TypeScript files in src directory
|
|
88
144
|
code-outline "src/**/*.ts"
|
|
89
145
|
|
|
146
|
+
# Parse multiple patterns at once; matches are unioned and deduped
|
|
147
|
+
code-outline "src/**/*.ts" "test/**/*.ts"
|
|
148
|
+
|
|
90
149
|
# Output JSON with depth limit
|
|
91
150
|
code-outline "*.js" --format json --depth 3
|
|
92
151
|
|
|
@@ -108,42 +167,56 @@ For more information, visit: https://github.com/sammons2/code-outline-cli
|
|
|
108
167
|
this.log(version);
|
|
109
168
|
}
|
|
110
169
|
parse() {
|
|
111
|
-
const {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
170
|
+
const { remainingArgs, namedOnlyOverride } = extractNamedOnlyOverride(this.argv().slice(2));
|
|
171
|
+
let values;
|
|
172
|
+
let positionals;
|
|
173
|
+
let tokens;
|
|
174
|
+
try {
|
|
175
|
+
({ values, positionals, tokens } = parseArgs({
|
|
176
|
+
args: remainingArgs,
|
|
177
|
+
tokens: true,
|
|
178
|
+
options: {
|
|
179
|
+
format: {
|
|
180
|
+
type: 'string',
|
|
181
|
+
short: 'f',
|
|
182
|
+
default: 'ascii',
|
|
183
|
+
},
|
|
184
|
+
depth: {
|
|
185
|
+
type: 'string',
|
|
186
|
+
short: 'd',
|
|
187
|
+
default: 'Infinity',
|
|
188
|
+
},
|
|
189
|
+
'named-only': {
|
|
190
|
+
type: 'boolean',
|
|
191
|
+
default: true,
|
|
192
|
+
},
|
|
193
|
+
all: {
|
|
194
|
+
type: 'boolean',
|
|
195
|
+
short: 'a',
|
|
196
|
+
default: false,
|
|
197
|
+
},
|
|
198
|
+
llmtext: {
|
|
199
|
+
type: 'boolean',
|
|
200
|
+
default: false,
|
|
201
|
+
},
|
|
202
|
+
help: {
|
|
203
|
+
type: 'boolean',
|
|
204
|
+
short: 'h',
|
|
205
|
+
default: false,
|
|
206
|
+
},
|
|
207
|
+
version: {
|
|
208
|
+
type: 'boolean',
|
|
209
|
+
short: 'v',
|
|
210
|
+
default: false,
|
|
211
|
+
},
|
|
143
212
|
},
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
}
|
|
213
|
+
allowPositionals: true,
|
|
214
|
+
}));
|
|
215
|
+
}
|
|
216
|
+
catch (error) {
|
|
217
|
+
const message = error instanceof Error ? error.message : 'Unknown option';
|
|
218
|
+
throw new CLIArgumentError(message);
|
|
219
|
+
}
|
|
147
220
|
if (values.help) {
|
|
148
221
|
this.printHelp();
|
|
149
222
|
process.exit(0);
|
|
@@ -155,23 +228,44 @@ For more information, visit: https://github.com/sammons2/code-outline-cli
|
|
|
155
228
|
if (positionals.length === 0) {
|
|
156
229
|
throw new CLIArgumentError('No file pattern provided');
|
|
157
230
|
}
|
|
231
|
+
// Whether --format was explicitly passed, before we apply the --llmtext
|
|
232
|
+
// override below. parseArgs fills `values.format` with its default even
|
|
233
|
+
// when the flag was never on the command line, so `typeof` alone cannot
|
|
234
|
+
// tell "user asked for json" apart from "format defaulted to ascii" --
|
|
235
|
+
// only the token stream can. This is what makes conflicting-flag
|
|
236
|
+
// detection (issue #20) possible.
|
|
237
|
+
const formatExplicitlyProvided = tokens.some((token) => token.kind === 'option' && token.name === 'format');
|
|
158
238
|
// Safely validate format using type guard
|
|
159
239
|
const formatValidation = validateFormat(values.format);
|
|
160
240
|
const format = this.validateAndThrow(formatValidation, 'Invalid format');
|
|
161
|
-
// Safely validate depth using validator
|
|
162
|
-
|
|
241
|
+
// Safely validate depth using the local validator (issue #21: 0 is valid,
|
|
242
|
+
// non-integers are rejected outright rather than silently floored)
|
|
243
|
+
const depthRaw = this.safeExtractValue(values.depth, 'Infinity');
|
|
244
|
+
const depthValidation = validateDepthFlag(depthRaw);
|
|
163
245
|
const depth = this.validateAndThrow(depthValidation, 'Invalid depth');
|
|
164
|
-
const
|
|
165
|
-
? false
|
|
166
|
-
: this.safeExtractValue(values['named-only'], true);
|
|
246
|
+
const allFlag = this.safeExtractValue(values.all, false);
|
|
167
247
|
const llmtext = this.safeExtractValue(values.llmtext, false);
|
|
248
|
+
if (llmtext && formatExplicitlyProvided && format !== 'llmtext') {
|
|
249
|
+
throw new CLIArgumentError(`--llmtext conflicts with --format ${format}. Pass only one, or set --format llmtext.`);
|
|
250
|
+
}
|
|
251
|
+
// --all always widens output regardless of --named-only/--no-named-only.
|
|
252
|
+
// Otherwise an explicit --no-named-only/--named-only=false wins over the
|
|
253
|
+
// boolean flag's default; absent any override, the boolean flag's own
|
|
254
|
+
// value (default true) applies.
|
|
255
|
+
const namedOnly = allFlag
|
|
256
|
+
? false
|
|
257
|
+
: (namedOnlyOverride ??
|
|
258
|
+
this.safeExtractValue(values['named-only'], true));
|
|
168
259
|
// If --llmtext flag is provided, override format to 'llmtext'
|
|
169
260
|
const finalFormat = llmtext ? 'llmtext' : format;
|
|
170
|
-
const
|
|
261
|
+
const patterns = [...new Set(positionals)];
|
|
171
262
|
// Warn if the pattern doesn't contain glob characters but looks like it should
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
263
|
+
for (const pattern of patterns) {
|
|
264
|
+
if (pattern.includes('*') ||
|
|
265
|
+
pattern.includes('?') ||
|
|
266
|
+
pattern.includes('[')) {
|
|
267
|
+
continue;
|
|
268
|
+
}
|
|
175
269
|
// Check if it's likely intended to be a glob pattern (directory-like structure)
|
|
176
270
|
const pathSegments = pattern
|
|
177
271
|
.split('/')
|
|
@@ -182,7 +276,6 @@ For more information, visit: https://github.com/sammons2/code-outline-cli
|
|
|
182
276
|
// (relative paths with many segments are likely intended as globs, but existing files should not warn)
|
|
183
277
|
const isAbsolutePath = isAbsolute(pattern);
|
|
184
278
|
const fileExists = existsSync(pattern);
|
|
185
|
-
// Debug: Show the evaluation
|
|
186
279
|
const shouldWarn = hasMultipleSegments &&
|
|
187
280
|
endsWithCommonExtension &&
|
|
188
281
|
!isAbsolutePath &&
|
|
@@ -203,7 +296,7 @@ For more information, visit: https://github.com/sammons2/code-outline-cli
|
|
|
203
296
|
help: false,
|
|
204
297
|
version: false,
|
|
205
298
|
},
|
|
206
|
-
|
|
299
|
+
patterns,
|
|
207
300
|
};
|
|
208
301
|
}
|
|
209
302
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli-argument-parser.js","sourceRoot":"","sources":["../src/cli-argument-parser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAErC,OAAO,
|
|
1
|
+
{"version":3,"file":"cli-argument-parser.js","sourceRoot":"","sources":["../src/cli-argument-parser.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli-orchestrator.d.ts","sourceRoot":"","sources":["../src/cli-orchestrator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAoB,MAAM,0BAA0B,CAAC;AAC/E,OAAO,EAAE,aAAa,EAAsB,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"cli-orchestrator.d.ts","sourceRoot":"","sources":["../src/cli-orchestrator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAoB,MAAM,0BAA0B,CAAC;AAC/E,OAAO,EAAE,aAAa,EAAsB,MAAM,qBAAqB,CAAC;AAExE,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAEjE,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAoB;IACnD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAgB;IAC9C,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAGf;IACtB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAA0B;IAC/C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA4B;gBAGnD,cAAc,GAAE,iBAA2C,EAC3D,aAAa,GAAE,aAAmC,EAClD,oBAAoB,GAAE,CACpB,MAAM,EAAE,YAAY,EACpB,OAAO,CAAC,EAAE,OAAO,KACd,gBACkC,EACvC,IAAI,GAAE,CAAC,IAAI,EAAE,MAAM,KAAK,KAAoC,EAC5D,QAAQ,GAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAA0C;IAS9D,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CAkHlC"}
|
package/dist/cli-orchestrator.js
CHANGED
|
@@ -17,23 +17,93 @@ export class CLIOrchestrator {
|
|
|
17
17
|
async run() {
|
|
18
18
|
try {
|
|
19
19
|
// Parse and validate arguments
|
|
20
|
-
const { options,
|
|
21
|
-
// Find matching files
|
|
22
|
-
|
|
23
|
-
//
|
|
24
|
-
|
|
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
|
+
});
|
|
25
64
|
// Format and output results
|
|
26
65
|
const outputHandler = this.outputHandlerFactory(options.format, options.llmtext);
|
|
27
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
|
+
}
|
|
28
97
|
}
|
|
29
98
|
catch (error) {
|
|
30
99
|
if (error instanceof CLIArgumentError) {
|
|
31
100
|
this.logError(`Error: ${error.message}`);
|
|
32
|
-
this.
|
|
101
|
+
this.logError('Run with --help for usage.');
|
|
33
102
|
this.exit(1);
|
|
34
103
|
}
|
|
35
104
|
else if (error instanceof FileProcessorError) {
|
|
36
105
|
this.logError(error.message);
|
|
106
|
+
this.logError('Run with --help for usage.');
|
|
37
107
|
this.exit(1);
|
|
38
108
|
}
|
|
39
109
|
else {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli-orchestrator.js","sourceRoot":"","sources":["../src/cli-orchestrator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC/E,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"cli-orchestrator.js","sourceRoot":"","sources":["../src/cli-orchestrator.ts"],"names":[],"mappings":"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"}
|
package/dist/file-processor.d.ts
CHANGED
|
@@ -4,16 +4,80 @@ import { Parser } from '@sammons/code-outline-parser';
|
|
|
4
4
|
export interface ProcessedFile {
|
|
5
5
|
file: string;
|
|
6
6
|
outline: NodeInfo | null;
|
|
7
|
+
hasError: boolean;
|
|
8
|
+
errorCount: number;
|
|
7
9
|
}
|
|
8
10
|
export declare class FileProcessorError extends Error {
|
|
9
11
|
constructor(message: string);
|
|
10
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[];
|
|
11
75
|
export declare class FileProcessor {
|
|
12
76
|
private readonly parser;
|
|
13
77
|
private readonly glob;
|
|
14
78
|
constructor(parser?: Parser, glob?: typeof fg);
|
|
15
79
|
findFiles(pattern: string): Promise<string[]>;
|
|
16
80
|
private parseFile;
|
|
17
|
-
processFiles(files: string[], depth: number, namedOnly: boolean): Promise<
|
|
81
|
+
processFiles(files: string[], depth: number, namedOnly: boolean): Promise<ParseFileOutcome[]>;
|
|
18
82
|
}
|
|
19
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":"
|
|
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"}
|
package/dist/file-processor.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { resolve } from 'node:path';
|
|
2
|
+
import { readFileSync } from 'node:fs';
|
|
2
3
|
import fg from 'fast-glob';
|
|
3
4
|
import { Parser } from '@sammons/code-outline-parser';
|
|
4
5
|
export class FileProcessorError extends Error {
|
|
@@ -7,6 +8,102 @@ export class FileProcessorError extends Error {
|
|
|
7
8
|
this.name = 'FileProcessorError';
|
|
8
9
|
}
|
|
9
10
|
}
|
|
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
|
+
};
|
|
10
107
|
export class FileProcessor {
|
|
11
108
|
parser;
|
|
12
109
|
glob;
|
|
@@ -15,29 +112,47 @@ export class FileProcessor {
|
|
|
15
112
|
this.glob = glob;
|
|
16
113
|
}
|
|
17
114
|
async findFiles(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.
|
|
18
122
|
const files = await this.glob(pattern, {
|
|
19
123
|
absolute: true,
|
|
20
|
-
ignore: [
|
|
124
|
+
ignore: [
|
|
125
|
+
'**/node_modules/**',
|
|
126
|
+
'**/dist/**',
|
|
127
|
+
'**/build/**',
|
|
128
|
+
...gitignorePatterns,
|
|
129
|
+
],
|
|
130
|
+
followSymbolicLinks: false,
|
|
131
|
+
suppressErrors: true,
|
|
21
132
|
});
|
|
22
|
-
|
|
133
|
+
const sortedFiles = [...files].sort((a, b) => (a < b ? -1 : a > b ? 1 : 0));
|
|
134
|
+
if (sortedFiles.length === 0) {
|
|
23
135
|
throw new FileProcessorError(`No files found matching pattern: ${pattern}`);
|
|
24
136
|
}
|
|
25
|
-
return
|
|
137
|
+
return sortedFiles;
|
|
26
138
|
}
|
|
27
139
|
async parseFile(file, depth, namedOnly) {
|
|
28
140
|
try {
|
|
29
|
-
const outline = await this.parser.parseFile(file, depth, namedOnly);
|
|
141
|
+
const { outline, hasError, errorCount } = await this.parser.parseFile(file, depth, namedOnly);
|
|
30
142
|
return {
|
|
143
|
+
kind: 'parsed',
|
|
31
144
|
file: resolve(file),
|
|
32
145
|
outline,
|
|
146
|
+
hasError,
|
|
147
|
+
errorCount,
|
|
33
148
|
};
|
|
34
149
|
}
|
|
35
150
|
catch (error) {
|
|
36
|
-
const
|
|
37
|
-
console.error(`Error parsing ${file}:`, errorMessage);
|
|
151
|
+
const reason = error instanceof Error ? error.message : 'Unknown error occurred';
|
|
38
152
|
return {
|
|
153
|
+
kind: 'parse_failed',
|
|
39
154
|
file: resolve(file),
|
|
40
|
-
|
|
155
|
+
reason,
|
|
41
156
|
};
|
|
42
157
|
}
|
|
43
158
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file-processor.js","sourceRoot":"","sources":["../src/file-processor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,MAAM,WAAW,CAAC;AAE3B,OAAO,EAAE,MAAM,EAAE,MAAM,8BAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"file-processor.js","sourceRoot":"","sources":["../src/file-processor.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
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,
|
|
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
|
@@ -18,9 +18,20 @@ export async function parseFiles(patterns, options) {
|
|
|
18
18
|
// Remove duplicates
|
|
19
19
|
const uniqueFiles = [...new Set(allFiles)];
|
|
20
20
|
// Process files
|
|
21
|
-
const
|
|
21
|
+
const outcomes = await fileProcessor.processFiles(uniqueFiles, options?.depth ?? 10, // Default depth
|
|
22
22
|
options?.namedOnly ?? false);
|
|
23
|
-
// Format output
|
|
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 });
|
|
24
35
|
const { Formatter } = await import('@sammons/code-outline-formatter');
|
|
25
36
|
const formatter = new Formatter(options?.format ?? 'ascii');
|
|
26
37
|
const output = formatter.format(results);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,2CAA2C;AAC3C,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAExD,wBAAwB;AACxB,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAE3D,wCAAwC;AACxC,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,QAA2B,EAC3B,OAKC;IAED,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,MAAM,CAAC,qBAAqB,CAAC,CAAC;IAE9D,MAAM,aAAa,GAAG,IAAI,aAAa,EAAE,CAAC;IAC1C,MAAM,YAAY,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;IAErE,uCAAuC;IACvC,MAAM,QAAQ,GAAG,EAAE,CAAC;IACpB,KAAK,MAAM,OAAO,IAAI,YAAY,EAAE,CAAC;QACnC,MAAM,KAAK,GAAG,MAAM,aAAa,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QACrD,QAAQ,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,CAAC;IAC1B,CAAC;IAED,oBAAoB;IACpB,MAAM,WAAW,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC;IAE3C,gBAAgB;IAChB,MAAM,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,2CAA2C;AAC3C,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAExD,wBAAwB;AACxB,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAE3D,wCAAwC;AACxC,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,QAA2B,EAC3B,OAKC;IAED,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,MAAM,CAAC,qBAAqB,CAAC,CAAC;IAE9D,MAAM,aAAa,GAAG,IAAI,aAAa,EAAE,CAAC;IAC1C,MAAM,YAAY,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;IAErE,uCAAuC;IACvC,MAAM,QAAQ,GAAG,EAAE,CAAC;IACpB,KAAK,MAAM,OAAO,IAAI,YAAY,EAAE,CAAC;QACnC,MAAM,KAAK,GAAG,MAAM,aAAa,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QACrD,QAAQ,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,CAAC;IAC1B,CAAC;IAED,oBAAoB;IACpB,MAAM,WAAW,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC;IAE3C,gBAAgB;IAChB,MAAM,QAAQ,GAAG,MAAM,aAAa,CAAC,YAAY,CAC/C,WAAW,EACX,OAAO,EAAE,KAAK,IAAI,EAAE,EAAE,gBAAgB;IACtC,OAAO,EAAE,SAAS,IAAI,KAAK,CAC5B,CAAC;IAEF,qEAAqE;IACrE,qEAAqE;IACrE,wEAAwE;IACxE,qEAAqE;IACrE,qCAAqC;IACrC,MAAM,OAAO,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CACvC,OAAO,CAAC,IAAI,KAAK,QAAQ;QACvB,CAAC,CAAC;YACE,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,QAAQ,EAAE,OAAO,CAAC,QAAQ;SAC3B;QACH,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,CAC3D,CAAC;IAEF,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,MAAM,CAAC,iCAAiC,CAAC,CAAC;IACtE,MAAM,SAAS,GAAG,IAAI,SAAS,CAAC,OAAO,EAAE,MAAM,IAAI,OAAO,CAAC,CAAC;IAE5D,MAAM,MAAM,GAAG,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAEzC,IAAI,OAAO,EAAE,MAAM,EAAE,CAAC;QACpB,MAAM,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,CAAC;QAC9B,MAAM,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;QAC7D,OAAO,sBAAsB,OAAO,CAAC,MAAM,EAAE,CAAC;IAChD,CAAC;SAAM,CAAC;QACN,OAAO,MAAM,CAAC;IAChB,CAAC;AACH,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sammons/code-outline-cli",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.2.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "CLI tool to parse and provide concise output for JavaScript/TypeScript files",
|
|
6
6
|
"publishConfig": {
|
|
@@ -33,8 +33,8 @@
|
|
|
33
33
|
],
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"fast-glob": "3.3.3",
|
|
36
|
-
"@sammons/code-outline-
|
|
37
|
-
"@sammons/code-outline-
|
|
36
|
+
"@sammons/code-outline-formatter": "2.2.0",
|
|
37
|
+
"@sammons/code-outline-parser": "2.2.0"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@types/node": "24.10.2",
|