@prantlf/jsonlint 16.0.0 → 17.0.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.
package/LICENSE CHANGED
@@ -1,7 +1,7 @@
1
1
  MIT License
2
2
 
3
3
  Copyright (c) 2012-2018 Zachary Carter
4
- Copyright (c) 2019-2024 Ferdinand Prantl
4
+ Copyright (c) 2019-2026 Ferdinand Prantl
5
5
 
6
6
  Permission is hereby granted, free of charge, to any person obtaining a copy
7
7
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -157,12 +157,16 @@ Usage: `jsonlint [options] [--] [<file, directory, pattern> ...]`
157
157
  -P, --pretty-print-invalid force pretty-printing even for invalid input
158
158
  -r, --trailing-newline ensure a line break at the end of the output
159
159
  -R, --no-trailing-newline ensure no line break at the end of the output
160
+ --no-strict disable the strict schema validation mode
160
161
  --prune-comments omit comments from the prettified output
161
162
  --strip-object-keys strip quotes from object keys if possible
162
163
  --enforce-double-quotes surrounds all strings with double quotes
163
164
  --enforce-single-quotes surrounds all strings with single quotes
164
165
  --trim-trailing-commas omit trailing commas from objects and arrays
166
+ --no-compact-empty-objects insert line break between empty {} and []
167
+ --force-crlf make sure all line breaks are CRLF
165
168
  --succeed-with-no-files succeed (exit code 0) if no files were found
169
+ --[no-]color force or disable colourful output of the diff
166
170
  -v, --version output the version number
167
171
  -h, --help display help for command
168
172
 
@@ -177,8 +181,8 @@ for JSON Schema validation are "draft-04", "draft-06", "draft-07",
177
181
  with "json-schema-". JSON Type Definition can be selected by "rfc8927",
178
182
  "json-type-definition" or "jtd". If not specified, it will be "draft-07".
179
183
 
180
- If you specify schemas using the "-V" parameter, you will have to separate
181
- files to test with "--".
184
+ If you specify multiple schemas, either separate them by comma (,) or
185
+ use the "-V" parameter multiple times.
182
186
 
183
187
  ### Configuration
184
188
 
@@ -222,6 +226,8 @@ The configuration is an object with the following properties, described above, w
222
226
  | duplicate-keys | duplicateKeys |
223
227
  | validate | |
224
228
  | environment | |
229
+ | strict | |
230
+ | color | |
225
231
  | log-files | logFiles |
226
232
  | quiet | |
227
233
  | continue | |
@@ -233,6 +239,8 @@ The configuration is an object with the following properties, described above, w
233
239
  | enforce-double-quotes | enforceDoubleQuotes |
234
240
  | enforce-single-quotes | enforceSingleQuotes |
235
241
  | trim-trailing-commas | trimTrailingCommas |
242
+ | compact-empty-objects | compactEmptyObjects |
243
+ | force-crlf | forceCrlf |
236
244
 
237
245
  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.
238
246
 
@@ -314,6 +322,12 @@ If you use external definitions in multiple schemas, you have to pass an array o
314
322
  const validate = compile(['string with main schema', 'string with a sub-schema'])
315
323
  ```
316
324
 
325
+ The schema is parsed in the *strict mode* by default. It'll fail with unknown schema keywords, string formats, conflicting property definitions, union types etc. You may need to relax the schema compilation by disabling the strict mode under circumstances:
326
+
327
+ ```js
328
+ const validate = compile('string with JSON Schema', { environment: 'draft-2020-12', strict: false })
329
+ ```
330
+
317
331
  ### Pretty-Printing
318
332
 
319
333
  You can parse a JSON string to an array of tokens and print it back to a string with some changes applied. It can be unification of whitespace, reformatting or stripping comments, for example. (Raw token values must be enabled when tokenizing the JSON input.)
@@ -337,6 +351,8 @@ The [`print`](#pretty-printing) method accepts an object `options` as the second
337
351
  | `enforceDoubleQuotes` | will surround all strings with double quotes |
338
352
  | `enforceSingleQuotes` | will surround all strings with single quotes |
339
353
  | `trimTrailingCommas` | will omit all trailing commas after the last object entry or array item |
354
+ | `compactEmptyObjects` | if set to `false`, will insert a line break between empty `{}` and `[]` |
355
+ | `forceCrlf` | make sure all line breaks are CRLF |
340
356
 
341
357
  ```js
