@spintax/core 0.11.0 → 0.13.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 +78 -0
- package/README.md +1 -1
- package/dist/index.cjs +65 -15
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +65 -15
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1387,6 +1387,37 @@ function trimFragment(fragment) {
|
|
|
1387
1387
|
if (fragment.lead === 0 && fragment.trail === 0) return fragment;
|
|
1388
1388
|
return new Window(fragment, fragment.lead, fragment.length - fragment.trail);
|
|
1389
1389
|
}
|
|
1390
|
+
function firstCodePointOf(fragment) {
|
|
1391
|
+
const hi = charCodeAtOf(fragment, 0);
|
|
1392
|
+
if (hi >= 55296 && hi <= 56319) {
|
|
1393
|
+
const lo = charCodeAtOf(fragment, 1);
|
|
1394
|
+
if (lo >= 56320 && lo <= 57343) return (hi - 55296) * 1024 + (lo - 56320) + 65536;
|
|
1395
|
+
}
|
|
1396
|
+
return hi;
|
|
1397
|
+
}
|
|
1398
|
+
function charCodeAtOf(fragment, index) {
|
|
1399
|
+
let piece = fragment;
|
|
1400
|
+
let at = index;
|
|
1401
|
+
for (; ; ) {
|
|
1402
|
+
if (at < 0 || at >= lengthOf(piece)) return -1;
|
|
1403
|
+
if (typeof piece === "string") return piece.charCodeAt(at);
|
|
1404
|
+
if (piece instanceof Window) {
|
|
1405
|
+
at += piece.from;
|
|
1406
|
+
piece = piece.base;
|
|
1407
|
+
continue;
|
|
1408
|
+
}
|
|
1409
|
+
let offset = 0;
|
|
1410
|
+
for (const child of piece.pieces) {
|
|
1411
|
+
const length = lengthOf(child);
|
|
1412
|
+
if (at < offset + length) {
|
|
1413
|
+
piece = child;
|
|
1414
|
+
at -= offset;
|
|
1415
|
+
break;
|
|
1416
|
+
}
|
|
1417
|
+
offset += length;
|
|
1418
|
+
}
|
|
1419
|
+
}
|
|
1420
|
+
}
|
|
1390
1421
|
function flatten(fragment) {
|
|
1391
1422
|
if (typeof fragment === "string") return fragment;
|
|
1392
1423
|
const out = [];
|
|
@@ -1780,7 +1811,12 @@ function assemblePermutation(node, rendered, opts) {
|
|
|
1780
1811
|
max = Math.max(min, Math.min(max, total));
|
|
1781
1812
|
const pick = randomInt(opts.rng, min, max);
|
|
1782
1813
|
shuffle(elements, opts.rng);
|
|
1783
|
-
return joinWithSeparators(
|
|
1814
|
+
return joinWithSeparators(
|
|
1815
|
+
elements.slice(0, pick),
|
|
1816
|
+
config.sep,
|
|
1817
|
+
config.lastsep ?? config.sep,
|
|
1818
|
+
normalizeBaseLang(opts.locale)
|
|
1819
|
+
);
|
|
1784
1820
|
}
|
|
1785
1821
|
function shuffle(arr, rng) {
|
|
1786
1822
|
for (let i = arr.length - 1; i > 0; i -= 1) {
|
|
@@ -1790,7 +1826,7 @@ function shuffle(arr, rng) {
|
|
|
1790
1826
|
arr[j] = tmp;
|
|
1791
1827
|
}
|
|
1792
1828
|
}
|
|
1793
|
-
function joinWithSeparators(elements, globalSep, globalLastsep) {
|
|
1829
|
+
function joinWithSeparators(elements, globalSep, globalLastsep, lang) {
|
|
1794
1830
|
const count = elements.length;
|
|
1795
1831
|
if (count === 0) return "";
|
|
1796
1832
|
if (count === 1) return elements[0].text;
|
|
@@ -1798,14 +1834,23 @@ function joinWithSeparators(elements, globalSep, globalLastsep) {
|
|
|
1798
1834
|
for (let i = 1; i < count; i += 1) {
|
|
1799
1835
|
const el = elements[i];
|
|
1800
1836
|
const sep = el.sep ?? (i === count - 1 ? globalLastsep : globalSep);
|
|
1801
|
-
pieces.push(padSeparator(sep), el.text);
|
|
1837
|
+
pieces.push(padSeparator(sep, lang, el.text), el.text);
|
|
1802
1838
|
}
|
|
1803
1839
|
return joinFragments(pieces);
|
|
1804
1840
|
}
|
|
1805
|
-
var UNSPACED_SCRIPT_RE = /^[\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}
|
|
1806
|
-
|
|
1841
|
+
var UNSPACED_SCRIPT_RE = /^[\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}ーー\p{Script=Thai}\p{Script=Lao}\p{Script=Khmer}\p{Script=Myanmar}]+$/u;
|
|
1842
|
+
var PROCLITICS = /* @__PURE__ */ new Map([
|
|
1843
|
+
["ar", { words: /* @__PURE__ */ new Set(["\u0648", "\u0641"]), letter: /^(?=\p{L})\p{Script=Arabic}$/u }],
|
|
1844
|
+
["he", { words: /* @__PURE__ */ new Set(["\u05D5"]), letter: /^(?=\p{L})\p{Script=Hebrew}$/u }]
|
|
1845
|
+
]);
|
|
1846
|
+
function padSeparator(sep, lang, next) {
|
|
1807
1847
|
const trimmed = phpTrim(sep);
|
|
1808
1848
|
if (trimmed === "") return sep;
|
|
1849
|
+
const proclitic = PROCLITICS.get(lang);
|
|
1850
|
+
if (proclitic !== void 0 && proclitic.words.has(trimmed)) {
|
|
1851
|
+
const first = firstCodePointOf(next);
|
|
1852
|
+
return first >= 0 && proclitic.letter.test(String.fromCodePoint(first)) ? ` ${trimmed}` : ` ${trimmed} `;
|
|
1853
|
+
}
|
|
1809
1854
|
if (/^\p{L}+$/u.test(trimmed) && !UNSPACED_SCRIPT_RE.test(trimmed)) return ` ${trimmed} `;
|
|
1810
1855
|
return sep;
|
|
1811
1856
|
}
|
|
@@ -1872,7 +1917,7 @@ var TLD_UPPER = "\\p{Lu}\\p{Lt}\\p{Lm}\\p{Lo}";
|
|
|
1872
1917
|
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})`;
|
|
1873
1918
|
var DOMAIN_PART = `(?:${LABEL}\\.)+${TLD}`;
|
|
1874
1919
|
var URI_BODY = `[^\\x00${WS}<>"')\\]]`;
|
|
1875
|
-
var URI_RE = new RegExp(`(?:(?:https?|ftp)
|
|
1920
|
+
var URI_RE = new RegExp(`(?:(?:https?|ftp):\\/\\/${URI_BODY}*|(?:mailto|tel):${URI_BODY}+)`, "giu");
|
|
1876
1921
|
var MAILTEL_PREFIX_RE = /^(?:mailto|tel):/iu;
|
|
1877
1922
|
var DOMAIN_AT_RE = new RegExp(`${DOMAIN_PART}${WORD_BOUNDARY}`, "uy");
|
|
1878
1923
|
var DOMAIN_SCAN_RE = new RegExp(`${AFTER_NON_WORD}(?:(${DOMAIN_PART}${WORD_BOUNDARY})|(?:${LABEL}\\.)*${LABEL})`, "gu");
|
|
@@ -1921,12 +1966,15 @@ var SENTENCE_OPENERS = "\xBF\xA1";
|
|
|
1921
1966
|
var LEAD = `(?:<[^>]+>|[${SENTENCE_OPENERS}]|${S})*`;
|
|
1922
1967
|
var QUOTES = `"'\xAB\xBB\u2039\u203A\u201C\u201D\u2018\u2019`;
|
|
1923
1968
|
var CLOSER = `[)\\]]|[${QUOTES}]+(?=${S}|$|<|\\/?>|[.,;:!?\u2026)\\]\u2014\u2013])`;
|
|
1969
|
+
var DOT_TOKEN_RE = new RegExp(`(?<=^|${S}|[(\\[{>/\\\\${QUOTES}])\\.[\\p{L}\\p{N}][\\p{L}\\p{N}_.\\-]*`, "gu");
|
|
1924
1970
|
var SPACE_BEFORE_PUNCT_RE = new RegExp(`(?<!${S})${S}+([,;:!?.])`, "gu");
|
|
1925
1971
|
var SPACE_AFTER_COMMA_RE = new RegExp(`([,;:])(?!\\p{Nd})(?!${S}|$|<|${CLOSER})`, "gu");
|
|
1926
1972
|
var SPACE_AFTER_SENTENCE_RE = new RegExp(`(?<![.!?])([.!?]+)(?![.!?])(?!\\p{Nd})(?!${S}|$|<|${CLOSER})`, "gu");
|
|
1927
1973
|
var SPACE_AFTER_OPENER_RE = new RegExp(`([${SENTENCE_OPENERS}])${S}+`, "gu");
|
|
1928
1974
|
var CAP_FIRST_RE = new RegExp(`^(${LEAD})(\\p{Ll})`, "u");
|
|
1929
1975
|
var up = (ch) => ch.toUpperCase();
|
|
1976
|
+
var upTurkic = (ch) => ch === "i" ? "\u0130" : ch.toUpperCase();
|
|
1977
|
+
var TURKIC_LANGS = /* @__PURE__ */ new Set(["tr", "az"]);
|
|
1930
1978
|
function indexLeads(text) {
|
|
1931
1979
|
const n = text.length;
|
|
1932
1980
|
const leadEnd = new Int32Array(n + 1);
|
|
@@ -1959,7 +2007,7 @@ function leadEndFrom(text, i, leads) {
|
|
|
1959
2007
|
}
|
|
1960
2008
|
return j < text.length ? leads().leadEnd[j] : j;
|
|
1961
2009
|
}
|
|
1962
|
-
function capitalizeAfter(text, lower, next, context) {
|
|
2010
|
+
function capitalizeAfter(text, lower, next, context, upper) {
|
|
1963
2011
|
const leads = () => {
|
|
1964
2012
|
if (context.leads === null || context.leads.leadEnd.length !== text.length + 1) context.leads = indexLeads(text);
|
|
1965
2013
|
return context.leads;
|
|
@@ -1974,7 +2022,7 @@ function capitalizeAfter(text, lower, next, context) {
|
|
|
1974
2022
|
if (cp === void 0) continue;
|
|
1975
2023
|
const ch = String.fromCodePoint(cp);
|
|
1976
2024
|
if (!lower.test(ch)) continue;
|
|
1977
|
-
out += text.slice(emitted, at) +
|
|
2025
|
+
out += text.slice(emitted, at) + upper(ch);
|
|
1978
2026
|
emitted = at + ch.length;
|
|
1979
2027
|
from = emitted;
|
|
1980
2028
|
}
|
|
@@ -2007,7 +2055,7 @@ var afterLineBreak = (text, from) => {
|
|
|
2007
2055
|
const at = text.indexOf("\n", from);
|
|
2008
2056
|
return at === -1 ? null : { leadStart: at + 1, resume: at + 1 };
|
|
2009
2057
|
};
|
|
2010
|
-
var SHIELD_PREFIXES = ["URL", "URI", "EMAIL", "DOM", "NUM", "ABBR"];
|
|
2058
|
+
var SHIELD_PREFIXES = ["URL", "URI", "EMAIL", "DOTTOK", "DOM", "NUM", "ABBR"];
|
|
2011
2059
|
var RESTORE_RE2 = new RegExp(`\\x00(?:${SHIELD_PREFIXES.join("|")})_\\d+\\x00`, "gu");
|
|
2012
2060
|
function restore(text, input, placeholders) {
|
|
2013
2061
|
if (!input.includes("\0")) {
|
|
@@ -2042,7 +2090,8 @@ function restoreAsTheLoopDoes(text, placeholders) {
|
|
|
2042
2090
|
}
|
|
2043
2091
|
return out;
|
|
2044
2092
|
}
|
|
2045
|
-
function postProcess(input) {
|
|
2093
|
+
function postProcess(input, locale = "") {
|
|
2094
|
+
const upper = TURKIC_LANGS.has(normalizeBaseLang(locale)) ? upTurkic : up;
|
|
2046
2095
|
const placeholders = /* @__PURE__ */ new Map();
|
|
2047
2096
|
let counter = 0;
|
|
2048
2097
|
const store = (value, prefix) => {
|
|
@@ -2062,6 +2111,7 @@ function postProcess(input) {
|
|
|
2062
2111
|
(m) => storeWithTrailingPunct(m, MAILTEL_PREFIX_RE.test(m) ? "URI" : "URL")
|
|
2063
2112
|
);
|
|
2064
2113
|
text = shieldEmails(text, (m) => store(m, "EMAIL"));
|
|
2114
|
+
text = text.replace(DOT_TOKEN_RE, (m) => storeWithTrailingPunct(m, "DOTTOK"));
|
|
2065
2115
|
text = shieldDomains(text, (m) => store(m, "DOM"));
|
|
2066
2116
|
text = text.replace(DECIMAL_RE, (m) => store(m, "NUM"));
|
|
2067
2117
|
text = text.replace(MULTI_ABBR_RE, (m) => store(m, "ABBR"));
|
|
@@ -2071,11 +2121,11 @@ function postProcess(input) {
|
|
|
2071
2121
|
text = text.replace(SPACE_AFTER_COMMA_RE, "$1 ");
|
|
2072
2122
|
text = text.replace(SPACE_AFTER_SENTENCE_RE, "$1 ");
|
|
2073
2123
|
text = text.replace(SPACE_AFTER_OPENER_RE, "$1");
|
|
2074
|
-
text = text.replace(CAP_FIRST_RE, (_m, lead, ch) => lead +
|
|
2124
|
+
text = text.replace(CAP_FIRST_RE, (_m, lead, ch) => lead + upper(ch));
|
|
2075
2125
|
const leadContext = { leads: null };
|
|
2076
|
-
text = capitalizeAfter(text, LOWER_RE, afterSentenceEnd, leadContext);
|
|
2077
|
-
text = capitalizeAfter(text, LOWER_RE, afterBlockTag(), leadContext);
|
|
2078
|
-
text = capitalizeAfter(text, LOWER_RE, afterLineBreak, leadContext);
|
|
2126
|
+
text = capitalizeAfter(text, LOWER_RE, afterSentenceEnd, leadContext, upper);
|
|
2127
|
+
text = capitalizeAfter(text, LOWER_RE, afterBlockTag(), leadContext, upper);
|
|
2128
|
+
text = capitalizeAfter(text, LOWER_RE, afterLineBreak, leadContext, upper);
|
|
2079
2129
|
return restore(text, input, placeholders).trim();
|
|
2080
2130
|
}
|
|
2081
2131
|
|
|
@@ -2096,7 +2146,7 @@ function renderWith(input, rng, opts = {}) {
|
|
|
2096
2146
|
};
|
|
2097
2147
|
const ast = resolveAst(input);
|
|
2098
2148
|
let out = renderAst(ast, ctx);
|
|
2099
|
-
if (opts.postProcess !== false) out = postProcess(out);
|
|
2149
|
+
if (opts.postProcess !== false) out = postProcess(out, ctx.locale);
|
|
2100
2150
|
return safetyRestore(out);
|
|
2101
2151
|
}
|
|
2102
2152
|
function resolveAst(input) {
|