norn-cli 1.3.11 → 1.3.13
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/CHANGELOG.md +17 -0
- package/dist/cli.js +95 -19
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,23 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to the "Norn" extension will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [1.3.13] - 2026-02-10
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
- **Script Variable Resolution**: Fixed `print` showing raw command text instead of script output
|
|
9
|
+
- `extractVariables` now skips runtime-computed values (`var x = run ...`, `var x = $1...`, `var x = METHOD url`)
|
|
10
|
+
- Variables are only pre-populated for static assignments, not scripts/captures
|
|
11
|
+
- **Test Explorer Script Paths**: Fixed script path resolution when running tests through Test Explorer
|
|
12
|
+
- Scripts in imported sequences now resolve relative to the imported file, not the importing file
|
|
13
|
+
- Added `sequenceSources` parameter to Test Explorer execution path
|
|
14
|
+
|
|
15
|
+
## [1.3.12] - 2026-02-10
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
- **Variable Request with Form Body**: Fixed `var x = POST EndpointName HeaderGroup` not passing URL-encoded body
|
|
19
|
+
- Body lines following the var request command are now correctly collected and sent
|
|
20
|
+
- Example: `var result = POST PostFormData FormData` followed by `key=value` lines now works
|
|
21
|
+
|
|
5
22
|
## [1.3.11] - 2026-02-09
|
|
6
23
|
|
|
7
24
|
### Fixed
|
package/dist/cli.js
CHANGED
|
@@ -20032,9 +20032,21 @@ function getNamedRequest(text, name) {
|
|
|
20032
20032
|
function extractVariables(text) {
|
|
20033
20033
|
const variables = {};
|
|
20034
20034
|
const variableRegex = /^\s*var\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*(.+)$/gm;
|
|
20035
|
+
const runtimePatterns = [
|
|
20036
|
+
/^run\s+/i,
|
|
20037
|
+
// var x = run ... (scripts/sequences)
|
|
20038
|
+
/^\$\d+/,
|
|
20039
|
+
// var x = $1... (response captures)
|
|
20040
|
+
/^(GET|POST|PUT|DELETE|PATCH|HEAD|OPTIONS)\s+/i
|
|
20041
|
+
// var x = METHOD url (request captures)
|
|
20042
|
+
];
|
|
20035
20043
|
let match;
|
|
20036
20044
|
while ((match = variableRegex.exec(text)) !== null) {
|
|
20037
20045
|
let value = match[2].trim();
|
|
20046
|
+
const isRuntimeValue = runtimePatterns.some((pattern) => pattern.test(value));
|
|
20047
|
+
if (isRuntimeValue) {
|
|
20048
|
+
continue;
|
|
20049
|
+
}
|
|
20038
20050
|
if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
|
|
20039
20051
|
value = value.slice(1, -1);
|
|
20040
20052
|
}
|
|
@@ -20338,7 +20350,7 @@ ${resolvedContent}`);
|
|
|
20338
20350
|
lineNumber: imp.lineNumber
|
|
20339
20351
|
});
|
|
20340
20352
|
} else {
|
|
20341
|
-
sequenceSources.set(lowerName,
|
|
20353
|
+
sequenceSources.set(lowerName, absolutePath);
|
|
20342
20354
|
const resolvedContent = substituteVariables(seq.content, importedVariables);
|
|
20343
20355
|
importedContents.push(`sequence ${seq.name}
|
|
20344
20356
|
${resolvedContent}
|
|
@@ -20358,7 +20370,8 @@ end sequence`);
|
|
|
20358
20370
|
errors,
|
|
20359
20371
|
resolvedPaths,
|
|
20360
20372
|
headerGroups,
|
|
20361
|
-
endpoints
|
|
20373
|
+
endpoints,
|
|
20374
|
+
sequenceSources
|
|
20362
20375
|
};
|
|
20363
20376
|
}
|
|
20364
20377
|
function extractSequencesFromText(text) {
|
|
@@ -27519,6 +27532,20 @@ function extractStepsFromSequence(content) {
|
|
|
27519
27532
|
let currentRequest = [];
|
|
27520
27533
|
let currentRequestStartLine = -1;
|
|
27521
27534
|
let inRequest = false;
|
|
27535
|
+
let currentVarRequest = [];
|
|
27536
|
+
let currentVarRequestStartLine = -1;
|
|
27537
|
+
let inVarRequest = false;
|
|
27538
|
+
const savePendingVarRequest = () => {
|
|
27539
|
+
if (currentVarRequest.length > 0) {
|
|
27540
|
+
steps.push({
|
|
27541
|
+
type: "varRequest",
|
|
27542
|
+
content: currentVarRequest.join("\n"),
|
|
27543
|
+
lineNumber: currentVarRequestStartLine
|
|
27544
|
+
});
|
|
27545
|
+
currentVarRequest = [];
|
|
27546
|
+
inVarRequest = false;
|
|
27547
|
+
}
|
|
27548
|
+
};
|
|
27522
27549
|
for (let lineIdx = 0; lineIdx < lines.length; lineIdx++) {
|
|
27523
27550
|
const line2 = lines[lineIdx];
|
|
27524
27551
|
const trimmed = line2.trim();
|
|
@@ -27532,6 +27559,7 @@ function extractStepsFromSequence(content) {
|
|
|
27532
27559
|
currentRequest = [];
|
|
27533
27560
|
inRequest = false;
|
|
27534
27561
|
}
|
|
27562
|
+
savePendingVarRequest();
|
|
27535
27563
|
steps.push({
|
|
27536
27564
|
type: "assertion",
|
|
27537
27565
|
content: trimmed,
|
|
@@ -27549,6 +27577,7 @@ function extractStepsFromSequence(content) {
|
|
|
27549
27577
|
currentRequest = [];
|
|
27550
27578
|
inRequest = false;
|
|
27551
27579
|
}
|
|
27580
|
+
savePendingVarRequest();
|
|
27552
27581
|
const condition = parseIfCondition(trimmed);
|
|
27553
27582
|
steps.push({
|
|
27554
27583
|
type: "if",
|
|
@@ -27567,6 +27596,7 @@ function extractStepsFromSequence(content) {
|
|
|
27567
27596
|
currentRequest = [];
|
|
27568
27597
|
inRequest = false;
|
|
27569
27598
|
}
|
|
27599
|
+
savePendingVarRequest();
|
|
27570
27600
|
steps.push({
|
|
27571
27601
|
type: "endif",
|
|
27572
27602
|
content: "",
|
|
@@ -27584,6 +27614,7 @@ function extractStepsFromSequence(content) {
|
|
|
27584
27614
|
currentRequest = [];
|
|
27585
27615
|
inRequest = false;
|
|
27586
27616
|
}
|
|
27617
|
+
savePendingVarRequest();
|
|
27587
27618
|
steps.push({
|
|
27588
27619
|
type: "print",
|
|
27589
27620
|
content: trimmed,
|
|
@@ -27602,6 +27633,7 @@ function extractStepsFromSequence(content) {
|
|
|
27602
27633
|
currentRequest = [];
|
|
27603
27634
|
inRequest = false;
|
|
27604
27635
|
}
|
|
27636
|
+
savePendingVarRequest();
|
|
27605
27637
|
steps.push({
|
|
27606
27638
|
type: "wait",
|
|
27607
27639
|
content: trimmed,
|
|
@@ -27619,6 +27651,7 @@ function extractStepsFromSequence(content) {
|
|
|
27619
27651
|
currentRequest = [];
|
|
27620
27652
|
inRequest = false;
|
|
27621
27653
|
}
|
|
27654
|
+
savePendingVarRequest();
|
|
27622
27655
|
steps.push({
|
|
27623
27656
|
type: "json",
|
|
27624
27657
|
content: trimmed,
|
|
@@ -27636,6 +27669,7 @@ function extractStepsFromSequence(content) {
|
|
|
27636
27669
|
currentRequest = [];
|
|
27637
27670
|
inRequest = false;
|
|
27638
27671
|
}
|
|
27672
|
+
savePendingVarRequest();
|
|
27639
27673
|
steps.push({
|
|
27640
27674
|
type: "propAssign",
|
|
27641
27675
|
content: trimmed,
|
|
@@ -27653,6 +27687,7 @@ function extractStepsFromSequence(content) {
|
|
|
27653
27687
|
currentRequest = [];
|
|
27654
27688
|
inRequest = false;
|
|
27655
27689
|
}
|
|
27690
|
+
savePendingVarRequest();
|
|
27656
27691
|
steps.push({
|
|
27657
27692
|
type: "script",
|
|
27658
27693
|
content: trimmed,
|
|
@@ -27670,6 +27705,7 @@ function extractStepsFromSequence(content) {
|
|
|
27670
27705
|
currentRequest = [];
|
|
27671
27706
|
inRequest = false;
|
|
27672
27707
|
}
|
|
27708
|
+
savePendingVarRequest();
|
|
27673
27709
|
steps.push({
|
|
27674
27710
|
type: "varRunSequence",
|
|
27675
27711
|
content: trimmed,
|
|
@@ -27687,6 +27723,7 @@ function extractStepsFromSequence(content) {
|
|
|
27687
27723
|
currentRequest = [];
|
|
27688
27724
|
inRequest = false;
|
|
27689
27725
|
}
|
|
27726
|
+
savePendingVarRequest();
|
|
27690
27727
|
steps.push({
|
|
27691
27728
|
type: "namedRequest",
|
|
27692
27729
|
content: trimmed,
|
|
@@ -27704,11 +27741,10 @@ function extractStepsFromSequence(content) {
|
|
|
27704
27741
|
currentRequest = [];
|
|
27705
27742
|
inRequest = false;
|
|
27706
27743
|
}
|
|
27707
|
-
|
|
27708
|
-
|
|
27709
|
-
|
|
27710
|
-
|
|
27711
|
-
});
|
|
27744
|
+
savePendingVarRequest();
|
|
27745
|
+
currentVarRequest = [trimmed];
|
|
27746
|
+
currentVarRequestStartLine = lineIdx;
|
|
27747
|
+
inVarRequest = true;
|
|
27712
27748
|
continue;
|
|
27713
27749
|
}
|
|
27714
27750
|
if (isVarAssignCommand(trimmed)) {
|
|
@@ -27721,6 +27757,7 @@ function extractStepsFromSequence(content) {
|
|
|
27721
27757
|
currentRequest = [];
|
|
27722
27758
|
inRequest = false;
|
|
27723
27759
|
}
|
|
27760
|
+
savePendingVarRequest();
|
|
27724
27761
|
steps.push({
|
|
27725
27762
|
type: "varAssign",
|
|
27726
27763
|
content: trimmed,
|
|
@@ -27736,9 +27773,17 @@ function extractStepsFromSequence(content) {
|
|
|
27736
27773
|
lineNumber: currentRequestStartLine
|
|
27737
27774
|
});
|
|
27738
27775
|
}
|
|
27776
|
+
savePendingVarRequest();
|
|
27739
27777
|
currentRequest = [trimmed];
|
|
27740
27778
|
currentRequestStartLine = lineIdx;
|
|
27741
27779
|
inRequest = true;
|
|
27780
|
+
} else if (inVarRequest) {
|
|
27781
|
+
if (trimmed === "" || trimmed.match(/^[a-zA-Z_][a-zA-Z0-9_]*\s*[=:]\s*.+$/) || trimmed.startsWith("{") || trimmed.startsWith('"') || trimmed.startsWith("[")) {
|
|
27782
|
+
currentVarRequest.push(trimmed);
|
|
27783
|
+
} else {
|
|
27784
|
+
savePendingVarRequest();
|
|
27785
|
+
lineIdx--;
|
|
27786
|
+
}
|
|
27742
27787
|
} else if (inRequest) {
|
|
27743
27788
|
if (trimmed.match(/^var\s+[a-zA-Z_][a-zA-Z0-9_]*\s*=\s*\$\d+/)) {
|
|
27744
27789
|
if (currentRequest.length > 0) {
|
|
@@ -27770,6 +27815,7 @@ function extractStepsFromSequence(content) {
|
|
|
27770
27815
|
lineNumber: currentRequestStartLine
|
|
27771
27816
|
});
|
|
27772
27817
|
}
|
|
27818
|
+
savePendingVarRequest();
|
|
27773
27819
|
return steps;
|
|
27774
27820
|
}
|
|
27775
27821
|
function extractCaptureDirectives(content) {
|
|
@@ -27836,7 +27882,7 @@ function getValueByPath(response, path5) {
|
|
|
27836
27882
|
return void 0;
|
|
27837
27883
|
}
|
|
27838
27884
|
}
|
|
27839
|
-
async function runSequenceWithJar(sequenceContent, fileVariables, cookieJar, workingDir, fullDocumentText, onProgress, callStack, sequenceArgs, apiDefinitions, tagFilterOptions) {
|
|
27885
|
+
async function runSequenceWithJar(sequenceContent, fileVariables, cookieJar, workingDir, fullDocumentText, onProgress, callStack, sequenceArgs, apiDefinitions, tagFilterOptions, sequenceSources) {
|
|
27840
27886
|
const startTime = Date.now();
|
|
27841
27887
|
const responses = [];
|
|
27842
27888
|
const scriptResults = [];
|
|
@@ -28155,9 +28201,10 @@ async function runSequenceWithJar(sequenceContent, fileVariables, cookieJar, wor
|
|
|
28155
28201
|
continue;
|
|
28156
28202
|
}
|
|
28157
28203
|
if (step.type === "varRequest") {
|
|
28158
|
-
const
|
|
28204
|
+
const commandLine = step.content.split("\n")[0];
|
|
28205
|
+
const parsed = parseVarRequestCommand(commandLine);
|
|
28159
28206
|
if (!parsed) {
|
|
28160
|
-
errors.push(`Step ${stepIdx + 1}: Invalid variable request: ${
|
|
28207
|
+
errors.push(`Step ${stepIdx + 1}: Invalid variable request: ${commandLine}`);
|
|
28161
28208
|
return {
|
|
28162
28209
|
name: "",
|
|
28163
28210
|
success: false,
|
|
@@ -28233,6 +28280,12 @@ async function runSequenceWithJar(sequenceContent, fileVariables, cookieJar, wor
|
|
|
28233
28280
|
const headerLines = Object.entries(resolvedHeaders).map(([k, v]) => `${k}: ${v}`);
|
|
28234
28281
|
requestText += "\n" + headerLines.join("\n");
|
|
28235
28282
|
}
|
|
28283
|
+
const contentLines = step.content.split("\n");
|
|
28284
|
+
if (contentLines.length > 1) {
|
|
28285
|
+
const bodyLines = contentLines.slice(1);
|
|
28286
|
+
const resolvedBodyLines = bodyLines.map((line2) => substituteVariables(line2, runtimeVariables));
|
|
28287
|
+
requestText += "\n\n" + resolvedBodyLines.join("\n");
|
|
28288
|
+
}
|
|
28236
28289
|
const requestParsed = parserHttpRequest(requestText, runtimeVariables);
|
|
28237
28290
|
const retryOpts = parsed.retryCount ? {
|
|
28238
28291
|
retryCount: parsed.retryCount,
|
|
@@ -28426,12 +28479,20 @@ async function runSequenceWithJar(sequenceContent, fileVariables, cookieJar, wor
|
|
|
28426
28479
|
}
|
|
28427
28480
|
}
|
|
28428
28481
|
reportProgress(stepIdx, "sequenceStart", `Starting sequence ${targetName}`, void 0, targetName);
|
|
28482
|
+
let subWorkingDir = workingDir;
|
|
28483
|
+
if (sequenceSources) {
|
|
28484
|
+
const sourceFile = sequenceSources.get(targetName.toLowerCase());
|
|
28485
|
+
if (sourceFile) {
|
|
28486
|
+
const path5 = await import("path");
|
|
28487
|
+
subWorkingDir = path5.dirname(sourceFile);
|
|
28488
|
+
}
|
|
28489
|
+
}
|
|
28429
28490
|
const subResult = await runSequenceWithJar(
|
|
28430
28491
|
targetSequence.content,
|
|
28431
28492
|
runtimeVariables,
|
|
28432
28493
|
// Pass current runtime variables (includes file vars + any captured)
|
|
28433
28494
|
cookieJar,
|
|
28434
|
-
|
|
28495
|
+
subWorkingDir,
|
|
28435
28496
|
fullDocumentText,
|
|
28436
28497
|
onProgress,
|
|
28437
28498
|
// Pass through progress callback
|
|
@@ -28441,8 +28502,10 @@ async function runSequenceWithJar(sequenceContent, fileVariables, cookieJar, wor
|
|
|
28441
28502
|
// Pass bound arguments as initial scope variables
|
|
28442
28503
|
apiDefinitions,
|
|
28443
28504
|
// Pass API definitions for endpoint resolution
|
|
28444
|
-
tagFilterOptions
|
|
28505
|
+
tagFilterOptions,
|
|
28445
28506
|
// Pass tag filter options for nested sequence filtering
|
|
28507
|
+
sequenceSources
|
|
28508
|
+
// Pass sequence sources for nested sequences
|
|
28446
28509
|
);
|
|
28447
28510
|
reportProgress(stepIdx, "sequenceEnd", `Finished sequence ${targetName}`, void 0, targetName);
|
|
28448
28511
|
for (const subResponse of subResult.responses) {
|
|
@@ -28751,11 +28814,19 @@ async function runSequenceWithJar(sequenceContent, fileVariables, cookieJar, wor
|
|
|
28751
28814
|
}
|
|
28752
28815
|
}
|
|
28753
28816
|
reportProgress(stepIdx, "sequenceStart", `Starting sequence ${sequenceName}`, void 0, sequenceName);
|
|
28817
|
+
let subWorkingDir = workingDir;
|
|
28818
|
+
if (sequenceSources) {
|
|
28819
|
+
const sourceFile = sequenceSources.get(sequenceName.toLowerCase());
|
|
28820
|
+
if (sourceFile) {
|
|
28821
|
+
const path5 = await import("path");
|
|
28822
|
+
subWorkingDir = path5.dirname(sourceFile);
|
|
28823
|
+
}
|
|
28824
|
+
}
|
|
28754
28825
|
const subResult = await runSequenceWithJar(
|
|
28755
28826
|
targetSequence.content,
|
|
28756
28827
|
runtimeVariables,
|
|
28757
28828
|
cookieJar,
|
|
28758
|
-
|
|
28829
|
+
subWorkingDir,
|
|
28759
28830
|
fullDocumentText,
|
|
28760
28831
|
onProgress,
|
|
28761
28832
|
[...currentCallStack, sequenceName],
|
|
@@ -28763,8 +28834,10 @@ async function runSequenceWithJar(sequenceContent, fileVariables, cookieJar, wor
|
|
|
28763
28834
|
// Pass bound arguments
|
|
28764
28835
|
apiDefinitions,
|
|
28765
28836
|
// Pass API definitions for endpoint resolution
|
|
28766
|
-
tagFilterOptions
|
|
28837
|
+
tagFilterOptions,
|
|
28767
28838
|
// Pass tag filter options for nested sequence filtering
|
|
28839
|
+
sequenceSources
|
|
28840
|
+
// Pass sequence sources for nested sequences
|
|
28768
28841
|
);
|
|
28769
28842
|
reportProgress(stepIdx, "sequenceEnd", `Finished sequence ${sequenceName}`, void 0, sequenceName);
|
|
28770
28843
|
for (const subResponse of subResult.responses) {
|
|
@@ -30499,7 +30572,7 @@ function formatCaseLabel(params) {
|
|
|
30499
30572
|
});
|
|
30500
30573
|
return `[${parts.join(", ")}]`;
|
|
30501
30574
|
}
|
|
30502
|
-
async function runAllSequences(fileContent, variables, cookieJar, workingDir, apiDefinitions, tagFilterOptions) {
|
|
30575
|
+
async function runAllSequences(fileContent, variables, cookieJar, workingDir, apiDefinitions, tagFilterOptions, sequenceSources) {
|
|
30503
30576
|
const allSequences = extractSequences(fileContent);
|
|
30504
30577
|
const results = [];
|
|
30505
30578
|
const testSequences = allSequences.filter((seq) => seq.isTest);
|
|
@@ -30543,7 +30616,8 @@ async function runAllSequences(fileContent, variables, cookieJar, workingDir, ap
|
|
|
30543
30616
|
void 0,
|
|
30544
30617
|
caseArgs,
|
|
30545
30618
|
apiDefinitions,
|
|
30546
|
-
tagFilterOptions
|
|
30619
|
+
tagFilterOptions,
|
|
30620
|
+
sequenceSources
|
|
30547
30621
|
);
|
|
30548
30622
|
result.name = `${seq.name}${caseLabel}`;
|
|
30549
30623
|
results.push(result);
|
|
@@ -30567,7 +30641,8 @@ async function runAllSequences(fileContent, variables, cookieJar, workingDir, ap
|
|
|
30567
30641
|
void 0,
|
|
30568
30642
|
defaultArgs,
|
|
30569
30643
|
apiDefinitions,
|
|
30570
|
-
tagFilterOptions
|
|
30644
|
+
tagFilterOptions,
|
|
30645
|
+
sequenceSources
|
|
30571
30646
|
);
|
|
30572
30647
|
result.name = seq.name;
|
|
30573
30648
|
results.push(result);
|
|
@@ -30742,7 +30817,8 @@ ${fileContent}` : fileContent;
|
|
|
30742
30817
|
void 0,
|
|
30743
30818
|
defaultArgs,
|
|
30744
30819
|
apiDefinitions,
|
|
30745
|
-
tagFilterOptions
|
|
30820
|
+
tagFilterOptions,
|
|
30821
|
+
importResult.sequenceSources
|
|
30746
30822
|
);
|
|
30747
30823
|
seqResult.name = targetSeq.name;
|
|
30748
30824
|
if (options.output === "json") {
|
|
@@ -30823,7 +30899,7 @@ ${fileContent}` : fileContent;
|
|
|
30823
30899
|
\u2501\u2501\u2501 ${relPath} \u2501\u2501\u2501`));
|
|
30824
30900
|
}
|
|
30825
30901
|
const apiDefinitions = (importResult.headerGroups?.length || 0) > 0 || (importResult.endpoints?.length || 0) > 0 ? { headerGroups: importResult.headerGroups || [], endpoints: importResult.endpoints || [] } : void 0;
|
|
30826
|
-
const seqResults = await runAllSequences(fileContentWithImports, variables, cookieJar, workingDir, apiDefinitions, tagFilterOptions);
|
|
30902
|
+
const seqResults = await runAllSequences(fileContentWithImports, variables, cookieJar, workingDir, apiDefinitions, tagFilterOptions, importResult.sequenceSources);
|
|
30827
30903
|
for (const result2 of seqResults) {
|
|
30828
30904
|
result2.sourceFile = filePath;
|
|
30829
30905
|
allResults.push(result2);
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "norn-cli",
|
|
3
3
|
"displayName": "Norn - REST Client",
|
|
4
4
|
"description": "A powerful REST client for making HTTP requests with sequences, variables, scripts, and cookie support",
|
|
5
|
-
"version": "1.3.
|
|
5
|
+
"version": "1.3.13",
|
|
6
6
|
"publisher": "Norn-PeterKrustanov",
|
|
7
7
|
"author": {
|
|
8
8
|
"name": "Peter Krastanov"
|