@suss/extractor 0.9.0 → 0.11.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/dist/index.cjs +71 -24
- package/dist/index.d.cts +296 -249
- package/dist/index.d.ts +296 -249
- package/dist/index.js +69 -21
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -3,7 +3,8 @@ import { createHash } from "crypto";
|
|
|
3
3
|
import {
|
|
4
4
|
exchangesHttpResponses,
|
|
5
5
|
withGraphqlMetadata,
|
|
6
|
-
withHttpMetadata
|
|
6
|
+
withHttpMetadata,
|
|
7
|
+
withSourceDocumentMetadata
|
|
7
8
|
} from "@suss/behavioral-ir";
|
|
8
9
|
|
|
9
10
|
// src/inputReads.ts
|
|
@@ -124,6 +125,7 @@ function unwrapJsonStringify(body) {
|
|
|
124
125
|
}
|
|
125
126
|
|
|
126
127
|
// src/paths/enumeratePaths.ts
|
|
128
|
+
import { CATCH_ENTRY_TEXT } from "@suss/behavioral-ir";
|
|
127
129
|
var MAX_PATHS = 256;
|
|
128
130
|
var UnmodeledFlow = class extends Error {
|
|
129
131
|
};
|
|
@@ -167,7 +169,7 @@ var loopCompletedCond = (headerText, exit) => fixedCond(
|
|
|
167
169
|
exit === "throw" ? "earlyThrow" : "earlyReturn"
|
|
168
170
|
);
|
|
169
171
|
var catchEntryCond = () => fixedCond(
|
|
170
|
-
{ sourceText:
|
|
172
|
+
{ sourceText: CATCH_ENTRY_TEXT, expression: null },
|
|
171
173
|
"positive",
|
|
172
174
|
"catchBlock"
|
|
173
175
|
);
|
|
@@ -177,7 +179,7 @@ function classify(path, home, isAncestorOrSelf) {
|
|
|
177
179
|
return cond.info;
|
|
178
180
|
}
|
|
179
181
|
const encloses = home !== null && isAncestorOrSelf(cond.branchStmt, home);
|
|
180
|
-
if (encloses || cond.info.polarity === "positive") {
|
|
182
|
+
if (encloses || cond.info.polarity === "positive" || cond.oppositeExit === null) {
|
|
181
183
|
return { ...cond.info, source: "explicit" };
|
|
182
184
|
}
|
|
183
185
|
const source = cond.oppositeExit === "throw" ? "earlyThrow" : "earlyReturn";
|
|
@@ -185,6 +187,9 @@ function classify(path, home, isAncestorOrSelf) {
|
|
|
185
187
|
});
|
|
186
188
|
}
|
|
187
189
|
function childrenOf(stmt) {
|
|
190
|
+
return [...ownBlocksOf(stmt), ...(stmt.callbacks ?? []).flat()];
|
|
191
|
+
}
|
|
192
|
+
function ownBlocksOf(stmt) {
|
|
188
193
|
if (stmt.kind === "if") {
|
|
189
194
|
return stmt.elseBody === null ? stmt.thenBody : [...stmt.thenBody, ...stmt.elseBody];
|
|
190
195
|
}
|
|
@@ -211,7 +216,7 @@ function hasStrayBreak(nodes) {
|
|
|
211
216
|
if (node.kind === "switch" || node.kind === "loop") {
|
|
212
217
|
return false;
|
|
213
218
|
}
|
|
214
|
-
return hasStrayBreak(
|
|
219
|
+
return hasStrayBreak(ownBlocksOf(node));
|
|
215
220
|
});
|
|
216
221
|
}
|
|
217
222
|
function exitKindOfList(stmts) {
|
|
@@ -248,11 +253,6 @@ function containsTerminal(ctx, stmt) {
|
|
|
248
253
|
return childrenOf(stmt).some((child) => containsTerminal(ctx, child));
|
|
249
254
|
}
|
|
250
255
|
function stepIf(stmt, path, ctx) {
|
|
251
|
-
const armsExit = stmt.exitKind !== null;
|
|
252
|
-
const armsHaveTerminals = containsTerminal(ctx, stmt);
|
|
253
|
-
if (!armsExit && !armsHaveTerminals) {
|
|
254
|
-
return [path];
|
|
255
|
-
}
|
|
256
256
|
const thenExit = exitKindOfList(stmt.thenBody);
|
|
257
257
|
const elseExit = stmt.elseBody === null ? null : exitKindOfList(stmt.elseBody);
|
|
258
258
|
const thenPath = [
|
|
@@ -261,7 +261,12 @@ function stepIf(stmt, path, ctx) {
|
|
|
261
261
|
];
|
|
262
262
|
const elsePath = [
|
|
263
263
|
...path,
|
|
264
|
-
branchCond(
|
|
264
|
+
branchCond(
|
|
265
|
+
stmt,
|
|
266
|
+
stmt.condition,
|
|
267
|
+
"negative",
|
|
268
|
+
stmt.elseBody === null ? thenExit : null
|
|
269
|
+
)
|
|
265
270
|
];
|
|
266
271
|
const out = [];
|
|
267
272
|
out.push(...enumerate(ctx, stmt.thenBody, thenPath));
|
|
@@ -333,7 +338,11 @@ function stepTry(stmt, path, ctx) {
|
|
|
333
338
|
}
|
|
334
339
|
return out;
|
|
335
340
|
}
|
|
336
|
-
function stepExit(
|
|
341
|
+
function stepExit(stmt, path, ctx) {
|
|
342
|
+
const collector = ctx.state.callbackExits[ctx.state.callbackExits.length - 1];
|
|
343
|
+
if (collector !== void 0 && (stmt.exit === "return" || stmt.exit === "throw")) {
|
|
344
|
+
collector.push(path);
|
|
345
|
+
}
|
|
337
346
|
return [];
|
|
338
347
|
}
|
|
339
348
|
function stepOpaque(_stmt, path, _ctx) {
|
|
@@ -347,16 +356,36 @@ var stepHandlers = {
|
|
|
347
356
|
exit: stepExit,
|
|
348
357
|
opaque: stepOpaque
|
|
349
358
|
};
|
|
359
|
+
function stepCallback(ctx, body, path) {
|
|
360
|
+
const exits = [];
|
|
361
|
+
ctx.state.callbackExits.push(exits);
|
|
362
|
+
let fellThrough;
|
|
363
|
+
try {
|
|
364
|
+
fellThrough = enumerate(ctx, body, path);
|
|
365
|
+
} finally {
|
|
366
|
+
ctx.state.callbackExits.pop();
|
|
367
|
+
}
|
|
368
|
+
const out = [...fellThrough, ...exits];
|
|
369
|
+
return out.length === 0 ? [path] : out;
|
|
370
|
+
}
|
|
350
371
|
function stepStatement(ctx, stmt, path) {
|
|
372
|
+
let paths = [path];
|
|
373
|
+
for (const body of stmt.callbacks ?? []) {
|
|
374
|
+
paths = paths.flatMap((each) => stepCallback(ctx, body, each));
|
|
375
|
+
}
|
|
351
376
|
const ownTerminals = ctx.terminalsByStmt.get(stmt) ?? [];
|
|
352
|
-
for (const
|
|
353
|
-
|
|
377
|
+
for (const each of withRejoined(paths)) {
|
|
378
|
+
for (const terminal of ownTerminals) {
|
|
379
|
+
recordTerminal(ctx, terminal, stmt, each);
|
|
380
|
+
}
|
|
354
381
|
}
|
|
355
382
|
const handler = stepHandlers[stmt.kind];
|
|
356
|
-
return
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
383
|
+
return paths.flatMap(
|
|
384
|
+
(each) => handler(
|
|
385
|
+
stmt,
|
|
386
|
+
each,
|
|
387
|
+
ctx
|
|
388
|
+
)
|
|
360
389
|
);
|
|
361
390
|
}
|
|
362
391
|
function soleDisagreement(left, right) {
|
|
@@ -413,14 +442,18 @@ function mergeRejoined(paths) {
|
|
|
413
442
|
}
|
|
414
443
|
return current;
|
|
415
444
|
}
|
|
445
|
+
function withRejoined(paths) {
|
|
446
|
+
const merged = mergeRejoined(paths);
|
|
447
|
+
return merged.length === paths.length ? paths : [...merged, ...paths];
|
|
448
|
+
}
|
|
416
449
|
function enumerate(ctx, stmts, prefix) {
|
|
417
450
|
let frontiers = [[...prefix]];
|
|
418
451
|
for (const stmt of stmts) {
|
|
419
452
|
const nextFrontiers = [];
|
|
420
|
-
for (const path of frontiers) {
|
|
453
|
+
for (const path of mergeRejoined(frontiers)) {
|
|
421
454
|
nextFrontiers.push(...stepStatement(ctx, stmt, path));
|
|
422
455
|
}
|
|
423
|
-
frontiers =
|
|
456
|
+
frontiers = nextFrontiers;
|
|
424
457
|
if (frontiers.length > MAX_PATHS) {
|
|
425
458
|
throw new PathBudgetExceeded(
|
|
426
459
|
`path budget exceeded, more than ${MAX_PATHS} paths`
|
|
@@ -460,14 +493,15 @@ function enumerateStructuredPaths(input) {
|
|
|
460
493
|
const state = {
|
|
461
494
|
byTerminal: /* @__PURE__ */ new Map(),
|
|
462
495
|
fallthrough: [],
|
|
463
|
-
pathCount: 0
|
|
496
|
+
pathCount: 0,
|
|
497
|
+
callbackExits: []
|
|
464
498
|
};
|
|
465
499
|
const ctx = {
|
|
466
500
|
terminalsByStmt: input.terminalsByStmt,
|
|
467
501
|
state,
|
|
468
502
|
isAncestorOrSelf
|
|
469
503
|
};
|
|
470
|
-
const continuations = enumerate(ctx, input.statements, []);
|
|
504
|
+
const continuations = withRejoined(enumerate(ctx, input.statements, []));
|
|
471
505
|
for (const path of continuations) {
|
|
472
506
|
chargeBudget(state);
|
|
473
507
|
state.fallthrough.push(classify(path, null, isAncestorOrSelf));
|
|
@@ -766,6 +800,11 @@ function buildMetadata(raw) {
|
|
|
766
800
|
if (graphql !== null) {
|
|
767
801
|
metadata = withGraphqlMetadata(metadata, graphql);
|
|
768
802
|
}
|
|
803
|
+
if (raw.sourceDocumentLabel !== void 0) {
|
|
804
|
+
metadata = withSourceDocumentMetadata(metadata, {
|
|
805
|
+
label: raw.sourceDocumentLabel
|
|
806
|
+
});
|
|
807
|
+
}
|
|
769
808
|
return Object.keys(metadata).length > 0 ? metadata : null;
|
|
770
809
|
}
|
|
771
810
|
function buildHttpMetadataValue(raw) {
|
|
@@ -783,6 +822,12 @@ function buildHttpMetadataValue(raw) {
|
|
|
783
822
|
if (raw.statusAccessors !== void 0 && raw.statusAccessors.length > 0) {
|
|
784
823
|
http.statusAccessors = raw.statusAccessors;
|
|
785
824
|
}
|
|
825
|
+
if (raw.successAccessors !== void 0 && raw.successAccessors.length > 0) {
|
|
826
|
+
http.successAccessors = raw.successAccessors;
|
|
827
|
+
}
|
|
828
|
+
if (raw.failureDelivery !== void 0) {
|
|
829
|
+
http.failureDelivery = raw.failureDelivery;
|
|
830
|
+
}
|
|
786
831
|
return Object.keys(http).length > 0 ? http : null;
|
|
787
832
|
}
|
|
788
833
|
function buildGraphqlMetadataValue(raw) {
|
|
@@ -796,6 +841,9 @@ function buildGraphqlMetadataValue(raw) {
|
|
|
796
841
|
if (raw.graphqlDeclaredContract !== void 0) {
|
|
797
842
|
graphql.declaredContract = raw.graphqlDeclaredContract;
|
|
798
843
|
}
|
|
844
|
+
if (raw.graphqlUnresolvedFragments !== void 0) {
|
|
845
|
+
graphql.unresolvedFragments = raw.graphqlUnresolvedFragments;
|
|
846
|
+
}
|
|
799
847
|
if (raw.graphqlUnresolvedDocument !== void 0) {
|
|
800
848
|
graphql.unresolvedDocument = raw.graphqlUnresolvedDocument;
|
|
801
849
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@suss/extractor",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Framework-agnostic extraction pipeline that turns raw extractions into suss behavioral summaries.",
|
|
6
6
|
"keywords": [
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"typecheck": "tsc --noEmit"
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
|
-
"@suss/behavioral-ir": "0.
|
|
48
|
+
"@suss/behavioral-ir": "0.11.0"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
51
|
"tsup": "*",
|