ci: browser compatibility linting (#19132)

This commit is contained in:
Zack Pollard 2025-06-13 15:54:59 +01:00 committed by GitHub
parent de756d9497
commit e2dfbd66c3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 140 additions and 2 deletions

5
web/.browserslistrc Normal file
View File

@ -0,0 +1,5 @@
> 0.2% and last 4 major versions
> 0.5%
not dead
edge >= 135
not edge < 135

View File

@ -1,4 +1,6 @@
import js from '@eslint/js';
import tslintPluginCompat from '@koddsson/eslint-plugin-tscompat';
import eslintPluginCompat from 'eslint-plugin-compat';
import eslintPluginSvelte from 'eslint-plugin-svelte';
import eslintPluginUnicorn from 'eslint-plugin-unicorn';
import globals from 'globals';
@ -14,6 +16,37 @@ export default typescriptEslint.config(
...eslintPluginSvelte.configs.recommended,
eslintPluginUnicorn.configs.recommended,
js.configs.recommended,
{
plugins: {
tscompat: tslintPluginCompat,
},
rules: {
'tscompat/tscompat': [
'error',
{ browserslist: ['> 0.2% and last 4 major versions', '> 0.5%', 'not dead', 'edge >= 135', 'not edge < 135'] },
],
},
languageOptions: {
parser,
parserOptions: {
project: ['./tsconfig.json'],
tsconfigRootDir: __dirname,
},
},
ignores: ['**/service-worker/**'],
},
{
plugins: {
compat: eslintPluginCompat,
},
settings: {
polyfills: [],
lintAllEsApis: true,
},
rules: {
'compat/compat': 'error',
},
},
{
ignores: [
'**/.DS_Store',

83
web/package-lock.json generated
View File

@ -42,6 +42,7 @@
"@eslint/eslintrc": "^3.1.0",
"@eslint/js": "^9.18.0",
"@faker-js/faker": "^9.3.0",
"@koddsson/eslint-plugin-tscompat": "^0.2.0",
"@socket.io/component-emitter": "^3.1.0",
"@sveltejs/adapter-static": "^3.0.8",
"@sveltejs/enhanced-img": "^0.6.0",
@ -63,6 +64,7 @@
"eslint": "^9.18.0",
"eslint-config-prettier": "^10.0.0",
"eslint-p": "^0.23.0",
"eslint-plugin-compat": "^6.0.2",
"eslint-plugin-svelte": "^3.9.0",
"eslint-plugin-unicorn": "^59.0.0",
"factory.ts": "^1.4.1",
@ -74,6 +76,7 @@
"rollup-plugin-visualizer": "^6.0.0",
"svelte": "^5.25.3",
"svelte-check": "^4.1.5",
"svelte-eslint-parser": "^1.2.0",
"tailwindcss": "^4.1.7",
"tslib": "^2.6.2",
"typescript": "^5.7.3",
@ -1537,6 +1540,26 @@
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
"node_modules/@koddsson/eslint-plugin-tscompat": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/@koddsson/eslint-plugin-tscompat/-/eslint-plugin-tscompat-0.2.0.tgz",
"integrity": "sha512-Oqd4kWSX0LiO9wWHjcmDfXZNC7TotFV/tLRhwCFU3XUeb//KYvJ75c9OmeSJ+vBv5lkCeB+xYsqyNrBc5j18XA==",
"dev": true,
"license": "ISC",
"dependencies": {
"@mdn/browser-compat-data": "^6.0.17",
"@typescript-eslint/type-utils": "^8.0.1",
"@typescript-eslint/utils": "^8.0.0",
"browserslist": "^4.23.0"
}
},
"node_modules/@koddsson/eslint-plugin-tscompat/node_modules/@mdn/browser-compat-data": {
"version": "6.0.22",
"resolved": "https://registry.npmjs.org/@mdn/browser-compat-data/-/browser-compat-data-6.0.22.tgz",
"integrity": "sha512-zhgOBTouJOd8IbE5dEEcfzg83l+nxKL/7Ru2HPeCVbog9I0JGHg3QZab9IxZquKFTUsc+c7QqU4EVENeZzZWRg==",
"dev": true,
"license": "CC0-1.0"
},
"node_modules/@mapbox/geojson-rewind": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/@mapbox/geojson-rewind/-/geojson-rewind-0.5.2.tgz",
@ -1687,6 +1710,13 @@
"integrity": "sha512-KPnNOtm5i2pMabqZxpUz7iQf+mfrYZyKCZ8QNz85czgEt7cuHcGorWfdzUMWYA0SD+a6Hn4FmJ+YhzzzjkTZrQ==",
"license": "Apache-2.0"
},
"node_modules/@mdn/browser-compat-data": {
"version": "5.7.6",
"resolved": "https://registry.npmjs.org/@mdn/browser-compat-data/-/browser-compat-data-5.7.6.tgz",
"integrity": "sha512-7xdrMX0Wk7grrTZQwAoy1GkvPMFoizStUoL+VmtUkAxegbCCec+3FKwOM6yc/uGU5+BEczQHXAlWiqvM8JeENg==",
"dev": true,
"license": "CC0-1.0"
},
"node_modules/@namnode/store": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/@namnode/store/-/store-0.1.0.tgz",
@ -3505,6 +3535,16 @@
"node": ">=12"
}
},
"node_modules/ast-metadata-inferer": {
"version": "0.8.1",
"resolved": "https://registry.npmjs.org/ast-metadata-inferer/-/ast-metadata-inferer-0.8.1.tgz",
"integrity": "sha512-ht3Dm6Zr7SXv6t1Ra6gFo0+kLDglHGrEbYihTkcycrbHw7WCcuhBzPlJYHEsIpycaUwzsJHje+vUcxXUX4ztTA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@mdn/browser-compat-data": "^5.6.19"
}
},
"node_modules/asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
@ -4717,6 +4757,42 @@
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
}
},
"node_modules/eslint-plugin-compat": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/eslint-plugin-compat/-/eslint-plugin-compat-6.0.2.tgz",
"integrity": "sha512-1ME+YfJjmOz1blH0nPZpHgjMGK4kjgEeoYqGCqoBPQ/mGu/dJzdoP0f1C8H2jcWZjzhZjAMccbM/VdXhPORIfA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@mdn/browser-compat-data": "^5.5.35",
"ast-metadata-inferer": "^0.8.1",
"browserslist": "^4.24.2",
"caniuse-lite": "^1.0.30001687",
"find-up": "^5.0.0",
"globals": "^15.7.0",
"lodash.memoize": "^4.1.2",
"semver": "^7.6.2"
},
"engines": {
"node": ">=18.x"
},
"peerDependencies": {
"eslint": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0"
}
},
"node_modules/eslint-plugin-compat/node_modules/globals": {
"version": "15.15.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-15.15.0.tgz",
"integrity": "sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/eslint-plugin-svelte": {
"version": "3.9.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-svelte/-/eslint-plugin-svelte-3.9.0.tgz",
@ -6494,6 +6570,13 @@
"integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==",
"license": "MIT"
},
"node_modules/lodash.memoize": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
"integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==",
"dev": true,
"license": "MIT"
},
"node_modules/lodash.merge": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",

