@elliemae/pui-cli 9.0.0-alpha.1 → 9.0.0-alpha.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/README.md +33 -0
  2. package/dist/cjs/commands/test.js +0 -1
  3. package/dist/cjs/commands/utils.js +4 -4
  4. package/dist/cjs/commands/vitest.js +0 -1
  5. package/dist/cjs/index.cjs +12 -0
  6. package/dist/cjs/index.js +6 -0
  7. package/dist/cjs/lint-config/eslint/common.cjs +1 -1
  8. package/dist/cjs/lint-config/eslint/flat/common.mjs +162 -0
  9. package/dist/cjs/lint-config/eslint/flat/index.mjs +20 -0
  10. package/dist/cjs/lint-config/eslint/flat/non-react-export.mjs +10 -0
  11. package/dist/cjs/lint-config/eslint/flat/non-react.mjs +6 -0
  12. package/dist/cjs/lint-config/eslint/flat/presets.mjs +79 -0
  13. package/dist/cjs/lint-config/eslint/flat/react-export.mjs +7 -0
  14. package/dist/cjs/lint-config/eslint/flat/react.mjs +60 -0
  15. package/dist/cjs/lint-config/eslint/flat/rules.mjs +170 -0
  16. package/dist/cjs/lint-config/eslint/typescript/non-react.cjs +1 -1
  17. package/dist/cjs/lint-config/eslint/typescript/react.cjs +1 -1
  18. package/dist/cjs/monorepo/utils.cjs +2 -2
  19. package/dist/cjs/monorepo/utils.js +1 -1
  20. package/dist/cjs/testing/jest.config.cjs +4 -4
  21. package/dist/cjs/testing/resolver.cjs +1 -1
  22. package/dist/cjs/testing/setup-react-env.js +1 -1
  23. package/dist/cjs/transpile/esbuild.js +1 -1
  24. package/dist/cjs/webpack/csp-plugin.js +2 -4
  25. package/dist/cjs/webpack/prop-types-shim.js +0 -1
  26. package/dist/cjs/webpack/webpack.lib.base.babel.js +0 -8
  27. package/dist/esm/commands/test.js +0 -1
  28. package/dist/esm/commands/utils.js +4 -4
  29. package/dist/esm/commands/vitest.js +0 -1
  30. package/dist/esm/index.cjs +12 -0
  31. package/dist/esm/index.js +12 -0
  32. package/dist/esm/lint-config/eslint/common.cjs +1 -1
  33. package/dist/esm/lint-config/eslint/flat/common.mjs +162 -0
  34. package/dist/esm/lint-config/eslint/flat/index.mjs +20 -0
  35. package/dist/esm/lint-config/eslint/flat/non-react-export.mjs +10 -0
  36. package/dist/esm/lint-config/eslint/flat/non-react.mjs +6 -0
  37. package/dist/esm/lint-config/eslint/flat/presets.mjs +79 -0
  38. package/dist/esm/lint-config/eslint/flat/react-export.mjs +7 -0
  39. package/dist/esm/lint-config/eslint/flat/react.mjs +60 -0
  40. package/dist/esm/lint-config/eslint/flat/rules.mjs +170 -0
  41. package/dist/esm/lint-config/eslint/typescript/non-react.cjs +1 -1
  42. package/dist/esm/lint-config/eslint/typescript/react.cjs +1 -1
  43. package/dist/esm/monorepo/utils.cjs +2 -2
  44. package/dist/esm/monorepo/utils.js +1 -1
  45. package/dist/esm/testing/jest.config.cjs +4 -4
  46. package/dist/esm/testing/resolver.cjs +1 -1
  47. package/dist/esm/testing/setup-react-env.js +1 -1
  48. package/dist/esm/transpile/esbuild.js +1 -1
  49. package/dist/esm/webpack/csp-plugin.js +2 -4
  50. package/dist/esm/webpack/prop-types-shim.js +0 -1
  51. package/dist/esm/webpack/webpack.lib.base.babel.js +0 -8
  52. package/dist/types/lib/commands/build.d.ts +1 -1
  53. package/dist/types/lib/commands/buildcdn.d.ts +1 -1
  54. package/dist/types/lib/commands/codemod.d.ts +1 -1
  55. package/dist/types/lib/commands/gendoc.d.ts +1 -1
  56. package/dist/types/lib/commands/lint.d.ts +1 -1
  57. package/dist/types/lib/commands/pack.d.ts +1 -1
  58. package/dist/types/lib/commands/start.d.ts +1 -1
  59. package/dist/types/lib/commands/storybook.d.ts +1 -1
  60. package/dist/types/lib/commands/test.d.ts +1 -1
  61. package/dist/types/lib/commands/tscheck.d.ts +1 -1
  62. package/dist/types/lib/commands/version.d.ts +1 -1
  63. package/dist/types/lib/commands/vitest.d.ts +1 -1
  64. package/dist/types/lib/index.d.cts +5 -1
  65. package/dist/types/lib/index.d.ts +4 -0
  66. package/dist/types/lib/lint-config/eslint/flat/common.d.mts +6 -0
  67. package/dist/types/lib/lint-config/eslint/flat/index.d.mts +6 -0
  68. package/dist/types/lib/lint-config/eslint/flat/non-react-export.d.mts +4 -0
  69. package/dist/types/lib/lint-config/eslint/flat/non-react.d.mts +3 -0
  70. package/dist/types/lib/lint-config/eslint/flat/presets.d.mts +63 -0
  71. package/dist/types/lib/lint-config/eslint/flat/react-export.d.mts +4 -0
  72. package/dist/types/lib/lint-config/eslint/flat/react.d.mts +4 -0
  73. package/dist/types/lib/lint-config/eslint/flat/rules.d.mts +350 -0
  74. package/dist/types/lib/server/appRoutes.d.ts +1 -1
  75. package/dist/types/lib/server/csp.d.ts +1 -1
  76. package/dist/types/lib/server/middlewares.d.ts +1 -1
  77. package/dist/types/lib/webpack/csp-plugin.d.ts +3 -3
  78. package/dist/types/lib/webpack/helpers.d.ts +1 -1
  79. package/dist/types/lib/webpack/interceptor-middleware.d.ts +2 -2
  80. package/dist/types/lib/webpack/webpack.base.babel.d.ts +1 -1
  81. package/dist/types/lib/webpack/webpack.lib.base.babel.d.ts +1 -1
  82. package/dist/types/lib/webpack/webpack.lib.prod.babel.d.ts +1 -1
  83. package/dist/types/lib/webpack/webpack.prod.babel.d.ts +1 -1
  84. package/dist/types/lib/webpack/webpack.storybook.d.ts +1 -1
  85. package/dist/types/tsconfig.tsbuildinfo +1 -1
  86. package/lib/lint-config/commitlint.config.cjs +1 -0
  87. package/lib/lint-config/eslint/common.cjs +164 -0
  88. package/lib/lint-config/eslint/flat/common.mjs +162 -0
  89. package/lib/lint-config/eslint/flat/index.mjs +20 -0
  90. package/lib/lint-config/eslint/flat/non-react-export.mjs +10 -0
  91. package/lib/lint-config/eslint/flat/non-react.mjs +6 -0
  92. package/lib/lint-config/eslint/flat/presets.mjs +79 -0
  93. package/lib/lint-config/eslint/flat/react-export.mjs +7 -0
  94. package/lib/lint-config/eslint/flat/react.mjs +60 -0
  95. package/lib/lint-config/eslint/flat/rules.mjs +170 -0
  96. package/lib/lint-config/eslint/non-react.cjs +14 -0
  97. package/lib/lint-config/eslint/react.cjs +26 -0
  98. package/lib/lint-config/eslint/typescript/common.cjs +49 -0
  99. package/lib/lint-config/eslint/typescript/non-react.cjs +12 -0
  100. package/lib/lint-config/eslint/typescript/react.cjs +19 -0
  101. package/lib/lint-config/lint-staged.config.js +15 -0
  102. package/lib/lint-config/prettier.config.cjs +8 -0
  103. package/lib/lint-config/stylelint.config.cjs +19 -0
  104. package/package.json +21 -22
