@prantlf/jsonlint 11.4.0 → 11.5.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 +3 -0
  2. package/lib/cli.js +80 -18
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -122,6 +122,7 @@ Usage: `jsonlint [options] [<file, directory, pattern> ...]`
122
122
  -E, --extensions [ext] file extensions to process for directory walk
123
123
  (default: ["json","JSON"])
124
124
  -i, --in-place overwrite the input files
125
+ -j, --diff print difference instead of writing the output
125
126
  -k, --check check that the input is equal to the output
126
127
  -t, --indent [num|char] number of spaces or specific characters
127
128
  to use for indentation (default: 2)
@@ -187,6 +188,8 @@ The configuration is an object with the following properties, described above, w
187
188
  | sort-keys | sortKeys |
188
189
  | extensions | |
189
190
  | in-place | inPlace |
191
+ | diff | |
192
+ | check | |
190
193
  | indent | |
191
194
  | compact | |
192
195
  | mode | |
package/lib/cli.js CHANGED
@@ -21,6 +21,7 @@ const commander = require('commander')
21
21
  .option('-s, --sort-keys', 'sort object keys (not when prettifying)')
22
22
  .option('-E, --extensions [ext]', 'file extensions to process for directory walk', collectValues, ['json', 'JSON'])
23
23
  .option('-i, --in-place', 'overwrite the input files')
24
+ .option('-j, --diff', 'print difference instead of writing the output')
24
25
  .option('-k, --check', 'check that the input is equal to the output')
25
26
  .option('-t, --indent [num|char]', 'number of spaces or specific characters to use for indentation', 2)
26
27
  .option('-c, --compact', 'compact error display')
@@ -87,6 +88,7 @@ if (params.config === false) {
87
88
  }
88
89
 
89
90
  const extensions = options.extensions.map(extension => '.' + extension)
91
+ let reported
90
92
 
