@atlaskit/eslint-plugin-platform 0.8.0 → 0.9.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.
- package/CHANGELOG.md +9 -0
- package/dist/cjs/index.js +2 -0
- package/dist/cjs/rules/ensure-valid-bin-values/index.js +68 -0
- package/dist/es2019/index.js +2 -0
- package/dist/es2019/rules/ensure-valid-bin-values/index.js +60 -0
- package/dist/esm/index.js +2 -0
- package/dist/esm/rules/ensure-valid-bin-values/index.js +60 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/rules/ensure-valid-bin-values/index.d.ts +3 -0
- package/dist/types-ts4.5/index.d.ts +1 -0
- package/dist/types-ts4.5/rules/ensure-valid-bin-values/index.d.ts +3 -0
- package/package.json +1 -1
- package/src/index.tsx +2 -0
- package/src/rules/ensure-valid-bin-values/__tests__/unit/rule.test.ts +158 -0
- package/src/rules/ensure-valid-bin-values/index.ts +70 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# @atlaskit/eslint-plugin-platform
|
|
2
2
|
|
|
3
|
+
## 0.9.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#146603](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/pull-requests/146603)
|
|
8
|
+
[`73a0361be46a2`](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/commits/73a0361be46a2) -
|
|
9
|
+
Created new rule `@atlaskit/platform/ensure-valid-bin-values` which validates bin values in
|
|
10
|
+
package.json files are valid point to files, not directories.
|
|
11
|
+
|
|
3
12
|
## 0.8.0
|
|
4
13
|
|
|
5
14
|
### Minor Changes
|
package/dist/cjs/index.js
CHANGED
|
@@ -16,6 +16,7 @@ var _noInvalidFeatureFlagUsage = _interopRequireDefault(require("./rules/no-inva
|
|
|
16
16
|
var _ensureFeatureFlagPrefix = _interopRequireDefault(require("./rules/ensure-feature-flag-prefix"));
|
|
17
17
|
var _ensureCriticalDependencyResolutions = _interopRequireDefault(require("./rules/ensure-critical-dependency-resolutions"));
|
|
18
18
|
var _ensureValidWorkspaceProtocolUsage = _interopRequireDefault(require("./rules/ensure-valid-workspace-protocol-usage"));
|
|
19
|
+
var _ensureValidBinValues = _interopRequireDefault(require("./rules/ensure-valid-bin-values"));
|
|
19
20
|
var _noInvalidStorybookDecoratorUsage = _interopRequireDefault(require("./rules/no-invalid-storybook-decorator-usage"));
|
|
20
21
|
var _ensurePublishValid = _interopRequireDefault(require("./rules/ensure-publish-valid"));
|
|
21
22
|
var _ensureNativeAndAfExportsSynced = _interopRequireDefault(require("./rules/ensure-native-and-af-exports-synced"));
|
|
@@ -37,6 +38,7 @@ var rules = exports.rules = {
|
|
|
37
38
|
'ensure-atlassian-team': _ensureAtlassianTeam.default,
|
|
38
39
|
'ensure-critical-dependency-resolutions': _ensureCriticalDependencyResolutions.default,
|
|
39
40
|
'ensure-valid-workspace-protocol-usage': _ensureValidWorkspaceProtocolUsage.default,
|
|
41
|
+
'ensure-valid-bin-values': _ensureValidBinValues.default,
|
|
40
42
|
'no-duplicate-dependencies': _noDuplicateDependencies.default,
|
|
41
43
|
'no-invalid-feature-flag-usage': _noInvalidFeatureFlagUsage.default,
|
|
42
44
|
'no-pre-post-install-scripts': _noPrePostInstalls.default,
|
|
@@ -0,0 +1,68 @@
|
|
|
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 _fs = _interopRequireDefault(require("fs"));
|
|
9
|
+
var _path = require("path");
|
|
10
|
+
var _handleAstObject = require("../util/handle-ast-object");
|
|
11
|
+
// eslint-disable-next-line import/no-extraneous-dependencies
|
|
12
|
+
|
|
13
|
+
var cwd = process.cwd();
|
|
14
|
+
function checkIsAllBinValuesAreValid(node, packageDir) {
|
|
15
|
+
var binObj = (0, _handleAstObject.getObjectPropertyAsObject)(node, 'bin');
|
|
16
|
+
if (!binObj || !Array.isArray(binObj.properties)) {
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
return binObj.properties.every(function (p) {
|
|
20
|
+
if (p.type === 'Property' && p.value.type === 'Literal') {
|
|
21
|
+
try {
|
|
22
|
+
var binValue = String(p.value.value);
|
|
23
|
+
var pathToBin = (0, _path.resolve)(cwd, packageDir, binValue);
|
|
24
|
+
// Ignore bin values that point to dist as these files don't always exist
|
|
25
|
+
if (binValue.startsWith('./dist/')) {
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
return _fs.default.statSync(pathToBin).isFile();
|
|
29
|
+
} catch (err) {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
// If it's not a property or doesn't have a literal value, consider it invalid
|
|
34
|
+
return false;
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
var rule = {
|
|
38
|
+
meta: {
|
|
39
|
+
type: 'problem',
|
|
40
|
+
docs: {
|
|
41
|
+
description: "Ensures bin values in package.json files are valid.",
|
|
42
|
+
recommended: true
|
|
43
|
+
},
|
|
44
|
+
hasSuggestions: false,
|
|
45
|
+
messages: {
|
|
46
|
+
invalidBinValue: "Invalid bin value. Ensure that the value points to a file and not a directory."
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
create: function create(context) {
|
|
50
|
+
var fileName = context.getFilename();
|
|
51
|
+
return {
|
|
52
|
+
ObjectExpression: function ObjectExpression(node) {
|
|
53
|
+
if (!fileName.endsWith('package.json') || node.type !== 'ObjectExpression') {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
var isAllBinValuesValid = checkIsAllBinValuesAreValid(node, (0, _path.dirname)(fileName));
|
|
57
|
+
if (isAllBinValuesValid) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
return context.report({
|
|
61
|
+
node: node,
|
|
62
|
+
messageId: 'invalidBinValue'
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
var _default = exports.default = rule;
|
package/dist/es2019/index.js
CHANGED
|
@@ -10,6 +10,7 @@ import noInvalidFeatureFlagUsage from './rules/no-invalid-feature-flag-usage';
|
|
|
10
10
|
import ensureFeatureFlagPrefix from './rules/ensure-feature-flag-prefix';
|
|
11
11
|
import ensureCriticalDependencyResolutions from './rules/ensure-critical-dependency-resolutions';
|
|
12
12
|
import ensureValidWorkspaceProtocolUsage from './rules/ensure-valid-workspace-protocol-usage';
|
|
13
|
+
import ensureValidBinValues from './rules/ensure-valid-bin-values';
|
|
13
14
|
import noInvalidStorybookDecoratorUsage from './rules/no-invalid-storybook-decorator-usage';
|
|
14
15
|
import ensurePublishValid from './rules/ensure-publish-valid';
|
|
15
16
|
import ensureNativeAndAfExportsSynced from './rules/ensure-native-and-af-exports-synced';
|
|
@@ -29,6 +30,7 @@ export const rules = {
|
|
|
29
30
|
'ensure-atlassian-team': ensureAtlassianTeam,
|
|
30
31
|
'ensure-critical-dependency-resolutions': ensureCriticalDependencyResolutions,
|
|
31
32
|
'ensure-valid-workspace-protocol-usage': ensureValidWorkspaceProtocolUsage,
|
|
33
|
+
'ensure-valid-bin-values': ensureValidBinValues,
|
|
32
34
|
'no-duplicate-dependencies': noDuplicateDependencies,
|
|
33
35
|
'no-invalid-feature-flag-usage': noInvalidFeatureFlagUsage,
|
|
34
36
|
'no-pre-post-install-scripts': noPreAndPostInstallScripts,
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
// eslint-disable-next-line import/no-extraneous-dependencies
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
import { resolve, dirname } from 'path';
|
|
4
|
+
import { getObjectPropertyAsObject } from '../util/handle-ast-object';
|
|
5
|
+
const cwd = process.cwd();
|
|
6
|
+
function checkIsAllBinValuesAreValid(node, packageDir) {
|
|
7
|
+
const binObj = getObjectPropertyAsObject(node, 'bin');
|
|
8
|
+
if (!binObj || !Array.isArray(binObj.properties)) {
|
|
9
|
+
return true;
|
|
10
|
+
}
|
|
11
|
+
return binObj.properties.every(p => {
|
|
12
|
+
if (p.type === 'Property' && p.value.type === 'Literal') {
|
|
13
|
+
try {
|
|
14
|
+
const binValue = String(p.value.value);
|
|
15
|
+
const pathToBin = resolve(cwd, packageDir, binValue);
|
|
16
|
+
// Ignore bin values that point to dist as these files don't always exist
|
|
17
|
+
if (binValue.startsWith('./dist/')) {
|
|
18
|
+
return true;
|
|
19
|
+
}
|
|
20
|
+
return fs.statSync(pathToBin).isFile();
|
|
21
|
+
} catch (err) {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
// If it's not a property or doesn't have a literal value, consider it invalid
|
|
26
|
+
return false;
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
const rule = {
|
|
30
|
+
meta: {
|
|
31
|
+
type: 'problem',
|
|
32
|
+
docs: {
|
|
33
|
+
description: `Ensures bin values in package.json files are valid.`,
|
|
34
|
+
recommended: true
|
|
35
|
+
},
|
|
36
|
+
hasSuggestions: false,
|
|
37
|
+
messages: {
|
|
38
|
+
invalidBinValue: `Invalid bin value. Ensure that the value points to a file and not a directory.`
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
create(context) {
|
|
42
|
+
const fileName = context.getFilename();
|
|
43
|
+
return {
|
|
44
|
+
ObjectExpression: node => {
|
|
45
|
+
if (!fileName.endsWith('package.json') || node.type !== 'ObjectExpression') {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
const isAllBinValuesValid = checkIsAllBinValuesAreValid(node, dirname(fileName));
|
|
49
|
+
if (isAllBinValuesValid) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
return context.report({
|
|
53
|
+
node,
|
|
54
|
+
messageId: 'invalidBinValue'
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
export default rule;
|
package/dist/esm/index.js
CHANGED
|
@@ -13,6 +13,7 @@ import noInvalidFeatureFlagUsage from './rules/no-invalid-feature-flag-usage';
|
|
|
13
13
|
import ensureFeatureFlagPrefix from './rules/ensure-feature-flag-prefix';
|
|
14
14
|
import ensureCriticalDependencyResolutions from './rules/ensure-critical-dependency-resolutions';
|
|
15
15
|
import ensureValidWorkspaceProtocolUsage from './rules/ensure-valid-workspace-protocol-usage';
|
|
16
|
+
import ensureValidBinValues from './rules/ensure-valid-bin-values';
|
|
16
17
|
import noInvalidStorybookDecoratorUsage from './rules/no-invalid-storybook-decorator-usage';
|
|
17
18
|
import ensurePublishValid from './rules/ensure-publish-valid';
|
|
18
19
|
import ensureNativeAndAfExportsSynced from './rules/ensure-native-and-af-exports-synced';
|
|
@@ -32,6 +33,7 @@ export var rules = {
|
|
|
32
33
|
'ensure-atlassian-team': ensureAtlassianTeam,
|
|
33
34
|
'ensure-critical-dependency-resolutions': ensureCriticalDependencyResolutions,
|
|
34
35
|
'ensure-valid-workspace-protocol-usage': ensureValidWorkspaceProtocolUsage,
|
|
36
|
+
'ensure-valid-bin-values': ensureValidBinValues,
|
|
35
37
|
'no-duplicate-dependencies': noDuplicateDependencies,
|
|
36
38
|
'no-invalid-feature-flag-usage': noInvalidFeatureFlagUsage,
|
|
37
39
|
'no-pre-post-install-scripts': noPreAndPostInstallScripts,
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
// eslint-disable-next-line import/no-extraneous-dependencies
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
import { resolve, dirname } from 'path';
|
|
4
|
+
import { getObjectPropertyAsObject } from '../util/handle-ast-object';
|
|
5
|
+
var cwd = process.cwd();
|
|
6
|
+
function checkIsAllBinValuesAreValid(node, packageDir) {
|
|
7
|
+
var binObj = getObjectPropertyAsObject(node, 'bin');
|
|
8
|
+
if (!binObj || !Array.isArray(binObj.properties)) {
|
|
9
|
+
return true;
|
|
10
|
+
}
|
|
11
|
+
return binObj.properties.every(function (p) {
|
|
12
|
+
if (p.type === 'Property' && p.value.type === 'Literal') {
|
|
13
|
+
try {
|
|
14
|
+
var binValue = String(p.value.value);
|
|
15
|
+
var pathToBin = resolve(cwd, packageDir, binValue);
|
|
16
|
+
// Ignore bin values that point to dist as these files don't always exist
|
|
17
|
+
if (binValue.startsWith('./dist/')) {
|
|
18
|
+
return true;
|
|
19
|
+
}
|
|
20
|
+
return fs.statSync(pathToBin).isFile();
|
|
21
|
+
} catch (err) {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
// If it's not a property or doesn't have a literal value, consider it invalid
|
|
26
|
+
return false;
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
var rule = {
|
|
30
|
+
meta: {
|
|
31
|
+
type: 'problem',
|
|
32
|
+
docs: {
|
|
33
|
+
description: "Ensures bin values in package.json files are valid.",
|
|
34
|
+
recommended: true
|
|
35
|
+
},
|
|
36
|
+
hasSuggestions: false,
|
|
37
|
+
messages: {
|
|
38
|
+
invalidBinValue: "Invalid bin value. Ensure that the value points to a file and not a directory."
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
create: function create(context) {
|
|
42
|
+
var fileName = context.getFilename();
|
|
43
|
+
return {
|
|
44
|
+
ObjectExpression: function ObjectExpression(node) {
|
|
45
|
+
if (!fileName.endsWith('package.json') || node.type !== 'ObjectExpression') {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
var isAllBinValuesValid = checkIsAllBinValuesAreValid(node, dirname(fileName));
|
|
49
|
+
if (isAllBinValuesValid) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
return context.report({
|
|
53
|
+
node: node,
|
|
54
|
+
messageId: 'invalidBinValue'
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
export default rule;
|
package/dist/types/index.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ export declare const rules: {
|
|
|
7
7
|
'ensure-atlassian-team': import("eslint").Rule.RuleModule;
|
|
8
8
|
'ensure-critical-dependency-resolutions': import("eslint").Rule.RuleModule;
|
|
9
9
|
'ensure-valid-workspace-protocol-usage': import("eslint").Rule.RuleModule;
|
|
10
|
+
'ensure-valid-bin-values': import("eslint").Rule.RuleModule;
|
|
10
11
|
'no-duplicate-dependencies': import("eslint").Rule.RuleModule;
|
|
11
12
|
'no-invalid-feature-flag-usage': import("eslint").Rule.RuleModule;
|
|
12
13
|
'no-pre-post-install-scripts': import("eslint").Rule.RuleModule;
|
|
@@ -7,6 +7,7 @@ export declare const rules: {
|
|
|
7
7
|
'ensure-atlassian-team': import("eslint").Rule.RuleModule;
|
|
8
8
|
'ensure-critical-dependency-resolutions': import("eslint").Rule.RuleModule;
|
|
9
9
|
'ensure-valid-workspace-protocol-usage': import("eslint").Rule.RuleModule;
|
|
10
|
+
'ensure-valid-bin-values': import("eslint").Rule.RuleModule;
|
|
10
11
|
'no-duplicate-dependencies': import("eslint").Rule.RuleModule;
|
|
11
12
|
'no-invalid-feature-flag-usage': import("eslint").Rule.RuleModule;
|
|
12
13
|
'no-pre-post-install-scripts': import("eslint").Rule.RuleModule;
|
package/package.json
CHANGED
package/src/index.tsx
CHANGED
|
@@ -10,6 +10,7 @@ import noInvalidFeatureFlagUsage from './rules/no-invalid-feature-flag-usage';
|
|
|
10
10
|
import ensureFeatureFlagPrefix from './rules/ensure-feature-flag-prefix';
|
|
11
11
|
import ensureCriticalDependencyResolutions from './rules/ensure-critical-dependency-resolutions';
|
|
12
12
|
import ensureValidWorkspaceProtocolUsage from './rules/ensure-valid-workspace-protocol-usage';
|
|
13
|
+
import ensureValidBinValues from './rules/ensure-valid-bin-values';
|
|
13
14
|
import noInvalidStorybookDecoratorUsage from './rules/no-invalid-storybook-decorator-usage';
|
|
14
15
|
import ensurePublishValid from './rules/ensure-publish-valid';
|
|
15
16
|
import ensureNativeAndAfExportsSynced from './rules/ensure-native-and-af-exports-synced';
|
|
@@ -30,6 +31,7 @@ export const rules = {
|
|
|
30
31
|
'ensure-atlassian-team': ensureAtlassianTeam,
|
|
31
32
|
'ensure-critical-dependency-resolutions': ensureCriticalDependencyResolutions,
|
|
32
33
|
'ensure-valid-workspace-protocol-usage': ensureValidWorkspaceProtocolUsage,
|
|
34
|
+
'ensure-valid-bin-values': ensureValidBinValues,
|
|
33
35
|
'no-duplicate-dependencies': noDuplicateDependencies,
|
|
34
36
|
'no-invalid-feature-flag-usage': noInvalidFeatureFlagUsage,
|
|
35
37
|
'no-pre-post-install-scripts': noPreAndPostInstallScripts,
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { tester } from '../../../../__tests__/utils/_tester';
|
|
2
|
+
import rule from '../../index';
|
|
3
|
+
|
|
4
|
+
const cwd = process.cwd();
|
|
5
|
+
|
|
6
|
+
const mockValidBinPaths = [
|
|
7
|
+
`${cwd}/packages/foo/run-ts.bin`,
|
|
8
|
+
`${cwd}/packages/foo/scripts/run-ts.bin`,
|
|
9
|
+
`${cwd}/packages/foo/bar/run-ts.ts`,
|
|
10
|
+
`${cwd}/packages/foo/bar/scripts/run-ts.ts`,
|
|
11
|
+
`${cwd}/packages/baz/run-ts.js`,
|
|
12
|
+
`${cwd}/packages/baz/scripts/run-ts.js`,
|
|
13
|
+
];
|
|
14
|
+
|
|
15
|
+
jest.mock('fs', () => {
|
|
16
|
+
const actual = jest.requireActual('fs');
|
|
17
|
+
return {
|
|
18
|
+
...actual,
|
|
19
|
+
statSync: jest.fn((stat: string) => ({
|
|
20
|
+
isFile: jest.fn(() => mockValidBinPaths.includes(stat)),
|
|
21
|
+
})),
|
|
22
|
+
};
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
describe('test ensure-valid-bin-values rule', () => {
|
|
26
|
+
tester.run('ensure-valid-bin-values', rule, {
|
|
27
|
+
valid: [
|
|
28
|
+
// .bin files are valid
|
|
29
|
+
{
|
|
30
|
+
code: `const foo = {
|
|
31
|
+
"bin": {
|
|
32
|
+
"run-ts": "./run-ts.bin",
|
|
33
|
+
}
|
|
34
|
+
}`,
|
|
35
|
+
filename: `${cwd}/packages/foo/package.json`,
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
code: `const foo = {
|
|
39
|
+
"bin": {
|
|
40
|
+
"run-ts": "./scripts/run-ts.bin",
|
|
41
|
+
}
|
|
42
|
+
}`,
|
|
43
|
+
filename: `${cwd}/packages/foo/package.json`,
|
|
44
|
+
},
|
|
45
|
+
// .ts files are valid
|
|
46
|
+
{
|
|
47
|
+
code: `const foo = {
|
|
48
|
+
"bin": {
|
|
49
|
+
"run-ts": "./run-ts.ts",
|
|
50
|
+
}
|
|
51
|
+
}`,
|
|
52
|
+
filename: `${cwd}/packages/foo/bar/package.json`,
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
code: `const foo = {
|
|
56
|
+
"bin": {
|
|
57
|
+
"run-ts": "./scripts/run-ts.ts",
|
|
58
|
+
}
|
|
59
|
+
}`,
|
|
60
|
+
filename: `${cwd}/packages/foo/bar/package.json`,
|
|
61
|
+
},
|
|
62
|
+
// .js files are valid
|
|
63
|
+
{
|
|
64
|
+
code: `const foo = {
|
|
65
|
+
"bin": {
|
|
66
|
+
"run-ts": "./run-ts.js",
|
|
67
|
+
}
|
|
68
|
+
}`,
|
|
69
|
+
filename: `${cwd}/packages/baz/package.json`,
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
code: `const foo = {
|
|
73
|
+
"bin": {
|
|
74
|
+
"run-ts": "./scripts/run-ts.js",
|
|
75
|
+
}
|
|
76
|
+
}`,
|
|
77
|
+
filename: `${cwd}/packages/baz/package.json`,
|
|
78
|
+
},
|
|
79
|
+
// dist paths are valid
|
|
80
|
+
{
|
|
81
|
+
code: `const foo = {
|
|
82
|
+
"bin": {
|
|
83
|
+
"run-ts": "./dist/run-ts.js",
|
|
84
|
+
}
|
|
85
|
+
}`,
|
|
86
|
+
filename: `${cwd}/packages/baz/package.json`,
|
|
87
|
+
},
|
|
88
|
+
],
|
|
89
|
+
invalid: [
|
|
90
|
+
// Pointing to anything other than a file is invalid
|
|
91
|
+
{
|
|
92
|
+
code: `const foo = {
|
|
93
|
+
"bin": {
|
|
94
|
+
"run-ts": "./bin",
|
|
95
|
+
}
|
|
96
|
+
}`,
|
|
97
|
+
filename: `${cwd}/packages/foo/package.json`,
|
|
98
|
+
errors: [
|
|
99
|
+
{
|
|
100
|
+
messageId: 'invalidBinValue',
|
|
101
|
+
},
|
|
102
|
+
],
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
code: `const foo = {
|
|
106
|
+
"bin": {
|
|
107
|
+
"run-ts": "./scripts/index",
|
|
108
|
+
}
|
|
109
|
+
}`,
|
|
110
|
+
filename: `${cwd}/packages/foo/package.json`,
|
|
111
|
+
errors: [
|
|
112
|
+
{
|
|
113
|
+
messageId: 'invalidBinValue',
|
|
114
|
+
},
|
|
115
|
+
],
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
code: `const foo = {
|
|
119
|
+
"bin": {
|
|
120
|
+
"run-ts": "./scripts/bin",
|
|
121
|
+
}
|
|
122
|
+
}`,
|
|
123
|
+
filename: `${cwd}/packages/foo/package.json`,
|
|
124
|
+
errors: [
|
|
125
|
+
{
|
|
126
|
+
messageId: 'invalidBinValue',
|
|
127
|
+
},
|
|
128
|
+
],
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
code: `const foo = {
|
|
132
|
+
"bin": {
|
|
133
|
+
"run-ts": "./",
|
|
134
|
+
}
|
|
135
|
+
}`,
|
|
136
|
+
filename: `${cwd}/packages/foo/package.json`,
|
|
137
|
+
errors: [
|
|
138
|
+
{
|
|
139
|
+
messageId: 'invalidBinValue',
|
|
140
|
+
},
|
|
141
|
+
],
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
code: `const foo = {
|
|
145
|
+
"bin": {
|
|
146
|
+
"run-ts": "",
|
|
147
|
+
}
|
|
148
|
+
}`,
|
|
149
|
+
filename: `${cwd}/packages/foo/package.json`,
|
|
150
|
+
errors: [
|
|
151
|
+
{
|
|
152
|
+
messageId: 'invalidBinValue',
|
|
153
|
+
},
|
|
154
|
+
],
|
|
155
|
+
},
|
|
156
|
+
],
|
|
157
|
+
});
|
|
158
|
+
});
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
// eslint-disable-next-line import/no-extraneous-dependencies
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
import { resolve, dirname } from 'path';
|
|
4
|
+
import type { Rule } from 'eslint';
|
|
5
|
+
import type { ObjectExpression } from 'estree';
|
|
6
|
+
import { getObjectPropertyAsObject } from '../util/handle-ast-object';
|
|
7
|
+
|
|
8
|
+
const cwd = process.cwd();
|
|
9
|
+
|
|
10
|
+
function checkIsAllBinValuesAreValid(node: ObjectExpression, packageDir: string) {
|
|
11
|
+
const binObj = getObjectPropertyAsObject(node, 'bin');
|
|
12
|
+
|
|
13
|
+
if (!binObj || !Array.isArray(binObj.properties)) {
|
|
14
|
+
return true;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return binObj.properties.every((p) => {
|
|
18
|
+
if (p.type === 'Property' && p.value.type === 'Literal') {
|
|
19
|
+
try {
|
|
20
|
+
const binValue = String(p.value.value);
|
|
21
|
+
const pathToBin = resolve(cwd, packageDir, binValue);
|
|
22
|
+
// Ignore bin values that point to dist as these files don't always exist
|
|
23
|
+
if (binValue.startsWith('./dist/')) {
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
return fs.statSync(pathToBin).isFile();
|
|
27
|
+
} catch (err) {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
// If it's not a property or doesn't have a literal value, consider it invalid
|
|
32
|
+
return false;
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const rule: Rule.RuleModule = {
|
|
37
|
+
meta: {
|
|
38
|
+
type: 'problem',
|
|
39
|
+
docs: {
|
|
40
|
+
description: `Ensures bin values in package.json files are valid.`,
|
|
41
|
+
recommended: true,
|
|
42
|
+
},
|
|
43
|
+
hasSuggestions: false,
|
|
44
|
+
messages: {
|
|
45
|
+
invalidBinValue: `Invalid bin value. Ensure that the value points to a file and not a directory.`,
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
create(context) {
|
|
49
|
+
const fileName = context.getFilename();
|
|
50
|
+
return {
|
|
51
|
+
ObjectExpression: (node: Rule.Node) => {
|
|
52
|
+
if (!fileName.endsWith('package.json') || node.type !== 'ObjectExpression') {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const isAllBinValuesValid = checkIsAllBinValuesAreValid(node, dirname(fileName));
|
|
57
|
+
if (isAllBinValuesValid) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return context.report({
|
|
62
|
+
node,
|
|
63
|
+
messageId: 'invalidBinValue',
|
|
64
|
+
});
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
export default rule;
|