@suss/adapter-ruby 0.21.0 → 0.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +78 -2
- package/dist/index.cjs +2335 -570
- package/dist/index.d.cts +280 -8
- package/dist/index.d.ts +280 -8
- package/dist/index.js +2018 -230
- package/package.json +4 -4
package/dist/index.d.ts
CHANGED
|
@@ -2,7 +2,8 @@ import { Tree, Node } from 'web-tree-sitter';
|
|
|
2
2
|
export { Node as RbNode, Tree as RbTree } from 'web-tree-sitter';
|
|
3
3
|
import { Database } from '@suss/datalog';
|
|
4
4
|
import { TypeShape, BehavioralSummary } from '@suss/behavioral-ir';
|
|
5
|
-
import { RawCodeStructure } from '@suss/extractor';
|
|
5
|
+
import { RawCodeStructure, TimingReport, ExtractionReport, CacheDiagnostic } from '@suss/extractor';
|
|
6
|
+
import { WhyExplained } from '@suss/resolution';
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* A new `Parser` for every call, so that parses running at the same time do
|
|
@@ -10,9 +11,51 @@ import { RawCodeStructure } from '@suss/extractor';
|
|
|
10
11
|
* is loaded once per process and shared.
|
|
11
12
|
*/
|
|
12
13
|
declare function parseRuby(source: string): Promise<Tree>;
|
|
14
|
+
/**
|
|
15
|
+
* Load the grammar ahead of time, for a caller whose own entry point is
|
|
16
|
+
* async but whose parsing happens later through `parseRubySync`. Loading
|
|
17
|
+
* the WASM grammar is the only async part; parsing a tree from it is not.
|
|
18
|
+
*/
|
|
19
|
+
declare function preloadRubyGrammar(): Promise<void>;
|
|
20
|
+
/**
|
|
21
|
+
* `parseRuby` without the await, for a caller that cannot itself be
|
|
22
|
+
* async. Throws if `preloadRubyGrammar` (or `parseRuby`) has not already
|
|
23
|
+
* loaded the grammar in this process.
|
|
24
|
+
*/
|
|
25
|
+
declare function parseRubySync(source: string): Tree;
|
|
13
26
|
|
|
27
|
+
interface Range {
|
|
28
|
+
start: number;
|
|
29
|
+
end: number;
|
|
30
|
+
}
|
|
31
|
+
declare function field(node: Node, name: string): Node | null;
|
|
32
|
+
declare function bodyStatements(body: Node): Node[];
|
|
14
33
|
/** A call whose block is the thing being configured rather than a place statements run. */
|
|
15
34
|
type BlockConfigures = (call: Node) => boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Every statement a body runs, in source order. Ruby runs a class body
|
|
37
|
+
* like any other code, so a declaration can sit inside an `if`, a
|
|
38
|
+
* `.each` block, a `begin` or a `class_eval`, and taking the body's own
|
|
39
|
+
* child list finds the first spelling and loses the rest in silence.
|
|
40
|
+
*
|
|
41
|
+
* `blockConfigures` says which calls keep their block to themselves.
|
|
42
|
+
* `field :x, String do argument :q, String end` declares an argument on
|
|
43
|
+
* the field, not on the class, so that block is not part of the body.
|
|
44
|
+
*/
|
|
45
|
+
declare function runStatements(body: Node, blockConfigures?: BlockConfigures): Node[];
|
|
46
|
+
/** The text inside a plain string node, with the quotes removed. A string with interpolation returns null. */
|
|
47
|
+
declare function stringLiteralValue(node: Node): string | null;
|
|
48
|
+
/** tree-sitter-ruby leaves the leading colon in a `simple_symbol`'s text, but not in a `hash_key_symbol`'s. */
|
|
49
|
+
declare function symbolValue(node: Node): string | null;
|
|
50
|
+
/** A `pair` node's key, when it is written as the bare `key:` shorthand. Null for a pair keyed by a string or an expression. */
|
|
51
|
+
declare function hashKeySymbolName(node: Node): string | null;
|
|
52
|
+
declare function booleanLiteralValue(node: Node): boolean | null;
|
|
53
|
+
/** Keyword arguments turn up as `pair` nodes directly among the argument list's children, rather than wrapped in a hash node. */
|
|
54
|
+
interface CallArgs {
|
|
55
|
+
positional: Node[];
|
|
56
|
+
keyword: Record<string, Node>;
|
|
57
|
+
}
|
|
58
|
+
declare function readCallArgs(argumentList: Node | null): CallArgs;
|
|
16
59
|
|
|
17
60
|
/**
|
|
18
61
|
* Finds the file behind a constant.
|
|
@@ -81,6 +124,8 @@ declare function graphqlTypeNameFromQualified(qualifiedName: string, convention:
|
|
|
81
124
|
interface ReachedBody {
|
|
82
125
|
info: ClassInfo;
|
|
83
126
|
knownClasses: ReadonlySet<string>;
|
|
127
|
+
/** Absolute path of the file the block is written in. */
|
|
128
|
+
file: string;
|
|
84
129
|
}
|
|
85
130
|
/** One ancestor: every block reopening its name, or the name alone when nothing reached it. Blocks stay together because Ruby treats a reopened class as one place in the chain. */
|
|
86
131
|
type AncestorEntry = {
|
|
@@ -119,21 +164,30 @@ interface AncestorLookup {
|
|
|
119
164
|
declare function reachDefinition(qualifiedName: string, lookup: AncestorLookup): Promise<ReachedBody[] | null>;
|
|
120
165
|
declare function ancestryOf(name: string, blocks: readonly ReachedBody[], lookup: AncestorLookup): Promise<Ancestry>;
|
|
121
166
|
/** What searching an ancestry for one method name came to. */
|
|
122
|
-
type MethodLookup =
|
|
167
|
+
type MethodLookup =
|
|
168
|
+
/** `block` is which ancestor's own body the method is written in, so a caller that needs its file can get there. */
|
|
169
|
+
{
|
|
123
170
|
type: "found";
|
|
124
171
|
method: Node;
|
|
172
|
+
block: ReachedBody;
|
|
125
173
|
}
|
|
126
|
-
/**
|
|
174
|
+
/**
|
|
175
|
+
* `reason` completes "could be answered by a method ...".
|
|
176
|
+
* `cause` says why the search stopped, since a caller deciding
|
|
177
|
+
* whether to look further needs more than the sentence: `unreadAncestor`
|
|
178
|
+
* is a base whose file this run could not open, and `dynamicDefine`
|
|
179
|
+
* is a body that calls `define_method`.
|
|
180
|
+
*/
|
|
127
181
|
| {
|
|
128
182
|
type: "unsettled";
|
|
129
183
|
reason: string;
|
|
184
|
+
cause: "unreadAncestor" | "dynamicDefine";
|
|
130
185
|
} | {
|
|
131
186
|
type: "none";
|
|
132
187
|
};
|
|
133
188
|
/**
|
|
134
|
-
* The method `name` resolves to. An ancestor nearer than any
|
|
135
|
-
*
|
|
136
|
-
* is not what Ruby would have called.
|
|
189
|
+
* The method `name` resolves to. An unread ancestor nearer than any
|
|
190
|
+
* definition stops the search, since Ruby would have called that one first.
|
|
137
191
|
*/
|
|
138
192
|
declare function methodInAncestry(ancestry: Ancestry, name: string): MethodLookup;
|
|
139
193
|
/** Every statement of every body reached, most distant ancestor first, so a nearer declaration overwrites what it inherits. */
|
|
@@ -153,6 +207,22 @@ declare function inheritedStatements(ancestry: Ancestry, blockConfigures?: Block
|
|
|
153
207
|
|
|
154
208
|
interface RubyPack {
|
|
155
209
|
name: string;
|
|
210
|
+
/**
|
|
211
|
+
* Pack version stamp, which feeds the cache invalidation key. Bump on
|
|
212
|
+
* any change that affects discovered units or extracted summaries.
|
|
213
|
+
* The CLI folds a hash of the loaded pack file and its config into
|
|
214
|
+
* this stamp on top, so a pack run through the CLI invalidates on an
|
|
215
|
+
* edit whether or not it declares a version of its own.
|
|
216
|
+
*/
|
|
217
|
+
version?: string;
|
|
218
|
+
/**
|
|
219
|
+
* Files under the project this pack reads that are not among the
|
|
220
|
+
* `.rb` files a run walks, given the files the run is about to walk.
|
|
221
|
+
* Their content feeds the same cache key the pack's own config does,
|
|
222
|
+
* so an edit to one of them re-extracts instead of handing back the
|
|
223
|
+
* previous answer.
|
|
224
|
+
*/
|
|
225
|
+
discoveryInputs?: (files: readonly string[]) => string[];
|
|
156
226
|
/** Wire protocol for the produced boundary bindings, e.g. "http-graphql". */
|
|
157
227
|
protocol: string;
|
|
158
228
|
discovery: RubyDiscoveryPattern[];
|
|
@@ -172,7 +242,29 @@ interface RbStoragePattern {
|
|
|
172
242
|
/** Which database is behind the connection, which the project settles. */
|
|
173
243
|
storageSystem: "postgresql" | "mysql" | "sqlite";
|
|
174
244
|
}
|
|
175
|
-
type RubyDiscoveryPattern = GraphqlObjectFields;
|
|
245
|
+
type RubyDiscoveryPattern = GraphqlObjectFields | ControllerActions;
|
|
246
|
+
/** A class whose ancestry reaches one of `baseClassNames` is a controller, and every instance method it defines directly is one of its actions, bound by `routeFor` to the method and path a project's own routing gives it, or discovered with no boundary binding when `routeFor` finds none. */
|
|
247
|
+
interface ControllerActions {
|
|
248
|
+
type: "controllerActions";
|
|
249
|
+
/** The library's own base a project's controllers extend, `ActionController::Base` say. */
|
|
250
|
+
baseClassNames: string[];
|
|
251
|
+
/** The directory a bare superclass name is looked up under, the project's own layout. */
|
|
252
|
+
root: string;
|
|
253
|
+
pathConvention: ConstantPathConvention;
|
|
254
|
+
/** The library's own classes a project's controller chain ends at. */
|
|
255
|
+
ancestryRootClassNames: string[];
|
|
256
|
+
/** Status code a wire response gets when the action does not say otherwise. */
|
|
257
|
+
defaultStatusCode: number;
|
|
258
|
+
/** Absolute path of the file this pattern's own routing came from, for the one gap `routingGaps` may report. */
|
|
259
|
+
routesFile: string;
|
|
260
|
+
/** The method and path a project's own routing gives one controller's action, or null when that action has none. */
|
|
261
|
+
routeFor: (controllerQualifiedName: string, actionName: string) => {
|
|
262
|
+
method: string;
|
|
263
|
+
path: string;
|
|
264
|
+
} | null;
|
|
265
|
+
/** One message per routing declaration kind this pattern's reading left uncovered. A pure read: calling it again gives the same list. */
|
|
266
|
+
routingGaps?: () => readonly string[];
|
|
267
|
+
}
|
|
176
268
|
/** A class or module whose ancestry reaches one of `baseClassNames` declares GraphQL fields through DSL calls in its own body. */
|
|
177
269
|
interface GraphqlObjectFields {
|
|
178
270
|
type: "graphqlObjectFields";
|
|
@@ -238,12 +330,142 @@ interface DiscoveryOptions {
|
|
|
238
330
|
packs: RubyPack[];
|
|
239
331
|
/** Repo-relative or absolute path recorded on each summary's `location.file`. */
|
|
240
332
|
filePath: string;
|
|
333
|
+
/** Absolute path of the file being read, for a block's own `ReachedBody.file`. Falls back to `filePath` when nothing was written to disk. */
|
|
334
|
+
absoluteFile?: string;
|
|
241
335
|
cache: FileCache;
|
|
242
336
|
/** What a pack needs to say a call talks to the database. Absent when no pack does. */
|
|
243
337
|
storage?: RbStorageOptions | undefined;
|
|
338
|
+
/** Called once per discovered unit whose own body is a method this run can follow calls out of, so the reach walk has a place to start. */
|
|
339
|
+
onReachSeed?: (raw: RawCodeStructure, seed: ReachSeed) => void;
|
|
340
|
+
}
|
|
341
|
+
/** The method behind a discovered unit's own body, and where it lives, so the reach walk can start there the way it starts at a `def` it found directly. */
|
|
342
|
+
interface ReachSeed {
|
|
343
|
+
readonly file: string;
|
|
344
|
+
readonly node: Node;
|
|
345
|
+
/** The class the method is written in, or null for one written outside any class. */
|
|
346
|
+
readonly enclosingQualifiedName: string | null;
|
|
244
347
|
}
|
|
245
348
|
declare function discoverUnits(root: Node, options: DiscoveryOptions): Promise<RawCodeStructure[]>;
|
|
246
349
|
|
|
350
|
+
/** A definition every file in the run can see, under the name it is written as. */
|
|
351
|
+
interface ConstantDefinition {
|
|
352
|
+
readonly qualifiedName: string;
|
|
353
|
+
readonly key: string;
|
|
354
|
+
}
|
|
355
|
+
/** A constant read somewhere, with the nesting it was read inside. */
|
|
356
|
+
interface ConstantReference {
|
|
357
|
+
readonly key: string;
|
|
358
|
+
/** The name as written, `Order` or `Types::Order`. */
|
|
359
|
+
readonly written: string;
|
|
360
|
+
/** The enclosing module and class names, outermost first. */
|
|
361
|
+
readonly nesting: readonly string[];
|
|
362
|
+
}
|
|
363
|
+
interface FileConstants {
|
|
364
|
+
readonly filePath: string;
|
|
365
|
+
readonly definitions: readonly ConstantDefinition[];
|
|
366
|
+
readonly references: readonly ConstantReference[];
|
|
367
|
+
}
|
|
368
|
+
/**
|
|
369
|
+
* Every constant this file defines and every one it reads. One walk, because
|
|
370
|
+
* the nesting a reference is written inside is what the walk already knows.
|
|
371
|
+
*/
|
|
372
|
+
declare function collectFileConstants(filePath: string, root: Node): FileConstants;
|
|
373
|
+
/**
|
|
374
|
+
* Link every constant read anywhere in the run to the definition behind it,
|
|
375
|
+
* looking outwards from the nesting it was read inside the way Ruby does.
|
|
376
|
+
*
|
|
377
|
+
* `binds(refKey, defKey)` is the link itself. `rbConstantFrom(from, to)`
|
|
378
|
+
* is the same link at file level, which is the closest thing to an
|
|
379
|
+
* import graph a language without imports has.
|
|
380
|
+
*/
|
|
381
|
+
declare function emitConstantBindings(db: Database, perFile: Iterable<FileConstants>): void;
|
|
382
|
+
|
|
383
|
+
/**
|
|
384
|
+
* A node's identity across the whole run. The end is part of it because a
|
|
385
|
+
* call and its receiver start at the same offset.
|
|
386
|
+
*/
|
|
387
|
+
declare function nodeId(filePath: string, node: Node): string;
|
|
388
|
+
/**
|
|
389
|
+
* The key a read of this expression joins on, for a caller that has an
|
|
390
|
+
* expression in hand and wants to ask the rules about it. `enclosing` is
|
|
391
|
+
* the method the expression is written in, or null outside one.
|
|
392
|
+
*/
|
|
393
|
+
declare function readKey(filePath: string, node: Node, enclosing: Node | null): string;
|
|
394
|
+
/**
|
|
395
|
+
* Walk a file and emit the value facts. A method is walked in its own right,
|
|
396
|
+
* so a body's returns and calls belong to the method that wrote them.
|
|
397
|
+
*/
|
|
398
|
+
declare function emitValueFacts(db: Database, filePath: string, root: Node): void;
|
|
399
|
+
|
|
400
|
+
/**
|
|
401
|
+
* The session behind `suss ask why` on a Ruby project: a tree-sitter
|
|
402
|
+
* parse of the asked-about source, a way to point at the expression
|
|
403
|
+
* somebody spelled, and the witness proof of what it resolved to,
|
|
404
|
+
* rendered through `@suss/resolution`'s phrases.
|
|
405
|
+
*
|
|
406
|
+
* It parses every file under the root and emits the same value and
|
|
407
|
+
* constant facts `extractRubyProject` does, keeping a location for
|
|
408
|
+
* every fact key so a proof's atoms can point back at source. A
|
|
409
|
+
* handle this session hands back pairs a tree-sitter node with the
|
|
410
|
+
* file it came from, since a node alone does not say which file
|
|
411
|
+
* parsed it.
|
|
412
|
+
*/
|
|
413
|
+
|
|
414
|
+
interface RubyWhySessionOptions {
|
|
415
|
+
/** The project root, which paths in every answer come out relative to. */
|
|
416
|
+
dir: string;
|
|
417
|
+
}
|
|
418
|
+
/** A found node, paired with the file it was parsed from. */
|
|
419
|
+
interface RubyValueHandle {
|
|
420
|
+
file: string;
|
|
421
|
+
node: Node;
|
|
422
|
+
}
|
|
423
|
+
declare class RubyWhySession {
|
|
424
|
+
private readonly root;
|
|
425
|
+
private readonly db;
|
|
426
|
+
private readonly locations;
|
|
427
|
+
private readonly trees;
|
|
428
|
+
constructor(options: RubyWhySessionOptions);
|
|
429
|
+
/**
|
|
430
|
+
* The smallest expression on `line` of `file` whose text is exactly
|
|
431
|
+
* `text`, or null.
|
|
432
|
+
*/
|
|
433
|
+
findExpression(file: string, line: number, text: string): RubyValueHandle | null;
|
|
434
|
+
/**
|
|
435
|
+
* The callee of the call written as `calleeText` between `startLine`
|
|
436
|
+
* and `endLine` of `file`, or null.
|
|
437
|
+
*/
|
|
438
|
+
findCallee(file: string, startLine: number, endLine: number, calleeText: string): RubyValueHandle | null;
|
|
439
|
+
/**
|
|
440
|
+
* Why `value` resolves to what it does: the witness proof, flattened
|
|
441
|
+
* to the chain and rendered. Null when the value does not resolve,
|
|
442
|
+
* which the caller says in its own words.
|
|
443
|
+
*/
|
|
444
|
+
explain(value: RubyValueHandle, options?: {
|
|
445
|
+
maxDepth?: number;
|
|
446
|
+
}): WhyExplained | null;
|
|
447
|
+
private locate;
|
|
448
|
+
private rootOf;
|
|
449
|
+
private pathOf;
|
|
450
|
+
/** A file path said relative to the root, or as given when it is outside the root. */
|
|
451
|
+
private displayPath;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
/**
|
|
455
|
+
* facts.ts: what discovery hands to the shared fact store.
|
|
456
|
+
*
|
|
457
|
+
* This is the Layer 1 contract: discover units, emit summaries, emit
|
|
458
|
+
* these facts.
|
|
459
|
+
*
|
|
460
|
+
* `entry` reuses the existing relation name and shape, where the unit
|
|
461
|
+
* is a pack-discovered entry point, so a Ruby-discovered field is an
|
|
462
|
+
* entry the same way a Python route or a TypeScript handler is.
|
|
463
|
+
*
|
|
464
|
+
* `rbRequires(from, to)` records a `require_relative` whose target is a
|
|
465
|
+
* file in the run. A plain `require` goes through the load path, which
|
|
466
|
+
* this run does not know, so it records nothing.
|
|
467
|
+
*/
|
|
468
|
+
|
|
247
469
|
/**
|
|
248
470
|
* The name is part of the key because the range is measured in lines, two
|
|
249
471
|
* units can start on the same line, and `entry` is a set, so keying on the range
|
|
@@ -264,6 +486,16 @@ interface ExtractRubyOptions {
|
|
|
264
486
|
packs: RubyPack[];
|
|
265
487
|
/** When set, `location.file` on each summary is relativized against this. */
|
|
266
488
|
workspaceRoot?: string;
|
|
489
|
+
/** The directory a summary's id measures its file from, when that differs from `workspaceRoot`. */
|
|
490
|
+
projectRoot?: string;
|
|
491
|
+
/** Called once with the run's per-phase wall time, for `suss extract --timing`. */
|
|
492
|
+
onTiming?: (report: TimingReport) => void;
|
|
493
|
+
/** Called once with the file-by-file funnel, for `suss extract --explain`. */
|
|
494
|
+
onExtractionReport?: (report: ExtractionReport) => void;
|
|
495
|
+
/** Called once with what the cache decided, for `suss extract --timing`. */
|
|
496
|
+
onCacheDiagnostic?: (diagnostic: CacheDiagnostic) => void;
|
|
497
|
+
/** Absolute. `<projectRoot>/.suss/cache` by default; `null` turns it off. */
|
|
498
|
+
cacheDir?: string | null;
|
|
267
499
|
}
|
|
268
500
|
interface ExtractRubyResult {
|
|
269
501
|
summaries: BehavioralSummary[];
|
|
@@ -273,6 +505,36 @@ declare function extractRubyProject(options: ExtractRubyOptions): Promise<Extrac
|
|
|
273
505
|
/** Every `.rb` file under `root`, depth-first, skipping the usual non-source directories. */
|
|
274
506
|
declare function findRubyFiles(root: string): string[];
|
|
275
507
|
|
|
508
|
+
/**
|
|
509
|
+
* Evidence for drafting a graphql-ruby `extends-base` dependency stub:
|
|
510
|
+
* every `require`/`require_relative` of the asked package, and every
|
|
511
|
+
* project class whose superclass is spelled from it. Discovery
|
|
512
|
+
* only recognizes a class through `baseClassNames`' literal names (see
|
|
513
|
+
* discovery.ts's `reachesConfiguredBase`), so a project's own base
|
|
514
|
+
* under a renamed namespace, or one that extends the library's own
|
|
515
|
+
* class directly, has to state the exact name.
|
|
516
|
+
*/
|
|
517
|
+
interface RubyRequireSite {
|
|
518
|
+
target: string;
|
|
519
|
+
file: string;
|
|
520
|
+
line: number;
|
|
521
|
+
}
|
|
522
|
+
interface RubyExtendsSite {
|
|
523
|
+
className: string;
|
|
524
|
+
superclassName: string;
|
|
525
|
+
file: string;
|
|
526
|
+
line: number;
|
|
527
|
+
}
|
|
528
|
+
interface RubyStubEvidence {
|
|
529
|
+
requires: RubyRequireSite[];
|
|
530
|
+
extendsSites: RubyExtendsSite[];
|
|
531
|
+
}
|
|
532
|
+
interface RubyStubEvidenceOptions {
|
|
533
|
+
packageName: string;
|
|
534
|
+
directory: string;
|
|
535
|
+
}
|
|
536
|
+
declare function rubyStubEvidence(options: RubyStubEvidenceOptions): Promise<RubyStubEvidence>;
|
|
537
|
+
|
|
276
538
|
/**
|
|
277
539
|
* Turns a Ruby DSL call's type argument into an IR type shape.
|
|
278
540
|
*
|
|
@@ -301,4 +563,14 @@ interface TypeReadContext {
|
|
|
301
563
|
*/
|
|
302
564
|
declare function typeShapeFromNode(node: Node, ctx: TypeReadContext): TypeShape | null;
|
|
303
565
|
|
|
304
|
-
|
|
566
|
+
/**
|
|
567
|
+
* version.ts: this adapter's own half of the cache key.
|
|
568
|
+
*
|
|
569
|
+
* `ADAPTER_VERSION` is the hand-bumped semver. Bump it on any change
|
|
570
|
+
* that affects extraction output: IR shape, discovery semantics,
|
|
571
|
+
* terminal classification, anything that would invalidate previously
|
|
572
|
+
* cached summaries.
|
|
573
|
+
*/
|
|
574
|
+
declare const ADAPTER_VERSION = "0.1.0";
|
|
575
|
+
|
|
576
|
+
export { ADAPTER_VERSION, type AncestorEntry, type AncestorLookup, type Ancestry, type CallArgs, type ClassInfo, type ConstantPathConvention, type ControllerActions, type DiscoveryOptions, type ExtractRubyOptions, type ExtractRubyResult, type FileCache, type FileConstants, type GraphqlObjectFields, type GraphqlTypeNameConvention, type MethodLookup, type Range, type RbStoragePattern, type ReachedBody, type RubyDiscoveryPattern, type RubyExtendsSite, type RubyPack, type RubyRequireSite, type RubyStubEvidence, type RubyStubEvidenceOptions, type RubyValueHandle, RubyWhySession, type RubyWhySessionOptions, type TypeReadContext, ancestryOf, bodyStatements, booleanLiteralValue, collectFileConstants, createFileCache, discoverUnits, emitConstantBindings, emitEntryFact, emitValueFacts, extractRubyProject, field, findRubyFiles, graphqlTypeNameFromQualified, hashKeySymbolName, inheritedStatements, methodInAncestry, nodeId, parseRuby, parseRubySync, preloadRubyGrammar, qualifyConstantRef, reachDefinition, readCallArgs, readKey, resolveConstantFile, rubyStubEvidence, runStatements, stringLiteralValue, symbolValue, typeShapeFromNode, underscoreConstantPath, unitKey, walkClasses, walkDefinitions };
|