eslint-plugin-stratified-design 0.12.6 → 0.12.8

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.
@@ -121,6 +121,26 @@ module.exports = {
121
121
  fileDir,
122
122
  createAliases(options.aliases)
123
123
  );
124
+ const report = (node, pathSearcher) => {
125
+ const [theMember, theImportSpec] = options.imports.reduce(
126
+ pathSearcher,
127
+ [undefined, undefined]
128
+ );
129
+ if (!theMember || !theImportSpec) return;
130
+
131
+ const { allow, disallow } = theImportSpec;
132
+ const fileSourceFromCwd = fromCwd(context.cwd, fileSource);
133
+ const isAllowed =
134
+ (allow ? Boolean(allow.find(match(fileSourceFromCwd))) : true) &&
135
+ (disallow ? !disallow.find(match(fileSourceFromCwd)) : true);
136
+ if (isAllowed) return;
137
+
138
+ context.report({
139
+ node,
140
+ messageId: "no-disallowed-imports",
141
+ data: { member: theMember, from: theImportSpec.import.from },
142
+ });
143
+ }
124
144
  return {
125
145
  ImportDeclaration(node) {
126
146
  const modulePath = createModulePath(node.source.value);
@@ -168,26 +188,63 @@ module.exports = {
168
188
 
169
189
  return [undefined, undefined];
170
190
  };
191
+ report(node, searchTheImportPath)
192
+ },
193
+ ExportNamedDeclaration(node) {
194
+ if (!node.source) return
195
+ const modulePath = createModulePath(node.source.value);
196
+ /**
197
+ * @param {[string | undefined, ImportPath | undefined]} param0
198
+ * @param {ImportPath} importSpec
199
+ */
200
+ const searchTheImportPath = ([theMember, theImportSpec], importSpec) => {
201
+ if (theMember && theImportSpec) return [theMember, theImportSpec];
202
+
203
+ const isModulePathMatched = match(fromCwd(context.cwd, modulePath))(importSpec.import.from)
171
204
 
172
- const [theMember, theImportSpec] = options.imports.reduce(
173
- searchTheImportPath,
174
- [undefined, undefined]
175
- );
176
- if (!theMember || !theImportSpec) return;
177
-
178
- const { allow, disallow } = theImportSpec;
179
- const fileSourceFromCwd = fromCwd(context.cwd, fileSource);
180
- const isAllowed =
181
- (allow ? Boolean(allow.find(match(fileSourceFromCwd))) : true) &&
182
- (disallow ? !disallow.find(match(fileSourceFromCwd)) : true);
183
- if (isAllowed) return;
184
-
185
- context.report({
186
- node,
187
- messageId: "no-disallowed-imports",
188
- data: { member: theMember, from: theImportSpec.import.from },
189
- });
205
+ if (importSpec.import.member === ANY_MEMBER) {
206
+ return isModulePathMatched ? ['Any member', importSpec] : [undefined, undefined]
207
+ }
208
+
209
+ const exportedSpecifiers = node.specifiers.map((specifier) => {
210
+ if (specifier.type === "ExportSpecifier") return specifier.exported.name;
211
+ return "";
212
+ });
213
+
214
+ const member = importSpec.import.member.find((specifier) =>
215
+ exportedSpecifiers.some((sp) => sp === specifier)
216
+ );
217
+
218
+ if (member && isModulePathMatched) return [`'${member}'`, importSpec];
219
+ return [undefined, undefined];
220
+ }
221
+ report(node, searchTheImportPath)
190
222
  },
223
+ ExportAllDeclaration(node) {
224
+ if (!node.source) return
225
+ const modulePath = createModulePath(node.source.value);
226
+ /**
227
+ * @param {[string | undefined, ImportPath | undefined]} param0
228
+ * @param {ImportPath} importSpec
229
+ */
230
+ const searchTheImportPath = ([theMember, theImportSpec], importSpec) => {
231
+ if (theMember && theImportSpec) return [theMember, theImportSpec];
232
+
233
+ const isModulePathMatched = match(fromCwd(context.cwd, modulePath))(importSpec.import.from)
234
+
235
+ if (importSpec.import.member === ANY_MEMBER) {
236
+ return isModulePathMatched ? ['Any member', importSpec] : [undefined, undefined]
237
+ }
238
+
239
+ if (importSpec.import.member.includes(NAMESPACE) && isModulePathMatched) {
240
+ if (!node.exported) return [`'${NAMESPACE}'`, importSpec]
241
+ return [`'${node.exported.name}'`, importSpec]
242
+
243
+ }
244
+ return [undefined, undefined];
245
+ }
246
+ report(node, searchTheImportPath)
247
+ }
191
248
  };
192
249
  },
193
250
  };
