norn-cli 1.3.8 → 1.3.10

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 +21 -0
  2. package/dist/cli.js +66 -20
  3. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -2,6 +2,27 @@
2
2
 
3
3
  All notable changes to the "Norn" extension will be documented in this file.
4
4
 
5
+ ## [1.3.10] - 2026-02-09
6
+
7
+ ### Fixed
8
+ - **Type Preservation in Property Assignments**: Bare variables now preserve their original type
9
+ - `payload.userId = myNumericVar` keeps the number type instead of converting to string
10
+ - Script outputs that are valid JSON (numbers, booleans, objects) are now properly typed
11
+ - Use `payload.field = "{{var}}"` to force string type when needed
12
+
13
+ ## [1.3.9] - 2026-02-09
14
+
15
+ ### Added
16
+ - **`pwsh` Script Type**: Added `pwsh` as an alias for `powershell` in script commands
17
+ - `var x = run pwsh "./script.ps1"` now works alongside `run powershell`
18
+ - **Bare Variable Support in Property Assignments**: Variables can be assigned without `{{}}` syntax
19
+ - `payload.userId = dynamicUserId` now works (previously required `{{dynamicUserId}}`)
20
+ - **Request Body in Verbose Output**: CLI `-v` flag now shows the actual request body and headers sent
21
+ - Helps debug payload issues by showing exactly what was transmitted
22
+
23
+ ### Fixed
24
+ - **Script Output Capture**: Fixed variable shadowing bug that could affect JSON parsing of script output
25
+
5
26
  ## [1.3.8] - 2026-02-09
6
27
 
7
28
  ### Fixed
