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
ngcc - use inner/outer class names as appropriate #33533
Conversation
All (the pull request submitter and all commit authors) CLAs are signed, but one or more commits were authored or co-authored by someone other than the pull request submitter. We need to confirm that all authors are ok with their commits being contributed to this project. Please have them confirm that by leaving a comment that contains only Note to project maintainer: There may be cases where the author cannot leave a comment, or the comment is not properly detected as consent. In those cases, you can manually confirm consent of the commit author(s), and set the ℹ️ Googlers: Go here for more info. |
079b5d8
to
22b8363
Compare
a9707ef
to
226aada
Compare
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.
👍
Inconsistent "quotation" marks in the first commit message's subject line:
refactor(ivy): split 'type' into 'type', 'internalType' and `adjacentType`
--> refactor(ivy): split `type` into `type`, `internalType` and `adjacentType`
@@ -86,6 +86,23 @@ export class Esm5ReflectionHost extends Esm2015ReflectionHost { | |||
return iife.parent.arguments[0]; | |||
} | |||
|
|||
getInternalNameOfClass(clazz: ClassDeclaration): ts.Identifier { |
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.
Could this method be called with a TS ClassDeclaration
(e.g. from a .d.ts
file)?
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 was debating this with myself. I left it as throwing and ran all the ngcc tests and it never threw.
The fact that this never returns null
means that we can't try calling the super
first. So we possibly could try calling it if the declaration is not in ES5 format.
I think the point is (at least as things stand right now) that ngtsc only ever calls this method when it is working on the source, not typings.
So at the moment I feel confident leaving it as it is.
…Type` When compiling an Angular decorator (e.g. Directive), @angular/compiler generates an 'expression' to be added as a static definition field on the class, a 'type' which will be added for that field to the .d.ts file, and a statement adjacent to the class that calls `setClassMetadata()`. Previously, the same WrappedNodeExpr of the class' ts.Identifier was used within each of this situations. In the ngtsc case, this is proper. In the ngcc case, if the class being compiled is within an ES5 IIFE, the outer name of the class may have changed. Thus, the class has both an inner and outer name. The outer name should continue to be used elsewhere in the compiler and in 'type'. The 'expression' will live within the IIFE, the `internalType` should be used. The adjacent statement will also live within the IIFE, the `adjacentType` should be used. This commit introduces `ReflectionHost.getInternalNameOfClass()` and `ReflectionHost.getAdjacentNameOfClass()`, which the compiler can use to query for the correct name to use.
…Class()` for ES5 In ES5 the class consists of an outer variable declaration that is initialised by an IIFE. Inside the IIFE the class is implemented by an inner function declaration that is returned from the IIFE. This inner declaration may have a different name to the outer declaration. This commit overrides `getInternalNameOfClass()` and `getAdjacentNameOfClass()` in `Esm5ReflectionHost` with methods that can find the correct inner declaration name identifier.
When decorating classes with ivy definitions (e.g. `ɵfac` or `ɵdir`) the inner name of the class declaration must be used. This is because in ES5 the definitions are inside the class's IIFE where the outer declaration has not yet been initialized.
226aada
to
64d5f04
Compare
Thanks @gkalpak |
A Googler has manually verified that the CLAs look good. (Googler, please make sure the reason for overriding the CLA status is clearly documented in these comments.) ℹ️ Googlers: Go here for more info. |
Presubmit |
…Class()` for ES5 (#33533) In ES5 the class consists of an outer variable declaration that is initialised by an IIFE. Inside the IIFE the class is implemented by an inner function declaration that is returned from the IIFE. This inner declaration may have a different name to the outer declaration. This commit overrides `getInternalNameOfClass()` and `getAdjacentNameOfClass()` in `Esm5ReflectionHost` with methods that can find the correct inner declaration name identifier. PR Close #33533
…Type` (#33533) When compiling an Angular decorator (e.g. Directive), @angular/compiler generates an 'expression' to be added as a static definition field on the class, a 'type' which will be added for that field to the .d.ts file, and a statement adjacent to the class that calls `setClassMetadata()`. Previously, the same WrappedNodeExpr of the class' ts.Identifier was used within each of this situations. In the ngtsc case, this is proper. In the ngcc case, if the class being compiled is within an ES5 IIFE, the outer name of the class may have changed. Thus, the class has both an inner and outer name. The outer name should continue to be used elsewhere in the compiler and in 'type'. The 'expression' will live within the IIFE, the `internalType` should be used. The adjacent statement will also live within the IIFE, the `adjacentType` should be used. This commit introduces `ReflectionHost.getInternalNameOfClass()` and `ReflectionHost.getAdjacentNameOfClass()`, which the compiler can use to query for the correct name to use. PR Close #33533
…Class()` for ES5 (#33533) In ES5 the class consists of an outer variable declaration that is initialised by an IIFE. Inside the IIFE the class is implemented by an inner function declaration that is returned from the IIFE. This inner declaration may have a different name to the outer declaration. This commit overrides `getInternalNameOfClass()` and `getAdjacentNameOfClass()` in `Esm5ReflectionHost` with methods that can find the correct inner declaration name identifier. PR Close #33533
…Type` (angular#33533) When compiling an Angular decorator (e.g. Directive), @angular/compiler generates an 'expression' to be added as a static definition field on the class, a 'type' which will be added for that field to the .d.ts file, and a statement adjacent to the class that calls `setClassMetadata()`. Previously, the same WrappedNodeExpr of the class' ts.Identifier was used within each of this situations. In the ngtsc case, this is proper. In the ngcc case, if the class being compiled is within an ES5 IIFE, the outer name of the class may have changed. Thus, the class has both an inner and outer name. The outer name should continue to be used elsewhere in the compiler and in 'type'. The 'expression' will live within the IIFE, the `internalType` should be used. The adjacent statement will also live within the IIFE, the `adjacentType` should be used. This commit introduces `ReflectionHost.getInternalNameOfClass()` and `ReflectionHost.getAdjacentNameOfClass()`, which the compiler can use to query for the correct name to use. PR Close angular#33533
…Class()` for ES5 (angular#33533) In ES5 the class consists of an outer variable declaration that is initialised by an IIFE. Inside the IIFE the class is implemented by an inner function declaration that is returned from the IIFE. This inner declaration may have a different name to the outer declaration. This commit overrides `getInternalNameOfClass()` and `getAdjacentNameOfClass()` in `Esm5ReflectionHost` with methods that can find the correct inner declaration name identifier. PR Close angular#33533
…ngular#33533) When decorating classes with ivy definitions (e.g. `ɵfac` or `ɵdir`) the inner name of the class declaration must be used. This is because in ES5 the definitions are inside the class's IIFE where the outer declaration has not yet been initialized. PR Close angular#33533
…Type` (angular#33533) When compiling an Angular decorator (e.g. Directive), @angular/compiler generates an 'expression' to be added as a static definition field on the class, a 'type' which will be added for that field to the .d.ts file, and a statement adjacent to the class that calls `setClassMetadata()`. Previously, the same WrappedNodeExpr of the class' ts.Identifier was used within each of this situations. In the ngtsc case, this is proper. In the ngcc case, if the class being compiled is within an ES5 IIFE, the outer name of the class may have changed. Thus, the class has both an inner and outer name. The outer name should continue to be used elsewhere in the compiler and in 'type'. The 'expression' will live within the IIFE, the `internalType` should be used. The adjacent statement will also live within the IIFE, the `adjacentType` should be used. This commit introduces `ReflectionHost.getInternalNameOfClass()` and `ReflectionHost.getAdjacentNameOfClass()`, which the compiler can use to query for the correct name to use. PR Close angular#33533
…Class()` for ES5 (angular#33533) In ES5 the class consists of an outer variable declaration that is initialised by an IIFE. Inside the IIFE the class is implemented by an inner function declaration that is returned from the IIFE. This inner declaration may have a different name to the outer declaration. This commit overrides `getInternalNameOfClass()` and `getAdjacentNameOfClass()` in `Esm5ReflectionHost` with methods that can find the correct inner declaration name identifier. PR Close angular#33533
…ngular#33533) When decorating classes with ivy definitions (e.g. `ɵfac` or `ɵdir`) the inner name of the class declaration must be used. This is because in ES5 the definitions are inside the class's IIFE where the outer declaration has not yet been initialized. PR Close angular#33533
This issue has been automatically locked due to inactivity. Read more about our automatic conversation locking policy. This action has been performed automatically by a bot. |
// FW-1651
In the
@ngx-formly/material
library, there are directives that inherit from other classes. In ES5 format this results in class declarations that have the following form:But then ngcc is adding definitions into the class as follows:
Note that the new definitions are referring to
Child
which is the outer class identifier.Unfortunately this
Child
identifier has not been initialised at the time the definitions are attached, so we get aReference
error.One approach was to move the definitions outside of the IIFE as follows:
This works for this case, but fails if the decorator definition contains references to identifiers that are only defined inside the IIFE. For example:
Here you can see that the
ɵɵdefineInjector()
call referencesBrowserModule_1
which is only defined within the IIFE.Also this is not correct because it stops the class from being tree shaken, since the IIFE is the unit of tree shaking.
So the proper solution is to teach ngcc/ngtsc which identifiers to use when generating ES5 definitions.