diff --git a/CHANGELOG.md b/CHANGELOG.md index a21793b07..6e1be837a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to ### Changed +- ⬆️ Bump eslint to V9 #1071 - ⚡️(frontend) improve accessibility: - #1248 - #1235 diff --git a/Makefile b/Makefile index 20ecdfae5..0c8df9ec6 100644 --- a/Makefile +++ b/Makefile @@ -372,6 +372,6 @@ bump-packages-version: ## bump the version of the project - VERSION_TYPE can be cd ./src/frontend/apps/e2e/ && yarn version --no-git-tag-version --$(VERSION_TYPE) cd ./src/frontend/apps/impress/ && yarn version --no-git-tag-version --$(VERSION_TYPE) cd ./src/frontend/servers/y-provider/ && yarn version --no-git-tag-version --$(VERSION_TYPE) - cd ./src/frontend/packages/eslint-config-impress/ && yarn version --no-git-tag-version --$(VERSION_TYPE) + cd ./src/frontend/packages/eslint-plugin-docs/ && yarn version --no-git-tag-version --$(VERSION_TYPE) cd ./src/frontend/packages/i18n/ && yarn version --no-git-tag-version --$(VERSION_TYPE) .PHONY: bump-packages-version diff --git a/renovate.json b/renovate.json index 0f1a43f64..6627d67bc 100644 --- a/renovate.json +++ b/renovate.json @@ -23,7 +23,6 @@ "@hocuspocus/provider", "@hocuspocus/server", "docx", - "eslint", "fetch-mock", "node", "node-fetch", diff --git a/src/frontend/Dockerfile b/src/frontend/Dockerfile index 2772dafdf..58552a87f 100644 --- a/src/frontend/Dockerfile +++ b/src/frontend/Dockerfile @@ -10,13 +10,13 @@ WORKDIR /home/frontend/ COPY ./src/frontend/package.json ./package.json COPY ./src/frontend/yarn.lock ./yarn.lock COPY ./src/frontend/apps/impress/package.json ./apps/impress/package.json -COPY ./src/frontend/packages/eslint-config-impress/package.json ./packages/eslint-config-impress/package.json +COPY ./src/frontend/packages/eslint-plugin-docs/package.json ./packages/eslint-plugin-docs/package.json RUN yarn install --frozen-lockfile COPY .dockerignore ./.dockerignore COPY ./src/frontend/.prettierrc.js ./.prettierrc.js -COPY ./src/frontend/packages/eslint-config-impress ./packages/eslint-config-impress +COPY ./src/frontend/packages/eslint-plugin-docs ./packages/eslint-plugin-docs COPY ./src/frontend/apps/impress ./apps/impress ### ---- Front-end builder image ---- diff --git a/src/frontend/apps/e2e/.eslintrc.js b/src/frontend/apps/e2e/.eslintrc.js deleted file mode 100644 index 46f10c31d..000000000 --- a/src/frontend/apps/e2e/.eslintrc.js +++ /dev/null @@ -1,9 +0,0 @@ -module.exports = { - root: true, - extends: ['impress/playwright'], - parserOptions: { - tsconfigRootDir: __dirname, - project: ['./tsconfig.json'], - }, - ignorePatterns: ['node_modules'], -}; diff --git a/src/frontend/apps/e2e/__tests__/app-impress/auth.setup.ts b/src/frontend/apps/e2e/__tests__/app-impress/auth.setup.ts index 2b7a4e043..b569b662d 100644 --- a/src/frontend/apps/e2e/__tests__/app-impress/auth.setup.ts +++ b/src/frontend/apps/e2e/__tests__/app-impress/auth.setup.ts @@ -5,14 +5,19 @@ import { keyCloakSignIn } from './utils-common'; const saveStorageState = async ( browserConfig: FullProject, ) => { - const browserName = browserConfig?.name || 'chromium'; + if (!browserConfig) { + throw new Error('No browser config found'); + } + + const browserName = browserConfig.name || 'chromium'; - const { storageState, ...useConfig } = browserConfig?.use; + const { storageState, ...useConfig } = browserConfig.use; const browser = await chromium.launch(); const context = await browser.newContext(useConfig); const page = await context.newPage(); try { + // eslint-disable-next-line playwright/no-networkidle await page.goto('/', { waitUntil: 'networkidle' }); await page.content(); await expect(page.getByText('Docs').first()).toBeVisible(); @@ -45,11 +50,9 @@ const saveStorageState = async ( }; async function globalSetup(config: FullConfig) { - /* eslint-disable @typescript-eslint/no-non-null-assertion */ const chromeConfig = config.projects.find((p) => p.name === 'chromium')!; const firefoxConfig = config.projects.find((p) => p.name === 'firefox')!; const webkitConfig = config.projects.find((p) => p.name === 'webkit')!; - /* eslint-enable @typescript-eslint/no-non-null-assertion */ await saveStorageState(chromeConfig); await saveStorageState(webkitConfig); diff --git a/src/frontend/apps/e2e/__tests__/app-impress/config.spec.ts b/src/frontend/apps/e2e/__tests__/app-impress/config.spec.ts index 250f2d6f8..6598c1c74 100644 --- a/src/frontend/apps/e2e/__tests__/app-impress/config.spec.ts +++ b/src/frontend/apps/e2e/__tests__/app-impress/config.spec.ts @@ -48,7 +48,7 @@ test.describe('Config', () => { await expect(image).toBeVisible(); // Wait for the media-check to be processed - // eslint-disable-next-line playwright/no-wait-for-timeout + await page.waitForTimeout(1000); // Check src of image diff --git a/src/frontend/apps/e2e/__tests__/app-impress/doc-editor.spec.ts b/src/frontend/apps/e2e/__tests__/app-impress/doc-editor.spec.ts index 41098f252..bebaeeec9 100644 --- a/src/frontend/apps/e2e/__tests__/app-impress/doc-editor.spec.ts +++ b/src/frontend/apps/e2e/__tests__/app-impress/doc-editor.spec.ts @@ -1,3 +1,4 @@ +/* eslint-disable playwright/no-conditional-expect */ import path from 'path'; import { chromium, expect, test } from '@playwright/test'; @@ -214,7 +215,6 @@ test.describe('Doc Editor', () => { }); test('it saves the doc when we quit pages', async ({ page, browserName }) => { - // eslint-disable-next-line playwright/no-skipped-test test.skip(browserName === 'webkit', 'This test is very flaky with webkit'); // Check the first doc @@ -277,7 +277,7 @@ test.describe('Doc Editor', () => { await expect(image).toBeVisible(); // Wait for the media-check to be processed - // eslint-disable-next-line playwright/no-wait-for-timeout + await page.waitForTimeout(1000); // Check src of image @@ -390,8 +390,6 @@ test.describe('Doc Editor', () => { const editor = page.locator('.ProseMirror'); await editor.getByText('Hello').selectText(); - /* eslint-disable playwright/no-conditional-expect */ - /* eslint-disable playwright/no-conditional-in-test */ if (!ai_transform && !ai_translate) { await expect(page.getByRole('button', { name: 'AI' })).toBeHidden(); return; @@ -418,8 +416,6 @@ test.describe('Doc Editor', () => { page.getByRole('menuitem', { name: 'Language' }), ).toBeHidden(); } - /* eslint-enable playwright/no-conditional-expect */ - /* eslint-enable playwright/no-conditional-in-test */ }); }); diff --git a/src/frontend/apps/e2e/__tests__/app-impress/doc-grid-dnd.spec.ts b/src/frontend/apps/e2e/__tests__/app-impress/doc-grid-dnd.spec.ts index 7298c5eef..ee41ce29e 100644 --- a/src/frontend/apps/e2e/__tests__/app-impress/doc-grid-dnd.spec.ts +++ b/src/frontend/apps/e2e/__tests__/app-impress/doc-grid-dnd.spec.ts @@ -36,9 +36,8 @@ test.describe('Doc grid dnd', () => { expect(draggableBoundingBox).toBeDefined(); expect(dropZoneBoundingBox).toBeDefined(); - // eslint-disable-next-line playwright/no-conditional-in-test if (!draggableBoundingBox || !dropZoneBoundingBox) { - throw new Error('Impossible de déterminer la position des éléments'); + throw new Error('Unable to determine the position of the elements'); } await page.mouse.move( @@ -86,9 +85,8 @@ test.describe('Doc grid dnd', () => { const noDropAndNoDragBoundigBox = await noDropAndNoDrag.boundingBox(); - // eslint-disable-next-line playwright/no-conditional-in-test if (!canDropAndDragBoundigBox || !noDropAndNoDragBoundigBox) { - throw new Error('Impossible de déterminer la position des éléments'); + throw new Error('Unable to determine the position of the elements'); } await page.mouse.move( @@ -137,9 +135,8 @@ test.describe('Doc grid dnd', () => { const noDropAndNoDragBoundigBox = await noDropAndNoDrag.boundingBox(); - // eslint-disable-next-line playwright/no-conditional-in-test if (!canDropAndDragBoundigBox || !noDropAndNoDragBoundigBox) { - throw new Error('Impossible de déterminer la position des éléments'); + throw new Error('Unable to determine the position of the elements'); } await page.mouse.move( diff --git a/src/frontend/apps/e2e/__tests__/app-impress/doc-header.spec.ts b/src/frontend/apps/e2e/__tests__/app-impress/doc-header.spec.ts index a1542353b..7f62529cc 100644 --- a/src/frontend/apps/e2e/__tests__/app-impress/doc-header.spec.ts +++ b/src/frontend/apps/e2e/__tests__/app-impress/doc-header.spec.ts @@ -281,7 +281,6 @@ test.describe('Doc Header', () => { page, browserName, }) => { - // eslint-disable-next-line playwright/no-skipped-test test.skip( browserName === 'webkit', 'navigator.clipboard is not working with webkit and playwright', @@ -316,7 +315,6 @@ test.describe('Doc Header', () => { }); test('It checks the copy as HTML button', async ({ page, browserName }) => { - // eslint-disable-next-line playwright/no-skipped-test test.skip( browserName === 'webkit', 'navigator.clipboard is not working with webkit and playwright', @@ -351,7 +349,6 @@ test.describe('Doc Header', () => { }); test('it checks the copy link button', async ({ page, browserName }) => { - // eslint-disable-next-line playwright/no-skipped-test test.skip( browserName === 'webkit', 'navigator.clipboard is not working with webkit and playwright', diff --git a/src/frontend/apps/e2e/__tests__/app-impress/doc-member-list.spec.ts b/src/frontend/apps/e2e/__tests__/app-impress/doc-member-list.spec.ts index 475970694..d63576585 100644 --- a/src/frontend/apps/e2e/__tests__/app-impress/doc-member-list.spec.ts +++ b/src/frontend/apps/e2e/__tests__/app-impress/doc-member-list.spec.ts @@ -151,7 +151,6 @@ test.describe('Document list members', () => { await expect(soloOwner).toBeVisible(); await list.click({ - // eslint-disable-next-line playwright/no-force-option force: true, // Force click to close the dropdown }); const newUserEmail = await addNewMember(page, 0, 'Owner'); @@ -163,13 +162,11 @@ test.describe('Document list members', () => { await currentUserRole.click(); await expect(soloOwner).toBeHidden(); await list.click({ - // eslint-disable-next-line playwright/no-force-option force: true, // Force click to close the dropdown }); await newUserRoles.click(); await list.click({ - // eslint-disable-next-line playwright/no-force-option force: true, // Force click to close the dropdown }); diff --git a/src/frontend/apps/e2e/__tests__/app-impress/doc-routing.spec.ts b/src/frontend/apps/e2e/__tests__/app-impress/doc-routing.spec.ts index 189dbc1e3..254399691 100644 --- a/src/frontend/apps/e2e/__tests__/app-impress/doc-routing.spec.ts +++ b/src/frontend/apps/e2e/__tests__/app-impress/doc-routing.spec.ts @@ -40,7 +40,6 @@ test.describe('Doc Routing', () => { }); test('checks 404 on docs/[id] page', async ({ page }) => { - // eslint-disable-next-line playwright/no-wait-for-timeout await page.waitForTimeout(300); await page.goto('/docs/some-unknown-doc'); diff --git a/src/frontend/apps/e2e/__tests__/app-impress/doc-tree.spec.ts b/src/frontend/apps/e2e/__tests__/app-impress/doc-tree.spec.ts index ad2bea5a7..b2a825d0c 100644 --- a/src/frontend/apps/e2e/__tests__/app-impress/doc-tree.spec.ts +++ b/src/frontend/apps/e2e/__tests__/app-impress/doc-tree.spec.ts @@ -1,4 +1,3 @@ -/* eslint-disable playwright/no-conditional-in-test */ import { expect, test } from '@playwright/test'; import { diff --git a/src/frontend/apps/e2e/__tests__/app-impress/doc-visibility.spec.ts b/src/frontend/apps/e2e/__tests__/app-impress/doc-visibility.spec.ts index 25bf4b8bb..b0ccea80e 100644 --- a/src/frontend/apps/e2e/__tests__/app-impress/doc-visibility.spec.ts +++ b/src/frontend/apps/e2e/__tests__/app-impress/doc-visibility.spec.ts @@ -15,7 +15,6 @@ test.describe('Doc Visibility', () => { }); test('It checks the copy link button', async ({ page, browserName }) => { - // eslint-disable-next-line playwright/no-skipped-test test.skip( browserName === 'webkit', 'navigator.clipboard is not working with webkit and playwright', @@ -119,8 +118,11 @@ test.describe('Doc Visibility: Restricted', () => { .click(); const otherBrowser = BROWSERS.find((b) => b !== browserName); + if (!otherBrowser) { + throw new Error('No alternative browser found'); + } - await keyCloakSignIn(page, otherBrowser!); + await keyCloakSignIn(page, otherBrowser); await expect(page.getByTestId('header-logo-link')).toBeVisible({ timeout: 10000, @@ -151,6 +153,9 @@ test.describe('Doc Visibility: Restricted', () => { }); const otherBrowser = BROWSERS.find((b) => b !== browserName); + if (!otherBrowser) { + throw new Error('No alternative browser found'); + } const username = `user@${otherBrowser}.test`; await inputSearch.fill(username); await page.getByRole('option', { name: username }).click(); @@ -174,7 +179,7 @@ test.describe('Doc Visibility: Restricted', () => { }) .click(); - await keyCloakSignIn(page, otherBrowser!); + await keyCloakSignIn(page, otherBrowser); await expect(page.getByTestId('header-logo-link')).toBeVisible(); @@ -449,7 +454,10 @@ test.describe('Doc Visibility: Authenticated', () => { .click(); const otherBrowser = BROWSERS.find((b) => b !== browserName); - await keyCloakSignIn(page, otherBrowser!); + if (!otherBrowser) { + throw new Error('No alternative browser found'); + } + await keyCloakSignIn(page, otherBrowser); await expect(page.getByTestId('header-logo-link')).toBeVisible({ timeout: 10000, @@ -537,7 +545,10 @@ test.describe('Doc Visibility: Authenticated', () => { .click(); const otherBrowser = BROWSERS.find((b) => b !== browserName); - await keyCloakSignIn(page, otherBrowser!); + if (!otherBrowser) { + throw new Error('No alternative browser found'); + } + await keyCloakSignIn(page, otherBrowser); await expect(page.getByTestId('header-logo-link')).toBeVisible(); diff --git a/src/frontend/apps/e2e/__tests__/app-impress/header.spec.ts b/src/frontend/apps/e2e/__tests__/app-impress/header.spec.ts index c0e534ec0..1b92bf18e 100644 --- a/src/frontend/apps/e2e/__tests__/app-impress/header.spec.ts +++ b/src/frontend/apps/e2e/__tests__/app-impress/header.spec.ts @@ -76,7 +76,6 @@ test.describe('Header', () => { * La gaufre load a js file from a remote server, * it takes some time to load the file and have the interaction available */ - // eslint-disable-next-line playwright/no-wait-for-timeout await page.waitForTimeout(1500); await header diff --git a/src/frontend/apps/e2e/__tests__/app-impress/utils-common.ts b/src/frontend/apps/e2e/__tests__/app-impress/utils-common.ts index 4cbf886bb..b90d680eb 100644 --- a/src/frontend/apps/e2e/__tests__/app-impress/utils-common.ts +++ b/src/frontend/apps/e2e/__tests__/app-impress/utils-common.ts @@ -27,7 +27,7 @@ export const CONFIG = { export const overrideConfig = async ( page: Page, - newConfig: { [K in keyof typeof CONFIG]?: unknown }, + newConfig: { [_K in keyof typeof CONFIG]?: unknown }, ) => await page.route('**/api/v1.0/config/', async (route) => { const request = route.request(); diff --git a/src/frontend/apps/e2e/eslint.config.mjs b/src/frontend/apps/e2e/eslint.config.mjs new file mode 100644 index 000000000..461c01c93 --- /dev/null +++ b/src/frontend/apps/e2e/eslint.config.mjs @@ -0,0 +1,20 @@ +import { defineConfig } from '@eslint/config-helpers'; +import docsPlugin from 'eslint-plugin-docs'; + +const eslintConfig = defineConfig([ + { + files: ['**/*.ts', '**/*.mjs'], + plugins: { + docs: docsPlugin, + }, + extends: ['docs/playwright'], + languageOptions: { + parserOptions: { + tsconfigRootDir: import.meta.dirname, + project: ['./tsconfig.json'], + }, + }, + }, +]); + +export default eslintConfig; diff --git a/src/frontend/apps/e2e/package.json b/src/frontend/apps/e2e/package.json index 74b2e4e41..010af0c47 100644 --- a/src/frontend/apps/e2e/package.json +++ b/src/frontend/apps/e2e/package.json @@ -3,7 +3,7 @@ "version": "3.5.0", "private": true, "scripts": { - "lint": "eslint . --ext .ts", + "lint": "eslint", "install-playwright": "playwright install --with-deps", "test": "playwright test", "test:ui": "yarn test --ui", @@ -15,7 +15,7 @@ "@playwright/test": "1.54.2", "@types/node": "*", "@types/pdf-parse": "1.1.5", - "eslint-config-impress": "*", + "eslint-plugin-docs": "*", "typescript": "*" }, "dependencies": { diff --git a/src/frontend/apps/e2e/tsconfig.json b/src/frontend/apps/e2e/tsconfig.json index a9aa4817c..64fe24546 100644 --- a/src/frontend/apps/e2e/tsconfig.json +++ b/src/frontend/apps/e2e/tsconfig.json @@ -12,8 +12,8 @@ "resolveJsonModule": true, "isolatedModules": true, "jsx": "preserve", - "incremental": true, + "incremental": true }, - "include": ["**/*.ts", "**/*.d.ts"], + "include": ["**/*.ts", "**/*.d.ts", "**/*.mjs"], "exclude": ["node_modules"] } diff --git a/src/frontend/apps/e2e/type/convert-stream.d.ts b/src/frontend/apps/e2e/type/convert-stream.d.ts index d79cbccc9..93b753a9c 100644 --- a/src/frontend/apps/e2e/type/convert-stream.d.ts +++ b/src/frontend/apps/e2e/type/convert-stream.d.ts @@ -1,5 +1,5 @@ declare module 'convert-stream' { export function toBuffer( - readableStream: NodeJS.ReadableStream, + _readableStream: NodeJS.ReadableStream, ): Promise; } diff --git a/src/frontend/apps/impress/.eslintrc.js b/src/frontend/apps/impress/.eslintrc.js deleted file mode 100644 index f2dbec761..000000000 --- a/src/frontend/apps/impress/.eslintrc.js +++ /dev/null @@ -1,14 +0,0 @@ -module.exports = { - root: true, - extends: ['impress/next'], - parserOptions: { - tsconfigRootDir: __dirname, - project: ['./tsconfig.json'], - }, - settings: { - next: { - rootDir: __dirname, - }, - }, - ignorePatterns: ['node_modules', '.eslintrc.js', 'service-worker.js'], -}; diff --git a/src/frontend/apps/impress/eslint.config.mjs b/src/frontend/apps/impress/eslint.config.mjs new file mode 100644 index 000000000..ba1fe17f6 --- /dev/null +++ b/src/frontend/apps/impress/eslint.config.mjs @@ -0,0 +1,24 @@ +import { defineConfig } from '@eslint/config-helpers'; +import docsPlugin from 'eslint-plugin-docs'; + +const eslintConfig = defineConfig([ + { + plugins: { + docs: docsPlugin, + }, + extends: ['docs/next'], + languageOptions: { + parserOptions: { + tsconfigRootDir: import.meta.dirname, + project: ['./tsconfig.json'], + }, + }, + settings: { + next: { + rootDir: import.meta.dirname, + }, + }, + }, +]); + +export default eslintConfig; diff --git a/src/frontend/apps/impress/package.json b/src/frontend/apps/impress/package.json index b30b80851..386fd4de8 100644 --- a/src/frontend/apps/impress/package.json +++ b/src/frontend/apps/impress/package.json @@ -75,7 +75,7 @@ "@types/react-dom": "*", "cross-env": "10.0.0", "dotenv": "17.2.1", - "eslint-config-impress": "*", + "eslint-plugin-docs": "*", "fetch-mock": "9.11.0", "jest": "30.0.5", "jest-environment-jsdom": "30.0.5", diff --git a/src/frontend/apps/impress/src/components/dropdown-menu/hook/useDropdownKeyboardNav.ts b/src/frontend/apps/impress/src/components/dropdown-menu/hook/useDropdownKeyboardNav.ts index 0fd41e6a6..b75ae7d4f 100644 --- a/src/frontend/apps/impress/src/components/dropdown-menu/hook/useDropdownKeyboardNav.ts +++ b/src/frontend/apps/impress/src/components/dropdown-menu/hook/useDropdownKeyboardNav.ts @@ -32,7 +32,7 @@ export const useDropdownKeyboardNav = ({ .filter((index) => index !== -1); switch (event.key) { - case 'ArrowDown': + case 'ArrowDown': { event.preventDefault(); const nextIndex = focusedIndex < enabledIndices.length - 1 ? focusedIndex + 1 : 0; @@ -40,8 +40,9 @@ export const useDropdownKeyboardNav = ({ setFocusedIndex(nextIndex); menuItemRefs.current[nextEnabledIndex]?.focus(); break; + } - case 'ArrowUp': + case 'ArrowUp': { event.preventDefault(); const prevIndex = focusedIndex > 0 ? focusedIndex - 1 : enabledIndices.length - 1; @@ -49,9 +50,10 @@ export const useDropdownKeyboardNav = ({ setFocusedIndex(prevIndex); menuItemRefs.current[prevEnabledIndex]?.focus(); break; + } case 'Enter': - case ' ': + case ' ': { event.preventDefault(); if (focusedIndex >= 0 && focusedIndex < enabledIndices.length) { const selectedOptionIndex = enabledIndices[focusedIndex]; @@ -62,6 +64,7 @@ export const useDropdownKeyboardNav = ({ } } break; + } case 'Escape': event.preventDefault(); diff --git a/src/frontend/apps/impress/src/components/quick-search/QuickSearchInput.tsx b/src/frontend/apps/impress/src/components/quick-search/QuickSearchInput.tsx index b750b508b..d464c884b 100644 --- a/src/frontend/apps/impress/src/components/quick-search/QuickSearchInput.tsx +++ b/src/frontend/apps/impress/src/components/quick-search/QuickSearchInput.tsx @@ -53,7 +53,6 @@ export const QuickSearchInput = ({ )} { diff --git a/src/frontend/apps/impress/src/custom-next.d.ts b/src/frontend/apps/impress/src/custom-next.d.ts index 0e5e6acf2..f6610a52f 100644 --- a/src/frontend/apps/impress/src/custom-next.d.ts +++ b/src/frontend/apps/impress/src/custom-next.d.ts @@ -1,5 +1,3 @@ -/* eslint-disable @typescript-eslint/no-unused-vars */ - declare module '*.svg' { import * as React from 'react'; diff --git a/src/frontend/apps/impress/src/features/docs/doc-editor/components/BlockNoteToolBar/AIButton.tsx b/src/frontend/apps/impress/src/features/docs/doc-editor/components/BlockNoteToolBar/AIButton.tsx index 45bd1ed49..08239779b 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-editor/components/BlockNoteToolBar/AIButton.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-editor/components/BlockNoteToolBar/AIButton.tsx @@ -205,7 +205,7 @@ type ItemProps = Omit & { onClick: (e: React.MouseEvent) => void; }; -interface AIMenuItemTransform { +interface AIMenuItemTransformProps { action: AITransformActions; docId: string; icon?: ReactNode; @@ -216,7 +216,7 @@ const AIMenuItemTransform = ({ action, children, icon, -}: PropsWithChildren) => { +}: PropsWithChildren) => { const { mutateAsync: requestAI, isPending } = useDocAITransform(); const editor = useBlockNoteEditor(); @@ -244,7 +244,7 @@ const AIMenuItemTransform = ({ ); }; -interface AIMenuItemTranslate { +interface AIMenuItemTranslateProps { language: string; docId: string; icon?: ReactNode; @@ -255,7 +255,7 @@ const AIMenuItemTranslate = ({ docId, icon, language, -}: PropsWithChildren) => { +}: PropsWithChildren) => { const { mutateAsync: requestAI, isPending } = useDocAITranslate(); const editor = useBlockNoteEditor(); diff --git a/src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/Interlinking/InterlinkingSearchInlineContent.tsx b/src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/Interlinking/InterlinkingSearchInlineContent.tsx index 94d56da69..d49eff6ac 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/Interlinking/InterlinkingSearchInlineContent.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/Interlinking/InterlinkingSearchInlineContent.tsx @@ -1,4 +1,3 @@ -/* eslint-disable react-hooks/rules-of-hooks */ import { createReactInlineContentSpec } from '@blocknote/react'; import { TFunction } from 'i18next'; diff --git a/src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/Interlinking/SearchPage.tsx b/src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/Interlinking/SearchPage.tsx index 4de6fd4c8..772bc71f3 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/Interlinking/SearchPage.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/Interlinking/SearchPage.tsx @@ -1,4 +1,3 @@ -/* eslint-disable react-hooks/rules-of-hooks */ import { PartialCustomInlineContentFromConfig, StyleSchema, diff --git a/src/frontend/apps/impress/src/features/docs/doc-export/blocks-mapping/imagePDF.tsx b/src/frontend/apps/impress/src/features/docs/doc-export/blocks-mapping/imagePDF.tsx index 728d5f3a8..cad4fd69e 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-export/blocks-mapping/imagePDF.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-export/blocks-mapping/imagePDF.tsx @@ -1,4 +1,3 @@ -/* eslint-disable jsx-a11y/alt-text */ import { DefaultProps } from '@blocknote/core'; import { Image, Text, View } from '@react-pdf/renderer'; diff --git a/src/frontend/apps/impress/src/features/docs/doc-export/inline-content-mapping/interlinkingLinkPDF.tsx b/src/frontend/apps/impress/src/features/docs/doc-export/inline-content-mapping/interlinkingLinkPDF.tsx index 157327228..c2d204b73 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-export/inline-content-mapping/interlinkingLinkPDF.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-export/inline-content-mapping/interlinkingLinkPDF.tsx @@ -1,4 +1,3 @@ -/* eslint-disable jsx-a11y/alt-text */ import { Image, Link, Text } from '@react-pdf/renderer'; import DocSelectedIcon from '../assets/doc-selected.png'; diff --git a/src/frontend/apps/impress/src/features/docs/doc-header/components/DocTitle.tsx b/src/frontend/apps/impress/src/features/docs/doc-header/components/DocTitle.tsx index b54e710d2..f8b404f66 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-header/components/DocTitle.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-header/components/DocTitle.tsx @@ -1,5 +1,3 @@ -/* eslint-disable jsx-a11y/click-events-have-key-events */ -/* eslint-disable jsx-a11y/no-noninteractive-element-interactions */ import { useTreeContext } from '@gouvfr-lasuite/ui-kit'; import { Tooltip } from '@openfun/cunningham-react'; import React, { useCallback, useEffect, useState } from 'react'; diff --git a/src/frontend/apps/impress/src/features/docs/doc-management/api/useDuplicateDoc.tsx b/src/frontend/apps/impress/src/features/docs/doc-management/api/useDuplicateDoc.tsx index f097401d7..91018baf6 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-management/api/useDuplicateDoc.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-management/api/useDuplicateDoc.tsx @@ -65,24 +65,19 @@ export function useDuplicateDoc(options?: DuplicateDocOptions) { return useMutation({ mutationFn: async (variables) => { - try { - // Save the document if we can first, to ensure the latest state is duplicated - if ( - variables.canSave && - provider && - provider.document.guid === variables.docId - ) { - await updateDoc({ - id: variables.docId, - content: toBase64(Y.encodeStateAsUpdate(provider.document)), - }); - } - - return await duplicateDoc(variables); - } catch (error) { - // If save fails, throw the error to prevent duplication - throw error; + // Save the document if we can first, to ensure the latest state is duplicated + if ( + variables.canSave && + provider && + provider.document.guid === variables.docId + ) { + await updateDoc({ + id: variables.docId, + content: toBase64(Y.encodeStateAsUpdate(provider.document)), + }); } + + return await duplicateDoc(variables); }, onSuccess: (data, variables, context) => { void queryClient.resetQueries({ diff --git a/src/frontend/apps/impress/src/features/docs/doc-tree/components/DocTree.tsx b/src/frontend/apps/impress/src/features/docs/doc-tree/components/DocTree.tsx index 841e3f11b..151234d60 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-tree/components/DocTree.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-tree/components/DocTree.tsx @@ -42,7 +42,7 @@ export const DocTree = ({ currentDoc }: DocTreeProps) => { docId: currentDoc.id, }, { - enabled: !!!treeContext?.root?.id, + enabled: !treeContext?.root?.id, queryKey: [KEY_DOC_TREE, { id: currentDoc.id }], }, ); diff --git a/src/frontend/apps/impress/src/features/service-worker/DocsDB.ts b/src/frontend/apps/impress/src/features/service-worker/DocsDB.ts index 36465345f..eb401f371 100644 --- a/src/frontend/apps/impress/src/features/service-worker/DocsDB.ts +++ b/src/frontend/apps/impress/src/features/service-worker/DocsDB.ts @@ -4,7 +4,6 @@ import { Doc, DocsResponse } from '@/docs/doc-management'; import { RequestData, RequestSerializer } from './RequestSerializer'; -// eslint-disable-next-line import/order import pkg from '@/../package.json'; export type DBRequest = { diff --git a/src/frontend/apps/impress/src/features/service-worker/__tests__/ApiPlugin.test.tsx b/src/frontend/apps/impress/src/features/service-worker/__tests__/ApiPlugin.test.tsx index 198fc91ff..7da85c6ea 100644 --- a/src/frontend/apps/impress/src/features/service-worker/__tests__/ApiPlugin.test.tsx +++ b/src/frontend/apps/impress/src/features/service-worker/__tests__/ApiPlugin.test.tsx @@ -133,7 +133,6 @@ describe('ApiPlugin', () => { const request = await apiPlugin.requestWillFetch?.(requestInit); if (withClone) { - // eslint-disable-next-line jest/no-conditional-expect expect(mockedClone).toHaveBeenCalled(); } diff --git a/src/frontend/apps/impress/src/features/service-worker/service-worker-api.ts b/src/frontend/apps/impress/src/features/service-worker/service-worker-api.ts index 947b27370..c9cbd0762 100644 --- a/src/frontend/apps/impress/src/features/service-worker/service-worker-api.ts +++ b/src/frontend/apps/impress/src/features/service-worker/service-worker-api.ts @@ -46,7 +46,7 @@ registerRoute( registerRoute( ({ url }) => - isApiUrl(url.href) && url.href.match(/.*\/documents\/([a-z0-9\-]+)\/$/g), + isApiUrl(url.href) && url.href.match(/.*\/documents\/([a-z0-9-]+)\/$/g), new NetworkOnly({ plugins: [ new ApiPlugin({ @@ -62,7 +62,7 @@ registerRoute( registerRoute( ({ url }) => - isApiUrl(url.href) && url.href.match(/.*\/documents\/([a-z0-9\-]+)\/$/g), + isApiUrl(url.href) && url.href.match(/.*\/documents\/([a-z0-9-]+)\/$/g), new NetworkOnly({ plugins: [ new ApiPlugin({ @@ -91,7 +91,7 @@ registerRoute( registerRoute( ({ url }) => - isApiUrl(url.href) && url.href.match(/.*\/documents\/([a-z0-9\-]+)\/$/g), + isApiUrl(url.href) && url.href.match(/.*\/documents\/([a-z0-9-]+)\/$/g), new NetworkOnly({ plugins: [ new ApiPlugin({ diff --git a/src/frontend/apps/impress/src/features/service-worker/service-worker.ts b/src/frontend/apps/impress/src/features/service-worker/service-worker.ts index 387010446..1e93160f3 100644 --- a/src/frontend/apps/impress/src/features/service-worker/service-worker.ts +++ b/src/frontend/apps/impress/src/features/service-worker/service-worker.ts @@ -18,13 +18,11 @@ import { StrategyOptions, } from 'workbox-strategies'; -// eslint-disable-next-line import/order import { DAYS_EXP, SW_DEV_URL, SW_VERSION, getCacheNameVersion } from './conf'; import { ApiPlugin } from './plugins/ApiPlugin'; import { OfflinePlugin } from './plugins/OfflinePlugin'; import { isApiUrl } from './service-worker-api'; -// eslint-disable-next-line import/order import pkg from '@/../package.json'; declare const self: ServiceWorkerGlobalScope & { @@ -131,7 +129,7 @@ setCatchHandler(async ({ request, url, event }) => { return ApiPlugin.getApiCatchHandler(); case request.destination === 'document': - if (url.pathname.match(/^\/docs\/([a-z0-9\-]+)\/$/g)) { + if (url.pathname.match(/^\/docs\/([a-z0-9-]+)\/$/g)) { return precacheStrategy.handle({ event, request: FALLBACK.docs }); } diff --git a/src/frontend/apps/impress/src/utils/string.ts b/src/frontend/apps/impress/src/utils/string.ts index 04a7e4f9c..f51ad9470 100644 --- a/src/frontend/apps/impress/src/utils/string.ts +++ b/src/frontend/apps/impress/src/utils/string.ts @@ -1,5 +1,5 @@ export const isValidEmail = (email: string) => { return !!email.match( - /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z\-0-9]{2,}))$/, + /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z\-0-9]{2,}))$/, ); }; diff --git a/src/frontend/package.json b/src/frontend/package.json index 6c5ce1fae..5f59f203b 100644 --- a/src/frontend/package.json +++ b/src/frontend/package.json @@ -20,7 +20,7 @@ "app:test": "yarn APP_IMPRESS run test", "ci:build": "yarn APP_IMPRESS run build:ci", "e2e:test": "yarn APP_E2E run test", - "lint": "yarn APP_IMPRESS run lint && yarn APP_E2E run lint && yarn workspace eslint-config-impress run lint && yarn I18N run lint && yarn COLLABORATION_SERVER run lint", + "lint": "yarn APP_IMPRESS run lint && yarn APP_E2E run lint && yarn workspace eslint-plugin-docs run lint && yarn I18N run lint && yarn COLLABORATION_SERVER run lint", "i18n:extract": "yarn I18N run extract-translation", "i18n:deploy": "yarn I18N run format-deploy && yarn APP_IMPRESS prettier", "i18n:test": "yarn I18N run test", @@ -33,7 +33,7 @@ "@types/react-dom": "19.1.7", "@typescript-eslint/eslint-plugin": "8.39.0", "@typescript-eslint/parser": "8.39.0", - "eslint": "8.57.0", + "eslint": "9.32.0", "react": "19.1.0", "react-dom": "19.1.0", "typescript": "5.9.2", diff --git a/src/frontend/packages/eslint-config-impress/.eslintrc.js b/src/frontend/packages/eslint-config-impress/.eslintrc.js deleted file mode 100644 index 76b342eb7..000000000 --- a/src/frontend/packages/eslint-config-impress/.eslintrc.js +++ /dev/null @@ -1,21 +0,0 @@ -const common = require('./common'); - -module.exports = { - root: true, - settings: { - react: { - version: 'detect', - }, - }, - extends: [ - 'plugin:prettier/recommended', - 'plugin:import/recommended', - 'plugin:react/recommended', - ], - rules: common.globalRules, - parserOptions: { - sourceType: 'module', - ecmaVersion: 'latest', - }, - ignorePatterns: ['node_modules'], -}; diff --git a/src/frontend/packages/eslint-config-impress/common.js b/src/frontend/packages/eslint-config-impress/common.js deleted file mode 100644 index 3dd25350f..000000000 --- a/src/frontend/packages/eslint-config-impress/common.js +++ /dev/null @@ -1,76 +0,0 @@ -const eslintTS = [ - { - files: ['*.ts', '*.tsx'], - extends: [ - 'plugin:@typescript-eslint/recommended', - 'plugin:@typescript-eslint/recommended-requiring-type-checking', - ], - parser: '@typescript-eslint/parser', // Specifies the ESLint parser - parserOptions: { - tsconfigRootDir: __dirname, - project: ['./tsconfig.json'], - }, - rules: { - '@typescript-eslint/no-explicit-any': 'error', - '@typescript-eslint/no-non-null-assertion': 'error', - '@typescript-eslint/no-unused-vars': [ - 'error', - { varsIgnorePattern: '^_', argsIgnorePattern: '^_' }, - ], - 'sort-imports': [ - 'error', - { - ignoreDeclarationSort: true, - }, - ], - }, - }, - { - files: ['*.d.ts'], - rules: { - 'no-unused-vars': 'off', - }, - }, -]; - -const globalRules = { - 'block-scoped-var': 'error', - curly: ['error', 'all'], - 'import/no-duplicates': ['error', { considerQueryString: false }], - 'import/order': [ - 'error', - { - alphabetize: { - order: 'asc', - }, - groups: ['builtin', 'external', 'internal', 'parent', 'sibling', 'index'], - pathGroups: [ - { - pattern: '@/**', - group: 'internal', - }, - ], - pathGroupsExcludedImportTypes: ['builtin'], - 'newlines-between': 'always', - warnOnUnassignedImports: true, - }, - ], - 'no-alert': 'error', - 'no-unused-vars': [ - 'error', - { varsIgnorePattern: '^_', argsIgnorePattern: '^_' }, - ], - 'no-var': 'error', - 'react/jsx-curly-brace-presence': [ - 'error', - { props: 'never', children: 'never', propElementValues: 'always' }, - ], - 'sort-imports': [ - 'error', - { - ignoreDeclarationSort: true, - }, - ], -}; - -module.exports = { eslintTS, globalRules }; diff --git a/src/frontend/packages/eslint-config-impress/jest.js b/src/frontend/packages/eslint-config-impress/jest.js deleted file mode 100644 index 93a5f2cfa..000000000 --- a/src/frontend/packages/eslint-config-impress/jest.js +++ /dev/null @@ -1,51 +0,0 @@ -const common = require('./common'); - -module.exports = { - extends: ['plugin:prettier/recommended', 'plugin:react/recommended'], - rules: common.globalRules, - settings: { - react: { - version: 'detect', - }, - }, - overrides: [ - ...common.eslintTS, - { - files: ['*.spec.*', '*.test.*', '**/__mock__/**/*'], - plugins: ['jest'], - extends: ['plugin:jest/recommended', 'plugin:testing-library/react'], - rules: { - '@typescript-eslint/ban-types': 'off', - '@typescript-eslint/no-empty-function': 'off', - '@typescript-eslint/no-explicit-any': 'off', - '@typescript-eslint/no-non-null-assertion': 'off', - '@typescript-eslint/no-unsafe-argument': 'off', - '@typescript-eslint/no-unsafe-assignment': 'off', - '@typescript-eslint/no-unsafe-call': 'off', - '@typescript-eslint/no-unsafe-member-access': 'off', - '@typescript-eslint/no-unsafe-return': 'off', - 'testing-library/no-await-sync-events': [ - 'error', - { eventModules: ['fire-event'] }, - ], - 'testing-library/await-async-events': [ - 'error', - { - eventModule: 'userEvent', - }, - ], - 'testing-library/no-manual-cleanup': 'off', - '@typescript-eslint/no-unused-vars': [ - 'error', - { varsIgnorePattern: '^_', argsIgnorePattern: '^_' }, - ], - 'react/display-name': 0, - 'jest/expect-expect': 'error', - '@typescript-eslint/unbound-method': 'off', - 'jest/unbound-method': 'error', - 'react/react-in-jsx-scope': 'off', - }, - }, - ], - ignorePatterns: ['node_modules'], -}; diff --git a/src/frontend/packages/eslint-config-impress/next.js b/src/frontend/packages/eslint-config-impress/next.js deleted file mode 100644 index f2a26994a..000000000 --- a/src/frontend/packages/eslint-config-impress/next.js +++ /dev/null @@ -1,40 +0,0 @@ -const common = require('./common'); - -module.exports = { - extends: [ - 'next', - 'plugin:prettier/recommended', - 'plugin:@tanstack/eslint-plugin-query/recommended', - 'plugin:jsx-a11y/recommended', - ], - parserOptions: { - babelOptions: { - presets: [require.resolve('next/babel')], - }, - }, - settings: { - 'jsx-a11y': { - polymorphicPropName: 'as', - components: { - Input: 'input', - Button: 'button', - Box: 'div', - Text: 'span', - Select: 'select', - }, - }, - }, - rules: { - ...common.globalRules, - 'react-hooks/rules-of-hooks': 'error', - 'react-hooks/exhaustive-deps': 'error', - }, - overrides: [ - ...common.eslintTS, - { - files: ['*.spec.*', '*.test.*', '**/__mock__/**/*'], - extends: ['impress/jest'], - }, - ], - ignorePatterns: ['node_modules'], -}; diff --git a/src/frontend/packages/eslint-config-impress/playwright.js b/src/frontend/packages/eslint-config-impress/playwright.js deleted file mode 100644 index c51edc5a5..000000000 --- a/src/frontend/packages/eslint-config-impress/playwright.js +++ /dev/null @@ -1,36 +0,0 @@ -const common = require('./common'); - -module.exports = { - extends: ['next', 'plugin:prettier/recommended'], - settings: { - react: { - version: 'detect', - }, - }, - parserOptions: { - babelOptions: { - presets: [require.resolve('next/babel')], - }, - }, - rules: { ...common.globalRules, '@next/next/no-html-link-for-pages': 'off' }, - overrides: [ - ...common.eslintTS, - { - files: ['**/*.ts'], - rules: { - '@typescript-eslint/no-unsafe-member-access': 'off', - }, - }, - { - files: ['*.spec.*', '*.test.*', '**/__mock__/**/*'], - extends: ['plugin:playwright/recommended'], - plugins: ['playwright'], - rules: { - '@typescript-eslint/no-unsafe-member-access': 'off', - '@typescript-eslint/no-unsafe-assignment': 'off', - '@typescript-eslint/no-non-null-assertion': 'off', - }, - }, - ], - ignorePatterns: ['node_modules'], -}; diff --git a/src/frontend/packages/eslint-plugin-docs/base.js b/src/frontend/packages/eslint-plugin-docs/base.js new file mode 100644 index 000000000..365d85c29 --- /dev/null +++ b/src/frontend/packages/eslint-plugin-docs/base.js @@ -0,0 +1,91 @@ +const js = require('@eslint/js'); +const nextPlugin = require('@next/eslint-plugin-next'); +const tanstackQuery = require('@tanstack/eslint-plugin-query'); +const { defineConfig } = require('eslint/config'); +const importPlugin = require('eslint-plugin-import'); +const jsxA11y = require('eslint-plugin-jsx-a11y'); +const prettier = require('eslint-plugin-prettier'); +const react = require('eslint-plugin-react'); +const reactHooks = require('eslint-plugin-react-hooks'); + +const globalRules = { + 'block-scoped-var': 'error', + curly: ['error', 'all'], + 'import/no-duplicates': ['error', { considerQueryString: false }], + 'import/order': [ + 'error', + { + alphabetize: { + order: 'asc', + }, + groups: ['builtin', 'external', 'internal', 'parent', 'sibling', 'index'], + pathGroups: [ + { + pattern: '@/**', + group: 'internal', + }, + ], + pathGroupsExcludedImportTypes: ['builtin'], + 'newlines-between': 'always', + warnOnUnassignedImports: true, + }, + ], + 'no-alert': 'error', + 'no-unused-vars': [ + 'error', + { varsIgnorePattern: '^_', argsIgnorePattern: '^_' }, + ], + 'no-var': 'error', + 'react/jsx-curly-brace-presence': [ + 'error', + { props: 'never', children: 'never', propElementValues: 'always' }, + ], +}; + +// Base configuration +const baseConfig = defineConfig({ + plugins: { + prettier, + import: importPlugin, + react, + 'react-hooks': reactHooks, + 'jsx-a11y': jsxA11y, + '@next/next': nextPlugin, + '@tanstack/query': tanstackQuery, + js, + }, + extends: ['js/recommended'], + settings: { + 'jsx-a11y': { + polymorphicPropName: 'as', + components: { + Input: 'input', + Button: 'button', + Box: 'div', + Text: 'span', + Select: 'select', + }, + }, + }, + rules: { + ...globalRules, + 'no-undef': 'off', + 'prettier/prettier': 'error', + 'react-hooks/rules-of-hooks': 'error', + 'react-hooks/exhaustive-deps': 'error', + '@tanstack/query/exhaustive-deps': 'error', + '@tanstack/query/no-rest-destructuring': 'warn', + '@tanstack/query/stable-query-client': 'error', + 'jsx-a11y/alt-text': 'error', + 'jsx-a11y/aria-props': 'error', + 'jsx-a11y/aria-proptypes': 'error', + 'jsx-a11y/aria-unsupported-elements': 'error', + 'jsx-a11y/role-has-required-aria-props': 'error', + 'jsx-a11y/role-supports-aria-props': 'error', + }, + linterOptions: { + reportUnusedDisableDirectives: 'error', + }, +}); + +module.exports = { baseConfig }; diff --git a/src/frontend/packages/eslint-plugin-docs/eslint.config.mjs b/src/frontend/packages/eslint-plugin-docs/eslint.config.mjs new file mode 100644 index 000000000..ab061a79c --- /dev/null +++ b/src/frontend/packages/eslint-plugin-docs/eslint.config.mjs @@ -0,0 +1,23 @@ +import { defineConfig } from '@eslint/config-helpers'; +import docsPlugin from 'eslint-plugin-docs'; + +const eslintConfig = defineConfig([ + { + files: ['**/*.js', '**/*.mjs'], + plugins: { + docs: docsPlugin, + }, + extends: ['docs/base'], + languageOptions: { + parserOptions: { + tsconfigRootDir: import.meta.dirname, + project: ['./tsconfig.json'], + }, + }, + rules: { + '@next/next/no-html-link-for-pages': 'off', + }, + }, +]); + +export default eslintConfig; diff --git a/src/frontend/packages/eslint-plugin-docs/index.d.ts b/src/frontend/packages/eslint-plugin-docs/index.d.ts new file mode 100644 index 000000000..65003ffc2 --- /dev/null +++ b/src/frontend/packages/eslint-plugin-docs/index.d.ts @@ -0,0 +1,20 @@ +import { ESLint } from 'eslint'; + +interface PluginMeta { + name: string; + version: string; + namespace: string; +} + +interface PluginConfig { + meta: PluginMeta; + configs: { + base: ESLint.ConfigData[]; + next: ESLint.ConfigData[]; + test: ESLint.ConfigData[]; + playwright: ESLint.ConfigData[]; + }; +} + +declare const plugin: PluginConfig; +export = plugin; diff --git a/src/frontend/packages/eslint-plugin-docs/index.js b/src/frontend/packages/eslint-plugin-docs/index.js new file mode 100644 index 000000000..97c36a765 --- /dev/null +++ b/src/frontend/packages/eslint-plugin-docs/index.js @@ -0,0 +1,28 @@ +const { baseConfig } = require('./base'); +const pkg = require('./package.json'); +const { playwrightConfig } = require('./playwright'); +const { testConfig } = require('./test'); +const { typescriptConfig, declarationConfig } = require('./typescript'); + +const plugin = { + meta: { + name: pkg.name, + version: pkg.version, + namespace: 'docs', + }, + configs: {}, +}; + +Object.assign(plugin.configs, { + base: [baseConfig], + next: [baseConfig, typescriptConfig, declarationConfig, testConfig], + test: [testConfig], + playwright: [ + baseConfig, + typescriptConfig, + declarationConfig, + playwrightConfig, + ], +}); + +module.exports = plugin; diff --git a/src/frontend/packages/eslint-config-impress/package.json b/src/frontend/packages/eslint-plugin-docs/package.json similarity index 68% rename from src/frontend/packages/eslint-config-impress/package.json rename to src/frontend/packages/eslint-plugin-docs/package.json index 6ccf06644..7bb436d6c 100644 --- a/src/frontend/packages/eslint-config-impress/package.json +++ b/src/frontend/packages/eslint-plugin-docs/package.json @@ -1,16 +1,24 @@ { - "name": "eslint-config-impress", + "name": "eslint-plugin-docs", "version": "3.5.0", "license": "MIT", + "main": "index.js", + "keywords": [ + "eslint", + "eslintplugin", + "eslint-plugin" + ], "scripts": { - "lint": "eslint --ext .js ." + "lint": "eslint" + }, + "peerDependencies": { + "eslint": ">=9.0.0" }, "dependencies": { "@next/eslint-plugin-next": "15.4.6", "@tanstack/eslint-plugin-query": "5.83.1", "@typescript-eslint/eslint-plugin": "*", "@typescript-eslint/parser": "*", - "eslint": "*", "eslint-config-next": "15.4.6", "eslint-config-prettier": "10.1.8", "eslint-plugin-import": "2.32.0", @@ -18,7 +26,9 @@ "eslint-plugin-jsx-a11y": "6.10.2", "eslint-plugin-playwright": "2.2.2", "eslint-plugin-prettier": "5.5.4", + "eslint-plugin-react": "7.37.5", "eslint-plugin-testing-library": "7.6.3", + "eslint-plugin-vitest": "0.5.4", "prettier": "3.6.2" } } diff --git a/src/frontend/packages/eslint-plugin-docs/playwright.js b/src/frontend/packages/eslint-plugin-docs/playwright.js new file mode 100644 index 000000000..f3e79825e --- /dev/null +++ b/src/frontend/packages/eslint-plugin-docs/playwright.js @@ -0,0 +1,37 @@ +const typescriptEslint = require('@typescript-eslint/eslint-plugin'); +const typescriptParser = require('@typescript-eslint/parser'); +const playwright = require('eslint-plugin-playwright'); + +const playwrightConfig = { + plugins: { + '@typescript-eslint': typescriptEslint, + playwright, + }, + languageOptions: { + parser: typescriptParser, + parserOptions: { + project: true, + }, + }, + files: [ + '**/*.spec.ts', + '**/*.test.ts', + '**/__mock__/**/*', + '**/auth.setup.ts', + ], + rules: { + ...playwright.configs['flat/recommended'].rules, + '@typescript-eslint/no-unsafe-member-access': 'off', + '@typescript-eslint/no-unsafe-assignment': 'off', + '@typescript-eslint/no-non-null-assertion': 'off', + '@typescript-eslint/no-unsafe-argument': 'off', + 'playwright/no-force-option': 'off', + 'playwright/no-wait-for-timeout': 'off', + 'playwright/no-conditional-in-test': 'off', + 'playwright/no-skipped-test': 'off', + 'playwright/expect-expect': 'error', + 'playwright/no-conditional-expect': 'error', + }, +}; + +module.exports = { playwrightConfig }; diff --git a/src/frontend/packages/eslint-plugin-docs/test.js b/src/frontend/packages/eslint-plugin-docs/test.js new file mode 100644 index 000000000..662392487 --- /dev/null +++ b/src/frontend/packages/eslint-plugin-docs/test.js @@ -0,0 +1,71 @@ +const typescriptEslint = require('@typescript-eslint/eslint-plugin'); +const typescriptParser = require('@typescript-eslint/parser'); +const jest = require('eslint-plugin-jest'); +const testingLibrary = require('eslint-plugin-testing-library'); +const vitest = require('eslint-plugin-vitest'); + +const testConfig = { + files: [ + '*.spec.*', + '*.test.*', + '**/__tests__/**/*', + '**/__mock__/**/*', + '**/__mocks__/**/*', + ], + languageOptions: { + parser: typescriptParser, + parserOptions: { + project: true, + }, + globals: { + describe: 'readonly', + it: 'readonly', + test: 'readonly', + expect: 'readonly', + beforeEach: 'readonly', + afterEach: 'readonly', + beforeAll: 'readonly', + afterAll: 'readonly', + jest: 'readonly', + }, + }, + plugins: { + '@typescript-eslint': typescriptEslint, + jest, + vitest, + 'testing-library': testingLibrary, + }, + rules: { + '@typescript-eslint/ban-types': 'off', + '@typescript-eslint/no-empty-function': 'off', + '@typescript-eslint/no-explicit-any': 'off', + '@typescript-eslint/no-non-null-assertion': 'off', + '@typescript-eslint/no-unsafe-argument': 'off', + '@typescript-eslint/no-unsafe-assignment': 'off', + '@typescript-eslint/no-unsafe-call': 'off', + '@typescript-eslint/no-unsafe-member-access': 'off', + '@typescript-eslint/no-unsafe-return': 'off', + '@typescript-eslint/no-unused-vars': [ + 'error', + { varsIgnorePattern: '^_', argsIgnorePattern: '^_' }, + ], + '@typescript-eslint/unbound-method': 'off', + 'jest/unbound-method': 'error', + 'jest/expect-expect': 'error', + 'testing-library/no-await-sync-events': [ + 'error', + { eventModules: ['fire-event'] }, + ], + 'testing-library/await-async-events': [ + 'error', + { + eventModule: 'userEvent', + }, + ], + 'testing-library/no-manual-cleanup': 'off', + 'react/display-name': 'off', + 'react/react-in-jsx-scope': 'off', + }, +}; + +module.exports = { testConfig }; diff --git a/src/frontend/packages/eslint-plugin-docs/typescript.js b/src/frontend/packages/eslint-plugin-docs/typescript.js new file mode 100644 index 000000000..5a398a78c --- /dev/null +++ b/src/frontend/packages/eslint-plugin-docs/typescript.js @@ -0,0 +1,44 @@ +const typescriptEslint = require('@typescript-eslint/eslint-plugin'); +const typescriptParser = require('@typescript-eslint/parser'); + +// TypeScript declaration files configuration +const declarationConfig = { + files: ['*.d.ts'], + rules: { + 'no-unused-vars': 'off', + }, +}; + +// TypeScript configuration +const typescriptConfig = { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parser: typescriptParser, + parserOptions: { + project: true, + }, + }, + plugins: { + '@typescript-eslint': typescriptEslint, + }, + rules: { + '@typescript-eslint/no-explicit-any': 'error', + '@typescript-eslint/no-non-null-assertion': 'error', + '@typescript-eslint/no-unsafe-argument': 'error', + '@typescript-eslint/no-unsafe-member-access': 'error', + '@typescript-eslint/no-unused-vars': [ + 'error', + { varsIgnorePattern: '^_', argsIgnorePattern: '^_' }, + ], + 'sort-imports': [ + 'error', + { + ignoreDeclarationSort: true, + }, + ], + // Turn off base rule as it can report incorrect errors + 'no-unused-vars': 'off', + }, +}; + +module.exports = { declarationConfig, typescriptConfig }; diff --git a/src/frontend/packages/i18n/.eslintrc.js b/src/frontend/packages/i18n/.eslintrc.js deleted file mode 100644 index 475c786bc..000000000 --- a/src/frontend/packages/i18n/.eslintrc.js +++ /dev/null @@ -1,11 +0,0 @@ -module.exports = { - root: true, - extends: ['impress/jest', 'plugin:import/recommended'], - parserOptions: { - sourceType: 'module', - ecmaVersion: 'latest', - tsconfigRootDir: __dirname, - project: ['./tsconfig.json'], - }, - ignorePatterns: ['node_modules'], -}; diff --git a/src/frontend/packages/i18n/eslint.config.mjs b/src/frontend/packages/i18n/eslint.config.mjs new file mode 100644 index 000000000..620d4857d --- /dev/null +++ b/src/frontend/packages/i18n/eslint.config.mjs @@ -0,0 +1,20 @@ +import { defineConfig } from '@eslint/config-helpers'; +import docsPlugin from 'eslint-plugin-docs'; + +const eslintConfig = defineConfig([ + { + files: ['**/*.ts', '**/*.mjs', '**/*.js'], + plugins: { + docs: docsPlugin, + }, + extends: ['docs/next', 'docs/test'], + languageOptions: { + parserOptions: { + tsconfigRootDir: import.meta.dirname, + project: ['./tsconfig.json'], + }, + }, + }, +]); + +export default eslintConfig; diff --git a/src/frontend/packages/i18n/package.json b/src/frontend/packages/i18n/package.json index b97c9cccc..71fecf8af 100644 --- a/src/frontend/packages/i18n/package.json +++ b/src/frontend/packages/i18n/package.json @@ -8,13 +8,13 @@ "format-deploy": "yarn format-deploy:impress", "format-deploy:impress": "node ./format-deploy.mjs --app=impress --output=../../apps/impress/src/i18n/translations.json", "format-rebuild-fr:impress": "node ./rebuild-translations.mjs --language=fr --app=impress --output=../../apps/impress/src/i18n/translations.json", - "lint": "eslint --ext .js,.ts,.mjs .", + "lint": "eslint", "test": "jest" }, "dependencies": { "@types/jest": "30.0.0", "@types/node": "*", - "eslint-config-impress": "*", + "eslint-plugin-docs": "*", "eslint-plugin-import": "2.32.0", "i18next-parser": "9.3.0", "jest": "30.0.5", diff --git a/src/frontend/packages/i18n/tsconfig.json b/src/frontend/packages/i18n/tsconfig.json index c4350f5a3..2c5fee270 100644 --- a/src/frontend/packages/i18n/tsconfig.json +++ b/src/frontend/packages/i18n/tsconfig.json @@ -16,6 +16,8 @@ }, "include": [ "**/*.ts", + "**/*.js", + "**/*.mjs" ], "exclude": ["node_modules"] } diff --git a/src/frontend/servers/y-provider/.eslintrc.cjs b/src/frontend/servers/y-provider/.eslintrc.cjs deleted file mode 100644 index 9e0dff2ab..000000000 --- a/src/frontend/servers/y-provider/.eslintrc.cjs +++ /dev/null @@ -1,17 +0,0 @@ -module.exports = { - root: true, - extends: ['impress/jest', 'impress/next'], - parserOptions: { - tsconfigRootDir: __dirname, - project: ['./tsconfig.json'], - }, - settings: { - next: { - rootDir: __dirname, - }, - }, - rules: { - '@next/next/no-html-link-for-pages': 'off', - }, - ignorePatterns: ['node_modules'], -}; diff --git a/src/frontend/servers/y-provider/Dockerfile b/src/frontend/servers/y-provider/Dockerfile index 120dbfd9d..01058037a 100644 --- a/src/frontend/servers/y-provider/Dockerfile +++ b/src/frontend/servers/y-provider/Dockerfile @@ -12,11 +12,11 @@ WORKDIR /home/frontend/ COPY ./src/frontend/package.json ./package.json COPY ./src/frontend/yarn.lock ./yarn.lock COPY ./src/frontend/servers/y-provider/package.json ./servers/y-provider/package.json -COPY ./src/frontend/packages/eslint-config-impress/package.json ./packages/eslint-config-impress/package.json +COPY ./src/frontend/packages/eslint-plugin-docs/package.json ./packages/eslint-plugin-docs/package.json RUN yarn install -COPY ./src/frontend/packages/eslint-config-impress ./packages/eslint-config-impress +COPY ./src/frontend/packages/eslint-plugin-docs ./packages/eslint-plugin-docs COPY ./src/frontend/servers/y-provider ./servers/y-provider FROM y-provider-deps AS y-provider-development diff --git a/src/frontend/servers/y-provider/__tests__/collaborationResetConnections.test.ts b/src/frontend/servers/y-provider/__tests__/collaborationResetConnections.test.ts index 91841cfc9..404d89063 100644 --- a/src/frontend/servers/y-provider/__tests__/collaborationResetConnections.test.ts +++ b/src/frontend/servers/y-provider/__tests__/collaborationResetConnections.test.ts @@ -58,7 +58,6 @@ describe('Server Tests', () => { expect(response.status).toBe(200); expect(response.body).toStrictEqual({ message: 'Connections reset' }); - // eslint-disable-next-line jest/unbound-method expect(closeConnectionsMock).toHaveBeenCalledOnce(); }); }); diff --git a/src/frontend/servers/y-provider/eslint.config.mjs b/src/frontend/servers/y-provider/eslint.config.mjs new file mode 100644 index 000000000..92bd03386 --- /dev/null +++ b/src/frontend/servers/y-provider/eslint.config.mjs @@ -0,0 +1,26 @@ +import { defineConfig } from '@eslint/config-helpers'; +import docsPlugin from 'eslint-plugin-docs'; + +const eslintConfig = defineConfig([ + { + ignores: ['dist/**'], + }, + { + files: ['**/*.mjs', '**/*.ts', '**/*.tsx'], + plugins: { + docs: docsPlugin, + }, + extends: ['docs/next'], + languageOptions: { + parserOptions: { + tsconfigRootDir: import.meta.dirname, + project: ['./tsconfig.json'], + }, + }, + rules: { + '@next/next/no-html-link-for-pages': 'off', + }, + }, +]); + +export default eslintConfig; diff --git a/src/frontend/servers/y-provider/package.json b/src/frontend/servers/y-provider/package.json index 45e319662..4ab4fe427 100644 --- a/src/frontend/servers/y-provider/package.json +++ b/src/frontend/servers/y-provider/package.json @@ -9,7 +9,7 @@ "build": "tsc -p tsconfig.build.json && tsc-alias", "dev": "cross-env COLLABORATION_LOGGING=true && nodemon --config nodemon.json", "start": "node ./dist/start-server.js", - "lint": "eslint . --ext .ts", + "lint": "eslint", "test": "vitest --run" }, "engines": { @@ -37,7 +37,7 @@ "@types/supertest": "6.0.3", "@types/ws": "8.18.1", "cross-env": "10.0.0", - "eslint-config-impress": "*", + "eslint-plugin-docs": "*", "nodemon": "3.1.10", "supertest": "7.1.4", "ts-node": "10.9.2", diff --git a/src/frontend/servers/y-provider/src/servers/hocuspocusServer.ts b/src/frontend/servers/y-provider/src/servers/hocuspocusServer.ts index 376e8ae03..afa6d9cf4 100644 --- a/src/frontend/servers/y-provider/src/servers/hocuspocusServer.ts +++ b/src/frontend/servers/y-provider/src/servers/hocuspocusServer.ts @@ -74,9 +74,12 @@ export const hocuspocusServer = Server.configure({ */ try { const user = await fetchCurrentUser(requestHeaders); + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access context.userId = user.id; - } catch {} + } catch { + /* empty */ + } logger( 'Connection established on room:', diff --git a/src/frontend/servers/y-provider/tsconfig.build.json b/src/frontend/servers/y-provider/tsconfig.build.json index c14ab5093..64ed03649 100644 --- a/src/frontend/servers/y-provider/tsconfig.build.json +++ b/src/frontend/servers/y-provider/tsconfig.build.json @@ -3,5 +3,6 @@ "compilerOptions": { "rootDir": "./src", }, + "include": ["**/*.ts"], "exclude": ["node_modules", "dist", "__tests__"], } diff --git a/src/frontend/servers/y-provider/tsconfig.json b/src/frontend/servers/y-provider/tsconfig.json index 120bda63e..1d16a8b86 100644 --- a/src/frontend/servers/y-provider/tsconfig.json +++ b/src/frontend/servers/y-provider/tsconfig.json @@ -21,6 +21,6 @@ "resolveFullPaths": true, "verbose": false }, - "include": ["**/*.ts"], + "include": ["**/*.ts", "**/*.mjs"], "exclude": ["node_modules"] } diff --git a/src/frontend/yarn.lock b/src/frontend/yarn.lock index 82d9ed4b3..598ff34be 100644 --- a/src/frontend/yarn.lock +++ b/src/frontend/yarn.lock @@ -1516,37 +1516,71 @@ resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.25.8.tgz#610d7ea539d2fcdbe39237b5cc175eb2c4451f9c" integrity sha512-cn3Yr7+OaaZq1c+2pe+8yxC8E144SReCQjN6/2ynubzYjvyqZjTXfQJpAcQpsdJq3My7XADANiYGHoFC69pLQw== -"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.7.0": +"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0", "@eslint-community/eslint-utils@^4.7.0": version "4.7.0" resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz#607084630c6c033992a082de6e6fbc1a8b52175a" integrity sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw== dependencies: eslint-visitor-keys "^3.4.3" -"@eslint-community/regexpp@^4.10.0", "@eslint-community/regexpp@^4.6.1": +"@eslint-community/regexpp@^4.10.0", "@eslint-community/regexpp@^4.12.1": version "4.12.1" resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.12.1.tgz#cfc6cffe39df390a3841cde2abccf92eaa7ae0e0" integrity sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ== -"@eslint/eslintrc@^2.1.4": - version "2.1.4" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.4.tgz#388a269f0f25c1b6adc317b5a2c55714894c70ad" - integrity sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ== +"@eslint/config-array@^0.21.0": + version "0.21.0" + resolved "https://registry.yarnpkg.com/@eslint/config-array/-/config-array-0.21.0.tgz#abdbcbd16b124c638081766392a4d6b509f72636" + integrity sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ== + dependencies: + "@eslint/object-schema" "^2.1.6" + debug "^4.3.1" + minimatch "^3.1.2" + +"@eslint/config-helpers@^0.3.0": + version "0.3.1" + resolved "https://registry.yarnpkg.com/@eslint/config-helpers/-/config-helpers-0.3.1.tgz#d316e47905bd0a1a931fa50e669b9af4104d1617" + integrity sha512-xR93k9WhrDYpXHORXpxVL5oHj3Era7wo6k/Wd8/IsQNnZUTzkGS29lyn3nAT05v6ltUuTFVCCYDEGfy2Or/sPA== + +"@eslint/core@^0.15.0", "@eslint/core@^0.15.2": + version "0.15.2" + resolved "https://registry.yarnpkg.com/@eslint/core/-/core-0.15.2.tgz#59386327d7862cc3603ebc7c78159d2dcc4a868f" + integrity sha512-78Md3/Rrxh83gCxoUc0EiciuOHsIITzLy53m3d9UyiW8y9Dj2D29FeETqyKA+BRK76tnTp6RXWb3pCay8Oyomg== + dependencies: + "@types/json-schema" "^7.0.15" + +"@eslint/eslintrc@^3.3.1": + version "3.3.1" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-3.3.1.tgz#e55f7f1dd400600dd066dbba349c4c0bac916964" + integrity sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ== dependencies: ajv "^6.12.4" debug "^4.3.2" - espree "^9.6.0" - globals "^13.19.0" + espree "^10.0.1" + globals "^14.0.0" ignore "^5.2.0" import-fresh "^3.2.1" js-yaml "^4.1.0" minimatch "^3.1.2" strip-json-comments "^3.1.1" -"@eslint/js@8.57.0": - version "8.57.0" - resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.57.0.tgz#a5417ae8427873f1dd08b70b3574b453e67b5f7f" - integrity sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g== +"@eslint/js@9.32.0": + version "9.32.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.32.0.tgz#a02916f58bd587ea276876cb051b579a3d75d091" + integrity sha512-BBpRFZK3eX6uMLKz8WxFOBIFFcGFJ/g8XuwjTHCqHROSIsopI+ddn/d5Cfh36+7+e5edVS8dbSHnBNhrLEX0zg== + +"@eslint/object-schema@^2.1.6": + version "2.1.6" + resolved "https://registry.yarnpkg.com/@eslint/object-schema/-/object-schema-2.1.6.tgz#58369ab5b5b3ca117880c0f6c0b0f32f6950f24f" + integrity sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA== + +"@eslint/plugin-kit@^0.3.4": + version "0.3.5" + resolved "https://registry.yarnpkg.com/@eslint/plugin-kit/-/plugin-kit-0.3.5.tgz#fd8764f0ee79c8ddab4da65460c641cefee017c5" + integrity sha512-Z5kJ+wU3oA7MMIqVR9tyZRtjYPr4OC004Q4Rw7pgOKUOKkJfZ3O24nz3WYfGRpMDNmcOi3TwQOmgm7B7Tpii0w== + dependencies: + "@eslint/core" "^0.15.2" + levn "^0.4.1" "@floating-ui/core@^1.7.3": version "1.7.3" @@ -1705,24 +1739,33 @@ uuid "^11.0.3" ws "^8.5.0" -"@humanwhocodes/config-array@^0.11.14": - version "0.11.14" - resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.14.tgz#d78e481a039f7566ecc9660b4ea7fe6b1fec442b" - integrity sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg== +"@humanfs/core@^0.19.1": + version "0.19.1" + resolved "https://registry.yarnpkg.com/@humanfs/core/-/core-0.19.1.tgz#17c55ca7d426733fe3c561906b8173c336b40a77" + integrity sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA== + +"@humanfs/node@^0.16.6": + version "0.16.6" + resolved "https://registry.yarnpkg.com/@humanfs/node/-/node-0.16.6.tgz#ee2a10eaabd1131987bf0488fd9b820174cd765e" + integrity sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw== dependencies: - "@humanwhocodes/object-schema" "^2.0.2" - debug "^4.3.1" - minimatch "^3.0.5" + "@humanfs/core" "^0.19.1" + "@humanwhocodes/retry" "^0.3.0" "@humanwhocodes/module-importer@^1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== -"@humanwhocodes/object-schema@^2.0.2": - version "2.0.3" - resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz#4a2868d75d6d6963e423bcf90b7fd1be343409d3" - integrity sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA== +"@humanwhocodes/retry@^0.3.0": + version "0.3.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.3.1.tgz#c72a5c76a9fbaf3488e231b13dc52c0da7bab42a" + integrity sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA== + +"@humanwhocodes/retry@^0.4.2": + version "0.4.3" + resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.4.3.tgz#c2b9d2e374ee62c586d3adbea87199b1d7a7a6ba" + integrity sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ== "@img/sharp-darwin-arm64@0.34.3": version "0.34.3" @@ -2304,7 +2347,7 @@ resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== -"@nodelib/fs.walk@^1.2.3", "@nodelib/fs.walk@^1.2.8": +"@nodelib/fs.walk@^1.2.3": version "1.2.8" resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== @@ -5269,7 +5312,7 @@ "@types/estree" "*" "@types/json-schema" "*" -"@types/estree@*", "@types/estree@1.0.8", "@types/estree@^1.0.0", "@types/estree@^1.0.8": +"@types/estree@*", "@types/estree@1.0.8", "@types/estree@^1.0.0", "@types/estree@^1.0.6", "@types/estree@^1.0.8": version "1.0.8" resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.8.tgz#958b91c991b1867ced318bedea0e215ee050726e" integrity sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w== @@ -5651,6 +5694,14 @@ "@typescript-eslint/types" "^8.39.0" debug "^4.3.4" +"@typescript-eslint/scope-manager@7.18.0": + version "7.18.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-7.18.0.tgz#c928e7a9fc2c0b3ed92ab3112c614d6bd9951c83" + integrity sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA== + dependencies: + "@typescript-eslint/types" "7.18.0" + "@typescript-eslint/visitor-keys" "7.18.0" + "@typescript-eslint/scope-manager@8.39.0", "@typescript-eslint/scope-manager@^8.15.0": version "8.39.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.39.0.tgz#ba4bf6d8257bbc172c298febf16bc22df4856570" @@ -5675,11 +5726,30 @@ debug "^4.3.4" ts-api-utils "^2.1.0" +"@typescript-eslint/types@7.18.0": + version "7.18.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-7.18.0.tgz#b90a57ccdea71797ffffa0321e744f379ec838c9" + integrity sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ== + "@typescript-eslint/types@8.39.0", "@typescript-eslint/types@^8.39.0": version "8.39.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.39.0.tgz#80f010b7169d434a91cd0529d70a528dbc9c99c6" integrity sha512-ArDdaOllnCj3yn/lzKn9s0pBQYmmyme/v1HbGIGB0GB/knFI3fWMHloC+oYTJW46tVbYnGKTMDK4ah1sC2v0Kg== +"@typescript-eslint/typescript-estree@7.18.0": + version "7.18.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-7.18.0.tgz#b5868d486c51ce8f312309ba79bdb9f331b37931" + integrity sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA== + dependencies: + "@typescript-eslint/types" "7.18.0" + "@typescript-eslint/visitor-keys" "7.18.0" + debug "^4.3.4" + globby "^11.1.0" + is-glob "^4.0.3" + minimatch "^9.0.4" + semver "^7.6.0" + ts-api-utils "^1.3.0" + "@typescript-eslint/typescript-estree@8.39.0": version "8.39.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.39.0.tgz#b9477a5c47a0feceffe91adf553ad9a3cd4cb3d6" @@ -5706,6 +5776,24 @@ "@typescript-eslint/types" "8.39.0" "@typescript-eslint/typescript-estree" "8.39.0" +"@typescript-eslint/utils@^7.7.1": + version "7.18.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-7.18.0.tgz#bca01cde77f95fc6a8d5b0dbcbfb3d6ca4be451f" + integrity sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw== + dependencies: + "@eslint-community/eslint-utils" "^4.4.0" + "@typescript-eslint/scope-manager" "7.18.0" + "@typescript-eslint/types" "7.18.0" + "@typescript-eslint/typescript-estree" "7.18.0" + +"@typescript-eslint/visitor-keys@7.18.0": + version "7.18.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-7.18.0.tgz#0564629b6124d67607378d0f0332a0495b25e7d7" + integrity sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg== + dependencies: + "@typescript-eslint/types" "7.18.0" + eslint-visitor-keys "^3.4.3" + "@typescript-eslint/visitor-keys@8.39.0": version "8.39.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.39.0.tgz#5d619a6e810cdd3fd1913632719cbccab08bf875" @@ -5714,7 +5802,7 @@ "@typescript-eslint/types" "8.39.0" eslint-visitor-keys "^4.2.1" -"@ungap/structured-clone@^1.0.0", "@ungap/structured-clone@^1.2.0", "@ungap/structured-clone@^1.3.0": +"@ungap/structured-clone@^1.0.0", "@ungap/structured-clone@^1.3.0": version "1.3.0" resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.3.0.tgz#d06bbb384ebcf6c505fde1c3d0ed4ddffe0aaff8" integrity sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g== @@ -6043,7 +6131,7 @@ acorn-walk@^8.1.1: dependencies: acorn "^8.11.0" -acorn@^8.11.0, acorn@^8.14.0, acorn@^8.15.0, acorn@^8.4.1, acorn@^8.8.1, acorn@^8.9.0: +acorn@^8.11.0, acorn@^8.14.0, acorn@^8.15.0, acorn@^8.4.1, acorn@^8.8.1: version "8.15.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.15.0.tgz#a360898bc415edaac46c8241f6383975b930b816" integrity sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg== @@ -7117,7 +7205,7 @@ cross-env@10.0.0: "@epic-web/invariant" "^1.0.0" cross-spawn "^7.0.6" -cross-spawn@^7.0.2, cross-spawn@^7.0.3, cross-spawn@^7.0.6: +cross-spawn@^7.0.3, cross-spawn@^7.0.6: version "7.0.6" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f" integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA== @@ -7414,13 +7502,6 @@ doctrine@^2.1.0: dependencies: esutils "^2.0.2" -doctrine@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" - integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== - dependencies: - esutils "^2.0.2" - docx@9.5.0, docx@^9.0.2: version "9.5.0" resolved "https://registry.yarnpkg.com/docx/-/docx-9.5.0.tgz#586990c4ecf1c7e83290529997b33f2c029bbe68" @@ -7929,7 +8010,7 @@ eslint-plugin-react-hooks@^5.0.0: resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.2.0.tgz#1be0080901e6ac31ce7971beed3d3ec0a423d9e3" integrity sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg== -eslint-plugin-react@^7.37.0: +eslint-plugin-react@7.37.5, eslint-plugin-react@^7.37.0: version "7.37.5" resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.37.5.tgz#2975511472bdda1b272b34d779335c9b0e877065" integrity sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA== @@ -7961,6 +8042,13 @@ eslint-plugin-testing-library@7.6.3: "@typescript-eslint/scope-manager" "^8.15.0" "@typescript-eslint/utils" "^8.15.0" +eslint-plugin-vitest@0.5.4: + version "0.5.4" + resolved "https://registry.yarnpkg.com/eslint-plugin-vitest/-/eslint-plugin-vitest-0.5.4.tgz#2838a40ee116ba7c15eb6132df31371d960e3bf5" + integrity sha512-um+odCkccAHU53WdKAw39MY61+1x990uXjSPguUCq3VcEHdqJrOb8OTMrbYlY6f9jAKx7x98kLVlIe3RJeJqoQ== + dependencies: + "@typescript-eslint/utils" "^7.7.1" + eslint-scope@5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" @@ -7969,15 +8057,15 @@ eslint-scope@5.1.1: esrecurse "^4.3.0" estraverse "^4.1.1" -eslint-scope@^7.2.2: - version "7.2.2" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.2.tgz#deb4f92563390f32006894af62a22dba1c46423f" - integrity sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg== +eslint-scope@^8.4.0: + version "8.4.0" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-8.4.0.tgz#88e646a207fad61436ffa39eb505147200655c82" + integrity sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg== dependencies: esrecurse "^4.3.0" estraverse "^5.2.0" -eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.3: +eslint-visitor-keys@^3.4.3: version "3.4.3" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== @@ -7987,65 +8075,62 @@ eslint-visitor-keys@^4.2.1: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz#4cfea60fe7dd0ad8e816e1ed026c1d5251b512c1" integrity sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ== -eslint@*, eslint@8.57.0: - version "8.57.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.57.0.tgz#c786a6fd0e0b68941aaf624596fb987089195668" - integrity sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ== +eslint@9.32.0: + version "9.32.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-9.32.0.tgz#4ea28df4a8dbc454e1251e0f3aed4bcf4ce50a47" + integrity sha512-LSehfdpgMeWcTZkWZVIJl+tkZ2nuSkyyB9C27MZqFWXuph7DvaowgcTvKqxvpLW1JZIk8PN7hFY3Rj9LQ7m7lg== dependencies: "@eslint-community/eslint-utils" "^4.2.0" - "@eslint-community/regexpp" "^4.6.1" - "@eslint/eslintrc" "^2.1.4" - "@eslint/js" "8.57.0" - "@humanwhocodes/config-array" "^0.11.14" + "@eslint-community/regexpp" "^4.12.1" + "@eslint/config-array" "^0.21.0" + "@eslint/config-helpers" "^0.3.0" + "@eslint/core" "^0.15.0" + "@eslint/eslintrc" "^3.3.1" + "@eslint/js" "9.32.0" + "@eslint/plugin-kit" "^0.3.4" + "@humanfs/node" "^0.16.6" "@humanwhocodes/module-importer" "^1.0.1" - "@nodelib/fs.walk" "^1.2.8" - "@ungap/structured-clone" "^1.2.0" + "@humanwhocodes/retry" "^0.4.2" + "@types/estree" "^1.0.6" + "@types/json-schema" "^7.0.15" ajv "^6.12.4" chalk "^4.0.0" - cross-spawn "^7.0.2" + cross-spawn "^7.0.6" debug "^4.3.2" - doctrine "^3.0.0" escape-string-regexp "^4.0.0" - eslint-scope "^7.2.2" - eslint-visitor-keys "^3.4.3" - espree "^9.6.1" - esquery "^1.4.2" + eslint-scope "^8.4.0" + eslint-visitor-keys "^4.2.1" + espree "^10.4.0" + esquery "^1.5.0" esutils "^2.0.2" fast-deep-equal "^3.1.3" - file-entry-cache "^6.0.1" + file-entry-cache "^8.0.0" find-up "^5.0.0" glob-parent "^6.0.2" - globals "^13.19.0" - graphemer "^1.4.0" ignore "^5.2.0" imurmurhash "^0.1.4" is-glob "^4.0.0" - is-path-inside "^3.0.3" - js-yaml "^4.1.0" json-stable-stringify-without-jsonify "^1.0.1" - levn "^0.4.1" lodash.merge "^4.6.2" minimatch "^3.1.2" natural-compare "^1.4.0" optionator "^0.9.3" - strip-ansi "^6.0.1" - text-table "^0.2.0" -espree@^9.6.0, espree@^9.6.1: - version "9.6.1" - resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f" - integrity sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ== +espree@^10.0.1, espree@^10.4.0: + version "10.4.0" + resolved "https://registry.yarnpkg.com/espree/-/espree-10.4.0.tgz#d54f4949d4629005a1fa168d937c3ff1f7e2a837" + integrity sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ== dependencies: - acorn "^8.9.0" + acorn "^8.15.0" acorn-jsx "^5.3.2" - eslint-visitor-keys "^3.4.1" + eslint-visitor-keys "^4.2.1" esprima@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== -esquery@^1.4.2: +esquery@^1.5.0: version "1.6.0" resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.6.0.tgz#91419234f804d852a82dceec3e16cdc22cf9dae7" integrity sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg== @@ -8302,12 +8387,12 @@ file-entry-cache@^10.1.3: dependencies: flat-cache "^6.1.12" -file-entry-cache@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" - integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== +file-entry-cache@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-8.0.0.tgz#7787bddcf1131bffb92636c69457bbc0edd6d81f" + integrity sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ== dependencies: - flat-cache "^3.0.4" + flat-cache "^4.0.0" filelist@^1.0.4: version "1.0.4" @@ -8356,14 +8441,13 @@ find-up@^5.0.0: locate-path "^6.0.0" path-exists "^4.0.0" -flat-cache@^3.0.4: - version "3.2.0" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.2.0.tgz#2c0c2d5040c99b1632771a9d105725c0115363ee" - integrity sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw== +flat-cache@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-4.0.1.tgz#0ece39fcb14ee012f4b0410bd33dd9c1f011127c" + integrity sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw== dependencies: flatted "^3.2.9" - keyv "^4.5.3" - rimraf "^3.0.2" + keyv "^4.5.4" flat-cache@^6.1.12: version "6.1.12" @@ -8702,13 +8786,18 @@ global-prefix@^3.0.0: kind-of "^6.0.2" which "^1.3.1" -globals@^13.19.0, globals@^13.23.0: +globals@^13.23.0: version "13.24.0" resolved "https://registry.yarnpkg.com/globals/-/globals-13.24.0.tgz#8432a19d78ce0c1e833949c36adb345400bb1171" integrity sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ== dependencies: type-fest "^0.20.2" +globals@^14.0.0: + version "14.0.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-14.0.0.tgz#898d7413c29babcf6bafe56fcadded858ada724e" + integrity sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ== + globalthis@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.4.tgz#7430ed3a975d97bfb59bcce41f5cabbafa651236" @@ -9457,11 +9546,6 @@ is-obj@^1.0.1: resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" integrity sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg== -is-path-inside@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" - integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== - is-plain-obj@^4.0.0: version "4.1.0" resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-4.1.0.tgz#d65025edec3657ce032fd7db63c97883eaed71f0" @@ -10226,7 +10310,7 @@ jszip@^3.10.1: readable-stream "~2.3.6" setimmediate "^1.0.5" -keyv@^4.5.3: +keyv@^4.5.4: version "4.5.4" resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== @@ -11032,7 +11116,7 @@ minimalistic-assert@^1.0.1: resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== -minimatch@^3.0.2, minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: +minimatch@^3.0.2, minimatch@^3.0.4, minimatch@^3.1.1, minimatch@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== @@ -13755,11 +13839,6 @@ text-decoder@^1.1.0: dependencies: b4a "^1.6.4" -text-table@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" - integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== - through2@^2.0.1: version "2.0.5" resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" @@ -13895,6 +13974,11 @@ trough@^2.0.0: resolved "https://registry.yarnpkg.com/trough/-/trough-2.2.0.tgz#94a60bd6bd375c152c1df911a4b11d5b0256f50f" integrity sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw== +ts-api-utils@^1.3.0: + version "1.4.3" + resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.4.3.tgz#bfc2215fe6528fecab2b0fba570a2e8a4263b064" + integrity sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw== + ts-api-utils@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-2.1.0.tgz#595f7094e46eed364c13fd23e75f9513d29baf91"