norn-cli 1.3.10 → 1.3.12

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.
@@ -6,14 +6,14 @@
6
6
  "sourceFile": "tests/Regression/15-contract-validation.norn",
7
7
  "assertionLine": 15,
8
8
  "status": "pass",
9
- "lastRunTime": "2026-02-08T20:13:44.031Z"
9
+ "lastRunTime": "2026-02-09T20:01:50.112Z"
10
10
  },
11
11
  "tests/Regression/15-contract-validation.norn:25": {
12
12
  "schemaPath": "tests/Regression/schemas/GET-users-1.schema.json",
13
13
  "sourceFile": "tests/Regression/15-contract-validation.norn",
14
14
  "assertionLine": 25,
15
15
  "status": "pass",
16
- "lastRunTime": "2026-02-08T20:16:27.876Z"
16
+ "lastRunTime": "2026-02-09T20:01:54.179Z"
17
17
  },
18
18
  "tests/Regression/15-contract-validation.norn:35": {
19
19
  "schemaPath": "tests/Regression/schemas/GET-todos-1.schema.json",
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.12] - 2026-02-10
6
+
7
+ ### Fixed
8
+ - **Variable Request with Form Body**: Fixed `var x = POST EndpointName HeaderGroup` not passing URL-encoded body
9
+ - Body lines following the var request command are now correctly collected and sent
10
+ - Example: `var result = POST PostFormData FormData` followed by `key=value` lines now works
11
+
12
+ ## [1.3.11] - 2026-02-09
13
+
14
+ ### Fixed
15
+ - **Syntax Highlighting**: Fixed header value colors in sequences
16
+ - `Content-Type: application/json` now correctly colors the entire value
17
+ - `/json` part no longer incorrectly highlighted as URL
18
+ - **Syntax Highlighting**: Fixed numbers in variable names being highlighted separately
19
+ - `item3.status` now shows as single variable color instead of `item` + `3` in different colors
20
+ - Added proper variable pattern matching in assert statements
21
+
5
22
  ## [1.3.10] - 2026-02-09
6
23
 
7
24
  ### Fixed
package/dist/cli.js CHANGED
@@ -20338,7 +20338,7 @@ ${resolvedContent}`);
20338
20338
  lineNumber: imp.lineNumber
20339
20339
  });
20340
20340
  } else {
20341
- sequenceSources.set(lowerName, imp.path);
20341
+ sequenceSources.set(lowerName, absolutePath);
20342
20342
  const resolvedContent = substituteVariables(seq.content, importedVariables);
20343
20343
  importedContents.push(`sequence ${seq.name}
20344
20344
  ${resolvedContent}
