Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
a59af28
feat(schemas): add public schema
caugner Feb 13, 2026
b94173e
chore(scripts/build): validate with public schema
caugner Feb 13, 2026
6e38d63
fix(scripts/build): convert Date to string explicitly
caugner Feb 13, 2026
5141563
fix(schemas/browsers): restore "maxProperties"
caugner Feb 13, 2026
6aab32a
fix(schemas): remove version_last from internal schema
caugner Feb 13, 2026
58bc695
fix(schemas): remove "mirror" from public schema
caugner Feb 13, 2026
02512b2
chore(schemas): rename internal types that differ
caugner Feb 13, 2026
e87f7f8
chore(scripts/generate-types): use public schema
caugner Feb 13, 2026
e6ec3f1
chore(schemas): refine public schema
caugner Feb 13, 2026
3625d24
ci(test): add diff-build job
caugner Feb 13, 2026
9c40066
ci(test): add step names
caugner Feb 13, 2026
bd382c9
fix(scripts/generate-types): generate internal types as well
caugner Feb 13, 2026
02fe4a2
chore(scripts/build): use new public type
caugner Feb 13, 2026
212d293
chore: fix internal type usages
caugner Feb 13, 2026
4869566
chore(vscode): use TS version from workspace
caugner Feb 13, 2026
b9028b7
chore(schemas): refine browsers schema
caugner Feb 13, 2026
8048401
fix(generate-types): keep types.d.ts for internal types
caugner Feb 13, 2026
46185f4
fix(schemas): remove source_file from internal schema
caugner Feb 13, 2026
b737787
chore(types): remove manual types
caugner Feb 13, 2026
252bb46
fix(schemas): refine internal schema
caugner Feb 13, 2026
02c1290
chore: fix internal schema usage
caugner Feb 13, 2026
154e7fb
chore: fix ESLint errors
caugner Feb 13, 2026
fe10aa9
fixup! chore(schemas): refine public schema
caugner Feb 13, 2026
2a320b4
fixup! chore: fix internal type usages
caugner Feb 13, 2026
6d3341f
fixup! fixup! chore: fix internal type usages
caugner Feb 13, 2026
5444400
Merge branch 'main' into public-schema
caugner Feb 16, 2026
bbffdde
chore(schemas): make SupportBlock partial
caugner Feb 16, 2026
0133009
fix(schemas): replace patternProperties on root
caugner Feb 16, 2026
6fce3da
fix(schemas): use intersection type
caugner Feb 16, 2026
eb86b1a
chore(schemas): prefer Record over index type
caugner Feb 16, 2026
4c78d36
fixup! fix(generate-types): keep types.d.ts for internal types
caugner Feb 17, 2026
613889f
refactor: rename types/{types => internal}.d.ts
caugner Feb 17, 2026
a78207a
chore(schemas): sync existing docs
caugner Feb 17, 2026
57f2f8c
fixup! fix(schemas): refine internal schema
caugner Feb 17, 2026
5bb0dc4
docs(schemas): describe public schema
caugner Feb 17, 2026
a64f7d6
docs(schemas): sync internal schema docs
caugner Feb 17, 2026
c43fb41
chore(scripts/generate-types): clean up old types
caugner Feb 17, 2026
fa492d8
refactor: revert named browsers export
caugner Feb 19, 2026
2160412
chore(eslint): prefer @typescript-eslint/no-unused-vars
caugner Feb 19, 2026
6ef2f5c
fix(lint/types): revert underscore on "unused var"
caugner Feb 19, 2026
4c20fb8
chore(schemas): remove examples from type descriptions
caugner Feb 19, 2026
8795524
fixup! refactor: revert named browsers export
caugner Feb 19, 2026
ed665b7
chore(schemas): remove duplicated information from description
caugner Feb 19, 2026
d9d323d
chore(schemas): revert BrowserName type
caugner Feb 19, 2026
22e9dbd
chore(schemas): reflect draft-07 in `$schema` value
caugner Feb 19, 2026
a760f58
chore(schemas): make descriptions more concise
caugner Feb 19, 2026
662ee59
fixup! chore(schemas): reflect draft-07 in `$schema` value
caugner Feb 19, 2026
883d288
chore(schemas): add description/examples to meta block
caugner Feb 19, 2026
30361cd
chore(schemas): prefer "subfeature" over "sub-feature"
caugner Feb 19, 2026
24ccd78
chore(schemas): refine Browsers type description
caugner Feb 19, 2026
ea1b029
chore(schemas): prefer "feature flags" over "[user-toggleable] flags"
caugner Feb 19, 2026
d39e07e
chore(schemas): refine Browsers type descriptions
caugner Feb 19, 2026
b1bc417
chore(schemas): remove "This is automatically generated"
caugner Feb 19, 2026
dacc025
fixup! chore(schemas): prefer "feature flags" over "[user-toggleable]…
caugner Feb 19, 2026
246c656
chore(schemas): refine `impl_url` description
caugner Feb 19, 2026
c80a51e
chore(schemas): remove errorMessage from public schema
caugner Feb 19, 2026
549e023
chore(schemas): refine `partial_implementation` description
caugner Feb 19, 2026
108d462
docs(schemas): sync docs with changes
caugner Feb 19, 2026
b7cccc5
refactor(lint/fixer): refine common-errors fix
caugner Feb 19, 2026
93f7b14
chore(lint): remove unnecessary type cast
caugner Feb 19, 2026
dd6452b
fix(schemas): refine [Internal]Identifier tsType
caugner Feb 19, 2026
662b144
chore(lint): replace any type
caugner Feb 19, 2026
fa35b21
fixup! chore(lint): remove unnecessary type cast
caugner Feb 19, 2026
dfc8889
Merge branch 'main' into public-schema
caugner Feb 20, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 73 additions & 7 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ on:
branches:
- main
pull_request:
merge_group:

