supercov 0.0.44 → 0.0.45
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/README.md +21 -12
- package/docs/agent-loop.md +12 -8
- package/docs/assertion-agent.md +156 -0
- package/docs/assertion-evidence.md +9 -694
- package/docs/assertion-maps.md +252 -0
- package/docs/assertions.md +82 -0
- package/docs/cli.md +23 -8
- package/docs/coverage-model.md +12 -0
- package/package.json +34 -35
- package/runtime/javascript/runtime.mjs +18 -33
- package/schemas/assertions.schema.json +276 -0
- package/analyzers/typescript/README.md +0 -59
- package/analyzers/typescript/bin/compiler-identity.mjs +0 -78
- package/analyzers/typescript/bin/identity.mjs +0 -71
- package/analyzers/typescript/bin/query.mjs +0 -29
- package/analyzers/typescript/dist/analyze.js +0 -5273
- package/analyzers/typescript/dist/archive.js +0 -337
- package/analyzers/typescript/dist/awaited-observations.js +0 -376
- package/analyzers/typescript/dist/build-identity.json +0 -1
- package/analyzers/typescript/dist/compiler.js +0 -32
- package/analyzers/typescript/dist/frontend.js +0 -75
- package/analyzers/typescript/dist/mock-counts.js +0 -2517
- package/analyzers/typescript/dist/native-frontend.js +0 -271
- package/analyzers/typescript/dist/pragmas.js +0 -186
- package/analyzers/typescript/dist/types.js +0 -1
- package/analyzers/typescript/package.json +0 -27
- package/analyzers/typescript/src/analyze.ts +0 -6180
- package/analyzers/typescript/src/archive.ts +0 -471
- package/analyzers/typescript/src/awaited-observations.ts +0 -561
- package/analyzers/typescript/src/compiler.ts +0 -49
- package/analyzers/typescript/src/frontend.ts +0 -136
- package/analyzers/typescript/src/mock-counts.ts +0 -3219
- package/analyzers/typescript/src/native-frontend.ts +0 -315
- package/analyzers/typescript/src/pragmas.ts +0 -284
- package/analyzers/typescript/src/types.ts +0 -45
- package/analyzers/typescript/tsconfig.json +0 -12
- package/docs/code-verification.md +0 -4
|
@@ -144,9 +144,6 @@ function createState() {
|
|
|
144
144
|
decisions: /* @__PURE__ */ new Map(),
|
|
145
145
|
hits: /* @__PURE__ */ new Set(),
|
|
146
146
|
events: [],
|
|
147
|
-
// Position of the test-file statement currently executing ("file:line:column"), set by the
|
|
148
|
-
// instrumented test module; production hits recorded meanwhile are attributed to it.
|
|
149
|
-
testStatement: void 0,
|
|
150
147
|
// Per value-position logical expression (`a && b`, `a || b`, `a ?? b`): the distinct
|
|
151
148
|
// (right operand evaluated?, result truthy?) pairs seen, keyed by branch id.
|
|
152
149
|
logicals: /* @__PURE__ */ new Map(),
|
|
@@ -317,7 +314,6 @@ function resetCoverage(testId2) {
|
|
|
317
314
|
state.decisions.clear();
|
|
318
315
|
state.hits.clear();
|
|
319
316
|
state.events.length = 0;
|
|
320
|
-
state.testStatement = void 0;
|
|
321
317
|
state.logicals.clear();
|
|
322
318
|
state.eventKeys.clear();
|
|
323
319
|
state.probeV2ContextEpochs.clear();
|
|
@@ -758,8 +754,8 @@ function withNodeAssertionPhase(operation, source, callback) {
|
|
|
758
754
|
const existing = context.phaseId && assertionPhaseState(scope).phaseIds.has(context.phaseId);
|
|
759
755
|
if (existing)
|
|
760
756
|
return callback();
|
|
761
|
-
//
|
|
762
|
-
//
|
|
757
|
+
// A lexical occurrence already identifies its source. Stack fallback is lazy
|
|
758
|
+
// and qualified so transformed coordinates cannot impersonate original ones.
|
|
763
759
|
if (typeof source === "function")
|
|
764
760
|
source = source();
|
|
765
761
|
const bridged = (_a8 = runtimeGlobal.__SUPERCOV_ASSERTION_PHASE_BRIDGE__) == null ? void 0 : _a8.call(runtimeGlobal, operation, source, callback);
|
|
@@ -792,15 +788,12 @@ function withNodeAssertionPhase(operation, source, callback) {
|
|
|
792
788
|
throw cleanInstrumentationStack(error);
|
|
793
789
|
}
|
|
794
790
|
}
|
|
795
|
-
//
|
|
796
|
-
//
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
const target = method === void 0 ? receiver : receiver[method];
|
|
802
|
-
const thisArgument = method === void 0 ? void 0 : receiver;
|
|
803
|
-
return (...args) => withNodeAssertionPhase(operation, source, () => Reflect.apply(target, thisArgument, args));
|
|
791
|
+
// Callee binding preserves receiver, getter/evaluation order, spreads and the
|
|
792
|
+
// original await/yield placement. Only the matcher call opens the phase.
|
|
793
|
+
function bindNodeAssertionPhase(operation, source, target, property = null) {
|
|
794
|
+
const callback = property === null ? target : target[property];
|
|
795
|
+
const receiver = property === null ? undefined : target;
|
|
796
|
+
return (...args) => withNodeAssertionPhase(operation, source, () => Reflect.apply(callback, receiver, args));
|
|
804
797
|
}
|
|
805
798
|
function takeNodeAssertionPhases(scope) {
|
|
806
799
|
var _a8, _b;
|
|
@@ -995,31 +988,25 @@ function recordBrowserEvent(event) {
|
|
|
995
988
|
state.events.push(event);
|
|
996
989
|
return true;
|
|
997
990
|
}
|
|
998
|
-
function testStatement(source) {
|
|
999
|
-
state.testStatement = typeof source === "string" && source.length > 0 ? source : void 0;
|
|
1000
|
-
}
|
|
1001
|
-
function statementFields() {
|
|
1002
|
-
return state.testStatement ? { statementId: state.testStatement } : {};
|
|
1003
|
-
}
|
|
1004
991
|
function coverageHit(id) {
|
|
1005
992
|
state.hits.add(id);
|
|
1006
993
|
const timestampMs = Date.now();
|
|
1007
994
|
const phaseId = currentPhaseId();
|
|
1008
995
|
if (isBrowser) {
|
|
1009
|
-
if (recordBrowserEvent(__spreadProps(__spreadValues(
|
|
996
|
+
if (recordBrowserEvent(__spreadProps(__spreadValues({
|
|
1010
997
|
type: "hit",
|
|
1011
998
|
id,
|
|
1012
999
|
timestampMs
|
|
1013
|
-
}, phaseId ? { phaseId } : {}),
|
|
1000
|
+
}, phaseId ? { phaseId } : {}), {
|
|
1014
1001
|
environment: "browser"
|
|
1015
1002
|
})))
|
|
1016
1003
|
persistBrowser();
|
|
1017
1004
|
} else {
|
|
1018
|
-
appendServer(__spreadValues(
|
|
1005
|
+
appendServer(__spreadValues({
|
|
1019
1006
|
type: "hit",
|
|
1020
1007
|
id,
|
|
1021
1008
|
timestampMs
|
|
1022
|
-
}, phaseId ? { phaseId } : {})
|
|
1009
|
+
}, phaseId ? { phaseId } : {}));
|
|
1023
1010
|
}
|
|
1024
1011
|
}
|
|
1025
1012
|
function registerProbeV2(definition) {
|
|
@@ -1254,22 +1241,22 @@ function mcdcEnd(frame, value) {
|
|
|
1254
1241
|
const timestampMs = Date.now();
|
|
1255
1242
|
const phaseId = currentPhaseId();
|
|
1256
1243
|
if (isBrowser) {
|
|
1257
|
-
if (recordBrowserEvent(__spreadProps(__spreadValues(
|
|
1244
|
+
if (recordBrowserEvent(__spreadProps(__spreadValues({
|
|
1258
1245
|
type: "decision",
|
|
1259
1246
|
id: decision.meta.id,
|
|
1260
1247
|
vector,
|
|
1261
1248
|
timestampMs
|
|
1262
|
-
}, phaseId ? { phaseId } : {}),
|
|
1249
|
+
}, phaseId ? { phaseId } : {}), {
|
|
1263
1250
|
environment: "browser"
|
|
1264
1251
|
})))
|
|
1265
1252
|
persistBrowser();
|
|
1266
1253
|
} else {
|
|
1267
|
-
appendServer(__spreadValues(
|
|
1254
|
+
appendServer(__spreadValues({
|
|
1268
1255
|
type: "decision",
|
|
1269
1256
|
meta: decision.meta,
|
|
1270
1257
|
vector,
|
|
1271
1258
|
timestampMs
|
|
1272
|
-
}, phaseId ? { phaseId } : {})
|
|
1259
|
+
}, phaseId ? { phaseId } : {}));
|
|
1273
1260
|
}
|
|
1274
1261
|
return value;
|
|
1275
1262
|
}
|
|
@@ -1310,13 +1297,12 @@ const directRuntimeApi = {
|
|
|
1310
1297
|
selectionEnd,
|
|
1311
1298
|
selectionRight,
|
|
1312
1299
|
takeNodeAssertionPhases,
|
|
1313
|
-
bindNodeAssertion,
|
|
1314
|
-
testStatement,
|
|
1315
1300
|
tryBegin,
|
|
1316
1301
|
tryCatch,
|
|
1317
1302
|
tryEnd,
|
|
1318
1303
|
withCoverageCarrier,
|
|
1319
1304
|
withNodeAssertionPhase,
|
|
1305
|
+
bindNodeAssertionPhase,
|
|
1320
1306
|
withRequestPhase,
|
|
1321
1307
|
writeExclusiveBackgroundRecord
|
|
1322
1308
|
};
|
|
@@ -1361,13 +1347,12 @@ export {
|
|
|
1361
1347
|
selectionEnd,
|
|
1362
1348
|
selectionRight,
|
|
1363
1349
|
takeNodeAssertionPhases,
|
|
1364
|
-
bindNodeAssertion,
|
|
1365
|
-
testStatement,
|
|
1366
1350
|
tryBegin,
|
|
1367
1351
|
tryCatch,
|
|
1368
1352
|
tryEnd,
|
|
1369
1353
|
withCoverageCarrier,
|
|
1370
1354
|
withNodeAssertionPhase,
|
|
1355
|
+
bindNodeAssertionPhase,
|
|
1371
1356
|
withRequestPhase,
|
|
1372
1357
|
writeExclusiveBackgroundRecord
|
|
1373
1358
|
};
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"title": "AssertionMap",
|
|
4
|
+
"type": "object",
|
|
5
|
+
"properties": {
|
|
6
|
+
"schemaVersion": {
|
|
7
|
+
"type": "integer",
|
|
8
|
+
"format": "uint32",
|
|
9
|
+
"minimum": 2,
|
|
10
|
+
"maximum": 2
|
|
11
|
+
},
|
|
12
|
+
"assertions": {
|
|
13
|
+
"type": "array",
|
|
14
|
+
"items": {
|
|
15
|
+
"$ref": "#/$defs/Assertion"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"changeAssessments": {
|
|
19
|
+
"type": "array",
|
|
20
|
+
"items": {
|
|
21
|
+
"$ref": "#/$defs/ChangeAssessment"
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"retiredAssertions": {
|
|
25
|
+
"type": "array",
|
|
26
|
+
"items": {
|
|
27
|
+
"$ref": "#/$defs/Retired"
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"additionalProperties": false,
|
|
32
|
+
"required": [
|
|
33
|
+
"schemaVersion",
|
|
34
|
+
"assertions"
|
|
35
|
+
],
|
|
36
|
+
"$defs": {
|
|
37
|
+
"Assertion": {
|
|
38
|
+
"type": "object",
|
|
39
|
+
"properties": {
|
|
40
|
+
"id": {
|
|
41
|
+
"type": "string"
|
|
42
|
+
},
|
|
43
|
+
"at": {
|
|
44
|
+
"$ref": "#/$defs/Anchor"
|
|
45
|
+
},
|
|
46
|
+
"questions": {
|
|
47
|
+
"type": "array",
|
|
48
|
+
"items": {
|
|
49
|
+
"type": "string"
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
"observes": {
|
|
53
|
+
"type": "array",
|
|
54
|
+
"items": {
|
|
55
|
+
"type": "string"
|
|
56
|
+
},
|
|
57
|
+
"default": []
|
|
58
|
+
},
|
|
59
|
+
"flows": {
|
|
60
|
+
"type": "array",
|
|
61
|
+
"items": {
|
|
62
|
+
"$ref": "#/$defs/Flow"
|
|
63
|
+
},
|
|
64
|
+
"default": []
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
"additionalProperties": false,
|
|
68
|
+
"required": [
|
|
69
|
+
"id",
|
|
70
|
+
"at"
|
|
71
|
+
]
|
|
72
|
+
},
|
|
73
|
+
"Anchor": {
|
|
74
|
+
"description": "One-based lines and UTF-8 byte columns, for every language. Text is exact.",
|
|
75
|
+
"type": "object",
|
|
76
|
+
"properties": {
|
|
77
|
+
"file": {
|
|
78
|
+
"type": "string"
|
|
79
|
+
},
|
|
80
|
+
"line": {
|
|
81
|
+
"type": "integer",
|
|
82
|
+
"format": "uint",
|
|
83
|
+
"minimum": 0
|
|
84
|
+
},
|
|
85
|
+
"column": {
|
|
86
|
+
"type": "integer",
|
|
87
|
+
"format": "uint",
|
|
88
|
+
"minimum": 0
|
|
89
|
+
},
|
|
90
|
+
"text": {
|
|
91
|
+
"type": "string"
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
"additionalProperties": false,
|
|
95
|
+
"required": [
|
|
96
|
+
"file",
|
|
97
|
+
"line",
|
|
98
|
+
"column",
|
|
99
|
+
"text"
|
|
100
|
+
]
|
|
101
|
+
},
|
|
102
|
+
"Flow": {
|
|
103
|
+
"type": "object",
|
|
104
|
+
"properties": {
|
|
105
|
+
"id": {
|
|
106
|
+
"type": "string"
|
|
107
|
+
},
|
|
108
|
+
"basis": {
|
|
109
|
+
"type": [
|
|
110
|
+
"string",
|
|
111
|
+
"null"
|
|
112
|
+
],
|
|
113
|
+
"pattern": "^scov2:[0-9a-f]{64}$"
|
|
114
|
+
},
|
|
115
|
+
"explanation": {
|
|
116
|
+
"type": "string"
|
|
117
|
+
},
|
|
118
|
+
"appliesTo": {
|
|
119
|
+
"type": "array",
|
|
120
|
+
"items": {
|
|
121
|
+
"$ref": "#/$defs/TestSelector"
|
|
122
|
+
}
|
|
123
|
+
},
|
|
124
|
+
"nodes": {
|
|
125
|
+
"type": "array",
|
|
126
|
+
"items": {
|
|
127
|
+
"$ref": "#/$defs/Node"
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
"edges": {
|
|
131
|
+
"type": "array",
|
|
132
|
+
"items": {
|
|
133
|
+
"$ref": "#/$defs/Edge"
|
|
134
|
+
},
|
|
135
|
+
"default": []
|
|
136
|
+
},
|
|
137
|
+
"countsAsAsserted": {
|
|
138
|
+
"type": "array",
|
|
139
|
+
"items": {
|
|
140
|
+
"type": "string"
|
|
141
|
+
}
|
|
142
|
+
},
|
|
143
|
+
"watch": {
|
|
144
|
+
"type": "array",
|
|
145
|
+
"items": {
|
|
146
|
+
"type": "string"
|
|
147
|
+
}
|
|
148
|
+
},
|
|
149
|
+
"questions": {
|
|
150
|
+
"type": "array",
|
|
151
|
+
"items": {
|
|
152
|
+
"type": "string"
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
},
|
|
156
|
+
"additionalProperties": false,
|
|
157
|
+
"required": [
|
|
158
|
+
"id",
|
|
159
|
+
"basis",
|
|
160
|
+
"explanation",
|
|
161
|
+
"appliesTo",
|
|
162
|
+
"nodes",
|
|
163
|
+
"countsAsAsserted",
|
|
164
|
+
"watch"
|
|
165
|
+
]
|
|
166
|
+
},
|
|
167
|
+
"TestSelector": {
|
|
168
|
+
"type": "object",
|
|
169
|
+
"properties": {
|
|
170
|
+
"file": {
|
|
171
|
+
"type": "string"
|
|
172
|
+
},
|
|
173
|
+
"name": {
|
|
174
|
+
"type": "string"
|
|
175
|
+
}
|
|
176
|
+
},
|
|
177
|
+
"additionalProperties": false,
|
|
178
|
+
"required": [
|
|
179
|
+
"file",
|
|
180
|
+
"name"
|
|
181
|
+
]
|
|
182
|
+
},
|
|
183
|
+
"Node": {
|
|
184
|
+
"type": "object",
|
|
185
|
+
"properties": {
|
|
186
|
+
"id": {
|
|
187
|
+
"type": "string"
|
|
188
|
+
},
|
|
189
|
+
"at": {
|
|
190
|
+
"$ref": "#/$defs/Anchor"
|
|
191
|
+
},
|
|
192
|
+
"role": {
|
|
193
|
+
"type": "string"
|
|
194
|
+
},
|
|
195
|
+
"meaning": {
|
|
196
|
+
"type": "string"
|
|
197
|
+
}
|
|
198
|
+
},
|
|
199
|
+
"additionalProperties": false,
|
|
200
|
+
"required": [
|
|
201
|
+
"id",
|
|
202
|
+
"at"
|
|
203
|
+
]
|
|
204
|
+
},
|
|
205
|
+
"Edge": {
|
|
206
|
+
"type": "object",
|
|
207
|
+
"properties": {
|
|
208
|
+
"from": {
|
|
209
|
+
"type": "string"
|
|
210
|
+
},
|
|
211
|
+
"to": {
|
|
212
|
+
"type": "string"
|
|
213
|
+
},
|
|
214
|
+
"kind": {
|
|
215
|
+
"type": "string"
|
|
216
|
+
},
|
|
217
|
+
"basis": {
|
|
218
|
+
"type": "string"
|
|
219
|
+
}
|
|
220
|
+
},
|
|
221
|
+
"additionalProperties": false,
|
|
222
|
+
"required": [
|
|
223
|
+
"from",
|
|
224
|
+
"to",
|
|
225
|
+
"kind"
|
|
226
|
+
]
|
|
227
|
+
},
|
|
228
|
+
"ChangeAssessment": {
|
|
229
|
+
"type": "object",
|
|
230
|
+
"properties": {
|
|
231
|
+
"id": {
|
|
232
|
+
"type": "string"
|
|
233
|
+
},
|
|
234
|
+
"basis": {
|
|
235
|
+
"type": [
|
|
236
|
+
"string",
|
|
237
|
+
"null"
|
|
238
|
+
],
|
|
239
|
+
"pattern": "^scov2:[0-9a-f]{64}$"
|
|
240
|
+
},
|
|
241
|
+
"affectedFlows": {
|
|
242
|
+
"type": "array",
|
|
243
|
+
"items": {
|
|
244
|
+
"type": "string"
|
|
245
|
+
}
|
|
246
|
+
},
|
|
247
|
+
"explanation": {
|
|
248
|
+
"type": "string"
|
|
249
|
+
}
|
|
250
|
+
},
|
|
251
|
+
"additionalProperties": false,
|
|
252
|
+
"required": [
|
|
253
|
+
"id",
|
|
254
|
+
"basis",
|
|
255
|
+
"affectedFlows",
|
|
256
|
+
"explanation"
|
|
257
|
+
]
|
|
258
|
+
},
|
|
259
|
+
"Retired": {
|
|
260
|
+
"type": "object",
|
|
261
|
+
"properties": {
|
|
262
|
+
"assertion": {
|
|
263
|
+
"$ref": "#/$defs/Assertion"
|
|
264
|
+
},
|
|
265
|
+
"reason": {
|
|
266
|
+
"type": "string"
|
|
267
|
+
}
|
|
268
|
+
},
|
|
269
|
+
"additionalProperties": false,
|
|
270
|
+
"required": [
|
|
271
|
+
"assertion",
|
|
272
|
+
"reason"
|
|
273
|
+
]
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
# JS/TS assertion analyzer (internal)
|
|
2
|
-
|
|
3
|
-
This private package is the post-run analysis component used by Supercov's
|
|
4
|
-
`runs <run> assertions` command. It is bundled in the npm distribution, not
|
|
5
|
-
published as a separate CLI or SDK.
|
|
6
|
-
|
|
7
|
-
See [Assertion evidence](../../docs/assertion-evidence.md) for public commands,
|
|
8
|
-
pragma syntax, report interpretation and supported scope.
|
|
9
|
-
|
|
10
|
-
## Product boundary
|
|
11
|
-
|
|
12
|
-
- `bin/query.mjs` is the CLI-to-analyzer JSON transport. It accepts an ordinary
|
|
13
|
-
archive representation prepared by Rust, validates identities and returns facts.
|
|
14
|
-
- `bin/identity.mjs` checks the analyzer source/build identity; its direct
|
|
15
|
-
invocation writes that identity during the build.
|
|
16
|
-
- `bin/compiler-identity.mjs` fingerprints the project's compiler implementation.
|
|
17
|
-
- `src/archive.ts` validates the archive protocol, source positions and attempt
|
|
18
|
-
ownership, then constructs query-local evidence in memory.
|
|
19
|
-
- `src/analyze.ts` extracts source-flow facts and exact assertion witnesses.
|
|
20
|
-
The Rust engine joins those facts into candidate classifications.
|
|
21
|
-
- `src/mock-counts.ts` models bounded synchronous console-mock count histories,
|
|
22
|
-
keeping count evidence separate from general value-protection claims.
|
|
23
|
-
- `src/awaited-observations.ts` recognizes bounded native child-capture/poll
|
|
24
|
-
source patterns for hint attachment, without manufacturing runtime witnesses.
|
|
25
|
-
- `src/frontend.ts` and `src/native-frontend.ts` implement the legacy and native
|
|
26
|
-
TypeScript compiler boundaries. `src/pragmas.ts` validates optional hints.
|
|
27
|
-
|
|
28
|
-
There is no converted-input command, on-disk research input, V8 remapping,
|
|
29
|
-
mutation runner or diagnostic-ablation option in the product interface.
|
|
30
|
-
Source files ship to support build-identity verification; tests and research
|
|
31
|
-
tools do not ship. Assertion candidates remain unverified, not safety proofs.
|
|
32
|
-
Only executable JavaScript and its build identity ship from `dist`; there is no
|
|
33
|
-
public SDK declaration surface or generated source-map payload.
|
|
34
|
-
|
|
35
|
-
## Build and test
|
|
36
|
-
|
|
37
|
-
From this directory:
|
|
38
|
-
|
|
39
|
-
```sh
|
|
40
|
-
npm ci --ignore-scripts
|
|
41
|
-
npm test
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
The build uses pinned TypeScript 5.8.3 explicitly. Project analysis uses the
|
|
45
|
-
project's compiler; native 7.0.2 has a separate frontend and identity checks.
|
|
46
|
-
Native compiler processes close after both successful and failed queries.
|
|
47
|
-
|
|
48
|
-
From the repository root, exercise real Node/Vitest archives and the installed
|
|
49
|
-
npm package:
|
|
50
|
-
|
|
51
|
-
```sh
|
|
52
|
-
npm run test:asserted-integration
|
|
53
|
-
npm run test:asserted-package
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
Controlled unit fixtures test parser, flow and witness rules. The ordinary-archive
|
|
57
|
-
integration tests execute real suites and explicit behavioral counterexamples.
|
|
58
|
-
Compiler-path and identity regressions run across supported CI platforms.
|
|
59
|
-
Historical external-cohort research is not part of the default suite or product.
|
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
import { createHash } from "node:crypto";
|
|
2
|
-
import { readFileSync, readdirSync } from "node:fs";
|
|
3
|
-
import { dirname, resolve } from "node:path";
|
|
4
|
-
import { createRequire } from "node:module";
|
|
5
|
-
import { pathToFileURL } from "node:url";
|
|
6
|
-
import { projectCompilerPath } from "../dist/compiler.js";
|
|
7
|
-
|
|
8
|
-
/** Hash the native implementation as well as its JS client; version.cjs alone is not the compiler. */
|
|
9
|
-
export function compilerIdentity(projectRoot) {
|
|
10
|
-
return compilerIdentityFromEntry(projectCompilerPath(projectRoot));
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export function compilerIdentityFromEntry(entry) {
|
|
14
|
-
const require = createRequire(pathToFileURL(entry));
|
|
15
|
-
const { version } = require(entry);
|
|
16
|
-
const entrySha256 = createHash("sha256")
|
|
17
|
-
.update(readFileSync(entry))
|
|
18
|
-
.digest("hex");
|
|
19
|
-
if (version !== "7.0.2")
|
|
20
|
-
return { backend: "typescript-legacy", version, sha256: entrySha256 };
|
|
21
|
-
const packageRoot = dirname(require.resolve("typescript/package.json"));
|
|
22
|
-
const platform = `@typescript/typescript-${process.platform}-${process.arch}`;
|
|
23
|
-
let nativeRoot;
|
|
24
|
-
try {
|
|
25
|
-
nativeRoot = dirname(require.resolve(`${platform}/package.json`));
|
|
26
|
-
} catch (cause) {
|
|
27
|
-
throw new Error(
|
|
28
|
-
`TypeScript 7's native compiler dependency ${platform} is missing. Install the project's optional TypeScript dependencies before recapturing tests.`,
|
|
29
|
-
{ cause },
|
|
30
|
-
);
|
|
31
|
-
}
|
|
32
|
-
const nativeMetadata = JSON.parse(
|
|
33
|
-
readFileSync(resolve(nativeRoot, "package.json"), "utf8"),
|
|
34
|
-
);
|
|
35
|
-
if (nativeMetadata.name !== platform || nativeMetadata.version !== version)
|
|
36
|
-
throw new Error(
|
|
37
|
-
`TypeScript native package identity mismatch: expected ${platform}@${version}`,
|
|
38
|
-
);
|
|
39
|
-
const executable = resolve(
|
|
40
|
-
nativeRoot,
|
|
41
|
-
"lib",
|
|
42
|
-
process.platform === "win32" ? "tsc.exe" : "tsc",
|
|
43
|
-
);
|
|
44
|
-
const nativeSha256 = createHash("sha256")
|
|
45
|
-
.update(readFileSync(executable))
|
|
46
|
-
.digest("hex");
|
|
47
|
-
const hash = createHash("sha256");
|
|
48
|
-
let files = 0;
|
|
49
|
-
function walk(root, relative = "") {
|
|
50
|
-
for (const file of readdirSync(resolve(root, relative), {
|
|
51
|
-
withFileTypes: true,
|
|
52
|
-
}).sort((a, b) => a.name.localeCompare(b.name))) {
|
|
53
|
-
if (file.name === "node_modules") continue;
|
|
54
|
-
const path = relative ? `${relative}/${file.name}` : file.name;
|
|
55
|
-
if (file.isDirectory()) walk(root, path);
|
|
56
|
-
else if (file.isFile()) {
|
|
57
|
-
hash
|
|
58
|
-
.update(path)
|
|
59
|
-
.update("\0")
|
|
60
|
-
.update(readFileSync(resolve(root, path)))
|
|
61
|
-
.update("\0");
|
|
62
|
-
files++;
|
|
63
|
-
} else throw new Error(`Unsupported compiler package entry: ${path}`);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
hash.update("typescript-package\0");
|
|
67
|
-
walk(packageRoot);
|
|
68
|
-
hash.update("native-package\0");
|
|
69
|
-
walk(nativeRoot);
|
|
70
|
-
return {
|
|
71
|
-
backend: "typescript-native-7",
|
|
72
|
-
version,
|
|
73
|
-
sha256: hash.digest("hex"),
|
|
74
|
-
nativePackage: platform,
|
|
75
|
-
nativeSha256,
|
|
76
|
-
files,
|
|
77
|
-
};
|
|
78
|
-
}
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
import { createHash } from "node:crypto";
|
|
2
|
-
import { readFileSync, writeFileSync } from "node:fs";
|
|
3
|
-
import { resolve } from "node:path";
|
|
4
|
-
import { fileURLToPath } from "node:url";
|
|
5
|
-
|
|
6
|
-
const root = resolve(import.meta.dirname, "..");
|
|
7
|
-
const sources = [
|
|
8
|
-
"src/analyze.ts",
|
|
9
|
-
"src/archive.ts",
|
|
10
|
-
"src/awaited-observations.ts",
|
|
11
|
-
"src/compiler.ts",
|
|
12
|
-
"src/frontend.ts",
|
|
13
|
-
"src/native-frontend.ts",
|
|
14
|
-
"src/types.ts",
|
|
15
|
-
"src/pragmas.ts",
|
|
16
|
-
"src/mock-counts.ts",
|
|
17
|
-
"bin/query.mjs",
|
|
18
|
-
"bin/compiler-identity.mjs",
|
|
19
|
-
"bin/identity.mjs",
|
|
20
|
-
"tsconfig.json",
|
|
21
|
-
// npm excludes package-lock.json from tarballs. Hash shipped build inputs,
|
|
22
|
-
// not a checkout-only file, so installed and development checks are identical.
|
|
23
|
-
"package.json",
|
|
24
|
-
];
|
|
25
|
-
const outputs = [
|
|
26
|
-
"dist/analyze.js",
|
|
27
|
-
"dist/archive.js",
|
|
28
|
-
"dist/awaited-observations.js",
|
|
29
|
-
"dist/compiler.js",
|
|
30
|
-
"dist/frontend.js",
|
|
31
|
-
"dist/native-frontend.js",
|
|
32
|
-
"dist/types.js",
|
|
33
|
-
"dist/pragmas.js",
|
|
34
|
-
"dist/mock-counts.js",
|
|
35
|
-
];
|
|
36
|
-
function digest(files) {
|
|
37
|
-
const hash = createHash("sha256");
|
|
38
|
-
for (const file of files)
|
|
39
|
-
hash
|
|
40
|
-
.update(file)
|
|
41
|
-
.update("\0")
|
|
42
|
-
.update(readFileSync(resolve(root, file)))
|
|
43
|
-
.update("\0");
|
|
44
|
-
return hash.digest("hex");
|
|
45
|
-
}
|
|
46
|
-
export function identity() {
|
|
47
|
-
return {
|
|
48
|
-
schema: 1,
|
|
49
|
-
sourceSha256: digest(sources),
|
|
50
|
-
compiledSha256: digest(outputs),
|
|
51
|
-
};
|
|
52
|
-
}
|
|
53
|
-
export function checkedIdentity() {
|
|
54
|
-
const built = JSON.parse(
|
|
55
|
-
readFileSync(resolve(root, "dist/build-identity.json"), "utf8"),
|
|
56
|
-
);
|
|
57
|
-
const current = identity();
|
|
58
|
-
if (JSON.stringify(built) !== JSON.stringify(current))
|
|
59
|
-
throw new Error(
|
|
60
|
-
"Assertion analyzer build is stale or modified; rebuild analyzers/typescript",
|
|
61
|
-
);
|
|
62
|
-
return current;
|
|
63
|
-
}
|
|
64
|
-
if (
|
|
65
|
-
process.argv[1] &&
|
|
66
|
-
resolve(process.argv[1]) === fileURLToPath(import.meta.url)
|
|
67
|
-
)
|
|
68
|
-
writeFileSync(
|
|
69
|
-
resolve(root, "dist/build-identity.json"),
|
|
70
|
-
JSON.stringify(identity()) + "\n",
|
|
71
|
-
);
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
// First-party query transport, never executed by the test runner.
|
|
2
|
-
import { readFileSync } from "node:fs";
|
|
3
|
-
import { checkedIdentity } from "./identity.mjs";
|
|
4
|
-
|
|
5
|
-
try {
|
|
6
|
-
const analyzer = checkedIdentity();
|
|
7
|
-
const input = JSON.parse(readFileSync(0, "utf8"));
|
|
8
|
-
// Check the build before importing executable analyzer code.
|
|
9
|
-
const { compilerIdentity } = await import("./compiler-identity.mjs");
|
|
10
|
-
const { analyzeArchive } = await import("../dist/archive.js");
|
|
11
|
-
const compiler = compilerIdentity(input.projectRoot);
|
|
12
|
-
const compilerSha256 = compiler.sha256;
|
|
13
|
-
const result = analyzeArchive(input);
|
|
14
|
-
if (
|
|
15
|
-
JSON.stringify(compilerIdentity(input.projectRoot)) !==
|
|
16
|
-
JSON.stringify(compiler) ||
|
|
17
|
-
JSON.stringify(checkedIdentity()) !== JSON.stringify(analyzer)
|
|
18
|
-
)
|
|
19
|
-
throw new Error("Analyzer or compiler changed during analysis");
|
|
20
|
-
process.stdout.write(
|
|
21
|
-
JSON.stringify({
|
|
22
|
-
...result,
|
|
23
|
-
analyzer: { ...analyzer, compilerSha256, compiler },
|
|
24
|
-
}),
|
|
25
|
-
);
|
|
26
|
-
} catch (error) {
|
|
27
|
-
console.error(error instanceof Error ? error.message : String(error));
|
|
28
|
-
process.exitCode = 1;
|
|
29
|
-
}
|