@svta/cml-structured-field-values 1.1.5 → 1.1.7

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.js CHANGED
@@ -1,5 +1,4 @@
1
1
  import { decodeBase64, encodeBase64, roundToEven } from "@svta/cml-utils";
2
-
3
2
  //#region src/SfItem.ts
4
3
  /**
5
4
  * Structured Field Item
@@ -19,11 +18,9 @@ var SfItem = class SfItem {
19
18
  this.params = params;
20
19
  }
21
20
  };
22
-
23
21
  //#endregion
24
22
  //#region src/utils/DICT.ts
25
23
  const DICT = "Dict";
26
-
27
24
  //#endregion
28
25
  //#region src/parse/ParsedValue.ts
29
26
  /**
@@ -35,7 +32,6 @@ function parsedValue(value, src) {
35
32
  src
36
33
  };
37
34
  }
38
-
39
35
  //#endregion
40
36
  //#region src/utils/throwError.ts
41
37
  function format(value) {
@@ -48,7 +44,6 @@ function format(value) {
48
44
  function throwError(action, src, type, cause) {
49
45
  return new Error(`failed to ${action} "${format(src)}" as ${type}`, { cause });
50
46
  }
51
-
52
47
  //#endregion
53
48
  //#region src/parse/parseError.ts
54
49
  /**
@@ -57,19 +52,15 @@ function throwError(action, src, type, cause) {
57
52
  function parseError(src, type, cause) {
58
53
  return throwError("parse", src, type, cause);
59
54
  }
60
-
61
55
  //#endregion
62
56
  //#region src/utils/INNER.ts
63
57
  const INNER = "Inner List";
64
-
65
58
  //#endregion
66
59
  //#region src/utils/BARE_ITEM.ts
67
60
  const BARE_ITEM = "Bare Item";
68
-
69
61
  //#endregion
70
62
  //#region src/utils/BOOLEAN.ts
71
63
  const BOOLEAN = "Boolean";
72
-
73
64
  //#endregion
74
65
  //#region src/parse/parseBoolean.ts
75
66
  /**
@@ -83,11 +74,9 @@ function parseBoolean(src) {
83
74
  if (src[i] === "0") return parsedValue(false, src.substring(++i));
84
75
  throw parseError(src, BOOLEAN);
85
76
  }
86
-
87
77
  //#endregion
88
78
  //#region src/utils/BYTES.ts
89
79
  const BYTES = "Byte Sequence";
90
-
91
80
  //#endregion
92
81
  //#region src/parse/parseByteSequence.ts
93
82
  /**
@@ -102,31 +91,25 @@ function parseByteSequence(src) {
102
91
  src = src.substring(re.lastIndex);
103
92
  return parsedValue(decodeBase64(b64_content), src);
104
93
  }
105
-
106
94
  //#endregion
107
95
  //#region src/utils/DATE.ts
108
96
  const DATE = "Date";
109
-
110
97
  //#endregion
111
98
  //#region src/utils/DECIMAL.ts
112
99
  const DECIMAL = "Decimal";
113
-
114
100
  //#endregion
115
101
  //#region src/utils/INTEGER.ts
116
102
  const INTEGER = "Integer";
117
-
118
- //#endregion
119
- //#region src/utils/INTEGER_DECIMAL.ts
120
- const INTEGER_DECIMAL = `${INTEGER} or ${DECIMAL}`;
121
-
122
103
  //#endregion
123
104
  //#region src/utils/isInvalidInt.ts
124
105
  function isInvalidInt(value) {
125
106
  return value < -999999999999999 || 999999999999999 < value;
126
107
  }
127
-
128
108
  //#endregion
129
109
  //#region src/parse/parseIntegerOrDecimal.ts
110
+ function integerOrDecimalError(src) {
111
+ return parseError(src, `${INTEGER} or ${DECIMAL}`);
112
+ }
130
113
  /**
131
114
  * @internal
132
115
  */
