@hubspot/eslint-config-ui-extensions 0.12.0 → 1.1.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.
- package/README.md +168 -24
- package/dist/__tests__/index.spec.d.ts +1 -0
- package/dist/__tests__/index.spec.js +303 -0
- package/dist/__tests__/rules/no-browser-dialogs.spec.d.ts +1 -0
- package/dist/__tests__/rules/no-browser-dialogs.spec.js +263 -0
- package/dist/__tests__/rules/no-browser-storage.spec.d.ts +1 -0
- package/dist/__tests__/rules/no-browser-storage.spec.js +428 -0
- package/dist/__tests__/rules/no-console.spec.d.ts +1 -0
- package/dist/__tests__/rules/no-console.spec.js +262 -0
- package/dist/__tests__/rules/no-dom-access.spec.d.ts +1 -0
- package/dist/__tests__/rules/no-dom-access.spec.js +288 -0
- package/dist/__tests__/rules/no-experimental-imports.spec.d.ts +1 -0
- package/dist/__tests__/rules/no-experimental-imports.spec.js +67 -0
- package/dist/__tests__/rules/no-html-elements.spec.d.ts +1 -0
- package/dist/__tests__/rules/no-html-elements.spec.js +142 -0
- package/dist/__tests__/rules/no-invalid-extension-point-imports.spec.d.ts +1 -0
- package/dist/__tests__/rules/no-invalid-extension-point-imports.spec.js +269 -0
- package/dist/__tests__/rules/no-invalid-image-src.spec.d.ts +1 -0
- package/dist/__tests__/rules/no-invalid-image-src.spec.js +227 -0
- package/dist/__tests__/rules/no-native-http.spec.d.ts +1 -0
- package/dist/__tests__/rules/no-native-http.spec.js +596 -0
- package/dist/__tests__/rules/no-parent-imports.spec.d.ts +1 -0
- package/dist/__tests__/rules/no-parent-imports.spec.js +337 -0
- package/dist/__tests__/rules/no-restricted-globals.spec.d.ts +1 -0
- package/dist/__tests__/rules/no-restricted-globals.spec.js +434 -0
- package/dist/__tests__/utils/ast-utils.spec.d.ts +1 -0
- package/dist/__tests__/utils/ast-utils.spec.js +297 -0
- package/dist/__tests__/utils/extension-point-utils.spec.d.ts +1 -0
- package/dist/__tests__/utils/extension-point-utils.spec.js +125 -0
- package/dist/__tests__/utils/import-utils.spec.d.ts +1 -0
- package/dist/__tests__/utils/import-utils.spec.js +176 -0
- package/dist/__tests__/utils/jsx-utils.spec.d.ts +1 -0
- package/dist/__tests__/utils/jsx-utils.spec.js +120 -0
- package/dist/__tests__/utils/scope-utils.spec.d.ts +1 -0
- package/dist/__tests__/utils/scope-utils.spec.js +80 -0
- package/dist/constants.d.ts +3 -0
- package/dist/constants.js +124 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +75 -0
- package/dist/rules/no-browser-dialogs.d.ts +2 -0
- package/dist/rules/no-browser-dialogs.js +62 -0
- package/dist/rules/no-browser-storage.d.ts +2 -0
- package/dist/rules/no-browser-storage.js +78 -0
- package/dist/rules/no-console.d.ts +2 -0
- package/dist/rules/no-console.js +78 -0
- package/dist/rules/no-dom-access.d.ts +2 -0
- package/dist/rules/no-dom-access.js +63 -0
- package/dist/rules/no-experimental-imports.d.ts +2 -0
- package/dist/rules/no-experimental-imports.js +29 -0
- package/dist/rules/no-html-elements.d.ts +2 -0
- package/dist/rules/no-html-elements.js +39 -0
- package/dist/rules/no-invalid-extension-point-imports.d.ts +2 -0
- package/dist/rules/no-invalid-extension-point-imports.js +54 -0
- package/dist/rules/no-invalid-image-src.d.ts +2 -0
- package/dist/rules/no-invalid-image-src.js +120 -0
- package/dist/rules/no-native-http.d.ts +2 -0
- package/dist/rules/no-native-http.js +70 -0
- package/dist/rules/no-parent-imports.d.ts +2 -0
- package/dist/rules/no-parent-imports.js +46 -0
- package/dist/rules/no-restricted-globals.d.ts +2 -0
- package/dist/rules/no-restricted-globals.js +132 -0
- package/dist/runtime.d.ts +2 -0
- package/dist/runtime.js +13 -0
- package/dist/utils/ast-utils.d.ts +42 -0
- package/dist/utils/ast-utils.js +79 -0
- package/dist/utils/extension-point-utils.d.ts +57 -0
- package/dist/utils/extension-point-utils.js +108 -0
- package/dist/utils/import-utils.d.ts +34 -0
- package/dist/utils/import-utils.js +52 -0
- package/dist/utils/jsx-utils.d.ts +30 -0
- package/dist/utils/jsx-utils.js +40 -0
- package/dist/utils/scope-utils.d.ts +30 -0
- package/dist/utils/scope-utils.js +66 -0
- package/package.json +43 -24
- package/CHANGELOG.md +0 -51
- package/eslintrc.js +0 -12
- package/lib/index.js +0 -57
- package/lib/runtime.js +0 -17
|
@@ -0,0 +1,434 @@
|
|
|
1
|
+
import { RuleTester } from 'eslint';
|
|
2
|
+
import tseslint from 'typescript-eslint';
|
|
3
|
+
import { noRestrictedGlobals } from "../../rules/no-restricted-globals.js";
|
|
4
|
+
import { languageOptions } from "../../runtime.js";
|
|
5
|
+
const ruleTester = new RuleTester({
|
|
6
|
+
languageOptions: {
|
|
7
|
+
...languageOptions,
|
|
8
|
+
parserOptions: {
|
|
9
|
+
ecmaVersion: 'latest',
|
|
10
|
+
sourceType: 'module',
|
|
11
|
+
ecmaFeatures: {
|
|
12
|
+
jsx: true,
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
});
|
|
17
|
+
const tsRuleTester = new RuleTester({
|
|
18
|
+
languageOptions: {
|
|
19
|
+
...languageOptions,
|
|
20
|
+
parser: tseslint.parser,
|
|
21
|
+
parserOptions: {
|
|
22
|
+
ecmaVersion: 'latest',
|
|
23
|
+
sourceType: 'module',
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
describe('no-restricted-globals', () => {
|
|
28
|
+
ruleTester.run('no-restricted-globals', noRestrictedGlobals, {
|
|
29
|
+
valid: [
|
|
30
|
+
{
|
|
31
|
+
name: 'allows importScripts as a local variable',
|
|
32
|
+
code: `
|
|
33
|
+
const importScripts = () => console.log('custom');
|
|
34
|
+
importScripts();
|
|
35
|
+
`,
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
name: 'allows addEventListener as a local variable',
|
|
39
|
+
code: `
|
|
40
|
+
const addEventListener = (event, handler) => {};
|
|
41
|
+
addEventListener('click', () => {});
|
|
42
|
+
`,
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
name: 'allows removeEventListener as a local variable',
|
|
46
|
+
code: `
|
|
47
|
+
const removeEventListener = (event, handler) => {};
|
|
48
|
+
removeEventListener('click', () => {});
|
|
49
|
+
`,
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
name: 'allows location as a local variable',
|
|
53
|
+
code: `
|
|
54
|
+
const location = { pathname: '/test' };
|
|
55
|
+
console.log(location.pathname);
|
|
56
|
+
`,
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
name: 'allows history as a local variable',
|
|
60
|
+
code: `
|
|
61
|
+
const history = { push: () => {} };
|
|
62
|
+
history.push('/new-path');
|
|
63
|
+
`,
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
name: 'allows location as a function parameter',
|
|
67
|
+
code: `
|
|
68
|
+
function navigate(location) {
|
|
69
|
+
return location.href;
|
|
70
|
+
}
|
|
71
|
+
`,
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
name: 'allows history as a destructured property',
|
|
75
|
+
code: `
|
|
76
|
+
const { history } = router;
|
|
77
|
+
history.push('/test');
|
|
78
|
+
`,
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
name: 'allows location as an object property',
|
|
82
|
+
code: `
|
|
83
|
+
const obj = { location: { href: '/test' } };
|
|
84
|
+
obj.location.href;
|
|
85
|
+
`,
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
name: 'allows addEventListener as an object method',
|
|
89
|
+
code: `
|
|
90
|
+
const emitter = {
|
|
91
|
+
addEventListener(event, handler) {}
|
|
92
|
+
};
|
|
93
|
+
emitter.addEventListener('event', () => {});
|
|
94
|
+
`,
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
name: 'allows property access on objects named after restricted globals',
|
|
98
|
+
code: `
|
|
99
|
+
const myObject = { location: {}, history: {} };
|
|
100
|
+
myObject.location.href;
|
|
101
|
+
myObject.history.push('/test');
|
|
102
|
+
`,
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
name: 'allows React component event props',
|
|
106
|
+
code: `
|
|
107
|
+
import { Button } from '@hubspot/ui-extensions';
|
|
108
|
+
function Component() {
|
|
109
|
+
return <Button onClick={() => {}}>Click</Button>;
|
|
110
|
+
}
|
|
111
|
+
`,
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
name: 'allows using context for location',
|
|
115
|
+
code: `
|
|
116
|
+
function Component({ context }) {
|
|
117
|
+
const currentPath = context.location.pathname;
|
|
118
|
+
return null;
|
|
119
|
+
}
|
|
120
|
+
`,
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
name: 'allows using actions for navigation',
|
|
124
|
+
code: `
|
|
125
|
+
function Component({ actions }) {
|
|
126
|
+
actions.openLink('/new-page');
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
129
|
+
`,
|
|
130
|
+
},
|
|
131
|
+
],
|
|
132
|
+
invalid: [
|
|
133
|
+
{
|
|
134
|
+
name: 'reports error for importScripts call',
|
|
135
|
+
code: `
|
|
136
|
+
importScripts('script.js');
|
|
137
|
+
`,
|
|
138
|
+
errors: [{ messageId: 'importScripts' }],
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
name: 'reports error for addEventListener call',
|
|
142
|
+
code: `
|
|
143
|
+
addEventListener('click', () => {});
|
|
144
|
+
`,
|
|
145
|
+
errors: [{ messageId: 'addEventListener' }],
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
name: 'reports error for removeEventListener call',
|
|
149
|
+
code: `
|
|
150
|
+
removeEventListener('click', handler);
|
|
151
|
+
`,
|
|
152
|
+
errors: [{ messageId: 'removeEventListener' }],
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
name: 'reports error for location access',
|
|
156
|
+
code: `
|
|
157
|
+
const path = location.pathname;
|
|
158
|
+
`,
|
|
159
|
+
errors: [{ messageId: 'location' }],
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
name: 'reports error for location.href',
|
|
163
|
+
code: `
|
|
164
|
+
console.log(location.href);
|
|
165
|
+
`,
|
|
166
|
+
errors: [{ messageId: 'location' }],
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
name: 'reports error for history access',
|
|
170
|
+
code: `
|
|
171
|
+
history.pushState({}, '', '/new-path');
|
|
172
|
+
`,
|
|
173
|
+
errors: [{ messageId: 'history' }],
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
name: 'reports error for history.back()',
|
|
177
|
+
code: `
|
|
178
|
+
history.back();
|
|
179
|
+
`,
|
|
180
|
+
errors: [{ messageId: 'history' }],
|
|
181
|
+
},
|
|
182
|
+
{
|
|
183
|
+
name: 'reports error for window.importScripts',
|
|
184
|
+
code: `
|
|
185
|
+
window.importScripts('script.js');
|
|
186
|
+
`,
|
|
187
|
+
errors: [{ messageId: 'importScripts' }],
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
name: 'reports error for window.addEventListener',
|
|
191
|
+
code: `
|
|
192
|
+
window.addEventListener('load', () => {});
|
|
193
|
+
`,
|
|
194
|
+
errors: [{ messageId: 'addEventListener' }],
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
name: 'reports error for window.removeEventListener',
|
|
198
|
+
code: `
|
|
199
|
+
window.removeEventListener('load', handler);
|
|
200
|
+
`,
|
|
201
|
+
errors: [{ messageId: 'removeEventListener' }],
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
name: 'reports error for window.location',
|
|
205
|
+
code: `
|
|
206
|
+
const url = window.location.href;
|
|
207
|
+
`,
|
|
208
|
+
errors: [{ messageId: 'location' }],
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
name: 'reports error for window.history',
|
|
212
|
+
code: `
|
|
213
|
+
window.history.pushState({}, '', '/path');
|
|
214
|
+
`,
|
|
215
|
+
errors: [{ messageId: 'history' }],
|
|
216
|
+
},
|
|
217
|
+
{
|
|
218
|
+
name: 'reports error for self.importScripts',
|
|
219
|
+
code: `
|
|
220
|
+
self.importScripts('worker-script.js');
|
|
221
|
+
`,
|
|
222
|
+
errors: [{ messageId: 'importScripts' }],
|
|
223
|
+
},
|
|
224
|
+
{
|
|
225
|
+
name: 'reports error for self.addEventListener',
|
|
226
|
+
code: `
|
|
227
|
+
self.addEventListener('message', (e) => {});
|
|
228
|
+
`,
|
|
229
|
+
errors: [{ messageId: 'addEventListener' }],
|
|
230
|
+
},
|
|
231
|
+
{
|
|
232
|
+
name: 'reports error for self.location',
|
|
233
|
+
code: `
|
|
234
|
+
console.log(self.location.href);
|
|
235
|
+
`,
|
|
236
|
+
errors: [{ messageId: 'location' }],
|
|
237
|
+
},
|
|
238
|
+
{
|
|
239
|
+
name: 'reports error for globalThis.importScripts',
|
|
240
|
+
code: `
|
|
241
|
+
globalThis.importScripts('script.js');
|
|
242
|
+
`,
|
|
243
|
+
errors: [{ messageId: 'importScripts' }],
|
|
244
|
+
},
|
|
245
|
+
{
|
|
246
|
+
name: 'reports error for globalThis.addEventListener',
|
|
247
|
+
code: `
|
|
248
|
+
globalThis.addEventListener('click', () => {});
|
|
249
|
+
`,
|
|
250
|
+
errors: [{ messageId: 'addEventListener' }],
|
|
251
|
+
},
|
|
252
|
+
{
|
|
253
|
+
name: 'reports error for globalThis.location',
|
|
254
|
+
code: `
|
|
255
|
+
const href = globalThis.location.href;
|
|
256
|
+
`,
|
|
257
|
+
errors: [{ messageId: 'location' }],
|
|
258
|
+
},
|
|
259
|
+
{
|
|
260
|
+
name: 'reports error for globalThis.history',
|
|
261
|
+
code: `
|
|
262
|
+
globalThis.history.back();
|
|
263
|
+
`,
|
|
264
|
+
errors: [{ messageId: 'history' }],
|
|
265
|
+
},
|
|
266
|
+
{
|
|
267
|
+
name: 'reports error for bracket notation window["location"]',
|
|
268
|
+
code: `
|
|
269
|
+
const path = window['location'].pathname;
|
|
270
|
+
`,
|
|
271
|
+
errors: [{ messageId: 'location' }],
|
|
272
|
+
},
|
|
273
|
+
{
|
|
274
|
+
name: 'reports error for bracket notation self["addEventListener"]',
|
|
275
|
+
code: `
|
|
276
|
+
self['addEventListener']('message', handler);
|
|
277
|
+
`,
|
|
278
|
+
errors: [{ messageId: 'addEventListener' }],
|
|
279
|
+
},
|
|
280
|
+
{
|
|
281
|
+
name: 'reports error for bracket notation globalThis["location"]',
|
|
282
|
+
code: `
|
|
283
|
+
const path = globalThis['location'].pathname;
|
|
284
|
+
`,
|
|
285
|
+
errors: [{ messageId: 'location' }],
|
|
286
|
+
},
|
|
287
|
+
{
|
|
288
|
+
name: 'reports error in React component',
|
|
289
|
+
code: `
|
|
290
|
+
import { Text } from '@hubspot/ui-extensions';
|
|
291
|
+
function Component() {
|
|
292
|
+
const path = location.pathname;
|
|
293
|
+
return <Text>{path}</Text>;
|
|
294
|
+
}
|
|
295
|
+
`,
|
|
296
|
+
errors: [{ messageId: 'location' }],
|
|
297
|
+
},
|
|
298
|
+
{
|
|
299
|
+
name: 'reports error in async function',
|
|
300
|
+
code: `
|
|
301
|
+
async function loadScript() {
|
|
302
|
+
importScripts('script.js');
|
|
303
|
+
}
|
|
304
|
+
`,
|
|
305
|
+
errors: [{ messageId: 'importScripts' }],
|
|
306
|
+
},
|
|
307
|
+
{
|
|
308
|
+
name: 'reports error in arrow function',
|
|
309
|
+
code: `
|
|
310
|
+
const getPath = () => location.pathname;
|
|
311
|
+
`,
|
|
312
|
+
errors: [{ messageId: 'location' }],
|
|
313
|
+
},
|
|
314
|
+
{
|
|
315
|
+
name: 'reports error in class method',
|
|
316
|
+
code: `
|
|
317
|
+
class Navigation {
|
|
318
|
+
navigate() {
|
|
319
|
+
history.pushState({}, '', '/test');
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
`,
|
|
323
|
+
errors: [{ messageId: 'history' }],
|
|
324
|
+
},
|
|
325
|
+
{
|
|
326
|
+
name: 'reports multiple errors for different restricted globals',
|
|
327
|
+
code: `
|
|
328
|
+
const path = location.pathname;
|
|
329
|
+
history.pushState({}, '', path);
|
|
330
|
+
addEventListener('popstate', () => {});
|
|
331
|
+
`,
|
|
332
|
+
errors: [
|
|
333
|
+
{ messageId: 'location' },
|
|
334
|
+
{ messageId: 'history' },
|
|
335
|
+
{ messageId: 'addEventListener' },
|
|
336
|
+
],
|
|
337
|
+
},
|
|
338
|
+
{
|
|
339
|
+
name: 'reports error in nested scopes',
|
|
340
|
+
code: `
|
|
341
|
+
function outer() {
|
|
342
|
+
function inner() {
|
|
343
|
+
return location.href;
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
`,
|
|
347
|
+
errors: [{ messageId: 'location' }],
|
|
348
|
+
},
|
|
349
|
+
{
|
|
350
|
+
name: 'reports error in try/catch block',
|
|
351
|
+
code: `
|
|
352
|
+
try {
|
|
353
|
+
const path = location.pathname;
|
|
354
|
+
} catch (e) {
|
|
355
|
+
console.error(e);
|
|
356
|
+
}
|
|
357
|
+
`,
|
|
358
|
+
errors: [{ messageId: 'location' }],
|
|
359
|
+
},
|
|
360
|
+
{
|
|
361
|
+
name: 'reports error in conditional',
|
|
362
|
+
code: `
|
|
363
|
+
if (location.pathname === '/test') {
|
|
364
|
+
console.log('test page');
|
|
365
|
+
}
|
|
366
|
+
`,
|
|
367
|
+
errors: [{ messageId: 'location' }],
|
|
368
|
+
},
|
|
369
|
+
],
|
|
370
|
+
});
|
|
371
|
+
tsRuleTester.run('no-restricted-globals (TypeScript)', noRestrictedGlobals, {
|
|
372
|
+
valid: [
|
|
373
|
+
{
|
|
374
|
+
name: 'allows location type in type alias',
|
|
375
|
+
code: `
|
|
376
|
+
type LocationType = typeof location;
|
|
377
|
+
`,
|
|
378
|
+
},
|
|
379
|
+
{
|
|
380
|
+
name: 'allows history type in interface property',
|
|
381
|
+
code: `
|
|
382
|
+
interface Router {
|
|
383
|
+
history: typeof history;
|
|
384
|
+
}
|
|
385
|
+
`,
|
|
386
|
+
},
|
|
387
|
+
{
|
|
388
|
+
name: 'allows addEventListener type in function return type',
|
|
389
|
+
code: `
|
|
390
|
+
function getListener(): typeof addEventListener {
|
|
391
|
+
return () => {};
|
|
392
|
+
}
|
|
393
|
+
`,
|
|
394
|
+
},
|
|
395
|
+
{
|
|
396
|
+
name: 'allows Location type references',
|
|
397
|
+
code: `
|
|
398
|
+
interface CustomLocation extends Location {
|
|
399
|
+
customProp: string;
|
|
400
|
+
}
|
|
401
|
+
`,
|
|
402
|
+
},
|
|
403
|
+
],
|
|
404
|
+
invalid: [
|
|
405
|
+
{
|
|
406
|
+
name: 'reports error for location usage even after type declarations',
|
|
407
|
+
code: `
|
|
408
|
+
type LocationType = typeof location;
|
|
409
|
+
|
|
410
|
+
function getPath() {
|
|
411
|
+
return location.pathname;
|
|
412
|
+
}
|
|
413
|
+
`,
|
|
414
|
+
errors: [{ messageId: 'location' }],
|
|
415
|
+
},
|
|
416
|
+
{
|
|
417
|
+
name: 'reports error for history in TypeScript with explicit types',
|
|
418
|
+
code: `
|
|
419
|
+
const state: any = {};
|
|
420
|
+
history.pushState(state, '', '/test');
|
|
421
|
+
`,
|
|
422
|
+
errors: [{ messageId: 'history' }],
|
|
423
|
+
},
|
|
424
|
+
{
|
|
425
|
+
name: 'reports error for addEventListener with typed handler',
|
|
426
|
+
code: `
|
|
427
|
+
const handler: EventListener = (e) => console.log(e);
|
|
428
|
+
addEventListener('click', handler);
|
|
429
|
+
`,
|
|
430
|
+
errors: [{ messageId: 'addEventListener' }],
|
|
431
|
+
},
|
|
432
|
+
],
|
|
433
|
+
});
|
|
434
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|