@atlaskit/eslint-plugin-platform 2.9.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 (29) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/dist/cjs/index.js +2 -0
  3. package/dist/cjs/rules/ensure-critical-dependency-resolutions/index.js +0 -1
  4. package/dist/cjs/rules/import/no-barrel-entry-imports/index.js +68 -16
  5. package/dist/cjs/rules/import/no-barrel-entry-jest-mock/index.js +42 -8
  6. package/dist/cjs/rules/import/shared/package-resolution.js +153 -8
  7. package/dist/cjs/rules/no-restricted-fedramp-imports/index.js +65 -0
  8. package/dist/cjs/rules/visit-example-type-import-required/index.js +1 -1
  9. package/dist/es2019/index.js +2 -0
  10. package/dist/es2019/rules/ensure-critical-dependency-resolutions/index.js +0 -1
  11. package/dist/es2019/rules/import/no-barrel-entry-imports/index.js +66 -17
  12. package/dist/es2019/rules/import/no-barrel-entry-jest-mock/index.js +43 -9
  13. package/dist/es2019/rules/import/shared/package-resolution.js +119 -4
  14. package/dist/es2019/rules/no-restricted-fedramp-imports/index.js +47 -0
  15. package/dist/es2019/rules/visit-example-type-import-required/index.js +1 -1
  16. package/dist/esm/index.js +2 -0
  17. package/dist/esm/rules/ensure-critical-dependency-resolutions/index.js +0 -1
  18. package/dist/esm/rules/import/no-barrel-entry-imports/index.js +69 -17
  19. package/dist/esm/rules/import/no-barrel-entry-jest-mock/index.js +43 -9
  20. package/dist/esm/rules/import/shared/package-resolution.js +151 -8
  21. package/dist/esm/rules/no-restricted-fedramp-imports/index.js +59 -0
  22. package/dist/esm/rules/visit-example-type-import-required/index.js +1 -1
  23. package/dist/types/index.d.ts +2 -0
  24. package/dist/types/rules/import/shared/package-resolution.d.ts +25 -0
  25. package/dist/types/rules/no-restricted-fedramp-imports/index.d.ts +3 -0
  26. package/dist/types-ts4.5/index.d.ts +2 -0
  27. package/dist/types-ts4.5/rules/import/shared/package-resolution.d.ts +25 -0
  28. package/dist/types-ts4.5/rules/no-restricted-fedramp-imports/index.d.ts +3 -0
  29. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # @atlaskit/eslint-plugin-platform
2
2
 
3
+ ## 2.9.1
4
+
5
+ ### Patch Changes
6
+
7
+ - [`5fed54075f1b8`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/5fed54075f1b8) -
8
+ add eslint rule for restricting isFedramp and isIsolatedCloud imports
9
+
3
10
  ## 2.9.0
4
11
 
5
12
  ### Minor Changes