@@ -135,35 +118,32 @@ function parseIntegerOrDecimal(src) {
135
118
  let sign = 1;
136
119
  let num = "";
137
120
  let value;
138
- const i = 0;
139
- const error = parseError(orig, INTEGER_DECIMAL);
140
- if (src[i] === "-") {
121
+ if (src[0] === "-") {
141
122
  sign = -1;
142
123
  src = src.substring(1);
143
124
  }
144
- if (src.length <= 0) throw error;
125
+ if (src.length <= 0) throw integerOrDecimalError(orig);
145
126
  const re_integer = /^(\d+)?/g;
146
127
  const result_integer = re_integer.exec(src);
147
- if (result_integer[0].length === 0) throw error;
128
+ if (result_integer[0].length === 0) throw integerOrDecimalError(orig);
148
129
  num += result_integer[1];
149
130
  src = src.substring(re_integer.lastIndex);
150
131
  if (src[0] === ".") {
151
- if (num.length > 12) throw error;
132
+ if (num.length > 12) throw integerOrDecimalError(orig);
152
133
  const re_decimal = /^(\.\d+)?/g;
153
134
  const result_decimal = re_decimal.exec(src);
154
135
  src = src.substring(re_decimal.lastIndex);
155
- if (result_decimal[0].length === 0 || result_decimal[1].length > 4) throw error;
136
+ if (result_decimal[0].length === 0 || result_decimal[1].length > 4) throw integerOrDecimalError(orig);
156
137
  num += result_decimal[1];
157
- if (num.length > 16) throw error;
138
+ if (num.length > 16) throw integerOrDecimalError(orig);
158
139
  value = parseFloat(num) * sign;
159
140
  } else {
160
- if (num.length > 15) throw error;
141
+ if (num.length > 15) throw integerOrDecimalError(orig);
161
142
  value = parseInt(num) * sign;
162
- if (isInvalidInt(value)) throw parseError(num, INTEGER_DECIMAL);
143
+ if (isInvalidInt(value)) throw integerOrDecimalError(num);
163
144
  }
164
145
  return parsedValue(value, src);
165
146
  }
166
-
167
147
  //#endregion
168
148
  //#region src/parse/parseDate.ts
169
149
  /**
@@ -177,15 +157,12 @@ function parseDate(src) {
177
157
  if (Number.isInteger(date.value) === false) throw parseError(src, DATE);
178
158
  return parsedValue(/* @__PURE__ */ new Date(date.value * 1e3), date.src);
179
159
  }
180
-
181
160
  //#endregion
182
161
  //#region src/utils/STRING.ts
183
162
  const STRING = "String";
184
-
185
163
  //#endregion
186
164
  //#region src/utils/STRING_REGEX.ts
187
165
  const STRING_REGEX = /[\x00-\x1f\x7f]+/;
188
-
189
166
  //#endregion
190
167
  //#region src/parse/parseString.ts
191
168
  /**
@@ -209,7 +186,6 @@ function parseString(src) {
209
186
  }
210
187
  throw parseError(src, STRING);
211
188
  }
212
-
213
189
  //#endregion
214
190
  //#region src/SfToken.ts
215
191
  /**
@@ -222,11 +198,9 @@ var SfToken = class {
222
198
  this.description = description;
223
199
  }
224
200
  };
225
-
226
201
  //#endregion
227
202
  //#region src/utils/TOKEN.ts
228
203
  const TOKEN = "Token";
229
-
230
204
  //#endregion
231
205
  //#region src/parse/parseToken.ts
232
206
  /**
@@ -239,7 +213,6 @@ function parseToken(src, options) {
239
213
  src = src.substring(re.lastIndex);
240
214
  return parsedValue(options?.useSymbol === false ? new SfToken(value) : Symbol.for(value), src);
241
215
  }
242
-
243
216
  //#endregion
244
217
  //#region src/parse/parseBareItem.ts
245
218
  /**
@@ -255,11 +228,6 @@ function parseBareItem(src, options) {
255
228
  if (first === `@`) return parseDate(src);
256
229
  throw parseError(src, BARE_ITEM);
257
230
  }
258
-
259
- //#endregion
260
- //#region src/utils/KEY.ts
261
- const KEY = "Key";
262
-
263
231
  //#endregion
264
232
  //#region src/parse/parseKey.ts
265
233
  /**
@@ -267,7 +235,7 @@ const KEY = "Key";
267
235
  */