@@ -20358,7 +20358,8 @@ end sequence`);
20358
20358
  errors,
20359
20359
  resolvedPaths,
20360
20360
  headerGroups,
20361
- endpoints
20361
+ endpoints,
20362
+ sequenceSources
20362
20363
  };
20363
20364
  }
20364
20365
  function extractSequencesFromText(text) {
@@ -27519,6 +27520,20 @@ function extractStepsFromSequence(content) {
27519
27520
  let currentRequest = [];
27520
27521
  let currentRequestStartLine = -1;
27521
27522
  let inRequest = false;
27523
+ let currentVarRequest = [];
27524
+ let currentVarRequestStartLine = -1;
27525
+ let inVarRequest = false;
27526
+ const savePendingVarRequest = () => {
27527
+ if (currentVarRequest.length > 0) {
27528
+ steps.push({
27529
+ type: "varRequest",
27530
+ content: currentVarRequest.join("\n"),
27531
+ lineNumber: currentVarRequestStartLine
27532
+ });
27533
+ currentVarRequest = [];
27534
+ inVarRequest = false;
27535
+ }
27536
+ };
27522
27537
  for (let lineIdx = 0; lineIdx < lines.length; lineIdx++) {
27523
27538
  const line2 = lines[lineIdx];
27524
27539
  const trimmed = line2.trim();
@@ -27532,6 +27547,7 @@ function extractStepsFromSequence(content) {
27532
27547
  currentRequest = [];
27533
27548
  inRequest = false;
27534
27549
  }
27550
+ savePendingVarRequest();
27535
27551
  steps.push({
27536
27552
  type: "assertion",
27537
27553
  content: trimmed,
@@ -27549,6 +27565,7 @@ function extractStepsFromSequence(content) {
27549
27565
  currentRequest = [];
27550
27566
  inRequest = false;
27551
27567
  }
27568
+ savePendingVarRequest();
27552
27569
  const condition = parseIfCondition(trimmed);
27553
27570
  steps.push({
27554
27571
  type: "if",
@@ -27567,6 +27584,7 @@ function extractStepsFromSequence(content) {
27567
27584
  currentRequest = [];
27568
27585
  inRequest = false;
27569
27586
  }
27587
+ savePendingVarRequest();
27570
27588
  steps.push({
27571
27589
  type: "endif",
27572
27590
  content: "",
@@ -27584,6 +27602,7 @@ function extractStepsFromSequence(content) {
27584
27602
  currentRequest = [];
27585
27603
  inRequest = false;
27586
27604
  }
27605
+ savePendingVarRequest();
27587
27606
  steps.push({
27588
27607
  type: "print",
27589
27608
  content: trimmed,
@@ -27602,6 +27621,7 @@ function extractStepsFromSequence(content) {
27602
27621
  currentRequest = [];
27603
27622
  inRequest = false;
27604
27623
  }
27624
+ savePendingVarRequest();
27605
27625
  steps.push({
27606
27626
  type: "wait",
27607
27627
  content: trimmed,
@@ -27619,6 +27639,7 @@ function extractStepsFromSequence(content) {
27619
27639
  currentRequest = [];
27620
27640
  inRequest = false;
27621
27641
  }
27642
+ savePendingVarRequest();
27622
27643
  steps.push({
27623
27644
  type: "json",
27624
27645
  content: trimmed,
@@ -27636,6 +27657,7 @@ function extractStepsFromSequence(content) {
27636
27657
  currentRequest = [];
27637
27658
  inRequest = false;
27638
27659
  }
27660
+ savePendingVarRequest();
27639
27661
  steps.push({
27640
27662
  type: "propAssign",
27641
27663
  content: trimmed,
@@ -27653,6 +27675,7 @@ function extractStepsFromSequence(content) {
27653
27675
  currentRequest = [];
27654
27676
  inRequest = false;
27655
27677
  }
27678
+ savePendingVarRequest();
27656
27679
  steps.push({
27657
27680
  type: "script",
27658
27681
  content: trimmed,
@@ -27670,6 +27693,7 @@ function extractStepsFromSequence(content) {
27670
27693
  currentRequest = [];
27671
27694
  inRequest = false;
27672
27695
  }
27696
+ savePendingVarRequest();
27673
27697
  steps.push({
27674
27698
  type: "varRunSequence",
27675
27699
  content: trimmed,
@@ -27687,6 +27711,7 @@ function extractStepsFromSequence(content) {
27687
27711
  currentRequest = [];
27688
27712
  inRequest = false;
27689
27713
  }
27714
+ savePendingVarRequest();
27690
27715
  steps.push({
27691
27716
  type: "namedRequest",
27692
27717
  content: trimmed,
@@ -27704,11 +27729,10 @@ function extractStepsFromSequence(content) {
27704
27729
  currentRequest = [];
27705
27730
  inRequest = false;
27706
27731
  }
27707
- steps.push({
27708
- type: "varRequest",
27709
- content: trimmed,
27710
- lineNumber: lineIdx
27711
- });
27732
+ savePendingVarRequest();
27733
+ currentVarRequest = [trimmed];
27734
+ currentVarRequestStartLine = lineIdx;
27735
+ inVarRequest = true;
27712
27736
  continue;
27713
27737
  }
27714
27738
  if (isVarAssignCommand(trimmed)) {
@@ -27721,6 +27745,7 @@ function extractStepsFromSequence(content) {
27721
27745
  currentRequest = [];
27722
27746
  inRequest = false;
27723
27747
  }
27748
+ savePendingVarRequest();
27724
27749
  steps.push({
27725
27750
  type: "varAssign",
27726
27751
  content: trimmed,
@@ -27736,9 +27761,17 @@ function extractStepsFromSequence(content) {
27736
27761
  lineNumber: currentRequestStartLine
27737
27762
  });
27738
27763
  }
27764
+ savePendingVarRequest();
27739
27765
  currentRequest = [trimmed];
27740
27766
  currentRequestStartLine = lineIdx;
27741
27767
  inRequest = true;
27768
+ } else if (inVarRequest) {
27769
+ if (trimmed === "" || trimmed.match(/^[a-zA-Z_][a-zA-Z0-9_]*\s*[=:]\s*.+$/) || trimmed.startsWith("{") || trimmed.startsWith('"') || trimmed.startsWith("[")) {
27770
+ currentVarRequest.push(trimmed);
27771
+ } else {
27772
+ savePendingVarRequest();
27773
+ lineIdx--;
27774
+ }
27742
27775
  } else if (inRequest) {
27743
27776
  if (trimmed.match(/^var\s+[a-zA-Z_][a-zA-Z0-9_]*\s*=\s*\$\d+/)) {
27744
27777
  if (currentRequest.length > 0) {
@@ -27770,6 +27803,7 @@ function extractStepsFromSequence(content) {
27770
27803
  lineNumber: currentRequestStartLine
27771
27804
  });
27772
27805
  }
27806
+ savePendingVarRequest();
27773
27807
  return steps;
27774
27808
  }
27775
27809
  function extractCaptureDirectives(content) {
@@ -27836,7 +27870,7 @@ function getValueByPath(response, path5) {
27836
27870
  return void 0;
27837
27871
  }
27838
27872
  }
27839
- async function runSequenceWithJar(sequenceContent, fileVariables, cookieJar, workingDir, fullDocumentText, onProgress, callStack, sequenceArgs, apiDefinitions, tagFilterOptions) {
27873
+ async function runSequenceWithJar(sequenceContent, fileVariables, cookieJar, workingDir, fullDocumentText, onProgress, callStack, sequenceArgs, apiDefinitions, tagFilterOptions, sequenceSources) {
27840
27874
  const startTime = Date.now();
27841
27875
  const responses = [];
27842
27876
  const scriptResults = [];
@@ -28155,9 +28189,10 @@ async function runSequenceWithJar(sequenceContent, fileVariables, cookieJar, wor
28155
28189
  continue;
28156
28190
  }
28157
28191
  if (step.type === "varRequest") {
28158
- const parsed = parseVarRequestCommand(step.content);
28192
+ const commandLine = step.content.split("\n")[0];
28193
+ const parsed = parseVarRequestCommand(commandLine);
28159
28194
  if (!parsed) {
28160
- errors.push(`Step ${stepIdx + 1}: Invalid variable request: ${step.content}`);
28195
+ errors.push(`Step ${stepIdx + 1}: Invalid variable request: ${commandLine}`);
28161
28196
  return {
28162
28197
  name: "",
28163
28198
  success: false,
@@ -28233,6 +28268,12 @@ async function runSequenceWithJar(sequenceContent, fileVariables, cookieJar, wor
28233
28268
  const headerLines = Object.entries(resolvedHeaders).map(([k, v]) => `${k}: ${v}`);
28234
28269
  requestText += "\n" + headerLines.join("\n");
28235
28270
  }
28271
+ const contentLines = step.content.split("\n");
28272
+ if (contentLines.length > 1) {
28273
+ const bodyLines = contentLines.slice(1);
28274
+ const resolvedBodyLines = bodyLines.map((line2) => substituteVariables(line2, runtimeVariables));
28275
+ requestText += "\n\n" + resolvedBodyLines.join("\n");
28276
+ }
28236
28277
  const requestParsed = parserHttpRequest(requestText, runtimeVariables);
28237
28278
  const retryOpts = parsed.retryCount ? {
28238
28279
  retryCount: parsed.retryCount,
@@ -28426,12 +28467,20 @@ async function runSequenceWithJar(sequenceContent, fileVariables, cookieJar, wor
28426
28467
  }
28427
28468
  }
28428
28469
  reportProgress(stepIdx, "sequenceStart", `Starting sequence ${targetName}`, void 0, targetName);
28470
+ let subWorkingDir = workingDir;
28471
+ if (sequenceSources) {
28472
+ const sourceFile = sequenceSources.get(targetName.toLowerCase());
28473
+ if (sourceFile) {
28474
+ const path5 = await import("path");
28475
+ subWorkingDir = path5.dirname(sourceFile);
28476
+ }
28477
+ }
28429
28478
  const subResult = await runSequenceWithJar(
28430
28479
  targetSequence.content,
28431
28480
  runtimeVariables,
28432
28481
  // Pass current runtime variables (includes file vars + any captured)
28433
28482
  cookieJar,
28434
- workingDir,
28483
+ subWorkingDir,
28435
28484
  fullDocumentText,
28436
28485
  onProgress,
28437
28486
  // Pass through progress callback
@@ -28441,8 +28490,10 @@ async function runSequenceWithJar(sequenceContent, fileVariables, cookieJar, wor
28441
28490
  // Pass bound arguments as initial scope variables
28442
28491
  apiDefinitions,
28443
28492
  // Pass API definitions for endpoint resolution
28444
- tagFilterOptions
28493
+ tagFilterOptions,
28445
28494
  // Pass tag filter options for nested sequence filtering
28495
+ sequenceSources
28496
+ // Pass sequence sources for nested sequences
28446
28497
  );
28447
28498
  reportProgress(stepIdx, "sequenceEnd", `Finished sequence ${targetName}`, void 0, targetName);
28448
28499
  for (const subResponse of subResult.responses) {
@@ -28751,11 +28802,19 @@ async function runSequenceWithJar(sequenceContent, fileVariables, cookieJar, wor
28751
28802
  }
28752
28803
  }
28753
28804
  reportProgress(stepIdx, "sequenceStart", `Starting sequence ${sequenceName}`, void 0, sequenceName);
28805
+ let subWorkingDir = workingDir;
28806
+ if (sequenceSources) {
28807
+ const sourceFile = sequenceSources.get(sequenceName.toLowerCase());
28808
+ if (sourceFile) {
28809
+ const path5 = await import("path");
28810
+ subWorkingDir = path5.dirname(sourceFile);
28811
+ }
28812
+ }
28754
28813
  const subResult = await runSequenceWithJar(
28755
28814
  targetSequence.content,
28756
28815
  runtimeVariables,
28757
28816
  cookieJar,
28758
- workingDir,
28817
+ subWorkingDir,
28759
28818
  fullDocumentText,
28760
28819
  onProgress,
28761
28820
  [...currentCallStack, sequenceName],
@@ -28763,8 +28822,10 @@ async function runSequenceWithJar(sequenceContent, fileVariables, cookieJar, wor
28763
28822
  // Pass bound arguments
28764
28823
  apiDefinitions,
28765
28824
  // Pass API definitions for endpoint resolution
28766
- tagFilterOptions
28825
+ tagFilterOptions,
28767
28826
  // Pass tag filter options for nested sequence filtering
28827
+ sequenceSources
28828
+ // Pass sequence sources for nested sequences
28768
28829
  );
28769
28830
  reportProgress(stepIdx, "sequenceEnd", `Finished sequence ${sequenceName}`, void 0, sequenceName);
28770
28831
  for (const subResponse of subResult.responses) {
@@ -30499,7 +30560,7 @@ function formatCaseLabel(params) {
30499
30560
  });
30500
30561
  return `[${parts.join(", ")}]`;
30501
30562
  }
30502
- async function runAllSequences(fileContent, variables, cookieJar, workingDir, apiDefinitions, tagFilterOptions) {
30563
+ async function runAllSequences(fileContent, variables, cookieJar, workingDir, apiDefinitions, tagFilterOptions, sequenceSources) {
30503
30564
  const allSequences = extractSequences(fileContent);
30504
30565
  const results = [];
30505
30566
  const testSequences = allSequences.filter((seq) => seq.isTest);
@@ -30543,7 +30604,8 @@ async function runAllSequences(fileContent, variables, cookieJar, workingDir, ap
30543
30604
  void 0,
30544
30605
  caseArgs,
30545
30606
  apiDefinitions,
30546
- tagFilterOptions
30607
+ tagFilterOptions,
30608
+ sequenceSources
30547
30609
  );
30548
30610
  result.name = `${seq.name}${caseLabel}`;
30549
30611
  results.push(result);
@@ -30567,7 +30629,8 @@ async function runAllSequences(fileContent, variables, cookieJar, workingDir, ap
30567
30629
  void 0,
30568
30630
  defaultArgs,
30569
30631
  apiDefinitions,
30570
- tagFilterOptions
30632
+ tagFilterOptions,
30633
+ sequenceSources
30571
30634
  );
30572
30635
  result.name = seq.name;
30573
30636
  results.push(result);
@@ -30742,7 +30805,8 @@ ${fileContent}` : fileContent;
30742
30805
  void 0,
30743
30806
  defaultArgs,
30744
30807
  apiDefinitions,
30745
- tagFilterOptions
30808
+ tagFilterOptions,
30809
+ importResult.sequenceSources
30746
30810
  );
30747
30811
  seqResult.name = targetSeq.name;
30748
30812
  if (options.output === "json") {
@@ -30823,7 +30887,7 @@ ${fileContent}` : fileContent;
30823
30887
  \u2501\u2501\u2501 ${relPath} \u2501\u2501\u2501`));
30824
30888
  }
30825
30889
  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);
30890
+ const seqResults = await runAllSequences(fileContentWithImports, variables, cookieJar, workingDir, apiDefinitions, tagFilterOptions, importResult.sequenceSources);
30827
30891
  for (const result2 of seqResults) {
30828
30892
  result2.sourceFile = filePath;
30829
30893
  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.10",
5
+ "version": "1.3.12",
6
6
  "publisher": "Norn-PeterKrustanov",
7
7
  "author": {
8
8
  "name": "Peter Krastanov"