@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.
Files changed (119) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/dist/cjs/index.js +4 -3
  3. package/dist/cjs/rules/ensure-critical-dependency-resolutions/index.js +2 -2
  4. package/dist/cjs/rules/ensure-native-and-af-exports-synced/index.js +3 -0
  5. package/dist/cjs/rules/feature-gating/no-alias/index.js +1 -1
  6. package/dist/cjs/rules/no-direct-document-usage/index.js +1 -1
  7. package/dist/cjs/rules/no-set-immediate/index.js +39 -0
  8. package/dist/cjs/rules/util/context-compat.js +4 -2
  9. package/dist/es2019/index.js +4 -3
  10. package/dist/es2019/rules/ensure-critical-dependency-resolutions/index.js +2 -2
  11. package/dist/es2019/rules/ensure-native-and-af-exports-synced/index.js +3 -0
  12. package/dist/es2019/rules/feature-gating/no-alias/index.js +1 -1
  13. package/dist/es2019/rules/no-direct-document-usage/index.js +1 -1
  14. package/dist/es2019/rules/no-set-immediate/index.js +33 -0
  15. package/dist/es2019/rules/util/context-compat.js +4 -2
  16. package/dist/esm/index.js +4 -3
  17. package/dist/esm/rules/ensure-critical-dependency-resolutions/index.js +2 -2
  18. package/dist/esm/rules/ensure-native-and-af-exports-synced/index.js +3 -0
  19. package/dist/esm/rules/feature-gating/no-alias/index.js +1 -1
  20. package/dist/esm/rules/no-direct-document-usage/index.js +1 -1
  21. package/dist/esm/rules/no-set-immediate/index.js +33 -0
  22. package/dist/esm/rules/util/context-compat.js +4 -2
  23. package/dist/types/index.d.ts +14 -6
  24. package/dist/types/rules/util/handle-ast-object.d.ts +1 -1
  25. package/dist/types-ts4.5/index.d.ts +14 -6
  26. package/dist/types-ts4.5/rules/util/handle-ast-object.d.ts +1 -1
  27. package/package.json +2 -2
  28. package/afm-cc/tsconfig.json +0 -24
  29. package/afm-jira/tsconfig.json +0 -24
  30. package/build/tsconfig.json +0 -17
  31. package/dist/cjs/rules/ensure-valid-platform-yarn-protocol-usage/index.js +0 -79
  32. package/dist/es2019/rules/ensure-valid-platform-yarn-protocol-usage/index.js +0 -62
  33. package/dist/esm/rules/ensure-valid-platform-yarn-protocol-usage/index.js +0 -75
  34. package/src/__tests__/utils/_tester.tsx +0 -26
  35. package/src/index.tsx +0 -251
  36. package/src/rules/compiled/README.md +0 -3
  37. package/src/rules/compiled/expand-background-shorthand/README.md +0 -23
  38. package/src/rules/compiled/expand-background-shorthand/__tests__/rule.test.ts +0 -160
  39. package/src/rules/compiled/expand-background-shorthand/index.tsx +0 -43
  40. package/src/rules/compiled/expand-border-shorthand/README.md +0 -51
  41. package/src/rules/compiled/expand-border-shorthand/__tests__/rule.test.ts +0 -211
  42. package/src/rules/compiled/expand-border-shorthand/index.ts +0 -103
  43. package/src/rules/compiled/expand-spacing-shorthand/README.md +0 -38
  44. package/src/rules/compiled/expand-spacing-shorthand/__tests__/rule.test.ts +0 -448
  45. package/src/rules/compiled/expand-spacing-shorthand/index.ts +0 -240
  46. package/src/rules/constants.tsx +0 -20
  47. package/src/rules/ensure-atlassian-team/__tests__/unit/rule.test.ts +0 -24
  48. package/src/rules/ensure-atlassian-team/index.ts +0 -51
  49. package/src/rules/ensure-critical-dependency-resolutions/__test__/unit/rule.test.tsx +0 -200
  50. package/src/rules/ensure-critical-dependency-resolutions/index.tsx +0 -172
  51. package/src/rules/ensure-feature-flag-prefix/__tests__/unit/rule.test.tsx +0 -65
  52. package/src/rules/ensure-feature-flag-prefix/index.tsx +0 -81
  53. package/src/rules/ensure-feature-flag-registration/__tests__/unit/rule.test.tsx +0 -115
  54. package/src/rules/ensure-feature-flag-registration/index.tsx +0 -106
  55. package/src/rules/ensure-native-and-af-exports-synced/__tests__/unit/rule.test.tsx +0 -199
  56. package/src/rules/ensure-native-and-af-exports-synced/index.tsx +0 -188
  57. package/src/rules/ensure-no-private-dependencies/__tests__/unit/rule.test.ts +0 -212
  58. package/src/rules/ensure-no-private-dependencies/index.ts +0 -64
  59. package/src/rules/ensure-publish-valid/__tests__/unit/rule.test.ts +0 -39
  60. package/src/rules/ensure-publish-valid/index.ts +0 -81
  61. package/src/rules/ensure-test-runner-arguments/__tests__/unit/rule.test.tsx +0 -298
  62. package/src/rules/ensure-test-runner-arguments/index.tsx +0 -121
  63. package/src/rules/ensure-test-runner-nested-count/__tests__/unit/rule.test.tsx +0 -308
  64. package/src/rules/ensure-test-runner-nested-count/index.tsx +0 -82
  65. package/src/rules/ensure-valid-bin-values/__tests__/unit/rule.test.ts +0 -159
  66. package/src/rules/ensure-valid-bin-values/index.ts +0 -70
  67. package/src/rules/ensure-valid-platform-yarn-protocol-usage/__tests__/unit/rule.test.ts +0 -147
  68. package/src/rules/ensure-valid-platform-yarn-protocol-usage/index.ts +0 -67
  69. package/src/rules/feature-gating/README.md +0 -8
  70. package/src/rules/feature-gating/inline-usage/README.md +0 -53
  71. package/src/rules/feature-gating/inline-usage/__tests__/rule.test.tsx +0 -106
  72. package/src/rules/feature-gating/inline-usage/index.tsx +0 -135
  73. package/src/rules/feature-gating/no-alias/README.md +0 -29
  74. package/src/rules/feature-gating/no-alias/__tests__/rule.test.tsx +0 -76
  75. package/src/rules/feature-gating/no-alias/index.tsx +0 -80
  76. package/src/rules/feature-gating/no-module-level-eval/README.md +0 -53
  77. package/src/rules/feature-gating/no-module-level-eval/__tests__/test.tsx +0 -133
  78. package/src/rules/feature-gating/no-module-level-eval/index.tsx +0 -54
  79. package/src/rules/feature-gating/no-module-level-eval-nav4/README.md +0 -8
  80. package/src/rules/feature-gating/no-module-level-eval-nav4/__tests__/test.tsx +0 -130
  81. package/src/rules/feature-gating/no-module-level-eval-nav4/index.tsx +0 -73
  82. package/src/rules/feature-gating/no-preconditioning/README.md +0 -69
  83. package/src/rules/feature-gating/no-preconditioning/__tests__/rule.test.tsx +0 -164
  84. package/src/rules/feature-gating/no-preconditioning/index.tsx +0 -138
  85. package/src/rules/feature-gating/prefer-fg/README.md +0 -3
  86. package/src/rules/feature-gating/prefer-fg/__tests__/rule.test.tsx +0 -83
  87. package/src/rules/feature-gating/prefer-fg/index.tsx +0 -110
  88. package/src/rules/feature-gating/static-feature-flags/README.md +0 -3
  89. package/src/rules/feature-gating/static-feature-flags/__tests__/test.tsx +0 -135
  90. package/src/rules/feature-gating/static-feature-flags/index.tsx +0 -103
  91. package/src/rules/feature-gating/use-recommended-utils/README.md +0 -67
  92. package/src/rules/feature-gating/use-recommended-utils/__tests__/rule.test.tsx +0 -78
  93. package/src/rules/feature-gating/use-recommended-utils/index.tsx +0 -57
  94. package/src/rules/feature-gating/utils.tsx +0 -48
  95. package/src/rules/no-direct-document-usage/index.tsx +0 -109
  96. package/src/rules/no-duplicate-dependencies/__tests__/unit/rule.test.ts +0 -116
  97. package/src/rules/no-duplicate-dependencies/index.ts +0 -79
  98. package/src/rules/no-invalid-feature-flag-usage/__tests__/unit/rule.test.tsx +0 -69
  99. package/src/rules/no-invalid-feature-flag-usage/index.tsx +0 -128
  100. package/src/rules/no-invalid-storybook-decorator-usage/__tests__/unit/rule.test.tsx +0 -18
  101. package/src/rules/no-invalid-storybook-decorator-usage/index.tsx +0 -39
  102. package/src/rules/no-pre-post-installs/__tests__/unit/rule.test.ts +0 -41
  103. package/src/rules/no-pre-post-installs/index.ts +0 -35
  104. package/src/rules/no-sparse-checkout/__tests__/unit/rule.test.tsx +0 -48
  105. package/src/rules/no-sparse-checkout/index.tsx +0 -54
  106. package/src/rules/use-entrypoints-in-examples/README.md +0 -27
  107. package/src/rules/use-entrypoints-in-examples/__tests__/rule.test.tsx +0 -34
  108. package/src/rules/use-entrypoints-in-examples/index.tsx +0 -43
  109. package/src/rules/util/__tests__/context-compat.test.ts +0 -122
  110. package/src/rules/util/compiled-utils.ts +0 -27
  111. package/src/rules/util/context-compat.ts +0 -41
  112. package/src/rules/util/file-exclusions.ts +0 -39
  113. package/src/rules/util/handle-ast-object.ts +0 -33
  114. package/src/rules/util/registration-utils.ts +0 -59
  115. package/tsconfig.app.json +0 -43
  116. package/tsconfig.dev.json +0 -40
  117. package/tsconfig.json +0 -23
  118. /package/dist/types/rules/{ensure-valid-platform-yarn-protocol-usage → no-set-immediate}/index.d.ts +0 -0
  119. /package/dist/types-ts4.5/rules/{ensure-valid-platform-yarn-protocol-usage → no-set-immediate}/index.d.ts +0 -0
