@atlaskit/eslint-plugin-platform 0.2.5 → 0.2.6

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 (33) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/dist/cjs/index.js +2 -0
  3. package/dist/cjs/rules/ensure-critical-dependency-resolutions/index.js +87 -0
  4. package/dist/cjs/rules/ensure-feature-flag-registration/index.js +2 -2
  5. package/dist/cjs/rules/ensure-publish-valid/index.js +4 -27
  6. package/dist/cjs/rules/ensure-test-runner-nested-count/index.js +2 -2
  7. package/dist/cjs/rules/util/handle-ast-object.js +32 -0
  8. package/dist/es2019/index.js +2 -0
  9. package/dist/es2019/rules/ensure-critical-dependency-resolutions/index.js +64 -0
  10. package/dist/es2019/rules/ensure-publish-valid/index.js +1 -20
  11. package/dist/es2019/rules/util/handle-ast-object.js +20 -0
  12. package/dist/esm/index.js +2 -0
  13. package/dist/esm/rules/ensure-critical-dependency-resolutions/index.js +80 -0
  14. package/dist/esm/rules/ensure-feature-flag-registration/index.js +2 -2
  15. package/dist/esm/rules/ensure-publish-valid/index.js +1 -24
  16. package/dist/esm/rules/ensure-test-runner-nested-count/index.js +2 -2
  17. package/dist/esm/rules/util/handle-ast-object.js +24 -0
  18. package/dist/types/index.d.ts +1 -0
  19. package/dist/types/rules/ensure-critical-dependency-resolutions/index.d.ts +3 -0
  20. package/dist/types/rules/util/handle-ast-object.d.ts +3 -0
  21. package/dist/types-ts4.5/index.d.ts +1 -0
  22. package/dist/types-ts4.5/rules/ensure-critical-dependency-resolutions/index.d.ts +3 -0
  23. package/dist/types-ts4.5/rules/util/handle-ast-object.d.ts +3 -0
  24. package/package.json +2 -1
  25. package/report.api.md +1 -0
  26. package/src/index.tsx +2 -0
  27. package/src/rules/ensure-critical-dependency-resolutions/__test__/unit/rule.test.tsx +125 -0
  28. package/src/rules/ensure-critical-dependency-resolutions/index.tsx +113 -0
  29. package/src/rules/ensure-publish-valid/index.ts +4 -43
  30. package/src/rules/util/handle-ast-object.ts +44 -0
  31. package/tmp/api-report-tmp.d.ts +1 -0
  32. package/tsconfig.app.json +36 -0
  33. package/tsconfig.dev.json +40 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # @atlaskit/eslint-plugin-platform
2
2
 
