@suss/adapter-ruby 0.5.3 → 0.5.5

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
@@ -335,7 +335,7 @@ async function mixinChain(self, callName, lookup, active, present) {
335
335
  return chain;
336
336
  }
337
337
  async function chainFor(qualifiedName, lookup, active) {
338
- const blocks = await reachDefinition(qualifiedName, lookup);
338
+ const blocks = lookup.localDefinition?.(qualifiedName) ?? await reachDefinition(qualifiedName, lookup);
339
339
  if (blocks === null) {
340
340
  return [{ type: "unfollowed", name: qualifiedName }];
341
341
  }
@@ -16003,7 +16003,7 @@ function createFileCache(parse3, readFile) {
16003
16003
  }
16004
16004
  };
16005
16005
  }
16006
- function fieldReadContext(pattern, cache, storage) {
16006
+ function fieldReadContext(pattern, cache, fileBlocks, storage) {
16007
16007
  return {
16008
16008
  pattern,
16009
16009
  cache,
@@ -16012,10 +16012,17 @@ function fieldReadContext(pattern, cache, storage) {
16012
16012
  root: pattern.root,
16013
16013
  pathConvention: pattern.pathConvention,
16014
16014
  ancestryRootClassNames: pattern.ancestryRootClassNames,
16015
- parsedFile: (absPath) => cache.get(absPath)
16015
+ parsedFile: (absPath) => cache.get(absPath),
16016
+ localDefinition: (name) => sameFileBlocks(name, fileBlocks)
16016
16017
  }
16017
16018
  };
16018
16019
  }
16020
+ function sameFileBlocks(name, fileBlocks) {
16021
+ const matches = fileBlocks.filter(
16022
+ (block) => block.info.qualifiedName === name
16023
+ );
16024
+ return matches.length === 0 ? null : matches;
16025
+ }
16019
16026
  function typeContext(scope, pattern) {
16020
16027
  return {
16021
16028
  nesting: scope.nesting,
@@ -16027,39 +16034,65 @@ function typeContext(scope, pattern) {
16027
16034
  }
16028
16035
  async function discoverUnits(root, options) {
16029
16036
  const classes = [];
16030
- walkClasses(root, (info) => classes.push(info));
16037
+ walkDefinitions(root, (info) => classes.push(info));
16031
16038
  const knownClasses = new Set(classes.map((info) => info.qualifiedName));
16039
+ const fileBlocks = classes.map((info) => ({
16040
+ info,
16041
+ knownClasses
16042
+ }));
16032
16043
  const units = [];
16033
16044
  for (const info of classes) {
16034
- const ownBlocks = classes.filter((other) => other.qualifiedName === info.qualifiedName).map((other) => ({ info: other, knownClasses }));
16045
+ const ownBlocks = fileBlocks.filter(
16046
+ (block) => block.info.qualifiedName === info.qualifiedName
16047
+ );
16035
16048
  for (const pack of options.packs) {
16036
16049
  for (const pattern of pack.discovery) {
16037
16050
  units.push(
16038
- ...await unitsFor(pattern, pack, info, ownBlocks, options)
16051
+ ...await unitsFor(
16052
+ pattern,
16053
+ pack,
16054
+ info,
16055
+ ownBlocks,
16056
+ fileBlocks,
16057
+ options
16058
+ )
16039
16059
  );
16040
16060
  }
16041
16061
  }
16042
16062
  }
16043
16063
  return units;
16044
16064
  }
16045
- function unitsFor(pattern, pack, info, ownBlocks, options) {
16065
+ function reachesConfiguredBase(ancestry, self, pattern) {
16066
+ return ancestry.some(
16067
+ (entry) => entry.name !== self && pattern.baseClassNames.includes(entry.name)
16068
+ );
16069
+ }
16070
+ function unitsFor(pattern, pack, info, ownBlocks, fileBlocks, options) {
16046
16071
  const table = {
16047
- graphqlObjectFields: (p) => graphqlObjectFieldUnits(p, pack, info, ownBlocks, options)
16072
+ graphqlObjectFields: (p) => graphqlObjectFieldUnits(p, pack, info, ownBlocks, fileBlocks, options)
16048
16073
  };
16049
16074
  return (0, import_behavioral_ir.dispatchByType)(table, pattern);
16050
16075
  }
16051
- async function graphqlObjectFieldUnits(pattern, pack, info, ownBlocks, options) {
16052
- if (info.superclassQualifiedName === null || !pattern.baseClassNames.includes(info.superclassQualifiedName) || info.bodyNode === null) {
16076
+ async function graphqlObjectFieldUnits(pattern, pack, info, ownBlocks, fileBlocks, options) {
16077
+ if (info.bodyNode === null || pattern.baseClassNames.includes(info.qualifiedName)) {
16078
+ return [];
16079
+ }
16080
+ const ctx = fieldReadContext(
16081
+ pattern,
16082
+ options.cache,
16083
+ fileBlocks,
16084
+ options.storage
16085
+ );
16086
+ const ancestry = await ancestryOf(info.qualifiedName, ownBlocks, ctx.lookup);
16087
+ if (!reachesConfiguredBase(ancestry, info.qualifiedName, pattern)) {
16053
16088
  return [];
16054
16089
  }
16055
16090
  const typeName = graphqlTypeNameFromQualified(
16056
16091
  info.qualifiedName,
16057
16092
  pattern.typeNameConvention
16058
16093
  );
16059
- const ctx = fieldReadContext(pattern, options.cache, options.storage);
16060
16094
  const knownClasses = ownBlocks[0]?.knownClasses ?? /* @__PURE__ */ new Set();
16061
16095
  const scope = { nesting: info.bodyNesting, knownClasses };
16062
- const ancestry = await ancestryOf(info.qualifiedName, ownBlocks, ctx.lookup);
16063
16096
  const declsByName = /* @__PURE__ */ new Map();
16064
16097
  for (const stmt of bodyStatements(info.bodyNode)) {
16065
16098
  const decl = await readFieldCall(stmt, scope, ctx, ancestry);
package/dist/index.d.cts CHANGED
@@ -101,6 +101,12 @@ interface AncestorLookup {
101
101
  */
102
102
  ancestryRootClassNames: readonly string[];
103
103
  parsedFile(absPath: string): Promise<Node | null>;
104
+ /**
105
+ * The blocks the file being read defines under a name, consulted
106
+ * before the path convention, since a constant defined in the same
107
+ * file is visible without a file of its own.
108
+ */
109
+ localDefinition?(qualifiedName: string): ReachedBody[] | null;
104
110
  }
105
111
  /**
106
112
  * Every block a file defines under `qualifiedName`, or null when the
@@ -164,10 +170,10 @@ interface RbStoragePattern {
164
170
  storageSystem: "postgres" | "mysql" | "sqlite";
165
171
  }
166
172
  type RubyDiscoveryPattern = GraphqlObjectFields;
167
- /** A class whose `< ...` superclass is one of `baseClassNames` declares GraphQL fields through DSL calls in its own body. */
173
+ /** A class or module whose ancestry reaches one of `baseClassNames` declares GraphQL fields through DSL calls in its own body. */
168
174
  interface GraphqlObjectFields {
169
175
  type: "graphqlObjectFields";
170
- /** The base class the library itself generates. A project's own intermediate base class is added through pack config. */
176
+ /** The base classes the library itself generates. The walk crosses a project's own intermediate bases on its own, so config only has to add a base with another name. */
171
177
  baseClassNames: string[];
172
178
  /** The directory a wiring keyword's referenced class is looked up under. That is the project's own layout, not the library's. */
173
179
  root: string;
package/dist/index.d.ts CHANGED
@@ -101,6 +101,12 @@ interface AncestorLookup {
101
101
  */
102
102
  ancestryRootClassNames: readonly string[];
103
103
  parsedFile(absPath: string): Promise<Node | null>;
104
+ /**
105
+ * The blocks the file being read defines under a name, consulted
106
+ * before the path convention, since a constant defined in the same
107
+ * file is visible without a file of its own.
108
+ */
109
+ localDefinition?(qualifiedName: string): ReachedBody[] | null;
104
110
  }
105
111
  /**
106
112
  * Every block a file defines under `qualifiedName`, or null when the
@@ -164,10 +170,10 @@ interface RbStoragePattern {
164
170
  storageSystem: "postgres" | "mysql" | "sqlite";
165
171
  }
166
172
  type RubyDiscoveryPattern = GraphqlObjectFields;
167
- /** A class whose `< ...` superclass is one of `baseClassNames` declares GraphQL fields through DSL calls in its own body. */
173
+ /** A class or module whose ancestry reaches one of `baseClassNames` declares GraphQL fields through DSL calls in its own body. */
168
174
  interface GraphqlObjectFields {
169
175
  type: "graphqlObjectFields";
170
- /** The base class the library itself generates. A project's own intermediate base class is added through pack config. */
176
+ /** The base classes the library itself generates. The walk crosses a project's own intermediate bases on its own, so config only has to add a base with another name. */
171
177
  baseClassNames: string[];
172
178
  /** The directory a wiring keyword's referenced class is looked up under. That is the project's own layout, not the library's. */
173
179
  root: string;
package/dist/index.js CHANGED
@@ -284,7 +284,7 @@ async function mixinChain(self, callName, lookup, active, present) {
284
284
  return chain;
285
285
  }
286
286
  async function chainFor(qualifiedName, lookup, active) {
287
- const blocks = await reachDefinition(qualifiedName, lookup);
287
+ const blocks = lookup.localDefinition?.(qualifiedName) ?? await reachDefinition(qualifiedName, lookup);
288
288
  if (blocks === null) {
289
289
  return [{ type: "unfollowed", name: qualifiedName }];
290
290
  }
@@ -15952,7 +15952,7 @@ function createFileCache(parse3, readFile) {
15952
15952
  }
15953
15953
  };
15954
15954
  }
15955
- function fieldReadContext(pattern, cache, storage) {
15955
+ function fieldReadContext(pattern, cache, fileBlocks, storage) {
15956
15956
  return {
15957
15957
  pattern,
15958
15958
  cache,
@@ -15961,10 +15961,17 @@ function fieldReadContext(pattern, cache, storage) {
15961
15961
  root: pattern.root,
15962
15962
  pathConvention: pattern.pathConvention,
15963
15963
  ancestryRootClassNames: pattern.ancestryRootClassNames,
15964
- parsedFile: (absPath) => cache.get(absPath)
15964
+ parsedFile: (absPath) => cache.get(absPath),
15965
+ localDefinition: (name) => sameFileBlocks(name, fileBlocks)
15965
15966
  }
15966
15967
  };
15967
15968
  }
15969
+ function sameFileBlocks(name, fileBlocks) {
15970
+ const matches = fileBlocks.filter(
15971
+ (block) => block.info.qualifiedName === name
15972
+ );
15973
+ return matches.length === 0 ? null : matches;
15974
+ }
15968
15975
  function typeContext(scope, pattern) {
15969
15976
  return {
15970
15977
  nesting: scope.nesting,
@@ -15976,39 +15983,65 @@ function typeContext(scope, pattern) {
15976
15983
  }
15977
15984
  async function discoverUnits(root, options) {
15978
15985
  const classes = [];
15979
- walkClasses(root, (info) => classes.push(info));
15986
+ walkDefinitions(root, (info) => classes.push(info));
15980
15987
  const knownClasses = new Set(classes.map((info) => info.qualifiedName));
15988
+ const fileBlocks = classes.map((info) => ({
15989
+ info,
15990
+ knownClasses
15991
+ }));
15981
15992
  const units = [];
15982
15993
  for (const info of classes) {
15983
- const ownBlocks = classes.filter((other) => other.qualifiedName === info.qualifiedName).map((other) => ({ info: other, knownClasses }));
15994
+ const ownBlocks = fileBlocks.filter(
15995
+ (block) => block.info.qualifiedName === info.qualifiedName
15996
+ );
15984
15997
  for (const pack of options.packs) {
15985
15998
  for (const pattern of pack.discovery) {
15986
15999
  units.push(
15987
- ...await unitsFor(pattern, pack, info, ownBlocks, options)
16000
+ ...await unitsFor(
16001
+ pattern,
16002
+ pack,
16003
+ info,
16004
+ ownBlocks,
16005
+ fileBlocks,
16006
+ options
16007
+ )
15988
16008
  );
15989
16009
  }
15990
16010
  }
15991
16011
  }
15992
16012
  return units;
15993
16013
  }
15994
- function unitsFor(pattern, pack, info, ownBlocks, options) {
16014
+ function reachesConfiguredBase(ancestry, self, pattern) {
16015
+ return ancestry.some(
16016
+ (entry) => entry.name !== self && pattern.baseClassNames.includes(entry.name)
16017
+ );
16018
+ }
16019
+ function unitsFor(pattern, pack, info, ownBlocks, fileBlocks, options) {
15995
16020
  const table = {
15996
- graphqlObjectFields: (p) => graphqlObjectFieldUnits(p, pack, info, ownBlocks, options)
16021
+ graphqlObjectFields: (p) => graphqlObjectFieldUnits(p, pack, info, ownBlocks, fileBlocks, options)
15997
16022
  };
15998
16023
  return dispatchByType(table, pattern);
15999
16024
  }
16000
- async function graphqlObjectFieldUnits(pattern, pack, info, ownBlocks, options) {
16001
- if (info.superclassQualifiedName === null || !pattern.baseClassNames.includes(info.superclassQualifiedName) || info.bodyNode === null) {
16025
+ async function graphqlObjectFieldUnits(pattern, pack, info, ownBlocks, fileBlocks, options) {
16026
+ if (info.bodyNode === null || pattern.baseClassNames.includes(info.qualifiedName)) {
16027
+ return [];
16028
+ }
16029
+ const ctx = fieldReadContext(
16030
+ pattern,
16031
+ options.cache,
16032
+ fileBlocks,
16033
+ options.storage
16034
+ );
16035
+ const ancestry = await ancestryOf(info.qualifiedName, ownBlocks, ctx.lookup);
16036
+ if (!reachesConfiguredBase(ancestry, info.qualifiedName, pattern)) {
16002
16037
  return [];
16003
16038
  }
16004
16039
  const typeName = graphqlTypeNameFromQualified(
16005
16040
  info.qualifiedName,
16006
16041
  pattern.typeNameConvention
16007
16042
  );
16008
- const ctx = fieldReadContext(pattern, options.cache, options.storage);
16009
16043
  const knownClasses = ownBlocks[0]?.knownClasses ?? /* @__PURE__ */ new Set();
16010
16044
  const scope = { nesting: info.bodyNesting, knownClasses };
16011
- const ancestry = await ancestryOf(info.qualifiedName, ownBlocks, ctx.lookup);
16012
16045
  const declsByName = /* @__PURE__ */ new Map();
16013
16046
  for (const stmt of bodyStatements(info.bodyNode)) {
16014
16047
  const decl = await readFieldCall(stmt, scope, ctx, ancestry);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@suss/adapter-ruby",
3
- "version": "0.5.3",
3
+ "version": "0.5.5",
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.5.3",
51
- "@suss/datalog": "0.5.3",
52
- "@suss/extractor": "0.5.3",
50
+ "@suss/behavioral-ir": "0.5.5",
51
+ "@suss/datalog": "0.5.5",
52
+ "@suss/extractor": "0.5.5",
53
53
  "web-tree-sitter": "^0.26.11"
54
54
  },
55
55
  "devDependencies": {