@g3nomaly/analyze 0.1.3 → 0.1.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.
Files changed (40) hide show
  1. package/README.md +42 -18
  2. package/dist/THIRD_PARTY_LICENSES.txt +4 -4
  3. package/dist/api/bundle-cache.d.ts +3 -1
  4. package/dist/api/graph.d.ts +131 -0
  5. package/dist/api/list.d.ts +2 -0
  6. package/dist/api/options.d.ts +2 -1
  7. package/dist/api/refs.d.ts +6 -2
  8. package/dist/api/scan.d.ts +8 -1
  9. package/dist/api/search.d.ts +5 -2
  10. package/dist/api/services.d.ts +1 -1
  11. package/dist/api/show.d.ts +2 -0
  12. package/dist/cli.js +1677 -596
  13. package/dist/index.d.ts +2 -1
  14. package/dist/index.js +1592 -556
  15. package/dist/model/index.d.ts +26 -0
  16. package/dist/model/registry.d.ts +24 -0
  17. package/dist/query/graph-view.d.ts +105 -0
  18. package/dist/query/graph.d.ts +22 -0
  19. package/dist/query/index.d.ts +3 -2
  20. package/dist/query/name-search.d.ts +1 -1
  21. package/dist/query/semantic.d.ts +10 -0
  22. package/dist/retrieval/filter.d.ts +4 -1
  23. package/dist/retrieval/graph-export.d.ts +82 -0
  24. package/dist/retrieval/index.d.ts +1 -0
  25. package/dist/retrieval/retriever.d.ts +21 -2
  26. package/dist/scanner/code/calls.d.ts +136 -0
  27. package/dist/scanner/code/extract.d.ts +10 -2
  28. package/dist/scanner/code/imports.d.ts +147 -0
  29. package/dist/scanner/code/language.d.ts +14 -0
  30. package/dist/scanner/code/planner.d.ts +16 -4
  31. package/dist/scanner/code/symbols.d.ts +19 -3
  32. package/dist/scanner/code/types.d.ts +76 -17
  33. package/dist/scanner/graph/builder.d.ts +14 -3
  34. package/dist/scanner/graph/communities.d.ts +17 -0
  35. package/dist/scanner/ignore.d.ts +5 -7
  36. package/dist/scanner/index.d.ts +4 -1
  37. package/dist/scanner/markdown/outline.d.ts +2 -0
  38. package/dist/scanner/packages.d.ts +6 -0
  39. package/dist/scanner/scanner.d.ts +2 -2
  40. package/package.json +3 -3
