diff --git a/README.md b/README.md index 95d2d78f4..8f558ed5d 100644 --- a/README.md +++ b/README.md @@ -4,9 +4,9 @@ This tool is used to generate the web-based `lib.dom.d.ts` file which is include ## Why is my fancy API still not available here? -A feature needs to be supported by more than two major browser engines to be included here, to make sure there is a good consensus among vendors: __Gecko__ (Firefox), __Blink__ (Chrome/Edge), and __WebKit__ (Safari). +A feature needs to be supported by two or more major browser engines to be included here, to make sure there is a good consensus among vendors: __Gecko__ (Firefox), __Blink__ (Chrome/Edge), and __WebKit__ (Safari). -If the condition is met but still is not available here, please [file an issue](hthttps://github.com/microsoft/TypeScript-DOM-lib-generator/issues/new). +If the condition is met but still is not available here, first check the heuristics below and then please [file an issue](hthttps://github.com/microsoft/TypeScript-DOM-lib-generator/issues/new). ## Build Instructions @@ -28,13 +28,13 @@ To test: npm run test ``` -To deploy: -```sh -npm run migrate -``` +## `@types/[lib]` to TypeScript Versions -The script will look in for a clone of the TypeScript repo in "../TypeScript", or "./TypeScript" to move the generated files in. +| `@types/[lib]` version | TypeScript Version | Minimum TypeScript Support | +| ---------------------------------------------------------------------- | ----------- | -------------- | +| `@types/web` [0.0.1](https://www.npmjs.com/package/@types/web/v/0.0.1) | ~4.3 | 4.4 | +| `@types/web` [0.0.2](https://www.npmjs.com/package/@types/web/v/0.0.2) | ~4.4 beta | 4.4 | ## Contribution Guidelines @@ -116,3 +116,26 @@ To give you a sense of whether we will accept changes, you can use these heurist - `removedTypes.json`: types that are defined in the spec file but should be removed. - `comments.json`: comment strings to be embedded in the generated .js files. - `deprecatedMessage.json`: the reason why one type is deprecated. The reason why it is a separate file rather than merge in comment.json is mdn/apiDescriptions.json would also possibly be deprecated. + +## Deployment to TypeScript + +To migrate the *.d.ts files into TypeScript: + +1. Run: + + ```sh + npm run migrate -- [previous_types_web_version] + ``` + + The script will look in for a clone of the TypeScript repo in "../TypeScript", or "./TypeScript" to move the generated files in. Or migrate the files manually, you do you. + +1. Update the README table with the mappings for versions in the `@types/[lib]`. E.g. TS 4.5 -> `@types/web` `0.0.23`. + +1. Generate a CHANGELOG for the releases: + + ```sh + # lib from to + npm run ts-changelog -- @types/web 0.0.2 0.0.23 + ``` + +1. Add the CHANGELOG to the release issue diff --git a/deploy/createTypesPackages.mjs b/deploy/createTypesPackages.mjs index 857389878..292b0e9c3 100644 --- a/deploy/createTypesPackages.mjs +++ b/deploy/createTypesPackages.mjs @@ -3,7 +3,7 @@ // node deploy/createTypesPackages.mjs // prettier-ignore -const packages = [ +export const packages = [ { name: "@types/web", description: "Types for the DOM, and other web technologies in browsers", @@ -71,8 +71,6 @@ const go = async () => { } }; -go(); - async function updatePackageJSON(packagePath, pkg, gitSha) { const pkgJSONPath = join(packagePath, "package.json"); const packageText = fs.readFileSync(pkgJSONPath, "utf8"); @@ -131,3 +129,7 @@ function copyREADME(pkg, pkgJSON, writePath) { fs.writeFileSync(writePath, readme); } + +if (process.argv[1] === fileURLToPath(import.meta.url)) { + go(); +} diff --git a/deploy/deployChangedPackages.mjs b/deploy/deployChangedPackages.mjs index cba5fca87..2c463c53e 100644 --- a/deploy/deployChangedPackages.mjs +++ b/deploy/deployChangedPackages.mjs @@ -6,12 +6,13 @@ // ones which have changed. import * as fs from "fs"; -import { join, dirname } from "path"; +import { join, dirname, basename } from "path"; import { fileURLToPath } from "url"; -import fetch from "node-fetch"; -import { spawnSync } from "child_process"; +import { spawnSync, execSync } from "child_process"; import { Octokit } from "@octokit/core"; import printDiff from "print-diff"; +import { generateChangelogFrom } from "../lib/changelog.js"; +import { packages } from "./createTypesPackages.mjs"; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore @@ -26,6 +27,9 @@ const verify = () => { ); }; +const gitShowFile = (commitish, path) => + execSync(`git show "${commitish}":${path}`, { encoding: "utf-8" }); + const go = async () => { verify(); @@ -40,28 +44,51 @@ const go = async () => { const newTSConfig = fs.readFileSync(localPackageJSONPath, "utf-8"); const pkgJSON = JSON.parse(newTSConfig); + // We'll need to map back from the filename in the npm package to the + // generated file in baselines inside the git tag + const thisPackageMeta = packages.find((p) => p.name === pkgJSON.name); + const dtsFiles = fs .readdirSync(join(generatedDir, dirName)) .filter((f) => f.endsWith(".d.ts")); + /** @type {string[]} */ + let releaseNotes = []; + // Look through each .d.ts file included in a package to // determine if anything has changed let upload = false; for (const file of dtsFiles) { + const originalFilename = basename( + thisPackageMeta.files.find((f) => f.to === file).from + ); + const generatedDTSPath = join(generatedDir, dirName, file); const generatedDTSContent = fs.readFileSync(generatedDTSPath, "utf8"); - const unpkgURL = `https://unpkg.com/${pkgJSON.name}/${file}`; + + // This assumes we'll only _ever_ ship patches, which may change in the + // future someday. + const [maj, min, patch] = pkgJSON.version.split("."); + const olderVersion = `${maj}.${min}.${patch - 1}`; + try { - const npmDTSReq = await fetch(unpkgURL); - const npmDTSText = await npmDTSReq.text(); - console.log(`Comparing ${file} from unpkg, to generated version:`); - printDiff(npmDTSText, generatedDTSContent); + const oldFile = gitShowFile( + `${pkgJSON.name}@${olderVersion}`, + `baselines/${originalFilename}` + ); + console.log(`Comparing ${file} from ${olderVersion}, to now:`); + printDiff(oldFile, generatedDTSContent); + + const title = `\n## \`${file}\`\n`; + const notes = generateChangelogFrom(oldFile, generatedDTSContent); + releaseNotes.push(title); + releaseNotes.push(notes.trim() === "" ? "No changes" : notes); - upload = upload || npmDTSText !== generatedDTSContent; + upload = upload || oldFile !== generatedDTSContent; } catch (error) { // Could not find a previous build console.log(` -Could not get the file ${file} inside the npm package ${pkgJSON.name} from unpkg at ${unpkgURL} +Could not get the file ${file} inside the npm package ${pkgJSON.name} from tag ${olderVersion}. Assuming that this means we need to upload this package.`); upload = true; } @@ -93,8 +120,10 @@ Assuming that this means we need to upload this package.`); uploaded.push(dirName); } - } + console.log("\n# Release notes:"); + console.log(releaseNotes.join("\n"), "\n\n"); + } // Warn if we did a dry run. if (!process.env.NODE_AUTH_TOKEN) { console.log( @@ -109,7 +138,7 @@ Assuming that this means we need to upload this package.`); } }; -async function createRelease(tag) { +async function createRelease(tag, body) { const authToken = process.env.GITHUB_TOKEN || process.env.GITHUB_API_TOKEN; const octokit = new Octokit({ auth: authToken }); @@ -119,6 +148,8 @@ async function createRelease(tag) { repo: "TypeScript-DOM-lib-generator", tag_name: tag, target_commitish: process.env.GITHUB_SHA, + name: tag, + body, }); } catch (error) { console.error( diff --git a/src/migrate.ts b/deploy/migrate.mjs similarity index 96% rename from src/migrate.ts rename to deploy/migrate.mjs index e312914a7..0433d8884 100644 --- a/src/migrate.ts +++ b/deploy/migrate.mjs @@ -16,6 +16,7 @@ if (!tscWD) const generatedFiles = readdirSync("generated"); generatedFiles.forEach((file) => { + if (file == ".DS_Store") return; const contents = readFileSync(join("generated", file), "utf8"); const newFilePath = join(tscWD, "src", "lib", file); writeFileSync(newFilePath, contents); diff --git a/deploy/versionChangelog.mjs b/deploy/versionChangelog.mjs new file mode 100644 index 000000000..3a652c463 --- /dev/null +++ b/deploy/versionChangelog.mjs @@ -0,0 +1,39 @@ +// @ts-check + +// npm run ts-changelog @types/web 0.0.1 0.0.3 + +import { generateChangelogFrom } from "../lib/changelog.js"; +import { packages } from "./createTypesPackages.mjs"; +import { execSync } from "child_process"; +import { basename } from "path"; + +const [name, before, to] = process.argv.slice(2); +if (!name || !before || !to) { + throw new Error( + "Expected three arguments: package name, version before, version to" + ); +} + +const go = () => { + // We'll need to map back from the filename in the npm package to the + // generated file in baselines inside the git tag + const thisPackageMeta = packages.find((p) => p.name === name); + if (!thisPackageMeta) + throw new Error(`Could not find ${name} in ${packages.map((p) => p.name)}`); + + for (const file of thisPackageMeta.files) { + const filename = `baselines/${basename(file.from)}`; + const beforeFileText = gitShowFile(`${name}@${before}`, filename); + const toFileText = gitShowFile(`${name}@${to}`, filename); + + const notes = generateChangelogFrom(beforeFileText, toFileText); + + console.log(`\n## \`${file.to}\`\n`); + console.log(notes.trim() === "" ? "No changes" : notes); + } +}; + +const gitShowFile = (commitish, path) => + execSync(`git show "${commitish}":${path}`, { encoding: "utf-8" }); + +go(); diff --git a/package.json b/package.json index 0ef23b783..a16767d1d 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,8 @@ "lint": "eslint --max-warnings 0 src", "test": "npm run lint && npm run build && node ./lib/test.js && node ./unittests/index.js", "changelog": "tsc && node ./lib/changelog.js", - "migrate": "node ./lib/migrate.js", + "ts-changelog": "node ./deploy/versionChangelog.mjs", + "migrate": "node ./deploy/migrate.mjs", "version": "npm i && tsc && node ./lib/version.js" }, "author": { diff --git a/src/changelog.ts b/src/changelog.ts index 880aed8fa..194012775 100644 --- a/src/changelog.ts +++ b/src/changelog.ts @@ -137,10 +137,21 @@ function writeAddedRemovedInline(added: Set, removed: Set) { const dom = "baselines/dom.generated.d.ts"; -export function generate(): string { +export function generateDefaultFromRecentTag(): string { const [base = gitLatestTag(), head = "HEAD"] = process.argv.slice(2); const previous = gitShowFile(base, dom); const current = gitShowFile(head, dom); + const changelog = generateChangelogFrom(previous, current); + if (!changelog.length) { + throw new Error(`No change reported between ${base} and ${head}.`); + } + return changelog; +} + +export function generateChangelogFrom( + previous: string, + current: string +): string { const { interfaces: { added, removed, modified }, others, @@ -150,6 +161,7 @@ export function generate(): string { if (added.size || removed.size) { outputs.push(writeAddedRemoved(added, removed)); } + if (modified.size) { const modifiedOutput = [`## Modified\n`]; for (const [key, value] of modified.entries()) { @@ -169,14 +181,9 @@ export function generate(): string { } const output = outputs.join("\n\n"); - - if (!output.length) { - throw new Error(`No change reported between ${base} and ${head}.`); - } - return output; } if (process.argv[1] === fileURLToPath(import.meta.url)) { - console.log(generate()); + console.log(generateDefaultFromRecentTag()); } diff --git a/src/version.ts b/src/version.ts index 04556224f..261f14a4e 100644 --- a/src/version.ts +++ b/src/version.ts @@ -1,8 +1,8 @@ import { execSync } from "child_process"; import { readFile, writeFile } from "fs/promises"; -import { generate } from "./changelog.js"; +import { generateDefaultFromRecentTag } from "./changelog.js"; -const output = generate(); +const output = generateDefaultFromRecentTag(); const path = new URL("../CHANGELOG.md", import.meta.url);