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.
- package/CHANGELOG.md +21 -0
- package/dist/cli.js +66 -20
- 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:
|
|
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:
|
|
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
|
|
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
|
-
|
|
28070
|
-
|
|
28071
|
-
|
|
28072
|
-
|
|
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
|
|
28309
|
-
|
|
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.
|
|
5
|
+
"version": "1.3.10",
|
|
6
6
|
"publisher": "Norn-PeterKrustanov",
|
|
7
7
|
"author": {
|
|
8
8
|
"name": "Peter Krastanov"
|