norn-cli 1.3.17 → 1.3.18
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/AGENTS.md +72 -0
- package/CHANGELOG.md +21 -1
- package/README.md +4 -2
- package/dist/cli.js +113 -54
- package/out/assertionRunner.js +537 -0
- package/out/cli/colors.js +129 -0
- package/out/cli/formatters/assertion.js +75 -0
- package/out/cli/formatters/index.js +23 -0
- package/out/cli/formatters/response.js +106 -0
- package/out/cli/formatters/summary.js +187 -0
- package/out/cli/redaction.js +237 -0
- package/out/cli/reporters/html.js +634 -0
- package/out/cli/reporters/index.js +22 -0
- package/out/cli/reporters/junit.js +211 -0
- package/out/cli.js +926 -0
- package/out/codeLensProvider.js +254 -0
- package/out/compareContentProvider.js +85 -0
- package/out/completionProvider.js +1886 -0
- package/out/contractDecorationProvider.js +243 -0
- package/out/coverageCalculator.js +756 -0
- package/out/coveragePanel.js +542 -0
- package/out/diagnosticProvider.js +980 -0
- package/out/environmentProvider.js +373 -0
- package/out/extension.js +1025 -0
- package/out/httpClient.js +269 -0
- package/out/jsonFileReader.js +320 -0
- package/out/nornapiParser.js +326 -0
- package/out/parser.js +725 -0
- package/out/responsePanel.js +4674 -0
- package/out/schemaGenerator.js +393 -0
- package/out/scriptRunner.js +419 -0
- package/out/sequenceRunner.js +3046 -0
- package/out/swaggerParser.js +339 -0
- package/out/test/extension.test.js +48 -0
- package/out/testProvider.js +658 -0
- package/out/validationCache.js +245 -0
- package/package.json +1 -1
package/AGENTS.md
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# Norn Extension - Copilot Instructions
|
|
2
|
+
|
|
3
|
+
These instructions apply to all conversations about the Norn VS Code extension.
|
|
4
|
+
|
|
5
|
+
## CLI Support is Mandatory
|
|
6
|
+
|
|
7
|
+
Every feature implementation must work in both:
|
|
8
|
+
1. **VS Code Extension** - Interactive UI with response panel
|
|
9
|
+
2. **CLI** (`src/cli.ts`) - Command-line execution
|
|
10
|
+
|
|
11
|
+
Before considering any feature complete, verify it works in the CLI. The CLI shares code with the extension (`parser.ts`, `sequenceRunner.ts`, `assertionRunner.ts`, `httpClient.ts`).
|
|
12
|
+
|
|
13
|
+
### CRITICAL: Running the Local CLI
|
|
14
|
+
|
|
15
|
+
**NEVER use `npx norn`** - this runs the globally installed npm package, NOT your local changes!
|
|
16
|
+
|
|
17
|
+
**ALWAYS use the local compiled CLI:**
|
|
18
|
+
```bash
|
|
19
|
+
# Correct - runs your local development version
|
|
20
|
+
node ./dist/cli.js run tests/file.norn --env prelive
|
|
21
|
+
|
|
22
|
+
# WRONG - runs the published npm package, ignores your changes
|
|
23
|
+
npx norn run tests/file.norn
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Before testing CLI changes:
|
|
27
|
+
1. Run `npm run compile` to build the latest code
|
|
28
|
+
2. Use `node ./dist/cli.js` to execute
|
|
29
|
+
|
|
30
|
+
## Skills Maintenance
|
|
31
|
+
|
|
32
|
+
When implementing features, check the `.github/skills/` directory for relevant skills:
|
|
33
|
+
|
|
34
|
+
- **If a skill is incorrect or outdated:** Update it with the correct information
|
|
35
|
+
- **If a skill is missing:** Create a new one following the Agent Skills format
|
|
36
|
+
|
|
37
|
+
Skills should capture lessons learned and patterns discovered during implementation to help future development.
|
|
38
|
+
|
|
39
|
+
## Code Style
|
|
40
|
+
|
|
41
|
+
- TypeScript with strict typing
|
|
42
|
+
- Simple IntelliSense completions (no complex snippets)
|
|
43
|
+
- Keep parsing logic in dedicated functions
|
|
44
|
+
- Test both extension and CLI after changes
|
|
45
|
+
|
|
46
|
+
## Test Verification
|
|
47
|
+
|
|
48
|
+
**MANDATORY:** When the user asks to publish, prepare a release, bump version, or create a patch:
|
|
49
|
+
1. **FIRST** invoke the Test Verification subagent using `runSubagent`
|
|
50
|
+
2. Wait for it to complete and report results
|
|
51
|
+
3. Only proceed if all tests pass
|
|
52
|
+
|
|
53
|
+
The Test Verification agent runs:
|
|
54
|
+
- `npm run compile` (must have 0 errors)
|
|
55
|
+
- `node ./dist/cli.js ./tests/Regression/ -e prelive` (all tests must pass)
|
|
56
|
+
|
|
57
|
+
**Trigger words:** publish, release, version, patch, bump, deploy
|
|
58
|
+
|
|
59
|
+
## Key Files
|
|
60
|
+
|
|
61
|
+
| Purpose | File |
|
|
62
|
+
|---------|------|
|
|
63
|
+
| Syntax highlighting | `syntaxes/norn.tmLanguage.json` |
|
|
64
|
+
| IntelliSense | `src/completionProvider.ts` |
|
|
65
|
+
| Sequence execution | `src/sequenceRunner.ts` |
|
|
66
|
+
| Assertions | `src/assertionRunner.ts` |
|
|
67
|
+
| HTTP requests | `src/httpClient.ts` |
|
|
68
|
+
| CLI | `src/cli.ts` |
|
|
69
|
+
| Parser | `src/parser.ts` |
|
|
70
|
+
| Response panel | `src/responsePanel.ts` |
|
|
71
|
+
| Diagnostics | `src/diagnosticProvider.ts` |
|
|
72
|
+
| Test Explorer | `src/testProvider.ts` |
|
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,26 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to the "Norn" extension will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [1.3.18] - 2026-02-15
|
|
6
|
+
|
|
7
|
+
### Improved
|
|
8
|
+
- **Environment Resolution (Extension + CLI)**: `.nornenv` resolution is now file-aware and uses the closest ancestor file.
|
|
9
|
+
- VS Code execution paths now resolve env variables from the current document path.
|
|
10
|
+
- CLI directory runs now resolve environments per test file path (including nested folders).
|
|
11
|
+
- CodeLens and environment status now reflect the active editor/file context.
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
- **IntelliSense in Request Bodies**:
|
|
15
|
+
- Header completions are suppressed when starting JSON body lines (`{` or `[`).
|
|
16
|
+
- Header suggestions remain available for non-body lines, including raw URL requests (e.g., `POST "https://..."`).
|
|
17
|
+
- **Syntax Highlighting**:
|
|
18
|
+
- Fixed header coloring after endpoint calls where header-group token matching could break on `Content-Type`.
|
|
19
|
+
- Improved assert string highlighting with variable interpolation inside quoted strings.
|
|
20
|
+
|
|
21
|
+
### Added
|
|
22
|
+
- **Regression Coverage**:
|
|
23
|
+
- Added env-resolution regression tests for parent vs nested `.nornenv` precedence.
|
|
24
|
+
|
|
5
25
|
## [1.3.17] - 2026-02-14
|
|
6
26
|
|
|
7
27
|
### Fixed
|
|
@@ -856,4 +876,4 @@ end sequence
|
|
|
856
876
|
- **IntelliSense**: Autocomplete for methods, headers, variables, and keywords
|
|
857
877
|
- **Diagnostics**: Error highlighting for undefined variables
|
|
858
878
|
- **CLI Tool**: Run requests from terminal with JSON output for CI/CD pipelines
|
|
859
|
-
- **Response Panel**: Webview with formatted JSON and execution results
|
|
879
|
+
- **Response Panel**: Webview with formatted JSON and execution results
|
package/README.md
CHANGED
|
@@ -340,7 +340,7 @@ end sequence
|
|
|
340
340
|
- Circular imports are detected and reported as errors
|
|
341
341
|
- Only named requests `[Name]` and sequences are imported
|
|
342
342
|
- Variables are resolved at import time (baked in), not exported
|
|
343
|
-
- `.nornenv`
|
|
343
|
+
- `.nornenv` resolution is file-aware: Norn walks up from the running file and uses the closest `.nornenv`
|
|
344
344
|
|
|
345
345
|
### API Definition Files (.nornapi)
|
|
346
346
|
|
|
@@ -506,7 +506,8 @@ end sequence
|
|
|
506
506
|
|
|
507
507
|
### Environments
|
|
508
508
|
|
|
509
|
-
Create a `.nornenv` file
|
|
509
|
+
Create a `.nornenv` file to manage environment-specific variables.
|
|
510
|
+
Norn resolves the closest `.nornenv` by walking up from the file being run (or edited):
|
|
510
511
|
|
|
511
512
|
```bash
|
|
512
513
|
# .nornenv file
|
|
@@ -1017,6 +1018,7 @@ end sequence
|
|
|
1017
1018
|
| `var name = value` | Common variable (all environments) |
|
|
1018
1019
|
| `[env:name]` | Start environment section |
|
|
1019
1020
|
| `# comment` | Comment line |
|
|
1021
|
+
| resolution | Closest ancestor `.nornenv` from the current `.norn`/`.nornapi` file |
|
|
1020
1022
|
|
|
1021
1023
|
### API Definitions (.nornapi)
|
|
1022
1024
|
|
package/dist/cli.js
CHANGED
|
@@ -10386,7 +10386,7 @@ var require_ms = __commonJS({
|
|
|
10386
10386
|
options = options || {};
|
|
10387
10387
|
var type = typeof val;
|
|
10388
10388
|
if (type === "string" && val.length > 0) {
|
|
10389
|
-
return
|
|
10389
|
+
return parse2(val);
|
|
10390
10390
|
} else if (type === "number" && isFinite(val)) {
|
|
10391
10391
|
return options.long ? fmtLong(val) : fmtShort(val);
|
|
10392
10392
|
}
|
|
@@ -10394,7 +10394,7 @@ var require_ms = __commonJS({
|
|
|
10394
10394
|
"val is not a non-empty string or a valid number. val=" + JSON.stringify(val)
|
|
10395
10395
|
);
|
|
10396
10396
|
};
|
|
10397
|
-
function
|
|
10397
|
+
function parse2(str) {
|
|
10398
10398
|
str = String(str);
|
|
10399
10399
|
if (str.length > 100) {
|
|
10400
10400
|
return;
|
|
@@ -12106,7 +12106,7 @@ var require_cjs = __commonJS({
|
|
|
12106
12106
|
out.publicSuffix = (_a = hostnameParts[hostnameParts.length - 1]) !== null && _a !== void 0 ? _a : null;
|
|
12107
12107
|
}
|
|
12108
12108
|
var RESULT = getEmptyResult();
|
|
12109
|
-
function
|
|
12109
|
+
function parse2(url2, options = {}) {
|
|
12110
12110
|
return parseImpl(url2, 5, suffixLookup, options, getEmptyResult());
|
|
12111
12111
|
}
|
|
12112
12112
|
function getHostname(url2, options = {}) {
|
|
@@ -12134,7 +12134,7 @@ var require_cjs = __commonJS({
|
|
|
12134
12134
|
exports2.getHostname = getHostname;
|
|
12135
12135
|
exports2.getPublicSuffix = getPublicSuffix2;
|
|
12136
12136
|
exports2.getSubdomain = getSubdomain;
|
|
12137
|
-
exports2.parse =
|
|
12137
|
+
exports2.parse = parse2;
|
|
12138
12138
|
}
|
|
12139
12139
|
});
|
|
12140
12140
|
|
|
@@ -15684,24 +15684,24 @@ var require_fast_uri = __commonJS({
|
|
|
15684
15684
|
function normalize(uri, options) {
|
|
15685
15685
|
if (typeof uri === "string") {
|
|
15686
15686
|
uri = /** @type {T} */
|
|
15687
|
-
serialize(
|
|
15687
|
+
serialize(parse2(uri, options), options);
|
|
15688
15688
|
} else if (typeof uri === "object") {
|
|
15689
15689
|
uri = /** @type {T} */
|
|
15690
|
-
|
|
15690
|
+
parse2(serialize(uri, options), options);
|
|
15691
15691
|
}
|
|
15692
15692
|
return uri;
|
|
15693
15693
|
}
|
|
15694
15694
|
function resolve5(baseURI, relativeURI, options) {
|
|
15695
15695
|
const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
|
|
15696
|
-
const resolved = resolveComponent(
|
|
15696
|
+
const resolved = resolveComponent(parse2(baseURI, schemelessOptions), parse2(relativeURI, schemelessOptions), schemelessOptions, true);
|
|
15697
15697
|
schemelessOptions.skipEscape = true;
|
|
15698
15698
|
return serialize(resolved, schemelessOptions);
|
|
15699
15699
|
}
|
|
15700
15700
|
function resolveComponent(base, relative2, options, skipNormalization) {
|
|
15701
15701
|
const target = {};
|
|
15702
15702
|
if (!skipNormalization) {
|
|
15703
|
-
base =
|
|
15704
|
-
relative2 =
|
|
15703
|
+
base = parse2(serialize(base, options), options);
|
|
15704
|
+
relative2 = parse2(serialize(relative2, options), options);
|
|
15705
15705
|
}
|
|
15706
15706
|
options = options || {};
|
|
15707
15707
|
if (!options.tolerant && relative2.scheme) {
|
|
@@ -15753,13 +15753,13 @@ var require_fast_uri = __commonJS({
|
|
|
15753
15753
|
function equal(uriA, uriB, options) {
|
|
15754
15754
|
if (typeof uriA === "string") {
|
|
15755
15755
|
uriA = unescape(uriA);
|
|
15756
|
-
uriA = serialize(normalizeComponentEncoding(
|
|
15756
|
+
uriA = serialize(normalizeComponentEncoding(parse2(uriA, options), true), { ...options, skipEscape: true });
|
|
15757
15757
|
} else if (typeof uriA === "object") {
|
|
15758
15758
|
uriA = serialize(normalizeComponentEncoding(uriA, true), { ...options, skipEscape: true });
|
|
15759
15759
|
}
|
|
15760
15760
|
if (typeof uriB === "string") {
|
|
15761
15761
|
uriB = unescape(uriB);
|
|
15762
|
-
uriB = serialize(normalizeComponentEncoding(
|
|
15762
|
+
uriB = serialize(normalizeComponentEncoding(parse2(uriB, options), true), { ...options, skipEscape: true });
|
|
15763
15763
|
} else if (typeof uriB === "object") {
|
|
15764
15764
|
uriB = serialize(normalizeComponentEncoding(uriB, true), { ...options, skipEscape: true });
|
|
15765
15765
|
}
|
|
@@ -15828,7 +15828,7 @@ var require_fast_uri = __commonJS({
|
|
|
15828
15828
|
return uriTokens.join("");
|
|
15829
15829
|
}
|
|
15830
15830
|
var URI_PARSE = /^(?:([^#/:?]+):)?(?:\/\/((?:([^#/?@]*)@)?(\[[^#/?\]]+\]|[^#/:?]*)(?::(\d*))?))?([^#?]*)(?:\?([^#]*))?(?:#((?:.|[\n\r])*))?/u;
|
|
15831
|
-
function
|
|
15831
|
+
function parse2(uri, opts) {
|
|
15832
15832
|
const options = Object.assign({}, opts);
|
|
15833
15833
|
const parsed = {
|
|
15834
15834
|
scheme: void 0,
|
|
@@ -15922,7 +15922,7 @@ var require_fast_uri = __commonJS({
|
|
|
15922
15922
|
resolveComponent,
|
|
15923
15923
|
equal,
|
|
15924
15924
|
serialize,
|
|
15925
|
-
parse:
|
|
15925
|
+
parse: parse2
|
|
15926
15926
|
};
|
|
15927
15927
|
module2.exports = fastUri;
|
|
15928
15928
|
module2.exports.default = fastUri;
|
|
@@ -30269,15 +30269,27 @@ function generateHtmlReportFromResponse(response, testName, options) {
|
|
|
30269
30269
|
|
|
30270
30270
|
// src/cli.ts
|
|
30271
30271
|
var ENV_FILENAME = ".nornenv";
|
|
30272
|
+
function getEnvSearchStartDirectory(targetPath) {
|
|
30273
|
+
const resolvedPath = path4.resolve(targetPath);
|
|
30274
|
+
try {
|
|
30275
|
+
const stats = fs5.statSync(resolvedPath);
|
|
30276
|
+
return stats.isDirectory() ? resolvedPath : path4.dirname(resolvedPath);
|
|
30277
|
+
} catch {
|
|
30278
|
+
return path4.dirname(resolvedPath);
|
|
30279
|
+
}
|
|
30280
|
+
}
|
|
30272
30281
|
function findEnvFileFromPath(filePath) {
|
|
30273
|
-
let dir =
|
|
30274
|
-
|
|
30275
|
-
while (dir !== root) {
|
|
30282
|
+
let dir = getEnvSearchStartDirectory(filePath);
|
|
30283
|
+
while (true) {
|
|
30276
30284
|
const envPath = path4.join(dir, ENV_FILENAME);
|
|
30277
30285
|
if (fs5.existsSync(envPath)) {
|
|
30278
30286
|
return envPath;
|
|
30279
30287
|
}
|
|
30280
|
-
|
|
30288
|
+
const parentDir = path4.dirname(dir);
|
|
30289
|
+
if (parentDir === dir) {
|
|
30290
|
+
break;
|
|
30291
|
+
}
|
|
30292
|
+
dir = parentDir;
|
|
30281
30293
|
}
|
|
30282
30294
|
return void 0;
|
|
30283
30295
|
}
|
|
@@ -30333,6 +30345,57 @@ function parseEnvFile(content) {
|
|
|
30333
30345
|
}
|
|
30334
30346
|
return config;
|
|
30335
30347
|
}
|
|
30348
|
+
function resolveEnvironmentForPath(targetPath, selectedEnv) {
|
|
30349
|
+
const envFilePath = findEnvFileFromPath(targetPath);
|
|
30350
|
+
if (!envFilePath) {
|
|
30351
|
+
return {
|
|
30352
|
+
variables: {},
|
|
30353
|
+
secretNames: /* @__PURE__ */ new Set(),
|
|
30354
|
+
secretValues: /* @__PURE__ */ new Map(),
|
|
30355
|
+
availableEnvironments: []
|
|
30356
|
+
};
|
|
30357
|
+
}
|
|
30358
|
+
const envContent = fs5.readFileSync(envFilePath, "utf-8");
|
|
30359
|
+
const envConfig = parseEnvFile(envContent);
|
|
30360
|
+
const variables = { ...envConfig.common };
|
|
30361
|
+
const secretNames = new Set(envConfig.secretNames);
|
|
30362
|
+
const secretValues = new Map(envConfig.secretValues);
|
|
30363
|
+
const availableEnvironments = envConfig.environments.map((e) => e.name);
|
|
30364
|
+
if (selectedEnv) {
|
|
30365
|
+
const targetEnv = envConfig.environments.find((e) => e.name === selectedEnv);
|
|
30366
|
+
if (!targetEnv) {
|
|
30367
|
+
return {
|
|
30368
|
+
envFilePath,
|
|
30369
|
+
variables,
|
|
30370
|
+
secretNames,
|
|
30371
|
+
secretValues,
|
|
30372
|
+
availableEnvironments,
|
|
30373
|
+
envNotFound: selectedEnv
|
|
30374
|
+
};
|
|
30375
|
+
}
|
|
30376
|
+
Object.assign(variables, targetEnv.variables);
|
|
30377
|
+
for (const [name, value] of Object.entries(targetEnv.variables)) {
|
|
30378
|
+
if (secretNames.has(name)) {
|
|
30379
|
+
secretValues.set(name, value);
|
|
30380
|
+
}
|
|
30381
|
+
}
|
|
30382
|
+
}
|
|
30383
|
+
return {
|
|
30384
|
+
envFilePath,
|
|
30385
|
+
variables,
|
|
30386
|
+
secretNames,
|
|
30387
|
+
secretValues,
|
|
30388
|
+
availableEnvironments
|
|
30389
|
+
};
|
|
30390
|
+
}
|
|
30391
|
+
function mergeSecrets(targetNames, targetValues, sourceNames, sourceValues) {
|
|
30392
|
+
for (const name of sourceNames) {
|
|
30393
|
+
targetNames.add(name);
|
|
30394
|
+
}
|
|
30395
|
+
for (const [name, value] of sourceValues) {
|
|
30396
|
+
targetValues.set(name, value);
|
|
30397
|
+
}
|
|
30398
|
+
}
|
|
30336
30399
|
function generateTimestamp() {
|
|
30337
30400
|
const now = /* @__PURE__ */ new Date();
|
|
30338
30401
|
const year = now.getFullYear();
|
|
@@ -30739,38 +30802,8 @@ async function main() {
|
|
|
30739
30802
|
const allErrors = [];
|
|
30740
30803
|
let overallSuccess = true;
|
|
30741
30804
|
const startTime = Date.now();
|
|
30742
|
-
const
|
|
30743
|
-
|
|
30744
|
-
let redaction = createRedactionOptions(/* @__PURE__ */ new Set(), /* @__PURE__ */ new Map(), !options.noRedact);
|
|
30745
|
-
if (envFilePath) {
|
|
30746
|
-
const envContent = fs5.readFileSync(envFilePath, "utf-8");
|
|
30747
|
-
const envConfig = parseEnvFile(envContent);
|
|
30748
|
-
envVariables = { ...envConfig.common };
|
|
30749
|
-
redaction = createRedactionOptions(
|
|
30750
|
-
envConfig.secretNames,
|
|
30751
|
-
envConfig.secretValues,
|
|
30752
|
-
!options.noRedact
|
|
30753
|
-
);
|
|
30754
|
-
if (options.env) {
|
|
30755
|
-
const targetEnv = envConfig.environments.find((e) => e.name === options.env);
|
|
30756
|
-
if (!targetEnv) {
|
|
30757
|
-
console.error(`Error: Environment '${options.env}' not found in .nornenv`);
|
|
30758
|
-
console.error(`Available environments: ${envConfig.environments.map((e) => e.name).join(", ") || "none"}`);
|
|
30759
|
-
process.exit(1);
|
|
30760
|
-
}
|
|
30761
|
-
Object.assign(envVariables, targetEnv.variables);
|
|
30762
|
-
for (const [name, value] of Object.entries(targetEnv.variables)) {
|
|
30763
|
-
if (envConfig.secretNames.has(name)) {
|
|
30764
|
-
redaction.secretValues.set(name, value);
|
|
30765
|
-
}
|
|
30766
|
-
}
|
|
30767
|
-
if (options.verbose) {
|
|
30768
|
-
console.log(colors.info(`Using environment: ${options.env}`));
|
|
30769
|
-
}
|
|
30770
|
-
}
|
|
30771
|
-
} else if (options.env) {
|
|
30772
|
-
console.error(colors.warning(`Warning: --env specified but no .nornenv file found`));
|
|
30773
|
-
}
|
|
30805
|
+
const combinedSecretNames = /* @__PURE__ */ new Set();
|
|
30806
|
+
const combinedSecretValues = /* @__PURE__ */ new Map();
|
|
30774
30807
|
let tagFilterOptions = void 0;
|
|
30775
30808
|
if (options.tagFilters.length > 0) {
|
|
30776
30809
|
tagFilterOptions = {
|
|
@@ -30789,9 +30822,22 @@ async function main() {
|
|
|
30789
30822
|
}
|
|
30790
30823
|
if (options.sequence || options.request) {
|
|
30791
30824
|
const filePath = filesToRun[0];
|
|
30825
|
+
const resolvedEnv = resolveEnvironmentForPath(filePath, options.env);
|
|
30826
|
+
if (resolvedEnv.envNotFound) {
|
|
30827
|
+
console.error(`Error: Environment '${resolvedEnv.envNotFound}' not found in .nornenv`);
|
|
30828
|
+
console.error(`Available environments: ${resolvedEnv.availableEnvironments.join(", ") || "none"}`);
|
|
30829
|
+
process.exit(1);
|
|
30830
|
+
}
|
|
30831
|
+
if (!resolvedEnv.envFilePath && options.env) {
|
|
30832
|
+
console.error(colors.warning(`Warning: --env specified but no .nornenv file found`));
|
|
30833
|
+
} else if (resolvedEnv.envFilePath && options.env && options.verbose) {
|
|
30834
|
+
console.log(colors.info(`Using environment: ${options.env}`));
|
|
30835
|
+
}
|
|
30836
|
+
mergeSecrets(combinedSecretNames, combinedSecretValues, resolvedEnv.secretNames, resolvedEnv.secretValues);
|
|
30837
|
+
const redaction2 = createRedactionOptions(combinedSecretNames, combinedSecretValues, !options.noRedact);
|
|
30792
30838
|
const fileContent = fs5.readFileSync(filePath, "utf-8");
|
|
30793
30839
|
const fileVariables = extractFileLevelVariables(fileContent);
|
|
30794
|
-
const variables = { ...
|
|
30840
|
+
const variables = { ...resolvedEnv.variables, ...fileVariables };
|
|
30795
30841
|
const cookieJar = createCookieJar();
|
|
30796
30842
|
const workingDir = path4.dirname(filePath);
|
|
30797
30843
|
const importResult = await resolveImports(
|
|
@@ -30835,7 +30881,7 @@ ${fileContent}` : fileContent;
|
|
|
30835
30881
|
console.log(JSON.stringify({ success: response.status >= 200 && response.status < 400, results: [response] }, null, 2));
|
|
30836
30882
|
} else {
|
|
30837
30883
|
const isSuccess = response.status >= 200 && response.status < 300;
|
|
30838
|
-
const lines = formatResponse(response, { colors, verbose: options.verbose, showDetails: !isSuccess || options.verbose, redaction });
|
|
30884
|
+
const lines = formatResponse(response, { colors, verbose: options.verbose, showDetails: !isSuccess || options.verbose, redaction: redaction2 });
|
|
30839
30885
|
for (const line2 of lines) {
|
|
30840
30886
|
console.log(line2);
|
|
30841
30887
|
}
|
|
@@ -30878,7 +30924,7 @@ ${fileContent}` : fileContent;
|
|
|
30878
30924
|
if (options.output === "json") {
|
|
30879
30925
|
console.log(JSON.stringify({ success: seqResult.success, results: [seqResult] }, null, 2));
|
|
30880
30926
|
} else {
|
|
30881
|
-
const lines = formatSequenceResult(seqResult, { colors, verbose: options.verbose, redaction });
|
|
30927
|
+
const lines = formatSequenceResult(seqResult, { colors, verbose: options.verbose, redaction: redaction2 });
|
|
30882
30928
|
for (const line2 of lines) {
|
|
30883
30929
|
console.log(line2);
|
|
30884
30930
|
}
|
|
@@ -30912,9 +30958,21 @@ ${fileContent}` : fileContent;
|
|
|
30912
30958
|
console.log("");
|
|
30913
30959
|
}
|
|
30914
30960
|
for (const filePath of filesToRun) {
|
|
30961
|
+
const resolvedEnv = resolveEnvironmentForPath(filePath, options.env);
|
|
30962
|
+
if (resolvedEnv.envNotFound) {
|
|
30963
|
+
console.error(`Error: Environment '${resolvedEnv.envNotFound}' not found in .nornenv`);
|
|
30964
|
+
console.error(`Available environments: ${resolvedEnv.availableEnvironments.join(", ") || "none"}`);
|
|
30965
|
+
process.exit(1);
|
|
30966
|
+
}
|
|
30967
|
+
if (!resolvedEnv.envFilePath && options.env) {
|
|
30968
|
+
const relPath = isDirectory ? path4.relative(inputPath, filePath) : path4.basename(filePath);
|
|
30969
|
+
console.error(colors.warning(`Warning: --env specified but no .nornenv file found for ${relPath}`));
|
|
30970
|
+
}
|
|
30971
|
+
mergeSecrets(combinedSecretNames, combinedSecretValues, resolvedEnv.secretNames, resolvedEnv.secretValues);
|
|
30972
|
+
const redaction2 = createRedactionOptions(combinedSecretNames, combinedSecretValues, !options.noRedact);
|
|
30915
30973
|
const fileContent = fs5.readFileSync(filePath, "utf-8");
|
|
30916
30974
|
const fileVariables = extractFileLevelVariables(fileContent);
|
|
30917
|
-
const variables = { ...
|
|
30975
|
+
const variables = { ...resolvedEnv.variables, ...fileVariables };
|
|
30918
30976
|
const cookieJar = createCookieJar();
|
|
30919
30977
|
const workingDir = path4.dirname(filePath);
|
|
30920
30978
|
const importResult = await resolveImports(
|
|
@@ -30964,7 +31022,7 @@ ${fileContent}` : fileContent;
|
|
|
30964
31022
|
}
|
|
30965
31023
|
if (options.output !== "json") {
|
|
30966
31024
|
for (const seqResult of seqResults) {
|
|
30967
|
-
const lines = formatSequenceResult(seqResult, { colors, verbose: options.verbose, redaction });
|
|
31025
|
+
const lines = formatSequenceResult(seqResult, { colors, verbose: options.verbose, redaction: redaction2 });
|
|
30968
31026
|
for (const line2 of lines) {
|
|
30969
31027
|
console.log(line2);
|
|
30970
31028
|
}
|
|
@@ -30972,6 +31030,7 @@ ${fileContent}` : fileContent;
|
|
|
30972
31030
|
}
|
|
30973
31031
|
}
|
|
30974
31032
|
const totalDuration = Date.now() - startTime;
|
|
31033
|
+
const redaction = createRedactionOptions(combinedSecretNames, combinedSecretValues, !options.noRedact);
|
|
30975
31034
|
const result = {
|
|
30976
31035
|
success: overallSuccess,
|
|
30977
31036
|
type: "all-sequences",
|