@@ -0,0 +1,147 @@
1
+ import type { Node } from 'web-tree-sitter';
2
+ import type { NodeRef } from '../../model';
3
+ /**
4
+ * @brief One import of a file: the paths it can stand for, most specific first. The first one that names a
5
+ * file of the scan wins.
6
+ *
7
+ * `from .models import Booking` is `['.models.Booking', '.models']`: `Booking` may be a module of its own.
8
+ */
9
+ export type ImportRequest = readonly string[];
10
+ /**
11
+ * @brief How a language names the files a file imports.
12
+ *
13
+ * Specs set it in `languages/`. `SymbolExtractor` calls `read` on each parsed file, and `CodePlanner` calls
14
+ * `resolve` once every source file of the scan is known.
15
+ */
16
+ export interface ImportSyntax {
17
+ /**
18
+ * @brief Reads the imports of a parsed file, in file order.
19
+ *
20
+ * @param root - Root node of the parsed file.
21
+ * @returns One request per import, as the file writes it.
22
+ */
23
+ read(root: Node): ImportRequest[];
24
+ /**
25
+ * @brief Finds the file an import names.
26
+ *
27
+ * @param specifier - One path of an {@link ImportRequest}, such as `slam/pose.hpp` or `./store`.
28
+ * @param from - Display path of the importing file.
29
+ * @param files - Every source file of the scan.
30
+ * @returns Display path of the imported file, or `null` when the scan has none or the specifier is ambiguous.
31
+ */
32
+ resolve(specifier: string, from: string, files: SourceFileIndex): string | null;
33
+ }
34
+ /**
35
+ * @brief Every source file of a scan with its imports, so an import can find its file and a name can tell which
36
+ * files its file sees.
37
+ *
38
+ * A file **sees** itself and every file it imports, directly or through the files those import. Created per scan
39
+ * by `RepositoryScanner` in `scanner/scanner.ts`, which hands it the packages of the scan. `CodePlanner` in
40
+ * `planner.ts` adds each source file it plans; the {@link ImportSyntax} of each language, `SymbolPlanner` and
41
+ * `CallLinker` read it back once the graph is built.
42
+ *
43
+ * @property entries - Each file by display path.
44
+ * @property byName - Display paths of the files with each file name.
45
+ * @property packages - Directory of each package of the scan, by the name its manifest gives.
46
+ * @property resolved - Display paths each file imports, resolved on first use.
47
+ * @property seen - Display paths each file sees, computed on first use.
48
+ */
49
+ export declare class SourceFileIndex {
50
+ private readonly entries;
51
+ private readonly byName;
52
+ private packages;
53
+ private readonly resolved;
54
+ private readonly seen;
55
+ /**
56
+ * @brief Adds a source file.
57
+ *
58
+ * @param path - Display path of the file.
59
+ * @param ref - Node of the file.
60
+ * @param syntax - How its language names imports, or `null` when its imports are not read.
61
+ * @param requests - Its imports, as the file writes them.
62
+ */
63
+ add(path: string, ref: NodeRef, syntax: ImportSyntax | null, requests: readonly ImportRequest[]): void;
64
+ /**
65
+ * @brief Tells the index where each package of the scan is, so an import of a package by name finds its files.
66
+ *
67
+ * @param packages - Each package by the display path of its directory, as `detectPackages` returns them.
68
+ */
69
+ usePackages(packages: ReadonlyMap<string, {
70
+ readonly packageName: string;
71
+ }>): void;
72
+ /**
73
+ * @brief Directory of the package with a name.
74
+ *
75
+ * @param name - Name its manifest gives, such as `@g3nomaly/core`.
76
+ * @returns Display path of its directory, `''` for the root, or `undefined` when the scan has no such package.
77
+ */
78
+ packageDirectory(name: string): string | undefined;
79
+ /**
80
+ * @brief Node of the source file at `path`.
81
+ *
82
+ * @param path - Display path of a file.
83
+ * @returns The node, or `undefined` when the scan has no source file there.
84
+ */
85
+ refOf(path: string): NodeRef | undefined;
86
+ /**
87
+ * @brief Tells whether the scan has a source file at `path`.
88
+ *
89
+ * @param path - Display path of a file.
90
+ */
91
+ has(path: string): boolean;
92
+ /**
93
+ * @brief The source files whose path is `tail` or ends with `/tail`, such as `libs/slam/include/slam/pose.hpp` for `slam/pose.hpp`.
94
+ *
95
+ * @param tail - Relative path, such as `slam/pose.hpp`.
96
+ * @returns Display paths of the matching files.
97
+ */
98
+ endingWith(tail: string): string[];
99
+ /**
100
+ * @brief The source files a file imports, each once. For each import the first path of its request that names a
101
+ * file of the scan counts.
102
+ *
103
+ * @param path - Display path of the importing file.
104
+ * @returns Display paths of the imported files, in the order the file imports them.
105
+ */
106
+ importsOf(path: string): readonly string[];
107
+ /**
108
+ * @brief Tells whether the scan reads the imports of a file, so what it sees is known.
109
+ *
110
+ * @param path - Display path of a file.
111
+ */
112
+ tracksImports(path: string): boolean;
113
+ /**
114
+ * @brief Tells whether a file sees another: it is that file, or imports it directly or through other files.
115
+ *
116
+ * @param from - Display path of the file a name is used in.
117
+ * @param to - Display path of the file a declaration is in.
118
+ * @returns True when `from` sees `to`, and always for a file whose imports the scan does not read.
119
+ */
120
+ sees(from: string, to: string): boolean;
121
+ }
122
+ /**
123
+ * @brief `#include "x.h"` and `#include <x.h>` of C and C++.
124
+ *
125
+ * An include resolves next to the including file first, then against every file whose path ends with it, such
126
+ * as `libs/slam/include/slam/pose.hpp` for `slam/pose.hpp`. When several end with it, the one closest to the
127
+ * including file wins. A header of a library outside the repository, such as `<vector>`, resolves to nothing.
128
+ */
129
+ export declare const C_INCLUDES: ImportSyntax;
130
+ /**
131
+ * @brief `import`, `export … from`, `import()` and `require()` of JavaScript and TypeScript.
132
+ *
133
+ * A relative specifier, such as `./store` or `../model/index.js`, resolves next to the importing file. A package of
134
+ * the scan, such as `@g3nomaly/core` or `@g3nomaly/core/config`, resolves below its directory or its `src`
135
+ * directory. A path alias such as `@/components/button` or `~/lib/api` resolves against every file whose path ends
136
+ * with what follows the alias, the closest winning. Each may leave out the extension, name a directory with an
137
+ * `index` file, or write `.js` for a `.ts` file. Any other package, such as `zod`, resolves to nothing.
138
+ */
139
+ export declare const ECMASCRIPT_IMPORTS: ImportSyntax;
140
+ /**
141
+ * @brief `import a.b` and `from .a import b` of Python.
142
+ *
143
+ * A relative module resolves against the directory of the importing file. An absolute one resolves against every
144
+ * file whose path ends with it, as `a/b.py` or `a/b/__init__.py`, the closest winning. `from a import b` tries
145
+ * the module `a.b` first, then `a`.
146
+ */
147
+ export declare const PYTHON_IMPORTS: ImportSyntax;
@@ -1,5 +1,6 @@
1
1
  import type { SymbolKind } from '../../model';