@@ -111,6 +111,31 @@ const deriveVarName = (nodeOrToken, levels) => {
111
111
  }
112
112
  };
113
113
 
114
+ const or = (...args) => {
115
+ for (const arg of args) {
116
+ try {
117
+ const result = arg();
118
+ if (result) return result;
119
+ else continue;
120
+ } catch (e) {
121
+ continue;
122
+ }
123
+ }
124
+ return undefined;
125
+ };
126
+
127
+ const deriveNames = (nodeOrToken) => {
128
+ const declaration = deriveDeclaration(nodeOrToken);
129
+ const names = or(
130
+ () => declaration.id.name,
131
+ () => declaration.declarations[0].id.name,
132
+ () => declaration.declarations[0].id.elements.map(({ name }) => name),
133
+ () =>
134
+ declaration.declarations[0].id.properties.map(({ value }) => value.name)
135
+ );
136
+ return names === undefined ? [] : Array.isArray(names) ? names : [names];
137
+ };
138
+
114
139
  /**
115
140
  * @param {SourceCode} sourceCode
116
141
  * @param {Node | Token} nodeOrToken
@@ -243,12 +268,9 @@ module.exports = {
243
268
  return {
244
269
  Program(node) {
245
270
  node.body.forEach((token) => {
246
- const name = deriveFuncName(token);
247
- if (name !== null) levels[name] = deriveLevel(sourceCode, token);
248
- });
249
- node.body.forEach((token) => {
250
- const name = deriveVarName(token, levels);
251
- if (name !== null) levels[name] = deriveLevel(sourceCode, token);
271
+ deriveNames(token).forEach((name) => {
272
+ if (name) levels[name] = deriveLevel(sourceCode, token);
273
+ });
252
274
  });
253
275
  },
254
276
  CallExpression(node) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-stratified-design",
3
- "version": "0.12.6",
3
+ "version": "0.12.8",
4
4
  "description": "ESlint rules for stratified design",
5
5
  "keywords": [
6
6
  "eslint",
@@ -20,6 +20,7 @@
20
20
  "scripts": {
21
21
  "lint": "eslint .",
22
22
  "test": "mocha tests --recursive",
23
+ "test:watch": "mocha tests --recursive --watch",
23
24
  "versioning": "node ./scripts/versioning"
24
25
  },
25
26
  "dependencies": {
@@ -215,6 +215,224 @@ ruleTester.run("no-disallowed-imports", rule, {
215
215
  },
216
216
  ],
217
217
  },
218
+
219
+ {
220
+ code: "export { foo } from './fileA'",
221
+ filename: "./src/fileB.js",
222
+ options: [],
223
+ },
224
+ {
225
+ code: "export { foo } from './fileA'",
226
+ filename: "./src/fileB.js",
227
+ options: [
228
+ {
229
+ imports: [{ import: { member: ["foo"], from: "src/fileA" } }],
230
+ },
231
+ ],
232
+ },
233
+ {
234
+ code: "export { foo } from './fileA'",
235
+ filename: "./src/fileB.js",
236
+ options: [
237
+ {
238
+ imports: [
239
+ {
240
+ import: { member: ["baz"], from: "src/fileC" },
241
+ allow: ["src/**/*.js"],
242
+ },
243
+ {
244
+ import: { member: ["foo", "bar"], from: "src/fileA" },
245
+ allow: ["src/**/*.js"],
246
+ },
247
+ ],
248
+ },
249
+ ],
250
+ },
251
+ {
252
+ code: "export { foo } from './fileA'",
253
+ filename: "./src/fileB.js",
254
+ options: [
255
+ {
256
+ imports: [
257
+ {
258
+ import: { member: ["foo", "bar"], from: "src/fileA" },
259
+ disallow: ["src/**/*.test.js"],
260
+ },
261
+ ],
262
+ },
263
+ ],
264
+ },
265
+ {
266
+ code: "export { foo } from './fileA'",
267
+ filename: "./src/fileB.js",
268
+ options: [
269
+ {
270
+ imports: [
271
+ {
272
+ import: { member: ["foo", "bar"], from: "src/fileA" },
273
+ allow: ["src/**/*.js"],
274
+ disallow: ["src/**/*.test.js"],
275
+ },
276
+ ],
277
+ },
278
+ ],
279
+ },
280
+ {
281
+ code: "export { foo } from '@/fileA'",
282
+ filename: "./src/fileB.js",
283
+ options: [
284
+ {
285
+ imports: [
286
+ {
287
+ import: { member: ["foo"], from: "src/fileA" },
288
+ allow: ["src/**/*.js"],
289
+ },
290
+ ],
291
+ aliases: { "@/": "./src/" },
292
+ },
293
+ ],
294
+ },
295
+ {
296
+ code: "export * from './fileA'",
297
+ filename: "./src/fileB.js",
298
+ options: [
299
+ {
300
+ imports: [
301
+ {
302
+ import: { member: ["*"], from: "src/fileA" },
303
+ allow: ["src/**/*.js"],
304
+ },
305
+ ],
306
+ },
307
+ ],
308
+ },
309
+ {
310
+ code: "export * as name from './fileA'",
311
+ filename: "./src/fileB.js",
312
+ options: [
313
+ {
314
+ imports: [
315
+ {
316
+ import: { member: ["*"], from: "src/fileA" },
317
+ allow: ["src/**/*.js"],
318
+ },
319
+ ],
320
+ },
321
+ ],
322
+ },
323
+ {
324
+ code: "export { foo } from 'nodeModule'",
325
+ filename: "./src/fileB.js",
326
+ options: [
327
+ {
328
+ imports: [
329
+ {
330
+ import: { member: ["*"], from: "src/fileA" },
331
+ disallow: ["src/**/*.js"],
332
+ },
333
+ ],
334
+ },
335
+ ],
336
+ },
337
+ {
338
+ code: "export { anyMember } from './fileA'",
339
+ filename: "./src/fileB.js",
340
+ options: [
341
+ {
342
+ imports: [
343
+ {
344
+ import: { member: "*", from: "src/fileA" },
345
+ allow: ["src/**/*.js"],
346
+ },
347
+ ],
348
+ },
349
+ ],
350
+ },
351
+ {
352
+ code: "export * as namespace from './fileA'",
353
+ filename: "./src/fileB.js",
354
+ options: [
355
+ {
356
+ imports: [
357
+ {
358
+ import: { member: "*", from: "src/fileA" },
359
+ allow: ["src/**/*.js"],
360
+ },
361
+ ],
362
+ },
363
+ ],
364
+ },
365
+ {
366
+ code: "export { anyMember } from './fileA.act'",
367
+ filename: "./src/fileB.cal.js",
368
+ options: [
369
+ {
370
+ imports: [
371
+ {
372
+ import: { member: "*", from: "**/*.act" },
373
+ allow: ["src/**/*.cal.js"],
374
+ },
375
+ ],
376
+ },
377
+ ],
378
+ },
379
+ {
380
+ code: "export { anyMember } from 'fileA.cal'",
381
+ filename: "./src/fileB.act.js",
382
+ options: [
383
+ {
384
+ imports: [
385
+ {
386
+ import: { member: "*", from: "**/*.act" },
387
+ disallow: ["src/**/*.cal.js"],
388
+ },
389
+ ],
390
+ },
391
+ ],
392
+ },
393
+ {
394
+ code: "export { anyMember } from 'nodeModule'",
395
+ filename: "./src/fileB.cal.js",
396
+ options: [
397
+ {
398
+ imports: [
399
+ {
400
+ import: { member: "*", from: "**/*.act" },
401
+ disallow: ["src/**/*.cal.js"],
402
+ },
403
+ ],
404
+ },
405
+ ],
406
+ },
407
+
408
+ {
409
+ code: "const foo = 'a'; export { foo };",
410
+ filename: "./src/fileB.cal.js",
411
+ options: [
412
+ {
413
+ imports: [
414
+ {
415
+ import: { member: ["foo"], from: "**/*.act" },
416
+ disallow: ["src/**/*.cal.js"],
417
+ },
418
+ ],
419
+ },
420
+ ],
421
+ },
422
+ {
423
+ code: "const foo = 'a'; export default foo;",
424
+ filename: "./src/fileB.cal.js",
425
+ options: [
426
+ {
427
+ imports: [
428
+ {
429
+ import: { member: ["foo"], from: "**/*.act" },
430
+ disallow: ["src/**/*.cal.js"],
431
+ },
432
+ ],
433
+ },
434
+ ],
435
+ },
218
436
  ],
