fixjson
Version:
JSON fixer for humans using (relaxed) JSON5
177 lines • 5.98 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.fixFile = exports.fixString = void 0;
const fs = require("fs");
const JSON5R = require("json5-relaxed");
const glob = require("glob");
const detectIndent = require("detect-indent");
function readFromStdin() {
process.stdin.setEncoding('utf8');
return new Promise(resolve => {
let buf = '';
process.stdin.on('data', chunk => {
buf += chunk;
});
process.stdin.on('end', () => {
resolve(buf);
});
});
}
function readFile(path) {
return new Promise((resolve, reject) => {
fs.readFile(path, 'utf8', (err, data) => {
if (err) {
reject(err);
return;
}
resolve(data);
});
});
}
function write(writer, chunk) {
return new Promise(resolve => writer.write(chunk, 'utf8', resolve));
}
function isDirectory(path) {
return new Promise((resolve, reject) => {
fs.stat(path, (err, stat) => {
if (err) {
reject(err);
}
else {
resolve(stat.isDirectory());
}
});
});
}
function globPath(path) {
return new Promise((resolve, reject) => {
glob(path, (err, p) => (err ? reject(err) : resolve(p)));
});
}
function globOne(pattern) {
return __awaiter(this, void 0, void 0, function* () {
const globbed = yield globPath(pattern);
const paths = [];
for (const path of globbed) {
if (!(yield isDirectory(path))) {
paths.push(path);
}
let pat = path;
if (pat[pat.length - 1] !== '/') {
pat += '/';
}
pat += '**/*.json';
Array.prototype.push.apply(paths, yield globPath(pat));
}
return paths;
});
}
function globAll(pats) {
return __awaiter(this, void 0, void 0, function* () {
if (pats.length === 0) {
// shortcut
return [];
}
// flatten
const paths = [];
for (const p of yield Promise.all(pats.map(globOne))) {
Array.prototype.push.apply(paths, p);
}
return paths;
});
}
class FixJSON {
constructor(config) {
this.config = Object.assign({ write: false, minify: false, stdout: process.stdout }, config);
this.stdout = this.config.stdout || process.stdout;
}
main(argv) {
return __awaiter(this, void 0, void 0, function* () {
const stdin = argv.length === 0;
if (stdin) {
const src = yield this.parseStdin();
if (this.stdout.setEncoding) {
this.stdout.setEncoding('utf8');
}
this.stdout.write(this.unparse(src));
return 1;
}
const files = yield globAll(argv);
yield this.fixFiles(files);
return files.length;
});
}
fixFiles(paths) {
return __awaiter(this, void 0, void 0, function* () {
const parsed = Promise.all(paths.map(p => this.parseFile(p)));
if (!this.config.write && this.stdout.setEncoding) {
this.stdout.setEncoding('utf8');
}
for (const src of yield parsed) {
const writer = this.config.write ? fs.createWriteStream(src.name) : this.stdout;
yield write(writer, this.unparse(src));
}
});
}
convertString(input) {
return this.unparse({ name: '', parsed: JSON5R.parse(input), indent: this.indent(input) });
}
convertFile(path) {
return __awaiter(this, void 0, void 0, function* () {
return this.unparse(yield this.parseFile(path));
});
}
indent(code) {
const { indent, minify } = this.config;
const spaces = minify ? '' : indent ? ' '.repeat(indent) : detectIndent(code).indent;
return spaces || ' ';
}
unparse(src) {
return JSON.stringify(src.parsed, null, src.indent) + '\n';
}
parseString(code, file) {
try {
return JSON5R.parse(code);
}
catch (e) {
e.message = `${file}: ${e.message}`;
throw e;
}
}
parseStdin() {
return __awaiter(this, void 0, void 0, function* () {
const name = this.config.stdinFilename || '<stdin>';
const code = yield readFromStdin();
const parsed = this.parseString(code, name);
return { name, parsed, indent: this.indent(code) };
});
}
parseFile(path) {
return __awaiter(this, void 0, void 0, function* () {
const code = yield readFile(path);
const parsed = this.parseString(code, path);
const indent = this.indent(code);
return { name: path, parsed, indent };
});
}
}
exports.default = FixJSON;
// Helper APIs
function fixString(input, config) {
return new FixJSON(config).convertString(input);
}
exports.fixString = fixString;
function fixFile(file, config) {
return new FixJSON(config).convertFile(file);
}
exports.fixFile = fixFile;
//# sourceMappingURL=index.js.map