diff --git a/.github/dependabot.yml b/.github/dependabot.yml index be006de9..8c8475ee 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -8,6 +8,6 @@ updates: groups: github-actions: patterns: - - "*" # Group all Actions updates into a single larger pull request + - '*' # Group all Actions updates into a single larger pull request schedule: interval: weekly diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index 2da594ed..d3c18b99 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -68,6 +68,10 @@ jobs: run: | pnpm install && pnpm setup-vendors + - name: run format check + run: | + pnpm format:check || (pnpm format && git diff && exit 1) + - name: run tests working-directory: apps/readest-app run: | diff --git a/.prettierignore b/.prettierignore index e70b52f2..2cbb8eaa 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1 +1,34 @@ -packages/foliate-js/ \ No newline at end of file +# Dependencies +node_modules +pnpm-lock.yaml + +# Build Artifacts (Web & Rust) +.next +.open-next +.build +.tauri +out +build +dist +target +fastlane +.wrangler + +# Autogenerated Tauri files +gen +**/autogenerated +**/schemas + +# Submodules (External Repos) +packages + +# Vendored Assets (Generated/External Code) +apps/readest-app/public/*.js +apps/readest-app/public/vendor + +# Environment & Editor +.env +.env.* +.vscode +.idea +*.log \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index 74cfcb5e..f0d8e61d 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -13,4 +13,19 @@ "javascript.validate.enable": false, "javascript.format.enable": false, "typescript.format.enable": false, -} \ No newline at end of file + "editor.defaultFormatter": "esbenp.prettier-vscode", + "editor.codeActionsOnSave": { + "source.fixAll.eslint": "explicit" + }, + "[css]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[typescript]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[typescriptreact]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "prettier.requireConfig": true, + "prettier.documentSelectors": ["**/*.{js,jsx,ts,tsx,css,json,md,html,yml}"] +} diff --git a/apps/readest-app/extensions/windows-thumbnail/README.md b/apps/readest-app/extensions/windows-thumbnail/README.md index 52eba5ac..25d34e93 100644 --- a/apps/readest-app/extensions/windows-thumbnail/README.md +++ b/apps/readest-app/extensions/windows-thumbnail/README.md @@ -12,28 +12,31 @@ This crate provides Windows Explorer thumbnail support for eBook files when Read ## Supported Formats -| Format | Extension | Cover Source | -|--------|-----------|--------------| -| EPUB | `.epub` | OPF manifest cover reference | -| MOBI/AZW | `.mobi`, `.azw`, `.prc` | EXTH cover offset | -| AZW3/KF8 | `.azw3`, `.kf8` | KF8 format cover | -| FB2 | `.fb2` | `` coverpage element | -| Comic Book | `.cbz`, `.cbr` | First image in archive | -| Plain Text | `.txt` | Generated placeholder | +| Format | Extension | Cover Source | +| ---------- | ----------------------- | ---------------------------- | +| EPUB | `.epub` | OPF manifest cover reference | +| MOBI/AZW | `.mobi`, `.azw`, `.prc` | EXTH cover offset | +| AZW3/KF8 | `.azw3`, `.kf8` | KF8 format cover | +| FB2 | `.fb2` | `` coverpage element | +| Comic Book | `.cbz`, `.cbr` | First image in archive | +| Plain Text | `.txt` | Generated placeholder | ## Building ### Library Only + ```bash cargo build --release ``` ### COM DLL (for Windows Explorer integration) + ```bash cargo build --release --features com ``` ### CLI Tool + ```bash cargo build --release --features cli ``` diff --git a/apps/readest-app/package.json b/apps/readest-app/package.json index 43d7a46e..f34011ab 100644 --- a/apps/readest-app/package.json +++ b/apps/readest-app/package.json @@ -15,6 +15,8 @@ "test": "dotenv -e .env -e .env.test.local vitest", "tauri": "tauri", "clippy": "cargo clippy -p Readest --no-deps -- -D warnings", + "format": "pnpm -w format", + "format:check": "pnpm -w format:check", "prepare-public-vendor": "mkdirp ./public/vendor/pdfjs ./public/vendor/simplecc", "copy-pdfjs-js": "cpx \"../../packages/foliate-js/node_modules/pdfjs-dist/legacy/build/{pdf.worker.min.mjs,pdf.min.mjs,pdf.d.mts}\" ./public/vendor/pdfjs", "copy-pdfjs-wasm": "cpx \"../../packages/foliate-js/node_modules/pdfjs-dist/wasm/{openjpeg.wasm,qcms_bg.wasm}\" ./public/vendor/pdfjs", diff --git a/apps/readest-app/src/app/reader/hooks/useBooknotesNav.ts b/apps/readest-app/src/app/reader/hooks/useBooknotesNav.ts index a847b7d1..7fc4960c 100644 --- a/apps/readest-app/src/app/reader/hooks/useBooknotesNav.ts +++ b/apps/readest-app/src/app/reader/hooks/useBooknotesNav.ts @@ -103,14 +103,7 @@ export function useBooknotesNav(bookKey: string, toc: TOCItem[]) { getView(bookKey)?.goTo(sorted[0]!.cfi); } }, - [ - allBooknotes, - bookKey, - setActiveBooknoteType, - setBooknoteResults, - setBooknoteIndex, - getView, - ], + [allBooknotes, bookKey, setActiveBooknoteType, setBooknoteResults, setBooknoteIndex, getView], ); const handleShowResults = useCallback(() => { diff --git a/apps/readest-app/src/services/translators/providers/yandex.ts b/apps/readest-app/src/services/translators/providers/yandex.ts index 6c1810cf..23a90534 100644 --- a/apps/readest-app/src/services/translators/providers/yandex.ts +++ b/apps/readest-app/src/services/translators/providers/yandex.ts @@ -24,27 +24,26 @@ async function translateSingleTextForService( lang: lang, service: service, text: text, - }) + }), }; const response = await fetchImpl(url, request); if (!response.ok) { const response_json = JSON.stringify(await response.json()); - throw new Error(`${service} failed with status ${response.status}\n${text.length}\n${JSON.stringify(request)}\n${response_json}`); + throw new Error( + `${service} failed with status ${response.status}\n${text.length}\n${JSON.stringify(request)}\n${response_json}`, + ); } const data = await response.json(); - if ( - data && - Array.isArray(data.translations) - ) { + if (data && Array.isArray(data.translations)) { return data.translations; } else { // fallback: return original texts if translation failed return [text]; } -}; +} export const yandexProvider: TranslationProvider = { name: 'yandex', @@ -60,18 +59,21 @@ export const yandexProvider: TranslationProvider = { - yandextranslate - yandexbrowser */ - const service = "yandexgpt"; + const service = 'yandexgpt'; // Yandex does not accept "auto" language - const source_lang = sourceLang == "AUTO" ? "en" : normalizeToShortLang(sourceLang).toLowerCase(); + const source_lang = + sourceLang == 'AUTO' ? 'en' : normalizeToShortLang(sourceLang).toLowerCase(); const target_lang = normalizeToShortLang(targetLang).toLowerCase(); const lang = `${source_lang}-${target_lang}`; - const responses = await Promise.all(texts.map(async text => { - return await translateSingleTextForService(text, lang, service) - })); + const responses = await Promise.all( + texts.map(async (text) => { + return await translateSingleTextForService(text, lang, service); + }), + ); const translatedTexts = responses.flat(); return translatedTexts; - } + }, }; diff --git a/apps/readest-app/src/services/webAppService.ts b/apps/readest-app/src/services/webAppService.ts index 182bc490..72a76eb8 100644 --- a/apps/readest-app/src/services/webAppService.ts +++ b/apps/readest-app/src/services/webAppService.ts @@ -322,7 +322,11 @@ export class WebAppService extends BaseAppService { throw new Error('selectFiles is not supported in browser'); } - async saveFile(filename: string, content: string | ArrayBuffer, mimeType?: string): Promise { + async saveFile( + filename: string, + content: string | ArrayBuffer, + mimeType?: string, + ): Promise { try { const blob = new Blob([content], { type: mimeType || 'application/octet-stream' }); const url = URL.createObjectURL(blob); diff --git a/apps/readest-app/src/types/error.ts b/apps/readest-app/src/types/error.ts index 8b137891..e69de29b 100644 --- a/apps/readest-app/src/types/error.ts +++ b/apps/readest-app/src/types/error.ts @@ -1 +0,0 @@ - diff --git a/apps/readest-app/src/utils/r2.ts b/apps/readest-app/src/utils/r2.ts index 6dc123c7..84fdb682 100644 --- a/apps/readest-app/src/utils/r2.ts +++ b/apps/readest-app/src/utils/r2.ts @@ -15,18 +15,18 @@ export const r2Storage = { return `https://${R2_ACCOUNT_ID}.r2.cloudflarestorage.com`; }, - getDownloadSignedUrl: async ( - bucketName: string, - fileKey: string, - expiresIn: number, - ) => { + getDownloadSignedUrl: async (bucketName: string, fileKey: string, expiresIn: number) => { return ( - await r2Storage.getR2Client().sign( - new Request(`${r2Storage.getR2Url()}/${bucketName}/${fileKey}?X-Amz-Expires=${expiresIn}`), - { - aws: { signQuery: true }, - }, - ) + await r2Storage + .getR2Client() + .sign( + new Request( + `${r2Storage.getR2Url()}/${bucketName}/${fileKey}?X-Amz-Expires=${expiresIn}`, + ), + { + aws: { signQuery: true }, + }, + ) ).url.toString(); }, diff --git a/apps/readest-app/src/utils/s3.ts b/apps/readest-app/src/utils/s3.ts index 723a0d88..da9f31fa 100644 --- a/apps/readest-app/src/utils/s3.ts +++ b/apps/readest-app/src/utils/s3.ts @@ -17,7 +17,6 @@ export const s3Client = new S3Client({ }, }); - export const s3Storage = { getClient: () => { return new S3Client({ @@ -31,12 +30,7 @@ export const s3Storage = { }); }, - getDownloadSignedUrl: async ( - bucketName: string, - fileKey: string, - expiresIn: number, - ) => { - + getDownloadSignedUrl: async (bucketName: string, fileKey: string, expiresIn: number) => { const getCommand = new GetObjectCommand({ Bucket: bucketName, Key: fileKey, @@ -53,7 +47,6 @@ export const s3Storage = { contentLength: number, expiresIn: number, ) => { - const signableHeaders = new Set(); signableHeaders.add('content-length'); const putCommand = new PutObjectCommand({ diff --git a/apps/readest-app/tsconfig.json b/apps/readest-app/tsconfig.json index 87c7b867..aee1067d 100644 --- a/apps/readest-app/tsconfig.json +++ b/apps/readest-app/tsconfig.json @@ -2,12 +2,7 @@ "extends": "@sindresorhus/tsconfig", "compilerOptions": { "target": "ES2022", - "lib": [ - "dom", - "dom.iterable", - "webworker", - "esnext" - ], + "lib": ["dom", "dom.iterable", "webworker", "esnext"], "allowJs": true, "skipLibCheck": true, "strict": true, @@ -25,25 +20,11 @@ } ], "paths": { - "@/*": [ - "./src/*" - ], - "@pdfjs/*": [ - "./public/vendor/pdfjs/*" - ], - "@simplecc/*": [ - "./public/vendor/simplecc/*" - ] + "@/*": ["./src/*"], + "@pdfjs/*": ["./public/vendor/pdfjs/*"], + "@simplecc/*": ["./public/vendor/simplecc/*"] } }, - "include": [ - "next-env.d.ts", - "**/*.ts", - "**/*.tsx", - "raw-loader.d.ts", - ".next/types/**/*.ts" - ], - "exclude": [ - "node_modules", - ] -} \ No newline at end of file + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "raw-loader.d.ts", ".next/types/**/*.ts"], + "exclude": ["node_modules"] +} diff --git a/package.json b/package.json index ce462eb2..d203180f 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,9 @@ "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "tauri": "pnpm --filter @readest/readest-app tauri", - "dev-web": "pnpm --filter @readest/readest-app dev-web" + "dev-web": "pnpm --filter @readest/readest-app dev-web", + "format": "prettier --write \"**/*.{js,jsx,ts,tsx,css,json,md,html,yml}\"", + "format:check": "prettier --check \"**/*.{js,jsx,ts,tsx,css,json,md,html,yml}\"" }, "devDependencies": { "@eslint/eslintrc": "^3.3.1", diff --git a/tsconfig.json b/tsconfig.json index 08d42c9e..dc491d9c 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -8,12 +8,12 @@ "strict": true, "moduleResolution": "bundler", "esModuleInterop": true, - "skipLibCheck": true, + "skipLibCheck": true }, "files": [], "references": [ { "path": "./apps/readest-app" - }, + } ] -} \ No newline at end of file +}