diff --git a/packages/header-parser/package.json b/packages/header-parser/package.json index 7e96ad3ec8..aece84eef9 100644 --- a/packages/header-parser/package.json +++ b/packages/header-parser/package.json @@ -21,6 +21,7 @@ "url": "https://github.com/DefinitelyTyped/DefinitelyTyped-tools/issues" }, "dependencies": { + "@definitelytyped/utils": "^1.0.0", "@types/parsimmon": "^1.10.1", "parsimmon": "^1.13.0" } diff --git a/packages/header-parser/src/index.ts b/packages/header-parser/src/index.ts index 47f77d5451..9725504d46 100644 --- a/packages/header-parser/src/index.ts +++ b/packages/header-parser/src/index.ts @@ -1,5 +1,5 @@ -import assert = require("assert"); import pm = require("parsimmon"); +import { AllTypeScriptVersion, TypeScriptVersion } from "@definitelytyped/utils"; /* Example: @@ -10,75 +10,6 @@ Example: // TypeScript Version: 2.1 */ -/** Parseable but unsupported TypeScript versions. */ -export type UnsupportedTypeScriptVersion = - | "2.0" | "2.1" | "2.2" | "2.3" | "2.4" | "2.5" | "2.6" | "2.7"; -/** - * Parseable and supported TypeScript versions. - * Only add to this list if we will support this version on DefinitelyTyped. - */ -export type TypeScriptVersion = - | "2.8" | "2.9" - | "3.0" | "3.1" | "3.2" | "3.3" | "3.4" | "3.5" | "3.6" | "3.7" | "3.8" | "3.9"; -export type AllTypeScriptVersion = UnsupportedTypeScriptVersion | TypeScriptVersion; -export namespace TypeScriptVersion { - export const supported: readonly TypeScriptVersion[] = - ["2.8", "2.9", - "3.0", "3.1", "3.2", "3.3", "3.4", "3.5", "3.6", "3.7", "3.8", "3.9"]; - export const unsupported: readonly UnsupportedTypeScriptVersion[] = - ["2.0", "2.1", "2.2", "2.3", "2.4", "2.5", "2.6", "2.7"]; - export const all: readonly AllTypeScriptVersion[] = [...unsupported, ...supported]; - export const lowest = supported[0]; - /** Latest version that may be specified in a `// TypeScript Version:` header. */ - export const latest = supported[supported.length - 1]; - - /** @deprecated */ - export function isPrerelease(_version: TypeScriptVersion): boolean { - return false; - } - - export function isSupported(v: AllTypeScriptVersion): v is TypeScriptVersion { - return supported.indexOf(v as TypeScriptVersion) > -1; - } - - export function range(min: TypeScriptVersion): ReadonlyArray { - return supported.filter(v => v >= min); - } - - const supportedTags: readonly string[] = [ - "ts2.8", - "ts2.9", - "ts3.0", - "ts3.1", - "ts3.2", - "ts3.3", - "ts3.4", - "ts3.5", - "ts3.6", - "ts3.7", - "ts3.8", - "ts3.9", - "latest", - ]; - - /** List of NPM tags that should be changed to point to the latest version. */ - export function tagsToUpdate(v: TypeScriptVersion): ReadonlyArray { - const idx = supportedTags.indexOf(`ts${v}`); - assert(idx !== -1); - return supportedTags.slice(idx); - } - - export function previous(v: TypeScriptVersion): TypeScriptVersion | undefined { - const index = supported.indexOf(v); - assert(index !== -1); - return index === 0 ? undefined : supported[index - 1]; - } - - export function isRedirectable(v: TypeScriptVersion): boolean { - return all.indexOf(v) >= all.indexOf("3.1"); - } -} - export interface Header { readonly nonNpm: boolean; readonly libraryName: string; diff --git a/packages/header-parser/tsconfig.json b/packages/header-parser/tsconfig.json index f7d7c9dc1e..75ffac41a0 100644 --- a/packages/header-parser/tsconfig.json +++ b/packages/header-parser/tsconfig.json @@ -4,6 +4,9 @@ "outDir": "dist", "rootDir": "src" }, - "include": ["src"] + "include": ["src"], + "references": [ + { "path": "../utils" } + ] } \ No newline at end of file diff --git a/packages/publisher/package-lock.json b/packages/publisher/package-lock.json index f60b02eced..e26201975e 100644 --- a/packages/publisher/package-lock.json +++ b/packages/publisher/package-lock.json @@ -2073,7 +2073,7 @@ "json-stable-stringify": "^1.0.1", "strip-json-comments": "^2.0.1", "tslint": "5.14.0", - "typescript": "^3.9.0-dev.20200304", + "typescript": "^3.9.0-dev.20200305", "yargs": "^15.1.0" }, "dependencies": { @@ -9922,9 +9922,9 @@ "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" }, "typescript": { - "version": "3.9.0-dev.20200304", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.0-dev.20200304.tgz", - "integrity": "sha512-eUip/GgJmjp4qtHiJDxVhE5SDDiPzBUg7KBAFUgb7HgL/tv10JAHej7fnS1i+7xrq1eDtbkJyPaYOVnhL9db7Q==" + "version": "3.9.0-dev.20200305", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.0-dev.20200305.tgz", + "integrity": "sha512-O24m5gu1sfYsDWIgWcA2TI2+8Ou1whbjSe9OxSPvyelJB/Vv1SeOo3IGkoudIuvt3SM/Nf34+6HDTy+dga26pA==" }, "underscore": { "version": "1.9.2", diff --git a/packages/publisher/src/tester/test-runner.ts b/packages/publisher/src/tester/test-runner.ts index 141ff91bec..912c1d2c13 100644 --- a/packages/publisher/src/tester/test-runner.ts +++ b/packages/publisher/src/tester/test-runner.ts @@ -20,7 +20,6 @@ import { import { assertDefined, CrashRecoveryState, - exec, execAndThrowErrors, joinPaths, logUncaughtErrors, @@ -31,9 +30,9 @@ import { FS, Semver, npmInstallFlags, - LoggerWithErrors, Logger, flatMapIterable, + installAllTypeScriptVersions, } from "@definitelytyped/utils"; import { allDependencies, getAffectedPackages } from "./get-affected-packages"; @@ -187,7 +186,11 @@ async function doInstalls(allPackages: AllPackages, packages: Iterable e[0]).join(", ")}`); } -interface TesterError { - message: string; -} - -async function runCommand(log: LoggerWithErrors, cwd: string | undefined, cmd: string, args: string[]): Promise { - const nodeCmd = `node ${cmd} ${args.join(" ")}`; - log.info(`Running: ${nodeCmd}`); - try { - const { error, stdout, stderr } = await exec(nodeCmd, cwd); - if (stdout) { - log.info(stdout); - } - if (stderr) { - log.error(stderr); - } - - return error && { message: `${error.message}\n${stdout}\n${stderr}` }; - } catch (e) { - return e as TesterError; - } -} - /** Returns all immediate subdirectories of the root directory that have changed. */ export function gitChanges(diffs: GitDiff[]): PackageId[] { const changedPackages = new Map>(); diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts index 059c5c17da..ca4d30bede 100644 --- a/packages/utils/src/index.ts +++ b/packages/utils/src/index.ts @@ -8,3 +8,4 @@ export * from "./miscellany"; export * from "./process"; export * from "./progress"; export * from "./semver"; +export * from "./typescript-installer"; diff --git a/packages/utils/src/typescript-installer.ts b/packages/utils/src/typescript-installer.ts new file mode 100644 index 0000000000..22306c1587 --- /dev/null +++ b/packages/utils/src/typescript-installer.ts @@ -0,0 +1,152 @@ +import assert = require("assert"); +import { exec } from "child_process"; +import * as fs from "fs-extra"; +import * as os from "os"; +import * as path from "path"; + +const installsDir = path.join(os.homedir(), ".dts", "typescript-installs"); + +/** Parseable but unsupported TypeScript versions. */ +export type UnsupportedTypeScriptVersion = + | "2.0" | "2.1" | "2.2" | "2.3" | "2.4" | "2.5" | "2.6" | "2.7"; +/** + * Parseable and supported TypeScript versions. + * Only add to this list if we will support this version on DefinitelyTyped. + */ +export type TypeScriptVersion = + | "2.8" | "2.9" + | "3.0" | "3.1" | "3.2" | "3.3" | "3.4" | "3.5" | "3.6" | "3.7" | "3.8" | "3.9"; + +export type AllTypeScriptVersion = UnsupportedTypeScriptVersion | TypeScriptVersion; + +export type TsVersion = TypeScriptVersion | "next" | "local"; + +export namespace TypeScriptVersion { + export const supported: readonly TypeScriptVersion[] = + ["2.8", "2.9", + "3.0", "3.1", "3.2", "3.3", "3.4", "3.5", "3.6", "3.7", "3.8", "3.9"]; + export const unsupported: readonly UnsupportedTypeScriptVersion[] = + ["2.0", "2.1", "2.2", "2.3", "2.4", "2.5", "2.6", "2.7"]; + export const all: readonly AllTypeScriptVersion[] = [...unsupported, ...supported]; + export const lowest = supported[0]; + /** Latest version that may be specified in a `// TypeScript Version:` header. */ + export const latest = supported[supported.length - 1]; + + /** @deprecated */ + export function isPrerelease(_version: TypeScriptVersion): boolean { + return false; + } + + export function isSupported(v: AllTypeScriptVersion): v is TypeScriptVersion { + return supported.indexOf(v as TypeScriptVersion) > -1; + } + + export function range(min: TypeScriptVersion): ReadonlyArray { + return supported.filter(v => v >= min); + } + + const supportedTags: readonly string[] = [ + "ts2.8", + "ts2.9", + "ts3.0", + "ts3.1", + "ts3.2", + "ts3.3", + "ts3.4", + "ts3.5", + "ts3.6", + "ts3.7", + "ts3.8", + "ts3.9", + "latest", + ]; + + /** List of NPM tags that should be changed to point to the latest version. */ + export function tagsToUpdate(v: TypeScriptVersion): ReadonlyArray { + const idx = supportedTags.indexOf(`ts${v}`); + assert(idx !== -1); + return supportedTags.slice(idx); + } + + export function previous(v: TypeScriptVersion): TypeScriptVersion | undefined { + const index = supported.indexOf(v); + assert(index !== -1); + return index === 0 ? undefined : supported[index - 1]; + } + + export function isRedirectable(v: TypeScriptVersion): boolean { + return all.indexOf(v) >= all.indexOf("3.1"); + } +} + +export async function installAllTypeScriptVersions() { + for (const v of TypeScriptVersion.supported) { + // manually install typescript@next outside the loop + if (v === TypeScriptVersion.supported[TypeScriptVersion.supported.length - 1]) { continue; } + await install(v); + } + await installTypeScriptNext(); +} + +export async function installTypeScriptNext() { + await install("next"); +} + +async function install(version: TsVersion): Promise { + if (version === "local") { + return; + } + const dir = installDir(version); + if (!await fs.pathExists(dir)) { + console.log(`Installing to ${dir}...`); + await fs.mkdirp(dir); + await fs.writeJson(path.join(dir, "package.json"), packageJson(version)); + await execAndThrowErrors("npm install --ignore-scripts --no-shrinkwrap --no-package-lock --no-bin-links", dir); + console.log("Installed!"); + console.log(""); + } +} + +export function cleanTypeScriptInstalls(): Promise { + return fs.remove(installsDir); +} + +export function typeScriptPath(version: TsVersion, tsLocal: string | undefined): string { + if (version === "local") { + return tsLocal! + "/typescript.js"; + } + return path.join(installDir(version), "node_modules", "typescript"); +} + +function installDir(version: TsVersion): string { + assert(version !== "local"); + return path.join(installsDir, version); +} + +/** Run a command and return the stdout, or if there was an error, throw. */ +async function execAndThrowErrors(cmd: string, cwd?: string): Promise { + return new Promise((resolve, reject) => { + exec(cmd, { encoding: "utf8", cwd }, (err, _stdout, stderr) => { + if (stderr) { + console.error(stderr); + } + + if (err) { + reject(err); + } else { + resolve(); + } + }); + }); +} + +function packageJson(version: TsVersion): {} { + return { + description: `Installs typescript@${version}`, + repository: "N/A", + license: "MIT", + dependencies: { + typescript: version, + }, + }; +}