norn-cli 1.6.0 → 1.6.2

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/AGENTS.md +9 -1
  2. package/CHANGELOG.md +23 -0
  3. package/dist/cli.js +246 -80
  4. package/package.json +1 -1
  5. package/out/assertionRunner.js +0 -537
  6. package/out/chatParticipant.js +0 -722
  7. package/out/cli/colors.js +0 -129
  8. package/out/cli/formatters/assertion.js +0 -75
  9. package/out/cli/formatters/index.js +0 -23
  10. package/out/cli/formatters/response.js +0 -106
  11. package/out/cli/formatters/summary.js +0 -187
  12. package/out/cli/redaction.js +0 -237
  13. package/out/cli/reporters/html.js +0 -634
  14. package/out/cli/reporters/index.js +0 -22
  15. package/out/cli/reporters/junit.js +0 -211
  16. package/out/cli.js +0 -989
  17. package/out/codeLensProvider.js +0 -248
  18. package/out/compareContentProvider.js +0 -85
  19. package/out/completionProvider.js +0 -2404
  20. package/out/contractDecorationProvider.js +0 -243
  21. package/out/coverageCalculator.js +0 -837
  22. package/out/coveragePanel.js +0 -545
  23. package/out/diagnosticProvider.js +0 -1113
  24. package/out/environmentProvider.js +0 -442
  25. package/out/extension.js +0 -1114
  26. package/out/httpClient.js +0 -269
  27. package/out/jsonFileReader.js +0 -320
  28. package/out/nornPrompt.js +0 -580
  29. package/out/nornapiParser.js +0 -326
  30. package/out/parser.js +0 -725
  31. package/out/responsePanel.js +0 -4674
  32. package/out/schemaGenerator.js +0 -393
  33. package/out/scriptRunner.js +0 -419
  34. package/out/sequenceRunner.js +0 -3046
  35. package/out/swaggerBodyIntellisenseCache.js +0 -147
  36. package/out/swaggerParser.js +0 -419
  37. package/out/test/coverageCalculator.test.js +0 -100
  38. package/out/test/extension.test.js +0 -48
  39. package/out/testProvider.js +0 -658
  40. package/out/validationCache.js +0 -245
