@atlaskit/eslint-plugin-platform 2.9.0 → 2.9.2
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 +17 -0
- package/dist/cjs/index.js +8 -2
- package/dist/cjs/rules/compiled/no-css-prop-in-object-spread/index.js +162 -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/no-xcss-in-cx/index.js +221 -0
- package/dist/cjs/rules/visit-example-type-import-required/index.js +24 -14
- package/dist/es2019/index.js +8 -2
- package/dist/es2019/rules/compiled/no-css-prop-in-object-spread/index.js +136 -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/no-xcss-in-cx/index.js +187 -0
- package/dist/es2019/rules/visit-example-type-import-required/index.js +24 -15
- package/dist/esm/index.js +8 -2
- package/dist/esm/rules/compiled/no-css-prop-in-object-spread/index.js +156 -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/no-xcss-in-cx/index.js +216 -0
- package/dist/esm/rules/visit-example-type-import-required/index.js +24 -14
- package/dist/types/index.d.ts +278 -241
- package/dist/types/rules/compiled/no-css-prop-in-object-spread/index.d.ts +3 -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/rules/no-xcss-in-cx/index.d.ts +31 -0
- package/dist/types-ts4.5/index.d.ts +222 -209
- package/dist/types-ts4.5/rules/compiled/no-css-prop-in-object-spread/index.d.ts +3 -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/dist/types-ts4.5/rules/no-xcss-in-cx/index.d.ts +31 -0
- package/package.json +1 -1
|
@@ -0,0 +1,216 @@
|
|
|
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
|
+
import { getImportSources, isCxFunction, isXcss } from '@atlaskit/eslint-utils/is-supported-import';
|
|
5
|
+
import { getScope } from '../util/context-compat';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Disallows passing xcss() results into cx() when used in an xcss prop.
|
|
9
|
+
*
|
|
10
|
+
* xcss() from @atlaskit/primitives and cx() from @atlaskit/css / @compiled/react
|
|
11
|
+
* are incompatible — xcss() produces an opaque StyleRule object, while cx()
|
|
12
|
+
* expects Compiled atomic class name strings. Mixing them causes runtime errors.
|
|
13
|
+
* xcss() results must never be passed to cx(), whether inline or pre-defined.
|
|
14
|
+
*
|
|
15
|
+
* ❌ Wrong — xcss() called inline inside cx():
|
|
16
|
+
* xcss={cx(xcss({ color: 'red' }), xcss({ fontWeight: 'bold' }))}
|
|
17
|
+
*
|
|
18
|
+
* ❌ Also wrong — xcss() results pre-defined but still passed into cx():
|
|
19
|
+
* const baseStyles = xcss({ color: 'red' });
|
|
20
|
+
* const boldStyles = xcss({ fontWeight: 'bold' });
|
|
21
|
+
* xcss={cx(baseStyles, boldStyles)}
|
|
22
|
+
*
|
|
23
|
+
* ✅ Correct — pass xcss() results directly to the xcss prop (no cx()):
|
|
24
|
+
* const baseStyles = xcss({ color: 'red' });
|
|
25
|
+
* xcss={baseStyles}
|
|
26
|
+
*
|
|
27
|
+
* ✅ Correct — use cssMap() + cx() (cssMap is compatible with cx()):
|
|
28
|
+
* const styles = cssMap({ base: { color: 'red' } });
|
|
29
|
+
* xcss={cx(styles.base, condition && styles.focused)}
|
|
30
|
+
*
|
|
31
|
+
* This rule is import-aware: it only flags xcss() calls (inline or via variable)
|
|
32
|
+
* imported from @atlaskit/primitives inside cx() calls imported from @atlaskit/css
|
|
33
|
+
* or @compiled/react that appear inside an xcss prop.
|
|
34
|
+
*/
|
|
35
|
+
var rule = {
|
|
36
|
+
meta: {
|
|
37
|
+
type: 'problem',
|
|
38
|
+
docs: {
|
|
39
|
+
description: 'Disallow calling xcss() inline inside cx() in an xcss prop. Define styles at module level instead.'
|
|
40
|
+
},
|
|
41
|
+
messages: {
|
|
42
|
+
noXcssInCx: 'Do not pass xcss() results into cx(). ' + 'xcss() produces a StyleRule object that is incompatible with cx(), which expects Compiled atomic class names. ' + 'Pass xcss() results directly to the xcss prop instead: xcss={myStyles}. ' + 'To conditionally combine styles, use cssMap() + cx(): const styles = cssMap({...}); xcss={cx(styles.base, cond && styles.active)}'
|
|
43
|
+
},
|
|
44
|
+
schema: []
|
|
45
|
+
},
|
|
46
|
+
create: function create(context) {
|
|
47
|
+
return {
|
|
48
|
+
JSXAttribute: function JSXAttribute(node) {
|
|
49
|
+
// Narrow Rule.Node to JSXAttribute (estree-jsx augments the `estree` Node
|
|
50
|
+
// union with JSX members, so this discriminated narrowing is safe).
|
|
51
|
+
if (node.type !== 'JSXAttribute') {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Only check `xcss` props
|
|
56
|
+
if (node.name.type !== 'JSXIdentifier' || node.name.name !== 'xcss') {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
if (!node.value || node.value.type !== 'JSXExpressionContainer') {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
var expression = node.value.expression;
|
|
63
|
+
if (expression.type === 'JSXEmptyExpression') {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Early-return if the expression cannot possibly contain a cx() call —
|
|
68
|
+
// avoids the cost of getImportSources/getScope on simple references like xcss={baseStyles}.
|
|
69
|
+
var isCallOrArray = expression.type === 'CallExpression' || expression.type === 'ArrayExpression';
|
|
70
|
+
if (!isCallOrArray) {
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
var importSources = getImportSources(context);
|
|
74
|
+
var _getScope = getScope(context, node),
|
|
75
|
+
references = _getScope.references;
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Returns true if an Identifier node resolves to a variable whose
|
|
79
|
+
* initializer is a call to xcss() imported from @atlaskit/primitives.
|
|
80
|
+
*
|
|
81
|
+
* Walks up the scope chain from the current JSXAttribute scope to find
|
|
82
|
+
* the variable definition, since module-level variables are not in the
|
|
83
|
+
* local scope's references list.
|
|
84
|
+
*
|
|
85
|
+
* e.g. `const baseStyles = xcss({ color: 'red' })` — passing `baseStyles`
|
|
86
|
+
* here returns true.
|
|
87
|
+
*/
|
|
88
|
+
var isXcssVariable = function isXcssVariable(identNode) {
|
|
89
|
+
if (identNode.type !== 'Identifier') {
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
var name = identNode.name;
|
|
93
|
+
// Walk up the scope chain to find the variable definition
|
|
94
|
+
var currentScope = getScope(context, node);
|
|
95
|
+
while (currentScope) {
|
|
96
|
+
var variable = currentScope.set.get(name);
|
|
97
|
+
if (variable) {
|
|
98
|
+
var _iterator = _createForOfIteratorHelper(variable.defs),
|
|
99
|
+
_step;
|
|
100
|
+
try {
|
|
101
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
102
|
+
var _def$node$init;
|
|
103
|
+
var def = _step.value;
|
|
104
|
+
if (def.type === 'Variable' && def.node.type === 'VariableDeclarator' && ((_def$node$init = def.node.init) === null || _def$node$init === void 0 ? void 0 : _def$node$init.type) === 'CallExpression') {
|
|
105
|
+
// isXcss checks the callee identifier against referencesInScope to
|
|
106
|
+
// find the import binding. The callee lives in the same scope as the
|
|
107
|
+
// variable definition, so use all references from that scope.
|
|
108
|
+
var defScopeRefs = currentScope.references;
|
|
109
|
+
if (isXcss(def.node.init.callee, defScopeRefs, importSources)) {
|
|
110
|
+
return true;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
// Found the variable but it's not an xcss() call
|
|
115
|
+
} catch (err) {
|
|
116
|
+
_iterator.e(err);
|
|
117
|
+
} finally {
|
|
118
|
+
_iterator.f();
|
|
119
|
+
}
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
122
|
+
currentScope = currentScope.upper;
|
|
123
|
+
}
|
|
124
|
+
return false;
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Recursively check a node that is an argument to cx() for xcss() results —
|
|
129
|
+
* both inline calls and references to variables initialised with xcss().
|
|
130
|
+
* Recurses into LogicalExpression (&&, ||) and ConditionalExpression (? :) so that
|
|
131
|
+
* patterns like cx(cond && xcss({...})) and cx(cond ? baseStyles : a) are caught.
|
|
132
|
+
*/
|
|
133
|
+
var _checkArgForXcss = function checkArgForXcss(argNode) {
|
|
134
|
+
if (!argNode) {
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
// Inline: cx(xcss({ color: 'red' }))
|
|
138
|
+
if (argNode.type === 'CallExpression' && isXcss(argNode.callee, references, importSources)) {
|
|
139
|
+
context.report({
|
|
140
|
+
node: argNode,
|
|
141
|
+
messageId: 'noXcssInCx'
|
|
142
|
+
});
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
// Variable reference: cx(baseStyles) where baseStyles = xcss({...})
|
|
146
|
+
if (isXcssVariable(argNode)) {
|
|
147
|
+
context.report({
|
|
148
|
+
node: argNode,
|
|
149
|
+
messageId: 'noXcssInCx'
|
|
150
|
+
});
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
// Recurse into `cond && xcss({...})` or `cond || xcss({...})`
|
|
154
|
+
if (argNode.type === 'LogicalExpression') {
|
|
155
|
+
_checkArgForXcss(argNode.left);
|
|
156
|
+
_checkArgForXcss(argNode.right);
|
|
157
|
+
}
|
|
158
|
+
// Recurse into `cond ? xcss({...}) : fallback`
|
|
159
|
+
if (argNode.type === 'ConditionalExpression') {
|
|
160
|
+
_checkArgForXcss(argNode.consequent);
|
|
161
|
+
_checkArgForXcss(argNode.alternate);
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Check all arguments of a cx() call for inline xcss() calls.
|
|
167
|
+
* Reports each xcss() call found as a violation.
|
|
168
|
+
*/
|
|
169
|
+
var checkCxArgs = function checkCxArgs(callNode) {
|
|
170
|
+
if (callNode.type !== 'CallExpression') {
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
if (!isCxFunction(callNode.callee, references, importSources)) {
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
var _iterator2 = _createForOfIteratorHelper(callNode.arguments),
|
|
177
|
+
_step2;
|
|
178
|
+
try {
|
|
179
|
+
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
180
|
+
var arg = _step2.value;
|
|
181
|
+
if (arg) {
|
|
182
|
+
_checkArgForXcss(arg.type === 'SpreadElement' ? arg.argument : arg);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
} catch (err) {
|
|
186
|
+
_iterator2.e(err);
|
|
187
|
+
} finally {
|
|
188
|
+
_iterator2.f();
|
|
189
|
+
}
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
// Case 1: xcss={cx(...)} — cx() directly as the xcss value
|
|
193
|
+
checkCxArgs(expression);
|
|
194
|
+
|
|
195
|
+
// Case 2: xcss={[..., cx(...), ...]} — cx() inside an xcss array
|
|
196
|
+
if (expression.type === 'ArrayExpression') {
|
|
197
|
+
var _iterator3 = _createForOfIteratorHelper(expression.elements),
|
|
198
|
+
_step3;
|
|
199
|
+
try {
|
|
200
|
+
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
|
|
201
|
+
var element = _step3.value;
|
|
202
|
+
if (element) {
|
|
203
|
+
checkCxArgs(element.type === 'SpreadElement' ? element.argument : element);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
} catch (err) {
|
|
207
|
+
_iterator3.e(err);
|
|
208
|
+
} finally {
|
|
209
|
+
_iterator3.f();
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
};
|
|
216
|
+
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
|
/**
|
|
@@ -111,7 +111,8 @@ function resolveVariableToConstant(programBody, variableName, cache) {
|
|
|
111
111
|
* Returns null for any argument that can't be statically resolved.
|
|
112
112
|
*/
|
|
113
113
|
function extractCallArgs(node, programBody, variableCache) {
|
|
114
|
-
|
|
114
|
+
var argOffset = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0;
|
|
115
|
+
if (node.arguments.length < argOffset + 3) {
|
|
115
116
|
return null;
|
|
116
117
|
}
|
|
117
118
|
function resolveArg(arg) {
|
|
@@ -123,9 +124,9 @@ function extractCallArgs(node, programBody, variableCache) {
|
|
|
123
124
|
}
|
|
124
125
|
return null;
|
|
125
126
|
}
|
|
126
|
-
var groupId = resolveArg(node.arguments[
|
|
127
|
-
var packageId = resolveArg(node.arguments[1]);
|
|
128
|
-
var exampleId = resolveArg(node.arguments[2]);
|
|
127
|
+
var groupId = resolveArg(node.arguments[argOffset]);
|
|
128
|
+
var packageId = resolveArg(node.arguments[argOffset + 1]);
|
|
129
|
+
var exampleId = resolveArg(node.arguments[argOffset + 2]);
|
|
129
130
|
if (!groupId || !packageId || !exampleId) {
|
|
130
131
|
return null;
|
|
131
132
|
}
|
|
@@ -173,8 +174,13 @@ function resolveExamplePathFromArgs(groupId, packageId, exampleId, testFilePath)
|
|
|
173
174
|
var examplesDir = path.resolve(packagesBase.basePath, groupId, packageId, 'examples');
|
|
174
175
|
var fallback = path.resolve(examplesDir, "".concat(exampleId, ".tsx"));
|
|
175
176
|
|
|
176
|
-
//
|
|
177
|
-
|
|
177
|
+
// Phase 4: loosen candidateRe to match both pre- and post-rename filename shapes.
|
|
178
|
+
// Pre-rename: ^(\d+-)?<id>(\.(examples?))?\.tsx$
|
|
179
|
+
// Post-rename: ^(\d+-)?<id>(\.<ident>){0,3}\.tsx$ (Volt prefix, optional .dup<N>, optional role)
|
|
180
|
+
// The {0,3} cap prevents matching arbitrary strings (e.g. 4-component names).
|
|
181
|
+
// Escape regex metacharacters in exampleId (ids are kebab-case today, but defensive).
|
|
182
|
+
var escapedId = exampleId.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
183
|
+
var candidateRe = new RegExp("^(?:\\d+-)?".concat(escapedId, "(?:\\.[A-Za-z][A-Za-z0-9_]*){0,3}\\.tsx$"));
|
|
178
184
|
try {
|
|
179
185
|
var match = fs.readdirSync(examplesDir).find(function (f) {
|
|
180
186
|
return candidateRe.test(f);
|
|
@@ -272,20 +278,24 @@ var rule = {
|
|
|
272
278
|
return;
|
|
273
279
|
}
|
|
274
280
|
var node = estreeNode;
|
|
275
|
-
|
|
276
|
-
|
|
281
|
+
var calleeIdentifier = null;
|
|
282
|
+
var argOffset = 0;
|
|
283
|
+
if (node.callee.type === AST_NODE_TYPES.MemberExpression && node.callee.property.type === AST_NODE_TYPES.Identifier && node.callee.property.name === 'visitExample') {
|
|
284
|
+
calleeIdentifier = node.callee.property;
|
|
285
|
+
} else if (node.callee.type === AST_NODE_TYPES.Identifier && node.callee.name === 'visitMockedExample') {
|
|
286
|
+
calleeIdentifier = node.callee;
|
|
287
|
+
argOffset = 1; // first arg is `page`
|
|
288
|
+
} else {
|
|
277
289
|
return;
|
|
278
290
|
}
|
|
279
291
|
|
|
280
|
-
// Narrow callee — we've confirmed property is an Identifier above
|
|
281
|
-
var callee = node.callee;
|
|
282
292
|
// reportCallee is typed as estree.Node for context.report compatibility
|
|
283
293
|
var reportCallee = estreeNode.callee;
|
|
284
294
|
var genericType = extractGenericType(node);
|
|
285
295
|
|
|
286
296
|
// ── Case 1: No generic type parameter ────────────────────────────────
|
|
287
297
|
if (genericType === null) {
|
|
288
|
-
var _args = extractCallArgs(node, programBody, variableCache);
|
|
298
|
+
var _args = extractCallArgs(node, programBody, variableCache, argOffset);
|
|
289
299
|
context.report({
|
|
290
300
|
node: reportCallee,
|
|
291
301
|
messageId: 'missingTypeofImport',
|
|
@@ -298,7 +308,7 @@ var rule = {
|
|
|
298
308
|
return null;
|
|
299
309
|
}
|
|
300
310
|
var importPath = computeRelativeImportPath(filename, examplePath);
|
|
301
|
-
var _ref2 =
|
|
311
|
+
var _ref2 = calleeIdentifier.range,
|
|
302
312
|
_ref3 = _slicedToArray(_ref2, 2),
|
|
303
313
|
start = _ref3[0],
|
|
304
314
|
end = _ref3[1];
|
|
@@ -360,7 +370,7 @@ var rule = {
|
|
|
360
370
|
}
|
|
361
371
|
|
|
362
372
|
// Validate that the import path matches the arguments
|
|
363
|
-
var args = extractCallArgs(node, programBody, variableCache);
|
|
373
|
+
var args = extractCallArgs(node, programBody, variableCache, argOffset);
|
|
364
374
|
if (!args) {
|
|
365
375
|
// Dynamic arguments — can't validate statically
|
|
366
376
|
return;
|