Merge branch 'master' into wip-master-statelessOverload

# Conflicts:
#	src/compiler/factory.ts
This commit is contained in:
Kanchalai Tanglertsampan
2017-02-14 15:21:06 -08:00
2233 changed files with 17742 additions and 7702 deletions
+13 -1
View File
@@ -8,11 +8,14 @@ Alexander Rusakov <a_s_rusakov@mail.ru>
Alex Eagle <alexeagle@google.com>
Anatoly Ressin <anatoly.ressin@icloud.com>
Anders Hejlsberg <andersh@microsoft.com> unknown <andersh@AndersX1.NOE.Nokia.com> unknown <andersh@andersh-yoga.redmond.corp.microsoft.com>
about-code <about-code@users.noreply.github.com> # Andreas Martin
Andrej Baran <andrej.baran@gmail.com>
Andrew Ochsner <andrew.ochsner@wipro.com>
Andrew Z Allen <me@andrewzallen.com>
Andy Hanson <anhans@microsoft.com> Andy <anhans@microsoft.com>
Anil Anar <anilanar@hotmail.com>
Anton Tolmachev <myste@mail.ru>
Anubha Mathur <anubmat@microsoft.com> anubmat <anubmat@microsoft.com>
Arnavion <arnavion@gmail.com> # Arnav Singh
Arthur Ozga <aozgaa@umich.edu> Arthur Ozga <t-arthoz@microsoft.com> Arthur Ozga <aozgaa-ms@outlook.com> Arthur Ozga <aozgaa@users.noreply.github.com> Arthur Ozga <arozga@microsoft.com>
Asad Saeeduddin <masaeedu@gmail.com>
@@ -37,6 +40,7 @@ Dan Corder <dev@dancorder.com>
Dan Quirk <danquirk@microsoft.com> Dan Quirk <danquirk@users.noreply.github.com> nknown <danquirk@DANQUIRK1.redmond.corp.microsoft.com>
Daniel Rosenwasser <drosen@microsoft.com> Daniel Rosenwasser <DanielRosenwasser@users.noreply.github.com> Daniel Rosenwasser <DanielRosenwasser@gmail.com> Daniel Rosenwasser <Daniel.Rosenwasser@microsoft.com> Daniel Rosenwasser <DanielRosenwasser@microsoft.com>
David Li <jiawei.davidli@gmail.com>
David Sheldrick <david@futurice.com>
David Souther <davidsouther@gmail.com>
Denis Nedelyaev <denvned@gmail.com>
Dick van den Brink <d_vandenbrink@outlook.com> unknown <d_vandenbrink@outlook.com> unknown <d_vandenbrink@live.com>
@@ -52,6 +56,7 @@ Evan Sebastian <evanlhoini@gmail.com>
Eyas <eyas.sharaiha@gmail.com> # Eyas Sharaiha
Fabian Cook <faybecook@gmail.com>
falsandtru <falsandtru@users.noreply.github.com> # @falsandtru
flowmemo <flowmemo@outlook.com> # @flowmemo
Frank Wallis <fwallis@outlook.com>
František Žiacik <fziacik@gratex.com> František Žiacik <ziacik@gmail.com>
Gabe Moothart <gmoothart@gmail.com>
@@ -62,6 +67,7 @@ Graeme Wicksted <graeme.wicksted@gmail.com>
Guillaume Salles <guillaume.salles@me.com>
Guy Bedford <guybedford@gmail.com> guybedford <guybedford@gmail.com>
Harald Niesche <harald@niesche.de>
Homa Wong <homawong@gmail.com>
Iain Monro <iain.monro@softwire.com>
Ingvar Stepanyan <me@rreverser.com>
impinball <impinball@gmail.com> # Isiah Meadows
@@ -81,6 +87,7 @@ Jonathan Park <jpark@daptiv.com>
Jonathan Turner <jont@microsoft.com> Jonathan Turner <probata@hotmail.com>
Jonathan Toland <toland@dnalot.com>
Jesse Schalken <me@jesseschalken.com>
Joel Day <joelday@gmail.com>
Josh Abernathy <joshaber@gmail.com> joshaber <joshaber@gmail.com>
Josh Kalderimis <josh.kalderimis@gmail.com>
Josh Soref <jsoref@users.noreply.github.com>
@@ -95,10 +102,12 @@ Kanchalai Tanglertsampan <yuisu@microsoft.com> Yui T <yuisu@microsoft.com>
Kanchalai Tanglertsampan <yuisu@microsoft.com> Yui <yuit@users.noreply.github.com>
Kanchalai Tanglertsampan <yuisu@microsoft.com> Yui <yuisu@microsoft.com>
Kanchalai Tanglertsampan <yuisu@microsoft.com> yui T <yuisu@microsoft.com>
Kārlis Gaņģis <Knagis@users.noreply.github.com>
Keith Mashinter <kmashint@yahoo.com> kmashint <kmashint@yahoo.com>
Ken Howard <ken@simplicatedweb.com>
Kevin Lang <klang2012@gmail.com>
kimamula <kenji.imamula@gmail.com> # Kenji Imamula
Klaus Meinhardt <klaus.meinhardt1@gmail.com>
Kyle Kelley <rgbkrk@gmail.com>
Lorant Pinter <lorant.pinter@prezi.com>
Lucien Greathouse <me@lpghatguy.com>
@@ -107,6 +116,7 @@ Martin Vseticka <vseticka.martin@gmail.com> Martin Všeticka <vseticka.martin@gm
gcnew <gcnew@abv.bg> # Marin Marinov
vvakame <vvakame+dev@gmail.com> # Masahiro Wakame
Matt McCutchen <rmccutch@mit.edu>
MANISH-GIRI <manish.giri.me@gmail.com> # Manish Giri
Max Deepfield <maxdeepfield@absolutefreakout.com>
Micah Zoltu <micah@zoltu.net>
Michael <maykelchiche@gmail.com>
@@ -213,4 +223,6 @@ Tim Perry <tim.perry@softwire.com>
Vidar Tonaas Fauske <vidartf@gmail.com>
Viktor Zozulyak <zozulyakviktor@gmail.com>
rix <rix@rixs-MacBook-Pro.local> # Richard Sentino
rohitverma007 <rohitverma@live.ca> # Rohit Verma
rohitverma007 <rohitverma@live.ca> # Rohit Verma
rdosanjh <me@rajdeep.io> # Raj Dosanjh
gdh1995 <gdh1995@qq.com> # Dahan Gong
+12
View File
@@ -12,13 +12,16 @@ TypeScript is authored by:
* Aliaksandr Radzivanovich
* Anatoly Ressin
* Anders Hejlsberg
* Andreas Martin
* Andrej Baran
* Andrew Ochsner
* Andrew Z Allen
* András Parditka
* Andy Hanson
* Anil Anar
* Anton Khlynovskiy
* Anton Tolmachev
* Anubha Mathur
* Arnav Singh
* Arthur Ozga
* Asad Saeeduddin
@@ -42,12 +45,14 @@ TypeScript is authored by:
* Cotton Hou
* Cyrus Najmabadi
* Dafrok Zhang
* Dahan Gong
* Dan Corder
* Dan Quirk
* Daniel Hollocher
* Daniel Rosenwasser
* David Kmenta
* David Li
* David Sheldrick
* David Souther
* Denis Nedelyaev
* Dick van den Brink
@@ -66,6 +71,7 @@ TypeScript is authored by:
* Eyas Sharaiha
* Fabian Cook
* @falsandtru
* @flowmemo
* Frank Wallis
* Franklin Tse
* František Žiacik
@@ -79,6 +85,7 @@ TypeScript is authored by:
* Guy Bedford
* Harald Niesche
* Herrington Darkholme
* Homa Wong
* Iain Monro
* Ingvar Stepanyan
* Isiah Meadows
@@ -93,6 +100,7 @@ TypeScript is authored by:
* Jeffrey Morlan
* Jesse Schalken
* Jiri Tobisek
* Joel Day
* Joey Wilson
* Johannes Rieken
* John Vilk
@@ -114,10 +122,13 @@ TypeScript is authored by:
* Ken Howard
* Kenji Imamula
* Kevin Lang
* Klaus Meinhardt
* Kyle Kelley
* Kārlis Gaņģis
* Lorant Pinter
* Lucien Greathouse
* Lukas Elmer
* Manish Giri
* Marin Marinov
* Marius Schulz
* Martin Vseticka
@@ -155,6 +166,7 @@ TypeScript is authored by:
* @progre
* Punya Biswal
* Rado Kirov
* Raj Dosanjh
* Richard Knoll
* Richard Sentino
* Robert Coie
+32 -169
View File
@@ -6,6 +6,8 @@ var path = require("path");
var child_process = require("child_process");
var fold = require("travis-fold");
var runTestsInParallel = require("./scripts/mocha-parallel").runTestsInParallel;
var ts = require("./lib/typescript");
// Variables
var compilerDirectory = "src/compiler/";
@@ -34,6 +36,24 @@ if (process.env.path !== undefined) {
process.env.PATH = nodeModulesPathPrefix + process.env.PATH;
}
function filesFromConfig(configPath) {
var configText = fs.readFileSync(configPath).toString();
var config = ts.parseConfigFileTextToJson(configPath, configText, /*stripComments*/ true);
if (config.error) {
throw new Error(diagnosticsToString([config.error]));
}
const configFileContent = ts.parseJsonConfigFileContent(config.config, ts.sys, path.dirname(configPath));
if (configFileContent.errors && configFileContent.errors.length) {
throw new Error(diagnosticsToString(configFileContent.errors));
}
return configFileContent.fileNames;
function diagnosticsToString(s) {
return s.map(function(e) { return ts.flattenDiagnosticMessageText(e.messageText, ts.sys.newLine); }).join(ts.sys.newLine);
}
}
function toNs(diff) {
return diff[0] * 1e9 + diff[1];
}
@@ -56,173 +76,12 @@ function measure(marker) {
console.log("travis_time:end:" + marker.id + ":start=" + toNs(marker.stamp) + ",finish=" + toNs(total) + ",duration=" + toNs(diff) + "\r");
}
var compilerSources = [
"core.ts",
"performance.ts",
"sys.ts",
"types.ts",
"scanner.ts",
"parser.ts",
"utilities.ts",
"binder.ts",
"checker.ts",
"factory.ts",
"visitor.ts",
"transformers/destructuring.ts",
"transformers/ts.ts",
"transformers/jsx.ts",
"transformers/esnext.ts",
"transformers/es2017.ts",
"transformers/es2016.ts",
"transformers/es2015.ts",
"transformers/generators.ts",
"transformers/es5.ts",
"transformers/module/es2015.ts",
"transformers/module/system.ts",
"transformers/module/module.ts",
"transformer.ts",
"sourcemap.ts",
"comments.ts",
"declarationEmitter.ts",
"emitter.ts",
"program.ts",
"commandLineParser.ts",
"tsc.ts",
"diagnosticInformationMap.generated.ts"
].map(function (f) {
return path.join(compilerDirectory, f);
});
var servicesSources = [
"core.ts",
"performance.ts",
"sys.ts",
"types.ts",
"scanner.ts",
"parser.ts",
"utilities.ts",
"binder.ts",
"checker.ts",
"factory.ts",
"visitor.ts",
"transformers/destructuring.ts",
"transformers/ts.ts",
"transformers/jsx.ts",
"transformers/esnext.ts",
"transformers/es2017.ts",
"transformers/es2016.ts",
"transformers/es2015.ts",
"transformers/generators.ts",
"transformers/es5.ts",
"transformers/module/es2015.ts",
"transformers/module/system.ts",
"transformers/module/module.ts",
"transformer.ts",
"sourcemap.ts",
"comments.ts",
"declarationEmitter.ts",
"emitter.ts",
"program.ts",
"commandLineParser.ts",
"diagnosticInformationMap.generated.ts"
].map(function (f) {
return path.join(compilerDirectory, f);
}).concat([
"types.ts",
"utilities.ts",
"breakpoints.ts",
"classifier.ts",
"completions.ts",
"documentHighlights.ts",
"documentRegistry.ts",
"findAllReferences.ts",
"goToDefinition.ts",
"goToImplementation.ts",
"jsDoc.ts",
"jsTyping.ts",
"navigateTo.ts",
"navigationBar.ts",
"outliningElementsCollector.ts",
"patternMatcher.ts",
"preProcess.ts",
"rename.ts",
"services.ts",
"shims.ts",
"signatureHelp.ts",
"symbolDisplay.ts",
"transpile.ts",
// Formatting
"formatting/formatting.ts",
"formatting/formattingContext.ts",
"formatting/formattingRequestKind.ts",
"formatting/formattingScanner.ts",
"formatting/references.ts",
"formatting/rule.ts",
"formatting/ruleAction.ts",
"formatting/ruleDescriptor.ts",
"formatting/ruleFlag.ts",
"formatting/ruleOperation.ts",
"formatting/ruleOperationContext.ts",
"formatting/rules.ts",
"formatting/rulesMap.ts",
"formatting/rulesProvider.ts",
"formatting/smartIndenter.ts",
"formatting/tokenRange.ts",
// CodeFixes
"codeFixProvider.ts",
"codefixes/fixes.ts",
"codefixes/fixExtendsInterfaceBecomesImplements.ts",
"codefixes/fixClassIncorrectlyImplementsInterface.ts",
"codefixes/fixClassDoesntImplementInheritedAbstractMember.ts",
"codefixes/fixClassSuperMustPrecedeThisAccess.ts",
"codefixes/fixConstructorForDerivedNeedSuperCall.ts",
"codefixes/helpers.ts",
"codefixes/importFixes.ts",
"codefixes/unusedIdentifierFixes.ts"
].map(function (f) {
return path.join(servicesDirectory, f);
}));
var baseServerCoreSources = [
"builder.ts",
"editorServices.ts",
"lsHost.ts",
"project.ts",
"protocol.ts",
"scriptInfo.ts",
"scriptVersionCache.ts",
"session.ts",
"shared.ts",
"types.ts",
"typingsCache.ts",
"utilities.ts",
].map(function (f) {
return path.join(serverDirectory, f);
});
var serverCoreSources = [
"server.ts"
].map(function (f) {
return path.join(serverDirectory, f);
}).concat(baseServerCoreSources);
var cancellationTokenSources = [
"cancellationToken.ts"
].map(function (f) {
return path.join(cancellationTokenDirectory, f);
});
var typingsInstallerSources = [
"../types.ts",
"../shared.ts",
"typingsInstaller.ts",
"nodeTypingsInstaller.ts"
].map(function (f) {
return path.join(typingsInstallerDirectory, f);
});
var serverSources = serverCoreSources.concat(servicesSources);
var languageServiceLibrarySources = baseServerCoreSources.concat(servicesSources);
var compilerSources = filesFromConfig("./src/compiler/tsconfig.json");
var servicesSources = filesFromConfig("./src/services/tsconfig.json");
var cancellationTokenSources = filesFromConfig(path.join(serverDirectory, "cancellationToken/tsconfig.json"));
var typingsInstallerSources = filesFromConfig(path.join(serverDirectory, "typingsInstaller/tsconfig.json"));
var serverSources = filesFromConfig(path.join(serverDirectory, "tsconfig.json"))
var languageServiceLibrarySources = filesFromConfig(path.join(serverDirectory, "tsconfig.library.json"));
var harnessCoreSources = [
"harness.ts",
@@ -269,6 +128,7 @@ var harnessSources = harnessCoreSources.concat([
"projectErrors.ts",
"matchFiles.ts",
"initializeTSConfig.ts",
"printer.ts",
].map(function (f) {
return path.join(unittestsDirectory, f);
})).concat([
@@ -1229,13 +1089,16 @@ var lintTargets = compilerSources
.concat(harnessSources)
// Other harness sources
.concat(["instrumenter.ts"].map(function (f) { return path.join(harnessDirectory, f) }))
.concat(serverCoreSources)
.concat(serverSources)
.concat(tslintRulesFiles)
.concat(servicesSources)
.concat(typingsInstallerSources)
.concat(cancellationTokenSources)
.concat(["Gulpfile.ts"])
.concat([nodeServerInFile, perftscPath, "tests/perfsys.ts", webhostPath]);
.concat([nodeServerInFile, perftscPath, "tests/perfsys.ts", webhostPath])
.map(function (p) { return path.resolve(p) });
// keep only unique items
lintTargets = Array.from(new Set(lintTargets));
function sendNextFile(files, child, callback, failures) {
var file = files.pop();
+1 -1
View File
@@ -2,7 +2,7 @@
"name": "typescript",
"author": "Microsoft Corp.",
"homepage": "http://typescriptlang.org/",
"version": "2.2.0",
"version": "2.3.0",
"license": "Apache-2.0",
"description": "TypeScript is a language for application scale JavaScript development",
"keywords": [
+1 -1
View File
@@ -167,7 +167,7 @@ function generateProtocolFile(protocolTs: string, typeScriptServicesDts: string)
const sanityCheckProgram = getProgramWithProtocolText(protocolDts, /*includeTypeScriptServices*/ false);
const diagnostics = [...sanityCheckProgram.getSyntacticDiagnostics(), ...sanityCheckProgram.getSemanticDiagnostics(), ...sanityCheckProgram.getGlobalDiagnostics()];
if (diagnostics.length) {
const flattenedDiagnostics = diagnostics.map(d => ts.flattenDiagnosticMessageText(d.messageText, "\n")).join("\n");
const flattenedDiagnostics = diagnostics.map(d => `${ts.flattenDiagnosticMessageText(d.messageText, "\n")} at ${d.file.fileName} line ${d.start}`).join("\n");
throw new Error(`Unexpected errors during sanity check: ${flattenedDiagnostics}`);
}
return protocolDts;
+34 -1
View File
@@ -1045,7 +1045,35 @@ namespace ts {
if (node.finallyBlock) {
// in finally flow is combined from pre-try/flow from try/flow from catch
// pre-flow is necessary to make sure that finally is reachable even if finally flows in both try and finally blocks are unreachable
addAntecedent(preFinallyLabel, preTryFlow);
// also for finally blocks we inject two extra edges into the flow graph.
// first -> edge that connects pre-try flow with the label at the beginning of the finally block, it has lock associated with it
// second -> edge that represents post-finally flow.
// these edges are used in following scenario:
// let a; (1)
// try { a = someOperation(); (2)}
// finally { (3) console.log(a) } (4)
// (5) a
// flow graph for this case looks roughly like this (arrows show ):
// (1-pre-try-flow) <--.. <-- (2-post-try-flow)
// ^ ^
// |*****(3-pre-finally-label) -----|
// ^
// |-- ... <-- (4-post-finally-label) <--- (5)
// In case when we walk the flow starting from inside the finally block we want to take edge '*****' into account
// since it ensures that finally is always reachable. However when we start outside the finally block and go through label (5)
// then edge '*****' should be discarded because label 4 is only reachable if post-finally label-4 is reachable
// Simply speaking code inside finally block is treated as reachable as pre-try-flow
// since we conservatively assume that any line in try block can throw or return in which case we'll enter finally.
// However code after finally is reachable only if control flow was not abrupted in try/catch or finally blocks - it should be composed from
// final flows of these blocks without taking pre-try flow into account.
//
// extra edges that we inject allows to control this behavior
// if when walking the flow we step on post-finally edge - we can mark matching pre-finally edge as locked so it will be skipped.
const preFinallyFlow: PreFinallyFlow = { flags: FlowFlags.PreFinally, antecedent: preTryFlow, lock: {} };
addAntecedent(preFinallyLabel, preFinallyFlow);
currentFlow = finishFlowLabel(preFinallyLabel);
bind(node.finallyBlock);
// if flow after finally is unreachable - keep it
@@ -1061,6 +1089,11 @@ namespace ts {
: unreachableFlow;
}
}
if (!(currentFlow.flags & FlowFlags.Unreachable)) {
const afterFinallyFlow: AfterFinallyFlow = { flags: FlowFlags.AfterFinally, antecedent: currentFlow };
preFinallyFlow.lock = afterFinallyFlow;
currentFlow = afterFinallyFlow;
}
}
else {
currentFlow = finishFlowLabel(preFinallyLabel);
+371 -170
View File
File diff suppressed because it is too large Load Diff
+14 -4
View File
@@ -459,6 +459,16 @@ namespace ts {
name: "alwaysStrict",
type: "boolean",
description: Diagnostics.Parse_in_strict_mode_and_emit_use_strict_for_each_source_file
},
{
// A list of plugins to load in the language service
name: "plugins",
type: "list",
isTSConfigOnly: true,
element: {
name: "plugin",
type: "object"
}
}
];
@@ -840,7 +850,7 @@ namespace ts {
* @param basePath A root directory to resolve relative path entries in the config
* file to. e.g. outDir
*/
export function parseJsonConfigFileContent(json: any, host: ParseConfigHost, basePath: string, existingOptions: CompilerOptions = {}, configFileName?: string, resolutionStack: Path[] = [], extraFileExtensions: FileExtensionInfo[] = []): ParsedCommandLine {
export function parseJsonConfigFileContent(json: any, host: ParseConfigHost, basePath: string, existingOptions: CompilerOptions = {}, configFileName?: string, resolutionStack: Path[] = [], extraFileExtensions: JsFileExtensionInfo[] = []): ParsedCommandLine {
const errors: Diagnostic[] = [];
basePath = normalizeSlashes(basePath);
const getCanonicalFileName = createGetCanonicalFileName(host.useCaseSensitiveFileNames);
@@ -1186,7 +1196,7 @@ namespace ts {
* @param host The host used to resolve files and directories.
* @param errors An array for diagnostic reporting.
*/
function matchFileNames(fileNames: string[], include: string[], exclude: string[], basePath: string, options: CompilerOptions, host: ParseConfigHost, errors: Diagnostic[], extraFileExtensions: FileExtensionInfo[]): ExpandResult {
function matchFileNames(fileNames: string[], include: string[], exclude: string[], basePath: string, options: CompilerOptions, host: ParseConfigHost, errors: Diagnostic[], extraFileExtensions: JsFileExtensionInfo[]): ExpandResult {
basePath = normalizePath(basePath);
// The exclude spec list is converted into a regular expression, which allows us to quickly
@@ -1361,7 +1371,7 @@ namespace ts {
*/
function hasFileWithHigherPriorityExtension(file: string, literalFiles: Map<string>, wildcardFiles: Map<string>, extensions: string[], keyMapper: (value: string) => string) {
const extensionPriority = getExtensionPriority(file, extensions);
const adjustedExtensionPriority = adjustExtensionPriority(extensionPriority);
const adjustedExtensionPriority = adjustExtensionPriority(extensionPriority, extensions);
for (let i = ExtensionPriority.Highest; i < adjustedExtensionPriority; i++) {
const higherPriorityExtension = extensions[i];
const higherPriorityPath = keyMapper(changeExtension(file, higherPriorityExtension));
@@ -1383,7 +1393,7 @@ namespace ts {
*/
function removeWildcardFilesWithLowerPriorityExtension(file: string, wildcardFiles: Map<string>, extensions: string[], keyMapper: (value: string) => string) {
const extensionPriority = getExtensionPriority(file, extensions);
const nextExtensionPriority = getNextLowestExtensionPriority(extensionPriority);
const nextExtensionPriority = getNextLowestExtensionPriority(extensionPriority, extensions);
for (let i = nextExtensionPriority; i < extensions.length; i++) {
const lowerPriorityExtension = extensions[i];
const lowerPriorityPath = keyMapper(changeExtension(file, lowerPriorityExtension));
+36 -22
View File
@@ -5,17 +5,17 @@ namespace ts {
export interface CommentWriter {
reset(): void;
setSourceFile(sourceFile: SourceFile): void;
emitNodeWithComments(emitContext: EmitContext, node: Node, emitCallback: (emitContext: EmitContext, node: Node) => void): void;
setWriter(writer: EmitTextWriter): void;
emitNodeWithComments(hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void): void;
emitBodyWithDetachedComments(node: Node, detachedRange: TextRange, emitCallback: (node: Node) => void): void;
emitTrailingCommentsOfPosition(pos: number): void;
emitLeadingCommentsOfPosition(pos: number): void;
}
export function createCommentWriter(host: EmitHost, writer: EmitTextWriter, sourceMap: SourceMapWriter): CommentWriter {
const compilerOptions = host.getCompilerOptions();
const extendedDiagnostics = compilerOptions.extendedDiagnostics;
const newLine = host.getNewLine();
const { emitPos } = sourceMap;
export function createCommentWriter(printerOptions: PrinterOptions, emitPos: ((pos: number) => void) | undefined): CommentWriter {
const extendedDiagnostics = printerOptions.extendedDiagnostics;
const newLine = getNewLineCharacter(printerOptions);
let writer: EmitTextWriter;
let containerPos = -1;
let containerEnd = -1;
let declarationListContainerEnd = -1;
@@ -24,19 +24,21 @@ namespace ts {
let currentLineMap: number[];
let detachedCommentsInfo: { nodePos: number, detachedCommentEndPos: number}[];
let hasWrittenComment = false;
let disabled: boolean = compilerOptions.removeComments;
let disabled: boolean = printerOptions.removeComments;
return {
reset,
setWriter,
setSourceFile,
emitNodeWithComments,
emitBodyWithDetachedComments,
emitTrailingCommentsOfPosition,
emitLeadingCommentsOfPosition,
};
function emitNodeWithComments(emitContext: EmitContext, node: Node, emitCallback: (emitContext: EmitContext, node: Node) => void) {
function emitNodeWithComments(hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void) {
if (disabled) {
emitCallback(emitContext, node);
emitCallback(hint, node);
return;
}
@@ -47,11 +49,11 @@ namespace ts {
// Both pos and end are synthesized, so just emit the node without comments.
if (emitFlags & EmitFlags.NoNestedComments) {
disabled = true;
emitCallback(emitContext, node);
emitCallback(hint, node);
disabled = false;
}
else {
emitCallback(emitContext, node);
emitCallback(hint, node);
}
}
else {
@@ -94,11 +96,11 @@ namespace ts {
if (emitFlags & EmitFlags.NoNestedComments) {
disabled = true;
emitCallback(emitContext, node);
emitCallback(hint, node);
disabled = false;
}
else {
emitCallback(emitContext, node);
emitCallback(hint, node);
}
if (extendedDiagnostics) {
@@ -198,9 +200,9 @@ namespace ts {
}
// Leading comments are emitted at /*leading comment1 */space/*leading comment*/space
emitPos(commentPos);
if (emitPos) emitPos(commentPos);
writeCommentRange(currentText, currentLineMap, writer, commentPos, commentEnd, newLine);
emitPos(commentEnd);
if (emitPos) emitPos(commentEnd);
if (hasTrailingNewLine) {
writer.writeLine();
@@ -210,6 +212,14 @@ namespace ts {
}
}
function emitLeadingCommentsOfPosition(pos: number) {
if (disabled || pos === -1) {
return;
}
emitLeadingComments(pos, /*isEmittedNode*/ true);
}
function emitTrailingComments(pos: number) {
forEachTrailingCommentToEmit(pos, emitTrailingComment);
}
@@ -220,9 +230,9 @@ namespace ts {
writer.write(" ");
}
emitPos(commentPos);
if (emitPos) emitPos(commentPos);
writeCommentRange(currentText, currentLineMap, writer, commentPos, commentEnd, newLine);
emitPos(commentEnd);
if (emitPos) emitPos(commentEnd);
if (hasTrailingNewLine) {
writer.writeLine();
@@ -248,9 +258,9 @@ namespace ts {
function emitTrailingCommentOfPosition(commentPos: number, commentEnd: number, _kind: SyntaxKind, hasTrailingNewLine: boolean) {
// trailing comments of a position are emitted at /*trailing comment1 */space/*trailing comment*/space
emitPos(commentPos);
if (emitPos) emitPos(commentPos);
writeCommentRange(currentText, currentLineMap, writer, commentPos, commentEnd, newLine);
emitPos(commentEnd);
if (emitPos) emitPos(commentEnd);
if (hasTrailingNewLine) {
writer.writeLine();
@@ -286,6 +296,10 @@ namespace ts {
detachedCommentsInfo = undefined;
}
function setWriter(output: EmitTextWriter): void {
writer = output;
}
function setSourceFile(sourceFile: SourceFile) {
currentSourceFile = sourceFile;
currentText = currentSourceFile.text;
@@ -323,9 +337,9 @@ namespace ts {
}
function writeComment(text: string, lineMap: number[], writer: EmitTextWriter, commentPos: number, commentEnd: number, newLine: string) {
emitPos(commentPos);
if (emitPos) emitPos(commentPos);
writeCommentRange(text, lineMap, writer, commentPos, commentEnd, newLine);
emitPos(commentEnd);
if (emitPos) emitPos(commentEnd);
}
/**
+22 -16
View File
@@ -3,7 +3,7 @@
namespace ts {
/** The version of the TypeScript compiler release */
export const version = "2.2.0";
export const version = "2.3.0";
}
/* @internal */
@@ -895,6 +895,14 @@ namespace ts {
return result;
}
export function convertToArray<T, U>(iterator: Iterator<T>, f: (value: T) => U) {
const result: U[] = [];
for (let { value, done } = iterator.next(); !done; { value, done } = iterator.next()) {
result.push(f(value));
}
return result;
}
/**
* Calls `callback` for each entry in the map, returning the first truthy result.
* Use `map.forEach` instead for normal iteration.
@@ -1447,7 +1455,7 @@ namespace ts {
return /^\.\.?($|[\\/])/.test(moduleName);
}
export function getEmitScriptTarget(compilerOptions: CompilerOptions) {
export function getEmitScriptTarget(compilerOptions: CompilerOptions | PrinterOptions) {
return compilerOptions.target || ScriptTarget.ES3;
}
@@ -2012,14 +2020,14 @@ namespace ts {
export const supportedJavascriptExtensions = [".js", ".jsx"];
const allSupportedExtensions = supportedTypeScriptExtensions.concat(supportedJavascriptExtensions);
export function getSupportedExtensions(options?: CompilerOptions, extraFileExtensions?: FileExtensionInfo[]): string[] {
export function getSupportedExtensions(options?: CompilerOptions, extraFileExtensions?: JsFileExtensionInfo[]): string[] {
const needAllExtensions = options && options.allowJs;
if (!extraFileExtensions || extraFileExtensions.length === 0) {
if (!extraFileExtensions || extraFileExtensions.length === 0 || !needAllExtensions) {
return needAllExtensions ? allSupportedExtensions : supportedTypeScriptExtensions;
}
const extensions = (needAllExtensions ? allSupportedExtensions : supportedTypeScriptExtensions).slice(0);
const extensions = allSupportedExtensions.slice(0);
for (const extInfo of extraFileExtensions) {
if (needAllExtensions || extInfo.scriptKind === ScriptKind.TS) {
if (extensions.indexOf(extInfo.extension) === -1) {
extensions.push(extInfo.extension);
}
}
@@ -2034,7 +2042,7 @@ namespace ts {
return forEach(supportedTypeScriptExtensions, extension => fileExtensionIs(fileName, extension));
}
export function isSupportedSourceFileName(fileName: string, compilerOptions?: CompilerOptions, extraFileExtensions?: FileExtensionInfo[]) {
export function isSupportedSourceFileName(fileName: string, compilerOptions?: CompilerOptions, extraFileExtensions?: JsFileExtensionInfo[]) {
if (!fileName) { return false; }
for (const extension of getSupportedExtensions(compilerOptions, extraFileExtensions)) {
@@ -2053,7 +2061,6 @@ namespace ts {
export const enum ExtensionPriority {
TypeScriptFiles = 0,
DeclarationAndJavaScriptFiles = 2,
Limit = 5,
Highest = TypeScriptFiles,
Lowest = DeclarationAndJavaScriptFiles,
@@ -2062,7 +2069,7 @@ namespace ts {
export function getExtensionPriority(path: string, supportedExtensions: string[]): ExtensionPriority {
for (let i = supportedExtensions.length - 1; i >= 0; i--) {
if (fileExtensionIs(path, supportedExtensions[i])) {
return adjustExtensionPriority(<ExtensionPriority>i);
return adjustExtensionPriority(<ExtensionPriority>i, supportedExtensions);
}
}
@@ -2074,27 +2081,26 @@ namespace ts {
/**
* Adjusts an extension priority to be the highest priority within the same range.
*/
export function adjustExtensionPriority(extensionPriority: ExtensionPriority): ExtensionPriority {
export function adjustExtensionPriority(extensionPriority: ExtensionPriority, supportedExtensions: string[]): ExtensionPriority {
if (extensionPriority < ExtensionPriority.DeclarationAndJavaScriptFiles) {
return ExtensionPriority.TypeScriptFiles;
}
else if (extensionPriority < ExtensionPriority.Limit) {
else if (extensionPriority < supportedExtensions.length) {
return ExtensionPriority.DeclarationAndJavaScriptFiles;
}
else {
return ExtensionPriority.Limit;
}
}
return supportedExtensions.length;
} }
/**
* Gets the next lowest extension priority for a given priority.
*/
export function getNextLowestExtensionPriority(extensionPriority: ExtensionPriority): ExtensionPriority {
export function getNextLowestExtensionPriority(extensionPriority: ExtensionPriority, supportedExtensions: string[]): ExtensionPriority {
if (extensionPriority < ExtensionPriority.DeclarationAndJavaScriptFiles) {
return ExtensionPriority.DeclarationAndJavaScriptFiles;
}
else {
return ExtensionPriority.Limit;
return supportedExtensions.length;
}
}
+19 -8
View File
@@ -35,13 +35,15 @@ namespace ts {
forEachEmittedFile(host, getDeclarationDiagnosticsFromFile, targetSourceFile);
return declarationDiagnostics.getDiagnostics(targetSourceFile ? targetSourceFile.fileName : undefined);
function getDeclarationDiagnosticsFromFile({ declarationFilePath }: EmitFileNames, sources: SourceFile[], isBundledEmit: boolean) {
emitDeclarations(host, resolver, declarationDiagnostics, declarationFilePath, sources, isBundledEmit, /*emitOnlyDtsFiles*/ false);
function getDeclarationDiagnosticsFromFile({ declarationFilePath }: EmitFileNames, sourceFileOrBundle: SourceFile | Bundle) {
emitDeclarations(host, resolver, declarationDiagnostics, declarationFilePath, sourceFileOrBundle, /*emitOnlyDtsFiles*/ false);
}
}
function emitDeclarations(host: EmitHost, resolver: EmitResolver, emitterDiagnostics: DiagnosticCollection, declarationFilePath: string,
sourceFiles: SourceFile[], isBundledEmit: boolean, emitOnlyDtsFiles: boolean): DeclarationEmit {
sourceFileOrBundle: SourceFile | Bundle, emitOnlyDtsFiles: boolean): DeclarationEmit {
const sourceFiles = sourceFileOrBundle.kind === SyntaxKind.Bundle ? sourceFileOrBundle.sourceFiles : [sourceFileOrBundle];
const isBundledEmit = sourceFileOrBundle.kind === SyntaxKind.Bundle;
const newLine = host.getNewLine();
const compilerOptions = host.getCompilerOptions();
@@ -322,13 +324,20 @@ namespace ts {
function writeTypeOfDeclaration(declaration: AccessorDeclaration | VariableLikeDeclaration, type: TypeNode, getSymbolAccessibilityDiagnostic: GetSymbolAccessibilityDiagnostic) {
writer.getSymbolAccessibilityDiagnostic = getSymbolAccessibilityDiagnostic;
write(": ");
if (type) {
// use the checker's type, not the declared type,
// for non-optional initialized parameters that aren't a parameter property
const shouldUseResolverType = declaration.kind === SyntaxKind.Parameter &&
resolver.isRequiredInitializedParameter(declaration as ParameterDeclaration);
if (type && !shouldUseResolverType) {
// Write the type
emitType(type);
}
else {
errorNameNode = declaration.name;
resolver.writeTypeOfDeclaration(declaration, enclosingDeclaration, TypeFormatFlags.UseTypeOfFunction | TypeFormatFlags.UseTypeAliasValue, writer);
const format = TypeFormatFlags.UseTypeOfFunction | TypeFormatFlags.UseTypeAliasValue |
(shouldUseResolverType ? TypeFormatFlags.AddUndefined : 0);
resolver.writeTypeOfDeclaration(declaration, enclosingDeclaration, format, writer);
errorNameNode = undefined;
}
}
@@ -1803,8 +1812,9 @@ namespace ts {
}
return addedBundledEmitReference;
function getDeclFileName(emitFileNames: EmitFileNames, _sourceFiles: SourceFile[], isBundledEmit: boolean) {
function getDeclFileName(emitFileNames: EmitFileNames, sourceFileOrBundle: SourceFile | Bundle) {
// Dont add reference path to this file if it is a bundled emit and caller asked not emit bundled file path
const isBundledEmit = sourceFileOrBundle.kind === SyntaxKind.Bundle;
if (isBundledEmit && !addBundledFileReference) {
return;
}
@@ -1817,10 +1827,11 @@ namespace ts {
}
/* @internal */
export function writeDeclarationFile(declarationFilePath: string, sourceFiles: SourceFile[], isBundledEmit: boolean, host: EmitHost, resolver: EmitResolver, emitterDiagnostics: DiagnosticCollection, emitOnlyDtsFiles: boolean) {
const emitDeclarationResult = emitDeclarations(host, resolver, emitterDiagnostics, declarationFilePath, sourceFiles, isBundledEmit, emitOnlyDtsFiles);
export function writeDeclarationFile(declarationFilePath: string, sourceFileOrBundle: SourceFile | Bundle, host: EmitHost, resolver: EmitResolver, emitterDiagnostics: DiagnosticCollection, emitOnlyDtsFiles: boolean) {
const emitDeclarationResult = emitDeclarations(host, resolver, emitterDiagnostics, declarationFilePath, sourceFileOrBundle, emitOnlyDtsFiles);
const emitSkipped = emitDeclarationResult.reportedDeclarationError || host.isEmitBlocked(declarationFilePath) || host.getCompilerOptions().noEmit;
if (!emitSkipped) {
const sourceFiles = sourceFileOrBundle.kind === SyntaxKind.Bundle ? sourceFileOrBundle.sourceFiles : [sourceFileOrBundle];
const declarationOutput = emitDeclarationResult.referencesOutput
+ getDeclarationOutput(emitDeclarationResult.synchronousDeclarationOutput, emitDeclarationResult.moduleElementDeclarationEmitInfo);
writeFile(host, emitterDiagnostics, declarationFilePath, declarationOutput, host.getCompilerOptions().emitBOM, sourceFiles);
+13 -5
View File
@@ -671,6 +671,10 @@
"category": "Error",
"code": 1215
},
"Identifier expected. '__esModule' is reserved as an exported marker when transforming ECMAScript modules.": {
"category": "Error",
"code": 1216
},
"Export assignment is not supported when '--module' flag is 'system'.": {
"category": "Error",
"code": 1218
@@ -1787,6 +1791,10 @@
"category": "Error",
"code": 2545
},
"Property '{0}' has conflicting declarations and is inaccessible in type '{1}'.": {
"category": "Error",
"code": 2546
},
"JSX element attributes type '{0}' may not be a union type.": {
"category": "Error",
"code": 2600
@@ -2047,6 +2055,10 @@
"category": "Error",
"code": 2704
},
"An async function or method in ES5/ES3 requires the 'Promise' constructor. Make sure you have a declaration for the 'Promise' constructor or include 'ES2015' in your `--lib` option.": {
"category": "Error",
"code": 2705
},
"Import declaration '{0}' is using private name '{1}'.": {
"category": "Error",
@@ -2801,7 +2813,7 @@
"category": "Message",
"code": 6099
},
"'package.json' does not have a 'types' or 'main' field.": {
"'package.json' does not have a '{0}' field.": {
"category": "Message",
"code": 6100
},
@@ -2949,10 +2961,6 @@
"category": "Message",
"code": 6136
},
"No types specified in 'package.json', so returning 'main' value of '{0}'": {
"category": "Message",
"code": 6137
},
"Property '{0}' is declared but never used.": {
"category": "Error",
"code": 6138
+553 -459
View File
File diff suppressed because it is too large Load Diff
+1291 -1084
View File
File diff suppressed because it is too large Load Diff
+71 -68
View File
@@ -67,40 +67,31 @@ namespace ts {
}
/** Reads from "main" or "types"/"typings" depending on `extensions`. */
function tryReadPackageJsonMainOrTypes(extensions: Extensions, packageJsonPath: string, baseDirectory: string, state: ModuleResolutionState): string {
function tryReadPackageJsonFields(readTypes: boolean, packageJsonPath: string, baseDirectory: string, state: ModuleResolutionState): string | undefined {
const jsonContent = readJson(packageJsonPath, state.host);
return readTypes ? tryReadFromField("typings") || tryReadFromField("types") : tryReadFromField("main");
switch (extensions) {
case Extensions.DtsOnly:
case Extensions.TypeScript:
return tryReadFromField("typings") || tryReadFromField("types");
case Extensions.JavaScript:
if (typeof jsonContent.main === "string") {
if (state.traceEnabled) {
trace(state.host, Diagnostics.No_types_specified_in_package_json_so_returning_main_value_of_0, jsonContent.main);
}
return normalizePath(combinePaths(baseDirectory, jsonContent.main));
}
return undefined;
}
function tryReadFromField(fieldName: string) {
if (hasProperty(jsonContent, fieldName)) {
const typesFile = (<any>jsonContent)[fieldName];
if (typeof typesFile === "string") {
const typesFilePath = normalizePath(combinePaths(baseDirectory, typesFile));
if (state.traceEnabled) {
trace(state.host, Diagnostics.package_json_has_0_field_1_that_references_2, fieldName, typesFile, typesFilePath);
}
return typesFilePath;
}
else {
if (state.traceEnabled) {
trace(state.host, Diagnostics.Expected_type_of_0_field_in_package_json_to_be_string_got_1, fieldName, typeof typesFile);
}
function tryReadFromField(fieldName: "typings" | "types" | "main"): string | undefined {
if (!hasProperty(jsonContent, fieldName)) {
if (state.traceEnabled) {
trace(state.host, Diagnostics.package_json_does_not_have_a_0_field, fieldName);
}
return;
}
const fileName = jsonContent[fieldName];
if (typeof fileName !== "string") {
if (state.traceEnabled) {
trace(state.host, Diagnostics.Expected_type_of_0_field_in_package_json_to_be_string_got_1, fieldName, typeof fileName);
}
return;
}
const path = normalizePath(combinePaths(baseDirectory, fileName));
if (state.traceEnabled) {
trace(state.host, Diagnostics.package_json_has_0_field_1_that_references_2, fieldName, fileName, path);
}
return path;
}
}
@@ -684,13 +675,18 @@ namespace ts {
}
export function nodeModuleNameResolver(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, cache?: ModuleResolutionCache): ResolvedModuleWithFailedLookupLocations {
return nodeModuleNameResolverWorker(moduleName, containingFile, compilerOptions, host, cache, /* jsOnly*/ false);
}
/* @internal */
export function nodeModuleNameResolverWorker(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, cache?: ModuleResolutionCache, jsOnly = false): ResolvedModuleWithFailedLookupLocations {
const containingDirectory = getDirectoryPath(containingFile);
const traceEnabled = isTraceEnabled(compilerOptions, host);
const failedLookupLocations: string[] = [];
const state: ModuleResolutionState = { compilerOptions, host, traceEnabled };
const result = tryResolve(Extensions.TypeScript) || tryResolve(Extensions.JavaScript);
const result = jsOnly ? tryResolve(Extensions.JavaScript) : (tryResolve(Extensions.TypeScript) || tryResolve(Extensions.JavaScript));
if (result && result.value) {
const { resolved, isExternalLibraryImport } = result.value;
return createResolvedModuleWithFailedLookupLocations(resolved, isExternalLibraryImport, failedLookupLocations);
@@ -698,7 +694,8 @@ namespace ts {
return { resolvedModule: undefined, failedLookupLocations };
function tryResolve(extensions: Extensions): SearchResult<{ resolved: Resolved, isExternalLibraryImport: boolean }> {
const resolved = tryLoadModuleUsingOptionalResolutionSettings(extensions, moduleName, containingDirectory, nodeLoadModuleByRelativeName, failedLookupLocations, state);
const loader: ResolutionKindSpecificLoader = (extensions, candidate, failedLookupLocations, onlyRecordFailures, state) => nodeLoadModuleByRelativeName(extensions, candidate, failedLookupLocations, onlyRecordFailures, state, /*considerPackageJson*/true);
const resolved = tryLoadModuleUsingOptionalResolutionSettings(extensions, moduleName, containingDirectory, loader, failedLookupLocations, state);
if (resolved) {
return toSearchResult({ resolved, isExternalLibraryImport: false });
}
@@ -713,7 +710,7 @@ namespace ts {
}
else {
const candidate = normalizePath(combinePaths(containingDirectory, moduleName));
const resolved = nodeLoadModuleByRelativeName(extensions, candidate, failedLookupLocations, /*onlyRecordFailures*/ false, state);
const resolved = nodeLoadModuleByRelativeName(extensions, candidate, failedLookupLocations, /*onlyRecordFailures*/ false, state, /*considerPackageJson*/true);
return resolved && toSearchResult({ resolved, isExternalLibraryImport: false });
}
}
@@ -731,7 +728,7 @@ namespace ts {
return real;
}
function nodeLoadModuleByRelativeName(extensions: Extensions, candidate: string, failedLookupLocations: Push<string>, onlyRecordFailures: boolean, state: ModuleResolutionState): Resolved | undefined {
function nodeLoadModuleByRelativeName(extensions: Extensions, candidate: string, failedLookupLocations: Push<string>, onlyRecordFailures: boolean, state: ModuleResolutionState, considerPackageJson: boolean): Resolved | undefined {
if (state.traceEnabled) {
trace(state.host, Diagnostics.Loading_module_as_file_Slash_folder_candidate_module_location_0_target_file_type_1, candidate, Extensions[extensions]);
}
@@ -759,7 +756,7 @@ namespace ts {
onlyRecordFailures = true;
}
}
return loadNodeModuleFromDirectory(extensions, candidate, failedLookupLocations, onlyRecordFailures, state);
return loadNodeModuleFromDirectory(extensions, candidate, failedLookupLocations, onlyRecordFailures, state, considerPackageJson);
}
/* @internal */
@@ -835,50 +832,57 @@ namespace ts {
return undefined;
}
function loadNodeModuleFromDirectory(extensions: Extensions, candidate: string, failedLookupLocations: Push<string>, onlyRecordFailures: boolean, state: ModuleResolutionState): Resolved | undefined {
const packageJsonPath = pathToPackageJson(candidate);
function loadNodeModuleFromDirectory(extensions: Extensions, candidate: string, failedLookupLocations: Push<string>, onlyRecordFailures: boolean, state: ModuleResolutionState, considerPackageJson = true): Resolved | undefined {
const directoryExists = !onlyRecordFailures && directoryProbablyExists(candidate, state.host);
if (directoryExists && state.host.fileExists(packageJsonPath)) {
if (state.traceEnabled) {
trace(state.host, Diagnostics.Found_package_json_at_0, packageJsonPath);
}
const mainOrTypesFile = tryReadPackageJsonMainOrTypes(extensions, packageJsonPath, candidate, state);
if (mainOrTypesFile) {
const onlyRecordFailures = !directoryProbablyExists(getDirectoryPath(mainOrTypesFile), state.host);
// A package.json "typings" may specify an exact filename, or may choose to omit an extension.
const fromExactFile = tryFile(mainOrTypesFile, failedLookupLocations, onlyRecordFailures, state);
if (fromExactFile) {
const resolved = fromExactFile && resolvedIfExtensionMatches(extensions, fromExactFile);
if (resolved) {
return resolved;
}
if (state.traceEnabled) {
trace(state.host, Diagnostics.File_0_has_an_unsupported_extension_so_skipping_it, fromExactFile);
}
}
const resolved = tryAddingExtensions(mainOrTypesFile, Extensions.TypeScript, failedLookupLocations, onlyRecordFailures, state);
if (resolved) {
return resolved;
if (considerPackageJson) {
const packageJsonPath = pathToPackageJson(candidate);
if (directoryExists && state.host.fileExists(packageJsonPath)) {
const fromPackageJson = loadModuleFromPackageJson(packageJsonPath, extensions, candidate, failedLookupLocations, state);
if (fromPackageJson) {
return fromPackageJson;
}
}
else {
if (state.traceEnabled) {
trace(state.host, Diagnostics.package_json_does_not_have_a_types_or_main_field);
if (directoryExists && state.traceEnabled) {
trace(state.host, Diagnostics.File_0_does_not_exist, packageJsonPath);
}
// record package json as one of failed lookup locations - in the future if this file will appear it will invalidate resolution results
failedLookupLocations.push(packageJsonPath);
}
}
else {
if (directoryExists && state.traceEnabled) {
trace(state.host, Diagnostics.File_0_does_not_exist, packageJsonPath);
}
// record package json as one of failed lookup locations - in the future if this file will appear it will invalidate resolution results
failedLookupLocations.push(packageJsonPath);
}
return loadModuleFromFile(extensions, combinePaths(candidate, "index"), failedLookupLocations, !directoryExists, state);
}
function loadModuleFromPackageJson(packageJsonPath: string, extensions: Extensions, candidate: string, failedLookupLocations: Push<string>, state: ModuleResolutionState): Resolved | undefined {
if (state.traceEnabled) {
trace(state.host, Diagnostics.Found_package_json_at_0, packageJsonPath);
}
const file = tryReadPackageJsonFields(extensions !== Extensions.JavaScript, packageJsonPath, candidate, state);
if (!file) {
return undefined;
}
const onlyRecordFailures = !directoryProbablyExists(getDirectoryPath(file), state.host);
const fromFile = tryFile(file, failedLookupLocations, onlyRecordFailures, state);
if (fromFile) {
const resolved = fromFile && resolvedIfExtensionMatches(extensions, fromFile);
if (resolved) {
return resolved;
}
if (state.traceEnabled) {
trace(state.host, Diagnostics.File_0_has_an_unsupported_extension_so_skipping_it, fromFile);
}
}
// Even if extensions is DtsOnly, we can still look up a .ts file as a result of package.json "types"
const nextExtensions = extensions === Extensions.DtsOnly ? Extensions.TypeScript : extensions;
// Don't do package.json lookup recursively, because Node.js' package lookup doesn't.
return nodeLoadModuleByRelativeName(nextExtensions, file, failedLookupLocations, onlyRecordFailures, state, /*considerPackageJson*/ false);
}
/** Resolve from an arbitrarily specified file. Return `undefined` if it has an unsupported extension. */
function resolvedIfExtensionMatches(extensions: Extensions, path: string): Resolved | undefined {
const extension = tryGetExtensionFromPath(path);
@@ -1040,7 +1044,6 @@ namespace ts {
return value !== undefined ? { value } : undefined;
}
/** Calls `callback` on `directory` and every ancestor directory it has, returning the first defined result. */
function forEachAncestorDirectory<T>(directory: string, callback: (directory: string) => SearchResult<T>): SearchResult<T> {
while (true) {
+3 -6
View File
@@ -1152,13 +1152,10 @@ namespace ts {
&& (options.isolatedModules || isExternalModuleFile)
&& !file.isDeclarationFile) {
// synthesize 'import "tslib"' declaration
const externalHelpersModuleReference = <StringLiteral>createSynthesizedNode(SyntaxKind.StringLiteral);
externalHelpersModuleReference.text = externalHelpersModuleNameText;
const importDecl = createSynthesizedNode(SyntaxKind.ImportDeclaration);
importDecl.parent = file;
const externalHelpersModuleReference = createLiteral(externalHelpersModuleNameText);
const importDecl = createImportDeclaration(undefined, undefined, undefined);
externalHelpersModuleReference.parent = importDecl;
importDecl.parent = file;
imports = [externalHelpersModuleReference];
}
+13 -15
View File
@@ -8,10 +8,9 @@ namespace ts {
*
* @param filePath The path to the generated output file.
* @param sourceMapFilePath The path to the output source map file.
* @param sourceFiles The input source files for the program.
* @param isBundledEmit A value indicating whether the generated output file is a bundle.
* @param sourceFileOrBundle The input source file or bundle for the program.
*/
initialize(filePath: string, sourceMapFilePath: string, sourceFiles: SourceFile[], isBundledEmit: boolean): void;
initialize(filePath: string, sourceMapFilePath: string, sourceFileOrBundle: SourceFile | Bundle): void;
/**
* Reset the SourceMapWriter to an empty state.
@@ -38,11 +37,11 @@ namespace ts {
/**
* Emits a node with possible leading and trailing source maps.
*
* @param emitContext The current emit context
* @param hint The current emit context
* @param node The node to emit.
* @param emitCallback The callback used to emit the node.
*/
emitNodeWithSourceMap(emitContext: EmitContext, node: Node, emitCallback: (emitContext: EmitContext, node: Node) => void): void;
emitNodeWithSourceMap(hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void): void;
/**
* Emits a token of a node node with possible leading and trailing source maps.
@@ -115,10 +114,9 @@ namespace ts {
*
* @param filePath The path to the generated output file.
* @param sourceMapFilePath The path to the output source map file.
* @param sourceFiles The input source files for the program.
* @param isBundledEmit A value indicating whether the generated output file is a bundle.
* @param sourceFileOrBundle The input source file or bundle for the program.
*/
function initialize(filePath: string, sourceMapFilePath: string, sourceFiles: SourceFile[], isBundledEmit: boolean) {
function initialize(filePath: string, sourceMapFilePath: string, sourceFileOrBundle: SourceFile | Bundle) {
if (disabled) {
return;
}
@@ -161,11 +159,10 @@ namespace ts {
if (compilerOptions.mapRoot) {
sourceMapDir = normalizeSlashes(compilerOptions.mapRoot);
if (!isBundledEmit) { // emitting single module file
Debug.assert(sourceFiles.length === 1);
if (sourceFileOrBundle.kind === SyntaxKind.SourceFile) { // emitting single module file
// For modules or multiple emit files the mapRoot will have directory structure like the sources
// So if src\a.ts and src\lib\b.ts are compiled together user would be moving the maps into mapRoot\a.js.map and mapRoot\lib\b.js.map
sourceMapDir = getDirectoryPath(getSourceFilePathInNewDir(sourceFiles[0], host, sourceMapDir));
sourceMapDir = getDirectoryPath(getSourceFilePathInNewDir(sourceFileOrBundle, host, sourceMapDir));
}
if (!isRootedDiskPath(sourceMapDir) && !isUrl(sourceMapDir)) {
@@ -311,12 +308,13 @@ namespace ts {
/**
* Emits a node with possible leading and trailing source maps.
*
* @param hint A hint as to the intended usage of the node.
* @param node The node to emit.
* @param emitCallback The callback used to emit the node.
*/
function emitNodeWithSourceMap(emitContext: EmitContext, node: Node, emitCallback: (emitContext: EmitContext, node: Node) => void) {
function emitNodeWithSourceMap(hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void) {
if (disabled) {
return emitCallback(emitContext, node);
return emitCallback(hint, node);
}
if (node) {
@@ -332,11 +330,11 @@ namespace ts {
if (emitFlags & EmitFlags.NoNestedSourceMaps) {
disabled = true;
emitCallback(emitContext, node);
emitCallback(hint, node);
disabled = false;
}
else {
emitCallback(emitContext, node);
emitCallback(hint, node);
}
if (node.kind !== SyntaxKind.NotEmittedStatement
+8 -1
View File
@@ -485,7 +485,10 @@ namespace ts {
// Node 4.0 `fs.watch` function supports the "recursive" option on both OSX and Windows
// (ref: https://github.com/nodejs/node/pull/2649 and https://github.com/Microsoft/TypeScript/issues/4643)
let options: any;
if (!directoryExists(directoryName)) {
if (!directoryExists(directoryName) || (isUNCPath(directoryName) && process.platform === "win32")) {
// do nothing if either
// - target folder does not exist
// - this is UNC path on Windows (https://github.com/Microsoft/TypeScript/issues/13874)
return noOpFileWatcher;
}
@@ -509,6 +512,10 @@ namespace ts {
};
}
);
function isUNCPath(s: string): boolean {
return s.length > 2 && s.charCodeAt(0) === CharacterCodes.slash && s.charCodeAt(1) === CharacterCodes.slash;
}
},
resolvePath: function(path: string): string {
return _path.resolve(path);
+15 -15
View File
@@ -105,14 +105,16 @@ namespace ts {
hoistFunctionDeclaration,
requestEmitHelper,
readEmitHelpers,
onSubstituteNode: (_emitContext, node) => node,
onSubstituteNode: (_, node) => node,
enableSubstitution,
isSubstitutionEnabled,
onEmitNode: (node, emitContext, emitCallback) => emitCallback(node, emitContext),
onEmitNode: (hint, node, callback) => callback(hint, node),
enableEmitNotification,
isEmitNotificationEnabled
};
performance.mark("beforeTransform");
// Chain together and initialize each transformer.
const transformation = chain(...transformers)(context);
@@ -122,6 +124,9 @@ namespace ts {
// Disable modification of the lexical environment.
lexicalEnvironmentDisabled = true;
performance.mark("afterTransform");
performance.measure("transformTime", "beforeTransform", "afterTransform");
return {
transformed,
emitNodeWithSubstitution,
@@ -159,21 +164,16 @@ namespace ts {
/**
* Emits a node with possible substitution.
*
* @param emitContext The current emit context.
* @param hint A hint as to the intended usage of the node.
* @param node The node to emit.
* @param emitCallback The callback used to emit the node or its substitute.
*/
function emitNodeWithSubstitution(emitContext: EmitContext, node: Node, emitCallback: (emitContext: EmitContext, node: Node) => void) {
function emitNodeWithSubstitution(hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void) {
if (node) {
if (isSubstitutionEnabled(node)) {
const substitute = context.onSubstituteNode(emitContext, node);
if (substitute && substitute !== node) {
emitCallback(emitContext, substitute);
return;
}
node = context.onSubstituteNode(hint, node) || node;
}
emitCallback(emitContext, node);
emitCallback(hint, node);
}
}
@@ -196,17 +196,17 @@ namespace ts {
/**
* Emits a node with possible emit notification.
*
* @param emitContext The current emit context.
* @param hint A hint as to the intended usage of the node.
* @param node The node to emit.
* @param emitCallback The callback used to emit the node.
*/
function emitNodeWithNotification(emitContext: EmitContext, node: Node, emitCallback: (emitContext: EmitContext, node: Node) => void) {
function emitNodeWithNotification(hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void) {
if (node) {
if (isEmitNotificationEnabled(node)) {
context.onEmitNode(emitContext, node, emitCallback);
context.onEmitNode(hint, node, emitCallback);
}
else {
emitCallback(emitContext, node);
emitCallback(hint, node);
}
}
}
+18 -5
View File
@@ -112,7 +112,10 @@ namespace ts {
Debug.assertNode(target, createAssignmentCallback ? isIdentifier : isExpression);
const expression = createAssignmentCallback
? createAssignmentCallback(<Identifier>target, value, location)
: createAssignment(visitNode(<Expression>target, visitor, isExpression), value, location);
: setTextRange(
createAssignment(visitNode(<Expression>target, visitor, isExpression), value),
location
);
expression.original = original;
emitExpression(expression);
}
@@ -174,9 +177,10 @@ namespace ts {
const variable = createVariableDeclaration(
name,
/*type*/ undefined,
pendingExpressions ? inlineExpressions(append(pendingExpressions, value)) : value,
location);
pendingExpressions ? inlineExpressions(append(pendingExpressions, value)) : value
);
variable.original = original;
setTextRange(variable, location);
if (isIdentifier(name)) {
setEmitFlags(variable, EmitFlags.NoNestedSourceMaps);
}
@@ -416,7 +420,7 @@ namespace ts {
const temp = createTempVariable(/*recordTempVariable*/ undefined);
if (flattenContext.hoistTempVariables) {
flattenContext.context.hoistVariableDeclaration(temp);
flattenContext.emitExpression(createAssignment(temp, value, location));
flattenContext.emitExpression(setTextRange(createAssignment(temp, value), location));
}
else {
flattenContext.emitBindingOrAssignment(temp, value, location, /*original*/ undefined);
@@ -492,6 +496,15 @@ namespace ts {
}
}
}
return createCall(getHelperName("__rest"), undefined, [value, createArrayLiteral(propertyNames, location)]);
return createCall(
getHelperName("__rest"),
undefined,
[
value,
setTextRange(
createArrayLiteral(propertyNames),
location
)
]);
}
}
+211 -172
View File
@@ -514,7 +514,7 @@ namespace ts {
exitSubtree(ancestorFacts, HierarchyFacts.None, HierarchyFacts.None);
return updateSourceFileNode(
node,
createNodeArray(statements, node.statements)
setTextRange(createNodeArray(statements), node.statements)
);
}
@@ -671,9 +671,10 @@ namespace ts {
setOriginalNode(variable, node);
const statements: Statement[] = [];
const statement = createVariableStatement(/*modifiers*/ undefined, createVariableDeclarationList([variable]), /*location*/ node);
const statement = createVariableStatement(/*modifiers*/ undefined, createVariableDeclarationList([variable]));
setOriginalNode(statement, node);
setTextRange(statement, node);
startOnNewLine(statement);
statements.push(statement);
@@ -818,7 +819,7 @@ namespace ts {
addRange(statements, endLexicalEnvironment());
const block = createBlock(createNodeArray(statements, /*location*/ node.members), /*location*/ undefined, /*multiLine*/ true);
const block = createBlock(setTextRange(createNodeArray(statements), /*location*/ node.members), /*multiLine*/ true);
setEmitFlags(block, EmitFlags.NoComments);
return block;
}
@@ -833,8 +834,10 @@ namespace ts {
function addExtendsHelperIfNeeded(statements: Statement[], node: ClassExpression | ClassDeclaration, extendsClauseElement: ExpressionWithTypeArguments): void {
if (extendsClauseElement) {
statements.push(
createStatement(
createExtendsHelper(context, getLocalName(node)),
setTextRange(
createStatement(
createExtendsHelper(context, getLocalName(node))
),
/*location*/ extendsClauseElement
)
);
@@ -854,19 +857,18 @@ namespace ts {
const ancestorFacts = enterSubtree(HierarchyFacts.ConstructorExcludes, HierarchyFacts.ConstructorIncludes);
const constructor = getFirstConstructorWithBody(node);
const hasSynthesizedSuper = hasSynthesizedDefaultSuperCall(constructor, extendsClauseElement !== undefined);
const constructorFunction =
createFunctionDeclaration(
/*decorators*/ undefined,
/*modifiers*/ undefined,
/*asteriskToken*/ undefined,
getDeclarationName(node),
/*typeParameters*/ undefined,
transformConstructorParameters(constructor, hasSynthesizedSuper),
/*type*/ undefined,
transformConstructorBody(constructor, node, extendsClauseElement, hasSynthesizedSuper),
/*location*/ constructor || node
);
const constructorFunction = createFunctionDeclaration(
/*decorators*/ undefined,
/*modifiers*/ undefined,
/*asteriskToken*/ undefined,
getDeclarationName(node),
/*typeParameters*/ undefined,
transformConstructorParameters(constructor, hasSynthesizedSuper),
/*type*/ undefined,
transformConstructorBody(constructor, node, extendsClauseElement, hasSynthesizedSuper)
);
setTextRange(constructorFunction, constructor || node);
if (extendsClauseElement) {
setEmitFlags(constructorFunction, EmitFlags.CapturesThis);
}
@@ -962,14 +964,16 @@ namespace ts {
}
const block = createBlock(
createNodeArray(
statements,
setTextRange(
createNodeArray(
statements
),
/*location*/ constructor ? constructor.body.statements : node.members
),
/*location*/ constructor ? constructor.body : node,
/*multiLine*/ true
);
setTextRange(block, constructor ? constructor.body : node);
if (!constructor) {
setEmitFlags(block, EmitFlags.NoComments);
}
@@ -1139,14 +1143,16 @@ namespace ts {
// Binding patterns are converted into a generated name and are
// evaluated inside the function body.
return setOriginalNode(
createParameter(
/*decorators*/ undefined,
/*modifiers*/ undefined,
/*dotDotDotToken*/ undefined,
getGeneratedNameForNode(node),
/*questionToken*/ undefined,
/*type*/ undefined,
/*initializer*/ undefined,
setTextRange(
createParameter(
/*decorators*/ undefined,
/*modifiers*/ undefined,
/*dotDotDotToken*/ undefined,
getGeneratedNameForNode(node),
/*questionToken*/ undefined,
/*type*/ undefined,
/*initializer*/ undefined
),
/*location*/ node
),
/*original*/ node
@@ -1155,14 +1161,16 @@ namespace ts {
else if (node.initializer) {
// Initializers are elided
return setOriginalNode(
createParameter(
/*decorators*/ undefined,
/*modifiers*/ undefined,
/*dotDotDotToken*/ undefined,
node.name,
/*questionToken*/ undefined,
/*type*/ undefined,
/*initializer*/ undefined,
setTextRange(
createParameter(
/*decorators*/ undefined,
/*modifiers*/ undefined,
/*dotDotDotToken*/ undefined,
node.name,
/*questionToken*/ undefined,
/*type*/ undefined,
/*initializer*/ undefined
),
/*location*/ node
),
/*original*/ node
@@ -1274,21 +1282,25 @@ namespace ts {
const statement = createIf(
createTypeCheck(getSynthesizedClone(name), "undefined"),
setEmitFlags(
createBlock([
createStatement(
createAssignment(
setEmitFlags(getMutableClone(name), EmitFlags.NoSourceMap),
setEmitFlags(initializer, EmitFlags.NoSourceMap | getEmitFlags(initializer)),
/*location*/ parameter
setTextRange(
createBlock([
createStatement(
setTextRange(
createAssignment(
setEmitFlags(getMutableClone(name), EmitFlags.NoSourceMap),
setEmitFlags(initializer, EmitFlags.NoSourceMap | getEmitFlags(initializer))
),
parameter
)
)
)
], /*location*/ parameter),
]),
parameter
),
EmitFlags.SingleLine | EmitFlags.NoTrailingSourceMap | EmitFlags.NoTokenSourceMaps
),
/*elseStatement*/ undefined,
/*location*/ parameter
)
);
statement.startsOnNewLine = true;
setTextRange(statement, parameter);
setEmitFlags(statement, EmitFlags.NoTokenSourceMaps | EmitFlags.NoTrailingSourceMap | EmitFlags.CustomPrologue);
statements.push(statement);
}
@@ -1332,15 +1344,17 @@ namespace ts {
// var param = [];
statements.push(
setEmitFlags(
createVariableStatement(
/*modifiers*/ undefined,
createVariableDeclarationList([
createVariableDeclaration(
declarationName,
/*type*/ undefined,
createArrayLiteral([])
)
]),
setTextRange(
createVariableStatement(
/*modifiers*/ undefined,
createVariableDeclarationList([
createVariableDeclaration(
declarationName,
/*type*/ undefined,
createArrayLiteral([])
)
])
),
/*location*/ parameter
),
EmitFlags.CustomPrologue
@@ -1351,26 +1365,33 @@ namespace ts {
// param[_i - restIndex] = arguments[_i];
// }
const forStatement = createFor(
createVariableDeclarationList([
createVariableDeclaration(temp, /*type*/ undefined, createLiteral(restIndex))
], /*location*/ parameter),
createLessThan(
temp,
createPropertyAccess(createIdentifier("arguments"), "length"),
/*location*/ parameter
setTextRange(
createVariableDeclarationList([
createVariableDeclaration(temp, /*type*/ undefined, createLiteral(restIndex))
]),
parameter
),
createPostfixIncrement(temp, /*location*/ parameter),
setTextRange(
createLessThan(
temp,
createPropertyAccess(createIdentifier("arguments"), "length")
),
parameter
),
setTextRange(createPostfixIncrement(temp), parameter),
createBlock([
startOnNewLine(
createStatement(
createAssignment(
createElementAccess(
expressionName,
restIndex === 0
? temp
: createSubtract(temp, createLiteral(restIndex))
),
createElementAccess(createIdentifier("arguments"), temp)
setTextRange(
createStatement(
createAssignment(
createElementAccess(
expressionName,
restIndex === 0
? temp
: createSubtract(temp, createLiteral(restIndex))
),
createElementAccess(createIdentifier("arguments"), temp)
)
),
/*location*/ parameter
)
@@ -1405,11 +1426,10 @@ namespace ts {
/*type*/ undefined,
initializer
)
]),
originalStatement
])
);
setEmitFlags(captureThisStatement, EmitFlags.NoComments | EmitFlags.CustomPrologue);
setTextRange(captureThisStatement, originalStatement);
setSourceMapRange(captureThisStatement, node);
statements.push(captureThisStatement);
}
@@ -1529,7 +1549,7 @@ namespace ts {
* @param member The SemicolonClassElement node.
*/
function transformSemicolonClassElementToStatement(member: SemicolonClassElement) {
return createEmptyStatement(/*location*/ member);
return setTextRange(createEmptyStatement(), member);
}
/**
@@ -1547,8 +1567,10 @@ namespace ts {
setEmitFlags(memberFunction, EmitFlags.NoComments);
setSourceMapRange(memberFunction, sourceMapRange);
const statement = createStatement(
createAssignment(memberName, memberFunction),
const statement = setTextRange(
createStatement(
createAssignment(memberName, memberFunction)
),
/*location*/ member
);
@@ -1571,15 +1593,12 @@ namespace ts {
* @param accessors The set of related get/set accessors.
*/
function transformAccessorsToStatement(receiver: LeftHandSideExpression, accessors: AllAccessorDeclarations, container: Node): Statement {
const statement = createStatement(
transformAccessorsToExpression(receiver, accessors, container, /*startsOnNewLine*/ false),
/*location*/ getSourceMapRange(accessors.firstAccessor)
);
const statement = createStatement(transformAccessorsToExpression(receiver, accessors, container, /*startsOnNewLine*/ false));
// The location for the statement is used to emit source maps only.
// No comments should be emitted for this statement to align with the
// old emitter.
setEmitFlags(statement, EmitFlags.NoComments);
setSourceMapRange(statement, getSourceMapRange(accessors.firstAccessor));
return statement;
}
@@ -1622,8 +1641,8 @@ namespace ts {
}
properties.push(
createPropertyAssignment("enumerable", createLiteral(true)),
createPropertyAssignment("configurable", createLiteral(true))
createPropertyAssignment("enumerable", createTrue()),
createPropertyAssignment("configurable", createTrue())
);
const call = createCall(
@@ -1632,7 +1651,7 @@ namespace ts {
[
target,
propertyName,
createObjectLiteral(properties, /*location*/ undefined, /*multiLine*/ true)
createObjectLiteral(properties, /*multiLine*/ true)
]
);
if (startsOnNewLine) {
@@ -1662,9 +1681,9 @@ namespace ts {
/*typeParameters*/ undefined,
visitParameterList(node.parameters, visitor, context),
/*type*/ undefined,
transformFunctionBody(node),
node
transformFunctionBody(node)
);
setTextRange(func, node);
setOriginalNode(func, node);
setEmitFlags(func, EmitFlags.CapturesThis);
exitSubtree(ancestorFacts, HierarchyFacts.None, HierarchyFacts.None);
@@ -1758,14 +1777,16 @@ namespace ts {
exitSubtree(ancestorFacts, HierarchyFacts.PropagateNewTargetMask, HierarchyFacts.None);
convertedLoopState = savedConvertedLoopState;
return setOriginalNode(
createFunctionExpression(
/*modifiers*/ undefined,
node.asteriskToken,
name,
/*typeParameters*/ undefined,
parameters,
/*type*/ undefined,
body,
setTextRange(
createFunctionExpression(
/*modifiers*/ undefined,
node.asteriskToken,
name,
/*typeParameters*/ undefined,
parameters,
/*type*/ undefined,
body
),
location
),
/*original*/ node
@@ -1832,7 +1853,8 @@ namespace ts {
}
const expression = visitNode(body, visitor, isExpression);
const returnStatement = createReturn(expression, /*location*/ body);
const returnStatement = createReturn(expression);
setTextRange(returnStatement, body);
setEmitFlags(returnStatement, EmitFlags.NoTokenSourceMaps | EmitFlags.NoTrailingSourceMap | EmitFlags.NoTrailingComments);
statements.push(returnStatement);
@@ -1851,7 +1873,8 @@ namespace ts {
multiLine = true;
}
const block = createBlock(createNodeArray(statements, statementsLocation), node.body, multiLine);
const block = createBlock(setTextRange(createNodeArray(statements), statementsLocation), multiLine);
setTextRange(block, node.body);
if (!multiLine && singleLine) {
setEmitFlags(block, EmitFlags.SingleLine);
}
@@ -1868,8 +1891,10 @@ namespace ts {
const updated = visitFunctionBody(node.body, functionBodyVisitor, context);
return updateBlock(
updated,
createNodeArray(
prependCaptureNewTargetIfNeeded(updated.statements, node, /*copyOnWrite*/ true),
setTextRange(
createNodeArray(
prependCaptureNewTargetIfNeeded(updated.statements, node, /*copyOnWrite*/ true)
),
/*location*/ updated.statements
)
);
@@ -1969,7 +1994,7 @@ namespace ts {
}
}
if (assignments) {
updated = createStatement(reduceLeft(assignments, (acc, v) => createBinary(v, SyntaxKind.CommaToken, acc)), node);
updated = setTextRange(createStatement(reduceLeft(assignments, (acc, v) => createBinary(v, SyntaxKind.CommaToken, acc))), node);
}
else {
// none of declarations has initializer - the entire variable statement can be deleted
@@ -1999,8 +2024,9 @@ namespace ts {
? visitVariableDeclarationInLetDeclarationList
: visitVariableDeclaration));
const declarationList = createVariableDeclarationList(declarations, /*location*/ node);
const declarationList = createVariableDeclarationList(declarations);
setOriginalNode(declarationList, node);
setTextRange(declarationList, node);
setCommentRange(declarationList, node);
if (node.transformFlags & TransformFlags.ContainsBindingPattern
@@ -2225,7 +2251,7 @@ namespace ts {
// we don't want to emit a temporary variable for the RHS, just use it directly.
const counter = createLoopVariable();
const rhsReference = expression.kind === SyntaxKind.Identifier
? createUniqueName((<Identifier>expression).text)
? createUniqueName(unescapeIdentifier((<Identifier>expression).text))
: createTempVariable(/*recordTempVariable*/ undefined);
const elementAccess = createElementAccess(rhsReference, counter);
@@ -2248,8 +2274,9 @@ namespace ts {
elementAccess
);
const declarationList = createVariableDeclarationList(declarations, /*location*/ initializer);
const declarationList = createVariableDeclarationList(declarations);
setOriginalNode(declarationList, initializer);
setTextRange(declarationList, initializer);
// Adjust the source map range for the first declaration to align with the old
// emitter.
@@ -2268,19 +2295,24 @@ namespace ts {
// The following call does not include the initializer, so we have
// to emit it separately.
statements.push(
createVariableStatement(
/*modifiers*/ undefined,
setOriginalNode(
createVariableDeclarationList([
createVariableDeclaration(
firstOriginalDeclaration ? firstOriginalDeclaration.name : createTempVariable(/*recordTempVariable*/ undefined),
/*type*/ undefined,
createElementAccess(rhsReference, counter)
)
], /*location*/ moveRangePos(initializer, -1)),
initializer
setTextRange(
createVariableStatement(
/*modifiers*/ undefined,
setOriginalNode(
setTextRange(
createVariableDeclarationList([
createVariableDeclaration(
firstOriginalDeclaration ? firstOriginalDeclaration.name : createTempVariable(/*recordTempVariable*/ undefined),
/*type*/ undefined,
createElementAccess(rhsReference, counter)
)
]),
moveRangePos(initializer, -1)
),
initializer
)
),
/*location*/ moveRangeEnd(initializer, -1)
moveRangeEnd(initializer, -1)
)
);
}
@@ -2306,7 +2338,7 @@ namespace ts {
// Currently there is not way to check that assignment is binary expression of destructing assignment
// so we have to cast never type to binaryExpression
(<BinaryExpression>assignment).end = initializer.end;
statements.push(createStatement(assignment, /*location*/ moveRangeEnd(initializer, -1)));
statements.push(setTextRange(createStatement(assignment), moveRangeEnd(initializer, -1)));
}
}
@@ -2332,33 +2364,38 @@ namespace ts {
// The old emitter does not emit source maps for the block.
// We add the location to preserve comments.
const body = createBlock(
createNodeArray(statements, /*location*/ statementsLocation),
/*location*/ bodyLocation
);
const body = createBlock(setTextRange(createNodeArray(statements), /*location*/ statementsLocation));
setTextRange(body, bodyLocation);
setEmitFlags(body, EmitFlags.NoSourceMap | EmitFlags.NoTokenSourceMaps);
const forStatement = createFor(
setEmitFlags(
createVariableDeclarationList([
createVariableDeclaration(counter, /*type*/ undefined, createLiteral(0), /*location*/ moveRangePos(node.expression, -1)),
createVariableDeclaration(rhsReference, /*type*/ undefined, expression, /*location*/ node.expression)
], /*location*/ node.expression),
setTextRange(
createVariableDeclarationList([
setTextRange(createVariableDeclaration(counter, /*type*/ undefined, createLiteral(0)), moveRangePos(node.expression, -1)),
setTextRange(createVariableDeclaration(rhsReference, /*type*/ undefined, expression), node.expression)
]),
node.expression
),
EmitFlags.NoHoisting
),
createLessThan(
counter,
createPropertyAccess(rhsReference, "length"),
/*location*/ node.expression
setTextRange(
createLessThan(
counter,
createPropertyAccess(rhsReference, "length")
),
node.expression
),
createPostfixIncrement(counter, /*location*/ node.expression),
body,
/*location*/ node
setTextRange(
createPostfixIncrement(counter),
node.expression
),
body
);
// Disable trailing source maps for the OpenParenToken to align source map emit with the old emitter.
setEmitFlags(forStatement, EmitFlags.NoTokenTrailingSourceMaps);
setTextRange(forStatement, node);
return restoreEnclosingLabel(forStatement, outermostLabeledStatement, convertedLoopState && resetLabel);
}
@@ -2418,7 +2455,6 @@ namespace ts {
setEmitFlags(
createObjectLiteral(
visitNodes(properties, visitor, isObjectLiteralElementLike, 0, numInitialProperties),
/*location*/ undefined,
node.multiLine
),
EmitFlags.Indented
@@ -2546,14 +2582,14 @@ namespace ts {
copyOutParameters(loopOutParameters, CopyDirection.ToOutParameter, statements);
}
addRange(statements, lexicalEnvironment)
loopBody = createBlock(statements, /*location*/ undefined, /*multiline*/ true);
loopBody = createBlock(statements, /*multiline*/ true);
}
if (isBlock(loopBody)) {
loopBody.multiLine = true;
}
else {
loopBody = createBlock([loopBody], /*location*/ undefined, /*multiline*/ true);
loopBody = createBlock([loopBody], /*multiline*/ true);
}
const isAsyncBlockContainingAwait =
@@ -2687,12 +2723,7 @@ namespace ts {
// visit childnodes to transform initializer/condition/incrementor parts
clone = visitEachChild(clone, visitor, context);
// set loop statement
clone.statement = createBlock(
convertedLoopBodyStatements,
/*location*/ undefined,
/*multiline*/ true
);
clone.statement = createBlock(convertedLoopBodyStatements, /*multiline*/ true);
// reset and re-aggregate the transform flags
clone.transformFlags = 0;
aggregateTransformFlags(clone);
@@ -2841,7 +2872,7 @@ namespace ts {
else {
loopParameters.push(createParameter(/*decorators*/ undefined, /*modifiers*/ undefined, /*dotDotDotToken*/ undefined, name));
if (resolver.getNodeCheckFlags(decl) & NodeCheckFlags.NeedsLoopOutParameter) {
const outParamName = createUniqueName("out_" + name.text);
const outParamName = createUniqueName("out_" + unescapeIdentifier(name.text));
loopOutParameters.push({ originalName: name, outParamName });
}
}
@@ -2903,9 +2934,9 @@ namespace ts {
receiver,
visitNode(property.name, visitor, isPropertyName)
),
visitNode(property.initializer, visitor, isExpression),
/*location*/ property
visitNode(property.initializer, visitor, isExpression)
);
setTextRange(expression, property);
if (startsOnNewLine) {
expression.startsOnNewLine = true;
}
@@ -2925,9 +2956,9 @@ namespace ts {
receiver,
visitNode(property.name, visitor, isPropertyName)
),
getSynthesizedClone(property.name),
/*location*/ property
getSynthesizedClone(property.name)
);
setTextRange(expression, property);
if (startsOnNewLine) {
expression.startsOnNewLine = true;
}
@@ -2948,9 +2979,9 @@ namespace ts {
receiver,
visitNode(method.name, visitor, isPropertyName)
),
transformFunctionLikeToExpression(method, /*location*/ method, /*name*/ undefined, container),
/*location*/ method
transformFunctionLikeToExpression(method, /*location*/ method, /*name*/ undefined, container)
);
setTextRange(expression, method);
if (startsOnNewLine) {
expression.startsOnNewLine = true;
}
@@ -2963,7 +2994,8 @@ namespace ts {
let updated: CatchClause;
if (isBindingPattern(node.variableDeclaration.name)) {
const temp = createTempVariable(undefined);
const newVariableDeclaration = createVariableDeclaration(temp, undefined, undefined, node.variableDeclaration);
const newVariableDeclaration = createVariableDeclaration(temp);
setTextRange(newVariableDeclaration, node.variableDeclaration);
const vars = flattenDestructuringBinding(
node.variableDeclaration,
visitor,
@@ -2971,8 +3003,9 @@ namespace ts {
FlattenLevel.All,
temp
);
const list = createVariableDeclarationList(vars, /*location*/node.variableDeclaration, /*flags*/node.variableDeclaration.flags);
const destructure = createVariableStatement(undefined, list);
const list = createVariableDeclarationList(vars);
setTextRange(list, node.variableDeclaration);
const destructure = createVariableStatement(/*modifiers*/ undefined, list);
updated = updateCatchClause(node, newVariableDeclaration, addStatementToStartOfBlock(node.block, destructure));
}
else {
@@ -3001,9 +3034,11 @@ namespace ts {
Debug.assert(!isComputedPropertyName(node.name));
const functionExpression = transformFunctionLikeToExpression(node, /*location*/ moveRangePos(node, -1), /*name*/ undefined, /*container*/ undefined);
setEmitFlags(functionExpression, EmitFlags.NoLeadingComments | getEmitFlags(functionExpression));
return createPropertyAssignment(
node.name,
functionExpression,
return setTextRange(
createPropertyAssignment(
node.name,
functionExpression
),
/*location*/ node
);
}
@@ -3030,9 +3065,11 @@ namespace ts {
* @param node A ShorthandPropertyAssignment node.
*/
function visitShorthandPropertyAssignment(node: ShorthandPropertyAssignment): ObjectLiteralElementLike {
return createPropertyAssignment(
node.name,
getSynthesizedClone(node.name),
return setTextRange(
createPropertyAssignment(
node.name,
getSynthesizedClone(node.name)
),
/*location*/ node
);
}
@@ -3225,8 +3262,7 @@ namespace ts {
function visitSpanOfNonSpreads(chunk: Expression[], multiLine: boolean, hasTrailingComma: boolean): VisitResult<Expression> {
return createArrayLiteral(
visitNodes(createNodeArray(chunk, /*location*/ undefined, hasTrailingComma), visitor, isExpression),
/*location*/ undefined,
visitNodes(createNodeArray(chunk, hasTrailingComma), visitor, isExpression),
multiLine
);
}
@@ -3250,7 +3286,7 @@ namespace ts {
* @param node A template literal.
*/
function visitTemplateLiteral(node: LiteralExpression): LeftHandSideExpression {
return createLiteral(node.text, /*location*/ node);
return setTextRange(createLiteral(node.text), node);
}
/**
@@ -3318,7 +3354,7 @@ namespace ts {
// ES6 Spec 11.8.6.1 - Static Semantics of TV's and TRV's
// <CR><LF> and <CR> LineTerminatorSequences are normalized to <LF> for both TV and TRV.
text = text.replace(/\r\n?/g, "\n");
return createLiteral(text, /*location*/ node);
return setTextRange(createLiteral(text), node);
}
/**
@@ -3342,7 +3378,8 @@ namespace ts {
// "abc" + (1 << 2) + ""
const expression = reduceLeft(expressions, createAdd);
if (nodeIsSynthesized(expression)) {
setTextRange(expression, node);
expression.pos = node.pos;
expression.end = node.end;
}
return expression;
@@ -3435,9 +3472,11 @@ namespace ts {
/**
* Called by the printer just before a node is printed.
*
* @param hint A hint as to the intended usage of the node.
* @param node The node to be printed.
* @param emitCallback The callback used to emit the node.
*/
function onEmitNode(emitContext: EmitContext, node: Node, emitCallback: (emitContext: EmitContext, node: Node) => void) {
function onEmitNode(hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void) {
if (enabledSubstitutions & ES2015SubstitutionFlags.CapturedThis && isFunctionLike(node)) {
// If we are tracking a captured `this`, keep track of the enclosing function.
const ancestorFacts = enterSubtree(
@@ -3445,11 +3484,11 @@ namespace ts {
getEmitFlags(node) & EmitFlags.CapturesThis
? HierarchyFacts.FunctionIncludes | HierarchyFacts.CapturesThis
: HierarchyFacts.FunctionIncludes);
previousOnEmitNode(emitContext, node, emitCallback);
previousOnEmitNode(hint, node, emitCallback);
exitSubtree(ancestorFacts, HierarchyFacts.None, HierarchyFacts.None);
return;
}
previousOnEmitNode(emitContext, node, emitCallback);
previousOnEmitNode(hint, node, emitCallback);
}
/**
@@ -3484,13 +3523,13 @@ namespace ts {
/**
* Hooks node substitutions.
*
* @param emitContext The context for the emitter.
* @param hint The context for the emitter.
* @param node The node to substitute.
*/
function onSubstituteNode(emitContext: EmitContext, node: Node) {
node = previousOnSubstituteNode(emitContext, node);
function onSubstituteNode(hint: EmitHint, node: Node) {
node = previousOnSubstituteNode(hint, node);
if (emitContext === EmitContext.Expression) {
if (hint === EmitHint.Expression) {
return substituteExpression(node);
}
@@ -3578,7 +3617,7 @@ namespace ts {
function substituteThisKeyword(node: PrimaryExpression): PrimaryExpression {
if (enabledSubstitutions & ES2015SubstitutionFlags.CapturedThis
&& hierarchyFacts & HierarchyFacts.CapturesThis) {
return createIdentifier("_this", /*location*/ node);
return setTextRange(createIdentifier("_this"), node);
}
return node;
}
+31 -17
View File
@@ -48,29 +48,37 @@ namespace ts {
// Transforms `a[x] **= b` into `(_a = a)[_x = x] = Math.pow(_a[_x], b)`
const expressionTemp = createTempVariable(hoistVariableDeclaration);
const argumentExpressionTemp = createTempVariable(hoistVariableDeclaration);
target = createElementAccess(
createAssignment(expressionTemp, left.expression, /*location*/ left.expression),
createAssignment(argumentExpressionTemp, left.argumentExpression, /*location*/ left.argumentExpression),
/*location*/ left
target = setTextRange(
createElementAccess(
setTextRange(createAssignment(expressionTemp, left.expression), left.expression),
setTextRange(createAssignment(argumentExpressionTemp, left.argumentExpression), left.argumentExpression)
),
left
);
value = createElementAccess(
expressionTemp,
argumentExpressionTemp,
/*location*/ left
value = setTextRange(
createElementAccess(
expressionTemp,
argumentExpressionTemp
),
left
);
}
else if (isPropertyAccessExpression(left)) {
// Transforms `a.x **= b` into `(_a = a).x = Math.pow(_a.x, b)`
const expressionTemp = createTempVariable(hoistVariableDeclaration);
target = createPropertyAccess(
createAssignment(expressionTemp, left.expression, /*location*/ left.expression),
left.name,
/*location*/ left
target = setTextRange(
createPropertyAccess(
setTextRange(createAssignment(expressionTemp, left.expression), left.expression),
left.name
),
left
);
value = createPropertyAccess(
expressionTemp,
left.name,
/*location*/ left
value = setTextRange(
createPropertyAccess(
expressionTemp,
left.name
),
left
);
}
else {
@@ -78,7 +86,13 @@ namespace ts {
target = left;
value = left;
}
return createAssignment(target, createMathPow(value, right, /*location*/ node), /*location*/ node);
return setTextRange(
createAssignment(
target,
createMathPow(value, right, /*location*/ node)
),
node
);
}
function visitExponentiationExpression(node: BinaryExpression) {
+32 -25
View File
@@ -104,10 +104,12 @@ namespace ts {
*/
function visitAwaitExpression(node: AwaitExpression): Expression {
return setOriginalNode(
createYield(
/*asteriskToken*/ undefined,
visitNode(node.expression, visitor, isExpression),
/*location*/ node
setTextRange(
createYield(
/*asteriskToken*/ undefined,
visitNode(node.expression, visitor, isExpression)
),
node
),
node
);
@@ -238,7 +240,8 @@ namespace ts {
addRange(statements, endLexicalEnvironment());
const block = createBlock(statements, /*location*/ node.body, /*multiLine*/ true);
const block = createBlock(statements, /*multiLine*/ true);
setTextRange(block, node.body);
// Minor optimization, emit `_super` helper to capture `super` access in an arrow.
// This step isn't needed if we eventually transform this to ES5.
@@ -266,7 +269,7 @@ namespace ts {
const declarations = endLexicalEnvironment();
if (some(declarations)) {
const block = convertToFunctionBody(expression);
return updateBlock(block, createNodeArray(concatenate(block.statements, declarations), block.statements));
return updateBlock(block, setTextRange(createNodeArray(concatenate(block.statements, declarations)), block.statements));
}
return expression;
@@ -281,7 +284,7 @@ namespace ts {
startLexicalEnvironment();
const visited = convertToFunctionBody(visitNode(body, visitor, isConciseBody));
const declarations = endLexicalEnvironment();
return updateBlock(visited, createNodeArray(concatenate(visited.statements, declarations), visited.statements));
return updateBlock(visited, setTextRange(createNodeArray(concatenate(visited.statements, declarations)), visited.statements));
}
}
@@ -396,33 +399,33 @@ namespace ts {
/**
* Hook for node emit.
*
* @param hint A hint as to the intended usage of the node.
* @param node The node to emit.
* @param emit A callback used to emit the node in the printer.
*/
function onEmitNode(emitContext: EmitContext, node: Node, emitCallback: (emitContext: EmitContext, node: Node) => void): void {
function onEmitNode(hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void): void {
// If we need to support substitutions for `super` in an async method,
// we should track it here.
if (enabledSubstitutions & ES2017SubstitutionFlags.AsyncMethodsWithSuper && isSuperContainer(node)) {
const savedCurrentSuperContainer = currentSuperContainer;
currentSuperContainer = node;
previousOnEmitNode(emitContext, node, emitCallback);
previousOnEmitNode(hint, node, emitCallback);
currentSuperContainer = savedCurrentSuperContainer;
}
else {
previousOnEmitNode(emitContext, node, emitCallback);
previousOnEmitNode(hint, node, emitCallback);
}
}
/**
* Hooks node substitutions.
*
* @param hint A hint as to the intended usage of the node.
* @param node The node to substitute.
* @param isExpression A value indicating whether the node is to be used in an expression
* position.
*/
function onSubstituteNode(emitContext: EmitContext, node: Node) {
node = previousOnSubstituteNode(emitContext, node);
if (emitContext === EmitContext.Expression) {
function onSubstituteNode(hint: EmitHint, node: Node) {
node = previousOnSubstituteNode(hint, node);
if (hint === EmitHint.Expression) {
return substituteExpression(<Expression>node);
}
@@ -431,21 +434,25 @@ namespace ts {
function createSuperAccessInAsyncMethod(argumentExpression: Expression, flags: NodeCheckFlags, location: TextRange): LeftHandSideExpression {
if (flags & NodeCheckFlags.AsyncMethodWithSuperBinding) {
return createPropertyAccess(
return setTextRange(
createPropertyAccess(
createCall(
createIdentifier("_super"),
/*typeArguments*/ undefined,
[argumentExpression]
),
"value"
),
location
);
}
else {
return setTextRange(
createCall(
createIdentifier("_super"),
/*typeArguments*/ undefined,
[argumentExpression]
),
"value",
location
);
}
else {
return createCall(
createIdentifier("_super"),
/*typeArguments*/ undefined,
[argumentExpression],
location
);
}
+12 -10
View File
@@ -12,7 +12,7 @@ namespace ts {
const compilerOptions = context.getCompilerOptions();
// enable emit notification only if using --jsx preserve or react-native
let previousOnEmitNode: (emitContext: EmitContext, node: Node, emitCallback: (emitContext: EmitContext, node: Node) => void) => void;
let previousOnEmitNode: (hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void) => void;
let noSubstitution: boolean[];
if (compilerOptions.jsx === JsxEmit.Preserve || compilerOptions.jsx === JsxEmit.ReactNative) {
previousOnEmitNode = context.onEmitNode;
@@ -41,9 +41,11 @@ namespace ts {
/**
* Called by the printer just before a node is printed.
*
* @param node The node to be printed.
* @param hint A hint as to the intended usage of the node.
* @param node The node to emit.
* @param emitCallback A callback used to emit the node.
*/
function onEmitNode(emitContext: EmitContext, node: Node, emitCallback: (emitContext: EmitContext, node: Node) => void) {
function onEmitNode(hint: EmitHint, node: Node, emitCallback: (emitContext: EmitHint, node: Node) => void) {
switch (node.kind) {
case SyntaxKind.JsxOpeningElement:
case SyntaxKind.JsxClosingElement:
@@ -53,21 +55,21 @@ namespace ts {
break;
}
previousOnEmitNode(emitContext, node, emitCallback);
previousOnEmitNode(hint, node, emitCallback);
}
/**
* Hooks node substitutions.
*
* @param emitContext The context for the emitter.
* @param hint A hint as to the intended usage of the node.
* @param node The node to substitute.
*/
function onSubstituteNode(emitContext: EmitContext, node: Node) {
function onSubstituteNode(hint: EmitHint, node: Node) {
if (node.id && noSubstitution && noSubstitution[node.id]) {
return previousOnSubstituteNode(emitContext, node);
return previousOnSubstituteNode(hint, node);
}
node = previousOnSubstituteNode(emitContext, node);
node = previousOnSubstituteNode(hint, node);
if (isPropertyAccessExpression(node)) {
return substitutePropertyAccessExpression(node);
}
@@ -85,7 +87,7 @@ namespace ts {
function substitutePropertyAccessExpression(node: PropertyAccessExpression): Expression {
const literalName = trySubstituteReservedName(node.name);
if (literalName) {
return createElementAccess(node.expression, literalName, /*location*/ node);
return setTextRange(createElementAccess(node.expression, literalName), node);
}
return node;
}
@@ -111,7 +113,7 @@ namespace ts {
function trySubstituteReservedName(name: Identifier) {
const token = name.originalKeywordKind || (nodeIsSynthesized(name) ? stringToToken(name.text) : undefined);
if (token >= SyntaxKind.FirstReservedWord && token <= SyntaxKind.LastReservedWord) {
return createLiteral(name, /*location*/ name);
return setTextRange(createLiteral(name), name);
}
return undefined;
}
+16 -12
View File
@@ -210,36 +210,40 @@ namespace ts {
const statement = createVariableStatement(
/*modifiers*/ undefined,
updateVariableDeclarationList(initializer, declarations),
/*location*/ initializer
);
setTextRange(statement, initializer);
leadingStatements = append(leadingStatements, statement);
}
}
else if (isAssignmentPattern(initializer)) {
temp = createTempVariable(/*recordTempVariable*/ undefined);
const expression = flattenDestructuringAssignment(
aggregateTransformFlags(createAssignment(initializer, temp, /*location*/ node.initializer)),
aggregateTransformFlags(
setTextRange(
createAssignment(initializer, temp),
node.initializer
)
),
visitor,
context,
FlattenLevel.ObjectRest
);
leadingStatements = append(leadingStatements, createStatement(expression, /*location*/ node.initializer));
leadingStatements = append(leadingStatements, setTextRange(createStatement(expression), node.initializer));
}
}
if (temp) {
const expression = visitNode(node.expression, visitor, isExpression);
const statement = visitNode(node.statement, visitor, isStatement);
const block = isBlock(statement)
? updateBlock(statement, createNodeArray(concatenate(leadingStatements, statement.statements), statement.statements))
: createBlock(append(leadingStatements, statement), statement, /*multiLine*/ true);
? updateBlock(statement, setTextRange(createNodeArray(concatenate(leadingStatements, statement.statements)), statement.statements))
: setTextRange(createBlock(append(leadingStatements, statement), /*multiLine*/ true), statement);
return updateForOf(
node,
createVariableDeclarationList(
[
createVariableDeclaration(temp, /*type*/ undefined, /*initializer*/ undefined, node.initializer)
],
node.initializer,
NodeFlags.Let
setTextRange(
createVariableDeclarationList([
setTextRange(createVariableDeclaration(temp), node.initializer)
], NodeFlags.Let),
node.initializer
),
expression,
block
@@ -380,7 +384,7 @@ namespace ts {
const trailingStatements = endLexicalEnvironment();
if (some(leadingStatements) || some(trailingStatements)) {
const block = convertToFunctionBody(body, /*multiLine*/ true);
return updateBlock(block, createNodeArray(concatenate(concatenate(leadingStatements, block.statements), trailingStatements), block.statements));
return updateBlock(block, setTextRange(createNodeArray(concatenate(concatenate(leadingStatements, block.statements), trailingStatements)), block.statements));
}
return body;
}
+129 -93
View File
@@ -450,15 +450,17 @@ namespace ts {
// Currently, we only support generators that were originally async functions.
if (node.asteriskToken && getEmitFlags(node) & EmitFlags.AsyncFunctionBody) {
node = setOriginalNode(
createFunctionDeclaration(
/*decorators*/ undefined,
node.modifiers,
/*asteriskToken*/ undefined,
node.name,
/*typeParameters*/ undefined,
visitParameterList(node.parameters, visitor, context),
/*type*/ undefined,
transformGeneratorFunctionBody(node.body),
setTextRange(
createFunctionDeclaration(
/*decorators*/ undefined,
node.modifiers,
/*asteriskToken*/ undefined,
node.name,
/*typeParameters*/ undefined,
visitParameterList(node.parameters, visitor, context),
/*type*/ undefined,
transformGeneratorFunctionBody(node.body)
),
/*location*/ node
),
node
@@ -498,14 +500,16 @@ namespace ts {
// Currently, we only support generators that were originally async functions.
if (node.asteriskToken && getEmitFlags(node) & EmitFlags.AsyncFunctionBody) {
node = setOriginalNode(
createFunctionExpression(
/*modifiers*/ undefined,
/*asteriskToken*/ undefined,
node.name,
/*typeParameters*/ undefined,
visitParameterList(node.parameters, visitor, context),
/*type*/ undefined,
transformGeneratorFunctionBody(node.body),
setTextRange(
createFunctionExpression(
/*modifiers*/ undefined,
/*asteriskToken*/ undefined,
node.name,
/*typeParameters*/ undefined,
visitParameterList(node.parameters, visitor, context),
/*type*/ undefined,
transformGeneratorFunctionBody(node.body)
),
/*location*/ node
),
node
@@ -606,7 +610,7 @@ namespace ts {
operationLocations = savedOperationLocations;
state = savedState;
return createBlock(statements, /*location*/ body, body.multiLine);
return setTextRange(createBlock(statements, body.multiLine), body);
}
/**
@@ -739,14 +743,17 @@ namespace ts {
const operator = node.operatorToken.kind;
if (isCompoundAssignment(operator)) {
return createBinary(
target,
SyntaxKind.EqualsToken,
createBinary(
cacheExpression(target),
getOperatorForCompoundAssignment(operator),
visitNode(right, visitor, isExpression),
node
return setTextRange(
createAssignment(
target,
setTextRange(
createBinary(
cacheExpression(target),
getOperatorForCompoundAssignment(operator),
visitNode(right, visitor, isExpression)
),
node
)
),
node
);
@@ -988,8 +995,11 @@ namespace ts {
const expressions = reduceLeft(elements, reduceElement, <Expression[]>[], numInitialElements);
return hasAssignedTemp
? createArrayConcat(temp, [createArrayLiteral(expressions, /*location*/ undefined, multiLine)])
: createArrayLiteral(leadingElement ? [leadingElement, ...expressions] : expressions, location, multiLine);
? createArrayConcat(temp, [createArrayLiteral(expressions, multiLine)])
: setTextRange(
createArrayLiteral(leadingElement ? [leadingElement, ...expressions] : expressions, multiLine),
location
);
function reduceElement(expressions: Expression[], element: Expression) {
if (containsYield(element) && expressions.length > 0) {
@@ -998,11 +1008,10 @@ namespace ts {
hasAssignedTemp
? createArrayConcat(
temp,
[createArrayLiteral(expressions, /*location*/ undefined, multiLine)]
[createArrayLiteral(expressions, multiLine)]
)
: createArrayLiteral(
leadingElement ? [leadingElement, ...expressions] : expressions,
/*location*/ undefined,
multiLine
)
);
@@ -1043,7 +1052,6 @@ namespace ts {
emitAssignment(temp,
createObjectLiteral(
visitNodes(properties, visitor, isObjectLiteralElementLike, 0, numInitialProperties),
/*location*/ undefined,
multiLine
)
);
@@ -1139,18 +1147,20 @@ namespace ts {
const { target, thisArg } = createCallBinding(createPropertyAccess(node.expression, "bind"), hoistVariableDeclaration);
return setOriginalNode(
createNew(
createFunctionApply(
cacheExpression(visitNode(target, visitor, isExpression)),
thisArg,
visitElements(
node.arguments,
/*leadingElement*/ createVoidZero()
)
setTextRange(
createNew(
createFunctionApply(
cacheExpression(visitNode(target, visitor, isExpression)),
thisArg,
visitElements(
node.arguments,
/*leadingElement*/ createVoidZero()
)
),
/*typeArguments*/ undefined,
[]
),
/*typeArguments*/ undefined,
[],
/*location*/ node
node
),
node
);
@@ -1423,9 +1433,11 @@ namespace ts {
}
else {
emitStatement(
createStatement(
visitNode(initializer, visitor, isExpression),
/*location*/ initializer
setTextRange(
createStatement(
visitNode(initializer, visitor, isExpression)
),
initializer
)
);
}
@@ -1441,9 +1453,11 @@ namespace ts {
markLabel(incrementLabel);
if (node.incrementor) {
emitStatement(
createStatement(
visitNode(node.incrementor, visitor, isExpression),
/*location*/ node.incrementor
setTextRange(
createStatement(
visitNode(node.incrementor, visitor, isExpression)
),
node.incrementor
)
);
}
@@ -1909,9 +1923,9 @@ namespace ts {
return -1;
}
function onSubstituteNode(emitContext: EmitContext, node: Node): Node {
node = previousOnSubstituteNode(emitContext, node);
if (emitContext === EmitContext.Expression) {
function onSubstituteNode(hint: EmitHint, node: Node): Node {
node = previousOnSubstituteNode(hint, node);
if (hint === EmitHint.Expression) {
return substituteExpression(<Expression>node);
}
return node;
@@ -2417,11 +2431,13 @@ namespace ts {
*/
function createInlineBreak(label: Label, location?: TextRange): ReturnStatement {
Debug.assert(label > 0, `Invalid label: ${label}`);
return createReturn(
createArrayLiteral([
createInstruction(Instruction.Break),
createLabel(label)
]),
return setTextRange(
createReturn(
createArrayLiteral([
createInstruction(Instruction.Break),
createLabel(label)
])
),
location
);
}
@@ -2433,10 +2449,12 @@ namespace ts {
* @param location An optional source map location for the statement.
*/
function createInlineReturn(expression?: Expression, location?: TextRange): ReturnStatement {
return createReturn(
createArrayLiteral(expression
? [createInstruction(Instruction.Return), expression]
: [createInstruction(Instruction.Return)]
return setTextRange(
createReturn(
createArrayLiteral(expression
? [createInstruction(Instruction.Return), expression]
: [createInstruction(Instruction.Return)]
)
),
location
);
@@ -2446,7 +2464,14 @@ namespace ts {
* Creates an expression that can be used to resume from a Yield operation.
*/
function createGeneratorResume(location?: TextRange): LeftHandSideExpression {
return createCall(createPropertyAccess(state, "sent"), /*typeArguments*/ undefined, [], location);
return setTextRange(
createCall(
createPropertyAccess(state, "sent"),
/*typeArguments*/ undefined,
[]
),
location
);
}
/**
@@ -2614,7 +2639,6 @@ namespace ts {
/*type*/ undefined,
createBlock(
buildResult,
/*location*/ undefined,
/*multiLine*/ buildResult.length > 0
)
),
@@ -2944,7 +2968,7 @@ namespace ts {
* @param operationLocation The source map location for the operation.
*/
function writeAssign(left: Expression, right: Expression, operationLocation: TextRange): void {
writeStatement(createStatement(createAssignment(left, right), operationLocation));
writeStatement(setTextRange(createStatement(createAssignment(left, right)), operationLocation));
}
/**
@@ -2956,7 +2980,7 @@ namespace ts {
function writeThrow(expression: Expression, operationLocation: TextRange): void {
lastOperationWasAbrupt = true;
lastOperationWasCompletion = true;
writeStatement(createThrow(expression, operationLocation));
writeStatement(setTextRange(createThrow(expression), operationLocation));
}
/**
@@ -2970,10 +2994,12 @@ namespace ts {
lastOperationWasCompletion = true;
writeStatement(
setEmitFlags(
createReturn(
createArrayLiteral(expression
? [createInstruction(Instruction.Return), expression]
: [createInstruction(Instruction.Return)]
setTextRange(
createReturn(
createArrayLiteral(expression
? [createInstruction(Instruction.Return), expression]
: [createInstruction(Instruction.Return)]
)
),
operationLocation
),
@@ -2992,11 +3018,13 @@ namespace ts {
lastOperationWasAbrupt = true;
writeStatement(
setEmitFlags(
createReturn(
createArrayLiteral([
createInstruction(Instruction.Break),
createLabel(label)
]),
setTextRange(
createReturn(
createArrayLiteral([
createInstruction(Instruction.Break),
createLabel(label)
])
),
operationLocation
),
EmitFlags.NoTokenSourceMaps
@@ -3017,11 +3045,13 @@ namespace ts {
createIf(
condition,
setEmitFlags(
createReturn(
createArrayLiteral([
createInstruction(Instruction.Break),
createLabel(label)
]),
setTextRange(
createReturn(
createArrayLiteral([
createInstruction(Instruction.Break),
createLabel(label)
])
),
operationLocation
),
EmitFlags.NoTokenSourceMaps
@@ -3045,11 +3075,13 @@ namespace ts {
createIf(
createLogicalNot(condition),
setEmitFlags(
createReturn(
createArrayLiteral([
createInstruction(Instruction.Break),
createLabel(label)
]),
setTextRange(
createReturn(
createArrayLiteral([
createInstruction(Instruction.Break),
createLabel(label)
])
),
operationLocation
),
EmitFlags.NoTokenSourceMaps
@@ -3070,11 +3102,13 @@ namespace ts {
lastOperationWasAbrupt = true;
writeStatement(
setEmitFlags(
createReturn(
createArrayLiteral(
expression
? [createInstruction(Instruction.Yield), expression]
: [createInstruction(Instruction.Yield)]
setTextRange(
createReturn(
createArrayLiteral(
expression
? [createInstruction(Instruction.Yield), expression]
: [createInstruction(Instruction.Yield)]
)
),
operationLocation
),
@@ -3093,11 +3127,13 @@ namespace ts {
lastOperationWasAbrupt = true;
writeStatement(
setEmitFlags(
createReturn(
createArrayLiteral([
createInstruction(Instruction.YieldStar),
expression
]),
setTextRange(
createReturn(
createArrayLiteral([
createInstruction(Instruction.YieldStar),
expression
])
),
operationLocation
),
EmitFlags.NoTokenSourceMaps
+3 -3
View File
@@ -143,15 +143,15 @@ namespace ts {
function transformJsxAttributeInitializer(node: StringLiteral | JsxExpression) {
if (node === undefined) {
return createLiteral(true);
return createTrue();
}
else if (node.kind === SyntaxKind.StringLiteral) {
const decoded = tryDecodeEntities((<StringLiteral>node).text);
return decoded ? createLiteral(decoded, /*location*/ node) : node;
return decoded ? setTextRange(createLiteral(decoded), node) : node;
}
else if (node.kind === SyntaxKind.JsxExpression) {
if (node.expression === undefined) {
return createLiteral(true);
return createTrue();
}
return visitJsxExpression(<JsxExpression>node);
}
+9 -9
View File
@@ -37,7 +37,7 @@ namespace ts {
addRange(statements, visitNodes(node.statements, visitor, isStatement, statementOffset));
return updateSourceFileNode(
node,
createNodeArray(statements, node.statements));
setTextRange(createNodeArray(statements), node.statements));
}
else {
return visitEachChild(node, visitor, context);
@@ -71,18 +71,18 @@ namespace ts {
/**
* Hook for node emit.
*
* @param emitContext A context hint for the emitter.
* @param hint A hint as to the intended usage of the node.
* @param node The node to emit.
* @param emit A callback used to emit the node in the printer.
*/
function onEmitNode(emitContext: EmitContext, node: Node, emitCallback: (emitContext: EmitContext, node: Node) => void): void {
function onEmitNode(hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void): void {
if (isSourceFile(node)) {
currentSourceFile = node;
previousOnEmitNode(emitContext, node, emitCallback);
previousOnEmitNode(hint, node, emitCallback);
currentSourceFile = undefined;
}
else {
previousOnEmitNode(emitContext, node, emitCallback);
previousOnEmitNode(hint, node, emitCallback);
}
}
@@ -93,12 +93,12 @@ namespace ts {
/**
* Hooks node substitutions.
*
* @param emitContext A context hint for the emitter.
* @param hint A hint as to the intended usage of the node.
* @param node The node to substitute.
*/
function onSubstituteNode(emitContext: EmitContext, node: Node) {
node = previousOnSubstituteNode(emitContext, node);
if (isIdentifier(node) && emitContext === EmitContext.Expression) {
function onSubstituteNode(hint: EmitHint, node: Node) {
node = previousOnSubstituteNode(hint, node);
if (isIdentifier(node) && hint === EmitHint.Expression) {
return substituteExpressionIdentifier(node);
}
return node;
+286 -250
View File
@@ -83,16 +83,20 @@ namespace ts {
const statements: Statement[] = [];
const statementOffset = addPrologueDirectives(statements, node.statements, /*ensureUseStrict*/ !compilerOptions.noImplicitUseStrict, sourceElementVisitor);
if (!currentModuleInfo.exportEquals) {
append(statements, createUnderscoreUnderscoreESModule());
}
append(statements, visitNode(currentModuleInfo.externalHelpersImportDeclaration, sourceElementVisitor, isStatement, /*optional*/ true));
addRange(statements, visitNodes(node.statements, sourceElementVisitor, isStatement, statementOffset));
addRange(statements, endLexicalEnvironment());
addExportEqualsIfNeeded(statements, /*emitAsReturn*/ false);
const updated = updateSourceFileNode(node, createNodeArray(statements, node.statements));
const updated = updateSourceFileNode(node, setTextRange(createNodeArray(statements), node.statements));
if (currentModuleInfo.hasExportStarsToExportValues) {
addEmitHelper(updated, exportStarHelper);
}
return updated;
}
@@ -131,47 +135,49 @@ namespace ts {
// Create an updated SourceFile:
//
// define(moduleName?, ["module1", "module2"], function ...
return updateSourceFileNode(node, createNodeArray(
[
createStatement(
createCall(
define,
/*typeArguments*/ undefined,
[
// Add the module name (if provided).
...(moduleName ? [moduleName] : []),
return updateSourceFileNode(node,
setTextRange(
createNodeArray([
createStatement(
createCall(
define,
/*typeArguments*/ undefined,
[
// Add the module name (if provided).
...(moduleName ? [moduleName] : []),
// Add the dependency array argument:
//
// ["require", "exports", module1", "module2", ...]
createArrayLiteral([
createLiteral("require"),
createLiteral("exports"),
...aliasedModuleNames,
...unaliasedModuleNames
]),
// Add the dependency array argument:
//
// ["require", "exports", module1", "module2", ...]
createArrayLiteral([
createLiteral("require"),
createLiteral("exports"),
...aliasedModuleNames,
...unaliasedModuleNames
]),
// Add the module body function argument:
//
// function (require, exports, module1, module2) ...
createFunctionExpression(
/*modifiers*/ undefined,
/*asteriskToken*/ undefined,
/*name*/ undefined,
/*typeParameters*/ undefined,
[
createParameter(/*decorators*/ undefined, /*modifiers*/ undefined, /*dotDotDotToken*/ undefined, "require"),
createParameter(/*decorators*/ undefined, /*modifiers*/ undefined, /*dotDotDotToken*/ undefined, "exports"),
...importAliasNames
],
/*type*/ undefined,
transformAsynchronousModuleBody(node)
)
]
// Add the module body function argument:
//
// function (require, exports, module1, module2) ...
createFunctionExpression(
/*modifiers*/ undefined,
/*asteriskToken*/ undefined,
/*name*/ undefined,
/*typeParameters*/ undefined,
[
createParameter(/*decorators*/ undefined, /*modifiers*/ undefined, /*dotDotDotToken*/ undefined, "require"),
createParameter(/*decorators*/ undefined, /*modifiers*/ undefined, /*dotDotDotToken*/ undefined, "exports"),
...importAliasNames
],
/*type*/ undefined,
transformAsynchronousModuleBody(node)
)
]
)
)
)
],
/*location*/ node.statements)
]),
/*location*/ node.statements
)
);
}
@@ -189,74 +195,76 @@ namespace ts {
/*typeParameters*/ undefined,
[createParameter(/*decorators*/ undefined, /*modifiers*/ undefined, /*dotDotDotToken*/ undefined, "factory")],
/*type*/ undefined,
createBlock(
[
createIf(
createLogicalAnd(
createTypeCheck(createIdentifier("module"), "object"),
createTypeCheck(createPropertyAccess(createIdentifier("module"), "exports"), "object")
),
createBlock([
createVariableStatement(
/*modifiers*/ undefined,
[
createVariableDeclaration(
"v",
/*type*/ undefined,
setTextRange(
createBlock(
[
createIf(
createLogicalAnd(
createTypeCheck(createIdentifier("module"), "object"),
createTypeCheck(createPropertyAccess(createIdentifier("module"), "exports"), "object")
),
createBlock([
createVariableStatement(
/*modifiers*/ undefined,
[
createVariableDeclaration(
"v",
/*type*/ undefined,
createCall(
createIdentifier("factory"),
/*typeArguments*/ undefined,
[
createIdentifier("require"),
createIdentifier("exports")
]
)
)
]
),
setEmitFlags(
createIf(
createStrictInequality(
createIdentifier("v"),
createIdentifier("undefined")
),
createStatement(
createAssignment(
createPropertyAccess(createIdentifier("module"), "exports"),
createIdentifier("v")
)
)
),
EmitFlags.SingleLine
)
]),
createIf(
createLogicalAnd(
createTypeCheck(createIdentifier("define"), "function"),
createPropertyAccess(createIdentifier("define"), "amd")
),
createBlock([
createStatement(
createCall(
createIdentifier("factory"),
createIdentifier("define"),
/*typeArguments*/ undefined,
[
createIdentifier("require"),
createIdentifier("exports")
createArrayLiteral([
createLiteral("require"),
createLiteral("exports"),
...aliasedModuleNames,
...unaliasedModuleNames
]),
createIdentifier("factory")
]
)
)
]
),
setEmitFlags(
createIf(
createStrictInequality(
createIdentifier("v"),
createIdentifier("undefined")
),
createStatement(
createAssignment(
createPropertyAccess(createIdentifier("module"), "exports"),
createIdentifier("v")
)
)
),
EmitFlags.SingleLine
])
)
]),
createIf(
createLogicalAnd(
createTypeCheck(createIdentifier("define"), "function"),
createPropertyAccess(createIdentifier("define"), "amd")
),
createBlock([
createStatement(
createCall(
createIdentifier("define"),
/*typeArguments*/ undefined,
[
createArrayLiteral([
createLiteral("require"),
createLiteral("exports"),
...aliasedModuleNames,
...unaliasedModuleNames
]),
createIdentifier("factory")
]
)
)
])
)
)
],
/*location*/ undefined,
/*multiLine*/ true
],
/*multiLine*/ true
),
/*location*/ undefined
)
);
@@ -274,8 +282,8 @@ namespace ts {
return updateSourceFileNode(
node,
createNodeArray(
[
setTextRange(
createNodeArray([
createStatement(
createCall(
umdHeader,
@@ -300,7 +308,7 @@ namespace ts {
]
)
)
],
]),
/*location*/ node.statements
)
);
@@ -367,6 +375,10 @@ namespace ts {
const statements: Statement[] = [];
const statementOffset = addPrologueDirectives(statements, node.statements, /*ensureUseStrict*/ !compilerOptions.noImplicitUseStrict, sourceElementVisitor);
if (!currentModuleInfo.exportEquals) {
append(statements, createUnderscoreUnderscoreESModule());
}
// Visit each statement of the module body.
append(statements, visitNode(currentModuleInfo.externalHelpersImportDeclaration, sourceElementVisitor, isStatement, /*optional*/ true));
addRange(statements, visitNodes(node.statements, sourceElementVisitor, isStatement, statementOffset));
@@ -378,7 +390,7 @@ namespace ts {
// Append the 'export =' statement if provided.
addExportEqualsIfNeeded(statements, /*emitAsReturn*/ true);
const body = createBlock(statements, /*location*/ undefined, /*multiLine*/ true);
const body = createBlock(statements, /*multiLine*/ true);
if (currentModuleInfo.hasExportStarsToExportValues) {
// If we have any `export * from ...` declarations
// we need to inform the emitter to add the __export helper.
@@ -399,11 +411,8 @@ namespace ts {
function addExportEqualsIfNeeded(statements: Statement[], emitAsReturn: boolean) {
if (currentModuleInfo.exportEquals) {
if (emitAsReturn) {
const statement = createReturn(
currentModuleInfo.exportEquals.expression,
/*location*/ currentModuleInfo.exportEquals
);
const statement = createReturn(currentModuleInfo.exportEquals.expression);
setTextRange(statement, currentModuleInfo.exportEquals);
setEmitFlags(statement, EmitFlags.NoTokenSourceMaps | EmitFlags.NoComments);
statements.push(statement);
}
@@ -415,10 +424,10 @@ namespace ts {
"exports"
),
currentModuleInfo.exportEquals.expression
),
/*location*/ currentModuleInfo.exportEquals
)
);
setTextRange(statement, currentModuleInfo.exportEquals);
setEmitFlags(statement, EmitFlags.NoComments);
statements.push(statement);
}
@@ -481,7 +490,7 @@ namespace ts {
if (moduleKind !== ModuleKind.AMD) {
if (!node.importClause) {
// import "mod";
return createStatement(createRequireCall(node), /*location*/ node);
return setTextRange(createStatement(createRequireCall(node)), node);
}
else {
const variables: VariableDeclaration[] = [];
@@ -520,12 +529,13 @@ namespace ts {
}
statements = append(statements,
createVariableStatement(
/*modifiers*/ undefined,
createVariableDeclarationList(
variables,
/*location*/ undefined,
languageVersion >= ScriptTarget.ES2015 ? NodeFlags.Const : NodeFlags.None
setTextRange(
createVariableStatement(
/*modifiers*/ undefined,
createVariableDeclarationList(
variables,
languageVersion >= ScriptTarget.ES2015 ? NodeFlags.Const : NodeFlags.None
)
),
/*location*/ node
)
@@ -539,14 +549,15 @@ namespace ts {
/*modifiers*/ undefined,
createVariableDeclarationList(
[
createVariableDeclaration(
getSynthesizedClone(namespaceDeclaration.name),
/*type*/ undefined,
getGeneratedNameForNode(node),
setTextRange(
createVariableDeclaration(
getSynthesizedClone(namespaceDeclaration.name),
/*type*/ undefined,
getGeneratedNameForNode(node)
),
/*location*/ node
)
],
/*location*/ undefined,
languageVersion >= ScriptTarget.ES2015 ? NodeFlags.Const : NodeFlags.None
)
)
@@ -592,31 +603,34 @@ namespace ts {
if (moduleKind !== ModuleKind.AMD) {
if (hasModifier(node, ModifierFlags.Export)) {
statements = append(statements,
createStatement(
createExportExpression(
node.name,
createRequireCall(node)
setTextRange(
createStatement(
createExportExpression(
node.name,
createRequireCall(node)
)
),
/*location*/ node
node
)
);
}
else {
statements = append(statements,
createVariableStatement(
/*modifiers*/ undefined,
createVariableDeclarationList(
[
createVariableDeclaration(
getSynthesizedClone(node.name),
/*type*/ undefined,
createRequireCall(node)
)
],
/*location*/ undefined,
/*flags*/ languageVersion >= ScriptTarget.ES2015 ? NodeFlags.Const : NodeFlags.None
setTextRange(
createVariableStatement(
/*modifiers*/ undefined,
createVariableDeclarationList(
[
createVariableDeclaration(
getSynthesizedClone(node.name),
/*type*/ undefined,
createRequireCall(node)
)
],
/*flags*/ languageVersion >= ScriptTarget.ES2015 ? NodeFlags.Const : NodeFlags.None
)
),
/*location*/ node
node
)
);
}
@@ -624,9 +638,11 @@ namespace ts {
else {
if (hasModifier(node, ModifierFlags.Export)) {
statements = append(statements,
createStatement(
createExportExpression(getExportName(node), getLocalName(node)),
/*location*/ node
setTextRange(
createStatement(
createExportExpression(getExportName(node), getLocalName(node))
),
node
)
);
}
@@ -657,20 +673,23 @@ namespace ts {
}
const generatedName = getGeneratedNameForNode(node);
if (node.exportClause) {
const statements: Statement[] = [];
// export { x, y } from "mod";
if (moduleKind !== ModuleKind.AMD) {
statements.push(
createVariableStatement(
/*modifiers*/ undefined,
createVariableDeclarationList([
createVariableDeclaration(
generatedName,
/*type*/ undefined,
createRequireCall(node)
)
]),
setTextRange(
createVariableStatement(
/*modifiers*/ undefined,
createVariableDeclarationList([
createVariableDeclaration(
generatedName,
/*type*/ undefined,
createRequireCall(node)
)
])
),
/*location*/ node
)
);
@@ -681,9 +700,11 @@ namespace ts {
specifier.propertyName || specifier.name
);
statements.push(
createStatement(
createExportExpression(getExportName(specifier), exportedValue),
/*location*/ specifier
setTextRange(
createStatement(
createExportExpression(getExportName(specifier), exportedValue)
),
specifier
)
);
}
@@ -692,17 +713,19 @@ namespace ts {
}
else {
// export * from "mod";
return createStatement(
createCall(
createIdentifier("__export"),
/*typeArguments*/ undefined,
[
moduleKind !== ModuleKind.AMD
? createRequireCall(node)
: generatedName
]
return setTextRange(
createStatement(
createCall(
createIdentifier("__export"),
/*typeArguments*/ undefined,
[
moduleKind !== ModuleKind.AMD
? createRequireCall(node)
: generatedName
]
)
),
/*location*/ node
node
);
}
}
@@ -741,15 +764,17 @@ namespace ts {
if (hasModifier(node, ModifierFlags.Export)) {
statements = append(statements,
setOriginalNode(
createFunctionDeclaration(
/*decorators*/ undefined,
visitNodes(node.modifiers, modifierVisitor, isModifier),
node.asteriskToken,
getDeclarationName(node, /*allowComments*/ true, /*allowSourceMaps*/ true),
/*typeParameters*/ undefined,
node.parameters,
/*type*/ undefined,
node.body,
setTextRange(
createFunctionDeclaration(
/*decorators*/ undefined,
visitNodes(node.modifiers, modifierVisitor, isModifier),
node.asteriskToken,
getDeclarationName(node, /*allowComments*/ true, /*allowSourceMaps*/ true),
/*typeParameters*/ undefined,
node.parameters,
/*type*/ undefined,
node.body
),
/*location*/ node
),
/*original*/ node
@@ -782,16 +807,18 @@ namespace ts {
if (hasModifier(node, ModifierFlags.Export)) {
statements = append(statements,
setOriginalNode(
createClassDeclaration(
/*decorators*/ undefined,
visitNodes(node.modifiers, modifierVisitor, isModifier),
getDeclarationName(node, /*allowComments*/ true, /*allowSourceMaps*/ true),
/*typeParameters*/ undefined,
node.heritageClauses,
node.members,
/*location*/ node
setTextRange(
createClassDeclaration(
/*decorators*/ undefined,
visitNodes(node.modifiers, modifierVisitor, isModifier),
getDeclarationName(node, /*allowComments*/ true, /*allowSourceMaps*/ true),
/*typeParameters*/ undefined,
node.heritageClauses,
node.members
),
node
),
/*original*/ node
node
)
);
}
@@ -820,6 +847,7 @@ namespace ts {
let statements: Statement[];
let variables: VariableDeclaration[];
let expressions: Expression[];
if (hasModifier(node, ModifierFlags.Export)) {
let modifiers: NodeArray<Modifier>;
@@ -843,7 +871,7 @@ namespace ts {
}
if (expressions) {
statements = append(statements, createStatement(inlineExpressions(expressions), /*location*/ node));
statements = append(statements, setTextRange(createStatement(inlineExpressions(expressions)), node));
}
}
else {
@@ -880,9 +908,11 @@ namespace ts {
}
else {
return createAssignment(
createPropertyAccess(
createIdentifier("exports"),
node.name,
setTextRange(
createPropertyAccess(
createIdentifier("exports"),
node.name
),
/*location*/ node.name
),
node.initializer
@@ -1107,43 +1137,39 @@ namespace ts {
* @param allowComments Whether to allow comments on the export.
*/
function appendExportStatement(statements: Statement[] | undefined, exportName: Identifier, expression: Expression, location?: TextRange, allowComments?: boolean): Statement[] | undefined {
if (exportName.text === "default") {
const sourceFile = getOriginalNode(currentSourceFile, isSourceFile);
if (sourceFile && !sourceFile.symbol.exports.get("___esModule")) {
if (languageVersion === ScriptTarget.ES3) {
statements = append(statements,
createStatement(
createExportExpression(
createIdentifier("__esModule"),
createLiteral(true)
)
)
);
}
else {
statements = append(statements,
createStatement(
createCall(
createPropertyAccess(createIdentifier("Object"), "defineProperty"),
/*typeArguments*/ undefined,
[
createIdentifier("exports"),
createLiteral("__esModule"),
createObjectLiteral([
createPropertyAssignment("value", createLiteral(true))
])
]
)
)
);
}
}
}
statements = append(statements, createExportStatement(exportName, expression, location, allowComments));
return statements;
}
function createUnderscoreUnderscoreESModule() {
let statement: Statement;
if (languageVersion === ScriptTarget.ES3) {
statement = createStatement(
createExportExpression(
createIdentifier("__esModule"),
createLiteral(true)
)
)
}
else {
statement = createStatement(
createCall(
createPropertyAccess(createIdentifier("Object"), "defineProperty"),
/*typeArguments*/ undefined,
[
createIdentifier("exports"),
createLiteral("__esModule"),
createObjectLiteral([
createPropertyAssignment("value", createLiteral(true))
])
]
)
);
}
setEmitFlags(statement, EmitFlags.CustomPrologue);
return statement;
}
/**
* Creates a call to the current file's export function to export a value.
*
@@ -1153,7 +1179,7 @@ namespace ts {
* @param allowComments An optional value indicating whether to emit comments for the statement.
*/
function createExportStatement(name: Identifier, value: Expression, location?: TextRange, allowComments?: boolean) {
const statement = createStatement(createExportExpression(name, value), location);
const statement = setTextRange(createStatement(createExportExpression(name, value)), location);
startOnNewLine(statement);
if (!allowComments) {
setEmitFlags(statement, EmitFlags.NoComments);
@@ -1170,12 +1196,14 @@ namespace ts {
* @param location The location to use for source maps and comments for the export.
*/
function createExportExpression(name: Identifier, value: Expression, location?: TextRange) {
return createAssignment(
createPropertyAccess(
createIdentifier("exports"),
getSynthesizedClone(name)
return setTextRange(
createAssignment(
createPropertyAccess(
createIdentifier("exports"),
getSynthesizedClone(name)
),
value
),
value,
location
);
}
@@ -1207,24 +1235,24 @@ namespace ts {
/**
* Hook for node emit notifications.
*
* @param emitContext A context hint for the emitter.
* @param hint A hint as to the intended usage of the node.
* @param node The node to emit.
* @param emit A callback used to emit the node in the printer.
*/
function onEmitNode(emitContext: EmitContext, node: Node, emitCallback: (emitContext: EmitContext, node: Node) => void): void {
function onEmitNode(hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void): void {
if (node.kind === SyntaxKind.SourceFile) {
currentSourceFile = <SourceFile>node;
currentModuleInfo = moduleInfoMap[getOriginalNodeId(currentSourceFile)];
noSubstitution = [];
previousOnEmitNode(emitContext, node, emitCallback);
previousOnEmitNode(hint, node, emitCallback);
currentSourceFile = undefined;
currentModuleInfo = undefined;
noSubstitution = undefined;
}
else {
previousOnEmitNode(emitContext, node, emitCallback);
previousOnEmitNode(hint, node, emitCallback);
}
}
@@ -1235,16 +1263,16 @@ namespace ts {
/**
* Hooks node substitutions.
*
* @param emitContext A context hint for the emitter.
* @param hint A hint as to the intended usage of the node.
* @param node The node to substitute.
*/
function onSubstituteNode(emitContext: EmitContext, node: Node) {
node = previousOnSubstituteNode(emitContext, node);
function onSubstituteNode(hint: EmitHint, node: Node) {
node = previousOnSubstituteNode(hint, node);
if (node.id && noSubstitution[node.id]) {
return node;
}
if (emitContext === EmitContext.Expression) {
if (hint === EmitHint.Expression) {
return substituteExpression(<Expression>node);
}
else if (isShorthandPropertyAssignment(node)) {
@@ -1268,9 +1296,9 @@ namespace ts {
// destructuring assignment
if (node.objectAssignmentInitializer) {
const initializer = createAssignment(exportedOrImportedName, node.objectAssignmentInitializer);
return createPropertyAssignment(name, initializer, /*location*/ node);
return setTextRange(createPropertyAssignment(name, initializer), node);
}
return createPropertyAssignment(name, exportedOrImportedName, /*location*/ node);
return setTextRange(createPropertyAssignment(name, exportedOrImportedName), node);
}
return node;
}
@@ -1312,9 +1340,11 @@ namespace ts {
if (!isGeneratedIdentifier(node) && !isLocalName(node)) {
const exportContainer = resolver.getReferencedExportContainer(node, isExportName(node));
if (exportContainer && exportContainer.kind === SyntaxKind.SourceFile) {
return createPropertyAccess(
createIdentifier("exports"),
getSynthesizedClone(node),
return setTextRange(
createPropertyAccess(
createIdentifier("exports"),
getSynthesizedClone(node)
),
/*location*/ node
);
}
@@ -1322,17 +1352,21 @@ namespace ts {
const importDeclaration = resolver.getReferencedImportDeclaration(node);
if (importDeclaration) {
if (isImportClause(importDeclaration)) {
return createPropertyAccess(
getGeneratedNameForNode(importDeclaration.parent),
createIdentifier("default"),
return setTextRange(
createPropertyAccess(
getGeneratedNameForNode(importDeclaration.parent),
createIdentifier("default")
),
/*location*/ node
);
}
else if (isImportSpecifier(importDeclaration)) {
const name = importDeclaration.propertyName || importDeclaration.name;
return createPropertyAccess(
getGeneratedNameForNode(importDeclaration.parent.parent.parent),
getSynthesizedClone(name),
return setTextRange(
createPropertyAccess(
getGeneratedNameForNode(importDeclaration.parent.parent.parent),
getSynthesizedClone(name)
),
/*location*/ node
);
}
@@ -1400,10 +1434,12 @@ namespace ts {
const exportedNames = getExports(node.operand);
if (exportedNames) {
let expression: Expression = node.kind === SyntaxKind.PostfixUnaryExpression
? createBinary(
node.operand,
createToken(node.operator === SyntaxKind.PlusPlusToken ? SyntaxKind.PlusEqualsToken : SyntaxKind.MinusEqualsToken),
createLiteral(1),
? setTextRange(
createBinary(
node.operand,
createToken(node.operator === SyntaxKind.PlusPlusToken ? SyntaxKind.PlusEqualsToken : SyntaxKind.MinusEqualsToken),
createLiteral(1)
),
/*location*/ node)
: node;
for (const exportName of exportedNames) {
+81 -78
View File
@@ -105,17 +105,20 @@ namespace ts {
const updated = setEmitFlags(
updateSourceFileNode(
node,
createNodeArray([
createStatement(
createCall(
createPropertyAccess(createIdentifier("System"), "register"),
/*typeArguments*/ undefined,
moduleName
? [moduleName, dependencies, moduleBodyFunction]
: [dependencies, moduleBodyFunction]
setTextRange(
createNodeArray([
createStatement(
createCall(
createPropertyAccess(createIdentifier("System"), "register"),
/*typeArguments*/ undefined,
moduleName
? [moduleName, dependencies, moduleBodyFunction]
: [dependencies, moduleBodyFunction]
)
)
)
], node.statements)
]),
node.statements
)
), EmitFlags.NoTrailingComments);
if (!(compilerOptions.outFile || compilerOptions.out)) {
@@ -260,35 +263,26 @@ namespace ts {
addRange(statements, endLexicalEnvironment());
const exportStarFunction = addExportStarIfNeeded(statements);
statements.push(
createReturn(
setMultiLine(
createObjectLiteral([
createPropertyAssignment("setters",
createSettersArray(exportStarFunction, dependencyGroups)
),
createPropertyAssignment("execute",
createFunctionExpression(
/*modifiers*/ undefined,
/*asteriskToken*/ undefined,
/*name*/ undefined,
/*typeParameters*/ undefined,
/*parameters*/ [],
/*type*/ undefined,
createBlock(
executeStatements,
/*location*/ undefined,
/*multiLine*/ true
)
)
)
]),
/*multiLine*/ true
const moduleObject = createObjectLiteral([
createPropertyAssignment("setters",
createSettersArray(exportStarFunction, dependencyGroups)
),
createPropertyAssignment("execute",
createFunctionExpression(
/*modifiers*/ undefined,
/*asteriskToken*/ undefined,
/*name*/ undefined,
/*typeParameters*/ undefined,
/*parameters*/ [],
/*type*/ undefined,
createBlock(executeStatements, /*multiLine*/ true)
)
)
);
]);
return createBlock(statements, /*location*/ undefined, /*multiLine*/ true);
moduleObject.multiLine = true;
statements.push(createReturn(moduleObject));
return createBlock(statements, /*multiLine*/ true);
}
/**
@@ -337,7 +331,7 @@ namespace ts {
exportedNames.push(
createPropertyAssignment(
createLiteral(exportedLocalName),
createLiteral(true)
createTrue()
)
);
}
@@ -359,7 +353,7 @@ namespace ts {
exportedNames.push(
createPropertyAssignment(
createLiteral((element.name || element.propertyName).text),
createLiteral(true)
createTrue()
)
);
}
@@ -373,7 +367,7 @@ namespace ts {
createVariableDeclaration(
exportedNamesStorageRef,
/*type*/ undefined,
createObjectLiteral(exportedNames, /*location*/ undefined, /*multiline*/ true)
createObjectLiteral(exportedNames, /*multiline*/ true)
)
])
)
@@ -456,9 +450,7 @@ namespace ts {
[exports]
)
)
],
/*location*/ undefined,
/*multiline*/ true)
], /*multiline*/ true)
);
}
@@ -525,7 +517,7 @@ namespace ts {
createCall(
exportFunction,
/*typeArguments*/ undefined,
[createObjectLiteral(properties, /*location*/ undefined, /*multiline*/ true)]
[createObjectLiteral(properties, /*multiline*/ true)]
)
)
);
@@ -558,12 +550,12 @@ namespace ts {
/*typeParameters*/ undefined,
[createParameter(/*decorators*/ undefined, /*modifiers*/ undefined, /*dotDotDotToken*/ undefined, parameterName)],
/*type*/ undefined,
createBlock(statements, /*location*/ undefined, /*multiLine*/ true)
createBlock(statements, /*multiLine*/ true)
)
);
}
return createArrayLiteral(setters, /*location*/ undefined, /*multiLine*/ true);
return createArrayLiteral(setters, /*multiLine*/ true);
}
//
@@ -713,19 +705,23 @@ namespace ts {
// Rewrite the class declaration into an assignment of a class expression.
statements = append(statements,
createStatement(
createAssignment(
name,
createClassExpression(
/*modifiers*/ undefined,
node.name,
/*typeParameters*/ undefined,
visitNodes(node.heritageClauses, destructuringVisitor, isHeritageClause),
visitNodes(node.members, destructuringVisitor, isClassElement),
/*location*/ node
setTextRange(
createStatement(
createAssignment(
name,
setTextRange(
createClassExpression(
/*modifiers*/ undefined,
node.name,
/*typeParameters*/ undefined,
visitNodes(node.heritageClauses, destructuringVisitor, isHeritageClause),
visitNodes(node.members, destructuringVisitor, isClassElement)
),
node
)
)
),
/*location*/ node
node
)
);
@@ -766,7 +762,7 @@ namespace ts {
let statements: Statement[];
if (expressions) {
statements = append(statements, createStatement(inlineExpressions(expressions), /*location*/ node));
statements = append(statements, setTextRange(createStatement(inlineExpressions(expressions)), node));
}
if (isMarkedDeclaration) {
@@ -864,8 +860,8 @@ namespace ts {
function createVariableAssignment(name: Identifier, value: Expression, location: TextRange, isExportedDeclaration: boolean) {
hoistVariableDeclaration(getSynthesizedClone(name));
return isExportedDeclaration
? createExportExpression(name, preventSubstitution(createAssignment(name, value, location)))
: preventSubstitution(createAssignment(name, value, location));
? createExportExpression(name, preventSubstitution(setTextRange(createAssignment(name, value), location)))
: preventSubstitution(setTextRange(createAssignment(name, value), location));
}
/**
@@ -1548,11 +1544,11 @@ namespace ts {
/**
* Hook for node emit notifications.
*
* @param emitContext A context hint for the emitter.
* @param hint A hint as to the intended usage of the node.
* @param node The node to emit.
* @param emit A callback used to emit the node in the printer.
* @param emitCallback A callback used to emit the node in the printer.
*/
function onEmitNode(emitContext: EmitContext, node: Node, emitCallback: (emitContext: EmitContext, node: Node) => void): void {
function onEmitNode(hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void): void {
if (node.kind === SyntaxKind.SourceFile) {
const id = getOriginalNodeId(node);
currentSourceFile = <SourceFile>node;
@@ -1564,7 +1560,7 @@ namespace ts {
delete noSubstitutionMap[id];
}
previousOnEmitNode(emitContext, node, emitCallback);
previousOnEmitNode(hint, node, emitCallback);
currentSourceFile = undefined;
moduleInfo = undefined;
@@ -1572,7 +1568,7 @@ namespace ts {
noSubstitution = undefined;
}
else {
previousOnEmitNode(emitContext, node, emitCallback);
previousOnEmitNode(hint, node, emitCallback);
}
}
@@ -1583,16 +1579,16 @@ namespace ts {
/**
* Hooks node substitutions.
*
* @param emitContext A context hint for the emitter.
* @param hint A hint as to the intended usage of the node.
* @param node The node to substitute.
*/
function onSubstituteNode(emitContext: EmitContext, node: Node) {
node = previousOnSubstituteNode(emitContext, node);
function onSubstituteNode(hint: EmitHint, node: Node) {
node = previousOnSubstituteNode(hint, node);
if (isSubstitutionPrevented(node)) {
return node;
}
if (emitContext === EmitContext.Expression) {
if (hint === EmitHint.Expression) {
return substituteExpression(<Expression>node);
}
@@ -1642,16 +1638,20 @@ namespace ts {
const importDeclaration = resolver.getReferencedImportDeclaration(node);
if (importDeclaration) {
if (isImportClause(importDeclaration)) {
return createPropertyAccess(
getGeneratedNameForNode(importDeclaration.parent),
createIdentifier("default"),
return setTextRange(
createPropertyAccess(
getGeneratedNameForNode(importDeclaration.parent),
createIdentifier("default")
),
/*location*/ node
);
}
else if (isImportSpecifier(importDeclaration)) {
return createPropertyAccess(
getGeneratedNameForNode(importDeclaration.parent.parent.parent),
getSynthesizedClone(importDeclaration.propertyName || importDeclaration.name),
return setTextRange(
createPropertyAccess(
getGeneratedNameForNode(importDeclaration.parent.parent.parent),
getSynthesizedClone(importDeclaration.propertyName || importDeclaration.name)
),
/*location*/ node
);
}
@@ -1718,10 +1718,13 @@ namespace ts {
const exportedNames = getExports(node.operand);
if (exportedNames) {
let expression: Expression = node.kind === SyntaxKind.PostfixUnaryExpression
? createPrefix(
node.operator,
node.operand,
/*location*/ node)
? setTextRange(
createPrefix(
node.operator,
node.operand
),
node
)
: node;
for (const exportName of exportedNames) {
+156 -117
View File
@@ -588,17 +588,17 @@ namespace ts {
name,
/*typeParameters*/ undefined,
visitNodes(node.heritageClauses, visitor, isHeritageClause),
transformClassMembers(node, hasExtendsClause),
node);
let emitFlags = getEmitFlags(node);
transformClassMembers(node, hasExtendsClause)
);
// To better align with the old emitter, we should not emit a trailing source map
// entry if the class has static properties.
let emitFlags = getEmitFlags(node);
if (hasStaticProperties) {
emitFlags |= EmitFlags.NoTrailingSourceMap;
}
setTextRange(classDeclaration, node);
setOriginalNode(classDeclaration, node);
setEmitFlags(classDeclaration, emitFlags);
return classDeclaration;
@@ -709,13 +709,24 @@ namespace ts {
// }
const heritageClauses = visitNodes(node.heritageClauses, visitor, isHeritageClause);
const members = transformClassMembers(node, hasExtendsClause);
const classExpression = createClassExpression(/*modifiers*/ undefined, name, /*typeParameters*/ undefined, heritageClauses, members, location);
const classExpression = createClassExpression(/*modifiers*/ undefined, name, /*typeParameters*/ undefined, heritageClauses, members);
setOriginalNode(classExpression, node);
setTextRange(classExpression, location);
// let ${name} = ${classExpression} where name is either declaredName if the class doesn't contain self-reference
// or decoratedClassAlias if the class contain self-reference.
const statement = createLetStatement(declName, classAlias ? createAssignment(classAlias, classExpression) : classExpression, location);
const statement = createVariableStatement(
/*modifiers*/ undefined,
createVariableDeclarationList([
createVariableDeclaration(
declName,
/*type*/ undefined,
classAlias ? createAssignment(classAlias, classExpression) : classExpression
)
], NodeFlags.Let)
);
setOriginalNode(statement, node);
setTextRange(statement, location);
setCommentRange(statement, node);
return statement;
}
@@ -734,18 +745,17 @@ namespace ts {
const heritageClauses = visitNodes(node.heritageClauses, visitor, isHeritageClause);
const members = transformClassMembers(node, some(heritageClauses, c => c.token === SyntaxKind.ExtendsKeyword));
const classExpression = setOriginalNode(
createClassExpression(
/*modifiers*/ undefined,
node.name,
/*typeParameters*/ undefined,
heritageClauses,
members,
/*location*/ node
),
node
const classExpression = createClassExpression(
/*modifiers*/ undefined,
node.name,
/*typeParameters*/ undefined,
heritageClauses,
members
);
setOriginalNode(classExpression, node);
setTextRange(classExpression, node);
if (staticProperties.length > 0) {
const expressions: Expression[] = [];
const temp = createTempVariable(hoistVariableDeclaration);
@@ -781,7 +791,7 @@ namespace ts {
}
addRange(members, visitNodes(node.members, classElementVisitor, isClassElement));
return createNodeArray(members, /*location*/ node.members);
return setTextRange(createNodeArray(members), /*location*/ node.members);
}
/**
@@ -812,12 +822,14 @@ namespace ts {
// }
return startOnNewLine(
setOriginalNode(
createConstructor(
/*decorators*/ undefined,
/*modifiers*/ undefined,
parameters,
body,
/*location*/ constructor || node
setTextRange(
createConstructor(
/*decorators*/ undefined,
/*modifiers*/ undefined,
parameters,
body
),
constructor || node
),
constructor
)
@@ -919,13 +931,15 @@ namespace ts {
// End the lexical environment.
addRange(statements, endLexicalEnvironment());
return createBlock(
createNodeArray(
statements,
/*location*/ constructor ? constructor.body.statements : node.members
return setTextRange(
createBlock(
setTextRange(
createNodeArray(statements),
/*location*/ constructor ? constructor.body.statements : node.members
),
/*multiLine*/ true
),
/*location*/ constructor ? constructor.body : /*location*/ undefined,
/*multiLine*/ true
/*location*/ constructor ? constructor.body : undefined
);
}
@@ -991,16 +1005,20 @@ namespace ts {
setEmitFlags(localName, EmitFlags.NoComments);
return startOnNewLine(
createStatement(
createAssignment(
createPropertyAccess(
createThis(),
propertyName,
/*location*/ node.name
),
localName
setTextRange(
createStatement(
createAssignment(
setTextRange(
createPropertyAccess(
createThis(),
propertyName
),
node.name
),
localName
)
),
/*location*/ moveRangePos(node, -1)
moveRangePos(node, -1)
)
);
}
@@ -1504,7 +1522,7 @@ namespace ts {
(properties || (properties = [])).push(createPropertyAssignment("returnType", createArrowFunction(/*modifiers*/ undefined, /*typeParameters*/ undefined, [], /*type*/ undefined, createToken(SyntaxKind.EqualsGreaterThanToken), serializeReturnTypeOfNode(node))));
}
if (properties) {
decoratorExpressions.push(createMetadataHelper(context, "design:typeinfo", createObjectLiteral(properties, /*location*/ undefined, /*multiLine*/ true)));
decoratorExpressions.push(createMetadataHelper(context, "design:typeinfo", createObjectLiteral(properties, /*multiLine*/ true)));
}
}
}
@@ -1939,10 +1957,7 @@ namespace ts {
expression = createAssignment(generatedName, expression);
}
return setOriginalNode(
createComputedPropertyName(expression, /*location*/ name),
name
);
return updateComputedPropertyName(name, expression);
}
else {
return name;
@@ -1961,9 +1976,11 @@ namespace ts {
function visitHeritageClause(node: HeritageClause): HeritageClause {
if (node.token === SyntaxKind.ExtendsKeyword) {
const types = visitNodes(node.types, visitor, isExpressionWithTypeArguments, 0, 1);
return createHeritageClause(
SyntaxKind.ExtendsKeyword,
types,
return setTextRange(
createHeritageClause(
SyntaxKind.ExtendsKeyword,
types
),
node
);
}
@@ -1980,11 +1997,10 @@ namespace ts {
* @param node The ExpressionWithTypeArguments to transform.
*/
function visitExpressionWithTypeArguments(node: ExpressionWithTypeArguments): ExpressionWithTypeArguments {
const expression = visitNode(node.expression, visitor, isLeftHandSideExpression);
return createExpressionWithTypeArguments(
return updateExpressionWithTypeArguments(
node,
/*typeArguments*/ undefined,
expression,
node
visitNode(node.expression, visitor, isLeftHandSideExpression)
);
}
@@ -2205,13 +2221,13 @@ namespace ts {
visitNode(node.name, visitor, isBindingName),
/*questionToken*/ undefined,
/*type*/ undefined,
visitNode(node.initializer, visitor, isExpression),
/*location*/ moveRangePastModifiers(node)
visitNode(node.initializer, visitor, isExpression)
);
// While we emit the source map for the node after skipping decorators and modifiers,
// we need to emit the comments for the original range.
setOriginalNode(parameter, node);
setTextRange(parameter, moveRangePastModifiers(node));
setCommentRange(parameter, node);
setSourceMapRange(parameter, moveRangePastModifiers(node));
setEmitFlags(parameter.name, EmitFlags.NoTrailingSourceMap);
@@ -2233,11 +2249,13 @@ namespace ts {
return undefined;
}
return createStatement(
inlineExpressions(
map(variables, transformInitializedVariable)
return setTextRange(
createStatement(
inlineExpressions(
map(variables, transformInitializedVariable)
)
),
/*location*/ node
node
);
}
else {
@@ -2258,9 +2276,11 @@ namespace ts {
);
}
else {
return createAssignment(
getNamespaceMemberNameWithSourceMapsAndWithoutComments(name),
visitNode(node.initializer, visitor, isExpression),
return setTextRange(
createAssignment(
getNamespaceMemberNameWithSourceMapsAndWithoutComments(name),
visitNode(node.initializer, visitor, isExpression)
),
/*location*/ node
);
}
@@ -2418,11 +2438,11 @@ namespace ts {
),
/*typeArguments*/ undefined,
[moduleArg]
),
/*location*/ node
)
);
setOriginalNode(enumStatement, node);
setTextRange(enumStatement, node);
setEmitFlags(enumStatement, emitFlags);
statements.push(enumStatement);
@@ -2448,8 +2468,7 @@ namespace ts {
currentNamespaceContainerName = savedCurrentNamespaceLocalName;
return createBlock(
createNodeArray(statements, /*location*/ node.members),
/*location*/ undefined,
setTextRange(createNodeArray(statements), /*location*/ node.members),
/*multiLine*/ true
);
}
@@ -2464,22 +2483,26 @@ namespace ts {
// we pass false as 'generateNameForComputedPropertyName' for a backward compatibility purposes
// old emitter always generate 'expression' part of the name as-is.
const name = getExpressionForPropertyName(member, /*generateNameForComputedPropertyName*/ false);
return createStatement(
createAssignment(
createElementAccess(
currentNamespaceContainerName,
return setTextRange(
createStatement(
setTextRange(
createAssignment(
createElementAccess(
currentNamespaceContainerName,
name
createAssignment(
createElementAccess(
currentNamespaceContainerName,
name
),
transformEnumMemberDeclarationValue(member)
)
),
transformEnumMemberDeclarationValue(member)
)
),
name,
/*location*/ member
name
),
member
)
),
/*location*/ member
member
);
}
@@ -2697,11 +2720,11 @@ namespace ts {
),
/*typeArguments*/ undefined,
[moduleArg]
),
/*location*/ node
)
);
setOriginalNode(moduleStatement, node);
setTextRange(moduleStatement, node);
setEmitFlags(moduleStatement, emitFlags);
statements.push(moduleStatement);
@@ -2756,13 +2779,13 @@ namespace ts {
currentScopeFirstDeclarationsOfName = savedCurrentScopeFirstDeclarationsOfName;
const block = createBlock(
createNodeArray(
statements,
setTextRange(
createNodeArray(statements),
/*location*/ statementsLocation
),
/*location*/ blockLocation,
/*multiLine*/ true
);
setTextRange(block, blockLocation);
// namespace hello.hi.world {
// function foo() {}
@@ -2962,18 +2985,20 @@ namespace ts {
// export var ${name} = ${moduleReference};
// var ${name} = ${moduleReference};
return setOriginalNode(
createVariableStatement(
visitNodes(node.modifiers, modifierVisitor, isModifier),
createVariableDeclarationList([
setOriginalNode(
createVariableDeclaration(
node.name,
/*type*/ undefined,
moduleReference
),
node
)
]),
setTextRange(
createVariableStatement(
visitNodes(node.modifiers, modifierVisitor, isModifier),
createVariableDeclarationList([
setOriginalNode(
createVariableDeclaration(
node.name,
/*type*/ undefined,
moduleReference
),
node
)
])
),
node
),
node
@@ -3034,7 +3059,7 @@ namespace ts {
* Creates a statement for the provided expression. This is used in calls to `map`.
*/
function expressionToStatement(expression: Expression) {
return createStatement(expression, /*location*/ undefined);
return createStatement(expression);
}
function addExportMemberAssignment(statements: Statement[], node: ClassDeclaration | FunctionDeclaration) {
@@ -3050,17 +3075,19 @@ namespace ts {
}
function createNamespaceExport(exportName: Identifier, exportValue: Expression, location?: TextRange) {
return createStatement(
createAssignment(
getNamespaceMemberName(currentNamespaceContainerName, exportName, /*allowComments*/ false, /*allowSourceMaps*/ true),
exportValue
return setTextRange(
createStatement(
createAssignment(
getNamespaceMemberName(currentNamespaceContainerName, exportName, /*allowComments*/ false, /*allowSourceMaps*/ true),
exportValue
)
),
location
);
}
function createNamespaceExportExpression(exportName: Identifier, exportValue: Expression, location?: TextRange) {
return createAssignment(getNamespaceMemberNameWithSourceMapsAndWithoutComments(exportName), exportValue, location);
return setTextRange(createAssignment(getNamespaceMemberNameWithSourceMapsAndWithoutComments(exportName), exportValue), location);
}
function getNamespaceMemberNameWithSourceMapsAndWithoutComments(name: Identifier) {
@@ -3092,7 +3119,7 @@ namespace ts {
function getClassAliasIfNeeded(node: ClassDeclaration) {
if (resolver.getNodeCheckFlags(node) & NodeCheckFlags.ClassWithConstructorReference) {
enableSubstitutionForClassAliases();
const classAlias = createUniqueName(node.name && !isGeneratedIdentifier(node.name) ? node.name.text : "default");
const classAlias = createUniqueName(node.name && !isGeneratedIdentifier(node.name) ? unescapeIdentifier(node.name.text) : "default");
classAliases[getOriginalNodeId(node)] = classAlias;
hoistVariableDeclaration(classAlias);
return classAlias;
@@ -3154,11 +3181,11 @@ namespace ts {
/**
* Hook for node emit.
*
* @param emitContext A context hint for the emitter.
* @param hint A hint as to the intended usage of the node.
* @param node The node to emit.
* @param emit A callback used to emit the node in the printer.
*/
function onEmitNode(emitContext: EmitContext, node: Node, emitCallback: (emitContext: EmitContext, node: Node) => void): void {
function onEmitNode(hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void): void {
const savedApplicableSubstitutions = applicableSubstitutions;
if (enabledSubstitutions & TypeScriptSubstitutionFlags.NamespaceExports && isTransformedModuleDeclaration(node)) {
@@ -3169,7 +3196,7 @@ namespace ts {
applicableSubstitutions |= TypeScriptSubstitutionFlags.NonQualifiedEnumMembers;
}
previousOnEmitNode(emitContext, node, emitCallback);
previousOnEmitNode(hint, node, emitCallback);
applicableSubstitutions = savedApplicableSubstitutions;
}
@@ -3177,12 +3204,12 @@ namespace ts {
/**
* Hooks node substitutions.
*
* @param emitContext A context hint for the emitter.
* @param hint A hint as to the intended usage of the node.
* @param node The node to substitute.
*/
function onSubstituteNode(emitContext: EmitContext, node: Node) {
node = previousOnSubstituteNode(emitContext, node);
if (emitContext === EmitContext.Expression) {
function onSubstituteNode(hint: EmitHint, node: Node) {
node = previousOnSubstituteNode(hint, node);
if (hint === EmitHint.Expression) {
return substituteExpression(<Expression>node);
}
else if (isShorthandPropertyAssignment(node)) {
@@ -3201,9 +3228,9 @@ namespace ts {
// destructuring assignment
if (node.objectAssignmentInitializer) {
const initializer = createAssignment(exportedName, node.objectAssignmentInitializer);
return createPropertyAssignment(name, initializer, /*location*/ node);
return setTextRange(createPropertyAssignment(name, initializer), node);
}
return createPropertyAssignment(name, exportedName, /*location*/ node);
return setTextRange(createPropertyAssignment(name, exportedName), node);
}
}
return node;
@@ -3263,7 +3290,10 @@ namespace ts {
(applicableSubstitutions & TypeScriptSubstitutionFlags.NamespaceExports && container.kind === SyntaxKind.ModuleDeclaration) ||
(applicableSubstitutions & TypeScriptSubstitutionFlags.NonQualifiedEnumMembers && container.kind === SyntaxKind.EnumDeclaration);
if (substitute) {
return createPropertyAccess(getGeneratedNameForNode(container), node, /*location*/ node);
return setTextRange(
createPropertyAccess(getGeneratedNameForNode(container), node),
/*location*/ node
);
}
}
}
@@ -3322,13 +3352,15 @@ namespace ts {
function createParamHelper(context: TransformationContext, expression: Expression, parameterOffset: number, location?: TextRange) {
context.requestEmitHelper(paramHelper);
return createCall(
getHelperName("__param"),
/*typeArguments*/ undefined,
[
createLiteral(parameterOffset),
expression
],
return setTextRange(
createCall(
getHelperName("__param"),
/*typeArguments*/ undefined,
[
createLiteral(parameterOffset),
expression
]
),
location
);
}
@@ -3371,7 +3403,7 @@ namespace ts {
function createDecorateHelper(context: TransformationContext, decoratorExpressions: Expression[], target: Expression, memberName?: Expression, descriptor?: Expression, location?: TextRange) {
context.requestEmitHelper(decorateHelper);
const argumentsArray: Expression[] = [];
argumentsArray.push(createArrayLiteral(decoratorExpressions, /*location*/ undefined, /*multiLine*/ true));
argumentsArray.push(createArrayLiteral(decoratorExpressions, /*multiLine*/ true));
argumentsArray.push(target);
if (memberName) {
argumentsArray.push(memberName);
@@ -3380,6 +3412,13 @@ namespace ts {
}
}
return createCall(getHelperName("__decorate"), /*typeArguments*/ undefined, argumentsArray, location);
return setTextRange(
createCall(
getHelperName("__decorate"),
/*typeArguments*/ undefined,
argumentsArray
),
location
);
}
}
+202 -60
View File
@@ -349,6 +349,7 @@
EnumMember,
// Top-level nodes
SourceFile,
Bundle,
// JSDoc nodes
JSDocTypeExpression,
@@ -959,8 +960,7 @@
}
// Represents an expression that is elided as part of a transformation to emit comments on a
// not-emitted node. The 'expression' property of a NotEmittedExpression should be emitted.
// @internal
// not-emitted node. The 'expression' property of a PartiallyEmittedExpression should be emitted.
export interface PartiallyEmittedExpression extends LeftHandSideExpression {
kind: SyntaxKind.PartiallyEmittedExpression;
expression: Expression;
@@ -1542,7 +1542,6 @@
// Represents a statement that is elided as part of a transformation to emit comments on a
// not-emitted node.
// @internal
export interface NotEmittedStatement extends Statement {
kind: SyntaxKind.NotEmittedStatement;
}
@@ -1777,24 +1776,28 @@
members: NodeArray<EnumMember>;
}
export type ModuleBody = ModuleBlock | ModuleDeclaration;
export type ModuleName = Identifier | StringLiteral;
export type ModuleBody = NamespaceBody | JSDocNamespaceBody;
export interface ModuleDeclaration extends DeclarationStatement {
kind: SyntaxKind.ModuleDeclaration;
name: Identifier | StringLiteral;
body?: ModuleBlock | NamespaceDeclaration | JSDocNamespaceDeclaration | Identifier;
body?: ModuleBody | JSDocNamespaceDeclaration | Identifier;
}
export type NamespaceBody = ModuleBlock | NamespaceDeclaration;
export interface NamespaceDeclaration extends ModuleDeclaration {
name: Identifier;
body: ModuleBlock | NamespaceDeclaration;
body: NamespaceBody;
}
export type JSDocNamespaceBody = Identifier | JSDocNamespaceDeclaration;
export interface JSDocNamespaceDeclaration extends ModuleDeclaration {
name: Identifier;
body: JSDocNamespaceDeclaration | Identifier;
body: JSDocNamespaceBody;
}
export interface ModuleBlock extends Node, Statement {
@@ -2073,10 +2076,25 @@
ArrayMutation = 1 << 8, // Potential array mutation
Referenced = 1 << 9, // Referenced as antecedent once
Shared = 1 << 10, // Referenced as antecedent more than once
PreFinally = 1 << 11, // Injected edge that links pre-finally label and pre-try flow
AfterFinally = 1 << 12, // Injected edge that links post-finally flow with the rest of the graph
Label = BranchLabel | LoopLabel,
Condition = TrueCondition | FalseCondition
}
export interface FlowLock {
locked?: boolean;
}
export interface AfterFinallyFlow extends FlowNode, FlowLock {
antecedent: FlowNode;
}
export interface PreFinallyFlow extends FlowNode {
antecedent: FlowNode;
lock: FlowLock;
}
export interface FlowNode {
flags: FlowFlags;
id?: number; // Node id used by flow type cache in checker
@@ -2206,6 +2224,11 @@
/* @internal */ ambientModuleNames: string[];
}
export interface Bundle extends Node {
kind: SyntaxKind.Bundle;
sourceFiles: SourceFile[];
}
export interface ScriptReferenceHost {
getCompilerOptions(): CompilerOptions;
getSourceFile(fileName: string): SourceFile;
@@ -2471,7 +2494,8 @@
InFirstTypeArgument = 0x00000100, // Writing first type argument of the instantiated type
InTypeAlias = 0x00000200, // Writing type in type alias declaration
UseTypeAliasValue = 0x00000400, // Serialize the type instead of using type-alias. This is needed when we emit declaration file.
SuppressAnyReturnType = 0x00000800, // If the return type is any-like, don't offer a return type.
SuppressAnyReturnType = 0x00000800, // If the return type is any-like, don't offer a return type.
AddUndefined = 0x00001000, // Add undefined to types of initialized, non-optional parameters
}
export const enum SymbolFormatFlags {
@@ -2576,6 +2600,7 @@
isDeclarationVisible(node: Declaration): boolean;
collectLinkedAliases(node: Identifier): Node[];
isImplementationOfOverload(node: FunctionLikeDeclaration): boolean;
isRequiredInitializedParameter(node: ParameterDeclaration): boolean;
writeTypeOfDeclaration(declaration: AccessorDeclaration | VariableLikeDeclaration, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: SymbolWriter): void;
writeReturnTypeOfSignatureDeclaration(signatureDeclaration: SignatureDeclaration, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: SymbolWriter): void;
writeTypeOfExpression(expr: Expression, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: SymbolWriter): void;
@@ -2599,37 +2624,34 @@
export const enum SymbolFlags {
None = 0,
FunctionScopedVariable = 0x00000001, // Variable (var) or parameter
BlockScopedVariable = 0x00000002, // A block-scoped variable (let or const)
Property = 0x00000004, // Property or enum member
EnumMember = 0x00000008, // Enum member
Function = 0x00000010, // Function
Class = 0x00000020, // Class
Interface = 0x00000040, // Interface
ConstEnum = 0x00000080, // Const enum
RegularEnum = 0x00000100, // Enum
ValueModule = 0x00000200, // Instantiated module
NamespaceModule = 0x00000400, // Uninstantiated module
TypeLiteral = 0x00000800, // Type Literal or mapped type
ObjectLiteral = 0x00001000, // Object Literal
Method = 0x00002000, // Method
Constructor = 0x00004000, // Constructor
GetAccessor = 0x00008000, // Get accessor
SetAccessor = 0x00010000, // Set accessor
Signature = 0x00020000, // Call, construct, or index signature
TypeParameter = 0x00040000, // Type parameter
TypeAlias = 0x00080000, // Type alias
ExportValue = 0x00100000, // Exported value marker (see comment in declareModuleMember in binder)
ExportType = 0x00200000, // Exported type marker (see comment in declareModuleMember in binder)
ExportNamespace = 0x00400000, // Exported namespace marker (see comment in declareModuleMember in binder)
Alias = 0x00800000, // An alias for another symbol (see comment in isAliasSymbolDeclaration in checker)
Instantiated = 0x01000000, // Instantiated symbol
Merged = 0x02000000, // Merged symbol (created during program binding)
Transient = 0x04000000, // Transient symbol (created during type check)
Prototype = 0x08000000, // Prototype property (no source representation)
SyntheticProperty = 0x10000000, // Property in union or intersection type
Optional = 0x20000000, // Optional property
ExportStar = 0x40000000, // Export * declaration
FunctionScopedVariable = 1 << 0, // Variable (var) or parameter
BlockScopedVariable = 1 << 1, // A block-scoped variable (let or const)
Property = 1 << 2, // Property or enum member
EnumMember = 1 << 3, // Enum member
Function = 1 << 4, // Function
Class = 1 << 5, // Class
Interface = 1 << 6, // Interface
ConstEnum = 1 << 7, // Const enum
RegularEnum = 1 << 8, // Enum
ValueModule = 1 << 9, // Instantiated module
NamespaceModule = 1 << 10, // Uninstantiated module
TypeLiteral = 1 << 11, // Type Literal or mapped type
ObjectLiteral = 1 << 12, // Object Literal
Method = 1 << 13, // Method
Constructor = 1 << 14, // Constructor
GetAccessor = 1 << 15, // Get accessor
SetAccessor = 1 << 16, // Set accessor
Signature = 1 << 17, // Call, construct, or index signature
TypeParameter = 1 << 18, // Type parameter
TypeAlias = 1 << 19, // Type alias
ExportValue = 1 << 20, // Exported value marker (see comment in declareModuleMember in binder)
ExportType = 1 << 21, // Exported type marker (see comment in declareModuleMember in binder)
ExportNamespace = 1 << 22, // Exported namespace marker (see comment in declareModuleMember in binder)
Alias = 1 << 23, // An alias for another symbol (see comment in isAliasSymbolDeclaration in checker)
Prototype = 1 << 24, // Prototype property (no source representation)
ExportStar = 1 << 25, // Export * declaration
Optional = 1 << 26, // Optional property
Transient = 1 << 27, // Transient symbol (created during type check)
Enum = RegularEnum | ConstEnum,
Variable = FunctionScopedVariable | BlockScopedVariable,
@@ -2689,11 +2711,9 @@
name: string; // Name of symbol
declarations?: Declaration[]; // Declarations associated with this symbol
valueDeclaration?: Declaration; // First value declaration of the symbol
members?: SymbolTable; // Class, interface or literal instance members
exports?: SymbolTable; // Module exports
globalExports?: SymbolTable; // Conditional global UMD exports
/* @internal */ isReadonly?: boolean; // readonly? (set only for intersections and unions)
/* @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
@@ -2718,8 +2738,6 @@
leftSpread?: Symbol; // Left source for synthetic spread property
rightSpread?: Symbol; // Right source for synthetic spread property
mappedTypeOrigin?: Symbol; // For a property on a mapped type, points back to the orignal 'T' from 'keyof T'.
hasNonUniformType?: boolean; // True if constituents have non-uniform types
isPartial?: boolean; // True if syntheric property of union type occurs in some but not all constituents
isDiscriminantProperty?: boolean; // True if discriminant synthetic property
resolvedExports?: SymbolTable; // Resolved exports of module
exportsChecked?: boolean; // True if exports of external module have been checked
@@ -2729,7 +2747,22 @@
}
/* @internal */
export interface TransientSymbol extends Symbol, SymbolLinks { }
export const enum CheckFlags {
Instantiated = 1 << 0, // Instantiated symbol
SyntheticProperty = 1 << 1, // Property in union or intersection type
Readonly = 1 << 2, // Readonly transient symbol
Partial = 1 << 3, // Synthetic property present in some but not all constituents
HasNonUniformType = 1 << 4, // Synthetic property with non-uniform type in constituents
ContainsPublic = 1 << 5, // Synthetic property with public constituent(s)
ContainsProtected = 1 << 6, // Synthetic property with protected constituent(s)
ContainsPrivate = 1 << 7, // Synthetic property with private constituent(s)
ContainsStatic = 1 << 8, // Synthetic property with static constituent(s)
}
/* @internal */
export interface TransientSymbol extends Symbol, SymbolLinks {
checkFlags: CheckFlags;
}
export type SymbolTable = Map<Symbol>;
@@ -3144,9 +3177,8 @@
ThisProperty
}
export interface FileExtensionInfo {
export interface JsFileExtensionInfo {
extension: string;
scriptKind: ScriptKind;
isMixedContent: boolean;
}
@@ -3190,7 +3222,11 @@
NodeJs = 2
}
export type CompilerOptionsValue = string | number | boolean | (string | number)[] | string[] | MapLike<string[]>;
export interface PluginImport {
name: string
}
export type CompilerOptionsValue = string | number | boolean | (string | number)[] | string[] | MapLike<string[]> | PluginImport[];
export interface CompilerOptions {
allowJs?: boolean;
@@ -3245,6 +3281,7 @@
outDir?: string;
outFile?: string;
paths?: MapLike<string[]>;
/*@internal*/ plugins?: PluginImport[];
preserveConstEnums?: boolean;
project?: string;
/* @internal */ pretty?: DiagnosticStyle;
@@ -3328,7 +3365,8 @@
JS = 1,
JSX = 2,
TS = 3,
TSX = 4
TSX = 4,
External = 5
}
export const enum ScriptTarget {
@@ -3403,7 +3441,7 @@
/* @internal */
export interface CommandLineOptionOfListType extends CommandLineOptionBase {
type: "list";
element: CommandLineOptionOfCustomType | CommandLineOptionOfPrimitiveType;
element: CommandLineOptionOfCustomType | CommandLineOptionOfPrimitiveType | TsConfigOnlyOption;
}
/* @internal */
@@ -3731,7 +3769,6 @@
helpers?: EmitHelper[]; // Emit helpers for the node
}
/* @internal */
export const enum EmitFlags {
SingleLine = 1 << 0, // The contents of this node should be emitted on a single line.
AdviseOnEmitNode = 1 << 1, // The printer should invoke the onEmitNode callback when printing this node.
@@ -3760,7 +3797,6 @@
HasEndOfDeclarationMarker = 1 << 21, // Declaration has an associated NotEmittedStatement to mark the end of the declaration
}
/* @internal */
export interface EmitHelper {
readonly name: string; // A unique name for this helper.
readonly scoped: boolean; // Indicates whether ther helper MUST be emitted in the current scope.
@@ -3787,8 +3823,7 @@
LastEmitHelper = Generator
}
/* @internal */
export const enum EmitContext {
export const enum EmitHint {
SourceFile, // Emitting a SourceFile
Expression, // Emitting an Expression
IdentifierName, // Emitting an IdentifierName
@@ -3863,7 +3898,7 @@
* Hook used by transformers to substitute expressions just before they
* are emitted by the pretty printer.
*/
onSubstituteNode?: (emitContext: EmitContext, node: Node) => Node;
onSubstituteNode?: (hint: EmitHint, node: Node) => Node;
/**
* Enables before/after emit notifications in the pretty printer for the provided
@@ -3881,7 +3916,7 @@
* Hook used to allow transformers to capture state before or after
* the printer emits a node.
*/
onEmitNode?: (emitContext: EmitContext, node: Node, emitCallback: (emitContext: EmitContext, node: Node) => void) => void;
onEmitNode?: (hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void) => void;
}
/* @internal */
@@ -3894,25 +3929,132 @@
/**
* Emits the substitute for a node, if one is available; otherwise, emits the node.
*
* @param emitContext The current emit context.
* @param hint A hint as to the intended usage of the node.
* @param node The node to substitute.
* @param emitCallback A callback used to emit the node or its substitute.
*/
emitNodeWithSubstitution(emitContext: EmitContext, node: Node, emitCallback: (emitContext: EmitContext, node: Node) => void): void;
emitNodeWithSubstitution(hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void): void;
/**
* Emits a node with possible notification.
*
* @param emitContext The current emit context.
* @param hint A hint as to the intended usage of the node.
* @param node The node to emit.
* @param emitCallback A callback used to emit the node.
*/
emitNodeWithNotification(emitContext: EmitContext, node: Node, emitCallback: (emitContext: EmitContext, node: Node) => void): void;
emitNodeWithNotification(hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void): void;
}
/* @internal */
export type Transformer = (context: TransformationContext) => (node: SourceFile) => SourceFile;
export interface Printer {
/**
* Print a node and its subtree as-is, without any emit transformations.
* @param hint A value indicating the purpose of a node. This is primarily used to
* distinguish between an `Identifier` used in an expression position, versus an
* `Identifier` used as an `IdentifierName` as part of a declaration. For most nodes you
* should just pass `Unspecified`.
* @param node The node to print. The node and its subtree are printed as-is, without any
* emit transformations.
* @param sourceFile A source file that provides context for the node. The source text of
* the file is used to emit the original source content for literals and identifiers, while
* the identifiers of the source file are used when generating unique names to avoid
* collisions.
*/
printNode(hint: EmitHint, node: Node, sourceFile: SourceFile): string;
/**
* Prints a source file as-is, without any emit transformations.
*/
printFile(sourceFile: SourceFile): string;
/**
* Prints a bundle of source files as-is, without any emit transformations.
*/
printBundle(bundle: Bundle): string;
/*@internal*/ writeNode(hint: EmitHint, node: Node, sourceFile: SourceFile, writer: EmitTextWriter): void;
/*@internal*/ writeFile(sourceFile: SourceFile, writer: EmitTextWriter): void;
/*@internal*/ writeBundle(bundle: Bundle, writer: EmitTextWriter): void;
}
export interface PrintHandlers {
/**
* A hook used by the Printer when generating unique names to avoid collisions with
* globally defined names that exist outside of the current source file.
*/
hasGlobalName?(name: string): boolean;
/**
* A hook used by the Printer to provide notifications prior to emitting a node. A
* compatible implementation **must** invoke `emitCallback` with the provided `hint` and
* `node` values.
* @param hint A hint indicating the intended purpose of the node.
* @param node The node to emit.
* @param emitCallback A callback that, when invoked, will emit the node.
* @example
* ```ts
* var printer = createPrinter(printerOptions, {
* onEmitNode(hint, node, emitCallback) {
* // set up or track state prior to emitting the node...
* emitCallback(hint, node);
* // restore state after emitting the node...
* }
* });
* ```
*/
onEmitNode?(hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void): void;
/**
* A hook used by the Printer to perform just-in-time substitution of a node. This is
* primarily used by node transformations that need to substitute one node for another,
* such as replacing `myExportedVar` with `exports.myExportedVar`. A compatible
* implementation **must** invoke `emitCallback` eith the provided `hint` and either
* the provided `node`, or its substitute.
* @param hint A hint indicating the intended purpose of the node.
* @param node The node to emit.
* @param emitCallback A callback that, when invoked, will emit the node.
* @example
* ```ts
* var printer = createPrinter(printerOptions, {
* onSubstituteNode(hint, node, emitCallback) {
* // perform substitution if necessary...
* emitCallback(hint, node);
* }
* });
* ```
*/
onSubstituteNode?(hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void): void;
/*@internal*/ onEmitSourceMapOfNode?: (hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void) => void;
/*@internal*/ onEmitSourceMapOfToken?: (node: Node, token: SyntaxKind, pos: number, emitCallback: (token: SyntaxKind, pos: number) => number) => number;
/*@internal*/ onEmitSourceMapOfPosition?: (pos: number) => void;
/*@internal*/ onEmitHelpers?: (node: Node, writeLines: (text: string) => void) => void;
/*@internal*/ onSetSourceFile?: (node: SourceFile) => void;
}
export interface PrinterOptions {
target?: ScriptTarget;
removeComments?: boolean;
newLine?: NewLineKind;
/*@internal*/ sourceMap?: boolean;
/*@internal*/ inlineSourceMap?: boolean;
/*@internal*/ extendedDiagnostics?: boolean;
}
/*@internal*/
export interface EmitTextWriter {
write(s: string): void;
writeTextOfNode(text: string, node: Node): void;
writeLine(): void;
increaseIndent(): void;
decreaseIndent(): void;
getText(): string;
rawWrite(s: string): void;
writeLiteral(s: string): void;
getTextPos(): number;
getLine(): number;
getColumn(): number;
getIndent(): number;
isAtStartOfLine(): boolean;
reset(): void;
}
export interface TextSpan {
start: number;
length: number;
+88 -76
View File
@@ -1523,6 +1523,11 @@ namespace ts {
return map(getJSDocs(node), doc => doc.comment);
}
export function hasJSDocParameterTags(node: FunctionLikeDeclaration | SignatureDeclaration) {
const parameterTags = getJSDocTags(node, SyntaxKind.JSDocParameterTag);
return parameterTags && parameterTags.length > 0;
}
function getJSDocTags(node: Node, kind: SyntaxKind): JSDocTag[] {
const docs = getJSDocs(node);
if (docs) {
@@ -2047,67 +2052,19 @@ namespace ts {
|| positionIsSynthesized(node.end);
}
export function getOriginalNode(node: Node): Node;
export function getOriginalNode<T extends Node>(node: Node, nodeTest: (node: Node) => node is T): T;
export function getOriginalNode(node: Node, nodeTest?: (node: Node) => boolean): Node {
if (node) {
while (node.original !== undefined) {
node = node.original;
}
export function getOriginalSourceFileOrBundle(sourceFileOrBundle: SourceFile | Bundle) {
if (sourceFileOrBundle.kind === SyntaxKind.Bundle) {
return updateBundle(sourceFileOrBundle, sameMap(sourceFileOrBundle.sourceFiles, getOriginalSourceFile));
}
return !nodeTest || nodeTest(node) ? node : undefined;
return getOriginalSourceFile(sourceFileOrBundle);
}
/**
* Gets a value indicating whether a node originated in the parse tree.
*
* @param node The node to test.
*/
export function isParseTreeNode(node: Node): boolean {
return (node.flags & NodeFlags.Synthesized) === 0;
}
/**
* Gets the original parse tree node for a node.
*
* @param node The original node.
* @returns The original parse tree node if found; otherwise, undefined.
*/
export function getParseTreeNode(node: Node): Node;
/**
* Gets the original parse tree node for a node.
*
* @param node The original node.
* @param nodeTest A callback used to ensure the correct type of parse tree node is returned.
* @returns The original parse tree node if found; otherwise, undefined.
*/
export function getParseTreeNode<T extends Node>(node: Node, nodeTest?: (node: Node) => node is T): T;
export function getParseTreeNode(node: Node, nodeTest?: (node: Node) => boolean): Node {
if (isParseTreeNode(node)) {
return node;
}
node = getOriginalNode(node);
if (isParseTreeNode(node) && (!nodeTest || nodeTest(node))) {
return node;
}
return undefined;
function getOriginalSourceFile(sourceFile: SourceFile) {
return getParseTreeNode(sourceFile, isSourceFile) || sourceFile;
}
export function getOriginalSourceFiles(sourceFiles: SourceFile[]) {
const originalSourceFiles: SourceFile[] = [];
for (const sourceFile of sourceFiles) {
const originalSourceFile = getParseTreeNode(sourceFile, isSourceFile);
if (originalSourceFile) {
originalSourceFiles.push(originalSourceFile);
}
}
return originalSourceFiles;
return sameMap(sourceFiles, getOriginalSourceFile);
}
export function getOriginalNodeId(node: Node) {
@@ -2446,23 +2403,6 @@ namespace ts {
s;
}
export interface EmitTextWriter {
write(s: string): void;
writeTextOfNode(text: string, node: Node): void;
writeLine(): void;
increaseIndent(): void;
decreaseIndent(): void;
getText(): string;
rawWrite(s: string): void;
writeLiteral(s: string): void;
getTextPos(): number;
getLine(): number;
getColumn(): number;
getIndent(): number;
isAtStartOfLine(): boolean;
reset(): void;
}
const indentStrings: string[] = ["", " "];
export function getIndentString(level: number) {
if (indentStrings[level] === undefined) {
@@ -2645,7 +2585,7 @@ namespace ts {
* Else, calls `getSourceFilesToEmit` with the (optional) target source file to determine the list of source files to emit.
*/
export function forEachEmittedFile(
host: EmitHost, action: (emitFileNames: EmitFileNames, sourceFiles: SourceFile[], isBundledEmit: boolean, emitOnlyDtsFiles: boolean) => void,
host: EmitHost, action: (emitFileNames: EmitFileNames, sourceFileOrBundle: SourceFile | Bundle, emitOnlyDtsFiles: boolean) => void,
sourceFilesOrTargetSourceFile?: SourceFile[] | SourceFile,
emitOnlyDtsFiles?: boolean) {
@@ -2656,7 +2596,7 @@ namespace ts {
const jsFilePath = options.outFile || options.out;
const sourceMapFilePath = getSourceMapFilePath(jsFilePath, options);
const declarationFilePath = options.declaration ? removeFileExtension(jsFilePath) + ".d.ts" : undefined;
action({ jsFilePath, sourceMapFilePath, declarationFilePath }, sourceFiles, /*isBundledEmit*/true, emitOnlyDtsFiles);
action({ jsFilePath, sourceMapFilePath, declarationFilePath }, createBundle(sourceFiles), emitOnlyDtsFiles);
}
}
else {
@@ -2664,7 +2604,7 @@ namespace ts {
const jsFilePath = getOwnEmitOutputFilePath(sourceFile, host, getOutputExtension(sourceFile, options));
const sourceMapFilePath = getSourceMapFilePath(jsFilePath, options);
const declarationFilePath = !isSourceFileJavaScript(sourceFile) && (emitOnlyDtsFiles || options.declaration) ? getDeclarationEmitOutputFilePath(sourceFile, host) : undefined;
action({ jsFilePath, sourceMapFilePath, declarationFilePath }, [sourceFile], /*isBundledEmit*/false, emitOnlyDtsFiles);
action({ jsFilePath, sourceMapFilePath, declarationFilePath }, sourceFile, emitOnlyDtsFiles);
}
}
}
@@ -3239,7 +3179,7 @@ namespace ts {
const carriageReturnLineFeed = "\r\n";
const lineFeed = "\n";
export function getNewLineCharacter(options: CompilerOptions): string {
export function getNewLineCharacter(options: CompilerOptions | PrinterOptions): string {
if (options.newLine === NewLineKind.CarriageReturnLineFeed) {
return carriageReturnLineFeed;
}
@@ -3350,6 +3290,14 @@ namespace ts {
}
}
export function getRangePos(range: TextRange | undefined) {
return range ? range.pos : -1;
}
export function getRangeEnd(range: TextRange | undefined) {
return range ? range.end : -1;
}
/**
* Increases (or decreases) a position by the provided amount.
*
@@ -3949,6 +3897,19 @@ namespace ts {
export function isModuleBody(node: Node): node is ModuleBody {
const kind = node.kind;
return kind === SyntaxKind.ModuleBlock
|| kind === SyntaxKind.ModuleDeclaration
|| kind === SyntaxKind.Identifier;
}
export function isNamespaceBody(node: Node): node is NamespaceBody {
const kind = node.kind;
return kind === SyntaxKind.ModuleBlock
|| kind === SyntaxKind.ModuleDeclaration;
}
export function isJSDocNamespaceBody(node: Node): node is JSDocNamespaceBody {
const kind = node.kind;
return kind === SyntaxKind.Identifier
|| kind === SyntaxKind.ModuleDeclaration;
}
@@ -4551,4 +4512,55 @@ namespace ts {
return true;
}
}
export function getOriginalNode(node: Node): Node;
export function getOriginalNode<T extends Node>(node: Node, nodeTest: (node: Node) => node is T): T;
export function getOriginalNode(node: Node, nodeTest?: (node: Node) => boolean): Node {
if (node) {
while (node.original !== undefined) {
node = node.original;
}
}
return !nodeTest || nodeTest(node) ? node : undefined;
}
/**
* Gets a value indicating whether a node originated in the parse tree.
*
* @param node The node to test.
*/
export function isParseTreeNode(node: Node): boolean {
return (node.flags & NodeFlags.Synthesized) === 0;
}
/**
* Gets the original parse tree node for a node.
*
* @param node The original node.
* @returns The original parse tree node if found; otherwise, undefined.
*/
export function getParseTreeNode(node: Node): Node;
/**
* Gets the original parse tree node for a node.
*
* @param node The original node.
* @param nodeTest A callback used to ensure the correct type of parse tree node is returned.
* @returns The original parse tree node if found; otherwise, undefined.
*/
export function getParseTreeNode<T extends Node>(node: Node, nodeTest?: (node: Node) => node is T): T;
export function getParseTreeNode(node: Node, nodeTest?: (node: Node) => boolean): Node {
if (isParseTreeNode(node)) {
return node;
}
node = getOriginalNode(node);
if (isParseTreeNode(node) && (!nodeTest || nodeTest(node))) {
return node;
}
return undefined;
}
}
+147 -166
View File
@@ -6,97 +6,6 @@
namespace ts {
export type VisitResult<T extends Node> = T | T[];
/**
* Describes an edge of a Node, used when traversing a syntax tree.
*/
interface NodeEdge {
/** The property name for the edge. */
name: string;
/** Indicates that the result is optional. */
optional?: boolean;
/** A callback used to test whether a node is valid. */
test?: (node: Node) => node is Node;
/** A callback used to lift a NodeArrayNode into a valid node. */
lift?: (nodes: NodeArray<Node>) => Node;
/** A callback used to parenthesize a node to preserve the intended order of operations. */
parenthesize?: (value: Node, parentNode: Node) => Node;
};
/**
* Describes the shape of a Node.
*/
type NodeTraversalPath = NodeEdge[];
/**
* This map contains information about the shape of each Node in "types.ts" pertaining to how
* each node should be traversed during a transformation.
*
* Each edge corresponds to a property in a Node subtype that should be traversed when visiting
* each child. The properties are assigned in the order in which traversal should occur.
*
* We only add entries for nodes that do not have a create/update pair defined in factory.ts
*
* NOTE: This needs to be kept up to date with changes to nodes in "types.ts". Currently, this
* map is not comprehensive. Only node edges relevant to tree transformation are
* currently defined. We may extend this to be more comprehensive, and eventually
* supplant the existing `forEachChild` implementation if performance is not
* significantly impacted.
*/
function getNodeEdgeTraversal(kind: SyntaxKind): NodeTraversalPath {
switch (kind) {
case SyntaxKind.QualifiedName: return [
{ name: "left", test: isEntityName },
{ name: "right", test: isIdentifier }
];
case SyntaxKind.Decorator: return [
{ name: "expression", test: isLeftHandSideExpression }
];
case SyntaxKind.TypeAssertionExpression: return [
{ name: "type", test: isTypeNode },
{ name: "expression", test: isUnaryExpression }
];
case SyntaxKind.AsExpression: return [
{ name: "expression", test: isExpression },
{ name: "type", test: isTypeNode }
];
case SyntaxKind.NonNullExpression: return [
{ name: "expression", test: isLeftHandSideExpression }
];
case SyntaxKind.EnumDeclaration: return [
{ name: "decorators", test: isDecorator },
{ name: "modifiers", test: isModifier },
{ name: "name", test: isIdentifier },
{ name: "members", test: isEnumMember }
];
case SyntaxKind.ModuleDeclaration: return [
{ name: "decorators", test: isDecorator },
{ name: "modifiers", test: isModifier },
{ name: "name", test: isModuleName },
{ name: "body", test: isModuleBody }
];
case SyntaxKind.ModuleBlock: return [
{ name: "statements", test: isStatement }
];
case SyntaxKind.ImportEqualsDeclaration: return [
{ name: "decorators", test: isDecorator },
{ name: "modifiers", test: isModifier },
{ name: "name", test: isIdentifier },
{ name: "moduleReference", test: isModuleReference }
];
case SyntaxKind.ExternalModuleReference: return [
{ name: "expression", test: isExpression, optional: true }
];
case SyntaxKind.EnumMember: return [
{ name: "name", test: isPropertyName },
{ name: "initializer", test: isExpression, optional: true, parenthesize: parenthesizeExpressionForList }
];
}
}
function reduceNode<T>(node: Node, f: (memo: T, node: Node) => T, initial: T) {
return node ? f(initial, node) : initial;
}
@@ -107,8 +16,7 @@ namespace ts {
/**
* Similar to `reduceLeft`, performs a reduction against each child of a node.
* NOTE: Unlike `forEachChild`, this does *not* visit every node. Only nodes added to the
* `nodeEdgeTraversalMap` above will be visited.
* NOTE: Unlike `forEachChild`, this does *not* visit every node.
*
* @param node The node containing the children to reduce.
* @param initial The initial value to supply to the reduction.
@@ -145,6 +53,11 @@ namespace ts {
break;
// Names
case SyntaxKind.QualifiedName:
result = reduceNode((<QualifiedName>node).left, cbNode, result);
result = reduceNode((<QualifiedName>node).right, cbNode, result);
break;
case SyntaxKind.ComputedPropertyName:
result = reduceNode((<ComputedPropertyName>node).expression, cbNode, result);
break;
@@ -252,6 +165,11 @@ namespace ts {
result = reduceNode((<TaggedTemplateExpression>node).template, cbNode, result);
break;
case SyntaxKind.TypeAssertionExpression:
result = reduceNode((<TypeAssertion>node).type, cbNode, result);
result = reduceNode((<TypeAssertion>node).expression, cbNode, result);
break;
case SyntaxKind.FunctionExpression:
result = reduceNodes((<FunctionExpression>node).modifiers, cbNodes, result);
result = reduceNode((<FunctionExpression>node).name, cbNode, result);
@@ -314,6 +232,15 @@ namespace ts {
result = reduceNodes((<ExpressionWithTypeArguments>node).typeArguments, cbNodes, result);
break;
case SyntaxKind.AsExpression:
result = reduceNode((<AsExpression>node).expression, cbNode, result);
result = reduceNode((<AsExpression>node).type, cbNode, result);
break;
case SyntaxKind.NonNullExpression:
result = reduceNode((<NonNullExpression>node).expression, cbNode, result);
break;
// Misc
case SyntaxKind.TemplateSpan:
result = reduceNode((<TemplateSpan>node).expression, cbNode, result);
@@ -415,10 +342,35 @@ namespace ts {
result = reduceNodes((<ClassDeclaration>node).members, cbNodes, result);
break;
case SyntaxKind.EnumDeclaration:
result = reduceNodes((<EnumDeclaration>node).decorators, cbNodes, result);
result = reduceNodes((<EnumDeclaration>node).modifiers, cbNodes, result);
result = reduceNode((<EnumDeclaration>node).name, cbNode, result);
result = reduceNodes((<EnumDeclaration>node).members, cbNodes, result);
break;
case SyntaxKind.ModuleDeclaration:
result = reduceNodes((<ModuleDeclaration>node).decorators, cbNodes, result);
result = reduceNodes((<ModuleDeclaration>node).modifiers, cbNodes, result);
result = reduceNode((<ModuleDeclaration>node).name, cbNode, result);
result = reduceNode((<ModuleDeclaration>node).body, cbNode, result);
break;
case SyntaxKind.ModuleBlock:
result = reduceNodes((<ModuleBlock>node).statements, cbNodes, result);
break;
case SyntaxKind.CaseBlock:
result = reduceNodes((<CaseBlock>node).clauses, cbNodes, result);
break;
case SyntaxKind.ImportEqualsDeclaration:
result = reduceNodes((<ImportEqualsDeclaration>node).decorators, cbNodes, result);
result = reduceNodes((<ImportEqualsDeclaration>node).modifiers, cbNodes, result);
result = reduceNode((<ImportEqualsDeclaration>node).name, cbNode, result);
result = reduceNode((<ImportEqualsDeclaration>node).moduleReference, cbNode, result);
break;
case SyntaxKind.ImportDeclaration:
result = reduceNodes((<ImportDeclaration>node).decorators, cbNodes, result);
result = reduceNodes((<ImportDeclaration>node).modifiers, cbNodes, result);
@@ -459,6 +411,11 @@ namespace ts {
result = reduceNode((<ExportDeclaration>node).moduleSpecifier, cbNode, result);
break;
// Module references
case SyntaxKind.ExternalModuleReference:
result = reduceNode((<ExternalModuleReference>node).expression, cbNode, result);
break;
// JSX
case SyntaxKind.JsxElement:
result = reduceNode((<JsxElement>node).openingElement, cbNode, result);
@@ -523,30 +480,25 @@ namespace ts {
break;
case SyntaxKind.SpreadAssignment:
result = reduceNode((node as SpreadAssignment).expression, cbNode, result);
result = reduceNode((<SpreadAssignment>node).expression, cbNode, result);
break;
// Enum
case SyntaxKind.EnumMember:
result = reduceNode((<EnumMember>node).name, cbNode, result);
result = reduceNode((<EnumMember>node).initializer, cbNode, result);
// Top-level nodes
case SyntaxKind.SourceFile:
result = reduceNodes((<SourceFile>node).statements, cbNodes, result);
break;
// Transformation nodes
case SyntaxKind.PartiallyEmittedExpression:
result = reduceNode((<PartiallyEmittedExpression>node).expression, cbNode, result);
break;
default:
const edgeTraversalPath = getNodeEdgeTraversal(kind);
if (edgeTraversalPath) {
for (const edge of edgeTraversalPath) {
const value = (<MapLike<any>>node)[edge.name];
if (value !== undefined) {
result = isArray(value)
? reduceNodes(<NodeArray<Node>>value, cbNodes, result)
: cbNode(result, <Node>value);
}
}
}
break;
}
@@ -560,11 +512,9 @@ namespace ts {
* @param visitor The callback used to visit the Node.
* @param test A callback to execute to verify the Node is valid.
* @param optional An optional value indicating whether the Node is itself optional.
* @param lift An optional callback to execute to lift a NodeArrayNode into a valid Node.
* @param lift An optional callback to execute to lift a NodeArray into a valid Node.
*/
export function visitNode<T extends Node>(node: T, visitor: (node: Node) => VisitResult<Node>, test: (node: Node) => boolean, optional?: boolean, lift?: (node: NodeArray<Node>) => T): T;
export function visitNode<T extends Node>(node: T, visitor: (node: Node) => VisitResult<Node>, test: (node: Node) => boolean, optional: boolean, lift: (node: NodeArray<Node>) => T, parenthesize: (node: Node, parentNode: Node) => Node, parentNode: Node): T;
export function visitNode(node: Node, visitor: (node: Node) => VisitResult<Node>, test: (node: Node) => boolean, optional?: boolean, lift?: (node: Node[]) => Node, parenthesize?: (node: Node, parentNode: Node) => Node, parentNode?: Node): Node {
export function visitNode<T extends Node>(node: T, visitor: (node: Node) => VisitResult<Node>, test: (node: Node) => boolean, optional?: boolean, lift?: (node: NodeArray<Node>) => T): T {
if (node === undefined || visitor === undefined) {
return node;
}
@@ -590,13 +540,9 @@ namespace ts {
visitedNode = visited;
}
if (parenthesize !== undefined) {
visitedNode = parenthesize(visitedNode, parentNode);
}
Debug.assertNode(visitedNode, test);
aggregateTransformFlags(visitedNode);
return visitedNode;
return <T>visitedNode;
}
/**
@@ -608,14 +554,12 @@ namespace ts {
* @param start An optional value indicating the starting offset at which to start visiting.
* @param count An optional value indicating the maximum number of nodes to visit.
*/
export function visitNodes<T extends Node>(nodes: NodeArray<T>, visitor: (node: Node) => VisitResult<Node>, test: (node: Node) => boolean, start?: number, count?: number): NodeArray<T>;
export function visitNodes<T extends Node>(nodes: NodeArray<T>, visitor: (node: Node) => VisitResult<Node>, test: (node: Node) => boolean, start: number, count: number, parenthesize: (node: Node, parentNode: Node) => Node, parentNode: Node): NodeArray<T>;
export function visitNodes(nodes: NodeArray<Node>, visitor: (node: Node) => VisitResult<Node>, test: (node: Node) => boolean, start?: number, count?: number, parenthesize?: (node: Node, parentNode: Node) => Node, parentNode?: Node): NodeArray<Node> {
export function visitNodes<T extends Node>(nodes: NodeArray<T>, visitor: (node: Node) => VisitResult<Node>, test: (node: Node) => boolean, start?: number, count?: number): NodeArray<T> {
if (nodes === undefined) {
return undefined;
}
let updated: NodeArray<Node>;
let updated: NodeArray<T>;
// Ensure start and count have valid values
const length = nodes.length;
@@ -631,8 +575,7 @@ namespace ts {
// If we are not visiting all of the original nodes, we must always create a new array.
// Since this is a fragment of a node array, we do not copy over the previous location
// and will only copy over `hasTrailingComma` if we are including the last element.
updated = createNodeArray<Node>([], /*location*/ undefined,
/*hasTrailingComma*/ nodes.hasTrailingComma && start + count === length);
updated = createNodeArray<T>([], /*hasTrailingComma*/ nodes.hasTrailingComma && start + count === length);
}
// Visit each original node.
@@ -643,26 +586,21 @@ namespace ts {
if (updated !== undefined || visited === undefined || visited !== node) {
if (updated === undefined) {
// Ensure we have a copy of `nodes`, up to the current index.
updated = createNodeArray(nodes.slice(0, i), /*location*/ nodes, nodes.hasTrailingComma);
updated = createNodeArray(nodes.slice(0, i), nodes.hasTrailingComma);
setTextRange(updated, nodes);
}
if (visited) {
if (isArray(visited)) {
for (let visitedNode of visited) {
visitedNode = parenthesize
? parenthesize(visitedNode, parentNode)
: visitedNode;
for (const visitedNode of visited) {
Debug.assertNode(visitedNode, test);
aggregateTransformFlags(visitedNode);
updated.push(visitedNode);
updated.push(<T>visitedNode);
}
}
else {
const visitedNode = parenthesize
? parenthesize(visited, parentNode)
: visited;
Debug.assertNode(visitedNode, test);
aggregateTransformFlags(visitedNode);
updated.push(visitedNode);
Debug.assertNode(visited, test);
aggregateTransformFlags(visited);
updated.push(<T>visited);
}
}
}
@@ -679,10 +617,10 @@ namespace ts {
context.startLexicalEnvironment();
statements = visitNodes(statements, visitor, isStatement, start);
if (ensureUseStrict && !startsWithUseStrict(statements)) {
statements = createNodeArray([createStatement(createLiteral("use strict")), ...statements], statements);
statements = setTextRange(createNodeArray([createStatement(createLiteral("use strict")), ...statements]), statements);
}
const declarations = context.endLexicalEnvironment();
return createNodeArray(concatenate(statements, declarations), statements);
return setTextRange(createNodeArray(concatenate(statements, declarations)), statements);
}
/**
@@ -751,6 +689,11 @@ namespace ts {
return node;
// Names
case SyntaxKind.QualifiedName:
return updateQualifiedName(<QualifiedName>node,
visitNode((<QualifiedName>node).left, visitor, isEntityName),
visitNode((<QualifiedName>node).right, visitor, isIdentifier));
case SyntaxKind.ComputedPropertyName:
return updateComputedPropertyName(<ComputedPropertyName>node,
visitNode((<ComputedPropertyName>node).expression, visitor, isExpression));
@@ -765,6 +708,10 @@ namespace ts {
visitNode((<ParameterDeclaration>node).type, visitor, isTypeNode, /*optional*/ true),
visitNode((<ParameterDeclaration>node).initializer, visitor, isExpression, /*optional*/ true));
case SyntaxKind.Decorator:
return updateDecorator(<Decorator>node,
visitNode((<Decorator>node).expression, visitor, isExpression));
// Type member
case SyntaxKind.PropertyDeclaration:
return updateProperty(<PropertyDeclaration>node,
@@ -860,6 +807,11 @@ namespace ts {
visitNode((<TaggedTemplateExpression>node).tag, visitor, isExpression),
visitNode((<TaggedTemplateExpression>node).template, visitor, isTemplateLiteral));
case SyntaxKind.TypeAssertionExpression:
return updateTypeAssertion(<TypeAssertion>node,
visitNode((<TypeAssertion>node).type, visitor, isTypeNode),
visitNode((<TypeAssertion>node).expression, visitor, isExpression));
case SyntaxKind.ParenthesizedExpression:
return updateParen(<ParenthesizedExpression>node,
visitNode((<ParenthesizedExpression>node).expression, visitor, isExpression));
@@ -942,6 +894,15 @@ namespace ts {
visitNodes((<ExpressionWithTypeArguments>node).typeArguments, visitor, isTypeNode),
visitNode((<ExpressionWithTypeArguments>node).expression, visitor, isExpression));
case SyntaxKind.AsExpression:
return updateAsExpression(<AsExpression>node,
visitNode((<AsExpression>node).expression, visitor, isExpression),
visitNode((<AsExpression>node).type, visitor, isTypeNode));
case SyntaxKind.NonNullExpression:
return updateNonNullExpression(<NonNullExpression>node,
visitNode((<NonNullExpression>node).expression, visitor, isExpression));
// Misc
case SyntaxKind.TemplateSpan:
return updateTemplateSpan(<TemplateSpan>node,
@@ -1063,10 +1024,35 @@ namespace ts {
visitNodes((<ClassDeclaration>node).heritageClauses, visitor, isHeritageClause),
visitNodes((<ClassDeclaration>node).members, visitor, isClassElement));
case SyntaxKind.EnumDeclaration:
return updateEnumDeclaration(<EnumDeclaration>node,
visitNodes((<EnumDeclaration>node).decorators, visitor, isDecorator),
visitNodes((<EnumDeclaration>node).modifiers, visitor, isModifier),
visitNode((<EnumDeclaration>node).name, visitor, isIdentifier),
visitNodes((<EnumDeclaration>node).members, visitor, isEnumMember));
case SyntaxKind.ModuleDeclaration:
return updateModuleDeclaration(<ModuleDeclaration>node,
visitNodes((<ModuleDeclaration>node).decorators, visitor, isDecorator),
visitNodes((<ModuleDeclaration>node).modifiers, visitor, isModifier),
visitNode((<ModuleDeclaration>node).name, visitor, isIdentifier),
visitNode((<ModuleDeclaration>node).body, visitor, isModuleBody));
case SyntaxKind.ModuleBlock:
return updateModuleBlock(<ModuleBlock>node,
visitNodes((<ModuleBlock>node).statements, visitor, isStatement));
case SyntaxKind.CaseBlock:
return updateCaseBlock(<CaseBlock>node,
visitNodes((<CaseBlock>node).clauses, visitor, isCaseOrDefaultClause));
case SyntaxKind.ImportEqualsDeclaration:
return updateImportEqualsDeclaration(<ImportEqualsDeclaration>node,
visitNodes((<ImportEqualsDeclaration>node).decorators, visitor, isDecorator),
visitNodes((<ImportEqualsDeclaration>node).modifiers, visitor, isModifier),
visitNode((<ImportEqualsDeclaration>node).name, visitor, isIdentifier),
visitNode((<ImportEqualsDeclaration>node).moduleReference, visitor, isModuleReference));
case SyntaxKind.ImportDeclaration:
return updateImportDeclaration(<ImportDeclaration>node,
visitNodes((<ImportDeclaration>node).decorators, visitor, isDecorator),
@@ -1114,6 +1100,11 @@ namespace ts {
visitNode((<ExportSpecifier>node).propertyName, visitor, isIdentifier, /*optional*/ true),
visitNode((<ExportSpecifier>node).name, visitor, isIdentifier));
// Module references
case SyntaxKind.ExternalModuleReference:
return updateExternalModuleReference(<ExternalModuleReference>node,
visitNode((<ExternalModuleReference>node).expression, visitor, isExpression));
// JSX
case SyntaxKind.JsxElement:
return updateJsxElement(<JsxElement>node,
@@ -1183,10 +1174,16 @@ namespace ts {
visitNode((<ShorthandPropertyAssignment>node).objectAssignmentInitializer, visitor, isExpression));
case SyntaxKind.SpreadAssignment:
return updateSpreadAssignment(node as SpreadAssignment,
visitNode((node as SpreadAssignment).expression, visitor, isExpression));
return updateSpreadAssignment(<SpreadAssignment>node,
visitNode((<SpreadAssignment>node).expression, visitor, isExpression));
// Top-level nodes
// Enum
case SyntaxKind.EnumMember:
return updateEnumMember(<EnumMember>node,
visitNode((<EnumMember>node).name, visitor, isPropertyName),
visitNode((<EnumMember>node).initializer, visitor, isExpression, /*optional*/ true));
// Top-level nodes
case SyntaxKind.SourceFile:
return updateSourceFileNode(<SourceFile>node,
visitLexicalEnvironment((<SourceFile>node).statements, visitor, context));
@@ -1197,30 +1194,8 @@ namespace ts {
visitNode((<PartiallyEmittedExpression>node).expression, visitor, isExpression));
default:
let updated: Node & MapLike<any>;
const edgeTraversalPath = getNodeEdgeTraversal(kind);
if (edgeTraversalPath) {
for (const edge of edgeTraversalPath) {
const value = <Node | NodeArray<Node>>(<Node & MapLike<any>>node)[edge.name];
if (value !== undefined) {
const visited = isArray(value)
? visitNodes(value, visitor, edge.test, 0, value.length, edge.parenthesize, node)
: visitNode(value, visitor, edge.test, edge.optional, edge.lift, edge.parenthesize, node);
if (updated !== undefined || visited !== value) {
if (updated === undefined) {
updated = getMutableClone(node);
}
if (visited !== value) {
updated[edge.name] = visited;
}
}
}
}
}
return updated ? updateNode(updated, node) : node;
return node;
}
// return node;
}
/**
@@ -1236,7 +1211,7 @@ namespace ts {
return statements;
}
return isNodeArray(statements)
? createNodeArray(concatenate(statements, declarations), statements)
? setTextRange(createNodeArray(concatenate(statements, declarations)), statements)
: addRange(statements, declarations);
}
@@ -1260,13 +1235,19 @@ namespace ts {
export function mergeFunctionBodyLexicalEnvironment(body: ConciseBody, declarations: Statement[]): ConciseBody {
if (body && declarations !== undefined && declarations.length > 0) {
if (isBlock(body)) {
return updateBlock(body, createNodeArray(concatenate(body.statements, declarations), body.statements));
return updateBlock(body, setTextRange(createNodeArray(concatenate(body.statements, declarations)), body.statements));
}
else {
return createBlock(
createNodeArray([createReturn(body, /*location*/ body), ...declarations], body),
/*location*/ body,
/*multiLine*/ true);
return setTextRange(
createBlock(
setTextRange(
createNodeArray([setTextRange(createReturn(body), body), ...declarations]),
body
),
/*multiLine*/ true
),
/*location*/ body
);
}
}
return body;
+125 -36
View File
@@ -183,7 +183,7 @@ namespace FourSlash {
// The current caret position in the active file
public currentCaretPosition = 0;
public lastKnownMarker: string = "";
public lastKnownMarker = "";
// The file that's currently 'opened'
public activeFile: FourSlashFile;
@@ -263,6 +263,20 @@ namespace FourSlash {
// Create map between fileName and its content for easily looking up when resolveReference flag is specified
this.inputFiles.set(file.fileName, file.content);
if (ts.getBaseFileName(file.fileName).toLowerCase() === "tsconfig.json") {
const configJson = ts.parseConfigFileTextToJson(file.fileName, file.content);
if (configJson.config === undefined) {
throw new Error(`Failed to parse test tsconfig.json: ${configJson.error.messageText}`);
}
// Extend our existing compiler options so that we can also support tsconfig only options
if (configJson.config.compilerOptions) {
const baseDirectory = ts.normalizePath(ts.getDirectoryPath(file.fileName));
const tsConfig = ts.convertCompilerOptionsFromJson(configJson.config.compilerOptions, baseDirectory, file.fileName);
if (!tsConfig.errors || !tsConfig.errors.length) {
compilationOptions = ts.extend(compilationOptions, tsConfig.options);
}
}
configFileName = file.fileName;
}
@@ -452,7 +466,8 @@ namespace FourSlash {
}
private messageAtLastKnownMarker(message: string) {
return "Marker: " + this.lastKnownMarker + "\n" + message;
const locationDescription = this.lastKnownMarker ? this.lastKnownMarker : this.getLineColStringAtPosition(this.currentCaretPosition);
return `At ${locationDescription}: ${message}`;
}
private assertionMessageAtLastKnownMarker(msg: string) {
@@ -562,7 +577,7 @@ namespace FourSlash {
}
public verifyGoToDefinitionIs(endMarker: string | string[]) {
this.verifyGoToXWorker(endMarker instanceof Array ? endMarker : [endMarker], () => this.getGoToDefinition());
this.verifyGoToXWorker(toArray(endMarker), () => this.getGoToDefinition());
}
public verifyGoToDefinition(arg0: any, endMarkerNames?: string | string[]) {
@@ -582,7 +597,7 @@ namespace FourSlash {
if (endMarkerNames) {
this.verifyGoToXPlain(arg0, endMarkerNames, getDefs);
}
else if (arg0 instanceof Array) {
else if (ts.isArray(arg0)) {
const pairs: [string | string[], string | string[]][] = arg0;
for (const [start, end] of pairs) {
this.verifyGoToXPlain(start, end, getDefs);
@@ -599,13 +614,8 @@ namespace FourSlash {
}
private verifyGoToXPlain(startMarkerNames: string | string[], endMarkerNames: string | string[], getDefs: () => ts.DefinitionInfo[] | undefined) {
if (startMarkerNames instanceof Array) {
for (const start of startMarkerNames) {
this.verifyGoToXSingle(start, endMarkerNames, getDefs);
}
}
else {
this.verifyGoToXSingle(startMarkerNames, endMarkerNames, getDefs);
for (const start of toArray(startMarkerNames)) {
this.verifyGoToXSingle(start, endMarkerNames, getDefs);
}
}
@@ -617,7 +627,7 @@ namespace FourSlash {
private verifyGoToXSingle(startMarkerName: string, endMarkerNames: string | string[], getDefs: () => ts.DefinitionInfo[] | undefined) {
this.goToMarker(startMarkerName);
this.verifyGoToXWorker(endMarkerNames instanceof Array ? endMarkerNames : [endMarkerNames], getDefs);
this.verifyGoToXWorker(toArray(endMarkerNames), getDefs);
}
private verifyGoToXWorker(endMarkers: string[], getDefs: () => ts.DefinitionInfo[] | undefined) {
@@ -899,8 +909,74 @@ namespace FourSlash {
}
}
public verifyRangesWithSameTextReferenceEachOther() {
this.rangesByText().forEach(ranges => this.verifyRangesReferenceEachOther(ranges));
public verifyReferenceGroups(startRanges: Range | Range[], parts: Array<{ definition: string, ranges: Range[] }>): void {
interface ReferenceJson { definition: string; ranges: ts.ReferenceEntry[]; }
type ReferencesJson = ReferenceJson[];
const fullExpected = parts.map<ReferenceJson>(({ definition, ranges }) => ({ definition, ranges: ranges.map(rangeToReferenceEntry) }));
for (const startRange of toArray(startRanges)) {
this.goToRangeStart(startRange);
const fullActual = this.findReferencesAtCaret().map<ReferenceJson>(({ definition, references }) => ({
definition: definition.displayParts.map(d => d.text).join(""),
ranges: references
}));
this.assertObjectsEqual<ReferencesJson>(fullActual, fullExpected);
}
function rangeToReferenceEntry(r: Range) {
let { isWriteAccess, isDefinition } = (r.marker && r.marker.data) || { isWriteAccess: false, isDefinition: false };
isWriteAccess = !!isWriteAccess; isDefinition = !!isDefinition;
return { fileName: r.fileName, textSpan: { start: r.start, length: r.end - r.start }, isWriteAccess, isDefinition }
}
}
public verifyNoReferences(markerNameOrRange?: string | Range) {
if (markerNameOrRange) {
if (typeof markerNameOrRange === "string") {
this.goToMarker(markerNameOrRange);
}
else {
this.goToRangeStart(markerNameOrRange);
}
}
const refs = this.getReferencesAtCaret();
if (refs && refs.length) {
console.log(refs);
this.raiseError("Expected getReferences to fail");
}
}
public verifySingleReferenceGroup(definition: string, ranges?: Range[]) {
ranges = ranges || this.getRanges();
this.verifyReferenceGroups(ranges, [{ definition, ranges }]);
}
private assertObjectsEqual<T>(fullActual: T, fullExpected: T, msgPrefix = ""): void {
const recur = <U>(actual: U, expected: U, path: string) => {
const fail = (msg: string) => {
console.log("Expected:", stringify(fullExpected));
console.log("Actual: ", stringify(fullActual));
this.raiseError(`${msgPrefix}At ${path}: ${msg}`);
};
for (const key in actual) if (ts.hasProperty(actual as any, key)) {
const ak = actual[key], ek = expected[key];
if (typeof ak === "object" && typeof ek === "object") {
recur(ak, ek, path ? path + "." + key : key);
}
else if (ak !== ek) {
fail(`Expected '${key}' to be '${ek}', got '${ak}'`);
}
}
for (const key in expected) if (ts.hasProperty(expected as any, key)) {
if (!ts.hasProperty(actual as any, key)) {
fail(`${msgPrefix}Missing property '${key}'`);
}
}
};
recur(fullActual, fullExpected, "");
}
public verifyDisplayPartsOfReferencedSymbol(expected: ts.SymbolDisplayPart[]) {
@@ -974,7 +1050,7 @@ namespace FourSlash {
public verifyQuickInfos(namesAndTexts: { [name: string]: string | [string, string] }) {
for (const name in namesAndTexts) if (ts.hasProperty(namesAndTexts, name)) {
const text = namesAndTexts[name];
if (text instanceof Array) {
if (ts.isArray(text)) {
assert(text.length === 2);
const [expectedText, expectedDocumentation] = text;
this.verifyQuickInfoAt(name, expectedText, expectedDocumentation);
@@ -1411,13 +1487,6 @@ namespace FourSlash {
Harness.IO.log(membersString);
}
public printReferences() {
const references = this.getReferencesAtCaret();
ts.forEach(references, entry => {
Harness.IO.log(stringify(entry));
});
}
public printContext() {
ts.forEach(this.languageServiceAdapterHost.getFilenames(), Harness.IO.log);
}
@@ -2053,7 +2122,7 @@ namespace FourSlash {
* Because codefixes are only applied on the working file, it is unsafe
* to apply this more than once (consider a refactoring across files).
*/
public verifyRangeAfterCodeFix(expectedText: string, errorCode?: number) {
public verifyRangeAfterCodeFix(expectedText: string, errorCode?: number, includeWhiteSpace?: boolean) {
const ranges = this.getRanges();
if (ranges.length !== 1) {
this.raiseError("Exactly one range should be specified in the testfile.");
@@ -2065,7 +2134,11 @@ namespace FourSlash {
const actualText = this.rangeText(ranges[0]);
if (this.removeWhitespace(actualText) !== this.removeWhitespace(expectedText)) {
const result = includeWhiteSpace
? actualText === expectedText
: this.removeWhitespace(actualText) === this.removeWhitespace(expectedText)
if (!result) {
this.raiseError(`Actual text doesn't match expected text. Actual:\n'${actualText}'\nExpected:\n'${expectedText}'`);
}
}
@@ -2095,10 +2168,18 @@ namespace FourSlash {
* @param fileName Path to file where error should be retrieved from.
*/
private getCodeFixActions(fileName: string, errorCode?: number): ts.CodeAction[] {
const diagnostics: ts.Diagnostic[] = this.getDiagnostics(fileName);
const diagnosticsForCodeFix = this.getDiagnostics(fileName).map(diagnostic => {
return {
start: diagnostic.start,
length: diagnostic.length,
code: diagnostic.code
}
});
const dedupedDiagnositcs = ts.deduplicate(diagnosticsForCodeFix, ts.equalOwnProperties);
let actions: ts.CodeAction[] = undefined;
for (const diagnostic of diagnostics) {
for (const diagnostic of dedupedDiagnositcs) {
if (errorCode && errorCode !== diagnostic.code) {
continue;
@@ -3082,6 +3163,10 @@ ${code}
}
return ts.arrayFrom(set.keys());
}
function toArray<T>(x: T | T[]): T[] {
return ts.isArray(x) ? x : [x];
}
}
namespace FourSlashInterface {
@@ -3346,6 +3431,18 @@ namespace FourSlashInterface {
this.state.verifyReferencesOf(start, references);
}
public referenceGroups(startRanges: FourSlash.Range[], parts: Array<{ definition: string, ranges: FourSlash.Range[] }>) {
this.state.verifyReferenceGroups(startRanges, parts);
}
public noReferences(markerNameOrRange?: string | FourSlash.Range) {
this.state.verifyNoReferences(markerNameOrRange);
}
public singleReferenceGroup(definition: string, ranges?: FourSlash.Range[]) {
this.state.verifySingleReferenceGroup(definition, ranges);
}
public rangesReferenceEachOther(ranges?: FourSlash.Range[]) {
this.state.verifyRangesReferenceEachOther(ranges);
}
@@ -3354,10 +3451,6 @@ namespace FourSlashInterface {
this.state.verifyDisplayPartsOfReferencedSymbol(expected);
}
public rangesWithSameTextReferenceEachOther() {
this.state.verifyRangesWithSameTextReferenceEachOther();
}
public currentParameterHelpArgumentNameIs(name: string) {
this.state.verifyCurrentParameterHelpName(name);
}
@@ -3442,8 +3535,8 @@ namespace FourSlashInterface {
this.DocCommentTemplate(/*expectedText*/ undefined, /*expectedOffset*/ undefined, /*empty*/ true);
}
public rangeAfterCodeFix(expectedText: string, errorCode?: number): void {
this.state.verifyRangeAfterCodeFix(expectedText, errorCode);
public rangeAfterCodeFix(expectedText: string, errorCode?: number, includeWhiteSpace?: boolean): void {
this.state.verifyRangeAfterCodeFix(expectedText, errorCode, includeWhiteSpace);
}
public importFixAtPosition(expectedTextArray: string[], errorCode?: number): void {
@@ -3660,10 +3753,6 @@ namespace FourSlashInterface {
this.state.printNavigationBar();
}
public printReferences() {
this.state.printReferences();
}
public printContext() {
this.state.printContext();
}
+88 -7
View File
@@ -5,7 +5,7 @@
namespace Harness.LanguageService {
export class ScriptInfo {
public version: number = 1;
public version = 1;
public editRanges: { length: number; textChangeRange: ts.TextChangeRange; }[] = [];
private lineMap: number[] = undefined;
@@ -126,7 +126,7 @@ namespace Harness.LanguageService {
protected virtualFileSystem: Utils.VirtualFileSystem = new Utils.VirtualFileSystem(virtualFileSystemRoot, /*useCaseSensitiveFilenames*/false);
constructor(protected cancellationToken = DefaultHostCancellationToken.Instance,
protected settings = ts.getDefaultCompilerOptions()) {
protected settings = ts.getDefaultCompilerOptions()) {
}
public getNewLine(): string {
@@ -135,7 +135,7 @@ namespace Harness.LanguageService {
public getFilenames(): string[] {
const fileNames: string[] = [];
for (const virtualEntry of this.virtualFileSystem.getAllFileEntries()){
for (const virtualEntry of this.virtualFileSystem.getAllFileEntries()) {
const scriptInfo = virtualEntry.content;
if (scriptInfo.isRootFile) {
// only include root files here
@@ -211,8 +211,8 @@ namespace Harness.LanguageService {
readDirectory(path: string, extensions?: string[], exclude?: string[], include?: string[]): string[] {
return ts.matchFiles(path, extensions, exclude, include,
/*useCaseSensitiveFileNames*/false,
this.getCurrentDirectory(),
(p) => this.virtualFileSystem.getAccessibleFileSystemEntries(p));
this.getCurrentDirectory(),
(p) => this.virtualFileSystem.getAccessibleFileSystemEntries(p));
}
readFile(path: string): string {
const snapshot = this.getScriptSnapshot(path);
@@ -594,7 +594,7 @@ namespace Harness.LanguageService {
class SessionServerHost implements ts.server.ServerHost, ts.server.Logger {
args: string[] = [];
newLine: string;
useCaseSensitiveFileNames: boolean = false;
useCaseSensitiveFileNames = false;
constructor(private host: NativeLanguageServiceHost) {
this.newLine = this.host.getNewLine();
@@ -724,6 +724,87 @@ namespace Harness.LanguageService {
createHash(s: string) {
return s;
}
require(_initialDir: string, _moduleName: string): ts.server.RequireResult {
switch (_moduleName) {
// Adds to the Quick Info a fixed string and a string from the config file
// and replaces the first display part
case "quickinfo-augmeneter":
return {
module: () => ({
create(info: ts.server.PluginCreateInfo) {
const proxy = makeDefaultProxy(info);
const langSvc: any = info.languageService;
proxy.getQuickInfoAtPosition = function () {
const parts = langSvc.getQuickInfoAtPosition.apply(langSvc, arguments);
if (parts.displayParts.length > 0) {
parts.displayParts[0].text = "Proxied";
}
parts.displayParts.push({ text: info.config.message, kind: "punctuation" });
return parts;
};
return proxy;
}
}),
error: undefined
};
// Throws during initialization
case "create-thrower":
return {
module: () => ({
create() {
throw new Error("I am not a well-behaved plugin");
}
}),
error: undefined
};
// Adds another diagnostic
case "diagnostic-adder":
return {
module: () => ({
create(info: ts.server.PluginCreateInfo) {
const proxy = makeDefaultProxy(info);
proxy.getSemanticDiagnostics = function (filename: string) {
const prev = info.languageService.getSemanticDiagnostics(filename);
const sourceFile: ts.SourceFile = info.languageService.getSourceFile(filename);
prev.push({
category: ts.DiagnosticCategory.Warning,
file: sourceFile,
code: 9999,
length: 3,
messageText: `Plugin diagnostic`,
start: 0
});
return prev;
}
return proxy;
}
}),
error: undefined
};
default:
return {
module: undefined,
error: "Could not resolve module"
};
}
function makeDefaultProxy(info: ts.server.PluginCreateInfo) {
// tslint:disable-next-line:no-null-keyword
const proxy = Object.create(null);
const langSvc: any = info.languageService;
for (const k of Object.keys(langSvc)) {
proxy[k] = function () {
return langSvc[k].apply(langSvc, arguments);
};
}
return proxy;
}
}
}
export class ServerLanguageServiceAdapter implements LanguageServiceAdapter {
@@ -738,7 +819,7 @@ namespace Harness.LanguageService {
// host to answer server queries about files on disk
const serverHost = new SessionServerHost(clientHost);
const server = new ts.server.Session(serverHost,
{ isCancellationRequested: () => false },
ts.server.nullCancellationToken,
/*useOneInferredProject*/ false,
/*typingsInstaller*/ undefined,
Utils.byteLength,
+2 -1
View File
@@ -118,6 +118,7 @@
"./unittests/initializeTSConfig.ts",
"./unittests/compileOnSave.ts",
"./unittests/typingsInstaller.ts",
"./unittests/projectErrors.ts"
"./unittests/projectErrors.ts",
"./unittests/printer.ts"
]
}
+2 -1
View File
@@ -4,6 +4,7 @@
namespace ts.projectSystem {
import CommandNames = server.CommandNames;
const nullCancellationToken = server.nullCancellationToken;
function createTestTypingsInstaller(host: server.ServerHost) {
return new TestTypingsInstaller("/a/data/", /*throttleLimit*/5, host);
@@ -520,7 +521,7 @@ namespace ts.projectSystem {
const expectedEmittedFileName = "/a/b/f1.js";
assert.isTrue(host.fileExists(expectedEmittedFileName));
assert.equal(host.readFile(expectedEmittedFileName), `"use strict";\r\nfunction Foo() { return 10; }\r\nexports.Foo = Foo;\r\n`);
assert.equal(host.readFile(expectedEmittedFileName), `"use strict";\r\nexports.__esModule = true;\r\nfunction Foo() { return 10; }\r\nexports.Foo = Foo;\r\n`);
});
it("shoud not emit js files in external projects", () => {
+97
View File
@@ -0,0 +1,97 @@
/// <reference path="..\..\compiler\emitter.ts" />
/// <reference path="..\harness.ts" />
namespace ts {
describe("PrinterAPI", () => {
function makePrintsCorrectly(prefix: string) {
return function printsCorrectly(name: string, options: PrinterOptions, printCallback: (printer: Printer) => string) {
it(name, () => {
Harness.Baseline.runBaseline(`printerApi/${prefix}.${name}.js`, () =>
printCallback(createPrinter({ newLine: NewLineKind.CarriageReturnLineFeed, ...options })));
});
}
}
describe("printFile", () => {
const printsCorrectly = makePrintsCorrectly("printsFileCorrectly");
const sourceFile = createSourceFile("source.ts", `
interface A<T> {
// comment1
readonly prop?: T;
// comment2
method(): void;
// comment3
new <T>(): A<T>;
// comment4
<T>(): A<T>;
}
// comment5
type B = number | string | object;
type C = A<number> & { x: string; }; // comment6
// comment7
enum E1 {
// comment8
first
}
const enum E2 {
second
}
// comment9
console.log(1 + 2);
`, ScriptTarget.ES2015);
printsCorrectly("default", {}, printer => printer.printFile(sourceFile));
printsCorrectly("removeComments", { removeComments: true }, printer => printer.printFile(sourceFile));
});
describe("printBundle", () => {
const printsCorrectly = makePrintsCorrectly("printsBundleCorrectly");
const bundle = createBundle([
createSourceFile("a.ts", `
/*! [a.ts] */
// comment0
const a = 1;
`, ScriptTarget.ES2015),
createSourceFile("b.ts", `
/*! [b.ts] */
// comment1
const b = 2;
`, ScriptTarget.ES2015)
]);
printsCorrectly("default", {}, printer => printer.printBundle(bundle));
printsCorrectly("removeComments", { removeComments: true }, printer => printer.printBundle(bundle));
});
describe("printNode", () => {
const printsCorrectly = makePrintsCorrectly("printsNodeCorrectly");
const sourceFile = createSourceFile("source.ts", "", ScriptTarget.ES2015);
const syntheticNode = createClassDeclaration(
undefined,
undefined,
/*name*/ createIdentifier("C"),
undefined,
undefined,
createNodeArray([
createProperty(
undefined,
createNodeArray([createToken(SyntaxKind.PublicKeyword)]),
createIdentifier("prop"),
undefined,
undefined,
undefined
)
])
);
printsCorrectly("class", {}, printer => printer.printNode(EmitHint.Unspecified, syntheticNode, sourceFile));
});
});
}
+1 -1
View File
@@ -27,7 +27,7 @@ namespace ts.server {
clearImmediate: noop,
createHash: s => s
};
const nullCancellationToken: HostCancellationToken = { isCancellationRequested: () => false };
const mockLogger: Logger = {
close: noop,
hasLevel(): boolean { return false; },
+424 -11
View File
@@ -34,10 +34,6 @@ namespace ts.projectSystem {
getLogFileName: (): string => undefined
};
export const nullCancellationToken: HostCancellationToken = {
isCancellationRequested: () => false
};
export const { content: libFileContent } = Harness.getDefaultLibraryFile(Harness.IO);
export const libFile: FileOrFolder = {
path: "/a/lib/lib.d.ts",
@@ -158,17 +154,33 @@ namespace ts.projectSystem {
}
class TestSession extends server.Session {
private seq = 0;
getProjectService() {
return this.projectService;
}
public getSeq() {
return this.seq;
}
public getNextSeq() {
return this.seq + 1;
}
public executeCommandSeq<T extends server.protocol.Request>(request: Partial<T>) {
this.seq++;
request.seq = this.seq;
request.type = "request";
return this.executeCommand(<T>request);
}
};
export function createSession(host: server.ServerHost, typingsInstaller?: server.ITypingsInstaller, projectServiceEventHandler?: server.ProjectServiceEventHandler) {
export function createSession(host: server.ServerHost, typingsInstaller?: server.ITypingsInstaller, projectServiceEventHandler?: server.ProjectServiceEventHandler, cancellationToken?: server.ServerCancellationToken) {
if (typingsInstaller === undefined) {
typingsInstaller = new TestTypingsInstaller("/a/data/", /*throttleLimit*/5, host);
}
return new TestSession(host, nullCancellationToken, /*useSingleInferredProject*/ false, typingsInstaller, Utils.byteLength, process.hrtime, nullLogger, /*canUseEvents*/ projectServiceEventHandler !== undefined, projectServiceEventHandler);
return new TestSession(host, cancellationToken || server.nullCancellationToken, /*useSingleInferredProject*/ false, typingsInstaller, Utils.byteLength, process.hrtime, nullLogger, /*canUseEvents*/ projectServiceEventHandler !== undefined, projectServiceEventHandler);
}
export interface CreateProjectServiceParameters {
@@ -191,7 +203,7 @@ namespace ts.projectSystem {
}
}
export function createProjectService(host: server.ServerHost, parameters: CreateProjectServiceParameters = {}) {
const cancellationToken = parameters.cancellationToken || nullCancellationToken;
const cancellationToken = parameters.cancellationToken || server.nullCancellationToken;
const logger = parameters.logger || nullLogger;
const useSingleInferredProject = parameters.useSingleInferredProject !== undefined ? parameters.useSingleInferredProject : false;
return new TestProjectService(host, logger, cancellationToken, useSingleInferredProject, parameters.typingsInstaller, parameters.eventHandler);
@@ -328,6 +340,8 @@ namespace ts.projectSystem {
export class TestServerHost implements server.ServerHost {
args: string[] = [];
private readonly output: string[] = [];
private fs: ts.FileMap<FSEntry>;
private getCanonicalFileName: (s: string) => string;
private toPath: (f: string) => Path;
@@ -477,6 +491,10 @@ namespace ts.projectSystem {
this.timeoutCallbacks.invoke();
}
runQueuedImmediateCallbacks() {
this.immediateCallbacks.invoke();
}
setImmediate(callback: TimeOutCallback, _time: number, ...args: any[]) {
return this.immediateCallbacks.register(callback, args);
}
@@ -509,7 +527,17 @@ namespace ts.projectSystem {
this.reloadFS(filesOrFolders);
}
write() { }
write(message: string) {
this.output.push(message);
}
getOutput(): ReadonlyArray<string> {
return this.output;
}
clearOutput() {
this.output.length = 0;
}
readonly readFile = (s: string) => (<File>this.fs.get(this.toPath(s))).content;
readonly resolvePath = (s: string) => s;
@@ -1589,6 +1617,41 @@ namespace ts.projectSystem {
checkProjectActualFiles(projectService.inferredProjects[1], [file2.path]);
});
it ("loading files with correct priority", () => {
const f1 = {
path: "/a/main.ts",
content: "let x = 1"
};
const f2 = {
path: "/a/main.js",
content: "var y = 1"
};
const config = {
path: "/a/tsconfig.json",
content: JSON.stringify({
compilerOptions: { allowJs: true }
})
};
const host = createServerHost([f1, f2, config]);
const projectService = createProjectService(host);
projectService.setHostConfiguration({
extraFileExtensions: [
{ extension: ".js", isMixedContent: false },
{ extension: ".html", isMixedContent: true }
]
});
projectService.openClientFile(f1.path);
projectService.checkNumberOfProjects({ configuredProjects: 1 });
checkProjectActualFiles(projectService.configuredProjects[0], [ f1.path ]);
projectService.closeClientFile(f1.path);
projectService.openClientFile(f2.path);
projectService.checkNumberOfProjects({ configuredProjects: 1, inferredProjects: 1 });
checkProjectActualFiles(projectService.configuredProjects[0], [ f1.path ]);
checkProjectActualFiles(projectService.inferredProjects[0], [ f2.path ]);
});
it("tsconfig script block support", () => {
const file1 = {
path: "/a/b/f1.ts",
@@ -1650,6 +1713,115 @@ namespace ts.projectSystem {
assert(completions && completions.entries[0].name !== "hello", `unexpected hello entry in completion list`);
});
it("no tsconfig script block diagnostic errors", () => {
// #1. Ensure no diagnostic errors when allowJs is true
const file1 = {
path: "/a/b/f1.ts",
content: ` `
};
const file2 = {
path: "/a/b/f2.html",
content: `var hello = "hello";`
};
const config1 = {
path: "/a/b/tsconfig.json",
content: JSON.stringify({ compilerOptions: { allowJs: true } })
};
let host = createServerHost([file1, file2, config1, libFile], { executingFilePath: combinePaths(getDirectoryPath(libFile.path), "tsc.js") });
let session = createSession(host);
// Specify .html extension as mixed content in a configure host request
const extraFileExtensions = [{ extension: ".html", scriptKind: ScriptKind.JS, isMixedContent: true }];
const configureHostRequest = makeSessionRequest<protocol.ConfigureRequestArguments>(CommandNames.Configure, { extraFileExtensions });
session.executeCommand(configureHostRequest).response;
openFilesForSession([file1], session);
let projectService = session.getProjectService();
checkNumberOfProjects(projectService, { configuredProjects: 1 });
let diagnostics = projectService.configuredProjects[0].getLanguageService().getCompilerOptionsDiagnostics();
assert.deepEqual(diagnostics, []);
// #2. Ensure no errors when allowJs is false
const config2 = {
path: "/a/b/tsconfig.json",
content: JSON.stringify({ compilerOptions: { allowJs: false } })
};
host = createServerHost([file1, file2, config2, libFile], { executingFilePath: combinePaths(getDirectoryPath(libFile.path), "tsc.js") });
session = createSession(host);
session.executeCommand(configureHostRequest).response;
openFilesForSession([file1], session);
projectService = session.getProjectService();
checkNumberOfProjects(projectService, { configuredProjects: 1 });
diagnostics = projectService.configuredProjects[0].getLanguageService().getCompilerOptionsDiagnostics();
assert.deepEqual(diagnostics, []);
// #3. Ensure no errors when compiler options aren't specified
const config3 = {
path: "/a/b/tsconfig.json",
content: JSON.stringify({ })
};
host = createServerHost([file1, file2, config3, libFile], { executingFilePath: combinePaths(getDirectoryPath(libFile.path), "tsc.js") });
session = createSession(host);
session.executeCommand(configureHostRequest).response;
openFilesForSession([file1], session);
projectService = session.getProjectService();
checkNumberOfProjects(projectService, { configuredProjects: 1 });
diagnostics = projectService.configuredProjects[0].getLanguageService().getCompilerOptionsDiagnostics();
assert.deepEqual(diagnostics, []);
// #4. Ensure no errors when files are explicitly specified in tsconfig
const config4 = {
path: "/a/b/tsconfig.json",
content: JSON.stringify({ compilerOptions: { allowJs: true }, files: [file1.path, file2.path] })
};
host = createServerHost([file1, file2, config4, libFile], { executingFilePath: combinePaths(getDirectoryPath(libFile.path), "tsc.js") });
session = createSession(host);
session.executeCommand(configureHostRequest).response;
openFilesForSession([file1], session);
projectService = session.getProjectService();
checkNumberOfProjects(projectService, { configuredProjects: 1 });
diagnostics = projectService.configuredProjects[0].getLanguageService().getCompilerOptionsDiagnostics();
assert.deepEqual(diagnostics, []);
// #4. Ensure no errors when files are explicitly excluded in tsconfig
const config5 = {
path: "/a/b/tsconfig.json",
content: JSON.stringify({ compilerOptions: { allowJs: true }, exclude: [file2.path] })
};
host = createServerHost([file1, file2, config5, libFile], { executingFilePath: combinePaths(getDirectoryPath(libFile.path), "tsc.js") });
session = createSession(host);
session.executeCommand(configureHostRequest).response;
openFilesForSession([file1], session);
projectService = session.getProjectService();
checkNumberOfProjects(projectService, { configuredProjects: 1 });
diagnostics = projectService.configuredProjects[0].getLanguageService().getCompilerOptionsDiagnostics();
assert.deepEqual(diagnostics, []);
});
it("project structure update is deferred if files are not added\removed", () => {
const file1 = {
path: "/a/b/f1.ts",
@@ -3031,6 +3203,54 @@ namespace ts.projectSystem {
});
});
describe("emit with outFile or out setting", () => {
function test(opts: CompilerOptions, expectedUsesOutFile: boolean) {
const f1 = {
path: "/a/a.ts",
content: "let x = 1"
};
const f2 = {
path: "/a/b.ts",
content: "let y = 1"
};
const config = {
path: "/a/tsconfig.json",
content: JSON.stringify({
compilerOptions: opts,
compileOnSave: true
})
};
const host = createServerHost([f1, f2, config]);
const session = createSession(host);
session.executeCommand(<protocol.OpenRequest>{
seq: 1,
type: "request",
command: "open",
arguments: { file: f1.path }
});
checkNumberOfProjects(session.getProjectService(), { configuredProjects: 1 });
const { response } = session.executeCommand(<protocol.CompileOnSaveAffectedFileListRequest>{
seq: 2,
type: "request",
command: "compileOnSaveAffectedFileList",
arguments: { file: f1.path }
});
assert.equal((<protocol.CompileOnSaveAffectedFileListSingleProject[]>response).length, 1, "expected output for 1 project");
assert.equal((<protocol.CompileOnSaveAffectedFileListSingleProject[]>response)[0].fileNames.length, 2, "expected output for 1 project");
assert.equal((<protocol.CompileOnSaveAffectedFileListSingleProject[]>response)[0].projectUsesOutFile, expectedUsesOutFile, "usesOutFile");
}
it ("projectUsesOutFile should not be returned if not set", () => {
test({}, /*expectedUsesOutFile*/ false);
});
it ("projectUsesOutFile should be true if outFile is set", () => {
test({ outFile: "/a/out.js" }, /*expectedUsesOutFile*/ true);
});
it ("projectUsesOutFile should be true if out is set", () => {
test({ out: "/a/out.js" }, /*expectedUsesOutFile*/ true);
});
});
describe("import helpers", () => {
it("should not crash in tsserver", () => {
const f1 = {
@@ -3048,6 +3268,200 @@ namespace ts.projectSystem {
});
});
describe("cancellationToken", () => {
it("is attached to request", () => {
const f1 = {
path: "/a/b/app.ts",
content: "let xyz = 1;"
};
const host = createServerHost([f1]);
let expectedRequestId: number;
const cancellationToken: server.ServerCancellationToken = {
isCancellationRequested: () => false,
setRequest: requestId => {
if (expectedRequestId === undefined) {
assert.isTrue(false, "unexpected call")
}
assert.equal(requestId, expectedRequestId);
},
resetRequest: noop
}
const session = createSession(host, /*typingsInstaller*/ undefined, /*projectServiceEventHandler*/ undefined, cancellationToken);
expectedRequestId = session.getNextSeq();
session.executeCommandSeq(<server.protocol.OpenRequest>{
command: "open",
arguments: { file: f1.path }
});
expectedRequestId = session.getNextSeq();
session.executeCommandSeq(<server.protocol.GeterrRequest>{
command: "geterr",
arguments: { files: [f1.path] }
});
expectedRequestId = session.getNextSeq();
session.executeCommandSeq(<server.protocol.OccurrencesRequest>{
command: "occurrences",
arguments: { file: f1.path, line: 1, offset: 6 }
});
expectedRequestId = 2;
host.runQueuedImmediateCallbacks();
expectedRequestId = 2;
host.runQueuedImmediateCallbacks();
});
it("Geterr is cancellable", () => {
const f1 = {
path: "/a/app.ts",
content: "let x = 1"
};
const config = {
path: "/a/tsconfig.json",
content: JSON.stringify({
compilerOptions: {}
})
};
let requestToCancel = -1;
const cancellationToken: server.ServerCancellationToken = (function(){
let currentId: number;
return <server.ServerCancellationToken>{
setRequest(requestId) {
currentId = requestId;
},
resetRequest(requestId) {
assert.equal(requestId, currentId, "unexpected request id in cancellation")
currentId = undefined;
},
isCancellationRequested() {
return requestToCancel === currentId;
}
}
})();
const host = createServerHost([f1, config]);
const session = createSession(host, /*typingsInstaller*/ undefined, () => {}, cancellationToken);
{
session.executeCommandSeq(<protocol.OpenRequest>{
command: "open",
arguments: { file: f1.path }
});
// send geterr for missing file
session.executeCommandSeq(<protocol.GeterrRequest>{
command: "geterr",
arguments: { files: ["/a/missing"] }
});
// no files - expect 'completed' event
assert.equal(host.getOutput().length, 1, "expect 1 message");
verifyRequestCompleted(session.getSeq(), 0);
}
{
const getErrId = session.getNextSeq();
// send geterr for a valid file
session.executeCommandSeq(<protocol.GeterrRequest>{
command: "geterr",
arguments: { files: [f1.path] }
});
assert.equal(host.getOutput().length, 0, "expect 0 messages");
// run new request
session.executeCommandSeq(<protocol.ProjectInfoRequest>{
command: "projectInfo",
arguments: { file: f1.path }
});
host.clearOutput();
// cancel previously issued Geterr
requestToCancel = getErrId;
host.runQueuedTimeoutCallbacks();
assert.equal(host.getOutput().length, 1, "expect 1 message");
verifyRequestCompleted(getErrId, 0);
requestToCancel = -1;
}
{
const getErrId = session.getNextSeq();
session.executeCommandSeq(<protocol.GeterrRequest>{
command: "geterr",
arguments: { files: [f1.path] }
});
assert.equal(host.getOutput().length, 0, "expect 0 messages");
// run first step
host.runQueuedTimeoutCallbacks();
assert.equal(host.getOutput().length, 1, "expect 1 messages");
const e1 = <protocol.Event>getMessage(0);
assert.equal(e1.event, "syntaxDiag");
host.clearOutput();
requestToCancel = getErrId;
host.runQueuedImmediateCallbacks();
assert.equal(host.getOutput().length, 1, "expect 1 message");
verifyRequestCompleted(getErrId, 0);
requestToCancel = -1;
}
{
const getErrId = session.getNextSeq();
session.executeCommandSeq(<protocol.GeterrRequest>{
command: "geterr",
arguments: { files: [f1.path] }
});
assert.equal(host.getOutput().length, 0, "expect 0 messages");
// run first step
host.runQueuedTimeoutCallbacks();
assert.equal(host.getOutput().length, 1, "expect 1 messages");
const e1 = <protocol.Event>getMessage(0);
assert.equal(e1.event, "syntaxDiag");
host.clearOutput();
host.runQueuedImmediateCallbacks();
assert.equal(host.getOutput().length, 2, "expect 2 messages");
const e2 = <protocol.Event>getMessage(0);
assert.equal(e2.event, "semanticDiag");
verifyRequestCompleted(getErrId, 1);
requestToCancel = -1;
}
{
const getErr1 = session.getNextSeq();
session.executeCommandSeq(<protocol.GeterrRequest>{
command: "geterr",
arguments: { files: [f1.path] }
});
assert.equal(host.getOutput().length, 0, "expect 0 messages");
// run first step
host.runQueuedTimeoutCallbacks();
assert.equal(host.getOutput().length, 1, "expect 1 messages");
const e1 = <protocol.Event>getMessage(0);
assert.equal(e1.event, "syntaxDiag");
host.clearOutput();
session.executeCommandSeq(<protocol.GeterrRequest>{
command: "geterr",
arguments: { files: [f1.path] }
});
// make sure that getErr1 is completed
verifyRequestCompleted(getErr1, 0);
}
function verifyRequestCompleted(expectedSeq: number, n: number) {
const event = <protocol.RequestCompletedEvent>getMessage(n);
assert.equal(event.event, "requestCompleted");
assert.equal(event.body.request_seq, expectedSeq, "expectedSeq");
host.clearOutput();
}
function getMessage(n: number) {
return JSON.parse(server.extractMessage(host.getOutput()[n]));
}
});
});
describe("maxNodeModuleJsDepth for inferred projects", () => {
it("should be set to 2 if the project has js root files", () => {
const file1: FileOrFolder = {
@@ -3067,7 +3481,7 @@ namespace ts.projectSystem {
let options = project.getCompilerOptions();
assert.isTrue(options.maxNodeModuleJsDepth === 2);
// Assert the option sticks
// Assert the option sticks
projectService.setCompilerOptionsForInferredProjects({ target: ScriptTarget.ES2016 });
project = projectService.inferredProjects[0];
options = project.getCompilerOptions();
@@ -3101,5 +3515,4 @@ namespace ts.projectSystem {
assert.isUndefined(project.getCompilerOptions().maxNodeModuleJsDepth);
});
});
}
+49 -8
View File
@@ -44,6 +44,47 @@ namespace ts.projectSystem {
});
}
import typingsName = server.typingsInstaller.typingsName;
describe("local module", () => {
it("should not be picked up", () => {
const f1 = {
path: "/a/app.js",
content: "const c = require('./config');"
};
const f2 = {
path: "/a/config.js",
content: "export let x = 1"
};
const typesCache = "/cache"
const typesConfig = {
path: typesCache + "/node_modules/@types/config/index.d.ts",
content: "export let y: number;"
};
const config = {
path: "/a/jsconfig.json",
content: JSON.stringify({
compilerOptions: { moduleResolution: "commonjs" },
typeAcquisition: { enable: true }
})
};
const host = createServerHost([f1, f2, config, typesConfig]);
const installer = new (class extends Installer {
constructor() {
super(host, { typesRegistry: createTypesRegistry("config"), globalTypingsCacheLocation: typesCache });
}
installWorker(_requestId: number, _args: string[], _cwd: string, _cb: server.typingsInstaller.RequestCompletedAction) {
assert(false, "should not be called")
}
})();
const service = createProjectService(host, { typingsInstaller: installer });
service.openClientFile(f1.path);
service.checkNumberOfProjects({ configuredProjects: 1 });
checkProjectActualFiles(service.configuredProjects[0], [f1.path, f2.path]);
installer.installAll(0);
});
});
describe("typingsInstaller", () => {
it("configured projects (typings installed) 1", () => {
const file1 = {
@@ -519,32 +560,32 @@ namespace ts.projectSystem {
const commander = {
path: "/a/data/node_modules/@types/commander/index.d.ts",
content: "declare const commander: { x: number }",
typings: "@types/commander"
typings: typingsName("commander")
};
const jquery = {
path: "/a/data/node_modules/@types/jquery/index.d.ts",
content: "declare const jquery: { x: number }",
typings: "@types/jquery"
typings: typingsName("jquery")
};
const lodash = {
path: "/a/data/node_modules/@types/lodash/index.d.ts",
content: "declare const lodash: { x: number }",
typings: "@types/lodash"
typings: typingsName("lodash")
};
const cordova = {
path: "/a/data/node_modules/@types/cordova/index.d.ts",
content: "declare const cordova: { x: number }",
typings: "@types/cordova"
typings: typingsName("cordova")
};
const grunt = {
path: "/a/data/node_modules/@types/grunt/index.d.ts",
content: "declare const grunt: { x: number }",
typings: "@types/grunt"
typings: typingsName("grunt")
};
const gulp = {
path: "/a/data/node_modules/@types/gulp/index.d.ts",
content: "declare const gulp: { x: number }",
typings: "@types/gulp"
typings: typingsName("gulp")
};
const host = createServerHost([lodashJs, commanderJs, file3]);
@@ -554,7 +595,7 @@ namespace ts.projectSystem {
}
installWorker(_requestId: number, args: string[], _cwd: string, cb: TI.RequestCompletedAction): void {
let typingFiles: (FileOrFolder & { typings: string })[] = [];
if (args.indexOf("@types/commander") >= 0) {
if (args.indexOf(typingsName("commander")) >= 0) {
typingFiles = [commander, jquery, lodash, cordova];
}
else {
@@ -982,7 +1023,7 @@ namespace ts.projectSystem {
return;
}
if (response.kind === server.EventEndInstallTypes) {
assert.deepEqual(response.packagesToInstall, ["@types/commander"]);
assert.deepEqual(response.packagesToInstall, [typingsName("commander")]);
seenTelemetryEvent = true;
return;
}
+1583 -384
View File
File diff suppressed because it is too large Load Diff
-50
View File
@@ -1,53 +1,3 @@
/**
* Represents the completion of an asynchronous operation
*/
interface Promise<T> {
/**
* Attaches callbacks for the resolution and/or rejection of the Promise.
* @param onfulfilled The callback to execute when the Promise is resolved.
* @param onrejected The callback to execute when the Promise is rejected.
* @returns A Promise for the completion of which ever callback is executed.
*/
then(onfulfilled?: ((value: T) => T | PromiseLike<T>) | undefined | null, onrejected?: ((reason: any) => T | PromiseLike<T>) | undefined | null): Promise<T>;
/**
* Attaches callbacks for the resolution and/or rejection of the Promise.
* @param onfulfilled The callback to execute when the Promise is resolved.
* @param onrejected The callback to execute when the Promise is rejected.
* @returns A Promise for the completion of which ever callback is executed.
*/
then<TResult>(onfulfilled: ((value: T) => T | PromiseLike<T>) | undefined | null, onrejected: (reason: any) => TResult | PromiseLike<TResult>): Promise<T | TResult>;
/**
* Attaches callbacks for the resolution and/or rejection of the Promise.
* @param onfulfilled The callback to execute when the Promise is resolved.
* @param onrejected The callback to execute when the Promise is rejected.
* @returns A Promise for the completion of which ever callback is executed.
*/
then<TResult>(onfulfilled: (value: T) => TResult | PromiseLike<TResult>, onrejected?: ((reason: any) => TResult | PromiseLike<TResult>) | undefined | null): Promise<TResult>;
/**
* Attaches callbacks for the resolution and/or rejection of the Promise.
* @param onfulfilled The callback to execute when the Promise is resolved.
* @param onrejected The callback to execute when the Promise is rejected.
* @returns A Promise for the completion of which ever callback is executed.
*/
then<TResult1, TResult2>(onfulfilled: (value: T) => TResult1 | PromiseLike<TResult1>, onrejected: (reason: any) => TResult2 | PromiseLike<TResult2>): Promise<TResult1 | TResult2>;
/**
* Attaches a callback for only the rejection of the Promise.
* @param onrejected The callback to execute when the Promise is rejected.
* @returns A Promise for the completion of the callback.
*/
catch(onrejected?: ((reason: any) => T | PromiseLike<T>) | undefined | null): Promise<T>;
/**
* Attaches a callback for only the rejection of the Promise.
* @param onrejected The callback to execute when the Promise is rejected.
* @returns A Promise for the completion of the callback.
*/
catch<TResult>(onrejected: (reason: any) => TResult | PromiseLike<TResult>): Promise<T | TResult>;
}
interface PromiseConstructor {
/**
+56 -11
View File
@@ -137,16 +137,10 @@ interface ObjectConstructor {
getOwnPropertyNames(o: any): string[];
/**
* Creates an object that has null prototype.
* @param o Object to use as a prototype. May be null
* Creates an object that has the specified prototype or that has null prototype.
* @param o Object to use as a prototype. May be null.
*/
create(o: null): any;
/**
* Creates an object that has the specified prototype, and that optionally contains specified properties.
* @param o Object to use as a prototype. May be null
*/
create<T extends object>(o: T): T;
create<T extends object>(o: T | null): T | object;
/**
* Creates an object that has the specified prototype, and that optionally contains specified properties.
@@ -341,14 +335,14 @@ interface String {
/**
* Replaces text in a string, using a regular expression or search string.
* @param searchValue A string that represents the regular expression.
* @param searchValue A string to search for.
* @param replaceValue A string containing the text to replace for every successful match of searchValue in this string.
*/
replace(searchValue: string, replaceValue: string): string;
/**
* Replaces text in a string, using a regular expression or search string.
* @param searchValue A string that represents the regular expression.
* @param searchValue A string to search for.
* @param replacer A function that returns the replacement text.
*/
replace(searchValue: string, replacer: (substring: string, ...args: any[]) => string): string;
@@ -1351,6 +1345,57 @@ interface PromiseLike<T> {
onrejected: (reason: any) => TResult2 | PromiseLike<TResult2>): PromiseLike<TResult1 | TResult2>;
}
/**
* Represents the completion of an asynchronous operation
*/
interface Promise<T> {
/**
* Attaches callbacks for the resolution and/or rejection of the Promise.
* @param onfulfilled The callback to execute when the Promise is resolved.
* @param onrejected The callback to execute when the Promise is rejected.
* @returns A Promise for the completion of which ever callback is executed.
*/
then(onfulfilled?: ((value: T) => T | PromiseLike<T>) | undefined | null, onrejected?: ((reason: any) => T | PromiseLike<T>) | undefined | null): Promise<T>;
/**
* Attaches callbacks for the resolution and/or rejection of the Promise.
* @param onfulfilled The callback to execute when the Promise is resolved.
* @param onrejected The callback to execute when the Promise is rejected.
* @returns A Promise for the completion of which ever callback is executed.
*/
then<TResult>(onfulfilled: ((value: T) => T | PromiseLike<T>) | undefined | null, onrejected: (reason: any) => TResult | PromiseLike<TResult>): Promise<T | TResult>;
/**
* Attaches callbacks for the resolution and/or rejection of the Promise.
* @param onfulfilled The callback to execute when the Promise is resolved.
* @param onrejected The callback to execute when the Promise is rejected.
* @returns A Promise for the completion of which ever callback is executed.
*/
then<TResult>(onfulfilled: (value: T) => TResult | PromiseLike<TResult>, onrejected?: ((reason: any) => TResult | PromiseLike<TResult>) | undefined | null): Promise<TResult>;
/**
* Attaches callbacks for the resolution and/or rejection of the Promise.
* @param onfulfilled The callback to execute when the Promise is resolved.
* @param onrejected The callback to execute when the Promise is rejected.
* @returns A Promise for the completion of which ever callback is executed.
*/
then<TResult1, TResult2>(onfulfilled: (value: T) => TResult1 | PromiseLike<TResult1>, onrejected: (reason: any) => TResult2 | PromiseLike<TResult2>): Promise<TResult1 | TResult2>;
/**
* Attaches a callback for only the rejection of the Promise.
* @param onrejected The callback to execute when the Promise is rejected.
* @returns A Promise for the completion of the callback.
*/
catch(onrejected?: ((reason: any) => T | PromiseLike<T>) | undefined | null): Promise<T>;
/**
* Attaches a callback for only the rejection of the Promise.
* @param onrejected The callback to execute when the Promise is rejected.
* @returns A Promise for the completion of the callback.
*/
catch<TResult>(onrejected: (reason: any) => TResult | PromiseLike<TResult>): Promise<T | TResult>;
}
interface ArrayLike<T> {
readonly length: number;
readonly [n: number]: T;
+636 -161
View File
File diff suppressed because it is too large Load Diff
@@ -1,14 +1,24 @@
/// <reference types="node" />
// TODO: extract services types
interface HostCancellationToken {
isCancellationRequested(): boolean;
}
/// <reference types="node"/>
import fs = require("fs");
function createCancellationToken(args: string[]): HostCancellationToken {
interface ServerCancellationToken {
isCancellationRequested(): boolean;
setRequest(requestId: number): void;
resetRequest(requestId: number): void;
}
function pipeExists(name: string): boolean {
try {
fs.statSync(name);
return true;
}
catch (e) {
return false;
}
}
function createCancellationToken(args: string[]): ServerCancellationToken {
let cancellationPipeName: string;
for (let i = 0; i < args.length - 1; i++) {
if (args[i] === "--cancellationPipeName") {
@@ -17,18 +27,44 @@ function createCancellationToken(args: string[]): HostCancellationToken {
}
}
if (!cancellationPipeName) {
return { isCancellationRequested: () => false };
return {
isCancellationRequested: () => false,
setRequest: (_requestId: number): void => void 0,
resetRequest: (_requestId: number): void => void 0
};
}
return {
isCancellationRequested() {
try {
fs.statSync(cancellationPipeName);
return true;
}
catch (e) {
return false;
}
// cancellationPipeName is a string without '*' inside that can optionally end with '*'
// when client wants to signal cancellation it should create a named pipe with name=<cancellationPipeName>
// server will synchronously check the presence of the pipe and treat its existance as indicator that current request should be canceled.
// in case if client prefers to use more fine-grained schema than one name for all request it can add '*' to the end of cancelellationPipeName.
// in this case pipe name will be build dynamically as <cancellationPipeName><request_seq>.
if (cancellationPipeName.charAt(cancellationPipeName.length - 1) === "*") {
const namePrefix = cancellationPipeName.slice(0, -1);
if (namePrefix.length === 0 || namePrefix.indexOf("*") >= 0) {
throw new Error("Invalid name for template cancellation pipe: it should have length greater than 2 characters and contain only one '*'.");
}
};
let perRequestPipeName: string;
let currentRequestId: number;
return {
isCancellationRequested: () => perRequestPipeName !== undefined && pipeExists(perRequestPipeName),
setRequest(requestId: number) {
currentRequestId = currentRequestId;
perRequestPipeName = namePrefix + requestId;
},
resetRequest(requestId: number) {
if (currentRequestId !== requestId) {
throw new Error(`Mismatched request id, expected ${currentRequestId}, actual ${requestId}`);
}
perRequestPipeName = undefined;
}
};
}
else {
return {
isCancellationRequested: () => pipeExists(cancellationPipeName),
setRequest: (_requestId: number): void => void 0,
resetRequest: (_requestId: number): void => void 0
};
}
}
export = createCancellationToken;
+20 -19
View File
@@ -13,6 +13,25 @@ namespace ts.server {
findInComments: boolean;
}
/* @internal */
export function extractMessage(message: string) {
// Read the content length
const contentLengthPrefix = "Content-Length: ";
const lines = message.split(/\r?\n/);
Debug.assert(lines.length >= 2, "Malformed response: Expected 3 lines in the response.");
const contentLengthText = lines[0];
Debug.assert(contentLengthText.indexOf(contentLengthPrefix) === 0, "Malformed response: Response text did not contain content-length header.");
const contentLength = parseInt(contentLengthText.substring(contentLengthPrefix.length));
// Read the body
const responseBody = lines[2];
// Verify content length
Debug.assert(responseBody.length + 1 === contentLength, "Malformed response: Content length did not match the response's body length.");
return responseBody;
}
export class SessionClient implements LanguageService {
private sequence: number = 0;
private lineMaps: ts.Map<number[]> = ts.createMap<number[]>();
@@ -84,7 +103,7 @@ namespace ts.server {
while (!foundResponseMessage) {
lastMessage = this.messages.shift();
Debug.assert(!!lastMessage, "Did not receive any responses.");
const responseBody = processMessage(lastMessage);
const responseBody = extractMessage(lastMessage);
try {
response = JSON.parse(responseBody);
// the server may emit events before emitting the response. We
@@ -109,24 +128,6 @@ namespace ts.server {
Debug.assert(!!response.body, "Malformed response: Unexpected empty response body.");
return response;
function processMessage(message: string) {
// Read the content length
const contentLengthPrefix = "Content-Length: ";
const lines = message.split("\r\n");
Debug.assert(lines.length >= 2, "Malformed response: Expected 3 lines in the response.");
const contentLengthText = lines[0];
Debug.assert(contentLengthText.indexOf(contentLengthPrefix) === 0, "Malformed response: Response text did not contain content-length header.");
const contentLength = parseInt(contentLengthText.substring(contentLengthPrefix.length));
// Read the body
const responseBody = lines[2];
// Verify content length
Debug.assert(responseBody.length + 1 === contentLength, "Malformed response: Content length did not match the response's body length.");
return responseBody;
}
}
openFile(fileName: string, content?: string, scriptKindName?: "TS" | "JS" | "TSX" | "JSX"): void {
+2 -2
View File
@@ -107,7 +107,7 @@ namespace ts.server {
export interface HostConfiguration {
formatCodeOptions: FormatCodeSettings;
hostInfo: string;
extraFileExtensions?: FileExtensionInfo[];
extraFileExtensions?: JsFileExtensionInfo[];
}
interface ConfigFileConversionResult {
@@ -132,7 +132,7 @@ namespace ts.server {
interface FilePropertyReader<T> {
getFileName(f: T): string;
getScriptKind(f: T): ScriptKind;
hasMixedContent(f: T, extraFileExtensions: FileExtensionInfo[]): boolean;
hasMixedContent(f: T, extraFileExtensions: JsFileExtensionInfo[]): boolean;
}
const fileNamePropertyReader: FilePropertyReader<string> = {
+1 -1
View File
@@ -28,7 +28,7 @@ namespace ts.server {
: undefined;
const primaryResult = resolveModuleName(moduleName, containingFile, compilerOptions, host);
// return result immediately only if it is .ts, .tsx or .d.ts
if (!(primaryResult.resolvedModule && extensionIsTypeScript(primaryResult.resolvedModule.extension)) && globalCache !== undefined) {
if (moduleHasNonRelativeName(moduleName) && !(primaryResult.resolvedModule && extensionIsTypeScript(primaryResult.resolvedModule.extension)) && globalCache !== undefined) {
// otherwise try to load typings from @types
// create different collection of failed lookup locations for second pass
+108 -5
View File
@@ -91,19 +91,38 @@ namespace ts.server {
}
}
export interface PluginCreateInfo {
project: Project;
languageService: LanguageService;
languageServiceHost: LanguageServiceHost;
serverHost: ServerHost;
config: any;
}
export interface PluginModule {
create(createInfo: PluginCreateInfo): LanguageService;
getExternalFiles?(proj: Project): string[];
}
export interface PluginModuleFactory {
(mod: { typescript: typeof ts }): PluginModule;
}
export abstract class Project {
private rootFiles: ScriptInfo[] = [];
private rootFilesMap: FileMap<ScriptInfo> = createFileMap<ScriptInfo>();
private lsHost: LSHost;
private program: ts.Program;
private cachedUnresolvedImportsPerFile = new UnresolvedImportsMap();
private lastCachedUnresolvedImportsList: SortedReadonlyArray<string>;
private readonly languageService: LanguageService;
// wrapper over the real language service that will suppress all semantic operations
protected languageService: LanguageService;
public languageServiceEnabled = true;
protected readonly lsHost: LSHost;
builder: Builder;
/**
* Set of files names that were updated since the last call to getChangesSinceVersion.
@@ -150,6 +169,17 @@ namespace ts.server {
return this.cachedUnresolvedImportsPerFile;
}
public static resolveModule(moduleName: string, initialDir: string, host: ServerHost, log: (message: string) => void): {} {
const resolvedPath = normalizeSlashes(host.resolvePath(combinePaths(initialDir, "node_modules")));
log(`Loading ${moduleName} from ${initialDir} (resolved to ${resolvedPath})`);
const result = host.require(resolvedPath, moduleName);
if (result.error) {
log(`Failed to load module: ${JSON.stringify(result.error)}`);
return undefined;
}
return result.module;
}
constructor(
private readonly projectName: string,
readonly projectKind: ProjectKind,
@@ -165,8 +195,8 @@ namespace ts.server {
this.compilerOptions.allowNonTsExtensions = true;
this.compilerOptions.allowJs = true;
}
else if (hasExplicitListOfFiles) {
// If files are listed explicitly, allow all extensions
else if (hasExplicitListOfFiles || this.compilerOptions.allowJs) {
// If files are listed explicitly or allowJs is specified, allow all extensions
this.compilerOptions.allowNonTsExtensions = true;
}
@@ -237,6 +267,10 @@ namespace ts.server {
abstract getProjectRootPath(): string | undefined;
abstract getTypeAcquisition(): TypeAcquisition;
getExternalFiles(): string[] {
return [];
}
getSourceFile(path: Path) {
if (!this.program) {
return undefined;
@@ -804,10 +838,12 @@ namespace ts.server {
private typeRootsWatchers: FileWatcher[];
readonly canonicalConfigFilePath: NormalizedPath;
private plugins: PluginModule[] = [];
/** Used for configured projects which may have multiple open roots */
openRefCount = 0;
constructor(configFileName: NormalizedPath,
constructor(private configFileName: NormalizedPath,
projectService: ProjectService,
documentRegistry: ts.DocumentRegistry,
hasExplicitListOfFiles: boolean,
@@ -817,12 +853,64 @@ namespace ts.server {
public compileOnSaveEnabled: boolean) {
super(configFileName, ProjectKind.Configured, projectService, documentRegistry, hasExplicitListOfFiles, languageServiceEnabled, compilerOptions, compileOnSaveEnabled);
this.canonicalConfigFilePath = asNormalizedPath(projectService.toCanonicalFileName(configFileName));
this.enablePlugins();
}
getConfigFilePath() {
return this.getProjectName();
}
enablePlugins() {
const host = this.projectService.host;
const options = this.getCompilerOptions();
const log = (message: string) => {
this.projectService.logger.info(message);
};
if (!(options.plugins && options.plugins.length)) {
this.projectService.logger.info("No plugins exist");
// No plugins
return;
}
if (!host.require) {
this.projectService.logger.info("Plugins were requested but not running in environment that supports 'require'. Nothing will be loaded");
return;
}
for (const pluginConfigEntry of options.plugins) {
const searchPath = getDirectoryPath(this.configFileName);
const resolvedModule = <PluginModuleFactory>Project.resolveModule(pluginConfigEntry.name, searchPath, host, log);
if (resolvedModule) {
this.enableProxy(resolvedModule, pluginConfigEntry);
}
}
}
private enableProxy(pluginModuleFactory: PluginModuleFactory, configEntry: PluginImport) {
try {
if (typeof pluginModuleFactory !== "function") {
this.projectService.logger.info(`Skipped loading plugin ${configEntry.name} because it did expose a proper factory function`);
return;
}
const info: PluginCreateInfo = {
config: configEntry,
project: this,
languageService: this.languageService,
languageServiceHost: this.lsHost,
serverHost: this.projectService.host
};
const pluginModule = pluginModuleFactory({ typescript: ts });
this.languageService = pluginModule.create(info);
this.plugins.push(pluginModule);
}
catch (e) {
this.projectService.logger.info(`Plugin activation failed: ${e}`);
}
}
getProjectRootPath() {
return getDirectoryPath(this.getConfigFilePath());
}
@@ -839,6 +927,21 @@ namespace ts.server {
return this.typeAcquisition;
}
getExternalFiles(): string[] {
const items: string[] = [];
for (const plugin of this.plugins) {
if (typeof plugin.getExternalFiles === "function") {
try {
items.push(...plugin.getExternalFiles(this));
}
catch (e) {
this.projectService.logger.info(`A plugin threw an exception in getExternalFiles: ${e}`);
}
}
}
return items;
}
watchConfigFile(callback: (project: ConfiguredProject) => void) {
this.projectFileWatcher = this.projectService.host.watchFile(this.getConfigFilePath(), _ => callback(this));
}
+22 -2
View File
@@ -1001,9 +1001,9 @@ namespace ts.server.protocol {
formatOptions?: FormatCodeSettings;
/**
* The host's additional supported file extensions
* The host's additional supported .js file extensions
*/
extraFileExtensions?: FileExtensionInfo[];
extraFileExtensions?: JsFileExtensionInfo[];
}
/**
@@ -1239,6 +1239,11 @@ namespace ts.server.protocol {
* List of files names that should be recompiled
*/
fileNames: string[];
/**
* true if project uses outFile or out compiler option
*/
projectUsesOutFile: boolean;
}
/**
@@ -1761,6 +1766,20 @@ namespace ts.server.protocol {
arguments: GeterrRequestArgs;
}
export type RequestCompletedEventName = "requestCompleted";
/**
* Event that is sent when server have finished processing request with specified id.
*/
export interface RequestCompletedEvent extends Event {
event: RequestCompletedEventName;
body: RequestCompletedEventBody;
}
export interface RequestCompletedEventBody {
request_seq: number;
}
/**
* Item of diagnostic information found in a DiagnosticEvent message.
*/
@@ -2248,6 +2267,7 @@ namespace ts.server.protocol {
outDir?: string;
outFile?: string;
paths?: MapLike<string[]>;
plugins?: PluginImport[];
preserveConstEnums?: boolean;
project?: string;
reactNamespace?: string;
+15 -5
View File
@@ -99,6 +99,8 @@ namespace ts.server {
birthtime: Date;
}
type RequireResult = { module: {}, error: undefined } | { module: undefined, error: {} };
const readline: {
createInterface(options: ReadLineOptions): NodeJS.EventEmitter;
} = require("readline");
@@ -354,7 +356,7 @@ namespace ts.server {
class IOSession extends Session {
constructor(
host: ServerHost,
cancellationToken: HostCancellationToken,
cancellationToken: ServerCancellationToken,
installerEventPort: number,
canUseEvents: boolean,
useSingleInferredProject: boolean,
@@ -593,15 +595,23 @@ namespace ts.server {
sys.gc = () => global.gc();
}
let cancellationToken: HostCancellationToken;
sys.require = (initialDir: string, moduleName: string): RequireResult => {
const result = nodeModuleNameResolverWorker(moduleName, initialDir + "/program.ts", { moduleResolution: ts.ModuleResolutionKind.NodeJs, allowJs: true }, sys, undefined, /*jsOnly*/ true);
try {
return { module: require(result.resolvedModule.resolvedFileName), error: undefined };
}
catch (e) {
return { module: undefined, error: e };
}
};
let cancellationToken: ServerCancellationToken;
try {
const factory = require("./cancellationToken");
cancellationToken = factory(sys.args);
}
catch (e) {
cancellationToken = {
isCancellationRequested: () => false
};
cancellationToken = nullCancellationToken;
};
let eventPort: number;
+192 -34
View File
@@ -8,6 +8,17 @@ namespace ts.server {
stack?: string;
}
export interface ServerCancellationToken extends HostCancellationToken {
setRequest(requestId: number): void;
resetRequest(requestId: number): void;
}
export const nullCancellationToken: ServerCancellationToken = {
isCancellationRequested: () => false,
setRequest: () => void 0,
resetRequest: () => void 0
};
function hrTimeToMilliseconds(time: number[]): number {
const seconds = time[0];
const nanoseconds = time[1];
@@ -193,18 +204,134 @@ namespace ts.server {
return `Content-Length: ${1 + len}\r\n\r\n${json}${newLine}`;
}
/**
* Allows to schedule next step in multistep operation
*/
interface NextStep {
immediate(action: () => void): void;
delay(ms: number, action: () => void): void;
}
/**
* External capabilities used by multistep operation
*/
interface MultistepOperationHost {
getCurrentRequestId(): number;
sendRequestCompletedEvent(requestId: number): void;
getServerHost(): ServerHost;
isCancellationRequested(): boolean;
executeWithRequestId(requestId: number, action: () => void): void;
logError(error: Error, message: string): void;
}
/**
* Represents operation that can schedule its next step to be executed later.
* Scheduling is done via instance of NextStep. If on current step subsequent step was not scheduled - operation is assumed to be completed.
*/
class MultistepOperation {
private requestId: number;
private timerHandle: any;
private immediateId: any;
private completed = true;
private readonly next: NextStep;
constructor(private readonly operationHost: MultistepOperationHost) {
this.next = {
immediate: action => this.immediate(action),
delay: (ms, action) => this.delay(ms, action)
}
}
public startNew(action: (next: NextStep) => void) {
this.complete();
this.requestId = this.operationHost.getCurrentRequestId();
this.completed = false;
this.executeAction(action);
}
private complete() {
if (!this.completed) {
if (this.requestId) {
this.operationHost.sendRequestCompletedEvent(this.requestId);
}
this.completed = true;
}
this.setTimerHandle(undefined);
this.setImmediateId(undefined);
}
private immediate(action: () => void) {
const requestId = this.requestId;
Debug.assert(requestId === this.operationHost.getCurrentRequestId(), "immediate: incorrect request id")
this.setImmediateId(this.operationHost.getServerHost().setImmediate(() => {
this.immediateId = undefined;
this.operationHost.executeWithRequestId(requestId, () => this.executeAction(action));
}));
}
private delay(ms: number, action: () => void) {
const requestId = this.requestId;
Debug.assert(requestId === this.operationHost.getCurrentRequestId(), "delay: incorrect request id")
this.setTimerHandle(this.operationHost.getServerHost().setTimeout(() => {
this.timerHandle = undefined;
this.operationHost.executeWithRequestId(requestId, () => this.executeAction(action));
}, ms));
}
private executeAction(action: (next: NextStep) => void) {
let stop = false;
try {
if (this.operationHost.isCancellationRequested()) {
stop = true;
}
else {
action(this.next);
}
}
catch (e) {
stop = true;
// ignore cancellation request
if (!(e instanceof OperationCanceledException)) {
this.operationHost.logError(e, `delayed processing of request ${this.requestId}`);
}
}
if (stop || !this.hasPendingWork()) {
this.complete();
}
}
private setTimerHandle(timerHandle: any) {;
if (this.timerHandle !== undefined) {
this.operationHost.getServerHost().clearTimeout(this.timerHandle);
}
this.timerHandle = timerHandle;
}
private setImmediateId(immediateId: number) {
if (this.immediateId !== undefined) {
this.operationHost.getServerHost().clearImmediate(this.immediateId);
}
this.immediateId = immediateId;
}
private hasPendingWork() {
return !!this.timerHandle || !!this.immediateId;
}
}
export class Session implements EventSender {
private readonly gcTimer: GcTimer;
protected projectService: ProjectService;
private errorTimer: any; /*NodeJS.Timer | number*/
private immediateId: any;
private changeSeq = 0;
private currentRequestId: number;
private errorCheck: MultistepOperation;
private eventHander: ProjectServiceEventHandler;
constructor(
private host: ServerHost,
cancellationToken: HostCancellationToken,
private readonly cancellationToken: ServerCancellationToken,
useSingleInferredProject: boolean,
protected readonly typingsInstaller: ITypingsInstaller,
private byteLength: (buf: string, encoding?: string) => number,
@@ -217,17 +344,35 @@ namespace ts.server {
? eventHandler || (event => this.defaultEventHandler(event))
: undefined;
const multistepOperationHost: MultistepOperationHost = {
executeWithRequestId: (requestId, action) => this.executeWithRequestId(requestId, action),
getCurrentRequestId: () => this.currentRequestId,
getServerHost: () => this.host,
logError: (err, cmd) => this.logError(err, cmd),
sendRequestCompletedEvent: requestId => this.sendRequestCompletedEvent(requestId),
isCancellationRequested: () => cancellationToken.isCancellationRequested()
}
this.errorCheck = new MultistepOperation(multistepOperationHost);
this.projectService = new ProjectService(host, logger, cancellationToken, useSingleInferredProject, typingsInstaller, this.eventHander);
this.gcTimer = new GcTimer(host, /*delay*/ 7000, logger);
}
private sendRequestCompletedEvent(requestId: number): void {
const event: protocol.RequestCompletedEvent = {
seq: 0,
type: "event",
event: "requestCompleted",
body: { request_seq: requestId }
};
this.send(event);
}
private defaultEventHandler(event: ProjectServiceEvent) {
switch (event.eventName) {
case ContextEvent:
const { project, fileName } = event.data;
this.projectService.logger.info(`got context event, updating diagnostics for ${fileName}`);
this.updateErrorCheck([{ fileName, project }], this.changeSeq,
(n) => n === this.changeSeq, 100);
this.errorCheck.startNew(next => this.updateErrorCheck(next, [{ fileName, project }], this.changeSeq, (n) => n === this.changeSeq, 100));
break;
case ConfigFileDiagEvent:
const { triggerFile, configFileName, diagnostics } = event.data;
@@ -284,7 +429,7 @@ namespace ts.server {
seq: 0,
type: "event",
event: eventName,
body: info,
body: info
};
this.send(ev);
}
@@ -342,18 +487,11 @@ namespace ts.server {
}, ms);
}
private updateErrorCheck(checkList: PendingErrorCheck[], seq: number,
matchSeq: (seq: number) => boolean, ms = 1500, followMs = 200, requireOpen = true) {
private updateErrorCheck(next: NextStep, checkList: PendingErrorCheck[], seq: number, matchSeq: (seq: number) => boolean, ms = 1500, followMs = 200, requireOpen = true) {
if (followMs > ms) {
followMs = ms;
}
if (this.errorTimer) {
this.host.clearTimeout(this.errorTimer);
}
if (this.immediateId) {
this.host.clearImmediate(this.immediateId);
this.immediateId = undefined;
}
let index = 0;
const checkOne = () => {
if (matchSeq(seq)) {
@@ -361,21 +499,18 @@ namespace ts.server {
index++;
if (checkSpec.project.containsFile(checkSpec.fileName, requireOpen)) {
this.syntacticCheck(checkSpec.fileName, checkSpec.project);
this.immediateId = this.host.setImmediate(() => {
next.immediate(() => {
this.semanticCheck(checkSpec.fileName, checkSpec.project);
this.immediateId = undefined;
if (checkList.length > index) {
this.errorTimer = this.host.setTimeout(checkOne, followMs);
}
else {
this.errorTimer = undefined;
next.delay(followMs, checkOne);
}
});
}
}
};
if ((checkList.length > index) && (matchSeq(seq))) {
this.errorTimer = this.host.setTimeout(checkOne, ms);
next.delay(ms, checkOne);
}
}
@@ -1040,7 +1175,8 @@ namespace ts.server {
if (project.compileOnSaveEnabled && project.languageServiceEnabled) {
result.push({
projectFileName: project.getProjectName(),
fileNames: project.getCompileOnSaveAffectedFileList(info)
fileNames: project.getCompileOnSaveAffectedFileList(info),
projectUsesOutFile: !!project.getCompilerOptions().outFile || !!project.getCompilerOptions().out
});
}
}
@@ -1086,7 +1222,7 @@ namespace ts.server {
}
}
private getDiagnostics(delay: number, fileNames: string[]) {
private getDiagnostics(next: NextStep, delay: number, fileNames: string[]): void {
const checkList = fileNames.reduce((accum: PendingErrorCheck[], uncheckedFileName: string) => {
const fileName = toNormalizedPath(uncheckedFileName);
const project = this.projectService.getDefaultProjectForFile(fileName, /*refreshInferredProjects*/ true);
@@ -1097,7 +1233,7 @@ namespace ts.server {
}, []);
if (checkList.length > 0) {
this.updateErrorCheck(checkList, this.changeSeq, (n) => n === this.changeSeq, delay);
this.updateErrorCheck(next, checkList, this.changeSeq, (n) => n === this.changeSeq, delay);
}
}
@@ -1334,7 +1470,7 @@ namespace ts.server {
: spans;
}
getDiagnosticsForProject(delay: number, fileName: string) {
private getDiagnosticsForProject(next: NextStep, delay: number, fileName: string): void {
const { fileNames, languageServiceDisabled } = this.getProjectInfoWorker(fileName, /*projectFileName*/ undefined, /*needFileNameList*/ true);
if (languageServiceDisabled) {
return;
@@ -1372,7 +1508,7 @@ namespace ts.server {
const checkList = fileNamesInProject.map(fileName => ({ fileName, project }));
// Project level error analysis runs on background files too, therefore
// doesn't require the file to be opened
this.updateErrorCheck(checkList, this.changeSeq, (n) => n == this.changeSeq, delay, 200, /*requireOpen*/ false);
this.updateErrorCheck(next, checkList, this.changeSeq, (n) => n == this.changeSeq, delay, 200, /*requireOpen*/ false);
}
}
@@ -1549,13 +1685,13 @@ namespace ts.server {
[CommandNames.SyntacticDiagnosticsSync]: (request: protocol.SyntacticDiagnosticsSyncRequest) => {
return this.requiredResponse(this.getSyntacticDiagnosticsSync(request.arguments));
},
[CommandNames.Geterr]: (request: protocol.Request) => {
const geterrArgs = <protocol.GeterrRequestArgs>request.arguments;
return { response: this.getDiagnostics(geterrArgs.delay, geterrArgs.files), responseRequired: false };
[CommandNames.Geterr]: (request: protocol.GeterrRequest) => {
this.errorCheck.startNew(next => this.getDiagnostics(next, request.arguments.delay, request.arguments.files));
return this.notRequired();
},
[CommandNames.GeterrForProject]: (request: protocol.Request) => {
const { file, delay } = <protocol.GeterrForProjectRequestArgs>request.arguments;
return { response: this.getDiagnosticsForProject(delay, file), responseRequired: false };
[CommandNames.GeterrForProject]: (request: protocol.GeterrForProjectRequest) => {
this.errorCheck.startNew(next => this.getDiagnosticsForProject(next, request.arguments.delay, request.arguments.file));
return this.notRequired();
},
[CommandNames.Change]: (request: protocol.ChangeRequest) => {
this.change(request.arguments);
@@ -1642,10 +1778,32 @@ namespace ts.server {
this.handlers.set(command, handler);
}
private setCurrentRequest(requestId: number): void {
Debug.assert(this.currentRequestId === undefined);
this.currentRequestId = requestId;
this.cancellationToken.setRequest(requestId);
}
private resetCurrentRequest(requestId: number): void {
Debug.assert(this.currentRequestId === requestId);
this.currentRequestId = undefined;
this.cancellationToken.resetRequest(requestId);
}
public executeWithRequestId<T>(requestId: number, f: () => T) {
try {
this.setCurrentRequest(requestId);
return f();
}
finally {
this.resetCurrentRequest(requestId);
}
}
public executeCommand(request: protocol.Request): { response?: any, responseRequired?: boolean } {
const handler = this.handlers.get(request.command);
if (handler) {
return handler(request);
return this.executeWithRequestId(request.seq, () => handler(request));
}
else {
this.logger.msg(`Unrecognized JSON command: ${JSON.stringify(request)}`, Msg.Err);
+2
View File
@@ -9,6 +9,7 @@ declare namespace ts.server {
data: any;
}
type RequireResult = { module: {}, error: undefined } | { module: undefined, error: {} };
export interface ServerHost extends System {
setTimeout(callback: (...args: any[]) => void, ms: number, ...args: any[]): any;
clearTimeout(timeoutId: any): void;
@@ -16,6 +17,7 @@ declare namespace ts.server {
clearImmediate(timeoutId: any): void;
gc?(): void;
trace?(s: string): void;
require?(initialPath: string, moduleName: string): RequireResult;
}
export interface SortedReadonlyArray<T> extends ReadonlyArray<T> {
@@ -295,8 +295,7 @@ namespace ts.server.typingsInstaller {
this.log.writeLine(`Installing typings ${JSON.stringify(typingsToInstall)}`);
}
const filteredTypings = this.filterTypings(typingsToInstall);
const scopedTypings = filteredTypings.map(x => `@types/${x}`);
if (scopedTypings.length === 0) {
if (filteredTypings.length === 0) {
if (this.log.isEnabled()) {
this.log.writeLine(`All typings are known to be missing or invalid - no need to go any further`);
}
@@ -316,6 +315,7 @@ namespace ts.server.typingsInstaller {
projectName: req.projectName
});
const scopedTypings = filteredTypings.map(typingsName);
this.installTypingsAsync(requestId, scopedTypings, cachePath, ok => {
try {
if (!ok) {
@@ -429,4 +429,10 @@ namespace ts.server.typingsInstaller {
protected abstract installWorker(requestId: number, args: string[], cwd: string, onRequestCompleted: RequestCompletedAction): void;
protected abstract sendResponse(response: SetTypings | InvalidateCachedTypings | BeginInstallTypes | EndInstallTypes): void;
}
/* @internal */
export function typingsName(packageName: string): string {
return `@types/${packageName}@ts${versionMajorMinor}`;
}
const versionMajorMinor = version.split(".").slice(0, 2).join(".");
}
+13 -19
View File
@@ -115,6 +115,7 @@ namespace ts.codefix {
registerCodeFix({
errorCodes: [
Diagnostics.Cannot_find_name_0.code,
Diagnostics.Cannot_find_namespace_0.code,
Diagnostics._0_refers_to_a_UMD_global_but_the_current_file_is_a_module_Consider_adding_an_import_instead.code
],
getCodeActions: (context: CodeFixContext) => {
@@ -416,8 +417,8 @@ namespace ts.codefix {
);
function getModuleSpecifierForNewImport() {
const fileName = sourceFile.path;
const moduleFileName = moduleSymbol.valueDeclaration.getSourceFile().path;
const fileName = sourceFile.fileName;
const moduleFileName = moduleSymbol.valueDeclaration.getSourceFile().fileName;
const sourceDirectory = getDirectoryPath(fileName);
const options = context.program.getCompilerOptions();
@@ -439,8 +440,7 @@ namespace ts.codefix {
return undefined;
}
const normalizedBaseUrl = toPath(options.baseUrl, getDirectoryPath(options.baseUrl), getCanonicalFileName);
let relativeName = tryRemoveParentDirectoryName(moduleFileName, normalizedBaseUrl);
let relativeName = getRelativePathIfInDirectory(moduleFileName, options.baseUrl);
if (!relativeName) {
return undefined;
}
@@ -477,9 +477,8 @@ namespace ts.codefix {
function tryGetModuleNameFromRootDirs() {
if (options.rootDirs) {
const normalizedRootDirs = map(options.rootDirs, rootDir => toPath(rootDir, /*basePath*/ undefined, getCanonicalFileName));
const normalizedTargetPath = getPathRelativeToRootDirs(moduleFileName, normalizedRootDirs);
const normalizedSourcePath = getPathRelativeToRootDirs(sourceDirectory, normalizedRootDirs);
const normalizedTargetPath = getPathRelativeToRootDirs(moduleFileName, options.rootDirs);
const normalizedSourcePath = getPathRelativeToRootDirs(sourceDirectory, options.rootDirs);
if (normalizedTargetPath !== undefined) {
const relativePath = normalizedSourcePath !== undefined ? getRelativePath(normalizedTargetPath, normalizedSourcePath) : normalizedTargetPath;
return removeFileExtension(relativePath);
@@ -546,9 +545,9 @@ namespace ts.codefix {
}
}
function getPathRelativeToRootDirs(path: Path, rootDirs: Path[]) {
function getPathRelativeToRootDirs(path: string, rootDirs: string[]) {
for (const rootDir of rootDirs) {
const relativeName = tryRemoveParentDirectoryName(path, rootDir);
const relativeName = getRelativePathIfInDirectory(path, rootDir);
if (relativeName !== undefined) {
return relativeName;
}
@@ -564,20 +563,15 @@ namespace ts.codefix {
return fileName;
}
function getRelativePathIfInDirectory(path: string, directoryPath: string) {
const relativePath = getRelativePathToDirectoryOrUrl(directoryPath, path, directoryPath, getCanonicalFileName, false);
return isRootedDiskPath(relativePath) || startsWith(relativePath, "..") ? undefined : relativePath;
}
function getRelativePath(path: string, directoryPath: string) {
const relativePath = getRelativePathToDirectoryOrUrl(directoryPath, path, directoryPath, getCanonicalFileName, false);
return moduleHasNonRelativeName(relativePath) ? "./" + relativePath : relativePath;
}
function tryRemoveParentDirectoryName(path: Path, parentDirectory: Path) {
const index = path.indexOf(parentDirectory);
if (index === 0) {
return endsWith(parentDirectory, directorySeparator)
? path.substring(parentDirectory.length)
: path.substring(parentDirectory.length + 1);
}
return undefined;
}
}
}
+47 -18
View File
@@ -25,7 +25,7 @@ namespace ts.codefix {
const forStatement = <ForStatement>token.parent.parent.parent;
const forInitializer = <VariableDeclarationList>forStatement.initializer;
if (forInitializer.declarations.length === 1) {
return createCodeFix("", forInitializer.pos, forInitializer.end - forInitializer.pos);
return createCodeFixToRemoveNode(forInitializer);
}
else {
return removeSingleItem(forInitializer.declarations, token);
@@ -35,7 +35,7 @@ namespace ts.codefix {
const forOfStatement = <ForOfStatement>token.parent.parent.parent;
if (forOfStatement.initializer.kind === SyntaxKind.VariableDeclarationList) {
const forOfInitializer = <VariableDeclarationList>forOfStatement.initializer;
return createCodeFix("{}", forOfInitializer.declarations[0].pos, forOfInitializer.declarations[0].end - forOfInitializer.declarations[0].pos);
return createCodeFix("{}", forOfInitializer.declarations[0].getStart(), forOfInitializer.declarations[0].getWidth());
}
break;
@@ -47,12 +47,12 @@ namespace ts.codefix {
case SyntaxKind.CatchClause:
const catchClause = <CatchClause>token.parent.parent;
const parameter = catchClause.variableDeclaration.getChildren()[0];
return createCodeFix("", parameter.pos, parameter.end - parameter.pos);
return createCodeFixToRemoveNode(parameter);
default:
const variableStatement = <VariableStatement>token.parent.parent.parent;
if (variableStatement.declarationList.declarations.length === 1) {
return createCodeFix("", variableStatement.pos, variableStatement.end - variableStatement.pos);
return createCodeFixToRemoveNode(variableStatement);
}
else {
const declarations = variableStatement.declarationList.declarations;
@@ -72,7 +72,7 @@ namespace ts.codefix {
case ts.SyntaxKind.Parameter:
const functionDeclaration = <FunctionDeclaration>token.parent.parent;
if (functionDeclaration.parameters.length === 1) {
return createCodeFix("", token.parent.pos, token.parent.end - token.parent.pos);
return createCodeFixToRemoveNode(token.parent);
}
else {
return removeSingleItem(functionDeclaration.parameters, token);
@@ -81,36 +81,43 @@ namespace ts.codefix {
// handle case where 'import a = A;'
case SyntaxKind.ImportEqualsDeclaration:
const importEquals = findImportDeclaration(token);
return createCodeFix("", importEquals.pos, importEquals.end - importEquals.pos);
return createCodeFixToRemoveNode(importEquals);
case SyntaxKind.ImportSpecifier:
const namedImports = <NamedImports>token.parent.parent;
if (namedImports.elements.length === 1) {
// Only 1 import and it is unused. So the entire declaration should be removed.
const importSpec = findImportDeclaration(token);
return createCodeFix("", importSpec.pos, importSpec.end - importSpec.pos);
return createCodeFixToRemoveNode(importSpec);
}
else {
return removeSingleItem(namedImports.elements, token);
}
// handle case where "import d, * as ns from './file'"
// handle case where "import d, * as ns from './file'"
// or "'import {a, b as ns} from './file'"
case SyntaxKind.ImportClause: // this covers both 'import |d|' and 'import |d,| *'
case SyntaxKind.ImportClause: // this covers both 'import |d|' and 'import |d,| *'
const importClause = <ImportClause>token.parent;
if (!importClause.namedBindings) { // |import d from './file'| or |import * as ns from './file'|
const importDecl = findImportDeclaration(importClause);
return createCodeFix("", importDecl.pos, importDecl.end - importDecl.pos);
return createCodeFixToRemoveNode(importDecl);
}
else { // import |d,| * as ns from './file'
return createCodeFix("", importClause.name.pos, importClause.namedBindings.pos - importClause.name.pos);
else {
// import |d,| * as ns from './file'
const start = importClause.name.getStart();
let end = findFirstNonSpaceCharPosStarting(importClause.name.end);
if (sourceFile.text.charCodeAt(end) === CharacterCodes.comma) {
end = findFirstNonSpaceCharPosStarting(end + 1);
}
return createCodeFix("", start, end - start);
}
case SyntaxKind.NamespaceImport:
const namespaceImport = <NamespaceImport>token.parent;
if (namespaceImport.name == token && !(<ImportClause>namespaceImport.parent).name) {
const importDecl = findImportDeclaration(namespaceImport);
return createCodeFix("", importDecl.pos, importDecl.end - importDecl.pos);
return createCodeFixToRemoveNode(importDecl);
}
else {
const start = (<ImportClause>namespaceImport.parent).name.end;
@@ -120,16 +127,14 @@ namespace ts.codefix {
break;
case SyntaxKind.PropertyDeclaration:
return createCodeFix("", token.parent.pos, token.parent.end - token.parent.pos);
case SyntaxKind.NamespaceImport:
return createCodeFix("", token.parent.pos, token.parent.end - token.parent.pos);
return createCodeFixToRemoveNode(token.parent);
}
if (isDeclarationName(token)) {
return createCodeFix("", token.parent.pos, token.parent.end - token.parent.pos);
return createCodeFixToRemoveNode(token.parent);
}
else if (isLiteralComputedPropertyDeclarationName(token)) {
return createCodeFix("", token.parent.parent.pos, token.parent.parent.end - token.parent.parent.pos);
return createCodeFixToRemoveNode(token.parent.parent);
}
else {
return undefined;
@@ -144,6 +149,30 @@ namespace ts.codefix {
return importDecl;
}
function createCodeFixToRemoveNode(node: Node) {
let end = node.getEnd();
const endCharCode = sourceFile.text.charCodeAt(end);
const afterEndCharCode = sourceFile.text.charCodeAt(end + 1);
if (isLineBreak(endCharCode)) {
end += 1;
}
// in the case of CR LF, you could have two consecutive new line characters for one new line.
// this needs to be differenciated from two LF LF chars that actually mean two new lines.
if (isLineBreak(afterEndCharCode) && endCharCode !== afterEndCharCode) {
end += 1;
}
const start = node.getStart();
return createCodeFix("", start, end - start);
}
function findFirstNonSpaceCharPosStarting(start: number) {
while (isWhiteSpace(sourceFile.text.charCodeAt(start))) {
start += 1;
}
return start;
}
function createCodeFix(newText: string, start: number, length: number): CodeAction[] {
return [{
description: formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Remove_declaration_for_Colon_0), { 0: token.getText() }),
+48 -10
View File
@@ -173,6 +173,18 @@ namespace ts.Completions {
// var y = require("/*completion position*/");
return getStringLiteralCompletionEntriesFromModuleNames(<StringLiteral>node, compilerOptions, host, typeChecker);
}
else if (isEqualityExpression(node.parent)) {
// Get completions from the type of the other operand
// i.e. switch (a) {
// case '/*completion position*/'
// }
return getStringLiteralCompletionEntriesFromType(typeChecker.getTypeAtLocation(node.parent.left === node ? node.parent.right : node.parent.left), typeChecker);
}
else if (isCaseOrDefaultClause(node.parent)) {
// Get completions from the type of the switch expression
// i.e. x === '/*completion position'
return getStringLiteralCompletionEntriesFromType(typeChecker.getTypeAtLocation((<SwitchStatement>node.parent.parent.parent).expression), typeChecker);
}
else {
const argumentInfo = SignatureHelp.getImmediatelyContainingArgumentInfo(node, position, sourceFile);
if (argumentInfo) {
@@ -184,7 +196,7 @@ namespace ts.Completions {
// Get completion for string literal from string literal type
// i.e. var x: "hi" | "hello" = "/*completion position*/"
return getStringLiteralCompletionEntriesFromContextualType(<StringLiteral>node, typeChecker);
return getStringLiteralCompletionEntriesFromType(typeChecker.getContextualType(<StringLiteral>node), typeChecker);
}
}
@@ -228,8 +240,7 @@ namespace ts.Completions {
return undefined;
}
function getStringLiteralCompletionEntriesFromContextualType(node: StringLiteral, typeChecker: TypeChecker): CompletionInfo | undefined {
const type = typeChecker.getContextualType(node);
function getStringLiteralCompletionEntriesFromType(type: Type, typeChecker: TypeChecker): CompletionInfo | undefined {
if (type) {
const entries: CompletionEntry[] = [];
addStringLiteralCompletionsFromType(type, entries, typeChecker);
@@ -904,13 +915,29 @@ namespace ts.Completions {
}
}
else if (sourceFile.languageVariant === LanguageVariant.JSX) {
if (kind === SyntaxKind.LessThanToken) {
isRightOfOpenTag = true;
location = contextToken;
}
else if (kind === SyntaxKind.SlashToken && contextToken.parent.kind === SyntaxKind.JsxClosingElement) {
isStartingCloseTag = true;
location = contextToken;
switch (contextToken.parent.kind) {
case SyntaxKind.JsxClosingElement:
if (kind === SyntaxKind.SlashToken) {
isStartingCloseTag = true;
location = contextToken;
}
break;
case SyntaxKind.BinaryExpression:
if (!((contextToken.parent as BinaryExpression).left.flags & NodeFlags.ThisNodeHasError)) {
// It has a left-hand side, so we're not in an opening JSX tag.
break;
}
// fall through
case SyntaxKind.JsxSelfClosingElement:
case SyntaxKind.JsxElement:
case SyntaxKind.JsxOpeningElement:
if (kind === SyntaxKind.LessThanToken) {
isRightOfOpenTag = true;
location = contextToken;
}
break;
}
}
}
@@ -1773,4 +1800,15 @@ namespace ts.Completions {
catch (e) {}
return undefined;
}
function isEqualityExpression(node: Node): node is BinaryExpression {
return isBinaryExpression(node) && isEqualityOperatorKind(node.operatorToken.kind);
}
function isEqualityOperatorKind(kind: SyntaxKind) {
return kind == SyntaxKind.EqualsEqualsToken ||
kind === SyntaxKind.ExclamationEqualsToken ||
kind === SyntaxKind.EqualsEqualsEqualsToken ||
kind === SyntaxKind.ExclamationEqualsEqualsToken;
}
}
+17 -25
View File
@@ -5,6 +5,10 @@ namespace ts.FindAllReferences {
return getReferencedSymbolsForNode(typeChecker, cancellationToken, node, sourceFiles, findInStrings, findInComments, isForRename);
}
export function convertReferences(referenceSymbols: ReferencedSymbol[]): ReferenceEntry[] {
return referenceSymbols && flatMap(referenceSymbols, r => r.references);
}
export function getReferencedSymbolsForNode(typeChecker: TypeChecker, cancellationToken: CancellationToken, node: Node, sourceFiles: SourceFile[], findInStrings?: boolean, findInComments?: boolean, isForRename?: boolean, implementations?: boolean): ReferencedSymbol[] | undefined {
if (!implementations) {
const special = getReferencedSymbolsSpecial(node, sourceFiles, typeChecker, cancellationToken);
@@ -277,7 +281,7 @@ namespace ts.FindAllReferences {
// if this symbol is visible from its parent container, e.g. exported, then bail out
// if symbol correspond to the union property - bail out
if (symbol.parent || (symbol.flags & SymbolFlags.SyntheticProperty)) {
if (symbol.parent || (symbol.flags & SymbolFlags.Transient && (<TransientSymbol>symbol).checkFlags & CheckFlags.SyntheticProperty)) {
return undefined;
}
@@ -402,22 +406,24 @@ namespace ts.FindAllReferences {
function getAllReferencesForKeyword(sourceFiles: SourceFile[], keywordKind: ts.SyntaxKind, cancellationToken: CancellationToken): ReferencedSymbol[] {
const name = tokenToString(keywordKind);
const definition: ReferencedSymbolDefinitionInfo = {
containerKind: "",
containerName: "",
fileName: "",
kind: ScriptElementKind.keyword,
name,
textSpan: createTextSpan(0, 1),
displayParts: [{ text: name, kind: ScriptElementKind.keyword }]
}
const references: ReferenceEntry[] = [];
for (const sourceFile of sourceFiles) {
cancellationToken.throwIfCancellationRequested();
addReferencesForKeywordInFile(sourceFile, keywordKind, name, cancellationToken, references);
}
if (!references.length) return undefined;
const definition: ReferencedSymbolDefinitionInfo = {
containerKind: "",
containerName: "",
fileName: references[0].fileName,
kind: ScriptElementKind.keyword,
name,
textSpan: references[0].textSpan,
displayParts: [{ text: name, kind: ScriptElementKind.keyword }]
}
return [{ definition, references }];
}
@@ -1316,20 +1322,6 @@ namespace ts.FindAllReferences {
return meaning;
}
export function convertReferences(referenceSymbols: ReferencedSymbol[]): ReferenceEntry[] {
if (!referenceSymbols) {
return undefined;
}
const referenceEntries: ReferenceEntry[] = [];
for (const referenceSymbol of referenceSymbols) {
addRange(referenceEntries, referenceSymbol.references);
}
return referenceEntries;
}
function isImplementation(node: Node): boolean {
if (!node) {
return false;
+2 -7
View File
@@ -1415,7 +1415,6 @@ namespace ts {
function findReferences(fileName: string, position: number): ReferencedSymbol[] {
const referencedSymbols = findReferencedSymbols(fileName, position, /*findInStrings*/ false, /*findInComments*/ false, /*isForRename*/false);
// Only include referenced symbols that have a valid definition.
return filter(referencedSymbols, rs => !!rs.definition);
}
@@ -1689,7 +1688,7 @@ namespace ts {
let allFixes: CodeAction[] = [];
forEach(errorCodes, error => {
forEach(deduplicate(errorCodes), error => {
cancellationToken.throwIfCancellationRequested();
const context = {
@@ -2075,9 +2074,5 @@ namespace ts {
throw new Error("getDefaultLibFilePath is only supported when consumed as a node module. ");
}
function initializeServices() {
objectAllocator = getServicesObjectAllocator();
}
initializeServices();
objectAllocator = getServicesObjectAllocator();
}
+1 -1
View File
@@ -1269,4 +1269,4 @@ namespace TypeScript.Services {
// TODO: it should be moved into a namespace though.
/* @internal */
const toolsVersion = "2.2";
const toolsVersion = "2.3";
+1 -1
View File
@@ -51,7 +51,7 @@ namespace ts.SymbolDisplay {
if (flags & SymbolFlags.Constructor) return ScriptElementKind.constructorImplementationElement;
if (flags & SymbolFlags.Property) {
if (flags & SymbolFlags.SyntheticProperty) {
if (flags & SymbolFlags.Transient && (<TransientSymbol>symbol).checkFlags & CheckFlags.SyntheticProperty) {
// If union property is result of union of non method (property/accessors/variables), it is labeled as property
const unionPropertyKind = forEach(typeChecker.getRootSymbols(symbol), rootSymbol => {
const rootSymbolFlags = rootSymbol.getFlags();
@@ -41,6 +41,7 @@ compile(process.argv.slice(2), {
* Please log a "breaking change" issue for any API breaking change affecting this issue
*/
"use strict";
exports.__esModule = true;
var ts = require("typescript");
function compile(fileNames, options) {
var program = ts.createProgram(fileNames, options);
@@ -71,6 +71,7 @@ fileNames.forEach(fileName => {
* Please log a "breaking change" issue for any API breaking change affecting this issue
*/
"use strict";
exports.__esModule = true;
var ts = require("typescript");
function delint(sourceFile) {
delintNode(sourceFile);
@@ -43,6 +43,7 @@ export function createProgram(rootFiles: string[], compilerOptionsJson: string):
* Please log a "breaking change" issue for any API breaking change affecting this issue
*/
"use strict";
exports.__esModule = true;
var ts = require("typescript");
function printError(error) {
if (!error) {
@@ -23,6 +23,7 @@ console.log(JSON.stringify(result));
* Please log a "breaking change" issue for any API breaking change affecting this issue
*/
"use strict";
exports.__esModule = true;
var ts = require("typescript");
var source = "let x: string = 'string'";
var result = ts.transpile(source, { module: ts.ModuleKind.CommonJS });
@@ -116,6 +116,7 @@ watch(currentDirectoryFiles, { module: ts.ModuleKind.CommonJS });
* Please log a "breaking change" issue for any API breaking change affecting this issue
*/
"use strict";
exports.__esModule = true;
var ts = require("typescript");
function watch(rootFileNames, options) {
var files = {};
@@ -31,6 +31,7 @@ export module A {
//// [part1.js]
"use strict";
exports.__esModule = true;
var A;
(function (A) {
var Utils;
@@ -44,6 +45,7 @@ var A;
})(A = exports.A || (exports.A = {}));
//// [part2.js]
"use strict";
exports.__esModule = true;
var A;
(function (A) {
// collision with 'Origin' var in other part of merged module
@@ -12,7 +12,7 @@ function f1(x: Color | string) {
if (typeof x === "number") {
>typeof x === "number" : boolean
>typeof x : string
>typeof x : "string" | "number" | "boolean" | "symbol" | "undefined" | "object" | "function"
>x : string | Color
>"number" : "number"
@@ -41,7 +41,7 @@ function f2(x: Color | string | string[]) {
if (typeof x === "object") {
>typeof x === "object" : boolean
>typeof x : string
>typeof x : "string" | "number" | "boolean" | "symbol" | "undefined" | "object" | "function"
>x : string | Color | string[]
>"object" : "object"
@@ -54,7 +54,7 @@ function f2(x: Color | string | string[]) {
}
if (typeof x === "number") {
>typeof x === "number" : boolean
>typeof x : string
>typeof x : "string" | "number" | "boolean" | "symbol" | "undefined" | "object" | "function"
>x : string | Color | string[]
>"number" : "number"
@@ -76,7 +76,7 @@ function f2(x: Color | string | string[]) {
}
if (typeof x === "string") {
>typeof x === "string" : boolean
>typeof x : string
>typeof x : "string" | "number" | "boolean" | "symbol" | "undefined" | "object" | "function"
>x : string | Color | string[]
>"string" : "string"
@@ -15,6 +15,7 @@ y = moduleA; // should be error
//// [aliasAssignments_moduleA.js]
"use strict";
exports.__esModule = true;
var someClass = (function () {
function someClass() {
}
@@ -23,6 +24,7 @@ var someClass = (function () {
exports.someClass = someClass;
//// [aliasAssignments_1.js]
"use strict";
exports.__esModule = true;
var moduleA = require("./aliasAssignments_moduleA");
var x = moduleA;
x = 1; // Should be error
@@ -24,6 +24,7 @@ var x: foo.A = foo.bar("hello"); // foo.A should be ok but foo.bar should be err
//// [aliasOnMergedModuleInterface_0.js]
//// [aliasOnMergedModuleInterface_1.js]
"use strict";
exports.__esModule = true;
var z;
z.bar("hello"); // This should be ok
var x = foo.bar("hello"); // foo.A should be ok but foo.bar should be error
@@ -29,6 +29,7 @@ class C2 {
//// [aliasUsage1_backbone.js]
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var Model = (function () {
function Model() {
}
@@ -47,6 +48,7 @@ var __extends = (this && this.__extends) || (function () {
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
var Backbone = require("./aliasUsage1_backbone");
var VisualizationModel = (function (_super) {
__extends(VisualizationModel, _super);
@@ -58,6 +60,7 @@ var VisualizationModel = (function (_super) {
exports.VisualizationModel = VisualizationModel;
//// [aliasUsage1_main.js]
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var moduleA = require("./aliasUsage1_moduleA");
var C2 = (function () {
function C2() {
@@ -23,6 +23,7 @@ var xs2: typeof moduleA[] = [moduleA];
//// [aliasUsageInArray_backbone.js]
"use strict";
exports.__esModule = true;
var Model = (function () {
function Model() {
}
@@ -41,6 +42,7 @@ var __extends = (this && this.__extends) || (function () {
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
exports.__esModule = true;
var Backbone = require("./aliasUsageInArray_backbone");
var VisualizationModel = (function (_super) {
__extends(VisualizationModel, _super);
@@ -52,6 +54,7 @@ var VisualizationModel = (function (_super) {
exports.VisualizationModel = VisualizationModel;
//// [aliasUsageInArray_main.js]
"use strict";
exports.__esModule = true;
var moduleA = require("./aliasUsageInArray_moduleA");
var xs = [moduleA];
var xs2 = [moduleA];
@@ -22,6 +22,7 @@ f = (x) => moduleA;
//// [aliasUsageInFunctionExpression_backbone.js]
"use strict";
exports.__esModule = true;
var Model = (function () {
function Model() {
}
@@ -40,6 +41,7 @@ var __extends = (this && this.__extends) || (function () {
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
exports.__esModule = true;
var Backbone = require("./aliasUsageInFunctionExpression_backbone");
var VisualizationModel = (function (_super) {
__extends(VisualizationModel, _super);
@@ -51,6 +53,7 @@ var VisualizationModel = (function (_super) {
exports.VisualizationModel = VisualizationModel;
//// [aliasUsageInFunctionExpression_main.js]
"use strict";
exports.__esModule = true;
var moduleA = require("./aliasUsageInFunctionExpression_moduleA");
var f = function (x) { return x; };
f = function (x) { return moduleA; };
@@ -26,6 +26,7 @@ var r2 = foo({ a: <IHasVisualizationModel>null });
//// [aliasUsageInGenericFunction_backbone.js]
"use strict";
exports.__esModule = true;
var Model = (function () {
function Model() {
}
@@ -44,6 +45,7 @@ var __extends = (this && this.__extends) || (function () {
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
exports.__esModule = true;
var Backbone = require("./aliasUsageInGenericFunction_backbone");
var VisualizationModel = (function (_super) {
__extends(VisualizationModel, _super);
@@ -55,6 +57,7 @@ var VisualizationModel = (function (_super) {
exports.VisualizationModel = VisualizationModel;
//// [aliasUsageInGenericFunction_main.js]
"use strict";
exports.__esModule = true;
var moduleA = require("./aliasUsageInGenericFunction_moduleA");
function foo(x) {
return x;
@@ -28,6 +28,7 @@ class N2 {
//// [aliasUsageInIndexerOfClass_backbone.js]
"use strict";
exports.__esModule = true;
var Model = (function () {
function Model() {
}
@@ -46,6 +47,7 @@ var __extends = (this && this.__extends) || (function () {
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
exports.__esModule = true;
var Backbone = require("./aliasUsageInIndexerOfClass_backbone");
var VisualizationModel = (function (_super) {
__extends(VisualizationModel, _super);
@@ -57,6 +59,7 @@ var VisualizationModel = (function (_super) {
exports.VisualizationModel = VisualizationModel;
//// [aliasUsageInIndexerOfClass_main.js]
"use strict";
exports.__esModule = true;
var moduleA = require("./aliasUsageInIndexerOfClass_moduleA");
var N = (function () {
function N() {
@@ -23,6 +23,7 @@ var c: { y: { z: IHasVisualizationModel } } = { y: { z: moduleA } };
//// [aliasUsageInObjectLiteral_backbone.js]
"use strict";
exports.__esModule = true;
var Model = (function () {
function Model() {
}
@@ -41,6 +42,7 @@ var __extends = (this && this.__extends) || (function () {
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
exports.__esModule = true;
var Backbone = require("./aliasUsageInObjectLiteral_backbone");
var VisualizationModel = (function (_super) {
__extends(VisualizationModel, _super);
@@ -52,6 +54,7 @@ var VisualizationModel = (function (_super) {
exports.VisualizationModel = VisualizationModel;
//// [aliasUsageInObjectLiteral_main.js]
"use strict";
exports.__esModule = true;
var moduleA = require("./aliasUsageInObjectLiteral_moduleA");
var a = { x: moduleA };
var b = { x: moduleA };
@@ -26,6 +26,7 @@ var f: { x: IHasVisualizationModel } = <{ x: IHasVisualizationModel }>null ? { x
//// [aliasUsageInOrExpression_backbone.js]
"use strict";
exports.__esModule = true;
var Model = (function () {
function Model() {
}
@@ -44,6 +45,7 @@ var __extends = (this && this.__extends) || (function () {
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
exports.__esModule = true;
var Backbone = require("./aliasUsageInOrExpression_backbone");
var VisualizationModel = (function (_super) {
__extends(VisualizationModel, _super);
@@ -55,6 +57,7 @@ var VisualizationModel = (function (_super) {
exports.VisualizationModel = VisualizationModel;
//// [aliasUsageInOrExpression_main.js]
"use strict";
exports.__esModule = true;
var moduleA = require("./aliasUsageInOrExpression_moduleA");
var i;
var d1 = i || moduleA;
@@ -26,6 +26,7 @@ class D extends C<IHasVisualizationModel> {
//// [aliasUsageInTypeArgumentOfExtendsClause_backbone.js]
"use strict";
exports.__esModule = true;
var Model = (function () {
function Model() {
}
@@ -44,6 +45,7 @@ var __extends = (this && this.__extends) || (function () {
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
exports.__esModule = true;
var Backbone = require("./aliasUsageInTypeArgumentOfExtendsClause_backbone");
var VisualizationModel = (function (_super) {
__extends(VisualizationModel, _super);
@@ -65,6 +67,7 @@ var __extends = (this && this.__extends) || (function () {
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
exports.__esModule = true;
var moduleA = require("./aliasUsageInTypeArgumentOfExtendsClause_moduleA");
var C = (function () {
function C() {
@@ -22,6 +22,7 @@ var m: typeof moduleA = i;
//// [aliasUsageInVarAssignment_backbone.js]
"use strict";
exports.__esModule = true;
var Model = (function () {
function Model() {
}
@@ -40,6 +41,7 @@ var __extends = (this && this.__extends) || (function () {
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
exports.__esModule = true;
var Backbone = require("./aliasUsageInVarAssignment_backbone");
var VisualizationModel = (function (_super) {
__extends(VisualizationModel, _super);
@@ -51,5 +53,6 @@ var VisualizationModel = (function (_super) {
exports.VisualizationModel = VisualizationModel;
//// [aliasUsageInVarAssignment_main.js]
"use strict";
exports.__esModule = true;
var i;
var m = i;
@@ -20,12 +20,15 @@ export var a = function () {
//// [aliasUsedAsNameValue_0.js]
"use strict";
exports.__esModule = true;
//// [aliasUsedAsNameValue_1.js]
"use strict";
exports.__esModule = true;
function b(a) { return null; }
exports.b = b;
//// [aliasUsedAsNameValue_2.js]
"use strict";
exports.__esModule = true;
///<reference path='aliasUsedAsNameValue_0.ts' />
///<reference path='aliasUsedAsNameValue_1.ts' />
var mod = require("./aliasUsedAsNameValue_0");
@@ -12,6 +12,8 @@ var d = b.q3;
//// [aliasWithInterfaceExportAssignmentUsedInVarInitializer_0.js]
"use strict";
exports.__esModule = true;
//// [aliasWithInterfaceExportAssignmentUsedInVarInitializer_1.js]
"use strict";
exports.__esModule = true;
var d = b.q3;
@@ -12,6 +12,7 @@ export class Foo {
//// [b.js]
"use strict";
exports.__esModule = true;
var Foo = (function () {
function Foo() {
}
@@ -20,5 +21,6 @@ var Foo = (function () {
exports.Foo = Foo;
//// [a.js]
"use strict";
exports.__esModule = true;
var b_1 = require("./b");
exports.x = new b_1["default"].Foo();
@@ -12,6 +12,7 @@ Foo.default.default.foo();
//// [a.js]
"use strict";
exports.__esModule = true;
var Foo = require("./b");
Foo["default"].bar();
Foo["default"]["default"].foo();
@@ -13,5 +13,6 @@ export var x = new Foo();
//// [a.js]
"use strict";
exports.__esModule = true;
var b_1 = require("./b");
exports.x = new b_1["default"]();
@@ -12,6 +12,7 @@ Foo.foo();
//// [a.js]
"use strict";
exports.__esModule = true;
var b_1 = require("./b");
b_1["default"].bar();
b_1["default"].foo();
@@ -5,5 +5,6 @@ export const a = 1
//// [alwaysStrictModule4.js]
"use strict";
exports.__esModule = true;
// Module commonjs
exports.a = 1;
@@ -5,5 +5,6 @@ export const a = 1;
//// [alwaysStrictModule6.js]
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
// Targeting ES5
exports.a = 1;
@@ -28,6 +28,7 @@ var n: number;
// Ambient external import declaration referencing ambient external module using top level module name
//// [consumer.js]
"use strict";
exports.__esModule = true;
// Ambient external module members are always exported with or without export keyword when module lacks export assignment
var imp3 = require("equ2");
var n = imp3.x;
@@ -34,6 +34,7 @@ foo(fileText);
//// [user.js]
"use strict";
exports.__esModule = true;
///<reference path="declarations.d.ts" />
var foobarbaz_1 = require("foobarbaz");
foobarbaz_1.foo(foobarbaz_1.baz);
@@ -4,4 +4,5 @@ export declare module "M" { }
//// [ambientExternalModuleInsideNonAmbientExternalModule.js]
define(["require", "exports"], function (require, exports) {
"use strict";
exports.__esModule = true;
});
@@ -19,6 +19,7 @@ declare module "M" {
//// [ambientExternalModuleMerging_use.js]
define(["require", "exports", "M"], function (require, exports, M) {
"use strict";
exports.__esModule = true;
// Should be strings
var x = M.x;
var y = M.y;
@@ -22,5 +22,6 @@ var c = new A();
//// [ambientExternalModuleWithInternalImportDeclaration_1.js]
define(["require", "exports", "M"], function (require, exports, A) {
"use strict";
exports.__esModule = true;
var c = new A();
});
@@ -21,5 +21,6 @@ var c = new A();
//// [ambientExternalModuleWithoutInternalImportDeclaration_1.js]
define(["require", "exports", "M"], function (require, exports, A) {
"use strict";
exports.__esModule = true;
var c = new A();
});
@@ -8,4 +8,5 @@ export declare module M { }
//// [ambientInsideNonAmbientExternalModule.js]
define(["require", "exports"], function (require, exports) {
"use strict";
exports.__esModule = true;
});
@@ -6,3 +6,4 @@ export declare namespace Foo {
//// [ambientNameRestrictions.js]
"use strict";
exports.__esModule = true;
@@ -15,6 +15,7 @@ foo(bar, baz, boom);
//// [user.js]
"use strict";
exports.__esModule = true;
///<reference path="declarations.d.ts"/>
var jquery_1 = require("jquery");
var baz = require("fs");
@@ -14,3 +14,4 @@ import foo from "foo";
//// [user.js]
"use strict";
exports.__esModule = true;
@@ -16,3 +16,4 @@ import foo, {bar} from "foo";
//// [user.js]
"use strict";
exports.__esModule = true;

Some files were not shown because too many files have changed in this diff Show More