Skip to content

Commit

Permalink
refactor: refactor cli (#285)
Browse files Browse the repository at this point in the history
- Separate features into different functions, so we can easily exit.
- Use `process.exitCode` instead of `process.exit()`
- Change exit code to 1 (file not sorted) and 2 (fatal errors)
- Update husky and lint-staged setup
- Minor tweak to the help information
  • Loading branch information
fisker authored Jan 30, 2023
1 parent 0850201 commit 1488785
Show file tree
Hide file tree
Showing 4 changed files with 150 additions and 118 deletions.
21 changes: 13 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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?
Expand Down Expand Up @@ -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?
156 changes: 89 additions & 67 deletions cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Loading

0 comments on commit 1488785

Please sign in to comment.