219
437
  invalid: [
220
438
  {
@@ -312,5 +530,101 @@ ruleTester.run("no-disallowed-imports", rule, {
312
530
  { messageId: "no-disallowed-imports", data: { member: "Any member", from: "**/*.act" } },
313
531
  ],
314
532
  },
533
+
534
+ {
535
+ code: "export { foo } from './fileA'",
536
+ filename: "./src/fileB.js",
537
+ options: [
538
+ {
539
+ imports: [
540
+ {
541
+ import: { member: ["foo"], from: "src/fileA" },
542
+ allow: ["src/**/*.test.js"],
543
+ },
544
+ ],
545
+ },
546
+ ],
547
+ errors: [{ messageId: "no-disallowed-imports", data: { member: "'foo'", from: "src/fileA" } }],
548
+ },
549
+ {
550
+ code: "export { foo } from './fileA'",
551
+ filename: "./src/fileB.js",
552
+ options: [
553
+ {
554
+ imports: [
555
+ {
556
+ import: { member: ["foo"], from: "src/fileA" },
557
+ disallow: ["src/**/*.js"],
558
+ },
559
+ ],
560
+ },
561
+ ],
562
+ errors: [{ messageId: "no-disallowed-imports", data: { member: "'foo'", from: "src/fileA" } }],
563
+ },
564
+ {
565
+ code: "export { foo } from './fileA'",
566
+ filename: "./src/fileB.js",
567
+ options: [
568
+ {
569
+ imports: [
570
+ {
571
+ import: { member: ["foo"], from: "src/fileA" },
572
+ allow: ["src/**/*.js"],
573
+ disallow: ["src/**/fileB.*"],
574
+ },
575
+ ],
576
+ },
577
+ ],
578
+ errors: [{ messageId: "no-disallowed-imports", data: { member: "'foo'", from: "src/fileA" } }],
579
+ },
580
+ {
581
+ code: "export * from './fileA'",
582
+ filename: "./src/fileB.js",
583
+ options: [
584
+ {
585
+ imports: [
586
+ {
587
+ import: { member: ["*"], from: "src/fileA" },
588
+ disallow: ["src/**/*.js"],
589
+ },
590
+ ],
591
+ },
592
+ ],
593
+ errors: [{ messageId: "no-disallowed-imports", data: { member: "'*'", from: "src/fileA" } }],
594
+ },
595
+ {
596
+ code: "export * as name from './fileA'",
597
+ filename: "./src/fileB.js",
598
+ options: [
599
+ {
600
+ imports: [
601
+ {
602
+ import: { member: ["*"], from: "src/fileA" },
603
+ disallow: ["src/**/*.js"],
604
+ },
605
+ ],
606
+ },
607
+ ],
608
+ errors: [
609
+ { messageId: "no-disallowed-imports", data: { member: "'name'", from: "src/fileA" } },
610
+ ],
611
+ },
612
+ {
613
+ code: "export { anyMember } from './fileA.act'",
614
+ filename: "./src/fileB.cal.js",
615
+ options: [
616
+ {
617
+ imports: [
618
+ {
619
+ import: { member: "*", from: "**/*.act" },
620
+ disallow: ["**/*.cal.js"],
621
+ },
622
+ ],
623
+ },
624
+ ],
625
+ errors: [
626
+ { messageId: "no-disallowed-imports", data: { member: "Any member", from: "**/*.act" } },
627
+ ],
628
+ },
315
629
  ],
316
630
  });