2
2
  import type { Node } from 'web-tree-sitter';
3
+ import type { ImportSyntax } from './imports';
3
4
  /**
4
5
  * @brief Doc comment dialect, which decides how the scanner reads doc comments.
5
6
  *
@@ -116,6 +117,14 @@ export interface CallStyle {
116
117
  * @property splitQualifiedName - Splits a qualified name such as `Foo::bar` into owner and member.
117
118
  * @property declaredReturnType - Reads the return type when the `@return` capture cannot express it, such as a C pointer.
118
119
  * @property call - How the language spells a call.
120
+ * @property imports - How the language names the files a file imports. Without it a file of the language imports nothing.
121
+ * @property namespaceSeparator - Separator of a qualified type name, such as `::` in `geo::Point`. When set, a
122
+ * qualified name only links to a declaration inside a namespace or type of that name.
123
+ * @property isPrivateFile - Answers whether the other files cannot see the types of a file, as for a C++ source file
124
+ * next to its headers. Its functions stay visible unless `isInternal` says otherwise.
125
+ * @property isInternal - Answers whether a function is visible only in its own file, such as a `static` C function.
126
+ * @property implicitReceiver - Whether a bare call inside a method can call another method of its type, as `flush()`
127
+ * means `this->flush()` in C++. Unset where a method needs `this.` or `self.`, as in JavaScript and Python.
119
128
  */
