Skip to content

Commit c99bdbd

Browse files
committed
Add cross-platform lint config
1 parent 8cec896 commit c99bdbd

File tree

4 files changed

+170
-1
lines changed

4 files changed

+170
-1
lines changed

.changeset/nice-dots-clap.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@nullvoxpopuli/eslint-configs': minor
3+
---
4+
5+
Add crossPlatform config. This is considered beta for now, and is not explicitly under SemVer at this time

README.md

+16-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ ESLint has grown complicated for projects with variance:
66
- JavaScript or TypeScript
77
- Node or Browser
88
- App or Library
9+
- Cross-Platform
910
- etc
1011

1112
This project aims to simplify both configuring and overriding ESLint configs.
@@ -98,6 +99,20 @@ module.exports = {
9899
}
99100
```
100101

102+
**Cross-Platform**
103+
104+
This config is ESM, as ESM is the most widely supported module format across different distributions (browser, node, etc).
105+
106+
```js
107+
// .eslintrc.cjs
108+
'use strict';
109+
110+
const { configs } = require('@nullvoxpopuli/eslint-configs');
111+
112+
// accommodates: JS, TS, ESM, and CJS
113+
module.exports = configs.crossPlatform();
114+
```
115+
101116
**Node**
102117

103118
This config looks at your package.json to determine if your project is CommonJS or ES Modules.
@@ -107,7 +122,7 @@ This config looks at your package.json to determine if your project is CommonJS
107122

108123
const { configs } = require('@nullvoxpopuli/eslint-configs');
109124

110-
// accommodates: JS
125+
// accommodates: JS, TS, ESM, and CJS
111126
module.exports = configs.node();
112127
```
113128

configs/cross-platform.js

+142
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
'use strict';
2+
3+
const path = require('path');
4+
5+
const { hasDep, configFor, pipe, merge, forFiles } = require('./-utils');
6+
7+
/**
8+
* @param {import('./types').Options} options
9+
*/
10+
const configBuilder = (options = {}) => {
11+
let hasTypeScript = hasDep('typescript');
12+
13+
let personalPreferences = pipe({}, (config) => merge(config, require('./base').base));
14+
15+
if (options.prettierIntegration) {
16+
personalPreferences = merge(personalPreferences, require('./rules/prettier').resolveRule());
17+
}
18+
19+
return {
20+
modules: {
21+
get js() {
22+
return pipe(
23+
{
24+
parserOptions: {
25+
sourceType: 'module',
26+
ecmaVersion: 'latest',
27+
},
28+
env: {
29+
browser: false,
30+
node: true,
31+
es6: true,
32+
},
33+
plugins: ['n'],
34+
extends: ['plugin:n/recommended'],
35+
},
36+
(config) => merge(config, personalPreferences),
37+
(config) => merge(config, require('./rules/imports'))
38+
);
39+
},
40+
get ts() {
41+
if (!hasTypeScript) return;
42+
43+
return pipe(
44+
{
45+
parserOptions: {
46+
sourceType: 'module',
47+
ecmaVersion: 'latest',
48+
},
49+
env: {
50+
browser: false,
51+
node: true,
52+
es6: true,
53+
},
54+
plugins: ['n'],
55+
extends: ['plugin:n/recommended', 'plugin:import/typescript'],
56+
},
57+
(config) => merge(config, personalPreferences),
58+
(config) => merge(config, require('./rules/imports')),
59+
(config) => merge(config, require('./rules/typescript'))
60+
);
61+
},
62+
},
63+
commonjs: {
64+
get js() {
65+
return pipe(
66+
{
67+
parserOptions: {
68+
sourceType: 'script',
69+
ecmaVersion: 'latest',
70+
},
71+
env: {
72+
browser: false,
73+
node: true,
74+
es6: true,
75+
},
76+
plugins: ['n'],
77+
extends: ['plugin:n/recommended'],
78+
},
79+
(config) => merge(config, personalPreferences),
80+
(config) => merge(config, require('./rules/imports'))
81+
);
82+
},
83+
get ts() {
84+
let hasTypeScript = hasDep('typescript');
85+
86+
if (!hasTypeScript) return;
87+
88+
return pipe(
89+
{
90+
parserOptions: {
91+
sourceType: 'script',
92+
ecmaVersion: 'latest',
93+
},
94+
env: {
95+
browser: false,
96+
node: true,
97+
es6: true,
98+
},
99+
plugins: ['n'],
100+
extends: ['plugin:n/recommended', 'plugin:import/typescript'],
101+
},
102+
(config) => merge(config, personalPreferences),
103+
(config) => merge(config, require('./rules/imports')),
104+
(config) => merge(config, require('./rules/typescript'))
105+
);
106+
},
107+
},
108+
get tests() {
109+
return {
110+
rules: {
111+
// devDependencies
112+
'n/no-unpublished-import': 'off',
113+
// side-effects are... fine?
114+
'import/no-unassigned-import': 'off',
115+
},
116+
};
117+
},
118+
get config() {
119+
return {
120+
rules: {
121+
// devDependencies
122+
'n/no-unpublished-import': 'off',
123+
},
124+
};
125+
},
126+
};
127+
};
128+
129+
function crossPlatform(options = {}) {
130+
let config = configBuilder(options);
131+
132+
return configFor([
133+
forFiles('**/*.cjs', config.commonjs.js),
134+
forFiles('**/*.cts', config.commonjs.ts),
135+
forFiles('**/*.{mts,ts}', config.modules.ts),
136+
forFiles('**/*.{mjs,js}', config.modules.js),
137+
forFiles('config/**/*', config.config),
138+
forFiles(['vitest.config.ts', 'tests/**/*'], config.tests),
139+
]);
140+
}
141+
142+
module.exports = crossPlatform;

index.js

+7
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,13 @@ module.exports = {
1414
ember(options = {}) {
1515
return require('./configs/ember')(options);
1616
},
17+
/**
18+
* @param {import('./configs/types').Options} [ options ]
19+
* @returns {import('eslint').Linter.Config}
20+
*/
21+
crossPlatform(options = {}) {
22+
return require('./configs/cross-platform')(options)
23+
},
1724
/**
1825
* @param {import('./configs/types').Options} [ options ]
1926
* @returns {import('eslint').Linter.Config}

0 commit comments

Comments
 (0)