Update dependencies and enhance ESLint config

This commit is contained in:
Ludy87 2025-09-26 11:28:41 +02:00
parent fd52dc0226
commit 4a8e2e477c
No known key found for this signature in database
GPG Key ID: 92696155E0220F94
38 changed files with 2196 additions and 402 deletions

1
.gitignore vendored
View File

@ -210,3 +210,4 @@ node_modules/
test_batch.json test_batch.json
*.backup.*.json *.backup.*.json
frontend/public/locales/*/translation.backup*.json frontend/public/locales/*/translation.backup*.json
/frontend

View File

@ -1,19 +1,39 @@
// @ts-check // @ts-check
import { fileURLToPath } from 'node:url';
import eslint from '@eslint/js'; import eslint from '@eslint/js';
import globals from 'globals';
import { defineConfig } from 'eslint/config'; import { defineConfig } from 'eslint/config';
import reactHooksPlugin from 'eslint-plugin-react-hooks';
import reactPlugin from 'eslint-plugin-react';
import tseslint from 'typescript-eslint'; import tseslint from 'typescript-eslint';
const tsconfigRootDir = fileURLToPath(new URL('./', import.meta.url));
const srcGlobs = ['{src,frontend/src}/**/*.{ts,tsx,js,jsx}'];
const srcTsGlobs = ['{src,frontend/src}/**/*.{ts,tsx}'];
const nodeGlobs = [
'scripts/**/*.{js,ts}',
'vite.config.ts',
'vitest.config.ts',
'vitest.minimal.config.ts',
'playwright.config.ts',
'tailwind.config.js',
'postcss.config.js',
'eslint.config.mjs',
];
export default defineConfig( export default defineConfig(
eslint.configs.recommended,
tseslint.configs.recommended,
{ {
ignores: [ ignores: [
"dist", // Contains 3rd party code "dist", // Contains 3rd party code
"public", // Contains 3rd party code "public", // Contains 3rd party code
], ],
}, },
eslint.configs.recommended,
{ {
files: ['**/*.{ts,tsx}'],
extends: [...tseslint.configs.recommended],
rules: { rules: {
"no-undef": "off", // Temporarily disabled until codebase conformant "no-undef": "off", // Temporarily disabled until codebase conformant
"@typescript-eslint/no-empty-object-type": [ "@typescript-eslint/no-empty-object-type": [
@ -26,17 +46,112 @@ export default defineConfig(
"@typescript-eslint/no-explicit-any": "off", // Temporarily disabled until codebase conformant "@typescript-eslint/no-explicit-any": "off", // Temporarily disabled until codebase conformant
"@typescript-eslint/no-require-imports": "off", // Temporarily disabled until codebase conformant "@typescript-eslint/no-require-imports": "off", // Temporarily disabled until codebase conformant
"@typescript-eslint/no-unused-vars": [ "@typescript-eslint/no-unused-vars": [
"error", "warn",
{ {
"args": "all", // All function args must be used (or explicitly ignored) args: 'all', // All function args must be used (or explicitly ignored)
"argsIgnorePattern": "^_", // Allow unused variables beginning with an underscore argsIgnorePattern: '^_', // Allow unused variables beginning with an underscore
"caughtErrors": "all", // Caught errors must be used (or explicitly ignored) caughtErrors: 'all', // Caught errors must be used (or explicitly ignored)
"caughtErrorsIgnorePattern": "^_", // Allow unused variables beginning with an underscore caughtErrorsIgnorePattern: '^_', // Allow unused variables beginning with an underscore
"destructuredArrayIgnorePattern": "^_", // Allow unused variables beginning with an underscore destructuredArrayIgnorePattern: '^_', // Allow unused variables beginning with an underscore
"varsIgnorePattern": "^_", // Allow unused variables beginning with an underscore varsIgnorePattern: '^_', // Allow unused variables beginning with an underscore
"ignoreRestSiblings": true, // Allow unused variables when removing attributes from objects (otherwise this requires explicit renaming like `({ x: _x, ...y }) => y`, which is clunky) ignoreRestSiblings: true, // Allow unused variables when removing attributes from objects (otherwise this requires explicit renaming like `({ x: _x, ...y }) => y`, which is clunky)
}, },
], ],
}, },
},
{
files: srcTsGlobs,
extends: [
...tseslint.configs.recommendedTypeChecked,
...tseslint.configs.stylisticTypeChecked,
],
languageOptions: {
parserOptions: {
projectService: true,
tsconfigRootDir,
},
},
},
{
files: srcGlobs,
extends: [reactPlugin.configs.flat.recommended],
languageOptions: {
globals: {
...globals.browser,
},
},
plugins: {
react: reactPlugin,
'react-hooks': reactHooksPlugin,
},
settings: {
react: {
version: 'detect',
},
},
rules: {
'react/react-in-jsx-scope': 'off', // Not needed with React 17+
'react-hooks/exhaustive-deps': 'off', // Temporarily disabled until codebase conformant
'react-hooks/rules-of-hooks': 'warn',
'@typescript-eslint/no-empty-function': 'off',
'@typescript-eslint/no-unsafe-member-access': 'off', // Temporarily disabled until codebase conformant
'@typescript-eslint/no-explicit-any': 'off', // Temporarily disabled until codebase conformant
"@typescript-eslint/no-inferrable-types": "off", // Temporarily disabled until codebase conformant
'@typescript-eslint/prefer-nullish-coalescing': 'off', // Temporarily disabled until codebase conformant
'@typescript-eslint/no-unsafe-assignment': 'off', // Temporarily disabled until codebase conformant
'@typescript-eslint/no-unsafe-return': 'off', // Temporarily disabled until codebase conformant
'@typescript-eslint/no-unsafe-call': 'off', // Temporarily disabled until codebase conformant
'@typescript-eslint/no-unsafe-arguments': 'off', // Temporarily disabled until codebase conformant
'@typescript-eslint/no-unsafe-argument': 'off', // Temporarily disabled until codebase conformant
'@typescript-eslint/require-await': 'off', // Temporarily disabled until codebase conformant
'@typescript-eslint/only-throw-error': 'off', // Temporarily disabled until codebase conformant
'@typescript-eslint/no-floating-promises': 'off', // Temporarily disabled until codebase conformant
'@typescript-eslint/prefer-promise-reject-errors': 'off', // Temporarily disabled until codebase conformant
'@typescript-eslint/prefer-optional-chain': 'off', // Temporarily disabled until codebase conformant
'@typescript-eslint/no-unnecessary-type-assertions': 'off', // Temporarily disabled until codebase conformant
'@typescript-eslint/unbound-method': 'off', // Temporarily disabled until codebase conformant
'@typescript-eslint/no-base-to-string': 'off', // Temporarily disabled until codebase conformant
'@typescript-eslint/no-misused-promises': 'off', // Temporarily disabled until codebase conformant
'@typescript-eslint/no-unnecessary-type-assertion': 'off', // Temporarily disabled until codebase conformant
'@typescript-eslint/restrict-template-expressions': 'off', // Temporarily disabled until codebase conformant
'@typescript-eslint/dot-notation': 'off', // Temporarily disabled until codebase conformant
'@typescript-eslint/prefer-regexp-exec': 'off', // Temporarily disabled until codebase conformant
'@typescript-eslint/prefer-includes': 'off', // Temporarily disabled until codebase conformant
'@typescript-eslint/consistent-indexed-object-style': 'off', // Temporarily disabled until codebase conformant
'@typescript-eslint/non-nullable-type-assertion-style': 'off', // Temporarily disabled until codebase conformant
'@typescript-eslint/consistent-generic-constructors': 'off', // Temporarily disabled until codebase conformant
'@typescript-eslint/class-literal-property-style': 'off', // Temporarily disabled until codebase conformant
'@typescript-eslint/consistent-type-definitions': 'off', // Temporarily disabled until codebase conformant
'@typescript-eslint/no-redundant-type-constituents': 'off', // Temporarily disabled until codebase conformant
'react/no-children-prop': 'warn', // Children should be passed as actual children, not via the children prop
'react/prop-types': 'off', // We use TypeScript's types for props instead
'react/display-name': 'off', // Temporarily disabled until codebase conformant
'react/no-unescaped-entities': 'off', // Temporarily disabled until codebase conformant
},
},
{
files: [
'src/**/*.{test,spec}.{ts,tsx}',
'src/tests/**/*.{ts,tsx}',
],
extends: [tseslint.configs.disableTypeChecked],
languageOptions: {
globals: {
...globals.browser,
...globals.vitest,
},
},
},
{
files: nodeGlobs,
extends: [tseslint.configs.disableTypeChecked],
languageOptions: {
globals: {
...globals.node,
},
},
} }
); );

File diff suppressed because it is too large Load Diff

View File

@ -6,32 +6,36 @@
"proxy": "http://localhost:8080", "proxy": "http://localhost:8080",
"dependencies": { "dependencies": {
"@atlaskit/pragmatic-drag-and-drop": "^1.7.7", "@atlaskit/pragmatic-drag-and-drop": "^1.7.7",
"@embedpdf/core": "^1.2.1", "@embedpdf/core": "^1.3.1",
"@embedpdf/engines": "^1.2.1", "@embedpdf/engines": "^1.3.1",
"@embedpdf/plugin-interaction-manager": "^1.2.1", "@embedpdf/plugin-interaction-manager": "^1.3.1",
"@embedpdf/plugin-loader": "^1.2.1", "@embedpdf/plugin-loader": "^1.3.1",
"@embedpdf/plugin-pan": "^1.2.1", "@embedpdf/plugin-pan": "^1.3.1",
"@embedpdf/plugin-render": "^1.2.1", "@embedpdf/plugin-render": "^1.3.1",
"@embedpdf/plugin-rotate": "^1.2.1", "@embedpdf/plugin-rotate": "^1.3.1",
"@embedpdf/plugin-scroll": "^1.2.1", "@embedpdf/plugin-scroll": "^1.3.1",
"@embedpdf/plugin-search": "^1.2.1", "@embedpdf/plugin-search": "^1.3.1",
"@embedpdf/plugin-selection": "^1.2.1", "@embedpdf/plugin-selection": "^1.3.1",
"@embedpdf/plugin-spread": "^1.2.1", "@embedpdf/plugin-spread": "^1.3.1",
"@embedpdf/plugin-thumbnail": "^1.2.1", "@embedpdf/plugin-thumbnail": "^1.3.1",
"@embedpdf/plugin-tiling": "^1.2.1", "@embedpdf/plugin-tiling": "^1.3.1",
"@embedpdf/plugin-viewport": "^1.2.1", "@embedpdf/plugin-viewport": "^1.3.1",
"@embedpdf/plugin-zoom": "^1.2.1", "@embedpdf/plugin-zoom": "^1.3.1",
"@emotion/react": "^11.14.0", "@emotion/react": "^11.14.0",
"@emotion/styled": "^11.14.1", "@emotion/styled": "^11.14.1",
"@iconify/react": "^6.0.2", "@iconify/react": "^6.0.2",
"@mantine/core": "^8.3.1", "@mantine/core": "^8.3.2",
"@mantine/dates": "^8.3.1", "@mantine/dates": "^8.3.2",
"@mantine/dropzone": "^8.3.1", "@mantine/dropzone": "^8.3.2",
"@mantine/hooks": "^8.3.1", "@mantine/hooks": "^8.3.2",
"@mui/icons-material": "^7.3.2", "@mui/icons-material": "^7.3.2",
"@mui/material": "^7.3.2", "@mui/material": "^7.3.2",
"@tailwindcss/postcss": "^4.1.13", "@tailwindcss/postcss": "^4.1.13",
"@tanstack/react-virtual": "^3.13.12", "@tanstack/react-virtual": "^3.13.12",
"@testing-library/dom": "^10.4.1",
"@testing-library/jest-dom": "^6.8.0",
"@testing-library/react": "^16.3.0",
"@testing-library/user-event": "^14.6.1",
"autoprefixer": "^10.4.21", "autoprefixer": "^10.4.21",
"axios": "^1.12.2", "axios": "^1.12.2",
"i18next": "^25.5.2", "i18next": "^25.5.2",
@ -41,11 +45,11 @@
"license-report": "^6.8.0", "license-report": "^6.8.0",
"pdf-lib": "^1.17.1", "pdf-lib": "^1.17.1",
"pdfjs-dist": "^5.4.149", "pdfjs-dist": "^5.4.149",
"posthog-js": "^1.268.0", "posthog-js": "^1.268.5",
"react": "^19.1.1", "react": "^19.1.1",
"react-dom": "^19.1.1", "react-dom": "^19.1.1",
"react-i18next": "^15.7.3", "react-i18next": "^16.0.0",
"react-router-dom": "^7.9.1", "react-router-dom": "^7.9.2",
"tailwindcss": "^4.1.13", "tailwindcss": "^4.1.13",
"web-vitals": "^5.1.0" "web-vitals": "^5.1.0"
}, },
@ -54,6 +58,7 @@
"dev": "npm run typecheck && vite", "dev": "npm run typecheck && vite",
"prebuild": "npm run generate-icons", "prebuild": "npm run generate-icons",
"lint": "eslint", "lint": "eslint",
"lint:fix": "eslint --fix",
"build": "npm run typecheck && vite build", "build": "npm run typecheck && vite build",
"preview": "vite preview", "preview": "vite preview",
"typecheck": "tsc --noEmit", "typecheck": "tsc --noEmit",
@ -94,9 +99,9 @@
}, },
"devDependencies": { "devDependencies": {
"@eslint/js": "^9.36.0", "@eslint/js": "^9.36.0",
"@iconify-json/material-symbols": "^1.2.37", "@iconify-json/material-symbols": "^1.2.39",
"@iconify/utils": "^3.0.2", "@iconify/utils": "^3.0.2",
"@playwright/test": "^1.55.0", "@playwright/test": "^1.55.1",
"@testing-library/dom": "^10.4.1", "@testing-library/dom": "^10.4.1",
"@testing-library/jest-dom": "^6.8.0", "@testing-library/jest-dom": "^6.8.0",
"@testing-library/react": "^16.3.0", "@testing-library/react": "^16.3.0",
@ -109,7 +114,9 @@
"@vitejs/plugin-react-swc": "^4.1.0", "@vitejs/plugin-react-swc": "^4.1.0",
"@vitest/coverage-v8": "^3.2.4", "@vitest/coverage-v8": "^3.2.4",
"eslint": "^9.36.0", "eslint": "^9.36.0",
"eslint-plugin-react": "^7.37.5",
"eslint-plugin-react-hooks": "^5.2.0", "eslint-plugin-react-hooks": "^5.2.0",
"globals": "^16.4.0",
"jsdom": "^27.0.0", "jsdom": "^27.0.0",
"license-checker": "^25.0.1", "license-checker": "^25.0.1",
"madge": "^8.0.0", "madge": "^8.0.0",

View File

@ -14,7 +14,7 @@ interface DragDropGridProps<T extends DragDropItem> {
selectionMode: boolean; selectionMode: boolean;
isAnimating: boolean; isAnimating: boolean;
onReorderPages: (sourcePageNumber: number, targetIndex: number, selectedPageIds?: string[]) => void; onReorderPages: (sourcePageNumber: number, targetIndex: number, selectedPageIds?: string[]) => void;
renderItem: (item: T, index: number, refs: React.MutableRefObject<Map<string, HTMLDivElement>>) => React.ReactNode; renderItem: (item: T, index: number, refs: React.RefObject<Map<string, HTMLDivElement>>) => React.ReactNode;
renderSplitMarker?: (item: T, index: number) => React.ReactNode; renderSplitMarker?: (item: T, index: number) => React.ReactNode;
} }

View File

@ -23,7 +23,7 @@ interface PageThumbnailProps {
selectionMode: boolean; selectionMode: boolean;
movingPage: number | null; movingPage: number | null;
isAnimating: boolean; isAnimating: boolean;
pageRefs: React.MutableRefObject<Map<string, HTMLDivElement>>; pageRefs: React.RefObject<Map<string, HTMLDivElement>>;
onReorderPages: (sourcePageNumber: number, targetIndex: number, selectedPageIds?: string[]) => void; onReorderPages: (sourcePageNumber: number, targetIndex: number, selectedPageIds?: string[]) => void;
onTogglePage: (pageId: string) => void; onTogglePage: (pageId: string) => void;
onAnimateReorder: () => void; onAnimateReorder: () => void;

View File

@ -8,7 +8,7 @@ import { StirlingFileStub } from "../../types/fileContext";
import { FileId } from "../../types/file"; import { FileId } from "../../types/file";
interface FileGridProps { interface FileGridProps {
files: Array<{ file: File; record?: StirlingFileStub }>; files: { file: File; record?: StirlingFileStub }[];
onRemove?: (index: number) => void; onRemove?: (index: number) => void;
onDoubleClick?: (item: { file: File; record?: StirlingFileStub }) => void; onDoubleClick?: (item: { file: File; record?: StirlingFileStub }) => void;
onView?: (item: { file: File; record?: StirlingFileStub }) => void; onView?: (item: { file: File; record?: StirlingFileStub }) => void;

View File

@ -8,7 +8,7 @@ export { useToast, ToastProvider, ToastRenderer };
let _api: ReturnType<typeof createImperativeApi> | null = null; let _api: ReturnType<typeof createImperativeApi> | null = null;
function createImperativeApi() { function createImperativeApi() {
const subscribers: Array<(fn: any) => void> = []; const subscribers: ((fn: any) => void)[] = [];
let api: any = null; let api: any = null;
return { return {
provide(instance: any) { provide(instance: any) {

View File

@ -9,7 +9,7 @@ import NoToolsFound from './shared/NoToolsFound';
import "./toolPicker/ToolPicker.css"; import "./toolPicker/ToolPicker.css";
interface SearchResultsProps { interface SearchResultsProps {
filteredTools: Array<{ item: [string, ToolRegistryEntry]; matchedText?: string }>; filteredTools: { item: [string, ToolRegistryEntry]; matchedText?: string }[];
onSelect: (id: string) => void; onSelect: (id: string) => void;
searchQuery?: string; searchQuery?: string;
} }

View File

@ -10,7 +10,7 @@ import { renderToolButtons } from "./shared/renderToolButtons";
interface ToolPickerProps { interface ToolPickerProps {
selectedToolKey: string | null; selectedToolKey: string | null;
onSelect: (id: string) => void; onSelect: (id: string) => void;
filteredTools: Array<{ item: [string, ToolRegistryEntry]; matchedText?: string }>; filteredTools: { item: [string, ToolRegistryEntry]; matchedText?: string }[];
isSearching?: boolean; isSearching?: boolean;
} }

View File

@ -34,7 +34,7 @@ describe('ChangePermissionsSettings', () => {
); );
// Should render checkboxes for all permission types // Should render checkboxes for all permission types
const permissionKeys = Object.keys(defaultParameters) as Array<keyof ChangePermissionsParameters>; const permissionKeys = Object.keys(defaultParameters) as (keyof ChangePermissionsParameters)[];
const checkboxes = screen.getAllByRole('checkbox'); const checkboxes = screen.getAllByRole('checkbox');
expect(checkboxes).toHaveLength(permissionKeys.length); expect(checkboxes).toHaveLength(permissionKeys.length);
@ -55,7 +55,7 @@ describe('ChangePermissionsSettings', () => {
</TestWrapper> </TestWrapper>
); );
const permissionKeys = Object.keys(defaultParameters) as Array<keyof ChangePermissionsParameters>; const permissionKeys = Object.keys(defaultParameters) as (keyof ChangePermissionsParameters)[];
permissionKeys.forEach(permission => { permissionKeys.forEach(permission => {
expect(screen.getByText(`mock-changePermissions.permissions.${permission}.label`)).toBeInTheDocument(); expect(screen.getByText(`mock-changePermissions.permissions.${permission}.label`)).toBeInTheDocument();
@ -183,13 +183,13 @@ describe('ChangePermissionsSettings', () => {
</TestWrapper> </TestWrapper>
); );
const permissionKeys = Object.keys(defaultParameters) as Array<keyof ChangePermissionsParameters>; const permissionKeys = Object.keys(defaultParameters) as (keyof ChangePermissionsParameters)[];
permissionKeys.forEach(permission => { permissionKeys.forEach(permission => {
expect(mockT).toHaveBeenCalledWith(`changePermissions.permissions.${permission}.label`, permission); expect(mockT).toHaveBeenCalledWith(`changePermissions.permissions.${permission}.label`, permission);
}); });
}); });
test.each(Object.keys(defaultParameters) as Array<keyof ChangePermissionsParameters>)('should handle %s permission type individually', (permission) => { test.each(Object.keys(defaultParameters) as (keyof ChangePermissionsParameters)[])('should handle %s permission type individually', (permission) => {
const testParameters: ChangePermissionsParameters = { const testParameters: ChangePermissionsParameters = {
...defaultParameters, ...defaultParameters,
[permission]: true [permission]: true

View File

@ -14,7 +14,7 @@ const ChangePermissionsSettings = ({ parameters, onParameterChange, disabled = f
return ( return (
<Stack gap="sm"> <Stack gap="sm">
<Stack gap="xs"> <Stack gap="xs">
{(Object.keys(parameters) as Array<keyof ChangePermissionsParameters>).map((key) => ( {(Object.keys(parameters) as (keyof ChangePermissionsParameters)[]).map((key) => (
<Checkbox <Checkbox
key={key} key={key}
label={t(`changePermissions.permissions.${key}.label`, key)} label={t(`changePermissions.permissions.${key}.label`, key)}

View File

@ -27,7 +27,7 @@ import { StirlingFile } from "../../../types/fileContext";
interface ConvertSettingsProps { interface ConvertSettingsProps {
parameters: ConvertParameters; parameters: ConvertParameters;
onParameterChange: <K extends keyof ConvertParameters>(key: K, value: ConvertParameters[K]) => void; onParameterChange: <K extends keyof ConvertParameters>(key: K, value: ConvertParameters[K]) => void;
getAvailableToExtensions: (fromExtension: string) => Array<{value: string, label: string, group: string}>; getAvailableToExtensions: (fromExtension: string) => {value: string, label: string, group: string}[];
selectedFiles: StirlingFile[]; selectedFiles: StirlingFile[];
disabled?: boolean; disabled?: boolean;
} }

View File

@ -11,7 +11,7 @@ interface SanitizeSettingsProps {
const SanitizeSettings = ({ parameters, onParameterChange, disabled = false }: SanitizeSettingsProps) => { const SanitizeSettings = ({ parameters, onParameterChange, disabled = false }: SanitizeSettingsProps) => {
const { t } = useTranslation(); const { t } = useTranslation();
const options = (Object.keys(defaultParameters) as Array<keyof SanitizeParameters>).map((key) => ({ const options = (Object.keys(defaultParameters) as (keyof SanitizeParameters)[]).map((key) => ({
key: key, key: key,
label: t(`sanitize.options.${key}`, key), label: t(`sanitize.options.${key}`, key),
description: t(`sanitize.options.${key}.desc`, `${key} from the PDF`), description: t(`sanitize.options.${key}.desc`, `${key} from the PDF`),

View File

@ -14,7 +14,7 @@ export const renderToolButtons = (
onSelect: (id: string) => void, onSelect: (id: string) => void,
showSubcategoryHeader: boolean = true, showSubcategoryHeader: boolean = true,
disableNavigation: boolean = false, disableNavigation: boolean = false,
searchResults?: Array<{ item: [string, any]; matchedText?: string }> searchResults?: { item: [string, any]; matchedText?: string }[]
) => { ) => {
// Create a map of matched text for quick lookup // Create a map of matched text for quick lookup
const matchedTextMap = new Map<string, string>(); const matchedTextMap = new Map<string, string>();

View File

@ -1,62 +0,0 @@
import { useTranslation } from 'react-i18next';
import { TooltipContent } from '../../types/tips';
/**
* Reusable tooltip for page selection functionality.
* Can be used by any tool that uses the GeneralUtils.parsePageList syntax.
*/
export const usePageSelectionTips = (): TooltipContent => {
const { t } = useTranslation();
return {
header: {
title: t("pageSelection.tooltip.header.title", "Page Selection Guide")
},
tips: [
{
description: t("pageSelection.tooltip.description", "Choose which pages to use for the operation. Supports single pages, ranges, formulas, and the all keyword.")
},
{
title: t("pageSelection.tooltip.individual.title", "Individual Pages"),
description: t("pageSelection.tooltip.individual.description", "Enter numbers separated by commas."),
bullets: [
t("pageSelection.tooltip.individual.bullet1", "<strong>1,3,5</strong> → selects pages 1, 3, 5"),
t("pageSelection.tooltip.individual.bullet2", "<strong>2,7,12</strong> → selects pages 2, 7, 12")
]
},
{
title: t("pageSelection.tooltip.ranges.title", "Page Ranges"),
description: t("pageSelection.tooltip.ranges.description", "Use - for consecutive pages."),
bullets: [
t("pageSelection.tooltip.ranges.bullet1", "<strong>3-6</strong> → selects pages 36"),
t("pageSelection.tooltip.ranges.bullet2", "<strong>10-15</strong> → selects pages 1015"),
t("pageSelection.tooltip.ranges.bullet3", "<strong>5-</strong> → selects pages 5 to end")
]
},
{
title: t("pageSelection.tooltip.mathematical.title", "Mathematical Functions"),
description: t("pageSelection.tooltip.mathematical.description", "Use n in formulas for patterns."),
bullets: [
t("pageSelection.tooltip.mathematical.bullet2", "<strong>2n-1</strong> → all odd pages (1, 3, 5…)"),
t("pageSelection.tooltip.mathematical.bullet1", "<strong>2n</strong> → all even pages (2, 4, 6…)"),
t("pageSelection.tooltip.mathematical.bullet3", "<strong>3n</strong> → every 3rd page (3, 6, 9…)"),
t("pageSelection.tooltip.mathematical.bullet4", "<strong>4n-1</strong> → pages 3, 7, 11, 15…")
]
},
{
title: t("pageSelection.tooltip.special.title", "Special Keywords"),
bullets: [
t("pageSelection.tooltip.special.bullet1", "<strong>all</strong> → selects all pages"),
]
},
{
title: t("pageSelection.tooltip.complex.title", "Complex Combinations"),
description: t("pageSelection.tooltip.complex.description", "Mix different types."),
bullets: [
t("pageSelection.tooltip.complex.bullet1", "<strong>1,3-5,8,2n</strong> → pages 1, 35, 8, plus evens"),
t("pageSelection.tooltip.complex.bullet2", "<strong>10-,2n-1</strong> → from page 10 to end + odd pages")
]
}
]
};
};

View File

@ -14,13 +14,13 @@ interface SearchLayerProps {
} }
interface SearchResultState { interface SearchResultState {
results: Array<{ results: {
pageIndex: number; pageIndex: number;
rects: Array<{ rects: {
origin: { x: number; y: number }; origin: { x: number; y: number };
size: { width: number; height: number }; size: { width: number; height: number };
}>; }[];
}>; }[];
activeResultIndex?: number; activeResultIndex?: number;
} }

View File

@ -4,10 +4,10 @@ import { useViewer } from '../../contexts/ViewerContext';
interface SearchResult { interface SearchResult {
pageIndex: number; pageIndex: number;
rects: Array<{ rects: {
origin: { x: number; y: number }; origin: { x: number; y: number };
size: { width: number; height: number }; size: { width: number; height: number };
}>; }[];
} }
/** /**

View File

@ -101,7 +101,7 @@ interface ToolWorkflowContextValue extends ToolWorkflowState {
handleReaderToggle: () => void; handleReaderToggle: () => void;
// Computed values // Computed values
filteredTools: Array<{ item: [string, ToolRegistryEntry]; matchedText?: string }>; // Filtered by search filteredTools: { item: [string, ToolRegistryEntry]; matchedText?: string }[]; // Filtered by search
isPanelVisible: boolean; isPanelVisible: boolean;
} }

View File

@ -82,10 +82,10 @@ interface RotationState {
interface SearchResult { interface SearchResult {
pageIndex: number; pageIndex: number;
rects: Array<{ rects: {
origin: { x: number; y: number }; origin: { x: number; y: number };
size: { width: number; height: number }; size: { width: number; height: number };
}>; }[];
} }
interface SearchState { interface SearchState {

View File

@ -25,7 +25,7 @@ const DEBUG = process.env.NODE_ENV === 'development';
*/ */
class SimpleMutex { class SimpleMutex {
private locked = false; private locked = false;
private queue: Array<() => void> = []; private queue: (() => void)[] = [];
async lock(): Promise<void> { async lock(): Promise<void> {
if (!this.locked) { if (!this.locked) {
@ -151,7 +151,7 @@ interface AddFileOptions {
files?: File[]; files?: File[];
// For 'processed' files // For 'processed' files
filesWithThumbnails?: Array<{ file: File; thumbnail?: string; pageCount?: number }>; filesWithThumbnails?: { file: File; thumbnail?: string; pageCount?: number }[];
// Insertion position // Insertion position
insertAfterPageId?: string; insertAfterPageId?: string;
@ -165,8 +165,8 @@ interface AddFileOptions {
*/ */
export async function addFiles( export async function addFiles(
options: AddFileOptions, options: AddFileOptions,
stateRef: React.MutableRefObject<FileContextState>, stateRef: React.RefObject<FileContextState>,
filesRef: React.MutableRefObject<Map<FileId, File>>, filesRef: React.RefObject<Map<FileId, File>>,
dispatch: React.Dispatch<FileContextAction>, dispatch: React.Dispatch<FileContextAction>,
lifecycleManager: FileLifecycleManager, lifecycleManager: FileLifecycleManager,
enablePersistence: boolean = false enablePersistence: boolean = false
@ -278,7 +278,7 @@ export async function consumeFiles(
inputFileIds: FileId[], inputFileIds: FileId[],
outputStirlingFiles: StirlingFile[], outputStirlingFiles: StirlingFile[],
outputStirlingFileStubs: StirlingFileStub[], outputStirlingFileStubs: StirlingFileStub[],
filesRef: React.MutableRefObject<Map<FileId, File>>, filesRef: React.RefObject<Map<FileId, File>>,
dispatch: React.Dispatch<FileContextAction> dispatch: React.Dispatch<FileContextAction>
): Promise<FileId[]> { ): Promise<FileId[]> {
if (DEBUG) console.log(`📄 consumeFiles: Processing ${inputFileIds.length} input files, ${outputStirlingFiles.length} output files with pre-created stubs`); if (DEBUG) console.log(`📄 consumeFiles: Processing ${inputFileIds.length} input files, ${outputStirlingFiles.length} output files with pre-created stubs`);
@ -355,9 +355,9 @@ export async function consumeFiles(
* Helper function to restore files to filesRef and manage IndexedDB cleanup * Helper function to restore files to filesRef and manage IndexedDB cleanup
*/ */
async function restoreFilesAndCleanup( async function restoreFilesAndCleanup(
filesToRestore: Array<{ file: File; record: StirlingFileStub }>, filesToRestore: { file: File; record: StirlingFileStub }[],
fileIdsToRemove: FileId[], fileIdsToRemove: FileId[],
filesRef: React.MutableRefObject<Map<FileId, File>>, filesRef: React.RefObject<Map<FileId, File>>,
indexedDB?: { deleteFile: (fileId: FileId) => Promise<void> } | null indexedDB?: { deleteFile: (fileId: FileId) => Promise<void> } | null
): Promise<void> { ): Promise<void> {
// Remove files from filesRef // Remove files from filesRef
@ -406,7 +406,7 @@ export async function undoConsumeFiles(
inputFiles: File[], inputFiles: File[],
inputStirlingFileStubs: StirlingFileStub[], inputStirlingFileStubs: StirlingFileStub[],
outputFileIds: FileId[], outputFileIds: FileId[],
filesRef: React.MutableRefObject<Map<FileId, File>>, filesRef: React.RefObject<Map<FileId, File>>,
dispatch: React.Dispatch<FileContextAction>, dispatch: React.Dispatch<FileContextAction>,
indexedDB?: { saveFile: (file: File, fileId: FileId, existingThumbnail?: string) => Promise<any>; deleteFile: (fileId: FileId) => Promise<void> } | null indexedDB?: { saveFile: (file: File, fileId: FileId, existingThumbnail?: string) => Promise<any>; deleteFile: (fileId: FileId) => Promise<void> } | null
): Promise<void> { ): Promise<void> {
@ -468,8 +468,8 @@ export async function undoConsumeFiles(
export async function addStirlingFileStubs( export async function addStirlingFileStubs(
stirlingFileStubs: StirlingFileStub[], stirlingFileStubs: StirlingFileStub[],
options: { insertAfterPageId?: string; selectFiles?: boolean } = {}, options: { insertAfterPageId?: string; selectFiles?: boolean } = {},
stateRef: React.MutableRefObject<FileContextState>, stateRef: React.RefObject<FileContextState>,
filesRef: React.MutableRefObject<Map<FileId, File>>, filesRef: React.RefObject<Map<FileId, File>>,
dispatch: React.Dispatch<FileContextAction>, dispatch: React.Dispatch<FileContextAction>,
_lifecycleManager: FileLifecycleManager _lifecycleManager: FileLifecycleManager
): Promise<StirlingFile[]> { ): Promise<StirlingFile[]> {

View File

@ -15,8 +15,8 @@ import {
* Create stable selectors using stateRef and filesRef * Create stable selectors using stateRef and filesRef
*/ */
export function createFileSelectors( export function createFileSelectors(
stateRef: React.MutableRefObject<FileContextState>, stateRef: React.RefObject<FileContextState>,
filesRef: React.MutableRefObject<Map<FileId, File>> filesRef: React.RefObject<Map<FileId, File>>
): FileContextSelectors { ): FileContextSelectors {
return { return {
getFile: (id: FileId) => { getFile: (id: FileId) => {
@ -111,7 +111,7 @@ export function buildQuickKeySet(stirlingFileStubs: Record<FileId, StirlingFileS
/** /**
* Helper for building quickKey sets from IndexedDB metadata * Helper for building quickKey sets from IndexedDB metadata
*/ */
export function buildQuickKeySetFromMetadata(metadata: Array<{ name: string; size: number; lastModified: number }>): Set<string> { export function buildQuickKeySetFromMetadata(metadata: { name: string; size: number; lastModified: number }[]): Set<string> {
const quickKeys = new Set<string>(); const quickKeys = new Set<string>();
metadata.forEach(meta => { metadata.forEach(meta => {
// Format: name|size|lastModified (same as createQuickKey) // Format: name|size|lastModified (same as createQuickKey)
@ -125,8 +125,8 @@ export function buildQuickKeySetFromMetadata(metadata: Array<{ name: string; siz
* Get primary file (first in list) - commonly used pattern * Get primary file (first in list) - commonly used pattern
*/ */
export function getPrimaryFile( export function getPrimaryFile(
stateRef: React.MutableRefObject<FileContextState>, stateRef: React.RefObject<FileContextState>,
filesRef: React.MutableRefObject<Map<FileId, File>> filesRef: React.RefObject<Map<FileId, File>>
): { file?: File; record?: StirlingFileStub } { ): { file?: File; record?: StirlingFileStub } {
const primaryFileId = stateRef.current.files.ids[0]; const primaryFileId = stateRef.current.files.ids[0];
if (!primaryFileId) return {}; if (!primaryFileId) return {};

View File

@ -16,7 +16,7 @@ export class FileLifecycleManager {
private fileGenerations = new Map<string, number>(); // Generation tokens to prevent stale cleanup private fileGenerations = new Map<string, number>(); // Generation tokens to prevent stale cleanup
constructor( constructor(
private filesRef: React.MutableRefObject<Map<FileId, File>>, private filesRef: React.RefObject<Map<FileId, File>>,
private dispatch: React.Dispatch<FileContextAction> private dispatch: React.Dispatch<FileContextAction>
) {} ) {}
@ -34,7 +34,7 @@ export class FileLifecycleManager {
/** /**
* Clean up resources for a specific file (with stateRef access for complete cleanup) * Clean up resources for a specific file (with stateRef access for complete cleanup)
*/ */
cleanupFile = (fileId: FileId, stateRef?: React.MutableRefObject<any>): void => { cleanupFile = (fileId: FileId, stateRef?: React.RefObject<any>): void => {
// Use comprehensive cleanup (same as removeFiles) // Use comprehensive cleanup (same as removeFiles)
this.cleanupAllResourcesForFile(fileId, stateRef); this.cleanupAllResourcesForFile(fileId, stateRef);
@ -68,7 +68,7 @@ export class FileLifecycleManager {
/** /**
* Schedule delayed cleanup for a file with generation token to prevent stale cleanup * Schedule delayed cleanup for a file with generation token to prevent stale cleanup
*/ */
scheduleCleanup = (fileId: FileId, delay: number = 30000, stateRef?: React.MutableRefObject<any>): void => { scheduleCleanup = (fileId: FileId, delay: number = 30000, stateRef?: React.RefObject<any>): void => {
// Cancel existing timer // Cancel existing timer
const existingTimer = this.cleanupTimers.get(fileId); const existingTimer = this.cleanupTimers.get(fileId);
if (existingTimer) { if (existingTimer) {
@ -101,7 +101,7 @@ export class FileLifecycleManager {
/** /**
* Remove a file immediately with complete resource cleanup * Remove a file immediately with complete resource cleanup
*/ */
removeFiles = (fileIds: FileId[], stateRef?: React.MutableRefObject<any>): void => { removeFiles = (fileIds: FileId[], stateRef?: React.RefObject<any>): void => {
fileIds.forEach(fileId => { fileIds.forEach(fileId => {
// Clean up all resources for this file // Clean up all resources for this file
this.cleanupAllResourcesForFile(fileId, stateRef); this.cleanupAllResourcesForFile(fileId, stateRef);
@ -114,7 +114,7 @@ export class FileLifecycleManager {
/** /**
* Complete resource cleanup for a single file * Complete resource cleanup for a single file
*/ */
private cleanupAllResourcesForFile = (fileId: FileId, stateRef?: React.MutableRefObject<any>): void => { private cleanupAllResourcesForFile = (fileId: FileId, stateRef?: React.RefObject<any>): void => {
// Remove from files ref // Remove from files ref
this.filesRef.current.delete(fileId); this.filesRef.current.delete(fileId);
@ -166,7 +166,7 @@ export class FileLifecycleManager {
/** /**
* Update file record with race condition guards * Update file record with race condition guards
*/ */
updateStirlingFileStub = (fileId: FileId, updates: Partial<StirlingFileStub>, stateRef?: React.MutableRefObject<any>): void => { updateStirlingFileStub = (fileId: FileId, updates: Partial<StirlingFileStub>, stateRef?: React.RefObject<any>): void => {
// Guard against updating removed files (race condition protection) // Guard against updating removed files (race condition protection)
if (!this.filesRef.current.has(fileId)) { if (!this.filesRef.current.has(fileId)) {
if (DEBUG) console.warn(`🗂️ Attempted to update removed file (filesRef): ${fileId}`); if (DEBUG) console.warn(`🗂️ Attempted to update removed file (filesRef): ${fileId}`);

View File

@ -125,7 +125,7 @@ describe('useAddPasswordParameters', () => {
expect(result.current.validateParameters()).toBe(true); expect(result.current.validateParameters()).toBe(true);
}); });
test.each(Object.keys(defaultChangePermissionsParameters) as Array<keyof ChangePermissionsParameters>)('should handle boolean restriction parameter %s', (param) => { test.each(Object.keys(defaultChangePermissionsParameters) as (keyof ChangePermissionsParameters)[])('should handle boolean restriction parameter %s', (param) => {
const { result } = renderHook(() => useAddPasswordParameters()); const { result } = renderHook(() => useAddPasswordParameters());
act(() => { act(() => {

View File

@ -96,7 +96,7 @@ describe('useChangePermissionsOperation', () => {
// Verify the form data contains the file // Verify the form data contains the file
expect(formData.get('fileInput')).toBe(testFile); expect(formData.get('fileInput')).toBe(testFile);
(Object.keys(testParameters) as Array<keyof ChangePermissionsParameters>).forEach(key => { (Object.keys(testParameters) as (keyof ChangePermissionsParameters)[]).forEach(key => {
expect(formData.get(key), `Parameter ${key} should be set correctly`).toBe(testParameters[key].toString()); expect(formData.get(key), `Parameter ${key} should be set correctly`).toBe(testParameters[key].toString());
}); });
}); });

View File

@ -30,7 +30,7 @@ describe('useChangePermissionsParameters', () => {
test('should update all permission parameters', () => { test('should update all permission parameters', () => {
const { result } = renderHook(() => useChangePermissionsParameters()); const { result } = renderHook(() => useChangePermissionsParameters());
const permissionKeys = Object.keys(defaultParameters) as Array<keyof ChangePermissionsParameters>; const permissionKeys = Object.keys(defaultParameters) as (keyof ChangePermissionsParameters)[];
// Set all to true // Set all to true
act(() => { act(() => {
@ -99,7 +99,7 @@ describe('useChangePermissionsParameters', () => {
// Set all restrictions - should still be valid // Set all restrictions - should still be valid
act(() => { act(() => {
const permissionKeys = Object.keys(defaultParameters) as Array<keyof ChangePermissionsParameters>; const permissionKeys = Object.keys(defaultParameters) as (keyof ChangePermissionsParameters)[];
permissionKeys.forEach(key => { permissionKeys.forEach(key => {
result.current.updateParameter(key, true); result.current.updateParameter(key, true);
}); });

View File

@ -42,8 +42,8 @@ export interface ConvertParameters extends BaseParameters {
export interface ConvertParametersHook extends BaseParametersHook<ConvertParameters> { export interface ConvertParametersHook extends BaseParametersHook<ConvertParameters> {
getEndpoint: () => string; getEndpoint: () => string;
getAvailableToExtensions: (fromExtension: string) => Array<{value: string, label: string, group: string}>; getAvailableToExtensions: (fromExtension: string) => {value: string, label: string, group: string}[];
analyzeFileTypes: (files: Array<{name: string}>) => void; analyzeFileTypes: (files: {name: string}[]) => void;
} }
export const defaultParameters: ConvertParameters = { export const defaultParameters: ConvertParameters = {
@ -157,7 +157,7 @@ export const useConvertParameters = (): ConvertParametersHook => {
const getAvailableToExtensions = getAvailableToExtensionsUtil; const getAvailableToExtensions = getAvailableToExtensionsUtil;
const analyzeFileTypes = useCallback((files: Array<{name: string}>) => { const analyzeFileTypes = useCallback((files: {name: string}[]) => {
if (files.length === 0) { if (files.length === 0) {
// No files - only reset smart detection, keep user's format choices // No files - only reset smart detection, keep user's format choices
baseHook.setParameters(prev => { baseHook.setParameters(prev => {

View File

@ -345,7 +345,7 @@ describe('useConvertParameters - Auto Detection & Smart Conversion', () => {
test('should handle malformed file objects', () => { test('should handle malformed file objects', () => {
const { result } = renderHook(() => useConvertParameters()); const { result } = renderHook(() => useConvertParameters());
const malformedFiles: Array<{name: string}> = [ const malformedFiles: {name: string}[] = [
{ name: 'valid.pdf' }, { name: 'valid.pdf' },
// @ts-expect-error - Testing runtime resilience // @ts-expect-error - Testing runtime resilience
{ name: null }, { name: null },

View File

@ -4,7 +4,7 @@ import { SUBCATEGORY_ORDER, SubcategoryId, ToolCategoryId, ToolRegistryEntry } f
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
type SubcategoryIdMap = { type SubcategoryIdMap = {
[subcategoryId in SubcategoryId]: Array<{ id: string /* FIX ME: Should be ToolId */; tool: ToolRegistryEntry }>; [subcategoryId in SubcategoryId]: { id: string /* FIX ME: Should be ToolId */; tool: ToolRegistryEntry }[];
} }
type GroupedTools = { type GroupedTools = {
@ -28,7 +28,7 @@ export interface ToolSection {
}; };
export function useToolSections( export function useToolSections(
filteredTools: Array<{ item: [string /* FIX ME: Should be ToolId */, ToolRegistryEntry]; matchedText?: string }>, filteredTools: { item: [string /* FIX ME: Should be ToolId */, ToolRegistryEntry]; matchedText?: string }[],
searchQuery?: string searchQuery?: string
) { ) {
const { t } = useTranslation(); const { t } = useTranslation();

View File

@ -6,10 +6,10 @@ export interface AutomationConfig {
id: string; id: string;
name: string; name: string;
description?: string; description?: string;
operations: Array<{ operations: {
operation: string; operation: string;
parameters: any; parameters: any;
}>; }[];
createdAt: string; createdAt: string;
updatedAt: string; updatedAt: string;
} }

View File

@ -10,12 +10,12 @@ import { FileId } from '../types/file';
export interface ProcessedFileMetadata { export interface ProcessedFileMetadata {
totalPages: number; totalPages: number;
pages: Array<{ pages: {
pageNumber: number; pageNumber: number;
thumbnail?: string; thumbnail?: string;
rotation: number; rotation: number;
splitBefore: boolean; splitBefore: boolean;
}>; }[];
thumbnailUrl?: string; // Page 1 thumbnail for FileEditor thumbnailUrl?: string; // Page 1 thumbnail for FileEditor
lastProcessed: number; lastProcessed: number;
} }

View File

@ -13,7 +13,7 @@ import {
type ConversionEndpoint type ConversionEndpoint
} from '../helpers/conversionEndpointDiscovery'; } from '../helpers/conversionEndpointDiscovery';
import * as path from 'path'; import * as path from 'path';
import * as fs from 'fs'; import fs from 'fs';
// Test configuration // Test configuration
const BASE_URL = process.env.BASE_URL || 'http://localhost:5173'; const BASE_URL = process.env.BASE_URL || 'http://localhost:5173';
@ -238,7 +238,7 @@ async function testConversion(page: Page, conversion: ConversionEndpoint) {
// Save and verify file is not empty // Save and verify file is not empty
const path = await download.path(); const path = await download.path();
if (path) { if (path) {
const fs = require('fs'); // fs is already imported at the top of the file
const stats = fs.statSync(path); const stats = fs.statSync(path);
expect(stats.size).toBeGreaterThan(0); expect(stats.size).toBeGreaterThan(0);

View File

@ -20,7 +20,7 @@ export function createTestStirlingFile(
* Create multiple StirlingFile objects for testing * Create multiple StirlingFile objects for testing
*/ */
export function createTestFilesWithId( export function createTestFilesWithId(
files: Array<{ name: string; content?: string; type?: string }> files: { name: string; content?: string; type?: string }[]
): StirlingFile[] { ): StirlingFile[] {
return files.map(({ name, content = 'test content', type = 'application/pdf' }) => return files.map(({ name, content = 'test content', type = 'application/pdf' }) =>
createTestStirlingFile(name, content, type) createTestStirlingFile(name, content, type)

View File

@ -64,7 +64,7 @@ export const isWebFormat = (extension: string): boolean => {
* Gets available target extensions for a given source extension * Gets available target extensions for a given source extension
* Extracted from useConvertParameters to be reusable in automation settings * Extracted from useConvertParameters to be reusable in automation settings
*/ */
export const getAvailableToExtensions = (fromExtension: string): Array<{value: string, label: string, group: string}> => { export const getAvailableToExtensions = (fromExtension: string): {value: string, label: string, group: string}[] => {
if (!fromExtension) return []; if (!fromExtension) return [];
// Handle dynamic format identifiers (file-<extension>) // Handle dynamic format identifiers (file-<extension>)

View File

@ -82,8 +82,8 @@ export function isFuzzyMatch(query: string, target: string, minScore?: number):
} }
// Convenience: rank a list of items by best score across provided getters // Convenience: rank a list of items by best score across provided getters
export function rankByFuzzy<T>(items: T[], query: string, getters: Array<(item: T) => string>, minScore?: number): Array<{ item: T; score: number; matchedText?: string }>{ export function rankByFuzzy<T>(items: T[], query: string, getters: ((item: T) => string)[], minScore?: number): { item: T; score: number; matchedText?: string }[]{
const results: Array<{ item: T; score: number; matchedText?: string }> = []; const results: { item: T; score: number; matchedText?: string }[] = [];
const threshold = typeof minScore === 'number' ? minScore : minScoreForQuery(query); const threshold = typeof minScore === 'number' ? minScore : minScoreForQuery(query);
for (const item of items) { for (const item of items) {
let best = 0; let best = 0;

View File

@ -18,10 +18,10 @@ export function filterToolRegistryByQuery(
const nq = normalizeForSearch(query); const nq = normalizeForSearch(query);
const threshold = minScoreForQuery(query); const threshold = minScoreForQuery(query);
const exactName: Array<{ id: string; tool: ToolRegistryEntry; pos: number }> = []; const exactName: { id: string; tool: ToolRegistryEntry; pos: number }[] = [];
const exactSyn: Array<{ id: string; tool: ToolRegistryEntry; text: string; pos: number }> = []; const exactSyn: { id: string; tool: ToolRegistryEntry; text: string; pos: number }[] = [];
const fuzzyName: Array<{ id: string; tool: ToolRegistryEntry; score: number; text: string }> = []; const fuzzyName: { id: string; tool: ToolRegistryEntry; score: number; text: string }[] = [];
const fuzzySyn: Array<{ id: string; tool: ToolRegistryEntry; score: number; text: string }> = []; const fuzzySyn: { id: string; tool: ToolRegistryEntry; score: number; text: string }[] = [];
for (const [id, tool] of entries) { for (const [id, tool] of entries) {
const nameNorm = normalizeForSearch(tool.name || ''); const nameNorm = normalizeForSearch(tool.name || '');

View File

@ -24,7 +24,6 @@
// "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
// "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
// "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
/* Modules */ /* Modules */
"module": "esnext", /* Specify what module code is generated. */ "module": "esnext", /* Specify what module code is generated. */
// "rootDir": "./", /* Specify the root folder within your source files. */ // "rootDir": "./", /* Specify the root folder within your source files. */
@ -113,6 +112,7 @@
}, },
"include": [ "include": [
"src", "src",
"src/global.d.ts" "src/global.d.ts",
, "vite.config.ts" ] "vite.config.ts"
]
} }