@jtml/core 0.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.
@@ -0,0 +1,675 @@
1
+ // src/core/types.ts
2
+ var TYPE_MAP = {
3
+ i: "integer",
4
+ f: "float",
5
+ s: "string",
6
+ b: "boolean",
7
+ t: "timestamp",
8
+ n: "null",
9
+ o: "object",
10
+ a: "array",
11
+ e: "enum",
12
+ ref: "reference"
13
+ };
14
+ var JTMLError = class extends Error {
15
+ constructor(message, code) {
16
+ super(message);
17
+ this.code = code;
18
+ this.name = "JTMLError";
19
+ }
20
+ };
21
+
22
+ // src/core/schema.ts
23
+ var SchemaManager = class {
24
+ constructor() {
25
+ this.schemas = /* @__PURE__ */ new Map();
26
+ }
27
+ /**
28
+ * Register a schema for reuse
29
+ */
30
+ register(schema) {
31
+ this.schemas.set(schema.id, schema);
32
+ }
33
+ /**
34
+ * Get a registered schema
35
+ */
36
+ get(id) {
37
+ return this.schemas.get(id);
38
+ }
39
+ /**
40
+ * Check if schema exists
41
+ */
42
+ has(id) {
43
+ return this.schemas.has(id);
44
+ }
45
+ /**
46
+ * Clear all schemas
47
+ */
48
+ clear() {
49
+ this.schemas.clear();
50
+ }
51
+ /**
52
+ * Export all schemas
53
+ */
54
+ export() {
55
+ return Array.from(this.schemas.values());
56
+ }
57
+ /**
58
+ * Import schemas
59
+ */
60
+ import(schemas) {
61
+ schemas.forEach((schema) => this.register(schema));
62
+ }
63
+ };
64
+ function inferType(value) {
65
+ if (value === null || value === void 0) {
66
+ return { type: "n" };
67
+ }
68
+ if (typeof value === "boolean") {
69
+ return { type: "b" };
70
+ }
71
+ if (typeof value === "number") {
72
+ return Number.isInteger(value) ? { type: "i" } : { type: "f" };
73
+ }
74
+ if (typeof value === "string") {
75
+ if (/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/.test(value)) {
76
+ return { type: "t" };
77
+ }
78
+ return { type: "s" };
79
+ }
80
+ if (Array.isArray(value)) {
81
+ if (value.length === 0) {
82
+ return { type: "a" };
83
+ }
84
+ const firstItemType = inferType(value[0]);
85
+ return { type: "a", arrayOf: firstItemType.type };
86
+ }
87
+ if (typeof value === "object") {
88
+ return { type: "o" };
89
+ }
90
+ throw new JTMLError(`Cannot infer type for value: ${value}`, "TYPE_INFERENCE_ERROR");
91
+ }
92
+ function inferSchema(data, schemaId) {
93
+ if (!Array.isArray(data) && typeof data !== "object") {
94
+ throw new JTMLError("Schema inference requires array or object data", "INVALID_DATA");
95
+ }
96
+ const fields = [];
97
+ const sample = Array.isArray(data) ? data[0] : data;
98
+ if (!sample || typeof sample !== "object") {
99
+ throw new JTMLError("Cannot infer schema from empty or non-object data", "INVALID_DATA");
100
+ }
101
+ for (const [key, value] of Object.entries(sample)) {
102
+ const typeInfo = inferType(value);
103
+ let optional = false;
104
+ if (Array.isArray(data)) {
105
+ optional = data.some(
106
+ (item) => item[key] === null || item[key] === void 0
107
+ );
108
+ }
109
+ fields.push({
110
+ name: key,
111
+ typeInfo: { ...typeInfo, optional }
112
+ });
113
+ }
114
+ return {
115
+ id: schemaId,
116
+ fields,
117
+ version: "1.0"
118
+ };
119
+ }
120
+ function serializeSchema(schema) {
121
+ const fieldDefs = schema.fields.map((field) => {
122
+ let def = `${field.name}:${field.typeInfo.type}`;
123
+ if (field.typeInfo.arrayOf) {
124
+ def += `[]`;
125
+ }
126
+ if (field.typeInfo.enumValues) {
127
+ def += `[${field.typeInfo.enumValues.join(",")}]`;
128
+ }
129
+ if (field.typeInfo.refSchema) {
130
+ def += `[${field.typeInfo.refSchema}]`;
131
+ }
132
+ if (field.typeInfo.optional) {
133
+ def += "?";
134
+ }
135
+ return def;
136
+ }).join(" ");
137
+ return `@schema ${schema.id}
138
+ ${fieldDefs}`;
139
+ }
140
+ function parseSchema(schemaStr) {
141
+ const lines = schemaStr.trim().split("\n");
142
+ const headerMatch = lines[0].match(/^@schema\s+(\S+)/);
143
+ if (!headerMatch) {
144
+ throw new JTMLError("Invalid schema format", "SCHEMA_PARSE_ERROR");
145
+ }
146
+ const schemaId = headerMatch[1];
147
+ if (lines.length < 2 || !lines[1]) {
148
+ throw new JTMLError("Schema is missing field definitions", "SCHEMA_PARSE_ERROR");
149
+ }
150
+ const fieldLine = lines[1];
151
+ const fields = [];
152
+ const fieldDefs = fieldLine.split(/\s+/);
153
+ for (const fieldDef of fieldDefs) {
154
+ const match = fieldDef.match(/^(\w+):([ifsbtnoae]+)(\[\])?(\[([^\]]+)\])?(\?)?$/);
155
+ if (!match) {
156
+ throw new JTMLError(`Invalid field definition: ${fieldDef}`, "SCHEMA_PARSE_ERROR");
157
+ }
158
+ const [, name, type, isArray, , enumOrRef, isOptional] = match;
159
+ const typeInfo = {
160
+ type,
161
+ optional: !!isOptional
162
+ };
163
+ if (isArray) {
164
+ typeInfo.arrayOf = type;
165
+ }
166
+ if (enumOrRef) {
167
+ if (type === "e") {
168
+ typeInfo.enumValues = enumOrRef.split(",");
169
+ } else if (type === "ref") {
170
+ typeInfo.refSchema = enumOrRef;
171
+ }
172
+ }
173
+ fields.push({ name, typeInfo });
174
+ }
175
+ return {
176
+ id: schemaId,
177
+ fields,
178
+ version: "1.0"
179
+ };
180
+ }
181
+ function validateAgainstSchema(data, schema) {
182
+ if (Array.isArray(data)) {
183
+ return data.every((item) => validateItem(item, schema));
184
+ }
185
+ return validateItem(data, schema);
186
+ }
187
+ function validateItem(item, schema) {
188
+ if (typeof item !== "object" || item === null) {
189
+ return false;
190
+ }
191
+ for (const field of schema.fields) {
192
+ const value = item[field.name];
193
+ if (value === null || value === void 0) {
194
+ if (!field.typeInfo.optional) {
195
+ return false;
196
+ }
197
+ continue;
198
+ }
199
+ const actualType = inferType(value);
200
+ if (actualType.type !== field.typeInfo.type) {
201
+ return false;
202
+ }
203
+ }
204
+ return true;
205
+ }
206
+ var schemaManager = new SchemaManager();
207
+
208
+ // src/core/encoder.ts
209
+ var JTMLEncoder = class {
210
+ /**
211
+ * Encode JSON data to JTML format
212
+ */
213
+ encode(data, options = {}) {
214
+ const {
215
+ schemaId = "default",
216
+ schemaRef,
217
+ autoInferTypes = true,
218
+ includeSchema = true
219
+ } = options;
220
+ let schema;
221
+ if (schemaRef) {
222
+ schema = schemaManager.get(schemaRef);
223
+ if (!schema) {
224
+ throw new JTMLError(`Schema not found: ${schemaRef}`, "SCHEMA_NOT_FOUND");
225
+ }
226
+ return this.encodeWithSchema(data, schema, false);
227
+ }
228
+ if (autoInferTypes) {
229
+ schema = inferSchema(data, schemaId);
230
+ schemaManager.register(schema);
231
+ }
232
+ if (schema) {
233
+ return this.encodeWithSchema(data, schema, includeSchema);
234
+ }
235
+ return this.encodeSimple(data);
236
+ }
237
+ /**
238
+ * Encode with explicit schema
239
+ */
240
+ encodeWithSchema(data, schema, includeSchema) {
241
+ const parts = [];
242
+ if (includeSchema) {
243
+ parts.push(serializeSchema(schema));
244
+ parts.push("");
245
+ parts.push("@data");
246
+ } else {
247
+ parts.push(`@ref ${schema.id}`);
248
+ parts.push("@data");
249
+ }
250
+ if (Array.isArray(data)) {
251
+ parts.push("@array");
252
+ for (const item of data) {
253
+ parts.push(this.encodeRow(item, schema));
254
+ }
255
+ } else if (typeof data === "object" && data !== null) {
256
+ parts.push(this.encodeRow(data, schema));
257
+ }
258
+ return parts.join("\n");
259
+ }
260
+ /**
261
+ * Encode a single row according to schema
262
+ */
263
+ encodeRow(item, schema) {
264
+ if (typeof item !== "object" || item === null) {
265
+ throw new JTMLError("Cannot encode non-object item", "INVALID_DATA");
266
+ }
267
+ const values = [];
268
+ const obj = item;
269
+ for (const field of schema.fields) {
270
+ const value = obj[field.name];
271
+ values.push(this.encodeValue(value));
272
+ }
273
+ return values.join("|");
274
+ }
275
+ /**
276
+ * Encode a single value
277
+ */
278
+ encodeValue(value) {
279
+ if (value === null || value === void 0) {
280
+ return "";
281
+ }
282
+ if (typeof value === "boolean") {
283
+ return value ? "1" : "0";
284
+ }
285
+ if (typeof value === "number") {
286
+ return String(value);
287
+ }
288
+ if (typeof value === "string") {
289
+ return value.replace(/\\/g, "\\\\").replace(/\|/g, "\\|").replace(/\n/g, "\\n");
290
+ }
291
+ if (Array.isArray(value)) {
292
+ return `[${value.map((v) => this.encodeValue(v)).join(",")}]`;
293
+ }
294
+ if (typeof value === "object") {
295
+ return `{${Object.entries(value).map(([k, v]) => `${k}:${this.encodeValue(v)}`).join(",")}}`;
296
+ }
297
+ return String(value);
298
+ }
299
+ /**
300
+ * Simple encoding without schema (fallback)
301
+ */
302
+ encodeSimple(data) {
303
+ if (Array.isArray(data)) {
304
+ return data.map((item) => JSON.stringify(item)).join("\n");
305
+ }
306
+ return JSON.stringify(data);
307
+ }
308
+ /**
309
+ * Encode with metadata
310
+ */
311
+ encodeWithMetadata(data, metadata, options = {}) {
312
+ const dataEncoded = this.encode(data, options);
313
+ const metaParts = ["", "@meta"];
314
+ for (const [key, value] of Object.entries(metadata)) {
315
+ metaParts.push(`${key}:${this.encodeValue(value)}`);
316
+ }
317
+ return dataEncoded + "\n" + metaParts.join("\n");
318
+ }
319
+ };
320
+ var encoder = new JTMLEncoder();
321
+ function encode(data, options) {
322
+ return encoder.encode(data, options);
323
+ }
324
+ function encodeBatch(datasets, schemaId = "batch") {
325
+ if (datasets.length === 0) {
326
+ throw new JTMLError("Cannot encode empty batch", "INVALID_DATA");
327
+ }
328
+ const schema = inferSchema(datasets[0], schemaId);
329
+ schemaManager.register(schema);
330
+ const parts = [];
331
+ parts.push(serializeSchema(schema));
332
+ parts.push("");
333
+ datasets.forEach((data, index) => {
334
+ parts.push(`@batch ${index}`);
335
+ const encoded = encoder.encode(data, {
336
+ schemaRef: schemaId,
337
+ includeSchema: false
338
+ });
339
+ parts.push(encoded);
340
+ parts.push("");
341
+ });
342
+ return parts.join("\n");
343
+ }
344
+
345
+ // src/core/decoder.ts
346
+ var JTMLDecoder = class {
347
+ /**
348
+ * Decode JTML format to JSON
349
+ */
350
+ decode(jtml, options = {}) {
351
+ const { schemaCache, strict = true } = options;
352
+ if (schemaCache) {
353
+ schemaCache.forEach((schema2, _id) => {
354
+ schemaManager.register(schema2);
355
+ });
356
+ }
357
+ const lines = jtml.trim().split("\n");
358
+ let schema;
359
+ let dataStartIndex = 0;
360
+ let metadata = {};
361
+ for (let i = 0; i < lines.length; i++) {
362
+ const line = lines[i].trim();
363
+ if (line.startsWith("@schema")) {
364
+ if (i + 1 >= lines.length) {
365
+ throw new JTMLError("Incomplete schema definition: missing field definitions", "SCHEMA_PARSE_ERROR");
366
+ }
367
+ const schemaLines = [line, lines[i + 1]];
368
+ schema = parseSchema(schemaLines.join("\n"));
369
+ schemaManager.register(schema);
370
+ i++;
371
+ } else if (line.startsWith("@ref")) {
372
+ const schemaId = line.split(/\s+/)[1];
373
+ if (!schemaId) {
374
+ throw new JTMLError("Missing schema ID in @ref directive", "SCHEMA_PARSE_ERROR");
375
+ }
376
+ schema = schemaManager.get(schemaId);
377
+ if (!schema) {
378
+ throw new JTMLError(`Schema not found: ${schemaId}`, "SCHEMA_NOT_FOUND");
379
+ }
380
+ } else if (line === "@data") {
381
+ dataStartIndex = i + 1;
382
+ break;
383
+ }
384
+ }
385
+ if (!schema && strict) {
386
+ throw new JTMLError("No schema found in JTML data", "SCHEMA_REQUIRED");
387
+ }
388
+ let metaStartIndex = -1;
389
+ for (let i = dataStartIndex; i < lines.length; i++) {
390
+ if (lines[i].trim() === "@meta") {
391
+ metaStartIndex = i + 1;
392
+ break;
393
+ }
394
+ }
395
+ const dataEndIndex = metaStartIndex > 0 ? metaStartIndex - 1 : lines.length;
396
+ const rawDataLines = lines.slice(dataStartIndex, dataEndIndex).filter((l) => l.trim());
397
+ const isArrayEncoding = rawDataLines[0]?.trim() === "@array";
398
+ const dataLines = isArrayEncoding ? rawDataLines.slice(1) : rawDataLines;
399
+ const results = [];
400
+ if (schema) {
401
+ for (const line of dataLines) {
402
+ if (line.trim()) {
403
+ results.push(this.decodeRow(line, schema));
404
+ }
405
+ }
406
+ } else {
407
+ for (const line of dataLines) {
408
+ if (line.trim()) {
409
+ results.push(JSON.parse(line));
410
+ }
411
+ }
412
+ }
413
+ if (metaStartIndex > 0) {
414
+ for (let i = metaStartIndex; i < lines.length; i++) {
415
+ const line = lines[i].trim();
416
+ if (line && !line.startsWith("@")) {
417
+ const colonIdx = line.indexOf(":");
418
+ if (colonIdx === -1) continue;
419
+ const key = line.slice(0, colonIdx);
420
+ const value = line.slice(colonIdx + 1);
421
+ if (key === "__proto__" || key === "constructor" || key === "prototype") continue;
422
+ metadata[key] = this.decodeValue(value);
423
+ }
424
+ }
425
+ }
426
+ if (!isArrayEncoding && results.length === 1 && Object.keys(metadata).length === 0) {
427
+ return results[0];
428
+ }
429
+ if (Object.keys(metadata).length > 0) {
430
+ return {
431
+ data: results.length === 1 ? results[0] : results,
432
+ metadata
433
+ };
434
+ }
435
+ return results;
436
+ }
437
+ /**
438
+ * Decode a single row according to schema
439
+ */
440
+ decodeRow(line, schema) {
441
+ const values = this.splitRow(line);
442
+ const result = {};
443
+ if (values.length !== schema.fields.length) {
444
+ throw new JTMLError(
445
+ `Row has ${values.length} values but schema expects ${schema.fields.length}`,
446
+ "SCHEMA_MISMATCH"
447
+ );
448
+ }
449
+ for (let i = 0; i < schema.fields.length; i++) {
450
+ const field = schema.fields[i];
451
+ const rawValue = values[i];
452
+ if (rawValue === "" || rawValue === null) {
453
+ result[field.name] = null;
454
+ } else {
455
+ result[field.name] = this.decodeValue(rawValue, field.typeInfo.type);
456
+ }
457
+ }
458
+ return result;
459
+ }
460
+ /**
461
+ * Split row by pipe delimiter, handling escaped pipes
462
+ */
463
+ splitRow(line) {
464
+ const parts = [];
465
+ let current = "";
466
+ let escaped = false;
467
+ for (let i = 0; i < line.length; i++) {
468
+ const char = line[i];
469
+ if (escaped) {
470
+ if (char === "n") {
471
+ current += "\n";
472
+ } else if (char === "\\") {
473
+ current += "\\";
474
+ } else if (char === "|") {
475
+ current += "|";
476
+ } else {
477
+ current += char;
478
+ }
479
+ escaped = false;
480
+ } else if (char === "\\") {
481
+ escaped = true;
482
+ } else if (char === "|") {
483
+ parts.push(current);
484
+ current = "";
485
+ } else {
486
+ current += char;
487
+ }
488
+ }
489
+ parts.push(current);
490
+ return parts;
491
+ }
492
+ /**
493
+ * Decode a single value
494
+ */
495
+ decodeValue(value, type) {
496
+ if (value === void 0 || value === "" || value === null) {
497
+ return null;
498
+ }
499
+ if (type === "b") {
500
+ return value === "1" || value === "true";
501
+ }
502
+ if (type === "i" || type === "f") {
503
+ const num = type === "i" ? parseInt(value, 10) : parseFloat(value);
504
+ if (!isFinite(num)) {
505
+ throw new JTMLError(`Invalid numeric value: ${value}`, "INVALID_VALUE");
506
+ }
507
+ return num;
508
+ }
509
+ if (!type && /^-?\d+(\.\d+)?$/.test(value)) {
510
+ return value.includes(".") ? parseFloat(value) : parseInt(value, 10);
511
+ }
512
+ if (value.startsWith("[") && value.endsWith("]")) {
513
+ const inner = value.slice(1, -1);
514
+ if (!inner) return [];
515
+ return inner.split(",").map((v) => this.decodeValue(v.trim(), type));
516
+ }
517
+ if (value.startsWith("{") && value.endsWith("}")) {
518
+ const inner = value.slice(1, -1);
519
+ const obj = /* @__PURE__ */ Object.create(null);
520
+ if (!inner) return obj;
521
+ const pairs = inner.split(",");
522
+ for (const pair of pairs) {
523
+ const colonIdx = pair.indexOf(":");
524
+ if (colonIdx === -1) continue;
525
+ const k = pair.slice(0, colonIdx).trim();
526
+ const v = pair.slice(colonIdx + 1).trim();
527
+ if (k === "__proto__" || k === "constructor" || k === "prototype") continue;
528
+ obj[k] = this.decodeValue(v);
529
+ }
530
+ return obj;
531
+ }
532
+ return value;
533
+ }
534
+ };
535
+ var decoder = new JTMLDecoder();
536
+ function decode(jtml, options) {
537
+ return decoder.decode(jtml, options);
538
+ }
539
+
540
+ // src/utils/tokenizer.ts
541
+ function estimateTokens(text, tokenizer = "claude") {
542
+ const normalized = text.trim().replace(/\s+/g, " ");
543
+ const charsPerToken = {
544
+ gpt: 4,
545
+ claude: 3.8,
546
+ llama: 4.2
547
+ };
548
+ const ratio = charsPerToken[tokenizer];
549
+ let estimate = normalized.length / ratio;
550
+ const structuralChars = (normalized.match(/[{}[\]":,]/g) || []).length;
551
+ estimate += structuralChars * 0.3;
552
+ const numbers = (normalized.match(/\d+/g) || []).length;
553
+ estimate += numbers * 0.2;
554
+ return Math.ceil(estimate);
555
+ }
556
+ function compareTokens(jsonText, jtmlText, tokenizer = "claude") {
557
+ const jsonTokens = estimateTokens(jsonText, tokenizer);
558
+ const jtmlTokens = estimateTokens(jtmlText, tokenizer);
559
+ const savings = jsonTokens - jtmlTokens;
560
+ const savingsPercent = jsonTokens > 0 ? savings / jsonTokens * 100 : 0;
561
+ return {
562
+ jsonTokens,
563
+ jtmlTokens,
564
+ savings,
565
+ savingsPercent
566
+ };
567
+ }
568
+ function calculateEfficiency(jsonText, jtmlText) {
569
+ const jsonLen = jsonText.length;
570
+ const jtmlLen = jtmlText.length;
571
+ return (jsonLen - jtmlLen) / jsonLen * 100;
572
+ }
573
+ function analyzeTokens(jsonText, jtmlText, tokenizer = "claude") {
574
+ const jsonStructural = (jsonText.match(/[{}[\]":,]/g) || []).length;
575
+ const jsonKeys = (jsonText.match(/"(\w+)":/g) || []).length;
576
+ const jtmlSchema = jtmlText.split("@data")[0] || "";
577
+ const jtmlData = jtmlText.split("@data")[1] || "";
578
+ const jtmlDelimiters = (jtmlText.match(/[|:]/g) || []).length;
579
+ return {
580
+ json: {
581
+ total: estimateTokens(jsonText, tokenizer),
582
+ structural: Math.ceil(jsonStructural * 0.8),
583
+ keys: Math.ceil(jsonKeys * 1.5),
584
+ // Keys with quotes
585
+ values: estimateTokens(jsonText, tokenizer) - Math.ceil(jsonStructural * 0.8) - Math.ceil(jsonKeys * 1.5)
586
+ },
587
+ jtml: {
588
+ total: estimateTokens(jtmlText, tokenizer),
589
+ schema: estimateTokens(jtmlSchema, tokenizer),
590
+ data: estimateTokens(jtmlData, tokenizer),
591
+ delimiters: Math.ceil(jtmlDelimiters * 0.5)
592
+ },
593
+ comparison: compareTokens(jsonText, jtmlText, tokenizer)
594
+ };
595
+ }
596
+ function formatTokenStats(stats) {
597
+ return `
598
+ Token Comparison:
599
+ JSON: ${stats.jsonTokens} tokens
600
+ JTML: ${stats.jtmlTokens} tokens
601
+ Savings: ${stats.savings} tokens (${stats.savingsPercent.toFixed(2)}%)
602
+ `.trim();
603
+ }
604
+ function estimateCostSavings(stats, pricePerMillion = 3) {
605
+ const costSavedPer1M = stats.savings / 1e6 * pricePerMillion;
606
+ const costSavedPer1K = stats.savings / 1e3 * (pricePerMillion / 1e3);
607
+ return {
608
+ tokensSaved: stats.savings,
609
+ costSavedPer1M,
610
+ costSavedPer1K
611
+ };
612
+ }
613
+
614
+ // src/index.ts
615
+ function jsonToJtml(json, schemaId) {
616
+ return encode(json, { schemaId, autoInferTypes: true });
617
+ }
618
+ function jtmlToJson(jtml) {
619
+ return decode(jtml);
620
+ }
621
+ function convertJsonString(jsonStr, schemaId) {
622
+ const data = JSON.parse(jsonStr);
623
+ return jsonToJtml(data, schemaId);
624
+ }
625
+ function roundTrip(data) {
626
+ const jtml = encode(data);
627
+ const recovered = decode(jtml);
628
+ return {
629
+ success: JSON.stringify(data) === JSON.stringify(recovered),
630
+ original: data,
631
+ recovered,
632
+ jtml
633
+ };
634
+ }
635
+ var index_default = {
636
+ encode,
637
+ decode,
638
+ jsonToJtml,
639
+ jtmlToJson,
640
+ convertJsonString,
641
+ roundTrip,
642
+ schemaManager,
643
+ estimateTokens,
644
+ compareTokens
645
+ };
646
+
647
+ export {
648
+ TYPE_MAP,
649
+ JTMLError,
650
+ SchemaManager,
651
+ inferType,
652
+ inferSchema,
653
+ serializeSchema,
654
+ parseSchema,
655
+ validateAgainstSchema,
656
+ schemaManager,
657
+ JTMLEncoder,
658
+ encoder,
659
+ encode,
660
+ encodeBatch,
661
+ JTMLDecoder,
662
+ decoder,
663
+ decode,
664
+ estimateTokens,
665
+ compareTokens,
666
+ calculateEfficiency,
667
+ analyzeTokens,
668
+ formatTokenStats,
669
+ estimateCostSavings,
670
+ jsonToJtml,
671
+ jtmlToJson,
672
+ convertJsonString,
673
+ roundTrip,
674
+ index_default
675
+ };
package/dist/cli.d.mts ADDED
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
package/dist/cli.d.ts ADDED
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node