@@ -218,6 +218,19 @@ ruleTester.run("no-same-level-funcs", rule, {
218
218
  code: "const arr2 = []; const arr1 = [...arr2];",
219
219
  filename: "./src/foo.js",
220
220
  },
221
+
222
+ {
223
+ code: "//@level 2\nconst [dat, fn2] = someFn()\nconst fn1 = () => { fn2() }\n",
224
+ filename: "./src/foo.js",
225
+ },
226
+ {
227
+ code: "//@level 2\nconst {dat, fn2} = someFn()\nconst fn1 = () => { fn2() }\n",
228
+ filename: "./src/foo.js",
229
+ },
230
+ {
231
+ code: "//@level 2\nconst {dat, fn2: func2} = someFn()\nconst fn1 = () => { func2() }\n",
232
+ filename: "./src/foo.js",
233
+ },
221
234
  ],
222
235
  invalid: [
223
236
  {
@@ -377,5 +390,21 @@ ruleTester.run("no-same-level-funcs", rule, {
377
390
  filename: "./src/foo.js",
378
391
  errors: [{ messageId: "no-same-level-funcs", data: { func: "arr" } }],
379
392
  },
393
+
394
+ {
395
+ code: "const [dat, fn2] = someFn()\nconst fn1 = () => { fn2() }\n",
396
+ filename: "./src/foo.js",
397
+ errors: [{ messageId: "no-same-level-funcs", data: { func: "fn2" } }],
398
+ },
399
+ {
400
+ code: "const {dat, fn2} = someFn()\nconst fn1 = () => { fn2() }\n",
401
+ filename: "./src/foo.js",
402
+ errors: [{ messageId: "no-same-level-funcs", data: { func: "fn2" } }],
403
+ },
404
+ {
405
+ code: "const {dat, fn2: func2} = someFn()\nconst fn1 = () => { func2() }\n",
406
+ filename: "./src/foo.js",
407
+ errors: [{ messageId: "no-same-level-funcs", data: { func: "func2" } }],
408
+ },
380
409
  ],
381
410
  });