doc-detective 2.16.0-dev.0 → 2.16.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/src/utils.js CHANGED
@@ -1,236 +1,251 @@
1
- const yargs = require("yargs/yargs");
2
- const { hideBin } = require("yargs/helpers");
3
- const { validate, resolvePaths } = require("doc-detective-common");
4
- const path = require("path");
5
- const fs = require("fs");
6
- const { spawn } = require("child_process");
7
- const os = require("os");
8
-
9
- exports.setArgs = setArgs;
10
- exports.setConfig = setConfig;
11
- exports.outputResults = outputResults;
12
- exports.spawnCommand = spawnCommand;
13
- exports.setMeta = setMeta;
14
-
15
- // Define args
16
- function setArgs(args) {
17
- if (!args) return {};
18
- let argv = yargs(hideBin(args))
19
- .option("config", {
20
- alias: "c",
21
- description: "Path to a `config.json` file.",
22
- type: "string",
23
- })
24
- .option("input", {
25
- alias: "i",
26
- description:
27
- "Path to test specifications and documentation source files. May be paths to specific files or to directories to scan for files.",
28
- type: "string",
29
- })
30
- .option("output", {
31
- alias: "o",
32
- description:
33
- "Path of the directory in which to store the output of Doc Detective commands.",
34
- type: "string",
35
- })
36
- .option("setup", {
37
- description:
38
- "Path to test specifications to perform before those specified by `input`. Useful for setting up testing environments.",
39
- type: "string",
40
- })
41
- .option("cleanup", {
42
- description:
43
- "Path to test specifications to perform after those specified by input. Useful for cleaning up testing environments.",
44
- type: "string",
45
- })
46
- .option("recursive", {
47
- alias: "r",
48
- description:
49
- "Boolean. If true searches input, setup, and cleanup paths recursively for test specificaions and source files. Defaults to `true`.",
50
- type: "string",
51
- })
52
- .option("logLevel", {
53
- alias: "l",
54
- description:
55
- "Detail level of logging events. Accepted values: silent, error, warning, info (default), debug",
56
- type: "string",
57
- })
58
- .help()
59
- .alias("help", "h").argv;
60
-
61
- return argv;
62
- }
63
-
64
- // Override config values based on args
65
- async function setConfig(config, args) {
66
- // If no args, return config
67
- if (!args) return config;
68
-
69
- // Load config from file
70
- if (args.config) {
71
- const configPath = path.resolve(args.config);
72
- configContent = require(configPath);
73
- // Validate config
74
- const validation = validate("config_v2", configContent);
75
- if (validation.valid) {
76
- config = configContent;
77
- config = await resolvePaths(config, config, configPath);
78
- } else {
79
- // Output validation errors
80
- console.error("Invalid config file:");
81
- validation.errors.forEach((error) => {
82
- console.error(error);
83
- });
84
- process.exit(1);
85
- }
86
- }
87
-
88
- // Override config values
89
- if (args.input) config.input = args.input;
90
- if (args.output) config.output = args.output;
91
- if (args.recursive) config.recursive = args.recursive;
92
- if (args.logLevel) config.logLevel = args.logLevel;
93
- if (
94
- (args.setup || args.cleanup || args.input || args.output) &&
95
- !config.runTests
96
- )
97
- config.runTests = {};
98
- if (args.input) config.runTests.input = args.input;
99
- if (args.output) config.runTests.output = args.output;
100
- if (args.setup) config.runTests.setup = args.setup;
101
- if (args.cleanup) config.runTests.cleanup = args.cleanup;
102
-
103
- // Validate config
104
- const validation = validate("config_v2", config);
105
- if (!validation.valid) {
106
- // Output validation errors
107
- console.error("Invalid config.");
108
- validation.errors.forEach((error) => {
109
- console.error(error);
110
- });
111
- process.exit(1);
112
- }
113
-
114
- return config;
115
- }
116
-
117
- async function outputResults(config = {}, outputPath, results, options = {}) {
118
- // DEBUG
119
- // outputPath = "./foobar/results.json";
120
- // END DEBUG
121
-
122
- // Define supported output extensions
123
- const outputExtensions = [".json"];
124
-
125
- // Normalize output path
126
- outputPath = path.resolve(outputPath);
127
-
128
- let data = JSON.stringify(results, null, 2);
129
- let outputFile = "";
130
- let outputDir = "";
131
- let reportType = "doc-detective-results";
132
- if (options.command) {
133
- if (options.command === "runCoverage") {
134
- reportType = "coverageResults";
135
- } else if (options.command === "runTests") {
136
- reportType = "testResults";
137
- }
138
- }
139
- // outputPath = path.resolve(outputPath, `${reportType}.json`);
140
-
141
- // Detect if output ends with a supported extension
142
- if (outputExtensions.some((ext) => outputPath.endsWith(ext))) {
143
- outputDir = path.dirname(outputPath);
144
- outputFile = outputPath;
145
- // If outputFile already exists, add a counter to the filename
146
- if (fs.existsSync(outputFile)) {
147
- let counter = 0;
148
- while (fs.existsSync(outputFile.replace(".json", `-${counter}.json`))) {
149
- counter++;
150
- }
151
- outputFile = outputFile.replace(".json", `-${counter}.json`);
152
- }
153
- } else {
154
- outputDir = outputPath;
155
- outputFile = path.resolve(outputDir, `${reportType}-${Date.now()}.json`);
156
- }
157
-
158
- try {
159
- // Create output directory if it doesn't exist
160
- if (!fs.existsSync(outputDir)) {
161
- fs.mkdirSync(outputDir, { recursive: true });
162
- }
163
-
164
- // Write results to output file
165
- fs.writeFileSync(outputFile, data);
166
- console.log(`See results at ${outputFile}`);
167
- } catch (err) {
168
- console.error(`Error writing results to ${outputFile}. ${err}`);
169
- }
170
- }
171
-
172
- // Perform a native command in the current working directory.
173
- async function spawnCommand(cmd, args) {
174
- // Split command into command and arguments
175
- if (cmd.includes(" ")) {
176
- const cmdArray = cmd.split(" ");
177
- cmd = cmdArray[0];
178
- cmdArgs = cmdArray.slice(1);
179
- // Add arguments to args array
180
- if (args) {
181
- args = cmdArgs.concat(args);
182
- } else {
183
- args = cmdArgs;
184
- }
185
- }
186
-
187
- const runCommand = spawn(cmd, args);
188
-
189
- // Capture stdout
190
- let stdout = "";
191
- for await (const chunk of runCommand.stdout) {
192
- stdout += chunk;
193
- }
194
- // Remove trailing newline
195
- stdout = stdout.replace(/\n$/, "");
196
-
197
- // Capture stderr
198
- let stderr = "";
199
- for await (const chunk of runCommand.stderr) {
200
- stderr += chunk;
201
- }
202
- // Remove trailing newline
203
- stderr = stderr.replace(/\n$/, "");
204
-
205
- // Capture exit code
206
- const exitCode = await new Promise((resolve, reject) => {
207
- runCommand.on("close", resolve);
208
- });
209
-
210
- return { stdout, stderr, exitCode };
211
- }
212
-
213
- function setMeta() {
214
- const platformMap = {
215
- win32: "windows",
216
- darwin: "mac",
217
- linux: "linux",
218
- };
219
-
220
- // Set meta
221
- const meta =
222
- process.env["DOC_DETECTIVE_META"] !== undefined
223
- ? JSON.parse(process.env["DOC_DETECTIVE_META"])
224
- : {};
225
- const package = require("../package.json");
226
- meta.distribution = "doc-detective";
227
- meta.dist_version = package.version;
228
- meta.dist_platform = platformMap[os.platform()] || os.platform();
229
- meta.dist_platform_version = os.release();
230
- meta.dist_platform_arch = os.arch();
231
- meta.dist_deployment = meta.dist_deployment || "node";
232
- meta.dist_deployment_version =
233
- meta.dist_deployment_version || process.version;
234
- meta.dist_interface = meta.dist_interface || "cli";
235
- process.env["DOC_DETECTIVE_META"] = JSON.stringify(meta);
236
- }
1
+ const yargs = require("yargs/yargs");
2
+ const { hideBin } = require("yargs/helpers");
3
+ const { validate, resolvePaths } = require("doc-detective-common");
4
+ const path = require("path");
5
+ const fs = require("fs");
6
+ const { spawn } = require("child_process");
7
+ const os = require("os");
8
+
9
+ exports.setArgs = setArgs;
10
+ exports.setConfig = setConfig;
11
+ exports.outputResults = outputResults;
12
+ exports.spawnCommand = spawnCommand;
13
+ exports.setMeta = setMeta;
14
+
15
+ // Define args
16
+ function setArgs(args) {
17
+ if (!args) return {};
18
+ let argv = yargs(hideBin(args))
19
+ .option("config", {
20
+ alias: "c",
21
+ description: "Path to a `config.json` file.",
22
+ type: "string",
23
+ })
24
+ .option("input", {
25
+ alias: "i",
26
+ description:
27
+ "Path to test specifications and documentation source files. May be paths to specific files or to directories to scan for files.",
28
+ type: "string",
29
+ })
30
+ .option("output", {
31
+ alias: "o",
32
+ description:
33
+ "Path of the directory in which to store the output of Doc Detective commands.",
34
+ type: "string",
35
+ })
36
+ .option("setup", {
37
+ description:
38
+ "Path to test specifications to perform before those specified by `input`. Useful for setting up testing environments.",
39
+ type: "string",
40
+ })
41
+ .option("cleanup", {
42
+ description:
43
+ "Path to test specifications to perform after those specified by input. Useful for cleaning up testing environments.",
44
+ type: "string",
45
+ })
46
+ .option("recursive", {
47
+ alias: "r",
48
+ description:
49
+ "Boolean. If true searches input, setup, and cleanup paths recursively for test specificaions and source files. Defaults to `true`.",
50
+ type: "string",
51
+ })
52
+ .option("logLevel", {
53
+ alias: "l",
54
+ description:
55
+ "Detail level of logging events. Accepted values: silent, error, warning, info (default), debug",
56
+ type: "string",
57
+ })
58
+ .help()
59
+ .alias("help", "h").argv;
60
+
61
+ return argv;
62
+ }
63
+
64
+ // Override config values based on args
65
+ async function setConfig(config, args) {
66
+ // If no args, return config
67
+ if (!args) return config;
68
+
69
+ // Load config from file
70
+ if (args.config) {
71
+ const configPath = path.resolve(args.config);
72
+ configContent = require(configPath);
73
+ // Validate config
74
+ const validation = validate("config_v2", configContent);
75
+ if (validation.valid) {
76
+ config = configContent;
77
+ config = await resolvePaths(config, config, configPath);
78
+ } else {
79
+ // Output validation errors
80
+ console.error("Invalid config file:");
81
+ validation.errors.forEach((error) => {
82
+ console.error(error);
83
+ });
84
+ process.exit(1);
85
+ }
86
+ }
87
+
88
+ // Override config values
89
+ if (
90
+ (args.setup || args.cleanup || args.input || args.output) &&
91
+ !config.runTests
92
+ )
93
+ config.runTests = {};
94
+ if (
95
+ (args.setup || args.cleanup || args.input || args.output) &&
96
+ !config.runCoverage
97
+ )
98
+ config.runCoverage = {};
99
+ if (args.input) {
100
+ config.input = args.input;
101
+ config.runCoverage.input = args.input;
102
+ config.runTests.input = args.input;
103
+ }
104
+ if (args.output) {
105
+ config.output = args.output;
106
+ config.runCoverage.output = args.output;
107
+ config.runTests.output = args.output;
108
+ }
109
+ if (args.recursive) {
110
+ config.recursive = args.recursive;
111
+ config.runCoverage.recursive = args.recursive;
112
+ config.runTests.recursive = args.recursive;
113
+ }
114
+ if (args.logLevel) config.logLevel = args.logLevel;
115
+ if (args.setup) config.runTests.setup = args.setup;
116
+ if (args.cleanup) config.runTests.cleanup = args.cleanup;
117
+
118
+ // Validate config
119
+ const validation = validate("config_v2", config);
120
+ if (!validation.valid) {
121
+ // Output validation errors
122
+ console.error("Invalid config.");
123
+ validation.errors.forEach((error) => {
124
+ console.error(error);
125
+ });
126
+ process.exit(1);
127
+ }
128
+
129
+ return config;
130
+ }
131
+
132
+ async function outputResults(config = {}, outputPath, results, options = {}) {
133
+ // DEBUG
134
+ // outputPath = "./foobar/results.json";
135
+ // END DEBUG
136
+
137
+ // Define supported output extensions
138
+ const outputExtensions = [".json"];
139
+
140
+ // Normalize output path
141
+ outputPath = path.resolve(outputPath);
142
+
143
+ let data = JSON.stringify(results, null, 2);
144
+ let outputFile = "";
145
+ let outputDir = "";
146
+ let reportType = "doc-detective-results";
147
+ if (options.command) {
148
+ if (options.command === "runCoverage") {
149
+ reportType = "coverageResults";
150
+ } else if (options.command === "runTests") {
151
+ reportType = "testResults";
152
+ }
153
+ }
154
+ // outputPath = path.resolve(outputPath, `${reportType}.json`);
155
+
156
+ // Detect if output ends with a supported extension
157
+ if (outputExtensions.some((ext) => outputPath.endsWith(ext))) {
158
+ outputDir = path.dirname(outputPath);
159
+ outputFile = outputPath;
160
+ // If outputFile already exists, add a counter to the filename
161
+ if (fs.existsSync(outputFile)) {
162
+ let counter = 0;
163
+ while (fs.existsSync(outputFile.replace(".json", `-${counter}.json`))) {
164
+ counter++;
165
+ }
166
+ outputFile = outputFile.replace(".json", `-${counter}.json`);
167
+ }
168
+ } else {
169
+ outputDir = outputPath;
170
+ outputFile = path.resolve(outputDir, `${reportType}-${Date.now()}.json`);
171
+ }
172
+
173
+ try {
174
+ // Create output directory if it doesn't exist
175
+ if (!fs.existsSync(outputDir)) {
176
+ fs.mkdirSync(outputDir, { recursive: true });
177
+ }
178
+
179
+ // Write results to output file
180
+ fs.writeFileSync(outputFile, data);
181
+ console.log(`See results at ${outputFile}`);
182
+ } catch (err) {
183
+ console.error(`Error writing results to ${outputFile}. ${err}`);
184
+ }
185
+ }
186
+
187
+ // Perform a native command in the current working directory.
188
+ async function spawnCommand(cmd, args) {
189
+ // Split command into command and arguments
190
+ if (cmd.includes(" ")) {
191
+ const cmdArray = cmd.split(" ");
192
+ cmd = cmdArray[0];
193
+ cmdArgs = cmdArray.slice(1);
194
+ // Add arguments to args array
195
+ if (args) {
196
+ args = cmdArgs.concat(args);
197
+ } else {
198
+ args = cmdArgs;
199
+ }
200
+ }
201
+
202
+ const runCommand = spawn(cmd, args);
203
+
204
+ // Capture stdout
205
+ let stdout = "";
206
+ for await (const chunk of runCommand.stdout) {
207
+ stdout += chunk;
208
+ }
209
+ // Remove trailing newline
210
+ stdout = stdout.replace(/\n$/, "");
211
+
212
+ // Capture stderr
213
+ let stderr = "";
214
+ for await (const chunk of runCommand.stderr) {
215
+ stderr += chunk;
216
+ }
217
+ // Remove trailing newline
218
+ stderr = stderr.replace(/\n$/, "");
219
+
220
+ // Capture exit code
221
+ const exitCode = await new Promise((resolve, reject) => {
222
+ runCommand.on("close", resolve);
223
+ });
224
+
225
+ return { stdout, stderr, exitCode };
226
+ }
227
+
228
+ function setMeta() {
229
+ const platformMap = {
230
+ win32: "windows",
231
+ darwin: "mac",
232
+ linux: "linux",
233
+ };
234
+
235
+ // Set meta
236
+ const meta =
237
+ process.env["DOC_DETECTIVE_META"] !== undefined
238
+ ? JSON.parse(process.env["DOC_DETECTIVE_META"])
239
+ : {};
240
+ const package = require("../package.json");
241
+ meta.distribution = "doc-detective";
242
+ meta.dist_version = package.version;
243
+ meta.dist_platform = platformMap[os.platform()] || os.platform();
244
+ meta.dist_platform_version = os.release();
245
+ meta.dist_platform_arch = os.arch();
246
+ meta.dist_deployment = meta.dist_deployment || "node";
247
+ meta.dist_deployment_version =
248
+ meta.dist_deployment_version || process.version;
249
+ meta.dist_interface = meta.dist_interface || "cli";
250
+ process.env["DOC_DETECTIVE_META"] = JSON.stringify(meta);
251
+ }
@@ -1,19 +1,19 @@
1
- {
2
- "id": "cleanup",
3
- "tests": [
4
- {
5
- "steps": [
6
- {
7
- "action": "setVariables",
8
- "path": ".env"
9
- },
10
- {
11
- "action": "runShell",
12
- "command": "echo",
13
- "args": ["cleanup"]
14
- }
15
- ]
16
- }
17
- ]
18
- }
1
+ {
2
+ "id": "cleanup",
3
+ "tests": [
4
+ {
5
+ "steps": [
6
+ {
7
+ "action": "setVariables",
8
+ "path": ".env"
9
+ },
10
+ {
11
+ "action": "runShell",
12
+ "command": "echo",
13
+ "args": ["cleanup"]
14
+ }
15
+ ]
16
+ }
17
+ ]
18
+ }
19
19
 
