blob: 2a25bc7128b09c3ebb670d45ef4a7f67357d94b9 [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 path from 'node:path';
import { fileURLToPath } from 'node:url';
import esMain from 'es-main';
import {
CompatData,
BrowserName,
Identifier,
ReleaseStatement,
SimpleSupportStatement,
} from '../../types/types.js';
import { walk } from '../../utils/index.js';
import bcd from '../../index.js';
const { browsers } = bcd;
const dirname = fileURLToPath(new URL('.', import.meta.url));
/**
* Fix the experimental status throughout compatibility data
* @param bcd Parsed BCD object to be updated in place.
*/
export const fixExperimental = (bcd: CompatData | Identifier): void => {
for (const { compat } of walk(undefined, bcd)) {
if (!compat.status?.experimental) {
continue;
}
// This entry is marked as experimental. Check which browsers support it.
const browserSupport = new Set<BrowserName>();
for (const [browser, support] of Object.entries(compat.support)) {
if (!support) {
continue;
}
// Consider only the first part of an array statement.
const statement: SimpleSupportStatement = Array.isArray(support)
? support[0]
: support;
// Ignore anything behind flag, prefix or alternative name
if (statement.flags || statement.prefix || statement.alternative_name) {
continue;
}
if (statement.version_added && !statement.version_removed) {
browserSupport.add(browser as BrowserName);
}
}
// Now check which of Blink, Gecko and WebKit support it.
const engineSupport = new Set();
for (const browser of browserSupport) {
const currentRelease = Object.values(browsers[browser].releases).find(
(r: ReleaseStatement) => r.status === 'current',
);
if (!currentRelease) {
continue;
}
const engine = currentRelease.engine;
engineSupport.add(engine);
}
let engineCount = 0;
for (const engine of ['Blink', 'Gecko', 'WebKit']) {
if (engineSupport.has(engine)) {
engineCount++;
}
}
if (engineCount > 1) {
compat.status.experimental = false;
}
}
};
/**
* Fix the experimental status throughout a file
* @param filename Filename of BCD to be updated in place.
*/
const fixExperimentalFile = (filename: string): void => {
const actual = fs.readFileSync(filename, 'utf-8').trim();
const bcd = JSON.parse(actual);
fixExperimental(bcd);
const expected = JSON.stringify(bcd, null, 2);
if (actual !== expected) {
fs.writeFileSync(filename, expected + '\n', 'utf-8');
}
};
/**
* Load files and fix experimental status
* @param files The files to fix
*/
const load = (...files: string[]): void => {
for (let file of files) {
if (file.indexOf(dirname) !== 0) {
file = path.resolve(dirname, '..', '..', file);
}
if (!fs.existsSync(file)) {
continue; // Ignore non-existent files
}
if (fs.statSync(file).isFile()) {
if (path.extname(file) === '.json') {
fixExperimentalFile(file);
}
continue;
}
const subFiles = fs
.readdirSync(file)
.map((subfile) => path.join(file, subfile));
load(...subFiles);
}
};
if (esMain(import.meta)) {
if (process.argv[2]) {
load(process.argv[2]);
} else {
load(
'api',
'css',
'html',
'http',
'svg',
'javascript',
'mathml',
'test',
'webassembly',
'webdriver',
'webextensions',
);
}
}