eslint-plugin-stratified-design 0.12.5 → 0.12.7

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
  };
@@ -20,36 +20,97 @@ const { fromCwd, match } = require("../helpers/common");
20
20
  * @typedef {({[name: string]: number})} Levels
21
21
  */
22
22
 
23
+ const hasArrFunction = (elements, levels) => {
24
+ return elements.reduce((hasFunc, element) => {
25
+ if (hasFunc) return true;
26
+ const type = element.type;
27
+ if (type === "FunctionExpression" || type === "ArrowFunctionExpression")
28
+ return true;
29
+ if (type === "ObjectExpression")
30
+ return hasObjFunction(element.properties, levels);
31
+ if (type === "ArrayExpression")
32
+ return hasArrFunction(element.elements, levels);
33
+ if ("name" in element && element.name in levels) return true;
34
+ return false;
35
+ }, false);
36
+ };
37
+
38
+ const hasObjFunction = (properties, levels) => {
39
+ return properties.reduce((hasFunc, property) => {
40
+ if (hasFunc) return true;
41
+ if (!("value" in property)) return false;
42
+ const type = property.value.type;
43
+ if (type === "FunctionExpression" || type === "ArrowFunctionExpression")
44
+ return true;
45
+ if (type === "ObjectExpression")
46
+ return hasObjFunction(property.value.properties, levels);
47
+ if (type === "ArrayExpression")
48
+ return hasArrFunction(property.value.elements, levels);
49
+ if ("name" in property.value && property.value.name in levels) return true;
50
+ return false;
51
+ }, false);
52
+ };
53
+
54
+ /**
55
+ * @param {Node | Token} nodeOrToken
56
+ */
57
+ const deriveDeclaration = (nodeOrToken) => {
58
+ return (nodeOrToken.type === "ExportNamedDeclaration" ||
59
+ nodeOrToken.type === "ExportDefaultDeclaration") &&
60
+ Boolean(nodeOrToken.declaration)
61
+ ? nodeOrToken.declaration
62
+ : nodeOrToken;
63
+ };
64
+
23
65
  /**
24
66
  * @param {Node | Token} nodeOrToken
25
67
  * @returns {string | null}
26
68
  */
27
69
  const deriveFuncName = (nodeOrToken) => {
28
- const declaration =
29
- (nodeOrToken.type === "ExportNamedDeclaration" ||
30
- nodeOrToken.type === "ExportDefaultDeclaration") &&
31
- Boolean(nodeOrToken.declaration)
32
- ? nodeOrToken.declaration
33
- : nodeOrToken;
34
- const isFuncDeclaration = declaration.type === "FunctionDeclaration";
35
- const isVarDeclaration =
36
- declaration.type === "VariableDeclaration" &&
70
+ const declaration = deriveDeclaration(nodeOrToken);
71
+
72
+ if (declaration.type === "FunctionDeclaration") return declaration.id.name;
73
+ if (declaration.type !== "VariableDeclaration") return null;
74
+
75
+ const { init, id } = declaration.declarations[0];
76
+ if (
37
77
  [
38
78
  "ArrowFunctionExpression",
39
79
  "FunctionExpression",
40
80
  "CallExpression",
41
81
  "TaggedTemplateExpression",
42
- ].includes(declaration.declarations[0].init.type);
43
-
44
- if (isFuncDeclaration || isVarDeclaration) {
45
- const name = isFuncDeclaration
46
- ? declaration.id.name
47
- : declaration.declarations[0].id.name;
48
- return name;
82
+ ].includes(init.type)
83
+ ) {
84
+ return id.name;
49
85
  }
86
+
50
87
  return null;
51
88
  };
52
89
 
