diff --git a/scripts/fix/index.js b/scripts/fix/index.js index 8187d6762afcd6..0aacafca827541 100644 --- a/scripts/fix/index.js +++ b/scripts/fix/index.js @@ -9,6 +9,7 @@ import esMain from 'es-main'; import fixBrowserOrder from './browser-order.js'; import fixFeatureOrder from './feature-order.js'; import fixLinks from './links.js'; +import fixStatus from './status.js'; const dirname = fileURLToPath(new URL('.', import.meta.url)); @@ -34,6 +35,7 @@ function load(...files) { fixBrowserOrder(file); fixFeatureOrder(file); fixLinks(file); + fixStatus(file); } continue; diff --git a/scripts/fix/status.js b/scripts/fix/status.js new file mode 100644 index 00000000000000..97f83f798de4f5 --- /dev/null +++ b/scripts/fix/status.js @@ -0,0 +1,38 @@ +/* This file is a part of @mdn/browser-compat-data + * See LICENSE file for more information. */ + +import { readFileSync, writeFileSync } from 'node:fs'; + +import { IS_WINDOWS } from '../../test/utils.js'; + +const fixStatusContradiction = (key, value) => { + const status = value?.__compat?.status; + if (status && status.experimental && status.deprecated) { + status.experimental = false; + } + return value; +}; + +/** + * @param {Promise} filename + */ +const fixStatus = (filename) => { + let actual = readFileSync(filename, 'utf-8').trim(); + let expected = JSON.stringify( + JSON.parse(actual, fixStatusContradiction), + null, + 2, + ); + + if (IS_WINDOWS) { + // prevent false positives from git.core.autocrlf on Windows + actual = actual.replace(/\r/g, ''); + expected = expected.replace(/\r/g, ''); + } + + if (actual !== expected) { + writeFileSync(filename, expected + '\n', 'utf-8'); + } +}; + +export default fixStatus; diff --git a/test/lint.js b/test/lint.js index 08075063f3e551..a4fab00c8149db 100644 --- a/test/lint.js +++ b/test/lint.js @@ -20,6 +20,7 @@ import { testNotes, testPrefix, testSchema, + testStatus, testStyle, testVersions, } from './linter/index.js'; @@ -95,6 +96,7 @@ const checkFiles = (...files) => { testConsistency(fileData); testDescriptions(fileData); testPrefix(fileData, filePath); + testStatus(fileData); testStyle(rawFileData); testVersions(fileData); testNotes(fileData); diff --git a/test/linter/index.js b/test/linter/index.js index f89a3b5e34f3fc..3fa43baf1dcda0 100644 --- a/test/linter/index.js +++ b/test/linter/index.js @@ -9,6 +9,7 @@ import testLinks from './test-links.js'; import testNotes from './test-notes.js'; import testPrefix from './test-prefix.js'; import testSchema from './test-schema.js'; +import testStatus from './test-status.js'; import testStyle from './test-style.js'; import testVersions from './test-versions.js'; @@ -21,6 +22,7 @@ export { testNotes, testPrefix, testSchema, + testStatus, testStyle, testVersions, }; diff --git a/test/linter/test-status.js b/test/linter/test-status.js new file mode 100644 index 00000000000000..2f308c95c107c3 --- /dev/null +++ b/test/linter/test-status.js @@ -0,0 +1,46 @@ +/* This file is a part of @mdn/browser-compat-data + * See LICENSE file for more information. */ + +import chalk from 'chalk-template'; +import { Logger } from '../utils.js'; + +/** + * @typedef {import('../../types').Identifier} Identifier + */ + +/** + * @param {Identifier} data + * @param {Logger} logger + */ +function checkStatus(data, logger, path = []) { + const status = data.__compat?.status; + if (status && status.experimental && status.deprecated) { + logger.error( + chalk`{red Unexpected simultaneous experimental and deprecated status in ${path.join( + '.', + )}}`, + chalk`Run {bold npm run fix} to fix this issue automatically`, + ); + } + for (const member in data) { + if (member === '__compat') { + continue; + } + checkStatus(data[member], logger, [...path, member]); + } +} + +/** + * @param {Identifier} data The contents of the file to test + * @returns {boolean} If the file contains errors + */ +function testStatusContradiction(data) { + const logger = new Logger('Status'); + + checkStatus(data, logger); + + logger.emit(); + return logger.hasErrors(); +} + +export default testStatusContradiction;