8000 UMD support by RyanCavanaugh · Pull Request #7264 · microsoft/TypeScript · GitHub
[go: up one dir, main page]

Skip to content

UMD support #7264

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

Merged
merged 11 commits into from
Mar 10, 2016
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Next Next commit
UMD support
  • Loading branch information
RyanCavanaugh committed Mar 9, 2016
commit 44aa7388eaf234abff335fa8606c0fd032ca5601
11 changes: 11 additions & 0 deletions src/compiler/binder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1355,6 +1355,8 @@ namespace ts {
case SyntaxKind.ImportSpecifier:
case SyntaxKind.ExportSpecifier:
return declareSymbolAndAddToSymbolTable(<Declaration>node, SymbolFlags.Alias, SymbolFlags.AliasExcludes);
case SyntaxKind.GlobalModuleExportDeclaration:
return bindGlobalModuleExportDeclaration(<GlobalModuleExportDeclaration>node);
case SyntaxKind.ImportClause:
return bindImportClause(<ImportClause>node);
case SyntaxKind.ExportDeclaration:
Expand Down Expand Up @@ -1404,6 +1406,15 @@ namespace ts {
}
}

function bindGlobalModuleExportDeclaration(node: GlobalModuleExportDeclaration) {
if (!file.externalModuleIndicator) {
Copy link
Member

Choose a reason for hiding this comment

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

Use the appropriate helper function to check this that's been defined elsewhere.

Copy link
Member Author

Choose a reason for hiding this comment

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

?

Copy link
Member

Choose a reason for hiding this comment

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

Sorry, I meant use isExternalModule in utilities.ts. Vlad mentioned it offhandedly and I was too lazy to look it up.

file.bindDiagnostics.push(createDiagnosticForNode(node, Diagnostics.Global_module_exports_may_only_appear_in_module_files));
return;
}
file.symbol.globalExports = file.symbol.globalExports || {};
declareSymbol(file.symbol.globalExports, file.symbol, node, SymbolFlags.Alias, SymbolFlags.AliasExcludes);
}

