-
Notifications
You must be signed in to change notification settings - Fork 12.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
initial revision of external module augmentations #6213
Conversation
@@ -109,6 +109,7 @@ namespace ts { | |||
let blockScopeContainer: Node; | |||
let lastContainer: Node; | |||
let seenThisKeyword: boolean; | |||
let isSourceFileExternalModule: boolean; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see this getting used anywhere apart from the later assignment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
right, forgot to remove that. Thanks
// error should already be reported so all errors in the body of augmentation can be ignored. | ||
const checkBody = isNameOfGlobalAugmentation(<LiteralExpression>node.name) || (getSymbolOfNode(node).flags & SymbolFlags.Merged); | ||
if (checkBody) { | ||
const globalAugmentation = isNameOfGlobalAugmentation(<LiteralExpression>node.name); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
isGlobalAugmentation or augmentsGlobal
What exactly is the recommended way to augment a default export? Is it possible in this implementation? |
it is not possible |
This also appears to take care of #2784. You might want to take note and give a heads up on that issue when this goes in. |
@@ -139,6 +141,14 @@ namespace ts { | |||
allSourcesModuleElementDeclarationEmitInfo = allSourcesModuleElementDeclarationEmitInfo.concat(moduleElementDeclarationEmitInfo); | |||
moduleElementDeclarationEmitInfo = []; | |||
} | |||
|
|||
if (!isBundledEmit && isExternalModule(sourceFile) && sourceFile.moduleAugmentations.length && !resultHasExternalModuleIndicator) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what about external modules with no exports or no module augmentation? soemthing like:
import {a} from "./mod";
// do something with a
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i thought we will do this for any external module, that we never emitted any import, export, or module augmentation for.
👍 |
} | ||
} | ||
} | ||
checkSourceElement(node.body); | ||
} | ||
|
||
function checkBodyOfModuleAugmentation(node: Node, isGlobalAugmentation: boolean): void { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be checkModuleAugmentationElement
. It checks and element in the body, not the body itself.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
✅
build failure is related to #6478 |
@ahejlsberg done, do you have any other comments? |
if (!reportError) { | ||
if (isGlobalAugmentation) { | ||
// global symbol should not have parent since it is not explicitly exported | ||
reportError = symbol.parent !== undefined; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The error message below seems a bit odd for this case, but maybe it's fine.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for global case we can easily lift this restriction since it is possible to add new entries to global scope from within a module. Currently the fact that we have it is only because of consistency in behavior for augmentations.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No sure I understand, maybe we're talking about different issues. This code is saying that you get an error when you have an exported member in a global augmentation block, right? I'm thinking it should never be valid to use export
in a global augmentation block.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the idea of this check is following: symbol.parent
will be undefined
if symbol was initially defined in the global scope. If symbol.parent
is not undefined
this means that this symbol was declared inside augmentation and will declare new entry in the global scope which is disallowed in current design
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If symbol.parent is not undefined this means that this symbol was declared inside augmentation
Why is that so? symbol.parent
is non-undefined when the symbol is exported, but it might still be declared inside the augmentation. I'm not getting this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
symbols whose initial declaration is in global scope are never exported and symbol.parent
for them is always undefined
. if symbol.parent !== undefined
this means that this symbol is exported from somewhere and as a consequence initially defined in augmentation not in global scope
In |
else { | ||
// this symbol contains only merged content from external modules and augmentations so it should always be exported (parent !== undefined) | ||
// and parent should have value side (valueDeclaration !== undefined) | ||
Debug.assert(symbol.parent !== undefined && symbol.parent.valueDeclaration !== undefined); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have a hard time reasoning about this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this assert is redundant. it basically says: augmentation can only change exported symbol (parent !== undefeind
) that really has a declaration (not a virtual symbol like prototype
) - this should always be the case. I'll remove it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So did you mean symbol.valueDeclaration !== undefined
? You currently have symbol.parent.valueDeclaration
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
symbol.parent.valueDeclaration
- is an augmentation: declare module ...
. symbol.valueDeclaration
is declaration inside the augmentation. Currently we report error if container that this symbol is module augmentation and not a normal external module
initial revision of external module augmentations
Awesome! Great stuff. Thank you! |
🎉 👏 👏 👏 👏 👏 👏 👏 |
👍 |
Module augmentation is a declaration of ambient module that directly nested either in external module or in top level ambient external module.
Name of module augmentation is resolved using the same set of rules as module specifiers in import \ export declarations.
If name is successfully resolved to some external module then declarations in module augmentation are merged with declarations inside module using standard rules for declaration merging.
Module augmentations cannot add new items to the top level scope but rather patch existing declarations.
for example
Here module
map
can declare that internally it will patchObservable
type and addmap
function to it.Fixes: #5269, #6022
Pending work:
"/"
but this is just a placeholder. The version that we ended up during the design meeting was:or