@atlaskit/eslint-plugin-platform 2.7.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 (114) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/dist/cjs/index.js +0 -2
  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/util/context-compat.js +4 -2
  7. package/dist/es2019/index.js +0 -2
  8. package/dist/es2019/rules/ensure-critical-dependency-resolutions/index.js +2 -2
  9. package/dist/es2019/rules/ensure-native-and-af-exports-synced/index.js +3 -0
  10. package/dist/es2019/rules/feature-gating/no-alias/index.js +1 -1
  11. package/dist/es2019/rules/util/context-compat.js +4 -2
  12. package/dist/esm/index.js +0 -2
  13. package/dist/esm/rules/ensure-critical-dependency-resolutions/index.js +2 -2
  14. package/dist/esm/rules/ensure-native-and-af-exports-synced/index.js +3 -0
  15. package/dist/esm/rules/feature-gating/no-alias/index.js +1 -1
  16. package/dist/esm/rules/util/context-compat.js +4 -2
  17. package/dist/types/index.d.ts +4 -6
  18. package/dist/types/rules/util/handle-ast-object.d.ts +1 -1
  19. package/dist/types-ts4.5/index.d.ts +4 -6
  20. package/dist/types-ts4.5/rules/util/handle-ast-object.d.ts +1 -1
  21. package/package.json +2 -2
  22. package/afm-cc/tsconfig.json +0 -24
  23. package/afm-jira/tsconfig.json +0 -24
  24. package/build/tsconfig.json +0 -17
  25. package/dist/cjs/rules/ensure-valid-platform-yarn-protocol-usage/index.js +0 -79
  26. package/dist/es2019/rules/ensure-valid-platform-yarn-protocol-usage/index.js +0 -62
  27. package/dist/esm/rules/ensure-valid-platform-yarn-protocol-usage/index.js +0 -75
  28. package/dist/types/rules/ensure-valid-platform-yarn-protocol-usage/index.d.ts +0 -3
  29. package/dist/types-ts4.5/rules/ensure-valid-platform-yarn-protocol-usage/index.d.ts +0 -3
  30. package/src/__tests__/utils/_tester.tsx +0 -26
  31. package/src/index.tsx +0 -254
  32. package/src/rules/compiled/README.md +0 -3
  33. package/src/rules/compiled/expand-background-shorthand/README.md +0 -23
  34. package/src/rules/compiled/expand-background-shorthand/__tests__/rule.test.ts +0 -160
  35. package/src/rules/compiled/expand-background-shorthand/index.tsx +0 -43
  36. package/src/rules/compiled/expand-border-shorthand/README.md +0 -51
  37. package/src/rules/compiled/expand-border-shorthand/__tests__/rule.test.ts +0 -211
  38. package/src/rules/compiled/expand-border-shorthand/index.ts +0 -103
  39. package/src/rules/compiled/expand-spacing-shorthand/README.md +0 -38
  40. package/src/rules/compiled/expand-spacing-shorthand/__tests__/rule.test.ts +0 -448
  41. package/src/rules/compiled/expand-spacing-shorthand/index.ts +0 -240
  42. package/src/rules/constants.tsx +0 -20
  43. package/src/rules/ensure-atlassian-team/__tests__/unit/rule.test.ts +0 -24
  44. package/src/rules/ensure-atlassian-team/index.ts +0 -51
  45. package/src/rules/ensure-critical-dependency-resolutions/__test__/unit/rule.test.tsx +0 -200
  46. package/src/rules/ensure-critical-dependency-resolutions/index.tsx +0 -172
  47. package/src/rules/ensure-feature-flag-prefix/__tests__/unit/rule.test.tsx +0 -65
  48. package/src/rules/ensure-feature-flag-prefix/index.tsx +0 -81
  49. package/src/rules/ensure-feature-flag-registration/__tests__/unit/rule.test.tsx +0 -115
  50. package/src/rules/ensure-feature-flag-registration/index.tsx +0 -106
  51. package/src/rules/ensure-native-and-af-exports-synced/__tests__/unit/rule.test.tsx +0 -199
  52. package/src/rules/ensure-native-and-af-exports-synced/index.tsx +0 -188
  53. package/src/rules/ensure-no-private-dependencies/__tests__/unit/rule.test.ts +0 -212
  54. package/src/rules/ensure-no-private-dependencies/index.ts +0 -64
  55. package/src/rules/ensure-publish-valid/__tests__/unit/rule.test.ts +0 -39
  56. package/src/rules/ensure-publish-valid/index.ts +0 -81
  57. package/src/rules/ensure-test-runner-arguments/__tests__/unit/rule.test.tsx +0 -298
  58. package/src/rules/ensure-test-runner-arguments/index.tsx +0 -121
  59. package/src/rules/ensure-test-runner-nested-count/__tests__/unit/rule.test.tsx +0 -308
  60. package/src/rules/ensure-test-runner-nested-count/index.tsx +0 -82
  61. package/src/rules/ensure-valid-bin-values/__tests__/unit/rule.test.ts +0 -159
  62. package/src/rules/ensure-valid-bin-values/index.ts +0 -70
  63. package/src/rules/ensure-valid-platform-yarn-protocol-usage/__tests__/unit/rule.test.ts +0 -147
  64. package/src/rules/ensure-valid-platform-yarn-protocol-usage/index.ts +0 -67
  65. package/src/rules/feature-gating/README.md +0 -8
  66. package/src/rules/feature-gating/inline-usage/README.md +0 -53
  67. package/src/rules/feature-gating/inline-usage/__tests__/rule.test.tsx +0 -106
  68. package/src/rules/feature-gating/inline-usage/index.tsx +0 -135
  69. package/src/rules/feature-gating/no-alias/README.md +0 -29
  70. package/src/rules/feature-gating/no-alias/__tests__/rule.test.tsx +0 -76
  71. package/src/rules/feature-gating/no-alias/index.tsx +0 -80
  72. package/src/rules/feature-gating/no-module-level-eval/README.md +0 -53
  73. package/src/rules/feature-gating/no-module-level-eval/__tests__/test.tsx +0 -133
  74. package/src/rules/feature-gating/no-module-level-eval/index.tsx +0 -54
  75. package/src/rules/feature-gating/no-module-level-eval-nav4/README.md +0 -8
  76. package/src/rules/feature-gating/no-module-level-eval-nav4/__tests__/test.tsx +0 -130
  77. package/src/rules/feature-gating/no-module-level-eval-nav4/index.tsx +0 -73
  78. package/src/rules/feature-gating/no-preconditioning/README.md +0 -69
  79. package/src/rules/feature-gating/no-preconditioning/__tests__/rule.test.tsx +0 -164
  80. package/src/rules/feature-gating/no-preconditioning/index.tsx +0 -138
  81. package/src/rules/feature-gating/prefer-fg/README.md +0 -3
  82. package/src/rules/feature-gating/prefer-fg/__tests__/rule.test.tsx +0 -83
  83. package/src/rules/feature-gating/prefer-fg/index.tsx +0 -110
  84. package/src/rules/feature-gating/static-feature-flags/README.md +0 -3
  85. package/src/rules/feature-gating/static-feature-flags/__tests__/test.tsx +0 -135
  86. package/src/rules/feature-gating/static-feature-flags/index.tsx +0 -103
  87. package/src/rules/feature-gating/use-recommended-utils/README.md +0 -67
  88. package/src/rules/feature-gating/use-recommended-utils/__tests__/rule.test.tsx +0 -78
  89. package/src/rules/feature-gating/use-recommended-utils/index.tsx +0 -57
  90. package/src/rules/feature-gating/utils.tsx +0 -48
  91. package/src/rules/no-direct-document-usage/index.tsx +0 -111
  92. package/src/rules/no-duplicate-dependencies/__tests__/unit/rule.test.ts +0 -116
  93. package/src/rules/no-duplicate-dependencies/index.ts +0 -79
  94. package/src/rules/no-invalid-feature-flag-usage/__tests__/unit/rule.test.tsx +0 -69
  95. package/src/rules/no-invalid-feature-flag-usage/index.tsx +0 -128
  96. package/src/rules/no-invalid-storybook-decorator-usage/__tests__/unit/rule.test.tsx +0 -18
  97. package/src/rules/no-invalid-storybook-decorator-usage/index.tsx +0 -39
  98. package/src/rules/no-pre-post-installs/__tests__/unit/rule.test.ts +0 -41
  99. package/src/rules/no-pre-post-installs/index.ts +0 -35
  100. package/src/rules/no-set-immediate/index.tsx +0 -43
  101. package/src/rules/no-sparse-checkout/__tests__/unit/rule.test.tsx +0 -48
  102. package/src/rules/no-sparse-checkout/index.tsx +0 -54
  103. package/src/rules/use-entrypoints-in-examples/README.md +0 -27
  104. package/src/rules/use-entrypoints-in-examples/__tests__/rule.test.tsx +0 -34
  105. package/src/rules/use-entrypoints-in-examples/index.tsx +0 -43
  106. package/src/rules/util/__tests__/context-compat.test.ts +0 -122
  107. package/src/rules/util/compiled-utils.ts +0 -27
  108. package/src/rules/util/context-compat.ts +0 -41
  109. package/src/rules/util/file-exclusions.ts +0 -39
  110. package/src/rules/util/handle-ast-object.ts +0 -33
  111. package/src/rules/util/registration-utils.ts +0 -59
  112. package/tsconfig.app.json +0 -43
  113. package/tsconfig.dev.json +0 -40
  114. package/tsconfig.json +0 -23
@@ -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
- });