package/README.md CHANGED
@@ -8,6 +8,39 @@
8
8
 
9
9
  ## Migration Guide
10
10
 
11
+ ### ESLint 9 flat config (alpha)
12
+
13
+ `pui-cli` now ships ESLint 9 with `typescript-eslint` v8 flat configs. Replace legacy `.eslintrc.cjs` with:
14
+
15
+ ```js
16
+ // eslint.config.mjs — React apps and libraries
17
+ import { eslintFlatConfig } from '@elliemae/pui-cli/eslint';
18
+
19
+ export default eslintFlatConfig;
20
+ ```
21
+
22
+ ```js
23
+ // eslint.config.mjs — non-React Node/TS services
24
+ import { eslintFlatBaseConfig } from '@elliemae/pui-cli/eslint';
25
+
26
+ export default eslintFlatBaseConfig;
27
+ ```
28
+
29
+ **Strict mode** (after the default config is clean — `no-unsafe-*` and `exhaustive-deps` as error):
30
+
31
+ ```js
32
+ import { eslintFlatConfigStrict } from '@elliemae/pui-cli/eslint';
33
+ // or eslintFlatBaseConfigStrict for non-React
34
+
35
+ export default eslintFlatConfigStrict;
36
+ ```
37
+
38
+ Remove `.eslintrc.cjs` and `.eslintignore` (ignores are included in the shared config). Run `pui-cli lint` / `pui-cli lint --fix` after upgrading `@elliemae/pui-cli`.
39
+
40
+ **Breaking changes:** Airbnb presets removed; type-aware rules use `projectService`; `import-x/*` replaces `import/*`; Prettier is not enforced via ESLint (use `lint-staged` / `prettier --write`).
41
+
42
+ **Rule-by-rule comparison:** [ESLint rules migration guide](docs/eslint-rules-migration.md) — old vs new presets, renamed rules, and what teams should expect after upgrade.
43
+
11
44
  ### v7 to v8
