@atlaskit/eslint-plugin-platform 0.0.4 → 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 CHANGED
@@ -1,5 +1,11 @@
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
+
3
9
  ## 0.0.4
4
10
 
5
11
  ### 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
  };
@@ -31,34 +31,6 @@ var getPackageJsonForFileName = function getPackageJsonForFileName(filename) {
31
31
  pkgJsonCache.set(pkgJsonPath, packageJson);
32
32
  return packageJson;
33
33
  };
34
- var __isOnlyOneFlagCheckInExpression = function __isOnlyOneFlagCheckInExpression(root, ignoredNode) {
35
- switch (root.type) {
36
- case 'IfStatement':
37
- return __isOnlyOneFlagCheckInExpression(root.test, ignoredNode);
38
- case 'CallExpression':
39
- if (root === ignoredNode) {
40
- return true;
41
- }
42
- return !(root.callee.type === 'Identifier' && root.callee.name === 'getBooleanFF');
43
-
44
- // shouldn't ever get here but just in case
45
- case 'Identifier':
46
- return root.name !== 'getBooleanFF';
47
- case 'BinaryExpression':
48
- case 'LogicalExpression':
49
- return __isOnlyOneFlagCheckInExpression(root.left, ignoredNode) && __isOnlyOneFlagCheckInExpression(root.right, ignoredNode);
50
- default:
51
- return true;
52
- }
53
- };
54
- var isOnlyOneFlagCheckInExpression = function isOnlyOneFlagCheckInExpression(node) {
55
- var root = node.parent;
56
- // find the root node of the expression
57
- while (root.type === 'LogicalExpression') {
58
- root = root.parent;
59
- }
60
- return __isOnlyOneFlagCheckInExpression(root, node);
61
- };
62
34
  var rule = {
63
35
  meta: {
64
36
  hasSuggestions: false,
@@ -67,11 +39,8 @@ var rule = {
67
39
  },
68
40
  type: 'problem',
69
41
  messages: {
70
- onlyInlineIf: "Only call feature flags as part of an expression, don't assign to a variable! See http://go/pff-eslint for more details",
71
- onlyStringLiteral: "Only get feature flags by string literal, don't use variables! See http://go/pff-eslint for more details",
72
42
  registrationSectionMissing: 'Please add a "platform-feature-flags" section to your package.json! See http://go/pff-eslint for more details',
73
- featureFlagMissing: "Please add a \"{{ featureFlag }}\" section to the \"platform-feature-flags\" section in your package.json. See http://go/pff-eslint for more details",
74
- multipleFlagCheckInExpression: "Only check one flag per expression! See http://go/pff-eslint for more details"
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"
75
44
  }
76
45
  },
77
46
  create: function create(context) {
@@ -79,33 +48,7 @@ var rule = {
79
48
  'CallExpression[callee.name=/getBooleanFF/]': function CallExpressionCalleeNameGetBooleanFF(node) {
80
49
  // to make typescript happy
81
50
  if (node.type === 'CallExpression') {
82
- var _node$parent;
83
51
  var args = node.arguments;
84
- if (args.length === 1 && args[0].type !== 'Literal') {
85
- return context.report({
86
- node: node,
87
- messageId: 'onlyStringLiteral'
88
- });
89
- }
90
- switch ((_node$parent = node.parent) === null || _node$parent === void 0 ? void 0 : _node$parent.type) {
91
- case 'IfStatement':
92
- case 'ConditionalExpression':
93
- break;
94
- case 'LogicalExpression':
95
- if (!isOnlyOneFlagCheckInExpression(node)) {
96
- context.report({
97
- node: node,
98
- messageId: 'multipleFlagCheckInExpression'
99
- });
100
- }
101
- break;
102
- default:
103
- return context.report({
104
- node: node,
105
- messageId: 'onlyInlineIf'
106
- });
107
- break;
108
- }
109
52
  var filename = context.getFilename();
110
53
  var packageJson = getPackageJsonForFileName(filename);
111
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;
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@atlaskit/eslint-plugin-platform",
3
- "version": "0.0.4",
3
+ "version": "0.0.5",
4
4
  "sideEffects": false
5
5
  }
@@ -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
  };
@@ -24,34 +24,6 @@ const getPackageJsonForFileName = filename => {
24
24
  pkgJsonCache.set(pkgJsonPath, packageJson);
25
25
  return packageJson;
26
26
  };
27
- const __isOnlyOneFlagCheckInExpression = (root, ignoredNode) => {
28
- switch (root.type) {
29
- case 'IfStatement':
30
- return __isOnlyOneFlagCheckInExpression(root.test, ignoredNode);
31
- case 'CallExpression':
32
- if (root === ignoredNode) {
33
- return true;
34
- }
35
- return !(root.callee.type === 'Identifier' && root.callee.name === 'getBooleanFF');
36
-
37
- // shouldn't ever get here but just in case
38
- case 'Identifier':
39
- return root.name !== 'getBooleanFF';
40
- case 'BinaryExpression':
41
- case 'LogicalExpression':
42
- return __isOnlyOneFlagCheckInExpression(root.left, ignoredNode) && __isOnlyOneFlagCheckInExpression(root.right, ignoredNode);
43
- default:
44
- return true;
45
- }
46
- };
47
- const isOnlyOneFlagCheckInExpression = node => {
48
- let root = node.parent;
49
- // find the root node of the expression
50
- while (root.type === 'LogicalExpression') {
51
- root = root.parent;
52
- }
53
- return __isOnlyOneFlagCheckInExpression(root, node);
54
- };
55
27
  const rule = {
56
28
  meta: {
57
29
  hasSuggestions: false,
@@ -60,11 +32,8 @@ const rule = {
60
32
  },
61
33
  type: 'problem',
62
34
  messages: {
63
- onlyInlineIf: "Only call feature flags as part of an expression, don't assign to a variable! See http://go/pff-eslint for more details",
64
- onlyStringLiteral: "Only get feature flags by string literal, don't use variables! See http://go/pff-eslint for more details",
65
35
  registrationSectionMissing: 'Please add a "platform-feature-flags" section to your package.json! See http://go/pff-eslint for more details',
66
- featureFlagMissing: `Please add a "{{ featureFlag }}" section to the "platform-feature-flags" section in your package.json. See http://go/pff-eslint for more details`,
67
- multipleFlagCheckInExpression: `Only check one flag per expression! See http://go/pff-eslint for more details`
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`
68
37
  }
69
38
  },
70
39
  create(context) {
@@ -72,33 +41,7 @@ const rule = {
72
41
  'CallExpression[callee.name=/getBooleanFF/]': node => {
73
42
  // to make typescript happy
74
43
  if (node.type === 'CallExpression') {
75
- var _node$parent;
76
44
  const args = node.arguments;
77
- if (args.length === 1 && args[0].type !== 'Literal') {
78
- return context.report({
79
- node,
80
- messageId: 'onlyStringLiteral'
81
- });
82
- }
83
- switch ((_node$parent = node.parent) === null || _node$parent === void 0 ? void 0 : _node$parent.type) {
84
- case 'IfStatement':
85
- case 'ConditionalExpression':
86
- break;
87
- case 'LogicalExpression':
88
- if (!isOnlyOneFlagCheckInExpression(node)) {
89
- context.report({
90
- node,
91
- messageId: 'multipleFlagCheckInExpression'
92
- });
93
- }
94
- break;
95
- default:
96
- return context.report({
97
- node,
98
- messageId: 'onlyInlineIf'
99
- });
100
- break;
101
- }
102
45
  const filename = context.getFilename();
103
46
  const packageJson = getPackageJsonForFileName(filename);
104
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;
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@atlaskit/eslint-plugin-platform",
3
- "version": "0.0.4",
3
+ "version": "0.0.5",
4
4
  "sideEffects": false
5
5
  }
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
  };
@@ -24,34 +24,6 @@ var getPackageJsonForFileName = function getPackageJsonForFileName(filename) {
24
24
  pkgJsonCache.set(pkgJsonPath, packageJson);
25
25
  return packageJson;
26
26
  };
27
- var __isOnlyOneFlagCheckInExpression = function __isOnlyOneFlagCheckInExpression(root, ignoredNode) {
28
- switch (root.type) {
29
- case 'IfStatement':
30
- return __isOnlyOneFlagCheckInExpression(root.test, ignoredNode);
31
- case 'CallExpression':
32
- if (root === ignoredNode) {
33
- return true;
34
- }
35
- return !(root.callee.type === 'Identifier' && root.callee.name === 'getBooleanFF');
36
-
37
- // shouldn't ever get here but just in case
38
- case 'Identifier':
39
- return root.name !== 'getBooleanFF';
40
- case 'BinaryExpression':
41
- case 'LogicalExpression':
42
- return __isOnlyOneFlagCheckInExpression(root.left, ignoredNode) && __isOnlyOneFlagCheckInExpression(root.right, ignoredNode);
43
- default:
44
- return true;
45
- }
46
- };
47
- var isOnlyOneFlagCheckInExpression = function isOnlyOneFlagCheckInExpression(node) {
48
- var root = node.parent;
49
- // find the root node of the expression
50
- while (root.type === 'LogicalExpression') {
51
- root = root.parent;
52
- }
53
- return __isOnlyOneFlagCheckInExpression(root, node);
54
- };
55
27
  var rule = {
56
28
  meta: {
57
29
  hasSuggestions: false,
@@ -60,11 +32,8 @@ var rule = {
60
32
  },
61
33
  type: 'problem',
62
34
  messages: {
63
- onlyInlineIf: "Only call feature flags as part of an expression, don't assign to a variable! See http://go/pff-eslint for more details",
64
- onlyStringLiteral: "Only get feature flags by string literal, don't use variables! See http://go/pff-eslint for more details",
65
35
  registrationSectionMissing: 'Please add a "platform-feature-flags" section to your package.json! See http://go/pff-eslint for more details',
66
- featureFlagMissing: "Please add a \"{{ featureFlag }}\" section to the \"platform-feature-flags\" section in your package.json. See http://go/pff-eslint for more details",
67
- multipleFlagCheckInExpression: "Only check one flag per expression! See http://go/pff-eslint for more details"
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"
68
37
  }
69
38
  },
70
39
  create: function create(context) {
@@ -72,33 +41,7 @@ var rule = {
72
41
  'CallExpression[callee.name=/getBooleanFF/]': function CallExpressionCalleeNameGetBooleanFF(node) {
73
42
  // to make typescript happy
74
43
  if (node.type === 'CallExpression') {
75
- var _node$parent;
76
44
  var args = node.arguments;
77
- if (args.length === 1 && args[0].type !== 'Literal') {
78
- return context.report({
79
- node: node,
80
- messageId: 'onlyStringLiteral'
81
- });
82
- }
83
- switch ((_node$parent = node.parent) === null || _node$parent === void 0 ? void 0 : _node$parent.type) {
84
- case 'IfStatement':
85
- case 'ConditionalExpression':
86
- break;
87
- case 'LogicalExpression':
88
- if (!isOnlyOneFlagCheckInExpression(node)) {
89
- context.report({
90
- node: node,
91
- messageId: 'multipleFlagCheckInExpression'
92
- });
93
- }
94
- break;
95
- default:
96
- return context.report({
97
- node: node,
98
- messageId: 'onlyInlineIf'
99
- });
100
- break;
101
- }
102
45
  var filename = context.getFilename();
103
46
  var packageJson = getPackageJsonForFileName(filename);
104
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;
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@atlaskit/eslint-plugin-platform",
3
- "version": "0.0.4",
3
+ "version": "0.0.5",
4
4
  "sideEffects": false
5
5
  }
@@ -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
  };
@@ -0,0 +1,3 @@
1
+ import type { Rule } from 'eslint';
2
+ declare const rule: Rule.RuleModule;
3
+ export default rule;
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",
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,49 +34,14 @@ describe('with existing platform-feature-flags section', () => {
34
34
  tester.run('ensure-feature-flag-registration', rule, {
35
35
  valid: [
36
36
  {
37
- // IfStatement
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('test-flag')`,
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
- {
67
- code: `if(getBooleanFF('test-flag') && getBooleanFF('test-flag')) { }`,
68
- errors: [
69
- { messageId: 'multipleFlagCheckInExpression' },
70
- { messageId: 'multipleFlagCheckInExpression' },
71
- ],
72
- },
73
- {
74
- code: `if((getBooleanFF('test-flag') || 1 == true) && getBooleanFF('test-flag')) { }`,
75
- errors: [
76
- { messageId: 'multipleFlagCheckInExpression' },
77
- { messageId: 'multipleFlagCheckInExpression' },
78
- ],
79
- },
80
45
  ],
81
46
  });
82
47
  });
@@ -33,51 +33,6 @@ const getPackageJsonForFileName = (filename: string): readPkgUp.PackageJson => {
33
33
  return packageJson;
34
34
  };
35
35
 
36
- const __isOnlyOneFlagCheckInExpression = (
37
- root: Rule.Node,
38
- ignoredNode: Rule.Node,
39
- ): boolean => {
40
- switch (root.type) {
41
- case 'IfStatement':
42
- return __isOnlyOneFlagCheckInExpression(
43
- root.test as Rule.Node,
44
- ignoredNode,
45
- );
46
-
47
- case 'CallExpression':
48
- if (root === ignoredNode) {
49
- return true;
50
- }
51
- return !(
52
- root.callee.type === 'Identifier' && root.callee.name === 'getBooleanFF'
53
- );
54
-
55
- // shouldn't ever get here but just in case
56
- case 'Identifier':
57
- return root.name !== 'getBooleanFF';
58
-
59
- case 'BinaryExpression':
60
- case 'LogicalExpression':
61
- return (
62
- __isOnlyOneFlagCheckInExpression(root.left as Rule.Node, ignoredNode) &&
63
- __isOnlyOneFlagCheckInExpression(root.right as Rule.Node, ignoredNode)
64
- );
65
-
66
- default:
67
- return true;
68
- }
69
- };
70
-
71
- const isOnlyOneFlagCheckInExpression = (node: Rule.Node): boolean => {
72
- let root = node.parent;
73
- // find the root node of the expression
74
- while (root.type === 'LogicalExpression') {
75
- root = root.parent;
76
- }
77
-
78
- return __isOnlyOneFlagCheckInExpression(root, node);
79
- };
80
-
81
36
  const rule: Rule.RuleModule = {
82
37
  meta: {
83
38
  hasSuggestions: false,
@@ -86,14 +41,9 @@ const rule: Rule.RuleModule = {
86
41
  },
87
42
  type: 'problem',
88
43
  messages: {
89
- onlyInlineIf:
90
- "Only call feature flags as part of an expression, don't assign to a variable! See http://go/pff-eslint for more details",
91
- onlyStringLiteral:
92
- "Only get feature flags by string literal, don't use variables! See http://go/pff-eslint for more details",
93
44
  registrationSectionMissing:
94
45
  'Please add a "platform-feature-flags" section to your package.json! See http://go/pff-eslint for more details',
95
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`,
96
- multipleFlagCheckInExpression: `Only check one flag per expression! See http://go/pff-eslint for more details`,
97
47
  },
98
48
  },
99
49
  create(context) {
@@ -103,33 +53,6 @@ const rule: Rule.RuleModule = {
103
53
  if (node.type === 'CallExpression') {
104
54
  const args = node.arguments;
105
55
 
106
- if (args.length === 1 && args[0].type !== 'Literal') {
107
- return context.report({
108
- node,
109
- messageId: 'onlyStringLiteral',
110
- });
111
- }
112
-
113
- switch (node.parent?.type) {
114
- case 'IfStatement':
115
- case 'ConditionalExpression':
116
- break;
117
- case 'LogicalExpression':
118
- if (!isOnlyOneFlagCheckInExpression(node)) {
119
- context.report({
120
- node,
121
- messageId: 'multipleFlagCheckInExpression',
122
- });
123
- }
124
- break;
125
- default:
126
- return context.report({
127
- node,
128
- messageId: 'onlyInlineIf',
129
- });
130
- break;
131
- }
132
-
133
56
  const filename = context.getFilename();
134
57
  const packageJson = getPackageJsonForFileName(filename);
135
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;
@@ -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)