90
+ /**
91
+ * @param {Node | Token} nodeOrToken
92
+ * @param {Levels} levels
93
+ * @returns {string | null}
94
+ */
95
+ const deriveVarName = (nodeOrToken, levels) => {
96
+ const declaration = deriveDeclaration(nodeOrToken);
97
+ if (declaration.type !== "VariableDeclaration") return null;
98
+ const { init, id } = declaration.declarations[0];
99
+ if (
100
+ init.type === "ObjectExpression" &&
101
+ hasObjFunction(init.properties, levels)
102
+ ) {
103
+ return id.name;
104
+ } else if (
105
+ init.type === "ArrayExpression" &&
106
+ hasArrFunction(init.elements, levels)
107
+ ) {
108
+ return id.name;
109
+ } else {
110
+ return null;
111
+ }
112
+ };
113
+
53
114
  /**
54
115
  * @param {SourceCode} sourceCode
55
116
  * @param {Node | Token} nodeOrToken
@@ -89,16 +150,24 @@ const isCalleeLowerLevel = (sourceCode, levels) => {
89
150
  if (calleeLevel === undefined) return true; // 호출되는 함수가 존재하지 않으면 true 리턴. 함수 내의 함수의 경우에는 항상 calleeLevel 이 undefined 이다.
90
151
 
91
152
  const caller = traceAncestor(sourceCode, node);
92
- const callerLevel = deriveLevel(sourceCode, caller);
93
- if (callerLevel < calleeLevel) return true;
153
+ const callerName = deriveFuncName(caller) || deriveVarName(caller, levels);
154
+ const callerLevel = levels[callerName];
94
155
 
95
- const callerName = deriveFuncName(caller);
156
+ if (callerLevel === undefined) return true;
157
+ if (callerLevel < calleeLevel) return true;
96
158
  if (callerName === calleeName) return true; // recursive function
97
159
 
98
160
  return false;
99
161
  };
100
162
  };
101
163
 
164
+ const deriveCalleeName = (callee) => {
165
+ if (callee.type === "Identifier") return callee.name;
166
+ if (callee.type === "MemberExpression")
167
+ return deriveCalleeName(callee.object);
168
+ return null;
169
+ };
170
+
102
171
  /** @type {import('eslint').Rule.RuleModule} */
