@atlaskit/eslint-plugin-platform 2.5.0 → 2.7.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 +17 -0
- package/afm-cc/tsconfig.json +1 -1
- package/dist/cjs/index.js +43 -3
- package/dist/cjs/rules/ensure-native-and-af-exports-synced/index.js +3 -0
- package/dist/cjs/rules/ensure-valid-platform-yarn-protocol-usage/index.js +1 -1
- package/dist/cjs/rules/feature-gating/no-preconditioning/index.js +1 -1
- package/dist/cjs/rules/no-direct-document-usage/index.js +103 -0
- package/dist/cjs/rules/no-set-immediate/index.js +39 -0
- package/dist/cjs/rules/no-sparse-checkout/index.js +43 -0
- package/dist/cjs/rules/util/file-exclusions.js +45 -0
- package/dist/es2019/index.js +43 -3
- package/dist/es2019/rules/ensure-native-and-af-exports-synced/index.js +3 -0
- package/dist/es2019/rules/ensure-valid-platform-yarn-protocol-usage/index.js +1 -1
- package/dist/es2019/rules/feature-gating/no-preconditioning/index.js +1 -1
- package/dist/es2019/rules/no-direct-document-usage/index.js +95 -0
- package/dist/es2019/rules/no-set-immediate/index.js +33 -0
- package/dist/es2019/rules/no-sparse-checkout/index.js +35 -0
- package/dist/es2019/rules/util/file-exclusions.js +37 -0
- package/dist/esm/index.js +43 -3
- package/dist/esm/rules/ensure-native-and-af-exports-synced/index.js +3 -0
- package/dist/esm/rules/ensure-valid-platform-yarn-protocol-usage/index.js +1 -1
- package/dist/esm/rules/feature-gating/no-preconditioning/index.js +1 -1
- package/dist/esm/rules/no-direct-document-usage/index.js +97 -0
- package/dist/esm/rules/no-set-immediate/index.js +33 -0
- package/dist/esm/rules/no-sparse-checkout/index.js +37 -0
- package/dist/esm/rules/util/file-exclusions.js +39 -0
- package/dist/types/index.d.ts +22 -0
- package/dist/types/rules/no-direct-document-usage/index.d.ts +3 -0
- package/dist/types/rules/no-set-immediate/index.d.ts +3 -0
- package/dist/types/rules/no-sparse-checkout/index.d.ts +3 -0
- package/dist/types/rules/util/file-exclusions.d.ts +13 -0
- package/dist/types-ts4.5/index.d.ts +22 -0
- package/dist/types-ts4.5/rules/no-direct-document-usage/index.d.ts +3 -0
- package/dist/types-ts4.5/rules/no-set-immediate/index.d.ts +3 -0
- package/dist/types-ts4.5/rules/no-sparse-checkout/index.d.ts +3 -0
- package/dist/types-ts4.5/rules/util/file-exclusions.d.ts +13 -0
- package/package.json +10 -1
- package/src/index.tsx +47 -2
- package/src/rules/ensure-native-and-af-exports-synced/index.tsx +3 -0
- package/src/rules/ensure-valid-bin-values/__tests__/unit/rule.test.ts +3 -2
- package/src/rules/ensure-valid-platform-yarn-protocol-usage/index.ts +1 -1
- package/src/rules/feature-gating/no-preconditioning/index.tsx +1 -1
- package/src/rules/no-direct-document-usage/index.tsx +111 -0
- package/src/rules/no-set-immediate/index.tsx +43 -0
- package/src/rules/no-sparse-checkout/__tests__/unit/rule.test.tsx +48 -0
- package/src/rules/no-sparse-checkout/index.tsx +54 -0
- package/src/rules/util/file-exclusions.ts +39 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# @atlaskit/eslint-plugin-platform
|
|
2
2
|
|
|
3
|
+
## 2.7.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#157255](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/pull-requests/157255)
|
|
8
|
+
[`334db48ef3650`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/334db48ef3650) -
|
|
9
|
+
Linting rule to forbid use of non standard setImediate
|
|
10
|
+
|
|
11
|
+
## 2.6.0
|
|
12
|
+
|
|
13
|
+
### Minor Changes
|
|
14
|
+
|
|
15
|
+
- [#168806](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/pull-requests/168806)
|
|
16
|
+
[`e4f94f422b9f1`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/e4f94f422b9f1) -
|
|
17
|
+
New linting rule to prevent direct "document" usage. This prevents failed tests when document is
|
|
18
|
+
not defined in the testing environment
|
|
19
|
+
|
|
3
20
|
## 2.5.0
|
|
4
21
|
|
|
5
22
|
### Minor Changes
|
package/afm-cc/tsconfig.json
CHANGED
package/dist/cjs/index.js
CHANGED
|
@@ -34,8 +34,29 @@ var _useEntrypointsInExamples = _interopRequireDefault(require("./rules/use-entr
|
|
|
34
34
|
var _useRecommendedUtils = _interopRequireDefault(require("./rules/feature-gating/use-recommended-utils"));
|
|
35
35
|
var _expandBackgroundShorthand = _interopRequireDefault(require("./rules/compiled/expand-background-shorthand"));
|
|
36
36
|
var _expandSpacingShorthand = _interopRequireDefault(require("./rules/compiled/expand-spacing-shorthand"));
|
|
37
|
+
var _noSparseCheckout = _interopRequireDefault(require("./rules/no-sparse-checkout"));
|
|
38
|
+
var _noDirectDocumentUsage = _interopRequireDefault(require("./rules/no-direct-document-usage"));
|
|
39
|
+
var _noSetImmediate = _interopRequireDefault(require("./rules/no-set-immediate"));
|
|
40
|
+
var _nodePath = require("node:path");
|
|
41
|
+
var _nodeFs = require("node:fs");
|
|
37
42
|
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; }
|
|
38
43
|
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; } // eslint-disable-next-line import/no-extraneous-dependencies
|
|
44
|
+
var jiraRoot;
|
|
45
|
+
try {
|
|
46
|
+
var findUp = require('find-up');
|
|
47
|
+
findUp.sync(function (dir) {
|
|
48
|
+
var productsJsonPath = (0, _nodePath.join)(dir, 'products.json');
|
|
49
|
+
if (findUp.sync.exists(productsJsonPath)) {
|
|
50
|
+
var productJson = JSON.parse((0, _nodeFs.readFileSync)(productsJsonPath, 'utf-8'));
|
|
51
|
+
if (productJson.Jira) {
|
|
52
|
+
jiraRoot = (0, _nodePath.normalize)((0, _nodePath.join)(dir, productJson.Jira.path));
|
|
53
|
+
return findUp.stop;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
} catch (_unused) {
|
|
58
|
+
// we aren't running inside of AFM, so we can ignore this.
|
|
59
|
+
}
|
|
39
60
|
var packageJson = require('@atlaskit/eslint-plugin-platform/package.json');
|
|
40
61
|
var rules = exports.rules = {
|
|
41
62
|
'ensure-feature-flag-registration': _ensureFeatureFlagRegistration.default,
|
|
@@ -64,7 +85,10 @@ var rules = exports.rules = {
|
|
|
64
85
|
'prefer-fg': _preferFg.default,
|
|
65
86
|
'no-alias': _noAlias.default,
|
|
66
87
|
'use-entrypoints-in-examples': _useEntrypointsInExamples.default,
|
|
67
|
-
'use-recommended-utils': _useRecommendedUtils.default
|
|
88
|
+
'use-recommended-utils': _useRecommendedUtils.default,
|
|
89
|
+
'no-sparse-checkout': _noSparseCheckout.default,
|
|
90
|
+
'no-direct-document-usage': _noDirectDocumentUsage.default,
|
|
91
|
+
'no-set-immediate': _noSetImmediate.default
|
|
68
92
|
};
|
|
69
93
|
var commonConfig = {
|
|
70
94
|
'@atlaskit/platform/ensure-test-runner-arguments': 'error',
|
|
@@ -73,6 +97,8 @@ var commonConfig = {
|
|
|
73
97
|
'@atlaskit/platform/no-invalid-storybook-decorator-usage': 'error',
|
|
74
98
|
'@atlaskit/platform/ensure-atlassian-team': 'error',
|
|
75
99
|
'@atlaskit/platform/no-module-level-eval-nav4': 'error',
|
|
100
|
+
'@atlaskit/platform/no-direct-document-usage': 'warn',
|
|
101
|
+
'@atlaskit/platform/no-set-immediate': 'error',
|
|
76
102
|
// Compiled: rules that are not included via `@compiled/recommended
|
|
77
103
|
'@atlaskit/platform/expand-border-shorthand': 'error',
|
|
78
104
|
'@atlaskit/platform/expand-background-shorthand': 'error',
|
|
@@ -101,6 +127,7 @@ var recommendedRules = _objectSpread(_objectSpread({}, commonConfig), {}, {
|
|
|
101
127
|
var jiraRules = commonConfig;
|
|
102
128
|
var jsonPrefix = '/* eslint-disable quote-props, comma-dangle, quotes, semi, eol-last, @typescript-eslint/semi, no-template-curly-in-string */ module.exports = ';
|
|
103
129
|
var jsonPrefixForFlatConfig = '/* eslint-disable quote-props, comma-dangle, quotes, semi, eol-last, no-template-curly-in-string */ module.exports = ';
|
|
130
|
+
var jsonPrefixForJira = 'module.exports = ';
|
|
104
131
|
var name = packageJson.name,
|
|
105
132
|
version = packageJson.version;
|
|
106
133
|
var plugin = exports.plugin = {
|
|
@@ -147,7 +174,14 @@ var plugin = exports.plugin = {
|
|
|
147
174
|
},
|
|
148
175
|
processors: {
|
|
149
176
|
'package-json-processor': {
|
|
150
|
-
preprocess: function preprocess(source) {
|
|
177
|
+
preprocess: function preprocess(source, filename) {
|
|
178
|
+
// we only need to check for jiraRoot because it uses a different
|
|
179
|
+
// ESLint version and produces fake errors due to how this processor handles JSON
|
|
180
|
+
if (jiraRoot && filename.startsWith(jiraRoot)) {
|
|
181
|
+
// augment the json into a js file
|
|
182
|
+
return [jsonPrefixForJira + source.trim()];
|
|
183
|
+
}
|
|
184
|
+
|
|
151
185
|
// augment the json into a js file
|
|
152
186
|
return [jsonPrefix + source.trim()];
|
|
153
187
|
},
|
|
@@ -170,7 +204,13 @@ var plugin = exports.plugin = {
|
|
|
170
204
|
// This processor is used for ESLint FlatConfig,
|
|
171
205
|
// once we roll out FlatConfig, we can remove the above processor
|
|
172
206
|
'package-json-processor-for-flat-config': {
|
|
173
|
-
|
|
207
|
+
// we only need to check for jiraRoot because it uses a different
|
|
208
|
+
// ESLint version and produces fake errors due to how this processor handles JSON
|
|
209
|
+
preprocess: function preprocess(source, filename) {
|
|
210
|
+
if (jiraRoot && filename.startsWith(jiraRoot)) {
|
|
211
|
+
// augment the json into a js file
|
|
212
|
+
return [jsonPrefixForJira + source.trim()];
|
|
213
|
+
}
|
|
174
214
|
// augment the json into a js file
|
|
175
215
|
return [jsonPrefixForFlatConfig + source.trim()];
|
|
176
216
|
},
|
|
@@ -13,6 +13,9 @@ var _registrationUtils = require("../util/registration-utils");
|
|
|
13
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
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
15
|
var exportsValidationExceptions = {
|
|
16
|
+
'@af/yarn-workspace': {
|
|
17
|
+
ignoredAfExportKeys: ['./lock-parser']
|
|
18
|
+
},
|
|
16
19
|
'@atlaskit/tokens': {
|
|
17
20
|
ignoredAfExportKeys: ['./babel-plugin']
|
|
18
21
|
},
|
|
@@ -53,7 +53,7 @@ var rule = {
|
|
|
53
53
|
},
|
|
54
54
|
hasSuggestions: false,
|
|
55
55
|
messages: {
|
|
56
|
-
invalidWorkspaceProtocolUsage: "The 'workspace:^'
|
|
56
|
+
invalidWorkspaceProtocolUsage: "The 'workspace:^'protocol is Used. To resolve this error, please use the 'workspace:*' protocol instead.",
|
|
57
57
|
invalidRootProtocolUsage: "The 'root:' protocol is not allowed in platform packages. To resolve this error, replace the 'root:' protocol with specific package versions (e.g. '^1.0.0')."
|
|
58
58
|
}
|
|
59
59
|
},
|
|
@@ -55,7 +55,7 @@ var rule = {
|
|
|
55
55
|
url: 'https://stash.atlassian.com/projects/ATLASSIAN/repos/atlassian-frontend-monorepo/browse/platform/packages/platform/eslint-plugin/src/rules/no-preconditioning/README.md'
|
|
56
56
|
},
|
|
57
57
|
messages: {
|
|
58
|
-
useConfig: 'Do not precondition gates or experiments with another gate. Configure this in Statsig instead to reduce unnecessary code and
|
|
58
|
+
useConfig: 'Do not precondition gates or experiments with another gate. Configure this in Statsig instead to reduce unnecessary code, simplify cleanup and to ensure accurate exposures in Statsig.',
|
|
59
59
|
incorrectExposure: 'Evaluate gates or experiments at the end of your logical expression to ensure exposure is tracked correctly.'
|
|
60
60
|
}
|
|
61
61
|
},
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = void 0;
|
|
7
|
+
var _fileExclusions = require("../util/file-exclusions");
|
|
8
|
+
var rule = {
|
|
9
|
+
meta: {
|
|
10
|
+
type: 'problem',
|
|
11
|
+
docs: {
|
|
12
|
+
description: 'Enforce using getDocument from @atlaskit/browser-apis instead of direct document usage',
|
|
13
|
+
recommended: true
|
|
14
|
+
},
|
|
15
|
+
messages: {
|
|
16
|
+
useGetDocument: 'Use getDocument from @atlaskit/browser-apis instead of direct document usage'
|
|
17
|
+
},
|
|
18
|
+
schema: []
|
|
19
|
+
},
|
|
20
|
+
create: function create(context) {
|
|
21
|
+
var hasGetDocumentImport = false;
|
|
22
|
+
var filename = context.filename;
|
|
23
|
+
|
|
24
|
+
// Skip test files
|
|
25
|
+
var skipResult = (0, _fileExclusions.skipForTestFiles)(context);
|
|
26
|
+
if (skipResult) {
|
|
27
|
+
return skipResult;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Skip example files
|
|
31
|
+
var skipResult2 = (0, _fileExclusions.skipForExampleFiles)(context);
|
|
32
|
+
if (skipResult2) {
|
|
33
|
+
return skipResult2;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Skip the getDocument.ts file itself
|
|
37
|
+
if (filename.endsWith('getDocument.ts')) {
|
|
38
|
+
return {};
|
|
39
|
+
}
|
|
40
|
+
return {
|
|
41
|
+
ImportDeclaration: function ImportDeclaration(node) {
|
|
42
|
+
if (node.source.value === '@atlaskit/browser-apis' && node.specifiers.some(function (specifier) {
|
|
43
|
+
return specifier.type === 'ImportSpecifier' && specifier.imported.type === 'Identifier' && specifier.imported.name === 'getDocument';
|
|
44
|
+
})) {
|
|
45
|
+
hasGetDocumentImport = true;
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
Identifier: function Identifier(node) {
|
|
49
|
+
if (node.name === 'document' && !hasGetDocumentImport) {
|
|
50
|
+
var parent = node.parent;
|
|
51
|
+
|
|
52
|
+
// Skip if 'document' is used as a property key in an object literal
|
|
53
|
+
if ((parent === null || parent === void 0 ? void 0 : parent.type) === 'Property' && parent.key === node) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Skip if 'document' is used as a shorthand property value
|
|
58
|
+
if ((parent === null || parent === void 0 ? void 0 : parent.type) === 'Property' && parent.value === node && parent.shorthand) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Skip if 'document' is used as a property being accessed in a member expression
|
|
63
|
+
if ((parent === null || parent === void 0 ? void 0 : parent.type) === 'MemberExpression' && parent.property === node && !parent.computed) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Skip if 'document' is being declared as a variable
|
|
68
|
+
if ((parent === null || parent === void 0 ? void 0 : parent.type) === 'VariableDeclarator' && parent.id === node) {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Skip if 'document' is a function name
|
|
73
|
+
if ((parent === null || parent === void 0 ? void 0 : parent.type) === 'FunctionDeclaration' && 'id' in parent && parent.id === node) {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
if ((parent === null || parent === void 0 ? void 0 : parent.type) === 'FunctionExpression' && 'id' in parent && parent.id === node) {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Skip if 'document' is a method name in a class or object
|
|
81
|
+
if ((parent === null || parent === void 0 ? void 0 : parent.type) === 'MethodDefinition' && parent.key === node) {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Skip if 'document' is being assigned to (shadowing the global)
|
|
86
|
+
if ((parent === null || parent === void 0 ? void 0 : parent.type) === 'AssignmentExpression' && parent.left === node) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Skip if 'document' is in a destructuring pattern (could be destructuring from an object)
|
|
91
|
+
if ((parent === null || parent === void 0 ? void 0 : parent.type) === 'ObjectPattern' || (parent === null || parent === void 0 ? void 0 : parent.type) === 'ArrayPattern') {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
context.report({
|
|
95
|
+
node: node,
|
|
96
|
+
messageId: 'useGetDocument'
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
var _default = exports.default = rule;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = void 0;
|
|
7
|
+
var rule = {
|
|
8
|
+
meta: {
|
|
9
|
+
docs: {
|
|
10
|
+
description: "Prevent usage of setImmediate in favor of React Testing Library's `waitFor` or similar",
|
|
11
|
+
recommended: true
|
|
12
|
+
},
|
|
13
|
+
type: 'problem',
|
|
14
|
+
messages: {
|
|
15
|
+
noSetImmediate: "Avoid using setImmediate. Use React Testing Library's waitFor or similar instead for better test reliability.",
|
|
16
|
+
suggestWaitFor: 'Replace with waitFor from @testing-library/react or similar'
|
|
17
|
+
},
|
|
18
|
+
hasSuggestions: true
|
|
19
|
+
},
|
|
20
|
+
create: function create(context) {
|
|
21
|
+
return {
|
|
22
|
+
CallExpression: function CallExpression(node) {
|
|
23
|
+
if (node.callee.type === 'Identifier' && node.callee.name === 'setImmediate') {
|
|
24
|
+
context.report({
|
|
25
|
+
node: node,
|
|
26
|
+
messageId: 'noSetImmediate',
|
|
27
|
+
suggest: [{
|
|
28
|
+
messageId: 'suggestWaitFor',
|
|
29
|
+
fix: function fix(fixer) {
|
|
30
|
+
return fixer.replaceText(node, 'await waitFor(() => { /* your assertion here */ })');
|
|
31
|
+
}
|
|
32
|
+
}]
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
var _default = exports.default = rule;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = void 0;
|
|
7
|
+
// We will be removing sparse checkout from pipelines in CI completely due to the load it causes on BBC.
|
|
8
|
+
// We will be incrementally removing sparse-checkout from the files below as it is probably unnecessasry.
|
|
9
|
+
// If you must add an exception below, please go through the chopper process before doing so
|
|
10
|
+
var sparseCheckoutExceptions = ['bitbucket-pipelines/pipelines/custom/run-issue-automat.ts', 'bitbucket-pipelines/pipelines/custom/marketplace/utils.ts', 'bitbucket-pipelines/pipelines/custom/confluence/utils/index.ts', 'bitbucket-pipelines/pipelines/custom/afm-tools/upload-afm-dependency-graph-cache.ts', 'bitbucket-pipelines/pipelines/custom/afm-tools/default-afm-tools.ts', 'bitbucket-pipelines/pipelines/custom/marketplace/utils.ts', 'bitbucket-pipelines/pipelines/custom/afm-git-hooks.ts', 'bitbucket-pipelines/pipelines/custom/update-codeowners-and-teams-gen.ts', 'bitbucket-pipelines/pipelines/custom/run-issue-automat.ts'];
|
|
11
|
+
var rule = {
|
|
12
|
+
meta: {
|
|
13
|
+
docs: {
|
|
14
|
+
recommended: false
|
|
15
|
+
},
|
|
16
|
+
type: 'problem',
|
|
17
|
+
messages: {
|
|
18
|
+
noSparseCheckout: 'Sparse checkout is not allowed in pipeline configurations. Use git-alternates instead by setting sparseCheckout to false or add this file to exceptions.'
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
create: function create(context) {
|
|
22
|
+
var fileName = context.filename;
|
|
23
|
+
if (sparseCheckoutExceptions.some(function (exception) {
|
|
24
|
+
return fileName.endsWith(exception);
|
|
25
|
+
})) {
|
|
26
|
+
return {};
|
|
27
|
+
}
|
|
28
|
+
return {
|
|
29
|
+
// Look for calls to afmClone or objects that match AFMCloneConfig type
|
|
30
|
+
'CallExpression[callee.object.name=alias][callee.property.name=afmClone] ObjectExpression Property': function CallExpressionCalleeObjectNameAliasCalleePropertyNameAfmClone_ObjectExpression_Property(node) {
|
|
31
|
+
if (node.key.type === 'Identifier' && node.key.name === 'sparseCheckout') {
|
|
32
|
+
if (node.value.type === 'Literal' && node.value.value === true) {
|
|
33
|
+
context.report({
|
|
34
|
+
node: node,
|
|
35
|
+
messageId: 'noSparseCheckout'
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
var _default = exports.default = rule;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.skipForTestFiles = exports.skipForExampleFiles = void 0;
|
|
7
|
+
/**
|
|
8
|
+
* Common patterns for test files that should be excluded from rules
|
|
9
|
+
*/
|
|
10
|
+
var TEST_FILE_PATTERNS = ['__tests__', 'test', 'spec'];
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Checks if a file should be excluded from rules based on test file patterns
|
|
14
|
+
* @param filename The filename to check
|
|
15
|
+
* @returns true if the file should be excluded, false otherwise
|
|
16
|
+
*/
|
|
17
|
+
var isTestFile = function isTestFile(filename) {
|
|
18
|
+
return TEST_FILE_PATTERNS.some(function (pattern) {
|
|
19
|
+
return filename.includes(pattern);
|
|
20
|
+
});
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Helper function to skip rules for test files
|
|
25
|
+
* @param context The ESLint rule context
|
|
26
|
+
* @returns An empty RuleListener if the file is a test file, undefined otherwise
|
|
27
|
+
*/
|
|
28
|
+
var skipForTestFiles = exports.skipForTestFiles = function skipForTestFiles(context) {
|
|
29
|
+
if (isTestFile(context.filename)) {
|
|
30
|
+
return {};
|
|
31
|
+
}
|
|
32
|
+
return undefined;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Helper function to skip rules for example files
|
|
37
|
+
* @param context The ESLint rule context
|
|
38
|
+
* @returns An empty RuleListener if the file is an example file, undefined otherwise
|
|
39
|
+
*/
|
|
40
|
+
var skipForExampleFiles = exports.skipForExampleFiles = function skipForExampleFiles(context) {
|
|
41
|
+
if (context.filename.includes('example')) {
|
|
42
|
+
return {};
|
|
43
|
+
}
|
|
44
|
+
return undefined;
|
|
45
|
+
};
|
package/dist/es2019/index.js
CHANGED
|
@@ -27,6 +27,27 @@ import useEntrypointsInExamples from './rules/use-entrypoints-in-examples';
|
|
|
27
27
|
import useRecommendedUtils from './rules/feature-gating/use-recommended-utils';
|
|
28
28
|
import expandBackgroundShorthand from './rules/compiled/expand-background-shorthand';
|
|
29
29
|
import expandSpacingShorthand from './rules/compiled/expand-spacing-shorthand';
|
|
30
|
+
import noSparseCheckout from './rules/no-sparse-checkout';
|
|
31
|
+
import noDirectDocumentUsage from './rules/no-direct-document-usage';
|
|
32
|
+
import noSetImmediate from './rules/no-set-immediate';
|
|
33
|
+
import { join, normalize } from 'node:path';
|
|
34
|
+
import { readFileSync } from 'node:fs';
|
|
35
|
+
let jiraRoot;
|
|
36
|
+
try {
|
|
37
|
+
const findUp = require('find-up');
|
|
38
|
+
findUp.sync(dir => {
|
|
39
|
+
const productsJsonPath = join(dir, 'products.json');
|
|
40
|
+
if (findUp.sync.exists(productsJsonPath)) {
|
|
41
|
+
const productJson = JSON.parse(readFileSync(productsJsonPath, 'utf-8'));
|
|
42
|
+
if (productJson.Jira) {
|
|
43
|
+
jiraRoot = normalize(join(dir, productJson.Jira.path));
|
|
44
|
+
return findUp.stop;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
} catch {
|
|
49
|
+
// we aren't running inside of AFM, so we can ignore this.
|
|
50
|
+
}
|
|
30
51
|
const packageJson = require('@atlaskit/eslint-plugin-platform/package.json');
|
|
31
52
|
const rules = {
|
|
32
53
|
'ensure-feature-flag-registration': ensureFeatureFlagRegistration,
|
|
@@ -55,7 +76,10 @@ const rules = {
|
|
|
55
76
|
'prefer-fg': preferFG,
|
|
56
77
|
'no-alias': noAlias,
|
|
57
78
|
'use-entrypoints-in-examples': useEntrypointsInExamples,
|
|
58
|
-
'use-recommended-utils': useRecommendedUtils
|
|
79
|
+
'use-recommended-utils': useRecommendedUtils,
|
|
80
|
+
'no-sparse-checkout': noSparseCheckout,
|
|
81
|
+
'no-direct-document-usage': noDirectDocumentUsage,
|
|
82
|
+
'no-set-immediate': noSetImmediate
|
|
59
83
|
};
|
|
60
84
|
const commonConfig = {
|
|
61
85
|
'@atlaskit/platform/ensure-test-runner-arguments': 'error',
|
|
@@ -64,6 +88,8 @@ const commonConfig = {
|
|
|
64
88
|
'@atlaskit/platform/no-invalid-storybook-decorator-usage': 'error',
|
|
65
89
|
'@atlaskit/platform/ensure-atlassian-team': 'error',
|
|
66
90
|
'@atlaskit/platform/no-module-level-eval-nav4': 'error',
|
|
91
|
+
'@atlaskit/platform/no-direct-document-usage': 'warn',
|
|
92
|
+
'@atlaskit/platform/no-set-immediate': 'error',
|
|
67
93
|
// Compiled: rules that are not included via `@compiled/recommended
|
|
68
94
|
'@atlaskit/platform/expand-border-shorthand': 'error',
|
|
69
95
|
'@atlaskit/platform/expand-background-shorthand': 'error',
|
|
@@ -93,6 +119,7 @@ const recommendedRules = {
|
|
|
93
119
|
const jiraRules = commonConfig;
|
|
94
120
|
const jsonPrefix = '/* eslint-disable quote-props, comma-dangle, quotes, semi, eol-last, @typescript-eslint/semi, no-template-curly-in-string */ module.exports = ';
|
|
95
121
|
const jsonPrefixForFlatConfig = '/* eslint-disable quote-props, comma-dangle, quotes, semi, eol-last, no-template-curly-in-string */ module.exports = ';
|
|
122
|
+
const jsonPrefixForJira = 'module.exports = ';
|
|
96
123
|
const {
|
|
97
124
|
name,
|
|
98
125
|
version
|
|
@@ -141,7 +168,14 @@ const plugin = {
|
|
|
141
168
|
},
|
|
142
169
|
processors: {
|
|
143
170
|
'package-json-processor': {
|
|
144
|
-
preprocess: source => {
|
|
171
|
+
preprocess: (source, filename) => {
|
|
172
|
+
// we only need to check for jiraRoot because it uses a different
|
|
173
|
+
// ESLint version and produces fake errors due to how this processor handles JSON
|
|
174
|
+
if (jiraRoot && filename.startsWith(jiraRoot)) {
|
|
175
|
+
// augment the json into a js file
|
|
176
|
+
return [jsonPrefixForJira + source.trim()];
|
|
177
|
+
}
|
|
178
|
+
|
|
145
179
|
// augment the json into a js file
|
|
146
180
|
return [jsonPrefix + source.trim()];
|
|
147
181
|
},
|
|
@@ -168,7 +202,13 @@ const plugin = {
|
|
|
168
202
|
// This processor is used for ESLint FlatConfig,
|
|
169
203
|
// once we roll out FlatConfig, we can remove the above processor
|
|
170
204
|
'package-json-processor-for-flat-config': {
|
|
171
|
-
|
|
205
|
+
// we only need to check for jiraRoot because it uses a different
|
|
206
|
+
// ESLint version and produces fake errors due to how this processor handles JSON
|
|
207
|
+
preprocess: (source, filename) => {
|
|
208
|
+
if (jiraRoot && filename.startsWith(jiraRoot)) {
|
|
209
|
+
// augment the json into a js file
|
|
210
|
+
return [jsonPrefixForJira + source.trim()];
|
|
211
|
+
}
|
|
172
212
|
// augment the json into a js file
|
|
173
213
|
return [jsonPrefixForFlatConfig + source.trim()];
|
|
174
214
|
},
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import path from 'path';
|
|
2
2
|
import { getMetadataForFilename } from '../util/registration-utils';
|
|
3
3
|
const exportsValidationExceptions = {
|
|
4
|
+
'@af/yarn-workspace': {
|
|
5
|
+
ignoredAfExportKeys: ['./lock-parser']
|
|
6
|
+
},
|
|
4
7
|
'@atlaskit/tokens': {
|
|
5
8
|
ignoredAfExportKeys: ['./babel-plugin']
|
|
6
9
|
},
|
|
@@ -36,7 +36,7 @@ const rule = {
|
|
|
36
36
|
},
|
|
37
37
|
hasSuggestions: false,
|
|
38
38
|
messages: {
|
|
39
|
-
invalidWorkspaceProtocolUsage: `The 'workspace:^'
|
|
39
|
+
invalidWorkspaceProtocolUsage: `The 'workspace:^'protocol is Used. To resolve this error, please use the 'workspace:*' protocol instead.`,
|
|
40
40
|
invalidRootProtocolUsage: `The 'root:' protocol is not allowed in platform packages. To resolve this error, replace the 'root:' protocol with specific package versions (e.g. '^1.0.0').`
|
|
41
41
|
}
|
|
42
42
|
},
|
|
@@ -50,7 +50,7 @@ const rule = {
|
|
|
50
50
|
url: 'https://stash.atlassian.com/projects/ATLASSIAN/repos/atlassian-frontend-monorepo/browse/platform/packages/platform/eslint-plugin/src/rules/no-preconditioning/README.md'
|
|
51
51
|
},
|
|
52
52
|
messages: {
|
|
53
|
-
useConfig: 'Do not precondition gates or experiments with another gate. Configure this in Statsig instead to reduce unnecessary code and
|
|
53
|
+
useConfig: 'Do not precondition gates or experiments with another gate. Configure this in Statsig instead to reduce unnecessary code, simplify cleanup and to ensure accurate exposures in Statsig.',
|
|
54
54
|
incorrectExposure: 'Evaluate gates or experiments at the end of your logical expression to ensure exposure is tracked correctly.'
|
|
55
55
|
}
|
|
56
56
|
},
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { skipForExampleFiles, skipForTestFiles } from '../util/file-exclusions';
|
|
2
|
+
const rule = {
|
|
3
|
+
meta: {
|
|
4
|
+
type: 'problem',
|
|
5
|
+
docs: {
|
|
6
|
+
description: 'Enforce using getDocument from @atlaskit/browser-apis instead of direct document usage',
|
|
7
|
+
recommended: true
|
|
8
|
+
},
|
|
9
|
+
messages: {
|
|
10
|
+
useGetDocument: 'Use getDocument from @atlaskit/browser-apis instead of direct document usage'
|
|
11
|
+
},
|
|
12
|
+
schema: []
|
|
13
|
+
},
|
|
14
|
+
create(context) {
|
|
15
|
+
let hasGetDocumentImport = false;
|
|
16
|
+
const filename = context.filename;
|
|
17
|
+
|
|
18
|
+
// Skip test files
|
|
19
|
+
const skipResult = skipForTestFiles(context);
|
|
20
|
+
if (skipResult) {
|
|
21
|
+
return skipResult;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Skip example files
|
|
25
|
+
const skipResult2 = skipForExampleFiles(context);
|
|
26
|
+
if (skipResult2) {
|
|
27
|
+
return skipResult2;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Skip the getDocument.ts file itself
|
|
31
|
+
if (filename.endsWith('getDocument.ts')) {
|
|
32
|
+
return {};
|
|
33
|
+
}
|
|
34
|
+
return {
|
|
35
|
+
ImportDeclaration(node) {
|
|
36
|
+
if (node.source.value === '@atlaskit/browser-apis' && node.specifiers.some(specifier => specifier.type === 'ImportSpecifier' && specifier.imported.type === 'Identifier' && specifier.imported.name === 'getDocument')) {
|
|
37
|
+
hasGetDocumentImport = true;
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
Identifier(node) {
|
|
41
|
+
if (node.name === 'document' && !hasGetDocumentImport) {
|
|
42
|
+
const parent = node.parent;
|
|
43
|
+
|
|
44
|
+
// Skip if 'document' is used as a property key in an object literal
|
|
45
|
+
if ((parent === null || parent === void 0 ? void 0 : parent.type) === 'Property' && parent.key === node) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Skip if 'document' is used as a shorthand property value
|
|
50
|
+
if ((parent === null || parent === void 0 ? void 0 : parent.type) === 'Property' && parent.value === node && parent.shorthand) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Skip if 'document' is used as a property being accessed in a member expression
|
|
55
|
+
if ((parent === null || parent === void 0 ? void 0 : parent.type) === 'MemberExpression' && parent.property === node && !parent.computed) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Skip if 'document' is being declared as a variable
|
|
60
|
+
if ((parent === null || parent === void 0 ? void 0 : parent.type) === 'VariableDeclarator' && parent.id === node) {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Skip if 'document' is a function name
|
|
65
|
+
if ((parent === null || parent === void 0 ? void 0 : parent.type) === 'FunctionDeclaration' && 'id' in parent && parent.id === node) {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
if ((parent === null || parent === void 0 ? void 0 : parent.type) === 'FunctionExpression' && 'id' in parent && parent.id === node) {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Skip if 'document' is a method name in a class or object
|
|
73
|
+
if ((parent === null || parent === void 0 ? void 0 : parent.type) === 'MethodDefinition' && parent.key === node) {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Skip if 'document' is being assigned to (shadowing the global)
|
|
78
|
+
if ((parent === null || parent === void 0 ? void 0 : parent.type) === 'AssignmentExpression' && parent.left === node) {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Skip if 'document' is in a destructuring pattern (could be destructuring from an object)
|
|
83
|
+
if ((parent === null || parent === void 0 ? void 0 : parent.type) === 'ObjectPattern' || (parent === null || parent === void 0 ? void 0 : parent.type) === 'ArrayPattern') {
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
context.report({
|
|
87
|
+
node,
|
|
88
|
+
messageId: 'useGetDocument'
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
export default rule;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
const rule = {
|
|
2
|
+
meta: {
|
|
3
|
+
docs: {
|
|
4
|
+
description: "Prevent usage of setImmediate in favor of React Testing Library's `waitFor` or similar",
|
|
5
|
+
recommended: true
|
|
6
|
+
},
|
|
7
|
+
type: 'problem',
|
|
8
|
+
messages: {
|
|
9
|
+
noSetImmediate: "Avoid using setImmediate. Use React Testing Library's waitFor or similar instead for better test reliability.",
|
|
10
|
+
suggestWaitFor: 'Replace with waitFor from @testing-library/react or similar'
|
|
11
|
+
},
|
|
12
|
+
hasSuggestions: true
|
|
13
|
+
},
|
|
14
|
+
create(context) {
|
|
15
|
+
return {
|
|
16
|
+
CallExpression(node) {
|
|
17
|
+
if (node.callee.type === 'Identifier' && node.callee.name === 'setImmediate') {
|
|
18
|
+
context.report({
|
|
19
|
+
node,
|
|
20
|
+
messageId: 'noSetImmediate',
|
|
21
|
+
suggest: [{
|
|
22
|
+
messageId: 'suggestWaitFor',
|
|
23
|
+
fix(fixer) {
|
|
24
|
+
return fixer.replaceText(node, 'await waitFor(() => { /* your assertion here */ })');
|
|
25
|
+
}
|
|
26
|
+
}]
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
export default rule;
|