doc-detective-common 3.0.0-dev.0 → 3.0.0-dev.1
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/LICENSE +661 -21
- package/package.json +6 -6
- package/src/files.js +31 -20
- package/src/index.js +2 -1
- package/src/resolvePaths.js +46 -42
- package/src/schemas/output_schemas/config_v3.schema.json +462 -388
- package/src/schemas/output_schemas/context_v3.schema.json +195 -162
- package/src/schemas/output_schemas/httpRequest_v3.schema.json +40 -18
- package/src/schemas/output_schemas/openApi_v3.schema.json +2 -2
- package/src/schemas/output_schemas/report_v3.schema.json +459 -383
- package/src/schemas/output_schemas/spec_v3.schema.json +452 -370
- package/src/schemas/output_schemas/step_v3.schema.json +44 -22
- package/src/schemas/output_schemas/test_v3.schema.json +247 -192
- package/src/schemas/schemas.json +1991 -1627
- package/src/schemas/src_schemas/config_v3.schema.json +22 -27
- package/src/schemas/src_schemas/context_v3.schema.json +88 -64
- package/src/schemas/src_schemas/httpRequest_v3.schema.json +19 -9
- package/src/schemas/src_schemas/openApi_v3.schema.json +2 -2
- package/src/schemas/src_schemas/spec_v3.schema.json +12 -30
- package/src/schemas/src_schemas/test_v3.schema.json +6 -6
- package/src/validate.js +44 -30
- package/test/files.test.js +8 -8
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "doc-detective-common",
|
|
3
|
-
"version": "3.0.0-dev.
|
|
3
|
+
"version": "3.0.0-dev.1",
|
|
4
4
|
"description": "Shared components for Doc Detective projects.",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"url": "git+https://github.com/doc-detective/doc-detective-common.git"
|
|
14
14
|
},
|
|
15
15
|
"author": "Manny Silva",
|
|
16
|
-
"license": "
|
|
16
|
+
"license": "AGPL-3.0-only",
|
|
17
17
|
"bugs": {
|
|
18
18
|
"url": "https://github.com/doc-detective/doc-detective-common/issues"
|
|
19
19
|
},
|
|
@@ -21,16 +21,16 @@
|
|
|
21
21
|
"devDependencies": {
|
|
22
22
|
"chai": "^5.2.0",
|
|
23
23
|
"mocha": "^11.1.0",
|
|
24
|
-
"sinon": "^
|
|
24
|
+
"sinon": "^20.0.0"
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@apidevtools/json-schema-ref-parser": "^
|
|
27
|
+
"@apidevtools/json-schema-ref-parser": "^12.0.1",
|
|
28
28
|
"ajv": "^8.17.1",
|
|
29
29
|
"ajv-errors": "^3.0.0",
|
|
30
30
|
"ajv-formats": "^3.0.1",
|
|
31
31
|
"ajv-keywords": "^5.1.0",
|
|
32
|
-
"axios": "^1.8.
|
|
32
|
+
"axios": "^1.8.4",
|
|
33
33
|
"uuid": "^11.1.0",
|
|
34
|
-
"yaml": "^2.7.
|
|
34
|
+
"yaml": "^2.7.1"
|
|
35
35
|
}
|
|
36
36
|
}
|
package/src/files.js
CHANGED
|
@@ -7,42 +7,54 @@ const { URL } = require("url");
|
|
|
7
7
|
* Reads a file from a given URL or local file path and returns its content.
|
|
8
8
|
* Supports JSON and YAML file formats.
|
|
9
9
|
*
|
|
10
|
-
* @param {string}
|
|
11
|
-
* @returns {Promise<Object|string|null>} - The parsed content of the file if it's JSON or YAML,
|
|
12
|
-
* the raw content if it's another format,
|
|
10
|
+
* @param {string} fileURLOrPath - The URL or local file path of the file to read.
|
|
11
|
+
* @returns {Promise<Object|string|null>} - The parsed content of the file if it's JSON or YAML,
|
|
12
|
+
* the raw content if it's another format,
|
|
13
13
|
* or null if an error occurs.
|
|
14
14
|
*/
|
|
15
|
-
async function readFile(
|
|
15
|
+
async function readFile({ fileURLOrPath }) {
|
|
16
|
+
if (!fileURLOrPath) {
|
|
17
|
+
throw new Error("fileURLOrPath is required");
|
|
18
|
+
}
|
|
19
|
+
if (typeof fileURLOrPath !== "string") {
|
|
20
|
+
throw new Error("fileURLOrPath must be a string");
|
|
21
|
+
}
|
|
22
|
+
if (fileURLOrPath.trim() === "") {
|
|
23
|
+
throw new Error("fileURLOrPath cannot be an empty string");
|
|
24
|
+
}
|
|
16
25
|
|
|
17
26
|
let content;
|
|
18
27
|
let isRemote = false;
|
|
19
28
|
|
|
20
29
|
try {
|
|
21
|
-
const parsedURL = new URL(
|
|
22
|
-
isRemote =
|
|
30
|
+
const parsedURL = new URL(fileURLOrPath);
|
|
31
|
+
isRemote =
|
|
32
|
+
parsedURL.protocol === "http:" || parsedURL.protocol === "https:";
|
|
23
33
|
} catch (error) {
|
|
24
34
|
// Not a valid URL, assume local file path
|
|
25
35
|
}
|
|
26
36
|
|
|
27
37
|
if (isRemote) {
|
|
28
38
|
try {
|
|
29
|
-
const response = await axios.get(
|
|
39
|
+
const response = await axios.get(fileURLOrPath);
|
|
30
40
|
content = response.data;
|
|
31
41
|
} catch (error) {
|
|
32
|
-
console.warn(
|
|
42
|
+
console.warn(
|
|
43
|
+
`Error reading remote file from ${fileURLOrPath}: ${error.message}`
|
|
44
|
+
);
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
} else {
|
|
48
|
+
try {
|
|
49
|
+
content = await fs.promises.readFile(fileURLOrPath, "utf8");
|
|
50
|
+
} catch (error) {
|
|
51
|
+
if (error.code === "ENOENT") {
|
|
52
|
+
console.warn(`File not found: ${fileURLOrPath}`);
|
|
53
|
+
} else {
|
|
54
|
+
console.warn(`Error reading file: ${error.message}`);
|
|
55
|
+
}
|
|
33
56
|
return null;
|
|
34
57
|
}
|
|
35
|
-
} else {
|
|
36
|
-
try {
|
|
37
|
-
content = await fs.promises.readFile(fileURL, "utf8");
|
|
38
|
-
} catch (error) {
|
|
39
|
-
if (error.code === 'ENOENT') {
|
|
40
|
-
console.warn(`File not found: ${fileURL}`);
|
|
41
|
-
} else {
|
|
42
|
-
console.warn(`Error reading file: ${error.message}`);
|
|
43
|
-
}
|
|
44
|
-
return null;
|
|
45
|
-
}
|
|
46
58
|
}
|
|
47
59
|
|
|
48
60
|
// Parse based on file content, and return either object or string
|
|
@@ -58,7 +70,6 @@ async function readFile(fileURL) {
|
|
|
58
70
|
return content;
|
|
59
71
|
}
|
|
60
72
|
}
|
|
61
|
-
|
|
62
73
|
}
|
|
63
74
|
|
|
64
75
|
module.exports = { readFile };
|
package/src/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const { schemas } = require("./schemas");
|
|
2
|
-
const { validate } = require("./validate");
|
|
2
|
+
const { validate, transformToSchemaKey } = require("./validate");
|
|
3
3
|
const { resolvePaths } = require("./resolvePaths");
|
|
4
4
|
const { readFile } = require("./files");
|
|
5
5
|
|
|
@@ -8,4 +8,5 @@ module.exports = {
|
|
|
8
8
|
validate,
|
|
9
9
|
resolvePaths,
|
|
10
10
|
readFile,
|
|
11
|
+
transformToSchemaKey,
|
|
11
12
|
};
|
package/src/resolvePaths.js
CHANGED
|
@@ -5,22 +5,29 @@ const { validate } = require("./validate");
|
|
|
5
5
|
exports.resolvePaths = resolvePaths;
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
|
-
* Resolves paths in
|
|
8
|
+
* Resolves relative paths in configuration and specification objects to absolute paths.
|
|
9
9
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* @
|
|
15
|
-
* @
|
|
10
|
+
* This function traverses an object (either a config or spec) and converts all path properties
|
|
11
|
+
* to absolute paths based on the provided configuration and file path. It can handle nested objects
|
|
12
|
+
* and special path relationships like path/directory and savePath/saveDirectory.
|
|
13
|
+
*
|
|
14
|
+
* @async
|
|
15
|
+
* @param {Object} options - The options object.
|
|
16
|
+
* @param {Object} options.config - The configuration object containing settings like relativePathBase.
|
|
17
|
+
* @param {Object} options.object - The object whose paths need to be resolved.
|
|
18
|
+
* @param {string} options.filePath - The reference file path for resolving relative paths.
|
|
19
|
+
* @param {boolean} [options.nested=false] - Flag indicating if this is a recursive call for a nested object.
|
|
20
|
+
* @param {string} [options.objectType] - The type of object ('config' or 'spec'). Required for nested objects.
|
|
21
|
+
* @returns {Promise<Object>} The object with all paths resolved to absolute paths.
|
|
22
|
+
* @throws {Error} Throws an error if the object isn't a valid config or spec, or if objectType is missing for nested objects.
|
|
16
23
|
*/
|
|
17
|
-
async function resolvePaths(
|
|
24
|
+
async function resolvePaths({
|
|
18
25
|
config,
|
|
19
26
|
object,
|
|
20
27
|
filePath,
|
|
21
28
|
nested = false,
|
|
22
|
-
objectType
|
|
23
|
-
) {
|
|
29
|
+
objectType,
|
|
30
|
+
}) {
|
|
24
31
|
// Config properties that contain paths
|
|
25
32
|
const configPaths = [
|
|
26
33
|
"input",
|
|
@@ -38,6 +45,9 @@ async function resolvePaths(
|
|
|
38
45
|
"file",
|
|
39
46
|
"path",
|
|
40
47
|
"directory",
|
|
48
|
+
"before",
|
|
49
|
+
"after",
|
|
50
|
+
"loadVariables",
|
|
41
51
|
"setup",
|
|
42
52
|
"cleanup",
|
|
43
53
|
"savePath",
|
|
@@ -68,13 +78,19 @@ async function resolvePaths(
|
|
|
68
78
|
if (path.isAbsolute(relativePath)) {
|
|
69
79
|
return relativePath;
|
|
70
80
|
}
|
|
71
|
-
|
|
72
|
-
filePath
|
|
73
|
-
|
|
74
|
-
|
|
81
|
+
|
|
82
|
+
// Check if filePath exists and is a file
|
|
83
|
+
const fileExists = fs.existsSync(filePath);
|
|
84
|
+
const isFile = fileExists
|
|
85
|
+
? fs.lstatSync(filePath).isFile()
|
|
86
|
+
: path.parse(filePath).ext !== "";
|
|
87
|
+
|
|
88
|
+
// Use directory of filePath if it's a file (or looks like one)
|
|
89
|
+
const basePath = isFile ? path.dirname(filePath) : filePath;
|
|
90
|
+
|
|
75
91
|
// Resolve the path based on the base type
|
|
76
92
|
return baseType === "file"
|
|
77
|
-
? path.resolve(
|
|
93
|
+
? path.resolve(basePath, relativePath)
|
|
78
94
|
: path.resolve(relativePath);
|
|
79
95
|
}
|
|
80
96
|
|
|
@@ -83,13 +99,19 @@ async function resolvePaths(
|
|
|
83
99
|
let pathProperties;
|
|
84
100
|
if (!nested && !objectType) {
|
|
85
101
|
// Check if object matches the config schema
|
|
86
|
-
const validation = validate(
|
|
102
|
+
const validation = validate({
|
|
103
|
+
schemaKey: "config_v3",
|
|
104
|
+
object: { ...object },
|
|
105
|
+
});
|
|
87
106
|
if (validation.valid) {
|
|
88
107
|
pathProperties = configPaths;
|
|
89
108
|
objectType = "config";
|
|
90
109
|
} else {
|
|
91
110
|
// Check if object matches the spec schema
|
|
92
|
-
const validation = validate(
|
|
111
|
+
const validation = validate({
|
|
112
|
+
schemaKey: "spec_v3",
|
|
113
|
+
object: { ...object },
|
|
114
|
+
});
|
|
93
115
|
if (validation.valid) {
|
|
94
116
|
pathProperties = specPaths;
|
|
95
117
|
objectType = "spec";
|
|
@@ -115,13 +137,13 @@ async function resolvePaths(
|
|
|
115
137
|
objectType === "config")
|
|
116
138
|
) {
|
|
117
139
|
// If the property is an object, recursively call resolvePaths to resolve paths within the object
|
|
118
|
-
object[property] = await resolvePaths(
|
|
119
|
-
config,
|
|
120
|
-
object[property],
|
|
121
|
-
filePath,
|
|
122
|
-
true,
|
|
123
|
-
objectType
|
|
124
|
-
);
|
|
140
|
+
object[property] = await resolvePaths({
|
|
141
|
+
config: config,
|
|
142
|
+
object: object[property],
|
|
143
|
+
filePath: filePath,
|
|
144
|
+
nested: true,
|
|
145
|
+
objectType: objectType,
|
|
146
|
+
});
|
|
125
147
|
} else if (typeof object[property] === "string") {
|
|
126
148
|
// If the property is a string, check if it matches any of the path properties and resolve it if it does
|
|
127
149
|
pathProperties.forEach((pathProperty) => {
|
|
@@ -133,24 +155,6 @@ async function resolvePaths(
|
|
|
133
155
|
object[pathProperty],
|
|
134
156
|
object.directory
|
|
135
157
|
);
|
|
136
|
-
} else {
|
|
137
|
-
object[pathProperty] = path.join(
|
|
138
|
-
object.directory,
|
|
139
|
-
object[pathProperty]
|
|
140
|
-
);
|
|
141
|
-
}
|
|
142
|
-
} else if (pathProperty === "savePath" && object.saveDirectory) {
|
|
143
|
-
if (path.isAbsolute(object.saveDirectory)) {
|
|
144
|
-
object[pathProperty] = resolve(
|
|
145
|
-
relativePathBase,
|
|
146
|
-
object[pathProperty],
|
|
147
|
-
object.saveDirectory
|
|
148
|
-
);
|
|
149
|
-
} else {
|
|
150
|
-
object[pathProperty] = path.join(
|
|
151
|
-
object.saveDirectory,
|
|
152
|
-
object[pathProperty]
|
|
153
|
-
);
|
|
154
158
|
}
|
|
155
159
|
} else {
|
|
156
160
|
object[pathProperty] = resolve(
|