@suss/ir-core 0.21.0 → 0.21.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/dist/index.js CHANGED
@@ -20,19 +20,32 @@ import {
20
20
  UnitInvocationSemanticsSchema,
21
21
  allBehaviors,
22
22
  behaviorOf,
23
+ boundaryNameString,
23
24
  busIdentityKey,
24
25
  busesAgree,
25
26
  channelsPair,
27
+ dispatchByType,
26
28
  ecsContainerInstanceName,
29
+ fixedTextLength,
27
30
  fnIdentityKey,
28
31
  formatChannel,
29
32
  gqlIdentityKey,
33
+ hasNameHole,
30
34
  methodsAgree,
31
35
  metricIdentityKey,
36
+ namePatternFromSub,
37
+ namePatternKey,
38
+ namesAgree,
39
+ namesNothing,
32
40
  normalizePath,
41
+ parseBoundaryName,
33
42
  parseChannel,
34
43
  pathAfterOrigin,
35
44
  pathShape,
45
+ patternHole,
46
+ referenceFromName,
47
+ referenceName,
48
+ referenceOf,
36
49
  routePathAdmits,
37
50
  semconvMappingOf,
38
51
  statesAnOrigin,
@@ -41,7 +54,7 @@ import {
41
54
  typeDefinitionKey,
42
55
  unitIdentityKey,
43
56
  withDefinitionsInlined
44
- } from "./chunk-QHFMZPEG.js";
57
+ } from "./chunk-PPQWK62O.js";
45
58
 
46
59
  // src/semconv.ts
47
60
  function semconvAttributes(binding) {
@@ -79,12 +92,16 @@ function withRewrittenPaths(binding, rewrite) {
79
92
  semantics: behavior.rewritePaths(binding.semantics, rewrite)
80
93
  };
81
94
  }
