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

JavaScript LS scaffolding + JS module inference #5266

Merged
merged 14 commits into from
Nov 10, 2015
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/lib.core.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1225,7 +1225,7 @@ interface ArrayBuffer {
interface ArrayBufferConstructor {
prototype: ArrayBuffer;
new (byteLength: number): ArrayBuffer;
isView(arg: any): boolean;
isView(arg: any): arg is ArrayBufferView;
Copy link
Member

Choose a reason for hiding this comment

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

Very distracting to have all these unrelated changes.

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 can roll back the LKG update portion of this if it's truly problematic.

}
declare var ArrayBuffer: ArrayBufferConstructor;

Expand Down
2 changes: 1 addition & 1 deletion lib/lib.core.es6.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1225,7 +1225,7 @@ interface ArrayBuffer {
interface ArrayBufferConstructor {
prototype: ArrayBuffer;
new (byteLength: number): ArrayBuffer;
isView(arg: any): boolean;
isView(arg: any): arg is ArrayBufferView;
}
declare var ArrayBuffer: ArrayBufferConstructor;

Expand Down
2 changes: 1 addition & 1 deletion lib/lib.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1225,7 +1225,7 @@ interface ArrayBuffer {
interface ArrayBufferConstructor {
prototype: ArrayBuffer;
new (byteLength: number): ArrayBuffer;
isView(arg: any): boolean;
isView(arg: any): arg is ArrayBufferView;
}
declare var ArrayBuffer: ArrayBufferConstructor;

Expand Down
2 changes: 1 addition & 1 deletion lib/lib.es6.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1225,7 +1225,7 @@ interface ArrayBuffer {
interface ArrayBufferConstructor {
prototype: ArrayBuffer;
new (byteLength: number): ArrayBuffer;
isView(arg: any): boolean;
isView(arg: any): arg is ArrayBufferView;
}
declare var ArrayBuffer: ArrayBufferConstructor;

Expand Down
337 changes: 228 additions & 109 deletions lib/tsc.js

Large diffs are not rendered by default.

643 changes: 411 additions & 232 deletions lib/tsserver.js

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions lib/typescript.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -574,7 +574,7 @@ declare namespace ts {
asteriskToken?: Node;
expression?: Expression;
}
interface BinaryExpression extends Expression {
interface BinaryExpression extends Expression, Declaration {
left: Expression;
operatorToken: Node;
right: Expression;
Expand Down Expand Up @@ -618,7 +618,7 @@ declare namespace ts {
interface ObjectLiteralExpression extends PrimaryExpression, Declaration {
properties: NodeArray<ObjectLiteralElement>;
}
interface PropertyAccessExpression extends MemberExpression {
interface PropertyAccessExpression extends MemberExpression, Declaration {
expression: LeftHandSideExpression;
dotToken: Node;
name: Identifier;
Expand Down Expand Up @@ -2153,7 +2153,7 @@ declare namespace ts {
function updateLanguageServiceSourceFile(sourceFile: SourceFile, scriptSnapshot: IScriptSnapshot, version: string, textChangeRange: TextChangeRange, aggressiveChecks?: boolean): SourceFile;
function createGetCanonicalFileName(useCaseSensitivefileNames: boolean): (fileName: string) => string;
function createDocumentRegistry(useCaseSensitiveFileNames?: boolean): DocumentRegistry;
function preProcessFile(sourceText: string, readImportFiles?: boolean): PreProcessedFileInfo;
function preProcessFile(sourceText: string, readImportFiles?: boolean, detectJavaScriptImports?: boolean): PreProcessedFileInfo;
function createLanguageService(host: LanguageServiceHost, documentRegistry?: DocumentRegistry): LanguageService;
function createClassifier(): Classifier;
/**
Expand Down
781 changes: 494 additions & 287 deletions lib/typescript.js

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions lib/typescriptServices.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -574,7 +574,7 @@ declare namespace ts {
asteriskToken?: Node;
expression?: Expression;
}
interface BinaryExpression extends Expression {
interface BinaryExpression extends Expression, Declaration {
left: Expression;
operatorToken: Node;
right: Expression;
Expand Down Expand Up @@ -618,7 +618,7 @@ declare namespace ts {
interface ObjectLiteralExpression extends PrimaryExpression, Declaration {
properties: NodeArray<ObjectLiteralElement>;
}
interface PropertyAccessExpression extends MemberExpression {
interface PropertyAccessExpression extends MemberExpression, Declaration {
expression: LeftHandSideExpression;
dotToken: Node;
name: Identifier;
Expand Down Expand Up @@ -2153,7 +2153,7 @@ declare namespace ts {
function updateLanguageServiceSourceFile(sourceFile: SourceFile, scriptSnapshot: IScriptSnapshot, version: string, textChangeRange: TextChangeRange, aggressiveChecks?: boolean): SourceFile;
function createGetCanonicalFileName(useCaseSensitivefileNames: boolean): (fileName: string) => string;
function createDocumentRegistry(useCaseSensitiveFileNames?: boolean): DocumentRegistry;
function preProcessFile(sourceText: string, readImportFiles?: boolean): PreProcessedFileInfo;
function preProcessFile(sourceText: string, readImportFiles?: boolean, detectJavaScriptImports?: boolean): PreProcessedFileInfo;
function createLanguageService(host: LanguageServiceHost, documentRegistry?: DocumentRegistry): LanguageService;
function createClassifier(): Classifier;
/**
Expand Down
781 changes: 494 additions & 287 deletions lib/typescriptServices.js

Large diffs are not rendered by default.

69 changes: 63 additions & 6 deletions src/compiler/binder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ namespace ts {

export const enum ModuleInstanceState {
NonInstantiated = 0,
Instantiated = 1,
ConstEnumOnly = 2
Instantiated = 1,
ConstEnumOnly = 2
}

export function getModuleInstanceState(node: Node): ModuleInstanceState {
Expand Down Expand Up @@ -90,6 +90,8 @@ namespace ts {
let lastContainer: Node;
let seenThisKeyword: boolean;

let isJavaScriptFile = isSourceFileJavaScript(file);

// If this file is an external module, then it is automatically in strict-mode according to
// ES6. If it is not an external module, then we'll determine if it is in strict mode or
// not depending on if we see "use strict" in certain places (or if we hit a class/namespace).
Expand Down Expand Up @@ -164,6 +166,9 @@ namespace ts {
return "__export";
case SyntaxKind.ExportAssignment:
return (<ExportAssignment>node).isExportEquals ? "export=" : "default";
case SyntaxKind.BinaryExpression:
// Binary expression case is for JS module 'module.exports = expr'
return "export=";
case SyntaxKind.FunctionDeclaration:
case SyntaxKind.ClassDeclaration:
return node.flags & NodeFlags.Default ? "default" : undefined;
Expand Down Expand Up @@ -779,7 +784,7 @@ namespace ts {
return "__" + indexOf((<SignatureDeclaration>node.parent).parameters, node);
}

function bind(node: Node) {
function bind(node: Node): void {
node.parent = parent;

let savedInStrictMode = inStrictMode;
Expand Down Expand Up @@ -851,9 +856,18 @@ namespace ts {

function bindWorker(node: Node) {
switch (node.kind) {
/* Strict mode checks */
case SyntaxKind.Identifier:
return checkStrictModeIdentifier(<Identifier>node);
case SyntaxKind.BinaryExpression:
if (isJavaScriptFile) {
if (isExportsPropertyAssignment(node)) {
bindExportsPropertyAssignment(<BinaryExpression>node);
}
else if (isModuleExportsAssignment(node)) {
bindModuleExportsAssignment(<BinaryExpression>node);
}
}
return checkStrictModeBinaryExpression(<BinaryExpression>node);
case SyntaxKind.CatchClause:
return checkStrictModeCatchClause(<CatchClause>node);
Expand Down Expand Up @@ -919,6 +933,14 @@ namespace ts {
checkStrictModeFunctionName(<FunctionExpression>node);
let bindingName = (<FunctionExpression>node).name ? (<FunctionExpression>node).name.text : "__function";
return bindAnonymousDeclaration(<FunctionExpression>node, SymbolFlags.Function, bindingName);

case SyntaxKind.CallExpression:
if (isJavaScriptFile) {
bindCallExpression(<CallExpression>node);
Copy link
Member

Choose a reason for hiding this comment

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

I would move the !file.commonJsModuleIndicator test into bindCallExpression so we have all the logic in one place.

}
break;

// Members of classes, interfaces, and modules
case SyntaxKind.ClassExpression:
case SyntaxKind.ClassDeclaration:
return bindClassLikeDeclaration(<ClassLikeDeclaration>node);
Expand All @@ -930,6 +952,8 @@ namespace ts {
return bindEnumDeclaration(<EnumDeclaration>node);
case SyntaxKind.ModuleDeclaration:
return bindModuleDeclaration(<ModuleDeclaration>node);

// Imports and exports
case SyntaxKind.ImportEqualsDeclaration:
case SyntaxKind.NamespaceImport:
case SyntaxKind.ImportSpecifier:
Expand All @@ -949,16 +973,21 @@ namespace ts {
function bindSourceFileIfExternalModule() {
setExportContextFlag(file);
if (isExternalModule(file)) {
bindAnonymousDeclaration(file, SymbolFlags.ValueModule, `"${removeFileExtension(file.fileName)}"`);
bindSourceFileAsExternalModule();
}
}

function bindExportAssignment(node: ExportAssignment) {
function bindSourceFileAsExternalModule() {
bindAnonymousDeclaration(file, SymbolFlags.ValueModule, `"${removeFileExtension(file.fileName) }"`);
}

function bindExportAssignment(node: ExportAssignment|BinaryExpression) {
Copy link
Member

Choose a reason for hiding this comment

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

We usually put a blank on both sides of the | operator.

let boundExpression = node.kind === SyntaxKind.ExportAssignment ? (<ExportAssignment>node).expression : (<BinaryExpression>node).right;
if (!container.symbol || !container.symbol.exports) {
// Export assignment in some sort of block construct
bindAnonymousDeclaration(node, SymbolFlags.Alias, getDeclarationName(node));
}
else if (node.expression.kind === SyntaxKind.Identifier) {
else if (boundExpression.kind === SyntaxKind.Identifier) {
// An export default clause with an identifier exports all meanings of that identifier
declareSymbol(container.symbol.exports, container.symbol, node, SymbolFlags.Alias, SymbolFlags.PropertyExcludes | SymbolFlags.AliasExcludes);
}
Expand All @@ -985,6 +1014,34 @@ namespace ts {
}
}

function setCommonJsModuleIndicator(node: Node) {
if (!file.commonJsModuleIndicator) {
file.commonJsModuleIndicator = node;
bindSourceFileAsExternalModule();
}
}

function bindExportsPropertyAssignment(node: BinaryExpression) {
// When we create a property via 'exports.foo = bar', the 'exports.foo' property access
// expression is the declaration
setCommonJsModuleIndicator(node);
declareSymbol(file.symbol.exports, file.symbol, <PropertyAccessExpression>node.left, SymbolFlags.Property | SymbolFlags.Export, SymbolFlags.None);
}

function bindModuleExportsAssignment(node: BinaryExpression) {
// 'module.exports = expr' assignment
setCommonJsModuleIndicator(node);
bindExportAssignment(node);
}

function bindCallExpression(node: CallExpression) {
// We're only inspecting call expressions to detect CommonJS modules, so we can skip
// this check if we've already seen the module indicator
if (!file.commonJsModuleIndicator && isRequireCall(node)) {
setCommonJsModuleIndicator(node);
}
}

function bindClassLikeDeclaration(node: ClassLikeDeclaration) {
if (node.kind === SyntaxKind.ClassDeclaration) {
bindBlockScopedDeclaration(node, SymbolFlags.Class, SymbolFlags.ClassExcludes);
Expand Down
Loading