@suss/adapter-ruby 0.20.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
@@ -5,7 +5,7 @@ var __export = (target, all) => {
5
5
  };
6
6
 
7
7
  // src/ast.ts
8
- import { IdMap, IdSet } from "@suss/extractor";
8
+ import { IdMap, IdSet, SKIP_CHILDREN, walkDescendants } from "@suss/extractor";
9
9
  function rangeOf(node) {
10
10
  return {
11
11
  start: node.startPosition.row + 1,
@@ -21,12 +21,37 @@ function field(node, name) {
21
21
  function bodyStatements(body) {
22
22
  return body.namedChildren.filter((child) => child !== null);
23
23
  }
24
+ var OWN_BODY_TYPES = /* @__PURE__ */ new Set([
25
+ "method",
26
+ "singleton_method",
27
+ "lambda",
28
+ "class",
29
+ "module",
30
+ "singleton_class"
31
+ ]);
32
+ var ARGUMENT_LIST_TYPE = "argument_list";
33
+ function runStatements(body, blockConfigures = () => false) {
34
+ const found = [];
35
+ const readsItsChildren = (node) => {
36
+ if (OWN_BODY_TYPES.has(node.type) || node.type === ARGUMENT_LIST_TYPE) {
37
+ return false;
38
+ }
39
+ return !(node.type === "call" && blockConfigures(node));
40
+ };
41
+ walkDescendants(body, null, {
42
+ at: (node) => {
43
+ found.push(node);
44
+ },
45
+ into: (node) => readsItsChildren(node) ? null : SKIP_CHILDREN
46
+ });
47
+ return found;
48
+ }
24
49
  function symbolValue(node) {
25
50
  return node.type === "simple_symbol" ? node.text.slice(1) : null;
26
51
  }
27
52
  function instanceMethodsByName(body) {
28
53
  const methods = /* @__PURE__ */ new Map();
29
- for (const stmt of bodyStatements(body)) {
54
+ for (const stmt of runStatements(body)) {
30
55
  if (stmt.type !== "method") {
31
56
  continue;
32
57
  }
@@ -39,7 +64,7 @@ function instanceMethodsByName(body) {
39
64
  }
40
65
  function bareCallArgumentGroups(body, name) {
41
66
  const groups = [];
42
- for (const stmt of bodyStatements(body)) {
67
+ for (const stmt of runStatements(body)) {
43
68
  if (stmt.type !== "call" || field(stmt, "receiver") !== null) {
44
69
  continue;
45
70
  }
@@ -142,7 +167,7 @@ function walkClasses(root, visit) {
142
167
  });
143
168
  }
144
169
  function walkDefinitions(root, visit) {
145
- walkBody(bodyStatements(root), [], visit);
170
+ walkBody(runStatements(root), [], visit);
146
171
  }
147
172
  function walkBody(statements, nesting, visit) {
148
173
  for (const stmt of statements) {
@@ -181,7 +206,7 @@ function visitClass(node, nesting, visit) {
181
206
  bodyNesting: identity.bodyNesting
182
207
  });
183
208
  if (bodyNode !== null) {
184
- walkBody(bodyStatements(bodyNode), identity.bodyNesting, visit);
209
+ walkBody(runStatements(bodyNode), identity.bodyNesting, visit);
185
210
  }
186
211
  }
187
212
  function visitModule(node, nesting, visit) {
@@ -200,7 +225,7 @@ function visitModule(node, nesting, visit) {
200
225
  bodyNesting: identity.bodyNesting
201
226
  });
202
227
  if (bodyNode !== null) {
203
- walkBody(bodyStatements(bodyNode), identity.bodyNesting, visit);
228
+ walkBody(runStatements(bodyNode), identity.bodyNesting, visit);
204
229
  }
205
230
  }
206
231
  function stripTypeSuffixName(qualifiedName) {
@@ -356,7 +381,7 @@ function definitionIn(blocks, name) {
356
381
  }
357
382
  return { method, dynamic };
358
383
  }
359
- function inheritedStatements(ancestry) {
384
+ function inheritedStatements(ancestry, blockConfigures) {
360
385
  const statements = [];
361
386
  for (const entry of [...ancestry].reverse()) {
362
387
  if (entry.type !== "bodies") {
@@ -367,7 +392,7 @@ function inheritedStatements(ancestry) {
367
392
  if (body === null) {
368
393
  continue;
369
394
  }
370
- for (const statement of bodyStatements(body)) {
395
+ for (const statement of runStatements(body, blockConfigures)) {
371
396
  statements.push({ block, statement });
372
397
  }
373
398
  }
@@ -376,7 +401,7 @@ function inheritedStatements(ancestry) {
376
401
  }
377
402
 
378
403
  // src/discovery.ts
379
- import { dispatchByType, graphqlResolverBinding } from "@suss/behavioral-ir";
404
+ import { dispatchByType as dispatchByType2, graphqlResolverBinding } from "@suss/behavioral-ir";
380
405
  import { unreadableReading } from "@suss/extractor";
381
406
 
382
407
  // src/paths/effects.ts
@@ -593,14 +618,6 @@ function lowerRubyBody(body, terminals) {
593
618
  }
594
619
 
595
620
  // src/paths/effects.ts
596
- var DECLARATION_TYPES = /* @__PURE__ */ new Set([
597
- "method",
598
- "singleton_method",
599
- "lambda",
600
- "class",
601
- "module",
602
- "singleton_class"
603
- ]);
604
621
  var RAISE_NAMES2 = /* @__PURE__ */ new Set(["raise", "fail"]);
605
622
  var BLOCK_TYPES = /* @__PURE__ */ new Set([
606
623
  "body_statement",
@@ -648,7 +665,7 @@ function isRaise2(node) {
648
665
  }
649
666
  function bodyCalls(node, found = []) {
650
667
  for (const child of children(node)) {
651
- if (DECLARATION_TYPES.has(child.type)) {
668
+ if (OWN_BODY_TYPES.has(child.type)) {
652
669
  continue;
653
670
  }
654
671
  if (child.type === "call" && !isPropertyRead(child) && !isRaise2(child)) {
@@ -15251,7 +15268,7 @@ function date4(params) {
15251
15268
  // ../../../node_modules/zod/v4/classic/external.js
15252
15269
  config(en_default());
15253
15270
 
15254
- // ../../ir-core/dist/chunk-52CH76PE.js
15271
+ // ../../ir-core/dist/chunk-PPQWK62O.js
15255
15272
  function gqlIdentityKey(typeName, fieldName) {
15256
15273
  return `gql:${typeName}.${fieldName}`;
15257
15274
  }
@@ -15261,6 +15278,9 @@ function fnIdentityKey(packageName, exportPath) {
15261
15278
  function busIdentityKey(messageBus, subject) {
15262
15279
  return `bus:${messageBus} ${subject}`;
15263
15280
  }
15281
+ function unitIdentityKey(deploymentTarget, instanceName) {
15282
+ return `unit:${deploymentTarget} ${instanceName}`;
15283
+ }
15264
15284
  function metricIdentityKey(metricSystem, metricType) {
15265
15285
  return `metric:${metricSystem} ${metricType}`;
15266
15286
  }
@@ -15534,6 +15554,42 @@ var metricSemantics = defineBoundarySemantics({
15534
15554
  }
15535
15555
  }
15536
15556
  });
15557
+ var HOLE_SPLIT = /(\{[^}]*\})/;
15558
+ function isHole(piece) {
15559
+ return piece.startsWith("{") && piece.endsWith("}");
15560
+ }
15561
+ function parseBoundaryName(name) {
15562
+ const parts = name.split(HOLE_SPLIT).filter((piece) => piece !== "").map(
15563
+ (piece) => isHole(piece) ? { type: "hole", label: piece.slice(1, -1) } : { type: "text", text: piece }
15564
+ );
15565
+ const only = parts.length === 1 ? parts[0] : void 0;
15566
+ if (only !== void 0 && only.type === "hole") {
15567
+ return { type: "reference", path: only.label.split(".") };
15568
+ }
15569
+ if (parts.some((part) => part.type === "hole")) {
15570
+ return { type: "pattern", parts };
15571
+ }
15572
+ return { type: "literal", value: name };
15573
+ }
15574
+ function patternHole(label) {
15575
+ return `{${label}}`;
15576
+ }
15577
+ function namesNothing(name) {
15578
+ return parseBoundaryName(name).type === "reference";
15579
+ }
15580
+ function referenceOf(name) {
15581
+ if (name.type !== "reference") {
15582
+ return null;
15583
+ }
15584
+ const root = name.path[0];
15585
+ if (root === void 0 || name.path.some((part) => part === "")) {
15586
+ return null;
15587
+ }
15588
+ return { root, fields: name.path.slice(1) };
15589
+ }
15590
+ function referenceFromName(name) {
15591
+ return referenceOf(parseBoundaryName(name));
15592
+ }
15537
15593
  var SCHEME_ORIGIN = /^[a-zA-Z][a-zA-Z\d+.-]*:\/\/[^/]*/;
15538
15594
  var PROTOCOL_RELATIVE_ORIGIN = /^\/\/[^/]*/;
15539
15595
  function pathAfterOrigin(text) {
@@ -15560,9 +15616,9 @@ var RestSemanticsSchema = external_exports.object({
15560
15616
  declaredResponses: external_exports.array(external_exports.number()).optional()
15561
15617
  });
15562
15618
  var OPENING_HOLE = /^\{([^{}]+)\}(.*)$/;
15563
- function variableOf(label) {
15564
- const parts = label.split(".");
15565
- return parts[parts.length - 1] ?? label;
15619
+ function baseUrlReference(semantics) {
15620
+ const label = OPENING_HOLE.exec(semantics.path ?? "")?.[1];
15621
+ return label === void 0 ? null : referenceFromName(patternHole(label));
15566
15622
  }
15567
15623
  function normalizePath(path4) {
15568
15624
  let normalized = path4.replace(/:([a-zA-Z_]\w*)/g, "{$1}");
@@ -15673,6 +15729,14 @@ var restSemantics = defineBoundarySemantics({
15673
15729
  }
15674
15730
  return routePathAdmits(semantics.path, path4) ? "match" : "nomatch";
15675
15731
  },
15732
+ /**
15733
+ * A route the registration pattern admits is inside it. A route
15734
+ * whose path this source never gave is left outside, because
15735
+ * nothing here can show it is one the pattern covers.
15736
+ */
15737
+ withinScope(semantics, scope) {
15738
+ return semantics.path !== null && routePathAdmits(scope, semantics.path);
15739
+ },
15676
15740
  /**
15677
15741
  * A call whose base URL the deployment fills in, resolved to the
15678
15742
  * path it reaches.
@@ -15688,22 +15752,20 @@ var restSemantics = defineBoundarySemantics({
15688
15752
  * route parameter, and `/orders/{id}` means every id rather than a
15689
15753
  * variable somebody set.
15690
15754
  */
15691
- groundName(semantics, deployedAs) {
15692
- if (semantics.path === null) {
15693
- return null;
15694
- }
15695
- const opening = OPENING_HOLE.exec(semantics.path);
15696
- if (opening === null) {
15755
+ groundName(semantics, deployment) {
15756
+ const reference = baseUrlReference(semantics);
15757
+ if (reference === null) {
15697
15758
  return null;
15698
15759
  }
15699
- const [, label, rest] = opening;
15700
- const base = deployedAs(variableOf(label));
15760
+ const base = deployment.setTo(reference);
15701
15761
  if (base === null) {
15702
15762
  return null;
15703
15763
  }
15764
+ const rest = OPENING_HOLE.exec(semantics.path ?? "")?.[2] ?? "";
15704
15765
  const grounded = pathAfterOrigin(`${base}${rest}`);
15705
15766
  return { ...semantics, path: grounded === "" ? "/" : grounded };
15706
15767
  },
15768
+ nameReference: baseUrlReference,
15707
15769
  ruleBoundary: {
15708
15770
  // "METHOD /path": one leading token, then an absolute path.
15709
15771
  claims(raw) {
@@ -15779,6 +15841,9 @@ var StorageSemanticsSchema = external_exports.object({
15779
15841
  */
15780
15842
  accessPath: external_exports.string().nullable()
15781
15843
  });
15844
+ function containerReference(semantics) {
15845
+ return semantics.container === null ? null : referenceFromName(semantics.container);
15846
+ }
15782
15847
  var storageSemantics = defineBoundarySemantics({
15783
15848
  name: "storage",
15784
15849
  schema: StorageSemanticsSchema,
@@ -15794,7 +15859,100 @@ var storageSemantics = defineBoundarySemantics({
15794
15859
  /** A query returns rows or items, not a status and a body. */
15795
15860
  exchangesHttpResponses: false,
15796
15861
  reportsUnpairedItself: false,
15797
- identityKey: () => null
15862
+ identityKey: () => null,
15863
+ displayLabel: storageLabel,
15864
+ /**
15865
+ * A container the source states as a variable is whatever the
15866
+ * deployment sets that variable to. `{SUBSCRIBERS_TABLE}` in the
15867
+ * code and `prod-subscribers-v1` in the manifest are one table.
15868
+ */
15869
+ groundName(semantics, deployment) {
15870
+ const reference = containerReference(semantics);
15871
+ if (reference === null) {
15872
+ return null;
15873
+ }
15874
+ const name = deployment.setTo(reference);
15875
+ return name === null ? null : { ...semantics, container: name };
15876
+ },
15877
+ nameReference: containerReference
15878
+ }
15879
+ });
15880
+ function storageLabel(semantics) {
15881
+ return `${semantics.storageSystem}:${storageContainerLabel(semantics)}`;
15882
+ }
15883
+ function storageContainerLabel(semantics) {
15884
+ const container = semantics.container ?? "<unnamed container>";
15885
+ const addressed = semantics.accessPath === null ? container : `${container}#${semantics.accessPath}`;
15886
+ return semantics.scope === "default" ? addressed : `${semantics.scope}/${addressed}`;
15887
+ }
15888
+ var UnitInvocationSemanticsSchema = DeployableUnitSchema.extend({
15889
+ name: external_exports.literal("unit-invocation"),
15890
+ instanceName: DeployableUnitSchema.shape.instanceName.nullable()
15891
+ });
15892
+ function calleeReference(semantics) {
15893
+ return semantics.instanceName === null ? null : referenceFromName(semantics.instanceName);
15894
+ }
15895
+ var unitInvocationSemantics = defineBoundarySemantics({
15896
+ name: "unit-invocation",
15897
+ schema: UnitInvocationSemanticsSchema,
15898
+ // faas.name is the deployed function's own name and instanceName is
15899
+ // the deployment template's logical id, which is a different string.
15900
+ // Runtime config leaves the pair off for the same reason.
15901
+ semconv: {},
15902
+ behavior: {
15903
+ /**
15904
+ * A synchronous invoke gives back whatever the handler returned,
15905
+ * which is a value rather than a status and a body. A handler's
15906
+ * return only becomes an HTTP response under a proxy integration,
15907
+ * and that route gets a REST binding instead of this one.
15908
+ */
15909
+ exchangesHttpResponses: false,
15910
+ /**
15911
+ * A unit nothing in the run invokes is the ordinary case, since
15912
+ * most services are reached from a stack suss never read. So an
15913
+ * uninvoked unit stays in the generic unmatched list rather than
15914
+ * being reported as a problem here.
15915
+ */
15916
+ reportsUnpairedItself: false,
15917
+ /**
15918
+ * A callee the source states only as a variable is not a name for
15919
+ * anything until the deployment fills it in, so it keys as nothing
15920
+ * rather than as a bucket that would agree with itself alone.
15921
+ */
15922
+ identityKey(semantics) {
15923
+ if (semantics.instanceName === null || namesNothing(semantics.instanceName)) {
15924
+ return null;
15925
+ }
15926
+ return unitIdentityKey(
15927
+ semantics.deploymentTarget,
15928
+ semantics.instanceName
15929
+ );
15930
+ },
15931
+ displayLabel(semantics) {
15932
+ if (semantics.instanceName === null) {
15933
+ return `unit:${semantics.deploymentTarget} (named at runtime)`;
15934
+ }
15935
+ return unitIdentityKey(
15936
+ semantics.deploymentTarget,
15937
+ semantics.instanceName
15938
+ );
15939
+ },
15940
+ /**
15941
+ * A call that reads its callee's name out of the environment
15942
+ * reaches whichever resource the template wires that variable to.
15943
+ * The logical id is the answer rather than the deployed name,
15944
+ * because the invoked unit's own summary is keyed by the logical
15945
+ * id and neither side ever writes the other's string.
15946
+ */
15947
+ groundName(semantics, deployment) {
15948
+ const reference = calleeReference(semantics);
15949
+ if (reference === null) {
15950
+ return null;
15951
+ }
15952
+ const logicalId = deployment.pointsAt(reference);
15953
+ return logicalId === null ? null : { ...semantics, instanceName: logicalId };
15954
+ },
15955
+ nameReference: calleeReference
15798
15956
  }
15799
15957
  });
15800
15958
  var SemanticsSchema = external_exports.discriminatedUnion("name", [
@@ -15805,7 +15963,8 @@ var SemanticsSchema = external_exports.discriminatedUnion("name", [
15805
15963
  runtimeConfigSemantics.schema,
15806
15964
  storageSemantics.schema,
15807
15965
  messageBusSemantics.schema,
15808
- metricSemantics.schema
15966
+ metricSemantics.schema,
15967
+ unitInvocationSemantics.schema
15809
15968
  ]);
15810
15969
  var DEFINITIONS = [
15811
15970
  restSemantics,
@@ -15815,7 +15974,8 @@ var DEFINITIONS = [
15815
15974
  runtimeConfigSemantics,
15816
15975
  storageSemantics,
15817
15976
  messageBusSemantics,
15818
- metricSemantics
15977
+ metricSemantics,
15978
+ unitInvocationSemantics
15819
15979
  ];
15820
15980
  var BY_NAME = new Map(
15821
15981
  DEFINITIONS.map((d) => [d.name, d])
@@ -15905,6 +16065,13 @@ var TypeShapeSchema = external_exports.lazy(
15905
16065
  );
15906
16066
 
15907
16067
  // ../../ir-core/dist/index.js
16068
+ var RelationSchema = external_exports.enum([
16069
+ "provides",
16070
+ "reads",
16071
+ "writes",
16072
+ "invokes"
16073
+ ]);
16074
+ var EffectRelationSchema = RelationSchema.exclude(["provides"]);
15908
16075
  var SuppressionSideSchema = external_exports.object({
15909
16076
  summary: external_exports.string().optional(),
15910
16077
  transitionId: external_exports.string().optional()
@@ -16093,9 +16260,9 @@ var RESOLUTION_RULES = [
16093
16260
  [lit("invokes", v("r"), v("f")), lit("returnsValue", v("f"), v("ret"))],
16094
16261
  "call result"
16095
16262
  ),
16096
- // Where a walk gets to, and whether it ran a call on the way. A value
16097
- // step keeps whatever the rest of the walk was, and a result step
16098
- // makes the whole walk one that ran a call.
16263
+ // Where a walk gets to, and whether it ran a call on the way. The walk
16264
+ // so far comes first, so demand stays on the value asked about; the
16265
+ // README says what the other order cost.
16099
16266
  rule(
16100
16267
  "reaches",
16101
16268
  [v("x"), v("z"), v("kind")],
@@ -16105,27 +16272,27 @@ var RESOLUTION_RULES = [
16105
16272
  "reaches",
16106
16273
  [v("x"), v("z"), v("kind")],
16107
16274
  [
16108
- lit("stepsTo", v("x"), v("y"), VALUE_STEP),
16109
- lit("reaches", v("y"), v("z"), v("kind"))
16275
+ lit("reaches", v("x"), v("y"), VALUE_STEP),
16276
+ lit("stepsTo", v("y"), v("z"), v("kind"))
16110
16277
  ]
16111
16278
  ),
16112
- // Two rules rather than one leaving the rest of the walk's kind free.
16113
- // A free kind is a second question about the same relation, and a
16279
+ // Two rules rather than one leaving the next step's kind free. A free
16280
+ // kind is a second question about the same relation, and a
16114
16281
  // demand-driven run then derives both to answer either.
16115
16282
  rule(
16116
16283
  "reaches",
16117
16284
  [v("x"), v("z"), RESULT_STEP],
16118
16285
  [
16119
- lit("stepsTo", v("x"), v("y"), RESULT_STEP),
16120
- lit("reaches", v("y"), v("z"), VALUE_STEP)
16286
+ lit("reaches", v("x"), v("y"), RESULT_STEP),
16287
+ lit("stepsTo", v("y"), v("z"), VALUE_STEP)
16121
16288
  ]
16122
16289
  ),
16123
16290
  rule(
16124
16291
  "reaches",
16125
16292
  [v("x"), v("z"), RESULT_STEP],
16126
16293
  [
16127
- lit("stepsTo", v("x"), v("y"), RESULT_STEP),
16128
- lit("reaches", v("y"), v("z"), RESULT_STEP)
16294
+ lit("reaches", v("x"), v("y"), RESULT_STEP),
16295
+ lit("stepsTo", v("y"), v("z"), RESULT_STEP)
16129
16296
  ]
16130
16297
  ),
16131
16298
  // What a value comes down to: the walk that never ran a call, stopped
@@ -16471,29 +16638,14 @@ var RESOLUTION_QUESTIONS = [
16471
16638
  // here demands reaches or callsInto. The chains are closures with
16472
16639
  // no depth bound: an alias run of any length resolves.
16473
16640
  rule("callOriginChain", [v("x"), v("x")], [lit("wantedCallOrigin", v("x"))]),
16641
+ // The chain with at least one hop taken, which is what tells a
16642
+ // destructured binding apart from asking about a node directly. The
16643
+ // whole chain is the seed plus those hops.
16474
16644
  rule(
16475
16645
  "callOriginChain",
16476
16646
  [v("x"), v("z")],
16477
- [lit("callOriginChain", v("x"), v("y")), lit("binds", v("y"), v("z"))]
16478
- ),
16479
- rule(
16480
- "callOriginChain",
16481
- [v("x"), v("z")],
16482
- [
16483
- lit("callOriginChain", v("x"), v("y")),
16484
- lit("endsHolding", v("y"), v("z"))
16485
- ]
16486
- ),
16487
- rule(
16488
- "callOriginChain",
16489
- [v("x"), v("z")],
16490
- [
16491
- lit("callOriginChain", v("x"), v("y")),
16492
- lit("fallbackBranch", v("y"), v("z"))
16493
- ]
16647
+ [lit("callOriginChainStepped", v("x"), v("z"))]
16494
16648
  ),
16495
- // The chain with at least one hop taken, which is what tells a
16496
- // destructured binding apart from asking about a node directly.
16497
16649
  rule(
16498
16650
  "callOriginChainStepped",
16499
16651
  [v("x"), v("z")],
@@ -16624,6 +16776,23 @@ var RESOLUTION_QUESTIONS = [
16624
16776
  lit("callsInto", v("g"), v("m"), v("n"))
16625
16777
  ]
16626
16778
  ),
16779
+ // Subject identity, its own demand class; the README's subject
16780
+ // section says why the origin pair rides on the written-value walk.
16781
+ rule(
16782
+ "wantedSubjectWritten",
16783
+ [v("x"), v("r")],
16784
+ [lit("wantedSubject", v("x")), lit("isWrittenAs", v("x"), v("r"))]
16785
+ ),
16786
+ rule(
16787
+ "wantedSubjectConstruction",
16788
+ [v("x"), v("r"), v("m"), v("n")],
16789
+ [
16790
+ lit("wantedSubject", v("x")),
16791
+ lit("isWrittenAs", v("x"), v("r")),
16792
+ lit("call", v("r"), v("c")),
16793
+ lit("comesFrom", v("c"), v("m"), v("n"))
16794
+ ]
16795
+ ),
16627
16796
  // The export table of one module, keyed by the module asked about.
16628
16797
  // The moduleExport rules flatten re-export chains of any length, and
16629
16798
  // the demand cone stays on export facts alone.
@@ -16948,7 +17117,7 @@ function unitsFor(pattern, pack, info, ownBlocks, fileBlocks, options) {
16948
17117
  const table = {
16949
17118
  graphqlObjectFields: (p) => graphqlObjectFieldUnits(p, pack, info, ownBlocks, fileBlocks, options)
16950
17119
  };
16951
- return dispatchByType(table, pattern);
17120
+ return dispatchByType2(table, pattern);
16952
17121
  }
16953
17122
  async function graphqlObjectFieldUnits(pattern, pack, info, ownBlocks, fileBlocks, options) {
16954
17123
  if (info.bodyNode === null || pattern.baseClassNames.includes(info.qualifiedName)) {
@@ -16971,7 +17140,10 @@ async function graphqlObjectFieldUnits(pattern, pack, info, ownBlocks, fileBlock
16971
17140
  const knownClasses = ownBlocks[0]?.knownClasses ?? /* @__PURE__ */ new Set();
16972
17141
  const scope = { nesting: info.bodyNesting, knownClasses };
16973
17142
  const declsByName = /* @__PURE__ */ new Map();
16974
- for (const stmt of bodyStatements(info.bodyNode)) {
17143
+ for (const stmt of runStatements(
17144
+ info.bodyNode,
17145
+ blockConfiguresCall(pattern)
17146
+ )) {
16975
17147
  const decl = await readFieldCall(stmt, scope, ctx, ancestry);
16976
17148
  if (decl !== null) {
16977
17149
  declsByName.set(decl.fieldName, decl);
@@ -16981,6 +17153,17 @@ async function graphqlObjectFieldUnits(pattern, pack, info, ownBlocks, fileBlock
16981
17153
  (decl) => buildFieldUnit(pack, typeName, decl, options.filePath)
16982
17154
  );
16983
17155
  }
17156
+ function blockConfiguresCall(pattern) {
17157
+ const names = /* @__PURE__ */ new Set([
17158
+ pattern.fieldCallName,
17159
+ pattern.typeCallName,
17160
+ pattern.argumentCallName
17161
+ ]);
17162
+ return (call) => {
17163
+ const method = field(call, "method")?.text;
17164
+ return field(call, "receiver") === null && method !== void 0 && names.has(method);
17165
+ };
17166
+ }
16984
17167
  function branchesFor(body, range) {
16985
17168
  if (body.effects === void 0 && body.extraEffects === void 0) {
16986
17169
  return [];
@@ -17045,7 +17228,7 @@ function bodyFromLookup(found, range, subject, nothingThere, storage) {
17045
17228
  ),
17046
17229
  none: () => nothingThere
17047
17230
  };
17048
- return dispatchByType(table, found);
17231
+ return dispatchByType2(table, found);
17049
17232
  }
17050
17233
  async function readFieldCall(stmt, scope, ctx, ancestry) {
17051
17234
  if (stmt.type !== "call" || field(stmt, "receiver") !== null) {
@@ -17056,10 +17239,13 @@ async function readFieldCall(stmt, scope, ctx, ancestry) {
17056
17239
  }
17057
17240
  const callArgs = readCallArgs(field(stmt, "arguments"));
17058
17241
  const nameArg = callArgs.positional[0];
17059
- const symbol2 = nameArg !== void 0 ? symbolValue(nameArg) : null;
17060
- if (symbol2 === null) {
17242
+ if (nameArg === void 0) {
17061
17243
  return null;
17062
17244
  }
17245
+ const symbol2 = symbolValue(nameArg);
17246
+ if (symbol2 === null) {
17247
+ return computedNameDeclaration(stmt, nameArg);
17248
+ }
17063
17249
  const read = await readFieldShape(
17064
17250
  symbol2,
17065
17251
  callArgs,
@@ -17070,11 +17256,29 @@ async function readFieldCall(stmt, scope, ctx, ancestry) {
17070
17256
  );
17071
17257
  return {
17072
17258
  fieldName: resolvedName(symbol2, callArgs, ctx.pattern),
17259
+ namedOnTheWire: true,
17073
17260
  node: stmt,
17074
17261
  contract: read.contract,
17075
17262
  body: read.body
17076
17263
  };
17077
17264
  }
17265
+ function computedNameDeclaration(stmt, nameArg) {
17266
+ const range = rangeOf(stmt);
17267
+ return {
17268
+ fieldName: nameArg.text,
17269
+ namedOnTheWire: false,
17270
+ node: stmt,
17271
+ contract: null,
17272
+ body: {
17273
+ readings: [
17274
+ unreadableReading(
17275
+ `This field is named by ${nameArg.text}, which is worked out when the class body runs, so the name the schema exposes it under was not read here`,
17276
+ range
17277
+ )
17278
+ ]
17279
+ }
17280
+ };
17281
+ }
17078
17282
  function wiringReference(callArgs, wiringKeywords) {
17079
17283
  for (const keyword of wiringKeywords) {
17080
17284
  const ref = callArgs.keyword[keyword];
@@ -17199,7 +17403,10 @@ function readClassContract(ancestry, pattern) {
17199
17403
  args: /* @__PURE__ */ new Map()
17200
17404
  };
17201
17405
  const handlers = classCallHandlers(pattern);
17202
- for (const { block, statement } of inheritedStatements(ancestry)) {
17406
+ for (const { block, statement } of inheritedStatements(
17407
+ ancestry,
17408
+ blockConfiguresCall(pattern)
17409
+ )) {
17203
17410
  if (statement.type !== "call" || field(statement, "receiver") !== null) {
17204
17411
  continue;
17205
17412
  }
@@ -17290,12 +17497,12 @@ function buildFieldUnit(pack, typeName, decl, filePath) {
17290
17497
  exportName: null,
17291
17498
  exportPath: null
17292
17499
  },
17293
- boundaryBinding: graphqlResolverBinding({
17500
+ boundaryBinding: decl.namedOnTheWire ? graphqlResolverBinding({
17294
17501
  transport: pack.protocol,
17295
17502
  recognition: pack.name,
17296
17503
  typeName,
17297
17504
  fieldName: decl.fieldName
17298
- }),
17505
+ }) : null,
17299
17506
  parameters,
17300
17507
  branches: branchesFor(decl.body, rangeOf(decl.node)),
17301
17508
  ...decl.body.bodyContent !== void 0 ? { bodyContent: decl.body.bodyContent } : {},
@@ -17366,14 +17573,6 @@ function nodeId(filePath, node) {
17366
17573
  function nameId(filePath, name) {
17367
17574
  return `${filePath}#${name}`;
17368
17575
  }
17369
- var DECLARATION_TYPES2 = /* @__PURE__ */ new Set([
17370
- "method",
17371
- "singleton_method",
17372
- "lambda",
17373
- "class",
17374
- "module",
17375
- "singleton_class"
17376
- ]);
17377
17576
  var WRITTEN_VALUE_TYPES = /* @__PURE__ */ new Set([
17378
17577
  "string",
17379
17578
  "integer",
@@ -17511,7 +17710,7 @@ function emitHash(emitter, hash2) {
17511
17710
  }
17512
17711
  function walkExpressions(node, visit) {
17513
17712
  for (const child of children3(node)) {
17514
- if (DECLARATION_TYPES2.has(child.type)) {
17713
+ if (OWN_BODY_TYPES.has(child.type)) {
17515
17714
  continue;
17516
17715
  }
17517
17716
  visit(child);
@@ -17569,7 +17768,7 @@ function emitMethodFacts(emitter, method) {
17569
17768
  }
17570
17769
  const recordNested = (node) => {
17571
17770
  for (const child of children3(node)) {
17572
- if (DECLARATION_TYPES2.has(child.type)) {
17771
+ if (OWN_BODY_TYPES.has(child.type)) {
17573
17772
  add(emitter, "containsFn", funcKey, nodeId(emitter.filePath, child));
17574
17773
  continue;
17575
17774
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@suss/adapter-ruby",
3
- "version": "0.20.0",
3
+ "version": "0.21.1",
4
4
  "type": "module",
5
5
  "description": "Ruby language adapter for suss, parsing source with tree-sitter (WASM), resolving constant nesting with a lexical binder, and emitting raw extractions for the suss pipeline.",
6
6
  "keywords": [
@@ -47,9 +47,9 @@
47
47
  "typecheck": "tsc --noEmit"
48
48
  },
49
49
  "dependencies": {
50
- "@suss/behavioral-ir": "0.20.0",
51
- "@suss/datalog": "0.20.0",
52
- "@suss/extractor": "0.20.0",
50
+ "@suss/behavioral-ir": "0.21.1",
51
+ "@suss/datalog": "0.21.1",
52
+ "@suss/extractor": "0.21.1",
53
53
  "web-tree-sitter": "^0.26.11"
54
54
  },
55
55
  "devDependencies": {