@tracelane/cli 0.1.0-alpha.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/NOTICE +11 -0
- package/README.md +104 -0
- package/dist/commands/init.d.ts +44 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +383 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +80 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/detect.d.ts +59 -0
- package/dist/lib/detect.d.ts.map +1 -0
- package/dist/lib/detect.js +140 -0
- package/dist/lib/detect.js.map +1 -0
- package/dist/lib/gitignore.d.ts +17 -0
- package/dist/lib/gitignore.d.ts.map +1 -0
- package/dist/lib/gitignore.js +40 -0
- package/dist/lib/gitignore.js.map +1 -0
- package/dist/lib/prompt.d.ts +8 -0
- package/dist/lib/prompt.d.ts.map +1 -0
- package/dist/lib/prompt.js +28 -0
- package/dist/lib/prompt.js.map +1 -0
- package/dist/lib/wdio-editor.d.ts +159 -0
- package/dist/lib/wdio-editor.d.ts.map +1 -0
- package/dist/lib/wdio-editor.js +508 -0
- package/dist/lib/wdio-editor.js.map +1 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +14 -0
- package/dist/version.js.map +1 -0
- package/package.json +42 -0
|
@@ -0,0 +1,508 @@
|
|
|
1
|
+
// String-based editor for wdio.conf.* (Strategy A from the v0.1 spec).
|
|
2
|
+
//
|
|
3
|
+
// We chose regex over an AST parser (ts-morph) for two reasons:
|
|
4
|
+
// 1. ts-morph adds ~10 MB to the published @tracelane/cli — bad tradeoff
|
|
5
|
+
// for a CLI whose only purpose is one transformation on first install.
|
|
6
|
+
// 2. The space of "real" WDIO conf shapes is small and well-defined; if
|
|
7
|
+
// a user has something exotic the regex doesn't match, the editor backs
|
|
8
|
+
// out cleanly and prints a manual-step snippet (the rest of `init` —
|
|
9
|
+
// install, mkdir, .gitignore — still runs).
|
|
10
|
+
//
|
|
11
|
+
// The contract every edit MUST satisfy after `applyWdioEdit` returns
|
|
12
|
+
// `{ ok: true, ... }`:
|
|
13
|
+
//
|
|
14
|
+
// - The source still contains `import TraceLaneService from '@tracelane/wdio';`
|
|
15
|
+
// (or the existing import was already there — idempotent re-run case).
|
|
16
|
+
// - The source still contains `[TraceLaneService, { mode: 'failed' }]`.
|
|
17
|
+
// - File length grew by 80–200 bytes (sanity bound; 0 = nothing happened,
|
|
18
|
+
// 10kb+ = the regex went off the rails). Idempotent re-runs are allowed
|
|
19
|
+
// to grow by 0 and return `alreadyConfigured: true`.
|
|
20
|
+
//
|
|
21
|
+
// On any sanity-check failure the caller restores the original file from the
|
|
22
|
+
// backup written next to the conf (`{path}.tracelane-init.backup`).
|
|
23
|
+
//
|
|
24
|
+
// SHADOW SAFETY (2026-05-29 code-review fix): every source-scanning regex
|
|
25
|
+
// runs against a `stripStringsAndComments` buffer, NOT the raw source. The
|
|
26
|
+
// strip replaces all string-literal + comment content with same-length
|
|
27
|
+
// space padding so offsets translate 1:1 between stripped and raw buffers
|
|
28
|
+
// — a match in the stripped buffer can be sliced out of the raw source by
|
|
29
|
+
// its index. This prevents:
|
|
30
|
+
// - `/* services: ['x'] */ export const config = { services: ['real'] }`
|
|
31
|
+
// from having the EXAMPLE in the comment edited and the real array
|
|
32
|
+
// left untouched.
|
|
33
|
+
// - `// services: ['x'] (example)` line-comment shadows.
|
|
34
|
+
// - `"services: [stuff]"` string-literal shadows.
|
|
35
|
+
// Plus: `findServicesArray` requires the matched `services:` key to live
|
|
36
|
+
// at brace-depth 1 from the top-level config object literal (not inside
|
|
37
|
+
// `capabilities: [{ services: [...] }]`, which is a per-capability driver
|
|
38
|
+
// hint with different semantics).
|
|
39
|
+
/** The import line we add at the top of the user's wdio.conf. */
|
|
40
|
+
export const TRACELANE_IMPORT = `import TraceLaneService from '@tracelane/wdio';`;
|
|
41
|
+
/** The services-array entry we add. Tuple form: [Service, options]. */
|
|
42
|
+
export const TRACELANE_SERVICE_TUPLE = `[TraceLaneService, { mode: 'failed' }]`;
|
|
43
|
+
/**
|
|
44
|
+
* Sanity bounds for the post-edit byte-count delta. The lower bound is
|
|
45
|
+
* different for the "added both import + entry" path vs the "entry only
|
|
46
|
+
* (idempotent import already present)" path — the import line alone is
|
|
47
|
+
* already ~50 bytes, so an entry-only edit can legitimately grow by less.
|
|
48
|
+
*/
|
|
49
|
+
export const EDIT_DELTA_MIN = 80; // both import + entry added
|
|
50
|
+
export const EDIT_DELTA_MIN_ENTRY_ONLY = 30; // entry only — tuple is ~40 bytes
|
|
51
|
+
export const EDIT_DELTA_MAX = 400;
|
|
52
|
+
// ---------------------------------------------------------------------------
|
|
53
|
+
// Shared scanner: walk the source once, tracking string-literal state +
|
|
54
|
+
// line/block comments. Two consumers:
|
|
55
|
+
// 1. `stripStringsAndComments`: produces a same-length buffer where every
|
|
56
|
+
// string-literal content and every comment body is replaced with a
|
|
57
|
+
// space, so a regex run against the stripped buffer can never match
|
|
58
|
+
// inside a string or comment. Offsets translate 1:1 — the index of a
|
|
59
|
+
// match in the stripped buffer points at the equivalent character in
|
|
60
|
+
// the raw source.
|
|
61
|
+
// 2. `findMatchingDelimiter`: bracket/brace counter used to find the
|
|
62
|
+
// closing `]` of a `services: [` or the closing `}` of a config object.
|
|
63
|
+
// Both share the same string/comment skipping so the strip and the matcher
|
|
64
|
+
// agree on what counts as "in code" vs "in a literal".
|
|
65
|
+
// ---------------------------------------------------------------------------
|
|
66
|
+
/**
|
|
67
|
+
* Produce a same-length copy of `src` where every string literal and every
|
|
68
|
+
* comment is replaced with a same-length space-padded run. Newlines inside
|
|
69
|
+
* line comments and block comments are preserved (so regex anchors like
|
|
70
|
+
* `^...$` with the `m` flag still see the same line structure).
|
|
71
|
+
*
|
|
72
|
+
* Inside template literals (backtick), `${...}` interpolation BODIES are
|
|
73
|
+
* treated as code — we re-enter normal mode for the interpolated expression
|
|
74
|
+
* so a `services:` mention there isn't shadowed. This is rare in practice
|
|
75
|
+
* (configs don't usually compute the services array via template literals)
|
|
76
|
+
* but it's cheap to do right.
|
|
77
|
+
*/
|
|
78
|
+
export function stripStringsAndComments(src) {
|
|
79
|
+
const out = new Array(src.length);
|
|
80
|
+
let i = 0;
|
|
81
|
+
const n = src.length;
|
|
82
|
+
while (i < n) {
|
|
83
|
+
const ch = src[i];
|
|
84
|
+
const next = src[i + 1];
|
|
85
|
+
// Line comment: `// ...` to end-of-line. Replace the body with spaces
|
|
86
|
+
// but keep newlines.
|
|
87
|
+
if (ch === '/' && next === '/') {
|
|
88
|
+
out[i] = ' ';
|
|
89
|
+
out[i + 1] = ' ';
|
|
90
|
+
i += 2;
|
|
91
|
+
while (i < n && src[i] !== '\n') {
|
|
92
|
+
out[i] = ' ';
|
|
93
|
+
i += 1;
|
|
94
|
+
}
|
|
95
|
+
// The newline itself is left intact when we fall through.
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
// Block comment: `/* ... */`. Replace bodies with spaces; preserve
|
|
99
|
+
// newlines.
|
|
100
|
+
if (ch === '/' && next === '*') {
|
|
101
|
+
out[i] = ' ';
|
|
102
|
+
out[i + 1] = ' ';
|
|
103
|
+
i += 2;
|
|
104
|
+
while (i < n && !(src[i] === '*' && src[i + 1] === '/')) {
|
|
105
|
+
out[i] = src[i] === '\n' ? '\n' : ' ';
|
|
106
|
+
i += 1;
|
|
107
|
+
}
|
|
108
|
+
// Pad the closing `*/` as well.
|
|
109
|
+
if (i < n) {
|
|
110
|
+
out[i] = ' ';
|
|
111
|
+
out[i + 1] = ' ';
|
|
112
|
+
i += 2;
|
|
113
|
+
}
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
// String literals: single, double, template.
|
|
117
|
+
if (ch === '"' || ch === "'" || ch === '`') {
|
|
118
|
+
const quote = ch;
|
|
119
|
+
// Keep the opening quote so a `findServicesArray` regex anchored to
|
|
120
|
+
// `^|[\s,{]` can never mistake a quote for the prelude. The CONTENT
|
|
121
|
+
// is what we strip.
|
|
122
|
+
out[i] = ch;
|
|
123
|
+
i += 1;
|
|
124
|
+
while (i < n) {
|
|
125
|
+
const c = src[i];
|
|
126
|
+
if (c === '\\') {
|
|
127
|
+
// Pad the escape pair as two spaces. Preserve the size.
|
|
128
|
+
out[i] = ' ';
|
|
129
|
+
if (i + 1 < n)
|
|
130
|
+
out[i + 1] = src[i + 1] === '\n' ? '\n' : ' ';
|
|
131
|
+
i += 2;
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
if (quote === '`' && c === '$' && src[i + 1] === '{') {
|
|
135
|
+
// Template-literal `${...}` interpolation. The dollar-brace itself
|
|
136
|
+
// is part of the literal syntax — pad it; INSIDE the braces we
|
|
137
|
+
// re-enter normal "code" mode by copying the chars through. The
|
|
138
|
+
// matching `}` closes the interpolation; pad it on the way out.
|
|
139
|
+
out[i] = ' ';
|
|
140
|
+
out[i + 1] = ' ';
|
|
141
|
+
let braceDepth = 1;
|
|
142
|
+
i += 2;
|
|
143
|
+
while (i < n && braceDepth > 0) {
|
|
144
|
+
const cc = src[i] ?? '';
|
|
145
|
+
if (cc === '{')
|
|
146
|
+
braceDepth += 1;
|
|
147
|
+
else if (cc === '}')
|
|
148
|
+
braceDepth -= 1;
|
|
149
|
+
if (braceDepth === 0) {
|
|
150
|
+
// Pad the closing brace.
|
|
151
|
+
out[i] = ' ';
|
|
152
|
+
i += 1;
|
|
153
|
+
break;
|
|
154
|
+
}
|
|
155
|
+
// Inside the interpolation — recurse-ish: copy chars through.
|
|
156
|
+
out[i] = cc;
|
|
157
|
+
i += 1;
|
|
158
|
+
}
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
if (c === quote) {
|
|
162
|
+
// Keep the closing quote for symmetry with the opener.
|
|
163
|
+
out[i] = c;
|
|
164
|
+
i += 1;
|
|
165
|
+
break;
|
|
166
|
+
}
|
|
167
|
+
// Plain literal content: replace with space (or newline).
|
|
168
|
+
out[i] = c === '\n' ? '\n' : ' ';
|
|
169
|
+
i += 1;
|
|
170
|
+
}
|
|
171
|
+
continue;
|
|
172
|
+
}
|
|
173
|
+
// Plain code character — copy through.
|
|
174
|
+
out[i] = ch ?? '';
|
|
175
|
+
i += 1;
|
|
176
|
+
}
|
|
177
|
+
return out.join('');
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Generic bracket/brace counter. Walks `src` from `openIndex` (which must
|
|
181
|
+
* point at an opening delimiter of the requested kind) and returns the
|
|
182
|
+
* index of the matching closer, or -1 if EOF arrives first.
|
|
183
|
+
*
|
|
184
|
+
* We accept a pre-stripped buffer as `scan`: the bracket/brace counting
|
|
185
|
+
* happens against the stripped buffer (so brackets inside strings/comments
|
|
186
|
+
* are spaces and don't count) but the result is still a valid offset into
|
|
187
|
+
* the original source (the strip is length-preserving).
|
|
188
|
+
*/
|
|
189
|
+
function findMatchingDelimiter(scan, openIndex, open, close) {
|
|
190
|
+
let depth = 0;
|
|
191
|
+
let i = openIndex;
|
|
192
|
+
const n = scan.length;
|
|
193
|
+
while (i < n) {
|
|
194
|
+
const ch = scan[i];
|
|
195
|
+
if (ch === open)
|
|
196
|
+
depth += 1;
|
|
197
|
+
else if (ch === close) {
|
|
198
|
+
depth -= 1;
|
|
199
|
+
if (depth === 0)
|
|
200
|
+
return i;
|
|
201
|
+
}
|
|
202
|
+
i += 1;
|
|
203
|
+
}
|
|
204
|
+
return -1;
|
|
205
|
+
}
|
|
206
|
+
function depthAt(scan) {
|
|
207
|
+
const out = new Array(scan.length);
|
|
208
|
+
let braces = 0;
|
|
209
|
+
let brackets = 0;
|
|
210
|
+
for (let i = 0; i < scan.length; i += 1) {
|
|
211
|
+
const ch = scan[i];
|
|
212
|
+
if (ch === '{')
|
|
213
|
+
braces += 1;
|
|
214
|
+
else if (ch === '}')
|
|
215
|
+
braces = Math.max(0, braces - 1);
|
|
216
|
+
else if (ch === '[')
|
|
217
|
+
brackets += 1;
|
|
218
|
+
else if (ch === ']')
|
|
219
|
+
brackets = Math.max(0, brackets - 1);
|
|
220
|
+
out[i] = { depth: braces + brackets };
|
|
221
|
+
}
|
|
222
|
+
return out;
|
|
223
|
+
}
|
|
224
|
+
// ---------------------------------------------------------------------------
|
|
225
|
+
// Public scanning helpers
|
|
226
|
+
// ---------------------------------------------------------------------------
|
|
227
|
+
/**
|
|
228
|
+
* Locate the `services:` array literal in a wdio.conf source string. Returns
|
|
229
|
+
* the bracket indices + the substring inside.
|
|
230
|
+
*
|
|
231
|
+
* The match runs against `stripStringsAndComments(source)` so a `services:`
|
|
232
|
+
* inside a comment or a string can never be selected. Among the remaining
|
|
233
|
+
* candidates, we prefer the SHALLOWEST brace+bracket depth — this rejects
|
|
234
|
+
* `capabilities: [{ services: ['safari'] }]` (depth 3) in favour of the
|
|
235
|
+
* outer testrunner `services:` (depth 1). The depth-1 preference matches
|
|
236
|
+
* the WDIO config schema (services live directly on the config object).
|
|
237
|
+
*
|
|
238
|
+
* Returns `undefined` if no `services:` key with an array literal is present
|
|
239
|
+
* outside strings/comments.
|
|
240
|
+
*/
|
|
241
|
+
export function findServicesArray(source) {
|
|
242
|
+
const scan = stripStringsAndComments(source);
|
|
243
|
+
const depths = depthAt(scan);
|
|
244
|
+
const re = /(?:^|[\s,{])(?:services|"services"|'services')\s*:\s*\[/g;
|
|
245
|
+
let m;
|
|
246
|
+
let best;
|
|
247
|
+
// biome-ignore lint/suspicious/noAssignInExpressions: idiomatic for global-flag regex iteration
|
|
248
|
+
while ((m = re.exec(scan)) !== null) {
|
|
249
|
+
const openIndex = m.index + m[0].length - 1; // points at `[`
|
|
250
|
+
const closeIndex = findMatchingDelimiter(scan, openIndex, '[', ']');
|
|
251
|
+
if (closeIndex === -1)
|
|
252
|
+
continue;
|
|
253
|
+
// Depth at the character JUST BEFORE the `[` — that's the depth at
|
|
254
|
+
// which the `services:` key was declared. (After we pass the `[` itself
|
|
255
|
+
// we're one bracket deeper, but the key's scope is the surrounding
|
|
256
|
+
// object.)
|
|
257
|
+
const keyDepth = depths[openIndex - 1]?.depth ?? 0;
|
|
258
|
+
if (best === undefined || keyDepth < best.depth) {
|
|
259
|
+
best = { openIndex, closeIndex, depth: keyDepth };
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
if (!best)
|
|
263
|
+
return undefined;
|
|
264
|
+
return {
|
|
265
|
+
openIndex: best.openIndex,
|
|
266
|
+
closeIndex: best.closeIndex,
|
|
267
|
+
// Slice the inner content out of the ORIGINAL source (strip is length-
|
|
268
|
+
// preserving so indices match), so the user's actual array contents
|
|
269
|
+
// are what gets edited.
|
|
270
|
+
inner: source.slice(best.openIndex + 1, best.closeIndex),
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* Insert the tracelane import after the LAST `import ... from '...';` line in
|
|
275
|
+
* the source. If no imports exist (which should never happen for a real WDIO
|
|
276
|
+
* conf) we insert at the top.
|
|
277
|
+
*
|
|
278
|
+
* We don't attempt to deduplicate or sort — the user's editor + Biome will
|
|
279
|
+
* fold our line in on the next save. Idempotency is enforced by the caller
|
|
280
|
+
* (it checks `hasTracelaneImport(source)` before invoking this).
|
|
281
|
+
*
|
|
282
|
+
* Match runs against the stripped buffer so a top-of-file block comment
|
|
283
|
+
* mentioning `import` cannot shadow the real import section.
|
|
284
|
+
*/
|
|
285
|
+
export function insertTracelaneImport(source) {
|
|
286
|
+
const scan = stripStringsAndComments(source);
|
|
287
|
+
const importLineRe = /^\s*import\s.+?\s+from\s+['"][^'"]+['"];?\s*$/gm;
|
|
288
|
+
let lastEnd = -1;
|
|
289
|
+
let m;
|
|
290
|
+
// biome-ignore lint/suspicious/noAssignInExpressions: idiomatic for global-flag regex iteration
|
|
291
|
+
while ((m = importLineRe.exec(scan)) !== null) {
|
|
292
|
+
lastEnd = m.index + m[0].length;
|
|
293
|
+
}
|
|
294
|
+
if (lastEnd === -1) {
|
|
295
|
+
// No imports — insert at the very top, before any code.
|
|
296
|
+
return `${TRACELANE_IMPORT}\n\n${source}`;
|
|
297
|
+
}
|
|
298
|
+
// Insert immediately after the last import line. Index is into the raw
|
|
299
|
+
// source because the strip is length-preserving.
|
|
300
|
+
return `${source.slice(0, lastEnd)}\n${TRACELANE_IMPORT}${source.slice(lastEnd)}`;
|
|
301
|
+
}
|
|
302
|
+
/**
|
|
303
|
+
* True if the source already has an `@tracelane/wdio` import. Matches both
|
|
304
|
+
* default and named import forms (`import TraceLaneService from ...` /
|
|
305
|
+
* `import { TraceLaneService } from ...`) and either quote style. Runs
|
|
306
|
+
* against the stripped buffer so a commented-out example
|
|
307
|
+
* // import TraceLaneService from '@tracelane/wdio';
|
|
308
|
+
* doesn't false-positive — but the stripped buffer preserves the import
|
|
309
|
+
* keyword itself, so a real import is still detected.
|
|
310
|
+
*
|
|
311
|
+
* Wait — we DO want to match the literal '@tracelane/wdio' inside the
|
|
312
|
+
* `from '...'` clause. The strip replaces string CONTENT with spaces, so
|
|
313
|
+
* `from '@tracelane/wdio'` becomes `from ' '` in the stripped
|
|
314
|
+
* buffer. We need to recognise the real import by structure: the keyword
|
|
315
|
+
* `import`, the binding, `from`, a string literal of any contents. We test
|
|
316
|
+
* the structural shape on the stripped buffer, then verify the string
|
|
317
|
+
* literal's contents against the RAW source at the matched offsets.
|
|
318
|
+
*/
|
|
319
|
+
export function hasTracelaneImport(source) {
|
|
320
|
+
const scan = stripStringsAndComments(source);
|
|
321
|
+
// Structural match against the stripped buffer (the string contents are
|
|
322
|
+
// padded out to spaces but the surrounding `from '...'` syntax stays).
|
|
323
|
+
const re = /import\s+[^;]*?from\s+(['"])([^'"]*)\1;?/g;
|
|
324
|
+
let m;
|
|
325
|
+
// biome-ignore lint/suspicious/noAssignInExpressions: idiomatic for global-flag regex iteration
|
|
326
|
+
while ((m = re.exec(scan)) !== null) {
|
|
327
|
+
// The group at index 2 is the STRING CONTENT in the stripped buffer (so
|
|
328
|
+
// spaces), but the same offsets in the RAW source carry the real chars.
|
|
329
|
+
const fullMatchStart = m.index;
|
|
330
|
+
const fullMatchEnd = m.index + m[0].length;
|
|
331
|
+
const raw = source.slice(fullMatchStart, fullMatchEnd);
|
|
332
|
+
if (/from\s+['"]@tracelane\/wdio['"]/.test(raw))
|
|
333
|
+
return true;
|
|
334
|
+
}
|
|
335
|
+
return false;
|
|
336
|
+
}
|
|
337
|
+
/**
|
|
338
|
+
* True if the source already mentions the TraceLaneService in a services
|
|
339
|
+
* array entry — either bare (`TraceLaneService`) or tuple
|
|
340
|
+
* (`[TraceLaneService, ...]`). Runs against the stripped buffer to ignore
|
|
341
|
+
* comment + string mentions.
|
|
342
|
+
*/
|
|
343
|
+
export function hasTracelaneServiceEntry(source) {
|
|
344
|
+
const scan = stripStringsAndComments(source);
|
|
345
|
+
return /\[\s*TraceLaneService\b|\bTraceLaneService\b\s*[,\]]/.test(scan);
|
|
346
|
+
}
|
|
347
|
+
/**
|
|
348
|
+
* Insert `[TraceLaneService, { mode: 'failed' }]` as the LAST element of an
|
|
349
|
+
* existing services array. Three input shapes covered:
|
|
350
|
+
*
|
|
351
|
+
* services: [] → services: [[Service, opts]]
|
|
352
|
+
* services: ['devtools'] → services: ['devtools', [Service, opts]]
|
|
353
|
+
* services: [['devtools', {}]] → services: [['devtools', {}], [Service, opts]]
|
|
354
|
+
*
|
|
355
|
+
* Returns the new full source. Caller has already located `block` via
|
|
356
|
+
* `findServicesArray`.
|
|
357
|
+
*/
|
|
358
|
+
export function appendToServicesArray(source, block) {
|
|
359
|
+
const inner = block.inner;
|
|
360
|
+
const trimmedInner = inner.replace(/\s+$/, '');
|
|
361
|
+
const isEmpty = trimmedInner.trim().length === 0;
|
|
362
|
+
// Detect trailing comma so we don't double-comma.
|
|
363
|
+
const hasTrailingComma = trimmedInner.endsWith(',');
|
|
364
|
+
// Replacement strategy: rebuild the inner content with our entry appended.
|
|
365
|
+
//
|
|
366
|
+
// - Empty array → `[<tuple>]`
|
|
367
|
+
// - Trailing , → `[existing, <tuple>]` (we add tuple after the comma)
|
|
368
|
+
// - No trailing → `[existing, <tuple>]` (we add `, <tuple>`)
|
|
369
|
+
let newInner;
|
|
370
|
+
if (isEmpty) {
|
|
371
|
+
newInner = TRACELANE_SERVICE_TUPLE;
|
|
372
|
+
}
|
|
373
|
+
else if (hasTrailingComma) {
|
|
374
|
+
newInner = `${trimmedInner} ${TRACELANE_SERVICE_TUPLE}`;
|
|
375
|
+
}
|
|
376
|
+
else {
|
|
377
|
+
newInner = `${trimmedInner}, ${TRACELANE_SERVICE_TUPLE}`;
|
|
378
|
+
}
|
|
379
|
+
return `${source.slice(0, block.openIndex + 1)}${newInner}${source.slice(block.closeIndex)}`;
|
|
380
|
+
}
|
|
381
|
+
/**
|
|
382
|
+
* Insert a `services: [[TraceLaneService, ...]]` line into a config object
|
|
383
|
+
* that has no `services:` key at all.
|
|
384
|
+
*
|
|
385
|
+
* Strategy: find the FIRST top-level `export const config` / `export default`
|
|
386
|
+
* config object literal, locate its outermost `{`/`}`, and insert
|
|
387
|
+
* services: [[TraceLaneService, { mode: 'failed' }]],
|
|
388
|
+
* just before the closing `}`. If we can't find the object literal, return
|
|
389
|
+
* undefined and let the caller back out to the manual-snippet path.
|
|
390
|
+
*
|
|
391
|
+
* Runs against the stripped buffer so an `export default { ... }` string in
|
|
392
|
+
* a doc-comment header can't be matched.
|
|
393
|
+
*/
|
|
394
|
+
export function insertServicesKey(source) {
|
|
395
|
+
const scan = stripStringsAndComments(source);
|
|
396
|
+
const re = /(?:export\s+(?:default|const\s+config[^=]*=)|module\.exports\s*=)\s*(\{)/;
|
|
397
|
+
const m = re.exec(scan);
|
|
398
|
+
if (!m)
|
|
399
|
+
return undefined;
|
|
400
|
+
const braceIndex = m.index + m[0].length - 1; // points at `{`
|
|
401
|
+
const closeIndex = findMatchingDelimiter(scan, braceIndex, '{', '}');
|
|
402
|
+
if (closeIndex === -1)
|
|
403
|
+
return undefined;
|
|
404
|
+
const insertion = ` services: [${TRACELANE_SERVICE_TUPLE}],\n`;
|
|
405
|
+
return `${source.slice(0, closeIndex)}${insertion}${source.slice(closeIndex)}`;
|
|
406
|
+
}
|
|
407
|
+
/**
|
|
408
|
+
* Manual-paste snippet shown when the editor backs out. The user pastes this
|
|
409
|
+
* at the top of their conf and adds the tuple to `services:` themselves.
|
|
410
|
+
*
|
|
411
|
+
* This is the single source of truth — `init.ts`'s "restored from backup"
|
|
412
|
+
* path also references this constant so the snippet copy doesn't drift.
|
|
413
|
+
*/
|
|
414
|
+
export const MANUAL_SNIPPET = `${TRACELANE_IMPORT}
|
|
415
|
+
|
|
416
|
+
// Inside your config object's \`services\` array:
|
|
417
|
+
// services: [${TRACELANE_SERVICE_TUPLE}],
|
|
418
|
+
`;
|
|
419
|
+
/**
|
|
420
|
+
* The single high-level entrypoint. Given the current source of a
|
|
421
|
+
* wdio.conf.*, produce the new source (with the import + service tuple
|
|
422
|
+
* added) — or fail cleanly with a manual snippet for the user to paste.
|
|
423
|
+
*
|
|
424
|
+
* Steps:
|
|
425
|
+
* 1. If both the import + the service entry are already present, no-op.
|
|
426
|
+
* 2. Add the import if it's missing.
|
|
427
|
+
* 3. Append to the existing `services: [...]` array, OR insert a new
|
|
428
|
+
* `services:` key if none exists.
|
|
429
|
+
* 4. Sanity-check the byte-count delta + presence of the marker strings.
|
|
430
|
+
*
|
|
431
|
+
* The sanity check at the END is the safety net: if our regex went off the
|
|
432
|
+
* rails (e.g. landed on an unusual shape) the delta is wildly wrong and we
|
|
433
|
+
* back out instead of writing a corrupt file.
|
|
434
|
+
*/
|
|
435
|
+
export function applyWdioEdit(originalSource) {
|
|
436
|
+
const hadImport = hasTracelaneImport(originalSource);
|
|
437
|
+
const hadEntry = hasTracelaneServiceEntry(originalSource);
|
|
438
|
+
// Idempotent re-run: both pieces present, nothing to do.
|
|
439
|
+
if (hadImport && hadEntry) {
|
|
440
|
+
return {
|
|
441
|
+
ok: true,
|
|
442
|
+
source: originalSource,
|
|
443
|
+
alreadyConfigured: true,
|
|
444
|
+
addedImport: false,
|
|
445
|
+
addedServiceEntry: false,
|
|
446
|
+
};
|
|
447
|
+
}
|
|
448
|
+
let next = originalSource;
|
|
449
|
+
if (!hadImport) {
|
|
450
|
+
next = insertTracelaneImport(next);
|
|
451
|
+
}
|
|
452
|
+
let addedEntry = false;
|
|
453
|
+
if (!hadEntry) {
|
|
454
|
+
const block = findServicesArray(next);
|
|
455
|
+
if (block !== undefined) {
|
|
456
|
+
next = appendToServicesArray(next, block);
|
|
457
|
+
addedEntry = true;
|
|
458
|
+
}
|
|
459
|
+
else {
|
|
460
|
+
// No `services:` key at all — try to insert one inside the config object.
|
|
461
|
+
const withKey = insertServicesKey(next);
|
|
462
|
+
if (withKey === undefined) {
|
|
463
|
+
return {
|
|
464
|
+
ok: false,
|
|
465
|
+
reason: "Couldn't find the WDIO config object's `services:` array or a config object literal in the conf file. The auto-edit was aborted — apply the snippet below manually.",
|
|
466
|
+
manualSnippet: MANUAL_SNIPPET,
|
|
467
|
+
};
|
|
468
|
+
}
|
|
469
|
+
next = withKey;
|
|
470
|
+
addedEntry = true;
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
// Sanity check: did our edit do something plausible?
|
|
474
|
+
if (!hasTracelaneImport(next)) {
|
|
475
|
+
return {
|
|
476
|
+
ok: false,
|
|
477
|
+
reason: 'Post-edit sanity check failed: import line missing.',
|
|
478
|
+
manualSnippet: MANUAL_SNIPPET,
|
|
479
|
+
};
|
|
480
|
+
}
|
|
481
|
+
if (!hasTracelaneServiceEntry(next)) {
|
|
482
|
+
return {
|
|
483
|
+
ok: false,
|
|
484
|
+
reason: 'Post-edit sanity check failed: TraceLaneService entry missing.',
|
|
485
|
+
manualSnippet: MANUAL_SNIPPET,
|
|
486
|
+
};
|
|
487
|
+
}
|
|
488
|
+
const delta = next.length - originalSource.length;
|
|
489
|
+
// If both import + entry were ADDED we expect ~80-200 bytes of growth.
|
|
490
|
+
// If ONLY the entry was added (import was already there) the floor is
|
|
491
|
+
// smaller — the tuple itself is ~40 bytes.
|
|
492
|
+
const expectedFloor = hadImport ? EDIT_DELTA_MIN_ENTRY_ONLY : EDIT_DELTA_MIN;
|
|
493
|
+
if (delta < expectedFloor || delta > EDIT_DELTA_MAX) {
|
|
494
|
+
return {
|
|
495
|
+
ok: false,
|
|
496
|
+
reason: `Post-edit sanity check failed: byte delta ${delta} outside [${expectedFloor}, ${EDIT_DELTA_MAX}] bounds.`,
|
|
497
|
+
manualSnippet: MANUAL_SNIPPET,
|
|
498
|
+
};
|
|
499
|
+
}
|
|
500
|
+
return {
|
|
501
|
+
ok: true,
|
|
502
|
+
source: next,
|
|
503
|
+
alreadyConfigured: false,
|
|
504
|
+
addedImport: !hadImport,
|
|
505
|
+
addedServiceEntry: addedEntry,
|
|
506
|
+
};
|
|
507
|
+
}
|
|
508
|
+
//# sourceMappingURL=wdio-editor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wdio-editor.js","sourceRoot":"","sources":["../../src/lib/wdio-editor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAeA,eAAO,MAAM,WAAW,QAAe,CAAC"}
|
package/dist/version.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// CLI version surfaced by `tracelane --version` / `tracelane --help`.
|
|
2
|
+
//
|
|
3
|
+
// Read at runtime from this package's package.json (via `createRequire` to
|
|
4
|
+
// keep an awkward JSON ESM import out of the source) so the printed version
|
|
5
|
+
// always matches what npm shipped — same pattern peek-cli/src/version.ts
|
|
6
|
+
// uses to dodge the P-8 drift bug (a hardcoded literal getting out of sync
|
|
7
|
+
// with Changesets-driven version bumps).
|
|
8
|
+
//
|
|
9
|
+
// The relative path is from the compiled dist/version.js → ../package.json.
|
|
10
|
+
import { createRequire } from 'node:module';
|
|
11
|
+
const _require = createRequire(import.meta.url);
|
|
12
|
+
const _pkg = _require('../package.json');
|
|
13
|
+
export const CLI_VERSION = _pkg.version;
|
|
14
|
+
//# sourceMappingURL=version.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,sEAAsE;AACtE,EAAE;AACF,2EAA2E;AAC3E,4EAA4E;AAC5E,yEAAyE;AACzE,2EAA2E;AAC3E,yCAAyC;AACzC,EAAE;AACF,4EAA4E;AAE5E,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,MAAM,QAAQ,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAChD,MAAM,IAAI,GAAG,QAAQ,CAAC,iBAAiB,CAAwB,CAAC;AAEhE,MAAM,CAAC,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@tracelane/cli",
|
|
3
|
+
"version": "0.1.0-alpha.1",
|
|
4
|
+
"description": "tracelane scaffolding CLI. `npx tracelane init` detects your test runner (WDIO / Playwright / Cypress) and wires @tracelane/wdio into wdio.conf.* in one command — the published path from `npm install` + manual conf edit to a single npx invocation.",
|
|
5
|
+
"license": "Apache-2.0",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"tracelane": "./dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"main": "./dist/index.js",
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"types": "./dist/index.d.ts",
|
|
15
|
+
"import": "./dist/index.js"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"files": [
|
|
19
|
+
"dist",
|
|
20
|
+
"NOTICE",
|
|
21
|
+
"README.md"
|
|
22
|
+
],
|
|
23
|
+
"scripts": {
|
|
24
|
+
"build": "tsc -p tsconfig.json && node ./scripts/postbuild.mjs",
|
|
25
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
26
|
+
"test": "vitest run --passWithNoTests"
|
|
27
|
+
},
|
|
28
|
+
"dependencies": {},
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"@types/node": "^22.10.0"
|
|
31
|
+
},
|
|
32
|
+
"publishConfig": {
|
|
33
|
+
"access": "public",
|
|
34
|
+
"provenance": true
|
|
35
|
+
},
|
|
36
|
+
"repository": {
|
|
37
|
+
"type": "git",
|
|
38
|
+
"url": "https://github.com/Cubenest/rrweb-stack",
|
|
39
|
+
"directory": "packages/tracelane-cli"
|
|
40
|
+
},
|
|
41
|
+
"homepage": "https://github.com/Cubenest/rrweb-stack/tree/main/packages/tracelane-cli#readme"
|
|
42
|
+
}
|