@@ -2463,17 +2463,26 @@ namespace ts {
2463
2463
* Attempts to find the symbol corresponding to the container a symbol is in - usually this
2464
2464
* is just its' `.parent`, but for locals, this value is `undefined`
2465
2465
*/
2466
- function getContainerOfSymbol (symbol: Symbol): Symbol | undefined {
2466
+ function getContainersOfSymbol (symbol: Symbol, enclosingDeclaration: Node | undefined ): Symbol[] | undefined {
2467
2467
const container = getParentOfSymbol(symbol);
2468
2468
if (container) {
2469
- return container;
2469
+ const additionalContainers = mapDefined(container.declarations, fileSymbolIfFileSymbolExportEqualsContainer);
2470
+ if (enclosingDeclaration && getAccessibleSymbolChain(container, enclosingDeclaration, SymbolFlags.Namespace, /*externalOnly*/ false)) {
2471
+ return concatenate([container], additionalContainers); // This order expresses a preference for the real container if it is in scope
2472
+ }
2473
+ return append(additionalContainers, container);
2470
2474
}
2471
- const candidate = forEach (symbol.declarations, d => !isAmbientModule(d) && d.parent && hasNonGlobalAugmentationExternalModuleSymbol(d.parent) ? getSymbolOfNode(d.parent) : undefined);
2472
- if (!candidate ) {
2475
+ const candidates = mapDefined (symbol.declarations, d => !isAmbientModule(d) && d.parent && hasNonGlobalAugmentationExternalModuleSymbol(d.parent) ? getSymbolOfNode(d.parent) : undefined);
2476
+ if (!length(candidates) ) {
2473
2477
return undefined;
2474
2478
}
2475
- const alias = getAliasForSymbolInContainer(candidate, symbol);
2476
- return alias ? candidate : undefined;
2479
+ return mapDefined(candidates, candidate => getAliasForSymbolInContainer(candidate, symbol) ? candidate : undefined);
2480
+
2481
+ function fileSymbolIfFileSymbolExportEqualsContainer(d: Declaration) {
2482
+ const fileSymbol = getExternalModuleContainer(d);
2483
+ const exported = fileSymbol && fileSymbol.exports && fileSymbol.exports.get(InternalSymbolName.ExportEquals);
2484
+ return resolveSymbol(exported) === resolveSymbol(container) ? fileSymbol : undefined;
2485
+ }
2477
2486
}
2478
2487
2479
2488
function getAliasForSymbolInContainer(container: Symbol, symbol: Symbol) {
@@ -2759,6 +2768,56 @@ namespace ts {
2759
2768
return access.accessibility === SymbolAccessibility.Accessible;
2760
2769
}
2761
2770
2771
+ function isAnySymbolAccessible(symbols: Symbol[] | undefined, enclosingDeclaration: Node, initialSymbol: Symbol, meaning: SymbolFlags, shouldComputeAliasesToMakeVisible: boolean): SymbolAccessibilityResult | undefined {
2772
+ if (!length(symbols)) return;
2773
+
2774
+ let hadAccessibleChain: Symbol | undefined;
2775
+ for (const symbol of symbols!) {
2776
+ // Symbol is accessible if it by itself is accessible
2777
+ const accessibleSymbolChain = getAccessibleSymbolChain(symbol, enclosingDeclaration, meaning, /*useOnlyExternalAliasing*/ false);
2778
+ if (accessibleSymbolChain) {
2779
+ hadAccessibleChain = symbol;
2780
+ const hasAccessibleDeclarations = hasVisibleDeclarations(accessibleSymbolChain[0], shouldComputeAliasesToMakeVisible);
2781
+ if (hasAccessibleDeclarations) {
2782
+ return hasAccessibleDeclarations;
2783
+ }
2784
+ }
2785
+ else {
2786
+ if (some(symbol.declarations, hasNonGlobalAugmentationExternalModuleSymbol)) {
2787
+ // Any meaning of a module symbol is always accessible via an `import` type
2788
+ return {
2789
+ accessibility: SymbolAccessibility.Accessible
2790
+ };
2791
+ }
2792
+ }
2793
+
2794
+ // If we haven't got the accessible symbol, it doesn't mean the symbol is actually inaccessible.
2795
+ // It could be a qualified symbol and hence verify the path
2796
+ // e.g.:
2797
+ // module m {
2798
+ // export class c {
2799
+ // }
2800
+ // }
2801
+ // const x: typeof m.c
2802
+ // In the above example when we start with checking if typeof m.c symbol is accessible,
2803
+ // we are going to see if c can be accessed in scope directly.
2804
+ // But it can't, hence the accessible is going to be undefined, but that doesn't mean m.c is inaccessible
2805
+ // It is accessible if the parent m is accessible because then m.c can be accessed through qualification
2806
+ const parentResult = isAnySymbolAccessible(getContainersOfSymbol(symbol, enclosingDeclaration), enclosingDeclaration, initialSymbol, initialSymbol === symbol ? getQualifiedLeftMeaning(meaning) : meaning, shouldComputeAliasesToMakeVisible);
2807
+ if (parentResult) {
2808
+ return parentResult;
2809
+ }
2810
+ }
2811
+
2812
+ if (hadAccessibleChain) {
2813
+ return {
2814
+ accessibility: SymbolAccessibility.NotAccessible,
2815
+ errorSymbolName: symbolToString(initialSymbol, enclosingDeclaration, meaning),
2816
+ errorModuleName: hadAccessibleChain !== initialSymbol ? symbolToString(hadAccessibleChain, enclosingDeclaration, SymbolFlags.Namespace) : undefined,
2817
+ };
2818
+ }
2819
+ }
2820
+
2762
2821
/**
2763
2822
* Check if the given symbol in given enclosing declaration is accessible and mark all associated alias to be visible if requested
2764
2823
*
@@ -2769,57 +2828,21 @@ namespace ts {
2769
2828
*/
2770
2829
function isSymbolAccessible(symbol: Symbol | undefined, enclosingDeclaration: Node | undefined, meaning: SymbolFlags, shouldComputeAliasesToMakeVisible: boolean): SymbolAccessibilityResult {
2771
2830
if (symbol && enclosingDeclaration) {
2772
- const initialSymbol = symbol;
2773
- let meaningToLook = meaning;
2774
- while (symbol) {
2775
- // Symbol is accessible if it by itself is accessible
2776
- const accessibleSymbolChain = getAccessibleSymbolChain(symbol, enclosingDeclaration, meaningToLook, /*useOnlyExternalAliasing*/ false);
2777
- if (accessibleSymbolChain) {
2778
- const hasAccessibleDeclarations = hasVisibleDeclarations(accessibleSymbolChain[0], shouldComputeAliasesToMakeVisible);
2779
- if (!hasAccessibleDeclarations) {
2780
- return {
2781
- accessibility: SymbolAccessibility.NotAccessible,
2782
- errorSymbolName: symbolToString(initialSymbol, enclosingDeclaration, meaning),
2783
- errorModuleName: symbol !== initialSymbol ? symbolToString(symbol, enclosingDeclaration, SymbolFlags.Namespace) : undefined,
2784
- };
2785
- }
2786
- return hasAccessibleDeclarations;
2787
- }
2788
- else {
2789
- if (some(symbol.declarations, hasNonGlobalAugmentationExternalModuleSymbol)) {
2790
- // Any meaning of a module symbol is always accessible via an `import` type
2791
- return {
2792
- accessibility: SymbolAccessibility.Accessible
2793
- };
2794
- }
2795
- }
2796
-
2797
- // If we haven't got the accessible symbol, it doesn't mean the symbol is actually inaccessible.
2798
- // It could be a qualified symbol and hence verify the path
2799
- // e.g.:
2800
- // module m {
2801
- // export class c {
2802
- // }
2803
- // }
2804
- // const x: typeof m.c
2805
- // In the above example when we start with checking if typeof m.c symbol is accessible,
2806
- // we are going to see if c can be accessed in scope directly.
2807
- // But it can't, hence the accessible is going to be undefined, but that doesn't mean m.c is inaccessible
2808
- // It is accessible if the parent m is accessible because then m.c can be accessed through qualification
2809
- meaningToLook = getQualifiedLeftMeaning(meaning);
2810
- symbol = getContainerOfSymbol(symbol);
2831
+ const result = isAnySymbolAccessible([symbol], enclosingDeclaration, symbol, meaning, shouldComputeAliasesToMakeVisible);
2832
+ if (result) {
2833
+ return result;
2811
2834
}
2812
2835
2813
2836
// This could be a symbol that is not exported in the external module
2814
2837
// or it could be a symbol from different external module that is not aliased and hence cannot be named
2815
- const symbolExternalModule = forEach(initialSymbol .declarations, getExternalModuleContainer);
2838
+ const symbolExternalModule = forEach(symbol .declarations, getExternalModuleContainer);
2816
2839
if (symbolExternalModule) {
2817
2840
const enclosingExternalModule = getExternalModuleContainer(enclosingDeclaration);
2818
2841
if (symbolExternalModule !== enclosingExternalModule) {
2819
2842
// name from different external module that is not visible
2820
2843
return {
2821
2844
accessibility: SymbolAccessibility.CannotBeNamed,
2822
- errorSymbolName: symbolToString(initialSymbol , enclosingDeclaration, meaning),
2845
+ errorSymbolName: symbolToString(symbol , enclosingDeclaration, meaning),
2823
2846
errorModuleName: symbolToString(symbolExternalModule)
2824
2847
};
2825
2848
}
@@ -2828,16 +2851,16 @@ namespace ts {
2828
2851
// Just a local name that is not accessible
2829
2852
return {
2830
2853
accessibility: SymbolAccessibility.NotAccessible,
2831
- errorSymbolName: symbolToString(initialSymbol , enclosingDeclaration, meaning),
2854
+ errorSymbolName: symbolToString(symbol , enclosingDeclaration, meaning),
2832
2855
};
2833
2856
}
2834
2857
2835
2858
return { accessibility: SymbolAccessibility.Accessible };
2859
+ }
2836
2860
2837
- function getExternalModuleContainer(declaration: Node) {
2838
- const node = findAncestor(declaration, hasExternalModuleSymbol);
2839
- return node && getSymbolOfNode(node);
2840
- }
2861
+ function getExternalModuleContainer(declaration: Node) {
2862
+ const node = findAncestor(declaration, hasExternalModuleSymbol);
2863
+ return node && getSymbolOfNode(node);
2841
2864
}
2842
2865
2843
2866
function hasExternalModuleSymbol(declaration: Node) {
@@ -3667,18 +3690,19 @@ namespace ts {
3667
3690
/** @param endOfChain Set to false for recursive calls; non-recursive calls should always output something. */
3668
3691
function getSymbolChain(symbol: Symbol, meaning: SymbolFlags, endOfChain: boolean): Symbol[] | undefined {
3669
3692
let accessibleSymbolChain = getAccessibleSymbolChain(symbol, context.enclosingDeclaration, meaning, !!(context.flags & NodeBuilderFlags.UseOnlyExternalAliasing));
3670
- let parentSymbol: Symbol | undefined;
3671
3693
3672
3694
if (!accessibleSymbolChain ||
3673
3695
needsQualification(accessibleSymbolChain[0], context.enclosingDeclaration, accessibleSymbolChain.length === 1 ? meaning : getQualifiedLeftMeaning(meaning))) {
3674
3696
3675
3697
// Go up and add our parent.
3676
- const parent = getContainerOfSymbol(accessibleSymbolChain ? accessibleSymbolChain[0] : symbol);
3677
- if (parent) {
3678
- const parentChain = getSymbolChain(parent, getQualifiedLeftMeaning(meaning), /*endOfChain*/ false);
3679
- if (parentChain) {
3680
- parentSymbol = parent;
3681
- accessibleSymbolChain = parentChain.concat(accessibleSymbolChain || [getAliasForSymbolInContainer(parent, symbol) || symbol]);
3698
+ const parents = getContainersOfSymbol(accessibleSymbolChain ? accessibleSymbolChain[0] : symbol, context.enclosingDeclaration);
3699
+ if (length(parents)) {
3700
+ for (const parent of parents!) {
3701
+ const parentChain = getSymbolChain(parent, getQualifiedLeftMeaning(meaning), /*endOfChain*/ false);
3702
+ if (parentChain) {
3703
+ accessibleSymbolChain = parentChain.concat(accessibleSymbolChain || [getAliasForSymbolInContainer(parent, symbol) || symbol]);
3704
+ break;
3705
+ }
3682
3706
}
3683
3707
}
3684
3708
}
@@ -3689,11 +3713,12 @@ namespace ts {
3689
3713
if (
3690
3714
// If this is the last part of outputting the symbol, always output. The cases apply only to parent symbols.
3691
3715
endOfChain ||
3692
- // If a parent symbol is an external module, don't write it. (We prefer just `x` vs `"foo/bar".x`.)
3693
- (yieldModuleSymbol || !(!parentSymbol && forEach(symbol.declarations, hasNonGlobalAugmentationExternalModuleSymbol))) &&
3694
3716
// If a parent symbol is an anonymous type, don't write it.
3695
3717
!(symbol.flags & (SymbolFlags.TypeLiteral | SymbolFlags.ObjectLiteral))) {
3696
-
3718
+ // If a parent symbol is an external module, don't write it. (We prefer just `x` vs `"foo/bar".x`.)
3719
+ if (!endOfChain && !yieldModuleSymbol && !!forEach(symbol.declarations, hasNonGlobalAugmentationExternalModuleSymbol)) {
3720
+ return;
3721
+ }
3697
3722
return [symbol];
3698
3723
}
3699
3724
}
0 commit comments