@rcrsr/rill-cli 0.6.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 (171) hide show
  1. package/LICENSE +21 -0
  2. package/dist/check/config.d.ts +20 -0
  3. package/dist/check/config.d.ts.map +1 -0
  4. package/dist/check/config.js +151 -0
  5. package/dist/check/config.js.map +1 -0
  6. package/dist/check/fixer.d.ts +39 -0
  7. package/dist/check/fixer.d.ts.map +1 -0
  8. package/dist/check/fixer.js +119 -0
  9. package/dist/check/fixer.js.map +1 -0
  10. package/dist/check/index.d.ts +10 -0
  11. package/dist/check/index.d.ts.map +1 -0
  12. package/dist/check/index.js +21 -0
  13. package/dist/check/index.js.map +1 -0
  14. package/dist/check/rules/anti-patterns.d.ts +65 -0
  15. package/dist/check/rules/anti-patterns.d.ts.map +1 -0
  16. package/dist/check/rules/anti-patterns.js +481 -0
  17. package/dist/check/rules/anti-patterns.js.map +1 -0
  18. package/dist/check/rules/closures.d.ts +66 -0
  19. package/dist/check/rules/closures.d.ts.map +1 -0
  20. package/dist/check/rules/closures.js +370 -0
  21. package/dist/check/rules/closures.js.map +1 -0
  22. package/dist/check/rules/collections.d.ts +90 -0
  23. package/dist/check/rules/collections.d.ts.map +1 -0
  24. package/dist/check/rules/collections.js +373 -0
  25. package/dist/check/rules/collections.js.map +1 -0
  26. package/dist/check/rules/conditionals.d.ts +41 -0
  27. package/dist/check/rules/conditionals.d.ts.map +1 -0
  28. package/dist/check/rules/conditionals.js +134 -0
  29. package/dist/check/rules/conditionals.js.map +1 -0
  30. package/dist/check/rules/flow.d.ts +46 -0
  31. package/dist/check/rules/flow.d.ts.map +1 -0
  32. package/dist/check/rules/flow.js +206 -0
  33. package/dist/check/rules/flow.js.map +1 -0
  34. package/dist/check/rules/formatting.d.ts +143 -0
  35. package/dist/check/rules/formatting.d.ts.map +1 -0
  36. package/dist/check/rules/formatting.js +656 -0
  37. package/dist/check/rules/formatting.js.map +1 -0
  38. package/dist/check/rules/helpers.d.ts +26 -0
  39. package/dist/check/rules/helpers.d.ts.map +1 -0
  40. package/dist/check/rules/helpers.js +66 -0
  41. package/dist/check/rules/helpers.js.map +1 -0
  42. package/dist/check/rules/index.d.ts +21 -0
  43. package/dist/check/rules/index.d.ts.map +1 -0
  44. package/dist/check/rules/index.js +78 -0
  45. package/dist/check/rules/index.js.map +1 -0
  46. package/dist/check/rules/loops.d.ts +77 -0
  47. package/dist/check/rules/loops.d.ts.map +1 -0
  48. package/dist/check/rules/loops.js +310 -0
  49. package/dist/check/rules/loops.js.map +1 -0
  50. package/dist/check/rules/naming.d.ts +21 -0
  51. package/dist/check/rules/naming.d.ts.map +1 -0
  52. package/dist/check/rules/naming.js +174 -0
  53. package/dist/check/rules/naming.js.map +1 -0
  54. package/dist/check/rules/strings.d.ts +28 -0
  55. package/dist/check/rules/strings.d.ts.map +1 -0
  56. package/dist/check/rules/strings.js +79 -0
  57. package/dist/check/rules/strings.js.map +1 -0
  58. package/dist/check/rules/types.d.ts +41 -0
  59. package/dist/check/rules/types.d.ts.map +1 -0
  60. package/dist/check/rules/types.js +167 -0
  61. package/dist/check/rules/types.js.map +1 -0
  62. package/dist/check/types.d.ts +112 -0
  63. package/dist/check/types.d.ts.map +1 -0
  64. package/dist/check/types.js +6 -0
  65. package/dist/check/types.js.map +1 -0
  66. package/dist/check/validator.d.ts +18 -0
  67. package/dist/check/validator.d.ts.map +1 -0
  68. package/dist/check/validator.js +110 -0
  69. package/dist/check/validator.js.map +1 -0
  70. package/dist/check/visitor.d.ts +33 -0
  71. package/dist/check/visitor.d.ts.map +1 -0
  72. package/dist/check/visitor.js +259 -0
  73. package/dist/check/visitor.js.map +1 -0
  74. package/dist/cli-check.d.ts +43 -0
  75. package/dist/cli-check.d.ts.map +1 -0
  76. package/dist/cli-check.js +366 -0
  77. package/dist/cli-check.js.map +1 -0
  78. package/dist/cli-error-enrichment.d.ts +73 -0
  79. package/dist/cli-error-enrichment.d.ts.map +1 -0
  80. package/dist/cli-error-enrichment.js +205 -0
  81. package/dist/cli-error-enrichment.js.map +1 -0
  82. package/dist/cli-error-formatter.d.ts +45 -0
  83. package/dist/cli-error-formatter.d.ts.map +1 -0
  84. package/dist/cli-error-formatter.js +218 -0
  85. package/dist/cli-error-formatter.js.map +1 -0
  86. package/dist/cli-eval.d.ts +15 -0
  87. package/dist/cli-eval.d.ts.map +1 -0
  88. package/dist/cli-eval.js +116 -0
  89. package/dist/cli-eval.js.map +1 -0
  90. package/dist/cli-exec.d.ts +58 -0
  91. package/dist/cli-exec.d.ts.map +1 -0
  92. package/dist/cli-exec.js +326 -0
  93. package/dist/cli-exec.js.map +1 -0
  94. package/dist/cli-explain.d.ts +24 -0
  95. package/dist/cli-explain.d.ts.map +1 -0
  96. package/dist/cli-explain.js +68 -0
  97. package/dist/cli-explain.js.map +1 -0
  98. package/dist/cli-lsp-diagnostic.d.ts +35 -0
  99. package/dist/cli-lsp-diagnostic.d.ts.map +1 -0
  100. package/dist/cli-lsp-diagnostic.js +98 -0
  101. package/dist/cli-lsp-diagnostic.js.map +1 -0
  102. package/dist/cli-module-loader.d.ts +19 -0
  103. package/dist/cli-module-loader.d.ts.map +1 -0
  104. package/dist/cli-module-loader.js +83 -0
  105. package/dist/cli-module-loader.js.map +1 -0
  106. package/dist/cli-shared.d.ts +62 -0
  107. package/dist/cli-shared.d.ts.map +1 -0
  108. package/dist/cli-shared.js +158 -0
  109. package/dist/cli-shared.js.map +1 -0
  110. package/dist/cli.d.ts +13 -0
  111. package/dist/cli.d.ts.map +1 -0
  112. package/dist/cli.js +62 -0
  113. package/dist/cli.js.map +1 -0
  114. package/dist/test-internal-import.d.ts +2 -0
  115. package/dist/test-internal-import.d.ts.map +1 -0
  116. package/dist/test-internal-import.js +7 -0
  117. package/dist/test-internal-import.js.map +1 -0
  118. package/package.json +24 -0
  119. package/src/check/config.ts +202 -0
  120. package/src/check/fixer.ts +174 -0
  121. package/src/check/index.ts +39 -0
  122. package/src/check/rules/anti-patterns.ts +585 -0
  123. package/src/check/rules/closures.ts +445 -0
  124. package/src/check/rules/collections.ts +437 -0
  125. package/src/check/rules/conditionals.ts +155 -0
  126. package/src/check/rules/flow.ts +262 -0
  127. package/src/check/rules/formatting.ts +811 -0
  128. package/src/check/rules/helpers.ts +89 -0
  129. package/src/check/rules/index.ts +140 -0
  130. package/src/check/rules/loops.ts +372 -0
  131. package/src/check/rules/naming.ts +242 -0
  132. package/src/check/rules/strings.ts +104 -0
  133. package/src/check/rules/types.ts +214 -0
  134. package/src/check/types.ts +163 -0
  135. package/src/check/validator.ts +136 -0
  136. package/src/check/visitor.ts +338 -0
  137. package/src/cli-check.ts +456 -0
  138. package/src/cli-error-enrichment.ts +274 -0
  139. package/src/cli-error-formatter.ts +313 -0
  140. package/src/cli-eval.ts +145 -0
  141. package/src/cli-exec.ts +408 -0
  142. package/src/cli-explain.ts +76 -0
  143. package/src/cli-lsp-diagnostic.ts +132 -0
  144. package/src/cli-module-loader.ts +101 -0
  145. package/src/cli-shared.ts +187 -0
  146. package/tests/check/cli-check.test.ts +189 -0
  147. package/tests/check/config.test.ts +350 -0
  148. package/tests/check/fixer.test.ts +373 -0
  149. package/tests/check/format-diagnostics.test.ts +327 -0
  150. package/tests/check/rules/anti-patterns.test.ts +467 -0
  151. package/tests/check/rules/closures.test.ts +192 -0
  152. package/tests/check/rules/collections.test.ts +380 -0
  153. package/tests/check/rules/conditionals.test.ts +185 -0
  154. package/tests/check/rules/flow.test.ts +250 -0
  155. package/tests/check/rules/formatting.test.ts +755 -0
  156. package/tests/check/rules/loops.test.ts +334 -0
  157. package/tests/check/rules/naming.test.ts +336 -0
  158. package/tests/check/rules/strings.test.ts +129 -0
  159. package/tests/check/rules/types.test.ts +257 -0
  160. package/tests/check/validator.test.ts +444 -0
  161. package/tests/check/visitor.test.ts +171 -0
  162. package/tests/cli/check.test.ts +801 -0
  163. package/tests/cli/error-enrichment.test.ts +510 -0
  164. package/tests/cli/error-formatter.test.ts +631 -0
  165. package/tests/cli/eval.test.ts +85 -0
  166. package/tests/cli/exec.test.ts +537 -0
  167. package/tests/cli-explain.test.ts +249 -0
  168. package/tests/cli-lsp-diagnostic.test.ts +202 -0
  169. package/tests/cli-shared.test.ts +439 -0
  170. package/tsconfig.json +9 -0
  171. package/tsconfig.tsbuildinfo +1 -0
