Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
},
"extends": ["eslint:recommended"],
"parserOptions": {
"ecmaVersion": 6,
"ecmaVersion": 2021,
"sourceType": "module"
}
}
59 changes: 29 additions & 30 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,47 +4,46 @@ Rules for valid, consistent, and readable package.json files

## Installation

You'll first need to install [ESLint](http://eslint.org):
You'll first need to install [ESLint](http://eslint.org) >=8 and `eslint-plugin-package-json`:

```
$ npm i eslint --save-dev
```

Next, install `eslint-plugin-package-json`:

```
$ npm install eslint-plugin-package-json --save-dev
```shell
$ npm install eslint eslint-plugin-package-json --save-dev
```

**Note:** If you installed ESLint globally (using the `-g` flag) then you must also install `eslint-plugin-package-json` globally.

## Usage

Add `package-json` to the plugins section of your `.eslintrc` configuration file. You can omit the `eslint-plugin-` prefix:

```json
{
"plugins": ["package-json"]
}
```

Use the prepackaged config by adding an "extends" property, or appending to an existing "extends" property:

```json
{
"extends": ["eslint:recommended", "plugin:package-json/recommended"],
"plugins": ["package-json"]
}
Add an override to your ESLint configuration file that specifies this plugin, [`jsonc-eslint-parser`](https://github.com/ota-meshi/jsonc-eslint-parser) and its recommended rules for your `package.json` file:

```js
module.exports = {
overrides: [
{
extends: ['plugin:package-json/recommended'],
files: ['package.json'],
parser: 'jsonc-eslint-parser'
plugins: ['package-json']
}
]
};
```

Or, individually configure the rules you want to use under the rules section.

```json
{
"rules": {
"package-json/rule-name": 2
}
}
```js
module.exports = {
overrides: [
{
files: ['package.json'],
parser: 'jsonc-eslint-parser'
plugins: ['package-json'],
rules: {
'package-json/valid-package-def': 'error'
}
}
]
};
```

## Supported Rules
Expand Down
17 changes: 17 additions & 0 deletions lib/createRule.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
const isPackageJson = filePath =>
filePath.endsWith('/package.json') || filePath === 'package.json';

function createRule(rule) {
return {
...rule,
create(context) {
if (!isPackageJson(context.filename)) {
return {};
}

return rule.create(context);
}
};
}

module.exports.createRule = createRule;
41 changes: 13 additions & 28 deletions lib/index.js
Original file line number Diff line number Diff line change
@@ -1,34 +1,19 @@
'use strict';

//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
const orderProperties = require('./rules/order-properties');
const sortCollections = require('./rules/sort-collections');
const validLocalDependency = require('./rules/valid-local-dependency');
const validPackageDef = require('./rules/valid-package-def');

var requireIndex = require('requireindex');

//------------------------------------------------------------------------------
// Plugin Definition
//------------------------------------------------------------------------------

// import all rules in lib/rules
module.exports.rules = requireIndex(__dirname + '/rules');

// import processors
const PackageJsonProcessor = require('./processors/PackageJsonProcessor');
module.exports.processors = {
// adapted from https://github.com/godaddy/eslint-plugin-i18n-json
// thank you!
'.json': PackageJsonProcessor
// add your processors here
};

module.exports.configs = {
recommended: {
rules: {
'package-json/sort-collections': 'error',
'package-json/order-properties': 'warn',
'package-json/valid-package-def': 'error',
'package-json/valid-local-dependency': 'error'
module.exports = {
configs: {
recommended: {
rules: {
'order-properties': orderProperties,
'sort-collections': sortCollections,
'valid-local-dependency': validLocalDependency,
'valid-package-def': validPackageDef
}
}
}
};
63 changes: 0 additions & 63 deletions lib/processors/PackageJsonProcessor.js

This file was deleted.

34 changes: 16 additions & 18 deletions lib/rules/order-properties.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
'use strict';
const disparity = require('disparity');
const {
isPackageJson,
extractPackageObjectFromAST
} = require('../processors/PackageJsonProcessor');
const { createRule } = require('../createRule');

//------------------------------------------------------------------------------
// Rule Definition
Expand Down Expand Up @@ -40,21 +37,21 @@ const standardOrder = [
'cpu'
];

const toIndexMap = (arr) =>
const toIndexMap = arr =>
arr.reduce((indexMap, value, index) => {
indexMap[value] = index;
return indexMap;
}, {});

module.exports = {
module.exports = createRule({
meta: {
docs: {
description:
'Package properties must be declared in standard order',
category: 'Best Practices',
recommended: true
},
fixable: 'code', // or "code" or "whitespace"
fixable: 'code',
schema: [
{
type: 'array',
Expand All @@ -67,13 +64,8 @@ module.exports = {

create(context) {
return {
'Program:exit': (node) => {
if (!isPackageJson(context.getFilename())) {
return;
}
const sourceCode = context.getSourceCode();
const packageRoot = extractPackageObjectFromAST(node);
const original = JSON.parse(sourceCode.getText(packageRoot));
'Program:exit'() {
const original = JSON.parse(context.sourceCode.text);
const originalIndexMap = toIndexMap(Object.keys(original));
const requiredOrder = context.options[0] || standardOrder;
const requiredIndexMap = toIndexMap(requiredOrder);
Expand Down Expand Up @@ -117,18 +109,24 @@ module.exports = {
);
if (diff) {
context.report({
node: packageRoot,
node: context.sourceCode.ast,
message:
'Package top-level properties are not ordered in the NPM standard way:\n\n{{ diff }}',
data: {
diff: diff.split('\n').slice(3).join('\n')
diff: diff
.split('\n')
.slice(3)
.join('\n')
},
fix(fixer) {
return fixer.replaceText(node, orderedSource);
return fixer.replaceText(
context.sourceCode.ast,
orderedSource
);
}
});
}
}
};
}
};
});
29 changes: 14 additions & 15 deletions lib/rules/sort-collections.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
'use strict';
const { isPackageJson } = require('../processors/PackageJsonProcessor');

const { createRule } = require('../createRule');

//------------------------------------------------------------------------------
// Rule Definition
Expand All @@ -11,7 +12,7 @@ const defaultCollections = [
'peerDependencies',
'config'
];
module.exports = {
module.exports = createRule({
meta: {
docs: {
description:
Expand All @@ -30,16 +31,13 @@ module.exports = {
]
},

create: function (context) {
create(context) {
const toSort = context.options[0] || defaultCollections;
return {
'Property:exit': (node) => {
if (!isPackageJson(context.getFilename())) {
return;
}
'JSONProperty:exit'(node) {
const collection = node.value;
if (
collection.type === 'ObjectExpression' &&
collection.type === 'JSONObjectExpression' &&
toSort.includes(node.key.value)
) {
const currentOrder = collection.properties;
Expand All @@ -63,12 +61,13 @@ module.exports = {
collection,
JSON.stringify(
desiredOrder.reduce((out, property) => {
out[property.key.value] =
JSON.parse(
context
.getSourceCode()
.getText(property.value)
);
out[
property.key.value
] = JSON.parse(
context
.getSourceCode()
.getText(property.value)
);
return out;
}, {}),
null,
Expand All @@ -84,4 +83,4 @@ module.exports = {
}
};
}
};
});
Loading