@bedrockio/eslint-plugin 1.4.9 → 1.5.0

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.
@@ -0,0 +1,37 @@
1
+ import react from 'eslint-plugin-react';
2
+ export default {
3
+ name: 'react',
4
+ files: ['**/*.{js,jsx,ts,tsx,mdx}'],
5
+ ignores: ['node_modules/**/*', '**/dist/**/*', '**/*.d.ts'],
6
+ plugins: {
7
+ react
8
+ },
9
+ languageOptions: {
10
+ parserOptions: {
11
+ ecmaFeatures: {
12
+ jsx: true
13
+ }
14
+ }
15
+ },
16
+ rules: {
17
+ ...react.configs['recommended'].rules,
18
+ ...react.configs['jsx-runtime'].rules,
19
+ 'no-console': 'warn',
20
+ 'react/prop-types': 'off',
21
+ 'react/display-name': 'off',
22
+ 'react/no-unescaped-entities': ['error', {
23
+ forbid: [{
24
+ char: '>',
25
+ alternatives: ['>']
26
+ }, {
27
+ char: '<',
28
+ alternatives: ['&lt;']
29
+ }]
30
+ }]
31
+ },
32
+ settings: {
33
+ react: {
34
+ version: 'detect'
35
+ }
36
+ }
37
+ };
@@ -0,0 +1,17 @@
1
+ import js from '@eslint/js';
2
+ export default {
3
+ name: 'recommended',
4
+ ignores: ['node_modules/**/*', '**/dist/**/*', '**/*.d.ts'],
5
+ languageOptions: {
6
+ ecmaVersion: 'latest',
7
+ sourceType: 'module'
8
+ },
9
+ rules: {
10
+ ...js.configs.recommended.rules,
11
+ 'no-console': 'warn',
12
+ curly: ['error', 'multi-line', 'consistent'],
13
+ 'no-unused-vars': ['warn', {
14
+ ignoreRestSiblings: true
15
+ }]
16
+ }
17
+ };
@@ -0,0 +1,167 @@
1
+ /**
2
+ * Patched Vite resolver for eslint-plugin-import.
3
+ *
4
+ * Based on `eslint-import-resolver-vite`:
5
+ * https://github.com/pzmosquito/eslint-import-resolver-vite
6
+ *
7
+ * The upstream resolver replaces every matching path segment when applying
8
+ * aliases. This breaks imports like `docs/components/...` when both `docs`
9
+ * and `components` are aliases, producing invalid paths.
10
+ *
11
+ * This version fixes the behavior so aliases only match the **leading prefix**
12
+ * of the import specifier, which matches how Vite/Rollup aliasing works.
13
+ *
14
+ * Additional improvements
15
+ * -----------------------
16
+ * - Supports both object and array alias forms used by Vite
17
+ * - Supports RegExp `find` entries in array aliases
18
+ * - Avoids rewriting absolute paths incorrectly
19
+ * - Cleans up root/publicDir resolution logic
20
+ *
21
+ */
22
+
23
+ import path from 'node:path';
24
+ import resolve from 'resolve';
25
+ import createDebug from 'debug';
26
+ import { existsSync } from 'node:fs';
27
+ const namespace = 'eslint-plugin-import:resolver:vite';
28
+ const log = createDebug(namespace);
29
+ function loadViteConfig(config) {
30
+ if (!config) {
31
+ throw new Error("'config' option must be a path to a vite config file.");
32
+ }
33
+ const file = path.resolve(process.cwd(), config);
34
+ if (!existsSync(file)) {
35
+ return;
36
+ }
37
+ const mod = require(file);
38
+ return mod.default || mod;
39
+ }
40
+ function tryResolve(source, resolveOptions, label) {
41
+ log('resolving:\t', `(${label})`, source);
42
+ const resolvedPath = resolve.sync(source, resolveOptions);
43
+ log('resolved:\t', resolvedPath);
44
+ return {
45
+ found: true,
46
+ path: resolvedPath
47
+ };
48
+ }
49
+ function normalizeAliasEntries(alias) {
50
+ if (!alias) {
51
+ return [];
52
+ }
53
+ if (Array.isArray(alias)) {
54
+ return alias.filter(Boolean).map(entry => ({
55
+ find: entry.find,
56
+ replacement: entry.replacement
57
+ }));
58
+ }
59
+ if (typeof alias === 'object') {
60
+ return Object.entries(alias).map(([find, replacement]) => ({
61
+ find,
62
+ replacement
63
+ }));
64
+ }
65
+ throw new Error('The alias must be either an object, or an array of objects.');
66
+ }
67
+ function applyStringAlias(source, find, replacement) {
68
+ if (source === find) {
69
+ return replacement;
70
+ }
71
+ if (source.startsWith(find + '/')) {
72
+ return replacement + source.slice(find.length);
73
+ }
74
+ return null;
75
+ }
76
+ function processAlias(alias, source) {
77
+ const entries = normalizeAliasEntries(alias);
78
+ for (const {
79
+ find,
80
+ replacement
81
+ } of entries) {
82
+ if (!find || !replacement) {
83
+ continue;
84
+ }
85
+ if (find instanceof RegExp) {
86
+ if (find.test(source)) {
87
+ return source.replace(find, replacement);
88
+ }
89
+ continue;
90
+ }
91
+ if (typeof find === 'string') {
92
+ const resolved = applyStringAlias(source, find, replacement);
93
+ if (resolved) {
94
+ return resolved;
95
+ }
96
+ }
97
+ }
98
+ return source;
99
+ }
100
+ function resolveRoot(root) {
101
+ if (!root) {
102
+ return process.cwd();
103
+ }
104
+ if (path.isAbsolute(root)) {
105
+ return root;
106
+ }
107
+ return path.resolve(process.cwd(), root);
108
+ }
109
+ export const interfaceVersion = 2;
110
+ function resolveImport(source, file, config) {
111
+ log('\nin file:\t', file);
112
+ if (resolve.isCore(source)) {
113
+ log('resolved:\t', source);
114
+ return {
115
+ found: true,
116
+ path: null
117
+ };
118
+ }
119
+ const viteConfig = loadViteConfig(config?.config);
120
+ if (!viteConfig) {
121
+ return {
122
+ found: false
123
+ };
124
+ }
125
+ const defaultExtensions = ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json'];
126
+ const viteResolve = viteConfig.resolve || {};
127
+ const extensions = viteResolve.extensions || defaultExtensions;
128
+ const resolveOptions = {
129
+ basedir: path.dirname(file),
130
+ extensions
131
+ };
132
+ try {
133
+ return tryResolve(source, resolveOptions, 'as is');
134
+ } catch {}
135
+ const parsedSource = processAlias(viteResolve.alias, source);
136
+ if (parsedSource !== source) {
137
+ try {
138
+ return tryResolve(parsedSource, resolveOptions, 'with alias');
139
+ } catch {}
140
+ }
141
+ if (path.isAbsolute(parsedSource)) {
142
+ try {
143
+ return tryResolve(parsedSource, resolveOptions, 'absolute path');
144
+ } catch {}
145
+ }
146
+ if (viteConfig.publicDir !== false) {
147
+ const rootDir = resolveRoot(viteConfig.root);
148
+ const publicDir = viteConfig.publicDir || 'public';
149
+ const publicBase = path.isAbsolute(publicDir) ? publicDir : path.resolve(rootDir, publicDir);
150
+ const publicSource = path.resolve(publicBase, parsedSource);
151
+ try {
152
+ return tryResolve(publicSource, resolveOptions, 'in public directory');
153
+ } catch {}
154
+ }
155
+ log('ERROR:\t', 'Unable to resolve');
156
+ return {
157
+ found: false
158
+ };
159
+ }
160
+ export function createViteImportResolver(config) {
161
+ return {
162
+ interfaceVersion: 3,
163
+ name: 'eslint-import-resolver-vite',
164
+ resolve: (source, file) => resolveImport(source, file, config)
165
+ };
166
+ }
167
+ export { resolveImport as resolve };
@@ -0,0 +1,27 @@
1
+ import ts from 'typescript-eslint';
2
+ export default {
3
+ name: 'typescript',
4
+ files: ['**/*.{ts,tsx}'],
5
+ ignores: ['node_modules/**/*', '**/dist/**/*', '**/*.d.ts'],
6
+ languageOptions: {
7
+ ecmaVersion: 'latest',
8
+ sourceType: 'module',
9
+ parser: ts.parser
10
+ },
11
+ plugins: {
12
+ '@typescript-eslint': ts.plugin
13
+ },
14
+ rules: {
15
+ // Pull in `eslint-recommended` adjustments from typescript-eslint.
16
+ // This disables core ESLint rules that conflict with TypeScript (e.g. no-undef).
17
+ ...ts.plugin.configs['eslint-recommended'].overrides[0].rules,
18
+ // Pull in the TypeScript recommended rules themselves.
19
+ // Avoid the flat config version as it's an array.
20
+ ...ts.plugin.configs.recommended.rules,
21
+ '@typescript-eslint/no-unused-vars': 'warn',
22
+ '@typescript-eslint/no-explicit-any': 'off',
23
+ // The above configs try to slip this rule in there despite it
24
+ // not being part of eslint-recommended so force it off again.
25
+ 'prefer-const': 'off'
26
+ }
27
+ };
@@ -0,0 +1,22 @@
1
+ import globals from 'globals';
2
+ export default {
3
+ name: 'vite',
4
+ files: ['**/*.{js,jsx,ts,tsx,mdx}'],
5
+ ignores: ['node_modules/**/*', '**/dist/**/*', '**/*.d.ts'],
6
+ languageOptions: {
7
+ ecmaVersion: 'latest',
8
+ sourceType: 'module',
9
+ globals: globals.browser
10
+ },
11
+ settings: {
12
+ 'import/resolver': {
13
+ exports: true,
14
+ ['@bedrockio/eslint-plugin/resolvers/vite']: {
15
+ config: './vite.config.js'
16
+ },
17
+ node: {
18
+ moduleDirectory: ['node_modules', 'src']
19
+ }
20
+ }
21
+ }
22
+ };
@@ -0,0 +1,29 @@
1
+ import globals from 'globals';
2
+ export default {
3
+ name: 'webpack',
4
+ files: ['**/*.{js,jsx,ts,tsx,mdx}'],
5
+ ignores: ['node_modules/**/*', '**/dist/**/*', '**/*.d.ts'],
6
+ languageOptions: {
7
+ ecmaVersion: 'latest',
8
+ sourceType: 'module',
9
+ globals: globals.browser
10
+ },
11
+ rules: {
12
+ 'import/no-unresolved': ['warn', {
13
+ // package.json "style" may be used here which
14
+ // will resolve for webpack but not within the
15
+ // eslint plugin
16
+ ignore: ['\\.css$']
17
+ }]
18
+ },
19
+ settings: {
20
+ 'import/resolver': {
21
+ webpack: {
22
+ config: './webpack.config.js'
23
+ },
24
+ node: {
25
+ moduleDirectory: ['node_modules', 'src']
26
+ }
27
+ }
28
+ }
29
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bedrockio/eslint-plugin",
3
- "version": "1.4.9",
3
+ "version": "1.5.0",
4
4
  "description": "Common ESLint plugin for Bedrock projects.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -16,8 +16,14 @@
16
16
  "main": "./dist/cjs/index.js",
17
17
  "module": "./src/index.js",
18
18
  "exports": {
19
- "import": "./src/index.js",
20
- "require": "./dist/cjs/index.js"
19
+ ".": {
20
+ "import": "./dist/esm/index.js",
21
+ "require": "./dist/cjs/index.js"
22
+ },
23
+ "./resolvers/vite": {
24
+ "import": "./dist/esm/resolvers/vite.js",
25
+ "require": "./dist/cjs/resolvers/vite.js"
26
+ }
21
27
  },
22
28
  "dependencies": {
23
29
  "@eslint/js": "^10.0.1",
@@ -28,7 +34,8 @@
28
34
  "eslint-plugin-jest": "^29.15.0",
29
35
  "eslint-plugin-mdx": "^3.7.0",
30
36
  "eslint-plugin-react": "^7.37.5",
31
- "globals": "^17.3.0"
37
+ "globals": "^17.3.0",
38
+ "typescript-eslint": "^8.57.0"
32
39
  },
33
40
  "devDependencies": {
34
41
  "@babel/cli": "^7.28.6",
@@ -36,20 +43,15 @@
36
43
  "@babel/preset-env": "^7.29.0",
37
44
  "@bedrockio/prettier-config": "^1.1.1",
38
45
  "eslint": "^9.39.2",
39
- "typescript": "^5.9.3",
40
- "typescript-eslint": "^8.55.0"
46
+ "typescript": "^5.9.3"
41
47
  },
42
48
  "peerDependencies": {
43
49
  "eslint": ">=9",
44
- "eslint-import-resolver-webpack": "^0.13.10",
45
- "typescript-eslint": "^8.55.0"
50
+ "eslint-import-resolver-webpack": "^0.13.10"
46
51
  },
47
52
  "peerDependenciesMeta": {
48
53
  "eslint-import-resolver-webpack": {
49
54
  "optional": true
50
- },
51
- "typescript-eslint": {
52
- "optional": true
53
55
  }
54
56
  },
55
57
  "prettier": "@bedrockio/prettier-config",
package/src/imports.js ADDED
@@ -0,0 +1,79 @@
1
+ import * as plugin from 'eslint-plugin-import';
2
+
3
+ export default {
4
+ ...plugin.flatConfigs.recommended,
5
+ name: 'imports',
6
+ ignores: ['node_modules/**/*', '**/dist/**/*', '**/*.d.ts'],
7
+ languageOptions: {
8
+ ecmaVersion: 'latest',
9
+ sourceType: 'module',
10
+ },
11
+ rules: {
12
+ ...plugin.flatConfigs.recommended.rules,
13
+ 'import/namespace': 'off',
14
+ 'import/no-unresolved': 'warn',
15
+ 'import/no-named-as-default-member': 'off',
16
+ 'import/first': 'warn',
17
+ 'import/order': [
18
+ 'warn',
19
+ {
20
+ 'newlines-between': 'always-and-inside-groups',
21
+ sortTypesGroup: true,
22
+ alphabetize: {
23
+ order: 'asc',
24
+ caseInsensitive: false,
25
+ },
26
+ named: true,
27
+ warnOnUnassignedImports: true,
28
+ consolidateIslands: 'inside-groups',
29
+ groups: [
30
+ 'builtin',
31
+ 'unknown',
32
+ 'external',
33
+ 'internal',
34
+ ['parent', 'sibling'],
35
+ 'index',
36
+ 'object',
37
+ 'type',
38
+ ],
39
+ pathGroups: [
40
+ {
41
+ pattern: 'semantic',
42
+ group: 'external',
43
+ },
44
+ {
45
+ pattern:
46
+ '+(stores|helpers|layouts|@stores|@helpers|@layouts){,/**}',
47
+ group: 'internal',
48
+ position: 'before',
49
+ },
50
+ {
51
+ pattern:
52
+ '+(screens|modals|components|@screens|@modals|@components){,/**}',
53
+ group: 'internal',
54
+ },
55
+ {
56
+ pattern: '+(hooks|@hooks|utils|@utils){,/**}',
57
+ group: 'internal',
58
+ position: 'after',
59
+ },
60
+ {
61
+ pattern: '+(assets|@assets){,**}',
62
+ group: 'sibling',
63
+ position: 'after',
64
+ },
65
+ {
66
+ pattern: '**/*.+(css|less|scss|png|jpg|svg|json)',
67
+ group: 'type',
68
+ position: 'after',
69
+ },
70
+ {
71
+ pattern: './**/*.+(css|less|scss|png|jpg|svg|json)',
72
+ group: 'type',
73
+ position: 'after',
74
+ },
75
+ ],
76
+ },
77
+ ],
78
+ },
79
+ };
package/src/index.js CHANGED
@@ -3,17 +3,19 @@ import { default as react } from './react.js';
3
3
  import { default as jest } from './jest.js';
4
4
  import { default as mdx } from './mdx.js';
5
5
  import { default as typescript } from './typescript.js';
6
- import { default as nodeImports } from './node-imports.js';
7
- import { default as viteImports } from './vite-imports.js';
8
- import { default as webpackImports } from './webpack-imports.js';
6
+ import { default as node } from './node.js';
7
+ import { default as vite } from './vite.js';
8
+ import { default as webpack } from './webpack.js';
9
+ import { default as imports } from './imports.js';
9
10
 
10
11
  export {
11
12
  mdx,
12
13
  jest,
13
14
  react,
15
+ node,
16
+ vite,
17
+ webpack,
18
+ imports,
14
19
  typescript,
15
20
  recommended,
16
- nodeImports,
17
- viteImports,
18
- webpackImports,
19
21
  };
package/src/jest.js CHANGED
@@ -2,8 +2,7 @@ import plugin from 'eslint-plugin-jest';
2
2
 
3
3
  export default {
4
4
  ...plugin.configs['flat/recommended'],
5
-
6
- files: ['**/*.{js,jsx,ts,tsx}'],
5
+ name: 'jest',
7
6
  files: [
8
7
  '**/test*/**/*.{js,jsx,ts,tsx}',
9
8
  '**/__tests__/**/*.{js,jsx,ts,tsx}',
package/src/mdx.js CHANGED
@@ -2,6 +2,7 @@ import * as mdx from 'eslint-plugin-mdx';
2
2
 
3
3
  const plugin = {
4
4
  ...mdx.flat,
5
+ name: 'mdx',
5
6
  files: ['**/*.mdx'],
6
7
  ignores: ['node_modules/**/*', '**/dist/**/*', '**/*.d.ts'],
7
8
  processor: mdx.createRemarkProcessor({
@@ -9,8 +10,9 @@ const plugin = {
9
10
  }),
10
11
  rules: {
11
12
  ...mdx.flat.rules,
12
- semi: 'off',
13
- 'no-undef': 'off',
13
+ // Note this seems to be causing
14
+ // issues in the resolve so disable it.
15
+ 'import/named': 'off',
14
16
  'no-unused-expressions': 'off',
15
17
  },
16
18
  };
@@ -1,16 +1,15 @@
1
- import * as plugin from 'eslint-plugin-import';
2
- import importRules from './importRules.js';
1
+ import globals from 'globals';
3
2
 
4
3
  export default {
5
- ...plugin.flatConfigs.recommended,
4
+ name: 'node',
6
5
  files: ['**/*.{js,jsx}'],
7
6
  ignores: ['node_modules/**/*', '**/dist/**/*', '**/*.d.ts'],
8
7
  languageOptions: {
9
8
  ecmaVersion: 'latest',
10
9
  sourceType: 'module',
11
10
  },
12
- rules: {
13
- ...importRules,
11
+ languageOptions: {
12
+ globals: globals.node,
14
13
  },
15
14
  settings: {
16
15
  'import/resolver': {
package/src/react.js CHANGED
@@ -1,7 +1,8 @@
1
1
  import react from 'eslint-plugin-react';
2
2
 
3
3
  export default {
4
- files: ['**/*.{js,jsx,ts,tsx}'],
4
+ name: 'react',
5
+ files: ['**/*.{js,jsx,ts,tsx,mdx}'],
5
6
  ignores: ['node_modules/**/*', '**/dist/**/*', '**/*.d.ts'],
6
7
  plugins: {
7
8
  react,
@@ -1,20 +1,14 @@
1
1
  import js from '@eslint/js';
2
- import globals from 'globals';
3
2
 
4
3
  export default {
5
- files: ['**/*.{js,jsx}'],
4
+ name: 'recommended',
6
5
  ignores: ['node_modules/**/*', '**/dist/**/*', '**/*.d.ts'],
7
6
  languageOptions: {
8
7
  ecmaVersion: 'latest',
9
8
  sourceType: 'module',
10
- globals: {
11
- ...globals.node,
12
- ...globals.browser,
13
- },
14
9
  },
15
10
  rules: {
16
11
  ...js.configs.recommended.rules,
17
- semi: 'error',
18
12
  'no-console': 'warn',
19
13
  curly: ['error', 'multi-line', 'consistent'],
20
14
  'no-unused-vars': [