@suss/ir-core 0.21.0 → 0.22.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.
@@ -323,6 +323,141 @@ var metricSemantics = defineBoundarySemantics({
323
323
  // src/semantics/rest.ts
324
324
  import { z as z6 } from "zod";
325
325
 
326
+ // src/dispatch.ts
327
+ function dispatchByType(table, value) {
328
+ const handler = table[value.type];
329
+ return handler(value);
330
+ }
331
+
332
+ // src/boundaryName.ts
333
+ var HOLE_SPLIT = /(\{[^}]*\})/;
334
+ var SUB_TOKEN = /\$\{([^}]*)\}/g;
335
+ var SUB_ESCAPE = /\$\{!/;
336
+ function isHole(piece) {
337
+ return piece.startsWith("{") && piece.endsWith("}");
338
+ }
339
+ function parseBoundaryName(name) {
340
+ const parts = name.split(HOLE_SPLIT).filter((piece) => piece !== "").map(
341
+ (piece) => isHole(piece) ? { type: "hole", label: piece.slice(1, -1) } : { type: "text", text: piece }
342
+ );
343
+ const only = parts.length === 1 ? parts[0] : void 0;
344
+ if (only !== void 0 && only.type === "hole") {
345
+ return { type: "reference", path: only.label.split(".") };
346
+ }
347
+ if (parts.some((part) => part.type === "hole")) {
348
+ return { type: "pattern", parts };
349
+ }
350
+ return { type: "literal", value: name };
351
+ }
352
+ var partString = {
353
+ text: (part) => part.text,
354
+ hole: (part) => patternHole(part.label)
355
+ };
356
+ var nameString = {
357
+ literal: (name) => name.value,
358
+ pattern: (name) => name.parts.map((part) => dispatchByType(partString, part)).join(""),
359
+ reference: (name) => patternHole(name.path.join("."))
360
+ };
361
+ function boundaryNameString(name) {
362
+ return dispatchByType(nameString, name);
363
+ }
364
+ function patternHole(label) {
365
+ return `{${label}}`;
366
+ }
367
+ function namePatternFromSub(value) {
368
+ if (Array.isArray(value)) {
369
+ return typeof value[0] === "string" ? namePatternFromSub(value[0]) : null;
370
+ }
371
+ if (typeof value !== "string") {
372
+ return null;
373
+ }
374
+ if (SUB_ESCAPE.test(value)) {
375
+ return null;
376
+ }
377
+ return value.replace(
378
+ SUB_TOKEN,
379
+ (_whole, inner) => patternHole(inner)
380
+ );
381
+ }
382
+ function namesNothing(name) {
383
+ return parseBoundaryName(name).type === "reference";
384
+ }
385
+ function hasNameHole(name) {
386
+ return parseBoundaryName(name).type !== "literal";
387
+ }
388
+ function namePatternKey(name) {
389
+ return dispatchByType(
390
+ {
391
+ literal: (parsed) => parsed.value,
392
+ pattern: (parsed) => boundaryNameString({
393
+ type: "pattern",
394
+ parts: parsed.parts.map(
395
+ (part) => part.type === "hole" ? { type: "hole", label: "" } : part
396
+ )
397
+ }),
398
+ reference: () => patternHole("")
399
+ },
400
+ parseBoundaryName(name)
401
+ );
402
+ }
403
+ function fixedTextLength(name) {
404
+ return dispatchByType(
405
+ {
406
+ literal: (parsed) => parsed.value.length,
407
+ pattern: (parsed) => parsed.parts.reduce(
408
+ (total, part) => total + (part.type === "text" ? part.text.length : 0),
409
+ 0
410
+ ),
411
+ reference: () => 0
412
+ },
413
+ parseBoundaryName(name)
414
+ );
415
+ }
416
+ function quote(text) {
417
+ return text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
418
+ }
419
+ function admits(pattern, name) {
420
+ const source = pattern.parts.map((part) => part.type === "hole" ? ".+" : quote(part.text)).join("");
421
+ return new RegExp(`^${source}$`).test(name);
422
+ }
423
+ function namesAgree(a, b) {
424
+ const left = parseBoundaryName(a);
425
+ const right = parseBoundaryName(b);
426
+ if (left.type === "reference" || right.type === "reference") {
427
+ return false;
428
+ }
429
+ if (left.type === "pattern" && right.type === "pattern") {
430
+ return namePatternKey(a) === namePatternKey(b);
431
+ }
432
+ if (left.type === "pattern") {
433
+ return admits(left, b);
434
+ }
435
+ if (right.type === "pattern") {
436
+ return admits(right, a);
437
+ }
438
+ return a === b;
439
+ }
440
+ function referenceName(reference) {
441
+ const path = [reference.root, ...reference.fields];
442
+ if (path.some((part) => part === "")) {
443
+ return null;
444
+ }
445
+ return boundaryNameString({ type: "reference", path });
446
+ }
447
+ function referenceOf(name) {
448
+ if (name.type !== "reference") {
449
+ return null;
450
+ }
451
+ const root = name.path[0];
452
+ if (root === void 0 || name.path.some((part) => part === "")) {
453
+ return null;
454
+ }
455
+ return { root, fields: name.path.slice(1) };
456
+ }
457
+ function referenceFromName(name) {
458
+ return referenceOf(parseBoundaryName(name));
459
+ }
460
+
326
461
  // src/urlPath.ts
327
462
  var SCHEME_ORIGIN = /^[a-zA-Z][a-zA-Z\d+.-]*:\/\/[^/]*/;
328
463
  var PROTOCOL_RELATIVE_ORIGIN = /^\/\/[^/]*/;
@@ -355,9 +490,9 @@ var RestSemanticsSchema = z6.object({
355
490
  declaredResponses: z6.array(z6.number()).optional()
356
491
  });
357
492
  var OPENING_HOLE = /^\{([^{}]+)\}(.*)$/;
358
- function variableOf(label) {
359
- const parts = label.split(".");
360
- return parts[parts.length - 1] ?? label;
493
+ function baseUrlReference(semantics) {
494
+ const label = OPENING_HOLE.exec(semantics.path ?? "")?.[1];
495
+ return label === void 0 ? null : referenceFromName(patternHole(label));
361
496
  }
362
497
  function normalizePath(path) {
363
498
  let normalized = path.replace(/:([a-zA-Z_]\w*)/g, "{$1}");
@@ -491,22 +626,20 @@ var restSemantics = defineBoundarySemantics({
491
626
  * route parameter, and `/orders/{id}` means every id rather than a
492
627
  * variable somebody set.
493
628
  */
494
- groundName(semantics, deployedAs) {
495
- if (semantics.path === null) {
496
- return null;
497
- }
498
- const opening = OPENING_HOLE.exec(semantics.path);
499
- if (opening === null) {
629
+ groundName(semantics, deployment) {
630
+ const reference = baseUrlReference(semantics);
631
+ if (reference === null) {
500
632
  return null;
501
633
  }
502
- const [, label, rest] = opening;
503
- const base = deployedAs(variableOf(label));
634
+ const base = deployment.setTo(reference);
504
635
  if (base === null) {
505
636
  return null;
506
637
  }
638
+ const rest = OPENING_HOLE.exec(semantics.path ?? "")?.[2] ?? "";
507
639
  const grounded = pathAfterOrigin(`${base}${rest}`);
508
640
  return { ...semantics, path: grounded === "" ? "/" : grounded };
509
641
  },
642
+ nameReference: baseUrlReference,
510
643
  ruleBoundary: {
511
644
  // "METHOD /path": one leading token, then an absolute path.
512
645
  claims(raw) {
@@ -596,6 +729,9 @@ var StorageSemanticsSchema = z9.object({
596
729
  */
597
730
  accessPath: z9.string().nullable()
598
731
  });
732
+ function containerReference(semantics) {
733
+ return semantics.container === null ? null : referenceFromName(semantics.container);
734
+ }
599
735
  var storageSemantics = defineBoundarySemantics({
600
736
  name: "storage",
601
737
  schema: StorageSemanticsSchema,
@@ -612,7 +748,21 @@ var storageSemantics = defineBoundarySemantics({
612
748
  exchangesHttpResponses: false,
613
749
  reportsUnpairedItself: false,
614
750
  identityKey: () => null,
615
- displayLabel: storageLabel
751
+ displayLabel: storageLabel,
752
+ /**
753
+ * A container the source states as a variable is whatever the
754
+ * deployment sets that variable to. `{SUBSCRIBERS_TABLE}` in the
755
+ * code and `prod-subscribers-v1` in the manifest are one table.
756
+ */
757
+ groundName(semantics, deployment) {
758
+ const reference = containerReference(semantics);
759
+ if (reference === null) {
760
+ return null;
761
+ }
762
+ const name = deployment.setTo(reference);
763
+ return name === null ? null : { ...semantics, container: name };
764
+ },
765
+ nameReference: containerReference
616
766
  }
617
767
  });
618
768
  function storageLabel(semantics) {
@@ -631,6 +781,9 @@ var UnitInvocationSemanticsSchema = DeployableUnitSchema.extend({
631
781
  name: z10.literal("unit-invocation"),
632
782
  instanceName: DeployableUnitSchema.shape.instanceName.nullable()
633
783
  });
784
+ function calleeReference(semantics) {
785
+ return semantics.instanceName === null ? null : referenceFromName(semantics.instanceName);
786
+ }
634
787
  var unitInvocationSemantics = defineBoundarySemantics({
635
788
  name: "unit-invocation",
636
789
  schema: UnitInvocationSemanticsSchema,
@@ -653,8 +806,13 @@ var unitInvocationSemantics = defineBoundarySemantics({
653
806
  * being reported as a problem here.
654
807
  */
655
808
  reportsUnpairedItself: false,
809
+ /**
810
+ * A callee the source states only as a variable is not a name for
811
+ * anything until the deployment fills it in, so it keys as nothing
812
+ * rather than as a bucket that would agree with itself alone.
813
+ */
656
814
  identityKey(semantics) {
657
- if (semantics.instanceName === null) {
815
+ if (semantics.instanceName === null || namesNothing(semantics.instanceName)) {
658
816
  return null;
659
817
  }
660
818
  return unitIdentityKey(
@@ -670,7 +828,23 @@ var unitInvocationSemantics = defineBoundarySemantics({
670
828
  semantics.deploymentTarget,
671
829
  semantics.instanceName
672
830
  );
673
- }
831
+ },
832
+ /**
833
+ * A call that reads its callee's name out of the environment
834
+ * reaches whichever resource the template wires that variable to.
835
+ * The logical id is the answer rather than the deployed name,
836
+ * because the invoked unit's own summary is keyed by the logical
837
+ * id and neither side ever writes the other's string.
838
+ */
839
+ groundName(semantics, deployment) {
840
+ const reference = calleeReference(semantics);
841
+ if (reference === null) {
842
+ return null;
843
+ }
844
+ const logicalId = deployment.pointsAt(reference);
845
+ return logicalId === null ? null : { ...semantics, instanceName: logicalId };
846
+ },
847
+ nameReference: calleeReference
674
848
  }
675
849
  });
676
850
 
@@ -860,6 +1034,19 @@ export {
860
1034
  channelsPair,
861
1035
  MessageBusSemanticsSchema,
862
1036
  MetricSemanticsSchema,
1037
+ dispatchByType,
1038
+ parseBoundaryName,
1039
+ boundaryNameString,
1040
+ patternHole,
1041
+ namePatternFromSub,
1042
+ namesNothing,
1043
+ hasNameHole,
1044
+ namePatternKey,
1045
+ fixedTextLength,
1046
+ namesAgree,
1047
+ referenceName,
1048
+ referenceOf,
1049
+ referenceFromName,
863
1050
  pathAfterOrigin,
864
1051
  statesAnOrigin,
865
1052
  RestSemanticsSchema,