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 CommonJs modules #7249

Merged
merged 5 commits into from
Mar 10, 2016
Merged

Fix CommonJs modules #7249

merged 5 commits into from
Mar 10, 2016

Conversation

billti
Copy link
Member

@billti billti commented Feb 26, 2016

This fix allows ES2015 module syntax (namespace imports and import lists) to work with:

a) JavaScript modules using the "module.exports = " pattern
b) TypeScript modules using the "export = " pattern

Ping @RyanCavanaugh and @mhegazy

@@ -278,9 +278,11 @@ namespace ts {
function declareSymbol(symbolTable: SymbolTable, parent: Symbol, node: Declaration, includes: SymbolFlags, excludes: SymbolFlags): Symbol {
Debug.assert(!hasDynamicName(node));

const isJsModuleExport = node.kind === SyntaxKind.BinaryExpression ? getSpecialPropertyAssignmentKind(node) === SpecialPropertyAssignmentKind.ModuleExports : false;
Copy link
Member

Choose a reason for hiding this comment

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

Shouldn't this be conditional on being in a JS file?

Copy link
Member

Choose a reason for hiding this comment

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

Also, just

node.kind === SyntaxKind.BinaryExpression && getSpecialPropertyAssignmentKind(node) === SpecialPropertyAssignmentKind.ModuleExports

Copy link
Member

Choose a reason for hiding this comment

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

No need to check node.kind === SyntaxKind.BinaryExpression; getSpecialPropertyAssignmentKind already does this (and returns .None)

Copy link
Member Author

Choose a reason for hiding this comment

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

I added the JS file check to getSpecialPropertyAssignmentKind, as these only apply to JS files.

@RyanCavanaugh
Copy link
Member

Looks OK overall. We should have a few compiler baselines for this scenario so we can get symbol baselines (since these are the easiest way to detect regressions in these sorts of features).

@billti
Copy link
Member Author

billti commented Feb 29, 2016

Addressed comments, and also fixed #7287 (as well as #7248, and original bug #7076).

@billti
Copy link
Member Author

billti commented Feb 29, 2016

Note: Just confirmed this fixes the issue raised in #7000 also.:

You can import React as a namespace using the default CommonJS module type:

reactcommonjs

Or if using "system", the synthetic default also works:

reactsystem

@RyanCavanaugh
Copy link
Member

👍

@billti
Copy link
Member Author

billti commented Mar 3, 2016

Ping @mhegazy and @vladima to see if they have any concerns - else I'd like to get this merged in.

@@ -1428,7 +1430,7 @@ namespace ts {
function bindModuleExportsAssignment(node: BinaryExpression) {
// 'module.exports = expr' assignment
setCommonJsModuleIndicator(node);
bindExportAssignment(node);
declareSymbol(file.symbol.exports, file.symbol, node, SymbolFlags.Property | SymbolFlags.Export | SymbolFlags.ValueModule, SymbolFlags.None);
Copy link
Member

Choose a reason for hiding this comment

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

Is there a reason you're setting with SymbolFlags.Property?

Copy link
Member Author

Choose a reason for hiding this comment

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

In part because 'module.exports' is a property, but mostly because there was some code path that was crapping out without an expected flag set, of which property seemed appropriate (the exact code path escapes me, as I wrote this over a week ago, and there were a lot of code paths).

Happy to be corrected on my usage of the mystic arts of SymbolFlags however.

Copy link
Contributor

Choose a reason for hiding this comment

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

shouldn't this be just SymbolFlags.Alias?

Copy link
Member Author

Choose a reason for hiding this comment

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

I went down that road and it was a can of worms. I can't remember all the issues I hit, many related to resolveAlias, but one of them was the getTargetOfAlias function has a set of explicit SyntaxKinds it expects. It also expects to be able to resolve a target declaration, whereas this is a binaryExpression setting a property from an expression (e.g. it could be module.exports = someCall() - as I have a test-case for).

Copy link
Contributor

Choose a reason for hiding this comment

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

i see now that would not work. but we should do it if the right hand side is an identified. this allows us to get a class from JS for instance in TS, and we have this mostly working today, you will just need to add one additional clause in getTargetOfAliasDeclaration.

if it is not, i would give this Property | ValueModule seems reasonable. not sure i see why we need the Export one though.

billti added a commit that referenced this pull request Mar 10, 2016
@billti billti merged commit 50059b6 into release-1.8 Mar 10, 2016
@billti billti deleted the FixCommonJSModules branch March 10, 2016 03:23
billti added a commit that referenced this pull request Mar 10, 2016
@ozguruksal
Copy link

I wish the "export = " pattern was deprecated. If TS is a superset of JS, then I wonder what benefit "export=" pattern offers to JS? After CommonJS, and AMD tried to fill the gap, now we have es2015 modules. We don't need "export=" pattern.

@nevir
Copy link

nevir commented Mar 28, 2016

export = allows you to keep backwards compatibility with CommonJS (e.g. anyone on Node, until it implements support for ES2015 modules).

For example, a module that exports a single function - that you want to be made available via require('my-module') instead of require('my-module').default

@unional
Copy link
Contributor

unional commented Apr 15, 2016

Cross-referencing:
#7398

Using this interop in the package could break at consumer level.

@microsoft microsoft locked and limited conversation to collaborators Jun 19, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants