Skip to content

Commit

Permalink
add pkg-dependency-order rule - fixes #68
Browse files Browse the repository at this point in the history
  • Loading branch information
SamVerschueren committed Feb 21, 2017
1 parent bb87f57 commit bf53d9c
Show file tree
Hide file tree
Showing 9 changed files with 259 additions and 0 deletions.
1 change: 1 addition & 0 deletions config.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ module.exports = {
'pkg-description': 'error',
'pkg-name': 'error',
'pkg-shorthand-repository': 'error',
'pkg-dependency-order': 'error',
readme: 'error',
'test-script': 'error',
'use-travis': 'warn',
Expand Down
49 changes: 49 additions & 0 deletions docs/rules/pkg-dependency-order.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Enforces alphabetical order of `dependencies` and `devDependencies` in `package.json`

Enforces an alphabetical order of the `dependencies` and `devDependencies` list in `package.json`.


## Fail

```json
{
"name": "foo",
"dependencies": {
"pify": "*",
"clinton": "*"
}
}
```

```json
{
"name": "foo",
"devDependencies": {
"xo": "*",
"ava": "*"
}
}
```


## Pass

```json
{
"name": "foo",
"dependencies": {
"clinton": "*",
"pify": "*"
}
}
```

```json
{
"name": "foo",
"devDependencies": {
"ava": "*",
"xo": "*"
}
}
```
1 change: 1 addition & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ Current working directory when linting local projects.
- [no-callback](docs/rules/no-callback.md) - Enforces the use of promises instead of callbacks.
- [no-dup-keywords](docs/rules/no-dup-keywords.md) - Enforce not having duplicate keywords in `package.json`. *(fixable)*
- [no-git-merge-conflict](docs/rules/no-git-merge-conflict.md) - Prevents having Git merge conflict markers.
- [pkg-dependency-order](docs/rules/pkg-dependency-order.md) - Enforces alphabetical order of `dependencies` and `devDependencies` in `package.json`. *(fixable)*
- [pkg-description](docs/rules/pkg-description.md) - Enforces the description to start with a capital letter and not end with a dot. *(fixable)*
- [pkg-main](docs/rules/pkg-main.md) - Enforces the existance of the main file.
- [pkg-name](docs/rules/pkg-name.md) - Enforces a valid package name.
Expand Down
53 changes: 53 additions & 0 deletions rules/pkg-dependency-order.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
'use strict';
const fix = prop => {
return pkg => {
const ret = {};
ret[prop] = Object.create(null);

const deps = pkg[prop] || {};
const orderedDeps = Object.keys(deps).sort();

for (const dep of orderedDeps) {
ret[prop][dep] = deps[dep];
}

return Object.assign(pkg, ret);
};
};

const checkOrder = input => {
const keys = Object.keys(input);
const orderedKeys = Object.keys(input).sort();

for (let i = 0; i < keys.length; i++) {
if (keys[i] !== orderedKeys[i]) {
return [orderedKeys[i], keys[i]];
}
}
};

module.exports = ctx => {
const file = ctx.fs.resolve('package.json');

return ctx.fs.readFile('package.json')
.then(pkg => {
const deps = checkOrder(pkg.dependencies || {});
const devDeps = checkOrder(pkg.devDependencies || {});

if (deps) {
ctx.report({
message: `Dependency \`${deps[0]}\` should occur before \`${deps[1]}\`.`,
fix: fix('dependencies'),
file
});
}

if (devDeps) {
ctx.report({
message: `Dev dependency \`${devDeps[0]}\` should occur before \`${devDeps[1]}\`.`,
fix: fix('devDependencies'),
file
});
}
});
};
11 changes: 11 additions & 0 deletions test/fixtures/pkg-dependency-order/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"name": "package",
"dependencies": {
"clinton": "*",
"pify": "*"
},
"devDependencies": {
"ava": "*",
"xo": "*"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"name": "package",
"dependencies": {
"pify": "*",
"clinton": "*"
},
"devDependencies": {
"ava": "*",
"xo": "*"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"name": "package",
"dependencies": {
"clinton": "*",
"pify": "*"
},
"devDependencies": {
"xo": "*",
"ava": "*"
}
}
11 changes: 11 additions & 0 deletions test/fixtures/pkg-dependency-order/unordered/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"name": "package",
"dependencies": {
"pify": "*",
"clinton": "*"
},
"devDependencies": {
"xo": "*",
"ava": "*"
}
}
111 changes: 111 additions & 0 deletions test/pkg-dependency-order.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import path from 'path';
import test from 'ava';
import clintonRuleTester from './fixtures/rule-tester';

const opts = {
cwd: 'test/fixtures/pkg-dependency-order',
rules: {
'pkg-dependency-order': 'error'
}
};

const ruleTester = clintonRuleTester(opts);

test('ordered dependencies and devDependencies', async t => {
await ruleTester(t, '.', []);
});

test('unordered dependencies', async t => {
await ruleTester(t, 'unordered-dependencies',
[
{
ruleId: 'pkg-dependency-order',
severity: 'error',
message: 'Dependency `clinton` should occur before `pify`.',
file: path.resolve(opts.cwd, 'unordered-dependencies/package.json')
}
],
[
{
name: 'package',
dependencies: {
clinton: '*',
pify: '*'
},
devDependencies: {
ava: '*',
xo: '*'
}
}
]
);
});

test('unordered devDependencies', async t => {
await ruleTester(t, 'unordered-devdependencies',
[
{
ruleId: 'pkg-dependency-order',
severity: 'error',
message: 'Dev dependency `ava` should occur before `xo`.',
file: path.resolve(opts.cwd, 'unordered-devdependencies/package.json')
}
],
[
{
name: 'package',
dependencies: {
clinton: '*',
pify: '*'
},
devDependencies: {
ava: '*',
xo: '*'
}
}
]
);
});

test('unordered dependencies and devDependencies', async t => {
await ruleTester(t, 'unordered',
[
{
ruleId: 'pkg-dependency-order',
severity: 'error',
message: 'Dependency `clinton` should occur before `pify`.',
file: path.resolve(opts.cwd, 'unordered/package.json')
},
{
ruleId: 'pkg-dependency-order',
severity: 'error',
message: 'Dev dependency `ava` should occur before `xo`.',
file: path.resolve(opts.cwd, 'unordered/package.json')
}
],
[
{
name: 'package',
dependencies: {
clinton: '*',
pify: '*'
},
devDependencies: {
xo: '*',
ava: '*'
}
},
{
name: 'package',
dependencies: {
pify: '*',
clinton: '*'
},
devDependencies: {
ava: '*',
xo: '*'
}
}
]
);
});

0 comments on commit bf53d9c

Please sign in to comment.