@@ -1,419 +0,0 @@
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.parseRunCommand = parseRunCommand;
37
- exports.isRunCommand = isRunCommand;
38
- exports.runScript = runScript;
39
- const child_process_1 = require("child_process");
40
- const path = __importStar(require("path"));
41
- // Cache for pwsh availability check
42
- let pwshAvailable = null;
43
- /**
44
- * Strips ANSI escape codes from a string.
45
- * PowerShell and other terminals use these for coloring/formatting,
46
- * but they appear as garbage when captured programmatically.
47
- */
48
- function stripAnsiCodes(str) {
49
- // Match all ANSI escape sequences:
50
- // - CSI sequences: ESC [ ... letter (most common, for colors/cursor)
51
- // - OSC sequences: ESC ] ... BEL or ESC \ (for window titles, etc.)
52
- // - Simple escape sequences: ESC letter
53
- return str.replace(/\x1B(?:\[[0-9;]*[a-zA-Z]|\][^\x07]*(?:\x07|\x1B\\)|[a-zA-Z])/g, '');
54
- }
55
- /**
56
- * Attempts to parse PowerShell table format into JSON.
57
- *
58
- * Handles formats like:
59
- *
60
- * Single column:
61
- * Id
62
- * --
63
- * 123
64
- *
65
- * Multiple columns:
66
- * Id Name Email
67
- * -- ---- -----
68
- * 123 John john@example.com
69
- *
70
- * List format (single object):
71
- * Id : 123
72
- * Name : John
73
- * Email : john@example.com
74
- *
75
- * @returns JSON string if parsing succeeds, null otherwise
76
- */
77
- function tryParsePowerShellOutput(output) {
78
- const lines = output.split('\n').map(l => l.trimEnd());
79
- // Filter out empty lines at start/end but keep track of non-empty ones
80
- const nonEmptyLines = lines.filter(l => l.trim() !== '');
81
- if (nonEmptyLines.length === 0) {
82
- return null;
83
- }
84
- // Check for PowerShell list format: "Key : Value" (used for single objects)
85
- // Look for multiple lines with " : " pattern
86
- const listFormatRegex = /^(\S+)\s*:\s*(.*)$/;
87
- const listMatches = nonEmptyLines.filter(l => listFormatRegex.test(l.trim()));
88
- if (listMatches.length >= 2 && listMatches.length === nonEmptyLines.length) {
89
- // All lines match list format - parse as object
90
- const obj = {};
91
- for (const line of nonEmptyLines) {
92
- const match = line.trim().match(listFormatRegex);
93
- if (match) {
94
- const key = match[1].trim();
95
- const value = parseValue(match[2].trim());
96
- obj[key] = value;
97
- }
98
- }
99
- return JSON.stringify(obj);
100
- }
101
- // Check for PowerShell table format
102
- // First non-empty line should be headers, second should be dashes
103
- if (nonEmptyLines.length >= 2) {
104
- const headerLine = nonEmptyLines[0];
105
- const dashLine = nonEmptyLines[1];
106
- // Check if second line is all dashes and spaces (separator line)
107
- if (/^[\s-]+$/.test(dashLine) && dashLine.includes('-')) {
108
- // Parse column positions from the dash line
109
- const columns = parseTableColumns(headerLine, dashLine);
110
- if (columns.length > 0) {
111
- const dataLines = nonEmptyLines.slice(2);
112
- if (dataLines.length === 0) {
113
- // Headers but no data
114
- return JSON.stringify([]);
115
- }
116
- if (dataLines.length === 1 && columns.length === 1) {
117
- // Single value - return just the value (common case)
118
- const value = parseValue(dataLines[0].trim());
119
- // If it's a simple value and there's only one column, return as object
120
- return JSON.stringify({ [columns[0].name]: value });
121
- }
122
- // Parse all data rows
123
- const results = [];
124
- for (const dataLine of dataLines) {
125
- const row = {};
126
- for (const col of columns) {
127
- const rawValue = dataLine.substring(col.start, col.end).trim();
128
- row[col.name] = parseValue(rawValue);
129
- }
130
- results.push(row);
131
- }
132
- // Return single object if only one row, array otherwise
133
- if (results.length === 1) {
134
- return JSON.stringify(results[0]);
135
- }
136
- return JSON.stringify(results);
137
- }
138
- }
139
- }
140
- // Single line of output - return as-is (will be stored as plain string)
141
- if (nonEmptyLines.length === 1) {
142
- return null; // Let it be stored as plain string
143
- }
144
- return null;
145
- }
146
- /**
147
- * Parses column definitions from header and dash lines.
148
- */
149
- function parseTableColumns(headerLine, dashLine) {
150
- const columns = [];
151
- // Find all dash segments first
152
- const dashRegex = /-+/g;
153
- const dashSegments = [];
154
- let match;
155
- while ((match = dashRegex.exec(dashLine)) !== null) {
156
- dashSegments.push({
157
- start: match.index,
158
- end: match.index + match[0].length
159
- });
160
- }
161
- // Now build columns from the segments
162
- for (let i = 0; i < dashSegments.length; i++) {
163
- const seg = dashSegments[i];
164
- const nextSeg = dashSegments[i + 1];
165
- // Column ends at start of next segment, or end of line
166
- const colEnd = nextSeg ? nextSeg.start : Math.max(headerLine.length, dashLine.length);
167
- // Extract header name from this column
168
- const headerName = headerLine.substring(seg.start, seg.end).trim();
169
- if (headerName) {
170
- columns.push({ name: headerName, start: seg.start, end: colEnd });
171
- }
172
- }
173
- return columns;
174
- }
175
- /**
176
- * Attempts to parse a string value into its appropriate type.
177
- */
178
- function parseValue(str) {
179
- if (str === '' || str.toLowerCase() === 'null') {
180
- return null;
181
- }
182
- if (str.toLowerCase() === 'true') {
183
- return true;
184
- }
185
- if (str.toLowerCase() === 'false') {
186
- return false;
187
- }
188
- // Try to parse as number
189
- if (/^-?\d+$/.test(str)) {
190
- return parseInt(str, 10);
191
- }
192
- if (/^-?\d+\.\d+$/.test(str)) {
193
- return parseFloat(str);
194
- }
195
- return str;
196
- }
197
- /**
198
- * Cleans script output by stripping ANSI codes and trimming whitespace.
199
- * Attempts to parse various output formats into JSON for property access.
200
- */
201
- function cleanScriptOutput(output) {
202
- // Strip ANSI escape codes
203
- let cleaned = stripAnsiCodes(output).trim();
204
- // If it looks like JSON (object or array), try to parse and re-stringify
205
- // This normalizes the JSON and validates it
206
- if ((cleaned.startsWith('{') && cleaned.endsWith('}')) ||
207
- (cleaned.startsWith('[') && cleaned.endsWith(']'))) {
208
- try {
209
- const parsed = JSON.parse(cleaned);
210
- // Re-stringify to ensure consistent formatting
211
- return JSON.stringify(parsed);
212
- }
213
- catch {
214
- // Not valid JSON, continue to try other formats
215
- }
216
- }
217
- // Try to parse PowerShell table/list format
218
- const psResult = tryParsePowerShellOutput(cleaned);
219
- if (psResult) {
220
- return psResult;
221
- }
222
- // Return cleaned string as-is
223
- return cleaned;
224
- }
225
- /**
226
- * Checks if pwsh (PowerShell 7+) is available on the system.
227
- * Result is cached for performance.
228
- */
229
- function isPwshAvailable() {
230
- if (pwshAvailable !== null) {
231
- return pwshAvailable;
232
- }
233
- try {
234
- const result = (0, child_process_1.spawnSync)('pwsh', ['--version'], {
235
- timeout: 5000,
236
- stdio: 'pipe',
237
- });
238
- pwshAvailable = result.status === 0;
239
- }
240
- catch {
241
- pwshAvailable = false;
242
- }
243
- return pwshAvailable;
244
- }
245
- /**
246
- * Parses a run command line into its components.
247
- * Format: run <type> <path> [args...]
248
- * Or: var <name> = run <type> <path> [args...]
249
- */
250
- function parseRunCommand(line) {
251
- const trimmed = line.trim();
252
- // Check for variable capture: var name = run ...
253
- const captureMatch = trimmed.match(/^var\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*run\s+(bash|powershell|pwsh|js)\s+(.+)$/i);
254
- if (captureMatch) {
255
- const [, varName, type, rest] = captureMatch;
256
- const { scriptPath, args } = parsePathAndArgs(rest);
257
- // Map 'pwsh' to 'powershell' for ScriptType
258
- const normalizedType = type.toLowerCase() === 'pwsh' ? 'powershell' : type.toLowerCase();
259
- return {
260
- type: normalizedType,
261
- scriptPath,
262
- args,
263
- captureAs: varName,
264
- };
265
- }
266
- // Check for plain run: run ...
267
- const runMatch = trimmed.match(/^run\s+(bash|powershell|pwsh|js)\s+(.+)$/i);
268
- if (runMatch) {
269
- const [, type, rest] = runMatch;
270
- const { scriptPath, args } = parsePathAndArgs(rest);
271
- // Map 'pwsh' to 'powershell' for ScriptType
272
- const normalizedType = type.toLowerCase() === 'pwsh' ? 'powershell' : type.toLowerCase();
273
- return {
274
- type: normalizedType,
275
- scriptPath,
276
- args,
277
- };
278
- }
279
- return null;
280
- }
281
- /**
282
- * Parses the script path and arguments from the remainder of the command.
283
- * Handles quoted paths with spaces.
284
- */
285
- function parsePathAndArgs(rest) {
286
- const parts = [];
287
- let current = '';
288
- let inQuote = false;
289
- let quoteChar = '';
290
- for (const char of rest) {
291
- if ((char === '"' || char === "'") && !inQuote) {
292
- inQuote = true;
293
- quoteChar = char;
294
- }
295
- else if (char === quoteChar && inQuote) {
296
- inQuote = false;
297
- quoteChar = '';
298
- }
299
- else if (char === ' ' && !inQuote) {
300
- if (current) {
301
- parts.push(current);
302
- current = '';
303
- }
304
- }
305
- else {
306
- current += char;
307
- }
308
- }
309
- if (current) {
310
- parts.push(current);
311
- }
312
- return {
313
- scriptPath: parts[0] || '',
314
- args: parts.slice(1),
315
- };
316
- }
317
- /**
318
- * Checks if a line is a run command
319
- */
320
- function isRunCommand(line) {
321
- const trimmed = line.trim();
322
- return /^(var\s+[a-zA-Z_][a-zA-Z0-9_]*\s*=\s*)?run\s+(bash|powershell|pwsh|js)\s+/i.test(trimmed);
323
- }
324
- /**
325
- * Executes a script and returns the result.
326
- */
327
- async function runScript(type, scriptPath, args, workingDir, variables = {}, captureVar) {
328
- const startTime = Date.now();
329
- // Resolve relative paths
330
- const resolvedPath = path.isAbsolute(scriptPath)
331
- ? scriptPath
332
- : path.resolve(workingDir, scriptPath);
333
- // Determine command and arguments based on script type
334
- let command;
335
- let cmdArgs;
336
- switch (type) {
337
- case 'bash':
338
- command = 'bash';
339
- cmdArgs = [resolvedPath, ...args];
340
- break;
341
- case 'powershell':
342
- // Prefer pwsh (PowerShell 7+) for newer SqlClient drivers and cross-platform support
343
- // Fall back to powershell (Windows PowerShell 5.1) if pwsh is not installed
344
- command = isPwshAvailable() ? 'pwsh' : 'powershell';
345
- // Use -ExecutionPolicy Bypass to avoid script execution policy issues
346
- // Don't use -NoProfile so that user's profile can load modules like SqlServer
347
- // Arguments are passed directly without shell interpretation, preserving special chars
348
- cmdArgs = ['-ExecutionPolicy', 'Bypass', '-File', resolvedPath, ...args];
349
- break;
350
- break;
351
- case 'js':
352
- command = 'node';
353
- cmdArgs = [resolvedPath, ...args];
354
- break;
355
- default:
356
- return {
357
- success: false,
358
- output: '',
359
- error: `Unknown script type: ${type}`,
360
- exitCode: 1,
361
- duration: Date.now() - startTime,
362
- type,
363
- scriptPath,
364
- captureVar,
365
- };
366
- }
367
- return new Promise((resolve) => {
368
- const env = {
369
- ...process.env,
370
- // Pass variables as environment variables with NORN_ prefix
371
- ...Object.fromEntries(Object.entries(variables).map(([k, v]) => [`NORN_${k.toUpperCase()}`, v])),
372
- // Also pass as JSON for convenience
373
- NORN_VARIABLES: JSON.stringify(variables),
374
- };
375
- // Don't use shell: true as it causes issues with special characters in arguments
376
- // Arguments are passed directly to the process, which handles them correctly
377
- const child = (0, child_process_1.spawn)(command, cmdArgs, {
378
- cwd: workingDir,
379
- env,
380
- shell: false,
381
- });
382
- let stdout = '';
383
- let stderr = '';
384
- child.stdout.on('data', (data) => {
385
- stdout += data.toString();
386
- });
387
- child.stderr.on('data', (data) => {
388
- stderr += data.toString();
389
- });
390
- child.on('error', (err) => {
391
- resolve({
392
- success: false,
393
- output: cleanScriptOutput(stdout),
394
- error: `Failed to execute script: ${err.message}`,
395
- exitCode: 1,
396
- duration: Date.now() - startTime,
397
- type,
398
- scriptPath,
399
- captureVar,
400
- });
401
- });
402
- child.on('close', (code) => {
403
- const exitCode = code ?? 0;
404
- // Clean the output: strip ANSI codes and normalize JSON if present
405
- const cleanedOutput = cleanScriptOutput(stdout);
406
- resolve({
407
- success: exitCode === 0,
408
- output: cleanedOutput,
409
- error: stderr.trim(),
410
- exitCode,
411
- duration: Date.now() - startTime,
412
- type,
413
- scriptPath,
414
- captureVar,
415
- });
416
- });
417
- });
418
- }
419
- //# sourceMappingURL=scriptRunner.js.map