342
358
  // Just concatenate the tokens to produce the same output as was the input.
@@ -361,6 +377,34 @@ print(tokens, {
361
377
  enforceDoubleQuotes: true,
362
378
  trimTrailingCommas: true
363
379
  })
380
+ // Same as `print(tokens, {})`, but uses \r\n for line breaks.
381
+ print(tokens, { forceCrlf: true })
382
+ ```
383
+
384
+ Pretty-printing can be also used to preserve the contents of string literal in the output. For example, the following input:
385
+
386
+ ```json
387
+ { "pattern": "^(?:\\\\x[0-9A-F]{2}|[\u0020-\u007E])+$" }
388
+ ```
389
+
390
+ will be validated and printed out by default:
391
+
392
+ ```json
393
+ {
394
+ "pattern": "^(?:\\\\x[0-9A-F]{2}|[ -~])+$"
395
+ }
396
+ ```
397
+
398
+ As you see, the escape Unicode sequences were replaced by the corresponding UTF-8 characters. While this saves space and is arguably more readable, you may have a coding standard which requires to represent some characters always by the escaped Unicode sequences. Yu can achieve it by enabling pretty-printing, which preserves the string literals in the input form. Apart from the programmatic way above, it's possible on the command line too:
399
+
400
+ jsonlint -p pattern.json
401
+
402
+ resulting in the following output:
403
+
404
+ ```json
405
+ {
406
+ "pattern": "^(?:\\\\x[0-9A-F]{2}|[\u0020-\u007E])+$"
407
+ }
364
408
  ```
365
409
 
366
410
  ### Tokenizing
@@ -445,7 +489,7 @@ ${reason}`)
445
489
 
446
490
  ## License
447
491
 
448
- Copyright (C) 2012-2024 Zachary Carter, Ferdinand Prantl
492
+ Copyright (C) 2012-2026 Zachary Carter, Ferdinand Prantl
449
493
 
450
494
  Licensed under the [MIT License].
451
495
 
package/lib/cli.js CHANGED
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- const { readdirSync, readFileSync, statSync, writeFileSync } = require('node:fs')
3
+ const { globSync, readdirSync, readFileSync, writeFileSync } = require('node:fs')
4
4
  const { extname, join } = require('node:path')
5
- const { isDynamicPattern, sync } = require('fast-glob')
5
+ const pico = require('picocolors')
6
6
  const { parse, tokenize } = require('./jsonlint')
7
7
  const { format } = require('./formatter')
8
8
  const { print } = require('./printer')
@@ -54,20 +54,39 @@ Options:
54
54
  -P, --pretty-print-invalid force pretty-printing even for invalid input
55
55
  -r, --trailing-newline ensure a line break at the end of the output
56
56
  -R, --no-trailing-newline ensure no line break at the end of the output
57
+ --no-strict disable the strict schema validation mode
57
58
  --prune-comments omit comments from the prettified output
58
59
  --strip-object-keys strip quotes from object keys if possible
59
- --enforce-double-quotes surrounds all strings with double quotes
60
- --enforce-single-quotes surrounds all strings with single quotes
60
+ --enforce-double-quotes surround all strings with double quotes
61
+ --enforce-single-quotes surround all strings with single quotes
61
62
  --trim-trailing-commas omit trailing commas from objects and arrays
63
+ --no-compact-empty-objects insert line break between empty {} and []
64
+ --force-crlf make sure all line breaks are CRLF
62
65
  --succeed-with-no-files succeed (exit code 0) if no files were found
