test-inventory 0.1.1 → 0.2.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 +30 -0
- package/README.md +3 -10
- package/dist/extract.d.ts +30 -2
- package/dist/extract.js +363 -57
- package/dist/frameworks/bindings.d.ts +20 -12
- package/dist/frameworks/bindings.js +113 -49
- package/dist/frameworks/playwright.js +59 -22
- package/dist/frameworks/vitest.d.ts +2 -0
- package/dist/frameworks/vitest.js +91 -12
- package/dist/index.d.ts +1 -1
- package/dist/model.d.ts +9 -3
- package/dist/options.d.ts +2 -0
- package/dist/records.d.ts +1 -0
- package/dist/records.js +29 -7
- package/dist/resolve.d.ts +3 -2
- package/dist/resolve.js +227 -57
- package/dist/scan-file.js +14 -5
- package/dist/types.d.ts +34 -3
- package/dist/values.d.ts +14 -0
- package/dist/values.js +44 -3
- package/package.json +12 -9
- package/schema/v1.json +48 -1
package/dist/values.js
CHANGED
|
@@ -56,6 +56,35 @@ export class Values {
|
|
|
56
56
|
bindingsByScope = new Map();
|
|
57
57
|
cache = new Map();
|
|
58
58
|
pending = new Set();
|
|
59
|
+
/** The functions being read at one of their calls, innermost last. */
|
|
60
|
+
calls = [];
|
|
61
|
+
/**
|
|
62
|
+
* Runs `read` with a function's parameters bound to the arguments of one call, worked out where the call is, so that
|
|
63
|
+
* titles and values built from them resolve, as in `test(\`${side} rejects a zero quantity\`)` inside
|
|
64
|
+
* `validatesQuantity('buy')`. `args` stop at a spread argument, after which no position is known. A missing argument
|
|
65
|
+
* takes the parameter's default value, worked out in `scopes`, the scopes around the function.
|
|
66
|
+
*/
|
|
67
|
+
withArguments(fn, args, scopes, read) {
|
|
68
|
+
const parameters = new Map();
|
|
69
|
+
for (const [index, parameter] of fn.params.entries()) {
|
|
70
|
+
const target = parameter.type === 'AssignmentPattern' ? parameter.left : parameter;
|
|
71
|
+
if (target.type !== 'Identifier')
|
|
72
|
+
continue;
|
|
73
|
+
const argument = args.at(index);
|
|
74
|
+
if (argument)
|
|
75
|
+
parameters.set(target.name, () => argument);
|
|
76
|
+
else if (parameter.type === 'AssignmentPattern') {
|
|
77
|
+
parameters.set(target.name, () => this.resolve(parameter.right, [...scopes, fn]));
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
this.calls.push({ fn, parameters, cache: new Map() });
|
|
81
|
+
try {
|
|
82
|
+
return read();
|
|
83
|
+
}
|
|
84
|
+
finally {
|
|
85
|
+
this.calls.pop();
|
|
86
|
+
}
|
|
87
|
+
}
|
|
59
88
|
/** `scopes` lists the scope nodes around the expression, outermost first. */
|
|
60
89
|
resolve(node, scopes) {
|
|
61
90
|
const expression = unwrap(node);
|
|
@@ -179,6 +208,11 @@ export class Values {
|
|
|
179
208
|
declarationOf(name, scopes) {
|
|
180
209
|
return this.lookup(name, scopes)?.binding.declaration ?? null;
|
|
181
210
|
}
|
|
211
|
+
/** The module a name is imported from where it is used; null when it isn't an import. */
|
|
212
|
+
importSource(name, scopes) {
|
|
213
|
+
const binding = this.lookup(name, scopes)?.binding;
|
|
214
|
+
return binding?.kind === 'import' ? binding.source : null;
|
|
215
|
+
}
|
|
182
216
|
/** Whether a name refers to a function or class declared in the file. */
|
|
183
217
|
isFunction(name, scopes) {
|
|
184
218
|
return this.lookup(name, scopes)?.binding.kind === 'function';
|
|
@@ -203,12 +237,19 @@ export class Values {
|
|
|
203
237
|
case 'import':
|
|
204
238
|
return { ok: false, importedFrom: binding.source };
|
|
205
239
|
case 'function':
|
|
206
|
-
case 'other':
|
|
207
240
|
return UNRESOLVED;
|
|
241
|
+
case 'other':
|
|
242
|
+
return this.resolveParameter(name, binding.declaration);
|
|
208
243
|
}
|
|
209
244
|
}
|
|
245
|
+
/** A parameter of a function read at one of its calls: the argument given there. */
|
|
246
|
+
resolveParameter(name, fn) {
|
|
247
|
+
const call = this.calls.findLast((item) => item.fn === fn);
|
|
248
|
+
return call?.parameters.get(name)?.() ?? UNRESOLVED;
|
|
249
|
+
}
|
|
210
250
|
resolveConstant(init, scopes) {
|
|
211
|
-
const
|
|
251
|
+
const cache = this.calls.at(-1)?.cache ?? this.cache;
|
|
252
|
+
const cached = cache.get(init);
|
|
212
253
|
if (cached)
|
|
213
254
|
return cached;
|
|
214
255
|
if (this.pending.has(init))
|
|
@@ -216,7 +257,7 @@ export class Values {
|
|
|
216
257
|
this.pending.add(init);
|
|
217
258
|
const resolved = this.resolve(init, scopes);
|
|
218
259
|
this.pending.delete(init);
|
|
219
|
-
|
|
260
|
+
cache.set(init, resolved);
|
|
220
261
|
return resolved;
|
|
221
262
|
}
|
|
222
263
|
enumMembers(node, scopes) {
|
package/package.json
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "test-inventory",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Test metadata from source code, not from test results.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"testing",
|
|
7
|
+
"playwright",
|
|
8
|
+
"vitest",
|
|
7
9
|
"test-suite",
|
|
8
10
|
"test-inventory",
|
|
9
11
|
"static-analysis",
|
|
@@ -77,26 +79,27 @@
|
|
|
77
79
|
"changeset": "changeset"
|
|
78
80
|
},
|
|
79
81
|
"dependencies": {
|
|
80
|
-
"oxc-parser": "0.
|
|
82
|
+
"oxc-parser": "0.154.0",
|
|
81
83
|
"tinyglobby": "^0.2.17"
|
|
82
84
|
},
|
|
83
85
|
"devDependencies": {
|
|
84
86
|
"@arethetypeswrong/cli": "^0.18.5",
|
|
85
87
|
"@changesets/changelog-github": "^1.0.1",
|
|
86
88
|
"@changesets/cli": "^3.0.3",
|
|
87
|
-
"@types/node": "
|
|
88
|
-
"@vitest/coverage-v8": "5.0.
|
|
89
|
+
"@types/node": "~22.12.0",
|
|
90
|
+
"@vitest/coverage-v8": "5.0.4",
|
|
89
91
|
"ajv": "^8.20.0",
|
|
90
|
-
"eslint": "
|
|
91
|
-
"prettier": "
|
|
92
|
+
"eslint": "~10.12.0",
|
|
93
|
+
"prettier": "3.9.10",
|
|
92
94
|
"publint": "^0.3.25",
|
|
93
95
|
"ts-json-schema-generator": "2.9.0",
|
|
94
|
-
"typedoc": "0.28.20",
|
|
96
|
+
"typedoc": "^0.28.20",
|
|
95
97
|
"typedoc-plugin-markdown": "^4.13.1",
|
|
96
98
|
"typedoc-vitepress-theme": "^1.1.4",
|
|
97
99
|
"typescript": "~6.0.3",
|
|
98
|
-
"typescript-eslint": "
|
|
100
|
+
"typescript-eslint": "~8.71.2",
|
|
99
101
|
"vitepress": "2.0.0-alpha.20",
|
|
100
|
-
"
|
|
102
|
+
"vitepress-plugin-llms": "^1.14.0",
|
|
103
|
+
"vitest": "5.0.4"
|
|
101
104
|
}
|
|
102
105
|
}
|
package/schema/v1.json
CHANGED
|
@@ -268,6 +268,17 @@
|
|
|
268
268
|
"minimum": 1,
|
|
269
269
|
"description": "In UTF-16 code units."
|
|
270
270
|
},
|
|
271
|
+
"declaredAt": {
|
|
272
|
+
"anyOf": [
|
|
273
|
+
{
|
|
274
|
+
"$ref": "#/definitions/DeclaredAt"
|
|
275
|
+
},
|
|
276
|
+
{
|
|
277
|
+
"type": "null"
|
|
278
|
+
}
|
|
279
|
+
],
|
|
280
|
+
"description": "Where a helper imported from another file writes the describe; the record's location is then the call that registers it. Null for code written in the scanned file."
|
|
281
|
+
},
|
|
271
282
|
"title": {
|
|
272
283
|
"type": "string",
|
|
273
284
|
"description": "As the runner shows it, tags included."
|
|
@@ -385,6 +396,7 @@
|
|
|
385
396
|
"lineEnd",
|
|
386
397
|
"columnStart",
|
|
387
398
|
"columnEnd",
|
|
399
|
+
"declaredAt",
|
|
388
400
|
"title",
|
|
389
401
|
"titleWithoutTags",
|
|
390
402
|
"hasDynamicTitle",
|
|
@@ -409,6 +421,29 @@
|
|
|
409
421
|
],
|
|
410
422
|
"description": "A describe block, with what is written on the describe itself. Inherited values are on the tests."
|
|
411
423
|
},
|
|
424
|
+
"DeclaredAt": {
|
|
425
|
+
"type": "object",
|
|
426
|
+
"properties": {
|
|
427
|
+
"relativeFilePath": {
|
|
428
|
+
"type": "string",
|
|
429
|
+
"description": "The helper's file, from the project root."
|
|
430
|
+
},
|
|
431
|
+
"lineStart": {
|
|
432
|
+
"type": "integer",
|
|
433
|
+
"minimum": 1
|
|
434
|
+
},
|
|
435
|
+
"columnStart": {
|
|
436
|
+
"type": "integer",
|
|
437
|
+
"minimum": 1,
|
|
438
|
+
"description": "In UTF-16 code units."
|
|
439
|
+
}
|
|
440
|
+
},
|
|
441
|
+
"required": [
|
|
442
|
+
"relativeFilePath",
|
|
443
|
+
"lineStart",
|
|
444
|
+
"columnStart"
|
|
445
|
+
]
|
|
446
|
+
},
|
|
412
447
|
"Annotation": {
|
|
413
448
|
"type": "object",
|
|
414
449
|
"properties": {
|
|
@@ -524,6 +559,17 @@
|
|
|
524
559
|
"minimum": 1,
|
|
525
560
|
"description": "In UTF-16 code units."
|
|
526
561
|
},
|
|
562
|
+
"declaredAt": {
|
|
563
|
+
"anyOf": [
|
|
564
|
+
{
|
|
565
|
+
"$ref": "#/definitions/DeclaredAt"
|
|
566
|
+
},
|
|
567
|
+
{
|
|
568
|
+
"type": "null"
|
|
569
|
+
}
|
|
570
|
+
],
|
|
571
|
+
"description": "Where a helper imported from another file writes the test; the record's location is then the call that registers it. Null for code written in the scanned file."
|
|
572
|
+
},
|
|
527
573
|
"title": {
|
|
528
574
|
"type": "string",
|
|
529
575
|
"description": "As the runner shows it, tags included."
|
|
@@ -646,7 +692,7 @@
|
|
|
646
692
|
"items": {
|
|
647
693
|
"type": "string"
|
|
648
694
|
},
|
|
649
|
-
"description": "From the test and
|
|
695
|
+
"description": "From the test, its describes and the `test.describe.configure()` calls around it. Playwright only."
|
|
650
696
|
},
|
|
651
697
|
"meta": {
|
|
652
698
|
"anyOf": [
|
|
@@ -702,6 +748,7 @@
|
|
|
702
748
|
"lineEnd",
|
|
703
749
|
"columnStart",
|
|
704
750
|
"columnEnd",
|
|
751
|
+
"declaredAt",
|
|
705
752
|
"title",
|
|
706
753
|
"titleWithoutTags",
|
|
707
754
|
"hasDynamicTitle",
|