From 8871c9162c22af3919bceb63a58bc56938fb9f19 Mon Sep 17 00:00:00 2001 From: pjmalandrino Date: Sat, 21 Mar 2026 15:58:43 +0100 Subject: [PATCH] Migrate frontend in typescript --- .github/workflows/ci.yml | 11 +- CONTRIBUTING.md | 11 +- README.md | 10 +- frontend/env.d.ts | 7 + frontend/eslint.config.js | 13 +- frontend/index.html | 2 +- frontend/package-lock.json | 515 +++++++++++++++++- frontend/package.json | 9 +- frontend/src/app/App.vue | 10 +- frontend/src/app/{main.js => main.ts} | 2 +- .../src/app/router/{index.js => index.ts} | 19 +- frontend/src/features/analysis/api.js | 24 - .../analysis/{api.test.js => api.test.ts} | 6 +- frontend/src/features/analysis/api.ts | 28 + frontend/src/features/analysis/bboxScaling.js | 58 -- ...boxScaling.test.js => bboxScaling.test.ts} | 2 +- frontend/src/features/analysis/bboxScaling.ts | 27 + .../features/analysis/{index.js => index.ts} | 2 +- ...ptions.test.js => pipelineOptions.test.ts} | 30 +- .../analysis/{store.test.js => store.test.ts} | 6 +- .../features/analysis/{store.js => store.ts} | 62 ++- .../features/analysis/ui/AnalysisPanel.vue | 10 +- .../src/features/analysis/ui/BboxOverlay.vue | 57 +- .../src/features/analysis/ui/ImageGallery.vue | 9 +- .../features/analysis/ui/MarkdownViewer.vue | 6 +- .../src/features/analysis/ui/ResultTabs.vue | 15 +- .../features/analysis/ui/StructureViewer.vue | 34 +- frontend/src/features/document/api.js | 27 - .../document/{api.test.js => api.test.ts} | 6 +- frontend/src/features/document/api.ts | 28 + .../features/document/{index.js => index.ts} | 2 +- .../document/{store.test.js => store.test.ts} | 6 +- .../features/document/{store.js => store.ts} | 29 +- .../src/features/document/ui/DocumentList.vue | 6 +- .../features/document/ui/DocumentUpload.vue | 19 +- .../src/features/document/ui/PagePreview.vue | 6 +- .../features/history/{index.js => index.ts} | 2 +- ...{navigation.test.js => navigation.test.ts} | 22 +- .../history/{store.test.js => store.test.ts} | 4 +- .../features/history/{store.js => store.ts} | 2 +- .../src/features/history/ui/HistoryList.vue | 17 +- .../features/settings/{index.js => index.ts} | 2 +- .../features/settings/{store.js => store.ts} | 13 +- .../features/settings/ui/SettingsPanel.vue | 6 +- frontend/src/pages/DocumentsPage.vue | 10 +- frontend/src/pages/HistoryPage.vue | 6 +- frontend/src/pages/HomePage.vue | 13 +- frontend/src/pages/SettingsPage.vue | 6 +- frontend/src/pages/StudioPage.vue | 31 +- frontend/src/shared/api/http.js | 15 - .../shared/api/{http.test.js => http.test.ts} | 2 +- frontend/src/shared/api/http.ts | 19 + frontend/src/shared/format.js | 10 - frontend/src/shared/format.ts | 5 + .../src/shared/{i18n.test.js => i18n.test.ts} | 6 +- frontend/src/shared/{i18n.js => i18n.ts} | 14 +- frontend/src/shared/types.ts | 79 +++ frontend/src/shared/ui/AppSidebar.vue | 4 +- frontend/src/shared/ui/{index.js => index.ts} | 0 frontend/{jsconfig.json => tsconfig.json} | 8 +- 60 files changed, 1021 insertions(+), 389 deletions(-) create mode 100644 frontend/env.d.ts rename frontend/src/app/{main.js => main.ts} (80%) rename frontend/src/app/router/{index.js => index.ts} (51%) delete mode 100644 frontend/src/features/analysis/api.js rename frontend/src/features/analysis/{api.test.js => api.test.ts} (94%) create mode 100644 frontend/src/features/analysis/api.ts delete mode 100644 frontend/src/features/analysis/bboxScaling.js rename frontend/src/features/analysis/{bboxScaling.test.js => bboxScaling.test.ts} (99%) create mode 100644 frontend/src/features/analysis/bboxScaling.ts rename frontend/src/features/analysis/{index.js => index.ts} (89%) rename frontend/src/features/analysis/{pipelineOptions.test.js => pipelineOptions.test.ts} (92%) rename frontend/src/features/analysis/{store.test.js => store.test.ts} (97%) rename frontend/src/features/analysis/{store.js => store.ts} (55%) delete mode 100644 frontend/src/features/document/api.js rename frontend/src/features/document/{api.test.js => api.test.ts} (93%) create mode 100644 frontend/src/features/document/api.ts rename frontend/src/features/document/{index.js => index.ts} (80%) rename frontend/src/features/document/{store.test.js => store.test.ts} (96%) rename frontend/src/features/document/{store.js => store.ts} (56%) rename frontend/src/features/history/{index.js => index.ts} (57%) rename frontend/src/features/history/{navigation.test.js => navigation.test.ts} (89%) rename frontend/src/features/history/{store.test.js => store.test.ts} (65%) rename frontend/src/features/history/{store.js => store.ts} (85%) rename frontend/src/features/settings/{index.js => index.ts} (58%) rename frontend/src/features/settings/{store.js => store.ts} (57%) delete mode 100644 frontend/src/shared/api/http.js rename frontend/src/shared/api/{http.test.js => http.test.ts} (98%) create mode 100644 frontend/src/shared/api/http.ts delete mode 100644 frontend/src/shared/format.js create mode 100644 frontend/src/shared/format.ts rename frontend/src/shared/{i18n.test.js => i18n.test.ts} (96%) rename frontend/src/shared/{i18n.js => i18n.ts} (96%) create mode 100644 frontend/src/shared/types.ts rename frontend/src/shared/ui/{index.js => index.ts} (100%) rename frontend/{jsconfig.json => tsconfig.json} (63%) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 76d08ba..a09f998 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -35,7 +35,10 @@ jobs: run: | pip install --upgrade pip pip install -r requirements.txt - pip install pytest pytest-asyncio httpx + pip install pytest pytest-asyncio httpx ruff + + - name: Lint + run: ruff check . - name: Run tests run: pytest tests/ -v @@ -59,6 +62,12 @@ jobs: - name: Install dependencies run: npm ci + - name: Lint + run: npx eslint src/ + + - name: Type check + run: npm run type-check + - name: Run tests run: npm run test:run diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 26921d3..5010328 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -48,13 +48,14 @@ ruff check . --fix # lint with auto-fix ruff format . # format ``` -### Frontend — ESLint + Prettier +### Frontend — TypeScript + ESLint + Prettier ```bash cd frontend -npx eslint src/ # lint -npx prettier --check src/ # check formatting -npx prettier --write src/ # auto-format +npm run type-check # type check (vue-tsc) +npx eslint src/ # lint +npx prettier --check src/ # check formatting +npx prettier --write src/ # auto-format ``` ## Running Tests @@ -64,7 +65,7 @@ npx prettier --write src/ # auto-format cd document-parser pytest tests/ -v -# Frontend (87 tests) +# Frontend (81 tests) cd frontend npm run test:run ``` diff --git a/README.md b/README.md index 4993580..595ea02 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ Upload a PDF, configure the extraction pipeline, and visualize the results — t | Service | Stack | Role | |---------|-------|------| -| **frontend** | Vue 3, Vite, Pinia | UI, PDF viewer, results display | +| **frontend** | Vue 3, TypeScript, Vite, Pinia | UI, PDF viewer, results display | | **document-parser** | FastAPI, Docling, SQLite, pdf2image | REST API, document parsing, storage | ### Backend structure (clean architecture) @@ -80,7 +80,7 @@ frontend/src/ │ ├── document/ # Document store, API, upload, list │ ├── history/ # History store, API, navigation │ └── settings/ # Settings store -└── shared/ # Shared utilities (i18n, http, format) +└── shared/ # Shared utilities (types, i18n, http, format) ``` ## Quick Start @@ -128,7 +128,7 @@ cd document-parser pip install pytest pytest-asyncio httpx pytest tests/ -v -# Frontend (87 tests) +# Frontend (81 tests) cd frontend npm run test:run ``` @@ -167,7 +167,7 @@ GitHub Actions pipelines (see [`.github/workflows/`](.github/workflows/)): | Workflow | Trigger | What it does | |----------|---------|--------------| -| **CI** | push to `main`, pull requests | Backend tests (99) + Frontend tests (87) + build | +| **CI** | push to `main`, pull requests | Lint + type check + Backend tests (99) + Frontend tests (81) + build | | **Release** | push tag `v*` | Build & push multi-arch Docker image to `ghcr.io` | To publish a new version: @@ -199,7 +199,7 @@ All Docker images are multi-arch (linux/amd64 + linux/arm64). No GPU required. ## Tech Stack -- **Frontend**: Vue 3, Vite, Pinia, DOMPurify +- **Frontend**: Vue 3, TypeScript, Vite, Pinia, DOMPurify - **Backend**: FastAPI, Docling 2.x, SQLite (aiosqlite), pdf2image - **CI**: GitHub Actions - **Infra**: Docker Compose + Nginx diff --git a/frontend/env.d.ts b/frontend/env.d.ts new file mode 100644 index 0000000..8b53f84 --- /dev/null +++ b/frontend/env.d.ts @@ -0,0 +1,7 @@ +/// + +declare module '*.vue' { + import type { DefineComponent } from 'vue' + const component: DefineComponent, Record, unknown> + export default component +} diff --git a/frontend/eslint.config.js b/frontend/eslint.config.js index 51ba3b2..8ae252b 100644 --- a/frontend/eslint.config.js +++ b/frontend/eslint.config.js @@ -1,15 +1,24 @@ import js from '@eslint/js' +import tseslint from 'typescript-eslint' import pluginVue from 'eslint-plugin-vue' export default [ js.configs.recommended, + ...tseslint.configs.recommended, ...pluginVue.configs['flat/recommended'], { - files: ['src/**/*.{js,vue}'], + files: ['src/**/*.{ts,js,vue}'], + languageOptions: { + parserOptions: { + parser: tseslint.parser, + }, + }, rules: { 'no-console': ['warn', { allow: ['warn', 'error'] }], 'no-debugger': 'error', - 'no-unused-vars': ['error', { argsIgnorePattern: '^_' }], + 'no-unused-vars': 'off', + '@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }], + '@typescript-eslint/no-explicit-any': 'off', 'vue/multi-word-component-names': 'off', 'vue/require-default-prop': 'off', // Formatting handled by Prettier diff --git a/frontend/index.html b/frontend/index.html index b5dfc1a..7e54f95 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -8,6 +8,6 @@
- + diff --git a/frontend/package-lock.json b/frontend/package-lock.json index cac0b58..91a310d 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -16,12 +16,16 @@ }, "devDependencies": { "@eslint/js": "^9.0.0", + "@types/dompurify": "^3.2.0", "@vitejs/plugin-vue": "^5.2.0", "eslint": "^9.0.0", "eslint-plugin-vue": "^9.32.0", "prettier": "^3.4.0", + "typescript": "^5.9.3", + "typescript-eslint": "^8.57.1", "vite": "^5.4.0", - "vitest": "^2.1.0" + "vitest": "^2.1.0", + "vue-tsc": "^2.2.12" } }, "node_modules/@babel/helper-string-parser": { @@ -946,6 +950,16 @@ "win32" ] }, + "node_modules/@types/dompurify": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@types/dompurify/-/dompurify-3.2.0.tgz", + "integrity": "sha512-Fgg31wv9QbLDA0SpTOXO3MaxySc4DKGLi8sna4/Utjo4r3ZRPdCt4UQee8BWr+Q5z21yifghREPJGYaEOEIACg==", + "deprecated": "This is a stub types definition. dompurify provides its own type definitions, so you do not need this installed.", + "dev": true, + "dependencies": { + "dompurify": "*" + } + }, "node_modules/@types/estree": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", @@ -964,6 +978,273 @@ "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", "optional": true }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.57.1.tgz", + "integrity": "sha512-Gn3aqnvNl4NGc6x3/Bqk1AOn0thyTU9bqDRhiRnUWezgvr2OnhYCWCgC8zXXRVqBsIL1pSDt7T9nJUe0oM0kDQ==", + "dev": true, + "dependencies": { + "@eslint-community/regexpp": "^4.12.2", + "@typescript-eslint/scope-manager": "8.57.1", + "@typescript-eslint/type-utils": "8.57.1", + "@typescript-eslint/utils": "8.57.1", + "@typescript-eslint/visitor-keys": "8.57.1", + "ignore": "^7.0.5", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.4.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.57.1", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.57.1.tgz", + "integrity": "sha512-k4eNDan0EIMTT/dUKc/g+rsJ6wcHYhNPdY19VoX/EOtaAG8DLtKCykhrUnuHPYvinn5jhAPgD2Qw9hXBwrahsw==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "8.57.1", + "@typescript-eslint/types": "8.57.1", + "@typescript-eslint/typescript-estree": "8.57.1", + "@typescript-eslint/visitor-keys": "8.57.1", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.57.1.tgz", + "integrity": "sha512-vx1F37BRO1OftsYlmG9xay1TqnjNVlqALymwWVuYTdo18XuKxtBpCj1QlzNIEHlvlB27osvXFWptYiEWsVdYsg==", + "dev": true, + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.57.1", + "@typescript-eslint/types": "^8.57.1", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.57.1.tgz", + "integrity": "sha512-hs/QcpCwlwT2L5S+3fT6gp0PabyGk4Q0Rv2doJXA0435/OpnSR3VRgvrp8Xdoc3UAYSg9cyUjTeFXZEPg/3OKg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "8.57.1", + "@typescript-eslint/visitor-keys": "8.57.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.57.1.tgz", + "integrity": "sha512-0lgOZB8cl19fHO4eI46YUx2EceQqhgkPSuCGLlGi79L2jwYY1cxeYc1Nae8Aw1xjgW3PKVDLlr3YJ6Bxx8HkWg==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.57.1.tgz", + "integrity": "sha512-+Bwwm0ScukFdyoJsh2u6pp4S9ktegF98pYUU0hkphOOqdMB+1sNQhIz8y5E9+4pOioZijrkfNO/HUJVAFFfPKA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "8.57.1", + "@typescript-eslint/typescript-estree": "8.57.1", + "@typescript-eslint/utils": "8.57.1", + "debug": "^4.4.3", + "ts-api-utils": "^2.4.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.57.1.tgz", + "integrity": "sha512-S29BOBPJSFUiblEl6RzPPjJt6w25A6XsBqRVDt53tA/tlL8q7ceQNZHTjPeONt/3S7KRI4quk+yP9jK2WjBiPQ==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.57.1.tgz", + "integrity": "sha512-ybe2hS9G6pXpqGtPli9Gx9quNV0TWLOmh58ADlmZe9DguLq0tiAKVjirSbtM1szG6+QH6rVXyU6GTLQbWnMY+g==", + "dev": true, + "dependencies": { + "@typescript-eslint/project-service": "8.57.1", + "@typescript-eslint/tsconfig-utils": "8.57.1", + "@typescript-eslint/types": "8.57.1", + "@typescript-eslint/visitor-keys": "8.57.1", + "debug": "^4.4.3", + "minimatch": "^10.2.2", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.4.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", + "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", + "dev": true, + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", + "dev": true, + "dependencies": { + "brace-expansion": "^5.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.57.1.tgz", + "integrity": "sha512-XUNSJ/lEVFttPMMoDVA2r2bwrl8/oPx8cURtczkSEswY5T3AeLmCy+EKWQNdL4u0MmAHOjcWrqJp2cdvgjn8dQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.57.1", + "@typescript-eslint/types": "8.57.1", + "@typescript-eslint/typescript-estree": "8.57.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.57.1.tgz", + "integrity": "sha512-YWnmJkXbofiz9KbnbbwuA2rpGkFPLbAIetcCNO6mJ8gdhdZ/v7WDXsoGFAJuM6ikUFKTlSQnjWnVO4ux+UzS6A==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "8.57.1", + "eslint-visitor-keys": "^5.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "dev": true, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/@vitejs/plugin-vue": { "version": "5.2.4", "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.2.4.tgz", @@ -1083,6 +1364,32 @@ "url": "https://opencollective.com/vitest" } }, + "node_modules/@volar/language-core": { + "version": "2.4.15", + "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.4.15.tgz", + "integrity": "sha512-3VHw+QZU0ZG9IuQmzT68IyN4hZNd9GchGPhbD9+pa8CVv7rnoOZwo7T8weIbrRmihqy3ATpdfXFnqRrfPVK6CA==", + "dev": true, + "dependencies": { + "@volar/source-map": "2.4.15" + } + }, + "node_modules/@volar/source-map": { + "version": "2.4.15", + "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-2.4.15.tgz", + "integrity": "sha512-CPbMWlUN6hVZJYGcU/GSoHu4EnCHiLaXI9n8c9la6RaI9W5JHX+NqG+GSQcB0JdC2FIBLdZJwGsfKyBB71VlTg==", + "dev": true + }, + "node_modules/@volar/typescript": { + "version": "2.4.15", + "resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-2.4.15.tgz", + "integrity": "sha512-2aZ8i0cqPGjXb4BhkMsPYDkkuc2ZQ6yOpqwAuNwUoncELqoy5fRgOQtLR9gB0g902iS0NAkvpIzs27geVyVdPg==", + "dev": true, + "dependencies": { + "@volar/language-core": "2.4.15", + "path-browserify": "^1.0.1", + "vscode-uri": "^3.0.8" + } + }, "node_modules/@vue/compiler-core": { "version": "3.5.30", "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.30.tgz", @@ -1139,11 +1446,69 @@ "@vue/shared": "3.5.30" } }, + "node_modules/@vue/compiler-vue2": { + "version": "2.7.16", + "resolved": "https://registry.npmjs.org/@vue/compiler-vue2/-/compiler-vue2-2.7.16.tgz", + "integrity": "sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A==", + "dev": true, + "dependencies": { + "de-indent": "^1.0.2", + "he": "^1.2.0" + } + }, "node_modules/@vue/devtools-api": { "version": "6.6.4", "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.6.4.tgz", "integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==" }, + "node_modules/@vue/language-core": { + "version": "2.2.12", + "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-2.2.12.tgz", + "integrity": "sha512-IsGljWbKGU1MZpBPN+BvPAdr55YPkj2nB/TBNGNC32Vy2qLG25DYu/NBN2vNtZqdRbTRjaoYrahLrToim2NanA==", + "dev": true, + "dependencies": { + "@volar/language-core": "2.4.15", + "@vue/compiler-dom": "^3.5.0", + "@vue/compiler-vue2": "^2.7.16", + "@vue/shared": "^3.5.0", + "alien-signals": "^1.0.3", + "minimatch": "^9.0.3", + "muggle-string": "^0.4.1", + "path-browserify": "^1.0.1" + }, + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@vue/language-core/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@vue/language-core/node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/@vue/reactivity": { "version": "3.5.30", "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.30.tgz", @@ -1226,6 +1591,12 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/alien-signals": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/alien-signals/-/alien-signals-1.0.13.tgz", + "integrity": "sha512-OGj9yyTnJEttvzhTUWuscOvtqxq5vrhF7vL9oS0xJ2mK0ItPYP1/y+vCFebfxoEyAz0++1AIwJ5CMr+Fk3nDmg==", + "dev": true + }, "node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -1392,6 +1763,12 @@ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==" }, + "node_modules/de-indent": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz", + "integrity": "sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==", + "dev": true + }, "node_modules/debug": { "version": "4.4.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", @@ -1718,6 +2095,23 @@ "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, "node_modules/file-entry-cache": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", @@ -1812,6 +2206,15 @@ "node": ">=8" } }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "bin": { + "he": "bin/he" + } + }, "node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", @@ -1995,6 +2398,12 @@ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true }, + "node_modules/muggle-string": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/muggle-string/-/muggle-string-0.4.1.tgz", + "integrity": "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==", + "dev": true + }, "node_modules/nanoid": { "version": "3.3.11", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", @@ -2089,6 +2498,12 @@ "node": ">=6" } }, + "node_modules/path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "dev": true + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -2127,6 +2542,18 @@ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==" }, + "node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/pinia": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/pinia/-/pinia-2.3.1.tgz", @@ -2369,6 +2796,22 @@ "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", "dev": true }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, "node_modules/tinypool": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.1.1.tgz", @@ -2396,6 +2839,18 @@ "node": ">=14.0.0" } }, + "node_modules/ts-api-utils": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz", + "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==", + "dev": true, + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -2420,6 +2875,42 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "devOptional": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typescript-eslint": { + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.57.1.tgz", + "integrity": "sha512-fLvZWf+cAGw3tqMCYzGIU6yR8K+Y9NT2z23RwOjlNFF2HwSB3KhdEFI5lSBv8tNmFkkBShSjsCjzx1vahZfISA==", + "dev": true, + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.57.1", + "@typescript-eslint/parser": "8.57.1", + "@typescript-eslint/typescript-estree": "8.57.1", + "@typescript-eslint/utils": "8.57.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", @@ -2581,6 +3072,12 @@ } } }, + "node_modules/vscode-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.1.0.tgz", + "integrity": "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==", + "dev": true + }, "node_modules/vue": { "version": "3.5.30", "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.30.tgz", @@ -2709,6 +3206,22 @@ "vue": "^3.5.0" } }, + "node_modules/vue-tsc": { + "version": "2.2.12", + "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-2.2.12.tgz", + "integrity": "sha512-P7OP77b2h/Pmk+lZdJ0YWs+5tJ6J2+uOQPo7tlBnY44QqQSPYvS0qVT4wqDJgwrZaLe47etJLLQRFia71GYITw==", + "dev": true, + "dependencies": { + "@volar/typescript": "2.4.15", + "@vue/language-core": "2.2.12" + }, + "bin": { + "vue-tsc": "bin/vue-tsc.js" + }, + "peerDependencies": { + "typescript": ">=5.0.0" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", diff --git a/frontend/package.json b/frontend/package.json index cd43c61..18fa10c 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -5,7 +5,8 @@ "type": "module", "scripts": { "dev": "vite", - "build": "vite build", + "build": "vue-tsc --noEmit && vite build", + "type-check": "vue-tsc --noEmit", "preview": "vite preview", "test": "vitest --watch", "test:run": "vitest run", @@ -23,11 +24,15 @@ }, "devDependencies": { "@eslint/js": "^9.0.0", + "@types/dompurify": "^3.2.0", "@vitejs/plugin-vue": "^5.2.0", "eslint": "^9.0.0", "eslint-plugin-vue": "^9.32.0", "prettier": "^3.4.0", + "typescript": "^5.9.3", + "typescript-eslint": "^8.57.1", "vite": "^5.4.0", - "vitest": "^2.1.0" + "vitest": "^2.1.0", + "vue-tsc": "^2.2.12" } } diff --git a/frontend/src/app/App.vue b/frontend/src/app/App.vue index a74103d..366d39a 100644 --- a/frontend/src/app/App.vue +++ b/frontend/src/app/App.vue @@ -26,13 +26,13 @@ - diff --git a/frontend/src/features/analysis/ui/ResultTabs.vue b/frontend/src/features/analysis/ui/ResultTabs.vue index e1aab63..afe41a1 100644 --- a/frontend/src/features/analysis/ui/ResultTabs.vue +++ b/frontend/src/features/analysis/ui/ResultTabs.vue @@ -96,14 +96,15 @@ - diff --git a/frontend/src/features/document/ui/DocumentUpload.vue b/frontend/src/features/document/ui/DocumentUpload.vue index 99e8327..270ce3d 100644 --- a/frontend/src/features/document/ui/DocumentUpload.vue +++ b/frontend/src/features/document/ui/DocumentUpload.vue @@ -22,29 +22,30 @@ - diff --git a/frontend/src/pages/StudioPage.vue b/frontend/src/pages/StudioPage.vue index 8aa4c5e..cc13240 100644 --- a/frontend/src/pages/StudioPage.vue +++ b/frontend/src/pages/StudioPage.vue @@ -281,16 +281,17 @@ -