@wcstack/typescript 4.0.0-rc.3 → 4.0.0-rc.4

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.esm.js CHANGED
@@ -572,7 +572,7 @@ function loadSchemaCore() {
572
572
  return cached;
573
573
  }
574
574
 
575
- var version = "4.0.0-rc.3";
575
+ var version = "4.0.0-rc.4";
576
576
  var pkg = {
577
577
  version: version};
578
578
 
@@ -766,32 +766,8 @@ var LINT_HINT = " Validate statically: npx @wcstack/lint <file>.";
766
766
  function raiseError(message, subject, candidates) {
767
767
  throw new Error(`[@wcstack/state] ${message}${hooks.explain?.(message, subject, candidates) ?? ""}`);
768
768
  }
769
- var CODES = [
770
- "",
771
- "binding-syntax",
772
- "template-syntax",
773
- "binding-path-missing",
774
- "binding-type-expectation",
775
- "filter-unknown",
776
- "filter-arity",
777
- "getter-cycle",
778
- "getter-depth-exceeded",
779
- "index-arity",
780
- "index-param-range",
781
- "recursion-unsupported",
782
- "token-misconfigured",
783
- "token-undeclared",
784
- "wildcard-rank",
785
- "spread-no-bindable",
786
- "declaration-alias",
787
- "name-alias"
788
- ];
789
- var codeOf = (id) => {
790
- const c = CODES[id / 100 | 0];
791
- return c ? `[wcs/${c}] ` : "";
792
- };
793
769
  function text(id, args = []) {
794
- return hooks.render?.(id, args) ?? `${codeOf(id)}#${id}${args.map((a) => ` ${typeof a === "string" ? JSON.stringify(a) : String(a)}`).join("")}`;
770
+ return hooks.render?.(id, args) ?? `#${id}${args.map((a) => ` ${typeof a === "string" ? JSON.stringify(a) : String(a)}`).join("")}`;
795
771
  }
