|
1 | 1 | import { ContractDefinition, SourceUnit } from "solidity-ast";
|
2 | 2 | import { findAll } from "solidity-ast/utils";
|
3 | 3 | import { DocItemWithContext } from "../site";
|
| 4 | +import { mapValues } from './map-values'; |
4 | 5 |
|
5 | 6 | export function getContractsInScope(item: DocItemWithContext) {
|
6 |
| - const cache = new WeakMap<SourceUnit, Record<string, ContractDefinition>>(); |
7 |
| - return run(item.__item_context.file); |
| 7 | + const cache = new WeakMap<SourceUnit, Record<string, () => ContractDefinition>>(); |
| 8 | + return mapValues(run(item.__item_context.file), fn => fn()); |
8 | 9 |
|
9 | 10 | function run(
|
10 | 11 | file: SourceUnit,
|
11 |
| - stack = new Set<SourceUnit>(), |
12 | 12 | aliasedImport = false,
|
13 |
| - ): Record<string, ContractDefinition> { |
14 |
| - if (stack.has(file)) { |
15 |
| - if (aliasedImport) { |
16 |
| - throw new Error('Circular dependency detected: aliased imports not supported'); |
17 |
| - } else { |
18 |
| - return {}; |
19 |
| - } |
20 |
| - } |
21 |
| - |
| 13 | + ): Record<string, () => ContractDefinition> { |
22 | 14 | if (cache.has(file)) {
|
23 | 15 | return cache.get(file)!;
|
24 | 16 | }
|
25 | 17 |
|
26 |
| - stack.add(file); |
| 18 | + const scope: Record<string, () => ContractDefinition> = {}; |
27 | 19 |
|
28 |
| - const scope: Record<string, ContractDefinition> = {}; |
| 20 | + cache.set(file, scope); |
29 | 21 |
|
30 | 22 | for (const c of findAll('ContractDefinition', file)) {
|
31 |
| - scope[c.name] = c; |
| 23 | + scope[c.name] = () => c; |
32 | 24 | }
|
33 | 25 |
|
34 | 26 | for (const i of findAll('ImportDirective', file)) {
|
35 | 27 | const importedFile = item.__item_context.build.deref('SourceUnit', i.sourceUnit);
|
36 |
| - const importedScope = run(importedFile, stack, aliasedImport || i.symbolAliases.length > 0); |
| 28 | + const importedScope = run(importedFile, aliasedImport || i.symbolAliases.length > 0); |
37 | 29 | if (i.symbolAliases.length === 0) {
|
38 | 30 | Object.assign(scope, importedScope);
|
39 | 31 | } else {
|
40 | 32 | for (const a of i.symbolAliases) {
|
41 |
| - scope[a.local ?? a.foreign.name] = importedScope[a.foreign.name]!; |
| 33 | + // Delayed function call supports circular dependencies |
| 34 | + scope[a.local ?? a.foreign.name] = importedScope[a.foreign.name] ?? (() => importedScope[a.foreign.name]!()); |
42 | 35 | }
|
43 | 36 | }
|
44 | 37 | };
|
45 | 38 |
|
46 |
| - stack.delete(file); |
47 |
| - |
48 |
| - cache.set(file, scope); |
49 | 39 | return scope;
|
50 | 40 | }
|
51 | 41 | }
|
|
0 commit comments