hbsig 0.0.1
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/cjs/bin_to_str.js +44 -0
- package/cjs/collect-body-keys.js +470 -0
- package/cjs/encode-array-item.js +110 -0
- package/cjs/encode-utils.js +236 -0
- package/cjs/encode.js +1318 -0
- package/cjs/erl_json.js +317 -0
- package/cjs/erl_str.js +1037 -0
- package/cjs/flat.js +222 -0
- package/cjs/http-message-signatures/httpbis.js +489 -0
- package/cjs/http-message-signatures/index.js +25 -0
- package/cjs/http-message-signatures/structured-header.js +129 -0
- package/cjs/httpsig.js +716 -0
- package/cjs/httpsig2.js +1160 -0
- package/cjs/id.js +470 -0
- package/cjs/index.js +63 -0
- package/cjs/send.js +194 -0
- package/cjs/signer-utils.js +617 -0
- package/cjs/signer.js +606 -0
- package/cjs/structured.js +296 -0
- package/cjs/test.js +27 -0
- package/cjs/utils.js +42 -0
- package/esm/bin_to_str.js +46 -0
- package/esm/collect-body-keys.js +436 -0
- package/esm/encode-array-item.js +112 -0
- package/esm/encode-utils.js +185 -0
- package/esm/encode.js +1219 -0
- package/esm/erl_json.js +289 -0
- package/esm/erl_str.js +1139 -0
- package/esm/flat.js +196 -0
- package/esm/http-message-signatures/httpbis.js +438 -0
- package/esm/http-message-signatures/index.js +4 -0
- package/esm/http-message-signatures/structured-header.js +105 -0
- package/esm/httpsig.js +658 -0
- package/esm/httpsig2.js +1097 -0
- package/esm/id.js +459 -0
- package/esm/index.js +4 -0
- package/esm/package.json +3 -0
- package/esm/send.js +124 -0
- package/esm/signer-utils.js +494 -0
- package/esm/signer.js +452 -0
- package/esm/structured.js +269 -0
- package/esm/test.js +6 -0
- package/esm/utils.js +28 -0
- package/package.json +28 -0
package/cjs/erl_str.js
ADDED
|
@@ -0,0 +1,1037 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.erl_str_from = erl_str_from;
|
|
7
|
+
exports.erl_str_to = erl_str_to;
|
|
8
|
+
exports.parse_body = parse_body;
|
|
9
|
+
function _slicedToArray(r, e) { return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest(); }
|
|
10
|
+
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
|
|
11
|
+
function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t["return"] && (u = t["return"](), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
|
|
12
|
+
function _arrayWithHoles(r) { if (Array.isArray(r)) return r; }
|
|
13
|
+
function _classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); }
|
|
14
|
+
function _defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, _toPropertyKey(o.key), o); } }
|
|
15
|
+
function _createClass(e, r, t) { return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; }
|
|
16
|
+
function _toConsumableArray(r) { return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread(); }
|
|
17
|
+
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
|
|
18
|
+
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
|
|
19
|
+
function _iterableToArray(r) { if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r); }
|
|
20
|
+
function _arrayWithoutHoles(r) { if (Array.isArray(r)) return _arrayLikeToArray(r); }
|
|
21
|
+
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
|
|
22
|
+
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
23
|
+
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
24
|
+
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
|
|
25
|
+
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; }
|
|
26
|
+
function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
|
|
27
|
+
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
|
|
28
|
+
/**
|
|
29
|
+
* Erlang term string parser and formatter
|
|
30
|
+
* Converts between Erlang term strings and JavaScript values
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Parse an Erlang term string into JavaScript values
|
|
35
|
+
* @param {string} str - Erlang term string
|
|
36
|
+
* @param {boolean} binaryMode - If true, keep binaries as Buffers; if false, convert to strings
|
|
37
|
+
* @returns {*} JavaScript value
|
|
38
|
+
*/
|
|
39
|
+
function erl_str_from(str) {
|
|
40
|
+
var binaryMode = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
|
|
41
|
+
// Handle the new response format
|
|
42
|
+
if (str.startsWith("#erl_response{")) {
|
|
43
|
+
var rawMatch = str.match(/#erl_response\{raw=([^]*?),formatted=([^]*?)\}$/);
|
|
44
|
+
if (rawMatch && rawMatch[1] && rawMatch[2]) {
|
|
45
|
+
var rawStr = rawMatch[1];
|
|
46
|
+
var formattedStr = rawMatch[2];
|
|
47
|
+
if (binaryMode) {
|
|
48
|
+
// In binary mode, just parse formatted
|
|
49
|
+
var _parser = new ErlangParser(formattedStr, true);
|
|
50
|
+
return _parser.parse();
|
|
51
|
+
} else {
|
|
52
|
+
// Build a type map from raw, then parse formatted with type info
|
|
53
|
+
var typeMap = buildTypeMap(rawStr);
|
|
54
|
+
var _parser2 = new TypeAwareParser(formattedStr, typeMap);
|
|
55
|
+
return _parser2.parse();
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Fallback for non-response format
|
|
61
|
+
var parser = new ErlangParser(str, binaryMode);
|
|
62
|
+
return parser.parse();
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Parse body field specially - convert to string only for multipart bodies
|
|
67
|
+
* @param {*} parsed - Parsed Erlang term object
|
|
68
|
+
* @returns {*} Object with body field potentially converted to string
|
|
69
|
+
*/
|
|
70
|
+
function parse_body(parsed) {
|
|
71
|
+
if (!parsed || _typeof(parsed) !== "object") {
|
|
72
|
+
return parsed;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// If there's a body field
|
|
76
|
+
if ("body" in parsed) {
|
|
77
|
+
if (Buffer.isBuffer(parsed.body)) {
|
|
78
|
+
// Check if this looks like a multipart body
|
|
79
|
+
// Multipart bodies start with "--" boundary
|
|
80
|
+
var bodyStart = parsed.body.toString("binary", 0, Math.min(100, parsed.body.length));
|
|
81
|
+
if (bodyStart.startsWith("--") && parsed["content-type"] && parsed["content-type"].includes("multipart")) {
|
|
82
|
+
// It's a multipart body, convert to string
|
|
83
|
+
return _objectSpread(_objectSpread({}, parsed), {}, {
|
|
84
|
+
body: parsed.body.toString("binary")
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
// Not multipart, keep as Buffer
|
|
88
|
+
return parsed;
|
|
89
|
+
}
|
|
90
|
+
// Already a string, return as-is
|
|
91
|
+
return parsed;
|
|
92
|
+
}
|
|
93
|
+
return parsed;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Build a map of paths to types by analyzing the raw string
|
|
97
|
+
function buildTypeMap(rawStr) {
|
|
98
|
+
var typeMap = new Map();
|
|
99
|
+
function detectBinaryType(str, startPos) {
|
|
100
|
+
// Check what follows <<
|
|
101
|
+
var pos = startPos + 2;
|
|
102
|
+
while (pos < str.length && /\s/.test(str[pos])) pos++;
|
|
103
|
+
if (pos < str.length && str[pos] === '"') {
|
|
104
|
+
// It looks like a string, but check if it has escape sequences
|
|
105
|
+
// If it has \NNN octal escapes, it's actually a binary that Erlang formatted as string
|
|
106
|
+
var scanPos = pos + 1;
|
|
107
|
+
var hasOctalEscapes = false;
|
|
108
|
+
while (scanPos < str.length && !(str[scanPos] === '"' && str[scanPos + 1] === ">" && str[scanPos + 2] === ">")) {
|
|
109
|
+
if (str[scanPos] === "\\" && scanPos + 1 < str.length) {
|
|
110
|
+
var nextChar = str[scanPos + 1];
|
|
111
|
+
// Check for octal escape \NNN
|
|
112
|
+
if (/[0-7]/.test(nextChar)) {
|
|
113
|
+
hasOctalEscapes = true;
|
|
114
|
+
break;
|
|
115
|
+
}
|
|
116
|
+
scanPos += 2;
|
|
117
|
+
} else {
|
|
118
|
+
scanPos++;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// If it has octal escapes, treat as binary
|
|
123
|
+
if (hasOctalEscapes) {
|
|
124
|
+
return "binary";
|
|
125
|
+
}
|
|
126
|
+
return "string";
|
|
127
|
+
}
|
|
128
|
+
return "binary";
|
|
129
|
+
}
|
|
130
|
+
function scanValue(str, pos, path) {
|
|
131
|
+
while (pos < str.length && /\s/.test(str[pos])) pos++;
|
|
132
|
+
if (pos >= str.length) return pos;
|
|
133
|
+
if (str[pos] === "#" && str[pos + 1] === "{") {
|
|
134
|
+
// Map
|
|
135
|
+
pos += 2;
|
|
136
|
+
var mapIndex = 0;
|
|
137
|
+
while (pos < str.length) {
|
|
138
|
+
while (pos < str.length && /\s/.test(str[pos])) pos++;
|
|
139
|
+
if (str[pos] === "}") return pos + 1;
|
|
140
|
+
|
|
141
|
+
// Parse key
|
|
142
|
+
var keyStart = pos;
|
|
143
|
+
if (str[pos] === "<" && str[pos + 1] === "<") {
|
|
144
|
+
// Binary key
|
|
145
|
+
var keyType = detectBinaryType(str, pos);
|
|
146
|
+
var keyEnd = pos + 2;
|
|
147
|
+
if (keyType === "string") {
|
|
148
|
+
keyEnd++; // skip "
|
|
149
|
+
while (keyEnd < str.length && !(str[keyEnd] === '"' && str[keyEnd + 1] === ">" && str[keyEnd + 2] === ">")) {
|
|
150
|
+
if (str[keyEnd] === "\\") keyEnd++;
|
|
151
|
+
keyEnd++;
|
|
152
|
+
}
|
|
153
|
+
keyEnd += 3;
|
|
154
|
+
} else {
|
|
155
|
+
var depth = 1;
|
|
156
|
+
while (depth > 0 && keyEnd < str.length) {
|
|
157
|
+
if (str[keyEnd] === "<" && str[keyEnd + 1] === "<") {
|
|
158
|
+
depth++;
|
|
159
|
+
keyEnd += 2;
|
|
160
|
+
} else if (str[keyEnd] === ">" && str[keyEnd + 1] === ">") {
|
|
161
|
+
depth--;
|
|
162
|
+
keyEnd += 2;
|
|
163
|
+
} else {
|
|
164
|
+
keyEnd++;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
pos = keyEnd;
|
|
169
|
+
} else {
|
|
170
|
+
// Regular key
|
|
171
|
+
while (pos < str.length && !/[\s=,}]/.test(str[pos])) pos++;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Skip =>
|
|
175
|
+
while (pos < str.length && /\s/.test(str[pos])) pos++;
|
|
176
|
+
if (str[pos] === "=" && str[pos + 1] === ">") pos += 2;
|
|
177
|
+
while (pos < str.length && /\s/.test(str[pos])) pos++;
|
|
178
|
+
|
|
179
|
+
// Parse value and record type if binary
|
|
180
|
+
if (str[pos] === "<" && str[pos + 1] === "<") {
|
|
181
|
+
var type = detectBinaryType(str, pos);
|
|
182
|
+
var pathKey = [].concat(_toConsumableArray(path), [mapIndex]).join(".");
|
|
183
|
+
typeMap.set(pathKey, type);
|
|
184
|
+
}
|
|
185
|
+
pos = scanValue(str, pos, [].concat(_toConsumableArray(path), [mapIndex]));
|
|
186
|
+
mapIndex++;
|
|
187
|
+
|
|
188
|
+
// Skip comma
|
|
189
|
+
while (pos < str.length && /\s/.test(str[pos])) pos++;
|
|
190
|
+
if (str[pos] === ",") pos++;
|
|
191
|
+
}
|
|
192
|
+
} else if (str[pos] === "<" && str[pos + 1] === "<") {
|
|
193
|
+
// Binary
|
|
194
|
+
var _type = detectBinaryType(str, pos);
|
|
195
|
+
var _pathKey = path.join(".");
|
|
196
|
+
typeMap.set(_pathKey, _type);
|
|
197
|
+
pos += 2;
|
|
198
|
+
if (_type === "string" || str[pos] === '"') {
|
|
199
|
+
// Skip past string literal
|
|
200
|
+
if (str[pos] === '"') pos++; // skip opening quote
|
|
201
|
+
while (pos < str.length && !(str[pos] === '"' && str[pos + 1] === ">" && str[pos + 2] === ">")) {
|
|
202
|
+
if (str[pos] === "\\") pos++;
|
|
203
|
+
pos++;
|
|
204
|
+
}
|
|
205
|
+
return pos + 3;
|
|
206
|
+
} else {
|
|
207
|
+
var _depth = 1;
|
|
208
|
+
while (_depth > 0 && pos < str.length) {
|
|
209
|
+
if (str[pos] === "<" && str[pos + 1] === "<") {
|
|
210
|
+
_depth++;
|
|
211
|
+
pos += 2;
|
|
212
|
+
} else if (str[pos] === ">" && str[pos + 1] === ">") {
|
|
213
|
+
_depth--;
|
|
214
|
+
pos += 2;
|
|
215
|
+
} else {
|
|
216
|
+
pos++;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
return pos;
|
|
220
|
+
}
|
|
221
|
+
} else if (str[pos] === "[") {
|
|
222
|
+
// List
|
|
223
|
+
pos++;
|
|
224
|
+
var listIndex = 0;
|
|
225
|
+
while (pos < str.length) {
|
|
226
|
+
while (pos < str.length && /\s/.test(str[pos])) pos++;
|
|
227
|
+
if (str[pos] === "]") return pos + 1;
|
|
228
|
+
pos = scanValue(str, pos, [].concat(_toConsumableArray(path), [listIndex]));
|
|
229
|
+
listIndex++;
|
|
230
|
+
while (pos < str.length && /\s/.test(str[pos])) pos++;
|
|
231
|
+
if (str[pos] === ",") pos++;
|
|
232
|
+
}
|
|
233
|
+
} else {
|
|
234
|
+
// Skip other values
|
|
235
|
+
while (pos < str.length && !/[\s,\]}=>]/.test(str[pos])) {
|
|
236
|
+
pos++;
|
|
237
|
+
}
|
|
238
|
+
return pos;
|
|
239
|
+
}
|
|
240
|
+
return pos;
|
|
241
|
+
}
|
|
242
|
+
scanValue(rawStr, 0, []);
|
|
243
|
+
return typeMap;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// Parser that uses type information
|
|
247
|
+
var TypeAwareParser = /*#__PURE__*/function () {
|
|
248
|
+
function TypeAwareParser(str, typeMap) {
|
|
249
|
+
_classCallCheck(this, TypeAwareParser);
|
|
250
|
+
this.str = str;
|
|
251
|
+
this.typeMap = typeMap;
|
|
252
|
+
this.pos = 0;
|
|
253
|
+
this.path = [];
|
|
254
|
+
}
|
|
255
|
+
return _createClass(TypeAwareParser, [{
|
|
256
|
+
key: "parse",
|
|
257
|
+
value: function parse() {
|
|
258
|
+
var result = this.parseValue();
|
|
259
|
+
this.skipWhitespace();
|
|
260
|
+
if (this.pos < this.str.length) {
|
|
261
|
+
throw new Error("Unexpected content at position ".concat(this.pos));
|
|
262
|
+
}
|
|
263
|
+
return result;
|
|
264
|
+
}
|
|
265
|
+
}, {
|
|
266
|
+
key: "peek",
|
|
267
|
+
value: function peek() {
|
|
268
|
+
var offset = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
|
|
269
|
+
return this.str[this.pos + offset] || "";
|
|
270
|
+
}
|
|
271
|
+
}, {
|
|
272
|
+
key: "advance",
|
|
273
|
+
value: function advance() {
|
|
274
|
+
var count = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;
|
|
275
|
+
this.pos += count;
|
|
276
|
+
}
|
|
277
|
+
}, {
|
|
278
|
+
key: "skipWhitespace",
|
|
279
|
+
value: function skipWhitespace() {
|
|
280
|
+
while (this.pos < this.str.length && /\s/.test(this.peek())) {
|
|
281
|
+
this.advance();
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
}, {
|
|
285
|
+
key: "parseValue",
|
|
286
|
+
value: function parseValue() {
|
|
287
|
+
this.skipWhitespace();
|
|
288
|
+
var ch = this.peek();
|
|
289
|
+
var ch2 = this.peek(1);
|
|
290
|
+
if (ch === "#" && ch2 === "{") {
|
|
291
|
+
return this.parseMap();
|
|
292
|
+
}
|
|
293
|
+
if (ch === "<" && ch2 === "<") {
|
|
294
|
+
return this.parseBinary();
|
|
295
|
+
}
|
|
296
|
+
if (ch === "[") {
|
|
297
|
+
return this.parseList();
|
|
298
|
+
}
|
|
299
|
+
if (ch === "'") {
|
|
300
|
+
return this.parseQuotedAtom();
|
|
301
|
+
}
|
|
302
|
+
if (ch === '"') {
|
|
303
|
+
return this.parseQuotedString();
|
|
304
|
+
}
|
|
305
|
+
return this.parseAtomOrNumber();
|
|
306
|
+
}
|
|
307
|
+
}, {
|
|
308
|
+
key: "parseMap",
|
|
309
|
+
value: function parseMap() {
|
|
310
|
+
this.advance(2); // skip #{
|
|
311
|
+
var map = {};
|
|
312
|
+
var mapIndex = 0;
|
|
313
|
+
while (true) {
|
|
314
|
+
this.skipWhitespace();
|
|
315
|
+
if (this.peek() === "}") {
|
|
316
|
+
this.advance();
|
|
317
|
+
break;
|
|
318
|
+
}
|
|
319
|
+
this.path.push(mapIndex);
|
|
320
|
+
var key = this.parseValue();
|
|
321
|
+
this.path.pop();
|
|
322
|
+
this.skipWhitespace();
|
|
323
|
+
if (this.peek() !== "=" || this.peek(1) !== ">") {
|
|
324
|
+
throw new Error("Expected =>");
|
|
325
|
+
}
|
|
326
|
+
this.advance(2);
|
|
327
|
+
this.skipWhitespace();
|
|
328
|
+
this.path.push(mapIndex);
|
|
329
|
+
var value = this.parseValue();
|
|
330
|
+
this.path.pop();
|
|
331
|
+
var jsKey = key instanceof Buffer ? key.toString("utf8") : _typeof(key) === "symbol" ? Symbol.keyFor(key) || String(key) : String(key);
|
|
332
|
+
map[jsKey] = value;
|
|
333
|
+
mapIndex++;
|
|
334
|
+
this.skipWhitespace();
|
|
335
|
+
if (this.peek() === ",") {
|
|
336
|
+
this.advance();
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
return map;
|
|
340
|
+
}
|
|
341
|
+
}, {
|
|
342
|
+
key: "parseBinary",
|
|
343
|
+
value: function parseBinary() {
|
|
344
|
+
var currentPath = this.path.join(".");
|
|
345
|
+
var type = this.typeMap.get(currentPath) || "binary";
|
|
346
|
+
|
|
347
|
+
// Parse the formatted version (always byte format)
|
|
348
|
+
this.advance(2); // skip <<
|
|
349
|
+
|
|
350
|
+
if (this.peek() === ">" && this.peek(1) === ">") {
|
|
351
|
+
this.advance(2);
|
|
352
|
+
return Buffer.alloc(0);
|
|
353
|
+
}
|
|
354
|
+
var bytes = [];
|
|
355
|
+
while (!(this.peek() === ">" && this.peek(1) === ">")) {
|
|
356
|
+
this.skipWhitespace();
|
|
357
|
+
var num = "";
|
|
358
|
+
while (/\d/.test(this.peek())) {
|
|
359
|
+
num += this.peek();
|
|
360
|
+
this.advance();
|
|
361
|
+
}
|
|
362
|
+
if (num) bytes.push(parseInt(num, 10));
|
|
363
|
+
this.skipWhitespace();
|
|
364
|
+
if (this.peek() === ",") this.advance();
|
|
365
|
+
}
|
|
366
|
+
this.advance(2); // skip >>
|
|
367
|
+
|
|
368
|
+
var buffer = Buffer.from(bytes);
|
|
369
|
+
|
|
370
|
+
// If it was a string literal in raw, convert to string
|
|
371
|
+
if (type === "string") {
|
|
372
|
+
return buffer.toString("utf8");
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
// For binaries that are not explicitly marked as strings, check if they're valid UTF-8
|
|
376
|
+
// that contains reasonable string content (no control characters except \t, \n, \r)
|
|
377
|
+
try {
|
|
378
|
+
var str = buffer.toString("utf8");
|
|
379
|
+
// Check if the string round-trips correctly
|
|
380
|
+
if (Buffer.from(str, "utf8").equals(buffer)) {
|
|
381
|
+
// It's valid UTF-8, but also check if it contains reasonable characters
|
|
382
|
+
var hasReasonableChars = true;
|
|
383
|
+
for (var i = 0; i < str.length; i++) {
|
|
384
|
+
var code = str.charCodeAt(i);
|
|
385
|
+
// Allow printable chars, space, tab, newline, carriage return, and Unicode
|
|
386
|
+
if (code < 0x20 && code !== 0x09 && code !== 0x0a && code !== 0x0d) {
|
|
387
|
+
hasReasonableChars = false;
|
|
388
|
+
break;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
if (hasReasonableChars) {
|
|
392
|
+
return str;
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
} catch (e) {
|
|
396
|
+
// Not valid UTF-8, keep as buffer
|
|
397
|
+
}
|
|
398
|
+
return buffer;
|
|
399
|
+
}
|
|
400
|
+
}, {
|
|
401
|
+
key: "parseQuotedString",
|
|
402
|
+
value: function parseQuotedString() {
|
|
403
|
+
this.advance(); // skip opening "
|
|
404
|
+
var str = "";
|
|
405
|
+
while (this.peek() !== '"') {
|
|
406
|
+
if (this.peek() === "\\") {
|
|
407
|
+
this.advance();
|
|
408
|
+
var escaped = this.peek();
|
|
409
|
+
switch (escaped) {
|
|
410
|
+
case '"':
|
|
411
|
+
str += '"';
|
|
412
|
+
break;
|
|
413
|
+
case "\\":
|
|
414
|
+
str += "\\";
|
|
415
|
+
break;
|
|
416
|
+
case "n":
|
|
417
|
+
str += "\n";
|
|
418
|
+
break;
|
|
419
|
+
case "r":
|
|
420
|
+
str += "\r";
|
|
421
|
+
break;
|
|
422
|
+
case "t":
|
|
423
|
+
str += "\t";
|
|
424
|
+
break;
|
|
425
|
+
default:
|
|
426
|
+
str += escaped;
|
|
427
|
+
}
|
|
428
|
+
this.advance();
|
|
429
|
+
} else {
|
|
430
|
+
str += this.peek();
|
|
431
|
+
this.advance();
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
this.advance(); // skip closing "
|
|
435
|
+
return str;
|
|
436
|
+
}
|
|
437
|
+
}, {
|
|
438
|
+
key: "parseList",
|
|
439
|
+
value: function parseList() {
|
|
440
|
+
this.advance(); // skip [
|
|
441
|
+
var list = [];
|
|
442
|
+
var listIndex = 0;
|
|
443
|
+
while (true) {
|
|
444
|
+
this.skipWhitespace();
|
|
445
|
+
if (this.peek() === "]") {
|
|
446
|
+
this.advance();
|
|
447
|
+
break;
|
|
448
|
+
}
|
|
449
|
+
this.path.push(listIndex);
|
|
450
|
+
list.push(this.parseValue());
|
|
451
|
+
this.path.pop();
|
|
452
|
+
listIndex++;
|
|
453
|
+
this.skipWhitespace();
|
|
454
|
+
if (this.peek() === ",") {
|
|
455
|
+
this.advance();
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
return list;
|
|
459
|
+
}
|
|
460
|
+
}, {
|
|
461
|
+
key: "parseQuotedAtom",
|
|
462
|
+
value: function parseQuotedAtom() {
|
|
463
|
+
this.advance(); // skip '
|
|
464
|
+
|
|
465
|
+
var atom = "";
|
|
466
|
+
while (this.peek() !== "'") {
|
|
467
|
+
if (this.peek() === "\\") {
|
|
468
|
+
this.advance();
|
|
469
|
+
var escaped = this.peek();
|
|
470
|
+
switch (escaped) {
|
|
471
|
+
case "'":
|
|
472
|
+
atom += "'";
|
|
473
|
+
break;
|
|
474
|
+
case "\\":
|
|
475
|
+
atom += "\\";
|
|
476
|
+
break;
|
|
477
|
+
case "n":
|
|
478
|
+
atom += "\n";
|
|
479
|
+
break;
|
|
480
|
+
case "r":
|
|
481
|
+
atom += "\r";
|
|
482
|
+
break;
|
|
483
|
+
case "t":
|
|
484
|
+
atom += "\t";
|
|
485
|
+
break;
|
|
486
|
+
default:
|
|
487
|
+
atom += escaped;
|
|
488
|
+
}
|
|
489
|
+
this.advance();
|
|
490
|
+
} else {
|
|
491
|
+
atom += this.peek();
|
|
492
|
+
this.advance();
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
this.advance(); // skip closing '
|
|
496
|
+
|
|
497
|
+
if (atom === "null") return null;
|
|
498
|
+
if (atom === "true") return true;
|
|
499
|
+
if (atom === "false") return false;
|
|
500
|
+
return Symbol["for"](atom);
|
|
501
|
+
}
|
|
502
|
+
}, {
|
|
503
|
+
key: "parseAtomOrNumber",
|
|
504
|
+
value: function parseAtomOrNumber() {
|
|
505
|
+
var token = "";
|
|
506
|
+
|
|
507
|
+
// Parse unquoted atom/number
|
|
508
|
+
while (this.pos < this.str.length) {
|
|
509
|
+
var ch = this.peek();
|
|
510
|
+
if (ch === "," || ch === "]" || ch === "}" || ch === ")" || ch === "=" && this.peek(1) === ">") {
|
|
511
|
+
break;
|
|
512
|
+
}
|
|
513
|
+
if (/\s/.test(ch)) {
|
|
514
|
+
var i = this.pos;
|
|
515
|
+
while (i < this.str.length && /\s/.test(this.str[i])) i++;
|
|
516
|
+
if (i >= this.str.length) break;
|
|
517
|
+
var nextCh = this.str[i];
|
|
518
|
+
if (nextCh === "," || nextCh === "]" || nextCh === "}" || nextCh === ")" || nextCh === "=" && i + 1 < this.str.length && this.str[i + 1] === ">") {
|
|
519
|
+
break;
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
token += ch;
|
|
523
|
+
this.advance();
|
|
524
|
+
}
|
|
525
|
+
token = token.trim();
|
|
526
|
+
if (token === "null") return null;
|
|
527
|
+
if (token === "true") return true;
|
|
528
|
+
if (token === "false") return false;
|
|
529
|
+
if (/^-?\d+(\.\d+)?([eE][+-]?\d+)?$/.test(token)) {
|
|
530
|
+
return parseFloat(token);
|
|
531
|
+
}
|
|
532
|
+
return Symbol["for"](token);
|
|
533
|
+
}
|
|
534
|
+
}]);
|
|
535
|
+
}(); // Parser implementation
|
|
536
|
+
var ErlangParser = /*#__PURE__*/function () {
|
|
537
|
+
function ErlangParser(str) {
|
|
538
|
+
var binaryMode = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
|
|
539
|
+
_classCallCheck(this, ErlangParser);
|
|
540
|
+
this.str = str;
|
|
541
|
+
this.pos = 0;
|
|
542
|
+
this.binaryMode = binaryMode;
|
|
543
|
+
}
|
|
544
|
+
return _createClass(ErlangParser, [{
|
|
545
|
+
key: "parse",
|
|
546
|
+
value: function parse() {
|
|
547
|
+
var result = this.parseValue();
|
|
548
|
+
this.skipWhitespace();
|
|
549
|
+
if (this.pos < this.str.length) {
|
|
550
|
+
throw new Error("Unexpected content at position ".concat(this.pos, ": ").concat(this.str.slice(this.pos, this.pos + 50)));
|
|
551
|
+
}
|
|
552
|
+
return result;
|
|
553
|
+
}
|
|
554
|
+
}, {
|
|
555
|
+
key: "peek",
|
|
556
|
+
value: function peek() {
|
|
557
|
+
var offset = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
|
|
558
|
+
return this.str[this.pos + offset] || "";
|
|
559
|
+
}
|
|
560
|
+
}, {
|
|
561
|
+
key: "advance",
|
|
562
|
+
value: function advance() {
|
|
563
|
+
var count = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;
|
|
564
|
+
this.pos += count;
|
|
565
|
+
}
|
|
566
|
+
}, {
|
|
567
|
+
key: "skipWhitespace",
|
|
568
|
+
value: function skipWhitespace() {
|
|
569
|
+
while (this.pos < this.str.length && /\s/.test(this.peek())) {
|
|
570
|
+
this.advance();
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
}, {
|
|
574
|
+
key: "parseValue",
|
|
575
|
+
value: function parseValue() {
|
|
576
|
+
this.skipWhitespace();
|
|
577
|
+
var ch = this.peek();
|
|
578
|
+
var ch2 = this.peek(1);
|
|
579
|
+
|
|
580
|
+
// Map: #{...}
|
|
581
|
+
if (ch === "#" && ch2 === "{") {
|
|
582
|
+
return this.parseMap();
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
// Binary: <<...>>
|
|
586
|
+
if (ch === "<" && ch2 === "<") {
|
|
587
|
+
return this.parseBinary();
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
// List: [...]
|
|
591
|
+
if (ch === "[") {
|
|
592
|
+
return this.parseList();
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
// Quoted atom: 'atom'
|
|
596
|
+
if (ch === "'") {
|
|
597
|
+
return this.parseQuotedAtom();
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
// Quoted string: "..."
|
|
601
|
+
if (ch === '"') {
|
|
602
|
+
return this.parseQuotedString();
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
// Number or unquoted atom
|
|
606
|
+
return this.parseAtomOrNumber();
|
|
607
|
+
}
|
|
608
|
+
}, {
|
|
609
|
+
key: "parseMap",
|
|
610
|
+
value: function parseMap() {
|
|
611
|
+
this.advance(2); // skip #{
|
|
612
|
+
var map = {};
|
|
613
|
+
while (true) {
|
|
614
|
+
this.skipWhitespace();
|
|
615
|
+
if (this.peek() === "}") {
|
|
616
|
+
this.advance();
|
|
617
|
+
break;
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
// Parse key
|
|
621
|
+
var key = this.parseValue();
|
|
622
|
+
this.skipWhitespace();
|
|
623
|
+
|
|
624
|
+
// Expect =>
|
|
625
|
+
if (this.peek() !== "=" || this.peek(1) !== ">") {
|
|
626
|
+
throw new Error("Expected => at position ".concat(this.pos));
|
|
627
|
+
}
|
|
628
|
+
this.advance(2);
|
|
629
|
+
this.skipWhitespace();
|
|
630
|
+
|
|
631
|
+
// Parse value
|
|
632
|
+
var value = this.parseValue();
|
|
633
|
+
|
|
634
|
+
// Convert key to string
|
|
635
|
+
var jsKey = void 0;
|
|
636
|
+
if (key instanceof Buffer) {
|
|
637
|
+
jsKey = key.toString("utf8");
|
|
638
|
+
} else if (_typeof(key) === "symbol") {
|
|
639
|
+
jsKey = Symbol.keyFor(key) || key.description || String(key);
|
|
640
|
+
} else {
|
|
641
|
+
jsKey = String(key);
|
|
642
|
+
}
|
|
643
|
+
map[jsKey] = value;
|
|
644
|
+
this.skipWhitespace();
|
|
645
|
+
if (this.peek() === ",") {
|
|
646
|
+
this.advance();
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
return map;
|
|
650
|
+
}
|
|
651
|
+
}, {
|
|
652
|
+
key: "parseBinary",
|
|
653
|
+
value: function parseBinary() {
|
|
654
|
+
this.advance(2); // skip <<
|
|
655
|
+
|
|
656
|
+
// String binary: <<"...">>
|
|
657
|
+
if (this.peek() === '"') {
|
|
658
|
+
this.advance(); // skip "
|
|
659
|
+
var content = "";
|
|
660
|
+
while (!(this.peek() === '"' && this.peek(1) === ">" && this.peek(2) === ">")) {
|
|
661
|
+
if (this.pos >= this.str.length) {
|
|
662
|
+
throw new Error("Unterminated string binary");
|
|
663
|
+
}
|
|
664
|
+
if (this.peek() === "\\") {
|
|
665
|
+
this.advance();
|
|
666
|
+
var escaped = this.peek();
|
|
667
|
+
|
|
668
|
+
// Check for octal escape sequences \NNN
|
|
669
|
+
if (/[0-7]/.test(escaped)) {
|
|
670
|
+
var octal = escaped;
|
|
671
|
+
this.advance();
|
|
672
|
+
|
|
673
|
+
// Get up to 2 more octal digits
|
|
674
|
+
if (/[0-7]/.test(this.peek())) {
|
|
675
|
+
octal += this.peek();
|
|
676
|
+
this.advance();
|
|
677
|
+
if (/[0-7]/.test(this.peek())) {
|
|
678
|
+
octal += this.peek();
|
|
679
|
+
this.advance();
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
// Convert octal to character
|
|
684
|
+
var charCode = parseInt(octal, 8);
|
|
685
|
+
content += String.fromCharCode(charCode);
|
|
686
|
+
} else {
|
|
687
|
+
// Regular escape sequences
|
|
688
|
+
switch (escaped) {
|
|
689
|
+
case '"':
|
|
690
|
+
content += '"';
|
|
691
|
+
break;
|
|
692
|
+
case "\\":
|
|
693
|
+
content += "\\";
|
|
694
|
+
break;
|
|
695
|
+
case "n":
|
|
696
|
+
content += "\n";
|
|
697
|
+
break;
|
|
698
|
+
case "r":
|
|
699
|
+
content += "\r";
|
|
700
|
+
break;
|
|
701
|
+
case "t":
|
|
702
|
+
content += "\t";
|
|
703
|
+
break;
|
|
704
|
+
default:
|
|
705
|
+
content += escaped;
|
|
706
|
+
}
|
|
707
|
+
this.advance();
|
|
708
|
+
}
|
|
709
|
+
} else {
|
|
710
|
+
content += this.peek();
|
|
711
|
+
this.advance();
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
this.advance(3); // skip ">>
|
|
715
|
+
|
|
716
|
+
// Check for structured field format
|
|
717
|
+
if (content.startsWith(":") && content.endsWith(":") && content.length >= 2) {
|
|
718
|
+
if (content === "::") {
|
|
719
|
+
return Buffer.alloc(0);
|
|
720
|
+
}
|
|
721
|
+
try {
|
|
722
|
+
var base64 = content.slice(1, -1);
|
|
723
|
+
return Buffer.from(base64, "base64");
|
|
724
|
+
} catch (e) {
|
|
725
|
+
// Not valid base64, treat as regular string
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
// In binary mode, return as Buffer; otherwise check if it's printable
|
|
730
|
+
if (this.binaryMode) {
|
|
731
|
+
return Buffer.from(content, "utf8");
|
|
732
|
+
} else {
|
|
733
|
+
// Check if the content is printable
|
|
734
|
+
var _bytes = Buffer.from(content, "utf8");
|
|
735
|
+
var isPrintable = Array.from(_bytes).every(function (b) {
|
|
736
|
+
return b >= 32 && b <= 126;
|
|
737
|
+
});
|
|
738
|
+
|
|
739
|
+
// If it contains non-printable characters, return as Buffer
|
|
740
|
+
if (!isPrintable) {
|
|
741
|
+
return _bytes;
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
// Otherwise return as string
|
|
745
|
+
return content;
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
// Empty binary: <<>>
|
|
750
|
+
if (this.peek() === ">" && this.peek(1) === ">") {
|
|
751
|
+
this.advance(2);
|
|
752
|
+
return Buffer.alloc(0);
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
// Byte binary: <<1,2,3>>
|
|
756
|
+
var bytes = [];
|
|
757
|
+
while (!(this.peek() === ">" && this.peek(1) === ">")) {
|
|
758
|
+
if (this.pos >= this.str.length) {
|
|
759
|
+
throw new Error("Unterminated byte binary");
|
|
760
|
+
}
|
|
761
|
+
this.skipWhitespace();
|
|
762
|
+
var num = "";
|
|
763
|
+
while (/\d/.test(this.peek())) {
|
|
764
|
+
num += this.peek();
|
|
765
|
+
this.advance();
|
|
766
|
+
}
|
|
767
|
+
if (num) {
|
|
768
|
+
bytes.push(parseInt(num, 10));
|
|
769
|
+
}
|
|
770
|
+
this.skipWhitespace();
|
|
771
|
+
if (this.peek() === ",") {
|
|
772
|
+
this.advance();
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
this.advance(2); // skip >>
|
|
776
|
+
return Buffer.from(bytes);
|
|
777
|
+
}
|
|
778
|
+
}, {
|
|
779
|
+
key: "parseQuotedString",
|
|
780
|
+
value: function parseQuotedString() {
|
|
781
|
+
this.advance(); // skip "
|
|
782
|
+
var str = "";
|
|
783
|
+
while (this.peek() !== '"') {
|
|
784
|
+
if (this.peek() === "\\") {
|
|
785
|
+
this.advance();
|
|
786
|
+
var escaped = this.peek();
|
|
787
|
+
switch (escaped) {
|
|
788
|
+
case '"':
|
|
789
|
+
str += '"';
|
|
790
|
+
break;
|
|
791
|
+
case "\\":
|
|
792
|
+
str += "\\";
|
|
793
|
+
break;
|
|
794
|
+
case "n":
|
|
795
|
+
str += "\n";
|
|
796
|
+
break;
|
|
797
|
+
case "r":
|
|
798
|
+
str += "\r";
|
|
799
|
+
break;
|
|
800
|
+
case "t":
|
|
801
|
+
str += "\t";
|
|
802
|
+
break;
|
|
803
|
+
default:
|
|
804
|
+
str += escaped;
|
|
805
|
+
}
|
|
806
|
+
this.advance();
|
|
807
|
+
} else {
|
|
808
|
+
str += this.peek();
|
|
809
|
+
this.advance();
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
this.advance(); // skip closing "
|
|
813
|
+
return str;
|
|
814
|
+
}
|
|
815
|
+
}, {
|
|
816
|
+
key: "parseList",
|
|
817
|
+
value: function parseList() {
|
|
818
|
+
this.advance(); // skip [
|
|
819
|
+
var list = [];
|
|
820
|
+
while (true) {
|
|
821
|
+
this.skipWhitespace();
|
|
822
|
+
if (this.peek() === "]") {
|
|
823
|
+
this.advance();
|
|
824
|
+
break;
|
|
825
|
+
}
|
|
826
|
+
list.push(this.parseValue());
|
|
827
|
+
this.skipWhitespace();
|
|
828
|
+
if (this.peek() === ",") {
|
|
829
|
+
this.advance();
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
return list;
|
|
833
|
+
}
|
|
834
|
+
}, {
|
|
835
|
+
key: "parseQuotedAtom",
|
|
836
|
+
value: function parseQuotedAtom() {
|
|
837
|
+
this.advance(); // skip '
|
|
838
|
+
var atom = "";
|
|
839
|
+
while (this.peek() !== "'") {
|
|
840
|
+
if (this.pos >= this.str.length) {
|
|
841
|
+
throw new Error("Unterminated quoted atom");
|
|
842
|
+
}
|
|
843
|
+
if (this.peek() === "\\") {
|
|
844
|
+
this.advance();
|
|
845
|
+
var escaped = this.peek();
|
|
846
|
+
switch (escaped) {
|
|
847
|
+
case "'":
|
|
848
|
+
atom += "'";
|
|
849
|
+
break;
|
|
850
|
+
case "\\":
|
|
851
|
+
atom += "\\";
|
|
852
|
+
break;
|
|
853
|
+
case "n":
|
|
854
|
+
atom += "\n";
|
|
855
|
+
break;
|
|
856
|
+
// Literal newline
|
|
857
|
+
case "r":
|
|
858
|
+
atom += "\r";
|
|
859
|
+
break;
|
|
860
|
+
case "t":
|
|
861
|
+
atom += "\t";
|
|
862
|
+
break;
|
|
863
|
+
default:
|
|
864
|
+
atom += escaped;
|
|
865
|
+
}
|
|
866
|
+
this.advance();
|
|
867
|
+
} else {
|
|
868
|
+
atom += this.peek();
|
|
869
|
+
this.advance();
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
this.advance(); // skip closing '
|
|
873
|
+
|
|
874
|
+
// Special atoms that become JS primitives
|
|
875
|
+
if (atom === "null") return null;
|
|
876
|
+
if (atom === "true") return true;
|
|
877
|
+
if (atom === "false") return false;
|
|
878
|
+
return Symbol["for"](atom);
|
|
879
|
+
}
|
|
880
|
+
}, {
|
|
881
|
+
key: "parseAtomOrNumber",
|
|
882
|
+
value: function parseAtomOrNumber() {
|
|
883
|
+
var startPos = this.pos;
|
|
884
|
+
var token = "";
|
|
885
|
+
|
|
886
|
+
// Simple approach: collect until we hit a known delimiter
|
|
887
|
+
while (this.pos < this.str.length) {
|
|
888
|
+
var ch = this.peek();
|
|
889
|
+
var ch2 = this.peek(1);
|
|
890
|
+
|
|
891
|
+
// Stop at these delimiters
|
|
892
|
+
if (ch === ",") break;
|
|
893
|
+
if (ch === "]") break;
|
|
894
|
+
if (ch === "}") break;
|
|
895
|
+
if (ch === ")") break;
|
|
896
|
+
if (ch === "=" && ch2 === ">") break;
|
|
897
|
+
|
|
898
|
+
// Handle backslash specially
|
|
899
|
+
if (ch === "\\") {
|
|
900
|
+
// In unquoted atoms, backslash is just a regular character
|
|
901
|
+
token += ch;
|
|
902
|
+
this.advance();
|
|
903
|
+
|
|
904
|
+
// Don't try to interpret the next character as an escape
|
|
905
|
+
if (this.pos < this.str.length) {
|
|
906
|
+
token += this.peek();
|
|
907
|
+
this.advance();
|
|
908
|
+
}
|
|
909
|
+
continue;
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
// For whitespace, check if it's trailing
|
|
913
|
+
if (/\s/.test(ch)) {
|
|
914
|
+
// Scan ahead to find next non-whitespace
|
|
915
|
+
var i = this.pos;
|
|
916
|
+
while (i < this.str.length && /\s/.test(this.str[i])) {
|
|
917
|
+
i++;
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
// Check what comes after whitespace
|
|
921
|
+
if (i >= this.str.length) {
|
|
922
|
+
// Hit end of string
|
|
923
|
+
break;
|
|
924
|
+
}
|
|
925
|
+
var nextCh = this.str[i];
|
|
926
|
+
if (nextCh === "," || nextCh === "]" || nextCh === "}" || nextCh === ")") {
|
|
927
|
+
// This whitespace is trailing, not part of atom
|
|
928
|
+
break;
|
|
929
|
+
}
|
|
930
|
+
if (nextCh === "=" && i + 1 < this.str.length && this.str[i + 1] === ">") {
|
|
931
|
+
// Whitespace before =>
|
|
932
|
+
break;
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
// Include this character in the atom
|
|
937
|
+
token += ch;
|
|
938
|
+
this.advance();
|
|
939
|
+
|
|
940
|
+
// Safety check to prevent infinite loops
|
|
941
|
+
if (this.pos - startPos > 1000) {
|
|
942
|
+
throw new Error("Atom too long at position ".concat(startPos));
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
// Trim only trailing whitespace
|
|
947
|
+
token = token.trimEnd();
|
|
948
|
+
if (!token) {
|
|
949
|
+
throw new Error("Empty atom at position ".concat(this.pos));
|
|
950
|
+
}
|
|
951
|
+
|
|
952
|
+
// Handle special atoms
|
|
953
|
+
if (token === "null") return null;
|
|
954
|
+
if (token === "true") return true;
|
|
955
|
+
if (token === "false") return false;
|
|
956
|
+
|
|
957
|
+
// Try to parse as number
|
|
958
|
+
if (/^-?\d+(\.\d+)?([eE][+-]?\d+)?$/.test(token)) {
|
|
959
|
+
return parseFloat(token);
|
|
960
|
+
}
|
|
961
|
+
|
|
962
|
+
// Return as atom
|
|
963
|
+
return Symbol["for"](token);
|
|
964
|
+
}
|
|
965
|
+
}]);
|
|
966
|
+
}();
|
|
967
|
+
/**
|
|
968
|
+
* Format JavaScript values as Erlang term strings
|
|
969
|
+
* @param {*} value - JavaScript value
|
|
970
|
+
* @returns {string} Erlang term string
|
|
971
|
+
*/
|
|
972
|
+
function erl_str_to(value) {
|
|
973
|
+
return formatValue(value);
|
|
974
|
+
}
|
|
975
|
+
|
|
976
|
+
// Formatter implementation
|
|
977
|
+
function formatValue(value) {
|
|
978
|
+
if (value === null) return "null";
|
|
979
|
+
if (value === undefined) return "undefined";
|
|
980
|
+
if (typeof value === "boolean") return value.toString();
|
|
981
|
+
if (typeof value === "number") {
|
|
982
|
+
return value.toString();
|
|
983
|
+
}
|
|
984
|
+
if (typeof value === "string") {
|
|
985
|
+
// Format as string binary
|
|
986
|
+
return "<<\"".concat(escapeString(value), "\">>");
|
|
987
|
+
}
|
|
988
|
+
if (_typeof(value) === "symbol") {
|
|
989
|
+
var key = Symbol.keyFor(value);
|
|
990
|
+
var name = key || value.description || "";
|
|
991
|
+
|
|
992
|
+
// Special symbols
|
|
993
|
+
if (name === "null") return "null";
|
|
994
|
+
if (name === "true") return "true";
|
|
995
|
+
if (name === "false") return "false";
|
|
996
|
+
if (name === "undefined") return "undefined";
|
|
997
|
+
|
|
998
|
+
// Check if needs quoting
|
|
999
|
+
if (/^[a-z][a-zA-Z0-9_]*$/.test(name)) {
|
|
1000
|
+
return name;
|
|
1001
|
+
} else {
|
|
1002
|
+
return "'".concat(escapeString(name), "'");
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
if (value instanceof Buffer || value instanceof Uint8Array) {
|
|
1006
|
+
var bytes = Array.from(value);
|
|
1007
|
+
|
|
1008
|
+
// Check if it's printable
|
|
1009
|
+
var isPrintable = bytes.every(function (b) {
|
|
1010
|
+
return b >= 32 && b <= 126;
|
|
1011
|
+
});
|
|
1012
|
+
if (isPrintable) {
|
|
1013
|
+
var str = Buffer.from(value).toString();
|
|
1014
|
+
return "<<\"".concat(escapeString(str), "\">>");
|
|
1015
|
+
} else {
|
|
1016
|
+
return "<<".concat(bytes.join(","), ">>");
|
|
1017
|
+
}
|
|
1018
|
+
}
|
|
1019
|
+
if (Array.isArray(value)) {
|
|
1020
|
+
var items = value.map(formatValue);
|
|
1021
|
+
return "[".concat(items.join(","), "]");
|
|
1022
|
+
}
|
|
1023
|
+
if (_typeof(value) === "object" && value !== null) {
|
|
1024
|
+
var entries = Object.entries(value).map(function (_ref) {
|
|
1025
|
+
var _ref2 = _slicedToArray(_ref, 2),
|
|
1026
|
+
k = _ref2[0],
|
|
1027
|
+
v = _ref2[1];
|
|
1028
|
+
var key = "<<\"".concat(escapeString(k), "\">>");
|
|
1029
|
+
return "".concat(key, " => ").concat(formatValue(v));
|
|
1030
|
+
});
|
|
1031
|
+
return "#{".concat(entries.join(","), "}");
|
|
1032
|
+
}
|
|
1033
|
+
return String(value);
|
|
1034
|
+
}
|
|
1035
|
+
function escapeString(str) {
|
|
1036
|
+
return str.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/\t/g, "\\t");
|
|
1037
|
+
}
|