permissions:
contents: read
Expand All @@ -18,11 +17,13 @@ jobs:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
Comment on lines +20 to +21
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All of the name: additions are pretty pointless here. Not sure why any are in this PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I sympathize with your scrutiny, but drive-by fixes like this are very common. I'm not sure if you're suggesting that I should add a separate PR just for adding workflow step names? This change increases consistency with other workflow across the MDN org, and reduces noise when looking at the logs of a failed workflow run.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Besides, this is part of #29042, which should be merged before, so this change shouldn't end up in this commit.)

with:
persist-credentials: false

- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
- name: Setup Node
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
with:
node-version-file: ".nvmrc"
cache: npm
Expand All @@ -40,11 +41,13 @@ jobs:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false

- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
- name: Setup Node
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
with:
node-version-file: ".nvmrc"
cache: npm
Expand All @@ -58,11 +61,13 @@ jobs:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false

- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
- name: Setup Node
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
with:
node-version-file: ".nvmrc"
cache: npm
Expand All @@ -71,3 +76,64 @@ jobs:
- run: npm ci

- run: npm run unittest

diff-build:
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest

concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number }}-diff-build
cancel-in-progress: true

steps:
- name: Determine base ref
id: base
run: |
if [[ "$GITHUB_HEAD_REF" == "release" ]]; then
VERSION=$(npm view @mdn/browser-compat-data version)
echo "ref=v$VERSION" >> "$GITHUB_OUTPUT"
echo "Comparing release branch against published v$VERSION"
else
echo "ref=$GITHUB_BASE_REF" >> "$GITHUB_OUTPUT"
echo "Comparing against base branch: $GITHUB_BASE_REF"
fi

# Base

- name: Checkout (base)
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
ref: ${{ steps.base.outputs.ref }}
path: base
persist-credentials: false

- name: Checkout (PR)
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
path: pr
persist-credentials: false

- name: Setup Node
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
with:
node-version-file: pr/.nvmrc
cache: npm
cache-dependency-path: |
base/package-lock.json
pr/package-lock.json
package-manager-cache: true

- name: Install
run: |
cd base && npm ci | sed "s/^/[base] /" &
cd pr && npm ci | sed "s/^/[pr] /" &
wait

- name: Format
run: |
cd base/build && npx prettier --write . | sed "s/^/[base] /" &
cd pr/build && npx prettier --write . | sed "s/^/[pr] /" &
wait

- name: Diff
run: git diff --color=always --no-index base/build/ pr/build/ || true
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@ yarn.lock
.nyc_output/
coverage.lcov
coverage/
types/types.d.ts
/types/internal.d.ts
/types/public.d.ts
.DS_Store
3 changes: 2 additions & 1 deletion .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ LICENSE
/build/
coverage/
.features.json
types.d.ts
/types/internal.d.ts
/types/public.d.ts
3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,6 @@
],
"url": "/schemas/browsers.schema.json"
}
]
],
"typescript.tsdk": "node_modules/typescript/lib"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is this for?

