@atlaskit/eslint-plugin-platform 2.8.0 → 2.9.1

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.
Files changed (47) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/cjs/index.js +8 -1
  3. package/dist/cjs/rules/ensure-critical-dependency-resolutions/index.js +0 -1
  4. package/dist/cjs/rules/ensure-use-sync-external-store-server-snapshot/index.js +41 -0
  5. package/dist/cjs/rules/import/no-barrel-entry-imports/index.js +534 -74
  6. package/dist/cjs/rules/import/no-barrel-entry-jest-mock/index.js +428 -119
  7. package/dist/cjs/rules/import/no-jest-mock-barrel-files/index.js +3 -2
  8. package/dist/cjs/rules/import/no-relative-barrel-file-imports/index.js +7 -3
  9. package/dist/cjs/rules/import/shared/jest-utils.js +62 -9
  10. package/dist/cjs/rules/import/shared/package-resolution.js +300 -22
  11. package/dist/cjs/rules/no-restricted-fedramp-imports/index.js +65 -0
  12. package/dist/cjs/rules/visit-example-type-import-required/index.js +409 -0
  13. package/dist/es2019/index.js +8 -1
  14. package/dist/es2019/rules/ensure-critical-dependency-resolutions/index.js +0 -1
  15. package/dist/es2019/rules/ensure-use-sync-external-store-server-snapshot/index.js +43 -0
  16. package/dist/es2019/rules/import/no-barrel-entry-imports/index.js +431 -25
  17. package/dist/es2019/rules/import/no-barrel-entry-jest-mock/index.js +287 -25
  18. package/dist/es2019/rules/import/no-jest-mock-barrel-files/index.js +3 -2
  19. package/dist/es2019/rules/import/no-relative-barrel-file-imports/index.js +7 -3
  20. package/dist/es2019/rules/import/shared/jest-utils.js +44 -0
  21. package/dist/es2019/rules/import/shared/package-resolution.js +211 -4
  22. package/dist/es2019/rules/no-restricted-fedramp-imports/index.js +47 -0
  23. package/dist/es2019/rules/visit-example-type-import-required/index.js +375 -0
  24. package/dist/esm/index.js +8 -1
  25. package/dist/esm/rules/ensure-critical-dependency-resolutions/index.js +0 -1
  26. package/dist/esm/rules/ensure-use-sync-external-store-server-snapshot/index.js +35 -0
  27. package/dist/esm/rules/import/no-barrel-entry-imports/index.js +535 -75
  28. package/dist/esm/rules/import/no-barrel-entry-jest-mock/index.js +430 -121
  29. package/dist/esm/rules/import/no-jest-mock-barrel-files/index.js +3 -2
  30. package/dist/esm/rules/import/no-relative-barrel-file-imports/index.js +7 -3
  31. package/dist/esm/rules/import/shared/jest-utils.js +61 -9
  32. package/dist/esm/rules/import/shared/package-resolution.js +298 -24
  33. package/dist/esm/rules/no-restricted-fedramp-imports/index.js +59 -0
  34. package/dist/esm/rules/visit-example-type-import-required/index.js +402 -0
  35. package/dist/types/index.d.ts +14 -0
  36. package/dist/types/rules/ensure-use-sync-external-store-server-snapshot/index.d.ts +3 -0
  37. package/dist/types/rules/import/shared/jest-utils.d.ts +8 -0
  38. package/dist/types/rules/import/shared/package-resolution.d.ts +47 -2
  39. package/dist/types/rules/no-restricted-fedramp-imports/index.d.ts +3 -0
  40. package/dist/types/rules/visit-example-type-import-required/index.d.ts +4 -0
  41. package/dist/types-ts4.5/index.d.ts +14 -0
  42. package/dist/types-ts4.5/rules/ensure-use-sync-external-store-server-snapshot/index.d.ts +3 -0
  43. package/dist/types-ts4.5/rules/import/shared/jest-utils.d.ts +8 -0
  44. package/dist/types-ts4.5/rules/import/shared/package-resolution.d.ts +47 -2
  45. package/dist/types-ts4.5/rules/no-restricted-fedramp-imports/index.d.ts +3 -0
  46. package/dist/types-ts4.5/rules/visit-example-type-import-required/index.d.ts +4 -0
  47. package/package.json +3 -1
@@ -10,7 +10,7 @@ import { dirname } from 'path';
10
10
  import { parseBarrelExports } from '../shared/barrel-parsing';
11
11
  import { DEFAULT_TARGET_FOLDERS, findWorkspaceRoot, isRelativeImport } from '../shared/file-system';
12
12
  import { findPackageInRegistry, isPackageInApplyToImportsFrom } from '../shared/package-registry';
13
- import { findExportForSourceFile, parsePackageExports } from '../shared/package-resolution';
13
+ import { findCrossPackageBridgeExportPath, findExportForSourceFile, parsePackageExports } from '../shared/package-resolution';
14
14
  import { realFileSystem } from '../shared/types';
15
15
 
16
16
  /**
@@ -41,6 +41,10 @@ var ruleMeta = {
41
41
  type: 'string'
42
42
  },
43
43
  description: 'The folder paths (relative to workspace root) containing packages whose imports will be checked and autofixed.'
44
+ },
45
+ preferImportedPackageSubpath: {
46
+ type: 'boolean',
47
+ description: 'Prefer subpaths on the imported barrel package when they bridge to the dependency (e.g. @scope/pkg/subpath instead of @scope/dependency).'
44
48
  }
45
49
  },
46
50
  additionalProperties: false
@@ -130,19 +134,14 @@ function buildImportStatement(_ref) {
130
134
  */
