norn-cli 1.5.3 → 1.6.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 +35 -0
- package/README.md +35 -0
- package/dist/cli.js +1417 -1337
- package/package.json +72 -2
- package/.norn-cache/secret-keys.json +0 -9
- package/.norn-cache/swagger-body-intellisense.json +0 -409
- package/.norn-cache/validation-results.json +0 -47
package/dist/cli.js
CHANGED
|
@@ -8881,11 +8881,11 @@ var require_mime_types = __commonJS({
|
|
|
8881
8881
|
}
|
|
8882
8882
|
return exts[0];
|
|
8883
8883
|
}
|
|
8884
|
-
function lookup(
|
|
8885
|
-
if (!
|
|
8884
|
+
function lookup(path10) {
|
|
8885
|
+
if (!path10 || typeof path10 !== "string") {
|
|
8886
8886
|
return false;
|
|
8887
8887
|
}
|
|
8888
|
-
var extension2 = extname2("x." +
|
|
8888
|
+
var extension2 = extname2("x." + path10).toLowerCase().substr(1);
|
|
8889
8889
|
if (!extension2) {
|
|
8890
8890
|
return false;
|
|
8891
8891
|
}
|
|
@@ -9990,11 +9990,11 @@ var require_form_data = __commonJS({
|
|
|
9990
9990
|
"use strict";
|
|
9991
9991
|
var CombinedStream = require_combined_stream();
|
|
9992
9992
|
var util3 = require("util");
|
|
9993
|
-
var
|
|
9993
|
+
var path10 = require("path");
|
|
9994
9994
|
var http3 = require("http");
|
|
9995
9995
|
var https3 = require("https");
|
|
9996
9996
|
var parseUrl = require("url").parse;
|
|
9997
|
-
var
|
|
9997
|
+
var fs11 = require("fs");
|
|
9998
9998
|
var Stream = require("stream").Stream;
|
|
9999
9999
|
var crypto3 = require("crypto");
|
|
10000
10000
|
var mime = require_mime_types();
|
|
@@ -10061,7 +10061,7 @@ var require_form_data = __commonJS({
|
|
|
10061
10061
|
if (value.end != void 0 && value.end != Infinity && value.start != void 0) {
|
|
10062
10062
|
callback(null, value.end + 1 - (value.start ? value.start : 0));
|
|
10063
10063
|
} else {
|
|
10064
|
-
|
|
10064
|
+
fs11.stat(value.path, function(err, stat) {
|
|
10065
10065
|
if (err) {
|
|
10066
10066
|
callback(err);
|
|
10067
10067
|
return;
|
|
@@ -10118,11 +10118,11 @@ var require_form_data = __commonJS({
|
|
|
10118
10118
|
FormData3.prototype._getContentDisposition = function(value, options) {
|
|
10119
10119
|
var filename;
|
|
10120
10120
|
if (typeof options.filepath === "string") {
|
|
10121
|
-
filename =
|
|
10121
|
+
filename = path10.normalize(options.filepath).replace(/\\/g, "/");
|
|
10122
10122
|
} else if (options.filename || value && (value.name || value.path)) {
|
|
10123
|
-
filename =
|
|
10123
|
+
filename = path10.basename(options.filename || value && (value.name || value.path));
|
|
10124
10124
|
} else if (value && value.readable && hasOwn(value, "httpVersion")) {
|
|
10125
|
-
filename =
|
|
10125
|
+
filename = path10.basename(value.client._httpMessage.path || "");
|
|
10126
10126
|
}
|
|
10127
10127
|
if (filename) {
|
|
10128
10128
|
return 'filename="' + filename + '"';
|
|
@@ -15331,8 +15331,8 @@ var require_utils = __commonJS({
|
|
|
15331
15331
|
}
|
|
15332
15332
|
return ind;
|
|
15333
15333
|
}
|
|
15334
|
-
function removeDotSegments(
|
|
15335
|
-
let input2 =
|
|
15334
|
+
function removeDotSegments(path10) {
|
|
15335
|
+
let input2 = path10;
|
|
15336
15336
|
const output2 = [];
|
|
15337
15337
|
let nextSlash = -1;
|
|
15338
15338
|
let len = 0;
|
|
@@ -15531,8 +15531,8 @@ var require_schemes = __commonJS({
|
|
|
15531
15531
|
wsComponent.secure = void 0;
|
|
15532
15532
|
}
|
|
15533
15533
|
if (wsComponent.resourceName) {
|
|
15534
|
-
const [
|
|
15535
|
-
wsComponent.path =
|
|
15534
|
+
const [path10, query] = wsComponent.resourceName.split("?");
|
|
15535
|
+
wsComponent.path = path10 && path10 !== "/" ? path10 : void 0;
|
|
15536
15536
|
wsComponent.query = query;
|
|
15537
15537
|
wsComponent.resourceName = void 0;
|
|
15538
15538
|
}
|
|
@@ -18738,8 +18738,8 @@ function validateAgainstSchemaDetailed(value, schemaPath, basePath, workspaceRoo
|
|
|
18738
18738
|
if (!valid && validate2.errors) {
|
|
18739
18739
|
const errors = validate2.errors.map((err) => convertAjvError(err, value));
|
|
18740
18740
|
const errorStrings = validate2.errors.map((err) => {
|
|
18741
|
-
const
|
|
18742
|
-
return `${
|
|
18741
|
+
const path10 = err.instancePath || "(root)";
|
|
18742
|
+
return `${path10}: ${err.message}`;
|
|
18743
18743
|
});
|
|
18744
18744
|
return {
|
|
18745
18745
|
valid: false,
|
|
@@ -18868,7 +18868,7 @@ function resolveValue(expr, responses, variables, getValueByPath2, responseIndex
|
|
|
18868
18868
|
if (refMatch) {
|
|
18869
18869
|
const responseIdx = parseInt(refMatch[1], 10);
|
|
18870
18870
|
const responseIndex = responseIdx - 1;
|
|
18871
|
-
const
|
|
18871
|
+
const path10 = refMatch[2];
|
|
18872
18872
|
if (responseIndex < 0 || responseIndex >= responses.length) {
|
|
18873
18873
|
return {
|
|
18874
18874
|
value: void 0,
|
|
@@ -18876,12 +18876,12 @@ function resolveValue(expr, responses, variables, getValueByPath2, responseIndex
|
|
|
18876
18876
|
};
|
|
18877
18877
|
}
|
|
18878
18878
|
const response = responses[responseIndex];
|
|
18879
|
-
const value = getValueByPath2(response,
|
|
18879
|
+
const value = getValueByPath2(response, path10);
|
|
18880
18880
|
return {
|
|
18881
18881
|
value,
|
|
18882
18882
|
responseIndex: responseIdx,
|
|
18883
18883
|
response,
|
|
18884
|
-
jsonPath:
|
|
18884
|
+
jsonPath: path10,
|
|
18885
18885
|
variableName: responseIndexToVariable?.get(responseIdx)
|
|
18886
18886
|
};
|
|
18887
18887
|
}
|
|
@@ -18898,22 +18898,22 @@ function resolveValue(expr, responses, variables, getValueByPath2, responseIndex
|
|
|
18898
18898
|
if (varName in variables) {
|
|
18899
18899
|
const varValue = variables[varName];
|
|
18900
18900
|
if (typeof varValue === "object" && varValue !== null) {
|
|
18901
|
-
const
|
|
18902
|
-
const value = getNestedValue2(varValue,
|
|
18901
|
+
const path10 = pathPart.replace(/^\./, "");
|
|
18902
|
+
const value = getNestedValue2(varValue, path10);
|
|
18903
18903
|
const isHttpResponse = "status" in varValue && "body" in varValue;
|
|
18904
18904
|
return {
|
|
18905
18905
|
value,
|
|
18906
18906
|
variableName: varName,
|
|
18907
|
-
jsonPath:
|
|
18907
|
+
jsonPath: path10,
|
|
18908
18908
|
response: isHttpResponse ? varValue : void 0
|
|
18909
18909
|
};
|
|
18910
18910
|
}
|
|
18911
18911
|
if (typeof varValue === "string") {
|
|
18912
18912
|
try {
|
|
18913
18913
|
const parsed = JSON.parse(varValue);
|
|
18914
|
-
const
|
|
18915
|
-
const value = getNestedValue2(parsed,
|
|
18916
|
-
return { value, variableName: varName, jsonPath:
|
|
18914
|
+
const path10 = pathPart.replace(/^\./, "");
|
|
18915
|
+
const value = getNestedValue2(parsed, path10);
|
|
18916
|
+
return { value, variableName: varName, jsonPath: path10 };
|
|
18917
18917
|
} catch {
|
|
18918
18918
|
return { value: void 0, error: `Cannot access path on non-object variable: ${varName}` };
|
|
18919
18919
|
}
|
|
@@ -18969,11 +18969,11 @@ function resolveValue(expr, responses, variables, getValueByPath2, responseIndex
|
|
|
18969
18969
|
}
|
|
18970
18970
|
return { value: void 0, error: `Cannot resolve expression: ${trimmed}` };
|
|
18971
18971
|
}
|
|
18972
|
-
function getNestedValue2(obj,
|
|
18973
|
-
if (!
|
|
18972
|
+
function getNestedValue2(obj, path10) {
|
|
18973
|
+
if (!path10 || obj === null || obj === void 0) {
|
|
18974
18974
|
return obj;
|
|
18975
18975
|
}
|
|
18976
|
-
const parts =
|
|
18976
|
+
const parts = path10.replace(/\[(\d+)\]/g, ".$1").split(".").filter((p) => p !== "");
|
|
18977
18977
|
let current = obj;
|
|
18978
18978
|
for (const part of parts) {
|
|
18979
18979
|
if (current === null || current === void 0) {
|
|
@@ -19769,16 +19769,16 @@ var init_source = __esm({
|
|
|
19769
19769
|
});
|
|
19770
19770
|
|
|
19771
19771
|
// src/cli.ts
|
|
19772
|
-
var
|
|
19772
|
+
var fs10 = __toESM(require("fs"));
|
|
19773
19773
|
var fsPromises = __toESM(require("fs/promises"));
|
|
19774
|
-
var
|
|
19774
|
+
var path9 = __toESM(require("path"));
|
|
19775
19775
|
|
|
19776
19776
|
// src/nornapiParser.ts
|
|
19777
|
-
function extractPathParameters(
|
|
19777
|
+
function extractPathParameters(path10) {
|
|
19778
19778
|
const params = [];
|
|
19779
19779
|
const regex = /(?<!\{)\{([a-zA-Z_][a-zA-Z0-9_]*)\}(?!\})/g;
|
|
19780
19780
|
let match;
|
|
19781
|
-
while ((match = regex.exec(
|
|
19781
|
+
while ((match = regex.exec(path10)) !== null) {
|
|
19782
19782
|
params.push(match[1]);
|
|
19783
19783
|
}
|
|
19784
19784
|
return params;
|
|
@@ -19828,12 +19828,12 @@ function parseNornApiFile(content) {
|
|
|
19828
19828
|
if (inEndpointsBlock) {
|
|
19829
19829
|
const endpointMatch = trimmed.match(/^([a-zA-Z_][a-zA-Z0-9_]*)\s*:\s*(GET|POST|PUT|DELETE|PATCH|HEAD|OPTIONS)\s+(.+)$/i);
|
|
19830
19830
|
if (endpointMatch) {
|
|
19831
|
-
const
|
|
19831
|
+
const path10 = endpointMatch[3].trim();
|
|
19832
19832
|
endpoints.push({
|
|
19833
19833
|
name: endpointMatch[1],
|
|
19834
19834
|
method: endpointMatch[2].toUpperCase(),
|
|
19835
|
-
path:
|
|
19836
|
-
parameters: extractPathParameters(
|
|
19835
|
+
path: path10,
|
|
19836
|
+
parameters: extractPathParameters(path10)
|
|
19837
19837
|
});
|
|
19838
19838
|
}
|
|
19839
19839
|
continue;
|
|
@@ -20123,11 +20123,11 @@ function extractFileLevelVariables(text) {
|
|
|
20123
20123
|
}
|
|
20124
20124
|
return variables;
|
|
20125
20125
|
}
|
|
20126
|
-
function getNestedValue(obj,
|
|
20127
|
-
if (!
|
|
20126
|
+
function getNestedValue(obj, path10) {
|
|
20127
|
+
if (!path10 || obj === null || obj === void 0) {
|
|
20128
20128
|
return obj;
|
|
20129
20129
|
}
|
|
20130
|
-
const parts =
|
|
20130
|
+
const parts = path10.replace(/\[(\d+)\]/g, ".$1").split(".").filter((p) => p !== "");
|
|
20131
20131
|
let current = obj;
|
|
20132
20132
|
for (const part of parts) {
|
|
20133
20133
|
if (current === null || current === void 0) {
|
|
@@ -20159,8 +20159,8 @@ function substituteVariables(text, variables) {
|
|
|
20159
20159
|
const value = variables[varName];
|
|
20160
20160
|
if (typeof value === "object" && value !== null) {
|
|
20161
20161
|
if (pathPart) {
|
|
20162
|
-
const
|
|
20163
|
-
const nestedValue = getNestedValue(value,
|
|
20162
|
+
const path10 = pathPart.replace(/^\./, "");
|
|
20163
|
+
const nestedValue = getNestedValue(value, path10);
|
|
20164
20164
|
return valueToString(nestedValue);
|
|
20165
20165
|
}
|
|
20166
20166
|
return valueToString(value);
|
|
@@ -20168,8 +20168,8 @@ function substituteVariables(text, variables) {
|
|
|
20168
20168
|
if (pathPart && typeof value === "string") {
|
|
20169
20169
|
try {
|
|
20170
20170
|
const parsed = JSON.parse(value);
|
|
20171
|
-
const
|
|
20172
|
-
const nestedValue = getNestedValue(parsed,
|
|
20171
|
+
const path10 = pathPart.replace(/^\./, "");
|
|
20172
|
+
const nestedValue = getNestedValue(parsed, path10);
|
|
20173
20173
|
return valueToString(nestedValue);
|
|
20174
20174
|
} catch {
|
|
20175
20175
|
return value;
|
|
@@ -20285,8 +20285,8 @@ async function resolveImports(text, baseDir, readFile2, alreadyImported = /* @__
|
|
|
20285
20285
|
const namedRequestSources = /* @__PURE__ */ new Map();
|
|
20286
20286
|
const sequenceSources = /* @__PURE__ */ new Map();
|
|
20287
20287
|
for (const imp of imports) {
|
|
20288
|
-
const
|
|
20289
|
-
const absolutePath =
|
|
20288
|
+
const path10 = await import("path");
|
|
20289
|
+
const absolutePath = path10.resolve(baseDir, imp.path);
|
|
20290
20290
|
if (importStack.has(absolutePath)) {
|
|
20291
20291
|
errors.push({
|
|
20292
20292
|
path: imp.path,
|
|
@@ -20333,7 +20333,7 @@ async function resolveImports(text, baseDir, readFile2, alreadyImported = /* @__
|
|
|
20333
20333
|
}
|
|
20334
20334
|
continue;
|
|
20335
20335
|
}
|
|
20336
|
-
const importDir =
|
|
20336
|
+
const importDir = path10.dirname(absolutePath);
|
|
20337
20337
|
const nestedResult = await resolveImports(content, importDir, readFile2, alreadyImported, importStack);
|
|
20338
20338
|
errors.push(...nestedResult.errors);
|
|
20339
20339
|
resolvedPaths.push(...nestedResult.resolvedPaths);
|
|
@@ -20932,9 +20932,9 @@ function isVisitable(thing) {
|
|
|
20932
20932
|
function removeBrackets(key) {
|
|
20933
20933
|
return utils_default.endsWith(key, "[]") ? key.slice(0, -2) : key;
|
|
20934
20934
|
}
|
|
20935
|
-
function renderKey(
|
|
20936
|
-
if (!
|
|
20937
|
-
return
|
|
20935
|
+
function renderKey(path10, key, dots) {
|
|
20936
|
+
if (!path10) return key;
|
|
20937
|
+
return path10.concat(key).map(function each(token, i) {
|
|
20938
20938
|
token = removeBrackets(token);
|
|
20939
20939
|
return !dots && i ? "[" + token + "]" : token;
|
|
20940
20940
|
}).join(dots ? "." : "");
|
|
@@ -20982,9 +20982,9 @@ function toFormData(obj, formData, options) {
|
|
|
20982
20982
|
}
|
|
20983
20983
|
return value;
|
|
20984
20984
|
}
|
|
20985
|
-
function defaultVisitor(value, key,
|
|
20985
|
+
function defaultVisitor(value, key, path10) {
|
|
20986
20986
|
let arr = value;
|
|
20987
|
-
if (value && !
|
|
20987
|
+
if (value && !path10 && typeof value === "object") {
|
|
20988
20988
|
if (utils_default.endsWith(key, "{}")) {
|
|
20989
20989
|
key = metaTokens ? key : key.slice(0, -2);
|
|
20990
20990
|
value = JSON.stringify(value);
|
|
@@ -21003,7 +21003,7 @@ function toFormData(obj, formData, options) {
|
|
|
21003
21003
|
if (isVisitable(value)) {
|
|
21004
21004
|
return true;
|
|
21005
21005
|
}
|
|
21006
|
-
formData.append(renderKey(
|
|
21006
|
+
formData.append(renderKey(path10, key, dots), convertValue(value));
|
|
21007
21007
|
return false;
|
|
21008
21008
|
}
|
|
21009
21009
|
const stack = [];
|
|
@@ -21012,10 +21012,10 @@ function toFormData(obj, formData, options) {
|
|
|
21012
21012
|
convertValue,
|
|
21013
21013
|
isVisitable
|
|
21014
21014
|
});
|
|
21015
|
-
function build(value,
|
|
21015
|
+
function build(value, path10) {
|
|
21016
21016
|
if (utils_default.isUndefined(value)) return;
|
|
21017
21017
|
if (stack.indexOf(value) !== -1) {
|
|
21018
|
-
throw Error("Circular reference detected in " +
|
|
21018
|
+
throw Error("Circular reference detected in " + path10.join("."));
|
|
21019
21019
|
}
|
|
21020
21020
|
stack.push(value);
|
|
21021
21021
|
utils_default.forEach(value, function each(el, key) {
|
|
@@ -21023,11 +21023,11 @@ function toFormData(obj, formData, options) {
|
|
|
21023
21023
|
formData,
|
|
21024
21024
|
el,
|
|
21025
21025
|
utils_default.isString(key) ? key.trim() : key,
|
|
21026
|
-
|
|
21026
|
+
path10,
|
|
21027
21027
|
exposedHelpers
|
|
21028
21028
|
);
|
|
21029
21029
|
if (result === true) {
|
|
21030
|
-
build(el,
|
|
21030
|
+
build(el, path10 ? path10.concat(key) : [key]);
|
|
21031
21031
|
}
|
|
21032
21032
|
});
|
|
21033
21033
|
stack.pop();
|
|
@@ -21239,7 +21239,7 @@ var platform_default = {
|
|
|
21239
21239
|
// node_modules/axios/lib/helpers/toURLEncodedForm.js
|
|
21240
21240
|
function toURLEncodedForm(data, options) {
|
|
21241
21241
|
return toFormData_default(data, new platform_default.classes.URLSearchParams(), {
|
|
21242
|
-
visitor: function(value, key,
|
|
21242
|
+
visitor: function(value, key, path10, helpers) {
|
|
21243
21243
|
if (platform_default.isNode && utils_default.isBuffer(value)) {
|
|
21244
21244
|
this.append(key, value.toString("base64"));
|
|
21245
21245
|
return false;
|
|
@@ -21269,11 +21269,11 @@ function arrayToObject(arr) {
|
|
|
21269
21269
|
return obj;
|
|
21270
21270
|
}
|
|
21271
21271
|
function formDataToJSON(formData) {
|
|
21272
|
-
function buildPath(
|
|
21273
|
-
let name =
|
|
21272
|
+
function buildPath(path10, value, target, index) {
|
|
21273
|
+
let name = path10[index++];
|
|
21274
21274
|
if (name === "__proto__") return true;
|
|
21275
21275
|
const isNumericKey = Number.isFinite(+name);
|
|
21276
|
-
const isLast = index >=
|
|
21276
|
+
const isLast = index >= path10.length;
|
|
21277
21277
|
name = !name && utils_default.isArray(target) ? target.length : name;
|
|
21278
21278
|
if (isLast) {
|
|
21279
21279
|
if (utils_default.hasOwnProp(target, name)) {
|
|
@@ -21286,7 +21286,7 @@ function formDataToJSON(formData) {
|
|
|
21286
21286
|
if (!target[name] || !utils_default.isObject(target[name])) {
|
|
21287
21287
|
target[name] = [];
|
|
21288
21288
|
}
|
|
21289
|
-
const result = buildPath(
|
|
21289
|
+
const result = buildPath(path10, value, target[name], index);
|
|
21290
21290
|
if (result && utils_default.isArray(target[name])) {
|
|
21291
21291
|
target[name] = arrayToObject(target[name]);
|
|
21292
21292
|
}
|
|
@@ -22608,9 +22608,9 @@ var http_default = isHttpAdapterSupported && function httpAdapter(config) {
|
|
|
22608
22608
|
auth = urlUsername + ":" + urlPassword;
|
|
22609
22609
|
}
|
|
22610
22610
|
auth && headers.delete("authorization");
|
|
22611
|
-
let
|
|
22611
|
+
let path10;
|
|
22612
22612
|
try {
|
|
22613
|
-
|
|
22613
|
+
path10 = buildURL(
|
|
22614
22614
|
parsed.pathname + parsed.search,
|
|
22615
22615
|
config.params,
|
|
22616
22616
|
config.paramsSerializer
|
|
@@ -22628,7 +22628,7 @@ var http_default = isHttpAdapterSupported && function httpAdapter(config) {
|
|
|
22628
22628
|
false
|
|
22629
22629
|
);
|
|
22630
22630
|
const options = {
|
|
22631
|
-
path:
|
|
22631
|
+
path: path10,
|
|
22632
22632
|
method,
|
|
22633
22633
|
headers: headers.toJSON(),
|
|
22634
22634
|
agents: { http: config.httpAgent, https: config.httpsAgent },
|
|
@@ -22864,14 +22864,14 @@ var isURLSameOrigin_default = platform_default.hasStandardBrowserEnv ? /* @__PUR
|
|
|
22864
22864
|
var cookies_default = platform_default.hasStandardBrowserEnv ? (
|
|
22865
22865
|
// Standard browser envs support document.cookie
|
|
22866
22866
|
{
|
|
22867
|
-
write(name, value, expires,
|
|
22867
|
+
write(name, value, expires, path10, domain, secure, sameSite) {
|
|
22868
22868
|
if (typeof document === "undefined") return;
|
|
22869
22869
|
const cookie = [`${name}=${encodeURIComponent(value)}`];
|
|
22870
22870
|
if (utils_default.isNumber(expires)) {
|
|
22871
22871
|
cookie.push(`expires=${new Date(expires).toUTCString()}`);
|
|
22872
22872
|
}
|
|
22873
|
-
if (utils_default.isString(
|
|
22874
|
-
cookie.push(`path=${
|
|
22873
|
+
if (utils_default.isString(path10)) {
|
|
22874
|
+
cookie.push(`path=${path10}`);
|
|
22875
22875
|
}
|
|
22876
22876
|
if (utils_default.isString(domain)) {
|
|
22877
22877
|
cookie.push(`domain=${domain}`);
|
|
@@ -24271,18 +24271,18 @@ var MemoryCookieStore = class extends Store {
|
|
|
24271
24271
|
/**
|
|
24272
24272
|
* @internal No doc because this is an overload that supports the implementation
|
|
24273
24273
|
*/
|
|
24274
|
-
findCookie(domain,
|
|
24274
|
+
findCookie(domain, path10, key, callback) {
|
|
24275
24275
|
const promiseCallback = createPromiseCallback(callback);
|
|
24276
|
-
if (domain == null ||
|
|
24276
|
+
if (domain == null || path10 == null || key == null) {
|
|
24277
24277
|
return promiseCallback.resolve(void 0);
|
|
24278
24278
|
}
|
|
24279
|
-
const result = this.idx[domain]?.[
|
|
24279
|
+
const result = this.idx[domain]?.[path10]?.[key];
|
|
24280
24280
|
return promiseCallback.resolve(result);
|
|
24281
24281
|
}
|
|
24282
24282
|
/**
|
|
24283
24283
|
* @internal No doc because this is an overload that supports the implementation
|
|
24284
24284
|
*/
|
|
24285
|
-
findCookies(domain,
|
|
24285
|
+
findCookies(domain, path10, allowSpecialUseDomain = false, callback) {
|
|
24286
24286
|
if (typeof allowSpecialUseDomain === "function") {
|
|
24287
24287
|
callback = allowSpecialUseDomain;
|
|
24288
24288
|
allowSpecialUseDomain = true;
|
|
@@ -24293,7 +24293,7 @@ var MemoryCookieStore = class extends Store {
|
|
|
24293
24293
|
return promiseCallback.resolve([]);
|
|
24294
24294
|
}
|
|
24295
24295
|
let pathMatcher;
|
|
24296
|
-
if (!
|
|
24296
|
+
if (!path10) {
|
|
24297
24297
|
pathMatcher = function matchAll2(domainIndex) {
|
|
24298
24298
|
for (const curPath in domainIndex) {
|
|
24299
24299
|
const pathIndex = domainIndex[curPath];
|
|
@@ -24308,7 +24308,7 @@ var MemoryCookieStore = class extends Store {
|
|
|
24308
24308
|
} else {
|
|
24309
24309
|
pathMatcher = function matchRFC(domainIndex) {
|
|
24310
24310
|
for (const cookiePath in domainIndex) {
|
|
24311
|
-
if (pathMatch(
|
|
24311
|
+
if (pathMatch(path10, cookiePath)) {
|
|
24312
24312
|
const pathIndex = domainIndex[cookiePath];
|
|
24313
24313
|
for (const key in pathIndex) {
|
|
24314
24314
|
const value = pathIndex[key];
|
|
@@ -24336,14 +24336,14 @@ var MemoryCookieStore = class extends Store {
|
|
|
24336
24336
|
*/
|
|
24337
24337
|
putCookie(cookie, callback) {
|
|
24338
24338
|
const promiseCallback = createPromiseCallback(callback);
|
|
24339
|
-
const { domain, path:
|
|
24340
|
-
if (domain == null ||
|
|
24339
|
+
const { domain, path: path10, key } = cookie;
|
|
24340
|
+
if (domain == null || path10 == null || key == null) {
|
|
24341
24341
|
return promiseCallback.resolve(void 0);
|
|
24342
24342
|
}
|
|
24343
24343
|
const domainEntry = this.idx[domain] ?? /* @__PURE__ */ Object.create(null);
|
|
24344
24344
|
this.idx[domain] = domainEntry;
|
|
24345
|
-
const pathEntry = domainEntry[
|
|
24346
|
-
domainEntry[
|
|
24345
|
+
const pathEntry = domainEntry[path10] ?? /* @__PURE__ */ Object.create(null);
|
|
24346
|
+
domainEntry[path10] = pathEntry;
|
|
24347
24347
|
pathEntry[key] = cookie;
|
|
24348
24348
|
return promiseCallback.resolve(void 0);
|
|
24349
24349
|
}
|
|
@@ -24357,20 +24357,20 @@ var MemoryCookieStore = class extends Store {
|
|
|
24357
24357
|
/**
|
|
24358
24358
|
* @internal No doc because this is an overload that supports the implementation
|
|
24359
24359
|
*/
|
|
24360
|
-
removeCookie(domain,
|
|
24360
|
+
removeCookie(domain, path10, key, callback) {
|
|
24361
24361
|
const promiseCallback = createPromiseCallback(callback);
|
|
24362
|
-
delete this.idx[domain]?.[
|
|
24362
|
+
delete this.idx[domain]?.[path10]?.[key];
|
|
24363
24363
|
return promiseCallback.resolve(void 0);
|
|
24364
24364
|
}
|
|
24365
24365
|
/**
|
|
24366
24366
|
* @internal No doc because this is an overload that supports the implementation
|
|
24367
24367
|
*/
|
|
24368
|
-
removeCookies(domain,
|
|
24368
|
+
removeCookies(domain, path10, callback) {
|
|
24369
24369
|
const promiseCallback = createPromiseCallback(callback);
|
|
24370
24370
|
const domainEntry = this.idx[domain];
|
|
24371
24371
|
if (domainEntry) {
|
|
24372
|
-
if (
|
|
24373
|
-
delete domainEntry[
|
|
24372
|
+
if (path10) {
|
|
24373
|
+
delete domainEntry[path10];
|
|
24374
24374
|
} else {
|
|
24375
24375
|
delete this.idx[domain];
|
|
24376
24376
|
}
|
|
@@ -24396,8 +24396,8 @@ var MemoryCookieStore = class extends Store {
|
|
|
24396
24396
|
domains.forEach((domain) => {
|
|
24397
24397
|
const domainEntry = idx[domain] ?? {};
|
|
24398
24398
|
const paths = Object.keys(domainEntry);
|
|
24399
|
-
paths.forEach((
|
|
24400
|
-
const pathEntry = domainEntry[
|
|
24399
|
+
paths.forEach((path10) => {
|
|
24400
|
+
const pathEntry = domainEntry[path10] ?? {};
|
|
24401
24401
|
const keys = Object.keys(pathEntry);
|
|
24402
24402
|
keys.forEach((key) => {
|
|
24403
24403
|
const keyEntry = pathEntry[key];
|
|
@@ -25281,18 +25281,18 @@ function cookieCompare(a, b) {
|
|
|
25281
25281
|
cmp = (a.creationIndex || 0) - (b.creationIndex || 0);
|
|
25282
25282
|
return cmp;
|
|
25283
25283
|
}
|
|
25284
|
-
function defaultPath(
|
|
25285
|
-
if (!
|
|
25284
|
+
function defaultPath(path10) {
|
|
25285
|
+
if (!path10 || path10.slice(0, 1) !== "/") {
|
|
25286
25286
|
return "/";
|
|
25287
25287
|
}
|
|
25288
|
-
if (
|
|
25289
|
-
return
|
|
25288
|
+
if (path10 === "/") {
|
|
25289
|
+
return path10;
|
|
25290
25290
|
}
|
|
25291
|
-
const rightSlash =
|
|
25291
|
+
const rightSlash = path10.lastIndexOf("/");
|
|
25292
25292
|
if (rightSlash === 0) {
|
|
25293
25293
|
return "/";
|
|
25294
25294
|
}
|
|
25295
|
-
return
|
|
25295
|
+
return path10.slice(0, rightSlash);
|
|
25296
25296
|
}
|
|
25297
25297
|
var IP_REGEX_LOWERCASE = /(?:^(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}$)|(?:^(?:(?:[a-f\d]{1,4}:){7}(?:[a-f\d]{1,4}|:)|(?:[a-f\d]{1,4}:){6}(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|:[a-f\d]{1,4}|:)|(?:[a-f\d]{1,4}:){5}(?::(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-f\d]{1,4}){1,2}|:)|(?:[a-f\d]{1,4}:){4}(?:(?::[a-f\d]{1,4}){0,1}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-f\d]{1,4}){1,3}|:)|(?:[a-f\d]{1,4}:){3}(?:(?::[a-f\d]{1,4}){0,2}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-f\d]{1,4}){1,4}|:)|(?:[a-f\d]{1,4}:){2}(?:(?::[a-f\d]{1,4}){0,3}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-f\d]{1,4}){1,5}|:)|(?:[a-f\d]{1,4}:){1}(?:(?::[a-f\d]{1,4}){0,4}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-f\d]{1,4}){1,6}|:)|(?::(?:(?::[a-f\d]{1,4}){0,5}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-f\d]{1,4}){1,7}|:)))$)/;
|
|
25298
25298
|
function domainMatch(domain, cookieDomain, canonicalize) {
|
|
@@ -25694,7 +25694,7 @@ var CookieJar = class _CookieJar {
|
|
|
25694
25694
|
return promiseCallback.reject(parameterError);
|
|
25695
25695
|
}
|
|
25696
25696
|
const host = canonicalDomain(context.hostname);
|
|
25697
|
-
const
|
|
25697
|
+
const path10 = context.pathname || "/";
|
|
25698
25698
|
const potentiallyTrustworthy = isPotentiallyTrustworthy(
|
|
25699
25699
|
url2,
|
|
25700
25700
|
this.allowSecureOnLocal
|
|
@@ -25725,7 +25725,7 @@ var CookieJar = class _CookieJar {
|
|
|
25725
25725
|
return false;
|
|
25726
25726
|
}
|
|
25727
25727
|
}
|
|
25728
|
-
if (!allPaths && typeof c.path === "string" && !pathMatch(
|
|
25728
|
+
if (!allPaths && typeof c.path === "string" && !pathMatch(path10, c.path)) {
|
|
25729
25729
|
return false;
|
|
25730
25730
|
}
|
|
25731
25731
|
if (c.secure && !potentiallyTrustworthy) {
|
|
@@ -25757,7 +25757,7 @@ var CookieJar = class _CookieJar {
|
|
|
25757
25757
|
}
|
|
25758
25758
|
store.findCookies(
|
|
25759
25759
|
host,
|
|
25760
|
-
allPaths ? null :
|
|
25760
|
+
allPaths ? null : path10,
|
|
25761
25761
|
this.allowSpecialUseDomain,
|
|
25762
25762
|
(err, cookies) => {
|
|
25763
25763
|
if (err) {
|
|
@@ -26785,11 +26785,11 @@ function readJsonFile(filePath, workingDir) {
|
|
|
26785
26785
|
};
|
|
26786
26786
|
}
|
|
26787
26787
|
}
|
|
26788
|
-
function setNestedValue(obj,
|
|
26789
|
-
if (!
|
|
26788
|
+
function setNestedValue(obj, path10, value) {
|
|
26789
|
+
if (!path10 || obj === null || obj === void 0 || typeof obj !== "object") {
|
|
26790
26790
|
return false;
|
|
26791
26791
|
}
|
|
26792
|
-
const parts =
|
|
26792
|
+
const parts = path10.replace(/\[(\d+)\]/g, ".$1").split(".").filter((p) => p !== "");
|
|
26793
26793
|
if (parts.length === 0) {
|
|
26794
26794
|
return false;
|
|
26795
26795
|
}
|
|
@@ -27291,8 +27291,8 @@ function bindSequenceArguments(params, args, runtimeVariables) {
|
|
|
27291
27291
|
}
|
|
27292
27292
|
return { variables: result };
|
|
27293
27293
|
}
|
|
27294
|
-
function getVariableValueByPath(
|
|
27295
|
-
const parts =
|
|
27294
|
+
function getVariableValueByPath(path10, variables) {
|
|
27295
|
+
const parts = path10.split(".");
|
|
27296
27296
|
let current = variables;
|
|
27297
27297
|
for (const part of parts) {
|
|
27298
27298
|
if (current === null || current === void 0) {
|
|
@@ -27657,8 +27657,8 @@ function evaluateValueExpression(expr, runtimeVariables) {
|
|
|
27657
27657
|
} else {
|
|
27658
27658
|
return { value: String(varValue), error: `Cannot access path on non-object value` };
|
|
27659
27659
|
}
|
|
27660
|
-
const
|
|
27661
|
-
const parts =
|
|
27660
|
+
const path10 = pathPart.replace(/^\./, "").replace(/\[(\d+)\]/g, ".$1");
|
|
27661
|
+
const parts = path10.split(".").filter((p) => p !== "");
|
|
27662
27662
|
let current = dataToNavigate;
|
|
27663
27663
|
for (const part of parts) {
|
|
27664
27664
|
if (current === null || current === void 0) {
|
|
@@ -27737,8 +27737,8 @@ function resolveBareVariables(text, variables) {
|
|
|
27737
27737
|
if (varName in variables) {
|
|
27738
27738
|
const value = variables[varName];
|
|
27739
27739
|
if (pathPart) {
|
|
27740
|
-
const
|
|
27741
|
-
const nestedValue = getNestedValueFromObject(value,
|
|
27740
|
+
const path10 = pathPart.replace(/^\./, "");
|
|
27741
|
+
const nestedValue = getNestedValueFromObject(value, path10);
|
|
27742
27742
|
return valueToString2(nestedValue);
|
|
27743
27743
|
}
|
|
27744
27744
|
return valueToString2(value);
|
|
@@ -27758,8 +27758,8 @@ function resolveBareVariables(text, variables) {
|
|
|
27758
27758
|
if (varName in variables) {
|
|
27759
27759
|
const value = variables[varName];
|
|
27760
27760
|
if (pathPart) {
|
|
27761
|
-
const
|
|
27762
|
-
return valueToString2(getNestedValueFromObject(value,
|
|
27761
|
+
const path10 = pathPart.replace(/^\./, "");
|
|
27762
|
+
return valueToString2(getNestedValueFromObject(value, path10));
|
|
27763
27763
|
}
|
|
27764
27764
|
return valueToString2(value);
|
|
27765
27765
|
}
|
|
@@ -27796,11 +27796,11 @@ function splitExpressionParts(expr) {
|
|
|
27796
27796
|
}
|
|
27797
27797
|
return parts;
|
|
27798
27798
|
}
|
|
27799
|
-
function getNestedValueFromObject(obj,
|
|
27800
|
-
if (!
|
|
27799
|
+
function getNestedValueFromObject(obj, path10) {
|
|
27800
|
+
if (!path10) {
|
|
27801
27801
|
return obj;
|
|
27802
27802
|
}
|
|
27803
|
-
const parts =
|
|
27803
|
+
const parts = path10.split(/\.|\[(\d+)\]/).filter((p) => p !== "" && p !== void 0);
|
|
27804
27804
|
let current = obj;
|
|
27805
27805
|
for (const part of parts) {
|
|
27806
27806
|
if (current === null || current === void 0) {
|
|
@@ -28145,24 +28145,24 @@ function extractCaptureDirectives(content) {
|
|
|
28145
28145
|
for (const line2 of content.split("\n")) {
|
|
28146
28146
|
const match = line2.trim().match(captureRegex);
|
|
28147
28147
|
if (match) {
|
|
28148
|
-
let
|
|
28149
|
-
if (
|
|
28150
|
-
|
|
28148
|
+
let path10 = match[3] || "";
|
|
28149
|
+
if (path10.startsWith(".")) {
|
|
28150
|
+
path10 = path10.substring(1);
|
|
28151
28151
|
}
|
|
28152
28152
|
captures.push({
|
|
28153
28153
|
varName: match[1],
|
|
28154
28154
|
afterRequest: parseInt(match[2], 10),
|
|
28155
|
-
path:
|
|
28155
|
+
path: path10
|
|
28156
28156
|
});
|
|
28157
28157
|
}
|
|
28158
28158
|
}
|
|
28159
28159
|
return captures;
|
|
28160
28160
|
}
|
|
28161
|
-
function getValueByPath(response,
|
|
28162
|
-
if (!
|
|
28161
|
+
function getValueByPath(response, path10) {
|
|
28162
|
+
if (!path10) {
|
|
28163
28163
|
return void 0;
|
|
28164
28164
|
}
|
|
28165
|
-
const parts =
|
|
28165
|
+
const parts = path10.replace(/\[(\d+)\]/g, ".$1").split(".").filter((p) => p !== "");
|
|
28166
28166
|
if (parts.length === 0) {
|
|
28167
28167
|
return void 0;
|
|
28168
28168
|
}
|
|
@@ -28203,7 +28203,7 @@ function getValueByPath(response, path9) {
|
|
|
28203
28203
|
return void 0;
|
|
28204
28204
|
}
|
|
28205
28205
|
}
|
|
28206
|
-
async function runSequenceWithJar(sequenceContent, fileVariables, cookieJar, workingDir, fullDocumentText, onProgress, callStack, sequenceArgs, apiDefinitions, tagFilterOptions, sequenceSources, executionContext) {
|
|
28206
|
+
async function runSequenceWithJar(sequenceContent, fileVariables, cookieJar, workingDir, fullDocumentText, onProgress, callStack, sequenceArgs, apiDefinitions, tagFilterOptions, sequenceSources, executionContext, debugHooks) {
|
|
28207
28207
|
const startTime = Date.now();
|
|
28208
28208
|
const responses = [];
|
|
28209
28209
|
const scriptResults = [];
|
|
@@ -28246,566 +28246,108 @@ async function runSequenceWithJar(sequenceContent, fileVariables, cookieJar, wor
|
|
|
28246
28246
|
let requestIndex = 0;
|
|
28247
28247
|
const ifStack = [];
|
|
28248
28248
|
const shouldSkip = () => ifStack.length > 0 && ifStack.some((v) => !v);
|
|
28249
|
-
|
|
28250
|
-
const
|
|
28251
|
-
|
|
28252
|
-
|
|
28253
|
-
|
|
28254
|
-
|
|
28255
|
-
|
|
28256
|
-
|
|
28257
|
-
|
|
28258
|
-
|
|
28259
|
-
|
|
28260
|
-
|
|
28261
|
-
|
|
28262
|
-
|
|
28263
|
-
|
|
28264
|
-
|
|
28265
|
-
orderedSteps.push(stepResult);
|
|
28266
|
-
reportProgress(stepIdx, "if", `if ${step.content} \u2192 ${conditionMet}`, stepResult);
|
|
28267
|
-
}
|
|
28268
|
-
continue;
|
|
28269
|
-
}
|
|
28270
|
-
if (step.type === "endif") {
|
|
28271
|
-
if (ifStack.length > 0) {
|
|
28272
|
-
ifStack.pop();
|
|
28273
|
-
}
|
|
28274
|
-
continue;
|
|
28275
|
-
}
|
|
28276
|
-
if (shouldSkip()) {
|
|
28277
|
-
continue;
|
|
28278
|
-
}
|
|
28279
|
-
if (step.type === "assertion") {
|
|
28280
|
-
const parsed = parseAssertCommand(substituteVariables(step.content, runtimeVariables));
|
|
28281
|
-
if (!parsed) {
|
|
28282
|
-
errors.push(`Step ${stepIdx + 1}: Invalid assert command: ${step.content}`);
|
|
28283
|
-
return {
|
|
28284
|
-
name: "",
|
|
28285
|
-
success: false,
|
|
28286
|
-
responses,
|
|
28287
|
-
scriptResults,
|
|
28288
|
-
assertionResults,
|
|
28289
|
-
steps: orderedSteps,
|
|
28290
|
-
errors,
|
|
28291
|
-
duration: Date.now() - startTime
|
|
28292
|
-
};
|
|
28293
|
-
}
|
|
28294
|
-
const result = evaluateAssertion(parsed, responses, runtimeVariables, getValueByPath, responseIndexToVariable, workingDir);
|
|
28295
|
-
assertionResults.push(result);
|
|
28296
|
-
const stepResult = {
|
|
28297
|
-
type: "assertion",
|
|
28298
|
-
stepIndex: stepIdx,
|
|
28299
|
-
assertion: result,
|
|
28300
|
-
lineNumber: step.lineNumber
|
|
28301
|
-
};
|
|
28302
|
-
orderedSteps.push(stepResult);
|
|
28303
|
-
const statusIcon = result.passed ? "\u2713" : "\u2717";
|
|
28304
|
-
reportProgress(stepIdx, "assertion", `${statusIcon} assert ${result.expression}`, stepResult);
|
|
28305
|
-
if (!result.passed) {
|
|
28306
|
-
const failMessage = result.message ? `Assertion failed: ${result.message}` : `Assertion failed: ${result.expression}`;
|
|
28307
|
-
errors.push(failMessage);
|
|
28308
|
-
if (result.error) {
|
|
28309
|
-
errors.push(` Error: ${result.error}`);
|
|
28310
|
-
} else {
|
|
28311
|
-
errors.push(` Expected: ${result.rightExpression ?? result.operator}`);
|
|
28312
|
-
errors.push(` Actual: ${JSON.stringify(result.leftValue)}`);
|
|
28313
|
-
}
|
|
28314
|
-
return {
|
|
28315
|
-
name: "",
|
|
28316
|
-
success: false,
|
|
28317
|
-
responses,
|
|
28318
|
-
scriptResults,
|
|
28319
|
-
assertionResults,
|
|
28320
|
-
steps: orderedSteps,
|
|
28321
|
-
errors,
|
|
28322
|
-
duration: Date.now() - startTime
|
|
28323
|
-
};
|
|
28324
|
-
}
|
|
28325
|
-
continue;
|
|
28326
|
-
}
|
|
28327
|
-
if (step.type === "print") {
|
|
28328
|
-
const parsed = parsePrintCommand(step.content);
|
|
28329
|
-
const titleResolved = resolveBareVariables(parsed.title, runtimeVariables);
|
|
28330
|
-
const title = substituteVariables(titleResolved, runtimeVariables);
|
|
28331
|
-
const bodyResolved = parsed.body ? resolveBareVariables(parsed.body, runtimeVariables) : void 0;
|
|
28332
|
-
const body = bodyResolved ? substituteVariables(bodyResolved, runtimeVariables) : void 0;
|
|
28333
|
-
const stepResult = {
|
|
28334
|
-
type: "print",
|
|
28335
|
-
stepIndex: stepIdx,
|
|
28336
|
-
print: {
|
|
28337
|
-
title,
|
|
28338
|
-
body,
|
|
28339
|
-
timestamp: Date.now() - startTime
|
|
28340
|
-
}
|
|
28341
|
-
};
|
|
28342
|
-
orderedSteps.push(stepResult);
|
|
28343
|
-
reportProgress(stepIdx, "print", `print: ${title}`, stepResult);
|
|
28344
|
-
continue;
|
|
28345
|
-
}
|
|
28346
|
-
if (step.type === "wait") {
|
|
28347
|
-
const durationMs = parseWaitCommand(step.content);
|
|
28348
|
-
reportProgress(stepIdx, "wait", `wait: ${durationMs}ms`);
|
|
28349
|
-
await sleep2(durationMs);
|
|
28350
|
-
const stepResult = {
|
|
28351
|
-
type: "print",
|
|
28352
|
-
stepIndex: stepIdx,
|
|
28353
|
-
print: {
|
|
28354
|
-
title: `Waited ${durationMs >= 1e3 ? durationMs / 1e3 + "s" : durationMs + "ms"}`,
|
|
28355
|
-
timestamp: Date.now() - startTime
|
|
28356
|
-
}
|
|
28357
|
-
};
|
|
28358
|
-
orderedSteps.push(stepResult);
|
|
28359
|
-
continue;
|
|
28360
|
-
}
|
|
28361
|
-
if (step.type === "json") {
|
|
28362
|
-
const bareResolved = resolveBareVariables(step.content, runtimeVariables);
|
|
28363
|
-
const parsed = parseJsonCommand(substituteVariables(bareResolved, runtimeVariables));
|
|
28364
|
-
if (!parsed) {
|
|
28365
|
-
errors.push(`Step ${stepIdx + 1}: Invalid json command: ${step.content}`);
|
|
28366
|
-
return {
|
|
28367
|
-
name: "",
|
|
28368
|
-
success: false,
|
|
28369
|
-
responses,
|
|
28370
|
-
scriptResults,
|
|
28371
|
-
assertionResults,
|
|
28372
|
-
steps: orderedSteps,
|
|
28373
|
-
errors,
|
|
28374
|
-
duration: Date.now() - startTime
|
|
28375
|
-
};
|
|
28376
|
-
}
|
|
28377
|
-
const result = readJsonFile(parsed.filePath, workingDir);
|
|
28378
|
-
const stepResult = {
|
|
28379
|
-
type: "json",
|
|
28380
|
-
stepIndex: stepIdx,
|
|
28381
|
-
json: {
|
|
28382
|
-
varName: parsed.varName,
|
|
28383
|
-
filePath: result.filePath,
|
|
28384
|
-
success: result.success,
|
|
28385
|
-
error: result.error,
|
|
28386
|
-
timestamp: Date.now() - startTime
|
|
28387
|
-
}
|
|
28388
|
-
};
|
|
28389
|
-
orderedSteps.push(stepResult);
|
|
28390
|
-
if (!result.success) {
|
|
28391
|
-
errors.push(`Failed to load JSON file: ${result.error}`);
|
|
28392
|
-
reportProgress(stepIdx, "json", `json: ${parsed.varName} \u2717 ${result.error}`, stepResult);
|
|
28393
|
-
return {
|
|
28394
|
-
name: "",
|
|
28395
|
-
success: false,
|
|
28396
|
-
responses,
|
|
28397
|
-
scriptResults,
|
|
28398
|
-
assertionResults,
|
|
28399
|
-
steps: orderedSteps,
|
|
28400
|
-
errors,
|
|
28401
|
-
duration: Date.now() - startTime
|
|
28402
|
-
};
|
|
28403
|
-
}
|
|
28404
|
-
runtimeVariables[parsed.varName] = JSON.stringify(result.data);
|
|
28405
|
-
reportProgress(stepIdx, "json", `json: ${parsed.varName} = ${parsed.filePath}`, stepResult);
|
|
28406
|
-
continue;
|
|
28249
|
+
const resolveDebugStepLocation = (step) => {
|
|
28250
|
+
const sequenceName = executionContext?.sequenceName;
|
|
28251
|
+
const indexed = sequenceName ? executionContext?.sequenceLocationIndex?.get(sequenceName.toLowerCase()) : void 0;
|
|
28252
|
+
const startLine = executionContext?.sequenceStartLine ?? indexed?.startLine;
|
|
28253
|
+
return {
|
|
28254
|
+
filePath: executionContext?.filePath ?? indexed?.filePath,
|
|
28255
|
+
sequenceName,
|
|
28256
|
+
declarationLine: indexed?.declarationLine ?? executionContext?.sequenceStartLine,
|
|
28257
|
+
absoluteLine: startLine !== void 0 ? startLine + 1 + step.lineNumber : void 0,
|
|
28258
|
+
relativeLine: step.lineNumber,
|
|
28259
|
+
nestingDepth
|
|
28260
|
+
};
|
|
28261
|
+
};
|
|
28262
|
+
const emitBeforeStep = async (step, stepIdx) => {
|
|
28263
|
+
if (!debugHooks?.beforeStep) {
|
|
28264
|
+
return;
|
|
28407
28265
|
}
|
|
28408
|
-
|
|
28409
|
-
|
|
28410
|
-
|
|
28411
|
-
|
|
28412
|
-
|
|
28413
|
-
|
|
28414
|
-
|
|
28415
|
-
|
|
28416
|
-
|
|
28417
|
-
|
|
28418
|
-
|
|
28419
|
-
|
|
28420
|
-
|
|
28421
|
-
};
|
|
28422
|
-
}
|
|
28423
|
-
if (!(parsed.varName in runtimeVariables)) {
|
|
28424
|
-
errors.push(`Step ${stepIdx + 1}: Variable '${parsed.varName}' is not defined`);
|
|
28425
|
-
return {
|
|
28426
|
-
name: "",
|
|
28427
|
-
success: false,
|
|
28428
|
-
responses,
|
|
28429
|
-
scriptResults,
|
|
28430
|
-
assertionResults,
|
|
28431
|
-
steps: orderedSteps,
|
|
28432
|
-
errors,
|
|
28433
|
-
duration: Date.now() - startTime
|
|
28434
|
-
};
|
|
28435
|
-
}
|
|
28436
|
-
let jsonObj;
|
|
28437
|
-
try {
|
|
28438
|
-
jsonObj = JSON.parse(runtimeVariables[parsed.varName]);
|
|
28439
|
-
} catch {
|
|
28440
|
-
errors.push(`Step ${stepIdx + 1}: Variable '${parsed.varName}' is not a valid JSON object`);
|
|
28441
|
-
return {
|
|
28442
|
-
name: "",
|
|
28443
|
-
success: false,
|
|
28444
|
-
responses,
|
|
28445
|
-
scriptResults,
|
|
28446
|
-
assertionResults,
|
|
28447
|
-
steps: orderedSteps,
|
|
28448
|
-
errors,
|
|
28449
|
-
duration: Date.now() - startTime
|
|
28450
|
-
};
|
|
28451
|
-
}
|
|
28452
|
-
const valueTrimmed = parsed.value.trim();
|
|
28453
|
-
const bareVarMatch = valueTrimmed.match(/^([a-zA-Z_][a-zA-Z0-9_]*)((?:\.[a-zA-Z_][a-zA-Z0-9_]*|\[\d+\])*)$/);
|
|
28454
|
-
let newValue;
|
|
28455
|
-
if (bareVarMatch && bareVarMatch[1] in runtimeVariables) {
|
|
28456
|
-
const varName = bareVarMatch[1];
|
|
28457
|
-
const pathPart = bareVarMatch[2] || "";
|
|
28458
|
-
let value = runtimeVariables[varName];
|
|
28459
|
-
if (typeof value === "string") {
|
|
28460
|
-
try {
|
|
28461
|
-
const parsed2 = JSON.parse(value);
|
|
28462
|
-
if (typeof parsed2 === "object" && parsed2 !== null) {
|
|
28463
|
-
value = parsed2;
|
|
28464
|
-
}
|
|
28465
|
-
} catch {
|
|
28466
|
-
}
|
|
28467
|
-
}
|
|
28468
|
-
if (pathPart) {
|
|
28469
|
-
const path9 = pathPart.replace(/^\./, "");
|
|
28470
|
-
newValue = getNestedValueFromObject(value, path9);
|
|
28471
|
-
} else {
|
|
28472
|
-
newValue = value;
|
|
28473
|
-
}
|
|
28474
|
-
} else {
|
|
28475
|
-
const bareResolvedValue = resolveBareVariables(parsed.value, runtimeVariables);
|
|
28476
|
-
const resolvedValue = substituteVariables(bareResolvedValue, runtimeVariables);
|
|
28477
|
-
newValue = resolvedValue;
|
|
28478
|
-
try {
|
|
28479
|
-
newValue = JSON.parse(resolvedValue);
|
|
28480
|
-
} catch {
|
|
28481
|
-
}
|
|
28482
|
-
}
|
|
28483
|
-
const success = setNestedValue(jsonObj, parsed.propertyPath, newValue);
|
|
28484
|
-
if (!success) {
|
|
28485
|
-
errors.push(`Step ${stepIdx + 1}: Failed to set property '${parsed.propertyPath}' on '${parsed.varName}'`);
|
|
28486
|
-
return {
|
|
28487
|
-
name: "",
|
|
28488
|
-
success: false,
|
|
28489
|
-
responses,
|
|
28490
|
-
scriptResults,
|
|
28491
|
-
assertionResults,
|
|
28492
|
-
steps: orderedSteps,
|
|
28493
|
-
errors,
|
|
28494
|
-
duration: Date.now() - startTime
|
|
28495
|
-
};
|
|
28496
|
-
}
|
|
28497
|
-
runtimeVariables[parsed.varName] = JSON.stringify(jsonObj);
|
|
28498
|
-
reportProgress(stepIdx, "propAssign", `${parsed.varName}.${parsed.propertyPath} = ${parsed.value}`, void 0);
|
|
28499
|
-
continue;
|
|
28266
|
+
await debugHooks.beforeStep({
|
|
28267
|
+
stepType: step.type,
|
|
28268
|
+
stepContent: step.content,
|
|
28269
|
+
stepIndex: stepIdx,
|
|
28270
|
+
totalSteps,
|
|
28271
|
+
location: resolveDebugStepLocation(step),
|
|
28272
|
+
runtimeVariables,
|
|
28273
|
+
responses
|
|
28274
|
+
});
|
|
28275
|
+
};
|
|
28276
|
+
const emitAfterStep = async (step, stepIdx) => {
|
|
28277
|
+
if (!debugHooks?.afterStep) {
|
|
28278
|
+
return;
|
|
28500
28279
|
}
|
|
28501
|
-
|
|
28502
|
-
|
|
28503
|
-
|
|
28504
|
-
|
|
28505
|
-
|
|
28506
|
-
|
|
28507
|
-
|
|
28508
|
-
|
|
28509
|
-
|
|
28510
|
-
|
|
28511
|
-
|
|
28512
|
-
|
|
28513
|
-
|
|
28514
|
-
};
|
|
28515
|
-
}
|
|
28516
|
-
const result = evaluateValueExpression(parsed.valueExpr, runtimeVariables);
|
|
28517
|
-
if (result.error) {
|
|
28518
|
-
errors.push(`Step ${stepIdx + 1}: ${result.error}`);
|
|
28519
|
-
return {
|
|
28520
|
-
name: "",
|
|
28521
|
-
success: false,
|
|
28522
|
-
responses,
|
|
28523
|
-
scriptResults,
|
|
28524
|
-
assertionResults,
|
|
28525
|
-
steps: orderedSteps,
|
|
28526
|
-
errors,
|
|
28527
|
-
duration: Date.now() - startTime
|
|
28528
|
-
};
|
|
28529
|
-
}
|
|
28530
|
-
runtimeVariables[parsed.varName] = result.value;
|
|
28531
|
-
reportProgress(stepIdx, "propAssign", `var ${parsed.varName} = ${result.value}`, void 0);
|
|
28532
|
-
continue;
|
|
28280
|
+
await debugHooks.afterStep({
|
|
28281
|
+
stepType: step.type,
|
|
28282
|
+
stepContent: step.content,
|
|
28283
|
+
stepIndex: stepIdx,
|
|
28284
|
+
totalSteps,
|
|
28285
|
+
location: resolveDebugStepLocation(step),
|
|
28286
|
+
runtimeVariables,
|
|
28287
|
+
responses
|
|
28288
|
+
});
|
|
28289
|
+
};
|
|
28290
|
+
const emitFailure = async (message, step, stepIdx) => {
|
|
28291
|
+
if (!debugHooks?.onFailure) {
|
|
28292
|
+
return;
|
|
28533
28293
|
}
|
|
28534
|
-
|
|
28535
|
-
|
|
28536
|
-
|
|
28537
|
-
|
|
28538
|
-
|
|
28539
|
-
|
|
28540
|
-
|
|
28541
|
-
|
|
28542
|
-
|
|
28543
|
-
|
|
28544
|
-
|
|
28545
|
-
|
|
28546
|
-
|
|
28547
|
-
|
|
28548
|
-
|
|
28549
|
-
|
|
28550
|
-
|
|
28551
|
-
|
|
28552
|
-
|
|
28553
|
-
|
|
28294
|
+
await debugHooks.onFailure({
|
|
28295
|
+
message,
|
|
28296
|
+
stepIndex: stepIdx,
|
|
28297
|
+
location: step ? resolveDebugStepLocation(step) : void 0,
|
|
28298
|
+
runtimeVariables,
|
|
28299
|
+
responses
|
|
28300
|
+
});
|
|
28301
|
+
};
|
|
28302
|
+
if (debugHooks?.onSequenceEnter) {
|
|
28303
|
+
await debugHooks.onSequenceEnter({
|
|
28304
|
+
sequenceName: executionContext?.sequenceName,
|
|
28305
|
+
filePath: executionContext?.filePath,
|
|
28306
|
+
declarationLine: executionContext?.sequenceStartLine,
|
|
28307
|
+
nestingDepth,
|
|
28308
|
+
runtimeVariables,
|
|
28309
|
+
responses
|
|
28310
|
+
});
|
|
28311
|
+
}
|
|
28312
|
+
try {
|
|
28313
|
+
for (let stepIdx = 0; stepIdx < steps.length; stepIdx++) {
|
|
28314
|
+
const step = steps[stepIdx];
|
|
28315
|
+
await emitBeforeStep(step, stepIdx);
|
|
28554
28316
|
try {
|
|
28555
|
-
|
|
28556
|
-
|
|
28557
|
-
|
|
28558
|
-
if (endpoint && apiDefinitions) {
|
|
28559
|
-
const paramsStr = endpointMatch[2] || "";
|
|
28560
|
-
const headerGroupsStr = endpointMatch[3]?.trim() || "";
|
|
28561
|
-
const paramTokens = paramsStr ? paramsStr.split(",").map((p) => p.trim()) : [];
|
|
28562
|
-
const params = {};
|
|
28563
|
-
const isNamedSyntax = paramTokens.length > 0 && paramTokens[0].includes(":");
|
|
28564
|
-
if (isNamedSyntax) {
|
|
28565
|
-
for (const token of paramTokens) {
|
|
28566
|
-
const kvMatch = token.match(/^([a-zA-Z_][a-zA-Z0-9_]*)\s*:\s*(.+)$/);
|
|
28567
|
-
if (kvMatch) {
|
|
28568
|
-
const paramName = kvMatch[1];
|
|
28569
|
-
let paramValue = kvMatch[2].trim().replace(/^["']|["']$/g, "");
|
|
28570
|
-
const bareResolved = resolveBareVariables(paramValue, runtimeVariables);
|
|
28571
|
-
params[paramName] = substituteVariables(bareResolved, runtimeVariables);
|
|
28572
|
-
}
|
|
28573
|
-
}
|
|
28317
|
+
if (step.type === "if") {
|
|
28318
|
+
if (shouldSkip()) {
|
|
28319
|
+
ifStack.push(false);
|
|
28574
28320
|
} else {
|
|
28575
|
-
|
|
28576
|
-
|
|
28577
|
-
|
|
28578
|
-
|
|
28579
|
-
|
|
28580
|
-
|
|
28581
|
-
|
|
28582
|
-
|
|
28583
|
-
let pathWithVars = substituteVariables(endpoint.path, runtimeVariables);
|
|
28584
|
-
for (const paramName of endpoint.parameters) {
|
|
28585
|
-
const value = params[paramName];
|
|
28586
|
-
if (value !== void 0) {
|
|
28587
|
-
pathWithVars = pathWithVars.replace(`{${paramName}}`, value);
|
|
28588
|
-
}
|
|
28589
|
-
}
|
|
28590
|
-
resolvedUrl = pathWithVars;
|
|
28591
|
-
if (headerGroupsStr) {
|
|
28592
|
-
const headerGroupNames = headerGroupsStr.split(/\s+/).filter((n) => n);
|
|
28593
|
-
for (const groupName of headerGroupNames) {
|
|
28594
|
-
const group = getHeaderGroup(
|
|
28595
|
-
{ headerGroups: apiDefinitions.headerGroups, endpoints: apiDefinitions.endpoints },
|
|
28596
|
-
groupName
|
|
28597
|
-
);
|
|
28598
|
-
if (group) {
|
|
28599
|
-
const groupHeaders = resolveHeaderValues(group, runtimeVariables);
|
|
28600
|
-
Object.assign(resolvedHeaders, groupHeaders);
|
|
28321
|
+
const conditionMet = evaluateIfCondition(step.content, responses, runtimeVariables, getValueByPath);
|
|
28322
|
+
ifStack.push(conditionMet);
|
|
28323
|
+
const stepResult = {
|
|
28324
|
+
type: "print",
|
|
28325
|
+
stepIndex: stepIdx,
|
|
28326
|
+
print: {
|
|
28327
|
+
title: `if ${step.content}: ${conditionMet ? "true" : "false"}`,
|
|
28328
|
+
timestamp: Date.now() - startTime
|
|
28601
28329
|
}
|
|
28602
|
-
}
|
|
28603
|
-
|
|
28604
|
-
|
|
28605
|
-
} else {
|
|
28606
|
-
resolvedUrl = substituteVariables(parsed.url, runtimeVariables);
|
|
28607
|
-
requestDescription = `${parsed.method} ${resolvedUrl}`;
|
|
28608
|
-
}
|
|
28609
|
-
let requestText = `${parsed.method} ${resolvedUrl}`;
|
|
28610
|
-
if (Object.keys(resolvedHeaders).length > 0) {
|
|
28611
|
-
const headerLines = Object.entries(resolvedHeaders).map(([k, v]) => `${k}: ${v}`);
|
|
28612
|
-
requestText += "\n" + headerLines.join("\n");
|
|
28613
|
-
}
|
|
28614
|
-
const contentLines = step.content.split("\n");
|
|
28615
|
-
if (contentLines.length > 1) {
|
|
28616
|
-
const extraLines = contentLines.slice(1).map((line2) => substituteVariables(line2, runtimeVariables));
|
|
28617
|
-
const hasExplicitBlank = extraLines.some((line2) => line2.trim() === "");
|
|
28618
|
-
const firstNonEmpty = extraLines.find((line2) => line2.trim() !== "");
|
|
28619
|
-
const startsWithHeader = firstNonEmpty ? /^[A-Za-z0-9\-_]+\s*:/.test(firstNonEmpty.trim()) : false;
|
|
28620
|
-
if (hasExplicitBlank || startsWithHeader) {
|
|
28621
|
-
requestText += "\n" + extraLines.join("\n");
|
|
28622
|
-
} else {
|
|
28623
|
-
requestText += "\n\n" + extraLines.join("\n");
|
|
28624
|
-
}
|
|
28625
|
-
}
|
|
28626
|
-
const requestParsed = parserHttpRequest(requestText, runtimeVariables);
|
|
28627
|
-
validatePreparedRequest(
|
|
28628
|
-
requestParsed,
|
|
28629
|
-
buildRequestValidationContext(stepIdx + 1, requestParsed.method, requestParsed.url, `var ${parsed.varName}`)
|
|
28630
|
-
);
|
|
28631
|
-
const retryOpts = parsed.retryCount ? {
|
|
28632
|
-
retryCount: parsed.retryCount,
|
|
28633
|
-
backoffMs: parsed.backoffMs || 1e3,
|
|
28634
|
-
onRetry: (attempt, total, error, waitMs) => {
|
|
28635
|
-
reportProgress(stepIdx, "request", `[Retry ${attempt}/${total}] ${requestDescription} - waiting ${waitMs}ms`, void 0);
|
|
28636
|
-
}
|
|
28637
|
-
} : void 0;
|
|
28638
|
-
const response = cookieJar ? await sendRequestWithJar(requestParsed, cookieJar, retryOpts) : await sendRequest(requestParsed, retryOpts);
|
|
28639
|
-
addResponse(response);
|
|
28640
|
-
responseIndexToVariable.set(responses.length, parsed.varName);
|
|
28641
|
-
runtimeVariables[parsed.varName] = response;
|
|
28642
|
-
const stepResult = {
|
|
28643
|
-
type: "request",
|
|
28644
|
-
stepIndex: stepIdx,
|
|
28645
|
-
response,
|
|
28646
|
-
requestMethod: parsed.method,
|
|
28647
|
-
requestUrl: resolvedUrl,
|
|
28648
|
-
variableName: parsed.varName
|
|
28649
|
-
};
|
|
28650
|
-
orderedSteps.push(stepResult);
|
|
28651
|
-
reportProgress(stepIdx, "request", `var ${parsed.varName} = ${requestDescription}`, stepResult);
|
|
28652
|
-
const relevantCaptures = captures.filter((c) => c.afterRequest === requestIndex);
|
|
28653
|
-
for (const capture of relevantCaptures) {
|
|
28654
|
-
const value = getValueByPath(response, capture.path);
|
|
28655
|
-
if (value !== void 0) {
|
|
28656
|
-
runtimeVariables[capture.varName] = value;
|
|
28657
|
-
} else {
|
|
28658
|
-
errors.push(`Warning: Could not capture ${capture.varName} from $${requestIndex}.${capture.path}`);
|
|
28330
|
+
};
|
|
28331
|
+
orderedSteps.push(stepResult);
|
|
28332
|
+
reportProgress(stepIdx, "if", `if ${step.content} \u2192 ${conditionMet}`, stepResult);
|
|
28659
28333
|
}
|
|
28334
|
+
continue;
|
|
28660
28335
|
}
|
|
28661
|
-
|
|
28662
|
-
|
|
28663
|
-
|
|
28664
|
-
buildRequestValidationContext(stepIdx + 1, void 0, void 0, `var ${parsed.varName}`)
|
|
28665
|
-
);
|
|
28666
|
-
let errorDetails = `Request failed for var ${parsed.varName}:
|
|
28667
|
-
${indentMultiline(userMessage)}`;
|
|
28668
|
-
if (requestDescription && !/\nRequest:\s/.test(userMessage)) {
|
|
28669
|
-
errorDetails += `
|
|
28670
|
-
Request: ${requestDescription}`;
|
|
28671
|
-
}
|
|
28672
|
-
errors.push(errorDetails);
|
|
28673
|
-
return {
|
|
28674
|
-
name: "",
|
|
28675
|
-
success: false,
|
|
28676
|
-
responses,
|
|
28677
|
-
scriptResults,
|
|
28678
|
-
assertionResults,
|
|
28679
|
-
steps: orderedSteps,
|
|
28680
|
-
errors,
|
|
28681
|
-
duration: Date.now() - startTime
|
|
28682
|
-
};
|
|
28683
|
-
}
|
|
28684
|
-
continue;
|
|
28685
|
-
}
|
|
28686
|
-
if (step.type === "script") {
|
|
28687
|
-
const parsed = parseRunCommand(substituteVariables(step.content, runtimeVariables));
|
|
28688
|
-
if (!parsed) {
|
|
28689
|
-
errors.push(`Step ${stepIdx + 1}: Invalid run command: ${step.content}`);
|
|
28690
|
-
return {
|
|
28691
|
-
name: "",
|
|
28692
|
-
success: false,
|
|
28693
|
-
responses,
|
|
28694
|
-
scriptResults,
|
|
28695
|
-
assertionResults,
|
|
28696
|
-
steps: orderedSteps,
|
|
28697
|
-
errors,
|
|
28698
|
-
duration: Date.now() - startTime
|
|
28699
|
-
};
|
|
28700
|
-
}
|
|
28701
|
-
const substitutedArgs = parsed.args.map((arg) => {
|
|
28702
|
-
const bareResolved = resolveBareVariables(arg, runtimeVariables);
|
|
28703
|
-
return substituteVariables(bareResolved, runtimeVariables);
|
|
28704
|
-
});
|
|
28705
|
-
const substitutedPath = substituteVariables(parsed.scriptPath, runtimeVariables);
|
|
28706
|
-
try {
|
|
28707
|
-
const result = await runScript(
|
|
28708
|
-
parsed.type,
|
|
28709
|
-
substitutedPath,
|
|
28710
|
-
substitutedArgs,
|
|
28711
|
-
workingDir || process.cwd(),
|
|
28712
|
-
runtimeVariables,
|
|
28713
|
-
parsed.captureAs
|
|
28714
|
-
);
|
|
28715
|
-
scriptResults.push(result);
|
|
28716
|
-
const stepResult = {
|
|
28717
|
-
type: "script",
|
|
28718
|
-
stepIndex: stepIdx,
|
|
28719
|
-
script: result
|
|
28720
|
-
};
|
|
28721
|
-
orderedSteps.push(stepResult);
|
|
28722
|
-
reportProgress(stepIdx, "script", `run ${parsed.type} ${substitutedPath}`, stepResult);
|
|
28723
|
-
if (!result.success) {
|
|
28724
|
-
errors.push(`Script failed (exit ${result.exitCode}): ${result.error || result.output}`);
|
|
28725
|
-
return {
|
|
28726
|
-
name: "",
|
|
28727
|
-
success: false,
|
|
28728
|
-
responses,
|
|
28729
|
-
scriptResults,
|
|
28730
|
-
assertionResults,
|
|
28731
|
-
steps: orderedSteps,
|
|
28732
|
-
errors,
|
|
28733
|
-
duration: Date.now() - startTime
|
|
28734
|
-
};
|
|
28735
|
-
}
|
|
28736
|
-
if (parsed.captureAs) {
|
|
28737
|
-
let outputValue = result.output;
|
|
28738
|
-
try {
|
|
28739
|
-
const jsonParsed = JSON.parse(result.output);
|
|
28740
|
-
outputValue = jsonParsed;
|
|
28741
|
-
} catch {
|
|
28336
|
+
if (step.type === "endif") {
|
|
28337
|
+
if (ifStack.length > 0) {
|
|
28338
|
+
ifStack.pop();
|
|
28742
28339
|
}
|
|
28743
|
-
|
|
28340
|
+
continue;
|
|
28744
28341
|
}
|
|
28745
|
-
|
|
28746
|
-
|
|
28747
|
-
return {
|
|
28748
|
-
name: "",
|
|
28749
|
-
success: false,
|
|
28750
|
-
responses,
|
|
28751
|
-
scriptResults,
|
|
28752
|
-
assertionResults,
|
|
28753
|
-
steps: orderedSteps,
|
|
28754
|
-
errors,
|
|
28755
|
-
duration: Date.now() - startTime
|
|
28756
|
-
};
|
|
28757
|
-
}
|
|
28758
|
-
} else if (step.type === "namedRequest") {
|
|
28759
|
-
const parsed = parseRunNamedRequestCommand(step.content);
|
|
28760
|
-
if (!parsed) {
|
|
28761
|
-
errors.push(`Invalid run command: ${step.content}`);
|
|
28762
|
-
return {
|
|
28763
|
-
name: "",
|
|
28764
|
-
success: false,
|
|
28765
|
-
responses,
|
|
28766
|
-
scriptResults,
|
|
28767
|
-
assertionResults,
|
|
28768
|
-
steps: orderedSteps,
|
|
28769
|
-
errors,
|
|
28770
|
-
duration: Date.now() - startTime
|
|
28771
|
-
};
|
|
28772
|
-
}
|
|
28773
|
-
const { name: targetName, args: runArgs } = parsed;
|
|
28774
|
-
if (!fullDocumentText) {
|
|
28775
|
-
errors.push(`Cannot run "${targetName}": full document text not provided`);
|
|
28776
|
-
return {
|
|
28777
|
-
name: "",
|
|
28778
|
-
success: false,
|
|
28779
|
-
responses,
|
|
28780
|
-
scriptResults,
|
|
28781
|
-
assertionResults,
|
|
28782
|
-
steps: orderedSteps,
|
|
28783
|
-
errors,
|
|
28784
|
-
duration: Date.now() - startTime
|
|
28785
|
-
};
|
|
28786
|
-
}
|
|
28787
|
-
const allSequences = extractSequences(fullDocumentText);
|
|
28788
|
-
const targetSequence = allSequences.find((s) => s.name === targetName);
|
|
28789
|
-
if (targetSequence) {
|
|
28790
|
-
const currentCallStack = callStack || [];
|
|
28791
|
-
if (currentCallStack.includes(targetName)) {
|
|
28792
|
-
errors.push(`Circular reference detected: ${[...currentCallStack, targetName].join(" \u2192 ")}`);
|
|
28793
|
-
return {
|
|
28794
|
-
name: "",
|
|
28795
|
-
success: false,
|
|
28796
|
-
responses,
|
|
28797
|
-
scriptResults,
|
|
28798
|
-
assertionResults,
|
|
28799
|
-
steps: orderedSteps,
|
|
28800
|
-
errors,
|
|
28801
|
-
duration: Date.now() - startTime
|
|
28802
|
-
};
|
|
28342
|
+
if (shouldSkip()) {
|
|
28343
|
+
continue;
|
|
28803
28344
|
}
|
|
28804
|
-
|
|
28805
|
-
|
|
28806
|
-
|
|
28807
|
-
|
|
28808
|
-
errors.push(
|
|
28345
|
+
if (step.type === "assertion") {
|
|
28346
|
+
const parsed = parseAssertCommand(substituteVariables(step.content, runtimeVariables));
|
|
28347
|
+
if (!parsed) {
|
|
28348
|
+
const invalidAssertMessage = `Step ${stepIdx + 1}: Invalid assert command: ${step.content}`;
|
|
28349
|
+
errors.push(invalidAssertMessage);
|
|
28350
|
+
await emitFailure(invalidAssertMessage, step, stepIdx);
|
|
28809
28351
|
return {
|
|
28810
28352
|
name: "",
|
|
28811
28353
|
success: false,
|
|
@@ -28817,600 +28359,1164 @@ ${indentMultiline(userMessage)}`;
|
|
|
28817
28359
|
duration: Date.now() - startTime
|
|
28818
28360
|
};
|
|
28819
28361
|
}
|
|
28820
|
-
|
|
28821
|
-
|
|
28822
|
-
|
|
28823
|
-
|
|
28824
|
-
|
|
28825
|
-
|
|
28826
|
-
|
|
28827
|
-
reportProgress(stepIdx, "sequenceStart", `Starting sequence ${targetName}`, void 0, targetName);
|
|
28828
|
-
let subWorkingDir = workingDir;
|
|
28829
|
-
if (sequenceSources) {
|
|
28830
|
-
const sourceFile = sequenceSources.get(targetName.toLowerCase());
|
|
28831
|
-
if (sourceFile) {
|
|
28832
|
-
const path9 = await import("path");
|
|
28833
|
-
subWorkingDir = path9.dirname(sourceFile);
|
|
28834
|
-
}
|
|
28835
|
-
}
|
|
28836
|
-
const subResult = await runSequenceWithJar(
|
|
28837
|
-
targetSequence.content,
|
|
28838
|
-
runtimeVariables,
|
|
28839
|
-
// Pass current runtime variables (includes file vars + any captured)
|
|
28840
|
-
cookieJar,
|
|
28841
|
-
subWorkingDir,
|
|
28842
|
-
fullDocumentText,
|
|
28843
|
-
onProgress,
|
|
28844
|
-
// Pass through progress callback
|
|
28845
|
-
[...currentCallStack, targetName],
|
|
28846
|
-
// Add to call stack for circular detection
|
|
28847
|
-
sequenceArgs2,
|
|
28848
|
-
// Pass bound arguments as initial scope variables
|
|
28849
|
-
apiDefinitions,
|
|
28850
|
-
// Pass API definitions for endpoint resolution
|
|
28851
|
-
tagFilterOptions,
|
|
28852
|
-
// Pass tag filter options for nested sequence filtering
|
|
28853
|
-
sequenceSources,
|
|
28854
|
-
// Pass sequence sources for nested sequences
|
|
28855
|
-
executionContext
|
|
28856
|
-
);
|
|
28857
|
-
reportProgress(stepIdx, "sequenceEnd", `Finished sequence ${targetName}`, void 0, targetName);
|
|
28858
|
-
for (const subResponse of subResult.responses) {
|
|
28859
|
-
addResponse(subResponse);
|
|
28860
|
-
}
|
|
28861
|
-
scriptResults.push(...subResult.scriptResults);
|
|
28862
|
-
assertionResults.push(...subResult.assertionResults);
|
|
28863
|
-
for (const subStep of subResult.steps) {
|
|
28864
|
-
orderedSteps.push({
|
|
28865
|
-
...subStep,
|
|
28866
|
-
stepIndex: orderedSteps.length
|
|
28867
|
-
});
|
|
28868
|
-
}
|
|
28869
|
-
requestIndex += subResult.responses.length;
|
|
28870
|
-
if (!subResult.success) {
|
|
28871
|
-
errors.push(`Sequence "${targetName}" failed`);
|
|
28872
|
-
errors.push(...subResult.errors);
|
|
28873
|
-
return {
|
|
28874
|
-
name: "",
|
|
28875
|
-
success: false,
|
|
28876
|
-
responses,
|
|
28877
|
-
scriptResults,
|
|
28878
|
-
assertionResults,
|
|
28879
|
-
steps: orderedSteps,
|
|
28880
|
-
errors,
|
|
28881
|
-
duration: Date.now() - startTime,
|
|
28882
|
-
variables: runtimeVariables
|
|
28362
|
+
const result = evaluateAssertion(parsed, responses, runtimeVariables, getValueByPath, responseIndexToVariable, workingDir);
|
|
28363
|
+
assertionResults.push(result);
|
|
28364
|
+
const stepResult = {
|
|
28365
|
+
type: "assertion",
|
|
28366
|
+
stepIndex: stepIdx,
|
|
28367
|
+
assertion: result,
|
|
28368
|
+
lineNumber: step.lineNumber
|
|
28883
28369
|
};
|
|
28884
|
-
|
|
28885
|
-
|
|
28886
|
-
|
|
28887
|
-
|
|
28888
|
-
|
|
28889
|
-
|
|
28890
|
-
|
|
28891
|
-
|
|
28892
|
-
success: false,
|
|
28893
|
-
responses,
|
|
28894
|
-
scriptResults,
|
|
28895
|
-
assertionResults,
|
|
28896
|
-
steps: orderedSteps,
|
|
28897
|
-
errors,
|
|
28898
|
-
duration: Date.now() - startTime
|
|
28899
|
-
};
|
|
28900
|
-
}
|
|
28901
|
-
requestIndex++;
|
|
28902
|
-
let requestUrl = "";
|
|
28903
|
-
let requestMethod = "";
|
|
28904
|
-
try {
|
|
28905
|
-
let requestParsed;
|
|
28906
|
-
if (apiDefinitions && apiDefinitions.endpoints.length > 0 && isApiRequestLine(namedRequest.content, apiDefinitions.endpoints)) {
|
|
28907
|
-
const apiRequest = parseApiRequest(
|
|
28908
|
-
namedRequest.content,
|
|
28909
|
-
apiDefinitions.endpoints,
|
|
28910
|
-
apiDefinitions.headerGroups
|
|
28911
|
-
);
|
|
28912
|
-
if (apiRequest) {
|
|
28913
|
-
const endpoint = getEndpoint(
|
|
28914
|
-
{ headerGroups: apiDefinitions.headerGroups, endpoints: apiDefinitions.endpoints },
|
|
28915
|
-
apiRequest.endpointName
|
|
28916
|
-
);
|
|
28917
|
-
if (endpoint) {
|
|
28918
|
-
let resolvedPath = endpoint.path;
|
|
28919
|
-
resolvedPath = resolvedPath.replace(/\{\{([a-zA-Z_][a-zA-Z0-9_]*)\}\}/g, (_, varName) => {
|
|
28920
|
-
return runtimeVariables[varName] !== void 0 ? String(runtimeVariables[varName]) : `{{${varName}}}`;
|
|
28921
|
-
});
|
|
28922
|
-
for (const [paramName, paramValue] of Object.entries(apiRequest.params)) {
|
|
28923
|
-
let resolvedValue = paramValue;
|
|
28924
|
-
if (runtimeVariables[paramValue] !== void 0) {
|
|
28925
|
-
resolvedValue = String(runtimeVariables[paramValue]);
|
|
28926
|
-
} else if (paramValue.startsWith("{{") && paramValue.endsWith("}}")) {
|
|
28927
|
-
const varName = paramValue.slice(2, -2);
|
|
28928
|
-
if (runtimeVariables[varName] !== void 0) {
|
|
28929
|
-
resolvedValue = String(runtimeVariables[varName]);
|
|
28930
|
-
}
|
|
28931
|
-
}
|
|
28932
|
-
resolvedPath = resolvedPath.replace(`{${paramName}}`, resolvedValue);
|
|
28933
|
-
}
|
|
28934
|
-
const combinedHeaders = {};
|
|
28935
|
-
for (const groupName of apiRequest.headerGroupNames) {
|
|
28936
|
-
const group = getHeaderGroup(apiDefinitions, groupName);
|
|
28937
|
-
if (group) {
|
|
28938
|
-
const resolvedHeaders = resolveHeaderValues(group, runtimeVariables);
|
|
28939
|
-
Object.assign(combinedHeaders, resolvedHeaders);
|
|
28940
|
-
}
|
|
28941
|
-
}
|
|
28942
|
-
for (const [headerName, headerValue] of Object.entries(apiRequest.inlineHeaders)) {
|
|
28943
|
-
let resolved = headerValue;
|
|
28944
|
-
resolved = resolved.replace(/\{\{([a-zA-Z_][a-zA-Z0-9_]*)\}\}/g, (_, varName) => {
|
|
28945
|
-
return runtimeVariables[varName] !== void 0 ? String(runtimeVariables[varName]) : `{{${varName}}}`;
|
|
28946
|
-
});
|
|
28947
|
-
combinedHeaders[headerName] = resolved;
|
|
28948
|
-
}
|
|
28949
|
-
const bodyParsed = parserHttpRequest(namedRequest.content, runtimeVariables);
|
|
28950
|
-
requestParsed = {
|
|
28951
|
-
method: apiRequest.method,
|
|
28952
|
-
url: resolvedPath,
|
|
28953
|
-
headers: combinedHeaders,
|
|
28954
|
-
body: bodyParsed.body
|
|
28955
|
-
};
|
|
28370
|
+
orderedSteps.push(stepResult);
|
|
28371
|
+
const statusIcon = result.passed ? "\u2713" : "\u2717";
|
|
28372
|
+
reportProgress(stepIdx, "assertion", `${statusIcon} assert ${result.expression}`, stepResult);
|
|
28373
|
+
if (!result.passed) {
|
|
28374
|
+
const failMessage = result.message ? `Assertion failed: ${result.message}` : `Assertion failed: ${result.expression}`;
|
|
28375
|
+
errors.push(failMessage);
|
|
28376
|
+
if (result.error) {
|
|
28377
|
+
errors.push(` Error: ${result.error}`);
|
|
28956
28378
|
} else {
|
|
28957
|
-
|
|
28379
|
+
errors.push(` Expected: ${result.rightExpression ?? result.operator}`);
|
|
28380
|
+
errors.push(` Actual: ${JSON.stringify(result.leftValue)}`);
|
|
28958
28381
|
}
|
|
28959
|
-
|
|
28960
|
-
|
|
28961
|
-
|
|
28962
|
-
|
|
28963
|
-
|
|
28964
|
-
|
|
28965
|
-
|
|
28966
|
-
|
|
28967
|
-
|
|
28968
|
-
|
|
28969
|
-
|
|
28970
|
-
validatePreparedRequest(
|
|
28971
|
-
requestParsed,
|
|
28972
|
-
buildRequestValidationContext(stepIdx + 1, requestMethod, requestUrl, targetName)
|
|
28973
|
-
);
|
|
28974
|
-
const effectiveRetryCount = parsed.retryCount ?? requestParsed.retryCount;
|
|
28975
|
-
const effectiveBackoffMs = parsed.backoffMs ?? requestParsed.backoffMs ?? 1e3;
|
|
28976
|
-
const retryOpts = effectiveRetryCount ? {
|
|
28977
|
-
retryCount: effectiveRetryCount,
|
|
28978
|
-
backoffMs: effectiveBackoffMs,
|
|
28979
|
-
onRetry: (attempt, total, error, waitMs) => {
|
|
28980
|
-
reportProgress(stepIdx, "request", `[Retry ${attempt}/${total}] run ${targetName} - waiting ${waitMs}ms`, void 0);
|
|
28981
|
-
}
|
|
28982
|
-
} : void 0;
|
|
28983
|
-
const response = cookieJar ? await sendRequestWithJar(requestParsed, cookieJar, retryOpts) : await sendRequest(requestParsed, retryOpts);
|
|
28984
|
-
addResponse(response);
|
|
28985
|
-
const stepResult = {
|
|
28986
|
-
type: "request",
|
|
28987
|
-
stepIndex: stepIdx,
|
|
28988
|
-
response,
|
|
28989
|
-
requestMethod: requestParsed.method,
|
|
28990
|
-
requestUrl: requestParsed.url
|
|
28991
|
-
};
|
|
28992
|
-
orderedSteps.push(stepResult);
|
|
28993
|
-
reportProgress(stepIdx, "namedRequest", `run ${targetName} \u2192 ${requestParsed.method} ${requestParsed.url}`, stepResult);
|
|
28994
|
-
const relevantCaptures = captures.filter((c) => c.afterRequest === requestIndex);
|
|
28995
|
-
for (const capture of relevantCaptures) {
|
|
28996
|
-
const value = getValueByPath(response, capture.path);
|
|
28997
|
-
if (value !== void 0) {
|
|
28998
|
-
runtimeVariables[capture.varName] = value;
|
|
28999
|
-
} else {
|
|
29000
|
-
errors.push(`Warning: Could not capture ${capture.varName} from $${requestIndex}.${capture.path}`);
|
|
28382
|
+
await emitFailure(failMessage, step, stepIdx);
|
|
28383
|
+
return {
|
|
28384
|
+
name: "",
|
|
28385
|
+
success: false,
|
|
28386
|
+
responses,
|
|
28387
|
+
scriptResults,
|
|
28388
|
+
assertionResults,
|
|
28389
|
+
steps: orderedSteps,
|
|
28390
|
+
errors,
|
|
28391
|
+
duration: Date.now() - startTime
|
|
28392
|
+
};
|
|
29001
28393
|
}
|
|
28394
|
+
continue;
|
|
29002
28395
|
}
|
|
29003
|
-
|
|
29004
|
-
|
|
29005
|
-
|
|
29006
|
-
|
|
29007
|
-
|
|
29008
|
-
|
|
29009
|
-
|
|
29010
|
-
|
|
29011
|
-
|
|
29012
|
-
|
|
29013
|
-
|
|
29014
|
-
|
|
29015
|
-
|
|
29016
|
-
|
|
29017
|
-
success: false,
|
|
29018
|
-
responses,
|
|
29019
|
-
scriptResults,
|
|
29020
|
-
assertionResults,
|
|
29021
|
-
steps: orderedSteps,
|
|
29022
|
-
errors,
|
|
29023
|
-
duration: Date.now() - startTime
|
|
29024
|
-
};
|
|
29025
|
-
}
|
|
29026
|
-
} else if (step.type === "varRunSequence") {
|
|
29027
|
-
const parsed = parseVarRunSequenceCommand(step.content);
|
|
29028
|
-
if (!parsed) {
|
|
29029
|
-
errors.push(`Invalid var run sequence command: ${step.content}`);
|
|
29030
|
-
return {
|
|
29031
|
-
name: "",
|
|
29032
|
-
success: false,
|
|
29033
|
-
responses,
|
|
29034
|
-
scriptResults,
|
|
29035
|
-
assertionResults,
|
|
29036
|
-
steps: orderedSteps,
|
|
29037
|
-
errors,
|
|
29038
|
-
duration: Date.now() - startTime
|
|
29039
|
-
};
|
|
29040
|
-
}
|
|
29041
|
-
const { varName, sequenceName, args: runArgs } = parsed;
|
|
29042
|
-
if (!fullDocumentText) {
|
|
29043
|
-
errors.push(`Cannot run sequence "${sequenceName}": full document text not provided`);
|
|
29044
|
-
return {
|
|
29045
|
-
name: "",
|
|
29046
|
-
success: false,
|
|
29047
|
-
responses,
|
|
29048
|
-
scriptResults,
|
|
29049
|
-
assertionResults,
|
|
29050
|
-
steps: orderedSteps,
|
|
29051
|
-
errors,
|
|
29052
|
-
duration: Date.now() - startTime
|
|
29053
|
-
};
|
|
29054
|
-
}
|
|
29055
|
-
const allSequences = extractSequences(fullDocumentText);
|
|
29056
|
-
const targetSequence = allSequences.find((s) => s.name === sequenceName);
|
|
29057
|
-
if (!targetSequence) {
|
|
29058
|
-
const namedRequest = getNamedRequest(fullDocumentText, sequenceName);
|
|
29059
|
-
if (!namedRequest) {
|
|
29060
|
-
errors.push(`"${sequenceName}" is not a named request or sequence`);
|
|
29061
|
-
return {
|
|
29062
|
-
name: "",
|
|
29063
|
-
success: false,
|
|
29064
|
-
responses,
|
|
29065
|
-
scriptResults,
|
|
29066
|
-
assertionResults,
|
|
29067
|
-
steps: orderedSteps,
|
|
29068
|
-
errors,
|
|
29069
|
-
duration: Date.now() - startTime
|
|
28396
|
+
if (step.type === "print") {
|
|
28397
|
+
const parsed = parsePrintCommand(step.content);
|
|
28398
|
+
const titleResolved = resolveBareVariables(parsed.title, runtimeVariables);
|
|
28399
|
+
const title = substituteVariables(titleResolved, runtimeVariables);
|
|
28400
|
+
const bodyResolved = parsed.body ? resolveBareVariables(parsed.body, runtimeVariables) : void 0;
|
|
28401
|
+
const body = bodyResolved ? substituteVariables(bodyResolved, runtimeVariables) : void 0;
|
|
28402
|
+
const stepResult = {
|
|
28403
|
+
type: "print",
|
|
28404
|
+
stepIndex: stepIdx,
|
|
28405
|
+
print: {
|
|
28406
|
+
title,
|
|
28407
|
+
body,
|
|
28408
|
+
timestamp: Date.now() - startTime
|
|
28409
|
+
}
|
|
29070
28410
|
};
|
|
28411
|
+
orderedSteps.push(stepResult);
|
|
28412
|
+
reportProgress(stepIdx, "print", `print: ${title}`, stepResult);
|
|
28413
|
+
continue;
|
|
29071
28414
|
}
|
|
29072
|
-
|
|
29073
|
-
|
|
29074
|
-
|
|
29075
|
-
|
|
29076
|
-
const requestParsed = parserHttpRequest(namedRequest.content, runtimeVariables);
|
|
29077
|
-
requestUrl = requestParsed.url;
|
|
29078
|
-
requestMethod = requestParsed.method;
|
|
29079
|
-
validatePreparedRequest(
|
|
29080
|
-
requestParsed,
|
|
29081
|
-
buildRequestValidationContext(stepIdx + 1, requestMethod, requestUrl, `${varName} = run ${sequenceName}`)
|
|
29082
|
-
);
|
|
29083
|
-
const effectiveRetryCount = parsed.retryCount ?? requestParsed.retryCount;
|
|
29084
|
-
const effectiveBackoffMs = parsed.backoffMs ?? requestParsed.backoffMs ?? 1e3;
|
|
29085
|
-
const retryOpts = effectiveRetryCount ? {
|
|
29086
|
-
retryCount: effectiveRetryCount,
|
|
29087
|
-
backoffMs: effectiveBackoffMs,
|
|
29088
|
-
onRetry: (attempt, total, error, waitMs) => {
|
|
29089
|
-
reportProgress(stepIdx, "request", `[Retry ${attempt}/${total}] var ${varName} = run ${sequenceName} - waiting ${waitMs}ms`, void 0);
|
|
29090
|
-
}
|
|
29091
|
-
} : void 0;
|
|
29092
|
-
const response = cookieJar ? await sendRequestWithJar(requestParsed, cookieJar, retryOpts) : await sendRequest(requestParsed, retryOpts);
|
|
29093
|
-
addResponse(response);
|
|
29094
|
-
responseIndexToVariable.set(responses.length, varName);
|
|
28415
|
+
if (step.type === "wait") {
|
|
28416
|
+
const durationMs = parseWaitCommand(step.content);
|
|
28417
|
+
reportProgress(stepIdx, "wait", `wait: ${durationMs}ms`);
|
|
28418
|
+
await sleep2(durationMs);
|
|
29095
28419
|
const stepResult = {
|
|
29096
|
-
type: "
|
|
28420
|
+
type: "print",
|
|
29097
28421
|
stepIndex: stepIdx,
|
|
29098
|
-
|
|
29099
|
-
|
|
29100
|
-
|
|
29101
|
-
|
|
28422
|
+
print: {
|
|
28423
|
+
title: `Waited ${durationMs >= 1e3 ? durationMs / 1e3 + "s" : durationMs + "ms"}`,
|
|
28424
|
+
timestamp: Date.now() - startTime
|
|
28425
|
+
}
|
|
29102
28426
|
};
|
|
29103
28427
|
orderedSteps.push(stepResult);
|
|
29104
|
-
|
|
29105
|
-
|
|
29106
|
-
|
|
29107
|
-
|
|
29108
|
-
|
|
29109
|
-
|
|
28428
|
+
continue;
|
|
28429
|
+
}
|
|
28430
|
+
if (step.type === "json") {
|
|
28431
|
+
const bareResolved = resolveBareVariables(step.content, runtimeVariables);
|
|
28432
|
+
const parsed = parseJsonCommand(substituteVariables(bareResolved, runtimeVariables));
|
|
28433
|
+
if (!parsed) {
|
|
28434
|
+
errors.push(`Step ${stepIdx + 1}: Invalid json command: ${step.content}`);
|
|
28435
|
+
return {
|
|
28436
|
+
name: "",
|
|
28437
|
+
success: false,
|
|
28438
|
+
responses,
|
|
28439
|
+
scriptResults,
|
|
28440
|
+
assertionResults,
|
|
28441
|
+
steps: orderedSteps,
|
|
28442
|
+
errors,
|
|
28443
|
+
duration: Date.now() - startTime
|
|
28444
|
+
};
|
|
28445
|
+
}
|
|
28446
|
+
const result = readJsonFile(parsed.filePath, workingDir);
|
|
28447
|
+
const stepResult = {
|
|
28448
|
+
type: "json",
|
|
28449
|
+
stepIndex: stepIdx,
|
|
28450
|
+
json: {
|
|
28451
|
+
varName: parsed.varName,
|
|
28452
|
+
filePath: result.filePath,
|
|
28453
|
+
success: result.success,
|
|
28454
|
+
error: result.error,
|
|
28455
|
+
timestamp: Date.now() - startTime
|
|
28456
|
+
}
|
|
29110
28457
|
};
|
|
29111
|
-
|
|
29112
|
-
|
|
29113
|
-
|
|
29114
|
-
|
|
29115
|
-
|
|
29116
|
-
|
|
28458
|
+
orderedSteps.push(stepResult);
|
|
28459
|
+
if (!result.success) {
|
|
28460
|
+
errors.push(`Failed to load JSON file: ${result.error}`);
|
|
28461
|
+
reportProgress(stepIdx, "json", `json: ${parsed.varName} \u2717 ${result.error}`, stepResult);
|
|
28462
|
+
return {
|
|
28463
|
+
name: "",
|
|
28464
|
+
success: false,
|
|
28465
|
+
responses,
|
|
28466
|
+
scriptResults,
|
|
28467
|
+
assertionResults,
|
|
28468
|
+
steps: orderedSteps,
|
|
28469
|
+
errors,
|
|
28470
|
+
duration: Date.now() - startTime
|
|
28471
|
+
};
|
|
28472
|
+
}
|
|
28473
|
+
runtimeVariables[parsed.varName] = JSON.stringify(result.data);
|
|
28474
|
+
reportProgress(stepIdx, "json", `json: ${parsed.varName} = ${parsed.filePath}`, stepResult);
|
|
28475
|
+
continue;
|
|
28476
|
+
}
|
|
28477
|
+
if (step.type === "propAssign") {
|
|
28478
|
+
const parsed = parsePropertyAssignment(step.content);
|
|
28479
|
+
if (!parsed) {
|
|
28480
|
+
errors.push(`Step ${stepIdx + 1}: Invalid property assignment: ${step.content}`);
|
|
28481
|
+
return {
|
|
28482
|
+
name: "",
|
|
28483
|
+
success: false,
|
|
28484
|
+
responses,
|
|
28485
|
+
scriptResults,
|
|
28486
|
+
assertionResults,
|
|
28487
|
+
steps: orderedSteps,
|
|
28488
|
+
errors,
|
|
28489
|
+
duration: Date.now() - startTime
|
|
28490
|
+
};
|
|
28491
|
+
}
|
|
28492
|
+
if (!(parsed.varName in runtimeVariables)) {
|
|
28493
|
+
errors.push(`Step ${stepIdx + 1}: Variable '${parsed.varName}' is not defined`);
|
|
28494
|
+
return {
|
|
28495
|
+
name: "",
|
|
28496
|
+
success: false,
|
|
28497
|
+
responses,
|
|
28498
|
+
scriptResults,
|
|
28499
|
+
assertionResults,
|
|
28500
|
+
steps: orderedSteps,
|
|
28501
|
+
errors,
|
|
28502
|
+
duration: Date.now() - startTime
|
|
28503
|
+
};
|
|
28504
|
+
}
|
|
28505
|
+
let jsonObj;
|
|
28506
|
+
try {
|
|
28507
|
+
jsonObj = JSON.parse(runtimeVariables[parsed.varName]);
|
|
28508
|
+
} catch {
|
|
28509
|
+
errors.push(`Step ${stepIdx + 1}: Variable '${parsed.varName}' is not a valid JSON object`);
|
|
28510
|
+
return {
|
|
28511
|
+
name: "",
|
|
28512
|
+
success: false,
|
|
28513
|
+
responses,
|
|
28514
|
+
scriptResults,
|
|
28515
|
+
assertionResults,
|
|
28516
|
+
steps: orderedSteps,
|
|
28517
|
+
errors,
|
|
28518
|
+
duration: Date.now() - startTime
|
|
28519
|
+
};
|
|
28520
|
+
}
|
|
28521
|
+
const valueTrimmed = parsed.value.trim();
|
|
28522
|
+
const bareVarMatch = valueTrimmed.match(/^([a-zA-Z_][a-zA-Z0-9_]*)((?:\.[a-zA-Z_][a-zA-Z0-9_]*|\[\d+\])*)$/);
|
|
28523
|
+
let newValue;
|
|
28524
|
+
if (bareVarMatch && bareVarMatch[1] in runtimeVariables) {
|
|
28525
|
+
const varName = bareVarMatch[1];
|
|
28526
|
+
const pathPart = bareVarMatch[2] || "";
|
|
28527
|
+
let value = runtimeVariables[varName];
|
|
28528
|
+
if (typeof value === "string") {
|
|
28529
|
+
try {
|
|
28530
|
+
const parsed2 = JSON.parse(value);
|
|
28531
|
+
if (typeof parsed2 === "object" && parsed2 !== null) {
|
|
28532
|
+
value = parsed2;
|
|
28533
|
+
}
|
|
28534
|
+
} catch {
|
|
28535
|
+
}
|
|
28536
|
+
}
|
|
28537
|
+
if (pathPart) {
|
|
28538
|
+
const path10 = pathPart.replace(/^\./, "");
|
|
28539
|
+
newValue = getNestedValueFromObject(value, path10);
|
|
29117
28540
|
} else {
|
|
29118
|
-
|
|
28541
|
+
newValue = value;
|
|
28542
|
+
}
|
|
28543
|
+
} else {
|
|
28544
|
+
const bareResolvedValue = resolveBareVariables(parsed.value, runtimeVariables);
|
|
28545
|
+
const resolvedValue = substituteVariables(bareResolvedValue, runtimeVariables);
|
|
28546
|
+
newValue = resolvedValue;
|
|
28547
|
+
try {
|
|
28548
|
+
newValue = JSON.parse(resolvedValue);
|
|
28549
|
+
} catch {
|
|
29119
28550
|
}
|
|
29120
28551
|
}
|
|
29121
|
-
|
|
29122
|
-
|
|
29123
|
-
|
|
29124
|
-
|
|
29125
|
-
|
|
29126
|
-
|
|
29127
|
-
|
|
29128
|
-
|
|
29129
|
-
|
|
29130
|
-
|
|
28552
|
+
const success = setNestedValue(jsonObj, parsed.propertyPath, newValue);
|
|
28553
|
+
if (!success) {
|
|
28554
|
+
errors.push(`Step ${stepIdx + 1}: Failed to set property '${parsed.propertyPath}' on '${parsed.varName}'`);
|
|
28555
|
+
return {
|
|
28556
|
+
name: "",
|
|
28557
|
+
success: false,
|
|
28558
|
+
responses,
|
|
28559
|
+
scriptResults,
|
|
28560
|
+
assertionResults,
|
|
28561
|
+
steps: orderedSteps,
|
|
28562
|
+
errors,
|
|
28563
|
+
duration: Date.now() - startTime
|
|
28564
|
+
};
|
|
29131
28565
|
}
|
|
29132
|
-
|
|
29133
|
-
|
|
29134
|
-
name: "",
|
|
29135
|
-
success: false,
|
|
29136
|
-
responses,
|
|
29137
|
-
scriptResults,
|
|
29138
|
-
assertionResults,
|
|
29139
|
-
steps: orderedSteps,
|
|
29140
|
-
errors,
|
|
29141
|
-
duration: Date.now() - startTime
|
|
29142
|
-
};
|
|
29143
|
-
}
|
|
29144
|
-
continue;
|
|
29145
|
-
}
|
|
29146
|
-
const currentCallStack = callStack || [];
|
|
29147
|
-
if (currentCallStack.includes(sequenceName)) {
|
|
29148
|
-
errors.push(`Circular reference detected: ${[...currentCallStack, sequenceName].join(" \u2192 ")}`);
|
|
29149
|
-
return {
|
|
29150
|
-
name: "",
|
|
29151
|
-
success: false,
|
|
29152
|
-
responses,
|
|
29153
|
-
scriptResults,
|
|
29154
|
-
assertionResults,
|
|
29155
|
-
steps: orderedSteps,
|
|
29156
|
-
errors,
|
|
29157
|
-
duration: Date.now() - startTime
|
|
29158
|
-
};
|
|
29159
|
-
}
|
|
29160
|
-
let sequenceArgs2 = {};
|
|
29161
|
-
if (targetSequence.parameters.length > 0 || runArgs.length > 0) {
|
|
29162
|
-
const bindResult = bindSequenceArguments(targetSequence.parameters, runArgs, runtimeVariables);
|
|
29163
|
-
if ("error" in bindResult) {
|
|
29164
|
-
errors.push(`Error calling sequence "${sequenceName}": ${bindResult.error}`);
|
|
29165
|
-
return {
|
|
29166
|
-
name: "",
|
|
29167
|
-
success: false,
|
|
29168
|
-
responses,
|
|
29169
|
-
scriptResults,
|
|
29170
|
-
assertionResults,
|
|
29171
|
-
steps: orderedSteps,
|
|
29172
|
-
errors,
|
|
29173
|
-
duration: Date.now() - startTime
|
|
29174
|
-
};
|
|
29175
|
-
}
|
|
29176
|
-
sequenceArgs2 = bindResult.variables;
|
|
29177
|
-
}
|
|
29178
|
-
if (tagFilterOptions && tagFilterOptions.filters.length > 0) {
|
|
29179
|
-
if (!sequenceMatchesTags(targetSequence, tagFilterOptions)) {
|
|
28566
|
+
runtimeVariables[parsed.varName] = JSON.stringify(jsonObj);
|
|
28567
|
+
reportProgress(stepIdx, "propAssign", `${parsed.varName}.${parsed.propertyPath} = ${parsed.value}`, void 0);
|
|
29180
28568
|
continue;
|
|
29181
28569
|
}
|
|
29182
|
-
|
|
29183
|
-
|
|
29184
|
-
|
|
29185
|
-
|
|
29186
|
-
|
|
29187
|
-
|
|
29188
|
-
|
|
29189
|
-
|
|
28570
|
+
if (step.type === "varAssign") {
|
|
28571
|
+
const parsed = parseVarAssignCommand(step.content);
|
|
28572
|
+
if (!parsed) {
|
|
28573
|
+
errors.push(`Step ${stepIdx + 1}: Invalid variable assignment: ${step.content}`);
|
|
28574
|
+
return {
|
|
28575
|
+
name: "",
|
|
28576
|
+
success: false,
|
|
28577
|
+
responses,
|
|
28578
|
+
scriptResults,
|
|
28579
|
+
assertionResults,
|
|
28580
|
+
steps: orderedSteps,
|
|
28581
|
+
errors,
|
|
28582
|
+
duration: Date.now() - startTime
|
|
28583
|
+
};
|
|
28584
|
+
}
|
|
28585
|
+
const result = evaluateValueExpression(parsed.valueExpr, runtimeVariables);
|
|
28586
|
+
if (result.error) {
|
|
28587
|
+
errors.push(`Step ${stepIdx + 1}: ${result.error}`);
|
|
28588
|
+
return {
|
|
28589
|
+
name: "",
|
|
28590
|
+
success: false,
|
|
28591
|
+
responses,
|
|
28592
|
+
scriptResults,
|
|
28593
|
+
assertionResults,
|
|
28594
|
+
steps: orderedSteps,
|
|
28595
|
+
errors,
|
|
28596
|
+
duration: Date.now() - startTime
|
|
28597
|
+
};
|
|
28598
|
+
}
|
|
28599
|
+
runtimeVariables[parsed.varName] = result.value;
|
|
28600
|
+
reportProgress(stepIdx, "propAssign", `var ${parsed.varName} = ${result.value}`, void 0);
|
|
28601
|
+
continue;
|
|
29190
28602
|
}
|
|
29191
|
-
|
|
29192
|
-
|
|
29193
|
-
|
|
29194
|
-
|
|
29195
|
-
|
|
29196
|
-
|
|
29197
|
-
|
|
29198
|
-
|
|
29199
|
-
|
|
29200
|
-
|
|
29201
|
-
|
|
29202
|
-
|
|
29203
|
-
|
|
29204
|
-
|
|
29205
|
-
|
|
29206
|
-
sequenceSources,
|
|
29207
|
-
// Pass sequence sources for nested sequences
|
|
29208
|
-
executionContext
|
|
29209
|
-
);
|
|
29210
|
-
reportProgress(stepIdx, "sequenceEnd", `Finished sequence ${sequenceName}`, void 0, sequenceName);
|
|
29211
|
-
for (const subResponse of subResult.responses) {
|
|
29212
|
-
addResponse(subResponse);
|
|
29213
|
-
}
|
|
29214
|
-
scriptResults.push(...subResult.scriptResults);
|
|
29215
|
-
assertionResults.push(...subResult.assertionResults);
|
|
29216
|
-
for (const subStep of subResult.steps) {
|
|
29217
|
-
orderedSteps.push({
|
|
29218
|
-
...subStep,
|
|
29219
|
-
stepIndex: orderedSteps.length
|
|
29220
|
-
});
|
|
29221
|
-
}
|
|
29222
|
-
const returnExpressions = extractReturnVariables(targetSequence.content);
|
|
29223
|
-
if (returnExpressions && returnExpressions.length > 0 && subResult.variables) {
|
|
29224
|
-
if (returnExpressions.length === 1) {
|
|
29225
|
-
const resolved = resolveReturnExpression(returnExpressions[0], subResult.variables);
|
|
29226
|
-
if (resolved) {
|
|
29227
|
-
runtimeVariables[varName] = resolved.value;
|
|
29228
|
-
} else {
|
|
29229
|
-
runtimeVariables[varName] = "";
|
|
28603
|
+
if (step.type === "varRequest") {
|
|
28604
|
+
const commandLine = step.content.split("\n")[0];
|
|
28605
|
+
const parsed = parseVarRequestCommand(commandLine);
|
|
28606
|
+
if (!parsed) {
|
|
28607
|
+
errors.push(`Step ${stepIdx + 1}: Invalid variable request: ${commandLine}`);
|
|
28608
|
+
return {
|
|
28609
|
+
name: "",
|
|
28610
|
+
success: false,
|
|
28611
|
+
responses,
|
|
28612
|
+
scriptResults,
|
|
28613
|
+
assertionResults,
|
|
28614
|
+
steps: orderedSteps,
|
|
28615
|
+
errors,
|
|
28616
|
+
duration: Date.now() - startTime
|
|
28617
|
+
};
|
|
29230
28618
|
}
|
|
29231
|
-
|
|
29232
|
-
|
|
29233
|
-
|
|
29234
|
-
|
|
29235
|
-
|
|
29236
|
-
|
|
28619
|
+
requestIndex++;
|
|
28620
|
+
let resolvedUrl = "";
|
|
28621
|
+
let resolvedHeaders = {};
|
|
28622
|
+
let requestDescription = `${parsed.method} ${parsed.url}`;
|
|
28623
|
+
try {
|
|
28624
|
+
const endpointMatch = parsed.url.match(/^([a-zA-Z_][a-zA-Z0-9_]*)(?:\(([^)]*)\))?(\s+.*)?$/);
|
|
28625
|
+
const potentialEndpointName = endpointMatch ? endpointMatch[1] : null;
|
|
28626
|
+
const endpoint = apiDefinitions && potentialEndpointName ? getEndpoint({ headerGroups: apiDefinitions.headerGroups, endpoints: apiDefinitions.endpoints }, potentialEndpointName) : void 0;
|
|
28627
|
+
if (endpoint && apiDefinitions) {
|
|
28628
|
+
const paramsStr = endpointMatch[2] || "";
|
|
28629
|
+
const headerGroupsStr = endpointMatch[3]?.trim() || "";
|
|
28630
|
+
const paramTokens = paramsStr ? paramsStr.split(",").map((p) => p.trim()) : [];
|
|
28631
|
+
const params = {};
|
|
28632
|
+
const isNamedSyntax = paramTokens.length > 0 && paramTokens[0].includes(":");
|
|
28633
|
+
if (isNamedSyntax) {
|
|
28634
|
+
for (const token of paramTokens) {
|
|
28635
|
+
const kvMatch = token.match(/^([a-zA-Z_][a-zA-Z0-9_]*)\s*:\s*(.+)$/);
|
|
28636
|
+
if (kvMatch) {
|
|
28637
|
+
const paramName = kvMatch[1];
|
|
28638
|
+
let paramValue = kvMatch[2].trim().replace(/^["']|["']$/g, "");
|
|
28639
|
+
const bareResolved = resolveBareVariables(paramValue, runtimeVariables);
|
|
28640
|
+
params[paramName] = substituteVariables(bareResolved, runtimeVariables);
|
|
28641
|
+
}
|
|
28642
|
+
}
|
|
28643
|
+
} else {
|
|
28644
|
+
endpoint.parameters.forEach((paramName, idx) => {
|
|
28645
|
+
if (paramTokens[idx] !== void 0) {
|
|
28646
|
+
let paramValue = paramTokens[idx].replace(/^["']|["']$/g, "");
|
|
28647
|
+
const bareResolved = resolveBareVariables(paramValue, runtimeVariables);
|
|
28648
|
+
params[paramName] = substituteVariables(bareResolved, runtimeVariables);
|
|
28649
|
+
}
|
|
28650
|
+
});
|
|
28651
|
+
}
|
|
28652
|
+
let pathWithVars = substituteVariables(endpoint.path, runtimeVariables);
|
|
28653
|
+
for (const paramName of endpoint.parameters) {
|
|
28654
|
+
const value = params[paramName];
|
|
28655
|
+
if (value !== void 0) {
|
|
28656
|
+
pathWithVars = pathWithVars.replace(`{${paramName}}`, value);
|
|
28657
|
+
}
|
|
28658
|
+
}
|
|
28659
|
+
resolvedUrl = pathWithVars;
|
|
28660
|
+
if (headerGroupsStr) {
|
|
28661
|
+
const headerGroupNames = headerGroupsStr.split(/\s+/).filter((n) => n);
|
|
28662
|
+
for (const groupName of headerGroupNames) {
|
|
28663
|
+
const group = getHeaderGroup(
|
|
28664
|
+
{ headerGroups: apiDefinitions.headerGroups, endpoints: apiDefinitions.endpoints },
|
|
28665
|
+
groupName
|
|
28666
|
+
);
|
|
28667
|
+
if (group) {
|
|
28668
|
+
const groupHeaders = resolveHeaderValues(group, runtimeVariables);
|
|
28669
|
+
Object.assign(resolvedHeaders, groupHeaders);
|
|
28670
|
+
}
|
|
28671
|
+
}
|
|
28672
|
+
}
|
|
28673
|
+
requestDescription = `${potentialEndpointName}(${paramTokens.join(", ")}) \u2192 ${parsed.method} ${resolvedUrl}`;
|
|
28674
|
+
} else {
|
|
28675
|
+
resolvedUrl = substituteVariables(parsed.url, runtimeVariables);
|
|
28676
|
+
requestDescription = `${parsed.method} ${resolvedUrl}`;
|
|
28677
|
+
}
|
|
28678
|
+
let requestText = `${parsed.method} ${resolvedUrl}`;
|
|
28679
|
+
if (Object.keys(resolvedHeaders).length > 0) {
|
|
28680
|
+
const headerLines = Object.entries(resolvedHeaders).map(([k, v]) => `${k}: ${v}`);
|
|
28681
|
+
requestText += "\n" + headerLines.join("\n");
|
|
28682
|
+
}
|
|
28683
|
+
const contentLines = step.content.split("\n");
|
|
28684
|
+
if (contentLines.length > 1) {
|
|
28685
|
+
const extraLines = contentLines.slice(1).map((line2) => substituteVariables(line2, runtimeVariables));
|
|
28686
|
+
const hasExplicitBlank = extraLines.some((line2) => line2.trim() === "");
|
|
28687
|
+
const firstNonEmpty = extraLines.find((line2) => line2.trim() !== "");
|
|
28688
|
+
const startsWithHeader = firstNonEmpty ? /^[A-Za-z0-9\-_]+\s*:/.test(firstNonEmpty.trim()) : false;
|
|
28689
|
+
if (hasExplicitBlank || startsWithHeader) {
|
|
28690
|
+
requestText += "\n" + extraLines.join("\n");
|
|
28691
|
+
} else {
|
|
28692
|
+
requestText += "\n\n" + extraLines.join("\n");
|
|
28693
|
+
}
|
|
28694
|
+
}
|
|
28695
|
+
const requestParsed = parserHttpRequest(requestText, runtimeVariables);
|
|
28696
|
+
validatePreparedRequest(
|
|
28697
|
+
requestParsed,
|
|
28698
|
+
buildRequestValidationContext(stepIdx + 1, requestParsed.method, requestParsed.url, `var ${parsed.varName}`)
|
|
28699
|
+
);
|
|
28700
|
+
const retryOpts = parsed.retryCount ? {
|
|
28701
|
+
retryCount: parsed.retryCount,
|
|
28702
|
+
backoffMs: parsed.backoffMs || 1e3,
|
|
28703
|
+
onRetry: (attempt, total, error, waitMs) => {
|
|
28704
|
+
reportProgress(stepIdx, "request", `[Retry ${attempt}/${total}] ${requestDescription} - waiting ${waitMs}ms`, void 0);
|
|
28705
|
+
}
|
|
28706
|
+
} : void 0;
|
|
28707
|
+
const response = cookieJar ? await sendRequestWithJar(requestParsed, cookieJar, retryOpts) : await sendRequest(requestParsed, retryOpts);
|
|
28708
|
+
addResponse(response);
|
|
28709
|
+
responseIndexToVariable.set(responses.length, parsed.varName);
|
|
28710
|
+
runtimeVariables[parsed.varName] = response;
|
|
28711
|
+
const stepResult = {
|
|
28712
|
+
type: "request",
|
|
28713
|
+
stepIndex: stepIdx,
|
|
28714
|
+
response,
|
|
28715
|
+
requestMethod: parsed.method,
|
|
28716
|
+
requestUrl: resolvedUrl,
|
|
28717
|
+
variableName: parsed.varName
|
|
28718
|
+
};
|
|
28719
|
+
orderedSteps.push(stepResult);
|
|
28720
|
+
reportProgress(stepIdx, "request", `var ${parsed.varName} = ${requestDescription}`, stepResult);
|
|
28721
|
+
const relevantCaptures = captures.filter((c) => c.afterRequest === requestIndex);
|
|
28722
|
+
for (const capture of relevantCaptures) {
|
|
28723
|
+
const value = getValueByPath(response, capture.path);
|
|
28724
|
+
if (value !== void 0) {
|
|
28725
|
+
runtimeVariables[capture.varName] = value;
|
|
28726
|
+
} else {
|
|
28727
|
+
errors.push(`Warning: Could not capture ${capture.varName} from $${requestIndex}.${capture.path}`);
|
|
28728
|
+
}
|
|
29237
28729
|
}
|
|
28730
|
+
} catch (error) {
|
|
28731
|
+
const userMessage = formatUserFacingError(
|
|
28732
|
+
error,
|
|
28733
|
+
buildRequestValidationContext(stepIdx + 1, void 0, void 0, `var ${parsed.varName}`)
|
|
28734
|
+
);
|
|
28735
|
+
let errorDetails = `Request failed for var ${parsed.varName}:
|
|
28736
|
+
${indentMultiline(userMessage)}`;
|
|
28737
|
+
if (requestDescription && !/\nRequest:\s/.test(userMessage)) {
|
|
28738
|
+
errorDetails += `
|
|
28739
|
+
Request: ${requestDescription}`;
|
|
28740
|
+
}
|
|
28741
|
+
errors.push(errorDetails);
|
|
28742
|
+
await emitFailure(errorDetails, step, stepIdx);
|
|
28743
|
+
return {
|
|
28744
|
+
name: "",
|
|
28745
|
+
success: false,
|
|
28746
|
+
responses,
|
|
28747
|
+
scriptResults,
|
|
28748
|
+
assertionResults,
|
|
28749
|
+
steps: orderedSteps,
|
|
28750
|
+
errors,
|
|
28751
|
+
duration: Date.now() - startTime
|
|
28752
|
+
};
|
|
29238
28753
|
}
|
|
29239
|
-
|
|
28754
|
+
continue;
|
|
29240
28755
|
}
|
|
29241
|
-
|
|
29242
|
-
|
|
29243
|
-
|
|
29244
|
-
|
|
29245
|
-
|
|
29246
|
-
|
|
29247
|
-
|
|
29248
|
-
|
|
29249
|
-
|
|
29250
|
-
|
|
29251
|
-
|
|
29252
|
-
|
|
29253
|
-
|
|
29254
|
-
|
|
29255
|
-
|
|
29256
|
-
|
|
29257
|
-
|
|
29258
|
-
|
|
29259
|
-
|
|
29260
|
-
|
|
29261
|
-
|
|
29262
|
-
|
|
29263
|
-
|
|
29264
|
-
|
|
29265
|
-
|
|
29266
|
-
|
|
29267
|
-
|
|
29268
|
-
|
|
29269
|
-
apiDefinitions.endpoints,
|
|
29270
|
-
apiDefinitions.headerGroups
|
|
29271
|
-
);
|
|
29272
|
-
if (apiRequest) {
|
|
29273
|
-
const endpoint = getEndpoint(
|
|
29274
|
-
{ headerGroups: apiDefinitions.headerGroups, endpoints: apiDefinitions.endpoints },
|
|
29275
|
-
apiRequest.endpointName
|
|
28756
|
+
if (step.type === "script") {
|
|
28757
|
+
const parsed = parseRunCommand(substituteVariables(step.content, runtimeVariables));
|
|
28758
|
+
if (!parsed) {
|
|
28759
|
+
errors.push(`Step ${stepIdx + 1}: Invalid run command: ${step.content}`);
|
|
28760
|
+
return {
|
|
28761
|
+
name: "",
|
|
28762
|
+
success: false,
|
|
28763
|
+
responses,
|
|
28764
|
+
scriptResults,
|
|
28765
|
+
assertionResults,
|
|
28766
|
+
steps: orderedSteps,
|
|
28767
|
+
errors,
|
|
28768
|
+
duration: Date.now() - startTime
|
|
28769
|
+
};
|
|
28770
|
+
}
|
|
28771
|
+
const substitutedArgs = parsed.args.map((arg) => {
|
|
28772
|
+
const bareResolved = resolveBareVariables(arg, runtimeVariables);
|
|
28773
|
+
return substituteVariables(bareResolved, runtimeVariables);
|
|
28774
|
+
});
|
|
28775
|
+
const substitutedPath = substituteVariables(parsed.scriptPath, runtimeVariables);
|
|
28776
|
+
try {
|
|
28777
|
+
const result = await runScript(
|
|
28778
|
+
parsed.type,
|
|
28779
|
+
substitutedPath,
|
|
28780
|
+
substitutedArgs,
|
|
28781
|
+
workingDir || process.cwd(),
|
|
28782
|
+
runtimeVariables,
|
|
28783
|
+
parsed.captureAs
|
|
29276
28784
|
);
|
|
29277
|
-
|
|
29278
|
-
|
|
29279
|
-
|
|
29280
|
-
|
|
29281
|
-
|
|
29282
|
-
|
|
29283
|
-
|
|
29284
|
-
|
|
28785
|
+
scriptResults.push(result);
|
|
28786
|
+
const stepResult = {
|
|
28787
|
+
type: "script",
|
|
28788
|
+
stepIndex: stepIdx,
|
|
28789
|
+
script: result
|
|
28790
|
+
};
|
|
28791
|
+
orderedSteps.push(stepResult);
|
|
28792
|
+
reportProgress(stepIdx, "script", `run ${parsed.type} ${substitutedPath}`, stepResult);
|
|
28793
|
+
if (!result.success) {
|
|
28794
|
+
errors.push(`Script failed (exit ${result.exitCode}): ${result.error || result.output}`);
|
|
28795
|
+
return {
|
|
28796
|
+
name: "",
|
|
28797
|
+
success: false,
|
|
28798
|
+
responses,
|
|
28799
|
+
scriptResults,
|
|
28800
|
+
assertionResults,
|
|
28801
|
+
steps: orderedSteps,
|
|
28802
|
+
errors,
|
|
28803
|
+
duration: Date.now() - startTime
|
|
28804
|
+
};
|
|
29285
28805
|
}
|
|
29286
|
-
|
|
29287
|
-
|
|
29288
|
-
|
|
29289
|
-
|
|
29290
|
-
|
|
28806
|
+
if (parsed.captureAs) {
|
|
28807
|
+
let outputValue = result.output;
|
|
28808
|
+
try {
|
|
28809
|
+
const jsonParsed = JSON.parse(result.output);
|
|
28810
|
+
outputValue = jsonParsed;
|
|
28811
|
+
} catch {
|
|
29291
28812
|
}
|
|
28813
|
+
runtimeVariables[parsed.captureAs] = outputValue;
|
|
29292
28814
|
}
|
|
29293
|
-
|
|
29294
|
-
|
|
29295
|
-
|
|
29296
|
-
|
|
29297
|
-
|
|
29298
|
-
|
|
29299
|
-
|
|
29300
|
-
|
|
29301
|
-
|
|
28815
|
+
} catch (error) {
|
|
28816
|
+
errors.push(`Script execution error: ${error.message}`);
|
|
28817
|
+
return {
|
|
28818
|
+
name: "",
|
|
28819
|
+
success: false,
|
|
28820
|
+
responses,
|
|
28821
|
+
scriptResults,
|
|
28822
|
+
assertionResults,
|
|
28823
|
+
steps: orderedSteps,
|
|
28824
|
+
errors,
|
|
28825
|
+
duration: Date.now() - startTime
|
|
28826
|
+
};
|
|
28827
|
+
}
|
|
28828
|
+
} else if (step.type === "namedRequest") {
|
|
28829
|
+
const parsed = parseRunNamedRequestCommand(step.content);
|
|
28830
|
+
if (!parsed) {
|
|
28831
|
+
errors.push(`Invalid run command: ${step.content}`);
|
|
28832
|
+
return {
|
|
28833
|
+
name: "",
|
|
28834
|
+
success: false,
|
|
28835
|
+
responses,
|
|
28836
|
+
scriptResults,
|
|
28837
|
+
assertionResults,
|
|
28838
|
+
steps: orderedSteps,
|
|
28839
|
+
errors,
|
|
28840
|
+
duration: Date.now() - startTime
|
|
28841
|
+
};
|
|
28842
|
+
}
|
|
28843
|
+
const { name: targetName, args: runArgs } = parsed;
|
|
28844
|
+
if (!fullDocumentText) {
|
|
28845
|
+
errors.push(`Cannot run "${targetName}": full document text not provided`);
|
|
28846
|
+
return {
|
|
28847
|
+
name: "",
|
|
28848
|
+
success: false,
|
|
28849
|
+
responses,
|
|
28850
|
+
scriptResults,
|
|
28851
|
+
assertionResults,
|
|
28852
|
+
steps: orderedSteps,
|
|
28853
|
+
errors,
|
|
28854
|
+
duration: Date.now() - startTime
|
|
28855
|
+
};
|
|
28856
|
+
}
|
|
28857
|
+
const allSequences = extractSequences(fullDocumentText);
|
|
28858
|
+
const targetSequence = allSequences.find((s) => s.name === targetName);
|
|
28859
|
+
if (targetSequence) {
|
|
28860
|
+
const currentCallStack = callStack || [];
|
|
28861
|
+
if (currentCallStack.includes(targetName)) {
|
|
28862
|
+
errors.push(`Circular reference detected: ${[...currentCallStack, targetName].join(" \u2192 ")}`);
|
|
28863
|
+
return {
|
|
28864
|
+
name: "",
|
|
28865
|
+
success: false,
|
|
28866
|
+
responses,
|
|
28867
|
+
scriptResults,
|
|
28868
|
+
assertionResults,
|
|
28869
|
+
steps: orderedSteps,
|
|
28870
|
+
errors,
|
|
28871
|
+
duration: Date.now() - startTime
|
|
28872
|
+
};
|
|
28873
|
+
}
|
|
28874
|
+
let sequenceArgs2 = {};
|
|
28875
|
+
if (targetSequence.parameters.length > 0 || runArgs.length > 0) {
|
|
28876
|
+
const bindResult = bindSequenceArguments(targetSequence.parameters, runArgs, runtimeVariables);
|
|
28877
|
+
if ("error" in bindResult) {
|
|
28878
|
+
errors.push(`Error calling sequence "${targetName}": ${bindResult.error}`);
|
|
28879
|
+
return {
|
|
28880
|
+
name: "",
|
|
28881
|
+
success: false,
|
|
28882
|
+
responses,
|
|
28883
|
+
scriptResults,
|
|
28884
|
+
assertionResults,
|
|
28885
|
+
steps: orderedSteps,
|
|
28886
|
+
errors,
|
|
28887
|
+
duration: Date.now() - startTime
|
|
28888
|
+
};
|
|
29302
28889
|
}
|
|
28890
|
+
sequenceArgs2 = bindResult.variables;
|
|
29303
28891
|
}
|
|
29304
|
-
|
|
29305
|
-
|
|
28892
|
+
if (tagFilterOptions && tagFilterOptions.filters.length > 0) {
|
|
28893
|
+
if (!sequenceMatchesTags(targetSequence, tagFilterOptions)) {
|
|
28894
|
+
continue;
|
|
28895
|
+
}
|
|
29306
28896
|
}
|
|
29307
|
-
|
|
29308
|
-
|
|
29309
|
-
|
|
28897
|
+
reportProgress(stepIdx, "sequenceStart", `Starting sequence ${targetName}`, void 0, targetName);
|
|
28898
|
+
let subWorkingDir = workingDir;
|
|
28899
|
+
if (sequenceSources) {
|
|
28900
|
+
const sourceFile = sequenceSources.get(targetName.toLowerCase());
|
|
28901
|
+
if (sourceFile) {
|
|
28902
|
+
const path10 = await import("path");
|
|
28903
|
+
subWorkingDir = path10.dirname(sourceFile);
|
|
28904
|
+
}
|
|
29310
28905
|
}
|
|
29311
|
-
|
|
29312
|
-
|
|
29313
|
-
|
|
29314
|
-
|
|
29315
|
-
|
|
28906
|
+
const targetLocation = executionContext?.sequenceLocationIndex?.get(targetName.toLowerCase());
|
|
28907
|
+
const childExecutionContext = {
|
|
28908
|
+
filePath: targetLocation?.filePath ?? executionContext?.filePath,
|
|
28909
|
+
sequenceName: targetName,
|
|
28910
|
+
environment: executionContext?.environment,
|
|
28911
|
+
sequenceStartLine: targetLocation?.startLine ?? targetSequence.startLine,
|
|
28912
|
+
sequenceLocationIndex: executionContext?.sequenceLocationIndex
|
|
29316
28913
|
};
|
|
29317
|
-
|
|
29318
|
-
|
|
29319
|
-
|
|
29320
|
-
|
|
29321
|
-
|
|
29322
|
-
|
|
28914
|
+
const subResult = await runSequenceWithJar(
|
|
28915
|
+
targetSequence.content,
|
|
28916
|
+
runtimeVariables,
|
|
28917
|
+
// Pass current runtime variables (includes file vars + any captured)
|
|
28918
|
+
cookieJar,
|
|
28919
|
+
subWorkingDir,
|
|
28920
|
+
fullDocumentText,
|
|
28921
|
+
onProgress,
|
|
28922
|
+
// Pass through progress callback
|
|
28923
|
+
[...currentCallStack, targetName],
|
|
28924
|
+
// Add to call stack for circular detection
|
|
28925
|
+
sequenceArgs2,
|
|
28926
|
+
// Pass bound arguments as initial scope variables
|
|
28927
|
+
apiDefinitions,
|
|
28928
|
+
// Pass API definitions for endpoint resolution
|
|
28929
|
+
tagFilterOptions,
|
|
28930
|
+
// Pass tag filter options for nested sequence filtering
|
|
28931
|
+
sequenceSources,
|
|
28932
|
+
// Pass sequence sources for nested sequences
|
|
28933
|
+
childExecutionContext,
|
|
28934
|
+
debugHooks
|
|
28935
|
+
);
|
|
28936
|
+
reportProgress(stepIdx, "sequenceEnd", `Finished sequence ${targetName}`, void 0, targetName);
|
|
28937
|
+
for (const subResponse of subResult.responses) {
|
|
28938
|
+
addResponse(subResponse);
|
|
28939
|
+
}
|
|
28940
|
+
scriptResults.push(...subResult.scriptResults);
|
|
28941
|
+
assertionResults.push(...subResult.assertionResults);
|
|
28942
|
+
for (const subStep of subResult.steps) {
|
|
28943
|
+
orderedSteps.push({
|
|
28944
|
+
...subStep,
|
|
28945
|
+
stepIndex: orderedSteps.length
|
|
28946
|
+
});
|
|
28947
|
+
}
|
|
28948
|
+
requestIndex += subResult.responses.length;
|
|
28949
|
+
if (!subResult.success) {
|
|
28950
|
+
errors.push(`Sequence "${targetName}" failed`);
|
|
28951
|
+
errors.push(...subResult.errors);
|
|
28952
|
+
return {
|
|
28953
|
+
name: "",
|
|
28954
|
+
success: false,
|
|
28955
|
+
responses,
|
|
28956
|
+
scriptResults,
|
|
28957
|
+
assertionResults,
|
|
28958
|
+
steps: orderedSteps,
|
|
28959
|
+
errors,
|
|
28960
|
+
duration: Date.now() - startTime,
|
|
28961
|
+
variables: runtimeVariables
|
|
28962
|
+
};
|
|
29323
28963
|
}
|
|
28964
|
+
continue;
|
|
29324
28965
|
}
|
|
29325
|
-
|
|
29326
|
-
|
|
29327
|
-
|
|
29328
|
-
|
|
29329
|
-
|
|
28966
|
+
const namedRequest = getNamedRequest(fullDocumentText, targetName);
|
|
28967
|
+
if (!namedRequest) {
|
|
28968
|
+
errors.push(`"${targetName}" is not a named request or sequence`);
|
|
28969
|
+
return {
|
|
28970
|
+
name: "",
|
|
28971
|
+
success: false,
|
|
28972
|
+
responses,
|
|
28973
|
+
scriptResults,
|
|
28974
|
+
assertionResults,
|
|
28975
|
+
steps: orderedSteps,
|
|
28976
|
+
errors,
|
|
28977
|
+
duration: Date.now() - startTime
|
|
28978
|
+
};
|
|
29330
28979
|
}
|
|
29331
|
-
|
|
29332
|
-
|
|
29333
|
-
|
|
29334
|
-
|
|
29335
|
-
|
|
29336
|
-
|
|
29337
|
-
|
|
29338
|
-
|
|
29339
|
-
|
|
28980
|
+
requestIndex++;
|
|
28981
|
+
let requestUrl = "";
|
|
28982
|
+
let requestMethod = "";
|
|
28983
|
+
try {
|
|
28984
|
+
let requestParsed;
|
|
28985
|
+
if (apiDefinitions && apiDefinitions.endpoints.length > 0 && isApiRequestLine(namedRequest.content, apiDefinitions.endpoints)) {
|
|
28986
|
+
const apiRequest = parseApiRequest(
|
|
28987
|
+
namedRequest.content,
|
|
28988
|
+
apiDefinitions.endpoints,
|
|
28989
|
+
apiDefinitions.headerGroups
|
|
28990
|
+
);
|
|
28991
|
+
if (apiRequest) {
|
|
28992
|
+
const endpoint = getEndpoint(
|
|
28993
|
+
{ headerGroups: apiDefinitions.headerGroups, endpoints: apiDefinitions.endpoints },
|
|
28994
|
+
apiRequest.endpointName
|
|
28995
|
+
);
|
|
28996
|
+
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
|
+
});
|
|
29001
|
+
for (const [paramName, paramValue] of Object.entries(apiRequest.params)) {
|
|
29002
|
+
let resolvedValue = paramValue;
|
|
29003
|
+
if (runtimeVariables[paramValue] !== void 0) {
|
|
29004
|
+
resolvedValue = String(runtimeVariables[paramValue]);
|
|
29005
|
+
} else if (paramValue.startsWith("{{") && paramValue.endsWith("}}")) {
|
|
29006
|
+
const varName = paramValue.slice(2, -2);
|
|
29007
|
+
if (runtimeVariables[varName] !== void 0) {
|
|
29008
|
+
resolvedValue = String(runtimeVariables[varName]);
|
|
29009
|
+
}
|
|
29010
|
+
}
|
|
29011
|
+
resolvedPath = resolvedPath.replace(`{${paramName}}`, resolvedValue);
|
|
29012
|
+
}
|
|
29013
|
+
const combinedHeaders = {};
|
|
29014
|
+
for (const groupName of apiRequest.headerGroupNames) {
|
|
29015
|
+
const group = getHeaderGroup(apiDefinitions, groupName);
|
|
29016
|
+
if (group) {
|
|
29017
|
+
const resolvedHeaders = resolveHeaderValues(group, runtimeVariables);
|
|
29018
|
+
Object.assign(combinedHeaders, resolvedHeaders);
|
|
29019
|
+
}
|
|
29020
|
+
}
|
|
29021
|
+
for (const [headerName, headerValue] of Object.entries(apiRequest.inlineHeaders)) {
|
|
29022
|
+
let resolved = headerValue;
|
|
29023
|
+
resolved = resolved.replace(/\{\{([a-zA-Z_][a-zA-Z0-9_]*)\}\}/g, (_, varName) => {
|
|
29024
|
+
return runtimeVariables[varName] !== void 0 ? String(runtimeVariables[varName]) : `{{${varName}}}`;
|
|
29025
|
+
});
|
|
29026
|
+
combinedHeaders[headerName] = resolved;
|
|
29027
|
+
}
|
|
29028
|
+
const bodyParsed = parserHttpRequest(namedRequest.content, runtimeVariables);
|
|
29029
|
+
requestParsed = {
|
|
29030
|
+
method: apiRequest.method,
|
|
29031
|
+
url: resolvedPath,
|
|
29032
|
+
headers: combinedHeaders,
|
|
29033
|
+
body: bodyParsed.body
|
|
29034
|
+
};
|
|
29035
|
+
} else {
|
|
29036
|
+
throw new Error(`Unknown endpoint: ${apiRequest.endpointName}`);
|
|
29037
|
+
}
|
|
29038
|
+
} else {
|
|
29039
|
+
requestParsed = parserHttpRequest(namedRequest.content, runtimeVariables);
|
|
29040
|
+
}
|
|
29041
|
+
} else {
|
|
29042
|
+
requestParsed = parserHttpRequest(namedRequest.content, runtimeVariables);
|
|
29043
|
+
if (apiDefinitions && apiDefinitions.headerGroups.length > 0) {
|
|
29044
|
+
requestParsed = applyHeaderGroupsToRequest(requestParsed, namedRequest.content, apiDefinitions.headerGroups, runtimeVariables);
|
|
29045
|
+
}
|
|
29046
|
+
}
|
|
29047
|
+
requestUrl = requestParsed.url;
|
|
29048
|
+
requestMethod = requestParsed.method;
|
|
29049
|
+
validatePreparedRequest(
|
|
29050
|
+
requestParsed,
|
|
29051
|
+
buildRequestValidationContext(stepIdx + 1, requestMethod, requestUrl, targetName)
|
|
29052
|
+
);
|
|
29053
|
+
const effectiveRetryCount = parsed.retryCount ?? requestParsed.retryCount;
|
|
29054
|
+
const effectiveBackoffMs = parsed.backoffMs ?? requestParsed.backoffMs ?? 1e3;
|
|
29055
|
+
const retryOpts = effectiveRetryCount ? {
|
|
29056
|
+
retryCount: effectiveRetryCount,
|
|
29057
|
+
backoffMs: effectiveBackoffMs,
|
|
29058
|
+
onRetry: (attempt, total, error, waitMs) => {
|
|
29059
|
+
reportProgress(stepIdx, "request", `[Retry ${attempt}/${total}] run ${targetName} - waiting ${waitMs}ms`, void 0);
|
|
29060
|
+
}
|
|
29061
|
+
} : void 0;
|
|
29062
|
+
const response = cookieJar ? await sendRequestWithJar(requestParsed, cookieJar, retryOpts) : await sendRequest(requestParsed, retryOpts);
|
|
29063
|
+
addResponse(response);
|
|
29064
|
+
const stepResult = {
|
|
29065
|
+
type: "request",
|
|
29066
|
+
stepIndex: stepIdx,
|
|
29067
|
+
response,
|
|
29068
|
+
requestMethod: requestParsed.method,
|
|
29069
|
+
requestUrl: requestParsed.url
|
|
29070
|
+
};
|
|
29071
|
+
orderedSteps.push(stepResult);
|
|
29072
|
+
reportProgress(stepIdx, "namedRequest", `run ${targetName} \u2192 ${requestParsed.method} ${requestParsed.url}`, stepResult);
|
|
29073
|
+
const relevantCaptures = captures.filter((c) => c.afterRequest === requestIndex);
|
|
29074
|
+
for (const capture of relevantCaptures) {
|
|
29075
|
+
const value = getValueByPath(response, capture.path);
|
|
29076
|
+
if (value !== void 0) {
|
|
29077
|
+
runtimeVariables[capture.varName] = value;
|
|
29340
29078
|
} else {
|
|
29341
|
-
|
|
29079
|
+
errors.push(`Warning: Could not capture ${capture.varName} from $${requestIndex}.${capture.path}`);
|
|
29342
29080
|
}
|
|
29343
29081
|
}
|
|
29082
|
+
} catch (error) {
|
|
29083
|
+
const userMessage = formatUserFacingError(
|
|
29084
|
+
error,
|
|
29085
|
+
buildRequestValidationContext(stepIdx + 1, requestMethod || void 0, requestUrl || void 0, targetName)
|
|
29086
|
+
);
|
|
29087
|
+
let errorDetails = `Named request "${targetName}" failed:
|
|
29088
|
+
${indentMultiline(userMessage)}`;
|
|
29089
|
+
if (requestUrl && !/\nRequest:\s/.test(userMessage)) {
|
|
29090
|
+
errorDetails += `
|
|
29091
|
+
Request: ${requestMethod} ${requestUrl}`;
|
|
29092
|
+
}
|
|
29093
|
+
errors.push(errorDetails);
|
|
29094
|
+
await emitFailure(errorDetails, step, stepIdx);
|
|
29095
|
+
return {
|
|
29096
|
+
name: "",
|
|
29097
|
+
success: false,
|
|
29098
|
+
responses,
|
|
29099
|
+
scriptResults,
|
|
29100
|
+
assertionResults,
|
|
29101
|
+
steps: orderedSteps,
|
|
29102
|
+
errors,
|
|
29103
|
+
duration: Date.now() - startTime
|
|
29104
|
+
};
|
|
29344
29105
|
}
|
|
29345
|
-
}
|
|
29346
|
-
|
|
29347
|
-
|
|
29348
|
-
|
|
29349
|
-
|
|
29350
|
-
|
|
29351
|
-
|
|
29352
|
-
|
|
29353
|
-
|
|
29354
|
-
|
|
29355
|
-
|
|
29106
|
+
} else if (step.type === "varRunSequence") {
|
|
29107
|
+
const parsed = parseVarRunSequenceCommand(step.content);
|
|
29108
|
+
if (!parsed) {
|
|
29109
|
+
errors.push(`Invalid var run sequence command: ${step.content}`);
|
|
29110
|
+
return {
|
|
29111
|
+
name: "",
|
|
29112
|
+
success: false,
|
|
29113
|
+
responses,
|
|
29114
|
+
scriptResults,
|
|
29115
|
+
assertionResults,
|
|
29116
|
+
steps: orderedSteps,
|
|
29117
|
+
errors,
|
|
29118
|
+
duration: Date.now() - startTime
|
|
29119
|
+
};
|
|
29356
29120
|
}
|
|
29357
|
-
|
|
29358
|
-
|
|
29359
|
-
|
|
29360
|
-
|
|
29361
|
-
|
|
29362
|
-
|
|
29363
|
-
|
|
29364
|
-
|
|
29365
|
-
|
|
29366
|
-
|
|
29367
|
-
|
|
29368
|
-
|
|
29369
|
-
|
|
29370
|
-
|
|
29371
|
-
const
|
|
29372
|
-
|
|
29373
|
-
|
|
29121
|
+
const { varName, sequenceName, args: runArgs } = parsed;
|
|
29122
|
+
if (!fullDocumentText) {
|
|
29123
|
+
errors.push(`Cannot run sequence "${sequenceName}": full document text not provided`);
|
|
29124
|
+
return {
|
|
29125
|
+
name: "",
|
|
29126
|
+
success: false,
|
|
29127
|
+
responses,
|
|
29128
|
+
scriptResults,
|
|
29129
|
+
assertionResults,
|
|
29130
|
+
steps: orderedSteps,
|
|
29131
|
+
errors,
|
|
29132
|
+
duration: Date.now() - startTime
|
|
29133
|
+
};
|
|
29134
|
+
}
|
|
29135
|
+
const allSequences = extractSequences(fullDocumentText);
|
|
29136
|
+
const targetSequence = allSequences.find((s) => s.name === sequenceName);
|
|
29137
|
+
if (!targetSequence) {
|
|
29138
|
+
const namedRequest = getNamedRequest(fullDocumentText, sequenceName);
|
|
29139
|
+
if (!namedRequest) {
|
|
29140
|
+
errors.push(`"${sequenceName}" is not a named request or sequence`);
|
|
29141
|
+
return {
|
|
29142
|
+
name: "",
|
|
29143
|
+
success: false,
|
|
29144
|
+
responses,
|
|
29145
|
+
scriptResults,
|
|
29146
|
+
assertionResults,
|
|
29147
|
+
steps: orderedSteps,
|
|
29148
|
+
errors,
|
|
29149
|
+
duration: Date.now() - startTime
|
|
29150
|
+
};
|
|
29151
|
+
}
|
|
29152
|
+
requestIndex++;
|
|
29153
|
+
let requestUrl = "";
|
|
29154
|
+
let requestMethod = "";
|
|
29155
|
+
try {
|
|
29156
|
+
const requestParsed = parserHttpRequest(namedRequest.content, runtimeVariables);
|
|
29157
|
+
requestUrl = requestParsed.url;
|
|
29158
|
+
requestMethod = requestParsed.method;
|
|
29159
|
+
validatePreparedRequest(
|
|
29160
|
+
requestParsed,
|
|
29161
|
+
buildRequestValidationContext(stepIdx + 1, requestMethod, requestUrl, `${varName} = run ${sequenceName}`)
|
|
29162
|
+
);
|
|
29163
|
+
const effectiveRetryCount = parsed.retryCount ?? requestParsed.retryCount;
|
|
29164
|
+
const effectiveBackoffMs = parsed.backoffMs ?? requestParsed.backoffMs ?? 1e3;
|
|
29165
|
+
const retryOpts = effectiveRetryCount ? {
|
|
29166
|
+
retryCount: effectiveRetryCount,
|
|
29167
|
+
backoffMs: effectiveBackoffMs,
|
|
29168
|
+
onRetry: (attempt, total, error, waitMs) => {
|
|
29169
|
+
reportProgress(stepIdx, "request", `[Retry ${attempt}/${total}] var ${varName} = run ${sequenceName} - waiting ${waitMs}ms`, void 0);
|
|
29170
|
+
}
|
|
29171
|
+
} : void 0;
|
|
29172
|
+
const response = cookieJar ? await sendRequestWithJar(requestParsed, cookieJar, retryOpts) : await sendRequest(requestParsed, retryOpts);
|
|
29173
|
+
addResponse(response);
|
|
29174
|
+
responseIndexToVariable.set(responses.length, varName);
|
|
29175
|
+
const stepResult = {
|
|
29176
|
+
type: "request",
|
|
29177
|
+
stepIndex: stepIdx,
|
|
29178
|
+
response,
|
|
29179
|
+
requestMethod: requestParsed.method,
|
|
29180
|
+
requestUrl: requestParsed.url,
|
|
29181
|
+
variableName: varName
|
|
29182
|
+
};
|
|
29183
|
+
orderedSteps.push(stepResult);
|
|
29184
|
+
reportProgress(stepIdx, "namedRequest", `var ${varName} = run ${sequenceName} \u2192 ${requestParsed.method} ${requestParsed.url}`, stepResult);
|
|
29185
|
+
const capturedResponse = {
|
|
29186
|
+
status: response.status,
|
|
29187
|
+
statusText: response.statusText,
|
|
29188
|
+
body: response.body,
|
|
29189
|
+
headers: response.headers
|
|
29190
|
+
};
|
|
29191
|
+
runtimeVariables[varName] = JSON.stringify(capturedResponse);
|
|
29192
|
+
const relevantCaptures = captures.filter((c) => c.afterRequest === requestIndex);
|
|
29193
|
+
for (const capture of relevantCaptures) {
|
|
29194
|
+
const value = getValueByPath(response, capture.path);
|
|
29195
|
+
if (value !== void 0) {
|
|
29196
|
+
runtimeVariables[capture.varName] = value;
|
|
29197
|
+
} else {
|
|
29198
|
+
errors.push(`Warning: Could not capture ${capture.varName} from $${requestIndex}.${capture.path}`);
|
|
29199
|
+
}
|
|
29200
|
+
}
|
|
29201
|
+
} catch (error) {
|
|
29202
|
+
const userMessage = formatUserFacingError(
|
|
29203
|
+
error,
|
|
29204
|
+
buildRequestValidationContext(stepIdx + 1, requestMethod || void 0, requestUrl || void 0, `${varName} = run ${sequenceName}`)
|
|
29205
|
+
);
|
|
29206
|
+
let errorDetails = `Named request "${sequenceName}" failed:
|
|
29207
|
+
${indentMultiline(userMessage)}`;
|
|
29208
|
+
if (requestUrl && !/\nRequest:\s/.test(userMessage)) {
|
|
29209
|
+
errorDetails += `
|
|
29210
|
+
Request: ${requestMethod} ${requestUrl}`;
|
|
29211
|
+
}
|
|
29212
|
+
errors.push(errorDetails);
|
|
29213
|
+
await emitFailure(errorDetails, step, stepIdx);
|
|
29214
|
+
return {
|
|
29215
|
+
name: "",
|
|
29216
|
+
success: false,
|
|
29217
|
+
responses,
|
|
29218
|
+
scriptResults,
|
|
29219
|
+
assertionResults,
|
|
29220
|
+
steps: orderedSteps,
|
|
29221
|
+
errors,
|
|
29222
|
+
duration: Date.now() - startTime
|
|
29223
|
+
};
|
|
29224
|
+
}
|
|
29225
|
+
continue;
|
|
29226
|
+
}
|
|
29227
|
+
const currentCallStack = callStack || [];
|
|
29228
|
+
if (currentCallStack.includes(sequenceName)) {
|
|
29229
|
+
errors.push(`Circular reference detected: ${[...currentCallStack, sequenceName].join(" \u2192 ")}`);
|
|
29230
|
+
return {
|
|
29231
|
+
name: "",
|
|
29232
|
+
success: false,
|
|
29233
|
+
responses,
|
|
29234
|
+
scriptResults,
|
|
29235
|
+
assertionResults,
|
|
29236
|
+
steps: orderedSteps,
|
|
29237
|
+
errors,
|
|
29238
|
+
duration: Date.now() - startTime
|
|
29239
|
+
};
|
|
29240
|
+
}
|
|
29241
|
+
let sequenceArgs2 = {};
|
|
29242
|
+
if (targetSequence.parameters.length > 0 || runArgs.length > 0) {
|
|
29243
|
+
const bindResult = bindSequenceArguments(targetSequence.parameters, runArgs, runtimeVariables);
|
|
29244
|
+
if ("error" in bindResult) {
|
|
29245
|
+
errors.push(`Error calling sequence "${sequenceName}": ${bindResult.error}`);
|
|
29246
|
+
return {
|
|
29247
|
+
name: "",
|
|
29248
|
+
success: false,
|
|
29249
|
+
responses,
|
|
29250
|
+
scriptResults,
|
|
29251
|
+
assertionResults,
|
|
29252
|
+
steps: orderedSteps,
|
|
29253
|
+
errors,
|
|
29254
|
+
duration: Date.now() - startTime
|
|
29255
|
+
};
|
|
29256
|
+
}
|
|
29257
|
+
sequenceArgs2 = bindResult.variables;
|
|
29258
|
+
}
|
|
29259
|
+
if (tagFilterOptions && tagFilterOptions.filters.length > 0) {
|
|
29260
|
+
if (!sequenceMatchesTags(targetSequence, tagFilterOptions)) {
|
|
29261
|
+
continue;
|
|
29262
|
+
}
|
|
29263
|
+
}
|
|
29264
|
+
reportProgress(stepIdx, "sequenceStart", `Starting sequence ${sequenceName}`, void 0, sequenceName);
|
|
29265
|
+
let subWorkingDir = workingDir;
|
|
29266
|
+
if (sequenceSources) {
|
|
29267
|
+
const sourceFile = sequenceSources.get(sequenceName.toLowerCase());
|
|
29268
|
+
if (sourceFile) {
|
|
29269
|
+
const path10 = await import("path");
|
|
29270
|
+
subWorkingDir = path10.dirname(sourceFile);
|
|
29271
|
+
}
|
|
29272
|
+
}
|
|
29273
|
+
const targetLocation = executionContext?.sequenceLocationIndex?.get(sequenceName.toLowerCase());
|
|
29274
|
+
const childExecutionContext = {
|
|
29275
|
+
filePath: targetLocation?.filePath ?? executionContext?.filePath,
|
|
29276
|
+
sequenceName,
|
|
29277
|
+
environment: executionContext?.environment,
|
|
29278
|
+
sequenceStartLine: targetLocation?.startLine ?? targetSequence.startLine,
|
|
29279
|
+
sequenceLocationIndex: executionContext?.sequenceLocationIndex
|
|
29280
|
+
};
|
|
29281
|
+
const subResult = await runSequenceWithJar(
|
|
29282
|
+
targetSequence.content,
|
|
29283
|
+
runtimeVariables,
|
|
29284
|
+
cookieJar,
|
|
29285
|
+
subWorkingDir,
|
|
29286
|
+
fullDocumentText,
|
|
29287
|
+
onProgress,
|
|
29288
|
+
[...currentCallStack, sequenceName],
|
|
29289
|
+
sequenceArgs2,
|
|
29290
|
+
// Pass bound arguments
|
|
29291
|
+
apiDefinitions,
|
|
29292
|
+
// Pass API definitions for endpoint resolution
|
|
29293
|
+
tagFilterOptions,
|
|
29294
|
+
// Pass tag filter options for nested sequence filtering
|
|
29295
|
+
sequenceSources,
|
|
29296
|
+
// Pass sequence sources for nested sequences
|
|
29297
|
+
childExecutionContext,
|
|
29298
|
+
debugHooks
|
|
29299
|
+
);
|
|
29300
|
+
reportProgress(stepIdx, "sequenceEnd", `Finished sequence ${sequenceName}`, void 0, sequenceName);
|
|
29301
|
+
for (const subResponse of subResult.responses) {
|
|
29302
|
+
addResponse(subResponse);
|
|
29303
|
+
}
|
|
29304
|
+
scriptResults.push(...subResult.scriptResults);
|
|
29305
|
+
assertionResults.push(...subResult.assertionResults);
|
|
29306
|
+
for (const subStep of subResult.steps) {
|
|
29307
|
+
orderedSteps.push({
|
|
29308
|
+
...subStep,
|
|
29309
|
+
stepIndex: orderedSteps.length
|
|
29310
|
+
});
|
|
29311
|
+
}
|
|
29312
|
+
const returnExpressions = extractReturnVariables(targetSequence.content);
|
|
29313
|
+
if (returnExpressions && returnExpressions.length > 0 && subResult.variables) {
|
|
29314
|
+
if (returnExpressions.length === 1) {
|
|
29315
|
+
const resolved = resolveReturnExpression(returnExpressions[0], subResult.variables);
|
|
29316
|
+
if (resolved) {
|
|
29317
|
+
runtimeVariables[varName] = resolved.value;
|
|
29318
|
+
} else {
|
|
29319
|
+
runtimeVariables[varName] = "";
|
|
29320
|
+
}
|
|
29321
|
+
} else {
|
|
29322
|
+
const returnedObj = {};
|
|
29323
|
+
for (const expr of returnExpressions) {
|
|
29324
|
+
const resolved = resolveReturnExpression(expr, subResult.variables);
|
|
29325
|
+
if (resolved) {
|
|
29326
|
+
returnedObj[resolved.key] = resolved.value;
|
|
29327
|
+
}
|
|
29328
|
+
}
|
|
29329
|
+
runtimeVariables[varName] = JSON.stringify(returnedObj);
|
|
29330
|
+
}
|
|
29374
29331
|
} else {
|
|
29375
|
-
|
|
29332
|
+
runtimeVariables[varName] = "";
|
|
29376
29333
|
}
|
|
29377
|
-
|
|
29378
|
-
|
|
29379
|
-
|
|
29380
|
-
|
|
29381
|
-
|
|
29382
|
-
|
|
29383
|
-
|
|
29334
|
+
requestIndex += subResult.responses.length;
|
|
29335
|
+
if (!subResult.success) {
|
|
29336
|
+
errors.push(`Sequence "${sequenceName}" failed`);
|
|
29337
|
+
errors.push(...subResult.errors);
|
|
29338
|
+
return {
|
|
29339
|
+
name: "",
|
|
29340
|
+
success: false,
|
|
29341
|
+
responses,
|
|
29342
|
+
scriptResults,
|
|
29343
|
+
assertionResults,
|
|
29344
|
+
steps: orderedSteps,
|
|
29345
|
+
errors,
|
|
29346
|
+
duration: Date.now() - startTime,
|
|
29347
|
+
variables: runtimeVariables
|
|
29348
|
+
};
|
|
29349
|
+
}
|
|
29350
|
+
continue;
|
|
29351
|
+
} else {
|
|
29352
|
+
requestIndex++;
|
|
29353
|
+
let parsed;
|
|
29354
|
+
let requestDescription = "";
|
|
29355
|
+
try {
|
|
29356
|
+
if (apiDefinitions && apiDefinitions.endpoints.length > 0 && isApiRequestLine(step.content, apiDefinitions.endpoints)) {
|
|
29357
|
+
const apiRequest = parseApiRequest(
|
|
29358
|
+
step.content,
|
|
29359
|
+
apiDefinitions.endpoints,
|
|
29360
|
+
apiDefinitions.headerGroups
|
|
29361
|
+
);
|
|
29362
|
+
if (apiRequest) {
|
|
29363
|
+
const endpoint = getEndpoint(
|
|
29364
|
+
{ headerGroups: apiDefinitions.headerGroups, endpoints: apiDefinitions.endpoints },
|
|
29365
|
+
apiRequest.endpointName
|
|
29366
|
+
);
|
|
29367
|
+
if (!endpoint) {
|
|
29368
|
+
throw new Error(`Unknown endpoint: ${apiRequest.endpointName}`);
|
|
29369
|
+
}
|
|
29370
|
+
const pathWithVars = substituteVariables(endpoint.path, runtimeVariables);
|
|
29371
|
+
const resolvedParams = {};
|
|
29372
|
+
for (const [key, value] of Object.entries(apiRequest.params)) {
|
|
29373
|
+
const bareResolved = resolveBareVariables(value, runtimeVariables);
|
|
29374
|
+
resolvedParams[key] = substituteVariables(bareResolved, runtimeVariables);
|
|
29375
|
+
}
|
|
29376
|
+
let resolvedPath = pathWithVars;
|
|
29377
|
+
for (const paramName of endpoint.parameters) {
|
|
29378
|
+
const value = resolvedParams[paramName];
|
|
29379
|
+
if (value !== void 0) {
|
|
29380
|
+
resolvedPath = resolvedPath.replace(`{${paramName}}`, value);
|
|
29381
|
+
}
|
|
29382
|
+
}
|
|
29383
|
+
const combinedHeaders = {};
|
|
29384
|
+
for (const groupName of apiRequest.headerGroupNames) {
|
|
29385
|
+
const group = getHeaderGroup(
|
|
29386
|
+
{ headerGroups: apiDefinitions.headerGroups, endpoints: apiDefinitions.endpoints },
|
|
29387
|
+
groupName
|
|
29388
|
+
);
|
|
29389
|
+
if (group) {
|
|
29390
|
+
const resolvedHeaders = resolveHeaderValues(group, runtimeVariables);
|
|
29391
|
+
Object.assign(combinedHeaders, resolvedHeaders);
|
|
29392
|
+
}
|
|
29393
|
+
}
|
|
29394
|
+
for (const [headerName, headerValue] of Object.entries(apiRequest.inlineHeaders)) {
|
|
29395
|
+
combinedHeaders[headerName] = substituteVariables(headerValue, runtimeVariables);
|
|
29396
|
+
}
|
|
29397
|
+
let resolvedBody;
|
|
29398
|
+
if (apiRequest.body) {
|
|
29399
|
+
resolvedBody = substituteVariables(apiRequest.body, runtimeVariables);
|
|
29400
|
+
}
|
|
29401
|
+
parsed = {
|
|
29402
|
+
method: apiRequest.method,
|
|
29403
|
+
url: resolvedPath,
|
|
29404
|
+
headers: combinedHeaders,
|
|
29405
|
+
body: resolvedBody
|
|
29406
|
+
};
|
|
29407
|
+
requestDescription = `${apiRequest.endpointName}(${Object.values(resolvedParams).join(", ")}) \u2192 ${parsed.method} ${parsed.url}`;
|
|
29408
|
+
} else {
|
|
29409
|
+
parsed = parserHttpRequest(step.content, runtimeVariables);
|
|
29410
|
+
requestDescription = `${parsed.method} ${parsed.url}`;
|
|
29411
|
+
if (apiDefinitions && apiDefinitions.headerGroups.length > 0) {
|
|
29412
|
+
parsed = applyHeaderGroupsToRequest(parsed, step.content, apiDefinitions.headerGroups, runtimeVariables);
|
|
29413
|
+
}
|
|
29414
|
+
}
|
|
29415
|
+
} else {
|
|
29416
|
+
parsed = parserHttpRequest(step.content, runtimeVariables);
|
|
29417
|
+
requestDescription = `${parsed.method} ${parsed.url}`;
|
|
29418
|
+
if (apiDefinitions && apiDefinitions.headerGroups.length > 0) {
|
|
29419
|
+
parsed = applyHeaderGroupsToRequest(parsed, step.content, apiDefinitions.headerGroups, runtimeVariables);
|
|
29420
|
+
}
|
|
29421
|
+
if (parsed.body) {
|
|
29422
|
+
const bodyTrimmed = parsed.body.trim();
|
|
29423
|
+
const bareVarMatch = bodyTrimmed.match(/^([a-zA-Z_][a-zA-Z0-9_]*)$/);
|
|
29424
|
+
if (bareVarMatch && bareVarMatch[1] in runtimeVariables) {
|
|
29425
|
+
const varValue = runtimeVariables[bareVarMatch[1]];
|
|
29426
|
+
if (typeof varValue === "object" && varValue !== null) {
|
|
29427
|
+
parsed.body = JSON.stringify(varValue);
|
|
29428
|
+
} else if (typeof varValue === "string") {
|
|
29429
|
+
parsed.body = varValue;
|
|
29430
|
+
} else {
|
|
29431
|
+
parsed.body = String(varValue);
|
|
29432
|
+
}
|
|
29433
|
+
}
|
|
29434
|
+
}
|
|
29435
|
+
}
|
|
29436
|
+
const { retryCount, backoffMs } = extractRetryOptions(step.content);
|
|
29437
|
+
validatePreparedRequest(
|
|
29438
|
+
parsed,
|
|
29439
|
+
buildRequestValidationContext(stepIdx + 1, parsed.method, parsed.url)
|
|
29440
|
+
);
|
|
29441
|
+
const retryOpts = retryCount ?? parsed.retryCount ? {
|
|
29442
|
+
retryCount: retryCount ?? parsed.retryCount ?? 0,
|
|
29443
|
+
backoffMs: backoffMs ?? parsed.backoffMs ?? 1e3,
|
|
29444
|
+
onRetry: (attempt, total, error, waitMs) => {
|
|
29445
|
+
reportProgress(stepIdx, "request", `[Retry ${attempt}/${total}] ${requestDescription} - waiting ${waitMs}ms`, void 0);
|
|
29446
|
+
}
|
|
29447
|
+
} : void 0;
|
|
29448
|
+
const response = cookieJar ? await sendRequestWithJar(parsed, cookieJar, retryOpts) : await sendRequest(parsed, retryOpts);
|
|
29449
|
+
addResponse(response);
|
|
29450
|
+
const stepResult = {
|
|
29451
|
+
type: "request",
|
|
29452
|
+
stepIndex: stepIdx,
|
|
29453
|
+
response,
|
|
29454
|
+
requestMethod: parsed.method,
|
|
29455
|
+
requestUrl: parsed.url
|
|
29456
|
+
};
|
|
29457
|
+
orderedSteps.push(stepResult);
|
|
29458
|
+
reportProgress(stepIdx, "request", requestDescription, stepResult);
|
|
29459
|
+
const relevantCaptures = captures.filter((c) => c.afterRequest === requestIndex);
|
|
29460
|
+
for (const capture of relevantCaptures) {
|
|
29461
|
+
const value = getValueByPath(response, capture.path);
|
|
29462
|
+
if (value !== void 0) {
|
|
29463
|
+
runtimeVariables[capture.varName] = value;
|
|
29464
|
+
} else {
|
|
29465
|
+
errors.push(`Warning: Could not capture ${capture.varName} from $${requestIndex}.${capture.path}`);
|
|
29466
|
+
}
|
|
29467
|
+
}
|
|
29468
|
+
} catch (error) {
|
|
29469
|
+
const userMessage = formatUserFacingError(
|
|
29470
|
+
error,
|
|
29471
|
+
buildRequestValidationContext(stepIdx + 1)
|
|
29472
|
+
);
|
|
29473
|
+
let errorDetails = `Request ${requestIndex} failed:
|
|
29384
29474
|
${indentMultiline(userMessage)}`;
|
|
29385
|
-
|
|
29386
|
-
|
|
29475
|
+
if (requestDescription && !/\nRequest:\s/.test(userMessage)) {
|
|
29476
|
+
errorDetails += `
|
|
29387
29477
|
Request: ${requestDescription}`;
|
|
29478
|
+
}
|
|
29479
|
+
errors.push(errorDetails);
|
|
29480
|
+
await emitFailure(errorDetails, step, stepIdx);
|
|
29481
|
+
return {
|
|
29482
|
+
name: "",
|
|
29483
|
+
success: false,
|
|
29484
|
+
responses,
|
|
29485
|
+
scriptResults,
|
|
29486
|
+
assertionResults,
|
|
29487
|
+
steps: orderedSteps,
|
|
29488
|
+
errors,
|
|
29489
|
+
duration: Date.now() - startTime
|
|
29490
|
+
};
|
|
29491
|
+
}
|
|
29388
29492
|
}
|
|
29389
|
-
|
|
29390
|
-
|
|
29391
|
-
name: "",
|
|
29392
|
-
success: false,
|
|
29393
|
-
responses,
|
|
29394
|
-
scriptResults,
|
|
29395
|
-
assertionResults,
|
|
29396
|
-
steps: orderedSteps,
|
|
29397
|
-
errors,
|
|
29398
|
-
duration: Date.now() - startTime
|
|
29399
|
-
};
|
|
29493
|
+
} finally {
|
|
29494
|
+
await emitAfterStep(step, stepIdx);
|
|
29400
29495
|
}
|
|
29401
29496
|
}
|
|
29497
|
+
return {
|
|
29498
|
+
name: "",
|
|
29499
|
+
success: errors.filter((e) => !e.startsWith("Warning")).length === 0,
|
|
29500
|
+
responses,
|
|
29501
|
+
scriptResults,
|
|
29502
|
+
assertionResults,
|
|
29503
|
+
steps: orderedSteps,
|
|
29504
|
+
errors,
|
|
29505
|
+
duration: Date.now() - startTime,
|
|
29506
|
+
variables: runtimeVariables
|
|
29507
|
+
};
|
|
29508
|
+
} finally {
|
|
29509
|
+
if (debugHooks?.onSequenceExit) {
|
|
29510
|
+
await debugHooks.onSequenceExit({
|
|
29511
|
+
sequenceName: executionContext?.sequenceName,
|
|
29512
|
+
filePath: executionContext?.filePath,
|
|
29513
|
+
declarationLine: executionContext?.sequenceStartLine,
|
|
29514
|
+
nestingDepth,
|
|
29515
|
+
runtimeVariables,
|
|
29516
|
+
responses
|
|
29517
|
+
});
|
|
29518
|
+
}
|
|
29402
29519
|
}
|
|
29403
|
-
return {
|
|
29404
|
-
name: "",
|
|
29405
|
-
success: errors.filter((e) => !e.startsWith("Warning")).length === 0,
|
|
29406
|
-
responses,
|
|
29407
|
-
scriptResults,
|
|
29408
|
-
assertionResults,
|
|
29409
|
-
steps: orderedSteps,
|
|
29410
|
-
errors,
|
|
29411
|
-
duration: Date.now() - startTime,
|
|
29412
|
-
variables: runtimeVariables
|
|
29413
|
-
};
|
|
29414
29520
|
}
|
|
29415
29521
|
|
|
29416
29522
|
// src/cli/colors.ts
|
|
@@ -30591,8 +30697,8 @@ function generateHtmlReportFromResponse(response, testName, options) {
|
|
|
30591
30697
|
}
|
|
30592
30698
|
|
|
30593
30699
|
// src/environmentParser.ts
|
|
30594
|
-
var
|
|
30595
|
-
var
|
|
30700
|
+
var fs7 = __toESM(require("fs"));
|
|
30701
|
+
var path6 = __toESM(require("path"));
|
|
30596
30702
|
|
|
30597
30703
|
// src/secrets/crypto.ts
|
|
30598
30704
|
var crypto2 = __toESM(require("crypto"));
|
|
@@ -30660,30 +30766,48 @@ function decryptSecretValue(encryptedValue, sharedKey) {
|
|
|
30660
30766
|
}
|
|
30661
30767
|
|
|
30662
30768
|
// src/secrets/keyStore.ts
|
|
30769
|
+
var fs6 = __toESM(require("fs"));
|
|
30770
|
+
var path5 = __toESM(require("path"));
|
|
30771
|
+
|
|
30772
|
+
// src/cacheDir.ts
|
|
30663
30773
|
var fs5 = __toESM(require("fs"));
|
|
30664
30774
|
var path4 = __toESM(require("path"));
|
|
30665
|
-
var
|
|
30775
|
+
var NORN_CACHE_DIR = ".norn-cache";
|
|
30776
|
+
var CACHE_GITIGNORE_FILE = ".gitignore";
|
|
30777
|
+
var CACHE_GITIGNORE_CONTENT = "*\n";
|
|
30778
|
+
function ensureNornCacheGitignore(cacheDir) {
|
|
30779
|
+
const gitignorePath = path4.join(cacheDir, CACHE_GITIGNORE_FILE);
|
|
30780
|
+
try {
|
|
30781
|
+
const hasDesiredContent = fs5.existsSync(gitignorePath) && fs5.readFileSync(gitignorePath, "utf8") === CACHE_GITIGNORE_CONTENT;
|
|
30782
|
+
if (hasDesiredContent) {
|
|
30783
|
+
return;
|
|
30784
|
+
}
|
|
30785
|
+
fs5.writeFileSync(gitignorePath, CACHE_GITIGNORE_CONTENT, "utf8");
|
|
30786
|
+
} catch {
|
|
30787
|
+
}
|
|
30788
|
+
}
|
|
30789
|
+
|
|
30790
|
+
// src/secrets/keyStore.ts
|
|
30666
30791
|
var CACHE_FILE = "secret-keys.json";
|
|
30667
30792
|
var CACHE_VERSION = 1;
|
|
30668
|
-
var CACHE_GITIGNORE_RULE = ".norn-cache/";
|
|
30669
30793
|
var sessionKeys = /* @__PURE__ */ new Map();
|
|
30670
30794
|
function getSearchStartDirectory(targetPath) {
|
|
30671
|
-
const resolvedPath =
|
|
30795
|
+
const resolvedPath = path5.resolve(targetPath);
|
|
30672
30796
|
try {
|
|
30673
|
-
const stats =
|
|
30674
|
-
return stats.isDirectory() ? resolvedPath :
|
|
30797
|
+
const stats = fs6.statSync(resolvedPath);
|
|
30798
|
+
return stats.isDirectory() ? resolvedPath : path5.dirname(resolvedPath);
|
|
30675
30799
|
} catch {
|
|
30676
|
-
return
|
|
30800
|
+
return path5.dirname(resolvedPath);
|
|
30677
30801
|
}
|
|
30678
30802
|
}
|
|
30679
30803
|
function findExistingCacheDir(targetPath) {
|
|
30680
30804
|
let dir = getSearchStartDirectory(targetPath);
|
|
30681
30805
|
while (true) {
|
|
30682
|
-
const cacheDir =
|
|
30683
|
-
if (
|
|
30806
|
+
const cacheDir = path5.join(dir, NORN_CACHE_DIR);
|
|
30807
|
+
if (fs6.existsSync(cacheDir) && fs6.statSync(cacheDir).isDirectory()) {
|
|
30684
30808
|
return cacheDir;
|
|
30685
30809
|
}
|
|
30686
|
-
const parent =
|
|
30810
|
+
const parent = path5.dirname(dir);
|
|
30687
30811
|
if (parent === dir) {
|
|
30688
30812
|
return void 0;
|
|
30689
30813
|
}
|
|
@@ -30692,67 +30816,24 @@ function findExistingCacheDir(targetPath) {
|
|
|
30692
30816
|
}
|
|
30693
30817
|
function ensureCacheDir(targetPath) {
|
|
30694
30818
|
const existing = findExistingCacheDir(targetPath);
|
|
30695
|
-
const cacheDir = existing ??
|
|
30696
|
-
if (!
|
|
30697
|
-
|
|
30819
|
+
const cacheDir = existing ?? path5.join(getSearchStartDirectory(targetPath), NORN_CACHE_DIR);
|
|
30820
|
+
if (!fs6.existsSync(cacheDir)) {
|
|
30821
|
+
fs6.mkdirSync(cacheDir, { recursive: true });
|
|
30698
30822
|
}
|
|
30823
|
+
ensureNornCacheGitignore(cacheDir);
|
|
30699
30824
|
return cacheDir;
|
|
30700
30825
|
}
|
|
30701
30826
|
function getCachePath(targetPath) {
|
|
30702
30827
|
const cacheDir = ensureCacheDir(targetPath);
|
|
30703
|
-
return
|
|
30704
|
-
}
|
|
30705
|
-
function findGitRepositoryRoot(targetPath) {
|
|
30706
|
-
let dir = getSearchStartDirectory(targetPath);
|
|
30707
|
-
while (true) {
|
|
30708
|
-
const gitPath = path4.join(dir, ".git");
|
|
30709
|
-
if (fs5.existsSync(gitPath)) {
|
|
30710
|
-
return dir;
|
|
30711
|
-
}
|
|
30712
|
-
const parent = path4.dirname(dir);
|
|
30713
|
-
if (parent === dir) {
|
|
30714
|
-
return void 0;
|
|
30715
|
-
}
|
|
30716
|
-
dir = parent;
|
|
30717
|
-
}
|
|
30718
|
-
}
|
|
30719
|
-
function lineIgnoresNornCache(line2) {
|
|
30720
|
-
const trimmed = line2.trim();
|
|
30721
|
-
if (trimmed === "" || trimmed.startsWith("#") || trimmed.startsWith("!")) {
|
|
30722
|
-
return false;
|
|
30723
|
-
}
|
|
30724
|
-
return /(^|\/)\.norn-cache\/?$/.test(trimmed);
|
|
30725
|
-
}
|
|
30726
|
-
function ensureNornCacheGitIgnored(targetPath) {
|
|
30727
|
-
const repoRoot = findGitRepositoryRoot(targetPath);
|
|
30728
|
-
if (!repoRoot) {
|
|
30729
|
-
return;
|
|
30730
|
-
}
|
|
30731
|
-
const gitignorePath = path4.join(repoRoot, ".gitignore");
|
|
30732
|
-
let current = "";
|
|
30733
|
-
try {
|
|
30734
|
-
if (fs5.existsSync(gitignorePath)) {
|
|
30735
|
-
current = fs5.readFileSync(gitignorePath, "utf8");
|
|
30736
|
-
const lines = current.split(/\r?\n/);
|
|
30737
|
-
if (lines.some(lineIgnoresNornCache)) {
|
|
30738
|
-
return;
|
|
30739
|
-
}
|
|
30740
|
-
}
|
|
30741
|
-
const prefix = current.length > 0 && !current.endsWith("\n") ? "\n" : "";
|
|
30742
|
-
const addition = `${prefix}# Norn cache
|
|
30743
|
-
${CACHE_GITIGNORE_RULE}
|
|
30744
|
-
`;
|
|
30745
|
-
fs5.writeFileSync(gitignorePath, current + addition, "utf8");
|
|
30746
|
-
} catch {
|
|
30747
|
-
}
|
|
30828
|
+
return path5.join(cacheDir, CACHE_FILE);
|
|
30748
30829
|
}
|
|
30749
30830
|
function readCache(targetPath) {
|
|
30750
30831
|
const cachePath = getCachePath(targetPath);
|
|
30751
|
-
if (!
|
|
30832
|
+
if (!fs6.existsSync(cachePath)) {
|
|
30752
30833
|
return { version: CACHE_VERSION, keys: {} };
|
|
30753
30834
|
}
|
|
30754
30835
|
try {
|
|
30755
|
-
const parsed = JSON.parse(
|
|
30836
|
+
const parsed = JSON.parse(fs6.readFileSync(cachePath, "utf8"));
|
|
30756
30837
|
if (parsed.version !== CACHE_VERSION || typeof parsed.keys !== "object" || parsed.keys === null) {
|
|
30757
30838
|
return { version: CACHE_VERSION, keys: {} };
|
|
30758
30839
|
}
|
|
@@ -30763,9 +30844,9 @@ function readCache(targetPath) {
|
|
|
30763
30844
|
}
|
|
30764
30845
|
function writeCache(targetPath, cache) {
|
|
30765
30846
|
const cachePath = getCachePath(targetPath);
|
|
30766
|
-
|
|
30847
|
+
fs6.writeFileSync(cachePath, JSON.stringify(cache, null, 2), { encoding: "utf8", mode: 384 });
|
|
30767
30848
|
try {
|
|
30768
|
-
|
|
30849
|
+
fs6.chmodSync(cachePath, 384);
|
|
30769
30850
|
} catch {
|
|
30770
30851
|
}
|
|
30771
30852
|
}
|
|
@@ -30818,7 +30899,6 @@ function setSessionSecretKey(kid, key) {
|
|
|
30818
30899
|
sessionKeys.set(kid, key);
|
|
30819
30900
|
}
|
|
30820
30901
|
function saveSecretKeyToCache(kid, key, targetPath) {
|
|
30821
|
-
ensureNornCacheGitIgnored(targetPath);
|
|
30822
30902
|
const cache = readCache(targetPath);
|
|
30823
30903
|
cache.keys[kid] = {
|
|
30824
30904
|
value: key,
|
|
@@ -30922,22 +31002,22 @@ function parseEnvFile(content, sourceFilePath) {
|
|
|
30922
31002
|
return config;
|
|
30923
31003
|
}
|
|
30924
31004
|
function getEnvSearchStartDirectory(targetPath) {
|
|
30925
|
-
const resolvedPath =
|
|
31005
|
+
const resolvedPath = path6.resolve(targetPath);
|
|
30926
31006
|
try {
|
|
30927
|
-
const stats =
|
|
30928
|
-
return stats.isDirectory() ? resolvedPath :
|
|
31007
|
+
const stats = fs7.statSync(resolvedPath);
|
|
31008
|
+
return stats.isDirectory() ? resolvedPath : path6.dirname(resolvedPath);
|
|
30929
31009
|
} catch {
|
|
30930
|
-
return
|
|
31010
|
+
return path6.dirname(resolvedPath);
|
|
30931
31011
|
}
|
|
30932
31012
|
}
|
|
30933
31013
|
function findEnvFileFromPath(filePath) {
|
|
30934
31014
|
let dir = getEnvSearchStartDirectory(filePath);
|
|
30935
31015
|
while (true) {
|
|
30936
|
-
const envPath =
|
|
30937
|
-
if (
|
|
31016
|
+
const envPath = path6.join(dir, ENV_FILENAME);
|
|
31017
|
+
if (fs7.existsSync(envPath)) {
|
|
30938
31018
|
return envPath;
|
|
30939
31019
|
}
|
|
30940
|
-
const parentDir =
|
|
31020
|
+
const parentDir = path6.dirname(dir);
|
|
30941
31021
|
if (parentDir === dir) {
|
|
30942
31022
|
break;
|
|
30943
31023
|
}
|
|
@@ -30962,7 +31042,7 @@ function resolveNornenvImports(config, baseDir, entryFilePath, readFile2, import
|
|
|
30962
31042
|
}
|
|
30963
31043
|
for (const imp of config.imports) {
|
|
30964
31044
|
const resolvedImportPath = resolveImportPath(imp.path, baseDir);
|
|
30965
|
-
if (!resolvedImportPath || !
|
|
31045
|
+
if (!resolvedImportPath || !fs7.existsSync(resolvedImportPath)) {
|
|
30966
31046
|
errors.push({
|
|
30967
31047
|
message: `Imported file not found: '${imp.path}'`,
|
|
30968
31048
|
filePath: entryFilePath,
|
|
@@ -30978,10 +31058,10 @@ function resolveNornenvImports(config, baseDir, entryFilePath, readFile2, import
|
|
|
30978
31058
|
});
|
|
30979
31059
|
continue;
|
|
30980
31060
|
}
|
|
30981
|
-
const normalizedPath =
|
|
31061
|
+
const normalizedPath = path6.resolve(resolvedImportPath);
|
|
30982
31062
|
if (stack.includes(normalizedPath)) {
|
|
30983
|
-
const entryDir =
|
|
30984
|
-
const cycle = [...stack, normalizedPath].map((p) =>
|
|
31063
|
+
const entryDir = path6.dirname(stack[0]);
|
|
31064
|
+
const cycle = [...stack, normalizedPath].map((p) => path6.relative(entryDir, p) || path6.basename(p)).join(" \u2192 ");
|
|
30985
31065
|
errors.push({
|
|
30986
31066
|
message: `Circular import detected: ${cycle}`,
|
|
30987
31067
|
filePath: entryFilePath,
|
|
@@ -31010,7 +31090,7 @@ function resolveNornenvImports(config, baseDir, entryFilePath, readFile2, import
|
|
|
31010
31090
|
if (importedConfig.imports.length > 0) {
|
|
31011
31091
|
const childResult = resolveNornenvImports(
|
|
31012
31092
|
importedConfig,
|
|
31013
|
-
|
|
31093
|
+
path6.dirname(normalizedPath),
|
|
31014
31094
|
normalizedPath,
|
|
31015
31095
|
readFile2,
|
|
31016
31096
|
[...stack, normalizedPath],
|
|
@@ -31028,7 +31108,7 @@ function resolveNornenvImports(config, baseDir, entryFilePath, readFile2, import
|
|
|
31028
31108
|
}
|
|
31029
31109
|
function resolveImportPath(importPath, baseDir) {
|
|
31030
31110
|
const cleaned = importPath.replace(/^["']|["']$/g, "");
|
|
31031
|
-
return
|
|
31111
|
+
return path6.resolve(baseDir, cleaned);
|
|
31032
31112
|
}
|
|
31033
31113
|
function registerVariableOrigins(config, filePath, origins) {
|
|
31034
31114
|
for (const varName of Object.keys(config.common)) {
|
|
@@ -31092,12 +31172,12 @@ function mergeConfigs(target, source, targetFilePath, sourceFilePath, variableOr
|
|
|
31092
31172
|
}
|
|
31093
31173
|
}
|
|
31094
31174
|
function toDisplayPath(filePath, entryFilePath) {
|
|
31095
|
-
const entryDir =
|
|
31096
|
-
const relative4 =
|
|
31097
|
-
return relative4 && relative4 !== "" ? relative4 :
|
|
31175
|
+
const entryDir = path6.dirname(entryFilePath);
|
|
31176
|
+
const relative4 = path6.relative(entryDir, filePath);
|
|
31177
|
+
return relative4 && relative4 !== "" ? relative4 : path6.basename(filePath);
|
|
31098
31178
|
}
|
|
31099
31179
|
function loadAndResolveEnvFile(filePath) {
|
|
31100
|
-
const content =
|
|
31180
|
+
const content = fs7.readFileSync(filePath, "utf-8");
|
|
31101
31181
|
const config = parseEnvFile(content, filePath);
|
|
31102
31182
|
if (config.imports.length === 0) {
|
|
31103
31183
|
const secretErrors = resolveEncryptedSecretValues(config, filePath);
|
|
@@ -31105,9 +31185,9 @@ function loadAndResolveEnvFile(filePath) {
|
|
|
31105
31185
|
}
|
|
31106
31186
|
const result = resolveNornenvImports(
|
|
31107
31187
|
config,
|
|
31108
|
-
|
|
31188
|
+
path6.dirname(filePath),
|
|
31109
31189
|
filePath,
|
|
31110
|
-
(p) =>
|
|
31190
|
+
(p) => fs7.readFileSync(p, "utf-8")
|
|
31111
31191
|
);
|
|
31112
31192
|
result.secretErrors.push(...resolveEncryptedSecretValues(result.config, filePath));
|
|
31113
31193
|
return result;
|
|
@@ -31173,14 +31253,14 @@ function resolveEncryptedSecretValues(config, entryFilePath) {
|
|
|
31173
31253
|
}
|
|
31174
31254
|
|
|
31175
31255
|
// src/secrets/cliSecrets.ts
|
|
31176
|
-
var
|
|
31177
|
-
var
|
|
31256
|
+
var fs9 = __toESM(require("fs"));
|
|
31257
|
+
var path8 = __toESM(require("path"));
|
|
31178
31258
|
var readline = __toESM(require("readline"));
|
|
31179
31259
|
var import_process = require("process");
|
|
31180
31260
|
|
|
31181
31261
|
// src/secrets/envFileSecrets.ts
|
|
31182
|
-
var
|
|
31183
|
-
var
|
|
31262
|
+
var fs8 = __toESM(require("fs"));
|
|
31263
|
+
var path7 = __toESM(require("path"));
|
|
31184
31264
|
var envRegex2 = /^\s*\[env:([a-zA-Z_][a-zA-Z0-9_-]*)\]\s*$/;
|
|
31185
31265
|
var secretRegex2 = /^(\s*secret\s+)([a-zA-Z_][a-zA-Z0-9_]*)(\s*=\s*)(.+)$/;
|
|
31186
31266
|
function extractSecretLines(content, filePath) {
|
|
@@ -31248,7 +31328,7 @@ function findSecretLine(content, variableName, envName) {
|
|
|
31248
31328
|
return secretLines.find((secret) => secret.name === variableName);
|
|
31249
31329
|
}
|
|
31250
31330
|
function loadSecretLine(filePath, variableName, envName) {
|
|
31251
|
-
const content =
|
|
31331
|
+
const content = fs8.readFileSync(filePath, "utf8");
|
|
31252
31332
|
const secret = findSecretLine(content, variableName, envName);
|
|
31253
31333
|
if (!secret) {
|
|
31254
31334
|
const envLabel = envName ? ` in [env:${envName}]` : "";
|
|
@@ -31257,22 +31337,22 @@ function loadSecretLine(filePath, variableName, envName) {
|
|
|
31257
31337
|
return { content, secret };
|
|
31258
31338
|
}
|
|
31259
31339
|
function writeSecretLine(filePath, content) {
|
|
31260
|
-
|
|
31340
|
+
fs8.writeFileSync(filePath, content, "utf8");
|
|
31261
31341
|
}
|
|
31262
31342
|
function discoverNornenvFiles(targetPath) {
|
|
31263
|
-
const resolved =
|
|
31264
|
-
if (!
|
|
31343
|
+
const resolved = path7.resolve(targetPath);
|
|
31344
|
+
if (!fs8.existsSync(resolved)) {
|
|
31265
31345
|
return [];
|
|
31266
31346
|
}
|
|
31267
|
-
const stats =
|
|
31347
|
+
const stats = fs8.statSync(resolved);
|
|
31268
31348
|
if (stats.isFile()) {
|
|
31269
|
-
return
|
|
31349
|
+
return path7.basename(resolved) === ".nornenv" ? [resolved] : [];
|
|
31270
31350
|
}
|
|
31271
31351
|
const results = [];
|
|
31272
31352
|
const walk = (dir) => {
|
|
31273
|
-
const entries =
|
|
31353
|
+
const entries = fs8.readdirSync(dir, { withFileTypes: true });
|
|
31274
31354
|
for (const entry of entries) {
|
|
31275
|
-
const fullPath =
|
|
31355
|
+
const fullPath = path7.join(dir, entry.name);
|
|
31276
31356
|
if (entry.isDirectory()) {
|
|
31277
31357
|
if (entry.name === "node_modules" || entry.name === ".git" || entry.name === "dist" || entry.name === "out") {
|
|
31278
31358
|
continue;
|
|
@@ -31331,8 +31411,8 @@ function formatSecretError(err, envFilePath) {
|
|
|
31331
31411
|
if (!envFilePath) {
|
|
31332
31412
|
return `${err.message}`;
|
|
31333
31413
|
}
|
|
31334
|
-
const relative4 =
|
|
31335
|
-
const fileLabel = relative4 && relative4 !== "" ? relative4 :
|
|
31414
|
+
const relative4 = path8.relative(path8.dirname(envFilePath), err.filePath);
|
|
31415
|
+
const fileLabel = relative4 && relative4 !== "" ? relative4 : path8.basename(err.filePath);
|
|
31336
31416
|
const lineLabel = err.line >= 0 ? `${fileLabel}:${err.line + 1}` : fileLabel;
|
|
31337
31417
|
return `${lineLabel} - ${err.message}`;
|
|
31338
31418
|
}
|
|
@@ -31428,7 +31508,7 @@ async function handleEncrypt(args) {
|
|
|
31428
31508
|
console.error(`Error: encrypt requires --file and --var.`);
|
|
31429
31509
|
return 1;
|
|
31430
31510
|
}
|
|
31431
|
-
const absoluteFilePath =
|
|
31511
|
+
const absoluteFilePath = path8.resolve(filePath);
|
|
31432
31512
|
const { content, secret } = loadSecretLine(absoluteFilePath, variableName, envName);
|
|
31433
31513
|
if (secret.encrypted) {
|
|
31434
31514
|
console.error(`Error: Secret '${variableName}' is already encrypted. Use rotate instead.`);
|
|
@@ -31460,7 +31540,7 @@ async function handleRotate(args) {
|
|
|
31460
31540
|
console.error(`Error: rotate requires --file and --var.`);
|
|
31461
31541
|
return 1;
|
|
31462
31542
|
}
|
|
31463
|
-
const absoluteFilePath =
|
|
31543
|
+
const absoluteFilePath = path8.resolve(filePath);
|
|
31464
31544
|
const { content, secret } = loadSecretLine(absoluteFilePath, variableName, envName);
|
|
31465
31545
|
let kid = explicitKid;
|
|
31466
31546
|
if (!kid && secret.encrypted) {
|
|
@@ -31491,7 +31571,7 @@ async function handleRotate(args) {
|
|
|
31491
31571
|
}
|
|
31492
31572
|
async function handleRekey(args) {
|
|
31493
31573
|
const positional = args.filter((arg) => !arg.startsWith("-"));
|
|
31494
|
-
const targetPath = positional[0] ?
|
|
31574
|
+
const targetPath = positional[0] ? path8.resolve(positional[0]) : process.cwd();
|
|
31495
31575
|
const targetKid = getFlagValue(args, "--kid");
|
|
31496
31576
|
const files = discoverNornenvFiles(targetPath);
|
|
31497
31577
|
if (files.length === 0) {
|
|
@@ -31501,7 +31581,7 @@ async function handleRekey(args) {
|
|
|
31501
31581
|
let updatedFiles = 0;
|
|
31502
31582
|
let updatedSecrets = 0;
|
|
31503
31583
|
for (const filePath of files) {
|
|
31504
|
-
const original =
|
|
31584
|
+
const original = fs9.readFileSync(filePath, "utf8");
|
|
31505
31585
|
const secretLines = extractSecretLines(original, filePath);
|
|
31506
31586
|
if (secretLines.length === 0) {
|
|
31507
31587
|
continue;
|
|
@@ -31552,7 +31632,7 @@ async function handleRekey(args) {
|
|
|
31552
31632
|
updatedSecrets += 1;
|
|
31553
31633
|
}
|
|
31554
31634
|
if (updated !== original) {
|
|
31555
|
-
|
|
31635
|
+
fs9.writeFileSync(filePath, updated, "utf8");
|
|
31556
31636
|
updatedFiles += 1;
|
|
31557
31637
|
}
|
|
31558
31638
|
}
|
|
@@ -31561,7 +31641,7 @@ async function handleRekey(args) {
|
|
|
31561
31641
|
}
|
|
31562
31642
|
async function handleAudit(args) {
|
|
31563
31643
|
const positional = args.filter((arg) => !arg.startsWith("-"));
|
|
31564
|
-
const targetPath = positional[0] ?
|
|
31644
|
+
const targetPath = positional[0] ? path8.resolve(positional[0]) : process.cwd();
|
|
31565
31645
|
const files = discoverNornenvFiles(targetPath);
|
|
31566
31646
|
if (files.length === 0) {
|
|
31567
31647
|
console.log(`No .nornenv files found under ${targetPath}`);
|
|
@@ -31569,7 +31649,7 @@ async function handleAudit(args) {
|
|
|
31569
31649
|
}
|
|
31570
31650
|
const issues = [];
|
|
31571
31651
|
for (const filePath of files) {
|
|
31572
|
-
const content =
|
|
31652
|
+
const content = fs9.readFileSync(filePath, "utf8");
|
|
31573
31653
|
const secrets = extractSecretLines(content, filePath);
|
|
31574
31654
|
for (const secret of secrets) {
|
|
31575
31655
|
if (!secret.encrypted) {
|
|
@@ -31656,9 +31736,9 @@ function printSecretResolutionErrors(errors, envFilePath) {
|
|
|
31656
31736
|
|
|
31657
31737
|
// src/cli.ts
|
|
31658
31738
|
function formatNornenvErrorLocation(rootEnvFilePath, errorFilePath, line2) {
|
|
31659
|
-
const baseDir =
|
|
31660
|
-
const relativePath =
|
|
31661
|
-
const fileLabel = relativePath && relativePath !== "" ? relativePath :
|
|
31739
|
+
const baseDir = path9.dirname(rootEnvFilePath);
|
|
31740
|
+
const relativePath = path9.relative(baseDir, errorFilePath);
|
|
31741
|
+
const fileLabel = relativePath && relativePath !== "" ? relativePath : path9.basename(errorFilePath);
|
|
31662
31742
|
return line2 >= 0 ? `${fileLabel}:${line2 + 1}` : fileLabel;
|
|
31663
31743
|
}
|
|
31664
31744
|
function resolveEnvironmentForPath(targetPath, selectedEnv) {
|
|
@@ -31740,10 +31820,10 @@ function generateTimestamp() {
|
|
|
31740
31820
|
return `${year}-${month}-${day}-${hours}${minutes}${seconds}`;
|
|
31741
31821
|
}
|
|
31742
31822
|
function generateReportPaths(outputDir, inputFile, timestamp) {
|
|
31743
|
-
const baseName =
|
|
31823
|
+
const baseName = path9.basename(inputFile, path9.extname(inputFile));
|
|
31744
31824
|
return {
|
|
31745
|
-
junitPath:
|
|
31746
|
-
htmlPath:
|
|
31825
|
+
junitPath: path9.join(outputDir, `${baseName}-${timestamp}-results.xml`),
|
|
31826
|
+
htmlPath: path9.join(outputDir, `${baseName}-${timestamp}-report.html`)
|
|
31747
31827
|
};
|
|
31748
31828
|
}
|
|
31749
31829
|
function parseArgs(args) {
|
|
@@ -32011,9 +32091,9 @@ async function runSingleRequest(fileContent, variables, cookieJar, apiDefinition
|
|
|
32011
32091
|
function discoverNornFiles(dirPath) {
|
|
32012
32092
|
const files = [];
|
|
32013
32093
|
function walkDir(currentPath) {
|
|
32014
|
-
const entries =
|
|
32094
|
+
const entries = fs10.readdirSync(currentPath, { withFileTypes: true });
|
|
32015
32095
|
for (const entry of entries) {
|
|
32016
|
-
const fullPath =
|
|
32096
|
+
const fullPath = path9.join(currentPath, entry.name);
|
|
32017
32097
|
if (entry.isDirectory()) {
|
|
32018
32098
|
if (!entry.name.startsWith(".") && entry.name !== "node_modules") {
|
|
32019
32099
|
walkDir(fullPath);
|
|
@@ -32033,7 +32113,7 @@ function countTestSequences(fileContent, tagFilterOptions) {
|
|
|
32033
32113
|
return { total: testSequences.length, filtered };
|
|
32034
32114
|
}
|
|
32035
32115
|
async function loadTheoryFile(theoryPath, workingDir) {
|
|
32036
|
-
const absolutePath =
|
|
32116
|
+
const absolutePath = path9.resolve(workingDir, theoryPath);
|
|
32037
32117
|
const content = await fsPromises.readFile(absolutePath, "utf-8");
|
|
32038
32118
|
return JSON.parse(content);
|
|
32039
32119
|
}
|
|
@@ -32152,12 +32232,12 @@ async function main() {
|
|
|
32152
32232
|
if (options.insecure) {
|
|
32153
32233
|
console.error(colors.warning("Warning: TLS certificate verification is disabled (--insecure). Use this only for local development."));
|
|
32154
32234
|
}
|
|
32155
|
-
const inputPath =
|
|
32156
|
-
if (!
|
|
32235
|
+
const inputPath = path9.resolve(options.file);
|
|
32236
|
+
if (!fs10.existsSync(inputPath)) {
|
|
32157
32237
|
console.error(`Error: Path not found: ${inputPath}`);
|
|
32158
32238
|
process.exit(1);
|
|
32159
32239
|
}
|
|
32160
|
-
const isDirectory =
|
|
32240
|
+
const isDirectory = fs10.statSync(inputPath).isDirectory();
|
|
32161
32241
|
let filesToRun;
|
|
32162
32242
|
if (isDirectory) {
|
|
32163
32243
|
filesToRun = discoverNornFiles(inputPath);
|
|
@@ -32224,11 +32304,11 @@ async function main() {
|
|
|
32224
32304
|
}
|
|
32225
32305
|
mergeSecrets(combinedSecretNames, combinedSecretValues, resolvedEnv.secretNames, resolvedEnv.secretValues);
|
|
32226
32306
|
const redaction2 = createRedactionOptions(combinedSecretNames, combinedSecretValues, !options.noRedact);
|
|
32227
|
-
const fileContent =
|
|
32307
|
+
const fileContent = fs10.readFileSync(filePath, "utf-8");
|
|
32228
32308
|
const fileVariables = extractFileLevelVariables(fileContent);
|
|
32229
32309
|
const variables = { ...resolvedEnv.variables, ...fileVariables };
|
|
32230
32310
|
const cookieJar = createCookieJar();
|
|
32231
|
-
const workingDir =
|
|
32311
|
+
const workingDir = path9.dirname(filePath);
|
|
32232
32312
|
const importResult = await resolveImports(
|
|
32233
32313
|
fileContent,
|
|
32234
32314
|
workingDir,
|
|
@@ -32329,7 +32409,7 @@ ${fileContent}` : fileContent;
|
|
|
32329
32409
|
let totalTestCount = 0;
|
|
32330
32410
|
let filteredTestCount = 0;
|
|
32331
32411
|
for (const filePath of filesToRun) {
|
|
32332
|
-
const fileContent =
|
|
32412
|
+
const fileContent = fs10.readFileSync(filePath, "utf-8");
|
|
32333
32413
|
const counts = countTestSequences(fileContent, tagFilterOptions);
|
|
32334
32414
|
totalTestCount += counts.total;
|
|
32335
32415
|
filteredTestCount += counts.filtered;
|
|
@@ -32371,16 +32451,16 @@ ${fileContent}` : fileContent;
|
|
|
32371
32451
|
process.exit(1);
|
|
32372
32452
|
}
|
|
32373
32453
|
if (!resolvedEnv.envFilePath && options.env) {
|
|
32374
|
-
const relPath = isDirectory ?
|
|
32454
|
+
const relPath = isDirectory ? path9.relative(inputPath, filePath) : path9.basename(filePath);
|
|
32375
32455
|
console.error(colors.warning(`Warning: --env specified but no .nornenv file found for ${relPath}`));
|
|
32376
32456
|
}
|
|
32377
32457
|
mergeSecrets(combinedSecretNames, combinedSecretValues, resolvedEnv.secretNames, resolvedEnv.secretValues);
|
|
32378
32458
|
const redaction2 = createRedactionOptions(combinedSecretNames, combinedSecretValues, !options.noRedact);
|
|
32379
|
-
const fileContent =
|
|
32459
|
+
const fileContent = fs10.readFileSync(filePath, "utf-8");
|
|
32380
32460
|
const fileVariables = extractFileLevelVariables(fileContent);
|
|
32381
32461
|
const variables = { ...resolvedEnv.variables, ...fileVariables };
|
|
32382
32462
|
const cookieJar = createCookieJar();
|
|
32383
|
-
const workingDir =
|
|
32463
|
+
const workingDir = path9.dirname(filePath);
|
|
32384
32464
|
const importResult = await resolveImports(
|
|
32385
32465
|
fileContent,
|
|
32386
32466
|
workingDir,
|
|
@@ -32412,7 +32492,7 @@ ${fileContent}` : fileContent;
|
|
|
32412
32492
|
continue;
|
|
32413
32493
|
}
|
|
32414
32494
|
if (isDirectory && options.output !== "json") {
|
|
32415
|
-
const relPath =
|
|
32495
|
+
const relPath = path9.relative(inputPath, filePath);
|
|
32416
32496
|
console.log(colors.info(`
|
|
32417
32497
|
\u2501\u2501\u2501 ${relPath} \u2501\u2501\u2501`));
|
|
32418
32498
|
}
|
|
@@ -32456,7 +32536,7 @@ ${fileContent}` : fileContent;
|
|
|
32456
32536
|
let htmlOutputPath = options.htmlOutput;
|
|
32457
32537
|
if (options.outputDir) {
|
|
32458
32538
|
const timestamp = generateTimestamp();
|
|
32459
|
-
const baseName = isDirectory ?
|
|
32539
|
+
const baseName = isDirectory ? path9.basename(inputPath) : path9.basename(inputPath, path9.extname(inputPath));
|
|
32460
32540
|
const generatedPaths = generateReportPaths(options.outputDir, baseName + ".norn", timestamp);
|
|
32461
32541
|
if (!junitOutputPath) {
|
|
32462
32542
|
junitOutputPath = generatedPaths.junitPath;
|
|
@@ -32464,12 +32544,12 @@ ${fileContent}` : fileContent;
|
|
|
32464
32544
|
if (!htmlOutputPath) {
|
|
32465
32545
|
htmlOutputPath = generatedPaths.htmlPath;
|
|
32466
32546
|
}
|
|
32467
|
-
if (!
|
|
32468
|
-
|
|
32547
|
+
if (!fs10.existsSync(options.outputDir)) {
|
|
32548
|
+
fs10.mkdirSync(options.outputDir, { recursive: true });
|
|
32469
32549
|
}
|
|
32470
32550
|
}
|
|
32471
32551
|
if (junitOutputPath) {
|
|
32472
|
-
const suiteName = isDirectory ?
|
|
32552
|
+
const suiteName = isDirectory ? path9.basename(inputPath) : path9.basename(inputPath, path9.extname(inputPath));
|
|
32473
32553
|
if (result.type === "request") {
|
|
32474
32554
|
generateJUnitReportFromResponse(
|
|
32475
32555
|
result.results[0],
|
|
@@ -32485,11 +32565,11 @@ ${fileContent}` : fileContent;
|
|
|
32485
32565
|
console.log(colors.info(`JUnit report written to: ${junitOutputPath}`));
|
|
32486
32566
|
}
|
|
32487
32567
|
if (htmlOutputPath) {
|
|
32488
|
-
const title = `Norn Test Report - ${
|
|
32568
|
+
const title = `Norn Test Report - ${path9.basename(inputPath)}`;
|
|
32489
32569
|
if (result.type === "request") {
|
|
32490
32570
|
generateHtmlReportFromResponse(
|
|
32491
32571
|
result.results[0],
|
|
32492
|
-
options.request ||
|
|
32572
|
+
options.request || path9.basename(inputPath),
|
|
32493
32573
|
{ outputPath: htmlOutputPath, redaction, title }
|
|
32494
32574
|
);
|
|
32495
32575
|
} else {
|