diff --git a/Jakefile.js b/Jakefile.js index 5ae4ab6e497..e6b64789a5f 100644 --- a/Jakefile.js +++ b/Jakefile.js @@ -5,7 +5,6 @@ var os = require("os"); var path = require("path"); var child_process = require("child_process"); var Linter = require("tslint"); -var readline = require("readline"); // Variables var compilerDirectory = "src/compiler/"; @@ -54,7 +53,6 @@ var compilerSources = [ "transformer.ts", "sourcemap.ts", "comments.ts", - "printer.ts", "declarationEmitter.ts", "emitter.ts", "program.ts", @@ -87,7 +85,6 @@ var servicesSources = [ "transformer.ts", "sourcemap.ts", "comments.ts", - "printer.ts", "declarationEmitter.ts", "emitter.ts", "program.ts", @@ -193,17 +190,6 @@ var harnessSources = harnessCoreSources.concat([ return path.join(serverDirectory, f); })); -var librarySourceMap = [ - { target: "lib.core.d.ts", sources: ["header.d.ts", "core.d.ts"] }, - { target: "lib.dom.d.ts", sources: ["importcore.d.ts", "intl.d.ts", "dom.generated.d.ts"] }, - { target: "lib.webworker.d.ts", sources: ["importcore.d.ts", "intl.d.ts", "webworker.generated.d.ts"] }, - { target: "lib.scriptHost.d.ts", sources: ["importcore.d.ts", "scriptHost.d.ts"] }, - { target: "lib.d.ts", sources: ["header.d.ts", "core.d.ts", "intl.d.ts", "dom.generated.d.ts", "webworker.importscripts.d.ts", "scriptHost.d.ts"] }, - { target: "lib.core.es6.d.ts", sources: ["header.d.ts", "core.d.ts", "es6.d.ts"] }, - { target: "lib.es6.d.ts", sources: ["header.d.ts", "es6.d.ts", "core.d.ts", "intl.d.ts", "dom.generated.d.ts", "dom.es6.d.ts", "webworker.importscripts.d.ts", "scriptHost.d.ts"] }, - { target: "lib.core.es7.d.ts", sources: ["header.d.ts", "core.d.ts", "es6.d.ts", "es7.d.ts"] }, - { target: "lib.es7.d.ts", sources: ["header.d.ts", "es6.d.ts", "es7.d.ts", "core.d.ts", "intl.d.ts", "dom.generated.d.ts", "dom.es6.d.ts", "webworker.importscripts.d.ts", "scriptHost.d.ts"] } -]; var es2015LibrarySources = [ "es2015.core.d.ts", "es2015.collection.d.ts", @@ -314,6 +300,10 @@ var builtLocalCompiler = path.join(builtLocalDirectory, compilerFilename); */ function compileFile(outFile, sources, prereqs, prefixes, useBuiltCompiler, opts, callback) { file(outFile, prereqs, function() { + if (process.env.USE_TRANSFORMS === "false") { + useBuiltCompiler = false; + } + var compilerPath = useBuiltCompiler ? builtLocalCompiler : LKGCompiler; var options = "--noImplicitAny --noEmitOnError --pretty"; opts = opts || {}; @@ -357,10 +347,6 @@ function compileFile(outFile, sources, prereqs, prefixes, useBuiltCompiler, opts options += " --stripInternal"; } - if (useBuiltCompiler && !environmentVariableIsDisabled("USE_TRANSFORMS")) { - console.warn("\u001b[93mwarning: 'USE_TRANSFORMS' environment variable is not set to 'false'. Experimental transforms will be enabled by default.\u001b[0m"); - } - var cmd = host + " " + compilerPath + " " + options + " "; cmd = cmd + sources.join(" "); console.log(cmd + "\n"); @@ -723,33 +709,16 @@ function cleanTestDirs() { } // used to pass data from jake command line directly to run.js -function writeTestConfigFile(tests, light, taskConfigFolder, workerCount, stackTraceLimit) { - var testConfig; - if (tests) { - (testConfig || (testConfig = {})).test = [tests]; - } - - if (light) { - (testConfig || (testConfig = {})).light = light; - } - - if (workerCount) { - (testConfig || (testConfig = {})).workerCount = workerCount; - } - - if (taskConfigFolder) { - (testConfig || (testConfig = {})).taskConfigFolder = taskConfigFolder; - } - - if (/^(\d+|full)$/.test(stackTraceLimit)) { - (testConfig || (testConfig = {})).stackTraceLimit = stackTraceLimit; - } - - if (testConfig) { - var testConfigContents = JSON.stringify(testConfig); - console.log('Running tests with config: ' + testConfigContents); - fs.writeFileSync('test.config', testConfigContents); - } +function writeTestConfigFile(tests, light, taskConfigsFolder, workerCount, stackTraceLimit) { + var testConfigContents = JSON.stringify({ + test: tests ? [tests] : undefined, + light: light, + workerCount: workerCount, + taskConfigsFolder: taskConfigsFolder, + stackTraceLimit: stackTraceLimit + }); + console.log('Running tests with config: ' + testConfigContents); + fs.writeFileSync('test.config', testConfigContents); } function deleteTemporaryProjectOutput() { @@ -758,257 +727,8 @@ function deleteTemporaryProjectOutput() { } } -function runTestsAndWriteOutput(file, defaultSubsets) { - cleanTestDirs(); - var tests = process.env.test || process.env.tests || process.env.t; - var light = process.env.light || false; - var testConfigFile = 'test.config'; - if (fs.existsSync(testConfigFile)) { - fs.unlinkSync(testConfigFile); - } - - writeTestConfigFile(testConfigFile, tests, light, 10); - - if (tests && tests.toLocaleLowerCase() === "rwc") { - testTimeout = 100000; - } - - var subsetRegexes; - var subsets; - if (tests || defaultSubsets.length === 0) { - subsetRegexes = [tests]; - subsets = [tests]; - } - else { - subsets = []; - subsetRegexes = []; - negations = []; - for (var i = 0; i < defaultSubsets.length; ++i) { - var subset = defaultSubsets[i]; - subsets.push(subset.name); - subsetRegexes.push(subset.pattern); - negations.push(subset.pattern); - } - - subsets.push("other"); - subsetRegexes.push("^(?!" + negations.join("|") + ")"); - } - - var out = fs.createWriteStream(file); - var outFileNames = subsetRegexes.length !== 1 ? [] : undefined; - var tapRange = /^(\d+)\.\.(\d+)(?:$|\r\n?|\n)/; - var tapOk = /^ok\s/; - var tapNotOk = /^not\sok\s/; - var tapComment = /^#(?: (tests|pass|fail) (\d+)$)?/; - var typeError = /^\s+TypeError:/; - var debugError = /^\s+Error:\sDebug\sFailure\./; - var progress = new ProgressBar(); - var totalTypeErrorCount = 0; - var totalDebugErrorCount = 0; - var totalReportedTestCount = 0; - var totalReportedPassCount = 0; - var totalReportedFailCount = 0; - var counter = subsetRegexes.length; - var errorStatus; - subsetRegexes.forEach(function (subsetRegex, i) { - var expectedTestCount = 0; - var testCount = 0; - var failureCount = 0; - var successCount = 0; - var reportedTestCount = 0; - var reportedPassCount = 0; - var reportedFailCount = 0; - var comments = []; - var typeErrorCount = 0; - var debugErrorCount = 0; - var outFileName; - var outFile; - if (subsetRegexes.length === 1) { - outFile = out; - } - else { - outFileName = path.join(os.tmpdir(), path.basename(file) + "." + i); - outFileNames[i] = outFileName; - outFile = fs.createWriteStream(outFileName); - } - - var args = []; - args.push("-R", "tap"); - args.push("--no-colors"); - args.push("-t", testTimeout); - if (subsetRegex) { - args.push("-g", '"' + subsetRegex + '"'); - } - - args.push(run); - - var cmd = "mocha " + args.join(" "); - if (subsetRegexes.length === 1) { - console.log(cmd); - } - - updateProgress(0); - - var p = child_process.spawn( - process.platform === "win32" ? "cmd" : "/bin/sh", - process.platform === "win32" ? ["/c", cmd] : ["-c", cmd], { - windowsVerbatimArguments: true, - env: { NODE_ENV: "development" } - }); - - var rl = readline.createInterface({ - input: p.stdout, - terminal: false - }); - - var start; - var end; - rl.on("line", function (line) { - if (!start) start = Date.now(); - var m = tapRange.exec(line); - if (m) { - expectedTestCount = parseInt(m[2]); - return; - } - - if (tapOk.test(line)) { - outFile.write(line.replace(/^ok\s+\d+\s+/, "ok ") + os.EOL); - successCount++; - } - else if (tapNotOk.test(line)) { - outFile.write(line.replace(/^not\s+ok\s+\d+\s+/, "not ok ") + os.EOL); - failureCount++; - } - else { - m = tapComment.exec(line); - if (m) { - if (m[1] === "tests") { - end = Date.now(); - reportedTestCount = parseInt(m[2]); - } - else if (m[1] === "pass") { - reportedPassCount = parseInt(m[2]); - } - else if (m[1] === "fail") { - reportedFailCount = parseInt(m[2]); - } - else { - outFile.write(line + os.EOL); - } - } - else { - outFile.write(line + os.EOL); - if (typeError.test(line)) { - typeErrorCount++; - } - else if (debugError.test(line)) { - debugErrorCount++; - } - } - return; - } - - testCount++; - - var percentComplete = testCount * 100 / expectedTestCount; - updateProgress(percentComplete); - }); - - p.on("exit", function (status) { - totalReportedTestCount += reportedTestCount; - totalReportedPassCount += reportedPassCount; - totalReportedFailCount += reportedFailCount; - totalTypeErrorCount += typeErrorCount; - totalDebugErrorCount += debugErrorCount; - - var duration = end - start; - var summary = - "pass: " + reportedPassCount + "/" + reportedTestCount + - ", duration: " + (duration / 1000).toFixed(2) + "s"; - - updateProgress(100, summary); - - if (subsetRegexes.length !== 1) { - outFile.close(); - } - - if (status && !errorStatus) { - errorStatus = status; - } - - counter--; - if (counter === 0) { - if (subsetRegexes.length !== 1) { - concatenate(); - } - else { - finish(); - } - } - }); - - function updateProgress(percentComplete, status) { - var title = status || (percentComplete < 100 ? "running..." : "done"); - if (subsetRegexes.length !== 1) { - title = "[" + subsets[i] + "] " + title; - } - - progress.update(percentComplete, - /*foregroundColor*/ failureCount > 0 - ? "red" - : successCount === expectedTestCount - ? "green" - : "cyan", - /*backgroundColor*/ "gray", - title, - i - ); - } - }); - - function concatenate() { - if (outFileNames.length > 0) { - var outFileName = outFileNames.shift(); - var outFile = fs.createReadStream(outFileName); - outFile.pipe(out, { end: false }); - outFile.on("end", function () { - fs.unlinkSync(outFileName); - concatenate(); - }); - return; - } - - finish(); - } - - function finish() { - out.write( - "# tests " + totalReportedTestCount + os.EOL + - "# pass " + totalReportedPassCount + os.EOL + - "# fail " + totalReportedFailCount + os.EOL); - console.log("# tests " + totalReportedTestCount); - console.log("# pass " + totalReportedPassCount); - console.log("# fail " + totalReportedFailCount); - - if (totalTypeErrorCount) { - console.log("# type errors " + totalTypeErrorCount); - } - - if (totalDebugErrorCount) { - console.log("# debug errors " + totalDebugErrorCount); - } - - deleteTemporaryProjectOutput(); - if (totalReportedFailCount) { - fail("Test failures reported: " + totalReportedFailCount); - } - else { - complete(); - } - } -} - -function runConsoleTests(defaultReporter, runInParallel, dirty) { +function runConsoleTests(defaultReporter, runInParallel) { + var dirty = process.env.dirty; if (!dirty) { cleanTestDirs(); } @@ -1016,7 +736,7 @@ function runConsoleTests(defaultReporter, runInParallel, dirty) { var debug = process.env.debug || process.env.d; tests = process.env.test || process.env.tests || process.env.t; var light = process.env.light || false; - var stackTraceLimit = process.env.stackTraceLimit || 1; + var stackTraceLimit = process.env.stackTraceLimit; var testConfigFile = 'test.config'; if (fs.existsSync(testConfigFile)) { fs.unlinkSync(testConfigFile); @@ -1134,33 +854,11 @@ task("runtests-parallel", ["build-rules", "tests", builtLocalDirectory], functio runConsoleTests('min', /*runInParallel*/ true); }, {async: true}); -desc("Runs the tests using the built run.js file. Optional arguments are: t[ests]=regex r[eporter]=[list|spec|json|] d[ebug]=true color[s]=false lint=true."); +desc("Runs the tests using the built run.js file. Optional arguments are: t[ests]=regex r[eporter]=[list|spec|json|] d[ebug]=true color[s]=false lint=true dirty=false."); task("runtests", ["build-rules", "tests", builtLocalDirectory], function() { runConsoleTests('mocha-fivemat-progress-reporter', /*runInParallel*/ false); }, {async: true}); -task("runtests-file", ["build-rules", "tests", builtLocalDirectory], function () { - var subsets = []; - var cores = os.cpus().length; - if (cores > 1) { - subsets.push({ name: "conformance", pattern: "^conformance\\b" }); - subsets.push({ name: "compiler", pattern: "^compiler\\b" }); - subsets.push({ name: "projects", pattern: "^Projects\\b" }); - if (cores > 4) { - subsets.push({ name: "fourslash", pattern: "^fourslash\\b" }); - subsets.push({ name: "fourslash (shims, shims-pp, server)", pattern: "^fourslash-" }); - } - else { - subsets.push({ name: "fourslash", pattern: "^fourslash" }); - } - } - runTestsAndWriteOutput("tests/baselines/local/testresults.tap", subsets); -}, { async: true }); - -task("runtests-dirty", ["build-rules", "tests", builtLocalDirectory], function () { - runConsoleTests("mocha-fivemat-progress-reporter", /*runInParallel*/ false, /*dirty*/ true); -}, { async: true }); - desc("Generates code coverage data via instanbul"); task("generate-code-coverage", ["tests", builtLocalDirectory], function () { var cmd = 'istanbul cover node_modules/mocha/bin/_mocha -- -R min -t ' + testTimeout + ' ' + run; @@ -1442,94 +1140,6 @@ task("lint-server", ["build-rules"], function() { } }); -function ProgressBar() { - this._progress = []; - this._lineCount = 0; -} -ProgressBar.prototype = { - progressChars: ["\u0020", "\u2591", "\u2592", "\u2593", "\u2588"], - colors: { - foreground: { - black: "\u001b[90m", - red: "\u001b[91m", - green: "\u001b[92m", - yellow: "\u001b[93m", - blue: "\u001b[94m", - magenta: "\u001b[95m", - cyan: "\u001b[96m", - white: "\u001b[97m", - gray: "\u001b[37m" - }, - background: { - black: "\u001b[40m", - red: "\u001b[41m", - green: "\u001b[42m", - yellow: "\u001b[43m", - blue: "\u001b[44m", - magenta: "\u001b[45m", - cyan: "\u001b[46m", - white: "\u001b[47m", - gray: "\u001b[100m" - }, - reset: "\u001b[0m" - }, - update: function (percentComplete, foregroundColor, backgroundColor, title, index) { - if (index === undefined) index = 0; - - var progress = ""; - for (var i = 0; i < 100; i += 4) { - progress += this.progressChars[Math.floor(Math.max(0, Math.min(4, percentComplete - i)))]; - } - - foregroundColor = foregroundColor && this.colors.foreground[foregroundColor]; - backgroundColor = backgroundColor && this.colors.background[backgroundColor]; - if (foregroundColor || backgroundColor) { - if (foregroundColor) { - progress = foregroundColor + progress; - } - if (backgroundColor) { - progress = backgroundColor + progress; - } - - progress += this.colors.reset; - } - - if (title) { - progress += " " + title; - } - - if (this._progress[index] !== progress) { - this._progress[index] = progress; - this._print(index); - } - }, - clear: function () { - if (this._lastProgress) { - readline.moveCursor(process.stdout, -process.stdout.columns, 0); - readline.clearLine(process.stdout, 1); - this._lastProgress = undefined; - this.visible = false; - } - }, - _print: function (index) { - readline.moveCursor(process.stdout, -process.stdout.columns, -this._lineCount); - var lineCount = 0; - for (var i = 0; i < this._progress.length; i++) { - if (i === index) { - readline.clearLine(process.stdout, 1); - process.stdout.write(this._progress[i] + os.EOL); - } - else { - readline.moveCursor(process.stdout, -process.stdout.columns, +1); - } - - lineCount++; - } - - this._lineCount = lineCount; - } -}; - function environmentVariableIsEnabled(name) { return /^(y(es)?|t(rue)?|on|enabled?|1|\+)$/.test(process.env[name]); } diff --git a/src/compiler/commandLineParser.ts b/src/compiler/commandLineParser.ts index b8c5fb7db3d..d9272fb2b62 100644 --- a/src/compiler/commandLineParser.ts +++ b/src/compiler/commandLineParser.ts @@ -374,12 +374,6 @@ namespace ts { type: "boolean", description: Diagnostics.Do_not_emit_use_strict_directives_in_module_output }, - { - name: "useLegacyEmitter", - type: "boolean", - experimental: true, - description: Diagnostics.Use_the_legacy_emitter_instead_of_the_transforming_emitter - }, { name: "listEmittedFiles", type: "boolean" diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 852b3ff9895..034bd27b147 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -2773,10 +2773,6 @@ "code": 6131 }, - "Use the legacy emitter instead of the transforming emitter.": { - "category": "Message", - "code": 6132 - }, "Variable '{0}' implicitly has an '{1}' type.": { "category": "Error", "code": 7005 diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 185719abddc..868ede1b0a8 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -1,285 +1,11 @@ /// -/// +/// /// +/// +/// /* @internal */ namespace ts { - export function getResolvedExternalModuleName(host: EmitHost, file: SourceFile): string { - return file.moduleName || getExternalModuleNameFromPath(host, file.fileName); - } - - export function getExternalModuleNameFromDeclaration(host: EmitHost, resolver: EmitResolver, declaration: ImportEqualsDeclaration | ImportDeclaration | ExportDeclaration): string { - const file = resolver.getExternalModuleFileFromDeclaration(declaration); - if (!file || isDeclarationFile(file)) { - return undefined; - } - return getResolvedExternalModuleName(host, file); - } - - type DependencyGroup = Array; - - const enum Jump { - Break = 1 << 1, - Continue = 1 << 2, - Return = 1 << 3 - } - - const entities: Map = { - "quot": 0x0022, - "amp": 0x0026, - "apos": 0x0027, - "lt": 0x003C, - "gt": 0x003E, - "nbsp": 0x00A0, - "iexcl": 0x00A1, - "cent": 0x00A2, - "pound": 0x00A3, - "curren": 0x00A4, - "yen": 0x00A5, - "brvbar": 0x00A6, - "sect": 0x00A7, - "uml": 0x00A8, - "copy": 0x00A9, - "ordf": 0x00AA, - "laquo": 0x00AB, - "not": 0x00AC, - "shy": 0x00AD, - "reg": 0x00AE, - "macr": 0x00AF, - "deg": 0x00B0, - "plusmn": 0x00B1, - "sup2": 0x00B2, - "sup3": 0x00B3, - "acute": 0x00B4, - "micro": 0x00B5, - "para": 0x00B6, - "middot": 0x00B7, - "cedil": 0x00B8, - "sup1": 0x00B9, - "ordm": 0x00BA, - "raquo": 0x00BB, - "frac14": 0x00BC, - "frac12": 0x00BD, - "frac34": 0x00BE, - "iquest": 0x00BF, - "Agrave": 0x00C0, - "Aacute": 0x00C1, - "Acirc": 0x00C2, - "Atilde": 0x00C3, - "Auml": 0x00C4, - "Aring": 0x00C5, - "AElig": 0x00C6, - "Ccedil": 0x00C7, - "Egrave": 0x00C8, - "Eacute": 0x00C9, - "Ecirc": 0x00CA, - "Euml": 0x00CB, - "Igrave": 0x00CC, - "Iacute": 0x00CD, - "Icirc": 0x00CE, - "Iuml": 0x00CF, - "ETH": 0x00D0, - "Ntilde": 0x00D1, - "Ograve": 0x00D2, - "Oacute": 0x00D3, - "Ocirc": 0x00D4, - "Otilde": 0x00D5, - "Ouml": 0x00D6, - "times": 0x00D7, - "Oslash": 0x00D8, - "Ugrave": 0x00D9, - "Uacute": 0x00DA, - "Ucirc": 0x00DB, - "Uuml": 0x00DC, - "Yacute": 0x00DD, - "THORN": 0x00DE, - "szlig": 0x00DF, - "agrave": 0x00E0, - "aacute": 0x00E1, - "acirc": 0x00E2, - "atilde": 0x00E3, - "auml": 0x00E4, - "aring": 0x00E5, - "aelig": 0x00E6, - "ccedil": 0x00E7, - "egrave": 0x00E8, - "eacute": 0x00E9, - "ecirc": 0x00EA, - "euml": 0x00EB, - "igrave": 0x00EC, - "iacute": 0x00ED, - "icirc": 0x00EE, - "iuml": 0x00EF, - "eth": 0x00F0, - "ntilde": 0x00F1, - "ograve": 0x00F2, - "oacute": 0x00F3, - "ocirc": 0x00F4, - "otilde": 0x00F5, - "ouml": 0x00F6, - "divide": 0x00F7, - "oslash": 0x00F8, - "ugrave": 0x00F9, - "uacute": 0x00FA, - "ucirc": 0x00FB, - "uuml": 0x00FC, - "yacute": 0x00FD, - "thorn": 0x00FE, - "yuml": 0x00FF, - "OElig": 0x0152, - "oelig": 0x0153, - "Scaron": 0x0160, - "scaron": 0x0161, - "Yuml": 0x0178, - "fnof": 0x0192, - "circ": 0x02C6, - "tilde": 0x02DC, - "Alpha": 0x0391, - "Beta": 0x0392, - "Gamma": 0x0393, - "Delta": 0x0394, - "Epsilon": 0x0395, - "Zeta": 0x0396, - "Eta": 0x0397, - "Theta": 0x0398, - "Iota": 0x0399, - "Kappa": 0x039A, - "Lambda": 0x039B, - "Mu": 0x039C, - "Nu": 0x039D, - "Xi": 0x039E, - "Omicron": 0x039F, - "Pi": 0x03A0, - "Rho": 0x03A1, - "Sigma": 0x03A3, - "Tau": 0x03A4, - "Upsilon": 0x03A5, - "Phi": 0x03A6, - "Chi": 0x03A7, - "Psi": 0x03A8, - "Omega": 0x03A9, - "alpha": 0x03B1, - "beta": 0x03B2, - "gamma": 0x03B3, - "delta": 0x03B4, - "epsilon": 0x03B5, - "zeta": 0x03B6, - "eta": 0x03B7, - "theta": 0x03B8, - "iota": 0x03B9, - "kappa": 0x03BA, - "lambda": 0x03BB, - "mu": 0x03BC, - "nu": 0x03BD, - "xi": 0x03BE, - "omicron": 0x03BF, - "pi": 0x03C0, - "rho": 0x03C1, - "sigmaf": 0x03C2, - "sigma": 0x03C3, - "tau": 0x03C4, - "upsilon": 0x03C5, - "phi": 0x03C6, - "chi": 0x03C7, - "psi": 0x03C8, - "omega": 0x03C9, - "thetasym": 0x03D1, - "upsih": 0x03D2, - "piv": 0x03D6, - "ensp": 0x2002, - "emsp": 0x2003, - "thinsp": 0x2009, - "zwnj": 0x200C, - "zwj": 0x200D, - "lrm": 0x200E, - "rlm": 0x200F, - "ndash": 0x2013, - "mdash": 0x2014, - "lsquo": 0x2018, - "rsquo": 0x2019, - "sbquo": 0x201A, - "ldquo": 0x201C, - "rdquo": 0x201D, - "bdquo": 0x201E, - "dagger": 0x2020, - "Dagger": 0x2021, - "bull": 0x2022, - "hellip": 0x2026, - "permil": 0x2030, - "prime": 0x2032, - "Prime": 0x2033, - "lsaquo": 0x2039, - "rsaquo": 0x203A, - "oline": 0x203E, - "frasl": 0x2044, - "euro": 0x20AC, - "image": 0x2111, - "weierp": 0x2118, - "real": 0x211C, - "trade": 0x2122, - "alefsym": 0x2135, - "larr": 0x2190, - "uarr": 0x2191, - "rarr": 0x2192, - "darr": 0x2193, - "harr": 0x2194, - "crarr": 0x21B5, - "lArr": 0x21D0, - "uArr": 0x21D1, - "rArr": 0x21D2, - "dArr": 0x21D3, - "hArr": 0x21D4, - "forall": 0x2200, - "part": 0x2202, - "exist": 0x2203, - "empty": 0x2205, - "nabla": 0x2207, - "isin": 0x2208, - "notin": 0x2209, - "ni": 0x220B, - "prod": 0x220F, - "sum": 0x2211, - "minus": 0x2212, - "lowast": 0x2217, - "radic": 0x221A, - "prop": 0x221D, - "infin": 0x221E, - "ang": 0x2220, - "and": 0x2227, - "or": 0x2228, - "cap": 0x2229, - "cup": 0x222A, - "int": 0x222B, - "there4": 0x2234, - "sim": 0x223C, - "cong": 0x2245, - "asymp": 0x2248, - "ne": 0x2260, - "equiv": 0x2261, - "le": 0x2264, - "ge": 0x2265, - "sub": 0x2282, - "sup": 0x2283, - "nsub": 0x2284, - "sube": 0x2286, - "supe": 0x2287, - "oplus": 0x2295, - "otimes": 0x2297, - "perp": 0x22A5, - "sdot": 0x22C5, - "lceil": 0x2308, - "rceil": 0x2309, - "lfloor": 0x230A, - "rfloor": 0x230B, - "lang": 0x2329, - "rang": 0x232A, - "loz": 0x25CA, - "spades": 0x2660, - "clubs": 0x2663, - "hearts": 0x2665, - "diams": 0x2666 - }; - // Flags enum to track count of temp variables and a few dedicated names const enum TempFlags { Auto = 0x00000000, // No preferred name @@ -287,56 +13,11 @@ namespace ts { _i = 0x10000000, // Use/preference flag for '_i' } - const enum CopyDirection { - ToOriginal, - ToOutParameter - } - - /** - * If loop contains block scoped binding captured in some function then loop body is converted to a function. - * Lexical bindings declared in loop initializer will be passed into the loop body function as parameters, - * however if this binding is modified inside the body - this new value should be propagated back to the original binding. - * This is done by declaring new variable (out parameter holder) outside of the loop for every binding that is reassigned inside the body. - * On every iteration this variable is initialized with value of corresponding binding. - * At every point where control flow leaves the loop either explicitly (break/continue) or implicitly (at the end of loop body) - * we copy the value inside the loop to the out parameter holder. - * - * for (let x;;) { - * let a = 1; - * let b = () => a; - * x++ - * if (...) break; - * ... - * } - * - * will be converted to - * - * var out_x; - * var loop = function(x) { - * var a = 1; - * var b = function() { return a; } - * x++; - * if (...) return out_x = x, "break"; - * ... - * out_x = x; - * } - * for (var x;;) { - * out_x = x; - * var state = loop(x); - * x = out_x; - * if (state === "break") break; - * } - * - * NOTE: values to out parameters are not copies if loop is abrupted with 'return' - in this case this will end the entire enclosing function - * so nobody can observe this new value. - */ - interface LoopOutParameter { - originalName: Identifier; - outParamName: string; - } - // targetSourceFile is when users only want one file in entire project to be emitted. This is used in compileOnSave feature export function emitFiles(resolver: EmitResolver, host: EmitHost, targetSourceFile: SourceFile): EmitResult { + const delimiters = createDelimiterMap(); + const brackets = createBracketsMap(); + // emit output for the __extends helper function const extendsHelper = ` var __extends = (this && this.__extends) || function (d, b) { @@ -345,6 +26,9 @@ var __extends = (this && this.__extends) || function (d, b) { d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); };`; + // Emit output for the __assign helper function. + // This is typically used for JSX spread attributes, + // and can be used for object literal spread properties. const assignHelper = ` var __assign = (this && this.__assign) || Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { @@ -376,6 +60,7 @@ var __param = (this && this.__param) || function (paramIndex, decorator) { return function (target, key) { decorator(target, key, paramIndex); } };`; + // emit output for the __awaiter helper function const awaiterHelper = ` var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { return new (P || (P = Promise))(function (resolve, reject) { @@ -386,17 +71,111 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge }); };`; + // emit output for the __export helper function + const exportStarHelper = ` +function __export(m) { + for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p]; +}`; + + // emit output for the UMD helper function. + const umdHelper = ` +(function (dependencies, factory) { + if (typeof module === 'object' && typeof module.exports === 'object') { + var v = factory(require, exports); if (v !== undefined) module.exports = v; + } + else if (typeof define === 'function' && define.amd) { + define(dependencies, factory); + } +})`; + + const superHelper = ` +const _super = name => super[name];`; + + const advancedSuperHelper = ` +const _super = (function (geti, seti) { + const cache = Object.create(null); + return name => cache[name] || (cache[name] = { get value() { return geti(name); }, set value(v) { seti(name, v); } }); +})(name => super[name], (name, value) => super[name] = value);`; + const compilerOptions = host.getCompilerOptions(); const languageVersion = getEmitScriptTarget(compilerOptions); - const modulekind = getEmitModuleKind(compilerOptions); + const moduleKind = getEmitModuleKind(compilerOptions); const sourceMapDataList: SourceMapData[] = compilerOptions.sourceMap || compilerOptions.inlineSourceMap ? [] : undefined; const emittedFilesList: string[] = compilerOptions.listEmittedFiles ? [] : undefined; const emitterDiagnostics = createDiagnosticCollection(); - let emitSkipped = false; const newLine = host.getNewLine(); + const transformers = getTransformers(compilerOptions); + const writer = createTextWriter(newLine); + const { + write, + writeLine, + increaseIndent, + decreaseIndent + } = writer; - const emitJavaScript = createFileEmitter(); - forEachExpectedEmitFile(host, emitFile, targetSourceFile); + const sourceMap = createSourceMapWriter(host, writer); + const { + emitStart, + emitEnd, + emitTokenStart, + emitTokenEnd + } = sourceMap; + + const comments = createCommentWriter(host, writer, sourceMap); + const { + emitNodeWithComments, + emitBodyWithDetachedComments, + emitTrailingCommentsOfPosition + } = comments; + + let nodeIdToGeneratedName: string[]; + let autoGeneratedIdToGeneratedName: string[]; + let generatedNameSet: Map; + let tempFlags: TempFlags; + let currentSourceFile: SourceFile; + let currentText: string; + let currentFileIdentifiers: Map; + let extendsEmitted: boolean; + let assignEmitted: boolean; + let decorateEmitted: boolean; + let paramEmitted: boolean; + let awaiterEmitted: boolean; + let isOwnFileEmit: boolean; + let emitSkipped = false; + + performance.emit("beforeTransform"); + const transformStart = performance.mark(); + + // Transform the source files + const transformed = transformFiles( + resolver, + host, + getSourceFilesToEmit(host, targetSourceFile), + transformers); + + performance.measure("transformTime", transformStart); + performance.emit("afterTransform"); + + // Extract helpers from the result + const { + getTokenSourceMapRange, + isSubstitutionEnabled, + isEmitNotificationEnabled, + onSubstituteNode, + onEmitNode + } = transformed; + + performance.emit("beforePrint"); + const printStart = performance.mark(); + + // Emit each output file + forEachTransformedEmitFile(host, transformed.getSourceFiles(), emitFile); + + // Clean up after transformation + transformed.dispose(); + + performance.measure("printTime", printStart); + performance.emit("afterPrint"); return { emitSkipped, @@ -405,6 +184,2459 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge sourceMaps: sourceMapDataList }; + function emitFile(jsFilePath: string, sourceMapFilePath: string, declarationFilePath: string, sourceFiles: SourceFile[], isBundledEmit: boolean) { + // Make sure not to write js file and source map file if any of them cannot be written + if (!host.isEmitBlocked(jsFilePath) && !compilerOptions.noEmit) { + printFile(jsFilePath, sourceMapFilePath, sourceFiles, isBundledEmit); + } + else { + emitSkipped = true; + } + + if (declarationFilePath) { + emitSkipped = writeDeclarationFile(declarationFilePath, getOriginalSourceFiles(sourceFiles), isBundledEmit, host, resolver, emitterDiagnostics) || emitSkipped; + } + + if (!emitSkipped && emittedFilesList) { + emittedFilesList.push(jsFilePath); + if (sourceMapFilePath) { + emittedFilesList.push(sourceMapFilePath); + } + if (declarationFilePath) { + emittedFilesList.push(declarationFilePath); + } + } + } + + function printFile(jsFilePath: string, sourceMapFilePath: string, sourceFiles: SourceFile[], isBundledEmit: boolean) { + sourceMap.initialize(jsFilePath, sourceMapFilePath, sourceFiles, isBundledEmit); + nodeIdToGeneratedName = []; + autoGeneratedIdToGeneratedName = []; + generatedNameSet = {}; + isOwnFileEmit = !isBundledEmit; + + // Emit helpers from all the files + if (isBundledEmit && moduleKind) { + forEach(sourceFiles, emitEmitHelpers); + } + + // Print each transformed source file. + forEach(sourceFiles, printSourceFile); + + writeLine(); + + const sourceMappingURL = sourceMap.getSourceMappingURL(); + if (sourceMappingURL) { + write(`//# sourceMappingURL=${sourceMappingURL}`); + } + + // Write the source map + if (compilerOptions.sourceMap && !compilerOptions.inlineSourceMap) { + writeFile(host, emitterDiagnostics, sourceMapFilePath, sourceMap.getText(), /*writeByteOrderMark*/ false); + } + + // Record source map data for the test harness. + if (sourceMapDataList) { + sourceMapDataList.push(sourceMap.getSourceMapData()); + } + + // Write the output file + writeFile(host, emitterDiagnostics, jsFilePath, writer.getText(), compilerOptions.emitBOM); + + // Reset state + sourceMap.reset(); + comments.reset(); + writer.reset(); + + tempFlags = TempFlags.Auto; + currentSourceFile = undefined; + currentText = undefined; + extendsEmitted = false; + assignEmitted = false; + decorateEmitted = false; + paramEmitted = false; + awaiterEmitted = false; + isOwnFileEmit = false; + } + + function printSourceFile(node: SourceFile) { + currentSourceFile = node; + currentText = node.text; + currentFileIdentifiers = node.identifiers; + sourceMap.setSourceFile(node); + comments.setSourceFile(node); + emitNodeWithNotification(node, emitWorker); + } + + /** + * Emits a node. + */ + function emit(node: Node) { + emitNodeWithNotification(node, emitWithComments); + } + + /** + * Emits a node with specialized emit flags. + */ + // TODO(rbuckton): This should be removed once source maps are aligned with the old + // emitter and new baselines are taken. This exists solely to + // align with the old emitter. + function emitSpecialized(node: Node, flags: NodeEmitFlags) { + if (node) { + const flagsToAdd = flags & ~node.emitFlags; + if (flagsToAdd) { + node.emitFlags |= flagsToAdd; + emit(node); + node.emitFlags &= ~flagsToAdd; + return; + } + + emit(node); + } + } + + /** + * Emits a node with comments. + * + * NOTE: Do not call this method directly. It is part of the emit pipeline + * and should only be called indirectly from emit. + */ + function emitWithComments(node: Node) { + emitNodeWithComments(node, emitWithSourceMap); + } + + /** + * Emits a node with source maps. + * + * NOTE: Do not call this method directly. It is part of the emit pipeline + * and should only be called indirectly from emitWithComments. + */ + function emitWithSourceMap(node: Node) { + emitNodeWithSourceMap(node, emitWorker); + } + + /** + * Emits an expression node. + */ + function emitExpression(node: Expression) { + emitNodeWithNotification(node, emitExpressionWithComments); + } + + /** + * Emits an expression with comments. + * + * NOTE: Do not call this method directly. It is part of the emitExpression pipeline + * and should only be called indirectly from emitExpression. + */ + function emitExpressionWithComments(node: Expression) { + emitNodeWithComments(node, emitExpressionWithSourceMap); + } + + /** + * Emits an expression with source maps. + * + * NOTE: Do not call this method directly. It is part of the emitExpression pipeline + * and should only be called indirectly from emitExpressionWithComments. + */ + function emitExpressionWithSourceMap(node: Expression) { + emitNodeWithSourceMap(node, emitExpressionWorker); + } + + /** + * Emits a node with emit notification if available. + */ + function emitNodeWithNotification(node: Node, emitCallback: (node: Node) => void) { + if (node) { + if (isEmitNotificationEnabled(node)) { + onEmitNode(node, emitCallback); + } + else { + emitCallback(node); + } + } + } + + function emitNodeWithSourceMap(node: Node, emitCallback: (node: Node) => void) { + if (node) { + emitStart(/*range*/ node, /*contextNode*/ node, shouldSkipLeadingSourceMapForNode, shouldSkipSourceMapForChildren, getSourceMapRange); + emitCallback(node); + emitEnd(/*range*/ node, /*contextNode*/ node, shouldSkipTrailingSourceMapForNode, shouldSkipSourceMapForChildren, getSourceMapRange); + } + } + + function getSourceMapRange(node: Node) { + return node.sourceMapRange || node; + } + + /** + * Determines whether to skip leading comment emit for a node. + * + * We do not emit comments for NotEmittedStatement nodes or any node that has + * NodeEmitFlags.NoLeadingComments. + * + * @param node A Node. + */ + function shouldSkipLeadingCommentsForNode(node: Node) { + return isNotEmittedStatement(node) + || (node.emitFlags & NodeEmitFlags.NoLeadingComments) !== 0; + } + + /** + * Determines whether to skip source map emit for the start position of a node. + * + * We do not emit source maps for NotEmittedStatement nodes or any node that + * has NodeEmitFlags.NoLeadingSourceMap. + * + * @param node A Node. + */ + function shouldSkipLeadingSourceMapForNode(node: Node) { + return isNotEmittedStatement(node) + || (node.emitFlags & NodeEmitFlags.NoLeadingSourceMap) !== 0; + } + + + /** + * Determines whether to skip source map emit for the end position of a node. + * + * We do not emit source maps for NotEmittedStatement nodes or any node that + * has NodeEmitFlags.NoTrailingSourceMap. + * + * @param node A Node. + */ + function shouldSkipTrailingSourceMapForNode(node: Node) { + return isNotEmittedStatement(node) + || (node.emitFlags & NodeEmitFlags.NoTrailingSourceMap) !== 0; + } + + /** + * Determines whether to skip source map emit for a node and its children. + * + * We do not emit source maps for a node that has NodeEmitFlags.NoNestedSourceMaps. + */ + function shouldSkipSourceMapForChildren(node: Node) { + return (node.emitFlags & NodeEmitFlags.NoNestedSourceMaps) !== 0; + } + + function emitWorker(node: Node): void { + if (tryEmitSubstitute(node, emitWorker, /*isExpression*/ false)) { + return; + } + + const kind = node.kind; + switch (kind) { + // Pseudo-literals + case SyntaxKind.TemplateHead: + case SyntaxKind.TemplateMiddle: + case SyntaxKind.TemplateTail: + return emitLiteral(node); + + // Identifiers + case SyntaxKind.Identifier: + return emitIdentifier(node); + + // Reserved words + case SyntaxKind.ConstKeyword: + case SyntaxKind.DefaultKeyword: + case SyntaxKind.ExportKeyword: + case SyntaxKind.VoidKeyword: + + // Strict mode reserved words + case SyntaxKind.PrivateKeyword: + case SyntaxKind.ProtectedKeyword: + case SyntaxKind.PublicKeyword: + case SyntaxKind.StaticKeyword: + + // Contextual keywords + case SyntaxKind.AbstractKeyword: + case SyntaxKind.AnyKeyword: + case SyntaxKind.AsyncKeyword: + case SyntaxKind.BooleanKeyword: + case SyntaxKind.DeclareKeyword: + case SyntaxKind.NumberKeyword: + case SyntaxKind.ReadonlyKeyword: + case SyntaxKind.StringKeyword: + case SyntaxKind.SymbolKeyword: + case SyntaxKind.GlobalKeyword: + return writeTokenNode(node); + + // Parse tree nodes + + // Names + case SyntaxKind.QualifiedName: + return emitQualifiedName(node); + case SyntaxKind.ComputedPropertyName: + return emitComputedPropertyName(node); + + // Signature elements + case SyntaxKind.TypeParameter: + return emitTypeParameter(node); + case SyntaxKind.Parameter: + return emitParameter(node); + case SyntaxKind.Decorator: + return emitDecorator(node); + + // Type members + case SyntaxKind.PropertySignature: + return emitPropertySignature(node); + case SyntaxKind.PropertyDeclaration: + return emitPropertyDeclaration(node); + case SyntaxKind.MethodSignature: + return emitMethodSignature(node); + case SyntaxKind.MethodDeclaration: + return emitMethodDeclaration(node); + case SyntaxKind.Constructor: + return emitConstructor(node); + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + return emitAccessorDeclaration(node); + case SyntaxKind.CallSignature: + return emitCallSignature(node); + case SyntaxKind.ConstructSignature: + return emitConstructSignature(node); + case SyntaxKind.IndexSignature: + return emitIndexSignature(node); + + // Types + case SyntaxKind.TypePredicate: + return emitTypePredicate(node); + case SyntaxKind.TypeReference: + return emitTypeReference(node); + case SyntaxKind.FunctionType: + return emitFunctionType(node); + case SyntaxKind.ConstructorType: + return emitConstructorType(node); + case SyntaxKind.TypeQuery: + return emitTypeQuery(node); + case SyntaxKind.TypeLiteral: + return emitTypeLiteral(node); + case SyntaxKind.ArrayType: + return emitArrayType(node); + case SyntaxKind.TupleType: + return emitTupleType(node); + case SyntaxKind.UnionType: + return emitUnionType(node); + case SyntaxKind.IntersectionType: + return emitIntersectionType(node); + case SyntaxKind.ParenthesizedType: + return emitParenthesizedType(node); + case SyntaxKind.ExpressionWithTypeArguments: + return emitExpressionWithTypeArguments(node); + case SyntaxKind.ThisType: + return emitThisType(node); + case SyntaxKind.StringLiteralType: + return emitLiteral(node); + + // Binding patterns + case SyntaxKind.ObjectBindingPattern: + return emitObjectBindingPattern(node); + case SyntaxKind.ArrayBindingPattern: + return emitArrayBindingPattern(node); + case SyntaxKind.BindingElement: + return emitBindingElement(node); + + // Misc + case SyntaxKind.TemplateSpan: + return emitTemplateSpan(node); + case SyntaxKind.SemicolonClassElement: + return emitSemicolonClassElement(node); + + // Statements + case SyntaxKind.Block: + return emitBlock(node); + case SyntaxKind.VariableStatement: + return emitVariableStatement(node); + case SyntaxKind.EmptyStatement: + return emitEmptyStatement(node); + case SyntaxKind.ExpressionStatement: + return emitExpressionStatement(node); + case SyntaxKind.IfStatement: + return emitIfStatement(node); + case SyntaxKind.DoStatement: + return emitDoStatement(node); + case SyntaxKind.WhileStatement: + return emitWhileStatement(node); + case SyntaxKind.ForStatement: + return emitForStatement(node); + case SyntaxKind.ForInStatement: + return emitForInStatement(node); + case SyntaxKind.ForOfStatement: + return emitForOfStatement(node); + case SyntaxKind.ContinueStatement: + return emitContinueStatement(node); + case SyntaxKind.BreakStatement: + return emitBreakStatement(node); + case SyntaxKind.ReturnStatement: + return emitReturnStatement(node); + case SyntaxKind.WithStatement: + return emitWithStatement(node); + case SyntaxKind.SwitchStatement: + return emitSwitchStatement(node); + case SyntaxKind.LabeledStatement: + return emitLabeledStatement(node); + case SyntaxKind.ThrowStatement: + return emitThrowStatement(node); + case SyntaxKind.TryStatement: + return emitTryStatement(node); + case SyntaxKind.DebuggerStatement: + return emitDebuggerStatement(node); + + // Declarations + case SyntaxKind.VariableDeclaration: + return emitVariableDeclaration(node); + case SyntaxKind.VariableDeclarationList: + return emitVariableDeclarationList(node); + case SyntaxKind.FunctionDeclaration: + return emitFunctionDeclaration(node); + case SyntaxKind.ClassDeclaration: + return emitClassDeclaration(node); + case SyntaxKind.InterfaceDeclaration: + return emitInterfaceDeclaration(node); + case SyntaxKind.TypeAliasDeclaration: + return emitTypeAliasDeclaration(node); + case SyntaxKind.EnumDeclaration: + return emitEnumDeclaration(node); + case SyntaxKind.ModuleDeclaration: + return emitModuleDeclaration(node); + case SyntaxKind.ModuleBlock: + return emitModuleBlock(node); + case SyntaxKind.CaseBlock: + return emitCaseBlock(node); + case SyntaxKind.ImportEqualsDeclaration: + return emitImportEqualsDeclaration(node); + case SyntaxKind.ImportDeclaration: + return emitImportDeclaration(node); + case SyntaxKind.ImportClause: + return emitImportClause(node); + case SyntaxKind.NamespaceImport: + return emitNamespaceImport(node); + case SyntaxKind.NamedImports: + return emitNamedImports(node); + case SyntaxKind.ImportSpecifier: + return emitImportSpecifier(node); + case SyntaxKind.ExportAssignment: + return emitExportAssignment(node); + case SyntaxKind.ExportDeclaration: + return emitExportDeclaration(node); + case SyntaxKind.NamedExports: + return emitNamedExports(node); + case SyntaxKind.ExportSpecifier: + return emitExportSpecifier(node); + case SyntaxKind.MissingDeclaration: + return; + + // Module references + case SyntaxKind.ExternalModuleReference: + return emitExternalModuleReference(node); + + // JSX (non-expression) + case SyntaxKind.JsxText: + return emitJsxText(node); + case SyntaxKind.JsxOpeningElement: + return emitJsxOpeningElement(node); + case SyntaxKind.JsxClosingElement: + return emitJsxClosingElement(node); + case SyntaxKind.JsxAttribute: + return emitJsxAttribute(node); + case SyntaxKind.JsxSpreadAttribute: + return emitJsxSpreadAttribute(node); + case SyntaxKind.JsxExpression: + return emitJsxExpression(node); + + // Clauses + case SyntaxKind.CaseClause: + return emitCaseClause(node); + case SyntaxKind.DefaultClause: + return emitDefaultClause(node); + case SyntaxKind.HeritageClause: + return emitHeritageClause(node); + case SyntaxKind.CatchClause: + return emitCatchClause(node); + + // Property assignments + case SyntaxKind.PropertyAssignment: + return emitPropertyAssignment(node); + case SyntaxKind.ShorthandPropertyAssignment: + return emitShorthandPropertyAssignment(node); + + // Enum + case SyntaxKind.EnumMember: + return emitEnumMember(node); + + // Top-level nodes + case SyntaxKind.SourceFile: + return emitSourceFile(node); + + // JSDoc nodes (ignored) + + // Transformation nodes (ignored) + } + + if (isExpression(node)) { + return emitExpressionWorker(node); + } + } + + function emitExpressionWorker(node: Node) { + if (tryEmitSubstitute(node, emitExpressionWorker, /*isExpression*/ true)) { + return; + } + + const kind = node.kind; + switch (kind) { + // Literals + case SyntaxKind.NumericLiteral: + case SyntaxKind.StringLiteral: + case SyntaxKind.RegularExpressionLiteral: + case SyntaxKind.NoSubstitutionTemplateLiteral: + return emitLiteral(node); + + // Identifiers + case SyntaxKind.Identifier: + return emitIdentifier(node); + + // Reserved words + case SyntaxKind.FalseKeyword: + case SyntaxKind.NullKeyword: + case SyntaxKind.SuperKeyword: + case SyntaxKind.TrueKeyword: + case SyntaxKind.ThisKeyword: + return writeTokenNode(node); + + // Expressions + case SyntaxKind.ArrayLiteralExpression: + return emitArrayLiteralExpression(node); + case SyntaxKind.ObjectLiteralExpression: + return emitObjectLiteralExpression(node); + case SyntaxKind.PropertyAccessExpression: + return emitPropertyAccessExpression(node); + case SyntaxKind.ElementAccessExpression: + return emitElementAccessExpression(node); + case SyntaxKind.CallExpression: + return emitCallExpression(node); + case SyntaxKind.NewExpression: + return emitNewExpression(node); + case SyntaxKind.TaggedTemplateExpression: + return emitTaggedTemplateExpression(node); + case SyntaxKind.TypeAssertionExpression: + return emitTypeAssertionExpression(node); + case SyntaxKind.ParenthesizedExpression: + return emitParenthesizedExpression(node); + case SyntaxKind.FunctionExpression: + return emitFunctionExpression(node); + case SyntaxKind.ArrowFunction: + return emitArrowFunction(node); + case SyntaxKind.DeleteExpression: + return emitDeleteExpression(node); + case SyntaxKind.TypeOfExpression: + return emitTypeOfExpression(node); + case SyntaxKind.VoidExpression: + return emitVoidExpression(node); + case SyntaxKind.AwaitExpression: + return emitAwaitExpression(node); + case SyntaxKind.PrefixUnaryExpression: + return emitPrefixUnaryExpression(node); + case SyntaxKind.PostfixUnaryExpression: + return emitPostfixUnaryExpression(node); + case SyntaxKind.BinaryExpression: + return emitBinaryExpression(node); + case SyntaxKind.ConditionalExpression: + return emitConditionalExpression(node); + case SyntaxKind.TemplateExpression: + return emitTemplateExpression(node); + case SyntaxKind.YieldExpression: + return emitYieldExpression(node); + case SyntaxKind.SpreadElementExpression: + return emitSpreadElementExpression(node); + case SyntaxKind.ClassExpression: + return emitClassExpression(node); + case SyntaxKind.OmittedExpression: + return; + case SyntaxKind.AsExpression: + return emitAsExpression(node); + case SyntaxKind.NonNullExpression: + return emitNonNullExpression(node); + + // JSX + case SyntaxKind.JsxElement: + return emitJsxElement(node); + case SyntaxKind.JsxSelfClosingElement: + return emitJsxSelfClosingElement(node); + + // Transformation nodes + case SyntaxKind.PartiallyEmittedExpression: + return emitPartiallyEmittedExpression(node); + } + } + + // + // Literals/Pseudo-literals + // + + // SyntaxKind.NumericLiteral + // SyntaxKind.StringLiteral + // SyntaxKind.RegularExpressionLiteral + // SyntaxKind.NoSubstitutionTemplateLiteral + // SyntaxKind.TemplateHead + // SyntaxKind.TemplateMiddle + // SyntaxKind.TemplateTail + function emitLiteral(node: LiteralLikeNode) { + const text = getLiteralTextOfNode(node); + if ((compilerOptions.sourceMap || compilerOptions.inlineSourceMap) + && (node.kind === SyntaxKind.StringLiteral || isTemplateLiteralKind(node.kind))) { + writer.writeLiteral(text); + } + else { + write(text); + } + } + + // + // Identifiers + // + + function emitIdentifier(node: Identifier) { + if (node.emitFlags & NodeEmitFlags.UMDDefine) { + writeLines(umdHelper); + } + else { + write(getTextOfNode(node, /*includeTrivia*/ false)); + } + } + + // + // Names + // + + function emitQualifiedName(node: QualifiedName) { + emitEntityName(node.left); + write("."); + emit(node.right); + } + + function emitEntityName(node: EntityName) { + if (node.kind === SyntaxKind.Identifier) { + emitExpression(node); + } + else { + emit(node); + } + } + + function emitComputedPropertyName(node: ComputedPropertyName) { + write("["); + emitExpression(node.expression); + write("]"); + } + + // + // Signature elements + // + + function emitTypeParameter(node: TypeParameterDeclaration) { + emit(node.name); + emitWithPrefix(" extends ", node.constraint); + } + + function emitParameter(node: ParameterDeclaration) { + emitDecorators(node, node.decorators); + emitModifiers(node, node.modifiers); + writeIfPresent(node.dotDotDotToken, "..."); + emit(node.name); + writeIfPresent(node.questionToken, "?"); + emitExpressionWithPrefix(" = ", node.initializer); + emitWithPrefix(": ", node.type); + } + + function emitDecorator(decorator: Decorator) { + write("@"); + emitExpression(decorator.expression); + } + + // + // Type members + // + + function emitPropertySignature(node: PropertySignature) { + emitDecorators(node, node.decorators); + emitModifiers(node, node.modifiers); + emit(node.name); + writeIfPresent(node.questionToken, "?"); + emitWithPrefix(": ", node.type); + write(";"); + } + + function emitPropertyDeclaration(node: PropertyDeclaration) { + emitDecorators(node, node.decorators); + emitModifiers(node, node.modifiers); + emit(node.name); + emitWithPrefix(": ", node.type); + emitExpressionWithPrefix(" = ", node.initializer); + write(";"); + } + + function emitMethodSignature(node: MethodSignature) { + emitDecorators(node, node.decorators); + emitModifiers(node, node.modifiers); + emit(node.name); + writeIfPresent(node.questionToken, "?"); + emitTypeParameters(node, node.typeParameters); + emitParameters(node, node.parameters); + emitWithPrefix(": ", node.type); + write(";"); + } + + function emitMethodDeclaration(node: MethodDeclaration) { + emitDecorators(node, node.decorators); + emitModifiers(node, node.modifiers); + writeIfPresent(node.asteriskToken, "*"); + emit(node.name); + emitSignatureAndBody(node, emitSignatureHead); + } + + function emitConstructor(node: ConstructorDeclaration) { + emitModifiers(node, node.modifiers); + write("constructor"); + emitSignatureAndBody(node, emitSignatureHead); + } + + function emitAccessorDeclaration(node: AccessorDeclaration) { + emitDecorators(node, node.decorators); + emitModifiers(node, node.modifiers); + write(node.kind === SyntaxKind.GetAccessor ? "get " : "set "); + emit(node.name); + emitSignatureAndBody(node, emitSignatureHead); + } + + function emitCallSignature(node: CallSignatureDeclaration) { + emitDecorators(node, node.decorators); + emitModifiers(node, node.modifiers); + emitTypeParameters(node, node.typeParameters); + emitParameters(node, node.parameters); + emitWithPrefix(": ", node.type); + write(";"); + } + + function emitConstructSignature(node: ConstructSignatureDeclaration) { + emitDecorators(node, node.decorators); + emitModifiers(node, node.modifiers); + write("new "); + emitTypeParameters(node, node.typeParameters); + emitParameters(node, node.parameters); + emitWithPrefix(": ", node.type); + write(";"); + } + + function emitIndexSignature(node: IndexSignatureDeclaration) { + emitDecorators(node, node.decorators); + emitModifiers(node, node.modifiers); + emitParametersForIndexSignature(node, node.parameters); + emitWithPrefix(": ", node.type); + write(";"); + } + + function emitSemicolonClassElement(node: SemicolonClassElement) { + write(";"); + } + + // + // Types + // + + function emitTypePredicate(node: TypePredicateNode) { + emit(node.parameterName); + write(" is "); + emit(node.type); + } + + function emitTypeReference(node: TypeReferenceNode) { + emit(node.typeName); + emitTypeArguments(node, node.typeArguments); + } + + function emitFunctionType(node: FunctionTypeNode) { + emitTypeParameters(node, node.typeParameters); + emitParametersForArrow(node, node.parameters); + write(" => "); + emit(node.type); + } + + function emitConstructorType(node: ConstructorTypeNode) { + write("new "); + emitTypeParameters(node, node.typeParameters); + emitParametersForArrow(node, node.parameters); + write(" => "); + emit(node.type); + } + + function emitTypeQuery(node: TypeQueryNode) { + write("typeof "); + emit(node.exprName); + } + + function emitTypeLiteral(node: TypeLiteralNode) { + write("{"); + emitList(node, node.members, ListFormat.TypeLiteralMembers); + write("}"); + } + + function emitArrayType(node: ArrayTypeNode) { + emit(node.elementType); + write("[]"); + } + + function emitTupleType(node: TupleTypeNode) { + write("["); + emitList(node, node.elementTypes, ListFormat.TupleTypeElements); + write("]"); + } + + function emitUnionType(node: UnionTypeNode) { + emitList(node, node.types, ListFormat.UnionTypeConstituents); + } + + function emitIntersectionType(node: IntersectionTypeNode) { + emitList(node, node.types, ListFormat.IntersectionTypeConstituents); + } + + function emitParenthesizedType(node: ParenthesizedTypeNode) { + write("("); + emit(node.type); + write(")"); + } + + function emitThisType(node: ThisTypeNode) { + write("this"); + } + + // + // Binding patterns + // + + function emitObjectBindingPattern(node: ObjectBindingPattern) { + const elements = node.elements; + if (elements.length === 0) { + write("{}"); + } + else { + write("{"); + emitList(node, elements, ListFormat.ObjectBindingPatternElements); + write("}"); + } + } + + function emitArrayBindingPattern(node: ArrayBindingPattern) { + const elements = node.elements; + if (elements.length === 0) { + write("[]"); + } + else { + write("["); + emitList(node, node.elements, ListFormat.ArrayBindingPatternElements); + write("]"); + } + } + + function emitBindingElement(node: BindingElement) { + emitWithSuffix(node.propertyName, ": "); + writeIfPresent(node.dotDotDotToken, "..."); + emit(node.name); + emitExpressionWithPrefix(" = ", node.initializer); + } + + // + // Expressions + // + + function emitArrayLiteralExpression(node: ArrayLiteralExpression) { + const elements = node.elements; + if (elements.length === 0) { + write("[]"); + } + else { + const preferNewLine = node.multiLine ? ListFormat.PreferNewLine : ListFormat.None; + emitExpressionList(node, elements, ListFormat.ArrayLiteralExpressionElements | preferNewLine); + } + } + + function emitObjectLiteralExpression(node: ObjectLiteralExpression) { + const properties = node.properties; + if (properties.length === 0) { + write("{}"); + } + else { + const indentedFlag = node.emitFlags & NodeEmitFlags.Indented; + if (indentedFlag) { + increaseIndent(); + } + + const preferNewLine = node.multiLine ? ListFormat.PreferNewLine : ListFormat.None; + const allowTrailingComma = languageVersion >= ScriptTarget.ES5 ? ListFormat.AllowTrailingComma : ListFormat.None; + emitList(node, properties, ListFormat.ObjectLiteralExpressionProperties | allowTrailingComma | preferNewLine); + + if (indentedFlag) { + decreaseIndent(); + } + } + } + + function emitPropertyAccessExpression(node: PropertyAccessExpression) { + if (tryEmitConstantValue(node)) { + return; + } + + const indentBeforeDot = needsIndentation(node, node.expression, node.dotToken); + const indentAfterDot = needsIndentation(node, node.dotToken, node.name); + const shouldEmitDotDot = !indentBeforeDot && needsDotDotForPropertyAccess(node.expression); + + emitExpression(node.expression); + increaseIndentIf(indentBeforeDot); + write(shouldEmitDotDot ? ".." : "."); + increaseIndentIf(indentAfterDot); + emit(node.name); + decreaseIndentIf(indentBeforeDot, indentAfterDot); + } + + // 1..toString is a valid property access, emit a dot after the literal + // Also emit a dot if expression is a integer const enum value - it will appear in generated code as numeric literal + function needsDotDotForPropertyAccess(expression: Expression) { + if (expression.kind === SyntaxKind.NumericLiteral) { + // check if numeric literal was originally written with a dot + const text = getLiteralTextOfNode(expression); + return text.indexOf(tokenToString(SyntaxKind.DotToken)) < 0; + } + else { + // check if constant enum value is integer + const constantValue = tryGetConstEnumValue(expression); + // isFinite handles cases when constantValue is undefined + return isFinite(constantValue) && Math.floor(constantValue) === constantValue; + } + } + + function emitElementAccessExpression(node: ElementAccessExpression) { + if (tryEmitConstantValue(node)) { + return; + } + + emitExpression(node.expression); + write("["); + emitExpression(node.argumentExpression); + write("]"); + } + + function emitCallExpression(node: CallExpression) { + emitExpression(node.expression); + emitExpressionList(node, node.arguments, ListFormat.CallExpressionArguments); + } + + function emitNewExpression(node: NewExpression) { + write("new "); + emitExpression(node.expression); + emitExpressionList(node, node.arguments, ListFormat.NewExpressionArguments); + } + + function emitTaggedTemplateExpression(node: TaggedTemplateExpression) { + emitExpression(node.tag); + write(" "); + emitExpression(node.template); + } + + function emitTypeAssertionExpression(node: TypeAssertion) { + if (node.type) { + write("<"); + emit(node.type); + write(">"); + } + + emitExpression(node.expression); + } + + function emitParenthesizedExpression(node: ParenthesizedExpression) { + write("("); + emitExpression(node.expression); + write(")"); + } + + function emitFunctionExpression(node: FunctionExpression) { + emitFunctionDeclarationOrExpression(node); + } + + function emitArrowFunction(node: ArrowFunction) { + emitDecorators(node, node.decorators); + emitModifiers(node, node.modifiers); + emitSignatureAndBody(node, emitArrowFunctionHead); + } + + function emitArrowFunctionHead(node: ArrowFunction) { + emitTypeParameters(node, node.typeParameters); + emitParametersForArrow(node, node.parameters); + emitWithPrefix(": ", node.type); + write(" =>"); + } + + function emitDeleteExpression(node: DeleteExpression) { + write("delete "); + emitExpression(node.expression); + } + + function emitTypeOfExpression(node: TypeOfExpression) { + write("typeof "); + emitExpression(node.expression); + } + + function emitVoidExpression(node: VoidExpression) { + write("void "); + emitExpression(node.expression); + } + + function emitAwaitExpression(node: AwaitExpression) { + write("await "); + emitExpression(node.expression); + } + + function emitPrefixUnaryExpression(node: PrefixUnaryExpression) { + writeTokenText(node.operator); + if (shouldEmitWhitespaceBeforeOperand(node)) { + write(" "); + } + emitExpression(node.operand); + } + + function shouldEmitWhitespaceBeforeOperand(node: PrefixUnaryExpression) { + // In some cases, we need to emit a space between the operator and the operand. One obvious case + // is when the operator is an identifier, like delete or typeof. We also need to do this for plus + // and minus expressions in certain cases. Specifically, consider the following two cases (parens + // are just for clarity of exposition, and not part of the source code): + // + // (+(+1)) + // (+(++1)) + // + // We need to emit a space in both cases. In the first case, the absence of a space will make + // the resulting expression a prefix increment operation. And in the second, it will make the resulting + // expression a prefix increment whose operand is a plus expression - (++(+x)) + // The same is true of minus of course. + const operand = node.operand; + return operand.kind === SyntaxKind.PrefixUnaryExpression + && ((node.operator === SyntaxKind.PlusToken && ((operand).operator === SyntaxKind.PlusToken || (operand).operator === SyntaxKind.PlusPlusToken)) + || (node.operator === SyntaxKind.MinusToken && ((operand).operator === SyntaxKind.MinusToken || (operand).operator === SyntaxKind.MinusMinusToken))); + } + + function emitPostfixUnaryExpression(node: PostfixUnaryExpression) { + emitExpression(node.operand); + writeTokenText(node.operator); + } + + function emitBinaryExpression(node: BinaryExpression) { + const isCommaOperator = node.operatorToken.kind !== SyntaxKind.CommaToken; + const indentBeforeOperator = needsIndentation(node, node.left, node.operatorToken); + const indentAfterOperator = needsIndentation(node, node.operatorToken, node.right); + + emitExpression(node.left); + increaseIndentIf(indentBeforeOperator, isCommaOperator ? " " : undefined); + writeTokenText(node.operatorToken.kind); + increaseIndentIf(indentAfterOperator, " "); + emitExpression(node.right); + decreaseIndentIf(indentBeforeOperator, indentAfterOperator); + } + + function emitConditionalExpression(node: ConditionalExpression) { + const indentBeforeQuestion = needsIndentation(node, node.condition, node.questionToken); + const indentAfterQuestion = needsIndentation(node, node.questionToken, node.whenTrue); + const indentBeforeColon = needsIndentation(node, node.whenTrue, node.colonToken); + const indentAfterColon = needsIndentation(node, node.colonToken, node.whenFalse); + + emitExpression(node.condition); + increaseIndentIf(indentBeforeQuestion, " "); + write("?"); + increaseIndentIf(indentAfterQuestion, " "); + emitExpression(node.whenTrue); + decreaseIndentIf(indentBeforeQuestion, indentAfterQuestion); + + increaseIndentIf(indentBeforeColon, " "); + write(":"); + increaseIndentIf(indentAfterColon, " "); + emitExpression(node.whenFalse); + decreaseIndentIf(indentBeforeColon, indentAfterColon); + } + + function emitTemplateExpression(node: TemplateExpression) { + emit(node.head); + emitList(node, node.templateSpans, ListFormat.TemplateExpressionSpans); + } + + function emitYieldExpression(node: YieldExpression) { + write(node.asteriskToken ? "yield*" : "yield"); + emitExpressionWithPrefix(" ", node.expression); + } + + function emitSpreadElementExpression(node: SpreadElementExpression) { + write("..."); + emitExpression(node.expression); + } + + function emitClassExpression(node: ClassExpression) { + emitClassDeclarationOrExpression(node); + } + + function emitExpressionWithTypeArguments(node: ExpressionWithTypeArguments) { + emitExpression(node.expression); + emitTypeArguments(node, node.typeArguments); + } + + function emitAsExpression(node: AsExpression) { + emitExpression(node.expression); + if (node.type) { + write(" as "); + emit(node.type); + } + } + + function emitNonNullExpression(node: NonNullExpression) { + emitExpression(node.expression); + write("!"); + } + + // + // Misc + // + + function emitTemplateSpan(node: TemplateSpan) { + emitExpression(node.expression); + emit(node.literal); + } + + // + // Statements + // + + function emitBlock(node: Block, format?: ListFormat) { + if (isSingleLineEmptyBlock(node)) { + writeToken(SyntaxKind.OpenBraceToken, node.pos, /*contextNode*/ node); + write(" "); + writeToken(SyntaxKind.CloseBraceToken, node.statements.end, /*contextNode*/ node); + } + else { + writeToken(SyntaxKind.OpenBraceToken, node.pos, /*contextNode*/ node); + emitBlockStatements(node); + writeToken(SyntaxKind.CloseBraceToken, node.statements.end, /*contextNode*/ node); + } + } + + function emitBlockStatements(node: Block) { + if (node.emitFlags & NodeEmitFlags.SingleLine) { + emitList(node, node.statements, ListFormat.SingleLineBlockStatements); + } + else { + emitList(node, node.statements, ListFormat.MultiLineBlockStatements); + } + } + + function emitVariableStatement(node: VariableStatement) { + emitModifiers(node, node.modifiers); + emit(node.declarationList); + write(";"); + } + + function emitEmptyStatement(node: EmptyStatement) { + write(";"); + } + + function emitExpressionStatement(node: ExpressionStatement) { + emitExpression(node.expression); + write(";"); + } + + function emitIfStatement(node: IfStatement) { + const openParenPos = writeToken(SyntaxKind.IfKeyword, node.pos, node); + write(" "); + writeToken(SyntaxKind.OpenParenToken, openParenPos, node); + emitExpression(node.expression); + writeToken(SyntaxKind.CloseParenToken, node.expression.end, node); + emitEmbeddedStatement(node.thenStatement); + if (node.elseStatement) { + writeLine(); + writeToken(SyntaxKind.ElseKeyword, node.thenStatement.end, node); + if (node.elseStatement.kind === SyntaxKind.IfStatement) { + write(" "); + emit(node.elseStatement); + } + else { + emitEmbeddedStatement(node.elseStatement); + } + } + } + + function emitDoStatement(node: DoStatement) { + write("do"); + emitEmbeddedStatement(node.statement); + if (isBlock(node.statement)) { + write(" "); + } + else { + writeLine(); + } + + write("while ("); + emitExpression(node.expression); + write(");"); + } + + function emitWhileStatement(node: WhileStatement) { + write("while ("); + emitExpression(node.expression); + write(")"); + emitEmbeddedStatement(node.statement); + } + + function emitForStatement(node: ForStatement) { + if (node.emitFlags & NodeEmitFlags.SourceMapAdjustRestParameterLoop) { + // TODO(rbuckton): This should be removed once source maps are aligned with the old + // emitter and new baselines are taken. This exists solely to + // align with the old emitter. + const openParenPos = writeToken(SyntaxKind.ForKeyword, node.pos); + write(" "); + writeToken(SyntaxKind.OpenParenToken, openParenPos); + const initializer = node.initializer; + initializer.emitFlags |= NodeEmitFlags.NoTrailingSourceMap; + emitForBinding(initializer); + write(";"); + emitEnd(initializer); + const condition = node.condition; + condition.emitFlags |= NodeEmitFlags.NoTrailingSourceMap; + write(" "); + emitExpression(condition); + write(";"); + emitEnd(condition); + write(" "); + emitExpression(node.incrementor); + write(")"); + emitEmbeddedStatement(node.statement); + return; + } + + const openParenPos = writeToken(SyntaxKind.ForKeyword, node.pos); + write(" "); + writeToken(SyntaxKind.OpenParenToken, openParenPos, /*contextNode*/ node); + emitForBinding(node.initializer); + write(";"); + emitExpressionWithPrefix(" ", node.condition); + write(";"); + emitExpressionWithPrefix(" ", node.incrementor); + write(")"); + emitEmbeddedStatement(node.statement); + } + + function emitForInStatement(node: ForInStatement) { + const openParenPos = writeToken(SyntaxKind.ForKeyword, node.pos); + write(" "); + writeToken(SyntaxKind.OpenParenToken, openParenPos); + emitForBinding(node.initializer); + write(" in "); + emitExpression(node.expression); + writeToken(SyntaxKind.CloseParenToken, node.expression.end); + emitEmbeddedStatement(node.statement); + } + + function emitForOfStatement(node: ForOfStatement) { + const openParenPos = writeToken(SyntaxKind.ForKeyword, node.pos); + write(" "); + writeToken(SyntaxKind.OpenParenToken, openParenPos); + emitForBinding(node.initializer); + write(" of "); + emitExpression(node.expression); + writeToken(SyntaxKind.CloseParenToken, node.expression.end); + emitEmbeddedStatement(node.statement); + } + + function emitForBinding(node: VariableDeclarationList | Expression) { + if (node !== undefined) { + if (node.kind === SyntaxKind.VariableDeclarationList) { + emit(node); + } + else { + emitExpression(node); + } + } + } + + function emitContinueStatement(node: ContinueStatement) { + writeToken(SyntaxKind.ContinueKeyword, node.pos); + emitWithPrefix(" ", node.label); + write(";"); + } + + function emitBreakStatement(node: BreakStatement) { + writeToken(SyntaxKind.BreakKeyword, node.pos); + emitWithPrefix(" ", node.label); + write(";"); + } + + function emitReturnStatement(node: ReturnStatement) { + writeToken(SyntaxKind.ReturnKeyword, node.pos, /*contextNode*/ node); + emitExpressionWithPrefix(" ", node.expression); + write(";"); + } + + function emitWithStatement(node: WithStatement) { + write("with ("); + emitExpression(node.expression); + write(")"); + emitEmbeddedStatement(node.statement); + } + + function emitSwitchStatement(node: SwitchStatement) { + const openParenPos = writeToken(SyntaxKind.SwitchKeyword, node.pos); + write(" "); + writeToken(SyntaxKind.OpenParenToken, openParenPos); + emitExpression(node.expression); + writeToken(SyntaxKind.CloseParenToken, node.expression.end); + write(" "); + emit(node.caseBlock); + } + + function emitLabeledStatement(node: LabeledStatement) { + emit(node.label); + write(": "); + emit(node.statement); + } + + function emitThrowStatement(node: ThrowStatement) { + write("throw"); + emitExpressionWithPrefix(" ", node.expression); + write(";"); + } + + function emitTryStatement(node: TryStatement) { + write("try "); + emit(node.tryBlock); + emit(node.catchClause); + if (node.finallyBlock) { + writeLine(); + write("finally "); + emit(node.finallyBlock); + } + } + + function emitDebuggerStatement(node: DebuggerStatement) { + writeToken(SyntaxKind.DebuggerKeyword, node.pos); + write(";"); + } + + // + // Declarations + // + + function emitVariableDeclaration(node: VariableDeclaration) { + emit(node.name); + emitExpressionWithPrefix(" = ", node.initializer); + } + + function emitVariableDeclarationList(node: VariableDeclarationList) { + write(isLet(node) ? "let " : isConst(node) ? "const " : "var "); + emitList(node, node.declarations, ListFormat.VariableDeclarationList); + } + + function emitFunctionDeclaration(node: FunctionDeclaration) { + emitFunctionDeclarationOrExpression(node); + } + + function emitFunctionDeclarationOrExpression(node: FunctionDeclaration | FunctionExpression) { + emitDecorators(node, node.decorators); + emitModifiers(node, node.modifiers); + write(node.asteriskToken ? "function* " : "function "); + emitSpecialized(node.name, NodeEmitFlags.NoSourceMap); + emitSignatureAndBody(node, emitSignatureHead); + } + + function emitSignatureAndBody(node: FunctionLikeDeclaration, emitSignatureHead: (node: SignatureDeclaration) => void) { + const body = node.body; + if (body) { + if (isBlock(body)) { + const indentedFlag = node.emitFlags & NodeEmitFlags.Indented; + if (indentedFlag) { + increaseIndent(); + } + + const savedTempFlags = tempFlags; + tempFlags = 0; + emitSignatureHead(node); + emitBlockFunctionBody(node, body); + if (indentedFlag) { + decreaseIndent(); + } + + tempFlags = savedTempFlags; + } + else { + emitSignatureHead(node); + write(" "); + emitExpression(body); + } + } + else { + emitSignatureHead(node); + write(";"); + } + + } + + function emitSignatureHead(node: FunctionDeclaration | FunctionExpression | MethodDeclaration | AccessorDeclaration | ConstructorDeclaration) { + emitTypeParameters(node, node.typeParameters); + emitParameters(node, node.parameters); + emitWithPrefix(": ", node.type); + } + + function shouldEmitBlockFunctionBodyOnSingleLine(parentNode: Node, body: Block) { + // We must emit a function body as a single-line body in the following case: + // * The body has NodeEmitFlags.SingleLine specified. + + // We must emit a function body as a multi-line body in the following cases: + // * The body is explicitly marked as multi-line. + // * A non-synthesized body's start and end position are on different lines. + // * Any statement in the body starts on a new line. + + if (body.emitFlags & NodeEmitFlags.SingleLine) { + return true; + } + + if (body.multiLine) { + return false; + } + + if (!nodeIsSynthesized(body) && !rangeIsOnSingleLine(body, currentSourceFile)) { + return false; + } + + if (shouldWriteLeadingLineTerminator(body, body.statements, ListFormat.PreserveLines) + || shouldWriteClosingLineTerminator(body, body.statements, ListFormat.PreserveLines)) { + return false; + } + + let previousStatement: Statement; + for (const statement of body.statements) { + if (shouldWriteSeparatingLineTerminator(previousStatement, statement, ListFormat.PreserveLines)) { + return false; + } + + previousStatement = statement; + } + + return true; + } + + function emitBlockFunctionBody(parentNode: Node, body: Block) { + // TODO(rbuckton): This should be removed once source maps are aligned with the old + // emitter and new baselines are taken. This exists solely to + // align with the old emitter. + if (body.emitFlags & NodeEmitFlags.SourceMapEmitOpenBraceAsToken) { + write(" "); + writeToken(SyntaxKind.OpenBraceToken, body.pos); + } + else { + write(" {"); + } + + increaseIndent(); + + emitBodyWithDetachedComments(body, body.statements, + shouldEmitBlockFunctionBodyOnSingleLine(parentNode, body) + ? emitBlockFunctionBodyOnSingleLine + : emitBlockFunctionBodyWorker); + + decreaseIndent(); + writeToken(SyntaxKind.CloseBraceToken, body.statements.end, body); + } + + function emitBlockFunctionBodyOnSingleLine(body: Block) { + emitBlockFunctionBodyWorker(body, /*emitBlockFunctionBodyOnSingleLine*/ true); + } + + function emitBlockFunctionBodyWorker(body: Block, emitBlockFunctionBodyOnSingleLine?: boolean) { + // Emit all the prologue directives (like "use strict"). + const statementOffset = emitPrologueDirectives(body.statements, /*startWithNewLine*/ true); + const helpersEmitted = emitHelpers(body); + + if (statementOffset === 0 && !helpersEmitted && emitBlockFunctionBodyOnSingleLine) { + decreaseIndent(); + emitList(body, body.statements, ListFormat.SingleLineFunctionBodyStatements); + increaseIndent(); + } + else { + emitList(body, body.statements, ListFormat.MultiLineFunctionBodyStatements, statementOffset); + } + } + + function emitClassDeclaration(node: ClassDeclaration) { + emitClassDeclarationOrExpression(node); + } + + function emitClassDeclarationOrExpression(node: ClassDeclaration | ClassExpression) { + emitDecorators(node, node.decorators); + emitModifiers(node, node.modifiers); + write("class"); + emitSpecializedWithPrefix(" ", node.name, NodeEmitFlags.NoSourceMap); + + const indentedFlag = node.emitFlags & NodeEmitFlags.Indented; + if (indentedFlag) { + increaseIndent(); + } + + emitTypeParameters(node, node.typeParameters); + emitList(node, node.heritageClauses, ListFormat.ClassHeritageClauses); + + const savedTempFlags = tempFlags; + tempFlags = 0; + + write(" {"); + emitList(node, node.members, ListFormat.ClassMembers); + write("}"); + + if (indentedFlag) { + decreaseIndent(); + } + + tempFlags = savedTempFlags; + } + + function emitInterfaceDeclaration(node: InterfaceDeclaration) { + emitDecorators(node, node.decorators); + emitModifiers(node, node.modifiers); + write("interface "); + emit(node.name); + emitTypeParameters(node, node.typeParameters); + emitList(node, node.heritageClauses, ListFormat.HeritageClauses); + write(" {"); + emitList(node, node.members, ListFormat.InterfaceMembers); + write("}"); + } + + function emitTypeAliasDeclaration(node: TypeAliasDeclaration) { + emitDecorators(node, node.decorators); + emitModifiers(node, node.modifiers); + write("type "); + emit(node.name); + emitTypeParameters(node, node.typeParameters); + write(" = "); + emit(node.type); + write(";"); + } + + function emitEnumDeclaration(node: EnumDeclaration) { + emitModifiers(node, node.modifiers); + write("enum "); + emit(node.name); + + const savedTempFlags = tempFlags; + tempFlags = 0; + + write(" {"); + emitList(node, node.members, ListFormat.EnumMembers); + write("}"); + tempFlags = savedTempFlags; + } + + function emitModuleDeclaration(node: ModuleDeclaration) { + emitModifiers(node, node.modifiers); + write(node.flags & NodeFlags.Namespace ? "namespace " : "module "); + emit(node.name); + + let body = node.body; + while (body.kind === SyntaxKind.ModuleDeclaration) { + write("."); + emit((body).name); + body = (body).body; + } + + write(" "); + emit(body); + } + + function emitModuleBlock(node: ModuleBlock) { + if (isSingleLineEmptyBlock(node)) { + write("{ }"); + } + else { + const savedTempFlags = tempFlags; + tempFlags = 0; + write("{"); + increaseIndent(); + emitBlockStatements(node); + write("}"); + tempFlags = savedTempFlags; + } + } + + function emitCaseBlock(node: CaseBlock) { + writeToken(SyntaxKind.OpenBraceToken, node.pos); + emitList(node, node.clauses, ListFormat.CaseBlockClauses); + writeToken(SyntaxKind.CloseBraceToken, node.clauses.end); + } + + function emitImportEqualsDeclaration(node: ImportEqualsDeclaration) { + emitModifiers(node, node.modifiers); + write("import "); + emit(node.name); + write(" = "); + emitModuleReference(node.moduleReference); + write(";"); + } + + function emitModuleReference(node: ModuleReference) { + if (node.kind === SyntaxKind.Identifier) { + emitExpression(node); + } + else { + emit(node); + } + } + + function emitImportDeclaration(node: ImportDeclaration) { + emitModifiers(node, node.modifiers); + write("import "); + if (node.importClause) { + emit(node.importClause); + write(" from "); + } + emitExpression(node.moduleSpecifier); + write(";"); + } + + function emitImportClause(node: ImportClause) { + emit(node.name); + if (node.name && node.namedBindings) { + write(", "); + } + emit(node.namedBindings); + } + + function emitNamespaceImport(node: NamespaceImport) { + write("* as "); + emit(node.name); + } + + function emitNamedImports(node: NamedImports) { + emitNamedImportsOrExports(node); + } + + function emitImportSpecifier(node: ImportSpecifier) { + emitImportOrExportSpecifier(node); + } + + function emitExportAssignment(node: ExportAssignment) { + write(node.isExportEquals ? "export = " : "export default "); + emitExpression(node.expression); + write(";"); + } + + function emitExportDeclaration(node: ExportDeclaration) { + write("export "); + if (node.exportClause) { + emit(node.exportClause); + } + else { + write("*"); + } + if (node.moduleSpecifier) { + write(" from "); + emitExpression(node.moduleSpecifier); + } + write(";"); + } + + function emitNamedExports(node: NamedExports) { + emitNamedImportsOrExports(node); + } + + function emitExportSpecifier(node: ExportSpecifier) { + emitImportOrExportSpecifier(node); + } + + function emitNamedImportsOrExports(node: NamedImportsOrExports) { + write("{"); + emitList(node, node.elements, ListFormat.NamedImportsOrExportsElements); + write("}"); + } + + function emitImportOrExportSpecifier(node: ImportOrExportSpecifier) { + if (node.propertyName) { + emit(node.propertyName); + write(" as "); + } + + emit(node.name); + } + + // + // Module references + // + + function emitExternalModuleReference(node: ExternalModuleReference) { + write("require("); + emitExpression(node.expression); + write(")"); + } + + // + // JSX + // + + function emitJsxElement(node: JsxElement) { + emit(node.openingElement); + emitList(node, node.children, ListFormat.JsxElementChildren); + emit(node.closingElement); + } + + function emitJsxSelfClosingElement(node: JsxSelfClosingElement) { + write("<"); + emitJsxTagName(node.tagName); + write(" "); + emitList(node, node.attributes, ListFormat.JsxElementAttributes); + write("/>"); + } + + function emitJsxOpeningElement(node: JsxOpeningElement) { + write("<"); + emitJsxTagName(node.tagName); + writeIfAny(node.attributes, " "); + emitList(node, node.attributes, ListFormat.JsxElementAttributes); + write(">"); + } + + function emitJsxText(node: JsxText) { + writer.writeLiteral(getTextOfNode(node, /*includeTrivia*/ true)); + } + + function emitJsxClosingElement(node: JsxClosingElement) { + write(""); + } + + function emitJsxAttribute(node: JsxAttribute) { + emit(node.name); + emitWithPrefix("=", node.initializer); + } + + function emitJsxSpreadAttribute(node: JsxSpreadAttribute) { + write("{..."); + emitExpression(node.expression); + write("}"); + } + + function emitJsxExpression(node: JsxExpression) { + if (node.expression) { + write("{"); + emitExpression(node.expression); + write("}"); + } + } + + function emitJsxTagName(node: EntityName) { + if (node.kind === SyntaxKind.Identifier) { + emitExpression(node); + } + else { + emit(node); + } + } + + // + // Clauses + // + + function emitCaseClause(node: CaseClause) { + write("case "); + emitExpression(node.expression); + write(":"); + + emitCaseOrDefaultClauseStatements(node, node.statements); + } + + function emitDefaultClause(node: DefaultClause) { + write("default:"); + emitCaseOrDefaultClauseStatements(node, node.statements); + } + + function emitCaseOrDefaultClauseStatements(parentNode: Node, statements: NodeArray) { + const emitAsSingleStatement = + statements.length === 1 && + ( + // treat synthesized nodes as located on the same line for emit purposes + nodeIsSynthesized(parentNode) || + nodeIsSynthesized(statements[0]) || + rangeStartPositionsAreOnSameLine(parentNode, statements[0], currentSourceFile) + ); + + if (emitAsSingleStatement) { + write(" "); + emit(statements[0]); + } + else { + emitList(parentNode, statements, ListFormat.CaseOrDefaultClauseStatements); + } + } + + function emitHeritageClause(node: HeritageClause) { + write(" "); + writeTokenText(node.token); + write(" "); + emitList(node, node.types, ListFormat.HeritageClauseTypes); + } + + function emitCatchClause(node: CatchClause) { + writeLine(); + const openParenPos = writeToken(SyntaxKind.CatchKeyword, node.pos); + write(" "); + writeToken(SyntaxKind.OpenParenToken, openParenPos); + emit(node.variableDeclaration); + writeToken(SyntaxKind.CloseParenToken, node.variableDeclaration ? node.variableDeclaration.end : openParenPos); + write(" "); + emit(node.block); + } + + // + // Property assignments + // + + function emitPropertyAssignment(node: PropertyAssignment) { + emit(node.name); + write(": "); + // This is to ensure that we emit comment in the following case: + // For example: + // obj = { + // id: /*comment1*/ ()=>void + // } + // "comment1" is not considered to be leading comment for node.initializer + // but rather a trailing comment on the previous node. + const initializer = node.initializer; + if (!shouldSkipLeadingCommentsForNode(initializer)) { + const commentRange = initializer.commentRange || initializer; + emitTrailingCommentsOfPosition(commentRange.pos); + } + + emitExpression(node.initializer); + } + + function emitShorthandPropertyAssignment(node: ShorthandPropertyAssignment) { + emit(node.name); + if (node.objectAssignmentInitializer) { + write(" = "); + emitExpression(node.objectAssignmentInitializer); + } + } + + // + // Enum + // + + function emitEnumMember(node: EnumMember) { + emit(node.name); + emitExpressionWithPrefix(" = ", node.initializer); + } + + // + // Top-level nodes + // + + function emitSourceFile(node: SourceFile) { + writeLine(); + emitShebang(); + emitBodyWithDetachedComments(node, node.statements, emitSourceFileWorker); + } + + function emitSourceFileWorker(node: SourceFile) { + const statements = node.statements; + const statementOffset = emitPrologueDirectives(statements); + const savedTempFlags = tempFlags; + tempFlags = 0; + emitHelpers(node); + emitList(node, statements, ListFormat.MultiLine, statementOffset); + tempFlags = savedTempFlags; + } + + // Transformation nodes + + function emitPartiallyEmittedExpression(node: PartiallyEmittedExpression) { + emitExpression(node.expression); + } + + /** + * Emits any prologue directives at the start of a Statement list, returning the + * number of prologue directives written to the output. + */ + function emitPrologueDirectives(statements: Node[], startWithNewLine?: boolean): number { + for (let i = 0; i < statements.length; i++) { + if (isPrologueDirective(statements[i])) { + if (startWithNewLine || i > 0) { + writeLine(); + } + emit(statements[i]); + } + else { + // return index of the first non prologue directive + return i; + } + } + + return statements.length; + } + + function emitHelpers(node: Node) { + const emitFlags = node.emitFlags; + let helpersEmitted = false; + if (emitFlags & NodeEmitFlags.EmitEmitHelpers) { + helpersEmitted = emitEmitHelpers(currentSourceFile); + } + + if (emitFlags & NodeEmitFlags.EmitExportStar) { + writeLines(exportStarHelper); + helpersEmitted = true; + } + + if (emitFlags & NodeEmitFlags.EmitSuperHelper) { + writeLines(superHelper); + helpersEmitted = true; + } + + if (emitFlags & NodeEmitFlags.EmitAdvancedSuperHelper) { + writeLines(advancedSuperHelper); + helpersEmitted = true; + } + + return helpersEmitted; + } + + function emitEmitHelpers(node: SourceFile) { + let helpersEmitted = false; + + // Only emit helpers if the user did not say otherwise. + if (!compilerOptions.noEmitHelpers) { + // Only Emit __extends function when target ES5. + // For target ES6 and above, we can emit classDeclaration as is. + if ((languageVersion < ScriptTarget.ES6) && (!extendsEmitted && node.flags & NodeFlags.HasClassExtends)) { + writeLines(extendsHelper); + extendsEmitted = true; + helpersEmitted = true; + } + + if (compilerOptions.jsx !== JsxEmit.Preserve && !assignEmitted && (node.flags & NodeFlags.HasJsxSpreadAttribute)) { + writeLines(assignHelper); + assignEmitted = true; + } + + if (!decorateEmitted && node.flags & NodeFlags.HasDecorators) { + writeLines(decorateHelper); + if (compilerOptions.emitDecoratorMetadata) { + writeLines(metadataHelper); + } + + decorateEmitted = true; + helpersEmitted = true; + } + + if (!paramEmitted && node.flags & NodeFlags.HasParamDecorators) { + writeLines(paramHelper); + paramEmitted = true; + helpersEmitted = true; + } + + if (!awaiterEmitted && node.flags & NodeFlags.HasAsyncFunctions) { + writeLines(awaiterHelper); + awaiterEmitted = true; + helpersEmitted = true; + } + + if (helpersEmitted) { + writeLine(); + } + } + + return helpersEmitted; + } + + function writeLines(text: string): void { + const lines = text.split(/\r\n|\r|\n/g); + for (let i = 0; i < lines.length; i++) { + const line = lines[i]; + if (line.length) { + if (i > 0) { + writeLine(); + } + write(line); + } + } + } + + // + // Helpers + // + + function emitShebang() { + const shebang = getShebang(currentText); + if (shebang) { + write(shebang); + writeLine(); + } + } + + function emitModifiers(node: Node, modifiers: NodeArray) { + if (modifiers && modifiers.length) { + emitList(node, modifiers, ListFormat.Modifiers); + write(" "); + } + } + + function emitWithPrefix(prefix: string, node: Node) { + emitNodeWithPrefix(prefix, node, emit); + } + + // TODO(rbuckton): This should be removed once source maps are aligned with the old + // emitter and new baselines are taken. This exists solely to + // align with the old emitter. + function emitSpecializedWithPrefix(prefix: string, node: Node, flags: NodeEmitFlags) { + if (node) { + write(prefix); + emitSpecialized(node, flags); + } + } + + function emitExpressionWithPrefix(prefix: string, node: Node) { + emitNodeWithPrefix(prefix, node, emitExpression); + } + + function emitNodeWithPrefix(prefix: string, node: Node, emit: (node: Node) => void) { + if (node) { + write(prefix); + emit(node); + } + } + + function emitWithSuffix(node: Node, suffix: string) { + if (node) { + emit(node); + write(suffix); + } + } + + function tryEmitSubstitute(node: Node, emitNode: (node: Node) => void, isExpression: boolean) { + if (isSubstitutionEnabled(node) && (node.emitFlags & NodeEmitFlags.NoSubstitution) === 0) { + const substitute = onSubstituteNode(node, isExpression); + if (substitute !== node) { + substitute.emitFlags |= NodeEmitFlags.NoSubstitution; + emitNode(substitute); + return true; + } + } + + return false; + } + + function tryEmitConstantValue(node: PropertyAccessExpression | ElementAccessExpression): boolean { + const constantValue = tryGetConstEnumValue(node); + if (constantValue !== undefined) { + write(String(constantValue)); + if (!compilerOptions.removeComments) { + const propertyName = isPropertyAccessExpression(node) + ? declarationNameToString(node.name) + : getTextOfNode(node.argumentExpression); + write(` /* ${propertyName} */`); + } + + return true; + } + + return false; + } + + function emitEmbeddedStatement(node: Statement) { + if (isBlock(node)) { + write(" "); + emit(node); + } + else { + writeLine(); + increaseIndent(); + emit(node); + decreaseIndent(); + } + } + + function emitDecorators(parentNode: Node, decorators: NodeArray) { + emitList(parentNode, decorators, ListFormat.Decorators); + } + + function emitTypeArguments(parentNode: Node, typeArguments: NodeArray) { + emitList(parentNode, typeArguments, ListFormat.TypeArguments); + } + + function emitTypeParameters(parentNode: Node, typeParameters: NodeArray) { + emitList(parentNode, typeParameters, ListFormat.TypeParameters); + } + + function emitParameters(parentNode: Node, parameters: NodeArray) { + emitList(parentNode, parameters, ListFormat.Parameters); + } + + function emitParametersForArrow(parentNode: Node, parameters: NodeArray) { + if (parameters && + parameters.length === 1 && + parameters[0].type === undefined && + parameters[0].pos === parentNode.pos) { + emit(parameters[0]); + } + else { + emitParameters(parentNode, parameters); + } + } + + function emitParametersForIndexSignature(parentNode: Node, parameters: NodeArray) { + emitList(parentNode, parameters, ListFormat.IndexSignatureParameters); + } + + function emitList(parentNode: Node, children: NodeArray, format: ListFormat, start?: number, count?: number) { + emitNodeList(emit, parentNode, children, format, start, count); + } + + function emitExpressionList(parentNode: Node, children: NodeArray, format: ListFormat, start?: number, count?: number) { + emitNodeList(emitExpression, parentNode, children, format, start, count); + } + + function emitNodeList(emit: (node: Node) => void, parentNode: Node, children: NodeArray, format: ListFormat, start = 0, count = children ? children.length - start : 0) { + const isUndefined = children === undefined; + if (isUndefined && format & ListFormat.OptionalIfUndefined) { + return; + } + + const isEmpty = isUndefined || children.length === 0 || start >= children.length || count === 0; + if (isEmpty && format & ListFormat.OptionalIfEmpty) { + return; + } + + if (format & ListFormat.BracketsMask) { + write(getOpeningBracket(format)); + } + + if (isEmpty) { + // Write a line terminator if the parent node was multi-line + if (format & ListFormat.MultiLine) { + writeLine(); + } + else if (format & ListFormat.SpaceBetweenBraces) { + write(" "); + } + } + else { + // Write the opening line terminator or leading whitespace. + const mayEmitInterveningComments = (format & ListFormat.NoInterveningComments) === 0; + let shouldEmitInterveningComments = mayEmitInterveningComments; + if (shouldWriteLeadingLineTerminator(parentNode, children, format)) { + writeLine(); + shouldEmitInterveningComments = false; + } + else if (format & ListFormat.SpaceBetweenBraces) { + write(" "); + } + + // Increase the indent, if requested. + if (format & ListFormat.Indented) { + increaseIndent(); + } + + // Emit each child. + let previousSibling: Node; + let shouldDecreaseIndentAfterEmit: boolean; + const delimiter = getDelimiter(format); + for (let i = 0; i < count; i++) { + const child = children[start + i]; + + // Write the delimiter if this is not the first node. + if (previousSibling) { + write(delimiter); + + // Write either a line terminator or whitespace to separate the elements. + if (shouldWriteSeparatingLineTerminator(previousSibling, child, format)) { + // If a synthesized node in a single-line list starts on a new + // line, we should increase the indent. + if ((format & (ListFormat.LinesMask | ListFormat.Indented)) === ListFormat.SingleLine) { + increaseIndent(); + shouldDecreaseIndentAfterEmit = true; + } + + writeLine(); + shouldEmitInterveningComments = false; + } + else if (previousSibling && format & ListFormat.SpaceBetweenSiblings) { + write(" "); + } + } + + if (shouldEmitInterveningComments) { + const commentRange = child.commentRange || child; + emitTrailingCommentsOfPosition(commentRange.pos); + } + else { + shouldEmitInterveningComments = mayEmitInterveningComments; + } + + // Emit this child. + emit(child); + + if (shouldDecreaseIndentAfterEmit) { + decreaseIndent(); + shouldDecreaseIndentAfterEmit = false; + } + + previousSibling = child; + } + + // Write a trailing comma, if requested. + const hasTrailingComma = (format & ListFormat.AllowTrailingComma) && children.hasTrailingComma; + if (format & ListFormat.CommaDelimited && hasTrailingComma) { + write(","); + } + + // Decrease the indent, if requested. + if (format & ListFormat.Indented) { + decreaseIndent(); + } + + // Write the closing line terminator or closing whitespace. + if (shouldWriteClosingLineTerminator(parentNode, children, format)) { + writeLine(); + } + else if (format & ListFormat.SpaceBetweenBraces) { + write(" "); + } + } + + if (format & ListFormat.BracketsMask) { + write(getClosingBracket(format)); + } + } + + function writeIfAny(nodes: NodeArray, text: string) { + if (nodes && nodes.length > 0) { + write(text); + } + } + + function writeIfPresent(node: Node, text: string) { + if (node !== undefined) { + write(text); + } + } + + function writeToken(token: SyntaxKind, pos: number, contextNode?: Node) { + const tokenStartPos = emitTokenStart(token, pos, contextNode, shouldSkipLeadingSourceMapForToken, getTokenSourceMapRange); + const tokenEndPos = writeTokenText(token, tokenStartPos); + return emitTokenEnd(token, tokenEndPos, contextNode, shouldSkipTrailingSourceMapForToken, getTokenSourceMapRange); + } + + function shouldSkipLeadingSourceMapForToken(contextNode: Node) { + return (contextNode.emitFlags & NodeEmitFlags.NoTokenLeadingSourceMaps) !== 0; + } + + function shouldSkipTrailingSourceMapForToken(contextNode: Node) { + return (contextNode.emitFlags & NodeEmitFlags.NoTokenTrailingSourceMaps) !== 0; + } + + function writeTokenText(token: SyntaxKind, pos?: number) { + const tokenString = tokenToString(token); + write(tokenString); + return positionIsSynthesized(pos) ? -1 : pos + tokenString.length; + } + + function writeTokenNode(node: Node) { + if (node) { + emitStart(/*range*/ node, /*contextNode*/ node, shouldSkipLeadingSourceMapForNode, shouldSkipSourceMapForChildren, getSourceMapRange); + writeTokenText(node.kind); + emitEnd(/*range*/ node, /*contextNode*/ node, shouldSkipTrailingSourceMapForNode, shouldSkipSourceMapForChildren, getSourceMapRange); + } + } + + function increaseIndentIf(value: boolean, valueToWriteWhenNotIndenting?: string) { + if (value) { + increaseIndent(); + writeLine(); + } + else if (valueToWriteWhenNotIndenting) { + write(valueToWriteWhenNotIndenting); + } + } + + // Helper function to decrease the indent if we previously indented. Allows multiple + // previous indent values to be considered at a time. This also allows caller to just + // call this once, passing in all their appropriate indent values, instead of needing + // to call this helper function multiple times. + function decreaseIndentIf(value1: boolean, value2?: boolean) { + if (value1) { + decreaseIndent(); + } + if (value2) { + decreaseIndent(); + } + } + + function shouldWriteLeadingLineTerminator(parentNode: Node, children: NodeArray, format: ListFormat) { + if (format & ListFormat.MultiLine) { + return true; + } + + if (format & ListFormat.PreserveLines) { + if (format & ListFormat.PreferNewLine) { + return true; + } + + const firstChild = children[0]; + if (firstChild === undefined) { + return !rangeIsOnSingleLine(parentNode, currentSourceFile); + } + else if (positionIsSynthesized(parentNode.pos) || nodeIsSynthesized(firstChild)) { + return synthesizedNodeStartsOnNewLine(firstChild, format); + } + else { + return !rangeStartPositionsAreOnSameLine(parentNode, firstChild, currentSourceFile); + } + } + else { + return false; + } + } + + function shouldWriteSeparatingLineTerminator(previousNode: Node, nextNode: Node, format: ListFormat) { + if (format & ListFormat.MultiLine) { + return true; + } + else if (format & ListFormat.PreserveLines) { + if (previousNode === undefined || nextNode === undefined) { + return false; + } + else if (nodeIsSynthesized(previousNode) || nodeIsSynthesized(nextNode)) { + return synthesizedNodeStartsOnNewLine(previousNode, format) || synthesizedNodeStartsOnNewLine(nextNode, format); + } + else { + return !rangeEndIsOnSameLineAsRangeStart(previousNode, nextNode, currentSourceFile); + } + } + else { + return nextNode.startsOnNewLine; + } + } + + function shouldWriteClosingLineTerminator(parentNode: Node, children: NodeArray, format: ListFormat) { + if (format & ListFormat.MultiLine) { + return (format & ListFormat.NoTrailingNewLine) === 0; + } + else if (format & ListFormat.PreserveLines) { + if (format & ListFormat.PreferNewLine) { + return true; + } + + const lastChild = lastOrUndefined(children); + if (lastChild === undefined) { + return !rangeIsOnSingleLine(parentNode, currentSourceFile); + } + else if (positionIsSynthesized(parentNode.pos) || nodeIsSynthesized(lastChild)) { + return synthesizedNodeStartsOnNewLine(lastChild, format); + } + else { + return !rangeEndPositionsAreOnSameLine(parentNode, lastChild, currentSourceFile); + } + } + else { + return false; + } + } + + function synthesizedNodeStartsOnNewLine(node: Node, format?: ListFormat) { + if (nodeIsSynthesized(node)) { + const startsOnNewLine = node.startsOnNewLine; + if (startsOnNewLine === undefined) { + return (format & ListFormat.PreferNewLine) !== 0; + } + + return startsOnNewLine; + } + + return (format & ListFormat.PreferNewLine) !== 0; + } + + function needsIndentation(parent: Node, node1: Node, node2: Node): boolean { + parent = skipSynthesizedParentheses(parent); + node1 = skipSynthesizedParentheses(node1); + node2 = skipSynthesizedParentheses(node2); + + // Always use a newline for synthesized code if the synthesizer desires it. + if (node2.startsOnNewLine) { + return true; + } + + return !nodeIsSynthesized(parent) + && !nodeIsSynthesized(node1) + && !nodeIsSynthesized(node2) + && !rangeEndIsOnSameLineAsRangeStart(node1, node2, currentSourceFile); + } + + function skipSynthesizedParentheses(node: Node) { + while (node.kind === SyntaxKind.ParenthesizedExpression && nodeIsSynthesized(node)) { + node = (node).expression; + } + + return node; + } + + function getTextOfNode(node: Node, includeTrivia?: boolean): string { + if (isGeneratedIdentifier(node)) { + return getGeneratedIdentifier(node); + } + else if (isIdentifier(node) && (nodeIsSynthesized(node) || !node.parent)) { + return unescapeIdentifier(node.text); + } + else if (node.kind === SyntaxKind.StringLiteral && (node).textSourceNode) { + return getTextOfNode((node).textSourceNode, includeTrivia); + } + else if (isLiteralExpression(node) && (nodeIsSynthesized(node) || !node.parent)) { + return node.text; + } + + return getSourceTextOfNodeFromSourceFile(currentSourceFile, node, includeTrivia); + } + + function getLiteralTextOfNode(node: LiteralLikeNode): string { + if (node.kind === SyntaxKind.StringLiteral && (node).textSourceNode) { + const textSourceNode = (node).textSourceNode; + if (isIdentifier(textSourceNode)) { + return "\"" + escapeNonAsciiCharacters(escapeString(getTextOfNode(textSourceNode))) + "\""; + } + else { + return getLiteralTextOfNode(textSourceNode); + } + } + + return getLiteralText(node, currentSourceFile, languageVersion); + } + + function tryGetConstEnumValue(node: Node): number { + if (compilerOptions.isolatedModules) { + return undefined; + } + + return isPropertyAccessExpression(node) || isElementAccessExpression(node) + ? resolver.getConstantValue(node) + : undefined; + } + + function isSingleLineEmptyBlock(block: Block) { + return !block.multiLine + && block.statements.length === 0 + && rangeEndIsOnSameLineAsRangeStart(block, block, currentSourceFile); + } + + function isUniqueName(name: string): boolean { + return !resolver.hasGlobalName(name) && + !hasProperty(currentFileIdentifiers, name) && + !hasProperty(generatedNameSet, name); + } + function isUniqueLocalName(name: string, container: Node): boolean { for (let node = container; isNodeDescendantOf(node, container); node = node.nextContainer) { if (node.locals && hasProperty(node.locals, name)) { @@ -417,7865 +2649,270 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge return true; } - interface ConvertedLoopState { - /* - * set of labels that occurred inside the converted loop - * used to determine if labeled jump can be emitted as is or it should be dispatched to calling code - */ - labels?: Map; - /* - * collection of labeled jumps that transfer control outside the converted loop. - * maps store association 'label -> labelMarker' where - * - label - value of label as it appear in code - * - label marker - return value that should be interpreted by calling code as 'jump to