teptris 0.3.11 → 0.3.13

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/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # teptris (JavaScript/TypeScript)
2
2
 
3
+ [![ci](https://github.com/leptris/teptris-ts/actions/workflows/ci.yml/badge.svg)](https://github.com/leptris/teptris-ts/actions/workflows/ci.yml)
4
+
3
5
  **Mission: be the best TOML parser and builder ever made — in C, Ruby,
4
6
  Rust, and JS — measured, not claimed.** The bar and the family ledger:
5
7
  [BEST-EVER.md](https://github.com/leptris/teptris/blob/main/BEST-EVER.md).
package/dist/teptris.wasm CHANGED
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "teptris",
3
- "version": "0.3.11",
3
+ "version": "0.3.13",
4
4
  "description": "TOML for JavaScript/TypeScript at libteptris speed (WebAssembly, no fallback) - version tracks the engine ({engine}.{iteration}; npm semver is 3-part)",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
@@ -29,6 +29,7 @@
29
29
  "types": "src/index.d.ts",
30
30
  "devDependencies": {
31
31
  "@iarna/toml": "^2.2.5",
32
+ "@ltd/j-toml": "^1.38.0",
32
33
  "smol-toml": "^1.9.1"
33
34
  }
34
35
  }
package/src/index.js CHANGED
@@ -28,7 +28,9 @@ function parseDateTime(str) {
28
28
  return {
29
29
  kind, year: +m[1], month: +m[2], day: +m[3], hour: +m[4],
30
30
  minute: +m[5], second: +m[6],
31
- nanosecond: m[7] ? Math.floor(+("0." + m[7]) * 1e9) : 0,
31
+ // integer string padding, not FP: 0.507029 * 1e9 floors to
32
+ // 507028999 (off by one)
33
+ nanosecond: m[7] ? +((m[7] + "000000000").slice(0, 9)) : 0,
32
34
  offset_seconds: offset,
33
35
  };
34
36
  }
@@ -42,7 +44,7 @@ function parseDateTime(str) {
42
44
  if (m) {
43
45
  return { kind: KIND_TIME, year: 0, month: 0, day: 0, hour: +m[1],
44
46
  minute: +m[2], second: +m[3],
45
- nanosecond: m[4] ? Math.floor(+("0." + m[4]) * 1e9) : 0,
47
+ nanosecond: m[4] ? +((m[4] + "000000000").slice(0, 9)) : 0,
46
48
  offset_seconds: 0 };
47
49
  }
48
50
  return null;
@@ -53,16 +55,15 @@ const RFC3339 =
53
55
 
54
56
  // cheap charset pre-check before the RFC 3339 regex: datetimes start
55
57
  // with a digit and only ever contain digits, date/time punctuation
56
- // and TZ marks - rejects nearly all plain strings without the regex
57
- const DATETIME_CHARS = /[0-9Tt: .+Zz-]/;
58
+ // and TZ marks - rejects nearly all plain strings without the regex.
59
+ // One whole-string regex pass (the per-char loop allocated a
60
+ // single-char string per character).
61
+ const DATETIME_CHARS = /^[0-9Tt: .+Zz-]*$/;
58
62
  const utf8 = new TextDecoder("utf-8");
63
+ const utf8enc = new TextEncoder();
59
64
  function maybeRfc3339(v) {
60
65
  const c0 = v.charCodeAt(0);
61
- if (!(c0 >= 48 && c0 <= 57)) return false;
62
- for (let i = 1; i < v.length; i++) {
63
- if (!DATETIME_CHARS.test(v[i])) return false;
64
- }
65
- return true;
66
+ return c0 >= 48 && c0 <= 57 && DATETIME_CHARS.test(v);
66
67
  }
67
68
 
68
69
  function buildValue(mod, b, key, v, errs) {
@@ -177,7 +178,9 @@ export function initApi(mod) {
177
178
  }
178
179
 
179
180
  function readOut(ptr) {
180
- const out = UTF8ToString(ptr);
181
+ // explicit length: the emit buffer is not NUL-terminated for us,
182
+ // and a full strlen scan over the output is measurable
183
+ const out = UTF8ToString(ptr, mod._teptris_wasm_toml_len());
181
184
  mod._teptris_wasm_free(ptr);
182
185
  return out;
183
186
  }
@@ -189,7 +192,7 @@ export function initApi(mod) {
189
192
  if (obj === null || typeof obj !== "object" || Array.isArray(obj)) {
190
193
  throw new TypeError("dump expects a table object (TOML roots are tables)");
191
194
  }
192
- const enc = new TextEncoder();
195
+
193
196
  let buf = new Uint8Array(1 << 16);
194
197
  let n = 0;
195
198
  let dv = new DataView(buf.buffer);
@@ -226,9 +229,23 @@ export function initApi(mod) {
226
229
  const wkey = (k) => {
227
230
  ensure(2 + k.length * 3);
228
231
  buf[n++] = 1;
229
- const { written } = enc.encodeInto(k, buf.subarray(n + 1));
230
- buf[n] = written;
231
- n += 1 + written;
232
+ // ASCII fast path: keys are tiny, so TextEncoder.encodeInto's
233
+ // per-call view allocation costs more than the copy itself;
234
+ // non-ASCII falls back to encodeInto (overwrites from offset 1)
235
+ let ascii = true;
236
+ for (let i = 0; i < k.length; i++) {
237
+ const c = k.charCodeAt(i);
238
+ if (c > 127) { ascii = false; break; }
239
+ buf[n + 1 + i] = c;
240
+ }
241
+ if (ascii) {
242
+ buf[n] = k.length;
243
+ n += 1 + k.length;
244
+ } else {
245
+ const { written } = utf8enc.encodeInto(k, buf.subarray(n + 1));
246
+ buf[n] = written;
247
+ n += 1 + written;
248
+ }
232
249
  };
233
250
  const scalar = (k, v) => {
234
251
  if (k === null) { ensure(2); buf[n++] = 1; buf[n++] = 0; }
@@ -243,7 +260,9 @@ export function initApi(mod) {
243
260
  if (typeof v === "string") {
244
261
  if (maybeRfc3339(v) && RFC3339.test(v)) {
245
262
  const dt = parseDateTime(v);
246
- wkey(k);
263
+ // the key prefix is already written (top of scalar()); the
264
+ // datetime record is value-only - re-sending the key here
265
+ // crashed bare array elements (k === null)
247
266
  ensure(27);
248
267
  buf[n++] = 7;
249
268
  buf[n++] = dt.kind;
@@ -256,9 +275,20 @@ export function initApi(mod) {
256
275
  }
257
276
  ensure(5 + v.length * 3);
258
277
  buf[n++] = 2;
259
- const { written } = enc.encodeInto(v, buf.subarray(n + 4));
260
- dv.setUint32(n, written, true);
261
- n += 4 + written;
278
+ let ascii = true;
279
+ for (let i = 0; i < v.length; i++) {
280
+ const c = v.charCodeAt(i);
281
+ if (c > 127) { ascii = false; break; }
282
+ buf[n + 4 + i] = c;
283
+ }
284
+ if (ascii) {
285
+ dv.setUint32(n, v.length, true);
286
+ n += 4 + v.length;
287
+ } else {
288
+ const { written } = utf8enc.encodeInto(v, buf.subarray(n + 4));
289
+ dv.setUint32(n, written, true);
290
+ n += 4 + written;
291
+ }
262
292
  return;
263
293
  }
264
294
  throw new Error("null/undefined cannot round-trip through TOML");