eslint@9, prettier (#105)

* Update build.yml to allow pushes to any branch

Remove branch restriction for push events, which prevents forked projects from running CI checks prior to creating a PR.

* eslint, prettier config only
This commit is contained in:
Scott Anderson
2026-08-02 02:43:54 -04:00
committed by GitHub
parent 2e0ff5a10c
commit 9478f7d0f5
15 changed files with 2352 additions and 2124 deletions

View File

@@ -1,36 +0,0 @@
module.exports = {
root: true,
env: { browser: true, es2020: true },
extends: [
'eslint:recommended',
'plugin:react/recommended',
'plugin:react/jsx-runtime',
'plugin:react-hooks/recommended',
'plugin:prettier/recommended',
'plugin:tailwindcss/recommended',
],
ignorePatterns: [
'dist',
'.eslintrc.cjs',
'tailwind.config.js',
'postcss.config.js',
],
parserOptions: { ecmaVersion: 'latest', sourceType: 'module' },
settings: { react: { version: '18.2' } },
plugins: [
'react-refresh',
'simple-import-sort',
'sort-destructure-keys',
'sort-keys-fix',
'prettier',
'tailwindcss',
],
rules: {
'react-refresh/only-export-components': [
'warn',
{ allowConstantExport: true },
],
'react/prop-types': 'off',
},
}

View File

@@ -18,3 +18,4 @@ jobs:
- name: Install dependencies - name: Install dependencies
run: npm i run: npm i
- run: npm run build - run: npm run build
- run: npm run lint:ci

2
.prettierignore Normal file
View File

@@ -0,0 +1,2 @@
LICENSE.md
dist/

View File

@@ -1,13 +0,0 @@
{
"arrowParens": "avoid",
"bracketSpacing": true,
"endOfLine": "auto",
"jsxBracketSameLine": false,
"printWidth": 80,
"semi": false,
"singleQuote": true,
"jsxSingleQuote": true,
"tabWidth": 2,
"trailingComma": "all",
"plugins": ["prettier-plugin-tailwindcss"]
}

187
eslint.config.mjs Normal file
View File

@@ -0,0 +1,187 @@
import js from '@eslint/js'
import stylistic from '@stylistic/eslint-plugin'
import queryPlugin from '@tanstack/eslint-plugin-query'
import typescriptEslint from '@typescript-eslint/eslint-plugin'
import tsParser from '@typescript-eslint/parser'
import eslintConfigPrettier from 'eslint-config-prettier/flat'
import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended'
import react from 'eslint-plugin-react'
import reactHooks from 'eslint-plugin-react-hooks'
import reactRefresh from 'eslint-plugin-react-refresh'
import simpleImportSort from 'eslint-plugin-simple-import-sort'
import sortDestructureKeys from 'eslint-plugin-sort-destructure-keys'
import tailwind from 'eslint-plugin-tailwindcss'
import globals from 'globals'
export default [
{
ignores: ['dist'],
},
js.configs.recommended,
react.configs.flat.recommended,
{
...react.configs.flat['jsx-runtime'],
settings: {
react: {
version: 'detect',
},
},
},
reactHooks.configs.flat.recommended,
reactRefresh.configs.recommended,
{
plugins: {
'simple-import-sort': simpleImportSort,
},
rules: {
'simple-import-sort/exports': 'error',
'simple-import-sort/imports': 'error',
},
},
{
plugins: {
'sort-destructure-keys': sortDestructureKeys,
},
rules: {
'sort-destructure-keys/sort-destructure-keys': 'error',
},
},
...tailwind.configs['flat/recommended'],
...queryPlugin.configs['flat/recommended'],
eslintConfigPrettier, // Disable any rules that conflict with prettier
eslintPluginPrettierRecommended,
{
files: ['*.{js,ts}'],
languageOptions: {
globals: globals.node,
},
},
{
files: ['*.config.{mjs,ts}'],
languageOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
},
rules: {
eqeqeq: 'error',
indent: ['error', 2],
'space-infix-ops': ['error', { int32Hint: false }],
},
},
{
files: ['src/**/*.{js,jsx,ts,tsx}'],
languageOptions: {
ecmaVersion: 'latest',
globals: globals.browser,
sourceType: 'module',
},
plugins: {
'@stylistic': stylistic,
},
rules: {
'@stylistic/brace-style': 'error',
'@stylistic/comma-dangle': ['error', 'always-multiline'],
'@stylistic/keyword-spacing': 'error',
'@stylistic/no-multiple-empty-lines': ['error', { max: 1 }],
'@stylistic/no-trailing-spaces': 'error',
'@stylistic/object-curly-spacing': ['error', 'always'],
'@stylistic/semi': ['error', 'never'],
'@stylistic/space-in-parens': 'error',
'@stylistic/space-infix-ops': ['error', { int32Hint: false }],
'@stylistic/type-annotation-spacing': [
'error',
{
after: true,
before: true,
overrides: {
colon: {
before: false,
},
},
},
],
eqeqeq: 'warn',
'max-depth': ['error', { max: 5 }],
'max-len': ['warn', { code: 120 }],
'max-lines': [
'error',
{ max: 2000, skipBlankLines: true, skipComments: true },
],
'max-lines-per-function': ['warn', { max: 500 }],
'no-constant-condition': 'warn',
'no-loss-of-precision': 'error',
'no-undef': 'warn',
'no-unused-vars': 'off', // @typescript-eslint/no-unused-vars
'space-infix-ops': 'off', // @stylistic/space-infix-ops
},
},
{
files: ['*.{ts,tsx}'],
languageOptions: {
parser: tsParser,
parserOptions: {
project: 'tsconfig.json',
},
},
plugins: {
'@typescript-eslint': typescriptEslint,
},
rules: {
'@typescript-eslint/consistent-type-definitions': ['error', 'type'],
'@typescript-eslint/no-duplicate-enum-values': 'error',
'@typescript-eslint/no-explicit-any': 'error',
'@typescript-eslint/no-inferrable-types': 'error',
'@typescript-eslint/no-mixed-enums': 'error',
'@typescript-eslint/no-require-imports': 'error',
'@typescript-eslint/no-type-alias': [
'error',
{
allowAliases: 'always',
allowCallbacks: 'always',
allowConditionalTypes: 'never',
allowConstructors: 'never',
allowGenerics: 'always',
allowLiterals: 'always',
allowMappedTypes: 'never',
allowTupleTypes: 'always',
},
],
'@typescript-eslint/no-unnecessary-type-assertion': 'error',
'@typescript-eslint/no-unsafe-argument': 'warn',
'@typescript-eslint/no-unsafe-assignment': 'warn',
'@typescript-eslint/no-unsafe-member-access': 'warn',
'@typescript-eslint/no-unused-vars': [
'warn',
{ argsIgnorePattern: '^_' },
],
'@typescript-eslint/prefer-as-const': 'error',
'@typescript-eslint/prefer-for-of': 'warn',
'@typescript-eslint/prefer-function-type': 'error',
'@typescript-eslint/prefer-includes': 'error',
'@typescript-eslint/prefer-literal-enum-member': 'error',
'@typescript-eslint/prefer-nullish-coalescing': 'warn',
},
},
{
// Reduce existing errors to warnings
plugins: {
'@tanstack/query': queryPlugin,
},
rules: {
'@tanstack/query/exhaustive-deps': 'warn',
'no-case-declarations': 'warn',
'no-empty': 'warn',
'no-redeclare': 'warn',
'react-hooks/immutability': 'warn',
'react-hooks/preserve-manual-memoization': 'warn',
'react-hooks/purity': 'warn',
'react-hooks/refs': 'warn',
'react-hooks/set-state-in-effect': 'warn',
'react-hooks/static-components': 'warn',
'react-refresh/only-export-components': 'warn',
'react/jsx-no-undef': 'warn',
'react/no-unescaped-entities': 'warn',
'react/prop-types': 'warn',
},
},
]

