mirror of
https://github.com/johannesjo/super-productivity.git
synced 2026-07-17 16:37:43 +00:00
* fix(sync): guard unprotected selector-based effects against sync replay Add skipWhileApplyingRemoteOps() guards to selector-based effects that were missing hydration protection, preventing unwanted side effects during sync/hydration replay: - tag.effects.ts: cleanupNullTasksForTaskList$ (hidden dispatch via tagService.updateTag inside tap) - reminder-countdown.effects.ts: reminderCountdownBanner$ (banner flash) - voice-reminder.effects.ts: dominaMode$ (unwanted TTS) - task-ui.effects.ts: timeEstimateExceeded$ and timeEstimateExceededDismissBanner$ (unwanted notifications/banners) Also enable the existing require-hydration-guard ESLint rule in eslint.config.js (scoped to *.effects.ts files) to prevent future regressions. The rule was already written but never wired into the linting pipeline. https://claude.ai/code/session_01WcAdr12nsvLdAjubLx1ZLf * fix: address PR review feedback for selector effects guards - Fix require-hydration-guard.spec.js for ESLint v9 (parserOptions → languageOptions) - Upgrade require-hydration-guard severity from warn to error - Restore require-entity-registry rule (also lost in ESLint v9 migration) - Remove unrelated package-lock.json noise https://claude.ai/code/session_01WcAdr12nsvLdAjubLx1ZLf --------- Co-authored-by: Claude <noreply@anthropic.com>
139 lines
4.4 KiB
JavaScript
139 lines
4.4 KiB
JavaScript
// @ts-check
|
|
const tseslint = require('typescript-eslint');
|
|
const angular = require('angular-eslint');
|
|
const prettierRecommended = require('eslint-plugin-prettier/recommended');
|
|
const preferArrow = require('eslint-plugin-prefer-arrow');
|
|
const localRules = require('eslint-plugin-local-rules');
|
|
|
|
module.exports = tseslint.config(
|
|
// Global ignores
|
|
{
|
|
ignores: [
|
|
'app-builds/**/*',
|
|
'dist/**',
|
|
'node_modules/**/*',
|
|
'src/app/t.const.ts',
|
|
'src/assets/bundled-plugins/**/*',
|
|
'src/app/config/env.generated.ts',
|
|
'.tmp/**/*',
|
|
'packages/**/*',
|
|
],
|
|
},
|
|
// TypeScript files
|
|
{
|
|
files: ['**/*.ts'],
|
|
extends: [
|
|
...tseslint.configs.recommended,
|
|
...angular.configs.tsRecommended,
|
|
prettierRecommended,
|
|
],
|
|
processor: angular.processInlineTemplates,
|
|
plugins: {
|
|
'prefer-arrow': preferArrow,
|
|
},
|
|
languageOptions: {
|
|
parserOptions: {
|
|
ecmaVersion: 2020,
|
|
sourceType: 'module',
|
|
},
|
|
},
|
|
rules: {
|
|
// Disabled rules
|
|
'@typescript-eslint/no-explicit-any': 'off',
|
|
'@typescript-eslint/ban-ts-comment': 'off',
|
|
'@typescript-eslint/no-empty-function': 'off',
|
|
'@typescript-eslint/explicit-module-boundary-types': 'off',
|
|
'@angular-eslint/component-selector': 'off',
|
|
'@angular-eslint/no-input-rename': 'off',
|
|
'@typescript-eslint/no-inferrable-types': 'off',
|
|
'no-underscore-dangle': 'off',
|
|
'arrow-body-style': 'off',
|
|
'@typescript-eslint/member-ordering': 'off',
|
|
'import/order': 'off',
|
|
'arrow-parens': 'off',
|
|
'@typescript-eslint/explicit-member-accessibility': 'off',
|
|
|
|
// Enabled rules
|
|
'prettier/prettier': 'error',
|
|
'@typescript-eslint/no-unused-vars': [
|
|
'error',
|
|
{ args: 'none', caughtErrors: 'none' },
|
|
],
|
|
'@typescript-eslint/explicit-function-return-type': [
|
|
'error',
|
|
{
|
|
allowExpressions: true,
|
|
allowTypedFunctionExpressions: true,
|
|
allowHigherOrderFunctions: true,
|
|
allowDirectConstAssertionInArrowFunctions: true,
|
|
allowConciseArrowFunctionExpressionsStartingWithVoid: true,
|
|
},
|
|
],
|
|
'@typescript-eslint/naming-convention': [
|
|
'error',
|
|
{
|
|
selector: 'default',
|
|
format: ['camelCase', 'snake_case', 'UPPER_CASE', 'PascalCase'],
|
|
leadingUnderscore: 'allowSingleOrDouble',
|
|
trailingUnderscore: 'allow',
|
|
filter: { regex: '(should)|@tags', match: false },
|
|
},
|
|
{
|
|
selector: 'variable',
|
|
format: ['camelCase', 'snake_case', 'UPPER_CASE', 'PascalCase'],
|
|
leadingUnderscore: 'allowSingleOrDouble',
|
|
trailingUnderscore: 'allow',
|
|
},
|
|
{ selector: 'enum', format: ['PascalCase', 'UPPER_CASE'] },
|
|
{ selector: 'typeLike', format: ['PascalCase'] },
|
|
],
|
|
'prefer-const': 'error',
|
|
'@typescript-eslint/no-unused-expressions': 'error',
|
|
'@typescript-eslint/no-empty-object-type': 'error',
|
|
'max-len': [
|
|
'error',
|
|
{
|
|
ignorePattern: '^import \\{.+;$',
|
|
ignoreRegExpLiterals: true,
|
|
ignoreStrings: true,
|
|
ignoreUrls: true,
|
|
code: 150,
|
|
},
|
|
],
|
|
'id-blacklist': 'error',
|
|
// @typescript-eslint/member-delimiter-style removed in v8 - Prettier handles this
|
|
'no-shadow': 'off',
|
|
'@typescript-eslint/no-shadow': 'error',
|
|
'comma-dangle': ['error', 'always-multiline'],
|
|
'no-mixed-operators': 'error',
|
|
'prefer-arrow/prefer-arrow-functions': 'error',
|
|
'@angular-eslint/directive-selector': [
|
|
'error',
|
|
{ type: 'attribute', prefix: '', style: 'camelCase' },
|
|
],
|
|
// @typescript-eslint/ban-types replaced by specific rules in v8
|
|
'@typescript-eslint/no-unsafe-function-type': 'error',
|
|
'@typescript-eslint/no-wrapper-object-types': 'error',
|
|
},
|
|
},
|
|
// NgRx effects files - require hydration guards on selector-based effects
|
|
{
|
|
files: ['**/*.effects.ts'],
|
|
plugins: {
|
|
'local-rules': localRules,
|
|
},
|
|
rules: {
|
|
'local-rules/require-hydration-guard': 'error',
|
|
'local-rules/require-entity-registry': 'warn',
|
|
},
|
|
},
|
|
// HTML files
|
|
{
|
|
files: ['**/*.html'],
|
|
extends: [...angular.configs.templateRecommended, prettierRecommended],
|
|
rules: {
|
|
'@angular-eslint/template/no-negated-async': 'off',
|
|
'prettier/prettier': 'error',
|
|
},
|
|
},
|
|
);
|