diff --git a/.dockerignore b/.dockerignore index 1f64bbcee3236..85c3bb869a73f 100644 --- a/.dockerignore +++ b/.dockerignore @@ -22,6 +22,7 @@ scripts/buildProtocol.js scripts/ior.js scripts/authors.js scripts/configurePrerelease.js +scripts/configureTSCBuild.js scripts/open-user-pr.js scripts/open-cherry-pick-pr.js scripts/processDiagnosticMessages.d.ts @@ -45,4 +46,4 @@ TEST-results.xml package-lock.json tests .vscode -.git \ No newline at end of file +.git diff --git a/.gitignore b/.gitignore index 64a6ca01b3a9d..86f344eda49ad 100644 --- a/.gitignore +++ b/.gitignore @@ -45,6 +45,8 @@ scripts/buildProtocol.js scripts/ior.js scripts/authors.js scripts/configurePrerelease.js +scripts/configureLanguageServiceBuild.js +scripts/createLanguageServiceBuild.js scripts/open-user-pr.js scripts/open-cherry-pick-pr.js scripts/processDiagnosticMessages.d.ts @@ -92,4 +94,4 @@ tests/cases/user/webpack/webpack tests/cases/user/puppeteer/puppeteer tests/cases/user/axios-src/axios-src tests/cases/user/prettier/prettier -.eslintcache \ No newline at end of file +.eslintcache diff --git a/.npmignore b/.npmignore index a0769e52a5444..7a8f8d5129113 100644 --- a/.npmignore +++ b/.npmignore @@ -31,4 +31,8 @@ yarn.lock CONTRIBUTING.md TEST-results.xml .dockerignore -Dockerfile \ No newline at end of file +Dockerfile +.DS_Store +.eslintrc.json +.yarnrc +tmp diff --git a/Gulpfile.js b/Gulpfile.js index 20c32e9fc4a61..b5ed366ee64ff 100644 --- a/Gulpfile.js +++ b/Gulpfile.js @@ -590,6 +590,10 @@ const configureExperimental = () => exec(process.execPath, ["scripts/configurePr task("configure-experimental", series(buildScripts, configureExperimental)); task("configure-experimental").description = "Runs scripts/configurePrerelease.ts to prepare a build for experimental publishing"; +const createLanguageServicesBuild = () => exec(process.execPath, ["scripts/createLanguageServicesBuild.js"]); +task("create-language-services-build", series(buildScripts, createLanguageServicesBuild)); +task("create-language-services-build").description = "Runs scripts/createLanguageServicesBuild.ts to prepare a build which only has the require('typescript') JS."; + const publishNightly = () => exec("npm", ["publish", "--tag", "next"]); task("publish-nightly", series(task("clean"), task("LKG"), task("clean"), task("runtests-parallel"), publishNightly)); task("publish-nightly").description = "Runs `npm publish --tag next` to create a new nightly build on npm"; diff --git a/scripts/configureLanguageServiceBuild.ts b/scripts/configureLanguageServiceBuild.ts new file mode 100644 index 0000000000000..d61aeaeec35f3 --- /dev/null +++ b/scripts/configureLanguageServiceBuild.ts @@ -0,0 +1,87 @@ +/// +import { normalize, dirname, join } from "path"; +import { readFileSync, writeFileSync, unlinkSync, existsSync } from "fs"; +import assert = require("assert"); +import { execSync } from "child_process"; +const args = process.argv.slice(2); + +/** + * A minimal description for a parsed package.json object. + */ +interface PackageJson { + name: string; + bin: {}; + main: string; + scripts: { + prepare: string + postpublish: string + } +} + +function main(): void { + if (args.length < 1) { + console.log("Usage:"); + console.log("\tnode configureTSCBuild.js "); + return; + } + + // Acquire the version from the package.json file and modify it appropriately. + const packageJsonFilePath = normalize(args[0]); + const packageJsonValue: PackageJson = JSON.parse(readFileSync(packageJsonFilePath).toString()); + + // Remove the bin section from the current package + delete packageJsonValue.bin; + // We won't be running eslint which would run before publishing + delete packageJsonValue.scripts.prepare; + // No infinite loops + delete packageJsonValue.scripts.postpublish; + + // Set the new name + packageJsonValue.name = "@typescript/language-services"; + + writeFileSync(packageJsonFilePath, JSON.stringify(packageJsonValue, /*replacer:*/ undefined, /*space:*/ 4)); + + // Remove the files which aren't use when just using the API + const toRemove = [ + // JS Files + "tsserver.js", + "tsserverlibrary.js", + "typescriptServices.js", + "typingsInstaller.js", + "tsc.js", + // DTS files + "typescriptServices.d.ts", + "tsserverlibrary.d.ts" + ]; + + // Get a link to the main dependency JS file + const lib = join(dirname(packageJsonFilePath), packageJsonValue.main); + const libPath = dirname(lib); + + // Remove the sibling JS large files referenced above + toRemove.forEach(file => { + const path = join(libPath, file); + if (existsSync(path)) unlinkSync(path); + }); + + // Remove VS-specific localization keys + execSync("rm -rf loc", { cwd: dirname(packageJsonFilePath) }); + + // Remove runnable file reference + execSync("rm -rf bin", { cwd: dirname(packageJsonFilePath) }); + + /////////////////////////////////// + + // This section verifies that the build of TypeScript compiles and emits + + const ts = require(lib); + const source = "let x: string = 'string'"; + + const results = ts.transpileModule(source, { + compilerOptions: { module: ts.ModuleKind.CommonJS } + }); + + assert(results.outputText.trim() === "var x = 'string';", `Running typescript with ${packageJsonValue.name} did not return the expected results, got: ${results.outputText}`); +} + +main(); diff --git a/scripts/createLanguageServiceBuild.ts b/scripts/createLanguageServiceBuild.ts new file mode 100644 index 0000000000000..c870979eb1297 --- /dev/null +++ b/scripts/createLanguageServiceBuild.ts @@ -0,0 +1,46 @@ +/// +import { join } from "path"; +import { readFileSync, unlinkSync } from "fs"; +import { tmpdir } from "os"; +import { execSync, ExecSyncOptions } from "child_process"; +import chalk from "chalk"; + +interface PackageJson { + name: string; + version: string +} + +const exec = (cmd: string, opts?: ExecSyncOptions) => { + console.log(chalk.gray(`> ${cmd} ${opts ? JSON.stringify(opts) : ""}`)); + execSync(cmd, opts); +}; + +const step = (msg: string) => { + console.log("\n\n" + chalk.bold("- ") + msg); +}; + +function main(): void { + console.log(chalk.bold("## Creating the language services build of TypeScript")); + process.stdout.write(chalk.grey("> node /scripts/createLanguageServiceBuild.ts")); + + // Create a tarball of the current version + step("Packing the current TypeScript via npm."); + exec("npm pack"); + + const packageJsonValue: PackageJson = JSON.parse(readFileSync("package.json", "utf8")); + const tarballFileName = `${packageJsonValue.name}-${packageJsonValue.version}.tgz`; + + const unzipDir = tmpdir(); + step(`Extracting the built version into a temporary folder. ${unzipDir}/package`); + exec(`tar -xvzf ${tarballFileName} -C ${unzipDir}`); + unlinkSync(tarballFileName); + + step(`Updating the build metadata`); + const packagePath = join(unzipDir, "package"); + exec(`node scripts/configureLanguageServiceBuild.js ${join(packagePath, "package.json")}`); + + step(`Deploying the language service`); + exec("npm publish --access public", { cwd: packagePath }); +} + +main();