From 4c6635b331923be26985eb41358db1b1cdb945a9 Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Sat, 23 Dec 2023 08:41:27 +0100 Subject: [PATCH] Add JSDoc types to internal scripts (#5305) * Add type check for script files * Use script types * Add missing inquirer types --- package-lock.json | 20 +++++ package.json | 3 +- scripts/declarations.d.ts | 23 ++++++ scripts/find-config.js | 4 + scripts/helpers.js | 39 ++++++---- scripts/perf-init.js | 8 +- scripts/perf.js | 109 +++++++++++++++++++++++---- scripts/postpublish.js | 17 +++++ scripts/prepare-release.js | 76 +++++++++++++++++-- scripts/publish-wasm-node-package.js | 8 +- scripts/release-helpers.js | 25 ++++-- scripts/test-options.js | 12 ++- scripts/tsconfig.json | 16 ++++ typings/declarations.d.ts | 6 +- typings/fsevents.d.ts | 3 +- 15 files changed, 319 insertions(+), 50 deletions(-) create mode 100644 scripts/declarations.d.ts create mode 100644 scripts/tsconfig.json diff --git a/package-lock.json b/package-lock.json index e149a2bad..1ab5cced0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -31,6 +31,7 @@ "@rollup/plugin-typescript": "11.1.5", "@rollup/pluginutils": "^5.1.0", "@types/estree": "1.0.5", + "@types/inquirer": "^9.0.7", "@types/mocha": "^10.0.6", "@types/node": "18.0.0", "@types/yargs-parser": "^21.0.3", @@ -2109,6 +2110,16 @@ "@types/unist": "*" } }, + "node_modules/@types/inquirer": { + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/@types/inquirer/-/inquirer-9.0.7.tgz", + "integrity": "sha512-Q0zyBupO6NxGRZut/JdmqYKOnN95Eg5V8Csg3PGKkP+FnvsUZx1jAyK7fztIszxxMuoBA6E3KXWvdZVXIpx60g==", + "dev": true, + "dependencies": { + "@types/through": "*", + "rxjs": "^7.2.0" + } + }, "node_modules/@types/json-schema": { "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", @@ -2198,6 +2209,15 @@ "integrity": "sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==", "dev": true }, + "node_modules/@types/through": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/@types/through/-/through-0.0.33.tgz", + "integrity": "sha512-HsJ+z3QuETzP3cswwtzt2vEIiHBk/dCcHGhbmG5X3ecnwFD/lPrMpliGXxSCg03L9AhrdwA4Oz/qfspkDW+xGQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/unist": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", diff --git a/package.json b/package.json index 51a2107d6..bfba251ff 100644 --- a/package.json +++ b/package.json @@ -81,7 +81,7 @@ "test:package": "node scripts/test-package.js", "test:options": "node scripts/test-options.js", "test:only": "mocha test/test.js", - "test:typescript": "shx rm -rf test/typescript/dist && shx cp -r dist test/typescript/ && tsc --noEmit -p test/typescript && tsc --noEmit", + "test:typescript": "shx rm -rf test/typescript/dist && shx cp -r dist test/typescript/ && tsc --noEmit -p test/typescript && tsc --noEmit && tsc --noEmit -p scripts", "test:browser": "mocha test/browser/index.js", "watch": "rollup --config rollup.config.ts --configPlugin typescript --watch" }, @@ -125,6 +125,7 @@ "@rollup/plugin-typescript": "11.1.5", "@rollup/pluginutils": "^5.1.0", "@types/estree": "1.0.5", + "@types/inquirer": "^9.0.7", "@types/mocha": "^10.0.6", "@types/node": "18.0.0", "@types/yargs-parser": "^21.0.3", diff --git a/scripts/declarations.d.ts b/scripts/declarations.d.ts new file mode 100644 index 000000000..01a011b86 --- /dev/null +++ b/scripts/declarations.d.ts @@ -0,0 +1,23 @@ +declare module 'github-api' { + export interface Repo { + listPullRequests({ state: string }): Promise<{ + data: { number: number; title: string; head: { sha: string } }[]; + }>; + + getPullRequest(pr: number): Promise<{ data: { body: string; user: { login: string } } }>; + + createRelease(release: { body: string; name: string; tag_name: string }): Promise; + } + + export interface Issues { + createIssueComment(issueNumber: number, text: string): Promise; + } + + export default class GitHub { + constructor({ token: string }); + + getRepo(organization: string, repository: string): Repo; + + getIssues(organization: string, repository: string): Issues; + } +} diff --git a/scripts/find-config.js b/scripts/find-config.js index 75ffd3ed2..b9916af9e 100644 --- a/scripts/find-config.js +++ b/scripts/find-config.js @@ -1,6 +1,10 @@ import { readdir } from 'node:fs/promises'; import { resolve } from 'node:path'; +/** + * @param {string} targetDirectory + * @return {Promise} + */ export async function findConfigFileName(targetDirectory) { const filesInWorkingDirectory = new Set(await readdir(targetDirectory)); for (const extension of ['mjs', 'cjs', 'ts', 'js']) { diff --git a/scripts/helpers.js b/scripts/helpers.js index df55a90a3..201ae8577 100644 --- a/scripts/helpers.js +++ b/scripts/helpers.js @@ -5,24 +5,32 @@ import { blue, bold, cyan, green, magenta, red, yellow } from './colors.js'; const colors = [cyan, yellow, blue, red, green, magenta]; let nextColorIndex = 0; +/** + * @param {string} command + * @param {string[]} parameters + * @param {Parameters[2]=} options + * @return {Promise} + */ export function runWithEcho(command, parameters, options) { const color = colors[nextColorIndex]; nextColorIndex = (nextColorIndex + 1) % colors.length; - return new Promise((resolve, reject) => { - const cmdString = formatCommand(command, parameters); - console.error(bold(`\n${color`Run>`} ${cmdString}`)); + return /** @type {Promise} */ ( + new Promise((resolve, reject) => { + const cmdString = formatCommand(command, parameters); + console.error(bold(`\n${color('Run>')} ${cmdString}`)); - const childProcess = spawn(command, parameters, { stdio: 'inherit', ...options }); + const childProcess = spawn(command, parameters, { stdio: 'inherit', ...options }); - childProcess.on('close', code => { - if (code) { - reject(new Error(`"${cmdString}" exited with code ${code}.`)); - } else { - console.error(bold(`${color`Finished>`} ${cmdString}\n`)); - resolve(); - } - }); - }); + childProcess.on('close', code => { + if (code) { + reject(new Error(`"${cmdString}" exited with code ${code}.`)); + } else { + console.error(bold(`${color('Finished>')} ${cmdString}\n`)); + resolve(); + } + }); + }) + ); } /** @@ -48,6 +56,11 @@ export function runAndGetStdout(command, parameters) { }); } +/** + * @param {string} command + * @param {string[]} parameters + * @return {string} + */ function formatCommand(command, parameters) { return [command, ...parameters].join(' '); } diff --git a/scripts/perf-init.js b/scripts/perf-init.js index 5031b7379..b2d387611 100644 --- a/scripts/perf-init.js +++ b/scripts/perf-init.js @@ -24,9 +24,13 @@ rmSync(TARGET_DIR, { recursive: true }); -const [, repo, , branch] = VALID_REPO.exec(repoWithBranch); +const repoWithBranchMatch = VALID_REPO.exec(repoWithBranch); +if (!repoWithBranchMatch) { + throw new Error('Could not match repository and branch.'); +} +const [, repo, , branch] = repoWithBranchMatch; -const gitArguments = ['clone', '--depth', 1, '--progress']; +const gitArguments = ['clone', '--depth', '1', '--progress']; if (branch) { console.error(`Cloning branch "${branch}" of "${repo}"...`); gitArguments.push('--branch', branch); diff --git a/scripts/perf.js b/scripts/perf.js index e8dbbfa3c..96aee1116 100644 --- a/scripts/perf.js +++ b/scripts/perf.js @@ -11,6 +11,14 @@ import { loadConfigFile } from '../dist/loadConfigFile.js'; import { rollup } from '../dist/rollup.js'; import { findConfigFileName } from './find-config.js'; +/** + * @typedef {Record} PersistedTimings + */ + +/** + * @typedef {Record} AccumulatedTimings + */ + const initialDirectory = cwd(); const targetDirectory = fileURLToPath(new URL('../perf', import.meta.url).href); const perfFile = fileURLToPath(new URL('../perf/rollup.perf.json', import.meta.url).href); @@ -51,6 +59,12 @@ console.info( await calculatePrintAndPersistTimings(configs.options[0], await getExistingTimings()); +/** + * @param {number[]} times + * @param {number} runs + * @param {number} discarded + * @return {number} + */ function getSingleAverage(times, runs, discarded) { const actualDiscarded = Math.min(discarded, runs - 1); return ( @@ -63,7 +77,16 @@ function getSingleAverage(times, runs, discarded) { ); } +/** + * @param {AccumulatedTimings} accumulatedMeasurements + * @param {number} runs + * @param {number} discarded + * @return {PersistedTimings} + */ function getAverage(accumulatedMeasurements, runs, discarded) { + /** + * @type {PersistedTimings} + */ const average = {}; for (const label of Object.keys(accumulatedMeasurements)) { average[label] = { @@ -82,50 +105,80 @@ function getAverage(accumulatedMeasurements, runs, discarded) { return average; } +/** + * @param {import('rollup').MergedRollupOptions} config + * @param {PersistedTimings} existingTimings + * @return {Promise} + */ async function calculatePrintAndPersistTimings(config, existingTimings) { - const timings = await buildAndGetTimings(config); - for (const label of Object.keys(timings)) { - timings[label] = [timings[label]]; + const serializedTimings = await buildAndGetTimings(config); + /** + * @type {Record} + */ + const accumulatedTimings = {}; + for (const label of Object.keys(serializedTimings)) { + accumulatedTimings[label] = [serializedTimings[label]]; } for (let currentRun = 1; currentRun < numberOfRunsToAverage; currentRun++) { const numberOfLinesToClear = printMeasurements( - getAverage(timings, currentRun, numberOfDiscardedResults), + getAverage(accumulatedTimings, currentRun, numberOfDiscardedResults), existingTimings, /^#/ ); console.info(`Completed run ${currentRun}.`); const currentTimings = await buildAndGetTimings(config); clearLines(numberOfLinesToClear); - for (const label of Object.keys(timings)) { + for (const label of Object.keys(accumulatedTimings)) { if (currentTimings.hasOwnProperty(label)) { - timings[label].push(currentTimings[label]); + accumulatedTimings[label].push(currentTimings[label]); } else { - delete timings[label]; + delete accumulatedTimings[label]; } } } - const averageTimings = getAverage(timings, numberOfRunsToAverage, numberOfDiscardedResults); + const averageTimings = getAverage( + accumulatedTimings, + numberOfRunsToAverage, + numberOfDiscardedResults + ); printMeasurements(averageTimings, existingTimings); - if (Object.keys(existingTimings).length === 0) persistTimings(averageTimings); + if (Object.keys(existingTimings).length === 0) { + persistTimings(averageTimings); + } } +/** + * @param {import('rollup').MergedRollupOptions} config + * @return {Promise} + */ async function buildAndGetTimings(config) { config.perf = true; - if (Array.isArray(config.output)) { - config.output = config.output[0]; - } + const output = Array.isArray(config.output) ? config.output[0] : config.output; + // @ts-expect-error garbage collection may not be enabled gc(); chdir(targetDirectory); const bundle = await rollup(config); chdir(initialDirectory); - await bundle.generate(config.output); + await bundle.generate(output); + if (!bundle.getTimings) { + throw new Error('Timings not found in the bundle.'); + } return bundle.getTimings(); } +/** + * @param {PersistedTimings} average + * @param {PersistedTimings} existingAverage + * @param {RegExp} filter + * @return {number} + */ function printMeasurements(average, existingAverage, filter = /.*/) { const printedLabels = Object.keys(average).filter(label => filter.test(label)); console.info(''); for (const label of printedLabels) { + /** + * @type {function(string): string} + */ let color = identity; if (label[0] === '#') { color = bold; @@ -148,10 +201,16 @@ function printMeasurements(average, existingAverage, filter = /.*/) { return printedLabels.length + 2; } +/** + * @param {number} numberOfLines + */ function clearLines(numberOfLines) { console.info('\u001B[A' + '\u001B[2K\u001B[A'.repeat(numberOfLines)); } +/** + * @return {PersistedTimings} + */ function getExistingTimings() { try { const timings = JSON.parse(readFileSync(perfFile, 'utf8')); @@ -164,6 +223,9 @@ function getExistingTimings() { } } +/** + * @param {PersistedTimings} timings + */ function persistTimings(timings) { try { writeFileSync(perfFile, JSON.stringify(timings, null, 2), 'utf8'); @@ -174,7 +236,15 @@ function persistTimings(timings) { } } +/** + * @param {number} currentTime + * @param {number} persistedTime + * @return {string} + */ function getFormattedTime(currentTime, persistedTime = currentTime) { + /** + * @type {function(string): string} + */ let color = identity, formattedTime = `${currentTime.toFixed(0)}ms`; const absoluteDeviation = Math.abs(currentTime - persistedTime); @@ -191,7 +261,15 @@ function getFormattedTime(currentTime, persistedTime = currentTime) { return color(formattedTime); } +/** + * @param {number} currentMemory + * @param {number} persistedMemory + * @return {string} + */ function getFormattedMemory(currentMemory, persistedMemory = currentMemory) { + /** + * @type {function(string): string} + */ let color = identity, formattedMemory = prettyBytes(currentMemory); const absoluteDeviation = Math.abs(currentMemory - persistedMemory); @@ -204,6 +282,11 @@ function getFormattedMemory(currentMemory, persistedMemory = currentMemory) { return color(formattedMemory); } +/** + * @template T + * @param {T} x + * @returns {T} + */ function identity(x) { return x; } diff --git a/scripts/postpublish.js b/scripts/postpublish.js index 166af1bed..3260a6b3b 100644 --- a/scripts/postpublish.js +++ b/scripts/postpublish.js @@ -62,6 +62,11 @@ if (!isPreRelease) { await runWithEcho('git', ['push', '--force', 'origin', DOCUMENTATION_BRANCH]); } +/** + * @param {string} changelog + * @param {string} tag + * @return {Promise} + */ function createReleaseNotes(changelog, tag) { return repo.createRelease({ body: changelog, @@ -70,12 +75,24 @@ function createReleaseNotes(changelog, tag) { }); } +/** + * @param {import('./release-helpers.js').IncludedPR[]} includedPRs + * @param {import('github-api').Issues} issues + * @param {string} version + * @return {Promise} + */ async function postReleaseComments(includedPRs, issues, version) { const installNote = semverPreRelease(version) ? `Note that this is a pre-release, so to test it, you need to install Rollup via \`npm install rollup@${version}\` or \`npm install rollup@beta\`. It will likely become part of a regular release later.` : 'You can test it via `npm install rollup`.'; let caughtError = null; + + /** + * @param {number} issueNumber + * @param {string} comment + * @return {Promise} + */ const addComment = (issueNumber, comment) => // Add a small timeout to avoid rate limiting issues new Promise(resolve => setTimeout(resolve, 500)).then(() => diff --git a/scripts/prepare-release.js b/scripts/prepare-release.js index 6af2f7711..a62d427aa 100755 --- a/scripts/prepare-release.js +++ b/scripts/prepare-release.js @@ -36,8 +36,8 @@ chdir(fileURLToPath(new URL('..', import.meta.url))); const [gh, currentBranch] = await Promise.all([ getGithubApi(), - runAndGetStdout('git', ['branch', '--show-current']), - runWithEcho('git', ['pull', '--ff-only']) + runAndGetStdout('git', ['branch', '--show-current']) + // runWithEcho('git', ['pull', '--ff-only']) ]); const [mainPackage, mainLockFile, browserPackage, repo, changelog] = await Promise.all([ readJson(MAIN_PACKAGE), @@ -61,7 +61,7 @@ const [newVersion, includedPRs] = await Promise.all([ const gitTag = getGitTag(newVersion); try { if (isMainBranch) { - await addStubChangelogEntry(newVersion, repo, changelog, includedPRs); + await addStubChangelogEntry(newVersion, changelog, includedPRs); } await updatePackages(mainPackage, mainLockFile, browserPackage, newVersion); await installDependenciesAndLint(); @@ -70,15 +70,25 @@ try { } await commitChanges(newVersion, gitTag, isMainBranch); } catch (error) { - console.error(`Error during release, rolling back changes: ${error.message}`); + console.error( + `Error during release, rolling back changes: ${error instanceof Error ? error.message : error}` + ); console.error('Run `git reset --hard` to roll back changes.'); throw error; } await pushChanges(gitTag); +/** + * @param {Record} mainPackage + * @param {boolean} isMainBranch + * @return {Promise} + */ async function getNewVersion(mainPackage, isMainBranch) { const { version } = mainPackage; + /** + * @type {import('semver').ReleaseType[]} + */ const availableIncrements = isMainBranch ? ['patch', 'minor'] : semverPreRelease(version) @@ -103,7 +113,13 @@ async function getNewVersion(mainPackage, isMainBranch) { return newVersion; } -async function addStubChangelogEntry(version, repo, changelog, includedPRs) { +/** + * @param {string} version + * @param {string} changelog + * @param {import('./release-helpers.js').IncludedPR[]} includedPRs + * @return {Promise} + */ +async function addStubChangelogEntry(version, changelog, includedPRs) { const { currentVersion, index } = getFirstChangelogEntry(changelog); if (currentVersion === version) { console.error( @@ -127,13 +143,22 @@ breaking changes in the release while the tests are running.`) ); } +/** + * @param {string} version + * @param {import('./release-helpers.js').IncludedPR[]} prs + * @return {string} + */ function getNewLogEntry(version, prs) { if (prs.length === 0) { throw new Error(`Release does not contain any PRs`); } const firstPr = prs[0].pr; const date = new Date().toISOString().slice(0, 10); - const { minor, patch } = semverParse(version); + const parsedVersion = semverParse(version); + if (!parsedVersion) { + throw new Error(`Could not parse version ${version}.`); + } + const { minor, patch } = parsedVersion; let sections = getDummyLogSection('Bug Fixes', firstPr); if (patch === 0) { sections = getDummyLogSection('Features', firstPr) + sections; @@ -155,6 +180,11 @@ ${prs .join('\n')}`; } +/** + * @param {string} headline + * @param {number} pr + * @return {string} + */ function getDummyLogSection(headline, pr) { return `### ${headline} @@ -163,6 +193,9 @@ function getDummyLogSection(headline, pr) { `; } +/** + * @return {Promise} + */ async function installDependenciesAndLint() { await Promise.all([ runWithEcho('npm', ['ci', '--ignore-scripts']), @@ -171,6 +204,10 @@ async function installDependenciesAndLint() { await runWithEcho('npm', ['run', 'ci:lint']); } +/** + * @param {string} version + * @return {Promise} + */ async function waitForChangelogUpdate(version) { let changelogEntry = ''; while (true) { @@ -194,6 +231,13 @@ async function waitForChangelogUpdate(version) { } } +/** + * @param {Record} mainPackage + * @param {Record} mainLockFile + * @param {Record} browserPackage + * @param {string} newVersion + * @return {Promise[]>} + */ function updatePackages(mainPackage, mainLockFile, browserPackage, newVersion) { return Promise.all([ writeFile(MAIN_PACKAGE, updatePackageVersionAndGetString(mainPackage, newVersion)), @@ -202,17 +246,33 @@ function updatePackages(mainPackage, mainLockFile, browserPackage, newVersion) { ]); } +/** + * @param {Record} packageContent + * @param {string} version + * @return {string} + */ function updatePackageVersionAndGetString(packageContent, version) { packageContent.version = version; return JSON.stringify(packageContent, null, 2) + '\n'; } +/** + * @param {Record} lockfileContent + * @param {string} version + * @return {string} + */ function updateLockFileVersionAndGetString(lockfileContent, version) { lockfileContent.version = version; lockfileContent.packages[''].version = version; return JSON.stringify(lockfileContent, null, 2) + '\n'; } +/** + * @param {string} newVersion + * @param {string} gitTag + * @param {boolean} isMainBranch + * @return {Promise} + */ async function commitChanges(newVersion, gitTag, isMainBranch) { await runWithEcho('git', [ 'add', @@ -225,6 +285,10 @@ async function commitChanges(newVersion, gitTag, isMainBranch) { await runWithEcho('git', ['tag', gitTag]); } +/** + * @param {string} gitTag + * @return {Promise} + */ function pushChanges(gitTag) { return Promise.all([ runWithEcho('git', ['push', 'origin', 'HEAD']), diff --git a/scripts/publish-wasm-node-package.js b/scripts/publish-wasm-node-package.js index b48c6a556..7c0d7c2f1 100644 --- a/scripts/publish-wasm-node-package.js +++ b/scripts/publish-wasm-node-package.js @@ -11,8 +11,12 @@ const WASM_NODE_PACKAGE_INFO = { const COPIED_FILES_OR_DIRS = ['LICENSE.md', 'dist']; const PACKAGE_DIR = fileURLToPath(new URL('../wasm-node-package', import.meta.url)); -function getOutputPath(...arguments_) { - return resolve(PACKAGE_DIR, ...arguments_); +/** + * @param {string[]} pathSegments + * @return {string} + */ +function getOutputPath(...pathSegments) { + return resolve(PACKAGE_DIR, ...pathSegments); } export default async function publishWasmNodePackage() { diff --git a/scripts/release-helpers.js b/scripts/release-helpers.js index 925eaed66..72bb75c3b 100644 --- a/scripts/release-helpers.js +++ b/scripts/release-helpers.js @@ -11,7 +11,7 @@ export function getFirstChangelogEntry(changelog) { const match = changelog.match( /(?## (?\d+\.\d+\.\d+(-\d+)?)[\S\s]*?)\n+## (?\d+\.\d+\.\d+)/ ); - if (!match) { + if (!match || !match.groups || typeof match.index !== 'number') { throw new Error('Could not detect any changelog entry.'); } const { @@ -21,13 +21,21 @@ export function getFirstChangelogEntry(changelog) { return { currentVersion, index, previousVersion, text }; } +/** + * @typedef {object} IncludedPR + * @property {string} author + * @property {number[]} closed - which PRs are closed by this + * @property {number} pr + * @property {string} text + */ + /** * @param {string} fromVersion * @param {string} toVersion - * @param repo + * @param {import('github-api').Repo} repo * @param {string|null} currentBranch We only have a branch when locally prepare a release, otherwise we use the sha to find the PR * @param {boolean} isPreRelease - * @returns {Promise<{ author: string, closed: string[], pr: string, text: string }[]>} + * @returns {Promise} */ export async function getIncludedPRs(fromVersion, toVersion, repo, currentBranch, isPreRelease) { const [commits, commitSha] = await Promise.all([ @@ -69,7 +77,7 @@ export async function getIncludedPRs(fromVersion, toVersion, repo, currentBranch const closedIssuesRegexp = /([Ff]ix(es|ed)?|([Cc]lose|[Rr]esolve)[ds]?) #(\d+)/g; const closed = []; while ((match = closedIssuesRegexp.exec(bodyWithoutComments))) { - closed.push(match[4]); + closed.push(Number(match[4])); } return { author: data.user.login, @@ -81,13 +89,16 @@ export async function getIncludedPRs(fromVersion, toVersion, repo, currentBranch ); } +/** + * @return {Promise} + */ export async function getGithubApi() { const GITHUB_TOKEN = '.github_token'; try { const token = (await readFile(GITHUB_TOKEN, 'utf8')).trim(); return new GitHub({ token }); } catch (error) { - if (error.code === 'ENOENT') { + if (error instanceof Error && 'code' in error && error.code === 'ENOENT') { console.error( `Could not find GitHub token file. Please create "${GITHUB_TOKEN}" containing a token with the following permissions: - public_repo` @@ -99,6 +110,10 @@ export async function getGithubApi() { } } +/** + * @param {string} version + * @return {string} + */ export function getGitTag(version) { return `v${version}`; } diff --git a/scripts/test-options.js b/scripts/test-options.js index 4ece8ce95..308bb804f 100644 --- a/scripts/test-options.js +++ b/scripts/test-options.js @@ -78,10 +78,14 @@ const helpOptionLines = splitHelpText.filter(line => line.startsWith('-')); const cliFlagsText = commandReferenceText .split('\n## ') .find(text => text.startsWith('Command line flags')); -const optionListLines = cliFlagsText - .match(/```\n([\S\s]*?)\n```/)[1] - .split('\n') - .filter(line => line.startsWith('-')); +if (!cliFlagsText) { + throw new Error('Could not find "Command line flags" section.'); +} +const cliMarkdownSection = cliFlagsText.match(/```\n([\S\s]*?)\n```/); +if (!cliMarkdownSection) { + throw new Error('Could not find markdown section in "Command line flags" section.'); +} +const optionListLines = cliMarkdownSection[1].split('\n').filter(line => line.startsWith('-')); for (const [index, line] of helpOptionLines.entries()) { const optionListLine = optionListLines[index]; diff --git a/scripts/tsconfig.json b/scripts/tsconfig.json new file mode 100644 index 000000000..7ec91e37d --- /dev/null +++ b/scripts/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "checkJs": true, + "allowJs": true, + "forceConsistentCasingInFileNames": true, + "module": "NodeNext", + "moduleResolution": "NodeNext", + "noEmit": true, + "noUnusedParameters": true, + "lib": ["ESNext"], + "esModuleInterop": true, + "skipLibCheck": true, + "strict": true, + "target": "ESNext" + } +} diff --git a/typings/declarations.d.ts b/typings/declarations.d.ts index 8cfd4ff9d..9831d8522 100644 --- a/typings/declarations.d.ts +++ b/typings/declarations.d.ts @@ -23,7 +23,7 @@ declare module 'is-reference' { parent: NodeWithFieldDefinition ): boolean; - export type Node = + type EstreeNode = | estree.ArrayExpression | estree.ArrayPattern | estree.ArrowFunctionExpression @@ -96,10 +96,10 @@ declare module 'is-reference' { | estree.YieldExpression; export type NodeWithFieldDefinition = - | Node + | EstreeNode | { computed: boolean; type: 'FieldDefinition'; - value: Node; + value: EstreeNode; }; } diff --git a/typings/fsevents.d.ts b/typings/fsevents.d.ts index fe400f2c7..8a1900adb 100644 --- a/typings/fsevents.d.ts +++ b/typings/fsevents.d.ts @@ -2,5 +2,6 @@ // and not installed on linux/windows. this will provide (bogus) type information for // linux/windows, and overwrite (replace) the types coming with the 'fsevents' module on macOS declare module 'fsevents' { - export default {}; + const fsevents: object; + export default fsevents; }