Skip to content
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

fix(ngcc): capture UMD/CommonJS inner class implementation nodes correctly #39346

Closed

Conversation

petebacondarwin
Copy link
Member

@petebacondarwin petebacondarwin commented Oct 20, 2020

Previously, UMD/CommonJS class inline declarations of the form:

exports.Foo = (function() { function Foo(); return Foo; })();

were capturing the whole IIFE as the implementation, rather than
the inner class (i.e. function Foo() {} in this case). This caused
the interpreter to break when it was trying to access such an export,
since it would try to evaluate the IIFE rather than treating it as a class
declaration.

@petebacondarwin petebacondarwin added action: review The PR is still awaiting reviews from at least one requested reviewer target: patch This PR is targeted for the next patch release comp: ngcc labels Oct 20, 2020
@ngbot ngbot bot modified the milestone: needsTriage Oct 20, 2020
@google-cla google-cla bot added the cla: yes label Oct 20, 2020
@pullapprove pullapprove bot requested a review from alxhub October 20, 2020 18:39
@petebacondarwin petebacondarwin changed the title fix(ngcc): capture UMD inner class implementation correctly fix(ngcc): capture UMD/CommonJS inner class implementation correctly Oct 20, 2020
@petebacondarwin petebacondarwin changed the title fix(ngcc): capture UMD/CommonJS inner class implementation correctly fix(ngcc): capture UMD/CommonJS inner class implementation nodes correctly Oct 20, 2020
Copy link
Member

@gkalpak gkalpak left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM with a couple of comments:

  • It would be cool if we could have an integration test showing all the bits working together (unless it would be too messy).
  • Commit message typo: Fool --> Foo 😁

@@ -342,7 +342,8 @@ export class StaticInterpreter {
}

