Skip to content

Commit 6cba0ae

Browse files
committed
build: add eslint.config.cjs for JavaScript targets on ESLint v8
Add flat config alongside the legacy `.eslintrc.*` configuration: - Create `eslint.config.cjs` with base JS config, override blocks for benchmarks, examples, tests, and REPL namespace files - Inline stdlib rules as a runtime plugin object via `lib/node_modules/@stdlib/_tools/eslint/rules/scripts/plugin.js` - Reuse existing rule definitions from `etc/eslint/rules/` - Separate non-clonable rule options (remark plugin instances) from the main rules object to work around `structuredClone` limitations in ESLint's flat config internals - Add `globals` package for flat config environment definitions - Legacy `.eslintrc.*` files remain in place as the default workflow Usage (requires ESLint v8 with flat config enabled): ESLINT_USE_FLAT_CONFIG=true npx eslint -c eslint.config.cjs <file> Note: files under `lib/node_modules/` are hard-ignored by ESLint v8 flat config. Full `lib/` linting via flat config requires ESLint v9, which allows `!**/node_modules/` ignore overrides. Ref: stdlib-js/metr-issue-tracker#54
1 parent 7bbb777 commit 6cba0ae

File tree

2 files changed

+164
-1
lines changed

2 files changed

+164
-1
lines changed

eslint.config.cjs

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
/**
2+
* @license Apache-2.0
3+
*
4+
* Copyright (c) 2026 The Stdlib Authors.
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
'use strict';
20+
21+
// MODULES //
22+
23+
var globals = require( 'globals' );
24+
var pluginN = require( 'eslint-plugin-n' );
25+
var pluginCspell = require( '@cspell/eslint-plugin' );
26+
var pluginJsdoc = require( 'eslint-plugin-jsdoc' );
27+
var stdlibPlugin = require( './lib/node_modules/@stdlib/_tools/eslint/rules/scripts/plugin.js' );
28+
var allRules = require( './etc/eslint/rules' );
29+
var overrides = require( './etc/eslint/overrides' );
30+
31+
32+
// VARIABLES //
33+
34+
var restrictedSyntaxConfig = overrides[ 1 ].rules[ 'no-restricted-syntax' ];
35+
var nonClonableRules = {};
36+
var rules = {};
37+
var val;
38+
var key;
39+
var i;
40+
41+
42+
// FUNCTIONS //
43+
44+
/**
45+
* Tests whether a value can be structured-cloned.
46+
*
47+
* @private
48+
* @param {*} value - value to test
49+
* @returns {boolean} boolean indicating whether the value is clonable
50+
*/
51+
function isClonable( value ) {
52+
try {
53+
// eslint-disable-next-line n/no-unsupported-features/es-builtins
54+
if ( typeof structuredClone === 'function' ) {
55+
structuredClone( value );
56+
}
57+
return true;
58+
} catch ( e ) {
59+
return false;
60+
}
61+
}
62+
63+
64+
// MAIN //
65+
66+
// Separate rules that contain non-clonable values (e.g., remark plugin
67+
// instances) because ESLint flat config internally clones config objects:
68+
for ( key in allRules ) {
69+
val = allRules[ key ];
70+
if ( isClonable( val ) ) {
71+
rules[ key ] = val;
72+
} else {
73+
nonClonableRules[ key ] = val;
74+
}
75+
}
76+
77+
module.exports = [
78+
// Global ignores:
79+
{
80+
'ignores': [
81+
'**/build/',
82+
'**/reports/',
83+
'dist/',
84+
'.git*'
85+
]
86+
},
87+
88+
// Base JavaScript config:
89+
{
90+
'files': [ '**/*.js' ],
91+
'languageOptions': {
92+
'ecmaVersion': 6,
93+
'sourceType': 'script',
94+
'globals': {
95+
...globals.browser,
96+
...globals.node,
97+
...globals.commonjs,
98+
...globals.worker
99+
}
100+
},
101+
'plugins': {
102+
'n': pluginN,
103+
'jsdoc': pluginJsdoc,
104+
'@cspell': pluginCspell,
105+
'stdlib': stdlibPlugin
106+
},
107+
'rules': rules
108+
},
109+
110+
// REPL namespace files:
111+
{
112+
'files': [ '**/lib/node_modules/@stdlib/**/lib/[a-z].js' ],
113+
'rules': {
114+
'stdlib/repl-namespace-order': 'error'
115+
}
116+
},
117+
118+
// Benchmarks:
119+
{
120+
'files': [ '**/benchmark/**/*.js' ],
121+
'rules': {
122+
'no-new-wrappers': 'warn',
123+
'max-lines': [ 'warn', {
124+
'max': 1000,
125+
'skipBlankLines': true,
126+
'skipComments': true
127+
}],
128+
'jsdoc/require-jsdoc': 'off',
129+
'no-restricted-syntax': restrictedSyntaxConfig
130+
}
131+
},
132+
133+
// Examples:
134+
{
135+
'files': [ '**/examples/**/*.js' ],
136+
'rules': {
137+
'no-console': 'off',
138+
'vars-on-top': 'off',
139+
'jsdoc/require-jsdoc': 'off',
140+
'stdlib/jsdoc-private-annotation': 'off',
141+
'stdlib/require-order': 'off',
142+
'stdlib/require-file-extensions': 'off',
143+
'no-restricted-syntax': restrictedSyntaxConfig
144+
}
145+
},
146+
147+
// Tests:
148+
{
149+
'files': [ '**/test/**/*.js' ],
150+
'rules': {
151+
'no-empty-function': 'off',
152+
'jsdoc/require-jsdoc': 'off',
153+
'no-undefined': 'off',
154+
'max-lines': [ 'warn', {
155+
'max': 1000,
156+
'skipBlankLines': true,
157+
'skipComments': true
158+
}],
159+
'no-restricted-syntax': restrictedSyntaxConfig
160+
}
161+
}
162+
];

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,12 +139,13 @@
139139
"doctrine": "^3.0.0",
140140
"editorconfig-checker": "^6.0.0",
141141
"envify": "^4.0.0",
142-
"@stylistic/eslint-plugin-ts": "^4.2.0",
142+
"@stylistic/eslint-plugin-ts": "^2.13.0",
143143
"eslint": "^8.57.0",
144144
"eslint-plugin-n": "^17.17.0",
145145
"eslint-plugin-expect-type": "^0.2.3",
146146
"eslint-plugin-import": "^2.29.0",
147147
"eslint-plugin-jsdoc": "^46.8.2",
148+
"globals": "^16.1.0",
148149
"exorcist": "^2.0.0",
149150
"factor-bundle": "^2.5.0",
150151
"gh-pages": "git+https://github.com/Planeshifter/gh-pages.git#main",

0 commit comments

Comments
 (0)