@suss/ir-core 0.33.0 → 0.34.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/README.md +30 -30
- package/dist/{chunk-N564FH5U.js → chunk-WOXA5GBL.js} +251 -208
- package/dist/index.cjs +335 -248
- package/dist/index.d.cts +399 -355
- package/dist/index.d.ts +399 -355
- package/dist/index.js +68 -26
- package/dist/{schemas-CIns0fqF.d.cts → schemas-CghZNwSE.d.cts} +88 -81
- package/dist/{schemas-CIns0fqF.d.ts → schemas-CghZNwSE.d.ts} +88 -81
- package/dist/schemas.cjs +248 -208
- package/dist/schemas.d.cts +1 -1
- package/dist/schemas.d.ts +1 -1
- package/dist/schemas.js +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -31,6 +31,7 @@ __export(index_exports, {
|
|
|
31
31
|
FunctionCallSemanticsSchema: () => FunctionCallSemanticsSchema,
|
|
32
32
|
GraphqlOperationSemanticsSchema: () => GraphqlOperationSemanticsSchema,
|
|
33
33
|
GraphqlResolverSemanticsSchema: () => GraphqlResolverSemanticsSchema,
|
|
34
|
+
IoSemanticsSchema: () => IoSemanticsSchema,
|
|
34
35
|
MessageBusSemanticsSchema: () => MessageBusSemanticsSchema,
|
|
35
36
|
MetricSemanticsSchema: () => MetricSemanticsSchema,
|
|
36
37
|
NOTHING_DEPLOYED: () => NOTHING_DEPLOYED,
|
|
@@ -43,6 +44,7 @@ __export(index_exports, {
|
|
|
43
44
|
StorageSemanticsSchema: () => StorageSemanticsSchema,
|
|
44
45
|
SuppressionFileSchema: () => SuppressionFileSchema,
|
|
45
46
|
SuppressionRuleSchema: () => SuppressionRuleSchema,
|
|
47
|
+
TEST_TITLE_SEPARATOR: () => TEST_TITLE_SEPARATOR,
|
|
46
48
|
TypeShapeSchema: () => TypeShapeSchema,
|
|
47
49
|
UnitInvocationSemanticsSchema: () => UnitInvocationSemanticsSchema,
|
|
48
50
|
applySuppressionsToFindings: () => applySuppressionsToFindings,
|
|
@@ -76,12 +78,17 @@ __export(index_exports, {
|
|
|
76
78
|
groundBinding: () => groundBinding,
|
|
77
79
|
groundedPairingKey: () => groundedPairingKey,
|
|
78
80
|
hasNameHole: () => hasNameHole,
|
|
81
|
+
ioBinding: () => ioBinding,
|
|
82
|
+
ioIdentityKey: () => ioIdentityKey,
|
|
79
83
|
isGraphqlOperationBinding: () => isGraphqlOperationBinding,
|
|
84
|
+
isModuleName: () => isModuleName,
|
|
85
|
+
labelWithDetail: () => labelWithDetail,
|
|
80
86
|
leavesTheProcess: () => leavesTheProcess,
|
|
81
87
|
messageBusBinding: () => messageBusBinding,
|
|
82
88
|
methodsAgree: () => methodsAgree,
|
|
83
89
|
metricBinding: () => metricBinding,
|
|
84
90
|
metricIdentityKey: () => metricIdentityKey,
|
|
91
|
+
moduleExportBinding: () => moduleExportBinding,
|
|
85
92
|
namePatternFromSub: () => namePatternFromSub,
|
|
86
93
|
namePatternKey: () => namePatternKey,
|
|
87
94
|
nameReference: () => nameReference,
|
|
@@ -121,6 +128,7 @@ __export(index_exports, {
|
|
|
121
128
|
storageContainerLabel: () => storageContainerLabel,
|
|
122
129
|
storageLabel: () => storageLabel,
|
|
123
130
|
storageSystemLabel: () => storageSystemLabel,
|
|
131
|
+
testUnitName: () => testUnitName,
|
|
124
132
|
typeDefinitionKey: () => typeDefinitionKey,
|
|
125
133
|
unitIdentityKey: () => unitIdentityKey,
|
|
126
134
|
unitInvocationBinding: () => unitInvocationBinding,
|
|
@@ -156,15 +164,15 @@ var graphqlOperationSemantics = defineBoundarySemantics({
|
|
|
156
164
|
behavior: {
|
|
157
165
|
/**
|
|
158
166
|
* An operation gets a data-and-errors document back, which the
|
|
159
|
-
* GraphQL contract checker reads. Status codes
|
|
167
|
+
* GraphQL contract checker reads. Status codes do not apply.
|
|
160
168
|
*/
|
|
161
169
|
exchangesHttpResponses: false,
|
|
162
170
|
leavesTheProcess: true,
|
|
163
171
|
reportsUnpairedItself: false,
|
|
164
172
|
identityKey: () => null,
|
|
165
|
-
/**
|
|
173
|
+
/** No key on purpose. The dedicated pass pairs an operation by its document. */
|
|
166
174
|
canPair: () => true,
|
|
167
|
-
/**
|
|
175
|
+
/** `query GetUser`. Only for display, since the contract checker does the pairing. */
|
|
168
176
|
displayLabel(semantics) {
|
|
169
177
|
return `${semantics.operationType} ${semantics.operationName ?? "<anonymous>"}`;
|
|
170
178
|
}
|
|
@@ -187,22 +195,26 @@ function unitIdentityKey(deploymentTarget, instanceName) {
|
|
|
187
195
|
function metricIdentityKey(metricSystem, metricType) {
|
|
188
196
|
return `metric:${metricSystem} ${metricType}`;
|
|
189
197
|
}
|
|
198
|
+
function ioIdentityKey(target) {
|
|
199
|
+
return `io:${target}`;
|
|
200
|
+
}
|
|
190
201
|
|
|
191
202
|
// src/schemas.ts
|
|
192
|
-
var
|
|
203
|
+
var import_zod13 = require("zod");
|
|
193
204
|
|
|
194
205
|
// src/semantics/registry.ts
|
|
195
|
-
var
|
|
206
|
+
var import_zod12 = require("zod");
|
|
196
207
|
|
|
197
208
|
// src/semantics/functionCall.ts
|
|
198
209
|
var import_zod2 = require("zod");
|
|
199
210
|
var FunctionCallSemanticsSchema = import_zod2.z.object({
|
|
200
211
|
name: import_zod2.z.literal("function-call"),
|
|
201
212
|
/**
|
|
202
|
-
*
|
|
203
|
-
*
|
|
204
|
-
* module path
|
|
205
|
-
*
|
|
213
|
+
* Where the function lives inside this repository. It is either the
|
|
214
|
+
* name of a module the project lists in `suss.json`, such as
|
|
215
|
+
* `"billing"`, or a module path, such as the file a server action is
|
|
216
|
+
* written in. A name has no separator in it and a path always does.
|
|
217
|
+
* Packs that don't do cross-module pairing can leave it unset.
|
|
206
218
|
*/
|
|
207
219
|
module: import_zod2.z.string().optional(),
|
|
208
220
|
/** Named export within the module, when applicable. */
|
|
@@ -227,35 +239,38 @@ var FunctionCallSemanticsSchema = import_zod2.z.object({
|
|
|
227
239
|
*/
|
|
228
240
|
exportPath: import_zod2.z.array(import_zod2.z.string()).optional()
|
|
229
241
|
});
|
|
242
|
+
function isModuleName(module2) {
|
|
243
|
+
return !module2.includes("/") && !module2.includes("\\");
|
|
244
|
+
}
|
|
230
245
|
var functionCallSemantics = defineBoundarySemantics({
|
|
231
246
|
name: "function-call",
|
|
232
247
|
schema: FunctionCallSemanticsSchema,
|
|
233
|
-
// A call
|
|
234
|
-
//
|
|
248
|
+
// A call inside the process does not produce a span, and the
|
|
249
|
+
// conventions have no attributes for it.
|
|
235
250
|
semconv: {},
|
|
236
251
|
behavior: {
|
|
237
|
-
/** A call returns a value,
|
|
252
|
+
/** A call returns a value, with no status. */
|
|
238
253
|
exchangesHttpResponses: false,
|
|
239
254
|
leavesTheProcess: false,
|
|
240
255
|
reportsUnpairedItself: false,
|
|
241
256
|
/**
|
|
242
|
-
* In-repo units
|
|
243
|
-
*
|
|
244
|
-
*
|
|
257
|
+
* In-repo units such as components have no key on purpose. They
|
|
258
|
+
* pair through call edges instead of the keyed pass, so a missing
|
|
259
|
+
* key does not make them unreachable.
|
|
245
260
|
*/
|
|
246
261
|
canPair: () => true,
|
|
247
|
-
/**
|
|
248
|
-
* `"fn:<package>::<exportPath>"` when both are set, and
|
|
249
|
-
* `"fn:<module>::<exportName>"` for an in-repo unit that states its
|
|
250
|
-
* module, the way a server action does. Components and bare
|
|
251
|
-
* handlers state neither and have no key at all.
|
|
252
|
-
*/
|
|
253
262
|
rewritePaths(semantics, rewrite) {
|
|
254
|
-
if (semantics.module === void 0) {
|
|
263
|
+
if (semantics.module === void 0 || isModuleName(semantics.module)) {
|
|
255
264
|
return semantics;
|
|
256
265
|
}
|
|
257
266
|
return { ...semantics, module: rewrite(semantics.module) };
|
|
258
267
|
},
|
|
268
|
+
/**
|
|
269
|
+
* `"fn:<package>::<exportPath>"` when both are set, and
|
|
270
|
+
* `"fn:<module>::<exportName>"` for an in-repo unit that gives its
|
|
271
|
+
* module, as a server action does. Components and plain handlers
|
|
272
|
+
* give neither and have no key.
|
|
273
|
+
*/
|
|
259
274
|
identityKey(semantics) {
|
|
260
275
|
if (semantics.package !== void 0 && semantics.exportPath !== void 0 && semantics.exportPath.length > 0) {
|
|
261
276
|
return fnIdentityKey(semantics.package, semantics.exportPath);
|
|
@@ -284,14 +299,14 @@ var GraphqlResolverSemanticsSchema = import_zod3.z.object({
|
|
|
284
299
|
var graphqlResolverSemantics = defineBoundarySemantics({
|
|
285
300
|
name: "graphql-resolver",
|
|
286
301
|
schema: GraphqlResolverSemanticsSchema,
|
|
287
|
-
// The conventions
|
|
288
|
-
// resolver the server ran for one field of it.
|
|
302
|
+
// The conventions describe the operation a client sent. They have no
|
|
303
|
+
// attribute for the resolver the server ran for one field of it.
|
|
289
304
|
semconv: {},
|
|
290
305
|
behavior: {
|
|
291
|
-
/** A resolver returns a field value,
|
|
306
|
+
/** A resolver returns a field value, with no status. */
|
|
292
307
|
exchangesHttpResponses: false,
|
|
293
|
-
// A
|
|
294
|
-
// server calls
|
|
308
|
+
// A resolver runs because a client outside the process sent a query,
|
|
309
|
+
// even though the server calls it in its own process.
|
|
295
310
|
leavesTheProcess: true,
|
|
296
311
|
reportsUnpairedItself: false,
|
|
297
312
|
/**
|
|
@@ -308,8 +323,32 @@ var graphqlResolverSemantics = defineBoundarySemantics({
|
|
|
308
323
|
}
|
|
309
324
|
});
|
|
310
325
|
|
|
311
|
-
// src/semantics/
|
|
326
|
+
// src/semantics/io.ts
|
|
312
327
|
var import_zod4 = require("zod");
|
|
328
|
+
var IoSemanticsSchema = import_zod4.z.object({
|
|
329
|
+
name: import_zod4.z.literal("io"),
|
|
330
|
+
/** The stream, such as `stdout` or `stderr`. Null when the source does not say which. */
|
|
331
|
+
target: import_zod4.z.string().nullable()
|
|
332
|
+
});
|
|
333
|
+
var ioSemantics = defineBoundarySemantics({
|
|
334
|
+
name: "io",
|
|
335
|
+
schema: IoSemanticsSchema,
|
|
336
|
+
// The semantic conventions have no attribute for a process's own streams.
|
|
337
|
+
semconv: {},
|
|
338
|
+
behavior: {
|
|
339
|
+
exchangesHttpResponses: false,
|
|
340
|
+
leavesTheProcess: true,
|
|
341
|
+
reportsUnpairedItself: false,
|
|
342
|
+
identityKey(semantics) {
|
|
343
|
+
return semantics.target === null ? null : ioIdentityKey(semantics.target);
|
|
344
|
+
},
|
|
345
|
+
// Nothing declares the reading side, so a write has nothing to meet.
|
|
346
|
+
canPair: () => false
|
|
347
|
+
}
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
// src/semantics/messageBus.ts
|
|
351
|
+
var import_zod5 = require("zod");
|
|
313
352
|
|
|
314
353
|
// src/channel.ts
|
|
315
354
|
function parseChannel(channel) {
|
|
@@ -335,12 +374,11 @@ function channelsPair(a, b) {
|
|
|
335
374
|
}
|
|
336
375
|
|
|
337
376
|
// src/semantics/messageBus.ts
|
|
338
|
-
var MessageBusSemanticsSchema =
|
|
339
|
-
name:
|
|
340
|
-
messageBus:
|
|
341
|
-
// The conventions
|
|
342
|
-
// underscore and one with a dot
|
|
343
|
-
// not a typo.
|
|
377
|
+
var MessageBusSemanticsSchema = import_zod5.z.object({
|
|
378
|
+
name: import_zod5.z.literal("message-bus"),
|
|
379
|
+
messageBus: import_zod5.z.enum([
|
|
380
|
+
// The conventions write these two AWS buses differently, one with an
|
|
381
|
+
// underscore and one with a dot. Both are as the conventions give them.
|
|
344
382
|
"aws_sqs",
|
|
345
383
|
"aws.sns",
|
|
346
384
|
"s3",
|
|
@@ -359,12 +397,13 @@ var MessageBusSemanticsSchema = import_zod4.z.object({
|
|
|
359
397
|
"cloudflare-tail"
|
|
360
398
|
]),
|
|
361
399
|
/**
|
|
362
|
-
*
|
|
363
|
-
* a subject pattern, or `bus#detailType`. Null when this
|
|
364
|
-
* not say which channel, as with a send whose queue the
|
|
365
|
-
*
|
|
400
|
+
* A stable channel identifier: a CloudFormation logical id, a queue or
|
|
401
|
+
* topic name, a subject pattern, or `bus#detailType`. Null when this
|
|
402
|
+
* source does not say which channel, as with a send whose queue the
|
|
403
|
+
* code picks at run time, or a receive whose queue is set in the
|
|
404
|
+
* event-source mapping.
|
|
366
405
|
*/
|
|
367
|
-
channel:
|
|
406
|
+
channel: import_zod5.z.string().min(1).nullable()
|
|
368
407
|
});
|
|
369
408
|
var messageBusSemantics = defineBoundarySemantics({
|
|
370
409
|
name: "message-bus",
|
|
@@ -378,25 +417,26 @@ var messageBusSemantics = defineBoundarySemantics({
|
|
|
378
417
|
exchangesHttpResponses: false,
|
|
379
418
|
leavesTheProcess: true,
|
|
380
419
|
/**
|
|
381
|
-
* `checkMessageBus`
|
|
382
|
-
*
|
|
420
|
+
* `checkMessageBus` reports every channel, unused ones included, so
|
|
421
|
+
* the generic unmatched list leaves them out.
|
|
383
422
|
*/
|
|
384
423
|
reportsUnpairedItself: true,
|
|
385
424
|
/**
|
|
386
|
-
* A channel
|
|
387
|
-
*
|
|
388
|
-
* channel
|
|
425
|
+
* A channel that is null here can still pair. The dedicated pass
|
|
426
|
+
* follows environment variable chains before comparing, so a
|
|
427
|
+
* consumer whose channel is set at run time meets the template that
|
|
428
|
+
* declares it.
|
|
389
429
|
*/
|
|
390
430
|
canPair: () => true,
|
|
391
431
|
/**
|
|
392
432
|
* `"bus:<messageBus> <subject>"`, or null when the channel is null
|
|
393
433
|
* or its subject is empty.
|
|
394
434
|
*
|
|
395
|
-
* The key has the subject
|
|
396
|
-
*
|
|
435
|
+
* The key has the subject and leaves out the bus, so a template
|
|
436
|
+
* writing `default#order.placed` and a handler writing
|
|
397
437
|
* `order.placed` land in one bucket, where `sidesAgree` compares the
|
|
398
|
-
* buses.
|
|
399
|
-
*
|
|
438
|
+
* buses. Keying on the bus would separate a side that cannot know
|
|
439
|
+
* its bus from the side that can.
|
|
400
440
|
*
|
|
401
441
|
* The bus technology stays in, because a queue and an event router
|
|
402
442
|
* are different destinations even with the same subject. Case stays
|
|
@@ -419,9 +459,9 @@ var messageBusSemantics = defineBoundarySemantics({
|
|
|
419
459
|
return channelsPair(a.channel, b.channel);
|
|
420
460
|
},
|
|
421
461
|
/**
|
|
422
|
-
* The whole channel, bus included,
|
|
423
|
-
*
|
|
424
|
-
*
|
|
462
|
+
* The whole channel, bus included, where the identity key has only
|
|
463
|
+
* the subject. A reader looking at unmatched channels needs to see
|
|
464
|
+
* which bus each one was on.
|
|
425
465
|
*/
|
|
426
466
|
displayLabel(semantics) {
|
|
427
467
|
if (semantics.channel === null) {
|
|
@@ -433,25 +473,25 @@ var messageBusSemantics = defineBoundarySemantics({
|
|
|
433
473
|
});
|
|
434
474
|
|
|
435
475
|
// src/semantics/metric.ts
|
|
436
|
-
var
|
|
437
|
-
var MetricSemanticsSchema =
|
|
438
|
-
name:
|
|
439
|
-
/**
|
|
440
|
-
metricSystem:
|
|
476
|
+
var import_zod6 = require("zod");
|
|
477
|
+
var MetricSemanticsSchema = import_zod6.z.object({
|
|
478
|
+
name: import_zod6.z.literal("metric"),
|
|
479
|
+
/** The system the series is stored in, such as `cloud-monitoring` or `cloudwatch`. */
|
|
480
|
+
metricSystem: import_zod6.z.string(),
|
|
441
481
|
/**
|
|
442
|
-
* The type string the system
|
|
443
|
-
* both sides
|
|
444
|
-
*
|
|
445
|
-
*
|
|
446
|
-
*
|
|
482
|
+
* The type string the system uses for the metric, written the same
|
|
483
|
+
* way on both sides. Null when the reader could not work the string
|
|
484
|
+
* out, as with a query it could not parse. A null type pairs with
|
|
485
|
+
* nothing, so it cannot pair with an unrelated metric that happens to
|
|
486
|
+
* share its source text.
|
|
447
487
|
*/
|
|
448
|
-
metricType:
|
|
488
|
+
metricType: import_zod6.z.string().nullable()
|
|
449
489
|
});
|
|
450
490
|
var metricSemantics = defineBoundarySemantics({
|
|
451
491
|
name: "metric",
|
|
452
492
|
schema: MetricSemanticsSchema,
|
|
453
|
-
// OpenTelemetry
|
|
454
|
-
// attribute for the system
|
|
493
|
+
// OpenTelemetry identifies a metric by its instrument name. It has no
|
|
494
|
+
// attribute for the metric's system or its type string.
|
|
455
495
|
semconv: {},
|
|
456
496
|
behavior: {
|
|
457
497
|
exchangesHttpResponses: false,
|
|
@@ -467,7 +507,7 @@ var metricSemantics = defineBoundarySemantics({
|
|
|
467
507
|
});
|
|
468
508
|
|
|
469
509
|
// src/semantics/rest.ts
|
|
470
|
-
var
|
|
510
|
+
var import_zod7 = require("zod");
|
|
471
511
|
|
|
472
512
|
// src/dispatch.ts
|
|
473
513
|
function dispatchByType(table, value) {
|
|
@@ -814,23 +854,23 @@ function compareRanks(a, b) {
|
|
|
814
854
|
}
|
|
815
855
|
|
|
816
856
|
// src/semantics/rest.ts
|
|
817
|
-
var RestSemanticsSchema =
|
|
818
|
-
name:
|
|
857
|
+
var RestSemanticsSchema = import_zod7.z.object({
|
|
858
|
+
name: import_zod7.z.literal("rest"),
|
|
819
859
|
/**
|
|
820
860
|
* Uppercase HTTP method ("GET", "POST", …), `"*"` for a handler that
|
|
821
861
|
* responds to every method, or null when this source does not say
|
|
822
862
|
* which method.
|
|
823
863
|
*/
|
|
824
|
-
method:
|
|
864
|
+
method: import_zod7.z.string().min(1).nullable(),
|
|
825
865
|
/** Normalized route path ("/users/{id}"), or null when this source does not give one. */
|
|
826
|
-
path:
|
|
866
|
+
path: import_zod7.z.string().min(1).nullable(),
|
|
827
867
|
/**
|
|
828
|
-
* Status codes the producing source explicitly
|
|
829
|
-
* responses
|
|
830
|
-
*
|
|
831
|
-
* metadata. Absent
|
|
868
|
+
* Status codes the producing source declared explicitly, such as
|
|
869
|
+
* OpenAPI responses or CloudFormation MethodResponses. They are kept
|
|
870
|
+
* here so the pairing layer can see them without unwrapping any
|
|
871
|
+
* metadata. Absent or empty for an inferred source.
|
|
832
872
|
*/
|
|
833
|
-
declaredResponses:
|
|
873
|
+
declaredResponses: import_zod7.z.array(import_zod7.z.number()).optional()
|
|
834
874
|
});
|
|
835
875
|
var OPENING_HOLE = /^\{([^{}]+)\}(.*)$/;
|
|
836
876
|
function baseUrlReference(semantics) {
|
|
@@ -887,16 +927,15 @@ var restSemantics = defineBoundarySemantics({
|
|
|
887
927
|
return `${semantics.method.toUpperCase()} ${normalizePath(semantics.path)}`;
|
|
888
928
|
},
|
|
889
929
|
/**
|
|
890
|
-
* The bucket has only the path
|
|
891
|
-
*
|
|
892
|
-
*
|
|
893
|
-
* sees and a suppression targets ("GET /users", "* /users")
|
|
894
|
-
* this key groups what a reader still tells apart.
|
|
930
|
+
* The bucket has only the path, so a `"*"` route lands with the
|
|
931
|
+
* consumers that each give a method, and `methodsAgree` compares the
|
|
932
|
+
* methods inside the bucket. The identity key is still what a reader
|
|
933
|
+
* sees and what a suppression targets ("GET /users", "* /users").
|
|
895
934
|
*
|
|
896
|
-
*
|
|
897
|
-
* `{userId}` where the Express route that serves it
|
|
898
|
-
* both match the same requests
|
|
899
|
-
* boundaries that never
|
|
935
|
+
* Parameter names are dropped too. A hand-written spec writes
|
|
936
|
+
* `{userId}` where the Express route that serves it writes `:id`,
|
|
937
|
+
* and both match the same requests. Pairing on the name would leave
|
|
938
|
+
* two boundaries that never meet.
|
|
900
939
|
*/
|
|
901
940
|
pairingKey(semantics) {
|
|
902
941
|
if (semantics.method === null || semantics.path === null) {
|
|
@@ -917,9 +956,9 @@ var restSemantics = defineBoundarySemantics({
|
|
|
917
956
|
return semantics.path === null ? [] : pathSpecificity(normalizePath(semantics.path));
|
|
918
957
|
},
|
|
919
958
|
/**
|
|
920
|
-
*
|
|
921
|
-
*
|
|
922
|
-
*
|
|
959
|
+
* The identity key, with a missing half still readable: `ANY` when
|
|
960
|
+
* the source gave no method, and `?` when it gave no path. Null when
|
|
961
|
+
* both are missing, since then there is nothing to show.
|
|
923
962
|
*/
|
|
924
963
|
displayLabel(semantics) {
|
|
925
964
|
if (semantics.method === null && semantics.path === null) {
|
|
@@ -930,11 +969,11 @@ var restSemantics = defineBoundarySemantics({
|
|
|
930
969
|
return `${method} ${path}`;
|
|
931
970
|
},
|
|
932
971
|
/**
|
|
933
|
-
*
|
|
934
|
-
*
|
|
935
|
-
*
|
|
936
|
-
*
|
|
937
|
-
*
|
|
972
|
+
* With both halves present, the method goes through `methodsAgree`
|
|
973
|
+
* (so a `"*"` route matches every method) and the path through
|
|
974
|
+
* `routePathAdmits`. A route missing either half might still handle
|
|
975
|
+
* the request, and this declaration cannot settle that, so the
|
|
976
|
+
* result is `"unknown"`.
|
|
938
977
|
*/
|
|
939
978
|
servesRequest(semantics, method, path) {
|
|
940
979
|
if (semantics.method === null || semantics.path === null) {
|
|
@@ -947,8 +986,8 @@ var restSemantics = defineBoundarySemantics({
|
|
|
947
986
|
},
|
|
948
987
|
/**
|
|
949
988
|
* A route the registration pattern admits is inside it. A route
|
|
950
|
-
*
|
|
951
|
-
*
|
|
989
|
+
* without a path counts as outside, because nothing shows that the
|
|
990
|
+
* pattern covers it.
|
|
952
991
|
*/
|
|
953
992
|
withinScope(semantics, scope) {
|
|
954
993
|
return semantics.path !== null && routePathAdmits(scope, semantics.path);
|
|
@@ -957,16 +996,12 @@ var restSemantics = defineBoundarySemantics({
|
|
|
957
996
|
* A call whose base URL the deployment fills in, resolved to the
|
|
958
997
|
* path it reaches.
|
|
959
998
|
*
|
|
960
|
-
* The source cannot settle this on its own,
|
|
961
|
-
*
|
|
962
|
-
*
|
|
963
|
-
*
|
|
964
|
-
*
|
|
965
|
-
*
|
|
966
|
-
*
|
|
967
|
-
* Only a hole at the front is a base URL. A hole further along is a
|
|
968
|
-
* route parameter, and `/orders/{id}` means every id rather than a
|
|
969
|
-
* variable somebody set.
|
|
999
|
+
* The source cannot settle this on its own, so the adapter leaves
|
|
1000
|
+
* the hole in. `API_BASE` could be `http://backend.internal`, and
|
|
1001
|
+
* then the path is `/orders`. It could equally be `/api/v2`, and
|
|
1002
|
+
* then the path is `/api/v2/orders`. Filling in the deployed value
|
|
1003
|
+
* and reading the path back out gets the right one either way.
|
|
1004
|
+
* `baseUrlReference` finds the hole that is the base URL.
|
|
970
1005
|
*/
|
|
971
1006
|
groundName(semantics, deployment) {
|
|
972
1007
|
const reference = baseUrlReference(semantics);
|
|
@@ -983,7 +1018,7 @@ var restSemantics = defineBoundarySemantics({
|
|
|
983
1018
|
},
|
|
984
1019
|
nameReference: baseUrlReference,
|
|
985
1020
|
ruleBoundary: {
|
|
986
|
-
// "METHOD /path": one
|
|
1021
|
+
// "METHOD /path": one token, a space, then an absolute path.
|
|
987
1022
|
claims(raw) {
|
|
988
1023
|
return /^\S+ +\//.test(raw.trim());
|
|
989
1024
|
},
|
|
@@ -998,12 +1033,12 @@ var restSemantics = defineBoundarySemantics({
|
|
|
998
1033
|
});
|
|
999
1034
|
|
|
1000
1035
|
// src/semantics/runtimeConfig.ts
|
|
1001
|
-
var
|
|
1036
|
+
var import_zod9 = require("zod");
|
|
1002
1037
|
|
|
1003
1038
|
// src/deployableUnit.ts
|
|
1004
|
-
var
|
|
1005
|
-
var DeployableUnitSchema =
|
|
1006
|
-
deploymentTarget:
|
|
1039
|
+
var import_zod8 = require("zod");
|
|
1040
|
+
var DeployableUnitSchema = import_zod8.z.object({
|
|
1041
|
+
deploymentTarget: import_zod8.z.enum([
|
|
1007
1042
|
"lambda",
|
|
1008
1043
|
"ecs-task",
|
|
1009
1044
|
"container",
|
|
@@ -1012,7 +1047,7 @@ var DeployableUnitSchema = import_zod7.z.object({
|
|
|
1012
1047
|
]),
|
|
1013
1048
|
// An empty name would agree with every other empty name, so a unit
|
|
1014
1049
|
// with no name has to leave the field off instead.
|
|
1015
|
-
instanceName:
|
|
1050
|
+
instanceName: import_zod8.z.string().min(1)
|
|
1016
1051
|
});
|
|
1017
1052
|
function ecsContainerInstanceName(taskDefinitionLogicalId, containerName) {
|
|
1018
1053
|
return `${taskDefinitionLogicalId}/${containerName}`;
|
|
@@ -1023,14 +1058,14 @@ var RuntimeConfigSemanticsSchema = DeployableUnitSchema.partial({
|
|
|
1023
1058
|
deploymentTarget: true,
|
|
1024
1059
|
instanceName: true
|
|
1025
1060
|
}).extend({
|
|
1026
|
-
name:
|
|
1061
|
+
name: import_zod9.z.literal("runtime-config")
|
|
1027
1062
|
});
|
|
1028
1063
|
var runtimeConfigSemantics = defineBoundarySemantics({
|
|
1029
1064
|
name: "runtime-config",
|
|
1030
1065
|
schema: RuntimeConfigSemanticsSchema,
|
|
1031
|
-
// service.name and cloud.resource_id
|
|
1032
|
-
// instanceName is the
|
|
1033
|
-
//
|
|
1066
|
+
// service.name and cloud.resource_id identify the same deployable, but
|
|
1067
|
+
// instanceName is the template's logical id, a different string from
|
|
1068
|
+
// both.
|
|
1034
1069
|
semconv: {},
|
|
1035
1070
|
behavior: {
|
|
1036
1071
|
/** A process reads its config at startup, and nothing replies. */
|
|
@@ -1039,46 +1074,53 @@ var runtimeConfigSemantics = defineBoundarySemantics({
|
|
|
1039
1074
|
// comes from outside the code.
|
|
1040
1075
|
leavesTheProcess: true,
|
|
1041
1076
|
reportsUnpairedItself: false,
|
|
1042
|
-
identityKey: () => null
|
|
1077
|
+
identityKey: () => null,
|
|
1078
|
+
// A reader sees which deployable's environment this is. Code that
|
|
1079
|
+
// reads a variable does not say which deployable runs it, so a read
|
|
1080
|
+
// has no name.
|
|
1081
|
+
displayLabel(semantics) {
|
|
1082
|
+
const instance = semantics.instanceName;
|
|
1083
|
+
return instance === void 0 ? null : `runtime-config:${instance}`;
|
|
1084
|
+
}
|
|
1043
1085
|
}
|
|
1044
1086
|
});
|
|
1045
1087
|
|
|
1046
1088
|
// src/semantics/storage.ts
|
|
1047
|
-
var
|
|
1048
|
-
var StorageSemanticsSchema =
|
|
1049
|
-
name:
|
|
1089
|
+
var import_zod10 = require("zod");
|
|
1090
|
+
var StorageSemanticsSchema = import_zod10.z.object({
|
|
1091
|
+
name: import_zod10.z.literal("storage"),
|
|
1050
1092
|
/**
|
|
1051
|
-
*
|
|
1052
|
-
*
|
|
1053
|
-
*
|
|
1054
|
-
* containers can share a name,
|
|
1055
|
-
*
|
|
1056
|
-
*
|
|
1093
|
+
* The storage system: an OpenTelemetry value such as `postgresql` or
|
|
1094
|
+
* `aws.dynamodb`, or suss's own word for one the conventions do not
|
|
1095
|
+
* cover, such as `s3`. Null when the reader could not work out which
|
|
1096
|
+
* system the source uses. Two products' containers can share a name,
|
|
1097
|
+
* and this field keeps them apart. The pairing pass decides how to
|
|
1098
|
+
* treat a null.
|
|
1057
1099
|
*/
|
|
1058
|
-
storageSystem:
|
|
1100
|
+
storageSystem: import_zod10.z.string().nullable(),
|
|
1059
1101
|
/**
|
|
1060
1102
|
* The ORM, schema, or deployment scope. A single-database setup uses
|
|
1061
1103
|
* `"default"`, and a monorepo with several schemas gives each one its
|
|
1062
1104
|
* own value.
|
|
1063
1105
|
*/
|
|
1064
|
-
scope:
|
|
1106
|
+
scope: import_zod10.z.string(),
|
|
1065
1107
|
/**
|
|
1066
|
-
* The table, bucket, collection
|
|
1067
|
-
*
|
|
1068
|
-
*
|
|
1069
|
-
*
|
|
1070
|
-
*
|
|
1071
|
-
*
|
|
1108
|
+
* The table, bucket, collection or index, as the source declares it.
|
|
1109
|
+
* Null when the reader could not work out the container, and a null
|
|
1110
|
+
* container pairs with nothing, so it cannot match by accident of
|
|
1111
|
+
* shared source text. The string uses the boundary-name syntax (a
|
|
1112
|
+
* literal, a pattern with `{}` holes, or a reference), and only
|
|
1113
|
+
* `parseBoundaryName` should read it.
|
|
1072
1114
|
*/
|
|
1073
|
-
container:
|
|
1115
|
+
container: import_zod10.z.string().nullable(),
|
|
1074
1116
|
/**
|
|
1075
|
-
* A secondary way into the container, a DynamoDB global
|
|
1076
|
-
* index or an Elasticsearch alias, each with its own key
|
|
1077
|
-
* Null means the container's
|
|
1117
|
+
* A secondary way into the container, such as a DynamoDB global
|
|
1118
|
+
* secondary index or an Elasticsearch alias, each with its own key
|
|
1119
|
+
* fields. Null means the container's primary key. A query through an
|
|
1078
1120
|
* index and a query through the table are different accesses, so
|
|
1079
1121
|
* they pair separately.
|
|
1080
1122
|
*/
|
|
1081
|
-
accessPath:
|
|
1123
|
+
accessPath: import_zod10.z.string().nullable()
|
|
1082
1124
|
});
|
|
1083
1125
|
function containerReference(semantics) {
|
|
1084
1126
|
return semantics.container === null ? null : referenceFromName(semantics.container);
|
|
@@ -1088,21 +1130,21 @@ var storageSemantics = defineBoundarySemantics({
|
|
|
1088
1130
|
schema: StorageSemanticsSchema,
|
|
1089
1131
|
semconv: {
|
|
1090
1132
|
storageSystem: { name: "db.system.name" },
|
|
1091
|
-
// "default"
|
|
1133
|
+
// suss writes "default" when the source did not say which database.
|
|
1092
1134
|
scope: { name: "db.namespace", placeholderValues: ["default"] },
|
|
1093
1135
|
container: { name: "db.collection.name" }
|
|
1094
|
-
//
|
|
1095
|
-
//
|
|
1136
|
+
// The conventions have no attribute for a secondary index, so
|
|
1137
|
+
// accessPath is left out.
|
|
1096
1138
|
},
|
|
1097
1139
|
behavior: {
|
|
1098
|
-
/** A query returns rows or items,
|
|
1140
|
+
/** A query returns rows or items, with no status. */
|
|
1099
1141
|
exchangesHttpResponses: false,
|
|
1100
1142
|
leavesTheProcess: true,
|
|
1101
1143
|
reportsUnpairedItself: false,
|
|
1102
1144
|
identityKey: () => null,
|
|
1103
1145
|
displayLabel: storageLabel,
|
|
1104
1146
|
/**
|
|
1105
|
-
* A container the source
|
|
1147
|
+
* A container the source gives as a variable is whatever the
|
|
1106
1148
|
* deployment sets that variable to. `{SUBSCRIBERS_TABLE}` in the
|
|
1107
1149
|
* code and `prod-subscribers-v1` in the manifest are one table.
|
|
1108
1150
|
*/
|
|
@@ -1132,9 +1174,9 @@ function storageContainerLabel(semantics) {
|
|
|
1132
1174
|
}
|
|
1133
1175
|
|
|
1134
1176
|
// src/semantics/unitInvocation.ts
|
|
1135
|
-
var
|
|
1177
|
+
var import_zod11 = require("zod");
|
|
1136
1178
|
var UnitInvocationSemanticsSchema = DeployableUnitSchema.extend({
|
|
1137
|
-
name:
|
|
1179
|
+
name: import_zod11.z.literal("unit-invocation"),
|
|
1138
1180
|
instanceName: DeployableUnitSchema.shape.instanceName.nullable()
|
|
1139
1181
|
});
|
|
1140
1182
|
function calleeReference(semantics) {
|
|
@@ -1164,9 +1206,9 @@ var unitInvocationSemantics = defineBoundarySemantics({
|
|
|
1164
1206
|
*/
|
|
1165
1207
|
reportsUnpairedItself: false,
|
|
1166
1208
|
/**
|
|
1167
|
-
* A callee the source
|
|
1168
|
-
*
|
|
1169
|
-
*
|
|
1209
|
+
* A callee the source gives only as a variable has no name until the
|
|
1210
|
+
* deployment fills it in. It gets no key, since a key built from the
|
|
1211
|
+
* variable would pair only with itself.
|
|
1170
1212
|
*/
|
|
1171
1213
|
identityKey(semantics) {
|
|
1172
1214
|
if (semantics.instanceName === null || namesNothing(semantics.instanceName)) {
|
|
@@ -1187,11 +1229,10 @@ var unitInvocationSemantics = defineBoundarySemantics({
|
|
|
1187
1229
|
);
|
|
1188
1230
|
},
|
|
1189
1231
|
/**
|
|
1190
|
-
* A call that reads its callee's name
|
|
1191
|
-
*
|
|
1192
|
-
*
|
|
1193
|
-
*
|
|
1194
|
-
* id and neither side ever writes the other's string.
|
|
1232
|
+
* A call that reads its callee's name from the environment reaches
|
|
1233
|
+
* whichever resource the template wires that variable to. The name
|
|
1234
|
+
* is grounded to the logical id and not the deployed name, because
|
|
1235
|
+
* the invoked unit's own summary is keyed by the logical id.
|
|
1195
1236
|
*/
|
|
1196
1237
|
groundName(semantics, deployment) {
|
|
1197
1238
|
const reference = calleeReference(semantics);
|
|
@@ -1206,7 +1247,7 @@ var unitInvocationSemantics = defineBoundarySemantics({
|
|
|
1206
1247
|
});
|
|
1207
1248
|
|
|
1208
1249
|
// src/semantics/registry.ts
|
|
1209
|
-
var SemanticsSchema =
|
|
1250
|
+
var SemanticsSchema = import_zod12.z.discriminatedUnion("name", [
|
|
1210
1251
|
restSemantics.schema,
|
|
1211
1252
|
functionCallSemantics.schema,
|
|
1212
1253
|
graphqlResolverSemantics.schema,
|
|
@@ -1215,7 +1256,8 @@ var SemanticsSchema = import_zod11.z.discriminatedUnion("name", [
|
|
|
1215
1256
|
storageSemantics.schema,
|
|
1216
1257
|
messageBusSemantics.schema,
|
|
1217
1258
|
metricSemantics.schema,
|
|
1218
|
-
unitInvocationSemantics.schema
|
|
1259
|
+
unitInvocationSemantics.schema,
|
|
1260
|
+
ioSemantics.schema
|
|
1219
1261
|
]);
|
|
1220
1262
|
var DEFINITIONS = [
|
|
1221
1263
|
restSemantics,
|
|
@@ -1226,7 +1268,8 @@ var DEFINITIONS = [
|
|
|
1226
1268
|
storageSemantics,
|
|
1227
1269
|
messageBusSemantics,
|
|
1228
1270
|
metricSemantics,
|
|
1229
|
-
unitInvocationSemantics
|
|
1271
|
+
unitInvocationSemantics,
|
|
1272
|
+
ioSemantics
|
|
1230
1273
|
];
|
|
1231
1274
|
var BY_NAME = new Map(
|
|
1232
1275
|
DEFINITIONS.map((d) => [d.name, d])
|
|
@@ -1249,90 +1292,95 @@ function allBehaviors() {
|
|
|
1249
1292
|
}
|
|
1250
1293
|
|
|
1251
1294
|
// src/schemas.ts
|
|
1252
|
-
var ConfidenceSourceSchema =
|
|
1295
|
+
var ConfidenceSourceSchema = import_zod13.z.enum([
|
|
1253
1296
|
"inferred_static",
|
|
1254
1297
|
"inferred_ai",
|
|
1255
1298
|
"declared",
|
|
1256
1299
|
"derived"
|
|
1257
1300
|
]);
|
|
1258
|
-
var ConfidenceLevelSchema =
|
|
1259
|
-
var CorroborationSchema =
|
|
1260
|
-
outcome:
|
|
1301
|
+
var ConfidenceLevelSchema = import_zod13.z.enum(["high", "medium", "low"]);
|
|
1302
|
+
var CorroborationSchema = import_zod13.z.object({
|
|
1303
|
+
outcome: import_zod13.z.enum(["observed", "refuted", "untested"]),
|
|
1261
1304
|
/** Executions that produced a verdict for this claim. */
|
|
1262
|
-
runs:
|
|
1305
|
+
runs: import_zod13.z.number(),
|
|
1263
1306
|
/** Present when refuted: the input and observation that disagreed. */
|
|
1264
|
-
counterexample:
|
|
1307
|
+
counterexample: import_zod13.z.unknown().optional(),
|
|
1265
1308
|
/** Present when untested: why no verdict was reachable. */
|
|
1266
|
-
reason:
|
|
1309
|
+
reason: import_zod13.z.string().optional()
|
|
1267
1310
|
});
|
|
1268
|
-
var ConfidenceInfoSchema =
|
|
1311
|
+
var ConfidenceInfoSchema = import_zod13.z.object({
|
|
1269
1312
|
source: ConfidenceSourceSchema,
|
|
1270
1313
|
level: ConfidenceLevelSchema,
|
|
1271
1314
|
corroboration: CorroborationSchema.optional()
|
|
1272
1315
|
});
|
|
1273
|
-
var SourceLocationSchema =
|
|
1274
|
-
file:
|
|
1316
|
+
var SourceLocationSchema = import_zod13.z.object({
|
|
1317
|
+
file: import_zod13.z.string(),
|
|
1275
1318
|
/** Line numbers, for a person reading the summary or an editor link. */
|
|
1276
|
-
range:
|
|
1319
|
+
range: import_zod13.z.object({ start: import_zod13.z.number(), end: import_zod13.z.number() }),
|
|
1277
1320
|
/**
|
|
1278
|
-
* Character offsets of the unit in its file. Identity and joins
|
|
1279
|
-
*
|
|
1280
|
-
*
|
|
1281
|
-
*
|
|
1282
|
-
* contract artifact's say.
|
|
1321
|
+
* Character offsets of the unit in its file. Identity and joins use
|
|
1322
|
+
* these, because two functions can share a line but never an offset
|
|
1323
|
+
* range. `range` gives the same place in lines. Absent on a summary
|
|
1324
|
+
* with no source position, such as one read from a contract.
|
|
1283
1325
|
*/
|
|
1284
|
-
span:
|
|
1285
|
-
exportName:
|
|
1326
|
+
span: import_zod13.z.object({ start: import_zod13.z.number(), end: import_zod13.z.number() }).optional(),
|
|
1327
|
+
exportName: import_zod13.z.string().nullable(),
|
|
1286
1328
|
/**
|
|
1287
|
-
* The project the extract
|
|
1288
|
-
*
|
|
1329
|
+
* The project the extract ran on, by the name the project gives
|
|
1330
|
+
* itself.
|
|
1289
1331
|
*
|
|
1290
1332
|
* Paths are relative to wherever the extract ran, so two services in
|
|
1291
|
-
* one repository both report `src/handlers.ts`, and merging their
|
|
1292
|
-
* summaries
|
|
1293
|
-
*
|
|
1333
|
+
* one repository can both report `src/handlers.ts`, and merging their
|
|
1334
|
+
* summaries would mix them up. This field tells them apart, and a
|
|
1335
|
+
* reader groups by it.
|
|
1294
1336
|
*/
|
|
1295
|
-
workspace:
|
|
1337
|
+
workspace: import_zod13.z.string().optional(),
|
|
1338
|
+
/**
|
|
1339
|
+
* The module of the application the unit belongs to, by the name the
|
|
1340
|
+
* project's `suss.json` gives it. Set only when the project lists its
|
|
1341
|
+
* modules, and then on every unit whose file is under a module's root.
|
|
1342
|
+
*/
|
|
1343
|
+
module: import_zod13.z.string().optional()
|
|
1296
1344
|
});
|
|
1297
|
-
var BoundaryBindingSchema =
|
|
1298
|
-
transport:
|
|
1345
|
+
var BoundaryBindingSchema = import_zod13.z.object({
|
|
1346
|
+
transport: import_zod13.z.string(),
|
|
1299
1347
|
semantics: SemanticsSchema,
|
|
1300
|
-
recognition:
|
|
1348
|
+
recognition: import_zod13.z.string()
|
|
1301
1349
|
});
|
|
1302
1350
|
function typeDefinitionKey(ref) {
|
|
1303
1351
|
return ref.def ?? null;
|
|
1304
1352
|
}
|
|
1305
|
-
var TypeShapeSchema =
|
|
1306
|
-
() =>
|
|
1307
|
-
|
|
1308
|
-
type:
|
|
1309
|
-
properties:
|
|
1310
|
-
spreads:
|
|
1353
|
+
var TypeShapeSchema = import_zod13.z.lazy(
|
|
1354
|
+
() => import_zod13.z.discriminatedUnion("type", [
|
|
1355
|
+
import_zod13.z.object({
|
|
1356
|
+
type: import_zod13.z.literal("record"),
|
|
1357
|
+
properties: import_zod13.z.record(import_zod13.z.string(), TypeShapeSchema),
|
|
1358
|
+
spreads: import_zod13.z.array(import_zod13.z.object({ sourceText: import_zod13.z.string() })).optional()
|
|
1311
1359
|
}),
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
type:
|
|
1316
|
-
value:
|
|
1317
|
-
raw:
|
|
1360
|
+
import_zod13.z.object({ type: import_zod13.z.literal("dictionary"), values: TypeShapeSchema }),
|
|
1361
|
+
import_zod13.z.object({ type: import_zod13.z.literal("array"), items: TypeShapeSchema }),
|
|
1362
|
+
import_zod13.z.object({
|
|
1363
|
+
type: import_zod13.z.literal("literal"),
|
|
1364
|
+
value: import_zod13.z.union([import_zod13.z.string(), import_zod13.z.number(), import_zod13.z.boolean()]),
|
|
1365
|
+
raw: import_zod13.z.string().optional()
|
|
1318
1366
|
}),
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
type:
|
|
1327
|
-
variants:
|
|
1367
|
+
import_zod13.z.object({ type: import_zod13.z.literal("text") }),
|
|
1368
|
+
import_zod13.z.object({ type: import_zod13.z.literal("integer") }),
|
|
1369
|
+
import_zod13.z.object({ type: import_zod13.z.literal("number") }),
|
|
1370
|
+
import_zod13.z.object({ type: import_zod13.z.literal("boolean") }),
|
|
1371
|
+
import_zod13.z.object({ type: import_zod13.z.literal("null") }),
|
|
1372
|
+
import_zod13.z.object({ type: import_zod13.z.literal("undefined") }),
|
|
1373
|
+
import_zod13.z.object({
|
|
1374
|
+
type: import_zod13.z.literal("union"),
|
|
1375
|
+
variants: import_zod13.z.array(TypeShapeSchema)
|
|
1328
1376
|
}),
|
|
1329
|
-
|
|
1330
|
-
type:
|
|
1331
|
-
name:
|
|
1332
|
-
from:
|
|
1333
|
-
def:
|
|
1377
|
+
import_zod13.z.object({
|
|
1378
|
+
type: import_zod13.z.literal("ref"),
|
|
1379
|
+
name: import_zod13.z.string(),
|
|
1380
|
+
from: import_zod13.z.string().optional(),
|
|
1381
|
+
def: import_zod13.z.string().optional()
|
|
1334
1382
|
}),
|
|
1335
|
-
|
|
1383
|
+
import_zod13.z.object({ type: import_zod13.z.literal("unknown") })
|
|
1336
1384
|
])
|
|
1337
1385
|
);
|
|
1338
1386
|
var MAX_DEFINITION_DEPTH = 6;
|
|
@@ -1454,6 +1502,9 @@ function boundaryLabel(binding) {
|
|
|
1454
1502
|
function displayLabel(binding) {
|
|
1455
1503
|
return boundaryLabel(binding) ?? `${binding.semantics.name}:${binding.recognition}`;
|
|
1456
1504
|
}
|
|
1505
|
+
function labelWithDetail(binding, detail) {
|
|
1506
|
+
return `${boundaryLabel(binding) ?? binding.semantics.name} ${detail}`;
|
|
1507
|
+
}
|
|
1457
1508
|
function normalizeRuleBoundary(raw) {
|
|
1458
1509
|
const trimmed = raw.trim();
|
|
1459
1510
|
for (const behavior of allBehaviors()) {
|
|
@@ -1617,8 +1668,8 @@ var PLATFORM_INJECTED_ENV_VARS = {
|
|
|
1617
1668
|
};
|
|
1618
1669
|
|
|
1619
1670
|
// src/relation.ts
|
|
1620
|
-
var
|
|
1621
|
-
var RelationSchema =
|
|
1671
|
+
var import_zod14 = require("zod");
|
|
1672
|
+
var RelationSchema = import_zod14.z.enum([
|
|
1622
1673
|
"provides",
|
|
1623
1674
|
"reads",
|
|
1624
1675
|
"writes",
|
|
@@ -1627,71 +1678,78 @@ var RelationSchema = import_zod13.z.enum([
|
|
|
1627
1678
|
var EffectRelationSchema = RelationSchema.exclude(["provides"]);
|
|
1628
1679
|
|
|
1629
1680
|
// src/suppressions.ts
|
|
1630
|
-
var
|
|
1631
|
-
var SuppressionSideSchema =
|
|
1632
|
-
summary:
|
|
1633
|
-
transitionId:
|
|
1681
|
+
var import_zod15 = require("zod");
|
|
1682
|
+
var SuppressionSideSchema = import_zod15.z.object({
|
|
1683
|
+
summary: import_zod15.z.string().optional(),
|
|
1684
|
+
transitionId: import_zod15.z.string().optional()
|
|
1634
1685
|
}).optional();
|
|
1635
|
-
var SuppressionRuleSchema =
|
|
1686
|
+
var SuppressionRuleSchema = import_zod15.z.object({
|
|
1636
1687
|
/**
|
|
1637
|
-
* The finding kind to match,
|
|
1638
|
-
* string
|
|
1639
|
-
*
|
|
1688
|
+
* The finding kind to match, behavioral or intent. The schema accepts
|
|
1689
|
+
* any string because ir-core cannot import either IR's kind enum. The
|
|
1690
|
+
* CLI's loader checks it against both.
|
|
1640
1691
|
*/
|
|
1641
|
-
kind:
|
|
1692
|
+
kind: import_zod15.z.string().optional(),
|
|
1642
1693
|
/**
|
|
1643
|
-
*
|
|
1644
|
-
* "fn:@acme/api::getUser". REST
|
|
1645
|
-
*
|
|
1646
|
-
* equal.
|
|
1694
|
+
* The boundary's human-readable key, such as "GET /pet/{petId}" or
|
|
1695
|
+
* "fn:@acme/api::getUser". A REST key goes through the same path
|
|
1696
|
+
* normalizer the checkers use, so `:id` and `{id}` compare equal.
|
|
1647
1697
|
*/
|
|
1648
|
-
boundary:
|
|
1698
|
+
boundary: import_zod15.z.string().optional(),
|
|
1649
1699
|
/**
|
|
1650
|
-
* Consumer-side discriminators, the narrowest useful match.
|
|
1651
|
-
*
|
|
1652
|
-
*
|
|
1653
|
-
*
|
|
1700
|
+
* Consumer-side discriminators, the narrowest useful match. They
|
|
1701
|
+
* apply only to behavioral findings. A rule that sets `consumer`
|
|
1702
|
+
* never matches an intent finding, because an intent finding has no
|
|
1703
|
+
* consumer side.
|
|
1654
1704
|
*/
|
|
1655
1705
|
consumer: SuppressionSideSchema,
|
|
1656
1706
|
/**
|
|
1657
|
-
* Provider-side discriminators, the
|
|
1658
|
-
* about a status the provider produces has its
|
|
1659
|
-
* side, and that id is the only
|
|
1660
|
-
* that one finding. As with `consumer`, a rule
|
|
1661
|
-
* `provider` never matches an intent finding.
|
|
1707
|
+
* Provider-side discriminators, matching the same fields as
|
|
1708
|
+
* `consumer`. A finding about a status the provider produces has its
|
|
1709
|
+
* transition id on this side, and that id is the only value narrow
|
|
1710
|
+
* enough to pick out that one finding. As with `consumer`, a rule
|
|
1711
|
+
* that sets `provider` never matches an intent finding.
|
|
1662
1712
|
*/
|
|
1663
1713
|
provider: SuppressionSideSchema,
|
|
1664
1714
|
/**
|
|
1665
|
-
*
|
|
1666
|
-
*
|
|
1667
|
-
*
|
|
1668
|
-
*
|
|
1669
|
-
|
|
1715
|
+
* The title of one PRD scenario. A PRD finding's boundary is the
|
|
1716
|
+
* whole PRD, so without this a rule accepts every scenario in it,
|
|
1717
|
+
* including one added later. A rule that sets `scenario` matches
|
|
1718
|
+
* only intent findings about a scenario with that title.
|
|
1719
|
+
*/
|
|
1720
|
+
scenario: import_zod15.z.string().optional(),
|
|
1721
|
+
/**
|
|
1722
|
+
* "narrow", the default, requires `kind` plus one of `boundary`,
|
|
1723
|
+
* `scenario`, `consumer.transitionId` or `provider.transitionId`, so
|
|
1724
|
+
* the rule targets a specific class of finding. "broad" allows a
|
|
1725
|
+
* match on kind alone or boundary alone, and such a rule also
|
|
1726
|
+
* silences future regressions in that category.
|
|
1670
1727
|
*/
|
|
1671
|
-
scope:
|
|
1728
|
+
scope: import_zod15.z.enum(["narrow", "broad"]).default("narrow"),
|
|
1672
1729
|
/** Required human-written justification. */
|
|
1673
|
-
reason:
|
|
1730
|
+
reason: import_zod15.z.string().min(1),
|
|
1674
1731
|
/** What to do when a finding matches. */
|
|
1675
|
-
effect:
|
|
1732
|
+
effect: import_zod15.z.enum(["mark", "downgrade", "hide"]).default("mark")
|
|
1676
1733
|
}).strict();
|
|
1677
|
-
var SuppressionFileSchema =
|
|
1678
|
-
version:
|
|
1679
|
-
rules:
|
|
1734
|
+
var SuppressionFileSchema = import_zod15.z.object({
|
|
1735
|
+
version: import_zod15.z.literal(1),
|
|
1736
|
+
rules: import_zod15.z.array(SuppressionRuleSchema)
|
|
1680
1737
|
}).strict();
|
|
1681
1738
|
function validateRule(rule) {
|
|
1682
1739
|
if (rule.scope === "broad") {
|
|
1683
|
-
if (rule.kind === void 0 && rule.boundary === void 0 && rule.consumer === void 0 && rule.provider === void 0) {
|
|
1684
|
-
return "broad-scope rule must constrain at least one field (kind, boundary, consumer, or provider)";
|
|
1740
|
+
if (rule.kind === void 0 && rule.boundary === void 0 && rule.scenario === void 0 && rule.consumer === void 0 && rule.provider === void 0) {
|
|
1741
|
+
return "broad-scope rule must constrain at least one field (kind, boundary, scenario, consumer, or provider)";
|
|
1685
1742
|
}
|
|
1686
1743
|
return null;
|
|
1687
1744
|
}
|
|
1688
1745
|
const hasKind = rule.kind !== void 0;
|
|
1689
1746
|
const hasBoundary = rule.boundary !== void 0;
|
|
1747
|
+
const hasScenario = rule.scenario !== void 0;
|
|
1690
1748
|
const hasTransition = rule.consumer?.transitionId !== void 0 || rule.provider?.transitionId !== void 0;
|
|
1691
|
-
if (hasKind && (hasBoundary || hasTransition)) {
|
|
1749
|
+
if (hasKind && (hasBoundary || hasScenario || hasTransition)) {
|
|
1692
1750
|
return null;
|
|
1693
1751
|
}
|
|
1694
|
-
return "narrow-scope rule must specify kind AND (boundary OR consumer.transitionId OR provider.transitionId); set scope: 'broad' to silence wider categories";
|
|
1752
|
+
return "narrow-scope rule must specify kind AND (boundary OR scenario OR consumer.transitionId OR provider.transitionId); set scope: 'broad' to silence wider categories";
|
|
1695
1753
|
}
|
|
1696
1754
|
function ruleBoundaryMatchesKey(ruleBoundary, key) {
|
|
1697
1755
|
if (key === null) {
|
|
@@ -1743,6 +1801,12 @@ function countsForThreshold(finding) {
|
|
|
1743
1801
|
return finding.suppressed.effect === "downgrade";
|
|
1744
1802
|
}
|
|
1745
1803
|
|
|
1804
|
+
// src/testName.ts
|
|
1805
|
+
var TEST_TITLE_SEPARATOR = " > ";
|
|
1806
|
+
function testUnitName(titles) {
|
|
1807
|
+
return titles.join(TEST_TITLE_SEPARATOR);
|
|
1808
|
+
}
|
|
1809
|
+
|
|
1746
1810
|
// src/typeShapeMatch.ts
|
|
1747
1811
|
function bodyShapesMatch(actual, declared) {
|
|
1748
1812
|
if (actual.type === "unknown" || declared.type === "unknown") {
|
|
@@ -1930,6 +1994,14 @@ function packageExportBinding(opts) {
|
|
|
1930
1994
|
exportPath: opts.exportPath
|
|
1931
1995
|
});
|
|
1932
1996
|
}
|
|
1997
|
+
function moduleExportBinding(opts) {
|
|
1998
|
+
return functionCallBinding({
|
|
1999
|
+
transport: "in-process",
|
|
2000
|
+
recognition: opts.recognition,
|
|
2001
|
+
module: opts.module,
|
|
2002
|
+
exportName: opts.exportName
|
|
2003
|
+
});
|
|
2004
|
+
}
|
|
1933
2005
|
function graphqlResolverBinding(opts) {
|
|
1934
2006
|
return {
|
|
1935
2007
|
transport: opts.transport,
|
|
@@ -2012,6 +2084,13 @@ function metricBinding(opts) {
|
|
|
2012
2084
|
recognition: opts.recognition
|
|
2013
2085
|
};
|
|
2014
2086
|
}
|
|
2087
|
+
function ioBinding(opts) {
|
|
2088
|
+
return {
|
|
2089
|
+
transport: "in-process",
|
|
2090
|
+
semantics: { name: "io", target: namedOrNull(opts.target, "io target") },
|
|
2091
|
+
recognition: opts.recognition
|
|
2092
|
+
};
|
|
2093
|
+
}
|
|
2015
2094
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2016
2095
|
0 && (module.exports = {
|
|
2017
2096
|
BoundaryBindingSchema,
|
|
@@ -2025,6 +2104,7 @@ function metricBinding(opts) {
|
|
|
2025
2104
|
FunctionCallSemanticsSchema,
|
|
2026
2105
|
GraphqlOperationSemanticsSchema,
|
|
2027
2106
|
GraphqlResolverSemanticsSchema,
|
|
2107
|
+
IoSemanticsSchema,
|
|
2028
2108
|
MessageBusSemanticsSchema,
|
|
2029
2109
|
MetricSemanticsSchema,
|
|
2030
2110
|
NOTHING_DEPLOYED,
|
|
@@ -2037,6 +2117,7 @@ function metricBinding(opts) {
|
|
|
2037
2117
|
StorageSemanticsSchema,
|
|
2038
2118
|
SuppressionFileSchema,
|
|
2039
2119
|
SuppressionRuleSchema,
|
|
2120
|
+
TEST_TITLE_SEPARATOR,
|
|
2040
2121
|
TypeShapeSchema,
|
|
2041
2122
|
UnitInvocationSemanticsSchema,
|
|
2042
2123
|
applySuppressionsToFindings,
|
|
@@ -2070,12 +2151,17 @@ function metricBinding(opts) {
|
|
|
2070
2151
|
groundBinding,
|
|
2071
2152
|
groundedPairingKey,
|
|
2072
2153
|
hasNameHole,
|
|
2154
|
+
ioBinding,
|
|
2155
|
+
ioIdentityKey,
|
|
2073
2156
|
isGraphqlOperationBinding,
|
|
2157
|
+
isModuleName,
|
|
2158
|
+
labelWithDetail,
|
|
2074
2159
|
leavesTheProcess,
|
|
2075
2160
|
messageBusBinding,
|
|
2076
2161
|
methodsAgree,
|
|
2077
2162
|
metricBinding,
|
|
2078
2163
|
metricIdentityKey,
|
|
2164
|
+
moduleExportBinding,
|
|
2079
2165
|
namePatternFromSub,
|
|
2080
2166
|
namePatternKey,
|
|
2081
2167
|
nameReference,
|
|
@@ -2115,6 +2201,7 @@ function metricBinding(opts) {
|
|
|
2115
2201
|
storageContainerLabel,
|
|
2116
2202
|
storageLabel,
|
|
2117
2203
|
storageSystemLabel,
|
|
2204
|
+
testUnitName,
|
|
2118
2205
|
typeDefinitionKey,
|
|
2119
2206
|
unitIdentityKey,
|
|
2120
2207
|
unitInvocationBinding,
|