| /* |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| // ESLint 9 flat config (migrated from .eslintrc.json during the Angular 20 |
| // line). angular-eslint / typescript-eslint meta-packages provide the flat |
| // presets; the rule set below is a 1:1 port of the previous eslintrc rules. |
| const angular = require('angular-eslint'); |
| const tseslint = require('typescript-eslint'); |
| const importPlugin = require('eslint-plugin-import'); |
| const jsdoc = require('eslint-plugin-jsdoc'); |
| const preferArrow = require('eslint-plugin-prefer-arrow'); |
| const prettier = require('eslint-config-prettier'); |
| // Local plugin: the Angular-specific constructor-params-order rule reimplemented |
| // from the former TSLint rule (ZEPPELIN-6372). |
| const localRules = require('./eslint-rules'); |
| const perfectionist = require('eslint-plugin-perfectionist'); |
| const playwright = require('eslint-plugin-playwright'); |
| const vitest = require('@vitest/eslint-plugin'); |
| |
| module.exports = tseslint.config( |
| { |
| // Build output, vendored binaries and the React sub-app are never linted. |
| ignores: ['dist/**', 'target/**', '.angular/**', 'coverage/**', 'node/**', 'projects/zeppelin-react/**'] |
| }, |
| { |
| // Fail (not just warn) on eslint-disable directives that no longer suppress |
| // anything. The flat-config default is 'warn', and `ng lint` exits 0 on |
| // warnings, so stale directives would otherwise accumulate unnoticed -- |
| // promoting to 'error' keeps the ZEPPELIN-6426 cleanup enforced. |
| linterOptions: { reportUnusedDisableDirectives: 'error' } |
| }, |
| { |
| files: ['**/*.{ts,mts}'], |
| // == legacy `plugin:@angular-eslint/recommended` (sets the TS parser and |
| // the @angular-eslint plugin). The @typescript-eslint plugin is registered |
| // separately below because tsRecommended does not bring it in. |
| extends: [...angular.configs.tsRecommended], |
| // == legacy `plugin:@angular-eslint/template/process-inline-templates` |
| processor: angular.processInlineTemplates, |
| languageOptions: { |
| parserOptions: { |
| project: true, |
| tsconfigRootDir: __dirname |
| } |
| }, |
| plugins: { |
| '@typescript-eslint': tseslint.plugin, |
| import: importPlugin, |
| jsdoc, |
| 'prefer-arrow': preferArrow, |
| local: localRules |
| }, |
| rules: { |
| '@angular-eslint/component-selector': [ |
| 'error', |
| { type: ['element', 'attribute'], prefix: ['zeppelin'], style: 'kebab-case' } |
| ], |
| '@angular-eslint/directive-selector': ['error', { type: 'attribute', prefix: ['zeppelin'], style: 'kebab-case' }], |
| '@angular-eslint/no-forward-ref': 'off', |
| |
| // OFF since the Angular 16 upgrade. Switching from the removed |
| // ng-cli-compat preset to @angular-eslint `recommended` turned this rule |
| // on, but the app keeps intentionally-empty lifecycle hooks as override |
| // placeholders; flagging them adds noise with no benefit. |
| '@angular-eslint/no-empty-lifecycle-method': 'off', |
| |
| // OFF since the Angular 19 upgrade. v19 flipped the `standalone` default |
| // to true, so `ng update` stamped `standalone: false` onto every |
| // NgModule-declared component/directive/pipe. This app is deliberately |
| // NgModule-based; prefer-standalone (added to the angular-eslint 19 |
| // recommended set) errors on exactly those declarations. Turning it on |
| // would force a full standalone migration -- a separate effort. |
| '@angular-eslint/prefer-standalone': 'off', |
| |
| // OFF since the Angular 20 upgrade. prefer-inject (added to the |
| // angular-eslint 20 recommended set) errors on every constructor-parameter |
| // injection (200+ across the app). Moving to the inject() function is a |
| // large, separate refactor, so the rule stays off for now. |
| '@angular-eslint/prefer-inject': 'off', |
| |
| '@angular-eslint/prefer-output-readonly': 'error', |
| '@typescript-eslint/adjacent-overload-signatures': 'off', |
| '@typescript-eslint/array-type': 'off', |
| '@typescript-eslint/ban-tslint-comment': 'off', |
| '@typescript-eslint/class-literal-property-style': 'off', |
| '@typescript-eslint/consistent-generic-constructors': 'off', |
| '@typescript-eslint/consistent-indexed-object-style': 'off', |
| '@typescript-eslint/consistent-type-assertions': 'off', |
| '@typescript-eslint/consistent-type-definitions': 'off', |
| '@typescript-eslint/no-confusing-non-null-assertion': 'off', |
| '@typescript-eslint/no-empty-function': 'off', |
| '@typescript-eslint/no-inferrable-types': 'off', |
| '@typescript-eslint/prefer-for-of': 'off', |
| '@typescript-eslint/prefer-function-type': 'off', |
| |
| // Replaced the removed `ban-types` rule during the Angular 19 upgrade |
| // (@typescript-eslint 8 split it into these). They keep the original |
| // intent -- ban the Object/String/Number/Boolean wrapper types and the |
| // unsafe `Function` type -- while still allowing `{}`, which ban-types |
| // had recommended as the alternative. |
| '@typescript-eslint/no-wrapper-object-types': 'error', |
| '@typescript-eslint/no-unsafe-function-type': 'error', |
| |
| '@typescript-eslint/member-ordering': 'warn', |
| |
| // Custom rule (reimplemented from TSLint, ZEPPELIN-6372): keep the New UI |
| // constructor parameter order consistent as public -> protected -> private. |
| 'local/constructor-params-order': 'error', |
| |
| '@typescript-eslint/explicit-member-accessibility': ['off', { accessibility: 'explicit' }], |
| '@typescript-eslint/no-explicit-any': 'error', |
| '@typescript-eslint/no-floating-promises': 'off', |
| '@typescript-eslint/no-for-in-array': 'error', |
| '@typescript-eslint/naming-convention': 'off', |
| '@typescript-eslint/no-non-null-assertion': 'off', |
| '@typescript-eslint/no-this-alias': 'error', |
| '@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_', varsIgnorePattern: '^_' }], |
| 'eol-last': 'off', |
| 'import/no-cycle': 'error', |
| 'import/no-deprecated': 'off', |
| 'import/no-unassigned-import': 'error', |
| 'import/order': 'error', |
| 'max-len': 'off', |
| 'new-parens': 'off', |
| 'no-bitwise': 'off', |
| 'no-duplicate-imports': 'error', |
| 'no-invalid-this': 'error', |
| 'no-irregular-whitespace': 'error', |
| 'no-magic-numbers': 'off', |
| 'no-param-reassign': 'error', |
| 'no-redeclare': 'error', |
| 'no-sparse-arrays': 'error', |
| 'no-template-curly-in-string': 'error', |
| 'no-trailing-spaces': 'off', |
| 'no-underscore-dangle': 'off', |
| 'prefer-arrow/prefer-arrow-functions': 'warn', |
| 'prefer-object-spread': 'error', |
| 'prefer-template': 'error', |
| 'quote-props': 'off', |
| 'space-before-function-paren': 'off', |
| yoda: 'error' |
| } |
| }, |
| { |
| // Library projects publish under the `lib` selector prefix, not `zeppelin`. |
| files: ['projects/zeppelin-sdk/**/*.ts', 'projects/zeppelin-visualization/**/*.ts'], |
| rules: { |
| '@angular-eslint/component-selector': ['error', { type: 'element', prefix: 'lib', style: 'kebab-case' }], |
| '@angular-eslint/directive-selector': ['error', { type: 'attribute', prefix: 'lib', style: 'camelCase' }] |
| } |
| }, |
| { |
| // Shell unit specs live outside the Angular build tsconfig, which excludes |
| // *.spec.ts. Point type-aware linting at the spec program explicitly. |
| files: [ |
| 'src/**/*.spec.ts', |
| 'projects/zeppelin-{sdk,visualization}/**/*.spec.ts', |
| 'test/**/*.spec.ts', |
| 'test/test-setup.ts', |
| 'vitest.shell.config.mts' |
| ], |
| languageOptions: { |
| parserOptions: { |
| project: ['./src/tsconfig.spec.json'], |
| tsconfigRootDir: __dirname |
| } |
| } |
| }, |
| { |
| // Catch specs that cannot fail, as eslint-plugin-playwright does for e2e. |
| files: ['src/**/*.spec.ts', 'projects/zeppelin-{sdk,visualization}/**/*.spec.ts', 'test/**/*.spec.ts'], |
| plugins: { vitest }, |
| rules: { |
| 'vitest/expect-expect': 'error', |
| 'vitest/no-conditional-expect': 'error', |
| 'vitest/no-identical-title': 'error', |
| 'vitest/no-standalone-expect': 'error', |
| 'vitest/valid-expect': 'error', |
| 'vitest/valid-describe-callback': 'error', |
| 'vitest/no-disabled-tests': 'warn', |
| 'vitest/no-focused-tests': 'error' |
| } |
| }, |
| { |
| // The shell test setup intentionally loads Zone.js for its side effects. |
| files: ['test/test-setup.ts'], |
| rules: { |
| 'import/no-unassigned-import': 'off' |
| } |
| }, |
| { |
| // ZEPPELIN-6325 / ZEPPELIN-6372: keep public-api.ts barrels alphabetically |
| // ordered by module specifier. Delegated to eslint-plugin-perfectionist |
| // rather than owning a custom statement-reordering fixer. |
| files: ['**/public-api.ts'], |
| plugins: { perfectionist }, |
| rules: { |
| 'perfectionist/sort-exports': 'error' |
| } |
| }, |
| { |
| files: ['e2e/**/*.ts'], |
| ...playwright.configs['flat/recommended'], |
| rules: { |
| ...playwright.configs['flat/recommended'].rules, |
| // Conditionals here gate setup actions for dual-mode UI (auth vs anonymous, an optional welcome modal). |
| // no-conditional-expect stays on: an assertion reached on only one branch passes without running. |
| 'playwright/no-conditional-in-test': 'off', |
| // Interpreter-backed specs skip on process.env.CI deliberately; only an unconditional skip is a leak. |
| 'playwright/no-skipped-test': ['error', { allowConditional: true }], |
| // Autofixable, and the pre-commit hook applies fixes without review. |
| // It rewrites `.not.toBeVisible()` into `.toBeHidden()`; both pass when the locator matches nothing, |
| // but the rewrite reads as a deliberate check, so a dead selector gets harder to spot. |
| 'playwright/no-useless-not': 'off', |
| // Lowered from the preset's error: 13 networkidle waits and 9 extracted-value assertions already exist, |
| // and `ng lint` exits 0 on warnings. |
| 'playwright/prefer-web-first-assertions': 'warn', |
| 'playwright/no-networkidle': 'warn' |
| } |
| }, |
| { |
| files: ['**/*.html'], |
| // == legacy `plugin:@angular-eslint/template/recommended` |
| extends: [...angular.configs.templateRecommended] |
| }, |
| // == legacy root `extends: ["prettier"]`; disables formatting rules that |
| // would conflict with Prettier. Last so it wins. |
| prettier |
| ); |