@rfanth/tjson 0.3.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/LICENSE ADDED
@@ -0,0 +1,11 @@
1
+ Copyright 2026 R.F. Anthracite (rfa at no spam rfanth no spam com)
2
+
3
+ Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
4
+
5
+ 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
6
+
7
+ 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
8
+
9
+ 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
10
+
11
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package/README.md ADDED
@@ -0,0 +1,103 @@
1
+ # tjson-rs
2
+
3
+ A Rust library and CLI tool for [TJSON](https://textjson.com)
4
+
5
+ TJSON is a hyper-readable, round trip safe and data preserving substitute for JSON that feels like text and represents the same data while looking quite different and allowing different generator rules to optimize readibility. It is not a superset or a subset of JSON. It's commonality is that it represents the same underlying data, not the format itself. It's position based to emphasize locality of meaning, and adds bare strings, pipe tables, comments, multiline string literals, and line folding to make the contained data easier to read while remaining fully convertible to and from standard JSON without data loss. TJSON is optimized for reading and deterministic data, not human editing.
6
+
7
+ Usage as a binary, library (including WASM too), and through serde Serialize are all fully supported.
8
+
9
+ ## Installation
10
+
11
+ Add to your `Cargo.toml`:
12
+
13
+ ```toml
14
+ [dependencies]
15
+ tjson = "0.1"
16
+ ```
17
+
18
+ Install the CLI:
19
+
20
+ ```sh
21
+ cargo install tjson-rs
22
+ ```
23
+
24
+ ## Library Usage
25
+
26
+ ### Parse TJSON
27
+
28
+ ```rust
29
+ use tjson::TjsonValue;
30
+
31
+ // Parse a TJSON object (keys indented 2 spaces at the top level)
32
+ let value: TjsonValue = " name: Alice\n age:30".parse()?;
33
+
34
+ // Parse a bare string
35
+ let value: TjsonValue = " hello world".parse()?;
36
+ ```
37
+
38
+ ### Render to TJSON
39
+
40
+ ```rust
41
+ use tjson::{TjsonValue, TjsonOptions};
42
+
43
+ let value = TjsonValue::from(serde_json::json!({"name": "Alice", "age": 30}));
44
+
45
+ // Default options
46
+ let tjson = value.to_tjson_with(TjsonOptions::default())?;
47
+
48
+ // Canonical (one key per line, no packing)
49
+ let canonical = value.to_tjson_with(TjsonOptions::canonical())?;
50
+ ```
51
+
52
+ ### Serde integration
53
+
54
+ ```rust
55
+ use serde::{Deserialize, Serialize};
56
+
57
+ #[derive(Serialize, Deserialize)]
58
+ struct Person {
59
+ name: String,
60
+ age: u32,
61
+ }
62
+
63
+ // Deserialize from TJSON
64
+ let person: Person = tjson::from_str(" name: Alice\n age:30")?;
65
+
66
+ // Serialize to TJSON
67
+ let tjson = tjson::to_string(&person)?;
68
+ ```
69
+
70
+ ## CLI Usage
71
+
72
+ ```sh
73
+ # JSON to TJSON
74
+ echo '{"name":"Alice","scores":[1,2,3]}' | tjson
75
+
76
+ # TJSON to JSON
77
+ echo ' name: Alice' | tjson --json
78
+
79
+ # From/to files
80
+ tjson -i data.json -o data.tjson
81
+ tjson --json -i data.tjson -o data.json
82
+
83
+ # Canonical output
84
+ tjson --canonical -i data.json
85
+ ```
86
+
87
+ ## WASM / JavaScript
88
+
89
+ The library compiles to WebAssembly via [wasm-pack](https://rustwasm.github.io/wasm-pack/):
90
+
91
+ ```sh
92
+ wasm-pack build --target bundler
93
+ ```
94
+
95
+ ## Resources
96
+
97
+ - Website and online demo: [textjson.com](https://textjson.com)
98
+ - Specification: _coming soon_
99
+ - Test suite: _coming soon_
100
+
101
+ ## License
102
+
103
+ BSD-3-Clause. See [LICENSE](LICENSE).
package/package.json ADDED
@@ -0,0 +1,25 @@
1
+ {
2
+ "name": "@rfanth/tjson",
3
+ "type": "module",
4
+ "description": "Text JSON (TJSON) - a readability optimized, round trip compatible alternative to JSON",
5
+ "version": "0.3.0",
6
+ "license": "BSD-3-Clause",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/rfanth/tjson"
10
+ },
11
+ "files": [
12
+ "tjson_bg.wasm",
13
+ "tjson.js",
14
+ "tjson_bg.js",
15
+ "tjson.d.ts"
16
+ ],
17
+ "main": "tjson.js",
18
+ "homepage": "https://textjson.com",
19
+ "types": "tjson.d.ts",
20
+ "sideEffects": [
21
+ "./tjson.js",
22
+ "./snippets/*"
23
+ ],
24
+ "author": "R.F. Anthracite <rfa@rfanth.com>"
25
+ }
package/tjson.d.ts ADDED
@@ -0,0 +1,12 @@
1
+ /* tslint:disable */
2
+ /* eslint-disable */
3
+
4
+ /**
5
+ * Parse a TJSON string and return it as a JSON string.
6
+ */
7
+ export function parse(input: string): string;
8
+
9
+ /**
10
+ * Render a JSON string as TJSON, with optional options object.
11
+ */
12
+ export function stringify(input: string, options: any): string;
package/tjson.js ADDED
@@ -0,0 +1,9 @@
1
+ /* @ts-self-types="./tjson.d.ts" */
2
+
3
+ import * as wasm from "./tjson_bg.wasm";
4
+ import { __wbg_set_wasm } from "./tjson_bg.js";
5
+ __wbg_set_wasm(wasm);
6
+ wasm.__wbindgen_start();
7
+ export {
8
+ parse, stringify
9
+ } from "./tjson_bg.js";
package/tjson_bg.js ADDED
@@ -0,0 +1,377 @@
1
+ /**
2
+ * Parse a TJSON string and return it as a JSON string.
3
+ * @param {string} input
4
+ * @returns {string}
5
+ */
6
+ export function parse(input) {
7
+ let deferred3_0;
8
+ let deferred3_1;
9
+ try {
10
+ const ptr0 = passStringToWasm0(input, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
11
+ const len0 = WASM_VECTOR_LEN;
12
+ const ret = wasm.parse(ptr0, len0);
13
+ var ptr2 = ret[0];
14
+ var len2 = ret[1];
15
+ if (ret[3]) {
16
+ ptr2 = 0; len2 = 0;
17
+ throw takeFromExternrefTable0(ret[2]);
18
+ }
19
+ deferred3_0 = ptr2;
20
+ deferred3_1 = len2;
21
+ return getStringFromWasm0(ptr2, len2);
22
+ } finally {
23
+ wasm.__wbindgen_free(deferred3_0, deferred3_1, 1);
24
+ }
25
+ }
26
+
27
+ /**
28
+ * Render a JSON string as TJSON, with optional options object.
29
+ * @param {string} input
30
+ * @param {any} options
31
+ * @returns {string}
32
+ */
33
+ export function stringify(input, options) {
34
+ let deferred3_0;
35
+ let deferred3_1;
36
+ try {
37
+ const ptr0 = passStringToWasm0(input, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
38
+ const len0 = WASM_VECTOR_LEN;
39
+ const ret = wasm.stringify(ptr0, len0, options);
40
+ var ptr2 = ret[0];
41
+ var len2 = ret[1];
42
+ if (ret[3]) {
43
+ ptr2 = 0; len2 = 0;
44
+ throw takeFromExternrefTable0(ret[2]);
45
+ }
46
+ deferred3_0 = ptr2;
47
+ deferred3_1 = len2;
48
+ return getStringFromWasm0(ptr2, len2);
49
+ } finally {
50
+ wasm.__wbindgen_free(deferred3_0, deferred3_1, 1);
51
+ }
52
+ }
53
+ export function __wbg_Error_55538483de6e3abe(arg0, arg1) {
54
+ const ret = Error(getStringFromWasm0(arg0, arg1));
55
+ return ret;
56
+ }
57
+ export function __wbg_Number_f257194b7002d6f9(arg0) {
58
+ const ret = Number(arg0);
59
+ return ret;
60
+ }
61
+ export function __wbg_String_8564e559799eccda(arg0, arg1) {
62
+ const ret = String(arg1);
63
+ const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
64
+ const len1 = WASM_VECTOR_LEN;
65
+ getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
66
+ getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
67
+ }
68
+ export function __wbg___wbindgen_bigint_get_as_i64_a738e80c0fe6f6a7(arg0, arg1) {
69
+ const v = arg1;
70
+ const ret = typeof(v) === 'bigint' ? v : undefined;
71
+ getDataViewMemory0().setBigInt64(arg0 + 8 * 1, isLikeNone(ret) ? BigInt(0) : ret, true);
72
+ getDataViewMemory0().setInt32(arg0 + 4 * 0, !isLikeNone(ret), true);
73
+ }
74
+ export function __wbg___wbindgen_boolean_get_fe2a24fdfdb4064f(arg0) {
75
+ const v = arg0;
76
+ const ret = typeof(v) === 'boolean' ? v : undefined;
77
+ return isLikeNone(ret) ? 0xFFFFFF : ret ? 1 : 0;
78
+ }
79
+ export function __wbg___wbindgen_debug_string_d89627202d0155b7(arg0, arg1) {
80
+ const ret = debugString(arg1);
81
+ const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
82
+ const len1 = WASM_VECTOR_LEN;
83
+ getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
84
+ getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
85
+ }
86
+ export function __wbg___wbindgen_in_fe3eb6a509f75744(arg0, arg1) {
87
+ const ret = arg0 in arg1;
88
+ return ret;
89
+ }
90
+ export function __wbg___wbindgen_is_bigint_ca270ac12ef71091(arg0) {
91
+ const ret = typeof(arg0) === 'bigint';
92
+ return ret;
93
+ }
94
+ export function __wbg___wbindgen_is_null_8d90524c9e0af183(arg0) {
95
+ const ret = arg0 === null;
96
+ return ret;
97
+ }
98
+ export function __wbg___wbindgen_is_object_59a002e76b059312(arg0) {
99
+ const val = arg0;
100
+ const ret = typeof(val) === 'object' && val !== null;
101
+ return ret;
102
+ }
103
+ export function __wbg___wbindgen_is_string_624d5244bb2bc87c(arg0) {
104
+ const ret = typeof(arg0) === 'string';
105
+ return ret;
106
+ }
107
+ export function __wbg___wbindgen_is_undefined_87a3a837f331fef5(arg0) {
108
+ const ret = arg0 === undefined;
109
+ return ret;
110
+ }
111
+ export function __wbg___wbindgen_jsval_eq_eedd705f9f2a4f35(arg0, arg1) {
112
+ const ret = arg0 === arg1;
113
+ return ret;
114
+ }
115
+ export function __wbg___wbindgen_jsval_loose_eq_cf851f110c48f9ba(arg0, arg1) {
116
+ const ret = arg0 == arg1;
117
+ return ret;
118
+ }
119
+ export function __wbg___wbindgen_number_get_769f3676dc20c1d7(arg0, arg1) {
120
+ const obj = arg1;
121
+ const ret = typeof(obj) === 'number' ? obj : undefined;
122
+ getDataViewMemory0().setFloat64(arg0 + 8 * 1, isLikeNone(ret) ? 0 : ret, true);
123
+ getDataViewMemory0().setInt32(arg0 + 4 * 0, !isLikeNone(ret), true);
124
+ }
125
+ export function __wbg___wbindgen_string_get_f1161390414f9b59(arg0, arg1) {
126
+ const obj = arg1;
127
+ const ret = typeof(obj) === 'string' ? obj : undefined;
128
+ var ptr1 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
129
+ var len1 = WASM_VECTOR_LEN;
130
+ getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
131
+ getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
132
+ }
133
+ export function __wbg___wbindgen_throw_5549492daedad139(arg0, arg1) {
134
+ throw new Error(getStringFromWasm0(arg0, arg1));
135
+ }
136
+ export function __wbg_entries_28ed7cb892e12eff(arg0) {
137
+ const ret = Object.entries(arg0);
138
+ return ret;
139
+ }
140
+ export function __wbg_get_94f5fc088edd3138(arg0, arg1) {
141
+ const ret = arg0[arg1 >>> 0];
142
+ return ret;
143
+ }
144
+ export function __wbg_get_with_ref_key_6412cf3094599694(arg0, arg1) {
145
+ const ret = arg0[arg1];
146
+ return ret;
147
+ }
148
+ export function __wbg_instanceof_ArrayBuffer_8d855993947fc3a2(arg0) {
149
+ let result;
150
+ try {
151
+ result = arg0 instanceof ArrayBuffer;
152
+ } catch (_) {
153
+ result = false;
154
+ }
155
+ const ret = result;
156
+ return ret;
157
+ }
158
+ export function __wbg_instanceof_Uint8Array_ce24d58a5f4bdcc3(arg0) {
159
+ let result;
160
+ try {
161
+ result = arg0 instanceof Uint8Array;
162
+ } catch (_) {
163
+ result = false;
164
+ }
165
+ const ret = result;
166
+ return ret;
167
+ }
168
+ export function __wbg_isSafeInteger_1dfae065cbfe1915(arg0) {
169
+ const ret = Number.isSafeInteger(arg0);
170
+ return ret;
171
+ }
172
+ export function __wbg_length_e6e1633fbea6cfa9(arg0) {
173
+ const ret = arg0.length;
174
+ return ret;
175
+ }
176
+ export function __wbg_length_fae3e439140f48a4(arg0) {
177
+ const ret = arg0.length;
178
+ return ret;
179
+ }
180
+ export function __wbg_new_1d96678aaacca32e(arg0) {
181
+ const ret = new Uint8Array(arg0);
182
+ return ret;
183
+ }
184
+ export function __wbg_prototypesetcall_3875d54d12ef2eec(arg0, arg1, arg2) {
185
+ Uint8Array.prototype.set.call(getArrayU8FromWasm0(arg0, arg1), arg2);
186
+ }
187
+ export function __wbindgen_cast_0000000000000001(arg0, arg1) {
188
+ // Cast intrinsic for `Ref(String) -> Externref`.
189
+ const ret = getStringFromWasm0(arg0, arg1);
190
+ return ret;
191
+ }
192
+ export function __wbindgen_cast_0000000000000002(arg0) {
193
+ // Cast intrinsic for `U64 -> Externref`.
194
+ const ret = BigInt.asUintN(64, arg0);
195
+ return ret;
196
+ }
197
+ export function __wbindgen_init_externref_table() {
198
+ const table = wasm.__wbindgen_externrefs;
199
+ const offset = table.grow(4);
200
+ table.set(0, undefined);
201
+ table.set(offset + 0, undefined);
202
+ table.set(offset + 1, null);
203
+ table.set(offset + 2, true);
204
+ table.set(offset + 3, false);
205
+ }
206
+ function debugString(val) {
207
+ // primitive types
208
+ const type = typeof val;
209
+ if (type == 'number' || type == 'boolean' || val == null) {
210
+ return `${val}`;
211
+ }
212
+ if (type == 'string') {
213
+ return `"${val}"`;
214
+ }
215
+ if (type == 'symbol') {
216
+ const description = val.description;
217
+ if (description == null) {
218
+ return 'Symbol';
219
+ } else {
220
+ return `Symbol(${description})`;
221
+ }
222
+ }
223
+ if (type == 'function') {
224
+ const name = val.name;
225
+ if (typeof name == 'string' && name.length > 0) {
226
+ return `Function(${name})`;
227
+ } else {
228
+ return 'Function';
229
+ }
230
+ }
231
+ // objects
232
+ if (Array.isArray(val)) {
233
+ const length = val.length;
234
+ let debug = '[';
235
+ if (length > 0) {
236
+ debug += debugString(val[0]);
237
+ }
238
+ for(let i = 1; i < length; i++) {
239
+ debug += ', ' + debugString(val[i]);
240
+ }
241
+ debug += ']';
242
+ return debug;
243
+ }
244
+ // Test for built-in
245
+ const builtInMatches = /\[object ([^\]]+)\]/.exec(toString.call(val));
246
+ let className;
247
+ if (builtInMatches && builtInMatches.length > 1) {
248
+ className = builtInMatches[1];
249
+ } else {
250
+ // Failed to match the standard '[object ClassName]'
251
+ return toString.call(val);
252
+ }
253
+ if (className == 'Object') {
254
+ // we're a user defined class or Object
255
+ // JSON.stringify avoids problems with cycles, and is generally much
256
+ // easier than looping through ownProperties of `val`.
257
+ try {
258
+ return 'Object(' + JSON.stringify(val) + ')';
259
+ } catch (_) {
260
+ return 'Object';
261
+ }
262
+ }
263
+ // errors
264
+ if (val instanceof Error) {
265
+ return `${val.name}: ${val.message}\n${val.stack}`;
266
+ }
267
+ // TODO we could test for more things here, like `Set`s and `Map`s.
268
+ return className;
269
+ }
270
+
271
+ function getArrayU8FromWasm0(ptr, len) {
272
+ ptr = ptr >>> 0;
273
+ return getUint8ArrayMemory0().subarray(ptr / 1, ptr / 1 + len);
274
+ }
275
+
276
+ let cachedDataViewMemory0 = null;
277
+ function getDataViewMemory0() {
278
+ if (cachedDataViewMemory0 === null || cachedDataViewMemory0.buffer.detached === true || (cachedDataViewMemory0.buffer.detached === undefined && cachedDataViewMemory0.buffer !== wasm.memory.buffer)) {
279
+ cachedDataViewMemory0 = new DataView(wasm.memory.buffer);
280
+ }
281
+ return cachedDataViewMemory0;
282
+ }
283
+
284
+ function getStringFromWasm0(ptr, len) {
285
+ ptr = ptr >>> 0;
286
+ return decodeText(ptr, len);
287
+ }
288
+
289
+ let cachedUint8ArrayMemory0 = null;
290
+ function getUint8ArrayMemory0() {
291
+ if (cachedUint8ArrayMemory0 === null || cachedUint8ArrayMemory0.byteLength === 0) {
292
+ cachedUint8ArrayMemory0 = new Uint8Array(wasm.memory.buffer);
293
+ }
294
+ return cachedUint8ArrayMemory0;
295
+ }
296
+
297
+ function isLikeNone(x) {
298
+ return x === undefined || x === null;
299
+ }
300
+
301
+ function passStringToWasm0(arg, malloc, realloc) {
302
+ if (realloc === undefined) {
303
+ const buf = cachedTextEncoder.encode(arg);
304
+ const ptr = malloc(buf.length, 1) >>> 0;
305
+ getUint8ArrayMemory0().subarray(ptr, ptr + buf.length).set(buf);
306
+ WASM_VECTOR_LEN = buf.length;
307
+ return ptr;
308
+ }
309
+
310
+ let len = arg.length;
311
+ let ptr = malloc(len, 1) >>> 0;
312
+
313
+ const mem = getUint8ArrayMemory0();
314
+
315
+ let offset = 0;
316
+
317
+ for (; offset < len; offset++) {
318
+ const code = arg.charCodeAt(offset);
319
+ if (code > 0x7F) break;
320
+ mem[ptr + offset] = code;
321
+ }
322
+ if (offset !== len) {
323
+ if (offset !== 0) {
324
+ arg = arg.slice(offset);
325
+ }
326
+ ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0;
327
+ const view = getUint8ArrayMemory0().subarray(ptr + offset, ptr + len);
328
+ const ret = cachedTextEncoder.encodeInto(arg, view);
329
+
330
+ offset += ret.written;
331
+ ptr = realloc(ptr, len, offset, 1) >>> 0;
332
+ }
333
+
334
+ WASM_VECTOR_LEN = offset;
335
+ return ptr;
336
+ }
337
+
338
+ function takeFromExternrefTable0(idx) {
339
+ const value = wasm.__wbindgen_externrefs.get(idx);
340
+ wasm.__externref_table_dealloc(idx);
341
+ return value;
342
+ }
343
+
344
+ let cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });
345
+ cachedTextDecoder.decode();
346
+ const MAX_SAFARI_DECODE_BYTES = 2146435072;
347
+ let numBytesDecoded = 0;
348
+ function decodeText(ptr, len) {
349
+ numBytesDecoded += len;
350
+ if (numBytesDecoded >= MAX_SAFARI_DECODE_BYTES) {
351
+ cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });
352
+ cachedTextDecoder.decode();
353
+ numBytesDecoded = len;
354
+ }
355
+ return cachedTextDecoder.decode(getUint8ArrayMemory0().subarray(ptr, ptr + len));
356
+ }
357
+
358
+ const cachedTextEncoder = new TextEncoder();
359
+
360
+ if (!('encodeInto' in cachedTextEncoder)) {
361
+ cachedTextEncoder.encodeInto = function (arg, view) {
362
+ const buf = cachedTextEncoder.encode(arg);
363
+ view.set(buf);
364
+ return {
365
+ read: arg.length,
366
+ written: buf.length
367
+ };
368
+ };
369
+ }
370
+
371
+ let WASM_VECTOR_LEN = 0;
372
+
373
+
374
+ let wasm;
375
+ export function __wbg_set_wasm(val) {
376
+ wasm = val;
377
+ }
package/tjson_bg.wasm ADDED
Binary file