From dc1205a27c7288658c4e4572a2f1a24f8a66cb36 Mon Sep 17 00:00:00 2001 From: Florian Scholz Date: Thu, 9 Jan 2025 13:55:54 +0100 Subject: [PATCH] Allowlist web-feature tags (#25614) --- api/Request.json | 3 --- api/WebSocketError.json | 4 ---- api/WebSocketStream.json | 18 ------------------ html/elements/script.json | 3 --- lint/linter/test-tags.test.ts | 12 ++++++++---- lint/linter/test-tags.ts | 28 ++++++++++++++++++++-------- package-lock.json | 8 ++++++++ package.json | 1 + 8 files changed, 37 insertions(+), 40 deletions(-) diff --git a/api/Request.json b/api/Request.json index 54892ca22b6b18..da707ce0eb4b93 100644 --- a/api/Request.json +++ b/api/Request.json @@ -236,9 +236,6 @@ "description": "`init.keepalive` parameter", "mdn_url": "https://developer.mozilla.org/docs/Web/API/Request/keepalive", "spec_url": "https://fetch.spec.whatwg.org/#dom-requestinit-keepalive", - "tags": [ - "web-features:fetch-keepalive" - ], "support": { "chrome": { "version_added": "66" diff --git a/api/WebSocketError.json b/api/WebSocketError.json index 9a59f9a7c82803..bbb76359badb7e 100644 --- a/api/WebSocketError.json +++ b/api/WebSocketError.json @@ -3,7 +3,6 @@ "WebSocketError": { "__compat": { "tags": [ - "web-features:web-socket-stream", "web-features:websockets" ], "support": { @@ -40,7 +39,6 @@ "__compat": { "description": "`WebSocketError()` constructor", "tags": [ - "web-features:web-socket-stream", "web-features:websockets" ], "support": { @@ -77,7 +75,6 @@ "closeCode": { "__compat": { "tags": [ - "web-features:web-socket-stream", "web-features:websockets" ], "support": { @@ -114,7 +111,6 @@ "reason": { "__compat": { "tags": [ - "web-features:web-socket-stream", "web-features:websockets" ], "support": { diff --git a/api/WebSocketStream.json b/api/WebSocketStream.json index 730daef83c3445..cce124f61c74e0 100644 --- a/api/WebSocketStream.json +++ b/api/WebSocketStream.json @@ -3,9 +3,6 @@ "WebSocketStream": { "__compat": { "mdn_url": "https://developer.mozilla.org/docs/Web/API/WebSocketStream", - "tags": [ - "web-features:web-socket-stream" - ], "support": { "chrome": { "version_added": "124" @@ -40,9 +37,6 @@ "__compat": { "description": "`WebSocketStream()` constructor", "mdn_url": "https://developer.mozilla.org/docs/Web/API/WebSocketStream/WebSocketStream", - "tags": [ - "web-features:web-socket-stream" - ], "support": { "chrome": { "version_added": "124" @@ -77,9 +71,6 @@ "close": { "__compat": { "mdn_url": "https://developer.mozilla.org/docs/Web/API/WebSocketStream/close", - "tags": [ - "web-features:web-socket-stream" - ], "support": { "chrome": { "version_added": "124" @@ -114,9 +105,6 @@ "closed": { "__compat": { "mdn_url": "https://developer.mozilla.org/docs/Web/API/WebSocketStream/closed", - "tags": [ - "web-features:web-socket-stream" - ], "support": { "chrome": { "version_added": "124" @@ -151,9 +139,6 @@ "opened": { "__compat": { "mdn_url": "https://developer.mozilla.org/docs/Web/API/WebSocketStream/opened", - "tags": [ - "web-features:web-socket-stream" - ], "support": { "chrome": { "version_added": "124" @@ -188,9 +173,6 @@ "url": { "__compat": { "mdn_url": "https://developer.mozilla.org/docs/Web/API/WebSocketStream/url", - "tags": [ - "web-features:web-socket-stream" - ], "support": { "chrome": { "version_added": "124" diff --git a/html/elements/script.json b/html/elements/script.json index 6755d888e48fcd..70abbfc5c32b1d 100644 --- a/html/elements/script.json +++ b/html/elements/script.json @@ -641,9 +641,6 @@ "integrity": { "__compat": { "spec_url": "https://html.spec.whatwg.org/multipage/webappapis.html#normalizing-a-module-integrity-map", - "tags": [ - "web-features:import-map-integrity" - ], "support": { "chrome": { "version_added": "127" diff --git a/lint/linter/test-tags.test.ts b/lint/linter/test-tags.test.ts index f8ffd1ef57eec5..c3ae6bcf102171 100644 --- a/lint/linter/test-tags.test.ts +++ b/lint/linter/test-tags.test.ts @@ -28,7 +28,7 @@ describe('test.check', () => { it('should not log error when tags are valid', () => { const data: CompatStatement = { - tags: ['web-features:tag1'], + tags: ['web-features:javascript'], support: {}, }; @@ -61,15 +61,19 @@ describe('test.check', () => { assert.ok(logger.messages[0].message.includes('Invalid tag found:')); }); - it('should log error when tag name uses characters other than lowercase alphanumeric and hyphen', () => { + it('should log an error when an invalid web-feature ID is used', () => { const data: CompatStatement = { - tags: ['namespace1:tag$'], + tags: ['web-features:foo'], support: {}, }; test.check(logger, { data }); assert.equal(logger.messages.length, 1); - assert.ok(logger.messages[0].message.includes('Invalid tag found:')); + assert.ok( + logger.messages[0].message.includes( + 'Non-registered web-features ID found:', + ), + ); }); }); diff --git a/lint/linter/test-tags.ts b/lint/linter/test-tags.ts index 4a4f44e0a3e907..14452d7cc74166 100644 --- a/lint/linter/test-tags.ts +++ b/lint/linter/test-tags.ts @@ -2,11 +2,13 @@ * See LICENSE file for more information. */ import chalk from 'chalk-template'; +import { features } from 'web-features'; import { Linter, Logger, LinterData } from '../utils.js'; import { CompatStatement } from '../../types/types.js'; const allowedNamespaces = ['web-features']; +const validFeatureIDs = Object.keys(features); /** * Process the data for spec URL errors @@ -20,19 +22,29 @@ const processData = (data: CompatStatement, logger: Logger): void => { for (const tag of data.tags) { if ( - !allowedNamespaces.some( - (namespace) => - tag.startsWith(namespace + ':') && - tag.split(':')[1].match(/^[a-z0-9-]*$/), - ) + !allowedNamespaces.some((namespace) => tag.startsWith(namespace + ':')) ) { logger.error( chalk`Invalid tag found: {bold ${tag}}. Check if: - - tag tag has a namespace - - the tag uses one of the allowed namespaces: {bold ${allowedNamespaces}} - - the tag name (after the namespace) uses only lowercase alphanumeric characters (a-z and 0-9) plus the - character (hyphen or minus sign)`, + - the tag has a namespace + - the tag uses one of the allowed namespaces: {bold ${allowedNamespaces}}`, ); } + + if (tag.startsWith('web-features')) { + const featureID = tag.split(':').pop() as string; + + if ( + !tag.includes(':snapshot:') && // ignore web-feature snapshots for now + !validFeatureIDs.includes(featureID) + ) { + logger.error( + chalk`Non-registered web-features ID found: {bold ${featureID}}. + - New web-feature IDs need to be present in https://github.com/web-platform-dx/web-features first. + - Check for typos or remove tag. Tagging will be taken care of by web-features maintainers.`, + ); + } + } } }; diff --git a/package-lock.json b/package-lock.json index 52bbf08dac3a39..ff55c82af33f0a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -55,6 +55,7 @@ "tempy": "^3.1.0", "tsx": "^4.19.2", "typescript": "~5.7.2", + "web-features": "^2.15.0", "web-specs": "^3.0.0", "yargs": "~17.7.0" }, @@ -7999,6 +8000,13 @@ "spdx-license-ids": "^3.0.0" } }, + "node_modules/web-features": { + "version": "2.15.0", + "resolved": "https://registry.npmjs.org/web-features/-/web-features-2.15.0.tgz", + "integrity": "sha512-sTuDfFU2UgQmGT3VRNRb6h+nH1C0SxR6l4nUyQ3qGJPzqgc6SnsqkjZs0TRc2YtGN5ysJqWQRknkgibe11ffOQ==", + "dev": true, + "license": "Apache-2.0" + }, "node_modules/web-specs": { "version": "3.32.0", "resolved": "https://registry.npmjs.org/web-specs/-/web-specs-3.32.0.tgz", diff --git a/package.json b/package.json index 2dc1495af8b759..925cf23c992949 100644 --- a/package.json +++ b/package.json @@ -89,6 +89,7 @@ "tempy": "^3.1.0", "tsx": "^4.19.2", "typescript": "~5.7.2", + "web-features": "^2.15.0", "web-specs": "^3.0.0", "yargs": "~17.7.0" },