@wix/himalaya-cli 0.1579.0 → 0.1581.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.
Files changed (54) hide show
  1. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/dev-server/src/app-config.d.ts +18 -3
  2. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/dev-server/src/builder.d.ts +3 -0
  3. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/sdk/motion/src/index.d.ts +51 -5
  4. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/sdk/network/src/index.d.ts +39 -0
  5. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/sdk/sdk-types/src/capabilities.generated.d.ts +2 -1
  6. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/sdk/webview-page/src/capabilities.generated.d.ts +2 -0
  7. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/ts/src/define-app.d.ts +1 -1
  8. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/ts/src/schema.d.ts +12 -0
  9. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/ts/src/validator.d.ts +6 -0
  10. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/media/src/index.d.ts +1 -0
  11. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/media/src/rendition.d.ts +42 -0
  12. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/audio-record.mjs +1 -0
  13. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/calendar.mjs +1 -0
  14. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/calls.mjs +1 -0
  15. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/contacts.mjs +1 -0
  16. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/core.mjs +1 -0
  17. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/location.mjs +1 -0
  18. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/motion.mjs +23 -2
  19. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/network.mjs +45 -0
  20. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/photos.mjs +1 -0
  21. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/sdk-types.mjs +1 -0
  22. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/sdui.mjs +1 -0
  23. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/tasks.mjs +1 -0
  24. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-media.mjs +78 -0
  25. package/dist/authoring-runtime/node_modules/@wix/himalaya/package.json +4 -0
  26. package/dist/cli.mjs +9144 -7459
  27. package/dist/preview-assets.generated.bin +0 -0
  28. package/dist/quickjs-intl.js +462 -0
  29. package/dist/quickjs-web-globals.js +540 -0
  30. package/dist/quickjs-worker-entry.js +313 -0
  31. package/guides/app-config.md +1 -1
  32. package/guides/component-reference.json +5 -3
  33. package/guides/component-reference.md +10 -2
  34. package/guides/designing-himi-screens.md +24 -0
  35. package/guides/himi-json-output.md +30 -1
  36. package/guides/importable-sdks.md +1 -0
  37. package/guides/one-app-section-mappings.md +4 -5
  38. package/guides/one-app-to-himi-app.md +214 -6
  39. package/guides/one-app-viewer.md +2 -2
  40. package/guides/sdk-reference.json +74 -7
  41. package/guides/tier-5-add-a-screen.md +32 -0
  42. package/guides/web-page-sdk-reference.md +1 -0
  43. package/package.json +3 -2
  44. package/templates/beauty-salon/dev/index.ts +197 -304
  45. package/templates/beauty-salon/tier5-src/himi-store-product/index.ts +44 -13
  46. package/templates/branded-lite/dev/index.ts +197 -304
  47. package/templates/branded-lite/l10n/en.json +2 -2
  48. package/templates/branded-lite/tier5-src/himi-store-product/index.ts +49 -17
  49. package/templates/gym-fitness/dev/index.ts +197 -304
  50. package/templates/gym-fitness/tier5-src/himi-store-product/index.ts +44 -13
  51. package/templates/portfolio-creative/dev/index.ts +197 -304
  52. package/templates/portfolio-creative/tier5-src/himi-store-product/index.ts +44 -13
  53. package/templates/retail-store/dev/index.ts +197 -304
  54. package/templates/retail-store/tier5-src/himi-store-product/index.ts +49 -17
