@prantlf/jsonlint 11.3.0 → 11.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +19 -0
  2. package/lib/cli.js +43 -14
  3. package/package.json +8 -7
package/README.md CHANGED
@@ -14,6 +14,7 @@ This is a fork of the original project ([zaach/jsonlint](https://github.com/zaac
14
14
  * Provides 100% compatible interface to the native `JSON.parse` method.
15
15
  * Optionally recognizes JavaScript-style comments (CJSON) and single quoted strings (JSON5).
16
16
  * Optionally ignores trailing commas and reports duplicate object keys as an error.
17
+ * Optionally checks that also the expected format matches, including sorted object keys.
17
18
  * Supports [JSON Schema] drafts 04, 06 and 07.
18
19
  * Offers pretty-printing including comment-stripping and object keys without quotes (JSON5).
19
20
  * Prefers the native JSON parser if possible to run [7x faster than the custom parser].
@@ -92,6 +93,23 @@ The same parameters can be passed from a configuration file:
92
93
  }
93
94
  ```
94
95
 
96
+ The input can be checked not only to be a valid JSON, but also to be formatted according to the coding standard. For example, check that there is a trailing li break in each JSON file, in addition to alphabetically sorted keys and no duplicate keys:
97
+
98
+ $ jsonlint -ksDr *.json
99
+
100
+ File: package.json
101
+ Formatted output differs
102
+ ===================================================================
103
+ --- package.json.orig
104
+ +++ package.json
105
+ @@ -105,4 +105,4 @@
106
+ "lint",
107
+ "jsonlint"
108
+ ]
109
+ -}
110
+ +}
111
+
112
+
95
113
  ### Usage
96
114
 
97
115
  Usage: `jsonlint [options] [<file, directory, pattern> ...]`
@@ -104,6 +122,7 @@ Usage: `jsonlint [options] [<file, directory, pattern> ...]`
104
122
  -E, --extensions [ext] file extensions to process for directory walk
105
123
  (default: ["json","JSON"])
106
124
  -i, --in-place overwrite the input files
125
+ -k, --check check that the input is equal to the output
107
126
  -t, --indent [num|char] number of spaces or specific characters
108
127
  to use for indentation (default: 2)
109
128
  -c, --compact compact error display
package/lib/cli.js CHANGED
@@ -3,7 +3,6 @@
3
3
  const { readdirSync, readFileSync, statSync, writeFileSync } = require('fs')
4
4
  const { extname, join, normalize } = require('path')
5
5
  const { isDynamicPattern, sync } = require('fast-glob')
6
- const { cosmiconfigSync } = require('cosmiconfig')
7
6
  const { parse, tokenize } = require('./jsonlint')
8
7
  const { format } = require('./formatter')
9
8
  const { print } = require('./printer')
@@ -22,6 +21,7 @@ const commander = require('commander')
22
21
  .option('-s, --sort-keys', 'sort object keys (not when prettifying)')
23
22
  .option('-E, --extensions [ext]', 'file extensions to process for directory walk', collectValues, ['json', 'JSON'])
24
23
  .option('-i, --in-place', 'overwrite the input files')
24
+ .option('-k, --check', 'check that the input is equal to the output')
25
25
  .option('-t, --indent [num|char]', 'number of spaces or specific characters to use for indentation', 2)
26
26
  .option('-c, --compact', 'compact error display')
27
27
  .option('-M, --mode [mode]', 'set other parsing flags according to a format type', 'json')
@@ -79,6 +79,7 @@ let options
79
79
  if (params.config === false) {
80
80
  options = params
81
81
  } else {
82
+ const { cosmiconfigSync } = require('cosmiconfig')
82
83
  const configurator = cosmiconfigSync('jsonlint')
83
84
  const { config = {} } = (params.config && configurator.load(params.config)) ||
84
85
  configurator.search() || {}
@@ -197,24 +198,49 @@ function processContents (source, file) {
197
198
  }
198
199
  }
199
200
 
201
+ function ensureLineBreak (parsed, source) {
202
+ const lines = source.split(/\r?\n/)
203
+ const newLine = !lines[lines.length - 1]
204
+ if (options.trailingNewline === true ||
205
+ (options.trailingNewline !== false && newLine)) {
206
+ parsed += '\n'
207
+ }
208
+ return parsed
209
+ }
210
+
211
+ function checkContents (file, source, parsed) {
212
+ const { createTwoFilesPatch } = require('diff')
213
+ const diff = createTwoFilesPatch(`${file}.orig`, file, source, parsed, '', '', { context: 3 })
214
+ if (diff.split(/\r?\n/).length > 4) {
215
+ const err = new Error('Formatted output differs')
216
+ if (options.compact) {
217
+ logCompactError(err, file)
218
+ } else {
219
+ logNormalError(err, file)
220
+ }
221
+ console.log(diff)
222
+ if (options.continue) {
223
+ process.exitCode = 1
224
+ } else {
225
+ process.exit(1)
226
+ }
227
+ }
228
+ }
229
+
200
230
  function processFile (file) {
201
231
  file = normalize(file)
202
232
  if (options.logFiles) {
203
233
  console.log(file)
204
234
  }
205
- const original = readFileSync(file, 'utf8')
206
- let source = processContents(original, file)
235
+ const source = readFileSync(file, 'utf8')
236
+ const parsed = processContents(source, file)
207
237
  if (options.inPlace) {
208
- const lines = original.split(/\r?\n/)
209
- const newLine = !lines[lines.length - 1]
210
- if (options.trailingNewline === true ||
211
- (options.trailingNewline !== false && newLine)) {
212
- source += '\n'
213
- }
214
- writeFileSync(file, source)
238
+ writeFileSync(file, ensureLineBreak(parsed, source))
239
+ } else if (options.check) {
240
+ checkContents(file, source, ensureLineBreak(parsed, source))
215
241
  } else {
216
242
  if (!(options.quiet || options.logFiles)) {
217
- console.log(source)
243
+ console.log(parsed)
218
244
  }
219
245
  }
220
246
  }
@@ -278,11 +304,14 @@ function main () {
278
304
  source += chunk.toString('utf8')
279
305
  })
280
306
  stdin.on('end', () => {
307
+ const file = '<stdin>'
281
308
  if (options.logFiles) {
282
- console.log('<stdin>')
309
+ console.log(file)
283
310
  }
284
- const parsed = processContents(source, '<stdin>')
285
- if (!(options.quiet || options.logFiles)) {
311
+ const parsed = processContents(source, file)
312
+ if (options.check) {
313
+ checkContents(file, source, ensureLineBreak(parsed, source))
314
+ } else if (!(options.quiet || options.logFiles)) {
286
315
  console.log(parsed)
287
316
  }
288
317
  })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prantlf/jsonlint",
3
- "version": "11.3.0",
3
+ "version": "11.4.0",
4
4
  "description": "JSON/CJSON/JSON5 parser, syntax and schema validator and pretty-printer.",
5
5
  "author": "Ferdinand Prantl <prantlf@gmail.com> (http://prantl.tk)",
6
6
  "contributors": [
@@ -77,15 +77,16 @@
77
77
  "dependencies": {
78
78
  "ajv": "6.12.6",
79
79
  "commander": "9.2.0",
80
- "cosmiconfig": "^7.0.1",
80
+ "cosmiconfig": "7.0.1",
81
+ "diff": "5.0.0",
81
82
  "fast-glob": "3.2.11"
82
83
  },
83
84
  "devDependencies": {
84
- "@semantic-release/changelog": "^6.0.1",
85
- "@semantic-release/git": "^10.0.1",
86
- "@types/node": "17.0.30",
87
- "@typescript-eslint/eslint-plugin": "5.21.0",
88
- "@typescript-eslint/parser": "5.21.0",
85
+ "@semantic-release/changelog": "6.0.1",
86
+ "@semantic-release/git": "10.0.1",
87
+ "@types/node": "17.0.31",
88
+ "@typescript-eslint/eslint-plugin": "5.22.0",
89
+ "@typescript-eslint/parser": "5.22.0",
89
90
  "eslint": "8.14.0",
90
91
  "eslint-config-standard": "17.0.0",
91
92
  "eslint-plugin-import": "2.26.0",