@atlaskit/eslint-plugin-platform 2.7.2 → 2.9.0
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 +16 -0
- package/dist/cjs/index.js +19 -3
- package/dist/cjs/rules/ensure-use-sync-external-store-server-snapshot/index.js +41 -0
- package/dist/cjs/rules/feature-gating/valid-gate-name/index.js +60 -0
- package/dist/cjs/rules/import/no-barrel-entry-imports/index.js +1279 -0
- package/dist/cjs/rules/import/no-barrel-entry-jest-mock/index.js +1659 -0
- package/dist/cjs/rules/import/no-conversation-assistant-barrel-imports/index.js +43 -0
- package/dist/cjs/rules/import/no-jest-mock-barrel-files/index.js +1402 -0
- package/dist/cjs/rules/import/no-relative-barrel-file-imports/index.js +781 -0
- package/dist/cjs/rules/import/shared/barrel-parsing.js +511 -0
- package/dist/cjs/rules/import/shared/file-system.js +186 -0
- package/dist/cjs/rules/import/shared/jest-utils.js +244 -0
- package/dist/cjs/rules/import/shared/package-registry.js +263 -0
- package/dist/cjs/rules/import/shared/package-resolution.js +318 -0
- package/dist/cjs/rules/import/shared/perf.js +89 -0
- package/dist/cjs/rules/import/shared/types.js +67 -0
- package/dist/cjs/rules/visit-example-type-import-required/index.js +409 -0
- package/dist/es2019/index.js +19 -3
- package/dist/es2019/rules/ensure-use-sync-external-store-server-snapshot/index.js +43 -0
- package/dist/es2019/rules/feature-gating/valid-gate-name/index.js +52 -0
- package/dist/es2019/rules/import/no-barrel-entry-imports/index.js +1158 -0
- package/dist/es2019/rules/import/no-barrel-entry-jest-mock/index.js +1341 -0
- package/dist/es2019/rules/import/no-conversation-assistant-barrel-imports/index.js +37 -0
- package/dist/es2019/rules/import/no-jest-mock-barrel-files/index.js +1180 -0
- package/dist/es2019/rules/import/no-relative-barrel-file-imports/index.js +742 -0
- package/dist/es2019/rules/import/shared/barrel-parsing.js +433 -0
- package/dist/es2019/rules/import/shared/file-system.js +174 -0
- package/dist/es2019/rules/import/shared/jest-utils.js +203 -0
- package/dist/es2019/rules/import/shared/package-registry.js +240 -0
- package/dist/es2019/rules/import/shared/package-resolution.js +253 -0
- package/dist/es2019/rules/import/shared/perf.js +83 -0
- package/dist/es2019/rules/import/shared/types.js +57 -0
- package/dist/es2019/rules/visit-example-type-import-required/index.js +375 -0
- package/dist/esm/index.js +19 -3
- package/dist/esm/rules/ensure-use-sync-external-store-server-snapshot/index.js +35 -0
- package/dist/esm/rules/feature-gating/valid-gate-name/index.js +53 -0
- package/dist/esm/rules/import/no-barrel-entry-imports/index.js +1272 -0
- package/dist/esm/rules/import/no-barrel-entry-jest-mock/index.js +1650 -0
- package/dist/esm/rules/import/no-conversation-assistant-barrel-imports/index.js +37 -0
- package/dist/esm/rules/import/no-jest-mock-barrel-files/index.js +1392 -0
- package/dist/esm/rules/import/no-relative-barrel-file-imports/index.js +774 -0
- package/dist/esm/rules/import/shared/barrel-parsing.js +500 -0
- package/dist/esm/rules/import/shared/file-system.js +176 -0
- package/dist/esm/rules/import/shared/jest-utils.js +231 -0
- package/dist/esm/rules/import/shared/package-registry.js +256 -0
- package/dist/esm/rules/import/shared/package-resolution.js +306 -0
- package/dist/esm/rules/import/shared/perf.js +80 -0
- package/dist/esm/rules/import/shared/types.js +61 -0
- package/dist/esm/rules/visit-example-type-import-required/index.js +402 -0
- package/dist/types/index.d.ts +28 -2
- package/dist/types/rules/ensure-use-sync-external-store-server-snapshot/index.d.ts +3 -0
- package/dist/types/rules/feature-gating/valid-gate-name/index.d.ts +3 -0
- package/dist/types/rules/import/no-barrel-entry-imports/index.d.ts +9 -0
- package/dist/types/rules/import/no-barrel-entry-jest-mock/index.d.ts +9 -0
- package/dist/types/rules/import/no-conversation-assistant-barrel-imports/index.d.ts +3 -0
- package/dist/types/rules/import/no-jest-mock-barrel-files/index.d.ts +22 -0
- package/dist/types/rules/import/no-relative-barrel-file-imports/index.d.ts +5 -0
- package/dist/types/rules/import/shared/barrel-parsing.d.ts +30 -0
- package/dist/types/rules/import/shared/file-system.d.ts +38 -0
- package/dist/types/rules/import/shared/jest-utils.d.ts +55 -0
- package/dist/types/rules/import/shared/package-registry.d.ts +26 -0
- package/dist/types/rules/import/shared/package-resolution.d.ts +58 -0
- package/dist/types/rules/import/shared/perf.d.ts +13 -0
- package/dist/types/rules/import/shared/types.d.ts +131 -0
- package/dist/types/rules/visit-example-type-import-required/index.d.ts +4 -0
- package/dist/types-ts4.5/index.d.ts +28 -2
- package/dist/types-ts4.5/rules/import/no-barrel-entry-imports/index.d.ts +9 -0
- package/dist/types-ts4.5/rules/import/no-barrel-entry-jest-mock/index.d.ts +9 -0
- package/dist/types-ts4.5/rules/import/no-conversation-assistant-barrel-imports/index.d.ts +3 -0
- package/dist/types-ts4.5/rules/import/no-jest-mock-barrel-files/index.d.ts +22 -0
- package/dist/types-ts4.5/rules/import/no-relative-barrel-file-imports/index.d.ts +5 -0
- package/dist/types-ts4.5/rules/import/shared/barrel-parsing.d.ts +30 -0
- package/dist/types-ts4.5/rules/import/shared/file-system.d.ts +38 -0
- package/dist/types-ts4.5/rules/import/shared/jest-utils.d.ts +55 -0
- package/dist/types-ts4.5/rules/import/shared/package-registry.d.ts +26 -0
- package/dist/types-ts4.5/rules/import/shared/package-resolution.d.ts +58 -0
- package/dist/types-ts4.5/rules/import/shared/perf.d.ts +13 -0
- package/dist/types-ts4.5/rules/import/shared/types.d.ts +131 -0
- package/dist/types-ts4.5/rules/visit-example-type-import-required/index.d.ts +4 -0
- package/package.json +6 -2
- package/dist/cjs/rules/ensure-native-and-af-exports-synced/index.js +0 -158
- package/dist/es2019/rules/ensure-native-and-af-exports-synced/index.js +0 -146
- package/dist/esm/rules/ensure-native-and-af-exports-synced/index.js +0 -151
- /package/dist/types-ts4.5/rules/{ensure-native-and-af-exports-synced → ensure-use-sync-external-store-server-snapshot}/index.d.ts +0 -0
- /package/dist/{types/rules/ensure-native-and-af-exports-synced → types-ts4.5/rules/feature-gating/valid-gate-name}/index.d.ts +0 -0
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { FileSystem } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Parse the package.json exports field and return a map of export paths to resolved file paths.
|
|
4
|
+
*/
|
|
5
|
+
export declare function parsePackageExports({ packageDir, fs, }: {
|
|
6
|
+
packageDir: string;
|
|
7
|
+
fs: FileSystem;
|
|
8
|
+
}): Map<string, string>;
|
|
9
|
+
export interface ExportMatchResult {
|
|
10
|
+
exportPath: string;
|
|
11
|
+
/**
|
|
12
|
+
* When resolved through an entry-point wrapper, the name under which
|
|
13
|
+
* the symbol is exported from the entry-point file.
|
|
14
|
+
* Callers use this to override the barrel's `originalName` so the
|
|
15
|
+
* generated import matches the entry-point's export shape.
|
|
16
|
+
*/
|
|
17
|
+
entryPointExportName?: string;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Find a matching export entry for a given source file path.
|
|
21
|
+
* Returns the export path (e.g., "./controllers/analytics") or null if not found.
|
|
22
|
+
*
|
|
23
|
+
* When `fs` is provided, also checks entry-point wrapper files. If an export resolves
|
|
24
|
+
* to a file inside a recognized entry-points folder (entry-points, entrypoints, etc.),
|
|
25
|
+
* the wrapper is parsed to see if it re-exports from `sourceFilePath`.
|
|
26
|
+
*
|
|
27
|
+
* `sourceExportName` is the name under which the symbol is exported from the source file
|
|
28
|
+
* (e.g. `'default'`). Used to look up the corresponding entry-point export name so the
|
|
29
|
+
* caller can generate the correct import style.
|
|
30
|
+
*/
|
|
31
|
+
export declare function findExportForSourceFile({ sourceFilePath, exportsMap, fs, sourceExportName, }: {
|
|
32
|
+
sourceFilePath: string;
|
|
33
|
+
exportsMap: Map<string, string>;
|
|
34
|
+
fs?: FileSystem;
|
|
35
|
+
sourceExportName?: string;
|
|
36
|
+
}): ExportMatchResult | null;
|
|
37
|
+
/**
|
|
38
|
+
* Extract the package name and subpath from an import specifier.
|
|
39
|
+
* Returns null if the import is not a scoped package import.
|
|
40
|
+
*/
|
|
41
|
+
export declare function extractPackageNameFromImport(moduleSpecifier: string): {
|
|
42
|
+
packageName: string;
|
|
43
|
+
subPath: string;
|
|
44
|
+
} | null;
|
|
45
|
+
/**
|
|
46
|
+
* Resolve a cross-package import to its package directory and export info.
|
|
47
|
+
* Returns null if the package is not in the target folder or cannot be resolved.
|
|
48
|
+
*/
|
|
49
|
+
export declare function resolveCrossPackageImport({ moduleSpecifier, workspaceRoot, fs, }: {
|
|
50
|
+
moduleSpecifier: string;
|
|
51
|
+
workspaceRoot: string;
|
|
52
|
+
fs: FileSystem;
|
|
53
|
+
}): {
|
|
54
|
+
packageName: string;
|
|
55
|
+
packageDir: string;
|
|
56
|
+
exportPath: string;
|
|
57
|
+
entryFilePath: string;
|
|
58
|
+
} | null;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { FileSystem } from './types';
|
|
2
|
+
export declare const PERF_ENV_VAR = "INTERNAL_ESLINT_BARREL_PERF";
|
|
3
|
+
export declare function isPerfEnabled(): boolean;
|
|
4
|
+
export declare function perfInc({ fs, key, by }: {
|
|
5
|
+
fs: FileSystem;
|
|
6
|
+
key: string;
|
|
7
|
+
by?: number;
|
|
8
|
+
}): void;
|
|
9
|
+
export declare function perfTime<T>({ fs, key, fn }: {
|
|
10
|
+
fs: FileSystem;
|
|
11
|
+
key: string;
|
|
12
|
+
fn: () => T;
|
|
13
|
+
}): T;
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Directory entry returned by readdirSync with withFileTypes option.
|
|
3
|
+
*/
|
|
4
|
+
export interface DirectoryEntry {
|
|
5
|
+
name: string;
|
|
6
|
+
isDirectory(): boolean;
|
|
7
|
+
isFile(): boolean;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* State for the package registry cache.
|
|
11
|
+
* This is used to cache package name to directory mappings for efficient lookups.
|
|
12
|
+
*/
|
|
13
|
+
export interface PackageRegistryCache {
|
|
14
|
+
/** Map of package name to absolute directory path */
|
|
15
|
+
packageNameToDir: Map<string, string>;
|
|
16
|
+
/** Set of directories that have been scanned (including those without packages) */
|
|
17
|
+
scannedDirectories: Set<string>;
|
|
18
|
+
/** yarn.lock mtime when cache was built (for invalidation) */
|
|
19
|
+
yarnLockMtime: number;
|
|
20
|
+
/** The workspace root this cache was built for (from package registry perspective) */
|
|
21
|
+
workspaceRoot: string | null;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Cache structure for file system operations.
|
|
25
|
+
* Contains both package registry cache and workspace root cache.
|
|
26
|
+
*/
|
|
27
|
+
export interface FileSystemCache extends Partial<PackageRegistryCache> {
|
|
28
|
+
/** Cached git repository root (from git rev-parse --show-toplevel) */
|
|
29
|
+
gitRepoRoot?: string;
|
|
30
|
+
/**
|
|
31
|
+
* Cache of parsed package.json exports maps keyed by absolute package directory.
|
|
32
|
+
* This avoids repeated reads/parses during IDE lint runs.
|
|
33
|
+
*/
|
|
34
|
+
packageExportsByDir?: Map<string, {
|
|
35
|
+
/** mtimeMs of package.json when this entry was computed. null means unknown (forces re-read). */
|
|
36
|
+
packageJsonMtimeMs: number | null;
|
|
37
|
+
exportsMap: Map<string, string>;
|
|
38
|
+
}>;
|
|
39
|
+
/**
|
|
40
|
+
* Cache of read file contents keyed by absolute file path.
|
|
41
|
+
* Used by barrel parsing to avoid repeated reads in IDE lint runs.
|
|
42
|
+
*/
|
|
43
|
+
fileContentByPath?: Map<string, {
|
|
44
|
+
/** mtimeMs when this entry was cached. null means unknown (forces re-read). */
|
|
45
|
+
mtimeMs: number | null;
|
|
46
|
+
content: string;
|
|
47
|
+
}>;
|
|
48
|
+
/**
|
|
49
|
+
* Cache of parsed barrel exports keyed by barrel file path.
|
|
50
|
+
* Stores the barrel file mtime at time of parsing to support invalidation.
|
|
51
|
+
*/
|
|
52
|
+
barrelExportsByPath?: Map<string, {
|
|
53
|
+
mtimeMs: number;
|
|
54
|
+
exports: Map<string, ExportInfo>;
|
|
55
|
+
}>;
|
|
56
|
+
/**
|
|
57
|
+
* Cache for resolveImportPath results keyed by basedir + importPath.
|
|
58
|
+
*/
|
|
59
|
+
resolvedImportPathByKey?: Map<string, string | null>;
|
|
60
|
+
/**
|
|
61
|
+
* Optional perf counters and timers for debugging and optimization.
|
|
62
|
+
* Enabled by setting INTERNAL_ESLINT_BARREL_PERF.
|
|
63
|
+
*/
|
|
64
|
+
perf?: {
|
|
65
|
+
installedExitHook: boolean;
|
|
66
|
+
counters: Record<string, number>;
|
|
67
|
+
timers: Record<string, number>;
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* File system abstraction for testability.
|
|
72
|
+
* This interface allows the core logic to be tested with mock file systems.
|
|
73
|
+
* The cache property holds package resolution state and can be passed as an empty
|
|
74
|
+
* object for tests to ensure fresh state for each test case.
|
|
75
|
+
*/
|
|
76
|
+
export interface FileSystem {
|
|
77
|
+
existsSync(path: string): boolean;
|
|
78
|
+
readFileSync(path: string, encoding: 'utf-8'): string;
|
|
79
|
+
realpathSync(path: string): string;
|
|
80
|
+
statSync(path: string): {
|
|
81
|
+
isFile(): boolean;
|
|
82
|
+
mtimeMs?: number;
|
|
83
|
+
};
|
|
84
|
+
readdirSync(path: string, options: {
|
|
85
|
+
withFileTypes: true;
|
|
86
|
+
}): DirectoryEntry[];
|
|
87
|
+
/** Execute a command synchronously and return stdout. Returns null on error. */
|
|
88
|
+
execSync(command: string, options?: {
|
|
89
|
+
cwd?: string;
|
|
90
|
+
}): string | null;
|
|
91
|
+
/** Cache for package resolution and workspace root - will be populated lazily */
|
|
92
|
+
cache: FileSystemCache;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Real file system implementation using Node.js fs module.
|
|
96
|
+
*/
|
|
97
|
+
export declare const realFileSystem: FileSystem;
|
|
98
|
+
/**
|
|
99
|
+
* Information about cross-package re-export origin.
|
|
100
|
+
*/
|
|
101
|
+
export interface CrossPackageSource {
|
|
102
|
+
/** The package name (e.g., '@atlassian/package-b') */
|
|
103
|
+
packageName: string;
|
|
104
|
+
/** The export path within the package (e.g., '.' or './utils') */
|
|
105
|
+
exportPath: string;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Information about where an export originates.
|
|
109
|
+
*/
|
|
110
|
+
export interface ExportInfo {
|
|
111
|
+
/** The absolute path to the file where this export originates */
|
|
112
|
+
path: string;
|
|
113
|
+
/** Whether this is a type-only export */
|
|
114
|
+
isTypeOnly: boolean;
|
|
115
|
+
/** Whether this is a re-export of a default export */
|
|
116
|
+
isDefaultExport?: boolean;
|
|
117
|
+
/** The original name of the symbol in the source file (for aliased exports) */
|
|
118
|
+
originalName?: string;
|
|
119
|
+
/** Information about cross-package re-export origin, if applicable */
|
|
120
|
+
crossPackageSource?: CrossPackageSource;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Context for package resolution operations.
|
|
124
|
+
*/
|
|
125
|
+
export interface PackageResolutionContext {
|
|
126
|
+
packageName: string;
|
|
127
|
+
packageDir: string;
|
|
128
|
+
exportPath: string;
|
|
129
|
+
entryFilePath: string;
|
|
130
|
+
exportsMap: Map<string, string>;
|
|
131
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlaskit/eslint-plugin-platform",
|
|
3
3
|
"description": "The essential plugin for use with Atlassian frontend platform tools",
|
|
4
|
-
"version": "2.
|
|
4
|
+
"version": "2.9.0",
|
|
5
5
|
"author": "Atlassian Pty Ltd",
|
|
6
6
|
"atlassian": {
|
|
7
7
|
"team": "Build Infra",
|
|
@@ -35,10 +35,14 @@
|
|
|
35
35
|
"@compiled/eslint-plugin": "^0.18.2",
|
|
36
36
|
"@manypkg/find-root": "^1.1.0",
|
|
37
37
|
"@manypkg/get-packages": "^1.1.3",
|
|
38
|
+
"@typescript-eslint/typescript-estree": "^5.56.0",
|
|
39
|
+
"@typescript-eslint/utils": "^7.1.0",
|
|
38
40
|
"fuse.js": "^6.6.2",
|
|
39
|
-
"read-pkg-up": "^7.0.1"
|
|
41
|
+
"read-pkg-up": "^7.0.1",
|
|
42
|
+
"typescript": "5.9.2"
|
|
40
43
|
},
|
|
41
44
|
"devDependencies": {
|
|
45
|
+
"@atlassian/eslint-utils": "^0.5.0",
|
|
42
46
|
"@atlassian/ts-loader": "^0.1.0",
|
|
43
47
|
"@types/eslint": "^8.56.6",
|
|
44
48
|
"eslint": "^8.57.0",
|
|
@@ -1,158 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
-
Object.defineProperty(exports, "__esModule", {
|
|
5
|
-
value: true
|
|
6
|
-
});
|
|
7
|
-
exports.default = void 0;
|
|
8
|
-
var _typeof2 = _interopRequireDefault(require("@babel/runtime/helpers/typeof"));
|
|
9
|
-
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
|
|
10
|
-
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
|
|
11
|
-
var _path = _interopRequireDefault(require("path"));
|
|
12
|
-
var _registrationUtils = require("../util/registration-utils");
|
|
13
|
-
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
14
|
-
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
15
|
-
var exportsValidationExceptions = {
|
|
16
|
-
'@af/yarn-workspace': {
|
|
17
|
-
ignoredAfExportKeys: ['./lock-parser']
|
|
18
|
-
},
|
|
19
|
-
'@atlaskit/tokens': {
|
|
20
|
-
ignoredAfExportKeys: ['./babel-plugin']
|
|
21
|
-
},
|
|
22
|
-
'@atlaskit/storybook-addon-design-system': {
|
|
23
|
-
ignoredAfExportKeys: ['.']
|
|
24
|
-
},
|
|
25
|
-
'@atlassian/react-async': {
|
|
26
|
-
ignoredAfExportKeys: ['./mock']
|
|
27
|
-
}
|
|
28
|
-
};
|
|
29
|
-
var rule = {
|
|
30
|
-
meta: {
|
|
31
|
-
docs: {
|
|
32
|
-
recommended: false
|
|
33
|
-
},
|
|
34
|
-
type: 'problem',
|
|
35
|
-
messages: {
|
|
36
|
-
missingExportsProperty: "The exports property must be defined for {{pkgName}}; it most likely can just be a duplicate of the \"af:exports\" property. See http://go/eslint-exports for details",
|
|
37
|
-
missingExportsKey: "Missing package.json exports key \"{{expectedKey}}\" in {{pkgName}}. The exports entry should be \"{{expectedKey}}\": \"{{expectedValue}}\". See http://go/eslint-exports for details",
|
|
38
|
-
unexpectedExportsKey: "Unexpected package.json exports key \"{{key}}\" in {{pkgName}}. The exports entry should be \"{{expectedKey}}\": \"{{expectedValue}}\". See http://go/eslint-exports for details",
|
|
39
|
-
unexpectedExportsValue: "Unexpected package.json exports value in {{pkgName}} for the \"{{key}}\" key. The exports entry should be \"{{key}}\": \"{{expectedValue}}\". See http://go/eslint-exports for details"
|
|
40
|
-
}
|
|
41
|
-
},
|
|
42
|
-
create: function create(context) {
|
|
43
|
-
var fileName = context.getFilename();
|
|
44
|
-
if (!fileName.endsWith('package.json')) {
|
|
45
|
-
return {};
|
|
46
|
-
}
|
|
47
|
-
var _getMetadataForFilena = (0, _registrationUtils.getMetadataForFilename)(fileName),
|
|
48
|
-
packageJson = _getMetadataForFilena.pkgJson;
|
|
49
|
-
var pkgName = packageJson.name;
|
|
50
|
-
if (!pkgName || !packageJson['af:exports']) {
|
|
51
|
-
return {};
|
|
52
|
-
}
|
|
53
|
-
if (!packageJson['exports']) {
|
|
54
|
-
context.report({
|
|
55
|
-
node: context.getSourceCode().ast,
|
|
56
|
-
messageId: 'missingExportsProperty',
|
|
57
|
-
data: {
|
|
58
|
-
pkgName: pkgName
|
|
59
|
-
}
|
|
60
|
-
});
|
|
61
|
-
return {};
|
|
62
|
-
}
|
|
63
|
-
var afExports = packageJson['af:exports'];
|
|
64
|
-
var nativeExports = packageJson['exports'];
|
|
65
|
-
return {
|
|
66
|
-
Program: function Program(node) {
|
|
67
|
-
for (var _i = 0, _Object$entries = Object.entries(afExports); _i < _Object$entries.length; _i++) {
|
|
68
|
-
var _exportsValidationExc;
|
|
69
|
-
var _Object$entries$_i = (0, _slicedToArray2.default)(_Object$entries[_i], 2),
|
|
70
|
-
afExportsKey = _Object$entries$_i[0],
|
|
71
|
-
afExportsValue = _Object$entries$_i[1];
|
|
72
|
-
if ((_exportsValidationExc = exportsValidationExceptions[pkgName]) !== null && _exportsValidationExc !== void 0 && _exportsValidationExc.ignoredAfExportKeys.includes(afExportsKey)) {
|
|
73
|
-
continue;
|
|
74
|
-
}
|
|
75
|
-
var exportKeyViolations = getExportKeyViolation(afExportsKey, afExportsValue, nativeExports);
|
|
76
|
-
if (exportKeyViolations) {
|
|
77
|
-
context.report({
|
|
78
|
-
data: _objectSpread(_objectSpread({}, exportKeyViolations), {}, {
|
|
79
|
-
key: afExportsKey,
|
|
80
|
-
pkgName: pkgName
|
|
81
|
-
}),
|
|
82
|
-
node: node,
|
|
83
|
-
messageId: exportKeyViolations.messageId
|
|
84
|
-
});
|
|
85
|
-
continue;
|
|
86
|
-
}
|
|
87
|
-
var exportValueViolations = getExportValueViolation(afExportsKey, afExportsValue, nativeExports);
|
|
88
|
-
if (exportValueViolations) {
|
|
89
|
-
context.report({
|
|
90
|
-
data: _objectSpread(_objectSpread({}, exportValueViolations), {}, {
|
|
91
|
-
pkgName: pkgName
|
|
92
|
-
}),
|
|
93
|
-
node: node,
|
|
94
|
-
messageId: 'unexpectedExportsValue'
|
|
95
|
-
});
|
|
96
|
-
continue;
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
};
|
|
101
|
-
}
|
|
102
|
-
};
|
|
103
|
-
function getExportKeyViolation(afExportsKey, afExportsValue, nativeExports) {
|
|
104
|
-
var afExportsValueHasExtension = _path.default.extname(afExportsValue) !== '';
|
|
105
|
-
if (afExportsValueHasExtension && !nativeExports.hasOwnProperty(afExportsKey)) {
|
|
106
|
-
return {
|
|
107
|
-
messageId: 'missingExportsKey',
|
|
108
|
-
expectedKey: afExportsKey,
|
|
109
|
-
expectedValue: afExportsValue
|
|
110
|
-
};
|
|
111
|
-
}
|
|
112
|
-
if (!afExportsValueHasExtension && nativeExports.hasOwnProperty(afExportsKey)) {
|
|
113
|
-
return {
|
|
114
|
-
messageId: 'unexpectedExportsKey',
|
|
115
|
-
expectedKey: "".concat(afExportsKey, "/*"),
|
|
116
|
-
expectedValue: "".concat(afExportsValue, "/*")
|
|
117
|
-
};
|
|
118
|
-
}
|
|
119
|
-
if (!afExportsValueHasExtension && !nativeExports.hasOwnProperty("".concat(afExportsKey, "/*"))) {
|
|
120
|
-
return {
|
|
121
|
-
messageId: 'missingExportsKey',
|
|
122
|
-
expectedKey: "".concat(afExportsKey, "/*"),
|
|
123
|
-
expectedValue: "".concat(afExportsValue, "/*")
|
|
124
|
-
};
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
function getNativeExportsValue(afExportsKey, afExportsValueHasExtension, nativeExports) {
|
|
128
|
-
var nativeExportsKey = afExportsValueHasExtension ? afExportsKey : "".concat(afExportsKey, "/*");
|
|
129
|
-
if ((0, _typeof2.default)(nativeExports[nativeExportsKey]) === 'object') {
|
|
130
|
-
return nativeExports[nativeExportsKey].default;
|
|
131
|
-
}
|
|
132
|
-
return nativeExports[nativeExportsKey];
|
|
133
|
-
}
|
|
134
|
-
function getExportValueViolation(afExportsKey, afExportsValue, nativeExports) {
|
|
135
|
-
var afExportsValueHasExtension = _path.default.extname(afExportsValue) !== '';
|
|
136
|
-
var nativeExportsValue = getNativeExportsValue(afExportsKey, afExportsValueHasExtension, nativeExports);
|
|
137
|
-
|
|
138
|
-
// Some entrypoints have been updated to an index.js file that registers ts-node
|
|
139
|
-
// Use path.basename to get the file name to see if it is equal to 'index.js'
|
|
140
|
-
if (afExportsValueHasExtension && _path.default.basename(nativeExportsValue) === 'index.js') {
|
|
141
|
-
return;
|
|
142
|
-
}
|
|
143
|
-
if (afExportsValueHasExtension && nativeExportsValue !== afExportsValue) {
|
|
144
|
-
return {
|
|
145
|
-
key: afExportsKey,
|
|
146
|
-
expectedValue: afExportsValue
|
|
147
|
-
};
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
// af:exports entrypoints without a file extension export the whole directory so check to ensure the exports value includes the wildcard
|
|
151
|
-
if (!afExportsValueHasExtension && !nativeExportsValue.startsWith("".concat(afExportsValue, "/*"))) {
|
|
152
|
-
return {
|
|
153
|
-
key: "".concat(afExportsKey, "/*"),
|
|
154
|
-
expectedValue: "".concat(afExportsValue, "/*")
|
|
155
|
-
};
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
var _default = exports.default = rule;
|
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
import path from 'path';
|
|
2
|
-
import { getMetadataForFilename } from '../util/registration-utils';
|
|
3
|
-
const exportsValidationExceptions = {
|
|
4
|
-
'@af/yarn-workspace': {
|
|
5
|
-
ignoredAfExportKeys: ['./lock-parser']
|
|
6
|
-
},
|
|
7
|
-
'@atlaskit/tokens': {
|
|
8
|
-
ignoredAfExportKeys: ['./babel-plugin']
|
|
9
|
-
},
|
|
10
|
-
'@atlaskit/storybook-addon-design-system': {
|
|
11
|
-
ignoredAfExportKeys: ['.']
|
|
12
|
-
},
|
|
13
|
-
'@atlassian/react-async': {
|
|
14
|
-
ignoredAfExportKeys: ['./mock']
|
|
15
|
-
}
|
|
16
|
-
};
|
|
17
|
-
const rule = {
|
|
18
|
-
meta: {
|
|
19
|
-
docs: {
|
|
20
|
-
recommended: false
|
|
21
|
-
},
|
|
22
|
-
type: 'problem',
|
|
23
|
-
messages: {
|
|
24
|
-
missingExportsProperty: `The exports property must be defined for {{pkgName}}; it most likely can just be a duplicate of the "af:exports" property. See http://go/eslint-exports for details`,
|
|
25
|
-
missingExportsKey: `Missing package.json exports key "{{expectedKey}}" in {{pkgName}}. The exports entry should be "{{expectedKey}}": "{{expectedValue}}". See http://go/eslint-exports for details`,
|
|
26
|
-
unexpectedExportsKey: `Unexpected package.json exports key "{{key}}" in {{pkgName}}. The exports entry should be "{{expectedKey}}": "{{expectedValue}}". See http://go/eslint-exports for details`,
|
|
27
|
-
unexpectedExportsValue: `Unexpected package.json exports value in {{pkgName}} for the "{{key}}" key. The exports entry should be "{{key}}": "{{expectedValue}}". See http://go/eslint-exports for details`
|
|
28
|
-
}
|
|
29
|
-
},
|
|
30
|
-
create(context) {
|
|
31
|
-
const fileName = context.getFilename();
|
|
32
|
-
if (!fileName.endsWith('package.json')) {
|
|
33
|
-
return {};
|
|
34
|
-
}
|
|
35
|
-
const {
|
|
36
|
-
pkgJson: packageJson
|
|
37
|
-
} = getMetadataForFilename(fileName);
|
|
38
|
-
const pkgName = packageJson.name;
|
|
39
|
-
if (!pkgName || !packageJson['af:exports']) {
|
|
40
|
-
return {};
|
|
41
|
-
}
|
|
42
|
-
if (!packageJson['exports']) {
|
|
43
|
-
context.report({
|
|
44
|
-
node: context.getSourceCode().ast,
|
|
45
|
-
messageId: 'missingExportsProperty',
|
|
46
|
-
data: {
|
|
47
|
-
pkgName
|
|
48
|
-
}
|
|
49
|
-
});
|
|
50
|
-
return {};
|
|
51
|
-
}
|
|
52
|
-
const afExports = packageJson['af:exports'];
|
|
53
|
-
const nativeExports = packageJson['exports'];
|
|
54
|
-
return {
|
|
55
|
-
Program(node) {
|
|
56
|
-
for (const [afExportsKey, afExportsValue] of Object.entries(afExports)) {
|
|
57
|
-
var _exportsValidationExc;
|
|
58
|
-
if ((_exportsValidationExc = exportsValidationExceptions[pkgName]) !== null && _exportsValidationExc !== void 0 && _exportsValidationExc.ignoredAfExportKeys.includes(afExportsKey)) {
|
|
59
|
-
continue;
|
|
60
|
-
}
|
|
61
|
-
const exportKeyViolations = getExportKeyViolation(afExportsKey, afExportsValue, nativeExports);
|
|
62
|
-
if (exportKeyViolations) {
|
|
63
|
-
context.report({
|
|
64
|
-
data: {
|
|
65
|
-
...exportKeyViolations,
|
|
66
|
-
key: afExportsKey,
|
|
67
|
-
pkgName
|
|
68
|
-
},
|
|
69
|
-
node,
|
|
70
|
-
messageId: exportKeyViolations.messageId
|
|
71
|
-
});
|
|
72
|
-
continue;
|
|
73
|
-
}
|
|
74
|
-
const exportValueViolations = getExportValueViolation(afExportsKey, afExportsValue, nativeExports);
|
|
75
|
-
if (exportValueViolations) {
|
|
76
|
-
context.report({
|
|
77
|
-
data: {
|
|
78
|
-
...exportValueViolations,
|
|
79
|
-
pkgName
|
|
80
|
-
},
|
|
81
|
-
node,
|
|
82
|
-
messageId: 'unexpectedExportsValue'
|
|
83
|
-
});
|
|
84
|
-
continue;
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
};
|
|
89
|
-
}
|
|
90
|
-
};
|
|
91
|
-
function getExportKeyViolation(afExportsKey, afExportsValue, nativeExports) {
|
|
92
|
-
const afExportsValueHasExtension = path.extname(afExportsValue) !== '';
|
|
93
|
-
if (afExportsValueHasExtension && !nativeExports.hasOwnProperty(afExportsKey)) {
|
|
94
|
-
return {
|
|
95
|
-
messageId: 'missingExportsKey',
|
|
96
|
-
expectedKey: afExportsKey,
|
|
97
|
-
expectedValue: afExportsValue
|
|
98
|
-
};
|
|
99
|
-
}
|
|
100
|
-
if (!afExportsValueHasExtension && nativeExports.hasOwnProperty(afExportsKey)) {
|
|
101
|
-
return {
|
|
102
|
-
messageId: 'unexpectedExportsKey',
|
|
103
|
-
expectedKey: `${afExportsKey}/*`,
|
|
104
|
-
expectedValue: `${afExportsValue}/*`
|
|
105
|
-
};
|
|
106
|
-
}
|
|
107
|
-
if (!afExportsValueHasExtension && !nativeExports.hasOwnProperty(`${afExportsKey}/*`)) {
|
|
108
|
-
return {
|
|
109
|
-
messageId: 'missingExportsKey',
|
|
110
|
-
expectedKey: `${afExportsKey}/*`,
|
|
111
|
-
expectedValue: `${afExportsValue}/*`
|
|
112
|
-
};
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
function getNativeExportsValue(afExportsKey, afExportsValueHasExtension, nativeExports) {
|
|
116
|
-
const nativeExportsKey = afExportsValueHasExtension ? afExportsKey : `${afExportsKey}/*`;
|
|
117
|
-
if (typeof nativeExports[nativeExportsKey] === 'object') {
|
|
118
|
-
return nativeExports[nativeExportsKey].default;
|
|
119
|
-
}
|
|
120
|
-
return nativeExports[nativeExportsKey];
|
|
121
|
-
}
|
|
122
|
-
function getExportValueViolation(afExportsKey, afExportsValue, nativeExports) {
|
|
123
|
-
const afExportsValueHasExtension = path.extname(afExportsValue) !== '';
|
|
124
|
-
const nativeExportsValue = getNativeExportsValue(afExportsKey, afExportsValueHasExtension, nativeExports);
|
|
125
|
-
|
|
126
|
-
// Some entrypoints have been updated to an index.js file that registers ts-node
|
|
127
|
-
// Use path.basename to get the file name to see if it is equal to 'index.js'
|
|
128
|
-
if (afExportsValueHasExtension && path.basename(nativeExportsValue) === 'index.js') {
|
|
129
|
-
return;
|
|
130
|
-
}
|
|
131
|
-
if (afExportsValueHasExtension && nativeExportsValue !== afExportsValue) {
|
|
132
|
-
return {
|
|
133
|
-
key: afExportsKey,
|
|
134
|
-
expectedValue: afExportsValue
|
|
135
|
-
};
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
// af:exports entrypoints without a file extension export the whole directory so check to ensure the exports value includes the wildcard
|
|
139
|
-
if (!afExportsValueHasExtension && !nativeExportsValue.startsWith(`${afExportsValue}/*`)) {
|
|
140
|
-
return {
|
|
141
|
-
key: `${afExportsKey}/*`,
|
|
142
|
-
expectedValue: `${afExportsValue}/*`
|
|
143
|
-
};
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
export default rule;
|