@o3co/ts.hocon 1.12.0 → 1.14.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/README.ja.md +256 -32
- package/README.md +166 -32
- package/dist/adapters/env.cjs +26 -1678
- package/dist/adapters/env.d.cts +1 -1
- package/dist/adapters/env.d.ts +1 -1
- package/dist/adapters/env.js +11 -1625
- package/dist/adapters/json5.cjs +496 -0
- package/dist/adapters/json5.d.cts +47 -0
- package/dist/adapters/json5.d.ts +47 -0
- package/dist/adapters/json5.js +496 -0
- package/dist/adapters/jsonc.cjs +17 -1632
- package/dist/adapters/jsonc.d.cts +1 -1
- package/dist/adapters/jsonc.d.ts +1 -1
- package/dist/adapters/jsonc.js +9 -1586
- package/dist/adapters/properties.cjs +7 -1773
- package/dist/adapters/properties.d.cts +1 -1
- package/dist/adapters/properties.d.ts +1 -1
- package/dist/adapters/properties.js +6 -1735
- package/dist/adapters/toml.cjs +12 -1626
- package/dist/adapters/toml.d.cts +1 -1
- package/dist/adapters/toml.d.ts +1 -1
- package/dist/adapters/toml.js +10 -1589
- package/dist/adapters/yaml.cjs +20 -1635
- package/dist/adapters/yaml.d.cts +1 -1
- package/dist/adapters/yaml.d.ts +1 -1
- package/dist/adapters/yaml.js +10 -1589
- package/dist/chunk-GBNQADHT.cjs +83 -0
- package/dist/chunk-IMJ7QHIK.cjs +158 -0
- package/dist/chunk-QY7ECGS6.js +83 -0
- package/dist/chunk-RO4D6BH7.cjs +3792 -0
- package/dist/chunk-WTXULUZS.js +3792 -0
- package/dist/chunk-XWKO4JM3.js +158 -0
- package/dist/{config-Dlq6rF3w.d.cts → config-OccaKqXu.d.cts} +148 -4
- package/dist/{config-Dlq6rF3w.d.ts → config-OccaKqXu.d.ts} +148 -4
- package/dist/index.cjs +35 -3449
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +25 -3383
- package/dist/zod.cjs +107 -3291
- package/dist/zod.d.cts +83 -3
- package/dist/zod.d.ts +83 -3
- package/dist/zod.js +95 -3245
- package/package.json +12 -2
|
@@ -0,0 +1,496 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true});
|
|
2
|
+
|
|
3
|
+
var _chunkGBNQADHTcjs = require('../chunk-GBNQADHT.cjs');
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
var _chunkRO4D6BH7cjs = require('../chunk-RO4D6BH7.cjs');
|
|
10
|
+
|
|
11
|
+
// src/adapters/json5.ts
|
|
12
|
+
function parseJson5(input, originDescription) {
|
|
13
|
+
const p = new Parser(_chunkRO4D6BH7cjs.stripBom.call(void 0, input), originDescription);
|
|
14
|
+
const doc = _chunkRO4D6BH7cjs.guardStackDepth.call(void 0,
|
|
15
|
+
() => p.parseDocument(),
|
|
16
|
+
(msg) => _chunkRO4D6BH7cjs.depthError.call(void 0, `json5: ${describe(originDescription)}: ${msg}`)
|
|
17
|
+
);
|
|
18
|
+
if (doc === null || typeof doc !== "object" || Array.isArray(doc)) {
|
|
19
|
+
throw new (0, _chunkRO4D6BH7cjs.ConfigError)(
|
|
20
|
+
`json5: ${describe(originDescription)}: document root is ${rootKind(doc)}, but a config root must be an object (spec F0.3)`,
|
|
21
|
+
""
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
return _chunkGBNQADHTcjs.fromMap.call(void 0, doc, originDescription);
|
|
25
|
+
}
|
|
26
|
+
function describe(origin) {
|
|
27
|
+
return origin === void 0 || origin === "" ? "document" : origin;
|
|
28
|
+
}
|
|
29
|
+
function rootKind(doc) {
|
|
30
|
+
if (doc === null) return "null";
|
|
31
|
+
if (Array.isArray(doc)) return "an array";
|
|
32
|
+
return typeof doc;
|
|
33
|
+
}
|
|
34
|
+
var INT64_MAX = 9223372036854775807n;
|
|
35
|
+
var INT64_MIN = -9223372036854775808n;
|
|
36
|
+
function isLineTerminator(cp) {
|
|
37
|
+
return cp === 10 || cp === 13 || cp === 8232 || cp === 8233;
|
|
38
|
+
}
|
|
39
|
+
var ZS_RE = /^\p{Zs}$/u;
|
|
40
|
+
function isJson5Space(cp) {
|
|
41
|
+
switch (cp) {
|
|
42
|
+
case 9:
|
|
43
|
+
case 11:
|
|
44
|
+
case 12:
|
|
45
|
+
case 32:
|
|
46
|
+
case 160:
|
|
47
|
+
case 65279:
|
|
48
|
+
return true;
|
|
49
|
+
default:
|
|
50
|
+
return ZS_RE.test(String.fromCodePoint(cp));
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
var IDENT_START_RE = /^[\p{Lu}\p{Ll}\p{Lt}\p{Lm}\p{Lo}\p{Nl}]$/u;
|
|
54
|
+
var IDENT_PART_EXTRA_RE = /^[\p{Mn}\p{Mc}\p{Nd}\p{Pc}]$/u;
|
|
55
|
+
function isIdentStart(cp) {
|
|
56
|
+
return cp === 36 || cp === 95 || IDENT_START_RE.test(String.fromCodePoint(cp));
|
|
57
|
+
}
|
|
58
|
+
function isIdentPart(cp) {
|
|
59
|
+
return isIdentStart(cp) || cp === 8204 || cp === 8205 || IDENT_PART_EXTRA_RE.test(String.fromCodePoint(cp));
|
|
60
|
+
}
|
|
61
|
+
function continuesIdentifier(s, i) {
|
|
62
|
+
if (i >= s.length) return false;
|
|
63
|
+
return isIdentPart(s.codePointAt(i));
|
|
64
|
+
}
|
|
65
|
+
function isHexDigit(c) {
|
|
66
|
+
return c >= "0" && c <= "9" || c >= "a" && c <= "f" || c >= "A" && c <= "F";
|
|
67
|
+
}
|
|
68
|
+
var hex4 = (cp) => cp.toString(16).toUpperCase().padStart(4, "0");
|
|
69
|
+
function isPlainObject(v) {
|
|
70
|
+
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
71
|
+
}
|
|
72
|
+
function mergeObjects(dst, src) {
|
|
73
|
+
const out = /* @__PURE__ */ Object.create(null);
|
|
74
|
+
for (const [k, v] of Object.entries(dst)) out[k] = v;
|
|
75
|
+
for (const [k, v] of Object.entries(src)) {
|
|
76
|
+
const prev = k in out ? out[k] : void 0;
|
|
77
|
+
if (prev !== void 0 && isPlainObject(prev) && isPlainObject(v)) {
|
|
78
|
+
out[k] = mergeObjects(prev, v);
|
|
79
|
+
} else {
|
|
80
|
+
out[k] = v;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return out;
|
|
84
|
+
}
|
|
85
|
+
var Parser = class {
|
|
86
|
+
// code unit offset where the current line starts
|
|
87
|
+
constructor(src, origin) {
|
|
88
|
+
this.src = src;
|
|
89
|
+
this.origin = origin;
|
|
90
|
+
this.pos = 0;
|
|
91
|
+
// UTF-16 code unit offset
|
|
92
|
+
this.line = 0;
|
|
93
|
+
// 0-based; reported 1-based
|
|
94
|
+
this.lineAt = 0;
|
|
95
|
+
}
|
|
96
|
+
errf(msg) {
|
|
97
|
+
const col = [...this.src.slice(this.lineAt, this.pos)].length + 1;
|
|
98
|
+
return new (0, _chunkRO4D6BH7cjs.ConfigError)(
|
|
99
|
+
`json5: ${describe(this.origin)}: line ${this.line + 1} col ${col}: ${msg}`,
|
|
100
|
+
""
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
/** The code point at `pos` (caller guarantees `pos < src.length`). */
|
|
104
|
+
rune() {
|
|
105
|
+
const cp = this.src.codePointAt(this.pos);
|
|
106
|
+
return { cp, size: cp > 65535 ? 2 : 1 };
|
|
107
|
+
}
|
|
108
|
+
advance(cp, size) {
|
|
109
|
+
this.pos += size;
|
|
110
|
+
if (isLineTerminator(cp)) {
|
|
111
|
+
if (cp === 13 && this.src[this.pos] === "\n") this.pos++;
|
|
112
|
+
this.line++;
|
|
113
|
+
this.lineAt = this.pos;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Parse exactly one JSON5 value, allowing only whitespace and comments after
|
|
118
|
+
* it (the F3.2 strictness rule).
|
|
119
|
+
*/
|
|
120
|
+
parseDocument() {
|
|
121
|
+
this.skipSpace();
|
|
122
|
+
const v = this.parseValue();
|
|
123
|
+
this.skipSpace();
|
|
124
|
+
if (this.pos < this.src.length) {
|
|
125
|
+
throw this.errf("unexpected content after top-level value");
|
|
126
|
+
}
|
|
127
|
+
return v;
|
|
128
|
+
}
|
|
129
|
+
/** Consume whitespace, line terminators, and both comment forms. */
|
|
130
|
+
skipSpace() {
|
|
131
|
+
while (this.pos < this.src.length) {
|
|
132
|
+
const { cp, size } = this.rune();
|
|
133
|
+
if (isJson5Space(cp) || isLineTerminator(cp)) {
|
|
134
|
+
this.advance(cp, size);
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
if (cp === 47 && this.src[this.pos + 1] === "/") {
|
|
138
|
+
this.pos += 2;
|
|
139
|
+
while (this.pos < this.src.length) {
|
|
140
|
+
const cp2 = this.src.codePointAt(this.pos);
|
|
141
|
+
if (isLineTerminator(cp2)) break;
|
|
142
|
+
this.pos += cp2 > 65535 ? 2 : 1;
|
|
143
|
+
}
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
if (cp === 47 && this.src[this.pos + 1] === "*") {
|
|
147
|
+
this.pos += 2;
|
|
148
|
+
let closed = false;
|
|
149
|
+
while (this.pos < this.src.length) {
|
|
150
|
+
const r2 = this.rune();
|
|
151
|
+
if (r2.cp === 42 && this.src[this.pos + 1] === "/") {
|
|
152
|
+
this.pos += 2;
|
|
153
|
+
closed = true;
|
|
154
|
+
break;
|
|
155
|
+
}
|
|
156
|
+
this.advance(r2.cp, r2.size);
|
|
157
|
+
}
|
|
158
|
+
if (!closed) throw this.errf("unterminated /* comment");
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
parseValue() {
|
|
165
|
+
if (this.pos >= this.src.length) {
|
|
166
|
+
throw this.errf("unexpected end of input, expected a value");
|
|
167
|
+
}
|
|
168
|
+
const c = this.src[this.pos];
|
|
169
|
+
if (c === "{") return this.parseObject();
|
|
170
|
+
if (c === "[") return this.parseArray();
|
|
171
|
+
if (c === '"' || c === "'") return this.parseString(c);
|
|
172
|
+
if (c === "+" || c === "-" || c === "." || c >= "0" && c <= "9") return this.parseNumber();
|
|
173
|
+
return this.parseKeyword();
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Handle true/false/null, and reject Infinity/NaN by name so the error
|
|
177
|
+
* explains itself (spec F0.6).
|
|
178
|
+
*/
|
|
179
|
+
parseKeyword() {
|
|
180
|
+
const rest = this.src.slice(this.pos);
|
|
181
|
+
for (const [kw, v] of [
|
|
182
|
+
["true", true],
|
|
183
|
+
["false", false],
|
|
184
|
+
["null", null]
|
|
185
|
+
]) {
|
|
186
|
+
if (rest.startsWith(kw) && !continuesIdentifier(rest, kw.length)) {
|
|
187
|
+
this.pos += kw.length;
|
|
188
|
+
return v;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
for (const kw of ["Infinity", "NaN"]) {
|
|
192
|
+
if (rest.startsWith(kw) && !continuesIdentifier(rest, kw.length)) {
|
|
193
|
+
throw this.errf(`${kw} is not representable in the HOCON number model (spec F0.6)`);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
const first = String.fromCodePoint(rest.codePointAt(0));
|
|
197
|
+
throw this.errf(`unexpected character ${JSON.stringify(first)}`);
|
|
198
|
+
}
|
|
199
|
+
// ── Objects and arrays ──────────────────────────────────────────────────────
|
|
200
|
+
parseObject() {
|
|
201
|
+
this.pos++;
|
|
202
|
+
const obj = /* @__PURE__ */ Object.create(null);
|
|
203
|
+
for (; ; ) {
|
|
204
|
+
this.skipSpace();
|
|
205
|
+
if (this.pos >= this.src.length) throw this.errf("unterminated object, expected '}'");
|
|
206
|
+
if (this.src[this.pos] === "}") {
|
|
207
|
+
this.pos++;
|
|
208
|
+
return obj;
|
|
209
|
+
}
|
|
210
|
+
const key = this.parseMemberName();
|
|
211
|
+
this.skipSpace();
|
|
212
|
+
if (this.pos >= this.src.length || this.src[this.pos] !== ":") {
|
|
213
|
+
throw this.errf(`expected ':' after object key ${JSON.stringify(key)}`);
|
|
214
|
+
}
|
|
215
|
+
this.pos++;
|
|
216
|
+
this.skipSpace();
|
|
217
|
+
let val = this.parseValue();
|
|
218
|
+
if (key in obj) {
|
|
219
|
+
const prev = obj[key];
|
|
220
|
+
if (isPlainObject(prev) && isPlainObject(val)) val = mergeObjects(prev, val);
|
|
221
|
+
}
|
|
222
|
+
obj[key] = val;
|
|
223
|
+
this.skipSpace();
|
|
224
|
+
if (this.pos >= this.src.length) throw this.errf("unterminated object, expected ',' or '}'");
|
|
225
|
+
const c = this.src[this.pos];
|
|
226
|
+
if (c === ",") {
|
|
227
|
+
this.pos++;
|
|
228
|
+
} else if (c === "}") {
|
|
229
|
+
this.pos++;
|
|
230
|
+
return obj;
|
|
231
|
+
} else {
|
|
232
|
+
throw this.errf("expected ',' or '}' in object");
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
parseArray() {
|
|
237
|
+
this.pos++;
|
|
238
|
+
const arr = [];
|
|
239
|
+
for (; ; ) {
|
|
240
|
+
this.skipSpace();
|
|
241
|
+
if (this.pos >= this.src.length) throw this.errf("unterminated array, expected ']'");
|
|
242
|
+
if (this.src[this.pos] === "]") {
|
|
243
|
+
this.pos++;
|
|
244
|
+
return arr;
|
|
245
|
+
}
|
|
246
|
+
arr.push(this.parseValue());
|
|
247
|
+
this.skipSpace();
|
|
248
|
+
if (this.pos >= this.src.length) throw this.errf("unterminated array, expected ',' or ']'");
|
|
249
|
+
const c = this.src[this.pos];
|
|
250
|
+
if (c === ",") {
|
|
251
|
+
this.pos++;
|
|
252
|
+
} else if (c === "]") {
|
|
253
|
+
this.pos++;
|
|
254
|
+
return arr;
|
|
255
|
+
} else {
|
|
256
|
+
throw this.errf("expected ',' or ']' in array");
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
// ── Member names (quoted or ES5 IdentifierName) ─────────────────────────────
|
|
261
|
+
parseMemberName() {
|
|
262
|
+
const c = this.src[this.pos];
|
|
263
|
+
if (c === '"' || c === "'") return this.parseString(c);
|
|
264
|
+
return this.parseIdentifier();
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Scan an ES5 IdentifierName, honouring `\uXXXX` escapes in the name (the
|
|
268
|
+
* escaped codepoint must itself be a legal identifier character for its
|
|
269
|
+
* position, per ES5 — `1` cannot start a key).
|
|
270
|
+
*/
|
|
271
|
+
parseIdentifier() {
|
|
272
|
+
let name = "";
|
|
273
|
+
let first = true;
|
|
274
|
+
while (this.pos < this.src.length) {
|
|
275
|
+
const r = this.rune();
|
|
276
|
+
let cp = r.cp;
|
|
277
|
+
let escaped = false;
|
|
278
|
+
if (cp === 92) {
|
|
279
|
+
if (this.src[this.pos + 1] !== "u") {
|
|
280
|
+
throw this.errf("only \\uXXXX escapes are allowed in identifiers");
|
|
281
|
+
}
|
|
282
|
+
this.pos += 2;
|
|
283
|
+
cp = this.readHex4();
|
|
284
|
+
escaped = true;
|
|
285
|
+
}
|
|
286
|
+
const legal = first ? isIdentStart(cp) : isIdentPart(cp);
|
|
287
|
+
if (!legal) {
|
|
288
|
+
if (escaped) {
|
|
289
|
+
throw this.errf(`escape \\u${hex4(cp)} is not a valid identifier character here`);
|
|
290
|
+
}
|
|
291
|
+
if (first) {
|
|
292
|
+
throw this.errf(`expected an object key, got ${JSON.stringify(String.fromCodePoint(cp))}`);
|
|
293
|
+
}
|
|
294
|
+
break;
|
|
295
|
+
}
|
|
296
|
+
name += String.fromCodePoint(cp);
|
|
297
|
+
if (!escaped) this.pos += r.size;
|
|
298
|
+
first = false;
|
|
299
|
+
}
|
|
300
|
+
if (name.length === 0) throw this.errf("expected an object key");
|
|
301
|
+
return name;
|
|
302
|
+
}
|
|
303
|
+
/** Read exactly four hex digits at `pos` and return the code point. */
|
|
304
|
+
readHex4() {
|
|
305
|
+
if (this.pos + 4 > this.src.length) throw this.errf("truncated \\u escape");
|
|
306
|
+
const quad = this.src.slice(this.pos, this.pos + 4);
|
|
307
|
+
if (!/^[0-9a-fA-F]{4}$/.test(quad)) {
|
|
308
|
+
throw this.errf(`invalid \\u escape ${JSON.stringify("\\u" + quad)}`);
|
|
309
|
+
}
|
|
310
|
+
this.pos += 4;
|
|
311
|
+
return parseInt(quad, 16);
|
|
312
|
+
}
|
|
313
|
+
// ── Strings ─────────────────────────────────────────────────────────────────
|
|
314
|
+
/**
|
|
315
|
+
* Scan a single- or double-quoted JSON5 string. `quote` is the opening quote
|
|
316
|
+
* character. JSON5 differences from JSON: either quote character, `\xHH`
|
|
317
|
+
* escapes, `\v`, `\0`, line continuations (backslash before a line
|
|
318
|
+
* terminator, including CRLF as one), any other non-digit character escaping
|
|
319
|
+
* to itself, and unescaped LS/PS allowed inside the string.
|
|
320
|
+
*/
|
|
321
|
+
parseString(quote) {
|
|
322
|
+
this.pos++;
|
|
323
|
+
let out = "";
|
|
324
|
+
for (; ; ) {
|
|
325
|
+
if (this.pos >= this.src.length) throw this.errf("unterminated string");
|
|
326
|
+
const { cp, size } = this.rune();
|
|
327
|
+
if (this.src[this.pos] === quote) {
|
|
328
|
+
this.pos++;
|
|
329
|
+
return out;
|
|
330
|
+
}
|
|
331
|
+
if (cp === 10 || cp === 13) {
|
|
332
|
+
throw this.errf("unescaped line terminator in string");
|
|
333
|
+
}
|
|
334
|
+
if (cp === 92) {
|
|
335
|
+
this.pos++;
|
|
336
|
+
out += this.readEscape();
|
|
337
|
+
continue;
|
|
338
|
+
}
|
|
339
|
+
out += this.src.slice(this.pos, this.pos + size);
|
|
340
|
+
this.advance(cp, size);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
/**
|
|
344
|
+
* Consume one escape sequence (the backslash is already consumed) and return
|
|
345
|
+
* its value.
|
|
346
|
+
*/
|
|
347
|
+
readEscape() {
|
|
348
|
+
if (this.pos >= this.src.length) throw this.errf("unterminated escape sequence");
|
|
349
|
+
const { cp, size } = this.rune();
|
|
350
|
+
if (isLineTerminator(cp)) {
|
|
351
|
+
this.advance(cp, size);
|
|
352
|
+
return "";
|
|
353
|
+
}
|
|
354
|
+
const ch = String.fromCodePoint(cp);
|
|
355
|
+
switch (ch) {
|
|
356
|
+
case "n":
|
|
357
|
+
this.pos++;
|
|
358
|
+
return "\n";
|
|
359
|
+
case "t":
|
|
360
|
+
this.pos++;
|
|
361
|
+
return " ";
|
|
362
|
+
case "r":
|
|
363
|
+
this.pos++;
|
|
364
|
+
return "\r";
|
|
365
|
+
case "b":
|
|
366
|
+
this.pos++;
|
|
367
|
+
return "\b";
|
|
368
|
+
case "f":
|
|
369
|
+
this.pos++;
|
|
370
|
+
return "\f";
|
|
371
|
+
case "v":
|
|
372
|
+
this.pos++;
|
|
373
|
+
return "\v";
|
|
374
|
+
case "0": {
|
|
375
|
+
const next = this.src[this.pos + 1];
|
|
376
|
+
if (next !== void 0 && next >= "0" && next <= "9") {
|
|
377
|
+
throw this.errf("octal escape sequences are not allowed");
|
|
378
|
+
}
|
|
379
|
+
this.pos++;
|
|
380
|
+
return "\0";
|
|
381
|
+
}
|
|
382
|
+
case "1":
|
|
383
|
+
case "2":
|
|
384
|
+
case "3":
|
|
385
|
+
case "4":
|
|
386
|
+
case "5":
|
|
387
|
+
case "6":
|
|
388
|
+
case "7":
|
|
389
|
+
case "8":
|
|
390
|
+
case "9":
|
|
391
|
+
throw this.errf(`escape \\${ch} is not allowed (digits cannot be escaped)`);
|
|
392
|
+
case "x": {
|
|
393
|
+
this.pos++;
|
|
394
|
+
if (this.pos + 2 > this.src.length) throw this.errf("truncated \\x escape");
|
|
395
|
+
const hh = this.src.slice(this.pos, this.pos + 2);
|
|
396
|
+
if (!/^[0-9a-fA-F]{2}$/.test(hh)) throw this.errf("invalid \\x escape");
|
|
397
|
+
this.pos += 2;
|
|
398
|
+
return String.fromCharCode(parseInt(hh, 16));
|
|
399
|
+
}
|
|
400
|
+
case "u": {
|
|
401
|
+
this.pos++;
|
|
402
|
+
const hi = this.readHex4();
|
|
403
|
+
if (hi >= 55296 && hi <= 57343) {
|
|
404
|
+
if (this.pos + 6 <= this.src.length && this.src[this.pos] === "\\" && this.src[this.pos + 1] === "u") {
|
|
405
|
+
this.pos += 2;
|
|
406
|
+
const lo = this.readHex4();
|
|
407
|
+
if (hi <= 56319 && lo >= 56320 && lo <= 57343) {
|
|
408
|
+
return String.fromCodePoint(65536 + (hi - 55296 << 10) + (lo - 56320));
|
|
409
|
+
}
|
|
410
|
+
throw this.errf(`unpaired \\u${hex4(hi)} surrogate (spec F3.5)`);
|
|
411
|
+
}
|
|
412
|
+
throw this.errf(`unpaired \\u${hex4(hi)} surrogate (spec F3.5)`);
|
|
413
|
+
}
|
|
414
|
+
return String.fromCharCode(hi);
|
|
415
|
+
}
|
|
416
|
+
default:
|
|
417
|
+
this.advance(cp, size);
|
|
418
|
+
return ch;
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
// ── Numbers ─────────────────────────────────────────────────────────────────
|
|
422
|
+
/**
|
|
423
|
+
* Scan a JSON5 numeric literal: optional sign, then a hex integer or a
|
|
424
|
+
* decimal with optional leading/trailing point and exponent. Signed
|
|
425
|
+
* Infinity/NaN are routed to the F0.6 error here.
|
|
426
|
+
*/
|
|
427
|
+
parseNumber() {
|
|
428
|
+
const start = this.pos;
|
|
429
|
+
let neg = false;
|
|
430
|
+
const sign = this.src[this.pos];
|
|
431
|
+
if (sign === "+" || sign === "-") {
|
|
432
|
+
neg = sign === "-";
|
|
433
|
+
this.pos++;
|
|
434
|
+
}
|
|
435
|
+
const rest = this.src.slice(this.pos);
|
|
436
|
+
for (const kw of ["Infinity", "NaN"]) {
|
|
437
|
+
if (rest.startsWith(kw) && !continuesIdentifier(rest, kw.length)) {
|
|
438
|
+
throw this.errf(`${kw} is not representable in the HOCON number model (spec F0.6)`);
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
if (rest.startsWith("0x") || rest.startsWith("0X")) {
|
|
442
|
+
this.pos += 2;
|
|
443
|
+
const ds = this.pos;
|
|
444
|
+
while (this.pos < this.src.length && isHexDigit(this.src[this.pos])) this.pos++;
|
|
445
|
+
if (this.pos === ds) throw this.errf("hex literal needs at least one digit");
|
|
446
|
+
const mag = BigInt("0x" + this.src.slice(ds, this.pos));
|
|
447
|
+
const limit = neg ? 1n << 63n : (1n << 63n) - 1n;
|
|
448
|
+
if (mag > limit) {
|
|
449
|
+
throw this.errf(`integer ${this.src.slice(start, this.pos)} does not fit in int64 (spec F0.5)`);
|
|
450
|
+
}
|
|
451
|
+
if (neg && mag === 0n) return -0;
|
|
452
|
+
return integerValue(neg ? -mag : mag);
|
|
453
|
+
}
|
|
454
|
+
let sawDigit = false;
|
|
455
|
+
let sawDot = false;
|
|
456
|
+
let sawExp = false;
|
|
457
|
+
while (this.pos < this.src.length) {
|
|
458
|
+
const c = this.src[this.pos];
|
|
459
|
+
if (c >= "0" && c <= "9") {
|
|
460
|
+
sawDigit = true;
|
|
461
|
+
} else if (c === "." && !sawDot && !sawExp) {
|
|
462
|
+
sawDot = true;
|
|
463
|
+
} else if ((c === "e" || c === "E") && sawDigit && !sawExp) {
|
|
464
|
+
sawExp = true;
|
|
465
|
+
const n = this.src[this.pos + 1];
|
|
466
|
+
if (n === "+" || n === "-") this.pos++;
|
|
467
|
+
} else {
|
|
468
|
+
break;
|
|
469
|
+
}
|
|
470
|
+
this.pos++;
|
|
471
|
+
}
|
|
472
|
+
const text = this.src.slice(start, this.pos);
|
|
473
|
+
if (!sawDigit) throw this.errf(`malformed number ${JSON.stringify(text)}`);
|
|
474
|
+
if (sawDot || sawExp) {
|
|
475
|
+
const f = Number(text);
|
|
476
|
+
if (Number.isNaN(f) || !Number.isFinite(f)) {
|
|
477
|
+
throw this.errf(`malformed number ${JSON.stringify(text)}`);
|
|
478
|
+
}
|
|
479
|
+
return f;
|
|
480
|
+
}
|
|
481
|
+
const digits = text.startsWith("+") ? text.slice(1) : text;
|
|
482
|
+
const i = BigInt(digits);
|
|
483
|
+
if (i > INT64_MAX || i < INT64_MIN) {
|
|
484
|
+
throw this.errf(`integer ${text} does not fit in int64 (spec F0.5)`);
|
|
485
|
+
}
|
|
486
|
+
if (i >= -9007199254740991n && i <= 9007199254740991n) return Number(digits);
|
|
487
|
+
return i;
|
|
488
|
+
}
|
|
489
|
+
};
|
|
490
|
+
function integerValue(v) {
|
|
491
|
+
if (v >= -9007199254740991n && v <= 9007199254740991n) return Number(v);
|
|
492
|
+
return v;
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
|
|
496
|
+
exports.parseJson5 = parseJson5;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { C as Config } from '../config-OccaKqXu.cjs';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Read JSON5 (https://json5.org, spec 1.0.0) as HOCON config.
|
|
5
|
+
*
|
|
6
|
+
* Unlike the jsonc adapter — which strips comments and hands the rest to
|
|
7
|
+
* `JSON.parse` — JSON5 changes the token grammar itself (unquoted identifier
|
|
8
|
+
* keys, single-quoted strings with line continuations, hex integers, leading
|
|
9
|
+
* and trailing decimal points, an explicit plus sign), so this adapter is a
|
|
10
|
+
* hand-rolled scanner and recursive-descent parser. Zero dependencies, like
|
|
11
|
+
* every adapter in this package; it is a port of go.hocon's `adapters/json5`.
|
|
12
|
+
*
|
|
13
|
+
* The accepted grammar is JSON5 1.0.0 as defined by the reference
|
|
14
|
+
* implementation (the json5 npm package), the dialect owner this spec item
|
|
15
|
+
* tracks — the same ownership rule F3.2 applies to JSONC. That is why a `//`
|
|
16
|
+
* comment here ends at LS/PS as well as LF/CR, while the jsonc adapter's runs
|
|
17
|
+
* through them: each dialect's owner decides. Where the mapping spec is
|
|
18
|
+
* stricter than JSON5, the spec wins:
|
|
19
|
+
*
|
|
20
|
+
* - `Infinity` and `NaN` (signed or bare) are errors, not values (spec F0.6).
|
|
21
|
+
* - Integers — decimal or hex — must fit in int64 (spec F0.5); a number
|
|
22
|
+
* written with `.`, `e` or `E` is a float, all other decimal forms and
|
|
23
|
+
* every hex form are integers. An integer past 2^53 is carried as a
|
|
24
|
+
* `bigint` so its digits survive verbatim (`getString` returns them
|
|
25
|
+
* exactly); `getNumber` and `toObject` still apply the JS number model,
|
|
26
|
+
* as they do for HOCON's own literals.
|
|
27
|
+
* - An unpaired `\uXXXX` surrogate **escape** is an error, and a valid pair
|
|
28
|
+
* combines into the astral codepoint (spec F3.5). This deliberately
|
|
29
|
+
* differs from the jsonc adapter, which accepts one: there `JSON.parse` —
|
|
30
|
+
* the host language's own decoder — owns the escape, and refusing would be
|
|
31
|
+
* the spec overriding the platform (the S1.2.6 class). Here the scanner is
|
|
32
|
+
* ours, so the four implementations can and do agree. A lone surrogate
|
|
33
|
+
* *code unit* sitting raw in the source string is still accepted as data —
|
|
34
|
+
* a JavaScript string is UTF-16 and holds it natively; go.hocon's
|
|
35
|
+
* equivalent check rejects invalid UTF-8 bytes, a case that cannot arise
|
|
36
|
+
* in a JS string.
|
|
37
|
+
* - Duplicate keys follow HOCON semantics: objects merge, otherwise the
|
|
38
|
+
* later value wins (spec F0.7).
|
|
39
|
+
* - The document holds exactly one value; whitespace and comments may follow
|
|
40
|
+
* it, anything else is an error (the F3.2 strictness rule).
|
|
41
|
+
*
|
|
42
|
+
* See the F3.x items in the format-ingestion mapping spec:
|
|
43
|
+
* https://github.com/o3co/xx.hocon/blob/main/docs/format-ingestion-mapping.md
|
|
44
|
+
*/
|
|
45
|
+
declare function parseJson5(input: string, originDescription?: string): Config;
|
|
46
|
+
|
|
47
|
+
export { parseJson5 };
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { C as Config } from '../config-OccaKqXu.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Read JSON5 (https://json5.org, spec 1.0.0) as HOCON config.
|
|
5
|
+
*
|
|
6
|
+
* Unlike the jsonc adapter — which strips comments and hands the rest to
|
|
7
|
+
* `JSON.parse` — JSON5 changes the token grammar itself (unquoted identifier
|
|
8
|
+
* keys, single-quoted strings with line continuations, hex integers, leading
|
|
9
|
+
* and trailing decimal points, an explicit plus sign), so this adapter is a
|
|
10
|
+
* hand-rolled scanner and recursive-descent parser. Zero dependencies, like
|
|
11
|
+
* every adapter in this package; it is a port of go.hocon's `adapters/json5`.
|
|
12
|
+
*
|
|
13
|
+
* The accepted grammar is JSON5 1.0.0 as defined by the reference
|
|
14
|
+
* implementation (the json5 npm package), the dialect owner this spec item
|
|
15
|
+
* tracks — the same ownership rule F3.2 applies to JSONC. That is why a `//`
|
|
16
|
+
* comment here ends at LS/PS as well as LF/CR, while the jsonc adapter's runs
|
|
17
|
+
* through them: each dialect's owner decides. Where the mapping spec is
|
|
18
|
+
* stricter than JSON5, the spec wins:
|
|
19
|
+
*
|
|
20
|
+
* - `Infinity` and `NaN` (signed or bare) are errors, not values (spec F0.6).
|
|
21
|
+
* - Integers — decimal or hex — must fit in int64 (spec F0.5); a number
|
|
22
|
+
* written with `.`, `e` or `E` is a float, all other decimal forms and
|
|
23
|
+
* every hex form are integers. An integer past 2^53 is carried as a
|
|
24
|
+
* `bigint` so its digits survive verbatim (`getString` returns them
|
|
25
|
+
* exactly); `getNumber` and `toObject` still apply the JS number model,
|
|
26
|
+
* as they do for HOCON's own literals.
|
|
27
|
+
* - An unpaired `\uXXXX` surrogate **escape** is an error, and a valid pair
|
|
28
|
+
* combines into the astral codepoint (spec F3.5). This deliberately
|
|
29
|
+
* differs from the jsonc adapter, which accepts one: there `JSON.parse` —
|
|
30
|
+
* the host language's own decoder — owns the escape, and refusing would be
|
|
31
|
+
* the spec overriding the platform (the S1.2.6 class). Here the scanner is
|
|
32
|
+
* ours, so the four implementations can and do agree. A lone surrogate
|
|
33
|
+
* *code unit* sitting raw in the source string is still accepted as data —
|
|
34
|
+
* a JavaScript string is UTF-16 and holds it natively; go.hocon's
|
|
35
|
+
* equivalent check rejects invalid UTF-8 bytes, a case that cannot arise
|
|
36
|
+
* in a JS string.
|
|
37
|
+
* - Duplicate keys follow HOCON semantics: objects merge, otherwise the
|
|
38
|
+
* later value wins (spec F0.7).
|
|
39
|
+
* - The document holds exactly one value; whitespace and comments may follow
|
|
40
|
+
* it, anything else is an error (the F3.2 strictness rule).
|
|
41
|
+
*
|
|
42
|
+
* See the F3.x items in the format-ingestion mapping spec:
|
|
43
|
+
* https://github.com/o3co/xx.hocon/blob/main/docs/format-ingestion-mapping.md
|
|
44
|
+
*/
|
|
45
|
+
declare function parseJson5(input: string, originDescription?: string): Config;
|
|
46
|
+
|
|
47
|
+
export { parseJson5 };
|