Skip to content

Commit f9945f5

Browse files
Full support for CommonJS auto-imports in JS (#37027)
* Support add new requires * Always use destructuring for requiring default exports * Add more tests * Update existing fourslash tests * Use `getExportsAndPropertiesOfModule` * Add UMD test * Apply suggestions from code review Fix typos Co-Authored-By: Nathan Shively-Sanders <[email protected]> Co-authored-by: Nathan Shively-Sanders <[email protected]>
1 parent 6a1e474 commit f9945f5

22 files changed

+561
-122
lines changed

src/compiler/checker.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -609,6 +609,9 @@ namespace ts {
609609
getJsxNamespace: n => unescapeLeadingUnderscores(getJsxNamespace(n)),
610610
getAccessibleSymbolChain,
611611
getTypePredicateOfSignature,
612+
resolveExternalModuleName: moduleSpecifier => {
613+
return resolveExternalModuleName(moduleSpecifier, moduleSpecifier, /*ignoreErrors*/ true);
614+
},
612615
resolveExternalModuleSymbol,
613616
tryGetThisTypeAt: (node, includeGlobalThis) => {
614617
node = getParseTreeNode(node);
@@ -2576,7 +2579,7 @@ namespace ts {
25762579
}
25772580

25782581
function getTargetOfExportAssignment(node: ExportAssignment | BinaryExpression, dontResolveAlias: boolean): Symbol | undefined {
2579-
const expression = (isExportAssignment(node) ? node.expression : node.right) as EntityNameExpression | ClassExpression;
2582+
const expression = isExportAssignment(node) ? node.expression : node.right;
25802583
const resolved = getTargetOfAliasLikeExpression(expression, dontResolveAlias);
25812584
markSymbolOfAliasDeclarationIfTypeOnly(node, /*immediateTarget*/ undefined, resolved, /*overwriteEmpty*/ false);
25822585
return resolved;

src/compiler/types.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3596,6 +3596,7 @@ namespace ts {
35963596
*/
35973597
/* @internal */ getAccessibleSymbolChain(symbol: Symbol, enclosingDeclaration: Node | undefined, meaning: SymbolFlags, useOnlyExternalAliasing: boolean): Symbol[] | undefined;
35983598
/* @internal */ getTypePredicateOfSignature(signature: Signature): TypePredicate | undefined;
3599+
/* @internal */ resolveExternalModuleName(moduleSpecifier: Expression): Symbol | undefined;
35993600
/**
36003601
* An external module with an 'export =' declaration resolves to the target of the 'export =' declaration,
36013602
* and an external module with no 'export =' declaration resolves to the module itself.
@@ -3830,6 +3831,10 @@ namespace ts {
38303831
/* @internal */
38313832
export type AnyImportSyntax = ImportDeclaration | ImportEqualsDeclaration;
38323833

3834+
/* @internal */
3835+
export type AnyImportOrRequire = AnyImportSyntax | RequireVariableDeclaration;
3836+
3837+
38333838
/* @internal */
38343839
export type AnyImportOrReExport = AnyImportSyntax | ExportDeclaration;
38353840

@@ -3846,7 +3851,13 @@ namespace ts {
38463851
| ValidImportTypeNode;
38473852

38483853
/* @internal */
3849-
export type RequireOrImportCall = CallExpression & { arguments: [StringLiteralLike] };
3854+
export type RequireOrImportCall = CallExpression & { expression: Identifier, arguments: [StringLiteralLike] };
3855+
3856+
/* @internal */
3857+
export interface RequireVariableDeclaration extends VariableDeclaration {
3858+
3859+
initializer: RequireOrImportCall;
3860+
}
38503861

38513862
/* @internal */
38523863
export type LateVisibilityPaintedStatement =

src/compiler/utilities.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1856,6 +1856,20 @@ namespace ts {
18561856
return !requireStringLiteralLikeArgument || isStringLiteralLike(arg);
18571857
}
18581858

1859+
/**
1860+
* Returns true if the node is a VariableDeclaration initialized to a require call (see `isRequireCall`).
1861+
* This function does not test if the node is in a JavaScript file or not.
1862+
*/
1863+
export function isRequireVariableDeclaration(node: Node, requireStringLiteralLikeArgument: true): node is RequireVariableDeclaration;
1864+
export function isRequireVariableDeclaration(node: Node, requireStringLiteralLikeArgument: boolean): node is VariableDeclaration;
1865+
export function isRequireVariableDeclaration(node: Node, requireStringLiteralLikeArgument: boolean): node is VariableDeclaration {
1866+
return isVariableDeclaration(node) && !!node.initializer && isRequireCall(node.initializer, requireStringLiteralLikeArgument);
1867+
}
1868+
1869+
export function isRequireVariableDeclarationStatement(node: Node, requireStringLiteralLikeArgument = true): node is VariableStatement {
1870+
return isVariableStatement(node) && every(node.declarationList.declarations, decl => isRequireVariableDeclaration(decl, requireStringLiteralLikeArgument));
1871+
}
1872+
18591873
export function isSingleOrDoubleQuote(charCode: number) {
18601874
return charCode === CharacterCodes.singleQuote || charCode === CharacterCodes.doubleQuote;
18611875
}

src/harness/fourslashImpl.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2717,7 +2717,7 @@ namespace FourSlash {
27172717
const oldText = this.tryGetFileContent(change.fileName);
27182718
ts.Debug.assert(!!change.isNewFile === (oldText === undefined));
27192719
const newContent = change.isNewFile ? ts.first(change.textChanges).newText : ts.textChanges.applyChanges(oldText!, change.textChanges);
2720-
assert.equal(newContent, expectedNewContent, `String mis-matched in file ${change.fileName}`);
2720+
this.verifyTextMatches(newContent, /*includeWhitespace*/ true, expectedNewContent);
27212721
}
27222722
for (const newFileName in newFileContent) {
27232723
ts.Debug.assert(changes.some(c => c.fileName === newFileName), "No change in file", () => newFileName);

0 commit comments

Comments
 (0)