@yeseh/cortex-cli 0.6.8 → 0.6.9

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.
Files changed (74) hide show
  1. package/dist/program.js +1538 -5
  2. package/dist/program.js.map +32 -3
  3. package/dist/run.d.ts +0 -1
  4. package/dist/run.d.ts.map +1 -1
  5. package/dist/run.js +3 -4
  6. package/dist/run.js.map +3 -3
  7. package/package.json +4 -6
  8. package/dist/chunk-dsfj4baj.js +0 -1543
  9. package/dist/chunk-dsfj4baj.js.map +0 -38
  10. package/src/category/commands/create.spec.ts +0 -139
  11. package/src/category/commands/create.ts +0 -119
  12. package/src/category/index.ts +0 -24
  13. package/src/commands/init.spec.ts +0 -203
  14. package/src/commands/init.ts +0 -301
  15. package/src/context.spec.ts +0 -60
  16. package/src/context.ts +0 -170
  17. package/src/errors.spec.ts +0 -264
  18. package/src/errors.ts +0 -105
  19. package/src/memory/commands/add.spec.ts +0 -169
  20. package/src/memory/commands/add.ts +0 -158
  21. package/src/memory/commands/definitions.spec.ts +0 -80
  22. package/src/memory/commands/list.spec.ts +0 -123
  23. package/src/memory/commands/list.ts +0 -269
  24. package/src/memory/commands/move.spec.ts +0 -85
  25. package/src/memory/commands/move.ts +0 -119
  26. package/src/memory/commands/remove.spec.ts +0 -79
  27. package/src/memory/commands/remove.ts +0 -108
  28. package/src/memory/commands/show.spec.ts +0 -71
  29. package/src/memory/commands/show.ts +0 -165
  30. package/src/memory/commands/test-helpers.spec.ts +0 -127
  31. package/src/memory/commands/update.spec.ts +0 -86
  32. package/src/memory/commands/update.ts +0 -230
  33. package/src/memory/index.spec.ts +0 -59
  34. package/src/memory/index.ts +0 -44
  35. package/src/memory/parsing.spec.ts +0 -105
  36. package/src/memory/parsing.ts +0 -22
  37. package/src/observability.spec.ts +0 -126
  38. package/src/observability.ts +0 -82
  39. package/src/output.spec.ts +0 -835
  40. package/src/output.ts +0 -119
  41. package/src/program.spec.ts +0 -46
  42. package/src/program.ts +0 -75
  43. package/src/run.spec.ts +0 -31
  44. package/src/run.ts +0 -9
  45. package/src/store/commands/add.spec.ts +0 -131
  46. package/src/store/commands/add.ts +0 -231
  47. package/src/store/commands/init.spec.ts +0 -220
  48. package/src/store/commands/init.ts +0 -272
  49. package/src/store/commands/list.spec.ts +0 -175
  50. package/src/store/commands/list.ts +0 -102
  51. package/src/store/commands/prune.spec.ts +0 -120
  52. package/src/store/commands/prune.ts +0 -152
  53. package/src/store/commands/reindexs.spec.ts +0 -94
  54. package/src/store/commands/reindexs.ts +0 -97
  55. package/src/store/commands/remove.spec.ts +0 -97
  56. package/src/store/commands/remove.ts +0 -189
  57. package/src/store/index.spec.ts +0 -60
  58. package/src/store/index.ts +0 -49
  59. package/src/store/utils/resolve-store-name.spec.ts +0 -62
  60. package/src/store/utils/resolve-store-name.ts +0 -79
  61. package/src/test-helpers.spec.ts +0 -430
  62. package/src/tests/cli.integration.spec.ts +0 -1306
  63. package/src/toon.spec.ts +0 -183
  64. package/src/toon.ts +0 -462
  65. package/src/utils/git.spec.ts +0 -95
  66. package/src/utils/git.ts +0 -51
  67. package/src/utils/input.spec.ts +0 -326
  68. package/src/utils/input.ts +0 -150
  69. package/src/utils/paths.spec.ts +0 -235
  70. package/src/utils/paths.ts +0 -75
  71. package/src/utils/prompts.spec.ts +0 -23
  72. package/src/utils/prompts.ts +0 -88
  73. package/src/utils/resolve-default-store.spec.ts +0 -135
  74. package/src/utils/resolve-default-store.ts +0 -74
