@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,402 @@
|
|
|
1
|
+
import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
|
|
2
|
+
import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
|
|
3
|
+
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; } } }; }
|
|
4
|
+
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; } }
|
|
5
|
+
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; }
|
|
6
|
+
import fs from 'fs';
|
|
7
|
+
import path from 'path';
|
|
8
|
+
import { AST_NODE_TYPES } from '@typescript-eslint/utils';
|
|
9
|
+
import { simpleTraverse } from '@typescript-eslint/typescript-estree';
|
|
10
|
+
export var RULE_NAME = 'visit-example-type-import-required';
|
|
11
|
+
var messages = {
|
|
12
|
+
missingTypeofImport: 'visitExample must use typeof import(...) generic type parameter. ' + 'Use visitExample<typeof import("path/to/example.tsx")>(groupId, packageId, exampleId).',
|
|
13
|
+
invalidTypeParameter: 'visitExample generic type parameter must be a typeof import(...) expression.',
|
|
14
|
+
pathMismatch: 'The import path "{{ importPath }}" does not match the expected example file for ' + 'visitExample({{ groupId }}, {{ packageId }}, {{ exampleId }}). ' + 'Expected import to resolve to: {{ expectedPath }}',
|
|
15
|
+
noPackageImports: 'Package imports (e.g., @atlaskit/...) are not allowed in visitExample type parameters. Use a relative import path.',
|
|
16
|
+
typeAliasNotInlined: 'Type aliases for typeof import(...) must be inlined directly into the visitExample call. ' + 'Use visitExample<typeof import("...")>(...) instead of defining a type alias.',
|
|
17
|
+
suggestFixPath: 'Update import path to match visitExample arguments'
|
|
18
|
+
};
|
|
19
|
+
function isTargetFile(filename) {
|
|
20
|
+
return filename.endsWith('.spec.tsx');
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Extracts the import path string from a TSTypeQuery node of the form `typeof import('...')`.
|
|
25
|
+
* Returns null if the node doesn't match that shape.
|
|
26
|
+
*/
|
|
27
|
+
function extractImportPathFromTypeQuery(typeQuery) {
|
|
28
|
+
// TSTypeQuery { exprName: TSImportType { argument: TSLiteralType { literal: Literal } } }
|
|
29
|
+
var exprName = typeQuery.exprName;
|
|
30
|
+
if (exprName.type !== AST_NODE_TYPES.TSImportType) {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
var argument = exprName.argument;
|
|
34
|
+
if (argument.type === AST_NODE_TYPES.TSLiteralType && argument.literal.type === AST_NODE_TYPES.Literal && typeof argument.literal.value === 'string') {
|
|
35
|
+
return argument.literal.value;
|
|
36
|
+
}
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Builds a map of all TSTypeAliasDeclaration nodes in the file, keyed by name.
|
|
41
|
+
* Each entry records whether the alias is at the top level of the program (file-level).
|
|
42
|
+
*/
|
|
43
|
+
function collectTypeAliases(ast) {
|
|
44
|
+
var result = new Map();
|
|
45
|
+
|
|
46
|
+
// Cast through unknown to work around a version mismatch: @typescript-eslint/utils
|
|
47
|
+
// vendors its own copy of @typescript-eslint/types (v7) while the root node_modules
|
|
48
|
+
// has a different version (v5). The TSESTree types are structurally identical at
|
|
49
|
+
// runtime — the cast is safe.
|
|
50
|
+
simpleTraverse(ast, {
|
|
51
|
+
enter: function enter(node, parent) {
|
|
52
|
+
// A type alias is "file-level" if its immediate parent is the Program,
|
|
53
|
+
// or if it's the declaration of a top-level ExportNamedDeclaration.
|
|
54
|
+
if (node.type === AST_NODE_TYPES.TSTypeAliasDeclaration) {
|
|
55
|
+
var isFileLevel = (parent === null || parent === void 0 ? void 0 : parent.type) === AST_NODE_TYPES.Program || (parent === null || parent === void 0 ? void 0 : parent.type) === AST_NODE_TYPES.ExportNamedDeclaration;
|
|
56
|
+
result.set(node.id.name, {
|
|
57
|
+
node: node,
|
|
58
|
+
isFileLevel: isFileLevel
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
return result;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Resolves a top-level `const foo = 'literal'` declaration to its string value.
|
|
68
|
+
* Returns null for non-const, non-string, or not-found variables.
|
|
69
|
+
*/
|
|
70
|
+
function resolveVariableToConstant(programBody, variableName, cache) {
|
|
71
|
+
if (cache.has(variableName)) {
|
|
72
|
+
var _cache$get;
|
|
73
|
+
return (_cache$get = cache.get(variableName)) !== null && _cache$get !== void 0 ? _cache$get : null;
|
|
74
|
+
}
|
|
75
|
+
var _iterator = _createForOfIteratorHelper(programBody),
|
|
76
|
+
_step;
|
|
77
|
+
try {
|
|
78
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
79
|
+
var node = _step.value;
|
|
80
|
+
if (node.type !== AST_NODE_TYPES.VariableDeclaration || node.kind !== 'const') {
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
var _iterator2 = _createForOfIteratorHelper(node.declarations),
|
|
84
|
+
_step2;
|
|
85
|
+
try {
|
|
86
|
+
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
87
|
+
var _declarator$init;
|
|
88
|
+
var declarator = _step2.value;
|
|
89
|
+
if (declarator.id.type === AST_NODE_TYPES.Identifier && declarator.id.name === variableName && ((_declarator$init = declarator.init) === null || _declarator$init === void 0 ? void 0 : _declarator$init.type) === AST_NODE_TYPES.Literal && typeof declarator.init.value === 'string') {
|
|
90
|
+
cache.set(variableName, declarator.init.value);
|
|
91
|
+
return declarator.init.value;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
} catch (err) {
|
|
95
|
+
_iterator2.e(err);
|
|
96
|
+
} finally {
|
|
97
|
+
_iterator2.f();
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
} catch (err) {
|
|
101
|
+
_iterator.e(err);
|
|
102
|
+
} finally {
|
|
103
|
+
_iterator.f();
|
|
104
|
+
}
|
|
105
|
+
cache.set(variableName, null);
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Extracts the (groupId, packageId, exampleId) string arguments from a visitExample call.
|
|
110
|
+
* Each argument may be a string literal or a reference to a top-level const string variable.
|
|
111
|
+
* Returns null for any argument that can't be statically resolved.
|
|
112
|
+
*/
|
|
113
|
+
function extractCallArgs(node, programBody, variableCache) {
|
|
114
|
+
if (node.arguments.length < 3) {
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
function resolveArg(arg) {
|
|
118
|
+
if (arg.type === AST_NODE_TYPES.Literal && typeof arg.value === 'string') {
|
|
119
|
+
return arg.value;
|
|
120
|
+
}
|
|
121
|
+
if (arg.type === AST_NODE_TYPES.Identifier) {
|
|
122
|
+
return resolveVariableToConstant(programBody, arg.name, variableCache);
|
|
123
|
+
}
|
|
124
|
+
return null;
|
|
125
|
+
}
|
|
126
|
+
var groupId = resolveArg(node.arguments[0]);
|
|
127
|
+
var packageId = resolveArg(node.arguments[1]);
|
|
128
|
+
var exampleId = resolveArg(node.arguments[2]);
|
|
129
|
+
if (!groupId || !packageId || !exampleId) {
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
return {
|
|
133
|
+
groupId: groupId,
|
|
134
|
+
packageId: packageId,
|
|
135
|
+
exampleId: exampleId
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
function getPackagesBasePath(testFilePath) {
|
|
139
|
+
var testFileDir = path.dirname(testFilePath);
|
|
140
|
+
var testFileSegments = testFileDir.split(path.sep);
|
|
141
|
+
var packagesIndex = testFileSegments.findIndex(function (seg) {
|
|
142
|
+
return seg === 'packages';
|
|
143
|
+
});
|
|
144
|
+
if (packagesIndex === -1) {
|
|
145
|
+
return null;
|
|
146
|
+
}
|
|
147
|
+
var baseSegments = testFileSegments.slice(0, packagesIndex + 1);
|
|
148
|
+
var basePath = path.isAbsolute(testFilePath) ? path.resolve.apply(path, ['/'].concat(_toConsumableArray(baseSegments))) : path.resolve.apply(path, [process.cwd()].concat(_toConsumableArray(baseSegments)));
|
|
149
|
+
return {
|
|
150
|
+
basePath: basePath,
|
|
151
|
+
packagesIndex: packagesIndex
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Resolves the expected example file path from visitExample arguments.
|
|
157
|
+
*
|
|
158
|
+
* visitExample('groupId', 'packageId', 'exampleId') maps to:
|
|
159
|
+
* packages/{groupId}/{packageId}/examples/{exampleId}.tsx
|
|
160
|
+
*
|
|
161
|
+
* Example files may also have a numeric sort prefix, e.g.:
|
|
162
|
+
* packages/{groupId}/{packageId}/examples/00-{exampleId}.tsx
|
|
163
|
+
*
|
|
164
|
+
* We scan the examples directory once and match against all candidates.
|
|
165
|
+
* Falls back to the bare `{exampleId}.tsx` name when the directory can't
|
|
166
|
+
* be read (e.g. in unit-test environments where the files don't exist).
|
|
167
|
+
*/
|
|
168
|
+
function resolveExamplePathFromArgs(groupId, packageId, exampleId, testFilePath) {
|
|
169
|
+
var packagesBase = getPackagesBasePath(testFilePath);
|
|
170
|
+
if (!packagesBase) {
|
|
171
|
+
return null;
|
|
172
|
+
}
|
|
173
|
+
var examplesDir = path.resolve(packagesBase.basePath, groupId, packageId, 'examples');
|
|
174
|
+
var fallback = path.resolve(examplesDir, "".concat(exampleId, ".tsx"));
|
|
175
|
+
|
|
176
|
+
// Match: exact name OR numeric-prefixed variant, with optional `.examples` infix
|
|
177
|
+
var candidateRe = new RegExp("^(?:\\d+-)?".concat(exampleId, "(?:\\.examples?)?\\.tsx$"));
|
|
178
|
+
try {
|
|
179
|
+
var match = fs.readdirSync(examplesDir).find(function (f) {
|
|
180
|
+
return candidateRe.test(f);
|
|
181
|
+
});
|
|
182
|
+
if (match) {
|
|
183
|
+
return path.resolve(examplesDir, match);
|
|
184
|
+
}
|
|
185
|
+
} catch (_unused) {
|
|
186
|
+
// Directory doesn't exist or can't be read (e.g. in test environments)
|
|
187
|
+
}
|
|
188
|
+
return fallback;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Computes a relative import path from one file to another
|
|
193
|
+
*/
|
|
194
|
+
function computeRelativeImportPath(fromFile, toFile) {
|
|
195
|
+
var fromDir = path.dirname(fromFile);
|
|
196
|
+
var relativePath = path.relative(fromDir, toFile);
|
|
197
|
+
// Normalize to forward slashes for import statements (standard in JavaScript/TypeScript)
|
|
198
|
+
relativePath = relativePath.replace(/\\/g, '/');
|
|
199
|
+
// Ensure relative imports start with ./ or ../
|
|
200
|
+
if (!relativePath.startsWith('.') && !relativePath.startsWith('/')) {
|
|
201
|
+
relativePath = "./".concat(relativePath);
|
|
202
|
+
}
|
|
203
|
+
return relativePath;
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Extracts the generic type argument from a `visitExample<...>(...)` call expression
|
|
207
|
+
* using the AST directly (no regex on source text).
|
|
208
|
+
*
|
|
209
|
+
* Returns:
|
|
210
|
+
* { type: 'inline', importPath } — for `visitExample<typeof import('...')>(...)`
|
|
211
|
+
* { type: 'alias', name } — for `visitExample<SomeTypeAlias>(...)`
|
|
212
|
+
* null — if no generic type parameter is present
|
|
213
|
+
*/
|
|
214
|
+
function extractGenericType(node) {
|
|
215
|
+
var _params, _ref, _node$typeArguments;
|
|
216
|
+
// `typeArguments` is the current property name; `typeParameters` is the deprecated alias.
|
|
217
|
+
// We fall back to `typeParameters` for compatibility with older parser versions.
|
|
218
|
+
var params = (_params = (_ref = (_node$typeArguments = node.typeArguments) !== null && _node$typeArguments !== void 0 ? _node$typeArguments : node.typeParameters) === null || _ref === void 0 ? void 0 : _ref.params) !== null && _params !== void 0 ? _params : [];
|
|
219
|
+
if (params.length === 0) {
|
|
220
|
+
return null;
|
|
221
|
+
}
|
|
222
|
+
var _params2 = _slicedToArray(params, 1),
|
|
223
|
+
typeParam = _params2[0];
|
|
224
|
+
|
|
225
|
+
// `typeof import('...')` → TSTypeQuery { exprName: TSImportType { ... } }
|
|
226
|
+
if (typeParam.type === AST_NODE_TYPES.TSTypeQuery) {
|
|
227
|
+
var importPath = extractImportPathFromTypeQuery(typeParam);
|
|
228
|
+
if (importPath !== null) {
|
|
229
|
+
return {
|
|
230
|
+
type: 'inline',
|
|
231
|
+
importPath: importPath
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// `SomeTypeAlias` → TSTypeReference { typeName: Identifier { name } }
|
|
237
|
+
if (typeParam.type === AST_NODE_TYPES.TSTypeReference && typeParam.typeName.type === AST_NODE_TYPES.Identifier) {
|
|
238
|
+
return {
|
|
239
|
+
type: 'alias',
|
|
240
|
+
name: typeParam.typeName.name
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
return null;
|
|
244
|
+
}
|
|
245
|
+
var rule = {
|
|
246
|
+
meta: {
|
|
247
|
+
type: 'problem',
|
|
248
|
+
docs: {
|
|
249
|
+
description: 'Ensures that visitExample uses a typeof import(...) generic and that the import path matches the example file resolved from the call arguments.'
|
|
250
|
+
},
|
|
251
|
+
fixable: 'code',
|
|
252
|
+
messages: messages,
|
|
253
|
+
schema: []
|
|
254
|
+
},
|
|
255
|
+
create: function create(context) {
|
|
256
|
+
var filename = context.filename;
|
|
257
|
+
var ast = context.sourceCode.ast;
|
|
258
|
+
var programBody = ast.body;
|
|
259
|
+
|
|
260
|
+
// Build the type alias map once per file (lazily on first visitExample call)
|
|
261
|
+
var typeAliases = null;
|
|
262
|
+
function getTypeAliases() {
|
|
263
|
+
if (!typeAliases) {
|
|
264
|
+
typeAliases = collectTypeAliases(ast);
|
|
265
|
+
}
|
|
266
|
+
return typeAliases;
|
|
267
|
+
}
|
|
268
|
+
var variableCache = new Map();
|
|
269
|
+
return {
|
|
270
|
+
CallExpression: function CallExpression(estreeNode) {
|
|
271
|
+
if (!isTargetFile(filename)) {
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
var node = estreeNode;
|
|
275
|
+
// Only handle `<anything>.visitExample(...)` calls
|
|
276
|
+
if (node.callee.type !== AST_NODE_TYPES.MemberExpression || node.callee.property.type !== AST_NODE_TYPES.Identifier || node.callee.property.name !== 'visitExample') {
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// Narrow callee — we've confirmed property is an Identifier above
|
|
281
|
+
var callee = node.callee;
|
|
282
|
+
// reportCallee is typed as estree.Node for context.report compatibility
|
|
283
|
+
var reportCallee = estreeNode.callee;
|
|
284
|
+
var genericType = extractGenericType(node);
|
|
285
|
+
|
|
286
|
+
// ── Case 1: No generic type parameter ────────────────────────────────
|
|
287
|
+
if (genericType === null) {
|
|
288
|
+
var _args = extractCallArgs(node, programBody, variableCache);
|
|
289
|
+
context.report({
|
|
290
|
+
node: reportCallee,
|
|
291
|
+
messageId: 'missingTypeofImport',
|
|
292
|
+
fix: function fix(fixer) {
|
|
293
|
+
if (!_args) {
|
|
294
|
+
return null;
|
|
295
|
+
}
|
|
296
|
+
var examplePath = resolveExamplePathFromArgs(_args.groupId, _args.packageId, _args.exampleId, filename);
|
|
297
|
+
if (!examplePath) {
|
|
298
|
+
return null;
|
|
299
|
+
}
|
|
300
|
+
var importPath = computeRelativeImportPath(filename, examplePath);
|
|
301
|
+
var _ref2 = callee.property.range,
|
|
302
|
+
_ref3 = _slicedToArray(_ref2, 2),
|
|
303
|
+
start = _ref3[0],
|
|
304
|
+
end = _ref3[1];
|
|
305
|
+
return fixer.insertTextAfterRange([start, end], "<typeof import('".concat(importPath, "')>"));
|
|
306
|
+
}
|
|
307
|
+
});
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// ── Case 2: Generic is a type alias reference (`visitExample<Foo>`) ──
|
|
312
|
+
var importPath;
|
|
313
|
+
if (genericType.type === 'alias') {
|
|
314
|
+
var found = getTypeAliases().get(genericType.name);
|
|
315
|
+
if (!found) {
|
|
316
|
+
// Unknown type alias — not a typeof import
|
|
317
|
+
context.report({
|
|
318
|
+
node: reportCallee,
|
|
319
|
+
messageId: 'missingTypeofImport'
|
|
320
|
+
});
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
323
|
+
if (found.isFileLevel) {
|
|
324
|
+
// Top-level `type Foo = typeof import(...)` is disallowed
|
|
325
|
+
context.report({
|
|
326
|
+
node: reportCallee,
|
|
327
|
+
messageId: 'typeAliasNotInlined'
|
|
328
|
+
});
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
var typeAnnotation = found.node.typeAnnotation;
|
|
332
|
+
if (typeAnnotation.type !== AST_NODE_TYPES.TSTypeQuery) {
|
|
333
|
+
context.report({
|
|
334
|
+
node: reportCallee,
|
|
335
|
+
messageId: 'missingTypeofImport'
|
|
336
|
+
});
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
var resolved = extractImportPathFromTypeQuery(typeAnnotation);
|
|
340
|
+
if (!resolved) {
|
|
341
|
+
context.report({
|
|
342
|
+
node: reportCallee,
|
|
343
|
+
messageId: 'missingTypeofImport'
|
|
344
|
+
});
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
347
|
+
importPath = resolved;
|
|
348
|
+
} else {
|
|
349
|
+
// ── Case 3: Inline `typeof import('...')` ────────────────────────
|
|
350
|
+
importPath = genericType.importPath;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
// Package-scoped imports (e.g. @atlaskit/foo/examples/...) are not allowed
|
|
354
|
+
if (importPath.startsWith('@')) {
|
|
355
|
+
context.report({
|
|
356
|
+
node: reportCallee,
|
|
357
|
+
messageId: 'noPackageImports'
|
|
358
|
+
});
|
|
359
|
+
return;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
// Validate that the import path matches the arguments
|
|
363
|
+
var args = extractCallArgs(node, programBody, variableCache);
|
|
364
|
+
if (!args) {
|
|
365
|
+
// Dynamic arguments — can't validate statically
|
|
366
|
+
return;
|
|
367
|
+
}
|
|
368
|
+
var expectedPath = resolveExamplePathFromArgs(args.groupId, args.packageId, args.exampleId, filename);
|
|
369
|
+
if (!expectedPath) {
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
var resolvedImport = path.normalize(path.resolve(path.dirname(filename), importPath));
|
|
373
|
+
var resolvedExpected = path.normalize(expectedPath);
|
|
374
|
+
|
|
375
|
+
// Compare without extensions so `.tsx` vs no extension doesn't matter
|
|
376
|
+
if (resolvedImport.replace(/\.(tsx?|jsx?)$/, '') !== resolvedExpected.replace(/\.(tsx?|jsx?)$/, '')) {
|
|
377
|
+
context.report({
|
|
378
|
+
node: estreeNode.arguments[0],
|
|
379
|
+
messageId: 'pathMismatch',
|
|
380
|
+
data: {
|
|
381
|
+
importPath: importPath,
|
|
382
|
+
groupId: args.groupId,
|
|
383
|
+
packageId: args.packageId,
|
|
384
|
+
exampleId: args.exampleId,
|
|
385
|
+
expectedPath: resolvedExpected
|
|
386
|
+
},
|
|
387
|
+
fix: function fix(fixer) {
|
|
388
|
+
var _node$typeArguments2;
|
|
389
|
+
var correctedPath = computeRelativeImportPath(filename, resolvedExpected);
|
|
390
|
+
var typeParams = (_node$typeArguments2 = node.typeArguments) !== null && _node$typeArguments2 !== void 0 ? _node$typeArguments2 : node.typeParameters;
|
|
391
|
+
if (!(typeParams !== null && typeParams !== void 0 && typeParams.range)) {
|
|
392
|
+
return null;
|
|
393
|
+
}
|
|
394
|
+
return fixer.replaceTextRange(typeParams.range, "<typeof import('".concat(correctedPath, "')>"));
|
|
395
|
+
}
|
|
396
|
+
});
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
};
|
|
400
|
+
}
|
|
401
|
+
};
|
|
402
|
+
export default rule;
|
package/dist/types/index.d.ts
CHANGED
|
@@ -15,7 +15,6 @@ declare const rules: {
|
|
|
15
15
|
'no-pre-post-install-scripts': import("eslint").Rule.RuleModule;
|
|
16
16
|
'no-invalid-storybook-decorator-usage': import("eslint").Rule.RuleModule;
|
|
17
17
|
'ensure-publish-valid': import("eslint").Rule.RuleModule;
|
|
18
|
-
'ensure-native-and-af-exports-synced': import("eslint").Rule.RuleModule;
|
|
19
18
|
'no-module-level-eval': import("eslint").Rule.RuleModule;
|
|
20
19
|
'no-module-level-eval-nav4': import("eslint").Rule.RuleModule;
|
|
21
20
|
'static-feature-flags': import("eslint").Rule.RuleModule;
|
|
@@ -25,10 +24,18 @@ declare const rules: {
|
|
|
25
24
|
'no-alias': import("eslint").Rule.RuleModule;
|
|
26
25
|
'use-entrypoints-in-examples': import("eslint").Rule.RuleModule;
|
|
27
26
|
'use-recommended-utils': import("eslint").Rule.RuleModule;
|
|
27
|
+
'valid-gate-name': import("eslint").Rule.RuleModule;
|
|
28
28
|
'no-sparse-checkout': import("eslint").Rule.RuleModule;
|
|
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-barrel-entry-imports': import("eslint").Rule.RuleModule;
|
|
33
|
+
'no-barrel-entry-jest-mock': import("eslint").Rule.RuleModule;
|
|
34
|
+
'no-jest-mock-barrel-files': import("eslint").Rule.RuleModule;
|
|
35
|
+
'no-relative-barrel-file-imports': import("eslint").Rule.RuleModule;
|
|
36
|
+
'no-conversation-assistant-barrel-imports': import("eslint").Rule.RuleModule;
|
|
37
|
+
'visit-example-type-import-required': import("eslint").Rule.RuleModule;
|
|
38
|
+
'ensure-use-sync-external-store-server-snapshot': import("eslint").Rule.RuleModule;
|
|
32
39
|
};
|
|
33
40
|
declare const plugin: {
|
|
34
41
|
meta: {
|
|
@@ -51,7 +58,6 @@ declare const plugin: {
|
|
|
51
58
|
'no-pre-post-install-scripts': import("eslint").Rule.RuleModule;
|
|
52
59
|
'no-invalid-storybook-decorator-usage': import("eslint").Rule.RuleModule;
|
|
53
60
|
'ensure-publish-valid': import("eslint").Rule.RuleModule;
|
|
54
|
-
'ensure-native-and-af-exports-synced': import("eslint").Rule.RuleModule;
|
|
55
61
|
'no-module-level-eval': import("eslint").Rule.RuleModule;
|
|
56
62
|
'no-module-level-eval-nav4': import("eslint").Rule.RuleModule;
|
|
57
63
|
'static-feature-flags': import("eslint").Rule.RuleModule;
|
|
@@ -61,10 +67,18 @@ declare const plugin: {
|
|
|
61
67
|
'no-alias': import("eslint").Rule.RuleModule;
|
|
62
68
|
'use-entrypoints-in-examples': import("eslint").Rule.RuleModule;
|
|
63
69
|
'use-recommended-utils': import("eslint").Rule.RuleModule;
|
|
70
|
+
'valid-gate-name': import("eslint").Rule.RuleModule;
|
|
64
71
|
'no-sparse-checkout': import("eslint").Rule.RuleModule;
|
|
65
72
|
'no-direct-document-usage': import("eslint").Rule.RuleModule;
|
|
66
73
|
'no-set-immediate': import("eslint").Rule.RuleModule;
|
|
67
74
|
'prefer-crypto-random-uuid': import("eslint").Rule.RuleModule;
|
|
75
|
+
'no-barrel-entry-imports': import("eslint").Rule.RuleModule;
|
|
76
|
+
'no-barrel-entry-jest-mock': import("eslint").Rule.RuleModule;
|
|
77
|
+
'no-jest-mock-barrel-files': import("eslint").Rule.RuleModule;
|
|
78
|
+
'no-relative-barrel-file-imports': import("eslint").Rule.RuleModule;
|
|
79
|
+
'no-conversation-assistant-barrel-imports': import("eslint").Rule.RuleModule;
|
|
80
|
+
'visit-example-type-import-required': import("eslint").Rule.RuleModule;
|
|
81
|
+
'ensure-use-sync-external-store-server-snapshot': import("eslint").Rule.RuleModule;
|
|
68
82
|
};
|
|
69
83
|
configs: {
|
|
70
84
|
recommended: {
|
|
@@ -76,9 +90,11 @@ declare const plugin: {
|
|
|
76
90
|
'@atlaskit/platform/inline-usage': "error";
|
|
77
91
|
'@atlaskit/platform/prefer-fg': "error";
|
|
78
92
|
'@atlaskit/platform/no-alias': "error";
|
|
93
|
+
'@atlaskit/platform/valid-gate-name': "error";
|
|
79
94
|
'@atlaskit/platform/ensure-feature-flag-registration': "error";
|
|
80
95
|
'@atlaskit/platform/ensure-test-runner-arguments': "error";
|
|
81
96
|
'@atlaskit/platform/ensure-test-runner-nested-count': "warn";
|
|
97
|
+
'@atlaskit/platform/ensure-use-sync-external-store-server-snapshot': "error";
|
|
82
98
|
'@atlaskit/platform/no-invalid-feature-flag-usage': "error";
|
|
83
99
|
'@atlaskit/platform/no-invalid-storybook-decorator-usage': "error";
|
|
84
100
|
'@atlaskit/platform/ensure-atlassian-team': "error";
|
|
@@ -107,9 +123,11 @@ declare const plugin: {
|
|
|
107
123
|
'@atlaskit/platform/inline-usage': "error";
|
|
108
124
|
'@atlaskit/platform/prefer-fg': "error";
|
|
109
125
|
'@atlaskit/platform/no-alias': "error";
|
|
126
|
+
'@atlaskit/platform/valid-gate-name': "error";
|
|
110
127
|
'@atlaskit/platform/ensure-feature-flag-registration': "error";
|
|
111
128
|
'@atlaskit/platform/ensure-test-runner-arguments': "error";
|
|
112
129
|
'@atlaskit/platform/ensure-test-runner-nested-count': "warn";
|
|
130
|
+
'@atlaskit/platform/ensure-use-sync-external-store-server-snapshot': "error";
|
|
113
131
|
'@atlaskit/platform/no-invalid-feature-flag-usage': "error";
|
|
114
132
|
'@atlaskit/platform/no-invalid-storybook-decorator-usage': "error";
|
|
115
133
|
'@atlaskit/platform/ensure-atlassian-team': "error";
|
|
@@ -131,6 +149,7 @@ declare const plugin: {
|
|
|
131
149
|
rules: {
|
|
132
150
|
'@atlaskit/platform/ensure-test-runner-arguments': "error";
|
|
133
151
|
'@atlaskit/platform/ensure-test-runner-nested-count': "warn";
|
|
152
|
+
'@atlaskit/platform/ensure-use-sync-external-store-server-snapshot': "error";
|
|
134
153
|
'@atlaskit/platform/no-invalid-feature-flag-usage': "error";
|
|
135
154
|
'@atlaskit/platform/no-invalid-storybook-decorator-usage': "error";
|
|
136
155
|
'@atlaskit/platform/ensure-atlassian-team': "error";
|
|
@@ -155,6 +174,7 @@ declare const plugin: {
|
|
|
155
174
|
rules: {
|
|
156
175
|
'@atlaskit/platform/ensure-test-runner-arguments': "error";
|
|
157
176
|
'@atlaskit/platform/ensure-test-runner-nested-count': "warn";
|
|
177
|
+
'@atlaskit/platform/ensure-use-sync-external-store-server-snapshot': "error";
|
|
158
178
|
'@atlaskit/platform/no-invalid-feature-flag-usage': "error";
|
|
159
179
|
'@atlaskit/platform/no-invalid-storybook-decorator-usage': "error";
|
|
160
180
|
'@atlaskit/platform/ensure-atlassian-team': "error";
|
|
@@ -187,9 +207,11 @@ declare const configs: {
|
|
|
187
207
|
'@atlaskit/platform/inline-usage': "error";
|
|
188
208
|
'@atlaskit/platform/prefer-fg': "error";
|
|
189
209
|
'@atlaskit/platform/no-alias': "error";
|
|
210
|
+
'@atlaskit/platform/valid-gate-name': "error";
|
|
190
211
|
'@atlaskit/platform/ensure-feature-flag-registration': "error";
|
|
191
212
|
'@atlaskit/platform/ensure-test-runner-arguments': "error";
|
|
192
213
|
'@atlaskit/platform/ensure-test-runner-nested-count': "warn";
|
|
214
|
+
'@atlaskit/platform/ensure-use-sync-external-store-server-snapshot': "error";
|
|
193
215
|
'@atlaskit/platform/no-invalid-feature-flag-usage': "error";
|
|
194
216
|
'@atlaskit/platform/no-invalid-storybook-decorator-usage': "error";
|
|
195
217
|
'@atlaskit/platform/ensure-atlassian-team': "error";
|
|
@@ -218,9 +240,11 @@ declare const configs: {
|
|
|
218
240
|
'@atlaskit/platform/inline-usage': "error";
|
|
219
241
|
'@atlaskit/platform/prefer-fg': "error";
|
|
220
242
|
'@atlaskit/platform/no-alias': "error";
|
|
243
|
+
'@atlaskit/platform/valid-gate-name': "error";
|
|
221
244
|
'@atlaskit/platform/ensure-feature-flag-registration': "error";
|
|
222
245
|
'@atlaskit/platform/ensure-test-runner-arguments': "error";
|
|
223
246
|
'@atlaskit/platform/ensure-test-runner-nested-count': "warn";
|
|
247
|
+
'@atlaskit/platform/ensure-use-sync-external-store-server-snapshot': "error";
|
|
224
248
|
'@atlaskit/platform/no-invalid-feature-flag-usage': "error";
|
|
225
249
|
'@atlaskit/platform/no-invalid-storybook-decorator-usage': "error";
|
|
226
250
|
'@atlaskit/platform/ensure-atlassian-team': "error";
|
|
@@ -242,6 +266,7 @@ declare const configs: {
|
|
|
242
266
|
rules: {
|
|
243
267
|
'@atlaskit/platform/ensure-test-runner-arguments': "error";
|
|
244
268
|
'@atlaskit/platform/ensure-test-runner-nested-count': "warn";
|
|
269
|
+
'@atlaskit/platform/ensure-use-sync-external-store-server-snapshot': "error";
|
|
245
270
|
'@atlaskit/platform/no-invalid-feature-flag-usage': "error";
|
|
246
271
|
'@atlaskit/platform/no-invalid-storybook-decorator-usage': "error";
|
|
247
272
|
'@atlaskit/platform/ensure-atlassian-team': "error";
|
|
@@ -266,6 +291,7 @@ declare const configs: {
|
|
|
266
291
|
rules: {
|
|
267
292
|
'@atlaskit/platform/ensure-test-runner-arguments': "error";
|
|
268
293
|
'@atlaskit/platform/ensure-test-runner-nested-count': "warn";
|
|
294
|
+
'@atlaskit/platform/ensure-use-sync-external-store-server-snapshot': "error";
|
|
269
295
|
'@atlaskit/platform/no-invalid-feature-flag-usage': "error";
|
|
270
296
|
'@atlaskit/platform/no-invalid-storybook-decorator-usage': "error";
|
|
271
297
|
'@atlaskit/platform/ensure-atlassian-team': "error";
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Rule } from 'eslint';
|
|
2
|
+
import { type FileSystem } from '../shared/types';
|
|
3
|
+
/**
|
|
4
|
+
* Factory function to create the ESLint rule with a given file system.
|
|
5
|
+
* This enables testing with mock file systems.
|
|
6
|
+
*/
|
|
7
|
+
export declare function createRule(fs: FileSystem): Rule.RuleModule;
|
|
8
|
+
declare const rule: Rule.RuleModule;
|
|
9
|
+
export default rule;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Rule } from 'eslint';
|
|
2
|
+
import { type FileSystem } from '../shared/types';
|
|
3
|
+
/**
|
|
4
|
+
* Factory function to create the ESLint rule with a given file system.
|
|
5
|
+
* This enables testing with mock file systems.
|
|
6
|
+
*/
|
|
7
|
+
export declare function createRule(fs: FileSystem): Rule.RuleModule;
|
|
8
|
+
declare const rule: Rule.RuleModule;
|
|
9
|
+
export default rule;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Rule } from 'eslint';
|
|
2
|
+
import { type ExportInfo, type FileSystem } from '../shared/types';
|
|
3
|
+
/**
|
|
4
|
+
* Validate and resolve a barrel file from an import path
|
|
5
|
+
* Returns null if not a valid relative barrel import
|
|
6
|
+
*/
|
|
7
|
+
export declare function validateAndResolveBarrelFile({ importPath, basedir, workspaceRoot, fs, }: {
|
|
8
|
+
importPath: string;
|
|
9
|
+
basedir: string;
|
|
10
|
+
workspaceRoot: string;
|
|
11
|
+
fs: FileSystem;
|
|
12
|
+
}): {
|
|
13
|
+
resolvedPath: string;
|
|
14
|
+
exportMap: Map<string, ExportInfo>;
|
|
15
|
+
} | null;
|
|
16
|
+
/**
|
|
17
|
+
* Factory function to create the ESLint rule with a given file system.
|
|
18
|
+
* This enables testing with mock file systems.
|
|
19
|
+
*/
|
|
20
|
+
export declare function createRule(fs: FileSystem): Rule.RuleModule;
|
|
21
|
+
declare const rule: Rule.RuleModule;
|
|
22
|
+
export default rule;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { ExportInfo, FileSystem } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Get all named exports from a file.
|
|
4
|
+
* This extracts what names are exported from a file for star exports.
|
|
5
|
+
*/
|
|
6
|
+
export declare function getNamedExportsFromFile({ filePath, fs, }: {
|
|
7
|
+
filePath: string;
|
|
8
|
+
fs: FileSystem;
|
|
9
|
+
}): Set<string>;
|
|
10
|
+
/**
|
|
11
|
+
* Check if an export map represents a barrel file (has re-exports from other files)
|
|
12
|
+
*/
|
|
13
|
+
export declare function hasReExportsFromOtherFiles({ exportMap, sourceFilePath, }: {
|
|
14
|
+
exportMap: Map<string, ExportInfo>;
|
|
15
|
+
sourceFilePath: string;
|
|
16
|
+
}): boolean;
|
|
17
|
+
/**
|
|
18
|
+
* Parse export statements from a file to find where each export comes from.
|
|
19
|
+
* Returns a map of export name -> ExportInfo.
|
|
20
|
+
*
|
|
21
|
+
* This function recursively traces through nested barrels and cross-package re-exports
|
|
22
|
+
* to find the ultimate source file for each export.
|
|
23
|
+
*/
|
|
24
|
+
export declare function parseBarrelExports({ barrelFilePath, depth, fs, workspaceRoot, visitedPackages, }: {
|
|
25
|
+
barrelFilePath: string;
|
|
26
|
+
depth?: number;
|
|
27
|
+
fs: FileSystem;
|
|
28
|
+
workspaceRoot?: string;
|
|
29
|
+
visitedPackages?: Set<string>;
|
|
30
|
+
}): Map<string, ExportInfo>;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { FileSystem } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* The default folder paths that barrel import rules apply to.
|
|
4
|
+
* Only imports from packages within these folders will be checked.
|
|
5
|
+
* This can be overridden via lint rule options.
|
|
6
|
+
*/
|
|
7
|
+
export declare const DEFAULT_TARGET_FOLDERS: string[];
|
|
8
|
+
/**
|
|
9
|
+
* Try to read file contents with error handling.
|
|
10
|
+
* Returns null if file cannot be read.
|
|
11
|
+
*/
|
|
12
|
+
export declare function readFileContent({ filePath, fs, }: {
|
|
13
|
+
filePath: string;
|
|
14
|
+
fs: FileSystem;
|
|
15
|
+
}): string | null;
|
|
16
|
+
/**
|
|
17
|
+
* Check if a path is a relative import (starts with ./ or ../)
|
|
18
|
+
*/
|
|
19
|
+
export declare function isRelativeImport(importPath: string): boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Resolve the actual file path from an import path.
|
|
22
|
+
* Handles extension inference and index file resolution.
|
|
23
|
+
*/
|
|
24
|
+
export declare function resolveImportPath({ basedir, importPath, fs, }: {
|
|
25
|
+
basedir: string;
|
|
26
|
+
importPath: string;
|
|
27
|
+
fs: FileSystem;
|
|
28
|
+
}): string | null;
|
|
29
|
+
/**
|
|
30
|
+
* Find the workspace root using git rev-parse --show-toplevel.
|
|
31
|
+
* The result is cached on fs.cache.gitRepoRoot to avoid repeated shell calls.
|
|
32
|
+
* Falls back to directory traversal if git command fails.
|
|
33
|
+
*/
|
|
34
|
+
export declare function findWorkspaceRoot({ startPath, fs, applyToImportsFrom, }: {
|
|
35
|
+
startPath: string;
|
|
36
|
+
fs: FileSystem;
|
|
37
|
+
applyToImportsFrom?: string[];
|
|
38
|
+
}): string;
|