@atlaskit/eslint-plugin-platform 2.4.2 → 2.6.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 +18 -0
- package/afm-cc/tsconfig.json +1 -1
- package/dist/cjs/index.js +42 -3
- package/dist/cjs/rules/ensure-native-and-af-exports-synced/index.js +3 -0
- package/dist/cjs/rules/ensure-no-private-dependencies/index.js +101 -0
- package/dist/cjs/rules/ensure-valid-platform-yarn-protocol-usage/index.js +3 -15
- 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-sparse-checkout/index.js +43 -0
- package/dist/cjs/rules/util/file-exclusions.js +45 -0
- package/dist/es2019/index.js +42 -3
- package/dist/es2019/rules/ensure-native-and-af-exports-synced/index.js +3 -0
- package/dist/es2019/rules/ensure-no-private-dependencies/index.js +63 -0
- package/dist/es2019/rules/ensure-valid-platform-yarn-protocol-usage/index.js +4 -16
- 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-sparse-checkout/index.js +35 -0
- package/dist/es2019/rules/util/file-exclusions.js +37 -0
- package/dist/esm/index.js +42 -3
- package/dist/esm/rules/ensure-native-and-af-exports-synced/index.js +3 -0
- package/dist/esm/rules/ensure-no-private-dependencies/index.js +96 -0
- package/dist/esm/rules/ensure-valid-platform-yarn-protocol-usage/index.js +4 -16
- 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-sparse-checkout/index.js +37 -0
- package/dist/esm/rules/util/file-exclusions.js +39 -0
- package/dist/types/index.d.ts +14 -0
- package/dist/types/rules/ensure-no-private-dependencies/index.d.ts +3 -0
- package/dist/types/rules/no-direct-document-usage/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 +14 -0
- package/dist/types-ts4.5/rules/ensure-no-private-dependencies/index.d.ts +3 -0
- package/dist/types-ts4.5/rules/no-direct-document-usage/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 +12 -2
- package/src/index.tsx +46 -2
- package/src/rules/ensure-native-and-af-exports-synced/index.tsx +3 -0
- package/src/rules/ensure-no-private-dependencies/__tests__/unit/rule.test.ts +212 -0
- package/src/rules/ensure-no-private-dependencies/index.ts +64 -0
- package/src/rules/ensure-valid-bin-values/__tests__/unit/rule.test.ts +3 -2
- package/src/rules/ensure-valid-platform-yarn-protocol-usage/__tests__/unit/rule.test.ts +57 -109
- package/src/rules/ensure-valid-platform-yarn-protocol-usage/index.ts +4 -16
- package/src/rules/feature-gating/no-preconditioning/index.tsx +1 -1
- package/src/rules/no-direct-document-usage/index.tsx +109 -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
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import type { Rule } from 'eslint';
|
|
2
|
+
import { skipForExampleFiles, skipForTestFiles } from '../util/file-exclusions';
|
|
3
|
+
|
|
4
|
+
const rule: Rule.RuleModule = {
|
|
5
|
+
meta: {
|
|
6
|
+
type: 'problem',
|
|
7
|
+
docs: {
|
|
8
|
+
description:
|
|
9
|
+
'Enforce using getDocument from @atlaskit/browser-apis instead of direct document usage',
|
|
10
|
+
recommended: true,
|
|
11
|
+
},
|
|
12
|
+
messages: {
|
|
13
|
+
useGetDocument:
|
|
14
|
+
'Use getDocument from @atlaskit/browser-apis instead of direct document usage',
|
|
15
|
+
},
|
|
16
|
+
schema: [],
|
|
17
|
+
},
|
|
18
|
+
create(context) {
|
|
19
|
+
let hasGetDocumentImport = false;
|
|
20
|
+
const filename = context.filename;
|
|
21
|
+
|
|
22
|
+
// Skip test files
|
|
23
|
+
const skipResult = skipForTestFiles(context);
|
|
24
|
+
if (skipResult) {
|
|
25
|
+
return skipResult;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Skip example files
|
|
29
|
+
const skipResult2 = skipForExampleFiles(context);
|
|
30
|
+
if (skipResult2) {
|
|
31
|
+
return skipResult2;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Skip the getDocument.ts file itself
|
|
35
|
+
if (filename.endsWith('getDocument.ts')) {
|
|
36
|
+
return {};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return {
|
|
40
|
+
ImportDeclaration(node) {
|
|
41
|
+
if (
|
|
42
|
+
node.source.value === '@atlaskit/browser-apis' &&
|
|
43
|
+
node.specifiers.some(
|
|
44
|
+
(specifier) =>
|
|
45
|
+
specifier.type === 'ImportSpecifier' && specifier.imported.name === 'getDocument',
|
|
46
|
+
)
|
|
47
|
+
) {
|
|
48
|
+
hasGetDocumentImport = true;
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
Identifier(node) {
|
|
52
|
+
if (node.name === 'document' && !hasGetDocumentImport) {
|
|
53
|
+
const parent = node.parent;
|
|
54
|
+
|
|
55
|
+
// Skip if 'document' is used as a property key in an object literal
|
|
56
|
+
if (parent?.type === 'Property' && parent.key === node) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Skip if 'document' is used as a shorthand property value
|
|
61
|
+
if (parent?.type === 'Property' && parent.value === node && parent.shorthand) {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Skip if 'document' is used as a property being accessed in a member expression
|
|
66
|
+
if (parent?.type === 'MemberExpression' && parent.property === node && !parent.computed) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Skip if 'document' is being declared as a variable
|
|
71
|
+
if (parent?.type === 'VariableDeclarator' && parent.id === node) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Skip if 'document' is a function name
|
|
76
|
+
if (parent?.type === 'FunctionDeclaration' && 'id' in parent && parent.id === node) {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (parent?.type === 'FunctionExpression' && 'id' in parent && parent.id === node) {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Skip if 'document' is a method name in a class or object
|
|
85
|
+
if (parent?.type === 'MethodDefinition' && parent.key === node) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Skip if 'document' is being assigned to (shadowing the global)
|
|
90
|
+
if (parent?.type === 'AssignmentExpression' && parent.left === node) {
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Skip if 'document' is in a destructuring pattern (could be destructuring from an object)
|
|
95
|
+
if (parent?.type === 'ObjectPattern' || parent?.type === 'ArrayPattern') {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
context.report({
|
|
100
|
+
node,
|
|
101
|
+
messageId: 'useGetDocument',
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
};
|
|
106
|
+
},
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
export default rule;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { tester } from '../../../../__tests__/utils/_tester';
|
|
2
|
+
import rule from '../../index';
|
|
3
|
+
|
|
4
|
+
describe('test no-sparse-checkout rule', () => {
|
|
5
|
+
tester.run('no-sparse-checkout', rule, {
|
|
6
|
+
valid: [
|
|
7
|
+
{
|
|
8
|
+
code: `
|
|
9
|
+
const config = {
|
|
10
|
+
clone: alias.afmClone({ sparseCheckout: false })
|
|
11
|
+
};
|
|
12
|
+
`,
|
|
13
|
+
filename: 'hello/foo.ts',
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
code: `
|
|
17
|
+
const config = {
|
|
18
|
+
clone: alias.afmClone({ cloneDepth: 1})
|
|
19
|
+
};
|
|
20
|
+
`,
|
|
21
|
+
filename: 'hello/foo.ts',
|
|
22
|
+
},
|
|
23
|
+
],
|
|
24
|
+
invalid: [
|
|
25
|
+
{
|
|
26
|
+
code: `
|
|
27
|
+
const config = {
|
|
28
|
+
clone: alias.afmClone({ sparseCheckout: true })
|
|
29
|
+
};
|
|
30
|
+
`,
|
|
31
|
+
filename: 'hello/foo.ts',
|
|
32
|
+
errors: [{ messageId: 'noSparseCheckout' }],
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
code: `
|
|
36
|
+
const config = {
|
|
37
|
+
clone: alias.afmClone({
|
|
38
|
+
cloneDepth: 'full',
|
|
39
|
+
sparseCheckout: true
|
|
40
|
+
})
|
|
41
|
+
};
|
|
42
|
+
`,
|
|
43
|
+
filename: 'hello/foo.ts',
|
|
44
|
+
errors: [{ messageId: 'noSparseCheckout' }],
|
|
45
|
+
},
|
|
46
|
+
],
|
|
47
|
+
});
|
|
48
|
+
});
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { Rule } from 'eslint';
|
|
2
|
+
import type { Property } from 'estree';
|
|
3
|
+
|
|
4
|
+
// We will be removing sparse checkout from pipelines in CI completely due to the load it causes on BBC.
|
|
5
|
+
// We will be incrementally removing sparse-checkout from the files below as it is probably unnecessasry.
|
|
6
|
+
// If you must add an exception below, please go through the chopper process before doing so
|
|
7
|
+
const sparseCheckoutExceptions = [
|
|
8
|
+
'bitbucket-pipelines/pipelines/custom/run-issue-automat.ts',
|
|
9
|
+
'bitbucket-pipelines/pipelines/custom/marketplace/utils.ts',
|
|
10
|
+
'bitbucket-pipelines/pipelines/custom/confluence/utils/index.ts',
|
|
11
|
+
'bitbucket-pipelines/pipelines/custom/afm-tools/upload-afm-dependency-graph-cache.ts',
|
|
12
|
+
'bitbucket-pipelines/pipelines/custom/afm-tools/default-afm-tools.ts',
|
|
13
|
+
'bitbucket-pipelines/pipelines/custom/marketplace/utils.ts',
|
|
14
|
+
'bitbucket-pipelines/pipelines/custom/afm-git-hooks.ts',
|
|
15
|
+
'bitbucket-pipelines/pipelines/custom/update-codeowners-and-teams-gen.ts',
|
|
16
|
+
'bitbucket-pipelines/pipelines/custom/run-issue-automat.ts',
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
const rule: Rule.RuleModule = {
|
|
20
|
+
meta: {
|
|
21
|
+
docs: {
|
|
22
|
+
recommended: false,
|
|
23
|
+
},
|
|
24
|
+
type: 'problem',
|
|
25
|
+
messages: {
|
|
26
|
+
noSparseCheckout:
|
|
27
|
+
'Sparse checkout is not allowed in pipeline configurations. Use git-alternates instead by setting sparseCheckout to false or add this file to exceptions.',
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
|
|
31
|
+
create(context) {
|
|
32
|
+
const fileName = context.filename;
|
|
33
|
+
if (sparseCheckoutExceptions.some((exception) => fileName.endsWith(exception))) {
|
|
34
|
+
return {};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return {
|
|
38
|
+
// Look for calls to afmClone or objects that match AFMCloneConfig type
|
|
39
|
+
'CallExpression[callee.object.name=alias][callee.property.name=afmClone] ObjectExpression Property':
|
|
40
|
+
(node: Property) => {
|
|
41
|
+
if (node.key.type === 'Identifier' && node.key.name === 'sparseCheckout') {
|
|
42
|
+
if (node.value.type === 'Literal' && node.value.value === true) {
|
|
43
|
+
context.report({
|
|
44
|
+
node,
|
|
45
|
+
messageId: 'noSparseCheckout',
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export default rule;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { Rule } from 'eslint';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Common patterns for test files that should be excluded from rules
|
|
5
|
+
*/
|
|
6
|
+
const TEST_FILE_PATTERNS = ['__tests__', 'test', 'spec'] as const;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Checks if a file should be excluded from rules based on test file patterns
|
|
10
|
+
* @param filename The filename to check
|
|
11
|
+
* @returns true if the file should be excluded, false otherwise
|
|
12
|
+
*/
|
|
13
|
+
const isTestFile = (filename: string): boolean => {
|
|
14
|
+
return TEST_FILE_PATTERNS.some((pattern) => filename.includes(pattern));
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Helper function to skip rules for test files
|
|
19
|
+
* @param context The ESLint rule context
|
|
20
|
+
* @returns An empty RuleListener if the file is a test file, undefined otherwise
|
|
21
|
+
*/
|
|
22
|
+
export const skipForTestFiles = (context: Rule.RuleContext): Rule.RuleListener | undefined => {
|
|
23
|
+
if (isTestFile(context.filename)) {
|
|
24
|
+
return {};
|
|
25
|
+
}
|
|
26
|
+
return undefined;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Helper function to skip rules for example files
|
|
31
|
+
* @param context The ESLint rule context
|
|
32
|
+
* @returns An empty RuleListener if the file is an example file, undefined otherwise
|
|
33
|
+
*/
|
|
34
|
+
export const skipForExampleFiles = (context: Rule.RuleContext): Rule.RuleListener | undefined => {
|
|
35
|
+
if (context.filename.includes('example')) {
|
|
36
|
+
return {};
|
|
37
|
+
}
|
|
38
|
+
return undefined;
|
|
39
|
+
};
|