@elench/testkit 0.1.96 → 0.1.97

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.
@@ -1,227 +0,0 @@
1
- const TESTKIT_TYPES = new Set(["int", "e2e", "scenario", "dal", "load", "pw", "all"]);
2
- const TESTKIT_DIR_COMMANDS = new Set(["run", "discover", "status", "doctor", "destroy", "cleanup", "typecheck"]);
3
- const PACKAGE_RUNNERS = new Set(["npx", "pnpm", "npm", "yarn", "bun"]);
4
-
5
- export function extractShellCommand(args = {}) {
6
- if (!args || typeof args !== "object") return "";
7
- const value =
8
- args.command ??
9
- args.cmd ??
10
- args.commandString ??
11
- args.shellCommand ??
12
- args.input ??
13
- args.script ??
14
- "";
15
- if (Array.isArray(value)) return value.map((part) => shellEscapeArg(part)).join(" ");
16
- return String(value || "");
17
- }
18
-
19
- export function planShellCommand(rawCommand) {
20
- const raw = String(rawCommand || "").trim();
21
- if (!raw) {
22
- return {
23
- executableCommand: "",
24
- rawCommand: raw,
25
- displayCommand: raw,
26
- command: "",
27
- title: "Shell command",
28
- testkitRelated: false,
29
- normalized: false,
30
- };
31
- }
32
-
33
- const testkit = planTestkitCommand(raw);
34
- if (testkit) return testkit;
35
-
36
- const testkitScript = planTestkitPackageScript(raw);
37
- if (testkitScript) return testkitScript;
38
-
39
- return {
40
- executableCommand: raw,
41
- rawCommand: raw,
42
- displayCommand: raw,
43
- command: firstCommandToken(raw),
44
- title: "Shell command",
45
- testkitRelated: false,
46
- normalized: false,
47
- };
48
- }
49
-
50
- function planTestkitPackageScript(raw) {
51
- if (containsShellControl(raw)) return null;
52
- const tokens = tokenizeShellWords(raw);
53
- if (!tokens || tokens.length < 3) return null;
54
- if (tokens[0] !== "npm" || tokens[1] !== "run") return null;
55
- if (tokens[2] !== "testkit" && !tokens[2].startsWith("testkit:")) return null;
56
- return {
57
- executableCommand: raw,
58
- rawCommand: raw,
59
- displayCommand: raw,
60
- command: "npm run testkit",
61
- title: "npm testkit script",
62
- testkitRelated: true,
63
- normalized: false,
64
- };
65
- }
66
-
67
- function planTestkitCommand(raw) {
68
- if (containsShellControl(raw)) return null;
69
- const tokens = tokenizeShellWords(raw);
70
- if (!tokens || tokens.length === 0) return null;
71
-
72
- const extracted = extractTestkitInvocation(tokens);
73
- if (!extracted) return null;
74
-
75
- const canonicalArgs = canonicalizeTestkitArgs(extracted.args);
76
- const executableCommand = ["testkit", ...canonicalArgs].map(shellEscapeArg).join(" ");
77
- const wasNormalized = executableCommand !== raw;
78
- return {
79
- executableCommand,
80
- rawCommand: raw,
81
- displayCommand: executableCommand,
82
- command: "testkit",
83
- title: "testkit command",
84
- testkitRelated: true,
85
- normalized: wasNormalized,
86
- normalizationReason: wasNormalized ? extracted.reason : null,
87
- };
88
- }
89
-
90
- function extractTestkitInvocation(tokens) {
91
- if (tokens[0] === "testkit") {
92
- return {
93
- args: tokens.slice(1),
94
- reason: "canonicalized local testkit invocation",
95
- };
96
- }
97
-
98
- if (!PACKAGE_RUNNERS.has(tokens[0])) return null;
99
-
100
- if (tokens[0] === "npm" && ["exec", "x"].includes(tokens[1])) {
101
- const index = findPackageTarget(tokens, 2);
102
- if (index >= 0) return { args: tokens.slice(index + 1), reason: "replaced npm exec testkit with local testkit" };
103
- }
104
-
105
- if (tokens[0] === "npx") {
106
- const index = findPackageTarget(tokens, 1);
107
- if (index >= 0) return { args: tokens.slice(index + 1), reason: "replaced npx testkit with local testkit" };
108
- }
109
-
110
- if (tokens[0] === "pnpm" && ["exec", "dlx"].includes(tokens[1])) {
111
- const index = findPackageTarget(tokens, 2);
112
- if (index >= 0) return { args: tokens.slice(index + 1), reason: "replaced pnpm testkit launcher with local testkit" };
113
- }
114
-
115
- if (tokens[0] === "yarn" && tokens[1] === "testkit") {
116
- return { args: tokens.slice(2), reason: "replaced yarn testkit launcher with local testkit" };
117
- }
118
-
119
- if (tokens[0] === "bun" && ["x", "run"].includes(tokens[1])) {
120
- const index = findPackageTarget(tokens, 2);
121
- if (index >= 0) return { args: tokens.slice(index + 1), reason: "replaced bun testkit launcher with local testkit" };
122
- }
123
-
124
- return null;
125
- }
126
-
127
- function canonicalizeTestkitArgs(inputArgs) {
128
- const args = [...inputArgs];
129
- if (args.length === 0) return [];
130
-
131
- if (TESTKIT_TYPES.has(args[0])) {
132
- return withDir(["run", "--type", args[0], ...args.slice(1)]);
133
- }
134
-
135
- if (!TESTKIT_DIR_COMMANDS.has(args[0])) {
136
- return args;
137
- }
138
-
139
- if (args[0] === "run") {
140
- const runArgs = [...args];
141
- if (TESTKIT_TYPES.has(runArgs[1])) {
142
- const type = runArgs.splice(1, 1)[0];
143
- if (!hasFlag(runArgs, "--type", "-t")) runArgs.splice(1, 0, "--type", type);
144
- }
145
- return withDir(runArgs);
146
- }
147
-
148
- return withDir(args);
149
- }
150
-
151
- function withDir(args) {
152
- if (hasFlag(args, "--dir", "-d") || args.includes("--help") || args.includes("-h")) return args;
153
- const [command, ...rest] = args;
154
- return [command, "--dir", ".", ...rest];
155
- }
156
-
157
- function hasFlag(args, longFlag, shortFlag) {
158
- return args.some((arg) => arg === longFlag || arg.startsWith(`${longFlag}=`) || arg === shortFlag);
159
- }
160
-
161
- function findPackageTarget(tokens, startIndex) {
162
- for (let index = startIndex; index < tokens.length; index += 1) {
163
- const token = tokens[index];
164
- if (token === "--") continue;
165
- if (token === "testkit" || token === "@elench/testkit") return index;
166
- if (!token.startsWith("-")) return -1;
167
- }
168
- return -1;
169
- }
170
-
171
- function firstCommandToken(command) {
172
- const tokens = tokenizeShellWords(command);
173
- return tokens?.[0] || command.split(/\s+/)[0] || "command";
174
- }
175
-
176
- function containsShellControl(command) {
177
- return /[\n;&|<>`]/.test(command);
178
- }
179
-
180
- function tokenizeShellWords(command) {
181
- const words = [];
182
- let current = "";
183
- let quote = null;
184
- let escaping = false;
185
-
186
- for (const char of String(command)) {
187
- if (escaping) {
188
- current += char;
189
- escaping = false;
190
- continue;
191
- }
192
- if (char === "\\") {
193
- escaping = true;
194
- continue;
195
- }
196
- if (quote) {
197
- if (char === quote) {
198
- quote = null;
199
- } else {
200
- current += char;
201
- }
202
- continue;
203
- }
204
- if (char === "'" || char === '"') {
205
- quote = char;
206
- continue;
207
- }
208
- if (/\s/.test(char)) {
209
- if (current) {
210
- words.push(current);
211
- current = "";
212
- }
213
- continue;
214
- }
215
- current += char;
216
- }
217
-
218
- if (escaping || quote) return null;
219
- if (current) words.push(current);
220
- return words;
221
- }
222
-
223
- function shellEscapeArg(value) {
224
- const stringValue = String(value);
225
- if (/^[a-zA-Z0-9._:@/%+=,-]+$/.test(stringValue)) return stringValue;
226
- return `'${stringValue.replace(/'/g, `'\\''`)}'`;
227
- }