View File

@ -59,6 +59,7 @@
"@eslint/eslintrc": "^3.1.0",
"@eslint/js": "^9.18.0",
"@faker-js/faker": "^9.3.0",
"@koddsson/eslint-plugin-tscompat": "^0.2.0",
"@socket.io/component-emitter": "^3.1.0",
"@sveltejs/adapter-static": "^3.0.8",
"@sveltejs/enhanced-img": "^0.6.0",
@ -80,6 +81,7 @@
"eslint": "^9.18.0",
"eslint-config-prettier": "^10.0.0",
"eslint-p": "^0.23.0",
"eslint-plugin-compat": "^6.0.2",
"eslint-plugin-svelte": "^3.9.0",
"eslint-plugin-unicorn": "^59.0.0",
"factory.ts": "^1.4.1",
@ -91,6 +93,7 @@
"rollup-plugin-visualizer": "^6.0.0",
"svelte": "^5.25.3",
"svelte-check": "^4.1.5",
"svelte-eslint-parser": "^1.2.0",
"tailwindcss": "^4.1.7",
"tslib": "^2.6.2",
"typescript": "^5.7.3",

View File

@ -300,8 +300,10 @@
const handleStopSlideshow = async () => {
try {
// eslint-disable-next-line tscompat/tscompat
if (document.fullscreenElement) {
document.body.style.cursor = '';
// eslint-disable-next-line tscompat/tscompat
await document.exitFullscreen();
}
} catch (error) {

View File

@ -57,6 +57,7 @@
canvas = new Canvas(canvasEl);
configureControlStyle();
// eslint-disable-next-line tscompat/tscompat
faceRect = new Rect({
fill: 'rgba(66,80,175,0.25)',
stroke: 'rgb(66,80,175)',

View File

@ -101,7 +101,9 @@
};
const onShowSettings = async () => {
// eslint-disable-next-line tscompat/tscompat
if (document.fullscreenElement) {
// eslint-disable-next-line tscompat/tscompat
await document.exitFullscreen();
}
await modalManager.show(SlideshowSettingsModal);

View File

@ -51,6 +51,7 @@
const entries: FileSystemEntry[] = [];
const files: File[] = [];
for (const item of dataTransfer.items) {
// eslint-disable-next-line tscompat/tscompat
const entry = item.webkitGetAsEntry();
if (entry) {
entries.push(entry);
@ -67,6 +68,7 @@
return handleFiles([...files, ...directoryFiles]);
};
// eslint-disable-next-line tscompat/tscompat
const browserSupportsDirectoryUpload = () => typeof DataTransferItem.prototype.webkitGetAsEntry === 'function';
const getAllFilesFromTransferEntries = async (transferEntries: FileSystemEntry[]): Promise<File[]> => {

View File

@ -310,6 +310,7 @@
void onScrub?.(segmentDate!, scrollPercent, monthGroupPercentY);
};
/* eslint-disable tscompat/tscompat */
const getTouch = (event: TouchEvent) => {
if (event.touches.length === 1) {
return event.touches[0];
@ -354,6 +355,7 @@
isHover = false;
}
};
/* eslint-enable tscompat/tscompat */
onMount(() => {
document.addEventListener('touchmove', onTouchMove, true);
return () => {

View File

@ -470,7 +470,11 @@ export class TimelineManager {
},
{ order: this.#options.order ?? AssetOrder.Desc },
);
return unprocessedIds.values().map((id) => lookup.get(id)!);
const result: TimelineAsset[] = [];
for (const id of unprocessedIds.values()) {
result.push(lookup.get(id)!);
}
return result;
}
removeAssets(ids: string[]) {

View File

@ -40,7 +40,8 @@ export function currentUrlReplaceAssetId(assetId: string) {
const params = new URLSearchParams($page.url.search);
// always remove the assetGridScrollTargetParams
params.delete('at');
const searchparams = params.size > 0 ? '?' + params.toString() : '';
const paramsString = params.toString();
const searchparams = paramsString == '' ? '' : '?' + params.toString();
// this contains special casing for the /photos/:assetId photos route, which hangs directly
// off / instead of a subpath, unlike every other asset-containing route.
return isPhotosRoute($page.route.id)