diff --git a/lib/index.js b/lib/index.js index 9997f32..14fba52 100644 --- a/lib/index.js +++ b/lib/index.js @@ -10,39 +10,61 @@ */ const { parsers } = require('prettier/parser-babylon'); -const { dependencies } = require('./rules/dependencies'); +const { custom } = require('./rules/custom'); const { engines } = require('./rules/engines'); const { files } = require('./rules/files'); const { scripts } = require('./rules/scripts'); -const { sort } = require('./rules/sort'); +const { sort: sortProps } = require('./rules/props'); const { 'json-stringify': parser } = parsers; const { parse } = parser; const rePkg = /package\.json$/; -const format = (properties) => { - let props = sort(properties); +const safe = (json) => { + try { + return JSON.parse(json); + } catch (_) { + return null; + } +}; + +const format = (properties, options) => { + let props = sortProps(properties); props = engines(props); props = files(props); props = scripts(props); - props = dependencies(props); + + if (options) { + const { sort } = safe(options); + if (sort) { + props = custom(props, sort); + } + } return props; }; module.exports = { name: 'prettier-plugin-package', + options: { + pluginPackage: { + type: 'path', + category: 'Plugins', + default: '', + description: 'Specify options for the package plugin' + } + }, parsers: { 'json-stringify': { ...parser, parse(...args) { const [, , options] = args; - const { filepath } = options; + const { filepath, pluginPackage } = options; const ast = parse(...args); if (rePkg.test(filepath)) { const { properties } = ast; - ast.properties = format(properties); + ast.properties = format(properties, pluginPackage); } return ast; diff --git a/lib/rules/custom.js b/lib/rules/custom.js new file mode 100644 index 0000000..f117bf4 --- /dev/null +++ b/lib/rules/custom.js @@ -0,0 +1,37 @@ +/* + Copyright © 2019 Andrew Powell + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of this Source Code Form. +*/ + +const alpha = (a, b) => (a.key.value > b.key.value ? 1 : a.key.value < b.key.value ? -1 : 0); + +const methods = { alpha }; + +const process = (props, sort) => { + const declaredMethods = Object.keys(sort); + let result = props; + + for (const methodName of declaredMethods) { + const method = methods[methodName]; + const propertyNames = sort[methodName]; + + if (method) { + result = result.map((prop) => { + if (propertyNames.includes(prop.key.value)) { + prop.value.properties.sort(method); + } + return prop; + }); + } + } + + return result; +}; + +module.exports = { custom: process }; diff --git a/lib/rules/dependencies.js b/lib/rules/dependencies.js deleted file mode 100644 index 61b9488..0000000 --- a/lib/rules/dependencies.js +++ /dev/null @@ -1,32 +0,0 @@ -/* - Copyright © 2019 Andrew Powell - - This Source Code Form is subject to the terms of the Mozilla Public - License, v. 2.0. If a copy of the MPL was not distributed with this - file, You can obtain one at http://mozilla.org/MPL/2.0/. - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of this Source Code Form. -*/ - -const dependencyNames = [ - // dependencies - 'bundledDependencies', - 'optionalDependencies', - 'peerDependencies', - 'dependencies', - 'devDependencies', - 'resolutions' -]; - -const process = (props) => - props.map((prop) => { - if (dependencyNames.includes(prop.key.value)) { - prop.value.properties.sort((a, b) => - a.key.value > b.key.value ? 1 : a.key.value < b.key.value ? -1 : 0 - ); - } - return prop; - }); - -module.exports = { dependencies: process }; diff --git a/lib/rules/sort.js b/lib/rules/sort.js deleted file mode 100644 index c16a7ec..0000000 --- a/lib/rules/sort.js +++ /dev/null @@ -1,74 +0,0 @@ -/* - Copyright © 2019 Andrew Powell - - This Source Code Form is subject to the terms of the Mozilla Public - License, v. 2.0. If a copy of the MPL was not distributed with this - file, You can obtain one at http://mozilla.org/MPL/2.0/. - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of this Source Code Form. -*/ -const primary = [ - // meta - 'name', - 'version', - 'flat', - 'private', - 'publishConfig', - 'description', - 'license', - 'repository', - 'author', - 'homepage', - 'bugs', - - // entry - 'main', - 'bin', - 'module', - - // constraints - 'engines', - 'cpu', - 'os', - - // content and util - 'scripts', - 'files', - 'keywords', - - // dependencies - 'bundledDependencies', - 'optionalDependencies', - 'peerDependencies', - 'dependencies', - 'devDependencies', - 'resolutions', - - // types - 'types', - 'typings' -]; - -const sort = (props) => { - const unknown = []; - const known = props.filter((prop) => { - if (primary.includes(prop.key.value)) { - return true; - } - unknown.push(prop); - return false; - }); - - known.sort((a, b) => { - const aIndex = primary.indexOf(a.key.value); - const bIndex = primary.indexOf(b.key.value); - - return aIndex > bIndex ? 1 : aIndex < bIndex ? -1 : 0; - }); - unknown.sort((a, b) => (a.key.value > b.key.value ? 1 : a.key.value < b.key.value ? -1 : 0)); - - return known.concat(unknown); -}; - -module.exports = { sort }; diff --git a/package-lock.json b/package-lock.json index 3a0b6e0..c81c9c9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3133,9 +3133,9 @@ "dev": true }, "handlebars": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.2.0.tgz", - "integrity": "sha512-Kb4xn5Qh1cxAKvQnzNWZ512DhABzyFNmsaJf3OAkWNa4NkaqWcNI8Tao8Tasi0/F4JD9oyG0YxuFyvyR57d+Gw==", + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.4.2.tgz", + "integrity": "sha512-cIv17+GhL8pHHnRJzGu2wwcthL5sb8uDKBHvZ2Dtu5s1YNt0ljbzKbamnc+gr69y7bzwQiBdr5+hOpRd5pnOdg==", "dev": true, "requires": { "neo-async": "^2.6.0", diff --git a/package.json b/package.json index 0522bec..56675fb 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "eslint-config-shellscape": "^2.0.2", "execa": "^2.0.3", "lint-staged": "^9.2.0", - "nyc": "^14.1.0", + "nyc": "^14.1.1", "pre-commit": "^1.2.2", "prettier": "^1.18.2" }, diff --git a/test/custom.js b/test/custom.js new file mode 100644 index 0000000..16e7571 --- /dev/null +++ b/test/custom.js @@ -0,0 +1,28 @@ +const test = require('ava'); +const prettier = require('prettier'); + +test('default', (t) => { + const options = { + filepath: 'package.json', + parser: 'json-stringify', + plugins: ['.'], + pluginPackage: JSON.stringify({ + sort: { + alpha: ['dependencies'] + } + }) + }; + const fixture = { + dependencies: { + nyc: '^14.1.0', + 'eslint-config-shellscape': '^2.0.2', + ava: '^2.2.0', + execa: '^2.0.3' + } + }; + + const input = JSON.stringify(fixture, null, 2); + const output = prettier.format(input, options); + + t.snapshot(output); +}); diff --git a/test/fixtures/fixture.json b/test/fixtures/fixture.json index 7df7e7e..01f2c6e 100644 --- a/test/fixtures/fixture.json +++ b/test/fixtures/fixture.json @@ -41,12 +41,6 @@ "prettier": "^1.18.2", "eslint-config-shellscape": "^2.0.2" }, - "dependencies": { - "nyc": "^14.1.0", - "eslint-config-shellscape": "^2.0.2", - "ava": "^2.2.0", - "execa": "^2.0.3" - }, "typings": "dist/index.d.ts", "dependencies": {}, "devDependencies": { @@ -60,17 +54,18 @@ "pre-commit": "^1.2.2", "prettier": "^1.18.2" }, - "ava": { - "files": [ - "!**/fixtures/**" - ] - }, + "pre-commit": "lint-staged", "lint-staged": { "*.js": [ "eslint --fix", "git add" ] }, + "ava": { + "files": [ + "!**/fixtures/**" + ] + }, "nyc": { "include": [ "lib/*.js" @@ -78,6 +73,5 @@ "exclude": [ "test/" ] - }, - "pre-commit": "lint-staged" + } } diff --git a/test/snapshots/custom.js.md b/test/snapshots/custom.js.md new file mode 100644 index 0000000..f015e5d --- /dev/null +++ b/test/snapshots/custom.js.md @@ -0,0 +1,19 @@ +# Snapshot report for `test/custom.js` + +The actual snapshot is saved in `custom.js.snap`. + +Generated by [AVA](https://ava.li). + +## default + +> Snapshot 1 + + `{␊ + "dependencies": {␊ + "ava": "^2.2.0",␊ + "eslint-config-shellscape": "^2.0.2",␊ + "execa": "^2.0.3",␊ + "nyc": "^14.1.0"␊ + }␊ + }␊ + ` diff --git a/test/snapshots/custom.js.snap b/test/snapshots/custom.js.snap new file mode 100644 index 0000000..e7fd47d Binary files /dev/null and b/test/snapshots/custom.js.snap differ diff --git a/test/snapshots/test.js.md b/test/snapshots/test.js.md index a874853..bdb798f 100644 --- a/test/snapshots/test.js.md +++ b/test/snapshots/test.js.md @@ -48,18 +48,18 @@ Generated by [AVA](https://ava.li). "prettier"␊ ],␊ "peerDependencies": {␊ - "eslint-config-shellscape": "^2.0.2",␊ - "prettier": "^1.18.2"␊ + "prettier": "^1.18.2",␊ + "eslint-config-shellscape": "^2.0.2"␊ },␊ "dependencies": {},␊ "devDependencies": {␊ - "@commitlint/cli": "^8.1.0",␊ "@commitlint/config-conventional": "^8.1.0",␊ + "lint-staged": "^9.2.0",␊ "ava": "^2.2.0",␊ "eslint-config-shellscape": "^2.0.2",␊ "execa": "^2.0.3",␊ - "lint-staged": "^9.2.0",␊ "nyc": "^14.1.0",␊ + "@commitlint/cli": "^8.1.0",␊ "pre-commit": "^1.2.2",␊ "prettier": "^1.18.2"␊ },␊ @@ -131,18 +131,18 @@ Generated by [AVA](https://ava.li). "prettier"␊ ],␊ "peerDependencies": {␊ - "eslint-config-shellscape": "^2.0.2",␊ - "prettier": "^1.18.2"␊ + "prettier": "^1.18.2",␊ + "eslint-config-shellscape": "^2.0.2"␊ },␊ "dependencies": {},␊ "devDependencies": {␊ - "@commitlint/cli": "^8.1.0",␊ "@commitlint/config-conventional": "^8.1.0",␊ + "lint-staged": "^9.2.0",␊ "ava": "^2.2.0",␊ "eslint-config-shellscape": "^2.0.2",␊ "execa": "^2.0.3",␊ - "lint-staged": "^9.2.0",␊ "nyc": "^14.1.0",␊ + "@commitlint/cli": "^8.1.0",␊ "pre-commit": "^1.2.2",␊ "prettier": "^1.18.2"␊ },␊ diff --git a/test/snapshots/test.js.snap b/test/snapshots/test.js.snap index afac647..1fd1288 100644 Binary files a/test/snapshots/test.js.snap and b/test/snapshots/test.js.snap differ