@@ -1,43 +1,43 @@
1
- {
2
- "envVariables": "",
3
- "input": ".",
4
- "output": ".",
5
- "recursive": true,
6
- "relativePathBase": "file",
7
- "logLevel": "debug",
8
- "runTests": {
9
- "input": "test.spec.json",
10
- "output": ".",
11
- "setup": "",
12
- "cleanup": "",
13
- "recursive": true,
14
- "detectSteps": false,
15
- "mediaDirectory": ".",
16
- "downloadDirectory": ".",
17
- "contexts": [
18
- {
19
- "app": { "name": "firefox" },
20
- "platforms": ["windows", "mac", "linux"]
21
- },
22
- {
23
- "app": { "name": "chrome", "options": { "headless": true } },
24
- "platforms": ["windows", "mac", "linux"]
25
- }
26
- ]
27
- },
28
- "runCoverage": {
29
- "recursive": true,
30
- "input": ".dev/",
31
- "output": ".",
32
- "markup": []
33
- },
34
- "suggestTests": {
35
- "recursive": true,
36
- "input": ".",
37
- "output": ".",
38
- "markup": []
39
- },
40
- "telemetry": {
41
- "send": false
42
- }
43
- }
1
+ {
2
+ "envVariables": "",
3
+ "input": ".",
4
+ "output": ".",
5
+ "recursive": true,
6
+ "relativePathBase": "file",
7
+ "logLevel": "debug",
8
+ "runTests": {
9
+ "input": "test.spec.json",
10
+ "output": ".",
11
+ "setup": "",
12
+ "cleanup": "",
13
+ "recursive": true,
14
+ "detectSteps": false,
15
+ "mediaDirectory": ".",
16
+ "downloadDirectory": ".",
17
+ "contexts": [
18
+ {
19
+ "app": { "name": "firefox" },
20
+ "platforms": ["windows", "mac", "linux"]
21
+ },
22
+ {
23
+ "app": { "name": "chrome", "options": { "headless": true } },
24
+ "platforms": ["windows", "mac", "linux"]
25
+ }
26
+ ]
27
+ },
28
+ "runCoverage": {
29
+ "recursive": true,
30
+ "input": ".dev/",
31
+ "output": ".",
32
+ "markup": []
33
+ },
34
+ "suggestTests": {
35
+ "recursive": true,
36
+ "input": ".",
37
+ "output": ".",
38
+ "markup": []
39
+ },
40
+ "telemetry": {
41
+ "send": false
42
+ }
43
+ }
@@ -1,18 +1,18 @@
1
- # Doc Detective documentation overview
2
-
3
- [comment]: # (test start {"id":"search-kittens"})
4
-
5
- [Doc Detective documentation](http://doc-detective.com) is split into a few key sections:
6
- [comment]: # (step {"action":"goTo", "url":"http://doc-detective.com"})
7
-
8
- - The landing page discusses what Doc Detective is, what it does, and who might find it useful.
9
- - [Get started](https://doc-detective.com/get-started.html) covers how to quickly get up and running with Doc Detective.
10
- [comment]: # (step {"action":"goTo", "url":"https://doc-detective.com/get-started.html"})
11
- - The [references](https://doc-detective.com/reference/) detail the various JSON objects that Doc Detective expects for configs, test specifications, tests, actions, and more. Each object schema includes an object description, field definitions, and examples.
12
- [comment]: # (step {"action":"goTo", "url":"https://doc-detective.com/reference/"})
13
- [comment]: # (step {"action":"goTo", "url":"https://doc-detective.com/reference/schemas/config.html"})
14
- [comment]: # (step {"action":"find", "selector":"h2#description", "matchText":"Description"})
15
- [comment]: # (step {"action":"find", "selector":"h2#fields", "matchText":"Fields"})
16
- [comment]: # (step {"action":"find", "selector":"h2#examples", "matchText":"Examples"})
17
-
1
+ # Doc Detective documentation overview
2
+
3
+ [comment]: # (test start {"id":"search-kittens"})
4
+
5
+ [Doc Detective documentation](http://doc-detective.com) is split into a few key sections:
6
+ [comment]: # (step {"action":"goTo", "url":"http://doc-detective.com"})
7
+
8
+ - The landing page discusses what Doc Detective is, what it does, and who might find it useful.
9
+ - [Get started](https://doc-detective.com/get-started.html) covers how to quickly get up and running with Doc Detective.
10
+ [comment]: # (step {"action":"goTo", "url":"https://doc-detective.com/get-started.html"})
11
+ - The [references](https://doc-detective.com/reference/) detail the various JSON objects that Doc Detective expects for configs, test specifications, tests, actions, and more. Each object schema includes an object description, field definitions, and examples.
12
+ [comment]: # (step {"action":"goTo", "url":"https://doc-detective.com/reference/"})
13
+ [comment]: # (step {"action":"goTo", "url":"https://doc-detective.com/reference/schemas/config.html"})
14
+ [comment]: # (step {"action":"find", "selector":"h2#description", "matchText":"Description"})
15
+ [comment]: # (step {"action":"find", "selector":"h2#fields", "matchText":"Fields"})
16
+ [comment]: # (step {"action":"find", "selector":"h2#examples", "matchText":"Examples"})
17
+
18
18
  [comment]: # (test end)