From 3de3c5496d60e423898d6e98c8632fc5e6aa7c4a Mon Sep 17 00:00:00 2001 From: Claas Augner Date: Thu, 16 Jul 2026 01:16:11 +0200 Subject: [PATCH 1/6] refactor(api): migrate from TypeScript to JavaScript with JSDoc types Convert the `api/` package sources from TypeScript to JavaScript, keeping `tsc` for strict type checking via JSDoc annotations (`@import` for external types, `@typedef` for derived types). - `tsconfig.json` uses `allowJs`/`checkJs`/`emitDeclarationOnly` to type-check the `.js` sources and emit `dist/index.d.ts`. - Run the generator with `node cli.js` instead of `ts-node`. - Add a `files` allowlist so the published tarball still includes the generated `dist/index.d.ts`, which is no longer force-included once `main` points outside `dist/`. - Keep `typescript-eslint` for linting and add an `env` so `no-undef` resolves globals like `URL` in the `.js` sources. The package now ships ESM (`"type": "module"`) instead of CommonJS. --- .lefthook.yml | 2 +- api/{cli.ts => cli.js} | 8 +- api/index.js | 177 +++++++++++++++++++++++++ api/index.ts | 151 --------------------- api/package-lock.json | 293 ----------------------------------------- api/package.json | 11 +- api/tsconfig.json | 5 +- package.json | 4 + 8 files changed, 198 insertions(+), 453 deletions(-) rename api/{cli.ts => cli.js} (64%) create mode 100644 api/index.js delete mode 100644 api/index.ts diff --git a/.lefthook.yml b/.lefthook.yml index 048faba..73bf5b5 100644 --- a/.lefthook.yml +++ b/.lefthook.yml @@ -7,7 +7,7 @@ pre-commit: eslint: run: npx eslint --fix --cache --max-warnings=0 {staged_files} - glob: "*.ts" + glob: "*.js" stage_fixed: true post-merge: diff --git a/api/cli.ts b/api/cli.js similarity index 64% rename from api/cli.ts rename to api/cli.js index 0e23076..4068063 100644 --- a/api/cli.ts +++ b/api/cli.js @@ -1,9 +1,9 @@ import { mkdir, writeFile } from "node:fs/promises"; -import { major } from "semver"; -import { bcdAPIs, walk } from "./index"; -import { version } from "./package.json"; +import semver from "semver"; +import { bcdAPIs, walk } from "./index.js"; +import pkg from "./package.json" with { type: "json" }; -const BUILD_PATH = `out/v${major(version)}`; +const BUILD_PATH = `out/v${semver.major(pkg.version)}`; main(); diff --git a/api/index.js b/api/index.js new file mode 100644 index 0000000..b5de478 --- /dev/null +++ b/api/index.js @@ -0,0 +1,177 @@ +import bcd from "@mdn/browser-compat-data" with { type: "json" }; + +/** + * @import { + * BrowserName, + * Browsers, + * CompatStatement, + * Identifier, + * SimpleSupportStatement, + * SupportStatement, + * VersionValue, + * } from "@mdn/browser-compat-data" + */ + +/** + * @typedef {object} Data + * @property {{ timestamp: string; version: string }} __meta + * @property {string} query + * @property {IdentifierExtended} data + * @property {Browsers} browsers + */ + +/** + * @typedef {SimpleSupportStatement & { release_date?: string }} SimpleSupportStatementExtended + */ + +/** + * @typedef {Omit & { + * support: Partial>; + * }} CompatStatementExtended + */ + +/** + * @typedef {{ [key: string]: IdentifierExtended | CompatStatementExtended }} IdentifierExtended + */ + +const { __meta, browsers, ...bcdAPIs } = bcd; + +export { __meta, bcdAPIs }; + +const filteredBrowsers = /** @type {Browsers} */ ( + Object.fromEntries( + Object.entries(browsers).map(([name, statement]) => [ + name, + { + ...statement, + releases: Object.fromEntries( + Object.entries(statement.releases).filter( + ([_, statement]) => statement.status !== "retired", + ), + ), + }, + ]), + ) +); + +/** + * @param {string} path + * @returns {Data | void} + */ +export function getBCDDataForPath(path) { + const subtree = path + .split(".") + .reduce( + (prev, curr) => prev?.[curr], + /** @type {Identifier | undefined} */ (bcdAPIs), + ); + if (subtree) { + return { + __meta, + query: path, + data: walk(subtree, path), + browsers: filteredBrowsers, + }; + } +} + +/** + * @param {Identifier} tree + * @param {string} path + * @param {(data: Data) => void} [callback] + * @returns {IdentifierExtended} + */ +export function walk(tree, path, callback) { + /** @type {IdentifierExtended} */ + const extendedTree = Object.fromEntries( + Object.entries(tree).map(([key, subtree]) => [ + key, + key === "__compat" + ? extendCompatStatement(/** @type {CompatStatement} */ (subtree)) + : walk(/** @type {Identifier} */ (subtree), `${path}.${key}`, callback), + ]), + ); + + /** @type {Data} */ + const data = { + __meta, + query: path.slice(1), + data: extendedTree, + browsers: filteredBrowsers, + }; + callback?.(data); + return extendedTree; +} + +/** + * @param {CompatStatement} statement + * @returns {CompatStatementExtended} + */ +function extendCompatStatement(statement) { + const support = Object.fromEntries( + /** @type {[BrowserName, SupportStatement][]} */ ( + Object.entries(statement.support) + ).map(([browserName, supportStatement]) => [ + browserName, + (supportStatement instanceof Array + ? supportStatement + : [supportStatement] + ).map((simpleSupportStatement) => + extendSimpleSupportStatement(simpleSupportStatement, browserName), + ), + ]), + ); + return { + ...statement, + mdn_url: getPathFromAbsoluteURL(statement.mdn_url), + support, + }; +} + +/** + * @param {SimpleSupportStatement} statement + * @param {BrowserName} browserName + * @returns {SimpleSupportStatementExtended} + */ +function extendSimpleSupportStatement(statement, browserName) { + const added = normalizeVersion(statement.version_added); + return { + ...statement, + release_date: added + ? browsers[browserName].releases[added]?.release_date + : undefined, + }; +} + +/** + * @param {string} [absoluteUrl] + * @returns {string | undefined} + */ +function getPathFromAbsoluteURL(absoluteUrl) { + if (!absoluteUrl || !absoluteUrl.includes("://")) { + return absoluteUrl; + } + + const url = new URL(absoluteUrl); + if (url.hostname !== "developer.mozilla.org") { + return absoluteUrl; + } + + const slug = url.pathname + url.hash; + if (slug.startsWith("/docs/")) { + return `/en-US${slug}`; + } + return slug; +} + +/** + * @param {VersionValue} [version] + * @returns {string | undefined} + */ +function normalizeVersion(version) { + return typeof version === "string" + ? version.startsWith("≤") + ? version.slice(1) + : version + : undefined; +} diff --git a/api/index.ts b/api/index.ts deleted file mode 100644 index c800128..0000000 --- a/api/index.ts +++ /dev/null @@ -1,151 +0,0 @@ -import bcd, { - BrowserName, - Browsers, - CompatStatement, - Identifier, - SimpleSupportStatement, - SupportStatement, - VersionValue, -} from "@mdn/browser-compat-data"; - -export interface Data { - __meta: { - timestamp: string; - version: string; - }; - query: string; - data: IdentifierExtended; - browsers: Browsers; -} - -export interface SimpleSupportStatementExtended extends SimpleSupportStatement { - release_date?: string; -} - -export interface CompatStatementExtended extends Omit< - CompatStatement, - "support" -> { - support: Partial>; -} - -export interface IdentifierExtended { - [key: string]: IdentifierExtended | CompatStatementExtended; -} - -const { __meta, browsers, ...bcdAPIs } = bcd; - -export { __meta, bcdAPIs }; - -const filteredBrowsers = Object.fromEntries( - Object.entries(browsers).map(([name, statement]) => [ - name, - { - ...statement, - releases: Object.fromEntries( - Object.entries(statement.releases).filter( - ([_, statement]) => statement.status !== "retired", - ), - ), - }, - ]), -) as Browsers; - -export function getBCDDataForPath(path: string): Data | void { - const subtree = path - .split(".") - .reduce((prev, curr) => prev?.[curr], bcdAPIs); - if (subtree) { - return { - __meta, - query: path, - data: walk(subtree, path), - browsers: filteredBrowsers, - }; - } -} - -export function walk( - tree: Identifier, - path: string, - callback?: (data: Data) => void, -): IdentifierExtended { - const extendedTree: IdentifierExtended = Object.fromEntries( - Object.entries(tree).map(([key, subtree]) => [ - key, - key === "__compat" - ? extendCompatStatement(subtree as CompatStatement) - : walk(subtree as Identifier, `${path}.${key}`, callback), - ]), - ); - - const data: Data = { - __meta, - query: path.slice(1), - data: extendedTree, - browsers: filteredBrowsers, - }; - callback?.(data); - return extendedTree; -} - -function extendCompatStatement( - statement: CompatStatement, -): CompatStatementExtended { - const support = Object.fromEntries( - ( - Object.entries(statement.support) as [BrowserName, SupportStatement][] - ).map(([browserName, supportStatement]) => [ - browserName, - (supportStatement instanceof Array - ? supportStatement - : [supportStatement] - ).map((simpleSupportStatement) => - extendSimpleSupportStatement(simpleSupportStatement, browserName), - ), - ]), - ); - return { - ...statement, - mdn_url: getPathFromAbsoluteURL(statement.mdn_url), - support, - }; -} - -function extendSimpleSupportStatement( - statement: SimpleSupportStatement, - browserName: BrowserName, -): SimpleSupportStatementExtended { - const added = normalizeVersion(statement.version_added); - return { - ...statement, - release_date: added - ? browsers[browserName].releases[added]?.release_date - : undefined, - }; -} - -function getPathFromAbsoluteURL(absoluteUrl?: string) { - if (!absoluteUrl || !absoluteUrl.includes("://")) { - return absoluteUrl; - } - - const url = new URL(absoluteUrl); - if (url.hostname !== "developer.mozilla.org") { - return absoluteUrl; - } - - const slug = url.pathname + url.hash; - if (slug.startsWith("/docs/")) { - return `/en-US${slug}`; - } - return slug; -} - -function normalizeVersion(version?: VersionValue): string | undefined { - return typeof version === "string" - ? version.startsWith("≤") - ? version.slice(1) - : version - : undefined; -} diff --git a/api/package-lock.json b/api/package-lock.json index 7f8efe9..893d287 100644 --- a/api/package-lock.json +++ b/api/package-lock.json @@ -12,50 +12,12 @@ "@types/node": "^24.10.3", "@types/semver": "^7.3.13", "semver": "^7.3.8", - "ts-node": "^10.9.1", "typescript": "^6.0.2" }, "peerDependencies": { "@mdn/browser-compat-data": "^8.0.0" } }, - "node_modules/@cspotcode/source-map-support": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", - "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "dev": true, - "dependencies": { - "@jridgewell/trace-mapping": "0.3.9" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", - "dev": true - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "dev": true, - "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, "node_modules/@mdn/browser-compat-data": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/@mdn/browser-compat-data/-/browser-compat-data-8.0.0.tgz", @@ -63,30 +25,6 @@ "license": "CC0-1.0", "peer": true }, - "node_modules/@tsconfig/node10": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", - "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", - "dev": true - }, - "node_modules/@tsconfig/node12": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", - "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "dev": true - }, - "node_modules/@tsconfig/node14": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", - "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "dev": true - }, - "node_modules/@tsconfig/node16": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", - "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", - "dev": true - }, "node_modules/@types/node": { "version": "24.13.3", "resolved": "https://registry.npmjs.org/@types/node/-/node-24.13.3.tgz", @@ -102,55 +40,6 @@ "integrity": "sha512-FmgJfu+MOcQ370SD0ev7EI8TlCAfKYU+B4m5T3yXc1CiRN94g/SZPtsCkk506aUDtlMnFZvasDwHHUcZUEaYuA==", "dev": true }, - "node_modules/acorn": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", - "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true - }, - "node_modules/create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true - }, - "node_modules/diff": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.4.tgz", - "integrity": "sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true - }, "node_modules/semver": { "version": "7.8.5", "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", @@ -163,49 +52,6 @@ "node": ">=10" } }, - "node_modules/ts-node": { - "version": "10.9.2", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", - "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", - "dev": true, - "dependencies": { - "@cspotcode/source-map-support": "^0.8.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.1", - "yn": "3.1.1" - }, - "bin": { - "ts-node": "dist/bin.js", - "ts-node-cwd": "dist/bin-cwd.js", - "ts-node-esm": "dist/bin-esm.js", - "ts-node-script": "dist/bin-script.js", - "ts-node-transpile-only": "dist/bin-transpile.js", - "ts-script": "dist/bin-script-deprecated.js" - }, - "peerDependencies": { - "@swc/core": ">=1.2.50", - "@swc/wasm": ">=1.2.50", - "@types/node": "*", - "typescript": ">=2.7" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "@swc/wasm": { - "optional": true - } - } - }, "node_modules/typescript": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", @@ -224,85 +70,15 @@ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", "dev": true - }, - "node_modules/v8-compile-cache-lib": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "dev": true - }, - "node_modules/yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true, - "engines": { - "node": ">=6" - } } }, "dependencies": { - "@cspotcode/source-map-support": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", - "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "dev": true, - "requires": { - "@jridgewell/trace-mapping": "0.3.9" - } - }, - "@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", - "dev": true - }, - "@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", - "dev": true - }, - "@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "dev": true, - "requires": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, "@mdn/browser-compat-data": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/@mdn/browser-compat-data/-/browser-compat-data-8.0.0.tgz", "integrity": "sha512-VS5jxDp3MxneNPtrueJhktBn+iB5ZlSLYZyAVZPXDYjhTrD/o8cGtRiuEdQoNZidUiUBh6K87wRTbWe2164iag==", "peer": true }, - "@tsconfig/node10": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", - "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", - "dev": true - }, - "@tsconfig/node12": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", - "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "dev": true - }, - "@tsconfig/node14": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", - "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "dev": true - }, - "@tsconfig/node16": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", - "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", - "dev": true - }, "@types/node": { "version": "24.13.3", "resolved": "https://registry.npmjs.org/@types/node/-/node-24.13.3.tgz", @@ -318,69 +94,12 @@ "integrity": "sha512-FmgJfu+MOcQ370SD0ev7EI8TlCAfKYU+B4m5T3yXc1CiRN94g/SZPtsCkk506aUDtlMnFZvasDwHHUcZUEaYuA==", "dev": true }, - "acorn": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", - "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", - "dev": true - }, - "acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", - "dev": true - }, - "arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true - }, - "create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true - }, - "diff": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.4.tgz", - "integrity": "sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==", - "dev": true - }, - "make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true - }, "semver": { "version": "7.8.5", "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", "dev": true }, - "ts-node": { - "version": "10.9.2", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", - "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", - "dev": true, - "requires": { - "@cspotcode/source-map-support": "^0.8.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.1", - "yn": "3.1.1" - } - }, "typescript": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", @@ -392,18 +111,6 @@ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", "dev": true - }, - "v8-compile-cache-lib": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "dev": true - }, - "yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true } } } diff --git a/api/package.json b/api/package.json index 706e70f..520cf88 100644 --- a/api/package.json +++ b/api/package.json @@ -12,18 +12,23 @@ }, "license": "MPL-2.0", "author": "MDN Web Docs", - "main": "dist/index.js", + "type": "module", + "main": "index.js", "types": "dist/index.d.ts", + "files": [ + "index.js", + "cli.js", + "dist/index.d.ts" + ], "scripts": { "build": "tsc", - "generate": "ts-node cli.ts", + "generate": "node cli.js", "test": "npm run generate && rm -r out" }, "devDependencies": { "@types/node": "^24.10.3", "@types/semver": "^7.3.13", "semver": "^7.3.8", - "ts-node": "^10.9.1", "typescript": "^6.0.2" }, "peerDependencies": { diff --git a/api/tsconfig.json b/api/tsconfig.json index 5132753..d8efc28 100644 --- a/api/tsconfig.json +++ b/api/tsconfig.json @@ -5,10 +5,13 @@ "moduleResolution": "nodenext", "resolveJsonModule": true, "esModuleInterop": true, + "allowJs": true, + "checkJs": true, "strict": true, "outDir": "dist", "declaration": true, + "emitDeclarationOnly": true, "types": ["node"] }, - "files": ["index.ts"] + "include": ["index.js", "cli.js"] } diff --git a/package.json b/package.json index 0735dab..254f8bf 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,10 @@ ] }, "eslintConfig": { + "env": { + "es2024": true, + "node": true + }, "parser": "@typescript-eslint/parser", "plugins": [ "@typescript-eslint" From e61cafe0b88df4d5caa3bee09bbd407e1708499b Mon Sep 17 00:00:00 2001 From: Claas Augner Date: Fri, 17 Jul 2026 11:21:34 +0200 Subject: [PATCH 2/6] build(api): build type declarations via a `prepack` hook Guarantee `dist/index.d.ts` is present in the published tarball regardless of build ordering, since `dist` is gitignored and `npm pack` silently omits missing `files` entries. Also makes local `npm pack` and `npm publish` ship the declarations. --- api/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/api/package.json b/api/package.json index 520cf88..2d8cdeb 100644 --- a/api/package.json +++ b/api/package.json @@ -23,6 +23,7 @@ "scripts": { "build": "tsc", "generate": "node cli.js", + "prepack": "tsc", "test": "npm run generate && rm -r out" }, "devDependencies": { From cf46530c05d02f93675eee8b47a0361784be0ed9 Mon Sep 17 00:00:00 2001 From: Claas Augner Date: Fri, 17 Jul 2026 11:22:20 +0200 Subject: [PATCH 3/6] build(api): drop `cli.js` from the published `files` `cli.js` is the internal generator entry, run via `npm run generate` from a checkout; it is not referenced by `main`, `bin`, or `exports`, so npm consumers never import it. It stays in the tsconfig `include` for type-checking. --- api/package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/api/package.json b/api/package.json index 2d8cdeb..0dc4750 100644 --- a/api/package.json +++ b/api/package.json @@ -17,7 +17,6 @@ "types": "dist/index.d.ts", "files": [ "index.js", - "cli.js", "dist/index.d.ts" ], "scripts": { From d00cdebcaff22617aa65e8b08ef98f4588743014 Mon Sep 17 00:00:00 2001 From: Claas Augner Date: Fri, 17 Jul 2026 11:37:08 +0200 Subject: [PATCH 4/6] build(eslint): drop redundant `es2024` env `no-undef` needs only the `node` env to resolve runtime globals like `URL`; `es2024` adds no globals the sources use, and `@typescript-eslint/parser` already parses the modern syntax. --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index 254f8bf..90385d3 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,6 @@ }, "eslintConfig": { "env": { - "es2024": true, "node": true }, "parser": "@typescript-eslint/parser", From 0cb74d9da10b38c56064f9b4273eef3d7fe76f56 Mon Sep 17 00:00:00 2001 From: Claas Augner Date: Fri, 17 Jul 2026 16:41:04 +0200 Subject: [PATCH 5/6] fix: restore root lockfile name to `bcd-utils` `npm install` in a worktree derived the project name from the directory basename and rewrote it into the lockfile. The root `package.json` has no `name` field, so revert the leaked value. --- package-lock.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package-lock.json b/package-lock.json index ae5cd80..9ab2d6f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,5 +1,5 @@ { - "name": "un-typescript", + "name": "bcd-utils", "lockfileVersion": 2, "requires": true, "packages": { From da046cdda02153b4b9217caa7677c36352e1bc58 Mon Sep 17 00:00:00 2001 From: Claas Augner Date: Fri, 17 Jul 2026 16:41:25 +0200 Subject: [PATCH 6/6] refactor(api): return `Data | undefined` from `getBCDDataForPath` `void` in a return union reads oddly for a function that returns a value or nothing; `undefined` is clearer and emits an identical declaration. --- api/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/index.js b/api/index.js index b5de478..c0174bf 100644 --- a/api/index.js +++ b/api/index.js @@ -56,7 +56,7 @@ const filteredBrowsers = /** @type {Browsers} */ ( /** * @param {string} path - * @returns {Data | void} + * @returns {Data | undefined} */ export function getBCDDataForPath(path) { const subtree = path