103
172
  module.exports = {
104
173
  meta: {
@@ -175,10 +244,11 @@ module.exports = {
175
244
  Program(node) {
176
245
  node.body.forEach((token) => {
177
246
  const name = deriveFuncName(token);
178
- if (name) {
179
- const level = deriveLevel(sourceCode, token);
180
- levels[name] = level;
181
- }
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);
182
252
  });
183
253
  },
184
254
  CallExpression(node) {
@@ -186,7 +256,7 @@ module.exports = {
186
256
  const isReported = report(node, name);
187
257
  if (isReported) return;
188
258
  }
189
- report(node, node.callee.name);
259
+ report(node, deriveCalleeName(node.callee));
190
260
  },
191
261
  JSXOpeningElement(node) {
192
262
  report(node, node.name.name);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-stratified-design",
3
- "version": "0.12.5",
3
+ "version": "0.12.7",
4
4
  "description": "ESlint rules for stratified design",
5
5
  "keywords": [
6
6
  "eslint",
@@ -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
  });
@@ -158,6 +158,66 @@ ruleTester.run("no-same-level-funcs", rule, {
158
158
  code: "/*@level 2*/const func = () => 'a'; /*@level 1*/const obj = { func: () => { func() } } ",
159
159
  filename: "./src/foo.js",
160
160
  },
161
+
162
+ {
163
+ code: "const func = () => 'a'; const obj = { a: func() } ",
164
+ filename: "./src/foo.js",
165
+ },
166
+ {
167
+ code: "/*@level 2*/const func = () => 'a'; /*@level 1*/const obj = { func: () => { func() } } ",
168
+ filename: "./src/foo.js",
169
+ errors: [{ messageId: "no-same-level-funcs", data: { func: "obj" } }],
170
+ },
171
+ {
172
+ code: "/*@level 2*/const obj = { func2: () => {} }; /*@level 1*/const func1 = () => { obj.func2() } ",
173
+ filename: "./src/foo.js",
174
+ },
175
+ {
176
+ code: "/*@level 2*/const obj = { func2(){} }; /*@level 1*/const func1 = () => { obj.func2() } ",
177
+ filename: "./src/foo.js",
178
+ },
179
+ {
180
+ code: "/*@level 3*/const func3 = () => 'a'; /*@level 2*/const obj = { func2: func3 }; /*@level 1*/const func1 = () => { obj.func2() } ",
181
+ filename: "./src/foo.js",
182
+ errors: [{ messageId: "no-same-level-funcs", data: { func: "obj" } }],
183
+ },
184
+
185
+ {
186
+ code: "const func = () => 'a'; const arr = [func()];",
187
+ filename: "./src/foo.js",
188
+ },
189
+ {
190
+ code: "/*@level 2*/const func = () => 'a'; /*@level 1*/const arr = [() => { func() }];",
191
+ filename: "./src/foo.js",
192
+ },
193
+ {
194
+ code: "/*@level 2*/const arr = [() => {}]; /*@level 1*/const func1 = () => { arr[0]() } ",
195
+ filename: "./src/foo.js",
196
+ },
197
+ {
198
+ code: "/*@level 3*/const func3 = () => 'a'; /*@level 2*/const arr = [func3]; /*@level 1*/const func1 = () => { arr[0]() } ",
199
+ filename: "./src/foo.js",
200
+ },
201
+ {
202
+ code: "import { func } from './module'; const arr = [{a: {b: {c: [func]}}}];",
203
+ filename: "./src/foo.js",
204
+ },
205
+ {
206
+ code: "const func = () => {}; const arr = [{a: {b: {c: [func]}}}];",
207
+ filename: "./src/foo.js",
208
+ },
209
+ {
210
+ code: "/*@level 3*/const func3 = () => {}; /*@level 2*/const arr = [{a: {b: {c: [func3]}}}]; /*@level 1*/const func1 = () => arr[0].a.b.c[0]();",
211
+ filename: "./src/foo.js",
212
+ },
213
+ {
214
+ code: "const obj2 = {}; const obj1 = {...obj2};",
215
+ filename: "./src/foo.js",
216
+ },
217
+ {
218
+ code: "const arr2 = []; const arr1 = [...arr2];",
219
+ filename: "./src/foo.js",
220
+ },
161
221
  ],
162
222
  invalid: [
163
223
  {
@@ -175,13 +235,11 @@ ruleTester.run("no-same-level-funcs", rule, {
175
235
  filename: "./src/foo.js",
176
236
  errors: [{ messageId: "no-same-level-funcs", data: { func: "func1" } }],
177
237
  },
178
-
179
238
  {
180
239
  code: "function func2(){ func1(); }; function func1(){}",
181
240
  filename: "./src/foo.js",
182
241
  errors: [{ messageId: "no-same-level-funcs", data: { func: "func1" } }],
183
242
  },
184
-
185
243
  {
186
244
  code: "export function func2(){ func1(); }; function func1(){}",
187
245
  filename: "./src/foo.js",
@@ -192,7 +250,6 @@ ruleTester.run("no-same-level-funcs", rule, {
192
250
  filename: "./src/foo.js",
193
251
  errors: [{ messageId: "no-same-level-funcs", data: { func: "func1" } }],
194
252
  },
195
-
196
253
  {
197
254
  code: "const func1 = () => {}; const func2 = () => { func1(); }",
198
255
  filename: "./src/foo.js",
@@ -203,7 +260,6 @@ ruleTester.run("no-same-level-funcs", rule, {
203
260
  filename: "./src/foo.js",
204
261
  errors: [{ messageId: "no-same-level-funcs", data: { func: "func1" } }],
205
262
  },
206
-
207
263
  {
208
264
  code: "const func1 = function(){}; const func2 = function(){ func1(); }",
209
265
  filename: "./src/foo.js",
@@ -214,7 +270,6 @@ ruleTester.run("no-same-level-funcs", rule, {
214
270
  filename: "./src/foo.js",
215
271
  errors: [{ messageId: "no-same-level-funcs", data: { func: "func1" } }],
216
272
  },
217
-
218
273
  {
219
274
  code: "const func1 = function func1(){}; const func2 = function func2(){ func1(); }",
220
275
  filename: "./src/foo.js",
@@ -225,7 +280,6 @@ ruleTester.run("no-same-level-funcs", rule, {
225
280
  filename: "./src/foo.js",
226
281
  errors: [{ messageId: "no-same-level-funcs", data: { func: "func1" } }],
227
282
  },
228
-
229
283
  {
230
284
  code: "const fn = () => 1; const value = fn()",
231
285
  filename: "./src/foo.js",
@@ -276,7 +330,6 @@ ruleTester.run("no-same-level-funcs", rule, {
276
330
  filename: "./src/foo.js",
277
331
  errors: [{ messageId: "no-same-level-funcs", data: { func: "func1" } }],
278
332
  },
279
-
280
333
  {
281
334
  code: "function func2(){};\n// @level 1\nfunction func1(){ func2(); }",
282
335
  filename: "./src/foo.js",
@@ -284,14 +337,45 @@ ruleTester.run("no-same-level-funcs", rule, {
284
337
  },
285
338
 
286
339
  {
287
- code: "const func = () => 'a'; const obj = { a: func() } ",
340
+ code: "const func = () => 'a'; const obj = { func: () => { func() } };",
288
341
  filename: "./src/foo.js",
289
342
  errors: [{ messageId: "no-same-level-funcs", data: { func: "func" } }],
290
343
  },
291
344
  {
292
- code: "const func = () => 'a'; const obj = { func: () => { func() } } ",
345
+ code: "const obj = { func2: () => {} }; const func1 = () => { obj.func2() } ",
346
+ filename: "./src/foo.js",
347
+ errors: [{ messageId: "no-same-level-funcs", data: { func: "obj" } }],
348
+ },
349
+ {
350
+ code: "const obj = { func2(){} }; const func1 = () => { obj.func2() } ",
351
+ filename: "./src/foo.js",
352
+ errors: [{ messageId: "no-same-level-funcs", data: { func: "obj" } }],
353
+ },
354
+ {
355
+ code: "const func3 = () => 'a'; const obj = { func2: func3 }; const func1 = () => { obj.func2() } ",
356
+ filename: "./src/foo.js",
357
+ errors: [{ messageId: "no-same-level-funcs", data: { func: "obj" } }],
358
+ },
359
+
360
+ {
361
+ code: "const func = () => 'a'; const arr = [() => { func() }];",
293
362
  filename: "./src/foo.js",
294
363
  errors: [{ messageId: "no-same-level-funcs", data: { func: "func" } }],
295
364
  },
365
+ {
366
+ code: "const arr = [() => {}]; const func1 = () => { arr[0]() } ",
367
+ filename: "./src/foo.js",
368
+ errors: [{ messageId: "no-same-level-funcs", data: { func: "arr" } }],
369
+ },
370
+ {
371
+ code: "const func3 = () => 'a'; const arr = [func3]; const func1 = () => { arr[0]() } ",
372
+ filename: "./src/foo.js",
373
+ errors: [{ messageId: "no-same-level-funcs", data: { func: "arr" } }],
374
+ },
375
+ {
376
+ code: "const func3 = () => {}; const arr = [{a: {b: {c: [func3]}}}]; const func1 = () => arr[0].a.b.c[0]();",
377
+ filename: "./src/foo.js",
378
+ errors: [{ messageId: "no-same-level-funcs", data: { func: "arr" } }],
379
+ },
296
380
  ],
297
381
  });