blob: 79fdda426004a968a6fa1ec9ad3dffec05ddf08a [file] [log] [blame] [edit]
/* This file is a part of @mdn/browser-compat-data
* See LICENSE file for more information. */
import fs from 'node:fs';
import stringify from 'fast-json-stable-stringify';
import { CompatData, BrowserName } from '../../types/types.js';
import {
InternalSupportStatement,
InternalSupportBlock,
} from '../../types/index.js';
import bcd from '../../index.js';
import { walk } from '../../utils/index.js';
import mirrorSupport from '../../scripts/build/mirror.js';
const downstreamBrowsers = (
Object.keys(bcd.browsers) as (keyof typeof bcd.browsers)[]
).filter((browser) => bcd.browsers[browser].upstream);
/**
* Check to see if the statement is equal to the mirrored statement
* @param support The support statement to test
* @param browser The browser to mirror for
* @returns Whether the support statement is equal to mirroring
*/
export const isMirrorEquivalent = (
support: InternalSupportBlock,
browser: BrowserName,
): boolean => {
const original = support[browser];
if (!original) {
return false; // No data for browser.
}
if (original === 'mirror') {
return false; // Already mirrored.
}
let mirrored;
try {
mirrored = mirrorSupport(browser, support);
} catch (e) {
// This can happen with missing engine_version. Don't mirror anything.
return false;
}
return stringify(mirrored) === stringify(original);
};
/**
* Check to see if mirroring is required
* @param supportData The support statement to test
* @param browser The browser to mirror for
* @returns Whether mirroring is required
*/
export const isMirrorRequired = (
supportData: Partial<Record<BrowserName, any>>,
browser: string,
): boolean => {
const current = bcd.browsers[browser];
const upstream: BrowserName | undefined = current.upstream;
if (!upstream || !supportData[browser] || !supportData[upstream]) {
return false;
}
if (
supportData[browser].version_added === false &&
supportData[upstream].version_added === 'preview' &&
!current.preview_name
) {
// Allow `"version_added": false` if
// - upstream only has preview support, and
// - target does not have preview versions.
return false;
}
return true;
};
/**
* Set the support statement for each browser to mirror if it matches mirroring
* @param bcd The compat data to update
*/
export const mirrorIfEquivalent = (bcd: CompatData): void => {
for (const { compat } of walk(undefined, bcd)) {
for (const browser of downstreamBrowsers) {
if (
isMirrorRequired(compat.support, browser) &&
isMirrorEquivalent(compat.support, browser)
) {
(compat.support[browser] as InternalSupportStatement) = 'mirror';
}
}
}
};
/**
* Update compat data to 'mirror' if the statement matches mirroring
* @param filename The name of the file to fix
*/
const fixMirror = (filename: string): void => {
if (filename.includes('/browsers/')) {
return;
}
const actual = fs.readFileSync(filename, 'utf-8').trim();
const bcd = JSON.parse(actual);
mirrorIfEquivalent(bcd);
const expected = JSON.stringify(bcd, null, 2);
if (actual !== expected) {
fs.writeFileSync(filename, expected + '\n', 'utf-8');
}
};
export default fixMirror;