chore: switch code formatter from Prettier to Biome (#4223)
Replace Prettier with Biome for formatting JS/TS/JSX/CSS/JSON. The CI format check drops from ~23s to ~0.4s. - Unify config into a single root biome.json (formatter + linter); the former apps/readest-app/biome.json was linter-only - Mirror the old .prettierrc.json style: 100 line width, 2-space indent, LF, single quotes, trailing commas - Enable the CSS tailwindDirectives parser for @apply in globals.css - Convert // prettier-ignore comments to // biome-ignore format: - Root scripts and lint-staged now run biome; apps/readest-app lint runs `biome lint` (lint-only) so formatting stays a separate CI step - Drop prettier + prettier-plugin-tailwindcss dependencies Markdown/YAML are no longer format-checked (Biome does not format them) and Tailwind class sorting is no longer enforced. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,40 +0,0 @@
|
||||
# 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
|
||||
|
||||
# Claude Code Skills & Config
|
||||
apps/readest-app/.claude
|
||||
|
||||
# Vendored Assets (Generated/External Code)
|
||||
apps/readest-app/public/*.js
|
||||
apps/readest-app/public/vendor
|
||||
apps/readest-app/src-tauri/plugins/tauri-plugin-turso
|
||||
apps/readest-app/src-tauri/plugins/tauri-plugin-webview-upgrade
|
||||
|
||||
# Environment & Editor
|
||||
.github
|
||||
.env
|
||||
.env.*
|
||||
.vscode
|
||||
.idea
|
||||
*.log
|
||||
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"trailingComma": "all",
|
||||
"printWidth": 100,
|
||||
"semi": true,
|
||||
"tabWidth": 2,
|
||||
"singleQuote": true,
|
||||
"jsxSingleQuote": true,
|
||||
"endOfLine": "lf",
|
||||
"plugins": ["prettier-plugin-tailwindcss"]
|
||||
}
|
||||
Vendored
+1
-1
@@ -2,7 +2,7 @@
|
||||
"recommendations": [
|
||||
"ms-vscode.vscode-typescript-next",
|
||||
"dbaeumer.vscode-eslint",
|
||||
"esbenp.prettier-vscode",
|
||||
"biomejs.biome",
|
||||
"rust-lang.rust-analyzer"
|
||||
]
|
||||
}
|
||||
|
||||
Vendored
+7
-6
@@ -13,19 +13,20 @@
|
||||
"javascript.validate.enable": false,
|
||||
"javascript.format.enable": false,
|
||||
"typescript.format.enable": false,
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
"editor.defaultFormatter": "biomejs.biome",
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll.eslint": "explicit"
|
||||
},
|
||||
"[css]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
"editor.defaultFormatter": "biomejs.biome"
|
||||
},
|
||||
"[typescript]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
"editor.defaultFormatter": "biomejs.biome"
|
||||
},
|
||||
"[typescriptreact]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
"editor.defaultFormatter": "biomejs.biome"
|
||||
},
|
||||
"prettier.requireConfig": true,
|
||||
"prettier.documentSelectors": ["**/*.{js,jsx,ts,tsx,css,json,md,html,yml}"]
|
||||
"[json]": {
|
||||
"editor.defaultFormatter": "biomejs.biome"
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -86,7 +86,7 @@ Recommended Visual Studio Code plugins for development:
|
||||
|
||||
- JavaScript and TypeScript Nightly (ms-vscode.vscode-typescript-next)
|
||||
- VS Code ESLint extension (dbaeumer.vscode-eslint)
|
||||
- Prettier - Code formatter (esbenp.prettier-vscode)
|
||||
- Biome - Code formatter and linter (biomejs.biome)
|
||||
- rust-analyzer (rust-lang.rust-analyzer) (for Tauri development only)
|
||||
|
||||
### When you're done
|
||||
|
||||
@@ -23,8 +23,8 @@ pnpm test:tauri # Run Tauri integration tests
|
||||
|
||||
# Linting & Formatting
|
||||
pnpm lint # Biome (linter) + tsgo (type check)
|
||||
pnpm format # Prettier (runs from monorepo root)
|
||||
pnpm format:check # Check formatting without writing
|
||||
pnpm format # Biome formatter (runs from monorepo root)
|
||||
pnpm format:check # Check formatting without writing (Biome)
|
||||
|
||||
# Rust
|
||||
pnpm fmt:check # Check formatting Rust code (src-tauri)
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
"dev-android": "tauri android build -t aarch64 -- --features devtools && adb install -r src-tauri/gen/android/app/build/outputs/apk/universal/release/app-universal-release.apk",
|
||||
"dev-ios": "tauri ios build -- --features devtools && ideviceinstaller -i src-tauri/gen/apple/build/arm64/Readest.ipa",
|
||||
"i18n:extract": "i18next-scanner --config i18next-scanner.config.cjs",
|
||||
"lint": "tsgo --noEmit && biome check . && pnpm lint:lua",
|
||||
"lint": "tsgo --noEmit && biome lint . && pnpm lint:lua",
|
||||
"lint:lua": "node ../readest.koplugin/scripts/lint-koplugin.mjs",
|
||||
"test:lua": "node ../readest.koplugin/scripts/test-koplugin.mjs",
|
||||
"test": "dotenv -e .env -e .env.test.local -- vitest",
|
||||
|
||||
@@ -166,8 +166,9 @@ describe('publishSettingsIfChanged', () => {
|
||||
});
|
||||
|
||||
test('publishes dictionarySettings.providerOrder when markExplicitProviderOrderPublish was called', async () => {
|
||||
const { markExplicitProviderOrderPublish } =
|
||||
await import('@/services/sync/replicaSettingsSync');
|
||||
const { markExplicitProviderOrderPublish } = await import(
|
||||
'@/services/sync/replicaSettingsSync'
|
||||
);
|
||||
markExplicitProviderOrderPublish();
|
||||
await publishSettingsIfChanged(
|
||||
makeSettings({
|
||||
@@ -184,8 +185,9 @@ describe('publishSettingsIfChanged', () => {
|
||||
});
|
||||
|
||||
test('explicit-publish opt-in is consumed after one publish (no carryover)', async () => {
|
||||
const { markExplicitProviderOrderPublish } =
|
||||
await import('@/services/sync/replicaSettingsSync');
|
||||
const { markExplicitProviderOrderPublish } = await import(
|
||||
'@/services/sync/replicaSettingsSync'
|
||||
);
|
||||
markExplicitProviderOrderPublish();
|
||||
const settings1 = makeSettings({
|
||||
dictionarySettings: {
|
||||
|
||||
@@ -352,8 +352,9 @@ describe('provider registry disabled handling', () => {
|
||||
});
|
||||
|
||||
it('isTranslatorAvailable returns false for disabled providers', async () => {
|
||||
const { getTranslator, isTranslatorAvailable } =
|
||||
await import('@/services/translators/providers');
|
||||
const { getTranslator, isTranslatorAvailable } = await import(
|
||||
'@/services/translators/providers'
|
||||
);
|
||||
const yandex = getTranslator('yandex')!;
|
||||
expect(isTranslatorAvailable(yandex, true)).toBe(false);
|
||||
expect(isTranslatorAvailable(yandex, false)).toBe(false);
|
||||
@@ -373,8 +374,9 @@ describe('provider registry disabled handling', () => {
|
||||
});
|
||||
|
||||
it('getTranslatorDisplayLabel returns the plain label for healthy providers', async () => {
|
||||
const { getTranslator, getTranslatorDisplayLabel } =
|
||||
await import('@/services/translators/providers');
|
||||
const { getTranslator, getTranslatorDisplayLabel } = await import(
|
||||
'@/services/translators/providers'
|
||||
);
|
||||
const google = getTranslator('google')!;
|
||||
expect(getTranslatorDisplayLabel(google, true, (s) => s)).toBe('Google Translate');
|
||||
});
|
||||
|
||||
@@ -76,23 +76,38 @@ describe('createChapterRegexps — Chinese (zh) regex matching', () => {
|
||||
});
|
||||
|
||||
describe('第N[卷节回讲篇封本册部话] variants', () => {
|
||||
it.each(['卷', '节', '回', '讲', '篇', '封', '本', '册', '部', '话'])(
|
||||
'should match 第一%s',
|
||||
(suffix) => {
|
||||
const regex = getFirstRegex('zh');
|
||||
expect(regex.test(`\n第一${suffix}\n`)).toBe(true);
|
||||
},
|
||||
);
|
||||
it.each([
|
||||
'卷',
|
||||
'节',
|
||||
'回',
|
||||
'讲',
|
||||
'篇',
|
||||
'封',
|
||||
'本',
|
||||
'册',
|
||||
'部',
|
||||
'话',
|
||||
])('should match 第一%s', (suffix) => {
|
||||
const regex = getFirstRegex('zh');
|
||||
expect(regex.test(`\n第一${suffix}\n`)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Chinese preface keywords', () => {
|
||||
it.each(['楔子', '前言', '简介', '引言', '序言', '序章', '总论', '概论', '后记'])(
|
||||
'should match %s',
|
||||
(keyword) => {
|
||||
const regex = getFirstRegex('zh');
|
||||
expect(regex.test(`\n${keyword}\n`)).toBe(true);
|
||||
},
|
||||
);
|
||||
it.each([
|
||||
'楔子',
|
||||
'前言',
|
||||
'简介',
|
||||
'引言',
|
||||
'序言',
|
||||
'序章',
|
||||
'总论',
|
||||
'概论',
|
||||
'后记',
|
||||
])('should match %s', (keyword) => {
|
||||
const regex = getFirstRegex('zh');
|
||||
expect(regex.test(`\n${keyword}\n`)).toBe(true);
|
||||
});
|
||||
|
||||
it('should match 前言 with title', () => {
|
||||
const regex = getFirstRegex('zh');
|
||||
@@ -106,13 +121,15 @@ describe('createChapterRegexps — Chinese (zh) regex matching', () => {
|
||||
});
|
||||
|
||||
describe('"chapter" keyword in Chinese context', () => {
|
||||
it.each(['Chapter 1', 'CHAPTER 10', 'chapter.5', 'chapter 2: The Beginning'])(
|
||||
'should match "%s" (case-insensitive)',
|
||||
(heading) => {
|
||||
const regex = getFirstRegex('zh');
|
||||
expect(regex.test(`\n${heading}\n`)).toBe(true);
|
||||
},
|
||||
);
|
||||
it.each([
|
||||
'Chapter 1',
|
||||
'CHAPTER 10',
|
||||
'chapter.5',
|
||||
'chapter 2: The Beginning',
|
||||
])('should match "%s" (case-insensitive)', (heading) => {
|
||||
const regex = getFirstRegex('zh');
|
||||
expect(regex.test(`\n${heading}\n`)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('番外 (bonus) prefix variants', () => {
|
||||
@@ -167,13 +184,16 @@ describe('createChapterRegexps — Chinese (zh) second regex', () => {
|
||||
// ---------------------------------------------------------------------------
|
||||
describe('createChapterRegexps — English (en) regex matching', () => {
|
||||
describe('Chapter keyword', () => {
|
||||
it.each(['Chapter 1', 'Chapter 12', 'Chapter 999', 'CHAPTER 5', 'chapter 3'])(
|
||||
'should match "%s"',
|
||||
(heading) => {
|
||||
const regex = getFirstRegex('en');
|
||||
expect(regex.test(`\n${heading}\n`)).toBe(true);
|
||||
},
|
||||
);
|
||||
it.each([
|
||||
'Chapter 1',
|
||||
'Chapter 12',
|
||||
'Chapter 999',
|
||||
'CHAPTER 5',
|
||||
'chapter 3',
|
||||
])('should match "%s"', (heading) => {
|
||||
const regex = getFirstRegex('en');
|
||||
expect(regex.test(`\n${heading}\n`)).toBe(true);
|
||||
});
|
||||
|
||||
it('should match "Chapter 1: Title" with title', () => {
|
||||
const regex = getFirstRegex('en');
|
||||
@@ -187,21 +207,30 @@ describe('createChapterRegexps — English (en) regex matching', () => {
|
||||
});
|
||||
|
||||
describe('Roman numeral chapters', () => {
|
||||
it.each(['V', 'X', 'L', 'C', 'D', 'M'])(
|
||||
'should match single Roman numeral "Chapter %s"',
|
||||
(numeral) => {
|
||||
const regex = getFirstRegex('en');
|
||||
expect(regex.test(`\nChapter ${numeral}\n`)).toBe(true);
|
||||
},
|
||||
);
|
||||
it.each([
|
||||
'V',
|
||||
'X',
|
||||
'L',
|
||||
'C',
|
||||
'D',
|
||||
'M',
|
||||
])('should match single Roman numeral "Chapter %s"', (numeral) => {
|
||||
const regex = getFirstRegex('en');
|
||||
expect(regex.test(`\nChapter ${numeral}\n`)).toBe(true);
|
||||
});
|
||||
|
||||
it.each(['II', 'III', 'IV', 'VII', 'XII', 'XIV', 'XLII'])(
|
||||
'should match multi-char Roman numeral "Chapter %s"',
|
||||
(numeral) => {
|
||||
const regex = getFirstRegex('en');
|
||||
expect(regex.test(`\nChapter ${numeral}\n`)).toBe(true);
|
||||
},
|
||||
);
|
||||
it.each([
|
||||
'II',
|
||||
'III',
|
||||
'IV',
|
||||
'VII',
|
||||
'XII',
|
||||
'XIV',
|
||||
'XLII',
|
||||
])('should match multi-char Roman numeral "Chapter %s"', (numeral) => {
|
||||
const regex = getFirstRegex('en');
|
||||
expect(regex.test(`\nChapter ${numeral}\n`)).toBe(true);
|
||||
});
|
||||
|
||||
it('should not match single "I" as Roman numeral (not in allowed set)', () => {
|
||||
const regex = getFirstRegex('en');
|
||||
@@ -223,31 +252,39 @@ describe('createChapterRegexps — English (en) regex matching', () => {
|
||||
expect(regex.test(`\n${keyword} 1\n`)).toBe(true);
|
||||
});
|
||||
|
||||
it.each(['Part', 'Section', 'Book', 'Volume', 'Act'])(
|
||||
'should match "%s 3: A New Beginning" with title',
|
||||
(keyword) => {
|
||||
const regex = getFirstRegex('en');
|
||||
expect(regex.test(`\n${keyword} 3: A New Beginning\n`)).toBe(true);
|
||||
},
|
||||
);
|
||||
it.each([
|
||||
'Part',
|
||||
'Section',
|
||||
'Book',
|
||||
'Volume',
|
||||
'Act',
|
||||
])('should match "%s 3: A New Beginning" with title', (keyword) => {
|
||||
const regex = getFirstRegex('en');
|
||||
expect(regex.test(`\n${keyword} 3: A New Beginning\n`)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('preface keywords', () => {
|
||||
it.each(['Prologue', 'Epilogue', 'Introduction', 'Foreword', 'Preface', 'Afterword'])(
|
||||
'should match "%s"',
|
||||
(keyword) => {
|
||||
const regex = getFirstRegex('en');
|
||||
expect(regex.test(`\n${keyword}\n`)).toBe(true);
|
||||
},
|
||||
);
|
||||
it.each([
|
||||
'Prologue',
|
||||
'Epilogue',
|
||||
'Introduction',
|
||||
'Foreword',
|
||||
'Preface',
|
||||
'Afterword',
|
||||
])('should match "%s"', (keyword) => {
|
||||
const regex = getFirstRegex('en');
|
||||
expect(regex.test(`\n${keyword}\n`)).toBe(true);
|
||||
});
|
||||
|
||||
it.each(['PROLOGUE', 'prologue', 'Prologue'])(
|
||||
'should match "%s" case-insensitively',
|
||||
(keyword) => {
|
||||
const regex = getFirstRegex('en');
|
||||
expect(regex.test(`\n${keyword}\n`)).toBe(true);
|
||||
},
|
||||
);
|
||||
it.each([
|
||||
'PROLOGUE',
|
||||
'prologue',
|
||||
'Prologue',
|
||||
])('should match "%s" case-insensitively', (keyword) => {
|
||||
const regex = getFirstRegex('en');
|
||||
expect(regex.test(`\n${keyword}\n`)).toBe(true);
|
||||
});
|
||||
|
||||
it('should match "Prologue: The Beginning"', () => {
|
||||
const regex = getFirstRegex('en');
|
||||
|
||||
@@ -33,7 +33,8 @@ const buttonVariants = cva(
|
||||
);
|
||||
|
||||
export interface ButtonProps
|
||||
extends React.ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> {
|
||||
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
|
||||
VariantProps<typeof buttonVariants> {
|
||||
asChild?: boolean;
|
||||
}
|
||||
|
||||
|
||||
@@ -424,12 +424,7 @@ export const getCacheStats = async (
|
||||
};
|
||||
|
||||
export const pruneCache = async (
|
||||
options: {
|
||||
maxAge?: number;
|
||||
maxEntries?: number;
|
||||
maxSizeInBytes?: number;
|
||||
dryRun?: boolean;
|
||||
} = {},
|
||||
options: { maxAge?: number; maxEntries?: number; maxSizeInBytes?: number; dryRun?: boolean } = {},
|
||||
): Promise<number> => {
|
||||
const { maxAge, maxEntries, maxSizeInBytes, dryRun = false } = options;
|
||||
|
||||
|
||||
@@ -340,8 +340,7 @@ export interface ViewSettingsConfig {
|
||||
}
|
||||
|
||||
export interface ViewSettings
|
||||
extends
|
||||
BookLayout,
|
||||
extends BookLayout,
|
||||
BookStyle,
|
||||
BookFont,
|
||||
BookLanguage,
|
||||
|
||||
@@ -13,7 +13,7 @@ import type { SelectedFile } from '@/hooks/useFileSelector';
|
||||
|
||||
export type AppPlatform = 'web' | 'tauri' | 'node';
|
||||
export type OsPlatform = 'android' | 'ios' | 'macos' | 'windows' | 'linux' | 'unknown';
|
||||
// prettier-ignore
|
||||
// biome-ignore format: keep the union members compact on a single line
|
||||
export type BaseDir = | 'Books' | 'Settings' | 'Data' | 'Fonts' | 'Images' | 'Dictionaries' | 'Log' | 'Cache' | 'Temp' | 'None';
|
||||
export type DeleteAction = 'cloud' | 'local' | 'both';
|
||||
export type SelectDirectoryMode = 'read' | 'write';
|
||||
|
||||
@@ -112,7 +112,7 @@ export const flattenContributors = (
|
||||
: formatLanguageMap(contributors?.name);
|
||||
};
|
||||
|
||||
// prettier-ignore
|
||||
// biome-ignore format: keep the language codes compact on a single line
|
||||
const LASTNAME_AUTHOR_SORT_LANGS = [ 'ar', 'bo', 'de', 'en', 'es', 'fr', 'hi', 'it', 'nl', 'pl', 'pt', 'ru', 'th', 'tr', 'uk' ];
|
||||
|
||||
const formatAuthorName = (name: string, lastNameFirst: boolean) => {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*/
|
||||
|
||||
// ISO 639-1 language codes (2-letter codes)
|
||||
// prettier-ignore
|
||||
// biome-ignore format: keep the ISO codes grouped by first letter
|
||||
const ISO_639_1_CODES = new Set([
|
||||
'aa', 'ab', 'ae', 'af', 'ak', 'am', 'an', 'ar', 'as', 'av', 'ay', 'az',
|
||||
'ba', 'be', 'bg', 'bh', 'bi', 'bm', 'bn', 'bo', 'br', 'bs',
|
||||
|
||||
@@ -1,25 +1,68 @@
|
||||
{
|
||||
"$schema": "https://biomejs.dev/schemas/2.4.15/schema.json",
|
||||
"vcs": { "enabled": true, "clientKind": "git", "useIgnoreFile": true },
|
||||
"files": { "ignoreUnknown": true },
|
||||
"formatter": { "enabled": false },
|
||||
"files": {
|
||||
"ignoreUnknown": true,
|
||||
"includes": [
|
||||
"**",
|
||||
"!**/node_modules/**",
|
||||
"!**/packages/**",
|
||||
"!**/.claude/**",
|
||||
"!**/gen/**",
|
||||
"!**/autogenerated/**",
|
||||
"!**/schemas/**"
|
||||
]
|
||||
},
|
||||
"formatter": {
|
||||
"enabled": true,
|
||||
"indentStyle": "space",
|
||||
"indentWidth": 2,
|
||||
"lineWidth": 100,
|
||||
"lineEnding": "lf",
|
||||
"includes": [
|
||||
"**",
|
||||
"!**/.next/**",
|
||||
"!**/.open-next/**",
|
||||
"!**/.build/**",
|
||||
"!**/.tauri/**",
|
||||
"!**/.wrangler/**",
|
||||
"!**/.vercel/**",
|
||||
"!**/out/**",
|
||||
"!**/build/**",
|
||||
"!**/dist/**",
|
||||
"!**/target/**",
|
||||
"!**/fastlane/**",
|
||||
"!apps/readest-app/public/*.js",
|
||||
"!apps/readest-app/public/vendor/**",
|
||||
"!apps/readest-app/src-tauri/plugins/tauri-plugin-turso/**",
|
||||
"!apps/readest-app/src-tauri/plugins/tauri-plugin-webview-upgrade/**",
|
||||
"!**/*.mjs",
|
||||
"!**/*.cjs",
|
||||
"!**/*.mts",
|
||||
"!pnpm-lock.yaml"
|
||||
]
|
||||
},
|
||||
"assist": { "enabled": false },
|
||||
"css": { "linter": { "enabled": false } },
|
||||
"css": {
|
||||
"parser": { "tailwindDirectives": true },
|
||||
"linter": { "enabled": false },
|
||||
"formatter": { "enabled": true, "quoteStyle": "single" }
|
||||
},
|
||||
"linter": {
|
||||
"enabled": true,
|
||||
"includes": [
|
||||
"**",
|
||||
"!.next/**",
|
||||
"!.open-next/**",
|
||||
"!.wrangler/**",
|
||||
"!.claude/**",
|
||||
"!dist/**",
|
||||
"!out/**",
|
||||
"!build/**",
|
||||
"!public/**",
|
||||
"!src-tauri/**",
|
||||
"!next-env.d.ts",
|
||||
"!i18next-scanner.config.cjs"
|
||||
"!apps/readest-app/.next/**",
|
||||
"!apps/readest-app/.open-next/**",
|
||||
"!apps/readest-app/.wrangler/**",
|
||||
"!apps/readest-app/.claude/**",
|
||||
"!apps/readest-app/dist/**",
|
||||
"!apps/readest-app/out/**",
|
||||
"!apps/readest-app/build/**",
|
||||
"!apps/readest-app/public/**",
|
||||
"!apps/readest-app/src-tauri/**",
|
||||
"!apps/readest-app/next-env.d.ts",
|
||||
"!apps/readest-app/i18next-scanner.config.cjs"
|
||||
],
|
||||
"rules": {
|
||||
"recommended": true,
|
||||
@@ -120,6 +163,12 @@
|
||||
}
|
||||
},
|
||||
"javascript": {
|
||||
"globals": ["React"]
|
||||
"globals": ["React"],
|
||||
"formatter": {
|
||||
"quoteStyle": "single",
|
||||
"jsxQuoteStyle": "single",
|
||||
"trailingCommas": "all",
|
||||
"semicolons": "always"
|
||||
}
|
||||
}
|
||||
}
|
||||
+4
-6
@@ -12,8 +12,8 @@
|
||||
"prepare": "husky",
|
||||
"fmt:check": "pnpm --filter @readest/readest-app fmt:check",
|
||||
"clippy:check": "pnpm --filter @readest/readest-app clippy:check",
|
||||
"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}\""
|
||||
"format": "biome format --write .",
|
||||
"format:check": "biome format ."
|
||||
},
|
||||
"packageManager": "pnpm@11.1.1",
|
||||
"devDependencies": {
|
||||
@@ -21,13 +21,11 @@
|
||||
"@sindresorhus/tsconfig": "^6.0.0",
|
||||
"husky": "^9.1.6",
|
||||
"lint-staged": "^16.2.7",
|
||||
"prettier": "^3.3.3",
|
||||
"prettier-plugin-tailwindcss": "^0.6.8",
|
||||
"typescript": "^5"
|
||||
},
|
||||
"lint-staged": {
|
||||
"**/*.{js,jsx,ts,tsx,css,json,md,html,yml}": [
|
||||
"prettier --write"
|
||||
"**/*.{js,jsx,ts,tsx,css,json}": [
|
||||
"biome format --write --no-errors-on-unmatched"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
Generated
-78
@@ -52,12 +52,6 @@ importers:
|
||||
lint-staged:
|
||||
specifier: ^16.2.7
|
||||
version: 16.4.0
|
||||
prettier:
|
||||
specifier: ^3.3.3
|
||||
version: 3.8.3
|
||||
prettier-plugin-tailwindcss:
|
||||
specifier: ^0.6.8
|
||||
version: 0.6.14(prettier@3.8.3)
|
||||
typescript:
|
||||
specifier: ^5
|
||||
version: 5.9.3
|
||||
@@ -7072,72 +7066,6 @@ packages:
|
||||
preact@10.29.1:
|
||||
resolution: {integrity: sha512-gQCLc/vWroE8lIpleXtdJhTFDogTdZG9AjMUpVkDf2iTCNwYNWA+u16dL41TqUDJO4gm2IgrcMv3uTpjd4Pwmg==}
|
||||
|
||||
prettier-plugin-tailwindcss@0.6.14:
|
||||
resolution: {integrity: sha512-pi2e/+ZygeIqntN+vC573BcW5Cve8zUB0SSAGxqpB4f96boZF4M3phPVoOFCeypwkpRYdi7+jQ5YJJUwrkGUAg==}
|
||||
engines: {node: '>=14.21.3'}
|
||||
peerDependencies:
|
||||
'@ianvs/prettier-plugin-sort-imports': '*'
|
||||
'@prettier/plugin-hermes': '*'
|
||||
'@prettier/plugin-oxc': '*'
|
||||
'@prettier/plugin-pug': '*'
|
||||
'@shopify/prettier-plugin-liquid': '*'
|
||||
'@trivago/prettier-plugin-sort-imports': '*'
|
||||
'@zackad/prettier-plugin-twig': '*'
|
||||
prettier: ^3.0
|
||||
prettier-plugin-astro: '*'
|
||||
prettier-plugin-css-order: '*'
|
||||
prettier-plugin-import-sort: '*'
|
||||
prettier-plugin-jsdoc: '*'
|
||||
prettier-plugin-marko: '*'
|
||||
prettier-plugin-multiline-arrays: '*'
|
||||
prettier-plugin-organize-attributes: '*'
|
||||
prettier-plugin-organize-imports: '*'
|
||||
prettier-plugin-sort-imports: '*'
|
||||
prettier-plugin-style-order: '*'
|
||||
prettier-plugin-svelte: '*'
|
||||
peerDependenciesMeta:
|
||||
'@ianvs/prettier-plugin-sort-imports':
|
||||
optional: true
|
||||
'@prettier/plugin-hermes':
|
||||
optional: true
|
||||
'@prettier/plugin-oxc':
|
||||
optional: true
|
||||
'@prettier/plugin-pug':
|
||||
optional: true
|
||||
'@shopify/prettier-plugin-liquid':
|
||||
optional: true
|
||||
'@trivago/prettier-plugin-sort-imports':
|
||||
optional: true
|
||||
'@zackad/prettier-plugin-twig':
|
||||
optional: true
|
||||
prettier-plugin-astro:
|
||||
optional: true
|
||||
prettier-plugin-css-order:
|
||||
optional: true
|
||||
prettier-plugin-import-sort:
|
||||
optional: true
|
||||
prettier-plugin-jsdoc:
|
||||
optional: true
|
||||
prettier-plugin-marko:
|
||||
optional: true
|
||||
prettier-plugin-multiline-arrays:
|
||||
optional: true
|
||||
prettier-plugin-organize-attributes:
|
||||
optional: true
|
||||
prettier-plugin-organize-imports:
|
||||
optional: true
|
||||
prettier-plugin-sort-imports:
|
||||
optional: true
|
||||
prettier-plugin-style-order:
|
||||
optional: true
|
||||
prettier-plugin-svelte:
|
||||
optional: true
|
||||
|
||||
prettier@3.8.3:
|
||||
resolution: {integrity: sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==}
|
||||
engines: {node: '>=14'}
|
||||
hasBin: true
|
||||
|
||||
pretty-bytes@6.1.1:
|
||||
resolution: {integrity: sha512-mQUvGU6aUFQ+rNvTIAcZuWGRT9a6f6Yrg9bHs4ImKF+HZCEK+plBvnAZYSIQztknZF2qnzNtr6F8s0+IuptdlQ==}
|
||||
engines: {node: ^14.13.1 || >=16.0.0}
|
||||
@@ -16113,12 +16041,6 @@ snapshots:
|
||||
|
||||
preact@10.29.1: {}
|
||||
|
||||
prettier-plugin-tailwindcss@0.6.14(prettier@3.8.3):
|
||||
dependencies:
|
||||
prettier: 3.8.3
|
||||
|
||||
prettier@3.8.3: {}
|
||||
|
||||
pretty-bytes@6.1.1: {}
|
||||
|
||||
pretty-format@27.5.1:
|
||||
|
||||
Reference in New Issue
Block a user