4058
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -20,7 +20,9 @@
"build-cf": "rm -rf package-lock.json && npm install && npm install --force @rollup/rollup-linux-x64-gnu@4.34.9 @swc/core-linux-x64-gnu && vite build", "build-cf": "rm -rf package-lock.json && npm install && npm install --force @rollup/rollup-linux-x64-gnu@4.34.9 @swc/core-linux-x64-gnu && vite build",
"build-selfhosted": "rm -rf package-lock.json && npm install && npm install --force @rollup/rollup-linux-x64-gnu@4.34.9 @swc/core-linux-x64-gnu && vite build --mode selfhosted", "build-selfhosted": "rm -rf package-lock.json && npm install && npm install --force @rollup/rollup-linux-x64-gnu@4.34.9 @swc/core-linux-x64-gnu && vite build --mode selfhosted",
"build-win": "del package-lock.json && npm install && npm install --force @rollup/rollup-win32-x64-msvc @swc/core-win32-x64-msvc && vite build --mode selfhosted", "build-win": "del package-lock.json && npm install && npm install --force @rollup/rollup-win32-x64-msvc @swc/core-win32-x64-msvc && vite build --mode selfhosted",
"lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0", "lint": "eslint && prettier -c .",
"lint:ci": "true # TODO: eslint -f gha && prettier -c .",
"lint:fix": "eslint --fix && prettier -w .",
"preview": "vite preview", "preview": "vite preview",
"setup-m1": "rm -rf node_modules package-lock.json && npm install && npm install --force @rollup/rollup-darwin-arm64 @swc/core-darwin-arm64", "setup-m1": "rm -rf node_modules package-lock.json && npm install && npm install --force @rollup/rollup-darwin-arm64 @swc/core-darwin-arm64",
"setup-apple-silicon": "npm install --no-optional && npm install --force @rollup/rollup-darwin-arm64 @swc/core-darwin-arm64", "setup-apple-silicon": "npm install --no-optional && npm install --force @rollup/rollup-darwin-arm64 @swc/core-darwin-arm64",
@@ -71,8 +73,11 @@
"@openreplay/tracker": "^14.0.4", "@openreplay/tracker": "^14.0.4",
"@revenuecat/purchases-capacitor": "^12.0.0", "@revenuecat/purchases-capacitor": "^12.0.0",
"@revenuecat/purchases-capacitor-ui": "^12.0.0", "@revenuecat/purchases-capacitor-ui": "^12.0.0",
"@stylistic/eslint-plugin": "^5.10.0",
"@swc/core": "^1.12.5", "@swc/core": "^1.12.5",
"@tanstack/react-query": "^5.17.0", "@tanstack/react-query": "^5.17.0",
"@typescript-eslint/eslint-plugin": "^8.59.4",
"@typescript-eslint/parser": "^8.59.4",
"aos": "^2.3.4", "aos": "^2.3.4",
"browser-image-compression": "^2.0.2", "browser-image-compression": "^2.0.2",
"caniuse-lite": "^1.0.30001769", "caniuse-lite": "^1.0.30001769",
@@ -116,20 +121,20 @@
"autoprefixer": "^10.4.16", "autoprefixer": "^10.4.16",
"baseline-browser-mapping": "^2.9.19", "baseline-browser-mapping": "^2.9.19",
"capacitor-set-version": "^2.2.0", "capacitor-set-version": "^2.2.0",
"eslint": "^8.56.0", "eslint": "^9.39.4",
"eslint-config-prettier": "^9.1.0", "eslint-config-prettier": "^10.1.8",
"eslint-plugin-prettier": "^5.1.2", "eslint-formatter-gha": "^2.0.1",
"eslint-plugin-react": "^7.33.2", "eslint-plugin-prettier": "^5.5.6",
"eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react": "^7.37.5",
"eslint-plugin-react-refresh": "^0.4.5", "eslint-plugin-react-hooks": "^7.1.1",
"eslint-plugin-simple-import-sort": "^10.0.0", "eslint-plugin-react-refresh": "^0.5.2",
"eslint-plugin-sort-destructure-keys": "^1.5.0", "eslint-plugin-simple-import-sort": "^13.0.0",
"eslint-plugin-sort-keys-fix": "^1.1.2", "eslint-plugin-sort-destructure-keys": "^3.0.0",
"eslint-plugin-tailwindcss": "^3.13.1", "eslint-plugin-tailwindcss": "^3.18.3",
"husky": "^8.0.3", "husky": "^8.0.3",
"patch-package": "^8.0.1", "patch-package": "^8.0.1",
"postcss": "^8.4.32", "postcss": "^8.4.32",
"prettier": "^3.1.1", "prettier": "^3.8.3",
"prettier-plugin-tailwindcss": "^0.5.10", "prettier-plugin-tailwindcss": "^0.5.10",
"tailwindcss": "^3.4.0", "tailwindcss": "^3.4.0",
"typescript": "^5.8.0", "typescript": "^5.8.0",

