@atlaskit/eslint-plugin-platform 2.6.0 → 2.7.1
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 +15 -0
- package/dist/cjs/index.js +4 -3
- package/dist/cjs/rules/ensure-critical-dependency-resolutions/index.js +2 -2
- package/dist/cjs/rules/ensure-native-and-af-exports-synced/index.js +3 -0
- package/dist/cjs/rules/feature-gating/no-alias/index.js +1 -1
- package/dist/cjs/rules/no-direct-document-usage/index.js +1 -1
- package/dist/cjs/rules/no-set-immediate/index.js +39 -0
- package/dist/cjs/rules/util/context-compat.js +4 -2
- package/dist/es2019/index.js +4 -3
- package/dist/es2019/rules/ensure-critical-dependency-resolutions/index.js +2 -2
- package/dist/es2019/rules/ensure-native-and-af-exports-synced/index.js +3 -0
- package/dist/es2019/rules/feature-gating/no-alias/index.js +1 -1
- package/dist/es2019/rules/no-direct-document-usage/index.js +1 -1
- package/dist/es2019/rules/no-set-immediate/index.js +33 -0
- package/dist/es2019/rules/util/context-compat.js +4 -2
- package/dist/esm/index.js +4 -3
- package/dist/esm/rules/ensure-critical-dependency-resolutions/index.js +2 -2
- package/dist/esm/rules/ensure-native-and-af-exports-synced/index.js +3 -0
- package/dist/esm/rules/feature-gating/no-alias/index.js +1 -1
- package/dist/esm/rules/no-direct-document-usage/index.js +1 -1
- package/dist/esm/rules/no-set-immediate/index.js +33 -0
- package/dist/esm/rules/util/context-compat.js +4 -2
- package/dist/types/index.d.ts +14 -6
- package/dist/types/rules/util/handle-ast-object.d.ts +1 -1
- package/dist/types-ts4.5/index.d.ts +14 -6
- package/dist/types-ts4.5/rules/util/handle-ast-object.d.ts +1 -1
- package/package.json +2 -2
- package/afm-cc/tsconfig.json +0 -24
- package/afm-jira/tsconfig.json +0 -24
- package/build/tsconfig.json +0 -17
- package/dist/cjs/rules/ensure-valid-platform-yarn-protocol-usage/index.js +0 -79
- package/dist/es2019/rules/ensure-valid-platform-yarn-protocol-usage/index.js +0 -62
- package/dist/esm/rules/ensure-valid-platform-yarn-protocol-usage/index.js +0 -75
- package/src/__tests__/utils/_tester.tsx +0 -26
- package/src/index.tsx +0 -251
- package/src/rules/compiled/README.md +0 -3
- package/src/rules/compiled/expand-background-shorthand/README.md +0 -23
- package/src/rules/compiled/expand-background-shorthand/__tests__/rule.test.ts +0 -160
- package/src/rules/compiled/expand-background-shorthand/index.tsx +0 -43
- package/src/rules/compiled/expand-border-shorthand/README.md +0 -51
- package/src/rules/compiled/expand-border-shorthand/__tests__/rule.test.ts +0 -211
- package/src/rules/compiled/expand-border-shorthand/index.ts +0 -103
- package/src/rules/compiled/expand-spacing-shorthand/README.md +0 -38
- package/src/rules/compiled/expand-spacing-shorthand/__tests__/rule.test.ts +0 -448
- package/src/rules/compiled/expand-spacing-shorthand/index.ts +0 -240
- package/src/rules/constants.tsx +0 -20
- package/src/rules/ensure-atlassian-team/__tests__/unit/rule.test.ts +0 -24
- package/src/rules/ensure-atlassian-team/index.ts +0 -51
- package/src/rules/ensure-critical-dependency-resolutions/__test__/unit/rule.test.tsx +0 -200
- package/src/rules/ensure-critical-dependency-resolutions/index.tsx +0 -172
- package/src/rules/ensure-feature-flag-prefix/__tests__/unit/rule.test.tsx +0 -65
- package/src/rules/ensure-feature-flag-prefix/index.tsx +0 -81
- package/src/rules/ensure-feature-flag-registration/__tests__/unit/rule.test.tsx +0 -115
- package/src/rules/ensure-feature-flag-registration/index.tsx +0 -106
- package/src/rules/ensure-native-and-af-exports-synced/__tests__/unit/rule.test.tsx +0 -199
- package/src/rules/ensure-native-and-af-exports-synced/index.tsx +0 -188
- package/src/rules/ensure-no-private-dependencies/__tests__/unit/rule.test.ts +0 -212
- package/src/rules/ensure-no-private-dependencies/index.ts +0 -64
- package/src/rules/ensure-publish-valid/__tests__/unit/rule.test.ts +0 -39
- package/src/rules/ensure-publish-valid/index.ts +0 -81
- package/src/rules/ensure-test-runner-arguments/__tests__/unit/rule.test.tsx +0 -298
- package/src/rules/ensure-test-runner-arguments/index.tsx +0 -121
- package/src/rules/ensure-test-runner-nested-count/__tests__/unit/rule.test.tsx +0 -308
- package/src/rules/ensure-test-runner-nested-count/index.tsx +0 -82
- package/src/rules/ensure-valid-bin-values/__tests__/unit/rule.test.ts +0 -159
- package/src/rules/ensure-valid-bin-values/index.ts +0 -70
- package/src/rules/ensure-valid-platform-yarn-protocol-usage/__tests__/unit/rule.test.ts +0 -147
- package/src/rules/ensure-valid-platform-yarn-protocol-usage/index.ts +0 -67
- package/src/rules/feature-gating/README.md +0 -8
- package/src/rules/feature-gating/inline-usage/README.md +0 -53
- package/src/rules/feature-gating/inline-usage/__tests__/rule.test.tsx +0 -106
- package/src/rules/feature-gating/inline-usage/index.tsx +0 -135
- package/src/rules/feature-gating/no-alias/README.md +0 -29
- package/src/rules/feature-gating/no-alias/__tests__/rule.test.tsx +0 -76
- package/src/rules/feature-gating/no-alias/index.tsx +0 -80
- package/src/rules/feature-gating/no-module-level-eval/README.md +0 -53
- package/src/rules/feature-gating/no-module-level-eval/__tests__/test.tsx +0 -133
- package/src/rules/feature-gating/no-module-level-eval/index.tsx +0 -54
- package/src/rules/feature-gating/no-module-level-eval-nav4/README.md +0 -8
- package/src/rules/feature-gating/no-module-level-eval-nav4/__tests__/test.tsx +0 -130
- package/src/rules/feature-gating/no-module-level-eval-nav4/index.tsx +0 -73
- package/src/rules/feature-gating/no-preconditioning/README.md +0 -69
- package/src/rules/feature-gating/no-preconditioning/__tests__/rule.test.tsx +0 -164
- package/src/rules/feature-gating/no-preconditioning/index.tsx +0 -138
- package/src/rules/feature-gating/prefer-fg/README.md +0 -3
- package/src/rules/feature-gating/prefer-fg/__tests__/rule.test.tsx +0 -83
- package/src/rules/feature-gating/prefer-fg/index.tsx +0 -110
- package/src/rules/feature-gating/static-feature-flags/README.md +0 -3
- package/src/rules/feature-gating/static-feature-flags/__tests__/test.tsx +0 -135
- package/src/rules/feature-gating/static-feature-flags/index.tsx +0 -103
- package/src/rules/feature-gating/use-recommended-utils/README.md +0 -67
- package/src/rules/feature-gating/use-recommended-utils/__tests__/rule.test.tsx +0 -78
- package/src/rules/feature-gating/use-recommended-utils/index.tsx +0 -57
- package/src/rules/feature-gating/utils.tsx +0 -48
- package/src/rules/no-direct-document-usage/index.tsx +0 -109
- package/src/rules/no-duplicate-dependencies/__tests__/unit/rule.test.ts +0 -116
- package/src/rules/no-duplicate-dependencies/index.ts +0 -79
- package/src/rules/no-invalid-feature-flag-usage/__tests__/unit/rule.test.tsx +0 -69
- package/src/rules/no-invalid-feature-flag-usage/index.tsx +0 -128
- package/src/rules/no-invalid-storybook-decorator-usage/__tests__/unit/rule.test.tsx +0 -18
- package/src/rules/no-invalid-storybook-decorator-usage/index.tsx +0 -39
- package/src/rules/no-pre-post-installs/__tests__/unit/rule.test.ts +0 -41
- package/src/rules/no-pre-post-installs/index.ts +0 -35
- package/src/rules/no-sparse-checkout/__tests__/unit/rule.test.tsx +0 -48
- package/src/rules/no-sparse-checkout/index.tsx +0 -54
- package/src/rules/use-entrypoints-in-examples/README.md +0 -27
- package/src/rules/use-entrypoints-in-examples/__tests__/rule.test.tsx +0 -34
- package/src/rules/use-entrypoints-in-examples/index.tsx +0 -43
- package/src/rules/util/__tests__/context-compat.test.ts +0 -122
- package/src/rules/util/compiled-utils.ts +0 -27
- package/src/rules/util/context-compat.ts +0 -41
- package/src/rules/util/file-exclusions.ts +0 -39
- package/src/rules/util/handle-ast-object.ts +0 -33
- package/src/rules/util/registration-utils.ts +0 -59
- package/tsconfig.app.json +0 -43
- package/tsconfig.dev.json +0 -40
- package/tsconfig.json +0 -23
- /package/dist/types/rules/{ensure-valid-platform-yarn-protocol-usage → no-set-immediate}/index.d.ts +0 -0
- /package/dist/types-ts4.5/rules/{ensure-valid-platform-yarn-protocol-usage → no-set-immediate}/index.d.ts +0 -0
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
import type { Rule } from 'eslint';
|
|
2
|
-
import { FEATURE_API_IMPORT_SOURCES } from '../../constants';
|
|
3
|
-
import { getDef, isIdentifierImportedFrom, type Node } from '../utils';
|
|
4
|
-
|
|
5
|
-
const IMPORT_SOURCES = new Set([
|
|
6
|
-
...FEATURE_API_IMPORT_SOURCES,
|
|
7
|
-
'@atlassian/jira-feature-flagging-utils',
|
|
8
|
-
'@atlassian/jira-feature-gate-component',
|
|
9
|
-
'@atlassian/jira-feature-gates-test-mocks',
|
|
10
|
-
'@atlassian/jira-feature-gates-storybook-mocks',
|
|
11
|
-
]);
|
|
12
|
-
|
|
13
|
-
// Any functions not in this list should be skipped for performance.
|
|
14
|
-
const FUNCTION_NAMES = new Set([
|
|
15
|
-
'ff',
|
|
16
|
-
'fg',
|
|
17
|
-
'getFeatureFlagValue',
|
|
18
|
-
'getMultivariateFeatureFlag',
|
|
19
|
-
'componentWithFF',
|
|
20
|
-
'componentWithFG',
|
|
21
|
-
'passGate',
|
|
22
|
-
'withGate',
|
|
23
|
-
'expVal',
|
|
24
|
-
'expValEquals',
|
|
25
|
-
'UNSAFE_noExposureExp',
|
|
26
|
-
'mockExp',
|
|
27
|
-
'withExp',
|
|
28
|
-
'wasExperimentManuallyExposed',
|
|
29
|
-
]);
|
|
30
|
-
|
|
31
|
-
const STATSIG_ONLY_FUNCTION_NAMES = new Set([
|
|
32
|
-
'fg',
|
|
33
|
-
'componentWithFG',
|
|
34
|
-
'passGate',
|
|
35
|
-
'withGate',
|
|
36
|
-
'expVal',
|
|
37
|
-
'expValEquals',
|
|
38
|
-
'UNSAFE_noExposureExp',
|
|
39
|
-
'mockExp',
|
|
40
|
-
'withExp',
|
|
41
|
-
'wasExperimentManuallyExposed',
|
|
42
|
-
]);
|
|
43
|
-
|
|
44
|
-
const rule: Rule.RuleModule = {
|
|
45
|
-
meta: {
|
|
46
|
-
type: 'problem',
|
|
47
|
-
docs: {
|
|
48
|
-
url: 'https://stash.atlassian.com/projects/ATLASSIAN/repos/atlassian-frontend-monorepo/browse/platform/packages/platform/eslint-plugin/src/rules/static-feature-flags/README.md',
|
|
49
|
-
description: 'Ensure feature flags or gates are static string literals',
|
|
50
|
-
},
|
|
51
|
-
fixable: 'code',
|
|
52
|
-
messages: {
|
|
53
|
-
FFLiteral:
|
|
54
|
-
'Use static string literal for `featureFlagName`. See https://team.atlassian.com/project/ATLAS-46997/about',
|
|
55
|
-
},
|
|
56
|
-
},
|
|
57
|
-
create(context) {
|
|
58
|
-
const targetedFunctionsSwitch =
|
|
59
|
-
context.options[0] === 'ssOnly' ? STATSIG_ONLY_FUNCTION_NAMES : FUNCTION_NAMES;
|
|
60
|
-
|
|
61
|
-
return {
|
|
62
|
-
// When they're not literals, show a message
|
|
63
|
-
'CallExpression[callee.type="Identifier"][arguments.length>0][arguments.0.type!="Literal"]': (
|
|
64
|
-
node: Node<any>,
|
|
65
|
-
) => {
|
|
66
|
-
if (node.type !== 'CallExpression') {
|
|
67
|
-
return;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
if (
|
|
71
|
-
node.callee.type === 'Identifier' &&
|
|
72
|
-
(!targetedFunctionsSwitch.has(node.callee.name) ||
|
|
73
|
-
!isIdentifierImportedFrom(node.callee.name, IMPORT_SOURCES, context, node))
|
|
74
|
-
) {
|
|
75
|
-
return;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
const nameArgument = node.arguments[0];
|
|
79
|
-
if (nameArgument.type === 'Identifier') {
|
|
80
|
-
const def = getDef(nameArgument.name, context, node);
|
|
81
|
-
if (def != null && def.type === 'Variable') {
|
|
82
|
-
const { value } = def.node.init as any;
|
|
83
|
-
|
|
84
|
-
context.report({
|
|
85
|
-
node: nameArgument,
|
|
86
|
-
messageId: 'FFLiteral',
|
|
87
|
-
fix: (fixer) => fixer.replaceText(nameArgument, `'${value}'`),
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
return;
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
context.report({
|
|
95
|
-
node: nameArgument,
|
|
96
|
-
messageId: 'FFLiteral',
|
|
97
|
-
});
|
|
98
|
-
},
|
|
99
|
-
};
|
|
100
|
-
},
|
|
101
|
-
};
|
|
102
|
-
|
|
103
|
-
export default rule;
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
# Use `fg` instead of `FeatureGates.checkGate` (feature-flags/use-recommended-utils)
|
|
2
|
-
|
|
3
|
-
`fg` method is recommended over `FeatureGates.checkGate`. The former is a wrapper to
|
|
4
|
-
`FeatureGates.checkGate` with unit testing mocking capabilities.
|
|
5
|
-
|
|
6
|
-
## Examples
|
|
7
|
-
|
|
8
|
-
### Feature Gates
|
|
9
|
-
|
|
10
|
-
👎 Examples of **incorrect** code for this rule: Gate is accessed with `FeatureGates.checkGate`
|
|
11
|
-
|
|
12
|
-
```tsx
|
|
13
|
-
import FeatureGates from '@atlaskit/feature-gate-js-client';
|
|
14
|
-
|
|
15
|
-
export const getThing = () => {
|
|
16
|
-
if (FeatureGates.checkGate('my_gate')) {
|
|
17
|
-
return getNewThing();
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
return getOldThing();
|
|
21
|
-
};
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
👍 Examples of **correct** code for this rule: Gate is accessed with `fg`
|
|
25
|
-
|
|
26
|
-
```tsx
|
|
27
|
-
import { fg } from '@atlassian/jira-feature-gating';
|
|
28
|
-
|
|
29
|
-
export const getThing = () => {
|
|
30
|
-
if (fg('my_gate')) {
|
|
31
|
-
return getNewThing();
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
return getOldThing();
|
|
35
|
-
};
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
### Experiments
|
|
39
|
-
|
|
40
|
-
👎 Examples of **incorrect** code for this rule: experiment is accessed with
|
|
41
|
-
`FeatureGates.getExperimentValue`
|
|
42
|
-
|
|
43
|
-
```tsx
|
|
44
|
-
import FeatureGates from '@atlaskit/feature-gate-js-client';
|
|
45
|
-
|
|
46
|
-
export const getThing = () => {
|
|
47
|
-
if (FeatureGates.getExperimentValue('my_experiment', 'is_enabled', false)) {
|
|
48
|
-
return newThing();
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
return oldThing();
|
|
52
|
-
};
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
👍 Examples of **correct** code for this rule: experiment is accessed with `expVal`
|
|
56
|
-
|
|
57
|
-
```tsx
|
|
58
|
-
import { expVal } from '@atlassian/jira-feature-experiments';
|
|
59
|
-
|
|
60
|
-
export const getThing = () => {
|
|
61
|
-
if (expVal('my_experiment', 'is_enabled', false)) {
|
|
62
|
-
return newThing();
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
return oldThing();
|
|
66
|
-
};
|
|
67
|
-
```
|
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
import outdent from 'outdent';
|
|
2
|
-
import { tester } from '../../../../__tests__/utils/_tester';
|
|
3
|
-
import rule from '../index';
|
|
4
|
-
|
|
5
|
-
tester.run('feature-flags/use-recommended-utils', rule, {
|
|
6
|
-
valid: [
|
|
7
|
-
{
|
|
8
|
-
name: 'Other `FeatureGate` methods are allowed',
|
|
9
|
-
code: outdent`
|
|
10
|
-
import FeatureGates from '@atlaskit/feature-gate-js-client';
|
|
11
|
-
|
|
12
|
-
FeatureGates.initialize();
|
|
13
|
-
`,
|
|
14
|
-
},
|
|
15
|
-
{
|
|
16
|
-
name: 'Use `fg` to access gates',
|
|
17
|
-
code: outdent`
|
|
18
|
-
import { fg } from '@atlassian/jira-feature-gating';
|
|
19
|
-
|
|
20
|
-
export const Component = () => {
|
|
21
|
-
return fg('my_gate') ? <HelloWorld /> : null;
|
|
22
|
-
};
|
|
23
|
-
`,
|
|
24
|
-
},
|
|
25
|
-
{
|
|
26
|
-
name: 'Use `expVal` to access experiments',
|
|
27
|
-
code: outdent`
|
|
28
|
-
import { expVal } from '@atlassian/jira-feature-experiments';
|
|
29
|
-
|
|
30
|
-
export const getThing = () => {
|
|
31
|
-
if (expVal('my_experiment', 'is_enabled', false)) {
|
|
32
|
-
return newThing();
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
return oldThing();
|
|
36
|
-
};
|
|
37
|
-
`,
|
|
38
|
-
},
|
|
39
|
-
],
|
|
40
|
-
invalid: [
|
|
41
|
-
{
|
|
42
|
-
name: '`checkGate` is not allowed',
|
|
43
|
-
code: outdent`
|
|
44
|
-
import FeatureGates from '@atlaskit/feature-gate-js-client';
|
|
45
|
-
|
|
46
|
-
export const Component = () => {
|
|
47
|
-
return FeatureGates.checkGate('my_gate') ? <HelloWorld /> : null;
|
|
48
|
-
};
|
|
49
|
-
`,
|
|
50
|
-
errors: [
|
|
51
|
-
{
|
|
52
|
-
message:
|
|
53
|
-
'Please do not use FeatureGates.checkGate, use `fg` from `@atlaskit/platform-feature-flags` instead.',
|
|
54
|
-
},
|
|
55
|
-
],
|
|
56
|
-
},
|
|
57
|
-
{
|
|
58
|
-
name: '`getExperimentValue` is not allowed',
|
|
59
|
-
code: outdent`
|
|
60
|
-
import FeatureGates from '@atlaskit/feature-gate-js-client';
|
|
61
|
-
|
|
62
|
-
export const getThing = () => {
|
|
63
|
-
if (FeatureGates.getExperimentValue('my_experiment', 'is_enabled', false)) {
|
|
64
|
-
return newThing();
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
return oldThing();
|
|
68
|
-
};
|
|
69
|
-
`,
|
|
70
|
-
errors: [
|
|
71
|
-
{
|
|
72
|
-
message:
|
|
73
|
-
'Experimentation is not suported in platform feature flags, reach out to #help-statsig-switcheroo.',
|
|
74
|
-
},
|
|
75
|
-
],
|
|
76
|
-
},
|
|
77
|
-
],
|
|
78
|
-
});
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import type { Rule } from 'eslint';
|
|
2
|
-
import { isIdentifierImportedFrom, type Node } from '../utils';
|
|
3
|
-
|
|
4
|
-
const BANNED_IMPORTS_SET = new Set(['@atlaskit/feature-gate-js-client']);
|
|
5
|
-
|
|
6
|
-
const rule: Rule.RuleModule = {
|
|
7
|
-
meta: {
|
|
8
|
-
docs: {
|
|
9
|
-
url: 'https://stash.atlassian.com/projects/ATLASSIAN/repos/atlassian-frontend-monorepo/browse/platform/packages/platform/eslint-plugin/src/rules/use-recommended-utils/README.md',
|
|
10
|
-
description: 'Prefer using the feature flag abstraction over direct statsig library.',
|
|
11
|
-
},
|
|
12
|
-
messages: {
|
|
13
|
-
notSupported:
|
|
14
|
-
'Experimentation is not suported in platform feature flags, reach out to #help-statsig-switcheroo.',
|
|
15
|
-
useRecommended:
|
|
16
|
-
'Please do not use FeatureGates.{{util}}, use {{recommended}} from {{lib}} instead.',
|
|
17
|
-
},
|
|
18
|
-
type: 'problem',
|
|
19
|
-
},
|
|
20
|
-
create(context) {
|
|
21
|
-
return {
|
|
22
|
-
'CallExpression > MemberExpression:matches([property.name="checkGate"])': (
|
|
23
|
-
node: Node<'MemberExpression'>,
|
|
24
|
-
) => {
|
|
25
|
-
if (
|
|
26
|
-
node.object.type === 'Identifier' &&
|
|
27
|
-
isIdentifierImportedFrom(node.object.name, BANNED_IMPORTS_SET, context, node)
|
|
28
|
-
) {
|
|
29
|
-
context.report({
|
|
30
|
-
messageId: 'useRecommended',
|
|
31
|
-
node,
|
|
32
|
-
data: {
|
|
33
|
-
lib: '`@atlaskit/platform-feature-flags`',
|
|
34
|
-
util: (node.property as any).name,
|
|
35
|
-
recommended: '`fg`',
|
|
36
|
-
},
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
|
-
},
|
|
40
|
-
'CallExpression > MemberExpression:matches([property.name="getExperimentValue"])': (
|
|
41
|
-
node: Node<'MemberExpression'>,
|
|
42
|
-
) => {
|
|
43
|
-
if (
|
|
44
|
-
node.object.type === 'Identifier' &&
|
|
45
|
-
isIdentifierImportedFrom(node.object.name, BANNED_IMPORTS_SET, context, node)
|
|
46
|
-
) {
|
|
47
|
-
context.report({
|
|
48
|
-
messageId: 'notSupported',
|
|
49
|
-
node,
|
|
50
|
-
});
|
|
51
|
-
}
|
|
52
|
-
},
|
|
53
|
-
};
|
|
54
|
-
},
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
export default rule;
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import { FEATURE_API_IMPORT_SOURCES } from '../constants';
|
|
2
|
-
import type { Rule, Scope } from 'eslint';
|
|
3
|
-
import type { Node as EstreeNode } from 'estree';
|
|
4
|
-
import { getScope } from '../util/context-compat';
|
|
5
|
-
|
|
6
|
-
export function isIdentifierImportedFrom(
|
|
7
|
-
identifierName: string,
|
|
8
|
-
sources: Set<string>,
|
|
9
|
-
context: Rule.RuleContext,
|
|
10
|
-
node: EstreeNode,
|
|
11
|
-
) {
|
|
12
|
-
if (sources.size > 0) {
|
|
13
|
-
return (
|
|
14
|
-
getScope(context, node)
|
|
15
|
-
.references.find((ref) => ref.identifier.name === identifierName)
|
|
16
|
-
?.resolved?.defs.some(
|
|
17
|
-
(def) =>
|
|
18
|
-
def.parent?.type === 'ImportDeclaration' && sources.has(def.parent.source.value + ''),
|
|
19
|
-
) ?? false
|
|
20
|
-
);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
return false;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export function isAPIimport(functionName: string, context: Rule.RuleContext, node: EstreeNode) {
|
|
27
|
-
return isIdentifierImportedFrom(functionName, FEATURE_API_IMPORT_SOURCES, context, node);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
// returns the definition node of a variable if it's declared within the scope of the file
|
|
31
|
-
export function getDef(name: string, context: Rule.RuleContext, node: EstreeNode) {
|
|
32
|
-
let scope: Scope.Scope | null = getScope(context, node);
|
|
33
|
-
|
|
34
|
-
while (scope && scope.type !== 'global') {
|
|
35
|
-
for (const variable of scope.variables) {
|
|
36
|
-
if (variable.name === name) {
|
|
37
|
-
const definition = variable.defs.find(
|
|
38
|
-
(def) => def.node && def.node.type === 'VariableDeclarator',
|
|
39
|
-
);
|
|
40
|
-
return definition;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
scope = scope.upper;
|
|
44
|
-
}
|
|
45
|
-
return null;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export type Node<T extends Rule.Node['type']> = Extract<Rule.Node, { type: T }>;
|
|
@@ -1,109 +0,0 @@
|
|
|
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;
|
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
import { tester } from '../../../../__tests__/utils/_tester';
|
|
2
|
-
import rule from '../../index';
|
|
3
|
-
|
|
4
|
-
describe('test no-duplicate-dependencies rule', () => {
|
|
5
|
-
tester.run('no-duplicate-dependencies-rule', rule, {
|
|
6
|
-
valid: [
|
|
7
|
-
{
|
|
8
|
-
code: `
|
|
9
|
-
module.exports = {
|
|
10
|
-
"dependencies": {
|
|
11
|
-
"foo": "^1.0.0",
|
|
12
|
-
"bar": "^2.0.0"
|
|
13
|
-
}
|
|
14
|
-
};
|
|
15
|
-
`,
|
|
16
|
-
filename: 'dependencies.json',
|
|
17
|
-
},
|
|
18
|
-
{
|
|
19
|
-
code: `
|
|
20
|
-
module.exports = {
|
|
21
|
-
"devDependencies": {
|
|
22
|
-
"foo": "^1.0.0",
|
|
23
|
-
"bar": "^2.0.0"
|
|
24
|
-
}
|
|
25
|
-
};
|
|
26
|
-
`,
|
|
27
|
-
filename: 'devDependencies.json',
|
|
28
|
-
},
|
|
29
|
-
{
|
|
30
|
-
code: `
|
|
31
|
-
module.exports = {
|
|
32
|
-
"dependencies": {
|
|
33
|
-
"foo": "^1.0.0",
|
|
34
|
-
"bar": "^2.0.0"
|
|
35
|
-
},
|
|
36
|
-
"devDependencies": {
|
|
37
|
-
"baz": "^3.0.0",
|
|
38
|
-
"qux": "^4.0.0"
|
|
39
|
-
}
|
|
40
|
-
};
|
|
41
|
-
`,
|
|
42
|
-
filename: 'devAndDependencies.json',
|
|
43
|
-
},
|
|
44
|
-
],
|
|
45
|
-
invalid: [
|
|
46
|
-
{
|
|
47
|
-
code: `
|
|
48
|
-
module.exports = {
|
|
49
|
-
"dependencies": {
|
|
50
|
-
"foo": "^1.0.0",
|
|
51
|
-
"bar": "^2.0.0"
|
|
52
|
-
},
|
|
53
|
-
"devDependencies": {
|
|
54
|
-
"foo": "^1.0.0",
|
|
55
|
-
"baz": "^3.0.0",
|
|
56
|
-
"qux": "^4.0.0"
|
|
57
|
-
}
|
|
58
|
-
};
|
|
59
|
-
`,
|
|
60
|
-
output: `
|
|
61
|
-
module.exports = {
|
|
62
|
-
"dependencies": {
|
|
63
|
-
"foo": "^1.0.0",
|
|
64
|
-
"bar": "^2.0.0"
|
|
65
|
-
},
|
|
66
|
-
"devDependencies": {
|
|
67
|
-
"baz": "^3.0.0",
|
|
68
|
-
"qux": "^4.0.0"
|
|
69
|
-
}
|
|
70
|
-
};
|
|
71
|
-
`,
|
|
72
|
-
errors: [
|
|
73
|
-
{
|
|
74
|
-
data: {
|
|
75
|
-
name: 'foo',
|
|
76
|
-
},
|
|
77
|
-
messageId: 'unexpectedDuplicateDependency',
|
|
78
|
-
},
|
|
79
|
-
],
|
|
80
|
-
filename: 'duplicateDependenciesFirst.json',
|
|
81
|
-
},
|
|
82
|
-
{
|
|
83
|
-
code: `
|
|
84
|
-
module.exports = {
|
|
85
|
-
"dependencies": {
|
|
86
|
-
"bar": "^1.0.0"
|
|
87
|
-
},
|
|
88
|
-
"devDependencies": {
|
|
89
|
-
"foo": "^2.0.0",
|
|
90
|
-
"bar": "^1.0.0"
|
|
91
|
-
}
|
|
92
|
-
};
|
|
93
|
-
`,
|
|
94
|
-
output: `
|
|
95
|
-
module.exports = {
|
|
96
|
-
"dependencies": {
|
|
97
|
-
"bar": "^1.0.0"
|
|
98
|
-
},
|
|
99
|
-
"devDependencies": {
|
|
100
|
-
"foo": "^2.0.0"
|
|
101
|
-
}
|
|
102
|
-
};
|
|
103
|
-
`,
|
|
104
|
-
errors: [
|
|
105
|
-
{
|
|
106
|
-
data: {
|
|
107
|
-
name: 'bar',
|
|
108
|
-
},
|
|
109
|
-
messageId: 'unexpectedDuplicateDependency',
|
|
110
|
-
},
|
|
111
|
-
],
|
|
112
|
-
filename: 'duplicateDependenciesLast.json',
|
|
113
|
-
},
|
|
114
|
-
],
|
|
115
|
-
});
|
|
116
|
-
});
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
// eslint-disable-next-line import/no-extraneous-dependencies
|
|
2
|
-
import type { Rule } from 'eslint';
|
|
3
|
-
|
|
4
|
-
const rule: Rule.RuleModule = {
|
|
5
|
-
meta: {
|
|
6
|
-
type: 'problem',
|
|
7
|
-
docs: {
|
|
8
|
-
description:
|
|
9
|
-
'This rule disallows a dependency to be defined in both dependencies and devDependencies',
|
|
10
|
-
recommended: false,
|
|
11
|
-
},
|
|
12
|
-
fixable: 'code',
|
|
13
|
-
messages: {
|
|
14
|
-
unexpectedDuplicateDependency: 'Unexpected duplicate dependency {{name}}',
|
|
15
|
-
},
|
|
16
|
-
},
|
|
17
|
-
create(context) {
|
|
18
|
-
const dependencies = new Map();
|
|
19
|
-
const devDependencies = new Map();
|
|
20
|
-
|
|
21
|
-
return {
|
|
22
|
-
'ObjectExpression Property[key.value=dependencies] Property': (node: Rule.Node) => {
|
|
23
|
-
// @ts-expect-error
|
|
24
|
-
dependencies.set(node.key.value, node.key);
|
|
25
|
-
},
|
|
26
|
-
'ObjectExpression Property[key.value=devDependencies] Property': (node: Rule.Node) => {
|
|
27
|
-
// @ts-expect-error
|
|
28
|
-
devDependencies.set(node.key.value, node.key);
|
|
29
|
-
},
|
|
30
|
-
'Program:exit': () => {
|
|
31
|
-
for (const [dependency, node] of devDependencies) {
|
|
32
|
-
if (dependencies.has(dependency)) {
|
|
33
|
-
context.report({
|
|
34
|
-
data: {
|
|
35
|
-
name: dependency,
|
|
36
|
-
},
|
|
37
|
-
fix(fixer) {
|
|
38
|
-
const sourceCode = context.getSourceCode();
|
|
39
|
-
const property = node.parent;
|
|
40
|
-
const isLastLine = sourceCode.getTokenAfter(property)?.value === '}';
|
|
41
|
-
const end = property.loc.end;
|
|
42
|
-
|
|
43
|
-
if (!isLastLine) {
|
|
44
|
-
return fixer.removeRange([
|
|
45
|
-
sourceCode.getIndexFromLoc({
|
|
46
|
-
line: property.loc.start.line,
|
|
47
|
-
column: 0,
|
|
48
|
-
}),
|
|
49
|
-
sourceCode.getIndexFromLoc({
|
|
50
|
-
line: end.line + 1,
|
|
51
|
-
column: 0,
|
|
52
|
-
}),
|
|
53
|
-
]);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
const previousToken = sourceCode.getTokenBefore(property)!;
|
|
57
|
-
|
|
58
|
-
return fixer.removeRange([
|
|
59
|
-
sourceCode.getIndexFromLoc({
|
|
60
|
-
line: previousToken.loc.end.line,
|
|
61
|
-
column: previousToken.loc.end.column - 1,
|
|
62
|
-
}),
|
|
63
|
-
sourceCode.getIndexFromLoc({
|
|
64
|
-
line: end.line,
|
|
65
|
-
column: end.column,
|
|
66
|
-
}),
|
|
67
|
-
]);
|
|
68
|
-
},
|
|
69
|
-
messageId: 'unexpectedDuplicateDependency',
|
|
70
|
-
node,
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
},
|
|
75
|
-
};
|
|
76
|
-
},
|
|
77
|
-
};
|
|
78
|
-
|
|
79
|
-
export default rule;
|