796
772
  function raise(id, args, subject, candidates) {
797
773
  raiseError(text(id, args), subject, candidates);
@@ -819,7 +795,21 @@ var FORMATS_FILTER_NAMES = [
819
795
  "time",
820
796
  "datetime",
821
797
  "ymd",
822
- "hms"
798
+ "hms",
799
+ "add",
800
+ "sub",
801
+ "mul",
802
+ "div",
803
+ "mod",
804
+ "abs",
805
+ "clamp",
806
+ "int",
807
+ "float",
808
+ "defaults",
809
+ "coalesce",
810
+ "number",
811
+ "string",
812
+ "nullIfEmpty"
823
813
  ];
824
814
  var definitions = /* @__PURE__ */ new Map();
825
815
  function hasFilter(name) {
@@ -1011,6 +1001,30 @@ function parseStatePart(statePart) {
1011
1001
  }
1012
1002
  var MAX_DRAIN_PASSES = 32;
1013
1003
  var MAX_RENDER_CHAIN = 100;
1004
+ var CODES = [
1005
+ "",
1006
+ "binding-syntax",
1007
+ "template-syntax",
1008
+ "binding-path-missing",
1009
+ "binding-type-expectation",
1010
+ "filter-unknown",
1011
+ "filter-arity",
1012
+ "getter-cycle",
1013
+ "getter-depth-exceeded",
1014
+ "index-arity",
1015
+ "index-param-range",
1016
+ "recursion-unsupported",
1017
+ "token-misconfigured",
1018
+ "token-undeclared",
1019
+ "wildcard-rank",
1020
+ "spread-no-bindable",
1021
+ "declaration-alias",
1022
+ "name-alias"
1023
+ ];
1024
+ var codeOf = (id) => {
1025
+ const c = CODES[id / 100 | 0];
1026
+ return c ? `[wcs/${c}] ` : "";
1027
+ };
1014
1028
  var MOVED = ["enableMustache", "sameValueGuard", "enableDirectionalInitialSync"];
1015
1029
  var element = (tag, at2) => `<${tag}${at2.map((a, i) => i % 2 ? `="${a}"` : ` ${a}`).join("")}>`;
1016
1030
  var CSP_GUIDE = "https://github.com/wcstack/wcstack/blob/main/docs/csp.md";
@@ -1690,26 +1704,26 @@ function findStartTagRegions(html) {
1690
1704
  let lower2 = null;
1691
1705
  let i = 0;
1692
1706
  while (i < html.length) {
1693
- const lt = html.indexOf("<", i);
1694
- if (lt === -1) break;
1695
- const next = html[lt + 1];
1696
- if (html.startsWith("<!--", lt)) {
1697
- const close = html.indexOf("-->", lt + 4);
1707
+ const lt2 = html.indexOf("<", i);
1708
+ if (lt2 === -1) break;
1709
+ const next = html[lt2 + 1];
1710
+ if (html.startsWith("<!--", lt2)) {
1711
+ const close = html.indexOf("-->", lt2 + 4);
1698
1712
  i = close === -1 ? html.length : close + 3;
1699
1713
  continue;
1700
1714
  }
1701
1715
  if (next === "!" || next === "?" || next === "/") {
1702
- const close = html.indexOf(">", lt + 1);
1716
+ const close = html.indexOf(">", lt2 + 1);
1703
1717
  i = close === -1 ? html.length : close + 1;
1704
1718
  continue;
1705
1719
  }
1706
1720
  if (next === void 0 || !/[A-Za-z]/.test(next)) {
1707
- i = lt + 1;
1721
+ i = lt2 + 1;
1708
1722
  continue;
1709
1723
  }
1710
- let n = lt + 1;
1724
+ let n = lt2 + 1;
1711
1725
  while (n < html.length && /[^\s/>]/.test(html[n])) n++;
1712
- const tagName = asciiLowerCase(html.slice(lt + 1, n));
1726
+ const tagName = asciiLowerCase(html.slice(lt2 + 1, n));
1713
1727
  let j = n;
1714
1728
  let quote = null;
1715
1729
  while (j < html.length) {
@@ -1723,10 +1737,10 @@ function findStartTagRegions(html) {
1723
1737
  }
1724
1738
  j++;
1725
1739
  }
1726
- const gt = j < html.length ? j : html.length;
1727
- const selfClosing = html[gt - 1] === "/";
1728
- out.push({ tagName, start: n, end: selfClosing ? gt - 1 : gt });
1729
- i = gt + 1;
1740
+ const gt2 = j < html.length ? j : html.length;
1741
+ const selfClosing = html[gt2 - 1] === "/";
1742
+ out.push({ tagName, start: n, end: selfClosing ? gt2 - 1 : gt2 });
1743
+ i = gt2 + 1;
1730
1744
  if (tagName === "script" || tagName === "style") {
1731
1745
  const close = (lower2 ??= asciiLowerCase(html)).indexOf(`</${tagName}`, i);
1732
1746
  i = close === -1 ? html.length : close;
@@ -1770,8 +1784,8 @@ function matchRawTextElement(html, lower2, pos) {
1770
1784
  return null;
1771
1785
  }
1772
1786
  function afterCloseTag(html, closeStart) {
1773
- const gt = html.indexOf(">", closeStart);
1774
- return gt === -1 ? html.length : gt + 1;
1787
+ const gt2 = html.indexOf(">", closeStart);
1788
+ return gt2 === -1 ? html.length : gt2 + 1;
1775
1789
  }
1776
1790
  function parseWcsStateElements(html, stateTagName = "wcs-state") {
1777
1791
  const elements = [];
@@ -1877,22 +1891,22 @@ function collectTemplateTags(html) {
1877
1891
  const tags = [];
1878
1892
  let pos = 0;
1879
1893
  while (pos < html.length) {
1880
- const lt = html.indexOf("<", pos);
1881
- if (lt === -1) break;
1882
- if (html.startsWith("<!--", lt)) {
1883
- const commentEnd = html.indexOf("-->", lt + 4);
1894
+ const lt2 = html.indexOf("<", pos);
1895
+ if (lt2 === -1) break;
1896
+ if (html.startsWith("<!--", lt2)) {
1897
+ const commentEnd = html.indexOf("-->", lt2 + 4);
1884
1898
  if (commentEnd === -1) break;
1885
1899
  pos = commentEnd + 3;
1886
1900
  continue;
1887
1901
  }
1888
- const raw = matchRawTextElement(html, lower2, lt);
1902
+ const raw = matchRawTextElement(html, lower2, lt2);
1889
1903
  if (raw !== null) {
1890
1904
  pos = raw.closed ? afterCloseTag(html, raw.contentEnd) : html.length;
1891
1905
  continue;
1892
1906
  }
1893
- const tag = /^<(\/?)template(?=[\s/>])/i.exec(html.slice(lt, lt + 11));
1894
- if (tag !== null) tags.push({ at: lt, close: tag[1] === "/" });
1895
- pos = lt + 1;
1907
+ const tag = /^<(\/?)template(?=[\s/>])/i.exec(html.slice(lt2, lt2 + 11));
1908
+ if (tag !== null) tags.push({ at: lt2, close: tag[1] === "/" });
1909
+ pos = lt2 + 1;
1896
1910
  }
1897
1911
  return tags;
1898
1912
  }
@@ -2036,32 +2050,8 @@ var hooks2 = {};
2036
2050
  function raiseError2(message, subject, candidates) {
2037
2051
  throw new Error(`[@wcstack/state] ${message}${hooks2.explain?.(message, subject, candidates) ?? ""}`);
2038
2052
  }
2039
- var CODES2 = [
2040
- "",
2041
- "binding-syntax",
2042
- "template-syntax",
2043
- "binding-path-missing",
2044
- "binding-type-expectation",
2045
- "filter-unknown",
2046
- "filter-arity",
2047
- "getter-cycle",
2048
- "getter-depth-exceeded",
2049
- "index-arity",
2050
- "index-param-range",
2051
- "recursion-unsupported",
2052
- "token-misconfigured",
2053
- "token-undeclared",
2054
- "wildcard-rank",
2055
- "spread-no-bindable",
2056
- "declaration-alias",
2057
- "name-alias"
2058
- ];
2059
- var codeOf2 = (id) => {
2060
- const c = CODES2[id / 100 | 0];
2061
- return c ? `[wcs/${c}] ` : "";
2062
- };
2063
2053
  function text2(id, args = []) {
2064
- return hooks2.render?.(id, args) ?? `${codeOf2(id)}#${id}${args.map((a) => ` ${typeof a === "string" ? JSON.stringify(a) : String(a)}`).join("")}`;
2054
+ return hooks2.render?.(id, args) ?? `#${id}${args.map((a) => ` ${typeof a === "string" ? JSON.stringify(a) : String(a)}`).join("")}`;
2065
2055
  }
2066
2056
  function raise2(id, args, subject, candidates) {
2067
2057
  raiseError2(text2(id, args), subject, candidates);
@@ -2165,42 +2155,6 @@ var numeric = (name, op) => ({
2165
2155
  var truthy = () => (value) => !!value;
2166
2156
  var falsy = () => (value) => !value;
2167
2157
  var boolean = () => (value) => Boolean(value);
2168
- var abs = () => (value) => {
2169
- if (typeof value !== "number") {
2170
- valueMustBeNumber("abs");
2171
- }
2172
- return Math.abs(value);
2173
- };
2174
- var clamp = (options) => {
2175
- const min = requiredNumberOption(options, 0, "clamp");
2176
- const max = requiredNumberOption(options, 1, "clamp");
2177
- return (value) => {
2178
- if (typeof value !== "number") {
2179
- valueMustBeNumber("clamp");
2180
- }
2181
- return Math.min(Math.max(value, min), max);
2182
- };
2183
- };
2184
- var number = () => (value) => Number(value);
2185
- var string = () => (value) => String(value);
2186
- var int = () => (value) => parseInt(String(value), 10);
2187
- var float = () => (value) => parseFloat(String(value));
2188
- var defaults = (options, literals) => {
2189
- const opt = options?.[0] ?? optionsRequired("defaults");
2190
- const fallback = firstLiteral(opt, literals);
2191
- return (value) => {
2192
- if (!value) {
2193
- return fallback;
2194
- }
2195
- return value;
2196
- };
2197
- };
2198
- var coalesce = (options, literals) => {
2199
- const opt = options?.[0] ?? optionsRequired("coalesce");
2200
- const fallback = firstLiteral(opt, literals);
2201
- return (value) => value ?? fallback;
2202
- };
2203
- var nullIfEmpty = () => (value) => value === "" ? null : value;
2204
2158
  var coreFilters = {
2205
2159
  eq: { factory: eq, arity: [1, 1] },
2206
2160
  ne: { factory: ne, arity: [1, 1] },
@@ -2209,23 +2163,9 @@ var coreFilters = {
2209
2163
  le: numeric("le", (value, opt) => value <= opt),
2210
2164
  gt: numeric("gt", (value, opt) => value > opt),
2211
2165
  ge: numeric("ge", (value, opt) => value >= opt),
2212
- add: numeric("add", (value, opt) => value + opt),
2213
- sub: numeric("sub", (value, opt) => value - opt),
2214
- mul: numeric("mul", (value, opt) => value * opt),
2215
- div: numeric("div", (value, opt) => value / opt),
2216
- mod: numeric("mod", (value, opt) => value % opt),
2217
- abs: { factory: abs, arity: [0, 0] },
2218
- clamp: { factory: clamp, arity: [2, 2] },
2219
- int: { factory: int, arity: [0, 0] },
2220
- float: { factory: float, arity: [0, 0] },
2221
2166
  falsy: { factory: falsy, arity: [0, 0] },
2222
2167
  truthy: { factory: truthy, arity: [0, 0] },
2223
- defaults: { factory: defaults, arity: [1, 1] },
2224
- coalesce: { factory: coalesce, arity: [1, 1] },
2225
- boolean: { factory: boolean, arity: [0, 0] },
2226
- number: { factory: number, arity: [0, 0] },
2227
- string: { factory: string, arity: [0, 0] },
2228
- nullIfEmpty: { factory: nullIfEmpty, arity: [0, 0] }
2168
+ boolean: { factory: boolean, arity: [0, 0] }
2229
2169
  };
2230
2170
  var nullishPassthrough = (factory) => (options) => {
2231
2171
  const filterFn = factory(options);
@@ -2410,7 +2350,44 @@ var hms = (options) => {
2410
2350
  return `${hours}${opt}${minutes}${opt}${seconds}`;
2411
2351
  };
2412
2352
  };
2413
- var formatFilters = {
2353
+ var abs = () => (value) => {
2354
+ if (typeof value !== "number") {
2355
+ valueMustBeNumber("abs");
2356
+ }
2357
+ return Math.abs(value);
2358
+ };
2359
+ var clamp = (options) => {
2360
+ const min = requiredNumberOption(options, 0, "clamp");
2361
+ const max = requiredNumberOption(options, 1, "clamp");
2362
+ return (value) => {
2363
+ if (typeof value !== "number") {
2364
+ valueMustBeNumber("clamp");
2365
+ }
2366
+ return Math.min(Math.max(value, min), max);
2367
+ };
2368
+ };
2369
+ var number = () => (value) => Number(value);
2370
+ var string = () => (value) => String(value);
2371
+ var int = () => (value) => parseInt(String(value), 10);
2372
+ var float = () => (value) => parseFloat(String(value));
2373
+ var defaults = (options, literals) => {
2374
+ const opt = options?.[0] ?? optionsRequired("defaults");
2375
+ const fallback = firstLiteral(opt, literals);
2376
+ return (value) => {
2377
+ if (!value) {
2378
+ return fallback;
2379
+ }
2380
+ return value;
2381
+ };
2382
+ };
2383
+ var coalesce = (options, literals) => {
2384
+ const opt = options?.[0] ?? optionsRequired("coalesce");
2385
+ const fallback = firstLiteral(opt, literals);
2386
+ return (value) => value ?? fallback;
2387
+ };
2388
+ var nullIfEmpty = () => (value) => value === "" ? null : value;
2389
+ var { eq: eq2, ne: ne2, not: not2, lt, le, gt, ge, falsy: falsy2, truthy: truthy2, boolean: boolean2 } = coreFilters;
2390
+ var registered = {
2414
2391
  toFixed: { factory: toFixed, arity: [0, 1] },
2415
2392
  locale: { factory: locale, arity: [0, 1] },
2416
2393
  // The `String(value)` family passes an absent value through (B8 — see nullishPassthrough)
@@ -2436,8 +2413,36 @@ var formatFilters = {
2436
2413
  time: { factory: time, arity: [0, 1] },
2437
2414
  datetime: { factory: datetime, arity: [0, 1] },
2438
2415
  ymd: { factory: ymd, arity: [0, 1] },
2439
- hms: { factory: hms, arity: [0, 1] }
2416
+ hms: { factory: hms, arity: [0, 1] },
2417
+ // the core set of 4.0.0-rc.3 (the core's own: eq ne not lt le gt ge falsy truthy boolean)
2418
+ eq: eq2,
2419
+ ne: ne2,
2420
+ not: not2,
2421
+ lt,
2422
+ le,
2423
+ gt,
2424
+ ge,
2425
+ add: numeric("add", (value, opt) => value + opt),
2426
+ sub: numeric("sub", (value, opt) => value - opt),
2427
+ mul: numeric("mul", (value, opt) => value * opt),
2428
+ div: numeric("div", (value, opt) => value / opt),
2429
+ mod: numeric("mod", (value, opt) => value % opt),
2430
+ abs: { factory: abs, arity: [0, 0] },
2431
+ clamp: { factory: clamp, arity: [2, 2] },
2432
+ int: { factory: int, arity: [0, 0] },
2433
+ float: { factory: float, arity: [0, 0] },
2434
+ falsy: falsy2,
2435
+ truthy: truthy2,
2436
+ defaults: { factory: defaults, arity: [1, 1] },
2437
+ coalesce: { factory: coalesce, arity: [1, 1] },
2438
+ boolean: boolean2,
2439
+ number: { factory: number, arity: [0, 0] },
2440
+ string: { factory: string, arity: [0, 0] },
2441
+ nullIfEmpty: { factory: nullIfEmpty, arity: [0, 0] }
2440
2442
  };
2443
+ var formatFilters = /* @__PURE__ */ Object.fromEntries(
2444
+ /* @__PURE__ */ Object.entries(registered).filter(([name]) => !(name in coreFilters))
2445
+ );
2441
2446
  var STRUCTURAL_BINDING_TYPE_SET2 = /* @__PURE__ */ new Set([
2442
2447
  "if",
2443
2448
  "elseif",
package/dist/tsc-core.cjs CHANGED
@@ -64,8 +64,8 @@ function matchRawTextElement(html, lower2, pos) {
64
64
  return null;
65
65
  }
66
66
  function afterCloseTag(html, closeStart) {
67
- const gt = html.indexOf(">", closeStart);
68
- return gt === -1 ? html.length : gt + 1;
67
+ const gt2 = html.indexOf(">", closeStart);
68
+ return gt2 === -1 ? html.length : gt2 + 1;
69
69
  }
70
70
  function parseWcsStateElements(html, stateTagName = "wcs-state") {
71
71
  const elements = [];
@@ -221,32 +221,8 @@ var hooks = {};
221
221
  function raiseError(message, subject, candidates) {
222
222
  throw new Error(`[@wcstack/state] ${message}${hooks.explain?.(message, subject, candidates) ?? ""}`);
223
223
  }
224
- var CODES = [
225
- "",
226
- "binding-syntax",
227
- "template-syntax",
228
- "binding-path-missing",
229
- "binding-type-expectation",
230
- "filter-unknown",
231
- "filter-arity",
232
- "getter-cycle",
233
- "getter-depth-exceeded",
234
- "index-arity",
235
- "index-param-range",
236
- "recursion-unsupported",
237
- "token-misconfigured",
238
- "token-undeclared",
239
- "wildcard-rank",
240
- "spread-no-bindable",
241
- "declaration-alias",
242
- "name-alias"
243
- ];
244
- var codeOf = (id) => {
245
- const c = CODES[id / 100 | 0];
246
- return c ? `[wcs/${c}] ` : "";
247
- };
248
224
  function text(id, args = []) {
249
- return hooks.render?.(id, args) ?? `${codeOf(id)}#${id}${args.map((a) => ` ${typeof a === "string" ? JSON.stringify(a) : String(a)}`).join("")}`;
225
+ return hooks.render?.(id, args) ?? `#${id}${args.map((a) => ` ${typeof a === "string" ? JSON.stringify(a) : String(a)}`).join("")}`;
250
226
  }
251
227
  function raise(id, args, subject, candidates) {
252
228
  raiseError(text(id, args), subject, candidates);
@@ -350,42 +326,6 @@ var numeric = (name, op) => ({
350
326
  var truthy = () => (value) => !!value;
351
327
  var falsy = () => (value) => !value;
352
328
  var boolean = () => (value) => Boolean(value);
353
- var abs = () => (value) => {
354
- if (typeof value !== "number") {
355
- valueMustBeNumber("abs");
356
- }
357
- return Math.abs(value);
358
- };
359
- var clamp = (options) => {
360
- const min = requiredNumberOption(options, 0, "clamp");
361
- const max = requiredNumberOption(options, 1, "clamp");
362
- return (value) => {
363
- if (typeof value !== "number") {
364
- valueMustBeNumber("clamp");
365
- }
366
- return Math.min(Math.max(value, min), max);
367
- };
368
- };
369
- var number = () => (value) => Number(value);
370
- var string = () => (value) => String(value);
371
- var int = () => (value) => parseInt(String(value), 10);
372
- var float = () => (value) => parseFloat(String(value));
373
- var defaults = (options, literals) => {
374
- const opt = options?.[0] ?? optionsRequired("defaults");
375
- const fallback = firstLiteral(opt, literals);
376
- return (value) => {
377
- if (!value) {
378
- return fallback;
379
- }
380
- return value;
381
- };
382
- };
383
- var coalesce = (options, literals) => {
384
- const opt = options?.[0] ?? optionsRequired("coalesce");
385
- const fallback = firstLiteral(opt, literals);
386
- return (value) => value ?? fallback;
387
- };
388
- var nullIfEmpty = () => (value) => value === "" ? null : value;
389
329
  var coreFilters = {
390
330
  eq: { factory: eq, arity: [1, 1] },
391
331
  ne: { factory: ne, arity: [1, 1] },
@@ -394,23 +334,9 @@ var coreFilters = {
394
334
  le: numeric("le", (value, opt) => value <= opt),
395
335
  gt: numeric("gt", (value, opt) => value > opt),
396
336
  ge: numeric("ge", (value, opt) => value >= opt),
397
- add: numeric("add", (value, opt) => value + opt),
398
- sub: numeric("sub", (value, opt) => value - opt),
399
- mul: numeric("mul", (value, opt) => value * opt),
400
- div: numeric("div", (value, opt) => value / opt),
401
- mod: numeric("mod", (value, opt) => value % opt),
402
- abs: { factory: abs, arity: [0, 0] },
403
- clamp: { factory: clamp, arity: [2, 2] },
404
- int: { factory: int, arity: [0, 0] },
405
- float: { factory: float, arity: [0, 0] },
406
337
  falsy: { factory: falsy, arity: [0, 0] },
407
338
  truthy: { factory: truthy, arity: [0, 0] },
408
- defaults: { factory: defaults, arity: [1, 1] },
409
- coalesce: { factory: coalesce, arity: [1, 1] },
410
- boolean: { factory: boolean, arity: [0, 0] },
411
- number: { factory: number, arity: [0, 0] },
412
- string: { factory: string, arity: [0, 0] },
413
- nullIfEmpty: { factory: nullIfEmpty, arity: [0, 0] }
339
+ boolean: { factory: boolean, arity: [0, 0] }
414
340
  };
415
341
  var nullishPassthrough = (factory) => (options) => {
416
342
  const filterFn = factory(options);
@@ -595,7 +521,44 @@ var hms = (options) => {
595
521
  return `${hours}${opt}${minutes}${opt}${seconds}`;
596
522
  };
597
523
  };
598
- var formatFilters = {
524
+ var abs = () => (value) => {
525
+ if (typeof value !== "number") {
526
+ valueMustBeNumber("abs");
527
+ }
528
+ return Math.abs(value);
529
+ };
530
+ var clamp = (options) => {
531
+ const min = requiredNumberOption(options, 0, "clamp");
532
+ const max = requiredNumberOption(options, 1, "clamp");
533
+ return (value) => {
534
+ if (typeof value !== "number") {
535
+ valueMustBeNumber("clamp");
536
+ }
537
+ return Math.min(Math.max(value, min), max);
538
+ };
539
+ };
540
+ var number = () => (value) => Number(value);
541
+ var string = () => (value) => String(value);
542
+ var int = () => (value) => parseInt(String(value), 10);
543
+ var float = () => (value) => parseFloat(String(value));
544
+ var defaults = (options, literals) => {
545
+ const opt = options?.[0] ?? optionsRequired("defaults");
546
+ const fallback = firstLiteral(opt, literals);
547
+ return (value) => {
548
+ if (!value) {
549
+ return fallback;
550
+ }
551
+ return value;
552
+ };
553
+ };
554
+ var coalesce = (options, literals) => {
555
+ const opt = options?.[0] ?? optionsRequired("coalesce");
556
+ const fallback = firstLiteral(opt, literals);
557
+ return (value) => value ?? fallback;
558
+ };
559
+ var nullIfEmpty = () => (value) => value === "" ? null : value;
560
+ var { eq: eq2, ne: ne2, not: not2, lt, le, gt, ge, falsy: falsy2, truthy: truthy2, boolean: boolean2 } = coreFilters;
561
+ var registered = {
599
562
  toFixed: { factory: toFixed, arity: [0, 1] },
600
563
  locale: { factory: locale, arity: [0, 1] },
601
564
  // The `String(value)` family passes an absent value through (B8 — see nullishPassthrough)
@@ -621,8 +584,36 @@ var formatFilters = {
621
584
  time: { factory: time, arity: [0, 1] },
622
585
  datetime: { factory: datetime, arity: [0, 1] },
623
586
  ymd: { factory: ymd, arity: [0, 1] },
624
- hms: { factory: hms, arity: [0, 1] }
587
+ hms: { factory: hms, arity: [0, 1] },
588
+ // the core set of 4.0.0-rc.3 (the core's own: eq ne not lt le gt ge falsy truthy boolean)
589
+ eq: eq2,
590
+ ne: ne2,
591
+ not: not2,
592
+ lt,
593
+ le,
594
+ gt,
595
+ ge,
596
+ add: numeric("add", (value, opt) => value + opt),
597
+ sub: numeric("sub", (value, opt) => value - opt),
598
+ mul: numeric("mul", (value, opt) => value * opt),
599
+ div: numeric("div", (value, opt) => value / opt),
600
+ mod: numeric("mod", (value, opt) => value % opt),
601
+ abs: { factory: abs, arity: [0, 0] },
602
+ clamp: { factory: clamp, arity: [2, 2] },
603
+ int: { factory: int, arity: [0, 0] },
604
+ float: { factory: float, arity: [0, 0] },
605
+ falsy: falsy2,
606
+ truthy: truthy2,
607
+ defaults: { factory: defaults, arity: [1, 1] },
608
+ coalesce: { factory: coalesce, arity: [1, 1] },
609
+ boolean: boolean2,
610
+ number: { factory: number, arity: [0, 0] },
611
+ string: { factory: string, arity: [0, 0] },
612
+ nullIfEmpty: { factory: nullIfEmpty, arity: [0, 0] }
625
613
  };
614
+ var formatFilters = /* @__PURE__ */ Object.fromEntries(
615
+ /* @__PURE__ */ Object.entries(registered).filter(([name]) => !(name in coreFilters))
616
+ );
626
617
  var STRUCTURAL_BINDING_TYPE_SET = /* @__PURE__ */ new Set([
627
618
  "if",
628
619
  "elseif",
@@ -573,7 +573,7 @@ function loadSchemaCore() {
573
573
  return cached;
574
574
  }
575
575
 
576
- var version = "4.0.0-rc.3";
576
+ var version = "4.0.0-rc.4";
577
577
  var pkg = {
578
578
  version: version};
579
579
 
package/dist/wcs-tsc.mjs CHANGED
@@ -5,7 +5,7 @@ import { tmpdir } from 'node:os';
5
5
  import { dirname, join, isAbsolute, resolve, basename } from 'node:path';
6
6
  import { fileURLToPath } from 'node:url';
7
7
 
8
- var version = "4.0.0-rc.3";
8
+ var version = "4.0.0-rc.4";
9
9
  var pkg = {
10
10
  version: version};
11
11
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wcstack/typescript",
3
- "version": "4.0.0-rc.3",
3
+ "version": "4.0.0-rc.4",
4
4
  "description": "TypeScript tooling for wcstack apps: wcs-schema generates the sidecar stateSchema from a typed state file, so wcs-validate checks data-wcs paths against real types in CI and every editor.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.esm.js",