1 | "use strict";
|
2 | var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
3 | if (k2 === undefined) k2 = k;
|
4 | var desc = Object.getOwnPropertyDescriptor(m, k);
|
5 | if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
6 | desc = { enumerable: true, get: function() { return m[k]; } };
|
7 | }
|
8 | Object.defineProperty(o, k2, desc);
|
9 | }) : (function(o, m, k, k2) {
|
10 | if (k2 === undefined) k2 = k;
|
11 | o[k2] = m[k];
|
12 | }));
|
13 | var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
14 | Object.defineProperty(o, "default", { enumerable: true, value: v });
|
15 | }) : function(o, v) {
|
16 | o["default"] = v;
|
17 | });
|
18 | var __importStar = (this && this.__importStar) || function (mod) {
|
19 | if (mod && mod.__esModule) return mod;
|
20 | var result = {};
|
21 | if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
22 | __setModuleDefault(result, mod);
|
23 | return result;
|
24 | };
|
25 | var __importDefault = (this && this.__importDefault) || function (mod) {
|
26 | return (mod && mod.__esModule) ? mod : { "default": mod };
|
27 | };
|
28 | Object.defineProperty(exports, "__esModule", { value: true });
|
29 | const code_frame_1 = require("@babel/code-frame");
|
30 | const fs_1 = __importDefault(require("fs"));
|
31 | const json5_1 = __importDefault(require("json5"));
|
32 | const path_1 = __importDefault(require("path"));
|
33 | const util_1 = require("util");
|
34 | const write_file_atomic_1 = __importDefault(require("write-file-atomic"));
|
35 | const JsonFileError_1 = __importStar(require("./JsonFileError"));
|
36 | const writeFileAtomicAsync = (0, util_1.promisify)(write_file_atomic_1.default);
|
37 | const DEFAULT_OPTIONS = {
|
38 | badJsonDefault: undefined,
|
39 | jsonParseErrorDefault: undefined,
|
40 | cantReadFileDefault: undefined,
|
41 | ensureDir: false,
|
42 | default: undefined,
|
43 | json5: false,
|
44 | space: 2,
|
45 | addNewLineAtEOF: true,
|
46 | };
|
47 |
|
48 |
|
49 |
|
50 |
|
51 |
|
52 |
|
53 |
|
54 | class JsonFile {
|
55 | constructor(file, options = {}) {
|
56 | this.file = file;
|
57 | this.options = options;
|
58 | }
|
59 | read(options) {
|
60 | return read(this.file, this._getOptions(options));
|
61 | }
|
62 | async readAsync(options) {
|
63 | return readAsync(this.file, this._getOptions(options));
|
64 | }
|
65 | async writeAsync(object, options) {
|
66 | return writeAsync(this.file, object, this._getOptions(options));
|
67 | }
|
68 | parseJsonString(json, options) {
|
69 | return parseJsonString(json, options);
|
70 | }
|
71 | async getAsync(key, defaultValue, options) {
|
72 | return getAsync(this.file, key, defaultValue, this._getOptions(options));
|
73 | }
|
74 | async setAsync(key, value, options) {
|
75 | return setAsync(this.file, key, value, this._getOptions(options));
|
76 | }
|
77 | async mergeAsync(sources, options) {
|
78 | return mergeAsync(this.file, sources, this._getOptions(options));
|
79 | }
|
80 | async deleteKeyAsync(key, options) {
|
81 | return deleteKeyAsync(this.file, key, this._getOptions(options));
|
82 | }
|
83 | async deleteKeysAsync(keys, options) {
|
84 | return deleteKeysAsync(this.file, keys, this._getOptions(options));
|
85 | }
|
86 | async rewriteAsync(options) {
|
87 | return rewriteAsync(this.file, this._getOptions(options));
|
88 | }
|
89 | _getOptions(options) {
|
90 | return {
|
91 | ...this.options,
|
92 | ...options,
|
93 | };
|
94 | }
|
95 | }
|
96 | exports.default = JsonFile;
|
97 | JsonFile.read = read;
|
98 | JsonFile.readAsync = readAsync;
|
99 | JsonFile.parseJsonString = parseJsonString;
|
100 | JsonFile.writeAsync = writeAsync;
|
101 | JsonFile.getAsync = getAsync;
|
102 | JsonFile.setAsync = setAsync;
|
103 | JsonFile.mergeAsync = mergeAsync;
|
104 | JsonFile.deleteKeyAsync = deleteKeyAsync;
|
105 | JsonFile.deleteKeysAsync = deleteKeysAsync;
|
106 | JsonFile.rewriteAsync = rewriteAsync;
|
107 | function read(file, options) {
|
108 | let json;
|
109 | try {
|
110 | json = fs_1.default.readFileSync(file, 'utf8');
|
111 | }
|
112 | catch (error) {
|
113 | assertEmptyJsonString(json, file);
|
114 | const defaultValue = cantReadFileDefault(options);
|
115 | if (defaultValue === undefined) {
|
116 | throw new JsonFileError_1.default(`Can't read JSON file: ${file}`, error, error.code, file);
|
117 | }
|
118 | else {
|
119 | return defaultValue;
|
120 | }
|
121 | }
|
122 | return parseJsonString(json, options, file);
|
123 | }
|
124 | async function readAsync(file, options) {
|
125 | let json;
|
126 | try {
|
127 | json = await fs_1.default.promises.readFile(file, 'utf8');
|
128 | }
|
129 | catch (error) {
|
130 | assertEmptyJsonString(json, file);
|
131 | const defaultValue = cantReadFileDefault(options);
|
132 | if (defaultValue === undefined) {
|
133 | throw new JsonFileError_1.default(`Can't read JSON file: ${file}`, error, error.code);
|
134 | }
|
135 | else {
|
136 | return defaultValue;
|
137 | }
|
138 | }
|
139 | return parseJsonString(json, options);
|
140 | }
|
141 | function parseJsonString(json, options, fileName) {
|
142 | assertEmptyJsonString(json, fileName);
|
143 | try {
|
144 | if (_getOption(options, 'json5')) {
|
145 | return json5_1.default.parse(json);
|
146 | }
|
147 | else {
|
148 | return JSON.parse(json);
|
149 | }
|
150 | }
|
151 | catch (e) {
|
152 | const defaultValue = jsonParseErrorDefault(options);
|
153 | if (defaultValue === undefined) {
|
154 | const location = locationFromSyntaxError(e, json);
|
155 | if (location) {
|
156 | const codeFrame = (0, code_frame_1.codeFrameColumns)(json, { start: location });
|
157 | e.codeFrame = codeFrame;
|
158 | e.message += `\n${codeFrame}`;
|
159 | }
|
160 | throw new JsonFileError_1.default(`Error parsing JSON: ${json}`, e, 'EJSONPARSE', fileName);
|
161 | }
|
162 | else {
|
163 | return defaultValue;
|
164 | }
|
165 | }
|
166 | }
|
167 | async function getAsync(file, key, defaultValue, options) {
|
168 | const object = await readAsync(file, options);
|
169 | if (key in object) {
|
170 | return object[key];
|
171 | }
|
172 | if (defaultValue === undefined) {
|
173 | throw new JsonFileError_1.default(`No value at key path "${key}" in JSON object from: ${file}`);
|
174 | }
|
175 | return defaultValue;
|
176 | }
|
177 | async function writeAsync(file, object, options) {
|
178 | if (options === null || options === void 0 ? void 0 : options.ensureDir) {
|
179 | await fs_1.default.promises.mkdir(path_1.default.dirname(file), { recursive: true });
|
180 | }
|
181 | const space = _getOption(options, 'space');
|
182 | const json5 = _getOption(options, 'json5');
|
183 | const addNewLineAtEOF = _getOption(options, 'addNewLineAtEOF');
|
184 | let json;
|
185 | try {
|
186 | if (json5) {
|
187 | json = json5_1.default.stringify(object, null, space);
|
188 | }
|
189 | else {
|
190 | json = JSON.stringify(object, null, space);
|
191 | }
|
192 | }
|
193 | catch (e) {
|
194 | throw new JsonFileError_1.default(`Couldn't JSON.stringify object for file: ${file}`, e);
|
195 | }
|
196 | const data = addNewLineAtEOF ? `${json}\n` : json;
|
197 | await writeFileAtomicAsync(file, data, {});
|
198 | return object;
|
199 | }
|
200 | async function setAsync(file, key, value, options) {
|
201 |
|
202 |
|
203 | const object = await readAsync(file, options);
|
204 | return writeAsync(file, { ...object, [key]: value }, options);
|
205 | }
|
206 | async function mergeAsync(file, sources, options) {
|
207 | const object = await readAsync(file, options);
|
208 | if (Array.isArray(sources)) {
|
209 | Object.assign(object, ...sources);
|
210 | }
|
211 | else {
|
212 | Object.assign(object, sources);
|
213 | }
|
214 | return writeAsync(file, object, options);
|
215 | }
|
216 | async function deleteKeyAsync(file, key, options) {
|
217 | return deleteKeysAsync(file, [key], options);
|
218 | }
|
219 | async function deleteKeysAsync(file, keys, options) {
|
220 | const object = await readAsync(file, options);
|
221 | let didDelete = false;
|
222 | for (let i = 0; i < keys.length; i++) {
|
223 | const key = keys[i];
|
224 | if (object.hasOwnProperty(key)) {
|
225 | delete object[key];
|
226 | didDelete = true;
|
227 | }
|
228 | }
|
229 | if (didDelete) {
|
230 | return writeAsync(file, object, options);
|
231 | }
|
232 | return object;
|
233 | }
|
234 | async function rewriteAsync(file, options) {
|
235 | const object = await readAsync(file, options);
|
236 | return writeAsync(file, object, options);
|
237 | }
|
238 | function jsonParseErrorDefault(options = {}) {
|
239 | if (options.jsonParseErrorDefault === undefined) {
|
240 | return options.default;
|
241 | }
|
242 | else {
|
243 | return options.jsonParseErrorDefault;
|
244 | }
|
245 | }
|
246 | function cantReadFileDefault(options = {}) {
|
247 | if (options.cantReadFileDefault === undefined) {
|
248 | return options.default;
|
249 | }
|
250 | else {
|
251 | return options.cantReadFileDefault;
|
252 | }
|
253 | }
|
254 | function _getOption(options, field) {
|
255 | if (options) {
|
256 | if (options[field] !== undefined) {
|
257 | return options[field];
|
258 | }
|
259 | }
|
260 | return DEFAULT_OPTIONS[field];
|
261 | }
|
262 | function locationFromSyntaxError(error, sourceString) {
|
263 |
|
264 | if ('lineNumber' in error && 'columnNumber' in error) {
|
265 | return { line: error.lineNumber, column: error.columnNumber };
|
266 | }
|
267 |
|
268 | const match = /at position (\d+)/.exec(error.message);
|
269 | if (match) {
|
270 | const index = parseInt(match[1], 10);
|
271 | const lines = sourceString.slice(0, index + 1).split('\n');
|
272 | return { line: lines.length, column: lines[lines.length - 1].length };
|
273 | }
|
274 | return null;
|
275 | }
|
276 | function assertEmptyJsonString(json, file) {
|
277 | if ((json === null || json === void 0 ? void 0 : json.trim()) === '') {
|
278 | throw new JsonFileError_1.EmptyJsonFileError(file);
|
279 | }
|
280 | }
|
281 |
|
\ | No newline at end of file |