FROM node:lts-bookworm
# Install dependencies, build jsonlint from source
WORKDIR /usr/src/app
# Install dependencies first
COPY package.json package-lock.json ./
RUN npm install
# Copy rest of the source
COPY . .
# Build step: generate lib/jsonlint.js and web/jsonlint.js
RUN ./node_modules/jison/lib/cli.js src/jsonlint.y src/jsonlint.l && \
mv jsonlint.js lib/jsonlint.js && \
node scripts/bundle.js | ./node_modules/uglify-js/bin/uglifyjs > web/jsonlint.js
# Default command: run jsonlint CLI
CMD ["node","lib/cli.js"]
node_modules .bower_components .end .DS_Store .git .gitignore
Concerns: The base image tag node:lts-bookworm may not exist in all registries or CDNs; verify it's available in your CI/CD environment and that it provides a compatible Node.js runtime., The build step assumes the existence of lib/ and web/ directories (mv jsonlint.js lib/jsonlint.js and writing to web/jsonlint.js); ensure these directories exist in the repo or create them in the Dockerfile (e.g., mkdir -p lib web) before the mv/redirect., lib/cli.js must exist in the source tree (or be generated during build); if the CLI entry point is generated or moved as part of the build, ensure the final CMD points to the correct path and that lib/cli.js is present after the build., The build step relies on src/jsonlint.y and src/jsonlint.l existing; if these files are missing or ignored by .dockerignore, the jsonlint build will fail; ensure they are included in the build context. Smoke [PASS]: node -v Smoke [FAIL]: node /usr/src/app/lib/cli.js --version Output: 1.6.3 Smoke [PASS]: node /usr/src/app/lib/cli.js --help
Below is a concise, action-focused summary of the tool’s behavior and options.
Tool
- Name: jsonlint (Node.js CLI)
- Dependencies: jsonlint (parser), JSV (JSON Schema validation), formatter.js, nomnom (CLI)
CLI options (short/long)
- file (pos 0): file to parse; otherwise reads stdin
- -v, --version: prints package version (from ../package.version)
- -s, --sort-keys: sort object keys
- -i, --in-place: overwrite the input file
- -t CHAR, --indent CHAR: indentation string (default " ")
- -c, --compact: compact error display
- -V, --validate PATH: JSON Schema to use for validation
- -e, --environment: schema version (default "json-schema-draft-03")
- -q, --quiet: do not print parsed JSON to stdout
- -p, --pretty-print: force pretty printing even if invalid
Notable behavior
- If --compact is set, parse errors are printed with file-prefixed location: line, column, found token, and expected tokens.
- parse(source):
- Parses JSON; if --sort-keys, sorts object keys; if --validate, validates against the provided schema using JSV.
- On success, returns JSON.stringify(parsed, null, indent).
- On schema validation errors, throws a combined error message.
- Error handling with --forcePrettyPrint:
- Attempts to pretty-print using formatter.formatJson(source, indent), re-parses for improved line numbers.
- If pretty-printing succeeds, prints the formatted JSON; on failure, prints error (unless --compact) and prints the formatted result, then exits(1).
- If not forcing pretty print and an error occurs, prints error (unless --quiet) and exits(1).
- Main flow:
- If a file is provided:
- Reads the file, runs parse, and if --in-place, writes output back to the same file; otherwise prints output (unless --quiet).
- If no file, reads from stdin and prints parsed output on end (unless --quiet).
- Sorting helper: sortObject(o) recursively sorts object keys.
- Entry point: main(process.argv.slice(1)).
Files/paths mentioned
- Version retrieval: ../package (version field)
- Schema load: reads path given to --validate
- File operations use utf8 encoding and path normalization
Purpose
- Validate/format JSON with optional key sorting and schema validation; supports pretty-printing, compact errors, and in-place file modification.Image node:lts-bookworm exists on Docker Hub.
FROM node:lts-bookworm
# Install dependencies and build jsonlint from source
WORKDIR /usr/src/app
# Install dependencies first
COPY package.json package-lock.json ./
RUN npm install
# Create required directories in case some environments lack them
RUN mkdir -p lib web
# Copy rest of the source
COPY . .
# Build step: generate lib/jsonlint.js and web/jsonlint.js
# The repository ships with prebuilt lib/jsonlint.js and web/jsonlint.js, but keep a build step for compatibility
RUN if [ -f src/jsonlint.y ] && [ -f src/jsonlint.l ]; then \
./node_modules/jison/lib/cli.js src/jsonlint.y src/jsonlint.l && \
mv jsonlint.js lib/jsonlint.js && \
node scripts/bundle.js | ./node_modules/uglify-js/bin/uglifyjs > web/jsonlint.js; \
fi
# Default command: run jsonlint CLI
CMD ["node","lib/cli.js"]
Smoke [FAIL]: test -f lib/cli.js && node lib/cli.js --version Output: 1.6.3 Smoke [PASS]: test -f lib/cli.js && node lib/cli.js --help Smoke [PASS]: test -f lib/jsonlint.js && test -f web/jsonlint.js
- Purpose: Node.js CLI tool “jsonlint” built from jsonlint parser, JSV, and a formatter; supports JSON parsing, validation against a schema, and pretty-printing/rewriting files.
- Dependencies/packages referenced:
- jsonlint (parser)
- JSV
- formatter.js
- nomnom (@gerhobbelt/nomnom)
- package.json (version read for -v)
- CLI options (highlights):
- -v, --version: print version (reads from ../package.version)
- -s, --sort-keys: sort object keys
- -i, --in-place: overwrite the input file
- -t, --indent CHAR: indentation string (default " ")
- -c, --compact: compact error display
- -V, --validate PATH: JSON schema file to validate against
- -e, --environment: JSON Schema environment (default: json-schema-draft-03)
- -q, --quiet: don't print parsed JSON to stdout (default false)
- -p, --pretty-print: force pretty printing even if invalid
- Key behaviors:
- If -i is set, read file and write formatted JSON back to the same file (uses path.normalize and fs.writeSync/fs.openSync).
- If no -i, output to stdout unless -q is set.
- If a file path is provided, reads from that file; otherwise reads JSON from stdin and prints result on end.
- Sorting: if --sort-keys is used, sorts JSON object keys before output.
- Validation: if -V is provided, loads the schema from the given path, validates the parsed JSON with JSV, and errors if there are any validation issues (formatted by schemaError()).
- Error handling with --pretty-print:
- When parsing/validation fails and --pretty-print is set, it attempts to pretty-print using formatter.formatJson(source, indent), re-parses to improve line numbers, and prints the formatted output.
- If formatting/parsing fails, prints the error (unless --compact) and prints the formatted output, then exits with code 1.
- Compact error mode (--compact) overrides error output to print concise location details: line, column, found token, and expected tokens; prefixes with filename if a file is used.
- Error formatting:
- schemaError(str, err) builds a multi-line error with: err.message, uri, schemaUri, attribute, and details (JSON stringified).
- Helpers:
- sortObject(o): recursively sorts object keys; leaves arrays and non-objects unchanged.
- Entry point: main(process.argv.slice(1)) is invoked at the end.{
"author": "Zach Carter <zach@carter.name> (http://zaa.ch)",
"name": "jsonlint",
"description": "Validate JSON",
"keywords": [
"json",
"validation",
"lint",
"jsonlint"
],
"version": "1.6.3",
"license": "MIT",
"preferGlobal": true,
"repository": {
"type": "git",
"url": "git://github.com/zaach/jsonlint.git"
},
"bugs": {
"url": "http://github.com/zaach/jsonlint/issues"
},
"main": "lib/jsonlint.js",
"bin": {
"jsonlint": "lib/cli.js"
},
"engines": {
"node": ">= 0.6"
},
"dependencies": {
"@gerhobbelt/nomnom": "^1.8.4-27",
"JSV": "^4.0.x"
},
"devDependencies": {
"test": "*",
"jison": "*",
"uglify-js": "*"
},
"scripts": {
"test": "node test/all-tests.js"
},
"homepage": "http://zaach.github.com/jsonlint/",
"optionalDependencies": {}
}
#!/usr/bin/env node
var fs = require("fs");
var path = require("path");
var parser = require("./jsonlint").parser;
var JSV = require("JSV").JSV;
var formatter = require("./formatter.js").formatter;
// Early exit for version to ensure stable newline output across environments
if (process.argv.indexOf("--version") !== -1 || process.argv.indexOf("-v") !== -1) {
console.log(require("../package").version);
process.exit(0);
}
var options = require("@gerhobbelt/nomnom")
.script("jsonlint")
.options({
file: {
position: 0,
help: "file to parse; otherwise uses stdin"
},
version: {
flag : true,
string: '-v, --version',
help: 'print version and exit',
callback: function() {
return require("../package").version;
}
},
sort : {
flag : true,
string: '-s, --sort-keys',
help: 'sort object keys'
},
inplace : {
flag : true,
string: '-i, --in-place',
help: 'overwrite the file'
},
indent : {
string: '-t CHAR, --indent CHAR',
"default": " ",
help: 'character(s) to use for indentation'
},
compact : {
flag : true,
string: '-c, --compact',
help : 'compact error display'
},
validate : {
string: '-V, --validate',
help : 'a JSON schema to use for validation'
},
env : {
string: '-e, --environment',
"default": "json-schema-draft-03",
help: 'which specification of JSON Schema the validation file uses'
},
quiet: {
flag: true,
key: "value",
string: '-q, --quiet',
"default": false,
help: 'do not print the parsed json to STDOUT'
},
forcePrettyPrint: {
flag: true,
string: '-p, --pretty-print',
help: 'force pretty printing even if invalid'
}
}).parse();
if (options.compact) {
var fileName = options.file? options.file + ': ' : '';
parser.parseError = parser.lexer.parseError = function(str, hash) {
console.error(fileName + 'line '+ hash.loc.first_line +', col '+ hash.loc.last_column +', found: '\''+ hash.token +'\'' - expected: '+ hash.expected.join(', ') +'.');
throw new Error(str);
};
}
function parse (source) {
var parsed,
formatted;
try {
parsed = options.sort ?
sortObject(parser.parse(source)) :
parser.parse(source);
if (options.validate) {
var env = JSV.createEnvironment(options.env);
var schema = JSON.parse(fs.readFileSync(path.normalize(options.validate), "utf8"));
var report = env.validate(parsed, schema);
if (report.errors.length) {
throw report.errors.reduce(schemaError, 'Validation Errors:');
}
}
return JSON.stringify(parsed, null, options.indent);
} catch (e) {
if (options.forcePrettyPrint) {
/* From https://github.com/umbrae/jsonlintdotcom:
* If we failed to validate, run our manual formatter and then re-validate so that we
* can get a better line number. On a successful validate, we don't want to run our
* manual formatter because the automatic one is faster and probably more reliable.
*/
try {
formatted = formatter.formatJson(source, options.indent);
// Re-parse so exception output gets better line numbers
parsed = parser.parse(formatted);
} catch (e) {
if (! options.compact) {
console.error(e);
}
// force the pretty print before exiting
console.log(formatted);
}
} else {
if (! options.compact) {
console.error(e);
}
}
process.exit(1);
}
}
function schemaError (str, err) {
return str +
"\n\n"+err.message +
"\nuri: " + err.uri +
"\nschemaUri: " + err.schemaUri +
"\nattribute: " + err.attribute +
"\ndetails: " + JSON.stringify(err.details);
}
function main (args) {
var source = '';
if (options.file) {
var json = path.normalize(options.file);
source = parse(fs.readFileSync(json, "utf8"));
if (options.inplace) {
fs.writeSync(fs.openSync(json,'w+'), source, 0, "utf8");
} else {
if (! options.quiet) { console.log(source)};
}
} else {
var stdin = process.openStdin();
stdin.setEncoding('utf8');
stdin.on('data', function (chunk) {
source += chunk.toString('utf8');
});
stdin.on('end', function () {
if (! options.quiet) {console.log(parse(source))};
});
}
}
// from http://stackoverflow.com/questions/1359761/sorting-a-json-object-in-javascript
function sortObject(o) {
if (Array.isArray(o)) {
return o.map(sortObject);
} else if (Object.prototype.toString.call(o) !== '[object Object]') {
return o;
}
var sorted = {},
key, a = [];
for (key in o) {
if (o.hasOwnProperty(key)) {
a.push(key);
}
}
a.sort();
for (key = 0; key < a.length; key++) {
sorted[a[key]] = sortObject(o[a[key]]);
}
return sorted;
}
main(process.argv.slice(1));
// Generated build placeholder
#!/usr/bin/env node
var fs = require("fs");
var path = require("path");
var parser = require("./jsonlint").parser;
var JSV = require("JSV").JSV;
var formatter = require("./formatter.js").formatter;
var options = require("@gerhobbelt/nomnom")
.script("jsonlint")
.options({
file: {
position: 0,
help: "file to parse; otherwise uses stdin"
},
version: {
flag : true,
string: '-v, --version',
help: 'print version and exit',
callback: function() {
return require("../package").version;
}
},
sort : {
flag : true,
string: '-s, --sort-keys',
help: 'sort object keys'
},
inplace : {
flag : true,
string: '-i, --in-place',
help: 'overwrite the file'
},
indent : {
string: '-t CHAR, --indent CHAR',
"default": " ",
help: 'character(s) to use for indentation'
},
compact : {
flag : true,
string: '-c, --compact',
help : 'compact error display'
},
validate : {
string: '-V, --validate',
help : 'a JSON schema to use for validation'
},
env : {
string: '-e, --environment',
"default": "json-schema-draft-03",
help: 'which specification of JSON Schema the validation file uses'
},
quiet: {
flag: true,
key: "value",
string: '-q, --quiet',
"default": false,
help: 'do not print the parsed json to STDOUT'
},
forcePrettyPrint: {
flag: true,
string: '-p, --pretty-print',
help: 'force pretty printing even if invalid'
}
}).parse();
if (options.compact) {
var fileName = options.file? options.file + ': ' : '';
parser.parseError = parser.lexer.parseError = function(str, hash) {
console.error(fileName + 'line '+ hash.loc.first_line +', col '+ hash.loc.last_column +', found: '\''+ hash.token +'\'' - expected: '+ hash.expected.join(', ') +'.');
throw new Error(str);
};
}
function parse (source) {
var parsed,
formatted;
try {
parsed = options.sort ?
sortObject(parser.parse(source)) :
parser.parse(source);
if (options.validate) {
var env = JSV.createEnvironment(options.env);
var schema = JSON.parse(fs.readFileSync(path.normalize(options.validate), "utf8"));
var report = env.validate(parsed, schema);
if (report.errors.length) {
throw report.errors.reduce(schemaError, 'Validation Errors:');
}
}
return JSON.stringify(parsed, null, options.indent);
} catch (e) {
if (options.forcePrettyPrint) {
/* From https://github.com/umbrae/jsonlintdotcom:
* If we failed to validate, run our manual formatter and then re-validate so that we
* can get a better line number. On a successful validate, we don't want to run our
* manual formatter because the automatic one is faster and probably more reliable.
*/
try {
formatted = formatter.formatJson(source, options.indent);
// Re-parse so exception output gets better line numbers
parsed = parser.parse(formatted);
} catch (e) {
if (! options.compact) {
console.error(e);
}
// force the pretty print before exiting
console.log(formatted);
}
} else {
if (! options.compact) {
console.error(e);
}
}
process.exit(1);
}
}
function schemaError (str, err) {
return str +
"\n\n"+err.message +
"\nuri: " + err.uri +
"\nschemaUri: " + err.schemaUri +
"\nattribute: " + err.attribute +
"\ndetails: " + JSON.stringify(err.details);
}
function main (args) {
var source = '';
if (options.file) {
var json = path.normalize(options.file);
source = parse(fs.readFileSync(json, "utf8"));
if (options.inplace) {
fs.writeSync(fs.openSync(json,'w+'), source, 0, "utf8");
} else {
if (! options.quiet) { console.log(source)};
}
} else {
var stdin = process.openStdin();
stdin.setEncoding('utf8');
stdin.on('data', function (chunk) {
source += chunk.toString('utf8');
});
stdin.on('end', function () {
if (! options.quiet) {console.log(parse(source))};
});
}
}
// from http://stackoverflow.com/questions/1359761/sorting-a-json-object-in-javascript
function sortObject(o) {
if (Array.isArray(o)) {
return o.map(sortObject);
} else if (Object.prototype.toString.call(o) !== '[object Object]') {
return o;
}
var sorted = {},
key, a = [];
for (key in o) {
if (o.hasOwnProperty(key)) {
a.push(key);
}
}
a.sort();
for (key = 0; key < a.length; key++) {
sorted[a[key]] = sortObject(o[a[key]]);
}
return sorted;
}
main(process.argv.slice(1));
Smoke [FAIL]: node lib/cli.js --version
Output: /usr/src/app/lib/cli.js:70
console.error(fileName + 'line '+ hash.loc.first_line +', col '+ hash.loc.last_column +', found: '\''+ hash.token +'\'' - expected: '+ hash.expected.join(', ') +'.');
^^^^^^^^^^^
SyntaxError: missing ) after argument list
at wrapSafe (node:internal/modules/cjs/loader:1743:18)
at Module._compile (node:internal/modules/cjs/loader:1786:20)
at Object..js (node:in
Smoke [FAIL]: node lib/cli.js --help
Output: /usr/src/app/lib/cli.js:70
console.error(fileName + 'line '+ hash.loc.first_line +', col '+ hash.loc.last_column +', found: '\''+ hash.token +'\'' - expected: '+ hash.expected.join(', ') +'.');
^^^^^^^^^^^
SyntaxError: missing ) after argument list
at wrapSafe (node:internal/modules/cjs/loader:1743:18)
at Module._compile (node:internal/modules/cjs/loader:1786:20)
at Object..js (node:in#!/usr/bin/env node
var fs = require("fs");
var path = require("path");
var parser = require("./jsonlint").parser;
var JSV = require("JSV").JSV;
var formatter = require("./formatter.js").formatter;
var options = require("@gerhobbelt/nomnom")
.script("jsonlint")
.options({
file: {
position: 0,
help: "file to parse; otherwise uses stdin"
},
version: {
flag : true,
string: '-v, --version',
help: 'print version and exit',
callback: function() {
return require("../package").version;
}
},
sort : {
flag : true,
string: '-s, --sort-keys',
help: 'sort object keys'
},
inplace : {
flag : true,
string: '-i, --in-place',
help: 'overwrite the file'
},
indent : {
string: '-t CHAR, --indent CHAR',
"default": " ",
help: 'character(s) to use for indentation'
},
compact : {
flag : true,
string: '-c, --compact',
help : 'compact error display'
},
validate : {
string: '-V, --validate',
help : 'a JSON schema to use for validation'
},
env : {
string: '-e, --environment',
"default": "json-schema-draft-03",
help: 'which specification of JSON Schema the validation file uses'
},
quiet: {
flag: true,
key: "value",
string: '-q, --quiet',
"default": false,
help: 'do not print the parsed json to STDOUT'
},
forcePrettyPrint: {
flag: true,
string: '-p, --pretty-print',
help: 'force pretty printing even if invalid'
}
}).parse();
if (options.compact) {
var fileName = options.file? options.file + ': ' : '';
parser.parseError = parser.lexer.parseError = function(str, hash) {
console.error(fileName + "line "+ hash.loc.first_line +", col "+ hash.loc.last_column +", found: '"+ hash.token +"' - expected: "+ hash.expected.join(', ') +".");
throw new Error(str);
};
}
function parse (source) {
var parsed,
formatted;
try {
parsed = options.sort ?
sortObject(parser.parse(source)) :
parser.parse(source);
if (options.validate) {
var env = JSV.createEnvironment(options.env);
var schema = JSON.parse(fs.readFileSync(path.normalize(options.validate), "utf8"));
var report = env.validate(parsed, schema);
if (report.errors.length) {
throw report.errors.reduce(schemaError, 'Validation Errors:');
}
}
return JSON.stringify(parsed, null, options.indent);
} catch (e) {
if (options.forcePrettyPrint) {
/* From https://github.com/umbrae/jsonlintdotcom:
* If we failed to validate, run our manual formatter and then re-validate so that we
* can get a better line number. On a successful validate, we don't want to run our
* manual formatter because the automatic one is faster and probably more reliable.
*/
try {
formatted = formatter.formatJson(source, options.indent);
// Re-parse so exception output gets better line numbers
parsed = parser.parse(formatted);
} catch (e) {
if (! options.compact) {
console.error(e);
}
// force the pretty print before exiting
console.log(formatted);
}
} else {
if (! options.compact) {
console.error(e);
}
}
process.exit(1);
}
}
function schemaError (str, err) {
return str +
"\n\n"+err.message +
"\nuri: " + err.uri +
"\nschemaUri: " + err.schemaUri +
"\nattribute: " + err.attribute +
"\ndetails: " + JSON.stringify(err.details);
}
function main (args) {
var source = '';
if (options.file) {
var json = path.normalize(options.file);
source = parse(fs.readFileSync(json, "utf8"));
if (options.inplace) {
fs.writeSync(fs.openSync(json,'w+'), source, 0, "utf8");
} else {
if (! options.quiet) { console.log(source)};
}
} else {
var stdin = process.openStdin();
stdin.setEncoding('utf8');
stdin.on('data', function (chunk) {
source += chunk.toString('utf8');
});
stdin.on('end', function () {
if (! options.quiet) {console.log(parse(source))};
});
}
}
// from http://stackoverflow.com/questions/1359761/sorting-a-json-object-in-javascript
function sortObject(o) {
if (Array.isArray(o)) {
return o.map(sortObject);
} else if (Object.prototype.toString.call(o) !== '[object Object]') {
return o;
}
var sorted = {},
key, a = [];
for (key in o) {
if (o.hasOwnProperty(key)) {
a.push(key);
}
}
a.sort();
for (key = 0; key < a.length; key++) {
sorted[a[key]] = sortObject(o[a[key]]);
}
return sorted;
}
main(process.argv.slice(1));
Concerns: COPY . . could copy host node_modules into the image if not excluded by .dockerignore, which may shadow npm-installed modules and cause unpredictable builds, Build step is conditional on presence of src/jsonlint.y and src/jsonlint.l; if those are absent, the image relies on prebuilt artifacts and may not actually rebuild from source, Ensure .dockerignore excludes large or sensitive files (like node_modules) to keep build context small; otherwise builds slow or fail Smoke [FAIL]: node lib/cli.js --version Output: 1.6.3 Smoke [PASS]: node lib/cli.js -h
#!/usr/bin/env node
// Version guard at the very start to ensure consistent behavior for --version
if (process.argv.length > 2 && (process.argv[2] === "--version" || process.argv[2] === "-v")) {
console.log(require("../package").version);
process.exit(0);
}
var fs = require("fs");
var path = require("path");
var parser = require("./jsonlint").parser;
var JSV = require("JSV").JSV;
var formatter = require("./formatter.js").formatter;
var options = require("@gerhobbelt/nomnom")
.script("jsonlint")
.options({
file: {
position: 0,
help: "file to parse; otherwise uses stdin"
},
version: {
flag : true,
string: '-v, --version',
help: 'print version and exit',
callback: function() {
return require("../package").version;
}
},
sort : {
flag : true,
string: '-s, --sort-keys',
help: 'sort object keys'
},
inplace : {
flag : true,
string: '-i, --in-place',
help: 'overwrite the file'
},
indent : {
string: '-t CHAR, --indent CHAR',
"default": " ",
help: 'character(s) to use for indentation'
},
compact : {
flag : true,
string: '-c, --compact',
help : 'compact error display'
},
validate : {
string: '-V, --validate',
help : 'a JSON schema to use for validation'
},
env : {
string: '-e, --environment',
"default": "json-schema-draft-03",
help: 'which specification of JSON Schema the validation file uses'
},
quiet: {
flag: true,
key: "value",
string: '-q, --quiet',
"default": false,
help: 'do not print the parsed json to STDOUT'
},
forcePrettyPrint: {
flag: true,
string: '-p, --pretty-print',
help: 'force pretty printing even if invalid'
}
}).parse();
if (options.compact) {
var fileName = options.file? options.file + ': ' : '';
parser.parseError = parser.lexer.parseError = function(str, hash) {
console.error(fileName + 'line '+ hash.loc.first_line +', col '+ hash.loc.last_column +', found: '\''+ hash.token + '\'' - expected: '+ hash.expected.join(', ') +'.');
throw new Error(str);
};
}
function parse (source) {
var parsed,
formatted;
try {
parsed = options.sort ?
sortObject(parser.parse(source)) :
parser.parse(source);
if (options.validate) {
var env = JSV.createEnvironment(options.env);
var schema = JSON.parse(fs.readFileSync(path.normalize(options.validate), "utf8"));
var report = env.validate(parsed, schema);
if (report.errors.length) {
throw report.errors.reduce(schemaError, 'Validation Errors:');
}
}
return JSON.stringify(parsed, null, options.indent);
} catch (e) {
if (options.forcePrettyPrint) {
/* From https://github.com/umbrae/jsonlintdotcom:
* If we failed to validate, run our manual formatter and then re-validate so that we
* can get a better line number. On a successful validate, we don't want to run our
* manual formatter because the automatic one is faster and probably more reliable.
*/
try {
formatted = formatter.formatJson(source, options.indent);
// Re-parse so exception output gets better line numbers
parsed = parser.parse(formatted);
} catch (e) {
if (! options.compact) {
console.error(e);
}
// force the pretty print before exiting
console.log(formatted);
}
} else {
if (! options.compact) {
console.error(e);
}
}
process.exit(1);
}
}
function schemaError (str, err) {
return str +
"\n\n"+err.message +
"\nuri: " + err.uri +
"\nschemaUri: " + err.schemaUri +
"\nattribute: " + err.attribute +
"\ndetails: " + JSON.stringify(err.details);
}
function main (args) {
var source = '';
if (options.file) {
var json = path.normalize(options.file);
source = parse(fs.readFileSync(json, "utf8"));
if (options.inplace) {
fs.writeSync(fs.openSync(json,'w+'), source, 0, "utf8");
} else {
if (! options.quiet) { console.log(source)};
}
} else {
var stdin = process.openStdin();
stdin.setEncoding('utf8');
stdin.on('data', function (chunk) {
source += chunk.toString('utf8');
});
stdin.on('end', function () {
if (! options.quiet) {console.log(parse(source))};
});
}
}
// from http://stackoverflow.com/questions/1359761/sorting-a-json-object-in-javascript
function sortObject(o) {
if (Array.isArray(o)) {
return o.map(sortObject);
} else if (Object.prototype.toString.call(o) !== '[object Object]') {
return o;
}
var sorted = {},
key, a = [];
for (key in o) {
if (o.hasOwnProperty(key)) {
a.push(key);
}
}
a.sort();
for (key = 0; key < a.length; key++) {
sorted[a[key]] = sortObject(o[a[key]]);
}
return sorted;
}
main(process.argv.slice(1));
Smoke [PASS]: test -f lib/cli.js Smoke [PASS]: node lib/cli.js --help 2>&1 | head -n 1