@@ -1,147 +0,0 @@
1
- import { tester } from '../../../../__tests__/utils/_tester';
2
- import rule from '../../index';
3
-
4
- const cwd = process.cwd();
5
-
6
- describe('test ensure-valid-platform-yarn-protocol-usage rule', () => {
7
- tester.run('workspace protocol', rule, {
8
- valid: [
9
- // Workspace protocol 'workspace:*' is allowed in packages as dependencies
10
- {
11
- code: `const foo = {
12
- "dependencies": {
13
- "@atlaskit/button": "workspace:*",
14
- "@atlaskit/primitives": "workspace:*",
15
- "@atlaskit/tokens": "workspace:*"
16
- }
17
- }`,
18
- filename: `${cwd}/packages/foo/package.json`,
19
- },
20
- // Workspace protocol 'workspace:*' is allowed in packages as devDependencies
21
- {
22
- code: `const foo = {
23
- "devDependencies": {
24
- "@atlaskit/button": "workspace:*",
25
- "@atlaskit/primitives": "workspace:*"
26
- }
27
- }`,
28
- filename: `${cwd}/packages/foo/package.json`,
29
- },
30
- // Workspace protocol is allowed in packages dependencies and devDependencies
31
- {
32
- code: `const foo = {
33
- "dependencies": {
34
- "@atlaskit/button": "workspace:*",
35
- "@atlaskit/primitives": "workspace:*"
36
- },
37
- "devDependencies": {
38
- "@atlaskit/button": "workspace:*",
39
- "@atlaskit/primitives": "workspace:*"
40
- }
41
- }`,
42
- filename: `${cwd}/packages/foo/package.json`,
43
- },
44
- ],
45
- invalid: [],
46
- });
47
-
48
- tester.run('root: protocol', rule, {
49
- // 'root:' protocol is not allowed in any platform package
50
- valid: [],
51
- invalid: [
52
- // 'root:' protocol is not allowed in packages as dependencies
53
- {
54
- code: `const foo = {
55
- "dependencies": {
56
- "react": "root:*",
57
- }
58
- }`,
59
- filename: `${cwd}/packages/foo/package.json`,
60
- errors: [
61
- {
62
- messageId: 'invalidRootProtocolUsage',
63
- },
64
- ],
65
- },
66
- // 'root:' protocol is not allowed in private packages as dependencies
67
- {
68
- code: `const foo = {
69
- "private": true,
70
- "dependencies": {
71
- "react": "root:*",
72
- }
73
- }`,
74
- filename: `${cwd}/packages/foo/package.json`,
75
- errors: [
76
- {
77
- messageId: 'invalidRootProtocolUsage',
78
- },
79
- ],
80
- },
81
- // 'root:' protocol is not allowed in public packages as devDependencies
82
- {
83
- code: `const foo = {
84
- "devDependencies": {
85
- "react": "root:*",
86
- }
87
- }`,
88
- filename: `${cwd}/packages/foo/package.json`,
89
- errors: [
90
- {
91
- messageId: 'invalidRootProtocolUsage',
92
- },
93
- ],
94
- },
95
- // 'root:' protocol is not allowed in private packages as devDependencies
96
- {
97
- code: `const foo = {
98
- "private": true,
99
- "devDependencies": {
100
- "react": "root:*",
101
- }
102
- }`,
103
- filename: `${cwd}/packages/foo/package.json`,
104
- errors: [
105
- {
106
- messageId: 'invalidRootProtocolUsage',
107
- },
108
- ],
109
- },
110
- // 'root:' protocol is not allowed in public packages as dependencies and devDependencies
111
- {
112
- code: `const foo = {
113
- "dependencies": {
114
- "lodash": "root:*"
115
- },
116
- "devDependencies": {
117
- "react": "root:*"
118
- }
119
- }`,
120
- filename: `${cwd}/packages/foo/package.json`,
121
- errors: [
122
- {
123
- messageId: 'invalidRootProtocolUsage',
124
- },
125
- ],
126
- },
127
- // 'root:' protocol is not allowed in private packages as dependencies and devDependencies
128
- {
129
- code: `const foo = {
130
- "private": true,
131
- "dependencies": {
132
- "lodash": "root:*"
133
- },
134
- "devDependencies": {
135
- "react": "root:*"
136
- }
137
- }`,
138
- filename: `${cwd}/packages/foo/package.json`,
139
- errors: [
140
- {
141
- messageId: 'invalidRootProtocolUsage',
142
- },
143
- ],
144
- },
145
- ],
146
- });
147
- });
@@ -1,67 +0,0 @@
1
- // eslint-disable-next-line import/no-extraneous-dependencies
2
- import type { Rule } from 'eslint';
3
- import type { ObjectExpression } from 'estree';
4
- import { getObjectPropertyAsObject } from '../util/handle-ast-object';
5
-
6
- const rootProtocolRegex = /^root:[\^~\*]$/;
7
-
8
- /**
9
- * Checks if the 'workspace:' and 'root:' protocol are used as either dependencies or devDependencies
10
- */
11
- function getYarnProtocolsUsed(node: ObjectExpression) {
12
- const protocolsUsed = { workspace: false, root: false };
13
-
14
- const dependencies = getObjectPropertyAsObject(node, 'dependencies');
15
- const devDependencies = getObjectPropertyAsObject(node, 'devDependencies');
16
- const peerDependencies = getObjectPropertyAsObject(node, 'peerDependencies');
17
-
18
- for (const obj of [dependencies, devDependencies, peerDependencies]) {
19
- for (const p of obj?.properties || []) {
20
- if (p.type === 'Property' && p.value.type === 'Literal') {
21
- if (typeof p.value.value === 'string') {
22
- if (rootProtocolRegex.test(p.value.value)) {
23
- protocolsUsed.root = true;
24
- }
25
- }
26
- }
27
- }
28
- }
29
-
30
- return protocolsUsed;
31
- }
32
-
33
- const rule: Rule.RuleModule = {
34
- meta: {
35
- type: 'problem',
36
- docs: {
37
- description: `Ensures that yarn protocols 'workspace:' and 'root:' are used correctly.`,
38
- recommended: true,
39
- },
40
- hasSuggestions: false,
41
- messages: {
42
- invalidWorkspaceProtocolUsage: `The 'workspace:^'protocol is Used. To resolve this error, please use the 'workspace:*' protocol instead.`,
43
- 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').`,
44
- },
45
- },
46
- create(context) {
47
- return {
48
- ObjectExpression: (node: Rule.Node) => {
49
- if (!context.filename.endsWith('package.json') || node.type !== 'ObjectExpression') {
50
- return;
51
- }
52
-
53
- const yarnProtocolsUsed = getYarnProtocolsUsed(node);
54
-
55
- // The 'root:' protocol can not be used in any platform packages
56
- if (yarnProtocolsUsed.root) {
57
- context.report({
58
- node,
59
- messageId: 'invalidRootProtocolUsage',
60
- });
61
- }
62
- },
63
- };
64
- },
65
- };
66
-
67
- export default rule;
@@ -1,8 +0,0 @@
1
- ### Notes
2
-
3
- - feature-gating/\* rules are copied from
4
- [eslint-plugin-jira/rules/ff](https://stash.atlassian.com/projects/ATLASSIAN/repos/atlassian-frontend-monorepo/browse/jira/dev-tooling/packages/eslint-plugin-jira/rules/ff)
5
- with small variations as mentioned in this
6
- [PR](https://stash.atlassian.com/projects/ATLASSIAN/repos/atlassian-frontend-monorepo/pull-requests/115546/overview)
7
- - these rules could be a WIP since they are still targeting JFE libraries- see
8
- [discussion](https://atlassian.slack.com/archives/C026LTWFZ47/p1730776455371799?thread_ts=1730715221.742919&cid=C026LTWFZ47)
@@ -1,53 +0,0 @@
1
- # Inline feature flags/gates and experiments usages (feature-flags/inline-usage)
2
-
3
- Ensure feature flags/gates and experiments are inlined so that they can be statically analyzable.
4
-
5
- ## Examples
6
-
7
- 👎 Examples of **incorrect** code for this rule: Feature flag call is assigned to a variable
8
-
9
- ```tsx
10
- import { ff } from '@atlassian/jira-feature-flagging';
11
-
12
- const myFF = () => ff('my_flag');
13
-
14
- export const doSomething = () => {
15
- if (myFF()) {
16
- doSomethingNew();
17
- } else {
18
- doSomethingOld();
19
- }
20
- };
21
- ```
22
-
23
- 👍 Examples of **correct** code for this rule: Usage is inlined
24
-
25
- ```tsx
26
- import { ff } from '@atlassian/jira-feature-flagging';
27
- import { fg } from '@atlassian/jira-feature-gating';
28
- import { expValEquals } from '@atlassian/jira-feature-experiments';
29
-
30
- export const doSomething = () => {
31
- if (ff('my_flag')) {
32
- doSomethingNew();
33
- } else {
34
- doSomethingOld();
35
- }
36
- };
37
-
38
- export const doSomething = () => {
39
- if (fg('my_gate')) {
40
- doSomethingNew();
41
- } else {
42
- doSomethingOld();
43
- }
44
- };
45
-
46
- export const doSomething = () => {
47
- if (expValEquals('my_exp', 'on', true)) {
48
- doSomethingNew();
49
- } else {
50
- doSomethingOld();
51
- }
52
- };
53
- ```
@@ -1,106 +0,0 @@
1
- import outdent from 'outdent';
2
- import { tester } from '../../../../__tests__/utils/_tester';
3
- import rule from '../index';
4
-
5
- const options = ['ssOnly'];
6
-
7
- tester.run('feature-flags/inline-usage', rule, {
8
- valid: [
9
- {
10
- name: 'Valid API usage',
11
- code: outdent`
12
- import { ff } from '@atlassian/jira-feature-flagging';
13
- import { fg } from '@atlassian/jira-feature-gating';
14
- import { expVal, expValEquals } from '@atlassian/jira-feature-experiments';
15
-
16
- export const FFComponent = () => ff('is.enabled') && <>Valid</>;
17
- export const FGComponent = () => fg('is.enabled') && <>Valid</>;
18
-
19
- export const ExpValComponent = function() {
20
- return expVal('is.enabled', 'on', false) && <>Valid</>;
21
- };
22
-
23
- export function ExpValEqualsComponent() {
24
- expValEquals('is.enabled', 'on', true) && <>Valid</>;
25
- }
26
-
27
- const valid1 = () => {
28
- console.log('valid');
29
- };
30
-
31
- const valid2 = () => 'valid';
32
- `,
33
- },
34
- {
35
- name: 'When using ssOnly option, ff() can avoid inline-usage',
36
- options,
37
- code: outdent`
38
- import { ff } from '@atlassian/jira-feature-flagging';
39
- import { fg } from '@atlassian/jira-feature-gating';
40
-
41
- const invalidFF = () => ff('is.enabled');
42
- export const FGComponent = () => fg('is.enabled') && <>Valid</>;
43
- `,
44
- },
45
- {
46
- name: 'Edge cases',
47
- code: outdent`
48
- import { ff } from '@atlassian/jira-feature-flagging';
49
-
50
- function edgeCase1() {
51
- console.log('workAround');
52
- return ff('is.enabled');
53
- }
54
-
55
- const edgeCase2 = function() {
56
- console.log('workAround');
57
- return ff('is.enabled');
58
- };
59
-
60
- const edgeCase3 = () => {
61
- console.log('workAround');
62
- return ff('is.enabled');
63
- };
64
-
65
- const edgeCase4 = () => {
66
- ff('is.enabled');
67
- };
68
- `,
69
- },
70
- ],
71
- invalid: [
72
- {
73
- name: 'Invalid API usage',
74
- code: outdent`
75
- import { ff } from '@atlassian/jira-feature-flagging';
76
- import { fg } from '@atlassian/jira-feature-gating';
77
- import { expVal, expValEquals, UNSAFE_noExposureExp } from '@atlassian/jira-feature-experiments';
78
-
79
- const invalidFF = () => ff('is.enabled');
80
- const invalidFG = () => fg('is.enabled');
81
- const invalidExpVal = () => expVal('is.enabled', 'on', false);
82
- const invalidExpValBinary = () => expVal('is.enabled', 'cohort', null) === 'variation';
83
- const invalidExpValBinary2 = () => expVal('is.enabled', 'count', 0) >= 0;
84
-
85
- const invalidExpValEquals = function() {
86
- return expValEquals('is.enabled', 'on', true);
87
- };
88
-
89
- function invalidUnsafe() {
90
- return UNSAFE_noExposureExp('is.enabled');
91
- }
92
- `,
93
- errors: Array.from(Array(7), () => ({ messageId: 'inlineUsage' })),
94
- },
95
- {
96
- name: 'When using ssOnly option, Statsig functions should be inlined',
97
- options,
98
- code: outdent`
99
- import { fg } from '@atlassian/jira-feature-gating';
100
-
101
- const invalidFG = () => fg('is.enabled');
102
- `,
103
- errors: [{ messageId: 'inlineUsage' }],
104
- },
105
- ],
106
- });
@@ -1,135 +0,0 @@
1
- import type { Rule } from 'eslint';
2
- import { isAPIimport, type Node } from '../utils';
3
-
4
- const FUNCTION_NAMES = new Set(['ff', 'fg', 'expVal', 'expValEquals', 'UNSAFE_noExposureExp']);
5
- const STATSIG_ONLY_FUNCTION_NAMES = new Set([
6
- 'fg',
7
- 'expVal',
8
- 'expValEquals',
9
- 'UNSAFE_noExposureExp',
10
- ]);
11
-
12
- const findDefinitionDeclaration = (
13
- node: Rule.Node,
14
- ): (Node<'VariableDeclaration'> | Node<'FunctionDeclaration'>) & Rule.NodeParentExtension =>
15
- node.type === 'VariableDeclaration' || node.type === 'FunctionDeclaration'
16
- ? node
17
- : findDefinitionDeclaration(node.parent);
18
-
19
- const validateCallExpression = (
20
- node: Node<'CallExpression'> & Rule.NodeParentExtension,
21
- context: Rule.RuleContext,
22
- ) => {
23
- const targetedFunctionsSwitch =
24
- context.options[0] === 'ssOnly' ? STATSIG_ONLY_FUNCTION_NAMES : FUNCTION_NAMES;
25
-
26
- const { callee } = node;
27
- const shouldWarn =
28
- callee.type === 'Identifier' &&
29
- targetedFunctionsSwitch.has(callee.name) &&
30
- isAPIimport(callee.name, context, node);
31
-
32
- if (shouldWarn) {
33
- const defDeclaration = findDefinitionDeclaration(node.parent);
34
-
35
- context.report({
36
- messageId: 'inlineUsage',
37
- node:
38
- defDeclaration.parent.type === 'ExportNamedDeclaration'
39
- ? defDeclaration.parent
40
- : defDeclaration,
41
- });
42
-
43
- return true;
44
- }
45
-
46
- return false;
47
- };
48
-
49
- const validateBinaryExpression = (
50
- node: Node<'BinaryExpression'> & Rule.NodeParentExtension,
51
- context: Rule.RuleContext,
52
- ) => {
53
- // Match all comparator operators i.e ===, >=, <
54
- if (node.operator.match(/^[=|<|>]/)) {
55
- if (
56
- node.left.type === 'CallExpression' &&
57
- validateCallExpression(node.left as Node<'CallExpression'>, context)
58
- ) {
59
- return;
60
- }
61
-
62
- if (node.right.type === 'CallExpression') {
63
- validateCallExpression(node.right as Node<'CallExpression'>, context);
64
- }
65
- }
66
- };
67
-
68
- const validateReturnExpression = ({ body }: Node<'BlockStatement'>, context: Rule.RuleContext) => {
69
- if (body.length !== 1) {
70
- return;
71
- }
72
-
73
- const [statement] = body;
74
-
75
- if (statement.type === 'ReturnStatement') {
76
- const { argument } = statement;
77
-
78
- if (argument && argument.type === 'CallExpression') {
79
- validateCallExpression(argument as Node<'CallExpression'>, context);
80
- } else if (argument && argument.type === 'BinaryExpression') {
81
- validateBinaryExpression(argument as Node<'BinaryExpression'>, context);
82
- }
83
- }
84
- };
85
-
86
- const validateFunctionBody = (
87
- body: Node<'BinaryExpression'> | Node<'CallExpression'> | Node<'BlockStatement'>,
88
- context: Rule.RuleContext,
89
- ) => {
90
- switch (body.type) {
91
- case 'CallExpression':
92
- validateCallExpression(body, context);
93
- break;
94
- case 'BinaryExpression':
95
- validateBinaryExpression(body, context);
96
- break;
97
- case 'BlockStatement':
98
- validateReturnExpression(body, context);
99
- break;
100
- default:
101
- }
102
- };
103
-
104
- const rule: Rule.RuleModule = {
105
- meta: {
106
- type: 'problem',
107
- docs: {
108
- description:
109
- 'Ensure feature flags/gates and experiments are inlined so that they can be statically analyzable.',
110
- url: 'https://stash.atlassian.com/projects/ATLASSIAN/repos/atlassian-frontend-monorepo/browse/platform/packages/platform/eslint-plugin/src/rules/inline-usage/README.md',
111
- },
112
- schema: [
113
- {
114
- enum: ['ssOnly'],
115
- },
116
- ],
117
- messages: {
118
- inlineUsage:
119
- 'Do not export or wrap feature flags/gates and experiments usages. Inline calls at the callsite to ensure it is statically analyzable.',
120
- },
121
- },
122
- create(context) {
123
- return {
124
- 'VariableDeclaration[declarations.length=1] > VariableDeclarator[id.type="Identifier"]:matches([init.type="ArrowFunctionExpression"], [init.type="FunctionExpression"]) > *.init':
125
- ({ body }: Node<'FunctionDeclaration'>) => {
126
- validateFunctionBody(body as Node<'BlockStatement'> & Rule.NodeParentExtension, context);
127
- },
128
- FunctionDeclaration: ({ body }: Node<'FunctionDeclaration'>) => {
129
- validateFunctionBody(body as Node<'BlockStatement'> & Rule.NodeParentExtension, context);
130
- },
131
- };
132
- },
133
- };
134
-
135
- export default rule;
@@ -1,29 +0,0 @@
1
- # Avoid aliasing feature flag utils (feature-flags/no-alias)
2
-
3
- Ensure feature flag usage is statically analyzable. This applies to all methods, weather you are
4
- writing production code, unit testing or storybooks.
5
-
6
- ## Examples
7
-
8
- 👎 Examples of **incorrect** code for this rule:
9
-
10
- ```tsx
11
- // Do not alias utils
12
- import { ff as getBoolean } from '@atlassian/jira-feature-flagging';
13
-
14
- // Do not reassign utils
15
- import { fg } from '@atlassian/jira-feature-gating';
16
- const aliasedFG = fg;
17
- ```
18
-
19
- 👍 Examples of **correct** code for this rule: Do not alias utils
20
-
21
- ```tsx
22
- import { ff } from '@atlassian/jira-feature-flagging';
23
-
24
- export const doSomething = () => {
25
- if (ff('my.flag')) {
26
- console.log('hello');
27
- }
28
- };
29
- ```
@@ -1,76 +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/no-alias', rule, {
6
- valid: [
7
- {
8
- name: '`@atlassian/jira-feature-flagging` imports are not aliased',
9
- code: outdent`
10
- import { ff, ffVal } from '@atlassian/jira-feature-flagging';
11
- `,
12
- },
13
- {
14
- name: '`@atlassian/jira-feature-flagging-utils` imports are not aliased',
15
- code: outdent`
16
- import { componentWithFF } from '@atlassian/jira-feature-flagging-utils';
17
- `,
18
- },
19
- {
20
- name: '`@atlassian/jira-feature-gating` imports are not aliased',
21
- code: outdent`
22
- import { fg } from '@atlassian/jira-feature-gating';
23
- `,
24
- },
25
- {
26
- name: '`@atlassian/jira-feature-gates-test-mocks` imports are not aliased',
27
- code: outdent`
28
- import { passGate } from '@atlassian/jira-feature-gates-test-mocks';
29
- `,
30
- },
31
- {
32
- name: '`@atlassian/jira-feature-gates-storybook-mocks` imports are not aliased',
33
- code: outdent`
34
- import { withGate } from '@atlassian/jira-feature-gates-storybook-mocks';
35
- `,
36
- },
37
- {
38
- name: 'Aliases for non related imports are allowed',
39
- code: outdent`
40
- import { memo as m } from 'react';
41
- import * as r from 'redux';
42
- `,
43
- },
44
- ],
45
- invalid: [
46
- {
47
- name: 'Do not alias utils',
48
- code: outdent`
49
- import { ff as getBoolean } from '@atlassian/jira-feature-flagging';
50
- `,
51
- errors: [{ messageId: 'noSpecifierAlias' }],
52
- },
53
- {
54
- name: 'Do not alias multiple utils',
55
- code: outdent`
56
- import { ff as getBoolean, ffVal as getFeatureFlagValue } from '@atlassian/jira-feature-flagging';
57
- `,
58
- errors: [{ messageId: 'noSpecifierAlias' }, { messageId: 'noSpecifierAlias' }],
59
- },
60
- {
61
- name: 'Do not allow namespace imports',
62
- code: outdent`
63
- import * as ffUtils from '@atlassian/jira-feature-flagging';
64
- `,
65
- errors: [{ messageId: 'noNamespaceSpecifier' }],
66
- },
67
- {
68
- name: 'Do not reassign utils',
69
- code: outdent`
70
- import { fg } from '@atlassian/jira-feature-gating';
71
- const aliasedFG = fg;
72
- `,
73
- errors: [{ messageId: 'noReassignment' }],
74
- },
75
- ],
76
- });