66
+ --[no-]color force or disable colourful output of the diff
63
67
  -v, --version output the version number
64
68
  -h, --help display help for command
65
69
 
70
+ You can use BASH patterns for including and excluding files (only files).
71
+ Patterns are case-sensitive and have to use slashes as directory separators.
72
+ A pattern to exclude from processing starts with "!".
73
+
74
+ Parsing mode can be "cjson" or "json5" to enable other flags automatically.
75
+ If no files or directories are specified, stdin will be parsed. Environments
76
+ for JSON Schema validation are "draft-04", "draft-06", "draft-07",
77
+ "draft-2019-09" or "draft-2020-12". The environment may be prefixed
78
+ with "json-schema-". JSON Type Definition can be selected by "rfc8927",
79
+ "json-type-definition" or "jtd". If not specified, it will be "draft-07".
80
+
81
+ If you specify multiple schemas, either separate them by comma (,) or
82
+ use the "-V" parameter multiple times.
83
+
66
84
  Examples:
67
85
  $ jsonlint myfile.json
68
86
  $ jsonlint --in-place --pretty-print mydir
69
87
  $ jsonlint --comments --trailing-commas --no-duplicate-keys \\
70
- --log-files --compact --continue '**/*.json' '!**/node_modules'`)
88
+ --log-files --compact --continue '**/*.json' '!**/node_modules'
89
+ $ jsonlint --validate openapi-schema.json --environment draft-07 myapi.json`)
71
90
  }
72
91
 
73
92
  const { argv } = process
@@ -174,6 +193,12 @@ for (let i = 2, l = argv.length; i < l; ++i) {
174
193
  }
175
194
  params.environment = arg
176
195
  return
196
+ case 'strict':
197
+ params.strict = flag
198
+ return
199
+ case 'color':
200
+ params.color = flag
201
+ return
177
202
  case 'x': case 'context':
178
203
  arg = match[4] || argv[++i]
179
204
  if (Number.isNaN(+arg)) {
@@ -217,6 +242,12 @@ for (let i = 2, l = argv.length; i < l; ++i) {
217
242
  case 'trim-trailing-commas':
218
243
  params.trimTrailingCommas = flag
219
244
  return
245
+ case 'compact-empty-objects':
246
+ params.compactEmptyObjects = flag
247
+ return
248
+ case 'force-crlf':
249
+ params.forceCrlf = flag
250
+ return
220
251
  case 'succeed-with-no-files':
221
252
  params.succeedWithNoFiles = flag
222
253
  return
@@ -257,6 +288,8 @@ const paramNames = {
257
288
  'enforce-double-quotes': 'enforceDoubleQuotes',
258
289
  'enforce-single-quotes': 'enforceSingleQuotes',
259
290
  'trim-trailing-commas': 'trimTrailingCommas',
291
+ 'compact-empty-objects': 'compactEmptyObjects',
292
+ 'force-crlf': 'forceCrlf',
260
293
  'sort-keys': 'sortKeys',
261
294
  'sort-keys-ignore-case': 'sortKeysIgnoreCase',
262
295
  'sort-keys-locale': 'sortKeysLocale',
@@ -346,6 +379,7 @@ function processContents (source, file) {
346
379
  }
347
380
  })
348
381
  parserOptions.environment = params.environment
382
+ parserOptions.strict = params.strict
349
383
  try {
350
384
  validate = compile(schemas, parserOptions)
351
385
  } catch (error) {
@@ -365,7 +399,9 @@ function processContents (source, file) {
365
399
  stripObjectKeys: params.stripObjectKeys,
366
400
  enforceDoubleQuotes: params.enforceDoubleQuotes,
367
401
  enforceSingleQuotes: params.enforceSingleQuotes,
368
- trimTrailingCommas: params.trimTrailingCommas
402
+ trimTrailingCommas: params.trimTrailingCommas,
403
+ compactEmptyObjects: params.compactEmptyObjects,
404
+ forceCrlf: params.forceCrlf
369
405
  })
370
406
  }
