From cf9770dda6050ca33b5b25d3a711037b4a84cf1f Mon Sep 17 00:00:00 2001 From: Aditya Date: Sun, 21 Jun 2026 09:31:09 +0530 Subject: [PATCH 01/10] feat: Production readiness & security hardening --- .github/workflows/ci.yml | 7 +- .github/workflows/release.yml | 7 +- CONTRIBUTING.md | 29 +++ SECURITY.md | 18 ++ electron/main.ts | 122 +++++++--- electron/preload.ts | 5 +- package-lock.json | 150 +++++++------ package.json | 9 +- src/App.tsx | 372 ++----------------------------- src/Settings.test.tsx | 14 +- src/Settings.tsx | 15 +- src/components/Editor.tsx | 85 +++++++ src/components/ErrorBoundary.tsx | 64 ++++++ src/lib/editor/MathEvaluator.ts | 115 +++++----- src/lib/editor/extensions.ts | 255 +++++++++++++++++++++ src/main.tsx | 39 +++- src/setupTests.ts | 67 +++--- src/store/useAIStore.ts | 4 - src/types.d.ts | 4 +- tests/MathEvaluator.test.ts | 45 ++++ tests/safeStorage.test.ts | 28 +++ 21 files changed, 882 insertions(+), 572 deletions(-) create mode 100644 CONTRIBUTING.md create mode 100644 SECURITY.md create mode 100644 src/components/Editor.tsx create mode 100644 src/components/ErrorBoundary.tsx create mode 100644 src/lib/editor/extensions.ts create mode 100644 tests/MathEvaluator.test.ts create mode 100644 tests/safeStorage.test.ts diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4d55965..f4b6366 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,13 +6,16 @@ on: branches: [main] jobs: ci: - runs-on: ubuntu-latest + strategy: + matrix: + os: [macos-latest, ubuntu-latest, windows-latest] + runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: '22' - - run: npm install + - run: npm ci - run: npm run typecheck - run: npm run lint - run: npm run format:check diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b46b22a..d86054a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,7 +1,6 @@ name: Release on: - push: - branches: [main] + workflow_dispatch: permissions: contents: write jobs: @@ -29,7 +28,7 @@ jobs: - uses: actions/setup-node@v4 with: node-version: '22' - - run: npm install + - run: npm ci - name: Sync package.json version run: npm --no-git-tag-version version ${{ needs.create-tag.outputs.new_version }} @@ -52,6 +51,8 @@ jobs: release/*.exe release/*.AppImage release/*.deb + release/*.yml + release/*.blockmap update-homebrew: needs: [create-tag, build-and-release] diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..c8c685c --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,29 @@ +# Contributing to PaperCache + +First of all, thank you for considering contributing to PaperCache! + +## Development Setup + +1. **Clone the repository:** + ```bash + git clone https://github.com/VariableThe/PaperCache.git + cd PaperCache + ``` + +2. **Install dependencies:** + We strictly use `npm ci` to ensure reproducible builds. + ```bash + npm ci + ``` + +3. **Start the development server:** + ```bash + npm run dev + ``` + +## Development Guidelines +- **Pull Requests Required**: Never push new features directly to the `main` branch. Always create a new branch and push your changes as a Pull Request (PR) for review. +- **Pre-PR Checks**: Run `npm run lint` and `npm run test` before opening any PR — don't open a PR with failing checks. +- **Performance Reporting**: Performance changes require a before/after bundle size comparison in the PR description (just paste the Vite build output). + +Thank you for your contributions! diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..0a97d23 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,18 @@ +# Security Policy + +## Supported Versions + +Currently, only the latest version of PaperCache receives security updates. Please ensure you are running the most recent version available. + +## Reporting a Vulnerability + +We take the security of PaperCache seriously. If you discover a security vulnerability, we would appreciate it if you could report it privately so it can be addressed before being disclosed publicly. + +Please report any security issues to: **adityasharma.variable@gmail.com** + +When reporting, please include: +- A description of the vulnerability. +- Steps to reproduce the issue. +- Any potential impact you have identified. + +You should receive an acknowledgment of your report within 48 hours, along with an estimated timeline for a fix. Thank you for helping keep PaperCache secure! diff --git a/electron/main.ts b/electron/main.ts index 816cb5b..0d6f379 100644 --- a/electron/main.ts +++ b/electron/main.ts @@ -12,7 +12,9 @@ import { dialog, safeStorage, powerMonitor, + session, } from 'electron' +import { autoUpdater } from 'electron-updater' import path from 'node:path' import { fileURLToPath } from 'node:url' import fs from 'node:fs' @@ -35,8 +37,15 @@ if (!fs.existsSync(COMMANDS_DIR)) { fs.mkdirSync(COMMANDS_DIR) } -fs.writeFileSync( - path.join(COMMANDS_DIR, 'basics.md'), +function writeCommandFile(name: string, content: string) { + const filePath = path.join(COMMANDS_DIR, name) + if (!fs.existsSync(filePath)) { + fs.writeFileSync(filePath, content) + } +} + +writeCommandFile( + 'basics.md', `# Basics - **Zoom**: \`Cmd + +\` to zoom in, \`Cmd + -\` to zoom out, \`Cmd + 0\` to reset. @@ -56,11 +65,11 @@ fs.writeFileSync( *Example use:* Press \`Cmd+K\` right now, select "Settings", and set your global hotkey! Next: [Folders](/file commands/folders.md) -`, +` ) -fs.writeFileSync( - path.join(COMMANDS_DIR, 'folders.md'), +writeCommandFile( + 'folders.md', `# Folders Organize your notes by using a \`/\` in the note title. @@ -70,11 +79,11 @@ Folders automatically receive a unique color identifier in the Graph View and Se If you rename this note (click the title at the top left) to \`projects/PaperCache.md\`, it will automatically be placed inside a \`projects\` folder! Next: [Variables](/file commands/variables.md) -`, +` ) -fs.writeFileSync( - path.join(COMMANDS_DIR, 'variables.md'), +writeCommandFile( + 'variables.md', `# Variables & Math PaperCache is a smart scratchpad. You can define variables and write math equations that auto-calculate. @@ -92,11 +101,11 @@ x * 3 = \u200B30 API_KEY Next: [Markdown & Code](/file commands/markdown.md) -`, +` ) -fs.writeFileSync( - path.join(COMMANDS_DIR, 'markdown.md'), +writeCommandFile( + 'markdown.md', `# Markdown & Code PaperCache supports full markdown with seamless inline editing. @@ -127,11 +136,11 @@ Type \`/ai \` and press enter to summon an AI assistant directly into yo \`/ai Write a python function to reverse a string\` Next: [Formats & Colors](/file commands/formats.md) -`, +` ) -fs.writeFileSync( - path.join(COMMANDS_DIR, 'formats.md'), +writeCommandFile( + 'formats.md', `# Formats & Colors PaperCache automatically recognizes and highlights common formats so you can easily spot them in your notes. @@ -146,11 +155,11 @@ Dates and times are also highlighted to help you keep track of your schedule. Meeting on 31-05-2024 at 14:30. Next: [Tags](/file commands/tags.md) -`, +` ) -fs.writeFileSync( - path.join(COMMANDS_DIR, 'tags.md'), +writeCommandFile( + 'tags.md', `# Tags You can tag your notes anywhere by typing an exclamation mark followed by a word (e.g., !important or !work). @@ -163,11 +172,11 @@ When you open the search menu (\`Cmd+P\`), you'll see all your unique tags at th Next: [Tasks](/file commands/tasks.md) [Back to Welcome](/file Welcome.md) -`, +` ) -fs.writeFileSync( - path.join(COMMANDS_DIR, 'tasks.md'), +writeCommandFile( + 'tasks.md', `# Tasks & Reminders Stay on top of your work by using tasks! @@ -184,17 +193,17 @@ Overdue tasks will automatically highlight in red. Next: [Ready](/file commands/ready.md) [Back to Welcome](/file Welcome.md) -`, +` ) -fs.writeFileSync( - path.join(COMMANDS_DIR, 'ready.md'), +writeCommandFile( + 'ready.md', `# Ready to get started? You're all set to use PaperCache! Start jotting down your thoughts, creating folders, and exploring the capabilities. [Back to Welcome](/file Welcome.md) -`, +` ) const welcomePath = path.join(NOTES_DIR, 'Welcome.md') @@ -346,6 +355,24 @@ app.on('web-contents-created', (event, contents) => { }) app.whenReady().then(() => { + // Content Security Policy + const isDev = !!process.env.VITE_DEV_SERVER_URL; + session.defaultSession.webRequest.onHeadersReceived((details, callback) => { + callback({ + responseHeaders: { + ...details.responseHeaders, + // unsafe-eval is required for mathjs dynamic compilation + 'Content-Security-Policy': [ + isDev + ? "default-src 'none'; script-src 'self' 'unsafe-eval' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; connect-src 'self' https: wss:; font-src 'self' data: https:; object-src 'none'; base-uri 'none';" + : "default-src 'none'; script-src 'self' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; connect-src 'self' https:; font-src 'self' data: https:; object-src 'none'; base-uri 'none';" + ] + } + }) + }) + + autoUpdater.checkForUpdatesAndNotify() + createWindow() powerMonitor.on('suspend', () => { @@ -379,6 +406,7 @@ app.whenReady().then(() => { const contextMenu = Menu.buildFromTemplate([ { label: 'Show/Hide PaperCache', click: toggleWindow }, + { label: 'Check for Updates', click: () => autoUpdater.checkForUpdatesAndNotify() }, { type: 'separator' }, { label: 'Quit', @@ -615,11 +643,53 @@ ipcMain.on('open-settings', () => { }) -ipcMain.handle('openai-chat', async (_, { model, messages, apiKey, baseURL }) => { +let memoryApiKey = '' +try { + const file = fs.readFileSync(path.join(NOTES_DIR, 'config.enc'), 'utf-8') + if (safeStorage.isEncryptionAvailable()) { + memoryApiKey = safeStorage.decryptString(Buffer.from(file, 'base64')) + } else { + memoryApiKey = file + } +} catch (e) {} + +ipcMain.handle('set-api-key', (_, key: string) => { + memoryApiKey = key; + try { + const dataToSave = safeStorage.isEncryptionAvailable() + ? safeStorage.encryptString(key).toString('base64') + : key; + fs.writeFileSync(path.join(NOTES_DIR, 'config.enc'), dataToSave); + return true; + } catch (e) { + return false; + } +}) + +ipcMain.handle('get-api-key-status', () => { + return !!memoryApiKey && memoryApiKey.length > 0; +}) + +ipcMain.on('check-for-updates', () => { + autoUpdater.checkForUpdatesAndNotify() +}) + +ipcMain.handle('openai-chat', async (_, { model, messages, baseURL }) => { + // Input Validation + if (typeof model !== 'string' || model.trim() === '') { + throw new Error('Invalid model provided') + } + if (!Array.isArray(messages)) { + throw new Error('Messages must be an array') + } + if (baseURL && typeof baseURL !== 'string') { + throw new Error('Invalid baseURL provided') + } + try { const OpenAI = (await import('openai')).default const openai = new OpenAI({ - apiKey: apiKey || 'dummy', + apiKey: memoryApiKey || 'dummy', baseURL: baseURL || undefined, }) const completion = await openai.chat.completions.create({ diff --git a/electron/preload.ts b/electron/preload.ts index 0f11d7f..6d24a9f 100644 --- a/electron/preload.ts +++ b/electron/preload.ts @@ -6,7 +6,10 @@ contextBridge.exposeInMainWorld('electronAPI', { saveNote: (id: string, content: string) => ipcRenderer.invoke('save-note', { id, content }), deleteNote: (id: string) => ipcRenderer.invoke('delete-note', id), renameNote: (oldId: string, newId: string) => ipcRenderer.invoke('rename-note', { oldId, newId }), - openAIChat: (args: { model: string, messages: { role: string; content: string }[], apiKey: string, baseURL: string }) => ipcRenderer.invoke('openai-chat', args), + openAIChat: (args: { model: string, messages: { role: string; content: string }[], baseURL: string }) => ipcRenderer.invoke('openai-chat', args), + setApiKey: (key: string) => ipcRenderer.invoke('set-api-key', key), + getApiKeyStatus: () => ipcRenderer.invoke('get-api-key-status'), + checkForUpdates: () => ipcRenderer.send('check-for-updates'), readNote: (id: string) => ipcRenderer.invoke('read-note', id), exportNote: (filename: string, content: string) => ipcRenderer.invoke('export-note', filename, content), diff --git a/package-lock.json b/package-lock.json index 99f411c..fd7dd5f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,7 +15,7 @@ "@codemirror/view": "^6.43.0", "@lezer/highlight": "^1.2.3", "@uiw/react-codemirror": "^4.25.10", - "marked": "^18.0.4", + "electron-updater": "^6.8.9", "mathjs": "^15.2.0", "openai": "^6.39.1", "react": "^19.2.6", @@ -52,6 +52,9 @@ "vite-plugin-electron": "^0.29.1", "vite-plugin-electron-renderer": "^0.14.7", "vitest": "^4.1.7" + }, + "engines": { + "node": ">=22" } }, "node_modules/@adobe/css-tools": { @@ -143,6 +146,7 @@ "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/code-frame": "^7.29.7", "@babel/generator": "^7.29.7", @@ -540,6 +544,7 @@ "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.43.0.tgz", "integrity": "sha512-V7ZCLQO3Jus9hzh2jVCCPW3mO4IBMr43O37PqSUYautJSnnJF41YlgLw21x0fLJTYvJ+Vkm6Gp+qKGH9pltgXA==", "license": "MIT", + "peer": true, "dependencies": { "@codemirror/state": "^6.6.0", "crelt": "^1.0.6", @@ -635,6 +640,7 @@ } ], "license": "MIT", + "peer": true, "engines": { "node": ">=20.19.0" }, @@ -683,6 +689,7 @@ } ], "license": "MIT", + "peer": true, "engines": { "node": ">=20.19.0" } @@ -959,7 +966,6 @@ "dev": true, "license": "BSD-2-Clause", "optional": true, - "peer": true, "dependencies": { "cross-dirname": "^0.1.0", "debug": "^4.3.4", @@ -981,7 +987,6 @@ "dev": true, "license": "MIT", "optional": true, - "peer": true, "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", @@ -991,31 +996,6 @@ "node": ">=14.14" } }, - "node_modules/@emnapi/core": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.1.tgz", - "integrity": "sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "@emnapi/wasi-threads": "1.2.2", - "tslib": "^2.4.0" - } - }, - "node_modules/@emnapi/runtime": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.1.tgz", - "integrity": "sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, "node_modules/@emnapi/wasi-threads": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.2.tgz", @@ -1023,7 +1003,6 @@ "dev": true, "license": "MIT", "optional": true, - "peer": true, "dependencies": { "tslib": "^2.4.0" } @@ -2509,8 +2488,7 @@ "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@types/cacheable-request": { "version": "6.0.3", @@ -2691,6 +2669,7 @@ "integrity": "sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==", "devOptional": true, "license": "MIT", + "peer": true, "dependencies": { "csstype": "^3.2.2" } @@ -2701,6 +2680,7 @@ "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", "dev": true, "license": "MIT", + "peer": true, "peerDependencies": { "@types/react": "^19.2.0" } @@ -2784,6 +2764,7 @@ "integrity": "sha512-5B7PfA2e1NQGCnDHd/0lW7W3gvp3d59Ryw54FYO8Uswxo9f6ikw3AZV+Xj/TvpImmpsiYyUqAfhC6kJID1jF6w==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.61.0", "@typescript-eslint/types": "8.61.0", @@ -3196,6 +3177,7 @@ "integrity": "sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==", "dev": true, "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -3449,7 +3431,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true, "license": "Python-2.0" }, "node_modules/aria-query": { @@ -3641,6 +3622,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "baseline-browser-mapping": "^2.10.12", "caniuse-lite": "^1.0.30001782", @@ -3692,7 +3674,6 @@ "version": "9.7.0", "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-9.7.0.tgz", "integrity": "sha512-g/kR520giAFYkSXTzcmF3kqQq7wi8F6N6SzeDgZrqTBN+VHdmgWOyTdD1yD7AATDId/yXLvuP34CxW46/BwCdw==", - "dev": true, "license": "MIT", "dependencies": { "debug": "^4.3.4", @@ -4069,8 +4050,7 @@ "integrity": "sha512-+R08/oI0nl3vfPcqftZRpytksBXDzOUveBq/NBVx0sUp1axwzPQrKinNx5yd5sxPu8j1wIy8AfnVQ+5eFdha6Q==", "dev": true, "license": "MIT", - "optional": true, - "peer": true + "optional": true }, "node_modules/cross-spawn": { "version": "7.0.6", @@ -4282,6 +4262,7 @@ "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", "license": "ISC", + "peer": true, "engines": { "node": ">=12" } @@ -4372,7 +4353,6 @@ "version": "4.4.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -4562,6 +4542,7 @@ "integrity": "sha512-O3zJUFUYHJKgzPqioHxfxzBzlSC1eXCSr79gMSBKBP5AgjjpmrydMsMLotEg9fAJF36vdUncb+4ndRNxoPdlSQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "app-builder-lib": "26.15.3", "builder-util": "26.15.3", @@ -4574,8 +4555,7 @@ "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/dotenv": { "version": "16.6.1", @@ -4730,6 +4710,34 @@ "dev": true, "license": "ISC" }, + "node_modules/electron-updater": { + "version": "6.8.9", + "resolved": "https://registry.npmjs.org/electron-updater/-/electron-updater-6.8.9.tgz", + "integrity": "sha512-ZhVxM9iGONUpZGI1FxdMRgJjUFXi7AYGVa5PwKlO1tV1/4zDxQmfKpXOHVztKrd6L9rLcFjERvi1Mf2vxyTkig==", + "license": "MIT", + "dependencies": { + "builder-util-runtime": "9.7.0", + "fs-extra": "^10.1.0", + "js-yaml": "^4.1.0", + "lazy-val": "^1.0.5", + "lodash.escaperegexp": "^4.1.2", + "lodash.isequal": "^4.5.0", + "semver": "~7.7.3", + "tiny-typed-emitter": "^2.1.0" + } + }, + "node_modules/electron-updater/node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/electron-winstaller": { "version": "5.4.0", "resolved": "https://registry.npmjs.org/electron-winstaller/-/electron-winstaller-5.4.0.tgz", @@ -4737,7 +4745,6 @@ "dev": true, "hasInstallScript": true, "license": "MIT", - "peer": true, "dependencies": { "@electron/asar": "^3.2.1", "debug": "^4.1.1", @@ -4758,7 +4765,6 @@ "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "graceful-fs": "^4.1.2", "jsonfile": "^4.0.0", @@ -4774,7 +4780,6 @@ "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", "dev": true, "license": "MIT", - "peer": true, "optionalDependencies": { "graceful-fs": "^4.1.6" } @@ -4785,7 +4790,6 @@ "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">= 4.0.0" } @@ -4924,6 +4928,7 @@ "dev": true, "hasInstallScript": true, "license": "MIT", + "peer": true, "bin": { "esbuild": "bin/esbuild" }, @@ -4994,6 +4999,7 @@ "integrity": "sha512-1y+7C+vi12bUK1IpZeaV3gsH9fHLBmPvYmPx42pvT/E9yG0IC8g3PUZZgp0+JLJl7ZDK0flc2gc+Aw9dpCvIsQ==", "dev": true, "license": "MIT", + "peer": true, "workspaces": [ "packages/*" ], @@ -5053,6 +5059,7 @@ "integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==", "dev": true, "license": "MIT", + "peer": true, "bin": { "eslint-config-prettier": "bin/cli.js" }, @@ -5524,7 +5531,6 @@ "version": "10.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", - "dev": true, "license": "MIT", "dependencies": { "graceful-fs": "^4.2.0", @@ -5814,7 +5820,6 @@ "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true, "license": "ISC" }, "node_modules/has-flag": { @@ -6385,7 +6390,6 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.2.0.tgz", "integrity": "sha512-ePWsvanv0DWuDRsW8dnt+R4jQ31SCRCQ7hhNcPXZPsoBZiemuZNYGf7adZdqX2D86j6rvKp3RpCxVTSb8WQlOw==", - "dev": true, "funding": [ { "type": "github", @@ -6514,7 +6518,6 @@ "version": "6.2.1", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", - "dev": true, "license": "MIT", "dependencies": { "universalify": "^2.0.0" @@ -6549,7 +6552,6 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/lazy-val/-/lazy-val-1.0.5.tgz", "integrity": "sha512-0/BnGCCfyUMkBpeDgWihanIAF9JmZhHBgUhEqzvf+adhNGLoP6TaiI5oF8oyb3I45P+PcnrqihSf01M0l0G5+Q==", - "dev": true, "license": "MIT" }, "node_modules/levn": { @@ -6975,6 +6977,19 @@ "integrity": "sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A==", "license": "MIT" }, + "node_modules/lodash.escaperegexp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz", + "integrity": "sha512-TM9YBvyC84ZxE3rgfefxUWiQKLilstD6k7PTGt6wfbtXF8ixIJLOL3VYyV/z+ZiPLsVxAsKAFVwWlWeb2Y8Yyw==", + "license": "MIT" + }, + "node_modules/lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==", + "deprecated": "This package is deprecated. Use require('node:util').isDeepStrictEqual instead.", + "license": "MIT" + }, "node_modules/log-update": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz", @@ -7151,7 +7166,6 @@ "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", "dev": true, "license": "MIT", - "peer": true, "bin": { "lz-string": "bin/bin.js" } @@ -7166,18 +7180,6 @@ "@jridgewell/sourcemap-codec": "^1.5.5" } }, - "node_modules/marked": { - "version": "18.0.4", - "resolved": "https://registry.npmjs.org/marked/-/marked-18.0.4.tgz", - "integrity": "sha512-c/BTaKzg0G6ezQx97DAkYU7k0HM6ys0FqYeKBL6hlBByZwy+ycA1+f0vDdjMHKKeEjdgkx0GOv9Il6D+85cOqA==", - "license": "MIT", - "bin": { - "marked": "bin/marked.js" - }, - "engines": { - "node": ">= 20" - } - }, "node_modules/matcher": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/matcher/-/matcher-3.0.0.tgz", @@ -7356,7 +7358,6 @@ "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "minimist": "^1.2.6" }, @@ -7368,7 +7369,6 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, "license": "MIT" }, "node_modules/nanoid": { @@ -7845,7 +7845,6 @@ "dev": true, "license": "MIT", "optional": true, - "peer": true, "dependencies": { "commander": "^9.4.0" }, @@ -7863,7 +7862,6 @@ "dev": true, "license": "MIT", "optional": true, - "peer": true, "engines": { "node": "^12.20.0 || >=14" } @@ -7894,6 +7892,7 @@ "integrity": "sha512-N2MylSdi48+5N/6S5j+maeHbUSIzzZ5uOcX5Hm4QpV8Dkb1HFjfAKTKX6yNPJQD9AhcT3ifHNB66tWTTJDi11Q==", "dev": true, "license": "MIT", + "peer": true, "bin": { "prettier": "bin/prettier.cjs" }, @@ -7923,7 +7922,6 @@ "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "ansi-regex": "^5.0.1", "ansi-styles": "^5.0.0", @@ -7939,7 +7937,6 @@ "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=10" }, @@ -7952,8 +7949,7 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/proc-log": { "version": "6.1.0", @@ -8078,6 +8074,7 @@ "resolved": "https://registry.npmjs.org/react/-/react-19.2.6.tgz", "integrity": "sha512-sfWGGfavi0xr8Pg0sVsyHMAOziVYKgPLNrS7ig+ivMNb3wbCBw3KxtflsGBAwD3gYQlE/AEZsTLgToRrSCjb0Q==", "license": "MIT", + "peer": true, "engines": { "node": ">=0.10.0" } @@ -8087,6 +8084,7 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.6.tgz", "integrity": "sha512-0prMI+hvBbPjsWnxDLxlCGyM8PN6UuWjEUCYmZhO67xIV9Xasa/r/vDnq+Xyq4Lo27g8QSbO5YzARu0D1Sps3g==", "license": "MIT", + "peer": true, "dependencies": { "scheduler": "^0.27.0" }, @@ -8303,7 +8301,6 @@ "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, "license": "ISC", - "peer": true, "dependencies": { "glob": "^7.1.3" }, @@ -8385,7 +8382,6 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/sax/-/sax-1.6.0.tgz", "integrity": "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA==", - "dev": true, "license": "BlueOak-1.0.0", "engines": { "node": ">=11.0.0" @@ -8795,7 +8791,6 @@ "integrity": "sha512-yYrrsWnrXMcdsnu/7YMYAofM1ktpL5By7vZhf15CrXijWWrEYZks5AXBudalfSWJLlnen/QUJUB5aoB0kqZUGA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "mkdirp": "^0.5.1", "rimraf": "~2.6.2" @@ -8841,6 +8836,12 @@ "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==", "license": "MIT" }, + "node_modules/tiny-typed-emitter": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tiny-typed-emitter/-/tiny-typed-emitter-2.1.0.tgz", + "integrity": "sha512-qVtvMxeXbVej0cQWKqVSSAHmKZEHAvxdF8HEUBFWts8h+xEo5m/lEiPakuyZ3BnCBjOD8i24kzNOiOLLgsSxhA==", + "license": "MIT" + }, "node_modules/tinybench": { "version": "2.9.0", "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", @@ -9029,6 +9030,7 @@ "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", "dev": true, "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -9082,7 +9084,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", - "dev": true, "license": "MIT", "engines": { "node": ">= 10.0.0" @@ -9178,6 +9179,7 @@ "integrity": "sha512-h9bXPmJichP5fLmVQo3PyaGSDE2n3aPuomeAlVRm0JLmt4rY6zmPKd59HYI4LNW8oTK7tlTsuC7l/m7awx9Jcw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "lightningcss": "^1.32.0", "picomatch": "^4.0.4", @@ -9270,7 +9272,8 @@ "resolved": "https://registry.npmjs.org/vite-plugin-electron-renderer/-/vite-plugin-electron-renderer-0.14.7.tgz", "integrity": "sha512-hHBMKuZ24MB2SIxG7U7ix+DDEnvxou7Bgy/TdhYxNz3S5N3Yh7Hjvj9blfMeGEJ0oaZJn7y5z0V/RyDmJ5OuCA==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/vitest": { "version": "4.1.8", @@ -9607,6 +9610,7 @@ "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==", "devOptional": true, "license": "MIT", + "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/package.json b/package.json index 4cf99bd..6333e0b 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,9 @@ "version": "0.1.17", "type": "module", "main": "dist-electron/main.js", + "engines": { + "node": ">=22" + }, "author": { "name": "Aditya Sharma", "email": "adityasharma.variable@gmail.com" @@ -44,6 +47,10 @@ "dist-electron/**/*", "package.json" ], + "publish": { + "provider": "github", + "releaseType": "release" + }, "mac": { "icon": "public/icon.png", "category": "public.app-category.productivity", @@ -77,7 +84,7 @@ "@codemirror/view": "^6.43.0", "@lezer/highlight": "^1.2.3", "@uiw/react-codemirror": "^4.25.10", - "marked": "^18.0.4", + "electron-updater": "^6.8.9", "mathjs": "^15.2.0", "openai": "^6.39.1", "react": "^19.2.6", diff --git a/src/App.tsx b/src/App.tsx index 49b21b1..3e1bc57 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,11 +1,4 @@ -import { useCallback, useMemo, useRef, useEffect } from 'react' -import CodeMirror from '@uiw/react-codemirror' -import { markdown } from '@codemirror/lang-markdown' -import { EditorView, ViewUpdate, keymap } from '@codemirror/view' -import { Prec } from '@codemirror/state' -import { syntaxHighlighting } from '@codemirror/language' -import { search } from '@codemirror/search' -import { insertTab, indentLess } from '@codemirror/commands' +import { useRef, useEffect } from 'react' import './App.css' import GraphView from './GraphView' @@ -13,34 +6,22 @@ import { RemindersPage } from './components/RemindersPage' import { useAppStore } from './store/useAppStore' import { useSettingsStore } from './store/useSettingsStore' -import { useAIStore } from './store/useAIStore' import { useNoteStorage } from './hooks/useNoteStorage' import { useVariables } from './hooks/useVariables' import { useReminders } from './hooks/useReminders' import { useGlobalHotkey } from './hooks/useGlobalHotkey' -import { mdHighlighting } from './lib/editor/matchers' -import { - numberPlugin, - symbolPlugin, - aiPlugin, - mathPlugin, - decomposedPlugins, -} from './lib/editor/plugins' import { NoteSearch } from './components/NoteSearch' import { MainActionMenu } from './components/MainActionMenu' import { NoteTitleBar } from './components/NoteTitleBar' -import { getSecure } from './lib/safeStorage' - -import { MathEvaluator } from './lib/editor/MathEvaluator' +import { Editor, EditorRef } from './components/Editor' function App() { const notes = useAppStore((state) => state.notes) const setNotes = useAppStore((state) => state.setNotes) const currentNoteIndex = useAppStore((state) => state.currentNoteIndex) const setCurrentNoteIndex = useAppStore((state) => state.setCurrentNoteIndex) - const zoomLevel = useAppStore((state) => state.zoomLevel) const showGraphView = useAppStore((state) => state.showGraphView) const setShowGraphView = useAppStore((state) => state.setShowGraphView) const showRemindersView = useAppStore((state) => state.showRemindersView) @@ -48,39 +29,12 @@ function App() { const showNoteSearch = useAppStore((state) => state.showNoteSearch) const setShowMainActionMenu = useAppStore((state) => state.setShowMainActionMenu) - const { - themePreset, - fontFamily, - showRulings, - bgType, - bgColor, - bgImage, - textColor, - numColor, - symColor, - aiColor, - mathColor, - } = useSettingsStore() - - const { apiBaseUrl, apiModel, aiSystemPrompt, setApiKey, apiKey } = useAIStore() - - // Load Secure API Key asynchronously on mount - useEffect(() => { - async function fetchApiKey() { - const key = await getSecure('papercache-apikey') - if (key) { - setApiKey(key) - } - } - fetchApiKey() - }, [setApiKey]) + const { fontFamily, bgType, bgColor, bgImage } = useSettingsStore() - const editorRef = useRef<{ view?: EditorView } | null>(null) + const editorRef = useRef(null) const searchInputRef = useRef(null) - const activeNote = notes[currentNoteIndex] || { id: '', content: '', mtime: 0 } - // Custom Hooks useNoteStorage() useVariables() @@ -112,7 +66,7 @@ function App() { aiColor: localStorage.getItem('papercache-ai-color') || '#8b5cf6', mathColor: localStorage.getItem('papercache-math-color') || '#10b981', }) - // Refresh AI Store (API Key handled securely, we don't listen to localStorage for it directly) + // Refresh AI Store useAIStore.setState({ apiBaseUrl: localStorage.getItem('papercache-api-base-url') || 'https://openrouter.ai/api/v1', @@ -122,47 +76,19 @@ function App() { localStorage.getItem('papercache-ai-system-prompt') || 'You are a helpful assistant directly inside a markdown note. You can format your responses with markdown.', }) - // Fetch Secure API Key again - getSecure('papercache-apikey').then((key) => { - if (key) setApiKey(key) - }) } window.addEventListener('storage', handleStorageChange) return () => { window.removeEventListener('storage', handleStorageChange) } - }, [setApiKey]) - - const handleEditorChange = useCallback( - (val: string, viewUpdate?: ViewUpdate) => { - const updatedNotes = [...notes] - if (updatedNotes[currentNoteIndex]) { - updatedNotes[currentNoteIndex].content = val - setNotes(updatedNotes) - window.electronAPI.saveNote(activeNote.id, val) - } - - if (viewUpdate?.transactions?.some((tr) => tr.docChanged)) { - if (editorRef.current?.view) { - MathEvaluator.triggerMathEvaluation(editorRef.current.view) - } - } - }, - [notes, currentNoteIndex, activeNote.id, setNotes] - ) + }, []) - const containerStyle: React.CSSProperties & Record = { - '--font-family': fontFamily, - '--text-color': textColor, - '--custom-color-num': numColor, - '--custom-color-sym': symColor, - '--custom-color-ai': aiColor, - '--custom-color-math': mathColor, - zoom: zoomLevel, - } + const containerStyle: React.CSSProperties = { + fontFamily: fontFamily === 'monospace' ? 'var(--font-mono)' : 'var(--font-sans)', + } as React.CSSProperties if (bgType === 'color') { - containerStyle['--bg-color'] = bgColor + containerStyle['--bg-color' as string] = bgColor containerStyle.backgroundImage = 'none' } else if (bgType === 'image' && bgImage) { containerStyle.backgroundImage = `url(${bgImage})` @@ -171,263 +97,9 @@ function App() { containerStyle.backgroundRepeat = 'no-repeat' } - const editorExtensions = useMemo( - () => [ - EditorView.lineWrapping, - Prec.highest( - // eslint-disable-next-line react-hooks/refs - keymap.of([ - { key: 'Tab', preventDefault: true, run: insertTab }, - { key: 'Shift-Tab', preventDefault: true, run: indentLess }, - { - key: 'Mod-h', - run: (view) => { - const selection = view.state.selection.main - if (!selection.empty) { - const selectedText = view.state.doc.sliceString(selection.from, selection.to) - view.dispatch({ - changes: { - from: selection.from, - to: selection.to, - insert: `==${selectedText}==`, - }, - selection: { anchor: selection.from + 2, head: selection.to + 2 }, - }) - return true - } - return false - }, - }, - { - key: 'Mod-e', - run: () => { - const note = useAppStore.getState().notes[useAppStore.getState().currentNoteIndex] - if (note) { - const filename = note.id.split('/').pop() || 'note.md' - window.electronAPI.exportNote(filename, note.content) - } - return true - }, - }, - { - key: 'Mod-Backspace', - run: () => { - const note = useAppStore.getState().notes[useAppStore.getState().currentNoteIndex] - if (note) { - if (note.id.startsWith('commands/')) { - alert('Files in the commands folder cannot be deleted.') - return true - } - if (confirm('Delete this note?')) { - window.electronAPI.deleteNote(note.id) - setNotes((prev) => prev.filter((n) => n.id !== note.id)) - if ( - useAppStore.getState().currentNoteIndex >= - useAppStore.getState().notes.length - 1 - ) - setCurrentNoteIndex(Math.max(0, useAppStore.getState().notes.length - 2)) - } - } - return true - }, - }, - { - key: 'Mod-Delete', - run: () => { - const note = useAppStore.getState().notes[useAppStore.getState().currentNoteIndex] - if (note) { - if (note.id.startsWith('commands/')) { - alert('Files in the commands folder cannot be deleted.') - return true - } - if (confirm('Delete this note?')) { - window.electronAPI.deleteNote(note.id) - setNotes((prev) => prev.filter((n) => n.id !== note.id)) - if ( - useAppStore.getState().currentNoteIndex >= - useAppStore.getState().notes.length - 1 - ) - setCurrentNoteIndex(Math.max(0, useAppStore.getState().notes.length - 2)) - } - } - return true - }, - }, - { - key: 'Enter', - run: (view) => { - const pos = view.state.selection.main.head - const line = view.state.doc.lineAt(pos) - const lineText = line.text.trim() - const lowerLine = lineText.toLowerCase() - if ( - lowerLine.startsWith('/ai') || - lowerLine.startsWith('/ctx') || - lowerLine.startsWith('/context') - ) { - const isCtx = lowerLine.startsWith('/ctx') || lowerLine.startsWith('/context') - const prefixLength = lowerLine.startsWith('/context') - ? 8 - : lowerLine.startsWith('/ctx') - ? 4 - : 3 - const prompt = lineText.substring(prefixLength).trim() - if (!apiKey) { - const errorText = '\n\u200BError - Set your OpenAI API key in settings\u200C\n' - view.dispatch({ changes: { from: line.to, insert: errorText } }) - return true - } - - const thinkingText = '\n\u200B...\u200C\n' - view.dispatch({ changes: { from: line.to, insert: thinkingText } }) - ;(async () => { - try { - let finalBaseUrl = apiBaseUrl.trim() - if (finalBaseUrl.endsWith('/chat/completions')) { - finalBaseUrl = finalBaseUrl.replace('/chat/completions', '') - } - if (finalBaseUrl.endsWith('/')) { - finalBaseUrl = finalBaseUrl.slice(0, -1) - } - - const systemContent = aiSystemPrompt.trim() - const messages: { role: 'user' | 'system'; content: string }[] = [] - if (systemContent) { - messages.push({ role: 'system', content: systemContent }) - } - - let finalPrompt = prompt - if (isCtx) { - const fullNoteText = view.state.doc.toString() - const MAX_CONTEXT_LENGTH = 50000 - let contextText = fullNoteText - if (contextText.length > MAX_CONTEXT_LENGTH) { - contextText = - contextText.substring(0, MAX_CONTEXT_LENGTH) + - '\n...[Context truncated due to length]' - } - finalPrompt = `Context:\n${contextText}\n\nPrompt:\n${prompt}` - } - - messages.push({ role: 'user', content: finalPrompt }) - - window.electronAPI - .openAIChat({ - model: apiModel.trim() || 'nvidia/nemotron-3-super-120b-a12b:free', - messages: messages, - apiKey: apiKey.trim() || '', - baseURL: finalBaseUrl || '', - }) - // eslint-disable-next-line @typescript-eslint/no-explicit-any - .then((completion: any) => { - let response: string - if (completion.choices && completion.choices.length > 0) { - response = completion.choices[0].message?.content || '' - } else if (completion.error) { - throw new Error(completion.error.message || 'Unknown API Error') - } else { - throw new Error( - 'Unexpected response format: ' + JSON.stringify(completion) - ) - } - - const docStr = view.state.doc.toString() - const finalVal = docStr.replace( - '\n\u200B...\u200C\n', - '\n\u200B' + response + '\u200C\n' - ) - handleEditorChange(finalVal) - }) - .catch((error) => { - const docStr = view.state.doc.toString() - const errorVal = docStr.replace( - '\n\u200B...\u200C\n', - '\n\u200BError - ' + error.message + '\u200C\n' - ) - handleEditorChange(errorVal) - }) - } catch (err: unknown) { - const docStr = view.state.doc.toString() - const errorVal = docStr.replace( - '\n\u200B...\u200C\n', - '\n\u200BSetup Error - ' + - ((err as Error).message || String(err)) + - '\u200C\n' - ) - handleEditorChange(errorVal) - } - })() - - return true - } - return false - }, - }, - ]) - ), - search({ top: true }), - markdown(), - syntaxHighlighting(mdHighlighting), - numberPlugin, - symbolPlugin, - aiPlugin, - mathPlugin, - ...decomposedPlugins, - EditorView.domEventHandlers({ - mousedown: (event) => { - const target = event.target as HTMLElement - const webLink = target?.closest('.cm-custom-clickable-link') - const fileLink = target?.closest('.cm-custom-file-link') - - if ((webLink || fileLink) && (event.metaKey || event.ctrlKey)) { - event.preventDefault() - if (webLink) { - const url = webLink.getAttribute('data-url') - if (url) { - let finalUrl = url - if (!/^https?:\/\//i.test(finalUrl)) { - finalUrl = 'https://' + finalUrl - } - window.electronAPI.openExternal(finalUrl) - } - } else if (fileLink) { - const path = fileLink.getAttribute('data-path') - if (path) { - window.dispatchEvent(new CustomEvent('open-papercache-note', { detail: { path } })) - } - } - return true - } - return false - }, - }), - ], - [ - apiKey, - apiBaseUrl, - apiModel, - aiSystemPrompt, - handleEditorChange, - setCurrentNoteIndex, - setNotes, - ] - ) - - useEffect(() => { - const handleWindowFocus = () => { - if (editorRef.current?.view && !editorRef.current.view.hasFocus) { - editorRef.current.view.focus() - } - } - window.addEventListener('focus', handleWindowFocus) - return () => window.removeEventListener('focus', handleWindowFocus) - }, []) - const handleAppClick = () => { setShowMainActionMenu(false) - if (editorRef.current?.view && !editorRef.current.view.hasFocus) { - editorRef.current.view.focus() - } + editorRef.current?.focus() } return ( @@ -461,10 +133,7 @@ function App() { window.electronAPI.saveNote(note.id, newContent) if (idx === currentNoteIndex) { - const view = editorRef.current?.view - if (view) { - view.dispatch({ changes: { from, to, insert } }) - } + editorRef.current?.dispatch({ changes: { from, to, insert } }) } } return newNotes @@ -494,22 +163,7 @@ function App() { /> )} -
- -
+ ) } diff --git a/src/Settings.test.tsx b/src/Settings.test.tsx index 1d757a9..233e8a8 100644 --- a/src/Settings.test.tsx +++ b/src/Settings.test.tsx @@ -12,6 +12,8 @@ describe('Settings Component', () => { updateGlobalShortcut: vi.fn(), closeWindow: vi.fn(), quitApp: vi.fn(), + getApiKeyStatus: vi.fn().mockResolvedValue(false), + setApiKey: vi.fn().mockResolvedValue(true), } as any // eslint-disable-line @typescript-eslint/no-explicit-any }) @@ -24,12 +26,12 @@ describe('Settings Component', () => { expect(screen.getByText('Appearance')).toBeInTheDocument() }) - it('loads initial state from localStorage', async () => { - localStorage.setItem('papercache-apikey-secure', 'sk-test-key') + it('loads API key status from IPC', async () => { + ;(window.electronAPI.getApiKeyStatus as any).mockResolvedValue(true) render() - const apiKeyInput = screen.getByPlaceholderText('sk-...') as HTMLInputElement - await waitFor(() => expect(apiKeyInput.value).toBe('sk-test-key')) + await waitFor(() => expect(screen.getByText('API Key ✅ (Set)')).toBeInTheDocument()) + expect(screen.getByPlaceholderText('Enter new key to replace existing')).toBeInTheDocument() }) it('updates state when inputs change', () => { @@ -41,7 +43,7 @@ describe('Settings Component', () => { expect((apiKeyInput as HTMLInputElement).value).toBe('sk-new-key') }) - it('saves settings to localStorage on Save Settings button click', async () => { + it('saves settings to IPC on Save Settings button click', async () => { render() const apiKeyInput = screen.getByPlaceholderText('sk-...') @@ -51,7 +53,7 @@ describe('Settings Component', () => { fireEvent.click(saveButton) await waitFor(() => { - expect(localStorage.getItem('papercache-apikey-secure')).toBe('sk-new-key') + expect(window.electronAPI.setApiKey).toHaveBeenCalledWith('sk-new-key') expect(window.electronAPI.closeWindow).toHaveBeenCalled() }) }) diff --git a/src/Settings.tsx b/src/Settings.tsx index 97cd863..0b64053 100644 --- a/src/Settings.tsx +++ b/src/Settings.tsx @@ -1,14 +1,14 @@ import { useState, useEffect } from 'react' -import { getSecure, setSecure } from './lib/safeStorage' import { SETTINGS_KEYS } from './lib/settingsKeys' import './Settings.css' export default function Settings() { const [apiKey, setApiKey] = useState('') + const [isApiKeySet, setIsApiKeySet] = useState(false) useEffect(() => { - getSecure('papercache-apikey').then((key) => { - if (key) setApiKey(key) + window.electronAPI.getApiKeyStatus().then((status) => { + setIsApiKeySet(status) }) const handleKeyDown = (e: KeyboardEvent) => { @@ -72,8 +72,9 @@ export default function Settings() { ) const saveSettings = async () => { - await setSecure('papercache-apikey', apiKey) - localStorage.removeItem('papercache-apikey') + if (apiKey) { + await window.electronAPI.setApiKey(apiKey) + } localStorage.setItem(SETTINGS_KEYS.API_BASE_URL, apiBaseUrl) localStorage.setItem(SETTINGS_KEYS.API_MODEL, apiModel) localStorage.setItem(SETTINGS_KEYS.AI_SYSTEM_PROMPT, aiSystemPrompt) @@ -136,12 +137,12 @@ export default function Settings() {

AI Configuration

- + setApiKey(e.target.value)} - placeholder="sk-..." + placeholder={isApiKeySet ? 'Enter new key to replace existing' : 'sk-...'} />
diff --git a/src/components/Editor.tsx b/src/components/Editor.tsx new file mode 100644 index 0000000..929c23a --- /dev/null +++ b/src/components/Editor.tsx @@ -0,0 +1,85 @@ +import { useCallback, useRef, useEffect, forwardRef, useImperativeHandle } from 'react' +import CodeMirror from '@uiw/react-codemirror' +import { ViewUpdate } from '@codemirror/view' +import { useAppStore } from '../../store/useAppStore' +import { useSettingsStore } from '../../store/useSettingsStore' +import { MathEvaluator } from './MathEvaluator' +import { useEditorExtensions } from './extensions' + +export interface EditorRef { + dispatch: (tx: any) => void + focus: () => void +} + +export const Editor = forwardRef((props, ref) => { + const notes = useAppStore((state) => state.notes) + const setNotes = useAppStore((state) => state.setNotes) + const currentNoteIndex = useAppStore((state) => state.currentNoteIndex) + const activeNote = notes[currentNoteIndex] || { id: '', content: '', mtime: 0 } + + const themePreset = useSettingsStore((state) => state.themePreset) + + const editorRef = useRef(null) + + useImperativeHandle(ref, () => ({ + dispatch: (tx: any) => { + if (editorRef.current?.view) { + editorRef.current.view.dispatch(tx) + } + }, + focus: () => { + if (editorRef.current?.view) { + editorRef.current.view.focus() + } + }, + })) + + const handleEditorChange = useCallback( + (val: string, viewUpdate?: ViewUpdate) => { + const updatedNotes = [...notes] + if (updatedNotes[currentNoteIndex]) { + updatedNotes[currentNoteIndex].content = val + setNotes(updatedNotes) + window.electronAPI.saveNote(activeNote.id, val) + } + + if (viewUpdate?.transactions?.some((tr) => tr.docChanged)) { + if (editorRef.current?.view) { + MathEvaluator.triggerMathEvaluation(editorRef.current.view) + } + } + }, + [notes, currentNoteIndex, activeNote.id, setNotes] + ) + + const extensions = useEditorExtensions(handleEditorChange) + + useEffect(() => { + const handleWindowFocus = () => { + if (editorRef.current?.view && !editorRef.current.view.hasFocus) { + editorRef.current.view.focus() + } + } + window.addEventListener('focus', handleWindowFocus) + return () => window.removeEventListener('focus', handleWindowFocus) + }, []) + + return ( +
+ +
+ ) +}) diff --git a/src/components/ErrorBoundary.tsx b/src/components/ErrorBoundary.tsx new file mode 100644 index 0000000..4a0aeda --- /dev/null +++ b/src/components/ErrorBoundary.tsx @@ -0,0 +1,64 @@ +import { Component, ErrorInfo, ReactNode } from 'react' + +interface Props { + children?: ReactNode +} + +interface State { + hasError: boolean + error?: Error +} + +export class ErrorBoundary extends Component { + public state: State = { + hasError: false, + } + + public static getDerivedStateFromError(error: Error): State { + return { hasError: true, error } + } + + public componentDidCatch(error: Error, errorInfo: ErrorInfo) { + console.error('Uncaught error:', error, errorInfo) + } + + public render() { + if (this.state.hasError) { + return ( +
+

Something went wrong.

+
+            {this.state.error?.message}
+          
+ +
+ ) + } + + return this.props.children + } +} diff --git a/src/lib/editor/MathEvaluator.ts b/src/lib/editor/MathEvaluator.ts index 37769b7..7cb7ba0 100644 --- a/src/lib/editor/MathEvaluator.ts +++ b/src/lib/editor/MathEvaluator.ts @@ -4,69 +4,76 @@ import { VariableScope } from './VariableScope' export class MathEvaluator { static evalTimeout: number | null = null - static triggerMathEvaluation(view: EditorView) { - if (this.evalTimeout) window.clearTimeout(this.evalTimeout) - this.evalTimeout = window.setTimeout(async () => { - let mathjs - try { - mathjs = await import('mathjs') - } catch { - return - } + static async evaluateMathChanges( + docStr: string, + scope: Record + ): Promise<{ from: number; to: number; insert: string }[]> { + let mathjs + try { + mathjs = await import('mathjs') + } catch { + return [] + } + const changes: { from: number; to: number; insert: string }[] = [] - const docStr = view.state.doc.toString() - const scope = VariableScope.getScope() + // 1. Evaluate new lines that end with '=' but don't have '\u200B' yet + const lines = docStr.split('\n') + let offset = 0 + for (let i = 0; i < lines.length; i++) { + const text = lines[i] + const lineLen = text.length - const changes: { from: number; to: number; insert: string }[] = [] + if (!text.includes('\u200B') && text.trim().endsWith('=')) { + const expr = text.substring(0, text.lastIndexOf('=')).trim() + if (expr && !expr.startsWith('/var') && !expr.startsWith('/globvar')) { + try { + const result = String(mathjs.evaluate(expr, scope)) + changes.push({ + from: offset + lineLen, + to: offset + lineLen, + insert: '\u200B' + result, + }) + } catch {} + } + } - // 1. Evaluate new lines that end with '=' but don't have '\u200B' yet - const lines = docStr.split('\n') - let offset = 0 - for (let i = 0; i < lines.length; i++) { - const text = lines[i] - const lineLen = text.length + offset += lineLen + 1 // +1 for '\n' + } - if (!text.includes('\u200B') && text.trim().endsWith('=')) { - const expr = text.substring(0, text.lastIndexOf('=')).trim() - if (expr && !expr.startsWith('/var') && !expr.startsWith('/globvar')) { - try { - const result = String(mathjs.evaluate(expr, scope)) + // 2. Re-evaluate existing calculations that already have '\u200B' + const reCalc = /^(.*?=\s*)\u200B(.*)$/gm + let calcMatch + while ((calcMatch = reCalc.exec(docStr)) !== null) { + const exprPart = calcMatch[1] + const oldResult = calcMatch[2] + const expr = exprPart.replace(/=\s*$/, '').trim() + if (expr) { + try { + const newResult = String(mathjs.evaluate(expr, scope)) + if (newResult !== oldResult) { + const startReplace = calcMatch.index + exprPart.length + 1 // +1 for \u200B + const endReplace = calcMatch.index + calcMatch[0].length + if (!changes.some((c) => c.from <= endReplace && c.to >= startReplace)) { changes.push({ - from: offset + lineLen, - to: offset + lineLen, - insert: '\u200B' + result, + from: startReplace, + to: endReplace, + insert: newResult, }) - } catch {} + } } - } - - offset += lineLen + 1 // +1 for '\n' + } catch {} } + } - // 2. Re-evaluate existing calculations that already have '\u200B' - const reCalc = /^(.*?=\s*)\u200B(.*)$/gm - let calcMatch - while ((calcMatch = reCalc.exec(docStr)) !== null) { - const exprPart = calcMatch[1] - const oldResult = calcMatch[2] - const expr = exprPart.replace(/=\s*$/, '').trim() - if (expr) { - try { - const newResult = String(mathjs.evaluate(expr, scope)) - if (newResult !== oldResult) { - const startReplace = calcMatch.index + exprPart.length + 1 // +1 for \u200B - const endReplace = calcMatch.index + calcMatch[0].length - if (!changes.some((c) => c.from <= endReplace && c.to >= startReplace)) { - changes.push({ - from: startReplace, - to: endReplace, - insert: newResult, - }) - } - } - } catch {} - } - } + return changes + } + + static triggerMathEvaluation(view: EditorView) { + if (this.evalTimeout) window.clearTimeout(this.evalTimeout) + this.evalTimeout = window.setTimeout(async () => { + const docStr = view.state.doc.toString() + const scope = VariableScope.getScope() + const changes = await this.evaluateMathChanges(docStr, scope) if (changes.length > 0) { view.dispatch({ changes }) diff --git a/src/lib/editor/extensions.ts b/src/lib/editor/extensions.ts new file mode 100644 index 0000000..7cf60a8 --- /dev/null +++ b/src/lib/editor/extensions.ts @@ -0,0 +1,255 @@ +import { useMemo } from 'react' +import { EditorView, keymap } from '@codemirror/view' +import { Prec } from '@codemirror/state' +import { search } from '@codemirror/search' +import { markdown } from '@codemirror/lang-markdown' +import { syntaxHighlighting } from '@codemirror/language' +import { insertTab, indentLess } from '@codemirror/commands' + +import { mdHighlighting } from './matchers' +import { numberPlugin, symbolPlugin, aiPlugin, mathPlugin, decomposedPlugins } from './plugins' +import { useAIStore } from '../../store/useAIStore' +import { useAppStore } from '../../store/useAppStore' + +export function useEditorExtensions(handleEditorChange: (val: string) => void) { + const { apiBaseUrl, apiModel, aiSystemPrompt } = useAIStore() + const setNotes = useAppStore((state) => state.setNotes) + const setCurrentNoteIndex = useAppStore((state) => state.setCurrentNoteIndex) + + return useMemo( + () => [ + EditorView.lineWrapping, + Prec.highest( + keymap.of([ + { key: 'Tab', preventDefault: true, run: insertTab }, + { key: 'Shift-Tab', preventDefault: true, run: indentLess }, + { + key: 'Mod-h', + run: (view) => { + const selection = view.state.selection.main + if (!selection.empty) { + const selectedText = view.state.doc.sliceString(selection.from, selection.to) + view.dispatch({ + changes: { + from: selection.from, + to: selection.to, + insert: `==${selectedText}==`, + }, + selection: { anchor: selection.from + 2, head: selection.to + 2 }, + }) + return true + } + return false + }, + }, + { + key: 'Mod-e', + run: () => { + const note = useAppStore.getState().notes[useAppStore.getState().currentNoteIndex] + if (note) { + const filename = note.id.split('/').pop() || 'note.md' + window.electronAPI.exportNote(filename, note.content) + } + return true + }, + }, + { + key: 'Mod-Backspace', + run: () => { + const note = useAppStore.getState().notes[useAppStore.getState().currentNoteIndex] + if (note) { + if (note.id.startsWith('commands/')) { + alert('Files in the commands folder cannot be deleted.') + return true + } + if (confirm('Delete this note?')) { + window.electronAPI.deleteNote(note.id) + setNotes((prev) => prev.filter((n) => n.id !== note.id)) + if ( + useAppStore.getState().currentNoteIndex >= + useAppStore.getState().notes.length - 1 + ) + setCurrentNoteIndex(Math.max(0, useAppStore.getState().notes.length - 2)) + } + } + return true + }, + }, + { + key: 'Mod-Delete', + run: () => { + const note = useAppStore.getState().notes[useAppStore.getState().currentNoteIndex] + if (note) { + if (note.id.startsWith('commands/')) { + alert('Files in the commands folder cannot be deleted.') + return true + } + if (confirm('Delete this note?')) { + window.electronAPI.deleteNote(note.id) + setNotes((prev) => prev.filter((n) => n.id !== note.id)) + if ( + useAppStore.getState().currentNoteIndex >= + useAppStore.getState().notes.length - 1 + ) + setCurrentNoteIndex(Math.max(0, useAppStore.getState().notes.length - 2)) + } + } + return true + }, + }, + { + key: 'Enter', + run: (view) => { + const pos = view.state.selection.main.head + const line = view.state.doc.lineAt(pos) + const lineText = line.text.trim() + const lowerLine = lineText.toLowerCase() + if ( + lowerLine.startsWith('/ai') || + lowerLine.startsWith('/ctx') || + lowerLine.startsWith('/context') + ) { + const isCtx = lowerLine.startsWith('/ctx') || lowerLine.startsWith('/context') + const prefixLength = lowerLine.startsWith('/context') + ? 8 + : lowerLine.startsWith('/ctx') + ? 4 + : 3 + const prompt = lineText.substring(prefixLength).trim() + + const thinkingText = '\n\u200B...\u200C\n' + view.dispatch({ changes: { from: line.to, insert: thinkingText } }) + ;(async () => { + try { + const isKeySet = await window.electronAPI.getApiKeyStatus() + if (!isKeySet) { + const docStr = view.state.doc.toString() + const errorVal = docStr.replace( + '\n\u200B...\u200C\n', + '\n\u200BError - Set your OpenAI API key in settings\u200C\n' + ) + handleEditorChange(errorVal) + return + } + + let finalBaseUrl = apiBaseUrl.trim() + if (finalBaseUrl.endsWith('/chat/completions')) { + finalBaseUrl = finalBaseUrl.replace('/chat/completions', '') + } + if (finalBaseUrl.endsWith('/')) { + finalBaseUrl = finalBaseUrl.slice(0, -1) + } + + const systemContent = aiSystemPrompt.trim() + const messages: { role: 'user' | 'system'; content: string }[] = [] + if (systemContent) { + messages.push({ role: 'system', content: systemContent }) + } + + let finalPrompt = prompt + if (isCtx) { + const fullNoteText = view.state.doc.toString() + const MAX_CONTEXT_LENGTH = 50000 + let contextText = fullNoteText + if (contextText.length > MAX_CONTEXT_LENGTH) { + contextText = + contextText.substring(0, MAX_CONTEXT_LENGTH) + + '\n...[Context truncated due to length]' + } + finalPrompt = `Context:\n${contextText}\n\nPrompt:\n${prompt}` + } + + messages.push({ role: 'user', content: finalPrompt }) + + window.electronAPI + .openAIChat({ + model: apiModel.trim() || 'nvidia/nemotron-3-super-120b-a12b:free', + messages: messages, + baseURL: finalBaseUrl || '', + }) + .then((completion: any) => { + let response: string + if (completion.choices && completion.choices.length > 0) { + response = completion.choices[0].message?.content || '' + } else if (completion.error) { + throw new Error(completion.error.message || 'Unknown API Error') + } else { + throw new Error( + 'Unexpected response format: ' + JSON.stringify(completion) + ) + } + + const docStr = view.state.doc.toString() + const finalVal = docStr.replace( + '\n\u200B...\u200C\n', + '\n\u200B' + response + '\u200C\n' + ) + handleEditorChange(finalVal) + }) + .catch((error) => { + const docStr = view.state.doc.toString() + const errorVal = docStr.replace( + '\n\u200B...\u200C\n', + '\n\u200BError - ' + error.message + '\u200C\n' + ) + handleEditorChange(errorVal) + }) + } catch (err: unknown) { + const docStr = view.state.doc.toString() + const errorVal = docStr.replace( + '\n\u200B...\u200C\n', + '\n\u200BSetup Error - ' + + ((err as Error).message || String(err)) + + '\u200C\n' + ) + handleEditorChange(errorVal) + } + })() + + return true + } + return false + }, + }, + ]) + ), + search({ top: true }), + markdown(), + syntaxHighlighting(mdHighlighting), + numberPlugin, + symbolPlugin, + aiPlugin, + mathPlugin, + ...decomposedPlugins, + EditorView.domEventHandlers({ + mousedown: (event) => { + const target = event.target as HTMLElement + const webLink = target?.closest('.cm-custom-clickable-link') + const fileLink = target?.closest('.cm-custom-file-link') + + if ((webLink || fileLink) && (event.metaKey || event.ctrlKey)) { + event.preventDefault() + if (webLink) { + const url = webLink.getAttribute('data-url') + if (url) { + let finalUrl = url + if (!/^https?:\/\//i.test(finalUrl)) { + finalUrl = 'https://' + finalUrl + } + window.electronAPI.openExternal(finalUrl) + } + } else if (fileLink) { + const path = fileLink.getAttribute('data-path') + if (path) { + window.dispatchEvent(new CustomEvent('open-papercache-note', { detail: { path } })) + } + } + return true + } + return false + }, + }), + ], + [apiBaseUrl, apiModel, aiSystemPrompt, handleEditorChange, setCurrentNoteIndex, setNotes] + ) +} diff --git a/src/main.tsx b/src/main.tsx index 463c37d..420ed0a 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -3,7 +3,7 @@ import { createRoot } from 'react-dom/client' import './index.css' import App from './App.tsx' import Settings from './Settings.tsx' -import { migrateApiKeyFromLocalStorage } from './lib/safeStorage' +import { ErrorBoundary } from './components/ErrorBoundary.tsx' function Root() { const [hash, setHash] = useState(window.location.hash) @@ -17,7 +17,36 @@ function Root() { useEffect(() => { async function migrate() { - await migrateApiKeyFromLocalStorage('papercache-apikey') + // Migrate legacy plain text key if it exists + const plain = localStorage.getItem('papercache-apikey') + if (plain) { + try { + const success = await window.electronAPI.setApiKey(plain) + if (success) { + localStorage.removeItem('papercache-apikey') + } + } catch (e) { + console.error('Failed to migrate plain API key', e) + } + } + + // Migrate legacy encrypted key if it exists + const secureEncrypted = localStorage.getItem('papercache-apikey-secure') + if (secureEncrypted) { + try { + // Decrypt it using the old method, then send to new IPC + const decrypted = await window.electronAPI.safeStorageDecrypt(secureEncrypted) + if (decrypted) { + const success = await window.electronAPI.setApiKey(decrypted) + if (success) { + localStorage.removeItem('papercache-apikey-secure') + } + } + } catch (e) { + console.error('Failed to migrate secure API key', e) + } + } + setMigrated(true) } migrate() @@ -25,7 +54,11 @@ function Root() { if (!migrated) return null - return {hash === '#/settings' ? : } + return ( + + {hash === '#/settings' ? : } + + ) } createRoot(document.getElementById('root')!).render() diff --git a/src/setupTests.ts b/src/setupTests.ts index aff2f7a..fbce366 100644 --- a/src/setupTests.ts +++ b/src/setupTests.ts @@ -1,39 +1,42 @@ import '@testing-library/jest-dom' -// Mock matchMedia which is not present in jsdom but might be needed by some UI components -Object.defineProperty(window, 'matchMedia', { - writable: true, - value: (query: string) => ({ - matches: false, - media: query, - onchange: null, - addListener: () => {}, // deprecated - removeListener: () => {}, // deprecated - addEventListener: () => {}, - removeEventListener: () => {}, - dispatchEvent: () => false, - }), -}) +// Mock matchMedia which is not present in jsdom but might be needed by some components +if (typeof window !== 'undefined') { + Object.defineProperty(window, 'matchMedia', { + writable: true, + value: (query: string) => ({ + matches: false, + media: query, + onchange: null, + addListener: vi.fn(), // deprecated + removeListener: vi.fn(), // deprecated + addEventListener: vi.fn(), + removeEventListener: vi.fn(), + dispatchEvent: vi.fn(), + }), + }) +} // Mock electronAPI for testing environments -if (!window.electronAPI) { +if (typeof window !== 'undefined' && !window.electronAPI) { window.electronAPI = { - getNotes: async () => [], - saveNote: async () => true, - deleteNote: async () => true, - renameNote: async () => true, - openSettings: () => {}, - closeWindow: () => {}, - quitApp: () => {}, - onPowerSuspend: () => () => {}, - onPowerResume: () => () => {}, - setLaunchAtStartup: () => {}, - updateGlobalShortcut: () => {}, - readNote: async () => '', - exportNote: async () => true, - openExternal: () => {}, - openFile: () => {}, - safeStorageEncrypt: async (val: string) => val, - safeStorageDecrypt: async (val: string) => val, + getPlatform: () => 'darwin', + openExternal: vi.fn(), + saveNote: vi.fn(), + deleteNote: vi.fn(), + renameNote: vi.fn(), + openAIChat: vi.fn(), + readNote: vi.fn().mockResolvedValue(''), + exportNote: vi.fn(), + openSettings: vi.fn(), + safeStorageEncrypt: vi.fn((val) => Promise.resolve(val)), + safeStorageDecrypt: vi.fn((val) => Promise.resolve(val)), + getAppVersion: vi.fn().mockResolvedValue('1.0.0'), + openDevTools: vi.fn(), + onReminderFired: vi.fn(), + onUpdateGlobalShortcut: vi.fn(), + onPowerSuspend: vi.fn().mockReturnValue(() => {}), + onPowerResume: vi.fn().mockReturnValue(() => {}), + removeListener: vi.fn(), } as unknown as typeof window.electronAPI } diff --git a/src/store/useAIStore.ts b/src/store/useAIStore.ts index 9109a1a..907ba13 100644 --- a/src/store/useAIStore.ts +++ b/src/store/useAIStore.ts @@ -1,19 +1,16 @@ import { create } from 'zustand' export interface AIState { - apiKey: string apiBaseUrl: string apiModel: string aiSystemPrompt: string - setApiKey: (key: string) => void setApiBaseUrl: (url: string) => void setApiModel: (model: string) => void setAiSystemPrompt: (prompt: string) => void } export const useAIStore = create((set) => ({ - apiKey: '', apiBaseUrl: localStorage.getItem('papercache-api-base-url') || 'https://openrouter.ai/api/v1', apiModel: localStorage.getItem('papercache-api-model') || 'nvidia/nemotron-3-super-120b-a12b:free', @@ -21,7 +18,6 @@ export const useAIStore = create((set) => ({ localStorage.getItem('papercache-ai-system-prompt') || 'You are a helpful assistant directly inside a markdown note. You can format your responses with markdown.', - setApiKey: (apiKey) => set({ apiKey }), setApiBaseUrl: (apiBaseUrl) => { localStorage.setItem('papercache-api-base-url', apiBaseUrl) set({ apiBaseUrl }) diff --git a/src/types.d.ts b/src/types.d.ts index f5d801b..7754708 100644 --- a/src/types.d.ts +++ b/src/types.d.ts @@ -7,9 +7,11 @@ export interface ElectronAPI { openAIChat: (args: { model: string messages: { role: string; content: string }[] - apiKey: string baseURL: string }) => Promise + setApiKey: (key: string) => Promise + getApiKeyStatus: () => Promise + checkForUpdates: () => void readNote: (id: string) => Promise exportNote: (filename: string, content: string) => Promise openSettings: () => void diff --git a/tests/MathEvaluator.test.ts b/tests/MathEvaluator.test.ts new file mode 100644 index 0000000..222f9ad --- /dev/null +++ b/tests/MathEvaluator.test.ts @@ -0,0 +1,45 @@ +import { describe, it, expect } from 'vitest' +import { MathEvaluator } from '../src/lib/editor/MathEvaluator' + +describe('MathEvaluator', () => { + it('evaluates new math expressions ending with =', async () => { + const docStr = '1 + 2 =\n' + const scope = {} + const changes = await MathEvaluator.evaluateMathChanges(docStr, scope) + expect(changes).toEqual([ + { from: 7, to: 7, insert: '\u200B3' } + ]) + }) + + it('updates existing evaluations if they changed', async () => { + const docStr = '1 + 3 =\u200B3' + const scope = {} + const changes = await MathEvaluator.evaluateMathChanges(docStr, scope) + expect(changes).toEqual([ + { from: 8, to: 9, insert: '4' } + ]) + }) + + it('ignores invalid expressions', async () => { + const docStr = '1 + * 2 =\n' + const scope = {} + const changes = await MathEvaluator.evaluateMathChanges(docStr, scope) + expect(changes).toEqual([]) + }) + + it('ignores /var definitions', async () => { + const docStr = '/var x = 10\n' + const scope = {} + const changes = await MathEvaluator.evaluateMathChanges(docStr, scope) + expect(changes).toEqual([]) // Because it's a variable declaration, not a math expression to evaluate inline + }) + + it('uses provided scope', async () => { + const docStr = 'x * 2 =\n' + const scope = { x: 5 } + const changes = await MathEvaluator.evaluateMathChanges(docStr, scope) + expect(changes).toEqual([ + { from: 7, to: 7, insert: '\u200B10' } + ]) + }) +}) diff --git a/tests/safeStorage.test.ts b/tests/safeStorage.test.ts new file mode 100644 index 0000000..0cb5ea7 --- /dev/null +++ b/tests/safeStorage.test.ts @@ -0,0 +1,28 @@ +import { describe, it, expect, beforeEach } from 'vitest' +import { setSecure, getSecure } from '../src/lib/safeStorage' + +describe('safeStorage (Renderer Flow)', () => { + beforeEach(() => { + localStorage.clear() + vi.clearAllMocks() + }) + + it('encrypts value and stores in localStorage securely', async () => { + await setSecure('test-key', 'secret-text') + expect(window.electronAPI.safeStorageEncrypt).toHaveBeenCalledWith('secret-text') + expect(localStorage.getItem('test-key-secure')).toBe('secret-text') // The mock just returns the value it received + }) + + it('decrypts value from localStorage securely', async () => { + localStorage.setItem('test-key-secure', 'encrypted-secret') + const decrypted = await getSecure('test-key') + expect(window.electronAPI.safeStorageDecrypt).toHaveBeenCalledWith('encrypted-secret') + expect(decrypted).toBe('encrypted-secret') + }) + + it('returns null if no secure key exists', async () => { + const decrypted = await getSecure('missing-key') + expect(window.electronAPI.safeStorageDecrypt).not.toHaveBeenCalled() + expect(decrypted).toBeNull() + }) +}) From 1e7f476820d1e4eb45d343f957410707fdefde35 Mon Sep 17 00:00:00 2001 From: Aditya Date: Sun, 21 Jun 2026 09:38:42 +0530 Subject: [PATCH 02/10] chore: Sync package-lock.json --- package-lock.json | 225 +++++++++++++++++++++++++++++++++++++--------- package.json | 1 + 2 files changed, 182 insertions(+), 44 deletions(-) diff --git a/package-lock.json b/package-lock.json index fd7dd5f..5521964 100644 --- a/package-lock.json +++ b/package-lock.json @@ -33,6 +33,7 @@ "@types/react": "^19.2.14", "@types/react-dom": "^19.2.3", "@vitejs/plugin-react": "^6.0.1", + "@vitest/coverage-v8": "^4.1.9", "electron": "^42.3.0", "electron-builder": "^26.8.1", "esbuild": "^0.28.0", @@ -385,6 +386,16 @@ "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", @@ -3029,17 +3040,49 @@ } } }, + "node_modules/@vitest/coverage-v8": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-4.1.9.tgz", + "integrity": "sha512-G9/lgqibheLVBDRuya45EbsEXTYcWoSG+TLg7i2axuzx0Eq62eXn+aWXyaVdV5vKvFSWd6ywcX8hA7la9Pvu8g==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@bcoe/v8-coverage": "^1.0.2", + "@vitest/utils": "4.1.9", + "ast-v8-to-istanbul": "^1.0.0", + "istanbul-lib-coverage": "^3.2.2", + "istanbul-lib-report": "^3.0.1", + "istanbul-reports": "^3.2.0", + "magicast": "^0.5.2", + "obug": "^2.1.1", + "std-env": "^4.0.0-rc.1", + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@vitest/browser": "4.1.9", + "vitest": "4.1.9" + }, + "peerDependenciesMeta": { + "@vitest/browser": { + "optional": true + } + } + }, "node_modules/@vitest/expect": { - "version": "4.1.8", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.8.tgz", - "integrity": "sha512-h3nDO677RDLEGlBxyQ5CW8RlMThSKSRLUePLOx09gNIWRL40edgA1GCZSZgf1W55MFAG6/Sw14KeaAnqv0NKdQ==", + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.9.tgz", + "integrity": "sha512-vl/rYsUKcBr3SnQn166+XR5ZQcgMx3DQhFWdfli/cWpLnLUmbxZvyrJZotLFUryib+LtArYMSTJ5RbQ57ZqrlA==", "dev": true, "license": "MIT", "dependencies": { "@standard-schema/spec": "^1.1.0", "@types/chai": "^5.2.2", - "@vitest/spy": "4.1.8", - "@vitest/utils": "4.1.8", + "@vitest/spy": "4.1.9", + "@vitest/utils": "4.1.9", "chai": "^6.2.2", "tinyrainbow": "^3.1.0" }, @@ -3048,13 +3091,13 @@ } }, "node_modules/@vitest/mocker": { - "version": "4.1.8", - "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.8.tgz", - "integrity": "sha512-LEiN/xe4OSIbKe9HQIp5OC24agGD9J5CnmMgsLohVVoOPWL9a2sBoR6VBx43jQZb7Kr1l4RCuyCJzcAa0+dojw==", + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.9.tgz", + "integrity": "sha512-EVkXzBjrPGM+cK8/ANWgBrkUCfJfb38/EfTSO8h7pWvKkyPkpWxvR7BkD2MyItMF62C97zAEoqdpUixwR/e+Rw==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/spy": "4.1.8", + "@vitest/spy": "4.1.9", "estree-walker": "^3.0.3", "magic-string": "^0.30.21" }, @@ -3075,9 +3118,9 @@ } }, "node_modules/@vitest/pretty-format": { - "version": "4.1.8", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.8.tgz", - "integrity": "sha512-9GasEBxpZ1VYIpqHf/0+YGg121uSNwCKOJqIrTwWP/TB7DmFCiaBpNl3aPZzoLWfWkuqhbH8vJIVobZkvdo2cA==", + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.9.tgz", + "integrity": "sha512-s0iufns3iIFitdgm+YR7g1whCAaGtXz459VS9/PqyKDEEFgYIhsHOQmXgIgDuYCt7DeQmiZT0Qe2OA2p4ZPu5A==", "dev": true, "license": "MIT", "dependencies": { @@ -3088,13 +3131,13 @@ } }, "node_modules/@vitest/runner": { - "version": "4.1.8", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.8.tgz", - "integrity": "sha512-EmVxeBAfMJvycdjd6Hm+RbFBbA9fKvo0Kx37hNpBYoYeavH3RNsBXWDooR1mgD52dCrxIIuP7UotpfiwOikvcg==", + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.9.tgz", + "integrity": "sha512-KXLMDtc7oe70+3mJfGrPUWPesswH+3sTxAMAMl8DG7I8IUQT4XW718dY5ID3vPUcmlu27CcKfY4P3h3I29SLJg==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/utils": "4.1.8", + "@vitest/utils": "4.1.9", "pathe": "^2.0.3" }, "funding": { @@ -3102,14 +3145,14 @@ } }, "node_modules/@vitest/snapshot": { - "version": "4.1.8", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.8.tgz", - "integrity": "sha512-acfZboRmAIf05DEKcBQy33VXojFJjtUdLyo7oOmV9kebb2xdU01UknNiPuPZoJZQyO7DF0gZdTGTpeAzET9QPQ==", + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.9.tgz", + "integrity": "sha512-Jc7RKGNBo8Z28WYIm0Niej4xdSPByRf6mU58VpHQkd6Zh05rlnA+twjbK5HyeIGHxrzsc3mJgS43uM0CZKzaIA==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "4.1.8", - "@vitest/utils": "4.1.8", + "@vitest/pretty-format": "4.1.9", + "@vitest/utils": "4.1.9", "magic-string": "^0.30.21", "pathe": "^2.0.3" }, @@ -3118,9 +3161,9 @@ } }, "node_modules/@vitest/spy": { - "version": "4.1.8", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.8.tgz", - "integrity": "sha512-6EevtBp6OZOPF7bmz36HrGMeP3txgVSrgebWxHOafDXGkhIzfXK14f8KF6MuFfgXXUeHxmpD3BQxkV00/3s5mA==", + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.9.tgz", + "integrity": "sha512-fHpsS6mIi+PiEW+vcRVOMkX1oSaPKne3VOclSFICPcGOmfKgXPU5iAah+wcNcj2xPrCCmfq99IDGf+EojhhvhA==", "dev": true, "license": "MIT", "funding": { @@ -3128,13 +3171,13 @@ } }, "node_modules/@vitest/utils": { - "version": "4.1.8", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.8.tgz", - "integrity": "sha512-uOJamYALNhfJ6iolExyQM40yIQwDqYnkKtQ5VCiSe17E33H0aQ/u+1GlRuz4LZBk6Mm3sg90G9hEbmEt37C1Zg==", + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.9.tgz", + "integrity": "sha512-A51o8ymO5PpqlWNnBP9ZHPXDIpuMtTLlGSjN7la4US+LJzoUMyhwjA5QXlm39JexgwHKW4Xjs8Z2d3dLCXOeuA==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "4.1.8", + "@vitest/pretty-format": "4.1.9", "convert-source-map": "^2.0.0", "tinyrainbow": "^3.1.0" }, @@ -3468,6 +3511,25 @@ "node": ">=12" } }, + "node_modules/ast-v8-to-istanbul": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-1.0.4.tgz", + "integrity": "sha512-0bC0/4bTSrnwdhU3IsZDwEdojvuPrSg59OYZfKsLRtJZ0u8VBx9DebfqqG8bRdCC0I7vjgxmPi41P0lpkhJHtA==", + "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/async": { "version": "3.2.6", "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", @@ -5951,6 +6013,13 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" } }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true, + "license": "MIT" + }, "node_modules/http-cache-semantics": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", @@ -6153,6 +6222,45 @@ "node": ">=18" } }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-reports": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", + "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/jake": { "version": "10.9.4", "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.4.tgz", @@ -7180,6 +7288,34 @@ "@jridgewell/sourcemap-codec": "^1.5.5" } }, + "node_modules/magicast": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.5.3.tgz", + "integrity": "sha512-pVKE4UdSQ7DvHzivsCIFx2BJn1mHG6KsyrFcaxFx6tONdneEuThrDx0Cj3AMg58KyN4pzYT+LHOotxDQDjNvkw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.3", + "@babel/types": "^7.29.0", + "source-map-js": "^1.2.1" + } + }, + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/matcher": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/matcher/-/matcher-3.0.0.tgz", @@ -9276,19 +9412,20 @@ "peer": true }, "node_modules/vitest": { - "version": "4.1.8", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.8.tgz", - "integrity": "sha512-flY6ScbCIt9HThs+C5HS7jvGOB560DJtk/Z15IQROTA6zEy49Nh8T/dofWTQL+n3vswqn87sbJNiuqw1SDp5Ig==", + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.9.tgz", + "integrity": "sha512-nE3/LEyc0z87uHYLZebqCUOaJr2hdtuPp7BQ4BosVFnfltxgAvMG08NyrSGlPpOUWvR27c5flSmYFTNr78L9GQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { - "@vitest/expect": "4.1.8", - "@vitest/mocker": "4.1.8", - "@vitest/pretty-format": "4.1.8", - "@vitest/runner": "4.1.8", - "@vitest/snapshot": "4.1.8", - "@vitest/spy": "4.1.8", - "@vitest/utils": "4.1.8", + "@vitest/expect": "4.1.9", + "@vitest/mocker": "4.1.9", + "@vitest/pretty-format": "4.1.9", + "@vitest/runner": "4.1.9", + "@vitest/snapshot": "4.1.9", + "@vitest/spy": "4.1.9", + "@vitest/utils": "4.1.9", "es-module-lexer": "^2.0.0", "expect-type": "^1.3.0", "magic-string": "^0.30.21", @@ -9316,12 +9453,12 @@ "@edge-runtime/vm": "*", "@opentelemetry/api": "^1.9.0", "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", - "@vitest/browser-playwright": "4.1.8", - "@vitest/browser-preview": "4.1.8", - "@vitest/browser-webdriverio": "4.1.8", - "@vitest/coverage-istanbul": "4.1.8", - "@vitest/coverage-v8": "4.1.8", - "@vitest/ui": "4.1.8", + "@vitest/browser-playwright": "4.1.9", + "@vitest/browser-preview": "4.1.9", + "@vitest/browser-webdriverio": "4.1.9", + "@vitest/coverage-istanbul": "4.1.9", + "@vitest/coverage-v8": "4.1.9", + "@vitest/ui": "4.1.9", "happy-dom": "*", "jsdom": "*", "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" diff --git a/package.json b/package.json index 6333e0b..45758ea 100644 --- a/package.json +++ b/package.json @@ -102,6 +102,7 @@ "@types/react": "^19.2.14", "@types/react-dom": "^19.2.3", "@vitejs/plugin-react": "^6.0.1", + "@vitest/coverage-v8": "^4.1.9", "electron": "^42.3.0", "electron-builder": "^26.8.1", "esbuild": "^0.28.0", From e28566e9cb989a4c0eb49a6896c39782d01e1305 Mon Sep 17 00:00:00 2001 From: "coderabbitai[bot]" <136622811+coderabbitai[bot]@users.noreply.github.com> Date: Sun, 21 Jun 2026 04:14:46 +0000 Subject: [PATCH 03/10] fix: apply CodeRabbit auto-fixes Fixed 5 file(s) based on 7 unresolved review comments. Co-authored-by: CodeRabbit --- CONTRIBUTING.md | 2 +- electron/main.ts | 27 +++++++------ package-lock.json | 77 +++++++++++++++++++++++------------- src/lib/editor/extensions.ts | 61 +++++++++++++++------------- src/main.tsx | 3 +- 5 files changed, 100 insertions(+), 70 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c8c685c..47d3333 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -23,7 +23,7 @@ First of all, thank you for considering contributing to PaperCache! ## Development Guidelines - **Pull Requests Required**: Never push new features directly to the `main` branch. Always create a new branch and push your changes as a Pull Request (PR) for review. -- **Pre-PR Checks**: Run `npm run lint` and `npm run test` before opening any PR — don't open a PR with failing checks. +- **Pre-PR Checks**: Run `npm run lint`, `npm run test`, `npm run typecheck`, and `npm run format:check` before opening any PR — don't open a PR with failing checks. - **Performance Reporting**: Performance changes require a before/after bundle size comparison in the PR description (just paste the Vite build output). Thank you for your contributions! diff --git a/electron/main.ts b/electron/main.ts index 0d6f379..43e750f 100644 --- a/electron/main.ts +++ b/electron/main.ts @@ -356,18 +356,18 @@ app.on('web-contents-created', (event, contents) => { app.whenReady().then(() => { // Content Security Policy - const isDev = !!process.env.VITE_DEV_SERVER_URL; + const isDev = !!process.env.VITE_DEV_SERVER_URL session.defaultSession.webRequest.onHeadersReceived((details, callback) => { callback({ responseHeaders: { ...details.responseHeaders, // unsafe-eval is required for mathjs dynamic compilation 'Content-Security-Policy': [ - isDev + isDev ? "default-src 'none'; script-src 'self' 'unsafe-eval' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; connect-src 'self' https: wss:; font-src 'self' data: https:; object-src 'none'; base-uri 'none';" - : "default-src 'none'; script-src 'self' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; connect-src 'self' https:; font-src 'self' data: https:; object-src 'none'; base-uri 'none';" - ] - } + : "default-src 'none'; script-src 'self' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; connect-src 'self' https:; font-src 'self' data: https:; object-src 'none'; base-uri 'none';", + ], + }, }) }) @@ -651,18 +651,19 @@ try { } else { memoryApiKey = file } -} catch (e) {} +} catch {} ipcMain.handle('set-api-key', (_, key: string) => { - memoryApiKey = key; + memoryApiKey = key try { - const dataToSave = safeStorage.isEncryptionAvailable() - ? safeStorage.encryptString(key).toString('base64') - : key; - fs.writeFileSync(path.join(NOTES_DIR, 'config.enc'), dataToSave); - return true; + const dataToSave = safeStorage.isEncryptionAvailable() + ? safeStorage.encryptString(key).toString('base64') + : key + fs.writeFileSync(path.join(NOTES_DIR, 'config.enc'), dataToSave) + return true } catch (e) { - return false; + console.error('Failed to save API key:', e) + return false } }) diff --git a/package-lock.json b/package-lock.json index 5521964..be725fc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -147,7 +147,6 @@ "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/code-frame": "^7.29.7", "@babel/generator": "^7.29.7", @@ -555,7 +554,6 @@ "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.43.0.tgz", "integrity": "sha512-V7ZCLQO3Jus9hzh2jVCCPW3mO4IBMr43O37PqSUYautJSnnJF41YlgLw21x0fLJTYvJ+Vkm6Gp+qKGH9pltgXA==", "license": "MIT", - "peer": true, "dependencies": { "@codemirror/state": "^6.6.0", "crelt": "^1.0.6", @@ -651,7 +649,6 @@ } ], "license": "MIT", - "peer": true, "engines": { "node": ">=20.19.0" }, @@ -700,7 +697,6 @@ } ], "license": "MIT", - "peer": true, "engines": { "node": ">=20.19.0" } @@ -977,6 +973,7 @@ "dev": true, "license": "BSD-2-Clause", "optional": true, + "peer": true, "dependencies": { "cross-dirname": "^0.1.0", "debug": "^4.3.4", @@ -998,6 +995,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", @@ -1007,6 +1005,31 @@ "node": ">=14.14" } }, + "node_modules/@emnapi/core": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.1.tgz", + "integrity": "sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.2", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.1.tgz", + "integrity": "sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@emnapi/wasi-threads": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.2.tgz", @@ -1014,6 +1037,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "tslib": "^2.4.0" } @@ -2499,7 +2523,8 @@ "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/@types/cacheable-request": { "version": "6.0.3", @@ -2680,7 +2705,6 @@ "integrity": "sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==", "devOptional": true, "license": "MIT", - "peer": true, "dependencies": { "csstype": "^3.2.2" } @@ -2691,7 +2715,6 @@ "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", "dev": true, "license": "MIT", - "peer": true, "peerDependencies": { "@types/react": "^19.2.0" } @@ -2775,7 +2798,6 @@ "integrity": "sha512-5B7PfA2e1NQGCnDHd/0lW7W3gvp3d59Ryw54FYO8Uswxo9f6ikw3AZV+Xj/TvpImmpsiYyUqAfhC6kJID1jF6w==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.61.0", "@typescript-eslint/types": "8.61.0", @@ -3046,7 +3068,6 @@ "integrity": "sha512-G9/lgqibheLVBDRuya45EbsEXTYcWoSG+TLg7i2axuzx0Eq62eXn+aWXyaVdV5vKvFSWd6ywcX8hA7la9Pvu8g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@bcoe/v8-coverage": "^1.0.2", "@vitest/utils": "4.1.9", @@ -3220,7 +3241,6 @@ "integrity": "sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==", "dev": true, "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -3684,7 +3704,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "baseline-browser-mapping": "^2.10.12", "caniuse-lite": "^1.0.30001782", @@ -4112,7 +4131,8 @@ "integrity": "sha512-+R08/oI0nl3vfPcqftZRpytksBXDzOUveBq/NBVx0sUp1axwzPQrKinNx5yd5sxPu8j1wIy8AfnVQ+5eFdha6Q==", "dev": true, "license": "MIT", - "optional": true + "optional": true, + "peer": true }, "node_modules/cross-spawn": { "version": "7.0.6", @@ -4324,7 +4344,6 @@ "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", "license": "ISC", - "peer": true, "engines": { "node": ">=12" } @@ -4604,7 +4623,6 @@ "integrity": "sha512-O3zJUFUYHJKgzPqioHxfxzBzlSC1eXCSr79gMSBKBP5AgjjpmrydMsMLotEg9fAJF36vdUncb+4ndRNxoPdlSQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "app-builder-lib": "26.15.3", "builder-util": "26.15.3", @@ -4617,7 +4635,8 @@ "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/dotenv": { "version": "16.6.1", @@ -4807,6 +4826,7 @@ "dev": true, "hasInstallScript": true, "license": "MIT", + "peer": true, "dependencies": { "@electron/asar": "^3.2.1", "debug": "^4.1.1", @@ -4827,6 +4847,7 @@ "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "graceful-fs": "^4.1.2", "jsonfile": "^4.0.0", @@ -4842,6 +4863,7 @@ "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", "dev": true, "license": "MIT", + "peer": true, "optionalDependencies": { "graceful-fs": "^4.1.6" } @@ -4852,6 +4874,7 @@ "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">= 4.0.0" } @@ -4990,7 +5013,6 @@ "dev": true, "hasInstallScript": true, "license": "MIT", - "peer": true, "bin": { "esbuild": "bin/esbuild" }, @@ -5061,7 +5083,6 @@ "integrity": "sha512-1y+7C+vi12bUK1IpZeaV3gsH9fHLBmPvYmPx42pvT/E9yG0IC8g3PUZZgp0+JLJl7ZDK0flc2gc+Aw9dpCvIsQ==", "dev": true, "license": "MIT", - "peer": true, "workspaces": [ "packages/*" ], @@ -5121,7 +5142,6 @@ "integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==", "dev": true, "license": "MIT", - "peer": true, "bin": { "eslint-config-prettier": "bin/cli.js" }, @@ -7274,6 +7294,7 @@ "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", "dev": true, "license": "MIT", + "peer": true, "bin": { "lz-string": "bin/bin.js" } @@ -7494,6 +7515,7 @@ "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "minimist": "^1.2.6" }, @@ -7981,6 +8003,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "commander": "^9.4.0" }, @@ -7998,6 +8021,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "engines": { "node": "^12.20.0 || >=14" } @@ -8028,7 +8052,6 @@ "integrity": "sha512-N2MylSdi48+5N/6S5j+maeHbUSIzzZ5uOcX5Hm4QpV8Dkb1HFjfAKTKX6yNPJQD9AhcT3ifHNB66tWTTJDi11Q==", "dev": true, "license": "MIT", - "peer": true, "bin": { "prettier": "bin/prettier.cjs" }, @@ -8058,6 +8081,7 @@ "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "ansi-regex": "^5.0.1", "ansi-styles": "^5.0.0", @@ -8073,6 +8097,7 @@ "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=10" }, @@ -8085,7 +8110,8 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/proc-log": { "version": "6.1.0", @@ -8210,7 +8236,6 @@ "resolved": "https://registry.npmjs.org/react/-/react-19.2.6.tgz", "integrity": "sha512-sfWGGfavi0xr8Pg0sVsyHMAOziVYKgPLNrS7ig+ivMNb3wbCBw3KxtflsGBAwD3gYQlE/AEZsTLgToRrSCjb0Q==", "license": "MIT", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -8220,7 +8245,6 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.6.tgz", "integrity": "sha512-0prMI+hvBbPjsWnxDLxlCGyM8PN6UuWjEUCYmZhO67xIV9Xasa/r/vDnq+Xyq4Lo27g8QSbO5YzARu0D1Sps3g==", "license": "MIT", - "peer": true, "dependencies": { "scheduler": "^0.27.0" }, @@ -8437,6 +8461,7 @@ "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, "license": "ISC", + "peer": true, "dependencies": { "glob": "^7.1.3" }, @@ -8927,6 +8952,7 @@ "integrity": "sha512-yYrrsWnrXMcdsnu/7YMYAofM1ktpL5By7vZhf15CrXijWWrEYZks5AXBudalfSWJLlnen/QUJUB5aoB0kqZUGA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "mkdirp": "^0.5.1", "rimraf": "~2.6.2" @@ -9166,7 +9192,6 @@ "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", "dev": true, "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -9315,7 +9340,6 @@ "integrity": "sha512-h9bXPmJichP5fLmVQo3PyaGSDE2n3aPuomeAlVRm0JLmt4rY6zmPKd59HYI4LNW8oTK7tlTsuC7l/m7awx9Jcw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "lightningcss": "^1.32.0", "picomatch": "^4.0.4", @@ -9408,8 +9432,7 @@ "resolved": "https://registry.npmjs.org/vite-plugin-electron-renderer/-/vite-plugin-electron-renderer-0.14.7.tgz", "integrity": "sha512-hHBMKuZ24MB2SIxG7U7ix+DDEnvxou7Bgy/TdhYxNz3S5N3Yh7Hjvj9blfMeGEJ0oaZJn7y5z0V/RyDmJ5OuCA==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/vitest": { "version": "4.1.9", @@ -9417,7 +9440,6 @@ "integrity": "sha512-nE3/LEyc0z87uHYLZebqCUOaJr2hdtuPp7BQ4BosVFnfltxgAvMG08NyrSGlPpOUWvR27c5flSmYFTNr78L9GQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@vitest/expect": "4.1.9", "@vitest/mocker": "4.1.9", @@ -9747,7 +9769,6 @@ "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==", "devOptional": true, "license": "MIT", - "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/src/lib/editor/extensions.ts b/src/lib/editor/extensions.ts index 7cf60a8..9e783b5 100644 --- a/src/lib/editor/extensions.ts +++ b/src/lib/editor/extensions.ts @@ -118,17 +118,20 @@ export function useEditorExtensions(handleEditorChange: (val: string) => void) { const prompt = lineText.substring(prefixLength).trim() const thinkingText = '\n\u200B...\u200C\n' - view.dispatch({ changes: { from: line.to, insert: thinkingText } }) + const markerStart = line.to + const markerEnd = markerStart + thinkingText.length + view.dispatch({ changes: { from: markerStart, insert: thinkingText } }) ;(async () => { try { const isKeySet = await window.electronAPI.getApiKeyStatus() if (!isKeySet) { - const docStr = view.state.doc.toString() - const errorVal = docStr.replace( - '\n\u200B...\u200C\n', - '\n\u200BError - Set your OpenAI API key in settings\u200C\n' - ) - handleEditorChange(errorVal) + view.dispatch({ + changes: { + from: markerStart, + to: markerEnd, + insert: '\n\u200BError - Set your OpenAI API key in settings\u200C\n', + }, + }) return } @@ -179,30 +182,34 @@ export function useEditorExtensions(handleEditorChange: (val: string) => void) { ) } - const docStr = view.state.doc.toString() - const finalVal = docStr.replace( - '\n\u200B...\u200C\n', - '\n\u200B' + response + '\u200C\n' - ) - handleEditorChange(finalVal) + view.dispatch({ + changes: { + from: markerStart, + to: markerEnd, + insert: '\n\u200B' + response + '\u200C\n', + }, + }) }) .catch((error) => { - const docStr = view.state.doc.toString() - const errorVal = docStr.replace( - '\n\u200B...\u200C\n', - '\n\u200BError - ' + error.message + '\u200C\n' - ) - handleEditorChange(errorVal) + view.dispatch({ + changes: { + from: markerStart, + to: markerEnd, + insert: '\n\u200BError - ' + error.message + '\u200C\n', + }, + }) }) } catch (err: unknown) { - const docStr = view.state.doc.toString() - const errorVal = docStr.replace( - '\n\u200B...\u200C\n', - '\n\u200BSetup Error - ' + - ((err as Error).message || String(err)) + - '\u200C\n' - ) - handleEditorChange(errorVal) + view.dispatch({ + changes: { + from: markerStart, + to: markerEnd, + insert: + '\n\u200BSetup Error - ' + + ((err as Error).message || String(err)) + + '\u200C\n', + }, + }) } })() diff --git a/src/main.tsx b/src/main.tsx index 420ed0a..16e9952 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -36,7 +36,8 @@ function Root() { try { // Decrypt it using the old method, then send to new IPC const decrypted = await window.electronAPI.safeStorageDecrypt(secureEncrypted) - if (decrypted) { + // Validate that the decrypted value looks like a valid API key + if (decrypted && decrypted.startsWith('sk-ant-') && decrypted.length >= 20) { const success = await window.electronAPI.setApiKey(decrypted) if (success) { localStorage.removeItem('papercache-apikey-secure') From 20cf69f10e1c56b9e171c2d19bc3c71e81c1471e Mon Sep 17 00:00:00 2001 From: Aditya Date: Sun, 21 Jun 2026 09:54:08 +0530 Subject: [PATCH 04/10] chore: address PR review feedback and fix dev build --- .github/workflows/ci.yml | 6 +- CONTRIBUTING.md | 2 +- SECURITY.md | 2 +- coverage/base.css | 224 ++++ coverage/block-navigation.js | 87 ++ coverage/clover.xml | 435 +++++++ coverage/coverage-final.json | 12 + coverage/favicon.png | Bin 0 -> 445 bytes coverage/index.html | 176 +++ coverage/prettify.css | 1 + coverage/prettify.js | 2 + coverage/sort-arrow-sprite.png | Bin 0 -> 138 bytes coverage/sorter.js | 210 ++++ coverage/src/Settings.css.html | 574 +++++++++ coverage/src/Settings.tsx.html | 1087 +++++++++++++++++ coverage/src/hooks/index.html | 131 ++ coverage/src/hooks/useReminders.ts.html | 409 +++++++ coverage/src/hooks/useVariables.ts.html | 205 ++++ coverage/src/index.html | 146 +++ coverage/src/lib/editor/MathEvaluator.ts.html | 334 +++++ coverage/src/lib/editor/VariableScope.ts.html | 277 +++++ coverage/src/lib/editor/index.html | 146 +++ coverage/src/lib/editor/widgets.ts.html | 736 +++++++++++ coverage/src/lib/index.html | 131 ++ coverage/src/lib/safeStorage.ts.html | 139 +++ coverage/src/lib/settingsKeys.ts.html | 145 +++ coverage/src/store/index.html | 116 ++ coverage/src/store/useAppStore.ts.html | 403 ++++++ coverage/src/utils.ts.html | 205 ++++ electron/main.ts | 43 +- src/App.tsx | 6 +- src/Settings.test.tsx | 31 +- src/Settings.tsx | 12 +- src/components/Editor.tsx | 39 +- src/components/ErrorBoundary.tsx | 2 +- src/lib/editor/MathEvaluator.ts | 3 + src/lib/editor/extensions.ts | 85 +- src/main.tsx | 5 +- src/setupTests.ts | 1 + vite.config.ts | 7 + 40 files changed, 6472 insertions(+), 103 deletions(-) create mode 100644 coverage/base.css create mode 100644 coverage/block-navigation.js create mode 100644 coverage/clover.xml create mode 100644 coverage/coverage-final.json create mode 100644 coverage/favicon.png create mode 100644 coverage/index.html create mode 100644 coverage/prettify.css create mode 100644 coverage/prettify.js create mode 100644 coverage/sort-arrow-sprite.png create mode 100644 coverage/sorter.js create mode 100644 coverage/src/Settings.css.html create mode 100644 coverage/src/Settings.tsx.html create mode 100644 coverage/src/hooks/index.html create mode 100644 coverage/src/hooks/useReminders.ts.html create mode 100644 coverage/src/hooks/useVariables.ts.html create mode 100644 coverage/src/index.html create mode 100644 coverage/src/lib/editor/MathEvaluator.ts.html create mode 100644 coverage/src/lib/editor/VariableScope.ts.html create mode 100644 coverage/src/lib/editor/index.html create mode 100644 coverage/src/lib/editor/widgets.ts.html create mode 100644 coverage/src/lib/index.html create mode 100644 coverage/src/lib/safeStorage.ts.html create mode 100644 coverage/src/lib/settingsKeys.ts.html create mode 100644 coverage/src/store/index.html create mode 100644 coverage/src/store/useAppStore.ts.html create mode 100644 coverage/src/utils.ts.html diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f4b6366..649de04 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,8 +11,10 @@ jobs: os: [macos-latest, ubuntu-latest, windows-latest] runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + with: + persist-credentials: false + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 with: node-version: '22' - run: npm ci diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 47d3333..b744425 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -23,7 +23,7 @@ First of all, thank you for considering contributing to PaperCache! ## Development Guidelines - **Pull Requests Required**: Never push new features directly to the `main` branch. Always create a new branch and push your changes as a Pull Request (PR) for review. -- **Pre-PR Checks**: Run `npm run lint`, `npm run test`, `npm run typecheck`, and `npm run format:check` before opening any PR — don't open a PR with failing checks. +- **Pre-PR Checks**: Run `npm run lint`, `npm run typecheck`, `npm run format:check`, and `npm run test` before opening any PR — don't open a PR with failing checks. - **Performance Reporting**: Performance changes require a before/after bundle size comparison in the PR description (just paste the Vite build output). Thank you for your contributions! diff --git a/SECURITY.md b/SECURITY.md index 0a97d23..67dce15 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -8,7 +8,7 @@ Currently, only the latest version of PaperCache receives security updates. Plea We take the security of PaperCache seriously. If you discover a security vulnerability, we would appreciate it if you could report it privately so it can be addressed before being disclosed publicly. -Please report any security issues to: **adityasharma.variable@gmail.com** +Please report any security issues to: **security@papercache.app** When reporting, please include: - A description of the vulnerability. diff --git a/coverage/base.css b/coverage/base.css new file mode 100644 index 0000000..f418035 --- /dev/null +++ b/coverage/base.css @@ -0,0 +1,224 @@ +body, html { + margin:0; padding: 0; + height: 100%; +} +body { + font-family: Helvetica Neue, Helvetica, Arial; + font-size: 14px; + color:#333; +} +.small { font-size: 12px; } +*, *:after, *:before { + -webkit-box-sizing:border-box; + -moz-box-sizing:border-box; + box-sizing:border-box; + } +h1 { font-size: 20px; margin: 0;} +h2 { font-size: 14px; } +pre { + font: 12px/1.4 Consolas, "Liberation Mono", Menlo, Courier, monospace; + margin: 0; + padding: 0; + -moz-tab-size: 2; + -o-tab-size: 2; + tab-size: 2; +} +a { color:#0074D9; text-decoration:none; } +a:hover { text-decoration:underline; } +.strong { font-weight: bold; } +.space-top1 { padding: 10px 0 0 0; } +.pad2y { padding: 20px 0; } +.pad1y { padding: 10px 0; } +.pad2x { padding: 0 20px; } +.pad2 { padding: 20px; } +.pad1 { padding: 10px; } +.space-left2 { padding-left:55px; } +.space-right2 { padding-right:20px; } +.center { text-align:center; } +.clearfix { display:block; } +.clearfix:after { + content:''; + display:block; + height:0; + clear:both; + visibility:hidden; + } +.fl { float: left; } +@media only screen and (max-width:640px) { + .col3 { width:100%; max-width:100%; } + .hide-mobile { display:none!important; } +} + +.quiet { + color: #7f7f7f; + color: rgba(0,0,0,0.5); +} +.quiet a { opacity: 0.7; } + +.fraction { + font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; + font-size: 10px; + color: #555; + background: #E8E8E8; + padding: 4px 5px; + border-radius: 3px; + vertical-align: middle; +} + +div.path a:link, div.path a:visited { color: #333; } +table.coverage { + border-collapse: collapse; + margin: 10px 0 0 0; + padding: 0; +} + +table.coverage td { + margin: 0; + padding: 0; + vertical-align: top; +} +table.coverage td.line-count { + text-align: right; + padding: 0 5px 0 20px; +} +table.coverage td.line-coverage { + text-align: right; + padding-right: 10px; + min-width:20px; +} + +table.coverage td span.cline-any { + display: inline-block; + padding: 0 5px; + width: 100%; +} +.missing-if-branch { + display: inline-block; + margin-right: 5px; + border-radius: 3px; + position: relative; + padding: 0 4px; + background: #333; + color: yellow; +} + +.skip-if-branch { + display: none; + margin-right: 10px; + position: relative; + padding: 0 4px; + background: #ccc; + color: white; +} +.missing-if-branch .typ, .skip-if-branch .typ { + color: inherit !important; +} +.coverage-summary { + border-collapse: collapse; + width: 100%; +} +.coverage-summary tr { border-bottom: 1px solid #bbb; } +.keyline-all { border: 1px solid #ddd; } +.coverage-summary td, .coverage-summary th { padding: 10px; } +.coverage-summary tbody { border: 1px solid #bbb; } +.coverage-summary td { border-right: 1px solid #bbb; } +.coverage-summary td:last-child { border-right: none; } +.coverage-summary th { + text-align: left; + font-weight: normal; + white-space: nowrap; +} +.coverage-summary th.file { border-right: none !important; } +.coverage-summary th.pct { } +.coverage-summary th.pic, +.coverage-summary th.abs, +.coverage-summary td.pct, +.coverage-summary td.abs { text-align: right; } +.coverage-summary td.file { white-space: nowrap; } +.coverage-summary td.pic { min-width: 120px !important; } +.coverage-summary tfoot td { } + +.coverage-summary .sorter { + height: 10px; + width: 7px; + display: inline-block; + margin-left: 0.5em; + background: url(sort-arrow-sprite.png) no-repeat scroll 0 0 transparent; +} +.coverage-summary .sorted .sorter { + background-position: 0 -20px; +} +.coverage-summary .sorted-desc .sorter { + background-position: 0 -10px; +} +.status-line { height: 10px; } +/* yellow */ +.cbranch-no { background: yellow !important; color: #111; } +/* dark red */ +.red.solid, .status-line.low, .low .cover-fill { background:#C21F39 } +.low .chart { border:1px solid #C21F39 } +.highlighted, +.highlighted .cstat-no, .highlighted .fstat-no, .highlighted .cbranch-no{ + background: #C21F39 !important; +} +/* medium red */ +.cstat-no, .fstat-no, .cbranch-no, .cbranch-no { background:#F6C6CE } +/* light red */ +.low, .cline-no { background:#FCE1E5 } +/* light green */ +.high, .cline-yes { background:rgb(230,245,208) } +/* medium green */ +.cstat-yes { background:rgb(161,215,106) } +/* dark green */ +.status-line.high, .high .cover-fill { background:rgb(77,146,33) } +.high .chart { border:1px solid rgb(77,146,33) } +/* dark yellow (gold) */ +.status-line.medium, .medium .cover-fill { background: #f9cd0b; } +.medium .chart { border:1px solid #f9cd0b; } +/* light yellow */ +.medium { background: #fff4c2; } + +.cstat-skip { background: #ddd; color: #111; } +.fstat-skip { background: #ddd; color: #111 !important; } +.cbranch-skip { background: #ddd !important; color: #111; } + +span.cline-neutral { background: #eaeaea; } + +.coverage-summary td.empty { + opacity: .5; + padding-top: 4px; + padding-bottom: 4px; + line-height: 1; + color: #888; +} + +.cover-fill, .cover-empty { + display:inline-block; + height: 12px; +} +.chart { + line-height: 0; +} +.cover-empty { + background: white; +} +.cover-full { + border-right: none !important; +} +pre.prettyprint { + border: none !important; + padding: 0 !important; + margin: 0 !important; +} +.com { color: #999 !important; } +.ignore-none { color: #999; font-weight: normal; } + +.wrapper { + min-height: 100%; + height: auto !important; + height: 100%; + margin: 0 auto -48px; +} +.footer, .push { + height: 48px; +} diff --git a/coverage/block-navigation.js b/coverage/block-navigation.js new file mode 100644 index 0000000..530d1ed --- /dev/null +++ b/coverage/block-navigation.js @@ -0,0 +1,87 @@ +/* eslint-disable */ +var jumpToCode = (function init() { + // Classes of code we would like to highlight in the file view + var missingCoverageClasses = ['.cbranch-no', '.cstat-no', '.fstat-no']; + + // Elements to highlight in the file listing view + var fileListingElements = ['td.pct.low']; + + // We don't want to select elements that are direct descendants of another match + var notSelector = ':not(' + missingCoverageClasses.join('):not(') + ') > '; // becomes `:not(a):not(b) > ` + + // Selector that finds elements on the page to which we can jump + var selector = + fileListingElements.join(', ') + + ', ' + + notSelector + + missingCoverageClasses.join(', ' + notSelector); // becomes `:not(a):not(b) > a, :not(a):not(b) > b` + + // The NodeList of matching elements + var missingCoverageElements = document.querySelectorAll(selector); + + var currentIndex; + + function toggleClass(index) { + missingCoverageElements + .item(currentIndex) + .classList.remove('highlighted'); + missingCoverageElements.item(index).classList.add('highlighted'); + } + + function makeCurrent(index) { + toggleClass(index); + currentIndex = index; + missingCoverageElements.item(index).scrollIntoView({ + behavior: 'smooth', + block: 'center', + inline: 'center' + }); + } + + function goToPrevious() { + var nextIndex = 0; + if (typeof currentIndex !== 'number' || currentIndex === 0) { + nextIndex = missingCoverageElements.length - 1; + } else if (missingCoverageElements.length > 1) { + nextIndex = currentIndex - 1; + } + + makeCurrent(nextIndex); + } + + function goToNext() { + var nextIndex = 0; + + if ( + typeof currentIndex === 'number' && + currentIndex < missingCoverageElements.length - 1 + ) { + nextIndex = currentIndex + 1; + } + + makeCurrent(nextIndex); + } + + return function jump(event) { + if ( + document.getElementById('fileSearch') === document.activeElement && + document.activeElement != null + ) { + // if we're currently focused on the search input, we don't want to navigate + return; + } + + switch (event.which) { + case 78: // n + case 74: // j + goToNext(); + break; + case 66: // b + case 75: // k + case 80: // p + goToPrevious(); + break; + } + }; +})(); +window.addEventListener('keydown', jumpToCode); diff --git a/coverage/clover.xml b/coverage/clover.xml new file mode 100644 index 0000000..cf25077 --- /dev/null +++ b/coverage/clover.xml @@ -0,0 +1,435 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/coverage/coverage-final.json b/coverage/coverage-final.json new file mode 100644 index 0000000..40e4a34 --- /dev/null +++ b/coverage/coverage-final.json @@ -0,0 +1,12 @@ +{"/Users/aditya/Projects/PaperCache/src/Settings.css": {"path":"/Users/aditya/Projects/PaperCache/src/Settings.css","statementMap":{},"fnMap":{},"branchMap":{},"s":{},"f":{},"b":{},"meta":{"lastBranch":0,"lastFunction":0,"lastStatement":0,"seen":{},"fnNames":{}}} +,"/Users/aditya/Projects/PaperCache/src/Settings.tsx": {"path":"/Users/aditya/Projects/PaperCache/src/Settings.tsx","statementMap":{"0":{"start":{"line":6,"column":17},"end":{"line":6,"column":null}},"1":{"start":{"line":7,"column":22},"end":{"line":7,"column":null}},"2":{"start":{"line":9,"column":2},"end":{"line":21,"column":null}},"3":{"start":{"line":10,"column":4},"end":{"line":12,"column":null}},"4":{"start":{"line":11,"column":6},"end":{"line":11,"column":null}},"5":{"start":{"line":14,"column":10},"end":{"line":18,"column":null}},"6":{"start":{"line":15,"column":6},"end":{"line":17,"column":null}},"7":{"start":{"line":16,"column":8},"end":{"line":16,"column":null}},"8":{"start":{"line":19,"column":4},"end":{"line":19,"column":null}},"9":{"start":{"line":20,"column":4},"end":{"line":20,"column":null}},"10":{"start":{"line":20,"column":17},"end":{"line":20,"column":null}},"11":{"start":{"line":22,"column":21},"end":{"line":24,"column":null}},"12":{"start":{"line":25,"column":19},"end":{"line":27,"column":null}},"13":{"start":{"line":28,"column":25},"end":{"line":31,"column":null}},"14":{"start":{"line":34,"column":32},"end":{"line":36,"column":null}},"15":{"start":{"line":37,"column":31},"end":{"line":39,"column":null}},"16":{"start":{"line":42,"column":26},"end":{"line":44,"column":null}},"17":{"start":{"line":47,"column":21},"end":{"line":49,"column":null}},"18":{"start":{"line":50,"column":22},"end":{"line":52,"column":null}},"19":{"start":{"line":53,"column":22},"end":{"line":55,"column":null}},"20":{"start":{"line":56,"column":17},"end":{"line":56,"column":null}},"21":{"start":{"line":57,"column":18},"end":{"line":57,"column":null}},"22":{"start":{"line":58,"column":18},"end":{"line":58,"column":null}},"23":{"start":{"line":60,"column":20},"end":{"line":62,"column":null}},"24":{"start":{"line":63,"column":19},"end":{"line":65,"column":null}},"25":{"start":{"line":66,"column":19},"end":{"line":68,"column":null}},"26":{"start":{"line":69,"column":18},"end":{"line":69,"column":null}},"27":{"start":{"line":70,"column":20},"end":{"line":72,"column":null}},"28":{"start":{"line":74,"column":23},"end":{"line":120,"column":null}},"29":{"start":{"line":75,"column":4},"end":{"line":77,"column":null}},"30":{"start":{"line":76,"column":6},"end":{"line":76,"column":null}},"31":{"start":{"line":78,"column":4},"end":{"line":78,"column":null}},"32":{"start":{"line":79,"column":4},"end":{"line":79,"column":null}},"33":{"start":{"line":80,"column":4},"end":{"line":80,"column":null}},"34":{"start":{"line":82,"column":4},"end":{"line":82,"column":null}},"35":{"start":{"line":83,"column":4},"end":{"line":83,"column":null}},"36":{"start":{"line":84,"column":4},"end":{"line":84,"column":null}},"37":{"start":{"line":85,"column":4},"end":{"line":85,"column":null}},"38":{"start":{"line":86,"column":4},"end":{"line":86,"column":null}},"39":{"start":{"line":87,"column":4},"end":{"line":87,"column":null}},"40":{"start":{"line":89,"column":4},"end":{"line":89,"column":null}},"41":{"start":{"line":90,"column":4},"end":{"line":90,"column":null}},"42":{"start":{"line":91,"column":4},"end":{"line":91,"column":null}},"43":{"start":{"line":92,"column":4},"end":{"line":92,"column":null}},"44":{"start":{"line":93,"column":4},"end":{"line":93,"column":null}},"45":{"start":{"line":96,"column":4},"end":{"line":96,"column":null}},"46":{"start":{"line":97,"column":4},"end":{"line":99,"column":null}},"47":{"start":{"line":98,"column":6},"end":{"line":98,"column":null}},"48":{"start":{"line":103,"column":6},"end":{"line":103,"column":null}},"49":{"start":{"line":104,"column":4},"end":{"line":104,"column":null}},"50":{"start":{"line":105,"column":4},"end":{"line":107,"column":null}},"51":{"start":{"line":106,"column":6},"end":{"line":106,"column":null}},"52":{"start":{"line":110,"column":6},"end":{"line":110,"column":null}},"53":{"start":{"line":111,"column":4},"end":{"line":111,"column":null}},"54":{"start":{"line":112,"column":4},"end":{"line":114,"column":null}},"55":{"start":{"line":113,"column":6},"end":{"line":113,"column":null}},"56":{"start":{"line":117,"column":4},"end":{"line":117,"column":null}},"57":{"start":{"line":119,"column":4},"end":{"line":119,"column":null}},"58":{"start":{"line":122,"column":8},"end":{"line":124,"column":null}},"59":{"start":{"line":123,"column":4},"end":{"line":123,"column":null}},"60":{"start":{"line":126,"column":8},"end":{"line":128,"column":null}},"61":{"start":{"line":127,"column":4},"end":{"line":127,"column":null}},"62":{"start":{"line":130,"column":2},"end":{"line":332,"column":null}},"63":{"start":{"line":144,"column":31},"end":{"line":144,"column":null}},"64":{"start":{"line":154,"column":31},"end":{"line":154,"column":null}},"65":{"start":{"line":164,"column":31},"end":{"line":164,"column":null}},"66":{"start":{"line":173,"column":31},"end":{"line":173,"column":null}},"67":{"start":{"line":198,"column":31},"end":{"line":198,"column":null}},"68":{"start":{"line":207,"column":31},"end":{"line":207,"column":null}},"69":{"start":{"line":220,"column":31},"end":{"line":220,"column":null}},"70":{"start":{"line":230,"column":56},"end":{"line":230,"column":null}},"71":{"start":{"line":250,"column":31},"end":{"line":250,"column":null}},"72":{"start":{"line":257,"column":52},"end":{"line":257,"column":null}},"73":{"start":{"line":267,"column":59},"end":{"line":267,"column":null}},"74":{"start":{"line":278,"column":67},"end":{"line":278,"column":96}},"75":{"start":{"line":288,"column":33},"end":{"line":288,"column":null}},"76":{"start":{"line":296,"column":67},"end":{"line":296,"column":98}},"77":{"start":{"line":301,"column":66},"end":{"line":301,"column":96}},"78":{"start":{"line":306,"column":66},"end":{"line":306,"column":96}},"79":{"start":{"line":311,"column":67},"end":{"line":311,"column":98}},"80":{"start":{"line":316,"column":65},"end":{"line":316,"column":94}}},"fnMap":{"0":{"name":"Settings","decl":{"start":{"line":5,"column":24},"end":{"line":5,"column":35}},"loc":{"start":{"line":5,"column":35},"end":{"line":334,"column":null}},"line":5},"1":{"name":"(anonymous_1)","decl":{"start":{"line":9,"column":2},"end":{"line":9,"column":18}},"loc":{"start":{"line":9,"column":18},"end":{"line":21,"column":5}},"line":9},"2":{"name":"(anonymous_2)","decl":{"start":{"line":10,"column":41},"end":{"line":10,"column":47}},"loc":{"start":{"line":10,"column":58},"end":{"line":12,"column":5}},"line":10},"3":{"name":"(anonymous_3)","decl":{"start":{"line":14,"column":10},"end":{"line":14,"column":27}},"loc":{"start":{"line":14,"column":48},"end":{"line":18,"column":null}},"line":14},"4":{"name":"(anonymous_4)","decl":{"start":{"line":20,"column":4},"end":{"line":20,"column":17}},"loc":{"start":{"line":20,"column":17},"end":{"line":20,"column":null}},"line":20},"5":{"name":"(anonymous_5)","decl":{"start":{"line":74,"column":23},"end":{"line":74,"column":35}},"loc":{"start":{"line":74,"column":35},"end":{"line":120,"column":null}},"line":74},"6":{"name":"(anonymous_6)","decl":{"start":{"line":122,"column":8},"end":{"line":122,"column":30}},"loc":{"start":{"line":122,"column":30},"end":{"line":124,"column":null}},"line":122},"7":{"name":"(anonymous_7)","decl":{"start":{"line":126,"column":8},"end":{"line":126,"column":24}},"loc":{"start":{"line":126,"column":24},"end":{"line":128,"column":null}},"line":126},"8":{"name":"(anonymous_8)","decl":{"start":{"line":144,"column":14},"end":{"line":144,"column":25}},"loc":{"start":{"line":144,"column":31},"end":{"line":144,"column":null}},"line":144},"9":{"name":"(anonymous_9)","decl":{"start":{"line":154,"column":14},"end":{"line":154,"column":25}},"loc":{"start":{"line":154,"column":31},"end":{"line":154,"column":null}},"line":154},"10":{"name":"(anonymous_10)","decl":{"start":{"line":164,"column":14},"end":{"line":164,"column":25}},"loc":{"start":{"line":164,"column":31},"end":{"line":164,"column":null}},"line":164},"11":{"name":"(anonymous_11)","decl":{"start":{"line":173,"column":14},"end":{"line":173,"column":25}},"loc":{"start":{"line":173,"column":31},"end":{"line":173,"column":null}},"line":173},"12":{"name":"(anonymous_12)","decl":{"start":{"line":198,"column":14},"end":{"line":198,"column":25}},"loc":{"start":{"line":198,"column":31},"end":{"line":198,"column":null}},"line":198},"13":{"name":"(anonymous_13)","decl":{"start":{"line":207,"column":14},"end":{"line":207,"column":25}},"loc":{"start":{"line":207,"column":31},"end":{"line":207,"column":null}},"line":207},"14":{"name":"(anonymous_14)","decl":{"start":{"line":220,"column":14},"end":{"line":220,"column":25}},"loc":{"start":{"line":220,"column":31},"end":{"line":220,"column":null}},"line":220},"15":{"name":"(anonymous_15)","decl":{"start":{"line":230,"column":39},"end":{"line":230,"column":50}},"loc":{"start":{"line":230,"column":56},"end":{"line":230,"column":null}},"line":230},"16":{"name":"(anonymous_16)","decl":{"start":{"line":250,"column":14},"end":{"line":250,"column":25}},"loc":{"start":{"line":250,"column":31},"end":{"line":250,"column":null}},"line":250},"17":{"name":"(anonymous_17)","decl":{"start":{"line":257,"column":35},"end":{"line":257,"column":46}},"loc":{"start":{"line":257,"column":52},"end":{"line":257,"column":null}},"line":257},"18":{"name":"(anonymous_18)","decl":{"start":{"line":267,"column":42},"end":{"line":267,"column":53}},"loc":{"start":{"line":267,"column":59},"end":{"line":267,"column":null}},"line":267},"19":{"name":"(anonymous_19)","decl":{"start":{"line":278,"column":50},"end":{"line":278,"column":61}},"loc":{"start":{"line":278,"column":67},"end":{"line":278,"column":96}},"line":278},"20":{"name":"(anonymous_20)","decl":{"start":{"line":288,"column":16},"end":{"line":288,"column":27}},"loc":{"start":{"line":288,"column":33},"end":{"line":288,"column":null}},"line":288},"21":{"name":"(anonymous_21)","decl":{"start":{"line":296,"column":50},"end":{"line":296,"column":61}},"loc":{"start":{"line":296,"column":67},"end":{"line":296,"column":98}},"line":296},"22":{"name":"(anonymous_22)","decl":{"start":{"line":301,"column":49},"end":{"line":301,"column":60}},"loc":{"start":{"line":301,"column":66},"end":{"line":301,"column":96}},"line":301},"23":{"name":"(anonymous_23)","decl":{"start":{"line":306,"column":49},"end":{"line":306,"column":60}},"loc":{"start":{"line":306,"column":66},"end":{"line":306,"column":96}},"line":306},"24":{"name":"(anonymous_24)","decl":{"start":{"line":311,"column":50},"end":{"line":311,"column":61}},"loc":{"start":{"line":311,"column":67},"end":{"line":311,"column":98}},"line":311},"25":{"name":"(anonymous_25)","decl":{"start":{"line":316,"column":48},"end":{"line":316,"column":59}},"loc":{"start":{"line":316,"column":65},"end":{"line":316,"column":94}},"line":316}},"branchMap":{"0":{"loc":{"start":{"line":15,"column":6},"end":{"line":17,"column":null}},"type":"if","locations":[{"start":{"line":15,"column":6},"end":{"line":17,"column":null}},{"start":{},"end":{}}],"line":15},"1":{"loc":{"start":{"line":23,"column":4},"end":{"line":23,"column":null}},"type":"binary-expr","locations":[{"start":{"line":23,"column":4},"end":{"line":23,"column":56}},{"start":{"line":23,"column":56},"end":{"line":23,"column":null}}],"line":23},"2":{"loc":{"start":{"line":26,"column":4},"end":{"line":26,"column":null}},"type":"binary-expr","locations":[{"start":{"line":26,"column":4},"end":{"line":26,"column":53}},{"start":{"line":26,"column":53},"end":{"line":26,"column":null}}],"line":26},"3":{"loc":{"start":{"line":29,"column":4},"end":{"line":30,"column":null}},"type":"binary-expr","locations":[{"start":{"line":29,"column":4},"end":{"line":29,"column":null}},{"start":{"line":30,"column":6},"end":{"line":30,"column":null}}],"line":29},"4":{"loc":{"start":{"line":35,"column":4},"end":{"line":35,"column":null}},"type":"binary-expr","locations":[{"start":{"line":35,"column":4},"end":{"line":35,"column":60}},{"start":{"line":35,"column":60},"end":{"line":35,"column":null}}],"line":35},"5":{"loc":{"start":{"line":38,"column":4},"end":{"line":38,"column":null}},"type":"binary-expr","locations":[{"start":{"line":38,"column":4},"end":{"line":38,"column":59}},{"start":{"line":38,"column":59},"end":{"line":38,"column":null}}],"line":38},"6":{"loc":{"start":{"line":48,"column":4},"end":{"line":48,"column":null}},"type":"binary-expr","locations":[{"start":{"line":48,"column":4},"end":{"line":48,"column":55}},{"start":{"line":48,"column":55},"end":{"line":48,"column":null}}],"line":48},"7":{"loc":{"start":{"line":54,"column":4},"end":{"line":54,"column":null}},"type":"binary-expr","locations":[{"start":{"line":54,"column":4},"end":{"line":54,"column":56}},{"start":{"line":54,"column":56},"end":{"line":54,"column":null}}],"line":54},"8":{"loc":{"start":{"line":56,"column":39},"end":{"line":56,"column":93}},"type":"binary-expr","locations":[{"start":{"line":56,"column":39},"end":{"line":56,"column":86}},{"start":{"line":56,"column":86},"end":{"line":56,"column":93}}],"line":56},"9":{"loc":{"start":{"line":57,"column":41},"end":{"line":57,"column":98}},"type":"binary-expr","locations":[{"start":{"line":57,"column":41},"end":{"line":57,"column":89}},{"start":{"line":57,"column":89},"end":{"line":57,"column":98}}],"line":57},"10":{"loc":{"start":{"line":58,"column":41},"end":{"line":58,"column":91}},"type":"binary-expr","locations":[{"start":{"line":58,"column":41},"end":{"line":58,"column":89}},{"start":{"line":58,"column":89},"end":{"line":58,"column":91}}],"line":58},"11":{"loc":{"start":{"line":61,"column":4},"end":{"line":61,"column":null}},"type":"binary-expr","locations":[{"start":{"line":61,"column":4},"end":{"line":61,"column":54}},{"start":{"line":61,"column":54},"end":{"line":61,"column":null}}],"line":61},"12":{"loc":{"start":{"line":64,"column":4},"end":{"line":64,"column":null}},"type":"binary-expr","locations":[{"start":{"line":64,"column":4},"end":{"line":64,"column":53}},{"start":{"line":64,"column":53},"end":{"line":64,"column":null}}],"line":64},"13":{"loc":{"start":{"line":67,"column":4},"end":{"line":67,"column":null}},"type":"binary-expr","locations":[{"start":{"line":67,"column":4},"end":{"line":67,"column":53}},{"start":{"line":67,"column":53},"end":{"line":67,"column":null}}],"line":67},"14":{"loc":{"start":{"line":69,"column":41},"end":{"line":69,"column":98}},"type":"binary-expr","locations":[{"start":{"line":69,"column":41},"end":{"line":69,"column":89}},{"start":{"line":69,"column":89},"end":{"line":69,"column":98}}],"line":69},"15":{"loc":{"start":{"line":71,"column":4},"end":{"line":71,"column":null}},"type":"binary-expr","locations":[{"start":{"line":71,"column":4},"end":{"line":71,"column":54}},{"start":{"line":71,"column":54},"end":{"line":71,"column":null}}],"line":71},"16":{"loc":{"start":{"line":75,"column":4},"end":{"line":77,"column":null}},"type":"if","locations":[{"start":{"line":75,"column":4},"end":{"line":77,"column":null}},{"start":{},"end":{}}],"line":75},"17":{"loc":{"start":{"line":97,"column":4},"end":{"line":99,"column":null}},"type":"if","locations":[{"start":{"line":97,"column":4},"end":{"line":99,"column":null}},{"start":{},"end":{}}],"line":97},"18":{"loc":{"start":{"line":103,"column":6},"end":{"line":103,"column":null}},"type":"binary-expr","locations":[{"start":{"line":103,"column":6},"end":{"line":103,"column":61}},{"start":{"line":103,"column":61},"end":{"line":103,"column":null}}],"line":103},"19":{"loc":{"start":{"line":105,"column":4},"end":{"line":107,"column":null}},"type":"if","locations":[{"start":{"line":105,"column":4},"end":{"line":107,"column":null}},{"start":{},"end":{}}],"line":105},"20":{"loc":{"start":{"line":110,"column":6},"end":{"line":110,"column":null}},"type":"binary-expr","locations":[{"start":{"line":110,"column":6},"end":{"line":110,"column":60}},{"start":{"line":110,"column":60},"end":{"line":110,"column":null}}],"line":110},"21":{"loc":{"start":{"line":112,"column":4},"end":{"line":114,"column":null}},"type":"if","locations":[{"start":{"line":112,"column":4},"end":{"line":114,"column":null}},{"start":{},"end":{}}],"line":112},"22":{"loc":{"start":{"line":140,"column":28},"end":{"line":140,"column":64}},"type":"cond-expr","locations":[{"start":{"line":140,"column":42},"end":{"line":140,"column":54}},{"start":{"line":140,"column":54},"end":{"line":140,"column":64}}],"line":140},"23":{"loc":{"start":{"line":145,"column":27},"end":{"line":145,"column":null}},"type":"cond-expr","locations":[{"start":{"line":145,"column":41},"end":{"line":145,"column":79}},{"start":{"line":145,"column":79},"end":{"line":145,"column":null}}],"line":145},"24":{"loc":{"start":{"line":264,"column":11},"end":{"line":272,"column":null}},"type":"binary-expr","locations":[{"start":{"line":264,"column":11},"end":{"line":264,"column":null}},{"start":{"line":265,"column":12},"end":{"line":272,"column":null}}],"line":264},"25":{"loc":{"start":{"line":275,"column":11},"end":{"line":279,"column":null}},"type":"binary-expr","locations":[{"start":{"line":275,"column":11},"end":{"line":275,"column":null}},{"start":{"line":276,"column":12},"end":{"line":279,"column":null}}],"line":275},"26":{"loc":{"start":{"line":282,"column":11},"end":{"line":291,"column":null}},"type":"binary-expr","locations":[{"start":{"line":282,"column":11},"end":{"line":282,"column":null}},{"start":{"line":283,"column":12},"end":{"line":291,"column":null}}],"line":282}},"s":{"0":9,"1":9,"2":9,"3":5,"4":5,"5":5,"6":0,"7":0,"8":5,"9":5,"10":5,"11":9,"12":9,"13":9,"14":9,"15":9,"16":9,"17":9,"18":9,"19":9,"20":9,"21":9,"22":9,"23":9,"24":9,"25":9,"26":9,"27":9,"28":9,"29":1,"30":1,"31":1,"32":1,"33":1,"34":1,"35":1,"36":1,"37":1,"38":1,"39":1,"40":1,"41":1,"42":1,"43":1,"44":1,"45":1,"46":1,"47":1,"48":1,"49":1,"50":1,"51":1,"52":1,"53":1,"54":1,"55":1,"56":1,"57":1,"58":9,"59":0,"60":9,"61":1,"62":9,"63":2,"64":0,"65":0,"66":0,"67":0,"68":0,"69":0,"70":0,"71":0,"72":0,"73":0,"74":0,"75":0,"76":0,"77":0,"78":0,"79":0,"80":0},"f":{"0":9,"1":5,"2":5,"3":0,"4":5,"5":1,"6":0,"7":1,"8":2,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0,"21":0,"22":0,"23":0,"24":0,"25":0},"b":{"0":[0,0],"1":[9,8],"2":[9,8],"3":[9,8],"4":[9,8],"5":[9,8],"6":[9,8],"7":[9,8],"8":[9,8],"9":[9,8],"10":[9,9],"11":[9,8],"12":[9,8],"13":[9,8],"14":[9,8],"15":[9,8],"16":[1,0],"17":[1,0],"18":[1,1],"19":[1,0],"20":[1,1],"21":[1,0],"22":[1,8],"23":[1,8],"24":[9,0],"25":[9,9],"26":[9,0]},"meta":{"lastBranch":27,"lastFunction":26,"lastStatement":81,"seen":{"f:5:24:5:35":0,"s:6:17:6:Infinity":0,"s:7:22:7:Infinity":1,"s:9:2:21:Infinity":2,"f:9:2:9:18":1,"s:10:4:12:Infinity":3,"f:10:41:10:47":2,"s:11:6:11:Infinity":4,"s:14:10:18:Infinity":5,"f:14:10:14:27":3,"b:15:6:17:Infinity:undefined:undefined:undefined:undefined":0,"s:15:6:17:Infinity":6,"s:16:8:16:Infinity":7,"s:19:4:19:Infinity":8,"s:20:4:20:Infinity":9,"f:20:4:20:17":4,"s:20:17:20:Infinity":10,"s:22:21:24:Infinity":11,"b:23:4:23:56:23:56:23:Infinity":1,"s:25:19:27:Infinity":12,"b:26:4:26:53:26:53:26:Infinity":2,"s:28:25:31:Infinity":13,"b:29:4:29:Infinity:30:6:30:Infinity":3,"s:34:32:36:Infinity":14,"b:35:4:35:60:35:60:35:Infinity":4,"s:37:31:39:Infinity":15,"b:38:4:38:59:38:59:38:Infinity":5,"s:42:26:44:Infinity":16,"s:47:21:49:Infinity":17,"b:48:4:48:55:48:55:48:Infinity":6,"s:50:22:52:Infinity":18,"s:53:22:55:Infinity":19,"b:54:4:54:56:54:56:54:Infinity":7,"s:56:17:56:Infinity":20,"b:56:39:56:86:56:86:56:93":8,"s:57:18:57:Infinity":21,"b:57:41:57:89:57:89:57:98":9,"s:58:18:58:Infinity":22,"b:58:41:58:89:58:89:58:91":10,"s:60:20:62:Infinity":23,"b:61:4:61:54:61:54:61:Infinity":11,"s:63:19:65:Infinity":24,"b:64:4:64:53:64:53:64:Infinity":12,"s:66:19:68:Infinity":25,"b:67:4:67:53:67:53:67:Infinity":13,"s:69:18:69:Infinity":26,"b:69:41:69:89:69:89:69:98":14,"s:70:20:72:Infinity":27,"b:71:4:71:54:71:54:71:Infinity":15,"s:74:23:120:Infinity":28,"f:74:23:74:35":5,"b:75:4:77:Infinity:undefined:undefined:undefined:undefined":16,"s:75:4:77:Infinity":29,"s:76:6:76:Infinity":30,"s:78:4:78:Infinity":31,"s:79:4:79:Infinity":32,"s:80:4:80:Infinity":33,"s:82:4:82:Infinity":34,"s:83:4:83:Infinity":35,"s:84:4:84:Infinity":36,"s:85:4:85:Infinity":37,"s:86:4:86:Infinity":38,"s:87:4:87:Infinity":39,"s:89:4:89:Infinity":40,"s:90:4:90:Infinity":41,"s:91:4:91:Infinity":42,"s:92:4:92:Infinity":43,"s:93:4:93:Infinity":44,"s:96:4:96:Infinity":45,"b:97:4:99:Infinity:undefined:undefined:undefined:undefined":17,"s:97:4:99:Infinity":46,"s:98:6:98:Infinity":47,"s:103:6:103:Infinity":48,"b:103:6:103:61:103:61:103:Infinity":18,"s:104:4:104:Infinity":49,"b:105:4:107:Infinity:undefined:undefined:undefined:undefined":19,"s:105:4:107:Infinity":50,"s:106:6:106:Infinity":51,"s:110:6:110:Infinity":52,"b:110:6:110:60:110:60:110:Infinity":20,"s:111:4:111:Infinity":53,"b:112:4:114:Infinity:undefined:undefined:undefined:undefined":21,"s:112:4:114:Infinity":54,"s:113:6:113:Infinity":55,"s:117:4:117:Infinity":56,"s:119:4:119:Infinity":57,"s:122:8:124:Infinity":58,"f:122:8:122:30":6,"s:123:4:123:Infinity":59,"s:126:8:128:Infinity":60,"f:126:8:126:24":7,"s:127:4:127:Infinity":61,"s:130:2:332:Infinity":62,"b:140:42:140:54:140:54:140:64":22,"f:144:14:144:25":8,"s:144:31:144:Infinity":63,"b:145:41:145:79:145:79:145:Infinity":23,"f:154:14:154:25":9,"s:154:31:154:Infinity":64,"f:164:14:164:25":10,"s:164:31:164:Infinity":65,"f:173:14:173:25":11,"s:173:31:173:Infinity":66,"f:198:14:198:25":12,"s:198:31:198:Infinity":67,"f:207:14:207:25":13,"s:207:31:207:Infinity":68,"f:220:14:220:25":14,"s:220:31:220:Infinity":69,"f:230:39:230:50":15,"s:230:56:230:Infinity":70,"f:250:14:250:25":16,"s:250:31:250:Infinity":71,"f:257:35:257:46":17,"s:257:52:257:Infinity":72,"b:264:11:264:Infinity:265:12:272:Infinity":24,"f:267:42:267:53":18,"s:267:59:267:Infinity":73,"b:275:11:275:Infinity:276:12:279:Infinity":25,"f:278:50:278:61":19,"s:278:67:278:96":74,"b:282:11:282:Infinity:283:12:291:Infinity":26,"f:288:16:288:27":20,"s:288:33:288:Infinity":75,"f:296:50:296:61":21,"s:296:67:296:98":76,"f:301:49:301:60":22,"s:301:66:301:96":77,"f:306:49:306:60":23,"s:306:66:306:96":78,"f:311:50:311:61":24,"s:311:67:311:98":79,"f:316:48:316:59":25,"s:316:65:316:94":80},"fnNames":{}}} +,"/Users/aditya/Projects/PaperCache/src/utils.ts": {"path":"/Users/aditya/Projects/PaperCache/src/utils.ts","statementMap":{"0":{"start":{"line":1,"column":13},"end":{"line":40,"column":null}},"1":{"start":{"line":2,"column":2},"end":{"line":2,"column":null}},"2":{"start":{"line":2,"column":12},"end":{"line":2,"column":null}},"3":{"start":{"line":3,"column":39},"end":{"line":3,"column":null}},"4":{"start":{"line":4,"column":2},"end":{"line":6,"column":null}},"5":{"start":{"line":5,"column":4},"end":{"line":5,"column":null}},"6":{"start":{"line":8,"column":2},"end":{"line":8,"column":null}},"7":{"start":{"line":8,"column":19},"end":{"line":8,"column":null}},"8":{"start":{"line":10,"column":19},"end":{"line":15,"column":null}},"9":{"start":{"line":12,"column":20},"end":{"line":12,"column":null}},"10":{"start":{"line":13,"column":6},"end":{"line":13,"column":null}},"11":{"start":{"line":15,"column":19},"end":{"line":15,"column":29}},"12":{"start":{"line":17,"column":16},"end":{"line":17,"column":null}},"13":{"start":{"line":18,"column":2},"end":{"line":34,"column":null}},"14":{"start":{"line":19,"column":4},"end":{"line":19,"column":null}},"15":{"start":{"line":19,"column":28},"end":{"line":19,"column":33}},"16":{"start":{"line":20,"column":18},"end":{"line":20,"column":null}},"17":{"start":{"line":21,"column":4},"end":{"line":29,"column":null}},"18":{"start":{"line":21,"column":17},"end":{"line":21,"column":20}},"19":{"start":{"line":22,"column":12},"end":{"line":22,"column":null}},"20":{"start":{"line":23,"column":17},"end":{"line":23,"column":null}},"21":{"start":{"line":24,"column":6},"end":{"line":24,"column":null}},"22":{"start":{"line":24,"column":21},"end":{"line":24,"column":null}},"23":{"start":{"line":25,"column":6},"end":{"line":28,"column":null}},"24":{"start":{"line":26,"column":8},"end":{"line":26,"column":null}},"25":{"start":{"line":27,"column":8},"end":{"line":27,"column":null}},"26":{"start":{"line":31,"column":15},"end":{"line":31,"column":null}},"27":{"start":{"line":32,"column":4},"end":{"line":32,"column":null}},"28":{"start":{"line":32,"column":17},"end":{"line":32,"column":20}},"29":{"start":{"line":32,"column":41},"end":{"line":32,"column":null}},"30":{"start":{"line":33,"column":4},"end":{"line":33,"column":null}},"31":{"start":{"line":36,"column":16},"end":{"line":36,"column":null}},"32":{"start":{"line":37,"column":2},"end":{"line":37,"column":null}},"33":{"start":{"line":38,"column":2},"end":{"line":38,"column":null}},"34":{"start":{"line":39,"column":2},"end":{"line":39,"column":null}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":1,"column":13},"end":{"line":1,"column":31}},"loc":{"start":{"line":1,"column":55},"end":{"line":40,"column":null}},"line":1},"1":{"name":"(anonymous_1)","decl":{"start":{"line":11,"column":5},"end":{"line":11,"column":10}},"loc":{"start":{"line":11,"column":16},"end":{"line":14,"column":5}},"line":11},"2":{"name":"(anonymous_2)","decl":{"start":{"line":15,"column":5},"end":{"line":15,"column":13}},"loc":{"start":{"line":15,"column":19},"end":{"line":15,"column":29}},"line":15},"3":{"name":"(anonymous_3)","decl":{"start":{"line":19,"column":13},"end":{"line":19,"column":19}},"loc":{"start":{"line":19,"column":28},"end":{"line":19,"column":33}},"line":19}},"branchMap":{"0":{"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":null}},"type":"if","locations":[{"start":{"line":2,"column":2},"end":{"line":2,"column":null}},{"start":{},"end":{}}],"line":2},"1":{"loc":{"start":{"line":5,"column":24},"end":{"line":5,"column":80}},"type":"binary-expr","locations":[{"start":{"line":5,"column":24},"end":{"line":5,"column":76}},{"start":{"line":5,"column":76},"end":{"line":5,"column":80}}],"line":5},"2":{"loc":{"start":{"line":8,"column":2},"end":{"line":8,"column":null}},"type":"if","locations":[{"start":{"line":8,"column":2},"end":{"line":8,"column":null}},{"start":{},"end":{}}],"line":8},"3":{"loc":{"start":{"line":13,"column":13},"end":{"line":13,"column":null}},"type":"cond-expr","locations":[{"start":{"line":13,"column":21},"end":{"line":13,"column":42}},{"start":{"line":13,"column":42},"end":{"line":13,"column":null}}],"line":13},"4":{"loc":{"start":{"line":18,"column":2},"end":{"line":34,"column":null}},"type":"if","locations":[{"start":{"line":18,"column":2},"end":{"line":34,"column":null}},{"start":{"line":30,"column":9},"end":{"line":34,"column":null}}],"line":18},"5":{"loc":{"start":{"line":24,"column":6},"end":{"line":24,"column":null}},"type":"if","locations":[{"start":{"line":24,"column":6},"end":{"line":24,"column":null}},{"start":{},"end":{}}],"line":24},"6":{"loc":{"start":{"line":25,"column":6},"end":{"line":28,"column":null}},"type":"if","locations":[{"start":{"line":25,"column":6},"end":{"line":28,"column":null}},{"start":{},"end":{}}],"line":25}},"s":{"0":1,"1":9,"2":1,"3":8,"4":8,"5":8,"6":8,"7":1,"8":7,"9":4,"10":4,"11":4,"12":7,"13":7,"14":3,"15":1,"16":3,"17":3,"18":3,"19":4,"20":4,"21":4,"22":3,"23":4,"24":3,"25":3,"26":4,"27":4,"28":4,"29":20,"30":4,"31":7,"32":7,"33":7,"34":7},"f":{"0":9,"1":4,"2":4,"3":1},"b":{"0":[1,8],"1":[8,4],"2":[1,7],"3":[4,0],"4":[3,4],"5":[3,1],"6":[3,1]},"meta":{"lastBranch":7,"lastFunction":4,"lastStatement":35,"seen":{"s:1:13:40:Infinity":0,"f:1:13:1:31":0,"b:2:2:2:Infinity:undefined:undefined:undefined:undefined":0,"s:2:2:2:Infinity":1,"s:2:12:2:Infinity":2,"s:3:39:3:Infinity":3,"s:4:2:6:Infinity":4,"s:5:4:5:Infinity":5,"b:5:24:5:76:5:76:5:80":1,"b:8:2:8:Infinity:undefined:undefined:undefined:undefined":2,"s:8:2:8:Infinity":6,"s:8:19:8:Infinity":7,"s:10:19:15:Infinity":8,"f:11:5:11:10":1,"s:12:20:12:Infinity":9,"s:13:6:13:Infinity":10,"b:13:21:13:42:13:42:13:Infinity":3,"f:15:5:15:13":2,"s:15:19:15:29":11,"s:17:16:17:Infinity":12,"b:18:2:34:Infinity:30:9:34:Infinity":4,"s:18:2:34:Infinity":13,"s:19:4:19:Infinity":14,"f:19:13:19:19":3,"s:19:28:19:33":15,"s:20:18:20:Infinity":16,"s:21:4:29:Infinity":17,"s:21:17:21:20":18,"s:22:12:22:Infinity":19,"s:23:17:23:Infinity":20,"b:24:6:24:Infinity:undefined:undefined:undefined:undefined":5,"s:24:6:24:Infinity":21,"s:24:21:24:Infinity":22,"b:25:6:28:Infinity:undefined:undefined:undefined:undefined":6,"s:25:6:28:Infinity":23,"s:26:8:26:Infinity":24,"s:27:8:27:Infinity":25,"s:31:15:31:Infinity":26,"s:32:4:32:Infinity":27,"s:32:17:32:20":28,"s:32:41:32:Infinity":29,"s:33:4:33:Infinity":30,"s:36:16:36:Infinity":31,"s:37:2:37:Infinity":32,"s:38:2:38:Infinity":33,"s:39:2:39:Infinity":34},"fnNames":{}}} +,"/Users/aditya/Projects/PaperCache/src/hooks/useReminders.ts": {"path":"/Users/aditya/Projects/PaperCache/src/hooks/useReminders.ts","statementMap":{"0":{"start":{"line":6,"column":67},"end":{"line":6,"column":null}},"1":{"start":{"line":8,"column":4},"end":{"line":8,"column":null}},"2":{"start":{"line":11,"column":2},"end":{"line":25,"column":null}},"3":{"start":{"line":12,"column":19},"end":{"line":12,"column":null}},"4":{"start":{"line":13,"column":18},"end":{"line":13,"column":null}},"5":{"start":{"line":14,"column":22},"end":{"line":14,"column":null}},"6":{"start":{"line":15,"column":4},"end":{"line":24,"column":null}},"7":{"start":{"line":16,"column":23},"end":{"line":16,"column":null}},"8":{"start":{"line":17,"column":6},"end":{"line":23,"column":null}},"9":{"start":{"line":18,"column":8},"end":{"line":22,"column":null}},"10":{"start":{"line":26,"column":2},"end":{"line":26,"column":null}},"11":{"start":{"line":30,"column":14},"end":{"line":30,"column":null}},"12":{"start":{"line":31,"column":22},"end":{"line":31,"column":null}},"13":{"start":{"line":32,"column":19},"end":{"line":32,"column":null}},"14":{"start":{"line":33,"column":21},"end":{"line":33,"column":null}},"15":{"start":{"line":35,"column":23},"end":{"line":35,"column":null}},"16":{"start":{"line":35,"column":44},"end":{"line":35,"column":75}},"17":{"start":{"line":37,"column":2},"end":{"line":49,"column":null}},"18":{"start":{"line":38,"column":4},"end":{"line":48,"column":null}},"19":{"start":{"line":39,"column":6},"end":{"line":47,"column":null}},"20":{"start":{"line":40,"column":8},"end":{"line":40,"column":null}},"21":{"start":{"line":41,"column":8},"end":{"line":44,"column":null}},"22":{"start":{"line":45,"column":8},"end":{"line":45,"column":null}},"23":{"start":{"line":46,"column":8},"end":{"line":46,"column":null}},"24":{"start":{"line":51,"column":2},"end":{"line":53,"column":null}},"25":{"start":{"line":52,"column":4},"end":{"line":52,"column":null}},"26":{"start":{"line":57,"column":14},"end":{"line":57,"column":null}},"27":{"start":{"line":58,"column":15},"end":{"line":62,"column":null}},"28":{"start":{"line":59,"column":20},"end":{"line":59,"column":51}},"29":{"start":{"line":60,"column":16},"end":{"line":60,"column":33}},"30":{"start":{"line":61,"column":19},"end":{"line":61,"column":26}},"31":{"start":{"line":64,"column":2},"end":{"line":64,"column":null}},"32":{"start":{"line":64,"column":13},"end":{"line":64,"column":null}},"33":{"start":{"line":67,"column":16},"end":{"line":67,"column":null}},"34":{"start":{"line":68,"column":2},"end":{"line":68,"column":null}},"35":{"start":{"line":72,"column":8},"end":{"line":72,"column":null}},"36":{"start":{"line":72,"column":39},"end":{"line":72,"column":50}},"37":{"start":{"line":73,"column":8},"end":{"line":73,"column":null}},"38":{"start":{"line":75,"column":2},"end":{"line":107,"column":null}},"39":{"start":{"line":76,"column":4},"end":{"line":78,"column":null}},"40":{"start":{"line":77,"column":6},"end":{"line":77,"column":null}},"41":{"start":{"line":80,"column":10},"end":{"line":84,"column":null}},"42":{"start":{"line":81,"column":6},"end":{"line":81,"column":null}},"43":{"start":{"line":82,"column":6},"end":{"line":82,"column":null}},"44":{"start":{"line":82,"column":28},"end":{"line":82,"column":null}},"45":{"start":{"line":83,"column":6},"end":{"line":83,"column":null}},"46":{"start":{"line":86,"column":4},"end":{"line":86,"column":null}},"47":{"start":{"line":88,"column":10},"end":{"line":93,"column":null}},"48":{"start":{"line":89,"column":6},"end":{"line":92,"column":null}},"49":{"start":{"line":90,"column":8},"end":{"line":90,"column":null}},"50":{"start":{"line":91,"column":8},"end":{"line":91,"column":null}},"51":{"start":{"line":95,"column":10},"end":{"line":97,"column":null}},"52":{"start":{"line":96,"column":6},"end":{"line":96,"column":null}},"53":{"start":{"line":99,"column":31},"end":{"line":99,"column":null}},"54":{"start":{"line":100,"column":30},"end":{"line":100,"column":null}},"55":{"start":{"line":102,"column":4},"end":{"line":106,"column":null}},"56":{"start":{"line":103,"column":6},"end":{"line":103,"column":null}},"57":{"start":{"line":103,"column":28},"end":{"line":103,"column":null}},"58":{"start":{"line":104,"column":6},"end":{"line":104,"column":null}},"59":{"start":{"line":105,"column":6},"end":{"line":105,"column":null}}},"fnMap":{"0":{"name":"parseReminders","decl":{"start":{"line":5,"column":9},"end":{"line":5,"column":24}},"loc":{"start":{"line":5,"column":57},"end":{"line":27,"column":null}},"line":5},"1":{"name":"handleDueReminders","decl":{"start":{"line":29,"column":9},"end":{"line":29,"column":28}},"loc":{"start":{"line":29,"column":43},"end":{"line":54,"column":null}},"line":29},"2":{"name":"(anonymous_2)","decl":{"start":{"line":35,"column":29},"end":{"line":35,"column":38}},"loc":{"start":{"line":35,"column":44},"end":{"line":35,"column":75}},"line":35},"3":{"name":"scheduleNextReminder","decl":{"start":{"line":56,"column":9},"end":{"line":56,"column":30}},"loc":{"start":{"line":56,"column":67},"end":{"line":69,"column":null}},"line":56},"4":{"name":"(anonymous_4)","decl":{"start":{"line":59,"column":5},"end":{"line":59,"column":14}},"loc":{"start":{"line":59,"column":20},"end":{"line":59,"column":51}},"line":59},"5":{"name":"(anonymous_5)","decl":{"start":{"line":60,"column":5},"end":{"line":60,"column":10}},"loc":{"start":{"line":60,"column":16},"end":{"line":60,"column":33}},"line":60},"6":{"name":"(anonymous_6)","decl":{"start":{"line":61,"column":5},"end":{"line":61,"column":13}},"loc":{"start":{"line":61,"column":19},"end":{"line":61,"column":26}},"line":61},"7":{"name":"useReminders","decl":{"start":{"line":71,"column":16},"end":{"line":71,"column":31}},"loc":{"start":{"line":71,"column":31},"end":{"line":108,"column":null}},"line":71},"8":{"name":"(anonymous_8)","decl":{"start":{"line":72,"column":16},"end":{"line":72,"column":29}},"loc":{"start":{"line":72,"column":39},"end":{"line":72,"column":50}},"line":72},"9":{"name":"(anonymous_9)","decl":{"start":{"line":75,"column":2},"end":{"line":75,"column":18}},"loc":{"start":{"line":75,"column":18},"end":{"line":107,"column":5}},"line":75},"10":{"name":"(anonymous_10)","decl":{"start":{"line":80,"column":10},"end":{"line":80,"column":35}},"loc":{"start":{"line":80,"column":35},"end":{"line":84,"column":null}},"line":80},"11":{"name":"(anonymous_11)","decl":{"start":{"line":88,"column":10},"end":{"line":88,"column":28}},"loc":{"start":{"line":88,"column":28},"end":{"line":93,"column":null}},"line":88},"12":{"name":"(anonymous_12)","decl":{"start":{"line":95,"column":10},"end":{"line":95,"column":27}},"loc":{"start":{"line":95,"column":27},"end":{"line":97,"column":null}},"line":95},"13":{"name":"(anonymous_13)","decl":{"start":{"line":102,"column":4},"end":{"line":102,"column":17}},"loc":{"start":{"line":102,"column":17},"end":{"line":106,"column":null}},"line":102}},"branchMap":{"0":{"loc":{"start":{"line":15,"column":4},"end":{"line":24,"column":null}},"type":"if","locations":[{"start":{"line":15,"column":4},"end":{"line":24,"column":null}},{"start":{},"end":{}}],"line":15},"1":{"loc":{"start":{"line":15,"column":8},"end":{"line":15,"column":30}},"type":"binary-expr","locations":[{"start":{"line":15,"column":8},"end":{"line":15,"column":19}},{"start":{"line":15,"column":19},"end":{"line":15,"column":30}}],"line":15},"2":{"loc":{"start":{"line":17,"column":6},"end":{"line":23,"column":null}},"type":"if","locations":[{"start":{"line":17,"column":6},"end":{"line":23,"column":null}},{"start":{},"end":{}}],"line":17},"3":{"loc":{"start":{"line":31,"column":22},"end":{"line":31,"column":null}},"type":"binary-expr","locations":[{"start":{"line":31,"column":22},"end":{"line":31,"column":80}},{"start":{"line":31,"column":80},"end":{"line":31,"column":null}}],"line":31},"4":{"loc":{"start":{"line":38,"column":4},"end":{"line":48,"column":null}},"type":"if","locations":[{"start":{"line":38,"column":4},"end":{"line":48,"column":null}},{"start":{},"end":{}}],"line":38},"5":{"loc":{"start":{"line":39,"column":6},"end":{"line":47,"column":null}},"type":"if","locations":[{"start":{"line":39,"column":6},"end":{"line":47,"column":null}},{"start":{},"end":{}}],"line":39},"6":{"loc":{"start":{"line":51,"column":2},"end":{"line":53,"column":null}},"type":"if","locations":[{"start":{"line":51,"column":2},"end":{"line":53,"column":null}},{"start":{},"end":{}}],"line":51},"7":{"loc":{"start":{"line":64,"column":2},"end":{"line":64,"column":null}},"type":"if","locations":[{"start":{"line":64,"column":2},"end":{"line":64,"column":null}},{"start":{},"end":{}}],"line":64},"8":{"loc":{"start":{"line":76,"column":4},"end":{"line":78,"column":null}},"type":"if","locations":[{"start":{"line":76,"column":4},"end":{"line":78,"column":null}},{"start":{},"end":{}}],"line":76},"9":{"loc":{"start":{"line":76,"column":8},"end":{"line":76,"column":87}},"type":"binary-expr","locations":[{"start":{"line":76,"column":8},"end":{"line":76,"column":49}},{"start":{"line":76,"column":49},"end":{"line":76,"column":87}}],"line":76},"10":{"loc":{"start":{"line":82,"column":6},"end":{"line":82,"column":null}},"type":"if","locations":[{"start":{"line":82,"column":6},"end":{"line":82,"column":null}},{"start":{},"end":{}}],"line":82},"11":{"loc":{"start":{"line":89,"column":6},"end":{"line":92,"column":null}},"type":"if","locations":[{"start":{"line":89,"column":6},"end":{"line":92,"column":null}},{"start":{},"end":{}}],"line":89},"12":{"loc":{"start":{"line":103,"column":6},"end":{"line":103,"column":null}},"type":"if","locations":[{"start":{"line":103,"column":6},"end":{"line":103,"column":null}},{"start":{},"end":{}}],"line":103}},"s":{"0":8,"1":8,"2":8,"3":8,"4":8,"5":8,"6":8,"7":6,"8":6,"9":6,"10":8,"11":6,"12":6,"13":6,"14":6,"15":6,"16":4,"17":6,"18":3,"19":2,"20":2,"21":2,"22":2,"23":2,"24":6,"25":2,"26":6,"27":6,"28":4,"29":3,"30":3,"31":6,"32":5,"33":1,"34":1,"35":5,"36":15,"37":5,"38":5,"39":5,"40":1,"41":5,"42":6,"43":6,"44":1,"45":6,"46":5,"47":5,"48":0,"49":0,"50":0,"51":5,"52":0,"53":5,"54":5,"55":5,"56":5,"57":0,"58":5,"59":5},"f":{"0":8,"1":6,"2":4,"3":6,"4":4,"5":3,"6":3,"7":5,"8":15,"9":5,"10":6,"11":0,"12":0,"13":5},"b":{"0":[6,2],"1":[8,6],"2":[6,0],"3":[6,6],"4":[2,1],"5":[2,0],"6":[2,4],"7":[5,1],"8":[1,4],"9":[5,1],"10":[1,5],"11":[0,0],"12":[0,5]},"meta":{"lastBranch":13,"lastFunction":14,"lastStatement":60,"seen":{"f:5:9:5:24":0,"s:6:67:6:Infinity":0,"s:8:4:8:Infinity":1,"s:11:2:25:Infinity":2,"s:12:19:12:Infinity":3,"s:13:18:13:Infinity":4,"s:14:22:14:Infinity":5,"b:15:4:24:Infinity:undefined:undefined:undefined:undefined":0,"s:15:4:24:Infinity":6,"b:15:8:15:19:15:19:15:30":1,"s:16:23:16:Infinity":7,"b:17:6:23:Infinity:undefined:undefined:undefined:undefined":2,"s:17:6:23:Infinity":8,"s:18:8:22:Infinity":9,"s:26:2:26:Infinity":10,"f:29:9:29:28":1,"s:30:14:30:Infinity":11,"s:31:22:31:Infinity":12,"b:31:22:31:80:31:80:31:Infinity":3,"s:32:19:32:Infinity":13,"s:33:21:33:Infinity":14,"s:35:23:35:Infinity":15,"f:35:29:35:38":2,"s:35:44:35:75":16,"s:37:2:49:Infinity":17,"b:38:4:48:Infinity:undefined:undefined:undefined:undefined":4,"s:38:4:48:Infinity":18,"b:39:6:47:Infinity:undefined:undefined:undefined:undefined":5,"s:39:6:47:Infinity":19,"s:40:8:40:Infinity":20,"s:41:8:44:Infinity":21,"s:45:8:45:Infinity":22,"s:46:8:46:Infinity":23,"b:51:2:53:Infinity:undefined:undefined:undefined:undefined":6,"s:51:2:53:Infinity":24,"s:52:4:52:Infinity":25,"f:56:9:56:30":3,"s:57:14:57:Infinity":26,"s:58:15:62:Infinity":27,"f:59:5:59:14":4,"s:59:20:59:51":28,"f:60:5:60:10":5,"s:60:16:60:33":29,"f:61:5:61:13":6,"s:61:19:61:26":30,"b:64:2:64:Infinity:undefined:undefined:undefined:undefined":7,"s:64:2:64:Infinity":31,"s:64:13:64:Infinity":32,"s:67:16:67:Infinity":33,"s:68:2:68:Infinity":34,"f:71:16:71:31":7,"s:72:8:72:Infinity":35,"f:72:16:72:29":8,"s:72:39:72:50":36,"s:73:8:73:Infinity":37,"s:75:2:107:Infinity":38,"f:75:2:75:18":9,"b:76:4:78:Infinity:undefined:undefined:undefined:undefined":8,"s:76:4:78:Infinity":39,"b:76:8:76:49:76:49:76:87":9,"s:77:6:77:Infinity":40,"s:80:10:84:Infinity":41,"f:80:10:80:35":10,"s:81:6:81:Infinity":42,"b:82:6:82:Infinity:undefined:undefined:undefined:undefined":10,"s:82:6:82:Infinity":43,"s:82:28:82:Infinity":44,"s:83:6:83:Infinity":45,"s:86:4:86:Infinity":46,"s:88:10:93:Infinity":47,"f:88:10:88:28":11,"b:89:6:92:Infinity:undefined:undefined:undefined:undefined":11,"s:89:6:92:Infinity":48,"s:90:8:90:Infinity":49,"s:91:8:91:Infinity":50,"s:95:10:97:Infinity":51,"f:95:10:95:27":12,"s:96:6:96:Infinity":52,"s:99:31:99:Infinity":53,"s:100:30:100:Infinity":54,"s:102:4:106:Infinity":55,"f:102:4:102:17":13,"b:103:6:103:Infinity:undefined:undefined:undefined:undefined":12,"s:103:6:103:Infinity":56,"s:103:28:103:Infinity":57,"s:104:6:104:Infinity":58,"s:105:6:105:Infinity":59},"fnNames":{}}} +,"/Users/aditya/Projects/PaperCache/src/hooks/useVariables.ts": {"path":"/Users/aditya/Projects/PaperCache/src/hooks/useVariables.ts","statementMap":{"0":{"start":{"line":6,"column":8},"end":{"line":6,"column":null}},"1":{"start":{"line":6,"column":39},"end":{"line":6,"column":50}},"2":{"start":{"line":9,"column":2},"end":{"line":39,"column":null}},"3":{"start":{"line":10,"column":16},"end":{"line":10,"column":null}},"4":{"start":{"line":12,"column":47},"end":{"line":12,"column":null}},"5":{"start":{"line":13,"column":20},"end":{"line":13,"column":null}},"6":{"start":{"line":15,"column":76},"end":{"line":15,"column":null}},"7":{"start":{"line":17,"column":6},"end":{"line":30,"column":null}},"8":{"start":{"line":19,"column":8},"end":{"line":29,"column":null}},"9":{"start":{"line":20,"column":23},"end":{"line":20,"column":null}},"10":{"start":{"line":21,"column":10},"end":{"line":28,"column":null}},"11":{"start":{"line":22,"column":12},"end":{"line":24,"column":null}},"12":{"start":{"line":23,"column":14},"end":{"line":23,"column":null}},"13":{"start":{"line":25,"column":12},"end":{"line":25,"column":null}},"14":{"start":{"line":27,"column":12},"end":{"line":27,"column":null}},"15":{"start":{"line":31,"column":6},"end":{"line":31,"column":null}},"16":{"start":{"line":31,"column":17},"end":{"line":31,"column":null}},"17":{"start":{"line":32,"column":7},"end":{"line":33,"column":null}},"18":{"start":{"line":35,"column":4},"end":{"line":35,"column":null}},"19":{"start":{"line":36,"column":4},"end":{"line":38,"column":null}},"20":{"start":{"line":37,"column":6},"end":{"line":37,"column":null}}},"fnMap":{"0":{"name":"useVariables","decl":{"start":{"line":5,"column":16},"end":{"line":5,"column":31}},"loc":{"start":{"line":5,"column":31},"end":{"line":40,"column":null}},"line":5},"1":{"name":"(anonymous_1)","decl":{"start":{"line":6,"column":16},"end":{"line":6,"column":29}},"loc":{"start":{"line":6,"column":39},"end":{"line":6,"column":50}},"line":6},"2":{"name":"(anonymous_2)","decl":{"start":{"line":9,"column":2},"end":{"line":9,"column":18}},"loc":{"start":{"line":9,"column":18},"end":{"line":39,"column":5}},"line":9},"3":{"name":"syncVars","decl":{"start":{"line":11,"column":19},"end":{"line":11,"column":30}},"loc":{"start":{"line":11,"column":30},"end":{"line":34,"column":null}},"line":11},"4":{"name":"(anonymous_4)","decl":{"start":{"line":36,"column":4},"end":{"line":36,"column":17}},"loc":{"start":{"line":36,"column":17},"end":{"line":38,"column":null}},"line":36}},"branchMap":{"0":{"loc":{"start":{"line":22,"column":12},"end":{"line":24,"column":null}},"type":"if","locations":[{"start":{"line":22,"column":12},"end":{"line":24,"column":null}},{"start":{},"end":{}}],"line":22},"1":{"loc":{"start":{"line":31,"column":6},"end":{"line":31,"column":null}},"type":"if","locations":[{"start":{"line":31,"column":6},"end":{"line":31,"column":null}},{"start":{},"end":{}}],"line":31}},"s":{"0":4,"1":12,"2":4,"3":4,"4":4,"5":4,"6":4,"7":4,"8":5,"9":7,"10":7,"11":7,"12":4,"13":7,"14":1,"15":4,"16":0,"17":4,"18":4,"19":4,"20":4},"f":{"0":4,"1":12,"2":4,"3":4,"4":4},"b":{"0":[4,3],"1":[0,4]},"meta":{"lastBranch":2,"lastFunction":5,"lastStatement":21,"seen":{"f:5:16:5:31":0,"s:6:8:6:Infinity":0,"f:6:16:6:29":1,"s:6:39:6:50":1,"s:9:2:39:Infinity":2,"f:9:2:9:18":2,"s:10:16:10:Infinity":3,"f:11:19:11:30":3,"s:12:47:12:Infinity":4,"s:13:20:13:Infinity":5,"s:15:76:15:Infinity":6,"s:17:6:30:Infinity":7,"s:19:8:29:Infinity":8,"s:20:23:20:Infinity":9,"s:21:10:28:Infinity":10,"b:22:12:24:Infinity:undefined:undefined:undefined:undefined":0,"s:22:12:24:Infinity":11,"s:23:14:23:Infinity":12,"s:25:12:25:Infinity":13,"s:27:12:27:Infinity":14,"b:31:6:31:Infinity:undefined:undefined:undefined:undefined":1,"s:31:6:31:Infinity":15,"s:31:17:31:Infinity":16,"s:32:7:33:Infinity":17,"s:35:4:35:Infinity":18,"s:36:4:38:Infinity":19,"f:36:4:36:17":4,"s:37:6:37:Infinity":20},"fnNames":{}}} +,"/Users/aditya/Projects/PaperCache/src/lib/safeStorage.ts": {"path":"/Users/aditya/Projects/PaperCache/src/lib/safeStorage.ts","statementMap":{"0":{"start":{"line":2,"column":20},"end":{"line":2,"column":null}},"1":{"start":{"line":3,"column":2},"end":{"line":3,"column":null}},"2":{"start":{"line":7,"column":20},"end":{"line":7,"column":null}},"3":{"start":{"line":8,"column":2},"end":{"line":8,"column":null}},"4":{"start":{"line":8,"column":18},"end":{"line":8,"column":null}},"5":{"start":{"line":9,"column":2},"end":{"line":9,"column":null}},"6":{"start":{"line":13,"column":16},"end":{"line":13,"column":null}},"7":{"start":{"line":14,"column":2},"end":{"line":17,"column":null}},"8":{"start":{"line":15,"column":4},"end":{"line":15,"column":null}},"9":{"start":{"line":16,"column":4},"end":{"line":16,"column":null}}},"fnMap":{"0":{"name":"setSecure","decl":{"start":{"line":1,"column":22},"end":{"line":1,"column":32}},"loc":{"start":{"line":1,"column":75},"end":{"line":4,"column":null}},"line":1},"1":{"name":"getSecure","decl":{"start":{"line":6,"column":22},"end":{"line":6,"column":32}},"loc":{"start":{"line":6,"column":69},"end":{"line":10,"column":null}},"line":6},"2":{"name":"migrateApiKeyFromLocalStorage","decl":{"start":{"line":12,"column":22},"end":{"line":12,"column":52}},"loc":{"start":{"line":12,"column":65},"end":{"line":18,"column":null}},"line":12}},"branchMap":{"0":{"loc":{"start":{"line":8,"column":2},"end":{"line":8,"column":null}},"type":"if","locations":[{"start":{"line":8,"column":2},"end":{"line":8,"column":null}},{"start":{},"end":{}}],"line":8},"1":{"loc":{"start":{"line":14,"column":2},"end":{"line":17,"column":null}},"type":"if","locations":[{"start":{"line":14,"column":2},"end":{"line":17,"column":null}},{"start":{},"end":{}}],"line":14}},"s":{"0":1,"1":1,"2":2,"3":2,"4":1,"5":1,"6":0,"7":0,"8":0,"9":0},"f":{"0":1,"1":2,"2":0},"b":{"0":[1,1],"1":[0,0]},"meta":{"lastBranch":2,"lastFunction":3,"lastStatement":10,"seen":{"f:1:22:1:32":0,"s:2:20:2:Infinity":0,"s:3:2:3:Infinity":1,"f:6:22:6:32":1,"s:7:20:7:Infinity":2,"b:8:2:8:Infinity:undefined:undefined:undefined:undefined":0,"s:8:2:8:Infinity":3,"s:8:18:8:Infinity":4,"s:9:2:9:Infinity":5,"f:12:22:12:52":2,"s:13:16:13:Infinity":6,"b:14:2:17:Infinity:undefined:undefined:undefined:undefined":1,"s:14:2:17:Infinity":7,"s:15:4:15:Infinity":8,"s:16:4:16:Infinity":9},"fnNames":{}}} +,"/Users/aditya/Projects/PaperCache/src/lib/settingsKeys.ts": {"path":"/Users/aditya/Projects/PaperCache/src/lib/settingsKeys.ts","statementMap":{"0":{"start":{"line":1,"column":29},"end":{"line":20,"column":null}}},"fnMap":{},"branchMap":{},"s":{"0":2},"f":{},"b":{},"meta":{"lastBranch":0,"lastFunction":0,"lastStatement":1,"seen":{"s:1:29:20:Infinity":0},"fnNames":{}}} +,"/Users/aditya/Projects/PaperCache/src/lib/editor/MathEvaluator.ts": {"path":"/Users/aditya/Projects/PaperCache/src/lib/editor/MathEvaluator.ts","statementMap":{"0":{"start":{"line":5,"column":38},"end":{"line":5,"column":null}},"1":{"start":{"line":12,"column":4},"end":{"line":16,"column":null}},"2":{"start":{"line":13,"column":6},"end":{"line":13,"column":null}},"3":{"start":{"line":15,"column":6},"end":{"line":15,"column":null}},"4":{"start":{"line":17,"column":68},"end":{"line":17,"column":null}},"5":{"start":{"line":20,"column":18},"end":{"line":20,"column":null}},"6":{"start":{"line":21,"column":17},"end":{"line":21,"column":null}},"7":{"start":{"line":22,"column":4},"end":{"line":41,"column":null}},"8":{"start":{"line":22,"column":17},"end":{"line":22,"column":20}},"9":{"start":{"line":23,"column":19},"end":{"line":23,"column":null}},"10":{"start":{"line":24,"column":22},"end":{"line":24,"column":null}},"11":{"start":{"line":26,"column":6},"end":{"line":38,"column":null}},"12":{"start":{"line":27,"column":21},"end":{"line":27,"column":null}},"13":{"start":{"line":28,"column":8},"end":{"line":37,"column":null}},"14":{"start":{"line":29,"column":10},"end":{"line":36,"column":null}},"15":{"start":{"line":30,"column":27},"end":{"line":30,"column":null}},"16":{"start":{"line":31,"column":12},"end":{"line":35,"column":null}},"17":{"start":{"line":40,"column":6},"end":{"line":40,"column":null}},"18":{"start":{"line":44,"column":19},"end":{"line":44,"column":null}},"19":{"start":{"line":46,"column":4},"end":{"line":66,"column":null}},"20":{"start":{"line":47,"column":23},"end":{"line":47,"column":null}},"21":{"start":{"line":48,"column":24},"end":{"line":48,"column":null}},"22":{"start":{"line":49,"column":19},"end":{"line":49,"column":null}},"23":{"start":{"line":50,"column":6},"end":{"line":65,"column":null}},"24":{"start":{"line":51,"column":8},"end":{"line":64,"column":null}},"25":{"start":{"line":52,"column":28},"end":{"line":52,"column":null}},"26":{"start":{"line":53,"column":10},"end":{"line":63,"column":null}},"27":{"start":{"line":54,"column":33},"end":{"line":54,"column":null}},"28":{"start":{"line":55,"column":31},"end":{"line":55,"column":null}},"29":{"start":{"line":56,"column":12},"end":{"line":62,"column":null}},"30":{"start":{"line":56,"column":37},"end":{"line":56,"column":81}},"31":{"start":{"line":57,"column":14},"end":{"line":61,"column":null}},"32":{"start":{"line":68,"column":4},"end":{"line":68,"column":null}},"33":{"start":{"line":72,"column":4},"end":{"line":72,"column":null}},"34":{"start":{"line":72,"column":26},"end":{"line":72,"column":null}},"35":{"start":{"line":73,"column":4},"end":{"line":81,"column":null}},"36":{"start":{"line":74,"column":21},"end":{"line":74,"column":null}},"37":{"start":{"line":75,"column":20},"end":{"line":75,"column":null}},"38":{"start":{"line":76,"column":22},"end":{"line":76,"column":null}},"39":{"start":{"line":78,"column":6},"end":{"line":80,"column":null}},"40":{"start":{"line":79,"column":8},"end":{"line":79,"column":null}}},"fnMap":{"0":{"name":"evaluateMathChanges","decl":{"start":{"line":7,"column":15},"end":{"line":7,"column":null}},"loc":{"start":{"line":10,"column":61},"end":{"line":69,"column":null}},"line":10},"1":{"name":"(anonymous_1)","decl":{"start":{"line":56,"column":25},"end":{"line":56,"column":31}},"loc":{"start":{"line":56,"column":37},"end":{"line":56,"column":81}},"line":56},"2":{"name":"triggerMathEvaluation","decl":{"start":{"line":71,"column":9},"end":{"line":71,"column":31}},"loc":{"start":{"line":71,"column":49},"end":{"line":82,"column":null}},"line":71},"3":{"name":"(anonymous_3)","decl":{"start":{"line":73,"column":41},"end":{"line":73,"column":53}},"loc":{"start":{"line":73,"column":53},"end":{"line":81,"column":7}},"line":73}},"branchMap":{"0":{"loc":{"start":{"line":26,"column":6},"end":{"line":38,"column":null}},"type":"if","locations":[{"start":{"line":26,"column":6},"end":{"line":38,"column":null}},{"start":{},"end":{}}],"line":26},"1":{"loc":{"start":{"line":26,"column":10},"end":{"line":26,"column":65}},"type":"binary-expr","locations":[{"start":{"line":26,"column":10},"end":{"line":26,"column":38}},{"start":{"line":26,"column":38},"end":{"line":26,"column":65}}],"line":26},"2":{"loc":{"start":{"line":28,"column":8},"end":{"line":37,"column":null}},"type":"if","locations":[{"start":{"line":28,"column":8},"end":{"line":37,"column":null}},{"start":{},"end":{}}],"line":28},"3":{"loc":{"start":{"line":28,"column":12},"end":{"line":28,"column":78}},"type":"binary-expr","locations":[{"start":{"line":28,"column":12},"end":{"line":28,"column":20}},{"start":{"line":28,"column":20},"end":{"line":28,"column":48}},{"start":{"line":28,"column":48},"end":{"line":28,"column":78}}],"line":28},"4":{"loc":{"start":{"line":50,"column":6},"end":{"line":65,"column":null}},"type":"if","locations":[{"start":{"line":50,"column":6},"end":{"line":65,"column":null}},{"start":{},"end":{}}],"line":50},"5":{"loc":{"start":{"line":53,"column":10},"end":{"line":63,"column":null}},"type":"if","locations":[{"start":{"line":53,"column":10},"end":{"line":63,"column":null}},{"start":{},"end":{}}],"line":53},"6":{"loc":{"start":{"line":56,"column":12},"end":{"line":62,"column":null}},"type":"if","locations":[{"start":{"line":56,"column":12},"end":{"line":62,"column":null}},{"start":{},"end":{}}],"line":56},"7":{"loc":{"start":{"line":56,"column":37},"end":{"line":56,"column":81}},"type":"binary-expr","locations":[{"start":{"line":56,"column":37},"end":{"line":56,"column":61}},{"start":{"line":56,"column":61},"end":{"line":56,"column":81}}],"line":56},"8":{"loc":{"start":{"line":72,"column":4},"end":{"line":72,"column":null}},"type":"if","locations":[{"start":{"line":72,"column":4},"end":{"line":72,"column":null}},{"start":{},"end":{}}],"line":72},"9":{"loc":{"start":{"line":78,"column":6},"end":{"line":80,"column":null}},"type":"if","locations":[{"start":{"line":78,"column":6},"end":{"line":80,"column":null}},{"start":{},"end":{}}],"line":78}},"s":{"0":1,"1":5,"2":5,"3":0,"4":5,"5":5,"6":5,"7":5,"8":5,"9":9,"10":9,"11":9,"12":3,"13":3,"14":3,"15":3,"16":3,"17":9,"18":5,"19":5,"20":1,"21":1,"22":1,"23":1,"24":1,"25":1,"26":1,"27":1,"28":1,"29":1,"30":0,"31":1,"32":5,"33":0,"34":0,"35":0,"36":0,"37":0,"38":0,"39":0,"40":0},"f":{"0":1,"1":0,"2":1,"3":0},"b":{"0":[3,6],"1":[9,8],"2":[3,0],"3":[3,3,3],"4":[1,0],"5":[1,0],"6":[1,0],"7":[0,0],"8":[0,0],"9":[0,0]},"meta":{"lastBranch":10,"lastFunction":4,"lastStatement":41,"seen":{"s:5:38:5:Infinity":0,"f:7:15:7:Infinity":0,"s:12:4:16:Infinity":1,"s:13:6:13:Infinity":2,"s:15:6:15:Infinity":3,"s:17:68:17:Infinity":4,"s:20:18:20:Infinity":5,"s:21:17:21:Infinity":6,"s:22:4:41:Infinity":7,"s:22:17:22:20":8,"s:23:19:23:Infinity":9,"s:24:22:24:Infinity":10,"b:26:6:38:Infinity:undefined:undefined:undefined:undefined":0,"s:26:6:38:Infinity":11,"b:26:10:26:38:26:38:26:65":1,"s:27:21:27:Infinity":12,"b:28:8:37:Infinity:undefined:undefined:undefined:undefined":2,"s:28:8:37:Infinity":13,"b:28:12:28:20:28:20:28:48:28:48:28:78":3,"s:29:10:36:Infinity":14,"s:30:27:30:Infinity":15,"s:31:12:35:Infinity":16,"s:40:6:40:Infinity":17,"s:44:19:44:Infinity":18,"s:46:4:66:Infinity":19,"s:47:23:47:Infinity":20,"s:48:24:48:Infinity":21,"s:49:19:49:Infinity":22,"b:50:6:65:Infinity:undefined:undefined:undefined:undefined":4,"s:50:6:65:Infinity":23,"s:51:8:64:Infinity":24,"s:52:28:52:Infinity":25,"b:53:10:63:Infinity:undefined:undefined:undefined:undefined":5,"s:53:10:63:Infinity":26,"s:54:33:54:Infinity":27,"s:55:31:55:Infinity":28,"b:56:12:62:Infinity:undefined:undefined:undefined:undefined":6,"s:56:12:62:Infinity":29,"f:56:25:56:31":1,"s:56:37:56:81":30,"b:56:37:56:61:56:61:56:81":7,"s:57:14:61:Infinity":31,"s:68:4:68:Infinity":32,"f:71:9:71:31":2,"b:72:4:72:Infinity:undefined:undefined:undefined:undefined":8,"s:72:4:72:Infinity":33,"s:72:26:72:Infinity":34,"s:73:4:81:Infinity":35,"f:73:41:73:53":3,"s:74:21:74:Infinity":36,"s:75:20:75:Infinity":37,"s:76:22:76:Infinity":38,"b:78:6:80:Infinity:undefined:undefined:undefined:undefined":9,"s:78:6:80:Infinity":39,"s:79:8:79:Infinity":40},"fnNames":{}}} +,"/Users/aditya/Projects/PaperCache/src/lib/editor/VariableScope.ts": {"path":"/Users/aditya/Projects/PaperCache/src/lib/editor/VariableScope.ts","statementMap":{"0":{"start":{"line":4,"column":34},"end":{"line":4,"column":null}},"1":{"start":{"line":7,"column":53},"end":{"line":7,"column":null}},"2":{"start":{"line":8,"column":25},"end":{"line":8,"column":null}},"3":{"start":{"line":9,"column":43},"end":{"line":9,"column":null}},"4":{"start":{"line":10,"column":24},"end":{"line":10,"column":null}},"5":{"start":{"line":13,"column":4},"end":{"line":13,"column":null}},"6":{"start":{"line":13,"column":39},"end":{"line":13,"column":null}},"7":{"start":{"line":14,"column":4},"end":{"line":14,"column":null}},"8":{"start":{"line":15,"column":4},"end":{"line":15,"column":null}},"9":{"start":{"line":15,"column":31},"end":{"line":15,"column":null}},"10":{"start":{"line":16,"column":4},"end":{"line":16,"column":null}},"11":{"start":{"line":17,"column":27},"end":{"line":17,"column":null}},"12":{"start":{"line":18,"column":4},"end":{"line":56,"column":null}},"13":{"start":{"line":20,"column":6},"end":{"line":24,"column":null}},"14":{"start":{"line":21,"column":8},"end":{"line":21,"column":null}},"15":{"start":{"line":23,"column":8},"end":{"line":23,"column":null}},"16":{"start":{"line":26,"column":48},"end":{"line":26,"column":null}},"17":{"start":{"line":27,"column":20},"end":{"line":27,"column":null}},"18":{"start":{"line":29,"column":20},"end":{"line":29,"column":null}},"19":{"start":{"line":32,"column":9},"end":{"line":33,"column":null}},"20":{"start":{"line":35,"column":6},"end":{"line":46,"column":null}},"21":{"start":{"line":36,"column":21},"end":{"line":36,"column":null}},"22":{"start":{"line":37,"column":8},"end":{"line":42,"column":null}},"23":{"start":{"line":38,"column":22},"end":{"line":38,"column":null}},"24":{"start":{"line":39,"column":10},"end":{"line":39,"column":null}},"25":{"start":{"line":41,"column":10},"end":{"line":41,"column":null}},"26":{"start":{"line":43,"column":8},"end":{"line":45,"column":null}},"27":{"start":{"line":44,"column":10},"end":{"line":44,"column":null}},"28":{"start":{"line":48,"column":6},"end":{"line":48,"column":null}},"29":{"start":{"line":48,"column":48},"end":{"line":48,"column":null}},"30":{"start":{"line":49,"column":6},"end":{"line":55,"column":null}},"31":{"start":{"line":50,"column":8},"end":{"line":50,"column":null}},"32":{"start":{"line":51,"column":8},"end":{"line":54,"column":null}},"33":{"start":{"line":52,"column":10},"end":{"line":52,"column":null}},"34":{"start":{"line":53,"column":10},"end":{"line":53,"column":null}},"35":{"start":{"line":53,"column":64},"end":{"line":53,"column":null}},"36":{"start":{"line":61,"column":7},"end":{"line":61,"column":null}},"37":{"start":{"line":62,"column":4},"end":{"line":62,"column":null}}},"fnMap":{"0":{"name":"triggerScopeUpdate","decl":{"start":{"line":12,"column":9},"end":{"line":12,"column":28}},"loc":{"start":{"line":12,"column":69},"end":{"line":57,"column":null}},"line":12},"1":{"name":"(anonymous_1)","decl":{"start":{"line":18,"column":46},"end":{"line":18,"column":58}},"loc":{"start":{"line":18,"column":58},"end":{"line":56,"column":7}},"line":18},"2":{"name":"(anonymous_2)","decl":{"start":{"line":53,"column":50},"end":{"line":53,"column":64}},"loc":{"start":{"line":53,"column":64},"end":{"line":53,"column":null}},"line":53},"3":{"name":"getScope","decl":{"start":{"line":59,"column":9},"end":{"line":59,"column":45}},"loc":{"start":{"line":59,"column":45},"end":{"line":63,"column":null}},"line":59}},"branchMap":{"0":{"loc":{"start":{"line":13,"column":4},"end":{"line":13,"column":null}},"type":"if","locations":[{"start":{"line":13,"column":4},"end":{"line":13,"column":null}},{"start":{},"end":{}}],"line":13},"1":{"loc":{"start":{"line":15,"column":4},"end":{"line":15,"column":null}},"type":"if","locations":[{"start":{"line":15,"column":4},"end":{"line":15,"column":null}},{"start":{},"end":{}}],"line":15},"2":{"loc":{"start":{"line":32,"column":9},"end":{"line":33,"column":null}},"type":"binary-expr","locations":[{"start":{"line":32,"column":9},"end":{"line":32,"column":null}},{"start":{"line":33,"column":8},"end":{"line":33,"column":null}}],"line":32},"3":{"loc":{"start":{"line":43,"column":8},"end":{"line":45,"column":null}},"type":"if","locations":[{"start":{"line":43,"column":8},"end":{"line":45,"column":null}},{"start":{},"end":{}}],"line":43},"4":{"loc":{"start":{"line":48,"column":6},"end":{"line":48,"column":null}},"type":"if","locations":[{"start":{"line":48,"column":6},"end":{"line":48,"column":null}},{"start":{},"end":{}}],"line":48},"5":{"loc":{"start":{"line":49,"column":6},"end":{"line":55,"column":null}},"type":"if","locations":[{"start":{"line":49,"column":6},"end":{"line":55,"column":null}},{"start":{},"end":{}}],"line":49},"6":{"loc":{"start":{"line":49,"column":10},"end":{"line":49,"column":97}},"type":"binary-expr","locations":[{"start":{"line":49,"column":10},"end":{"line":49,"column":21}},{"start":{"line":49,"column":21},"end":{"line":49,"column":97}}],"line":49},"7":{"loc":{"start":{"line":51,"column":8},"end":{"line":54,"column":null}},"type":"if","locations":[{"start":{"line":51,"column":8},"end":{"line":54,"column":null}},{"start":{},"end":{}}],"line":51},"8":{"loc":{"start":{"line":61,"column":7},"end":{"line":61,"column":null}},"type":"binary-expr","locations":[{"start":{"line":61,"column":7},"end":{"line":61,"column":97}},{"start":{"line":61,"column":97},"end":{"line":61,"column":null}}],"line":61}},"s":{"0":1,"1":1,"2":1,"3":1,"4":1,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0,"21":0,"22":0,"23":0,"24":0,"25":0,"26":0,"27":0,"28":0,"29":0,"30":0,"31":0,"32":0,"33":0,"34":0,"35":0,"36":0,"37":0},"f":{"0":1,"1":0,"2":0,"3":1},"b":{"0":[0,0],"1":[0,0],"2":[0,0],"3":[0,0],"4":[0,0],"5":[0,0],"6":[0,0],"7":[0,0],"8":[0,0]},"meta":{"lastBranch":9,"lastFunction":4,"lastStatement":38,"seen":{"s:4:34:4:Infinity":0,"s:7:53:7:Infinity":1,"s:8:25:8:Infinity":2,"s:9:43:9:Infinity":3,"s:10:24:10:Infinity":4,"f:12:9:12:28":0,"b:13:4:13:Infinity:undefined:undefined:undefined:undefined":0,"s:13:4:13:Infinity":5,"s:13:39:13:Infinity":6,"s:14:4:14:Infinity":7,"b:15:4:15:Infinity:undefined:undefined:undefined:undefined":1,"s:15:4:15:Infinity":8,"s:15:31:15:Infinity":9,"s:16:4:16:Infinity":10,"s:17:27:17:Infinity":11,"s:18:4:56:Infinity":12,"f:18:46:18:58":1,"s:20:6:24:Infinity":13,"s:21:8:21:Infinity":14,"s:23:8:23:Infinity":15,"s:26:48:26:Infinity":16,"s:27:20:27:Infinity":17,"s:29:20:29:Infinity":18,"s:32:9:33:Infinity":19,"b:32:9:32:Infinity:33:8:33:Infinity":2,"s:35:6:46:Infinity":20,"s:36:21:36:Infinity":21,"s:37:8:42:Infinity":22,"s:38:22:38:Infinity":23,"s:39:10:39:Infinity":24,"s:41:10:41:Infinity":25,"b:43:8:45:Infinity:undefined:undefined:undefined:undefined":3,"s:43:8:45:Infinity":26,"s:44:10:44:Infinity":27,"b:48:6:48:Infinity:undefined:undefined:undefined:undefined":4,"s:48:6:48:Infinity":28,"s:48:48:48:Infinity":29,"b:49:6:55:Infinity:undefined:undefined:undefined:undefined":5,"s:49:6:55:Infinity":30,"b:49:10:49:21:49:21:49:97":6,"s:50:8:50:Infinity":31,"b:51:8:54:Infinity:undefined:undefined:undefined:undefined":7,"s:51:8:54:Infinity":32,"s:52:10:52:Infinity":33,"s:53:10:53:Infinity":34,"f:53:50:53:64":2,"s:53:64:53:Infinity":35,"f:59:9:59:45":3,"s:61:7:61:Infinity":36,"b:61:7:61:97:61:97:61:Infinity":8,"s:62:4:62:Infinity":37},"fnNames":{}}} +,"/Users/aditya/Projects/PaperCache/src/lib/editor/widgets.ts": {"path":"/Users/aditya/Projects/PaperCache/src/lib/editor/widgets.ts","statementMap":{"0":{"start":{"line":7,"column":4},"end":{"line":7,"column":null}},"1":{"start":{"line":8,"column":4},"end":{"line":8,"column":null}},"2":{"start":{"line":9,"column":4},"end":{"line":9,"column":null}},"3":{"start":{"line":13,"column":4},"end":{"line":13,"column":null}},"4":{"start":{"line":17,"column":17},"end":{"line":17,"column":null}},"5":{"start":{"line":18,"column":4},"end":{"line":18,"column":null}},"6":{"start":{"line":19,"column":4},"end":{"line":19,"column":null}},"7":{"start":{"line":20,"column":4},"end":{"line":20,"column":null}},"8":{"start":{"line":22,"column":4},"end":{"line":27,"column":null}},"9":{"start":{"line":23,"column":23},"end":{"line":23,"column":null}},"10":{"start":{"line":24,"column":6},"end":{"line":24,"column":null}},"11":{"start":{"line":25,"column":6},"end":{"line":25,"column":null}},"12":{"start":{"line":26,"column":6},"end":{"line":26,"column":null}},"13":{"start":{"line":29,"column":21},"end":{"line":29,"column":null}},"14":{"start":{"line":31,"column":4},"end":{"line":31,"column":null}},"15":{"start":{"line":32,"column":4},"end":{"line":32,"column":null}},"16":{"start":{"line":34,"column":4},"end":{"line":44,"column":null}},"17":{"start":{"line":35,"column":6},"end":{"line":35,"column":null}},"18":{"start":{"line":36,"column":6},"end":{"line":36,"column":null}},"19":{"start":{"line":37,"column":6},"end":{"line":37,"column":null}},"20":{"start":{"line":38,"column":27},"end":{"line":38,"column":null}},"21":{"start":{"line":40,"column":6},"end":{"line":40,"column":null}},"22":{"start":{"line":41,"column":6},"end":{"line":43,"column":null}},"23":{"start":{"line":42,"column":8},"end":{"line":42,"column":null}},"24":{"start":{"line":45,"column":4},"end":{"line":45,"column":null}},"25":{"start":{"line":55,"column":4},"end":{"line":55,"column":null}},"26":{"start":{"line":56,"column":4},"end":{"line":56,"column":null}},"27":{"start":{"line":57,"column":4},"end":{"line":57,"column":null}},"28":{"start":{"line":58,"column":4},"end":{"line":58,"column":null}},"29":{"start":{"line":62,"column":4},"end":{"line":62,"column":null}},"30":{"start":{"line":66,"column":17},"end":{"line":66,"column":null}},"31":{"start":{"line":67,"column":4},"end":{"line":67,"column":null}},"32":{"start":{"line":69,"column":4},"end":{"line":73,"column":null}},"33":{"start":{"line":70,"column":6},"end":{"line":70,"column":null}},"34":{"start":{"line":72,"column":6},"end":{"line":72,"column":null}},"35":{"start":{"line":75,"column":4},"end":{"line":84,"column":null}},"36":{"start":{"line":76,"column":6},"end":{"line":76,"column":null}},"37":{"start":{"line":77,"column":6},"end":{"line":77,"column":null}},"38":{"start":{"line":78,"column":19},"end":{"line":78,"column":null}},"39":{"start":{"line":79,"column":17},"end":{"line":79,"column":null}},"40":{"start":{"line":80,"column":21},"end":{"line":80,"column":null}},"41":{"start":{"line":81,"column":6},"end":{"line":83,"column":null}},"42":{"start":{"line":86,"column":4},"end":{"line":86,"column":null}},"43":{"start":{"line":93,"column":4},"end":{"line":93,"column":null}},"44":{"start":{"line":94,"column":4},"end":{"line":94,"column":null}},"45":{"start":{"line":97,"column":4},"end":{"line":97,"column":null}},"46":{"start":{"line":100,"column":17},"end":{"line":100,"column":null}},"47":{"start":{"line":101,"column":4},"end":{"line":101,"column":null}},"48":{"start":{"line":102,"column":4},"end":{"line":102,"column":null}},"49":{"start":{"line":103,"column":4},"end":{"line":103,"column":null}},"50":{"start":{"line":110,"column":4},"end":{"line":110,"column":null}},"51":{"start":{"line":111,"column":4},"end":{"line":111,"column":null}},"52":{"start":{"line":114,"column":4},"end":{"line":114,"column":null}},"53":{"start":{"line":117,"column":17},"end":{"line":117,"column":null}},"54":{"start":{"line":118,"column":4},"end":{"line":118,"column":null}},"55":{"start":{"line":119,"column":4},"end":{"line":119,"column":null}},"56":{"start":{"line":121,"column":19},"end":{"line":121,"column":null}},"57":{"start":{"line":122,"column":4},"end":{"line":122,"column":null}},"58":{"start":{"line":123,"column":4},"end":{"line":123,"column":null}},"59":{"start":{"line":124,"column":4},"end":{"line":124,"column":null}},"60":{"start":{"line":125,"column":4},"end":{"line":125,"column":null}},"61":{"start":{"line":126,"column":4},"end":{"line":126,"column":null}},"62":{"start":{"line":127,"column":4},"end":{"line":127,"column":null}},"63":{"start":{"line":128,"column":4},"end":{"line":128,"column":null}},"64":{"start":{"line":129,"column":4},"end":{"line":129,"column":null}},"65":{"start":{"line":130,"column":4},"end":{"line":130,"column":null}},"66":{"start":{"line":132,"column":4},"end":{"line":144,"column":null}},"67":{"start":{"line":133,"column":6},"end":{"line":133,"column":null}},"68":{"start":{"line":134,"column":6},"end":{"line":134,"column":null}},"69":{"start":{"line":135,"column":6},"end":{"line":135,"column":null}},"70":{"start":{"line":137,"column":6},"end":{"line":137,"column":null}},"71":{"start":{"line":138,"column":6},"end":{"line":138,"column":null}},"72":{"start":{"line":139,"column":6},"end":{"line":139,"column":null}},"73":{"start":{"line":141,"column":6},"end":{"line":143,"column":null}},"74":{"start":{"line":142,"column":8},"end":{"line":142,"column":null}},"75":{"start":{"line":146,"column":17},"end":{"line":146,"column":null}},"76":{"start":{"line":148,"column":4},"end":{"line":148,"column":null}},"77":{"start":{"line":149,"column":4},"end":{"line":149,"column":null}},"78":{"start":{"line":151,"column":4},"end":{"line":151,"column":null}},"79":{"start":{"line":162,"column":4},"end":{"line":162,"column":null}},"80":{"start":{"line":163,"column":4},"end":{"line":163,"column":null}},"81":{"start":{"line":164,"column":4},"end":{"line":164,"column":null}},"82":{"start":{"line":165,"column":4},"end":{"line":165,"column":null}},"83":{"start":{"line":166,"column":4},"end":{"line":166,"column":null}},"84":{"start":{"line":170,"column":4},"end":{"line":171,"column":null}},"85":{"start":{"line":176,"column":17},"end":{"line":176,"column":null}},"86":{"start":{"line":177,"column":4},"end":{"line":180,"column":null}},"87":{"start":{"line":182,"column":4},"end":{"line":186,"column":null}},"88":{"start":{"line":183,"column":6},"end":{"line":183,"column":null}},"89":{"start":{"line":185,"column":6},"end":{"line":185,"column":null}},"90":{"start":{"line":189,"column":4},"end":{"line":200,"column":null}},"91":{"start":{"line":190,"column":6},"end":{"line":190,"column":null}},"92":{"start":{"line":191,"column":6},"end":{"line":191,"column":null}},"93":{"start":{"line":193,"column":19},"end":{"line":193,"column":null}},"94":{"start":{"line":194,"column":17},"end":{"line":194,"column":null}},"95":{"start":{"line":195,"column":21},"end":{"line":195,"column":null}},"96":{"start":{"line":197,"column":6},"end":{"line":199,"column":null}},"97":{"start":{"line":202,"column":4},"end":{"line":202,"column":null}},"98":{"start":{"line":206,"column":4},"end":{"line":206,"column":null}},"99":{"start":{"line":212,"column":17},"end":{"line":212,"column":null}},"100":{"start":{"line":213,"column":4},"end":{"line":213,"column":null}},"101":{"start":{"line":214,"column":4},"end":{"line":214,"column":null}},"102":{"start":{"line":215,"column":4},"end":{"line":215,"column":null}}},"fnMap":{"0":{"name":"constructor","decl":{"start":{"line":6,"column":2},"end":{"line":6,"column":14}},"loc":{"start":{"line":6,"column":46},"end":{"line":10,"column":null}},"line":6},"1":{"name":"eq","decl":{"start":{"line":12,"column":2},"end":{"line":12,"column":5}},"loc":{"start":{"line":12,"column":24},"end":{"line":14,"column":null}},"line":12},"2":{"name":"toDOM","decl":{"start":{"line":16,"column":2},"end":{"line":16,"column":10}},"loc":{"start":{"line":16,"column":10},"end":{"line":46,"column":null}},"line":16},"3":{"name":"(anonymous_3)","decl":{"start":{"line":34,"column":9},"end":{"line":34,"column":20}},"loc":{"start":{"line":34,"column":26},"end":{"line":44,"column":null}},"line":34},"4":{"name":"(anonymous_4)","decl":{"start":{"line":41,"column":6},"end":{"line":41,"column":23}},"loc":{"start":{"line":41,"column":23},"end":{"line":43,"column":9}},"line":41},"5":{"name":"constructor_2","decl":{"start":{"line":54,"column":2},"end":{"line":54,"column":14}},"loc":{"start":{"line":54,"column":63},"end":{"line":59,"column":null}},"line":54},"6":{"name":"eq_2","decl":{"start":{"line":61,"column":2},"end":{"line":61,"column":5}},"loc":{"start":{"line":61,"column":28},"end":{"line":63,"column":null}},"line":61},"7":{"name":"toDOM_2","decl":{"start":{"line":65,"column":2},"end":{"line":65,"column":10}},"loc":{"start":{"line":65,"column":10},"end":{"line":87,"column":null}},"line":65},"8":{"name":"(anonymous_8)","decl":{"start":{"line":75,"column":9},"end":{"line":75,"column":20}},"loc":{"start":{"line":75,"column":26},"end":{"line":84,"column":null}},"line":75},"9":{"name":"constructor_3","decl":{"start":{"line":92,"column":2},"end":{"line":92,"column":14}},"loc":{"start":{"line":92,"column":29},"end":{"line":95,"column":null}},"line":92},"10":{"name":"eq_3","decl":{"start":{"line":96,"column":2},"end":{"line":96,"column":5}},"loc":{"start":{"line":96,"column":28},"end":{"line":98,"column":null}},"line":96},"11":{"name":"toDOM_3","decl":{"start":{"line":99,"column":2},"end":{"line":99,"column":10}},"loc":{"start":{"line":99,"column":10},"end":{"line":104,"column":null}},"line":99},"12":{"name":"constructor_4","decl":{"start":{"line":109,"column":2},"end":{"line":109,"column":14}},"loc":{"start":{"line":109,"column":29},"end":{"line":112,"column":null}},"line":109},"13":{"name":"eq_4","decl":{"start":{"line":113,"column":2},"end":{"line":113,"column":5}},"loc":{"start":{"line":113,"column":25},"end":{"line":115,"column":null}},"line":113},"14":{"name":"toDOM_4","decl":{"start":{"line":116,"column":2},"end":{"line":116,"column":10}},"loc":{"start":{"line":116,"column":10},"end":{"line":152,"column":null}},"line":116},"15":{"name":"(anonymous_15)","decl":{"start":{"line":132,"column":11},"end":{"line":132,"column":22}},"loc":{"start":{"line":132,"column":28},"end":{"line":144,"column":null}},"line":132},"16":{"name":"(anonymous_16)","decl":{"start":{"line":141,"column":6},"end":{"line":141,"column":23}},"loc":{"start":{"line":141,"column":23},"end":{"line":143,"column":9}},"line":141},"17":{"name":"constructor_5","decl":{"start":{"line":161,"column":2},"end":{"line":161,"column":14}},"loc":{"start":{"line":161,"column":81},"end":{"line":167,"column":null}},"line":161},"18":{"name":"eq_5","decl":{"start":{"line":169,"column":2},"end":{"line":169,"column":5}},"loc":{"start":{"line":169,"column":28},"end":{"line":173,"column":null}},"line":169},"19":{"name":"toDOM_5","decl":{"start":{"line":175,"column":2},"end":{"line":175,"column":10}},"loc":{"start":{"line":175,"column":10},"end":{"line":203,"column":null}},"line":175},"20":{"name":"(anonymous_20)","decl":{"start":{"line":189,"column":9},"end":{"line":189,"column":24}},"loc":{"start":{"line":189,"column":30},"end":{"line":200,"column":null}},"line":189},"21":{"name":"ignoreEvent","decl":{"start":{"line":205,"column":2},"end":{"line":205,"column":16}},"loc":{"start":{"line":205,"column":16},"end":{"line":207,"column":null}},"line":205},"22":{"name":"toDOM_6","decl":{"start":{"line":211,"column":2},"end":{"line":211,"column":10}},"loc":{"start":{"line":211,"column":10},"end":{"line":216,"column":null}},"line":211}},"branchMap":{"0":{"loc":{"start":{"line":13,"column":11},"end":{"line":13,"column":null}},"type":"binary-expr","locations":[{"start":{"line":13,"column":11},"end":{"line":13,"column":39}},{"start":{"line":13,"column":39},"end":{"line":13,"column":null}}],"line":13},"1":{"loc":{"start":{"line":22,"column":4},"end":{"line":27,"column":null}},"type":"if","locations":[{"start":{"line":22,"column":4},"end":{"line":27,"column":null}},{"start":{},"end":{}}],"line":22},"2":{"loc":{"start":{"line":62,"column":11},"end":{"line":62,"column":null}},"type":"binary-expr","locations":[{"start":{"line":62,"column":11},"end":{"line":62,"column":45}},{"start":{"line":62,"column":45},"end":{"line":62,"column":null}}],"line":62},"3":{"loc":{"start":{"line":67,"column":45},"end":{"line":67,"column":null}},"type":"cond-expr","locations":[{"start":{"line":67,"column":60},"end":{"line":67,"column":85}},{"start":{"line":67,"column":85},"end":{"line":67,"column":null}}],"line":67},"4":{"loc":{"start":{"line":69,"column":4},"end":{"line":73,"column":null}},"type":"if","locations":[{"start":{"line":69,"column":4},"end":{"line":73,"column":null}},{"start":{"line":71,"column":11},"end":{"line":73,"column":null}}],"line":69},"5":{"loc":{"start":{"line":79,"column":29},"end":{"line":79,"column":null}},"type":"cond-expr","locations":[{"start":{"line":79,"column":44},"end":{"line":79,"column":48}},{"start":{"line":79,"column":48},"end":{"line":79,"column":null}}],"line":79},"6":{"loc":{"start":{"line":80,"column":21},"end":{"line":80,"column":null}},"type":"cond-expr","locations":[{"start":{"line":80,"column":36},"end":{"line":80,"column":47}},{"start":{"line":80,"column":47},"end":{"line":80,"column":null}}],"line":80},"7":{"loc":{"start":{"line":171,"column":6},"end":{"line":171,"column":null}},"type":"binary-expr","locations":[{"start":{"line":171,"column":6},"end":{"line":171,"column":40}},{"start":{"line":171,"column":40},"end":{"line":171,"column":66}},{"start":{"line":171,"column":66},"end":{"line":171,"column":null}}],"line":171},"8":{"loc":{"start":{"line":179,"column":7},"end":{"line":179,"column":null}},"type":"cond-expr","locations":[{"start":{"line":179,"column":22},"end":{"line":179,"column":42}},{"start":{"line":179,"column":42},"end":{"line":179,"column":null}}],"line":179},"9":{"loc":{"start":{"line":180,"column":7},"end":{"line":180,"column":null}},"type":"cond-expr","locations":[{"start":{"line":180,"column":39},"end":{"line":180,"column":59}},{"start":{"line":180,"column":59},"end":{"line":180,"column":null}}],"line":180},"10":{"loc":{"start":{"line":180,"column":7},"end":{"line":180,"column":39}},"type":"binary-expr","locations":[{"start":{"line":180,"column":7},"end":{"line":180,"column":23}},{"start":{"line":180,"column":23},"end":{"line":180,"column":39}}],"line":180},"11":{"loc":{"start":{"line":182,"column":4},"end":{"line":186,"column":null}},"type":"if","locations":[{"start":{"line":182,"column":4},"end":{"line":186,"column":null}},{"start":{"line":184,"column":11},"end":{"line":186,"column":null}}],"line":182},"12":{"loc":{"start":{"line":194,"column":29},"end":{"line":194,"column":null}},"type":"cond-expr","locations":[{"start":{"line":194,"column":44},"end":{"line":194,"column":49}},{"start":{"line":194,"column":49},"end":{"line":194,"column":null}}],"line":194},"13":{"loc":{"start":{"line":195,"column":21},"end":{"line":195,"column":null}},"type":"cond-expr","locations":[{"start":{"line":195,"column":36},"end":{"line":195,"column":46}},{"start":{"line":195,"column":46},"end":{"line":195,"column":null}}],"line":195}},"s":{"0":4,"1":4,"2":4,"3":2,"4":1,"5":1,"6":1,"7":1,"8":1,"9":1,"10":1,"11":1,"12":1,"13":1,"14":1,"15":1,"16":1,"17":0,"18":0,"19":0,"20":0,"21":0,"22":0,"23":0,"24":1,"25":4,"26":4,"27":4,"28":4,"29":0,"30":4,"31":4,"32":4,"33":2,"34":2,"35":4,"36":2,"37":2,"38":2,"39":2,"40":2,"41":2,"42":4,"43":1,"44":1,"45":0,"46":1,"47":1,"48":1,"49":1,"50":1,"51":1,"52":0,"53":1,"54":1,"55":1,"56":1,"57":1,"58":1,"59":1,"60":1,"61":1,"62":1,"63":1,"64":1,"65":1,"66":1,"67":0,"68":0,"69":0,"70":0,"71":0,"72":0,"73":0,"74":0,"75":1,"76":1,"77":1,"78":1,"79":0,"80":0,"81":0,"82":0,"83":0,"84":0,"85":0,"86":0,"87":0,"88":0,"89":0,"90":0,"91":0,"92":0,"93":0,"94":0,"95":0,"96":0,"97":0,"98":0,"99":0,"100":0,"101":0,"102":0},"f":{"0":4,"1":2,"2":1,"3":0,"4":0,"5":4,"6":0,"7":4,"8":2,"9":1,"10":0,"11":1,"12":1,"13":0,"14":1,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0,"21":0,"22":0},"b":{"0":[2,1],"1":[1,0],"2":[0,0],"3":[2,2],"4":[2,2],"5":[1,1],"6":[1,1],"7":[0,0,0],"8":[0,0],"9":[0,0],"10":[0,0],"11":[0,0],"12":[0,0],"13":[0,0]},"meta":{"lastBranch":14,"lastFunction":23,"lastStatement":103,"seen":{"f:6:2:6:14":0,"s:7:4:7:Infinity":0,"s:8:4:8:Infinity":1,"s:9:4:9:Infinity":2,"f:12:2:12:5":1,"s:13:4:13:Infinity":3,"b:13:11:13:39:13:39:13:Infinity":0,"f:16:2:16:10":2,"s:17:17:17:Infinity":4,"s:18:4:18:Infinity":5,"s:19:4:19:Infinity":6,"s:20:4:20:Infinity":7,"b:22:4:27:Infinity:undefined:undefined:undefined:undefined":1,"s:22:4:27:Infinity":8,"s:23:23:23:Infinity":9,"s:24:6:24:Infinity":10,"s:25:6:25:Infinity":11,"s:26:6:26:Infinity":12,"s:29:21:29:Infinity":13,"s:31:4:31:Infinity":14,"s:32:4:32:Infinity":15,"s:34:4:44:Infinity":16,"f:34:9:34:20":3,"s:35:6:35:Infinity":17,"s:36:6:36:Infinity":18,"s:37:6:37:Infinity":19,"s:38:27:38:Infinity":20,"s:40:6:40:Infinity":21,"s:41:6:43:Infinity":22,"f:41:6:41:23":4,"s:42:8:42:Infinity":23,"s:45:4:45:Infinity":24,"f:54:2:54:14":5,"s:55:4:55:Infinity":25,"s:56:4:56:Infinity":26,"s:57:4:57:Infinity":27,"s:58:4:58:Infinity":28,"f:61:2:61:5":6,"s:62:4:62:Infinity":29,"b:62:11:62:45:62:45:62:Infinity":2,"f:65:2:65:10":7,"s:66:17:66:Infinity":30,"s:67:4:67:Infinity":31,"b:67:60:67:85:67:85:67:Infinity":3,"b:69:4:73:Infinity:71:11:73:Infinity":4,"s:69:4:73:Infinity":32,"s:70:6:70:Infinity":33,"s:72:6:72:Infinity":34,"s:75:4:84:Infinity":35,"f:75:9:75:20":8,"s:76:6:76:Infinity":36,"s:77:6:77:Infinity":37,"s:78:19:78:Infinity":38,"s:79:17:79:Infinity":39,"b:79:44:79:48:79:48:79:Infinity":5,"s:80:21:80:Infinity":40,"b:80:36:80:47:80:47:80:Infinity":6,"s:81:6:83:Infinity":41,"s:86:4:86:Infinity":42,"f:92:2:92:14":9,"s:93:4:93:Infinity":43,"s:94:4:94:Infinity":44,"f:96:2:96:5":10,"s:97:4:97:Infinity":45,"f:99:2:99:10":11,"s:100:17:100:Infinity":46,"s:101:4:101:Infinity":47,"s:102:4:102:Infinity":48,"s:103:4:103:Infinity":49,"f:109:2:109:14":12,"s:110:4:110:Infinity":50,"s:111:4:111:Infinity":51,"f:113:2:113:5":13,"s:114:4:114:Infinity":52,"f:116:2:116:10":14,"s:117:17:117:Infinity":53,"s:118:4:118:Infinity":54,"s:119:4:119:Infinity":55,"s:121:19:121:Infinity":56,"s:122:4:122:Infinity":57,"s:123:4:123:Infinity":58,"s:124:4:124:Infinity":59,"s:125:4:125:Infinity":60,"s:126:4:126:Infinity":61,"s:127:4:127:Infinity":62,"s:128:4:128:Infinity":63,"s:129:4:129:Infinity":64,"s:130:4:130:Infinity":65,"s:132:4:144:Infinity":66,"f:132:11:132:22":15,"s:133:6:133:Infinity":67,"s:134:6:134:Infinity":68,"s:135:6:135:Infinity":69,"s:137:6:137:Infinity":70,"s:138:6:138:Infinity":71,"s:139:6:139:Infinity":72,"s:141:6:143:Infinity":73,"f:141:6:141:23":16,"s:142:8:142:Infinity":74,"s:146:17:146:Infinity":75,"s:148:4:148:Infinity":76,"s:149:4:149:Infinity":77,"s:151:4:151:Infinity":78,"f:161:2:161:14":17,"s:162:4:162:Infinity":79,"s:163:4:163:Infinity":80,"s:164:4:164:Infinity":81,"s:165:4:165:Infinity":82,"s:166:4:166:Infinity":83,"f:169:2:169:5":18,"s:170:4:171:Infinity":84,"b:171:6:171:40:171:40:171:66:171:66:171:Infinity":7,"f:175:2:175:10":19,"s:176:17:176:Infinity":85,"s:177:4:180:Infinity":86,"b:179:22:179:42:179:42:179:Infinity":8,"b:180:39:180:59:180:59:180:Infinity":9,"b:180:7:180:23:180:23:180:39":10,"b:182:4:186:Infinity:184:11:186:Infinity":11,"s:182:4:186:Infinity":87,"s:183:6:183:Infinity":88,"s:185:6:185:Infinity":89,"s:189:4:200:Infinity":90,"f:189:9:189:24":20,"s:190:6:190:Infinity":91,"s:191:6:191:Infinity":92,"s:193:19:193:Infinity":93,"s:194:17:194:Infinity":94,"b:194:44:194:49:194:49:194:Infinity":12,"s:195:21:195:Infinity":95,"b:195:36:195:46:195:46:195:Infinity":13,"s:197:6:199:Infinity":96,"s:202:4:202:Infinity":97,"f:205:2:205:16":21,"s:206:4:206:Infinity":98,"f:211:2:211:10":22,"s:212:17:212:Infinity":99,"s:213:4:213:Infinity":100,"s:214:4:214:Infinity":101,"s:215:4:215:Infinity":102},"fnNames":{}}} +,"/Users/aditya/Projects/PaperCache/src/store/useAppStore.ts": {"path":"/Users/aditya/Projects/PaperCache/src/store/useAppStore.ts","statementMap":{"0":{"start":{"line":42,"column":13},"end":{"line":106,"column":null}},"1":{"start":{"line":42,"column":54},"end":{"line":106,"column":2}},"2":{"start":{"line":59,"column":4},"end":{"line":61,"column":null}},"3":{"start":{"line":59,"column":20},"end":{"line":61,"column":6}},"4":{"start":{"line":62,"column":45},"end":{"line":62,"column":null}},"5":{"start":{"line":64,"column":4},"end":{"line":66,"column":null}},"6":{"start":{"line":64,"column":20},"end":{"line":66,"column":6}},"7":{"start":{"line":69,"column":4},"end":{"line":72,"column":null}},"8":{"start":{"line":69,"column":20},"end":{"line":72,"column":6}},"9":{"start":{"line":74,"column":4},"end":{"line":79,"column":null}},"10":{"start":{"line":74,"column":20},"end":{"line":79,"column":6}},"11":{"start":{"line":80,"column":33},"end":{"line":80,"column":null}},"12":{"start":{"line":81,"column":35},"end":{"line":81,"column":null}},"13":{"start":{"line":82,"column":41},"end":{"line":82,"column":null}},"14":{"start":{"line":83,"column":43},"end":{"line":83,"column":null}},"15":{"start":{"line":85,"column":4},"end":{"line":90,"column":null}},"16":{"start":{"line":85,"column":20},"end":{"line":90,"column":6}},"17":{"start":{"line":91,"column":49},"end":{"line":91,"column":null}},"18":{"start":{"line":93,"column":4},"end":{"line":98,"column":null}},"19":{"start":{"line":93,"column":20},"end":{"line":98,"column":6}},"20":{"start":{"line":100,"column":4},"end":{"line":105,"column":null}},"21":{"start":{"line":100,"column":20},"end":{"line":105,"column":6}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":42,"column":27},"end":{"line":42,"column":45}},"loc":{"start":{"line":42,"column":54},"end":{"line":106,"column":2}},"line":42},"1":{"name":"(anonymous_1)","decl":{"start":{"line":58,"column":2},"end":{"line":58,"column":13}},"loc":{"start":{"line":59,"column":4},"end":{"line":61,"column":null}},"line":59},"2":{"name":"(anonymous_2)","decl":{"start":{"line":59,"column":4},"end":{"line":59,"column":9}},"loc":{"start":{"line":59,"column":20},"end":{"line":61,"column":6}},"line":59},"3":{"name":"(anonymous_3)","decl":{"start":{"line":62,"column":2},"end":{"line":62,"column":24}},"loc":{"start":{"line":62,"column":45},"end":{"line":62,"column":null}},"line":62},"4":{"name":"(anonymous_4)","decl":{"start":{"line":63,"column":2},"end":{"line":63,"column":17}},"loc":{"start":{"line":64,"column":4},"end":{"line":66,"column":null}},"line":64},"5":{"name":"(anonymous_5)","decl":{"start":{"line":64,"column":4},"end":{"line":64,"column":9}},"loc":{"start":{"line":64,"column":20},"end":{"line":66,"column":6}},"line":64},"6":{"name":"(anonymous_6)","decl":{"start":{"line":68,"column":2},"end":{"line":68,"column":21}},"loc":{"start":{"line":69,"column":4},"end":{"line":72,"column":null}},"line":69},"7":{"name":"(anonymous_7)","decl":{"start":{"line":69,"column":4},"end":{"line":69,"column":9}},"loc":{"start":{"line":69,"column":20},"end":{"line":72,"column":6}},"line":69},"8":{"name":"(anonymous_8)","decl":{"start":{"line":73,"column":2},"end":{"line":73,"column":25}},"loc":{"start":{"line":74,"column":4},"end":{"line":79,"column":null}},"line":74},"9":{"name":"(anonymous_9)","decl":{"start":{"line":74,"column":4},"end":{"line":74,"column":9}},"loc":{"start":{"line":74,"column":20},"end":{"line":79,"column":6}},"line":74},"10":{"name":"(anonymous_10)","decl":{"start":{"line":80,"column":2},"end":{"line":80,"column":18}},"loc":{"start":{"line":80,"column":33},"end":{"line":80,"column":null}},"line":80},"11":{"name":"(anonymous_11)","decl":{"start":{"line":81,"column":2},"end":{"line":81,"column":19}},"loc":{"start":{"line":81,"column":35},"end":{"line":81,"column":null}},"line":81},"12":{"name":"(anonymous_12)","decl":{"start":{"line":82,"column":2},"end":{"line":82,"column":22}},"loc":{"start":{"line":82,"column":41},"end":{"line":82,"column":null}},"line":82},"13":{"name":"(anonymous_13)","decl":{"start":{"line":83,"column":2},"end":{"line":83,"column":23}},"loc":{"start":{"line":83,"column":43},"end":{"line":83,"column":null}},"line":83},"14":{"name":"(anonymous_14)","decl":{"start":{"line":84,"column":2},"end":{"line":84,"column":27}},"loc":{"start":{"line":85,"column":4},"end":{"line":90,"column":null}},"line":85},"15":{"name":"(anonymous_15)","decl":{"start":{"line":85,"column":4},"end":{"line":85,"column":9}},"loc":{"start":{"line":85,"column":20},"end":{"line":90,"column":6}},"line":85},"16":{"name":"(anonymous_16)","decl":{"start":{"line":91,"column":2},"end":{"line":91,"column":26}},"loc":{"start":{"line":91,"column":49},"end":{"line":91,"column":null}},"line":91},"17":{"name":"(anonymous_17)","decl":{"start":{"line":92,"column":2},"end":{"line":92,"column":26}},"loc":{"start":{"line":93,"column":4},"end":{"line":98,"column":null}},"line":93},"18":{"name":"(anonymous_18)","decl":{"start":{"line":93,"column":4},"end":{"line":93,"column":9}},"loc":{"start":{"line":93,"column":20},"end":{"line":98,"column":6}},"line":93},"19":{"name":"(anonymous_19)","decl":{"start":{"line":99,"column":2},"end":{"line":99,"column":23}},"loc":{"start":{"line":100,"column":4},"end":{"line":105,"column":null}},"line":100},"20":{"name":"(anonymous_20)","decl":{"start":{"line":100,"column":4},"end":{"line":100,"column":9}},"loc":{"start":{"line":100,"column":20},"end":{"line":105,"column":6}},"line":100}},"branchMap":{"0":{"loc":{"start":{"line":45,"column":13},"end":{"line":45,"column":null}},"type":"binary-expr","locations":[{"start":{"line":45,"column":13},"end":{"line":45,"column":64}},{"start":{"line":45,"column":64},"end":{"line":45,"column":null}}],"line":45},"1":{"loc":{"start":{"line":60,"column":13},"end":{"line":60,"column":null}},"type":"cond-expr","locations":[{"start":{"line":60,"column":43},"end":{"line":60,"column":64}},{"start":{"line":60,"column":64},"end":{"line":60,"column":null}}],"line":60},"2":{"loc":{"start":{"line":65,"column":17},"end":{"line":65,"column":null}},"type":"cond-expr","locations":[{"start":{"line":65,"column":51},"end":{"line":65,"column":80}},{"start":{"line":65,"column":80},"end":{"line":65,"column":null}}],"line":65},"3":{"loc":{"start":{"line":71,"column":8},"end":{"line":71,"column":null}},"type":"cond-expr","locations":[{"start":{"line":71,"column":46},"end":{"line":71,"column":83}},{"start":{"line":71,"column":83},"end":{"line":71,"column":null}}],"line":71},"4":{"loc":{"start":{"line":76,"column":8},"end":{"line":78,"column":null}},"type":"cond-expr","locations":[{"start":{"line":77,"column":12},"end":{"line":77,"column":null}},{"start":{"line":78,"column":12},"end":{"line":78,"column":null}}],"line":76},"5":{"loc":{"start":{"line":87,"column":8},"end":{"line":89,"column":null}},"type":"cond-expr","locations":[{"start":{"line":88,"column":12},"end":{"line":88,"column":null}},{"start":{"line":89,"column":12},"end":{"line":89,"column":null}}],"line":87},"6":{"loc":{"start":{"line":95,"column":8},"end":{"line":97,"column":null}},"type":"cond-expr","locations":[{"start":{"line":96,"column":12},"end":{"line":96,"column":null}},{"start":{"line":97,"column":12},"end":{"line":97,"column":null}}],"line":95},"7":{"loc":{"start":{"line":102,"column":8},"end":{"line":104,"column":null}},"type":"cond-expr","locations":[{"start":{"line":103,"column":12},"end":{"line":103,"column":null}},{"start":{"line":104,"column":12},"end":{"line":104,"column":null}}],"line":102}},"s":{"0":3,"1":3,"2":2,"3":2,"4":1,"5":0,"6":0,"7":2,"8":2,"9":0,"10":0,"11":0,"12":0,"13":1,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0,"21":0},"f":{"0":3,"1":2,"2":2,"3":1,"4":0,"5":0,"6":2,"7":2,"8":0,"9":0,"10":0,"11":0,"12":1,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0},"b":{"0":[3,3],"1":[1,1],"2":[0,0],"3":[1,1],"4":[0,0],"5":[0,0],"6":[0,0],"7":[0,0]},"meta":{"lastBranch":8,"lastFunction":21,"lastStatement":22,"seen":{"s:42:13:106:Infinity":0,"f:42:27:42:45":0,"s:42:54:106:2":1,"b:45:13:45:64:45:64:45:Infinity":0,"f:58:2:58:13":1,"s:59:4:61:Infinity":2,"f:59:4:59:9":2,"s:59:20:61:6":3,"b:60:43:60:64:60:64:60:Infinity":1,"f:62:2:62:24":3,"s:62:45:62:Infinity":4,"f:63:2:63:17":4,"s:64:4:66:Infinity":5,"f:64:4:64:9":5,"s:64:20:66:6":6,"b:65:51:65:80:65:80:65:Infinity":2,"f:68:2:68:21":6,"s:69:4:72:Infinity":7,"f:69:4:69:9":7,"s:69:20:72:6":8,"b:71:46:71:83:71:83:71:Infinity":3,"f:73:2:73:25":8,"s:74:4:79:Infinity":9,"f:74:4:74:9":9,"s:74:20:79:6":10,"b:77:12:77:Infinity:78:12:78:Infinity":4,"f:80:2:80:18":10,"s:80:33:80:Infinity":11,"f:81:2:81:19":11,"s:81:35:81:Infinity":12,"f:82:2:82:22":12,"s:82:41:82:Infinity":13,"f:83:2:83:23":13,"s:83:43:83:Infinity":14,"f:84:2:84:27":14,"s:85:4:90:Infinity":15,"f:85:4:85:9":15,"s:85:20:90:6":16,"b:88:12:88:Infinity:89:12:89:Infinity":5,"f:91:2:91:26":16,"s:91:49:91:Infinity":17,"f:92:2:92:26":17,"s:93:4:98:Infinity":18,"f:93:4:93:9":18,"s:93:20:98:6":19,"b:96:12:96:Infinity:97:12:97:Infinity":6,"f:99:2:99:23":19,"s:100:4:105:Infinity":20,"f:100:4:100:9":20,"s:100:20:105:6":21,"b:103:12:103:Infinity:104:12:104:Infinity":7},"fnNames":{}}} +} diff --git a/coverage/favicon.png b/coverage/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..c1525b811a167671e9de1fa78aab9f5c0b61cef7 GIT binary patch literal 445 zcmV;u0Yd(XP))rP{nL}Ln%S7`m{0DjX9TLF* zFCb$4Oi7vyLOydb!7n&^ItCzb-%BoB`=x@N2jll2Nj`kauio%aw_@fe&*}LqlFT43 z8doAAe))z_%=P%v^@JHp3Hjhj^6*Kr_h|g_Gr?ZAa&y>wxHE99Gk>A)2MplWz2xdG zy8VD2J|Uf#EAw*bo5O*PO_}X2Tob{%bUoO2G~T`@%S6qPyc}VkhV}UifBuRk>%5v( z)x7B{I~z*k<7dv#5tC+m{km(D087J4O%+<<;K|qwefb6@GSX45wCK}Sn*> + + + + Code coverage report for All files + + + + + + + + + +
+
+

All files

+
+ +
+ 68.68% + Statements + 283/412 +
+ + +
+ 60.75% + Branches + 113/186 +
+ + +
+ 49.03% + Functions + 51/104 +
+ + +
+ 69.55% + Lines + 265/381 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
src +
+
82.75%96/11686.76%59/6836.66%11/3081.48%88/108
src/hooks +
+
92.59%75/8180%24/3089.47%17/1994.59%70/74
src/lib +
+
63.63%7/1150%2/466.66%2/360%6/10
src/lib/editor +
+
53.29%97/18232.35%22/6845.16%14/3154.85%96/175
src/store +
+
36.36%8/2237.5%6/1633.33%7/2135.71%5/14
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/prettify.css b/coverage/prettify.css new file mode 100644 index 0000000..b317a7c --- /dev/null +++ b/coverage/prettify.css @@ -0,0 +1 @@ +.pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun,.opn,.clo{color:#660}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun,.opn,.clo{color:#440}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee} diff --git a/coverage/prettify.js b/coverage/prettify.js new file mode 100644 index 0000000..b322523 --- /dev/null +++ b/coverage/prettify.js @@ -0,0 +1,2 @@ +/* eslint-disable */ +window.PR_SHOULD_USE_CONTINUATION=true;(function(){var h=["break,continue,do,else,for,if,return,while"];var u=[h,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"];var p=[u,"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"];var l=[p,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"];var x=[p,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"];var R=[x,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"];var r="all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes";var w=[p,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"];var s="caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END";var I=[h,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"];var f=[h,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"];var H=[h,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"];var A=[l,R,w,s+I,f,H];var e=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/;var C="str";var z="kwd";var j="com";var O="typ";var G="lit";var L="pun";var F="pln";var m="tag";var E="dec";var J="src";var P="atn";var n="atv";var N="nocode";var M="(?:^^\\.?|[+-]|\\!|\\!=|\\!==|\\#|\\%|\\%=|&|&&|&&=|&=|\\(|\\*|\\*=|\\+=|\\,|\\-=|\\->|\\/|\\/=|:|::|\\;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|\\?|\\@|\\[|\\^|\\^=|\\^\\^|\\^\\^=|\\{|\\||\\|=|\\|\\||\\|\\|=|\\~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\\s*";function k(Z){var ad=0;var S=false;var ac=false;for(var V=0,U=Z.length;V122)){if(!(al<65||ag>90)){af.push([Math.max(65,ag)|32,Math.min(al,90)|32])}if(!(al<97||ag>122)){af.push([Math.max(97,ag)&~32,Math.min(al,122)&~32])}}}}af.sort(function(av,au){return(av[0]-au[0])||(au[1]-av[1])});var ai=[];var ap=[NaN,NaN];for(var ar=0;arat[0]){if(at[1]+1>at[0]){an.push("-")}an.push(T(at[1]))}}an.push("]");return an.join("")}function W(al){var aj=al.source.match(new RegExp("(?:\\[(?:[^\\x5C\\x5D]|\\\\[\\s\\S])*\\]|\\\\u[A-Fa-f0-9]{4}|\\\\x[A-Fa-f0-9]{2}|\\\\[0-9]+|\\\\[^ux0-9]|\\(\\?[:!=]|[\\(\\)\\^]|[^\\x5B\\x5C\\(\\)\\^]+)","g"));var ah=aj.length;var an=[];for(var ak=0,am=0;ak=2&&ai==="["){aj[ak]=X(ag)}else{if(ai!=="\\"){aj[ak]=ag.replace(/[a-zA-Z]/g,function(ao){var ap=ao.charCodeAt(0);return"["+String.fromCharCode(ap&~32,ap|32)+"]"})}}}}return aj.join("")}var aa=[];for(var V=0,U=Z.length;V=0;){S[ac.charAt(ae)]=Y}}var af=Y[1];var aa=""+af;if(!ag.hasOwnProperty(aa)){ah.push(af);ag[aa]=null}}ah.push(/[\0-\uffff]/);V=k(ah)})();var X=T.length;var W=function(ah){var Z=ah.sourceCode,Y=ah.basePos;var ad=[Y,F];var af=0;var an=Z.match(V)||[];var aj={};for(var ae=0,aq=an.length;ae=5&&"lang-"===ap.substring(0,5);if(am&&!(ai&&typeof ai[1]==="string")){am=false;ap=J}if(!am){aj[ag]=ap}}var ab=af;af+=ag.length;if(!am){ad.push(Y+ab,ap)}else{var al=ai[1];var ak=ag.indexOf(al);var ac=ak+al.length;if(ai[2]){ac=ag.length-ai[2].length;ak=ac-al.length}var ar=ap.substring(5);B(Y+ab,ag.substring(0,ak),W,ad);B(Y+ab+ak,al,q(ar,al),ad);B(Y+ab+ac,ag.substring(ac),W,ad)}}ah.decorations=ad};return W}function i(T){var W=[],S=[];if(T.tripleQuotedStrings){W.push([C,/^(?:\'\'\'(?:[^\'\\]|\\[\s\S]|\'{1,2}(?=[^\']))*(?:\'\'\'|$)|\"\"\"(?:[^\"\\]|\\[\s\S]|\"{1,2}(?=[^\"]))*(?:\"\"\"|$)|\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$))/,null,"'\""])}else{if(T.multiLineStrings){W.push([C,/^(?:\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$)|\`(?:[^\\\`]|\\[\s\S])*(?:\`|$))/,null,"'\"`"])}else{W.push([C,/^(?:\'(?:[^\\\'\r\n]|\\.)*(?:\'|$)|\"(?:[^\\\"\r\n]|\\.)*(?:\"|$))/,null,"\"'"])}}if(T.verbatimStrings){S.push([C,/^@\"(?:[^\"]|\"\")*(?:\"|$)/,null])}var Y=T.hashComments;if(Y){if(T.cStyleComments){if(Y>1){W.push([j,/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,null,"#"])}else{W.push([j,/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\r\n]*)/,null,"#"])}S.push([C,/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,null])}else{W.push([j,/^#[^\r\n]*/,null,"#"])}}if(T.cStyleComments){S.push([j,/^\/\/[^\r\n]*/,null]);S.push([j,/^\/\*[\s\S]*?(?:\*\/|$)/,null])}if(T.regexLiterals){var X=("/(?=[^/*])(?:[^/\\x5B\\x5C]|\\x5C[\\s\\S]|\\x5B(?:[^\\x5C\\x5D]|\\x5C[\\s\\S])*(?:\\x5D|$))+/");S.push(["lang-regex",new RegExp("^"+M+"("+X+")")])}var V=T.types;if(V){S.push([O,V])}var U=(""+T.keywords).replace(/^ | $/g,"");if(U.length){S.push([z,new RegExp("^(?:"+U.replace(/[\s,]+/g,"|")+")\\b"),null])}W.push([F,/^\s+/,null," \r\n\t\xA0"]);S.push([G,/^@[a-z_$][a-z_$@0-9]*/i,null],[O,/^(?:[@_]?[A-Z]+[a-z][A-Za-z_$@0-9]*|\w+_t\b)/,null],[F,/^[a-z_$][a-z_$@0-9]*/i,null],[G,new RegExp("^(?:0x[a-f0-9]+|(?:\\d(?:_\\d+)*\\d*(?:\\.\\d*)?|\\.\\d\\+)(?:e[+\\-]?\\d+)?)[a-z]*","i"),null,"0123456789"],[F,/^\\[\s\S]?/,null],[L,/^.[^\s\w\.$@\'\"\`\/\#\\]*/,null]);return g(W,S)}var K=i({keywords:A,hashComments:true,cStyleComments:true,multiLineStrings:true,regexLiterals:true});function Q(V,ag){var U=/(?:^|\s)nocode(?:\s|$)/;var ab=/\r\n?|\n/;var ac=V.ownerDocument;var S;if(V.currentStyle){S=V.currentStyle.whiteSpace}else{if(window.getComputedStyle){S=ac.defaultView.getComputedStyle(V,null).getPropertyValue("white-space")}}var Z=S&&"pre"===S.substring(0,3);var af=ac.createElement("LI");while(V.firstChild){af.appendChild(V.firstChild)}var W=[af];function ae(al){switch(al.nodeType){case 1:if(U.test(al.className)){break}if("BR"===al.nodeName){ad(al);if(al.parentNode){al.parentNode.removeChild(al)}}else{for(var an=al.firstChild;an;an=an.nextSibling){ae(an)}}break;case 3:case 4:if(Z){var am=al.nodeValue;var aj=am.match(ab);if(aj){var ai=am.substring(0,aj.index);al.nodeValue=ai;var ah=am.substring(aj.index+aj[0].length);if(ah){var ak=al.parentNode;ak.insertBefore(ac.createTextNode(ah),al.nextSibling)}ad(al);if(!ai){al.parentNode.removeChild(al)}}}break}}function ad(ak){while(!ak.nextSibling){ak=ak.parentNode;if(!ak){return}}function ai(al,ar){var aq=ar?al.cloneNode(false):al;var ao=al.parentNode;if(ao){var ap=ai(ao,1);var an=al.nextSibling;ap.appendChild(aq);for(var am=an;am;am=an){an=am.nextSibling;ap.appendChild(am)}}return aq}var ah=ai(ak.nextSibling,0);for(var aj;(aj=ah.parentNode)&&aj.nodeType===1;){ah=aj}W.push(ah)}for(var Y=0;Y=S){ah+=2}if(V>=ap){Z+=2}}}var t={};function c(U,V){for(var S=V.length;--S>=0;){var T=V[S];if(!t.hasOwnProperty(T)){t[T]=U}else{if(window.console){console.warn("cannot override language handler %s",T)}}}}function q(T,S){if(!(T&&t.hasOwnProperty(T))){T=/^\s*]*(?:>|$)/],[j,/^<\!--[\s\S]*?(?:-\->|$)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],[L,/^(?:<[%?]|[%?]>)/],["lang-",/^]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-js",/^]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]),["default-markup","htm","html","mxml","xhtml","xml","xsl"]);c(g([[F,/^[\s]+/,null," \t\r\n"],[n,/^(?:\"[^\"]*\"?|\'[^\']*\'?)/,null,"\"'"]],[[m,/^^<\/?[a-z](?:[\w.:-]*\w)?|\/?>$/i],[P,/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^>\'\"\s]*(?:[^>\'\"\s\/]|\/(?=\s)))/],[L,/^[=<>\/]+/],["lang-js",/^on\w+\s*=\s*\"([^\"]+)\"/i],["lang-js",/^on\w+\s*=\s*\'([^\']+)\'/i],["lang-js",/^on\w+\s*=\s*([^\"\'>\s]+)/i],["lang-css",/^style\s*=\s*\"([^\"]+)\"/i],["lang-css",/^style\s*=\s*\'([^\']+)\'/i],["lang-css",/^style\s*=\s*([^\"\'>\s]+)/i]]),["in.tag"]);c(g([],[[n,/^[\s\S]+/]]),["uq.val"]);c(i({keywords:l,hashComments:true,cStyleComments:true,types:e}),["c","cc","cpp","cxx","cyc","m"]);c(i({keywords:"null,true,false"}),["json"]);c(i({keywords:R,hashComments:true,cStyleComments:true,verbatimStrings:true,types:e}),["cs"]);c(i({keywords:x,cStyleComments:true}),["java"]);c(i({keywords:H,hashComments:true,multiLineStrings:true}),["bsh","csh","sh"]);c(i({keywords:I,hashComments:true,multiLineStrings:true,tripleQuotedStrings:true}),["cv","py"]);c(i({keywords:s,hashComments:true,multiLineStrings:true,regexLiterals:true}),["perl","pl","pm"]);c(i({keywords:f,hashComments:true,multiLineStrings:true,regexLiterals:true}),["rb"]);c(i({keywords:w,cStyleComments:true,regexLiterals:true}),["js"]);c(i({keywords:r,hashComments:3,cStyleComments:true,multilineStrings:true,tripleQuotedStrings:true,regexLiterals:true}),["coffee"]);c(g([],[[C,/^[\s\S]+/]]),["regex"]);function d(V){var U=V.langExtension;try{var S=a(V.sourceNode);var T=S.sourceCode;V.sourceCode=T;V.spans=S.spans;V.basePos=0;q(U,T)(V);D(V)}catch(W){if("console" in window){console.log(W&&W.stack?W.stack:W)}}}function y(W,V,U){var S=document.createElement("PRE");S.innerHTML=W;if(U){Q(S,U)}var T={langExtension:V,numberLines:U,sourceNode:S};d(T);return S.innerHTML}function b(ad){function Y(af){return document.getElementsByTagName(af)}var ac=[Y("pre"),Y("code"),Y("xmp")];var T=[];for(var aa=0;aa=0){var ah=ai.match(ab);var am;if(!ah&&(am=o(aj))&&"CODE"===am.tagName){ah=am.className.match(ab)}if(ah){ah=ah[1]}var al=false;for(var ak=aj.parentNode;ak;ak=ak.parentNode){if((ak.tagName==="pre"||ak.tagName==="code"||ak.tagName==="xmp")&&ak.className&&ak.className.indexOf("prettyprint")>=0){al=true;break}}if(!al){var af=aj.className.match(/\blinenums\b(?::(\d+))?/);af=af?af[1]&&af[1].length?+af[1]:true:false;if(af){Q(aj,af)}S={langExtension:ah,sourceNode:aj,numberLines:af};d(S)}}}if(X]*(?:>|$)/],[PR.PR_COMMENT,/^<\!--[\s\S]*?(?:-\->|$)/],[PR.PR_PUNCTUATION,/^(?:<[%?]|[%?]>)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],["lang-",/^]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-handlebars",/^]*type\s*=\s*['"]?text\/x-handlebars-template['"]?\b[^>]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-js",/^]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i],[PR.PR_DECLARATION,/^{{[#^>/]?\s*[\w.][^}]*}}/],[PR.PR_DECLARATION,/^{{&?\s*[\w.][^}]*}}/],[PR.PR_DECLARATION,/^{{{>?\s*[\w.][^}]*}}}/],[PR.PR_COMMENT,/^{{![^}]*}}/]]),["handlebars","hbs"]);PR.registerLangHandler(PR.createSimpleLexer([[PR.PR_PLAIN,/^[ \t\r\n\f]+/,null," \t\r\n\f"]],[[PR.PR_STRING,/^\"(?:[^\n\r\f\\\"]|\\(?:\r\n?|\n|\f)|\\[\s\S])*\"/,null],[PR.PR_STRING,/^\'(?:[^\n\r\f\\\']|\\(?:\r\n?|\n|\f)|\\[\s\S])*\'/,null],["lang-css-str",/^url\(([^\)\"\']*)\)/i],[PR.PR_KEYWORD,/^(?:url|rgb|\!important|@import|@page|@media|@charset|inherit)(?=[^\-\w]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|(?:\\[0-9a-f]+ ?))(?:[_a-z0-9\-]|\\(?:\\[0-9a-f]+ ?))*)\s*:/i],[PR.PR_COMMENT,/^\/\*[^*]*\*+(?:[^\/*][^*]*\*+)*\//],[PR.PR_COMMENT,/^(?:)/],[PR.PR_LITERAL,/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],[PR.PR_LITERAL,/^#(?:[0-9a-f]{3}){1,2}/i],[PR.PR_PLAIN,/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i],[PR.PR_PUNCTUATION,/^[^\s\w\'\"]+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_KEYWORD,/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_STRING,/^[^\)\"\']+/]]),["css-str"]); diff --git a/coverage/sort-arrow-sprite.png b/coverage/sort-arrow-sprite.png new file mode 100644 index 0000000000000000000000000000000000000000..6ed68316eb3f65dec9063332d2f69bf3093bbfab GIT binary patch literal 138 zcmeAS@N?(olHy`uVBq!ia0vp^>_9Bd!3HEZxJ@+%Qh}Z>jv*C{$p!i!8j}?a+@3A= zIAGwzjijN=FBi!|L1t?LM;Q;gkwn>2cAy-KV{dn nf0J1DIvEHQu*n~6U}x}qyky7vi4|9XhBJ7&`njxgN@xNA8m%nc literal 0 HcmV?d00001 diff --git a/coverage/sorter.js b/coverage/sorter.js new file mode 100644 index 0000000..4ed70ae --- /dev/null +++ b/coverage/sorter.js @@ -0,0 +1,210 @@ +/* eslint-disable */ +var addSorting = (function() { + 'use strict'; + var cols, + currentSort = { + index: 0, + desc: false + }; + + // returns the summary table element + function getTable() { + return document.querySelector('.coverage-summary'); + } + // returns the thead element of the summary table + function getTableHeader() { + return getTable().querySelector('thead tr'); + } + // returns the tbody element of the summary table + function getTableBody() { + return getTable().querySelector('tbody'); + } + // returns the th element for nth column + function getNthColumn(n) { + return getTableHeader().querySelectorAll('th')[n]; + } + + function onFilterInput() { + const searchValue = document.getElementById('fileSearch').value; + const rows = document.getElementsByTagName('tbody')[0].children; + + // Try to create a RegExp from the searchValue. If it fails (invalid regex), + // it will be treated as a plain text search + let searchRegex; + try { + searchRegex = new RegExp(searchValue, 'i'); // 'i' for case-insensitive + } catch (error) { + searchRegex = null; + } + + for (let i = 0; i < rows.length; i++) { + const row = rows[i]; + let isMatch = false; + + if (searchRegex) { + // If a valid regex was created, use it for matching + isMatch = searchRegex.test(row.textContent); + } else { + // Otherwise, fall back to the original plain text search + isMatch = row.textContent + .toLowerCase() + .includes(searchValue.toLowerCase()); + } + + row.style.display = isMatch ? '' : 'none'; + } + } + + // loads the search box + function addSearchBox() { + var template = document.getElementById('filterTemplate'); + var templateClone = template.content.cloneNode(true); + templateClone.getElementById('fileSearch').oninput = onFilterInput; + template.parentElement.appendChild(templateClone); + } + + // loads all columns + function loadColumns() { + var colNodes = getTableHeader().querySelectorAll('th'), + colNode, + cols = [], + col, + i; + + for (i = 0; i < colNodes.length; i += 1) { + colNode = colNodes[i]; + col = { + key: colNode.getAttribute('data-col'), + sortable: !colNode.getAttribute('data-nosort'), + type: colNode.getAttribute('data-type') || 'string' + }; + cols.push(col); + if (col.sortable) { + col.defaultDescSort = col.type === 'number'; + colNode.innerHTML = + colNode.innerHTML + ''; + } + } + return cols; + } + // attaches a data attribute to every tr element with an object + // of data values keyed by column name + function loadRowData(tableRow) { + var tableCols = tableRow.querySelectorAll('td'), + colNode, + col, + data = {}, + i, + val; + for (i = 0; i < tableCols.length; i += 1) { + colNode = tableCols[i]; + col = cols[i]; + val = colNode.getAttribute('data-value'); + if (col.type === 'number') { + val = Number(val); + } + data[col.key] = val; + } + return data; + } + // loads all row data + function loadData() { + var rows = getTableBody().querySelectorAll('tr'), + i; + + for (i = 0; i < rows.length; i += 1) { + rows[i].data = loadRowData(rows[i]); + } + } + // sorts the table using the data for the ith column + function sortByIndex(index, desc) { + var key = cols[index].key, + sorter = function(a, b) { + a = a.data[key]; + b = b.data[key]; + return a < b ? -1 : a > b ? 1 : 0; + }, + finalSorter = sorter, + tableBody = document.querySelector('.coverage-summary tbody'), + rowNodes = tableBody.querySelectorAll('tr'), + rows = [], + i; + + if (desc) { + finalSorter = function(a, b) { + return -1 * sorter(a, b); + }; + } + + for (i = 0; i < rowNodes.length; i += 1) { + rows.push(rowNodes[i]); + tableBody.removeChild(rowNodes[i]); + } + + rows.sort(finalSorter); + + for (i = 0; i < rows.length; i += 1) { + tableBody.appendChild(rows[i]); + } + } + // removes sort indicators for current column being sorted + function removeSortIndicators() { + var col = getNthColumn(currentSort.index), + cls = col.className; + + cls = cls.replace(/ sorted$/, '').replace(/ sorted-desc$/, ''); + col.className = cls; + } + // adds sort indicators for current column being sorted + function addSortIndicators() { + getNthColumn(currentSort.index).className += currentSort.desc + ? ' sorted-desc' + : ' sorted'; + } + // adds event listeners for all sorter widgets + function enableUI() { + var i, + el, + ithSorter = function ithSorter(i) { + var col = cols[i]; + + return function() { + var desc = col.defaultDescSort; + + if (currentSort.index === i) { + desc = !currentSort.desc; + } + sortByIndex(i, desc); + removeSortIndicators(); + currentSort.index = i; + currentSort.desc = desc; + addSortIndicators(); + }; + }; + for (i = 0; i < cols.length; i += 1) { + if (cols[i].sortable) { + // add the click event handler on the th so users + // dont have to click on those tiny arrows + el = getNthColumn(i).querySelector('.sorter').parentElement; + if (el.addEventListener) { + el.addEventListener('click', ithSorter(i)); + } else { + el.attachEvent('onclick', ithSorter(i)); + } + } + } + } + // adds sorting functionality to the UI + return function() { + if (!getTable()) { + return; + } + cols = loadColumns(); + loadData(); + addSearchBox(); + addSortIndicators(); + enableUI(); + }; +})(); + +window.addEventListener('load', addSorting); diff --git a/coverage/src/Settings.css.html b/coverage/src/Settings.css.html new file mode 100644 index 0000000..e4863bd --- /dev/null +++ b/coverage/src/Settings.css.html @@ -0,0 +1,574 @@ + + + + + + Code coverage report for src/Settings.css + + + + + + + + + +
+
+

All files / src Settings.css

+
+ +
+ 0% + Statements + 0/0 +
+ + +
+ 0% + Branches + 0/0 +
+ + +
+ 0% + Functions + 0/0 +
+ + +
+ 0% + Lines + 0/0 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
.settings-container {
+  font-family: 'JetBrains Mono', monospace;
+  background: #1e1e1e;
+  color: #fff;
+  height: 100vh;
+  display: flex;
+  flex-direction: column;
+  padding: 30px 20px;
+  box-sizing: border-box;
+  -webkit-app-region: drag;
+}
+ 
+.settings-header {
+  margin-bottom: 30px;
+  text-align: center;
+  padding-top: 10px;
+}
+ 
+.settings-header h2 {
+  margin: 0;
+  font-size: 20px;
+  font-weight: 500;
+}
+ 
+.settings-content {
+  flex: 1;
+  -webkit-app-region: no-drag;
+  overflow-y: auto;
+  padding: 0 10px;
+}
+ 
+section {
+  background: rgba(0, 0, 0, 0.2);
+  padding: 16px;
+  border-radius: 8px;
+  margin-bottom: 20px;
+}
+ 
+section h3 {
+  margin-top: 0;
+  margin-bottom: 16px;
+  font-size: 14px;
+  color: #ccc;
+  text-transform: uppercase;
+  letter-spacing: 1px;
+}
+ 
+.setting-group {
+  margin-bottom: 20px;
+  text-align: center;
+}
+ 
+.setting-group label {
+  display: block;
+  margin-bottom: 8px;
+  font-size: 13px;
+  color: #aaa;
+}
+ 
+.setting-group input {
+  width: 100%;
+  padding: 10px;
+  border: 1px solid #333;
+  background: #2a2a2a;
+  color: #fff;
+  border-radius: 6px;
+  font-family: 'JetBrains Mono', monospace;
+  font-size: 14px;
+  box-sizing: border-box;
+  outline: none;
+  text-align: center;
+}
+ 
+.setting-group select {
+  width: 100%;
+  padding: 10px;
+  border: 1px solid #333;
+  background: #2a2a2a;
+  color: #fff;
+  border-radius: 6px;
+  font-family: 'JetBrains Mono', monospace;
+  font-size: 14px;
+  box-sizing: border-box;
+  outline: none;
+  text-align: center;
+}
+ 
+.setting-group input:focus,
+.setting-group select:focus {
+  border-color: #666;
+}
+ 
+.setting-group.color-row {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+ 
+.setting-group.color-row label {
+  margin-bottom: 0;
+}
+ 
+.setting-group.color-row input[type='color'] {
+  width: 50px;
+  height: 30px;
+  padding: 0;
+  border: none;
+  border-radius: 4px;
+  background: transparent;
+  cursor: pointer;
+}
+ 
+.save-btn {
+  flex: 1;
+  padding: 12px;
+  background: #fcfcfc;
+  color: #000;
+  border: none;
+  border-radius: 6px;
+  font-weight: bold;
+  cursor: pointer;
+}
+ 
+.save-btn:hover {
+  background: #e0e0e0;
+}
+ 
+.settings-footer {
+  margin-top: auto;
+  -webkit-app-region: no-drag;
+  display: flex;
+  gap: 10px;
+}
+ 
+.quit-btn {
+  flex: 1;
+  padding: 12px;
+  background: #2a2a2a;
+  color: #ff4444;
+  border: 1px solid #ff4444;
+  border-radius: 6px;
+  font-weight: bold;
+  cursor: pointer;
+}
+ 
+.quit-btn:hover {
+  background: rgba(255, 68, 68, 0.1);
+}
+ 
+.close-btn {
+  flex: 1;
+  padding: 12px;
+  background: #2a2a2a;
+  color: #fff;
+  border: 1px solid #666;
+  border-radius: 6px;
+  font-weight: bold;
+  cursor: pointer;
+}
+ 
+.close-btn:hover {
+  background: #333;
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/src/Settings.tsx.html b/coverage/src/Settings.tsx.html new file mode 100644 index 0000000..7c46a79 --- /dev/null +++ b/coverage/src/Settings.tsx.html @@ -0,0 +1,1087 @@ + + + + + + Code coverage report for src/Settings.tsx + + + + + + + + + +
+
+

All files / src Settings.tsx

+
+ +
+ 75.3% + Statements + 61/81 +
+ + +
+ 85.18% + Branches + 46/54 +
+ + +
+ 26.92% + Functions + 7/26 +
+ + +
+ 75% + Lines + 60/80 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 +262 +263 +264 +265 +266 +267 +268 +269 +270 +271 +272 +273 +274 +275 +276 +277 +278 +279 +280 +281 +282 +283 +284 +285 +286 +287 +288 +289 +290 +291 +292 +293 +294 +295 +296 +297 +298 +299 +300 +301 +302 +303 +304 +305 +306 +307 +308 +309 +310 +311 +312 +313 +314 +315 +316 +317 +318 +319 +320 +321 +322 +323 +324 +325 +326 +327 +328 +329 +330 +331 +332 +333 +334 +335  +  +  +  +  +9x +9x +  +9x +5x +5x +  +  +5x +  +  +  +  +5x +5x +  +9x +  +  +9x +  +  +9x +  +  +  +  +  +9x +  +  +9x +  +  +  +  +9x +  +  +  +  +9x +  +  +9x +  +  +9x +  +  +9x +9x +9x +  +9x +  +  +9x +  +  +9x +  +  +9x +9x +  +  +  +9x +1x +1x +  +1x +1x +1x +  +1x +1x +1x +1x +1x +1x +  +1x +1x +1x +1x +1x +  +  +1x +1x +1x +  +  +  +  +1x +1x +1x +1x +  +  +  +1x +1x +1x +1x +  +  +  +1x +  +1x +  +  +9x +  +  +  +9x +1x +  +  +9x +  +  +  +  +  +  +  +  +  +  +  +  +  +2x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import { useState, useEffect } from 'react'
+import { SETTINGS_KEYS } from './lib/settingsKeys'
+import './Settings.css'
+ 
+export default function Settings() {
+  const [apiKey, setApiKey] = useState('')
+  const [isApiKeySet, setIsApiKeySet] = useState(false)
+ 
+  useEffect(() => {
+    window.electronAPI.getApiKeyStatus().then((status) => {
+      setIsApiKeySet(status)
+    })
+ 
+    const handleKeyDown = (e: KeyboardEvent) => {
+      if (e.key === 'Escape') {
+        window.electronAPI.closeWindow()
+      }
+    }
+    window.addEventListener('keydown', handleKeyDown)
+    return () => window.removeEventListener('keydown', handleKeyDown)
+  }, [])
+  const [apiBaseUrl, setApiBaseUrl] = useState(
+    localStorage.getItem(SETTINGS_KEYS.API_BASE_URL) || 'https://openrouter.ai/api/v1'
+  )
+  const [apiModel, setApiModel] = useState(
+    localStorage.getItem(SETTINGS_KEYS.API_MODEL) || 'nvidia/nemotron-3-super-120b-a12b:free'
+  )
+  const [aiSystemPrompt, setAiSystemPrompt] = useState(
+    localStorage.getItem(SETTINGS_KEYS.AI_SYSTEM_PROMPT) ||
+      'Please provide a short and concise answer.'
+  )
+ 
+  // Shortcuts
+  const [globalShortcutNewNote, setGlobalShortcutNewNote] = useState(
+    localStorage.getItem(SETTINGS_KEYS.SHORTCUT_NEWNOTE) || 'CommandOrControl+Shift+N'
+  )
+  const [globalShortcutToggle, setGlobalShortcutToggle] = useState(
+    localStorage.getItem(SETTINGS_KEYS.SHORTCUT_TOGGLE) || 'CommandOrControl+Shift+C'
+  )
+ 
+  // Startup
+  const [launchAtStartup, setLaunchAtStartup] = useState(
+    localStorage.getItem(SETTINGS_KEYS.LAUNCH_STARTUP) === 'true'
+  )
+ 
+  // Appearance State
+  const [fontFamily, setFontFamily] = useState(
+    localStorage.getItem(SETTINGS_KEYS.FONT_FAMILY) || "'JetBrains Mono', monospace"
+  )
+  const [showRulings, setShowRulings] = useState(
+    localStorage.getItem(SETTINGS_KEYS.SHOW_RULINGS) !== 'false'
+  )
+  const [themePreset, setThemePreset] = useState(
+    localStorage.getItem(SETTINGS_KEYS.THEME_PRESET) || 'grid-light'
+  )
+  const [bgType, setBgType] = useState(localStorage.getItem(SETTINGS_KEYS.BG_TYPE) || 'color') // preset, color, image
+  const [bgColor, setBgColor] = useState(localStorage.getItem(SETTINGS_KEYS.BG_COLOR) || '#ffffff')
+  const [bgImage, setBgImage] = useState(localStorage.getItem(SETTINGS_KEYS.BG_IMAGE) || '')
+ 
+  const [textColor, setTextColor] = useState(
+    localStorage.getItem(SETTINGS_KEYS.TEXT_COLOR) || '#000000'
+  )
+  const [numColor, setNumColor] = useState(
+    localStorage.getItem(SETTINGS_KEYS.NUM_COLOR) || '#8ab4f8'
+  )
+  const [symColor, setSymColor] = useState(
+    localStorage.getItem(SETTINGS_KEYS.SYM_COLOR) || '#ff0000'
+  )
+  const [aiColor, setAiColor] = useState(localStorage.getItem(SETTINGS_KEYS.AI_COLOR) || '#8b5cf6')
+  const [mathColor, setMathColor] = useState(
+    localStorage.getItem(SETTINGS_KEYS.MATH_COLOR) || '#10b981'
+  )
+ 
+  const saveSettings = async () => {
+    Eif (apiKey) {
+      await window.electronAPI.setApiKey(apiKey)
+    }
+    localStorage.setItem(SETTINGS_KEYS.API_BASE_URL, apiBaseUrl)
+    localStorage.setItem(SETTINGS_KEYS.API_MODEL, apiModel)
+    localStorage.setItem(SETTINGS_KEYS.AI_SYSTEM_PROMPT, aiSystemPrompt)
+ 
+    localStorage.setItem(SETTINGS_KEYS.FONT_FAMILY, fontFamily)
+    localStorage.setItem(SETTINGS_KEYS.SHOW_RULINGS, showRulings.toString())
+    localStorage.setItem(SETTINGS_KEYS.THEME_PRESET, themePreset)
+    localStorage.setItem(SETTINGS_KEYS.BG_TYPE, bgType)
+    localStorage.setItem(SETTINGS_KEYS.BG_COLOR, bgColor)
+    localStorage.setItem(SETTINGS_KEYS.BG_IMAGE, bgImage)
+ 
+    localStorage.setItem(SETTINGS_KEYS.TEXT_COLOR, textColor)
+    localStorage.setItem(SETTINGS_KEYS.NUM_COLOR, numColor)
+    localStorage.setItem(SETTINGS_KEYS.SYM_COLOR, symColor)
+    localStorage.setItem(SETTINGS_KEYS.AI_COLOR, aiColor)
+    localStorage.setItem(SETTINGS_KEYS.MATH_COLOR, mathColor)
+ 
+    // Startup
+    localStorage.setItem(SETTINGS_KEYS.LAUNCH_STARTUP, launchAtStartup.toString())
+    Eif (window.electronAPI.setLaunchAtStartup) {
+      window.electronAPI.setLaunchAtStartup(launchAtStartup)
+    }
+ 
+    // Shortcuts
+    const oldShortcut =
+      localStorage.getItem('papercache-shortcut-newnote') || 'CommandOrControl+Shift+N'
+    localStorage.setItem('papercache-shortcut-newnote', globalShortcutNewNote)
+    Eif (window.electronAPI.updateGlobalShortcut) {
+      window.electronAPI.updateGlobalShortcut('new-note', oldShortcut, globalShortcutNewNote)
+    }
+ 
+    const oldToggleShortcut =
+      localStorage.getItem('papercache-shortcut-toggle') || 'CommandOrControl+Shift+C'
+    localStorage.setItem('papercache-shortcut-toggle', globalShortcutToggle)
+    Eif (window.electronAPI.updateGlobalShortcut) {
+      window.electronAPI.updateGlobalShortcut('toggle', oldToggleShortcut, globalShortcutToggle)
+    }
+ 
+    // Dispatch storage event manually for the same window to pick it up immediately
+    window.dispatchEvent(new Event('storage'))
+ 
+    window.electronAPI.closeWindow() // actually closes settings window
+  }
+ 
+  const closeSettings = () => {
+    window.electronAPI.closeWindow()
+  }
+ 
+  const quitApp = () => {
+    window.electronAPI.quitApp()
+  }
+ 
+  return (
+    <div className="settings-container">
+      <div className="settings-header">
+        <h2>Settings</h2>
+      </div>
+ 
+      <div className="settings-content">
+        <section>
+          <h3>AI Configuration</h3>
+          <div className="setting-group">
+            <label>API Key {isApiKeySet ? '✅ (Set)' : ''}</label>
+            <input
+              type="password"
+              value={apiKey}
+              onChange={(e) => setApiKey(e.target.value)}
+              placeholder={isApiKeySet ? 'Enter new key to replace existing' : 'sk-...'}
+            />
+          </div>
+ 
+          <div className="setting-group">
+            <label>API Base URL</label>
+            <input
+              type="text"
+              value={apiBaseUrl}
+              onChange={(e) => setApiBaseUrl(e.target.value)}
+              placeholder="https://openrouter.ai/api/v1"
+            />
+          </div>
+ 
+          <div className="setting-group">
+            <label>Model Name</label>
+            <input
+              type="text"
+              value={apiModel}
+              onChange={(e) => setApiModel(e.target.value)}
+              placeholder="nvidia/nemotron-3-super-120b-a12b:free"
+            />
+          </div>
+ 
+          <div className="setting-group">
+            <label>System Prompt (Instructions)</label>
+            <textarea
+              value={aiSystemPrompt}
+              onChange={(e) => setAiSystemPrompt(e.target.value)}
+              placeholder="e.g. Please provide a short and concise answer."
+              rows={3}
+              style={{
+                width: '100%',
+                padding: '8px',
+                background: 'rgba(128,128,128,0.1)',
+                border: '1px solid rgba(128,128,128,0.2)',
+                color: 'inherit',
+                borderRadius: '4px',
+                fontFamily: "'JetBrains Mono', monospace",
+                resize: 'vertical',
+                textAlign: 'center',
+              }}
+            />
+          </div>
+        </section>
+ 
+        <section>
+          <h3>Global Shortcuts</h3>
+          <div className="setting-group">
+            <label>Toggle App Visibility</label>
+            <input
+              type="text"
+              value={globalShortcutToggle}
+              onChange={(e) => setGlobalShortcutToggle(e.target.value)}
+              placeholder="e.g. CommandOrControl+Shift+C"
+            />
+          </div>
+          <div className="setting-group">
+            <label>New Note (Global)</label>
+            <input
+              type="text"
+              value={globalShortcutNewNote}
+              onChange={(e) => setGlobalShortcutNewNote(e.target.value)}
+              placeholder="e.g. CommandOrControl+Shift+N"
+            />
+          </div>
+        </section>
+ 
+        <section>
+          <h3>System</h3>
+          <div className="setting-group">
+            <label>Launch at Startup</label>
+            <input
+              type="checkbox"
+              checked={launchAtStartup}
+              onChange={(e) => setLaunchAtStartup(e.target.checked)}
+              style={{ width: 'auto', marginRight: 'auto' }}
+            />
+          </div>
+        </section>
+ 
+        <section>
+          <h3>Appearance</h3>
+          <div className="setting-group">
+            <label>Font Family</label>
+            <select value={fontFamily} onChange={(e) => setFontFamily(e.target.value)}>
+              <option value="'JetBrains Mono', monospace">JetBrains Mono (Default)</option>
+              <option value="Menlo, Monaco, 'Courier New', monospace">Monospace</option>
+              <option value="Inter, system-ui, -apple-system, sans-serif">
+                Sans-serif (Modern)
+              </option>
+              <option value="-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif">
+                System Default
+              </option>
+              <option value="Georgia, Cambria, 'Times New Roman', Times, serif">
+                Serif (Classic)
+              </option>
+            </select>
+          </div>
+ 
+          <div className="setting-group">
+            <label>Show Ruled Lines (Grid)</label>
+            <input
+              type="checkbox"
+              checked={showRulings}
+              onChange={(e) => setShowRulings(e.target.checked)}
+              style={{ width: 'auto', marginRight: 'auto' }}
+            />
+          </div>
+ 
+          <div className="setting-group">
+            <label>Background Type</label>
+            <select value={bgType} onChange={(e) => setBgType(e.target.value)}>
+              <option value="preset">Preset Theme</option>
+              <option value="color">Solid Color</option>
+              <option value="image">Custom Image URL</option>
+            </select>
+          </div>
+ 
+          {bgType === 'preset' && (
+            <div className="setting-group">
+              <label>Theme Preset</label>
+              <select value={themePreset} onChange={(e) => setThemePreset(e.target.value)}>
+                <option value="paper-light">Paper Light</option>
+                <option value="grid-dark">Grid Dark</option>
+                <option value="blueprint">Blueprint</option>
+              </select>
+            </div>
+          )}
+ 
+          {bgType === 'color' && (
+            <div className="setting-group color-row">
+              <label>Background Color</label>
+              <input type="color" value={bgColor} onChange={(e) => setBgColor(e.target.value)} />
+            </div>
+          )}
+ 
+          {bgType === 'image' && (
+            <div className="setting-group">
+              <label>Background Image URL</label>
+              <input
+                type="text"
+                value={bgImage}
+                onChange={(e) => setBgImage(e.target.value)}
+                placeholder="https://..."
+              />
+            </div>
+          )}
+ 
+          <div className="setting-group color-row">
+            <label>Main Text</label>
+            <input type="color" value={textColor} onChange={(e) => setTextColor(e.target.value)} />
+          </div>
+ 
+          <div className="setting-group color-row">
+            <label>Numbers</label>
+            <input type="color" value={numColor} onChange={(e) => setNumColor(e.target.value)} />
+          </div>
+ 
+          <div className="setting-group color-row">
+            <label>Math Symbols</label>
+            <input type="color" value={symColor} onChange={(e) => setSymColor(e.target.value)} />
+          </div>
+ 
+          <div className="setting-group color-row">
+            <label>Math Results (Autofill)</label>
+            <input type="color" value={mathColor} onChange={(e) => setMathColor(e.target.value)} />
+          </div>
+ 
+          <div className="setting-group color-row">
+            <label>AI Response Text</label>
+            <input type="color" value={aiColor} onChange={(e) => setAiColor(e.target.value)} />
+          </div>
+        </section>
+      </div>
+ 
+      <div className="settings-footer">
+        <button className="quit-btn" onClick={quitApp}>
+          Quit
+        </button>
+        <button className="close-btn" onClick={closeSettings}>
+          Close Settings
+        </button>
+        <button className="save-btn" onClick={saveSettings}>
+          Save Settings
+        </button>
+      </div>
+    </div>
+  )
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/src/hooks/index.html b/coverage/src/hooks/index.html new file mode 100644 index 0000000..daf2cec --- /dev/null +++ b/coverage/src/hooks/index.html @@ -0,0 +1,131 @@ + + + + + + Code coverage report for src/hooks + + + + + + + + + +
+
+

All files src/hooks

+
+ +
+ 92.59% + Statements + 75/81 +
+ + +
+ 80% + Branches + 24/30 +
+ + +
+ 89.47% + Functions + 17/19 +
+ + +
+ 94.59% + Lines + 70/74 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
useReminders.ts +
+
91.66%55/6080.76%21/2685.71%12/1492.72%51/55
useVariables.ts +
+
95.23%20/2175%3/4100%5/5100%19/19
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/src/hooks/useReminders.ts.html b/coverage/src/hooks/useReminders.ts.html new file mode 100644 index 0000000..56c7ab7 --- /dev/null +++ b/coverage/src/hooks/useReminders.ts.html @@ -0,0 +1,409 @@ + + + + + + Code coverage report for src/hooks/useReminders.ts + + + + + + + + + +
+
+

All files / src/hooks useReminders.ts

+
+ +
+ 91.66% + Statements + 55/60 +
+ + +
+ 80.76% + Branches + 21/26 +
+ + +
+ 85.71% + Functions + 12/14 +
+ + +
+ 92.72% + Lines + 51/55 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109  +  +  +  +  +8x +  +8x +  +  +8x +8x +8x +8x +8x +6x +6x +6x +  +  +  +  +  +  +  +8x +  +  +  +6x +6x +6x +6x +  +6x +  +6x +3x +2x +2x +2x +  +  +  +2x +2x +  +  +  +  +6x +2x +  +  +  +  +6x +6x +4x +3x +3x +  +  +6x +  +  +1x +1x +  +  +  +15x +5x +  +5x +5x +1x +  +  +5x +6x +6x +6x +  +  +5x +  +5x +  +  +  +  +  +  +5x +  +  +  +5x +5x +  +5x +5x +5x +5x +  +  +  + 
import { useEffect, useRef } from 'react'
+import { useAppStore, type Note } from '../store/useAppStore'
+import { SETTINGS_KEYS } from '../lib/settingsKeys'
+ 
+function parseReminders(content: string, noteId: string) {
+  const reminders: { dueAt: Date; label: string; key: string }[] = []
+  const reRem =
+    /\/(task(?:-done)?)(?:\s+\((\d{4}-\d{2}-\d{2} \d{2}:\d{2})\))?\s+(.*?)(?:\s+@\s+(\d{4}-\d{2}-\d{2}(?:\s+\d{2}:\d{2}(?::\d{2})?)?))?[ \t]*$/gm
+ 
+  let match
+  while ((match = reRem.exec(content)) !== null) {
+    const isDone = match[1] === 'task-done'
+    const label = match[3]
+    const targetStr = match[4]
+    if (!isDone && targetStr) {
+      const targetMs = new Date(targetStr).getTime()
+      Eif (!isNaN(targetMs)) {
+        reminders.push({
+          dueAt: new Date(targetMs),
+          label,
+          key: `${noteId}-${targetMs}-${label}`,
+        })
+      }
+    }
+  }
+  return reminders
+}
+ 
+function handleDueReminders(notes: Note[]) {
+  const now = Date.now()
+  const notifiedStr = localStorage.getItem(SETTINGS_KEYS.NOTIFIED_REMINDERS) || '[]'
+  const notified = new Set<string>(JSON.parse(notifiedStr))
+  let hasNewNotifs = false
+ 
+  const allReminders = notes.flatMap((n) => parseReminders(n.content, n.id))
+ 
+  for (const r of allReminders) {
+    if (now >= r.dueAt.getTime()) {
+      Eif (!notified.has(r.key)) {
+        console.log('Triggering OS notification for:', r.label)
+        new Notification('PaperCache Reminder', {
+          body: r.label,
+          silent: false,
+        })
+        notified.add(r.key)
+        hasNewNotifs = true
+      }
+    }
+  }
+ 
+  if (hasNewNotifs) {
+    localStorage.setItem(SETTINGS_KEYS.NOTIFIED_REMINDERS, JSON.stringify(Array.from(notified)))
+  }
+}
+ 
+function scheduleNextReminder(notes: Note[], callback: () => void) {
+  const now = Date.now()
+  const next = notes
+    .flatMap((n) => parseReminders(n.content, n.id))
+    .map((r) => r.dueAt.getTime())
+    .filter((t) => t > now)
+    .sort()[0]
+ 
+  if (!next) return null
+ 
+  // Ensure delay is at least 1000ms to avoid tight loops if something goes wrong
+  const delay = Math.max(next - now, 1000)
+  return setTimeout(callback, delay)
+}
+ 
+export function useReminders() {
+  const notes = useAppStore((state) => state.notes)
+  const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null)
+ 
+  useEffect(() => {
+    if (Notification.permission !== 'granted' && Notification.permission !== 'denied') {
+      Notification.requestPermission()
+    }
+ 
+    const checkAndSchedule = () => {
+      handleDueReminders(notes)
+      if (timerRef.current) clearTimeout(timerRef.current)
+      timerRef.current = scheduleNextReminder(notes, checkAndSchedule)
+    }
+ 
+    checkAndSchedule()
+ 
+    const onSuspend = () => {
+      if (timerRef.current) {
+        clearTimeout(timerRef.current)
+        timerRef.current = null
+      }
+    }
+ 
+    const onResume = () => {
+      checkAndSchedule()
+    }
+ 
+    const unsubscribeSuspend = window.electronAPI.onPowerSuspend(onSuspend)
+    const unsubscribeResume = window.electronAPI.onPowerResume(onResume)
+ 
+    return () => {
+      Iif (timerRef.current) clearTimeout(timerRef.current)
+      unsubscribeSuspend()
+      unsubscribeResume()
+    }
+  }, [notes])
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/src/hooks/useVariables.ts.html b/coverage/src/hooks/useVariables.ts.html new file mode 100644 index 0000000..020bddc --- /dev/null +++ b/coverage/src/hooks/useVariables.ts.html @@ -0,0 +1,205 @@ + + + + + + Code coverage report for src/hooks/useVariables.ts + + + + + + + + + +
+
+

All files / src/hooks useVariables.ts

+
+ +
+ 95.23% + Statements + 20/21 +
+ + +
+ 75% + Branches + 3/4 +
+ + +
+ 100% + Functions + 5/5 +
+ + +
+ 100% + Lines + 19/19 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41  +  +  +  +  +12x +  +  +4x +4x +  +4x +4x +  +4x +  +4x +  +5x +7x +7x +7x +4x +  +7x +  +1x +  +  +  +4x +4x +  +  +4x +4x +4x +  +  +  + 
import { useEffect } from 'react'
+ 
+import { useAppStore } from '../store/useAppStore'
+ 
+export function useVariables() {
+  const notes = useAppStore((state) => state.notes)
+ 
+  // Sync global variables whenever notes change
+  useEffect(() => {
+    let abort = false
+    async function syncVars() {
+      const globals: Record<string, unknown> = {}
+      const reVar = /^\/globvar\s+([a-zA-Z0-9_]+)\s*=\s*(.*)$/gm
+ 
+      let mathjs: { evaluate: (e: string, s: unknown) => unknown } | null = null
+ 
+      for (const note of notes) {
+        let varMatch
+        while ((varMatch = reVar.exec(note.content)) !== null) {
+          const name = varMatch[1]
+          try {
+            if (!mathjs) {
+              mathjs = await import('mathjs')
+            }
+            globals[name] = mathjs.evaluate(varMatch[2], globals)
+          } catch {
+            globals[name] = varMatch[2].trim()
+          }
+        }
+      }
+      Iif (abort) return
+      ;(window as unknown as { __globalVariables: Record<string, unknown> }).__globalVariables =
+        globals
+    }
+    syncVars()
+    return () => {
+      abort = true
+    }
+  }, [notes])
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/src/index.html b/coverage/src/index.html new file mode 100644 index 0000000..cb89e96 --- /dev/null +++ b/coverage/src/index.html @@ -0,0 +1,146 @@ + + + + + + Code coverage report for src + + + + + + + + + +
+
+

All files src

+
+ +
+ 82.75% + Statements + 96/116 +
+ + +
+ 86.76% + Branches + 59/68 +
+ + +
+ 36.66% + Functions + 11/30 +
+ + +
+ 81.48% + Lines + 88/108 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
Settings.css +
+
0%0/00%0/00%0/00%0/0
Settings.tsx +
+
75.3%61/8185.18%46/5426.92%7/2675%60/80
utils.ts +
+
100%35/3592.85%13/14100%4/4100%28/28
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/src/lib/editor/MathEvaluator.ts.html b/coverage/src/lib/editor/MathEvaluator.ts.html new file mode 100644 index 0000000..f168737 --- /dev/null +++ b/coverage/src/lib/editor/MathEvaluator.ts.html @@ -0,0 +1,334 @@ + + + + + + Code coverage report for src/lib/editor/MathEvaluator.ts + + + + + + + + + +
+
+

All files / src/lib/editor MathEvaluator.ts

+
+ +
+ 75.6% + Statements + 31/41 +
+ + +
+ 52.38% + Branches + 11/21 +
+ + +
+ 50% + Functions + 2/4 +
+ + +
+ 78.94% + Lines + 30/38 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84  +  +  +  +1x +  +  +  +  +  +  +5x +5x +  +  +  +5x +  +  +5x +5x +5x +9x +9x +  +9x +3x +3x +3x +3x +3x +  +  +  +  +  +  +  +  +9x +  +  +  +5x +  +5x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +  +  +  +  +  +  +  +  +  +  +5x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import type { EditorView } from '@codemirror/view'
+import { VariableScope } from './VariableScope'
+ 
+export class MathEvaluator {
+  static evalTimeout: number | null = null
+ 
+  static async evaluateMathChanges(
+    docStr: string,
+    scope: Record<string, any>
+  ): Promise<{ from: number; to: number; insert: string }[]> {
+    let mathjs
+    try {
+      mathjs = await import('mathjs')
+    } catch {
+      return []
+    }
+    const changes: { from: number; to: number; insert: string }[] = []
+ 
+    // 1. Evaluate new lines that end with '=' but don't have '\u200B' yet
+    const lines = docStr.split('\n')
+    let offset = 0
+    for (let i = 0; i < lines.length; i++) {
+      const text = lines[i]
+      const lineLen = text.length
+ 
+      if (!text.includes('\u200B') && text.trim().endsWith('=')) {
+        const expr = text.substring(0, text.lastIndexOf('=')).trim()
+        Eif (expr && !expr.startsWith('/var') && !expr.startsWith('/globvar')) {
+          try {
+            const result = String(mathjs.evaluate(expr, scope))
+            changes.push({
+              from: offset + lineLen,
+              to: offset + lineLen,
+              insert: '\u200B' + result,
+            })
+          } catch {}
+        }
+      }
+ 
+      offset += lineLen + 1 // +1 for '\n'
+    }
+ 
+    // 2. Re-evaluate existing calculations that already have '\u200B'
+    const reCalc = /^(.*?=\s*)\u200B(.*)$/gm
+    let calcMatch
+    while ((calcMatch = reCalc.exec(docStr)) !== null) {
+      const exprPart = calcMatch[1]
+      const oldResult = calcMatch[2]
+      const expr = exprPart.replace(/=\s*$/, '').trim()
+      Eif (expr) {
+        try {
+          const newResult = String(mathjs.evaluate(expr, scope))
+          Eif (newResult !== oldResult) {
+            const startReplace = calcMatch.index + exprPart.length + 1 // +1 for \u200B
+            const endReplace = calcMatch.index + calcMatch[0].length
+            Eif (!changes.some((c) => c.from <= endReplace && c.to >= startReplace)) {
+              changes.push({
+                from: startReplace,
+                to: endReplace,
+                insert: newResult,
+              })
+            }
+          }
+        } catch {}
+      }
+    }
+ 
+    return changes
+  }
+ 
+  static triggerMathEvaluation(view: EditorView) {
+    if (this.evalTimeout) window.clearTimeout(this.evalTimeout)
+    this.evalTimeout = window.setTimeout(async () => {
+      const docStr = view.state.doc.toString()
+      const scope = VariableScope.getScope()
+      const changes = await this.evaluateMathChanges(docStr, scope)
+ 
+      if (changes.length > 0) {
+        view.dispatch({ changes })
+      }
+    }, 300)
+  }
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/src/lib/editor/VariableScope.ts.html b/coverage/src/lib/editor/VariableScope.ts.html new file mode 100644 index 0000000..924571c --- /dev/null +++ b/coverage/src/lib/editor/VariableScope.ts.html @@ -0,0 +1,277 @@ + + + + + + Code coverage report for src/lib/editor/VariableScope.ts + + + + + + + + + +
+
+

All files / src/lib/editor VariableScope.ts

+
+ +
+ 13.15% + Statements + 5/38 +
+ + +
+ 0% + Branches + 0/18 +
+ + +
+ 50% + Functions + 2/4 +
+ + +
+ 14.7% + Lines + 5/34 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65  +  +  +1x +  +  +1x +1x +1x +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import type { EditorView } from '@codemirror/view'
+import { StateEffect } from '@codemirror/state'
+ 
+export const scopeChangedEffect = StateEffect.define<void>()
+ 
+export class VariableScope {
+  static globalScopeCache: Record<string, unknown> = {}
+  static lastDocString = ''
+  static scopeEvalTimeout: number | null = null
+  static scopeVersion = 0
+ 
+  static triggerScopeUpdate(docStr: string, view: EditorView | null) {
+    if (docStr === this.lastDocString) return
+    this.lastDocString = docStr
+    if (this.scopeEvalTimeout) window.clearTimeout(this.scopeEvalTimeout)
+    this.scopeVersion++
+    const currentVersion = this.scopeVersion
+    this.scopeEvalTimeout = window.setTimeout(async () => {
+      let mathjs
+      try {
+        mathjs = await import('mathjs')
+      } catch {
+        return
+      }
+ 
+      const newScope: Record<string, unknown> = {}
+      const reVar = /^\/var\s+([a-zA-Z0-9_]+)\s*=\s*(.*)$/gm
+      let varMatch
+      let changed = false
+ 
+      const globalVars =
+        (window as unknown as { __globalVariables: Record<string, unknown> }).__globalVariables ||
+        {}
+ 
+      while ((varMatch = reVar.exec(docStr)) !== null) {
+        const name = varMatch[1]
+        try {
+          const val = mathjs.evaluate(varMatch[2], Object.assign({}, globalVars, newScope))
+          newScope[name] = val
+        } catch {
+          newScope[name] = varMatch[2].trim()
+        }
+        if (this.globalScopeCache[name] !== newScope[name]) {
+          changed = true
+        }
+      }
+ 
+      if (currentVersion !== this.scopeVersion) return
+      if (changed || Object.keys(this.globalScopeCache).length !== Object.keys(newScope).length) {
+        this.globalScopeCache = newScope
+        if (view) {
+          view.dispatch({ effects: [scopeChangedEffect.of()] })
+          import('./MathEvaluator').then((m) => m.MathEvaluator.triggerMathEvaluation(view))
+        }
+      }
+    }, 300)
+  }
+ 
+  static getScope(): Record<string, unknown> {
+    const globalVars =
+      (window as unknown as { __globalVariables: Record<string, unknown> }).__globalVariables || {}
+    return Object.assign({}, globalVars, this.globalScopeCache)
+  }
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/src/lib/editor/index.html b/coverage/src/lib/editor/index.html new file mode 100644 index 0000000..12e98f3 --- /dev/null +++ b/coverage/src/lib/editor/index.html @@ -0,0 +1,146 @@ + + + + + + Code coverage report for src/lib/editor + + + + + + + + + +
+
+

All files src/lib/editor

+
+ +
+ 53.29% + Statements + 97/182 +
+ + +
+ 32.35% + Branches + 22/68 +
+ + +
+ 45.16% + Functions + 14/31 +
+ + +
+ 54.85% + Lines + 96/175 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
MathEvaluator.ts +
+
75.6%31/4152.38%11/2150%2/478.94%30/38
VariableScope.ts +
+
13.15%5/380%0/1850%2/414.7%5/34
widgets.ts +
+
59.22%61/10337.93%11/2943.47%10/2359.22%61/103
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/src/lib/editor/widgets.ts.html b/coverage/src/lib/editor/widgets.ts.html new file mode 100644 index 0000000..e2bfa45 --- /dev/null +++ b/coverage/src/lib/editor/widgets.ts.html @@ -0,0 +1,736 @@ + + + + + + Code coverage report for src/lib/editor/widgets.ts + + + + + + + + + +
+
+

All files / src/lib/editor widgets.ts

+
+ +
+ 59.22% + Statements + 61/103 +
+ + +
+ 37.93% + Branches + 11/29 +
+ + +
+ 43.47% + Functions + 10/23 +
+ + +
+ 59.22% + Lines + 61/103 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218  +  +  +  +  +  +4x +4x +4x +  +  +  +2x +  +  +  +1x +1x +1x +1x +  +1x +1x +1x +1x +1x +  +  +1x +  +1x +1x +  +1x +  +  +  +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +  +  +  +4x +4x +4x +4x +  +  +  +  +  +  +  +4x +4x +  +4x +2x +  +2x +  +  +4x +2x +2x +2x +2x +2x +2x +  +  +  +  +4x +  +  +  +  +  +  +1x +1x +  +  +  +  +  +1x +1x +1x +1x +  +  +  +  +  +  +1x +1x +  +  +  +  +  +1x +1x +1x +  +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +  +1x +1x +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import { WidgetType, EditorView } from '@codemirror/view'
+ 
+export class CopyWidget extends WidgetType {
+  code: string
+  language: string
+  constructor(code: string, language: string) {
+    super()
+    this.code = code
+    this.language = language
+  }
+ 
+  eq(other: CopyWidget) {
+    return other.code === this.code && other.language === this.language
+  }
+ 
+  toDOM() {
+    const wrap = document.createElement('span')
+    wrap.setAttribute('aria-hidden', 'true')
+    wrap.className = 'cm-copy-button'
+    wrap.title = 'Copy code'
+ 
+    Eif (this.language) {
+      const langSpan = document.createElement('sup')
+      langSpan.textContent = this.language
+      langSpan.className = 'cm-code-lang'
+      wrap.appendChild(langSpan)
+    }
+ 
+    const iconSpan = document.createElement('span')
+    // Standard copy icon (two offset rounded rectangles)
+    iconSpan.innerHTML = `<svg viewBox="0 0 24 24" width="14" height="14" stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg>`
+    wrap.appendChild(iconSpan)
+ 
+    wrap.onclick = (e) => {
+      e.preventDefault()
+      e.stopPropagation()
+      navigator.clipboard.writeText(this.code)
+      const originalHtml = iconSpan.innerHTML
+      // Checkmark icon
+      iconSpan.innerHTML = `<svg viewBox="0 0 24 24" width="14" height="14" stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"></polyline></svg>`
+      setTimeout(() => {
+        iconSpan.innerHTML = originalHtml
+      }, 2000)
+    }
+    return wrap
+  }
+}
+ 
+export class CheckboxWidget extends WidgetType {
+  checked: boolean
+  pos: number
+  view: EditorView
+ 
+  constructor(checked: boolean, pos: number, view: EditorView) {
+    super()
+    this.checked = checked
+    this.pos = pos
+    this.view = view
+  }
+ 
+  eq(other: CheckboxWidget) {
+    return other.checked === this.checked && other.pos === this.pos
+  }
+ 
+  toDOM() {
+    const wrap = document.createElement('span')
+    wrap.className = 'cm-checkbox-widget' + (this.checked ? ' cm-checkbox-checked' : '')
+ 
+    if (this.checked) {
+      wrap.innerHTML = `<svg viewBox="0 0 24 24" width="14" height="14" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"></polyline></svg>`
+    } else {
+      wrap.innerHTML = `` // empty for unchecked, border provides the box
+    }
+ 
+    wrap.onclick = (e) => {
+      e.preventDefault()
+      e.stopPropagation()
+      const from = this.pos
+      const to = this.pos + (this.checked ? 8 : 6) // length of "/checked" or "/check"
+      const insert = this.checked ? '/check' : '/checked'
+      this.view.dispatch({
+        changes: { from, to, insert },
+      })
+    }
+ 
+    return wrap
+  }
+}
+ 
+export class VariableWidget extends WidgetType {
+  value: string
+  constructor(value: string) {
+    super()
+    this.value = value
+  }
+  eq(other: VariableWidget) {
+    return other.value === this.value
+  }
+  toDOM() {
+    const span = document.createElement('span')
+    span.textContent = String(this.value)
+    span.className = 'cm-variable-pill'
+    return span
+  }
+}
+ 
+export class ColorWidget extends WidgetType {
+  color: string
+  constructor(color: string) {
+    super()
+    this.color = color
+  }
+  eq(other: ColorWidget) {
+    return other.color === this.color
+  }
+  toDOM() {
+    const span = document.createElement('span')
+    span.className = 'cm-color-pill'
+    span.style.setProperty('--pill-color', this.color)
+ 
+    const circle = document.createElement('span')
+    circle.className = 'cm-color-circle'
+    circle.style.backgroundColor = this.color
+    circle.style.width = '10px'
+    circle.style.height = '10px'
+    circle.style.borderRadius = '50%'
+    circle.style.display = 'inline-block'
+    circle.style.marginRight = '4px'
+    circle.style.cursor = 'pointer'
+    circle.title = 'Copy hex code'
+ 
+    circle.onclick = (e) => {
+      e.preventDefault()
+      e.stopPropagation()
+      navigator.clipboard.writeText(this.color)
+ 
+      span.classList.remove('flash')
+      void span.offsetWidth // Trigger reflow to restart animation if clicked quickly
+      span.classList.add('flash')
+ 
+      setTimeout(() => {
+        span.classList.remove('flash')
+      }, 500)
+    }
+ 
+    const text = document.createTextNode(this.color)
+ 
+    span.appendChild(circle)
+    span.appendChild(text)
+ 
+    return span
+  }
+}
+ 
+export class ReminderWidget extends WidgetType {
+  checked: boolean
+  overdue: boolean
+  pos: number
+  view: EditorView
+ 
+  constructor(checked: boolean, overdue: boolean, pos: number, view: EditorView) {
+    super()
+    this.checked = checked
+    this.overdue = overdue
+    this.pos = pos
+    this.view = view
+  }
+ 
+  eq(other: ReminderWidget) {
+    return (
+      other.checked === this.checked && other.pos === this.pos && other.overdue === this.overdue
+    )
+  }
+ 
+  toDOM() {
+    const wrap = document.createElement('span')
+    wrap.className =
+      'cm-rem-widget' +
+      (this.checked ? ' cm-rem-checked' : '') +
+      (this.overdue && !this.checked ? ' cm-rem-overdue' : '')
+ 
+    if (this.checked) {
+      wrap.innerHTML = `<svg viewBox="0 0 24 24" width="14" height="14" fill="currentColor"><circle cx="12" cy="12" r="8"></circle></svg>`
+    } else {
+      wrap.innerHTML = `` // empty for unchecked, border provides the box
+    }
+ 
+    // Use onmousedown to prevent CodeMirror from interfering with selection
+    wrap.onmousedown = (e) => {
+      e.preventDefault()
+      e.stopPropagation()
+ 
+      const from = this.pos
+      const to = this.pos + (this.checked ? 10 : 5) // length of "/task-done" or "/task"
+      const insert = this.checked ? '/task' : '/task-done'
+ 
+      this.view.dispatch({
+        changes: { from, to, insert },
+      })
+    }
+ 
+    return wrap
+  }
+ 
+  ignoreEvent() {
+    return true
+  }
+}
+ 
+export class ContextWidget extends WidgetType {
+  toDOM() {
+    const span = document.createElement('span')
+    span.textContent = 'Context Attached'
+    span.className = 'cm-ctx-pill'
+    return span
+  }
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/src/lib/index.html b/coverage/src/lib/index.html new file mode 100644 index 0000000..8ac68ad --- /dev/null +++ b/coverage/src/lib/index.html @@ -0,0 +1,131 @@ + + + + + + Code coverage report for src/lib + + + + + + + + + +
+
+

All files src/lib

+
+ +
+ 63.63% + Statements + 7/11 +
+ + +
+ 50% + Branches + 2/4 +
+ + +
+ 66.66% + Functions + 2/3 +
+ + +
+ 60% + Lines + 6/10 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
safeStorage.ts +
+
60%6/1050%2/466.66%2/355.55%5/9
settingsKeys.ts +
+
100%1/1100%0/0100%0/0100%1/1
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/src/lib/safeStorage.ts.html b/coverage/src/lib/safeStorage.ts.html new file mode 100644 index 0000000..c4630a3 --- /dev/null +++ b/coverage/src/lib/safeStorage.ts.html @@ -0,0 +1,139 @@ + + + + + + Code coverage report for src/lib/safeStorage.ts + + + + + + + + + +
+
+

All files / src/lib safeStorage.ts

+
+ +
+ 60% + Statements + 6/10 +
+ + +
+ 50% + Branches + 2/4 +
+ + +
+ 66.66% + Functions + 2/3 +
+ + +
+ 55.55% + Lines + 5/9 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19  +1x +1x +  +  +  +2x +2x +1x +  +  +  +  +  +  +  +  +  + 
export async function setSecure(key: string, value: string): Promise<void> {
+  const encrypted = await window.electronAPI.safeStorageEncrypt(value)
+  localStorage.setItem(`${key}-secure`, encrypted)
+}
+ 
+export async function getSecure(key: string): Promise<string | null> {
+  const encrypted = localStorage.getItem(`${key}-secure`)
+  if (!encrypted) return null
+  return await window.electronAPI.safeStorageDecrypt(encrypted)
+}
+ 
+export async function migrateApiKeyFromLocalStorage(key: string) {
+  const plain = localStorage.getItem(key)
+  if (plain) {
+    await setSecure(key, plain)
+    localStorage.removeItem(key)
+  }
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/src/lib/settingsKeys.ts.html b/coverage/src/lib/settingsKeys.ts.html new file mode 100644 index 0000000..632a173 --- /dev/null +++ b/coverage/src/lib/settingsKeys.ts.html @@ -0,0 +1,145 @@ + + + + + + Code coverage report for src/lib/settingsKeys.ts + + + + + + + + + +
+
+

All files / src/lib settingsKeys.ts

+
+ +
+ 100% + Statements + 1/1 +
+ + +
+ 100% + Branches + 0/0 +
+ + +
+ 100% + Functions + 0/0 +
+ + +
+ 100% + Lines + 1/1 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +212x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
export const SETTINGS_KEYS = {
+  THEME_PRESET: 'papercache-theme-preset',
+  FONT_FAMILY: 'papercache-font',
+  SHOW_RULINGS: 'papercache-rulings',
+  BG_TYPE: 'papercache-bg-type',
+  BG_COLOR: 'papercache-bg-color',
+  BG_IMAGE: 'papercache-bg-image',
+  TEXT_COLOR: 'papercache-color-text',
+  NUM_COLOR: 'papercache-color-num',
+  SYM_COLOR: 'papercache-color-sym',
+  AI_COLOR: 'papercache-ai-color',
+  MATH_COLOR: 'papercache-math-color',
+  API_BASE_URL: 'papercache-api-base-url',
+  API_MODEL: 'papercache-api-model',
+  AI_SYSTEM_PROMPT: 'papercache-ai-system-prompt',
+  SHORTCUT_NEWNOTE: 'papercache-shortcut-newnote',
+  SHORTCUT_TOGGLE: 'papercache-shortcut-toggle',
+  LAUNCH_STARTUP: 'papercache-launch-startup',
+  NOTIFIED_REMINDERS: 'papercache_notified',
+} as const
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/src/store/index.html b/coverage/src/store/index.html new file mode 100644 index 0000000..3333ff9 --- /dev/null +++ b/coverage/src/store/index.html @@ -0,0 +1,116 @@ + + + + + + Code coverage report for src/store + + + + + + + + + +
+
+

All files src/store

+
+ +
+ 36.36% + Statements + 8/22 +
+ + +
+ 37.5% + Branches + 6/16 +
+ + +
+ 33.33% + Functions + 7/21 +
+ + +
+ 35.71% + Lines + 5/14 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
useAppStore.ts +
+
36.36%8/2237.5%6/1633.33%7/2135.71%5/14
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/src/store/useAppStore.ts.html b/coverage/src/store/useAppStore.ts.html new file mode 100644 index 0000000..cc8fb50 --- /dev/null +++ b/coverage/src/store/useAppStore.ts.html @@ -0,0 +1,403 @@ + + + + + + Code coverage report for src/store/useAppStore.ts + + + + + + + + + +
+
+

All files / src/store useAppStore.ts

+
+ +
+ 36.36% + Statements + 8/22 +
+ + +
+ 37.5% + Branches + 6/16 +
+ + +
+ 33.33% + Functions + 7/21 +
+ + +
+ 35.71% + Lines + 5/14 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +3x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +2x +  +  +1x +  +  +  +  +  +  +2x +  +  +  +  +  +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import { create } from 'zustand'
+ 
+export interface Note {
+  id: string
+  content: string
+  mtime: number
+}
+ 
+interface AppState {
+  notes: Note[]
+  currentNoteIndex: number
+  zoomLevel: number
+ 
+  // UI state
+  showGraphView: boolean
+  showRemindersView: boolean
+  isRenaming: boolean
+  renameValue: string
+  showNoteSearch: boolean
+  noteSearchQuery: string
+  searchSelectedIndex: number
+  showNoteActionMenu: boolean
+  showMainActionMenu: boolean
+  actionMenuIndex: number
+ 
+  setNotes: (notes: Note[] | ((prev: Note[]) => Note[])) => void
+  setCurrentNoteIndex: (index: number) => void
+  setZoomLevel: (zoom: number | ((prev: number) => number)) => void
+ 
+  setShowGraphView: (show: boolean | ((prev: boolean) => boolean)) => void
+  setShowRemindersView: (show: boolean | ((prev: boolean) => boolean)) => void
+  setIsRenaming: (isRenaming: boolean) => void
+  setRenameValue: (renameValue: string) => void
+  setShowNoteSearch: (show: boolean) => void
+  setNoteSearchQuery: (query: string) => void
+  setSearchSelectedIndex: (index: number | ((prev: number) => number)) => void
+  setShowNoteActionMenu: (show: boolean) => void
+  setShowMainActionMenu: (show: boolean | ((prev: boolean) => boolean)) => void
+  setActionMenuIndex: (index: number | ((prev: number) => number)) => void
+}
+ 
+export const useAppStore = create<AppState>((set) => ({
+  notes: [],
+  currentNoteIndex: 0,
+  zoomLevel: Number(localStorage.getItem('papercache-zoom')) || 1,
+ 
+  showGraphView: false,
+  showRemindersView: false,
+  isRenaming: false,
+  renameValue: '',
+  showNoteSearch: false,
+  noteSearchQuery: '',
+  searchSelectedIndex: 0,
+  showNoteActionMenu: false,
+  showMainActionMenu: false,
+  actionMenuIndex: 0,
+ 
+  setNotes: (notes) =>
+    set((state) => ({
+      notes: typeof notes === 'function' ? notes(state.notes) : notes,
+    })),
+  setCurrentNoteIndex: (currentNoteIndex) => set({ currentNoteIndex }),
+  setZoomLevel: (zoomLevel) =>
+    set((state) => ({
+      zoomLevel: typeof zoomLevel === 'function' ? zoomLevel(state.zoomLevel) : zoomLevel,
+    })),
+ 
+  setShowGraphView: (showGraphView) =>
+    set((state) => ({
+      showGraphView:
+        typeof showGraphView === 'function' ? showGraphView(state.showGraphView) : showGraphView,
+    })),
+  setShowRemindersView: (showRemindersView) =>
+    set((state) => ({
+      showRemindersView:
+        typeof showRemindersView === 'function'
+          ? showRemindersView(state.showRemindersView)
+          : showRemindersView,
+    })),
+  setIsRenaming: (isRenaming) => set({ isRenaming }),
+  setRenameValue: (renameValue) => set({ renameValue }),
+  setShowNoteSearch: (showNoteSearch) => set({ showNoteSearch }),
+  setNoteSearchQuery: (noteSearchQuery) => set({ noteSearchQuery }),
+  setSearchSelectedIndex: (searchSelectedIndex) =>
+    set((state) => ({
+      searchSelectedIndex:
+        typeof searchSelectedIndex === 'function'
+          ? searchSelectedIndex(state.searchSelectedIndex)
+          : searchSelectedIndex,
+    })),
+  setShowNoteActionMenu: (showNoteActionMenu) => set({ showNoteActionMenu }),
+  setShowMainActionMenu: (showMainActionMenu) =>
+    set((state) => ({
+      showMainActionMenu:
+        typeof showMainActionMenu === 'function'
+          ? showMainActionMenu(state.showMainActionMenu)
+          : showMainActionMenu,
+    })),
+  setActionMenuIndex: (actionMenuIndex) =>
+    set((state) => ({
+      actionMenuIndex:
+        typeof actionMenuIndex === 'function'
+          ? actionMenuIndex(state.actionMenuIndex)
+          : actionMenuIndex,
+    })),
+}))
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/src/utils.ts.html b/coverage/src/utils.ts.html new file mode 100644 index 0000000..a467a9e --- /dev/null +++ b/coverage/src/utils.ts.html @@ -0,0 +1,205 @@ + + + + + + Code coverage report for src/utils.ts + + + + + + + + + +
+
+

All files / src utils.ts

+
+ +
+ 100% + Statements + 35/35 +
+ + +
+ 92.85% + Branches + 13/14 +
+ + +
+ 100% + Functions + 4/4 +
+ + +
+ 100% + Lines + 28/28 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +411x +9x +8x +8x +8x +  +  +8x +  +7x +  +4x +4x +  +4x +  +7x +7x +3x +3x +3x +4x +4x +4x +4x +3x +3x +  +  +  +4x +20x +4x +  +  +7x +7x +7x +7x +  + 
export const getFolderColor = (str: string): string => {
+  if (!str) return '#ffffff'
+  let colors: Record<string, string> = {}
+  try {
+    colors = JSON.parse(localStorage.getItem('papercache-folder-colors') || '{}')
+  } catch {}
+ 
+  if (colors[str]) return colors[str]
+ 
+  const usedHues = Object.values(colors)
+    .map((c) => {
+      const match = c.match(/hsl\((\d+)/)
+      return match ? parseInt(match[1]) : null
+    })
+    .filter((h) => h !== null) as number[]
+ 
+  let bestHue = 0
+  if (usedHues.length > 0) {
+    usedHues.sort((a, b) => a - b)
+    let maxDist = 0
+    for (let i = 0; i < usedHues.length; i++) {
+      const next = (i + 1) % usedHues.length
+      let dist = usedHues[next] - usedHues[i]
+      if (dist <= 0) dist += 360
+      if (dist > maxDist) {
+        maxDist = dist
+        bestHue = (usedHues[i] + dist / 2) % 360
+      }
+    }
+  } else {
+    let hash = 0
+    for (let i = 0; i < str.length; i++) hash = str.charCodeAt(i) + ((hash << 5) - hash)
+    bestHue = Math.abs(hash % 360)
+  }
+ 
+  const color = `hsl(${Math.round(bestHue)}, 70%, 60%)`
+  colors[str] = color
+  localStorage.setItem('papercache-folder-colors', JSON.stringify(colors))
+  return color
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/electron/main.ts b/electron/main.ts index 43e750f..5e86328 100644 --- a/electron/main.ts +++ b/electron/main.ts @@ -356,17 +356,32 @@ app.on('web-contents-created', (event, contents) => { app.whenReady().then(() => { // Content Security Policy - const isDev = !!process.env.VITE_DEV_SERVER_URL + const isDev = !!process.env.VITE_DEV_SERVER_URL; session.defaultSession.webRequest.onHeadersReceived((details, callback) => { + const isDevCSP = + "default-src 'none'; " + + "script-src 'self' 'unsafe-eval' 'unsafe-inline'; " + + "style-src 'self' 'unsafe-inline'; " + + "img-src 'self' data: https:; " + + "connect-src 'self' https: wss:; " + + "font-src 'self' data: https:; " + + "object-src 'none'; " + + "base-uri 'none';" + const isProdCSP = + "default-src 'none'; " + + "script-src 'self' 'unsafe-eval'; " + + "style-src 'self' 'unsafe-inline'; " + + "img-src 'self' data: https:; " + + "connect-src 'self' https:; " + + "font-src 'self' data: https:; " + + "object-src 'none'; " + + "base-uri 'none';" + callback({ responseHeaders: { ...details.responseHeaders, // unsafe-eval is required for mathjs dynamic compilation - 'Content-Security-Policy': [ - isDev - ? "default-src 'none'; script-src 'self' 'unsafe-eval' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; connect-src 'self' https: wss:; font-src 'self' data: https:; object-src 'none'; base-uri 'none';" - : "default-src 'none'; script-src 'self' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; connect-src 'self' https:; font-src 'self' data: https:; object-src 'none'; base-uri 'none';", - ], + 'Content-Security-Policy': [isDev ? isDevCSP : isProdCSP], }, }) }) @@ -651,24 +666,26 @@ try { } else { memoryApiKey = file } -} catch {} +} catch { + // Empty +} ipcMain.handle('set-api-key', (_, key: string) => { - memoryApiKey = key + memoryApiKey = key; try { - const dataToSave = safeStorage.isEncryptionAvailable() - ? safeStorage.encryptString(key).toString('base64') + const dataToSave = safeStorage.isEncryptionAvailable() + ? safeStorage.encryptString(key).toString('base64') : key fs.writeFileSync(path.join(NOTES_DIR, 'config.enc'), dataToSave) return true - } catch (e) { - console.error('Failed to save API key:', e) + } catch (err) { + console.error('Failed to set API key:', err) return false } }) ipcMain.handle('get-api-key-status', () => { - return !!memoryApiKey && memoryApiKey.length > 0; + return !!memoryApiKey && memoryApiKey.length > 0 }) ipcMain.on('check-for-updates', () => { diff --git a/src/App.tsx b/src/App.tsx index 3e1bc57..3d242c5 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -6,6 +6,7 @@ import { RemindersPage } from './components/RemindersPage' import { useAppStore } from './store/useAppStore' import { useSettingsStore } from './store/useSettingsStore' +import { useAIStore } from './store/useAIStore' import { useNoteStorage } from './hooks/useNoteStorage' import { useVariables } from './hooks/useVariables' @@ -15,7 +16,7 @@ import { useGlobalHotkey } from './hooks/useGlobalHotkey' import { NoteSearch } from './components/NoteSearch' import { MainActionMenu } from './components/MainActionMenu' import { NoteTitleBar } from './components/NoteTitleBar' -import { Editor, EditorRef } from './components/Editor' +import { Editor, type EditorRef } from './components/Editor' function App() { const notes = useAppStore((state) => state.notes) @@ -29,7 +30,8 @@ function App() { const showNoteSearch = useAppStore((state) => state.showNoteSearch) const setShowMainActionMenu = useAppStore((state) => state.setShowMainActionMenu) - const { fontFamily, bgType, bgColor, bgImage } = useSettingsStore() + const { themePreset, fontFamily, showRulings, bgType, bgColor, bgImage, textColor, numColor } = + useSettingsStore() const editorRef = useRef(null) diff --git a/src/Settings.test.tsx b/src/Settings.test.tsx index 233e8a8..8d85536 100644 --- a/src/Settings.test.tsx +++ b/src/Settings.test.tsx @@ -1,5 +1,5 @@ import { describe, it, expect, vi, beforeEach } from 'vitest' -import { render, screen, fireEvent, waitFor } from '@testing-library/react' +import { render, screen, fireEvent, waitFor, act } from '@testing-library/react' import Settings from './Settings' describe('Settings Component', () => { @@ -17,8 +17,11 @@ describe('Settings Component', () => { } as any // eslint-disable-line @typescript-eslint/no-explicit-any }) - it('renders settings headers correctly', () => { - render() + it('renders settings headers correctly', async () => { + await act(async () => { + render() + }) + expect(screen.getByText('Settings')).toBeInTheDocument() expect(screen.getByText('AI Configuration')).toBeInTheDocument() expect(screen.getByText('Global Shortcuts')).toBeInTheDocument() @@ -28,14 +31,18 @@ describe('Settings Component', () => { it('loads API key status from IPC', async () => { ;(window.electronAPI.getApiKeyStatus as any).mockResolvedValue(true) - render() + await act(async () => { + render() + }) - await waitFor(() => expect(screen.getByText('API Key ✅ (Set)')).toBeInTheDocument()) + expect(screen.getByText('API Key ✅ (Set)')).toBeInTheDocument() expect(screen.getByPlaceholderText('Enter new key to replace existing')).toBeInTheDocument() }) - it('updates state when inputs change', () => { - render() + it('updates state when inputs change', async () => { + await act(async () => { + render() + }) const apiKeyInput = screen.getByPlaceholderText('sk-...') fireEvent.change(apiKeyInput, { target: { value: 'sk-new-key' } }) @@ -44,7 +51,9 @@ describe('Settings Component', () => { }) it('saves settings to IPC on Save Settings button click', async () => { - render() + await act(async () => { + render() + }) const apiKeyInput = screen.getByPlaceholderText('sk-...') fireEvent.change(apiKeyInput, { target: { value: 'sk-new-key' } }) @@ -58,8 +67,10 @@ describe('Settings Component', () => { }) }) - it('calls quitApp when Quit PaperCache is clicked', () => { - render() + it('calls quitApp when Quit PaperCache is clicked', async () => { + await act(async () => { + render() + }) const quitButton = screen.getByText('Quit') fireEvent.click(quitButton) diff --git a/src/Settings.tsx b/src/Settings.tsx index 0b64053..e4741e7 100644 --- a/src/Settings.tsx +++ b/src/Settings.tsx @@ -72,13 +72,19 @@ export default function Settings() { ) const saveSettings = async () => { - if (apiKey) { - await window.electronAPI.setApiKey(apiKey) - } localStorage.setItem(SETTINGS_KEYS.API_BASE_URL, apiBaseUrl) localStorage.setItem(SETTINGS_KEYS.API_MODEL, apiModel) localStorage.setItem(SETTINGS_KEYS.AI_SYSTEM_PROMPT, aiSystemPrompt) + if (apiKey) { + const success = await window.electronAPI.setApiKey(apiKey) + if (!success) { + alert('Failed to save API key securely. Check console.') + } + } else { + await window.electronAPI.setApiKey('') // clear key + } + localStorage.setItem(SETTINGS_KEYS.FONT_FAMILY, fontFamily) localStorage.setItem(SETTINGS_KEYS.SHOW_RULINGS, showRulings.toString()) localStorage.setItem(SETTINGS_KEYS.THEME_PRESET, themePreset) diff --git a/src/components/Editor.tsx b/src/components/Editor.tsx index 929c23a..1f34657 100644 --- a/src/components/Editor.tsx +++ b/src/components/Editor.tsx @@ -1,17 +1,21 @@ import { useCallback, useRef, useEffect, forwardRef, useImperativeHandle } from 'react' import CodeMirror from '@uiw/react-codemirror' import { ViewUpdate } from '@codemirror/view' -import { useAppStore } from '../../store/useAppStore' -import { useSettingsStore } from '../../store/useSettingsStore' -import { MathEvaluator } from './MathEvaluator' -import { useEditorExtensions } from './extensions' +import { useAppStore } from '../store/useAppStore' +import { useSettingsStore } from '../store/useSettingsStore' +import { MathEvaluator } from '../lib/editor/MathEvaluator' +import { useEditorExtensions } from '../lib/editor/extensions' + +import { type TransactionSpec } from '@codemirror/state' +import { EditorView } from '@codemirror/view' export interface EditorRef { - dispatch: (tx: any) => void + dispatch: (tx: TransactionSpec) => void focus: () => void + view?: EditorView } -export const Editor = forwardRef((props, ref) => { +export const Editor = forwardRef((_props, ref) => { const notes = useAppStore((state) => state.notes) const setNotes = useAppStore((state) => state.setNotes) const currentNoteIndex = useAppStore((state) => state.currentNoteIndex) @@ -19,10 +23,10 @@ export const Editor = forwardRef((props, ref) => { const themePreset = useSettingsStore((state) => state.themePreset) - const editorRef = useRef(null) + const editorRef = useRef(null) useImperativeHandle(ref, () => ({ - dispatch: (tx: any) => { + dispatch: (tx: TransactionSpec) => { if (editorRef.current?.view) { editorRef.current.view.dispatch(tx) } @@ -36,12 +40,17 @@ export const Editor = forwardRef((props, ref) => { const handleEditorChange = useCallback( (val: string, viewUpdate?: ViewUpdate) => { - const updatedNotes = [...notes] - if (updatedNotes[currentNoteIndex]) { - updatedNotes[currentNoteIndex].content = val - setNotes(updatedNotes) - window.electronAPI.saveNote(activeNote.id, val) - } + setNotes((prevNotes) => { + const updatedNotes = [...prevNotes] + if (updatedNotes[currentNoteIndex]) { + updatedNotes[currentNoteIndex] = { + ...updatedNotes[currentNoteIndex], + content: val, + } + window.electronAPI.saveNote(updatedNotes[currentNoteIndex].id, val) + } + return updatedNotes + }) if (viewUpdate?.transactions?.some((tr) => tr.docChanged)) { if (editorRef.current?.view) { @@ -49,7 +58,7 @@ export const Editor = forwardRef((props, ref) => { } } }, - [notes, currentNoteIndex, activeNote.id, setNotes] + [currentNoteIndex, setNotes] ) const extensions = useEditorExtensions(handleEditorChange) diff --git a/src/components/ErrorBoundary.tsx b/src/components/ErrorBoundary.tsx index 4a0aeda..fa00360 100644 --- a/src/components/ErrorBoundary.tsx +++ b/src/components/ErrorBoundary.tsx @@ -1,4 +1,4 @@ -import { Component, ErrorInfo, ReactNode } from 'react' +import { Component, type ErrorInfo, type ReactNode } from 'react' interface Props { children?: ReactNode diff --git a/src/lib/editor/MathEvaluator.ts b/src/lib/editor/MathEvaluator.ts index 7cb7ba0..3b0d15a 100644 --- a/src/lib/editor/MathEvaluator.ts +++ b/src/lib/editor/MathEvaluator.ts @@ -71,6 +71,9 @@ export class MathEvaluator { static triggerMathEvaluation(view: EditorView) { if (this.evalTimeout) window.clearTimeout(this.evalTimeout) this.evalTimeout = window.setTimeout(async () => { + // Guard against the editor being unmounted during the timeout + if (!view.state) return + const docStr = view.state.doc.toString() const scope = VariableScope.getScope() const changes = await this.evaluateMathChanges(docStr, scope) diff --git a/src/lib/editor/extensions.ts b/src/lib/editor/extensions.ts index 9e783b5..b173e5b 100644 --- a/src/lib/editor/extensions.ts +++ b/src/lib/editor/extensions.ts @@ -9,12 +9,29 @@ import { insertTab, indentLess } from '@codemirror/commands' import { mdHighlighting } from './matchers' import { numberPlugin, symbolPlugin, aiPlugin, mathPlugin, decomposedPlugins } from './plugins' import { useAIStore } from '../../store/useAIStore' -import { useAppStore } from '../../store/useAppStore' +import { useAppStore, type Note } from '../../store/useAppStore' + +const handleDeleteNote = () => { + const note = useAppStore.getState().notes[useAppStore.getState().currentNoteIndex] + if (note) { + if (note.id.startsWith('commands/')) { + alert('Files in the commands folder cannot be deleted.') + return true + } + if (confirm('Delete this note?')) { + window.electronAPI.deleteNote(note.id) + useAppStore.getState().setNotes((prev: Note[]) => prev.filter((n: Note) => n.id !== note.id)) + if (useAppStore.getState().currentNoteIndex >= useAppStore.getState().notes.length - 1) + useAppStore + .getState() + .setCurrentNoteIndex(Math.max(0, useAppStore.getState().notes.length - 2)) + } + } + return true +} export function useEditorExtensions(handleEditorChange: (val: string) => void) { const { apiBaseUrl, apiModel, aiSystemPrompt } = useAIStore() - const setNotes = useAppStore((state) => state.setNotes) - const setCurrentNoteIndex = useAppStore((state) => state.setCurrentNoteIndex) return useMemo( () => [ @@ -55,47 +72,11 @@ export function useEditorExtensions(handleEditorChange: (val: string) => void) { }, { key: 'Mod-Backspace', - run: () => { - const note = useAppStore.getState().notes[useAppStore.getState().currentNoteIndex] - if (note) { - if (note.id.startsWith('commands/')) { - alert('Files in the commands folder cannot be deleted.') - return true - } - if (confirm('Delete this note?')) { - window.electronAPI.deleteNote(note.id) - setNotes((prev) => prev.filter((n) => n.id !== note.id)) - if ( - useAppStore.getState().currentNoteIndex >= - useAppStore.getState().notes.length - 1 - ) - setCurrentNoteIndex(Math.max(0, useAppStore.getState().notes.length - 2)) - } - } - return true - }, + run: () => handleDeleteNote(), }, { key: 'Mod-Delete', - run: () => { - const note = useAppStore.getState().notes[useAppStore.getState().currentNoteIndex] - if (note) { - if (note.id.startsWith('commands/')) { - alert('Files in the commands folder cannot be deleted.') - return true - } - if (confirm('Delete this note?')) { - window.electronAPI.deleteNote(note.id) - setNotes((prev) => prev.filter((n) => n.id !== note.id)) - if ( - useAppStore.getState().currentNoteIndex >= - useAppStore.getState().notes.length - 1 - ) - setCurrentNoteIndex(Math.max(0, useAppStore.getState().notes.length - 2)) - } - } - return true - }, + run: () => handleDeleteNote(), }, { key: 'Enter', @@ -118,17 +99,15 @@ export function useEditorExtensions(handleEditorChange: (val: string) => void) { const prompt = lineText.substring(prefixLength).trim() const thinkingText = '\n\u200B...\u200C\n' - const markerStart = line.to - const markerEnd = markerStart + thinkingText.length - view.dispatch({ changes: { from: markerStart, insert: thinkingText } }) + view.dispatch({ changes: { from: line.to, insert: thinkingText } }) ;(async () => { try { const isKeySet = await window.electronAPI.getApiKeyStatus() if (!isKeySet) { view.dispatch({ changes: { - from: markerStart, - to: markerEnd, + from: line.to, + to: line.to + thinkingText.length, insert: '\n\u200BError - Set your OpenAI API key in settings\u200C\n', }, }) @@ -184,8 +163,8 @@ export function useEditorExtensions(handleEditorChange: (val: string) => void) { view.dispatch({ changes: { - from: markerStart, - to: markerEnd, + from: line.to, + to: line.to + thinkingText.length, insert: '\n\u200B' + response + '\u200C\n', }, }) @@ -193,8 +172,8 @@ export function useEditorExtensions(handleEditorChange: (val: string) => void) { .catch((error) => { view.dispatch({ changes: { - from: markerStart, - to: markerEnd, + from: line.to, + to: line.to + thinkingText.length, insert: '\n\u200BError - ' + error.message + '\u200C\n', }, }) @@ -202,8 +181,8 @@ export function useEditorExtensions(handleEditorChange: (val: string) => void) { } catch (err: unknown) { view.dispatch({ changes: { - from: markerStart, - to: markerEnd, + from: line.to, + to: line.to + thinkingText.length, insert: '\n\u200BSetup Error - ' + ((err as Error).message || String(err)) + @@ -257,6 +236,6 @@ export function useEditorExtensions(handleEditorChange: (val: string) => void) { }, }), ], - [apiBaseUrl, apiModel, aiSystemPrompt, handleEditorChange, setCurrentNoteIndex, setNotes] + [apiBaseUrl, apiModel, aiSystemPrompt, handleEditorChange] ) } diff --git a/src/main.tsx b/src/main.tsx index 16e9952..7e8f804 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -36,8 +36,9 @@ function Root() { try { // Decrypt it using the old method, then send to new IPC const decrypted = await window.electronAPI.safeStorageDecrypt(secureEncrypted) - // Validate that the decrypted value looks like a valid API key - if (decrypted && decrypted.startsWith('sk-ant-') && decrypted.length >= 20) { + // Ensure it looks like an API key (e.g. typical lengths for OpenAI or anthropic are 40+ chars) + // and not the original base64 garbage + if (decrypted && decrypted !== secureEncrypted && decrypted.length > 20) { const success = await window.electronAPI.setApiKey(decrypted) if (success) { localStorage.removeItem('papercache-apikey-secure') diff --git a/src/setupTests.ts b/src/setupTests.ts index fbce366..45a93ae 100644 --- a/src/setupTests.ts +++ b/src/setupTests.ts @@ -1,4 +1,5 @@ import '@testing-library/jest-dom' +import { vi } from 'vitest' // Mock matchMedia which is not present in jsdom but might be needed by some components if (typeof window !== 'undefined') { diff --git a/vite.config.ts b/vite.config.ts index 54e1763..62347c3 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -11,6 +11,13 @@ export default defineConfig({ electron([ { entry: 'electron/main.ts', + vite: { + build: { + rollupOptions: { + external: ['electron-updater'], + }, + }, + }, }, { entry: 'electron/preload.ts', From 74d96589fc7fd1e863e9d479eacf4ff7c803661e Mon Sep 17 00:00:00 2001 From: Aditya Date: Sun, 21 Jun 2026 09:54:21 +0530 Subject: [PATCH 05/10] 0.1.18 --- .gitignore | 1 + coverage/base.css | 224 ---- coverage/block-navigation.js | 87 -- coverage/clover.xml | 435 ------- coverage/coverage-final.json | 12 - coverage/favicon.png | Bin 445 -> 0 bytes coverage/index.html | 176 --- coverage/prettify.css | 1 - coverage/prettify.js | 2 - coverage/sort-arrow-sprite.png | Bin 138 -> 0 bytes coverage/sorter.js | 210 ---- coverage/src/Settings.css.html | 574 --------- coverage/src/Settings.tsx.html | 1087 ----------------- coverage/src/hooks/index.html | 131 -- coverage/src/hooks/useReminders.ts.html | 409 ------- coverage/src/hooks/useVariables.ts.html | 205 ---- coverage/src/index.html | 146 --- coverage/src/lib/editor/MathEvaluator.ts.html | 334 ----- coverage/src/lib/editor/VariableScope.ts.html | 277 ----- coverage/src/lib/editor/index.html | 146 --- coverage/src/lib/editor/widgets.ts.html | 736 ----------- coverage/src/lib/index.html | 131 -- coverage/src/lib/safeStorage.ts.html | 139 --- coverage/src/lib/settingsKeys.ts.html | 145 --- coverage/src/store/index.html | 116 -- coverage/src/store/useAppStore.ts.html | 403 ------ coverage/src/utils.ts.html | 205 ---- package-lock.json | 4 +- package.json | 2 +- 29 files changed, 4 insertions(+), 6334 deletions(-) delete mode 100644 coverage/base.css delete mode 100644 coverage/block-navigation.js delete mode 100644 coverage/clover.xml delete mode 100644 coverage/coverage-final.json delete mode 100644 coverage/favicon.png delete mode 100644 coverage/index.html delete mode 100644 coverage/prettify.css delete mode 100644 coverage/prettify.js delete mode 100644 coverage/sort-arrow-sprite.png delete mode 100644 coverage/sorter.js delete mode 100644 coverage/src/Settings.css.html delete mode 100644 coverage/src/Settings.tsx.html delete mode 100644 coverage/src/hooks/index.html delete mode 100644 coverage/src/hooks/useReminders.ts.html delete mode 100644 coverage/src/hooks/useVariables.ts.html delete mode 100644 coverage/src/index.html delete mode 100644 coverage/src/lib/editor/MathEvaluator.ts.html delete mode 100644 coverage/src/lib/editor/VariableScope.ts.html delete mode 100644 coverage/src/lib/editor/index.html delete mode 100644 coverage/src/lib/editor/widgets.ts.html delete mode 100644 coverage/src/lib/index.html delete mode 100644 coverage/src/lib/safeStorage.ts.html delete mode 100644 coverage/src/lib/settingsKeys.ts.html delete mode 100644 coverage/src/store/index.html delete mode 100644 coverage/src/store/useAppStore.ts.html delete mode 100644 coverage/src/utils.ts.html diff --git a/.gitignore b/.gitignore index 9ef3318..667cd7b 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,4 @@ dist-ssr dist-electron release *.env +coverage/ diff --git a/coverage/base.css b/coverage/base.css deleted file mode 100644 index f418035..0000000 --- a/coverage/base.css +++ /dev/null @@ -1,224 +0,0 @@ -body, html { - margin:0; padding: 0; - height: 100%; -} -body { - font-family: Helvetica Neue, Helvetica, Arial; - font-size: 14px; - color:#333; -} -.small { font-size: 12px; } -*, *:after, *:before { - -webkit-box-sizing:border-box; - -moz-box-sizing:border-box; - box-sizing:border-box; - } -h1 { font-size: 20px; margin: 0;} -h2 { font-size: 14px; } -pre { - font: 12px/1.4 Consolas, "Liberation Mono", Menlo, Courier, monospace; - margin: 0; - padding: 0; - -moz-tab-size: 2; - -o-tab-size: 2; - tab-size: 2; -} -a { color:#0074D9; text-decoration:none; } -a:hover { text-decoration:underline; } -.strong { font-weight: bold; } -.space-top1 { padding: 10px 0 0 0; } -.pad2y { padding: 20px 0; } -.pad1y { padding: 10px 0; } -.pad2x { padding: 0 20px; } -.pad2 { padding: 20px; } -.pad1 { padding: 10px; } -.space-left2 { padding-left:55px; } -.space-right2 { padding-right:20px; } -.center { text-align:center; } -.clearfix { display:block; } -.clearfix:after { - content:''; - display:block; - height:0; - clear:both; - visibility:hidden; - } -.fl { float: left; } -@media only screen and (max-width:640px) { - .col3 { width:100%; max-width:100%; } - .hide-mobile { display:none!important; } -} - -.quiet { - color: #7f7f7f; - color: rgba(0,0,0,0.5); -} -.quiet a { opacity: 0.7; } - -.fraction { - font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; - font-size: 10px; - color: #555; - background: #E8E8E8; - padding: 4px 5px; - border-radius: 3px; - vertical-align: middle; -} - -div.path a:link, div.path a:visited { color: #333; } -table.coverage { - border-collapse: collapse; - margin: 10px 0 0 0; - padding: 0; -} - -table.coverage td { - margin: 0; - padding: 0; - vertical-align: top; -} -table.coverage td.line-count { - text-align: right; - padding: 0 5px 0 20px; -} -table.coverage td.line-coverage { - text-align: right; - padding-right: 10px; - min-width:20px; -} - -table.coverage td span.cline-any { - display: inline-block; - padding: 0 5px; - width: 100%; -} -.missing-if-branch { - display: inline-block; - margin-right: 5px; - border-radius: 3px; - position: relative; - padding: 0 4px; - background: #333; - color: yellow; -} - -.skip-if-branch { - display: none; - margin-right: 10px; - position: relative; - padding: 0 4px; - background: #ccc; - color: white; -} -.missing-if-branch .typ, .skip-if-branch .typ { - color: inherit !important; -} -.coverage-summary { - border-collapse: collapse; - width: 100%; -} -.coverage-summary tr { border-bottom: 1px solid #bbb; } -.keyline-all { border: 1px solid #ddd; } -.coverage-summary td, .coverage-summary th { padding: 10px; } -.coverage-summary tbody { border: 1px solid #bbb; } -.coverage-summary td { border-right: 1px solid #bbb; } -.coverage-summary td:last-child { border-right: none; } -.coverage-summary th { - text-align: left; - font-weight: normal; - white-space: nowrap; -} -.coverage-summary th.file { border-right: none !important; } -.coverage-summary th.pct { } -.coverage-summary th.pic, -.coverage-summary th.abs, -.coverage-summary td.pct, -.coverage-summary td.abs { text-align: right; } -.coverage-summary td.file { white-space: nowrap; } -.coverage-summary td.pic { min-width: 120px !important; } -.coverage-summary tfoot td { } - -.coverage-summary .sorter { - height: 10px; - width: 7px; - display: inline-block; - margin-left: 0.5em; - background: url(sort-arrow-sprite.png) no-repeat scroll 0 0 transparent; -} -.coverage-summary .sorted .sorter { - background-position: 0 -20px; -} -.coverage-summary .sorted-desc .sorter { - background-position: 0 -10px; -} -.status-line { height: 10px; } -/* yellow */ -.cbranch-no { background: yellow !important; color: #111; } -/* dark red */ -.red.solid, .status-line.low, .low .cover-fill { background:#C21F39 } -.low .chart { border:1px solid #C21F39 } -.highlighted, -.highlighted .cstat-no, .highlighted .fstat-no, .highlighted .cbranch-no{ - background: #C21F39 !important; -} -/* medium red */ -.cstat-no, .fstat-no, .cbranch-no, .cbranch-no { background:#F6C6CE } -/* light red */ -.low, .cline-no { background:#FCE1E5 } -/* light green */ -.high, .cline-yes { background:rgb(230,245,208) } -/* medium green */ -.cstat-yes { background:rgb(161,215,106) } -/* dark green */ -.status-line.high, .high .cover-fill { background:rgb(77,146,33) } -.high .chart { border:1px solid rgb(77,146,33) } -/* dark yellow (gold) */ -.status-line.medium, .medium .cover-fill { background: #f9cd0b; } -.medium .chart { border:1px solid #f9cd0b; } -/* light yellow */ -.medium { background: #fff4c2; } - -.cstat-skip { background: #ddd; color: #111; } -.fstat-skip { background: #ddd; color: #111 !important; } -.cbranch-skip { background: #ddd !important; color: #111; } - -span.cline-neutral { background: #eaeaea; } - -.coverage-summary td.empty { - opacity: .5; - padding-top: 4px; - padding-bottom: 4px; - line-height: 1; - color: #888; -} - -.cover-fill, .cover-empty { - display:inline-block; - height: 12px; -} -.chart { - line-height: 0; -} -.cover-empty { - background: white; -} -.cover-full { - border-right: none !important; -} -pre.prettyprint { - border: none !important; - padding: 0 !important; - margin: 0 !important; -} -.com { color: #999 !important; } -.ignore-none { color: #999; font-weight: normal; } - -.wrapper { - min-height: 100%; - height: auto !important; - height: 100%; - margin: 0 auto -48px; -} -.footer, .push { - height: 48px; -} diff --git a/coverage/block-navigation.js b/coverage/block-navigation.js deleted file mode 100644 index 530d1ed..0000000 --- a/coverage/block-navigation.js +++ /dev/null @@ -1,87 +0,0 @@ -/* eslint-disable */ -var jumpToCode = (function init() { - // Classes of code we would like to highlight in the file view - var missingCoverageClasses = ['.cbranch-no', '.cstat-no', '.fstat-no']; - - // Elements to highlight in the file listing view - var fileListingElements = ['td.pct.low']; - - // We don't want to select elements that are direct descendants of another match - var notSelector = ':not(' + missingCoverageClasses.join('):not(') + ') > '; // becomes `:not(a):not(b) > ` - - // Selector that finds elements on the page to which we can jump - var selector = - fileListingElements.join(', ') + - ', ' + - notSelector + - missingCoverageClasses.join(', ' + notSelector); // becomes `:not(a):not(b) > a, :not(a):not(b) > b` - - // The NodeList of matching elements - var missingCoverageElements = document.querySelectorAll(selector); - - var currentIndex; - - function toggleClass(index) { - missingCoverageElements - .item(currentIndex) - .classList.remove('highlighted'); - missingCoverageElements.item(index).classList.add('highlighted'); - } - - function makeCurrent(index) { - toggleClass(index); - currentIndex = index; - missingCoverageElements.item(index).scrollIntoView({ - behavior: 'smooth', - block: 'center', - inline: 'center' - }); - } - - function goToPrevious() { - var nextIndex = 0; - if (typeof currentIndex !== 'number' || currentIndex === 0) { - nextIndex = missingCoverageElements.length - 1; - } else if (missingCoverageElements.length > 1) { - nextIndex = currentIndex - 1; - } - - makeCurrent(nextIndex); - } - - function goToNext() { - var nextIndex = 0; - - if ( - typeof currentIndex === 'number' && - currentIndex < missingCoverageElements.length - 1 - ) { - nextIndex = currentIndex + 1; - } - - makeCurrent(nextIndex); - } - - return function jump(event) { - if ( - document.getElementById('fileSearch') === document.activeElement && - document.activeElement != null - ) { - // if we're currently focused on the search input, we don't want to navigate - return; - } - - switch (event.which) { - case 78: // n - case 74: // j - goToNext(); - break; - case 66: // b - case 75: // k - case 80: // p - goToPrevious(); - break; - } - }; -})(); -window.addEventListener('keydown', jumpToCode); diff --git a/coverage/clover.xml b/coverage/clover.xml deleted file mode 100644 index cf25077..0000000 --- a/coverage/clover.xml +++ /dev/null @@ -1,435 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/coverage/coverage-final.json b/coverage/coverage-final.json deleted file mode 100644 index 40e4a34..0000000 --- a/coverage/coverage-final.json +++ /dev/null @@ -1,12 +0,0 @@ -{"/Users/aditya/Projects/PaperCache/src/Settings.css": {"path":"/Users/aditya/Projects/PaperCache/src/Settings.css","statementMap":{},"fnMap":{},"branchMap":{},"s":{},"f":{},"b":{},"meta":{"lastBranch":0,"lastFunction":0,"lastStatement":0,"seen":{},"fnNames":{}}} -,"/Users/aditya/Projects/PaperCache/src/Settings.tsx": {"path":"/Users/aditya/Projects/PaperCache/src/Settings.tsx","statementMap":{"0":{"start":{"line":6,"column":17},"end":{"line":6,"column":null}},"1":{"start":{"line":7,"column":22},"end":{"line":7,"column":null}},"2":{"start":{"line":9,"column":2},"end":{"line":21,"column":null}},"3":{"start":{"line":10,"column":4},"end":{"line":12,"column":null}},"4":{"start":{"line":11,"column":6},"end":{"line":11,"column":null}},"5":{"start":{"line":14,"column":10},"end":{"line":18,"column":null}},"6":{"start":{"line":15,"column":6},"end":{"line":17,"column":null}},"7":{"start":{"line":16,"column":8},"end":{"line":16,"column":null}},"8":{"start":{"line":19,"column":4},"end":{"line":19,"column":null}},"9":{"start":{"line":20,"column":4},"end":{"line":20,"column":null}},"10":{"start":{"line":20,"column":17},"end":{"line":20,"column":null}},"11":{"start":{"line":22,"column":21},"end":{"line":24,"column":null}},"12":{"start":{"line":25,"column":19},"end":{"line":27,"column":null}},"13":{"start":{"line":28,"column":25},"end":{"line":31,"column":null}},"14":{"start":{"line":34,"column":32},"end":{"line":36,"column":null}},"15":{"start":{"line":37,"column":31},"end":{"line":39,"column":null}},"16":{"start":{"line":42,"column":26},"end":{"line":44,"column":null}},"17":{"start":{"line":47,"column":21},"end":{"line":49,"column":null}},"18":{"start":{"line":50,"column":22},"end":{"line":52,"column":null}},"19":{"start":{"line":53,"column":22},"end":{"line":55,"column":null}},"20":{"start":{"line":56,"column":17},"end":{"line":56,"column":null}},"21":{"start":{"line":57,"column":18},"end":{"line":57,"column":null}},"22":{"start":{"line":58,"column":18},"end":{"line":58,"column":null}},"23":{"start":{"line":60,"column":20},"end":{"line":62,"column":null}},"24":{"start":{"line":63,"column":19},"end":{"line":65,"column":null}},"25":{"start":{"line":66,"column":19},"end":{"line":68,"column":null}},"26":{"start":{"line":69,"column":18},"end":{"line":69,"column":null}},"27":{"start":{"line":70,"column":20},"end":{"line":72,"column":null}},"28":{"start":{"line":74,"column":23},"end":{"line":120,"column":null}},"29":{"start":{"line":75,"column":4},"end":{"line":77,"column":null}},"30":{"start":{"line":76,"column":6},"end":{"line":76,"column":null}},"31":{"start":{"line":78,"column":4},"end":{"line":78,"column":null}},"32":{"start":{"line":79,"column":4},"end":{"line":79,"column":null}},"33":{"start":{"line":80,"column":4},"end":{"line":80,"column":null}},"34":{"start":{"line":82,"column":4},"end":{"line":82,"column":null}},"35":{"start":{"line":83,"column":4},"end":{"line":83,"column":null}},"36":{"start":{"line":84,"column":4},"end":{"line":84,"column":null}},"37":{"start":{"line":85,"column":4},"end":{"line":85,"column":null}},"38":{"start":{"line":86,"column":4},"end":{"line":86,"column":null}},"39":{"start":{"line":87,"column":4},"end":{"line":87,"column":null}},"40":{"start":{"line":89,"column":4},"end":{"line":89,"column":null}},"41":{"start":{"line":90,"column":4},"end":{"line":90,"column":null}},"42":{"start":{"line":91,"column":4},"end":{"line":91,"column":null}},"43":{"start":{"line":92,"column":4},"end":{"line":92,"column":null}},"44":{"start":{"line":93,"column":4},"end":{"line":93,"column":null}},"45":{"start":{"line":96,"column":4},"end":{"line":96,"column":null}},"46":{"start":{"line":97,"column":4},"end":{"line":99,"column":null}},"47":{"start":{"line":98,"column":6},"end":{"line":98,"column":null}},"48":{"start":{"line":103,"column":6},"end":{"line":103,"column":null}},"49":{"start":{"line":104,"column":4},"end":{"line":104,"column":null}},"50":{"start":{"line":105,"column":4},"end":{"line":107,"column":null}},"51":{"start":{"line":106,"column":6},"end":{"line":106,"column":null}},"52":{"start":{"line":110,"column":6},"end":{"line":110,"column":null}},"53":{"start":{"line":111,"column":4},"end":{"line":111,"column":null}},"54":{"start":{"line":112,"column":4},"end":{"line":114,"column":null}},"55":{"start":{"line":113,"column":6},"end":{"line":113,"column":null}},"56":{"start":{"line":117,"column":4},"end":{"line":117,"column":null}},"57":{"start":{"line":119,"column":4},"end":{"line":119,"column":null}},"58":{"start":{"line":122,"column":8},"end":{"line":124,"column":null}},"59":{"start":{"line":123,"column":4},"end":{"line":123,"column":null}},"60":{"start":{"line":126,"column":8},"end":{"line":128,"column":null}},"61":{"start":{"line":127,"column":4},"end":{"line":127,"column":null}},"62":{"start":{"line":130,"column":2},"end":{"line":332,"column":null}},"63":{"start":{"line":144,"column":31},"end":{"line":144,"column":null}},"64":{"start":{"line":154,"column":31},"end":{"line":154,"column":null}},"65":{"start":{"line":164,"column":31},"end":{"line":164,"column":null}},"66":{"start":{"line":173,"column":31},"end":{"line":173,"column":null}},"67":{"start":{"line":198,"column":31},"end":{"line":198,"column":null}},"68":{"start":{"line":207,"column":31},"end":{"line":207,"column":null}},"69":{"start":{"line":220,"column":31},"end":{"line":220,"column":null}},"70":{"start":{"line":230,"column":56},"end":{"line":230,"column":null}},"71":{"start":{"line":250,"column":31},"end":{"line":250,"column":null}},"72":{"start":{"line":257,"column":52},"end":{"line":257,"column":null}},"73":{"start":{"line":267,"column":59},"end":{"line":267,"column":null}},"74":{"start":{"line":278,"column":67},"end":{"line":278,"column":96}},"75":{"start":{"line":288,"column":33},"end":{"line":288,"column":null}},"76":{"start":{"line":296,"column":67},"end":{"line":296,"column":98}},"77":{"start":{"line":301,"column":66},"end":{"line":301,"column":96}},"78":{"start":{"line":306,"column":66},"end":{"line":306,"column":96}},"79":{"start":{"line":311,"column":67},"end":{"line":311,"column":98}},"80":{"start":{"line":316,"column":65},"end":{"line":316,"column":94}}},"fnMap":{"0":{"name":"Settings","decl":{"start":{"line":5,"column":24},"end":{"line":5,"column":35}},"loc":{"start":{"line":5,"column":35},"end":{"line":334,"column":null}},"line":5},"1":{"name":"(anonymous_1)","decl":{"start":{"line":9,"column":2},"end":{"line":9,"column":18}},"loc":{"start":{"line":9,"column":18},"end":{"line":21,"column":5}},"line":9},"2":{"name":"(anonymous_2)","decl":{"start":{"line":10,"column":41},"end":{"line":10,"column":47}},"loc":{"start":{"line":10,"column":58},"end":{"line":12,"column":5}},"line":10},"3":{"name":"(anonymous_3)","decl":{"start":{"line":14,"column":10},"end":{"line":14,"column":27}},"loc":{"start":{"line":14,"column":48},"end":{"line":18,"column":null}},"line":14},"4":{"name":"(anonymous_4)","decl":{"start":{"line":20,"column":4},"end":{"line":20,"column":17}},"loc":{"start":{"line":20,"column":17},"end":{"line":20,"column":null}},"line":20},"5":{"name":"(anonymous_5)","decl":{"start":{"line":74,"column":23},"end":{"line":74,"column":35}},"loc":{"start":{"line":74,"column":35},"end":{"line":120,"column":null}},"line":74},"6":{"name":"(anonymous_6)","decl":{"start":{"line":122,"column":8},"end":{"line":122,"column":30}},"loc":{"start":{"line":122,"column":30},"end":{"line":124,"column":null}},"line":122},"7":{"name":"(anonymous_7)","decl":{"start":{"line":126,"column":8},"end":{"line":126,"column":24}},"loc":{"start":{"line":126,"column":24},"end":{"line":128,"column":null}},"line":126},"8":{"name":"(anonymous_8)","decl":{"start":{"line":144,"column":14},"end":{"line":144,"column":25}},"loc":{"start":{"line":144,"column":31},"end":{"line":144,"column":null}},"line":144},"9":{"name":"(anonymous_9)","decl":{"start":{"line":154,"column":14},"end":{"line":154,"column":25}},"loc":{"start":{"line":154,"column":31},"end":{"line":154,"column":null}},"line":154},"10":{"name":"(anonymous_10)","decl":{"start":{"line":164,"column":14},"end":{"line":164,"column":25}},"loc":{"start":{"line":164,"column":31},"end":{"line":164,"column":null}},"line":164},"11":{"name":"(anonymous_11)","decl":{"start":{"line":173,"column":14},"end":{"line":173,"column":25}},"loc":{"start":{"line":173,"column":31},"end":{"line":173,"column":null}},"line":173},"12":{"name":"(anonymous_12)","decl":{"start":{"line":198,"column":14},"end":{"line":198,"column":25}},"loc":{"start":{"line":198,"column":31},"end":{"line":198,"column":null}},"line":198},"13":{"name":"(anonymous_13)","decl":{"start":{"line":207,"column":14},"end":{"line":207,"column":25}},"loc":{"start":{"line":207,"column":31},"end":{"line":207,"column":null}},"line":207},"14":{"name":"(anonymous_14)","decl":{"start":{"line":220,"column":14},"end":{"line":220,"column":25}},"loc":{"start":{"line":220,"column":31},"end":{"line":220,"column":null}},"line":220},"15":{"name":"(anonymous_15)","decl":{"start":{"line":230,"column":39},"end":{"line":230,"column":50}},"loc":{"start":{"line":230,"column":56},"end":{"line":230,"column":null}},"line":230},"16":{"name":"(anonymous_16)","decl":{"start":{"line":250,"column":14},"end":{"line":250,"column":25}},"loc":{"start":{"line":250,"column":31},"end":{"line":250,"column":null}},"line":250},"17":{"name":"(anonymous_17)","decl":{"start":{"line":257,"column":35},"end":{"line":257,"column":46}},"loc":{"start":{"line":257,"column":52},"end":{"line":257,"column":null}},"line":257},"18":{"name":"(anonymous_18)","decl":{"start":{"line":267,"column":42},"end":{"line":267,"column":53}},"loc":{"start":{"line":267,"column":59},"end":{"line":267,"column":null}},"line":267},"19":{"name":"(anonymous_19)","decl":{"start":{"line":278,"column":50},"end":{"line":278,"column":61}},"loc":{"start":{"line":278,"column":67},"end":{"line":278,"column":96}},"line":278},"20":{"name":"(anonymous_20)","decl":{"start":{"line":288,"column":16},"end":{"line":288,"column":27}},"loc":{"start":{"line":288,"column":33},"end":{"line":288,"column":null}},"line":288},"21":{"name":"(anonymous_21)","decl":{"start":{"line":296,"column":50},"end":{"line":296,"column":61}},"loc":{"start":{"line":296,"column":67},"end":{"line":296,"column":98}},"line":296},"22":{"name":"(anonymous_22)","decl":{"start":{"line":301,"column":49},"end":{"line":301,"column":60}},"loc":{"start":{"line":301,"column":66},"end":{"line":301,"column":96}},"line":301},"23":{"name":"(anonymous_23)","decl":{"start":{"line":306,"column":49},"end":{"line":306,"column":60}},"loc":{"start":{"line":306,"column":66},"end":{"line":306,"column":96}},"line":306},"24":{"name":"(anonymous_24)","decl":{"start":{"line":311,"column":50},"end":{"line":311,"column":61}},"loc":{"start":{"line":311,"column":67},"end":{"line":311,"column":98}},"line":311},"25":{"name":"(anonymous_25)","decl":{"start":{"line":316,"column":48},"end":{"line":316,"column":59}},"loc":{"start":{"line":316,"column":65},"end":{"line":316,"column":94}},"line":316}},"branchMap":{"0":{"loc":{"start":{"line":15,"column":6},"end":{"line":17,"column":null}},"type":"if","locations":[{"start":{"line":15,"column":6},"end":{"line":17,"column":null}},{"start":{},"end":{}}],"line":15},"1":{"loc":{"start":{"line":23,"column":4},"end":{"line":23,"column":null}},"type":"binary-expr","locations":[{"start":{"line":23,"column":4},"end":{"line":23,"column":56}},{"start":{"line":23,"column":56},"end":{"line":23,"column":null}}],"line":23},"2":{"loc":{"start":{"line":26,"column":4},"end":{"line":26,"column":null}},"type":"binary-expr","locations":[{"start":{"line":26,"column":4},"end":{"line":26,"column":53}},{"start":{"line":26,"column":53},"end":{"line":26,"column":null}}],"line":26},"3":{"loc":{"start":{"line":29,"column":4},"end":{"line":30,"column":null}},"type":"binary-expr","locations":[{"start":{"line":29,"column":4},"end":{"line":29,"column":null}},{"start":{"line":30,"column":6},"end":{"line":30,"column":null}}],"line":29},"4":{"loc":{"start":{"line":35,"column":4},"end":{"line":35,"column":null}},"type":"binary-expr","locations":[{"start":{"line":35,"column":4},"end":{"line":35,"column":60}},{"start":{"line":35,"column":60},"end":{"line":35,"column":null}}],"line":35},"5":{"loc":{"start":{"line":38,"column":4},"end":{"line":38,"column":null}},"type":"binary-expr","locations":[{"start":{"line":38,"column":4},"end":{"line":38,"column":59}},{"start":{"line":38,"column":59},"end":{"line":38,"column":null}}],"line":38},"6":{"loc":{"start":{"line":48,"column":4},"end":{"line":48,"column":null}},"type":"binary-expr","locations":[{"start":{"line":48,"column":4},"end":{"line":48,"column":55}},{"start":{"line":48,"column":55},"end":{"line":48,"column":null}}],"line":48},"7":{"loc":{"start":{"line":54,"column":4},"end":{"line":54,"column":null}},"type":"binary-expr","locations":[{"start":{"line":54,"column":4},"end":{"line":54,"column":56}},{"start":{"line":54,"column":56},"end":{"line":54,"column":null}}],"line":54},"8":{"loc":{"start":{"line":56,"column":39},"end":{"line":56,"column":93}},"type":"binary-expr","locations":[{"start":{"line":56,"column":39},"end":{"line":56,"column":86}},{"start":{"line":56,"column":86},"end":{"line":56,"column":93}}],"line":56},"9":{"loc":{"start":{"line":57,"column":41},"end":{"line":57,"column":98}},"type":"binary-expr","locations":[{"start":{"line":57,"column":41},"end":{"line":57,"column":89}},{"start":{"line":57,"column":89},"end":{"line":57,"column":98}}],"line":57},"10":{"loc":{"start":{"line":58,"column":41},"end":{"line":58,"column":91}},"type":"binary-expr","locations":[{"start":{"line":58,"column":41},"end":{"line":58,"column":89}},{"start":{"line":58,"column":89},"end":{"line":58,"column":91}}],"line":58},"11":{"loc":{"start":{"line":61,"column":4},"end":{"line":61,"column":null}},"type":"binary-expr","locations":[{"start":{"line":61,"column":4},"end":{"line":61,"column":54}},{"start":{"line":61,"column":54},"end":{"line":61,"column":null}}],"line":61},"12":{"loc":{"start":{"line":64,"column":4},"end":{"line":64,"column":null}},"type":"binary-expr","locations":[{"start":{"line":64,"column":4},"end":{"line":64,"column":53}},{"start":{"line":64,"column":53},"end":{"line":64,"column":null}}],"line":64},"13":{"loc":{"start":{"line":67,"column":4},"end":{"line":67,"column":null}},"type":"binary-expr","locations":[{"start":{"line":67,"column":4},"end":{"line":67,"column":53}},{"start":{"line":67,"column":53},"end":{"line":67,"column":null}}],"line":67},"14":{"loc":{"start":{"line":69,"column":41},"end":{"line":69,"column":98}},"type":"binary-expr","locations":[{"start":{"line":69,"column":41},"end":{"line":69,"column":89}},{"start":{"line":69,"column":89},"end":{"line":69,"column":98}}],"line":69},"15":{"loc":{"start":{"line":71,"column":4},"end":{"line":71,"column":null}},"type":"binary-expr","locations":[{"start":{"line":71,"column":4},"end":{"line":71,"column":54}},{"start":{"line":71,"column":54},"end":{"line":71,"column":null}}],"line":71},"16":{"loc":{"start":{"line":75,"column":4},"end":{"line":77,"column":null}},"type":"if","locations":[{"start":{"line":75,"column":4},"end":{"line":77,"column":null}},{"start":{},"end":{}}],"line":75},"17":{"loc":{"start":{"line":97,"column":4},"end":{"line":99,"column":null}},"type":"if","locations":[{"start":{"line":97,"column":4},"end":{"line":99,"column":null}},{"start":{},"end":{}}],"line":97},"18":{"loc":{"start":{"line":103,"column":6},"end":{"line":103,"column":null}},"type":"binary-expr","locations":[{"start":{"line":103,"column":6},"end":{"line":103,"column":61}},{"start":{"line":103,"column":61},"end":{"line":103,"column":null}}],"line":103},"19":{"loc":{"start":{"line":105,"column":4},"end":{"line":107,"column":null}},"type":"if","locations":[{"start":{"line":105,"column":4},"end":{"line":107,"column":null}},{"start":{},"end":{}}],"line":105},"20":{"loc":{"start":{"line":110,"column":6},"end":{"line":110,"column":null}},"type":"binary-expr","locations":[{"start":{"line":110,"column":6},"end":{"line":110,"column":60}},{"start":{"line":110,"column":60},"end":{"line":110,"column":null}}],"line":110},"21":{"loc":{"start":{"line":112,"column":4},"end":{"line":114,"column":null}},"type":"if","locations":[{"start":{"line":112,"column":4},"end":{"line":114,"column":null}},{"start":{},"end":{}}],"line":112},"22":{"loc":{"start":{"line":140,"column":28},"end":{"line":140,"column":64}},"type":"cond-expr","locations":[{"start":{"line":140,"column":42},"end":{"line":140,"column":54}},{"start":{"line":140,"column":54},"end":{"line":140,"column":64}}],"line":140},"23":{"loc":{"start":{"line":145,"column":27},"end":{"line":145,"column":null}},"type":"cond-expr","locations":[{"start":{"line":145,"column":41},"end":{"line":145,"column":79}},{"start":{"line":145,"column":79},"end":{"line":145,"column":null}}],"line":145},"24":{"loc":{"start":{"line":264,"column":11},"end":{"line":272,"column":null}},"type":"binary-expr","locations":[{"start":{"line":264,"column":11},"end":{"line":264,"column":null}},{"start":{"line":265,"column":12},"end":{"line":272,"column":null}}],"line":264},"25":{"loc":{"start":{"line":275,"column":11},"end":{"line":279,"column":null}},"type":"binary-expr","locations":[{"start":{"line":275,"column":11},"end":{"line":275,"column":null}},{"start":{"line":276,"column":12},"end":{"line":279,"column":null}}],"line":275},"26":{"loc":{"start":{"line":282,"column":11},"end":{"line":291,"column":null}},"type":"binary-expr","locations":[{"start":{"line":282,"column":11},"end":{"line":282,"column":null}},{"start":{"line":283,"column":12},"end":{"line":291,"column":null}}],"line":282}},"s":{"0":9,"1":9,"2":9,"3":5,"4":5,"5":5,"6":0,"7":0,"8":5,"9":5,"10":5,"11":9,"12":9,"13":9,"14":9,"15":9,"16":9,"17":9,"18":9,"19":9,"20":9,"21":9,"22":9,"23":9,"24":9,"25":9,"26":9,"27":9,"28":9,"29":1,"30":1,"31":1,"32":1,"33":1,"34":1,"35":1,"36":1,"37":1,"38":1,"39":1,"40":1,"41":1,"42":1,"43":1,"44":1,"45":1,"46":1,"47":1,"48":1,"49":1,"50":1,"51":1,"52":1,"53":1,"54":1,"55":1,"56":1,"57":1,"58":9,"59":0,"60":9,"61":1,"62":9,"63":2,"64":0,"65":0,"66":0,"67":0,"68":0,"69":0,"70":0,"71":0,"72":0,"73":0,"74":0,"75":0,"76":0,"77":0,"78":0,"79":0,"80":0},"f":{"0":9,"1":5,"2":5,"3":0,"4":5,"5":1,"6":0,"7":1,"8":2,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0,"21":0,"22":0,"23":0,"24":0,"25":0},"b":{"0":[0,0],"1":[9,8],"2":[9,8],"3":[9,8],"4":[9,8],"5":[9,8],"6":[9,8],"7":[9,8],"8":[9,8],"9":[9,8],"10":[9,9],"11":[9,8],"12":[9,8],"13":[9,8],"14":[9,8],"15":[9,8],"16":[1,0],"17":[1,0],"18":[1,1],"19":[1,0],"20":[1,1],"21":[1,0],"22":[1,8],"23":[1,8],"24":[9,0],"25":[9,9],"26":[9,0]},"meta":{"lastBranch":27,"lastFunction":26,"lastStatement":81,"seen":{"f:5:24:5:35":0,"s:6:17:6:Infinity":0,"s:7:22:7:Infinity":1,"s:9:2:21:Infinity":2,"f:9:2:9:18":1,"s:10:4:12:Infinity":3,"f:10:41:10:47":2,"s:11:6:11:Infinity":4,"s:14:10:18:Infinity":5,"f:14:10:14:27":3,"b:15:6:17:Infinity:undefined:undefined:undefined:undefined":0,"s:15:6:17:Infinity":6,"s:16:8:16:Infinity":7,"s:19:4:19:Infinity":8,"s:20:4:20:Infinity":9,"f:20:4:20:17":4,"s:20:17:20:Infinity":10,"s:22:21:24:Infinity":11,"b:23:4:23:56:23:56:23:Infinity":1,"s:25:19:27:Infinity":12,"b:26:4:26:53:26:53:26:Infinity":2,"s:28:25:31:Infinity":13,"b:29:4:29:Infinity:30:6:30:Infinity":3,"s:34:32:36:Infinity":14,"b:35:4:35:60:35:60:35:Infinity":4,"s:37:31:39:Infinity":15,"b:38:4:38:59:38:59:38:Infinity":5,"s:42:26:44:Infinity":16,"s:47:21:49:Infinity":17,"b:48:4:48:55:48:55:48:Infinity":6,"s:50:22:52:Infinity":18,"s:53:22:55:Infinity":19,"b:54:4:54:56:54:56:54:Infinity":7,"s:56:17:56:Infinity":20,"b:56:39:56:86:56:86:56:93":8,"s:57:18:57:Infinity":21,"b:57:41:57:89:57:89:57:98":9,"s:58:18:58:Infinity":22,"b:58:41:58:89:58:89:58:91":10,"s:60:20:62:Infinity":23,"b:61:4:61:54:61:54:61:Infinity":11,"s:63:19:65:Infinity":24,"b:64:4:64:53:64:53:64:Infinity":12,"s:66:19:68:Infinity":25,"b:67:4:67:53:67:53:67:Infinity":13,"s:69:18:69:Infinity":26,"b:69:41:69:89:69:89:69:98":14,"s:70:20:72:Infinity":27,"b:71:4:71:54:71:54:71:Infinity":15,"s:74:23:120:Infinity":28,"f:74:23:74:35":5,"b:75:4:77:Infinity:undefined:undefined:undefined:undefined":16,"s:75:4:77:Infinity":29,"s:76:6:76:Infinity":30,"s:78:4:78:Infinity":31,"s:79:4:79:Infinity":32,"s:80:4:80:Infinity":33,"s:82:4:82:Infinity":34,"s:83:4:83:Infinity":35,"s:84:4:84:Infinity":36,"s:85:4:85:Infinity":37,"s:86:4:86:Infinity":38,"s:87:4:87:Infinity":39,"s:89:4:89:Infinity":40,"s:90:4:90:Infinity":41,"s:91:4:91:Infinity":42,"s:92:4:92:Infinity":43,"s:93:4:93:Infinity":44,"s:96:4:96:Infinity":45,"b:97:4:99:Infinity:undefined:undefined:undefined:undefined":17,"s:97:4:99:Infinity":46,"s:98:6:98:Infinity":47,"s:103:6:103:Infinity":48,"b:103:6:103:61:103:61:103:Infinity":18,"s:104:4:104:Infinity":49,"b:105:4:107:Infinity:undefined:undefined:undefined:undefined":19,"s:105:4:107:Infinity":50,"s:106:6:106:Infinity":51,"s:110:6:110:Infinity":52,"b:110:6:110:60:110:60:110:Infinity":20,"s:111:4:111:Infinity":53,"b:112:4:114:Infinity:undefined:undefined:undefined:undefined":21,"s:112:4:114:Infinity":54,"s:113:6:113:Infinity":55,"s:117:4:117:Infinity":56,"s:119:4:119:Infinity":57,"s:122:8:124:Infinity":58,"f:122:8:122:30":6,"s:123:4:123:Infinity":59,"s:126:8:128:Infinity":60,"f:126:8:126:24":7,"s:127:4:127:Infinity":61,"s:130:2:332:Infinity":62,"b:140:42:140:54:140:54:140:64":22,"f:144:14:144:25":8,"s:144:31:144:Infinity":63,"b:145:41:145:79:145:79:145:Infinity":23,"f:154:14:154:25":9,"s:154:31:154:Infinity":64,"f:164:14:164:25":10,"s:164:31:164:Infinity":65,"f:173:14:173:25":11,"s:173:31:173:Infinity":66,"f:198:14:198:25":12,"s:198:31:198:Infinity":67,"f:207:14:207:25":13,"s:207:31:207:Infinity":68,"f:220:14:220:25":14,"s:220:31:220:Infinity":69,"f:230:39:230:50":15,"s:230:56:230:Infinity":70,"f:250:14:250:25":16,"s:250:31:250:Infinity":71,"f:257:35:257:46":17,"s:257:52:257:Infinity":72,"b:264:11:264:Infinity:265:12:272:Infinity":24,"f:267:42:267:53":18,"s:267:59:267:Infinity":73,"b:275:11:275:Infinity:276:12:279:Infinity":25,"f:278:50:278:61":19,"s:278:67:278:96":74,"b:282:11:282:Infinity:283:12:291:Infinity":26,"f:288:16:288:27":20,"s:288:33:288:Infinity":75,"f:296:50:296:61":21,"s:296:67:296:98":76,"f:301:49:301:60":22,"s:301:66:301:96":77,"f:306:49:306:60":23,"s:306:66:306:96":78,"f:311:50:311:61":24,"s:311:67:311:98":79,"f:316:48:316:59":25,"s:316:65:316:94":80},"fnNames":{}}} -,"/Users/aditya/Projects/PaperCache/src/utils.ts": {"path":"/Users/aditya/Projects/PaperCache/src/utils.ts","statementMap":{"0":{"start":{"line":1,"column":13},"end":{"line":40,"column":null}},"1":{"start":{"line":2,"column":2},"end":{"line":2,"column":null}},"2":{"start":{"line":2,"column":12},"end":{"line":2,"column":null}},"3":{"start":{"line":3,"column":39},"end":{"line":3,"column":null}},"4":{"start":{"line":4,"column":2},"end":{"line":6,"column":null}},"5":{"start":{"line":5,"column":4},"end":{"line":5,"column":null}},"6":{"start":{"line":8,"column":2},"end":{"line":8,"column":null}},"7":{"start":{"line":8,"column":19},"end":{"line":8,"column":null}},"8":{"start":{"line":10,"column":19},"end":{"line":15,"column":null}},"9":{"start":{"line":12,"column":20},"end":{"line":12,"column":null}},"10":{"start":{"line":13,"column":6},"end":{"line":13,"column":null}},"11":{"start":{"line":15,"column":19},"end":{"line":15,"column":29}},"12":{"start":{"line":17,"column":16},"end":{"line":17,"column":null}},"13":{"start":{"line":18,"column":2},"end":{"line":34,"column":null}},"14":{"start":{"line":19,"column":4},"end":{"line":19,"column":null}},"15":{"start":{"line":19,"column":28},"end":{"line":19,"column":33}},"16":{"start":{"line":20,"column":18},"end":{"line":20,"column":null}},"17":{"start":{"line":21,"column":4},"end":{"line":29,"column":null}},"18":{"start":{"line":21,"column":17},"end":{"line":21,"column":20}},"19":{"start":{"line":22,"column":12},"end":{"line":22,"column":null}},"20":{"start":{"line":23,"column":17},"end":{"line":23,"column":null}},"21":{"start":{"line":24,"column":6},"end":{"line":24,"column":null}},"22":{"start":{"line":24,"column":21},"end":{"line":24,"column":null}},"23":{"start":{"line":25,"column":6},"end":{"line":28,"column":null}},"24":{"start":{"line":26,"column":8},"end":{"line":26,"column":null}},"25":{"start":{"line":27,"column":8},"end":{"line":27,"column":null}},"26":{"start":{"line":31,"column":15},"end":{"line":31,"column":null}},"27":{"start":{"line":32,"column":4},"end":{"line":32,"column":null}},"28":{"start":{"line":32,"column":17},"end":{"line":32,"column":20}},"29":{"start":{"line":32,"column":41},"end":{"line":32,"column":null}},"30":{"start":{"line":33,"column":4},"end":{"line":33,"column":null}},"31":{"start":{"line":36,"column":16},"end":{"line":36,"column":null}},"32":{"start":{"line":37,"column":2},"end":{"line":37,"column":null}},"33":{"start":{"line":38,"column":2},"end":{"line":38,"column":null}},"34":{"start":{"line":39,"column":2},"end":{"line":39,"column":null}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":1,"column":13},"end":{"line":1,"column":31}},"loc":{"start":{"line":1,"column":55},"end":{"line":40,"column":null}},"line":1},"1":{"name":"(anonymous_1)","decl":{"start":{"line":11,"column":5},"end":{"line":11,"column":10}},"loc":{"start":{"line":11,"column":16},"end":{"line":14,"column":5}},"line":11},"2":{"name":"(anonymous_2)","decl":{"start":{"line":15,"column":5},"end":{"line":15,"column":13}},"loc":{"start":{"line":15,"column":19},"end":{"line":15,"column":29}},"line":15},"3":{"name":"(anonymous_3)","decl":{"start":{"line":19,"column":13},"end":{"line":19,"column":19}},"loc":{"start":{"line":19,"column":28},"end":{"line":19,"column":33}},"line":19}},"branchMap":{"0":{"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":null}},"type":"if","locations":[{"start":{"line":2,"column":2},"end":{"line":2,"column":null}},{"start":{},"end":{}}],"line":2},"1":{"loc":{"start":{"line":5,"column":24},"end":{"line":5,"column":80}},"type":"binary-expr","locations":[{"start":{"line":5,"column":24},"end":{"line":5,"column":76}},{"start":{"line":5,"column":76},"end":{"line":5,"column":80}}],"line":5},"2":{"loc":{"start":{"line":8,"column":2},"end":{"line":8,"column":null}},"type":"if","locations":[{"start":{"line":8,"column":2},"end":{"line":8,"column":null}},{"start":{},"end":{}}],"line":8},"3":{"loc":{"start":{"line":13,"column":13},"end":{"line":13,"column":null}},"type":"cond-expr","locations":[{"start":{"line":13,"column":21},"end":{"line":13,"column":42}},{"start":{"line":13,"column":42},"end":{"line":13,"column":null}}],"line":13},"4":{"loc":{"start":{"line":18,"column":2},"end":{"line":34,"column":null}},"type":"if","locations":[{"start":{"line":18,"column":2},"end":{"line":34,"column":null}},{"start":{"line":30,"column":9},"end":{"line":34,"column":null}}],"line":18},"5":{"loc":{"start":{"line":24,"column":6},"end":{"line":24,"column":null}},"type":"if","locations":[{"start":{"line":24,"column":6},"end":{"line":24,"column":null}},{"start":{},"end":{}}],"line":24},"6":{"loc":{"start":{"line":25,"column":6},"end":{"line":28,"column":null}},"type":"if","locations":[{"start":{"line":25,"column":6},"end":{"line":28,"column":null}},{"start":{},"end":{}}],"line":25}},"s":{"0":1,"1":9,"2":1,"3":8,"4":8,"5":8,"6":8,"7":1,"8":7,"9":4,"10":4,"11":4,"12":7,"13":7,"14":3,"15":1,"16":3,"17":3,"18":3,"19":4,"20":4,"21":4,"22":3,"23":4,"24":3,"25":3,"26":4,"27":4,"28":4,"29":20,"30":4,"31":7,"32":7,"33":7,"34":7},"f":{"0":9,"1":4,"2":4,"3":1},"b":{"0":[1,8],"1":[8,4],"2":[1,7],"3":[4,0],"4":[3,4],"5":[3,1],"6":[3,1]},"meta":{"lastBranch":7,"lastFunction":4,"lastStatement":35,"seen":{"s:1:13:40:Infinity":0,"f:1:13:1:31":0,"b:2:2:2:Infinity:undefined:undefined:undefined:undefined":0,"s:2:2:2:Infinity":1,"s:2:12:2:Infinity":2,"s:3:39:3:Infinity":3,"s:4:2:6:Infinity":4,"s:5:4:5:Infinity":5,"b:5:24:5:76:5:76:5:80":1,"b:8:2:8:Infinity:undefined:undefined:undefined:undefined":2,"s:8:2:8:Infinity":6,"s:8:19:8:Infinity":7,"s:10:19:15:Infinity":8,"f:11:5:11:10":1,"s:12:20:12:Infinity":9,"s:13:6:13:Infinity":10,"b:13:21:13:42:13:42:13:Infinity":3,"f:15:5:15:13":2,"s:15:19:15:29":11,"s:17:16:17:Infinity":12,"b:18:2:34:Infinity:30:9:34:Infinity":4,"s:18:2:34:Infinity":13,"s:19:4:19:Infinity":14,"f:19:13:19:19":3,"s:19:28:19:33":15,"s:20:18:20:Infinity":16,"s:21:4:29:Infinity":17,"s:21:17:21:20":18,"s:22:12:22:Infinity":19,"s:23:17:23:Infinity":20,"b:24:6:24:Infinity:undefined:undefined:undefined:undefined":5,"s:24:6:24:Infinity":21,"s:24:21:24:Infinity":22,"b:25:6:28:Infinity:undefined:undefined:undefined:undefined":6,"s:25:6:28:Infinity":23,"s:26:8:26:Infinity":24,"s:27:8:27:Infinity":25,"s:31:15:31:Infinity":26,"s:32:4:32:Infinity":27,"s:32:17:32:20":28,"s:32:41:32:Infinity":29,"s:33:4:33:Infinity":30,"s:36:16:36:Infinity":31,"s:37:2:37:Infinity":32,"s:38:2:38:Infinity":33,"s:39:2:39:Infinity":34},"fnNames":{}}} -,"/Users/aditya/Projects/PaperCache/src/hooks/useReminders.ts": {"path":"/Users/aditya/Projects/PaperCache/src/hooks/useReminders.ts","statementMap":{"0":{"start":{"line":6,"column":67},"end":{"line":6,"column":null}},"1":{"start":{"line":8,"column":4},"end":{"line":8,"column":null}},"2":{"start":{"line":11,"column":2},"end":{"line":25,"column":null}},"3":{"start":{"line":12,"column":19},"end":{"line":12,"column":null}},"4":{"start":{"line":13,"column":18},"end":{"line":13,"column":null}},"5":{"start":{"line":14,"column":22},"end":{"line":14,"column":null}},"6":{"start":{"line":15,"column":4},"end":{"line":24,"column":null}},"7":{"start":{"line":16,"column":23},"end":{"line":16,"column":null}},"8":{"start":{"line":17,"column":6},"end":{"line":23,"column":null}},"9":{"start":{"line":18,"column":8},"end":{"line":22,"column":null}},"10":{"start":{"line":26,"column":2},"end":{"line":26,"column":null}},"11":{"start":{"line":30,"column":14},"end":{"line":30,"column":null}},"12":{"start":{"line":31,"column":22},"end":{"line":31,"column":null}},"13":{"start":{"line":32,"column":19},"end":{"line":32,"column":null}},"14":{"start":{"line":33,"column":21},"end":{"line":33,"column":null}},"15":{"start":{"line":35,"column":23},"end":{"line":35,"column":null}},"16":{"start":{"line":35,"column":44},"end":{"line":35,"column":75}},"17":{"start":{"line":37,"column":2},"end":{"line":49,"column":null}},"18":{"start":{"line":38,"column":4},"end":{"line":48,"column":null}},"19":{"start":{"line":39,"column":6},"end":{"line":47,"column":null}},"20":{"start":{"line":40,"column":8},"end":{"line":40,"column":null}},"21":{"start":{"line":41,"column":8},"end":{"line":44,"column":null}},"22":{"start":{"line":45,"column":8},"end":{"line":45,"column":null}},"23":{"start":{"line":46,"column":8},"end":{"line":46,"column":null}},"24":{"start":{"line":51,"column":2},"end":{"line":53,"column":null}},"25":{"start":{"line":52,"column":4},"end":{"line":52,"column":null}},"26":{"start":{"line":57,"column":14},"end":{"line":57,"column":null}},"27":{"start":{"line":58,"column":15},"end":{"line":62,"column":null}},"28":{"start":{"line":59,"column":20},"end":{"line":59,"column":51}},"29":{"start":{"line":60,"column":16},"end":{"line":60,"column":33}},"30":{"start":{"line":61,"column":19},"end":{"line":61,"column":26}},"31":{"start":{"line":64,"column":2},"end":{"line":64,"column":null}},"32":{"start":{"line":64,"column":13},"end":{"line":64,"column":null}},"33":{"start":{"line":67,"column":16},"end":{"line":67,"column":null}},"34":{"start":{"line":68,"column":2},"end":{"line":68,"column":null}},"35":{"start":{"line":72,"column":8},"end":{"line":72,"column":null}},"36":{"start":{"line":72,"column":39},"end":{"line":72,"column":50}},"37":{"start":{"line":73,"column":8},"end":{"line":73,"column":null}},"38":{"start":{"line":75,"column":2},"end":{"line":107,"column":null}},"39":{"start":{"line":76,"column":4},"end":{"line":78,"column":null}},"40":{"start":{"line":77,"column":6},"end":{"line":77,"column":null}},"41":{"start":{"line":80,"column":10},"end":{"line":84,"column":null}},"42":{"start":{"line":81,"column":6},"end":{"line":81,"column":null}},"43":{"start":{"line":82,"column":6},"end":{"line":82,"column":null}},"44":{"start":{"line":82,"column":28},"end":{"line":82,"column":null}},"45":{"start":{"line":83,"column":6},"end":{"line":83,"column":null}},"46":{"start":{"line":86,"column":4},"end":{"line":86,"column":null}},"47":{"start":{"line":88,"column":10},"end":{"line":93,"column":null}},"48":{"start":{"line":89,"column":6},"end":{"line":92,"column":null}},"49":{"start":{"line":90,"column":8},"end":{"line":90,"column":null}},"50":{"start":{"line":91,"column":8},"end":{"line":91,"column":null}},"51":{"start":{"line":95,"column":10},"end":{"line":97,"column":null}},"52":{"start":{"line":96,"column":6},"end":{"line":96,"column":null}},"53":{"start":{"line":99,"column":31},"end":{"line":99,"column":null}},"54":{"start":{"line":100,"column":30},"end":{"line":100,"column":null}},"55":{"start":{"line":102,"column":4},"end":{"line":106,"column":null}},"56":{"start":{"line":103,"column":6},"end":{"line":103,"column":null}},"57":{"start":{"line":103,"column":28},"end":{"line":103,"column":null}},"58":{"start":{"line":104,"column":6},"end":{"line":104,"column":null}},"59":{"start":{"line":105,"column":6},"end":{"line":105,"column":null}}},"fnMap":{"0":{"name":"parseReminders","decl":{"start":{"line":5,"column":9},"end":{"line":5,"column":24}},"loc":{"start":{"line":5,"column":57},"end":{"line":27,"column":null}},"line":5},"1":{"name":"handleDueReminders","decl":{"start":{"line":29,"column":9},"end":{"line":29,"column":28}},"loc":{"start":{"line":29,"column":43},"end":{"line":54,"column":null}},"line":29},"2":{"name":"(anonymous_2)","decl":{"start":{"line":35,"column":29},"end":{"line":35,"column":38}},"loc":{"start":{"line":35,"column":44},"end":{"line":35,"column":75}},"line":35},"3":{"name":"scheduleNextReminder","decl":{"start":{"line":56,"column":9},"end":{"line":56,"column":30}},"loc":{"start":{"line":56,"column":67},"end":{"line":69,"column":null}},"line":56},"4":{"name":"(anonymous_4)","decl":{"start":{"line":59,"column":5},"end":{"line":59,"column":14}},"loc":{"start":{"line":59,"column":20},"end":{"line":59,"column":51}},"line":59},"5":{"name":"(anonymous_5)","decl":{"start":{"line":60,"column":5},"end":{"line":60,"column":10}},"loc":{"start":{"line":60,"column":16},"end":{"line":60,"column":33}},"line":60},"6":{"name":"(anonymous_6)","decl":{"start":{"line":61,"column":5},"end":{"line":61,"column":13}},"loc":{"start":{"line":61,"column":19},"end":{"line":61,"column":26}},"line":61},"7":{"name":"useReminders","decl":{"start":{"line":71,"column":16},"end":{"line":71,"column":31}},"loc":{"start":{"line":71,"column":31},"end":{"line":108,"column":null}},"line":71},"8":{"name":"(anonymous_8)","decl":{"start":{"line":72,"column":16},"end":{"line":72,"column":29}},"loc":{"start":{"line":72,"column":39},"end":{"line":72,"column":50}},"line":72},"9":{"name":"(anonymous_9)","decl":{"start":{"line":75,"column":2},"end":{"line":75,"column":18}},"loc":{"start":{"line":75,"column":18},"end":{"line":107,"column":5}},"line":75},"10":{"name":"(anonymous_10)","decl":{"start":{"line":80,"column":10},"end":{"line":80,"column":35}},"loc":{"start":{"line":80,"column":35},"end":{"line":84,"column":null}},"line":80},"11":{"name":"(anonymous_11)","decl":{"start":{"line":88,"column":10},"end":{"line":88,"column":28}},"loc":{"start":{"line":88,"column":28},"end":{"line":93,"column":null}},"line":88},"12":{"name":"(anonymous_12)","decl":{"start":{"line":95,"column":10},"end":{"line":95,"column":27}},"loc":{"start":{"line":95,"column":27},"end":{"line":97,"column":null}},"line":95},"13":{"name":"(anonymous_13)","decl":{"start":{"line":102,"column":4},"end":{"line":102,"column":17}},"loc":{"start":{"line":102,"column":17},"end":{"line":106,"column":null}},"line":102}},"branchMap":{"0":{"loc":{"start":{"line":15,"column":4},"end":{"line":24,"column":null}},"type":"if","locations":[{"start":{"line":15,"column":4},"end":{"line":24,"column":null}},{"start":{},"end":{}}],"line":15},"1":{"loc":{"start":{"line":15,"column":8},"end":{"line":15,"column":30}},"type":"binary-expr","locations":[{"start":{"line":15,"column":8},"end":{"line":15,"column":19}},{"start":{"line":15,"column":19},"end":{"line":15,"column":30}}],"line":15},"2":{"loc":{"start":{"line":17,"column":6},"end":{"line":23,"column":null}},"type":"if","locations":[{"start":{"line":17,"column":6},"end":{"line":23,"column":null}},{"start":{},"end":{}}],"line":17},"3":{"loc":{"start":{"line":31,"column":22},"end":{"line":31,"column":null}},"type":"binary-expr","locations":[{"start":{"line":31,"column":22},"end":{"line":31,"column":80}},{"start":{"line":31,"column":80},"end":{"line":31,"column":null}}],"line":31},"4":{"loc":{"start":{"line":38,"column":4},"end":{"line":48,"column":null}},"type":"if","locations":[{"start":{"line":38,"column":4},"end":{"line":48,"column":null}},{"start":{},"end":{}}],"line":38},"5":{"loc":{"start":{"line":39,"column":6},"end":{"line":47,"column":null}},"type":"if","locations":[{"start":{"line":39,"column":6},"end":{"line":47,"column":null}},{"start":{},"end":{}}],"line":39},"6":{"loc":{"start":{"line":51,"column":2},"end":{"line":53,"column":null}},"type":"if","locations":[{"start":{"line":51,"column":2},"end":{"line":53,"column":null}},{"start":{},"end":{}}],"line":51},"7":{"loc":{"start":{"line":64,"column":2},"end":{"line":64,"column":null}},"type":"if","locations":[{"start":{"line":64,"column":2},"end":{"line":64,"column":null}},{"start":{},"end":{}}],"line":64},"8":{"loc":{"start":{"line":76,"column":4},"end":{"line":78,"column":null}},"type":"if","locations":[{"start":{"line":76,"column":4},"end":{"line":78,"column":null}},{"start":{},"end":{}}],"line":76},"9":{"loc":{"start":{"line":76,"column":8},"end":{"line":76,"column":87}},"type":"binary-expr","locations":[{"start":{"line":76,"column":8},"end":{"line":76,"column":49}},{"start":{"line":76,"column":49},"end":{"line":76,"column":87}}],"line":76},"10":{"loc":{"start":{"line":82,"column":6},"end":{"line":82,"column":null}},"type":"if","locations":[{"start":{"line":82,"column":6},"end":{"line":82,"column":null}},{"start":{},"end":{}}],"line":82},"11":{"loc":{"start":{"line":89,"column":6},"end":{"line":92,"column":null}},"type":"if","locations":[{"start":{"line":89,"column":6},"end":{"line":92,"column":null}},{"start":{},"end":{}}],"line":89},"12":{"loc":{"start":{"line":103,"column":6},"end":{"line":103,"column":null}},"type":"if","locations":[{"start":{"line":103,"column":6},"end":{"line":103,"column":null}},{"start":{},"end":{}}],"line":103}},"s":{"0":8,"1":8,"2":8,"3":8,"4":8,"5":8,"6":8,"7":6,"8":6,"9":6,"10":8,"11":6,"12":6,"13":6,"14":6,"15":6,"16":4,"17":6,"18":3,"19":2,"20":2,"21":2,"22":2,"23":2,"24":6,"25":2,"26":6,"27":6,"28":4,"29":3,"30":3,"31":6,"32":5,"33":1,"34":1,"35":5,"36":15,"37":5,"38":5,"39":5,"40":1,"41":5,"42":6,"43":6,"44":1,"45":6,"46":5,"47":5,"48":0,"49":0,"50":0,"51":5,"52":0,"53":5,"54":5,"55":5,"56":5,"57":0,"58":5,"59":5},"f":{"0":8,"1":6,"2":4,"3":6,"4":4,"5":3,"6":3,"7":5,"8":15,"9":5,"10":6,"11":0,"12":0,"13":5},"b":{"0":[6,2],"1":[8,6],"2":[6,0],"3":[6,6],"4":[2,1],"5":[2,0],"6":[2,4],"7":[5,1],"8":[1,4],"9":[5,1],"10":[1,5],"11":[0,0],"12":[0,5]},"meta":{"lastBranch":13,"lastFunction":14,"lastStatement":60,"seen":{"f:5:9:5:24":0,"s:6:67:6:Infinity":0,"s:8:4:8:Infinity":1,"s:11:2:25:Infinity":2,"s:12:19:12:Infinity":3,"s:13:18:13:Infinity":4,"s:14:22:14:Infinity":5,"b:15:4:24:Infinity:undefined:undefined:undefined:undefined":0,"s:15:4:24:Infinity":6,"b:15:8:15:19:15:19:15:30":1,"s:16:23:16:Infinity":7,"b:17:6:23:Infinity:undefined:undefined:undefined:undefined":2,"s:17:6:23:Infinity":8,"s:18:8:22:Infinity":9,"s:26:2:26:Infinity":10,"f:29:9:29:28":1,"s:30:14:30:Infinity":11,"s:31:22:31:Infinity":12,"b:31:22:31:80:31:80:31:Infinity":3,"s:32:19:32:Infinity":13,"s:33:21:33:Infinity":14,"s:35:23:35:Infinity":15,"f:35:29:35:38":2,"s:35:44:35:75":16,"s:37:2:49:Infinity":17,"b:38:4:48:Infinity:undefined:undefined:undefined:undefined":4,"s:38:4:48:Infinity":18,"b:39:6:47:Infinity:undefined:undefined:undefined:undefined":5,"s:39:6:47:Infinity":19,"s:40:8:40:Infinity":20,"s:41:8:44:Infinity":21,"s:45:8:45:Infinity":22,"s:46:8:46:Infinity":23,"b:51:2:53:Infinity:undefined:undefined:undefined:undefined":6,"s:51:2:53:Infinity":24,"s:52:4:52:Infinity":25,"f:56:9:56:30":3,"s:57:14:57:Infinity":26,"s:58:15:62:Infinity":27,"f:59:5:59:14":4,"s:59:20:59:51":28,"f:60:5:60:10":5,"s:60:16:60:33":29,"f:61:5:61:13":6,"s:61:19:61:26":30,"b:64:2:64:Infinity:undefined:undefined:undefined:undefined":7,"s:64:2:64:Infinity":31,"s:64:13:64:Infinity":32,"s:67:16:67:Infinity":33,"s:68:2:68:Infinity":34,"f:71:16:71:31":7,"s:72:8:72:Infinity":35,"f:72:16:72:29":8,"s:72:39:72:50":36,"s:73:8:73:Infinity":37,"s:75:2:107:Infinity":38,"f:75:2:75:18":9,"b:76:4:78:Infinity:undefined:undefined:undefined:undefined":8,"s:76:4:78:Infinity":39,"b:76:8:76:49:76:49:76:87":9,"s:77:6:77:Infinity":40,"s:80:10:84:Infinity":41,"f:80:10:80:35":10,"s:81:6:81:Infinity":42,"b:82:6:82:Infinity:undefined:undefined:undefined:undefined":10,"s:82:6:82:Infinity":43,"s:82:28:82:Infinity":44,"s:83:6:83:Infinity":45,"s:86:4:86:Infinity":46,"s:88:10:93:Infinity":47,"f:88:10:88:28":11,"b:89:6:92:Infinity:undefined:undefined:undefined:undefined":11,"s:89:6:92:Infinity":48,"s:90:8:90:Infinity":49,"s:91:8:91:Infinity":50,"s:95:10:97:Infinity":51,"f:95:10:95:27":12,"s:96:6:96:Infinity":52,"s:99:31:99:Infinity":53,"s:100:30:100:Infinity":54,"s:102:4:106:Infinity":55,"f:102:4:102:17":13,"b:103:6:103:Infinity:undefined:undefined:undefined:undefined":12,"s:103:6:103:Infinity":56,"s:103:28:103:Infinity":57,"s:104:6:104:Infinity":58,"s:105:6:105:Infinity":59},"fnNames":{}}} -,"/Users/aditya/Projects/PaperCache/src/hooks/useVariables.ts": {"path":"/Users/aditya/Projects/PaperCache/src/hooks/useVariables.ts","statementMap":{"0":{"start":{"line":6,"column":8},"end":{"line":6,"column":null}},"1":{"start":{"line":6,"column":39},"end":{"line":6,"column":50}},"2":{"start":{"line":9,"column":2},"end":{"line":39,"column":null}},"3":{"start":{"line":10,"column":16},"end":{"line":10,"column":null}},"4":{"start":{"line":12,"column":47},"end":{"line":12,"column":null}},"5":{"start":{"line":13,"column":20},"end":{"line":13,"column":null}},"6":{"start":{"line":15,"column":76},"end":{"line":15,"column":null}},"7":{"start":{"line":17,"column":6},"end":{"line":30,"column":null}},"8":{"start":{"line":19,"column":8},"end":{"line":29,"column":null}},"9":{"start":{"line":20,"column":23},"end":{"line":20,"column":null}},"10":{"start":{"line":21,"column":10},"end":{"line":28,"column":null}},"11":{"start":{"line":22,"column":12},"end":{"line":24,"column":null}},"12":{"start":{"line":23,"column":14},"end":{"line":23,"column":null}},"13":{"start":{"line":25,"column":12},"end":{"line":25,"column":null}},"14":{"start":{"line":27,"column":12},"end":{"line":27,"column":null}},"15":{"start":{"line":31,"column":6},"end":{"line":31,"column":null}},"16":{"start":{"line":31,"column":17},"end":{"line":31,"column":null}},"17":{"start":{"line":32,"column":7},"end":{"line":33,"column":null}},"18":{"start":{"line":35,"column":4},"end":{"line":35,"column":null}},"19":{"start":{"line":36,"column":4},"end":{"line":38,"column":null}},"20":{"start":{"line":37,"column":6},"end":{"line":37,"column":null}}},"fnMap":{"0":{"name":"useVariables","decl":{"start":{"line":5,"column":16},"end":{"line":5,"column":31}},"loc":{"start":{"line":5,"column":31},"end":{"line":40,"column":null}},"line":5},"1":{"name":"(anonymous_1)","decl":{"start":{"line":6,"column":16},"end":{"line":6,"column":29}},"loc":{"start":{"line":6,"column":39},"end":{"line":6,"column":50}},"line":6},"2":{"name":"(anonymous_2)","decl":{"start":{"line":9,"column":2},"end":{"line":9,"column":18}},"loc":{"start":{"line":9,"column":18},"end":{"line":39,"column":5}},"line":9},"3":{"name":"syncVars","decl":{"start":{"line":11,"column":19},"end":{"line":11,"column":30}},"loc":{"start":{"line":11,"column":30},"end":{"line":34,"column":null}},"line":11},"4":{"name":"(anonymous_4)","decl":{"start":{"line":36,"column":4},"end":{"line":36,"column":17}},"loc":{"start":{"line":36,"column":17},"end":{"line":38,"column":null}},"line":36}},"branchMap":{"0":{"loc":{"start":{"line":22,"column":12},"end":{"line":24,"column":null}},"type":"if","locations":[{"start":{"line":22,"column":12},"end":{"line":24,"column":null}},{"start":{},"end":{}}],"line":22},"1":{"loc":{"start":{"line":31,"column":6},"end":{"line":31,"column":null}},"type":"if","locations":[{"start":{"line":31,"column":6},"end":{"line":31,"column":null}},{"start":{},"end":{}}],"line":31}},"s":{"0":4,"1":12,"2":4,"3":4,"4":4,"5":4,"6":4,"7":4,"8":5,"9":7,"10":7,"11":7,"12":4,"13":7,"14":1,"15":4,"16":0,"17":4,"18":4,"19":4,"20":4},"f":{"0":4,"1":12,"2":4,"3":4,"4":4},"b":{"0":[4,3],"1":[0,4]},"meta":{"lastBranch":2,"lastFunction":5,"lastStatement":21,"seen":{"f:5:16:5:31":0,"s:6:8:6:Infinity":0,"f:6:16:6:29":1,"s:6:39:6:50":1,"s:9:2:39:Infinity":2,"f:9:2:9:18":2,"s:10:16:10:Infinity":3,"f:11:19:11:30":3,"s:12:47:12:Infinity":4,"s:13:20:13:Infinity":5,"s:15:76:15:Infinity":6,"s:17:6:30:Infinity":7,"s:19:8:29:Infinity":8,"s:20:23:20:Infinity":9,"s:21:10:28:Infinity":10,"b:22:12:24:Infinity:undefined:undefined:undefined:undefined":0,"s:22:12:24:Infinity":11,"s:23:14:23:Infinity":12,"s:25:12:25:Infinity":13,"s:27:12:27:Infinity":14,"b:31:6:31:Infinity:undefined:undefined:undefined:undefined":1,"s:31:6:31:Infinity":15,"s:31:17:31:Infinity":16,"s:32:7:33:Infinity":17,"s:35:4:35:Infinity":18,"s:36:4:38:Infinity":19,"f:36:4:36:17":4,"s:37:6:37:Infinity":20},"fnNames":{}}} -,"/Users/aditya/Projects/PaperCache/src/lib/safeStorage.ts": {"path":"/Users/aditya/Projects/PaperCache/src/lib/safeStorage.ts","statementMap":{"0":{"start":{"line":2,"column":20},"end":{"line":2,"column":null}},"1":{"start":{"line":3,"column":2},"end":{"line":3,"column":null}},"2":{"start":{"line":7,"column":20},"end":{"line":7,"column":null}},"3":{"start":{"line":8,"column":2},"end":{"line":8,"column":null}},"4":{"start":{"line":8,"column":18},"end":{"line":8,"column":null}},"5":{"start":{"line":9,"column":2},"end":{"line":9,"column":null}},"6":{"start":{"line":13,"column":16},"end":{"line":13,"column":null}},"7":{"start":{"line":14,"column":2},"end":{"line":17,"column":null}},"8":{"start":{"line":15,"column":4},"end":{"line":15,"column":null}},"9":{"start":{"line":16,"column":4},"end":{"line":16,"column":null}}},"fnMap":{"0":{"name":"setSecure","decl":{"start":{"line":1,"column":22},"end":{"line":1,"column":32}},"loc":{"start":{"line":1,"column":75},"end":{"line":4,"column":null}},"line":1},"1":{"name":"getSecure","decl":{"start":{"line":6,"column":22},"end":{"line":6,"column":32}},"loc":{"start":{"line":6,"column":69},"end":{"line":10,"column":null}},"line":6},"2":{"name":"migrateApiKeyFromLocalStorage","decl":{"start":{"line":12,"column":22},"end":{"line":12,"column":52}},"loc":{"start":{"line":12,"column":65},"end":{"line":18,"column":null}},"line":12}},"branchMap":{"0":{"loc":{"start":{"line":8,"column":2},"end":{"line":8,"column":null}},"type":"if","locations":[{"start":{"line":8,"column":2},"end":{"line":8,"column":null}},{"start":{},"end":{}}],"line":8},"1":{"loc":{"start":{"line":14,"column":2},"end":{"line":17,"column":null}},"type":"if","locations":[{"start":{"line":14,"column":2},"end":{"line":17,"column":null}},{"start":{},"end":{}}],"line":14}},"s":{"0":1,"1":1,"2":2,"3":2,"4":1,"5":1,"6":0,"7":0,"8":0,"9":0},"f":{"0":1,"1":2,"2":0},"b":{"0":[1,1],"1":[0,0]},"meta":{"lastBranch":2,"lastFunction":3,"lastStatement":10,"seen":{"f:1:22:1:32":0,"s:2:20:2:Infinity":0,"s:3:2:3:Infinity":1,"f:6:22:6:32":1,"s:7:20:7:Infinity":2,"b:8:2:8:Infinity:undefined:undefined:undefined:undefined":0,"s:8:2:8:Infinity":3,"s:8:18:8:Infinity":4,"s:9:2:9:Infinity":5,"f:12:22:12:52":2,"s:13:16:13:Infinity":6,"b:14:2:17:Infinity:undefined:undefined:undefined:undefined":1,"s:14:2:17:Infinity":7,"s:15:4:15:Infinity":8,"s:16:4:16:Infinity":9},"fnNames":{}}} -,"/Users/aditya/Projects/PaperCache/src/lib/settingsKeys.ts": {"path":"/Users/aditya/Projects/PaperCache/src/lib/settingsKeys.ts","statementMap":{"0":{"start":{"line":1,"column":29},"end":{"line":20,"column":null}}},"fnMap":{},"branchMap":{},"s":{"0":2},"f":{},"b":{},"meta":{"lastBranch":0,"lastFunction":0,"lastStatement":1,"seen":{"s:1:29:20:Infinity":0},"fnNames":{}}} -,"/Users/aditya/Projects/PaperCache/src/lib/editor/MathEvaluator.ts": {"path":"/Users/aditya/Projects/PaperCache/src/lib/editor/MathEvaluator.ts","statementMap":{"0":{"start":{"line":5,"column":38},"end":{"line":5,"column":null}},"1":{"start":{"line":12,"column":4},"end":{"line":16,"column":null}},"2":{"start":{"line":13,"column":6},"end":{"line":13,"column":null}},"3":{"start":{"line":15,"column":6},"end":{"line":15,"column":null}},"4":{"start":{"line":17,"column":68},"end":{"line":17,"column":null}},"5":{"start":{"line":20,"column":18},"end":{"line":20,"column":null}},"6":{"start":{"line":21,"column":17},"end":{"line":21,"column":null}},"7":{"start":{"line":22,"column":4},"end":{"line":41,"column":null}},"8":{"start":{"line":22,"column":17},"end":{"line":22,"column":20}},"9":{"start":{"line":23,"column":19},"end":{"line":23,"column":null}},"10":{"start":{"line":24,"column":22},"end":{"line":24,"column":null}},"11":{"start":{"line":26,"column":6},"end":{"line":38,"column":null}},"12":{"start":{"line":27,"column":21},"end":{"line":27,"column":null}},"13":{"start":{"line":28,"column":8},"end":{"line":37,"column":null}},"14":{"start":{"line":29,"column":10},"end":{"line":36,"column":null}},"15":{"start":{"line":30,"column":27},"end":{"line":30,"column":null}},"16":{"start":{"line":31,"column":12},"end":{"line":35,"column":null}},"17":{"start":{"line":40,"column":6},"end":{"line":40,"column":null}},"18":{"start":{"line":44,"column":19},"end":{"line":44,"column":null}},"19":{"start":{"line":46,"column":4},"end":{"line":66,"column":null}},"20":{"start":{"line":47,"column":23},"end":{"line":47,"column":null}},"21":{"start":{"line":48,"column":24},"end":{"line":48,"column":null}},"22":{"start":{"line":49,"column":19},"end":{"line":49,"column":null}},"23":{"start":{"line":50,"column":6},"end":{"line":65,"column":null}},"24":{"start":{"line":51,"column":8},"end":{"line":64,"column":null}},"25":{"start":{"line":52,"column":28},"end":{"line":52,"column":null}},"26":{"start":{"line":53,"column":10},"end":{"line":63,"column":null}},"27":{"start":{"line":54,"column":33},"end":{"line":54,"column":null}},"28":{"start":{"line":55,"column":31},"end":{"line":55,"column":null}},"29":{"start":{"line":56,"column":12},"end":{"line":62,"column":null}},"30":{"start":{"line":56,"column":37},"end":{"line":56,"column":81}},"31":{"start":{"line":57,"column":14},"end":{"line":61,"column":null}},"32":{"start":{"line":68,"column":4},"end":{"line":68,"column":null}},"33":{"start":{"line":72,"column":4},"end":{"line":72,"column":null}},"34":{"start":{"line":72,"column":26},"end":{"line":72,"column":null}},"35":{"start":{"line":73,"column":4},"end":{"line":81,"column":null}},"36":{"start":{"line":74,"column":21},"end":{"line":74,"column":null}},"37":{"start":{"line":75,"column":20},"end":{"line":75,"column":null}},"38":{"start":{"line":76,"column":22},"end":{"line":76,"column":null}},"39":{"start":{"line":78,"column":6},"end":{"line":80,"column":null}},"40":{"start":{"line":79,"column":8},"end":{"line":79,"column":null}}},"fnMap":{"0":{"name":"evaluateMathChanges","decl":{"start":{"line":7,"column":15},"end":{"line":7,"column":null}},"loc":{"start":{"line":10,"column":61},"end":{"line":69,"column":null}},"line":10},"1":{"name":"(anonymous_1)","decl":{"start":{"line":56,"column":25},"end":{"line":56,"column":31}},"loc":{"start":{"line":56,"column":37},"end":{"line":56,"column":81}},"line":56},"2":{"name":"triggerMathEvaluation","decl":{"start":{"line":71,"column":9},"end":{"line":71,"column":31}},"loc":{"start":{"line":71,"column":49},"end":{"line":82,"column":null}},"line":71},"3":{"name":"(anonymous_3)","decl":{"start":{"line":73,"column":41},"end":{"line":73,"column":53}},"loc":{"start":{"line":73,"column":53},"end":{"line":81,"column":7}},"line":73}},"branchMap":{"0":{"loc":{"start":{"line":26,"column":6},"end":{"line":38,"column":null}},"type":"if","locations":[{"start":{"line":26,"column":6},"end":{"line":38,"column":null}},{"start":{},"end":{}}],"line":26},"1":{"loc":{"start":{"line":26,"column":10},"end":{"line":26,"column":65}},"type":"binary-expr","locations":[{"start":{"line":26,"column":10},"end":{"line":26,"column":38}},{"start":{"line":26,"column":38},"end":{"line":26,"column":65}}],"line":26},"2":{"loc":{"start":{"line":28,"column":8},"end":{"line":37,"column":null}},"type":"if","locations":[{"start":{"line":28,"column":8},"end":{"line":37,"column":null}},{"start":{},"end":{}}],"line":28},"3":{"loc":{"start":{"line":28,"column":12},"end":{"line":28,"column":78}},"type":"binary-expr","locations":[{"start":{"line":28,"column":12},"end":{"line":28,"column":20}},{"start":{"line":28,"column":20},"end":{"line":28,"column":48}},{"start":{"line":28,"column":48},"end":{"line":28,"column":78}}],"line":28},"4":{"loc":{"start":{"line":50,"column":6},"end":{"line":65,"column":null}},"type":"if","locations":[{"start":{"line":50,"column":6},"end":{"line":65,"column":null}},{"start":{},"end":{}}],"line":50},"5":{"loc":{"start":{"line":53,"column":10},"end":{"line":63,"column":null}},"type":"if","locations":[{"start":{"line":53,"column":10},"end":{"line":63,"column":null}},{"start":{},"end":{}}],"line":53},"6":{"loc":{"start":{"line":56,"column":12},"end":{"line":62,"column":null}},"type":"if","locations":[{"start":{"line":56,"column":12},"end":{"line":62,"column":null}},{"start":{},"end":{}}],"line":56},"7":{"loc":{"start":{"line":56,"column":37},"end":{"line":56,"column":81}},"type":"binary-expr","locations":[{"start":{"line":56,"column":37},"end":{"line":56,"column":61}},{"start":{"line":56,"column":61},"end":{"line":56,"column":81}}],"line":56},"8":{"loc":{"start":{"line":72,"column":4},"end":{"line":72,"column":null}},"type":"if","locations":[{"start":{"line":72,"column":4},"end":{"line":72,"column":null}},{"start":{},"end":{}}],"line":72},"9":{"loc":{"start":{"line":78,"column":6},"end":{"line":80,"column":null}},"type":"if","locations":[{"start":{"line":78,"column":6},"end":{"line":80,"column":null}},{"start":{},"end":{}}],"line":78}},"s":{"0":1,"1":5,"2":5,"3":0,"4":5,"5":5,"6":5,"7":5,"8":5,"9":9,"10":9,"11":9,"12":3,"13":3,"14":3,"15":3,"16":3,"17":9,"18":5,"19":5,"20":1,"21":1,"22":1,"23":1,"24":1,"25":1,"26":1,"27":1,"28":1,"29":1,"30":0,"31":1,"32":5,"33":0,"34":0,"35":0,"36":0,"37":0,"38":0,"39":0,"40":0},"f":{"0":1,"1":0,"2":1,"3":0},"b":{"0":[3,6],"1":[9,8],"2":[3,0],"3":[3,3,3],"4":[1,0],"5":[1,0],"6":[1,0],"7":[0,0],"8":[0,0],"9":[0,0]},"meta":{"lastBranch":10,"lastFunction":4,"lastStatement":41,"seen":{"s:5:38:5:Infinity":0,"f:7:15:7:Infinity":0,"s:12:4:16:Infinity":1,"s:13:6:13:Infinity":2,"s:15:6:15:Infinity":3,"s:17:68:17:Infinity":4,"s:20:18:20:Infinity":5,"s:21:17:21:Infinity":6,"s:22:4:41:Infinity":7,"s:22:17:22:20":8,"s:23:19:23:Infinity":9,"s:24:22:24:Infinity":10,"b:26:6:38:Infinity:undefined:undefined:undefined:undefined":0,"s:26:6:38:Infinity":11,"b:26:10:26:38:26:38:26:65":1,"s:27:21:27:Infinity":12,"b:28:8:37:Infinity:undefined:undefined:undefined:undefined":2,"s:28:8:37:Infinity":13,"b:28:12:28:20:28:20:28:48:28:48:28:78":3,"s:29:10:36:Infinity":14,"s:30:27:30:Infinity":15,"s:31:12:35:Infinity":16,"s:40:6:40:Infinity":17,"s:44:19:44:Infinity":18,"s:46:4:66:Infinity":19,"s:47:23:47:Infinity":20,"s:48:24:48:Infinity":21,"s:49:19:49:Infinity":22,"b:50:6:65:Infinity:undefined:undefined:undefined:undefined":4,"s:50:6:65:Infinity":23,"s:51:8:64:Infinity":24,"s:52:28:52:Infinity":25,"b:53:10:63:Infinity:undefined:undefined:undefined:undefined":5,"s:53:10:63:Infinity":26,"s:54:33:54:Infinity":27,"s:55:31:55:Infinity":28,"b:56:12:62:Infinity:undefined:undefined:undefined:undefined":6,"s:56:12:62:Infinity":29,"f:56:25:56:31":1,"s:56:37:56:81":30,"b:56:37:56:61:56:61:56:81":7,"s:57:14:61:Infinity":31,"s:68:4:68:Infinity":32,"f:71:9:71:31":2,"b:72:4:72:Infinity:undefined:undefined:undefined:undefined":8,"s:72:4:72:Infinity":33,"s:72:26:72:Infinity":34,"s:73:4:81:Infinity":35,"f:73:41:73:53":3,"s:74:21:74:Infinity":36,"s:75:20:75:Infinity":37,"s:76:22:76:Infinity":38,"b:78:6:80:Infinity:undefined:undefined:undefined:undefined":9,"s:78:6:80:Infinity":39,"s:79:8:79:Infinity":40},"fnNames":{}}} -,"/Users/aditya/Projects/PaperCache/src/lib/editor/VariableScope.ts": {"path":"/Users/aditya/Projects/PaperCache/src/lib/editor/VariableScope.ts","statementMap":{"0":{"start":{"line":4,"column":34},"end":{"line":4,"column":null}},"1":{"start":{"line":7,"column":53},"end":{"line":7,"column":null}},"2":{"start":{"line":8,"column":25},"end":{"line":8,"column":null}},"3":{"start":{"line":9,"column":43},"end":{"line":9,"column":null}},"4":{"start":{"line":10,"column":24},"end":{"line":10,"column":null}},"5":{"start":{"line":13,"column":4},"end":{"line":13,"column":null}},"6":{"start":{"line":13,"column":39},"end":{"line":13,"column":null}},"7":{"start":{"line":14,"column":4},"end":{"line":14,"column":null}},"8":{"start":{"line":15,"column":4},"end":{"line":15,"column":null}},"9":{"start":{"line":15,"column":31},"end":{"line":15,"column":null}},"10":{"start":{"line":16,"column":4},"end":{"line":16,"column":null}},"11":{"start":{"line":17,"column":27},"end":{"line":17,"column":null}},"12":{"start":{"line":18,"column":4},"end":{"line":56,"column":null}},"13":{"start":{"line":20,"column":6},"end":{"line":24,"column":null}},"14":{"start":{"line":21,"column":8},"end":{"line":21,"column":null}},"15":{"start":{"line":23,"column":8},"end":{"line":23,"column":null}},"16":{"start":{"line":26,"column":48},"end":{"line":26,"column":null}},"17":{"start":{"line":27,"column":20},"end":{"line":27,"column":null}},"18":{"start":{"line":29,"column":20},"end":{"line":29,"column":null}},"19":{"start":{"line":32,"column":9},"end":{"line":33,"column":null}},"20":{"start":{"line":35,"column":6},"end":{"line":46,"column":null}},"21":{"start":{"line":36,"column":21},"end":{"line":36,"column":null}},"22":{"start":{"line":37,"column":8},"end":{"line":42,"column":null}},"23":{"start":{"line":38,"column":22},"end":{"line":38,"column":null}},"24":{"start":{"line":39,"column":10},"end":{"line":39,"column":null}},"25":{"start":{"line":41,"column":10},"end":{"line":41,"column":null}},"26":{"start":{"line":43,"column":8},"end":{"line":45,"column":null}},"27":{"start":{"line":44,"column":10},"end":{"line":44,"column":null}},"28":{"start":{"line":48,"column":6},"end":{"line":48,"column":null}},"29":{"start":{"line":48,"column":48},"end":{"line":48,"column":null}},"30":{"start":{"line":49,"column":6},"end":{"line":55,"column":null}},"31":{"start":{"line":50,"column":8},"end":{"line":50,"column":null}},"32":{"start":{"line":51,"column":8},"end":{"line":54,"column":null}},"33":{"start":{"line":52,"column":10},"end":{"line":52,"column":null}},"34":{"start":{"line":53,"column":10},"end":{"line":53,"column":null}},"35":{"start":{"line":53,"column":64},"end":{"line":53,"column":null}},"36":{"start":{"line":61,"column":7},"end":{"line":61,"column":null}},"37":{"start":{"line":62,"column":4},"end":{"line":62,"column":null}}},"fnMap":{"0":{"name":"triggerScopeUpdate","decl":{"start":{"line":12,"column":9},"end":{"line":12,"column":28}},"loc":{"start":{"line":12,"column":69},"end":{"line":57,"column":null}},"line":12},"1":{"name":"(anonymous_1)","decl":{"start":{"line":18,"column":46},"end":{"line":18,"column":58}},"loc":{"start":{"line":18,"column":58},"end":{"line":56,"column":7}},"line":18},"2":{"name":"(anonymous_2)","decl":{"start":{"line":53,"column":50},"end":{"line":53,"column":64}},"loc":{"start":{"line":53,"column":64},"end":{"line":53,"column":null}},"line":53},"3":{"name":"getScope","decl":{"start":{"line":59,"column":9},"end":{"line":59,"column":45}},"loc":{"start":{"line":59,"column":45},"end":{"line":63,"column":null}},"line":59}},"branchMap":{"0":{"loc":{"start":{"line":13,"column":4},"end":{"line":13,"column":null}},"type":"if","locations":[{"start":{"line":13,"column":4},"end":{"line":13,"column":null}},{"start":{},"end":{}}],"line":13},"1":{"loc":{"start":{"line":15,"column":4},"end":{"line":15,"column":null}},"type":"if","locations":[{"start":{"line":15,"column":4},"end":{"line":15,"column":null}},{"start":{},"end":{}}],"line":15},"2":{"loc":{"start":{"line":32,"column":9},"end":{"line":33,"column":null}},"type":"binary-expr","locations":[{"start":{"line":32,"column":9},"end":{"line":32,"column":null}},{"start":{"line":33,"column":8},"end":{"line":33,"column":null}}],"line":32},"3":{"loc":{"start":{"line":43,"column":8},"end":{"line":45,"column":null}},"type":"if","locations":[{"start":{"line":43,"column":8},"end":{"line":45,"column":null}},{"start":{},"end":{}}],"line":43},"4":{"loc":{"start":{"line":48,"column":6},"end":{"line":48,"column":null}},"type":"if","locations":[{"start":{"line":48,"column":6},"end":{"line":48,"column":null}},{"start":{},"end":{}}],"line":48},"5":{"loc":{"start":{"line":49,"column":6},"end":{"line":55,"column":null}},"type":"if","locations":[{"start":{"line":49,"column":6},"end":{"line":55,"column":null}},{"start":{},"end":{}}],"line":49},"6":{"loc":{"start":{"line":49,"column":10},"end":{"line":49,"column":97}},"type":"binary-expr","locations":[{"start":{"line":49,"column":10},"end":{"line":49,"column":21}},{"start":{"line":49,"column":21},"end":{"line":49,"column":97}}],"line":49},"7":{"loc":{"start":{"line":51,"column":8},"end":{"line":54,"column":null}},"type":"if","locations":[{"start":{"line":51,"column":8},"end":{"line":54,"column":null}},{"start":{},"end":{}}],"line":51},"8":{"loc":{"start":{"line":61,"column":7},"end":{"line":61,"column":null}},"type":"binary-expr","locations":[{"start":{"line":61,"column":7},"end":{"line":61,"column":97}},{"start":{"line":61,"column":97},"end":{"line":61,"column":null}}],"line":61}},"s":{"0":1,"1":1,"2":1,"3":1,"4":1,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0,"21":0,"22":0,"23":0,"24":0,"25":0,"26":0,"27":0,"28":0,"29":0,"30":0,"31":0,"32":0,"33":0,"34":0,"35":0,"36":0,"37":0},"f":{"0":1,"1":0,"2":0,"3":1},"b":{"0":[0,0],"1":[0,0],"2":[0,0],"3":[0,0],"4":[0,0],"5":[0,0],"6":[0,0],"7":[0,0],"8":[0,0]},"meta":{"lastBranch":9,"lastFunction":4,"lastStatement":38,"seen":{"s:4:34:4:Infinity":0,"s:7:53:7:Infinity":1,"s:8:25:8:Infinity":2,"s:9:43:9:Infinity":3,"s:10:24:10:Infinity":4,"f:12:9:12:28":0,"b:13:4:13:Infinity:undefined:undefined:undefined:undefined":0,"s:13:4:13:Infinity":5,"s:13:39:13:Infinity":6,"s:14:4:14:Infinity":7,"b:15:4:15:Infinity:undefined:undefined:undefined:undefined":1,"s:15:4:15:Infinity":8,"s:15:31:15:Infinity":9,"s:16:4:16:Infinity":10,"s:17:27:17:Infinity":11,"s:18:4:56:Infinity":12,"f:18:46:18:58":1,"s:20:6:24:Infinity":13,"s:21:8:21:Infinity":14,"s:23:8:23:Infinity":15,"s:26:48:26:Infinity":16,"s:27:20:27:Infinity":17,"s:29:20:29:Infinity":18,"s:32:9:33:Infinity":19,"b:32:9:32:Infinity:33:8:33:Infinity":2,"s:35:6:46:Infinity":20,"s:36:21:36:Infinity":21,"s:37:8:42:Infinity":22,"s:38:22:38:Infinity":23,"s:39:10:39:Infinity":24,"s:41:10:41:Infinity":25,"b:43:8:45:Infinity:undefined:undefined:undefined:undefined":3,"s:43:8:45:Infinity":26,"s:44:10:44:Infinity":27,"b:48:6:48:Infinity:undefined:undefined:undefined:undefined":4,"s:48:6:48:Infinity":28,"s:48:48:48:Infinity":29,"b:49:6:55:Infinity:undefined:undefined:undefined:undefined":5,"s:49:6:55:Infinity":30,"b:49:10:49:21:49:21:49:97":6,"s:50:8:50:Infinity":31,"b:51:8:54:Infinity:undefined:undefined:undefined:undefined":7,"s:51:8:54:Infinity":32,"s:52:10:52:Infinity":33,"s:53:10:53:Infinity":34,"f:53:50:53:64":2,"s:53:64:53:Infinity":35,"f:59:9:59:45":3,"s:61:7:61:Infinity":36,"b:61:7:61:97:61:97:61:Infinity":8,"s:62:4:62:Infinity":37},"fnNames":{}}} -,"/Users/aditya/Projects/PaperCache/src/lib/editor/widgets.ts": {"path":"/Users/aditya/Projects/PaperCache/src/lib/editor/widgets.ts","statementMap":{"0":{"start":{"line":7,"column":4},"end":{"line":7,"column":null}},"1":{"start":{"line":8,"column":4},"end":{"line":8,"column":null}},"2":{"start":{"line":9,"column":4},"end":{"line":9,"column":null}},"3":{"start":{"line":13,"column":4},"end":{"line":13,"column":null}},"4":{"start":{"line":17,"column":17},"end":{"line":17,"column":null}},"5":{"start":{"line":18,"column":4},"end":{"line":18,"column":null}},"6":{"start":{"line":19,"column":4},"end":{"line":19,"column":null}},"7":{"start":{"line":20,"column":4},"end":{"line":20,"column":null}},"8":{"start":{"line":22,"column":4},"end":{"line":27,"column":null}},"9":{"start":{"line":23,"column":23},"end":{"line":23,"column":null}},"10":{"start":{"line":24,"column":6},"end":{"line":24,"column":null}},"11":{"start":{"line":25,"column":6},"end":{"line":25,"column":null}},"12":{"start":{"line":26,"column":6},"end":{"line":26,"column":null}},"13":{"start":{"line":29,"column":21},"end":{"line":29,"column":null}},"14":{"start":{"line":31,"column":4},"end":{"line":31,"column":null}},"15":{"start":{"line":32,"column":4},"end":{"line":32,"column":null}},"16":{"start":{"line":34,"column":4},"end":{"line":44,"column":null}},"17":{"start":{"line":35,"column":6},"end":{"line":35,"column":null}},"18":{"start":{"line":36,"column":6},"end":{"line":36,"column":null}},"19":{"start":{"line":37,"column":6},"end":{"line":37,"column":null}},"20":{"start":{"line":38,"column":27},"end":{"line":38,"column":null}},"21":{"start":{"line":40,"column":6},"end":{"line":40,"column":null}},"22":{"start":{"line":41,"column":6},"end":{"line":43,"column":null}},"23":{"start":{"line":42,"column":8},"end":{"line":42,"column":null}},"24":{"start":{"line":45,"column":4},"end":{"line":45,"column":null}},"25":{"start":{"line":55,"column":4},"end":{"line":55,"column":null}},"26":{"start":{"line":56,"column":4},"end":{"line":56,"column":null}},"27":{"start":{"line":57,"column":4},"end":{"line":57,"column":null}},"28":{"start":{"line":58,"column":4},"end":{"line":58,"column":null}},"29":{"start":{"line":62,"column":4},"end":{"line":62,"column":null}},"30":{"start":{"line":66,"column":17},"end":{"line":66,"column":null}},"31":{"start":{"line":67,"column":4},"end":{"line":67,"column":null}},"32":{"start":{"line":69,"column":4},"end":{"line":73,"column":null}},"33":{"start":{"line":70,"column":6},"end":{"line":70,"column":null}},"34":{"start":{"line":72,"column":6},"end":{"line":72,"column":null}},"35":{"start":{"line":75,"column":4},"end":{"line":84,"column":null}},"36":{"start":{"line":76,"column":6},"end":{"line":76,"column":null}},"37":{"start":{"line":77,"column":6},"end":{"line":77,"column":null}},"38":{"start":{"line":78,"column":19},"end":{"line":78,"column":null}},"39":{"start":{"line":79,"column":17},"end":{"line":79,"column":null}},"40":{"start":{"line":80,"column":21},"end":{"line":80,"column":null}},"41":{"start":{"line":81,"column":6},"end":{"line":83,"column":null}},"42":{"start":{"line":86,"column":4},"end":{"line":86,"column":null}},"43":{"start":{"line":93,"column":4},"end":{"line":93,"column":null}},"44":{"start":{"line":94,"column":4},"end":{"line":94,"column":null}},"45":{"start":{"line":97,"column":4},"end":{"line":97,"column":null}},"46":{"start":{"line":100,"column":17},"end":{"line":100,"column":null}},"47":{"start":{"line":101,"column":4},"end":{"line":101,"column":null}},"48":{"start":{"line":102,"column":4},"end":{"line":102,"column":null}},"49":{"start":{"line":103,"column":4},"end":{"line":103,"column":null}},"50":{"start":{"line":110,"column":4},"end":{"line":110,"column":null}},"51":{"start":{"line":111,"column":4},"end":{"line":111,"column":null}},"52":{"start":{"line":114,"column":4},"end":{"line":114,"column":null}},"53":{"start":{"line":117,"column":17},"end":{"line":117,"column":null}},"54":{"start":{"line":118,"column":4},"end":{"line":118,"column":null}},"55":{"start":{"line":119,"column":4},"end":{"line":119,"column":null}},"56":{"start":{"line":121,"column":19},"end":{"line":121,"column":null}},"57":{"start":{"line":122,"column":4},"end":{"line":122,"column":null}},"58":{"start":{"line":123,"column":4},"end":{"line":123,"column":null}},"59":{"start":{"line":124,"column":4},"end":{"line":124,"column":null}},"60":{"start":{"line":125,"column":4},"end":{"line":125,"column":null}},"61":{"start":{"line":126,"column":4},"end":{"line":126,"column":null}},"62":{"start":{"line":127,"column":4},"end":{"line":127,"column":null}},"63":{"start":{"line":128,"column":4},"end":{"line":128,"column":null}},"64":{"start":{"line":129,"column":4},"end":{"line":129,"column":null}},"65":{"start":{"line":130,"column":4},"end":{"line":130,"column":null}},"66":{"start":{"line":132,"column":4},"end":{"line":144,"column":null}},"67":{"start":{"line":133,"column":6},"end":{"line":133,"column":null}},"68":{"start":{"line":134,"column":6},"end":{"line":134,"column":null}},"69":{"start":{"line":135,"column":6},"end":{"line":135,"column":null}},"70":{"start":{"line":137,"column":6},"end":{"line":137,"column":null}},"71":{"start":{"line":138,"column":6},"end":{"line":138,"column":null}},"72":{"start":{"line":139,"column":6},"end":{"line":139,"column":null}},"73":{"start":{"line":141,"column":6},"end":{"line":143,"column":null}},"74":{"start":{"line":142,"column":8},"end":{"line":142,"column":null}},"75":{"start":{"line":146,"column":17},"end":{"line":146,"column":null}},"76":{"start":{"line":148,"column":4},"end":{"line":148,"column":null}},"77":{"start":{"line":149,"column":4},"end":{"line":149,"column":null}},"78":{"start":{"line":151,"column":4},"end":{"line":151,"column":null}},"79":{"start":{"line":162,"column":4},"end":{"line":162,"column":null}},"80":{"start":{"line":163,"column":4},"end":{"line":163,"column":null}},"81":{"start":{"line":164,"column":4},"end":{"line":164,"column":null}},"82":{"start":{"line":165,"column":4},"end":{"line":165,"column":null}},"83":{"start":{"line":166,"column":4},"end":{"line":166,"column":null}},"84":{"start":{"line":170,"column":4},"end":{"line":171,"column":null}},"85":{"start":{"line":176,"column":17},"end":{"line":176,"column":null}},"86":{"start":{"line":177,"column":4},"end":{"line":180,"column":null}},"87":{"start":{"line":182,"column":4},"end":{"line":186,"column":null}},"88":{"start":{"line":183,"column":6},"end":{"line":183,"column":null}},"89":{"start":{"line":185,"column":6},"end":{"line":185,"column":null}},"90":{"start":{"line":189,"column":4},"end":{"line":200,"column":null}},"91":{"start":{"line":190,"column":6},"end":{"line":190,"column":null}},"92":{"start":{"line":191,"column":6},"end":{"line":191,"column":null}},"93":{"start":{"line":193,"column":19},"end":{"line":193,"column":null}},"94":{"start":{"line":194,"column":17},"end":{"line":194,"column":null}},"95":{"start":{"line":195,"column":21},"end":{"line":195,"column":null}},"96":{"start":{"line":197,"column":6},"end":{"line":199,"column":null}},"97":{"start":{"line":202,"column":4},"end":{"line":202,"column":null}},"98":{"start":{"line":206,"column":4},"end":{"line":206,"column":null}},"99":{"start":{"line":212,"column":17},"end":{"line":212,"column":null}},"100":{"start":{"line":213,"column":4},"end":{"line":213,"column":null}},"101":{"start":{"line":214,"column":4},"end":{"line":214,"column":null}},"102":{"start":{"line":215,"column":4},"end":{"line":215,"column":null}}},"fnMap":{"0":{"name":"constructor","decl":{"start":{"line":6,"column":2},"end":{"line":6,"column":14}},"loc":{"start":{"line":6,"column":46},"end":{"line":10,"column":null}},"line":6},"1":{"name":"eq","decl":{"start":{"line":12,"column":2},"end":{"line":12,"column":5}},"loc":{"start":{"line":12,"column":24},"end":{"line":14,"column":null}},"line":12},"2":{"name":"toDOM","decl":{"start":{"line":16,"column":2},"end":{"line":16,"column":10}},"loc":{"start":{"line":16,"column":10},"end":{"line":46,"column":null}},"line":16},"3":{"name":"(anonymous_3)","decl":{"start":{"line":34,"column":9},"end":{"line":34,"column":20}},"loc":{"start":{"line":34,"column":26},"end":{"line":44,"column":null}},"line":34},"4":{"name":"(anonymous_4)","decl":{"start":{"line":41,"column":6},"end":{"line":41,"column":23}},"loc":{"start":{"line":41,"column":23},"end":{"line":43,"column":9}},"line":41},"5":{"name":"constructor_2","decl":{"start":{"line":54,"column":2},"end":{"line":54,"column":14}},"loc":{"start":{"line":54,"column":63},"end":{"line":59,"column":null}},"line":54},"6":{"name":"eq_2","decl":{"start":{"line":61,"column":2},"end":{"line":61,"column":5}},"loc":{"start":{"line":61,"column":28},"end":{"line":63,"column":null}},"line":61},"7":{"name":"toDOM_2","decl":{"start":{"line":65,"column":2},"end":{"line":65,"column":10}},"loc":{"start":{"line":65,"column":10},"end":{"line":87,"column":null}},"line":65},"8":{"name":"(anonymous_8)","decl":{"start":{"line":75,"column":9},"end":{"line":75,"column":20}},"loc":{"start":{"line":75,"column":26},"end":{"line":84,"column":null}},"line":75},"9":{"name":"constructor_3","decl":{"start":{"line":92,"column":2},"end":{"line":92,"column":14}},"loc":{"start":{"line":92,"column":29},"end":{"line":95,"column":null}},"line":92},"10":{"name":"eq_3","decl":{"start":{"line":96,"column":2},"end":{"line":96,"column":5}},"loc":{"start":{"line":96,"column":28},"end":{"line":98,"column":null}},"line":96},"11":{"name":"toDOM_3","decl":{"start":{"line":99,"column":2},"end":{"line":99,"column":10}},"loc":{"start":{"line":99,"column":10},"end":{"line":104,"column":null}},"line":99},"12":{"name":"constructor_4","decl":{"start":{"line":109,"column":2},"end":{"line":109,"column":14}},"loc":{"start":{"line":109,"column":29},"end":{"line":112,"column":null}},"line":109},"13":{"name":"eq_4","decl":{"start":{"line":113,"column":2},"end":{"line":113,"column":5}},"loc":{"start":{"line":113,"column":25},"end":{"line":115,"column":null}},"line":113},"14":{"name":"toDOM_4","decl":{"start":{"line":116,"column":2},"end":{"line":116,"column":10}},"loc":{"start":{"line":116,"column":10},"end":{"line":152,"column":null}},"line":116},"15":{"name":"(anonymous_15)","decl":{"start":{"line":132,"column":11},"end":{"line":132,"column":22}},"loc":{"start":{"line":132,"column":28},"end":{"line":144,"column":null}},"line":132},"16":{"name":"(anonymous_16)","decl":{"start":{"line":141,"column":6},"end":{"line":141,"column":23}},"loc":{"start":{"line":141,"column":23},"end":{"line":143,"column":9}},"line":141},"17":{"name":"constructor_5","decl":{"start":{"line":161,"column":2},"end":{"line":161,"column":14}},"loc":{"start":{"line":161,"column":81},"end":{"line":167,"column":null}},"line":161},"18":{"name":"eq_5","decl":{"start":{"line":169,"column":2},"end":{"line":169,"column":5}},"loc":{"start":{"line":169,"column":28},"end":{"line":173,"column":null}},"line":169},"19":{"name":"toDOM_5","decl":{"start":{"line":175,"column":2},"end":{"line":175,"column":10}},"loc":{"start":{"line":175,"column":10},"end":{"line":203,"column":null}},"line":175},"20":{"name":"(anonymous_20)","decl":{"start":{"line":189,"column":9},"end":{"line":189,"column":24}},"loc":{"start":{"line":189,"column":30},"end":{"line":200,"column":null}},"line":189},"21":{"name":"ignoreEvent","decl":{"start":{"line":205,"column":2},"end":{"line":205,"column":16}},"loc":{"start":{"line":205,"column":16},"end":{"line":207,"column":null}},"line":205},"22":{"name":"toDOM_6","decl":{"start":{"line":211,"column":2},"end":{"line":211,"column":10}},"loc":{"start":{"line":211,"column":10},"end":{"line":216,"column":null}},"line":211}},"branchMap":{"0":{"loc":{"start":{"line":13,"column":11},"end":{"line":13,"column":null}},"type":"binary-expr","locations":[{"start":{"line":13,"column":11},"end":{"line":13,"column":39}},{"start":{"line":13,"column":39},"end":{"line":13,"column":null}}],"line":13},"1":{"loc":{"start":{"line":22,"column":4},"end":{"line":27,"column":null}},"type":"if","locations":[{"start":{"line":22,"column":4},"end":{"line":27,"column":null}},{"start":{},"end":{}}],"line":22},"2":{"loc":{"start":{"line":62,"column":11},"end":{"line":62,"column":null}},"type":"binary-expr","locations":[{"start":{"line":62,"column":11},"end":{"line":62,"column":45}},{"start":{"line":62,"column":45},"end":{"line":62,"column":null}}],"line":62},"3":{"loc":{"start":{"line":67,"column":45},"end":{"line":67,"column":null}},"type":"cond-expr","locations":[{"start":{"line":67,"column":60},"end":{"line":67,"column":85}},{"start":{"line":67,"column":85},"end":{"line":67,"column":null}}],"line":67},"4":{"loc":{"start":{"line":69,"column":4},"end":{"line":73,"column":null}},"type":"if","locations":[{"start":{"line":69,"column":4},"end":{"line":73,"column":null}},{"start":{"line":71,"column":11},"end":{"line":73,"column":null}}],"line":69},"5":{"loc":{"start":{"line":79,"column":29},"end":{"line":79,"column":null}},"type":"cond-expr","locations":[{"start":{"line":79,"column":44},"end":{"line":79,"column":48}},{"start":{"line":79,"column":48},"end":{"line":79,"column":null}}],"line":79},"6":{"loc":{"start":{"line":80,"column":21},"end":{"line":80,"column":null}},"type":"cond-expr","locations":[{"start":{"line":80,"column":36},"end":{"line":80,"column":47}},{"start":{"line":80,"column":47},"end":{"line":80,"column":null}}],"line":80},"7":{"loc":{"start":{"line":171,"column":6},"end":{"line":171,"column":null}},"type":"binary-expr","locations":[{"start":{"line":171,"column":6},"end":{"line":171,"column":40}},{"start":{"line":171,"column":40},"end":{"line":171,"column":66}},{"start":{"line":171,"column":66},"end":{"line":171,"column":null}}],"line":171},"8":{"loc":{"start":{"line":179,"column":7},"end":{"line":179,"column":null}},"type":"cond-expr","locations":[{"start":{"line":179,"column":22},"end":{"line":179,"column":42}},{"start":{"line":179,"column":42},"end":{"line":179,"column":null}}],"line":179},"9":{"loc":{"start":{"line":180,"column":7},"end":{"line":180,"column":null}},"type":"cond-expr","locations":[{"start":{"line":180,"column":39},"end":{"line":180,"column":59}},{"start":{"line":180,"column":59},"end":{"line":180,"column":null}}],"line":180},"10":{"loc":{"start":{"line":180,"column":7},"end":{"line":180,"column":39}},"type":"binary-expr","locations":[{"start":{"line":180,"column":7},"end":{"line":180,"column":23}},{"start":{"line":180,"column":23},"end":{"line":180,"column":39}}],"line":180},"11":{"loc":{"start":{"line":182,"column":4},"end":{"line":186,"column":null}},"type":"if","locations":[{"start":{"line":182,"column":4},"end":{"line":186,"column":null}},{"start":{"line":184,"column":11},"end":{"line":186,"column":null}}],"line":182},"12":{"loc":{"start":{"line":194,"column":29},"end":{"line":194,"column":null}},"type":"cond-expr","locations":[{"start":{"line":194,"column":44},"end":{"line":194,"column":49}},{"start":{"line":194,"column":49},"end":{"line":194,"column":null}}],"line":194},"13":{"loc":{"start":{"line":195,"column":21},"end":{"line":195,"column":null}},"type":"cond-expr","locations":[{"start":{"line":195,"column":36},"end":{"line":195,"column":46}},{"start":{"line":195,"column":46},"end":{"line":195,"column":null}}],"line":195}},"s":{"0":4,"1":4,"2":4,"3":2,"4":1,"5":1,"6":1,"7":1,"8":1,"9":1,"10":1,"11":1,"12":1,"13":1,"14":1,"15":1,"16":1,"17":0,"18":0,"19":0,"20":0,"21":0,"22":0,"23":0,"24":1,"25":4,"26":4,"27":4,"28":4,"29":0,"30":4,"31":4,"32":4,"33":2,"34":2,"35":4,"36":2,"37":2,"38":2,"39":2,"40":2,"41":2,"42":4,"43":1,"44":1,"45":0,"46":1,"47":1,"48":1,"49":1,"50":1,"51":1,"52":0,"53":1,"54":1,"55":1,"56":1,"57":1,"58":1,"59":1,"60":1,"61":1,"62":1,"63":1,"64":1,"65":1,"66":1,"67":0,"68":0,"69":0,"70":0,"71":0,"72":0,"73":0,"74":0,"75":1,"76":1,"77":1,"78":1,"79":0,"80":0,"81":0,"82":0,"83":0,"84":0,"85":0,"86":0,"87":0,"88":0,"89":0,"90":0,"91":0,"92":0,"93":0,"94":0,"95":0,"96":0,"97":0,"98":0,"99":0,"100":0,"101":0,"102":0},"f":{"0":4,"1":2,"2":1,"3":0,"4":0,"5":4,"6":0,"7":4,"8":2,"9":1,"10":0,"11":1,"12":1,"13":0,"14":1,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0,"21":0,"22":0},"b":{"0":[2,1],"1":[1,0],"2":[0,0],"3":[2,2],"4":[2,2],"5":[1,1],"6":[1,1],"7":[0,0,0],"8":[0,0],"9":[0,0],"10":[0,0],"11":[0,0],"12":[0,0],"13":[0,0]},"meta":{"lastBranch":14,"lastFunction":23,"lastStatement":103,"seen":{"f:6:2:6:14":0,"s:7:4:7:Infinity":0,"s:8:4:8:Infinity":1,"s:9:4:9:Infinity":2,"f:12:2:12:5":1,"s:13:4:13:Infinity":3,"b:13:11:13:39:13:39:13:Infinity":0,"f:16:2:16:10":2,"s:17:17:17:Infinity":4,"s:18:4:18:Infinity":5,"s:19:4:19:Infinity":6,"s:20:4:20:Infinity":7,"b:22:4:27:Infinity:undefined:undefined:undefined:undefined":1,"s:22:4:27:Infinity":8,"s:23:23:23:Infinity":9,"s:24:6:24:Infinity":10,"s:25:6:25:Infinity":11,"s:26:6:26:Infinity":12,"s:29:21:29:Infinity":13,"s:31:4:31:Infinity":14,"s:32:4:32:Infinity":15,"s:34:4:44:Infinity":16,"f:34:9:34:20":3,"s:35:6:35:Infinity":17,"s:36:6:36:Infinity":18,"s:37:6:37:Infinity":19,"s:38:27:38:Infinity":20,"s:40:6:40:Infinity":21,"s:41:6:43:Infinity":22,"f:41:6:41:23":4,"s:42:8:42:Infinity":23,"s:45:4:45:Infinity":24,"f:54:2:54:14":5,"s:55:4:55:Infinity":25,"s:56:4:56:Infinity":26,"s:57:4:57:Infinity":27,"s:58:4:58:Infinity":28,"f:61:2:61:5":6,"s:62:4:62:Infinity":29,"b:62:11:62:45:62:45:62:Infinity":2,"f:65:2:65:10":7,"s:66:17:66:Infinity":30,"s:67:4:67:Infinity":31,"b:67:60:67:85:67:85:67:Infinity":3,"b:69:4:73:Infinity:71:11:73:Infinity":4,"s:69:4:73:Infinity":32,"s:70:6:70:Infinity":33,"s:72:6:72:Infinity":34,"s:75:4:84:Infinity":35,"f:75:9:75:20":8,"s:76:6:76:Infinity":36,"s:77:6:77:Infinity":37,"s:78:19:78:Infinity":38,"s:79:17:79:Infinity":39,"b:79:44:79:48:79:48:79:Infinity":5,"s:80:21:80:Infinity":40,"b:80:36:80:47:80:47:80:Infinity":6,"s:81:6:83:Infinity":41,"s:86:4:86:Infinity":42,"f:92:2:92:14":9,"s:93:4:93:Infinity":43,"s:94:4:94:Infinity":44,"f:96:2:96:5":10,"s:97:4:97:Infinity":45,"f:99:2:99:10":11,"s:100:17:100:Infinity":46,"s:101:4:101:Infinity":47,"s:102:4:102:Infinity":48,"s:103:4:103:Infinity":49,"f:109:2:109:14":12,"s:110:4:110:Infinity":50,"s:111:4:111:Infinity":51,"f:113:2:113:5":13,"s:114:4:114:Infinity":52,"f:116:2:116:10":14,"s:117:17:117:Infinity":53,"s:118:4:118:Infinity":54,"s:119:4:119:Infinity":55,"s:121:19:121:Infinity":56,"s:122:4:122:Infinity":57,"s:123:4:123:Infinity":58,"s:124:4:124:Infinity":59,"s:125:4:125:Infinity":60,"s:126:4:126:Infinity":61,"s:127:4:127:Infinity":62,"s:128:4:128:Infinity":63,"s:129:4:129:Infinity":64,"s:130:4:130:Infinity":65,"s:132:4:144:Infinity":66,"f:132:11:132:22":15,"s:133:6:133:Infinity":67,"s:134:6:134:Infinity":68,"s:135:6:135:Infinity":69,"s:137:6:137:Infinity":70,"s:138:6:138:Infinity":71,"s:139:6:139:Infinity":72,"s:141:6:143:Infinity":73,"f:141:6:141:23":16,"s:142:8:142:Infinity":74,"s:146:17:146:Infinity":75,"s:148:4:148:Infinity":76,"s:149:4:149:Infinity":77,"s:151:4:151:Infinity":78,"f:161:2:161:14":17,"s:162:4:162:Infinity":79,"s:163:4:163:Infinity":80,"s:164:4:164:Infinity":81,"s:165:4:165:Infinity":82,"s:166:4:166:Infinity":83,"f:169:2:169:5":18,"s:170:4:171:Infinity":84,"b:171:6:171:40:171:40:171:66:171:66:171:Infinity":7,"f:175:2:175:10":19,"s:176:17:176:Infinity":85,"s:177:4:180:Infinity":86,"b:179:22:179:42:179:42:179:Infinity":8,"b:180:39:180:59:180:59:180:Infinity":9,"b:180:7:180:23:180:23:180:39":10,"b:182:4:186:Infinity:184:11:186:Infinity":11,"s:182:4:186:Infinity":87,"s:183:6:183:Infinity":88,"s:185:6:185:Infinity":89,"s:189:4:200:Infinity":90,"f:189:9:189:24":20,"s:190:6:190:Infinity":91,"s:191:6:191:Infinity":92,"s:193:19:193:Infinity":93,"s:194:17:194:Infinity":94,"b:194:44:194:49:194:49:194:Infinity":12,"s:195:21:195:Infinity":95,"b:195:36:195:46:195:46:195:Infinity":13,"s:197:6:199:Infinity":96,"s:202:4:202:Infinity":97,"f:205:2:205:16":21,"s:206:4:206:Infinity":98,"f:211:2:211:10":22,"s:212:17:212:Infinity":99,"s:213:4:213:Infinity":100,"s:214:4:214:Infinity":101,"s:215:4:215:Infinity":102},"fnNames":{}}} -,"/Users/aditya/Projects/PaperCache/src/store/useAppStore.ts": {"path":"/Users/aditya/Projects/PaperCache/src/store/useAppStore.ts","statementMap":{"0":{"start":{"line":42,"column":13},"end":{"line":106,"column":null}},"1":{"start":{"line":42,"column":54},"end":{"line":106,"column":2}},"2":{"start":{"line":59,"column":4},"end":{"line":61,"column":null}},"3":{"start":{"line":59,"column":20},"end":{"line":61,"column":6}},"4":{"start":{"line":62,"column":45},"end":{"line":62,"column":null}},"5":{"start":{"line":64,"column":4},"end":{"line":66,"column":null}},"6":{"start":{"line":64,"column":20},"end":{"line":66,"column":6}},"7":{"start":{"line":69,"column":4},"end":{"line":72,"column":null}},"8":{"start":{"line":69,"column":20},"end":{"line":72,"column":6}},"9":{"start":{"line":74,"column":4},"end":{"line":79,"column":null}},"10":{"start":{"line":74,"column":20},"end":{"line":79,"column":6}},"11":{"start":{"line":80,"column":33},"end":{"line":80,"column":null}},"12":{"start":{"line":81,"column":35},"end":{"line":81,"column":null}},"13":{"start":{"line":82,"column":41},"end":{"line":82,"column":null}},"14":{"start":{"line":83,"column":43},"end":{"line":83,"column":null}},"15":{"start":{"line":85,"column":4},"end":{"line":90,"column":null}},"16":{"start":{"line":85,"column":20},"end":{"line":90,"column":6}},"17":{"start":{"line":91,"column":49},"end":{"line":91,"column":null}},"18":{"start":{"line":93,"column":4},"end":{"line":98,"column":null}},"19":{"start":{"line":93,"column":20},"end":{"line":98,"column":6}},"20":{"start":{"line":100,"column":4},"end":{"line":105,"column":null}},"21":{"start":{"line":100,"column":20},"end":{"line":105,"column":6}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":42,"column":27},"end":{"line":42,"column":45}},"loc":{"start":{"line":42,"column":54},"end":{"line":106,"column":2}},"line":42},"1":{"name":"(anonymous_1)","decl":{"start":{"line":58,"column":2},"end":{"line":58,"column":13}},"loc":{"start":{"line":59,"column":4},"end":{"line":61,"column":null}},"line":59},"2":{"name":"(anonymous_2)","decl":{"start":{"line":59,"column":4},"end":{"line":59,"column":9}},"loc":{"start":{"line":59,"column":20},"end":{"line":61,"column":6}},"line":59},"3":{"name":"(anonymous_3)","decl":{"start":{"line":62,"column":2},"end":{"line":62,"column":24}},"loc":{"start":{"line":62,"column":45},"end":{"line":62,"column":null}},"line":62},"4":{"name":"(anonymous_4)","decl":{"start":{"line":63,"column":2},"end":{"line":63,"column":17}},"loc":{"start":{"line":64,"column":4},"end":{"line":66,"column":null}},"line":64},"5":{"name":"(anonymous_5)","decl":{"start":{"line":64,"column":4},"end":{"line":64,"column":9}},"loc":{"start":{"line":64,"column":20},"end":{"line":66,"column":6}},"line":64},"6":{"name":"(anonymous_6)","decl":{"start":{"line":68,"column":2},"end":{"line":68,"column":21}},"loc":{"start":{"line":69,"column":4},"end":{"line":72,"column":null}},"line":69},"7":{"name":"(anonymous_7)","decl":{"start":{"line":69,"column":4},"end":{"line":69,"column":9}},"loc":{"start":{"line":69,"column":20},"end":{"line":72,"column":6}},"line":69},"8":{"name":"(anonymous_8)","decl":{"start":{"line":73,"column":2},"end":{"line":73,"column":25}},"loc":{"start":{"line":74,"column":4},"end":{"line":79,"column":null}},"line":74},"9":{"name":"(anonymous_9)","decl":{"start":{"line":74,"column":4},"end":{"line":74,"column":9}},"loc":{"start":{"line":74,"column":20},"end":{"line":79,"column":6}},"line":74},"10":{"name":"(anonymous_10)","decl":{"start":{"line":80,"column":2},"end":{"line":80,"column":18}},"loc":{"start":{"line":80,"column":33},"end":{"line":80,"column":null}},"line":80},"11":{"name":"(anonymous_11)","decl":{"start":{"line":81,"column":2},"end":{"line":81,"column":19}},"loc":{"start":{"line":81,"column":35},"end":{"line":81,"column":null}},"line":81},"12":{"name":"(anonymous_12)","decl":{"start":{"line":82,"column":2},"end":{"line":82,"column":22}},"loc":{"start":{"line":82,"column":41},"end":{"line":82,"column":null}},"line":82},"13":{"name":"(anonymous_13)","decl":{"start":{"line":83,"column":2},"end":{"line":83,"column":23}},"loc":{"start":{"line":83,"column":43},"end":{"line":83,"column":null}},"line":83},"14":{"name":"(anonymous_14)","decl":{"start":{"line":84,"column":2},"end":{"line":84,"column":27}},"loc":{"start":{"line":85,"column":4},"end":{"line":90,"column":null}},"line":85},"15":{"name":"(anonymous_15)","decl":{"start":{"line":85,"column":4},"end":{"line":85,"column":9}},"loc":{"start":{"line":85,"column":20},"end":{"line":90,"column":6}},"line":85},"16":{"name":"(anonymous_16)","decl":{"start":{"line":91,"column":2},"end":{"line":91,"column":26}},"loc":{"start":{"line":91,"column":49},"end":{"line":91,"column":null}},"line":91},"17":{"name":"(anonymous_17)","decl":{"start":{"line":92,"column":2},"end":{"line":92,"column":26}},"loc":{"start":{"line":93,"column":4},"end":{"line":98,"column":null}},"line":93},"18":{"name":"(anonymous_18)","decl":{"start":{"line":93,"column":4},"end":{"line":93,"column":9}},"loc":{"start":{"line":93,"column":20},"end":{"line":98,"column":6}},"line":93},"19":{"name":"(anonymous_19)","decl":{"start":{"line":99,"column":2},"end":{"line":99,"column":23}},"loc":{"start":{"line":100,"column":4},"end":{"line":105,"column":null}},"line":100},"20":{"name":"(anonymous_20)","decl":{"start":{"line":100,"column":4},"end":{"line":100,"column":9}},"loc":{"start":{"line":100,"column":20},"end":{"line":105,"column":6}},"line":100}},"branchMap":{"0":{"loc":{"start":{"line":45,"column":13},"end":{"line":45,"column":null}},"type":"binary-expr","locations":[{"start":{"line":45,"column":13},"end":{"line":45,"column":64}},{"start":{"line":45,"column":64},"end":{"line":45,"column":null}}],"line":45},"1":{"loc":{"start":{"line":60,"column":13},"end":{"line":60,"column":null}},"type":"cond-expr","locations":[{"start":{"line":60,"column":43},"end":{"line":60,"column":64}},{"start":{"line":60,"column":64},"end":{"line":60,"column":null}}],"line":60},"2":{"loc":{"start":{"line":65,"column":17},"end":{"line":65,"column":null}},"type":"cond-expr","locations":[{"start":{"line":65,"column":51},"end":{"line":65,"column":80}},{"start":{"line":65,"column":80},"end":{"line":65,"column":null}}],"line":65},"3":{"loc":{"start":{"line":71,"column":8},"end":{"line":71,"column":null}},"type":"cond-expr","locations":[{"start":{"line":71,"column":46},"end":{"line":71,"column":83}},{"start":{"line":71,"column":83},"end":{"line":71,"column":null}}],"line":71},"4":{"loc":{"start":{"line":76,"column":8},"end":{"line":78,"column":null}},"type":"cond-expr","locations":[{"start":{"line":77,"column":12},"end":{"line":77,"column":null}},{"start":{"line":78,"column":12},"end":{"line":78,"column":null}}],"line":76},"5":{"loc":{"start":{"line":87,"column":8},"end":{"line":89,"column":null}},"type":"cond-expr","locations":[{"start":{"line":88,"column":12},"end":{"line":88,"column":null}},{"start":{"line":89,"column":12},"end":{"line":89,"column":null}}],"line":87},"6":{"loc":{"start":{"line":95,"column":8},"end":{"line":97,"column":null}},"type":"cond-expr","locations":[{"start":{"line":96,"column":12},"end":{"line":96,"column":null}},{"start":{"line":97,"column":12},"end":{"line":97,"column":null}}],"line":95},"7":{"loc":{"start":{"line":102,"column":8},"end":{"line":104,"column":null}},"type":"cond-expr","locations":[{"start":{"line":103,"column":12},"end":{"line":103,"column":null}},{"start":{"line":104,"column":12},"end":{"line":104,"column":null}}],"line":102}},"s":{"0":3,"1":3,"2":2,"3":2,"4":1,"5":0,"6":0,"7":2,"8":2,"9":0,"10":0,"11":0,"12":0,"13":1,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0,"21":0},"f":{"0":3,"1":2,"2":2,"3":1,"4":0,"5":0,"6":2,"7":2,"8":0,"9":0,"10":0,"11":0,"12":1,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0},"b":{"0":[3,3],"1":[1,1],"2":[0,0],"3":[1,1],"4":[0,0],"5":[0,0],"6":[0,0],"7":[0,0]},"meta":{"lastBranch":8,"lastFunction":21,"lastStatement":22,"seen":{"s:42:13:106:Infinity":0,"f:42:27:42:45":0,"s:42:54:106:2":1,"b:45:13:45:64:45:64:45:Infinity":0,"f:58:2:58:13":1,"s:59:4:61:Infinity":2,"f:59:4:59:9":2,"s:59:20:61:6":3,"b:60:43:60:64:60:64:60:Infinity":1,"f:62:2:62:24":3,"s:62:45:62:Infinity":4,"f:63:2:63:17":4,"s:64:4:66:Infinity":5,"f:64:4:64:9":5,"s:64:20:66:6":6,"b:65:51:65:80:65:80:65:Infinity":2,"f:68:2:68:21":6,"s:69:4:72:Infinity":7,"f:69:4:69:9":7,"s:69:20:72:6":8,"b:71:46:71:83:71:83:71:Infinity":3,"f:73:2:73:25":8,"s:74:4:79:Infinity":9,"f:74:4:74:9":9,"s:74:20:79:6":10,"b:77:12:77:Infinity:78:12:78:Infinity":4,"f:80:2:80:18":10,"s:80:33:80:Infinity":11,"f:81:2:81:19":11,"s:81:35:81:Infinity":12,"f:82:2:82:22":12,"s:82:41:82:Infinity":13,"f:83:2:83:23":13,"s:83:43:83:Infinity":14,"f:84:2:84:27":14,"s:85:4:90:Infinity":15,"f:85:4:85:9":15,"s:85:20:90:6":16,"b:88:12:88:Infinity:89:12:89:Infinity":5,"f:91:2:91:26":16,"s:91:49:91:Infinity":17,"f:92:2:92:26":17,"s:93:4:98:Infinity":18,"f:93:4:93:9":18,"s:93:20:98:6":19,"b:96:12:96:Infinity:97:12:97:Infinity":6,"f:99:2:99:23":19,"s:100:4:105:Infinity":20,"f:100:4:100:9":20,"s:100:20:105:6":21,"b:103:12:103:Infinity:104:12:104:Infinity":7},"fnNames":{}}} -} diff --git a/coverage/favicon.png b/coverage/favicon.png deleted file mode 100644 index c1525b811a167671e9de1fa78aab9f5c0b61cef7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 445 zcmV;u0Yd(XP))rP{nL}Ln%S7`m{0DjX9TLF* zFCb$4Oi7vyLOydb!7n&^ItCzb-%BoB`=x@N2jll2Nj`kauio%aw_@fe&*}LqlFT43 z8doAAe))z_%=P%v^@JHp3Hjhj^6*Kr_h|g_Gr?ZAa&y>wxHE99Gk>A)2MplWz2xdG zy8VD2J|Uf#EAw*bo5O*PO_}X2Tob{%bUoO2G~T`@%S6qPyc}VkhV}UifBuRk>%5v( z)x7B{I~z*k<7dv#5tC+m{km(D087J4O%+<<;K|qwefb6@GSX45wCK}Sn*> - - - - Code coverage report for All files - - - - - - - - - -
-
-

All files

-
- -
- 68.68% - Statements - 283/412 -
- - -
- 60.75% - Branches - 113/186 -
- - -
- 49.03% - Functions - 51/104 -
- - -
- 69.55% - Lines - 265/381 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FileStatementsBranchesFunctionsLines
src -
-
82.75%96/11686.76%59/6836.66%11/3081.48%88/108
src/hooks -
-
92.59%75/8180%24/3089.47%17/1994.59%70/74
src/lib -
-
63.63%7/1150%2/466.66%2/360%6/10
src/lib/editor -
-
53.29%97/18232.35%22/6845.16%14/3154.85%96/175
src/store -
-
36.36%8/2237.5%6/1633.33%7/2135.71%5/14
-
-
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/prettify.css b/coverage/prettify.css deleted file mode 100644 index b317a7c..0000000 --- a/coverage/prettify.css +++ /dev/null @@ -1 +0,0 @@ -.pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun,.opn,.clo{color:#660}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun,.opn,.clo{color:#440}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee} diff --git a/coverage/prettify.js b/coverage/prettify.js deleted file mode 100644 index b322523..0000000 --- a/coverage/prettify.js +++ /dev/null @@ -1,2 +0,0 @@ -/* eslint-disable */ -window.PR_SHOULD_USE_CONTINUATION=true;(function(){var h=["break,continue,do,else,for,if,return,while"];var u=[h,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"];var p=[u,"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"];var l=[p,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"];var x=[p,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"];var R=[x,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"];var r="all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes";var w=[p,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"];var s="caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END";var I=[h,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"];var f=[h,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"];var H=[h,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"];var A=[l,R,w,s+I,f,H];var e=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/;var C="str";var z="kwd";var j="com";var O="typ";var G="lit";var L="pun";var F="pln";var m="tag";var E="dec";var J="src";var P="atn";var n="atv";var N="nocode";var M="(?:^^\\.?|[+-]|\\!|\\!=|\\!==|\\#|\\%|\\%=|&|&&|&&=|&=|\\(|\\*|\\*=|\\+=|\\,|\\-=|\\->|\\/|\\/=|:|::|\\;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|\\?|\\@|\\[|\\^|\\^=|\\^\\^|\\^\\^=|\\{|\\||\\|=|\\|\\||\\|\\|=|\\~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\\s*";function k(Z){var ad=0;var S=false;var ac=false;for(var V=0,U=Z.length;V122)){if(!(al<65||ag>90)){af.push([Math.max(65,ag)|32,Math.min(al,90)|32])}if(!(al<97||ag>122)){af.push([Math.max(97,ag)&~32,Math.min(al,122)&~32])}}}}af.sort(function(av,au){return(av[0]-au[0])||(au[1]-av[1])});var ai=[];var ap=[NaN,NaN];for(var ar=0;arat[0]){if(at[1]+1>at[0]){an.push("-")}an.push(T(at[1]))}}an.push("]");return an.join("")}function W(al){var aj=al.source.match(new RegExp("(?:\\[(?:[^\\x5C\\x5D]|\\\\[\\s\\S])*\\]|\\\\u[A-Fa-f0-9]{4}|\\\\x[A-Fa-f0-9]{2}|\\\\[0-9]+|\\\\[^ux0-9]|\\(\\?[:!=]|[\\(\\)\\^]|[^\\x5B\\x5C\\(\\)\\^]+)","g"));var ah=aj.length;var an=[];for(var ak=0,am=0;ak=2&&ai==="["){aj[ak]=X(ag)}else{if(ai!=="\\"){aj[ak]=ag.replace(/[a-zA-Z]/g,function(ao){var ap=ao.charCodeAt(0);return"["+String.fromCharCode(ap&~32,ap|32)+"]"})}}}}return aj.join("")}var aa=[];for(var V=0,U=Z.length;V=0;){S[ac.charAt(ae)]=Y}}var af=Y[1];var aa=""+af;if(!ag.hasOwnProperty(aa)){ah.push(af);ag[aa]=null}}ah.push(/[\0-\uffff]/);V=k(ah)})();var X=T.length;var W=function(ah){var Z=ah.sourceCode,Y=ah.basePos;var ad=[Y,F];var af=0;var an=Z.match(V)||[];var aj={};for(var ae=0,aq=an.length;ae=5&&"lang-"===ap.substring(0,5);if(am&&!(ai&&typeof ai[1]==="string")){am=false;ap=J}if(!am){aj[ag]=ap}}var ab=af;af+=ag.length;if(!am){ad.push(Y+ab,ap)}else{var al=ai[1];var ak=ag.indexOf(al);var ac=ak+al.length;if(ai[2]){ac=ag.length-ai[2].length;ak=ac-al.length}var ar=ap.substring(5);B(Y+ab,ag.substring(0,ak),W,ad);B(Y+ab+ak,al,q(ar,al),ad);B(Y+ab+ac,ag.substring(ac),W,ad)}}ah.decorations=ad};return W}function i(T){var W=[],S=[];if(T.tripleQuotedStrings){W.push([C,/^(?:\'\'\'(?:[^\'\\]|\\[\s\S]|\'{1,2}(?=[^\']))*(?:\'\'\'|$)|\"\"\"(?:[^\"\\]|\\[\s\S]|\"{1,2}(?=[^\"]))*(?:\"\"\"|$)|\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$))/,null,"'\""])}else{if(T.multiLineStrings){W.push([C,/^(?:\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$)|\`(?:[^\\\`]|\\[\s\S])*(?:\`|$))/,null,"'\"`"])}else{W.push([C,/^(?:\'(?:[^\\\'\r\n]|\\.)*(?:\'|$)|\"(?:[^\\\"\r\n]|\\.)*(?:\"|$))/,null,"\"'"])}}if(T.verbatimStrings){S.push([C,/^@\"(?:[^\"]|\"\")*(?:\"|$)/,null])}var Y=T.hashComments;if(Y){if(T.cStyleComments){if(Y>1){W.push([j,/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,null,"#"])}else{W.push([j,/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\r\n]*)/,null,"#"])}S.push([C,/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,null])}else{W.push([j,/^#[^\r\n]*/,null,"#"])}}if(T.cStyleComments){S.push([j,/^\/\/[^\r\n]*/,null]);S.push([j,/^\/\*[\s\S]*?(?:\*\/|$)/,null])}if(T.regexLiterals){var X=("/(?=[^/*])(?:[^/\\x5B\\x5C]|\\x5C[\\s\\S]|\\x5B(?:[^\\x5C\\x5D]|\\x5C[\\s\\S])*(?:\\x5D|$))+/");S.push(["lang-regex",new RegExp("^"+M+"("+X+")")])}var V=T.types;if(V){S.push([O,V])}var U=(""+T.keywords).replace(/^ | $/g,"");if(U.length){S.push([z,new RegExp("^(?:"+U.replace(/[\s,]+/g,"|")+")\\b"),null])}W.push([F,/^\s+/,null," \r\n\t\xA0"]);S.push([G,/^@[a-z_$][a-z_$@0-9]*/i,null],[O,/^(?:[@_]?[A-Z]+[a-z][A-Za-z_$@0-9]*|\w+_t\b)/,null],[F,/^[a-z_$][a-z_$@0-9]*/i,null],[G,new RegExp("^(?:0x[a-f0-9]+|(?:\\d(?:_\\d+)*\\d*(?:\\.\\d*)?|\\.\\d\\+)(?:e[+\\-]?\\d+)?)[a-z]*","i"),null,"0123456789"],[F,/^\\[\s\S]?/,null],[L,/^.[^\s\w\.$@\'\"\`\/\#\\]*/,null]);return g(W,S)}var K=i({keywords:A,hashComments:true,cStyleComments:true,multiLineStrings:true,regexLiterals:true});function Q(V,ag){var U=/(?:^|\s)nocode(?:\s|$)/;var ab=/\r\n?|\n/;var ac=V.ownerDocument;var S;if(V.currentStyle){S=V.currentStyle.whiteSpace}else{if(window.getComputedStyle){S=ac.defaultView.getComputedStyle(V,null).getPropertyValue("white-space")}}var Z=S&&"pre"===S.substring(0,3);var af=ac.createElement("LI");while(V.firstChild){af.appendChild(V.firstChild)}var W=[af];function ae(al){switch(al.nodeType){case 1:if(U.test(al.className)){break}if("BR"===al.nodeName){ad(al);if(al.parentNode){al.parentNode.removeChild(al)}}else{for(var an=al.firstChild;an;an=an.nextSibling){ae(an)}}break;case 3:case 4:if(Z){var am=al.nodeValue;var aj=am.match(ab);if(aj){var ai=am.substring(0,aj.index);al.nodeValue=ai;var ah=am.substring(aj.index+aj[0].length);if(ah){var ak=al.parentNode;ak.insertBefore(ac.createTextNode(ah),al.nextSibling)}ad(al);if(!ai){al.parentNode.removeChild(al)}}}break}}function ad(ak){while(!ak.nextSibling){ak=ak.parentNode;if(!ak){return}}function ai(al,ar){var aq=ar?al.cloneNode(false):al;var ao=al.parentNode;if(ao){var ap=ai(ao,1);var an=al.nextSibling;ap.appendChild(aq);for(var am=an;am;am=an){an=am.nextSibling;ap.appendChild(am)}}return aq}var ah=ai(ak.nextSibling,0);for(var aj;(aj=ah.parentNode)&&aj.nodeType===1;){ah=aj}W.push(ah)}for(var Y=0;Y=S){ah+=2}if(V>=ap){Z+=2}}}var t={};function c(U,V){for(var S=V.length;--S>=0;){var T=V[S];if(!t.hasOwnProperty(T)){t[T]=U}else{if(window.console){console.warn("cannot override language handler %s",T)}}}}function q(T,S){if(!(T&&t.hasOwnProperty(T))){T=/^\s*]*(?:>|$)/],[j,/^<\!--[\s\S]*?(?:-\->|$)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],[L,/^(?:<[%?]|[%?]>)/],["lang-",/^]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-js",/^]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]),["default-markup","htm","html","mxml","xhtml","xml","xsl"]);c(g([[F,/^[\s]+/,null," \t\r\n"],[n,/^(?:\"[^\"]*\"?|\'[^\']*\'?)/,null,"\"'"]],[[m,/^^<\/?[a-z](?:[\w.:-]*\w)?|\/?>$/i],[P,/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^>\'\"\s]*(?:[^>\'\"\s\/]|\/(?=\s)))/],[L,/^[=<>\/]+/],["lang-js",/^on\w+\s*=\s*\"([^\"]+)\"/i],["lang-js",/^on\w+\s*=\s*\'([^\']+)\'/i],["lang-js",/^on\w+\s*=\s*([^\"\'>\s]+)/i],["lang-css",/^style\s*=\s*\"([^\"]+)\"/i],["lang-css",/^style\s*=\s*\'([^\']+)\'/i],["lang-css",/^style\s*=\s*([^\"\'>\s]+)/i]]),["in.tag"]);c(g([],[[n,/^[\s\S]+/]]),["uq.val"]);c(i({keywords:l,hashComments:true,cStyleComments:true,types:e}),["c","cc","cpp","cxx","cyc","m"]);c(i({keywords:"null,true,false"}),["json"]);c(i({keywords:R,hashComments:true,cStyleComments:true,verbatimStrings:true,types:e}),["cs"]);c(i({keywords:x,cStyleComments:true}),["java"]);c(i({keywords:H,hashComments:true,multiLineStrings:true}),["bsh","csh","sh"]);c(i({keywords:I,hashComments:true,multiLineStrings:true,tripleQuotedStrings:true}),["cv","py"]);c(i({keywords:s,hashComments:true,multiLineStrings:true,regexLiterals:true}),["perl","pl","pm"]);c(i({keywords:f,hashComments:true,multiLineStrings:true,regexLiterals:true}),["rb"]);c(i({keywords:w,cStyleComments:true,regexLiterals:true}),["js"]);c(i({keywords:r,hashComments:3,cStyleComments:true,multilineStrings:true,tripleQuotedStrings:true,regexLiterals:true}),["coffee"]);c(g([],[[C,/^[\s\S]+/]]),["regex"]);function d(V){var U=V.langExtension;try{var S=a(V.sourceNode);var T=S.sourceCode;V.sourceCode=T;V.spans=S.spans;V.basePos=0;q(U,T)(V);D(V)}catch(W){if("console" in window){console.log(W&&W.stack?W.stack:W)}}}function y(W,V,U){var S=document.createElement("PRE");S.innerHTML=W;if(U){Q(S,U)}var T={langExtension:V,numberLines:U,sourceNode:S};d(T);return S.innerHTML}function b(ad){function Y(af){return document.getElementsByTagName(af)}var ac=[Y("pre"),Y("code"),Y("xmp")];var T=[];for(var aa=0;aa=0){var ah=ai.match(ab);var am;if(!ah&&(am=o(aj))&&"CODE"===am.tagName){ah=am.className.match(ab)}if(ah){ah=ah[1]}var al=false;for(var ak=aj.parentNode;ak;ak=ak.parentNode){if((ak.tagName==="pre"||ak.tagName==="code"||ak.tagName==="xmp")&&ak.className&&ak.className.indexOf("prettyprint")>=0){al=true;break}}if(!al){var af=aj.className.match(/\blinenums\b(?::(\d+))?/);af=af?af[1]&&af[1].length?+af[1]:true:false;if(af){Q(aj,af)}S={langExtension:ah,sourceNode:aj,numberLines:af};d(S)}}}if(X]*(?:>|$)/],[PR.PR_COMMENT,/^<\!--[\s\S]*?(?:-\->|$)/],[PR.PR_PUNCTUATION,/^(?:<[%?]|[%?]>)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],["lang-",/^]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-handlebars",/^]*type\s*=\s*['"]?text\/x-handlebars-template['"]?\b[^>]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-js",/^]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i],[PR.PR_DECLARATION,/^{{[#^>/]?\s*[\w.][^}]*}}/],[PR.PR_DECLARATION,/^{{&?\s*[\w.][^}]*}}/],[PR.PR_DECLARATION,/^{{{>?\s*[\w.][^}]*}}}/],[PR.PR_COMMENT,/^{{![^}]*}}/]]),["handlebars","hbs"]);PR.registerLangHandler(PR.createSimpleLexer([[PR.PR_PLAIN,/^[ \t\r\n\f]+/,null," \t\r\n\f"]],[[PR.PR_STRING,/^\"(?:[^\n\r\f\\\"]|\\(?:\r\n?|\n|\f)|\\[\s\S])*\"/,null],[PR.PR_STRING,/^\'(?:[^\n\r\f\\\']|\\(?:\r\n?|\n|\f)|\\[\s\S])*\'/,null],["lang-css-str",/^url\(([^\)\"\']*)\)/i],[PR.PR_KEYWORD,/^(?:url|rgb|\!important|@import|@page|@media|@charset|inherit)(?=[^\-\w]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|(?:\\[0-9a-f]+ ?))(?:[_a-z0-9\-]|\\(?:\\[0-9a-f]+ ?))*)\s*:/i],[PR.PR_COMMENT,/^\/\*[^*]*\*+(?:[^\/*][^*]*\*+)*\//],[PR.PR_COMMENT,/^(?:)/],[PR.PR_LITERAL,/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],[PR.PR_LITERAL,/^#(?:[0-9a-f]{3}){1,2}/i],[PR.PR_PLAIN,/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i],[PR.PR_PUNCTUATION,/^[^\s\w\'\"]+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_KEYWORD,/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_STRING,/^[^\)\"\']+/]]),["css-str"]); diff --git a/coverage/sort-arrow-sprite.png b/coverage/sort-arrow-sprite.png deleted file mode 100644 index 6ed68316eb3f65dec9063332d2f69bf3093bbfab..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 138 zcmeAS@N?(olHy`uVBq!ia0vp^>_9Bd!3HEZxJ@+%Qh}Z>jv*C{$p!i!8j}?a+@3A= zIAGwzjijN=FBi!|L1t?LM;Q;gkwn>2cAy-KV{dn nf0J1DIvEHQu*n~6U}x}qyky7vi4|9XhBJ7&`njxgN@xNA8m%nc diff --git a/coverage/sorter.js b/coverage/sorter.js deleted file mode 100644 index 4ed70ae..0000000 --- a/coverage/sorter.js +++ /dev/null @@ -1,210 +0,0 @@ -/* eslint-disable */ -var addSorting = (function() { - 'use strict'; - var cols, - currentSort = { - index: 0, - desc: false - }; - - // returns the summary table element - function getTable() { - return document.querySelector('.coverage-summary'); - } - // returns the thead element of the summary table - function getTableHeader() { - return getTable().querySelector('thead tr'); - } - // returns the tbody element of the summary table - function getTableBody() { - return getTable().querySelector('tbody'); - } - // returns the th element for nth column - function getNthColumn(n) { - return getTableHeader().querySelectorAll('th')[n]; - } - - function onFilterInput() { - const searchValue = document.getElementById('fileSearch').value; - const rows = document.getElementsByTagName('tbody')[0].children; - - // Try to create a RegExp from the searchValue. If it fails (invalid regex), - // it will be treated as a plain text search - let searchRegex; - try { - searchRegex = new RegExp(searchValue, 'i'); // 'i' for case-insensitive - } catch (error) { - searchRegex = null; - } - - for (let i = 0; i < rows.length; i++) { - const row = rows[i]; - let isMatch = false; - - if (searchRegex) { - // If a valid regex was created, use it for matching - isMatch = searchRegex.test(row.textContent); - } else { - // Otherwise, fall back to the original plain text search - isMatch = row.textContent - .toLowerCase() - .includes(searchValue.toLowerCase()); - } - - row.style.display = isMatch ? '' : 'none'; - } - } - - // loads the search box - function addSearchBox() { - var template = document.getElementById('filterTemplate'); - var templateClone = template.content.cloneNode(true); - templateClone.getElementById('fileSearch').oninput = onFilterInput; - template.parentElement.appendChild(templateClone); - } - - // loads all columns - function loadColumns() { - var colNodes = getTableHeader().querySelectorAll('th'), - colNode, - cols = [], - col, - i; - - for (i = 0; i < colNodes.length; i += 1) { - colNode = colNodes[i]; - col = { - key: colNode.getAttribute('data-col'), - sortable: !colNode.getAttribute('data-nosort'), - type: colNode.getAttribute('data-type') || 'string' - }; - cols.push(col); - if (col.sortable) { - col.defaultDescSort = col.type === 'number'; - colNode.innerHTML = - colNode.innerHTML + ''; - } - } - return cols; - } - // attaches a data attribute to every tr element with an object - // of data values keyed by column name - function loadRowData(tableRow) { - var tableCols = tableRow.querySelectorAll('td'), - colNode, - col, - data = {}, - i, - val; - for (i = 0; i < tableCols.length; i += 1) { - colNode = tableCols[i]; - col = cols[i]; - val = colNode.getAttribute('data-value'); - if (col.type === 'number') { - val = Number(val); - } - data[col.key] = val; - } - return data; - } - // loads all row data - function loadData() { - var rows = getTableBody().querySelectorAll('tr'), - i; - - for (i = 0; i < rows.length; i += 1) { - rows[i].data = loadRowData(rows[i]); - } - } - // sorts the table using the data for the ith column - function sortByIndex(index, desc) { - var key = cols[index].key, - sorter = function(a, b) { - a = a.data[key]; - b = b.data[key]; - return a < b ? -1 : a > b ? 1 : 0; - }, - finalSorter = sorter, - tableBody = document.querySelector('.coverage-summary tbody'), - rowNodes = tableBody.querySelectorAll('tr'), - rows = [], - i; - - if (desc) { - finalSorter = function(a, b) { - return -1 * sorter(a, b); - }; - } - - for (i = 0; i < rowNodes.length; i += 1) { - rows.push(rowNodes[i]); - tableBody.removeChild(rowNodes[i]); - } - - rows.sort(finalSorter); - - for (i = 0; i < rows.length; i += 1) { - tableBody.appendChild(rows[i]); - } - } - // removes sort indicators for current column being sorted - function removeSortIndicators() { - var col = getNthColumn(currentSort.index), - cls = col.className; - - cls = cls.replace(/ sorted$/, '').replace(/ sorted-desc$/, ''); - col.className = cls; - } - // adds sort indicators for current column being sorted - function addSortIndicators() { - getNthColumn(currentSort.index).className += currentSort.desc - ? ' sorted-desc' - : ' sorted'; - } - // adds event listeners for all sorter widgets - function enableUI() { - var i, - el, - ithSorter = function ithSorter(i) { - var col = cols[i]; - - return function() { - var desc = col.defaultDescSort; - - if (currentSort.index === i) { - desc = !currentSort.desc; - } - sortByIndex(i, desc); - removeSortIndicators(); - currentSort.index = i; - currentSort.desc = desc; - addSortIndicators(); - }; - }; - for (i = 0; i < cols.length; i += 1) { - if (cols[i].sortable) { - // add the click event handler on the th so users - // dont have to click on those tiny arrows - el = getNthColumn(i).querySelector('.sorter').parentElement; - if (el.addEventListener) { - el.addEventListener('click', ithSorter(i)); - } else { - el.attachEvent('onclick', ithSorter(i)); - } - } - } - } - // adds sorting functionality to the UI - return function() { - if (!getTable()) { - return; - } - cols = loadColumns(); - loadData(); - addSearchBox(); - addSortIndicators(); - enableUI(); - }; -})(); - -window.addEventListener('load', addSorting); diff --git a/coverage/src/Settings.css.html b/coverage/src/Settings.css.html deleted file mode 100644 index e4863bd..0000000 --- a/coverage/src/Settings.css.html +++ /dev/null @@ -1,574 +0,0 @@ - - - - - - Code coverage report for src/Settings.css - - - - - - - - - -
-
-

All files / src Settings.css

-
- -
- 0% - Statements - 0/0 -
- - -
- 0% - Branches - 0/0 -
- - -
- 0% - Functions - 0/0 -
- - -
- 0% - Lines - 0/0 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 -100 -101 -102 -103 -104 -105 -106 -107 -108 -109 -110 -111 -112 -113 -114 -115 -116 -117 -118 -119 -120 -121 -122 -123 -124 -125 -126 -127 -128 -129 -130 -131 -132 -133 -134 -135 -136 -137 -138 -139 -140 -141 -142 -143 -144 -145 -146 -147 -148 -149 -150 -151 -152 -153 -154 -155 -156 -157 -158 -159 -160 -161 -162 -163 -164  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  - 
.settings-container {
-  font-family: 'JetBrains Mono', monospace;
-  background: #1e1e1e;
-  color: #fff;
-  height: 100vh;
-  display: flex;
-  flex-direction: column;
-  padding: 30px 20px;
-  box-sizing: border-box;
-  -webkit-app-region: drag;
-}
- 
-.settings-header {
-  margin-bottom: 30px;
-  text-align: center;
-  padding-top: 10px;
-}
- 
-.settings-header h2 {
-  margin: 0;
-  font-size: 20px;
-  font-weight: 500;
-}
- 
-.settings-content {
-  flex: 1;
-  -webkit-app-region: no-drag;
-  overflow-y: auto;
-  padding: 0 10px;
-}
- 
-section {
-  background: rgba(0, 0, 0, 0.2);
-  padding: 16px;
-  border-radius: 8px;
-  margin-bottom: 20px;
-}
- 
-section h3 {
-  margin-top: 0;
-  margin-bottom: 16px;
-  font-size: 14px;
-  color: #ccc;
-  text-transform: uppercase;
-  letter-spacing: 1px;
-}
- 
-.setting-group {
-  margin-bottom: 20px;
-  text-align: center;
-}
- 
-.setting-group label {
-  display: block;
-  margin-bottom: 8px;
-  font-size: 13px;
-  color: #aaa;
-}
- 
-.setting-group input {
-  width: 100%;
-  padding: 10px;
-  border: 1px solid #333;
-  background: #2a2a2a;
-  color: #fff;
-  border-radius: 6px;
-  font-family: 'JetBrains Mono', monospace;
-  font-size: 14px;
-  box-sizing: border-box;
-  outline: none;
-  text-align: center;
-}
- 
-.setting-group select {
-  width: 100%;
-  padding: 10px;
-  border: 1px solid #333;
-  background: #2a2a2a;
-  color: #fff;
-  border-radius: 6px;
-  font-family: 'JetBrains Mono', monospace;
-  font-size: 14px;
-  box-sizing: border-box;
-  outline: none;
-  text-align: center;
-}
- 
-.setting-group input:focus,
-.setting-group select:focus {
-  border-color: #666;
-}
- 
-.setting-group.color-row {
-  display: flex;
-  justify-content: space-between;
-  align-items: center;
-}
- 
-.setting-group.color-row label {
-  margin-bottom: 0;
-}
- 
-.setting-group.color-row input[type='color'] {
-  width: 50px;
-  height: 30px;
-  padding: 0;
-  border: none;
-  border-radius: 4px;
-  background: transparent;
-  cursor: pointer;
-}
- 
-.save-btn {
-  flex: 1;
-  padding: 12px;
-  background: #fcfcfc;
-  color: #000;
-  border: none;
-  border-radius: 6px;
-  font-weight: bold;
-  cursor: pointer;
-}
- 
-.save-btn:hover {
-  background: #e0e0e0;
-}
- 
-.settings-footer {
-  margin-top: auto;
-  -webkit-app-region: no-drag;
-  display: flex;
-  gap: 10px;
-}
- 
-.quit-btn {
-  flex: 1;
-  padding: 12px;
-  background: #2a2a2a;
-  color: #ff4444;
-  border: 1px solid #ff4444;
-  border-radius: 6px;
-  font-weight: bold;
-  cursor: pointer;
-}
- 
-.quit-btn:hover {
-  background: rgba(255, 68, 68, 0.1);
-}
- 
-.close-btn {
-  flex: 1;
-  padding: 12px;
-  background: #2a2a2a;
-  color: #fff;
-  border: 1px solid #666;
-  border-radius: 6px;
-  font-weight: bold;
-  cursor: pointer;
-}
- 
-.close-btn:hover {
-  background: #333;
-}
- 
- -
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/src/Settings.tsx.html b/coverage/src/Settings.tsx.html deleted file mode 100644 index 7c46a79..0000000 --- a/coverage/src/Settings.tsx.html +++ /dev/null @@ -1,1087 +0,0 @@ - - - - - - Code coverage report for src/Settings.tsx - - - - - - - - - -
-
-

All files / src Settings.tsx

-
- -
- 75.3% - Statements - 61/81 -
- - -
- 85.18% - Branches - 46/54 -
- - -
- 26.92% - Functions - 7/26 -
- - -
- 75% - Lines - 60/80 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 -100 -101 -102 -103 -104 -105 -106 -107 -108 -109 -110 -111 -112 -113 -114 -115 -116 -117 -118 -119 -120 -121 -122 -123 -124 -125 -126 -127 -128 -129 -130 -131 -132 -133 -134 -135 -136 -137 -138 -139 -140 -141 -142 -143 -144 -145 -146 -147 -148 -149 -150 -151 -152 -153 -154 -155 -156 -157 -158 -159 -160 -161 -162 -163 -164 -165 -166 -167 -168 -169 -170 -171 -172 -173 -174 -175 -176 -177 -178 -179 -180 -181 -182 -183 -184 -185 -186 -187 -188 -189 -190 -191 -192 -193 -194 -195 -196 -197 -198 -199 -200 -201 -202 -203 -204 -205 -206 -207 -208 -209 -210 -211 -212 -213 -214 -215 -216 -217 -218 -219 -220 -221 -222 -223 -224 -225 -226 -227 -228 -229 -230 -231 -232 -233 -234 -235 -236 -237 -238 -239 -240 -241 -242 -243 -244 -245 -246 -247 -248 -249 -250 -251 -252 -253 -254 -255 -256 -257 -258 -259 -260 -261 -262 -263 -264 -265 -266 -267 -268 -269 -270 -271 -272 -273 -274 -275 -276 -277 -278 -279 -280 -281 -282 -283 -284 -285 -286 -287 -288 -289 -290 -291 -292 -293 -294 -295 -296 -297 -298 -299 -300 -301 -302 -303 -304 -305 -306 -307 -308 -309 -310 -311 -312 -313 -314 -315 -316 -317 -318 -319 -320 -321 -322 -323 -324 -325 -326 -327 -328 -329 -330 -331 -332 -333 -334 -335  -  -  -  -  -9x -9x -  -9x -5x -5x -  -  -5x -  -  -  -  -5x -5x -  -9x -  -  -9x -  -  -9x -  -  -  -  -  -9x -  -  -9x -  -  -  -  -9x -  -  -  -  -9x -  -  -9x -  -  -9x -  -  -9x -9x -9x -  -9x -  -  -9x -  -  -9x -  -  -9x -9x -  -  -  -9x -1x -1x -  -1x -1x -1x -  -1x -1x -1x -1x -1x -1x -  -1x -1x -1x -1x -1x -  -  -1x -1x -1x -  -  -  -  -1x -1x -1x -1x -  -  -  -1x -1x -1x -1x -  -  -  -1x -  -1x -  -  -9x -  -  -  -9x -1x -  -  -9x -  -  -  -  -  -  -  -  -  -  -  -  -  -2x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  - 
import { useState, useEffect } from 'react'
-import { SETTINGS_KEYS } from './lib/settingsKeys'
-import './Settings.css'
- 
-export default function Settings() {
-  const [apiKey, setApiKey] = useState('')
-  const [isApiKeySet, setIsApiKeySet] = useState(false)
- 
-  useEffect(() => {
-    window.electronAPI.getApiKeyStatus().then((status) => {
-      setIsApiKeySet(status)
-    })
- 
-    const handleKeyDown = (e: KeyboardEvent) => {
-      if (e.key === 'Escape') {
-        window.electronAPI.closeWindow()
-      }
-    }
-    window.addEventListener('keydown', handleKeyDown)
-    return () => window.removeEventListener('keydown', handleKeyDown)
-  }, [])
-  const [apiBaseUrl, setApiBaseUrl] = useState(
-    localStorage.getItem(SETTINGS_KEYS.API_BASE_URL) || 'https://openrouter.ai/api/v1'
-  )
-  const [apiModel, setApiModel] = useState(
-    localStorage.getItem(SETTINGS_KEYS.API_MODEL) || 'nvidia/nemotron-3-super-120b-a12b:free'
-  )
-  const [aiSystemPrompt, setAiSystemPrompt] = useState(
-    localStorage.getItem(SETTINGS_KEYS.AI_SYSTEM_PROMPT) ||
-      'Please provide a short and concise answer.'
-  )
- 
-  // Shortcuts
-  const [globalShortcutNewNote, setGlobalShortcutNewNote] = useState(
-    localStorage.getItem(SETTINGS_KEYS.SHORTCUT_NEWNOTE) || 'CommandOrControl+Shift+N'
-  )
-  const [globalShortcutToggle, setGlobalShortcutToggle] = useState(
-    localStorage.getItem(SETTINGS_KEYS.SHORTCUT_TOGGLE) || 'CommandOrControl+Shift+C'
-  )
- 
-  // Startup
-  const [launchAtStartup, setLaunchAtStartup] = useState(
-    localStorage.getItem(SETTINGS_KEYS.LAUNCH_STARTUP) === 'true'
-  )
- 
-  // Appearance State
-  const [fontFamily, setFontFamily] = useState(
-    localStorage.getItem(SETTINGS_KEYS.FONT_FAMILY) || "'JetBrains Mono', monospace"
-  )
-  const [showRulings, setShowRulings] = useState(
-    localStorage.getItem(SETTINGS_KEYS.SHOW_RULINGS) !== 'false'
-  )
-  const [themePreset, setThemePreset] = useState(
-    localStorage.getItem(SETTINGS_KEYS.THEME_PRESET) || 'grid-light'
-  )
-  const [bgType, setBgType] = useState(localStorage.getItem(SETTINGS_KEYS.BG_TYPE) || 'color') // preset, color, image
-  const [bgColor, setBgColor] = useState(localStorage.getItem(SETTINGS_KEYS.BG_COLOR) || '#ffffff')
-  const [bgImage, setBgImage] = useState(localStorage.getItem(SETTINGS_KEYS.BG_IMAGE) || '')
- 
-  const [textColor, setTextColor] = useState(
-    localStorage.getItem(SETTINGS_KEYS.TEXT_COLOR) || '#000000'
-  )
-  const [numColor, setNumColor] = useState(
-    localStorage.getItem(SETTINGS_KEYS.NUM_COLOR) || '#8ab4f8'
-  )
-  const [symColor, setSymColor] = useState(
-    localStorage.getItem(SETTINGS_KEYS.SYM_COLOR) || '#ff0000'
-  )
-  const [aiColor, setAiColor] = useState(localStorage.getItem(SETTINGS_KEYS.AI_COLOR) || '#8b5cf6')
-  const [mathColor, setMathColor] = useState(
-    localStorage.getItem(SETTINGS_KEYS.MATH_COLOR) || '#10b981'
-  )
- 
-  const saveSettings = async () => {
-    Eif (apiKey) {
-      await window.electronAPI.setApiKey(apiKey)
-    }
-    localStorage.setItem(SETTINGS_KEYS.API_BASE_URL, apiBaseUrl)
-    localStorage.setItem(SETTINGS_KEYS.API_MODEL, apiModel)
-    localStorage.setItem(SETTINGS_KEYS.AI_SYSTEM_PROMPT, aiSystemPrompt)
- 
-    localStorage.setItem(SETTINGS_KEYS.FONT_FAMILY, fontFamily)
-    localStorage.setItem(SETTINGS_KEYS.SHOW_RULINGS, showRulings.toString())
-    localStorage.setItem(SETTINGS_KEYS.THEME_PRESET, themePreset)
-    localStorage.setItem(SETTINGS_KEYS.BG_TYPE, bgType)
-    localStorage.setItem(SETTINGS_KEYS.BG_COLOR, bgColor)
-    localStorage.setItem(SETTINGS_KEYS.BG_IMAGE, bgImage)
- 
-    localStorage.setItem(SETTINGS_KEYS.TEXT_COLOR, textColor)
-    localStorage.setItem(SETTINGS_KEYS.NUM_COLOR, numColor)
-    localStorage.setItem(SETTINGS_KEYS.SYM_COLOR, symColor)
-    localStorage.setItem(SETTINGS_KEYS.AI_COLOR, aiColor)
-    localStorage.setItem(SETTINGS_KEYS.MATH_COLOR, mathColor)
- 
-    // Startup
-    localStorage.setItem(SETTINGS_KEYS.LAUNCH_STARTUP, launchAtStartup.toString())
-    Eif (window.electronAPI.setLaunchAtStartup) {
-      window.electronAPI.setLaunchAtStartup(launchAtStartup)
-    }
- 
-    // Shortcuts
-    const oldShortcut =
-      localStorage.getItem('papercache-shortcut-newnote') || 'CommandOrControl+Shift+N'
-    localStorage.setItem('papercache-shortcut-newnote', globalShortcutNewNote)
-    Eif (window.electronAPI.updateGlobalShortcut) {
-      window.electronAPI.updateGlobalShortcut('new-note', oldShortcut, globalShortcutNewNote)
-    }
- 
-    const oldToggleShortcut =
-      localStorage.getItem('papercache-shortcut-toggle') || 'CommandOrControl+Shift+C'
-    localStorage.setItem('papercache-shortcut-toggle', globalShortcutToggle)
-    Eif (window.electronAPI.updateGlobalShortcut) {
-      window.electronAPI.updateGlobalShortcut('toggle', oldToggleShortcut, globalShortcutToggle)
-    }
- 
-    // Dispatch storage event manually for the same window to pick it up immediately
-    window.dispatchEvent(new Event('storage'))
- 
-    window.electronAPI.closeWindow() // actually closes settings window
-  }
- 
-  const closeSettings = () => {
-    window.electronAPI.closeWindow()
-  }
- 
-  const quitApp = () => {
-    window.electronAPI.quitApp()
-  }
- 
-  return (
-    <div className="settings-container">
-      <div className="settings-header">
-        <h2>Settings</h2>
-      </div>
- 
-      <div className="settings-content">
-        <section>
-          <h3>AI Configuration</h3>
-          <div className="setting-group">
-            <label>API Key {isApiKeySet ? '✅ (Set)' : ''}</label>
-            <input
-              type="password"
-              value={apiKey}
-              onChange={(e) => setApiKey(e.target.value)}
-              placeholder={isApiKeySet ? 'Enter new key to replace existing' : 'sk-...'}
-            />
-          </div>
- 
-          <div className="setting-group">
-            <label>API Base URL</label>
-            <input
-              type="text"
-              value={apiBaseUrl}
-              onChange={(e) => setApiBaseUrl(e.target.value)}
-              placeholder="https://openrouter.ai/api/v1"
-            />
-          </div>
- 
-          <div className="setting-group">
-            <label>Model Name</label>
-            <input
-              type="text"
-              value={apiModel}
-              onChange={(e) => setApiModel(e.target.value)}
-              placeholder="nvidia/nemotron-3-super-120b-a12b:free"
-            />
-          </div>
- 
-          <div className="setting-group">
-            <label>System Prompt (Instructions)</label>
-            <textarea
-              value={aiSystemPrompt}
-              onChange={(e) => setAiSystemPrompt(e.target.value)}
-              placeholder="e.g. Please provide a short and concise answer."
-              rows={3}
-              style={{
-                width: '100%',
-                padding: '8px',
-                background: 'rgba(128,128,128,0.1)',
-                border: '1px solid rgba(128,128,128,0.2)',
-                color: 'inherit',
-                borderRadius: '4px',
-                fontFamily: "'JetBrains Mono', monospace",
-                resize: 'vertical',
-                textAlign: 'center',
-              }}
-            />
-          </div>
-        </section>
- 
-        <section>
-          <h3>Global Shortcuts</h3>
-          <div className="setting-group">
-            <label>Toggle App Visibility</label>
-            <input
-              type="text"
-              value={globalShortcutToggle}
-              onChange={(e) => setGlobalShortcutToggle(e.target.value)}
-              placeholder="e.g. CommandOrControl+Shift+C"
-            />
-          </div>
-          <div className="setting-group">
-            <label>New Note (Global)</label>
-            <input
-              type="text"
-              value={globalShortcutNewNote}
-              onChange={(e) => setGlobalShortcutNewNote(e.target.value)}
-              placeholder="e.g. CommandOrControl+Shift+N"
-            />
-          </div>
-        </section>
- 
-        <section>
-          <h3>System</h3>
-          <div className="setting-group">
-            <label>Launch at Startup</label>
-            <input
-              type="checkbox"
-              checked={launchAtStartup}
-              onChange={(e) => setLaunchAtStartup(e.target.checked)}
-              style={{ width: 'auto', marginRight: 'auto' }}
-            />
-          </div>
-        </section>
- 
-        <section>
-          <h3>Appearance</h3>
-          <div className="setting-group">
-            <label>Font Family</label>
-            <select value={fontFamily} onChange={(e) => setFontFamily(e.target.value)}>
-              <option value="'JetBrains Mono', monospace">JetBrains Mono (Default)</option>
-              <option value="Menlo, Monaco, 'Courier New', monospace">Monospace</option>
-              <option value="Inter, system-ui, -apple-system, sans-serif">
-                Sans-serif (Modern)
-              </option>
-              <option value="-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif">
-                System Default
-              </option>
-              <option value="Georgia, Cambria, 'Times New Roman', Times, serif">
-                Serif (Classic)
-              </option>
-            </select>
-          </div>
- 
-          <div className="setting-group">
-            <label>Show Ruled Lines (Grid)</label>
-            <input
-              type="checkbox"
-              checked={showRulings}
-              onChange={(e) => setShowRulings(e.target.checked)}
-              style={{ width: 'auto', marginRight: 'auto' }}
-            />
-          </div>
- 
-          <div className="setting-group">
-            <label>Background Type</label>
-            <select value={bgType} onChange={(e) => setBgType(e.target.value)}>
-              <option value="preset">Preset Theme</option>
-              <option value="color">Solid Color</option>
-              <option value="image">Custom Image URL</option>
-            </select>
-          </div>
- 
-          {bgType === 'preset' && (
-            <div className="setting-group">
-              <label>Theme Preset</label>
-              <select value={themePreset} onChange={(e) => setThemePreset(e.target.value)}>
-                <option value="paper-light">Paper Light</option>
-                <option value="grid-dark">Grid Dark</option>
-                <option value="blueprint">Blueprint</option>
-              </select>
-            </div>
-          )}
- 
-          {bgType === 'color' && (
-            <div className="setting-group color-row">
-              <label>Background Color</label>
-              <input type="color" value={bgColor} onChange={(e) => setBgColor(e.target.value)} />
-            </div>
-          )}
- 
-          {bgType === 'image' && (
-            <div className="setting-group">
-              <label>Background Image URL</label>
-              <input
-                type="text"
-                value={bgImage}
-                onChange={(e) => setBgImage(e.target.value)}
-                placeholder="https://..."
-              />
-            </div>
-          )}
- 
-          <div className="setting-group color-row">
-            <label>Main Text</label>
-            <input type="color" value={textColor} onChange={(e) => setTextColor(e.target.value)} />
-          </div>
- 
-          <div className="setting-group color-row">
-            <label>Numbers</label>
-            <input type="color" value={numColor} onChange={(e) => setNumColor(e.target.value)} />
-          </div>
- 
-          <div className="setting-group color-row">
-            <label>Math Symbols</label>
-            <input type="color" value={symColor} onChange={(e) => setSymColor(e.target.value)} />
-          </div>
- 
-          <div className="setting-group color-row">
-            <label>Math Results (Autofill)</label>
-            <input type="color" value={mathColor} onChange={(e) => setMathColor(e.target.value)} />
-          </div>
- 
-          <div className="setting-group color-row">
-            <label>AI Response Text</label>
-            <input type="color" value={aiColor} onChange={(e) => setAiColor(e.target.value)} />
-          </div>
-        </section>
-      </div>
- 
-      <div className="settings-footer">
-        <button className="quit-btn" onClick={quitApp}>
-          Quit
-        </button>
-        <button className="close-btn" onClick={closeSettings}>
-          Close Settings
-        </button>
-        <button className="save-btn" onClick={saveSettings}>
-          Save Settings
-        </button>
-      </div>
-    </div>
-  )
-}
- 
- -
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/src/hooks/index.html b/coverage/src/hooks/index.html deleted file mode 100644 index daf2cec..0000000 --- a/coverage/src/hooks/index.html +++ /dev/null @@ -1,131 +0,0 @@ - - - - - - Code coverage report for src/hooks - - - - - - - - - -
-
-

All files src/hooks

-
- -
- 92.59% - Statements - 75/81 -
- - -
- 80% - Branches - 24/30 -
- - -
- 89.47% - Functions - 17/19 -
- - -
- 94.59% - Lines - 70/74 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FileStatementsBranchesFunctionsLines
useReminders.ts -
-
91.66%55/6080.76%21/2685.71%12/1492.72%51/55
useVariables.ts -
-
95.23%20/2175%3/4100%5/5100%19/19
-
-
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/src/hooks/useReminders.ts.html b/coverage/src/hooks/useReminders.ts.html deleted file mode 100644 index 56c7ab7..0000000 --- a/coverage/src/hooks/useReminders.ts.html +++ /dev/null @@ -1,409 +0,0 @@ - - - - - - Code coverage report for src/hooks/useReminders.ts - - - - - - - - - -
-
-

All files / src/hooks useReminders.ts

-
- -
- 91.66% - Statements - 55/60 -
- - -
- 80.76% - Branches - 21/26 -
- - -
- 85.71% - Functions - 12/14 -
- - -
- 92.72% - Lines - 51/55 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 -100 -101 -102 -103 -104 -105 -106 -107 -108 -109  -  -  -  -  -8x -  -8x -  -  -8x -8x -8x -8x -8x -6x -6x -6x -  -  -  -  -  -  -  -8x -  -  -  -6x -6x -6x -6x -  -6x -  -6x -3x -2x -2x -2x -  -  -  -2x -2x -  -  -  -  -6x -2x -  -  -  -  -6x -6x -4x -3x -3x -  -  -6x -  -  -1x -1x -  -  -  -15x -5x -  -5x -5x -1x -  -  -5x -6x -6x -6x -  -  -5x -  -5x -  -  -  -  -  -  -5x -  -  -  -5x -5x -  -5x -5x -5x -5x -  -  -  - 
import { useEffect, useRef } from 'react'
-import { useAppStore, type Note } from '../store/useAppStore'
-import { SETTINGS_KEYS } from '../lib/settingsKeys'
- 
-function parseReminders(content: string, noteId: string) {
-  const reminders: { dueAt: Date; label: string; key: string }[] = []
-  const reRem =
-    /\/(task(?:-done)?)(?:\s+\((\d{4}-\d{2}-\d{2} \d{2}:\d{2})\))?\s+(.*?)(?:\s+@\s+(\d{4}-\d{2}-\d{2}(?:\s+\d{2}:\d{2}(?::\d{2})?)?))?[ \t]*$/gm
- 
-  let match
-  while ((match = reRem.exec(content)) !== null) {
-    const isDone = match[1] === 'task-done'
-    const label = match[3]
-    const targetStr = match[4]
-    if (!isDone && targetStr) {
-      const targetMs = new Date(targetStr).getTime()
-      Eif (!isNaN(targetMs)) {
-        reminders.push({
-          dueAt: new Date(targetMs),
-          label,
-          key: `${noteId}-${targetMs}-${label}`,
-        })
-      }
-    }
-  }
-  return reminders
-}
- 
-function handleDueReminders(notes: Note[]) {
-  const now = Date.now()
-  const notifiedStr = localStorage.getItem(SETTINGS_KEYS.NOTIFIED_REMINDERS) || '[]'
-  const notified = new Set<string>(JSON.parse(notifiedStr))
-  let hasNewNotifs = false
- 
-  const allReminders = notes.flatMap((n) => parseReminders(n.content, n.id))
- 
-  for (const r of allReminders) {
-    if (now >= r.dueAt.getTime()) {
-      Eif (!notified.has(r.key)) {
-        console.log('Triggering OS notification for:', r.label)
-        new Notification('PaperCache Reminder', {
-          body: r.label,
-          silent: false,
-        })
-        notified.add(r.key)
-        hasNewNotifs = true
-      }
-    }
-  }
- 
-  if (hasNewNotifs) {
-    localStorage.setItem(SETTINGS_KEYS.NOTIFIED_REMINDERS, JSON.stringify(Array.from(notified)))
-  }
-}
- 
-function scheduleNextReminder(notes: Note[], callback: () => void) {
-  const now = Date.now()
-  const next = notes
-    .flatMap((n) => parseReminders(n.content, n.id))
-    .map((r) => r.dueAt.getTime())
-    .filter((t) => t > now)
-    .sort()[0]
- 
-  if (!next) return null
- 
-  // Ensure delay is at least 1000ms to avoid tight loops if something goes wrong
-  const delay = Math.max(next - now, 1000)
-  return setTimeout(callback, delay)
-}
- 
-export function useReminders() {
-  const notes = useAppStore((state) => state.notes)
-  const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null)
- 
-  useEffect(() => {
-    if (Notification.permission !== 'granted' && Notification.permission !== 'denied') {
-      Notification.requestPermission()
-    }
- 
-    const checkAndSchedule = () => {
-      handleDueReminders(notes)
-      if (timerRef.current) clearTimeout(timerRef.current)
-      timerRef.current = scheduleNextReminder(notes, checkAndSchedule)
-    }
- 
-    checkAndSchedule()
- 
-    const onSuspend = () => {
-      if (timerRef.current) {
-        clearTimeout(timerRef.current)
-        timerRef.current = null
-      }
-    }
- 
-    const onResume = () => {
-      checkAndSchedule()
-    }
- 
-    const unsubscribeSuspend = window.electronAPI.onPowerSuspend(onSuspend)
-    const unsubscribeResume = window.electronAPI.onPowerResume(onResume)
- 
-    return () => {
-      Iif (timerRef.current) clearTimeout(timerRef.current)
-      unsubscribeSuspend()
-      unsubscribeResume()
-    }
-  }, [notes])
-}
- 
- -
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/src/hooks/useVariables.ts.html b/coverage/src/hooks/useVariables.ts.html deleted file mode 100644 index 020bddc..0000000 --- a/coverage/src/hooks/useVariables.ts.html +++ /dev/null @@ -1,205 +0,0 @@ - - - - - - Code coverage report for src/hooks/useVariables.ts - - - - - - - - - -
-
-

All files / src/hooks useVariables.ts

-
- -
- 95.23% - Statements - 20/21 -
- - -
- 75% - Branches - 3/4 -
- - -
- 100% - Functions - 5/5 -
- - -
- 100% - Lines - 19/19 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41  -  -  -  -  -12x -  -  -4x -4x -  -4x -4x -  -4x -  -4x -  -5x -7x -7x -7x -4x -  -7x -  -1x -  -  -  -4x -4x -  -  -4x -4x -4x -  -  -  - 
import { useEffect } from 'react'
- 
-import { useAppStore } from '../store/useAppStore'
- 
-export function useVariables() {
-  const notes = useAppStore((state) => state.notes)
- 
-  // Sync global variables whenever notes change
-  useEffect(() => {
-    let abort = false
-    async function syncVars() {
-      const globals: Record<string, unknown> = {}
-      const reVar = /^\/globvar\s+([a-zA-Z0-9_]+)\s*=\s*(.*)$/gm
- 
-      let mathjs: { evaluate: (e: string, s: unknown) => unknown } | null = null
- 
-      for (const note of notes) {
-        let varMatch
-        while ((varMatch = reVar.exec(note.content)) !== null) {
-          const name = varMatch[1]
-          try {
-            if (!mathjs) {
-              mathjs = await import('mathjs')
-            }
-            globals[name] = mathjs.evaluate(varMatch[2], globals)
-          } catch {
-            globals[name] = varMatch[2].trim()
-          }
-        }
-      }
-      Iif (abort) return
-      ;(window as unknown as { __globalVariables: Record<string, unknown> }).__globalVariables =
-        globals
-    }
-    syncVars()
-    return () => {
-      abort = true
-    }
-  }, [notes])
-}
- 
- -
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/src/index.html b/coverage/src/index.html deleted file mode 100644 index cb89e96..0000000 --- a/coverage/src/index.html +++ /dev/null @@ -1,146 +0,0 @@ - - - - - - Code coverage report for src - - - - - - - - - -
-
-

All files src

-
- -
- 82.75% - Statements - 96/116 -
- - -
- 86.76% - Branches - 59/68 -
- - -
- 36.66% - Functions - 11/30 -
- - -
- 81.48% - Lines - 88/108 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FileStatementsBranchesFunctionsLines
Settings.css -
-
0%0/00%0/00%0/00%0/0
Settings.tsx -
-
75.3%61/8185.18%46/5426.92%7/2675%60/80
utils.ts -
-
100%35/3592.85%13/14100%4/4100%28/28
-
-
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/src/lib/editor/MathEvaluator.ts.html b/coverage/src/lib/editor/MathEvaluator.ts.html deleted file mode 100644 index f168737..0000000 --- a/coverage/src/lib/editor/MathEvaluator.ts.html +++ /dev/null @@ -1,334 +0,0 @@ - - - - - - Code coverage report for src/lib/editor/MathEvaluator.ts - - - - - - - - - -
-
-

All files / src/lib/editor MathEvaluator.ts

-
- -
- 75.6% - Statements - 31/41 -
- - -
- 52.38% - Branches - 11/21 -
- - -
- 50% - Functions - 2/4 -
- - -
- 78.94% - Lines - 30/38 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84  -  -  -  -1x -  -  -  -  -  -  -5x -5x -  -  -  -5x -  -  -5x -5x -5x -9x -9x -  -9x -3x -3x -3x -3x -3x -  -  -  -  -  -  -  -  -9x -  -  -  -5x -  -5x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -  -  -  -  -  -  -  -  -  -  -5x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  - 
import type { EditorView } from '@codemirror/view'
-import { VariableScope } from './VariableScope'
- 
-export class MathEvaluator {
-  static evalTimeout: number | null = null
- 
-  static async evaluateMathChanges(
-    docStr: string,
-    scope: Record<string, any>
-  ): Promise<{ from: number; to: number; insert: string }[]> {
-    let mathjs
-    try {
-      mathjs = await import('mathjs')
-    } catch {
-      return []
-    }
-    const changes: { from: number; to: number; insert: string }[] = []
- 
-    // 1. Evaluate new lines that end with '=' but don't have '\u200B' yet
-    const lines = docStr.split('\n')
-    let offset = 0
-    for (let i = 0; i < lines.length; i++) {
-      const text = lines[i]
-      const lineLen = text.length
- 
-      if (!text.includes('\u200B') && text.trim().endsWith('=')) {
-        const expr = text.substring(0, text.lastIndexOf('=')).trim()
-        Eif (expr && !expr.startsWith('/var') && !expr.startsWith('/globvar')) {
-          try {
-            const result = String(mathjs.evaluate(expr, scope))
-            changes.push({
-              from: offset + lineLen,
-              to: offset + lineLen,
-              insert: '\u200B' + result,
-            })
-          } catch {}
-        }
-      }
- 
-      offset += lineLen + 1 // +1 for '\n'
-    }
- 
-    // 2. Re-evaluate existing calculations that already have '\u200B'
-    const reCalc = /^(.*?=\s*)\u200B(.*)$/gm
-    let calcMatch
-    while ((calcMatch = reCalc.exec(docStr)) !== null) {
-      const exprPart = calcMatch[1]
-      const oldResult = calcMatch[2]
-      const expr = exprPart.replace(/=\s*$/, '').trim()
-      Eif (expr) {
-        try {
-          const newResult = String(mathjs.evaluate(expr, scope))
-          Eif (newResult !== oldResult) {
-            const startReplace = calcMatch.index + exprPart.length + 1 // +1 for \u200B
-            const endReplace = calcMatch.index + calcMatch[0].length
-            Eif (!changes.some((c) => c.from <= endReplace && c.to >= startReplace)) {
-              changes.push({
-                from: startReplace,
-                to: endReplace,
-                insert: newResult,
-              })
-            }
-          }
-        } catch {}
-      }
-    }
- 
-    return changes
-  }
- 
-  static triggerMathEvaluation(view: EditorView) {
-    if (this.evalTimeout) window.clearTimeout(this.evalTimeout)
-    this.evalTimeout = window.setTimeout(async () => {
-      const docStr = view.state.doc.toString()
-      const scope = VariableScope.getScope()
-      const changes = await this.evaluateMathChanges(docStr, scope)
- 
-      if (changes.length > 0) {
-        view.dispatch({ changes })
-      }
-    }, 300)
-  }
-}
- 
- -
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/src/lib/editor/VariableScope.ts.html b/coverage/src/lib/editor/VariableScope.ts.html deleted file mode 100644 index 924571c..0000000 --- a/coverage/src/lib/editor/VariableScope.ts.html +++ /dev/null @@ -1,277 +0,0 @@ - - - - - - Code coverage report for src/lib/editor/VariableScope.ts - - - - - - - - - -
-
-

All files / src/lib/editor VariableScope.ts

-
- -
- 13.15% - Statements - 5/38 -
- - -
- 0% - Branches - 0/18 -
- - -
- 50% - Functions - 2/4 -
- - -
- 14.7% - Lines - 5/34 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65  -  -  -1x -  -  -1x -1x -1x -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  - 
import type { EditorView } from '@codemirror/view'
-import { StateEffect } from '@codemirror/state'
- 
-export const scopeChangedEffect = StateEffect.define<void>()
- 
-export class VariableScope {
-  static globalScopeCache: Record<string, unknown> = {}
-  static lastDocString = ''
-  static scopeEvalTimeout: number | null = null
-  static scopeVersion = 0
- 
-  static triggerScopeUpdate(docStr: string, view: EditorView | null) {
-    if (docStr === this.lastDocString) return
-    this.lastDocString = docStr
-    if (this.scopeEvalTimeout) window.clearTimeout(this.scopeEvalTimeout)
-    this.scopeVersion++
-    const currentVersion = this.scopeVersion
-    this.scopeEvalTimeout = window.setTimeout(async () => {
-      let mathjs
-      try {
-        mathjs = await import('mathjs')
-      } catch {
-        return
-      }
- 
-      const newScope: Record<string, unknown> = {}
-      const reVar = /^\/var\s+([a-zA-Z0-9_]+)\s*=\s*(.*)$/gm
-      let varMatch
-      let changed = false
- 
-      const globalVars =
-        (window as unknown as { __globalVariables: Record<string, unknown> }).__globalVariables ||
-        {}
- 
-      while ((varMatch = reVar.exec(docStr)) !== null) {
-        const name = varMatch[1]
-        try {
-          const val = mathjs.evaluate(varMatch[2], Object.assign({}, globalVars, newScope))
-          newScope[name] = val
-        } catch {
-          newScope[name] = varMatch[2].trim()
-        }
-        if (this.globalScopeCache[name] !== newScope[name]) {
-          changed = true
-        }
-      }
- 
-      if (currentVersion !== this.scopeVersion) return
-      if (changed || Object.keys(this.globalScopeCache).length !== Object.keys(newScope).length) {
-        this.globalScopeCache = newScope
-        if (view) {
-          view.dispatch({ effects: [scopeChangedEffect.of()] })
-          import('./MathEvaluator').then((m) => m.MathEvaluator.triggerMathEvaluation(view))
-        }
-      }
-    }, 300)
-  }
- 
-  static getScope(): Record<string, unknown> {
-    const globalVars =
-      (window as unknown as { __globalVariables: Record<string, unknown> }).__globalVariables || {}
-    return Object.assign({}, globalVars, this.globalScopeCache)
-  }
-}
- 
- -
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/src/lib/editor/index.html b/coverage/src/lib/editor/index.html deleted file mode 100644 index 12e98f3..0000000 --- a/coverage/src/lib/editor/index.html +++ /dev/null @@ -1,146 +0,0 @@ - - - - - - Code coverage report for src/lib/editor - - - - - - - - - -
-
-

All files src/lib/editor

-
- -
- 53.29% - Statements - 97/182 -
- - -
- 32.35% - Branches - 22/68 -
- - -
- 45.16% - Functions - 14/31 -
- - -
- 54.85% - Lines - 96/175 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FileStatementsBranchesFunctionsLines
MathEvaluator.ts -
-
75.6%31/4152.38%11/2150%2/478.94%30/38
VariableScope.ts -
-
13.15%5/380%0/1850%2/414.7%5/34
widgets.ts -
-
59.22%61/10337.93%11/2943.47%10/2359.22%61/103
-
-
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/src/lib/editor/widgets.ts.html b/coverage/src/lib/editor/widgets.ts.html deleted file mode 100644 index e2bfa45..0000000 --- a/coverage/src/lib/editor/widgets.ts.html +++ /dev/null @@ -1,736 +0,0 @@ - - - - - - Code coverage report for src/lib/editor/widgets.ts - - - - - - - - - -
-
-

All files / src/lib/editor widgets.ts

-
- -
- 59.22% - Statements - 61/103 -
- - -
- 37.93% - Branches - 11/29 -
- - -
- 43.47% - Functions - 10/23 -
- - -
- 59.22% - Lines - 61/103 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 -100 -101 -102 -103 -104 -105 -106 -107 -108 -109 -110 -111 -112 -113 -114 -115 -116 -117 -118 -119 -120 -121 -122 -123 -124 -125 -126 -127 -128 -129 -130 -131 -132 -133 -134 -135 -136 -137 -138 -139 -140 -141 -142 -143 -144 -145 -146 -147 -148 -149 -150 -151 -152 -153 -154 -155 -156 -157 -158 -159 -160 -161 -162 -163 -164 -165 -166 -167 -168 -169 -170 -171 -172 -173 -174 -175 -176 -177 -178 -179 -180 -181 -182 -183 -184 -185 -186 -187 -188 -189 -190 -191 -192 -193 -194 -195 -196 -197 -198 -199 -200 -201 -202 -203 -204 -205 -206 -207 -208 -209 -210 -211 -212 -213 -214 -215 -216 -217 -218  -  -  -  -  -  -4x -4x -4x -  -  -  -2x -  -  -  -1x -1x -1x -1x -  -1x -1x -1x -1x -1x -  -  -1x -  -1x -1x -  -1x -  -  -  -  -  -  -  -  -  -  -1x -  -  -  -  -  -  -  -  -  -4x -4x -4x -4x -  -  -  -  -  -  -  -4x -4x -  -4x -2x -  -2x -  -  -4x -2x -2x -2x -2x -2x -2x -  -  -  -  -4x -  -  -  -  -  -  -1x -1x -  -  -  -  -  -1x -1x -1x -1x -  -  -  -  -  -  -1x -1x -  -  -  -  -  -1x -1x -1x -  -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -  -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -1x -  -1x -1x -  -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  - 
import { WidgetType, EditorView } from '@codemirror/view'
- 
-export class CopyWidget extends WidgetType {
-  code: string
-  language: string
-  constructor(code: string, language: string) {
-    super()
-    this.code = code
-    this.language = language
-  }
- 
-  eq(other: CopyWidget) {
-    return other.code === this.code && other.language === this.language
-  }
- 
-  toDOM() {
-    const wrap = document.createElement('span')
-    wrap.setAttribute('aria-hidden', 'true')
-    wrap.className = 'cm-copy-button'
-    wrap.title = 'Copy code'
- 
-    Eif (this.language) {
-      const langSpan = document.createElement('sup')
-      langSpan.textContent = this.language
-      langSpan.className = 'cm-code-lang'
-      wrap.appendChild(langSpan)
-    }
- 
-    const iconSpan = document.createElement('span')
-    // Standard copy icon (two offset rounded rectangles)
-    iconSpan.innerHTML = `<svg viewBox="0 0 24 24" width="14" height="14" stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg>`
-    wrap.appendChild(iconSpan)
- 
-    wrap.onclick = (e) => {
-      e.preventDefault()
-      e.stopPropagation()
-      navigator.clipboard.writeText(this.code)
-      const originalHtml = iconSpan.innerHTML
-      // Checkmark icon
-      iconSpan.innerHTML = `<svg viewBox="0 0 24 24" width="14" height="14" stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"></polyline></svg>`
-      setTimeout(() => {
-        iconSpan.innerHTML = originalHtml
-      }, 2000)
-    }
-    return wrap
-  }
-}
- 
-export class CheckboxWidget extends WidgetType {
-  checked: boolean
-  pos: number
-  view: EditorView
- 
-  constructor(checked: boolean, pos: number, view: EditorView) {
-    super()
-    this.checked = checked
-    this.pos = pos
-    this.view = view
-  }
- 
-  eq(other: CheckboxWidget) {
-    return other.checked === this.checked && other.pos === this.pos
-  }
- 
-  toDOM() {
-    const wrap = document.createElement('span')
-    wrap.className = 'cm-checkbox-widget' + (this.checked ? ' cm-checkbox-checked' : '')
- 
-    if (this.checked) {
-      wrap.innerHTML = `<svg viewBox="0 0 24 24" width="14" height="14" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"></polyline></svg>`
-    } else {
-      wrap.innerHTML = `` // empty for unchecked, border provides the box
-    }
- 
-    wrap.onclick = (e) => {
-      e.preventDefault()
-      e.stopPropagation()
-      const from = this.pos
-      const to = this.pos + (this.checked ? 8 : 6) // length of "/checked" or "/check"
-      const insert = this.checked ? '/check' : '/checked'
-      this.view.dispatch({
-        changes: { from, to, insert },
-      })
-    }
- 
-    return wrap
-  }
-}
- 
-export class VariableWidget extends WidgetType {
-  value: string
-  constructor(value: string) {
-    super()
-    this.value = value
-  }
-  eq(other: VariableWidget) {
-    return other.value === this.value
-  }
-  toDOM() {
-    const span = document.createElement('span')
-    span.textContent = String(this.value)
-    span.className = 'cm-variable-pill'
-    return span
-  }
-}
- 
-export class ColorWidget extends WidgetType {
-  color: string
-  constructor(color: string) {
-    super()
-    this.color = color
-  }
-  eq(other: ColorWidget) {
-    return other.color === this.color
-  }
-  toDOM() {
-    const span = document.createElement('span')
-    span.className = 'cm-color-pill'
-    span.style.setProperty('--pill-color', this.color)
- 
-    const circle = document.createElement('span')
-    circle.className = 'cm-color-circle'
-    circle.style.backgroundColor = this.color
-    circle.style.width = '10px'
-    circle.style.height = '10px'
-    circle.style.borderRadius = '50%'
-    circle.style.display = 'inline-block'
-    circle.style.marginRight = '4px'
-    circle.style.cursor = 'pointer'
-    circle.title = 'Copy hex code'
- 
-    circle.onclick = (e) => {
-      e.preventDefault()
-      e.stopPropagation()
-      navigator.clipboard.writeText(this.color)
- 
-      span.classList.remove('flash')
-      void span.offsetWidth // Trigger reflow to restart animation if clicked quickly
-      span.classList.add('flash')
- 
-      setTimeout(() => {
-        span.classList.remove('flash')
-      }, 500)
-    }
- 
-    const text = document.createTextNode(this.color)
- 
-    span.appendChild(circle)
-    span.appendChild(text)
- 
-    return span
-  }
-}
- 
-export class ReminderWidget extends WidgetType {
-  checked: boolean
-  overdue: boolean
-  pos: number
-  view: EditorView
- 
-  constructor(checked: boolean, overdue: boolean, pos: number, view: EditorView) {
-    super()
-    this.checked = checked
-    this.overdue = overdue
-    this.pos = pos
-    this.view = view
-  }
- 
-  eq(other: ReminderWidget) {
-    return (
-      other.checked === this.checked && other.pos === this.pos && other.overdue === this.overdue
-    )
-  }
- 
-  toDOM() {
-    const wrap = document.createElement('span')
-    wrap.className =
-      'cm-rem-widget' +
-      (this.checked ? ' cm-rem-checked' : '') +
-      (this.overdue && !this.checked ? ' cm-rem-overdue' : '')
- 
-    if (this.checked) {
-      wrap.innerHTML = `<svg viewBox="0 0 24 24" width="14" height="14" fill="currentColor"><circle cx="12" cy="12" r="8"></circle></svg>`
-    } else {
-      wrap.innerHTML = `` // empty for unchecked, border provides the box
-    }
- 
-    // Use onmousedown to prevent CodeMirror from interfering with selection
-    wrap.onmousedown = (e) => {
-      e.preventDefault()
-      e.stopPropagation()
- 
-      const from = this.pos
-      const to = this.pos + (this.checked ? 10 : 5) // length of "/task-done" or "/task"
-      const insert = this.checked ? '/task' : '/task-done'
- 
-      this.view.dispatch({
-        changes: { from, to, insert },
-      })
-    }
- 
-    return wrap
-  }
- 
-  ignoreEvent() {
-    return true
-  }
-}
- 
-export class ContextWidget extends WidgetType {
-  toDOM() {
-    const span = document.createElement('span')
-    span.textContent = 'Context Attached'
-    span.className = 'cm-ctx-pill'
-    return span
-  }
-}
- 
- -
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/src/lib/index.html b/coverage/src/lib/index.html deleted file mode 100644 index 8ac68ad..0000000 --- a/coverage/src/lib/index.html +++ /dev/null @@ -1,131 +0,0 @@ - - - - - - Code coverage report for src/lib - - - - - - - - - -
-
-

All files src/lib

-
- -
- 63.63% - Statements - 7/11 -
- - -
- 50% - Branches - 2/4 -
- - -
- 66.66% - Functions - 2/3 -
- - -
- 60% - Lines - 6/10 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FileStatementsBranchesFunctionsLines
safeStorage.ts -
-
60%6/1050%2/466.66%2/355.55%5/9
settingsKeys.ts -
-
100%1/1100%0/0100%0/0100%1/1
-
-
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/src/lib/safeStorage.ts.html b/coverage/src/lib/safeStorage.ts.html deleted file mode 100644 index c4630a3..0000000 --- a/coverage/src/lib/safeStorage.ts.html +++ /dev/null @@ -1,139 +0,0 @@ - - - - - - Code coverage report for src/lib/safeStorage.ts - - - - - - - - - -
-
-

All files / src/lib safeStorage.ts

-
- -
- 60% - Statements - 6/10 -
- - -
- 50% - Branches - 2/4 -
- - -
- 66.66% - Functions - 2/3 -
- - -
- 55.55% - Lines - 5/9 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19  -1x -1x -  -  -  -2x -2x -1x -  -  -  -  -  -  -  -  -  - 
export async function setSecure(key: string, value: string): Promise<void> {
-  const encrypted = await window.electronAPI.safeStorageEncrypt(value)
-  localStorage.setItem(`${key}-secure`, encrypted)
-}
- 
-export async function getSecure(key: string): Promise<string | null> {
-  const encrypted = localStorage.getItem(`${key}-secure`)
-  if (!encrypted) return null
-  return await window.electronAPI.safeStorageDecrypt(encrypted)
-}
- 
-export async function migrateApiKeyFromLocalStorage(key: string) {
-  const plain = localStorage.getItem(key)
-  if (plain) {
-    await setSecure(key, plain)
-    localStorage.removeItem(key)
-  }
-}
- 
- -
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/src/lib/settingsKeys.ts.html b/coverage/src/lib/settingsKeys.ts.html deleted file mode 100644 index 632a173..0000000 --- a/coverage/src/lib/settingsKeys.ts.html +++ /dev/null @@ -1,145 +0,0 @@ - - - - - - Code coverage report for src/lib/settingsKeys.ts - - - - - - - - - -
-
-

All files / src/lib settingsKeys.ts

-
- -
- 100% - Statements - 1/1 -
- - -
- 100% - Branches - 0/0 -
- - -
- 100% - Functions - 0/0 -
- - -
- 100% - Lines - 1/1 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -212x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  - 
export const SETTINGS_KEYS = {
-  THEME_PRESET: 'papercache-theme-preset',
-  FONT_FAMILY: 'papercache-font',
-  SHOW_RULINGS: 'papercache-rulings',
-  BG_TYPE: 'papercache-bg-type',
-  BG_COLOR: 'papercache-bg-color',
-  BG_IMAGE: 'papercache-bg-image',
-  TEXT_COLOR: 'papercache-color-text',
-  NUM_COLOR: 'papercache-color-num',
-  SYM_COLOR: 'papercache-color-sym',
-  AI_COLOR: 'papercache-ai-color',
-  MATH_COLOR: 'papercache-math-color',
-  API_BASE_URL: 'papercache-api-base-url',
-  API_MODEL: 'papercache-api-model',
-  AI_SYSTEM_PROMPT: 'papercache-ai-system-prompt',
-  SHORTCUT_NEWNOTE: 'papercache-shortcut-newnote',
-  SHORTCUT_TOGGLE: 'papercache-shortcut-toggle',
-  LAUNCH_STARTUP: 'papercache-launch-startup',
-  NOTIFIED_REMINDERS: 'papercache_notified',
-} as const
- 
- -
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/src/store/index.html b/coverage/src/store/index.html deleted file mode 100644 index 3333ff9..0000000 --- a/coverage/src/store/index.html +++ /dev/null @@ -1,116 +0,0 @@ - - - - - - Code coverage report for src/store - - - - - - - - - -
-
-

All files src/store

-
- -
- 36.36% - Statements - 8/22 -
- - -
- 37.5% - Branches - 6/16 -
- - -
- 33.33% - Functions - 7/21 -
- - -
- 35.71% - Lines - 5/14 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FileStatementsBranchesFunctionsLines
useAppStore.ts -
-
36.36%8/2237.5%6/1633.33%7/2135.71%5/14
-
-
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/src/store/useAppStore.ts.html b/coverage/src/store/useAppStore.ts.html deleted file mode 100644 index cc8fb50..0000000 --- a/coverage/src/store/useAppStore.ts.html +++ /dev/null @@ -1,403 +0,0 @@ - - - - - - Code coverage report for src/store/useAppStore.ts - - - - - - - - - -
-
-

All files / src/store useAppStore.ts

-
- -
- 36.36% - Statements - 8/22 -
- - -
- 37.5% - Branches - 6/16 -
- - -
- 33.33% - Functions - 7/21 -
- - -
- 35.71% - Lines - 5/14 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 -100 -101 -102 -103 -104 -105 -106 -107  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -3x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -2x -  -  -1x -  -  -  -  -  -  -2x -  -  -  -  -  -  -  -  -  -  -  -  -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  - 
import { create } from 'zustand'
- 
-export interface Note {
-  id: string
-  content: string
-  mtime: number
-}
- 
-interface AppState {
-  notes: Note[]
-  currentNoteIndex: number
-  zoomLevel: number
- 
-  // UI state
-  showGraphView: boolean
-  showRemindersView: boolean
-  isRenaming: boolean
-  renameValue: string
-  showNoteSearch: boolean
-  noteSearchQuery: string
-  searchSelectedIndex: number
-  showNoteActionMenu: boolean
-  showMainActionMenu: boolean
-  actionMenuIndex: number
- 
-  setNotes: (notes: Note[] | ((prev: Note[]) => Note[])) => void
-  setCurrentNoteIndex: (index: number) => void
-  setZoomLevel: (zoom: number | ((prev: number) => number)) => void
- 
-  setShowGraphView: (show: boolean | ((prev: boolean) => boolean)) => void
-  setShowRemindersView: (show: boolean | ((prev: boolean) => boolean)) => void
-  setIsRenaming: (isRenaming: boolean) => void
-  setRenameValue: (renameValue: string) => void
-  setShowNoteSearch: (show: boolean) => void
-  setNoteSearchQuery: (query: string) => void
-  setSearchSelectedIndex: (index: number | ((prev: number) => number)) => void
-  setShowNoteActionMenu: (show: boolean) => void
-  setShowMainActionMenu: (show: boolean | ((prev: boolean) => boolean)) => void
-  setActionMenuIndex: (index: number | ((prev: number) => number)) => void
-}
- 
-export const useAppStore = create<AppState>((set) => ({
-  notes: [],
-  currentNoteIndex: 0,
-  zoomLevel: Number(localStorage.getItem('papercache-zoom')) || 1,
- 
-  showGraphView: false,
-  showRemindersView: false,
-  isRenaming: false,
-  renameValue: '',
-  showNoteSearch: false,
-  noteSearchQuery: '',
-  searchSelectedIndex: 0,
-  showNoteActionMenu: false,
-  showMainActionMenu: false,
-  actionMenuIndex: 0,
- 
-  setNotes: (notes) =>
-    set((state) => ({
-      notes: typeof notes === 'function' ? notes(state.notes) : notes,
-    })),
-  setCurrentNoteIndex: (currentNoteIndex) => set({ currentNoteIndex }),
-  setZoomLevel: (zoomLevel) =>
-    set((state) => ({
-      zoomLevel: typeof zoomLevel === 'function' ? zoomLevel(state.zoomLevel) : zoomLevel,
-    })),
- 
-  setShowGraphView: (showGraphView) =>
-    set((state) => ({
-      showGraphView:
-        typeof showGraphView === 'function' ? showGraphView(state.showGraphView) : showGraphView,
-    })),
-  setShowRemindersView: (showRemindersView) =>
-    set((state) => ({
-      showRemindersView:
-        typeof showRemindersView === 'function'
-          ? showRemindersView(state.showRemindersView)
-          : showRemindersView,
-    })),
-  setIsRenaming: (isRenaming) => set({ isRenaming }),
-  setRenameValue: (renameValue) => set({ renameValue }),
-  setShowNoteSearch: (showNoteSearch) => set({ showNoteSearch }),
-  setNoteSearchQuery: (noteSearchQuery) => set({ noteSearchQuery }),
-  setSearchSelectedIndex: (searchSelectedIndex) =>
-    set((state) => ({
-      searchSelectedIndex:
-        typeof searchSelectedIndex === 'function'
-          ? searchSelectedIndex(state.searchSelectedIndex)
-          : searchSelectedIndex,
-    })),
-  setShowNoteActionMenu: (showNoteActionMenu) => set({ showNoteActionMenu }),
-  setShowMainActionMenu: (showMainActionMenu) =>
-    set((state) => ({
-      showMainActionMenu:
-        typeof showMainActionMenu === 'function'
-          ? showMainActionMenu(state.showMainActionMenu)
-          : showMainActionMenu,
-    })),
-  setActionMenuIndex: (actionMenuIndex) =>
-    set((state) => ({
-      actionMenuIndex:
-        typeof actionMenuIndex === 'function'
-          ? actionMenuIndex(state.actionMenuIndex)
-          : actionMenuIndex,
-    })),
-}))
- 
- -
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/src/utils.ts.html b/coverage/src/utils.ts.html deleted file mode 100644 index a467a9e..0000000 --- a/coverage/src/utils.ts.html +++ /dev/null @@ -1,205 +0,0 @@ - - - - - - Code coverage report for src/utils.ts - - - - - - - - - -
-
-

All files / src utils.ts

-
- -
- 100% - Statements - 35/35 -
- - -
- 92.85% - Branches - 13/14 -
- - -
- 100% - Functions - 4/4 -
- - -
- 100% - Lines - 28/28 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -411x -9x -8x -8x -8x -  -  -8x -  -7x -  -4x -4x -  -4x -  -7x -7x -3x -3x -3x -4x -4x -4x -4x -3x -3x -  -  -  -4x -20x -4x -  -  -7x -7x -7x -7x -  - 
export const getFolderColor = (str: string): string => {
-  if (!str) return '#ffffff'
-  let colors: Record<string, string> = {}
-  try {
-    colors = JSON.parse(localStorage.getItem('papercache-folder-colors') || '{}')
-  } catch {}
- 
-  if (colors[str]) return colors[str]
- 
-  const usedHues = Object.values(colors)
-    .map((c) => {
-      const match = c.match(/hsl\((\d+)/)
-      return match ? parseInt(match[1]) : null
-    })
-    .filter((h) => h !== null) as number[]
- 
-  let bestHue = 0
-  if (usedHues.length > 0) {
-    usedHues.sort((a, b) => a - b)
-    let maxDist = 0
-    for (let i = 0; i < usedHues.length; i++) {
-      const next = (i + 1) % usedHues.length
-      let dist = usedHues[next] - usedHues[i]
-      if (dist <= 0) dist += 360
-      if (dist > maxDist) {
-        maxDist = dist
-        bestHue = (usedHues[i] + dist / 2) % 360
-      }
-    }
-  } else {
-    let hash = 0
-    for (let i = 0; i < str.length; i++) hash = str.charCodeAt(i) + ((hash << 5) - hash)
-    bestHue = Math.abs(hash % 360)
-  }
- 
-  const color = `hsl(${Math.round(bestHue)}, 70%, 60%)`
-  colors[str] = color
-  localStorage.setItem('papercache-folder-colors', JSON.stringify(colors))
-  return color
-}
- 
- -
-
- - - - - - - - \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index be725fc..08300f2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "papercache", - "version": "0.1.17", + "version": "0.1.18", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "papercache", - "version": "0.1.17", + "version": "0.1.18", "dependencies": { "@codemirror/lang-markdown": "^6.5.0", "@codemirror/language": "^6.12.3", diff --git a/package.json b/package.json index 45758ea..0005bb0 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "papercache", "private": true, - "version": "0.1.17", + "version": "0.1.18", "type": "module", "main": "dist-electron/main.js", "engines": { From e300f4a93f7c3965328feb47720816d4027a8a9e Mon Sep 17 00:00:00 2001 From: Aditya Date: Sun, 21 Jun 2026 10:00:58 +0530 Subject: [PATCH 06/10] chore: bump version to 0.2.10 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0005bb0..dbea129 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "papercache", "private": true, - "version": "0.1.18", + "version": "0.2.10", "type": "module", "main": "dist-electron/main.js", "engines": { From 2e765540673657b0c6a138b1621bd372d5566f94 Mon Sep 17 00:00:00 2001 From: Aditya Date: Sun, 21 Jun 2026 10:02:58 +0530 Subject: [PATCH 07/10] fix: import autoUpdater as CJS default export --- electron/main.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/electron/main.ts b/electron/main.ts index 5e86328..687d868 100644 --- a/electron/main.ts +++ b/electron/main.ts @@ -14,7 +14,8 @@ import { powerMonitor, session, } from 'electron' -import { autoUpdater } from 'electron-updater' +import electronUpdater from 'electron-updater' +const { autoUpdater } = electronUpdater import path from 'node:path' import { fileURLToPath } from 'node:url' import fs from 'node:fs' From 02b1c6660021275c7194028a2f8f4b768bad2ef3 Mon Sep 17 00:00:00 2001 From: Aditya Date: Sun, 21 Jun 2026 10:06:06 +0530 Subject: [PATCH 08/10] ui: adjust Graph View font and hide node labels on zoom out --- src/GraphView.tsx | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/GraphView.tsx b/src/GraphView.tsx index 9472ec3..36ae798 100644 --- a/src/GraphView.tsx +++ b/src/GraphView.tsx @@ -91,7 +91,14 @@ export default function GraphView({ borderBottom: `1px solid ${textColor}22`, }} > -

+

Graph View