@atlaskit/eslint-plugin-platform 0.0.3 → 0.0.5
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 +12 -0
- package/dist/cjs/index.js +5 -2
- package/dist/cjs/rules/ensure-feature-flag-registration/index.js +0 -21
- package/dist/cjs/rules/no-invalid-feature-flag-usage/index.js +87 -0
- package/dist/cjs/version.json +1 -1
- package/dist/es2019/index.js +5 -2
- package/dist/es2019/rules/ensure-feature-flag-registration/index.js +0 -21
- package/dist/es2019/rules/no-invalid-feature-flag-usage/index.js +80 -0
- package/dist/es2019/version.json +1 -1
- package/dist/esm/index.js +5 -2
- package/dist/esm/rules/ensure-feature-flag-registration/index.js +0 -21
- package/dist/esm/rules/no-invalid-feature-flag-usage/index.js +79 -0
- package/dist/esm/version.json +1 -1
- package/dist/types/index.d.ts +2 -0
- package/dist/types/rules/no-invalid-feature-flag-usage/index.d.ts +3 -0
- package/package.json +1 -1
- package/report.api.md +2 -0
- package/src/index.tsx +3 -0
- package/src/rules/ensure-feature-flag-registration/__tests__/unit/rule.test.tsx +2 -23
- package/src/rules/ensure-feature-flag-registration/index.tsx +0 -24
- package/src/rules/no-invalid-feature-flag-usage/__tests__/unit/rule.test.tsx +49 -0
- package/src/rules/no-invalid-feature-flag-usage/index.tsx +108 -0
- package/tmp/api-report-tmp.d.ts +2 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @atlaskit/eslint-plugin-platform
|
|
2
2
|
|
|
3
|
+
## 0.0.5
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [`aeb52cac34c`](https://bitbucket.org/atlassian/atlassian-frontend/commits/aeb52cac34c) - Split feature flag registration rule into two to more easily use it in products
|
|
8
|
+
|
|
9
|
+
## 0.0.4
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- [`cd5b194f403`](https://bitbucket.org/atlassian/atlassian-frontend/commits/cd5b194f403) - Add check to ensure that there is only one feature flag call per expression
|
|
14
|
+
|
|
3
15
|
## 0.0.3
|
|
4
16
|
|
|
5
17
|
### Patch Changes
|
package/dist/cjs/index.js
CHANGED
|
@@ -6,15 +6,18 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
});
|
|
7
7
|
exports.rules = exports.configs = void 0;
|
|
8
8
|
var _ensureFeatureFlagRegistration = _interopRequireDefault(require("./rules/ensure-feature-flag-registration"));
|
|
9
|
+
var _noInvalidFeatureFlagUsage = _interopRequireDefault(require("./rules/no-invalid-feature-flag-usage"));
|
|
9
10
|
var rules = {
|
|
10
|
-
'ensure-feature-flag-registration': _ensureFeatureFlagRegistration.default
|
|
11
|
+
'ensure-feature-flag-registration': _ensureFeatureFlagRegistration.default,
|
|
12
|
+
'no-invalid-feature-flag-usage': _noInvalidFeatureFlagUsage.default
|
|
11
13
|
};
|
|
12
14
|
exports.rules = rules;
|
|
13
15
|
var configs = {
|
|
14
16
|
recommended: {
|
|
15
17
|
plugins: ['@atlaskit/platform'],
|
|
16
18
|
rules: {
|
|
17
|
-
'@atlaskit/platform/ensure-feature-flag-registration': 'error'
|
|
19
|
+
'@atlaskit/platform/ensure-feature-flag-registration': 'error',
|
|
20
|
+
'@atlaskit/platform/no-invalid-feature-flag-usage': 'error'
|
|
18
21
|
}
|
|
19
22
|
}
|
|
20
23
|
};
|
|
@@ -39,8 +39,6 @@ var rule = {
|
|
|
39
39
|
},
|
|
40
40
|
type: 'problem',
|
|
41
41
|
messages: {
|
|
42
|
-
onlyInlineIf: "Only call feature flags as part of an expression, don't assign to a variable! See http://go/pff-eslint for more details",
|
|
43
|
-
onlyStringLiteral: "Only get feature flags by string literal, don't use variables! See http://go/pff-eslint for more details",
|
|
44
42
|
registrationSectionMissing: 'Please add a "platform-feature-flags" section to your package.json! See http://go/pff-eslint for more details',
|
|
45
43
|
featureFlagMissing: "Please add a \"{{ featureFlag }}\" section to the \"platform-feature-flags\" section in your package.json. See http://go/pff-eslint for more details"
|
|
46
44
|
}
|
|
@@ -50,26 +48,7 @@ var rule = {
|
|
|
50
48
|
'CallExpression[callee.name=/getBooleanFF/]': function CallExpressionCalleeNameGetBooleanFF(node) {
|
|
51
49
|
// to make typescript happy
|
|
52
50
|
if (node.type === 'CallExpression') {
|
|
53
|
-
var _node$parent;
|
|
54
51
|
var args = node.arguments;
|
|
55
|
-
if (args.length === 1 && args[0].type !== 'Literal') {
|
|
56
|
-
return context.report({
|
|
57
|
-
node: node,
|
|
58
|
-
messageId: 'onlyStringLiteral'
|
|
59
|
-
});
|
|
60
|
-
}
|
|
61
|
-
switch ((_node$parent = node.parent) === null || _node$parent === void 0 ? void 0 : _node$parent.type) {
|
|
62
|
-
case 'IfStatement':
|
|
63
|
-
case 'ConditionalExpression':
|
|
64
|
-
case 'LogicalExpression':
|
|
65
|
-
break;
|
|
66
|
-
default:
|
|
67
|
-
return context.report({
|
|
68
|
-
node: node,
|
|
69
|
-
messageId: 'onlyInlineIf'
|
|
70
|
-
});
|
|
71
|
-
break;
|
|
72
|
-
}
|
|
73
52
|
var filename = context.getFilename();
|
|
74
53
|
var packageJson = getPackageJsonForFileName(filename);
|
|
75
54
|
var platformFeatureFlags = packageJson['platform-feature-flags'];
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
Object.defineProperty(exports, "__esModule", {
|
|
5
|
+
value: true
|
|
6
|
+
});
|
|
7
|
+
exports.default = void 0;
|
|
8
|
+
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
|
|
9
|
+
var FF_GETTER_BOOLEAN_IDENTIFIER = 'getBooleanFF';
|
|
10
|
+
var __isOnlyOneFlagCheckInExpression = function __isOnlyOneFlagCheckInExpression(root, ignoredNode) {
|
|
11
|
+
switch (root.type) {
|
|
12
|
+
case 'IfStatement':
|
|
13
|
+
return __isOnlyOneFlagCheckInExpression(root.test, ignoredNode);
|
|
14
|
+
case 'CallExpression':
|
|
15
|
+
if (root === ignoredNode) {
|
|
16
|
+
return true;
|
|
17
|
+
}
|
|
18
|
+
return !(root.callee.type === 'Identifier' && root.callee.name === FF_GETTER_BOOLEAN_IDENTIFIER);
|
|
19
|
+
|
|
20
|
+
// shouldn't ever get here but just in case
|
|
21
|
+
case 'Identifier':
|
|
22
|
+
return root.name !== FF_GETTER_BOOLEAN_IDENTIFIER;
|
|
23
|
+
case 'BinaryExpression':
|
|
24
|
+
case 'LogicalExpression':
|
|
25
|
+
return __isOnlyOneFlagCheckInExpression(root.left, ignoredNode) && __isOnlyOneFlagCheckInExpression(root.right, ignoredNode);
|
|
26
|
+
default:
|
|
27
|
+
return true;
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
var isOnlyOneFlagCheckInExpression = function isOnlyOneFlagCheckInExpression(node) {
|
|
31
|
+
var root = node.parent;
|
|
32
|
+
// find the root node of the expression
|
|
33
|
+
while (root.type === 'LogicalExpression') {
|
|
34
|
+
root = root.parent;
|
|
35
|
+
}
|
|
36
|
+
return __isOnlyOneFlagCheckInExpression(root, node);
|
|
37
|
+
};
|
|
38
|
+
var rule = {
|
|
39
|
+
meta: {
|
|
40
|
+
hasSuggestions: false,
|
|
41
|
+
docs: {
|
|
42
|
+
recommended: false
|
|
43
|
+
},
|
|
44
|
+
type: 'problem',
|
|
45
|
+
messages: {
|
|
46
|
+
onlyInlineIf: "Only call feature flags as part of an expression, don't assign to a variable! See http://go/pff-eslint for more details",
|
|
47
|
+
onlyStringLiteral: "Only get feature flags by string literal, don't use variables! See http://go/pff-eslint for more details",
|
|
48
|
+
multipleFlagCheckInExpression: "Only check one flag per expression! See http://go/pff-eslint for more details"
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
create: function create(context) {
|
|
52
|
+
return (0, _defineProperty2.default)({}, "CallExpression[callee.name=/".concat(FF_GETTER_BOOLEAN_IDENTIFIER, "/]"), function CallExpressionCalleeName(node) {
|
|
53
|
+
// to make typescript happy
|
|
54
|
+
if (node.type === 'CallExpression') {
|
|
55
|
+
var _node$parent;
|
|
56
|
+
var args = node.arguments;
|
|
57
|
+
if (args.length === 1 && args[0].type !== 'Literal') {
|
|
58
|
+
return context.report({
|
|
59
|
+
node: node,
|
|
60
|
+
messageId: 'onlyStringLiteral'
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
switch ((_node$parent = node.parent) === null || _node$parent === void 0 ? void 0 : _node$parent.type) {
|
|
64
|
+
case 'IfStatement':
|
|
65
|
+
case 'ConditionalExpression':
|
|
66
|
+
break;
|
|
67
|
+
case 'LogicalExpression':
|
|
68
|
+
if (!isOnlyOneFlagCheckInExpression(node)) {
|
|
69
|
+
context.report({
|
|
70
|
+
node: node,
|
|
71
|
+
messageId: 'multipleFlagCheckInExpression'
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
break;
|
|
75
|
+
default:
|
|
76
|
+
return context.report({
|
|
77
|
+
node: node,
|
|
78
|
+
messageId: 'onlyInlineIf'
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return {};
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
var _default = rule;
|
|
87
|
+
exports.default = _default;
|
package/dist/cjs/version.json
CHANGED
package/dist/es2019/index.js
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
import ensureFeatureFlagRegistration from './rules/ensure-feature-flag-registration';
|
|
2
|
+
import noInvalidFeatureFlagUsage from './rules/no-invalid-feature-flag-usage';
|
|
2
3
|
export const rules = {
|
|
3
|
-
'ensure-feature-flag-registration': ensureFeatureFlagRegistration
|
|
4
|
+
'ensure-feature-flag-registration': ensureFeatureFlagRegistration,
|
|
5
|
+
'no-invalid-feature-flag-usage': noInvalidFeatureFlagUsage
|
|
4
6
|
};
|
|
5
7
|
export const configs = {
|
|
6
8
|
recommended: {
|
|
7
9
|
plugins: ['@atlaskit/platform'],
|
|
8
10
|
rules: {
|
|
9
|
-
'@atlaskit/platform/ensure-feature-flag-registration': 'error'
|
|
11
|
+
'@atlaskit/platform/ensure-feature-flag-registration': 'error',
|
|
12
|
+
'@atlaskit/platform/no-invalid-feature-flag-usage': 'error'
|
|
10
13
|
}
|
|
11
14
|
}
|
|
12
15
|
};
|
|
@@ -32,8 +32,6 @@ const rule = {
|
|
|
32
32
|
},
|
|
33
33
|
type: 'problem',
|
|
34
34
|
messages: {
|
|
35
|
-
onlyInlineIf: "Only call feature flags as part of an expression, don't assign to a variable! See http://go/pff-eslint for more details",
|
|
36
|
-
onlyStringLiteral: "Only get feature flags by string literal, don't use variables! See http://go/pff-eslint for more details",
|
|
37
35
|
registrationSectionMissing: 'Please add a "platform-feature-flags" section to your package.json! See http://go/pff-eslint for more details',
|
|
38
36
|
featureFlagMissing: `Please add a "{{ featureFlag }}" section to the "platform-feature-flags" section in your package.json. See http://go/pff-eslint for more details`
|
|
39
37
|
}
|
|
@@ -43,26 +41,7 @@ const rule = {
|
|
|
43
41
|
'CallExpression[callee.name=/getBooleanFF/]': node => {
|
|
44
42
|
// to make typescript happy
|
|
45
43
|
if (node.type === 'CallExpression') {
|
|
46
|
-
var _node$parent;
|
|
47
44
|
const args = node.arguments;
|
|
48
|
-
if (args.length === 1 && args[0].type !== 'Literal') {
|
|
49
|
-
return context.report({
|
|
50
|
-
node,
|
|
51
|
-
messageId: 'onlyStringLiteral'
|
|
52
|
-
});
|
|
53
|
-
}
|
|
54
|
-
switch ((_node$parent = node.parent) === null || _node$parent === void 0 ? void 0 : _node$parent.type) {
|
|
55
|
-
case 'IfStatement':
|
|
56
|
-
case 'ConditionalExpression':
|
|
57
|
-
case 'LogicalExpression':
|
|
58
|
-
break;
|
|
59
|
-
default:
|
|
60
|
-
return context.report({
|
|
61
|
-
node,
|
|
62
|
-
messageId: 'onlyInlineIf'
|
|
63
|
-
});
|
|
64
|
-
break;
|
|
65
|
-
}
|
|
66
45
|
const filename = context.getFilename();
|
|
67
46
|
const packageJson = getPackageJsonForFileName(filename);
|
|
68
47
|
const platformFeatureFlags = packageJson['platform-feature-flags'];
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
const FF_GETTER_BOOLEAN_IDENTIFIER = 'getBooleanFF';
|
|
2
|
+
const __isOnlyOneFlagCheckInExpression = (root, ignoredNode) => {
|
|
3
|
+
switch (root.type) {
|
|
4
|
+
case 'IfStatement':
|
|
5
|
+
return __isOnlyOneFlagCheckInExpression(root.test, ignoredNode);
|
|
6
|
+
case 'CallExpression':
|
|
7
|
+
if (root === ignoredNode) {
|
|
8
|
+
return true;
|
|
9
|
+
}
|
|
10
|
+
return !(root.callee.type === 'Identifier' && root.callee.name === FF_GETTER_BOOLEAN_IDENTIFIER);
|
|
11
|
+
|
|
12
|
+
// shouldn't ever get here but just in case
|
|
13
|
+
case 'Identifier':
|
|
14
|
+
return root.name !== FF_GETTER_BOOLEAN_IDENTIFIER;
|
|
15
|
+
case 'BinaryExpression':
|
|
16
|
+
case 'LogicalExpression':
|
|
17
|
+
return __isOnlyOneFlagCheckInExpression(root.left, ignoredNode) && __isOnlyOneFlagCheckInExpression(root.right, ignoredNode);
|
|
18
|
+
default:
|
|
19
|
+
return true;
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
const isOnlyOneFlagCheckInExpression = node => {
|
|
23
|
+
let root = node.parent;
|
|
24
|
+
// find the root node of the expression
|
|
25
|
+
while (root.type === 'LogicalExpression') {
|
|
26
|
+
root = root.parent;
|
|
27
|
+
}
|
|
28
|
+
return __isOnlyOneFlagCheckInExpression(root, node);
|
|
29
|
+
};
|
|
30
|
+
const rule = {
|
|
31
|
+
meta: {
|
|
32
|
+
hasSuggestions: false,
|
|
33
|
+
docs: {
|
|
34
|
+
recommended: false
|
|
35
|
+
},
|
|
36
|
+
type: 'problem',
|
|
37
|
+
messages: {
|
|
38
|
+
onlyInlineIf: "Only call feature flags as part of an expression, don't assign to a variable! See http://go/pff-eslint for more details",
|
|
39
|
+
onlyStringLiteral: "Only get feature flags by string literal, don't use variables! See http://go/pff-eslint for more details",
|
|
40
|
+
multipleFlagCheckInExpression: `Only check one flag per expression! See http://go/pff-eslint for more details`
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
create(context) {
|
|
44
|
+
return {
|
|
45
|
+
[`CallExpression[callee.name=/${FF_GETTER_BOOLEAN_IDENTIFIER}/]`]: node => {
|
|
46
|
+
// to make typescript happy
|
|
47
|
+
if (node.type === 'CallExpression') {
|
|
48
|
+
var _node$parent;
|
|
49
|
+
const args = node.arguments;
|
|
50
|
+
if (args.length === 1 && args[0].type !== 'Literal') {
|
|
51
|
+
return context.report({
|
|
52
|
+
node,
|
|
53
|
+
messageId: 'onlyStringLiteral'
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
switch ((_node$parent = node.parent) === null || _node$parent === void 0 ? void 0 : _node$parent.type) {
|
|
57
|
+
case 'IfStatement':
|
|
58
|
+
case 'ConditionalExpression':
|
|
59
|
+
break;
|
|
60
|
+
case 'LogicalExpression':
|
|
61
|
+
if (!isOnlyOneFlagCheckInExpression(node)) {
|
|
62
|
+
context.report({
|
|
63
|
+
node,
|
|
64
|
+
messageId: 'multipleFlagCheckInExpression'
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
break;
|
|
68
|
+
default:
|
|
69
|
+
return context.report({
|
|
70
|
+
node,
|
|
71
|
+
messageId: 'onlyInlineIf'
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return {};
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
export default rule;
|
package/dist/es2019/version.json
CHANGED
package/dist/esm/index.js
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
import ensureFeatureFlagRegistration from './rules/ensure-feature-flag-registration';
|
|
2
|
+
import noInvalidFeatureFlagUsage from './rules/no-invalid-feature-flag-usage';
|
|
2
3
|
export var rules = {
|
|
3
|
-
'ensure-feature-flag-registration': ensureFeatureFlagRegistration
|
|
4
|
+
'ensure-feature-flag-registration': ensureFeatureFlagRegistration,
|
|
5
|
+
'no-invalid-feature-flag-usage': noInvalidFeatureFlagUsage
|
|
4
6
|
};
|
|
5
7
|
export var configs = {
|
|
6
8
|
recommended: {
|
|
7
9
|
plugins: ['@atlaskit/platform'],
|
|
8
10
|
rules: {
|
|
9
|
-
'@atlaskit/platform/ensure-feature-flag-registration': 'error'
|
|
11
|
+
'@atlaskit/platform/ensure-feature-flag-registration': 'error',
|
|
12
|
+
'@atlaskit/platform/no-invalid-feature-flag-usage': 'error'
|
|
10
13
|
}
|
|
11
14
|
}
|
|
12
15
|
};
|
|
@@ -32,8 +32,6 @@ var rule = {
|
|
|
32
32
|
},
|
|
33
33
|
type: 'problem',
|
|
34
34
|
messages: {
|
|
35
|
-
onlyInlineIf: "Only call feature flags as part of an expression, don't assign to a variable! See http://go/pff-eslint for more details",
|
|
36
|
-
onlyStringLiteral: "Only get feature flags by string literal, don't use variables! See http://go/pff-eslint for more details",
|
|
37
35
|
registrationSectionMissing: 'Please add a "platform-feature-flags" section to your package.json! See http://go/pff-eslint for more details',
|
|
38
36
|
featureFlagMissing: "Please add a \"{{ featureFlag }}\" section to the \"platform-feature-flags\" section in your package.json. See http://go/pff-eslint for more details"
|
|
39
37
|
}
|
|
@@ -43,26 +41,7 @@ var rule = {
|
|
|
43
41
|
'CallExpression[callee.name=/getBooleanFF/]': function CallExpressionCalleeNameGetBooleanFF(node) {
|
|
44
42
|
// to make typescript happy
|
|
45
43
|
if (node.type === 'CallExpression') {
|
|
46
|
-
var _node$parent;
|
|
47
44
|
var args = node.arguments;
|
|
48
|
-
if (args.length === 1 && args[0].type !== 'Literal') {
|
|
49
|
-
return context.report({
|
|
50
|
-
node: node,
|
|
51
|
-
messageId: 'onlyStringLiteral'
|
|
52
|
-
});
|
|
53
|
-
}
|
|
54
|
-
switch ((_node$parent = node.parent) === null || _node$parent === void 0 ? void 0 : _node$parent.type) {
|
|
55
|
-
case 'IfStatement':
|
|
56
|
-
case 'ConditionalExpression':
|
|
57
|
-
case 'LogicalExpression':
|
|
58
|
-
break;
|
|
59
|
-
default:
|
|
60
|
-
return context.report({
|
|
61
|
-
node: node,
|
|
62
|
-
messageId: 'onlyInlineIf'
|
|
63
|
-
});
|
|
64
|
-
break;
|
|
65
|
-
}
|
|
66
45
|
var filename = context.getFilename();
|
|
67
46
|
var packageJson = getPackageJsonForFileName(filename);
|
|
68
47
|
var platformFeatureFlags = packageJson['platform-feature-flags'];
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
2
|
+
var FF_GETTER_BOOLEAN_IDENTIFIER = 'getBooleanFF';
|
|
3
|
+
var __isOnlyOneFlagCheckInExpression = function __isOnlyOneFlagCheckInExpression(root, ignoredNode) {
|
|
4
|
+
switch (root.type) {
|
|
5
|
+
case 'IfStatement':
|
|
6
|
+
return __isOnlyOneFlagCheckInExpression(root.test, ignoredNode);
|
|
7
|
+
case 'CallExpression':
|
|
8
|
+
if (root === ignoredNode) {
|
|
9
|
+
return true;
|
|
10
|
+
}
|
|
11
|
+
return !(root.callee.type === 'Identifier' && root.callee.name === FF_GETTER_BOOLEAN_IDENTIFIER);
|
|
12
|
+
|
|
13
|
+
// shouldn't ever get here but just in case
|
|
14
|
+
case 'Identifier':
|
|
15
|
+
return root.name !== FF_GETTER_BOOLEAN_IDENTIFIER;
|
|
16
|
+
case 'BinaryExpression':
|
|
17
|
+
case 'LogicalExpression':
|
|
18
|
+
return __isOnlyOneFlagCheckInExpression(root.left, ignoredNode) && __isOnlyOneFlagCheckInExpression(root.right, ignoredNode);
|
|
19
|
+
default:
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
var isOnlyOneFlagCheckInExpression = function isOnlyOneFlagCheckInExpression(node) {
|
|
24
|
+
var root = node.parent;
|
|
25
|
+
// find the root node of the expression
|
|
26
|
+
while (root.type === 'LogicalExpression') {
|
|
27
|
+
root = root.parent;
|
|
28
|
+
}
|
|
29
|
+
return __isOnlyOneFlagCheckInExpression(root, node);
|
|
30
|
+
};
|
|
31
|
+
var rule = {
|
|
32
|
+
meta: {
|
|
33
|
+
hasSuggestions: false,
|
|
34
|
+
docs: {
|
|
35
|
+
recommended: false
|
|
36
|
+
},
|
|
37
|
+
type: 'problem',
|
|
38
|
+
messages: {
|
|
39
|
+
onlyInlineIf: "Only call feature flags as part of an expression, don't assign to a variable! See http://go/pff-eslint for more details",
|
|
40
|
+
onlyStringLiteral: "Only get feature flags by string literal, don't use variables! See http://go/pff-eslint for more details",
|
|
41
|
+
multipleFlagCheckInExpression: "Only check one flag per expression! See http://go/pff-eslint for more details"
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
create: function create(context) {
|
|
45
|
+
return _defineProperty({}, "CallExpression[callee.name=/".concat(FF_GETTER_BOOLEAN_IDENTIFIER, "/]"), function CallExpressionCalleeName(node) {
|
|
46
|
+
// to make typescript happy
|
|
47
|
+
if (node.type === 'CallExpression') {
|
|
48
|
+
var _node$parent;
|
|
49
|
+
var args = node.arguments;
|
|
50
|
+
if (args.length === 1 && args[0].type !== 'Literal') {
|
|
51
|
+
return context.report({
|
|
52
|
+
node: node,
|
|
53
|
+
messageId: 'onlyStringLiteral'
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
switch ((_node$parent = node.parent) === null || _node$parent === void 0 ? void 0 : _node$parent.type) {
|
|
57
|
+
case 'IfStatement':
|
|
58
|
+
case 'ConditionalExpression':
|
|
59
|
+
break;
|
|
60
|
+
case 'LogicalExpression':
|
|
61
|
+
if (!isOnlyOneFlagCheckInExpression(node)) {
|
|
62
|
+
context.report({
|
|
63
|
+
node: node,
|
|
64
|
+
messageId: 'multipleFlagCheckInExpression'
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
break;
|
|
68
|
+
default:
|
|
69
|
+
return context.report({
|
|
70
|
+
node: node,
|
|
71
|
+
messageId: 'onlyInlineIf'
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return {};
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
export default rule;
|
package/dist/esm/version.json
CHANGED
package/dist/types/index.d.ts
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
export declare const rules: {
|
|
2
2
|
'ensure-feature-flag-registration': import("eslint").Rule.RuleModule;
|
|
3
|
+
'no-invalid-feature-flag-usage': import("eslint").Rule.RuleModule;
|
|
3
4
|
};
|
|
4
5
|
export declare const configs: {
|
|
5
6
|
recommended: {
|
|
6
7
|
plugins: string[];
|
|
7
8
|
rules: {
|
|
8
9
|
'@atlaskit/platform/ensure-feature-flag-registration': string;
|
|
10
|
+
'@atlaskit/platform/no-invalid-feature-flag-usage': string;
|
|
9
11
|
};
|
|
10
12
|
};
|
|
11
13
|
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlaskit/eslint-plugin-platform",
|
|
3
3
|
"description": "The essential plugin for use with Atlassian frontend platform tools",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.5",
|
|
5
5
|
"author": "Atlassian Pty Ltd",
|
|
6
6
|
"atlassian": {
|
|
7
7
|
"team": "UIP - Platform Integration Trust (PITa)",
|
package/report.api.md
CHANGED
|
@@ -23,6 +23,7 @@ export const configs: {
|
|
|
23
23
|
plugins: string[];
|
|
24
24
|
rules: {
|
|
25
25
|
'@atlaskit/platform/ensure-feature-flag-registration': string;
|
|
26
|
+
'@atlaskit/platform/no-invalid-feature-flag-usage': string;
|
|
26
27
|
};
|
|
27
28
|
};
|
|
28
29
|
};
|
|
@@ -30,6 +31,7 @@ export const configs: {
|
|
|
30
31
|
// @public (undocumented)
|
|
31
32
|
export const rules: {
|
|
32
33
|
'ensure-feature-flag-registration': Rule.RuleModule;
|
|
34
|
+
'no-invalid-feature-flag-usage': Rule.RuleModule;
|
|
33
35
|
};
|
|
34
36
|
|
|
35
37
|
// (No @packageDocumentation comment for this package)
|
package/src/index.tsx
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import ensureFeatureFlagRegistration from './rules/ensure-feature-flag-registration';
|
|
2
|
+
import noInvalidFeatureFlagUsage from './rules/no-invalid-feature-flag-usage';
|
|
2
3
|
|
|
3
4
|
export const rules = {
|
|
4
5
|
'ensure-feature-flag-registration': ensureFeatureFlagRegistration,
|
|
6
|
+
'no-invalid-feature-flag-usage': noInvalidFeatureFlagUsage,
|
|
5
7
|
};
|
|
6
8
|
|
|
7
9
|
export const configs = {
|
|
@@ -9,6 +11,7 @@ export const configs = {
|
|
|
9
11
|
plugins: ['@atlaskit/platform'],
|
|
10
12
|
rules: {
|
|
11
13
|
'@atlaskit/platform/ensure-feature-flag-registration': 'error',
|
|
14
|
+
'@atlaskit/platform/no-invalid-feature-flag-usage': 'error',
|
|
12
15
|
},
|
|
13
16
|
},
|
|
14
17
|
};
|
|
@@ -34,35 +34,14 @@ describe('with existing platform-feature-flags section', () => {
|
|
|
34
34
|
tester.run('ensure-feature-flag-registration', rule, {
|
|
35
35
|
valid: [
|
|
36
36
|
{
|
|
37
|
-
|
|
38
|
-
code: `if(getBooleanFF('test-flag')) { }`,
|
|
39
|
-
},
|
|
40
|
-
{
|
|
41
|
-
// ConditionalExpression
|
|
42
|
-
code: `const val = getBooleanFF('test-flag') ? 'yay' : 'no';`,
|
|
43
|
-
},
|
|
44
|
-
{
|
|
45
|
-
// LogicalExpression
|
|
46
|
-
code: `const val = 100 + (getBooleanFF('test-flag') && 50 || 10);`,
|
|
37
|
+
code: `getBooleanFF('test-flag')`,
|
|
47
38
|
},
|
|
48
39
|
],
|
|
49
40
|
invalid: [
|
|
50
41
|
{
|
|
51
|
-
code: `getBooleanFF('
|
|
52
|
-
errors: [{ messageId: 'onlyInlineIf' }],
|
|
53
|
-
},
|
|
54
|
-
{
|
|
55
|
-
code: `const val = getBooleanFF('test-flag')`,
|
|
56
|
-
errors: [{ messageId: 'onlyInlineIf' }],
|
|
57
|
-
},
|
|
58
|
-
{
|
|
59
|
-
code: `if(getBooleanFF('invalid-flag')) { }`,
|
|
42
|
+
code: `getBooleanFF('invalid-flag')`,
|
|
60
43
|
errors: [{ messageId: 'featureFlagMissing' }],
|
|
61
44
|
},
|
|
62
|
-
{
|
|
63
|
-
code: `const ff = "test-flag"; if(getBooleanFF(ff)) { }`,
|
|
64
|
-
errors: [{ messageId: 'onlyStringLiteral' }],
|
|
65
|
-
},
|
|
66
45
|
],
|
|
67
46
|
});
|
|
68
47
|
});
|
|
@@ -41,10 +41,6 @@ const rule: Rule.RuleModule = {
|
|
|
41
41
|
},
|
|
42
42
|
type: 'problem',
|
|
43
43
|
messages: {
|
|
44
|
-
onlyInlineIf:
|
|
45
|
-
"Only call feature flags as part of an expression, don't assign to a variable! See http://go/pff-eslint for more details",
|
|
46
|
-
onlyStringLiteral:
|
|
47
|
-
"Only get feature flags by string literal, don't use variables! See http://go/pff-eslint for more details",
|
|
48
44
|
registrationSectionMissing:
|
|
49
45
|
'Please add a "platform-feature-flags" section to your package.json! See http://go/pff-eslint for more details',
|
|
50
46
|
featureFlagMissing: `Please add a "{{ featureFlag }}" section to the "platform-feature-flags" section in your package.json. See http://go/pff-eslint for more details`,
|
|
@@ -57,26 +53,6 @@ const rule: Rule.RuleModule = {
|
|
|
57
53
|
if (node.type === 'CallExpression') {
|
|
58
54
|
const args = node.arguments;
|
|
59
55
|
|
|
60
|
-
if (args.length === 1 && args[0].type !== 'Literal') {
|
|
61
|
-
return context.report({
|
|
62
|
-
node,
|
|
63
|
-
messageId: 'onlyStringLiteral',
|
|
64
|
-
});
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
switch (node.parent?.type) {
|
|
68
|
-
case 'IfStatement':
|
|
69
|
-
case 'ConditionalExpression':
|
|
70
|
-
case 'LogicalExpression':
|
|
71
|
-
break;
|
|
72
|
-
default:
|
|
73
|
-
return context.report({
|
|
74
|
-
node,
|
|
75
|
-
messageId: 'onlyInlineIf',
|
|
76
|
-
});
|
|
77
|
-
break;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
56
|
const filename = context.getFilename();
|
|
81
57
|
const packageJson = getPackageJsonForFileName(filename);
|
|
82
58
|
const platformFeatureFlags = packageJson[
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { tester } from '../../../../__tests__/utils/_tester';
|
|
2
|
+
import rule from '../../index';
|
|
3
|
+
|
|
4
|
+
describe('enforce-feature-flag-usage-structure tests', () => {
|
|
5
|
+
tester.run('ensure-feature-flag-registration', rule, {
|
|
6
|
+
valid: [
|
|
7
|
+
{
|
|
8
|
+
// IfStatement
|
|
9
|
+
code: `if(getBooleanFF('test-flag')) { }`,
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
// ConditionalExpression
|
|
13
|
+
code: `const val = getBooleanFF('test-flag') ? 'yay' : 'no';`,
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
// LogicalExpression
|
|
17
|
+
code: `const val = 100 + (getBooleanFF('test-flag') && 50 || 10);`,
|
|
18
|
+
},
|
|
19
|
+
],
|
|
20
|
+
invalid: [
|
|
21
|
+
{
|
|
22
|
+
code: `getBooleanFF('test-flag')`,
|
|
23
|
+
errors: [{ messageId: 'onlyInlineIf' }],
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
code: `const val = getBooleanFF('test-flag')`,
|
|
27
|
+
errors: [{ messageId: 'onlyInlineIf' }],
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
code: `const ff = "test-flag"; if(getBooleanFF(ff)) { }`,
|
|
31
|
+
errors: [{ messageId: 'onlyStringLiteral' }],
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
code: `if(getBooleanFF('test-flag') && getBooleanFF('test-flag')) { }`,
|
|
35
|
+
errors: [
|
|
36
|
+
{ messageId: 'multipleFlagCheckInExpression' },
|
|
37
|
+
{ messageId: 'multipleFlagCheckInExpression' },
|
|
38
|
+
],
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
code: `if((getBooleanFF('test-flag') || 1 == true) && getBooleanFF('test-flag')) { }`,
|
|
42
|
+
errors: [
|
|
43
|
+
{ messageId: 'multipleFlagCheckInExpression' },
|
|
44
|
+
{ messageId: 'multipleFlagCheckInExpression' },
|
|
45
|
+
],
|
|
46
|
+
},
|
|
47
|
+
],
|
|
48
|
+
});
|
|
49
|
+
});
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import type { Rule } from 'eslint';
|
|
2
|
+
|
|
3
|
+
const FF_GETTER_BOOLEAN_IDENTIFIER = 'getBooleanFF' as const;
|
|
4
|
+
|
|
5
|
+
const __isOnlyOneFlagCheckInExpression = (
|
|
6
|
+
root: Rule.Node,
|
|
7
|
+
ignoredNode: Rule.Node,
|
|
8
|
+
): boolean => {
|
|
9
|
+
switch (root.type) {
|
|
10
|
+
case 'IfStatement':
|
|
11
|
+
return __isOnlyOneFlagCheckInExpression(
|
|
12
|
+
root.test as Rule.Node,
|
|
13
|
+
ignoredNode,
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
case 'CallExpression':
|
|
17
|
+
if (root === ignoredNode) {
|
|
18
|
+
return true;
|
|
19
|
+
}
|
|
20
|
+
return !(
|
|
21
|
+
root.callee.type === 'Identifier' &&
|
|
22
|
+
root.callee.name === FF_GETTER_BOOLEAN_IDENTIFIER
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
// shouldn't ever get here but just in case
|
|
26
|
+
case 'Identifier':
|
|
27
|
+
return root.name !== FF_GETTER_BOOLEAN_IDENTIFIER;
|
|
28
|
+
|
|
29
|
+
case 'BinaryExpression':
|
|
30
|
+
case 'LogicalExpression':
|
|
31
|
+
return (
|
|
32
|
+
__isOnlyOneFlagCheckInExpression(root.left as Rule.Node, ignoredNode) &&
|
|
33
|
+
__isOnlyOneFlagCheckInExpression(root.right as Rule.Node, ignoredNode)
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
default:
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const isOnlyOneFlagCheckInExpression = (node: Rule.Node): boolean => {
|
|
42
|
+
let root = node.parent;
|
|
43
|
+
// find the root node of the expression
|
|
44
|
+
while (root.type === 'LogicalExpression') {
|
|
45
|
+
root = root.parent;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return __isOnlyOneFlagCheckInExpression(root, node);
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const rule: Rule.RuleModule = {
|
|
52
|
+
meta: {
|
|
53
|
+
hasSuggestions: false,
|
|
54
|
+
docs: {
|
|
55
|
+
recommended: false,
|
|
56
|
+
},
|
|
57
|
+
type: 'problem',
|
|
58
|
+
messages: {
|
|
59
|
+
onlyInlineIf:
|
|
60
|
+
"Only call feature flags as part of an expression, don't assign to a variable! See http://go/pff-eslint for more details",
|
|
61
|
+
onlyStringLiteral:
|
|
62
|
+
"Only get feature flags by string literal, don't use variables! See http://go/pff-eslint for more details",
|
|
63
|
+
multipleFlagCheckInExpression: `Only check one flag per expression! See http://go/pff-eslint for more details`,
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
create(context) {
|
|
67
|
+
return {
|
|
68
|
+
[`CallExpression[callee.name=/${FF_GETTER_BOOLEAN_IDENTIFIER}/]`]: (
|
|
69
|
+
node: Rule.Node,
|
|
70
|
+
) => {
|
|
71
|
+
// to make typescript happy
|
|
72
|
+
if (node.type === 'CallExpression') {
|
|
73
|
+
const args = node.arguments;
|
|
74
|
+
|
|
75
|
+
if (args.length === 1 && args[0].type !== 'Literal') {
|
|
76
|
+
return context.report({
|
|
77
|
+
node,
|
|
78
|
+
messageId: 'onlyStringLiteral',
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
switch (node.parent?.type) {
|
|
83
|
+
case 'IfStatement':
|
|
84
|
+
case 'ConditionalExpression':
|
|
85
|
+
break;
|
|
86
|
+
case 'LogicalExpression':
|
|
87
|
+
if (!isOnlyOneFlagCheckInExpression(node)) {
|
|
88
|
+
context.report({
|
|
89
|
+
node,
|
|
90
|
+
messageId: 'multipleFlagCheckInExpression',
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
break;
|
|
94
|
+
default:
|
|
95
|
+
return context.report({
|
|
96
|
+
node,
|
|
97
|
+
messageId: 'onlyInlineIf',
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return {};
|
|
103
|
+
},
|
|
104
|
+
};
|
|
105
|
+
},
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
export default rule;
|
package/tmp/api-report-tmp.d.ts
CHANGED
|
@@ -12,6 +12,7 @@ export const configs: {
|
|
|
12
12
|
plugins: string[];
|
|
13
13
|
rules: {
|
|
14
14
|
'@atlaskit/platform/ensure-feature-flag-registration': string;
|
|
15
|
+
'@atlaskit/platform/no-invalid-feature-flag-usage': string;
|
|
15
16
|
};
|
|
16
17
|
};
|
|
17
18
|
};
|
|
@@ -19,6 +20,7 @@ export const configs: {
|
|
|
19
20
|
// @public (undocumented)
|
|
20
21
|
export const rules: {
|
|
21
22
|
'ensure-feature-flag-registration': Rule.RuleModule;
|
|
23
|
+
'no-invalid-feature-flag-usage': Rule.RuleModule;
|
|
22
24
|
};
|
|
23
25
|
|
|
24
26
|
// (No @packageDocumentation comment for this package)
|