regor 1.4.5 → 1.4.7

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.
@@ -137,7 +137,180 @@ var callUnmounted = (context) => {
137
137
  context.unmounted?.();
138
138
  };
139
139
 
140
+ // src/log/warnings.ts
141
+ var warnings = {
142
+ [8 /* ModelRequiresRef */]: (el) => `Model binding requires a ref at ${el.outerHTML}`,
143
+ [7 /* ModelNotSupportOnElement */]: (el) => `Model binding is not supported on ${el.tagName} element at ${el.outerHTML}`,
144
+ [0 /* MissingBindingExpression */]: (name, el) => `${name} binding expression is missing at ${el.outerHTML}`,
145
+ [1 /* InvalidForExpression */]: (name, forPath, el) => `invalid ${name} expression: ${forPath} at ${el.outerHTML}`,
146
+ [2 /* BindingRequiresObjectExpressions */]: (name, el) => `${name} requires object expression at ${el.outerHTML}`,
147
+ [3 /* KeyIsEmpty */]: (name, el) => `${name} binder: key is empty on ${el.outerHTML}.`,
148
+ [4 /* PropertyAssignmentFailed */]: (key, tag, value, e) => ({
149
+ msg: `Failed setting prop "${key}" on <${tag.toLowerCase()}>: value ${value} is invalid.`,
150
+ args: [e]
151
+ }),
152
+ [5 /* MissingEventType */]: (name, el) => `${name} binding missing event type at ${el.outerHTML}`,
153
+ [6 /* ErrorLog */]: (msg, e) => ({ msg, args: [e] })
154
+ };
155
+ var warning = (type, ...args) => {
156
+ const msg = warnings[type];
157
+ const item = isFunction(msg) ? msg.call(warnings, ...args) : msg;
158
+ const handler = warningHandler.warning;
159
+ if (!handler) return;
160
+ if (isString(item)) handler(item);
161
+ else handler(item, ...item.args);
162
+ };
163
+ var warningHandler = {
164
+ warning: console.warn
165
+ };
166
+
167
+ // src/reactivity/refSymbols.ts
168
+ var refSymbol = Symbol("ref");
169
+ var srefSymbol = Symbol("sref");
170
+ var rawSymbol = Symbol("raw");
171
+
172
+ // src/reactivity/isRef.ts
173
+ var isRef = (value) => {
174
+ return value != null && value[srefSymbol] === 1;
175
+ };
176
+
177
+ // src/app/propValidators.ts
178
+ var PropValidationError = class extends Error {
179
+ propPath;
180
+ detail;
181
+ constructor(propPath, detail) {
182
+ super(detail);
183
+ this.name = "PropValidationError";
184
+ this.propPath = propPath;
185
+ this.detail = detail;
186
+ }
187
+ };
188
+ var fail = (name, message) => {
189
+ throw new PropValidationError(name, `${message}.`);
190
+ };
191
+ var describeValue = (value) => {
192
+ if (value === null) return "null";
193
+ if (value === void 0) return "undefined";
194
+ if (typeof value === "string") return "string";
195
+ if (typeof value === "number") return "number";
196
+ if (typeof value === "boolean") return "boolean";
197
+ if (typeof value === "bigint") return "bigint";
198
+ if (typeof value === "symbol") return "symbol";
199
+ if (typeof value === "function") return "function";
200
+ if (isArray(value)) return "array";
201
+ if (value instanceof Date) return "Date";
202
+ if (value instanceof RegExp) return "RegExp";
203
+ if (value instanceof Map) return "Map";
204
+ if (value instanceof Set) return "Set";
205
+ const ctorName = value?.constructor?.name;
206
+ return ctorName && ctorName !== "Object" ? ctorName : "object";
207
+ };
208
+ var formatLiteral = (value) => {
209
+ if (typeof value === "string") return `"${value}"`;
210
+ if (typeof value === "number" || typeof value === "boolean") {
211
+ return String(value);
212
+ }
213
+ if (value === null) return "null";
214
+ if (value === void 0) return "undefined";
215
+ return describeValue(value);
216
+ };
217
+ var isString2 = (value, name) => {
218
+ if (typeof value !== "string") fail(name, "expected string");
219
+ };
220
+ var isNumber = (value, name) => {
221
+ if (typeof value !== "number") fail(name, "expected number");
222
+ };
223
+ var isBoolean = (value, name) => {
224
+ if (typeof value !== "boolean") fail(name, "expected boolean");
225
+ };
226
+ var isClass = (ctor) => {
227
+ return (value, name) => {
228
+ if (!(value instanceof ctor)) {
229
+ fail(name, `expected instance of ${ctor.name || "provided class"}`);
230
+ }
231
+ };
232
+ };
233
+ var optional = (validator) => {
234
+ return (value, name, head) => {
235
+ if (value === void 0) return;
236
+ validator(value, name, head);
237
+ };
238
+ };
239
+ var nullable = (validator) => {
240
+ return (value, name, head) => {
241
+ if (value === null) return;
242
+ validator(value, name, head);
243
+ };
244
+ };
245
+ var oneOf = (values) => {
246
+ return (value, name) => {
247
+ if (values.includes(value)) return;
248
+ fail(
249
+ name,
250
+ `expected one of ${values.map((x) => formatLiteral(x)).join(", ")}`
251
+ );
252
+ };
253
+ };
254
+ var arrayOf = (validator) => {
255
+ return (value, name, head) => {
256
+ if (!isArray(value)) fail(name, "expected array");
257
+ const items = value;
258
+ for (let i = 0; i < items.length; ++i) {
259
+ validator(items[i], `${name}[${i}]`, head);
260
+ }
261
+ };
262
+ };
263
+ var shape = (schema) => {
264
+ return (value, name, head) => {
265
+ if (!isObject(value)) fail(name, "expected object");
266
+ const record = value;
267
+ for (const key in schema) {
268
+ const validator = schema[key];
269
+ validator(record[key], `${name}.${key}`, head);
270
+ }
271
+ };
272
+ };
273
+ var refOf = (validator) => {
274
+ return (value, name, head) => {
275
+ if (!isRef(value)) fail(name, "expected ref");
276
+ const refValue = value;
277
+ validator(refValue(), `${name}.value`, head);
278
+ };
279
+ };
280
+ var pval = {
281
+ fail,
282
+ isString: isString2,
283
+ isNumber,
284
+ isBoolean,
285
+ isClass,
286
+ optional,
287
+ nullable,
288
+ oneOf,
289
+ arrayOf,
290
+ shape,
291
+ refOf
292
+ };
293
+
140
294
  // src/app/ComponentHead.ts