Copy link
Contributor Author

@caugner caugner Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This ensures that VSCode uses the TypeScript version referenced by package.json, rather than using the latest TypeScript version. Specifically, the latest TypeScript version seems to report additional (unrelated) warnings/errors that I don't want to resolve in this PR.

(It would make sense to move this to a separate PR.)

}
8 changes: 4 additions & 4 deletions eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ export default [
'CODE_OF_CONDUCT.md',
'build/',
'**/coverage/',
'**/types.d.ts',
'types/internal.d.ts',
'types/public.d.ts',
],
},
...fixupConfigRules(
Expand Down Expand Up @@ -77,9 +78,7 @@ export default [
rules: {
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-unused-expressions': 'error',
'@typescript-eslint/no-unused-vars': 'off',

'no-unused-vars': [
'@typescript-eslint/no-unused-vars': [
'error',
{
argsIgnorePattern: '^_',
Expand Down Expand Up @@ -166,6 +165,7 @@ export default [
'no-return-assign': 'error',
'no-self-compare': 'error',
'no-unused-expressions': 'error',
'no-unused-vars': 'off', // Using @typescript-eslint/no-unused-vars instead.
'no-useless-call': 'error',

'prefer-arrow-functions/prefer-arrow-functions': [
Expand Down
18 changes: 12 additions & 6 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* This file is a part of @mdn/browser-compat-data
* See LICENSE file for more information. */

/** @import {CompatData} from './types/types.js' */
/** @import {InternalCompatData} from './types/index.js' */

import fs from 'node:fs/promises';
import path from 'node:path';
Expand All @@ -17,10 +17,12 @@ const dirname = fileURLToPath(new URL('.', import.meta.url));

/**
* Recursively load one or more directories passed as arguments.
* @param {...string} dirs The directories to load
* @returns {Promise<CompatData>} All of the browser compatibility data
* @template {keyof InternalCompatData} Dir
* @param {...Dir} dirs The directories to load
* @returns {Promise<Pick<InternalCompatData, Dir>>} All of the browser compatibility data
*/
const load = async (...dirs) => {
/** @type {Partial<Pick<InternalCompatData, Dir>>} */
const result = {};

for (const dir of dirs) {
Expand All @@ -35,12 +37,13 @@ const load = async (...dirs) => {
for (const fp of paths) {
try {
const rawcontents = await fs.readFile(fp);
/** @type {CompatData} */
/** @type {InternalCompatData} */
const contents = JSON.parse(rawcontents.toString('utf8'));

// Add source_file props
const walker = walk(undefined, contents);
for (const { compat } of walker) {
// @ts-expect-error Need to better reflect transition from internal to public data.
compat.source_file = normalizePath(path.relative(dirname, fp));
}

Expand All @@ -54,7 +57,10 @@ const load = async (...dirs) => {
}
}

return /** @type {CompatData} */ (result);
return /** @type {Pick<InternalCompatData, Dir>} */ (result);
};

export default await load(...dataFolders);
/** @type {InternalCompatData} */
const bcd = await load(...dataFolders);

export default bcd;
6 changes: 3 additions & 3 deletions index.test.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
/* This file is a part of @mdn/browser-compat-data
* See LICENSE file for more information. */

/** @import {CompatStatement} from './types/types.js' */
/** @import {InternalCompatStatement} from './types/index.js' */

import assert from 'node:assert/strict';

import bcd from './index.js';

describe('Using BCD', () => {
it('subscript notation', () => {
/** @type {CompatStatement | undefined} */
/** @type {InternalCompatStatement | undefined} */
const data = bcd['api']['AbortController']['__compat'];
assert.ok(data);
});

it('dot notation', () => {
/** @type {CompatStatement | undefined} */
/** @type {InternalCompatStatement | undefined} */
const data = bcd.api.AbortController.__compat;
assert.ok(data);
});
Expand Down
26 changes: 15 additions & 11 deletions lint/common/overlap.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@ import { createStatementGroupKey } from '../utils.js';
import compareStatements from '../../scripts/lib/compare-statements.js';

/** @import {Logger} from '../utils.js' */
/** @import {BrowserName, SimpleSupportStatement, SupportStatement} from '../../types/types.js' */
/** @import {BrowserName, InternalSimpleSupportStatement, InternalSupportStatement} from '../../types/index.js' */

/**
* Groups statements by group key.
* @param {SimpleSupportStatement[]} data The support statements to group.
* @returns {Map<string, SimpleSupportStatement[]>} the statement groups
* @param {InternalSimpleSupportStatement[]} data The support statements to group.
* @returns {Map<string, InternalSimpleSupportStatement[]>} the statement groups
*/
const groupByStatementKey = (data) => {
/** @type {Map<string, SimpleSupportStatement[]>} */
/** @type {Map<string, InternalSimpleSupportStatement[]>} */
const groups = new Map();

for (const support of data) {
Expand All @@ -34,7 +34,7 @@ const groupByStatementKey = (data) => {

/**
* Formats a support statement as a simplified JSON-like version range.
* @param {SimpleSupportStatement} support The statement to format
* @param {InternalSimpleSupportStatement} support The statement to format
* @returns {string} The formatted range
*/
const formatRange = (support) => {
Expand All @@ -52,12 +52,12 @@ const formatRange = (support) => {

/**
* Process data and check to make sure there aren't support statements whose version ranges overlap.
* @param {SupportStatement} data The data to test
* @param {InternalSupportStatement} data The data to test
* @param {BrowserName} browser The name of the browser
* @param {object} options The check options
* @param {Logger} [options.logger] The logger to output errors to
* @param {boolean} [options.fix] Whether the statements should be fixed (if possible)
* @returns {SupportStatement} the data (with fixes, if specified)
* @returns {InternalSupportStatement} the data (with fixes, if specified)
*/
export const checkOverlap = (data, browser, { logger, fix = false }) => {
if (!Array.isArray(data)) {
Expand All @@ -73,8 +73,12 @@ export const checkOverlap = (data, browser, { logger, fix = false }) => {
const statements = groupData.slice().sort(compareStatements).reverse();

for (let i = 0; i < statements.length - 1; i++) {
const current = /** @type {SimpleSupportStatement} */ (statements.at(i));
const next = /** @type {SimpleSupportStatement} */ (statements.at(i + 1));
const current = /** @type {InternalSimpleSupportStatement} */ (
statements.at(i)
);
const next = /** @type {InternalSimpleSupportStatement} */ (
statements.at(i + 1)
);

if (!statementsOverlap(current, next)) {
continue;
Expand Down Expand Up @@ -106,8 +110,8 @@ export const checkOverlap = (data, browser, { logger, fix = false }) => {

/**
* Checks if the support statements overlap in terms of their version ranges.
* @param {SimpleSupportStatement} current the current statement.
* @param {SimpleSupportStatement} next the chronologically following statement.
* @param {InternalSimpleSupportStatement} current the current statement.
* @param {InternalSimpleSupportStatement} next the chronologically following statement.
* @returns {boolean} Whether the support statements overlap.
*/
const statementsOverlap = (current, next) => {
Expand Down
12 changes: 6 additions & 6 deletions lint/fixer/browser-order.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* This file is a part of @mdn/browser-compat-data
* See LICENSE file for more information. */

/** @import {BrowserName, CompatStatement, SupportBlock} from '../../types/types.js' */
/** @import {BrowserName, InternalCompatStatement, InternalSupportBlock} from '../../types/index.js' */

/**
* Return a new "support_block" object whose first-level properties
Expand All @@ -10,8 +10,8 @@
* guaranteed "own" property ordering, which is insertion order for
* non-integer keys (which is our case).
* @param {string} key The key of the object
* @param {CompatStatement} value The value of the key
* @returns {CompatStatement} Value with sorting applied
* @param {InternalCompatStatement} value The value of the key
* @returns {InternalCompatStatement} Value with sorting applied
*/
export const orderSupportBlock = (key, value) => {
if (key === '__compat') {
Expand All @@ -21,15 +21,15 @@ export const orderSupportBlock = (key, value) => {
.sort()
.reduce(
/**
* @param {SupportBlock} result
* @param {InternalSupportBlock} result
* @param {BrowserName} key
* @returns {SupportBlock}
* @returns {InternalSupportBlock}
*/
(result, key) => {
result[key] = value.support[key];
return result;
},
/** @type {SupportBlock} */ ({}),
/** @type {InternalSupportBlock} */ ({}),
);
}
return value;
Expand Down
Loading