package/src/toon.spec.ts DELETED
@@ -1,183 +0,0 @@
1
- /**
2
- * Unit tests for toon.ts
3
- *
4
- * TOON (Token-Oriented Object Notation) encoder.
5
- *
6
- * @module cli/toon.spec
7
- */
8
-
9
- import { describe, it, expect } from 'bun:test';
10
- import { encode } from './toon';
11
-
12
- // ============================================================================
13
- // encode - primitives
14
- // ============================================================================
15
-
16
- describe('encode - primitives', () => {
17
- it('should encode a string primitive', () => {
18
- // Top-level primitive string: no key, just the value
19
- expect(encode('hello')).toBe('hello');
20
- });
21
-
22
- it('should encode a number primitive', () => {
23
- expect(encode(42)).toBe('42');
24
- });
25
-
26
- it('should encode a boolean primitive', () => {
27
- expect(encode(true)).toBe('true');
28
- expect(encode(false)).toBe('false');
29
- });
30
-
31
- it('should encode null as "null"', () => {
32
- expect(encode(null)).toBe('null');
33
- });
34
-
35
- it('should encode undefined as "null"', () => {
36
- expect(encode(undefined)).toBe('null');
37
- });
38
-
39
- it('should quote strings containing the delimiter (tab)', () => {
40
- expect(encode('hello\tworld')).toBe('"hello\\tworld"');
41
- });
42
-
43
- it('should quote strings containing a colon (:)', () => {
44
- expect(encode('key:value')).toBe('"key:value"');
45
- });
46
-
47
- it('should quote strings containing a newline', () => {
48
- expect(encode('line1\nline2')).toBe('"line1\\nline2"');
49
- });
50
-
51
- it('should quote strings containing a double quote', () => {
52
- expect(encode('"quoted"')).toBe('"\\"quoted\\""');
53
- });
54
- });
55
-
56
- // ============================================================================
57
- // encode - flat objects
58
- // ============================================================================
59
-
60
- describe('encode - flat objects', () => {
61
- it('should encode a single key-value pair', () => {
62
- expect(encode({ name: 'test' })).toBe('name:test');
63
- });
64
-
65
- it('should encode multiple key-value pairs with tab delimiter', () => {
66
- expect(encode({ name: 'test', count: 42 })).toBe('name:test\tcount:42');
67
- });
68
-
69
- it('should use custom delimiter when specified', () => {
70
- expect(encode({ a: 1, b: 2 }, { delimiter: '|' })).toBe('a:1|b:2');
71
- });
72
- });
73
-
74
- // ============================================================================
75
- // encode - nested objects (no key folding)
76
- // ============================================================================
77
-
78
- describe('encode - nested objects (no key folding)', () => {
79
- it('should encode nested object with inline braces', () => {
80
- // "user:{name:Alice\trole:admin}"
81
- expect(encode({ user: { name: 'Alice', role: 'admin' } })).toBe('user:{name:Alice\trole:admin}');
82
- });
83
-
84
- it('should handle deeply nested objects', () => {
85
- // "a:{b:{c:deep}}"
86
- expect(encode({ a: { b: { c: 'deep' } } })).toBe('a:{b:{c:deep}}');
87
- });
88
- });
89
-
90
- // ============================================================================
91
- // encode - key folding
92
- // ============================================================================
93
-
94
- describe('encode - key folding', () => {
95
- it('should flatten nested object to dotted keys with keyFolding:safe', () => {
96
- expect(encode({ user: { name: 'Alice', role: 'admin' } }, { keyFolding: 'safe' }))
97
- .toBe('user.name:Alice\tuser.role:admin');
98
- });
99
-
100
- it('should handle multi-level nesting with keyFolding:safe', () => {
101
- expect(encode(
102
- { user: { profile: { name: 'Alice' }, settings: { theme: 'dark' } } },
103
- { keyFolding: 'safe' },
104
- )).toBe('user.profile.name:Alice\tuser.settings.theme:dark');
105
- });
106
- });
107
-
108
- // ============================================================================
109
- // encode - arrays
110
- // ============================================================================
111
-
112
- describe('encode - arrays', () => {
113
- it('should encode uniform array of objects in tabular format', () => {
114
- const input = {
115
- items: [
116
- { id: 1, name: 'Alice' },
117
- { id: 2, name: 'Bob' },
118
- ],
119
- };
120
- // items[2]{id\tname}:\n\t1\tAlice\n\t2\tBob
121
- const expected = 'items[2]{id\tname}:\n\t1\tAlice\n\t2\tBob';
122
- expect(encode(input)).toBe(expected);
123
- });
124
-
125
- it('should encode empty array as quoted empty string (serializePrimitive path)', () => {
126
- // isUniformArray returns false for empty arrays; the else branch in the
127
- // object serialiser calls serializePrimitive([], delimiter) which does
128
- // quoteString(String([])) → '""'
129
- expect(encode({ items: [] })).toBe('items:""');
130
- });
131
-
132
- it('should serialize non-uniform array via serializePrimitive (String coercion)', () => {
133
- // Non-uniform arrays fall through to the else branch in the object
134
- // serialiser → serializePrimitive → quoteString(String([...]))
135
- const input = {
136
- items: [
137
- { id: 1, name: 'Alice' },
138
- { id: 2 }, // missing 'name' key — non-uniform
139
- ],
140
- };
141
- expect(encode(input)).toBe('items:"[object Object],[object Object]"');
142
- });
143
-
144
- it('should serialize primitive array via serializePrimitive (comma-joined string)', () => {
145
- // Primitive arrays also go through serializePrimitive → quoteString(String([...]))
146
- expect(encode({ tags: [
147
- 'a',
148
- 'b',
149
- 'c',
150
- ] })).toBe('tags:"a,b,c"');
151
- });
152
-
153
- it('should serialize array of mixed types via serializePrimitive', () => {
154
- expect(encode({ mixed: [
155
- 1,
156
- 'two',
157
- true,
158
- ] })).toBe('mixed:"1,two,true"');
159
- });
160
- });
161
-
162
- // ============================================================================
163
- // encode - edge cases
164
- // ============================================================================
165
-
166
- describe('encode - edge cases', () => {
167
- it('should encode an empty object', () => {
168
- expect(encode({})).toBe('');
169
- });
170
-
171
- it('should handle object with array of uniform items alongside other fields', () => {
172
- const input = {
173
- title: 'Report',
174
- rows: [
175
- { id: 1, val: 'a' },
176
- { id: 2, val: 'b' },
177
- ],
178
- };
179
- // "title:Report\trows[2]{id\tval}:\n\t1\ta\n\t2\tb"
180
- const expected = 'title:Report\trows[2]{id\tval}:\n\t1\ta\n\t2\tb';
181
- expect(encode(input)).toBe(expected);
182
- });
183
- });
package/src/toon.ts DELETED
@@ -1,462 +0,0 @@
1
- /**
2
- * TOON (Token-Oriented Object Notation) encoder.
3
- *
4
- * A compact serialization format optimized for LLM context consumption,
5
- * achieving approximately 40% token reduction compared to JSON while
6
- * improving parsing accuracy from 70% to 74% in LLM benchmarks.
7
- *
8
- * ## Key Features
9
- *
10
- * - **Tab delimiters** - Uses tabs between key-value pairs instead of JSON's
11
- * commas and braces, maximizing token efficiency
12
- * - **Key folding** - Collapses nested object paths to dotted notation
13
- * (e.g., `user.profile.name` instead of nested objects)
14
- * - **Tabular arrays** - Uniform object arrays use a compact header+rows format,
15
- * dramatically reducing repetition
16
- *
17
- * ## Format Specification
18
- *
19
- * | JSON Construct | TOON Equivalent |
20
- * |----------------|-----------------|
21
- * | `{"key": "value"}` | `key:value` |
22
- * | `{"a": 1, "b": 2}` | `a:1\tb:2` |
23
- * | Nested object | `parent.child:value` (with key folding) |
24
- * | Uniform array | `items[N]{col1\tcol2}:\n\tval1\tval2` |
25
- *
26
- * ## Token Efficiency
27
- *
28
- * TOON reduces token count through:
29
- * 1. Eliminating JSON syntax tokens (`{`, `}`, `[`, `]`, `,`, `"`)
30
- * 2. Using single-character delimiters (tabs, colons)
31
- * 3. Deduplicating keys in tabular array format
32
- *
33
- * Typical savings:
34
- * - Simple objects: ~30% reduction
35
- * - Nested objects with key folding: ~40% reduction
36
- * - Arrays of uniform objects: ~50% reduction
37
- *
38
- * @module cli/toon
39
- *
40
- * @example Basic object encoding
41
- * ```ts
42
- * import { encode } from './toon';
43
- *
44
- * encode({ name: 'test', count: 42 });
45
- * // Output: "name:test\tcount:42"
46
- * ```
47
- *
48
- * @example Key folding for nested objects
49
- * ```ts
50
- * encode(
51
- * { user: { name: 'Alice', role: 'admin' } },
52
- * { keyFolding: 'safe' }
53
- * );
54
- * // Output: "user.name:Alice\tuser.role:admin"
55
- * //
56
- * // Without key folding:
57
- * // "user:{name:Alice\trole:admin}"
58
- * ```
59
- *
60
- * @example Tabular arrays (automatic for uniform object arrays)
61
- * ```ts
62
- * encode({
63
- * items: [
64
- * { id: 1, name: 'Widget' },
65
- * { id: 2, name: 'Gadget' },
66
- * ]
67
- * });
68
- * // Output:
69
- * // "items[2]{id\tname}:
70
- * // \t1\tWidget
71
- * // \t2\tGadget"
72
- * //
73
- * // Equivalent JSON (32 tokens):
74
- * // {"items":[{"id":1,"name":"Widget"},{"id":2,"name":"Gadget"}]}
75
- * // TOON version (18 tokens): ~44% reduction
76
- * ```
77
- *
78
- * @see {@link ToonOptions} for configuration options
79
- * @see {@link encode} for the main encoding function
80
- */
81
-
82
- /**
83
- * Configuration options for TOON encoding.
84
- *
85
- * @example Using custom delimiter
86
- * ```ts
87
- * encode({ a: 1, b: 2 }, { delimiter: '|' });
88
- * // Output: "a:1|b:2"
89
- * ```
90
- *
91
- * @example Enabling key folding
92
- * ```ts
93
- * encode({ config: { debug: true } }, { keyFolding: 'safe' });
94
- * // Output: "config.debug:true"
95
- * ```
96
- */
97
- export interface ToonOptions {
98
- /**
99
- * Character used to separate key-value pairs.
100
- *
101
- * The tab character (`\t`) is used by default as it provides optimal
102
- * token efficiency in most LLM tokenizers (single token per delimiter).
103
- *
104
- * @default '\t'
105
- */
106
- delimiter?: string;
107
-
108
- /**
109
- * Controls how nested objects are serialized.
110
- *
111
- * - `'none'` - Nested objects are serialized inline with braces:
112
- * `parent:{child:value}`
113
- * - `'safe'` - Nested paths are collapsed to dotted notation:
114
- * `parent.child:value`
115
- *
116
- * Key folding (`'safe'`) typically produces more compact output and is
117
- * easier for LLMs to parse, but may cause key collisions if object
118
- * keys contain dots.
119
- *
120
- * @default 'none'
121
- */
122
- keyFolding?: 'safe' | 'none';
123
- }
124
-
125
- /**
126
- * Default encoding options.
127
- *
128
- * - `delimiter`: Tab character for maximum token efficiency
129
- * - `keyFolding`: Disabled by default for safety (avoids key collisions)
130
- */
131
- const DEFAULT_OPTIONS: Required<ToonOptions> = {
132
- delimiter: '\t',
133
- keyFolding: 'none',
134
- };
135
-
136
- /**
137
- * Checks if a string needs quoting (contains delimiter, newline, or special chars).
138
- *
139
- * Values containing these characters must be quoted to preserve TOON format integrity:
140
- * - The delimiter character (default: tab)
141
- * - Newlines (`\n`, `\r`)
142
- * - Double quotes (`"`)
143
- * - Colons (`:`) - used as key-value separator
144
- *
145
- * @param value - The string value to check
146
- * @param delimiter - The current delimiter character
147
- * @returns `true` if the value requires quoting
148
- */
149
- const needsQuoting = (value: string, delimiter: string): boolean => {
150
- return (
151
- value.includes(delimiter) ||
152
- value.includes('\n') ||
153
- value.includes('\r') ||
154
- value.includes('"') ||
155
- value.includes(':')
156
- );
157
- };
158
-
159
- /**
160
- * Quotes a string value for TOON output.
161
- *
162
- * Uses JSON string escaping rules to ensure special characters are
163
- * properly escaped in the output.
164
- *
165
- * @param value - The string to quote
166
- * @returns JSON-escaped quoted string
167
- */
168
- const quoteString = (value: string): string => {
169
- return JSON.stringify(value);
170
- };
171
-
172
- /**
173
- * Serializes a primitive value to its TOON string representation.
174
- *
175
- * Handles the following types:
176
- * - `null`/`undefined` → `"null"`
177
- * - `string` → quoted if contains special chars, otherwise raw
178
- * - `number`/`boolean` → string representation
179
- * - Other types → JSON-stringified
180
- *
181
- * @param value - The primitive value to serialize
182
- * @param delimiter - The delimiter used for quoting decisions
183
- * @returns TOON string representation of the value
184
- */
185
- const serializePrimitive = (value: unknown, delimiter: string): string => {
186
- if (value === null) return 'null';
187
- if (value === undefined) return 'null';
188
- if (typeof value === 'string') {
189
- return needsQuoting(value, delimiter) ? quoteString(value) : value;
190
- }
191
- if (typeof value === 'number' || typeof value === 'boolean') {
192
- return String(value);
193
- }
194
- return quoteString(String(value));
195
- };
196
-
197
- /**
198
- * Checks if an array contains uniform objects (all same keys).
199
- *
200
- * Uniform arrays qualify for the more compact tabular format where
201
- * column headers are specified once and rows contain only values.
202
- *
203
- * An array is uniform if:
204
- * 1. It contains at least one element
205
- * 2. All elements are non-null objects (not arrays)
206
- * 3. All objects have exactly the same keys
207
- *
208
- * @param arr - The array to check
209
- * @returns Type predicate indicating if array contains uniform objects
210
- */
211
- const isUniformArray = (arr: unknown[]): arr is Record<string, unknown>[] => {
212
- if (arr.length === 0) return false;
213
- if (!arr.every((item) => typeof item === 'object' && item !== null && !Array.isArray(item))) {
214
- return false;
215
- }
216
- const first = arr[0] as Record<string, unknown>;
217
- const firstKeys = Object.keys(first).sort().join(',');
218
- return arr.every(
219
- (item) =>
220
- Object.keys(item as object)
221
- .sort()
222
- .join(',') === firstKeys,
223
- );
224
- };
225
-
226
- /**
227
- * Serializes a uniform array in tabular format.
228
- *
229
- * Tabular format provides significant token savings for arrays of objects
230
- * with identical structure by specifying column headers once.
231
- *
232
- * Format: `key[count]{col1\tcol2}:\n\tval1\tval2\n\tval3\tval4`
233
- *
234
- * @param arr - Array of uniform objects to serialize
235
- * @param key - The property name for this array
236
- * @param delimiter - Character used between values
237
- * @returns Tabular TOON representation
238
- *
239
- * @example
240
- * ```ts
241
- * serializeTabularArray(
242
- * [{ id: 1, name: 'a' }, { id: 2, name: 'b' }],
243
- * 'items',
244
- * '\t'
245
- * );
246
- * // Returns:
247
- * // "items[2]{id\tname}:
248
- * // \t1\ta
249
- * // \t2\tb"
250
- * ```
251
- */
252
- const serializeTabularArray = (
253
- arr: Record<string, unknown>[],
254
- key: string,
255
- delimiter: string,
256
- ): string => {
257
- if (arr.length === 0) return `${key}:[]`;
258
-
259
- const first = arr[0] as Record<string, unknown>;
260
- const headers = Object.keys(first);
261
- const headerLine = `${key}[${arr.length}]{${headers.join(delimiter)}}:`;
262
-
263
- const rows = arr.map((item) => {
264
- const values = headers.map((h) => serializePrimitive(item[h], delimiter));
265
- return delimiter + values.join(delimiter);
266
- });
267
-
268
- return [
269
- headerLine, ...rows,
270
- ].join('\n');
271
- };
272
-
273
- /**
274
- * Flattens an object with key folding (dotted notation).
275
- *
276
- * Recursively traverses nested objects and creates a flat object with
277
- * dotted key paths. Arrays are preserved as-is (not flattened).
278
- *
279
- * @param obj - The object to flatten
280
- * @param prefix - Current key prefix for recursion (empty string at root)
281
- * @returns Flattened object with dotted keys
282
- *
283
- * @example
284
- * ```ts
285
- * flattenObject({ user: { name: 'Alice', settings: { theme: 'dark' } } });
286
- * // Returns: { 'user.name': 'Alice', 'user.settings.theme': 'dark' }
287
- * ```
288
- */
289
- const flattenObject = (
290
- obj: Record<string, unknown>,
291
- prefix: string = '',
292
- ): Record<string, unknown> => {
293
- const result: Record<string, unknown> = {};
294
-
295
- for (const [
296
- key, value,
297
- ] of Object.entries(obj)) {
298
- const fullKey = prefix ? `${prefix}.${key}` : key;
299
-
300
- if (value !== null && typeof value === 'object' && !Array.isArray(value)) {
301
- Object.assign(result, flattenObject(value as Record<string, unknown>, fullKey));
302
- }
303
- else {
304
- result[fullKey] = value;
305
- }
306
- }
307
-
308
- return result;
309
- };
310
-
311
- /**
312
- * Serializes a value to TOON format (internal recursive function).
313
- *
314
- * Handles all value types and applies the appropriate serialization strategy:
315
- * - Primitives: Direct serialization with optional quoting
316
- * - Arrays: Tabular format for uniform objects, JSON for mixed/primitive arrays
317
- * - Objects: Key folding or inline braces based on options
318
- *
319
- * @param value - The value to serialize
320
- * @param options - Encoding options (fully resolved with defaults)
321
- * @param key - Optional key name when serializing as an object property
322
- * @returns TOON-formatted string
323
- */
324
- const serializeValue = (value: unknown, options: Required<ToonOptions>, key?: string): string => {
325
- const { delimiter, keyFolding } = options;
326
-
327
- // Handle primitives
328
- if (value === null || value === undefined) {
329
- return key ? `${key}:null` : 'null';
330
- }
331
-
332
- if (typeof value !== 'object') {
333
- const serialized = serializePrimitive(value, delimiter);
334
- return key ? `${key}:${serialized}` : serialized;
335
- }
336
-
337
- // Handle arrays
338
- if (Array.isArray(value)) {
339
- if (isUniformArray(value) && key) {
340
- return serializeTabularArray(value, key, delimiter);
341
- }
342
- // Non-uniform arrays: serialize as JSON array
343
- const serialized = JSON.stringify(value);
344
- return key ? `${key}:${serialized}` : serialized;
345
- }
346
-
347
- // Handle objects
348
- let obj = value as Record<string, unknown>;
349
- if (keyFolding === 'safe') {
350
- obj = flattenObject(obj);
351
- }
352
-
353
- const entries = Object.entries(obj);
354
- const parts: string[] = [];
355
-
356
- for (const [
357
- k, v,
358
- ] of entries) {
359
- if (Array.isArray(v) && isUniformArray(v)) {
360
- parts.push(serializeTabularArray(v, k, delimiter));
361
- }
362
- else if (
363
- typeof v === 'object' &&
364
- v !== null &&
365
- !Array.isArray(v) &&
366
- keyFolding !== 'safe'
367
- ) {
368
- // Nested object without key folding - serialize inline
369
- parts.push(`${k}:{${serializeValue(v, options)}}`);
370
- }
371
- else {
372
- const serialized = serializePrimitive(v, delimiter);
373
- parts.push(`${k}:${serialized}`);
374
- }
375
- }
376
-
377
- const result = parts.join(delimiter);
378
- return key ? `${key}:{${result}}` : result;
379
- };
380
-
381
- /**
382
- * Encodes a value to TOON format.
383
- *
384
- * TOON (Token-Oriented Object Notation) is a compact serialization format
385
- * designed to minimize token consumption in LLM contexts while remaining
386
- * human-readable and easily parseable by language models.
387
- *
388
- * @param value - The value to encode (must be JSON-serializable)
389
- * @param options - Encoding options for customizing output format
390
- * @returns TOON-encoded string representation
391
- *
392
- * @example Basic object encoding
393
- * ```ts
394
- * const data = { name: 'test', count: 42 };
395
- * encode(data);
396
- * // Returns: "name:test\tcount:42"
397
- * //
398
- * // Equivalent JSON: {"name":"test","count":42}
399
- * // Token savings: ~35%
400
- * ```
401
- *
402
- * @example Nested objects with key folding
403
- * ```ts
404
- * const nested = {
405
- * user: {
406
- * profile: { name: 'Alice', email: 'alice@example.com' },
407
- * settings: { theme: 'dark' }
408
- * }
409
- * };
410
- *
411
- * // Without key folding (default):
412
- * encode(nested);
413
- * // Returns: "user:{profile:{name:Alice\temail:alice@example.com}\tsettings:{theme:dark}}"
414
- *
415
- * // With key folding:
416
- * encode(nested, { keyFolding: 'safe' });
417
- * // Returns: "user.profile.name:Alice\tuser.profile.email:alice@example.com\tuser.settings.theme:dark"
418
- * ```
419
- *
420
- * @example Tabular arrays (automatic for uniform object arrays)
421
- * ```ts
422
- * const users = {
423
- * users: [
424
- * { id: 1, name: 'Alice', role: 'admin' },
425
- * { id: 2, name: 'Bob', role: 'user' },
426
- * { id: 3, name: 'Charlie', role: 'user' },
427
- * ]
428
- * };
429
- *
430
- * encode(users);
431
- * // Returns:
432
- * // "users[3]{id\tname\trole}:
433
- * // \t1\tAlice\tadmin
434
- * // \t2\tBob\tuser
435
- * // \t3\tCharlie\tuser"
436
- * //
437
- * // Equivalent JSON (87 chars, ~25 tokens):
438
- * // {"users":[{"id":1,"name":"Alice","role":"admin"},{"id":2,"name":"Bob","role":"user"},{"id":3,"name":"Charlie","role":"user"}]}
439
- * //
440
- * // TOON (67 chars, ~15 tokens): ~40% token reduction
441
- * ```
442
- *
443
- * @example Mixed content
444
- * ```ts
445
- * encode({
446
- * title: 'Report',
447
- * metadata: { version: 1 },
448
- * tags: ['urgent', 'review'] // Non-uniform arrays use JSON format
449
- * }, { keyFolding: 'safe' });
450
- * // Returns: "title:Report\tmetadata.version:1\ttags:[\"urgent\",\"review\"]"
451
- * ```
452
- *
453
- * @see {@link ToonOptions} for available configuration options
454
- */
455
- export const encode = (value: unknown, options?: ToonOptions): string => {
456
- const mergedOptions: Required<ToonOptions> = {
457
- ...DEFAULT_OPTIONS,
458
- ...options,
459
- };
460
-
461
- return serializeValue(value, mergedOptions);
462
- };