@q1k-oss/mint-format 1.0.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.cjs +480 -0
- package/dist/index.d.cts +104 -0
- package/dist/index.d.ts +104 -0
- package/dist/index.js +452 -0
- package/package.json +62 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,480 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
decode: () => decode,
|
|
24
|
+
default: () => index_default,
|
|
25
|
+
encode: () => encode,
|
|
26
|
+
estimateTokens: () => estimateTokens,
|
|
27
|
+
validate: () => validate
|
|
28
|
+
});
|
|
29
|
+
module.exports = __toCommonJS(index_exports);
|
|
30
|
+
var STATUS_SYMBOLS = {
|
|
31
|
+
completed: "\u2713",
|
|
32
|
+
complete: "\u2713",
|
|
33
|
+
success: "\u2713",
|
|
34
|
+
done: "\u2713",
|
|
35
|
+
passed: "\u2713",
|
|
36
|
+
true: "\u2713",
|
|
37
|
+
yes: "\u2713",
|
|
38
|
+
failed: "\u2717",
|
|
39
|
+
failure: "\u2717",
|
|
40
|
+
error: "\u2717",
|
|
41
|
+
rejected: "\u2717",
|
|
42
|
+
false: "\u2717",
|
|
43
|
+
no: "\u2717",
|
|
44
|
+
pending: "\u23F3",
|
|
45
|
+
waiting: "\u23F3",
|
|
46
|
+
in_progress: "\u23F3",
|
|
47
|
+
running: "\u23F3",
|
|
48
|
+
warning: "\u26A0",
|
|
49
|
+
warn: "\u26A0",
|
|
50
|
+
review: "?",
|
|
51
|
+
unknown: "?"
|
|
52
|
+
};
|
|
53
|
+
var REVERSE_SYMBOLS = {
|
|
54
|
+
"\u2713": "true",
|
|
55
|
+
"\u2717": "false",
|
|
56
|
+
"\u23F3": "pending",
|
|
57
|
+
"\u26A0": "warning",
|
|
58
|
+
"?": "unknown"
|
|
59
|
+
};
|
|
60
|
+
function needsQuoting(value) {
|
|
61
|
+
if (value === "") return true;
|
|
62
|
+
if (value.startsWith(" ") || value.endsWith(" ")) return true;
|
|
63
|
+
if (value.includes("|") || value.includes("\n") || value.includes("\r")) return true;
|
|
64
|
+
if (value.includes(",")) return true;
|
|
65
|
+
if (/^-?\d+\.?\d*$/.test(value)) return true;
|
|
66
|
+
if (["true", "false", "null"].includes(value.toLowerCase())) return true;
|
|
67
|
+
if (value.includes(":") && !value.includes("://")) return true;
|
|
68
|
+
if (value.includes('"')) return true;
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
function escapeString(value) {
|
|
72
|
+
return value.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/\t/g, "\\t");
|
|
73
|
+
}
|
|
74
|
+
function unescapeString(value) {
|
|
75
|
+
return value.replace(/\\n/g, "\n").replace(/\\r/g, "\r").replace(/\\t/g, " ").replace(/\\"/g, '"').replace(/\\\\/g, "\\");
|
|
76
|
+
}
|
|
77
|
+
function formatPrimitive(value, options, inTable = false) {
|
|
78
|
+
if (value === null || value === void 0) {
|
|
79
|
+
return inTable ? "-" : "null";
|
|
80
|
+
}
|
|
81
|
+
if (typeof value === "boolean") {
|
|
82
|
+
return String(value);
|
|
83
|
+
}
|
|
84
|
+
if (typeof value === "number") {
|
|
85
|
+
if (!isFinite(value)) return "null";
|
|
86
|
+
return String(value);
|
|
87
|
+
}
|
|
88
|
+
if (typeof value === "string") {
|
|
89
|
+
if (options.compact && STATUS_SYMBOLS[value.toLowerCase()]) {
|
|
90
|
+
return STATUS_SYMBOLS[value.toLowerCase()];
|
|
91
|
+
}
|
|
92
|
+
if (value === "" && inTable) return "-";
|
|
93
|
+
if (needsQuoting(value)) {
|
|
94
|
+
return `"${escapeString(value)}"`;
|
|
95
|
+
}
|
|
96
|
+
return value;
|
|
97
|
+
}
|
|
98
|
+
return String(value);
|
|
99
|
+
}
|
|
100
|
+
function isPrimitive(value) {
|
|
101
|
+
return value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean";
|
|
102
|
+
}
|
|
103
|
+
function isTableArray(arr) {
|
|
104
|
+
if (arr.length === 0) return false;
|
|
105
|
+
if (!arr.every((item) => item !== null && typeof item === "object" && !Array.isArray(item))) {
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
const firstKeys = Object.keys(arr[0]).sort().join(",");
|
|
109
|
+
const sameKeys = arr.every((item) => {
|
|
110
|
+
const keys = Object.keys(item).sort().join(",");
|
|
111
|
+
return keys === firstKeys;
|
|
112
|
+
});
|
|
113
|
+
if (!sameKeys) return false;
|
|
114
|
+
return arr.every((item) => {
|
|
115
|
+
const obj = item;
|
|
116
|
+
return Object.values(obj).every((val) => isPrimitive(val));
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
function isPrimitiveArray(arr) {
|
|
120
|
+
return arr.every((item) => isPrimitive(item));
|
|
121
|
+
}
|
|
122
|
+
function getColumnWidths(headers, rows) {
|
|
123
|
+
const widths = headers.map((h) => h.length);
|
|
124
|
+
for (const row of rows) {
|
|
125
|
+
for (let i = 0; i < row.length; i++) {
|
|
126
|
+
widths[i] = Math.max(widths[i] || 0, row[i]?.length || 0);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return widths;
|
|
130
|
+
}
|
|
131
|
+
function padCell(value, width) {
|
|
132
|
+
return value + " ".repeat(Math.max(0, width - value.length));
|
|
133
|
+
}
|
|
134
|
+
function encodeTable(arr, options, indentLevel) {
|
|
135
|
+
if (arr.length === 0) return "| |";
|
|
136
|
+
const indent = " ".repeat(options.indent || 2);
|
|
137
|
+
const baseIndent = indent.repeat(indentLevel);
|
|
138
|
+
const headers = Object.keys(arr[0]);
|
|
139
|
+
const rows = arr.map((obj) => headers.map((h) => formatPrimitive(obj[h], options, true)));
|
|
140
|
+
const widths = getColumnWidths(headers, rows);
|
|
141
|
+
const lines = [];
|
|
142
|
+
const headerCells = headers.map((h, i) => padCell(h, widths[i]));
|
|
143
|
+
lines.push(`${baseIndent}| ${headerCells.join(" | ")} |`);
|
|
144
|
+
for (const row of rows) {
|
|
145
|
+
const cells = row.map((cell, i) => padCell(cell, widths[i]));
|
|
146
|
+
lines.push(`${baseIndent}| ${cells.join(" | ")} |`);
|
|
147
|
+
}
|
|
148
|
+
return lines.join("\n");
|
|
149
|
+
}
|
|
150
|
+
function encodeValue(value, options, indentLevel) {
|
|
151
|
+
const indent = " ".repeat(options.indent || 2);
|
|
152
|
+
const baseIndent = indent.repeat(indentLevel);
|
|
153
|
+
if (value === null || typeof value !== "object") {
|
|
154
|
+
return formatPrimitive(value, options);
|
|
155
|
+
}
|
|
156
|
+
if (Array.isArray(value)) {
|
|
157
|
+
if (value.length === 0) {
|
|
158
|
+
return "[]";
|
|
159
|
+
}
|
|
160
|
+
if (isPrimitiveArray(value)) {
|
|
161
|
+
return value.map((v) => formatPrimitive(v, options)).join(", ");
|
|
162
|
+
}
|
|
163
|
+
if (isTableArray(value)) {
|
|
164
|
+
return "\n" + encodeTable(value, options, indentLevel + 1);
|
|
165
|
+
}
|
|
166
|
+
const lines2 = [];
|
|
167
|
+
for (const item of value) {
|
|
168
|
+
if (item === null || typeof item !== "object") {
|
|
169
|
+
lines2.push(`${baseIndent}${indent}- ${formatPrimitive(item, options)}`);
|
|
170
|
+
} else {
|
|
171
|
+
const encoded = encodeValue(item, options, indentLevel + 2);
|
|
172
|
+
if (encoded.includes("\n")) {
|
|
173
|
+
lines2.push(`${baseIndent}${indent}-`);
|
|
174
|
+
lines2.push(encoded);
|
|
175
|
+
} else {
|
|
176
|
+
lines2.push(`${baseIndent}${indent}- ${encoded}`);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
return "\n" + lines2.join("\n");
|
|
181
|
+
}
|
|
182
|
+
const obj = value;
|
|
183
|
+
const keys = options.sortKeys ? Object.keys(obj).sort() : Object.keys(obj);
|
|
184
|
+
if (keys.length === 0) {
|
|
185
|
+
return "";
|
|
186
|
+
}
|
|
187
|
+
const lines = [];
|
|
188
|
+
for (const key of keys) {
|
|
189
|
+
const val = obj[key];
|
|
190
|
+
if (val === null) {
|
|
191
|
+
lines.push(`${baseIndent}${key}: null`);
|
|
192
|
+
} else if (typeof val !== "object") {
|
|
193
|
+
lines.push(`${baseIndent}${key}: ${formatPrimitive(val, options)}`);
|
|
194
|
+
} else if (Array.isArray(val)) {
|
|
195
|
+
if (val.length === 0) {
|
|
196
|
+
lines.push(`${baseIndent}${key}: []`);
|
|
197
|
+
} else if (isPrimitiveArray(val)) {
|
|
198
|
+
lines.push(`${baseIndent}${key}: ${val.map((v) => formatPrimitive(v, options)).join(", ")}`);
|
|
199
|
+
} else {
|
|
200
|
+
lines.push(`${baseIndent}${key}:${encodeValue(val, options, indentLevel)}`);
|
|
201
|
+
}
|
|
202
|
+
} else {
|
|
203
|
+
const nested = encodeValue(val, options, indentLevel + 1);
|
|
204
|
+
if (nested === "") {
|
|
205
|
+
lines.push(`${baseIndent}${key}:`);
|
|
206
|
+
} else if (nested.includes("\n")) {
|
|
207
|
+
lines.push(`${baseIndent}${key}:`);
|
|
208
|
+
lines.push(nested);
|
|
209
|
+
} else {
|
|
210
|
+
lines.push(`${baseIndent}${key}: ${nested}`);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
return lines.join("\n");
|
|
215
|
+
}
|
|
216
|
+
function encode(value, options = {}) {
|
|
217
|
+
const opts = {
|
|
218
|
+
indent: 2,
|
|
219
|
+
compact: false,
|
|
220
|
+
sortKeys: false,
|
|
221
|
+
...options
|
|
222
|
+
};
|
|
223
|
+
if (value === null || value === void 0) {
|
|
224
|
+
return "null";
|
|
225
|
+
}
|
|
226
|
+
if (typeof value !== "object") {
|
|
227
|
+
return formatPrimitive(value, opts);
|
|
228
|
+
}
|
|
229
|
+
if (Array.isArray(value)) {
|
|
230
|
+
if (value.length === 0) return "_: []";
|
|
231
|
+
if (isPrimitiveArray(value)) {
|
|
232
|
+
return `_: ${value.map((v) => formatPrimitive(v, opts)).join(", ")}`;
|
|
233
|
+
}
|
|
234
|
+
if (isTableArray(value)) {
|
|
235
|
+
return `_:
|
|
236
|
+
${encodeTable(value, opts, 1)}`;
|
|
237
|
+
}
|
|
238
|
+
return `_:${encodeValue(value, opts, 0)}`;
|
|
239
|
+
}
|
|
240
|
+
return encodeValue(value, opts, 0);
|
|
241
|
+
}
|
|
242
|
+
function parsePrimitive(value) {
|
|
243
|
+
const trimmed = value.trim();
|
|
244
|
+
if (trimmed === "null" || trimmed === "-" || trimmed === "") {
|
|
245
|
+
return null;
|
|
246
|
+
}
|
|
247
|
+
if (trimmed === "true") return true;
|
|
248
|
+
if (trimmed === "false") return false;
|
|
249
|
+
if (REVERSE_SYMBOLS[trimmed]) {
|
|
250
|
+
return REVERSE_SYMBOLS[trimmed];
|
|
251
|
+
}
|
|
252
|
+
if (trimmed.startsWith('"') && trimmed.endsWith('"')) {
|
|
253
|
+
return unescapeString(trimmed.slice(1, -1));
|
|
254
|
+
}
|
|
255
|
+
if (/^-?\d+(\.\d+)?([eE][+-]?\d+)?$/.test(trimmed)) {
|
|
256
|
+
const num = Number(trimmed);
|
|
257
|
+
if (isFinite(num)) return num;
|
|
258
|
+
}
|
|
259
|
+
return trimmed;
|
|
260
|
+
}
|
|
261
|
+
function parseTable(lines, startIndex, indent) {
|
|
262
|
+
const result = [];
|
|
263
|
+
let headers = [];
|
|
264
|
+
let i = startIndex;
|
|
265
|
+
const headerLine = lines[i].trim();
|
|
266
|
+
if (!headerLine.startsWith("|")) {
|
|
267
|
+
return { value: [], endIndex: startIndex };
|
|
268
|
+
}
|
|
269
|
+
headers = headerLine.split("|").slice(1, -1).map((h) => h.trim());
|
|
270
|
+
i++;
|
|
271
|
+
while (i < lines.length) {
|
|
272
|
+
const line = lines[i];
|
|
273
|
+
const lineIndent = line.length - line.trimStart().length;
|
|
274
|
+
const trimmed = line.trim();
|
|
275
|
+
if (!trimmed.startsWith("|")) {
|
|
276
|
+
break;
|
|
277
|
+
}
|
|
278
|
+
if (lineIndent < indent && trimmed !== "") {
|
|
279
|
+
break;
|
|
280
|
+
}
|
|
281
|
+
const cells = trimmed.split("|").slice(1, -1).map((c) => parsePrimitive(c.trim()));
|
|
282
|
+
if (cells.length === headers.length) {
|
|
283
|
+
const row = {};
|
|
284
|
+
headers.forEach((h, idx) => {
|
|
285
|
+
row[h] = cells[idx];
|
|
286
|
+
});
|
|
287
|
+
result.push(row);
|
|
288
|
+
}
|
|
289
|
+
i++;
|
|
290
|
+
}
|
|
291
|
+
return { value: result, endIndex: i - 1 };
|
|
292
|
+
}
|
|
293
|
+
function parseDocument(lines, startIndex, baseIndent, options) {
|
|
294
|
+
const result = {};
|
|
295
|
+
let i = startIndex;
|
|
296
|
+
while (i < lines.length) {
|
|
297
|
+
const line = lines[i];
|
|
298
|
+
if (line.trim() === "" || line.trim().startsWith("#")) {
|
|
299
|
+
i++;
|
|
300
|
+
continue;
|
|
301
|
+
}
|
|
302
|
+
const lineIndent = line.length - line.trimStart().length;
|
|
303
|
+
if (lineIndent < baseIndent) {
|
|
304
|
+
break;
|
|
305
|
+
}
|
|
306
|
+
if (lineIndent > baseIndent) {
|
|
307
|
+
i++;
|
|
308
|
+
continue;
|
|
309
|
+
}
|
|
310
|
+
const trimmed = line.trim();
|
|
311
|
+
if (trimmed.startsWith("|")) {
|
|
312
|
+
i++;
|
|
313
|
+
continue;
|
|
314
|
+
}
|
|
315
|
+
const colonIndex = trimmed.indexOf(":");
|
|
316
|
+
if (colonIndex === -1) {
|
|
317
|
+
i++;
|
|
318
|
+
continue;
|
|
319
|
+
}
|
|
320
|
+
const key = trimmed.slice(0, colonIndex).trim();
|
|
321
|
+
const valueStr = trimmed.slice(colonIndex + 1).trim();
|
|
322
|
+
if (valueStr === "" || valueStr === "[]") {
|
|
323
|
+
let foundNested = false;
|
|
324
|
+
let nextIdx = i + 1;
|
|
325
|
+
while (nextIdx < lines.length && lines[nextIdx].trim() === "") {
|
|
326
|
+
nextIdx++;
|
|
327
|
+
}
|
|
328
|
+
if (nextIdx < lines.length) {
|
|
329
|
+
const nextLine = lines[nextIdx];
|
|
330
|
+
const nextIndent = nextLine.length - nextLine.trimStart().length;
|
|
331
|
+
const nextTrimmed = nextLine.trim();
|
|
332
|
+
if (nextIndent > baseIndent && nextTrimmed.startsWith("|")) {
|
|
333
|
+
const tableResult = parseTable(lines, nextIdx, nextIndent);
|
|
334
|
+
result[key] = tableResult.value;
|
|
335
|
+
i = tableResult.endIndex + 1;
|
|
336
|
+
foundNested = true;
|
|
337
|
+
} else if (nextIndent > baseIndent && nextTrimmed !== "" && !nextTrimmed.startsWith("#")) {
|
|
338
|
+
const nestedResult = parseDocument(lines, nextIdx, nextIndent, options);
|
|
339
|
+
result[key] = nestedResult.value;
|
|
340
|
+
i = nestedResult.endIndex;
|
|
341
|
+
foundNested = true;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
if (!foundNested) {
|
|
345
|
+
result[key] = valueStr === "[]" ? [] : {};
|
|
346
|
+
i++;
|
|
347
|
+
}
|
|
348
|
+
} else if (valueStr.startsWith('"') && valueStr.endsWith('"')) {
|
|
349
|
+
result[key] = parsePrimitive(valueStr);
|
|
350
|
+
i++;
|
|
351
|
+
} else if (valueStr.includes(" | ")) {
|
|
352
|
+
result[key] = valueStr.split(" | ").map((v) => parsePrimitive(v.trim()));
|
|
353
|
+
i++;
|
|
354
|
+
} else if (valueStr.includes(", ")) {
|
|
355
|
+
result[key] = valueStr.split(", ").map((v) => parsePrimitive(v.trim()));
|
|
356
|
+
i++;
|
|
357
|
+
} else {
|
|
358
|
+
result[key] = parsePrimitive(valueStr);
|
|
359
|
+
i++;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
return { value: result, endIndex: i };
|
|
363
|
+
}
|
|
364
|
+
function decode(input, options = {}) {
|
|
365
|
+
const opts = {
|
|
366
|
+
strict: true,
|
|
367
|
+
indent: 2,
|
|
368
|
+
...options
|
|
369
|
+
};
|
|
370
|
+
const normalized = input.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
371
|
+
const lines = normalized.split("\n");
|
|
372
|
+
if (lines.every((l) => l.trim() === "" || l.trim().startsWith("#"))) {
|
|
373
|
+
return {};
|
|
374
|
+
}
|
|
375
|
+
let startIndex = 0;
|
|
376
|
+
while (startIndex < lines.length && (lines[startIndex].trim() === "" || lines[startIndex].trim().startsWith("#"))) {
|
|
377
|
+
startIndex++;
|
|
378
|
+
}
|
|
379
|
+
if (startIndex >= lines.length) {
|
|
380
|
+
return {};
|
|
381
|
+
}
|
|
382
|
+
const firstLine = lines[startIndex].trim();
|
|
383
|
+
if (firstLine.startsWith("|")) {
|
|
384
|
+
const tableResult = parseTable(lines, startIndex, 0);
|
|
385
|
+
return tableResult.value;
|
|
386
|
+
}
|
|
387
|
+
if (firstLine.startsWith("_:")) {
|
|
388
|
+
const valueStr = firstLine.slice(2).trim();
|
|
389
|
+
if (valueStr === "" || valueStr === "[]") {
|
|
390
|
+
const nextLine = lines[startIndex + 1];
|
|
391
|
+
if (nextLine && nextLine.trim().startsWith("|")) {
|
|
392
|
+
const tableResult = parseTable(lines, startIndex + 1, 2);
|
|
393
|
+
return tableResult.value;
|
|
394
|
+
}
|
|
395
|
+
return [];
|
|
396
|
+
}
|
|
397
|
+
if (valueStr.includes(", ")) {
|
|
398
|
+
return valueStr.split(", ").map((v) => parsePrimitive(v.trim()));
|
|
399
|
+
}
|
|
400
|
+
return [parsePrimitive(valueStr)];
|
|
401
|
+
}
|
|
402
|
+
const result = parseDocument(lines, startIndex, 0, opts);
|
|
403
|
+
return result.value;
|
|
404
|
+
}
|
|
405
|
+
function validate(input) {
|
|
406
|
+
const errors = [];
|
|
407
|
+
const lines = input.replace(/\r\n/g, "\n").replace(/\r/g, "\n").split("\n");
|
|
408
|
+
let inTable = false;
|
|
409
|
+
let tableColumns = 0;
|
|
410
|
+
for (let i = 0; i < lines.length; i++) {
|
|
411
|
+
const line = lines[i];
|
|
412
|
+
const lineNum = i + 1;
|
|
413
|
+
const trimmed = line.trim();
|
|
414
|
+
if (trimmed === "" || trimmed.startsWith("#")) {
|
|
415
|
+
continue;
|
|
416
|
+
}
|
|
417
|
+
const indent = line.length - line.trimStart().length;
|
|
418
|
+
if (indent % 2 !== 0) {
|
|
419
|
+
errors.push({
|
|
420
|
+
line: lineNum,
|
|
421
|
+
column: 1,
|
|
422
|
+
message: `Inconsistent indentation: ${indent} spaces (should be multiple of 2)`,
|
|
423
|
+
context: line
|
|
424
|
+
});
|
|
425
|
+
}
|
|
426
|
+
if (trimmed.startsWith("|")) {
|
|
427
|
+
const pipes = trimmed.split("|").length - 1;
|
|
428
|
+
if (!inTable) {
|
|
429
|
+
inTable = true;
|
|
430
|
+
tableColumns = pipes;
|
|
431
|
+
} else {
|
|
432
|
+
if (pipes !== tableColumns) {
|
|
433
|
+
errors.push({
|
|
434
|
+
line: lineNum,
|
|
435
|
+
column: 1,
|
|
436
|
+
message: `Table column mismatch: expected ${tableColumns - 1} columns, got ${pipes - 1}`,
|
|
437
|
+
context: line
|
|
438
|
+
});
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
if (!trimmed.endsWith("|")) {
|
|
442
|
+
errors.push({
|
|
443
|
+
line: lineNum,
|
|
444
|
+
column: trimmed.length,
|
|
445
|
+
message: "Table row must end with |",
|
|
446
|
+
context: line
|
|
447
|
+
});
|
|
448
|
+
}
|
|
449
|
+
} else {
|
|
450
|
+
inTable = false;
|
|
451
|
+
tableColumns = 0;
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
return {
|
|
455
|
+
valid: errors.length === 0,
|
|
456
|
+
errors
|
|
457
|
+
};
|
|
458
|
+
}
|
|
459
|
+
function estimateTokens(data) {
|
|
460
|
+
const jsonStr = JSON.stringify(data, null, 2);
|
|
461
|
+
const mintStr = encode(data);
|
|
462
|
+
const jsonTokens = Math.ceil(jsonStr.length / 3.5);
|
|
463
|
+
const mintTokens = Math.ceil(mintStr.length / 3.5);
|
|
464
|
+
const savings = jsonTokens - mintTokens;
|
|
465
|
+
const savingsPercent = Math.round(savings / jsonTokens * 100);
|
|
466
|
+
return {
|
|
467
|
+
json: jsonTokens,
|
|
468
|
+
mint: mintTokens,
|
|
469
|
+
savings,
|
|
470
|
+
savingsPercent
|
|
471
|
+
};
|
|
472
|
+
}
|
|
473
|
+
var index_default = { encode, decode, validate, estimateTokens };
|
|
474
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
475
|
+
0 && (module.exports = {
|
|
476
|
+
decode,
|
|
477
|
+
encode,
|
|
478
|
+
estimateTokens,
|
|
479
|
+
validate
|
|
480
|
+
});
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 🌿 MINT Format - Minimal Inference Notation for Tokens
|
|
3
|
+
*
|
|
4
|
+
* A fresh, human-readable, token-efficient data format for LLM prompts.
|
|
5
|
+
*
|
|
6
|
+
* @packageDocumentation
|
|
7
|
+
*/
|
|
8
|
+
interface EncodeOptions {
|
|
9
|
+
/** Spaces per indentation level (default: 2) */
|
|
10
|
+
indent?: number;
|
|
11
|
+
/** Enable compact mode with symbols (default: false) */
|
|
12
|
+
compact?: boolean;
|
|
13
|
+
/** Sort object keys alphabetically (default: false) */
|
|
14
|
+
sortKeys?: boolean;
|
|
15
|
+
}
|
|
16
|
+
interface DecodeOptions {
|
|
17
|
+
/** Enable strict validation (default: true) */
|
|
18
|
+
strict?: boolean;
|
|
19
|
+
/** Expected indentation spaces (default: 2) */
|
|
20
|
+
indent?: number;
|
|
21
|
+
}
|
|
22
|
+
interface ValidationResult {
|
|
23
|
+
valid: boolean;
|
|
24
|
+
errors: ValidationError[];
|
|
25
|
+
}
|
|
26
|
+
interface ValidationError {
|
|
27
|
+
line: number;
|
|
28
|
+
column: number;
|
|
29
|
+
message: string;
|
|
30
|
+
context?: string;
|
|
31
|
+
}
|
|
32
|
+
interface TokenEstimate {
|
|
33
|
+
json: number;
|
|
34
|
+
mint: number;
|
|
35
|
+
savings: number;
|
|
36
|
+
savingsPercent: number;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Encode JavaScript value to MINT format
|
|
40
|
+
*
|
|
41
|
+
* @param value - Value to encode
|
|
42
|
+
* @param options - Encoding options
|
|
43
|
+
* @returns MINT-formatted string
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```typescript
|
|
47
|
+
* const data = {
|
|
48
|
+
* users: [
|
|
49
|
+
* { id: 1, name: 'Alice' },
|
|
50
|
+
* { id: 2, name: 'Bob' }
|
|
51
|
+
* ]
|
|
52
|
+
* };
|
|
53
|
+
*
|
|
54
|
+
* console.log(encode(data));
|
|
55
|
+
* // users:
|
|
56
|
+
* // | id | name |
|
|
57
|
+
* // | 1 | Alice |
|
|
58
|
+
* // | 2 | Bob |
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
declare function encode(value: unknown, options?: EncodeOptions): string;
|
|
62
|
+
/**
|
|
63
|
+
* Decode MINT string to JavaScript value
|
|
64
|
+
*
|
|
65
|
+
* @param input - MINT-formatted string
|
|
66
|
+
* @param options - Decoding options
|
|
67
|
+
* @returns Parsed JavaScript value
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* ```typescript
|
|
71
|
+
* const mint = `
|
|
72
|
+
* users:
|
|
73
|
+
* | id | name |
|
|
74
|
+
* | 1 | Alice |
|
|
75
|
+
* | 2 | Bob |
|
|
76
|
+
* `;
|
|
77
|
+
*
|
|
78
|
+
* const data = decode(mint);
|
|
79
|
+
* console.log(data.users[0].name); // "Alice"
|
|
80
|
+
* ```
|
|
81
|
+
*/
|
|
82
|
+
declare function decode(input: string, options?: DecodeOptions): unknown;
|
|
83
|
+
/**
|
|
84
|
+
* Validate MINT syntax
|
|
85
|
+
*
|
|
86
|
+
* @param input - MINT-formatted string
|
|
87
|
+
* @returns Validation result with errors
|
|
88
|
+
*/
|
|
89
|
+
declare function validate(input: string): ValidationResult;
|
|
90
|
+
/**
|
|
91
|
+
* Estimate token counts
|
|
92
|
+
*
|
|
93
|
+
* @param data - Data to analyze
|
|
94
|
+
* @returns Token estimates for JSON and MINT
|
|
95
|
+
*/
|
|
96
|
+
declare function estimateTokens(data: unknown): TokenEstimate;
|
|
97
|
+
declare const _default: {
|
|
98
|
+
encode: typeof encode;
|
|
99
|
+
decode: typeof decode;
|
|
100
|
+
validate: typeof validate;
|
|
101
|
+
estimateTokens: typeof estimateTokens;
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
export { type DecodeOptions, type EncodeOptions, type TokenEstimate, type ValidationError, type ValidationResult, decode, _default as default, encode, estimateTokens, validate };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 🌿 MINT Format - Minimal Inference Notation for Tokens
|
|
3
|
+
*
|
|
4
|
+
* A fresh, human-readable, token-efficient data format for LLM prompts.
|
|
5
|
+
*
|
|
6
|
+
* @packageDocumentation
|
|
7
|
+
*/
|
|
8
|
+
interface EncodeOptions {
|
|
9
|
+
/** Spaces per indentation level (default: 2) */
|
|
10
|
+
indent?: number;
|
|
11
|
+
/** Enable compact mode with symbols (default: false) */
|
|
12
|
+
compact?: boolean;
|
|
13
|
+
/** Sort object keys alphabetically (default: false) */
|
|
14
|
+
sortKeys?: boolean;
|
|
15
|
+
}
|
|
16
|
+
interface DecodeOptions {
|
|
17
|
+
/** Enable strict validation (default: true) */
|
|
18
|
+
strict?: boolean;
|
|
19
|
+
/** Expected indentation spaces (default: 2) */
|
|
20
|
+
indent?: number;
|
|
21
|
+
}
|
|
22
|
+
interface ValidationResult {
|
|
23
|
+
valid: boolean;
|
|
24
|
+
errors: ValidationError[];
|
|
25
|
+
}
|
|
26
|
+
interface ValidationError {
|
|
27
|
+
line: number;
|
|
28
|
+
column: number;
|
|
29
|
+
message: string;
|
|
30
|
+
context?: string;
|
|
31
|
+
}
|
|
32
|
+
interface TokenEstimate {
|
|
33
|
+
json: number;
|
|
34
|
+
mint: number;
|
|
35
|
+
savings: number;
|
|
36
|
+
savingsPercent: number;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Encode JavaScript value to MINT format
|
|
40
|
+
*
|
|
41
|
+
* @param value - Value to encode
|
|
42
|
+
* @param options - Encoding options
|
|
43
|
+
* @returns MINT-formatted string
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```typescript
|
|
47
|
+
* const data = {
|
|
48
|
+
* users: [
|
|
49
|
+
* { id: 1, name: 'Alice' },
|
|
50
|
+
* { id: 2, name: 'Bob' }
|
|
51
|
+
* ]
|
|
52
|
+
* };
|
|
53
|
+
*
|
|
54
|
+
* console.log(encode(data));
|
|
55
|
+
* // users:
|
|
56
|
+
* // | id | name |
|
|
57
|
+
* // | 1 | Alice |
|
|
58
|
+
* // | 2 | Bob |
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
declare function encode(value: unknown, options?: EncodeOptions): string;
|
|
62
|
+
/**
|
|
63
|
+
* Decode MINT string to JavaScript value
|
|
64
|
+
*
|
|
65
|
+
* @param input - MINT-formatted string
|
|
66
|
+
* @param options - Decoding options
|
|
67
|
+
* @returns Parsed JavaScript value
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* ```typescript
|
|
71
|
+
* const mint = `
|
|
72
|
+
* users:
|
|
73
|
+
* | id | name |
|
|
74
|
+
* | 1 | Alice |
|
|
75
|
+
* | 2 | Bob |
|
|
76
|
+
* `;
|
|
77
|
+
*
|
|
78
|
+
* const data = decode(mint);
|
|
79
|
+
* console.log(data.users[0].name); // "Alice"
|
|
80
|
+
* ```
|
|
81
|
+
*/
|
|
82
|
+
declare function decode(input: string, options?: DecodeOptions): unknown;
|
|
83
|
+
/**
|
|
84
|
+
* Validate MINT syntax
|
|
85
|
+
*
|
|
86
|
+
* @param input - MINT-formatted string
|
|
87
|
+
* @returns Validation result with errors
|
|
88
|
+
*/
|
|
89
|
+
declare function validate(input: string): ValidationResult;
|
|
90
|
+
/**
|
|
91
|
+
* Estimate token counts
|
|
92
|
+
*
|
|
93
|
+
* @param data - Data to analyze
|
|
94
|
+
* @returns Token estimates for JSON and MINT
|
|
95
|
+
*/
|
|
96
|
+
declare function estimateTokens(data: unknown): TokenEstimate;
|
|
97
|
+
declare const _default: {
|
|
98
|
+
encode: typeof encode;
|
|
99
|
+
decode: typeof decode;
|
|
100
|
+
validate: typeof validate;
|
|
101
|
+
estimateTokens: typeof estimateTokens;
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
export { type DecodeOptions, type EncodeOptions, type TokenEstimate, type ValidationError, type ValidationResult, decode, _default as default, encode, estimateTokens, validate };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,452 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
var STATUS_SYMBOLS = {
|
|
3
|
+
completed: "\u2713",
|
|
4
|
+
complete: "\u2713",
|
|
5
|
+
success: "\u2713",
|
|
6
|
+
done: "\u2713",
|
|
7
|
+
passed: "\u2713",
|
|
8
|
+
true: "\u2713",
|
|
9
|
+
yes: "\u2713",
|
|
10
|
+
failed: "\u2717",
|
|
11
|
+
failure: "\u2717",
|
|
12
|
+
error: "\u2717",
|
|
13
|
+
rejected: "\u2717",
|
|
14
|
+
false: "\u2717",
|
|
15
|
+
no: "\u2717",
|
|
16
|
+
pending: "\u23F3",
|
|
17
|
+
waiting: "\u23F3",
|
|
18
|
+
in_progress: "\u23F3",
|
|
19
|
+
running: "\u23F3",
|
|
20
|
+
warning: "\u26A0",
|
|
21
|
+
warn: "\u26A0",
|
|
22
|
+
review: "?",
|
|
23
|
+
unknown: "?"
|
|
24
|
+
};
|
|
25
|
+
var REVERSE_SYMBOLS = {
|
|
26
|
+
"\u2713": "true",
|
|
27
|
+
"\u2717": "false",
|
|
28
|
+
"\u23F3": "pending",
|
|
29
|
+
"\u26A0": "warning",
|
|
30
|
+
"?": "unknown"
|
|
31
|
+
};
|
|
32
|
+
function needsQuoting(value) {
|
|
33
|
+
if (value === "") return true;
|
|
34
|
+
if (value.startsWith(" ") || value.endsWith(" ")) return true;
|
|
35
|
+
if (value.includes("|") || value.includes("\n") || value.includes("\r")) return true;
|
|
36
|
+
if (value.includes(",")) return true;
|
|
37
|
+
if (/^-?\d+\.?\d*$/.test(value)) return true;
|
|
38
|
+
if (["true", "false", "null"].includes(value.toLowerCase())) return true;
|
|
39
|
+
if (value.includes(":") && !value.includes("://")) return true;
|
|
40
|
+
if (value.includes('"')) return true;
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
function escapeString(value) {
|
|
44
|
+
return value.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/\t/g, "\\t");
|
|
45
|
+
}
|
|
46
|
+
function unescapeString(value) {
|
|
47
|
+
return value.replace(/\\n/g, "\n").replace(/\\r/g, "\r").replace(/\\t/g, " ").replace(/\\"/g, '"').replace(/\\\\/g, "\\");
|
|
48
|
+
}
|
|
49
|
+
function formatPrimitive(value, options, inTable = false) {
|
|
50
|
+
if (value === null || value === void 0) {
|
|
51
|
+
return inTable ? "-" : "null";
|
|
52
|
+
}
|
|
53
|
+
if (typeof value === "boolean") {
|
|
54
|
+
return String(value);
|
|
55
|
+
}
|
|
56
|
+
if (typeof value === "number") {
|
|
57
|
+
if (!isFinite(value)) return "null";
|
|
58
|
+
return String(value);
|
|
59
|
+
}
|
|
60
|
+
if (typeof value === "string") {
|
|
61
|
+
if (options.compact && STATUS_SYMBOLS[value.toLowerCase()]) {
|
|
62
|
+
return STATUS_SYMBOLS[value.toLowerCase()];
|
|
63
|
+
}
|
|
64
|
+
if (value === "" && inTable) return "-";
|
|
65
|
+
if (needsQuoting(value)) {
|
|
66
|
+
return `"${escapeString(value)}"`;
|
|
67
|
+
}
|
|
68
|
+
return value;
|
|
69
|
+
}
|
|
70
|
+
return String(value);
|
|
71
|
+
}
|
|
72
|
+
function isPrimitive(value) {
|
|
73
|
+
return value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean";
|
|
74
|
+
}
|
|
75
|
+
function isTableArray(arr) {
|
|
76
|
+
if (arr.length === 0) return false;
|
|
77
|
+
if (!arr.every((item) => item !== null && typeof item === "object" && !Array.isArray(item))) {
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
const firstKeys = Object.keys(arr[0]).sort().join(",");
|
|
81
|
+
const sameKeys = arr.every((item) => {
|
|
82
|
+
const keys = Object.keys(item).sort().join(",");
|
|
83
|
+
return keys === firstKeys;
|
|
84
|
+
});
|
|
85
|
+
if (!sameKeys) return false;
|
|
86
|
+
return arr.every((item) => {
|
|
87
|
+
const obj = item;
|
|
88
|
+
return Object.values(obj).every((val) => isPrimitive(val));
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
function isPrimitiveArray(arr) {
|
|
92
|
+
return arr.every((item) => isPrimitive(item));
|
|
93
|
+
}
|
|
94
|
+
function getColumnWidths(headers, rows) {
|
|
95
|
+
const widths = headers.map((h) => h.length);
|
|
96
|
+
for (const row of rows) {
|
|
97
|
+
for (let i = 0; i < row.length; i++) {
|
|
98
|
+
widths[i] = Math.max(widths[i] || 0, row[i]?.length || 0);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return widths;
|
|
102
|
+
}
|
|
103
|
+
function padCell(value, width) {
|
|
104
|
+
return value + " ".repeat(Math.max(0, width - value.length));
|
|
105
|
+
}
|
|
106
|
+
function encodeTable(arr, options, indentLevel) {
|
|
107
|
+
if (arr.length === 0) return "| |";
|
|
108
|
+
const indent = " ".repeat(options.indent || 2);
|
|
109
|
+
const baseIndent = indent.repeat(indentLevel);
|
|
110
|
+
const headers = Object.keys(arr[0]);
|
|
111
|
+
const rows = arr.map((obj) => headers.map((h) => formatPrimitive(obj[h], options, true)));
|
|
112
|
+
const widths = getColumnWidths(headers, rows);
|
|
113
|
+
const lines = [];
|
|
114
|
+
const headerCells = headers.map((h, i) => padCell(h, widths[i]));
|
|
115
|
+
lines.push(`${baseIndent}| ${headerCells.join(" | ")} |`);
|
|
116
|
+
for (const row of rows) {
|
|
117
|
+
const cells = row.map((cell, i) => padCell(cell, widths[i]));
|
|
118
|
+
lines.push(`${baseIndent}| ${cells.join(" | ")} |`);
|
|
119
|
+
}
|
|
120
|
+
return lines.join("\n");
|
|
121
|
+
}
|
|
122
|
+
function encodeValue(value, options, indentLevel) {
|
|
123
|
+
const indent = " ".repeat(options.indent || 2);
|
|
124
|
+
const baseIndent = indent.repeat(indentLevel);
|
|
125
|
+
if (value === null || typeof value !== "object") {
|
|
126
|
+
return formatPrimitive(value, options);
|
|
127
|
+
}
|
|
128
|
+
if (Array.isArray(value)) {
|
|
129
|
+
if (value.length === 0) {
|
|
130
|
+
return "[]";
|
|
131
|
+
}
|
|
132
|
+
if (isPrimitiveArray(value)) {
|
|
133
|
+
return value.map((v) => formatPrimitive(v, options)).join(", ");
|
|
134
|
+
}
|
|
135
|
+
if (isTableArray(value)) {
|
|
136
|
+
return "\n" + encodeTable(value, options, indentLevel + 1);
|
|
137
|
+
}
|
|
138
|
+
const lines2 = [];
|
|
139
|
+
for (const item of value) {
|
|
140
|
+
if (item === null || typeof item !== "object") {
|
|
141
|
+
lines2.push(`${baseIndent}${indent}- ${formatPrimitive(item, options)}`);
|
|
142
|
+
} else {
|
|
143
|
+
const encoded = encodeValue(item, options, indentLevel + 2);
|
|
144
|
+
if (encoded.includes("\n")) {
|
|
145
|
+
lines2.push(`${baseIndent}${indent}-`);
|
|
146
|
+
lines2.push(encoded);
|
|
147
|
+
} else {
|
|
148
|
+
lines2.push(`${baseIndent}${indent}- ${encoded}`);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return "\n" + lines2.join("\n");
|
|
153
|
+
}
|
|
154
|
+
const obj = value;
|
|
155
|
+
const keys = options.sortKeys ? Object.keys(obj).sort() : Object.keys(obj);
|
|
156
|
+
if (keys.length === 0) {
|
|
157
|
+
return "";
|
|
158
|
+
}
|
|
159
|
+
const lines = [];
|
|
160
|
+
for (const key of keys) {
|
|
161
|
+
const val = obj[key];
|
|
162
|
+
if (val === null) {
|
|
163
|
+
lines.push(`${baseIndent}${key}: null`);
|
|
164
|
+
} else if (typeof val !== "object") {
|
|
165
|
+
lines.push(`${baseIndent}${key}: ${formatPrimitive(val, options)}`);
|
|
166
|
+
} else if (Array.isArray(val)) {
|
|
167
|
+
if (val.length === 0) {
|
|
168
|
+
lines.push(`${baseIndent}${key}: []`);
|
|
169
|
+
} else if (isPrimitiveArray(val)) {
|
|
170
|
+
lines.push(`${baseIndent}${key}: ${val.map((v) => formatPrimitive(v, options)).join(", ")}`);
|
|
171
|
+
} else {
|
|
172
|
+
lines.push(`${baseIndent}${key}:${encodeValue(val, options, indentLevel)}`);
|
|
173
|
+
}
|
|
174
|
+
} else {
|
|
175
|
+
const nested = encodeValue(val, options, indentLevel + 1);
|
|
176
|
+
if (nested === "") {
|
|
177
|
+
lines.push(`${baseIndent}${key}:`);
|
|
178
|
+
} else if (nested.includes("\n")) {
|
|
179
|
+
lines.push(`${baseIndent}${key}:`);
|
|
180
|
+
lines.push(nested);
|
|
181
|
+
} else {
|
|
182
|
+
lines.push(`${baseIndent}${key}: ${nested}`);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
return lines.join("\n");
|
|
187
|
+
}
|
|
188
|
+
function encode(value, options = {}) {
|
|
189
|
+
const opts = {
|
|
190
|
+
indent: 2,
|
|
191
|
+
compact: false,
|
|
192
|
+
sortKeys: false,
|
|
193
|
+
...options
|
|
194
|
+
};
|
|
195
|
+
if (value === null || value === void 0) {
|
|
196
|
+
return "null";
|
|
197
|
+
}
|
|
198
|
+
if (typeof value !== "object") {
|
|
199
|
+
return formatPrimitive(value, opts);
|
|
200
|
+
}
|
|
201
|
+
if (Array.isArray(value)) {
|
|
202
|
+
if (value.length === 0) return "_: []";
|
|
203
|
+
if (isPrimitiveArray(value)) {
|
|
204
|
+
return `_: ${value.map((v) => formatPrimitive(v, opts)).join(", ")}`;
|
|
205
|
+
}
|
|
206
|
+
if (isTableArray(value)) {
|
|
207
|
+
return `_:
|
|
208
|
+
${encodeTable(value, opts, 1)}`;
|
|
209
|
+
}
|
|
210
|
+
return `_:${encodeValue(value, opts, 0)}`;
|
|
211
|
+
}
|
|
212
|
+
return encodeValue(value, opts, 0);
|
|
213
|
+
}
|
|
214
|
+
function parsePrimitive(value) {
|
|
215
|
+
const trimmed = value.trim();
|
|
216
|
+
if (trimmed === "null" || trimmed === "-" || trimmed === "") {
|
|
217
|
+
return null;
|
|
218
|
+
}
|
|
219
|
+
if (trimmed === "true") return true;
|
|
220
|
+
if (trimmed === "false") return false;
|
|
221
|
+
if (REVERSE_SYMBOLS[trimmed]) {
|
|
222
|
+
return REVERSE_SYMBOLS[trimmed];
|
|
223
|
+
}
|
|
224
|
+
if (trimmed.startsWith('"') && trimmed.endsWith('"')) {
|
|
225
|
+
return unescapeString(trimmed.slice(1, -1));
|
|
226
|
+
}
|
|
227
|
+
if (/^-?\d+(\.\d+)?([eE][+-]?\d+)?$/.test(trimmed)) {
|
|
228
|
+
const num = Number(trimmed);
|
|
229
|
+
if (isFinite(num)) return num;
|
|
230
|
+
}
|
|
231
|
+
return trimmed;
|
|
232
|
+
}
|
|
233
|
+
function parseTable(lines, startIndex, indent) {
|
|
234
|
+
const result = [];
|
|
235
|
+
let headers = [];
|
|
236
|
+
let i = startIndex;
|
|
237
|
+
const headerLine = lines[i].trim();
|
|
238
|
+
if (!headerLine.startsWith("|")) {
|
|
239
|
+
return { value: [], endIndex: startIndex };
|
|
240
|
+
}
|
|
241
|
+
headers = headerLine.split("|").slice(1, -1).map((h) => h.trim());
|
|
242
|
+
i++;
|
|
243
|
+
while (i < lines.length) {
|
|
244
|
+
const line = lines[i];
|
|
245
|
+
const lineIndent = line.length - line.trimStart().length;
|
|
246
|
+
const trimmed = line.trim();
|
|
247
|
+
if (!trimmed.startsWith("|")) {
|
|
248
|
+
break;
|
|
249
|
+
}
|
|
250
|
+
if (lineIndent < indent && trimmed !== "") {
|
|
251
|
+
break;
|
|
252
|
+
}
|
|
253
|
+
const cells = trimmed.split("|").slice(1, -1).map((c) => parsePrimitive(c.trim()));
|
|
254
|
+
if (cells.length === headers.length) {
|
|
255
|
+
const row = {};
|
|
256
|
+
headers.forEach((h, idx) => {
|
|
257
|
+
row[h] = cells[idx];
|
|
258
|
+
});
|
|
259
|
+
result.push(row);
|
|
260
|
+
}
|
|
261
|
+
i++;
|
|
262
|
+
}
|
|
263
|
+
return { value: result, endIndex: i - 1 };
|
|
264
|
+
}
|
|
265
|
+
function parseDocument(lines, startIndex, baseIndent, options) {
|
|
266
|
+
const result = {};
|
|
267
|
+
let i = startIndex;
|
|
268
|
+
while (i < lines.length) {
|
|
269
|
+
const line = lines[i];
|
|
270
|
+
if (line.trim() === "" || line.trim().startsWith("#")) {
|
|
271
|
+
i++;
|
|
272
|
+
continue;
|
|
273
|
+
}
|
|
274
|
+
const lineIndent = line.length - line.trimStart().length;
|
|
275
|
+
if (lineIndent < baseIndent) {
|
|
276
|
+
break;
|
|
277
|
+
}
|
|
278
|
+
if (lineIndent > baseIndent) {
|
|
279
|
+
i++;
|
|
280
|
+
continue;
|
|
281
|
+
}
|
|
282
|
+
const trimmed = line.trim();
|
|
283
|
+
if (trimmed.startsWith("|")) {
|
|
284
|
+
i++;
|
|
285
|
+
continue;
|
|
286
|
+
}
|
|
287
|
+
const colonIndex = trimmed.indexOf(":");
|
|
288
|
+
if (colonIndex === -1) {
|
|
289
|
+
i++;
|
|
290
|
+
continue;
|
|
291
|
+
}
|
|
292
|
+
const key = trimmed.slice(0, colonIndex).trim();
|
|
293
|
+
const valueStr = trimmed.slice(colonIndex + 1).trim();
|
|
294
|
+
if (valueStr === "" || valueStr === "[]") {
|
|
295
|
+
let foundNested = false;
|
|
296
|
+
let nextIdx = i + 1;
|
|
297
|
+
while (nextIdx < lines.length && lines[nextIdx].trim() === "") {
|
|
298
|
+
nextIdx++;
|
|
299
|
+
}
|
|
300
|
+
if (nextIdx < lines.length) {
|
|
301
|
+
const nextLine = lines[nextIdx];
|
|
302
|
+
const nextIndent = nextLine.length - nextLine.trimStart().length;
|
|
303
|
+
const nextTrimmed = nextLine.trim();
|
|
304
|
+
if (nextIndent > baseIndent && nextTrimmed.startsWith("|")) {
|
|
305
|
+
const tableResult = parseTable(lines, nextIdx, nextIndent);
|
|
306
|
+
result[key] = tableResult.value;
|
|
307
|
+
i = tableResult.endIndex + 1;
|
|
308
|
+
foundNested = true;
|
|
309
|
+
} else if (nextIndent > baseIndent && nextTrimmed !== "" && !nextTrimmed.startsWith("#")) {
|
|
310
|
+
const nestedResult = parseDocument(lines, nextIdx, nextIndent, options);
|
|
311
|
+
result[key] = nestedResult.value;
|
|
312
|
+
i = nestedResult.endIndex;
|
|
313
|
+
foundNested = true;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
if (!foundNested) {
|
|
317
|
+
result[key] = valueStr === "[]" ? [] : {};
|
|
318
|
+
i++;
|
|
319
|
+
}
|
|
320
|
+
} else if (valueStr.startsWith('"') && valueStr.endsWith('"')) {
|
|
321
|
+
result[key] = parsePrimitive(valueStr);
|
|
322
|
+
i++;
|
|
323
|
+
} else if (valueStr.includes(" | ")) {
|
|
324
|
+
result[key] = valueStr.split(" | ").map((v) => parsePrimitive(v.trim()));
|
|
325
|
+
i++;
|
|
326
|
+
} else if (valueStr.includes(", ")) {
|
|
327
|
+
result[key] = valueStr.split(", ").map((v) => parsePrimitive(v.trim()));
|
|
328
|
+
i++;
|
|
329
|
+
} else {
|
|
330
|
+
result[key] = parsePrimitive(valueStr);
|
|
331
|
+
i++;
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
return { value: result, endIndex: i };
|
|
335
|
+
}
|
|
336
|
+
function decode(input, options = {}) {
|
|
337
|
+
const opts = {
|
|
338
|
+
strict: true,
|
|
339
|
+
indent: 2,
|
|
340
|
+
...options
|
|
341
|
+
};
|
|
342
|
+
const normalized = input.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
343
|
+
const lines = normalized.split("\n");
|
|
344
|
+
if (lines.every((l) => l.trim() === "" || l.trim().startsWith("#"))) {
|
|
345
|
+
return {};
|
|
346
|
+
}
|
|
347
|
+
let startIndex = 0;
|
|
348
|
+
while (startIndex < lines.length && (lines[startIndex].trim() === "" || lines[startIndex].trim().startsWith("#"))) {
|
|
349
|
+
startIndex++;
|
|
350
|
+
}
|
|
351
|
+
if (startIndex >= lines.length) {
|
|
352
|
+
return {};
|
|
353
|
+
}
|
|
354
|
+
const firstLine = lines[startIndex].trim();
|
|
355
|
+
if (firstLine.startsWith("|")) {
|
|
356
|
+
const tableResult = parseTable(lines, startIndex, 0);
|
|
357
|
+
return tableResult.value;
|
|
358
|
+
}
|
|
359
|
+
if (firstLine.startsWith("_:")) {
|
|
360
|
+
const valueStr = firstLine.slice(2).trim();
|
|
361
|
+
if (valueStr === "" || valueStr === "[]") {
|
|
362
|
+
const nextLine = lines[startIndex + 1];
|
|
363
|
+
if (nextLine && nextLine.trim().startsWith("|")) {
|
|
364
|
+
const tableResult = parseTable(lines, startIndex + 1, 2);
|
|
365
|
+
return tableResult.value;
|
|
366
|
+
}
|
|
367
|
+
return [];
|
|
368
|
+
}
|
|
369
|
+
if (valueStr.includes(", ")) {
|
|
370
|
+
return valueStr.split(", ").map((v) => parsePrimitive(v.trim()));
|
|
371
|
+
}
|
|
372
|
+
return [parsePrimitive(valueStr)];
|
|
373
|
+
}
|
|
374
|
+
const result = parseDocument(lines, startIndex, 0, opts);
|
|
375
|
+
return result.value;
|
|
376
|
+
}
|
|
377
|
+
function validate(input) {
|
|
378
|
+
const errors = [];
|
|
379
|
+
const lines = input.replace(/\r\n/g, "\n").replace(/\r/g, "\n").split("\n");
|
|
380
|
+
let inTable = false;
|
|
381
|
+
let tableColumns = 0;
|
|
382
|
+
for (let i = 0; i < lines.length; i++) {
|
|
383
|
+
const line = lines[i];
|
|
384
|
+
const lineNum = i + 1;
|
|
385
|
+
const trimmed = line.trim();
|
|
386
|
+
if (trimmed === "" || trimmed.startsWith("#")) {
|
|
387
|
+
continue;
|
|
388
|
+
}
|
|
389
|
+
const indent = line.length - line.trimStart().length;
|
|
390
|
+
if (indent % 2 !== 0) {
|
|
391
|
+
errors.push({
|
|
392
|
+
line: lineNum,
|
|
393
|
+
column: 1,
|
|
394
|
+
message: `Inconsistent indentation: ${indent} spaces (should be multiple of 2)`,
|
|
395
|
+
context: line
|
|
396
|
+
});
|
|
397
|
+
}
|
|
398
|
+
if (trimmed.startsWith("|")) {
|
|
399
|
+
const pipes = trimmed.split("|").length - 1;
|
|
400
|
+
if (!inTable) {
|
|
401
|
+
inTable = true;
|
|
402
|
+
tableColumns = pipes;
|
|
403
|
+
} else {
|
|
404
|
+
if (pipes !== tableColumns) {
|
|
405
|
+
errors.push({
|
|
406
|
+
line: lineNum,
|
|
407
|
+
column: 1,
|
|
408
|
+
message: `Table column mismatch: expected ${tableColumns - 1} columns, got ${pipes - 1}`,
|
|
409
|
+
context: line
|
|
410
|
+
});
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
if (!trimmed.endsWith("|")) {
|
|
414
|
+
errors.push({
|
|
415
|
+
line: lineNum,
|
|
416
|
+
column: trimmed.length,
|
|
417
|
+
message: "Table row must end with |",
|
|
418
|
+
context: line
|
|
419
|
+
});
|
|
420
|
+
}
|
|
421
|
+
} else {
|
|
422
|
+
inTable = false;
|
|
423
|
+
tableColumns = 0;
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
return {
|
|
427
|
+
valid: errors.length === 0,
|
|
428
|
+
errors
|
|
429
|
+
};
|
|
430
|
+
}
|
|
431
|
+
function estimateTokens(data) {
|
|
432
|
+
const jsonStr = JSON.stringify(data, null, 2);
|
|
433
|
+
const mintStr = encode(data);
|
|
434
|
+
const jsonTokens = Math.ceil(jsonStr.length / 3.5);
|
|
435
|
+
const mintTokens = Math.ceil(mintStr.length / 3.5);
|
|
436
|
+
const savings = jsonTokens - mintTokens;
|
|
437
|
+
const savingsPercent = Math.round(savings / jsonTokens * 100);
|
|
438
|
+
return {
|
|
439
|
+
json: jsonTokens,
|
|
440
|
+
mint: mintTokens,
|
|
441
|
+
savings,
|
|
442
|
+
savingsPercent
|
|
443
|
+
};
|
|
444
|
+
}
|
|
445
|
+
var index_default = { encode, decode, validate, estimateTokens };
|
|
446
|
+
export {
|
|
447
|
+
decode,
|
|
448
|
+
index_default as default,
|
|
449
|
+
encode,
|
|
450
|
+
estimateTokens,
|
|
451
|
+
validate
|
|
452
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@q1k-oss/mint-format",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "🌿 MINT Format encoder/decoder - Minimal Inference Notation for Tokens",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"mint",
|
|
7
|
+
"format",
|
|
8
|
+
"serialization",
|
|
9
|
+
"llm",
|
|
10
|
+
"token",
|
|
11
|
+
"json",
|
|
12
|
+
"encoder",
|
|
13
|
+
"decoder",
|
|
14
|
+
"minimal"
|
|
15
|
+
],
|
|
16
|
+
"homepage": "https://github.com/q1k-oss/mint",
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "git+https://github.com/q1k-oss/mint.git",
|
|
20
|
+
"directory": "packages/mint"
|
|
21
|
+
},
|
|
22
|
+
"license": "MIT",
|
|
23
|
+
"author": "MINT Format Contributors",
|
|
24
|
+
"type": "module",
|
|
25
|
+
"exports": {
|
|
26
|
+
".": {
|
|
27
|
+
"types": "./dist/index.d.ts",
|
|
28
|
+
"import": "./dist/index.js",
|
|
29
|
+
"require": "./dist/index.cjs"
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
"main": "./dist/index.cjs",
|
|
33
|
+
"module": "./dist/index.js",
|
|
34
|
+
"types": "./dist/index.d.ts",
|
|
35
|
+
"files": [
|
|
36
|
+
"dist",
|
|
37
|
+
"README.md",
|
|
38
|
+
"LICENSE"
|
|
39
|
+
],
|
|
40
|
+
"scripts": {
|
|
41
|
+
"build": "tsup src/index.ts --format cjs,esm --dts --clean",
|
|
42
|
+
"clean": "rm -rf dist",
|
|
43
|
+
"dev": "tsup src/index.ts --format cjs,esm --dts --watch",
|
|
44
|
+
"lint": "eslint src --ext .ts",
|
|
45
|
+
"test": "vitest run",
|
|
46
|
+
"test:watch": "vitest",
|
|
47
|
+
"test:coverage": "vitest run --coverage",
|
|
48
|
+
"typecheck": "tsc --noEmit"
|
|
49
|
+
},
|
|
50
|
+
"devDependencies": {
|
|
51
|
+
"@types/node": "^20.10.0",
|
|
52
|
+
"tsup": "^8.0.1",
|
|
53
|
+
"typescript": "^5.3.2",
|
|
54
|
+
"vitest": "^1.0.0"
|
|
55
|
+
},
|
|
56
|
+
"publishConfig": {
|
|
57
|
+
"access": "public"
|
|
58
|
+
},
|
|
59
|
+
"engines": {
|
|
60
|
+
"node": ">=16.0.0"
|
|
61
|
+
}
|
|
62
|
+
}
|