131
135
 
132
136
  /**
133
- * Resolves import context for barrel file analysis.
137
+ * Resolves import context for barrel file analysis from a module specifier string.
134
138
  * Returns null if the import should not be processed (relative import, not in target folder, etc.)
135
139
  */
136
- function resolveImportContext(_ref2) {
137
- var node = _ref2.node,
140
+ function resolveImportContextFromModulePath(_ref2) {
141
+ var importPath = _ref2.importPath,
138
142
  workspaceRoot = _ref2.workspaceRoot,
139
143
  fs = _ref2.fs,
140
144
  applyToImportsFrom = _ref2.applyToImportsFrom;
141
- if (!node.source || typeof node.source.value !== 'string') {
142
- return null;
143
- }
144
- var importPath = node.source.value;
145
-
146
145
  // Skip relative imports - this rule is for cross-package imports
147
146
  if (isRelativeImport(importPath)) {
148
147
  return null;
@@ -216,19 +215,41 @@ function resolveImportContext(_ref2) {
216
215
  };
217
216
  }
218
217
 
218
+ /**
219
+ * Resolves import context for barrel file analysis.
220
+ * Returns null if the import should not be processed (relative import, not in target folder, etc.)
221
+ */
222
+ function resolveImportContext(_ref3) {
223
+ var node = _ref3.node,
224
+ workspaceRoot = _ref3.workspaceRoot,
225
+ fs = _ref3.fs,
226
+ applyToImportsFrom = _ref3.applyToImportsFrom;
227
+ if (!node.source || typeof node.source.value !== 'string') {
228
+ return null;
229
+ }
230
+ return resolveImportContextFromModulePath({
231
+ importPath: node.source.value,
232
+ workspaceRoot: workspaceRoot,
233
+ fs: fs,
234
+ applyToImportsFrom: applyToImportsFrom
235
+ });
236
+ }
237
+
219
238
  /**
220
239
  * Classifies import specifiers by their target export paths.
221
240
  * Groups specifiers that can be remapped to more specific exports.
222
241
  * For cross-package re-exports, suggests importing from the source package's most specific subpath.
223
242
  */
224
- function classifySpecifiers(_ref3) {
225
- var node = _ref3.node,
226
- importContext = _ref3.importContext,
227
- workspaceRoot = _ref3.workspaceRoot,
228
- fs = _ref3.fs;
243
+ function classifySpecifiers(_ref4) {
244
+ var node = _ref4.node,
245
+ importContext = _ref4.importContext,
246
+ workspaceRoot = _ref4.workspaceRoot,
247
+ fs = _ref4.fs,
248
+ preferImportedPackageSubpath = _ref4.preferImportedPackageSubpath;
229
249
  var currentExportPath = importContext.currentExportPath,
230
250
  exportsMap = importContext.exportsMap,
231
- exportMap = importContext.exportMap;
251
+ exportMap = importContext.exportMap,
252
+ importedPackageName = importContext.packageName;
232
253
  var specifiers = node.specifiers;
233
254
  var specifiersByTarget = new Map();
234
255
  var unmappedSpecifiers = [];
@@ -249,6 +270,7 @@ function classifySpecifiers(_ref3) {
249
270
  var kind = 'value';
250
271
  if (spec.type === 'ImportDefaultSpecifier') {
251
272
  nameInSource = 'default';
273
+ kind = node.importKind === 'type' ? 'type' : 'value';
252
274
  } else if (spec.type === 'ImportSpecifier') {
253
275
  nameInSource = getImportedName(spec);
254
276
  var parentImportKind = node.importKind;
@@ -258,12 +280,42 @@ function classifySpecifiers(_ref3) {
258
280
  }
259
281
  var exportInfo = exportMap.get(nameInSource);
260
282
  if (exportInfo) {
261
- var _exportInfo$crossPack;
283
+ var _exportInfo$crossPack, _exportInfo$originalN2, _matchResult$exportPa2;
262
284
  var effectiveKind = kind === 'type' || exportInfo.isTypeOnly ? 'type' : 'value';
263
285
 
264
286
  // Check if this is a cross-package re-export
265
287
  var sourcePackageName = (_exportInfo$crossPack = exportInfo.crossPackageSource) === null || _exportInfo$crossPack === void 0 ? void 0 : _exportInfo$crossPack.packageName;
266
288
  if (sourcePackageName) {
289
+ var targetKey = void 0;
290
+ var resolvedOriginalName = exportInfo.originalName;
291
+ if (preferImportedPackageSubpath) {
292
+ var bridge = findCrossPackageBridgeExportPath({
293
+ exportsMap: exportsMap,
294
+ crossPackageName: sourcePackageName,
295
+ exportedName: nameInSource,
296
+ fs: fs
297
+ });
298
+ if (bridge) {
299
+ targetKey = importedPackageName + bridge.exportPath.slice(1);
300
+ if (bridge.entryPointExportName !== undefined) {
301
+ resolvedOriginalName = bridge.entryPointExportName === nameInSource ? undefined : bridge.entryPointExportName;
302
+ }
303
+ if (!specifiersByTarget.has(targetKey)) {
304
+ specifiersByTarget.set(targetKey, []);
305
+ }
306
+ specifiersByTarget.get(targetKey).push({
307
+ spec: _objectSpread(_objectSpread({}, spec), {}, {
308
+ importKind: effectiveKind
309
+ }),
310
+ originalName: resolvedOriginalName,
311
+ targetExportPath: targetKey,
312
+ kind: effectiveKind,
313
+ sourcePackageName: sourcePackageName
314
+ });
315
+ continue;
316
+ }
317
+ }
318
+
267
319
  // For cross-package re-exports, find the most specific subpath in the source package
268
320
  // Note: Package resolution is not constrained by applyToImportsFrom - any package can be resolved
269
321
  var sourcePackageExportsMap = sourcePackageExportsMaps.get(sourcePackageName);
@@ -285,14 +337,22 @@ function classifySpecifiers(_ref3) {
285
337
  // Find the best export path in the source package
286
338
  var _targetExportPath = null;
287
339
  if (sourcePackageExportsMap) {
288
- _targetExportPath = findExportForSourceFile({
340
+ var _exportInfo$originalN, _matchResult$exportPa;
341
+ var _sourceExportName = (_exportInfo$originalN = exportInfo.originalName) !== null && _exportInfo$originalN !== void 0 ? _exportInfo$originalN : nameInSource;
342
+ var _matchResult = findExportForSourceFile({
289
343
  sourceFilePath: exportInfo.path,
290
- exportsMap: sourcePackageExportsMap
344
+ exportsMap: sourcePackageExportsMap,
345
+ fs: fs,
346
+ sourceExportName: _sourceExportName
291
347
  });
348
+ _targetExportPath = (_matchResult$exportPa = _matchResult === null || _matchResult === void 0 ? void 0 : _matchResult.exportPath) !== null && _matchResult$exportPa !== void 0 ? _matchResult$exportPa : null;
349
+ if ((_matchResult === null || _matchResult === void 0 ? void 0 : _matchResult.entryPointExportName) !== undefined) {
350
+ resolvedOriginalName = _matchResult.entryPointExportName === nameInSource ? undefined : _matchResult.entryPointExportName;
351
+ }
292
352
  }
293
353
 
294
354
  // Build the full import path: @package/subpath or just @package if no subpath found
295
- var targetKey = _targetExportPath ? sourcePackageName + _targetExportPath.slice(1) // Remove leading '.' from subpath
355
+ targetKey = _targetExportPath ? sourcePackageName + _targetExportPath.slice(1) // Remove leading '.' from subpath
296
356
  : sourcePackageName;
297
357
  if (!specifiersByTarget.has(targetKey)) {
298
358
  specifiersByTarget.set(targetKey, []);
@@ -301,7 +361,7 @@ function classifySpecifiers(_ref3) {
301
361
  spec: _objectSpread(_objectSpread({}, spec), {}, {
302
362
  importKind: effectiveKind
303
363
  }),
304
- originalName: exportInfo.originalName,
364
+ originalName: resolvedOriginalName,
305
365
  targetExportPath: targetKey,
306
366
  kind: effectiveKind,
307
367
  sourcePackageName: sourcePackageName
@@ -310,10 +370,18 @@ function classifySpecifiers(_ref3) {
310
370
  }
311
371
 
312
372
  // Find if there's a package.json export that points to this source file
313
- var targetExportPath = findExportForSourceFile({
373
+ var sourceExportName = (_exportInfo$originalN2 = exportInfo.originalName) !== null && _exportInfo$originalN2 !== void 0 ? _exportInfo$originalN2 : nameInSource;
374
+ var matchResult = findExportForSourceFile({
314
375
  sourceFilePath: exportInfo.path,
315
- exportsMap: exportsMap
376
+ exportsMap: exportsMap,
377
+ fs: fs,
378
+ sourceExportName: sourceExportName
316
379
  });
380
+ var targetExportPath = (_matchResult$exportPa2 = matchResult === null || matchResult === void 0 ? void 0 : matchResult.exportPath) !== null && _matchResult$exportPa2 !== void 0 ? _matchResult$exportPa2 : null;
381
+ var resolvedOriginalName2 = exportInfo.originalName;
382
+ if ((matchResult === null || matchResult === void 0 ? void 0 : matchResult.entryPointExportName) !== undefined) {
383
+ resolvedOriginalName2 = matchResult.entryPointExportName === nameInSource ? undefined : matchResult.entryPointExportName;
384
+ }
317
385
 
318
386
  // Get the file that the current export path resolves to
319
387
  var currentExportResolvedFile = exportsMap.get(currentExportPath);
@@ -332,7 +400,7 @@ function classifySpecifiers(_ref3) {
332
400
  spec: _objectSpread(_objectSpread({}, spec), {}, {
333
401
  importKind: effectiveKind
334
402
  }),
335
- originalName: exportInfo.originalName,
403
+ originalName: resolvedOriginalName2,
336
404
  targetExportPath: targetExportPath,
337
405
  kind: effectiveKind
338
406
  });
@@ -368,10 +436,10 @@ function classifySpecifiers(_ref3) {
368
436
  * Transforms a specifier to use the original export name (handling aliasing).
369
437
  * Converts named imports of default exports to ImportDefaultSpecifier.
370
438
  */
371
- function transformSpecifierForExport(_ref4) {
372
- var spec = _ref4.spec,
373
- originalName = _ref4.originalName,
374
- kind = _ref4.kind;
439
+ function transformSpecifierForExport(_ref5) {
440
+ var spec = _ref5.spec,
441
+ originalName = _ref5.originalName,
442
+ kind = _ref5.kind;
375
443
  if (!originalName) {
376
444
  return spec;
377
445
  }
@@ -420,12 +488,12 @@ function transformSpecifierForExport(_ref4) {
420
488
  * Merges new specifiers with an existing import declaration.
421
489
  * Returns the new import statement string.
422
490
  */
423
- function buildMergedImportStatement(_ref5) {
424
- var existingImport = _ref5.existingImport,
425
- newSpecs = _ref5.newSpecs,
426
- newImportPath = _ref5.newImportPath,
427
- nodeImportKind = _ref5.nodeImportKind,
428
- quoteChar = _ref5.quoteChar;
491
+ function buildMergedImportStatement(_ref6) {
492
+ var existingImport = _ref6.existingImport,
493
+ newSpecs = _ref6.newSpecs,
494
+ newImportPath = _ref6.newImportPath,
495
+ nodeImportKind = _ref6.nodeImportKind,
496
+ quoteChar = _ref6.quoteChar;
429
497
  var existingSpecs = existingImport.specifiers.map(function (s) {
430
498
  if (existingImport.importKind === 'type') {
431
499
  return _objectSpread(_objectSpread({}, s), {}, {
@@ -498,9 +566,9 @@ function getJestAutomock(node) {
498
566
  /**
499
567
  * Find all Jest automocks in the AST that match the given import path.
500
568
  */
501
- function findMatchingAutomocks(_ref6) {
502
- var sourceCode = _ref6.sourceCode,
503
- importPath = _ref6.importPath;
569
+ function findMatchingAutomocks(_ref7) {
570
+ var sourceCode = _ref7.sourceCode,
571
+ importPath = _ref7.importPath;
504
572
  var automocks = [];
505
573
  var ast = sourceCode.ast;
506
574
  var _iterator2 = _createForOfIteratorHelper(ast.body),
@@ -524,9 +592,9 @@ function findMatchingAutomocks(_ref6) {
524
592
  /**
525
593
  * Build a jest.mock() statement string
526
594
  */
527
- function buildAutomockStatement(_ref7) {
528
- var path = _ref7.path,
529
- quoteChar = _ref7.quoteChar;
595
+ function buildAutomockStatement(_ref8) {
596
+ var path = _ref8.path,
597
+ quoteChar = _ref8.quoteChar;
530
598
  return "jest.mock(".concat(quoteChar).concat(path).concat(quoteChar, ");");
531
599
  }
532
600
 
@@ -534,10 +602,10 @@ function buildAutomockStatement(_ref7) {
534
602
  * Creates a fix to remove a node with proper whitespace handling.
535
603
  * Removes surrounding newlines to avoid leaving blank lines.
536
604
  */
537
- function createNodeRemovalFix(_ref8) {
538
- var fixer = _ref8.fixer,
539
- node = _ref8.node,
540
- sourceCode = _ref8.sourceCode;
605
+ function createNodeRemovalFix(_ref9) {
606
+ var fixer = _ref9.fixer,
607
+ node = _ref9.node,
608
+ sourceCode = _ref9.sourceCode;
541
609
  var nodeStart = node.range[0];
542
610
  var nodeEnd = node.range[1];
543
611
 
@@ -563,13 +631,13 @@ function createNodeRemovalFix(_ref8) {
563
631
  * Generates new import statements and handles merging with existing imports.
564
632
  * Also updates Jest automocks (jest.mock calls with only a path) when present.
565
633
  */
566
- function createBarrelImportFix(_ref9) {
567
- var fixer = _ref9.fixer,
568
- node = _ref9.node,
569
- context = _ref9.context,
570
- importContext = _ref9.importContext,
571
- specifiersByTarget = _ref9.specifiersByTarget,
572
- unmappedSpecifiers = _ref9.unmappedSpecifiers;
634
+ function createBarrelImportFix(_ref0) {
635
+ var fixer = _ref0.fixer,
636
+ node = _ref0.node,
637
+ context = _ref0.context,
638
+ importContext = _ref0.importContext,
639
+ specifiersByTarget = _ref0.specifiersByTarget,
640
+ unmappedSpecifiers = _ref0.unmappedSpecifiers;
573
641
  var importPath = importContext.importPath,
574
642
  packageName = importContext.packageName;
575
643
  var sourceCode = context.sourceCode;
@@ -611,10 +679,10 @@ function createBarrelImportFix(_ref9) {
611
679
  : packageName + targetExportPath.slice(1); // Remove leading '.' for same-package imports
612
680
 
613
681
  // Transform specifiers if needed (handle aliasing)
614
- var specs = specsWithTarget.map(function (_ref1) {
615
- var spec = _ref1.spec,
616
- originalName = _ref1.originalName,
617
- kind = _ref1.kind;
682
+ var specs = specsWithTarget.map(function (_ref10) {
683
+ var spec = _ref10.spec,
684
+ originalName = _ref10.originalName,
685
+ kind = _ref10.kind;
618
686
  return transformSpecifierForExport({
619
687
  spec: spec,
620
688
  originalName: originalName,
@@ -625,9 +693,9 @@ function createBarrelImportFix(_ref9) {
625
693
  // Check if any specifier in this group is a value import (not type-only)
626
694
  // Only add automock paths for value imports (types don't need mocking at runtime)
627
695
  if (automocks.length > 0) {
628
- var hasValueImport = specsWithTarget.some(function (_ref10) {
629
- var kind = _ref10.kind,
630
- spec = _ref10.spec;
696
+ var hasValueImport = specsWithTarget.some(function (_ref11) {
697
+ var kind = _ref11.kind,
698
+ spec = _ref11.spec;
631
699
  return kind === 'value' && (spec.type !== 'ImportSpecifier' || spec.importKind !== 'type');
632
700
  });
633
701
  if (hasValueImport) {
@@ -659,7 +727,10 @@ function createBarrelImportFix(_ref9) {
659
727
  }
660
728
  } else {
661
729
  // Create new import
662
- var _isTypeImport = node.importKind === 'type';
730
+ var allSpecsAreType = specsWithTarget.every(function (s) {
731
+ return s.kind === 'type';
732
+ });
733
+ var _isTypeImport = node.importKind === 'type' || allSpecsAreType;
663
734
  var importStatement = buildImportStatement({
664
735
  specs: specs,
665
736
  path: newImportPath,
@@ -685,7 +756,10 @@ function createBarrelImportFix(_ref9) {
685
756
  var unmappedSpecs = unmappedSpecifiers.map(function (u) {
686
757
  return u.spec;
687
758
  });
688
- var isTypeImport = node.importKind === 'type';
759
+ var allUnmappedAreType = unmappedSpecifiers.every(function (u) {
760
+ return u.kind === 'type';
761
+ });
762
+ var isTypeImport = node.importKind === 'type' || allUnmappedAreType;
689
763
  var remainingImport = buildImportStatement({
690
764
  specs: unmappedSpecs,
691
765
  path: importPath,
@@ -698,9 +772,9 @@ function createBarrelImportFix(_ref9) {
698
772
 
699
773
  // If there are unmapped value specifiers and automocks, keep the original automock path too
700
774
  if (automocks.length > 0) {
701
- var hasUnmappedValueImport = unmappedSpecifiers.some(function (_ref0) {
702
- var kind = _ref0.kind,
703
- spec = _ref0.spec;
775
+ var hasUnmappedValueImport = unmappedSpecifiers.some(function (_ref1) {
776
+ var kind = _ref1.kind,
777
+ spec = _ref1.spec;
704
778
  return kind === 'value' && (spec.type !== 'ImportSpecifier' || spec.importKind !== 'type');
705
779
  });
706
780
  if (hasUnmappedValueImport) {
@@ -751,17 +825,380 @@ function createBarrelImportFix(_ref9) {
751
825
  }
752
826
  return fixes;
753
827
  }
828
+ function isPlainRequireCall(node) {
829
+ if (node.callee.type !== 'Identifier' || node.callee.name !== 'require') {
830
+ return false;
831
+ }
832
+ if (node.arguments.length !== 1) {
833
+ return false;
834
+ }
835
+ var arg = node.arguments[0];
836
+ return arg.type === 'Literal' && typeof arg.value === 'string';
837
+ }
838
+ function unwrapToRequireCall(expr) {
839
+ var e = expr;
840
+ for (;;) {
841
+ var wrapped = e;
842
+ if (wrapped.type !== 'ParenthesizedExpression' || !wrapped.expression) {
843
+ break;
844
+ }
845
+ e = wrapped.expression;
846
+ }
847
+ if (e.type !== 'CallExpression' || !isPlainRequireCall(e)) {
848
+ return null;
849
+ }
850
+ return e;
851
+ }
852
+ function buildSyntheticImportFromRequireAccess(exportPropertyName, modulePath) {
853
+ var specifiers = exportPropertyName === 'default' ? [{
854
+ type: 'ImportDefaultSpecifier',
855
+ local: {
856
+ type: 'Identifier',
857
+ name: '_r'
858
+ }
859
+ }] : [{
860
+ type: 'ImportSpecifier',
861
+ imported: {
862
+ type: 'Identifier',
863
+ name: exportPropertyName
864
+ },
865
+ local: {
866
+ type: 'Identifier',
867
+ name: exportPropertyName
868
+ }
869
+ }];
870
+ return {
871
+ type: 'ImportDeclaration',
872
+ source: {
873
+ type: 'Literal',
874
+ value: modulePath,
875
+ raw: "'".concat(modulePath, "'")
876
+ },
877
+ specifiers: specifiers,
878
+ importKind: 'value'
879
+ };
880
+ }
881
+ function fullNewImportPathForTarget(targetKey, specsWithTarget, packageName) {
882
+ var isCrossPackage = specsWithTarget.some(function (s) {
883
+ return s.sourcePackageName;
884
+ });
885
+ return isCrossPackage ? targetKey : packageName + targetKey.slice(1);
886
+ }
887
+ function getRhsPropertyAfterTransform(spec) {
888
+ if (spec.type === 'ImportDefaultSpecifier') {
889
+ return 'default';
890
+ }
891
+ return getImportedName(spec);
892
+ }
893
+ function appendAutomockFixesForPathMigration(_ref12) {
894
+ var fixer = _ref12.fixer,
895
+ sourceCode = _ref12.sourceCode,
896
+ oldBarrelPath = _ref12.oldBarrelPath,
897
+ newPaths = _ref12.newPaths;
898
+ var automocks = findMatchingAutomocks({
899
+ sourceCode: sourceCode,
900
+ importPath: oldBarrelPath
901
+ });
902
+ if (automocks.length === 0 || newPaths.length === 0) {
903
+ return [];
904
+ }
905
+ var fixes = [];
906
+ var _iterator5 = _createForOfIteratorHelper(automocks),
907
+ _step5;
908
+ try {
909
+ var _loop3 = function _loop3() {
910
+ var automock = _step5.value;
911
+ var newAutomockStatements = newPaths.map(function (path) {
912
+ return buildAutomockStatement({
913
+ path: path,
914
+ quoteChar: automock.quoteChar
915
+ });
916
+ });
917
+ fixes.push(fixer.replaceTextRange(automock.statementNode.range, newAutomockStatements.join('\n')));
918
+ };
919
+ for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
920
+ _loop3();
921
+ }
922
+ } catch (err) {
923
+ _iterator5.e(err);
924
+ } finally {
925
+ _iterator5.f();
926
+ }
927
+ return fixes;
928
+ }
929
+
930
+ /**
931
+ * `require('barrel').default` or `require('barrel').namedExport`
932
+ */
933
+ function handleRequireMemberExpression(_ref13) {
934
+ var node = _ref13.node,
935
+ context = _ref13.context,
936
+ workspaceRoot = _ref13.workspaceRoot,
937
+ fs = _ref13.fs,
938
+ applyToImportsFrom = _ref13.applyToImportsFrom,
939
+ preferImportedPackageSubpath = _ref13.preferImportedPackageSubpath;
940
+ if (node.computed || node.property.type !== 'Identifier') {
941
+ return;
942
+ }
943
+ var reqCall = unwrapToRequireCall(node.object);
944
+ if (!reqCall) {
945
+ return;
946
+ }
947
+ var modulePath = reqCall.arguments[0].value;
948
+ var importContext = resolveImportContextFromModulePath({
949
+ importPath: modulePath,
950
+ workspaceRoot: workspaceRoot,
951
+ fs: fs,
952
+ applyToImportsFrom: applyToImportsFrom
953
+ });
954
+ if (!importContext) {
955
+ return;
956
+ }
957
+ var exportPropertyName = node.property.name;
958
+ var synthetic = buildSyntheticImportFromRequireAccess(exportPropertyName, modulePath);
959
+ var _classifySpecifiers = classifySpecifiers({
960
+ node: synthetic,
961
+ importContext: importContext,
962
+ workspaceRoot: workspaceRoot,
963
+ fs: fs,
964
+ preferImportedPackageSubpath: preferImportedPackageSubpath
965
+ }),
966
+ specifiersByTarget = _classifySpecifiers.specifiersByTarget,
967
+ hasNamespaceImport = _classifySpecifiers.hasNamespaceImport;
968
+ if (hasNamespaceImport || specifiersByTarget.size === 0) {
969
+ return;
970
+ }
971
+ var entries = _toConsumableArray(specifiersByTarget.entries());
972
+ if (entries.length !== 1) {
973
+ return;
974
+ }
975
+ var _ref14 = entries[0],
976
+ _ref15 = _slicedToArray(_ref14, 2),
977
+ targetKey = _ref15[0],
978
+ specsWithTarget = _ref15[1];
979
+ if (specsWithTarget.length !== 1) {
980
+ return;
981
+ }
982
+ var st = specsWithTarget[0];
983
+ var newImportPath = fullNewImportPathForTarget(targetKey, specsWithTarget, importContext.packageName);
984
+ var transformed = transformSpecifierForExport({
985
+ spec: st.spec,
986
+ originalName: st.originalName,
987
+ kind: st.kind
988
+ });
989
+ var newRhs = getRhsPropertyAfterTransform(transformed);
990
+ var sourceCode = context.getSourceCode();
991
+ var quote = sourceCode.getText(reqCall.arguments[0])[0];
992
+ context.report({
993
+ node: node,
994
+ messageId: 'barrelEntryImport',
995
+ data: {
996
+ path: importContext.importPath
997
+ },
998
+ fix: function fix(fixer) {
999
+ var fixes = [];
1000
+ fixes.push(fixer.replaceText(node, "require(".concat(quote).concat(newImportPath).concat(quote, ").").concat(newRhs)));
1001
+ if (st.kind === 'value') {
1002
+ fixes.push.apply(fixes, _toConsumableArray(appendAutomockFixesForPathMigration({
1003
+ fixer: fixer,
1004
+ sourceCode: sourceCode,
1005
+ oldBarrelPath: modulePath,
1006
+ newPaths: [newImportPath]
1007
+ })));
1008
+ }
1009
+ return fixes;
1010
+ }
1011
+ });
1012
+ }
1013
+
1014
+ /**
1015
+ * `const { a, b } = require('barrel')`
1016
+ */
1017
+ function handleRequireDestructuringDeclarator(_ref16) {
1018
+ var node = _ref16.node,
1019
+ context = _ref16.context,
1020
+ workspaceRoot = _ref16.workspaceRoot,
1021
+ fs = _ref16.fs,
1022
+ applyToImportsFrom = _ref16.applyToImportsFrom,
1023
+ preferImportedPackageSubpath = _ref16.preferImportedPackageSubpath;
1024
+ if (node.id.type !== 'ObjectPattern' || !node.init || node.init.type !== 'CallExpression') {
1025
+ return;
1026
+ }
1027
+ var initCall = node.init;
1028
+ if (!isPlainRequireCall(initCall)) {
1029
+ return;
1030
+ }
1031
+ var modulePath = initCall.arguments[0].value;
1032
+ var importContext = resolveImportContextFromModulePath({
1033
+ importPath: modulePath,
1034
+ workspaceRoot: workspaceRoot,
1035
+ fs: fs,
1036
+ applyToImportsFrom: applyToImportsFrom
1037
+ });
1038
+ if (!importContext) {
1039
+ return;
1040
+ }
1041
+ var specifiers = [];
1042
+ var _iterator6 = _createForOfIteratorHelper(node.id.properties),
1043
+ _step6;
1044
+ try {
1045
+ for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) {
1046
+ var prop = _step6.value;
1047
+ if (prop.type !== 'Property' || prop.computed) {
1048
+ continue;
1049
+ }
1050
+ if (prop.key.type !== 'Identifier' || prop.value.type !== 'Identifier') {
1051
+ continue;
1052
+ }
1053
+ var importedName = prop.key.name;
1054
+ var localName = prop.value.name;
1055
+ specifiers.push({
1056
+ type: 'ImportSpecifier',
1057
+ imported: {
1058
+ type: 'Identifier',
1059
+ name: importedName
1060
+ },
1061
+ local: {
1062
+ type: 'Identifier',
1063
+ name: localName
1064
+ }
1065
+ });
1066
+ }
1067
+ } catch (err) {
1068
+ _iterator6.e(err);
1069
+ } finally {
1070
+ _iterator6.f();
1071
+ }
1072
+ if (specifiers.length === 0) {
1073
+ return;
1074
+ }
1075
+ var synthetic = {
1076
+ type: 'ImportDeclaration',
1077
+ source: {
1078
+ type: 'Literal',
1079
+ value: modulePath,
1080
+ raw: "'".concat(modulePath, "'")
1081
+ },
1082
+ specifiers: specifiers,
1083
+ importKind: 'value'
1084
+ };
1085
+ var _classifySpecifiers2 = classifySpecifiers({
1086
+ node: synthetic,
1087
+ importContext: importContext,
1088
+ workspaceRoot: workspaceRoot,
1089
+ fs: fs,
1090
+ preferImportedPackageSubpath: preferImportedPackageSubpath
1091
+ }),
1092
+ specifiersByTarget = _classifySpecifiers2.specifiersByTarget,
1093
+ unmappedSpecifiers = _classifySpecifiers2.unmappedSpecifiers,
1094
+ hasNamespaceImport = _classifySpecifiers2.hasNamespaceImport;
1095
+ if (hasNamespaceImport || specifiersByTarget.size === 0 || unmappedSpecifiers.length > 0) {
1096
+ return;
1097
+ }
1098
+ var parentDecl = node.parent;
1099
+ if (parentDecl.type !== 'VariableDeclaration') {
1100
+ return;
1101
+ }
1102
+ if (specifiersByTarget.size > 1 && parentDecl.declarations.length !== 1) {
1103
+ return;
1104
+ }
1105
+ var sourceCode = context.getSourceCode();
1106
+ var quote = sourceCode.getText(initCall.arguments[0])[0];
1107
+ var pkg = importContext.packageName;
1108
+ var buildFixes = function buildFixes(fixer) {
1109
+ var fixes = [];
1110
+ var hasValue = false;
1111
+ var automockPaths = [];
1112
+ if (specifiersByTarget.size === 1) {
1113
+ var _ref17 = _toConsumableArray(specifiersByTarget.entries())[0],
1114
+ _ref18 = _slicedToArray(_ref17, 2),
1115
+ targetKey = _ref18[0],
1116
+ specsWithTarget = _ref18[1];
1117
+ var newImportPath = fullNewImportPathForTarget(targetKey, specsWithTarget, pkg);
1118
+ if (specsWithTarget.some(function (s) {
1119
+ return s.kind === 'value';
1120
+ })) {
1121
+ hasValue = true;
1122
+ automockPaths.push(newImportPath);
1123
+ }
1124
+ fixes.push(fixer.replaceText(initCall.arguments[0], "".concat(quote).concat(newImportPath).concat(quote)));
1125
+ } else {
1126
+ var lines = [];
1127
+ var _iterator7 = _createForOfIteratorHelper(specifiersByTarget),
1128
+ _step7;
1129
+ try {
1130
+ for (_iterator7.s(); !(_step7 = _iterator7.n()).done;) {
1131
+ var _step7$value = _slicedToArray(_step7.value, 2),
1132
+ _targetKey = _step7$value[0],
1133
+ _specsWithTarget = _step7$value[1];
1134
+ var _newImportPath = fullNewImportPathForTarget(_targetKey, _specsWithTarget, pkg);
1135
+ if (_specsWithTarget.some(function (s) {
1136
+ return s.kind === 'value';
1137
+ })) {
1138
+ hasValue = true;
1139
+ automockPaths.push(_newImportPath);
1140
+ }
1141
+ var _iterator8 = _createForOfIteratorHelper(_specsWithTarget),
1142
+ _step8;
1143
+ try {
1144
+ for (_iterator8.s(); !(_step8 = _iterator8.n()).done;) {
1145
+ var st = _step8.value;
1146
+ var transformed = transformSpecifierForExport({
1147
+ spec: st.spec,
1148
+ originalName: st.originalName,
1149
+ kind: st.kind
1150
+ });
1151
+ var rhs = getRhsPropertyAfterTransform(transformed);
1152
+ var local = st.spec.local.name;
1153
+ lines.push("".concat(local, " = require(").concat(quote).concat(_newImportPath).concat(quote, ").").concat(rhs));
1154
+ }
1155
+ } catch (err) {
1156
+ _iterator8.e(err);
1157
+ } finally {
1158
+ _iterator8.f();
1159
+ }
1160
+ }
1161
+ } catch (err) {
1162
+ _iterator7.e(err);
1163
+ } finally {
1164
+ _iterator7.f();
1165
+ }
1166
+ var declText = lines.map(function (l) {
1167
+ return "".concat(parentDecl.kind, " ").concat(l, ";");
1168
+ }).join('\n');
1169
+ fixes.push(fixer.replaceText(parentDecl, declText));
1170
+ }
1171
+ if (hasValue) {
1172
+ fixes.push.apply(fixes, _toConsumableArray(appendAutomockFixesForPathMigration({
1173
+ fixer: fixer,
1174
+ sourceCode: sourceCode,
1175
+ oldBarrelPath: modulePath,
1176
+ newPaths: _toConsumableArray(new Set(automockPaths))
1177
+ })));
1178
+ }
1179
+ return fixes;
1180
+ };
1181
+ context.report({
1182
+ node: initCall,
1183
+ messageId: 'barrelEntryImport',
1184
+ data: {
1185
+ path: importContext.importPath
1186
+ },
1187
+ fix: buildFixes
1188
+ });
1189
+ }
754
1190
 
755
1191
  /**
756
1192
  * Handles an ImportDeclaration node to check for barrel file imports.
757
1193
  * Reports and auto-fixes imports that could use more specific export paths.
758
1194
  */
759
- function handleImportDeclaration(_ref11) {
760
- var node = _ref11.node,
761
- context = _ref11.context,
762
- workspaceRoot = _ref11.workspaceRoot,
763
- fs = _ref11.fs,
764
- applyToImportsFrom = _ref11.applyToImportsFrom;
1195
+ function handleImportDeclaration(_ref19) {
1196
+ var node = _ref19.node,
1197
+ context = _ref19.context,
1198
+ workspaceRoot = _ref19.workspaceRoot,
1199
+ fs = _ref19.fs,
1200
+ applyToImportsFrom = _ref19.applyToImportsFrom,
1201
+ preferImportedPackageSubpath = _ref19.preferImportedPackageSubpath;
765
1202
  // Resolve import context (validates and extracts package/export info)
766
1203
  // applyToImportsFrom is used here to filter which packages the rule applies to
767
1204
  var importContext = resolveImportContext({
@@ -780,15 +1217,16 @@ function handleImportDeclaration(_ref11) {
780
1217
  }
781
1218
 
782
1219
  // Classify specifiers by their target export paths
783
- var _classifySpecifiers = classifySpecifiers({
1220
+ var _classifySpecifiers3 = classifySpecifiers({
784
1221
  node: node,
785
1222
  importContext: importContext,
786
1223
  workspaceRoot: workspaceRoot,
787
- fs: fs
1224
+ fs: fs,
1225
+ preferImportedPackageSubpath: preferImportedPackageSubpath
788
1226
  }),
789
- specifiersByTarget = _classifySpecifiers.specifiersByTarget,
790
- unmappedSpecifiers = _classifySpecifiers.unmappedSpecifiers,
791
- hasNamespaceImport = _classifySpecifiers.hasNamespaceImport;
1227
+ specifiersByTarget = _classifySpecifiers3.specifiersByTarget,
1228
+ unmappedSpecifiers = _classifySpecifiers3.unmappedSpecifiers,
1229
+ hasNamespaceImport = _classifySpecifiers3.hasNamespaceImport;
792
1230
 
793
1231
  // If namespace import, report without auto-fix if there are specific exports available
794
1232
  if (hasNamespaceImport) {
@@ -837,9 +1275,10 @@ export function createRule(fs) {
837
1275
  return {
838
1276
  meta: ruleMeta,
839
1277
  create: function create(context) {
840
- var _options$applyToImpor;
1278
+ var _options$applyToImpor, _options$preferImport;
841
1279
  var options = context.options[0] || {};
842
1280
  var applyToImportsFrom = (_options$applyToImpor = options.applyToImportsFrom) !== null && _options$applyToImpor !== void 0 ? _options$applyToImpor : DEFAULT_TARGET_FOLDERS;
1281
+ var preferImportedPackageSubpath = (_options$preferImport = options.preferImportedPackageSubpath) !== null && _options$preferImport !== void 0 ? _options$preferImport : false;
843
1282
  var workspaceRoot = findWorkspaceRoot({
844
1283
  startPath: dirname(context.filename),
845
1284
  fs: fs,
@@ -853,7 +1292,28 @@ export function createRule(fs) {
853
1292
  context: context,
854
1293
  workspaceRoot: workspaceRoot,
855
1294
  fs: fs,
856
- applyToImportsFrom: applyToImportsFrom
1295
+ applyToImportsFrom: applyToImportsFrom,
1296
+ preferImportedPackageSubpath: preferImportedPackageSubpath
1297
+ });
1298
+ },
1299
+ MemberExpression: function MemberExpression(rawNode) {
1300
+ handleRequireMemberExpression({
1301
+ node: rawNode,
1302
+ context: context,
1303
+ workspaceRoot: workspaceRoot,
1304
+ fs: fs,
1305
+ applyToImportsFrom: applyToImportsFrom,
1306
+ preferImportedPackageSubpath: preferImportedPackageSubpath
1307
+ });
1308
+ },
1309
+ VariableDeclarator: function VariableDeclarator(rawNode) {
1310
+ handleRequireDestructuringDeclarator({
1311
+ node: rawNode,
1312
+ context: context,
1313
+ workspaceRoot: workspaceRoot,
1314
+ fs: fs,
1315
+ applyToImportsFrom: applyToImportsFrom,
1316
+ preferImportedPackageSubpath: preferImportedPackageSubpath
857
1317
  });
858
1318
  }
859
1319
  };