Skip to content

Commit 92549e8

Browse files
committed
Discourage npm packages with native alternatives
Fixes xojs/xo#550
1 parent 9117295 commit 92549e8

4 files changed

Lines changed: 191 additions & 33 deletions

File tree

source/javascript-rules.js

Lines changed: 3 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import {restrictedImports} from './restricted-imports.js';
2+
13
export const javascriptRules = {
24
'@stylistic/comma-dangle': [
35
'error',
@@ -247,25 +249,7 @@ export const javascriptRules = {
247249
},
248250
],
249251
'no-buffer-constructor': 'error',
250-
'no-restricted-imports': [
251-
'error',
252-
'domain',
253-
'freelist',
254-
'smalloc',
255-
'punycode',
256-
'sys',
257-
'querystring',
258-
'colors',
259-
// TODO: Enable this in 2028.
260-
// {
261-
// name: 'buffer',
262-
// message: 'Use Uint8Array instead. See: https://sindresorhus.com/blog/goodbye-nodejs-buffer',
263-
// },
264-
// {
265-
// name: 'node:buffer',
266-
// message: 'Use Uint8Array instead. See: https://sindresorhus.com/blog/goodbye-nodejs-buffer',
267-
// },
268-
],
252+
'no-restricted-imports': ['error', ...restrictedImports],
269253
'@stylistic/array-bracket-newline': [
270254
'error',
271255
'consistent',

source/restricted-imports.js

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
export const restrictedImports = [
2+
'domain',
3+
'freelist',
4+
'smalloc',
5+
'punycode',
6+
'sys',
7+
'querystring',
8+
'colors',
9+
// TODO: Enable this in 2028.
10+
// {
11+
// name: 'buffer',
12+
// message: 'Use Uint8Array instead. See: https://sindresorhus.com/blog/goodbye-nodejs-buffer',
13+
// },
14+
// {
15+
// name: 'node:buffer',
16+
// message: 'Use Uint8Array instead. See: https://sindresorhus.com/blog/goodbye-nodejs-buffer',
17+
// },
18+
{
19+
name: 'mkdirp',
20+
message: 'Use `fs.mkdir` with `{recursive: true}` instead.',
21+
},
22+
{
23+
name: 'rimraf',
24+
message: 'Use `fs.rm` with `{recursive: true}` instead.',
25+
},
26+
{
27+
name: 'object-assign',
28+
message: 'Use `Object.assign()` or object spread instead.',
29+
},
30+
{
31+
name: 'xtend',
32+
message: 'Use `Object.assign()` or object spread instead.',
33+
},
34+
{
35+
name: 'extend-shallow',
36+
message: 'Use `Object.assign()` or object spread instead.',
37+
},
38+
{
39+
name: 'left-pad',
40+
message: 'Use `String.prototype.padStart()` instead.',
41+
},
42+
{
43+
name: 'pad-left',
44+
message: 'Use `String.prototype.padStart()` instead.',
45+
},
46+
{
47+
name: 'right-pad',
48+
message: 'Use `String.prototype.padEnd()` instead.',
49+
},
50+
{
51+
name: 'pad-right',
52+
message: 'Use `String.prototype.padEnd()` instead.',
53+
},
54+
{
55+
name: 'safe-buffer',
56+
message: 'Use `Buffer.alloc()` or `Buffer.from()` instead.',
57+
},
58+
{
59+
name: 'safer-buffer',
60+
message: 'Use `Buffer.alloc()` or `Buffer.from()` instead.',
61+
},
62+
{
63+
name: 'buffer-alloc',
64+
message: 'Use `Buffer.alloc()` instead.',
65+
},
66+
{
67+
name: 'array-flatten',
68+
message: 'Use `Array.prototype.flat()` instead.',
69+
},
70+
{
71+
name: 'concat-map',
72+
message: 'Use `Array.prototype.flatMap()` instead.',
73+
},
74+
{
75+
name: 'pad',
76+
message: 'Use `String.prototype.padStart()` / `String.prototype.padEnd()` instead.',
77+
},
78+
{
79+
name: 'co',
80+
message: 'Use async/await instead.',
81+
},
82+
{
83+
name: 'inherits',
84+
message: 'Use `class extends` instead.',
85+
},
86+
{
87+
name: 'windows-1252',
88+
message: 'Use `TextDecoder` instead.',
89+
},
90+
{
91+
name: 'string_decoder',
92+
message: 'Use `TextDecoder` instead.',
93+
},
94+
{
95+
name: 'isarray',
96+
message: 'Use `Array.isArray()` instead.',
97+
},
98+
{
99+
name: 'object-keys',
100+
message: 'Use `Object.keys()` instead.',
101+
},
102+
{
103+
name: 'object.assign',
104+
message: 'Use `Object.assign()` or object spread instead.',
105+
},
106+
{
107+
name: 'globalthis',
108+
message: 'Use the `globalThis` global instead.',
109+
},
110+
{
111+
name: 'es6-promise',
112+
message: 'Use `Promise` instead.',
113+
},
114+
{
115+
name: 'abort-controller',
116+
message: 'Use the native `AbortController` instead.',
117+
},
118+
{
119+
name: 'queue-microtask',
120+
message: 'Use `queueMicrotask()` instead.',
121+
},
122+
{
123+
name: 'buffer-from',
124+
message: 'Use `Buffer.from()` instead.',
125+
},
126+
{
127+
name: 'has',
128+
message: 'Use `Object.hasOwn()` instead.',
129+
},
130+
{
131+
name: 'hasown',
132+
message: 'Use `Object.hasOwn()` instead.',
133+
},
134+
{
135+
name: 'repeat-string',
136+
message: 'Use `String.prototype.repeat()` instead.',
137+
},
138+
{
139+
name: 'path-parse',
140+
message: 'Use `path.parse()` instead.',
141+
},
142+
{
143+
name: 'node.extend',
144+
message: 'Use `Object.assign()` or object spread instead.',
145+
},
146+
{
147+
name: 'aggregate-error',
148+
message: 'Use the native `AggregateError` instead.',
149+
},
150+
{
151+
name: 'is-nan',
152+
message: 'Use `Number.isNaN()` instead.',
153+
},
154+
{
155+
name: 'is-finite',
156+
message: 'Use `Number.isFinite()` instead.',
157+
},
158+
{
159+
name: 'object-is',
160+
message: 'Use `Object.is()` instead.',
161+
},
162+
{
163+
name: 'defaults',
164+
message: 'Use `Object.assign()` instead.',
165+
},
166+
{
167+
name: 'whatwg-url',
168+
message: 'Use the native `URL` API instead.',
169+
},
170+
// TODO: Enable when targeting Node.js 24+.
171+
// {
172+
// name: 'escape-string-regexp',
173+
// message: 'Use `RegExp.escape()` instead.',
174+
// },
175+
];

source/typescript-rules.js

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import {restrictedImports} from './restricted-imports.js';
2+
13
export const getNamingConventionRule = ({isTsx}) => ({
24
'@typescript-eslint/naming-convention': [
35
'error',
@@ -424,20 +426,7 @@ export const typescriptRules = {
424426
},
425427
],
426428
'no-restricted-imports': 'off',
427-
'@typescript-eslint/no-restricted-imports': [
428-
'error',
429-
{
430-
paths: [
431-
'domain',
432-
'freelist',
433-
'smalloc',
434-
'punycode',
435-
'sys',
436-
'querystring',
437-
'colors',
438-
],
439-
},
440-
],
429+
'@typescript-eslint/no-restricted-imports': ['error', {paths: [...restrictedImports]}],
441430

442431
// The rule is buggy and keeps inferring `any` for types that are not `any`. Just a lot of false-positives.
443432
// '@typescript-eslint/no-redundant-type-constituents': 'error',

test/test.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,16 @@ test('typescript', async t => {
4040
t.true(hasRule(errors, '@typescript-eslint/no-inferrable-types'));
4141
});
4242

43+
test('restricted imports', async t => {
44+
const errors = await runEslint('import objectAssign from \'object-assign\';\n', eslintConfigXo());
45+
t.true(hasRule(errors, 'no-restricted-imports'));
46+
});
47+
48+
test('restricted imports - typescript', async t => {
49+
const errors = await runEslint('import objectAssign from \'object-assign\';\n', eslintConfigXo(), {filePath: 'test/fixture.ts'});
50+
t.true(hasRule(errors, '@typescript-eslint/no-restricted-imports'));
51+
});
52+
4353
test('space', async t => {
4454
const fixture = `
4555
export function foo() {

0 commit comments

Comments
 (0)