371
407
  const sortOptions = {}
@@ -433,11 +469,41 @@ function ensureLineBreak (parsed, source) {
433
469
  const newLine = !lines[lines.length - 1]
434
470
  if (params.trailingNewline === true ||
435
471
  (params.trailingNewline !== false && newLine)) {
436
- parsed += '\n'
472
+ parsed += params.forceCrlf === true ? "\r\n" : "\n"
437
473
  }
438
474
  return parsed
439
475
  }
440
476
 
477
+ function printDiff (diff) {
478
+ const { env } = process
479
+ const isColorSupported =
480
+ !(env.NO_COLOR || params.color === false || env.CI || env.TERM === 'dumb') &&
481
+ (env.FORCE_COLOR || params.color === true || process.platform === "win32" || process.stdout.isTTY)
482
+ if (isColorSupported) {
483
+ const lines = diff.split(/\r?\n/)
484
+ for (const line of lines) {
485
+ if (/^@@ +-\d+,\d+ +\+\d+,\d+ +@@/.test(line) ||
486
+ /^@@ +-\d+ +\+\d+,\d+ +@@/.test(line) ||
487
+ /^@@ +-\d+,\d+ +\+\d+ +@@/.test(line) ||
488
+ /^@@ +-\d+ +\+\d+ +@@/.test(line)) {
489
+ console.log(pico.blue(line)) // meta
490
+ } else if (/={3,}/.test(line) ||
491
+ /^-{3}/.test(line) ||
492
+ /^\+{3}/.test(line)) {
493
+ console.log(pico.gray(line)) // comment
494
+ } else if (/^\+/.test(line)) {
495
+ console.log(pico.green(line)) // addition
496
+ } else if (/^-/.test(line)) {
497
+ console.log(pico.red(line)) // deletion
498
+ } else {
499
+ console.log(line)
500
+ }
501
+ }
502
+ } else {
503
+ console.log(diff)
504
+ }
505
+ }
506
+
441
507
  function checkContents (file, source, parsed) {
442
508
  const { createTwoFilesPatch, structuredPatch } = require('diff')
443
509
  const structured = structuredPatch(`${file}.orig`, file, source, parsed, '', '', { context: params.context })
@@ -454,7 +520,7 @@ function checkContents (file, source, parsed) {
454
520
  }
455
521
  if (!params.quiet) {
456
522
  const diff = createTwoFilesPatch(`${file}.orig`, file, source, parsed, '', '', { context: params.context })
457
- console.log(diff)
523
+ printDiff(diff)
458
524
  }
459
525
  if (params.continue) {
460
526
  process.exitCode = 1
@@ -522,22 +588,26 @@ function processFile (file) {
522
588
  }
523
589
  }
524
590
 
525
- function processSource (src, checkExtension) {
591
+ function processSource (path, isFile, isDirectory, checkExtension) {
526
592
  try {
527
- const srcStat = statSync(src)
528
- if (srcStat.isFile()) {
593
+ if (isFile) {
529
594
  if (checkExtension) {
530
- const ext = extname(src)
595
+ const ext = extname(path)
531
596
  if (extensions.indexOf(ext) < 0) {
532
597
  return
533
598
  }
534
599
  }
535
- processFile(src)
536
- } else if (srcStat.isDirectory()) {
537
- const sources = readdirSync(src)
600
+ processFile(path)
601
+ } else if (isDirectory) {
602
+ const sources = readdirSync(path, { withFileTypes: true })
538
603
  for (const source of sources) {
539
- processSource(join(src, source), true)
604
+ const subpath = join(path, source.name)
605
+ const isFile = source.isFile()
606
+ const isDirectory = source.isDirectory()
607
+ processSource(subpath, isFile, isDirectory, false)
540
608
  }
609
+ } else {
610
+ console.warn('WARN', 'Not a file or directory:', path)
541
611
  }
542
612
  } catch ({ message }) {
543
613
  console.warn('WARN', message)
@@ -545,31 +615,32 @@ function processSource (src, checkExtension) {
545
615
  }
546
616
 
547
617
  function processPatterns (patterns) {
548
- const files = sync(patterns, { onlyFiles: true })
549
- if (!files.length) {
550
- console.error('no files found')
618
+ const include = []
619
+ const exclude = []
620
+ for (const pattern of patterns) {
621
+ if (pattern.startsWith('!')) {
622
+ exclude.push(pattern.slice(1))
623
+ } else {
624
+ include.push(pattern)
625
+ }
626
+ }
627
+ const sources = globSync(include, { exclude, withFileTypes: true })
628
+ if (!sources.length) {
629
+ console.error('no files or directories found for the input patterns')
551
630
  process.exit(params.succeedWithNoFiles ? 0 : 1)
552
631
  }
553
- for (const file of files) {
554
- try {
555
- processFile(file)
556
- } catch ({ message }) {
557
- console.warn('WARN', message)
558
- }
632
+ for (const source of sources) {
633
+ const path = join(source.parentPath, source.name)
634
+ const isFile = source.isFile()
635
+ const isDirectory = source.isDirectory()
636
+ processSource(path, isFile, isDirectory, false)
559
637
  }
560
638
  }
561
639
 
562
640
  function main () {
563
641
  const files = args.length && args || params.patterns || []
564
642
  if (files.length) {
565
- const dynamic = files.some(file => isDynamicPattern(file))
566
- if (dynamic) {
567
- processPatterns(files)
568
- } else {
569
- for (const file of files) {
570
- processSource(file, false)
571
- }
572
- }
643
+ processPatterns(files)
573
644
  } else {
574
645
  let source = ''
575
646
  const stdin = process.openStdin()
package/lib/index.d.ts CHANGED
@@ -425,6 +425,13 @@ declare module '@prantlf/jsonlint/lib/validator' {
425
425
  * 'json-type-definition' | 'jtd' | 'rfc8927'`
426
426
  */
427
427
  environment?: Environment
428
+
429
+ /**
430
+ * Enable or disable the strict schema validation mode.
431
+ *
432
+ * The default is `true`. You may need to set it to `false` to ignore some schema extensions.
433
+ */
434
+ strict?: boolean
428
435
  }
429
436
 
430
437
  /**
@@ -499,6 +506,16 @@ declare module '@prantlf/jsonlint/lib/printer' {
499
506
  * Remove trailing commas after the last item in objects and arrays.
500
507
  */
501
508
  trimTrailingCommas?: boolean
509
+
510
+ /**
511
+ * If set to `false`, will insert a line break between empty `{}` and `[]`.
512
+ */
513
+ compactEmptyObjects?: boolean
514
+
515
+ /**
516
+ * Make sure all line breaks are CRLF.
517
+ */
518
+ forceCrlf?: boolean
502
519
  }
503
520
 
504
521
  /**
package/lib/jsonlint.js CHANGED
@@ -9,7 +9,7 @@
9
9
  // This is autogenerated with esprima tools, see:
10
10
  // https://github.com/ariya/esprima/blob/master/esprima.js
11
11
 
12
- // eslint-disable-next-line no-unused-vars
12
+ // biome-ignore lint/correctness/noUnusedVariables: generated code
13
13
  const Uni = {
14
14
  isWhiteSpace: function isWhiteSpace (x) {
15
15
  // section 7.2, table 2
@@ -727,7 +727,7 @@ function parseInternal (input, options) {
727
727
  }
728
728
  }
729
729
 
730
- // eslint-disable-next-line no-unused-vars
730
+ // biome-ignore lint/correctness/noUnusedVariables: concatenated with other files
731
731
  function parseCustom (input, options) {
732
732
  if (typeof options === 'function') {
733
733
  options = {
@@ -739,7 +739,7 @@ function parseCustom (input, options) {
739
739
  return parseInternal(input, options)
740
740
  }
741
741
 
742
- // eslint-disable-next-line no-unused-vars
742
+ // biome-ignore lint/correctness/noUnusedVariables: concatenated with other files
743
743
  function tokenize (input, options) {
744
744
  if (!options) {
745
745
  options = {}
@@ -759,7 +759,7 @@ function escapePointerToken (token) {
759
759
  .replace(/\//g, '~1')
760
760
  }
761
761
 
762
- // eslint-disable-next-line no-unused-vars
762
+ // biome-ignore lint/correctness/noUnusedVariables: concatenated with other files
763
763
  function pathToPointer (tokens) {
764
764
  if (tokens.length === 0) {
765
765
  return ''
@@ -775,7 +775,7 @@ function unescapePointerToken (token) {
775
775
  .replace(/~0/g, '~')
776
776
  }
777
777
 
778
- // eslint-disable-next-line no-unused-vars
778
+ // biome-ignore lint/correctness/noUnusedVariables: concatenated with other files
779
779
  function pointerToPath (pointer) {
780
780
  if (pointer === '') {
781
781
  return []
@@ -881,7 +881,7 @@ function getLocationOnSpiderMonkey (input, reason) {
881
881
  if (match) {
882
882
  const line = +match[1]
883
883
  const column = +match[2]
884
- const offset = getOffset(input, line, column) // eslint-disable-line no-undef
884
+ const offset = getOffset(input, line, column)
885
885
  return {
886
886
  offset,
887
887
  line,
@@ -942,7 +942,7 @@ function improveNativeError (input, error) {
942
942
  return error
943
943
  }
944
944
 
945
- // eslint-disable-next-line no-unused-vars
945
+ // biome-ignore lint/correctness/noUnusedVariables: concatenated with other files
946
946
  function parseNative (input, reviver) {
947
947
  try {
948
948
  return JSON.parse(input, reviver)
@@ -974,7 +974,7 @@ function getReviver (options) {
974
974
  }
975
975
  }
976
976
 
977
- // eslint-disable-next-line no-unused-vars
977
+ // biome-ignore lint/correctness/noUnusedVariables: concatenated with other files
978
978
  function parse (input, options) {
979
979
  options || (options = {})
980
980
  return needsCustomParser(options)
package/lib/printer.js CHANGED
@@ -48,6 +48,8 @@
48
48
  const enforceDoubleQuotes = options.enforceDoubleQuotes
49
49
  const enforceSingleQuotes = options.enforceSingleQuotes
50
50
  const trimTrailingCommas = options.trimTrailingCommas
51
+ const compactEmptyObjects = options.compactEmptyObjects !== false
52
+ const newLineChar = options.forceCrlf === true ? "\r\n" : "\n"
51
53
 
52
54
  let outputString = ''
53
55
  let foundLineBreak
@@ -90,7 +92,7 @@
90
92
  let addDelayedSpaceOrLineBreak
91
93
  if (prettyPrint) {
92
94
  addLineBreak = function () {
93
- outputString += '\n'
95
+ outputString += newLineChar
94
96
  }
95
97
 
96
98
  addDelayedSpaceOrLineBreak = function () {
@@ -206,7 +208,7 @@
206
208
  if (enforceDoubleQuotes && tokenContent[0] !== '"') {
207
209
  outputString += JSON.stringify(tokenValue)
208
210
  } else if (enforceSingleQuotes && tokenContent[0] !== '\'') {
209
- outputString += `\'${tokenValue.replace(/'/g, '\\\'')}\'`
211
+ outputString += `'${tokenValue.replace(/'/g, '\\\'')}'`
210
212
  } else {
211
213
  outputString += tokenContent
212
214
  }
@@ -216,6 +218,8 @@
216
218
  tryAddingInlineComment()
217
219
  }
218
220
 
221
+ let justOpenedScope
222
+
219
223
  function openScope () {
220
224
  addDelayedSpaceOrLineBreak()
221
225
  scopes.push(scopeType)
@@ -224,15 +228,17 @@
224
228
  outputString += tokenContent
225
229
  tryAddingInlineComment()
226
230
  ++indentLevel
227
- needsLineBreak = true
231
+ needsLineBreak = justOpenedScope = true
228
232
  }
229
233
 
230
234
  function closeScope () {
231
235
  scopeType = scopes.pop()
232
- addLineBreak()
233
236
  --indentLevel
234
- addIndent()
235
- needsSpace = needsLineBreak = false
237
+ if (!compactEmptyObjects || !justOpenedScope) {
238
+ addLineBreak()
239
+ addIndent()
240
+ }
241
+ needsSpace = needsLineBreak = justOpenedScope = false
236
242
  outputString += tokenContent
237
243
  tryAddingInlineComment()
238
244
  }
@@ -278,11 +284,11 @@
278
284
  case '{':
279
285
  case '[':
280
286
  openScope()
281
- break
287
+ continue
282
288
  case '}':
283
289
  case ']':
284
290
  closeScope()
285
- break
291
+ continue
286
292
  case ',':
287
293
  addComma()
288
294
  break
@@ -292,7 +298,9 @@
292
298
  break
293
299
  default: // whitespace
294
300
  foundLineBreak = tokenContent.indexOf('\n') >= 0
301
+ continue
295
302
  }
303
+ justOpenedScope = false
296
304
  }
297
305
 
298
306
  return outputString
package/lib/validator.js CHANGED
@@ -7,7 +7,10 @@
7
7
  AjvJTD: 'ajv/dist/jtd',
8
8
  Ajv2019: 'ajv/dist/2019',
9
9
  Ajv2020: 'ajv/dist/2020',
10
- Schema06: 'ajv/dist/refs/json-schema-draft-06.json'
10
+ Schema06: 'ajv/dist/refs/json-schema-draft-06.json',
11
+ Keywords: 'ajv-keywords',
12
+ Formats: 'ajv-formats',
13
+ Formats2019: 'ajv-formats-draft2019'
11
14
  }
12
15
  const requireAjv = name => {
13
16
  const exported = require(ajv[name])
@@ -101,27 +104,38 @@
101
104
  return error
102
105
  }
103
106
 
104
- function createAjv (environment) {
107
+ function createAjv (environment, ajvOptions) {
105
108
  let ajv
106
109
  if (!environment || environment === 'json-schema-draft-06' || environment === 'draft-06') {
107
110
  const Ajv = requireAjv('Ajv07')
108
- ajv = new Ajv()
111
+ ajv = new Ajv(ajvOptions)
109
112
  ajv.addMetaSchema(requireAjv('Schema06'))
113
+ requireAjv('Formats')(ajv)
114
+ requireAjv('Keywords')(ajv)
110
115
  } else if (environment === 'json-schema-draft-07' || environment === 'draft-07') {
111
116
  const Ajv = requireAjv('Ajv07')
112
- ajv = new Ajv()
117
+ ajv = new Ajv(ajvOptions)
118
+ requireAjv('Formats')(ajv)
119
+ requireAjv('Formats2019')(ajv)
120
+ requireAjv('Keywords')(ajv)
113
121
  } else if (environment === 'json-schema-draft-04' || environment === 'draft-04') {
114
122
  const Ajv = requireAjv('Ajv04')
115
- ajv = new Ajv()
123
+ ajv = new Ajv(ajvOptions)
116
124
  } else if (environment === 'json-schema-draft-2019-09' || environment === 'draft-2019-09') {
117
125
  const Ajv = requireAjv('Ajv2019')
118
- ajv = new Ajv()
126
+ ajv = new Ajv(ajvOptions)
127
+ requireAjv('Formats')(ajv)
128
+ requireAjv('Formats2019')(ajv)
129
+ requireAjv('Keywords')(ajv)
119
130
  } else if (environment === 'json-schema-draft-2020-12' || environment === 'draft-2020-12') {
120
131
  const Ajv = requireAjv('Ajv2020')
121
- ajv = new Ajv()
132
+ ajv = new Ajv(ajvOptions)
133
+ requireAjv('Formats')(ajv)
134
+ requireAjv('Formats2019')(ajv)
135
+ requireAjv('Keywords')(ajv)
122
136
  } else if (environment === 'json-type-definition' || environment === 'jtd' || environment === 'rfc8927') {
123
137
  const Ajv = requireAjv('AjvJTD')
124
- ajv = new Ajv()
138
+ ajv = new Ajv(ajvOptions)
125
139
  } else {
126
140
  throw new RangeError(`Unsupported environment for the JSON Schema validation: "${environment}".`)
127
141
  }
@@ -160,7 +174,11 @@
160
174
  options = environment
161
175
  environment = options.environment
162
176
  }
163
- const ajv = createAjv(environment)
177
+ const ajvOptions = {}
178
+ if (options.strict === false) {
179
+ ajvOptions.strict = false
180
+ }
181
+ const ajv = createAjv(environment, ajvOptions)
164
182
  const parseOptions = {
165
183
  mode: options.mode,
166
184
  ignoreBOM: options.ignoreBOM,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prantlf/jsonlint",
3
- "version": "16.0.0",
3
+ "version": "17.0.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": [
@@ -36,7 +36,7 @@
36
36
  "web"
37
37
  ],
38
38
  "engines": {
39
- "node": ">=16.9"
39
+ "node": ">=22.2"
40
40
  },
41
41
  "scripts": {
42
42
  "build": "npm run compile:jsonlint && rollup -c && npm run minify && npm run compile:tests",
@@ -58,28 +58,31 @@
58
58
  "dependencies": {
59
59
  "ajv": "8.17.1",
60
60
  "ajv-draft-04": "1.0.0",
61
+ "ajv-formats": "^3.0.1",
62
+ "ajv-formats-draft2019": "^1.6.1",
63
+ "ajv-keywords": "^5.1.0",
61
64
  "cosmiconfig": "9.0.0",
62
- "diff": "5.2.0",
63
- "fast-glob": "3.3.2"
65
+ "diff": "8.0.2",
66
+ "picocolors": "^1.1.1"
64
67
  },
65
68
  "devDependencies": {
66
- "@biomejs/biome": "^1.8.3",
67
- "@rollup/plugin-commonjs": "26.0.1",
69
+ "@biomejs/biome": "^2.3.11",
70
+ "@rollup/plugin-commonjs": "29.0.0",
68
71
  "@rollup/plugin-json": "6.1.0",
69
- "@rollup/plugin-node-resolve": "15.2.3",
70
- "@types/node": "22.2.0",
72
+ "@rollup/plugin-node-resolve": "16.0.3",
73
+ "@types/node": "25.0.3",
71
74
  "@unixcompat/cat.js": "2.0.0",
72
75
  "@unixcompat/mv.js": "2.0.0",
73
- "c8": "10.1.2",
74
- "esbuild": "0.23.0",
76
+ "c8": "10.1.3",
77
+ "esbuild": "0.27.2",
75
78
  "http-server": "14.1.1",
76
- "js-yaml": "4.1.0",
77
- "rollup": "4.20.0",
78
- "rollup-plugin-swc-minify": "1.1.2",
79
+ "js-yaml": "4.1.1",
80
+ "rollup": "4.54.0",
81
+ "rollup-plugin-swc-minify": "1.3.0",
79
82
  "tehanu": "1.0.1",
80
83
  "tehanu-repo-coco": "1.0.1",
81
84
  "tehanu-teru": "1.0.1",
82
- "typescript": "5.5.4"
85
+ "typescript": "5.9.3"
83
86
  },
84
87
  "keywords": [
85
88
  "json",