@suss/recognize 0.33.1 → 0.34.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.cjs CHANGED
@@ -63,6 +63,7 @@ function opsIn(ctx) {
63
63
  // src/compile.ts
64
64
  var MAX_RECEIVER_HOPS = 8;
65
65
  function compile(chain, recognition) {
66
+ const receiverMethods = methodsWhoseReceiversAreAsked(chain);
66
67
  return (_call, ctx) => {
67
68
  const ops = opsIn(ctx);
68
69
  if (ops === null) {
@@ -83,6 +84,9 @@ function compile(chain, recognition) {
83
84
  if (methods === null) {
84
85
  return null;
85
86
  }
87
+ if (receiverMethods !== null) {
88
+ ops.readingReceivers?.(receiverMethods);
89
+ }
86
90
  for (const subject of subjectsOf(chain, ops)) {
87
91
  const method = operationOf(subject);
88
92
  const meaning = method === null ? null : listed(methods, method);
@@ -101,6 +105,14 @@ function compile(chain, recognition) {
101
105
  return null;
102
106
  };
103
107
  }
108
+ function methodsWhoseReceiversAreAsked(chain) {
109
+ const start = linkIn(chain, "start");
110
+ const table = methodsIn(chain);
111
+ if (start === null || start.at.starts !== "receiver" || start.at.origin.origin !== "constructed" || linkIn(chain, "subject") !== null || table === null || table.ignoringCase) {
112
+ return null;
113
+ }
114
+ return new Set(Object.keys(table.table));
115
+ }
104
116
  function linkIn(chain, asks) {
105
117
  const link = chain.links.find((candidate) => candidate.asks === asks);
106
118
  return link ?? null;
@@ -134,7 +146,23 @@ function listed(link, method) {
134
146
  }
135
147
  function subjectsOf(chain, ops) {
136
148
  const link = linkIn(chain, "subject");
137
- return link === null ? [ops] : walk([ops], link.of);
149
+ if (link === null) {
150
+ return [ops];
151
+ }
152
+ announceArgumentReads(link.of, ops);
153
+ return walk([ops], link.of);
154
+ }
155
+ function announceArgumentReads(steps, ops) {
156
+ const first = steps[0];
157
+ if (first === void 0 || first.to !== "argument") {
158
+ return;
159
+ }
160
+ const at = first.at;
161
+ if (typeof at === "number") {
162
+ ops.readingArguments?.(at, at);
163
+ return;
164
+ }
165
+ ops.readingArguments?.(at.from);
138
166
  }
139
167
  var STEP = {
140
168
  receiver: (step, ops) => receiversOf(ops, step.method),
@@ -216,9 +244,24 @@ function accessEffect(matched, access) {
216
244
  const ending = chain.ending;
217
245
  const { input, kind, reached, unsettled } = access;
218
246
  const stated = { input, entry: reached.entry, kind };
219
- const selector = namesFor(meaning.selector, subject, stated, unsettled);
220
- const fields = namesFor(meaning.fields, subject, stated, unsettled);
221
- return {
247
+ const listening = ops.statesSlots !== void 0;
248
+ const selectorRead = listening ? /* @__PURE__ */ new Map() : null;
249
+ const fieldsRead = listening ? /* @__PURE__ */ new Map() : null;
250
+ const selector = namesFor(
251
+ meaning.selector,
252
+ subject,
253
+ stated,
254
+ unsettled,
255
+ selectorRead
256
+ );
257
+ const fields = namesFor(
258
+ meaning.fields,
259
+ subject,
260
+ stated,
261
+ unsettled,
262
+ fieldsRead
263
+ );
264
+ const effect = {
222
265
  type: "interaction",
223
266
  binding: (0, import_behavioral_ir.storageBinding)({
224
267
  recognition,
@@ -237,6 +280,69 @@ function accessEffect(matched, access) {
237
280
  ...selector.length > 0 ? { selector } : {}
238
281
  }
239
282
  };
283
+ const slots = [
284
+ ...slotsRead("selector", selector, selectorRead),
285
+ ...slotsRead("field", fields, fieldsRead)
286
+ ];
287
+ if (slots.length > 0) {
288
+ ops.statesSlots?.(effect, slots);
289
+ }
290
+ return effect;
291
+ }
292
+ function slotsRead(slot, names, read) {
293
+ if (read === null) {
294
+ return [];
295
+ }
296
+ return [...new Set(names)].flatMap(
297
+ (name) => (read.get(name) ?? []).map((value) => ({ slot, name, value }))
298
+ );
299
+ }
300
+ function noteRead(read, name, value) {
301
+ const already = read.get(name);
302
+ if (already === void 0) {
303
+ read.set(name, [value]);
304
+ return;
305
+ }
306
+ if (!already.includes(value)) {
307
+ already.push(value);
308
+ }
309
+ }
310
+ function recording(value, read) {
311
+ return {
312
+ text: () => value.text(),
313
+ name: (unsettled) => value.name(unsettled),
314
+ ...value.names === void 0 ? {} : { names: (cap) => value.names?.(cap) ?? null },
315
+ flag: () => value.flag(),
316
+ entries: (unsettled) => value.entries(unsettled).map((entry) => {
317
+ if (entry.key !== null) {
318
+ noteRead(read, entry.key, entry.value);
319
+ }
320
+ return { key: entry.key, value: recording(entry.value, read) };
321
+ }),
322
+ items: () => value.items().map((item) => recording(item, read)),
323
+ property: (name) => {
324
+ const inside = value.property(name);
325
+ if (inside === null) {
326
+ return null;
327
+ }
328
+ noteRead(read, name, inside);
329
+ return recording(inside, read);
330
+ },
331
+ asArg: () => value.asArg(),
332
+ parts: () => value.parts(),
333
+ holes: () => value.holes(),
334
+ ...value.interpolated === void 0 ? {} : { interpolated: () => value.interpolated?.() ?? [] }
335
+ };
336
+ }
337
+ function watched(inputs, read) {
338
+ if (read === null) {
339
+ return inputs;
340
+ }
341
+ return {
342
+ ...inputs,
343
+ input: recording(inputs.input, read),
344
+ entry: inputs.entry === null ? null : recording(inputs.entry, read)
345
+ };
240
346
  }
241
347
  function reachedBy(chain, subject, unsettled) {
242
348
  const link = linkIn(chain, "containers");
@@ -315,7 +421,7 @@ var NOTHING_STATED = {
315
421
  parts: () => null,
316
422
  holes: () => []
317
423
  };
318
- function namesFor(says, subject, stated, unsettled) {
424
+ function namesFor(says, subject, stated, unsettled, read = null) {
319
425
  if (says === void 0) {
320
426
  return [];
321
427
  }
@@ -324,7 +430,7 @@ function namesFor(says, subject, stated, unsettled) {
324
430
  }
325
431
  if (typeof says === "function") {
326
432
  const input2 = stated.input;
327
- return input2 === null ? [] : [...says({ ...stated, input: input2 })];
433
+ return input2 === null ? [] : [...says(watched({ ...stated, input: input2 }, read))];
328
434
  }
329
435
  if ("selectorParam" in says) {
330
436
  return [...subject.parameterReadsAt?.(says.selectorParam) ?? []];
@@ -334,7 +440,7 @@ function namesFor(says, subject, stated, unsettled) {
334
440
  return namesAt(subject, pointed, unsettled);
335
441
  }
336
442
  const input = statedValue(subject, pointed.of) ?? NOTHING_STATED;
337
- return [...pointed.by({ ...stated, input })];
443
+ return [...pointed.by(watched({ ...stated, input }, read))];
338
444
  }
339
445
  function namesAt(subject, pick, unsettled) {
340
446
  if (pick === void 0) {
@@ -375,20 +481,27 @@ function messageSend(matched) {
375
481
  }
376
482
  const messages = messagesIn(input, ending.messages);
377
483
  const sent = messages.length === 0 ? [NOTHING_STATED] : messages;
378
- return sent.map((message) => ({
379
- type: "interaction",
380
- binding: (0, import_behavioral_ir.messageBusBinding)({
381
- recognition,
382
- messageBus: ending.wire,
383
- channel: channelOf(message, input, ending)
384
- }),
385
- callee: ops.calleeText(),
386
- interaction: {
387
- class: "message-send",
388
- ...bodyOf(message, ending),
389
- ...routingKeyOf(message, ending)
484
+ const effects = [];
485
+ for (const message of sent) {
486
+ const channels = channelsOf({ message, input, ending });
487
+ for (const channel of channels) {
488
+ effects.push({
489
+ type: "interaction",
490
+ binding: (0, import_behavioral_ir.messageBusBinding)({
491
+ recognition,
492
+ messageBus: ending.wire,
493
+ channel
494
+ }),
495
+ callee: ops.calleeText(),
496
+ interaction: {
497
+ class: "message-send",
498
+ ...bodyOf(message, ending),
499
+ ...routingKeyOf(message, ending)
500
+ }
501
+ });
390
502
  }
391
- }));
503
+ }
504
+ return effects;
392
505
  }
393
506
  function messagesIn(input, location) {
394
507
  if (location.each === "theInput") {
@@ -397,25 +510,47 @@ function messagesIn(input, location) {
397
510
  const collection = input.property(location.property);
398
511
  return collection === null ? [] : collection.items();
399
512
  }
400
- function channelOf(message, input, ending) {
401
- const parts = [];
402
- for (const part of ending.channel) {
403
- const holder = part.on === "theInput" ? input : message;
404
- const written = firstWritten(holder, part.property);
405
- if (written === null) {
406
- if (part.whenAbsent === void 0) {
407
- return null;
408
- }
409
- parts.push(part.whenAbsent);
410
- continue;
411
- }
412
- const stated = written.name(part.unsettled ?? ending.unsettledName);
413
- if (stated === null || stated === "") {
414
- return null;
513
+ var CHANNEL_CAP = 16;
514
+ function oneName(written, unsettled) {
515
+ const stated = written.name(unsettled);
516
+ return stated === null || stated === "" ? null : [stated];
517
+ }
518
+ function everyString(written, unsettled) {
519
+ const each = written.names?.(CHANNEL_CAP) ?? null;
520
+ if (each === null || each.length < 2 || each.includes("")) {
521
+ return oneName(written, unsettled);
522
+ }
523
+ return each;
524
+ }
525
+ function channelsOf(sending) {
526
+ const each = channelsRead(sending, "everyString");
527
+ return each.length > CHANNEL_CAP ? channelsRead(sending, "oneName") : each;
528
+ }
529
+ function channelsRead(sending, read) {
530
+ const separator = sending.ending.channelSeparator ?? "#";
531
+ let channels = null;
532
+ for (const part of sending.ending.channel) {
533
+ const values = partValues(part, sending, read);
534
+ if (values === null) {
535
+ return [null];
415
536
  }
416
- parts.push(stated);
537
+ channels = channels === null ? values : crossed(channels, values, separator);
417
538
  }
418
- return parts.join(ending.channelSeparator ?? "#");
539
+ return channels ?? [""];
540
+ }
541
+ function crossed(heads, values, separator) {
542
+ return heads.flatMap(
543
+ (head) => values.map((value) => `${head}${separator}${value}`)
544
+ );
545
+ }
546
+ function partValues(part, sending, read) {
547
+ const holder = part.on === "theInput" ? sending.input : sending.message;
548
+ const written = firstWritten(holder, part.property);
549
+ if (written === null) {
550
+ return part.whenAbsent === void 0 ? null : [part.whenAbsent];
551
+ }
552
+ const unsettled = part.unsettled ?? sending.ending.unsettledName;
553
+ return read === "everyString" ? everyString(written, unsettled) : oneName(written, unsettled);
419
554
  }
420
555
  function firstWritten(holder, properties) {
421
556
  for (const property of properties) {
@@ -498,28 +633,68 @@ function sqlAccess(matched) {
498
633
  namesInHoles(chain, stated.value),
499
634
  settledHoles(stated.value)
500
635
  );
501
- const accesses = (0, import_sql.readSqlAccess)(statement, { dialect: ending.dialect });
502
- return accesses.length === 0 ? null : accesses.map((access) => ({
503
- type: "interaction",
504
- binding: (0, import_behavioral_ir.storageBinding)({
505
- recognition,
506
- storageSystem: ending.system,
507
- ...ending.transport === void 0 ? {} : { transport: ending.transport },
508
- // A statement that qualifies its table says which namespace
509
- // the access is in, and the pack's own scope is the fallback
510
- // for a statement that leaves it out.
511
- scope: access.qualifier[access.qualifier.length - 1] ?? ending.scope,
512
- container: access.table
513
- }),
514
- callee: ops.calleeText(),
515
- interaction: {
516
- class: "storage-access",
517
- kind: access.kind,
518
- fields: access.fields,
519
- ...access.selector.length > 0 ? { selector: access.selector } : {},
520
- operation: method
636
+ const accesses = (0, import_sql.readSqlAccess)(statement, {
637
+ dialect: ending.dialect,
638
+ placeholders: ops.statesSlots !== void 0
639
+ });
640
+ if (accesses.length === 0) {
641
+ return null;
642
+ }
643
+ const values = placeholderValues(
644
+ stated,
645
+ subject,
646
+ matched.meaning.parameters
647
+ );
648
+ return accesses.map((access) => {
649
+ const effect = {
650
+ type: "interaction",
651
+ binding: (0, import_behavioral_ir.storageBinding)({
652
+ recognition,
653
+ storageSystem: ending.system,
654
+ ...ending.transport === void 0 ? {} : { transport: ending.transport },
655
+ // A statement that qualifies its table says which namespace
656
+ // the access is in, and the pack's own scope is the fallback
657
+ // for a statement that leaves it out.
658
+ scope: access.qualifier[access.qualifier.length - 1] ?? ending.scope,
659
+ container: access.table
660
+ }),
661
+ callee: ops.calleeText(),
662
+ interaction: {
663
+ class: "storage-access",
664
+ kind: access.kind,
665
+ fields: access.fields,
666
+ ...access.selector.length > 0 ? { selector: access.selector } : {},
667
+ operation: method
668
+ }
669
+ };
670
+ const slots = (access.placeholders ?? []).flatMap((one) => {
671
+ const value = placeholderValue(values, one.placeholder);
672
+ return value === null ? [] : [{ slot: SLOT_OF[one.clause], name: one.field, value }];
673
+ });
674
+ if (slots.length > 0) {
675
+ ops.statesSlots?.(effect, slots);
521
676
  }
522
- }));
677
+ return effect;
678
+ });
679
+ }
680
+ var SLOT_OF = {
681
+ fields: "field",
682
+ selector: "selector"
683
+ };
684
+ function placeholderValues(stated, subject, says) {
685
+ const writesItsOwn = stated.parts.some((part) => /\$\d/.test(part));
686
+ if (stated.parts.length > 1 && !writesItsOwn) {
687
+ return { numbered: stated.value.interpolated?.() ?? [], named: null };
688
+ }
689
+ const picks = says === void 0 ? [] : Array.isArray(says) ? says : [says];
690
+ const given = picks.map((pick) => statedValue(subject, pick)).find((value) => value !== null);
691
+ return given === void 0 ? { numbered: [], named: null } : { numbered: given.items(), named: given };
692
+ }
693
+ function placeholderValue(values, placeholder) {
694
+ if (typeof placeholder === "number") {
695
+ return values.numbered[placeholder - 1] ?? null;
696
+ }
697
+ return values.named?.property(placeholder) ?? null;
523
698
  }
524
699
  function statementIn(subject, says) {
525
700
  const picks = Array.isArray(says) ? says : [says];
@@ -711,8 +886,8 @@ function describe(chain) {
711
886
  ];
712
887
  return {
713
888
  name: declaredName(chain.ending),
714
- // A method table with a rule inside it is still a table, so that
715
- // link stays counted as data and the rule is priced beside it.
889
+ // A method table with a rule inside still counts as a data link. The
890
+ // rule is counted on its own, as a function link.
716
891
  dataLinks: chain.links.length - links.length,
717
892
  functionLinks: written.map((rule) => rule.asks),
718
893
  astLinks: written.filter((rule) => rule.reachesAst).map((rule) => rule.asks),
package/dist/index.d.cts CHANGED
@@ -1,7 +1,7 @@
1
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-CVG6Jnr-.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 ScopeLink, w as SelectorParamPick, x as SqlEnding, y as StartLink, z as StatedInputs, B as StatedRule, D as StorageEnding, G as SubjectLink, T as ToArgument, H as ToReceiver, J as UnitInvokeEnding } from './chain-CVG6Jnr-.cjs';
2
+ export { CallOps, ClassOps, 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-DYU9ZdzF.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 ScopeLink, w as SelectorParamPick, x as SqlEnding, y as StartLink, z as StatedInputs, B as StatedRule, D as StorageEnding, G as SubjectLink, T as ToArgument, H as ToReceiver, J as UnitInvokeEnding } from './chain-DYU9ZdzF.cjs';
5
5
  import { Effect, MessageBusSemantics, DeployableUnit } from '@suss/behavioral-ir';
6
6
 
7
7
  /**
@@ -15,8 +15,8 @@ import { Effect, MessageBusSemantics, DeployableUnit } from '@suss/behavioral-ir
15
15
 
16
16
  /**
17
17
  * A receiver whose method one of these modules declared. Pass every
18
- * module that ships the same client, the way three packages all speak
19
- * one wire protocol.
18
+ * module that ships the same client, for example several packages that
19
+ * implement one wire protocol.
20
20
  */
21
21
  declare function declaredBy(...importedFrom: readonly string[]): DeclaredBy;
22
22
  /** A client made from one of these modules' exports. */
@@ -30,18 +30,18 @@ declare function constructedFrom(spec: {
30
30
  declare function opsIn(ctx: unknown): CallOps | null;
31
31
 
32
32
  /**
33
- * Turning a chain into the recognizer hook the adapters already call.
33
+ * Turns a chain into the recognizer hook the adapters already call.
34
34
  *
35
- * The links are guards, so the compiled hook checks the cheap one
36
- * first: looking a method up in a table costs nothing, while following
37
- * a receiver to the library that made it walks declarations. The chain
38
- * says which questions to ask, not the order to ask them in. A link
39
- * that changes what the receiver is, the way Prisma's model property
40
- * does, will need that order back, and the note here is where to start.
35
+ * Every link is a guard, and the compiled hook checks the cheapest one
36
+ * first. Looking a method up in a table costs nothing, while following
37
+ * a receiver to the library that made it walks declarations. So the
38
+ * hook ignores the order the pack declared its links in. A link that
39
+ * changes what the receiver is, as a Prisma model property would, needs
40
+ * declared order back, and that change goes here.
41
41
  *
42
42
  * A chain that states a subject asks its questions of a call next to
43
- * the one in hand, so the walk lives here. The README beside this file
44
- * says what each step reaches and why the walk is bounded.
43
+ * the one in hand, and the walk to that call is also here. DESIGN.md
44
+ * describes what each step reaches and why the walk is bounded.
45
45
  */
46
46
 
47
47
  /** A chain, as the hook the adapter dispatches to on every call. */
@@ -71,28 +71,27 @@ interface RanExample {
71
71
  /** How a pack's test compiles one line and runs the pack over it. */
72
72
  type RunOverCode = (code: string) => Effect[];
73
73
  /**
74
- * Every example a pack declares, run. A declaration with no example is
75
- * left out, which is what the pack health check catches separately.
74
+ * Runs every example a pack declares. A declaration with no example is
75
+ * skipped here; `examplesMissing` lists those, and the pack health
76
+ * check reports them.
76
77
  */
77
78
  declare function runExamples(pack: PatternPack, run: RunOverCode): RanExample[];
78
79
  /** The declarations a pack shipped without a line of code to run. */
79
80
  declare function examplesMissing(pack: PatternPack): string[];
80
81
 
81
82
  /**
82
- * messageSends.ts: a pack that recognizes a call putting a message on a
83
- * wire.
83
+ * A pack that recognizes a call putting a message on a wire.
84
84
  *
85
- * The AWS SDK shape is the one this was written against. An operation
86
- * is a command class and its arguments are one object, so the pack says
87
- * which command, where the message is inside it, and which of the
88
- * message's properties name the channel:
85
+ * It was written against the AWS SDK. There an operation is a command
86
+ * class and its arguments are one object, so the pack says which
87
+ * command, where the message is inside it, and which of the message's
88
+ * properties make up the channel:
89
89
  *
90
90
  * client.send(new SendMessageCommand({ QueueUrl, MessageBody }))
91
91
  * client.send(new PutEventsCommand({ Entries: [{ EventBusName, DetailType }] }))
92
92
  *
93
- * A library taking one message and a batch of them offers two commands,
94
- * so a pack writes two declarations. Which of the two a command is
95
- * belongs to the command rather than to a setting on one declaration.
93
+ * A library that sends one message and a batch through separate
94
+ * commands gets two declarations, one per command.
96
95
  */
97
96
 
98
97
  interface MessageSendsSpec {
@@ -102,19 +101,19 @@ interface MessageSendsSpec {
102
101
  messages: MessageLocation;
103
102
  /** The parts of the channel, joined in the order they are written. */
104
103
  channel: readonly ChannelPart[];
105
- /** What joins the parts. Defaults to "#", which is what a bus and a subject use. */
104
+ /** What joins the parts. Defaults to "#", as used between a bus and a subject. */
106
105
  channelSeparator?: string;
107
106
  /** The property a message states its body on. */
108
107
  body?: string;
109
108
  /**
110
- * The property whose literal value rides along as the routing key,
111
- * scoping the message for a reader without joining the channel.
109
+ * The property whose literal value is recorded as the routing key. A
110
+ * reader can filter on it, and it stays out of the channel name.
112
111
  */
113
112
  routingKey?: string;
114
113
  /**
115
114
  * What a reader gives back for a channel nothing in the source
116
- * settles. Defaults to keeping the reference, since a queue named
117
- * only at deploy time is the common case rather than the exception.
115
+ * settles. Defaults to keeping the reference, because most queues get
116
+ * their name at deploy time.
118
117
  */
119
118
  unsettledName?: UnsettledName;
120
119
  /** How the pack pins down the client its calls are on. */
@@ -146,15 +145,15 @@ declare function messageSends(spec: MessageSendsSpec): MessageSends;
146
145
  */
147
146
 
148
147
  /**
149
- * One thing a pack matches, as whichever entry point built it hands it
150
- * over. `storageCalls` and `sqlStatements` both come out as this.
148
+ * One thing a pack matches, as an entry point returns it. `storageCalls`
149
+ * and `sqlStatements` both return this.
151
150
  */
152
151
  interface Match {
153
152
  readonly declared: Chain<MethodMeaning>;
154
153
  }
155
154
  /** What a pack says about itself, beyond the calls it matches. */
156
155
  interface PackSpec {
157
- /** The languages the pack runs on, as the adapters name them. */
156
+ /** The languages the pack runs on, spelled as the adapters spell them. */
158
157
  languages: string[];
159
158
  /**
160
159
  * The name effects from this pack are recorded under, which is the
@@ -168,24 +167,23 @@ interface PackSpec {
168
167
  */
169
168
  version?: string;
170
169
  /**
171
- * What the pack itself speaks, when that is not the wire its accesses
172
- * record. An S3 access goes over the AWS SDK and says so on every
173
- * effect, while the pack speaks S3.
170
+ * The pack's own protocol, when it differs from the wire its accesses
171
+ * record. An S3 pack records the AWS SDK as the wire on every effect,
172
+ * and its protocol is S3.
174
173
  */
175
174
  protocol?: string;
176
175
  /**
177
- * Further modules whose presence makes a file worth reading, beyond
178
- * the ones the chains match on. A helper a project reaches by a
179
- * relative path gives the gate nothing; the library that helper
180
- * imports gives it something.
176
+ * More modules that make a file worth reading, beyond the ones the
177
+ * chains match on. A helper imported by a relative path does not open
178
+ * the import gate, so the pack lists the library the helper imports.
181
179
  */
182
180
  requiresImport?: string[];
183
181
  /**
184
182
  * Recognizers written against the adapter directly, run alongside the
185
- * declared chains. A pack migrating one call at a time keeps what is
186
- * not declared yet here, and a pack that needs a shape the endings
187
- * cannot say keeps it here for good. Health reporting counts these as
188
- * function links, so the cost of staying here is visible.
183
+ * declared chains. A pack moving to chains one call at a time keeps
184
+ * the calls it has not declared yet here, and a call no ending can
185
+ * describe stays here for good. The pack health report counts these
186
+ * as function links, so a reader sees how many are left.
189
187
  */
190
188
  recognizers?: InvocationRecognizer[];
191
189
  /**
@@ -198,9 +196,10 @@ interface PackSpec {
198
196
  /** A pack, assembled from the calls it says it matches. */
199
197
  declare function pack(name: string, matches: readonly Match[], spec: PackSpec): PatternPack;
200
198
  /**
201
- * What a set of chains cost, for a pack that assembles itself. A pack
202
- * part way through the migration still has a hand-rolled walk beside
203
- * its declarations, and this is how the part that moved is priced.
199
+ * Describes a set of chains for the pack health report, for a pack that
200
+ * builds its `PatternPack` by hand. A pack partway through moving to
201
+ * declared chains keeps hand-written recognizers beside them, and this
202
+ * reports on the part that has moved.
204
203
  */
205
204
  declare function declarationsIn(matches: readonly Match[]): PackDeclarations;
206
205
 
@@ -208,13 +207,13 @@ declare function declarationsIn(matches: readonly Match[]): PackDeclarations;
208
207
  * The entry point for a pack whose calls hand the store a statement
209
208
  * written as SQL.
210
209
  *
211
- * A typed client says what it reached in its arguments, so the chain
212
- * asks the call. A raw statement says it in the text, so the chain
213
- * hands the text to `@suss/sql` and the parse settles the container,
214
- * the kind, the fields and the selector of every table the statement
215
- * touches. The links up to that point are the same ones every chain
216
- * states, which is why this is an ending rather than a grammar of its
217
- * own.
210
+ * With a typed client, the call's arguments show which table it
211
+ * reached. With a raw statement that information is in the SQL text,
212
+ * so the chain passes the text to `@suss/sql`. The parse gives the
213
+ * container, the kind, the fields and the selector of every table the
214
+ * statement touches. Every link before that point is one any other
215
+ * chain uses too, so SQL is a chain ending and needs no separate
216
+ * grammar.
218
217
  */
219
218
 
220
219
  /** What a pack says about the store its statements reach. */
@@ -255,10 +254,10 @@ declare function sqlStatements(spec: SqlStatementsSpec): SqlStatements;
255
254
  * The entry point for a pack that recognizes storage calls, and the
256
255
  * chain it builds.
257
256
  *
258
- * The entry point says what comes out rather than how, so a pack author
259
- * writes `storageCalls` and never meets an `Effect`. Each method on the
260
- * returned value adds one link and gives back a new chain, so a chain
261
- * is finished data by the time `pack` receives it.
257
+ * A pack author writes `storageCalls` and never builds an `Effect` by
258
+ * hand. Each method on the returned value adds one link and returns a
259
+ * new chain, so by the time `pack` receives a chain it is plain data
260
+ * that nothing changes afterwards.
262
261
  */
263
262
 
264
263
  /** What a pack says about the store its calls reach. */
@@ -271,8 +270,8 @@ interface StorageCallsSpec {
271
270
  scope?: string;
272
271
  /**
273
272
  * How the pack pins down the client its calls are on. A pack that
274
- * matches a helper a project lists in its own config leaves this out,
275
- * because the name that project gave is the whole of what it has.
273
+ * matches a helper listed in a project's own config leaves this out,
274
+ * because the helper's name is the only thing it has to match on.
276
275
  */
277
276
  client?: ReceiverOrigin;
278
277
  /**
@@ -294,9 +293,9 @@ interface StorageCalls {
294
293
  ignoringCase?: boolean;
295
294
  }): StorageCalls;
296
295
  /**
297
- * What a bare call of the client itself does. A store hook is the
298
- * case: `useAppStore((s) => s.bears)` reaches for no method, so the
299
- * one meaning here is the whole answer.
296
+ * What a bare call of the client itself does. A store hook such as
297
+ * `useAppStore((s) => s.bears)` calls no method, so this meaning
298
+ * applies to every call.
300
299
  */
301
300
  calls(meaning: StorageMethod): StorageCalls;
302
301
  /**
@@ -336,13 +335,12 @@ interface StorageCalls {
336
335
  declare function storageCalls(spec: StorageCallsSpec): StorageCalls;
337
336
 
338
337
  /**
339
- * unitInvokes.ts: a pack that recognizes a call invoking one deployed
340
- * unit by name.
338
+ * A pack that recognizes a call invoking one deployed unit by name.
341
339
  *
342
- * The AWS SDK shape is the one this was written against, and it is the
343
- * same shape a send has: an operation is a command class and its
344
- * arguments are one object, so the pack says which command and which of
345
- * its properties says which unit the call reaches.
340
+ * It was written against the AWS SDK, where an invoke looks like a
341
+ * message send: an operation is a command class and its arguments are
342
+ * one object. The pack says which command, and which of its properties
343
+ * identifies the unit the call reaches.
346
344
  *
347
345
  * client.send(new InvokeCommand({ FunctionName, Payload }))
348
346
  */