@atlaskit/eslint-plugin-platform 0.2.6 → 0.3.0

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 (29) hide show
  1. package/CHANGELOG.md +28 -22
  2. package/dist/cjs/index.js +26 -11
  3. package/dist/cjs/rules/ensure-atlassian-team/index.js +1 -2
  4. package/dist/cjs/rules/ensure-critical-dependency-resolutions/index.js +1 -2
  5. package/dist/cjs/rules/ensure-feature-flag-prefix/index.js +1 -2
  6. package/dist/cjs/rules/ensure-feature-flag-registration/index.js +1 -2
  7. package/dist/cjs/rules/ensure-publish-valid/index.js +1 -2
  8. package/dist/cjs/rules/ensure-test-runner-arguments/index.js +1 -2
  9. package/dist/cjs/rules/ensure-test-runner-nested-count/index.js +1 -2
  10. package/dist/cjs/rules/no-duplicate-dependencies/index.js +90 -0
  11. package/dist/cjs/rules/no-invalid-feature-flag-usage/index.js +1 -2
  12. package/dist/cjs/rules/no-invalid-storybook-decorator-usage/index.js +1 -2
  13. package/dist/cjs/rules/no-pre-post-installs/index.js +1 -2
  14. package/dist/cjs/rules/util/handle-ast-object.js +3 -5
  15. package/dist/cjs/rules/util/registration-utils.js +3 -5
  16. package/dist/es2019/index.js +23 -2
  17. package/dist/es2019/rules/no-duplicate-dependencies/index.js +65 -0
  18. package/dist/esm/index.js +22 -4
  19. package/dist/esm/rules/no-duplicate-dependencies/index.js +83 -0
  20. package/dist/types/index.d.ts +1 -0
  21. package/dist/types/rules/no-duplicate-dependencies/index.d.ts +3 -0
  22. package/dist/types-ts4.5/index.d.ts +1 -0
  23. package/dist/types-ts4.5/rules/no-duplicate-dependencies/index.d.ts +3 -0
  24. package/package.json +2 -2
  25. package/report.api.md +1 -0
  26. package/src/index.tsx +24 -4
  27. package/src/rules/no-duplicate-dependencies/__tests__/unit/rule.test.ts +116 -0
  28. package/src/rules/no-duplicate-dependencies/index.ts +83 -0
  29. package/tmp/api-report-tmp.d.ts +1 -0
package/CHANGELOG.md CHANGED
@@ -1,133 +1,139 @@
1
1
  # @atlaskit/eslint-plugin-platform
2
2
 
3
+ ## 0.3.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#41190](https://bitbucket.org/atlassian/atlassian-frontend/pull-requests/41190) [`a5047d254d4`](https://bitbucket.org/atlassian/atlassian-frontend/commits/a5047d254d4) - Add no-duplicate-dependencies rule and enable package-json-processor autofix
8
+
3
9
  ## 0.2.6
4
10
 
5
11
  ### Patch Changes
6
12
 
