@spintax/core 0.8.0 → 0.9.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/CHANGELOG.md +74 -0
- package/dist/index.cjs +76 -35
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +76 -35
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1098,11 +1098,12 @@ function checkVariableReferences(text, idx, known, out) {
|
|
|
1098
1098
|
refsOf.set(name, refs);
|
|
1099
1099
|
}
|
|
1100
1100
|
const { reaches: reachesCycle, via } = namesThatReachACycle(defs, refsOf);
|
|
1101
|
+
const lengths = routeLengths(via);
|
|
1101
1102
|
for (const name of defs.keys()) {
|
|
1102
1103
|
if (!reachesCycle.has(name)) continue;
|
|
1103
1104
|
out.push(err(
|
|
1104
1105
|
"variable.circular-reference",
|
|
1105
|
-
`Circular variable reference: ${cyclePath(name, via)}.`,
|
|
1106
|
+
`Circular variable reference: ${cyclePath(name, via, lengths)}.`,
|
|
1106
1107
|
{ ...defPos.get(name) ?? somewhere, data: { name } }
|
|
1107
1108
|
));
|
|
1108
1109
|
}
|
|
@@ -1162,7 +1163,7 @@ function namesThatReachACycle(defs, refsOf) {
|
|
|
1162
1163
|
return { reaches, via };
|
|
1163
1164
|
}
|
|
1164
1165
|
var CYCLE_PATH_LIMIT = 8;
|
|
1165
|
-
function cyclePath(name, via) {
|
|
1166
|
+
function cyclePath(name, via, lengths) {
|
|
1166
1167
|
const seen = /* @__PURE__ */ new Set([name]);
|
|
1167
1168
|
const shown = [name];
|
|
1168
1169
|
let current = name;
|
|
@@ -1174,16 +1175,7 @@ function cyclePath(name, via) {
|
|
|
1174
1175
|
return shown.join(" \u2192 ");
|
|
1175
1176
|
}
|
|
1176
1177
|
if (shown.length >= CYCLE_PATH_LIMIT) {
|
|
1177
|
-
|
|
1178
|
-
let walk2 = next;
|
|
1179
|
-
while (!seen.has(walk2)) {
|
|
1180
|
-
seen.add(walk2);
|
|
1181
|
-
more += 1;
|
|
1182
|
-
const step = via.get(walk2);
|
|
1183
|
-
if (step === void 0) break;
|
|
1184
|
-
walk2 = step;
|
|
1185
|
-
}
|
|
1186
|
-
return `${shown.join(" \u2192 ")} \u2192 \u2026 (${more} more)`;
|
|
1178
|
+
return `${shown.join(" \u2192 ")} \u2192 \u2026 (${lengths.get(name) - shown.length} more)`;
|
|
1187
1179
|
}
|
|
1188
1180
|
seen.add(next);
|
|
1189
1181
|
shown.push(next);
|
|
@@ -1191,6 +1183,33 @@ function cyclePath(name, via) {
|
|
|
1191
1183
|
}
|
|
1192
1184
|
return shown.join(" \u2192 ");
|
|
1193
1185
|
}
|
|
1186
|
+
function routeLengths(via) {
|
|
1187
|
+
const lengths = /* @__PURE__ */ new Map();
|
|
1188
|
+
for (const start of via.keys()) {
|
|
1189
|
+
if (lengths.has(start)) continue;
|
|
1190
|
+
const walk2 = [];
|
|
1191
|
+
const onWalk = /* @__PURE__ */ new Map();
|
|
1192
|
+
let node = start;
|
|
1193
|
+
while (node !== void 0 && !lengths.has(node) && !onWalk.has(node)) {
|
|
1194
|
+
onWalk.set(node, walk2.length);
|
|
1195
|
+
walk2.push(node);
|
|
1196
|
+
node = via.get(node);
|
|
1197
|
+
}
|
|
1198
|
+
let tailEnd = walk2.length;
|
|
1199
|
+
let length = node === void 0 ? 0 : lengths.get(node) ?? 0;
|
|
1200
|
+
if (node !== void 0 && onWalk.has(node)) {
|
|
1201
|
+
const from = onWalk.get(node);
|
|
1202
|
+
length = walk2.length - from;
|
|
1203
|
+
for (let k = from; k < walk2.length; k += 1) lengths.set(walk2[k], length);
|
|
1204
|
+
tailEnd = from;
|
|
1205
|
+
}
|
|
1206
|
+
for (let k = tailEnd - 1; k >= 0; k -= 1) {
|
|
1207
|
+
length += 1;
|
|
1208
|
+
lengths.set(walk2[k], length);
|
|
1209
|
+
}
|
|
1210
|
+
}
|
|
1211
|
+
return lengths;
|
|
1212
|
+
}
|
|
1194
1213
|
function checkIncludeTargets(text, idx, known, out) {
|
|
1195
1214
|
const set = new Set(known);
|
|
1196
1215
|
INCLUDE_RE.lastIndex = 0;
|
|
@@ -1442,42 +1461,61 @@ function rollDefinitions(defDefs, vars, context, opts) {
|
|
|
1442
1461
|
if (name in definitions && !outranked.has(name)) continue;
|
|
1443
1462
|
aliases[name] = value;
|
|
1444
1463
|
}
|
|
1464
|
+
const visible = nameMap(vars);
|
|
1445
1465
|
for (const name of orderDefinitions(definitions, aliases)) {
|
|
1446
1466
|
if (outranked.has(name)) continue;
|
|
1447
|
-
const value = definitions[name] ?? "";
|
|
1448
|
-
rolled[name] =
|
|
1467
|
+
const value = renderNodes(parseSequence(definitions[name] ?? ""), { ...opts, vars: visible });
|
|
1468
|
+
rolled[name] = value;
|
|
1469
|
+
visible[name] = value;
|
|
1470
|
+
truthinessByVars.delete(visible);
|
|
1449
1471
|
}
|
|
1450
1472
|
return rolled;
|
|
1451
1473
|
}
|
|
1452
1474
|
function orderDefinitions(defDefs, aliases) {
|
|
1453
1475
|
const names = Object.keys(defDefs);
|
|
1454
|
-
const
|
|
1476
|
+
const position = new Map(names.map((name, i) => [name, i]));
|
|
1477
|
+
const unplaced = /* @__PURE__ */ new Map();
|
|
1478
|
+
const waitingOn = /* @__PURE__ */ new Map();
|
|
1455
1479
|
for (const name of names) {
|
|
1456
|
-
|
|
1457
|
-
|
|
1480
|
+
let count = 0;
|
|
1481
|
+
for (const dep of referencedNames(defDefs[name] ?? "", aliases)) {
|
|
1482
|
+
if (dep === name || !position.has(dep)) continue;
|
|
1483
|
+
count += 1;
|
|
1484
|
+
const waiting = waitingOn.get(dep);
|
|
1485
|
+
if (waiting === void 0) waitingOn.set(dep, [name]);
|
|
1486
|
+
else waiting.push(name);
|
|
1487
|
+
}
|
|
1488
|
+
unplaced.set(name, count);
|
|
1458
1489
|
}
|
|
1459
1490
|
const ordered = [];
|
|
1460
|
-
let
|
|
1461
|
-
while (
|
|
1462
|
-
const
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1491
|
+
let round = names.filter((name) => unplaced.get(name) === 0);
|
|
1492
|
+
while (round.length > 0) {
|
|
1493
|
+
const next = [];
|
|
1494
|
+
for (const name of round) {
|
|
1495
|
+
ordered.push(name);
|
|
1496
|
+
for (const waiting of waitingOn.get(name) ?? []) {
|
|
1497
|
+
const left = unplaced.get(waiting) - 1;
|
|
1498
|
+
unplaced.set(waiting, left);
|
|
1499
|
+
if (left === 0) next.push(waiting);
|
|
1500
|
+
}
|
|
1501
|
+
}
|
|
1502
|
+
round = next.sort((a, b) => position.get(a) - position.get(b));
|
|
1503
|
+
}
|
|
1504
|
+
if (ordered.length < names.length) {
|
|
1505
|
+
const placed = new Set(ordered);
|
|
1506
|
+
for (const name of names) if (!placed.has(name)) ordered.push(name);
|
|
1469
1507
|
}
|
|
1470
1508
|
return ordered;
|
|
1471
1509
|
}
|
|
1472
1510
|
function referencedNames(value, aliases) {
|
|
1473
1511
|
const seen = /* @__PURE__ */ new Set();
|
|
1474
1512
|
const queue = directReferences(value);
|
|
1475
|
-
|
|
1476
|
-
const name = queue
|
|
1513
|
+
for (let i = 0; i < queue.length; i += 1) {
|
|
1514
|
+
const name = queue[i];
|
|
1477
1515
|
if (seen.has(name)) continue;
|
|
1478
1516
|
seen.add(name);
|
|
1479
1517
|
const alias = aliases[name];
|
|
1480
|
-
if (alias !== void 0)
|
|
1518
|
+
if (alias !== void 0) for (const ref of directReferences(alias)) queue.push(ref);
|
|
1481
1519
|
}
|
|
1482
1520
|
return seen;
|
|
1483
1521
|
}
|
|
@@ -1817,13 +1855,17 @@ var WS = UCP_SPACE;
|
|
|
1817
1855
|
var S = `[${WS}]`;
|
|
1818
1856
|
var AFTER_NON_WORD = `(?<![${UCP_WORD}])`;
|
|
1819
1857
|
var WORD_BOUNDARY = `(?:(?<=[${UCP_WORD}])(?![${UCP_WORD}])|(?<![${UCP_WORD}])(?=[${UCP_WORD}]))`;
|
|
1820
|
-
var
|
|
1821
|
-
var
|
|
1858
|
+
var XN = "[xX][nN]--";
|
|
1859
|
+
var LABEL = `(?:${XN})?[\\p{L}\\p{N}]+(?:-[\\p{L}\\p{N}]+)*`;
|
|
1860
|
+
var TLD_LOWER = "\\p{Ll}\\p{Lm}\\p{Lo}";
|
|
1861
|
+
var TLD_UPPER = "\\p{Lu}\\p{Lt}\\p{Lm}\\p{Lo}";
|
|
1862
|
+
var TLD = `(?:${XN}[a-zA-Z0-9\\-\\u017F\\u212A]{2,59}|[${TLD_LOWER}][${TLD_LOWER}\\p{N}-]{1,62}|[${TLD_UPPER}][${TLD_UPPER}\\p{N}-]{1,62})`;
|
|
1863
|
+
var DOMAIN_PART = `(?:${LABEL}\\.)+${TLD}`;
|
|
1822
1864
|
var URI_BODY = `[^\\x00${WS}<>"')\\]]`;
|
|
1823
1865
|
var URI_RE = new RegExp(`(?:(?:https?|ftp):\\/\\/|(?:mailto|tel):)${URI_BODY}+`, "giu");
|
|
1824
1866
|
var MAILTEL_PREFIX_RE = /^(?:mailto|tel):/iu;
|
|
1825
|
-
var DOMAIN_AT_RE = new RegExp(`${DOMAIN_PART}${WORD_BOUNDARY}`, "
|
|
1826
|
-
var DOMAIN_SCAN_RE = new RegExp(`${AFTER_NON_WORD}(?:(${DOMAIN_PART}${WORD_BOUNDARY})|(?:${LABEL}\\.)*${LABEL})`, "
|
|
1867
|
+
var DOMAIN_AT_RE = new RegExp(`${DOMAIN_PART}${WORD_BOUNDARY}`, "uy");
|
|
1868
|
+
var DOMAIN_SCAN_RE = new RegExp(`${AFTER_NON_WORD}(?:(${DOMAIN_PART}${WORD_BOUNDARY})|(?:${LABEL}\\.)*${LABEL})`, "gu");
|
|
1827
1869
|
var DECIMAL_RE = /\b\d+\.\d+\b/gu;
|
|
1828
1870
|
var MULTI_ABBR_RE = new RegExp(`${AFTER_NON_WORD}(?:\\p{L}{1,2}\\.${S}*){2,}`, "gu");
|
|
1829
1871
|
var SINGLE_ABBR_RE = new RegExp(`(?<![\\p{L}\\p{N}])(?:${SINGLE_ABBREVS.join("|")})\\.(?=${S}|$|<)`, "giu");
|
|
@@ -1892,7 +1934,6 @@ function indexLeads(text) {
|
|
|
1892
1934
|
return { leadEnd };
|
|
1893
1935
|
}
|
|
1894
1936
|
var LOWER_RE = /^\p{Ll}/u;
|
|
1895
|
-
var LOWER_CASELESS_RE = /^\p{Ll}/iu;
|
|
1896
1937
|
var BLOCK_TAG_NAME_RE = /<\/?(?:p|h[1-6]|li|blockquote|div|td|th)/iuy;
|
|
1897
1938
|
var SENTENCE_END_SCAN_RE = new RegExp(`[.!?${String.fromCharCode(8230)}]`, "g");
|
|
1898
1939
|
var LEAD_WALK = 32;
|
|
@@ -2021,7 +2062,7 @@ function postProcess(input) {
|
|
|
2021
2062
|
text = text.replace(CAP_FIRST_RE, (_m, lead, ch) => lead + up(ch));
|
|
2022
2063
|
const leadContext = { leads: null };
|
|
2023
2064
|
text = capitalizeAfter(text, LOWER_RE, afterSentenceEnd, leadContext);
|
|
2024
|
-
text = capitalizeAfter(text,
|
|
2065
|
+
text = capitalizeAfter(text, LOWER_RE, afterBlockTag(), leadContext);
|
|
2025
2066
|
text = capitalizeAfter(text, LOWER_RE, afterLineBreak, leadContext);
|
|
2026
2067
|
return restore(text, input, placeholders).trim();
|
|
2027
2068
|
}
|