norn-cli 1.6.2 → 1.7.0
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 +18 -0
- package/dist/cli.js +135 -37
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,24 @@ All notable changes to the "Norn" extension will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [1.7.0] - 2026-03-07
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
- **Explicit Environment Lookup (Extension + CLI)**:
|
|
11
|
+
- Added `{{$env.name}}` so tests, sequences, endpoints, header groups, and interpolated strings can read directly from the active environment even when a file variable, local variable, or sequence parameter uses the same name.
|
|
12
|
+
- Added IntelliSense for the `$env` namespace and environment variable suggestions after typing `{{$env.`.
|
|
13
|
+
- Added diagnostics for invalid `{{$env...}}` references and warnings when local/file/parameter variables shadow environment variables.
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
- **Assertion String Literal Escaping**:
|
|
17
|
+
- Fixed escaped quotes in assertion string literals and quoted `var` expressions so values like `\"{orderId}\"` compare correctly instead of failing with visually identical expected/actual output.
|
|
18
|
+
|
|
19
|
+
- **Parameterized Test Snippet UX**:
|
|
20
|
+
- Updated `@data` completion to insert `data()` with the cursor inside the parentheses instead of placeholder values.
|
|
21
|
+
|
|
22
|
+
- **Decorator Syntax Highlighting**:
|
|
23
|
+
- Fixed `.norn` syntax coloring so decorator lines such as `@data(...)` keep their highlighting when they follow request blocks like `DELETE ...`.
|
|
24
|
+
|
|
7
25
|
## [1.6.2] - 2026-03-07
|
|
8
26
|
|
|
9
27
|
### Fixed
|
package/dist/cli.js
CHANGED
|
@@ -18783,6 +18783,39 @@ var init_schemaGenerator = __esm({
|
|
|
18783
18783
|
}
|
|
18784
18784
|
});
|
|
18785
18785
|
|
|
18786
|
+
// src/quotedString.ts
|
|
18787
|
+
function decodeQuotedStringLiteral(literal) {
|
|
18788
|
+
if (literal.length < 2) {
|
|
18789
|
+
return literal;
|
|
18790
|
+
}
|
|
18791
|
+
const quoteChar = literal[0];
|
|
18792
|
+
if (quoteChar !== '"' && quoteChar !== "'" || literal[literal.length - 1] !== quoteChar) {
|
|
18793
|
+
return literal;
|
|
18794
|
+
}
|
|
18795
|
+
const inner = literal.slice(1, -1);
|
|
18796
|
+
let decoded = "";
|
|
18797
|
+
for (let i = 0; i < inner.length; i++) {
|
|
18798
|
+
const char = inner[i];
|
|
18799
|
+
if (char !== "\\" || i === inner.length - 1) {
|
|
18800
|
+
decoded += char;
|
|
18801
|
+
continue;
|
|
18802
|
+
}
|
|
18803
|
+
const nextChar = inner[i + 1];
|
|
18804
|
+
if (nextChar === "\\" || nextChar === quoteChar) {
|
|
18805
|
+
decoded += nextChar;
|
|
18806
|
+
i++;
|
|
18807
|
+
continue;
|
|
18808
|
+
}
|
|
18809
|
+
decoded += char;
|
|
18810
|
+
}
|
|
18811
|
+
return decoded;
|
|
18812
|
+
}
|
|
18813
|
+
var init_quotedString = __esm({
|
|
18814
|
+
"src/quotedString.ts"() {
|
|
18815
|
+
"use strict";
|
|
18816
|
+
}
|
|
18817
|
+
});
|
|
18818
|
+
|
|
18786
18819
|
// src/assertionRunner.ts
|
|
18787
18820
|
var assertionRunner_exports = {};
|
|
18788
18821
|
__export(assertionRunner_exports, {
|
|
@@ -18806,7 +18839,7 @@ function parseAssertCommand(line2) {
|
|
|
18806
18839
|
if (pipeIndex !== -1) {
|
|
18807
18840
|
message = content.substring(pipeIndex + 1).trim();
|
|
18808
18841
|
if (message.startsWith('"') && message.endsWith('"') || message.startsWith("'") && message.endsWith("'")) {
|
|
18809
|
-
message = message
|
|
18842
|
+
message = decodeQuotedStringLiteral(message);
|
|
18810
18843
|
}
|
|
18811
18844
|
content = content.substring(0, pipeIndex).trim();
|
|
18812
18845
|
}
|
|
@@ -18848,8 +18881,17 @@ function parseAssertCommand(line2) {
|
|
|
18848
18881
|
function findUnquotedPipe(str) {
|
|
18849
18882
|
let inQuote = false;
|
|
18850
18883
|
let quoteChar = "";
|
|
18884
|
+
let escapeNext = false;
|
|
18851
18885
|
for (let i = 0; i < str.length; i++) {
|
|
18852
18886
|
const char = str[i];
|
|
18887
|
+
if (escapeNext) {
|
|
18888
|
+
escapeNext = false;
|
|
18889
|
+
continue;
|
|
18890
|
+
}
|
|
18891
|
+
if (inQuote && char === "\\") {
|
|
18892
|
+
escapeNext = true;
|
|
18893
|
+
continue;
|
|
18894
|
+
}
|
|
18853
18895
|
if ((char === '"' || char === "'") && !inQuote) {
|
|
18854
18896
|
inQuote = true;
|
|
18855
18897
|
quoteChar = char;
|
|
@@ -18934,11 +18976,28 @@ function resolveValue(expr, responses, variables, getValueByPath2, responseIndex
|
|
|
18934
18976
|
}
|
|
18935
18977
|
}
|
|
18936
18978
|
}
|
|
18937
|
-
const varMatch = trimmed.match(/^\{\{([a-zA-Z_][a-zA-Z0-9_]*)\}\}$/);
|
|
18979
|
+
const varMatch = trimmed.match(/^\{\{(\$env|[a-zA-Z_][a-zA-Z0-9_]*)((?:\.[a-zA-Z_][a-zA-Z0-9_]*|\[\d+\])*)\}\}$/);
|
|
18938
18980
|
if (varMatch) {
|
|
18939
18981
|
const varName = varMatch[1];
|
|
18982
|
+
const pathPart = varMatch[2] || "";
|
|
18940
18983
|
if (varName in variables) {
|
|
18941
18984
|
const varValue = variables[varName];
|
|
18985
|
+
if (pathPart) {
|
|
18986
|
+
if (typeof varValue === "object" && varValue !== null) {
|
|
18987
|
+
const path10 = pathPart.replace(/^\./, "");
|
|
18988
|
+
return { value: getNestedValue2(varValue, path10) };
|
|
18989
|
+
}
|
|
18990
|
+
if (typeof varValue === "string") {
|
|
18991
|
+
try {
|
|
18992
|
+
const parsed = JSON.parse(varValue);
|
|
18993
|
+
const path10 = pathPart.replace(/^\./, "");
|
|
18994
|
+
return { value: getNestedValue2(parsed, path10) };
|
|
18995
|
+
} catch {
|
|
18996
|
+
return { value: void 0, error: `Cannot access path on non-object variable: ${varName}` };
|
|
18997
|
+
}
|
|
18998
|
+
}
|
|
18999
|
+
return { value: void 0, error: `Cannot access path on non-object variable: ${varName}` };
|
|
19000
|
+
}
|
|
18942
19001
|
if (typeof varValue === "string" && /^-?\d+(\.\d+)?$/.test(varValue)) {
|
|
18943
19002
|
return { value: parseFloat(varValue) };
|
|
18944
19003
|
}
|
|
@@ -18947,7 +19006,7 @@ function resolveValue(expr, responses, variables, getValueByPath2, responseIndex
|
|
|
18947
19006
|
return { value: void 0, error: `Variable {{${varName}}} is not defined` };
|
|
18948
19007
|
}
|
|
18949
19008
|
if (trimmed.startsWith('"') && trimmed.endsWith('"') || trimmed.startsWith("'") && trimmed.endsWith("'")) {
|
|
18950
|
-
return { value: trimmed
|
|
19009
|
+
return { value: decodeQuotedStringLiteral(trimmed) };
|
|
18951
19010
|
}
|
|
18952
19011
|
if (/^-?\d+(\.\d+)?$/.test(trimmed)) {
|
|
18953
19012
|
return { value: parseFloat(trimmed) };
|
|
@@ -19227,6 +19286,7 @@ var init_assertionRunner = __esm({
|
|
|
19227
19286
|
"src/assertionRunner.ts"() {
|
|
19228
19287
|
"use strict";
|
|
19229
19288
|
init_schemaGenerator();
|
|
19289
|
+
init_quotedString();
|
|
19230
19290
|
}
|
|
19231
19291
|
});
|
|
19232
19292
|
|
|
@@ -19850,9 +19910,7 @@ function getEndpoint(definition, name) {
|
|
|
19850
19910
|
function resolveHeaderValues(headerGroup, variables) {
|
|
19851
19911
|
const resolved = {};
|
|
19852
19912
|
for (const [name, value] of Object.entries(headerGroup.headers)) {
|
|
19853
|
-
resolved[name] = value
|
|
19854
|
-
return variables[varName] ?? `{{${varName}}}`;
|
|
19855
|
-
});
|
|
19913
|
+
resolved[name] = substituteVariables(value, variables);
|
|
19856
19914
|
}
|
|
19857
19915
|
return resolved;
|
|
19858
19916
|
}
|
|
@@ -20149,9 +20207,29 @@ function valueToString(value) {
|
|
|
20149
20207
|
}
|
|
20150
20208
|
return String(value);
|
|
20151
20209
|
}
|
|
20210
|
+
var ENV_SCOPE_KEY = "$env";
|
|
20211
|
+
function attachEnvironmentScope(variables, envVariables) {
|
|
20212
|
+
if (!envVariables) {
|
|
20213
|
+
return variables;
|
|
20214
|
+
}
|
|
20215
|
+
Object.defineProperty(variables, ENV_SCOPE_KEY, {
|
|
20216
|
+
value: envVariables,
|
|
20217
|
+
enumerable: false,
|
|
20218
|
+
configurable: true,
|
|
20219
|
+
writable: false
|
|
20220
|
+
});
|
|
20221
|
+
return variables;
|
|
20222
|
+
}
|
|
20223
|
+
function copyEnvironmentScope(target, source) {
|
|
20224
|
+
const envScope = source[ENV_SCOPE_KEY];
|
|
20225
|
+
if (envScope && typeof envScope === "object") {
|
|
20226
|
+
attachEnvironmentScope(target, envScope);
|
|
20227
|
+
}
|
|
20228
|
+
return target;
|
|
20229
|
+
}
|
|
20152
20230
|
function substituteVariables(text, variables) {
|
|
20153
20231
|
return text.replace(
|
|
20154
|
-
/\{\{(
|
|
20232
|
+
/\{\{(\$env|\$\d+|[a-zA-Z_][a-zA-Z0-9_]*)((?:\.[a-zA-Z_][a-zA-Z0-9_-]*|\[\d+\])*)\}\}/g,
|
|
20155
20233
|
(match, varName, pathPart) => {
|
|
20156
20234
|
if (!(varName in variables)) {
|
|
20157
20235
|
return match;
|
|
@@ -20161,8 +20239,14 @@ function substituteVariables(text, variables) {
|
|
|
20161
20239
|
if (pathPart) {
|
|
20162
20240
|
const path10 = pathPart.replace(/^\./, "");
|
|
20163
20241
|
const nestedValue = getNestedValue(value, path10);
|
|
20242
|
+
if (nestedValue === void 0 && varName === ENV_SCOPE_KEY) {
|
|
20243
|
+
return match;
|
|
20244
|
+
}
|
|
20164
20245
|
return valueToString(nestedValue);
|
|
20165
20246
|
}
|
|
20247
|
+
if (varName === ENV_SCOPE_KEY) {
|
|
20248
|
+
return match;
|
|
20249
|
+
}
|
|
20166
20250
|
return valueToString(value);
|
|
20167
20251
|
}
|
|
20168
20252
|
if (pathPart && typeof value === "string") {
|
|
@@ -20170,8 +20254,14 @@ function substituteVariables(text, variables) {
|
|
|
20170
20254
|
const parsed = JSON.parse(value);
|
|
20171
20255
|
const path10 = pathPart.replace(/^\./, "");
|
|
20172
20256
|
const nestedValue = getNestedValue(parsed, path10);
|
|
20257
|
+
if (nestedValue === void 0 && varName === ENV_SCOPE_KEY) {
|
|
20258
|
+
return match;
|
|
20259
|
+
}
|
|
20173
20260
|
return valueToString(nestedValue);
|
|
20174
20261
|
} catch {
|
|
20262
|
+
if (varName === ENV_SCOPE_KEY) {
|
|
20263
|
+
return match;
|
|
20264
|
+
}
|
|
20175
20265
|
return value;
|
|
20176
20266
|
}
|
|
20177
20267
|
}
|
|
@@ -26940,7 +27030,7 @@ function formatUserFacingError(error, context) {
|
|
|
26940
27030
|
}
|
|
26941
27031
|
|
|
26942
27032
|
// src/requestValidation.ts
|
|
26943
|
-
var PLACEHOLDER_REGEX = /\{\{([a-zA-Z_][a-zA-Z0-9_]*)\}\}/g;
|
|
27033
|
+
var PLACEHOLDER_REGEX = /\{\{(\$env|\$[0-9]+|[a-zA-Z_][a-zA-Z0-9_]*)((?:\.[a-zA-Z_][a-zA-Z0-9_-]*|\[\d+\])*)\}\}/g;
|
|
26944
27034
|
function collectUnresolvedPlaceholders(text) {
|
|
26945
27035
|
if (!text) {
|
|
26946
27036
|
return [];
|
|
@@ -26949,15 +27039,23 @@ function collectUnresolvedPlaceholders(text) {
|
|
|
26949
27039
|
let match;
|
|
26950
27040
|
PLACEHOLDER_REGEX.lastIndex = 0;
|
|
26951
27041
|
while ((match = PLACEHOLDER_REGEX.exec(text)) !== null) {
|
|
26952
|
-
names.add(match[
|
|
27042
|
+
names.add(match[0]);
|
|
26953
27043
|
}
|
|
26954
27044
|
return [...names];
|
|
26955
27045
|
}
|
|
27046
|
+
function extractEnvScopedNames(placeholders) {
|
|
27047
|
+
return placeholders.filter((value) => value.startsWith("{{$env.")).map((value) => value.slice("{{$env.".length, -2).split(/[.[\]]/)[0]).filter(Boolean);
|
|
27048
|
+
}
|
|
26956
27049
|
function buildMissingVariableHint(missingVars, context) {
|
|
26957
27050
|
const env3 = context?.environment;
|
|
27051
|
+
const envScopedNames = extractEnvScopedNames(missingVars);
|
|
27052
|
+
const unscopedVars = missingVars.filter((value) => !value.startsWith("{{$env."));
|
|
26958
27053
|
if (env3?.hasEnvFile && env3.availableEnvironments && env3.availableEnvironments.length > 0 && !env3.activeEnvironment) {
|
|
26959
27054
|
return `A .nornenv file was found but no environment is selected. Select one of: ${env3.availableEnvironments.join(", ")}.`;
|
|
26960
27055
|
}
|
|
27056
|
+
if (env3?.hasEnvFile && env3.activeEnvironment && envScopedNames.length > 0 && unscopedVars.length === 0) {
|
|
27057
|
+
return `Check that ${envScopedNames.map((v) => `'${v}'`).join(", ")} exist in the active environment '${env3.activeEnvironment}'.`;
|
|
27058
|
+
}
|
|
26961
27059
|
if (env3?.hasEnvFile && env3.activeEnvironment) {
|
|
26962
27060
|
return `Check that ${missingVars.map((v) => `'${v}'`).join(", ")} exist in the active environment '${env3.activeEnvironment}' or as file-level variables.`;
|
|
26963
27061
|
}
|
|
@@ -26975,7 +27073,7 @@ function describeUnresolvedLocation(label, vars) {
|
|
|
26975
27073
|
if (vars.length === 0) {
|
|
26976
27074
|
return void 0;
|
|
26977
27075
|
}
|
|
26978
|
-
return `${label}: unresolved ${vars.length === 1 ? "variable" : "variables"} ${vars.
|
|
27076
|
+
return `${label}: unresolved ${vars.length === 1 ? "variable" : "variables"} ${vars.join(", ")}`;
|
|
26979
27077
|
}
|
|
26980
27078
|
function shouldValidateBodyPlaceholders(parsed) {
|
|
26981
27079
|
const method = String(parsed.method || "").toUpperCase();
|
|
@@ -26995,7 +27093,7 @@ function validatePreparedRequest(parsed, context) {
|
|
|
26995
27093
|
throw new NornError({
|
|
26996
27094
|
category: "variable-resolution",
|
|
26997
27095
|
code: "unresolved-request-variables",
|
|
26998
|
-
message: `Request could not be prepared: unresolved ${missingVars.length === 1 ? "variable" : "variables"} ${missingVars.
|
|
27096
|
+
message: `Request could not be prepared: unresolved ${missingVars.length === 1 ? "variable" : "variables"} ${missingVars.join(", ")}.`,
|
|
26999
27097
|
details,
|
|
27000
27098
|
hint: buildMissingVariableHint(missingVars, context),
|
|
27001
27099
|
context: {
|
|
@@ -27029,6 +27127,7 @@ function validatePreparedRequest(parsed, context) {
|
|
|
27029
27127
|
}
|
|
27030
27128
|
|
|
27031
27129
|
// src/sequenceRunner.ts
|
|
27130
|
+
init_quotedString();
|
|
27032
27131
|
init_assertionRunner();
|
|
27033
27132
|
function applyHeaderGroupsToRequest(parsed, requestText, headerGroups, variables) {
|
|
27034
27133
|
const lines = requestText.split("\n");
|
|
@@ -27191,7 +27290,7 @@ function parseRunArguments(argsStr) {
|
|
|
27191
27290
|
if (namedMatch) {
|
|
27192
27291
|
let value = namedMatch[2].trim();
|
|
27193
27292
|
if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
|
|
27194
|
-
value = value
|
|
27293
|
+
value = decodeQuotedStringLiteral(value);
|
|
27195
27294
|
}
|
|
27196
27295
|
args.push({
|
|
27197
27296
|
name: namedMatch[1],
|
|
@@ -27200,7 +27299,7 @@ function parseRunArguments(argsStr) {
|
|
|
27200
27299
|
} else {
|
|
27201
27300
|
let value = trimmed;
|
|
27202
27301
|
if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
|
|
27203
|
-
value = value
|
|
27302
|
+
value = decodeQuotedStringLiteral(value);
|
|
27204
27303
|
}
|
|
27205
27304
|
args.push({ value });
|
|
27206
27305
|
}
|
|
@@ -27371,7 +27470,7 @@ function parseSequenceParameters(line2) {
|
|
|
27371
27470
|
hasSeenDefault = true;
|
|
27372
27471
|
let defaultValue = defaultMatch[2].trim();
|
|
27373
27472
|
if (defaultValue.startsWith('"') && defaultValue.endsWith('"') || defaultValue.startsWith("'") && defaultValue.endsWith("'")) {
|
|
27374
|
-
defaultValue = defaultValue
|
|
27473
|
+
defaultValue = decodeQuotedStringLiteral(defaultValue);
|
|
27375
27474
|
}
|
|
27376
27475
|
params.push({
|
|
27377
27476
|
name: defaultMatch[1],
|
|
@@ -27498,7 +27597,7 @@ function parseTypedValue(value) {
|
|
|
27498
27597
|
return parseFloat(value);
|
|
27499
27598
|
}
|
|
27500
27599
|
if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
|
|
27501
|
-
return value
|
|
27600
|
+
return decodeQuotedStringLiteral(value);
|
|
27502
27601
|
}
|
|
27503
27602
|
return value;
|
|
27504
27603
|
}
|
|
@@ -27624,7 +27723,7 @@ function parseVarAssignCommand(line2) {
|
|
|
27624
27723
|
function evaluateValueExpression(expr, runtimeVariables) {
|
|
27625
27724
|
const trimmed = expr.trim();
|
|
27626
27725
|
if (trimmed.startsWith('"') && trimmed.endsWith('"') || trimmed.startsWith("'") && trimmed.endsWith("'")) {
|
|
27627
|
-
const inner = trimmed
|
|
27726
|
+
const inner = decodeQuotedStringLiteral(trimmed);
|
|
27628
27727
|
const substituted = substituteVariables(inner, runtimeVariables);
|
|
27629
27728
|
return { value: substituted };
|
|
27630
27729
|
}
|
|
@@ -27749,7 +27848,7 @@ function resolveBareVariables(text, variables) {
|
|
|
27749
27848
|
const resolvedParts = parts.map((part) => {
|
|
27750
27849
|
const partTrimmed = part.trim();
|
|
27751
27850
|
if (partTrimmed.startsWith('"') && partTrimmed.endsWith('"') || partTrimmed.startsWith("'") && partTrimmed.endsWith("'")) {
|
|
27752
|
-
return partTrimmed
|
|
27851
|
+
return decodeQuotedStringLiteral(partTrimmed);
|
|
27753
27852
|
}
|
|
27754
27853
|
const varMatch = partTrimmed.match(/^([a-zA-Z_][a-zA-Z0-9_]*)((?:\.[a-zA-Z_][a-zA-Z0-9_]*|\[\d+\])*)$/);
|
|
27755
27854
|
if (varMatch) {
|
|
@@ -27775,8 +27874,19 @@ function splitExpressionParts(expr) {
|
|
|
27775
27874
|
let current = "";
|
|
27776
27875
|
let inString = false;
|
|
27777
27876
|
let stringChar = "";
|
|
27877
|
+
let escapeNext = false;
|
|
27778
27878
|
for (let i = 0; i < expr.length; i++) {
|
|
27779
27879
|
const char = expr[i];
|
|
27880
|
+
if (escapeNext) {
|
|
27881
|
+
current += char;
|
|
27882
|
+
escapeNext = false;
|
|
27883
|
+
continue;
|
|
27884
|
+
}
|
|
27885
|
+
if (inString && char === "\\") {
|
|
27886
|
+
current += char;
|
|
27887
|
+
escapeNext = true;
|
|
27888
|
+
continue;
|
|
27889
|
+
}
|
|
27780
27890
|
if (!inString && (char === '"' || char === "'")) {
|
|
27781
27891
|
inString = true;
|
|
27782
27892
|
stringChar = char;
|
|
@@ -28232,7 +28342,7 @@ async function runSequenceWithJar(sequenceContent, fileVariables, cookieJar, wor
|
|
|
28232
28342
|
});
|
|
28233
28343
|
}
|
|
28234
28344
|
};
|
|
28235
|
-
const runtimeVariables = { ...fileVariables, ...sequenceArgs };
|
|
28345
|
+
const runtimeVariables = copyEnvironmentScope({ ...fileVariables, ...sequenceArgs }, fileVariables);
|
|
28236
28346
|
const buildRequestValidationContext = (stepNumber, method, url2, requestName) => ({
|
|
28237
28347
|
source: "sequence",
|
|
28238
28348
|
filePath: executionContext?.filePath,
|
|
@@ -28994,19 +29104,13 @@ ${indentMultiline(userMessage)}`;
|
|
|
28994
29104
|
apiRequest.endpointName
|
|
28995
29105
|
);
|
|
28996
29106
|
if (endpoint) {
|
|
28997
|
-
let resolvedPath = endpoint.path;
|
|
28998
|
-
resolvedPath = resolvedPath.replace(/\{\{([a-zA-Z_][a-zA-Z0-9_]*)\}\}/g, (_, varName) => {
|
|
28999
|
-
return runtimeVariables[varName] !== void 0 ? String(runtimeVariables[varName]) : `{{${varName}}}`;
|
|
29000
|
-
});
|
|
29107
|
+
let resolvedPath = substituteVariables(endpoint.path, runtimeVariables);
|
|
29001
29108
|
for (const [paramName, paramValue] of Object.entries(apiRequest.params)) {
|
|
29002
29109
|
let resolvedValue = paramValue;
|
|
29003
29110
|
if (runtimeVariables[paramValue] !== void 0) {
|
|
29004
29111
|
resolvedValue = String(runtimeVariables[paramValue]);
|
|
29005
|
-
} else
|
|
29006
|
-
|
|
29007
|
-
if (runtimeVariables[varName] !== void 0) {
|
|
29008
|
-
resolvedValue = String(runtimeVariables[varName]);
|
|
29009
|
-
}
|
|
29112
|
+
} else {
|
|
29113
|
+
resolvedValue = substituteVariables(paramValue, runtimeVariables);
|
|
29010
29114
|
}
|
|
29011
29115
|
resolvedPath = resolvedPath.replace(`{${paramName}}`, resolvedValue);
|
|
29012
29116
|
}
|
|
@@ -29019,10 +29123,7 @@ ${indentMultiline(userMessage)}`;
|
|
|
29019
29123
|
}
|
|
29020
29124
|
}
|
|
29021
29125
|
for (const [headerName, headerValue] of Object.entries(apiRequest.inlineHeaders)) {
|
|
29022
|
-
|
|
29023
|
-
resolved = resolved.replace(/\{\{([a-zA-Z_][a-zA-Z0-9_]*)\}\}/g, (_, varName) => {
|
|
29024
|
-
return runtimeVariables[varName] !== void 0 ? String(runtimeVariables[varName]) : `{{${varName}}}`;
|
|
29025
|
-
});
|
|
29126
|
+
const resolved = substituteVariables(headerValue, runtimeVariables);
|
|
29026
29127
|
combinedHeaders[headerName] = resolved;
|
|
29027
29128
|
}
|
|
29028
29129
|
const bodyParsed = parserHttpRequest(namedRequest.content, runtimeVariables);
|
|
@@ -32114,10 +32215,7 @@ async function runSingleRequest(fileContent, variables, cookieJar, apiDefinition
|
|
|
32114
32215
|
}
|
|
32115
32216
|
}
|
|
32116
32217
|
for (const [headerName, headerValue] of Object.entries(apiRequest.inlineHeaders)) {
|
|
32117
|
-
|
|
32118
|
-
resolved = resolved.replace(/\{\{([a-zA-Z_][a-zA-Z0-9_]*)\}\}/g, (_, varName) => {
|
|
32119
|
-
return variables[varName] !== void 0 ? String(variables[varName]) : `{{${varName}}}`;
|
|
32120
|
-
});
|
|
32218
|
+
const resolved = substituteVariables(headerValue, variables);
|
|
32121
32219
|
combinedHeaders[headerName] = resolved;
|
|
32122
32220
|
}
|
|
32123
32221
|
const parsed2 = {
|
|
@@ -32408,7 +32506,7 @@ async function main() {
|
|
|
32408
32506
|
const redaction2 = createRedactionOptions(combinedSecretNames, combinedSecretValues, !options.noRedact);
|
|
32409
32507
|
const fileContent = fs10.readFileSync(filePath, "utf-8");
|
|
32410
32508
|
const fileVariables = extractFileLevelVariables(fileContent);
|
|
32411
|
-
const variables = { ...resolvedEnv.variables, ...fileVariables };
|
|
32509
|
+
const variables = attachEnvironmentScope({ ...resolvedEnv.variables, ...fileVariables }, resolvedEnv.variables);
|
|
32412
32510
|
const cookieJar = createCookieJar();
|
|
32413
32511
|
const workingDir = path9.dirname(filePath);
|
|
32414
32512
|
const importResult = await resolveImports(
|
|
@@ -32624,7 +32722,7 @@ ${fileContent}` : fileContent;
|
|
|
32624
32722
|
const redaction2 = createRedactionOptions(combinedSecretNames, combinedSecretValues, !options.noRedact);
|
|
32625
32723
|
const fileContent = fs10.readFileSync(filePath, "utf-8");
|
|
32626
32724
|
const fileVariables = extractFileLevelVariables(fileContent);
|
|
32627
|
-
const variables = { ...resolvedEnv.variables, ...fileVariables };
|
|
32725
|
+
const variables = attachEnvironmentScope({ ...resolvedEnv.variables, ...fileVariables }, resolvedEnv.variables);
|
|
32628
32726
|
const cookieJar = createCookieJar();
|
|
32629
32727
|
const workingDir = path9.dirname(filePath);
|
|
32630
32728
|
const importResult = await resolveImports(
|
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.
|
|
5
|
+
"version": "1.7.0",
|
|
6
6
|
"publisher": "Norn-PeterKrustanov",
|
|
7
7
|
"author": {
|
|
8
8
|
"name": "Peter Krastanov"
|