package/dist/cli.js CHANGED
@@ -26192,6 +26192,8 @@ async function sendRequestWithJar(request, jar, retryOptions) {
26192
26192
  let currentMethod = request.method;
26193
26193
  let currentBody = request.body;
26194
26194
  let finalResponse = null;
26195
+ let sentRequestBody = void 0;
26196
+ let sentRequestHeaders = {};
26195
26197
  try {
26196
26198
  while (redirectCount <= maxRedirects) {
26197
26199
  const existingCookies = await jar.getCookies(currentUrl);
@@ -26238,6 +26240,8 @@ async function sendRequestWithJar(request, jar, retryOptions) {
26238
26240
  }
26239
26241
  }
26240
26242
  }
26243
+ sentRequestBody = data;
26244
+ sentRequestHeaders = { ...headers };
26241
26245
  const response = await axios_default({
26242
26246
  method: currentMethod,
26243
26247
  url: currentUrl,
@@ -26290,7 +26294,9 @@ async function sendRequestWithJar(request, jar, retryOptions) {
26290
26294
  headers: finalResponse.headers,
26291
26295
  body: finalResponse.data,
26292
26296
  duration: Date.now() - startTime,
26293
- cookies
26297
+ cookies,
26298
+ requestBody: sentRequestBody,
26299
+ requestHeaders: sentRequestHeaders
26294
26300
  };
26295
26301
  if (attemptsMade > 1 || totalAttempts > 1) {
26296
26302
  result.retryInfo = {
@@ -26453,23 +26459,25 @@ function isPwshAvailable() {
26453
26459
  }
26454
26460
  function parseRunCommand(line2) {
26455
26461
  const trimmed = line2.trim();
26456
- const captureMatch = trimmed.match(/^var\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*run\s+(bash|powershell|js)\s+(.+)$/i);
26462
+ const captureMatch = trimmed.match(/^var\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*run\s+(bash|powershell|pwsh|js)\s+(.+)$/i);
26457
26463
  if (captureMatch) {
26458
26464
  const [, varName, type, rest] = captureMatch;
26459
26465
  const { scriptPath, args } = parsePathAndArgs(rest);
26466
+ const normalizedType = type.toLowerCase() === "pwsh" ? "powershell" : type.toLowerCase();
26460
26467
  return {
26461
- type: type.toLowerCase(),
26468
+ type: normalizedType,
26462
26469
  scriptPath,
26463
26470
  args,
26464
26471
  captureAs: varName
26465
26472
  };
26466
26473
  }
26467
- const runMatch = trimmed.match(/^run\s+(bash|powershell|js)\s+(.+)$/i);
26474
+ const runMatch = trimmed.match(/^run\s+(bash|powershell|pwsh|js)\s+(.+)$/i);
26468
26475
  if (runMatch) {
26469
26476
  const [, type, rest] = runMatch;
26470
26477
  const { scriptPath, args } = parsePathAndArgs(rest);
26478
+ const normalizedType = type.toLowerCase() === "pwsh" ? "powershell" : type.toLowerCase();
26471
26479
  return {
26472
- type: type.toLowerCase(),
26480
+ type: normalizedType,
26473
26481
  scriptPath,
26474
26482
  args
26475
26483
  };
@@ -26507,7 +26515,7 @@ function parsePathAndArgs(rest) {
26507
26515
  }
26508
26516
  function isRunCommand(line2) {
26509
26517
  const trimmed = line2.trim();
26510
- return /^(var\s+[a-zA-Z_][a-zA-Z0-9_]*\s*=\s*)?run\s+(bash|powershell|js)\s+/i.test(trimmed);
26518
+ return /^(var\s+[a-zA-Z_][a-zA-Z0-9_]*\s*=\s*)?run\s+(bash|powershell|pwsh|js)\s+/i.test(trimmed);
26511
26519
  }
26512
26520
  async function runScript(type, scriptPath, args, workingDir, variables = {}, captureVar) {
26513
26521
  const startTime = Date.now();
@@ -28021,9 +28029,7 @@ async function runSequenceWithJar(sequenceContent, fileVariables, cookieJar, wor
28021
28029
  continue;
28022
28030
  }
28023
28031
  if (step.type === "propAssign") {
28024
- const bareResolved = resolveBareVariables(step.content, runtimeVariables);
28025
- const substitutedContent = substituteVariables(bareResolved, runtimeVariables);
28026
- const parsed = parsePropertyAssignment(substitutedContent);
28032
+ const parsed = parsePropertyAssignment(step.content);
28027
28033
  if (!parsed) {
28028
28034
  errors.push(`Step ${stepIdx + 1}: Invalid property assignment: ${step.content}`);
28029
28035
  return {
@@ -28066,10 +28072,36 @@ async function runSequenceWithJar(sequenceContent, fileVariables, cookieJar, wor
28066
28072
  duration: Date.now() - startTime
28067
28073
  };
28068
28074
  }
28069
- let newValue = parsed.value;
28070
- try {
28071
- newValue = JSON.parse(parsed.value);
28072
- } catch {
28075
+ const valueTrimmed = parsed.value.trim();
28076
+ const bareVarMatch = valueTrimmed.match(/^([a-zA-Z_][a-zA-Z0-9_]*)((?:\.[a-zA-Z_][a-zA-Z0-9_]*|\[\d+\])*)$/);
28077
+ let newValue;
28078
+ if (bareVarMatch && bareVarMatch[1] in runtimeVariables) {
28079
+ const varName = bareVarMatch[1];
28080
+ const pathPart = bareVarMatch[2] || "";
28081
+ let value = runtimeVariables[varName];
28082
+ if (typeof value === "string") {
28083
+ try {
28084
+ const parsed2 = JSON.parse(value);
28085
+ if (typeof parsed2 === "object" && parsed2 !== null) {
28086
+ value = parsed2;
28087
+ }
28088
+ } catch {
28089
+ }
28090
+ }
28091
+ if (pathPart) {
28092
+ const path5 = pathPart.replace(/^\./, "");
28093
+ newValue = getNestedValueFromObject(value, path5);
28094
+ } else {
28095
+ newValue = value;
28096
+ }
28097
+ } else {
28098
+ const bareResolvedValue = resolveBareVariables(parsed.value, runtimeVariables);
28099
+ const resolvedValue = substituteVariables(bareResolvedValue, runtimeVariables);
28100
+ newValue = resolvedValue;
28101
+ try {
28102
+ newValue = JSON.parse(resolvedValue);
28103
+ } catch {
28104
+ }
28073
28105
  }
28074
28106
  const success = setNestedValue(jsonObj, parsed.propertyPath, newValue);
28075
28107
  if (!success) {
@@ -28305,10 +28337,8 @@ async function runSequenceWithJar(sequenceContent, fileVariables, cookieJar, wor
28305
28337
  if (parsed.captureAs) {
28306
28338
  let outputValue = result.output;
28307
28339
  try {
28308
- const parsed2 = JSON.parse(result.output);
28309
- if (typeof parsed2 === "object" && parsed2 !== null) {
28310
- outputValue = parsed2;
28311
- }
28340
+ const jsonParsed = JSON.parse(result.output);
28341
+ outputValue = jsonParsed;
28312
28342
  } catch {
28313
28343
  }
28314
28344
  runtimeVariables[parsed.captureAs] = outputValue;
@@ -28857,6 +28887,20 @@ async function runSequenceWithJar(sequenceContent, fileVariables, cookieJar, wor
28857
28887
  if (apiDefinitions && apiDefinitions.headerGroups.length > 0) {
28858
28888
  parsed = applyHeaderGroupsToRequest(parsed, step.content, apiDefinitions.headerGroups, runtimeVariables);
28859
28889
  }
28890
+ if (parsed.body) {
28891
+ const bodyTrimmed = parsed.body.trim();
28892
+ const bareVarMatch = bodyTrimmed.match(/^([a-zA-Z_][a-zA-Z0-9_]*)$/);
28893
+ if (bareVarMatch && bareVarMatch[1] in runtimeVariables) {
28894
+ const varValue = runtimeVariables[bareVarMatch[1]];
28895
+ if (typeof varValue === "object" && varValue !== null) {
28896
+ parsed.body = JSON.stringify(varValue);
28897
+ } else if (typeof varValue === "string") {
28898
+ parsed.body = varValue;
28899
+ } else {
28900
+ parsed.body = String(varValue);
28901
+ }
28902
+ }
28903
+ }
28860
28904
  }
28861
28905
  const { retryCount, backoffMs } = extractRetryOptions(step.content);
28862
28906
  const retryOpts = retryCount ?? parsed.retryCount ? {
@@ -29375,11 +29419,13 @@ function formatRequestStep(step, options) {
29375
29419
  colors,
29376
29420
  redaction,
29377
29421
  verbose,
29378
- showDetails: !isSuccess,
29379
- // Show request details on failure
29422
+ showDetails: !isSuccess || verbose,
29423
+ // Show request details on failure or verbose
29380
29424
  index: requestIndex,
29381
29425
  method: step.requestMethod,
29382
- url: step.requestUrl
29426
+ url: step.requestUrl,
29427
+ requestBody: step.response.requestBody,
29428
+ requestHeaders: step.response.requestHeaders
29383
29429
  });
29384
29430
  }
29385
29431
  function formatAssertionStep(step, options) {
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.8",
5
+ "version": "1.3.10",
6
6
  "publisher": "Norn-PeterKrustanov",
7
7
  "author": {
8
8
  "name": "Peter Krastanov"