12
45
 
13
46
  [Changelog](https://confluence.ice.com/display/FEAE/CLI+ChangeLog#CLIChangeLog-v8)
@@ -74,7 +74,6 @@ const cmdArgs = {
74
74
  }
75
75
  };
76
76
  const testCmd = {
77
- // eslint-disable-next-line max-statements
78
77
  handler: async (argv) => {
79
78
  let commandOptions = "--coverage --maxWorkers=50%";
80
79
  if (argv.fix) commandOptions += " -u";
@@ -71,7 +71,7 @@ const readPackageLock = async () => {
71
71
  const pkgLockJSON = await (0, import_promises.readFile)(appPkgLockFile, "utf8");
72
72
  const { dependencies } = JSON.parse(pkgLockJSON);
73
73
  return (moduleName) => dependencies[moduleName]?.version || "";
74
- } catch (err) {
74
+ } catch {
75
75
  console.warn("Package lock file not found");
76
76
  return () => "";
77
77
  }
@@ -101,8 +101,8 @@ const getModulesInfo = async () => {
101
101
  cli: getModuleVersion("@elliemae/pui-cli"),
102
102
  dimsum: getModuleVersion("@elliemae/ds-system")
103
103
  };
104
- } catch (err) {
105
- console.warn(err);
104
+ } catch {
105
+ console.warn("Package lock file not found");
106
106
  return {};
107
107
  }
108
108
  };
@@ -206,7 +206,7 @@ const isPathExist = async (pathToCheck) => {
206
206
  try {
207
207
  await (0, import_promises.access)(pathToCheck, import_node_fs.constants.F_OK);
208
208
  return true;
209
- } catch (err) {
209
+ } catch {
210
210
  return false;
211
211
  }
212
212
  };
@@ -64,7 +64,6 @@ const cmdArgs = {
64
64
  }
65
65
  };