91
93
  function convertConfig (config) {
92
94
  const result = {}
@@ -108,11 +110,17 @@ function mergeOptions (target, ...sources) {
108
110
  return target
109
111
  }
110
112
 
111
- function logNormalError (error, file) {
112
- if (process.exitCode > 0) {
113
+ function separateBlocks () {
114
+ if (reported) {
113
115
  console.log()
116
+ } else {
117
+ reported = true
114
118
  }
115
- console.log('File:', file)
119
+ }
120
+
121
+ function logNormalError (error, file) {
122
+ separateBlocks()
123
+ console.info('File:', file)
116
124
  console.error(error.message)
117
125
  }
118
126
 
@@ -209,35 +217,82 @@ function ensureLineBreak (parsed, source) {
209
217
  }
210
218
 
211
219
  function checkContents (file, source, parsed) {
212
- const { createTwoFilesPatch } = require('diff')
220
+ const { createTwoFilesPatch, structuredPatch } = require('diff')
221
+ const structured = structuredPatch(`${file}.orig`, file, source, parsed, '', '', { context: 3 })
222
+ const length = structured.hunks && structured.hunks.length
213
223
  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')
224
+ if (length > 0) {
225
+ const hunk = length === 1 ? 'hunk differs' : 'hunks differ'
226
+ const message = `${length} ${hunk}`
216
227
  if (options.compact) {
217
- logCompactError(err, file)
228
+ console.error(`${file}: ${message}`)
218
229
  } else {
219
- logNormalError(err, file)
230
+ separateBlocks()
231
+ console.info('File:', file)
232
+ console.error(message)
233
+ }
234
+ if (!options.quiet) {
235
+ console.log(diff)
220
236
  }
221
- console.log(diff)
222
237
  if (options.continue) {
223
238
  process.exitCode = 1
224
239
  } else {
225
240
  process.exit(1)
226
241
  }
242
+ } else {
243
+ if (options.compact) {
244
+ console.info(`${file}: no difference`)
245
+ } else if (options.logFiles) {
246
+ console.info(file)
247
+ }
248
+ }
249
+ }
250
+
251
+ function diffContents (file, source, parsed) {
252
+ const { createTwoFilesPatch, structuredPatch } = require('diff')
253
+ const compact = options.quiet || options.compact
254
+ let diff, length
255
+ if (compact) {
256
+ diff = structuredPatch(`${file}.orig`, file, source, parsed, '', '', { context: 3 })
257
+ length = diff.hunks && diff.hunks.length
258
+ } else {
259
+ diff = createTwoFilesPatch(`${file}.orig`, file, source, parsed, '', '', { context: 3 })
260
+ length = diff.split(/\r?\n/).length - 4
261
+ }
262
+ if (length > 0) {
263
+ if (compact) {
264
+ const hunk = length === 1 ? 'hunk differs' : 'hunks differ'
265
+ console.info(`${file}: ${length} ${hunk}`)
266
+ } else {
267
+ separateBlocks()
268
+ console.info('File:', file)
269
+ console.log(diff)
270
+ }
271
+ } else {
272
+ if (options.compact) {
273
+ console.info(`${file}: no difference`)
274
+ } else if (options.logFiles) {
275
+ console.info(file)
276
+ }
227
277
  }
228
278
  }
229
279
 
230
280
  function processFile (file) {
231
281
  file = normalize(file)
232
- if (options.logFiles) {
233
- console.log(file)
282
+ if (options.logFiles && !(options.compact || options.check || options.diff)) {
283
+ console.info(file)
234
284
  }
235
285
  const source = readFileSync(file, 'utf8')
236
286
  const parsed = processContents(source, file)
237
287
  if (options.inPlace) {
288
+ if (options.logFiles && options.compact) {
289
+ console.info(file)
290
+ }
238
291
  writeFileSync(file, ensureLineBreak(parsed, source))
239
292
  } else if (options.check) {
240
293
  checkContents(file, source, ensureLineBreak(parsed, source))
294
+ } else if (options.diff) {
295
+ diffContents(file, source, ensureLineBreak(parsed, source))
241
296
  } else {
242
297
  if (!(options.quiet || options.logFiles)) {
243
298
  console.log(parsed)
@@ -263,21 +318,21 @@ function processSource (src, checkExtension) {
263
318
  }
264
319
  }
265
320
  } catch ({ message }) {
266
- console.log('WARN', message)
321
+ console.warn('WARN', message)
267
322
  }
268
323
  }
269
324
 
270
325
  function processPatterns (patterns) {
271
326
  const files = sync(patterns, { onlyFiles: true })
272
327
  if (!files.length) {
273
- console.log('no files found')
328
+ console.error('no files found')
274
329
  process.exit(1)
275
330
  }
276
331
  for (const file of files) {
277
332
  try {
278
333
  processFile(file)
279
334
  } catch ({ message }) {
280
- console.log('WARN', message)
335
+ console.warn('WARN', message)
281
336
  }
282
337
  }
283
338
  }
@@ -305,14 +360,21 @@ function main () {
305
360
  })
306
361
  stdin.on('end', () => {
307
362
  const file = '<stdin>'
308
- if (options.logFiles) {
309
- console.log(file)
363
+ if (options.logFiles && !(options.compact || options.check || options.diff)) {
364
+ console.info(file)
310
365
  }
311
366
  const parsed = processContents(source, file)
312
367
  if (options.check) {
313
368
  checkContents(file, source, ensureLineBreak(parsed, source))
314
- } else if (!(options.quiet || options.logFiles)) {
315
- console.log(parsed)
369
+ } else if (options.diff) {
370
+ diffContents(file, source, ensureLineBreak(parsed, source))
371
+ } else {
372
+ if (options.logFiles && options.compact) {
373
+ console.info(file)
374
+ }
375
+ if (!(options.quiet || options.logFiles)) {
376
+ console.log(parsed)
377
+ }
316
378
  }
317
379
  })
318
380
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prantlf/jsonlint",
3
- "version": "11.4.0",
3
+ "version": "11.5.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": [