Skip to content

Commit 1a36fce

Browse files
committed
JavaScript LS scaffolding + JS module inference
1 parent 21e30e0 commit 1a36fce

31 files changed

+968
-235
lines changed

lib/lib.core.d.ts

+16
Original file line numberDiff line numberDiff line change
@@ -1198,6 +1198,22 @@ interface PromiseLike<T> {
11981198
then<TResult>(onfulfilled?: (value: T) => TResult | PromiseLike<TResult>, onrejected?: (reason: any) => void): PromiseLike<TResult>;
11991199
}
12001200

1201+
1202+
declare namespace CommonJS {
1203+
export var require: Require;
1204+
1205+
export var exports: any;
1206+
1207+
interface Exports { }
1208+
interface Module {
1209+
exports: Exports;
1210+
}
1211+
1212+
interface Require {
1213+
(moduleName: string): any;
1214+
}
1215+
}
1216+
12011217
interface ArrayLike<T> {
12021218
length: number;
12031219
[n: number]: T;

lib/lib.core.es6.d.ts

+16
Original file line numberDiff line numberDiff line change
@@ -1198,6 +1198,22 @@ interface PromiseLike<T> {
11981198
then<TResult>(onfulfilled?: (value: T) => TResult | PromiseLike<TResult>, onrejected?: (reason: any) => void): PromiseLike<TResult>;
11991199
}
12001200

1201+
1202+
declare namespace CommonJS {
1203+
export var require: Require;
1204+
1205+
export var exports: any;
1206+
1207+
interface Exports { }
1208+
interface Module {
1209+
exports: Exports;
1210+
}
1211+
1212+
interface Require {
1213+
(moduleName: string): any;
1214+
}
1215+
}
1216+
12011217
interface ArrayLike<T> {
12021218
length: number;
12031219
[n: number]: T;

lib/lib.d.ts

+16
Original file line numberDiff line numberDiff line change
@@ -1198,6 +1198,22 @@ interface PromiseLike<T> {
11981198
then<TResult>(onfulfilled?: (value: T) => TResult | PromiseLike<TResult>, onrejected?: (reason: any) => void): PromiseLike<TResult>;
11991199
}
12001200

1201+
1202+
declare namespace CommonJS {
1203+
export var require: Require;
1204+
1205+
export var exports: any;
1206+
1207+
interface Exports { }
1208+
interface Module {
1209+
exports: Exports;
1210+
}
1211+
1212+
interface Require {
1213+
(moduleName: string): any;
1214+
}
1215+
}
1216+
12011217
interface ArrayLike<T> {
12021218
length: number;
12031219
[n: number]: T;

lib/lib.es6.d.ts

+16
Original file line numberDiff line numberDiff line change
@@ -1198,6 +1198,22 @@ interface PromiseLike<T> {
11981198
then<TResult>(onfulfilled?: (value: T) => TResult | PromiseLike<TResult>, onrejected?: (reason: any) => void): PromiseLike<TResult>;
11991199
}
12001200

1201+
1202+
declare namespace CommonJS {
1203+
export var require: Require;
1204+
1205+
export var exports: any;
1206+
1207+
interface Exports { }
1208+
interface Module {
1209+
exports: Exports;
1210+
}
1211+
1212+
interface Require {
1213+
(moduleName: string): any;
1214+
}
1215+
}
1216+
12011217
interface ArrayLike<T> {
12021218
length: number;
12031219
[n: number]: T;

lib/tsc.js

+1
Original file line numberDiff line numberDiff line change
@@ -650,6 +650,7 @@ var ts;
650650
}
651651
ts.fileExtensionIs = fileExtensionIs;
652652
ts.supportedExtensions = [".ts", ".tsx", ".d.ts"];
653+
ts.supportedJsExtensions = ts.supportedExtensions.concat(".js", ".jsx");
653654
var extensionsToRemove = [".d.ts", ".ts", ".js", ".tsx", ".jsx"];
654655
function removeFileExtension(path) {
655656
for (var _i = 0; _i < extensionsToRemove.length; _i++) {

src/compiler/binder.ts

+61-4
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ namespace ts {
66

77
export const enum ModuleInstanceState {
88
NonInstantiated = 0,
9-
Instantiated = 1,
10-
ConstEnumOnly = 2
9+
Instantiated = 1,
10+
ConstEnumOnly = 2
1111
}
1212

1313
export function getModuleInstanceState(node: Node): ModuleInstanceState {
@@ -90,6 +90,8 @@ namespace ts {
9090
let lastContainer: Node;
9191
let seenThisKeyword: boolean;
9292

93+
let isJavaScriptFile = isSourceFileJavaScript(file);
94+
9395
// If this file is an external module, then it is automatically in strict-mode according to
9496
// ES6. If it is not an external module, then we'll determine if it is in strict mode or
9597
// not depending on if we see "use strict" in certain places (or if we hit a class/namespace).
@@ -167,6 +169,10 @@ namespace ts {
167169
case SyntaxKind.FunctionDeclaration:
168170
case SyntaxKind.ClassDeclaration:
169171
return node.flags & NodeFlags.Default ? "default" : undefined;
172+
173+
case SyntaxKind.BinaryExpression:
174+
Debug.assert(isModuleExportsAssignment(node));
175+
return "__jsExports";
170176
}
171177
}
172178

@@ -779,7 +785,7 @@ namespace ts {
779785
return "__" + indexOf((<SignatureDeclaration>node.parent).parameters, node);
780786
}
781787

782-
function bind(node: Node) {
788+
function bind(node: Node): void {
783789
node.parent = parent;
784790

785791
let savedInStrictMode = inStrictMode;
@@ -851,9 +857,18 @@ namespace ts {
851857

852858
function bindWorker(node: Node) {
853859
switch (node.kind) {
860+
/* Strict mode checks */
854861
case SyntaxKind.Identifier:
855862
return checkStrictModeIdentifier(<Identifier>node);
856863
case SyntaxKind.BinaryExpression:
864+
if (isJavaScriptFile) {
865+
if (isExportsPropertyAssignment(node)) {
866+
bindExportsPropertyAssignment(<BinaryExpression>node);
867+
}
868+
else if (isModuleExportsAssignment(node)) {
869+
bindModuleExportsAssignment(<BinaryExpression>node);
870+
}
871+
}
857872
return checkStrictModeBinaryExpression(<BinaryExpression>node);
858873
case SyntaxKind.CatchClause:
859874
return checkStrictModeCatchClause(<CatchClause>node);
@@ -919,6 +934,16 @@ namespace ts {
919934
checkStrictModeFunctionName(<FunctionExpression>node);
920935
let bindingName = (<FunctionExpression>node).name ? (<FunctionExpression>node).name.text : "__function";
921936
return bindAnonymousDeclaration(<FunctionExpression>node, SymbolFlags.Function, bindingName);
937+
938+
case SyntaxKind.CallExpression:
939+
// We're only inspecting call expressions to detect CommonJS modules, so we can skip
940+
// this check if we've already seen the module indicator
941+
if (isJavaScriptFile && !file.commonJsModuleIndicator) {
942+
bindCallExpression(<CallExpression>node);
943+
}
944+
break;
945+
946+
// Members of classes, interfaces, and modules
922947
case SyntaxKind.ClassExpression:
923948
case SyntaxKind.ClassDeclaration:
924949
return bindClassLikeDeclaration(<ClassLikeDeclaration>node);
@@ -930,6 +955,8 @@ namespace ts {
930955
return bindEnumDeclaration(<EnumDeclaration>node);
931956
case SyntaxKind.ModuleDeclaration:
932957
return bindModuleDeclaration(<ModuleDeclaration>node);
958+
959+
// Imports and exports
933960
case SyntaxKind.ImportEqualsDeclaration:
934961
case SyntaxKind.NamespaceImport:
935962
case SyntaxKind.ImportSpecifier:
@@ -949,10 +976,14 @@ namespace ts {
949976
function bindSourceFileIfExternalModule() {
950977
setExportContextFlag(file);
951978
if (isExternalModule(file)) {
952-
bindAnonymousDeclaration(file, SymbolFlags.ValueModule, `"${removeFileExtension(file.fileName)}"`);
979+
bindSourceFileAsExternalModule();
953980
}
954981
}
955982

983+
function bindSourceFileAsExternalModule() {
984+
bindAnonymousDeclaration(file, SymbolFlags.ValueModule, `"${removeFileExtension(file.fileName) }"`);
985+
}
986+
956987
function bindExportAssignment(node: ExportAssignment) {
957988
if (!container.symbol || !container.symbol.exports) {
958989
// Export assignment in some sort of block construct
@@ -985,6 +1016,32 @@ namespace ts {
9851016
}
9861017
}
9871018

1019+
function setCommonJsModuleIndicator(node: Node) {
1020+
if (!file.commonJsModuleIndicator) {
1021+
file.commonJsModuleIndicator = node;
1022+
bindSourceFileAsExternalModule();
1023+
}
1024+
}
1025+
1026+
function bindExportsPropertyAssignment(node: BinaryExpression) {
1027+
// When we create a property via 'exports.foo = bar', the 'exports.foo' property access
1028+
// expression is the declaration
1029+
setCommonJsModuleIndicator(node);
1030+
declareSymbol(file.symbol.exports, file.symbol, <PropertyAccessExpression>node.left, SymbolFlags.Property | SymbolFlags.Export, SymbolFlags.None);
1031+
}
1032+
1033+
function bindModuleExportsAssignment(node: BinaryExpression) {
1034+
// 'module.exports = expr' assignment
1035+
setCommonJsModuleIndicator(node);
1036+
declareSymbol(file.symbol.exports, file.symbol, node, SymbolFlags.None, SymbolFlags.None);
1037+
}
1038+
1039+
function bindCallExpression(node: CallExpression) {
1040+
if (isRequireCall(node)) {
1041+
setCommonJsModuleIndicator(node);
1042+
}
1043+
}
1044+
9881045
function bindClassLikeDeclaration(node: ClassLikeDeclaration) {
9891046
if (node.kind === SyntaxKind.ClassDeclaration) {
9901047
bindBlockScopedDeclaration(node, SymbolFlags.Class, SymbolFlags.ClassExcludes);

0 commit comments

Comments
 (0)