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

Full support for CommonJS auto-imports in JS #37027

Merged
merged 8 commits into from
Feb 28, 2020

Conversation

andrewbranch
Copy link
Member

In #32684, I added the ability for auto-imports to write a require variable declaration in JS files. However, it didn’t work for named or default exports, and under default project settings, would never be triggered from completions; it was only reachable by code fix. This is particularly problematic for JS, because unless the user has explicitly enabled type checking JS through VS Code settings, a tsconfig or jsconfig file, or // @ts-check, you can’t get code fixes because you don’t get errors.

This PR removes those limitations, and also recognizes members of object literals assigned to module.exports as importable symbols.

How do we choose between import and require for a JS file?

Rules are evaluated in order (highest priority first).

  1. If the imported identifier could be added to an existing import, add it there.
  2. If the imported identifier could be added to an existing require, add it there.
  3. If the importing file contains any ES2015+ import/export syntax, use import.
  4. If the importing file contains any CommonJS syntax, use require.
  5. If the compiler options indicate a module target of ES2015+, use import.
  6. Use require.

How are require variable declarations written for different kinds of exports?

  • const { foo } = require('./foo') maps to named ES exports and CommonJS exported object literal members (module.exports = { foo }).
  • const { default: foo } = require('./foo') maps to default ES exports (hopefully people aren’t actually doing this).
  • const foo = require('./foo') maps to everything else.

Fixes #20292
Fixes #30549

Related:

src/compiler/checker.ts Outdated Show resolved Hide resolved
Comment on lines -173 to +177
Equals,
ConstEquals
CommonJS,
Copy link
Member Author

@andrewbranch andrewbranch Feb 25, 2020

Choose a reason for hiding this comment

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

This is the fundamental conceptual change in this file, and everything else is basically just implementation details. This enum used to represent final syntax; now it’s more a representation of where the symbol can be found in the module. Whether or not to use JS is then calculated and stored elsewhere, so that

  • CommonJS can mean import foo = require('mod') or const foo = require('mod')
  • Namespace can mean import * as foo from 'mod' or const foo = require('mod')
  • Default can mean import foo from 'mod' or const { default: foo } = require('mod')
  • Named can mean import { foo } from 'mod' or const { foo } = require('mod')
Copy link
Member

@sandersn sandersn left a comment

Choose a reason for hiding this comment

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

Looks pretty good to me, although I wasn't previously familiar with the importFixes code.

src/compiler/types.ts Outdated Show resolved Hide resolved
src/compiler/types.ts Outdated Show resolved Hide resolved
src/services/codefixes/importFixes.ts Show resolved Hide resolved
Fix typos

Co-Authored-By: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
4 participants