@suss/recognize 0.20.0 → 0.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/ast.d.cts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { CallOps } from '@suss/extractor';
2
- import { L as LinkFunction } from './chain-_S93eC3O.cjs';
2
+ import { L as LinkFunction } from './chain-IogmSi0t.cjs';
3
3
  import '@suss/behavioral-ir';
4
4
 
5
5
  /**
package/dist/ast.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { CallOps } from '@suss/extractor';
2
- import { L as LinkFunction } from './chain-_S93eC3O.js';
2
+ import { L as LinkFunction } from './chain-IogmSi0t.js';
3
3
  import '@suss/behavioral-ir';
4
4
 
5
5
  /**
@@ -1,4 +1,4 @@
1
- import { MessageBusSemantics } from '@suss/behavioral-ir';
1
+ import { MessageBusSemantics, DeployableUnit } from '@suss/behavioral-ir';
2
2
  import { ReceiverOrigin, ValueOps, CallOps, UnsettledName } from '@suss/extractor';
3
3
 
4
4
  /**
@@ -136,6 +136,13 @@ interface AccessPathLink {
136
136
  interface ContainersLink {
137
137
  readonly asks: "containers";
138
138
  readonly in: OneArgument;
139
+ /**
140
+ * What one of them is. An entry keys the container by name and says
141
+ * what the call did there, which is how a batch write is written. A
142
+ * name is the container on its own, which is how a call that reads
143
+ * several parameters at once is written. Defaults to an entry.
144
+ */
145
+ readonly each?: "entry" | "name";
139
146
  }
140
147
  /**
141
148
  * Where a call states its inputs, when it states them as one object
@@ -307,9 +314,15 @@ interface MessageSendMethod {
307
314
  /** Where the call states the message, or the collection of them. */
308
315
  readonly input: OneArgument;
309
316
  }
317
+ /**
318
+ * What one invoke method does. An invoke states its whole request as
319
+ * one object the same way a send does, so both say where that object
320
+ * is and nothing else.
321
+ */
322
+ type UnitInvokeMethod = MessageSendMethod;
310
323
  type MethodMeaning = StorageMethod | SqlMethod | MessageSendMethod;
311
324
  /** What a chain produces when every link matches. */
312
- type Ending = StorageEnding | SqlEnding | MessageSendEnding;
325
+ type Ending = StorageEnding | SqlEnding | MessageSendEnding | UnitInvokeEnding;
313
326
  /** A storage access: one call, one thing it read or wrote. */
314
327
  interface StorageEnding {
315
328
  readonly yields: "storageAccess";
@@ -377,8 +390,13 @@ interface ManyIn {
377
390
  * the same way, so a pack states the parts in the order they join.
378
391
  */
379
392
  interface ChannelPart {
380
- /** The property the message states this part on. */
381
- readonly property: string;
393
+ /**
394
+ * The properties the message may state this part on, tried in order.
395
+ * A library that lets one destination be written more than one way
396
+ * lists each spelling: an SNS publish writes its topic as `TopicArn`
397
+ * or as `TargetArn`, and the two are the same part of the channel.
398
+ */
399
+ readonly property: readonly string[];
382
400
  /**
383
401
  * Where the property is written. A batch command states the queue
384
402
  * once beside the list of messages, so its channel part reads off
@@ -425,6 +443,29 @@ interface MessageSendEnding {
425
443
  */
426
444
  readonly unsettledName: UnsettledName;
427
445
  }
446
+ /**
447
+ * A call that hands a payload to one deployed unit, named on the call.
448
+ *
449
+ * The unit's name is read off the call's own input rather than off a
450
+ * message, because there is one callee per call however many messages a
451
+ * send takes. A name written as a fully-qualified cloud id is reduced
452
+ * to the resource segment, so an ARN and a bare name come out the same.
453
+ */
454
+ interface UnitInvokeEnding {
455
+ readonly yields: "unitInvoke";
456
+ /** The platform running the unit, in the IR's deployable-unit words. */
457
+ readonly platform: DeployableUnit["deploymentTarget"];
458
+ /** The properties the call may name the unit on, tried in order. */
459
+ readonly named: readonly string[];
460
+ /** The property the call states its payload on, when the pack can say. */
461
+ readonly payload?: string;
462
+ /**
463
+ * What a reader gives back for a name nothing in the source settles.
464
+ * A function name usually arrives through an env var, whose name both
465
+ * sides agree on, so `"reference"` keeps it.
466
+ */
467
+ readonly unsettledName: UnsettledName;
468
+ }
428
469
  /**
429
470
  * A pack's declaration for one kind of call: the links, the ending, and
430
471
  * a line of code it matches.
@@ -436,4 +477,4 @@ interface Chain<TMeaning = MethodMeaning> {
436
477
  readonly example: string | null;
437
478
  }
438
479
 
439
- export type { ArgumentPick as A, StorageEnding as B, Chain as C, SubjectLink as D, Ending as E, FromReceiver as F, ToReceiver as G, InterpolatesLink as I, KindAsAsked as K, LinkFunction as L, MethodMeaning as M, OneArgument as O, SqlMethod as S, ToArgument as T, MessageSendMethod as a, MessageLocation as b, ChannelPart as c, CallStep as d, StorageMethod as e, AccessKind as f, AccessPathLink as g, ArgumentsFrom as h, CallsLink as i, ContainerArgument as j, ContainerLink as k, ContainerRule as l, ContainersLink as m, InputLink as n, InputRule as o, Link as p, ManyIn as q, MatchStart as r, MessageSendEnding as s, MethodsLink as t, OneMessage as u, SelectorParamPick as v, SqlEnding as w, StartLink as x, StatedInputs as y, StatedRule as z };
480
+ export type { ArgumentPick as A, StorageEnding as B, Chain as C, SubjectLink as D, Ending as E, FromReceiver as F, ToReceiver as G, UnitInvokeEnding as H, InterpolatesLink as I, KindAsAsked as K, LinkFunction as L, MethodMeaning as M, OneArgument as O, SqlMethod as S, ToArgument as T, UnitInvokeMethod as U, MessageSendMethod as a, MessageLocation as b, ChannelPart as c, CallStep as d, StorageMethod as e, AccessKind as f, AccessPathLink as g, ArgumentsFrom as h, CallsLink as i, ContainerArgument as j, ContainerLink as k, ContainerRule as l, ContainersLink as m, InputLink as n, InputRule as o, Link as p, ManyIn as q, MatchStart as r, MessageSendEnding as s, MethodsLink as t, OneMessage as u, SelectorParamPick as v, SqlEnding as w, StartLink as x, StatedInputs as y, StatedRule as z };
@@ -1,4 +1,4 @@
1
- import { MessageBusSemantics } from '@suss/behavioral-ir';
1
+ import { MessageBusSemantics, DeployableUnit } from '@suss/behavioral-ir';
2
2
  import { ReceiverOrigin, ValueOps, CallOps, UnsettledName } from '@suss/extractor';
3
3
 
4
4
  /**
@@ -136,6 +136,13 @@ interface AccessPathLink {
136
136
  interface ContainersLink {
137
137
  readonly asks: "containers";
138
138
  readonly in: OneArgument;
139
+ /**
140
+ * What one of them is. An entry keys the container by name and says
141
+ * what the call did there, which is how a batch write is written. A
142
+ * name is the container on its own, which is how a call that reads
143
+ * several parameters at once is written. Defaults to an entry.
144
+ */
145
+ readonly each?: "entry" | "name";
139
146
  }
140
147
  /**
141
148
  * Where a call states its inputs, when it states them as one object
@@ -307,9 +314,15 @@ interface MessageSendMethod {
307
314
  /** Where the call states the message, or the collection of them. */
308
315
  readonly input: OneArgument;
309
316
  }
317
+ /**
318
+ * What one invoke method does. An invoke states its whole request as
319
+ * one object the same way a send does, so both say where that object
320
+ * is and nothing else.
321
+ */
322
+ type UnitInvokeMethod = MessageSendMethod;
310
323
  type MethodMeaning = StorageMethod | SqlMethod | MessageSendMethod;
311
324
  /** What a chain produces when every link matches. */
312
- type Ending = StorageEnding | SqlEnding | MessageSendEnding;
325
+ type Ending = StorageEnding | SqlEnding | MessageSendEnding | UnitInvokeEnding;
313
326
  /** A storage access: one call, one thing it read or wrote. */
314
327
  interface StorageEnding {
315
328
  readonly yields: "storageAccess";
@@ -377,8 +390,13 @@ interface ManyIn {
377
390
  * the same way, so a pack states the parts in the order they join.
378
391
  */
379
392
  interface ChannelPart {
380
- /** The property the message states this part on. */
381
- readonly property: string;
393
+ /**
394
+ * The properties the message may state this part on, tried in order.
395
+ * A library that lets one destination be written more than one way
396
+ * lists each spelling: an SNS publish writes its topic as `TopicArn`
397
+ * or as `TargetArn`, and the two are the same part of the channel.
398
+ */
399
+ readonly property: readonly string[];
382
400
  /**
383
401
  * Where the property is written. A batch command states the queue
384
402
  * once beside the list of messages, so its channel part reads off
@@ -425,6 +443,29 @@ interface MessageSendEnding {
425
443
  */
426
444
  readonly unsettledName: UnsettledName;
427
445
  }
446
+ /**
447
+ * A call that hands a payload to one deployed unit, named on the call.
448
+ *
449
+ * The unit's name is read off the call's own input rather than off a
450
+ * message, because there is one callee per call however many messages a
451
+ * send takes. A name written as a fully-qualified cloud id is reduced
452
+ * to the resource segment, so an ARN and a bare name come out the same.
453
+ */
454
+ interface UnitInvokeEnding {
455
+ readonly yields: "unitInvoke";
456
+ /** The platform running the unit, in the IR's deployable-unit words. */
457
+ readonly platform: DeployableUnit["deploymentTarget"];
458
+ /** The properties the call may name the unit on, tried in order. */
459
+ readonly named: readonly string[];
460
+ /** The property the call states its payload on, when the pack can say. */
461
+ readonly payload?: string;
462
+ /**
463
+ * What a reader gives back for a name nothing in the source settles.
464
+ * A function name usually arrives through an env var, whose name both
465
+ * sides agree on, so `"reference"` keeps it.
466
+ */
467
+ readonly unsettledName: UnsettledName;
468
+ }
428
469
  /**
429
470
  * A pack's declaration for one kind of call: the links, the ending, and
430
471
  * a line of code it matches.
@@ -436,4 +477,4 @@ interface Chain<TMeaning = MethodMeaning> {
436
477
  readonly example: string | null;
437
478
  }
438
479
 
439
- export type { ArgumentPick as A, StorageEnding as B, Chain as C, SubjectLink as D, Ending as E, FromReceiver as F, ToReceiver as G, InterpolatesLink as I, KindAsAsked as K, LinkFunction as L, MethodMeaning as M, OneArgument as O, SqlMethod as S, ToArgument as T, MessageSendMethod as a, MessageLocation as b, ChannelPart as c, CallStep as d, StorageMethod as e, AccessKind as f, AccessPathLink as g, ArgumentsFrom as h, CallsLink as i, ContainerArgument as j, ContainerLink as k, ContainerRule as l, ContainersLink as m, InputLink as n, InputRule as o, Link as p, ManyIn as q, MatchStart as r, MessageSendEnding as s, MethodsLink as t, OneMessage as u, SelectorParamPick as v, SqlEnding as w, StartLink as x, StatedInputs as y, StatedRule as z };
480
+ export type { ArgumentPick as A, StorageEnding as B, Chain as C, SubjectLink as D, Ending as E, FromReceiver as F, ToReceiver as G, UnitInvokeEnding as H, InterpolatesLink as I, KindAsAsked as K, LinkFunction as L, MethodMeaning as M, OneArgument as O, SqlMethod as S, ToArgument as T, UnitInvokeMethod as U, MessageSendMethod as a, MessageLocation as b, ChannelPart as c, CallStep as d, StorageMethod as e, AccessKind as f, AccessPathLink as g, ArgumentsFrom as h, CallsLink as i, ContainerArgument as j, ContainerLink as k, ContainerRule as l, ContainersLink as m, InputLink as n, InputRule as o, Link as p, ManyIn as q, MatchStart as r, MessageSendEnding as s, MethodsLink as t, OneMessage as u, SelectorParamPick as v, SqlEnding as w, StartLink as x, StatedInputs as y, StatedRule as z };
package/dist/index.cjs CHANGED
@@ -30,7 +30,8 @@ __export(index_exports, {
30
30
  pack: () => pack,
31
31
  runExamples: () => runExamples,
32
32
  sqlStatements: () => sqlStatements,
33
- storageCalls: () => storageCalls
33
+ storageCalls: () => storageCalls,
34
+ unitInvokes: () => unitInvokes
34
35
  });
35
36
  module.exports = __toCommonJS(index_exports);
36
37
 
@@ -192,7 +193,8 @@ function startsHere(chain, subject) {
192
193
  var YIELD = {
193
194
  storageAccess,
194
195
  sqlAccess,
195
- messageSend
196
+ messageSend,
197
+ unitInvoke
196
198
  };
197
199
  function storageAccess(matched) {
198
200
  const { subject, chain } = matched;
@@ -223,7 +225,7 @@ function accessEffect(matched, access) {
223
225
  storageSystem: ending.system,
224
226
  ...ending.transport === void 0 ? {} : { transport: ending.transport },
225
227
  scope: ending.scope,
226
- container: reached.entry === null ? containerOf(chain, selector, subject, unsettled) : reached.container,
228
+ container: reached.stated ? reached.container : containerOf(chain, selector, subject, unsettled),
227
229
  accessPath: accessPathOf(chain, subject, unsettled)
228
230
  }),
229
231
  callee: ops.calleeText(),
@@ -238,11 +240,24 @@ function accessEffect(matched, access) {
238
240
  }
239
241
  function reachedBy(chain, subject, unsettled) {
240
242
  const link = linkIn(chain, "containers");
241
- const map = link === null ? null : statedValue(subject, link.in);
242
- if (map === null) {
243
- return [{ container: null, entry: null }];
244
- }
245
- return map.entries(unsettled).map((entry) => ({ container: entry.key, entry: entry.value }));
243
+ const alone = [{ container: null, entry: null, stated: false }];
244
+ const stated = link === null ? null : statedValue(subject, link.in);
245
+ if (link === null || stated === null) {
246
+ return alone;
247
+ }
248
+ if (link.each === "name") {
249
+ const named = stated.items().map((item) => ({
250
+ container: item.name(unsettled),
251
+ entry: null,
252
+ stated: true
253
+ }));
254
+ return named.length === 0 ? alone : named;
255
+ }
256
+ return stated.entries(unsettled).map((entry) => ({
257
+ container: entry.key,
258
+ entry: entry.value,
259
+ stated: true
260
+ }));
246
261
  }
247
262
  function kindOf(kind, subject, unsettled) {
248
263
  if (typeof kind === "string") {
@@ -382,7 +397,7 @@ function channelOf(message, input, ending) {
382
397
  const parts = [];
383
398
  for (const part of ending.channel) {
384
399
  const holder = part.on === "theInput" ? input : message;
385
- const written = holder.property(part.property);
400
+ const written = firstWritten(holder, part.property);
386
401
  if (written === null) {
387
402
  if (part.whenAbsent === void 0) {
388
403
  return null;
@@ -398,6 +413,15 @@ function channelOf(message, input, ending) {
398
413
  }
399
414
  return parts.join(ending.channelSeparator ?? "#");
400
415
  }
416
+ function firstWritten(holder, properties) {
417
+ for (const property of properties) {
418
+ const written = holder.property(property);
419
+ if (written !== null) {
420
+ return written;
421
+ }
422
+ }
423
+ return null;
424
+ }
401
425
  function bodyOf(message, ending) {
402
426
  if (ending.body === void 0) {
403
427
  return {};
@@ -414,6 +438,50 @@ function routingKeyOf(message, ending) {
414
438
  const stated = message.property(ending.routingKey)?.text() ?? null;
415
439
  return stated === null || stated === "" ? {} : { routingKey: stated };
416
440
  }
441
+ function unitInvoke(matched) {
442
+ const { ops, subject, chain, recognition } = matched;
443
+ const ending = chain.ending;
444
+ const input = statedValue(
445
+ subject,
446
+ matched.meaning.input
447
+ );
448
+ if (input === null) {
449
+ return null;
450
+ }
451
+ return [
452
+ {
453
+ type: "interaction",
454
+ binding: (0, import_behavioral_ir.unitInvocationBinding)({
455
+ recognition,
456
+ deploymentTarget: ending.platform,
457
+ instanceName: invokedUnitIn(input, ending)
458
+ }),
459
+ callee: ops.calleeText(),
460
+ interaction: {
461
+ class: "unit-invoke",
462
+ ...payloadOf(input, ending)
463
+ }
464
+ }
465
+ ];
466
+ }
467
+ function invokedUnitIn(input, ending) {
468
+ for (const property of ending.named) {
469
+ const stated = input.property(property)?.name(ending.unsettledName) ?? null;
470
+ if (stated !== null && stated !== "") {
471
+ return (0, import_behavioral_ir.resourceNameIn)(stated);
472
+ }
473
+ }
474
+ return null;
475
+ }
476
+ function payloadOf(input, ending) {
477
+ if (ending.payload === void 0) {
478
+ return {};
479
+ }
480
+ const stated = (0, import_extractor.unwrapJsonStringify)(
481
+ input.property(ending.payload)?.asArg() ?? null
482
+ );
483
+ return stated === null ? {} : { payload: stated };
484
+ }
417
485
  function sqlAccess(matched) {
418
486
  const { ops, subject, method, chain, recognition } = matched;
419
487
  const ending = chain.ending;
@@ -517,7 +585,8 @@ function chainFrom(declared) {
517
585
  var DISPATCHED_ON = {
518
586
  storageAccess: "invocation",
519
587
  sqlAccess: "access",
520
- messageSend: "invocation"
588
+ messageSend: "invocation",
589
+ unitInvoke: "invocation"
521
590
  };
522
591
  function walkedBy(chains, walk2, recognizedAs) {
523
592
  return chains.filter((chain) => DISPATCHED_ON[chain.ending.yields] === walk2).map((chain) => compile(chain, recognizedAs));
@@ -541,6 +610,7 @@ function pack(name, matches, spec) {
541
610
  ...spec.recognizers ?? []
542
611
  ],
543
612
  ...access.length === 0 ? {} : { accessRecognizers: access },
613
+ ...spec.projectHelpers === void 0 ? {} : { projectHelpers: spec.projectHelpers },
544
614
  declarations: declarationsIn(matches)
545
615
  };
546
616
  }
@@ -551,10 +621,19 @@ function wireOf(ending) {
551
621
  if (ending.yields === "messageSend") {
552
622
  return ending.wire;
553
623
  }
624
+ if (ending.yields === "unitInvoke") {
625
+ return ending.platform;
626
+ }
554
627
  return ending.transport ?? ending.system;
555
628
  }
556
629
  function declaredName(ending) {
557
- return ending.yields === "messageSend" ? ending.wire : ending.system;
630
+ if (ending.yields === "messageSend") {
631
+ return ending.wire;
632
+ }
633
+ if (ending.yields === "unitInvoke") {
634
+ return ending.platform;
635
+ }
636
+ return ending.system;
558
637
  }
559
638
  function protocolOf(chains) {
560
639
  const wires = new Set(chains.map((chain) => wireOf(chain.ending)));
@@ -716,11 +795,43 @@ function chainFrom3(declared) {
716
795
  typeof says === "function" ? { asks: "container", from: says } : { asks: "container", argument: says }
717
796
  ),
718
797
  accessPath: (says) => adding({ asks: "accessPath", argument: says }),
719
- containersIn: (says) => adding({ asks: "containers", in: says }),
798
+ containersIn: (says, options) => adding({
799
+ asks: "containers",
800
+ in: says,
801
+ each: options?.each ?? "entry"
802
+ }),
720
803
  input: (says) => adding({ asks: "input", at: says }),
721
804
  example: (code) => chainFrom3({ ...declared, example: code })
722
805
  };
723
806
  }
807
+
808
+ // src/unitInvokes.ts
809
+ function unitInvokes(spec) {
810
+ const ending = {
811
+ yields: "unitInvoke",
812
+ platform: spec.platform,
813
+ named: spec.named,
814
+ ...spec.payload === void 0 ? {} : { payload: spec.payload },
815
+ unsettledName: spec.unsettledName ?? "reference"
816
+ };
817
+ return chainFrom4({
818
+ links: chainStart(spec.client),
819
+ ending,
820
+ example: null
821
+ });
822
+ }
823
+ function chainFrom4(declared) {
824
+ const adding = (link) => chainFrom4({ ...declared, links: [...declared.links, link] });
825
+ return {
826
+ declared,
827
+ methods: (table, options) => adding({
828
+ asks: "methods",
829
+ table,
830
+ ignoringCase: options?.ignoringCase ?? false
831
+ }),
832
+ example: (code) => chainFrom4({ ...declared, example: code })
833
+ };
834
+ }
724
835
  // Annotate the CommonJS export names for ESM import in node:
725
836
  0 && (module.exports = {
726
837
  compile,
@@ -733,5 +844,6 @@ function chainFrom3(declared) {
733
844
  pack,
734
845
  runExamples,
735
846
  sqlStatements,
736
- storageCalls
847
+ storageCalls,
848
+ unitInvokes
737
849
  });
package/dist/index.d.cts CHANGED
@@ -1,8 +1,8 @@
1
- import { ConstructedFrom, DeclaredBy, CallOps, InvocationRecognizer, PatternPack, UnsettledName, ReceiverOrigin, PackDeclarations } from '@suss/extractor';
2
- export { CallOps, ConstructedFrom, DeclaredBy, DeclaredMatch, OpsCarrier, PackDeclarations, PatternPack, ReceiverOrigin, UnsettledName, ValueEntry, ValueOps } from '@suss/extractor';
3
- import { C as Chain, M as MethodMeaning, a as MessageSendMethod, b as MessageLocation, c as ChannelPart, S as SqlMethod, I as InterpolatesLink, d as CallStep, e as StorageMethod, A as ArgumentPick, L as LinkFunction, O as OneArgument } from './chain-_S93eC3O.cjs';
4
- export { f as AccessKind, g as AccessPathLink, h as ArgumentsFrom, i as CallsLink, j as ContainerArgument, k as ContainerLink, l as ContainerRule, m as ContainersLink, E as Ending, F as FromReceiver, n as InputLink, o as InputRule, K as KindAsAsked, p as Link, q as ManyIn, r as MatchStart, s as MessageSendEnding, t as MethodsLink, u as OneMessage, v as SelectorParamPick, w as SqlEnding, x as StartLink, y as StatedInputs, z as StatedRule, B as StorageEnding, D as SubjectLink, T as ToArgument, G as ToReceiver } from './chain-_S93eC3O.cjs';
5
- import { Effect, MessageBusSemantics } from '@suss/behavioral-ir';
1
+ import { ConstructedFrom, DeclaredBy, CallOps, InvocationRecognizer, PatternPack, UnsettledName, ReceiverOrigin, ProjectHelpers, PackDeclarations } from '@suss/extractor';
2
+ export { CallOps, ConstructedFrom, DeclaredBy, DeclaredMatch, HelperDeclarations, HelperSink, HelperValue, OpsCarrier, PackDeclarations, PatternPack, ProjectHelper, ProjectHelpers, ReceiverOrigin, UnsettledName, ValueEntry, ValueOps } from '@suss/extractor';
3
+ import { C as Chain, M as MethodMeaning, a as MessageSendMethod, b as MessageLocation, c as ChannelPart, S as SqlMethod, I as InterpolatesLink, d as CallStep, e as StorageMethod, A as ArgumentPick, L as LinkFunction, O as OneArgument, U as UnitInvokeMethod } from './chain-IogmSi0t.cjs';
4
+ export { f as AccessKind, g as AccessPathLink, h as ArgumentsFrom, i as CallsLink, j as ContainerArgument, k as ContainerLink, l as ContainerRule, m as ContainersLink, E as Ending, F as FromReceiver, n as InputLink, o as InputRule, K as KindAsAsked, p as Link, q as ManyIn, r as MatchStart, s as MessageSendEnding, t as MethodsLink, u as OneMessage, v as SelectorParamPick, w as SqlEnding, x as StartLink, y as StatedInputs, z as StatedRule, B as StorageEnding, D as SubjectLink, T as ToArgument, G as ToReceiver, H as UnitInvokeEnding } from './chain-IogmSi0t.cjs';
5
+ import { Effect, MessageBusSemantics, DeployableUnit } from '@suss/behavioral-ir';
6
6
 
7
7
  /**
8
8
  * The small builders a pack writes its origins with, and the vocabulary
@@ -188,6 +188,12 @@ interface PackSpec {
188
188
  * function links, so the cost of staying here is visible.
189
189
  */
190
190
  recognizers?: InvocationRecognizer[];
191
+ /**
192
+ * Functions the project wrote in front of this library, read once
193
+ * across the project before extraction. What the pack makes of them
194
+ * joins the chains above for the rest of the run.
195
+ */
196
+ projectHelpers?: ProjectHelpers;
191
197
  }
192
198
  /** A pack, assembled from the calls it says it matches. */
193
199
  declare function pack(name: string, matches: readonly Match[], spec: PackSpec): PatternPack;
@@ -303,9 +309,12 @@ interface StorageCalls {
303
309
  accessPath(says: ArgumentPick): StorageCalls;
304
310
  /**
305
311
  * Where a call that reaches several containers at once states them.
306
- * Each entry becomes one effect, against the container its key says.
312
+ * Each entry becomes one effect, against the container its key says,
313
+ * or against the name itself where the call lists names alone.
307
314
  */
308
- containersIn(says: OneArgument): StorageCalls;
315
+ containersIn(says: OneArgument, options?: {
316
+ each?: "entry" | "name";
317
+ }): StorageCalls;
309
318
  /**
310
319
  * Where a call states its inputs, when it states them as one object.
311
320
  * A call that states none does not match, and a rule the pack wrote
@@ -320,4 +329,46 @@ interface StorageCalls {
320
329
  /** A pack that recognizes calls against a store. */
321
330
  declare function storageCalls(spec: StorageCallsSpec): StorageCalls;
322
331
 
323
- export { ArgumentPick, CallStep, Chain, ChannelPart, InterpolatesLink, LinkFunction, type Match, MessageLocation, MessageSendMethod, type MessageSends, type MessageSendsSpec, MethodMeaning, OneArgument, type PackSpec, type RanExample, type RunOverCode, SqlMethod, type SqlStatements, type SqlStatementsSpec, type StorageCalls, type StorageCallsSpec, StorageMethod, compile, constructedFrom, declarationsIn, declaredBy, examplesMissing, messageSends, opsIn, pack, runExamples, sqlStatements, storageCalls };
332
+ /**
333
+ * unitInvokes.ts: a pack that recognizes a call invoking one deployed
334
+ * unit by name.
335
+ *
336
+ * The AWS SDK shape is the one this was written against, and it is the
337
+ * same shape a send has: an operation is a command class and its
338
+ * arguments are one object, so the pack says which command and which of
339
+ * its properties says which unit the call reaches.
340
+ *
341
+ * client.send(new InvokeCommand({ FunctionName, Payload }))
342
+ */
343
+
344
+ interface UnitInvokesSpec {
345
+ /** The platform running the unit, in the IR's deployable-unit words. */
346
+ platform: DeployableUnit["deploymentTarget"];
347
+ /** The properties the call may name the unit on, tried in order. */
348
+ named: readonly string[];
349
+ /** The property the call states its payload on. */
350
+ payload?: string;
351
+ /**
352
+ * What a reader gives back for a name nothing settles. Defaults to
353
+ * keeping the reference, since a function name reaches the code
354
+ * through an env var far more often than it is written out.
355
+ */
356
+ unsettledName?: UnsettledName;
357
+ /** How the pack pins down the client its calls are on. */
358
+ client?: ReceiverOrigin;
359
+ }
360
+ /** A chain over invokes, and the links that can still be added. */
361
+ interface UnitInvokes {
362
+ /** Which methods invoke, and where each one states its request. */
363
+ methods(table: Readonly<Record<string, UnitInvokeMethod>>, options?: {
364
+ ignoringCase?: boolean;
365
+ }): UnitInvokes;
366
+ /** A line of code this matches, which the pack's tests run. */
367
+ example(code: string): UnitInvokes;
368
+ /** The links and the ending, as data. */
369
+ readonly declared: Chain<UnitInvokeMethod>;
370
+ }
371
+ /** A pack that recognizes a call invoking a deployed unit. */
372
+ declare function unitInvokes(spec: UnitInvokesSpec): UnitInvokes;
373
+
374
+ export { ArgumentPick, CallStep, Chain, ChannelPart, InterpolatesLink, LinkFunction, type Match, MessageLocation, MessageSendMethod, type MessageSends, type MessageSendsSpec, MethodMeaning, OneArgument, type PackSpec, type RanExample, type RunOverCode, SqlMethod, type SqlStatements, type SqlStatementsSpec, type StorageCalls, type StorageCallsSpec, StorageMethod, UnitInvokeMethod, type UnitInvokes, type UnitInvokesSpec, compile, constructedFrom, declarationsIn, declaredBy, examplesMissing, messageSends, opsIn, pack, runExamples, sqlStatements, storageCalls, unitInvokes };
package/dist/index.d.ts CHANGED
@@ -1,8 +1,8 @@
1
- import { ConstructedFrom, DeclaredBy, CallOps, InvocationRecognizer, PatternPack, UnsettledName, ReceiverOrigin, PackDeclarations } from '@suss/extractor';
2
- export { CallOps, ConstructedFrom, DeclaredBy, DeclaredMatch, OpsCarrier, PackDeclarations, PatternPack, ReceiverOrigin, UnsettledName, ValueEntry, ValueOps } from '@suss/extractor';
3
- import { C as Chain, M as MethodMeaning, a as MessageSendMethod, b as MessageLocation, c as ChannelPart, S as SqlMethod, I as InterpolatesLink, d as CallStep, e as StorageMethod, A as ArgumentPick, L as LinkFunction, O as OneArgument } from './chain-_S93eC3O.js';
4
- export { f as AccessKind, g as AccessPathLink, h as ArgumentsFrom, i as CallsLink, j as ContainerArgument, k as ContainerLink, l as ContainerRule, m as ContainersLink, E as Ending, F as FromReceiver, n as InputLink, o as InputRule, K as KindAsAsked, p as Link, q as ManyIn, r as MatchStart, s as MessageSendEnding, t as MethodsLink, u as OneMessage, v as SelectorParamPick, w as SqlEnding, x as StartLink, y as StatedInputs, z as StatedRule, B as StorageEnding, D as SubjectLink, T as ToArgument, G as ToReceiver } from './chain-_S93eC3O.js';
5
- import { Effect, MessageBusSemantics } from '@suss/behavioral-ir';
1
+ import { ConstructedFrom, DeclaredBy, CallOps, InvocationRecognizer, PatternPack, UnsettledName, ReceiverOrigin, ProjectHelpers, PackDeclarations } from '@suss/extractor';
2
+ export { CallOps, ConstructedFrom, DeclaredBy, DeclaredMatch, HelperDeclarations, HelperSink, HelperValue, OpsCarrier, PackDeclarations, PatternPack, ProjectHelper, ProjectHelpers, ReceiverOrigin, UnsettledName, ValueEntry, ValueOps } from '@suss/extractor';
3
+ import { C as Chain, M as MethodMeaning, a as MessageSendMethod, b as MessageLocation, c as ChannelPart, S as SqlMethod, I as InterpolatesLink, d as CallStep, e as StorageMethod, A as ArgumentPick, L as LinkFunction, O as OneArgument, U as UnitInvokeMethod } from './chain-IogmSi0t.js';
4
+ export { f as AccessKind, g as AccessPathLink, h as ArgumentsFrom, i as CallsLink, j as ContainerArgument, k as ContainerLink, l as ContainerRule, m as ContainersLink, E as Ending, F as FromReceiver, n as InputLink, o as InputRule, K as KindAsAsked, p as Link, q as ManyIn, r as MatchStart, s as MessageSendEnding, t as MethodsLink, u as OneMessage, v as SelectorParamPick, w as SqlEnding, x as StartLink, y as StatedInputs, z as StatedRule, B as StorageEnding, D as SubjectLink, T as ToArgument, G as ToReceiver, H as UnitInvokeEnding } from './chain-IogmSi0t.js';
5
+ import { Effect, MessageBusSemantics, DeployableUnit } from '@suss/behavioral-ir';
6
6
 
7
7
  /**
8
8
  * The small builders a pack writes its origins with, and the vocabulary
@@ -188,6 +188,12 @@ interface PackSpec {
188
188
  * function links, so the cost of staying here is visible.
189
189
  */
190
190
  recognizers?: InvocationRecognizer[];
191
+ /**
192
+ * Functions the project wrote in front of this library, read once
193
+ * across the project before extraction. What the pack makes of them
194
+ * joins the chains above for the rest of the run.
195
+ */
196
+ projectHelpers?: ProjectHelpers;
191
197
  }
192
198
  /** A pack, assembled from the calls it says it matches. */
193
199
  declare function pack(name: string, matches: readonly Match[], spec: PackSpec): PatternPack;
@@ -303,9 +309,12 @@ interface StorageCalls {
303
309
  accessPath(says: ArgumentPick): StorageCalls;
304
310
  /**
305
311
  * Where a call that reaches several containers at once states them.
306
- * Each entry becomes one effect, against the container its key says.
312
+ * Each entry becomes one effect, against the container its key says,
313
+ * or against the name itself where the call lists names alone.
307
314
  */
308
- containersIn(says: OneArgument): StorageCalls;
315
+ containersIn(says: OneArgument, options?: {
316
+ each?: "entry" | "name";
317
+ }): StorageCalls;
309
318
  /**
310
319
  * Where a call states its inputs, when it states them as one object.
311
320
  * A call that states none does not match, and a rule the pack wrote
@@ -320,4 +329,46 @@ interface StorageCalls {
320
329
  /** A pack that recognizes calls against a store. */
321
330
  declare function storageCalls(spec: StorageCallsSpec): StorageCalls;
322
331
 
323
- export { ArgumentPick, CallStep, Chain, ChannelPart, InterpolatesLink, LinkFunction, type Match, MessageLocation, MessageSendMethod, type MessageSends, type MessageSendsSpec, MethodMeaning, OneArgument, type PackSpec, type RanExample, type RunOverCode, SqlMethod, type SqlStatements, type SqlStatementsSpec, type StorageCalls, type StorageCallsSpec, StorageMethod, compile, constructedFrom, declarationsIn, declaredBy, examplesMissing, messageSends, opsIn, pack, runExamples, sqlStatements, storageCalls };
332
+ /**
333
+ * unitInvokes.ts: a pack that recognizes a call invoking one deployed
334
+ * unit by name.
335
+ *
336
+ * The AWS SDK shape is the one this was written against, and it is the
337
+ * same shape a send has: an operation is a command class and its
338
+ * arguments are one object, so the pack says which command and which of
339
+ * its properties says which unit the call reaches.
340
+ *
341
+ * client.send(new InvokeCommand({ FunctionName, Payload }))
342
+ */
343
+
344
+ interface UnitInvokesSpec {
345
+ /** The platform running the unit, in the IR's deployable-unit words. */
346
+ platform: DeployableUnit["deploymentTarget"];
347
+ /** The properties the call may name the unit on, tried in order. */
348
+ named: readonly string[];
349
+ /** The property the call states its payload on. */
350
+ payload?: string;
351
+ /**
352
+ * What a reader gives back for a name nothing settles. Defaults to
353
+ * keeping the reference, since a function name reaches the code
354
+ * through an env var far more often than it is written out.
355
+ */
356
+ unsettledName?: UnsettledName;
357
+ /** How the pack pins down the client its calls are on. */
358
+ client?: ReceiverOrigin;
359
+ }
360
+ /** A chain over invokes, and the links that can still be added. */
361
+ interface UnitInvokes {
362
+ /** Which methods invoke, and where each one states its request. */
363
+ methods(table: Readonly<Record<string, UnitInvokeMethod>>, options?: {
364
+ ignoringCase?: boolean;
365
+ }): UnitInvokes;
366
+ /** A line of code this matches, which the pack's tests run. */
367
+ example(code: string): UnitInvokes;
368
+ /** The links and the ending, as data. */
369
+ readonly declared: Chain<UnitInvokeMethod>;
370
+ }
371
+ /** A pack that recognizes a call invoking a deployed unit. */
372
+ declare function unitInvokes(spec: UnitInvokesSpec): UnitInvokes;
373
+
374
+ export { ArgumentPick, CallStep, Chain, ChannelPart, InterpolatesLink, LinkFunction, type Match, MessageLocation, MessageSendMethod, type MessageSends, type MessageSendsSpec, MethodMeaning, OneArgument, type PackSpec, type RanExample, type RunOverCode, SqlMethod, type SqlStatements, type SqlStatementsSpec, type StorageCalls, type StorageCallsSpec, StorageMethod, UnitInvokeMethod, type UnitInvokes, type UnitInvokesSpec, compile, constructedFrom, declarationsIn, declaredBy, examplesMissing, messageSends, opsIn, pack, runExamples, sqlStatements, storageCalls, unitInvokes };
package/dist/index.js CHANGED
@@ -1,5 +1,10 @@
1
1
  // src/compile.ts
2
- import { messageBusBinding, storageBinding } from "@suss/behavioral-ir";
2
+ import {
3
+ messageBusBinding,
4
+ resourceNameIn,
5
+ storageBinding,
6
+ unitInvocationBinding
7
+ } from "@suss/behavioral-ir";
3
8
  import { unwrapJsonStringify } from "@suss/extractor";
4
9
  import { readSqlAccess, sqlFromParts } from "@suss/sql";
5
10
 
@@ -156,7 +161,8 @@ function startsHere(chain, subject) {
156
161
  var YIELD = {
157
162
  storageAccess,
158
163
  sqlAccess,
159
- messageSend
164
+ messageSend,
165
+ unitInvoke
160
166
  };
161
167
  function storageAccess(matched) {
162
168
  const { subject, chain } = matched;
@@ -187,7 +193,7 @@ function accessEffect(matched, access) {
187
193
  storageSystem: ending.system,
188
194
  ...ending.transport === void 0 ? {} : { transport: ending.transport },
189
195
  scope: ending.scope,
190
- container: reached.entry === null ? containerOf(chain, selector, subject, unsettled) : reached.container,
196
+ container: reached.stated ? reached.container : containerOf(chain, selector, subject, unsettled),
191
197
  accessPath: accessPathOf(chain, subject, unsettled)
192
198
  }),
193
199
  callee: ops.calleeText(),
@@ -202,11 +208,24 @@ function accessEffect(matched, access) {
202
208
  }
203
209
  function reachedBy(chain, subject, unsettled) {
204
210
  const link = linkIn(chain, "containers");
205
- const map = link === null ? null : statedValue(subject, link.in);
206
- if (map === null) {
207
- return [{ container: null, entry: null }];
208
- }
209
- return map.entries(unsettled).map((entry) => ({ container: entry.key, entry: entry.value }));
211
+ const alone = [{ container: null, entry: null, stated: false }];
212
+ const stated = link === null ? null : statedValue(subject, link.in);
213
+ if (link === null || stated === null) {
214
+ return alone;
215
+ }
216
+ if (link.each === "name") {
217
+ const named = stated.items().map((item) => ({
218
+ container: item.name(unsettled),
219
+ entry: null,
220
+ stated: true
221
+ }));
222
+ return named.length === 0 ? alone : named;
223
+ }
224
+ return stated.entries(unsettled).map((entry) => ({
225
+ container: entry.key,
226
+ entry: entry.value,
227
+ stated: true
228
+ }));
210
229
  }
211
230
  function kindOf(kind, subject, unsettled) {
212
231
  if (typeof kind === "string") {
@@ -346,7 +365,7 @@ function channelOf(message, input, ending) {
346
365
  const parts = [];
347
366
  for (const part of ending.channel) {
348
367
  const holder = part.on === "theInput" ? input : message;
349
- const written = holder.property(part.property);
368
+ const written = firstWritten(holder, part.property);
350
369
  if (written === null) {
351
370
  if (part.whenAbsent === void 0) {
352
371
  return null;
@@ -362,6 +381,15 @@ function channelOf(message, input, ending) {
362
381
  }
363
382
  return parts.join(ending.channelSeparator ?? "#");
364
383
  }
384
+ function firstWritten(holder, properties) {
385
+ for (const property of properties) {
386
+ const written = holder.property(property);
387
+ if (written !== null) {
388
+ return written;
389
+ }
390
+ }
391
+ return null;
392
+ }
365
393
  function bodyOf(message, ending) {
366
394
  if (ending.body === void 0) {
367
395
  return {};
@@ -378,6 +406,50 @@ function routingKeyOf(message, ending) {
378
406
  const stated = message.property(ending.routingKey)?.text() ?? null;
379
407
  return stated === null || stated === "" ? {} : { routingKey: stated };
380
408
  }
409
+ function unitInvoke(matched) {
410
+ const { ops, subject, chain, recognition } = matched;
411
+ const ending = chain.ending;
412
+ const input = statedValue(
413
+ subject,
414
+ matched.meaning.input
415
+ );
416
+ if (input === null) {
417
+ return null;
418
+ }
419
+ return [
420
+ {
421
+ type: "interaction",
422
+ binding: unitInvocationBinding({
423
+ recognition,
424
+ deploymentTarget: ending.platform,
425
+ instanceName: invokedUnitIn(input, ending)
426
+ }),
427
+ callee: ops.calleeText(),
428
+ interaction: {
429
+ class: "unit-invoke",
430
+ ...payloadOf(input, ending)
431
+ }
432
+ }
433
+ ];
434
+ }
435
+ function invokedUnitIn(input, ending) {
436
+ for (const property of ending.named) {
437
+ const stated = input.property(property)?.name(ending.unsettledName) ?? null;
438
+ if (stated !== null && stated !== "") {
439
+ return resourceNameIn(stated);
440
+ }
441
+ }
442
+ return null;
443
+ }
444
+ function payloadOf(input, ending) {
445
+ if (ending.payload === void 0) {
446
+ return {};
447
+ }
448
+ const stated = unwrapJsonStringify(
449
+ input.property(ending.payload)?.asArg() ?? null
450
+ );
451
+ return stated === null ? {} : { payload: stated };
452
+ }
381
453
  function sqlAccess(matched) {
382
454
  const { ops, subject, method, chain, recognition } = matched;
383
455
  const ending = chain.ending;
@@ -481,7 +553,8 @@ function chainFrom(declared) {
481
553
  var DISPATCHED_ON = {
482
554
  storageAccess: "invocation",
483
555
  sqlAccess: "access",
484
- messageSend: "invocation"
556
+ messageSend: "invocation",
557
+ unitInvoke: "invocation"
485
558
  };
486
559
  function walkedBy(chains, walk2, recognizedAs) {
487
560
  return chains.filter((chain) => DISPATCHED_ON[chain.ending.yields] === walk2).map((chain) => compile(chain, recognizedAs));
@@ -505,6 +578,7 @@ function pack(name, matches, spec) {
505
578
  ...spec.recognizers ?? []
506
579
  ],
507
580
  ...access.length === 0 ? {} : { accessRecognizers: access },
581
+ ...spec.projectHelpers === void 0 ? {} : { projectHelpers: spec.projectHelpers },
508
582
  declarations: declarationsIn(matches)
509
583
  };
510
584
  }
@@ -515,10 +589,19 @@ function wireOf(ending) {
515
589
  if (ending.yields === "messageSend") {
516
590
  return ending.wire;
517
591
  }
592
+ if (ending.yields === "unitInvoke") {
593
+ return ending.platform;
594
+ }
518
595
  return ending.transport ?? ending.system;
519
596
  }
520
597
  function declaredName(ending) {
521
- return ending.yields === "messageSend" ? ending.wire : ending.system;
598
+ if (ending.yields === "messageSend") {
599
+ return ending.wire;
600
+ }
601
+ if (ending.yields === "unitInvoke") {
602
+ return ending.platform;
603
+ }
604
+ return ending.system;
522
605
  }
523
606
  function protocolOf(chains) {
524
607
  const wires = new Set(chains.map((chain) => wireOf(chain.ending)));
@@ -680,11 +763,43 @@ function chainFrom3(declared) {
680
763
  typeof says === "function" ? { asks: "container", from: says } : { asks: "container", argument: says }
681
764
  ),
682
765
  accessPath: (says) => adding({ asks: "accessPath", argument: says }),
683
- containersIn: (says) => adding({ asks: "containers", in: says }),
766
+ containersIn: (says, options) => adding({
767
+ asks: "containers",
768
+ in: says,
769
+ each: options?.each ?? "entry"
770
+ }),
684
771
  input: (says) => adding({ asks: "input", at: says }),
685
772
  example: (code) => chainFrom3({ ...declared, example: code })
686
773
  };
687
774
  }
775
+
776
+ // src/unitInvokes.ts
777
+ function unitInvokes(spec) {
778
+ const ending = {
779
+ yields: "unitInvoke",
780
+ platform: spec.platform,
781
+ named: spec.named,
782
+ ...spec.payload === void 0 ? {} : { payload: spec.payload },
783
+ unsettledName: spec.unsettledName ?? "reference"
784
+ };
785
+ return chainFrom4({
786
+ links: chainStart(spec.client),
787
+ ending,
788
+ example: null
789
+ });
790
+ }
791
+ function chainFrom4(declared) {
792
+ const adding = (link) => chainFrom4({ ...declared, links: [...declared.links, link] });
793
+ return {
794
+ declared,
795
+ methods: (table, options) => adding({
796
+ asks: "methods",
797
+ table,
798
+ ignoringCase: options?.ignoringCase ?? false
799
+ }),
800
+ example: (code) => chainFrom4({ ...declared, example: code })
801
+ };
802
+ }
688
803
  export {
689
804
  compile,
690
805
  constructedFrom,
@@ -696,5 +811,6 @@ export {
696
811
  pack,
697
812
  runExamples,
698
813
  sqlStatements,
699
- storageCalls
814
+ storageCalls,
815
+ unitInvokes
700
816
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@suss/recognize",
3
- "version": "0.20.0",
3
+ "version": "0.21.0",
4
4
  "type": "module",
5
5
  "description": "Write a pack as data: a chain of named links that any language adapter with the executor ops can run.",
6
6
  "keywords": [
@@ -49,9 +49,9 @@
49
49
  "typecheck": "tsc --noEmit"
50
50
  },
51
51
  "dependencies": {
52
- "@suss/behavioral-ir": "0.20.0",
53
- "@suss/extractor": "0.20.0",
54
- "@suss/sql": "0.20.0"
52
+ "@suss/behavioral-ir": "0.21.0",
53
+ "@suss/extractor": "0.21.0",
54
+ "@suss/sql": "0.21.0"
55
55
  },
56
56
  "devDependencies": {
57
57
  "tsup": "*",