82
- function groundedPairingKey(binding, deployedAs) {
95
+ function groundedPairingKey(binding, deployment) {
96
+ return pairingKey(groundBinding(binding, deployment));
97
+ }
98
+ function groundBinding(binding, deployment) {
83
99
  const behavior = behaviorOf(binding.semantics);
84
- const grounded = behavior.groundName?.(binding.semantics, deployedAs) ?? null;
85
- return pairingKey(
86
- grounded === null ? binding : { ...binding, semantics: grounded }
87
- );
100
+ const grounded = behavior.groundName?.(binding.semantics, deployment) ?? null;
101
+ return grounded === null ? binding : { ...binding, semantics: grounded };
102
+ }
103
+ function nameReference(binding) {
104
+ return behaviorOf(binding.semantics).nameReference?.(binding.semantics) ?? null;
88
105
  }
89
106
  function pairingKey(binding) {
90
107
  const behavior = behaviorOf(binding.semantics);
@@ -138,141 +155,6 @@ function withinScope(binding, scope) {
138
155
  return within === void 0 ? false : within(binding.semantics, scope);
139
156
  }
140
157
 
141
- // src/dispatch.ts
142
- function dispatchByType(table, value) {
143
- const handler = table[value.type];
144
- return handler(value);
145
- }
146
-
147
- // src/boundaryName.ts
148
- var HOLE_SPLIT = /(\{[^}]*\})/;
149
- var SUB_TOKEN = /\$\{([^}]*)\}/g;
150
- var SUB_ESCAPE = /\$\{!/;
151
- function isHole(piece) {
152
- return piece.startsWith("{") && piece.endsWith("}");
153
- }
154
- function parseBoundaryName(name) {
155
- const parts = name.split(HOLE_SPLIT).filter((piece) => piece !== "").map(
156
- (piece) => isHole(piece) ? { type: "hole", label: piece.slice(1, -1) } : { type: "text", text: piece }
157
- );
158
- const only = parts.length === 1 ? parts[0] : void 0;
159
- if (only !== void 0 && only.type === "hole") {
160
- return { type: "reference", path: only.label.split(".") };
161
- }
162
- if (parts.some((part) => part.type === "hole")) {
163
- return { type: "pattern", parts };
164
- }
165
- return { type: "literal", value: name };
166
- }
167
- var partString = {
168
- text: (part) => part.text,
169
- hole: (part) => patternHole(part.label)
170
- };
171
- var nameString = {
172
- literal: (name) => name.value,
173
- pattern: (name) => name.parts.map((part) => dispatchByType(partString, part)).join(""),
174
- reference: (name) => patternHole(name.path.join("."))
175
- };
176
- function boundaryNameString(name) {
177
- return dispatchByType(nameString, name);
178
- }
179
- function patternHole(label) {
180
- return `{${label}}`;
181
- }
182
- function namePatternFromSub(value) {
183
- if (Array.isArray(value)) {
184
- return typeof value[0] === "string" ? namePatternFromSub(value[0]) : null;
185
- }
186
- if (typeof value !== "string") {
187
- return null;
188
- }
189
- if (SUB_ESCAPE.test(value)) {
190
- return null;
191
- }
192
- return value.replace(
193
- SUB_TOKEN,
194
- (_whole, inner) => patternHole(inner)
195
- );
196
- }
197
- function namesNothing(name) {
198
- return parseBoundaryName(name).type === "reference";
199
- }
200
- function hasNameHole(name) {
201
- return parseBoundaryName(name).type !== "literal";
202
- }
203
- function namePatternKey(name) {
204
- return dispatchByType(
205
- {
206
- literal: (parsed) => parsed.value,
207
- pattern: (parsed) => boundaryNameString({
208
- type: "pattern",
209
- parts: parsed.parts.map(
210
- (part) => part.type === "hole" ? { type: "hole", label: "" } : part
211
- )
212
- }),
213
- reference: () => patternHole("")
214
- },
215
- parseBoundaryName(name)
216
- );
217
- }
218
- function fixedTextLength(name) {
219
- return dispatchByType(
220
- {
221
- literal: (parsed) => parsed.value.length,
222
- pattern: (parsed) => parsed.parts.reduce(
223
- (total, part) => total + (part.type === "text" ? part.text.length : 0),
224
- 0
225
- ),
226
- reference: () => 0
227
- },
228
- parseBoundaryName(name)
229
- );
230
- }
231
- function quote(text) {
232
- return text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
233
- }
234
- function admits(pattern, name) {
235
- const source = pattern.parts.map((part) => part.type === "hole" ? ".+" : quote(part.text)).join("");
236
- return new RegExp(`^${source}$`).test(name);
237
- }
238
- function namesAgree(a, b) {
239
- const left = parseBoundaryName(a);
240
- const right = parseBoundaryName(b);
241
- if (left.type === "reference" || right.type === "reference") {
242
- return false;
243
- }
244
- if (left.type === "pattern" && right.type === "pattern") {
245
- return namePatternKey(a) === namePatternKey(b);
246
- }
247
- if (left.type === "pattern") {
248
- return admits(left, b);
249
- }
250
- if (right.type === "pattern") {
251
- return admits(right, a);
252
- }
253
- return a === b;
254
- }
255
- function referenceName(reference) {
256
- const path = [reference.root, ...reference.fields];
257
- if (path.some((part) => part === "")) {
258
- return null;
259
- }
260
- return boundaryNameString({ type: "reference", path });
261
- }
262
- function referenceOf(name) {
263
- if (name.type !== "reference") {
264
- return null;
265
- }
266
- const root = name.path[0];
267
- if (root === void 0 || name.path.some((part) => part === "")) {
268
- return null;
269
- }
270
- return { root, fields: name.path.slice(1) };
271
- }
272
- function referenceFromName(name) {
273
- return referenceOf(parseBoundaryName(name));
274
- }
275
-
276
158
  // src/boundarySpelling.ts
277
159
  function resourceNameIn(spelling) {
278
160
  if (spelling.startsWith("arn:")) {
@@ -337,6 +219,13 @@ function fileInCodeScope(file, scope) {
337
219
  return path === prefix || path.startsWith(`${prefix}/`);
338
220
  }
339
221
 
222
+ // src/deployment.ts
223
+ var NOTHING_DEPLOYED = {
224
+ variableFor: () => null,
225
+ setTo: () => null,
226
+ pointsAt: () => null
227
+ };
228
+
340
229
  // src/relation.ts
341
230
  import { z } from "zod";
342
231
  var RelationSchema = z.enum([
@@ -747,6 +636,7 @@ export {
747
636
  GraphqlResolverSemanticsSchema,
748
637
  MessageBusSemanticsSchema,
749
638
  MetricSemanticsSchema,
639
+ NOTHING_DEPLOYED,
750
640
  RelationSchema,
751
641
  RestSemanticsSchema,
752
642
  RuntimeConfigSemanticsSchema,
@@ -782,6 +672,7 @@ export {
782
672
  gqlIdentityKey,
783
673
  graphqlOperationBinding,
784
674
  graphqlResolverBinding,
675
+ groundBinding,
785
676
  groundedPairingKey,
786
677
  hasNameHole,
787
678
  isGraphqlOperationBinding,
@@ -791,6 +682,7 @@ export {
791
682
  metricIdentityKey,
792
683
  namePatternFromSub,
793
684
  namePatternKey,
685
+ nameReference,
794
686
  namesAgree,
795
687
  namesBoundary,
796
688
  namesBoundaryExactly,
package/dist/schemas.cjs CHANGED
@@ -358,6 +358,44 @@ var metricSemantics = defineBoundarySemantics({
358
358
  // src/semantics/rest.ts
359
359
  var import_zod6 = require("zod");
360
360
 
361
+ // src/boundaryName.ts
362
+ var HOLE_SPLIT = /(\{[^}]*\})/;
363
+ function isHole(piece) {
364
+ return piece.startsWith("{") && piece.endsWith("}");
365
+ }
366
+ function parseBoundaryName(name) {
367
+ const parts = name.split(HOLE_SPLIT).filter((piece) => piece !== "").map(
368
+ (piece) => isHole(piece) ? { type: "hole", label: piece.slice(1, -1) } : { type: "text", text: piece }
369
+ );
370
+ const only = parts.length === 1 ? parts[0] : void 0;
371
+ if (only !== void 0 && only.type === "hole") {
372
+ return { type: "reference", path: only.label.split(".") };
373
+ }
374
+ if (parts.some((part) => part.type === "hole")) {
375
+ return { type: "pattern", parts };
376
+ }
377
+ return { type: "literal", value: name };
378
+ }
379
+ function patternHole(label) {
380
+ return `{${label}}`;
381
+ }
382
+ function namesNothing(name) {
383
+ return parseBoundaryName(name).type === "reference";
384
+ }
385
+ function referenceOf(name) {
386
+ if (name.type !== "reference") {
387
+ return null;
388
+ }
389
+ const root = name.path[0];
390
+ if (root === void 0 || name.path.some((part) => part === "")) {
391
+ return null;
392
+ }
393
+ return { root, fields: name.path.slice(1) };
394
+ }
395
+ function referenceFromName(name) {
396
+ return referenceOf(parseBoundaryName(name));
397
+ }
398
+
361
399
  // src/urlPath.ts
362
400
  var SCHEME_ORIGIN = /^[a-zA-Z][a-zA-Z\d+.-]*:\/\/[^/]*/;
363
401
  var PROTOCOL_RELATIVE_ORIGIN = /^\/\/[^/]*/;
@@ -387,9 +425,9 @@ var RestSemanticsSchema = import_zod6.z.object({
387
425
  declaredResponses: import_zod6.z.array(import_zod6.z.number()).optional()
388
426
  });
389
427
  var OPENING_HOLE = /^\{([^{}]+)\}(.*)$/;
390
- function variableOf(label) {
391
- const parts = label.split(".");
392
- return parts[parts.length - 1] ?? label;
428
+ function baseUrlReference(semantics) {
429
+ const label = OPENING_HOLE.exec(semantics.path ?? "")?.[1];
430
+ return label === void 0 ? null : referenceFromName(patternHole(label));
393
431
  }
394
432
  function normalizePath(path) {
395
433
  let normalized = path.replace(/:([a-zA-Z_]\w*)/g, "{$1}");
@@ -523,22 +561,20 @@ var restSemantics = defineBoundarySemantics({
523
561
  * route parameter, and `/orders/{id}` means every id rather than a
524
562
  * variable somebody set.
525
563
  */
526
- groundName(semantics, deployedAs) {
527
- if (semantics.path === null) {
564
+ groundName(semantics, deployment) {
565
+ const reference = baseUrlReference(semantics);
566
+ if (reference === null) {
528
567
  return null;
529
568
  }
530
- const opening = OPENING_HOLE.exec(semantics.path);
531
- if (opening === null) {
532
- return null;
533
- }
534
- const [, label, rest] = opening;
535
- const base = deployedAs(variableOf(label));
569
+ const base = deployment.setTo(reference);
536
570
  if (base === null) {
537
571
  return null;
538
572
  }
573
+ const rest = OPENING_HOLE.exec(semantics.path ?? "")?.[2] ?? "";
539
574
  const grounded = pathAfterOrigin(`${base}${rest}`);
540
575
  return { ...semantics, path: grounded === "" ? "/" : grounded };
541
576
  },
577
+ nameReference: baseUrlReference,
542
578
  ruleBoundary: {
543
579
  // "METHOD /path": one leading token, then an absolute path.
544
580
  claims(raw) {
@@ -625,6 +661,9 @@ var StorageSemanticsSchema = import_zod9.z.object({
625
661
  */
626
662
  accessPath: import_zod9.z.string().nullable()
627
663
  });
664
+ function containerReference(semantics) {
665
+ return semantics.container === null ? null : referenceFromName(semantics.container);
666
+ }
628
667
  var storageSemantics = defineBoundarySemantics({
629
668
  name: "storage",
630
669
  schema: StorageSemanticsSchema,
@@ -641,7 +680,21 @@ var storageSemantics = defineBoundarySemantics({
641
680
  exchangesHttpResponses: false,
642
681
  reportsUnpairedItself: false,
643
682
  identityKey: () => null,
644
- displayLabel: storageLabel
683
+ displayLabel: storageLabel,
684
+ /**
685
+ * A container the source states as a variable is whatever the
686
+ * deployment sets that variable to. `{SUBSCRIBERS_TABLE}` in the
687
+ * code and `prod-subscribers-v1` in the manifest are one table.
688
+ */
689
+ groundName(semantics, deployment) {
690
+ const reference = containerReference(semantics);
691
+ if (reference === null) {
692
+ return null;
693
+ }
694
+ const name = deployment.setTo(reference);
695
+ return name === null ? null : { ...semantics, container: name };
696
+ },
697
+ nameReference: containerReference
645
698
  }
646
699
  });
647
700
  function storageLabel(semantics) {
@@ -659,6 +712,9 @@ var UnitInvocationSemanticsSchema = DeployableUnitSchema.extend({
659
712
  name: import_zod10.z.literal("unit-invocation"),
660
713
  instanceName: DeployableUnitSchema.shape.instanceName.nullable()
661
714
  });
715
+ function calleeReference(semantics) {
716
+ return semantics.instanceName === null ? null : referenceFromName(semantics.instanceName);
717
+ }
662
718
  var unitInvocationSemantics = defineBoundarySemantics({
663
719
  name: "unit-invocation",
664
720
  schema: UnitInvocationSemanticsSchema,
@@ -681,8 +737,13 @@ var unitInvocationSemantics = defineBoundarySemantics({
681
737
  * being reported as a problem here.
682
738
  */
683
739
  reportsUnpairedItself: false,
740
+ /**
741
+ * A callee the source states only as a variable is not a name for
742
+ * anything until the deployment fills it in, so it keys as nothing
743
+ * rather than as a bucket that would agree with itself alone.
744
+ */
684
745
  identityKey(semantics) {
685
- if (semantics.instanceName === null) {
746
+ if (semantics.instanceName === null || namesNothing(semantics.instanceName)) {
686
747
  return null;
687
748
  }
688
749
  return unitIdentityKey(
@@ -698,7 +759,23 @@ var unitInvocationSemantics = defineBoundarySemantics({
698
759
  semantics.deploymentTarget,
699
760
  semantics.instanceName
700
761
  );
701
- }
762
+ },
763
+ /**
764
+ * A call that reads its callee's name out of the environment
765
+ * reaches whichever resource the template wires that variable to.
766
+ * The logical id is the answer rather than the deployed name,
767
+ * because the invoked unit's own summary is keyed by the logical
768
+ * id and neither side ever writes the other's string.
769
+ */
770
+ groundName(semantics, deployment) {
771
+ const reference = calleeReference(semantics);
772
+ if (reference === null) {
773
+ return null;
774
+ }
775
+ const logicalId = deployment.pointsAt(reference);
776
+ return logicalId === null ? null : { ...semantics, instanceName: logicalId };
777
+ },
778
+ nameReference: calleeReference
702
779
  }
703
780
  });
704
781
 
package/dist/schemas.js CHANGED
@@ -17,7 +17,7 @@ import {
17
17
  TypeShapeSchema,
18
18
  typeDefinitionKey,
19
19
  withDefinitionsInlined
20
- } from "./chunk-QHFMZPEG.js";
20
+ } from "./chunk-PPQWK62O.js";
21
21
  export {
22
22
  BoundaryBindingSchema,
23
23
  ConfidenceInfoSchema,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@suss/ir-core",
3
- "version": "0.21.0",
3
+ "version": "0.21.1",
4
4
  "type": "module",
5
5
  "description": "Shared IR primitives for suss — type shapes, boundary bindings, source locations, and confidence. Imported by both @suss/behavioral-ir and @suss/intent-ir so neither depends on the other.",
6
6
  "keywords": [