package/dist/cjs/index.js CHANGED
@@ -36,6 +36,7 @@ var _noSparseCheckout = _interopRequireDefault(require("./rules/no-sparse-checko
36
36
  var _noDirectDocumentUsage = _interopRequireDefault(require("./rules/no-direct-document-usage"));
37
37
  var _noSetImmediate = _interopRequireDefault(require("./rules/no-set-immediate"));
38
38
  var _preferCryptoRandomUuid = _interopRequireDefault(require("./rules/prefer-crypto-random-uuid"));
39
+ var _noRestrictedFedrampImports = _interopRequireDefault(require("./rules/no-restricted-fedramp-imports"));
39
40
  var _noBarrelEntryImports = _interopRequireDefault(require("./rules/import/no-barrel-entry-imports"));
40
41
  var _noBarrelEntryJestMock = _interopRequireDefault(require("./rules/import/no-barrel-entry-jest-mock"));
41
42
  var _noJestMockBarrelFiles = _interopRequireDefault(require("./rules/import/no-jest-mock-barrel-files"));
@@ -94,6 +95,7 @@ var rules = exports.rules = {
94
95
  'no-direct-document-usage': _noDirectDocumentUsage.default,
95
96
  'no-set-immediate': _noSetImmediate.default,
96
97
  'prefer-crypto-random-uuid': _preferCryptoRandomUuid.default,
98
+ 'no-restricted-fedramp-imports': _noRestrictedFedrampImports.default,
97
99
  'no-barrel-entry-imports': _noBarrelEntryImports.default,
98
100
  'no-barrel-entry-jest-mock': _noBarrelEntryJestMock.default,
99
101
  'no-jest-mock-barrel-files': _noJestMockBarrelFiles.default,
@@ -18,7 +18,6 @@ var DESIRED_PKG_VERSIONS = {
18
18
  tslib: ['2.6', '2.8'],
19
19
  '@types/react': ['16.14', '18.2', '18.3'],
20
20
  'react-relay': ['npm:atl-react-relay@0.0.0-main-39e79f66'],
21
- 'relay-compiler': ['npm:atl-relay-compiler@0.0.0-main-39e79f66'],
22
21
  'relay-runtime': ['npm:atl-relay-runtime@0.0.0-main-39e79f66'],
23
22
  'relay-test-utils': ['npm:atl-relay-test-utils@0.0.0-main-39e79f66']
24
23
  };
@@ -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
@@ -247,10 +251,12 @@ function classifySpecifiers(_ref4) {
247
251
  var node = _ref4.node,
248
252
  importContext = _ref4.importContext,
249
253
  workspaceRoot = _ref4.workspaceRoot,
250
- fs = _ref4.fs;
254
+ fs = _ref4.fs,
255
+ preferImportedPackageSubpath = _ref4.preferImportedPackageSubpath;
251
256
  var currentExportPath = importContext.currentExportPath,
252
257
  exportsMap = importContext.exportsMap,
253
- exportMap = importContext.exportMap;
258
+ exportMap = importContext.exportMap,
259
+ importedPackageName = importContext.packageName;
254
260
  var specifiers = node.specifiers;
255
261
  var specifiersByTarget = new Map();
256
262
  var unmappedSpecifiers = [];
@@ -271,6 +277,7 @@ function classifySpecifiers(_ref4) {
271
277
  var kind = 'value';
272
278
  if (spec.type === 'ImportDefaultSpecifier') {
273
279
  nameInSource = 'default';
280
+ kind = node.importKind === 'type' ? 'type' : 'value';
274
281
  } else if (spec.type === 'ImportSpecifier') {
275
282
  nameInSource = getImportedName(spec);
276
283
  var parentImportKind = node.importKind;
@@ -286,6 +293,36 @@ function classifySpecifiers(_ref4) {
286
293
  // Check if this is a cross-package re-export
287
294
  var sourcePackageName = (_exportInfo$crossPack = exportInfo.crossPackageSource) === null || _exportInfo$crossPack === void 0 ? void 0 : _exportInfo$crossPack.packageName;
288
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
+
289
326
  // For cross-package re-exports, find the most specific subpath in the source package
290
327
  // Note: Package resolution is not constrained by applyToImportsFrom - any package can be resolved
291
328
  var sourcePackageExportsMap = sourcePackageExportsMaps.get(sourcePackageName);
@@ -306,7 +343,6 @@ function classifySpecifiers(_ref4) {
306
343
 
307
344
  // Find the best export path in the source package
308
345
  var _targetExportPath = null;
309
- var resolvedOriginalName = exportInfo.originalName;
310
346
  if (sourcePackageExportsMap) {
311
347
  var _exportInfo$originalN, _matchResult$exportPa;
312
348
  var _sourceExportName = (_exportInfo$originalN = exportInfo.originalName) !== null && _exportInfo$originalN !== void 0 ? _exportInfo$originalN : nameInSource;
@@ -323,7 +359,7 @@ function classifySpecifiers(_ref4) {
323
359
  }
324
360
 
325
361
  // Build the full import path: @package/subpath or just @package if no subpath found
326
- var targetKey = _targetExportPath ? sourcePackageName + _targetExportPath.slice(1) // Remove leading '.' from subpath
362
+ targetKey = _targetExportPath ? sourcePackageName + _targetExportPath.slice(1) // Remove leading '.' from subpath
327
363
  : sourcePackageName;
328
364
  if (!specifiersByTarget.has(targetKey)) {
329
365
  specifiersByTarget.set(targetKey, []);
@@ -698,7 +734,10 @@ function createBarrelImportFix(_ref0) {
698
734
  }
699
735
  } else {
700
736
  // Create new import
701
- 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;
702
741
  var importStatement = buildImportStatement({
703
742
  specs: specs,
704
743
  path: newImportPath,
@@ -724,7 +763,10 @@ function createBarrelImportFix(_ref0) {
724
763
  var unmappedSpecs = unmappedSpecifiers.map(function (u) {
725
764
  return u.spec;
726
765
  });
727
- 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;
728
770
  var remainingImport = buildImportStatement({
729
771
  specs: unmappedSpecs,
730
772
  path: importPath,
@@ -900,7 +942,8 @@ function handleRequireMemberExpression(_ref13) {
900
942
  context = _ref13.context,
901
943
  workspaceRoot = _ref13.workspaceRoot,
902
944
  fs = _ref13.fs,
903
- applyToImportsFrom = _ref13.applyToImportsFrom;
945
+ applyToImportsFrom = _ref13.applyToImportsFrom,
946
+ preferImportedPackageSubpath = _ref13.preferImportedPackageSubpath;
904
947
  if (node.computed || node.property.type !== 'Identifier') {
905
948
  return;
906
949
  }
@@ -924,7 +967,8 @@ function handleRequireMemberExpression(_ref13) {
924
967
  node: synthetic,
925
968
  importContext: importContext,
926
969
  workspaceRoot: workspaceRoot,
927
- fs: fs
970
+ fs: fs,
971
+ preferImportedPackageSubpath: preferImportedPackageSubpath
928
972
  }),
929
973
  specifiersByTarget = _classifySpecifiers.specifiersByTarget,
930
974
  hasNamespaceImport = _classifySpecifiers.hasNamespaceImport;
@@ -982,7 +1026,8 @@ function handleRequireDestructuringDeclarator(_ref16) {
982
1026
  context = _ref16.context,
983
1027
  workspaceRoot = _ref16.workspaceRoot,
984
1028
  fs = _ref16.fs,
985
- applyToImportsFrom = _ref16.applyToImportsFrom;
1029
+ applyToImportsFrom = _ref16.applyToImportsFrom,
1030
+ preferImportedPackageSubpath = _ref16.preferImportedPackageSubpath;
986
1031
  if (node.id.type !== 'ObjectPattern' || !node.init || node.init.type !== 'CallExpression') {
987
1032
  return;
988
1033
  }
@@ -1048,7 +1093,8 @@ function handleRequireDestructuringDeclarator(_ref16) {
1048
1093
  node: synthetic,
1049
1094
  importContext: importContext,
1050
1095
  workspaceRoot: workspaceRoot,
1051
- fs: fs
1096
+ fs: fs,
1097
+ preferImportedPackageSubpath: preferImportedPackageSubpath
1052
1098
  }),
1053
1099
  specifiersByTarget = _classifySpecifiers2.specifiersByTarget,
1054
1100
  unmappedSpecifiers = _classifySpecifiers2.unmappedSpecifiers,
@@ -1158,7 +1204,8 @@ function handleImportDeclaration(_ref19) {
1158
1204
  context = _ref19.context,
1159
1205
  workspaceRoot = _ref19.workspaceRoot,
1160
1206
  fs = _ref19.fs,
1161
- applyToImportsFrom = _ref19.applyToImportsFrom;
1207
+ applyToImportsFrom = _ref19.applyToImportsFrom,
1208
+ preferImportedPackageSubpath = _ref19.preferImportedPackageSubpath;
1162
1209
  // Resolve import context (validates and extracts package/export info)
1163
1210
  // applyToImportsFrom is used here to filter which packages the rule applies to
1164
1211
  var importContext = resolveImportContext({
@@ -1181,7 +1228,8 @@ function handleImportDeclaration(_ref19) {
1181
1228
  node: node,
1182
1229
  importContext: importContext,
1183
1230
  workspaceRoot: workspaceRoot,
1184
- fs: fs
1231
+ fs: fs,
1232
+ preferImportedPackageSubpath: preferImportedPackageSubpath
1185
1233
  }),
1186
1234
  specifiersByTarget = _classifySpecifiers3.specifiersByTarget,
1187
1235
  unmappedSpecifiers = _classifySpecifiers3.unmappedSpecifiers,
@@ -1234,9 +1282,10 @@ function createRule(fs) {
1234
1282
  return {
1235
1283
  meta: ruleMeta,
1236
1284
  create: function create(context) {
1237
- var _options$applyToImpor;
1285
+ var _options$applyToImpor, _options$preferImport;
1238
1286
  var options = context.options[0] || {};
1239
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;
1240
1289
  var workspaceRoot = (0, _fileSystem.findWorkspaceRoot)({
1241
1290
  startPath: (0, _path.dirname)(context.filename),
1242
1291
  fs: fs,
@@ -1250,7 +1299,8 @@ function createRule(fs) {
1250
1299
  context: context,
1251
1300
  workspaceRoot: workspaceRoot,
1252
1301
  fs: fs,
1253
- applyToImportsFrom: applyToImportsFrom
1302
+ applyToImportsFrom: applyToImportsFrom,
1303
+ preferImportedPackageSubpath: preferImportedPackageSubpath
1254
1304
  });
1255
1305
  },
1256
1306
  MemberExpression: function MemberExpression(rawNode) {
@@ -1259,7 +1309,8 @@ function createRule(fs) {
1259
1309
  context: context,
1260
1310
  workspaceRoot: workspaceRoot,
1261
1311
  fs: fs,
1262
- applyToImportsFrom: applyToImportsFrom
1312
+ applyToImportsFrom: applyToImportsFrom,
1313
+ preferImportedPackageSubpath: preferImportedPackageSubpath
1263
1314
  });
1264
1315
  },
1265
1316
  VariableDeclarator: function VariableDeclarator(rawNode) {
@@ -1268,7 +1319,8 @@ function createRule(fs) {
1268
1319
  context: context,
1269
1320
  workspaceRoot: workspaceRoot,
1270
1321
  fs: fs,
1271
- applyToImportsFrom: applyToImportsFrom
1322
+ applyToImportsFrom: applyToImportsFrom,
1323
+ preferImportedPackageSubpath: preferImportedPackageSubpath
1272
1324
  });
1273
1325
  }
1274
1326
  };
@@ -671,7 +671,9 @@ function traceSymbolsToExports(_ref10) {
671
671
  exportMap = _ref10.exportMap,
672
672
  exportsMap = _ref10.exportsMap,
673
673
  currentExportPath = _ref10.currentExportPath,
674
- fs = _ref10.fs;
674
+ fs = _ref10.fs,
675
+ barrelPackageName = _ref10.barrelPackageName,
676
+ preferImportedPackageSubpath = _ref10.preferImportedPackageSubpath;
675
677
  var groupedByExport = new Map();
676
678
  var crossPackageGroups = new Map();
677
679
  var unmappedSymbols = [];
@@ -689,16 +691,38 @@ function traceSymbolsToExports(_ref10) {
689
691
 
690
692
  // Check for cross-package source first
691
693
  if (exportInfo.crossPackageSource) {
692
- var key = "".concat(exportInfo.crossPackageSource.packageName).concat(exportInfo.crossPackageSource.exportPath === '.' ? '' : exportInfo.crossPackageSource.exportPath.slice(1));
694
+ var key = void 0;
695
+ var tracedOriginalName = exportInfo.originalName;
696
+ var barrelBridgeExportPath = void 0;
697
+ if (preferImportedPackageSubpath) {
698
+ var bridge = (0, _packageResolution.findCrossPackageBridgeExportPath)({
699
+ exportsMap: exportsMap,
700
+ crossPackageName: exportInfo.crossPackageSource.packageName,
701
+ exportedName: symbolName,
702
+ fs: fs
703
+ });
704
+ if (bridge) {
705
+ key = "".concat(barrelPackageName).concat(bridge.exportPath.slice(1));
706
+ barrelBridgeExportPath = bridge.exportPath;
707
+ if (bridge.entryPointExportName !== undefined) {
708
+ tracedOriginalName = bridge.entryPointExportName === symbolName ? undefined : bridge.entryPointExportName;
709
+ }
710
+ } else {
711
+ key = "".concat(exportInfo.crossPackageSource.packageName).concat(exportInfo.crossPackageSource.exportPath === '.' ? '' : exportInfo.crossPackageSource.exportPath.slice(1));
712
+ }
713
+ } else {
714
+ key = "".concat(exportInfo.crossPackageSource.packageName).concat(exportInfo.crossPackageSource.exportPath === '.' ? '' : exportInfo.crossPackageSource.exportPath.slice(1));
715
+ }
693
716
  if (!crossPackageGroups.has(key)) {
694
717
  crossPackageGroups.set(key, []);
695
718
  }
696
719
  crossPackageGroups.get(key).push({
697
720
  symbolName: symbolName,
698
- originalName: exportInfo.originalName,
721
+ originalName: tracedOriginalName,
699
722
  sourceFilePath: exportInfo.path,
700
723
  isTypeOnly: exportInfo.isTypeOnly,
701
- crossPackageSource: exportInfo.crossPackageSource
724
+ crossPackageSource: exportInfo.crossPackageSource,
725
+ barrelBridgeExportPath: barrelBridgeExportPath
702
726
  });
703
727
  continue;
704
728
  }
@@ -1069,6 +1093,10 @@ var ruleMeta = {
1069
1093
  type: 'string'
1070
1094
  },
1071
1095
  description: 'The folder paths (relative to workspace root) containing packages whose imports will be checked and autofixed.'
1096
+ },
1097
+ preferImportedPackageSubpath: {
1098
+ type: 'boolean',
1099
+ description: 'Prefer subpaths on the mocked barrel package when they bridge to the dependency.'
1072
1100
  }
1073
1101
  },
1074
1102
  additionalProperties: false
@@ -1087,9 +1115,10 @@ function createRule(fs) {
1087
1115
  return {
1088
1116
  meta: ruleMeta,
1089
1117
  create: function create(context) {
1090
- var _options$applyToImpor;
1118
+ var _options$applyToImpor, _options$preferImport;
1091
1119
  var options = context.options[0] || {};
1092
1120
  var applyToImportsFrom = (_options$applyToImpor = options.applyToImportsFrom) !== null && _options$applyToImpor !== void 0 ? _options$applyToImpor : _fileSystem.DEFAULT_TARGET_FOLDERS;
1121
+ var preferImportedPackageSubpath = (_options$preferImport = options.preferImportedPackageSubpath) !== null && _options$preferImport !== void 0 ? _options$preferImport : false;
1093
1122
  var workspaceRoot = (0, _fileSystem.findWorkspaceRoot)({
1094
1123
  startPath: (0, _path.dirname)(context.filename),
1095
1124
  fs: fs,
@@ -1184,7 +1213,9 @@ function createRule(fs) {
1184
1213
  exportMap: raContext.exportMap,
1185
1214
  exportsMap: raContext.exportsMap,
1186
1215
  currentExportPath: raContext.currentExportPath,
1187
- fs: fs
1216
+ fs: fs,
1217
+ barrelPackageName: raContext.packageName,
1218
+ preferImportedPackageSubpath: preferImportedPackageSubpath
1188
1219
  }),
1189
1220
  _groupedByExport = _traceSymbolsToExport.groupedByExport,
1190
1221
  _crossPackageGroups = _traceSymbolsToExport.crossPackageGroups;
@@ -1281,7 +1312,9 @@ function createRule(fs) {
1281
1312
  exportMap: mockContext.exportMap,
1282
1313
  exportsMap: mockContext.exportsMap,
1283
1314
  currentExportPath: mockContext.currentExportPath,
1284
- fs: fs
1315
+ fs: fs,
1316
+ barrelPackageName: mockContext.packageName,
1317
+ preferImportedPackageSubpath: preferImportedPackageSubpath
1285
1318
  }),
1286
1319
  groupedByExport = _traceSymbolsToExport2.groupedByExport,
1287
1320
  crossPackageGroups = _traceSymbolsToExport2.crossPackageGroups,
@@ -1373,8 +1406,9 @@ function createRule(fs) {
1373
1406
 
1374
1407
  // Get cross-package source info from the first symbol (all symbols in same group have same source)
1375
1408
  var crossPackageSource = _symbols[0].crossPackageSource;
1409
+ var bridgeExportPath = _symbols[0].barrelBridgeExportPath;
1376
1410
  crossPackageMockGroups.push({
1377
- exportPath: crossPackageSource.exportPath,
1411
+ exportPath: bridgeExportPath !== null && bridgeExportPath !== void 0 ? bridgeExportPath : crossPackageSource.exportPath,
1378
1412
  importPath: _importPath,
1379
1413
  propertyNames: _symbols.map(function (s) {
1380
1414
  return s.symbolName;
@@ -6,7 +6,9 @@ Object.defineProperty(exports, "__esModule", {
6
6
  value: true
7
7
  });
8
8
  exports.extractPackageNameFromImport = extractPackageNameFromImport;
9
+ exports.findCrossPackageBridgeExportPath = findCrossPackageBridgeExportPath;
9
10
  exports.findExportForSourceFile = findExportForSourceFile;
11
+ exports.isKebabCaseExportKey = isKebabCaseExportKey;
10
12
  exports.parsePackageExports = parsePackageExports;
11
13
  exports.resolveCrossPackageImport = resolveCrossPackageImport;
12
14
  var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
@@ -173,10 +175,52 @@ function parsePackageExports(_ref2) {
173
175
  });
174
176
  return exportsMap;
175
177
  }
178
+ /**
179
+ * Check whether a subpath export key (e.g. `"./checkbox-select"`) is kebab-case.
180
+ *
181
+ * A key is considered kebab-case when the portion after the leading `"./"` prefix
182
+ * consists only of lowercase letters, digits, hyphens, dots, and forward-slash
183
+ * separators — i.e. no uppercase letters, underscores, or camelCase humps.
184
+ */
185
+ function isKebabCaseExportKey(key) {
186
+ var body = key.replace(/^\.\//, '');
187
+ if (body.length === 0) {
188
+ return false;
189
+ }
190
+ return /^[a-z0-9][a-z0-9\-./]*$/.test(body);
191
+ }
192
+
193
+ /**
194
+ * Given a list of candidate {@link ExportMatchResult}s that all resolve to the same
195
+ * source file, pick the best one. When any candidate's export path is kebab-case
196
+ * and points to an entry-point file, prefer it over non-kebab-case alternatives.
197
+ * Falls back to the first candidate if no kebab-case entry-point candidate is found.
198
+ */
199
+ function pickBestMatch(candidates, exportsMap) {
200
+ if (candidates.length === 1) {
201
+ return candidates[0];
202
+ }
203
+
204
+ // Among candidates whose value is an entry-point file, prefer kebab-case keys.
205
+ var entryPointKebab = candidates.filter(function (c) {
206
+ var resolved = exportsMap.get(c.exportPath);
207
+ return resolved && isInEntryPointsFolder(resolved) && isKebabCaseExportKey(c.exportPath);
208
+ });
209
+ if (entryPointKebab.length > 0) {
210
+ return entryPointKebab[0];
211
+ }
212
+
213
+ // Fall back to the first candidate (preserves previous behaviour).
214
+ return candidates[0];
215
+ }
216
+
176
217
  /**
177
218
  * Find a matching export entry for a given source file path.
178
219
  * Returns the export path (e.g., "./controllers/analytics") or null if not found.
179
220
  *
221
+ * When multiple export paths resolve to the same source file **and** point to an
222
+ * entry-point file, kebab-case keys are preferred over other casing styles.
223
+ *
180
224
  * When `fs` is provided, also checks entry-point wrapper files. If an export resolves
181
225
  * to a file inside a recognized entry-points folder (entry-points, entrypoints, etc.),
182
226
  * the wrapper is parsed to see if it re-exports from `sourceFilePath`.
@@ -190,6 +234,8 @@ function findExportForSourceFile(_ref3) {
190
234
  exportsMap = _ref3.exportsMap,
191
235
  fs = _ref3.fs,
192
236
  sourceExportName = _ref3.sourceExportName;
237
+ // --- Phase 1: direct matches (export value === sourceFilePath) ---
238
+ var directMatches = [];
193
239
  var _iterator3 = _createForOfIteratorHelper(exportsMap),
194
240
  _step3;
195
241
  try {
@@ -198,9 +244,9 @@ function findExportForSourceFile(_ref3) {
198
244
  _exportPath = _step3$value[0],
199
245
  _resolvedPath = _step3$value[1];
200
246
  if (_resolvedPath === sourceFilePath) {
201
- return {
247
+ directMatches.push({
202
248
  exportPath: _exportPath
203
- };
249
+ });
204
250
  }
205
251
  }
206
252
  } catch (err) {
@@ -208,7 +254,13 @@ function findExportForSourceFile(_ref3) {
208
254
  } finally {
209
255
  _iterator3.f();
210
256
  }
257
+ if (directMatches.length > 0) {
258
+ return pickBestMatch(directMatches, exportsMap);
259
+ }
260
+
261
+ // --- Phase 2: entry-point wrapper re-export matches ---
211
262
  if (fs) {
263
+ var entryPointMatches = [];
212
264
  var _iterator4 = _createForOfIteratorHelper(exportsMap),
213
265
  _step4;
214
266
  try {
@@ -231,10 +283,10 @@ function findExportForSourceFile(_ref3) {
231
283
  if (sourceExportName !== undefined && reExport.nameMap.has(sourceExportName)) {
232
284
  entryPointExportName = reExport.nameMap.get(sourceExportName);
233
285
  }
234
- return {
286
+ entryPointMatches.push({
235
287
  exportPath: exportPath,
236
288
  entryPointExportName: entryPointExportName
237
- };
289
+ });
238
290
  }
239
291
  }
240
292
  } catch (err) {
@@ -249,6 +301,99 @@ function findExportForSourceFile(_ref3) {
249
301
  } finally {
250
302
  _iterator4.f();
251
303
  }
304
+ if (entryPointMatches.length > 0) {
305
+ return pickBestMatch(entryPointMatches, exportsMap);
306
+ }
307
+ }
308
+ return null;
309
+ }
310
+
311
+ /**
312
+ * When a symbol reaches the consumer through a barrel package that re-exports from
313
+ * `crossPackageName`, find a `package.json` export subpath of that barrel whose entry
314
+ * file directly re-exports the symbol from `crossPackageName` (named exports only).
315
+ *
316
+ * This enables rewriting imports to `@scope/barrel/subpath` instead of
317
+ * `@scope/cross-package/...` when the barrel exposes such a subpath (e.g. `@atlaskit/select/react-select`).
318
+ */
319
+ function findCrossPackageBridgeExportPath(_ref4) {
320
+ var exportsMap = _ref4.exportsMap,
321
+ crossPackageName = _ref4.crossPackageName,
322
+ exportedName = _ref4.exportedName,
323
+ fs = _ref4.fs;
324
+ var _iterator6 = _createForOfIteratorHelper(exportsMap),
325
+ _step6;
326
+ try {
327
+ for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) {
328
+ var _step6$value = (0, _slicedToArray2.default)(_step6.value, 2),
329
+ exportPath = _step6$value[0],
330
+ resolvedPath = _step6$value[1];
331
+ var content = (0, _fileSystem.readFileContent)({
332
+ filePath: resolvedPath,
333
+ fs: fs
334
+ });
335
+ if (!content) {
336
+ continue;
337
+ }
338
+ try {
339
+ var sourceFile = ts.createSourceFile(resolvedPath, content, ts.ScriptTarget.Latest, true);
340
+ var _iterator7 = _createForOfIteratorHelper(sourceFile.statements),
341
+ _step7;
342
+ try {
343
+ for (_iterator7.s(); !(_step7 = _iterator7.n()).done;) {
344
+ var statement = _step7.value;
345
+ if (!ts.isExportDeclaration(statement) || statement.isTypeOnly) {
346
+ continue;
347
+ }
348
+ if (!statement.moduleSpecifier || !ts.isStringLiteral(statement.moduleSpecifier)) {
349
+ continue;
350
+ }
351
+ if (statement.moduleSpecifier.text !== crossPackageName) {
352
+ continue;
353
+ }
354
+ if (!statement.exportClause || ts.isNamespaceExport(statement.exportClause)) {
355
+ continue;
356
+ }
357
+ if (!ts.isNamedExports(statement.exportClause)) {
358
+ continue;
359
+ }
360
+ var _iterator8 = _createForOfIteratorHelper(statement.exportClause.elements),
361
+ _step8;
362
+ try {
363
+ for (_iterator8.s(); !(_step8 = _iterator8.n()).done;) {
364
+ var element = _step8.value;
365
+ if (element.isTypeOnly) {
366
+ continue;
367
+ }
368
+ var publicName = element.name.text;
369
+ if (publicName !== exportedName) {
370
+ continue;
371
+ }
372
+ var entryPointExportName = element.propertyName ? element.propertyName.text : undefined;
373
+ return {
374
+ exportPath: exportPath,
375
+ entryPointExportName: entryPointExportName
376
+ };
377
+ }
378
+ } catch (err) {
379
+ _iterator8.e(err);
380
+ } finally {
381
+ _iterator8.f();
382
+ }
383
+ }
384
+ } catch (err) {
385
+ _iterator7.e(err);
386
+ } finally {
387
+ _iterator7.f();
388
+ }
389
+ } catch (_unused4) {
390
+ // Ignore parse errors for individual export entry files
391
+ }
392
+ }
393
+ } catch (err) {
394
+ _iterator6.e(err);
395
+ } finally {
396
+ _iterator6.f();
252
397
  }
253
398
  return null;
254
399
  }
@@ -272,10 +417,10 @@ function extractPackageNameFromImport(moduleSpecifier) {
272
417
  * Resolve a cross-package import to its package directory and export info.
273
418
  * Returns null if the package is not in the target folder or cannot be resolved.
274
419
  */
275
- function resolveCrossPackageImport(_ref4) {
276
- var moduleSpecifier = _ref4.moduleSpecifier,
277
- workspaceRoot = _ref4.workspaceRoot,
278
- fs = _ref4.fs;
420
+ function resolveCrossPackageImport(_ref5) {
421
+ var moduleSpecifier = _ref5.moduleSpecifier,
422
+ workspaceRoot = _ref5.workspaceRoot,
423
+ fs = _ref5.fs;
279
424
  // Only handle @atlassian/* scoped packages
280
425
  var parsed = extractPackageNameFromImport(moduleSpecifier);
281
426
  if (!parsed) {
@@ -0,0 +1,65 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; }
8
+ function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
9
+ function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
10
+ // eslint-disable-next-line import/no-extraneous-dependencies
11
+
12
+ var RESTRICTED_IMPORTS = {
13
+ '@atlassian/atl-context': ['isFedRamp', 'isIsolatedCloud'],
14
+ '@atlaskit/atlassian-context': ['isFedRamp', 'isIsolatedCloud'],
15
+ '@atlassian/teams-common': ['isFedramp']
16
+ };
17
+ var rule = {
18
+ meta: {
19
+ type: 'problem',
20
+ docs: {
21
+ description: 'Disallow importing deprecated FedRamp/IsolatedCloud context functions. Use isFeatureEnabled from AEM (Atlassian Environment Manager) instead.',
22
+ recommended: true
23
+ },
24
+ messages: {
25
+ noRestrictedFedrampImports: '{{name}} from {{source}} will be deprecated soon. Please use isFeatureEnabled from AEM (Atlassian Environment Manager) instead. See go/AEM for more details.'
26
+ },
27
+ schema: []
28
+ },
29
+ create: function create(context) {
30
+ return {
31
+ ImportDeclaration: function ImportDeclaration(node) {
32
+ var source = node.source.value;
33
+ if (typeof source !== 'string') {
34
+ return;
35
+ }
36
+ var restrictedNames = RESTRICTED_IMPORTS[source];
37
+ if (!restrictedNames) {
38
+ return;
39
+ }
40
+ var _iterator = _createForOfIteratorHelper(node.specifiers),
41
+ _step;
42
+ try {
43
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
44
+ var specifier = _step.value;
45
+ if (specifier.type === 'ImportSpecifier' && restrictedNames.includes(specifier.imported.name)) {
46
+ context.report({
47
+ node: specifier,
48
+ messageId: 'noRestrictedFedrampImports',
49
+ data: {
50
+ name: specifier.imported.name,
51
+ source: source
52
+ }
53
+ });
54
+ }
55
+ }
56
+ } catch (err) {
57
+ _iterator.e(err);
58
+ } finally {
59
+ _iterator.f();
60
+ }
61
+ }
62
+ };
63
+ }
64
+ };
65
+ var _default = exports.default = rule;
@@ -24,7 +24,7 @@ var messages = {
24
24
  suggestFixPath: 'Update import path to match visitExample arguments'
25
25
  };
26
26
  function isTargetFile(filename) {
27
- return filename.endsWith('.spec.tsx');
27
+ return filename.endsWith('.spec.tsx') || filename.endsWith('.spec.ts');
28
28
  }
29
29
 
30
30
  /**
@@ -29,6 +29,7 @@ import noSparseCheckout from './rules/no-sparse-checkout';
29
29
  import noDirectDocumentUsage from './rules/no-direct-document-usage';
30
30
  import noSetImmediate from './rules/no-set-immediate';
31
31
  import preferCryptoRandomUuid from './rules/prefer-crypto-random-uuid';
32
+ import noRestrictedFedrampImports from './rules/no-restricted-fedramp-imports';
32
33
  import noBarrelEntryImports from './rules/import/no-barrel-entry-imports';
33
34
  import noBarrelEntryJestMock from './rules/import/no-barrel-entry-jest-mock';
34
35
  import noJestMockBarrelFiles from './rules/import/no-jest-mock-barrel-files';
@@ -85,6 +86,7 @@ const rules = {
85
86
  'no-direct-document-usage': noDirectDocumentUsage,
86
87
  'no-set-immediate': noSetImmediate,
87
88
  'prefer-crypto-random-uuid': preferCryptoRandomUuid,
89
+ 'no-restricted-fedramp-imports': noRestrictedFedrampImports,
88
90
  'no-barrel-entry-imports': noBarrelEntryImports,
89
91
  'no-barrel-entry-jest-mock': noBarrelEntryJestMock,
90
92
  'no-jest-mock-barrel-files': noJestMockBarrelFiles,