| /* 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 { dataFoldersMinusBrowsers } from '../lib/data-folders.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(...dataFoldersMinusBrowsers); |
| } |
| } |