From 4efd6526694feb051b16d277dadc20de90118b57 Mon Sep 17 00:00:00 2001 From: Claas Augner Date: Fri, 17 Oct 2025 18:22:52 +0200 Subject: [PATCH 1/5] feat(mirror): ignore OS limitations when mirroring to mobile --- scripts/build/mirror.test.ts | 69 +++++++++++++++++++++++++++++++++++- scripts/build/mirror.ts | 53 ++++++++++++++++++++++++++- 2 files changed, 120 insertions(+), 2 deletions(-) diff --git a/scripts/build/mirror.test.ts b/scripts/build/mirror.test.ts index 6a6a5a33269aba..8f4986fe588fda 100644 --- a/scripts/build/mirror.test.ts +++ b/scripts/build/mirror.test.ts @@ -7,9 +7,44 @@ import { BrowserName } from '../../types/types.js'; import bcd from '../../index.js'; import { InternalSupportBlock } from '../../types/index.js'; -import mirrorSupport from './mirror.js'; +import mirrorSupport, { isOSLimitation } from './mirror.js'; describe('mirror', () => { + describe('isOSLimitation', () => { + it('returns true for OS limitation notes', () => { + assert.equal( + isOSLimitation('Supported on ChromeOS, macOS, and Windows only.'), + true, + ); + assert.equal( + isOSLimitation('Supported on Linux and Windows only.'), + true, + ); + assert.equal(isOSLimitation('Supported on macOS only.'), true); + assert.equal(isOSLimitation('Not supported on Windows.'), true); + assert.equal(isOSLimitation('Not yet supported on macOS.'), true); + }); + + it('returns false for non-OS-limitation notes', () => { + assert.equal( + isOSLimitation('This feature requires a flag to be enabled.'), + false, + ); + assert.equal( + isOSLimitation('Before version 70, this method always returned true.'), + false, + ); + assert.equal( + isOSLimitation('Firefox 73 added support for this thing.'), + false, + ); + }); + + it('returns false for empty string', () => { + assert.equal(isOSLimitation(''), false); + }); + }); + describe('default export', () => { describe('version numbers match expected values', () => { const mappings: { @@ -189,6 +224,38 @@ describe('mirror', () => { notes: 'This feature is only supported in ChromeOS, macOS and Linux.', }); }); + + it('OS-specific partial_implementation and notes are not mirrored', () => { + const support = { + chrome: { + version_added: '134', + partial_implementation: true, + notes: 'Supported on ChromeOS, macOS, and Windows only.', + }, + }; + + const mirrored = mirrorSupport('chrome_android', support); + assert.deepEqual(mirrored, { + version_added: '134', + }); + }); + + it('Non-OS-specific partial_implementation and notes are still mirrored', () => { + const support = { + chrome: { + version_added: '70', + partial_implementation: true, + notes: 'This feature is incomplete and may not work as expected.', + }, + }; + + const mirrored = mirrorSupport('chrome_android', support); + assert.deepEqual(mirrored, { + version_added: '70', + partial_implementation: true, + notes: 'This feature is incomplete and may not work as expected.', + }); + }); }); describe('Validations', () => { diff --git a/scripts/build/mirror.ts b/scripts/build/mirror.ts index dd8408c36e038e..3e8e2f9b05ed58 100644 --- a/scripts/build/mirror.ts +++ b/scripts/build/mirror.ts @@ -16,7 +16,33 @@ const { browsers } = bcd; type Notes = string | [string, string, ...string[]] | null; /** + * Check if a note indicates OS-specific limitations. + * @param notes A single notes string from a support statement + * @returns True if the notes indicate OS-specific limitations */ +export const isOSLimitation = (notes: string): boolean => { + const words = notes + .split(/\s+/) + .map((word) => word.toLowerCase().replace(/[,.;:!?]$/g, '')); // Remove trailing punctuation + + if (words.length === 0) { + return false; + } + + const os = ['chromeos', 'linux', 'macos', 'windows']; + const expectedWords = ['supported', 'on', 'only', 'not', 'yet', 'and']; + + let hasOSKeyword = false; + for (const word of words) { + if (os.includes(word)) { + hasOSKeyword = true; + } else if (!expectedWords.includes(word)) { + return false; + } + } + + return hasOSKeyword; +}; const matchingSafariVersions = new Map([ ['1', '1'], @@ -215,6 +241,30 @@ export const bumpSupport = ( const newData: SimpleSupportStatement = copyStatement(sourceData); + if ( + browsers[sourceBrowser].type === 'desktop' && + browsers[destination].type === 'mobile' && + sourceData.partial_implementation + ) { + const notes = Array.isArray(sourceData.notes) + ? sourceData.notes + : sourceData.notes + ? [sourceData.notes] + : []; + const [firstNote, secondNote, ...otherNotes] = notes.filter( + (notes) => !isOSLimitation(notes), + ); + if (!firstNote) { + // Ignore OS limitation. + delete newData.partial_implementation; + delete newData.notes; + } else if (!secondNote) { + newData.notes = firstNote; + } else { + newData.notes = [firstNote, secondNote, ...otherNotes]; + } + } + if (!browsers[destination].accepts_flags && newData.flags) { // Remove flag data if the target browser doesn't accept flags return { version_added: false }; @@ -254,7 +304,8 @@ export const bumpSupport = ( return { version_added: false }; } - if (sourceData.notes) { + // Only process notes if they weren't already removed (e.g., for OS-specific limitations) + if (sourceData.notes && newData.notes !== undefined) { const sourceBrowserName = sourceBrowser === 'chrome' ? '(Google )?Chrome' From 36be133f2298022647f9553d2e19410bb01689a1 Mon Sep 17 00:00:00 2001 From: Claas Augner Date: Fri, 17 Oct 2025 18:23:29 +0200 Subject: [PATCH 2/5] Run `npm run lint:fix` --- api/GPUAdapter.json | 8 ++------ api/GPUCommandEncoder.json | 20 +++++--------------- api/GPUDevice.json | 24 ++++++------------------ api/GPUQuerySet.json | 4 +--- api/GPUSupportedFeatures.json | 8 ++------ api/GPUTexture.json | 4 +--- 6 files changed, 17 insertions(+), 51 deletions(-) diff --git a/api/GPUAdapter.json b/api/GPUAdapter.json index e68fdaba7cc106..8a86252d300bf3 100644 --- a/api/GPUAdapter.json +++ b/api/GPUAdapter.json @@ -128,9 +128,7 @@ "partial_implementation": true, "notes": "Supported on ChromeOS, macOS, and Windows only." }, - "chrome_android": { - "version_added": "127" - }, + "chrome_android": "mirror", "edge": "mirror", "firefox": { "version_added": "141", @@ -437,9 +435,7 @@ "partial_implementation": true, "notes": "Supported on ChromeOS, macOS, and Windows only." }, - "chrome_android": { - "version_added": "133" - }, + "chrome_android": "mirror", "deno": { "version_added": false }, diff --git a/api/GPUCommandEncoder.json b/api/GPUCommandEncoder.json index cb50be45a7b13a..64450b756fe6df 100644 --- a/api/GPUCommandEncoder.json +++ b/api/GPUCommandEncoder.json @@ -127,9 +127,7 @@ "partial_implementation": true, "notes": "Supported on ChromeOS, macOS, and Windows only." }, - "chrome_android": { - "version_added": "121" - }, + "chrome_android": "mirror", "deno": { "version_added": false }, @@ -227,9 +225,7 @@ "partial_implementation": true, "notes": "Supported on ChromeOS, macOS, and Windows only." }, - "chrome_android": { - "version_added": "125" - }, + "chrome_android": "mirror", "deno": { "version_added": false }, @@ -268,9 +264,7 @@ "partial_implementation": true, "notes": "Supported on ChromeOS, macOS, and Windows only." }, - "chrome_android": { - "version_added": "123" - }, + "chrome_android": "mirror", "deno": { "version_added": false }, @@ -310,9 +304,7 @@ "partial_implementation": true, "notes": "Supported on ChromeOS, macOS, and Windows only." }, - "chrome_android": { - "version_added": "121" - }, + "chrome_android": "mirror", "deno": { "version_added": false }, @@ -467,9 +459,7 @@ "partial_implementation": true, "notes": "Supported on ChromeOS, macOS, and Windows only." }, - "chrome_android": { - "version_added": "137" - }, + "chrome_android": "mirror", "deno": { "version_added": false }, diff --git a/api/GPUDevice.json b/api/GPUDevice.json index 7eaec51ef69995..926f181f45db15 100644 --- a/api/GPUDevice.json +++ b/api/GPUDevice.json @@ -167,9 +167,7 @@ "partial_implementation": true, "notes": "Supported on ChromeOS, macOS, and Windows only." }, - "chrome_android": { - "version_added": "137" - }, + "chrome_android": "mirror", "deno": { "version_added": false }, @@ -716,9 +714,7 @@ "partial_implementation": true, "notes": "Supported on ChromeOS, macOS, and Windows only." }, - "chrome_android": { - "version_added": "135" - }, + "chrome_android": "mirror", "deno": { "version_added": false }, @@ -816,9 +812,7 @@ "partial_implementation": true, "notes": "Supported on ChromeOS, macOS, and Windows only." }, - "chrome_android": { - "version_added": "121" - }, + "chrome_android": "mirror", "deno": { "version_added": false }, @@ -974,9 +968,7 @@ "partial_implementation": true, "notes": "Supported on ChromeOS, macOS, and Windows only." }, - "chrome_android": { - "version_added": "130" - }, + "chrome_android": "mirror", "deno": { "version_added": false }, @@ -1277,9 +1269,7 @@ "partial_implementation": true, "notes": "Supported on ChromeOS, macOS, and Windows only." }, - "chrome_android": { - "version_added": "130" - }, + "chrome_android": "mirror", "deno": { "version_added": false }, @@ -1899,9 +1889,7 @@ "partial_implementation": true, "notes": "Supported on ChromeOS, macOS, and Windows only." }, - "chrome_android": { - "version_added": "121" - }, + "chrome_android": "mirror", "deno": { "version_added": false }, diff --git a/api/GPUQuerySet.json b/api/GPUQuerySet.json index 2acf454b5187c9..3ab300baef4819 100644 --- a/api/GPUQuerySet.json +++ b/api/GPUQuerySet.json @@ -301,9 +301,7 @@ "partial_implementation": true, "notes": "Supported on ChromeOS, macOS, and Windows only." }, - "chrome_android": { - "version_added": "121" - }, + "chrome_android": "mirror", "deno": { "version_added": false }, diff --git a/api/GPUSupportedFeatures.json b/api/GPUSupportedFeatures.json index 5a7dc06b04605e..b5b2c3ff4cc05a 100644 --- a/api/GPUSupportedFeatures.json +++ b/api/GPUSupportedFeatures.json @@ -862,9 +862,7 @@ "partial_implementation": true, "notes": "Supported on ChromeOS, macOS, and Windows only." }, - "chrome_android": { - "version_added": "142" - }, + "chrome_android": "mirror", "deno": { "version_added": false }, @@ -904,9 +902,7 @@ "partial_implementation": true, "notes": "Supported on ChromeOS, macOS, and Windows only." }, - "chrome_android": { - "version_added": "142" - }, + "chrome_android": "mirror", "deno": { "version_added": false }, diff --git a/api/GPUTexture.json b/api/GPUTexture.json index 9205a57dee9670..646d4b7783f9c7 100644 --- a/api/GPUTexture.json +++ b/api/GPUTexture.json @@ -169,9 +169,7 @@ "partial_implementation": true, "notes": "Supported on ChromeOS, macOS, and Windows only." }, - "chrome_android": { - "version_added": "132" - }, + "chrome_android": "mirror", "deno": { "version_added": false }, From 0199816580a52d268ff721a1842985027be6e8fa Mon Sep 17 00:00:00 2001 From: Claas Augner Date: Tue, 28 Oct 2025 17:41:56 +0100 Subject: [PATCH 3/5] fixup! feat(mirror): ignore OS limitations when mirroring to mobile --- scripts/build/mirror.test.ts | 5 ---- scripts/build/mirror.ts | 46 ++++++++++++++++++++---------------- 2 files changed, 25 insertions(+), 26 deletions(-) diff --git a/scripts/build/mirror.test.ts b/scripts/build/mirror.test.ts index 8f4986fe588fda..eb09fb953fbe2f 100644 --- a/scripts/build/mirror.test.ts +++ b/scripts/build/mirror.test.ts @@ -16,13 +16,8 @@ describe('mirror', () => { isOSLimitation('Supported on ChromeOS, macOS, and Windows only.'), true, ); - assert.equal( - isOSLimitation('Supported on Linux and Windows only.'), - true, - ); assert.equal(isOSLimitation('Supported on macOS only.'), true); assert.equal(isOSLimitation('Not supported on Windows.'), true); - assert.equal(isOSLimitation('Not yet supported on macOS.'), true); }); it('returns false for non-OS-limitation notes', () => { diff --git a/scripts/build/mirror.ts b/scripts/build/mirror.ts index 3e8e2f9b05ed58..3224e53ffc18b3 100644 --- a/scripts/build/mirror.ts +++ b/scripts/build/mirror.ts @@ -15,33 +15,37 @@ const { browsers } = bcd; type Notes = string | [string, string, ...string[]] | null; +const OS_NOTES = [ + 'Available on macOS and Windows only.', + 'Available only on macOS.', + 'ChromeOS only', + 'ChromeOS and Windows', + 'Fully supported on Windows and Linux, no support on ChromeOS.', + 'Linux support is not enabled by default.', + 'Not supported on macOS.', + 'Not supported on Windows.', + 'Only on macOS and Windows.', + 'Only on Windows.', + 'Only supported on ChromeOS', + 'Only supported on macOS.', + 'Only supported on Windows.', + 'Only works on macOS.', + 'Supported on ChromeOS, macOS, and Windows only.', + 'Supported on ChromeOS and macOS only.', + 'Supported on macOS only.', + 'Supported on macOS Catalina 10.15.1+, Windows, and ChromeOS. Not yet supported on Linux.', + 'Supported on Windows only, in all contexts except for service workers.', + 'Supported only on macOS 10.12 (Sierra) and later.', + 'This cursor is only supported on macOS and Linux.', +].map((s) => s.toLowerCase()); + /** * Check if a note indicates OS-specific limitations. * @param notes A single notes string from a support statement * @returns True if the notes indicate OS-specific limitations */ export const isOSLimitation = (notes: string): boolean => { - const words = notes - .split(/\s+/) - .map((word) => word.toLowerCase().replace(/[,.;:!?]$/g, '')); // Remove trailing punctuation - - if (words.length === 0) { - return false; - } - - const os = ['chromeos', 'linux', 'macos', 'windows']; - const expectedWords = ['supported', 'on', 'only', 'not', 'yet', 'and']; - - let hasOSKeyword = false; - for (const word of words) { - if (os.includes(word)) { - hasOSKeyword = true; - } else if (!expectedWords.includes(word)) { - return false; - } - } - - return hasOSKeyword; + return OS_NOTES.includes(notes.toLowerCase()); }; const matchingSafariVersions = new Map([ From 94e67e4ece9ea8c0b0b2a71b3d2facc9df743e9e Mon Sep 17 00:00:00 2001 From: Claas Augner Date: Tue, 28 Oct 2025 17:48:43 +0100 Subject: [PATCH 4/5] Run `npm run fix` once --- api/GPUDevice.json | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/api/GPUDevice.json b/api/GPUDevice.json index 9e89b95e1449e5..8b108dff16d50b 100644 --- a/api/GPUDevice.json +++ b/api/GPUDevice.json @@ -167,9 +167,7 @@ "partial_implementation": true, "notes": "Supported on ChromeOS, macOS, and Windows only." }, - "chrome_android": { - "version_added": "138" - }, + "chrome_android": "mirror", "deno": { "version_added": false }, From 9815f158e79c94406a340b063b62881c83e8e157 Mon Sep 17 00:00:00 2001 From: Claas Augner Date: Tue, 4 Nov 2025 12:11:48 +0100 Subject: [PATCH 5/5] Run `npm run lint:fix` --- api/GPUCommandEncoder.json | 4 +--- api/GPUDevice.json | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/api/GPUCommandEncoder.json b/api/GPUCommandEncoder.json index 5fbd1224c9e587..2c1d336c4ffecc 100644 --- a/api/GPUCommandEncoder.json +++ b/api/GPUCommandEncoder.json @@ -224,9 +224,7 @@ "partial_implementation": true, "notes": "Supported on ChromeOS, macOS, and Windows only." }, - "chrome_android": { - "version_added": "140" - }, + "chrome_android": "mirror", "deno": { "version_added": false }, diff --git a/api/GPUDevice.json b/api/GPUDevice.json index 7b2b34f08d3f61..0dced8188ca013 100644 --- a/api/GPUDevice.json +++ b/api/GPUDevice.json @@ -206,9 +206,7 @@ "partial_implementation": true, "notes": "Supported on ChromeOS, macOS, and Windows only." }, - "chrome_android": { - "version_added": "140" - }, + "chrome_android": "mirror", "deno": { "version_added": false },