@expo/json-file
Version:
A module for reading, writing, and manipulating JSON files
440 lines (438 loc) • 14 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, /**
* The JsonFile class represents the contents of json file.
*
* It's polymorphic on "JSONObject", which is a simple type representing
* and object with string keys and either objects or primitive types as values.
* @type {[type]}
*/ "default", {
enumerable: true,
get: function() {
return JsonFile;
}
});
function _json5() {
const data = /*#__PURE__*/ _interop_require_default(require("json5"));
_json5 = function() {
return data;
};
return data;
}
function _nodefs() {
const data = /*#__PURE__*/ _interop_require_default(require("node:fs"));
_nodefs = function() {
return data;
};
return data;
}
function _nodepath() {
const data = /*#__PURE__*/ _interop_require_default(require("node:path"));
_nodepath = function() {
return data;
};
return data;
}
const _JsonFileError = /*#__PURE__*/ _interop_require_wildcard(require("./JsonFileError"));
const _writeAtomic = require("./writeAtomic");
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
function _getRequireWildcardCache(nodeInterop) {
if (typeof WeakMap !== "function") return null;
var cacheBabelInterop = new WeakMap();
var cacheNodeInterop = new WeakMap();
return (_getRequireWildcardCache = function(nodeInterop) {
return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
})(nodeInterop);
}
function _interop_require_wildcard(obj, nodeInterop) {
if (!nodeInterop && obj && obj.__esModule) {
return obj;
}
if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
return {
default: obj
};
}
var cache = _getRequireWildcardCache(nodeInterop);
if (cache && cache.has(obj)) {
return cache.get(obj);
}
var newObj = {
__proto__: null
};
var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
for(var key in obj){
if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
if (desc && (desc.get || desc.set)) {
Object.defineProperty(newObj, key, desc);
} else {
newObj[key] = obj[key];
}
}
}
newObj.default = obj;
if (cache) {
cache.set(obj, newObj);
}
return newObj;
}
const DEFAULT_OPTIONS = {
badJsonDefault: undefined,
jsonParseErrorDefault: undefined,
cantReadFileDefault: undefined,
ensureDir: false,
mode: undefined,
default: undefined,
json5: false,
space: 2,
addNewLineAtEOF: true
};
class JsonFile {
file;
options;
static read = read;
static readAsync = readAsync;
static parseJsonString = parseJsonString;
static write = write;
static writeAsync = writeAsync;
static get = getSync;
static getAsync = getAsync;
static set = setSync;
static setAsync = setAsync;
static merge = merge;
static mergeAsync = mergeAsync;
static deleteKey = deleteKey;
static deleteKeyAsync = deleteKeyAsync;
static deleteKeys = deleteKeys;
static deleteKeysAsync = deleteKeysAsync;
static rewrite = rewrite;
static rewriteAsync = rewriteAsync;
constructor(file, options = {}){
this.file = file;
this.options = options;
}
read(options) {
return read(this.file, this._getOptions(options));
}
async readAsync(options) {
return readAsync(this.file, this._getOptions(options));
}
write(object, options) {
return write(this.file, object, this._getOptions(options));
}
async writeAsync(object, options) {
return writeAsync(this.file, object, this._getOptions(options));
}
parseJsonString(json, options) {
return parseJsonString(json, options);
}
get(key, defaultValue, options) {
return getSync(this.file, key, defaultValue, this._getOptions(options));
}
async getAsync(key, defaultValue, options) {
return getAsync(this.file, key, defaultValue, this._getOptions(options));
}
set(key, value, options) {
return setSync(this.file, key, value, this._getOptions(options));
}
async setAsync(key, value, options) {
return setAsync(this.file, key, value, this._getOptions(options));
}
async merge(sources, options) {
return merge(this.file, sources, this._getOptions(options));
}
async mergeAsync(sources, options) {
return mergeAsync(this.file, sources, this._getOptions(options));
}
deleteKey(key, options) {
return deleteKey(this.file, key, this._getOptions(options));
}
async deleteKeyAsync(key, options) {
return deleteKeyAsync(this.file, key, this._getOptions(options));
}
deleteKeys(keys, options) {
return deleteKeys(this.file, keys, this._getOptions(options));
}
async deleteKeysAsync(keys, options) {
return deleteKeysAsync(this.file, keys, this._getOptions(options));
}
rewrite(options) {
return rewrite(this.file, this._getOptions(options));
}
async rewriteAsync(options) {
return rewriteAsync(this.file, this._getOptions(options));
}
_getOptions(options) {
return {
...this.options,
...options
};
}
}
function read(file, options) {
let json;
try {
json = _nodefs().default.readFileSync(file, 'utf8');
} catch (error) {
assertEmptyJsonString(json, file);
const defaultValue = cantReadFileDefault(options);
if (defaultValue === undefined) {
throw new _JsonFileError.default(`Can't read JSON file: ${file}`, error, error.code, file);
} else {
return defaultValue;
}
}
return parseJsonString(json, options, file);
}
async function readAsync(file, options) {
let json;
try {
json = await _nodefs().default.promises.readFile(file, 'utf8');
} catch (error) {
assertEmptyJsonString(json, file);
const defaultValue = cantReadFileDefault(options);
if (defaultValue === undefined) {
throw new _JsonFileError.default(`Can't read JSON file: ${file}`, error, error.code);
} else {
return defaultValue;
}
}
return parseJsonString(json, options);
}
function parseJsonString(json, options, fileName) {
assertEmptyJsonString(json, fileName);
try {
if (_getOption(options, 'json5')) {
return _json5().default.parse(json);
} else {
return JSON.parse(json);
}
} catch (e) {
const defaultValue = jsonParseErrorDefault(options);
if (defaultValue === undefined) {
const location = locationFromSyntaxError(e, json);
if (location) {
const { codeFrameColumns } = require('@babel/code-frame');
const codeFrame = codeFrameColumns(json, {
start: location
});
e.codeFrame = codeFrame;
e.message += `\n${codeFrame}`;
}
throw new _JsonFileError.default(`Error parsing JSON: ${json}`, e, 'EJSONPARSE', fileName);
} else {
return defaultValue;
}
}
}
function getSync(file, key, defaultValue, options) {
const object = read(file, options);
if (key in object) {
return object[key];
}
if (defaultValue === undefined) {
throw new _JsonFileError.default(`No value at key path "${String(key)}" in JSON object from: ${file}`);
}
return defaultValue;
}
async function getAsync(file, key, defaultValue, options) {
const object = await readAsync(file, options);
if (key in object) {
return object[key];
}
if (defaultValue === undefined) {
throw new _JsonFileError.default(`No value at key path "${String(key)}" in JSON object from: ${file}`);
}
return defaultValue;
}
function write(file, object, options) {
if (options?.ensureDir) {
_nodefs().default.mkdirSync(_nodepath().default.dirname(file), {
recursive: true
});
}
const space = _getOption(options, 'space');
const json5 = _getOption(options, 'json5');
const addNewLineAtEOF = _getOption(options, 'addNewLineAtEOF');
let json;
try {
if (json5) {
json = _json5().default.stringify(object, null, space);
} else {
json = JSON.stringify(object, null, space);
}
} catch (e) {
throw new _JsonFileError.default(`Couldn't JSON.stringify object for file: ${file}`, e);
}
const data = addNewLineAtEOF ? `${json}\n` : json;
(0, _writeAtomic.writeFileAtomicSync)(file, data, {
mode: options?.mode
});
return object;
}
async function writeAsync(file, object, options) {
if (options?.ensureDir) {
await _nodefs().default.promises.mkdir(_nodepath().default.dirname(file), {
recursive: true
});
}
const space = _getOption(options, 'space');
const json5 = _getOption(options, 'json5');
const addNewLineAtEOF = _getOption(options, 'addNewLineAtEOF');
let json;
try {
if (json5) {
json = _json5().default.stringify(object, null, space);
} else {
json = JSON.stringify(object, null, space);
}
} catch (e) {
throw new _JsonFileError.default(`Couldn't JSON.stringify object for file: ${file}`, e);
}
const data = addNewLineAtEOF ? `${json}\n` : json;
await (0, _writeAtomic.writeFileAtomic)(file, data, {
mode: options?.mode
});
return object;
}
function setSync(file, key, value, options) {
// TODO: Consider implementing some kind of locking mechanism, but
// it's not critical for our use case, so we'll leave it out for now
const object = read(file, options);
return write(file, {
...object,
[key]: value
}, options);
}
async function setAsync(file, key, value, options) {
// TODO: Consider implementing some kind of locking mechanism, but
// it's not critical for our use case, so we'll leave it out for now
const object = await readAsync(file, options);
return writeAsync(file, {
...object,
[key]: value
}, options);
}
async function mergeAsync(file, sources, options) {
const object = await readAsync(file, options);
if (Array.isArray(sources)) {
Object.assign(object, ...sources);
} else {
Object.assign(object, sources);
}
return writeAsync(file, object, options);
}
function merge(file, sources, options) {
const object = read(file, options);
if (Array.isArray(sources)) {
Object.assign(object, ...sources);
} else {
Object.assign(object, sources);
}
return write(file, object, options);
}
async function deleteKeyAsync(file, key, options) {
return deleteKeysAsync(file, [
key
], options);
}
function deleteKey(file, key, options) {
return deleteKeys(file, [
key
], options);
}
async function deleteKeysAsync(file, keys, options) {
const object = await readAsync(file, options);
let didDelete = false;
for(let i = 0; i < keys.length; i++){
const key = keys[i];
if (key != null && object.hasOwnProperty(key)) {
delete object[key];
didDelete = true;
}
}
if (didDelete) {
return writeAsync(file, object, options);
}
return object;
}
function deleteKeys(file, keys, options) {
const object = read(file, options);
let didDelete = false;
for(let i = 0; i < keys.length; i++){
const key = keys[i];
if (key != null && object.hasOwnProperty(key)) {
delete object[key];
didDelete = true;
}
}
if (didDelete) {
return write(file, object, options);
}
return object;
}
async function rewriteAsync(file, options) {
const object = await readAsync(file, options);
return writeAsync(file, object, options);
}
function rewrite(file, options) {
return write(file, read(file, options), options);
}
function jsonParseErrorDefault(options = {}) {
if (options.jsonParseErrorDefault === undefined) {
return options.default;
} else {
return options.jsonParseErrorDefault;
}
}
function cantReadFileDefault(options = {}) {
if (options.cantReadFileDefault === undefined) {
return options.default;
} else {
return options.cantReadFileDefault;
}
}
function _getOption(options, field) {
if (options) {
if (options[field] !== undefined) {
return options[field];
}
}
return DEFAULT_OPTIONS[field];
}
function locationFromSyntaxError(error, sourceString) {
// JSON5 SyntaxError has lineNumber and columnNumber.
if ('lineNumber' in error && 'columnNumber' in error) {
return {
line: error.lineNumber,
column: error.columnNumber
};
}
// JSON SyntaxError only includes the index in the message.
const match = /at position (\d+)/.exec(error.message);
if (match && match[1] != null) {
const index = parseInt(match[1], 10);
const lines = sourceString.slice(0, index + 1).split('\n');
const lastLine = lines[lines.length - 1];
if (lastLine != null) {
return {
line: lines.length,
column: lastLine.length
};
}
}
return null;
}
function assertEmptyJsonString(json, file) {
if (json?.trim() === '') {
throw new _JsonFileError.EmptyJsonFileError(file);
}
}
//# sourceMappingURL=JsonFile.js.map