@@ -0,0 +1,366 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * CLI Check Entry Point
4
+ *
5
+ * Implements argument parsing for rill-check.
6
+ * Validates Rill source files against linting rules.
7
+ */
8
+ import { VALIDATION_RULES, loadConfig, createDefaultConfig, validateScript, applyFixes, } from './check/index.js';
9
+ import { parseWithRecovery } from '@rcrsr/rill';
10
+ import { VERSION, detectHelpVersionFlag } from './cli-shared.js';
11
+ /**
12
+ * Parse command-line arguments for rill-check
13
+ *
14
+ * @param argv - Raw command-line arguments (typically process.argv.slice(2))
15
+ * @returns Parsed command object
16
+ */
17
+ export function parseCheckArgs(argv) {
18
+ // Check for --help or --version flags in any position
19
+ const helpVersionFlag = detectHelpVersionFlag(argv);
20
+ if (helpVersionFlag !== null) {
21
+ return helpVersionFlag;
22
+ }
23
+ // Extract flags
24
+ const fix = argv.includes('--fix');
25
+ const verbose = argv.includes('--verbose');
26
+ // Extract format flag
27
+ let format = 'text';
28
+ const formatIndex = argv.indexOf('--format');
29
+ if (formatIndex !== -1) {
30
+ const formatValue = argv[formatIndex + 1];
31
+ if (formatValue === 'text' || formatValue === 'json') {
32
+ format = formatValue;
33
+ }
34
+ else if (!formatValue || formatValue.startsWith('-')) {
35
+ throw new Error('--format requires argument: text or json');
36
+ }
37
+ else {
38
+ throw new Error(`Invalid format: ${formatValue}. Expected text or json`);
39
+ }
40
+ }
41
+ // Check for unknown flags
42
+ const knownFlags = new Set([
43
+ '--help',
44
+ '-h',
45
+ '--version',
46
+ '-v',
47
+ '--fix',
48
+ '--verbose',
49
+ '--format',
50
+ ]);
51
+ for (let i = 0; i < argv.length; i++) {
52
+ const arg = argv[i];
53
+ if (!arg)
54
+ continue;
55
+ // Skip non-flag arguments
56
+ if (!arg.startsWith('-')) {
57
+ continue;
58
+ }
59
+ // Skip format value argument
60
+ if (i > 0 && argv[i - 1] === '--format') {
61
+ continue;
62
+ }
63
+ // Check if unknown flag
64
+ if (!knownFlags.has(arg)) {
65
+ throw new Error(`Unknown option: ${arg}`);
66
+ }
67
+ }
68
+ // Extract file path (first non-flag argument)
69
+ let file;
70
+ for (let i = 0; i < argv.length; i++) {
71
+ const arg = argv[i];
72
+ if (!arg)
73
+ continue;
74
+ // Skip flags
75
+ if (arg.startsWith('-')) {
76
+ // Skip --format and its value
77
+ if (arg === '--format') {
78
+ i++; // Skip next argument (the format value)
79
+ }
80
+ continue;
81
+ }
82
+ // First non-flag argument is the file
83
+ file = arg;
84
+ break;
85
+ }
86
+ if (!file) {
87
+ throw new Error('Missing file argument');
88
+ }
89
+ return { mode: 'check', file, fix, verbose, format };
90
+ }
91
+ // ============================================================
92
+ // DIAGNOSTIC FORMATTING
93
+ // ============================================================
94
+ /**
95
+ * Format diagnostics for output
96
+ *
97
+ * Adapts pattern from cli-shared.ts formatError function.
98
+ * Text format: file:line:col: severity: message (code)
99
+ * JSON format: complete schema with errors array and summary
100
+ * Verbose mode: adds category field to diagnostics
101
+ *
102
+ * @param file - File path being checked
103
+ * @param diagnostics - Array of diagnostics to format
104
+ * @param format - Output format ('text' or 'json')
105
+ * @param verbose - Whether to include category and doc references
106
+ * @returns Formatted output string
107
+ */
108
+ export function formatDiagnostics(file, diagnostics, format, verbose) {
109
+ if (format === 'json') {
110
+ return formatDiagnosticsJSON(file, diagnostics, verbose);
111
+ }
112
+ return formatDiagnosticsText(file, diagnostics);
113
+ }
114
+ /**
115
+ * Format diagnostics as text
116
+ * Pattern: file:line:col: severity: message (code)
117
+ */
118
+ function formatDiagnosticsText(file, diagnostics) {
119
+ return diagnostics
120
+ .map((d) => {
121
+ const { line, column } = d.location;
122
+ return `${file}:${line}:${column}: ${d.severity}: ${d.message} (${d.code})`;
123
+ })
124
+ .join('\n');
125
+ }
126
+ /**
127
+ * Format diagnostics as JSON
128
+ * Includes file, errors array, and summary
129
+ */
130
+ function formatDiagnosticsJSON(file, diagnostics, verbose) {
131
+ // Build category lookup map from validation rules
132
+ const categoryMap = new Map();
133
+ for (const rule of VALIDATION_RULES) {
134
+ categoryMap.set(rule.code, rule.category);
135
+ }
136
+ // Format each diagnostic
137
+ const errors = diagnostics.map((d) => {
138
+ const error = {
139
+ location: {
140
+ line: d.location.line,
141
+ column: d.location.column,
142
+ offset: d.location.offset,
143
+ },
144
+ severity: d.severity,
145
+ code: d.code,
146
+ message: d.message,
147
+ context: d.context,
148
+ };
149
+ // Add category if verbose mode
150
+ if (verbose) {
151
+ const category = categoryMap.get(d.code);
152
+ if (category) {
153
+ error['category'] = category;
154
+ }
155
+ }
156
+ // Add fix if present
157
+ if (d.fix) {
158
+ error['fix'] = {
159
+ description: d.fix.description,
160
+ applicable: d.fix.applicable,
161
+ range: {
162
+ start: {
163
+ line: d.fix.range.start.line,
164
+ column: d.fix.range.start.column,
165
+ offset: d.fix.range.start.offset,
166
+ },
167
+ end: {
168
+ line: d.fix.range.end.line,
169
+ column: d.fix.range.end.column,
170
+ offset: d.fix.range.end.offset,
171
+ },
172
+ },
173
+ replacement: d.fix.replacement,
174
+ };
175
+ }
176
+ return error;
177
+ });
178
+ // Count diagnostics by severity
179
+ const summary = {
180
+ total: diagnostics.length,
181
+ errors: diagnostics.filter((d) => d.severity === 'error').length,
182
+ warnings: diagnostics.filter((d) => d.severity === 'warning').length,
183
+ info: diagnostics.filter((d) => d.severity === 'info').length,
184
+ };
185
+ const output = {
186
+ file,
187
+ errors,
188
+ summary,
189
+ };
190
+ return JSON.stringify(output, null, 2);
191
+ }
192
+ // ============================================================
193
+ // MAIN ENTRY POINT
194
+ // ============================================================
195
+ /**
196
+ * Main entry point for rill-check CLI.
197
+ * Orchestrates argument parsing, file reading, validation, fixing, and output.
198
+ */
199
+ async function main() {
200
+ try {
201
+ // Parse command-line arguments
202
+ const args = parseCheckArgs(process.argv.slice(2));
203
+ // Handle help mode
204
+ if (args.mode === 'help') {
205
+ console.log(`rill-check - Validate Rill scripts
206
+
207
+ Usage: rill-check [options] <file>
208
+
209
+ Options:
210
+ --fix Apply automatic fixes
211
+ --format <fmt> Output format: text (default) or json
212
+ --verbose Include category and documentation references
213
+ -h, --help Show this help message
214
+ -v, --version Show version number`);
215
+ process.exit(0);
216
+ }
217
+ // Handle version mode
218
+ if (args.mode === 'version') {
219
+ console.log(VERSION);
220
+ process.exit(0);
221
+ }
222
+ // At this point, args.mode must be 'check'
223
+ // TypeScript needs explicit assertion after early returns
224
+ if (args.mode !== 'check') {
225
+ throw new Error('Unexpected mode');
226
+ }
227
+ // Load configuration from cwd (null if not present)
228
+ const config = loadConfig(process.cwd()) ?? createDefaultConfig();
229
+ // Read source file
230
+ let source;
231
+ try {
232
+ const fs = await import('node:fs');
233
+ // Check if file exists
234
+ if (!fs.existsSync(args.file)) {
235
+ console.error(`Error [RILL-C001]: File not found: ${args.file}`);
236
+ process.exit(2);
237
+ }
238
+ // Check if path is a directory
239
+ const stats = fs.statSync(args.file);
240
+ if (stats.isDirectory()) {
241
+ console.error(`Error [RILL-C002]: Path is a directory: ${args.file}`);
242
+ process.exit(2);
243
+ }
244
+ // Read file contents
245
+ source = fs.readFileSync(args.file, 'utf-8');
246
+ }
247
+ catch (err) {
248
+ // Handle read errors (permissions, etc.)
249
+ if (err instanceof Error &&
250
+ 'code' in err &&
251
+ typeof err.code === 'string') {
252
+ const code = err.code;
253
+ if (code === 'ENOENT') {
254
+ console.error(`Error [RILL-C001]: File not found: ${args.file}`);
255
+ }
256
+ else if (code === 'EISDIR') {
257
+ console.error(`Error [RILL-C002]: Path is a directory: ${args.file}`);
258
+ }
259
+ else {
260
+ console.error(`Error [RILL-C002]: Cannot read file: ${args.file}`);
261
+ }
262
+ }
263
+ else {
264
+ console.error(`Error [RILL-C002]: Cannot read file: ${args.file}`);
265
+ }
266
+ process.exit(2);
267
+ }
268
+ // Parse AST with recovery to collect all errors
269
+ const parseResult = parseWithRecovery(source);
270
+ // Convert parse errors to diagnostics
271
+ // Only report the first parse error; subsequent errors are usually cascade noise
272
+ const parseDiagnostics = parseResult.errors
273
+ .slice(0, 1)
274
+ .map((err) => {
275
+ const location = err.location ?? { line: 1, column: 1, offset: 0 };
276
+ const lineContent = source.split('\n')[location.line - 1]?.trim() ?? '';
277
+ return {
278
+ code: 'parse-error',
279
+ severity: 'error',
280
+ message: err.message.replace(/ at \d+:\d+$/, ''),
281
+ location,
282
+ context: lineContent,
283
+ fix: null,
284
+ };
285
+ });
286
+ // If there are parse errors, report them and exit
287
+ if (parseDiagnostics.length > 0) {
288
+ const output = formatDiagnostics(args.file, parseDiagnostics, args.format, args.verbose);
289
+ console.log(output);
290
+ // If --fix was requested, report that fixes cannot be applied
291
+ if (args.fix) {
292
+ console.error('Cannot apply fixes: file has parse errors');
293
+ }
294
+ process.exit(3);
295
+ }
296
+ const ast = parseResult.ast;
297
+ // Run validation
298
+ const diagnostics = validateScript(ast, source, config);
299
+ // Apply fixes if requested
300
+ if (args.fix && diagnostics.length > 0) {
301
+ const result = applyFixes(source, diagnostics, {
302
+ source,
303
+ ast,
304
+ config,
305
+ diagnostics: [],
306
+ variables: new Map(),
307
+ assertedHostCalls: new Set(),
308
+ variableScopes: new Map(),
309
+ scopeStack: [],
310
+ });
311
+ // Write fixed source back to file
312
+ if (result.applied > 0) {
313
+ const fs = await import('node:fs');
314
+ fs.writeFileSync(args.file, result.modified, 'utf-8');
315
+ }
316
+ // Report fix results to stderr
317
+ if (result.applied > 0 || result.skipped > 0) {
318
+ if (result.applied > 0) {
319
+ console.error(`Applied ${result.applied} fix${result.applied === 1 ? '' : 'es'}`);
320
+ }
321
+ if (result.skipped > 0) {
322
+ console.error(`Skipped ${result.skipped} fix${result.skipped === 1 ? '' : 'es'}`);
323
+ }
324
+ }
325
+ }
326
+ // Format and output diagnostics
327
+ if (diagnostics.length === 0) {
328
+ // No errors - success
329
+ if (args.format === 'json') {
330
+ console.log(JSON.stringify({
331
+ file: args.file,
332
+ errors: [],
333
+ summary: { total: 0, errors: 0, warnings: 0, info: 0 },
334
+ }, null, 2));
335
+ }
336
+ else {
337
+ console.log('No issues found');
338
+ }
339
+ process.exit(0);
340
+ }
341
+ else {
342
+ // Output diagnostics
343
+ const output = formatDiagnostics(args.file, diagnostics, args.format, args.verbose);
344
+ console.log(output);
345
+ process.exit(1);
346
+ }
347
+ }
348
+ catch (err) {
349
+ // Handle unexpected errors
350
+ if (err instanceof Error) {
351
+ console.error(`Error: ${err.message}`);
352
+ }
353
+ else {
354
+ console.error(`Error: ${String(err)}`);
355
+ }
356
+ process.exit(1);
357
+ }
358
+ }
359
+ // Only run main if this is the entry point (not imported)
360
+ const shouldRunMain = process.env['NODE_ENV'] !== 'test' &&
361
+ !process.env['VITEST'] &&
362
+ !process.env['VITEST_WORKER_ID'];
363
+ if (shouldRunMain) {
364
+ main();
365
+ }
366
+ //# sourceMappingURL=cli-check.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli-check.js","sourceRoot":"","sources":["../src/cli-check.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,73 @@
1
+ /**
2
+ * CLI Error Enrichment
3
+ * Functions for extracting source snippets and suggesting similar names
4
+ */
5
+ import type { SourceSpan, RillError, CallFrame } from '@rcrsr/rill';
6
+ export interface SourceSnippet {
7
+ readonly lines: SnippetLine[];
8
+ readonly highlightSpan: SourceSpan;
9
+ }
10
+ export interface SnippetLine {
11
+ readonly lineNumber: number;
12
+ readonly content: string;
13
+ readonly isErrorLine: boolean;
14
+ }
15
+ export interface ScopeInfo {
16
+ readonly variableNames: string[];
17
+ readonly functionNames: string[];
18
+ }
19
+ export interface EnrichedError {
20
+ readonly errorId: string;
21
+ readonly message: string;
22
+ readonly span?: SourceSpan | undefined;
23
+ readonly context?: Record<string, unknown> | undefined;
24
+ readonly callStack?: CallFrame[] | undefined;
25
+ readonly sourceSnippet?: SourceSnippet | undefined;
26
+ readonly suggestions?: string[] | undefined;
27
+ readonly helpUrl?: string | undefined;
28
+ }
29
+ /**
30
+ * Extract source lines around error location.
31
+ *
32
+ * Constraints:
33
+ * - Context lines: 2 before, 2 after (configurable)
34
+ * - Line numbers: 1-based
35
+ * - Handles edge cases: line 1, last line
36
+ *
37
+ * @param source - Full source text
38
+ * @param span - Error location span
39
+ * @param contextLines - Number of context lines before/after (default: 2)
40
+ * @returns Snippet with context lines
41
+ * @throws {RangeError} When span exceeds source bounds
42
+ */
43
+ export declare function extractSnippet(source: string, span: SourceSpan, contextLines?: number): SourceSnippet;
44
+ /**
45
+ * Find similar names using fuzzy matching.
46
+ *
47
+ * Constraints:
48
+ * - Edit distance threshold: <= 2
49
+ * - Max suggestions: 3
50
+ * - Sort: ascending by distance, then alphabetically
51
+ *
52
+ * @param target - Name to match against
53
+ * @param candidates - Available names
54
+ * @returns Up to 3 similar names, sorted by distance then alphabetically
55
+ */
56
+ export declare function suggestSimilarNames(target: string, candidates: string[]): string[];
57
+ /**
58
+ * Enrich RillError with source snippets and suggestions.
59
+ *
60
+ * Constraints:
61
+ * - Source must be valid UTF-8
62
+ * - Snippet extraction: 2 lines before, error line, 2 after
63
+ * - Fuzzy matching: edit distance <= 2
64
+ * - Max 3 suggestions
65
+ *
66
+ * @param error - RillError to enrich
67
+ * @param source - Full source text
68
+ * @param scope - Optional scope information for suggestions
69
+ * @returns Enriched error with snippet and suggestions
70
+ * @throws {TypeError} When source is not a string or error is null
71
+ */
72
+ export declare function enrichError(error: RillError, source: string, scope?: ScopeInfo): EnrichedError;
73
+ //# sourceMappingURL=cli-error-enrichment.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli-error-enrichment.d.ts","sourceRoot":"","sources":["../src/cli-error-enrichment.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAMpE,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,KAAK,EAAE,WAAW,EAAE,CAAC;IAC9B,QAAQ,CAAC,aAAa,EAAE,UAAU,CAAC;CACpC;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC;CAC/B;AAED,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,aAAa,EAAE,MAAM,EAAE,CAAC;IACjC,QAAQ,CAAC,aAAa,EAAE,MAAM,EAAE,CAAC;CAClC;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,CAAC,EAAE,UAAU,GAAG,SAAS,CAAC;IACvC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC;IACvD,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,EAAE,GAAG,SAAS,CAAC;IAC7C,QAAQ,CAAC,aAAa,CAAC,EAAE,aAAa,GAAG,SAAS,CAAC;IACnD,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IAC5C,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACvC;AAMD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,UAAU,EAChB,YAAY,GAAE,MAAU,GACvB,aAAa,CAsCf;AAMD;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,EAAE,GACnB,MAAM,EAAE,CA6BV;AAkDD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,WAAW,CACzB,KAAK,EAAE,SAAS,EAChB,MAAM,EAAE,MAAM,EACd,KAAK,CAAC,EAAE,SAAS,GAChB,aAAa,CAwDf"}
@@ -0,0 +1,205 @@
1
+ /**
2
+ * CLI Error Enrichment
3
+ * Functions for extracting source snippets and suggesting similar names
4
+ */
5
+ // ============================================================
6
+ // SOURCE SNIPPET EXTRACTION
7
+ // ============================================================
8
+ /**
9
+ * Extract source lines around error location.
10
+ *
11
+ * Constraints:
12
+ * - Context lines: 2 before, 2 after (configurable)
13
+ * - Line numbers: 1-based
14
+ * - Handles edge cases: line 1, last line
15
+ *
16
+ * @param source - Full source text
17
+ * @param span - Error location span
18
+ * @param contextLines - Number of context lines before/after (default: 2)
19
+ * @returns Snippet with context lines
20
+ * @throws {RangeError} When span exceeds source bounds
21
+ */
22
+ export function extractSnippet(source, span, contextLines = 2) {
23
+ // EC-7: Empty source returns empty snippet
24
+ if (source === '') {
25
+ return { lines: [], highlightSpan: span };
26
+ }
27
+ const lines = source.split('\n');
28
+ const totalLines = lines.length;
29
+ // EC-6: Validate span is within bounds (1-based line numbers)
30
+ if (span.start.line < 1 || span.start.line > totalLines) {
31
+ throw new RangeError('Span exceeds source bounds');
32
+ }
33
+ if (span.end.line < 1 || span.end.line > totalLines) {
34
+ throw new RangeError('Span exceeds source bounds');
35
+ }
36
+ // Calculate context range
37
+ const errorStartLine = span.start.line;
38
+ const errorEndLine = span.end.line;
39
+ const firstLine = Math.max(1, errorStartLine - contextLines);
40
+ const lastLine = Math.min(totalLines, errorEndLine + contextLines);
41
+ // Build snippet lines
42
+ const snippetLines = [];
43
+ for (let lineNum = firstLine; lineNum <= lastLine; lineNum++) {
44
+ const isErrorLine = lineNum >= errorStartLine && lineNum <= errorEndLine;
45
+ snippetLines.push({
46
+ lineNumber: lineNum,
47
+ content: lines[lineNum - 1] ?? '', // Convert 1-based to 0-based index
48
+ isErrorLine,
49
+ });
50
+ }
51
+ return {
52
+ lines: snippetLines,
53
+ highlightSpan: span,
54
+ };
55
+ }
56
+ // ============================================================
57
+ // NAME SUGGESTION
58
+ // ============================================================
59
+ /**
60
+ * Find similar names using fuzzy matching.
61
+ *
62
+ * Constraints:
63
+ * - Edit distance threshold: <= 2
64
+ * - Max suggestions: 3
65
+ * - Sort: ascending by distance, then alphabetically
66
+ *
67
+ * @param target - Name to match against
68
+ * @param candidates - Available names
69
+ * @returns Up to 3 similar names, sorted by distance then alphabetically
70
+ */
71
+ export function suggestSimilarNames(target, candidates) {
72
+ // EC-9: Empty target returns []
73
+ if (target === '') {
74
+ return [];
75
+ }
76
+ // EC-10: Empty candidates returns []
77
+ if (candidates.length === 0) {
78
+ return [];
79
+ }
80
+ // Calculate edit distance for each candidate
81
+ const candidatesWithDistance = candidates
82
+ .map((candidate) => ({
83
+ name: candidate,
84
+ distance: levenshteinDistance(target, candidate),
85
+ }))
86
+ .filter((item) => item.distance <= 2); // IR-8: Edit distance threshold
87
+ // Sort: ascending by distance, then alphabetically
88
+ candidatesWithDistance.sort((a, b) => {
89
+ if (a.distance !== b.distance) {
90
+ return a.distance - b.distance;
91
+ }
92
+ return a.name.localeCompare(b.name);
93
+ });
94
+ // IR-8: Max 3 suggestions
95
+ return candidatesWithDistance.slice(0, 3).map((item) => item.name);
96
+ }
97
+ /**
98
+ * Calculate Levenshtein distance between two strings.
99
+ * Uses dynamic programming with O(m*n) time and O(min(m,n)) space.
100
+ *
101
+ * @param a - First string
102
+ * @param b - Second string
103
+ * @returns Edit distance (number of operations to transform a into b)
104
+ */
105
+ function levenshteinDistance(a, b) {
106
+ // Ensure a is the shorter string for space optimization
107
+ if (a.length > b.length) {
108
+ [a, b] = [b, a];
109
+ }
110
+ const m = a.length;
111
+ const n = b.length;
112
+ // Early exit for empty strings
113
+ if (m === 0)
114
+ return n;
115
+ if (n === 0)
116
+ return m;
117
+ // Use rolling array optimization (only need previous row)
118
+ let prevRow = Array.from({ length: m + 1 }, (_, i) => i);
119
+ let currRow = new Array(m + 1);
120
+ for (let j = 1; j <= n; j++) {
121
+ currRow[0] = j;
122
+ for (let i = 1; i <= m; i++) {
123
+ const cost = a[i - 1] === b[j - 1] ? 0 : 1;
124
+ currRow[i] = Math.min(prevRow[i] + 1, // deletion
125
+ currRow[i - 1] + 1, // insertion
126
+ prevRow[i - 1] + cost // substitution
127
+ );
128
+ }
129
+ // Swap rows for next iteration
130
+ [prevRow, currRow] = [currRow, prevRow];
131
+ }
132
+ return prevRow[m] ?? 0;
133
+ }
134
+ // ============================================================
135
+ // ERROR ENRICHMENT
136
+ // ============================================================
137
+ /**
138
+ * Enrich RillError with source snippets and suggestions.
139
+ *
140
+ * Constraints:
141
+ * - Source must be valid UTF-8
142
+ * - Snippet extraction: 2 lines before, error line, 2 after
143
+ * - Fuzzy matching: edit distance <= 2
144
+ * - Max 3 suggestions
145
+ *
146
+ * @param error - RillError to enrich
147
+ * @param source - Full source text
148
+ * @param scope - Optional scope information for suggestions
149
+ * @returns Enriched error with snippet and suggestions
150
+ * @throws {TypeError} When source is not a string or error is null
151
+ */
152
+ export function enrichError(error, source, scope) {
153
+ // EC-4: Null error
154
+ if (!error) {
155
+ throw new TypeError('Error is required');
156
+ }
157
+ // EC-3: Invalid source encoding (JavaScript strings are always valid UTF-16)
158
+ if (typeof source !== 'string') {
159
+ throw new TypeError('Source must be valid UTF-8');
160
+ }
161
+ // Extract span from error location
162
+ let span;
163
+ if (error.location) {
164
+ // Create a minimal span from the location (single character)
165
+ span = {
166
+ start: error.location,
167
+ end: error.location,
168
+ };
169
+ }
170
+ // Extract source snippet if we have a span
171
+ let sourceSnippet;
172
+ if (span && source !== '') {
173
+ try {
174
+ sourceSnippet = extractSnippet(source, span);
175
+ }
176
+ catch {
177
+ // If snippet extraction fails (e.g., invalid span), skip it
178
+ sourceSnippet = undefined;
179
+ }
180
+ }
181
+ // Generate suggestions if scope info is provided
182
+ let suggestions;
183
+ if (scope && error.context) {
184
+ // Look for undefined variable names in context
185
+ const undefinedName = error.context['name'];
186
+ if (undefinedName && typeof undefinedName === 'string') {
187
+ const candidates = [...scope.variableNames, ...scope.functionNames];
188
+ const similarNames = suggestSimilarNames(undefinedName, candidates);
189
+ if (similarNames.length > 0) {
190
+ suggestions = similarNames;
191
+ }
192
+ }
193
+ }
194
+ return {
195
+ errorId: error.errorId,
196
+ message: error.message.replace(/ at \d+:\d+$/, ''), // Strip location suffix
197
+ span,
198
+ context: error.context,
199
+ callStack: undefined, // Call stack not part of base RillError
200
+ sourceSnippet,
201
+ suggestions,
202
+ helpUrl: error.helpUrl,
203
+ };
204
+ }
205
+ //# sourceMappingURL=cli-error-enrichment.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli-error-enrichment.js","sourceRoot":"","sources":["../src/cli-error-enrichment.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAmCH,+DAA+D;AAC/D,4BAA4B;AAC5B,+DAA+D;AAE/D;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,cAAc,CAC5B,MAAc,EACd,IAAgB,EAChB,eAAuB,CAAC;IAExB,2CAA2C;IAC3C,IAAI,MAAM,KAAK,EAAE,EAAE,CAAC;QAClB,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC;IAC5C,CAAC;IAED,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACjC,MAAM,UAAU,GAAG,KAAK,CAAC,MAAM,CAAC;IAEhC,8DAA8D;IAC9D,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,UAAU,EAAE,CAAC;QACxD,MAAM,IAAI,UAAU,CAAC,4BAA4B,CAAC,CAAC;IACrD,CAAC;IACD,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,GAAG,UAAU,EAAE,CAAC;QACpD,MAAM,IAAI,UAAU,CAAC,4BAA4B,CAAC,CAAC;IACrD,CAAC;IAED,0BAA0B;IAC1B,MAAM,cAAc,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;IACvC,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;IACnC,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,cAAc,GAAG,YAAY,CAAC,CAAC;IAC7D,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,YAAY,GAAG,YAAY,CAAC,CAAC;IAEnE,sBAAsB;IACtB,MAAM,YAAY,GAAkB,EAAE,CAAC;IACvC,KAAK,IAAI,OAAO,GAAG,SAAS,EAAE,OAAO,IAAI,QAAQ,EAAE,OAAO,EAAE,EAAE,CAAC;QAC7D,MAAM,WAAW,GAAG,OAAO,IAAI,cAAc,IAAI,OAAO,IAAI,YAAY,CAAC;QACzE,YAAY,CAAC,IAAI,CAAC;YAChB,UAAU,EAAE,OAAO;YACnB,OAAO,EAAE,KAAK,CAAC,OAAO,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,mCAAmC;YACtE,WAAW;SACZ,CAAC,CAAC;IACL,CAAC;IAED,OAAO;QACL,KAAK,EAAE,YAAY;QACnB,aAAa,EAAE,IAAI;KACpB,CAAC;AACJ,CAAC;AAED,+DAA+D;AAC/D,kBAAkB;AAClB,+DAA+D;AAE/D;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,mBAAmB,CACjC,MAAc,EACd,UAAoB;IAEpB,gCAAgC;IAChC,IAAI,MAAM,KAAK,EAAE,EAAE,CAAC;QAClB,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,qCAAqC;IACrC,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC5B,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,6CAA6C;IAC7C,MAAM,sBAAsB,GAAG,UAAU;SACtC,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;QACnB,IAAI,EAAE,SAAS;QACf,QAAQ,EAAE,mBAAmB,CAAC,MAAM,EAAE,SAAS,CAAC;KACjD,CAAC,CAAC;SACF,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,IAAI,CAAC,CAAC,CAAC,CAAC,gCAAgC;IAEzE,mDAAmD;IACnD,sBAAsB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QACnC,IAAI,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,QAAQ,EAAE,CAAC;YAC9B,OAAO,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,QAAQ,CAAC;QACjC,CAAC;QACD,OAAO,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IACtC,CAAC,CAAC,CAAC;IAEH,0BAA0B;IAC1B,OAAO,sBAAsB,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACrE,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,mBAAmB,CAAC,CAAS,EAAE,CAAS;IAC/C,wDAAwD;IACxD,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC;QACxB,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC;IACnB,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC;IAEnB,+BAA+B;IAC/B,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,CAAC,CAAC;IACtB,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,CAAC,CAAC;IAEtB,0DAA0D;IAC1D,IAAI,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC;IACzD,IAAI,OAAO,GAAG,IAAI,KAAK,CAAS,CAAC,GAAG,CAAC,CAAC,CAAC;IAEvC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC5B,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QAEf,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YAC5B,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YAC3C,OAAO,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CACnB,OAAO,CAAC,CAAC,CAAE,GAAG,CAAC,EAAE,WAAW;YAC5B,OAAO,CAAC,CAAC,GAAG,CAAC,CAAE,GAAG,CAAC,EAAE,YAAY;YACjC,OAAO,CAAC,CAAC,GAAG,CAAC,CAAE,GAAG,IAAI,CAAC,eAAe;aACvC,CAAC;QACJ,CAAC;QAED,+BAA+B;QAC/B,CAAC,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAC1C,CAAC;IAED,OAAO,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;AACzB,CAAC;AAED,+DAA+D;AAC/D,mBAAmB;AACnB,+DAA+D;AAE/D;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,WAAW,CACzB,KAAgB,EAChB,MAAc,EACd,KAAiB;IAEjB,mBAAmB;IACnB,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,SAAS,CAAC,mBAAmB,CAAC,CAAC;IAC3C,CAAC;IAED,6EAA6E;IAC7E,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;QAC/B,MAAM,IAAI,SAAS,CAAC,4BAA4B,CAAC,CAAC;IACpD,CAAC;IAED,mCAAmC;IACnC,IAAI,IAA4B,CAAC;IACjC,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;QACnB,6DAA6D;QAC7D,IAAI,GAAG;YACL,KAAK,EAAE,KAAK,CAAC,QAAQ;YACrB,GAAG,EAAE,KAAK,CAAC,QAAQ;SACpB,CAAC;IACJ,CAAC;IAED,2CAA2C;IAC3C,IAAI,aAAwC,CAAC;IAC7C,IAAI,IAAI,IAAI,MAAM,KAAK,EAAE,EAAE,CAAC;QAC1B,IAAI,CAAC;YACH,aAAa,GAAG,cAAc,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QAC/C,CAAC;QAAC,MAAM,CAAC;YACP,4DAA4D;YAC5D,aAAa,GAAG,SAAS,CAAC;QAC5B,CAAC;IACH,CAAC;IAED,iDAAiD;IACjD,IAAI,WAAiC,CAAC;IACtC,IAAI,KAAK,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;QAC3B,+CAA+C;QAC/C,MAAM,aAAa,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAuB,CAAC;QAClE,IAAI,aAAa,IAAI,OAAO,aAAa,KAAK,QAAQ,EAAE,CAAC;YACvD,MAAM,UAAU,GAAG,CAAC,GAAG,KAAK,CAAC,aAAa,EAAE,GAAG,KAAK,CAAC,aAAa,CAAC,CAAC;YACpE,MAAM,YAAY,GAAG,mBAAmB,CAAC,aAAa,EAAE,UAAU,CAAC,CAAC;YACpE,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC5B,WAAW,GAAG,YAAY,CAAC;YAC7B,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO;QACL,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC,EAAE,wBAAwB;QAC5E,IAAI;QACJ,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,SAAS,EAAE,SAAS,EAAE,wCAAwC;QAC9D,aAAa;QACb,WAAW;QACX,OAAO,EAAE,KAAK,CAAC,OAAO;KACvB,CAAC;AACJ,CAAC"}