encode-shared.js 3.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.parseEncodeTrie = parseEncodeTrie;
  4. /**
  5. * Parse a compact encode trie string into a Map structure used for encoding.
  6. *
  7. * Format per entry (ascending code points using delta encoding):
  8. * <diffBase36>[&name;][{<children>}] -- diff omitted when 0
  9. * Where diff = currentKey - previousKey - 1 (first entry stores absolute key).
  10. * `&name;` is the entity value (already wrapped); a following `{` denotes children.
  11. */
  12. function parseEncodeTrie(serialized) {
  13. const top = new Map();
  14. const totalLength = serialized.length;
  15. let cursor = 0;
  16. let lastTopKey = -1;
  17. function readDiff() {
  18. const start = cursor;
  19. while (cursor < totalLength) {
  20. const char = serialized.charAt(cursor);
  21. if ((char < "0" || char > "9") && (char < "a" || char > "z")) {
  22. break;
  23. }
  24. cursor++;
  25. }
  26. if (cursor === start)
  27. return 0;
  28. return Number.parseInt(serialized.slice(start, cursor), 36);
  29. }
  30. function readEntity() {
  31. if (serialized[cursor] !== "&") {
  32. throw new Error(`Child entry missing value near index ${cursor}`);
  33. }
  34. // Cursor currently points at '&'
  35. const start = cursor;
  36. const end = serialized.indexOf(";", cursor + 1);
  37. if (end === -1) {
  38. throw new Error(`Unterminated entity starting at index ${start}`);
  39. }
  40. cursor = end + 1; // Move past ';'
  41. return serialized.slice(start, cursor); // Includes & ... ;
  42. }
  43. while (cursor < totalLength) {
  44. const keyDiff = readDiff();
  45. const key = lastTopKey === -1 ? keyDiff : lastTopKey + keyDiff + 1;
  46. let value;
  47. if (serialized[cursor] === "&")
  48. value = readEntity();
  49. if (serialized[cursor] === "{") {
  50. cursor++; // Skip '{'
  51. // Parse first child
  52. let diff = readDiff();
  53. let childKey = diff; // First key (lastChildKey = -1)
  54. const firstValue = readEntity();
  55. if (serialized[cursor] === "{") {
  56. throw new Error("Unexpected nested '{' beyond depth 2");
  57. }
  58. // If end of block -> single child optimization
  59. if (serialized[cursor] === "}") {
  60. top.set(key, { value, next: childKey, nextValue: firstValue });
  61. cursor++; // Skip '}'
  62. }
  63. else {
  64. const childMap = new Map();
  65. childMap.set(childKey, firstValue);
  66. let lastChildKey = childKey;
  67. while (cursor < totalLength && serialized[cursor] !== "}") {
  68. diff = readDiff();
  69. childKey = lastChildKey + diff + 1;
  70. const childValue = readEntity();
  71. if (serialized[cursor] === "{") {
  72. throw new Error("Unexpected nested '{' beyond depth 2");
  73. }
  74. childMap.set(childKey, childValue);
  75. lastChildKey = childKey;
  76. }
  77. if (serialized[cursor] !== "}") {
  78. throw new Error("Unterminated child block");
  79. }
  80. cursor++; // Skip '}'
  81. top.set(key, { value, next: childMap });
  82. }
  83. }
  84. else if (value === undefined) {
  85. throw new Error(`Malformed encode trie: missing value at index ${cursor}`);
  86. }
  87. else {
  88. top.set(key, value);
  89. }
  90. lastTopKey = key;
  91. }
  92. return top;
  93. }
  94. //# sourceMappingURL=encode-shared.js.map