7
- - [`7efeb93141c`](https://bitbucket.org/atlassian/atlassian-frontend/commits/7efeb93141c) - Add a rule to ensure critical packages are resolved to the correct versions
13
+ - [#39249](https://bitbucket.org/atlassian/atlassian-frontend/pull-requests/39249) [`7efeb93141c`](https://bitbucket.org/atlassian/atlassian-frontend/commits/7efeb93141c) - Add a rule to ensure critical packages are resolved to the correct versions
8
14
 
9
15
  ## 0.2.5
10
16
 
11
17
  ### Patch Changes
12
18
 
13
- - [`e5f52093b2a`](https://bitbucket.org/atlassian/atlassian-frontend/commits/e5f52093b2a) - Add a rule to ensure that publish config is correct for packages
19
+ - [#39049](https://bitbucket.org/atlassian/atlassian-frontend/pull-requests/39049) [`e5f52093b2a`](https://bitbucket.org/atlassian/atlassian-frontend/commits/e5f52093b2a) - Add a rule to ensure that publish config is correct for packages
14
20
 
15
21
  ## 0.2.4
16
22
 
17
23
  ### Patch Changes
18
24
 
19
- - [`eb64cbdd681`](https://bitbucket.org/atlassian/atlassian-frontend/commits/eb64cbdd681) - Add a new rule to verify that the atlassian team is defined if the relevant section exists in the package.json
25
+ - [#38261](https://bitbucket.org/atlassian/atlassian-frontend/pull-requests/38261) [`eb64cbdd681`](https://bitbucket.org/atlassian/atlassian-frontend/commits/eb64cbdd681) - Add a new rule to verify that the atlassian team is defined if the relevant section exists in the package.json
20
26
 
21
27
  ## 0.2.3
22
28
 
23
29
  ### Patch Changes
24
30
 
25
- - [`0bf64fb3dd0`](https://bitbucket.org/atlassian/atlassian-frontend/commits/0bf64fb3dd0) - Update to support unary expressions like negation
31
+ - [#33879](https://bitbucket.org/atlassian/atlassian-frontend/pull-requests/33879) [`0bf64fb3dd0`](https://bitbucket.org/atlassian/atlassian-frontend/commits/0bf64fb3dd0) - Update to support unary expressions like negation
26
32
 
27
33
  ## 0.2.2
28
34
 
29
35
  ### Patch Changes
30
36
 
31
- - [`9d00501a414`](https://bitbucket.org/atlassian/atlassian-frontend/commits/9d00501a414) - Ensure legacy types are published for TS 4.5-4.8
37
+ - [#33793](https://bitbucket.org/atlassian/atlassian-frontend/pull-requests/33793) [`9d00501a414`](https://bitbucket.org/atlassian/atlassian-frontend/commits/9d00501a414) - Ensure legacy types are published for TS 4.5-4.8
32
38
 
33
39
  ## 0.2.1
34
40
 
35
41
  ### Patch Changes
36
42
 
37
- - [`41fae2c6f68`](https://bitbucket.org/atlassian/atlassian-frontend/commits/41fae2c6f68) - Upgrade Typescript from `4.5.5` to `4.9.5`
43
+ - [#33649](https://bitbucket.org/atlassian/atlassian-frontend/pull-requests/33649) [`41fae2c6f68`](https://bitbucket.org/atlassian/atlassian-frontend/commits/41fae2c6f68) - Upgrade Typescript from `4.5.5` to `4.9.5`
38
44
 
39
45
  ## 0.2.0
40
46
 
41
47
  ### Minor Changes
42
48
 
43
- - [`56507598609`](https://bitbucket.org/atlassian/atlassian-frontend/commits/56507598609) - Skip minor dependency bump
49
+ - [#33258](https://bitbucket.org/atlassian/atlassian-frontend/pull-requests/33258) [`56507598609`](https://bitbucket.org/atlassian/atlassian-frontend/commits/56507598609) - Skip minor dependency bump
44
50
 
45
51
  ## 0.1.8
46
52
 
47
53
  ### Patch Changes
48
54
 
49
- - [`cb0e94d2ce4`](https://bitbucket.org/atlassian/atlassian-frontend/commits/cb0e94d2ce4) - Fix prefixes for all flags being checked at any callsite, only the current flag will be checked from now on
55
+ - [#32441](https://bitbucket.org/atlassian/atlassian-frontend/pull-requests/32441) [`cb0e94d2ce4`](https://bitbucket.org/atlassian/atlassian-frontend/commits/cb0e94d2ce4) - Fix prefixes for all flags being checked at any callsite, only the current flag will be checked from now on
50
56
 
51
57
  ## 0.1.7
52
58
 
53
59
  ### Patch Changes
54
60
 
55
- - [`2e01c9c74b5`](https://bitbucket.org/atlassian/atlassian-frontend/commits/2e01c9c74b5) - DUMMY remove before merging to master; dupe adf-schema via adf-utils
61
+ - [#32424](https://bitbucket.org/atlassian/atlassian-frontend/pull-requests/32424) [`2e01c9c74b5`](https://bitbucket.org/atlassian/atlassian-frontend/commits/2e01c9c74b5) - DUMMY remove before merging to master; dupe adf-schema via adf-utils
56
62
 
57
63
  ## 0.1.6
58
64
 
59
65
  ### Patch Changes
60
66
 
61
- - [`e8a8808f299`](https://bitbucket.org/atlassian/atlassian-frontend/commits/e8a8808f299) - Add a new eslint rule that enforces prefixes on platform feature flags. Ignore existing usages.
67
+ - [#31962](https://bitbucket.org/atlassian/atlassian-frontend/pull-requests/31962) [`e8a8808f299`](https://bitbucket.org/atlassian/atlassian-frontend/commits/e8a8808f299) - Add a new eslint rule that enforces prefixes on platform feature flags. Ignore existing usages.
62
68
 
63
69
  ## 0.1.5
64
70
 
65
71
  ### Patch Changes
66
72
 
67
- - [`b47e48ad163`](https://bitbucket.org/atlassian/atlassian-frontend/commits/b47e48ad163) - Adds an eslint rule to confirm that storybooks only get passed an object - to ensure that codemods work correctly.
73
+ - [#31956](https://bitbucket.org/atlassian/atlassian-frontend/pull-requests/31956) [`b47e48ad163`](https://bitbucket.org/atlassian/atlassian-frontend/commits/b47e48ad163) - Adds an eslint rule to confirm that storybooks only get passed an object - to ensure that codemods work correctly.
68
74
 
69
75
  ## 0.1.4
70
76
 
71
77
  ### Patch Changes
72
78
 
73
- - [`971489f4ff4`](https://bitbucket.org/atlassian/atlassian-frontend/commits/971489f4ff4) - Add test runner to identified calls that require registration of platform feature flags
79
+ - [#31631](https://bitbucket.org/atlassian/atlassian-frontend/pull-requests/31631) [`971489f4ff4`](https://bitbucket.org/atlassian/atlassian-frontend/commits/971489f4ff4) - Add test runner to identified calls that require registration of platform feature flags
74
80
 
75
81
  ## 0.1.3
76
82
 
77
83
  ### Patch Changes
78
84
 
79
- - [`7facf919a4e`](https://bitbucket.org/atlassian/atlassian-frontend/commits/7facf919a4e) - Remove product specific rules and make it so the recommended set is used everywhere instead
85
+ - [#31581](https://bitbucket.org/atlassian/atlassian-frontend/pull-requests/31581) [`7facf919a4e`](https://bitbucket.org/atlassian/atlassian-frontend/commits/7facf919a4e) - Remove product specific rules and make it so the recommended set is used everywhere instead
80
86
 
81
87
  ## 0.1.2
82
88
 
83
89
  ### Patch Changes
84
90
 
85
- - [`166815fbd8f`](https://bitbucket.org/atlassian/atlassian-frontend/commits/166815fbd8f) - Add recommended set of flags for use in products
91
+ - [#31440](https://bitbucket.org/atlassian/atlassian-frontend/pull-requests/31440) [`166815fbd8f`](https://bitbucket.org/atlassian/atlassian-frontend/commits/166815fbd8f) - Add recommended set of flags for use in products
86
92
 
87
93
  ## 0.1.1
88
94
 
89
95
  ### Patch Changes
90
96
 
91
- - [`7edd9e8b4b1`](https://bitbucket.org/atlassian/atlassian-frontend/commits/7edd9e8b4b1) - Add suggestion to change feature flag to the closest matching feature flag using fuzzy search
97
+ - [#30710](https://bitbucket.org/atlassian/atlassian-frontend/pull-requests/30710) [`7edd9e8b4b1`](https://bitbucket.org/atlassian/atlassian-frontend/commits/7edd9e8b4b1) - Add suggestion to change feature flag to the closest matching feature flag using fuzzy search
92
98
 
93
99
  ## 0.1.0
94
100
 
95
101
  ### Minor Changes
96
102
 
97
- - [`6339334e3ac`](https://bitbucket.org/atlassian/atlassian-frontend/commits/6339334e3ac) - Adds new rule to disallow pre/post install scripts in package.json.
103
+ - [#30401](https://bitbucket.org/atlassian/atlassian-frontend/pull-requests/30401) [`6339334e3ac`](https://bitbucket.org/atlassian/atlassian-frontend/commits/6339334e3ac) - Adds new rule to disallow pre/post install scripts in package.json.
98
104
 
99
105
  ## 0.0.7
100
106
 
101
107
  ### Patch Changes
102
108
 
103
- - [`0cab60b90c3`](https://bitbucket.org/atlassian/atlassian-frontend/commits/0cab60b90c3) - Add fix to eslint rule on the arguments of nested test runner
109
+ - [#30777](https://bitbucket.org/atlassian/atlassian-frontend/pull-requests/30777) [`0cab60b90c3`](https://bitbucket.org/atlassian/atlassian-frontend/commits/0cab60b90c3) - Add fix to eslint rule on the arguments of nested test runner
104
110
 
105
111
  ## 0.0.6
106
112
 
107
113
  ### Patch Changes
108
114
 
109
- - [`99449cce7f5`](https://bitbucket.org/atlassian/atlassian-frontend/commits/99449cce7f5) - Eslint rules around test runner arguments and limit on nested test runners
115
+ - [#30491](https://bitbucket.org/atlassian/atlassian-frontend/pull-requests/30491) [`99449cce7f5`](https://bitbucket.org/atlassian/atlassian-frontend/commits/99449cce7f5) - Eslint rules around test runner arguments and limit on nested test runners
110
116
 
111
117
  ## 0.0.5
112
118
 
113
119
  ### Patch Changes
114
120
 
115
- - [`aeb52cac34c`](https://bitbucket.org/atlassian/atlassian-frontend/commits/aeb52cac34c) - Split feature flag registration rule into two to more easily use it in products
121
+ - [#30484](https://bitbucket.org/atlassian/atlassian-frontend/pull-requests/30484) [`aeb52cac34c`](https://bitbucket.org/atlassian/atlassian-frontend/commits/aeb52cac34c) - Split feature flag registration rule into two to more easily use it in products
116
122
 
117
123
  ## 0.0.4
118
124
 
119
125
  ### Patch Changes
120
126
 
121
- - [`cd5b194f403`](https://bitbucket.org/atlassian/atlassian-frontend/commits/cd5b194f403) - Add check to ensure that there is only one feature flag call per expression
127
+ - [#30432](https://bitbucket.org/atlassian/atlassian-frontend/pull-requests/30432) [`cd5b194f403`](https://bitbucket.org/atlassian/atlassian-frontend/commits/cd5b194f403) - Add check to ensure that there is only one feature flag call per expression
122
128
 
123
129
  ## 0.0.3
124
130
 
125
131
  ### Patch Changes
126
132
 
127
- - [`11706c3e7c5`](https://bitbucket.org/atlassian/atlassian-frontend/commits/11706c3e7c5) - Publish platform eslint rules to npm to be consumed in other products
133
+ - [#30320](https://bitbucket.org/atlassian/atlassian-frontend/pull-requests/30320) [`11706c3e7c5`](https://bitbucket.org/atlassian/atlassian-frontend/commits/11706c3e7c5) - Publish platform eslint rules to npm to be consumed in other products
128
134
 
129
135
  ## 0.0.2
130
136
 
131
137
  ### Patch Changes
132
138
 
133
- - [`85dc0230439`](https://bitbucket.org/atlassian/atlassian-frontend/commits/85dc0230439) - Add eslint rule to allow for platform feature flag usage
139
+ - [#28303](https://bitbucket.org/atlassian/atlassian-frontend/pull-requests/28303) [`85dc0230439`](https://bitbucket.org/atlassian/atlassian-frontend/commits/85dc0230439) - Add eslint rule to allow for platform feature flag usage
package/dist/cjs/index.js CHANGED
@@ -5,30 +5,34 @@ Object.defineProperty(exports, "__esModule", {
5
5
  value: true
6
6
  });
7
7
  exports.rules = exports.processors = exports.configs = void 0;
8
+ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
8
9
  var _ensureFeatureFlagRegistration = _interopRequireDefault(require("./rules/ensure-feature-flag-registration"));
9
10
  var _noPrePostInstalls = _interopRequireDefault(require("./rules/no-pre-post-installs"));
10
11
  var _ensureTestRunnerArguments = _interopRequireDefault(require("./rules/ensure-test-runner-arguments"));
11
12
  var _ensureTestRunnerNestedCount = _interopRequireDefault(require("./rules/ensure-test-runner-nested-count"));
12
13
  var _ensureAtlassianTeam = _interopRequireDefault(require("./rules/ensure-atlassian-team"));
14
+ var _noDuplicateDependencies = _interopRequireDefault(require("./rules/no-duplicate-dependencies"));
13
15
  var _noInvalidFeatureFlagUsage = _interopRequireDefault(require("./rules/no-invalid-feature-flag-usage"));
14
16
  var _ensureFeatureFlagPrefix = _interopRequireDefault(require("./rules/ensure-feature-flag-prefix"));
15
17
  var _ensureCriticalDependencyResolutions = _interopRequireDefault(require("./rules/ensure-critical-dependency-resolutions"));
16
18
  var _noInvalidStorybookDecoratorUsage = _interopRequireDefault(require("./rules/no-invalid-storybook-decorator-usage"));
17
19
  var _ensurePublishValid = _interopRequireDefault(require("./rules/ensure-publish-valid"));
18
- var rules = {
20
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
21
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
22
+ var rules = exports.rules = {
19
23
  'ensure-feature-flag-registration': _ensureFeatureFlagRegistration.default,
20
24
  'ensure-feature-flag-prefix': _ensureFeatureFlagPrefix.default,
21
25
  'ensure-test-runner-arguments': _ensureTestRunnerArguments.default,
22
26
  'ensure-test-runner-nested-count': _ensureTestRunnerNestedCount.default,
23
27
  'ensure-atlassian-team': _ensureAtlassianTeam.default,
24
28
  'ensure-critical-dependency-resolutions': _ensureCriticalDependencyResolutions.default,
29
+ 'no-duplicate-dependencies': _noDuplicateDependencies.default,
25
30
  'no-invalid-feature-flag-usage': _noInvalidFeatureFlagUsage.default,
26
31
  'no-pre-post-install-scripts': _noPrePostInstalls.default,
27
32
  'no-invalid-storybook-decorator-usage': _noInvalidStorybookDecoratorUsage.default,
28
33
  'ensure-publish-valid': _ensurePublishValid.default
29
34
  };
30
- exports.rules = rules;
31
- var configs = {
35
+ var configs = exports.configs = {
32
36
  recommended: {
33
37
  plugins: ['@atlaskit/platform'],
34
38
  rules: {
@@ -44,16 +48,27 @@ var configs = {
44
48
  }
45
49
  }
46
50
  };
47
- exports.configs = configs;
48
- var processors = {
51
+ var jsonPrefix = '/* eslint-disable quote-props, comma-dangle, quotes, semi, eol-last, @typescript-eslint/semi, no-template-curly-in-string */ module.exports = ';
52
+ var processors = exports.processors = {
49
53
  'package-json-processor': {
50
54
  preprocess: function preprocess(source) {
51
55
  // augment the json into a js file
52
- return ["/* eslint-disable quote-props, comma-dangle, quotes, semi, eol-last, @typescript-eslint/semi, no-template-curly-in-string */ module.exports = ".concat(source.trim())];
56
+ return [jsonPrefix + source.trim()];
53
57
  },
54
- postprocess: function postprocess(errors) {
55
- return errors[0];
56
- }
58
+ postprocess: function postprocess(messages) {
59
+ return messages[0].map(function (message) {
60
+ var fix = message.fix;
61
+ if (!fix) {
62
+ return message;
63
+ }
64
+ var offset = jsonPrefix.length;
65
+ return _objectSpread(_objectSpread({}, message), {}, {
66
+ fix: _objectSpread(_objectSpread({}, fix), {}, {
67
+ range: [fix.range[0] - offset, fix.range[1] - offset]
68
+ })
69
+ });
70
+ });
71
+ },
72
+ supportsAutofix: true
57
73
  }
58
- };
59
- exports.processors = processors;
74
+ };
@@ -46,5 +46,4 @@ var rule = {
46
46
  };
47
47
  }
48
48
  };
49
- var _default = rule;
50
- exports.default = _default;
49
+ var _default = exports.default = rule;
@@ -83,5 +83,4 @@ var rule = {
83
83
  };
84
84
  }
85
85
  };
86
- var _default = rule;
87
- exports.default = _default;
86
+ var _default = exports.default = rule;
@@ -69,5 +69,4 @@ var rule = {
69
69
  }));
70
70
  }
71
71
  };
72
- var _default = rule;
73
- exports.default = _default;
72
+ var _default = exports.default = rule;
@@ -91,5 +91,4 @@ var rule = {
91
91
  }));
92
92
  }
93
93
  };
94
- var _default = rule;
95
- exports.default = _default;
94
+ var _default = exports.default = rule;
@@ -72,5 +72,4 @@ var rule = {
72
72
  };
73
73
  }
74
74
  };
75
- var _default = rule;
76
- exports.default = _default;
75
+ var _default = exports.default = rule;
@@ -102,5 +102,4 @@ var rule = {
102
102
  });
103
103
  }
104
104
  };
105
- var _default = rule;
106
- exports.default = _default;
105
+ var _default = exports.default = rule;
@@ -65,5 +65,4 @@ var rule = {
65
65
  });
66
66
  }
67
67
  };
68
- var _default = rule;
69
- exports.default = _default;
68
+ var _default = exports.default = rule;
@@ -0,0 +1,90 @@
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 _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
9
+ function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }
10
+ function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
11
+ function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
12
+ var rule = {
13
+ meta: {
14
+ type: 'problem',
15
+ docs: {
16
+ description: 'This rule disallows a dependency to be defined in both dependencies and devDependencies',
17
+ recommended: false
18
+ },
19
+ fixable: 'code',
20
+ messages: {
21
+ unexpectedDuplicateDependency: 'Unexpected duplicate dependency {{name}}'
22
+ }
23
+ },
24
+ create: function create(context) {
25
+ var dependencies = new Map();
26
+ var devDependencies = new Map();
27
+ return {
28
+ 'ObjectExpression Property[key.value=dependencies] Property': function ObjectExpressionPropertyKeyValueDependenciesProperty(node) {
29
+ // @ts-expect-error
30
+ dependencies.set(node.key.value, node.key);
31
+ },
32
+ 'ObjectExpression Property[key.value=devDependencies] Property': function ObjectExpressionPropertyKeyValueDevDependenciesProperty(node) {
33
+ // @ts-expect-error
34
+ devDependencies.set(node.key.value, node.key);
35
+ },
36
+ 'Program:exit': function ProgramExit() {
37
+ var _iterator = _createForOfIteratorHelper(devDependencies),
38
+ _step;
39
+ try {
40
+ var _loop = function _loop() {
41
+ var _step$value = (0, _slicedToArray2.default)(_step.value, 2),
42
+ dependency = _step$value[0],
43
+ node = _step$value[1];
44
+ if (dependencies.has(dependency)) {
45
+ context.report({
46
+ data: {
47
+ name: dependency
48
+ },
49
+ fix: function fix(fixer) {
50
+ var _sourceCode$getTokenA;
51
+ var sourceCode = context.getSourceCode();
52
+ var property = node.parent;
53
+ var isLastLine = ((_sourceCode$getTokenA = sourceCode.getTokenAfter(property)) === null || _sourceCode$getTokenA === void 0 ? void 0 : _sourceCode$getTokenA.value) === '}';
54
+ var end = property.loc.end;
55
+ if (!isLastLine) {
56
+ return fixer.removeRange([sourceCode.getIndexFromLoc({
57
+ line: property.loc.start.line,
58
+ column: 0
59
+ }), sourceCode.getIndexFromLoc({
60
+ line: end.line + 1,
61
+ column: 0
62
+ })]);
63
+ }
64
+ var previousToken = sourceCode.getTokenBefore(property);
65
+ return fixer.removeRange([sourceCode.getIndexFromLoc({
66
+ line: previousToken.loc.end.line,
67
+ column: previousToken.loc.end.column - 1
68
+ }), sourceCode.getIndexFromLoc({
69
+ line: end.line,
70
+ column: end.column
71
+ })]);
72
+ },
73
+ messageId: 'unexpectedDuplicateDependency',
74
+ node: node
75
+ });
76
+ }
77
+ };
78
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
79
+ _loop();
80
+ }
81
+ } catch (err) {
82
+ _iterator.e(err);
83
+ } finally {
84
+ _iterator.f();
85
+ }
86
+ }
87
+ };
88
+ }
89
+ };
90
+ var _default = exports.default = rule;
@@ -87,5 +87,4 @@ var rule = {
87
87
  });
88
88
  }
89
89
  };
90
- var _default = rule;
91
- exports.default = _default;
90
+ var _default = exports.default = rule;
@@ -34,5 +34,4 @@ var rule = {
34
34
  });
35
35
  }
36
36
  };
37
- var _default = rule;
38
- exports.default = _default;
37
+ var _default = exports.default = rule;
@@ -30,5 +30,4 @@ var rule = {
30
30
  };
31
31
  }
32
32
  };
33
- var _default = rule;
34
- exports.default = _default;
33
+ var _default = exports.default = rule;
@@ -4,7 +4,7 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.getObjectPropertyAsObject = exports.getObjectPropertyAsLiteral = void 0;
7
- var getObjectPropertyAsLiteral = function getObjectPropertyAsLiteral(node, property) {
7
+ var getObjectPropertyAsLiteral = exports.getObjectPropertyAsLiteral = function getObjectPropertyAsLiteral(node, property) {
8
8
  var prop = node.properties.find(function (p) {
9
9
  return p.type === 'Property' && p.key.type === 'Literal' && p.key.value === property;
10
10
  });
@@ -16,8 +16,7 @@ var getObjectPropertyAsLiteral = function getObjectPropertyAsLiteral(node, prope
16
16
  }
17
17
  return null;
18
18
  };
19
- exports.getObjectPropertyAsLiteral = getObjectPropertyAsLiteral;
20
- var getObjectPropertyAsObject = function getObjectPropertyAsObject(node, property) {
19
+ var getObjectPropertyAsObject = exports.getObjectPropertyAsObject = function getObjectPropertyAsObject(node, property) {
21
20
  var prop = node.properties.find(function (p) {
22
21
  return p.type === 'Property' && p.key.type === 'Literal' && p.key.value === property;
23
22
  });
@@ -28,5 +27,4 @@ var getObjectPropertyAsObject = function getObjectPropertyAsObject(node, propert
28
27
  return (_prop$value = prop.value) !== null && _prop$value !== void 0 ? _prop$value : null;
29
28
  }
30
29
  return null;
31
- };
32
- exports.getObjectPropertyAsObject = getObjectPropertyAsObject;
30
+ };
@@ -11,15 +11,14 @@ var _path = _interopRequireDefault(require("path"));
11
11
  var _fuse = _interopRequireDefault(require("fuse.js"));
12
12
  // defines a "getter" to "type" map, if more types are required for feature flags (like string) add it here!
13
13
  // if you don't want to verify the type use `null` as the value
14
- var getterIdentifierToFlagTypeMap = {
14
+ var getterIdentifierToFlagTypeMap = exports.getterIdentifierToFlagTypeMap = {
15
15
  getBooleanFF: 'boolean',
16
16
  ffTest: 'boolean'
17
17
  };
18
- exports.getterIdentifierToFlagTypeMap = getterIdentifierToFlagTypeMap;
19
18
  // make sure we cache reading the package.json so we don't end up reading it for every instance of this rule.
20
19
  var pkgJsonCache = new Map();
21
20
  // get the ancestor package.json for a given file
22
- var getMetadataForFilename = function getMetadataForFilename(filename) {
21
+ var getMetadataForFilename = exports.getMetadataForFilename = function getMetadataForFilename(filename) {
23
22
  var splitFilename = filename.split(_path.default.sep);
24
23
  for (var i = 0; i < splitFilename.length; i++) {
25
24
  // attempt to search using the filename in the cache to see if we've read the package.json for a sibling file before
@@ -43,5 +42,4 @@ var getMetadataForFilename = function getMetadataForFilename(filename) {
43
42
  };
44
43
  pkgJsonCache.set(pkgJsonPath, metaData);
45
44
  return metaData;
46
- };
47
- exports.getMetadataForFilename = getMetadataForFilename;
45
+ };
@@ -3,6 +3,7 @@ import noPreAndPostInstallScripts from './rules/no-pre-post-installs';
3
3
  import ensureTestRunnerArguments from './rules/ensure-test-runner-arguments';
4
4
  import ensureTestRunnerNestedCount from './rules/ensure-test-runner-nested-count';
5
5
  import ensureAtlassianTeam from './rules/ensure-atlassian-team';
6
+ import noDuplicateDependencies from './rules/no-duplicate-dependencies';
6
7
  import noInvalidFeatureFlagUsage from './rules/no-invalid-feature-flag-usage';
7
8
  import ensureFeatureFlagPrefix from './rules/ensure-feature-flag-prefix';
8
9
  import ensureCriticalDependencyResolutions from './rules/ensure-critical-dependency-resolutions';
@@ -15,6 +16,7 @@ export const rules = {
15
16
  'ensure-test-runner-nested-count': ensureTestRunnerNestedCount,
16
17
  'ensure-atlassian-team': ensureAtlassianTeam,
17
18
  'ensure-critical-dependency-resolutions': ensureCriticalDependencyResolutions,
19
+ 'no-duplicate-dependencies': noDuplicateDependencies,
18
20
  'no-invalid-feature-flag-usage': noInvalidFeatureFlagUsage,
19
21
  'no-pre-post-install-scripts': noPreAndPostInstallScripts,
20
22
  'no-invalid-storybook-decorator-usage': noInvalidStorybookDecoratorUsage,
@@ -36,12 +38,31 @@ export const configs = {
36
38
  }
37
39
  }
38
40
  };
41
+ const jsonPrefix = '/* eslint-disable quote-props, comma-dangle, quotes, semi, eol-last, @typescript-eslint/semi, no-template-curly-in-string */ module.exports = ';
39
42
  export const processors = {
40
43
  'package-json-processor': {
41
44
  preprocess: source => {
42
45
  // augment the json into a js file
43
- return [`/* eslint-disable quote-props, comma-dangle, quotes, semi, eol-last, @typescript-eslint/semi, no-template-curly-in-string */ module.exports = ${source.trim()}`];
46
+ return [jsonPrefix + source.trim()];
44
47
  },
45
- postprocess: errors => errors[0]
48
+ postprocess: messages => {
49
+ return messages[0].map(message => {
50
+ const {
51
+ fix
52
+ } = message;
53
+ if (!fix) {
54
+ return message;
55
+ }
56
+ const offset = jsonPrefix.length;
57
+ return {
58
+ ...message,
59
+ fix: {
60
+ ...fix,
61
+ range: [fix.range[0] - offset, fix.range[1] - offset]
62
+ }
63
+ };
64
+ });
65
+ },
66
+ supportsAutofix: true
46
67
  }
47
68
  };
@@ -0,0 +1,65 @@
1
+ const rule = {
2
+ meta: {
3
+ type: 'problem',
4
+ docs: {
5
+ description: 'This rule disallows a dependency to be defined in both dependencies and devDependencies',
6
+ recommended: false
7
+ },
8
+ fixable: 'code',
9
+ messages: {
10
+ unexpectedDuplicateDependency: 'Unexpected duplicate dependency {{name}}'
11
+ }
12
+ },
13
+ create(context) {
14
+ const dependencies = new Map();
15
+ const devDependencies = new Map();
16
+ return {
17
+ 'ObjectExpression Property[key.value=dependencies] Property': node => {
18
+ // @ts-expect-error
19
+ dependencies.set(node.key.value, node.key);
20
+ },
21
+ 'ObjectExpression Property[key.value=devDependencies] Property': node => {
22
+ // @ts-expect-error
23
+ devDependencies.set(node.key.value, node.key);
24
+ },
25
+ 'Program:exit': () => {
26
+ for (const [dependency, node] of devDependencies) {
27
+ if (dependencies.has(dependency)) {
28
+ context.report({
29
+ data: {
30
+ name: dependency
31
+ },
32
+ fix(fixer) {
33
+ var _sourceCode$getTokenA;
34
+ const sourceCode = context.getSourceCode();
35
+ const property = node.parent;
36
+ const isLastLine = ((_sourceCode$getTokenA = sourceCode.getTokenAfter(property)) === null || _sourceCode$getTokenA === void 0 ? void 0 : _sourceCode$getTokenA.value) === '}';
37
+ const end = property.loc.end;
38
+ if (!isLastLine) {
39
+ return fixer.removeRange([sourceCode.getIndexFromLoc({
40
+ line: property.loc.start.line,
41
+ column: 0
42
+ }), sourceCode.getIndexFromLoc({
43
+ line: end.line + 1,
44
+ column: 0
45
+ })]);
46
+ }
47
+ const previousToken = sourceCode.getTokenBefore(property);
48
+ return fixer.removeRange([sourceCode.getIndexFromLoc({
49
+ line: previousToken.loc.end.line,
50
+ column: previousToken.loc.end.column - 1
51
+ }), sourceCode.getIndexFromLoc({
52
+ line: end.line,
53
+ column: end.column
54
+ })]);
55
+ },
56
+ messageId: 'unexpectedDuplicateDependency',
57
+ node
58
+ });
59
+ }
60
+ }
61
+ }
62
+ };
63
+ }
64
+ };
65
+ export default rule;
package/dist/esm/index.js CHANGED
@@ -1,8 +1,12 @@
1
+ import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
3
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
1
4
  import ensureFeatureFlagRegistration from './rules/ensure-feature-flag-registration';
2
5
  import noPreAndPostInstallScripts from './rules/no-pre-post-installs';
3
6
  import ensureTestRunnerArguments from './rules/ensure-test-runner-arguments';
4
7
  import ensureTestRunnerNestedCount from './rules/ensure-test-runner-nested-count';
5
8
  import ensureAtlassianTeam from './rules/ensure-atlassian-team';
9
+ import noDuplicateDependencies from './rules/no-duplicate-dependencies';
6
10
  import noInvalidFeatureFlagUsage from './rules/no-invalid-feature-flag-usage';
7
11
  import ensureFeatureFlagPrefix from './rules/ensure-feature-flag-prefix';
8
12
  import ensureCriticalDependencyResolutions from './rules/ensure-critical-dependency-resolutions';
@@ -15,6 +19,7 @@ export var rules = {
15
19
  'ensure-test-runner-nested-count': ensureTestRunnerNestedCount,
16
20
  'ensure-atlassian-team': ensureAtlassianTeam,
17
21
  'ensure-critical-dependency-resolutions': ensureCriticalDependencyResolutions,
22
+ 'no-duplicate-dependencies': noDuplicateDependencies,
18
23
  'no-invalid-feature-flag-usage': noInvalidFeatureFlagUsage,
19
24
  'no-pre-post-install-scripts': noPreAndPostInstallScripts,
20
25
  'no-invalid-storybook-decorator-usage': noInvalidStorybookDecoratorUsage,
@@ -36,14 +41,27 @@ export var configs = {
36
41
  }
37
42
  }
38
43
  };
44
+ var jsonPrefix = '/* eslint-disable quote-props, comma-dangle, quotes, semi, eol-last, @typescript-eslint/semi, no-template-curly-in-string */ module.exports = ';
39
45
  export var processors = {
40
46
  'package-json-processor': {
41
47
  preprocess: function preprocess(source) {
42
48
  // augment the json into a js file
43
- return ["/* eslint-disable quote-props, comma-dangle, quotes, semi, eol-last, @typescript-eslint/semi, no-template-curly-in-string */ module.exports = ".concat(source.trim())];
49
+ return [jsonPrefix + source.trim()];
44
50
  },
45
- postprocess: function postprocess(errors) {
46
- return errors[0];
47
- }
51
+ postprocess: function postprocess(messages) {
52
+ return messages[0].map(function (message) {
53
+ var fix = message.fix;
54
+ if (!fix) {
55
+ return message;
56
+ }
57
+ var offset = jsonPrefix.length;
58
+ return _objectSpread(_objectSpread({}, message), {}, {
59
+ fix: _objectSpread(_objectSpread({}, fix), {}, {
60
+ range: [fix.range[0] - offset, fix.range[1] - offset]
61
+ })
62
+ });
63
+ });
64
+ },
65
+ supportsAutofix: true
48
66
  }
49
67
  };
@@ -0,0 +1,83 @@
1
+ import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
2
+ function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }
3
+ function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
4
+ function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
5
+ var rule = {
6
+ meta: {
7
+ type: 'problem',
8
+ docs: {
9
+ description: 'This rule disallows a dependency to be defined in both dependencies and devDependencies',
10
+ recommended: false
11
+ },
12
+ fixable: 'code',
13
+ messages: {
14
+ unexpectedDuplicateDependency: 'Unexpected duplicate dependency {{name}}'
15
+ }
16
+ },
17
+ create: function create(context) {
18
+ var dependencies = new Map();
19
+ var devDependencies = new Map();
20
+ return {
21
+ 'ObjectExpression Property[key.value=dependencies] Property': function ObjectExpressionPropertyKeyValueDependenciesProperty(node) {
22
+ // @ts-expect-error
23
+ dependencies.set(node.key.value, node.key);
24
+ },
25
+ 'ObjectExpression Property[key.value=devDependencies] Property': function ObjectExpressionPropertyKeyValueDevDependenciesProperty(node) {
26
+ // @ts-expect-error
27
+ devDependencies.set(node.key.value, node.key);
28
+ },
29
+ 'Program:exit': function ProgramExit() {
30
+ var _iterator = _createForOfIteratorHelper(devDependencies),
31
+ _step;
32
+ try {
33
+ var _loop = function _loop() {
34
+ var _step$value = _slicedToArray(_step.value, 2),
35
+ dependency = _step$value[0],
36
+ node = _step$value[1];
37
+ if (dependencies.has(dependency)) {
38
+ context.report({
39
+ data: {
40
+ name: dependency
41
+ },
42
+ fix: function fix(fixer) {
43
+ var _sourceCode$getTokenA;
44
+ var sourceCode = context.getSourceCode();
45
+ var property = node.parent;
46
+ var isLastLine = ((_sourceCode$getTokenA = sourceCode.getTokenAfter(property)) === null || _sourceCode$getTokenA === void 0 ? void 0 : _sourceCode$getTokenA.value) === '}';
47
+ var end = property.loc.end;
48
+ if (!isLastLine) {
49
+ return fixer.removeRange([sourceCode.getIndexFromLoc({
50
+ line: property.loc.start.line,
51
+ column: 0
52
+ }), sourceCode.getIndexFromLoc({
53
+ line: end.line + 1,
54
+ column: 0
55
+ })]);
56
+ }
57
+ var previousToken = sourceCode.getTokenBefore(property);
58
+ return fixer.removeRange([sourceCode.getIndexFromLoc({
59
+ line: previousToken.loc.end.line,
60
+ column: previousToken.loc.end.column - 1
61
+ }), sourceCode.getIndexFromLoc({
62
+ line: end.line,
63
+ column: end.column
64
+ })]);
65
+ },
66
+ messageId: 'unexpectedDuplicateDependency',
67
+ node: node
68
+ });
69
+ }
70
+ };
71
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
72
+ _loop();
73
+ }
74
+ } catch (err) {
75
+ _iterator.e(err);
76
+ } finally {
77
+ _iterator.f();
78
+ }
79
+ }
80
+ };
81
+ }
82
+ };
83
+ export default rule;
@@ -6,6 +6,7 @@ export declare const rules: {
6
6
  'ensure-test-runner-nested-count': import("eslint").Rule.RuleModule;
7
7
  'ensure-atlassian-team': import("eslint").Rule.RuleModule;
8
8
  'ensure-critical-dependency-resolutions': import("eslint").Rule.RuleModule;
9
+ 'no-duplicate-dependencies': import("eslint").Rule.RuleModule;
9
10
  'no-invalid-feature-flag-usage': import("eslint").Rule.RuleModule;
10
11
  'no-pre-post-install-scripts': import("eslint").Rule.RuleModule;
11
12
  'no-invalid-storybook-decorator-usage': import("eslint").Rule.RuleModule;
@@ -0,0 +1,3 @@
1
+ import type { Rule } from 'eslint';
2
+ declare const rule: Rule.RuleModule;
3
+ export default rule;
@@ -6,6 +6,7 @@ export declare const rules: {
6
6
  'ensure-test-runner-nested-count': import("eslint").Rule.RuleModule;
7
7
  'ensure-atlassian-team': import("eslint").Rule.RuleModule;
8
8
  'ensure-critical-dependency-resolutions': import("eslint").Rule.RuleModule;
9
+ 'no-duplicate-dependencies': import("eslint").Rule.RuleModule;
9
10
  'no-invalid-feature-flag-usage': import("eslint").Rule.RuleModule;
10
11
  'no-pre-post-install-scripts': import("eslint").Rule.RuleModule;
11
12
  'no-invalid-storybook-decorator-usage': import("eslint").Rule.RuleModule;
@@ -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.2.6",
4
+ "version": "0.3.0",
5
5
  "author": "Atlassian Pty Ltd",
6
6
  "atlassian": {
7
7
  "team": "UIP - Platform Integration Trust (PITa)",
@@ -38,7 +38,7 @@
38
38
  "devDependencies": {
39
39
  "@atlassian/atlassian-frontend-prettier-config-1.0.1": "npm:@atlassian/atlassian-frontend-prettier-config@1.0.1",
40
40
  "eslint": "^7.7.0",
41
- "tsconfig-paths": "^3.9.0"
41
+ "tsconfig-paths": "^4.2.0"
42
42
  },
43
43
  "prettier": "@atlassian/atlassian-frontend-prettier-config-1.0.1"
44
44
  }
package/report.api.md CHANGED
@@ -52,6 +52,7 @@ export const rules: {
52
52
  'ensure-test-runner-nested-count': Rule.RuleModule;
53
53
  'ensure-atlassian-team': Rule.RuleModule;
54
54
  'ensure-critical-dependency-resolutions': Rule.RuleModule;
55
+ 'no-duplicate-dependencies': Rule.RuleModule;
55
56
  'no-invalid-feature-flag-usage': Rule.RuleModule;
56
57
  'no-pre-post-install-scripts': Rule.RuleModule;
57
58
  'no-invalid-storybook-decorator-usage': Rule.RuleModule;
package/src/index.tsx CHANGED
@@ -4,6 +4,7 @@ import noPreAndPostInstallScripts from './rules/no-pre-post-installs';
4
4
  import ensureTestRunnerArguments from './rules/ensure-test-runner-arguments';
5
5
  import ensureTestRunnerNestedCount from './rules/ensure-test-runner-nested-count';
6
6
  import ensureAtlassianTeam from './rules/ensure-atlassian-team';
7
+ import noDuplicateDependencies from './rules/no-duplicate-dependencies';
7
8
  import noInvalidFeatureFlagUsage from './rules/no-invalid-feature-flag-usage';
8
9
  import ensureFeatureFlagPrefix from './rules/ensure-feature-flag-prefix';
9
10
  import ensureCriticalDependencyResolutions from './rules/ensure-critical-dependency-resolutions';
@@ -17,6 +18,7 @@ export const rules = {
17
18
  'ensure-test-runner-nested-count': ensureTestRunnerNestedCount,
18
19
  'ensure-atlassian-team': ensureAtlassianTeam,
19
20
  'ensure-critical-dependency-resolutions': ensureCriticalDependencyResolutions,
21
+ 'no-duplicate-dependencies': noDuplicateDependencies,
20
22
  'no-invalid-feature-flag-usage': noInvalidFeatureFlagUsage,
21
23
  'no-pre-post-install-scripts': noPreAndPostInstallScripts,
22
24
  'no-invalid-storybook-decorator-usage': noInvalidStorybookDecoratorUsage,
@@ -41,14 +43,32 @@ export const configs = {
41
43
  },
42
44
  };
43
45
 
46
+ const jsonPrefix =
47
+ '/* eslint-disable quote-props, comma-dangle, quotes, semi, eol-last, @typescript-eslint/semi, no-template-curly-in-string */ module.exports = ';
48
+
44
49
  export const processors = {
45
50
  'package-json-processor': {
46
51
  preprocess: (source: string) => {
47
52
  // augment the json into a js file
48
- return [
49
- `/* eslint-disable quote-props, comma-dangle, quotes, semi, eol-last, @typescript-eslint/semi, no-template-curly-in-string */ module.exports = ${source.trim()}`,
50
- ];
53
+ return [jsonPrefix + source.trim()];
54
+ },
55
+ postprocess: (messages) => {
56
+ return messages[0].map((message) => {
57
+ const { fix } = message;
58
+ if (!fix) {
59
+ return message;
60
+ }
61
+
62
+ const offset = jsonPrefix.length;
63
+ return {
64
+ ...message,
65
+ fix: {
66
+ ...fix,
67
+ range: [fix.range[0] - offset, fix.range[1] - offset],
68
+ },
69
+ };
70
+ });
51
71
  },
52
- postprocess: (errors) => errors[0],
72
+ supportsAutofix: true,
53
73
  } as Linter.Processor,
54
74
  };
@@ -0,0 +1,116 @@
1
+ import { tester } from '../../../../__tests__/utils/_tester';
2
+ import rule from '../../index';
3
+
4
+ describe('test no-duplicate-dependencies rule', () => {
5
+ tester.run('no-duplicate-dependencies-rule', rule, {
6
+ valid: [
7
+ {
8
+ code: `
9
+ module.exports = {
10
+ "dependencies": {
11
+ "foo": "^1.0.0",
12
+ "bar": "^2.0.0"
13
+ }
14
+ };
15
+ `,
16
+ filename: 'dependencies.json',
17
+ },
18
+ {
19
+ code: `
20
+ module.exports = {
21
+ "devDependencies": {
22
+ "foo": "^1.0.0",
23
+ "bar": "^2.0.0"
24
+ }
25
+ };
26
+ `,
27
+ filename: 'devDependencies.json',
28
+ },
29
+ {
30
+ code: `
31
+ module.exports = {
32
+ "dependencies": {
33
+ "foo": "^1.0.0",
34
+ "bar": "^2.0.0"
35
+ },
36
+ "devDependencies": {
37
+ "baz": "^3.0.0",
38
+ "qux": "^4.0.0"
39
+ }
40
+ };
41
+ `,
42
+ filename: 'devAndDependencies.json',
43
+ },
44
+ ],
45
+ invalid: [
46
+ {
47
+ code: `
48
+ module.exports = {
49
+ "dependencies": {
50
+ "foo": "^1.0.0",
51
+ "bar": "^2.0.0"
52
+ },
53
+ "devDependencies": {
54
+ "foo": "^1.0.0",
55
+ "baz": "^3.0.0",
56
+ "qux": "^4.0.0"
57
+ }
58
+ };
59
+ `,
60
+ output: `
61
+ module.exports = {
62
+ "dependencies": {
63
+ "foo": "^1.0.0",
64
+ "bar": "^2.0.0"
65
+ },
66
+ "devDependencies": {
67
+ "baz": "^3.0.0",
68
+ "qux": "^4.0.0"
69
+ }
70
+ };
71
+ `,
72
+ errors: [
73
+ {
74
+ data: {
75
+ name: 'foo',
76
+ },
77
+ messageId: 'unexpectedDuplicateDependency',
78
+ },
79
+ ],
80
+ filename: 'duplicateDependenciesFirst.json',
81
+ },
82
+ {
83
+ code: `
84
+ module.exports = {
85
+ "dependencies": {
86
+ "bar": "^1.0.0"
87
+ },
88
+ "devDependencies": {
89
+ "foo": "^2.0.0",
90
+ "bar": "^1.0.0"
91
+ }
92
+ };
93
+ `,
94
+ output: `
95
+ module.exports = {
96
+ "dependencies": {
97
+ "bar": "^1.0.0"
98
+ },
99
+ "devDependencies": {
100
+ "foo": "^2.0.0"
101
+ }
102
+ };
103
+ `,
104
+ errors: [
105
+ {
106
+ data: {
107
+ name: 'bar',
108
+ },
109
+ messageId: 'unexpectedDuplicateDependency',
110
+ },
111
+ ],
112
+ filename: 'duplicateDependenciesLast.json',
113
+ },
114
+ ],
115
+ });
116
+ });
@@ -0,0 +1,83 @@
1
+ import type { Rule } from 'eslint';
2
+
3
+ const rule: Rule.RuleModule = {
4
+ meta: {
5
+ type: 'problem',
6
+ docs: {
7
+ description:
8
+ 'This rule disallows a dependency to be defined in both dependencies and devDependencies',
9
+ recommended: false,
10
+ },
11
+ fixable: 'code',
12
+ messages: {
13
+ unexpectedDuplicateDependency: 'Unexpected duplicate dependency {{name}}',
14
+ },
15
+ },
16
+ create(context) {
17
+ const dependencies = new Map();
18
+ const devDependencies = new Map();
19
+
20
+ return {
21
+ 'ObjectExpression Property[key.value=dependencies] Property': (
22
+ node: Rule.Node,
23
+ ) => {
24
+ // @ts-expect-error
25
+ dependencies.set(node.key.value, node.key);
26
+ },
27
+ 'ObjectExpression Property[key.value=devDependencies] Property': (
28
+ node: Rule.Node,
29
+ ) => {
30
+ // @ts-expect-error
31
+ devDependencies.set(node.key.value, node.key);
32
+ },
33
+ 'Program:exit': () => {
34
+ for (const [dependency, node] of devDependencies) {
35
+ if (dependencies.has(dependency)) {
36
+ context.report({
37
+ data: {
38
+ name: dependency,
39
+ },
40
+ fix(fixer) {
41
+ const sourceCode = context.getSourceCode();
42
+ const property = node.parent;
43
+ const isLastLine =
44
+ sourceCode.getTokenAfter(property)?.value === '}';
45
+ const end = property.loc.end;
46
+
47
+ if (!isLastLine) {
48
+ return fixer.removeRange([
49
+ sourceCode.getIndexFromLoc({
50
+ line: property.loc.start.line,
51
+ column: 0,
52
+ }),
53
+ sourceCode.getIndexFromLoc({
54
+ line: end.line + 1,
55
+ column: 0,
56
+ }),
57
+ ]);
58
+ }
59
+
60
+ const previousToken = sourceCode.getTokenBefore(property)!;
61
+
62
+ return fixer.removeRange([
63
+ sourceCode.getIndexFromLoc({
64
+ line: previousToken.loc.end.line,
65
+ column: previousToken.loc.end.column - 1,
66
+ }),
67
+ sourceCode.getIndexFromLoc({
68
+ line: end.line,
69
+ column: end.column,
70
+ }),
71
+ ]);
72
+ },
73
+ messageId: 'unexpectedDuplicateDependency',
74
+ node,
75
+ });
76
+ }
77
+ }
78
+ },
79
+ };
80
+ },
81
+ };
82
+
83
+ export default rule;
@@ -38,6 +38,7 @@ export const rules: {
38
38
  'ensure-test-runner-nested-count': Rule.RuleModule;
39
39
  'ensure-atlassian-team': Rule.RuleModule;
40
40
  'ensure-critical-dependency-resolutions': Rule.RuleModule;
41
+ 'no-duplicate-dependencies': Rule.RuleModule;
41
42
  'no-invalid-feature-flag-usage': Rule.RuleModule;
42
43
  'no-pre-post-install-scripts': Rule.RuleModule;
43
44
  'no-invalid-storybook-decorator-usage': Rule.RuleModule;