diff --git a/README.md b/README.md index 8376d397..408167ff 100644 --- a/README.md +++ b/README.md @@ -71,7 +71,7 @@ $ sort-package-json "**/package.json" --check #### `--quiet` flag -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. ```bash $ sort-package-json "**/package.json" --check --quiet @@ -202,21 +202,27 @@ _Alphabetically ordered._ ## Automatically Sort -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": { "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 ### How does it sort? @@ -244,4 +250,3 @@ A lot of people who ask for configuration cite the use case that they simply don ### What?! Why would you want to do this?! 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? - diff --git a/cli.js b/cli.js index c2369172..08cf307f 100755 --- a/cli.js +++ b/cli.js @@ -3,91 +3,113 @@ import { globbySync } from 'globby' import fs from 'node:fs' import sortPackageJson from './index.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 sortPackageJsonFiles(patterns, { isCheck, shouldBeQuit }) { + const files = globbySync(patterns) + const printToStdout = shouldBeQuit ? () => {} : console.log + + if (files.length === 0) { + console.error('No matching files.') + process.exitCode = 2 + return + } -const patterns = cliArguments.filter( - (argument) => !isCheckFlag(argument) && !isQuietFlag(argument), -) + let notSortedFiles = 0 + for (const file of files) { + const packageJson = fs.readFileSync(file, 'utf8') + const sorted = sortPackageJson(packageJson) -if (!patterns.length) { - patterns[0] = 'package.json' -} + if (sorted !== packageJson) { + if (isCheck) { + notSortedFiles++ + printToStdout(file) + process.exitCode = 1 + } else { + fs.writeFileSync(file, sorted) + + printToStdout(`${file} is sorted!`) + } + } + } -const files = globbySync(patterns) + if (isCheck) { + // Print a empty line + printToStdout() -if (files.length === 0) { - stderr('No matching files.') - process.exit(1) + if (notSortedFiles) { + printToStdout( + notSortedFiles === 1 + ? `${notSortedFiles} of ${files.length} matched file is not sorted.` + : `${notSortedFiles} of ${files.length} matched files are not sorted.`, + ) + } else { + printToStdout( + files.length === 1 + ? `${files.length} matched file is sorted.` + : `${files.length} matched files are sorted.`, + ) + } + } } -let notSortedFiles = 0 +function run() { + const cliArguments = process.argv.slice(2) + + if ( + cliArguments.some((argument) => argument === '--help' || argument === '-h') + ) { + return showHelpInformation() + } + + if ( + cliArguments.some( + (argument) => argument === '--version' || argument === '-v', + ) + ) { + return showVersion() + } -files.forEach((file) => { - const packageJson = fs.readFileSync(file, 'utf8') - const sorted = sortPackageJson(packageJson) + const patterns = [] + let isCheck = false + let shouldBeQuit = false - if (sorted !== packageJson) { - if (isCheck) { - notSortedFiles++ - stdout(file) + for (const argument of cliArguments) { + if (argument === '--check' || argument === '-c') { + isCheck = true + } else if (argument === '--quiet' || argument === '-q') { + shouldBeQuit = 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, shouldBeQuit }) } + +run() diff --git a/tests/snapshots/cli.js.md b/tests/snapshots/cli.js.md index 25b467ce..57af69bc 100644 --- a/tests/snapshots/cli.js.md +++ b/tests/snapshots/cli.js.md @@ -16,14 +16,15 @@ Generated by [AVA](https://avajs.dev). result: { errorCode: null, stderr: '', - stdout: `Usage: sort-package-json [OPTION...] [FILE...]␊ - Sort npm package.json files. Default: ./package.json␊ - Strings passed as files are parsed as globs.␊ + stdout: `Usage: sort-package-json [options] [file/glob ...]␊ ␊ - -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␊ + Sort package.json files.␊ + If file/glob is omitted, './package.json' file will be processed.␊ + ␊ + -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␊ ␊ `, }, @@ -42,14 +43,15 @@ Generated by [AVA](https://avajs.dev). result: { errorCode: null, stderr: '', - stdout: `Usage: sort-package-json [OPTION...] [FILE...]␊ - Sort npm package.json files. Default: ./package.json␊ - Strings passed as files are parsed as globs.␊ + stdout: `Usage: sort-package-json [options] [file/glob ...]␊ + ␊ + Sort package.json files.␊ + If file/glob is omitted, './package.json' file will be processed.␊ ␊ - -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␊ ␊ `, }, @@ -67,14 +69,15 @@ Generated by [AVA](https://avajs.dev). result: { errorCode: null, stderr: '', - stdout: `Usage: sort-package-json [OPTION...] [FILE...]␊ - Sort npm package.json files. Default: ./package.json␊ - Strings passed as files are parsed as globs.␊ + stdout: `Usage: sort-package-json [options] [file/glob ...]␊ + ␊ + Sort package.json files.␊ + If file/glob is omitted, './package.json' file will be processed.␊ ␊ - -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␊ ␊ `, }, @@ -93,14 +96,15 @@ Generated by [AVA](https://avajs.dev). result: { errorCode: null, stderr: '', - stdout: `Usage: sort-package-json [OPTION...] [FILE...]␊ - Sort npm package.json files. Default: ./package.json␊ - Strings passed as files are parsed as globs.␊ + stdout: `Usage: sort-package-json [options] [file/glob ...]␊ ␊ - -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␊ + Sort package.json files.␊ + If file/glob is omitted, './package.json' file will be processed.␊ + ␊ + -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␊ ␊ `, }, @@ -189,14 +193,15 @@ Generated by [AVA](https://avajs.dev). result: { errorCode: null, stderr: '', - stdout: `Usage: sort-package-json [OPTION...] [FILE...]␊ - Sort npm package.json files. Default: ./package.json␊ - Strings passed as files are parsed as globs.␊ + stdout: `Usage: sort-package-json [options] [file/glob ...]␊ + ␊ + Sort package.json files.␊ + If file/glob is omitted, './package.json' file will be processed.␊ ␊ - -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␊ ␊ `, }, @@ -600,7 +605,7 @@ Generated by [AVA](https://avajs.dev). }, ], result: { - errorCode: 2, + errorCode: 1, stderr: '', stdout: `bad-1/package.json␊ bad-2/package.json␊ @@ -685,7 +690,7 @@ Generated by [AVA](https://avajs.dev). }, ], result: { - errorCode: 2, + errorCode: 1, stderr: '', stdout: '', }, @@ -872,7 +877,7 @@ Generated by [AVA](https://avajs.dev). }, ], result: { - errorCode: 2, + errorCode: 1, stderr: '', stdout: `bad-1/package.json␊ bad-2/package.json␊ @@ -939,7 +944,7 @@ Generated by [AVA](https://avajs.dev). }, ], result: { - errorCode: 2, + errorCode: 1, stderr: '', stdout: '', }, @@ -967,7 +972,7 @@ Generated by [AVA](https://avajs.dev). }, ], result: { - errorCode: 1, + errorCode: 2, stderr: `No matching files.␊ `, stdout: '', @@ -997,7 +1002,7 @@ Generated by [AVA](https://avajs.dev). }, ], result: { - errorCode: 1, + errorCode: 2, stderr: `No matching files.␊ `, stdout: '', @@ -1027,7 +1032,7 @@ Generated by [AVA](https://avajs.dev). }, ], result: { - errorCode: 1, + errorCode: 2, stderr: `No matching files.␊ `, stdout: '', @@ -1058,7 +1063,7 @@ Generated by [AVA](https://avajs.dev). }, ], result: { - errorCode: 1, + errorCode: 2, stderr: `No matching files.␊ `, stdout: '', diff --git a/tests/snapshots/cli.js.snap b/tests/snapshots/cli.js.snap index 968ae376..35fbb27f 100644 Binary files a/tests/snapshots/cli.js.snap and b/tests/snapshots/cli.js.snap differ