295
+ var formatComponentValidationError = (element, propName, error) => {
296
+ const tagName = element.tagName?.toLowerCase?.() || "unknown";
297
+ const finalPropName = error instanceof PropValidationError ? error.propPath : propName;
298
+ const detail = error instanceof PropValidationError ? error.detail : error instanceof Error ? error.message : String(error);
299
+ if (error instanceof Error) {
300
+ return new Error(
301
+ `Invalid prop "${finalPropName}" on <${tagName}>: ${detail}`,
302
+ {
303
+ cause: error
304
+ }
305
+ );
306
+ }
307
+ return new Error(
308
+ `Invalid prop "${finalPropName}" on <${tagName}>: ${detail}`,
309
+ {
310
+ cause: error
311
+ }
312
+ );
313
+ };
141
314
  var ComponentHead = class {
142
315
  /**
143
316
  * Values provided by parent for this component instance.
@@ -225,12 +398,18 @@ var ComponentHead = class {
225
398
  * @internal
226
399
  */
227
400
  __element;
228
- constructor(props, element, ctx, start, end) {
401
+ /**
402
+ * Runtime behavior used when `validateProps(...)` encounters invalid input.
403
+ * Defaults to `'throw'`.
404
+ */
405
+ __propValidationMode;
406
+ constructor(props, element, ctx, start, end, propValidationMode) {
229
407
  this.props = props;
230
408
  this.__element = element;
231
409
  this.ctx = ctx;
232
410
  this.start = start;
233
411
  this.end = end;
412
+ this.__propValidationMode = propValidationMode;
234
413
  }
235
414
  /**
236
415
  * Emits a custom DOM event from the component host element.
@@ -309,6 +488,61 @@ var ComponentHead = class {
309
488
  `${constructor} was not found in the context stack at occurrence ${occurrence}.`
310
489
  );
311
490
  }
491
+ /**
492
+ * Validates selected incoming props using assertion-style validators.
493
+ *
494
+ * Only keys listed in `schema` are checked. Validation throws immediately
495
+ * on the first invalid prop and does not mutate `head.props`.
496
+ *
497
+ * The schema is keyed from `head.props`, so editor completion can suggest
498
+ * known prop names while still allowing you to validate only a subset.
499
+ *
500
+ * Validators typically come from `pval`, but custom user validators are also
501
+ * supported. Custom validators may throw their own `Error`, though `pval.fail(...)`
502
+ * is recommended so nested validators can preserve the exact failing prop path.
503
+ *
504
+ * Example:
505
+ * ```ts
506
+ * head.validateProps({
507
+ * title: pval.isString,
508
+ * count: pval.optional(pval.isNumber),
509
+ * })
510
+ * ```
511
+ *
512
+ * Example with a custom validator:
513
+ * ```ts
514
+ * const isNonEmptyString: PropValidator<string> = (value, name) => {
515
+ * if (typeof value !== 'string' || value.trim() === '') {
516
+ * pval.fail(name, 'expected non-empty string')
517
+ * }
518
+ * }
519
+ * ```
520
+ *
521
+ * @param schema - Validators to apply to selected incoming props.
522
+ */
523
+ validateProps(schema) {
524
+ if (this.__propValidationMode === "off") return;
525
+ const props = this.props;
526
+ for (const name in schema) {
527
+ const validator = schema[name];
528
+ if (!validator) continue;
529
+ const validateProp = validator;
530
+ try {
531
+ validateProp(props[name], name, this);
532
+ } catch (error) {
533
+ const enrichedError = formatComponentValidationError(
534
+ this.__element,
535
+ name,
536
+ error
537
+ );
538
+ if (this.__propValidationMode === "warn") {
539
+ warningHandler.warning(enrichedError.message, enrichedError);
540
+ continue;
541
+ }
542
+ throw enrichedError;
543
+ }
544
+ }
545
+ }
312
546
  /**
313
547
  * Unmounts this component instance by removing nodes between `start` and `end`
314
548
  * and calling unmount lifecycle handlers for captured contexts.
@@ -342,33 +576,6 @@ var addUnbinder = (node, unbinder) => {
342
576
  getBindData(node).unbinders.push(unbinder);
343
577
  };
344
578
 
345
- // src/log/warnings.ts
346
- var warnings = {
347
- [8 /* ModelRequiresRef */]: (el) => `Model binding requires a ref at ${el.outerHTML}`,
348
- [7 /* ModelNotSupportOnElement */]: (el) => `Model binding is not supported on ${el.tagName} element at ${el.outerHTML}`,
349
- [0 /* MissingBindingExpression */]: (name, el) => `${name} binding expression is missing at ${el.outerHTML}`,
350
- [1 /* InvalidForExpression */]: (name, forPath, el) => `invalid ${name} expression: ${forPath} at ${el.outerHTML}`,
351
- [2 /* BindingRequiresObjectExpressions */]: (name, el) => `${name} requires object expression at ${el.outerHTML}`,
352
- [3 /* KeyIsEmpty */]: (name, el) => `${name} binder: key is empty on ${el.outerHTML}.`,
353
- [4 /* PropertyAssignmentFailed */]: (key, tag, value, e) => ({
354
- msg: `Failed setting prop "${key}" on <${tag.toLowerCase()}>: value ${value} is invalid.`,
355
- args: [e]
356
- }),
357
- [5 /* MissingEventType */]: (name, el) => `${name} binding missing event type at ${el.outerHTML}`,
358
- [6 /* ErrorLog */]: (msg, e) => ({ msg, args: [e] })
359
- };
360
- var warning = (type, ...args) => {
361
- const msg = warnings[type];
362
- const item = isFunction(msg) ? msg.call(warnings, ...args) : msg;
363
- const handler = warningHandler.warning;
364
- if (!handler) return;
365
- if (isString(item)) handler(item);
366
- else handler(item, ...item.args);
367
- };
368
- var warningHandler = {
369
- warning: console.warn
370
- };
371
-
372
579
  // src/bind/switch.ts