268
236
  function parseKey(src) {
269
237
  let i = 0;
270
- if (/^[a-z*]$/.test(src[i]) === false) throw parseError(src, KEY);
238
+ if (/^[a-z*]$/.test(src[i]) === false) throw parseError(src, "Key");
271
239
  let value = "";
272
240
  while (src.length > i) {
273
241
  if (/^[a-z0-9_\-.*]$/.test(src[i]) === false) return parsedValue(value, src.substring(i));
@@ -276,7 +244,6 @@ function parseKey(src) {
276
244
  }
277
245
  return parsedValue(value, src.substring(i));
278
246
  }
279
-
280
247
  //#endregion
281
248
  //#region src/parse/parseParameters.ts
282
249
  /**
@@ -302,7 +269,6 @@ function parseParameters(src, options) {
302
269
  }
303
270
  return parsedValue(parameters, src);
304
271
  }
305
-
306
272
  //#endregion
307
273
  //#region src/parse/parseItem.ts
308
274
  /**
@@ -315,7 +281,6 @@ function parseItem(src, options) {
315
281
  src = parsedParameters.src;
316
282
  return parsedValue(new SfItem(parsedBareItem.value, parsedParameters.value), src);
317
283
  }
318
-
319
284
  //#endregion
320
285
  //#region src/parse/parseInnerList.ts
321
286
  /**
@@ -339,7 +304,6 @@ function parseInnerList(src, options) {
339
304
  }
340
305
  throw parseError(src, INNER);
341
306
  }
342
-
343
307
  //#endregion
344
308
  //#region src/parse/parseItemOrInnerList.ts
345
309
  /**
@@ -349,7 +313,6 @@ function parseItemOrInnerList(src, options) {
349
313
  if (src[0] === "(") return parseInnerList(src, options);
350
314
  return parseItem(src, options);
351
315
  }
352
-
353
316
  //#endregion
354
317
  //#region src/parse/parseDict.ts
355
318
  /**
@@ -380,7 +343,6 @@ function parseDict(src, options) {
380
343
  }
381
344
  return parsedValue(value, src);
382
345
  }
383
-
384
346
  //#endregion
385
347
  //#region src/decodeSfDict.ts
386
348
  /**
@@ -400,11 +362,9 @@ function decodeSfDict(input, options) {
400
362
  throw parseError(input, DICT, cause);
401
363
  }
402
364
  }
403
-
404
365
  //#endregion
405
366
  //#region src/utils/ITEM.ts
406
367
  const ITEM = "Item";
407
-
408
368
  //#endregion
409
369
  //#region src/decodeSfItem.ts
410
370
  /**
@@ -424,11 +384,9 @@ function decodeSfItem(input, options) {
424
384
  throw parseError(input, ITEM, cause);
425
385
  }
426
386
  }
427
-
428
387
  //#endregion
429
388
  //#region src/utils/LIST.ts
430
389
  const LIST = "List";
431
-
432
390
  //#endregion
433
391
  //#region src/parse/parseList.ts
434
392
  /**
@@ -447,7 +405,6 @@ function parseList(src, options) {
447
405
  }
448
406
  return parsedValue(value, src);
449
407
  }
450
-
451
408
  //#endregion
452
409
  //#region src/decodeSfList.ts
453
410
  /**
@@ -467,7 +424,6 @@ function decodeSfList(input, options) {
467
424
  throw parseError(input, LIST, cause);
468
425
  }
469
426
  }
470
-
471
427
  //#endregion
472
428
  //#region src/serialize/serializeError.ts
473
429
  /**
@@ -476,7 +432,6 @@ function decodeSfList(input, options) {
476
432
  function serializeError(src, type, cause) {
477
433
  return throwError("serialize", src, type, cause);
478
434
  }
479
-
480
435
  //#endregion
481
436
  //#region src/serialize/serializeBoolean.ts
482
437
  /**
@@ -486,7 +441,6 @@ function serializeBoolean(value) {
486
441
  if (typeof value !== "boolean") throw serializeError(value, BOOLEAN);
487
442
  return value ? "?1" : "?0";
488
443
  }
489
-
490
444
  //#endregion
491
445
  //#region src/serialize/serializeByteSequence.ts
492
446
  /**
@@ -496,7 +450,6 @@ function serializeByteSequence(value) {
496
450
  if (ArrayBuffer.isView(value) === false) throw serializeError(value, BYTES);
497
451
  return `:${encodeBase64(value)}:`;
498
452
  }
499
-
500
453
  //#endregion
501
454
  //#region src/serialize/serializeInteger.ts
502
455
  /**
@@ -506,7 +459,6 @@ function serializeInteger(value) {
506
459
  if (isInvalidInt(value)) throw serializeError(value, INTEGER);
507
460
  return value.toString();
508
461
  }
509
-
510
462
  //#endregion
511
463
  //#region src/serialize/serializeDate.ts
512
464
  /**
@@ -515,7 +467,6 @@ function serializeInteger(value) {
515
467
  function serializeDate(value) {
516
468
  return `@${serializeInteger(value.getTime() / 1e3)}`;
517
469
  }
518
-
519
470
  //#endregion
520
471
  //#region src/serialize/serializeDecimal.ts
521
472
  /**
@@ -523,21 +474,23 @@ function serializeDate(value) {
523
474
  */
524
475
  function serializeDecimal(value) {
525
476
  const roundedValue = roundToEven(value, 3);
526
- if (Math.floor(Math.abs(roundedValue)).toString().length > 12) throw serializeError(value, DECIMAL);
477
+ if (Math.abs(roundedValue) >= 0xe8d4a51000) throw serializeError(value, DECIMAL);
527
478
  const stringValue = roundedValue.toString();
528
479
  return stringValue.includes(".") ? stringValue : `${stringValue}.0`;
529
480
  }
530
-
531
481
  //#endregion
532
482
  //#region src/serialize/serializeString.ts
483
+ const ESCAPE_OR_CONTROL_REGEX = /[\x00-\x1f\x7f"\\]/;
484
+ const BACKSLASH_REGEX = /\\/g;
485
+ const DQUOTE_REGEX = /"/g;
533
486
  /**
534
487
  * @internal
535
488
  */
536
489
  function serializeString(value) {
490
+ if (ESCAPE_OR_CONTROL_REGEX.test(value) === false) return `"${value}"`;
537
491
  if (STRING_REGEX.test(value)) throw serializeError(value, STRING);
538
- return `"${value.replace(/\\/g, `\\\\`).replace(/"/g, `\\"`)}"`;
492
+ return `"${value.replace(BACKSLASH_REGEX, "\\\\").replace(DQUOTE_REGEX, "\\\"")}"`;
539
493
  }