3
+ ## 0.2.6
4
+
5
+ ### Patch Changes
6
+
7
+ - [`7efeb93141c`](https://bitbucket.org/atlassian/atlassian-frontend/commits/7efeb93141c) - Add a rule to ensure critical packages are resolved to the correct versions
8
+
3
9
  ## 0.2.5
4
10
 
5
11
  ### Patch Changes
package/dist/cjs/index.js CHANGED
@@ -12,6 +12,7 @@ var _ensureTestRunnerNestedCount = _interopRequireDefault(require("./rules/ensur
12
12
  var _ensureAtlassianTeam = _interopRequireDefault(require("./rules/ensure-atlassian-team"));
13
13
  var _noInvalidFeatureFlagUsage = _interopRequireDefault(require("./rules/no-invalid-feature-flag-usage"));
14
14
  var _ensureFeatureFlagPrefix = _interopRequireDefault(require("./rules/ensure-feature-flag-prefix"));
15
+ var _ensureCriticalDependencyResolutions = _interopRequireDefault(require("./rules/ensure-critical-dependency-resolutions"));
15
16
  var _noInvalidStorybookDecoratorUsage = _interopRequireDefault(require("./rules/no-invalid-storybook-decorator-usage"));
16
17
  var _ensurePublishValid = _interopRequireDefault(require("./rules/ensure-publish-valid"));
17
18
  var rules = {
@@ -20,6 +21,7 @@ var rules = {
20
21
  'ensure-test-runner-arguments': _ensureTestRunnerArguments.default,
21
22
  'ensure-test-runner-nested-count': _ensureTestRunnerNestedCount.default,
22
23
  'ensure-atlassian-team': _ensureAtlassianTeam.default,
24
+ 'ensure-critical-dependency-resolutions': _ensureCriticalDependencyResolutions.default,
23
25
  'no-invalid-feature-flag-usage': _noInvalidFeatureFlagUsage.default,
24
26
  'no-pre-post-install-scripts': _noPrePostInstalls.default,
25
27
  'no-invalid-storybook-decorator-usage': _noInvalidStorybookDecoratorUsage.default,
@@ -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 _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
9
+ var _findRoot = require("@manypkg/find-root");
10
+ var _handleAstObject = require("../util/handle-ast-object");
11
+ // Here we only need to specify the major and minor versions
12
+ // In matchMinorVersion, we will check if the versions in resolutions fall in the right ranges.
13
+ var DESIRED_PKG_VERSIONS = {
14
+ typescript: '4.9',
15
+ '@types/react': '16.14'
16
+ };
17
+ var matchMinorVersion = function matchMinorVersion(desiredVersion, versionInResolutions) {
18
+ var firstChar = versionInResolutions[0];
19
+ // The version is invalid if it doesn't start with a number or ~
20
+ if (!/^\d$/.test(firstChar) && firstChar !== '~') {
21
+ return false;
22
+ }
23
+ return versionInResolutions.startsWith(desiredVersion) || versionInResolutions.startsWith('~' + desiredVersion);
24
+ };
25
+ var verifyResolutionFromObject = function verifyResolutionFromObject(node, pkg, version, optional) {
26
+ // For root package.json, we require the critical packages' resolutions exist and with matching version
27
+ // For individual package's package.json, it's ok if resolutions don't exist. But if they do, the version should match
28
+ var resolutionExist = node.properties.some(function (p) {
29
+ return p.type === 'Property' && p.key.type === 'Literal' && p.key.value === pkg;
30
+ });
31
+ if (!resolutionExist) {
32
+ return optional;
33
+ }
34
+ var resolutionExistAndMatch = node.properties.some(function (p) {
35
+ return p.type === 'Property' && p.key.type === 'Literal' && p.key.value === pkg && p.value.type === 'Literal' && matchMinorVersion(version, p.value.value);
36
+ });
37
+ return resolutionExistAndMatch;
38
+ };
39
+ var rule = {
40
+ meta: {
41
+ type: 'problem',
42
+ docs: {
43
+ description: 'Enforce the versions of critical packages are within desired ranges by checking resolutions section in package.json',
44
+ recommended: true
45
+ },
46
+ hasSuggestions: false,
47
+ messages: {
48
+ invalidPackageResolution: "Make sure the resolutions for the following packages match major and minor version ranges ".concat(JSON.stringify(DESIRED_PKG_VERSIONS))
49
+ }
50
+ },
51
+ create: function create(context) {
52
+ var fileName = context.getFilename();
53
+ return {
54
+ ObjectExpression: function (_ObjectExpression) {
55
+ function ObjectExpression(_x) {
56
+ return _ObjectExpression.apply(this, arguments);
57
+ }
58
+ ObjectExpression.toString = function () {
59
+ return _ObjectExpression.toString();
60
+ };
61
+ return ObjectExpression;
62
+ }(function (node) {
63
+ if (!fileName.endsWith('package.json') || node.type !== 'ObjectExpression') {
64
+ return;
65
+ }
66
+ var packageResolutions = (0, _handleAstObject.getObjectPropertyAsObject)(node, 'resolutions');
67
+ var rootDir = (0, _findRoot.findRootSync)(process.cwd());
68
+ var isRootPackageJson = fileName.endsWith("".concat(rootDir, "/package.json"));
69
+ if (packageResolutions !== null) {
70
+ for (var _i = 0, _Object$entries = Object.entries(DESIRED_PKG_VERSIONS); _i < _Object$entries.length; _i++) {
71
+ var _Object$entries$_i = (0, _slicedToArray2.default)(_Object$entries[_i], 2),
72
+ key = _Object$entries$_i[0],
73
+ value = _Object$entries$_i[1];
74
+ if (!verifyResolutionFromObject(packageResolutions, key, value, !isRootPackageJson)) {
75
+ return context.report({
76
+ node: node,
77
+ messageId: 'invalidPackageResolution'
78
+ });
79
+ }
80
+ }
81
+ }
82
+ })
83
+ };
84
+ }
85
+ };
86
+ var _default = rule;
87
+ exports.default = _default;
@@ -7,8 +7,8 @@ Object.defineProperty(exports, "__esModule", {
7
7
  exports.default = void 0;
8
8
  var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
9
9
  var _registrationUtils = require("../util/registration-utils");
10
- function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
11
- function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { (0, _defineProperty2.default)(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
10
+ 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; }
11
+ 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; }
12
12
  var rule = {
13
13
  meta: {
14
14
  docs: {
@@ -4,30 +4,7 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.default = void 0;
7
- var getObjectPropertyAsLiteral = function getObjectPropertyAsLiteral(node, property) {
8
- var prop = node.properties.find(function (p) {
9
- return p.type === 'Property' && p.key.type === 'Literal' && p.key.value === property;
10
- });
11
-
12
- // double check for property is to make typescript happy
13
- if ((prop === null || prop === void 0 ? void 0 : prop.type) === 'Property' && (prop === null || prop === void 0 ? void 0 : prop.value.type) === 'Literal') {
14
- var _prop$value$value;
15
- return (_prop$value$value = prop.value.value) !== null && _prop$value$value !== void 0 ? _prop$value$value : null;
16
- }
17
- return null;
18
- };
19
- var getObjectPropertyAsObject = function getObjectPropertyAsObject(node, property) {
20
- var prop = node.properties.find(function (p) {
21
- return p.type === 'Property' && p.key.type === 'Literal' && p.key.value === property;
22
- });
23
-
24
- // double check for property is to make typescript happy
25
- if ((prop === null || prop === void 0 ? void 0 : prop.type) === 'Property' && (prop === null || prop === void 0 ? void 0 : prop.value.type) === 'ObjectExpression') {
26
- var _prop$value;
27
- return (_prop$value = prop.value) !== null && _prop$value !== void 0 ? _prop$value : null;
28
- }
29
- return null;
30
- };
7
+ var _handleAstObject = require("../util/handle-ast-object");
31
8
  var rule = {
32
9
  meta: {
33
10
  type: 'problem',
@@ -61,9 +38,9 @@ var rule = {
61
38
  if (!context.getFilename().endsWith('package.json') || node.type !== 'ObjectExpression') {
62
39
  return;
63
40
  }
64
- var packageName = getObjectPropertyAsLiteral(node, 'name');
65
- var packagePrivate = getObjectPropertyAsLiteral(node, 'private');
66
- var packagePublishConfig = getObjectPropertyAsObject(node, 'publishConfig');
41
+ var packageName = (0, _handleAstObject.getObjectPropertyAsLiteral)(node, 'name');
42
+ var packagePrivate = (0, _handleAstObject.getObjectPropertyAsLiteral)(node, 'private');
43
+ var packagePublishConfig = (0, _handleAstObject.getObjectPropertyAsObject)(node, 'publishConfig');
67
44
 
68
45
  // exit if package is on known exception list
69
46
  if (exceptions && exceptions.findIndex(function (name) {
@@ -6,8 +6,8 @@ Object.defineProperty(exports, "__esModule", {
6
6
  });
7
7
  exports.default = void 0;
8
8
  var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
9
- function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
10
- function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { (0, _defineProperty2.default)(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
9
+ 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; }
10
+ 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; }
11
11
  var NESTED_LIMIT = 4;
12
12
  var TEST_RUNNER_IDENTIFIER = 'ffTest';
13
13
  var getDepthOfNestedRunner = function getDepthOfNestedRunner(node) {
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.getObjectPropertyAsObject = exports.getObjectPropertyAsLiteral = void 0;
7
+ var getObjectPropertyAsLiteral = function getObjectPropertyAsLiteral(node, property) {
8
+ var prop = node.properties.find(function (p) {
9
+ return p.type === 'Property' && p.key.type === 'Literal' && p.key.value === property;
10
+ });
11
+
12
+ // double check for property is to make typescript happy
13
+ if ((prop === null || prop === void 0 ? void 0 : prop.type) === 'Property' && (prop === null || prop === void 0 ? void 0 : prop.value.type) === 'Literal') {
14
+ var _prop$value$value;
15
+ return (_prop$value$value = prop.value.value) !== null && _prop$value$value !== void 0 ? _prop$value$value : null;
16
+ }
17
+ return null;
18
+ };
19
+ exports.getObjectPropertyAsLiteral = getObjectPropertyAsLiteral;
20
+ var getObjectPropertyAsObject = function getObjectPropertyAsObject(node, property) {
21
+ var prop = node.properties.find(function (p) {
22
+ return p.type === 'Property' && p.key.type === 'Literal' && p.key.value === property;
23
+ });
24
+
25
+ // double check for property is to make typescript happy
26
+ if ((prop === null || prop === void 0 ? void 0 : prop.type) === 'Property' && (prop === null || prop === void 0 ? void 0 : prop.value.type) === 'ObjectExpression') {
27
+ var _prop$value;
28
+ return (_prop$value = prop.value) !== null && _prop$value !== void 0 ? _prop$value : null;
29
+ }
30
+ return null;
31
+ };
32
+ exports.getObjectPropertyAsObject = getObjectPropertyAsObject;
@@ -5,6 +5,7 @@ import ensureTestRunnerNestedCount from './rules/ensure-test-runner-nested-count
5
5
  import ensureAtlassianTeam from './rules/ensure-atlassian-team';
6
6
  import noInvalidFeatureFlagUsage from './rules/no-invalid-feature-flag-usage';
7
7
  import ensureFeatureFlagPrefix from './rules/ensure-feature-flag-prefix';
8
+ import ensureCriticalDependencyResolutions from './rules/ensure-critical-dependency-resolutions';
8
9
  import noInvalidStorybookDecoratorUsage from './rules/no-invalid-storybook-decorator-usage';
9
10
  import ensurePublishValid from './rules/ensure-publish-valid';
10
11
  export const rules = {
@@ -13,6 +14,7 @@ export const rules = {
13
14
  'ensure-test-runner-arguments': ensureTestRunnerArguments,
14
15
  'ensure-test-runner-nested-count': ensureTestRunnerNestedCount,
15
16
  'ensure-atlassian-team': ensureAtlassianTeam,
17
+ 'ensure-critical-dependency-resolutions': ensureCriticalDependencyResolutions,
16
18
  'no-invalid-feature-flag-usage': noInvalidFeatureFlagUsage,
17
19
  'no-pre-post-install-scripts': noPreAndPostInstallScripts,
18
20
  'no-invalid-storybook-decorator-usage': noInvalidStorybookDecoratorUsage,
@@ -0,0 +1,64 @@
1
+ import { findRootSync } from '@manypkg/find-root';
2
+ import { getObjectPropertyAsObject } from '../util/handle-ast-object';
3
+
4
+ // Here we only need to specify the major and minor versions
5
+ // In matchMinorVersion, we will check if the versions in resolutions fall in the right ranges.
6
+ const DESIRED_PKG_VERSIONS = {
7
+ typescript: '4.9',
8
+ '@types/react': '16.14'
9
+ };
10
+ const matchMinorVersion = (desiredVersion, versionInResolutions) => {
11
+ const firstChar = versionInResolutions[0];
12
+ // The version is invalid if it doesn't start with a number or ~
13
+ if (!/^\d$/.test(firstChar) && firstChar !== '~') {
14
+ return false;
15
+ }
16
+ return versionInResolutions.startsWith(desiredVersion) || versionInResolutions.startsWith('~' + desiredVersion);
17
+ };
18
+ const verifyResolutionFromObject = (node, pkg, version, optional) => {
19
+ // For root package.json, we require the critical packages' resolutions exist and with matching version
20
+ // For individual package's package.json, it's ok if resolutions don't exist. But if they do, the version should match
21
+ const resolutionExist = node.properties.some(p => p.type === 'Property' && p.key.type === 'Literal' && p.key.value === pkg);
22
+ if (!resolutionExist) {
23
+ return optional;
24
+ }
25
+ const resolutionExistAndMatch = node.properties.some(p => p.type === 'Property' && p.key.type === 'Literal' && p.key.value === pkg && p.value.type === 'Literal' && matchMinorVersion(version, p.value.value));
26
+ return resolutionExistAndMatch;
27
+ };
28
+ const rule = {
29
+ meta: {
30
+ type: 'problem',
31
+ docs: {
32
+ description: 'Enforce the versions of critical packages are within desired ranges by checking resolutions section in package.json',
33
+ recommended: true
34
+ },
35
+ hasSuggestions: false,
36
+ messages: {
37
+ invalidPackageResolution: `Make sure the resolutions for the following packages match major and minor version ranges ${JSON.stringify(DESIRED_PKG_VERSIONS)}`
38
+ }
39
+ },
40
+ create(context) {
41
+ const fileName = context.getFilename();
42
+ return {
43
+ ObjectExpression: node => {
44
+ if (!fileName.endsWith('package.json') || node.type !== 'ObjectExpression') {
45
+ return;
46
+ }
47
+ const packageResolutions = getObjectPropertyAsObject(node, 'resolutions');
48
+ const rootDir = findRootSync(process.cwd());
49
+ const isRootPackageJson = fileName.endsWith(`${rootDir}/package.json`);
50
+ if (packageResolutions !== null) {
51
+ for (const [key, value] of Object.entries(DESIRED_PKG_VERSIONS)) {
52
+ if (!verifyResolutionFromObject(packageResolutions, key, value, !isRootPackageJson)) {
53
+ return context.report({
54
+ node,
55
+ messageId: 'invalidPackageResolution'
56
+ });
57
+ }
58
+ }
59
+ }
60
+ }
61
+ };
62
+ }
63
+ };
64
+ export default rule;
@@ -1,23 +1,4 @@
1
- const getObjectPropertyAsLiteral = (node, property) => {
2
- const prop = node.properties.find(p => p.type === 'Property' && p.key.type === 'Literal' && p.key.value === property);
3
-
4
- // double check for property is to make typescript happy
5
- if ((prop === null || prop === void 0 ? void 0 : prop.type) === 'Property' && (prop === null || prop === void 0 ? void 0 : prop.value.type) === 'Literal') {
6
- var _prop$value$value;
7
- return (_prop$value$value = prop.value.value) !== null && _prop$value$value !== void 0 ? _prop$value$value : null;
8
- }
9
- return null;
10
- };
11
- const getObjectPropertyAsObject = (node, property) => {
12
- const prop = node.properties.find(p => p.type === 'Property' && p.key.type === 'Literal' && p.key.value === property);
13
-
14
- // double check for property is to make typescript happy
15
- if ((prop === null || prop === void 0 ? void 0 : prop.type) === 'Property' && (prop === null || prop === void 0 ? void 0 : prop.value.type) === 'ObjectExpression') {
16
- var _prop$value;
17
- return (_prop$value = prop.value) !== null && _prop$value !== void 0 ? _prop$value : null;
18
- }
19
- return null;
20
- };
1
+ import { getObjectPropertyAsLiteral, getObjectPropertyAsObject } from '../util/handle-ast-object';
21
2
  const rule = {
22
3
  meta: {
23
4
  type: 'problem',
@@ -0,0 +1,20 @@
1
+ export const getObjectPropertyAsLiteral = (node, property) => {
2
+ const prop = node.properties.find(p => p.type === 'Property' && p.key.type === 'Literal' && p.key.value === property);
3
+
4
+ // double check for property is to make typescript happy
5
+ if ((prop === null || prop === void 0 ? void 0 : prop.type) === 'Property' && (prop === null || prop === void 0 ? void 0 : prop.value.type) === 'Literal') {
6
+ var _prop$value$value;
7
+ return (_prop$value$value = prop.value.value) !== null && _prop$value$value !== void 0 ? _prop$value$value : null;
8
+ }
9
+ return null;
10
+ };
11
+ export const getObjectPropertyAsObject = (node, property) => {
12
+ const prop = node.properties.find(p => p.type === 'Property' && p.key.type === 'Literal' && p.key.value === property);
13
+
14
+ // double check for property is to make typescript happy
15
+ if ((prop === null || prop === void 0 ? void 0 : prop.type) === 'Property' && (prop === null || prop === void 0 ? void 0 : prop.value.type) === 'ObjectExpression') {
16
+ var _prop$value;
17
+ return (_prop$value = prop.value) !== null && _prop$value !== void 0 ? _prop$value : null;
18
+ }
19
+ return null;
20
+ };
package/dist/esm/index.js CHANGED
@@ -5,6 +5,7 @@ import ensureTestRunnerNestedCount from './rules/ensure-test-runner-nested-count
5
5
  import ensureAtlassianTeam from './rules/ensure-atlassian-team';
6
6
  import noInvalidFeatureFlagUsage from './rules/no-invalid-feature-flag-usage';
7
7
  import ensureFeatureFlagPrefix from './rules/ensure-feature-flag-prefix';
8
+ import ensureCriticalDependencyResolutions from './rules/ensure-critical-dependency-resolutions';
8
9
  import noInvalidStorybookDecoratorUsage from './rules/no-invalid-storybook-decorator-usage';
9
10
  import ensurePublishValid from './rules/ensure-publish-valid';
10
11
  export var rules = {
@@ -13,6 +14,7 @@ export var rules = {
13
14
  'ensure-test-runner-arguments': ensureTestRunnerArguments,
14
15
  'ensure-test-runner-nested-count': ensureTestRunnerNestedCount,
15
16
  'ensure-atlassian-team': ensureAtlassianTeam,
17
+ 'ensure-critical-dependency-resolutions': ensureCriticalDependencyResolutions,
16
18
  'no-invalid-feature-flag-usage': noInvalidFeatureFlagUsage,
17
19
  'no-pre-post-install-scripts': noPreAndPostInstallScripts,
18
20
  'no-invalid-storybook-decorator-usage': noInvalidStorybookDecoratorUsage,
@@ -0,0 +1,80 @@
1
+ import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
2
+ import { findRootSync } from '@manypkg/find-root';
3
+ import { getObjectPropertyAsObject } from '../util/handle-ast-object';
4
+
5
+ // Here we only need to specify the major and minor versions
6
+ // In matchMinorVersion, we will check if the versions in resolutions fall in the right ranges.
7
+ var DESIRED_PKG_VERSIONS = {
8
+ typescript: '4.9',
9
+ '@types/react': '16.14'
10
+ };
11
+ var matchMinorVersion = function matchMinorVersion(desiredVersion, versionInResolutions) {
12
+ var firstChar = versionInResolutions[0];
13
+ // The version is invalid if it doesn't start with a number or ~
14
+ if (!/^\d$/.test(firstChar) && firstChar !== '~') {
15
+ return false;
16
+ }
17
+ return versionInResolutions.startsWith(desiredVersion) || versionInResolutions.startsWith('~' + desiredVersion);
18
+ };
19
+ var verifyResolutionFromObject = function verifyResolutionFromObject(node, pkg, version, optional) {
20
+ // For root package.json, we require the critical packages' resolutions exist and with matching version
21
+ // For individual package's package.json, it's ok if resolutions don't exist. But if they do, the version should match
22
+ var resolutionExist = node.properties.some(function (p) {
23
+ return p.type === 'Property' && p.key.type === 'Literal' && p.key.value === pkg;
24
+ });
25
+ if (!resolutionExist) {
26
+ return optional;
27
+ }
28
+ var resolutionExistAndMatch = node.properties.some(function (p) {
29
+ return p.type === 'Property' && p.key.type === 'Literal' && p.key.value === pkg && p.value.type === 'Literal' && matchMinorVersion(version, p.value.value);
30
+ });
31
+ return resolutionExistAndMatch;
32
+ };
33
+ var rule = {
34
+ meta: {
35
+ type: 'problem',
36
+ docs: {
37
+ description: 'Enforce the versions of critical packages are within desired ranges by checking resolutions section in package.json',
38
+ recommended: true
39
+ },
40
+ hasSuggestions: false,
41
+ messages: {
42
+ invalidPackageResolution: "Make sure the resolutions for the following packages match major and minor version ranges ".concat(JSON.stringify(DESIRED_PKG_VERSIONS))
43
+ }
44
+ },
45
+ create: function create(context) {
46
+ var fileName = context.getFilename();
47
+ return {
48
+ ObjectExpression: function (_ObjectExpression) {
49
+ function ObjectExpression(_x) {
50
+ return _ObjectExpression.apply(this, arguments);
51
+ }
52
+ ObjectExpression.toString = function () {
53
+ return _ObjectExpression.toString();
54
+ };
55
+ return ObjectExpression;
56
+ }(function (node) {
57
+ if (!fileName.endsWith('package.json') || node.type !== 'ObjectExpression') {
58
+ return;
59
+ }
60
+ var packageResolutions = getObjectPropertyAsObject(node, 'resolutions');
61
+ var rootDir = findRootSync(process.cwd());
62
+ var isRootPackageJson = fileName.endsWith("".concat(rootDir, "/package.json"));
63
+ if (packageResolutions !== null) {
64
+ for (var _i = 0, _Object$entries = Object.entries(DESIRED_PKG_VERSIONS); _i < _Object$entries.length; _i++) {
65
+ var _Object$entries$_i = _slicedToArray(_Object$entries[_i], 2),
66
+ key = _Object$entries$_i[0],
67
+ value = _Object$entries$_i[1];
68
+ if (!verifyResolutionFromObject(packageResolutions, key, value, !isRootPackageJson)) {
69
+ return context.report({
70
+ node: node,
71
+ messageId: 'invalidPackageResolution'
72
+ });
73
+ }
74
+ }
75
+ }
76
+ })
77
+ };
78
+ }
79
+ };
80
+ export default rule;
@@ -1,6 +1,6 @@
1
1
  import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
- function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
3
- function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
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; }
4
4
  import { getMetadataForFilename, getterIdentifierToFlagTypeMap } from '../util/registration-utils';
5
5
  var rule = {
6
6
  meta: {
@@ -1,27 +1,4 @@
1
- var getObjectPropertyAsLiteral = function getObjectPropertyAsLiteral(node, property) {
2
- var prop = node.properties.find(function (p) {
3
- return p.type === 'Property' && p.key.type === 'Literal' && p.key.value === property;
4
- });
5
-
6
- // double check for property is to make typescript happy
7
- if ((prop === null || prop === void 0 ? void 0 : prop.type) === 'Property' && (prop === null || prop === void 0 ? void 0 : prop.value.type) === 'Literal') {
8
- var _prop$value$value;
9
- return (_prop$value$value = prop.value.value) !== null && _prop$value$value !== void 0 ? _prop$value$value : null;
10
- }
11
- return null;
12
- };
13
- var getObjectPropertyAsObject = function getObjectPropertyAsObject(node, property) {
14
- var prop = node.properties.find(function (p) {
15
- return p.type === 'Property' && p.key.type === 'Literal' && p.key.value === property;
16
- });
17
-
18
- // double check for property is to make typescript happy
19
- if ((prop === null || prop === void 0 ? void 0 : prop.type) === 'Property' && (prop === null || prop === void 0 ? void 0 : prop.value.type) === 'ObjectExpression') {
20
- var _prop$value;
21
- return (_prop$value = prop.value) !== null && _prop$value !== void 0 ? _prop$value : null;
22
- }
23
- return null;
24
- };
1
+ import { getObjectPropertyAsLiteral, getObjectPropertyAsObject } from '../util/handle-ast-object';
25
2
  var rule = {
26
3
  meta: {
27
4
  type: 'problem',
@@ -1,6 +1,6 @@
1
1
  import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
- function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
3
- function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
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; }
4
4
  var NESTED_LIMIT = 4;
5
5
  var TEST_RUNNER_IDENTIFIER = 'ffTest';
6
6
  var getDepthOfNestedRunner = function getDepthOfNestedRunner(node) {
@@ -0,0 +1,24 @@
1
+ export var getObjectPropertyAsLiteral = function getObjectPropertyAsLiteral(node, property) {
2
+ var prop = node.properties.find(function (p) {
3
+ return p.type === 'Property' && p.key.type === 'Literal' && p.key.value === property;
4
+ });
5
+
6
+ // double check for property is to make typescript happy
7
+ if ((prop === null || prop === void 0 ? void 0 : prop.type) === 'Property' && (prop === null || prop === void 0 ? void 0 : prop.value.type) === 'Literal') {
8
+ var _prop$value$value;
9
+ return (_prop$value$value = prop.value.value) !== null && _prop$value$value !== void 0 ? _prop$value$value : null;
10
+ }
11
+ return null;
12
+ };
13
+ export var getObjectPropertyAsObject = function getObjectPropertyAsObject(node, property) {
14
+ var prop = node.properties.find(function (p) {
15
+ return p.type === 'Property' && p.key.type === 'Literal' && p.key.value === property;
16
+ });
17
+
18
+ // double check for property is to make typescript happy
19
+ if ((prop === null || prop === void 0 ? void 0 : prop.type) === 'Property' && (prop === null || prop === void 0 ? void 0 : prop.value.type) === 'ObjectExpression') {
20
+ var _prop$value;
21
+ return (_prop$value = prop.value) !== null && _prop$value !== void 0 ? _prop$value : null;
22
+ }
23
+ return null;
24
+ };
@@ -5,6 +5,7 @@ export declare const rules: {
5
5
  'ensure-test-runner-arguments': import("eslint").Rule.RuleModule;
6
6
  'ensure-test-runner-nested-count': import("eslint").Rule.RuleModule;
7
7
  'ensure-atlassian-team': import("eslint").Rule.RuleModule;
8
+ 'ensure-critical-dependency-resolutions': import("eslint").Rule.RuleModule;
8
9
  'no-invalid-feature-flag-usage': import("eslint").Rule.RuleModule;
9
10
  'no-pre-post-install-scripts': import("eslint").Rule.RuleModule;
10
11
  '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;
@@ -0,0 +1,3 @@
1
+ import type { ObjectExpression, SimpleLiteral, RegExpLiteral, BigIntLiteral } from 'estree';
2
+ export declare const getObjectPropertyAsLiteral: (node: ObjectExpression, property: string) => SimpleLiteral['value'] | RegExpLiteral['value'] | BigIntLiteral['value'];
3
+ export declare const getObjectPropertyAsObject: (node: ObjectExpression, property: string) => ObjectExpression | null;
@@ -5,6 +5,7 @@ export declare const rules: {
5
5
  'ensure-test-runner-arguments': import("eslint").Rule.RuleModule;
6
6
  'ensure-test-runner-nested-count': import("eslint").Rule.RuleModule;
7
7
  'ensure-atlassian-team': import("eslint").Rule.RuleModule;
8
+ 'ensure-critical-dependency-resolutions': import("eslint").Rule.RuleModule;
8
9
  'no-invalid-feature-flag-usage': import("eslint").Rule.RuleModule;
9
10
  'no-pre-post-install-scripts': import("eslint").Rule.RuleModule;
10
11
  '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;
@@ -0,0 +1,3 @@
1
+ import type { ObjectExpression, SimpleLiteral, RegExpLiteral, BigIntLiteral } from 'estree';
2
+ export declare const getObjectPropertyAsLiteral: (node: ObjectExpression, property: string) => SimpleLiteral['value'] | RegExpLiteral['value'] | BigIntLiteral['value'];
3
+ export declare const getObjectPropertyAsObject: (node: ObjectExpression, property: string) => ObjectExpression | null;
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.5",
4
+ "version": "0.2.6",
5
5
  "author": "Atlassian Pty Ltd",
6
6
  "atlassian": {
7
7
  "team": "UIP - Platform Integration Trust (PITa)",
@@ -31,6 +31,7 @@
31
31
  },
32
32
  "dependencies": {
33
33
  "@babel/runtime": "^7.0.0",
34
+ "@manypkg/find-root": "^1.1.0",
34
35
  "fuse.js": "^6.6.2",
35
36
  "read-pkg-up": "^7.0.1"
36
37
  },
package/report.api.md CHANGED
@@ -51,6 +51,7 @@ export const rules: {
51
51
  'ensure-test-runner-arguments': Rule.RuleModule;
52
52
  'ensure-test-runner-nested-count': Rule.RuleModule;
53
53
  'ensure-atlassian-team': Rule.RuleModule;
54
+ 'ensure-critical-dependency-resolutions': Rule.RuleModule;
54
55
  'no-invalid-feature-flag-usage': Rule.RuleModule;
55
56
  'no-pre-post-install-scripts': Rule.RuleModule;
56
57
  'no-invalid-storybook-decorator-usage': Rule.RuleModule;
package/src/index.tsx CHANGED
@@ -6,6 +6,7 @@ import ensureTestRunnerNestedCount from './rules/ensure-test-runner-nested-count
6
6
  import ensureAtlassianTeam from './rules/ensure-atlassian-team';
7
7
  import noInvalidFeatureFlagUsage from './rules/no-invalid-feature-flag-usage';
8
8
  import ensureFeatureFlagPrefix from './rules/ensure-feature-flag-prefix';
9
+ import ensureCriticalDependencyResolutions from './rules/ensure-critical-dependency-resolutions';
9
10
  import noInvalidStorybookDecoratorUsage from './rules/no-invalid-storybook-decorator-usage';
10
11
  import ensurePublishValid from './rules/ensure-publish-valid';
11
12
 
@@ -15,6 +16,7 @@ export const rules = {
15
16
  'ensure-test-runner-arguments': ensureTestRunnerArguments,
16
17
  'ensure-test-runner-nested-count': ensureTestRunnerNestedCount,
17
18
  'ensure-atlassian-team': ensureAtlassianTeam,
19
+ 'ensure-critical-dependency-resolutions': ensureCriticalDependencyResolutions,
18
20
  'no-invalid-feature-flag-usage': noInvalidFeatureFlagUsage,
19
21
  'no-pre-post-install-scripts': noPreAndPostInstallScripts,
20
22
  'no-invalid-storybook-decorator-usage': noInvalidStorybookDecoratorUsage,
@@ -0,0 +1,125 @@
1
+ import { tester } from '../../../../__tests__/utils/_tester';
2
+ import rule from '../../index';
3
+
4
+ const cwd = process.cwd();
5
+
6
+ describe('test ensure-critical-dependency-resolutions rule', () => {
7
+ tester.run('ensure-critical-dependency-resolutions', rule, {
8
+ valid: [
9
+ // Root package.json, have all of the correct resolutions
10
+ {
11
+ code: `const foo = {
12
+ "resolutions": {
13
+ "@types/react": "16.14.15",
14
+ "typescript": "4.9.5",
15
+ }
16
+ }`,
17
+ filename: `${cwd}/package.json`,
18
+ },
19
+ // Root package.json, have all of the correct resolutions with ~
20
+ {
21
+ code: `const foo = {
22
+ "resolutions": {
23
+ "@types/react": "~16.14.25",
24
+ "typescript": "~4.9.8",
25
+ }
26
+ }`,
27
+ filename: `${cwd}/package.json`,
28
+ },
29
+ // Individual package's package.json. Have part of correct resolutions
30
+ {
31
+ code: `const foo = {
32
+ "resolutions": {
33
+ "@types/react": "16.14.15",
34
+ }
35
+ }`,
36
+ filename: `${cwd}/package/name/package.json`,
37
+ },
38
+ // Individual package's package.json. Not have relevant package resolutions
39
+ {
40
+ code: `const foo = {
41
+ "resolutions": {
42
+ "@types/abcd": "1.2.3",
43
+ }
44
+ }`,
45
+ filename: `${cwd}/package/name/package.json`,
46
+ },
47
+ ],
48
+ invalid: [
49
+ // Root package.json. One package is correct, the other is missing
50
+ {
51
+ code: `const foo = {
52
+ "resolutions": {
53
+ "typescript": "~4.9.8",
54
+ }
55
+ }`,
56
+ filename: `${cwd}/package.json`,
57
+ errors: [
58
+ {
59
+ messageId: 'invalidPackageResolution',
60
+ },
61
+ ],
62
+ },
63
+ // Root package.json. Both packages have the wrong version ranges
64
+ {
65
+ code: `const foo = {
66
+ "resolutions": {
67
+ "@types/react": "16.8.25",
68
+ "typescript": "4.5.8",
69
+ }
70
+ }`,
71
+ filename: `${cwd}/package.json`,
72
+ errors: [
73
+ {
74
+ messageId: 'invalidPackageResolution',
75
+ },
76
+ ],
77
+ },
78
+ // Root package.json. One package is correct, the other has wrong version range
79
+ {
80
+ code: `const foo = {
81
+ "resolutions": {
82
+ "@types/react": "~16.14.25",
83
+ "typescript": "~4.5.8",
84
+ }
85
+ }`,
86
+ filename: `${cwd}/package.json`,
87
+ errors: [
88
+ {
89
+ messageId: 'invalidPackageResolution',
90
+ },
91
+ ],
92
+ },
93
+ // Root package.json. One package is correct, the other has ^ in its version
94
+ {
95
+ code: `const foo = {
96
+ "resolutions": {
97
+ "@types/react": "~16.14.25",
98
+ "typescript": "^4.9.5",
99
+ }
100
+ }`,
101
+ filename: `${cwd}/package.json`,
102
+ errors: [
103
+ {
104
+ messageId: 'invalidPackageResolution',
105
+ },
106
+ ],
107
+ },
108
+ // Individual package's package.json. One package is correct, the other is wrong
109
+ {
110
+ code: `const foo = {
111
+ "resolutions": {
112
+ "@types/react": "16.14.15",
113
+ "typescript": "4.5.8",
114
+ }
115
+ }`,
116
+ filename: `${cwd}/packages/packge/directory/package.json`,
117
+ errors: [
118
+ {
119
+ messageId: 'invalidPackageResolution',
120
+ },
121
+ ],
122
+ },
123
+ ],
124
+ });
125
+ });
@@ -0,0 +1,113 @@
1
+ import { findRootSync } from '@manypkg/find-root';
2
+ import type { Rule } from 'eslint';
3
+ import type { ObjectExpression } from 'estree';
4
+ import { getObjectPropertyAsObject } from '../util/handle-ast-object';
5
+
6
+ // Here we only need to specify the major and minor versions
7
+ // In matchMinorVersion, we will check if the versions in resolutions fall in the right ranges.
8
+ const DESIRED_PKG_VERSIONS: Record<string, string> = {
9
+ typescript: '4.9',
10
+ '@types/react': '16.14',
11
+ };
12
+
13
+ const matchMinorVersion = (
14
+ desiredVersion: string,
15
+ versionInResolutions: string,
16
+ ): boolean => {
17
+ const firstChar = versionInResolutions[0];
18
+ // The version is invalid if it doesn't start with a number or ~
19
+ if (!/^\d$/.test(firstChar) && firstChar !== '~') {
20
+ return false;
21
+ }
22
+
23
+ return (
24
+ versionInResolutions.startsWith(desiredVersion) ||
25
+ versionInResolutions.startsWith('~' + desiredVersion)
26
+ );
27
+ };
28
+
29
+ const verifyResolutionFromObject = (
30
+ node: ObjectExpression,
31
+ pkg: string,
32
+ version: string,
33
+ optional: boolean,
34
+ ): boolean => {
35
+ // For root package.json, we require the critical packages' resolutions exist and with matching version
36
+ // For individual package's package.json, it's ok if resolutions don't exist. But if they do, the version should match
37
+ const resolutionExist = node.properties.some(
38
+ (p) =>
39
+ p.type === 'Property' && p.key.type === 'Literal' && p.key.value === pkg,
40
+ );
41
+
42
+ if (!resolutionExist) {
43
+ return optional;
44
+ }
45
+
46
+ const resolutionExistAndMatch = node.properties.some(
47
+ (p) =>
48
+ p.type === 'Property' &&
49
+ p.key.type === 'Literal' &&
50
+ p.key.value === pkg &&
51
+ p.value.type === 'Literal' &&
52
+ matchMinorVersion(version, p.value.value as string),
53
+ );
54
+
55
+ return resolutionExistAndMatch;
56
+ };
57
+
58
+ const rule: Rule.RuleModule = {
59
+ meta: {
60
+ type: 'problem',
61
+ docs: {
62
+ description:
63
+ 'Enforce the versions of critical packages are within desired ranges by checking resolutions section in package.json',
64
+ recommended: true,
65
+ },
66
+ hasSuggestions: false,
67
+ messages: {
68
+ invalidPackageResolution: `Make sure the resolutions for the following packages match major and minor version ranges ${JSON.stringify(
69
+ DESIRED_PKG_VERSIONS,
70
+ )}`,
71
+ },
72
+ },
73
+ create(context) {
74
+ const fileName = context.getFilename();
75
+ return {
76
+ ObjectExpression: (node: Rule.Node) => {
77
+ if (
78
+ !fileName.endsWith('package.json') ||
79
+ node.type !== 'ObjectExpression'
80
+ ) {
81
+ return;
82
+ }
83
+
84
+ const packageResolutions = getObjectPropertyAsObject(
85
+ node,
86
+ 'resolutions',
87
+ );
88
+ const rootDir = findRootSync(process.cwd());
89
+ const isRootPackageJson = fileName.endsWith(`${rootDir}/package.json`);
90
+
91
+ if (packageResolutions !== null) {
92
+ for (const [key, value] of Object.entries(DESIRED_PKG_VERSIONS)) {
93
+ if (
94
+ !verifyResolutionFromObject(
95
+ packageResolutions as ObjectExpression,
96
+ key,
97
+ value,
98
+ !isRootPackageJson,
99
+ )
100
+ ) {
101
+ return context.report({
102
+ node,
103
+ messageId: 'invalidPackageResolution',
104
+ });
105
+ }
106
+ }
107
+ }
108
+ },
109
+ };
110
+ },
111
+ };
112
+
113
+ export default rule;
@@ -1,47 +1,8 @@
1
1
  import type { Rule } from 'eslint';
2
- import type {
3
- ObjectExpression,
4
- SimpleLiteral,
5
- RegExpLiteral,
6
- BigIntLiteral,
7
- } from 'estree';
8
- const getObjectPropertyAsLiteral = (
9
- node: ObjectExpression,
10
- property: string,
11
- ): SimpleLiteral['value'] | RegExpLiteral['value'] | BigIntLiteral['value'] => {
12
- const prop = node.properties.find(
13
- (p) =>
14
- p.type === 'Property' &&
15
- p.key.type === 'Literal' &&
16
- p.key.value === property,
17
- );
18
-
19
- // double check for property is to make typescript happy
20
- if (prop?.type === 'Property' && prop?.value.type === 'Literal') {
21
- return prop.value.value ?? null;
22
- }
23
-
24
- return null;
25
- };
26
-
27
- const getObjectPropertyAsObject = (
28
- node: ObjectExpression,
29
- property: string,
30
- ): ObjectExpression | null => {
31
- const prop = node.properties.find(
32
- (p) =>
33
- p.type === 'Property' &&
34
- p.key.type === 'Literal' &&
35
- p.key.value === property,
36
- );
37
-
38
- // double check for property is to make typescript happy
39
- if (prop?.type === 'Property' && prop?.value.type === 'ObjectExpression') {
40
- return prop.value ?? null;
41
- }
42
-
43
- return null;
44
- };
2
+ import {
3
+ getObjectPropertyAsLiteral,
4
+ getObjectPropertyAsObject,
5
+ } from '../util/handle-ast-object';
45
6
 
46
7
  type RuleOptions = {
47
8
  // exceptions to this rule, will be ignored
@@ -0,0 +1,44 @@
1
+ import type {
2
+ ObjectExpression,
3
+ SimpleLiteral,
4
+ RegExpLiteral,
5
+ BigIntLiteral,
6
+ } from 'estree';
7
+
8
+ export const getObjectPropertyAsLiteral = (
9
+ node: ObjectExpression,
10
+ property: string,
11
+ ): SimpleLiteral['value'] | RegExpLiteral['value'] | BigIntLiteral['value'] => {
12
+ const prop = node.properties.find(
13
+ (p) =>
14
+ p.type === 'Property' &&
15
+ p.key.type === 'Literal' &&
16
+ p.key.value === property,
17
+ );
18
+
19
+ // double check for property is to make typescript happy
20
+ if (prop?.type === 'Property' && prop?.value.type === 'Literal') {
21
+ return prop.value.value ?? null;
22
+ }
23
+
24
+ return null;
25
+ };
26
+
27
+ export const getObjectPropertyAsObject = (
28
+ node: ObjectExpression,
29
+ property: string,
30
+ ): ObjectExpression | null => {
31
+ const prop = node.properties.find(
32
+ (p) =>
33
+ p.type === 'Property' &&
34
+ p.key.type === 'Literal' &&
35
+ p.key.value === property,
36
+ );
37
+
38
+ // double check for property is to make typescript happy
39
+ if (prop?.type === 'Property' && prop?.value.type === 'ObjectExpression') {
40
+ return prop.value ?? null;
41
+ }
42
+
43
+ return null;
44
+ };
@@ -37,6 +37,7 @@ export const rules: {
37
37
  'ensure-test-runner-arguments': Rule.RuleModule;
38
38
  'ensure-test-runner-nested-count': Rule.RuleModule;
39
39
  'ensure-atlassian-team': Rule.RuleModule;
40
+ 'ensure-critical-dependency-resolutions': Rule.RuleModule;
40
41
  'no-invalid-feature-flag-usage': Rule.RuleModule;
41
42
  'no-pre-post-install-scripts': Rule.RuleModule;
42
43
  'no-invalid-storybook-decorator-usage': Rule.RuleModule;
@@ -0,0 +1,36 @@
1
+ {
2
+ "extends": "../../../tsconfig.node.json",
3
+ "include": ["./src/**/*.ts", "./src/**/*.tsx"],
4
+ "exclude": [
5
+ "**/docs/**/*",
6
+ "**/__tests__/**/*",
7
+ "**/vr-tests/**/*",
8
+ "**/__perf__/**/*",
9
+ "**/*.test.*",
10
+ "**/test.*",
11
+ "**/test-*",
12
+ "**/examples.ts",
13
+ "**/examples.tsx",
14
+ "**/examples/*.ts",
15
+ "**/examples/*.tsx",
16
+ "**/examples/**/*.ts",
17
+ "**/examples/**/*.tsx",
18
+ "**/storybook/**/*",
19
+ "**/constellation/**/*",
20
+ ".storybook/*",
21
+ "./__fixtures__/**/*",
22
+ "./__generated__/**/*",
23
+ "./mocks/**/*",
24
+ "./__mocks__/**/*",
25
+ "**/mock.*",
26
+ "**/codemods/**/*.ts",
27
+ "**/codemods/**/*.tsx"
28
+ ],
29
+ "compilerOptions": {
30
+ "baseUrl": "./",
31
+ "lib": ["ES2021.String"],
32
+ "composite": true,
33
+ "outDir": "../../../tsDist/@atlaskit__eslint-plugin-platform/app"
34
+ },
35
+ "references": []
36
+ }
@@ -0,0 +1,40 @@
1
+ {
2
+ "extends": "../../../tsconfig.node.json",
3
+ "include": [
4
+ "**/docs/**/*",
5
+ "**/__tests__/**/*",
6
+ "**/vr-tests/**/*",
7
+ "**/__perf__/**/*",
8
+ "**/*.test.*",
9
+ "**/test.*",
10
+ "**/test-*",
11
+ "**/examples.ts",
12
+ "**/examples.tsx",
13
+ "**/examples/*.ts",
14
+ "**/examples/*.tsx",
15
+ "**/examples/**/*.ts",
16
+ "**/examples/**/*.tsx",
17
+ "**/storybook/**/*",
18
+ "**/constellation/**/*",
19
+ ".storybook/*",
20
+ "./__fixtures__/**/*",
21
+ "./__generated__/**/*",
22
+ "./mocks/**/*",
23
+ "./__mocks__/**/*",
24
+ "**/mock.*",
25
+ "**/codemods/**/*.ts",
26
+ "**/codemods/**/*.tsx"
27
+ ],
28
+ "exclude": ["./dist/**/*", "./build/**/*", "./node_modules/**/*"],
29
+ "compilerOptions": {
30
+ "baseUrl": "./",
31
+ "lib": ["ES2021.String"],
32
+ "composite": true,
33
+ "outDir": "../../../tsDist/@atlaskit__eslint-plugin-platform/dev"
34
+ },
35
+ "references": [
36
+ {
37
+ "path": "tsconfig.app.json"
38
+ }
39
+ ]
40
+ }