@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.
- package/CHANGELOG.md +7 -0
- package/dist/cjs/index.js +2 -0
- package/dist/cjs/rules/ensure-critical-dependency-resolutions/index.js +0 -1
- package/dist/cjs/rules/import/no-barrel-entry-imports/index.js +68 -16
- package/dist/cjs/rules/import/no-barrel-entry-jest-mock/index.js +42 -8
- package/dist/cjs/rules/import/shared/package-resolution.js +153 -8
- package/dist/cjs/rules/no-restricted-fedramp-imports/index.js +65 -0
- package/dist/cjs/rules/visit-example-type-import-required/index.js +1 -1
- package/dist/es2019/index.js +2 -0
- package/dist/es2019/rules/ensure-critical-dependency-resolutions/index.js +0 -1
- package/dist/es2019/rules/import/no-barrel-entry-imports/index.js +66 -17
- package/dist/es2019/rules/import/no-barrel-entry-jest-mock/index.js +43 -9
- package/dist/es2019/rules/import/shared/package-resolution.js +119 -4
- package/dist/es2019/rules/no-restricted-fedramp-imports/index.js +47 -0
- package/dist/es2019/rules/visit-example-type-import-required/index.js +1 -1
- package/dist/esm/index.js +2 -0
- package/dist/esm/rules/ensure-critical-dependency-resolutions/index.js +0 -1
- package/dist/esm/rules/import/no-barrel-entry-imports/index.js +69 -17
- package/dist/esm/rules/import/no-barrel-entry-jest-mock/index.js +43 -9
- package/dist/esm/rules/import/shared/package-resolution.js +151 -8
- package/dist/esm/rules/no-restricted-fedramp-imports/index.js +59 -0
- package/dist/esm/rules/visit-example-type-import-required/index.js +1 -1
- package/dist/types/index.d.ts +2 -0
- package/dist/types/rules/import/shared/package-resolution.d.ts +25 -0
- package/dist/types/rules/no-restricted-fedramp-imports/index.d.ts +3 -0
- package/dist/types-ts4.5/index.d.ts +2 -0
- package/dist/types-ts4.5/rules/import/shared/package-resolution.d.ts +25 -0
- package/dist/types-ts4.5/rules/no-restricted-fedramp-imports/index.d.ts +3 -0
- package/package.json +1 -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
|
|
@@ -240,10 +244,12 @@ function classifySpecifiers(_ref4) {
|
|
|
240
244
|
var node = _ref4.node,
|
|
241
245
|
importContext = _ref4.importContext,
|
|
242
246
|
workspaceRoot = _ref4.workspaceRoot,
|
|
243
|
-
fs = _ref4.fs
|
|
247
|
+
fs = _ref4.fs,
|
|
248
|
+
preferImportedPackageSubpath = _ref4.preferImportedPackageSubpath;
|
|
244
249
|
var currentExportPath = importContext.currentExportPath,
|
|
245
250
|
exportsMap = importContext.exportsMap,
|
|
246
|
-
exportMap = importContext.exportMap
|
|
251
|
+
exportMap = importContext.exportMap,
|
|
252
|
+
importedPackageName = importContext.packageName;
|
|
247
253
|
var specifiers = node.specifiers;
|
|
248
254
|
var specifiersByTarget = new Map();
|
|
249
255
|
var unmappedSpecifiers = [];
|
|
@@ -264,6 +270,7 @@ function classifySpecifiers(_ref4) {
|
|
|
264
270
|
var kind = 'value';
|
|
265
271
|
if (spec.type === 'ImportDefaultSpecifier') {
|
|
266
272
|
nameInSource = 'default';
|
|
273
|
+
kind = node.importKind === 'type' ? 'type' : 'value';
|
|
267
274
|
} else if (spec.type === 'ImportSpecifier') {
|
|
268
275
|
nameInSource = getImportedName(spec);
|
|
269
276
|
var parentImportKind = node.importKind;
|
|
@@ -279,6 +286,36 @@ function classifySpecifiers(_ref4) {
|
|
|
279
286
|
// Check if this is a cross-package re-export
|
|
280
287
|
var sourcePackageName = (_exportInfo$crossPack = exportInfo.crossPackageSource) === null || _exportInfo$crossPack === void 0 ? void 0 : _exportInfo$crossPack.packageName;
|
|
281
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
|
+
|
|
282
319
|
// For cross-package re-exports, find the most specific subpath in the source package
|
|
283
320
|
// Note: Package resolution is not constrained by applyToImportsFrom - any package can be resolved
|
|
284
321
|
var sourcePackageExportsMap = sourcePackageExportsMaps.get(sourcePackageName);
|
|
@@ -299,7 +336,6 @@ function classifySpecifiers(_ref4) {
|
|
|
299
336
|
|
|
300
337
|
// Find the best export path in the source package
|
|
301
338
|
var _targetExportPath = null;
|
|
302
|
-
var resolvedOriginalName = exportInfo.originalName;
|
|
303
339
|
if (sourcePackageExportsMap) {
|
|
304
340
|
var _exportInfo$originalN, _matchResult$exportPa;
|
|
305
341
|
var _sourceExportName = (_exportInfo$originalN = exportInfo.originalName) !== null && _exportInfo$originalN !== void 0 ? _exportInfo$originalN : nameInSource;
|
|
@@ -316,7 +352,7 @@ function classifySpecifiers(_ref4) {
|
|
|
316
352
|
}
|
|
317
353
|
|
|
318
354
|
// Build the full import path: @package/subpath or just @package if no subpath found
|
|
319
|
-
|
|
355
|
+
targetKey = _targetExportPath ? sourcePackageName + _targetExportPath.slice(1) // Remove leading '.' from subpath
|
|
320
356
|
: sourcePackageName;
|
|
321
357
|
if (!specifiersByTarget.has(targetKey)) {
|
|
322
358
|
specifiersByTarget.set(targetKey, []);
|
|
@@ -691,7 +727,10 @@ function createBarrelImportFix(_ref0) {
|
|
|
691
727
|
}
|
|
692
728
|
} else {
|
|
693
729
|
// Create new import
|
|
694
|
-
var
|
|
730
|
+
var allSpecsAreType = specsWithTarget.every(function (s) {
|
|
731
|
+
return s.kind === 'type';
|
|
732
|
+
});
|
|
733
|
+
var _isTypeImport = node.importKind === 'type' || allSpecsAreType;
|
|
695
734
|
var importStatement = buildImportStatement({
|
|
696
735
|
specs: specs,
|
|
697
736
|
path: newImportPath,
|
|
@@ -717,7 +756,10 @@ function createBarrelImportFix(_ref0) {
|
|
|
717
756
|
var unmappedSpecs = unmappedSpecifiers.map(function (u) {
|
|
718
757
|
return u.spec;
|
|
719
758
|
});
|
|
720
|
-
var
|
|
759
|
+
var allUnmappedAreType = unmappedSpecifiers.every(function (u) {
|
|
760
|
+
return u.kind === 'type';
|
|
761
|
+
});
|
|
762
|
+
var isTypeImport = node.importKind === 'type' || allUnmappedAreType;
|
|
721
763
|
var remainingImport = buildImportStatement({
|
|
722
764
|
specs: unmappedSpecs,
|
|
723
765
|
path: importPath,
|
|
@@ -893,7 +935,8 @@ function handleRequireMemberExpression(_ref13) {
|
|
|
893
935
|
context = _ref13.context,
|
|
894
936
|
workspaceRoot = _ref13.workspaceRoot,
|
|
895
937
|
fs = _ref13.fs,
|
|
896
|
-
applyToImportsFrom = _ref13.applyToImportsFrom
|
|
938
|
+
applyToImportsFrom = _ref13.applyToImportsFrom,
|
|
939
|
+
preferImportedPackageSubpath = _ref13.preferImportedPackageSubpath;
|
|
897
940
|
if (node.computed || node.property.type !== 'Identifier') {
|
|
898
941
|
return;
|
|
899
942
|
}
|
|
@@ -917,7 +960,8 @@ function handleRequireMemberExpression(_ref13) {
|
|
|
917
960
|
node: synthetic,
|
|
918
961
|
importContext: importContext,
|
|
919
962
|
workspaceRoot: workspaceRoot,
|
|
920
|
-
fs: fs
|
|
963
|
+
fs: fs,
|
|
964
|
+
preferImportedPackageSubpath: preferImportedPackageSubpath
|
|
921
965
|
}),
|
|
922
966
|
specifiersByTarget = _classifySpecifiers.specifiersByTarget,
|
|
923
967
|
hasNamespaceImport = _classifySpecifiers.hasNamespaceImport;
|
|
@@ -975,7 +1019,8 @@ function handleRequireDestructuringDeclarator(_ref16) {
|
|
|
975
1019
|
context = _ref16.context,
|
|
976
1020
|
workspaceRoot = _ref16.workspaceRoot,
|
|
977
1021
|
fs = _ref16.fs,
|
|
978
|
-
applyToImportsFrom = _ref16.applyToImportsFrom
|
|
1022
|
+
applyToImportsFrom = _ref16.applyToImportsFrom,
|
|
1023
|
+
preferImportedPackageSubpath = _ref16.preferImportedPackageSubpath;
|
|
979
1024
|
if (node.id.type !== 'ObjectPattern' || !node.init || node.init.type !== 'CallExpression') {
|
|
980
1025
|
return;
|
|
981
1026
|
}
|
|
@@ -1041,7 +1086,8 @@ function handleRequireDestructuringDeclarator(_ref16) {
|
|
|
1041
1086
|
node: synthetic,
|
|
1042
1087
|
importContext: importContext,
|
|
1043
1088
|
workspaceRoot: workspaceRoot,
|
|
1044
|
-
fs: fs
|
|
1089
|
+
fs: fs,
|
|
1090
|
+
preferImportedPackageSubpath: preferImportedPackageSubpath
|
|
1045
1091
|
}),
|
|
1046
1092
|
specifiersByTarget = _classifySpecifiers2.specifiersByTarget,
|
|
1047
1093
|
unmappedSpecifiers = _classifySpecifiers2.unmappedSpecifiers,
|
|
@@ -1151,7 +1197,8 @@ function handleImportDeclaration(_ref19) {
|
|
|
1151
1197
|
context = _ref19.context,
|
|
1152
1198
|
workspaceRoot = _ref19.workspaceRoot,
|
|
1153
1199
|
fs = _ref19.fs,
|
|
1154
|
-
applyToImportsFrom = _ref19.applyToImportsFrom
|
|
1200
|
+
applyToImportsFrom = _ref19.applyToImportsFrom,
|
|
1201
|
+
preferImportedPackageSubpath = _ref19.preferImportedPackageSubpath;
|
|
1155
1202
|
// Resolve import context (validates and extracts package/export info)
|
|
1156
1203
|
// applyToImportsFrom is used here to filter which packages the rule applies to
|
|
1157
1204
|
var importContext = resolveImportContext({
|
|
@@ -1174,7 +1221,8 @@ function handleImportDeclaration(_ref19) {
|
|
|
1174
1221
|
node: node,
|
|
1175
1222
|
importContext: importContext,
|
|
1176
1223
|
workspaceRoot: workspaceRoot,
|
|
1177
|
-
fs: fs
|
|
1224
|
+
fs: fs,
|
|
1225
|
+
preferImportedPackageSubpath: preferImportedPackageSubpath
|
|
1178
1226
|
}),
|
|
1179
1227
|
specifiersByTarget = _classifySpecifiers3.specifiersByTarget,
|
|
1180
1228
|
unmappedSpecifiers = _classifySpecifiers3.unmappedSpecifiers,
|
|
@@ -1227,9 +1275,10 @@ export function createRule(fs) {
|
|
|
1227
1275
|
return {
|
|
1228
1276
|
meta: ruleMeta,
|
|
1229
1277
|
create: function create(context) {
|
|
1230
|
-
var _options$applyToImpor;
|
|
1278
|
+
var _options$applyToImpor, _options$preferImport;
|
|
1231
1279
|
var options = context.options[0] || {};
|
|
1232
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;
|
|
1233
1282
|
var workspaceRoot = findWorkspaceRoot({
|
|
1234
1283
|
startPath: dirname(context.filename),
|
|
1235
1284
|
fs: fs,
|
|
@@ -1243,7 +1292,8 @@ export function createRule(fs) {
|
|
|
1243
1292
|
context: context,
|
|
1244
1293
|
workspaceRoot: workspaceRoot,
|
|
1245
1294
|
fs: fs,
|
|
1246
|
-
applyToImportsFrom: applyToImportsFrom
|
|
1295
|
+
applyToImportsFrom: applyToImportsFrom,
|
|
1296
|
+
preferImportedPackageSubpath: preferImportedPackageSubpath
|
|
1247
1297
|
});
|
|
1248
1298
|
},
|
|
1249
1299
|
MemberExpression: function MemberExpression(rawNode) {
|
|
@@ -1252,7 +1302,8 @@ export function createRule(fs) {
|
|
|
1252
1302
|
context: context,
|
|
1253
1303
|
workspaceRoot: workspaceRoot,
|
|
1254
1304
|
fs: fs,
|
|
1255
|
-
applyToImportsFrom: applyToImportsFrom
|
|
1305
|
+
applyToImportsFrom: applyToImportsFrom,
|
|
1306
|
+
preferImportedPackageSubpath: preferImportedPackageSubpath
|
|
1256
1307
|
});
|
|
1257
1308
|
},
|
|
1258
1309
|
VariableDeclarator: function VariableDeclarator(rawNode) {
|
|
@@ -1261,7 +1312,8 @@ export function createRule(fs) {
|
|
|
1261
1312
|
context: context,
|
|
1262
1313
|
workspaceRoot: workspaceRoot,
|
|
1263
1314
|
fs: fs,
|
|
1264
|
-
applyToImportsFrom: applyToImportsFrom
|
|
1315
|
+
applyToImportsFrom: applyToImportsFrom,
|
|
1316
|
+
preferImportedPackageSubpath: preferImportedPackageSubpath
|
|
1265
1317
|
});
|
|
1266
1318
|
}
|
|
1267
1319
|
};
|
|
@@ -10,7 +10,7 @@ import { hasReExportsFromOtherFiles, parseBarrelExports } from '../shared/barrel
|
|
|
10
10
|
import { DEFAULT_TARGET_FOLDERS, findWorkspaceRoot, isRelativeImport, readFileContent, resolveImportPath } from '../shared/file-system';
|
|
11
11
|
import { extractImportPath, findJestRequireActualCalls, findJestRequireMockCalls, isJestMockCall, isJestRequireActual, resolveNewPathForRequireMock } from '../shared/jest-utils';
|
|
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
|
/**
|
|
@@ -662,7 +662,9 @@ function traceSymbolsToExports(_ref10) {
|
|
|
662
662
|
exportMap = _ref10.exportMap,
|
|
663
663
|
exportsMap = _ref10.exportsMap,
|
|
664
664
|
currentExportPath = _ref10.currentExportPath,
|
|
665
|
-
fs = _ref10.fs
|
|
665
|
+
fs = _ref10.fs,
|
|
666
|
+
barrelPackageName = _ref10.barrelPackageName,
|
|
667
|
+
preferImportedPackageSubpath = _ref10.preferImportedPackageSubpath;
|
|
666
668
|
var groupedByExport = new Map();
|
|
667
669
|
var crossPackageGroups = new Map();
|
|
668
670
|
var unmappedSymbols = [];
|
|
@@ -680,16 +682,38 @@ function traceSymbolsToExports(_ref10) {
|
|
|
680
682
|
|
|
681
683
|
// Check for cross-package source first
|
|
682
684
|
if (exportInfo.crossPackageSource) {
|
|
683
|
-
var key =
|
|
685
|
+
var key = void 0;
|
|
686
|
+
var tracedOriginalName = exportInfo.originalName;
|
|
687
|
+
var barrelBridgeExportPath = void 0;
|
|
688
|
+
if (preferImportedPackageSubpath) {
|
|
689
|
+
var bridge = findCrossPackageBridgeExportPath({
|
|
690
|
+
exportsMap: exportsMap,
|
|
691
|
+
crossPackageName: exportInfo.crossPackageSource.packageName,
|
|
692
|
+
exportedName: symbolName,
|
|
693
|
+
fs: fs
|
|
694
|
+
});
|
|
695
|
+
if (bridge) {
|
|
696
|
+
key = "".concat(barrelPackageName).concat(bridge.exportPath.slice(1));
|
|
697
|
+
barrelBridgeExportPath = bridge.exportPath;
|
|
698
|
+
if (bridge.entryPointExportName !== undefined) {
|
|
699
|
+
tracedOriginalName = bridge.entryPointExportName === symbolName ? undefined : bridge.entryPointExportName;
|
|
700
|
+
}
|
|
701
|
+
} else {
|
|
702
|
+
key = "".concat(exportInfo.crossPackageSource.packageName).concat(exportInfo.crossPackageSource.exportPath === '.' ? '' : exportInfo.crossPackageSource.exportPath.slice(1));
|
|
703
|
+
}
|
|
704
|
+
} else {
|
|
705
|
+
key = "".concat(exportInfo.crossPackageSource.packageName).concat(exportInfo.crossPackageSource.exportPath === '.' ? '' : exportInfo.crossPackageSource.exportPath.slice(1));
|
|
706
|
+
}
|
|
684
707
|
if (!crossPackageGroups.has(key)) {
|
|
685
708
|
crossPackageGroups.set(key, []);
|
|
686
709
|
}
|
|
687
710
|
crossPackageGroups.get(key).push({
|
|
688
711
|
symbolName: symbolName,
|
|
689
|
-
originalName:
|
|
712
|
+
originalName: tracedOriginalName,
|
|
690
713
|
sourceFilePath: exportInfo.path,
|
|
691
714
|
isTypeOnly: exportInfo.isTypeOnly,
|
|
692
|
-
crossPackageSource: exportInfo.crossPackageSource
|
|
715
|
+
crossPackageSource: exportInfo.crossPackageSource,
|
|
716
|
+
barrelBridgeExportPath: barrelBridgeExportPath
|
|
693
717
|
});
|
|
694
718
|
continue;
|
|
695
719
|
}
|
|
@@ -1060,6 +1084,10 @@ var ruleMeta = {
|
|
|
1060
1084
|
type: 'string'
|
|
1061
1085
|
},
|
|
1062
1086
|
description: 'The folder paths (relative to workspace root) containing packages whose imports will be checked and autofixed.'
|
|
1087
|
+
},
|
|
1088
|
+
preferImportedPackageSubpath: {
|
|
1089
|
+
type: 'boolean',
|
|
1090
|
+
description: 'Prefer subpaths on the mocked barrel package when they bridge to the dependency.'
|
|
1063
1091
|
}
|
|
1064
1092
|
},
|
|
1065
1093
|
additionalProperties: false
|
|
@@ -1078,9 +1106,10 @@ export function createRule(fs) {
|
|
|
1078
1106
|
return {
|
|
1079
1107
|
meta: ruleMeta,
|
|
1080
1108
|
create: function create(context) {
|
|
1081
|
-
var _options$applyToImpor;
|
|
1109
|
+
var _options$applyToImpor, _options$preferImport;
|
|
1082
1110
|
var options = context.options[0] || {};
|
|
1083
1111
|
var applyToImportsFrom = (_options$applyToImpor = options.applyToImportsFrom) !== null && _options$applyToImpor !== void 0 ? _options$applyToImpor : DEFAULT_TARGET_FOLDERS;
|
|
1112
|
+
var preferImportedPackageSubpath = (_options$preferImport = options.preferImportedPackageSubpath) !== null && _options$preferImport !== void 0 ? _options$preferImport : false;
|
|
1084
1113
|
var workspaceRoot = findWorkspaceRoot({
|
|
1085
1114
|
startPath: dirname(context.filename),
|
|
1086
1115
|
fs: fs,
|
|
@@ -1175,7 +1204,9 @@ export function createRule(fs) {
|
|
|
1175
1204
|
exportMap: raContext.exportMap,
|
|
1176
1205
|
exportsMap: raContext.exportsMap,
|
|
1177
1206
|
currentExportPath: raContext.currentExportPath,
|
|
1178
|
-
fs: fs
|
|
1207
|
+
fs: fs,
|
|
1208
|
+
barrelPackageName: raContext.packageName,
|
|
1209
|
+
preferImportedPackageSubpath: preferImportedPackageSubpath
|
|
1179
1210
|
}),
|
|
1180
1211
|
_groupedByExport = _traceSymbolsToExport.groupedByExport,
|
|
1181
1212
|
_crossPackageGroups = _traceSymbolsToExport.crossPackageGroups;
|
|
@@ -1272,7 +1303,9 @@ export function createRule(fs) {
|
|
|
1272
1303
|
exportMap: mockContext.exportMap,
|
|
1273
1304
|
exportsMap: mockContext.exportsMap,
|
|
1274
1305
|
currentExportPath: mockContext.currentExportPath,
|
|
1275
|
-
fs: fs
|
|
1306
|
+
fs: fs,
|
|
1307
|
+
barrelPackageName: mockContext.packageName,
|
|
1308
|
+
preferImportedPackageSubpath: preferImportedPackageSubpath
|
|
1276
1309
|
}),
|
|
1277
1310
|
groupedByExport = _traceSymbolsToExport2.groupedByExport,
|
|
1278
1311
|
crossPackageGroups = _traceSymbolsToExport2.crossPackageGroups,
|
|
@@ -1364,8 +1397,9 @@ export function createRule(fs) {
|
|
|
1364
1397
|
|
|
1365
1398
|
// Get cross-package source info from the first symbol (all symbols in same group have same source)
|
|
1366
1399
|
var crossPackageSource = _symbols[0].crossPackageSource;
|
|
1400
|
+
var bridgeExportPath = _symbols[0].barrelBridgeExportPath;
|
|
1367
1401
|
crossPackageMockGroups.push({
|
|
1368
|
-
exportPath: crossPackageSource.exportPath,
|
|
1402
|
+
exportPath: bridgeExportPath !== null && bridgeExportPath !== void 0 ? bridgeExportPath : crossPackageSource.exportPath,
|
|
1369
1403
|
importPath: _importPath,
|
|
1370
1404
|
propertyNames: _symbols.map(function (s) {
|
|
1371
1405
|
return s.symbolName;
|
|
@@ -161,10 +161,52 @@ export function parsePackageExports(_ref2) {
|
|
|
161
161
|
});
|
|
162
162
|
return exportsMap;
|
|
163
163
|
}
|
|
164
|
+
/**
|
|
165
|
+
* Check whether a subpath export key (e.g. `"./checkbox-select"`) is kebab-case.
|
|
166
|
+
*
|
|
167
|
+
* A key is considered kebab-case when the portion after the leading `"./"` prefix
|
|
168
|
+
* consists only of lowercase letters, digits, hyphens, dots, and forward-slash
|
|
169
|
+
* separators — i.e. no uppercase letters, underscores, or camelCase humps.
|
|
170
|
+
*/
|
|
171
|
+
export function isKebabCaseExportKey(key) {
|
|
172
|
+
var body = key.replace(/^\.\//, '');
|
|
173
|
+
if (body.length === 0) {
|
|
174
|
+
return false;
|
|
175
|
+
}
|
|
176
|
+
return /^[a-z0-9][a-z0-9\-./]*$/.test(body);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Given a list of candidate {@link ExportMatchResult}s that all resolve to the same
|
|
181
|
+
* source file, pick the best one. When any candidate's export path is kebab-case
|
|
182
|
+
* and points to an entry-point file, prefer it over non-kebab-case alternatives.
|
|
183
|
+
* Falls back to the first candidate if no kebab-case entry-point candidate is found.
|
|
184
|
+
*/
|
|
185
|
+
function pickBestMatch(candidates, exportsMap) {
|
|
186
|
+
if (candidates.length === 1) {
|
|
187
|
+
return candidates[0];
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// Among candidates whose value is an entry-point file, prefer kebab-case keys.
|
|
191
|
+
var entryPointKebab = candidates.filter(function (c) {
|
|
192
|
+
var resolved = exportsMap.get(c.exportPath);
|
|
193
|
+
return resolved && isInEntryPointsFolder(resolved) && isKebabCaseExportKey(c.exportPath);
|
|
194
|
+
});
|
|
195
|
+
if (entryPointKebab.length > 0) {
|
|
196
|
+
return entryPointKebab[0];
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Fall back to the first candidate (preserves previous behaviour).
|
|
200
|
+
return candidates[0];
|
|
201
|
+
}
|
|
202
|
+
|
|
164
203
|
/**
|
|
165
204
|
* Find a matching export entry for a given source file path.
|
|
166
205
|
* Returns the export path (e.g., "./controllers/analytics") or null if not found.
|
|
167
206
|
*
|
|
207
|
+
* When multiple export paths resolve to the same source file **and** point to an
|
|
208
|
+
* entry-point file, kebab-case keys are preferred over other casing styles.
|
|
209
|
+
*
|
|
168
210
|
* When `fs` is provided, also checks entry-point wrapper files. If an export resolves
|
|
169
211
|
* to a file inside a recognized entry-points folder (entry-points, entrypoints, etc.),
|
|
170
212
|
* the wrapper is parsed to see if it re-exports from `sourceFilePath`.
|
|
@@ -178,6 +220,8 @@ export function findExportForSourceFile(_ref3) {
|
|
|
178
220
|
exportsMap = _ref3.exportsMap,
|
|
179
221
|
fs = _ref3.fs,
|
|
180
222
|
sourceExportName = _ref3.sourceExportName;
|
|
223
|
+
// --- Phase 1: direct matches (export value === sourceFilePath) ---
|
|
224
|
+
var directMatches = [];
|
|
181
225
|
var _iterator3 = _createForOfIteratorHelper(exportsMap),
|
|
182
226
|
_step3;
|
|
183
227
|
try {
|
|
@@ -186,9 +230,9 @@ export function findExportForSourceFile(_ref3) {
|
|
|
186
230
|
_exportPath = _step3$value[0],
|
|
187
231
|
_resolvedPath = _step3$value[1];
|
|
188
232
|
if (_resolvedPath === sourceFilePath) {
|
|
189
|
-
|
|
233
|
+
directMatches.push({
|
|
190
234
|
exportPath: _exportPath
|
|
191
|
-
};
|
|
235
|
+
});
|
|
192
236
|
}
|
|
193
237
|
}
|
|
194
238
|
} catch (err) {
|
|
@@ -196,7 +240,13 @@ export function findExportForSourceFile(_ref3) {
|
|
|
196
240
|
} finally {
|
|
197
241
|
_iterator3.f();
|
|
198
242
|
}
|
|
243
|
+
if (directMatches.length > 0) {
|
|
244
|
+
return pickBestMatch(directMatches, exportsMap);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// --- Phase 2: entry-point wrapper re-export matches ---
|
|
199
248
|
if (fs) {
|
|
249
|
+
var entryPointMatches = [];
|
|
200
250
|
var _iterator4 = _createForOfIteratorHelper(exportsMap),
|
|
201
251
|
_step4;
|
|
202
252
|
try {
|
|
@@ -219,10 +269,10 @@ export function findExportForSourceFile(_ref3) {
|
|
|
219
269
|
if (sourceExportName !== undefined && reExport.nameMap.has(sourceExportName)) {
|
|
220
270
|
entryPointExportName = reExport.nameMap.get(sourceExportName);
|
|
221
271
|
}
|
|
222
|
-
|
|
272
|
+
entryPointMatches.push({
|
|
223
273
|
exportPath: exportPath,
|
|
224
274
|
entryPointExportName: entryPointExportName
|
|
225
|
-
};
|
|
275
|
+
});
|
|
226
276
|
}
|
|
227
277
|
}
|
|
228
278
|
} catch (err) {
|
|
@@ -237,6 +287,99 @@ export function findExportForSourceFile(_ref3) {
|
|
|
237
287
|
} finally {
|
|
238
288
|
_iterator4.f();
|
|
239
289
|
}
|
|
290
|
+
if (entryPointMatches.length > 0) {
|
|
291
|
+
return pickBestMatch(entryPointMatches, exportsMap);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
return null;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* When a symbol reaches the consumer through a barrel package that re-exports from
|
|
299
|
+
* `crossPackageName`, find a `package.json` export subpath of that barrel whose entry
|
|
300
|
+
* file directly re-exports the symbol from `crossPackageName` (named exports only).
|
|
301
|
+
*
|
|
302
|
+
* This enables rewriting imports to `@scope/barrel/subpath` instead of
|
|
303
|
+
* `@scope/cross-package/...` when the barrel exposes such a subpath (e.g. `@atlaskit/select/react-select`).
|
|
304
|
+
*/
|
|
305
|
+
export function findCrossPackageBridgeExportPath(_ref4) {
|
|
306
|
+
var exportsMap = _ref4.exportsMap,
|
|
307
|
+
crossPackageName = _ref4.crossPackageName,
|
|
308
|
+
exportedName = _ref4.exportedName,
|
|
309
|
+
fs = _ref4.fs;
|
|
310
|
+
var _iterator6 = _createForOfIteratorHelper(exportsMap),
|
|
311
|
+
_step6;
|
|
312
|
+
try {
|
|
313
|
+
for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) {
|
|
314
|
+
var _step6$value = _slicedToArray(_step6.value, 2),
|
|
315
|
+
exportPath = _step6$value[0],
|
|
316
|
+
resolvedPath = _step6$value[1];
|
|
317
|
+
var content = readFileContent({
|
|
318
|
+
filePath: resolvedPath,
|
|
319
|
+
fs: fs
|
|
320
|
+
});
|
|
321
|
+
if (!content) {
|
|
322
|
+
continue;
|
|
323
|
+
}
|
|
324
|
+
try {
|
|
325
|
+
var sourceFile = ts.createSourceFile(resolvedPath, content, ts.ScriptTarget.Latest, true);
|
|
326
|
+
var _iterator7 = _createForOfIteratorHelper(sourceFile.statements),
|
|
327
|
+
_step7;
|
|
328
|
+
try {
|
|
329
|
+
for (_iterator7.s(); !(_step7 = _iterator7.n()).done;) {
|
|
330
|
+
var statement = _step7.value;
|
|
331
|
+
if (!ts.isExportDeclaration(statement) || statement.isTypeOnly) {
|
|
332
|
+
continue;
|
|
333
|
+
}
|
|
334
|
+
if (!statement.moduleSpecifier || !ts.isStringLiteral(statement.moduleSpecifier)) {
|
|
335
|
+
continue;
|
|
336
|
+
}
|
|
337
|
+
if (statement.moduleSpecifier.text !== crossPackageName) {
|
|
338
|
+
continue;
|
|
339
|
+
}
|
|
340
|
+
if (!statement.exportClause || ts.isNamespaceExport(statement.exportClause)) {
|
|
341
|
+
continue;
|
|
342
|
+
}
|
|
343
|
+
if (!ts.isNamedExports(statement.exportClause)) {
|
|
344
|
+
continue;
|
|
345
|
+
}
|
|
346
|
+
var _iterator8 = _createForOfIteratorHelper(statement.exportClause.elements),
|
|
347
|
+
_step8;
|
|
348
|
+
try {
|
|
349
|
+
for (_iterator8.s(); !(_step8 = _iterator8.n()).done;) {
|
|
350
|
+
var element = _step8.value;
|
|
351
|
+
if (element.isTypeOnly) {
|
|
352
|
+
continue;
|
|
353
|
+
}
|
|
354
|
+
var publicName = element.name.text;
|
|
355
|
+
if (publicName !== exportedName) {
|
|
356
|
+
continue;
|
|
357
|
+
}
|
|
358
|
+
var entryPointExportName = element.propertyName ? element.propertyName.text : undefined;
|
|
359
|
+
return {
|
|
360
|
+
exportPath: exportPath,
|
|
361
|
+
entryPointExportName: entryPointExportName
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
} catch (err) {
|
|
365
|
+
_iterator8.e(err);
|
|
366
|
+
} finally {
|
|
367
|
+
_iterator8.f();
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
} catch (err) {
|
|
371
|
+
_iterator7.e(err);
|
|
372
|
+
} finally {
|
|
373
|
+
_iterator7.f();
|
|
374
|
+
}
|
|
375
|
+
} catch (_unused4) {
|
|
376
|
+
// Ignore parse errors for individual export entry files
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
} catch (err) {
|
|
380
|
+
_iterator6.e(err);
|
|
381
|
+
} finally {
|
|
382
|
+
_iterator6.f();
|
|
240
383
|
}
|
|
241
384
|
return null;
|
|
242
385
|
}
|
|
@@ -260,10 +403,10 @@ export function extractPackageNameFromImport(moduleSpecifier) {
|
|
|
260
403
|
* Resolve a cross-package import to its package directory and export info.
|
|
261
404
|
* Returns null if the package is not in the target folder or cannot be resolved.
|
|
262
405
|
*/
|
|
263
|
-
export function resolveCrossPackageImport(
|
|
264
|
-
var moduleSpecifier =
|
|
265
|
-
workspaceRoot =
|
|
266
|
-
fs =
|
|
406
|
+
export function resolveCrossPackageImport(_ref5) {
|
|
407
|
+
var moduleSpecifier = _ref5.moduleSpecifier,
|
|
408
|
+
workspaceRoot = _ref5.workspaceRoot,
|
|
409
|
+
fs = _ref5.fs;
|
|
267
410
|
// Only handle @atlassian/* scoped packages
|
|
268
411
|
var parsed = extractPackageNameFromImport(moduleSpecifier);
|
|
269
412
|
if (!parsed) {
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
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; } } }; }
|
|
2
|
+
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; } }
|
|
3
|
+
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; }
|
|
4
|
+
// eslint-disable-next-line import/no-extraneous-dependencies
|
|
5
|
+
|
|
6
|
+
var RESTRICTED_IMPORTS = {
|
|
7
|
+
'@atlassian/atl-context': ['isFedRamp', 'isIsolatedCloud'],
|
|
8
|
+
'@atlaskit/atlassian-context': ['isFedRamp', 'isIsolatedCloud'],
|
|
9
|
+
'@atlassian/teams-common': ['isFedramp']
|
|
10
|
+
};
|
|
11
|
+
var rule = {
|
|
12
|
+
meta: {
|
|
13
|
+
type: 'problem',
|
|
14
|
+
docs: {
|
|
15
|
+
description: 'Disallow importing deprecated FedRamp/IsolatedCloud context functions. Use isFeatureEnabled from AEM (Atlassian Environment Manager) instead.',
|
|
16
|
+
recommended: true
|
|
17
|
+
},
|
|
18
|
+
messages: {
|
|
19
|
+
noRestrictedFedrampImports: '{{name}} from {{source}} will be deprecated soon. Please use isFeatureEnabled from AEM (Atlassian Environment Manager) instead. See go/AEM for more details.'
|
|
20
|
+
},
|
|
21
|
+
schema: []
|
|
22
|
+
},
|
|
23
|
+
create: function create(context) {
|
|
24
|
+
return {
|
|
25
|
+
ImportDeclaration: function ImportDeclaration(node) {
|
|
26
|
+
var source = node.source.value;
|
|
27
|
+
if (typeof source !== 'string') {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
var restrictedNames = RESTRICTED_IMPORTS[source];
|
|
31
|
+
if (!restrictedNames) {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
var _iterator = _createForOfIteratorHelper(node.specifiers),
|
|
35
|
+
_step;
|
|
36
|
+
try {
|
|
37
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
38
|
+
var specifier = _step.value;
|
|
39
|
+
if (specifier.type === 'ImportSpecifier' && restrictedNames.includes(specifier.imported.name)) {
|
|
40
|
+
context.report({
|
|
41
|
+
node: specifier,
|
|
42
|
+
messageId: 'noRestrictedFedrampImports',
|
|
43
|
+
data: {
|
|
44
|
+
name: specifier.imported.name,
|
|
45
|
+
source: source
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
} catch (err) {
|
|
51
|
+
_iterator.e(err);
|
|
52
|
+
} finally {
|
|
53
|
+
_iterator.f();
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
export default rule;
|
|
@@ -17,7 +17,7 @@ var messages = {
|
|
|
17
17
|
suggestFixPath: 'Update import path to match visitExample arguments'
|
|
18
18
|
};
|
|
19
19
|
function isTargetFile(filename) {
|
|
20
|
-
return filename.endsWith('.spec.tsx');
|
|
20
|
+
return filename.endsWith('.spec.tsx') || filename.endsWith('.spec.ts');
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
/**
|
package/dist/types/index.d.ts
CHANGED
|
@@ -29,6 +29,7 @@ declare const rules: {
|
|
|
29
29
|
'no-direct-document-usage': import("eslint").Rule.RuleModule;
|
|
30
30
|
'no-set-immediate': import("eslint").Rule.RuleModule;
|
|
31
31
|
'prefer-crypto-random-uuid': import("eslint").Rule.RuleModule;
|
|
32
|
+
'no-restricted-fedramp-imports': import("eslint").Rule.RuleModule;
|
|
32
33
|
'no-barrel-entry-imports': import("eslint").Rule.RuleModule;
|
|
33
34
|
'no-barrel-entry-jest-mock': import("eslint").Rule.RuleModule;
|
|
34
35
|
'no-jest-mock-barrel-files': import("eslint").Rule.RuleModule;
|
|
@@ -72,6 +73,7 @@ declare const plugin: {
|
|
|
72
73
|
'no-direct-document-usage': import("eslint").Rule.RuleModule;
|
|
73
74
|
'no-set-immediate': import("eslint").Rule.RuleModule;
|
|
74
75
|
'prefer-crypto-random-uuid': import("eslint").Rule.RuleModule;
|
|
76
|
+
'no-restricted-fedramp-imports': import("eslint").Rule.RuleModule;
|
|
75
77
|
'no-barrel-entry-imports': import("eslint").Rule.RuleModule;
|
|
76
78
|
'no-barrel-entry-jest-mock': import("eslint").Rule.RuleModule;
|
|
77
79
|
'no-jest-mock-barrel-files': import("eslint").Rule.RuleModule;
|
|
@@ -16,10 +16,21 @@ export interface ExportMatchResult {
|
|
|
16
16
|
*/
|
|
17
17
|
entryPointExportName?: string;
|
|
18
18
|
}
|
|
19
|
+
/**
|
|
20
|
+
* Check whether a subpath export key (e.g. `"./checkbox-select"`) is kebab-case.
|
|
21
|
+
*
|
|
22
|
+
* A key is considered kebab-case when the portion after the leading `"./"` prefix
|
|
23
|
+
* consists only of lowercase letters, digits, hyphens, dots, and forward-slash
|
|
24
|
+
* separators — i.e. no uppercase letters, underscores, or camelCase humps.
|
|
25
|
+
*/
|
|
26
|
+
export declare function isKebabCaseExportKey(key: string): boolean;
|
|
19
27
|
/**
|
|
20
28
|
* Find a matching export entry for a given source file path.
|
|
21
29
|
* Returns the export path (e.g., "./controllers/analytics") or null if not found.
|
|
22
30
|
*
|
|
31
|
+
* When multiple export paths resolve to the same source file **and** point to an
|
|
32
|
+
* entry-point file, kebab-case keys are preferred over other casing styles.
|
|
33
|
+
*
|
|
23
34
|
* When `fs` is provided, also checks entry-point wrapper files. If an export resolves
|
|
24
35
|
* to a file inside a recognized entry-points folder (entry-points, entrypoints, etc.),
|
|
25
36
|
* the wrapper is parsed to see if it re-exports from `sourceFilePath`.
|
|
@@ -34,6 +45,20 @@ export declare function findExportForSourceFile({ sourceFilePath, exportsMap, fs
|
|
|
34
45
|
fs?: FileSystem;
|
|
35
46
|
sourceExportName?: string;
|
|
36
47
|
}): ExportMatchResult | null;
|
|
48
|
+
/**
|
|
49
|
+
* When a symbol reaches the consumer through a barrel package that re-exports from
|
|
50
|
+
* `crossPackageName`, find a `package.json` export subpath of that barrel whose entry
|
|
51
|
+
* file directly re-exports the symbol from `crossPackageName` (named exports only).
|
|
52
|
+
*
|
|
53
|
+
* This enables rewriting imports to `@scope/barrel/subpath` instead of
|
|
54
|
+
* `@scope/cross-package/...` when the barrel exposes such a subpath (e.g. `@atlaskit/select/react-select`).
|
|
55
|
+
*/
|
|
56
|
+
export declare function findCrossPackageBridgeExportPath({ exportsMap, crossPackageName, exportedName, fs, }: {
|
|
57
|
+
exportsMap: Map<string, string>;
|
|
58
|
+
crossPackageName: string;
|
|
59
|
+
exportedName: string;
|
|
60
|
+
fs: FileSystem;
|
|
61
|
+
}): ExportMatchResult | null;
|
|
37
62
|
/**
|
|
38
63
|
* Extract the package name and subpath from an import specifier.
|
|
39
64
|
* Returns null if the import is not a scoped package import.
|