Binary file
@@ -0,0 +1,462 @@
1
+ // ../../core/dev-server/src/quickjs-intl.ts
2
+ var NONFINITE_TAG = "\0himi-nonfinite:";
3
+ var INTL_SHIM = `
4
+ // ############################################################################################
5
+ // NO BACKTICKS AND NO LITERAL NUL ANYWHERE BELOW. This whole block is a TEMPLATE LITERAL in the
6
+ // TypeScript source, so a backtick in a comment terminates it and a NUL byte makes grep treat
7
+ // the entire file as binary and silently match nothing. Both have happened, twice and once
8
+ // respectively, while editing these comments. Write length and this and Intl.X unquoted.
9
+ // ############################################################################################
10
+ (function () {
11
+ var NF_TAG = ${JSON.stringify(NONFINITE_TAG)};
12
+
13
+ // EVERY BUILTIN THIS SHIM USES IS CAPTURED HERE, BEFORE AUTHOR CODE RUNS.
14
+ //
15
+ // The shim installs at prelude time and its functions run LATER, inside the bundle's call
16
+ // stack \u2014 so any global it resolves at call time is a global the bundle can replace first.
17
+ // Measured: a bundle doing globalThis.Symbol = undefined made every ToPrimitive reduction throw
18
+ // TypeError, where native Intl kept using the intrinsic well-known symbol and fell back to
19
+ // valueOf. That is a false FAILURE, and it reached the format path as well as the locale walk
20
+ // because both share the reduction.
21
+ //
22
+ // Same discipline the prelude already applies to its readback channel, and for the same stated
23
+ // reason: anything reachable after untrusted code runs is reachable BY it. JSON.stringify is
24
+ // called out there by name as a global that was reassigned in exactly this way.
25
+ var $Sym = typeof Symbol !== "undefined" && Symbol ? Symbol.toPrimitive : undefined;
26
+ var $stringify = JSON.stringify, $parse = JSON.parse;
27
+ var $is = Object.is, $trunc = Math.trunc, $isFinite = isFinite;
28
+ var $String = String, $Number = Number, $Boolean = Boolean, $TypeError = TypeError;
29
+ var $now = Date.now;
30
+ // Reflect.apply, because INVOKING a user function must not read a property off it. The spec's
31
+ // Call operation goes straight to the function's internal [[Call]]; sp.call(...) consults the
32
+ // mutable .call slot, which a bundle can poison:
33
+ // var f = function () { return 5; }; f.call = function () { throw new Error("poison"); };
34
+ // o[Symbol.toPrimitive] = f; -> host formats 5, the shim threw "poison"
35
+ var $apply = Reflect.apply;
36
+ var D = globalThis.__himiIntlDate, N = globalThis.__himiIntlNumber,
37
+ C = globalThis.__himiIntlCompare, V = globalThis.__himiIntlValidate,
38
+ L = globalThis.__himiIntlToLocale;
39
+ // Captured before any bundle runs, for the same reason every other intrinsic here is: a bundle
40
+ // that replaces 'Date.prototype.getTime' must not be able to steer what this hands the host.
41
+ var $Date = Date, $getTime = Date.prototype.getTime;
42
+ delete globalThis.__himiIntlDate; delete globalThis.__himiIntlNumber;
43
+ delete globalThis.__himiIntlCompare; delete globalThis.__himiIntlValidate;
44
+ delete globalThis.__himiIntlToLocale;
45
+ // Non-finite numbers are TAGGED on the way out. JSON has no spelling for them, so a plain
46
+ // stringify turns NaN into null, the host reads To$Number(null) === 0, and the one value Intl
47
+ // rejects becomes a value it accepts.
48
+ var enc = function (v) {
49
+ try {
50
+ if (v === undefined) return "";
51
+ return $stringify(v, function (k, val) {
52
+ return typeof val === "number" && !$isFinite(val) ? NF_TAG + $String(val) : val;
53
+ });
54
+ } catch (e) { return ""; }
55
+ };
56
+
57
+ // OPTION BAGS ARE READ BY PROPERTY LOOKUP, NOT SERIALIZED. JSON.stringify captures own
58
+ // ENUMERABLE properties only, while Intl constructors do an ordinary [[Get]] per recognized
59
+ // key \u2014 so a non-enumerable or prototype-inherited option is meaningful to the host and
60
+ // invisible to a serializer:
61
+ //
62
+ // var o = {}; Object.defineProperty(o, "style", { value: "currency" });
63
+ // new Intl.NumberFormat("en", o) // host: throws, currency is missing
64
+ // // $stringify(o) === "{}" -> validated as defaults
65
+ //
66
+ // which is a false pass again. So each bag is rebuilt by reading it through the same lookup the
67
+ // host would use (getters included), and only THAT flat object is serialized.
68
+ //
69
+ // READ EXACTLY THE KEYS THE HOST READS, AND NOT ONE MORE. An earlier cut added a for..in
70
+ // pass so that an option ECMA-402 adds later would still travel rather than be silently
71
+ // dropped. That was being cleverer than the spec, and it cost a FALSE FAILURE in the other
72
+ // direction: host Intl never enumerates the bag, it does one [[Get]] per recognized key, so
73
+ //
74
+ // new Intl.NumberFormat("en", { style: "percent", get unrelated() { throw new Error("boom"); } })
75
+ // host "50%" \u2014 never touches the unrelated getter
76
+ // for..in \u2014 invokes it, and the run dies on someone else's getter
77
+ //
78
+ // The residual cost is accepted deliberately: when the host gains an option this list has not
79
+ // heard of, a bundle using it early would have that option dropped. That needs the host to grow
80
+ // AND a bundle to adopt it before this list is updated, whereas the getter above breaks a valid
81
+ // bundle today. Matching the host's read set exactly is the only rule that cannot diverge in
82
+ // either direction now, and "now" is what a crawl reports on.
83
+ //
84
+ // A NON-PRIMITIVE VALUE IS COERCED HERE, NOT DROPPED. Skipping it read as "absent" and the host
85
+ // does no such thing \u2014 it coerces, and then usually rejects:
86
+ //
87
+ // { style: function () {} } host: ToString -> invalid enum -> RangeError
88
+ // { style: {} } host: ToString -> invalid enum -> RangeError
89
+ // { minimumFractionDigits: { valueOf: () => 3 } } host: ToNumber -> 3 -> ACCEPTED
90
+ //
91
+ // so dropping produced a false pass on the first two, and failing closed would produce a false
92
+ // FAILURE on the third. Both are forbidden. The coercion is per option class because that is
93
+ // what the spec does \u2014 ToNumber for the digit counts, ToBoolean for the flags, ToString for
94
+ // everything else \u2014 and those are language-level operations, so performing them in the guest is
95
+ // identical to the host performing them. After coercion the value is a primitive and marshals
96
+ // exactly. A primitive is passed through verbatim and left for the host to coerce, which matters
97
+ // for useGrouping, where a real boolean and the string "true" are not interchangeable.
98
+ var NUMK = ["minimumIntegerDigits","minimumFractionDigits","maximumFractionDigits",
99
+ "minimumSignificantDigits","maximumSignificantDigits","roundingIncrement","fractionalSecondDigits"];
100
+ var BOOLK = ["hour12","ignorePunctuation","numeric"];
101
+ var has = function (arr, k) { for (var i = 0; i < arr.length; i++) if (arr[i] === k) return true; return false; };
102
+ // ToString, which is NOT the $String() function. They differ on exactly one input: $String()
103
+ // stringifies a Symbol, spec ToString throws. Intl applies ToString to string-valued options
104
+ // and to both sides of a collation, so $String() reported an ordering where the host threw.
105
+ var toStr = function (v) {
106
+ if (typeof v === "symbol") throw new $TypeError("Cannot convert a Symbol value to a string");
107
+ return $String(v);
108
+ };
109
+
110
+ // CanonicalizeLocaleList, which JSON cannot stand in for. A locale list is walked by INDEX with
111
+ // a HasProperty check, so a hole is skipped \u2014 while JSON.stringify renders it as null and the
112
+ // host then rejects the null:
113
+ //
114
+ // new Intl.NumberFormat(Array(1)) host: fine, the hole is skipped
115
+ // $stringify(Array(1)) "[null]" -> host TypeError
116
+ //
117
+ // which failed a bundle that works. Normalised here to a dense array of strings instead.
118
+ var encLocales = function (v) {
119
+ if (v === undefined) return "";
120
+ if (typeof v === "string") return $stringify([v]);
121
+ // ToObject: throws for null/undefined and succeeds for everything else. A PRIMITIVE becomes a
122
+ // wrapper whose length is undefined, which LengthOfArrayLike reads as 0 \u2014 an EMPTY list,
123
+ // i.e. the default locale. So {} and 5 and even a Symbol are all accepted by the host and
124
+ // format with the default locale; stringifying them into a locale was a false failure.
125
+ if (v === null) throw new $TypeError("Cannot convert undefined or null to object");
126
+ // LengthOfArrayLike, not $Number(): ToLength truncates toward zero and clamps, and ToNumber of
127
+ // a BigInt throws. length 1.9 means index 0 ONLY \u2014 reading index 1 invoked a getter the host
128
+ // never touches \u2014 and length 1n is a TypeError rather than 1.
129
+ var len = v.length;
130
+ // Reduce it FIRST, the same way every other numeric argument is reduced. LengthOfArrayLike
131
+ // applies spec ToNumber, which is ToPrimitive then reject-a-BigInt \u2014 so an object whose
132
+ // primitive is a BigInt is a TypeError, while explicit $Number() on that same object walks
133
+ // valueOf, gets 1n, and quietly returns 1. This is the round-8 class; the reduction existed
134
+ // and simply was not applied to length when this walk was written.
135
+ var lt = typeof len;
136
+ if (len !== null && (lt === "object" || lt === "function")) len = toPrim(len, "number");
137
+ if (typeof len === "bigint") throw new $TypeError("Cannot convert a BigInt value to a number");
138
+ var n = $Number(len);
139
+ n = n !== n ? 0 : $trunc(n);
140
+ if (n < 0) n = 0;
141
+ if (n > 9007199254740991) n = 9007199254740991;
142
+ var out = [];
143
+ for (var i = 0; i < n; i++) {
144
+ if (i in v) {
145
+ var el = v[i];
146
+ var et = typeof el;
147
+ // Each element must be a String or an Object. Anything else is a TypeError on the host,
148
+ // not the bad-locale RangeError that stringifying it would have produced.
149
+ if (et !== "string" && !(el !== null && (et === "object" || et === "function"))) {
150
+ throw new $TypeError("Locale must be a string or an object");
151
+ }
152
+ out.push(toStr(el));
153
+ }
154
+ }
155
+ return $stringify(out);
156
+ };
157
+
158
+ // ToPrimitive, so an OBJECT reduces to a primitive before anything classifies it.
159
+ //
160
+ // This is what closes the coercion axis instead of adding a third BigInt special case. Explicit
161
+ // $Number() differs from spec ToNumber in exactly ONE way \u2014 it accepts a BigInt where ToNumber
162
+ // throws \u2014 so every object whose primitive is a BigInt slipped past a typeof check:
163
+ //
164
+ // { [Symbol.toPrimitive]: () => 1n } host TypeError, $Number() gave 1
165
+ // { [Symbol.toPrimitive]: () => 9007199254740993n } host exact, $Number() rounded it
166
+ //
167
+ // Reduce first and the primitive paths below \u2014 already exact as of the previous commit \u2014 handle
168
+ // every input there is. Ordinary order is valueOf-then-toString for a number hint and the
169
+ // reverse for a string hint, same as the spec.
170
+ var toPrim = function (v, hint) {
171
+ if (v === null) return v;
172
+ var t = typeof v;
173
+ if (t !== "object" && t !== "function") return v;
174
+ var sp = v[$Sym];
175
+ if (sp !== undefined && sp !== null) {
176
+ var r = $apply(sp, v, [hint]);
177
+ var rt = typeof r;
178
+ if (r === null || (rt !== "object" && rt !== "function")) return r;
179
+ throw new $TypeError("Cannot convert object to primitive value");
180
+ }
181
+ var order = hint === "string" ? ["toString", "valueOf"] : ["valueOf", "toString"];
182
+ for (var i = 0; i < order.length; i++) {
183
+ var f = v[order[i]];
184
+ if (typeof f === "function") {
185
+ var res = $apply(f, v, []);
186
+ var rest = typeof res;
187
+ if (res === null || (rest !== "object" && rest !== "function")) return res;
188
+ }
189
+ }
190
+ throw new $TypeError("Cannot convert object to primitive value");
191
+ };
192
+
193
+ var coerce = function (k, v) {
194
+ var t = typeof v;
195
+ // A primitive travels VERBATIM and the host coerces it. That is what keeps useGrouping:false
196
+ // a boolean rather than the string "false", which the host would reject.
197
+ if (v === null || t === "string" || t === "number" || t === "boolean") return v;
198
+ // ToBoolean never calls ToPrimitive \u2014 an object is simply truthy \u2014 so the boolean class must
199
+ // not be reduced first.
200
+ if (has(BOOLK, k)) return $Boolean(v);
201
+ if (t === "bigint") {
202
+ if (has(NUMK, k)) throw new $TypeError("Cannot convert a BigInt value to a number");
203
+ return toStr(v);
204
+ }
205
+ var p = toPrim(v, has(NUMK, k) ? "number" : "string");
206
+ if (has(NUMK, k)) {
207
+ if (typeof p === "bigint") throw new $TypeError("Cannot convert a BigInt value to a number");
208
+ return $Number(p);
209
+ }
210
+ return toStr(p);
211
+ };
212
+ var pick = function (o, keys) {
213
+ var out = {};
214
+ if (o === undefined) return out;
215
+ // null IS NOT THE SAME AS OMITTED. The constructors special-case undefined only \u2014 an options
216
+ // bag goes through ToObject, and ToObject(null) throws \u2014 so treating null as "use defaults"
217
+ // passed a bundle the host rejects:
218
+ // new Intl.NumberFormat("en", null) host TypeError, this returned {} and validated clean
219
+ if (o === null) throw new $TypeError("Cannot convert undefined or null to object");
220
+ for (var i = 0; i < keys.length; i++) {
221
+ var v = o[keys[i]];
222
+ if (v !== undefined) out[keys[i]] = coerce(keys[i], v);
223
+ }
224
+ return out;
225
+ };
226
+ var DTF = ["localeMatcher","calendar","numberingSystem","hour12","hourCycle","timeZone","weekday",
227
+ "era","year","month","day","dayPeriod","hour","minute","second","fractionalSecondDigits",
228
+ "timeZoneName","formatMatcher","dateStyle","timeStyle"];
229
+ var NF = ["localeMatcher","style","currency","currencyDisplay","currencySign","unit","unitDisplay",
230
+ "numberingSystem","minimumIntegerDigits","minimumFractionDigits","maximumFractionDigits",
231
+ "minimumSignificantDigits","maximumSignificantDigits","useGrouping","notation","compactDisplay",
232
+ "signDisplay","roundingMode","roundingIncrement","roundingPriority","trailingZeroDisplay"];
233
+ var COL = ["localeMatcher","usage","sensitivity","ignorePunctuation","numeric","caseFirst","collation"];
234
+
235
+ // NO resolvedOptions(). It would have to invent resolved values \u2014 a locale, a calendar, a
236
+ // numberingSystem, a timeZone \u2014 and echoing the caller's own option bag back is a confident
237
+ // wrong answer, not an implementation: a bundle branching on the resolved timeZone would read
238
+ // undefined here and a real zone on device. Absent, it throws where it is unsupported, which
239
+ // is the honest failure and the rule the header states.
240
+ // (No backticks in this string: it is a template literal in the TS source.)
241
+ //
242
+ // EVERY CONSTRUCTOR VALIDATES THROUGH THE HOST, because host Intl rejects a bad locale or
243
+ // option bag AT CONSTRUCTION, not at format time. Deferring meant
244
+ // new Intl.NumberFormat("en", { style: "currency" }) // no currency
245
+ // succeeded here and threw under node:vm, so a bundle that built a bad formatter without
246
+ // reaching a format call passed the crawl and died on device. Same false-pass class the
247
+ // swallowed-throw bug was.
248
+ function DateTimeFormat(locales, options) {
249
+ if (!(this instanceof DateTimeFormat)) return new DateTimeFormat(locales, options);
250
+ var l = encLocales(locales), o = enc(pick(options, DTF));
251
+ V("DateTimeFormat", l, o);
252
+ // ToNumber on the date argument, which means ToPrimitive first: an object whose primitive is
253
+ // a BigInt is a TypeError on the host, not a date.
254
+ this.format = function (d) {
255
+ var v = d;
256
+ var t = typeof v;
257
+ if (v !== null && (t === "object" || t === "function")) v = toPrim(v, "number");
258
+ if (typeof v === "bigint") throw new $TypeError("Cannot convert a BigInt value to a number");
259
+ return D(l, o, v === undefined ? $now() : $Number(v));
260
+ };
261
+ }
262
+ function NumberFormat(locales, options) {
263
+ if (!(this instanceof NumberFormat)) return new NumberFormat(locales, options);
264
+ var l = encLocales(locales), o = enc(pick(options, NF));
265
+ V("NumberFormat", l, o);
266
+ // THE VALUE CROSSES AS A STRING PLUS A KIND, never as a coerced double. Host NumberFormat
267
+ // takes an Intl mathematical value, which is EXACT for a BigInt and for a numeric string:
268
+ // format(9007199254740993n) -> 9,007,199,254,740,993
269
+ // format($Number(that)) -> 9,007,199,254,740,992 <- last digit gone
270
+ // format("9007199254740993") -> 9,007,199,254,740,993
271
+ // so $Number() here silently reformatted anything past double precision. A number still goes
272
+ // as a number: $String(Number) round-trips a double exactly.
273
+ this.format = function (n) {
274
+ var v = n;
275
+ var t = typeof v;
276
+ // ToPrimitive first \u2014 the exactness below is only exact if it sees what the host sees.
277
+ if (v !== null && (t === "object" || t === "function")) v = toPrim(v, "number");
278
+ t = typeof v;
279
+ // $String, not v.toString(): ToString of a BigInt is an internal operation, so it is
280
+ // unaffected by a replaced BigInt.prototype.toString, which the method call was not.
281
+ if (t === "bigint") return N(l, o, $String(v), "b");
282
+ if (t === "string") return N(l, o, v, "s");
283
+ // NEGATIVE ZERO survives the crossing explicitly. The host prints "-0" \u2014 it keeps the sign
284
+ // \u2014 while $String(-0) is "0", so the sign was lost on the way out and never came back.
285
+ // $Number("-0") is -0, so spelling it is enough to restore it.
286
+ var n2 = $Number(v);
287
+ return N(l, o, $is(n2, -0) ? "-0" : $String(n2), "n");
288
+ };
289
+ }
290
+ // Collator carries its OPTIONS through. Dropping them made { numeric: true } compare "2" and
291
+ // "10" lexically \u2014 2 after 10 \u2014 which is a plausible-looking wrong order, the worst kind.
292
+ function Collator(locales, options) {
293
+ if (!(this instanceof Collator)) return new Collator(locales, options);
294
+ var l = encLocales(locales), o = enc(pick(options, COL));
295
+ V("Collator", l, o);
296
+ this.compare = function (a, b) { return C(toStr(a), toStr(b), l, o); };
297
+ }
298
+
299
+ globalThis.Intl = { DateTimeFormat: DateTimeFormat, NumberFormat: NumberFormat, Collator: Collator };
300
+ // QuickJS ships a localeCompare that is a code-unit subtraction, so "a".localeCompare("B") is
301
+ // 31 where ICU says -1 \u2014 a SIGN FLIP, not a magnitude difference, which silently reverses
302
+ // every sort a bundle performs. Replaced rather than left alone, and its third argument is
303
+ // threaded too: localeCompare(that, locales, { numeric: true }) is the idiomatic natural sort.
304
+ String.prototype.localeCompare = function (that, locales, options) {
305
+ // STRICT, so this is not boxed. The native method does RequireObjectCoercible on its
306
+ // receiver and throws for null/undefined; a sloppy replacement has this already rebound to
307
+ // globalThis by the time it runs, so it stringified the global object and compared happily
308
+ // where the host threw.
309
+ "use strict";
310
+ if (this === null || this === undefined) {
311
+ throw new $TypeError("String.prototype.localeCompare called on null or undefined");
312
+ }
313
+ return C(toStr(this), toStr(that), encLocales(locales), enc(pick(options, COL)));
314
+ };
315
+
316
+ // Date.prototype.toLocale{,Date,Time}String \u2014 SEPARATE built-ins from Intl.DateTimeFormat, and
317
+ // leaving them native was a real hole. QuickJS-ng implements all three without ICU: it accepts
318
+ // the options bag and ignores it, so a bundle asking for a short month got a full numeric date
319
+ // and no error. Measured against node:vm on the sync realm before this existed:
320
+ //
321
+ // toLocaleTimeString("en-US", {hour:"numeric",minute:"2-digit"}) "2:00 AM" vs "02:00:00 AM"
322
+ // toLocaleDateString("en-US", {month:"short"}) "Jan" vs "01/01/1970"
323
+ // toLocaleString("en-US", {dateStyle:"medium"}) "Jan 1, 1970" vs "01/01/1970, 02:00:00 AM"
324
+ //
325
+ // Options are passed through the SAME 'pick(options, DTF)' whitelist the formatter uses, so one
326
+ // option vocabulary serves both paths, and the host applies ECMA-402's own defaulting by calling
327
+ // the very method that was called here.
328
+ //
329
+ // STRICT and receiver-checked for the same reason localeCompare above is: the native methods do
330
+ // their brand check on the receiver, and a sloppy replacement would have 'this' rebound to
331
+ // globalThis and format the current time instead of throwing.
332
+ var toLocale = function (kind) {
333
+ return function (locales, options) {
334
+ "use strict";
335
+ if (!(this instanceof $Date)) {
336
+ throw new $TypeError("Date.prototype.toLocaleString called on a non-Date object");
337
+ }
338
+ var t = $getTime.call(this);
339
+ // An Invalid Date formats as "Invalid Date" on the host too, and NaN cannot cross as a
340
+ // number \u2014 so it is answered here rather than sent, matching what node:vm returns.
341
+ if (t !== t) return "Invalid Date";
342
+ return L(kind, t, encLocales(locales), enc(pick(options, DTF)));
343
+ };
344
+ };
345
+ $Date.prototype.toLocaleString = toLocale("a");
346
+ $Date.prototype.toLocaleDateString = toLocale("d");
347
+ $Date.prototype.toLocaleTimeString = toLocale("t");
348
+ })();
349
+ `;
350
+ function installIntl(ctx) {
351
+ const parse = (s) => {
352
+ if (!s) return void 0;
353
+ try {
354
+ return JSON.parse(
355
+ s,
356
+ (_k, val) => typeof val === "string" && val.startsWith(NONFINITE_TAG) ? Number(val.slice(NONFINITE_TAG.length)) : val
357
+ );
358
+ } catch {
359
+ return void 0;
360
+ }
361
+ };
362
+ const hooks = [
363
+ [
364
+ "__himiIntlDate",
365
+ (l, o, t) => {
366
+ const fmt = new Intl.DateTimeFormat(
367
+ parse(ctx.getString(l)),
368
+ parse(ctx.getString(o))
369
+ );
370
+ return ctx.newString(fmt.format(new Date(ctx.getNumber(t))));
371
+ }
372
+ ],
373
+ [
374
+ // `Date.prototype.toLocale*` is NOT `Intl.DateTimeFormat`, and missing that was a real defect
375
+ // shipped in #1684: QuickJS-ng implements these three natively with no ICU, so it accepts the
376
+ // options argument and then IGNORES it. Measured against node:vm on the sync realm, before
377
+ // this hook existed:
378
+ //
379
+ // toLocaleTimeString("en-US", {hour:"numeric",minute:"2-digit"})
380
+ // node:vm "2:00 AM" realm "02:00:00 AM"
381
+ // toLocaleDateString("en-US", {month:"short"})
382
+ // node:vm "Jan" realm "01/01/1970"
383
+ //
384
+ // A wrong LABEL, silently — no error, and invisible to a render test, which is the class this
385
+ // whole bridge exists to close. Bundles reach for `toLocaleTimeString` at least as often as
386
+ // for `Intl.DateTimeFormat`, so covering only the latter closed half the hole.
387
+ //
388
+ // The HOST does the defaulting rather than the guest reimplementing ECMA-402's
389
+ // ToDateTimeOptions: node is the reference implementation, so calling the very method the
390
+ // guest called is correct by construction and cannot drift from it.
391
+ "__himiIntlToLocale",
392
+ (k, t, l, o) => {
393
+ const kind = ctx.getString(k);
394
+ const date = new Date(ctx.getNumber(t));
395
+ const locales = parse(ctx.getString(l));
396
+ const options = parse(ctx.getString(o));
397
+ const out = kind === "d" ? date.toLocaleDateString(locales, options) : kind === "t" ? date.toLocaleTimeString(locales, options) : date.toLocaleString(locales, options);
398
+ return ctx.newString(out);
399
+ }
400
+ ],
401
+ [
402
+ "__himiIntlNumber",
403
+ (l, o, v, k) => {
404
+ const fmt = new Intl.NumberFormat(
405
+ parse(ctx.getString(l)),
406
+ parse(ctx.getString(o))
407
+ );
408
+ const raw = ctx.getString(v);
409
+ const kind = k === void 0 ? "n" : ctx.getString(k);
410
+ const value = kind === "b" ? BigInt(raw) : kind === "s" ? raw : Number(raw);
411
+ return ctx.newString(fmt.format(value));
412
+ }
413
+ ],
414
+ [
415
+ "__himiIntlCompare",
416
+ (a, b, l, o) => {
417
+ const collator = new Intl.Collator(
418
+ parse(ctx.getString(l)),
419
+ parse(o === void 0 ? "" : ctx.getString(o))
420
+ );
421
+ return ctx.newNumber(collator.compare(ctx.getString(a), ctx.getString(b)));
422
+ }
423
+ ],
424
+ [
425
+ // Construct-and-discard on the host, purely for its throw. Host Intl validates at
426
+ // CONSTRUCTION; the guest constructors call this so a bad locale or option bag fails at
427
+ // the same moment it would under node:vm, rather than surviving until a format call the
428
+ // crawled path may never reach.
429
+ "__himiIntlValidate",
430
+ (k, l, o) => {
431
+ const locales = parse(ctx.getString(l));
432
+ const options = parse(ctx.getString(o));
433
+ switch (ctx.getString(k)) {
434
+ case "DateTimeFormat":
435
+ new Intl.DateTimeFormat(locales, options);
436
+ break;
437
+ case "NumberFormat":
438
+ new Intl.NumberFormat(locales, options);
439
+ break;
440
+ default:
441
+ new Intl.Collator(locales, options);
442
+ }
443
+ return ctx.undefined;
444
+ }
445
+ ]
446
+ ];
447
+ for (const [name, fn] of hooks) {
448
+ const handle = ctx.newFunction(name, fn);
449
+ ctx.setProp(ctx.global, name, handle);
450
+ handle.dispose();
451
+ }
452
+ const res = ctx.evalCode(INTL_SHIM, "himi-intl.js");
453
+ if (res.error) {
454
+ const detail = ctx.dump(res.error);
455
+ res.error.dispose();
456
+ throw new Error(`Intl shim failed: ${String(detail?.message ?? detail)}`);
457
+ }
458
+ res.value.dispose();
459
+ }
460
+ export {
461
+ installIntl
462
+ };