540
-
541
494
  //#endregion
542
495
  //#region src/utils/symbolToStr.ts
543
496
  /**
@@ -552,18 +505,17 @@ function serializeString(value) {
552
505
  function symbolToStr(symbol) {
553
506
  return symbol.description || symbol.toString().slice(7, -1);
554
507
  }
555
-
556
508
  //#endregion
557
509
  //#region src/serialize/serializeToken.ts
510
+ const TOKEN_REGEX = /^[a-zA-Z*][!#$%&'*+\-.^_`|~\w:/]*$/;
558
511
  /**
559
512
  * @internal
560
513
  */
561
514
  function serializeToken(token) {
562
515
  const value = symbolToStr(token);
563
- if (/^([a-zA-Z*])([!#$%&'*+\-.^_`|~\w:/]*)$/.test(value) === false) throw serializeError(value, TOKEN);
516
+ if (TOKEN_REGEX.test(value) === false) throw serializeError(value, TOKEN);
564
517
  return value;
565
518
  }
566
-
567
519
  //#endregion
568
520
  //#region src/serialize/serializeBareItem.ts
569
521
  /**
@@ -585,17 +537,21 @@ function serializeBareItem(value) {
585
537
  default: throw serializeError(value, BARE_ITEM);
586
538
  }
587
539
  }
588
-
589
540
  //#endregion
590
541
  //#region src/serialize/serializeKey.ts
591
542
  /**
592
543
  * @internal
593
544
  */
594
545
  function serializeKey(value) {
595
- if (/^[a-z*][a-z0-9\-_.*]*$/.test(value) === false) throw serializeError(value, KEY);
546
+ if (typeof value !== "string" || value.length === 0) throw serializeError(value, "Key");
547
+ let code = value.charCodeAt(0);
548
+ if ((code < 97 || code > 122) && code !== 42) throw serializeError(value, "Key");
549
+ for (let i = 1; i < value.length; i++) {
550
+ code = value.charCodeAt(i);
551
+ if ((code < 97 || code > 122) && (code < 48 || code > 57) && code !== 95 && code !== 45 && code !== 46 && code !== 42) throw serializeError(value, "Key");
552
+ }
596
553
  return value;
597
554
  }
598
-
599
555
  //#endregion
600
556
  //#region src/serialize/serializeParams.ts
601
557
  /**
@@ -603,12 +559,14 @@ function serializeKey(value) {
603
559
  */
604
560
  function serializeParams(params) {
605
561
  if (params == null) return "";
606
- return Object.entries(params).map(([key, value]) => {
607
- if (value === true) return `;${serializeKey(key)}`;
608
- return `;${serializeKey(key)}=${serializeBareItem(value)}`;
609
- }).join("");
562
+ let output = "";
563
+ for (const key of Object.keys(params)) {
564
+ const value = params[key];
565
+ output += `;${serializeKey(key)}`;
566
+ if (value !== true) output += `=${serializeBareItem(value)}`;
567
+ }
568
+ return output;
610
569
  }
611
-
612
570
  //#endregion
613
571
  //#region src/serialize/serializeItem.ts
614
572
  /**
@@ -618,16 +576,41 @@ function serializeItem(value) {
618
576
  if (value instanceof SfItem) return `${serializeBareItem(value.value)}${serializeParams(value.params)}`;
619
577
  else return serializeBareItem(value);
620
578
  }
621
-
622
579
  //#endregion
623
580
  //#region src/serialize/serializeInnerList.ts
581
+ function serializeInnerList(value, params) {
582
+ let list;
583
+ if (Array.isArray(value)) list = value;
584
+ else {
585
+ list = value.value;
586
+ params = value.params;
587
+ }
588
+ let output = "(";
589
+ for (let i = 0; i < list.length; i++) {
590
+ if (i > 0) output += " ";
591
+ output += serializeItem(list[i]);
592
+ }
593
+ return `${output})${serializeParams(params)}`;
594
+ }
595
+ //#endregion
596
+ //#region src/serialize/serializeDictMember.ts
624
597
  /**
598
+ * Serialize one dictionary member: the key, then the parameters alone for a `true` value, otherwise `=` and the member.
599
+ *
625
600
  * @internal
626
601
  */
627
- function serializeInnerList(value) {
628
- return `(${value.value.map(serializeItem).join(" ")})${serializeParams(value.params)}`;
602
+ function serializeDictMember(key, member) {
603
+ const output = serializeKey(key);
604
+ if (member instanceof SfItem) {
605
+ const { value, params } = member;
606
+ if (value === true) return `${output}${serializeParams(params)}`;
607
+ if (Array.isArray(value)) return `${output}=${serializeInnerList(value, params)}`;
608
+ return `${output}=${serializeBareItem(value)}${serializeParams(params)}`;
609
+ }
610
+ if (member === true) return output;
611
+ if (Array.isArray(member)) return `${output}=${serializeInnerList(member)}`;
612
+ return `${output}=${serializeBareItem(member)}`;
629
613
  }
630
-
631
614
  //#endregion
632
615
  //#region src/serialize/serializeDict.ts
633
616
  /**
@@ -635,25 +618,15 @@ function serializeInnerList(value) {
635
618
  */
636
619
  function serializeDict(dict, options) {
637
620
  if (typeof dict !== "object" || dict == null) throw serializeError(dict, DICT);
638
- const entries = dict instanceof Map ? dict.entries() : Object.entries(dict);
639
- const optionalWhiteSpace = options?.whitespace === false ? "" : " ";
640
- return Array.from(entries).map(([key, item]) => {
641
- if (item instanceof SfItem === false) item = new SfItem(item);
642
- let output = serializeKey(key);
643
- if (item.value === true) output += serializeParams(item.params);
644
- else {
645
- output += "=";
646
- if (Array.isArray(item.value)) output += serializeInnerList(item);
647
- else output += serializeItem(item);
648
- }
649
- return output;
650
- }).join(`,${optionalWhiteSpace}`);
621
+ const parts = [];
622
+ if (dict instanceof Map) dict.forEach((member, key) => parts.push(serializeDictMember(key, member)));
623
+ else for (const key of Object.keys(dict)) parts.push(serializeDictMember(key, dict[key]));
624
+ return parts.join(options?.whitespace === false ? "," : ", ");
651
625
  }
652
-
653
626
  //#endregion
654
627
  //#region src/encodeSfDict.ts
655
628
  /**
656
- * Encode an object into a structured field dictionary
629
+ * Encode a structured field dictionary to a string
657
630
  *
658
631
  * @param value - The structured field dictionary to encode
659
632
  * @param options - Encoding options
@@ -665,14 +638,28 @@ function serializeDict(dict, options) {
665
638
  function encodeSfDict(value, options) {
666
639
  return serializeDict(value, options);
667
640
  }
668
-
669
641
  //#endregion
670
642
  //#region src/encodeSfItem.ts
671
643
  function encodeSfItem(value, params) {
672
- if (!(value instanceof SfItem)) value = new SfItem(value, params);
673
- return serializeItem(value);
644
+ if (value instanceof SfItem) return serializeItem(value);
645
+ return `${serializeBareItem(value)}${serializeParams(params)}`;
646
+ }
647
+ //#endregion
648
+ //#region src/serialize/serializeMember.ts
649
+ /**
650
+ * Serialize a list member: an inner list when the value is an array, an item otherwise.
651
+ *
652
+ * @internal
653
+ */
654
+ function serializeMember(member) {
655
+ if (member instanceof SfItem) {
656
+ const { value, params } = member;
657
+ if (Array.isArray(value)) return serializeInnerList(value, params);
658
+ return `${serializeBareItem(value)}${serializeParams(params)}`;
659
+ }
660
+ if (Array.isArray(member)) return serializeInnerList(member);
661
+ return serializeBareItem(member);
674
662
  }
675
-
676
663
  //#endregion
677
664
  //#region src/serialize/serializeList.ts
678
665
  /**
@@ -680,19 +667,18 @@ function encodeSfItem(value, params) {
680
667
  */
681
668
  function serializeList(list, options) {
682
669
  if (Array.isArray(list) === false) throw serializeError(list, LIST);
683
- const optionalWhiteSpace = options?.whitespace === false ? "" : " ";
684
- return list.map((item) => {
685
- if (item instanceof SfItem === false) item = new SfItem(item);
686
- const i = item;
687
- if (Array.isArray(i.value)) return serializeInnerList(i);
688
- return serializeItem(i);
689
- }).join(`,${optionalWhiteSpace}`);
670
+ const separator = options?.whitespace === false ? "," : ", ";
671
+ let output = "";
672
+ for (let i = 0; i < list.length; i++) {
673
+ if (i > 0) output += separator;
674
+ output += serializeMember(list[i]);
675
+ }
676
+ return output;
690
677
  }
691
-
692
678
  //#endregion
693
679
  //#region src/encodeSfList.ts
694
680
  /**
695
- * Encode a list into a structured field dictionary
681
+ * Encode a structured field list to a string
696
682
  *
697
683
  * @param value - The structured field list to encode
698
684
  * @param options - Encoding options
@@ -704,7 +690,7 @@ function serializeList(list, options) {
704
690
  function encodeSfList(value, options) {
705
691
  return serializeList(value, options);
706
692
  }
707
-
708
693
  //#endregion
709
694
  export { SfItem, SfToken, decodeSfDict, decodeSfItem, decodeSfList, encodeSfDict, encodeSfItem, encodeSfList, parseBareItem, parseBoolean, parseByteSequence, parseDate, parseDict, parseError, parseInnerList, parseIntegerOrDecimal, parseItem, parseItemOrInnerList, parseKey, parseList, parseParameters, parseString, parseToken, serializeBareItem, serializeBoolean, serializeByteSequence, serializeDate, serializeDecimal, serializeDict, serializeError, serializeInnerList, serializeInteger, serializeItem, serializeKey, serializeList, serializeParams, serializeString, serializeToken, symbolToStr };
695
+
710
696
  //# sourceMappingURL=index.js.map