sort-package-json
Advanced tools
Comparing version 2.3.0 to 2.4.0
135
cli.js
@@ -5,90 +5,95 @@ #!/usr/bin/env node | ||
import sortPackageJson from './index.js' | ||
import Reporter from './reporter.js' | ||
const isCheckFlag = (argument) => argument === '--check' || argument === '-c' | ||
const isHelpFlag = (argument) => argument === '--help' || argument === '-h' | ||
const isVersionFlag = (argument) => | ||
argument === '--version' || argument === '-v' | ||
const isQuietFlag = (argument) => argument === '--quiet' || argument === '-q' | ||
function showVersion() { | ||
const { name, version } = JSON.parse( | ||
fs.readFileSync(new URL('package.json', import.meta.url)), | ||
) | ||
const cliArguments = process.argv.slice(2) | ||
const isCheck = cliArguments.some(isCheckFlag) | ||
const isQuiet = cliArguments.some(isQuietFlag) | ||
console.log(`${name} ${version}`) | ||
} | ||
const stdout = isQuiet ? () => {} : console.log | ||
const stderr = console.error | ||
function showHelpInformation() { | ||
console.log( | ||
`Usage: sort-package-json [options] [file/glob ...] | ||
const isHelp = cliArguments.some(isHelpFlag) | ||
const isVersion = cliArguments.some(isVersionFlag) | ||
Sort package.json files. | ||
If file/glob is omitted, './package.json' file will be processed. | ||
if (isHelp) { | ||
console.log( | ||
`Usage: sort-package-json [OPTION...] [FILE...] | ||
Sort npm package.json files. Default: ./package.json | ||
Strings passed as files are parsed as globs. | ||
-c, --check check if FILES are sorted | ||
-q, --quiet don't output success messages | ||
-h, --help display this help and exit | ||
-v, --version display the version and exit | ||
-c, --check Check if files are sorted | ||
-q, --quiet Don't output success messages | ||
-h, --help Display this help | ||
-v, --version Display the package version | ||
`, | ||
) | ||
process.exit(0) | ||
} | ||
if (isVersion) { | ||
const packageJsonUrl = new URL('package.json', import.meta.url) | ||
const packageJsonBuffer = fs.readFileSync(packageJsonUrl) | ||
const { version } = JSON.parse(packageJsonBuffer) | ||
console.log(`sort-package-json ${version}`) | ||
process.exit(0) | ||
} | ||
function sortPackageJsonFile(file, reporter, isCheck) { | ||
const original = fs.readFileSync(file, 'utf8') | ||
const sorted = sortPackageJson(original) | ||
if (sorted === original) { | ||
return reporter.reportNotChanged(file) | ||
} | ||
const patterns = cliArguments.filter( | ||
(argument) => !isCheckFlag(argument) && !isQuietFlag(argument), | ||
) | ||
if (!isCheck) { | ||
fs.writeFileSync(file, sorted) | ||
} | ||
if (!patterns.length) { | ||
patterns[0] = 'package.json' | ||
reporter.reportChanged(file) | ||
} | ||
const files = globbySync(patterns) | ||
function sortPackageJsonFiles(patterns, options) { | ||
const files = globbySync(patterns) | ||
const reporter = new Reporter(files, options) | ||
const { isCheck } = options | ||
if (files.length === 0) { | ||
stderr('No matching files.') | ||
process.exit(1) | ||
for (const file of files) { | ||
try { | ||
sortPackageJsonFile(file, reporter, isCheck) | ||
} catch (error) { | ||
reporter.reportFailed(file, error) | ||
} | ||
} | ||
reporter.printSummary() | ||
} | ||
let notSortedFiles = 0 | ||
function run() { | ||
const cliArguments = process.argv.slice(2) | ||
files.forEach((file) => { | ||
const packageJson = fs.readFileSync(file, 'utf8') | ||
const sorted = sortPackageJson(packageJson) | ||
if ( | ||
cliArguments.some((argument) => argument === '--help' || argument === '-h') | ||
) { | ||
return showHelpInformation() | ||
} | ||
if (sorted !== packageJson) { | ||
if (isCheck) { | ||
notSortedFiles++ | ||
stdout(file) | ||
if ( | ||
cliArguments.some( | ||
(argument) => argument === '--version' || argument === '-v', | ||
) | ||
) { | ||
return showVersion() | ||
} | ||
const patterns = [] | ||
let isCheck = false | ||
let shouldBeQuiet = false | ||
for (const argument of cliArguments) { | ||
if (argument === '--check' || argument === '-c') { | ||
isCheck = true | ||
} else if (argument === '--quiet' || argument === '-q') { | ||
shouldBeQuiet = true | ||
} else { | ||
fs.writeFileSync(file, sorted, 'utf8') | ||
stdout(`${file} is sorted!`) | ||
patterns.push(argument) | ||
} | ||
} | ||
}) | ||
if (isCheck) { | ||
stdout() | ||
if (notSortedFiles) { | ||
stdout( | ||
notSortedFiles === 1 | ||
? `${notSortedFiles} of ${files.length} matched file is not sorted.` | ||
: `${notSortedFiles} of ${files.length} matched files are not sorted.`, | ||
) | ||
} else { | ||
stdout( | ||
files.length === 1 | ||
? `${files.length} matched file is sorted.` | ||
: `${files.length} matched files are sorted.`, | ||
) | ||
if (!patterns.length) { | ||
patterns[0] = 'package.json' | ||
} | ||
process.exit(notSortedFiles) | ||
sortPackageJsonFiles(patterns, { isCheck, shouldBeQuiet }) | ||
} | ||
run() |
45
index.js
@@ -7,4 +7,6 @@ import sortObjectKeys from 'sort-object-keys' | ||
const hasOwnProperty = (object, property) => | ||
Object.prototype.hasOwnProperty.call(object, property) | ||
const hasOwn = | ||
Object.hasOwn || | ||
// TODO: Remove this when we drop supported for Node.js v14 | ||
((object, property) => Object.prototype.hasOwnProperty.call(object, property)) | ||
const pipe = | ||
@@ -17,3 +19,3 @@ (fns) => | ||
Array.isArray(x) && x.every((item) => typeof item === 'string') ? fn(x) : x | ||
const uniq = onStringArray((xs) => xs.filter((x, i) => i === xs.indexOf(x))) | ||
const uniq = onStringArray((xs) => [...new Set(xs)]) | ||
const sortArray = onStringArray((array) => [...array].sort()) | ||
@@ -27,9 +29,9 @@ const uniqAndSortArray = pipe([uniq, sortArray]) | ||
const over = onObject((object) => { | ||
object = sortObjectKeys(object, comparator) | ||
if (deep) { | ||
for (const [key, value] of Object.entries(object)) { | ||
object[key] = over(value) | ||
} | ||
object = Object.fromEntries( | ||
Object.entries(object).map(([key, value]) => [key, over(value)]), | ||
) | ||
} | ||
return object | ||
return sortObjectKeys(object, comparator) | ||
}) | ||
@@ -53,4 +55,4 @@ | ||
(object, ...args) => | ||
hasOwnProperty(object, property) | ||
? Object.assign(object, { [property]: over(object[property], ...args) }) | ||
hasOwn(object, property) | ||
? { ...object, [property]: over(object[property], ...args) } | ||
: object | ||
@@ -150,4 +152,4 @@ const sortGitHooks = sortObjectBy(gitHooks) | ||
return ( | ||
'devDependencies' in packageJson && | ||
!!packageJson.devDependencies[dependency] | ||
hasOwn(packageJson, 'devDependencies') && | ||
hasOwn(packageJson.devDependencies, dependency) | ||
) | ||
@@ -173,8 +175,4 @@ } | ||
const order = keys.reduce( | ||
(order, key) => | ||
order.concat( | ||
prefixable.has(key) ? [`pre${key}`, key, `post${key}`] : [key], | ||
), | ||
[], | ||
const order = keys.flatMap((key) => | ||
prefixable.has(key) ? [`pre${key}`, key, `post${key}`] : [key], | ||
) | ||
@@ -322,8 +320,5 @@ | ||
const overFields = pipe( | ||
fields.reduce((fns, { key, over }) => { | ||
if (over) { | ||
fns.push(overProperty(key, over)) | ||
} | ||
return fns | ||
}, []), | ||
fields | ||
.map(({ key, over }) => (over ? overProperty(key, over) : undefined)) | ||
.filter(Boolean), | ||
) | ||
@@ -361,3 +356,3 @@ | ||
onObject((json) => { | ||
let sortOrder = options.sortOrder ? options.sortOrder : defaultSortOrder | ||
let sortOrder = options.sortOrder || defaultSortOrder | ||
@@ -364,0 +359,0 @@ if (Array.isArray(sortOrder)) { |
{ | ||
"name": "sort-package-json", | ||
"version": "2.3.0", | ||
"version": "2.4.0", | ||
"description": "Sort an Object or package.json based on the well-known package.json keys", | ||
@@ -27,3 +27,4 @@ "keywords": [ | ||
"index.d.ts", | ||
"cli.js" | ||
"cli.js", | ||
"reporter.js" | ||
], | ||
@@ -30,0 +31,0 @@ "scripts": { |
@@ -74,3 +74,3 @@ # Sort Package.json | ||
In order to silence any successful output, you can run CLI with the `--quiet` flag (or `-q`). This will stop the CLI from outputting if it runs successfully, but will still display errors if they occur. Exit codes will not change. | ||
In order to silence any successful output, you can run CLI with the `--quiet` flag (or `-q`). This will stop the CLI from outputting if it runs successfully, but won't effect error messages and the exit code. | ||
@@ -206,11 +206,15 @@ ```bash | ||
The package.json file can be sorted automatically before committing, install `husky` and `lint-staged` and add the following to your `package.json` file: | ||
The package.json file can be sorted automatically before committing. | ||
```bash | ||
npm install husky lint-staged --save-dev | ||
npm pkg set scripts.prepare="husky install" | ||
npm run prepare | ||
npx husky add .husky/pre-commit "npx lint-staged" | ||
``` | ||
Add the following to your `package.json` file | ||
```json | ||
{ | ||
"husky": { | ||
"hooks": { | ||
"pre-commit": "lint-staged" | ||
} | ||
}, | ||
"lint-staged": { | ||
@@ -222,2 +226,4 @@ "package.json": "sort-package-json" | ||
See [Husky](https://github.com/typicode/husky) and [lint-staged](https://github.com/okonet/lint-staged) for more information. | ||
## PFAQ: Potential Frequently Asked Questions | ||
@@ -250,2 +256,1 @@ | ||
Well, it's nice to have the keys of a package.json in a well sorted order. Almost everyone would agree having "name" at the top of a package.json is sensible (rather than sorted alphabetically or somewhere silly like the bottom), so why not the rest of the package.json? | ||
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
27115
6
564
253