function bindExportDeclaration(node: ExportDeclaration) {
if (!container.symbol || !container.symbol.exports) {
// Export * in some sort of block construct
Expand Down
28 changes: 28 additions & 0 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -981,6 +981,10 @@ namespace ts {
return getExternalModuleMember(<ImportDeclaration>node.parent.parent.parent, node);
}

function getTargetOfGlobalModuleExportDeclaration(node: GlobalModuleExportDeclaration): Symbol {
return node.parent.symbol;
Copy link
Contributor

Choose a reason for hiding this comment

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

can this symbol be merged with anything?

Copy link
Member Author

Choose a reason for hiding this comment

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

Hrm, yes. You could have a module jquery.d.ts and then an augmentation of it in another file. I assume that has some impact here?

Copy link
Contributor

Choose a reason for hiding this comment

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

use getMergedSymbol

}

function getTargetOfExportSpecifier(node: ExportSpecifier): Symbol {
return (<ExportDeclaration>node.parent.parent).moduleSpecifier ?
getExternalModuleMember(<ExportDeclaration>node.parent.parent, node) :
Expand All @@ -1005,6 +1009,8 @@ namespace ts {
return getTargetOfExportSpecifier(<ExportSpecifier>node);
case SyntaxKind.ExportAssignment:
return getTargetOfExportAssignment(<ExportAssignment>node);
case SyntaxKind.GlobalModuleExportDeclaration:
return getTargetOfGlobalModuleExportDeclaration(<GlobalModuleExportDeclaration>node);
}
}

Expand Down Expand Up @@ -15220,6 +15226,23 @@ namespace ts {
}
}

function checkGlobalModuleExportDeclaration(node: GlobalModuleExportDeclaration) {
if (node.modifiers && node.modifiers.length) {
error(node, Diagnostics.Modifiers_cannot_appear_here);
}

if (node.parent.kind !== SyntaxKind.SourceFile) {
error(node, Diagnostics.Global_module_exports_may_only_appear_at_top_level);
}
else {
const parent = node.parent as SourceFile;
// Note: the binder handles the case where the declaration isn't in an external module
if (parent.externalModuleIndicator && !parent.isDeclarationFile) {
error(node, Diagnostics.Global_module_exports_may_only_appear_in_declaration_files);
}
}
Copy link
Member

Choose a reason for hiding this comment

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

Spoke offline with @vladima. Add all of this to the binder.


}

function checkSourceElement(node: Node): void {
if (!node) {
Expand Down Expand Up @@ -15337,6 +15360,8 @@ namespace ts {
return checkExportDeclaration(<ExportDeclaration>node);
case SyntaxKind.ExportAssignment:
return checkExportAssignment(<ExportAssignment>node);
case SyntaxKind.GlobalModuleExportDeclaration:
return checkGlobalModuleExportDeclaration(<GlobalModuleExportDeclaration>node);
case SyntaxKind.EmptyStatement:
checkGrammarStatementInAmbientContext(node);
return;
Expand Down Expand Up @@ -16331,6 +16356,9 @@ namespace ts {
if (file.moduleAugmentations.length) {
(augmentations || (augmentations = [])).push(file.moduleAugmentations);
}
if (file.wasReferenced && file.symbol && file.symbol.globalExports) {
mergeSymbolTable(globals, file.symbol.globalExports);
}
});

if (augmentations) {
Expand Down
12 changes: 12 additions & 0 deletions src/compiler/diagnosticMessages.json
Original file line number Diff line number Diff line change
Expand Up @@ -831,6 +831,18 @@
"category": "Error",
"code": 1313
},
"Global module exports may only appear in module files.": {
"category": "Error",
"code": 1314
},
"Global module exports may only appear in declaration files.": {
"category": "Error",
"code": 1315
},
"Global module exports may only appear at top level.": {
"category": "Error",
"code": 1316
},
"Duplicate identifier '{0}'.": {
"category": "Error",
"code": 2300
Expand Down
38 changes: 32 additions & 6 deletions src/compiler/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,9 @@ namespace ts {
case SyntaxKind.ImportClause:
return visitNode(cbNode, (<ImportClause>node).name) ||
visitNode(cbNode, (<ImportClause>node).namedBindings);
case SyntaxKind.GlobalModuleExportDeclaration:
return visitNode(cbNode, (<GlobalModuleExportDeclaration>node).name);

case SyntaxKind.NamespaceImport:
return visitNode(cbNode, (<NamespaceImport>node).name);
case SyntaxKind.NamedImports:
Expand Down Expand Up @@ -1125,7 +1128,7 @@ namespace ts {
if (token === SyntaxKind.DefaultKeyword) {
return lookAhead(nextTokenIsClassOrFunction);
}
return token !== SyntaxKind.AsteriskToken && token !== SyntaxKind.OpenBraceToken && canFollowModifier();
return token !== SyntaxKind.AsteriskToken && token !== SyntaxKind.AsKeyword && token !== SyntaxKind.OpenBraceToken && canFollowModifier();
}
if (token === SyntaxKind.DefaultKeyword) {
return nextTokenIsClassOrFunction();
Expand Down Expand Up @@ -4400,7 +4403,8 @@ namespace ts {
continue;

case SyntaxKind.GlobalKeyword:
return nextToken() === SyntaxKind.OpenBraceToken;
nextToken();
return token === SyntaxKind.OpenBraceToken || token === SyntaxKind.Identifier || token === SyntaxKind.ExportKeyword;

case SyntaxKind.ImportKeyword:
nextToken();
Expand All @@ -4409,7 +4413,8 @@ namespace ts {
case SyntaxKind.ExportKeyword:
nextToken();
if (token === SyntaxKind.EqualsToken || token === SyntaxKind.AsteriskToken ||
token === SyntaxKind.OpenBraceToken || token === SyntaxKind.DefaultKeyword) {
token === SyntaxKind.OpenBraceToken || token === SyntaxKind.DefaultKeyword ||
token === SyntaxKind.AsKeyword) {
return true;
}
continue;
Expand Down Expand Up @@ -4586,16 +4591,23 @@ namespace ts {
case SyntaxKind.EnumKeyword:
return parseEnumDeclaration(fullStart, decorators, modifiers);
case SyntaxKind.GlobalKeyword:
return parseModuleDeclaration(fullStart, decorators, modifiers);
Copy link
Member

Choose a reason for hiding this comment

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

You can let this fall through again.

case SyntaxKind.ModuleKeyword:
case SyntaxKind.NamespaceKeyword:
return parseModuleDeclaration(fullStart, decorators, modifiers);
case SyntaxKind.ImportKeyword:
return parseImportDeclarationOrImportEqualsDeclaration(fullStart, decorators, modifiers);
case SyntaxKind.ExportKeyword:
nextToken();
return token === SyntaxKind.DefaultKeyword || token === SyntaxKind.EqualsToken ?
parseExportAssignment(fullStart, decorators, modifiers) :
parseExportDeclaration(fullStart, decorators, modifiers);
switch (token) {
case SyntaxKind.DefaultKeyword:
case SyntaxKind.EqualsToken:
return parseExportAssignment(fullStart, decorators, modifiers);
case SyntaxKind.AsKeyword:
return parseGlobalModuleExportDeclaration(fullStart, decorators, modifiers);
default:
return parseExportDeclaration(fullStart, decorators, modifiers);
}
default:
if (decorators || modifiers) {
// We reached this point because we encountered decorators and/or modifiers and assumed a declaration
Expand Down Expand Up @@ -5264,6 +5276,20 @@ namespace ts {
return nextToken() === SyntaxKind.SlashToken;
}

function parseGlobalModuleExportDeclaration(fullStart: number, decorators: NodeArray<Decorator>, modifiers: ModifiersArray): GlobalModuleExportDeclaration {
const exportDeclaration = <GlobalModuleExportDeclaration>createNode(SyntaxKind.GlobalModuleExportDeclaration, fullStart);
exportDeclaration.decorators = decorators;
exportDeclaration.modifiers = modifiers;
parseExpected(SyntaxKind.AsKeyword);
parseExpected(SyntaxKind.NamespaceKeyword);

exportDeclaration.name = parseIdentifier();

parseExpected(SyntaxKind.SemicolonToken);

return finishNode(exportDeclaration);
}

function parseImportDeclarationOrImportEqualsDeclaration(fullStart: number, decorators: NodeArray<Decorator>, modifiers: ModifiersArray): ImportEqualsDeclaration | ImportDeclaration {
parseExpected(SyntaxKind.ImportKeyword);
const afterImportPos = scanner.getStartPos();
Expand Down
24 changes: 16 additions & 8 deletions src/compiler/program.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1282,7 +1282,7 @@ namespace ts {
}

function processRootFile(fileName: string, isDefaultLib: boolean) {
processSourceFile(normalizePath(fileName), isDefaultLib);
processSourceFile(normalizePath(fileName), isDefaultLib, /*isReference*/ true);
}

function fileReferenceIsEqualTo(a: FileReference, b: FileReference): boolean {
Expand Down Expand Up @@ -1376,15 +1376,18 @@ namespace ts {
}
}

function processSourceFile(fileName: string, isDefaultLib: boolean, refFile?: SourceFile, refPos?: number, refEnd?: number) {
/**
* 'isReference' indicates whether the file was brought in via a reference directive (rather than an import declaration)
*/
function processSourceFile(fileName: string, isDefaultLib: boolean, isReference: boolean, refFile?: SourceFile, refPos?: number, refEnd?: number) {
Copy link
Member

Choose a reason for hiding this comment

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

A little bit of documentation on this would be helpful. From a cursory glance, it doesn't seem obvious that this is differentiated from an import.

Alternatively, make an enum.

let diagnosticArgument: string[];
let diagnostic: DiagnosticMessage;
if (hasExtension(fileName)) {
if (!options.allowNonTsExtensions && !forEach(supportedExtensions, extension => fileExtensionIs(host.getCanonicalFileName(fileName), extension))) {
diagnostic = Diagnostics.File_0_has_unsupported_extension_The_only_supported_extensions_are_1;
diagnosticArgument = [fileName, "'" + supportedExtensions.join("', '") + "'"];
}
else if (!findSourceFile(fileName, toPath(fileName, currentDirectory, getCanonicalFileName), isDefaultLib, refFile, refPos, refEnd)) {
else if (!findSourceFile(fileName, toPath(fileName, currentDirectory, getCanonicalFileName), isDefaultLib, isReference, refFile, refPos, refEnd)) {
diagnostic = Diagnostics.File_0_not_found;
diagnosticArgument = [fileName];
}
Expand All @@ -1394,13 +1397,13 @@ namespace ts {
}
}
else {
const nonTsFile: SourceFile = options.allowNonTsExtensions && findSourceFile(fileName, toPath(fileName, currentDirectory, getCanonicalFileName), isDefaultLib, refFile, refPos, refEnd);
const nonTsFile: SourceFile = options.allowNonTsExtensions && findSourceFile(fileName, toPath(fileName, currentDirectory, getCanonicalFileName), isDefaultLib, isReference, refFile, refPos, refEnd);
if (!nonTsFile) {
if (options.allowNonTsExtensions) {
diagnostic = Diagnostics.File_0_not_found;
diagnosticArgument = [fileName];
}
else if (!forEach(supportedExtensions, extension => findSourceFile(fileName + extension, toPath(fileName + extension, currentDirectory, getCanonicalFileName), isDefaultLib, refFile, refPos, refEnd))) {
else if (!forEach(supportedExtensions, extension => findSourceFile(fileName + extension, toPath(fileName + extension, currentDirectory, getCanonicalFileName), isDefaultLib, isReference, refFile, refPos, refEnd))) {
diagnostic = Diagnostics.File_0_not_found;
fileName += ".ts";
diagnosticArgument = [fileName];
Expand Down Expand Up @@ -1429,7 +1432,7 @@ namespace ts {
}

// Get source file from normalized fileName
function findSourceFile(fileName: string, path: Path, isDefaultLib: boolean, refFile?: SourceFile, refPos?: number, refEnd?: number): SourceFile {
function findSourceFile(fileName: string, path: Path, isDefaultLib: boolean, isReference: boolean, refFile?: SourceFile, refPos?: number, refEnd?: number): SourceFile {
if (filesByName.contains(path)) {
const file = filesByName.get(path);
// try to check if we've already seen this file but with a different casing in path
Expand All @@ -1438,6 +1441,10 @@ namespace ts {
reportFileNamesDifferOnlyInCasingError(fileName, file.fileName, refFile, refPos, refEnd);
}

if (file) {
file.wasReferenced = file.wasReferenced || isReference;
}

return file;
}

Expand All @@ -1454,6 +1461,7 @@ namespace ts {

filesByName.set(path, file);
if (file) {
file.wasReferenced = file.wasReferenced || isReference;
file.path = path;

if (host.useCaseSensitiveFileNames()) {
Expand Down Expand Up @@ -1491,7 +1499,7 @@ namespace ts {
function processReferencedFiles(file: SourceFile, basePath: string) {
forEach(file.referencedFiles, ref => {
const referencedFileName = resolveTripleslashReference(ref.fileName, file.fileName);
processSourceFile(referencedFileName, /*isDefaultLib*/ false, file, ref.pos, ref.end);
processSourceFile(referencedFileName, /*isDefaultLib*/ false, /*isReference*/ true, file, ref.pos, ref.end);
});
}

Expand All @@ -1517,7 +1525,7 @@ namespace ts {
i < file.imports.length;

if (shouldAddFile) {
const importedFile = findSourceFile(resolution.resolvedFileName, toPath(resolution.resolvedFileName, currentDirectory, getCanonicalFileName), /*isDefaultLib*/ false, file, skipTrivia(file.text, file.imports[i].pos), file.imports[i].end);
const importedFile = findSourceFile(resolution.resolvedFileName, toPath(resolution.resolvedFileName, currentDirectory, getCanonicalFileName), /*isDefaultLib*/ false, /*isReference*/ false, file, skipTrivia(file.text, file.imports[i].pos), file.imports[i].end);

if (importedFile && resolution.isExternalLibraryImport) {
// Since currently irrespective of allowJs, we only look for supportedTypeScript extension external module files,
Expand Down
10 changes: 10 additions & 0 deletions src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,7 @@ namespace ts {
ModuleDeclaration,
ModuleBlock,
CaseBlock,
GlobalModuleExportDeclaration,
ImportEqualsDeclaration,
ImportDeclaration,
ImportClause,
Expand Down Expand Up @@ -1324,6 +1325,12 @@ namespace ts {
name: Identifier;
}

// @kind(SyntaxKind.GlobalModuleImport)
export interface GlobalModuleExportDeclaration extends DeclarationStatement {
name: Identifier;
moduleReference: LiteralLikeNode;
}

// @kind(SyntaxKind.ExportDeclaration)
export interface ExportDeclaration extends DeclarationStatement {
exportClause?: NamedExports;
Expand Down Expand Up @@ -1537,6 +1544,8 @@ namespace ts {
/* @internal */ externalModuleIndicator: Node;
// The first node that causes this file to be a CommonJS module
/* @internal */ commonJsModuleIndicator: Node;
// True if the file was a root file in a compilation or a /// reference targets
/* @internal */ wasReferenced?: boolean;

/* @internal */ identifiers: Map<string>;
/* @internal */ nodeCount: number;
Expand Down Expand Up @@ -1995,6 +2004,7 @@ namespace ts {

members?: SymbolTable; // Class, interface or literal instance members
exports?: SymbolTable; // Module exports
globalExports?: SymbolTable; // Conditional global UMD exports
/* @internal */ id?: number; // Unique id (used to look up SymbolLinks)
/* @internal */ mergeId?: number; // Merge id (used to look up merged symbol)
/* @internal */ parent?: Symbol; // Parent symbol
Expand Down
1 change: 1 addition & 0 deletions src/compiler/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1471,6 +1471,7 @@ namespace ts {
// export default ...
export function isAliasSymbolDeclaration(node: Node): boolean {
return node.kind === SyntaxKind.ImportEqualsDeclaration ||
node.kind === SyntaxKind.GlobalModuleExportDeclaration ||
node.kind === SyntaxKind.ImportClause && !!(<ImportClause>node).name ||
node.kind === SyntaxKind.NamespaceImport ||
node.kind === SyntaxKind.ImportSpecifier ||
Expand Down
2 changes: 1 addition & 1 deletion src/harness/compilerRunner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ class CompilerBaselineRunner extends RunnerBase {
toBeCompiled = [];
otherFiles = [];

if (/require\(/.test(lastUnit.content) || /reference\spath/.test(lastUnit.content)) {
if (testCaseContent.settings["noImplicitReferences"] || /require\(/.test(lastUnit.content) || /reference\spath/.test(lastUnit.content)) {
toBeCompiled.push({ unitName: this.makeUnitName(lastUnit.name, rootDir), content: lastUnit.content });
units.forEach(unit => {
if (unit.name !== lastUnit.name) {
Expand Down
3 changes: 2 additions & 1 deletion src/harness/harness.ts
Original file line number Diff line number Diff line change
Expand Up @@ -896,7 +896,8 @@ namespace Harness {
{ name: "fileName", type: "string" },
{ name: "libFiles", type: "string" },
{ name: "noErrorTruncation", type: "boolean" },
{ name: "suppressOutputPathCheck", type: "boolean" }
{ name: "suppressOutputPathCheck", type: "boolean" },
{ name: "noImplicitReferences", type: "boolean" }
];

let optionsIndex: ts.Map<ts.CommandLineOption>;
49E0 Expand Down
Loading
0