@o3co/ts.hocon 1.9.0 → 1.10.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/dist/index.cjs CHANGED
@@ -1101,12 +1101,12 @@ function isDecimalDigit(ch) {
1101
1101
  }
1102
1102
  function isUnquotedStart(ch) {
1103
1103
  if (ch === "" || isHoconWhitespace(ch)) return false;
1104
- if ('{}[],:=+#"$?!@*&^\\'.includes(ch)) return false;
1104
+ if ('{}[],:=+#"$?!@*&^`\\'.includes(ch)) return false;
1105
1105
  return true;
1106
1106
  }
1107
1107
  function isUnquotedContinue(ch, nextFn) {
1108
1108
  if (ch === "" || isHoconWhitespace(ch)) return false;
1109
- if ('{}[],:=#"$?!@*&^\\'.includes(ch)) return false;
1109
+ if ('{}[],:=#"$?!@*&^`\\'.includes(ch)) return false;
1110
1110
  if (ch === "+" && nextFn() === "=") return false;
1111
1111
  if (ch === "/" && nextFn() === "/") return false;
1112
1112
  return true;
@@ -1255,6 +1255,17 @@ var Parser = class {
1255
1255
  this.advance();
1256
1256
  const raw = t.value.startsWith(".") && segments.length > 0 && !t.precedingSpace ? t.value.slice(1) : t.value;
1257
1257
  const parts = raw.split(".");
1258
+ const leadingDotIsSeparator = spaceConcat || postDotPrefix !== "";
1259
+ for (let i = 0; i < parts.length; i++) {
1260
+ if (parts[i] !== "") continue;
1261
+ if (i === parts.length - 1) continue;
1262
+ if (i === 0 && leadingDotIsSeparator) continue;
1263
+ throw new ParseError(
1264
+ `path has ${i === 0 ? "a leading period '.'" : "two adjacent periods '.'"} \u2014 empty key segment not allowed, use quoted "" (HOCON.md path rules)`,
1265
+ t.line,
1266
+ t.col
1267
+ );
1268
+ }
1258
1269
  const filtered = parts.filter((s) => s.length > 0);
1259
1270
  if (spaceConcat) {
1260
1271
  segments[segments.length - 1] = `${segments[segments.length - 1]}${t.precedingWhitespace}`;
@@ -1533,29 +1544,108 @@ function parseTokens(tokens) {
1533
1544
 
1534
1545
  // src/internal/properties/properties.ts
1535
1546
  function parseProperties(input) {
1536
- const root = /* @__PURE__ */ Object.create(null);
1537
1547
  const pairs = [];
1538
- for (const line of input.split("\n")) {
1539
- const trimmed = line.trim();
1540
- if (trimmed === "" || trimmed.startsWith("#") || trimmed.startsWith("!")) continue;
1541
- const sepIdx = findSeparator(trimmed);
1542
- if (sepIdx === -1) continue;
1543
- const key = trimmed.slice(0, sepIdx).trim();
1544
- const value = trimmed.slice(sepIdx + 1).trim();
1548
+ for (const { text, line } of logicalLines(input)) {
1549
+ const [rawKey, rawValue] = splitKeyValue(text);
1550
+ const key = unescapeProps(rawKey, line);
1545
1551
  if (key === "") continue;
1546
- pairs.push([key, value]);
1552
+ pairs.push([key, unescapeProps(rawValue, line)]);
1547
1553
  }
1548
- pairs.sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0);
1549
- for (const [key, value] of pairs) {
1554
+ return nestPairs(pairs);
1555
+ }
1556
+ function nestPairs(pairs) {
1557
+ const root = /* @__PURE__ */ Object.create(null);
1558
+ const sorted = [...pairs].sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0);
1559
+ for (const [key, value] of sorted) {
1550
1560
  setNested(root, key.split("."), value);
1551
1561
  }
1552
1562
  return root;
1553
1563
  }
1554
- function findSeparator(line) {
1555
- for (let i = 0; i < line.length; i++) {
1556
- if (line[i] === "=" || line[i] === ":") return i;
1564
+ function logicalLines(input) {
1565
+ const natural = input.replace(/\r\n/g, "\n").replace(/\r/g, "\n").split("\n");
1566
+ const out = [];
1567
+ for (let i = 0; i < natural.length; i++) {
1568
+ let text = trimLeadingSpace(natural[i] ?? "");
1569
+ if (text === "" || text.startsWith("#") || text.startsWith("!")) continue;
1570
+ const start = i + 1;
1571
+ while (endsWithContinuation(text)) {
1572
+ text = text.slice(0, -1);
1573
+ if (i + 1 >= natural.length) break;
1574
+ i++;
1575
+ text += trimLeadingSpace(natural[i] ?? "");
1576
+ }
1577
+ out.push({ text, line: start });
1578
+ }
1579
+ return out;
1580
+ }
1581
+ function trimLeadingSpace(s) {
1582
+ return s.replace(/^[ \t\f]+/, "");
1583
+ }
1584
+ function endsWithContinuation(line) {
1585
+ let n = 0;
1586
+ for (let i = line.length - 1; i >= 0 && line[i] === "\\"; i--) n++;
1587
+ return n % 2 === 1;
1588
+ }
1589
+ function splitKeyValue(line) {
1590
+ let key = "";
1591
+ let i = 0;
1592
+ for (; i < line.length; i++) {
1593
+ const c = line[i];
1594
+ if (c === "\\" && i + 1 < line.length) {
1595
+ key += c + line[i + 1];
1596
+ i++;
1597
+ continue;
1598
+ }
1599
+ if (c === "=" || c === ":" || isPropsSpace(c)) break;
1600
+ key += c;
1601
+ }
1602
+ while (i < line.length && isPropsSpace(line[i])) i++;
1603
+ if (i < line.length && (line[i] === "=" || line[i] === ":")) {
1604
+ i++;
1605
+ while (i < line.length && isPropsSpace(line[i])) i++;
1606
+ }
1607
+ return [key, line.slice(i)];
1608
+ }
1609
+ function isPropsSpace(c) {
1610
+ return c === " " || c === " " || c === "\f";
1611
+ }
1612
+ function unescapeProps(s, line) {
1613
+ let out = "";
1614
+ for (let i = 0; i < s.length; i++) {
1615
+ if (s[i] !== "\\") {
1616
+ out += s[i];
1617
+ continue;
1618
+ }
1619
+ i++;
1620
+ if (i >= s.length) break;
1621
+ const e = s[i];
1622
+ switch (e) {
1623
+ case "t":
1624
+ out += " ";
1625
+ break;
1626
+ case "n":
1627
+ out += "\n";
1628
+ break;
1629
+ case "r":
1630
+ out += "\r";
1631
+ break;
1632
+ case "f":
1633
+ out += "\f";
1634
+ break;
1635
+ case "u": {
1636
+ const hex = s.slice(i + 1, i + 5);
1637
+ if (!/^[0-9a-fA-F]{4}$/.test(hex)) {
1638
+ throw new ParseError(`malformed \\u escape in .properties: \\u${hex}`, line, i + 1);
1639
+ }
1640
+ out += String.fromCharCode(parseInt(hex, 16));
1641
+ i += 4;
1642
+ break;
1643
+ }
1644
+ default:
1645
+ out += e;
1646
+ }
1557
1647
  }
1558
- return -1;
1648
+ return out;
1559
1649
  }
1560
1650
  var DANGEROUS_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
1561
1651
  function setNested(obj, segments, value) {
package/dist/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
- import { C as Config } from './config-D27s3_aG.cjs';
2
- export { B as ByteUnit, D as DurationUnit, H as HoconValue, P as PackageResolver, a as ParseOptions, R as ReadonlyHoconValue, b as ResolveOptions, S as ScalarValueType, c as asArray, d as asBoolean, e as asNumber, f as asObject, g as asString, h as defaultParseOptions, i as defaultResolveOptions, j as isArray, k as isNull, l as isObject, m as isScalar, p as parse, n as parseAsync, o as parseFile, q as parseFileAsync, r as parseFileWithOptions, s as parseString, t as parseStringWithOptions } from './config-D27s3_aG.cjs';
1
+ import { C as Config } from './config-PdhVgeLS.cjs';
2
+ export { B as ByteUnit, D as DurationUnit, H as HoconValue, P as PackageResolver, a as ParseOptions, R as ReadonlyHoconValue, b as ResolveOptions, S as ScalarValueType, c as asArray, d as asBoolean, e as asNumber, f as asObject, g as asString, h as defaultParseOptions, i as defaultResolveOptions, j as isArray, k as isNull, l as isObject, m as isScalar, p as parse, n as parseAsync, o as parseFile, q as parseFileAsync, r as parseFileWithOptions, s as parseString, t as parseStringWithOptions } from './config-PdhVgeLS.cjs';
3
3
 
4
4
  declare class ParseError extends Error {
5
5
  readonly line: number;
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { C as Config } from './config-D27s3_aG.js';
2
- export { B as ByteUnit, D as DurationUnit, H as HoconValue, P as PackageResolver, a as ParseOptions, R as ReadonlyHoconValue, b as ResolveOptions, S as ScalarValueType, c as asArray, d as asBoolean, e as asNumber, f as asObject, g as asString, h as defaultParseOptions, i as defaultResolveOptions, j as isArray, k as isNull, l as isObject, m as isScalar, p as parse, n as parseAsync, o as parseFile, q as parseFileAsync, r as parseFileWithOptions, s as parseString, t as parseStringWithOptions } from './config-D27s3_aG.js';
1
+ import { C as Config } from './config-PdhVgeLS.js';
2
+ export { B as ByteUnit, D as DurationUnit, H as HoconValue, P as PackageResolver, a as ParseOptions, R as ReadonlyHoconValue, b as ResolveOptions, S as ScalarValueType, c as asArray, d as asBoolean, e as asNumber, f as asObject, g as asString, h as defaultParseOptions, i as defaultResolveOptions, j as isArray, k as isNull, l as isObject, m as isScalar, p as parse, n as parseAsync, o as parseFile, q as parseFileAsync, r as parseFileWithOptions, s as parseString, t as parseStringWithOptions } from './config-PdhVgeLS.js';
3
3
 
4
4
  declare class ParseError extends Error {
5
5
  readonly line: number;
package/dist/index.js CHANGED
@@ -1040,12 +1040,12 @@ function isDecimalDigit(ch) {
1040
1040
  }
1041
1041
  function isUnquotedStart(ch) {
1042
1042
  if (ch === "" || isHoconWhitespace(ch)) return false;
1043
- if ('{}[],:=+#"$?!@*&^\\'.includes(ch)) return false;
1043
+ if ('{}[],:=+#"$?!@*&^`\\'.includes(ch)) return false;
1044
1044
  return true;
1045
1045
  }
1046
1046
  function isUnquotedContinue(ch, nextFn) {
1047
1047
  if (ch === "" || isHoconWhitespace(ch)) return false;
1048
- if ('{}[],:=#"$?!@*&^\\'.includes(ch)) return false;
1048
+ if ('{}[],:=#"$?!@*&^`\\'.includes(ch)) return false;
1049
1049
  if (ch === "+" && nextFn() === "=") return false;
1050
1050
  if (ch === "/" && nextFn() === "/") return false;
1051
1051
  return true;
@@ -1194,6 +1194,17 @@ var Parser = class {
1194
1194
  this.advance();
1195
1195
  const raw = t.value.startsWith(".") && segments.length > 0 && !t.precedingSpace ? t.value.slice(1) : t.value;
1196
1196
  const parts = raw.split(".");
1197
+ const leadingDotIsSeparator = spaceConcat || postDotPrefix !== "";
1198
+ for (let i = 0; i < parts.length; i++) {
1199
+ if (parts[i] !== "") continue;
1200
+ if (i === parts.length - 1) continue;
1201
+ if (i === 0 && leadingDotIsSeparator) continue;
1202
+ throw new ParseError(
1203
+ `path has ${i === 0 ? "a leading period '.'" : "two adjacent periods '.'"} \u2014 empty key segment not allowed, use quoted "" (HOCON.md path rules)`,
1204
+ t.line,
1205
+ t.col
1206
+ );
1207
+ }
1197
1208
  const filtered = parts.filter((s) => s.length > 0);
1198
1209
  if (spaceConcat) {
1199
1210
  segments[segments.length - 1] = `${segments[segments.length - 1]}${t.precedingWhitespace}`;
@@ -1472,29 +1483,108 @@ function parseTokens(tokens) {
1472
1483
 
1473
1484
  // src/internal/properties/properties.ts
1474
1485
  function parseProperties(input) {
1475
- const root = /* @__PURE__ */ Object.create(null);
1476
1486
  const pairs = [];
1477
- for (const line of input.split("\n")) {
1478
- const trimmed = line.trim();
1479
- if (trimmed === "" || trimmed.startsWith("#") || trimmed.startsWith("!")) continue;
1480
- const sepIdx = findSeparator(trimmed);
1481
- if (sepIdx === -1) continue;
1482
- const key = trimmed.slice(0, sepIdx).trim();
1483
- const value = trimmed.slice(sepIdx + 1).trim();
1487
+ for (const { text, line } of logicalLines(input)) {
1488
+ const [rawKey, rawValue] = splitKeyValue(text);
1489
+ const key = unescapeProps(rawKey, line);
1484
1490
  if (key === "") continue;
1485
- pairs.push([key, value]);
1491
+ pairs.push([key, unescapeProps(rawValue, line)]);
1486
1492
  }
1487
- pairs.sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0);
1488
- for (const [key, value] of pairs) {
1493
+ return nestPairs(pairs);
1494
+ }
1495
+ function nestPairs(pairs) {
1496
+ const root = /* @__PURE__ */ Object.create(null);
1497
+ const sorted = [...pairs].sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0);
1498
+ for (const [key, value] of sorted) {
1489
1499
  setNested(root, key.split("."), value);
1490
1500
  }
1491
1501
  return root;
1492
1502
  }
1493
- function findSeparator(line) {
1494
- for (let i = 0; i < line.length; i++) {
1495
- if (line[i] === "=" || line[i] === ":") return i;
1503
+ function logicalLines(input) {
1504
+ const natural = input.replace(/\r\n/g, "\n").replace(/\r/g, "\n").split("\n");
1505
+ const out = [];
1506
+ for (let i = 0; i < natural.length; i++) {
1507
+ let text = trimLeadingSpace(natural[i] ?? "");
1508
+ if (text === "" || text.startsWith("#") || text.startsWith("!")) continue;
1509
+ const start = i + 1;
1510
+ while (endsWithContinuation(text)) {
1511
+ text = text.slice(0, -1);
1512
+ if (i + 1 >= natural.length) break;
1513
+ i++;
1514
+ text += trimLeadingSpace(natural[i] ?? "");
1515
+ }
1516
+ out.push({ text, line: start });
1517
+ }
1518
+ return out;
1519
+ }
1520
+ function trimLeadingSpace(s) {
1521
+ return s.replace(/^[ \t\f]+/, "");
1522
+ }
1523
+ function endsWithContinuation(line) {
1524
+ let n = 0;
1525
+ for (let i = line.length - 1; i >= 0 && line[i] === "\\"; i--) n++;
1526
+ return n % 2 === 1;
1527
+ }
1528
+ function splitKeyValue(line) {
1529
+ let key = "";
1530
+ let i = 0;
1531
+ for (; i < line.length; i++) {
1532
+ const c = line[i];
1533
+ if (c === "\\" && i + 1 < line.length) {
1534
+ key += c + line[i + 1];
1535
+ i++;
1536
+ continue;
1537
+ }
1538
+ if (c === "=" || c === ":" || isPropsSpace(c)) break;
1539
+ key += c;
1540
+ }
1541
+ while (i < line.length && isPropsSpace(line[i])) i++;
1542
+ if (i < line.length && (line[i] === "=" || line[i] === ":")) {
1543
+ i++;
1544
+ while (i < line.length && isPropsSpace(line[i])) i++;
1545
+ }
1546
+ return [key, line.slice(i)];
1547
+ }
1548
+ function isPropsSpace(c) {
1549
+ return c === " " || c === " " || c === "\f";
1550
+ }
1551
+ function unescapeProps(s, line) {
1552
+ let out = "";
1553
+ for (let i = 0; i < s.length; i++) {
1554
+ if (s[i] !== "\\") {
1555
+ out += s[i];
1556
+ continue;
1557
+ }
1558
+ i++;
1559
+ if (i >= s.length) break;
1560
+ const e = s[i];
1561
+ switch (e) {
1562
+ case "t":
1563
+ out += " ";
1564
+ break;
1565
+ case "n":
1566
+ out += "\n";
1567
+ break;
1568
+ case "r":
1569
+ out += "\r";
1570
+ break;
1571
+ case "f":
1572
+ out += "\f";
1573
+ break;
1574
+ case "u": {
1575
+ const hex = s.slice(i + 1, i + 5);
1576
+ if (!/^[0-9a-fA-F]{4}$/.test(hex)) {
1577
+ throw new ParseError(`malformed \\u escape in .properties: \\u${hex}`, line, i + 1);
1578
+ }
1579
+ out += String.fromCharCode(parseInt(hex, 16));
1580
+ i += 4;
1581
+ break;
1582
+ }
1583
+ default:
1584
+ out += e;
1585
+ }
1496
1586
  }
1497
- return -1;
1587
+ return out;
1498
1588
  }
1499
1589
  var DANGEROUS_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
1500
1590
  function setNested(obj, segments, value) {
package/dist/zod.cjs CHANGED
@@ -1083,12 +1083,12 @@ function isDecimalDigit(ch) {
1083
1083
  }
1084
1084
  function isUnquotedStart(ch) {
1085
1085
  if (ch === "" || isHoconWhitespace(ch)) return false;
1086
- if ('{}[],:=+#"$?!@*&^\\'.includes(ch)) return false;
1086
+ if ('{}[],:=+#"$?!@*&^`\\'.includes(ch)) return false;
1087
1087
  return true;
1088
1088
  }
1089
1089
  function isUnquotedContinue(ch, nextFn) {
1090
1090
  if (ch === "" || isHoconWhitespace(ch)) return false;
1091
- if ('{}[],:=#"$?!@*&^\\'.includes(ch)) return false;
1091
+ if ('{}[],:=#"$?!@*&^`\\'.includes(ch)) return false;
1092
1092
  if (ch === "+" && nextFn() === "=") return false;
1093
1093
  if (ch === "/" && nextFn() === "/") return false;
1094
1094
  return true;
@@ -1237,6 +1237,17 @@ var Parser = class {
1237
1237
  this.advance();
1238
1238
  const raw = t.value.startsWith(".") && segments.length > 0 && !t.precedingSpace ? t.value.slice(1) : t.value;
1239
1239
  const parts = raw.split(".");
1240
+ const leadingDotIsSeparator = spaceConcat || postDotPrefix !== "";
1241
+ for (let i = 0; i < parts.length; i++) {
1242
+ if (parts[i] !== "") continue;
1243
+ if (i === parts.length - 1) continue;
1244
+ if (i === 0 && leadingDotIsSeparator) continue;
1245
+ throw new ParseError(
1246
+ `path has ${i === 0 ? "a leading period '.'" : "two adjacent periods '.'"} \u2014 empty key segment not allowed, use quoted "" (HOCON.md path rules)`,
1247
+ t.line,
1248
+ t.col
1249
+ );
1250
+ }
1240
1251
  const filtered = parts.filter((s) => s.length > 0);
1241
1252
  if (spaceConcat) {
1242
1253
  segments[segments.length - 1] = `${segments[segments.length - 1]}${t.precedingWhitespace}`;
@@ -1515,29 +1526,108 @@ function parseTokens(tokens) {
1515
1526
 
1516
1527
  // src/internal/properties/properties.ts
1517
1528
  function parseProperties(input) {
1518
- const root = /* @__PURE__ */ Object.create(null);
1519
1529
  const pairs = [];
1520
- for (const line of input.split("\n")) {
1521
- const trimmed = line.trim();
1522
- if (trimmed === "" || trimmed.startsWith("#") || trimmed.startsWith("!")) continue;
1523
- const sepIdx = findSeparator(trimmed);
1524
- if (sepIdx === -1) continue;
1525
- const key = trimmed.slice(0, sepIdx).trim();
1526
- const value = trimmed.slice(sepIdx + 1).trim();
1530
+ for (const { text, line } of logicalLines(input)) {
1531
+ const [rawKey, rawValue] = splitKeyValue(text);
1532
+ const key = unescapeProps(rawKey, line);
1527
1533
  if (key === "") continue;
1528
- pairs.push([key, value]);
1534
+ pairs.push([key, unescapeProps(rawValue, line)]);
1529
1535
  }
1530
- pairs.sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0);
1531
- for (const [key, value] of pairs) {
1536
+ return nestPairs(pairs);
1537
+ }
1538
+ function nestPairs(pairs) {
1539
+ const root = /* @__PURE__ */ Object.create(null);
1540
+ const sorted = [...pairs].sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0);
1541
+ for (const [key, value] of sorted) {
1532
1542
  setNested(root, key.split("."), value);
1533
1543
  }
1534
1544
  return root;
1535
1545
  }
1536
- function findSeparator(line) {
1537
- for (let i = 0; i < line.length; i++) {
1538
- if (line[i] === "=" || line[i] === ":") return i;
1546
+ function logicalLines(input) {
1547
+ const natural = input.replace(/\r\n/g, "\n").replace(/\r/g, "\n").split("\n");
1548
+ const out = [];
1549
+ for (let i = 0; i < natural.length; i++) {
1550
+ let text = trimLeadingSpace(natural[i] ?? "");
1551
+ if (text === "" || text.startsWith("#") || text.startsWith("!")) continue;
1552
+ const start = i + 1;
1553
+ while (endsWithContinuation(text)) {
1554
+ text = text.slice(0, -1);
1555
+ if (i + 1 >= natural.length) break;
1556
+ i++;
1557
+ text += trimLeadingSpace(natural[i] ?? "");
1558
+ }
1559
+ out.push({ text, line: start });
1560
+ }
1561
+ return out;
1562
+ }
1563
+ function trimLeadingSpace(s) {
1564
+ return s.replace(/^[ \t\f]+/, "");
1565
+ }
1566
+ function endsWithContinuation(line) {
1567
+ let n = 0;
1568
+ for (let i = line.length - 1; i >= 0 && line[i] === "\\"; i--) n++;
1569
+ return n % 2 === 1;
1570
+ }
1571
+ function splitKeyValue(line) {
1572
+ let key = "";
1573
+ let i = 0;
1574
+ for (; i < line.length; i++) {
1575
+ const c = line[i];
1576
+ if (c === "\\" && i + 1 < line.length) {
1577
+ key += c + line[i + 1];
1578
+ i++;
1579
+ continue;
1580
+ }
1581
+ if (c === "=" || c === ":" || isPropsSpace(c)) break;
1582
+ key += c;
1583
+ }
1584
+ while (i < line.length && isPropsSpace(line[i])) i++;
1585
+ if (i < line.length && (line[i] === "=" || line[i] === ":")) {
1586
+ i++;
1587
+ while (i < line.length && isPropsSpace(line[i])) i++;
1588
+ }
1589
+ return [key, line.slice(i)];
1590
+ }
1591
+ function isPropsSpace(c) {
1592
+ return c === " " || c === " " || c === "\f";
1593
+ }
1594
+ function unescapeProps(s, line) {
1595
+ let out = "";
1596
+ for (let i = 0; i < s.length; i++) {
1597
+ if (s[i] !== "\\") {
1598
+ out += s[i];
1599
+ continue;
1600
+ }
1601
+ i++;
1602
+ if (i >= s.length) break;
1603
+ const e = s[i];
1604
+ switch (e) {
1605
+ case "t":
1606
+ out += " ";
1607
+ break;
1608
+ case "n":
1609
+ out += "\n";
1610
+ break;
1611
+ case "r":
1612
+ out += "\r";
1613
+ break;
1614
+ case "f":
1615
+ out += "\f";
1616
+ break;
1617
+ case "u": {
1618
+ const hex = s.slice(i + 1, i + 5);
1619
+ if (!/^[0-9a-fA-F]{4}$/.test(hex)) {
1620
+ throw new ParseError(`malformed \\u escape in .properties: \\u${hex}`, line, i + 1);
1621
+ }
1622
+ out += String.fromCharCode(parseInt(hex, 16));
1623
+ i += 4;
1624
+ break;
1625
+ }
1626
+ default:
1627
+ out += e;
1628
+ }
1539
1629
  }
1540
- return -1;
1630
+ return out;
1541
1631
  }
1542
1632
  var DANGEROUS_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
1543
1633
  function setNested(obj, segments, value) {
package/dist/zod.d.cts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { ZodType } from 'zod';
2
- import { C as Config, a as ParseOptions } from './config-D27s3_aG.cjs';
2
+ import { C as Config, a as ParseOptions } from './config-PdhVgeLS.cjs';
3
3
 
4
4
  declare function validate<T>(config: Config, schema: ZodType<T>): T;
5
5
  declare function getValidated<T>(config: Config, path: string, schema: ZodType<T>): T;
package/dist/zod.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { ZodType } from 'zod';
2
- import { C as Config, a as ParseOptions } from './config-D27s3_aG.js';
2
+ import { C as Config, a as ParseOptions } from './config-PdhVgeLS.js';
3
3
 
4
4
  declare function validate<T>(config: Config, schema: ZodType<T>): T;
5
5
  declare function getValidated<T>(config: Config, path: string, schema: ZodType<T>): T;
package/dist/zod.js CHANGED
@@ -1044,12 +1044,12 @@ function isDecimalDigit(ch) {
1044
1044
  }
1045
1045
  function isUnquotedStart(ch) {
1046
1046
  if (ch === "" || isHoconWhitespace(ch)) return false;
1047
- if ('{}[],:=+#"$?!@*&^\\'.includes(ch)) return false;
1047
+ if ('{}[],:=+#"$?!@*&^`\\'.includes(ch)) return false;
1048
1048
  return true;
1049
1049
  }
1050
1050
  function isUnquotedContinue(ch, nextFn) {
1051
1051
  if (ch === "" || isHoconWhitespace(ch)) return false;
1052
- if ('{}[],:=#"$?!@*&^\\'.includes(ch)) return false;
1052
+ if ('{}[],:=#"$?!@*&^`\\'.includes(ch)) return false;
1053
1053
  if (ch === "+" && nextFn() === "=") return false;
1054
1054
  if (ch === "/" && nextFn() === "/") return false;
1055
1055
  return true;
@@ -1198,6 +1198,17 @@ var Parser = class {
1198
1198
  this.advance();
1199
1199
  const raw = t.value.startsWith(".") && segments.length > 0 && !t.precedingSpace ? t.value.slice(1) : t.value;
1200
1200
  const parts = raw.split(".");
1201
+ const leadingDotIsSeparator = spaceConcat || postDotPrefix !== "";
1202
+ for (let i = 0; i < parts.length; i++) {
1203
+ if (parts[i] !== "") continue;
1204
+ if (i === parts.length - 1) continue;
1205
+ if (i === 0 && leadingDotIsSeparator) continue;
1206
+ throw new ParseError(
1207
+ `path has ${i === 0 ? "a leading period '.'" : "two adjacent periods '.'"} \u2014 empty key segment not allowed, use quoted "" (HOCON.md path rules)`,
1208
+ t.line,
1209
+ t.col
1210
+ );
1211
+ }
1201
1212
  const filtered = parts.filter((s) => s.length > 0);
1202
1213
  if (spaceConcat) {
1203
1214
  segments[segments.length - 1] = `${segments[segments.length - 1]}${t.precedingWhitespace}`;
@@ -1476,29 +1487,108 @@ function parseTokens(tokens) {
1476
1487
 
1477
1488
  // src/internal/properties/properties.ts
1478
1489
  function parseProperties(input) {
1479
- const root = /* @__PURE__ */ Object.create(null);
1480
1490
  const pairs = [];
1481
- for (const line of input.split("\n")) {
1482
- const trimmed = line.trim();
1483
- if (trimmed === "" || trimmed.startsWith("#") || trimmed.startsWith("!")) continue;
1484
- const sepIdx = findSeparator(trimmed);
1485
- if (sepIdx === -1) continue;
1486
- const key = trimmed.slice(0, sepIdx).trim();
1487
- const value = trimmed.slice(sepIdx + 1).trim();
1491
+ for (const { text, line } of logicalLines(input)) {
1492
+ const [rawKey, rawValue] = splitKeyValue(text);
1493
+ const key = unescapeProps(rawKey, line);
1488
1494
  if (key === "") continue;
1489
- pairs.push([key, value]);
1495
+ pairs.push([key, unescapeProps(rawValue, line)]);
1490
1496
  }
1491
- pairs.sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0);
1492
- for (const [key, value] of pairs) {
1497
+ return nestPairs(pairs);
1498
+ }
1499
+ function nestPairs(pairs) {
1500
+ const root = /* @__PURE__ */ Object.create(null);
1501
+ const sorted = [...pairs].sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0);
1502
+ for (const [key, value] of sorted) {
1493
1503
  setNested(root, key.split("."), value);
1494
1504
  }
1495
1505
  return root;
1496
1506
  }
1497
- function findSeparator(line) {
1498
- for (let i = 0; i < line.length; i++) {
1499
- if (line[i] === "=" || line[i] === ":") return i;
1507
+ function logicalLines(input) {
1508
+ const natural = input.replace(/\r\n/g, "\n").replace(/\r/g, "\n").split("\n");
1509
+ const out = [];
1510
+ for (let i = 0; i < natural.length; i++) {
1511
+ let text = trimLeadingSpace(natural[i] ?? "");
1512
+ if (text === "" || text.startsWith("#") || text.startsWith("!")) continue;
1513
+ const start = i + 1;
1514
+ while (endsWithContinuation(text)) {
1515
+ text = text.slice(0, -1);
1516
+ if (i + 1 >= natural.length) break;
1517
+ i++;
1518
+ text += trimLeadingSpace(natural[i] ?? "");
1519
+ }
1520
+ out.push({ text, line: start });
1521
+ }
1522
+ return out;
1523
+ }
1524
+ function trimLeadingSpace(s) {
1525
+ return s.replace(/^[ \t\f]+/, "");
1526
+ }
1527
+ function endsWithContinuation(line) {
1528
+ let n = 0;
1529
+ for (let i = line.length - 1; i >= 0 && line[i] === "\\"; i--) n++;
1530
+ return n % 2 === 1;
1531
+ }
1532
+ function splitKeyValue(line) {
1533
+ let key = "";
1534
+ let i = 0;
1535
+ for (; i < line.length; i++) {
1536
+ const c = line[i];
1537
+ if (c === "\\" && i + 1 < line.length) {
1538
+ key += c + line[i + 1];
1539
+ i++;
1540
+ continue;
1541
+ }
1542
+ if (c === "=" || c === ":" || isPropsSpace(c)) break;
1543
+ key += c;
1544
+ }
1545
+ while (i < line.length && isPropsSpace(line[i])) i++;
1546
+ if (i < line.length && (line[i] === "=" || line[i] === ":")) {
1547
+ i++;
1548
+ while (i < line.length && isPropsSpace(line[i])) i++;
1549
+ }
1550
+ return [key, line.slice(i)];
1551
+ }
1552
+ function isPropsSpace(c) {
1553
+ return c === " " || c === " " || c === "\f";
1554
+ }
1555
+ function unescapeProps(s, line) {
1556
+ let out = "";
1557
+ for (let i = 0; i < s.length; i++) {
1558
+ if (s[i] !== "\\") {
1559
+ out += s[i];
1560
+ continue;
1561
+ }
1562
+ i++;
1563
+ if (i >= s.length) break;
1564
+ const e = s[i];
1565
+ switch (e) {
1566
+ case "t":
1567
+ out += " ";
1568
+ break;
1569
+ case "n":
1570
+ out += "\n";
1571
+ break;
1572
+ case "r":
1573
+ out += "\r";
1574
+ break;
1575
+ case "f":
1576
+ out += "\f";
1577
+ break;
1578
+ case "u": {
1579
+ const hex = s.slice(i + 1, i + 5);
1580
+ if (!/^[0-9a-fA-F]{4}$/.test(hex)) {
1581
+ throw new ParseError(`malformed \\u escape in .properties: \\u${hex}`, line, i + 1);
1582
+ }
1583
+ out += String.fromCharCode(parseInt(hex, 16));
1584
+ i += 4;
1585
+ break;
1586
+ }
1587
+ default:
1588
+ out += e;
1589
+ }
1500
1590
  }
1501
- return -1;
1591
+ return out;
1502
1592
  }
1503
1593
  var DANGEROUS_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
1504
1594
  function setNested(obj, segments, value) {