private visitAmbiguousDeclaration(decl: Declaration, declContext: Context) {
return decl.kind === DeclarationKind.Inline && decl.implementation !== undefined ?
return decl.kind === DeclarationKind.Inline && decl.implementation !== undefined &&
!isDeclaration(decl.implementation) ?
// Inline declarations with an `implementation` should be visited as expressions
Copy link
Member

@gkalpak gkalpak Oct 21, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment could be updated to mention the new requirement for implementation to be a ts.Expression.

return SomeClass;
}())`,
'SomeClass',
`SomeClass = (function() {\n function SomeClass() {}\n return SomeClass;\n }())`,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
`SomeClass = (function() {\n function SomeClass() {}\n return SomeClass;\n }())`,
'SomeClass = (function() {\n function SomeClass() {}\n return SomeClass;\n }())',

@gkalpak gkalpak added the action: cleanup The PR is in need of cleanup, either due to needing a rebase or in response to comments from reviews label Oct 21, 2020
@petebacondarwin
Copy link
Member Author

Hmm, an integration test... Let me look into that. Trouble is that we don't have any UMD packages to test against.

@alxhub
Copy link
Member

alxhub commented Oct 21, 2020

Presubmit

@petebacondarwin petebacondarwin added action: presubmit The PR is in need of a google3 presubmit and removed action: cleanup The PR is in need of cleanup, either due to needing a rebase or in response to comments from reviews action: review The PR is still awaiting reviews from at least one requested reviewer labels Oct 21, 2020
@petebacondarwin
Copy link
Member Author

@gkalpak - I managed to create an integration test that actually fails without this fix!!

@JoostK JoostK added the action: cleanup The PR is in need of cleanup, either due to needing a rebase or in response to comments from reviews label Oct 21, 2020
…ctly

Previously, UMD/CommonJS class inline declarations of the form:

```ts
exports.Foo = (function() { function Foo(); return Foo; })();
```

were capturing the whole IIFE as the implementation, rather than
the inner class (i.e. `function Foo() {}` in this case). This caused
the interpreter to break when it was trying to access such an export,
since it would try to evaluate the IIFE rather than treating it as a class
declaration.
@petebacondarwin petebacondarwin removed the action: cleanup The PR is in need of cleanup, either due to needing a rebase or in response to comments from reviews label Oct 21, 2020
The compiler uses a `Reference` abstraction to refer to TS nodes
that it needs to refer to from other parts of the source. Such
references keep track of any identifiers that represent the referenced
node.

Prior to this commit, the compiler (and specifically `ReferenceEmitter`
classes) assumed that the reference identifiers are always free standing.
In other words a reference identifier would be an expression like
`FooDirective` in the expression `class FooDirective {}`.

But in UMD/CommonJS source, a reference can actually refer to an "exports"
declaration of the form `exports.FooDirective = ...`.
In such cases the `FooDirective` identifier is not free-standing
since it is part of a property access, so the `ReferenceEmitter`
should take this into account when emitting an expression that
refers to such a `Reference`.

This commit changes the `LocalIdentifierStrategy` reference emitter
so that if the `node` being referenced is not a declaration itself and
is in the current file, then it should be used directly, rather than
trying to use one of its identifiers.
@petebacondarwin petebacondarwin added the action: review The PR is still awaiting reviews from at least one requested reviewer label Oct 22, 2020
@petebacondarwin petebacondarwin removed the action: review The PR is still awaiting reviews from at least one requested reviewer label Oct 22, 2020
@AndrewKushnir
Copy link
Contributor

Presubmit.

@AndrewKushnir AndrewKushnir removed the action: presubmit The PR is in need of a google3 presubmit label Oct 23, 2020
@AndrewKushnir
Copy link
Contributor

FYI, presubmit is successful (I've updated g3 status for this PR).

@petebacondarwin petebacondarwin added the action: merge The PR is ready for merge by the caretaker label Oct 23, 2020
@petebacondarwin petebacondarwin removed the request for review from alxhub October 23, 2020 19:02
@petebacondarwin
Copy link
Member Author

Thanks @AndrewKushnir

alxhub pushed a commit that referenced this pull request Oct 23, 2020
…ctly (#39346)

Previously, UMD/CommonJS class inline declarations of the form:

```ts
exports.Foo = (function() { function Foo(); return Foo; })();
```

were capturing the whole IIFE as the implementation, rather than
the inner class (i.e. `function Foo() {}` in this case). This caused
the interpreter to break when it was trying to access such an export,
since it would try to evaluate the IIFE rather than treating it as a class
declaration.

PR Close #39346
alxhub pushed a commit that referenced this pull request Oct 23, 2020
The compiler uses a `Reference` abstraction to refer to TS nodes
that it needs to refer to from other parts of the source. Such
references keep track of any identifiers that represent the referenced
node.

Prior to this commit, the compiler (and specifically `ReferenceEmitter`
classes) assumed that the reference identifiers are always free standing.
In other words a reference identifier would be an expression like
`FooDirective` in the expression `class FooDirective {}`.

But in UMD/CommonJS source, a reference can actually refer to an "exports"
declaration of the form `exports.FooDirective = ...`.
In such cases the `FooDirective` identifier is not free-standing
since it is part of a property access, so the `ReferenceEmitter`
should take this into account when emitting an expression that
refers to such a `Reference`.

This commit changes the `LocalIdentifierStrategy` reference emitter
so that if the `node` being referenced is not a declaration itself and
is in the current file, then it should be used directly, rather than
trying to use one of its identifiers.

PR Close #39346
@alxhub alxhub closed this in 413b552 Oct 23, 2020
alxhub pushed a commit that referenced this pull request Oct 23, 2020
The compiler uses a `Reference` abstraction to refer to TS nodes
that it needs to refer to from other parts of the source. Such
references keep track of any identifiers that represent the referenced
node.

Prior to this commit, the compiler (and specifically `ReferenceEmitter`
classes) assumed that the reference identifiers are always free standing.
In other words a reference identifier would be an expression like
`FooDirective` in the expression `class FooDirective {}`.

But in UMD/CommonJS source, a reference can actually refer to an "exports"
declaration of the form `exports.FooDirective = ...`.
In such cases the `FooDirective` identifier is not free-standing
since it is part of a property access, so the `ReferenceEmitter`
should take this into account when emitting an expression that
refers to such a `Reference`.

This commit changes the `LocalIdentifierStrategy` reference emitter
so that if the `node` being referenced is not a declaration itself and
is in the current file, then it should be used directly, rather than
trying to use one of its identifiers.

PR Close #39346
alxhub pushed a commit that referenced this pull request Oct 23, 2020
…ctly (#39346)

Previously, UMD/CommonJS class inline declarations of the form:

```ts
exports.Foo = (function() { function Foo(); return Foo; })();
```

were capturing the whole IIFE as the implementation, rather than
the inner class (i.e. `function Foo() {}` in this case). This caused
the interpreter to break when it was trying to access such an export,
since it would try to evaluate the IIFE rather than treating it as a class
declaration.

PR Close #39346
alxhub pushed a commit that referenced this pull request Oct 23, 2020
The compiler uses a `Reference` abstraction to refer to TS nodes
that it needs to refer to from other parts of the source. Such
references keep track of any identifiers that represent the referenced
node.

Prior to this commit, the compiler (and specifically `ReferenceEmitter`
classes) assumed that the reference identifiers are always free standing.
In other words a reference identifier would be an expression like
`FooDirective` in the expression `class FooDirective {}`.

But in UMD/CommonJS source, a reference can actually refer to an "exports"
declaration of the form `exports.FooDirective = ...`.
In such cases the `FooDirective` identifier is not free-standing
since it is part of a property access, so the `ReferenceEmitter`
should take this into account when emitting an expression that
refers to such a `Reference`.

This commit changes the `LocalIdentifierStrategy` reference emitter
so that if the `node` being referenced is not a declaration itself and
is in the current file, then it should be used directly, rather than
trying to use one of its identifiers.

PR Close #39346
@petebacondarwin petebacondarwin deleted the ngcc-umd-inline-exports branch October 24, 2020 09:40
@angular-automatic-lock-bot
Copy link

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Nov 24, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
action: merge The PR is ready for merge by the caretaker cla: yes target: patch This PR is targeted for the next patch release
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants