@zenoaihq/tson 1.0.1 → 1.1.0

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/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // src/utils.ts
2
- var SPECIAL_CHARS = /* @__PURE__ */ new Set([",", "|", "@", "#", "{", "}", "[", "]", "\n", "\r", " ", " "]);
2
+ var SPECIAL_CHARS = /* @__PURE__ */ new Set([",", "|", "@", "#", "{", "}", "[", "]", "\n", "\r", " ", " ", '"', "(", ")"]);
3
3
  function needsQuoting(value) {
4
4
  if (value.length === 0) {
5
5
  return true;
@@ -31,7 +31,36 @@ function escapeString(value) {
31
31
  return value.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/\t/g, "\\t");
32
32
  }
33
33
  function unescapeString(value) {
34
- return value.replace(/\\t/g, " ").replace(/\\r/g, "\r").replace(/\\n/g, "\n").replace(/\\"/g, '"').replace(/\\\\/g, "\\");
34
+ const result = [];
35
+ let i = 0;
36
+ while (i < value.length) {
37
+ if (value[i] === "\\" && i + 1 < value.length) {
38
+ const nextChar = value[i + 1];
39
+ if (nextChar === "\\") {
40
+ result.push("\\");
41
+ i += 2;
42
+ } else if (nextChar === '"') {
43
+ result.push('"');
44
+ i += 2;
45
+ } else if (nextChar === "n") {
46
+ result.push("\n");
47
+ i += 2;
48
+ } else if (nextChar === "r") {
49
+ result.push("\r");
50
+ i += 2;
51
+ } else if (nextChar === "t") {
52
+ result.push(" ");
53
+ i += 2;
54
+ } else {
55
+ result.push(value[i]);
56
+ i += 1;
57
+ }
58
+ } else {
59
+ result.push(value[i]);
60
+ i += 1;
61
+ }
62
+ }
63
+ return result.join("");
35
64
  }
36
65
  function formatPrimitive(value) {
37
66
  if (value === null) {
@@ -160,11 +189,11 @@ function splitByDelimiter(text, delimiter) {
160
189
  }
161
190
  function parseKeySchema(keyString) {
162
191
  const trimmed = keyString.trim();
192
+ if (trimmed.startsWith('"') && trimmed.endsWith('"')) {
193
+ return { keyName: unescapeString(trimmed.slice(1, -1)), schema: null, count: null };
194
+ }
163
195
  if (!trimmed.includes("(")) {
164
- if (trimmed.startsWith('"') && trimmed.endsWith('"')) {
165
- return { keyName: unescapeString(trimmed.slice(1, -1)), schema: null };
166
- }
167
- return { keyName: trimmed, schema: null };
196
+ return { keyName: trimmed, schema: null, count: null };
168
197
  }
169
198
  const parenIdx = trimmed.indexOf("(");
170
199
  let keyName = trimmed.slice(0, parenIdx).trim();
@@ -178,14 +207,54 @@ function parseKeySchema(keyString) {
178
207
  if (schemaStr.startsWith("@")) {
179
208
  schemaStr = schemaStr.slice(1);
180
209
  }
210
+ let nestedCount = null;
211
+ const hashIdx = findTrailingHash(schemaStr);
212
+ if (hashIdx !== -1) {
213
+ const countPart = schemaStr.slice(hashIdx + 1).trim();
214
+ const parsedCount = parseInt(countPart, 10);
215
+ if (!isNaN(parsedCount)) {
216
+ nestedCount = parsedCount;
217
+ schemaStr = schemaStr.slice(0, hashIdx).trim();
218
+ }
219
+ }
181
220
  const schemaKeys = splitByDelimiter(schemaStr, ",");
182
- return { keyName, schema: schemaKeys };
221
+ return { keyName, schema: schemaKeys, count: nestedCount };
222
+ }
223
+ function findTrailingHash(schemaStr) {
224
+ let inQuotes = false;
225
+ let depthParen = 0;
226
+ for (let i = schemaStr.length - 1; i >= 0; i--) {
227
+ const char = schemaStr[i];
228
+ if (char === '"') {
229
+ let backslashCount = 0;
230
+ for (let j = i - 1; j >= 0; j--) {
231
+ if (schemaStr[j] === "\\") {
232
+ backslashCount++;
233
+ } else {
234
+ break;
235
+ }
236
+ }
237
+ if (backslashCount % 2 === 0) {
238
+ inQuotes = !inQuotes;
239
+ }
240
+ }
241
+ if (!inQuotes) {
242
+ if (char === ")") {
243
+ depthParen++;
244
+ } else if (char === "(") {
245
+ depthParen--;
246
+ } else if (char === "#" && depthParen === 0) {
247
+ return i;
248
+ }
249
+ }
250
+ }
251
+ return -1;
183
252
  }
184
253
  function buildSchemaMap(keys) {
185
254
  const schemaMap = {};
186
255
  for (const key of keys) {
187
- const { keyName, schema } = parseKeySchema(key);
188
- schemaMap[keyName] = schema;
256
+ const { keyName, schema, count } = parseKeySchema(key);
257
+ schemaMap[keyName] = { schema, count };
189
258
  }
190
259
  return schemaMap;
191
260
  }
@@ -300,9 +369,21 @@ function serializeTabular(arr) {
300
369
  keyStr = `"${escapeString(keyStr)}"`;
301
370
  }
302
371
  if (key in nestedSchemas) {
303
- const schemaKeys = nestedSchemas[key];
304
- const schemaStr = schemaKeys.join(",");
305
- keyStr = `${keyStr}(@${schemaStr})`;
372
+ const schemaInfo = nestedSchemas[key];
373
+ const schemaKeys = schemaInfo.schema;
374
+ const nestedCount = schemaInfo.count;
375
+ const formattedSchemaKeys = schemaKeys.map((sk) => {
376
+ if (needsQuoting(sk)) {
377
+ return `"${escapeString(sk)}"`;
378
+ }
379
+ return sk;
380
+ });
381
+ const schemaStr = formattedSchemaKeys.join(",");
382
+ if (nestedCount !== null) {
383
+ keyStr = `${keyStr}(@${schemaStr}#${nestedCount})`;
384
+ } else {
385
+ keyStr = `${keyStr}(@${schemaStr})`;
386
+ }
306
387
  }
307
388
  keyParts.push(keyStr);
308
389
  }
@@ -313,7 +394,12 @@ function serializeTabular(arr) {
313
394
  for (const key of keys) {
314
395
  const value = obj[key];
315
396
  if (key in nestedSchemas) {
316
- valueParts.push(serializeSchematizedObject(value, nestedSchemas[key]));
397
+ const schemaInfo = nestedSchemas[key];
398
+ if (schemaInfo.count !== null) {
399
+ valueParts.push(serializeSchematizedArray(value, schemaInfo.schema));
400
+ } else {
401
+ valueParts.push(serializeSchematizedObject(value, schemaInfo.schema));
402
+ }
317
403
  } else {
318
404
  valueParts.push(serializeValue(value));
319
405
  }
@@ -327,19 +413,49 @@ function detectNestedSchemas(arr, keys) {
327
413
  const nestedSchemas = {};
328
414
  for (const key of keys) {
329
415
  const values = arr.map((obj) => obj[key]);
330
- if (!values.every((v) => typeof v === "object" && v !== null && !Array.isArray(v))) {
331
- continue;
332
- }
333
- if (values.length === 0) {
416
+ if (values.every((v) => typeof v === "object" && v !== null && !Array.isArray(v))) {
417
+ if (values.length === 0) {
418
+ continue;
419
+ }
420
+ const firstKeys = Object.keys(values[0]);
421
+ const allSame = values.slice(1).every((v) => {
422
+ const objKeys = Object.keys(v);
423
+ return objKeys.length === firstKeys.length && objKeys.every((k, i) => k === firstKeys[i]);
424
+ });
425
+ if (allSame) {
426
+ nestedSchemas[key] = { schema: firstKeys, count: null };
427
+ }
334
428
  continue;
335
429
  }
336
- const firstKeys = Object.keys(values[0]);
337
- const allSame = values.slice(1).every((v) => {
338
- const objKeys = Object.keys(v);
339
- return objKeys.length === firstKeys.length && objKeys.every((k, i) => k === firstKeys[i]);
340
- });
341
- if (allSame) {
342
- nestedSchemas[key] = firstKeys;
430
+ if (values.every((v) => Array.isArray(v))) {
431
+ if (values.length === 0) {
432
+ continue;
433
+ }
434
+ let allUniform = true;
435
+ let firstSchema = null;
436
+ let arrayCount = null;
437
+ for (const v of values) {
438
+ const arr2 = v;
439
+ if (!isUniformObjectArray(arr2)) {
440
+ allUniform = false;
441
+ break;
442
+ }
443
+ if (arr2.length === 0) {
444
+ continue;
445
+ }
446
+ const vSchema = Object.keys(arr2[0]);
447
+ const vCount = arr2.length;
448
+ if (firstSchema === null) {
449
+ firstSchema = vSchema;
450
+ arrayCount = vCount;
451
+ } else if (vSchema.length !== firstSchema.length || !vSchema.every((k, i) => k === firstSchema[i]) || vCount !== arrayCount) {
452
+ allUniform = false;
453
+ break;
454
+ }
455
+ }
456
+ if (allUniform && firstSchema !== null) {
457
+ nestedSchemas[key] = { schema: firstSchema, count: arrayCount };
458
+ }
343
459
  }
344
460
  }
345
461
  return nestedSchemas;
@@ -355,6 +471,16 @@ function serializeSchematizedObject(obj, schema) {
355
471
  }
356
472
  return "{" + valueParts.join(",") + "}";
357
473
  }
474
+ function serializeSchematizedArray(arr, schema) {
475
+ if (arr.length === 0) {
476
+ return "[]";
477
+ }
478
+ const objParts = [];
479
+ for (const obj of arr) {
480
+ objParts.push(serializeSchematizedObject(obj, schema));
481
+ }
482
+ return "[" + objParts.join(",") + "]";
483
+ }
358
484
 
359
485
  // src/deserializer.ts
360
486
  function loads(s) {
@@ -407,8 +533,14 @@ function parseKeyedObject(content) {
407
533
  }
408
534
  const keysPart = parts[0];
409
535
  const { keys, count } = parseKeys(keysPart);
536
+ if (keys.length === 0 && count !== null) {
537
+ return Array.from({ length: count }, () => ({}));
538
+ }
410
539
  const schemaMap = buildSchemaMap(keys);
411
540
  const fieldNames = keys.map((k) => parseKeySchema(k).keyName);
541
+ if (keys.length === 0) {
542
+ return {};
543
+ }
412
544
  if (parts.length === 1) {
413
545
  throw new Error("Invalid object format: missing values");
414
546
  }
@@ -431,9 +563,11 @@ function parseSingleObject(fieldNames, valuesStr, schemaMap) {
431
563
  for (let i = 0; i < fieldNames.length; i++) {
432
564
  const fieldName = fieldNames[i];
433
565
  const valueStr = values[i];
434
- const schema = schemaMap[fieldName];
566
+ const schemaInfo = schemaMap[fieldName];
567
+ const schema = schemaInfo?.schema;
568
+ const count = schemaInfo?.count;
435
569
  if (schema) {
436
- obj[fieldName] = parseSchematizedValue(valueStr, schema);
570
+ obj[fieldName] = parseSchematizedValue(valueStr, schema, count);
437
571
  } else {
438
572
  obj[fieldName] = parseValue(valueStr);
439
573
  }
@@ -456,7 +590,36 @@ function parseTabularArray(fieldNames, rowParts, schemaMap, expectedCount) {
456
590
  }
457
591
  return result;
458
592
  }
459
- function parseSchematizedValue(valueStr, schema) {
593
+ function parseSchematizedValue(valueStr, schema, expectedCount = null) {
594
+ const trimmed = valueStr.trim();
595
+ if (expectedCount !== null) {
596
+ return parseSchematizedArray(trimmed, schema, expectedCount);
597
+ }
598
+ return parseSingleSchematizedObject(trimmed, schema);
599
+ }
600
+ function parseSchematizedArray(valueStr, schema, expectedCount) {
601
+ const trimmed = valueStr.trim();
602
+ if (!trimmed.startsWith("[") || !trimmed.endsWith("]")) {
603
+ throw new Error(`Schematized array must be wrapped in brackets: ${valueStr}`);
604
+ }
605
+ const content = trimmed.slice(1, -1).trim();
606
+ if (content.length === 0) {
607
+ return [];
608
+ }
609
+ const parts = splitByDelimiter(content, ",");
610
+ if (parts.length !== expectedCount) {
611
+ throw new Error(
612
+ `Array count mismatch: expected ${expectedCount} objects but got ${parts.length}`
613
+ );
614
+ }
615
+ const result = [];
616
+ for (const part of parts) {
617
+ const obj = parseSingleSchematizedObject(part.trim(), schema);
618
+ result.push(obj);
619
+ }
620
+ return result;
621
+ }
622
+ function parseSingleSchematizedObject(valueStr, schema) {
460
623
  const trimmed = valueStr.trim();
461
624
  if (!trimmed.startsWith("{") || !trimmed.endsWith("}")) {
462
625
  throw new Error(`Schematized value must be wrapped in braces: ${valueStr}`);
@@ -476,12 +639,14 @@ function parseSchematizedValue(valueStr, schema) {
476
639
  const obj = {};
477
640
  for (let i = 0; i < fieldNames.length; i++) {
478
641
  const fieldName = fieldNames[i];
479
- const valueStr2 = values[i];
480
- const nestedSchema = nestedSchemaMap[fieldName];
642
+ const valStr = values[i];
643
+ const schemaInfo = nestedSchemaMap[fieldName];
644
+ const nestedSchema = schemaInfo?.schema;
645
+ const nestedCount = schemaInfo?.count;
481
646
  if (nestedSchema) {
482
- obj[fieldName] = parseSchematizedValue(valueStr2, nestedSchema);
647
+ obj[fieldName] = parseSchematizedValue(valStr, nestedSchema, nestedCount);
483
648
  } else {
484
- obj[fieldName] = parseValue(valueStr2);
649
+ obj[fieldName] = parseValue(valStr);
485
650
  }
486
651
  }
487
652
  return obj;
@@ -505,6 +670,203 @@ function parseArray(text) {
505
670
  return result;
506
671
  }
507
672
 
508
- export { buildSchemaMap, dump, dumps, escapeString, formatPrimitive, isUniformObjectArray, load, loads, looksLikeNumber, needsQuoting, parseKeySchema, parseKeys, parsePrimitive, splitByDelimiter, unescapeString };
673
+ // src/prettify.ts
674
+ function prettify(tsonStr, indent = " ") {
675
+ if (!tsonStr || !tsonStr.trim()) {
676
+ return tsonStr;
677
+ }
678
+ return prettifyValue(tsonStr.trim(), indent, 0);
679
+ }
680
+ function minify(tsonStr) {
681
+ if (!tsonStr) {
682
+ return tsonStr;
683
+ }
684
+ const lines = tsonStr.split("\n");
685
+ const result = [];
686
+ for (const line of lines) {
687
+ result.push(line.trim());
688
+ }
689
+ return result.join("");
690
+ }
691
+ function prettifyValue(text, indent, depth) {
692
+ text = text.trim();
693
+ if (!text) {
694
+ return text;
695
+ }
696
+ if (text.startsWith("{@")) {
697
+ return prettifyObject(text, indent, depth);
698
+ }
699
+ if (text.startsWith("{")) {
700
+ return text;
701
+ }
702
+ if (text.startsWith("[")) {
703
+ return prettifyArray(text, indent, depth);
704
+ }
705
+ return text;
706
+ }
707
+ function prettifyObject(text, indent, depth) {
708
+ if (!text.startsWith("{@") || !text.endsWith("}")) {
709
+ return text;
710
+ }
711
+ const content = text.slice(2, -1);
712
+ if (!content) {
713
+ return "{@}";
714
+ }
715
+ const parts = splitTopLevel(content, "|");
716
+ if (parts.length === 0) {
717
+ return text;
718
+ }
719
+ const schema = parts[0];
720
+ const valueRows = parts.slice(1);
721
+ const nextIndent = indent.repeat(depth + 1);
722
+ if (valueRows.length === 0) {
723
+ return `{@${schema}}`;
724
+ }
725
+ const lines = [`{@${schema}`];
726
+ for (const row of valueRows) {
727
+ lines.push(`${nextIndent}|${row}`);
728
+ }
729
+ lines[lines.length - 1] = lines[lines.length - 1] + "}";
730
+ return lines.join("\n");
731
+ }
732
+ function prettifyArray(text, indent, depth) {
733
+ if (!text.startsWith("[") || !text.endsWith("]")) {
734
+ return text;
735
+ }
736
+ const content = text.slice(1, -1);
737
+ if (!content) {
738
+ return "[]";
739
+ }
740
+ const elements = splitTopLevel(content, ",");
741
+ if (elements.length <= 1) {
742
+ return text;
743
+ }
744
+ const nextIndent = indent.repeat(depth + 1);
745
+ const lines = [];
746
+ for (let i = 0; i < elements.length; i++) {
747
+ const prettified = prettifyValue(elements[i].trim(), indent, depth + 1);
748
+ if (i === 0) {
749
+ lines.push(`[${prettified}`);
750
+ } else {
751
+ lines.push(`${nextIndent},${prettified}`);
752
+ }
753
+ }
754
+ lines[lines.length - 1] = lines[lines.length - 1] + "]";
755
+ return lines.join("\n");
756
+ }
757
+ function splitTopLevel(text, delimiter) {
758
+ const parts = [];
759
+ const current = [];
760
+ let depth = 0;
761
+ let inString = false;
762
+ let escapeNext = false;
763
+ for (let i = 0; i < text.length; i++) {
764
+ const char = text[i];
765
+ if (escapeNext) {
766
+ current.push(char);
767
+ escapeNext = false;
768
+ continue;
769
+ }
770
+ if (char === "\\") {
771
+ current.push(char);
772
+ escapeNext = true;
773
+ continue;
774
+ }
775
+ if (char === '"') {
776
+ inString = !inString;
777
+ current.push(char);
778
+ continue;
779
+ }
780
+ if (inString) {
781
+ current.push(char);
782
+ continue;
783
+ }
784
+ if (char === "{" || char === "[") {
785
+ depth++;
786
+ current.push(char);
787
+ } else if (char === "}" || char === "]") {
788
+ depth--;
789
+ current.push(char);
790
+ } else if (char === delimiter && depth === 0) {
791
+ parts.push(current.join(""));
792
+ current.length = 0;
793
+ } else {
794
+ current.push(char);
795
+ }
796
+ }
797
+ if (current.length > 0) {
798
+ parts.push(current.join(""));
799
+ }
800
+ return parts;
801
+ }
802
+
803
+ // src/fileio.ts
804
+ async function loadJson(filepath) {
805
+ const fs = await import('fs/promises');
806
+ const content = await fs.readFile(filepath, "utf-8");
807
+ return JSON.parse(content);
808
+ }
809
+ async function loadTson(filepath) {
810
+ const fs = await import('fs/promises');
811
+ const content = await fs.readFile(filepath, "utf-8");
812
+ return loads(content);
813
+ }
814
+ async function saveTson(data, filepath, options = {}) {
815
+ const fs = await import('fs/promises');
816
+ let tsonStr = dumps(data);
817
+ if (options.format === "pretty") {
818
+ tsonStr = prettify(tsonStr, options.indent || " ");
819
+ }
820
+ await fs.writeFile(filepath, tsonStr, "utf-8");
821
+ }
822
+ async function saveTsonString(tsonStr, filepath, options = {}) {
823
+ const fs = await import('fs/promises');
824
+ if (options.format === "pretty") {
825
+ tsonStr = prettify(tsonStr, options.indent || " ");
826
+ } else if (options.format === "compact") {
827
+ tsonStr = minify(tsonStr);
828
+ }
829
+ await fs.writeFile(filepath, tsonStr, "utf-8");
830
+ }
831
+ async function jsonToTson(inputPath, outputPath, options = {}) {
832
+ const data = await loadJson(inputPath);
833
+ let tsonStr = dumps(data);
834
+ if (options.format === "pretty") {
835
+ tsonStr = prettify(tsonStr);
836
+ }
837
+ if (outputPath) {
838
+ await saveTsonString(tsonStr, outputPath);
839
+ }
840
+ return tsonStr;
841
+ }
842
+ async function tsonToJson(inputPath, outputPath, options = {}) {
843
+ const data = await loadTson(inputPath);
844
+ const jsonStr = JSON.stringify(data, null, options.indent ?? 2);
845
+ if (outputPath) {
846
+ const fs = await import('fs/promises');
847
+ await fs.writeFile(outputPath, jsonStr, "utf-8");
848
+ }
849
+ return jsonStr;
850
+ }
851
+ async function readTsonString(filepath) {
852
+ const fs = await import('fs/promises');
853
+ return fs.readFile(filepath, "utf-8");
854
+ }
855
+ async function prettifyFile(inputPath, outputPath, indent = " ") {
856
+ const tsonStr = await readTsonString(inputPath);
857
+ const prettyStr = prettify(tsonStr, indent);
858
+ const target = outputPath || inputPath;
859
+ await saveTsonString(prettyStr, target);
860
+ return prettyStr;
861
+ }
862
+ async function minifyFile(inputPath, outputPath) {
863
+ const tsonStr = await readTsonString(inputPath);
864
+ const compactStr = minify(tsonStr);
865
+ const target = outputPath || inputPath;
866
+ await saveTsonString(compactStr, target);
867
+ return compactStr;
868
+ }
869
+
870
+ export { buildSchemaMap, dump, dumps, escapeString, formatPrimitive, isUniformObjectArray, jsonToTson, load, loadJson, loadTson, loads, looksLikeNumber, minify, minifyFile, needsQuoting, parseKeySchema, parseKeys, parsePrimitive, prettify, prettifyFile, readTsonString, saveTson, saveTsonString, splitByDelimiter, tsonToJson, unescapeString };
509
871
  //# sourceMappingURL=index.js.map
510
872
  //# sourceMappingURL=index.js.map