@suss/extractor 0.32.0 → 0.33.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/README.md +3 -3
- package/dist/index.cjs +36 -6
- package/dist/index.d.cts +52 -6
- package/dist/index.d.ts +52 -6
- package/dist/index.js +39 -6
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -63,8 +63,8 @@ const summary = assembleSummary(raw);
|
|
|
63
63
|
## More
|
|
64
64
|
|
|
65
65
|
- [How the extractor assembles a summary](./DESIGN.md)
|
|
66
|
-
- [Documentation](https://
|
|
67
|
-
- [Every package and pack suss ships](https://
|
|
66
|
+
- [Documentation](https://suss.sh/)
|
|
67
|
+
- [Every package and pack suss ships](https://suss.sh/packs/catalog)
|
|
68
68
|
- [Source and issues](https://github.com/nimbuscloud-ai/suss)
|
|
69
69
|
|
|
70
70
|
## Coverage
|
|
@@ -77,4 +77,4 @@ Licensed under Apache 2.0. See [LICENSE](../../LICENSE).
|
|
|
77
77
|
|
|
78
78
|
---
|
|
79
79
|
|
|
80
|
-
For the canonical design, see [docs/architecture.md](../../docs/architecture.md).
|
|
80
|
+
For the canonical design, see [docs/theory/architecture.md](../../docs/theory/architecture.md).
|
package/dist/index.cjs
CHANGED
|
@@ -395,7 +395,7 @@ function stampModuleImports(summaries, importsOf) {
|
|
|
395
395
|
|
|
396
396
|
// src/moduleInit.ts
|
|
397
397
|
function moduleInitStructure(options) {
|
|
398
|
-
const { name, file, range, effects } = options;
|
|
398
|
+
const { name, file, range, effects, calls } = options;
|
|
399
399
|
return {
|
|
400
400
|
identity: {
|
|
401
401
|
name,
|
|
@@ -422,7 +422,7 @@ function moduleInitStructure(options) {
|
|
|
422
422
|
emitEvent: null,
|
|
423
423
|
location: range
|
|
424
424
|
},
|
|
425
|
-
effects: [],
|
|
425
|
+
effects: calls ?? [],
|
|
426
426
|
extraEffects: effects,
|
|
427
427
|
location: range,
|
|
428
428
|
isDefault: true
|
|
@@ -1809,6 +1809,14 @@ function recognizersWithNoUnits(packs) {
|
|
|
1809
1809
|
detail: `${funnel.candidateFiles} gated files, and no pack in this run discovered a unit in them. ${funnel.pack} reads calls inside units another pack finds, so add the pack that finds this project's handlers (-f express, -f fastify, ...), or run suss init to work out which.`
|
|
1810
1810
|
}));
|
|
1811
1811
|
}
|
|
1812
|
+
function gatedPacksWithNoFiles(packs) {
|
|
1813
|
+
return packs.filter(
|
|
1814
|
+
(funnel) => funnel.gates.length > 0 && funnel.unresolvedGates.length === 0 && funnel.candidateFiles === 0
|
|
1815
|
+
).map((funnel) => ({
|
|
1816
|
+
label: funnel.pack,
|
|
1817
|
+
detail: `${funnel.gates.join(", ")} is installed and no file in this run imports it, directly or through a module of the project's own. Either this code does not use the library, or it reaches it some way the import gate does not follow.`
|
|
1818
|
+
}));
|
|
1819
|
+
}
|
|
1812
1820
|
function helpersThatMatchedNothing(packs) {
|
|
1813
1821
|
return packs.flatMap(
|
|
1814
1822
|
(funnel) => funnel.helpersUnmatched.map((helper) => ({
|
|
@@ -1899,6 +1907,12 @@ function evaluatePackHealth(report) {
|
|
|
1899
1907
|
audience: "run",
|
|
1900
1908
|
violations: funnelDrops(report.packs)
|
|
1901
1909
|
},
|
|
1910
|
+
{
|
|
1911
|
+
name: "every pack whose library is installed had files to read",
|
|
1912
|
+
code: "no-files",
|
|
1913
|
+
audience: "run",
|
|
1914
|
+
violations: gatedPacksWithNoFiles(report.packs)
|
|
1915
|
+
},
|
|
1902
1916
|
{
|
|
1903
1917
|
name: "every recognizer had units to look inside",
|
|
1904
1918
|
code: "no-units",
|
|
@@ -2093,6 +2107,22 @@ function unreadSentences(raw) {
|
|
|
2093
2107
|
...handedOver.map(unreadReasonOf).filter((reason) => reason !== null)
|
|
2094
2108
|
];
|
|
2095
2109
|
}
|
|
2110
|
+
function effectsOfBranch(branch) {
|
|
2111
|
+
const effects = [
|
|
2112
|
+
...branch.effects.map(effectToIR),
|
|
2113
|
+
...branch.extraEffects ?? []
|
|
2114
|
+
];
|
|
2115
|
+
return (0, import_behavioral_ir5.foldRepeatedEffects)(effects.map(withNormalizedCallee));
|
|
2116
|
+
}
|
|
2117
|
+
function withNormalizedCallee(effect) {
|
|
2118
|
+
if (effect.type !== "invocation" && effect.type !== "interaction") {
|
|
2119
|
+
return effect;
|
|
2120
|
+
}
|
|
2121
|
+
if (effect.callee === void 0) {
|
|
2122
|
+
return effect;
|
|
2123
|
+
}
|
|
2124
|
+
return { ...effect, callee: (0, import_behavioral_ir5.normalizeCalleeText)(effect.callee) };
|
|
2125
|
+
}
|
|
2096
2126
|
function assembleSummary(raw, options = DEFAULT_OPTIONS) {
|
|
2097
2127
|
const transitions = raw.branches.map((rawBranch) => {
|
|
2098
2128
|
const branch = branchWithCollapsedReadings(rawBranch);
|
|
@@ -2103,10 +2133,7 @@ function assembleSummary(raw, options = DEFAULT_OPTIONS) {
|
|
|
2103
2133
|
id: makeTransitionId(raw.identity.name, branch),
|
|
2104
2134
|
conditions,
|
|
2105
2135
|
output: terminalToOutput(branch.terminal),
|
|
2106
|
-
effects:
|
|
2107
|
-
...branch.effects.map(effectToIR),
|
|
2108
|
-
...branch.extraEffects ?? []
|
|
2109
|
-
],
|
|
2136
|
+
effects: effectsOfBranch(branch),
|
|
2110
2137
|
location: branch.location,
|
|
2111
2138
|
isDefault: branch.isDefault
|
|
2112
2139
|
};
|
|
@@ -2171,6 +2198,9 @@ function buildMetadata(raw) {
|
|
|
2171
2198
|
if (raw.wrappers !== void 0 && raw.wrappers.length > 0) {
|
|
2172
2199
|
metadata = (0, import_behavioral_ir5.withWrapperMetadata)(metadata, { applied: raw.wrappers });
|
|
2173
2200
|
}
|
|
2201
|
+
if (raw.requestSpelling !== void 0) {
|
|
2202
|
+
metadata = (0, import_behavioral_ir5.withRequestSpellingMetadata)(metadata, raw.requestSpelling);
|
|
2203
|
+
}
|
|
2174
2204
|
return Object.keys(metadata).length > 0 ? metadata : null;
|
|
2175
2205
|
}
|
|
2176
2206
|
function buildHttpMetadataValue(raw) {
|
package/dist/index.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Effect, MessageBusSemantics, DeployableUnit, CodeUnitKind, BehavioralSummary, Predicate, TypeShape, RenderNode, BoundaryBinding, WrapperReference, GraphqlDeclaredContract, ConfidenceInfo, Transition, Gap, Input, Output } from '@suss/behavioral-ir';
|
|
1
|
+
import { Effect, MessageBusSemantics, DeployableUnit, CodeUnitKind, RequestSpellingMetadata, BehavioralSummary, Predicate, TypeShape, RenderNode, BoundaryBinding, WrapperReference, GraphqlDeclaredContract, ConfidenceInfo, Transition, Gap, Input, Output } from '@suss/behavioral-ir';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -173,6 +173,15 @@ type DiscoveryMatch = {
|
|
|
173
173
|
* `axios.get(...)`.
|
|
174
174
|
*/
|
|
175
175
|
factoryMethods?: string[];
|
|
176
|
+
/**
|
|
177
|
+
* The property of the factory call's config object that every
|
|
178
|
+
* request through the instance is sent under, `baseURL` for axios.
|
|
179
|
+
* Both sides of a boundary have to read one route the same way,
|
|
180
|
+
* and a spec's `servers[0].url` already goes in front of the
|
|
181
|
+
* provider's paths, so a base written here goes in front of the
|
|
182
|
+
* consumer's.
|
|
183
|
+
*/
|
|
184
|
+
basePathOption?: string;
|
|
176
185
|
/**
|
|
177
186
|
* The import and every instance built from it can be called as a
|
|
178
187
|
* function, so `axios(config)` and `api(config)` are requests the
|
|
@@ -1174,6 +1183,18 @@ interface PatternPack {
|
|
|
1174
1183
|
terminals: TerminalPattern[];
|
|
1175
1184
|
contractReading?: ContractPattern;
|
|
1176
1185
|
inputMapping: InputMappingPattern;
|
|
1186
|
+
/**
|
|
1187
|
+
* For a REST pack, where in the handler each part of the request is
|
|
1188
|
+
* read, in the same words `inputMapping` gives the parameters: an
|
|
1189
|
+
* Express handler reads a header at `request.headers`, a Lambda
|
|
1190
|
+
* handler at `event.headers`. The adapter stamps this on every route
|
|
1191
|
+
* the pack recognizes, and the intent pass rewrites the route's reads
|
|
1192
|
+
* from it into the sections an author writes under `receives`.
|
|
1193
|
+
*
|
|
1194
|
+
* Leave it out on a pack whose handlers do not take a request, and
|
|
1195
|
+
* leave a section out when the framework has no path for it.
|
|
1196
|
+
*/
|
|
1197
|
+
requestSpelling?: RequestSpellingMetadata;
|
|
1177
1198
|
/**
|
|
1178
1199
|
* Transport (wire protocol) used in the `BoundaryBinding.transport`
|
|
1179
1200
|
* of discovered units. Every pack has to say what its transport is
|
|
@@ -1337,6 +1358,16 @@ interface PatternPack {
|
|
|
1337
1358
|
* available without importing anything).
|
|
1338
1359
|
*/
|
|
1339
1360
|
requiresImport?: string[];
|
|
1361
|
+
/**
|
|
1362
|
+
* Files this library's code generator writes beside the module it
|
|
1363
|
+
* generates, e.g. `["schema.prisma"]`. A project can point the
|
|
1364
|
+
* generator at a directory of its own, and then every consumer
|
|
1365
|
+
* imports the module by relative path and `requiresImport` matches
|
|
1366
|
+
* nothing. A directory containing one of these files counts as the
|
|
1367
|
+
* gated package, so those consumers reach the pack the way an
|
|
1368
|
+
* ordinary import would.
|
|
1369
|
+
*/
|
|
1370
|
+
generatedModuleMarkers?: string[];
|
|
1340
1371
|
/**
|
|
1341
1372
|
* Functions the project itself wrote in front of this library, read
|
|
1342
1373
|
* once across the whole project before any file is walked. What the
|
|
@@ -1974,12 +2005,12 @@ declare function stampModuleImports(summaries: BehavioralSummary[], importsOf: (
|
|
|
1974
2005
|
* and a service that reads its configuration there reads it there for
|
|
1975
2006
|
* good. Walking unit bodies alone never sees that read, so the read gets
|
|
1976
2007
|
* a unit of its own, one per file, named after the file, with no
|
|
1977
|
-
* boundary. Attributing it to each handler
|
|
1978
|
-
*
|
|
2008
|
+
* boundary. Attributing it to each handler would report one read as
|
|
2009
|
+
* several. The calls those statements make go on the same unit, so the
|
|
2010
|
+
* closure can reach the functions behind them.
|
|
1979
2011
|
*
|
|
1980
|
-
* The
|
|
1981
|
-
*
|
|
1982
|
-
* same way, so it lives here.
|
|
2012
|
+
* The one default branch has a `void` terminal, because module
|
|
2013
|
+
* initialization returns to nobody. Every adapter builds it the same way.
|
|
1983
2014
|
*/
|
|
1984
2015
|
|
|
1985
2016
|
interface ModuleInitOptions {
|
|
@@ -1991,6 +2022,8 @@ interface ModuleInitOptions {
|
|
|
1991
2022
|
end: number;
|
|
1992
2023
|
};
|
|
1993
2024
|
effects: Effect[];
|
|
2025
|
+
/** The calls the top-level statements make while the module loads. */
|
|
2026
|
+
calls?: RawEffect[];
|
|
1994
2027
|
}
|
|
1995
2028
|
declare function moduleInitStructure(options: ModuleInitOptions): RawCodeStructure;
|
|
1996
2029
|
|
|
@@ -3032,6 +3065,17 @@ interface ValueOps {
|
|
|
3032
3065
|
* there, so a query that hands over a table object can still be read.
|
|
3033
3066
|
*/
|
|
3034
3067
|
holes(): readonly (CallOps | null)[];
|
|
3068
|
+
/**
|
|
3069
|
+
* The same holes as values, in the same order, for a reader that
|
|
3070
|
+
* wants what the source settled a hole to rather than what call was
|
|
3071
|
+
* written there. A table kept in a module constant is the case: the
|
|
3072
|
+
* hole is a name, not a call, so `holes` gives null for it and this
|
|
3073
|
+
* gives the constant.
|
|
3074
|
+
*
|
|
3075
|
+
* An adapter that has not implemented this leaves it out, and a
|
|
3076
|
+
* reader then has only the calls.
|
|
3077
|
+
*/
|
|
3078
|
+
interpolated?(): readonly ValueOps[];
|
|
3035
3079
|
}
|
|
3036
3080
|
/** One entry of an object a call states. */
|
|
3037
3081
|
interface ValueEntry {
|
|
@@ -3405,6 +3449,8 @@ interface RawCodeStructure {
|
|
|
3405
3449
|
};
|
|
3406
3450
|
/** The wrappers registered around this unit: middleware, error handlers. */
|
|
3407
3451
|
wrappers?: WrapperReference[];
|
|
3452
|
+
/** Where a REST pack's handlers read each part of the request, from the pack. */
|
|
3453
|
+
requestSpelling?: RequestSpellingMetadata;
|
|
3408
3454
|
/** The extractor cannot derive this. An adapter that has the SDL and knows
|
|
3409
3455
|
* which field the resolver serves fills it in. */
|
|
3410
3456
|
graphqlDeclaredContract?: GraphqlDeclaredContract;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Effect, MessageBusSemantics, DeployableUnit, CodeUnitKind, BehavioralSummary, Predicate, TypeShape, RenderNode, BoundaryBinding, WrapperReference, GraphqlDeclaredContract, ConfidenceInfo, Transition, Gap, Input, Output } from '@suss/behavioral-ir';
|
|
1
|
+
import { Effect, MessageBusSemantics, DeployableUnit, CodeUnitKind, RequestSpellingMetadata, BehavioralSummary, Predicate, TypeShape, RenderNode, BoundaryBinding, WrapperReference, GraphqlDeclaredContract, ConfidenceInfo, Transition, Gap, Input, Output } from '@suss/behavioral-ir';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -173,6 +173,15 @@ type DiscoveryMatch = {
|
|
|
173
173
|
* `axios.get(...)`.
|
|
174
174
|
*/
|
|
175
175
|
factoryMethods?: string[];
|
|
176
|
+
/**
|
|
177
|
+
* The property of the factory call's config object that every
|
|
178
|
+
* request through the instance is sent under, `baseURL` for axios.
|
|
179
|
+
* Both sides of a boundary have to read one route the same way,
|
|
180
|
+
* and a spec's `servers[0].url` already goes in front of the
|
|
181
|
+
* provider's paths, so a base written here goes in front of the
|
|
182
|
+
* consumer's.
|
|
183
|
+
*/
|
|
184
|
+
basePathOption?: string;
|
|
176
185
|
/**
|
|
177
186
|
* The import and every instance built from it can be called as a
|
|
178
187
|
* function, so `axios(config)` and `api(config)` are requests the
|
|
@@ -1174,6 +1183,18 @@ interface PatternPack {
|
|
|
1174
1183
|
terminals: TerminalPattern[];
|
|
1175
1184
|
contractReading?: ContractPattern;
|
|
1176
1185
|
inputMapping: InputMappingPattern;
|
|
1186
|
+
/**
|
|
1187
|
+
* For a REST pack, where in the handler each part of the request is
|
|
1188
|
+
* read, in the same words `inputMapping` gives the parameters: an
|
|
1189
|
+
* Express handler reads a header at `request.headers`, a Lambda
|
|
1190
|
+
* handler at `event.headers`. The adapter stamps this on every route
|
|
1191
|
+
* the pack recognizes, and the intent pass rewrites the route's reads
|
|
1192
|
+
* from it into the sections an author writes under `receives`.
|
|
1193
|
+
*
|
|
1194
|
+
* Leave it out on a pack whose handlers do not take a request, and
|
|
1195
|
+
* leave a section out when the framework has no path for it.
|
|
1196
|
+
*/
|
|
1197
|
+
requestSpelling?: RequestSpellingMetadata;
|
|
1177
1198
|
/**
|
|
1178
1199
|
* Transport (wire protocol) used in the `BoundaryBinding.transport`
|
|
1179
1200
|
* of discovered units. Every pack has to say what its transport is
|
|
@@ -1337,6 +1358,16 @@ interface PatternPack {
|
|
|
1337
1358
|
* available without importing anything).
|
|
1338
1359
|
*/
|
|
1339
1360
|
requiresImport?: string[];
|
|
1361
|
+
/**
|
|
1362
|
+
* Files this library's code generator writes beside the module it
|
|
1363
|
+
* generates, e.g. `["schema.prisma"]`. A project can point the
|
|
1364
|
+
* generator at a directory of its own, and then every consumer
|
|
1365
|
+
* imports the module by relative path and `requiresImport` matches
|
|
1366
|
+
* nothing. A directory containing one of these files counts as the
|
|
1367
|
+
* gated package, so those consumers reach the pack the way an
|
|
1368
|
+
* ordinary import would.
|
|
1369
|
+
*/
|
|
1370
|
+
generatedModuleMarkers?: string[];
|
|
1340
1371
|
/**
|
|
1341
1372
|
* Functions the project itself wrote in front of this library, read
|
|
1342
1373
|
* once across the whole project before any file is walked. What the
|
|
@@ -1974,12 +2005,12 @@ declare function stampModuleImports(summaries: BehavioralSummary[], importsOf: (
|
|
|
1974
2005
|
* and a service that reads its configuration there reads it there for
|
|
1975
2006
|
* good. Walking unit bodies alone never sees that read, so the read gets
|
|
1976
2007
|
* a unit of its own, one per file, named after the file, with no
|
|
1977
|
-
* boundary. Attributing it to each handler
|
|
1978
|
-
*
|
|
2008
|
+
* boundary. Attributing it to each handler would report one read as
|
|
2009
|
+
* several. The calls those statements make go on the same unit, so the
|
|
2010
|
+
* closure can reach the functions behind them.
|
|
1979
2011
|
*
|
|
1980
|
-
* The
|
|
1981
|
-
*
|
|
1982
|
-
* same way, so it lives here.
|
|
2012
|
+
* The one default branch has a `void` terminal, because module
|
|
2013
|
+
* initialization returns to nobody. Every adapter builds it the same way.
|
|
1983
2014
|
*/
|
|
1984
2015
|
|
|
1985
2016
|
interface ModuleInitOptions {
|
|
@@ -1991,6 +2022,8 @@ interface ModuleInitOptions {
|
|
|
1991
2022
|
end: number;
|
|
1992
2023
|
};
|
|
1993
2024
|
effects: Effect[];
|
|
2025
|
+
/** The calls the top-level statements make while the module loads. */
|
|
2026
|
+
calls?: RawEffect[];
|
|
1994
2027
|
}
|
|
1995
2028
|
declare function moduleInitStructure(options: ModuleInitOptions): RawCodeStructure;
|
|
1996
2029
|
|
|
@@ -3032,6 +3065,17 @@ interface ValueOps {
|
|
|
3032
3065
|
* there, so a query that hands over a table object can still be read.
|
|
3033
3066
|
*/
|
|
3034
3067
|
holes(): readonly (CallOps | null)[];
|
|
3068
|
+
/**
|
|
3069
|
+
* The same holes as values, in the same order, for a reader that
|
|
3070
|
+
* wants what the source settled a hole to rather than what call was
|
|
3071
|
+
* written there. A table kept in a module constant is the case: the
|
|
3072
|
+
* hole is a name, not a call, so `holes` gives null for it and this
|
|
3073
|
+
* gives the constant.
|
|
3074
|
+
*
|
|
3075
|
+
* An adapter that has not implemented this leaves it out, and a
|
|
3076
|
+
* reader then has only the calls.
|
|
3077
|
+
*/
|
|
3078
|
+
interpolated?(): readonly ValueOps[];
|
|
3035
3079
|
}
|
|
3036
3080
|
/** One entry of an object a call states. */
|
|
3037
3081
|
interface ValueEntry {
|
|
@@ -3405,6 +3449,8 @@ interface RawCodeStructure {
|
|
|
3405
3449
|
};
|
|
3406
3450
|
/** The wrappers registered around this unit: middleware, error handlers. */
|
|
3407
3451
|
wrappers?: WrapperReference[];
|
|
3452
|
+
/** Where a REST pack's handlers read each part of the request, from the pack. */
|
|
3453
|
+
requestSpelling?: RequestSpellingMetadata;
|
|
3408
3454
|
/** The extractor cannot derive this. An adapter that has the SDL and knows
|
|
3409
3455
|
* which field the resolver serves fills it in. */
|
|
3410
3456
|
graphqlDeclaredContract?: GraphqlDeclaredContract;
|
package/dist/index.js
CHANGED
|
@@ -2,9 +2,12 @@
|
|
|
2
2
|
import { createHash as createHash3 } from "crypto";
|
|
3
3
|
import {
|
|
4
4
|
exchangesHttpResponses as exchangesHttpResponses2,
|
|
5
|
+
foldRepeatedEffects,
|
|
6
|
+
normalizeCalleeText,
|
|
5
7
|
withGraphqlMetadata,
|
|
6
8
|
withHttpMetadata,
|
|
7
9
|
withMountMetadata,
|
|
10
|
+
withRequestSpellingMetadata,
|
|
8
11
|
withSourceDocumentMetadata,
|
|
9
12
|
withWrapperMetadata as withWrapperMetadata2
|
|
10
13
|
} from "@suss/behavioral-ir";
|
|
@@ -319,7 +322,7 @@ function stampModuleImports(summaries, importsOf) {
|
|
|
319
322
|
|
|
320
323
|
// src/moduleInit.ts
|
|
321
324
|
function moduleInitStructure(options) {
|
|
322
|
-
const { name, file, range, effects } = options;
|
|
325
|
+
const { name, file, range, effects, calls } = options;
|
|
323
326
|
return {
|
|
324
327
|
identity: {
|
|
325
328
|
name,
|
|
@@ -346,7 +349,7 @@ function moduleInitStructure(options) {
|
|
|
346
349
|
emitEvent: null,
|
|
347
350
|
location: range
|
|
348
351
|
},
|
|
349
|
-
effects: [],
|
|
352
|
+
effects: calls ?? [],
|
|
350
353
|
extraEffects: effects,
|
|
351
354
|
location: range,
|
|
352
355
|
isDefault: true
|
|
@@ -1732,6 +1735,14 @@ function recognizersWithNoUnits(packs) {
|
|
|
1732
1735
|
detail: `${funnel.candidateFiles} gated files, and no pack in this run discovered a unit in them. ${funnel.pack} reads calls inside units another pack finds, so add the pack that finds this project's handlers (-f express, -f fastify, ...), or run suss init to work out which.`
|
|
1733
1736
|
}));
|
|
1734
1737
|
}
|
|
1738
|
+
function gatedPacksWithNoFiles(packs) {
|
|
1739
|
+
return packs.filter(
|
|
1740
|
+
(funnel) => funnel.gates.length > 0 && funnel.unresolvedGates.length === 0 && funnel.candidateFiles === 0
|
|
1741
|
+
).map((funnel) => ({
|
|
1742
|
+
label: funnel.pack,
|
|
1743
|
+
detail: `${funnel.gates.join(", ")} is installed and no file in this run imports it, directly or through a module of the project's own. Either this code does not use the library, or it reaches it some way the import gate does not follow.`
|
|
1744
|
+
}));
|
|
1745
|
+
}
|
|
1735
1746
|
function helpersThatMatchedNothing(packs) {
|
|
1736
1747
|
return packs.flatMap(
|
|
1737
1748
|
(funnel) => funnel.helpersUnmatched.map((helper) => ({
|
|
@@ -1822,6 +1833,12 @@ function evaluatePackHealth(report) {
|
|
|
1822
1833
|
audience: "run",
|
|
1823
1834
|
violations: funnelDrops(report.packs)
|
|
1824
1835
|
},
|
|
1836
|
+
{
|
|
1837
|
+
name: "every pack whose library is installed had files to read",
|
|
1838
|
+
code: "no-files",
|
|
1839
|
+
audience: "run",
|
|
1840
|
+
violations: gatedPacksWithNoFiles(report.packs)
|
|
1841
|
+
},
|
|
1825
1842
|
{
|
|
1826
1843
|
name: "every recognizer had units to look inside",
|
|
1827
1844
|
code: "no-units",
|
|
@@ -2016,6 +2033,22 @@ function unreadSentences(raw) {
|
|
|
2016
2033
|
...handedOver.map(unreadReasonOf).filter((reason) => reason !== null)
|
|
2017
2034
|
];
|
|
2018
2035
|
}
|
|
2036
|
+
function effectsOfBranch(branch) {
|
|
2037
|
+
const effects = [
|
|
2038
|
+
...branch.effects.map(effectToIR),
|
|
2039
|
+
...branch.extraEffects ?? []
|
|
2040
|
+
];
|
|
2041
|
+
return foldRepeatedEffects(effects.map(withNormalizedCallee));
|
|
2042
|
+
}
|
|
2043
|
+
function withNormalizedCallee(effect) {
|
|
2044
|
+
if (effect.type !== "invocation" && effect.type !== "interaction") {
|
|
2045
|
+
return effect;
|
|
2046
|
+
}
|
|
2047
|
+
if (effect.callee === void 0) {
|
|
2048
|
+
return effect;
|
|
2049
|
+
}
|
|
2050
|
+
return { ...effect, callee: normalizeCalleeText(effect.callee) };
|
|
2051
|
+
}
|
|
2019
2052
|
function assembleSummary(raw, options = DEFAULT_OPTIONS) {
|
|
2020
2053
|
const transitions = raw.branches.map((rawBranch) => {
|
|
2021
2054
|
const branch = branchWithCollapsedReadings(rawBranch);
|
|
@@ -2026,10 +2059,7 @@ function assembleSummary(raw, options = DEFAULT_OPTIONS) {
|
|
|
2026
2059
|
id: makeTransitionId(raw.identity.name, branch),
|
|
2027
2060
|
conditions,
|
|
2028
2061
|
output: terminalToOutput(branch.terminal),
|
|
2029
|
-
effects:
|
|
2030
|
-
...branch.effects.map(effectToIR),
|
|
2031
|
-
...branch.extraEffects ?? []
|
|
2032
|
-
],
|
|
2062
|
+
effects: effectsOfBranch(branch),
|
|
2033
2063
|
location: branch.location,
|
|
2034
2064
|
isDefault: branch.isDefault
|
|
2035
2065
|
};
|
|
@@ -2094,6 +2124,9 @@ function buildMetadata(raw) {
|
|
|
2094
2124
|
if (raw.wrappers !== void 0 && raw.wrappers.length > 0) {
|
|
2095
2125
|
metadata = withWrapperMetadata2(metadata, { applied: raw.wrappers });
|
|
2096
2126
|
}
|
|
2127
|
+
if (raw.requestSpelling !== void 0) {
|
|
2128
|
+
metadata = withRequestSpellingMetadata(metadata, raw.requestSpelling);
|
|
2129
|
+
}
|
|
2097
2130
|
return Object.keys(metadata).length > 0 ? metadata : null;
|
|
2098
2131
|
}
|
|
2099
2132
|
function buildHttpMetadataValue(raw) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@suss/extractor",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.33.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "The suss extraction pipeline, which turns what a language adapter read into the summaries the checker pairs across a boundary.",
|
|
6
6
|
"keywords": [
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
"typecheck": "tsc --noEmit"
|
|
47
47
|
},
|
|
48
48
|
"dependencies": {
|
|
49
|
-
"@suss/behavioral-ir": "0.
|
|
49
|
+
"@suss/behavioral-ir": "0.33.1",
|
|
50
50
|
"zod": "^4.0.0"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|