66
66
  const vitestCmd = {
67
- // eslint-disable-next-line max-statements
68
67
  handler: async (argv) => {
69
68
  let commandOptions = "--coverage";
70
69
  if (argv.fix) commandOptions = "-u";
@@ -1,4 +1,12 @@
1
1
  const { babelConfig } = require('./babel.config.cjs');
2
+ const {
3
+ eslintFlatBaseConfig,
4
+ eslintFlatBaseConfigStrict,
5
+ } = require('./lint-config/eslint/flat/non-react-export.mjs');
6
+ const {
7
+ eslintFlatConfig,
8
+ eslintFlatConfigStrict,
9
+ } = require('./lint-config/eslint/flat/react-export.mjs');
2
10
  const {
3
11
  esConfig: eslintBaseConfig,
4
12
  } = require('./lint-config/eslint/non-react.cjs');
@@ -13,6 +21,10 @@ const { jestNodeConfig } = require('./testing/jest.node.config.cjs');
13
21
 
14
22
  module.exports = {
15
23
  babelConfig,
24
+ eslintFlatBaseConfig,
25
+ eslintFlatBaseConfigStrict,
26
+ eslintFlatConfig,
27
+ eslintFlatConfigStrict,
16
28
  eslintBaseConfig,
17
29
  eslintConfig,
18
30
  stylelintConfig,
package/dist/cjs/index.js CHANGED
@@ -22,6 +22,10 @@ __export(index_exports, {
22
22
  commitlintConfig: () => import_commitlint_config.commitlintConfig,
23
23
  eslintBaseConfig: () => import_non_react.esConfig,
24
24
  eslintConfig: () => import_react.esReactConfig,
25
+ eslintFlatBaseConfig: () => import_non_react_export.eslintFlatBaseConfig,
26
+ eslintFlatBaseConfigStrict: () => import_non_react_export.eslintFlatBaseConfigStrict,
27
+ eslintFlatConfig: () => import_react_export.eslintFlatConfig,
28
+ eslintFlatConfigStrict: () => import_react_export.eslintFlatConfigStrict,
25
29
  jestConfig: () => import_jest_config.jestConfig,
26
30
  jestNodeConfig: () => import_jest_node_config.jestNodeConfig,
27
31
  lintStagedConfig: () => import_lint_staged_config.lintStagedConfig,
@@ -32,6 +36,8 @@ __export(index_exports, {
32
36
  });
33
37
  module.exports = __toCommonJS(index_exports);
34
38
  var import_babel_config = require("./babel.config.cjs");
39
+ var import_non_react_export = require("./lint-config/eslint/flat/non-react-export.mjs");
40
+ var import_react_export = require("./lint-config/eslint/flat/react-export.mjs");
35
41
  var import_non_react = require("./lint-config/eslint/non-react.cjs");
36
42
  var import_react = require("./lint-config/eslint/react.cjs");
37
43
  var import_stylelint_config = require("./lint-config/stylelint.config.cjs");
@@ -1,4 +1,4 @@
1
- /* eslint-disable max-lines */
1
+
2
2
  const prettierOptions = require("../prettier.config.cjs");
3
3
  // const webpackConfig = require('../../webpack/webpack.prod.babel');
4
4
 
@@ -0,0 +1,162 @@
1
+ import eslint from '@eslint/js';
2
+ import { defineConfig } from 'eslint/config';
3
+ import eslintConfigPrettier from 'eslint-config-prettier';
4
+ import eslintComments from 'eslint-plugin-eslint-comments';
5
+ import importX from 'eslint-plugin-import-x';
6
+ import jest from 'eslint-plugin-jest';
7
+ import testingLibrary from 'eslint-plugin-testing-library';
8
+ import wdio from 'eslint-plugin-wdio';
9
+ import globals from 'globals';
10
+ import tseslint from 'typescript-eslint';
11
+ import {
12
+ jestRecommendedRules,
13
+ sharedCoreRules,
14
+ testFiles,
15
+ testJsxFiles,
16
+ testingLibraryDomRules,
17
+ testingLibraryReactRules,
18
+ wdioGlobals,
19
+ wdioRecommendedRules,
20
+ wdioSpecFiles,
21
+ } from './presets.mjs';
22
+ import {
23
+ ignorePatterns,
24
+ jsRules,
25
+ typescriptRules,
26
+ typescriptStrictRules,
27
+ typescriptTestRelaxedRules,
28
+ } from './rules.mjs';
29
+
30
+ const tsconfigRootDir = process.cwd();
31
+
32
+ const typescriptParserOptions = {
33
+ projectService: true,
34
+ tsconfigRootDir,
35
+ };
36
+
37
+ /** Cached flat config arrays (only two variants: default + strict). */
38
+ const configCache = new Map();
39
+
40
+ /** @param {Record<string, unknown>} tsRules - `typescriptRules` or `typescriptStrictRules` */
41
+ export function createBaseFlatConfigs(tsRules) {
42
+ if (configCache.has(tsRules)) {
43
+ return configCache.get(tsRules);
44
+ }
45
+
46
+ const config = defineConfig(
47
+ { ignores: ignorePatterns },
48
+ eslint.configs.recommended,
49
+ eslintConfigPrettier,
50
+ {
51
+ plugins: {
52
+ 'eslint-comments': eslintComments,
53
+ 'import-x': importX,
54
+ },
55
+ languageOptions: {
56
+ ecmaVersion: 'latest',
57
+ sourceType: 'module',
58
+ parserOptions: {
59
+ ecmaFeatures: { jsx: true },
60
+ },
61
+ globals: {
62
+ ...globals.browser,
63
+ ...globals.node,
64
+ ...globals.es2021,
65
+ },
66
+ },
67
+ settings: {
68
+ 'import-x/resolver': {
69
+ node: { extensions: ['.js', '.jsx', '.ts', '.tsx'] },
70
+ typescript: { alwaysTryTypes: true },
71
+ },
72
+ },
73
+ rules: sharedCoreRules,
74
+ },
75
+ {
76
+ files: ['**/*.{js,jsx,mjs,cjs}'],
77
+ rules: jsRules,
78
+ },
79
+ ...tseslint.configs.recommendedTypeChecked.map((config) => ({
80
+ ...config,
81
+ files: ['**/*.{ts,tsx}'],
82
+ })),
83
+ {
84
+ files: ['**/*.{ts,tsx}'],
85
+ rules: tsRules,
86
+ languageOptions: {
87
+ parserOptions: typescriptParserOptions,
88
+ },
89
+ },
90
+ {
91
+ files: testFiles,
92
+ plugins: {
93
+ jest,
94
+ 'testing-library': testingLibrary,
95
+ },
96
+ languageOptions: {
97
+ globals: globals.jest,
98
+ },
99
+ settings: {
100
+ jest: { version: 'detect' },
101
+ },
102
+ rules: {
103
+ ...jestRecommendedRules,
104
+ ...testingLibraryDomRules,
105
+ 'testing-library/no-node-access': 'off',
106
+ ...typescriptTestRelaxedRules,
107
+ },
108
+ },
109
+ {
110
+ files: testJsxFiles,
111
+ rules: {
112
+ ...testingLibraryReactRules,
113
+ 'testing-library/no-node-access': 'off',
114
+ },
115
+ },
116
+ {
117
+ files: wdioSpecFiles,
118
+ plugins: { wdio, jest },
119
+ languageOptions: { globals: wdioGlobals },
120
+ rules: {
121
+ ...wdioRecommendedRules,
122
+ 'jest/valid-expect': 'off',
123
+ },
124
+ },
125
+ {
126
+ files: ['**/eslint.config.{mjs,cjs,js}'],
127
+ rules: { 'import-x/no-unresolved': 'off' },
128
+ },
129
+ {
130
+ files: ['**/scripts/**', '**/ci_cd/**'],
131
+ rules: {
132
+ 'no-console': 'off',
133
+ 'max-lines': 'off',
134
+ complexity: 'off',
135
+ },
136
+ },
137
+ {
138
+ files: ['**/lint-config/**'],
139
+ rules: {
140
+ 'max-lines': 'off',
141
+ 'import-x/no-named-as-default-member': 'off',
142
+ 'import-x/default': 'off',
143
+ },
144
+ },
145
+ {
146
+ files: ['**/*.d.ts'],
147
+ rules: {
148
+ '@typescript-eslint/no-explicit-any': 'off',
149
+ '@typescript-eslint/no-empty-object-type': 'off',
150
+ },
151
+ },
152
+ );
153
+
154
+ configCache.set(tsRules, config);
155
+ return config;
156
+ }
157
+
158
+ /** Default flat base — `no-unsafe-*` as warn in application TypeScript. */
159
+ export const baseFlatConfigs = createBaseFlatConfigs(typescriptRules);
160
+
161
+ /** Strict flat base — `no-unsafe-*` as error in application TypeScript. */
162
+ export const baseFlatConfigsStrict = createBaseFlatConfigs(typescriptStrictRules);
@@ -0,0 +1,20 @@
1
+ export { eslintFlatConfig, eslintFlatConfigStrict } from './react-export.mjs';
2
+ export {
3
+ eslintFlatBaseConfig,
4
+ eslintFlatBaseConfigStrict,
5
+ } from './non-react-export.mjs';
6
+ export { reactFlatConfigs, reactFlatConfigsStrict } from './react.mjs';
7
+ export {
8
+ nonReactFlatConfigs,
9
+ nonReactFlatConfigsStrict,
10
+ } from './non-react.mjs';
11
+ export {
12
+ baseFlatConfigs,
13
+ baseFlatConfigsStrict,
14
+ createBaseFlatConfigs,
15
+ } from './common.mjs';
16
+ export {
17
+ storybookFiles,
18
+ testFiles,
19
+ testJsxFiles,
20
+ } from './presets.mjs';
@@ -0,0 +1,10 @@
1
+ import {
2
+ nonReactFlatConfigs,
3
+ nonReactFlatConfigsStrict,
4
+ } from './non-react.mjs';
5
+
6
+ /** Flat ESLint config for non-React TypeScript libraries and services. */
7
+ export const eslintFlatBaseConfig = nonReactFlatConfigs;
8
+
9
+ /** Strict flat ESLint config for non-React TypeScript (`no-unsafe-*` as error). */
10
+ export const eslintFlatBaseConfigStrict = nonReactFlatConfigsStrict;
@@ -0,0 +1,6 @@
1
+ import { baseFlatConfigs, baseFlatConfigsStrict } from './common.mjs';
2
+
3
+ /** `defineConfig` already applied in `createBaseFlatConfigs`. */
4
+ export const nonReactFlatConfigs = baseFlatConfigs;
5
+
6
+ export const nonReactFlatConfigsStrict = baseFlatConfigsStrict;
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Preset rule bundles and file globs computed once at module load (not per config factory call).
3
+ */
4
+ import eslintComments from 'eslint-plugin-eslint-comments';
5
+ import importX from 'eslint-plugin-import-x';
6
+ import jest from 'eslint-plugin-jest';
7
+ import jsxA11y from 'eslint-plugin-jsx-a11y';
8
+ import react from 'eslint-plugin-react';
9
+ import reactHooks from 'eslint-plugin-react-hooks';
10
+ import reduxSaga from 'eslint-plugin-redux-saga';
11
+ import storybook from 'eslint-plugin-storybook';
12
+ import testingLibrary from 'eslint-plugin-testing-library';
13
+ import wdio from 'eslint-plugin-wdio';
14
+
15
+ export const testFiles = [
16
+ '**/*.{test,spec}.{js,jsx,ts,tsx}',
17
+ '**/__tests__/**',
18
+ '**/lib/testing/**',
19
+ '**/mocks/**',
20
+ ];
21
+
22
+ export const testJsxFiles = ['**/*.{test,spec}.{jsx,tsx}'];
23
+
24
+ export const wdioSpecFiles = [
25
+ '**/*.func.spec.js',
26
+ '**/*.visual.spec.js',
27
+ '**/*e2e*.{js,ts}',
28
+ '**/e2e/**',
29
+ ];
30
+
31
+ export const storybookFiles = [
32
+ '**/*.stories.{js,jsx,ts,tsx}',
33
+ '**/.storybook/**',
34
+ ];
35
+
36
+ /** @type {import('eslint').Linter.RulesRecord} */
37
+ export const sharedCoreRules = {
38
+ ...eslintComments.configs.recommended.rules,
39
+ ...importX.configs.recommended.rules,
40
+ 'import-x/named': 'off',
41
+ };
42
+
43
+ /** @type {import('eslint').Linter.RulesRecord} */
44
+ export const jestRecommendedRules = jest.configs.recommended.rules;
45
+
46
+ const testingLibraryDom =
47
+ testingLibrary.configs['flat/dom'] ?? testingLibrary.configs.dom;
48
+ const testingLibraryReact =
49
+ testingLibrary.configs['flat/react'] ?? testingLibrary.configs.react;
50
+
51
+ /** @type {import('eslint').Linter.RulesRecord} */
52
+ export const testingLibraryDomRules = testingLibraryDom?.rules ?? {};
53
+
54
+ /** @type {import('eslint').Linter.RulesRecord} */
55
+ export const testingLibraryReactRules = testingLibraryReact?.rules ?? {};
56
+
57
+ /** @type {import('eslint').Linter.RulesRecord} */
58
+ export const reactPresetRules = {
59
+ ...react.configs.recommended.rules,
60
+ ...reactHooks.configs.recommended.rules,
61
+ ...jsxA11y.flatConfigs.recommended.rules,
62
+ ...reduxSaga.configs.recommended.rules,
63
+ };
64
+
65
+ /** @type {import('eslint').Linter.RulesRecord} */
66
+ export const wdioRecommendedRules = wdio.configs.recommended.rules ?? {};
67
+
68
+ /** @type {Record<string, boolean>} */
69
+ export const wdioGlobals = wdio.configs.recommended.globals ?? {};
70
+
71
+ const storybookFlat =
72
+ storybook.configs['flat/recommended'] ??
73
+ storybook.configs.recommended ??
74
+ [];
75
+
76
+ /** Normalized once — Storybook flat config may be array or single object. */
77
+ export const storybookFlatConfigs = Array.isArray(storybookFlat)
78
+ ? storybookFlat
79
+ : [storybookFlat];
@@ -0,0 +1,7 @@
1
+ import { reactFlatConfigs, reactFlatConfigsStrict } from './react.mjs';
2
+
3
+ /** Flat ESLint config for React + TypeScript PUI apps. */
4
+ export const eslintFlatConfig = reactFlatConfigs;
5
+
6
+ /** Strict flat ESLint config for React + TypeScript (errors on `no-unsafe-*` and `exhaustive-deps`). */
7
+ export const eslintFlatConfigStrict = reactFlatConfigsStrict;
@@ -0,0 +1,60 @@
1
+ import { defineConfig } from 'eslint/config';
2
+ import jsxA11y from 'eslint-plugin-jsx-a11y';
3
+ import react from 'eslint-plugin-react';
4
+ import reactHooks from 'eslint-plugin-react-hooks';
5
+ import reduxSaga from 'eslint-plugin-redux-saga';
6
+ import { baseFlatConfigs, baseFlatConfigsStrict } from './common.mjs';
7
+ import {
8
+ reactPresetRules,
9
+ storybookFiles,
10
+ storybookFlatConfigs,
11
+ } from './presets.mjs';
12
+ import { reactRules, reactStrictRules } from './rules.mjs';
13
+
14
+ const reactPluginBlock = {
15
+ plugins: {
16
+ react,
17
+ 'react-hooks': reactHooks,
18
+ 'jsx-a11y': jsxA11y,
19
+ 'redux-saga': reduxSaga,
20
+ },
21
+ settings: {
22
+ react: { version: 'detect' },
23
+ },
24
+ };
25
+
26
+ /**
27
+ * @param {import('eslint').Linter.Config[]} baseConfigs
28
+ * @param {typeof reactRules} puiReactRules
29
+ */
30
+ function createReactFlatConfigs(baseConfigs, puiReactRules) {
31
+ return defineConfig(
32
+ ...baseConfigs,
33
+ {
34
+ ...reactPluginBlock,
35
+ rules: {
36
+ ...reactPresetRules,
37
+ ...puiReactRules,
38
+ },
39
+ },
40
+ ...storybookFlatConfigs,
41
+ {
42
+ files: storybookFiles,
43
+ rules: {
44
+ 'react/jsx-props-no-spreading': 'off',
45
+ },
46
+ },
47
+ );
48
+ }
49
+
50
+ /** Default React flat config — migration-friendly type-safety warnings. */
51
+ export const reactFlatConfigs = createReactFlatConfigs(
52
+ baseFlatConfigs,
53
+ reactRules,
54
+ );
55
+
56
+ /** Strict React flat config — `no-unsafe-*` and `exhaustive-deps` as error. */
57
+ export const reactFlatConfigsStrict = createReactFlatConfigs(
58
+ baseFlatConfigsStrict,
59
+ reactStrictRules,
60
+ );
@@ -0,0 +1,170 @@
1
+ /** Shared rule sets migrated from legacy eslintrc (common.cjs + typescript/*.cjs). */
2
+
3
+ export const baseRules = {
4
+ 'arrow-body-style': ['error', 'as-needed'],
5
+ 'class-methods-use-this': 'off',
6
+ 'import-x/imports-first': 'off',
7
+ 'import-x/newline-after-import': 'off',
8
+ 'import-x/no-dynamic-require': 'off',
9
+ // Off — legacy parity; PUI apps import via @elliemae/app-react-dependencies (not direct package.json entries).
10
+ 'import-x/no-extraneous-dependencies': 'off',
11
+ 'import-x/no-named-as-default': 'off',
12
+ 'import-x/no-unresolved': [
13
+ 'error',
14
+ { caseSensitive: true, caseSensitiveStrict: true },
15
+ ],
16
+ 'import-x/no-webpack-loader-syntax': 'off',
17
+ 'import-x/prefer-default-export': 'off',
18
+ 'import-x/default': 'off',
19
+ 'import-x/namespace': 'off',
20
+ 'import-x/extensions': [
21
+ 'error',
22
+ 'never',
23
+ {
24
+ json: 'ignorePackages',
25
+ js: 'ignorePackages',
26
+ },
27
+ ],
28
+ complexity: ['error', { max: 10 }],
29
+ 'max-depth': ['error', { max: 4 }],
30
+ 'max-lines-per-function': 'off',
31
+ 'max-nested-callbacks': ['error', { max: 3 }],
32
+ 'max-params': ['error', { max: 3 }],
33
+ 'max-statements': ['error', { max: 20 }],
34
+ 'max-len': 'off',
35
+ 'newline-per-chained-call': 'off',
36
+ 'no-confusing-arrow': 'off',
37
+ 'no-console': 'warn',
38
+ 'no-param-reassign': ['error', { props: false }],
39
+ 'prefer-template': 'error',
40
+ 'require-yield': 'off',
41
+ 'eslint-comments/disable-enable-pair': 'off',
42
+ };
43
+
44
+ /** Relaxed type-checked rules for test files (shared by default and strict configs). */
45
+ export const typescriptTestRelaxedRules = {
46
+ '@typescript-eslint/no-unsafe-assignment': 'off',
47
+ '@typescript-eslint/no-unsafe-member-access': 'off',
48
+ '@typescript-eslint/no-unsafe-call': 'off',
49
+ '@typescript-eslint/no-unsafe-argument': 'off',
50
+ '@typescript-eslint/no-unsafe-return': 'off',
51
+ '@typescript-eslint/unbound-method': 'off',
52
+ };
53
+
54
+ export const jsRules = {
55
+ ...baseRules,
56
+ 'max-lines': ['error', { max: 120, skipComments: true }],
57
+ 'no-unused-vars': 'error',
58
+ };
59
+
60
+ export const typescriptRules = {
61
+ ...baseRules,
62
+ 'max-lines': ['error', { max: 200, skipComments: true }],
63
+ '@typescript-eslint/explicit-module-boundary-types': 'off',
64
+ '@typescript-eslint/explicit-function-return-type': 'off',
65
+ '@typescript-eslint/no-use-before-define': [
66
+ 'error',
67
+ { functions: false, classes: true, variables: true, typedefs: true },
68
+ ],
69
+ '@typescript-eslint/unbound-method': ['error', { ignoreStatic: true }],
70
+ '@typescript-eslint/no-floating-promises': ['error', { ignoreIIFE: true }],
71
+ '@typescript-eslint/no-misused-promises': [
72
+ 'error',
73
+ { checksVoidReturn: { attributes: false } },
74
+ ],
75
+ '@typescript-eslint/no-unsafe-assignment': 'warn',
76
+ '@typescript-eslint/no-unsafe-member-access': 'warn',
77
+ '@typescript-eslint/no-unsafe-call': 'warn',
78
+ '@typescript-eslint/no-unsafe-argument': 'warn',
79
+ '@typescript-eslint/no-unsafe-return': 'warn',
80
+ '@typescript-eslint/consistent-type-imports': [
81
+ 'error',
82
+ { prefer: 'type-imports', fixStyle: 'inline-type-imports' },
83
+ ],
84
+ '@typescript-eslint/no-import-type-side-effects': 'error',
85
+ 'no-unused-vars': 'off',
86
+ '@typescript-eslint/no-unused-vars': [
87
+ 'error',
88
+ { argsIgnorePattern: '^_', ignoreRestSiblings: true },
89
+ ],
90
+ };
91
+
92
+ /** Stricter TypeScript rules (error on unsafe any usage). */
93
+ export const typescriptStrictRules = {
94
+ ...typescriptRules,
95
+ '@typescript-eslint/no-unsafe-assignment': 'error',
96
+ '@typescript-eslint/no-unsafe-member-access': 'error',
97
+ '@typescript-eslint/no-unsafe-call': 'error',
98
+ '@typescript-eslint/no-unsafe-argument': 'error',
99
+ '@typescript-eslint/no-unsafe-return': 'error',
100
+ };
101
+
102
+ export const reactRules = {
103
+ 'jsx-a11y/aria-props': 'error',
104
+ 'jsx-a11y/heading-has-content': 'off',
105
+ 'jsx-a11y/label-has-associated-control': [
106
+ 'error',
107
+ {
108
+ controlComponents: ['Input'],
109
+ },
110
+ ],
111
+ 'jsx-a11y/label-has-for': 'off',
112
+ 'jsx-a11y/mouse-events-have-key-events': 'error',
113
+ 'jsx-a11y/role-has-required-aria-props': 'error',
114
+ 'jsx-a11y/role-supports-aria-props': 'error',
115
+ 'react/destructuring-assignment': 'off',
116
+ 'react-hooks/rules-of-hooks': 'error',
117
+ 'react-hooks/exhaustive-deps': 'warn',
118
+ 'react/jsx-closing-tag-location': 'off',
119
+ 'react/forbid-prop-types': 'off',
120
+ 'react/jsx-first-prop-new-line': ['error', 'multiline'],
121
+ 'react/jsx-no-target-blank': 'off',
122
+ 'react/jsx-props-no-spreading': 'off',
123
+ 'react/jsx-uses-vars': 'error',
124
+ 'react/require-default-props': 'off',
125
+ 'react/require-extension': 'off',
126
+ 'react/self-closing-comp': 'off',
127
+ 'react/sort-comp': 'off',
128
+ 'react/react-in-jsx-scope': 'off',
129
+ 'react/jsx-filename-extension': [
130
+ 'warn',
131
+ { extensions: ['.js', '.jsx', '.tsx', '.mdx'] },
132
+ ],
133
+ 'react/function-component-definition': [
134
+ 'error',
135
+ { namedComponents: 'arrow-function' },
136
+ ],
137
+ 'react/prop-types': 'off',
138
+ 'redux-saga/no-yield-in-race': 'error',
139
+ 'redux-saga/yield-effects': 'error',
140
+ };
141
+
142
+ /** Stricter React rules (exhaustive-deps as error). */
143
+ export const reactStrictRules = {
144
+ ...reactRules,
145
+ 'react-hooks/exhaustive-deps': 'error',
146
+ };
147
+
148
+ export const ignorePatterns = [
149
+ '**/build/**',
150
+ '**/node_modules/**',
151
+ '**/dist/**',
152
+ '**/reports/**',
153
+ '**/allure-report/**',
154
+ '**/coverage/**',
155
+ '**/demo/**',
156
+ '**/docs/**',
157
+ '**/docs/api/**',
158
+ '**/temp/**',
159
+ '**/.tmp/**',
160
+ '**/public/**',
161
+ '**/webroot/**',
162
+ '**/cdn/**',
163
+ '**/.docusaurus/**',
164
+ '**/vendor/*.js',
165
+ '**/.nx/**',
166
+ '**/pnpm-lock.yaml',
167
+ '**/.scannerwork/**',
168
+ '**/stats.json',
169
+ '**/jsconfig.json',
170
+ ];
@@ -1,4 +1,4 @@
1
- /* eslint-disable max-lines */
1
+
2
2
  const { baseRules } = require('../common.cjs');
3
3
  const { tsBaseExtends, tsBaseRules, tsBaseConfig } = require('./common.cjs');
4
4
 
@@ -1,4 +1,4 @@
1
- /* eslint-disable max-lines */
1
+
2
2
  const { baseRules, reactRules } = require('../common.cjs');
3
3
  const { tsBaseExtends, tsBaseRules, tsBaseConfig } = require('./common.cjs');
4
4