View File

@@ -1,6 +1,6 @@
export default { export default {
plugins: { plugins: {
tailwindcss: {},
autoprefixer: {}, autoprefixer: {},
tailwindcss: {},
}, },
} }

13
prettier.config.mjs Normal file
View File

@@ -0,0 +1,13 @@
export default {
arrowParens: 'avoid',
bracketSpacing: true,
endOfLine: 'auto',
jsxBracketSameLine: false,
jsxSingleQuote: true,
plugins: ['prettier-plugin-tailwindcss'],
printWidth: 80,
semi: false,
singleQuote: true,
tabWidth: 2,
trailingComma: 'all',
}

View File

@@ -1,4 +1,3 @@
/* eslint-env node */
export const API_URL = export const API_URL =
import.meta.env.VITE_APP_API_URL === 'AUTO' import.meta.env.VITE_APP_API_URL === 'AUTO'
? `${window.location.hostname}/api` ? `${window.location.hostname}/api`

View File

@@ -1,5 +1,6 @@
import resolveConfig from 'tailwindcss/resolveConfig' import resolveConfig from 'tailwindcss/resolveConfig'
import tailwindConfig from '/tailwind.config.js'
import tailwindConfig from '/tailwind.config.mjs'
export const { theme: THEME } = resolveConfig(tailwindConfig) export const { theme: THEME } = resolveConfig(tailwindConfig)

