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.
Files changed (3) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/dist/cli.js +95 -19
  3. 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, imp.path);
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
- steps.push({
27708
- type: "varRequest",
27709
- content: trimmed,
27710
- lineNumber: lineIdx
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 parsed = parseVarRequestCommand(step.content);
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: ${step.content}`);
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
- workingDir,
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
- workingDir,
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.11",
5
+ "version": "1.3.13",
6
6
  "publisher": "Norn-PeterKrustanov",
7
7
  "author": {
8
8
  "name": "Peter Krastanov"