mason-parser 1.0.0 → 1.0.2
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/README.md +114 -11
- package/dist/index.d.mts +19 -5
- package/dist/index.d.ts +19 -5
- package/dist/index.js +765 -128
- package/dist/index.mjs +761 -128
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1,216 +1,822 @@
|
|
|
1
1
|
// index.ts
|
|
2
|
+
var BACKTICK_REGEX = /`+/g;
|
|
3
|
+
var DOUBLE_QUOTE_REGEX = /"/g;
|
|
4
|
+
var LANGUAGE_TAG_REGEX = /^[a-zA-Z0-9+#-]+$/;
|
|
5
|
+
var NUMBER_REGEX = /^[+-]?(?:\d+\.?\d*|\.\d+)(?:[eE][+-]?\d+)?$/;
|
|
6
|
+
function findColonIndex(line, start) {
|
|
7
|
+
const len = line.length;
|
|
8
|
+
let inDouble = false;
|
|
9
|
+
let inSingle = false;
|
|
10
|
+
let inBacktick = false;
|
|
11
|
+
for (let i = start; i < len; i++) {
|
|
12
|
+
const code = line.charCodeAt(i);
|
|
13
|
+
if (code === 92) {
|
|
14
|
+
i++;
|
|
15
|
+
continue;
|
|
16
|
+
}
|
|
17
|
+
if (code === 34 && !inSingle && !inBacktick) {
|
|
18
|
+
inDouble = !inDouble;
|
|
19
|
+
} else if (code === 39 && !inDouble && !inBacktick) {
|
|
20
|
+
inSingle = !inSingle;
|
|
21
|
+
} else if (code === 96 && !inDouble && !inSingle) {
|
|
22
|
+
inBacktick = !inBacktick;
|
|
23
|
+
} else if (code === 58 && !inDouble && !inSingle && !inBacktick) {
|
|
24
|
+
return i;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return -1;
|
|
28
|
+
}
|
|
2
29
|
function parsePrimitiveValue(val) {
|
|
3
|
-
const
|
|
4
|
-
if (
|
|
5
|
-
|
|
30
|
+
const len = val.length;
|
|
31
|
+
if (len === 0) return val;
|
|
32
|
+
const first = val.charCodeAt(0);
|
|
33
|
+
const last = val.charCodeAt(len - 1);
|
|
34
|
+
if (len >= 2) {
|
|
35
|
+
if (first === 34 && last === 34 || first === 39 && last === 39 || first === 96 && last === 96) {
|
|
36
|
+
const content = val.slice(1, -1);
|
|
37
|
+
if (content.indexOf("\\") !== -1) {
|
|
38
|
+
if (first === 34) {
|
|
39
|
+
return content.replace(/\\"/g, '"').replace(/\\\\/g, "\\");
|
|
40
|
+
} else if (first === 39) {
|
|
41
|
+
return content.replace(/\\'/g, "'").replace(/\\\\/g, "\\");
|
|
42
|
+
} else if (first === 96) {
|
|
43
|
+
return content.replace(/\\`/g, "`").replace(/\\\\/g, "\\");
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return content;
|
|
47
|
+
}
|
|
6
48
|
}
|
|
7
|
-
if (
|
|
8
|
-
if (
|
|
9
|
-
if (
|
|
10
|
-
if (
|
|
11
|
-
|
|
49
|
+
if (first === 116 && val === "true") return true;
|
|
50
|
+
if (first === 102 && val === "false") return false;
|
|
51
|
+
if (first === 110 && val === "null") return null;
|
|
52
|
+
if (first >= 48 && first <= 57 || first === 45 || first === 46 || first === 43) {
|
|
53
|
+
if (NUMBER_REGEX.test(val)) {
|
|
54
|
+
const num = Number(val);
|
|
55
|
+
if (!isNaN(num)) {
|
|
56
|
+
return num;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return val;
|
|
61
|
+
}
|
|
62
|
+
function parseValueWithMultiline(initialValStr, lines, currentLineIndex) {
|
|
63
|
+
const valStr = initialValStr;
|
|
64
|
+
let nextLineIndex = currentLineIndex;
|
|
65
|
+
let backtickCount = 0;
|
|
66
|
+
while (backtickCount < valStr.length && valStr.charCodeAt(backtickCount) === 96) {
|
|
67
|
+
backtickCount++;
|
|
68
|
+
}
|
|
69
|
+
if (backtickCount > 0) {
|
|
70
|
+
const termSeq = "`".repeat(backtickCount);
|
|
71
|
+
if (valStr.endsWith(termSeq) && valStr.length >= backtickCount * 2) {
|
|
72
|
+
let content = valStr.slice(backtickCount, -backtickCount);
|
|
73
|
+
if (backtickCount > 1 && content.startsWith(" ") && content.endsWith(" ") && content.trim() !== "") {
|
|
74
|
+
content = content.slice(1, -1);
|
|
75
|
+
}
|
|
76
|
+
const trimmedVal = content.trim();
|
|
77
|
+
if (trimmedVal === "true" || trimmedVal === "false" || trimmedVal === "null" || trimmedVal !== "" && !isNaN(Number(trimmedVal))) {
|
|
78
|
+
return { value: parsePrimitiveValue(trimmedVal), nextLineIndex };
|
|
79
|
+
} else {
|
|
80
|
+
return { value: content, nextLineIndex };
|
|
81
|
+
}
|
|
82
|
+
} else {
|
|
83
|
+
let firstLineContent = valStr.slice(backtickCount).trim();
|
|
84
|
+
if (backtickCount >= 3 && LANGUAGE_TAG_REGEX.test(firstLineContent)) {
|
|
85
|
+
firstLineContent = "";
|
|
86
|
+
}
|
|
87
|
+
let multilineContent = firstLineContent;
|
|
88
|
+
if (multilineContent) {
|
|
89
|
+
multilineContent += "\n";
|
|
90
|
+
}
|
|
91
|
+
let j = currentLineIndex + 1;
|
|
92
|
+
for (; j < lines.length; j++) {
|
|
93
|
+
const nextRawLine = lines[j];
|
|
94
|
+
let endIdx = nextRawLine.length - 1;
|
|
95
|
+
while (endIdx >= 0) {
|
|
96
|
+
const code = nextRawLine.charCodeAt(endIdx);
|
|
97
|
+
if (code === 32 || code === 9 || code === 13) {
|
|
98
|
+
endIdx--;
|
|
99
|
+
} else {
|
|
100
|
+
break;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
let endsWithTerm = false;
|
|
104
|
+
if (endIdx + 1 >= backtickCount) {
|
|
105
|
+
endsWithTerm = true;
|
|
106
|
+
for (let k = 0; k < backtickCount; k++) {
|
|
107
|
+
if (nextRawLine.charCodeAt(endIdx - k) !== 96) {
|
|
108
|
+
endsWithTerm = false;
|
|
109
|
+
break;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
if (endsWithTerm) {
|
|
114
|
+
const lastIndex = endIdx - backtickCount + 1;
|
|
115
|
+
const lineContent = nextRawLine.slice(0, lastIndex);
|
|
116
|
+
multilineContent += lineContent;
|
|
117
|
+
nextLineIndex = j;
|
|
118
|
+
break;
|
|
119
|
+
} else {
|
|
120
|
+
multilineContent += nextRawLine + "\n";
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
const trimmedVal = multilineContent.trim();
|
|
124
|
+
if (trimmedVal === "true" || trimmedVal === "false" || trimmedVal === "null" || trimmedVal !== "" && !isNaN(Number(trimmedVal))) {
|
|
125
|
+
return { value: parsePrimitiveValue(trimmedVal), nextLineIndex };
|
|
126
|
+
} else {
|
|
127
|
+
let cleanStr = multilineContent;
|
|
128
|
+
if (cleanStr.startsWith("\n")) {
|
|
129
|
+
cleanStr = cleanStr.slice(1);
|
|
130
|
+
} else if (cleanStr.startsWith("\r\n")) {
|
|
131
|
+
cleanStr = cleanStr.slice(2);
|
|
132
|
+
}
|
|
133
|
+
if (cleanStr.endsWith("\n")) {
|
|
134
|
+
cleanStr = cleanStr.slice(0, -1);
|
|
135
|
+
}
|
|
136
|
+
if (cleanStr.endsWith("\r")) {
|
|
137
|
+
cleanStr = cleanStr.slice(0, -1);
|
|
138
|
+
}
|
|
139
|
+
if (cleanStr.startsWith('"') && cleanStr.endsWith('"') || cleanStr.startsWith("'") && cleanStr.endsWith("'")) {
|
|
140
|
+
cleanStr = cleanStr.slice(1, -1);
|
|
141
|
+
}
|
|
142
|
+
return { value: cleanStr, nextLineIndex };
|
|
143
|
+
}
|
|
144
|
+
}
|
|
12
145
|
}
|
|
13
|
-
return
|
|
146
|
+
return { value: parsePrimitiveValue(valStr), nextLineIndex };
|
|
14
147
|
}
|
|
15
148
|
function stringifyPrimitiveValue(val) {
|
|
16
149
|
if (val === null) return "null";
|
|
17
150
|
if (typeof val === "boolean") return val ? "true" : "false";
|
|
18
151
|
if (typeof val === "number") return String(val);
|
|
19
152
|
const str = String(val);
|
|
20
|
-
|
|
153
|
+
if (str.includes("\n")) {
|
|
154
|
+
let maxConsecutive = 0;
|
|
155
|
+
let match;
|
|
156
|
+
BACKTICK_REGEX.lastIndex = 0;
|
|
157
|
+
while ((match = BACKTICK_REGEX.exec(str)) !== null) {
|
|
158
|
+
if (match[0].length > maxConsecutive) {
|
|
159
|
+
maxConsecutive = match[0].length;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
const wrapCount = maxConsecutive + 1;
|
|
163
|
+
const wrapSeq = "`".repeat(wrapCount);
|
|
164
|
+
return `${wrapSeq}
|
|
165
|
+
${str}
|
|
166
|
+
${wrapSeq}`;
|
|
167
|
+
}
|
|
168
|
+
if (str.includes("`")) {
|
|
169
|
+
let maxConsecutive = 0;
|
|
170
|
+
let match;
|
|
171
|
+
BACKTICK_REGEX.lastIndex = 0;
|
|
172
|
+
while ((match = BACKTICK_REGEX.exec(str)) !== null) {
|
|
173
|
+
if (match[0].length > maxConsecutive) {
|
|
174
|
+
maxConsecutive = match[0].length;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
const wrapCount = maxConsecutive + 1;
|
|
178
|
+
const wrapSeq = "`".repeat(wrapCount);
|
|
179
|
+
return `${wrapSeq}${str}${wrapSeq}`;
|
|
180
|
+
}
|
|
181
|
+
const needsQuotes = str.trim() !== str || str.includes(":") || str === "true" || str === "false" || str === "null" || NUMBER_REGEX.test(str) && str !== "";
|
|
21
182
|
if (needsQuotes) {
|
|
22
|
-
return `"${str.replace(
|
|
183
|
+
return `"${str.replace(DOUBLE_QUOTE_REGEX, '\\"')}"`;
|
|
23
184
|
}
|
|
24
185
|
return str;
|
|
25
186
|
}
|
|
26
|
-
function parse(text) {
|
|
27
|
-
return parseWithTrace(text).data;
|
|
187
|
+
function parse(text, options) {
|
|
188
|
+
return parseWithTrace(text, options).data;
|
|
189
|
+
}
|
|
190
|
+
function fastParseWithTrace(text) {
|
|
191
|
+
const startTime = typeof performance !== "undefined" ? performance.now() : Date.now();
|
|
192
|
+
const lines = text.split(/\r?\n/);
|
|
193
|
+
let root = {};
|
|
194
|
+
let rootConvertedToArray = false;
|
|
195
|
+
const stack = [];
|
|
196
|
+
for (let i = 0; i < lines.length; i++) {
|
|
197
|
+
const rawLine = lines[i];
|
|
198
|
+
const len = rawLine.length;
|
|
199
|
+
let startIdx = 0;
|
|
200
|
+
while (startIdx < len) {
|
|
201
|
+
const code = rawLine.charCodeAt(startIdx);
|
|
202
|
+
if (code === 32 || code === 9 || code === 13) {
|
|
203
|
+
startIdx++;
|
|
204
|
+
} else {
|
|
205
|
+
break;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
if (startIdx === len) {
|
|
209
|
+
continue;
|
|
210
|
+
}
|
|
211
|
+
const firstChar = rawLine.charCodeAt(startIdx);
|
|
212
|
+
if (firstChar === 60 && rawLine.startsWith("<!--", startIdx)) {
|
|
213
|
+
continue;
|
|
214
|
+
}
|
|
215
|
+
let endIdx = len - 1;
|
|
216
|
+
while (endIdx > startIdx) {
|
|
217
|
+
const code = rawLine.charCodeAt(endIdx);
|
|
218
|
+
if (code === 32 || code === 9 || code === 13) {
|
|
219
|
+
endIdx--;
|
|
220
|
+
} else {
|
|
221
|
+
break;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
const trimmedLen = endIdx - startIdx + 1;
|
|
225
|
+
if (trimmedLen === 2 && rawLine.charCodeAt(startIdx) === 91 && rawLine.charCodeAt(startIdx + 1) === 93) {
|
|
226
|
+
let isRootEmpty = false;
|
|
227
|
+
if (Array.isArray(root)) {
|
|
228
|
+
isRootEmpty = root.length === 0;
|
|
229
|
+
} else {
|
|
230
|
+
let hasKeys = false;
|
|
231
|
+
for (const _ in root) {
|
|
232
|
+
hasKeys = true;
|
|
233
|
+
break;
|
|
234
|
+
}
|
|
235
|
+
isRootEmpty = !hasKeys;
|
|
236
|
+
}
|
|
237
|
+
if (stack.length === 0 && !rootConvertedToArray && isRootEmpty) {
|
|
238
|
+
root = [];
|
|
239
|
+
rootConvertedToArray = true;
|
|
240
|
+
continue;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
if (firstChar === 35) {
|
|
244
|
+
let hashCount = 0;
|
|
245
|
+
while (startIdx + hashCount <= endIdx && rawLine.charCodeAt(startIdx + hashCount) === 35) {
|
|
246
|
+
hashCount++;
|
|
247
|
+
}
|
|
248
|
+
let hStart = startIdx + hashCount;
|
|
249
|
+
while (hStart <= endIdx) {
|
|
250
|
+
const code = rawLine.charCodeAt(hStart);
|
|
251
|
+
if (code === 32 || code === 9) {
|
|
252
|
+
hStart++;
|
|
253
|
+
} else {
|
|
254
|
+
break;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
let actualHeadingName = "";
|
|
258
|
+
let isExplicitArray = false;
|
|
259
|
+
if (hStart <= endIdx) {
|
|
260
|
+
if (endIdx - hStart >= 1 && rawLine.charCodeAt(endIdx - 1) === 91 && rawLine.charCodeAt(endIdx) === 93) {
|
|
261
|
+
isExplicitArray = true;
|
|
262
|
+
let hEnd = endIdx - 2;
|
|
263
|
+
while (hEnd >= hStart) {
|
|
264
|
+
const code = rawLine.charCodeAt(hEnd);
|
|
265
|
+
if (code === 32 || code === 9) {
|
|
266
|
+
hEnd--;
|
|
267
|
+
} else {
|
|
268
|
+
break;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
actualHeadingName = hStart <= hEnd ? rawLine.slice(hStart, hEnd + 1) : "";
|
|
272
|
+
} else {
|
|
273
|
+
actualHeadingName = rawLine.slice(hStart, endIdx + 1);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
while (stack.length > 0 && stack[stack.length - 1].level >= hashCount) {
|
|
277
|
+
stack.pop();
|
|
278
|
+
}
|
|
279
|
+
let activeParent = root;
|
|
280
|
+
let activeParentItem = null;
|
|
281
|
+
if (stack.length > 0) {
|
|
282
|
+
activeParentItem = stack[stack.length - 1];
|
|
283
|
+
activeParent = activeParentItem.value;
|
|
284
|
+
}
|
|
285
|
+
if (!actualHeadingName) {
|
|
286
|
+
if (activeParentItem && activeParentItem.isExplicitArray || Array.isArray(activeParent)) {
|
|
287
|
+
actualHeadingName = "";
|
|
288
|
+
} else {
|
|
289
|
+
continue;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
const newNode = isExplicitArray ? [] : {};
|
|
293
|
+
if (activeParentItem && activeParentItem.isExplicitArray) {
|
|
294
|
+
activeParent.push(newNode);
|
|
295
|
+
} else if (Array.isArray(activeParent)) {
|
|
296
|
+
if (actualHeadingName === "") {
|
|
297
|
+
activeParent.push(newNode);
|
|
298
|
+
} else {
|
|
299
|
+
activeParent.push({ [actualHeadingName]: newNode });
|
|
300
|
+
}
|
|
301
|
+
} else {
|
|
302
|
+
activeParent[actualHeadingName] = newNode;
|
|
303
|
+
}
|
|
304
|
+
stack.push({
|
|
305
|
+
level: hashCount,
|
|
306
|
+
key: actualHeadingName,
|
|
307
|
+
parent: activeParent,
|
|
308
|
+
value: newNode,
|
|
309
|
+
type: isExplicitArray ? "array" : "object",
|
|
310
|
+
isExplicitArray
|
|
311
|
+
});
|
|
312
|
+
continue;
|
|
313
|
+
}
|
|
314
|
+
if (firstChar === 42 || firstChar === 45 || firstChar === 43) {
|
|
315
|
+
let bulletValIdx = startIdx + 1;
|
|
316
|
+
while (bulletValIdx <= endIdx) {
|
|
317
|
+
const code = rawLine.charCodeAt(bulletValIdx);
|
|
318
|
+
if (code === 32 || code === 9) {
|
|
319
|
+
bulletValIdx++;
|
|
320
|
+
} else {
|
|
321
|
+
break;
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
const bulletValStr = bulletValIdx <= endIdx ? rawLine.slice(bulletValIdx, endIdx + 1) : "";
|
|
325
|
+
let value;
|
|
326
|
+
if (bulletValStr.charCodeAt(0) === 96) {
|
|
327
|
+
const multiline = parseValueWithMultiline(bulletValStr, lines, i);
|
|
328
|
+
value = multiline.value;
|
|
329
|
+
i = multiline.nextLineIndex;
|
|
330
|
+
} else {
|
|
331
|
+
value = parsePrimitiveValue(bulletValStr);
|
|
332
|
+
}
|
|
333
|
+
if (stack.length === 0) {
|
|
334
|
+
if (!root._items) {
|
|
335
|
+
root._items = [];
|
|
336
|
+
}
|
|
337
|
+
root._items.push(value);
|
|
338
|
+
continue;
|
|
339
|
+
}
|
|
340
|
+
const activeItem = stack[stack.length - 1];
|
|
341
|
+
if (activeItem.type !== "array") {
|
|
342
|
+
let hasKeys = false;
|
|
343
|
+
for (const k in activeItem.value) {
|
|
344
|
+
if (Object.prototype.hasOwnProperty.call(activeItem.value, k)) {
|
|
345
|
+
hasKeys = true;
|
|
346
|
+
break;
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
if (!hasKeys) {
|
|
350
|
+
const parent = activeItem.parent;
|
|
351
|
+
const key = activeItem.key;
|
|
352
|
+
activeItem.type = "array";
|
|
353
|
+
activeItem.value = [];
|
|
354
|
+
if (Array.isArray(parent)) {
|
|
355
|
+
parent[parent.length - 1] = { [key]: activeItem.value };
|
|
356
|
+
} else {
|
|
357
|
+
parent[key] = activeItem.value;
|
|
358
|
+
}
|
|
359
|
+
activeItem.value.push(value);
|
|
360
|
+
} else {
|
|
361
|
+
if (!activeItem.value._items) {
|
|
362
|
+
activeItem.value._items = [];
|
|
363
|
+
}
|
|
364
|
+
activeItem.value._items.push(value);
|
|
365
|
+
}
|
|
366
|
+
} else {
|
|
367
|
+
activeItem.value.push(value);
|
|
368
|
+
}
|
|
369
|
+
continue;
|
|
370
|
+
}
|
|
371
|
+
const colonIndex = findColonIndex(rawLine, startIdx);
|
|
372
|
+
if (colonIndex !== -1 && colonIndex <= endIdx) {
|
|
373
|
+
let kEnd = colonIndex - 1;
|
|
374
|
+
while (kEnd >= startIdx) {
|
|
375
|
+
const code = rawLine.charCodeAt(kEnd);
|
|
376
|
+
if (code === 32 || code === 9) {
|
|
377
|
+
kEnd--;
|
|
378
|
+
} else {
|
|
379
|
+
break;
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
const key = startIdx <= kEnd ? rawLine.slice(startIdx, kEnd + 1) : "";
|
|
383
|
+
let vStart = colonIndex + 1;
|
|
384
|
+
while (vStart <= endIdx) {
|
|
385
|
+
const code = rawLine.charCodeAt(vStart);
|
|
386
|
+
if (code === 32 || code === 9) {
|
|
387
|
+
vStart++;
|
|
388
|
+
} else {
|
|
389
|
+
break;
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
const valStr = vStart <= endIdx ? rawLine.slice(vStart, endIdx + 1) : "";
|
|
393
|
+
let parsedVal;
|
|
394
|
+
if (valStr.charCodeAt(0) === 96) {
|
|
395
|
+
const multiline = parseValueWithMultiline(valStr, lines, i);
|
|
396
|
+
parsedVal = multiline.value;
|
|
397
|
+
i = multiline.nextLineIndex;
|
|
398
|
+
} else {
|
|
399
|
+
parsedVal = parsePrimitiveValue(valStr);
|
|
400
|
+
}
|
|
401
|
+
if (stack.length === 0) {
|
|
402
|
+
root[key] = parsedVal;
|
|
403
|
+
continue;
|
|
404
|
+
}
|
|
405
|
+
const activeItem = stack[stack.length - 1];
|
|
406
|
+
if (activeItem.type === "array") {
|
|
407
|
+
continue;
|
|
408
|
+
}
|
|
409
|
+
activeItem.value[key] = parsedVal;
|
|
410
|
+
continue;
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
const duration = (typeof performance !== "undefined" ? performance.now() : Date.now()) - startTime;
|
|
414
|
+
return {
|
|
415
|
+
data: root,
|
|
416
|
+
trace: [],
|
|
417
|
+
stats: {
|
|
418
|
+
parseTimeMs: duration,
|
|
419
|
+
linesProcessed: lines.length,
|
|
420
|
+
charCount: text.length,
|
|
421
|
+
estimatedTokens: Math.ceil(text.length / 3.8),
|
|
422
|
+
jsonCharCount: 0,
|
|
423
|
+
jsonEstimatedTokens: 0,
|
|
424
|
+
tokenSavingsPercent: 0
|
|
425
|
+
}
|
|
426
|
+
};
|
|
28
427
|
}
|
|
29
|
-
function parseWithTrace(text) {
|
|
428
|
+
function parseWithTrace(text, options) {
|
|
429
|
+
if (options?.noTrace) {
|
|
430
|
+
return fastParseWithTrace(text);
|
|
431
|
+
}
|
|
30
432
|
const startTime = typeof performance !== "undefined" ? performance.now() : Date.now();
|
|
31
433
|
const lines = text.split(/\r?\n/);
|
|
32
434
|
const trace = [];
|
|
33
|
-
const
|
|
435
|
+
const noTrace = options?.noTrace ?? false;
|
|
436
|
+
let root = {};
|
|
437
|
+
let rootConvertedToArray = false;
|
|
34
438
|
const stack = [];
|
|
35
|
-
const getStackNames = () =>
|
|
439
|
+
const getStackNames = () => {
|
|
440
|
+
if (noTrace) return [];
|
|
441
|
+
return stack.map((s) => `${"#".repeat(s.level)} ${s.key}`);
|
|
442
|
+
};
|
|
36
443
|
for (let i = 0; i < lines.length; i++) {
|
|
37
444
|
const rawLine = lines[i];
|
|
38
|
-
const line = rawLine.trim();
|
|
39
445
|
const lineNumber = i + 1;
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
}
|
|
446
|
+
let startIdx = 0;
|
|
447
|
+
const len = rawLine.length;
|
|
448
|
+
while (startIdx < len) {
|
|
449
|
+
const code = rawLine.charCodeAt(startIdx);
|
|
450
|
+
if (code === 32 || code === 9 || code === 13) {
|
|
451
|
+
startIdx++;
|
|
452
|
+
} else {
|
|
453
|
+
break;
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
if (startIdx === len) {
|
|
457
|
+
if (!noTrace) {
|
|
458
|
+
trace.push({
|
|
459
|
+
lineNumber,
|
|
460
|
+
lineText: rawLine,
|
|
461
|
+
action: "Skipped empty line or comment",
|
|
462
|
+
stackDepth: stack.length,
|
|
463
|
+
currentStack: getStackNames(),
|
|
464
|
+
status: "info"
|
|
465
|
+
});
|
|
466
|
+
}
|
|
467
|
+
continue;
|
|
468
|
+
}
|
|
469
|
+
const firstChar = rawLine.charCodeAt(startIdx);
|
|
470
|
+
if (firstChar === 60 && rawLine.startsWith("<!--", startIdx)) {
|
|
471
|
+
if (!noTrace) {
|
|
472
|
+
trace.push({
|
|
473
|
+
lineNumber,
|
|
474
|
+
lineText: rawLine,
|
|
475
|
+
action: "Skipped empty line or comment",
|
|
476
|
+
stackDepth: stack.length,
|
|
477
|
+
currentStack: getStackNames(),
|
|
478
|
+
status: "info"
|
|
479
|
+
});
|
|
480
|
+
}
|
|
49
481
|
continue;
|
|
50
482
|
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
483
|
+
let endIdx = len - 1;
|
|
484
|
+
while (endIdx > startIdx) {
|
|
485
|
+
const code = rawLine.charCodeAt(endIdx);
|
|
486
|
+
if (code === 32 || code === 9 || code === 13) {
|
|
487
|
+
endIdx--;
|
|
488
|
+
} else {
|
|
489
|
+
break;
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
const trimmedLen = endIdx - startIdx + 1;
|
|
493
|
+
if (trimmedLen === 2 && rawLine.charCodeAt(startIdx) === 91 && rawLine.charCodeAt(startIdx + 1) === 93) {
|
|
494
|
+
let isRootEmpty = false;
|
|
495
|
+
if (Array.isArray(root)) {
|
|
496
|
+
isRootEmpty = root.length === 0;
|
|
497
|
+
} else {
|
|
498
|
+
let hasKeys = false;
|
|
499
|
+
for (const _ in root) {
|
|
500
|
+
hasKeys = true;
|
|
501
|
+
break;
|
|
502
|
+
}
|
|
503
|
+
isRootEmpty = !hasKeys;
|
|
504
|
+
}
|
|
505
|
+
if (stack.length === 0 && !rootConvertedToArray && isRootEmpty) {
|
|
506
|
+
root = [];
|
|
507
|
+
rootConvertedToArray = true;
|
|
508
|
+
if (!noTrace) {
|
|
57
509
|
trace.push({
|
|
58
510
|
lineNumber,
|
|
59
511
|
lineText: rawLine,
|
|
60
|
-
action:
|
|
512
|
+
action: 'Converted root container to an Array via top-level "[]"',
|
|
61
513
|
stackDepth: stack.length,
|
|
62
514
|
currentStack: getStackNames(),
|
|
63
|
-
status: "
|
|
515
|
+
status: "success"
|
|
64
516
|
});
|
|
65
|
-
continue;
|
|
66
517
|
}
|
|
67
|
-
|
|
68
|
-
|
|
518
|
+
continue;
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
if (firstChar === 35) {
|
|
522
|
+
let hashCount = 0;
|
|
523
|
+
while (startIdx + hashCount <= endIdx && rawLine.charCodeAt(startIdx + hashCount) === 35) {
|
|
524
|
+
hashCount++;
|
|
525
|
+
}
|
|
526
|
+
let hStart = startIdx + hashCount;
|
|
527
|
+
while (hStart <= endIdx) {
|
|
528
|
+
const code = rawLine.charCodeAt(hStart);
|
|
529
|
+
if (code === 32 || code === 9) {
|
|
530
|
+
hStart++;
|
|
531
|
+
} else {
|
|
532
|
+
break;
|
|
69
533
|
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
534
|
+
}
|
|
535
|
+
const headingName = hStart <= endIdx ? rawLine.slice(hStart, endIdx + 1) : "";
|
|
536
|
+
while (stack.length > 0 && stack[stack.length - 1].level >= hashCount) {
|
|
537
|
+
stack.pop();
|
|
538
|
+
}
|
|
539
|
+
let activeParent = root;
|
|
540
|
+
let activeParentItem = null;
|
|
541
|
+
if (stack.length > 0) {
|
|
542
|
+
activeParentItem = stack[stack.length - 1];
|
|
543
|
+
activeParent = activeParentItem.value;
|
|
544
|
+
}
|
|
545
|
+
let actualHeadingName = headingName;
|
|
546
|
+
let isExplicitArray = false;
|
|
547
|
+
if (headingName.endsWith("[]")) {
|
|
548
|
+
actualHeadingName = headingName.slice(0, -2).trim();
|
|
549
|
+
isExplicitArray = true;
|
|
550
|
+
}
|
|
551
|
+
if (!actualHeadingName) {
|
|
552
|
+
if (activeParentItem && activeParentItem.isExplicitArray || Array.isArray(activeParent)) {
|
|
553
|
+
actualHeadingName = "";
|
|
554
|
+
} else {
|
|
555
|
+
if (!noTrace) {
|
|
556
|
+
trace.push({
|
|
557
|
+
lineNumber,
|
|
558
|
+
lineText: rawLine,
|
|
559
|
+
action: `Warning: Empty heading name at level ${hashCount}`,
|
|
560
|
+
stackDepth: stack.length,
|
|
561
|
+
currentStack: getStackNames(),
|
|
562
|
+
status: "warning"
|
|
563
|
+
});
|
|
564
|
+
}
|
|
565
|
+
continue;
|
|
74
566
|
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
567
|
+
}
|
|
568
|
+
const newNode = isExplicitArray ? [] : {};
|
|
569
|
+
if (activeParentItem && activeParentItem.isExplicitArray) {
|
|
570
|
+
activeParent.push(newNode);
|
|
571
|
+
if (!noTrace) {
|
|
78
572
|
trace.push({
|
|
79
573
|
lineNumber,
|
|
80
574
|
lineText: rawLine,
|
|
81
|
-
action: `
|
|
575
|
+
action: `Pushed new item into explicit array "${activeParentItem.key}" via heading "${actualHeadingName}"`,
|
|
82
576
|
stackDepth: stack.length,
|
|
83
577
|
currentStack: getStackNames(),
|
|
84
578
|
status: "success"
|
|
85
579
|
});
|
|
580
|
+
}
|
|
581
|
+
} else if (Array.isArray(activeParent)) {
|
|
582
|
+
if (actualHeadingName === "") {
|
|
583
|
+
activeParent.push(newNode);
|
|
584
|
+
if (!noTrace) {
|
|
585
|
+
trace.push({
|
|
586
|
+
lineNumber,
|
|
587
|
+
lineText: rawLine,
|
|
588
|
+
action: `Pushed anonymous object directly into parent Array`,
|
|
589
|
+
stackDepth: stack.length,
|
|
590
|
+
currentStack: getStackNames(),
|
|
591
|
+
status: "success"
|
|
592
|
+
});
|
|
593
|
+
}
|
|
86
594
|
} else {
|
|
87
|
-
activeParent[
|
|
595
|
+
activeParent.push({ [actualHeadingName]: newNode });
|
|
596
|
+
if (!noTrace) {
|
|
597
|
+
trace.push({
|
|
598
|
+
lineNumber,
|
|
599
|
+
lineText: rawLine,
|
|
600
|
+
action: `Created heading "${actualHeadingName}" at level ${hashCount} and pushed inside parent Array`,
|
|
601
|
+
stackDepth: stack.length,
|
|
602
|
+
currentStack: getStackNames(),
|
|
603
|
+
status: "success"
|
|
604
|
+
});
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
} else {
|
|
608
|
+
activeParent[actualHeadingName] = newNode;
|
|
609
|
+
if (!noTrace) {
|
|
88
610
|
trace.push({
|
|
89
611
|
lineNumber,
|
|
90
612
|
lineText: rawLine,
|
|
91
|
-
action: `Created heading "${
|
|
613
|
+
action: `Created heading "${actualHeadingName}" at level ${hashCount} in parent Object${isExplicitArray ? " as Array" : ""}`,
|
|
92
614
|
stackDepth: stack.length,
|
|
93
615
|
currentStack: getStackNames(),
|
|
94
616
|
status: "success"
|
|
95
617
|
});
|
|
96
618
|
}
|
|
97
|
-
stack.push({
|
|
98
|
-
level: hashCount,
|
|
99
|
-
key: headingName,
|
|
100
|
-
parent: activeParent,
|
|
101
|
-
value: newNode,
|
|
102
|
-
type: "object"
|
|
103
|
-
});
|
|
104
|
-
continue;
|
|
105
619
|
}
|
|
620
|
+
stack.push({
|
|
621
|
+
level: hashCount,
|
|
622
|
+
key: actualHeadingName,
|
|
623
|
+
parent: activeParent,
|
|
624
|
+
value: newNode,
|
|
625
|
+
type: isExplicitArray ? "array" : "object",
|
|
626
|
+
isExplicitArray
|
|
627
|
+
});
|
|
628
|
+
continue;
|
|
106
629
|
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
630
|
+
if (firstChar === 42 || firstChar === 45 || firstChar === 43) {
|
|
631
|
+
let bulletValIdx = startIdx + 1;
|
|
632
|
+
while (bulletValIdx <= endIdx) {
|
|
633
|
+
const code = rawLine.charCodeAt(bulletValIdx);
|
|
634
|
+
if (code === 32 || code === 9) {
|
|
635
|
+
bulletValIdx++;
|
|
636
|
+
} else {
|
|
637
|
+
break;
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
const bulletValStr = bulletValIdx <= endIdx ? rawLine.slice(bulletValIdx, endIdx + 1) : "";
|
|
641
|
+
const { value, nextLineIndex } = parseValueWithMultiline(bulletValStr, lines, i);
|
|
642
|
+
i = nextLineIndex;
|
|
111
643
|
if (stack.length === 0) {
|
|
112
644
|
if (!root._items) {
|
|
113
645
|
root._items = [];
|
|
114
646
|
}
|
|
115
647
|
root._items.push(value);
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
648
|
+
if (!noTrace) {
|
|
649
|
+
trace.push({
|
|
650
|
+
lineNumber,
|
|
651
|
+
lineText: rawLine,
|
|
652
|
+
action: `No active heading. Pushed bullet item to root implicit list "_items"`,
|
|
653
|
+
stackDepth: stack.length,
|
|
654
|
+
currentStack: getStackNames(),
|
|
655
|
+
status: "info"
|
|
656
|
+
});
|
|
657
|
+
}
|
|
124
658
|
continue;
|
|
125
659
|
}
|
|
126
660
|
const activeItem = stack[stack.length - 1];
|
|
127
661
|
if (activeItem.type !== "array") {
|
|
128
|
-
|
|
129
|
-
const
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
662
|
+
let hasKeys = false;
|
|
663
|
+
for (const k in activeItem.value) {
|
|
664
|
+
if (Object.prototype.hasOwnProperty.call(activeItem.value, k)) {
|
|
665
|
+
hasKeys = true;
|
|
666
|
+
break;
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
if (!hasKeys) {
|
|
670
|
+
const parent = activeItem.parent;
|
|
671
|
+
const key = activeItem.key;
|
|
672
|
+
activeItem.type = "array";
|
|
673
|
+
activeItem.value = [];
|
|
674
|
+
if (Array.isArray(parent)) {
|
|
675
|
+
parent[parent.length - 1] = { [key]: activeItem.value };
|
|
676
|
+
} else {
|
|
677
|
+
parent[key] = activeItem.value;
|
|
678
|
+
}
|
|
679
|
+
if (!noTrace) {
|
|
680
|
+
trace.push({
|
|
681
|
+
lineNumber,
|
|
682
|
+
lineText: rawLine,
|
|
683
|
+
action: `Array trigger: Converted heading "${key}" to an Array because it was an empty Object`,
|
|
684
|
+
stackDepth: stack.length,
|
|
685
|
+
currentStack: getStackNames(),
|
|
686
|
+
status: "info"
|
|
687
|
+
});
|
|
688
|
+
}
|
|
689
|
+
activeItem.value.push(value);
|
|
690
|
+
if (!noTrace) {
|
|
691
|
+
trace.push({
|
|
692
|
+
lineNumber,
|
|
693
|
+
lineText: rawLine,
|
|
694
|
+
action: `Pushed item "${value}" (type: ${typeof value}) into array "${activeItem.key}"`,
|
|
695
|
+
stackDepth: stack.length,
|
|
696
|
+
currentStack: getStackNames(),
|
|
697
|
+
status: "success"
|
|
698
|
+
});
|
|
699
|
+
}
|
|
134
700
|
} else {
|
|
135
|
-
|
|
701
|
+
if (!activeItem.value._items) {
|
|
702
|
+
activeItem.value._items = [];
|
|
703
|
+
}
|
|
704
|
+
activeItem.value._items.push(value);
|
|
705
|
+
if (!noTrace) {
|
|
706
|
+
trace.push({
|
|
707
|
+
lineNumber,
|
|
708
|
+
lineText: rawLine,
|
|
709
|
+
action: `Pushed bullet item "${value}" to implicit list "_items" inside non-empty Object under heading "${activeItem.key}"`,
|
|
710
|
+
stackDepth: stack.length,
|
|
711
|
+
currentStack: getStackNames(),
|
|
712
|
+
status: "info"
|
|
713
|
+
});
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
} else {
|
|
717
|
+
activeItem.value.push(value);
|
|
718
|
+
if (!noTrace) {
|
|
719
|
+
trace.push({
|
|
720
|
+
lineNumber,
|
|
721
|
+
lineText: rawLine,
|
|
722
|
+
action: `Pushed item "${value}" (type: ${typeof value}) into array "${activeItem.key}"`,
|
|
723
|
+
stackDepth: stack.length,
|
|
724
|
+
currentStack: getStackNames(),
|
|
725
|
+
status: "success"
|
|
726
|
+
});
|
|
136
727
|
}
|
|
137
|
-
trace.push({
|
|
138
|
-
lineNumber,
|
|
139
|
-
lineText: rawLine,
|
|
140
|
-
action: `Array trigger: Converted heading "${key}" to an Array`,
|
|
141
|
-
stackDepth: stack.length,
|
|
142
|
-
currentStack: getStackNames(),
|
|
143
|
-
status: "info"
|
|
144
|
-
});
|
|
145
728
|
}
|
|
146
|
-
activeItem.value.push(value);
|
|
147
|
-
trace.push({
|
|
148
|
-
lineNumber,
|
|
149
|
-
lineText: rawLine,
|
|
150
|
-
action: `Pushed item "${value}" (type: ${typeof value}) into array "${activeItem.key}"`,
|
|
151
|
-
stackDepth: stack.length,
|
|
152
|
-
currentStack: getStackNames(),
|
|
153
|
-
status: "success"
|
|
154
|
-
});
|
|
155
729
|
continue;
|
|
156
730
|
}
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
731
|
+
const colonIndex = findColonIndex(rawLine, startIdx);
|
|
732
|
+
if (colonIndex !== -1 && colonIndex <= endIdx) {
|
|
733
|
+
let kEnd = colonIndex - 1;
|
|
734
|
+
while (kEnd >= startIdx) {
|
|
735
|
+
const code = rawLine.charCodeAt(kEnd);
|
|
736
|
+
if (code === 32 || code === 9) {
|
|
737
|
+
kEnd--;
|
|
738
|
+
} else {
|
|
739
|
+
break;
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
const key = startIdx <= kEnd ? rawLine.slice(startIdx, kEnd + 1) : "";
|
|
743
|
+
let vStart = colonIndex + 1;
|
|
744
|
+
while (vStart <= endIdx) {
|
|
745
|
+
const code = rawLine.charCodeAt(vStart);
|
|
746
|
+
if (code === 32 || code === 9) {
|
|
747
|
+
vStart++;
|
|
748
|
+
} else {
|
|
749
|
+
break;
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
const valStr = vStart <= endIdx ? rawLine.slice(vStart, endIdx + 1) : "";
|
|
753
|
+
const { value: parsedVal, nextLineIndex } = parseValueWithMultiline(valStr, lines, i);
|
|
754
|
+
i = nextLineIndex;
|
|
162
755
|
if (stack.length === 0) {
|
|
163
756
|
root[key] = parsedVal;
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
757
|
+
if (!noTrace) {
|
|
758
|
+
trace.push({
|
|
759
|
+
lineNumber,
|
|
760
|
+
lineText: rawLine,
|
|
761
|
+
action: `Set root key "${key}" to "${parsedVal}"`,
|
|
762
|
+
stackDepth: stack.length,
|
|
763
|
+
currentStack: getStackNames(),
|
|
764
|
+
status: "success"
|
|
765
|
+
});
|
|
766
|
+
}
|
|
172
767
|
continue;
|
|
173
768
|
}
|
|
174
769
|
const activeItem = stack[stack.length - 1];
|
|
175
770
|
if (activeItem.type === "array") {
|
|
771
|
+
if (!noTrace) {
|
|
772
|
+
trace.push({
|
|
773
|
+
lineNumber,
|
|
774
|
+
lineText: rawLine,
|
|
775
|
+
action: `Error: Key-value "${key}" encountered inside array "${activeItem.key}"`,
|
|
776
|
+
stackDepth: stack.length,
|
|
777
|
+
currentStack: getStackNames(),
|
|
778
|
+
status: "error"
|
|
779
|
+
});
|
|
780
|
+
}
|
|
781
|
+
continue;
|
|
782
|
+
}
|
|
783
|
+
activeItem.value[key] = parsedVal;
|
|
784
|
+
if (!noTrace) {
|
|
176
785
|
trace.push({
|
|
177
786
|
lineNumber,
|
|
178
787
|
lineText: rawLine,
|
|
179
|
-
action: `
|
|
788
|
+
action: `Set key "${key}" to "${parsedVal}" in active heading "${activeItem.key}"`,
|
|
180
789
|
stackDepth: stack.length,
|
|
181
790
|
currentStack: getStackNames(),
|
|
182
|
-
status: "
|
|
791
|
+
status: "success"
|
|
183
792
|
});
|
|
184
|
-
continue;
|
|
185
793
|
}
|
|
186
|
-
|
|
794
|
+
continue;
|
|
795
|
+
}
|
|
796
|
+
if (!noTrace) {
|
|
187
797
|
trace.push({
|
|
188
798
|
lineNumber,
|
|
189
799
|
lineText: rawLine,
|
|
190
|
-
action: `
|
|
800
|
+
action: `Unparsed content: Line skipped or treated as plain text`,
|
|
191
801
|
stackDepth: stack.length,
|
|
192
802
|
currentStack: getStackNames(),
|
|
193
|
-
status: "
|
|
803
|
+
status: "warning"
|
|
194
804
|
});
|
|
195
|
-
continue;
|
|
196
805
|
}
|
|
197
|
-
trace.push({
|
|
198
|
-
lineNumber,
|
|
199
|
-
lineText: rawLine,
|
|
200
|
-
action: `Unparsed content: Line skipped or treated as plain text`,
|
|
201
|
-
stackDepth: stack.length,
|
|
202
|
-
currentStack: getStackNames(),
|
|
203
|
-
status: "warning"
|
|
204
|
-
});
|
|
205
806
|
}
|
|
206
807
|
const endTime = typeof performance !== "undefined" ? performance.now() : Date.now();
|
|
207
808
|
const parseTimeMs = Number((endTime - startTime).toFixed(3));
|
|
208
809
|
const charCount = text.length;
|
|
209
810
|
const estimatedTokens = Math.ceil(charCount / 4.1);
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
811
|
+
let jsonCharCount = 0;
|
|
812
|
+
let jsonEstimatedTokens = 0;
|
|
813
|
+
let tokenSavingsPercent = 0;
|
|
814
|
+
if (!noTrace) {
|
|
815
|
+
const jsonString = JSON.stringify(root, null, 2);
|
|
816
|
+
jsonCharCount = jsonString.length;
|
|
817
|
+
jsonEstimatedTokens = Math.ceil(jsonCharCount / 3.7);
|
|
818
|
+
tokenSavingsPercent = Number(((jsonEstimatedTokens - estimatedTokens) / jsonEstimatedTokens * 100).toFixed(1));
|
|
819
|
+
}
|
|
214
820
|
return {
|
|
215
821
|
data: root,
|
|
216
822
|
trace,
|
|
@@ -225,14 +831,35 @@ function parseWithTrace(text) {
|
|
|
225
831
|
}
|
|
226
832
|
};
|
|
227
833
|
}
|
|
228
|
-
function stringify(obj, level = 0) {
|
|
834
|
+
function stringify(obj, level = 0, parentKey) {
|
|
229
835
|
if (obj === null || obj === void 0) return "";
|
|
230
836
|
let output = "";
|
|
231
837
|
const hashes = (lvl) => "#".repeat(lvl);
|
|
232
838
|
if (Array.isArray(obj)) {
|
|
839
|
+
if (level === 0) {
|
|
840
|
+
output += "[]\n\n";
|
|
841
|
+
}
|
|
842
|
+
let itemName = "Item";
|
|
843
|
+
if (parentKey) {
|
|
844
|
+
if (parentKey.endsWith("ies")) {
|
|
845
|
+
itemName = parentKey.slice(0, -3) + "y";
|
|
846
|
+
} else if (parentKey.endsWith("s") && !parentKey.endsWith("ss")) {
|
|
847
|
+
itemName = parentKey.slice(0, -1);
|
|
848
|
+
} else {
|
|
849
|
+
itemName = parentKey;
|
|
850
|
+
}
|
|
851
|
+
itemName = itemName.charAt(0).toUpperCase() + itemName.slice(1);
|
|
852
|
+
}
|
|
233
853
|
for (const item of obj) {
|
|
234
854
|
if (typeof item === "object" && item !== null) {
|
|
235
|
-
|
|
855
|
+
const nextLevel = level + 1;
|
|
856
|
+
output += `${hashes(nextLevel)} ${itemName}
|
|
857
|
+
`;
|
|
858
|
+
const nestedString = stringify(item, nextLevel);
|
|
859
|
+
if (nestedString) {
|
|
860
|
+
output += nestedString;
|
|
861
|
+
}
|
|
862
|
+
output += "\n";
|
|
236
863
|
} else {
|
|
237
864
|
output += `* ${stringifyPrimitiveValue(item)}
|
|
238
865
|
`;
|
|
@@ -251,10 +878,12 @@ function stringify(obj, level = 0) {
|
|
|
251
878
|
}
|
|
252
879
|
for (const key of complex) {
|
|
253
880
|
const nextLevel = level + 1;
|
|
254
|
-
output += `${hashes(nextLevel)} ${key}
|
|
255
|
-
`;
|
|
256
881
|
const val = obj[key];
|
|
257
|
-
const
|
|
882
|
+
const isArrayOfObjects = Array.isArray(val) && val.some((item) => typeof item === "object" && item !== null);
|
|
883
|
+
const headingNameSuffix = isArrayOfObjects ? "[]" : "";
|
|
884
|
+
output += `${hashes(nextLevel)} ${key}${headingNameSuffix}
|
|
885
|
+
`;
|
|
886
|
+
const nestedString = stringify(val, nextLevel, key);
|
|
258
887
|
if (nestedString) {
|
|
259
888
|
output += nestedString;
|
|
260
889
|
}
|
|
@@ -264,11 +893,15 @@ function stringify(obj, level = 0) {
|
|
|
264
893
|
return output.trim() + "\n";
|
|
265
894
|
}
|
|
266
895
|
export {
|
|
896
|
+
fastParseWithTrace,
|
|
267
897
|
parse,
|
|
268
898
|
parse as parseMSON,
|
|
899
|
+
parseWithTrace as parseMaSON,
|
|
269
900
|
parsePrimitiveValue,
|
|
901
|
+
parseValueWithMultiline,
|
|
270
902
|
parseWithTrace,
|
|
271
903
|
stringify,
|
|
272
904
|
stringify as stringifyMSON,
|
|
905
|
+
stringify as stringifyMaSON,
|
|
273
906
|
stringifyPrimitiveValue
|
|
274
907
|
};
|