373
580
  var switches = {};
374
581
  var switchCounter = {};
@@ -772,16 +979,6 @@ var isScope = (value) => {
772
979
  return scopeSymbol2 in value;
773
980
  };
774
981
 
775
- // src/reactivity/refSymbols.ts
776
- var refSymbol = Symbol("ref");
777
- var srefSymbol = Symbol("sref");
778
- var rawSymbol = Symbol("raw");
779
-
780
- // src/reactivity/isRef.ts
781
- var isRef = (value) => {
782
- return value != null && value[srefSymbol] === 1;
783
- };
784
-
785
982
  // src/directives/context.ts
786
983
  var contextDirective = {
787
984
  collectRefObj: true,
@@ -1349,7 +1546,8 @@ var ComponentBinder = class {
1349
1546
  component,
1350
1547
  capturedContext,
1351
1548
  startOfComponent,
1352
- endOfComponent
1549
+ endOfComponent,
1550
+ binder.__config.propValidationMode
1353
1551
  );
1354
1552
  const componentCtx2 = useScope(() => {
1355
1553
  return registeredComponent.context(head2) ?? {};
@@ -2865,11 +3063,11 @@ var patchAttribute = (el, key, value, previousKey) => {
2865
3063
  }
2866
3064
  return;
2867
3065
  }
2868
- const isBoolean = key in booleanAttributes;
2869
- if (isNullOrUndefined(value) || isBoolean && !includeBooleanAttr(value)) {
3066
+ const isBoolean2 = key in booleanAttributes;
3067
+ if (isNullOrUndefined(value) || isBoolean2 && !includeBooleanAttr(value)) {
2870
3068
  el.removeAttribute(key);
2871
3069
  } else {
2872
- el.setAttribute(key, isBoolean ? "" : value);
3070
+ el.setAttribute(key, isBoolean2 ? "" : value);
2873
3071
  }
2874
3072
  };
2875
3073
 
@@ -3119,7 +3317,7 @@ var decimalSeparators = /[.,' ·٫]/;
3119
3317
  var handleInputAndTextArea = (el, flags, getModelRef, parsedValue) => {
3120
3318
  const isLazy = flags.lazy;
3121
3319
  const eventType = isLazy ? "change" : "input";
3122
- const isNumber = isNumberInput(el);
3320
+ const isNumber2 = isNumberInput(el);
3123
3321
  const trimmer = () => {
3124
3322
  if (!flags.trim && !getFlags(parsedValue()[1]).trim) return;
3125
3323
  el.value = el.value.trim();
@@ -3149,7 +3347,7 @@ var handleInputAndTextArea = (el, flags, getModelRef, parsedValue) => {
3149
3347
  if (!target || target.composing) return;
3150
3348
  let value = target.value;
3151
3349
  const flags2 = getFlags(parsedValue()[1]);
3152
- if (isNumber || flags2.number || flags2.int) {
3350
+ if (isNumber2 || flags2.number || flags2.int) {
3153
3351
  if (flags2.int) {
3154
3352
  value = parseInt(value);
3155
3353
  } else {
@@ -3763,6 +3961,15 @@ var RegorConfig = class _RegorConfig {
3763
3961
  forGrowThreshold = 10;
3764
3962
  globalContext;
3765
3963
  useInterpolation = true;
3964
+ /**
3965
+ * Controls how `head.validateProps(...)` behaves when a validator fails.
3966
+ *
3967
+ * - `'throw'` (default): rethrows the validation error immediately.
3968
+ * - `'warn'`: forwards the validation error to `warningHandler.warning(...)`
3969
+ * and continues.
3970
+ * - `'off'`: skips runtime prop validation entirely.
3971
+ */
3972
+ propValidationMode = "throw";
3766
3973
  constructor(globalContext) {
3767
3974
  this.setDirectives("r-");
3768
3975
  if (globalContext) {
@@ -4454,12 +4661,12 @@ var Jsep = class {
4454
4661
  this.__gobbleSpaces();
4455
4662
  let ch = this.__code;
4456
4663
  while (ch === PERIOD_CODE || ch === OBRACK_CODE || ch === OPAREN_CODE || ch === QUMARK_CODE) {
4457
- let optional;
4664
+ let optional2;
4458
4665
  if (ch === QUMARK_CODE) {
4459
4666
  if (this.__expr.charCodeAt(this.__index + 1) !== PERIOD_CODE) {
4460
4667
  break;
4461
4668
  }
4462
- optional = true;
4669
+ optional2 = true;
4463
4670
  this.__index += 2;
4464
4671
  this.__gobbleSpaces();
4465
4672
  ch = this.__code;
@@ -4485,7 +4692,7 @@ var Jsep = class {
4485
4692
  callee: node
4486
4693
  };
4487
4694
  } else {
4488
- if (optional) {
4695
+ if (optional2) {
4489
4696
  this.__index--;
4490
4697
  }
4491
4698
  this.__gobbleSpaces();
@@ -4496,7 +4703,7 @@ var Jsep = class {
4496
4703
  property: this.__gobbleIdentifier()
4497
4704
  };
4498
4705
  }
4499
- if (optional) {
4706
+ if (optional2) {
4500
4707
  node.optional = true;
4501
4708
  }
4502
4709
  this.__gobbleSpaces();
@@ -6350,6 +6557,7 @@ export {
6350
6557
  onUnmounted,
6351
6558
  pause,
6352
6559
  persist,
6560
+ pval,
6353
6561
  raw,
6354
6562
  ref,
6355
6563
  removeNode,