diff --git a/Jakefile.js b/Jakefile.js index a6483355c73..3015134ea6c 100644 --- a/Jakefile.js +++ b/Jakefile.js @@ -2,262 +2,254 @@ // @ts-check /// -var fs = require("fs"); -var os = require("os"); -var path = require("path"); -var child_process = require("child_process"); -var fold = require("travis-fold"); -var ts = require("./lib/typescript"); +const fs = require("fs"); +const os = require("os"); +const path = require("path"); +const child_process = require("child_process"); +const removeInternal = require("remove-internal"); +const fold = require("travis-fold"); +const ts = require("./lib/typescript"); +const del = require("del"); const getDirSize = require("./scripts/build/getDirSize"); -// Variables -var compilerDirectory = "src/compiler/"; -var serverDirectory = "src/server/"; -var harnessDirectory = "src/harness/"; -var libraryDirectory = "src/lib/"; -var scriptsDirectory = "scripts/"; -var unittestsDirectory = "src/harness/unittests/"; -var docDirectory = "doc/"; -var lclDirectory = "src/loc/lcl"; +const host = process.env.TYPESCRIPT_HOST || process.env.host || "node"; -var builtDirectory = "built/"; -var builtLocalDirectory = "built/local/"; -var LKGDirectory = "lib/"; +const locales = ["cs", "de", "es", "fr", "it", "ja", "ko", "pl", "pt-br", "ru", "tr", "zh-cn", "zh-tw"]; -var copyright = "CopyrightNotice.txt"; -var thirdParty = "ThirdPartyNoticeText.txt"; +const defaultTestTimeout = 40000; -var defaultTestTimeout = 40000; +let useDebugMode = true; -// add node_modules to path so we don't need global modules, prefer the modules by adding them first -var nodeModulesPathPrefix = path.resolve("./node_modules/.bin/") + path.delimiter; -if (process.env.path !== undefined) { - process.env.path = nodeModulesPathPrefix + process.env.path; -} -else if (process.env.PATH !== undefined) { - process.env.PATH = nodeModulesPathPrefix + process.env.PATH; -} +const TaskNames = { + local: "local", + runtests: "runtests", + runtestsParallel: "runtests-parallel", + buildRules: "build-rules", + clean: "clean", + lib: "lib", + buildFoldStart: "build-fold-start", + buildFoldEnd: "build-fold-end", + generateDiagnostics: "generate-diagnostics", + coreBuild: "core-build", + lkg: "LKG", + release: "release", + lssl: "lssl", + lint: "lint" +}; -/** - * @param diagnostics {ts.Diagnostic[]} - * @param [pretty] {boolean} - */ -function diagnosticsToString(diagnostics, pretty) { - const host = { - getCurrentDirectory() { return process.cwd(); }, - getCanonicalFileName(fileName) { return fileName; }, - getNewLine() { return os.EOL; } - }; - return pretty ? ts.formatDiagnosticsWithColorAndContext(diagnostics, host) : - ts.formatDiagnostics(diagnostics, host); -} +const Paths = { + lkg: "lib", + lkgCompiler: "lib/tsc.js", -/** @param diagnostics {ts.Diagnostic[]} */ -function reportDiagnostics(diagnostics) { - console.log(diagnosticsToString(diagnostics, process.stdout.isTTY)); -} + built: "built", + builtLocal: "built/local", + builtLocalCompiler: "built/local/tsc.js", + builtLocalRun: "built/local/run.js", + locLcg: "built/local/enu/diagnosticMessages.generated.json.lcg", + typesMapOutput: "built/local/typesMap.json", + servicesFile: "built/local/typescriptServices.js", + servicesDefinitionFile: "built/local/typescriptServices.d.ts", -/** @param jsonPath {string} */ -function readJson(jsonPath) { - const jsonText = fs.readFileSync(jsonPath, "utf8"); - const result = ts.parseConfigFileTextToJson(jsonPath, jsonText); - if (result.error) { - reportDiagnostics([result.error]); - throw new Error("An error occurred during parse."); - } - return result.config; -} + tsserverLibraryFile: "built/local/tsserverlibrary.js", + tsserverLibraryDefinitionFile: "built/local/tsserverlibrary.d.ts", -/** @param configPath {string} */ -function filesFromConfig(configPath) { - const config = readJson(configPath); - const configFileContent = ts.parseJsonConfigFileContent(config, ts.sys, path.dirname(configPath)); - if (configFileContent.errors && configFileContent.errors.length) { - reportDiagnostics(configFileContent.errors); - throw new Error("An error occurred during parse."); - } - return configFileContent.fileNames; -} + baselines: { + local: "tests/baselines/local", + localTest262: "tests/baselines/test262/local", + localRwc: "tests/baselines/rwc/local", + reference: "tests/baselines/reference", + referenceTest262: "tests/baselines/test262/reference", + referenceRwc: "tests/baselines/rwc/reference" + }, + copyright: "CopyrightNotice.txt", + thirdParty: "ThirdPartyNoticeText.txt", + library: "src/lib", -function toNs(diff) { - return diff[0] * 1e9 + diff[1]; -} + processDiagnosticMessagesJs: "scripts/processDiagnosticMessages.js", + diagnosticInformationMap: "src/parser/diagnosticInformationMap.generated.ts", + diagnosticMessagesJson: "src/parser/diagnosticMessages.json", -function mark() { - if (!fold.isTravis()) return; - var stamp = process.hrtime(); - var id = Math.floor(Math.random() * 0xFFFFFFFF).toString(16); - console.log("travis_time:start:" + id + "\r"); - return { - stamp: stamp, - id: id - }; -} + srcServer: "src/server", -function measure(marker) { - if (!fold.isTravis()) return; - var diff = process.hrtime(marker.stamp); - var total = [marker.stamp[0] + diff[0], marker.stamp[1] + diff[1]]; - console.log("travis_time:end:" + marker.id + ":start=" + toNs(marker.stamp) + ",finish=" + toNs(total) + ",duration=" + toNs(diff) + "\r"); -} +}; -function removeConstModifierFromEnumDeclarations(text) { - return text.replace(/^(\s*)(export )?const enum (\S+) {(\s*)$/gm, '$1$2enum $3 {$4'); -} +const ConfigFileFor = { + tsc: "src/tsc", + tsserver: "src/tsserver", + runjs: "src/testRunner", + lint: "scripts/tslint", + all: "src" +}; -var compilerSources = filesFromConfig("./src/compiler/tsconfig.json"); -var servicesSources = filesFromConfig("./src/services/tsconfig.json"); -var cancellationTokenSources = filesFromConfig(path.join(serverDirectory, "cancellationToken/tsconfig.json")); -var typingsInstallerSources = filesFromConfig(path.join(serverDirectory, "typingsInstaller/tsconfig.json")); -var watchGuardSources = filesFromConfig(path.join(serverDirectory, "watchGuard/tsconfig.json")); -var serverSources = filesFromConfig(path.join(serverDirectory, "tsconfig.json")); -var languageServiceLibrarySources = filesFromConfig(path.join(serverDirectory, "tsconfig.library.json")); -var harnessSources = filesFromConfig("./src/harness/tsconfig.json"); - -var typesMapOutputPath = path.join(builtLocalDirectory, 'typesMap.json'); +const ExpectedLKGFiles = [ + "tsc.js", + "tsserver.js", + "typescriptServices.js", + "typescriptServices.d.ts", + "typescript.js", + "typescript.d.ts", + "tsserverlibrary.js", + "tsserverlibrary.d.js", + "cancellationToken.js", + "typingsInstaller.js", + "protocol.d.ts", + "watchGuard.js" +]; /** @type {{ libs: string[], paths?: Record, sources?: Record }} */ -var libraries = readJson("./src/lib/libs.json"); +const libraries = readJson("./src/lib/libs.json"); -/** - * .lcg file is what localization team uses to know what messages to localize. - * The file is always generated in 'enu\diagnosticMessages.generated.json.lcg' - */ -var generatedLCGFile = path.join(builtLocalDirectory, "enu", "diagnosticMessages.generated.json.lcg"); +directory(Paths.builtLocal); -/** - * The localization target produces the two following transformations: - * 1. 'src\loc\lcl\\diagnosticMessages.generated.json.lcl' => 'built\local\\diagnosticMessages.generated.json' - * convert localized resources into a .json file the compiler can understand - * 2. 'src\compiler\diagnosticMessages.generated.json' => 'built\local\ENU\diagnosticMessages.generated.json.lcg' - * generate the lcg file (source of messages to localize) from the diagnosticMessages.generated.json - */ -var localizationTargets = ["cs", "de", "es", "fr", "it", "ja", "ko", "pl", "pt-br", "ru", "tr", "zh-cn", "zh-tw"].map(function (f) { - return path.join(builtLocalDirectory, f); -}).concat(path.dirname(generatedLCGFile)); +// Local target to build the compiler and services +desc("Builds the full compiler and services"); +task(TaskNames.local, [ + TaskNames.buildFoldStart, + TaskNames.generateDiagnostics, + TaskNames.lib, + TaskNames.coreBuild, + // buildProtocolDts, + // builtGeneratedDiagnosticMessagesJSON, + TaskNames.lssl, + // "localize", + TaskNames.buildFoldEnd +]); -// Prepends the contents of prefixFile to destinationFile -function prependFile(prefixFile, destinationFile) { - if (!fs.existsSync(prefixFile)) { - fail(prefixFile + " does not exist!"); +desc("Runs all the tests in parallel using the built run.js file. Optional arguments are: t[ests]=category1|category2|... d[ebug]=true."); +task(TaskNames.runtestsParallel, [TaskNames.lib], function () { + tsbuild([ConfigFileFor.runjs, ConfigFileFor.lint]); + runConsoleTests("min", /*parallel*/ true); +}, { async: true }); + +desc("Runs all the tests in parallel using the built run.js file. Optional arguments are: t[ests]=category1|category2|... d[ebug]=true."); +task(TaskNames.runtests, [TaskNames.lib], function () { + tsbuild([ConfigFileFor.runjs, ConfigFileFor.lint]); + runConsoleTests('mocha-fivemat-progress-reporter', /*runInParallel*/ false);; +}, { async: true }); + +const libraryTargets = getLibraryTargets(); +desc("Builds the library targets"); +task(TaskNames.lib, libraryTargets); + +desc("Builds language service server library"); +task("lssl", [TaskNames.coreBuild, Paths.tsserverLibraryFile, Paths.tsserverLibraryDefinitionFile, Paths.typesMapOutput]); + +// Makes a new LKG. This target does not build anything, but errors if not all the outputs are present in the built/local directory +desc("Makes a new LKG out of the built js files"); +task(TaskNames.lkg, [ + TaskNames.clean, + TaskNames.release, + TaskNames.local, + ...libraryTargets +], () => { + const sizeBefore = getDirSize(Paths.lkg); + const localizationTargets = locales.map(f => path.join(Paths.builtLocal, f)).concat(path.dirname(Paths.locLcg)); + + const copyrightContent = fs.readFileSync(Paths.copyright, { encoding: 'utf-8' }); + + const expectedFiles = [...libraryTargets, ...ExpectedLKGFiles, ...localizationTargets]; + const missingFiles = expectedFiles.filter(f => !fs.existsSync(f)); + if (missingFiles.length > 0) { + fail(new Error("Cannot replace the LKG unless all built targets are present in directory " + Paths.builtLocal + + ". The following files are missing:\n" + missingFiles.join("\n"))); } - if (!fs.existsSync(destinationFile)) { - fail(destinationFile + " failed to be created!"); + // Copy all the targets into the LKG directory + jake.mkdirP(Paths.lkg); + expectedFiles.forEach(f => { + let content = fs.readFileSync(f, { encoding: 'utf-8' }); + + // If this is a .d.ts file, run remove-internal on it + if (f.endsWith(".d.ts")) { + content = removeInternal.elide(content).result; + } + + if (f.endsWith(".d.ts") || f.endsWith(".js")) { + // Prepend the copyright header to it + content = copyrightContent + content; + } + + fs.writeFile(path.join(Paths.lkg, path.basename(f)), content, { encoding: 'utf-8' }, (err) => { + if (err) throw err; + }); + }); + + const sizeAfter = getDirSize(Paths.lkg); + if (sizeAfter > (sizeBefore * 1.10)) { + throw new Error("The lib folder increased by 10% or more. This likely indicates a bug."); } - var temp = "temptemp"; - jake.cpR(prefixFile, temp, { silent: true }); - fs.appendFileSync(temp, fs.readFileSync(destinationFile)); - fs.renameSync(temp, destinationFile); -} +}); -// concatenate a list of sourceFiles to a destinationFile -function concatenateFiles(destinationFile, sourceFiles) { - var temp = "temptemp"; - // append all files in sequence - var text = ""; - for (var i = 0; i < sourceFiles.length; i++) { - if (!fs.existsSync(sourceFiles[i])) { - fail(sourceFiles[i] + " does not exist!"); - } - if (i > 0) { text += "\n\n"; } - text += fs.readFileSync(sourceFiles[i]).toString().replace(/\r?\n/g, "\n"); +desc("Runs tslint on the compiler sources. Optional arguments are: f[iles]=regex"); +task(TaskNames.lint, [TaskNames.buildRules], () => { + if (fold.isTravis()) console.log(fold.start("lint")); + function lint(project, cb) { + const fix = process.env.fix || process.env.f; + const cmd = `node node_modules/tslint/bin/tslint --project ${project} --formatters-dir ./built/local/tslint/formatters --format autolinkableStylish${fix ? " --fix" : ""}`; + console.log("Linting: " + cmd); + jake.exec([cmd], cb, /** @type {jake.ExecOptions} */({ interactive: true, windowsVerbatimArguments: true })); } - fs.writeFileSync(temp, text); - // Move the file to the final destination - fs.renameSync(temp, destinationFile); -} + lint("scripts/tslint/tsconfig.json", () => lint("src/tsconfig-base.json", () => { + if (fold.isTravis()) console.log(fold.end("lint")); + complete(); + })); +}); -var useDebugMode = true; -var host = process.env.TYPESCRIPT_HOST || process.env.host || "node"; -var compilerFilename = "tsc.js"; -var LKGCompiler = path.join(LKGDirectory, compilerFilename); -var builtLocalCompiler = path.join(builtLocalDirectory, compilerFilename); +desc("Diffs the compiler baselines using the diff tool specified by the 'DIFF' environment variable"); +task('diff', function () { + var cmd = `"${getDiffTool()} ${Paths.baselines.reference} ${Paths.baselines.local}`; + console.log(cmd); + exec(cmd); +}, { async: true }); -/** - * Compiles a file from a list of sources - * @param {string} outFile the target file name - * @param {string[]} sources an array of the names of the source files - * @param {string[]} prereqs prerequisite tasks to compiling the file - * @param {string[]} prefixes a list of files to prepend to the target file - * @param {boolean} useBuiltCompiler true to use the built compiler, false to use the LKG - * @param {object} [opts] property bag containing auxiliary options - * @param {boolean} [opts.noOutFile] true to compile without using --out - * @param {boolean} [opts.generateDeclarations] true to compile using --declaration - * @param {string} [opts.outDir] value for '--outDir' command line option - * @param {boolean} [opts.keepComments] false to compile using --removeComments - * @param {boolean} [opts.preserveConstEnums] true if compiler should keep const enums in code - * @param {boolean} [opts.noResolve] true if compiler should not include non-rooted files in compilation - * @param {boolean} [opts.stripInternal] true if compiler should remove declarations marked as internal - * @param {boolean} [opts.inlineSourceMap] true if compiler should inline sourceMap - * @param {string[]} [opts.types] array of types to include in compilation - * @param {string} [opts.lib] explicit libs to include. - * @param {function(): void} [callback] a function to execute after the compilation process ends - */ -function compileFile(outFile, sources, prereqs, prefixes, useBuiltCompiler, opts, callback) { - file(outFile, prereqs, function() { - var startCompileTime = mark(); - opts = opts || {}; - var compilerPath = useBuiltCompiler ? builtLocalCompiler : LKGCompiler; - var options = "--noImplicitAny --noImplicitThis --alwaysStrict --noEmitOnError"; - if (opts.types) { - options += " --types " + opts.types.join(","); - } - options += " --pretty"; - // Keep comments when specifically requested - // or when in debug mode. - if (!(opts.keepComments || useDebugMode)) { - options += " --removeComments"; - } +desc("Diffs the RWC baselines using the diff tool specified by the 'DIFF' environment variable"); +task('diff-rwc', function () { + var cmd = `"${getDiffTool()} ${Paths.baselines.referenceRwc} ${Paths.baselines.localRwc}`; + console.log(cmd); + exec(cmd); +}, { async: true }); - if (opts.generateDeclarations) { - options += " --declaration"; - } +desc("Sets the release mode flag"); +task("release", function () { + useDebugMode = false; +}); - if (opts.preserveConstEnums || useDebugMode) { - options += " --preserveConstEnums"; - } +desc("Clears the release mode flag"); +task("setDebugMode", function () { + useDebugMode = true; +}); - if (opts.outDir) { - options += " --outDir " + opts.outDir; - } +desc("Emit the start of the build fold"); +task(TaskNames.buildFoldStart, [], function () { + if (fold.isTravis()) console.log(fold.start("build")); +}); - if (!opts.noOutFile) { - options += " --out " + outFile; - } - else { - options += " --module commonjs"; - } +desc("Emit the end of the build fold"); +task(TaskNames.buildFoldEnd, [], function () { + if (fold.isTravis()) console.log(fold.end("build")); +}); - if (opts.noResolve) { - options += " --noResolve"; - } +desc("Compiles tslint rules to js"); +task(TaskNames.buildRules, [], function () { + tsbuild(ConfigFileFor.lint, undefined, () => complete()); +}, { async: true }); - if (useDebugMode) { - if (opts.inlineSourceMap) { - options += " --inlineSourceMap --inlineSources"; - } - else { - options += " --sourcemap"; - } - } - options += " --newLine LF"; +desc("Cleans the compiler output, declare files, and tests"); +task(TaskNames.clean, function () { + jake.rmRf(Paths.built); +}); - if (opts.stripInternal) { - options += " --stripInternal"; - } - options += " --target es5"; - if (opts.lib) { - options += " --lib " + opts.lib; - } - else { - options += " --lib es5"; - } - options += " --noUnusedLocals --noUnusedParameters --strictNullChecks"; +desc("Generates a diagnostic file in TypeScript based on an input JSON file"); +task(TaskNames.generateDiagnostics, [Paths.diagnosticInformationMap]); - var cmd = host + " " + compilerPath + " " + options + " "; - cmd = cmd + sources.join(" "); - console.log(cmd + "\n"); +task(TaskNames.coreBuild, function () { + tsbuild(ConfigFileFor.all, undefined, () => complete()); +}, { async: true }); +file(Paths.diagnosticMessagesJson); +file(Paths.diagnosticInformationMap, [Paths.diagnosticMessagesJson], function (complete) { + tsbuild("scripts/processDiagnosticMessages.tsconfig.json", /*lkg*/ true, function () { + const cmd = `${host} scripts/processDiagnosticMessages.js ${Paths.diagnosticMessagesJson}`; + console.log(cmd); var ex = jake.createExec([cmd]); // Add listeners for output and error ex.addListener("stdout", function (output) { @@ -267,492 +259,49 @@ function compileFile(outFile, sources, prereqs, prefixes, useBuiltCompiler, opts process.stderr.write(error); }); ex.addListener("cmdEnd", function () { - if (!useDebugMode && prefixes && fs.existsSync(outFile)) { - for (var i in prefixes) { - prependFile(prefixes[i], outFile); - } - } - - if (callback) { - callback(); - } - - measure(startCompileTime); complete(); }); - ex.addListener("error", function () { - fs.unlinkSync(outFile); - fail("Compilation of " + outFile + " unsuccessful"); - measure(startCompileTime); - }); ex.run(); - }, { async: true }); -} - -// Prerequisite task for built directory and library typings -directory(builtLocalDirectory); - -var libraryTargets = libraries.libs.map(function (lib) { - var relativeSources = ["header.d.ts"].concat(libraries.sources && libraries.sources[lib] || [lib + ".d.ts"]); - var relativeTarget = libraries.paths && libraries.paths[lib] || ("lib." + lib + ".d.ts"); - var sources = [copyright].concat(relativeSources.map(s => path.join(libraryDirectory, s))); - var target = path.join(builtLocalDirectory, relativeTarget); - file(target, [builtLocalDirectory].concat(sources), function () { - concatenateFiles(target, sources); }); - return target; -}); - -// Lib target to build the library files -desc("Builds the library targets"); -task("lib", libraryTargets); - - -// Generate diagnostics -var processDiagnosticMessagesJs = path.join(scriptsDirectory, "processDiagnosticMessages.js"); -var processDiagnosticMessagesTs = path.join(scriptsDirectory, "processDiagnosticMessages.ts"); -var processDiagnosticMessagesSources = filesFromConfig("./scripts/processDiagnosticMessages.tsconfig.json"); - -var diagnosticMessagesJson = path.join(compilerDirectory, "diagnosticMessages.json"); -var diagnosticInfoMapTs = path.join(compilerDirectory, "diagnosticInformationMap.generated.ts"); -var generatedDiagnosticMessagesJSON = path.join(compilerDirectory, "diagnosticMessages.generated.json"); -var builtGeneratedDiagnosticMessagesJSON = path.join(builtLocalDirectory, "diagnosticMessages.generated.json"); - -file(processDiagnosticMessagesTs); - -// processDiagnosticMessages script -compileFile(processDiagnosticMessagesJs, - processDiagnosticMessagesSources, - processDiagnosticMessagesSources, - [], - /*useBuiltCompiler*/ false); - -// Localize diagnostics script -var generateLocalizedDiagnosticMessagesJs = path.join(scriptsDirectory, "generateLocalizedDiagnosticMessages.js"); -var generateLocalizedDiagnosticMessagesTs = path.join(scriptsDirectory, "generateLocalizedDiagnosticMessages.ts"); - -file(generateLocalizedDiagnosticMessagesTs); - -compileFile(generateLocalizedDiagnosticMessagesJs, - [generateLocalizedDiagnosticMessagesTs], - [generateLocalizedDiagnosticMessagesTs], - [], - /*useBuiltCompiler*/ false, { noOutFile: true, types: ["node", "xml2js"] }); - -// Localize diagnostics -file(generatedLCGFile, [generateLocalizedDiagnosticMessagesJs, diagnosticInfoMapTs, generatedDiagnosticMessagesJSON], function () { - var cmd = host + " " + generateLocalizedDiagnosticMessagesJs + " " + lclDirectory + " " + builtLocalDirectory + " " + generatedDiagnosticMessagesJSON; - console.log(cmd); - var ex = jake.createExec([cmd]); - // Add listeners for output and error - ex.addListener("stdout", function (output) { - process.stdout.write(output); - }); - ex.addListener("stderr", function (error) { - process.stderr.write(error); - }); - ex.addListener("cmdEnd", function () { - complete(); - }); - ex.run(); }, { async: true }); -task("localize", [generatedLCGFile]); - -var buildProtocolTs = path.join(scriptsDirectory, "buildProtocol.ts"); -var buildProtocolJs = path.join(scriptsDirectory, "buildProtocol.js"); -var buildProtocolDts = path.join(builtLocalDirectory, "protocol.d.ts"); -var typescriptServicesDts = path.join(builtLocalDirectory, "typescriptServices.d.ts"); - -file(buildProtocolTs); - -compileFile(buildProtocolJs, - [buildProtocolTs], - [buildProtocolTs], - [], - /*useBuiltCompiler*/ false, - { noOutFile: true, lib: "es6" }); - -file(buildProtocolDts, [buildProtocolTs, buildProtocolJs, typescriptServicesDts], function() { - - var protocolTs = path.join(serverDirectory, "protocol.ts"); - - var cmd = host + " " + buildProtocolJs + " "+ protocolTs + " " + typescriptServicesDts + " " + buildProtocolDts; - console.log(cmd); - var ex = jake.createExec([cmd]); - // Add listeners for output and error - ex.addListener("stdout", function (output) { - process.stdout.write(output); - }); - ex.addListener("stderr", function (error) { - process.stderr.write(error); - }); - ex.addListener("cmdEnd", function () { - complete(); - }); - ex.run(); -}, { async: true }); - -// The generated diagnostics map; built for the compiler and for the 'generate-diagnostics' task -file(diagnosticInfoMapTs, [processDiagnosticMessagesJs, diagnosticMessagesJson], function () { - var cmd = host + " " + processDiagnosticMessagesJs + " " + diagnosticMessagesJson; - console.log(cmd); - var ex = jake.createExec([cmd]); - // Add listeners for output and error - ex.addListener("stdout", function (output) { - process.stdout.write(output); - }); - ex.addListener("stderr", function (error) { - process.stderr.write(error); - }); - ex.addListener("cmdEnd", function () { - complete(); - }); - ex.run(); -}, { async: true }); - -file(builtGeneratedDiagnosticMessagesJSON, [generatedDiagnosticMessagesJSON], function () { - if (fs.existsSync(builtLocalDirectory)) { - jake.cpR(generatedDiagnosticMessagesJSON, builtGeneratedDiagnosticMessagesJSON); - } -}); - -desc("Generates a diagnostic file in TypeScript based on an input JSON file"); -task("generate-diagnostics", [diagnosticInfoMapTs]); - -// Publish nightly -var configurePrereleaseJs = path.join(scriptsDirectory, "configurePrerelease.js"); -var configurePrereleaseTs = path.join(scriptsDirectory, "configurePrerelease.ts"); -var packageJson = "package.json"; -var versionFile = path.join(compilerDirectory, "core.ts"); - -file(configurePrereleaseTs); - -compileFile(/*outfile*/configurePrereleaseJs, - /*sources*/[configurePrereleaseTs], - /*prereqs*/[configurePrereleaseTs], - /*prefixes*/[], - /*useBuiltCompiler*/ false, - { noOutFile: true, generateDeclarations: false, keepComments: false, noResolve: false, stripInternal: false }); - -task("setDebugMode", function () { - useDebugMode = true; -}); - -task("configure-nightly", [configurePrereleaseJs], function () { - var cmd = host + " " + configurePrereleaseJs + " dev " + packageJson + " " + versionFile; - console.log(cmd); - exec(cmd); -}, { async: true }); - -desc("Configure, build, test, and publish the nightly release."); -task("publish-nightly", ["configure-nightly", "LKG", "clean", "setDebugMode", "runtests-parallel"], function () { - var cmd = "npm publish --tag next"; - console.log(cmd); - exec(cmd); -}); - -task("configure-insiders", [configurePrereleaseJs], function () { - var cmd = host + " " + configurePrereleaseJs + " insiders " + packageJson + " " + versionFile; - console.log(cmd); - exec(cmd); -}, { async: true }); - -desc("Configure, build, test, and publish the insiders release."); -task("publish-insiders", ["configure-insiders", "LKG", "clean", "setDebugMode", "runtests-parallel"], function () { - var cmd = "npm publish --tag insiders"; - console.log(cmd); - exec(cmd); -}); - -var importDefinitelyTypedTestsDirectory = path.join(scriptsDirectory, "importDefinitelyTypedTests"); -var importDefinitelyTypedTestsJs = path.join(importDefinitelyTypedTestsDirectory, "importDefinitelyTypedTests.js"); -var importDefinitelyTypedTestsTs = path.join(importDefinitelyTypedTestsDirectory, "importDefinitelyTypedTests.ts"); - -file(importDefinitelyTypedTestsTs); -file(importDefinitelyTypedTestsJs, ["tsd-scripts", importDefinitelyTypedTestsTs], function () { - var cmd = host + " " + LKGCompiler + " -p " + importDefinitelyTypedTestsDirectory; - console.log(cmd); - exec(cmd); -}, { async: true }); - -task("importDefinitelyTypedTests", [importDefinitelyTypedTestsJs], function () { - var cmd = host + " " + importDefinitelyTypedTestsJs + " ./ ../DefinitelyTyped"; - console.log(cmd); - exec(cmd); -}, { async: true }); - -// Local target to build the compiler and services -var tscFile = path.join(builtLocalDirectory, compilerFilename); -compileFile(tscFile, compilerSources, [builtLocalDirectory, copyright].concat(compilerSources), [copyright], /*useBuiltCompiler:*/ false); - -var servicesFile = path.join(builtLocalDirectory, "typescriptServices.js"); -var standaloneDefinitionsFile = path.join(builtLocalDirectory, "typescriptServices.d.ts"); -var nodePackageFile = path.join(builtLocalDirectory, "typescript.js"); -var nodeDefinitionsFile = path.join(builtLocalDirectory, "typescript.d.ts"); -var nodeStandaloneDefinitionsFile = path.join(builtLocalDirectory, "typescript_standalone.d.ts"); - -compileFile(servicesFile, servicesSources, [builtLocalDirectory, copyright].concat(servicesSources), - /*prefixes*/[copyright], - /*useBuiltCompiler*/ true, - /*opts*/ { - noOutFile: false, - generateDeclarations: true, - preserveConstEnums: true, - keepComments: true, - noResolve: false, - stripInternal: true - }, - /*callback*/ function () { - jake.cpR(servicesFile, nodePackageFile, { silent: true }); - - prependFile(copyright, standaloneDefinitionsFile); - - // Stanalone/web definition file using global 'ts' namespace - jake.cpR(standaloneDefinitionsFile, nodeDefinitionsFile, { silent: true }); - var definitionFileContents = fs.readFileSync(nodeDefinitionsFile).toString(); - definitionFileContents = removeConstModifierFromEnumDeclarations(definitionFileContents); - fs.writeFileSync(standaloneDefinitionsFile, definitionFileContents); - - // Official node package definition file, pointed to by 'typings' in package.json - // Created by appending 'export = ts;' at the end of the standalone file to turn it into an external module - var nodeDefinitionsFileContents = definitionFileContents + "\nexport = ts;"; - fs.writeFileSync(nodeDefinitionsFile, nodeDefinitionsFileContents); - - // Node package definition file to be distributed without the package. Created by replacing - // 'ts' namespace with '"typescript"' as a module. - var nodeStandaloneDefinitionsFileContents = definitionFileContents.replace(/declare (namespace|module) ts/g, 'declare module "typescript"'); - fs.writeFileSync(nodeStandaloneDefinitionsFile, nodeStandaloneDefinitionsFileContents); - }); - -file(typescriptServicesDts, [servicesFile]); - -var cancellationTokenFile = path.join(builtLocalDirectory, "cancellationToken.js"); -compileFile(cancellationTokenFile, cancellationTokenSources, [builtLocalDirectory].concat(cancellationTokenSources), /*prefixes*/ [copyright], /*useBuiltCompiler*/ true, { types: ["node"], outDir: builtLocalDirectory, noOutFile: true, lib: "es6" }); - -var typingsInstallerFile = path.join(builtLocalDirectory, "typingsInstaller.js"); -compileFile(typingsInstallerFile, typingsInstallerSources, [builtLocalDirectory].concat(typingsInstallerSources), /*prefixes*/ [copyright], /*useBuiltCompiler*/ true, { types: ["node"], outDir: builtLocalDirectory, noOutFile: false, lib: "es6" }); - -var watchGuardFile = path.join(builtLocalDirectory, "watchGuard.js"); -compileFile(watchGuardFile, watchGuardSources, [builtLocalDirectory].concat(watchGuardSources), /*prefixes*/ [copyright], /*useBuiltCompiler*/ true, { types: ["node"], outDir: builtLocalDirectory, noOutFile: false, lib: "es6" }); - -var serverFile = path.join(builtLocalDirectory, "tsserver.js"); -compileFile(serverFile, serverSources, [builtLocalDirectory, copyright, cancellationTokenFile, typingsInstallerFile, watchGuardFile].concat(serverSources).concat(servicesSources), /*prefixes*/ [copyright], /*useBuiltCompiler*/ true, { types: ["node"], preserveConstEnums: true, lib: "es6" }); -var tsserverLibraryFile = path.join(builtLocalDirectory, "tsserverlibrary.js"); -var tsserverLibraryDefinitionFile = path.join(builtLocalDirectory, "tsserverlibrary.d.ts"); -file(typesMapOutputPath, /** @type {*} */(function() { - var content = fs.readFileSync(path.join(serverDirectory, 'typesMap.json')); +file(Paths.typesMapOutput, /** @type {*} */(function () { + var content = fs.readFileSync(path.join(Paths.srcServer, 'typesMap.json')); // Validate that it's valid JSON try { JSON.parse(content.toString()); } catch (e) { console.log("Parse error in typesMap.json: " + e); } - fs.writeFileSync(typesMapOutputPath, content); + fs.writeFileSync(Paths.typesMapOutput, content); })); -compileFile( - tsserverLibraryFile, - languageServiceLibrarySources, - [builtLocalDirectory, copyright, builtLocalCompiler].concat(languageServiceLibrarySources).concat(libraryTargets), - /*prefixes*/[copyright], - /*useBuiltCompiler*/ true, - { noOutFile: false, generateDeclarations: true, stripInternal: true, preserveConstEnums: true, keepComments: true }, - /*callback*/ function () { - prependFile(copyright, tsserverLibraryDefinitionFile); - // Appending exports at the end of the server library - var tsserverLibraryDefinitionFileContents = - fs.readFileSync(tsserverLibraryDefinitionFile).toString() + - "\nexport = ts;" + - "\nexport as namespace ts;"; - tsserverLibraryDefinitionFileContents = removeConstModifierFromEnumDeclarations(tsserverLibraryDefinitionFileContents); - - fs.writeFileSync(tsserverLibraryDefinitionFile, tsserverLibraryDefinitionFileContents); - }); - -// Local target to build the language service server library -desc("Builds language service server library"); -task("lssl", [tsserverLibraryFile, tsserverLibraryDefinitionFile, typesMapOutputPath]); - -desc("Emit the start of the build fold"); -task("build-fold-start", [], function () { - if (fold.isTravis()) console.log(fold.start("build")); +file(Paths.tsserverLibraryFile, [TaskNames.coreBuild, Paths.copyright, ...libraryTargets], function() { + // fs.writeFileSync(Paths.tsserverLibraryFile, fs.readFileSync(path.join(Paths.builtLocal, "server.js"), { encoding: 'utf-8'})); + fs.writeFileSync(Paths.tsserverLibraryFile, "wat"); }); -desc("Emit the end of the build fold"); -task("build-fold-end", [], function () { - if (fold.isTravis()) console.log(fold.end("build")); +file(Paths.tsserverLibraryDefinitionFile, [TaskNames.coreBuild, Paths.copyright, ...libraryTargets], function () { + const content = fs.readFileSync(Paths.servicesFile, { encoding: 'utf-8' }); + const newContent = + removeConstModifierFromEnumDeclarations(content) + + `\nexport = ts` + + `\nexport as namespace ts;`; + + fs.writeFileSync(Paths.tsserverLibraryDefinitionFile, newContent, { encoding: 'utf-8' }); }); -// Local target to build the compiler and services -desc("Builds the full compiler and services"); -task("local", ["build-fold-start", "generate-diagnostics", "lib", tscFile, servicesFile, nodeDefinitionsFile, serverFile, buildProtocolDts, builtGeneratedDiagnosticMessagesJSON, "lssl", "localize", "build-fold-end"]); - -// Local target to build only tsc.js -desc("Builds only the compiler"); -task("tsc", ["generate-diagnostics", "lib", tscFile]); - -// Local target to build the compiler and services -desc("Sets release mode flag"); -task("release", function () { - useDebugMode = false; -}); - -// Set the default task to "local" -task("default", ["local"]); - -// Cleans the built directory -desc("Cleans the compiler output, declare files, and tests"); -task("clean", function () { - jake.rmRf(builtDirectory); -}); - -// Generate Markdown spec -var word2mdJs = path.join(scriptsDirectory, "word2md.js"); -var word2mdTs = path.join(scriptsDirectory, "word2md.ts"); -var specWord = path.join(docDirectory, "TypeScript Language Specification.docx"); -var specMd = path.join(docDirectory, "spec.md"); - -file(word2mdTs); - -// word2md script -compileFile(word2mdJs, - [word2mdTs], - [word2mdTs], - [], - /*useBuiltCompiler*/ false, - { - lib: "scripthost,es5" +function getLibraryTargets() { + return libraries.libs.map(function (lib) { + var relativeSources = ["header.d.ts"].concat(libraries.sources && libraries.sources[lib] || [lib + ".d.ts"]); + var relativeTarget = libraries.paths && libraries.paths[lib] || ("lib." + lib + ".d.ts"); + var sources = [Paths.copyright].concat(relativeSources.map(s => path.join(Paths.library, s))); + var target = path.join(Paths.builtLocal, relativeTarget); + file(target, [Paths.builtLocal].concat(sources), function () { + concatenateFiles(target, sources); + }); + return target; }); - -// The generated spec.md; built for the 'generate-spec' task -file(specMd, [word2mdJs, specWord], function () { - var specWordFullPath = path.resolve(specWord); - var specMDFullPath = path.resolve(specMd); - var cmd = "cscript //nologo " + word2mdJs + ' "' + specWordFullPath + '" ' + '"' + specMDFullPath + '"'; - console.log(cmd); - child_process.exec(cmd, function () { - complete(); - }); -}, { async: true }); - - -desc("Generates a Markdown version of the Language Specification"); -task("generate-spec", [specMd]); - - -// Makes a new LKG. This target does not build anything, but errors if not all the outputs are present in the built/local directory -desc("Makes a new LKG out of the built js files"); -task("LKG", ["clean", "release", "local"].concat(libraryTargets), () => { - const sizeBefore = getDirSize(LKGDirectory); - var expectedFiles = [tscFile, servicesFile, serverFile, nodePackageFile, nodeDefinitionsFile, standaloneDefinitionsFile, tsserverLibraryFile, tsserverLibraryDefinitionFile, cancellationTokenFile, typingsInstallerFile, buildProtocolDts, watchGuardFile]. - concat(libraryTargets). - concat(localizationTargets); - var missingFiles = expectedFiles.filter(f => !fs.existsSync(f)); - if (missingFiles.length > 0) { - fail(new Error("Cannot replace the LKG unless all built targets are present in directory " + builtLocalDirectory + - ". The following files are missing:\n" + missingFiles.join("\n"))); - } - // Copy all the targets into the LKG directory - jake.mkdirP(LKGDirectory); - expectedFiles.forEach(f => jake.cpR(f, LKGDirectory)); - - const sizeAfter = getDirSize(LKGDirectory); - if (sizeAfter > (sizeBefore * 1.10)) { - throw new Error("The lib folder increased by 10% or more. This likely indicates a bug."); - } -}); - -// Test directory -directory(builtLocalDirectory); - -// Task to build the tests infrastructure using the built compiler -var run = path.join(builtLocalDirectory, "run.js"); -compileFile( - /*outFile*/ run, - /*source*/ harnessSources, - /*prereqs*/[builtLocalDirectory, tscFile, tsserverLibraryFile].concat(libraryTargets).concat(servicesSources).concat(harnessSources), - /*prefixes*/[], - /*useBuiltCompiler:*/ true, - /*opts*/ { types: ["node", "mocha", "chai"], lib: "es6" }); - -var internalTests = "internal/"; - -var localBaseline = "tests/baselines/local/"; -var refBaseline = "tests/baselines/reference/"; - -var localRwcBaseline = path.join(internalTests, "baselines/rwc/local"); -var refRwcBaseline = path.join(internalTests, "baselines/rwc/reference"); - -var localTest262Baseline = path.join(internalTests, "baselines/test262/local"); -var refTest262Baseline = path.join(internalTests, "baselines/test262/reference"); - -desc("Builds the test infrastructure using the built compiler"); -task("tests", ["local", run].concat(libraryTargets)); - -function exec(cmd, completeHandler, errorHandler) { - var ex = jake.createExec([cmd], /** @type {jake.ExecOptions} */({ windowsVerbatimArguments: true, interactive: true })); - // Add listeners for output and error - ex.addListener("stdout", function (output) { - process.stdout.write(output); - }); - ex.addListener("stderr", function (error) { - process.stderr.write(error); - }); - ex.addListener("cmdEnd", function () { - if (completeHandler) { - completeHandler(); - } - complete(); - }); - ex.addListener("error", function (e, status) { - if (errorHandler) { - errorHandler(e, status); - } - else { - fail("Process exited with code " + status); - } - }); - - ex.run(); -} - -const del = require("del"); -function cleanTestDirs() { - // Clean the local baselines directory - if (fs.existsSync(localBaseline)) { - del.sync(localBaseline); - } - - // Clean the local Rwc baselines directory - if (fs.existsSync(localRwcBaseline)) { - del.sync(localRwcBaseline); - } - - jake.mkdirP(localRwcBaseline); - jake.mkdirP(localTest262Baseline); - jake.mkdirP(localBaseline); -} - -// used to pass data from jake command line directly to run.js -function writeTestConfigFile(tests, runners, light, taskConfigsFolder, workerCount, stackTraceLimit, colors, testTimeout) { - var testConfigContents = JSON.stringify({ - runners: runners ? runners.split(",") : undefined, - test: tests ? [tests] : undefined, - light: light, - workerCount: workerCount, - taskConfigsFolder: taskConfigsFolder, - stackTraceLimit: stackTraceLimit, - noColor: !colors, - timeout: testTimeout - }); - fs.writeFileSync('test.config', testConfigContents); -} - -function deleteTemporaryProjectOutput() { - if (fs.existsSync(path.join(localBaseline, "projectOutput/"))) { - jake.rmRf(path.join(localBaseline, "projectOutput/")); - } } function runConsoleTests(defaultReporter, runInParallel) { @@ -803,7 +352,7 @@ function runConsoleTests(defaultReporter, runInParallel) { // timeout normally isn't necessary but Travis-CI has been timing out on compiler baselines occasionally // default timeout is 2sec which really should be enough, but maybe we just need a small amount longer if (!runInParallel) { - var startTime = mark(); + var startTime = Travis.mark(); var args = []; args.push("-R", reporter); if (tests) { @@ -827,7 +376,7 @@ function runConsoleTests(defaultReporter, runInParallel) { else { args.push("-t", testTimeout); } - args.push(run); + args.push(Paths.builtLocalRun); var cmd = "mocha " + args.join(" "); console.log(cmd); @@ -836,12 +385,12 @@ function runConsoleTests(defaultReporter, runInParallel) { process.env.NODE_ENV = "development"; exec(cmd, function () { process.env.NODE_ENV = savedNodeEnv; - measure(startTime); + Travis.measure(startTime); runLinter(); finish(); }, function (e, status) { process.env.NODE_ENV = savedNodeEnv; - measure(startTime); + Travis.measure(startTime); finish(status); }); @@ -849,15 +398,17 @@ function runConsoleTests(defaultReporter, runInParallel) { else { var savedNodeEnv = process.env.NODE_ENV; process.env.NODE_ENV = "development"; - var startTime = mark(); - exec(host + " " + run, function () { + var startTime = Travis.mark(); + exec(host + " " + Paths.builtLocalRun, function () { process.env.NODE_ENV = savedNodeEnv; - measure(startTime); - runLinter(); + Travis.measure(startTime); + var lint = jake.Task["lint"]; + lint.addListener("complete", () => finish()); + lint.invoke(); finish(); }, function (e, status) { process.env.NODE_ENV = savedNodeEnv; - measure(startTime); + Travis.measure(startTime); finish(status); }); } @@ -885,59 +436,166 @@ function runConsoleTests(defaultReporter, runInParallel) { }); lint.invoke(); } + + // used to pass data from jake command line directly to run.js + function writeTestConfigFile(tests, runners, light, taskConfigsFolder, workerCount, stackTraceLimit, colors, testTimeout) { + var testConfigContents = JSON.stringify({ + runners: runners ? runners.split(",") : undefined, + test: tests ? [tests] : undefined, + light: light, + workerCount: workerCount, + taskConfigsFolder: taskConfigsFolder, + stackTraceLimit: stackTraceLimit, + noColor: !colors, + timeout: testTimeout + }); + fs.writeFileSync('test.config', testConfigContents); + } + + function deleteTemporaryProjectOutput() { + if (fs.existsSync(path.join(Paths.baselines.local, "projectOutput/"))) { + jake.rmRf(path.join(Paths.baselines.local, "projectOutput/")); + } + } } -desc("Runs all the tests in parallel using the built run.js file. Optional arguments are: t[ests]=category1|category2|... d[ebug]=true."); -task("runtests-parallel", ["build-rules", "tests", builtLocalDirectory], function () { - 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 bail=false dirty=false."); -task("runtests", ["build-rules", "tests", builtLocalDirectory], function() { - runConsoleTests('mocha-fivemat-progress-reporter', /*runInParallel*/ false); -}, { async: true }); - -desc("Generates code coverage data via instanbul"); -task("generate-code-coverage", ["tests", builtLocalDirectory], function () { - var testTimeout = process.env.timeout || defaultTestTimeout; - var cmd = 'istanbul cover node_modules/mocha/bin/_mocha -- -R min -t ' + testTimeout + ' ' + run; - console.log(cmd); - exec(cmd); -}, { async: true }); - -// Browser tests -var nodeServerOutFile = "tests/webTestServer.js"; -var nodeServerInFile = "tests/webTestServer.ts"; -compileFile(nodeServerOutFile, [nodeServerInFile], [builtLocalDirectory, tscFile], [], /*useBuiltCompiler:*/ true, { noOutFile: true, lib: "es6" }); - -desc("Runs browserify on run.js to produce a file suitable for running tests in the browser"); -task("browserify", [], function() { - // Shell out to `gulp`, since we do the work to handle sourcemaps correctly w/o inline maps there - var cmd = 'gulp browserify --silent'; - exec(cmd); -}, { async: true }); - -desc("Runs the tests using the built run.js file like 'jake runtests'. Syntax is jake runtests-browser. Additional optional parameters tests=[regex], browser=[chrome|IE]"); -task("runtests-browser", ["browserify", nodeServerOutFile], function () { - cleanTestDirs(); - host = "node"; - var browser = process.env.browser || process.env.b || (os.platform() === "win32" ? "edge" : "chrome"); - var runners = process.env.runners || process.env.runner || process.env.ru; - 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); - } - if (tests || runners || light) { - writeTestConfigFile(tests, runners, light); +function cleanTestDirs() { + // Clean the local baselines directory + if (fs.existsSync(Paths.baselines.local)) { + del.sync(Paths.baselines.local); } - tests = tests ? tests : ''; - var cmd = host + " tests/webTestServer.js " + browser + " " + JSON.stringify(tests); - console.log(cmd); - exec(cmd); -}, { async: true }); + // Clean the local Rwc baselines directory + if (fs.existsSync(Paths.baselines.localRwc)) { + del.sync(Paths.baselines.localRwc); + } + + jake.mkdirP(Paths.baselines.local); + jake.mkdirP(Paths.baselines.localRwc); + jake.mkdirP(Paths.baselines.localTest262); +} + +function tsbuild(tsconfigPath, useLkg = true, done = undefined) { + const startCompileTime = Travis.mark(); + + const compilerPath = useLkg ? Paths.lkgCompiler : Paths.builtLocalCompiler; + const cmd = `${host} ${compilerPath} -b -v ${Array.isArray(tsconfigPath) ? tsconfigPath.join(" ") : tsconfigPath}`; + + var ex = jake.createExec([cmd]); + // Add listeners for output and error + ex.addListener("stdout", function (output) { + process.stdout.write(output); + }); + ex.addListener("stderr", function (error) { + process.stderr.write(error); + }); + ex.addListener("cmdEnd", function () { + Travis.measure(startCompileTime); + done && done(); + }); + ex.addListener("error", function () { + fail(`Compilation of ${tsconfigPath} unsuccessful`); + Travis.measure(startCompileTime); + }); + ex.run(); +} + +const Travis = { + mark() { + if (!fold.isTravis()) return; + var stamp = process.hrtime(); + var id = Math.floor(Math.random() * 0xFFFFFFFF).toString(16); + console.log("travis_time:start:" + id + "\r"); + return { + stamp: stamp, + id: id + }; + }, + measure(marker) { + if (!fold.isTravis()) return; + var diff = process.hrtime(marker.stamp); + var total = [marker.stamp[0] + diff[0], marker.stamp[1] + diff[1]]; + console.log("travis_time:end:" + marker.id + ":start=" + toNs(marker.stamp) + ",finish=" + toNs(total) + ",duration=" + toNs(diff) + "\r"); + } +}; + +function toNs(diff) { + return diff[0] * 1e9 + diff[1]; +} + +function exec(cmd, completeHandler, errorHandler) { + var ex = jake.createExec([cmd], /** @type {jake.ExecOptions} */({ windowsVerbatimArguments: true, interactive: true })); + // Add listeners for output and error + ex.addListener("stdout", function (output) { + process.stdout.write(output); + }); + ex.addListener("stderr", function (error) { + process.stderr.write(error); + }); + ex.addListener("cmdEnd", function () { + if (completeHandler) { + completeHandler(); + } + complete(); + }); + ex.addListener("error", function (e, status) { + if (errorHandler) { + errorHandler(e, status); + } + else { + fail("Process exited with code " + status); + } + }); + + ex.run(); +} + +/** @param jsonPath {string} */ +function readJson(jsonPath) { + const jsonText = fs.readFileSync(jsonPath, "utf8"); + const result = ts.parseConfigFileTextToJson(jsonPath, jsonText); + if (result.error) { + reportDiagnostics([result.error]); + throw new Error("An error occurred during parse."); + } + return result.config; +} + +/** @param diagnostics {ts.Diagnostic[]} */ +function reportDiagnostics(diagnostics) { + console.log(diagnosticsToString(diagnostics, process.stdout.isTTY)); +} + +/** + * @param diagnostics {ts.Diagnostic[]} + * @param [pretty] {boolean} + */ +function diagnosticsToString(diagnostics, pretty) { + const host = { + getCurrentDirectory() { return process.cwd(); }, + getCanonicalFileName(fileName) { return fileName; }, + getNewLine() { return os.EOL; } + }; + return pretty ? ts.formatDiagnosticsWithColorAndContext(diagnostics, host) : + ts.formatDiagnostics(diagnostics, host); +} + +// concatenate a list of sourceFiles to a destinationFile +function concatenateFiles(destinationFile, sourceFiles) { + var temp = "temptemp"; + // append all files in sequence + var text = ""; + for (var i = 0; i < sourceFiles.length; i++) { + if (!fs.existsSync(sourceFiles[i])) { + fail(sourceFiles[i] + " does not exist!"); + } + if (i > 0) { text += "\n\n"; } + text += fs.readFileSync(sourceFiles[i]).toString().replace(/\r?\n/g, "\n"); + } + fs.writeFileSync(temp, text); + // Move the file to the final destination + fs.renameSync(temp, destinationFile); +} function getDiffTool() { var program = process.env['DIFF']; @@ -947,183 +605,6 @@ function getDiffTool() { return program; } -// Baseline Diff -desc("Diffs the compiler baselines using the diff tool specified by the 'DIFF' environment variable"); -task('diff', function () { - var cmd = '"' + getDiffTool() + '" ' + refBaseline + ' ' + localBaseline; - console.log(cmd); - exec(cmd); -}, { async: true }); - -desc("Diffs the RWC baselines using the diff tool specified by the 'DIFF' environment variable"); -task('diff-rwc', function () { - var cmd = '"' + getDiffTool() + '" ' + refRwcBaseline + ' ' + localRwcBaseline; - console.log(cmd); - exec(cmd); -}, { async: true }); - -desc("Builds the test sources and automation in debug mode"); -task("tests-debug", ["setDebugMode", "tests"]); - - -// Makes the test results the new baseline -desc("Makes the most recent test results the new baseline, overwriting the old baseline"); -task("baseline-accept", function () { - acceptBaseline(localBaseline, refBaseline); -}); - -function acceptBaseline(sourceFolder, targetFolder) { - console.log('Accept baselines from ' + sourceFolder + ' to ' + targetFolder); - var deleteEnding = '.delete'; - - acceptBaselineFolder(sourceFolder, targetFolder); - - function acceptBaselineFolder(sourceFolder, targetFolder) { - var files = fs.readdirSync(sourceFolder); - - for (var i in files) { - var filename = files[i]; - var fullLocalPath = path.join(sourceFolder, filename); - var stat = fs.statSync(fullLocalPath); - if (stat.isFile()) { - if (filename.substr(filename.length - deleteEnding.length) === deleteEnding) { - filename = filename.substr(0, filename.length - deleteEnding.length); - fs.unlinkSync(path.join(targetFolder, filename)); - } - else { - var target = path.join(targetFolder, filename); - if (fs.existsSync(target)) { - fs.unlinkSync(target); - } - jake.mkdirP(path.dirname(target)); - fs.renameSync(path.join(sourceFolder, filename), target); - } - } - else if (stat.isDirectory()) { - acceptBaselineFolder(fullLocalPath, path.join(targetFolder, filename)); - } - } - } +function removeConstModifierFromEnumDeclarations(text) { + return text.replace(/^(\s*)(export )?const enum (\S+) {(\s*)$/gm, '$1$2enum $3 {$4'); } - -desc("Makes the most recent rwc test results the new baseline, overwriting the old baseline"); -task("baseline-accept-rwc", function () { - acceptBaseline(localRwcBaseline, refRwcBaseline); -}); - -desc("Makes the most recent test262 test results the new baseline, overwriting the old baseline"); -task("baseline-accept-test262", function () { - acceptBaseline(localTest262Baseline, refTest262Baseline); -}); - - -// Webhost -var webhostPath = "tests/webhost/webtsc.ts"; -var webhostJsPath = "tests/webhost/webtsc.js"; -compileFile(webhostJsPath, [webhostPath], [tscFile, webhostPath].concat(libraryTargets), [], /*useBuiltCompiler*/true); - -desc("Builds the tsc web host"); -task("webhost", [webhostJsPath], function () { - jake.cpR(path.join(builtLocalDirectory, "lib.d.ts"), "tests/webhost/", { silent: true }); -}); - -// Perf compiler -var perftscPath = "tests/perftsc.ts"; -var perftscJsPath = "built/local/perftsc.js"; -compileFile(perftscJsPath, [perftscPath], [tscFile, perftscPath, "tests/perfsys.ts"].concat(libraryTargets), [], /*useBuiltCompiler*/ true); -desc("Builds augmented version of the compiler for perf tests"); -task("perftsc", [perftscJsPath]); - -// Instrumented compiler -var loggedIOpath = harnessDirectory + 'loggedIO.ts'; -var loggedIOJsPath = builtLocalDirectory + 'loggedIO.js'; -file(loggedIOJsPath, [builtLocalDirectory, loggedIOpath], function () { - var temp = builtLocalDirectory + 'temp'; - jake.mkdirP(temp); - var options = "--target es5 --lib es6 --types --outdir " + temp + ' ' + loggedIOpath; - var cmd = host + " " + LKGDirectory + compilerFilename + " " + options + " "; - console.log(cmd + "\n"); - var ex = jake.createExec([cmd]); - ex.addListener("cmdEnd", function () { - fs.renameSync(temp + '/harness/loggedIO.js', loggedIOJsPath); - jake.rmRf(temp); - complete(); - }); - ex.run(); -}, { async: true }); - -var instrumenterPath = harnessDirectory + 'instrumenter.ts'; -var instrumenterJsPath = builtLocalDirectory + 'instrumenter.js'; -compileFile(instrumenterJsPath, [instrumenterPath], [tscFile, instrumenterPath].concat(libraryTargets), [], /*useBuiltCompiler*/ true, { lib: "es6", types: ["node"], noOutFile: true, outDir: builtLocalDirectory }); - -desc("Builds an instrumented tsc.js - run with test=[testname]"); -task('tsc-instrumented', [loggedIOJsPath, instrumenterJsPath, tscFile], function () { - var test = process.env.test || process.env.tests || process.env.t || "iocapture"; - var cmd = host + ' ' + instrumenterJsPath + " record " + test + " " + builtLocalDirectory + compilerFilename; - console.log(cmd); - var ex = jake.createExec([cmd]); - ex.addListener("cmdEnd", function () { - complete(); - }); - ex.run(); -}, { async: true }); - -desc("Updates the sublime plugin's tsserver"); -task("update-sublime", ["local", serverFile], function () { - jake.cpR(serverFile, "../TypeScript-Sublime-Plugin/tsserver/"); - jake.cpR(serverFile + ".map", "../TypeScript-Sublime-Plugin/tsserver/"); -}); - -var tslintRuleDir = "scripts/tslint/rules"; -var tslintRules = fs.readdirSync(tslintRuleDir); -var tslintRulesFiles = tslintRules.map(function (p) { - return path.join(tslintRuleDir, p); -}); -var tslintRulesOutFiles = tslintRules.map(function (p) { - return path.join(builtLocalDirectory, "tslint/rules", p.replace(".ts", ".js")); -}); -var tslintFormattersDir = "scripts/tslint/formatters"; -var tslintFormatters = [ - "autolinkableStylishFormatter", -]; -var tslintFormatterFiles = tslintFormatters.map(function (p) { - return path.join(tslintFormattersDir, p + ".ts"); -}); -var tslintFormattersOutFiles = tslintFormatters.map(function (p) { - return path.join(builtLocalDirectory, "tslint/formatters", p + ".js"); -}); -desc("Compiles tslint rules to js"); -task("build-rules", ["build-rules-start"].concat(tslintRulesOutFiles).concat(tslintFormattersOutFiles).concat(["build-rules-end"])); -tslintRulesFiles.forEach(function (ruleFile, i) { - compileFile(tslintRulesOutFiles[i], [ruleFile], [ruleFile], [], /*useBuiltCompiler*/ false, - { noOutFile: true, generateDeclarations: false, outDir: path.join(builtLocalDirectory, "tslint/rules"), lib: "es6" }); -}); -tslintFormatterFiles.forEach(function (ruleFile, i) { - compileFile(tslintFormattersOutFiles[i], [ruleFile], [ruleFile], [], /*useBuiltCompiler*/ false, - { noOutFile: true, generateDeclarations: false, outDir: path.join(builtLocalDirectory, "tslint/formatters"), lib: "es6" }); -}); - -desc("Emit the start of the build-rules fold"); -task("build-rules-start", [], function () { - if (fold.isTravis()) console.log(fold.start("build-rules")); -}); - -desc("Emit the end of the build-rules fold"); -task("build-rules-end", [], function () { - if (fold.isTravis()) console.log(fold.end("build-rules")); -}); - -desc("Runs tslint on the compiler sources. Optional arguments are: f[iles]=regex"); -task("lint", ["build-rules"], () => { - if (fold.isTravis()) console.log(fold.start("lint")); - function lint(project, cb) { - const fix = process.env.fix || process.env.f; - const cmd = `node node_modules/tslint/bin/tslint --project ${project} --formatters-dir ./built/local/tslint/formatters --format autolinkableStylish${fix ? " --fix" : ""}`; - console.log("Linting: " + cmd); - jake.exec([cmd], cb, /** @type {jake.ExecOptions} */({ interactive: true, windowsVerbatimArguments: true })); - } - lint("scripts/tslint/tsconfig.json", () => lint("src/tsconfig-base.json", () => { - if (fold.isTravis()) console.log(fold.end("lint")); - complete(); - })); -}); diff --git a/src/compiler/program.ts b/src/compiler/program.ts index b08f966864a..856f9580f0e 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -349,7 +349,7 @@ namespace ts { output += host.getNewLine(); } - return output + host.getNewLine(); + return output; } export function flattenDiagnosticMessageText(messageText: string | DiagnosticMessageChain | undefined, newLine: string): string { diff --git a/src/compiler/resolutionCache.ts b/src/compiler/resolutionCache.ts index 4614c3bede4..de84b9bb665 100644 --- a/src/compiler/resolutionCache.ts +++ b/src/compiler/resolutionCache.ts @@ -33,10 +33,10 @@ namespace ts { resolvedFileName: string | undefined; } - interface CachedResolvedModuleWithFailedLookupLocations extends ts.ResolvedModuleWithFailedLookupLocations, ResolutionWithFailedLookupLocations { + interface CachedResolvedModuleWithFailedLookupLocations extends ResolvedModuleWithFailedLookupLocations, ResolutionWithFailedLookupLocations { } - interface ResolvedTypeReferenceDirectiveWithFailedLookupLocations extends ts.ResolvedTypeReferenceDirectiveWithFailedLookupLocations, ResolutionWithFailedLookupLocations { + interface CachedResolvedTypeReferenceDirectiveWithFailedLookupLocations extends ResolvedTypeReferenceDirectiveWithFailedLookupLocations, ResolutionWithFailedLookupLocations { } export interface ResolutionCacheHost extends ModuleResolutionHost { @@ -95,8 +95,8 @@ namespace ts { resolutionHost.getCanonicalFileName ); - const resolvedTypeReferenceDirectives = createMap>(); - const perDirectoryResolvedTypeReferenceDirectives = createMap>(); + const resolvedTypeReferenceDirectives = createMap>(); + const perDirectoryResolvedTypeReferenceDirectives = createMap>(); /** * These are the extensions that failed lookup files will have by default, @@ -137,7 +137,7 @@ namespace ts { return resolution.resolvedModule; } - function getResolvedTypeReferenceDirective(resolution: ResolvedTypeReferenceDirectiveWithFailedLookupLocations) { + function getResolvedTypeReferenceDirective(resolution: CachedResolvedTypeReferenceDirectiveWithFailedLookupLocations) { return resolution.resolvedTypeReferenceDirective; } @@ -319,7 +319,7 @@ namespace ts { } function resolveTypeReferenceDirectives(typeDirectiveNames: string[], containingFile: string): ResolvedTypeReferenceDirective[] { - return resolveNamesWithLocalCache( + return resolveNamesWithLocalCache( typeDirectiveNames, containingFile, resolvedTypeReferenceDirectives, perDirectoryResolvedTypeReferenceDirectives, resolveTypeReferenceDirective, getResolvedTypeReferenceDirective, diff --git a/src/core/core.ts b/src/core/core.ts index 4797f3f085b..20a4677d672 100644 --- a/src/core/core.ts +++ b/src/core/core.ts @@ -62,7 +62,7 @@ namespace ts { export interface Push { push(...values: T[]): void; } - + /** Create a MapLike with good performance. */ function createDictionaryObject(): MapLike { const map = Object.create(/*prototype*/ null); // tslint:disable-line:no-null-keyword diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts index 86c83bd73e2..8045f3a948b 100644 --- a/src/harness/fourslash.ts +++ b/src/harness/fourslash.ts @@ -9,8 +9,7 @@ namespace FourSlash { ShimsWithPreprocess, Server } - - + // Represents a parsed source file with metadata interface FourSlashFile { // The contents of the file (with markers, etc stripped out) diff --git a/src/harness/harness.ts b/src/harness/harness.ts index f86892648c1..7a3019d9b36 100644 --- a/src/harness/harness.ts +++ b/src/harness/harness.ts @@ -7,7 +7,7 @@ var assert: typeof _chai.assert = _chai.assert; { // chai's builtin `assert.isFalse` is featureful but slow - we don't use those features, // so we'll just overwrite it as an alterative to migrating a bunch of code off of chai - assert.isFalse = (expr, msg) => { if (expr as any as boolean !== false) throw new Error(msg); }; + assert.isFalse = (expr: any, msg: string) => { if (expr !== false) throw new Error(msg); }; const assertDeepImpl = assert.deepEqual; assert.deepEqual = (a, b, msg) => { diff --git a/src/parser/utilities.ts b/src/parser/utilities.ts index 52e81dd517c..83e56d81631 100644 --- a/src/parser/utilities.ts +++ b/src/parser/utilities.ts @@ -6818,7 +6818,7 @@ namespace ts { lastChain.next = tailChain; return headChain; - } + } function getDiagnosticFilePath(diagnostic: Diagnostic): string | undefined { return diagnostic.file ? diagnostic.file.path : undefined; @@ -6924,12 +6924,6 @@ namespace ts { return true; } - - - // - // Paths - // - /** * Internally, we represent paths as strings with '/' as the directory separator. * When we make system calls (eg: LanguageServiceHost.getDirectory()), @@ -6938,7 +6932,6 @@ namespace ts { export const directorySeparator = "/"; const altDirectorySeparator = "\\"; const urlSchemeSeparator = "://"; - const backslashRegExp = /\\/g; /** diff --git a/src/server/tsconfig.json b/src/server/tsconfig.json index 5339673cb9e..2448371dc3e 100644 --- a/src/server/tsconfig.json +++ b/src/server/tsconfig.json @@ -2,7 +2,7 @@ "extends": "../tsconfig-base", "compilerOptions": { "removeComments": true, - "outFile": "../../built/local/tsserverlibrary.js", + "outFile": "../../built/local/server.js", "preserveConstEnums": true, "types": [ "node"