120
129
  export interface LanguageSpec {
121
130
  readonly id: string;
@@ -166,6 +175,11 @@ export interface LanguageSpec {
166
175
  returnsValue(facts: DefinitionFacts): boolean;
167
176
  readonly declaredReturnType?: (facts: DefinitionFacts) => string | null;
168
177
  readonly call: CallStyle;
178
+ readonly imports?: ImportSyntax;
179
+ readonly namespaceSeparator?: string;
180
+ readonly isPrivateFile?: (path: string) => boolean;
181
+ readonly isInternal?: (facts: DefinitionFacts) => boolean;
182
+ readonly implicitReceiver?: boolean;
169
183
  }
170
184
  /**
171
185
  * Language family of a spec.
@@ -7,6 +7,7 @@ import { type Reporter } from '../reporter';
7
7
  import type { SqlPlanner } from '../sql/planner';
8
8
  import type { SymbolExtractor } from './extract';
9
9
  import type { GrammarLoader } from './grammar';
10
+ import type { SourceFileIndex } from './imports';
10
11
  import type { LanguageRegistry } from './languages';
11
12
  import type { SymbolPlanner } from './symbols';
12
13
  /**
@@ -22,7 +23,7 @@ export interface SourceFile {
22
23
  readonly displayPath: string;
23
24
  }
24
25
  /**
25
- * @brief Adds source files and their symbols to the graph.
26
+ * @brief Adds source files and their symbols to the graph, and an `imports` edge for each file a file imports.
26
27
  *
27
28
  * The SQL files of a repository are no code: `DatabasePlanner` adds them. A SQL file of a skill
28
29
  * that creates tables goes to the `SqlPlanner`.
@@ -34,7 +35,7 @@ export interface SourceFile {
34
35
  * `SkillPlanner` in `skills/planner.ts` calls `isSource` and `planFile`.
35
36
  *
36
37
  * @example
37
- * const code = new CodePlanner(graph, registry, grammars, extractor, symbols, files, sql, reporter);
38
+ * const code = new CodePlanner(graph, registry, grammars, extractor, symbols, sources, files, sql, reporter);
38
39
  * await code.planTree(sections.code, source);
39
40
  */
40
41
  export declare class CodePlanner {
@@ -43,6 +44,7 @@ export declare class CodePlanner {
43
44
  private readonly grammars;
44
45
  private readonly extractor;
45
46
  private readonly symbols;
47
+ private readonly sources;
46
48
  private readonly files;
47
49
  private readonly sql;
48
50
  private readonly reporter;
@@ -54,11 +56,12 @@ export declare class CodePlanner {
54
56
  * @param grammars - Loads the parser and query of a language spec.
55
57
  * @param extractor - Extracts the raw symbols from a parsed syntax tree.
56
58
  * @param symbols - Adds the symbols of a file below its source node.
59
+ * @param sources - Every source file of the scan, which the imports resolve against.
57
60
  * @param files - Reads the text of a file, to embed it in its node.
58
61
  * @param sql - Adds SQL files that create tables as databases.
59
62
  * @param reporter - Receives a warning for each file that cannot be read or parsed. Silent by default.
60
63
  */
61
- constructor(graph: GraphBuilder, registry: LanguageRegistry, grammars: GrammarLoader, extractor: SymbolExtractor, symbols: SymbolPlanner, files: FileRenderer, sql: SqlPlanner, reporter?: Reporter);
64
+ constructor(graph: GraphBuilder, registry: LanguageRegistry, grammars: GrammarLoader, extractor: SymbolExtractor, symbols: SymbolPlanner, sources: SourceFileIndex, files: FileRenderer, sql: SqlPlanner, reporter?: Reporter);
62
65
  /**
63
66
  * @brief Tells whether a file is source code, whether or not the scanner can read its symbols.
64
67
  *
@@ -66,7 +69,7 @@ export declare class CodePlanner {
66
69
  */
67
70
  isSource(path: string): boolean;
68
71
  /**
69
- * @brief Adds every file of `source` that declares a class or a function, in folders below `section`.
72
+ * @brief Adds every file of `source` that declares a class or a function or imports a file, in folders below `section`.
70
73
  *
71
74
  * Files in unsupported languages are skipped. JSON, TOML and YAML files go to `configs`, in the same
72
75
  * pass, so the tree stays in path order.
@@ -89,6 +92,8 @@ export declare class CodePlanner {
89
92
  /**
90
93
  * @brief Adds a `source` node for the file below `parent`, registers its display path, and plans its symbols.
91
94
  *
95
+ * Its imports resolve when the graph is built, once every source file of the scan is known.
96
+ *
92
97
  * @param parent - Node the file is added below.
93
98
  * @param file - File to add.
94
99
  * @param extracted - Symbols of the file, or `null` to add the file without symbols.
@@ -96,6 +101,13 @@ export declare class CodePlanner {
96
101
  * @returns Node of the file.
97
102
  */
98
103
  private add;
104
+ /**
105
+ * @brief Records an `imports` edge from a file to each file of the scan it imports.
106
+ *
107
+ * @param from - Node of the importing file.
108
+ * @param path - Display path of the importing file.
109
+ */
110
+ private linkImports;
99
111
  /**
100
112
  * @brief Reads the symbols of a file.
101
113
  *
@@ -3,6 +3,8 @@ import type { GraphBuilder } from '../graph/builder';
3
3
  import type { CodeHighlighter } from '../highlight';
4
4
  import type { ProseResolvers } from '../markdown/links';
5
5
  import type { MarkdownRenderer } from '../markdown/renderer';
6
+ import type { CallLinker } from './calls';
7
+ import type { SourceFileIndex } from './imports';
6
8
  import type { RawSymbol } from './extract';
7
9
  import { type LanguageSpec } from './language';
8
10
  import type { CallableIndex, TypeIndex, TypeLinker } from './types';
@@ -22,13 +24,13 @@ export interface FileContext {
22
24
  * @brief Adds the symbols of a file to the graph: one node per class or function,
23
25
  * with a child node per parameter and field.
24
26
  *
25
- * Type names in signatures become links to the types they name. Holds the graph, the renderers,
27
+ * Type names in signatures become links to the types they name, and calls in bodies become `calls` edges. Holds the graph, the renderers,
26
28
  * and the indexes and linkers it registers into and links through. Created per scan by
27
29
  * `RepositoryScanner` in `scanner/scanner.ts`; `CodePlanner` in `planner.ts` calls `plan` for
28
30
  * each file it extracts symbols from.
29
31
  *
30
32
  * @example
31
- * const symbols = new SymbolPlanner(graph, highlighter, markdown, types, callables, linker, resolvers);
33
+ * const symbols = new SymbolPlanner(graph, highlighter, markdown, types, callables, linker, calls, sources, resolvers);
32
34
  * symbols.plan(fileRef, { spec, path: 'src/app.ts', packageName: null }, extracted.symbols);
33
35
  */
34
36
  export declare class SymbolPlanner {
@@ -38,6 +40,8 @@ export declare class SymbolPlanner {
38
40
  private readonly types;
39
41
  private readonly callables;
40
42
  private readonly linker;
43
+ private readonly calls;
44
+ private readonly sources;
41
45
  private readonly resolvers;
42
46
  /**
43
47
  * Takes the graph and renderers it writes with, and the indexes and linkers that resolve names.
@@ -48,9 +52,11 @@ export declare class SymbolPlanner {
48
52
  * @param types - Index of type declarations, where each new type is registered.
49
53
  * @param callables - Index of functions and methods, where each new callable is registered.
50
54
  * @param linker - Links the type names of signatures to their declarations.
55
+ * @param calls - Links the calls in function bodies to the functions they reach.
56
+ * @param sources - Source files with their imports, which decide the files a name can refer to.
51
57
  * @param resolvers - Resolves the names in prose descriptions to links.
52
58
  */
53
- constructor(graph: GraphBuilder, highlighter: CodeHighlighter, markdown: MarkdownRenderer, types: TypeIndex, callables: CallableIndex, linker: TypeLinker, resolvers: ProseResolvers);
59
+ constructor(graph: GraphBuilder, highlighter: CodeHighlighter, markdown: MarkdownRenderer, types: TypeIndex, callables: CallableIndex, linker: TypeLinker, calls: CallLinker, sources: SourceFileIndex, resolvers: ProseResolvers);
54
60
  /**
55
61
  * @brief Adds `symbols` and everything inside them below the file node `fileRef`.
56
62
  *
@@ -81,6 +87,16 @@ export declare class SymbolPlanner {
81
87
  * @returns Content of the symbol node.
82
88
  */
83
89
  private symbolContent;
90
+ /**
91
+ * @brief Records the `calls` edges of a function, with its parameters and the fields of its type as the
92
+ * variables a call can go through.
93
+ *
94
+ * @param symbol - The calling function.
95
+ * @param scope - Where the function sits in the file.
96
+ * @param typeScope - Scope that the names of the function resolve in.
97
+ * @param self - Node of the function, where the edges start.
98
+ */
99
+ private linkCalls;
84
100
  /**
85
101
  * @brief Builds the content of a parameter or field node: linked type, default, optional flag and rendered description.
86
102
  *
@@ -6,20 +6,45 @@ import type { GraphBuilder } from '../graph/builder';
6
6
  * @property path - Display path of the file the name is in. `null` for a name in prose, which has no file of its own.
7
7
  * @property family - Language family of the name. `null` matches every language.
8
8
  * @property typeParameters - Type parameters in scope, such as `T`. They are never linked.
9
+ * @property namespaceSeparator - Separator of a qualified name in this language, such as `::`, from the spec's
10
+ * `namespaceSeparator`. Unset where a qualifier may be a module or a variable, which says nothing about the declaration.
11
+ * @property sees - Tells whether the file of the name sees a file, through what it imports. Unset where every file
12
+ * counts, as for prose.
9
13
  */
10
14
  export interface TypeScope {
11
15
  readonly path: string | null;
12
16
  readonly family: string | null;
13
17
  readonly typeParameters: ReadonlySet<string>;
18
+ readonly namespaceSeparator?: string;
19
+ readonly sees?: (path: string) => boolean;
14
20
  }
15
21
  /** Scope of a name in a document: any language, no file. */
16
22
  export declare const PROSE_SCOPE: TypeScope;
23
+ /**
24
+ * @brief One declaration of a name: its node, where it is, and who can see it.
25
+ *
26
+ * @property ref - Node of the declaration.
27
+ * @property path - Display path of the file that declares it.
28
+ * @property family - Language family of that file.
29
+ * @property owners - Names of the namespaces and types around it, outermost first, such as `['geo', 'Point']`.
30
+ * @property local - Whether only its own file can see it, as a type in a C++ source file or a `static` C function.
31
+ * @property privateFile - Whether its file is one the other files cannot see, such as a C++ source file. A
32
+ * declaration there that has a twin in a header is the definition of that twin.
33
+ */
34
+ export interface DeclarationSite {
35
+ readonly ref: NodeRef;
36
+ readonly path: string;
37
+ readonly family: string;
38
+ readonly owners: readonly string[];
39
+ readonly local: boolean;
40
+ readonly privateFile: boolean;
41
+ }
17
42
  /**
18
43
  * @brief Every class, interface, struct, enum, trait and type alias of the scan, by name.
19
44
  *
20
45
  * Holds every declaration of each name. Created per scan by `RepositoryScanner` in
21
46
  * `scanner/scanner.ts`; `SymbolPlanner` in `symbols.ts` registers each type it adds,
22
- * and {@link TypeLinker} resolves names against it. Created with `new TypeIndex()`.
47
+ * and {@link TypeLinker} and `CallLinker` in `calls.ts` resolve names against it. Created with `new TypeIndex()`.
23
48
  *
24
49
  * @property byName - Declarations of each name.
25
50
  */
@@ -29,11 +54,9 @@ export declare class TypeIndex {
29
54
  * @brief Adds a type declaration under its name.
30
55
  *
31
56
  * @param name - Name the type is declared with.
32
- * @param ref - Node of the declaration.
33
- * @param path - Display path of the file that declares it.
34
- * @param family - Language family of that file, from `familyOf`.
57
+ * @param site - Node, file and visibility of the declaration.
35
58
  */
36
- register(name: string, ref: NodeRef, path: string, family: string): void;
59
+ register(name: string, site: DeclarationSite): void;
37
60
  /**
38
61
  * @brief The declaration a name refers to, or `null` when there is none or the name is ambiguous.
39
62
  *
@@ -41,20 +64,29 @@ export declare class TypeIndex {
41
64
  *
42
65
  * @param name - Identifier to resolve.
43
66
  * @param scope - Where the name is used.
67
+ * @param qualifier - Names written in front of it, outermost first. Empty for a bare name.
44
68
  * @returns The node of the declaration, or `null`.
45
69
  */
46
- resolve(name: string, scope: TypeScope): NodeRef | null;
70
+ resolve(name: string, scope: TypeScope, qualifier?: readonly string[]): NodeRef | null;
71
+ }
72
+ /**
73
+ * @brief Where a function or method is declared, and whether it is a member of a type.
74
+ *
75
+ * @property member - Whether a type owns it, so only a call through that type or one of its instances reaches it.
76
+ */
77
+ export interface CallableSite extends DeclarationSite {
78
+ readonly member: boolean;
47
79
  }
48
80
  /**
49
81
  * @brief Every function and method of the scan, by name and by `Owner.name`. Lets
50
- * prose refer to a function the way it refers to a type.
82
+ * prose refer to a function the way it refers to a type, and calls find what they call.
51
83
  *
52
84
  * Holds every declaration of each key. Created per scan by `RepositoryScanner` in
53
85
  * `scanner/scanner.ts`; `SymbolPlanner` in `symbols.ts` registers each function and
54
- * method it adds, and {@link TypeLinker.mention} resolves inline code against it.
55
- * Created with `new CallableIndex()`.
86
+ * method it adds, {@link TypeLinker.mention} resolves inline code against it, and `CallLinker`
87
+ * in `calls.ts` resolves calls. Created with `new CallableIndex()`.
56
88
  *
57
- * @property byName - Declarations of each key: the name, and `Owner.name` for a method.
89
+ * @property byName - Declarations of each key: the name, and `Owner.name` for a function with an owner.
58
90
  */
59
91
  export declare class CallableIndex {
60
92
  private readonly byName;
@@ -62,12 +94,9 @@ export declare class CallableIndex {
62
94
  * @brief Adds a function or method under its name and, when it has an owner, under `Owner.name`.
63
95
  *
64
96
  * @param name - Name the function is declared with.
65
- * @param owner - Name of the type or namespace it is declared in, or `null`.
66
- * @param ref - Node of the declaration.
67
- * @param path - Display path of its file.
68
- * @param family - Language family of its file, from `familyOf`.
97
+ * @param site - Node, file and visibility of the declaration. Its last owner, if any, is the `Owner` of the key.
69
98
  */
70
- register(name: string, owner: string | null, ref: NodeRef, path: string, family: string): void;
99
+ register(name: string, site: CallableSite): void;
71
100
  /**
72
101
  * @brief The function a piece of inline code names.
73
102
  *
@@ -76,7 +105,34 @@ export declare class CallableIndex {
76
105
  * @returns The function, or `null` when the text names none or more than one.
77
106
  */
78
107
  resolve(text: string, scope: TypeScope): NodeRef | null;
108
+ /**
109
+ * @brief The function a call reaches.
110
+ *
111
+ * @param name - Name the call uses.
112
+ * @param scope - Where the call is.
113
+ * @param owner - The type or namespace the call goes through, or `null` for a call of a free function.
114
+ * @param qualifier - Names written in front of `owner`, outermost first, which the declaration's owners must end with.
115
+ * @returns The function, or `null` when the call reaches none of the scan or the name is ambiguous.
116
+ */
117
+ resolveCall(name: string, scope: TypeScope, owner: string | null, qualifier?: readonly string[]): NodeRef | null;
79
118
  }
119
+ /**
120
+ * @brief Counts the leading directories two file paths have in common.
121
+ *
122
+ * @param a - POSIX path of a file.
123
+ * @param b - POSIX path of a file.
124
+ * @returns Number of leading directories the two paths share.
125
+ */
126
+ export declare function sharedDirectories(a: string, b: string): number;
127
+ /**
128
+ * @brief The names written in front of the name at `index`, each followed by `separator`, outermost first.
129
+ *
130
+ * @param text - Source text, such as `const geo::Point&`.
131
+ * @param index - Offset of the name in `text`.
132
+ * @param separator - Separator of a qualified name, such as `::`.
133
+ * @returns The qualifier, such as `['geo']`, or `[]` for a bare name.
134
+ */
135
+ export declare function qualifierBefore(text: string, index: number, separator: string): string[];
80
136
  /**
81
137
  * @brief Turns type names in source text into links between nodes, and records each link as an edge.
82
138
  *
@@ -104,7 +160,9 @@ export declare class TypeLinker {
104
160
  /**
105
161
  * @brief Links every known type name in `text`, such as `Booking` in `Promise<Booking>`.
106
162
  *
107
- * Records one `relation` edge from `from` to each type it finds.
163
+ * Records one `relation` edge from `from` to each type it finds. Where the scope has a namespace separator, a
164
+ * qualified name such as `Eigen::Quaterniond` only links to a declaration inside `Eigen`, and the qualifier
165
+ * itself is no type name.
108
166
  *
109
167
  * @param text - Source text to scan for names.
110
168
  * @param from - Node the text belongs to. The edges start here.
@@ -116,7 +174,8 @@ export declare class TypeLinker {
116
174
  /**
117
175
  * @brief The type or function that inline code names, and an edge to it.
118
176
  *
119
- * @param text - Inline code, such as `Booking` or `choose_route()`.
177
+ * @param text - Inline code, such as `Booking`, `geo::Point` or `choose_route()`. A qualified type name only
178
+ * names a type declared inside what qualifies it.
120
179
  * @param from - Node the code is written in. The edge starts here.
121
180
  * @param scope - Where the code is used.
122
181
  * @param relation - Kind of edge to record, `mentions` by default.
@@ -34,7 +34,8 @@ export type ContentSource<K extends NodeType> = (self: NodeRef) => ContentOf<K>
34
34
  * @property folders - Folder nodes by `parent/name`.
35
35
  * @property files - File nodes by normalized path.
36
36
  * @property packages - Packages by display path of their directory, set by `markPackages`.
37
- * @property packageSections - Sections whose folders become `package` nodes where a package sits.
37
+ * @property packageSections - Sections whose folders become `package` nodes where a package sits, most preferred first.
38
+ * @property packageNodes - Every `package` node `folder` created, with the display path of its directory and the rank of its section in `packageSections`.
38
39
  * @example
39
40
  * const graph = new GraphBuilder();
40
41
  */
@@ -45,7 +46,8 @@ export declare class GraphBuilder {
45
46
  private readonly folders;
46
47
  private readonly files;
47
48
  private packages;
48
- private readonly packageSections;
49
+ private packageSections;
50
+ private readonly packageNodes;
49
51
  /**
50
52
  * @brief Adds a node. Kinds without content of their own, such as folders, take no `content`.
51
53
  *
@@ -57,7 +59,10 @@ export declare class GraphBuilder {
57
59
  /**
58
60
  * @brief Makes `folder` create a `package` node instead of a folder for every package directory below the given sections.
59
61
  *
60
- * @param sections - Sections whose `folder` paths are display paths of the repository, such as the code and docs sections.
62
+ * One directory stays one package: when it is a package below several of the sections, `build` keeps the
63
+ * `package` node of the first of them and turns the others into plain folders.
64
+ *
65
+ * @param sections - Sections whose `folder` paths are display paths of the repository, most preferred first, such as the code and then the docs section.
61
66
  * @param packages - Packages by display path of their directory, as `detectPackages` returns them.
62
67
  */
63
68
  markPackages(sections: readonly NodeRef[], packages: ReadonlyMap<string, PackageInfo>): void;
@@ -65,6 +70,7 @@ export declare class GraphBuilder {
65
70
  * @brief Finds the folder at `directory` below `parent`, creating it and its ancestors on first use.
66
71
  *
67
72
  * Below a section passed to `markPackages`, a directory that holds a package becomes a `package` node.
73
+ * `build` keeps one of them per directory.
68
74
  *
69
75
  * @param parent - Node the directory is below.
70
76
  * @param directory - Slash-separated path, such as `docs/guides`. `''` names `parent` itself.
@@ -110,5 +116,10 @@ export declare class GraphBuilder {
110
116
  nodes: GraphNode[];
111
117
  edges: Edge[];
112
118
  }>;
119
+ /**
120
+ * @brief Turns every `package` node of a directory into a plain folder, except the one in the most preferred
121
+ * section passed to `markPackages`. A folder has the same route as a package, so links made before stay valid.
122
+ */
123
+ private keepOnePackagePerDirectory;
113
124
  }
114
125
  export {};
@@ -0,0 +1,17 @@
1
+ import type { CommunityIndex, Edge, GraphNode } from '../../model';
2
+ /**
3
+ * @brief Splits the nodes of a scan into communities: groups whose nodes link to each other more than to the rest.
4
+ *
5
+ * Every page and entry is one unit: a file, a class, a function, a term, a table. A parameter or field counts
6
+ * as the entry it belongs to. A section, folder or package belongs to no community. Every edge between two
7
+ * units links them, and so does each unit with the unit it is in, such as a method with its class.
8
+ *
9
+ * The split maximises modularity with the Louvain method: nodes move to the community of a neighbour while
10
+ * that raises modularity, then each community becomes one node and the next level starts. It walks the nodes
11
+ * in order, so one scan gives one split.
12
+ *
13
+ * @param nodes - Every node of the scan, in `NodeRef` order.
14
+ * @param edges - Every edge of the scan.
15
+ * @returns The community of each node and the label of each community, the largest first.
16
+ */
17
+ export declare function detectCommunities(nodes: readonly GraphNode[], edges: readonly Edge[]): CommunityIndex;
@@ -1,6 +1,6 @@
1
1
  /** Name of the file at the root of a repository that lists what analyze skips. */
2
2
  export declare const IGNORE_FILE = ".analyzeignore";
3
- /** Lines of the `.analyzeignore` that analyze writes when a repository has none. */
3
+ /** The patterns analyze skips when a repository has no `.analyzeignore`, in the format of that file. */
4
4
  export declare const DEFAULT_IGNORE_LINES: readonly string[];
5
5
  /**
6
6
  * @brief Turns the lines of an ignore file into globs that `Bun.Glob` matches against root-relative paths.
@@ -14,12 +14,10 @@ export declare const DEFAULT_IGNORE_LINES: readonly string[];
14
14
  */
15
15
  export declare function ignoreGlobs(text: string): string[];
16
16
  /**
17
- * @brief Reads the `.analyzeignore` of a repository, and writes one with {@link DEFAULT_IGNORE_LINES} when it has none.
17
+ * @brief Reads the `.analyzeignore` of a repository. Without one, the built-in {@link DEFAULT_IGNORE_LINES} apply.
18
+ * A file replaces the built-in list rather than adding to it. Nothing is written.
18
19
  *
19
20
  * @param repo - Absolute path of the repository.
20
- * @returns The globs of the file, and whether this call created the file.
21
+ * @returns The globs of the file, or of the built-in list when the repository has no file.
21
22
  */
22
- export declare function loadIgnoreFile(repo: string): {
23
- globs: string[];
24
- created: boolean;
25
- };
23
+ export declare function loadIgnoreFile(repo: string): string[];
@@ -1,10 +1,12 @@
1
+ export { CallLinker, type CallContext, type CallVia, type RawCall, readCalls } from './code/calls';
1
2
  export { type ExtractedFile, type RawField, type RawParameter, type RawSymbol, SymbolExtractor } from './code/extract';
2
3
  export { GrammarLoader } from './code/grammar';
4
+ export { C_INCLUDES, ECMASCRIPT_IMPORTS, type ImportRequest, type ImportSyntax, PYTHON_IMPORTS, SourceFileIndex, } from './code/imports';
3
5
  export type { CallStyle, DocStyle, LanguageSpec } from './code/language';
4
6
  export { LANGUAGES, LanguageRegistry } from './code/languages';
5
7
  export { CodePlanner, type SourceFile } from './code/planner';
6
8
  export { type FileContext, SymbolPlanner } from './code/symbols';
7
- export { CallableIndex, PROSE_SCOPE, TypeIndex, TypeLinker, type TypeScope } from './code/types';
9
+ export { CallableIndex, type CallableSite, type DeclarationSite, PROSE_SCOPE, TypeIndex, TypeLinker, type TypeScope, } from './code/types';
8
10
  export { FileRenderer, type RenderedFile } from './content';
9
11
  export { type ParsedDecision, type ParsedDecisions, parseDecisions } from './decisions/parse';
10
12
  export { DecisionPlanner } from './decisions/planner';
@@ -16,6 +18,7 @@ export { type ParsedGlossary, type ParsedTerm, parseGlossary } from './glossary/
16
18
  export { GlossaryPlanner } from './glossary/planner';
17
19
  export { type TermFinder, TermIndex, TermLinker, type TermMatch } from './glossary/terms';
18
20
  export { type ContentOf, type ContentSource, GraphBuilder, type IdentityOf } from './graph/builder';
21
+ export { detectCommunities } from './graph/communities';
19
22
  export { type CodeHighlighter, ShikiHighlighter } from './highlight';
20
23
  export { type LinkOrigin, ProseResolvers } from './markdown/links';
21
24
  export { joinLines, type MarkdownLine, outlineLines, plainText } from './markdown/outline';
@@ -22,6 +22,8 @@ export declare function outlineLines(markdown: string): MarkdownLine[];
22
22
  /**
23
23
  * @brief Removes inline markdown markers from a short text such as a heading.
24
24
  *
25
+ * A code span keeps its text as it is. An `_` inside a word, as in `add_library`, is no emphasis and stays.
26
+ *
25
27
  * @param markdown - Inline markdown, for example `**Lane** (_route_)`.
26
28
  * @returns The text a reader sees, for example `Lane (route)`.
27
29
  */
@@ -22,6 +22,12 @@ export interface PackageInfo {
22
22
  * A directory with several manifests is read by the first reader in `READERS` that understands one. The root
23
23
  * directory of a source is left out: it is the repository itself.
24
24
  *
25
+ * A `vcpkg.json` marks a package wherever it is. A `CMakeLists.txt` marks one only when it builds a package of
26
+ * its own: it calls `project(`, or a command whose name holds `library` or `executable` (such as `add_library` or a
27
+ * `g3n_add_library` macro), or its directory has an `include/` folder. In a `src`, `test`, `tests`, `cmake` or
28
+ * `examples` directory of a package only `project(` counts, so the CMake files a package pulls in with
29
+ * `add_subdirectory` do not make packages of their own. {@link readCMake} has the details.
30
+ *
25
31
  * @param sources - Directories with their files, such as the code sources of a scan.
26
32
  * @returns Packages by display path of their directory, such as `packages/core`.
27
33
  */
@@ -60,7 +60,7 @@ export declare class RepositoryScanner {
60
60
  * code, database and tasks, in that order.
61
61
  *
62
62
  * @param input - The directories of each section.
63
- * @returns The nodes and edges of the bundle, without its meta and semantic index.
63
+ * @returns The nodes, edges and communities of the bundle, without its meta and semantic index.
64
64
  */
65
- scan(input: ScanInput): Promise<Pick<DocsBundle, 'nodes' | 'edges'>>;
65
+ scan(input: ScanInput): Promise<Required<Pick<DocsBundle, 'nodes' | 'edges' | 'communities'>>>;
66
66
  }