View File

@@ -105,8 +105,10 @@ const TermsView = () => {
</ul> </ul>
<h2>5. Acceptable Use Policy</h2> <h2>5. Acceptable Use Policy</h2>
<p><em>Applies to both Cloud and Self-Hosted Services</em></p> <p>
<em>Applies to both Cloud and Self-Hosted Services</em>
</p>
<h3>You may not use our services to:</h3> <h3>You may not use our services to:</h3>
<ul> <ul>
<li>Violate any applicable laws or regulations</li> <li>Violate any applicable laws or regulations</li>

View File

@@ -3,11 +3,11 @@ export default {
corePlugins: { corePlugins: {
preflight: false, preflight: false,
}, },
darkMode: 'class',
plugins: [],
theme: { theme: {
extend: { extend: {
colors: {}, colors: {},
}, },
}, },
darkMode: 'class',
plugins: [],
} }

37
tsconfig.json Normal file
View File

@@ -0,0 +1,37 @@
// https://www.typescriptlang.org/tsconfig/
{
"compilerOptions": {
// Type Checking
"allowUnreachableCode": false,
"allowUnusedLabels": false,
"alwaysStrict": true,
"exactOptionalPropertyTypes": true,
"noFallthroughCasesInSwitch": true,
"noImplicitAny": true,
"noImplicitOverride": true,
"noImplicitReturns": true,
"noImplicitThis": true,
"noPropertyAccessFromIndexSignature": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"strict": true,
"strictBindCallApply": true,
"strictFunctionTypes": true,
"strictNullChecks": true,
"strictPropertyInitialization": true,
"useUnknownInCatchVariables": true,
// Modules
"module": "nodenext",
"moduleResolution": "nodenext",
"rootDir": "src",
// Emit
"outDir": "dist",
"sourceMap": true,
"sourceRoot": "./src/",
// Language and Environment
"target": "ES2020"
}
}

