@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
@@ -48,6 +48,10 @@ var ruleMeta = {
48
48
  type: 'string'
49
49
  },
50
50
  description: 'The folder paths (relative to workspace root) containing packages whose imports will be checked and autofixed.'
51
+ },
52
+ preferImportedPackageSubpath: {
53
+ type: 'boolean',
54
+ description: 'Prefer subpaths on the imported barrel package when they bridge to the dependency (e.g. @scope/pkg/subpath instead of @scope/dependency).'
51
55
  }
52
56
  },
53
57
  additionalProperties: false
@@ -137,19 +141,14 @@ function buildImportStatement(_ref) {
137
141
  */
138
142
 
139
143
  /**
140
- * Resolves import context for barrel file analysis.
144
+ * Resolves import context for barrel file analysis from a module specifier string.
141
145
  * Returns null if the import should not be processed (relative import, not in target folder, etc.)
142
146
  */
143
- function resolveImportContext(_ref2) {
144
- var node = _ref2.node,
147
+ function resolveImportContextFromModulePath(_ref2) {
148
+ var importPath = _ref2.importPath,
145
149
  workspaceRoot = _ref2.workspaceRoot,
146
150
  fs = _ref2.fs,
147
151
  applyToImportsFrom = _ref2.applyToImportsFrom;
148
- if (!node.source || typeof node.source.value !== 'string') {
149
- return null;
150
- }
151
- var importPath = node.source.value;
152
-
153
152
  // Skip relative imports - this rule is for cross-package imports
154
153
  if ((0, _fileSystem.isRelativeImport)(importPath)) {
155
154
  return null;
@@ -223,19 +222,41 @@ function resolveImportContext(_ref2) {
223
222
  };
224
223
  }
225
224
 
225
+ /**
226
+ * Resolves import context for barrel file analysis.
227
+ * Returns null if the import should not be processed (relative import, not in target folder, etc.)
228
+ */
229
+ function resolveImportContext(_ref3) {
230
+ var node = _ref3.node,
231
+ workspaceRoot = _ref3.workspaceRoot,
232
+ fs = _ref3.fs,
233
+ applyToImportsFrom = _ref3.applyToImportsFrom;
234
+ if (!node.source || typeof node.source.value !== 'string') {
235
+ return null;
236
+ }
237
+ return resolveImportContextFromModulePath({
238
+ importPath: node.source.value,
239
+ workspaceRoot: workspaceRoot,
240
+ fs: fs,
241
+ applyToImportsFrom: applyToImportsFrom
242
+ });
243
+ }
244
+
226
245
  /**
227
246
  * Classifies import specifiers by their target export paths.
228
247
  * Groups specifiers that can be remapped to more specific exports.
229
248
  * For cross-package re-exports, suggests importing from the source package's most specific subpath.
230
249
  */
231
- function classifySpecifiers(_ref3) {
232
- var node = _ref3.node,
233
- importContext = _ref3.importContext,
234
- workspaceRoot = _ref3.workspaceRoot,
235
- fs = _ref3.fs;
250
+ function classifySpecifiers(_ref4) {
251
+ var node = _ref4.node,
252
+ importContext = _ref4.importContext,
253
+ workspaceRoot = _ref4.workspaceRoot,
254
+ fs = _ref4.fs,
255
+ preferImportedPackageSubpath = _ref4.preferImportedPackageSubpath;
236
256
  var currentExportPath = importContext.currentExportPath,
237
257
  exportsMap = importContext.exportsMap,
238
- exportMap = importContext.exportMap;
258
+ exportMap = importContext.exportMap,
259
+ importedPackageName = importContext.packageName;
239
260
  var specifiers = node.specifiers;
240
261
  var specifiersByTarget = new Map();
241
262
  var unmappedSpecifiers = [];
@@ -256,6 +277,7 @@ function classifySpecifiers(_ref3) {
256
277
  var kind = 'value';
257
278
  if (spec.type === 'ImportDefaultSpecifier') {
258
279
  nameInSource = 'default';
280
+ kind = node.importKind === 'type' ? 'type' : 'value';
259
281
  } else if (spec.type === 'ImportSpecifier') {
260
282
  nameInSource = getImportedName(spec);
261
283
  var parentImportKind = node.importKind;
@@ -265,12 +287,42 @@ function classifySpecifiers(_ref3) {
265
287
  }
266
288
  var exportInfo = exportMap.get(nameInSource);
267
289
  if (exportInfo) {
268
- var _exportInfo$crossPack;
290
+ var _exportInfo$crossPack, _exportInfo$originalN2, _matchResult$exportPa2;
269
291
  var effectiveKind = kind === 'type' || exportInfo.isTypeOnly ? 'type' : 'value';
270
292
 
271
293
  // Check if this is a cross-package re-export
272
294
  var sourcePackageName = (_exportInfo$crossPack = exportInfo.crossPackageSource) === null || _exportInfo$crossPack === void 0 ? void 0 : _exportInfo$crossPack.packageName;
273
295
  if (sourcePackageName) {
296
+ var targetKey = void 0;
297
+ var resolvedOriginalName = exportInfo.originalName;
298
+ if (preferImportedPackageSubpath) {
299
+ var bridge = (0, _packageResolution.findCrossPackageBridgeExportPath)({
300
+ exportsMap: exportsMap,
301
+ crossPackageName: sourcePackageName,
302
+ exportedName: nameInSource,
303
+ fs: fs
304
+ });
305
+ if (bridge) {
306
+ targetKey = importedPackageName + bridge.exportPath.slice(1);
307
+ if (bridge.entryPointExportName !== undefined) {
308
+ resolvedOriginalName = bridge.entryPointExportName === nameInSource ? undefined : bridge.entryPointExportName;
309
+ }
310
+ if (!specifiersByTarget.has(targetKey)) {
311
+ specifiersByTarget.set(targetKey, []);
312
+ }
313
+ specifiersByTarget.get(targetKey).push({
314
+ spec: _objectSpread(_objectSpread({}, spec), {}, {
315
+ importKind: effectiveKind
316
+ }),
317
+ originalName: resolvedOriginalName,
318
+ targetExportPath: targetKey,
319
+ kind: effectiveKind,
320
+ sourcePackageName: sourcePackageName
321
+ });
322
+ continue;
323
+ }
324
+ }
325
+
274
326
  // For cross-package re-exports, find the most specific subpath in the source package
275
327
  // Note: Package resolution is not constrained by applyToImportsFrom - any package can be resolved
276
328
  var sourcePackageExportsMap = sourcePackageExportsMaps.get(sourcePackageName);
@@ -292,14 +344,22 @@ function classifySpecifiers(_ref3) {
292
344
  // Find the best export path in the source package
293
345
  var _targetExportPath = null;
294
346
  if (sourcePackageExportsMap) {
295
- _targetExportPath = (0, _packageResolution.findExportForSourceFile)({
347
+ var _exportInfo$originalN, _matchResult$exportPa;
348
+ var _sourceExportName = (_exportInfo$originalN = exportInfo.originalName) !== null && _exportInfo$originalN !== void 0 ? _exportInfo$originalN : nameInSource;
349
+ var _matchResult = (0, _packageResolution.findExportForSourceFile)({
296
350
  sourceFilePath: exportInfo.path,
297
- exportsMap: sourcePackageExportsMap
351
+ exportsMap: sourcePackageExportsMap,
352
+ fs: fs,
353
+ sourceExportName: _sourceExportName
298
354
  });
355
+ _targetExportPath = (_matchResult$exportPa = _matchResult === null || _matchResult === void 0 ? void 0 : _matchResult.exportPath) !== null && _matchResult$exportPa !== void 0 ? _matchResult$exportPa : null;
356
+ if ((_matchResult === null || _matchResult === void 0 ? void 0 : _matchResult.entryPointExportName) !== undefined) {
357
+ resolvedOriginalName = _matchResult.entryPointExportName === nameInSource ? undefined : _matchResult.entryPointExportName;
358
+ }
299
359
  }
300
360
 
301
361
  // Build the full import path: @package/subpath or just @package if no subpath found
302
- var targetKey = _targetExportPath ? sourcePackageName + _targetExportPath.slice(1) // Remove leading '.' from subpath
362
+ targetKey = _targetExportPath ? sourcePackageName + _targetExportPath.slice(1) // Remove leading '.' from subpath
303
363
  : sourcePackageName;
304
364
  if (!specifiersByTarget.has(targetKey)) {
305
365
  specifiersByTarget.set(targetKey, []);
@@ -308,7 +368,7 @@ function classifySpecifiers(_ref3) {
308
368
  spec: _objectSpread(_objectSpread({}, spec), {}, {
309
369
  importKind: effectiveKind
310
370
  }),
311
- originalName: exportInfo.originalName,
371
+ originalName: resolvedOriginalName,
312
372
  targetExportPath: targetKey,
313
373
  kind: effectiveKind,
314
374
  sourcePackageName: sourcePackageName
@@ -317,10 +377,18 @@ function classifySpecifiers(_ref3) {
317
377
  }
318
378
 
319
379
  // Find if there's a package.json export that points to this source file
320
- var targetExportPath = (0, _packageResolution.findExportForSourceFile)({
380
+ var sourceExportName = (_exportInfo$originalN2 = exportInfo.originalName) !== null && _exportInfo$originalN2 !== void 0 ? _exportInfo$originalN2 : nameInSource;
381
+ var matchResult = (0, _packageResolution.findExportForSourceFile)({
321
382
  sourceFilePath: exportInfo.path,
322
- exportsMap: exportsMap
383
+ exportsMap: exportsMap,
384
+ fs: fs,
385
+ sourceExportName: sourceExportName
323
386
  });
387
+ var targetExportPath = (_matchResult$exportPa2 = matchResult === null || matchResult === void 0 ? void 0 : matchResult.exportPath) !== null && _matchResult$exportPa2 !== void 0 ? _matchResult$exportPa2 : null;
388
+ var resolvedOriginalName2 = exportInfo.originalName;
389
+ if ((matchResult === null || matchResult === void 0 ? void 0 : matchResult.entryPointExportName) !== undefined) {
390
+ resolvedOriginalName2 = matchResult.entryPointExportName === nameInSource ? undefined : matchResult.entryPointExportName;
391
+ }
324
392
 
325
393
  // Get the file that the current export path resolves to
326
394
  var currentExportResolvedFile = exportsMap.get(currentExportPath);
@@ -339,7 +407,7 @@ function classifySpecifiers(_ref3) {
339
407
  spec: _objectSpread(_objectSpread({}, spec), {}, {
340
408
  importKind: effectiveKind
341
409
  }),
342
- originalName: exportInfo.originalName,
410
+ originalName: resolvedOriginalName2,
343
411
  targetExportPath: targetExportPath,
344
412
  kind: effectiveKind
345
413
  });
@@ -375,10 +443,10 @@ function classifySpecifiers(_ref3) {
375
443
  * Transforms a specifier to use the original export name (handling aliasing).
376
444
  * Converts named imports of default exports to ImportDefaultSpecifier.
377
445
  */
378
- function transformSpecifierForExport(_ref4) {
379
- var spec = _ref4.spec,
380
- originalName = _ref4.originalName,
381
- kind = _ref4.kind;
446
+ function transformSpecifierForExport(_ref5) {
447
+ var spec = _ref5.spec,
448
+ originalName = _ref5.originalName,
449
+ kind = _ref5.kind;
382
450
  if (!originalName) {
383
451
  return spec;
384
452
  }
@@ -427,12 +495,12 @@ function transformSpecifierForExport(_ref4) {
427
495
  * Merges new specifiers with an existing import declaration.
428
496
  * Returns the new import statement string.
429
497
  */
430
- function buildMergedImportStatement(_ref5) {
431
- var existingImport = _ref5.existingImport,
432
- newSpecs = _ref5.newSpecs,
433
- newImportPath = _ref5.newImportPath,
434
- nodeImportKind = _ref5.nodeImportKind,
435
- quoteChar = _ref5.quoteChar;
498
+ function buildMergedImportStatement(_ref6) {
499
+ var existingImport = _ref6.existingImport,
500
+ newSpecs = _ref6.newSpecs,
501
+ newImportPath = _ref6.newImportPath,
502
+ nodeImportKind = _ref6.nodeImportKind,
503
+ quoteChar = _ref6.quoteChar;
436
504
  var existingSpecs = existingImport.specifiers.map(function (s) {
437
505
  if (existingImport.importKind === 'type') {
438
506
  return _objectSpread(_objectSpread({}, s), {}, {
@@ -505,9 +573,9 @@ function getJestAutomock(node) {
505
573
  /**
506
574
  * Find all Jest automocks in the AST that match the given import path.
507
575
  */
508
- function findMatchingAutomocks(_ref6) {
509
- var sourceCode = _ref6.sourceCode,
510
- importPath = _ref6.importPath;
576
+ function findMatchingAutomocks(_ref7) {
577
+ var sourceCode = _ref7.sourceCode,
578
+ importPath = _ref7.importPath;
511
579
  var automocks = [];
512
580
  var ast = sourceCode.ast;
513
581
  var _iterator2 = _createForOfIteratorHelper(ast.body),
@@ -531,9 +599,9 @@ function findMatchingAutomocks(_ref6) {
531
599
  /**
532
600
  * Build a jest.mock() statement string
533
601
  */
534
- function buildAutomockStatement(_ref7) {
535
- var path = _ref7.path,
536
- quoteChar = _ref7.quoteChar;
602
+ function buildAutomockStatement(_ref8) {
603
+ var path = _ref8.path,
604
+ quoteChar = _ref8.quoteChar;
537
605
  return "jest.mock(".concat(quoteChar).concat(path).concat(quoteChar, ");");
538
606
  }
539
607
 
@@ -541,10 +609,10 @@ function buildAutomockStatement(_ref7) {
541
609
  * Creates a fix to remove a node with proper whitespace handling.
542
610
  * Removes surrounding newlines to avoid leaving blank lines.
543
611
  */
544
- function createNodeRemovalFix(_ref8) {
545
- var fixer = _ref8.fixer,
546
- node = _ref8.node,
547
- sourceCode = _ref8.sourceCode;
612
+ function createNodeRemovalFix(_ref9) {
613
+ var fixer = _ref9.fixer,
614
+ node = _ref9.node,
615
+ sourceCode = _ref9.sourceCode;
548
616
  var nodeStart = node.range[0];
549
617
  var nodeEnd = node.range[1];
550
618
 
@@ -570,13 +638,13 @@ function createNodeRemovalFix(_ref8) {
570
638
  * Generates new import statements and handles merging with existing imports.
571
639
  * Also updates Jest automocks (jest.mock calls with only a path) when present.
572
640
  */
573
- function createBarrelImportFix(_ref9) {
574
- var fixer = _ref9.fixer,
575
- node = _ref9.node,
576
- context = _ref9.context,
577
- importContext = _ref9.importContext,
578
- specifiersByTarget = _ref9.specifiersByTarget,
579
- unmappedSpecifiers = _ref9.unmappedSpecifiers;
641
+ function createBarrelImportFix(_ref0) {
642
+ var fixer = _ref0.fixer,
643
+ node = _ref0.node,
644
+ context = _ref0.context,
645
+ importContext = _ref0.importContext,
646
+ specifiersByTarget = _ref0.specifiersByTarget,
647
+ unmappedSpecifiers = _ref0.unmappedSpecifiers;
580
648
  var importPath = importContext.importPath,
581
649
  packageName = importContext.packageName;
582
650
  var sourceCode = context.sourceCode;
@@ -618,10 +686,10 @@ function createBarrelImportFix(_ref9) {
618
686
  : packageName + targetExportPath.slice(1); // Remove leading '.' for same-package imports
619
687
 
620
688
  // Transform specifiers if needed (handle aliasing)
621
- var specs = specsWithTarget.map(function (_ref1) {
622
- var spec = _ref1.spec,
623
- originalName = _ref1.originalName,
624
- kind = _ref1.kind;
689
+ var specs = specsWithTarget.map(function (_ref10) {
690
+ var spec = _ref10.spec,
691
+ originalName = _ref10.originalName,
692
+ kind = _ref10.kind;
625
693
  return transformSpecifierForExport({
626
694
  spec: spec,
627
695
  originalName: originalName,
@@ -632,9 +700,9 @@ function createBarrelImportFix(_ref9) {
632
700
  // Check if any specifier in this group is a value import (not type-only)
633
701
  // Only add automock paths for value imports (types don't need mocking at runtime)
634
702
  if (automocks.length > 0) {
635
- var hasValueImport = specsWithTarget.some(function (_ref10) {
636
- var kind = _ref10.kind,
637
- spec = _ref10.spec;
703
+ var hasValueImport = specsWithTarget.some(function (_ref11) {
704
+ var kind = _ref11.kind,
705
+ spec = _ref11.spec;
638
706
  return kind === 'value' && (spec.type !== 'ImportSpecifier' || spec.importKind !== 'type');
639
707
  });
640
708
  if (hasValueImport) {
@@ -666,7 +734,10 @@ function createBarrelImportFix(_ref9) {
666
734
  }
667
735
  } else {
668
736
  // Create new import
669
- var _isTypeImport = node.importKind === 'type';
737
+ var allSpecsAreType = specsWithTarget.every(function (s) {
738
+ return s.kind === 'type';
739
+ });
740
+ var _isTypeImport = node.importKind === 'type' || allSpecsAreType;
670
741
  var importStatement = buildImportStatement({
671
742
  specs: specs,
672
743
  path: newImportPath,
@@ -692,7 +763,10 @@ function createBarrelImportFix(_ref9) {
692
763
  var unmappedSpecs = unmappedSpecifiers.map(function (u) {
693
764
  return u.spec;
694
765
  });
695
- var isTypeImport = node.importKind === 'type';
766
+ var allUnmappedAreType = unmappedSpecifiers.every(function (u) {
767
+ return u.kind === 'type';
768
+ });
769
+ var isTypeImport = node.importKind === 'type' || allUnmappedAreType;
696
770
  var remainingImport = buildImportStatement({
697
771
  specs: unmappedSpecs,
698
772
  path: importPath,
@@ -705,9 +779,9 @@ function createBarrelImportFix(_ref9) {
705
779
 
706
780
  // If there are unmapped value specifiers and automocks, keep the original automock path too
707
781
  if (automocks.length > 0) {
708
- var hasUnmappedValueImport = unmappedSpecifiers.some(function (_ref0) {
709
- var kind = _ref0.kind,
710
- spec = _ref0.spec;
782
+ var hasUnmappedValueImport = unmappedSpecifiers.some(function (_ref1) {
783
+ var kind = _ref1.kind,
784
+ spec = _ref1.spec;
711
785
  return kind === 'value' && (spec.type !== 'ImportSpecifier' || spec.importKind !== 'type');
712
786
  });
713
787
  if (hasUnmappedValueImport) {
@@ -758,17 +832,380 @@ function createBarrelImportFix(_ref9) {
758
832
  }
759
833
  return fixes;
760
834
  }
835
+ function isPlainRequireCall(node) {
836
+ if (node.callee.type !== 'Identifier' || node.callee.name !== 'require') {
837
+ return false;
838
+ }
839
+ if (node.arguments.length !== 1) {
840
+ return false;
841
+ }
842
+ var arg = node.arguments[0];
843
+ return arg.type === 'Literal' && typeof arg.value === 'string';
844
+ }
845
+ function unwrapToRequireCall(expr) {
846
+ var e = expr;
847
+ for (;;) {
848
+ var wrapped = e;
849
+ if (wrapped.type !== 'ParenthesizedExpression' || !wrapped.expression) {
850
+ break;
851
+ }
852
+ e = wrapped.expression;
853
+ }
854
+ if (e.type !== 'CallExpression' || !isPlainRequireCall(e)) {
855
+ return null;
856
+ }
857
+ return e;
858
+ }
859
+ function buildSyntheticImportFromRequireAccess(exportPropertyName, modulePath) {
860
+ var specifiers = exportPropertyName === 'default' ? [{
861
+ type: 'ImportDefaultSpecifier',
862
+ local: {
863
+ type: 'Identifier',
864
+ name: '_r'
865
+ }
866
+ }] : [{
867
+ type: 'ImportSpecifier',
868
+ imported: {
869
+ type: 'Identifier',
870
+ name: exportPropertyName
871
+ },
872
+ local: {
873
+ type: 'Identifier',
874
+ name: exportPropertyName
875
+ }
876
+ }];
877
+ return {
878
+ type: 'ImportDeclaration',
879
+ source: {
880
+ type: 'Literal',
881
+ value: modulePath,
882
+ raw: "'".concat(modulePath, "'")
883
+ },
884
+ specifiers: specifiers,
885
+ importKind: 'value'
886
+ };
887
+ }
888
+ function fullNewImportPathForTarget(targetKey, specsWithTarget, packageName) {
889
+ var isCrossPackage = specsWithTarget.some(function (s) {
890
+ return s.sourcePackageName;
891
+ });
892
+ return isCrossPackage ? targetKey : packageName + targetKey.slice(1);
893
+ }
894
+ function getRhsPropertyAfterTransform(spec) {
895
+ if (spec.type === 'ImportDefaultSpecifier') {
896
+ return 'default';
897
+ }
898
+ return getImportedName(spec);
899
+ }
900
+ function appendAutomockFixesForPathMigration(_ref12) {
901
+ var fixer = _ref12.fixer,
902
+ sourceCode = _ref12.sourceCode,
903
+ oldBarrelPath = _ref12.oldBarrelPath,
904
+ newPaths = _ref12.newPaths;
905
+ var automocks = findMatchingAutomocks({
906
+ sourceCode: sourceCode,
907
+ importPath: oldBarrelPath
908
+ });
909
+ if (automocks.length === 0 || newPaths.length === 0) {
910
+ return [];
911
+ }
912
+ var fixes = [];
913
+ var _iterator5 = _createForOfIteratorHelper(automocks),
914
+ _step5;
915
+ try {
916
+ var _loop3 = function _loop3() {
917
+ var automock = _step5.value;
918
+ var newAutomockStatements = newPaths.map(function (path) {
919
+ return buildAutomockStatement({
920
+ path: path,
921
+ quoteChar: automock.quoteChar
922
+ });
923
+ });
924
+ fixes.push(fixer.replaceTextRange(automock.statementNode.range, newAutomockStatements.join('\n')));
925
+ };
926
+ for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
927
+ _loop3();
928
+ }
929
+ } catch (err) {
930
+ _iterator5.e(err);
931
+ } finally {
932
+ _iterator5.f();
933
+ }
934
+ return fixes;
935
+ }
936
+
937
+ /**
938
+ * `require('barrel').default` or `require('barrel').namedExport`
939
+ */
940
+ function handleRequireMemberExpression(_ref13) {
941
+ var node = _ref13.node,
942
+ context = _ref13.context,
943
+ workspaceRoot = _ref13.workspaceRoot,
944
+ fs = _ref13.fs,
945
+ applyToImportsFrom = _ref13.applyToImportsFrom,
946
+ preferImportedPackageSubpath = _ref13.preferImportedPackageSubpath;
947
+ if (node.computed || node.property.type !== 'Identifier') {
948
+ return;
949
+ }
950
+ var reqCall = unwrapToRequireCall(node.object);
951
+ if (!reqCall) {
952
+ return;
953
+ }
954
+ var modulePath = reqCall.arguments[0].value;
955
+ var importContext = resolveImportContextFromModulePath({
956
+ importPath: modulePath,
957
+ workspaceRoot: workspaceRoot,
958
+ fs: fs,
959
+ applyToImportsFrom: applyToImportsFrom
960
+ });
961
+ if (!importContext) {
962
+ return;
963
+ }
964
+ var exportPropertyName = node.property.name;
965
+ var synthetic = buildSyntheticImportFromRequireAccess(exportPropertyName, modulePath);
966
+ var _classifySpecifiers = classifySpecifiers({
967
+ node: synthetic,
968
+ importContext: importContext,
969
+ workspaceRoot: workspaceRoot,
970
+ fs: fs,
971
+ preferImportedPackageSubpath: preferImportedPackageSubpath
972
+ }),
973
+ specifiersByTarget = _classifySpecifiers.specifiersByTarget,
974
+ hasNamespaceImport = _classifySpecifiers.hasNamespaceImport;
975
+ if (hasNamespaceImport || specifiersByTarget.size === 0) {
976
+ return;
977
+ }
978
+ var entries = (0, _toConsumableArray2.default)(specifiersByTarget.entries());
979
+ if (entries.length !== 1) {
980
+ return;
981
+ }
982
+ var _ref14 = entries[0],
983
+ _ref15 = (0, _slicedToArray2.default)(_ref14, 2),
984
+ targetKey = _ref15[0],
985
+ specsWithTarget = _ref15[1];
986
+ if (specsWithTarget.length !== 1) {
987
+ return;
988
+ }
989
+ var st = specsWithTarget[0];
990
+ var newImportPath = fullNewImportPathForTarget(targetKey, specsWithTarget, importContext.packageName);
991
+ var transformed = transformSpecifierForExport({
992
+ spec: st.spec,
993
+ originalName: st.originalName,
994
+ kind: st.kind
995
+ });
996
+ var newRhs = getRhsPropertyAfterTransform(transformed);
997
+ var sourceCode = context.getSourceCode();
998
+ var quote = sourceCode.getText(reqCall.arguments[0])[0];
999
+ context.report({
1000
+ node: node,
1001
+ messageId: 'barrelEntryImport',
1002
+ data: {
1003
+ path: importContext.importPath
1004
+ },
1005
+ fix: function fix(fixer) {
1006
+ var fixes = [];
1007
+ fixes.push(fixer.replaceText(node, "require(".concat(quote).concat(newImportPath).concat(quote, ").").concat(newRhs)));
1008
+ if (st.kind === 'value') {
1009
+ fixes.push.apply(fixes, (0, _toConsumableArray2.default)(appendAutomockFixesForPathMigration({
1010
+ fixer: fixer,
1011
+ sourceCode: sourceCode,
1012
+ oldBarrelPath: modulePath,
1013
+ newPaths: [newImportPath]
1014
+ })));
1015
+ }
1016
+ return fixes;
1017
+ }
1018
+ });
1019
+ }
1020
+
1021
+ /**
1022
+ * `const { a, b } = require('barrel')`
1023
+ */
1024
+ function handleRequireDestructuringDeclarator(_ref16) {
1025
+ var node = _ref16.node,
1026
+ context = _ref16.context,
1027
+ workspaceRoot = _ref16.workspaceRoot,
1028
+ fs = _ref16.fs,
1029
+ applyToImportsFrom = _ref16.applyToImportsFrom,
1030
+ preferImportedPackageSubpath = _ref16.preferImportedPackageSubpath;
1031
+ if (node.id.type !== 'ObjectPattern' || !node.init || node.init.type !== 'CallExpression') {
1032
+ return;
1033
+ }
1034
+ var initCall = node.init;
1035
+ if (!isPlainRequireCall(initCall)) {
1036
+ return;
1037
+ }
1038
+ var modulePath = initCall.arguments[0].value;
1039
+ var importContext = resolveImportContextFromModulePath({
1040
+ importPath: modulePath,
1041
+ workspaceRoot: workspaceRoot,
1042
+ fs: fs,
1043
+ applyToImportsFrom: applyToImportsFrom
1044
+ });
1045
+ if (!importContext) {
1046
+ return;
1047
+ }
1048
+ var specifiers = [];
1049
+ var _iterator6 = _createForOfIteratorHelper(node.id.properties),
1050
+ _step6;
1051
+ try {
1052
+ for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) {
1053
+ var prop = _step6.value;
1054
+ if (prop.type !== 'Property' || prop.computed) {
1055
+ continue;
1056
+ }
1057
+ if (prop.key.type !== 'Identifier' || prop.value.type !== 'Identifier') {
1058
+ continue;
1059
+ }
1060
+ var importedName = prop.key.name;
1061
+ var localName = prop.value.name;
1062
+ specifiers.push({
1063
+ type: 'ImportSpecifier',
1064
+ imported: {
1065
+ type: 'Identifier',
1066
+ name: importedName
1067
+ },
1068
+ local: {
1069
+ type: 'Identifier',
1070
+ name: localName
1071
+ }
1072
+ });
1073
+ }
1074
+ } catch (err) {
1075
+ _iterator6.e(err);
1076
+ } finally {
1077
+ _iterator6.f();
1078
+ }
1079
+ if (specifiers.length === 0) {
1080
+ return;
1081
+ }
1082
+ var synthetic = {
1083
+ type: 'ImportDeclaration',
1084
+ source: {
1085
+ type: 'Literal',
1086
+ value: modulePath,
1087
+ raw: "'".concat(modulePath, "'")
1088
+ },
1089
+ specifiers: specifiers,
1090
+ importKind: 'value'
1091
+ };
1092
+ var _classifySpecifiers2 = classifySpecifiers({
1093
+ node: synthetic,
1094
+ importContext: importContext,
1095
+ workspaceRoot: workspaceRoot,
1096
+ fs: fs,
1097
+ preferImportedPackageSubpath: preferImportedPackageSubpath
1098
+ }),
1099
+ specifiersByTarget = _classifySpecifiers2.specifiersByTarget,
1100
+ unmappedSpecifiers = _classifySpecifiers2.unmappedSpecifiers,
1101
+ hasNamespaceImport = _classifySpecifiers2.hasNamespaceImport;
1102
+ if (hasNamespaceImport || specifiersByTarget.size === 0 || unmappedSpecifiers.length > 0) {
1103
+ return;
1104
+ }
1105
+ var parentDecl = node.parent;
1106
+ if (parentDecl.type !== 'VariableDeclaration') {
1107
+ return;
1108
+ }
1109
+ if (specifiersByTarget.size > 1 && parentDecl.declarations.length !== 1) {
1110
+ return;
1111
+ }
1112
+ var sourceCode = context.getSourceCode();
1113
+ var quote = sourceCode.getText(initCall.arguments[0])[0];
1114
+ var pkg = importContext.packageName;
1115
+ var buildFixes = function buildFixes(fixer) {
1116
+ var fixes = [];
1117
+ var hasValue = false;
1118
+ var automockPaths = [];
1119
+ if (specifiersByTarget.size === 1) {
1120
+ var _ref17 = (0, _toConsumableArray2.default)(specifiersByTarget.entries())[0],
1121
+ _ref18 = (0, _slicedToArray2.default)(_ref17, 2),
1122
+ targetKey = _ref18[0],
1123
+ specsWithTarget = _ref18[1];
1124
+ var newImportPath = fullNewImportPathForTarget(targetKey, specsWithTarget, pkg);
1125
+ if (specsWithTarget.some(function (s) {
1126
+ return s.kind === 'value';
1127
+ })) {
1128
+ hasValue = true;
1129
+ automockPaths.push(newImportPath);
1130
+ }
1131
+ fixes.push(fixer.replaceText(initCall.arguments[0], "".concat(quote).concat(newImportPath).concat(quote)));
1132
+ } else {
1133
+ var lines = [];
1134
+ var _iterator7 = _createForOfIteratorHelper(specifiersByTarget),
1135
+ _step7;
1136
+ try {
1137
+ for (_iterator7.s(); !(_step7 = _iterator7.n()).done;) {
1138
+ var _step7$value = (0, _slicedToArray2.default)(_step7.value, 2),
1139
+ _targetKey = _step7$value[0],
1140
+ _specsWithTarget = _step7$value[1];
1141
+ var _newImportPath = fullNewImportPathForTarget(_targetKey, _specsWithTarget, pkg);
1142
+ if (_specsWithTarget.some(function (s) {
1143
+ return s.kind === 'value';
1144
+ })) {
1145
+ hasValue = true;
1146
+ automockPaths.push(_newImportPath);
1147
+ }
1148
+ var _iterator8 = _createForOfIteratorHelper(_specsWithTarget),
1149
+ _step8;
1150
+ try {
1151
+ for (_iterator8.s(); !(_step8 = _iterator8.n()).done;) {
1152
+ var st = _step8.value;
1153
+ var transformed = transformSpecifierForExport({
1154
+ spec: st.spec,
1155
+ originalName: st.originalName,
1156
+ kind: st.kind
1157
+ });
1158
+ var rhs = getRhsPropertyAfterTransform(transformed);
1159
+ var local = st.spec.local.name;
1160
+ lines.push("".concat(local, " = require(").concat(quote).concat(_newImportPath).concat(quote, ").").concat(rhs));
1161
+ }
1162
+ } catch (err) {
1163
+ _iterator8.e(err);
1164
+ } finally {
1165
+ _iterator8.f();
1166
+ }
1167
+ }
1168
+ } catch (err) {
1169
+ _iterator7.e(err);
1170
+ } finally {
1171
+ _iterator7.f();
1172
+ }
1173
+ var declText = lines.map(function (l) {
1174
+ return "".concat(parentDecl.kind, " ").concat(l, ";");
1175
+ }).join('\n');
1176
+ fixes.push(fixer.replaceText(parentDecl, declText));
1177
+ }
1178
+ if (hasValue) {
1179
+ fixes.push.apply(fixes, (0, _toConsumableArray2.default)(appendAutomockFixesForPathMigration({
1180
+ fixer: fixer,
1181
+ sourceCode: sourceCode,
1182
+ oldBarrelPath: modulePath,
1183
+ newPaths: (0, _toConsumableArray2.default)(new Set(automockPaths))
1184
+ })));
1185
+ }
1186
+ return fixes;
1187
+ };
1188
+ context.report({
1189
+ node: initCall,
1190
+ messageId: 'barrelEntryImport',
1191
+ data: {
1192
+ path: importContext.importPath
1193
+ },
1194
+ fix: buildFixes
1195
+ });
1196
+ }
761
1197
 
762
1198
  /**
763
1199
  * Handles an ImportDeclaration node to check for barrel file imports.
764
1200
  * Reports and auto-fixes imports that could use more specific export paths.
765
1201
  */
766
- function handleImportDeclaration(_ref11) {
767
- var node = _ref11.node,
768
- context = _ref11.context,
769
- workspaceRoot = _ref11.workspaceRoot,
770
- fs = _ref11.fs,
771
- applyToImportsFrom = _ref11.applyToImportsFrom;
1202
+ function handleImportDeclaration(_ref19) {
1203
+ var node = _ref19.node,
1204
+ context = _ref19.context,
1205
+ workspaceRoot = _ref19.workspaceRoot,
1206
+ fs = _ref19.fs,
1207
+ applyToImportsFrom = _ref19.applyToImportsFrom,
1208
+ preferImportedPackageSubpath = _ref19.preferImportedPackageSubpath;
772
1209
  // Resolve import context (validates and extracts package/export info)
773
1210
  // applyToImportsFrom is used here to filter which packages the rule applies to
774
1211
  var importContext = resolveImportContext({
@@ -787,15 +1224,16 @@ function handleImportDeclaration(_ref11) {
787
1224
  }
788
1225
 
789
1226
  // Classify specifiers by their target export paths
790
- var _classifySpecifiers = classifySpecifiers({
1227
+ var _classifySpecifiers3 = classifySpecifiers({
791
1228
  node: node,
792
1229
  importContext: importContext,
793
1230
  workspaceRoot: workspaceRoot,
794
- fs: fs
1231
+ fs: fs,
1232
+ preferImportedPackageSubpath: preferImportedPackageSubpath
795
1233
  }),
796
- specifiersByTarget = _classifySpecifiers.specifiersByTarget,
797
- unmappedSpecifiers = _classifySpecifiers.unmappedSpecifiers,
798
- hasNamespaceImport = _classifySpecifiers.hasNamespaceImport;
1234
+ specifiersByTarget = _classifySpecifiers3.specifiersByTarget,
1235
+ unmappedSpecifiers = _classifySpecifiers3.unmappedSpecifiers,
1236
+ hasNamespaceImport = _classifySpecifiers3.hasNamespaceImport;
799
1237
 
800
1238
  // If namespace import, report without auto-fix if there are specific exports available
801
1239
  if (hasNamespaceImport) {
@@ -844,9 +1282,10 @@ function createRule(fs) {
844
1282
  return {
845
1283
  meta: ruleMeta,
846
1284
  create: function create(context) {
847
- var _options$applyToImpor;
1285
+ var _options$applyToImpor, _options$preferImport;
848
1286
  var options = context.options[0] || {};
849
1287
  var applyToImportsFrom = (_options$applyToImpor = options.applyToImportsFrom) !== null && _options$applyToImpor !== void 0 ? _options$applyToImpor : _fileSystem.DEFAULT_TARGET_FOLDERS;
1288
+ var preferImportedPackageSubpath = (_options$preferImport = options.preferImportedPackageSubpath) !== null && _options$preferImport !== void 0 ? _options$preferImport : false;
850
1289
  var workspaceRoot = (0, _fileSystem.findWorkspaceRoot)({
851
1290
  startPath: (0, _path.dirname)(context.filename),
852
1291
  fs: fs,
@@ -860,7 +1299,28 @@ function createRule(fs) {
860
1299
  context: context,
861
1300
  workspaceRoot: workspaceRoot,
862
1301
  fs: fs,
863
- applyToImportsFrom: applyToImportsFrom
1302
+ applyToImportsFrom: applyToImportsFrom,
1303
+ preferImportedPackageSubpath: preferImportedPackageSubpath
1304
+ });
1305
+ },
1306
+ MemberExpression: function MemberExpression(rawNode) {
1307
+ handleRequireMemberExpression({
1308
+ node: rawNode,
1309
+ context: context,
1310
+ workspaceRoot: workspaceRoot,
1311
+ fs: fs,
1312
+ applyToImportsFrom: applyToImportsFrom,
1313
+ preferImportedPackageSubpath: preferImportedPackageSubpath
1314
+ });
1315
+ },
1316
+ VariableDeclarator: function VariableDeclarator(rawNode) {
1317
+ handleRequireDestructuringDeclarator({
1318
+ node: rawNode,
1319
+ context: context,
1320
+ workspaceRoot: workspaceRoot,
1321
+ fs: fs,
1322
+ applyToImportsFrom: applyToImportsFrom,
1323
+ preferImportedPackageSubpath: preferImportedPackageSubpath
864
1324
  });
865
1325
  }
866
1326
  };