diff --git a/.eslintrc.cjs.bak b/.eslintrc.cjs.bak new file mode 100644 index 0000000..d589258 --- /dev/null +++ b/.eslintrc.cjs.bak @@ -0,0 +1,29 @@ +module.exports = { + root: true, + parser: '@typescript-eslint/parser', + parserOptions: { + ecmaVersion: 2022, + sourceType: 'module', + }, + plugins: ['@typescript-eslint'], + extends: [ + 'eslint:recommended', + 'plugin:@typescript-eslint/recommended', + 'prettier', + ], + env: { + node: true, + es2022: true, + }, + rules: { + '@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }], + '@typescript-eslint/no-explicit-any': 'warn', + 'no-console': 'off', + }, + ignorePatterns: [ + 'dist/', + 'node_modules/', + 'webapp/dist/', + 'webapp/node_modules/', + ], +}; diff --git a/coverage/coverage-summary.json b/coverage/coverage-summary.json new file mode 100644 index 0000000..b5b7fe9 --- /dev/null +++ b/coverage/coverage-summary.json @@ -0,0 +1,22 @@ +{"total": {"lines":{"total":879,"covered":199,"skipped":0,"pct":22.63},"statements":{"total":967,"covered":226,"skipped":0,"pct":23.37},"functions":{"total":146,"covered":38,"skipped":0,"pct":26.02},"branches":{"total":497,"covered":100,"skipped":0,"pct":20.12},"branchesTrue":{"total":0,"covered":0,"skipped":0,"pct":100}} +,"C:\\GitHub\\Mind-o-Mat\\src\\index.ts": {"lines":{"total":0,"covered":0,"skipped":0,"pct":100},"functions":{"total":0,"covered":0,"skipped":0,"pct":100},"statements":{"total":0,"covered":0,"skipped":0,"pct":100},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}} +,"C:\\GitHub\\Mind-o-Mat\\src\\ingest.ts": {"lines":{"total":58,"covered":58,"skipped":0,"pct":100},"functions":{"total":9,"covered":9,"skipped":0,"pct":100},"statements":{"total":66,"covered":65,"skipped":0,"pct":98.48},"branches":{"total":28,"covered":24,"skipped":0,"pct":85.71}} +,"C:\\GitHub\\Mind-o-Mat\\src\\llm.ts": {"lines":{"total":24,"covered":0,"skipped":0,"pct":0},"functions":{"total":3,"covered":0,"skipped":0,"pct":0},"statements":{"total":24,"covered":0,"skipped":0,"pct":0},"branches":{"total":26,"covered":0,"skipped":0,"pct":0}} +,"C:\\GitHub\\Mind-o-Mat\\src\\notes-api-server.ts": {"lines":{"total":52,"covered":42,"skipped":0,"pct":80.76},"functions":{"total":14,"covered":9,"skipped":0,"pct":64.28},"statements":{"total":62,"covered":48,"skipped":0,"pct":77.41},"branches":{"total":39,"covered":30,"skipped":0,"pct":76.92}} +,"C:\\GitHub\\Mind-o-Mat\\src\\vault-path.ts": {"lines":{"total":25,"covered":24,"skipped":0,"pct":96},"functions":{"total":4,"covered":4,"skipped":0,"pct":100},"statements":{"total":26,"covered":25,"skipped":0,"pct":96.15},"branches":{"total":18,"covered":15,"skipped":0,"pct":83.33}} +,"C:\\GitHub\\Mind-o-Mat\\src\\cli\\index-cmd.ts": {"lines":{"total":215,"covered":47,"skipped":0,"pct":21.86},"functions":{"total":23,"covered":6,"skipped":0,"pct":26.08},"statements":{"total":245,"covered":56,"skipped":0,"pct":22.85},"branches":{"total":106,"covered":21,"skipped":0,"pct":19.81}} +,"C:\\GitHub\\Mind-o-Mat\\src\\cli\\index.ts": {"lines":{"total":29,"covered":0,"skipped":0,"pct":0},"functions":{"total":2,"covered":0,"skipped":0,"pct":0},"statements":{"total":29,"covered":0,"skipped":0,"pct":0},"branches":{"total":17,"covered":0,"skipped":0,"pct":0}} +,"C:\\GitHub\\Mind-o-Mat\\src\\cli\\ingest.ts": {"lines":{"total":127,"covered":0,"skipped":0,"pct":0},"functions":{"total":16,"covered":0,"skipped":0,"pct":0},"statements":{"total":139,"covered":0,"skipped":0,"pct":0},"branches":{"total":84,"covered":0,"skipped":0,"pct":0}} +,"C:\\GitHub\\Mind-o-Mat\\src\\cli\\init-vault.ts": {"lines":{"total":78,"covered":0,"skipped":0,"pct":0},"functions":{"total":2,"covered":0,"skipped":0,"pct":0},"statements":{"total":83,"covered":0,"skipped":0,"pct":0},"branches":{"total":29,"covered":0,"skipped":0,"pct":0}} +,"C:\\GitHub\\Mind-o-Mat\\src\\cli\\sync.ts": {"lines":{"total":57,"covered":0,"skipped":0,"pct":0},"functions":{"total":4,"covered":0,"skipped":0,"pct":0},"statements":{"total":60,"covered":0,"skipped":0,"pct":0},"branches":{"total":20,"covered":0,"skipped":0,"pct":0}} +,"C:\\GitHub\\Mind-o-Mat\\webapp\\src\\App.tsx": {"lines":{"total":46,"covered":0,"skipped":0,"pct":0},"functions":{"total":19,"covered":0,"skipped":0,"pct":0},"statements":{"total":51,"covered":0,"skipped":0,"pct":0},"branches":{"total":51,"covered":0,"skipped":0,"pct":0}} +,"C:\\GitHub\\Mind-o-Mat\\webapp\\src\\ClusterMap.tsx": {"lines":{"total":19,"covered":0,"skipped":0,"pct":0},"functions":{"total":7,"covered":0,"skipped":0,"pct":0},"statements":{"total":19,"covered":0,"skipped":0,"pct":0},"branches":{"total":12,"covered":0,"skipped":0,"pct":0}} +,"C:\\GitHub\\Mind-o-Mat\\webapp\\src\\Editor.tsx": {"lines":{"total":24,"covered":0,"skipped":0,"pct":0},"functions":{"total":6,"covered":0,"skipped":0,"pct":0},"statements":{"total":26,"covered":0,"skipped":0,"pct":0},"branches":{"total":16,"covered":0,"skipped":0,"pct":0}} +,"C:\\GitHub\\Mind-o-Mat\\webapp\\src\\EditorWithLoad.tsx": {"lines":{"total":61,"covered":0,"skipped":0,"pct":0},"functions":{"total":15,"covered":0,"skipped":0,"pct":0},"statements":{"total":66,"covered":0,"skipped":0,"pct":0},"branches":{"total":16,"covered":0,"skipped":0,"pct":0}} +,"C:\\GitHub\\Mind-o-Mat\\webapp\\src\\RadialView.tsx": {"lines":{"total":25,"covered":0,"skipped":0,"pct":0},"functions":{"total":10,"covered":0,"skipped":0,"pct":0},"statements":{"total":27,"covered":0,"skipped":0,"pct":0},"branches":{"total":18,"covered":0,"skipped":0,"pct":0}} +,"C:\\GitHub\\Mind-o-Mat\\webapp\\src\\landkarte.ts": {"lines":{"total":4,"covered":0,"skipped":0,"pct":0},"functions":{"total":1,"covered":0,"skipped":0,"pct":0},"statements":{"total":4,"covered":0,"skipped":0,"pct":0},"branches":{"total":3,"covered":0,"skipped":0,"pct":0}} +,"C:\\GitHub\\Mind-o-Mat\\webapp\\src\\main.tsx": {"lines":{"total":1,"covered":0,"skipped":0,"pct":0},"functions":{"total":0,"covered":0,"skipped":0,"pct":100},"statements":{"total":1,"covered":0,"skipped":0,"pct":0},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}} +,"C:\\GitHub\\Mind-o-Mat\\webapp\\src\\note-loader.ts": {"lines":{"total":5,"covered":0,"skipped":0,"pct":0},"functions":{"total":1,"covered":0,"skipped":0,"pct":0},"statements":{"total":5,"covered":0,"skipped":0,"pct":0},"branches":{"total":2,"covered":0,"skipped":0,"pct":0}} +,"C:\\GitHub\\Mind-o-Mat\\webapp\\src\\notes-api.ts": {"lines":{"total":15,"covered":15,"skipped":0,"pct":100},"functions":{"total":4,"covered":4,"skipped":0,"pct":100},"statements":{"total":19,"covered":18,"skipped":0,"pct":94.73},"branches":{"total":10,"covered":9,"skipped":0,"pct":90}} +,"C:\\GitHub\\Mind-o-Mat\\webapp\\src\\sync-queue.ts": {"lines":{"total":14,"covered":13,"skipped":0,"pct":92.85},"functions":{"total":6,"covered":6,"skipped":0,"pct":100},"statements":{"total":15,"covered":14,"skipped":0,"pct":93.33},"branches":{"total":2,"covered":1,"skipped":0,"pct":50}} +} diff --git a/eslint-flat.log.err b/eslint-flat.log.err new file mode 100644 index 0000000..e69de29 diff --git a/package-lock.json b/package-lock.json index 60e346d..d9ccb93 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,6 +19,7 @@ "@types/node": "^22.0.0", "@typescript-eslint/eslint-plugin": "^8.69.0", "@typescript-eslint/parser": "^8.69.0", + "@vitest/coverage-v8": "^5.0.0", "chokidar": "^5.0.0", "eslint": "^9.39.5", "eslint-config-prettier": "^10.1.8", @@ -80,17 +81,42 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/helper-string-parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-validator-identifier": { "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=6.9.0" } }, + "node_modules/@babel/parser": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.8.tgz", + "integrity": "sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.8" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/@babel/runtime": { "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.7.tgz", @@ -101,6 +127,30 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/types": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.8.tgz", + "integrity": "sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-1.0.2.tgz", + "integrity": "sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/@bramus/specificity": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/@bramus/specificity/-/specificity-2.4.2.tgz", @@ -1238,6 +1288,58 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/@vitest/coverage-v8": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-5.0.0.tgz", + "integrity": "sha512-toMg6PZGCIa/lQNCDoASrfb1ly4hsUKXFtFYC9kD4t78o5Y6LyNJU7AENt8eHPr3quYdxaxK7hj2mnbFfUk9NA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@bcoe/v8-coverage": "^1.0.2", + "@vitest/istanbul-lib-coverage": "^1.0.0", + "@vitest/istanbul-lib-report": "^1.0.0", + "ast-v8-to-istanbul": "^1.0.5", + "magicast": "^0.5.4", + "obug": "^2.1.4", + "std-env": "^4.2.0", + "tinyrainbow": "^3.1.1" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@vitest/browser": "5.0.0", + "vitest": "5.0.0" + }, + "peerDependenciesMeta": { + "@vitest/browser": { + "optional": true + } + } + }, + "node_modules/@vitest/istanbul-lib-coverage": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@vitest/istanbul-lib-coverage/-/istanbul-lib-coverage-1.0.1.tgz", + "integrity": "sha512-k3DJZ8LhMBK9NS4SclF1ASD3OgXEWDorbIcPTRDK0/Zae6fRvu+fJRxtFdLfHsa9Y24beCdPnoNZ4LviTNstfA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=22" + } + }, + "node_modules/@vitest/istanbul-lib-report": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@vitest/istanbul-lib-report/-/istanbul-lib-report-1.0.1.tgz", + "integrity": "sha512-1EOLRfsTMnyAr3+kEAsP4o9dhaDlGPpD7H5iLBBeq//YpNB1VIahkPhB+eRp9N2Dkfw8oySROjE3yf9XDeaIkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/istanbul-lib-coverage": "1.0.1" + }, + "engines": { + "node": ">=22" + } + }, "node_modules/@vitest/mocker": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-5.0.0.tgz", @@ -1373,6 +1475,25 @@ "node": ">=12" } }, + "node_modules/ast-v8-to-istanbul": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-1.0.5.tgz", + "integrity": "sha512-UPAgKJFSEGMWSDr3LX4tqnAb4f7KGT8O40Tyx8wbYmmZ/yn58lNCm8h3svs3eXgiGd5AXxz8NDOvXWvicq+rJA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.31", + "estree-walker": "^3.0.3", + "js-tokens": "^10.0.0" + } + }, + "node_modules/ast-v8-to-istanbul/node_modules/js-tokens": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-10.0.0.tgz", + "integrity": "sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==", + "dev": true, + "license": "MIT" + }, "node_modules/balanced-match": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", @@ -2630,6 +2751,18 @@ "@jridgewell/sourcemap-codec": "^1.5.5" } }, + "node_modules/magicast": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.5.4.tgz", + "integrity": "sha512-llBEhWm1SacoRwgHUoQJYtwp4PBLF4faQi5TCpIGyGs9n4y5+juI0tDgyKIfpqxckRHaHzouUEph3THklWh03w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7", + "source-map-js": "^1.2.1" + } + }, "node_modules/mdn-data": { "version": "2.27.1", "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.27.1.tgz", @@ -3202,6 +3335,16 @@ "url": "https://github.com/sponsors/SuperchupuDev" } }, + "node_modules/tinyrainbow": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.1.tgz", + "integrity": "sha512-yau8yJdTt989Mm0Bd/236QnzEiPf2xLLTqUZRUJOo/3CB078LSwzei343DgtJVmfJKJE3TMINY1u42SQsP6mXw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/tldts": { "version": "7.4.11", "resolved": "https://registry.npmjs.org/tldts/-/tldts-7.4.11.tgz", diff --git a/package.json b/package.json index 45e7ff9..1733062 100644 --- a/package.json +++ b/package.json @@ -51,6 +51,7 @@ "@types/node": "^22.0.0", "@typescript-eslint/eslint-plugin": "^8.69.0", "@typescript-eslint/parser": "^8.69.0", + "@vitest/coverage-v8": "^5.0.0", "chokidar": "^5.0.0", "eslint": "^9.39.5", "eslint-config-prettier": "^10.1.8", diff --git a/perf-test.log.err b/perf-test.log.err new file mode 100644 index 0000000..e69de29 diff --git a/tests/find-similar-groups.test.ts b/tests/find-similar-groups.test.ts new file mode 100644 index 0000000..7b5c1ea --- /dev/null +++ b/tests/find-similar-groups.test.ts @@ -0,0 +1,135 @@ +// Direkter Unit-Test fuer findSimilarGroups (v0.5) +import { describe, it, expect, beforeEach, afterEach } from 'vitest'; +import { mkdtempSync, mkdirSync, writeFileSync, rmSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; +import { findSimilarGroups } from '../src/cli/index-cmd.js'; +import type { VaultNode } from '../src/cli/index-cmd.js'; + +const vaults: string[] = []; +afterEach(() => { + for (const v of vaults) rmSync(v, { recursive: true, force: true }); +}); + +function setupVault(files: Record): string { + const vault = mkdtempSync(join(tmpdir(), 'mindomat-similar-direct-')); + for (const d of [ + '00_Inbox', '10_Wiki/Seiten', '01_Daily', '20_Projekte', + '99_System', '99_System/Skripte', '99_System/Logs', '99_System/Cache', + ]) { + mkdirSync(join(vault, d), { recursive: true }); + } + for (const [rel, content] of Object.entries(files)) { + const full = join(vault, rel); + mkdirSync(join(full, '..'), { recursive: true }); + writeFileSync(full, content); + } + return vault; +} + +function node(id: string, cluster = null): VaultNode { + return { + id, + title: id, + type: 'inbox', + cluster, + status: null, + created: null, + aktualisiert: null, + tags: [], + size: 0, + veraltet: false, + contentHash: 'h', + }; +} + +describe('findSimilarGroups direkt', () => { + it('leere Liste: keine Gruppen', () => { + const vault = setupVault({}); + vaults.push(vault); + const groups = findSimilarGroups(vault, [], 0.15); + expect(groups).toEqual([]); + }); + + it('Notiz mit zu kurzem Body wird uebersprungen', () => { + const vault = setupVault({ + '01_Daily/2026-01-01_Kurz.md': '# K', + }); + vaults.push(vault); + const n = node('01_Daily/2026-01-01_Kurz.md'); + const groups = findSimilarGroups(vault, [n], 0.15); + expect(groups).toEqual([]); + }); + + it('nicht-existierende Datei wird uebersprungen', () => { + const vault = setupVault({}); + vaults.push(vault); + const n = node('00_Inbox/2026-01-01_NichtDa.md'); + const groups = findSimilarGroups(vault, [n], 0.15); + expect(groups).toEqual([]); + }); + + it('aehnliche Notizen werden gefunden (Threshold)', () => { + const vault = setupVault({ + '01_Daily/2026-09-05_A.md': `--- +title: Kaffee +--- + +# Kaffee + +Jeden Morgen trinke ich Kaffee mit Milch. Stille vor dem Tag.`, + '01_Daily/2026-09-05_B.md': `--- +title: Kaffee Abends +--- + +# Kaffee + +Abends trinke ich Kaffee mit Hafermilch. Andere Stille.`, + '01_Daily/2026-09-05_Sport.md': `--- +title: Sport +--- + +# Sport + +Ich gehe joggen im Park.`, + }); + vaults.push(vault); + const nodes = [ + node('01_Daily/2026-09-05_A.md'), + node('01_Daily/2026-09-05_B.md'), + node('01_Daily/2026-09-05_Sport.md'), + ]; + const groups = findSimilarGroups(vault, nodes, 0.15); + // Es sollte mindestens eine Gruppe geben (A und B sind aehnlich) + expect(groups.length).toBeGreaterThanOrEqual(1); + // Die aehnlichste Gruppe sollte A+B sein + const abGroup = groups.find((g) => + g.nodes.some((n) => n.id.includes('_A.md')) && + g.nodes.some((n) => n.id.includes('_B.md')), + ); + expect(abGroup).toBeDefined(); + }); + + it('Threshold filtert: hoeher = weniger Gruppen', () => { + const vault = setupVault({ + '01_Daily/2026-09-05_A.md': `--- +title: Test +--- + +Kaffee Tee Milch Zucker`, + '01_Daily/2026-09-05_B.md': `--- +title: Test +--- + +Kaffee Tee Brot Butter`, + }); + vaults.push(vault); + const nodes = [ + node('01_Daily/2026-09-05_A.md'), + node('01_Daily/2026-09-05_B.md'), + ]; + const low = findSimilarGroups(vault, nodes, 0.1); + const high = findSimilarGroups(vault, nodes, 0.99); + expect(low.length).toBeGreaterThanOrEqual(high.length); + }); +}); diff --git a/vitest-cov.log.err b/vitest-cov.log.err new file mode 100644 index 0000000..c853f85 --- /dev/null +++ b/vitest-cov.log.err @@ -0,0 +1,4 @@ +ERROR: Coverage for lines (22.63%) does not meet global threshold (50%) +ERROR: Coverage for functions (26.02%) does not meet global threshold (50%) +ERROR: Coverage for statements (23.37%) does not meet global threshold (50%) +ERROR: Coverage for branches (20.12%) does not meet global threshold (50%) diff --git a/vitest.config.mjs b/vitest.config.mjs index e812b4c..6139b11 100644 --- a/vitest.config.mjs +++ b/vitest.config.mjs @@ -1,5 +1,5 @@ // Vitest Config -// Phase 1.1 + 4.1 (jsdom fuer PWA-Editor-Tests) +// Phase 1.1 + 4.1 (jsdom fuer PWA-Editor-Tests) + Bonus (Coverage) import { defineConfig } from 'vitest/config'; @@ -13,5 +13,17 @@ export default defineConfig({ ['tests/**/sync-queue.test.ts', 'jsdom'], ], globals: false, + coverage: { + provider: 'v8', + reporter: ['text', 'json-summary'], + include: ['src/**/*.ts', 'webapp/src/**/*.ts', 'webapp/src/**/*.tsx'], + exclude: ['src/templates/**', '**/*.test.ts', '**/*.d.ts'], + thresholds: { + lines: 50, + functions: 50, + branches: 50, + statements: 50, + }, + }, }, });