View File

@@ -6,7 +6,6 @@ export default defineConfig({
plugins: [ plugins: [
react(), react(),
VitePWA({ VitePWA({
registerType: 'prompt',
includeAssets: [ includeAssets: [
'favicon.ico', 'favicon.ico',
'robots.txt', 'robots.txt',
@@ -15,59 +14,60 @@ export default defineConfig({
'mstile-150x150.png', 'mstile-150x150.png',
], ],
injectManifest: { injectManifest: {
globPatterns: ['**/*.{js,css,html,png,svg}'],
globIgnores: ['index.html'], globIgnores: ['index.html'],
globPatterns: ['**/*.{js,css,html,png,svg}'],
}, },
manifest: { manifest: {
name: 'Donetick: Simplify Tasks & Chores, Together.',
short_name: 'Donetick',
icons: [
{
src: '/android-chrome-192x192.png',
sizes: '192x192',
type: 'image/png',
},
{
src: '/android-chrome-512x512.png',
sizes: '512x512',
type: 'image/png',
},
{
src: 'pwa-64x64.png',
sizes: '64x64',
type: 'image/png',
},
{
src: 'pwa-192x192.png',
sizes: '192x192',
type: 'image/png',
},
{
src: 'pwa-512x512.png',
sizes: '512x512',
type: 'image/png',
},
{
src: 'maskable-icon-512x512.png',
sizes: '512x512',
type: 'image/png',
purpose: 'maskable',
},
],
theme_color: '#ffffff',
background_color: '#ffffff', background_color: '#ffffff',
display: 'standalone', display: 'standalone',
icons: [
{
sizes: '192x192',
src: '/android-chrome-192x192.png',
type: 'image/png',
},
{
sizes: '512x512',
src: '/android-chrome-512x512.png',
type: 'image/png',
},
{
sizes: '64x64',
src: 'pwa-64x64.png',
type: 'image/png',
},
{
sizes: '192x192',
src: 'pwa-192x192.png',
type: 'image/png',
},
{
sizes: '512x512',
src: 'pwa-512x512.png',
type: 'image/png',
},
{
purpose: 'maskable',
sizes: '512x512',
src: 'maskable-icon-512x512.png',
type: 'image/png',
},
],
name: 'Donetick: Simplify Tasks & Chores, Together.',
short_name: 'Donetick',
theme_color: '#ffffff',
}, },
registerType: 'prompt',
workbox: { workbox: {
skipWaiting: true, // Force the waiting service worker to become the active service worker
clientsClaim: true, // Take control of uncontrolled clients as soon as the service worker becomes active clientsClaim: true, // Take control of uncontrolled clients as soon as the service worker becomes active
maximumFileSizeToCacheInBytes: 6000000, // 6MB maximumFileSizeToCacheInBytes: 6000000, // 6MB
//Exclude API and Swagger routes from service worker navigation fallback //Exclude API and Swagger routes from service worker navigation fallback
navigateFallback: '/index.html', navigateFallback: '/index.html',
navigateFallbackDenylist: [ navigateFallbackDenylist: [
/^\/api\//, // Exclude all API routes /^\/api\//, // Exclude all API routes
/^\/swagger/, // Exclude all Swagger routes /^\/swagger/, // Exclude all Swagger routes
] ],
skipWaiting: true, // Force the waiting service worker to become the active service worker
}, },
}), }),
], ],