Skip to content

Commit 7eebd76

Browse files
committed
feat: Read options from configuration files
1 parent 83037b8 commit 7eebd76

File tree

5 files changed

+230
-78
lines changed

5 files changed

+230
-78
lines changed

README.md

Lines changed: 122 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,11 @@ This is a fork of the original project ([zaach/jsonlint](https://github.com/zaac
1717
* Supports [JSON Schema] drafts 04, 06 and 07.
1818
* Offers pretty-printing including comment-stripping and object keys without quotes (JSON5).
1919
* Prefers the native JSON parser if possible to run [7x faster than the custom parser].
20-
* Reports errors with rich additional information. From the schema validation too.
21-
* Implements JavaScript modules using [UMD] to work everywhere.
20+
* Reports errors with rich additional information. From the JSON Schema validation too.
21+
* Consumes configuration from both command line and [configuration files](configuration).
22+
* Implements JavaScript modules using [UMD] to work in Node.js, in a browser, everywhere.
2223
* Depends on up-to-date npm modules with no installation warnings.
23-
* Small size - 18.2 kB minified, 6.3 kB gzipped.
24+
* Small size - 18.7 kB minified, 6.54 kB gzipped, 5.16 kB brotlied.
2425

2526
**Note:** In comparison with the original project, this package exports only the `parse` method; not the `Parser` object.
2627

@@ -52,9 +53,11 @@ Example of an error message:
5253

5354
## Command-line Interface
5455

55-
Install `jsonlint` with `npm`` globally to be able to use the command-line interface in any directory:
56+
Install `jsonlint` with `npm`, `pnpm` or `yarn` globally to be able to use the command-line interface in any directory:
5657

57-
npm i @prantlf/jsonlint -g
58+
npm i -g @prantlf/jsonlint
59+
pnpm i -g @prantlf/jsonlint
60+
yarn add --global @prantlf/jsonlint
5861

5962
Validate a single file:
6063

@@ -64,9 +67,9 @@ or pipe the JSON input into `stdin`:
6467

6568
cat myfile.json | jsonlint
6669

67-
or process all `.json` files in a directory:
70+
or process all `.json` files in a directory and rewriting them with the pretty-printed output:
6871

69-
jsonlint mydir
72+
jsonlint --in-place --pretty-print mydir
7073

7174
By default, `jsonlint` will either report a syntax error with details or pretty-print the source if it is valid.
7275

@@ -75,58 +78,118 @@ A more complex example: check all JSON files in a Node.js project, except for de
7578
jsonlint --comments --trailing-commas --no-duplicate-keys \
7679
--log-files --compact --continue '**/*.json' '!**/node_modules'
7780

78-
### Options
79-
80-
$ jsonlint -h
81-
82-
Usage: jsonlint [options] [<file, directory, pattern> ...]
83-
84-
JSON parser, syntax and schema validator and pretty-printer.
85-
86-
Options:
87-
-s, --sort-keys sort object keys (not when prettifying)
88-
-E, --extensions [ext] file extensions to process for directory walk
89-
(default: ["json","JSON"])
90-
-i, --in-place overwrite the input files
91-
-t, --indent [num|char] number of spaces or specific characters
92-
to use for indentation (default: 2)
93-
-c, --compact compact error display
94-
-M, --mode [mode] set other parsing flags according to a format
95-
type (default: "json")
96-
-C, --comments recognize and ignore JavaScript-style comments
97-
-S, --single-quoted-strings support single quotes as string delimiters
98-
-T, --trailing-commas ignore trailing commas in objects and arrays
99-
-D, --no-duplicate-keys report duplicate object keys as an error
100-
-V, --validate [file] JSON schema file to use for validation
101-
-e, --environment [env] which specification of JSON Schema the
102-
validation file uses
103-
-l, --log-files print only the parsed file names to stdout
104-
-q, --quiet do not print the parsed json to stdout
105-
-n, --continue continue with other files if an error occurs
106-
-p, --pretty-print prettify the input instead of stringifying
107-
the parsed object
108-
-P, --pretty-print-invalid force pretty-printing even for invalid input
109-
-r, --trailing-newline ensure a line break at the end of the output
110-
-R, --no-trailing-newline ensure no line break at the end of the output
111-
--prune-comments omit comments from the prettified output
112-
--strip-object-keys strip quotes from object keys if possible
113-
(JSON5)
114-
--enforce-double-quotes surrounds all strings with double quotes
115-
--enforce-single-quotes surrounds all strings with single quotes
116-
(JSON5)
117-
--trim-trailing-commas omit trailing commas from objects and arrays
118-
(JSON5)
119-
-v, --version output the version number
120-
-h, --help output usage information
121-
122-
You can use BASH patterns for including and excluding files (only files).
123-
Patterns are case-sensitive and have to use slashes as a path separators.
124-
A pattern to exclude from processing starts with "!".
125-
126-
Parsing mode can be "cjson" or "json5" to enable other flags automatically.
127-
If no files or directories are specified, stdin will be parsed. Environments
128-
for JSON schema validation are "json-schema-draft-04", "json-schema-draft-06"
129-
or "json-schema-draft-07". If not specified, it will be auto-detected.
81+
The same parameters can be passed from a configuration file:
82+
83+
```json
84+
{
85+
"comments": true,
86+
"trailing-commas": true,
87+
"duplicate-keys": false,
88+
"log-files": true,
89+
"compact": true,
90+
"continue": true,
91+
"patterns": ["**/*.json", "!**/node_modules"]
92+
}
93+
```
94+
95+
### Usage
96+
97+
Usage: `jsonlint [options] [<file, directory, pattern> ...]`
98+
99+
#### Options
100+
101+
-f, --config [file] read options from a custom configuration file
102+
-F, --no-config disable searching for configuration file
103+
-s, --sort-keys sort object keys (not when prettifying)
104+
-E, --extensions [ext] file extensions to process for directory walk
105+
(default: ["json","JSON"])
106+
-i, --in-place overwrite the input files
107+
-t, --indent [num|char] number of spaces or specific characters
108+
to use for indentation (default: 2)
109+
-c, --compact compact error display
110+
-M, --mode [mode] set other parsing flags according to a format
111+
type (default: "json")
112+
-C, --comments recognize and ignore JavaScript-style comments
113+
-S, --single-quoted-strings support single quotes as string delimiters
114+
-T, --trailing-commas ignore trailing commas in objects and arrays
115+
-D, --no-duplicate-keys report duplicate object keys as an error
116+
-V, --validate [file] JSON schema file to use for validation
117+
-e, --environment [env] which specification of JSON Schema the
118+
validation file uses
119+
-l, --log-files print only the parsed file names to stdout
120+
-q, --quiet do not print the parsed json to stdout
121+
-n, --continue continue with other files if an error occurs
122+
-p, --pretty-print prettify the input instead of stringifying
123+
the parsed object
124+
-P, --pretty-print-invalid force pretty-printing even for invalid input
125+
-r, --trailing-newline ensure a line break at the end of the output
126+
-R, --no-trailing-newline ensure no line break at the end of the output
127+
--prune-comments omit comments from the prettified output
128+
--strip-object-keys strip quotes from object keys if possible
129+
(JSON5)
130+
--enforce-double-quotes surrounds all strings with double quotes
131+
--enforce-single-quotes surrounds all strings with single quotes
132+
(JSON5)
133+
--trim-trailing-commas omit trailing commas from objects and arrays
134+
(JSON5)
135+
-v, --version output the version number
136+
-h, --help output usage information
137+
138+
You can use BASH patterns for including and excluding files (only files).
139+
Patterns are case-sensitive and have to use slashes as a path separators.
140+
A pattern to exclude from processing starts with "!".
141+
142+
Parsing mode can be "cjson" or "json5" to enable other flags automatically.
143+
If no files or directories are specified, stdin will be parsed. Environments
144+
for JSON schema validation are "json-schema-draft-04", "json-schema-draft-06"
145+
or "json-schema-draft-07". If not specified, it will be auto-detected.
146+
147+
### Configuration
148+
149+
In addition to the command line parameters, the options can be supplied from the following files:
150+
151+
package.json, key jsonlint
152+
.jsonlintrc
153+
.jsonlintrc.json
154+
.jsonlintrc.yaml
155+
.jsonlintrc.yml
156+
.jsonlintrc.js
157+
.jsonlintrc.cjs
158+
jsonlint.config.js
159+
jsonlint.config.cjs
160+
161+
The automatic search for one of the following locations above can be disabled by the command-line parameter `-F|--no-config`. A concrete configuration file can be specified by the command-line parameter `-f|--config [file]`. Parameters from the command line will have higher priority than parameters from a configuration file.
162+
163+
The configuration is an object with the following properties, described above, which can be entered either in the kebab-case or in the camel-case:
164+
165+
| Parameter | Alias |
166+
| --------- | ----- |
167+
| patterns | |
168+
| sort-keys | sortKeys |
169+
| extensions | |
170+
| in-place | inPlace |
171+
| indent | |
172+
| compact | |
173+
| mode | |
174+
| comments | |
175+
| single-quoted-strings | singleQuotedStrings |
176+
| trailing-commas | trailingCommas |
177+
| duplicate-keys | duplicateKeys |
178+
| validate | |
179+
| environment | |
180+
| log-files | logFiles |
181+
| quiet | |
182+
| continue | |
183+
| pretty-print | prettyPrint |
184+
| pretty-print-invalid | prettyPrintInvalid |
185+
| trailing-newline | trailingNewline'
186+
| prune-comments | pruneComments |
187+
| strip-object-keys | stripObjectKeys |
188+
| enforce-double-quotes | enforceDoubleQuotes |
189+
| enforce-single-quotes | enforceSingleQuotes |
190+
| trim-trailing-commas | trimTrailingCommas |
191+
192+
The parameter `config` will be ignored in configuration files. The extra parameter `patterns` can be set to an array of strings with paths or patterns instead of putting them to the command line.
130193

131194
## Module Interface
132195

lib/cli.js

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
const { readdirSync, readFileSync, statSync, writeFileSync } = require('fs')
44
const { extname, join, normalize } = require('path')
55
const { isDynamicPattern, sync } = require('fast-glob')
6+
const { cosmiconfigSync } = require('cosmiconfig')
67
const { parse, tokenize } = require('./jsonlint')
78
const { format } = require('./formatter')
89
const { print } = require('./printer')
@@ -16,6 +17,8 @@ const commander = require('commander')
1617
.name('jsonlint')
1718
.usage('[options] [<file, directory, pattern> ...]')
1819
.description(description)
20+
.option('-f, --config [file]', 'read options from a custom configuration file')
21+
.option('-F, --no-config', 'disable searching for configuration files')
1922
.option('-s, --sort-keys', 'sort object keys (not when prettifying)')
2023
.option('-E, --extensions [ext]', 'file extensions to process for directory walk', collectValues, ['json', 'JSON'])
2124
.option('-i, --in-place', 'overwrite the input files')
@@ -54,9 +57,56 @@ const commander = require('commander')
5457
})
5558
.parse(process.argv)
5659

57-
const options = commander.opts()
60+
const paramNames = {
61+
'trailing-commas': 'trailingCommas',
62+
'single-quoted-strings': 'singleQuotedStrings',
63+
'duplicate-keys': 'duplicateKeys',
64+
'pretty-print': 'prettyPrint',
65+
'prune-comments': 'pruneComments',
66+
'strip-object-keys': 'stripObjectKeys',
67+
'enforce-double-quotes': 'enforceDoubleQuotes',
68+
'enforce-single-quotes': 'enforceSingleQuotes',
69+
'trim-trailing-commas': 'trimTrailingCommas',
70+
'sort-keys': 'sortKeys',
71+
'pretty-print-invalid': 'prettyPrintInvalid',
72+
'log-files': 'logFiles',
73+
'in-place': 'inPlace',
74+
'trailing-newline': 'trailingNewline'
75+
}
76+
77+
const params = commander.opts()
78+
let options
79+
if (params.config === false) {
80+
options = params
81+
} else {
82+
const configurator = cosmiconfigSync('jsonlint')
83+
const { config = {} } = (params.config && configurator.load(params.config)) ||
84+
configurator.search() || {}
85+
options = mergeOptions({}, convertConfig(config), params)
86+
}
87+
5888
const extensions = options.extensions.map(extension => '.' + extension)
5989

90+
function convertConfig (config) {
91+
const result = {}
92+
for (const key in config) {
93+
const name = paramNames[key] || key
94+
result[name] = config[key]
95+
}
96+
return result
97+
}
98+
99+
function mergeOptions (target, ...sources) {
100+
for (const source of sources) {
101+
for (const key in source) {
102+
if (target[key] == null) {
103+
target[key] = source[key]
104+
}
105+
}
106+
}
107+
return target
108+
}
109+
60110
function logNormalError (error, file) {
61111
if (process.exitCode > 0) {
62112
console.log()
@@ -207,7 +257,10 @@ function processPatterns (patterns) {
207257
}
208258

209259
function main () {
210-
const { args: files } = commander
260+
let { args: files } = commander
261+
if (!files.length) {
262+
files = options.patterns || []
263+
}
211264
if (files.length) {
212265
const dynamic = files.some(file => isDynamicPattern(file))
213266
if (dynamic) {

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
"build": "npm run compile && npm run compile:tests",
4646
"compile": "node scripts/bundle-jsonlint && terser -o web/jsonlint.min.js --source-map \"filename='jsonlint.js',url='jsonlint.min.js.map',includeSources=true\" lib/jsonlint.js && terser -o web/validator.min.js --source-map \"filename='validator.js',url='validator.min.js.map',includeSources=true\" lib/validator.js && terser -o web/formatter.min.js --source-map \"filename='formatter.js',url='formatter.min.js.map',includeSources=true\" lib/formatter.js && terser -o web/sorter.min.js --source-map \"filename='sorter.js',url='sorter.min.js.map',includeSources=true\" lib/sorter.js && terser -o web/printer.min.js --source-map \"filename='printer.js',url='printer.min.js.map',includeSources=true\" lib/printer.js && node scripts/bundle-schema-drafts && terser -o web/schema-drafts.min.js --source-map \"filename='schema-drafts.js',url='schema-drafts.min.js.map',includeSources=true\" lib/schema-drafts.js && terser -o web/ajv.min.js --source-map \"filename='ajv.js',url='ajv.min.js.map',includeSources=true\" node_modules/ajv/dist/ajv.bundle.js",
4747
"compile:tests": "tsc --lib es6 test/typings.test.ts",
48-
"test": "nyc --silent node test/typings.test.js && nyc --silent --no-clean node test/parse1 && nyc --silent --no-clean node test/parse1 --native-parser && nyc --silent --no-clean node test/parse2 && nyc --silent --no-clean node test/parse3 && nyc --silent --no-clean node test/parse4 && nyc --silent --no-clean node test/parse5 && nyc --silent --no-clean node test/portable && nyc --silent --no-clean node test/tokenize && nyc --silent --no-clean node test/print && nyc --silent --no-clean node lib/cli package.json test/recursive && nyc --silent --no-clean node lib/cli -sq test/passes/hasOwnProperty.json && nyc --silent --no-clean node lib/cli -s -e json-schema-draft-04 -V test/passes/3.schema.json test/passes/3.json && nyc --silent --no-clean node lib/cli -C test/passes/comments.txt && nyc --silent --no-clean node lib/cli -pS test/passes/strings.txt && nyc --silent --no-clean node lib/cli -M json5 test/passes/json5.text && nyc --silent --no-clean node lib/cli -v && nyc --silent --no-clean node lib/cli -h && nyc --silent --no-clean node lib/cli -Pc test/fails/10.json || nyc --silent --no-clean node lib/cli -l 'test/**/*.json' '!**/fails' && nyc report",
48+
"test": "nyc --silent node test/typings.test.js && nyc --silent --no-clean node test/parse1 && nyc --silent --no-clean node test/parse1 --native-parser && nyc --silent --no-clean node test/parse2 && nyc --silent --no-clean node test/parse3 && nyc --silent --no-clean node test/parse4 && nyc --silent --no-clean node test/parse5 && nyc --silent --no-clean node test/portable && nyc --silent --no-clean node test/tokenize && nyc --silent --no-clean node test/print && nyc --silent --no-clean node lib/cli package.json test/recursive && nyc --silent --no-clean node lib/cli -sq test/passes/hasOwnProperty.json && nyc --silent --no-clean node lib/cli -s -e json-schema-draft-04 -V test/passes/3.schema.json test/passes/3.json && nyc --silent --no-clean node lib/cli -C test/passes/comments.txt && nyc --silent --no-clean node lib/cli -pS test/passes/strings.txt && nyc --silent --no-clean node lib/cli -M json5 test/passes/json5.text && nyc --silent --no-clean node lib/cli -v && nyc --silent --no-clean node lib/cli -h && nyc --silent --no-clean node lib/cli -Pc test/fails/10.json || nyc --silent --no-clean node lib/cli -f test/.jsonrc.yml 'test/**/*.json' '!**/fails' && nyc report",
4949
"start": "http-server -c 5",
5050
"web": "npm run web:sync && npm run web:deploy",
5151
"web:clone": "test ! -d ../jsonlint-pages && git clone --single-branch --branch gh-pages `git remote get-url origin` ../jsonlint-pages",
@@ -77,6 +77,7 @@
7777
"dependencies": {
7878
"ajv": "6.12.6",
7979
"commander": "9.2.0",
80+
"cosmiconfig": "^7.0.1",
8081
"fast-glob": "3.2.11"
8182
},
8283
"devDependencies": {

0 commit comments

Comments
 (0)