@odoo/owl 2.0.0-beta-12 → 2.0.0-beta-16

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/owl.iife.js CHANGED
@@ -80,6 +80,68 @@
80
80
  return new VToggler(key, child);
81
81
  }
82
82
 
83
+ // Custom error class that wraps error that happen in the owl lifecycle
84
+ class OwlError extends Error {
85
+ }
86
+ // Maps fibers to thrown errors
87
+ const fibersInError = new WeakMap();
88
+ const nodeErrorHandlers = new WeakMap();
89
+ function _handleError(node, error) {
90
+ if (!node) {
91
+ return false;
92
+ }
93
+ const fiber = node.fiber;
94
+ if (fiber) {
95
+ fibersInError.set(fiber, error);
96
+ }
97
+ const errorHandlers = nodeErrorHandlers.get(node);
98
+ if (errorHandlers) {
99
+ let handled = false;
100
+ // execute in the opposite order
101
+ for (let i = errorHandlers.length - 1; i >= 0; i--) {
102
+ try {
103
+ errorHandlers[i](error);
104
+ handled = true;
105
+ break;
106
+ }
107
+ catch (e) {
108
+ error = e;
109
+ }
110
+ }
111
+ if (handled) {
112
+ return true;
113
+ }
114
+ }
115
+ return _handleError(node.parent, error);
116
+ }
117
+ function handleError(params) {
118
+ let { error } = params;
119
+ // Wrap error if it wasn't wrapped by wrapError (ie when not in dev mode)
120
+ if (!(error instanceof OwlError)) {
121
+ error = Object.assign(new OwlError(`An error occured in the owl lifecycle (see this Error's "cause" property)`), { cause: error });
122
+ }
123
+ const node = "node" in params ? params.node : params.fiber.node;
124
+ const fiber = "fiber" in params ? params.fiber : node.fiber;
125
+ // resets the fibers on components if possible. This is important so that
126
+ // new renderings can be properly included in the initial one, if any.
127
+ let current = fiber;
128
+ do {
129
+ current.node.fiber = current;
130
+ current = current.parent;
131
+ } while (current);
132
+ fibersInError.set(fiber.root, error);
133
+ const handled = _handleError(node, error);
134
+ if (!handled) {
135
+ console.warn(`[Owl] Unhandled error. Destroying the root component`);
136
+ try {
137
+ node.app.destroy();
138
+ }
139
+ catch (e) {
140
+ console.error(e);
141
+ }
142
+ }
143
+ }
144
+
83
145
  const { setAttribute: elemSetAttribute, removeAttribute } = Element.prototype;
84
146
  const tokenList = DOMTokenList.prototype;
85
147
  const tokenListAdd = tokenList.add;
@@ -217,7 +279,7 @@
217
279
  function makePropSetter(name) {
218
280
  return function setProp(value) {
219
281
  // support 0, fallback to empty string for other falsy values
220
- this[name] = value === 0 ? 0 : value || "";
282
+ this[name] = value === 0 ? 0 : value ? value.valueOf() : "";
221
283
  };
222
284
  }
223
285
  function isProp(tag, key) {
@@ -701,7 +763,7 @@
701
763
  };
702
764
  }
703
765
  }
704
- throw new Error("boom");
766
+ throw new OwlError("boom");
705
767
  }
706
768
  function addRef(tree) {
707
769
  tree.isRef = true;
@@ -1385,61 +1447,6 @@
1385
1447
  vnode.remove();
1386
1448
  }
1387
1449
 
1388
- // Maps fibers to thrown errors
1389
- const fibersInError = new WeakMap();
1390
- const nodeErrorHandlers = new WeakMap();
1391
- function _handleError(node, error) {
1392
- if (!node) {
1393
- return false;
1394
- }
1395
- const fiber = node.fiber;
1396
- if (fiber) {
1397
- fibersInError.set(fiber, error);
1398
- }
1399
- const errorHandlers = nodeErrorHandlers.get(node);
1400
- if (errorHandlers) {
1401
- let handled = false;
1402
- // execute in the opposite order
1403
- for (let i = errorHandlers.length - 1; i >= 0; i--) {
1404
- try {
1405
- errorHandlers[i](error);
1406
- handled = true;
1407
- break;
1408
- }
1409
- catch (e) {
1410
- error = e;
1411
- }
1412
- }
1413
- if (handled) {
1414
- return true;
1415
- }
1416
- }
1417
- return _handleError(node.parent, error);
1418
- }
1419
- function handleError(params) {
1420
- const error = params.error;
1421
- const node = "node" in params ? params.node : params.fiber.node;
1422
- const fiber = "fiber" in params ? params.fiber : node.fiber;
1423
- // resets the fibers on components if possible. This is important so that
1424
- // new renderings can be properly included in the initial one, if any.
1425
- let current = fiber;
1426
- do {
1427
- current.node.fiber = current;
1428
- current = current.parent;
1429
- } while (current);
1430
- fibersInError.set(fiber.root, error);
1431
- const handled = _handleError(node, error);
1432
- if (!handled) {
1433
- console.warn(`[Owl] Unhandled error. Destroying the root component`);
1434
- try {
1435
- node.app.destroy();
1436
- }
1437
- catch (e) {
1438
- console.error(e);
1439
- }
1440
- }
1441
- }
1442
-
1443
1450
  function makeChildFiber(node, parent) {
1444
1451
  let current = node.fiber;
1445
1452
  if (current) {
@@ -1478,7 +1485,7 @@
1478
1485
  return fiber;
1479
1486
  }
1480
1487
  function throwOnRender() {
1481
- throw new Error("Attempted to render cancelled fiber");
1488
+ throw new OwlError("Attempted to render cancelled fiber");
1482
1489
  }
1483
1490
  /**
1484
1491
  * @returns number of not-yet rendered fibers cancelled
@@ -1855,7 +1862,7 @@
1855
1862
  */
1856
1863
  function reactive(target, callback = () => { }) {
1857
1864
  if (!canBeMadeReactive(target)) {
1858
- throw new Error(`Cannot make the given value reactive`);
1865
+ throw new OwlError(`Cannot make the given value reactive`);
1859
1866
  }
1860
1867
  if (SKIP in target) {
1861
1868
  return target;
@@ -2124,10 +2131,10 @@
2124
2131
  }
2125
2132
  function validateTarget(target) {
2126
2133
  if (!(target instanceof HTMLElement)) {
2127
- throw new Error("Cannot mount component: the target is not a valid DOM element");
2134
+ throw new OwlError("Cannot mount component: the target is not a valid DOM element");
2128
2135
  }
2129
2136
  if (!document.body.contains(target)) {
2130
- throw new Error("Cannot mount a component on a detached dom node");
2137
+ throw new OwlError("Cannot mount a component on a detached dom node");
2131
2138
  }
2132
2139
  }
2133
2140
  class EventBus extends EventTarget {
@@ -2148,7 +2155,7 @@
2148
2155
  async function loadFile(url) {
2149
2156
  const result = await fetch(url);
2150
2157
  if (!result.ok) {
2151
- throw new Error("Error while fetching xml templates");
2158
+ throw new OwlError("Error while fetching xml templates");
2152
2159
  }
2153
2160
  return await result.text();
2154
2161
  }
@@ -2170,7 +2177,7 @@
2170
2177
  let currentNode = null;
2171
2178
  function getCurrent() {
2172
2179
  if (!currentNode) {
2173
- throw new Error("No active component (a hook function should only be called in 'setup')");
2180
+ throw new OwlError("No active component (a hook function should only be called in 'setup')");
2174
2181
  }
2175
2182
  return currentNode;
2176
2183
  }
@@ -2232,7 +2239,6 @@
2232
2239
  this.parent = parent;
2233
2240
  this.props = props;
2234
2241
  this.parentKey = parentKey;
2235
- this.level = parent ? parent.level + 1 : 0;
2236
2242
  const defaultProps = C.defaultProps;
2237
2243
  props = Object.assign({}, props);
2238
2244
  if (defaultProps) {
@@ -2465,17 +2471,27 @@
2465
2471
 
2466
2472
  const TIMEOUT = Symbol("timeout");
2467
2473
  function wrapError(fn, hookName) {
2468
- const error = new Error(`The following error occurred in ${hookName}: `);
2469
- const timeoutError = new Error(`${hookName}'s promise hasn't resolved after 3 seconds`);
2474
+ const error = new OwlError(`The following error occurred in ${hookName}: `);
2475
+ const timeoutError = new OwlError(`${hookName}'s promise hasn't resolved after 3 seconds`);
2470
2476
  const node = getCurrent();
2471
2477
  return (...args) => {
2478
+ const onError = (cause) => {
2479
+ error.cause = cause;
2480
+ if (cause instanceof Error) {
2481
+ error.message += `"${cause.message}"`;
2482
+ }
2483
+ else {
2484
+ error.message = `Something that is not an Error was thrown in ${hookName} (see this Error's "cause" property)`;
2485
+ }
2486
+ throw error;
2487
+ };
2472
2488
  try {
2473
2489
  const result = fn(...args);
2474
2490
  if (result instanceof Promise) {
2475
2491
  if (hookName === "onWillStart" || hookName === "onWillUpdateProps") {
2476
2492
  const fiber = node.fiber;
2477
2493
  Promise.race([
2478
- result,
2494
+ result.catch(() => { }),
2479
2495
  new Promise((resolve) => setTimeout(() => resolve(TIMEOUT), 3000)),
2480
2496
  ]).then((res) => {
2481
2497
  if (res === TIMEOUT && node.fiber === fiber) {
@@ -2483,21 +2499,12 @@
2483
2499
  }
2484
2500
  });
2485
2501
  }
2486
- return result.catch((cause) => {
2487
- error.cause = cause;
2488
- if (cause instanceof Error) {
2489
- error.message += `"${cause.message}"`;
2490
- }
2491
- throw error;
2492
- });
2502
+ return result.catch(onError);
2493
2503
  }
2494
2504
  return result;
2495
2505
  }
2496
2506
  catch (cause) {
2497
- if (cause instanceof Error) {
2498
- error.message += `"${cause.message}"`;
2499
- }
2500
- throw error;
2507
+ onError(cause);
2501
2508
  }
2502
2509
  };
2503
2510
  }
@@ -2601,7 +2608,7 @@
2601
2608
  }
2602
2609
  this.target = el && el.querySelector(this.selector);
2603
2610
  if (!this.target) {
2604
- throw new Error("invalid portal target");
2611
+ throw new OwlError("invalid portal target");
2605
2612
  }
2606
2613
  }
2607
2614
  this.realBDom.mount(this.target, null);
@@ -2695,7 +2702,7 @@
2695
2702
  function validate(obj, spec) {
2696
2703
  let errors = validateSchema(obj, spec);
2697
2704
  if (errors.length) {
2698
- throw new Error("Invalid object: " + errors.join(", "));
2705
+ throw new OwlError("Invalid object: " + errors.join(", "));
2699
2706
  }
2700
2707
  }
2701
2708
  /**
@@ -2848,7 +2855,7 @@
2848
2855
  keys = Object.values(collection);
2849
2856
  }
2850
2857
  else {
2851
- throw new Error("Invalid loop expression");
2858
+ throw new OwlError("Invalid loop expression");
2852
2859
  }
2853
2860
  const n = values.length;
2854
2861
  return [keys, values, n, new Array(n)];
@@ -2954,7 +2961,7 @@
2954
2961
  if (el) {
2955
2962
  count++;
2956
2963
  if (count > 1) {
2957
- throw new Error("Cannot have 2 elements with same ref name at the same time");
2964
+ throw new OwlError("Cannot have 2 elements with same ref name at the same time");
2958
2965
  }
2959
2966
  }
2960
2967
  if (count === 0 || el) {
@@ -2991,13 +2998,13 @@
2991
2998
  : name in schema && !("*" in schema) && !isOptional(schema[name]);
2992
2999
  for (let p in defaultProps) {
2993
3000
  if (isMandatory(p)) {
2994
- throw new Error(`A default value cannot be defined for a mandatory prop (name: '${p}', component: ${ComponentClass.name})`);
3001
+ throw new OwlError(`A default value cannot be defined for a mandatory prop (name: '${p}', component: ${ComponentClass.name})`);
2995
3002
  }
2996
3003
  }
2997
3004
  }
2998
3005
  const errors = validateSchema(props, schema);
2999
3006
  if (errors.length) {
3000
- throw new Error(`Invalid props for component '${ComponentClass.name}': ` + errors.join(", "));
3007
+ throw new OwlError(`Invalid props for component '${ComponentClass.name}': ` + errors.join(", "));
3001
3008
  }
3002
3009
  }
3003
3010
  const helpers = {
@@ -3018,6 +3025,7 @@
3018
3025
  bind,
3019
3026
  createCatcher,
3020
3027
  markRaw,
3028
+ OwlError,
3021
3029
  };
3022
3030
 
3023
3031
  const bdom = { text, createBlock, list, multi, html, toggler, comment };
@@ -3045,7 +3053,7 @@
3045
3053
  }
3046
3054
  }
3047
3055
  }
3048
- throw new Error(msg);
3056
+ throw new OwlError(msg);
3049
3057
  }
3050
3058
  return doc;
3051
3059
  }
@@ -3076,7 +3084,7 @@
3076
3084
  if (currentAsString === newAsString) {
3077
3085
  return;
3078
3086
  }
3079
- throw new Error(`Template ${name} already defined with different content`);
3087
+ throw new OwlError(`Template ${name} already defined with different content`);
3080
3088
  }
3081
3089
  this.rawTemplates[name] = template;
3082
3090
  }
@@ -3101,7 +3109,7 @@
3101
3109
  extraInfo = ` (for component "${componentName}")`;
3102
3110
  }
3103
3111
  catch { }
3104
- throw new Error(`Missing template: "${name}"${extraInfo}`);
3112
+ throw new OwlError(`Missing template: "${name}"${extraInfo}`);
3105
3113
  }
3106
3114
  const isFn = typeof rawTemplate === "function" && !(rawTemplate instanceof Element);
3107
3115
  const templateFn = isFn ? rawTemplate : this._compileTemplate(name, rawTemplate);
@@ -3117,7 +3125,7 @@
3117
3125
  return this.templates[name];
3118
3126
  }
3119
3127
  _compileTemplate(name, template) {
3120
- throw new Error(`Unable to compile a template. Please use owl full build instead`);
3128
+ throw new OwlError(`Unable to compile a template. Please use owl full build instead`);
3121
3129
  }
3122
3130
  callTemplate(owner, subTemplate, ctx, parent, key) {
3123
3131
  const template = this.getTemplate(subTemplate);
@@ -3199,14 +3207,14 @@
3199
3207
  i++;
3200
3208
  cur = expr[i];
3201
3209
  if (!cur) {
3202
- throw new Error("Invalid expression");
3210
+ throw new OwlError("Invalid expression");
3203
3211
  }
3204
3212
  s += cur;
3205
3213
  }
3206
3214
  i++;
3207
3215
  }
3208
3216
  if (expr[i] !== start) {
3209
- throw new Error("Invalid expression");
3217
+ throw new OwlError("Invalid expression");
3210
3218
  }
3211
3219
  s += start;
3212
3220
  if (start === "`") {
@@ -3313,7 +3321,7 @@
3313
3321
  error = e; // Silence all errors and throw a generic error below
3314
3322
  }
3315
3323
  if (current.length || error) {
3316
- throw new Error(`Tokenizer error: could not tokenize \`${expr}\``);
3324
+ throw new OwlError(`Tokenizer error: could not tokenize \`${expr}\``);
3317
3325
  }
3318
3326
  return result;
3319
3327
  }
@@ -3864,7 +3872,7 @@
3864
3872
  .slice(1)
3865
3873
  .map((m) => {
3866
3874
  if (!MODS.has(m)) {
3867
- throw new Error(`Unknown event modifier: '${m}'`);
3875
+ throw new OwlError(`Unknown event modifier: '${m}'`);
3868
3876
  }
3869
3877
  return `"${m}"`;
3870
3878
  });
@@ -3906,13 +3914,18 @@
3906
3914
  attrs["block-attribute-" + idx] = attrName;
3907
3915
  }
3908
3916
  else if (key.startsWith("t-att")) {
3917
+ attrName = key === "t-att" ? null : key.slice(6);
3909
3918
  expr = compileExpr(ast.attrs[key]);
3919
+ if (attrName && isProp(ast.tag, attrName)) {
3920
+ // we force a new string or new boolean to bypass the equality check in blockdom when patching same value
3921
+ const C = attrName === "value" ? "String" : "Boolean";
3922
+ expr = `new ${C}(${expr})`;
3923
+ }
3910
3924
  const idx = block.insertData(expr, "attr");
3911
3925
  if (key === "t-att") {
3912
3926
  attrs[`block-attributes`] = String(idx);
3913
3927
  }
3914
3928
  else {
3915
- attrName = key.slice(6);
3916
3929
  attrs[`block-attribute-${idx}`] = attrName;
3917
3930
  }
3918
3931
  }
@@ -4180,7 +4193,8 @@
4180
4193
  this.define(`key${this.target.loopLevel}`, ast.key ? compileExpr(ast.key) : loopVar);
4181
4194
  if (this.dev) {
4182
4195
  // Throw error on duplicate keys in dev mode
4183
- this.addLine(`if (keys${block.id}.has(key${this.target.loopLevel})) { throw new Error(\`Got duplicate key in t-foreach: \${key${this.target.loopLevel}}\`)}`);
4196
+ this.helpers.add("OwlError");
4197
+ this.addLine(`if (keys${block.id}.has(key${this.target.loopLevel})) { throw new OwlError(\`Got duplicate key in t-foreach: \${key${this.target.loopLevel}}\`)}`);
4184
4198
  this.addLine(`keys${block.id}.add(key${this.target.loopLevel});`);
4185
4199
  }
4186
4200
  let id;
@@ -4394,7 +4408,7 @@
4394
4408
  value = `bind(ctx, ${value || undefined})`;
4395
4409
  }
4396
4410
  else {
4397
- throw new Error("Invalid prop suffix");
4411
+ throw new OwlError("Invalid prop suffix");
4398
4412
  }
4399
4413
  }
4400
4414
  name = /^[a-z_]+$/i.test(name) ? name : `'${name}'`;
@@ -4587,9 +4601,6 @@
4587
4601
  }
4588
4602
  }
4589
4603
 
4590
- // -----------------------------------------------------------------------------
4591
- // AST Type definition
4592
- // -----------------------------------------------------------------------------
4593
4604
  // -----------------------------------------------------------------------------
4594
4605
  // Parser
4595
4606
  // -----------------------------------------------------------------------------
@@ -4698,7 +4709,7 @@
4698
4709
  return null;
4699
4710
  }
4700
4711
  if (tagName.startsWith("block-")) {
4701
- throw new Error(`Invalid tag name: '${tagName}'`);
4712
+ throw new OwlError(`Invalid tag name: '${tagName}'`);
4702
4713
  }
4703
4714
  ctx = Object.assign({}, ctx);
4704
4715
  if (tagName === "pre") {
@@ -4717,14 +4728,14 @@
4717
4728
  const value = node.getAttribute(attr);
4718
4729
  if (attr.startsWith("t-on")) {
4719
4730
  if (attr === "t-on") {
4720
- throw new Error("Missing event name with t-on directive");
4731
+ throw new OwlError("Missing event name with t-on directive");
4721
4732
  }
4722
4733
  on = on || {};
4723
4734
  on[attr.slice(5)] = value;
4724
4735
  }
4725
4736
  else if (attr.startsWith("t-model")) {
4726
4737
  if (!["input", "select", "textarea"].includes(tagName)) {
4727
- throw new Error("The t-model directive only works with <input>, <textarea> and <select>");
4738
+ throw new OwlError("The t-model directive only works with <input>, <textarea> and <select>");
4728
4739
  }
4729
4740
  let baseExpr, expr;
4730
4741
  if (hasDotAtTheEnd.test(value)) {
@@ -4738,7 +4749,7 @@
4738
4749
  expr = value.slice(index + 1, -1);
4739
4750
  }
4740
4751
  else {
4741
- throw new Error(`Invalid t-model expression: "${value}" (it should be assignable)`);
4752
+ throw new OwlError(`Invalid t-model expression: "${value}" (it should be assignable)`);
4742
4753
  }
4743
4754
  const typeAttr = node.getAttribute("type");
4744
4755
  const isInput = tagName === "input";
@@ -4768,11 +4779,11 @@
4768
4779
  }
4769
4780
  }
4770
4781
  else if (attr.startsWith("block-")) {
4771
- throw new Error(`Invalid attribute: '${attr}'`);
4782
+ throw new OwlError(`Invalid attribute: '${attr}'`);
4772
4783
  }
4773
4784
  else if (attr !== "t-name") {
4774
4785
  if (attr.startsWith("t-") && !attr.startsWith("t-att")) {
4775
- throw new Error(`Unknown QWeb directive: '${attr}'`);
4786
+ throw new OwlError(`Unknown QWeb directive: '${attr}'`);
4776
4787
  }
4777
4788
  const tModel = ctx.tModelInfo;
4778
4789
  if (tModel && ["t-att-value", "t-attf-value"].includes(attr)) {
@@ -4823,7 +4834,7 @@
4823
4834
  };
4824
4835
  }
4825
4836
  if (ast.type === 11 /* TComponent */) {
4826
- throw new Error("t-esc is not supported on Component nodes");
4837
+ throw new OwlError("t-esc is not supported on Component nodes");
4827
4838
  }
4828
4839
  return tesc;
4829
4840
  }
@@ -4871,7 +4882,7 @@
4871
4882
  node.removeAttribute("t-as");
4872
4883
  const key = node.getAttribute("t-key");
4873
4884
  if (!key) {
4874
- throw new Error(`"Directive t-foreach should always be used with a t-key!" (expression: t-foreach="${collection}" t-as="${elem}")`);
4885
+ throw new OwlError(`"Directive t-foreach should always be used with a t-key!" (expression: t-foreach="${collection}" t-as="${elem}")`);
4875
4886
  }
4876
4887
  node.removeAttribute("t-key");
4877
4888
  const memo = node.getAttribute("t-memo") || "";
@@ -5031,7 +5042,7 @@
5031
5042
  const firstLetter = name[0];
5032
5043
  let isDynamic = node.hasAttribute("t-component");
5033
5044
  if (isDynamic && name !== "t") {
5034
- throw new Error(`Directive 't-component' can only be used on <t> nodes (used on a <${name}>)`);
5045
+ throw new OwlError(`Directive 't-component' can only be used on <t> nodes (used on a <${name}>)`);
5035
5046
  }
5036
5047
  if (!(firstLetter === firstLetter.toUpperCase() || isDynamic)) {
5037
5048
  return null;
@@ -5055,7 +5066,7 @@
5055
5066
  }
5056
5067
  else {
5057
5068
  const message = directiveErrorMap.get(name.split("-").slice(0, 2).join("-"));
5058
- throw new Error(message || `unsupported directive on Component: ${name}`);
5069
+ throw new OwlError(message || `unsupported directive on Component: ${name}`);
5059
5070
  }
5060
5071
  }
5061
5072
  else {
@@ -5070,7 +5081,7 @@
5070
5081
  const slotNodes = Array.from(clone.querySelectorAll("[t-set-slot]"));
5071
5082
  for (let slotNode of slotNodes) {
5072
5083
  if (slotNode.tagName !== "t") {
5073
- throw new Error(`Directive 't-set-slot' can only be used on <t> nodes (used on a <${slotNode.tagName}>)`);
5084
+ throw new OwlError(`Directive 't-set-slot' can only be used on <t> nodes (used on a <${slotNode.tagName}>)`);
5074
5085
  }
5075
5086
  const name = slotNode.getAttribute("t-set-slot");
5076
5087
  // check if this is defined in a sub component (in which case it should
@@ -5235,25 +5246,25 @@
5235
5246
  let nattr = (name) => +!!node.getAttribute(name);
5236
5247
  if (prevElem && (pattr("t-if") || pattr("t-elif"))) {
5237
5248
  if (pattr("t-foreach")) {
5238
- throw new Error("t-if cannot stay at the same level as t-foreach when using t-elif or t-else");
5249
+ throw new OwlError("t-if cannot stay at the same level as t-foreach when using t-elif or t-else");
5239
5250
  }
5240
5251
  if (["t-if", "t-elif", "t-else"].map(nattr).reduce(function (a, b) {
5241
5252
  return a + b;
5242
5253
  }) > 1) {
5243
- throw new Error("Only one conditional branching directive is allowed per node");
5254
+ throw new OwlError("Only one conditional branching directive is allowed per node");
5244
5255
  }
5245
5256
  // All text (with only spaces) and comment nodes (nodeType 8) between
5246
5257
  // branch nodes are removed
5247
5258
  let textNode;
5248
5259
  while ((textNode = node.previousSibling) !== prevElem) {
5249
5260
  if (textNode.nodeValue.trim().length && textNode.nodeType !== 8) {
5250
- throw new Error("text is not allowed between branching directives");
5261
+ throw new OwlError("text is not allowed between branching directives");
5251
5262
  }
5252
5263
  textNode.remove();
5253
5264
  }
5254
5265
  }
5255
5266
  else {
5256
- throw new Error("t-elif and t-else directives must be preceded by a t-if or t-elif directive");
5267
+ throw new OwlError("t-elif and t-else directives must be preceded by a t-if or t-elif directive");
5257
5268
  }
5258
5269
  }
5259
5270
  }
@@ -5269,7 +5280,7 @@
5269
5280
  const elements = [...el.querySelectorAll("[t-esc]")].filter((el) => el.tagName[0] === el.tagName[0].toUpperCase() || el.hasAttribute("t-component"));
5270
5281
  for (const el of elements) {
5271
5282
  if (el.childNodes.length) {
5272
- throw new Error("Cannot have t-esc on a component that already has content");
5283
+ throw new OwlError("Cannot have t-esc on a component that already has content");
5273
5284
  }
5274
5285
  const value = el.getAttribute("t-esc");
5275
5286
  el.removeAttribute("t-esc");
@@ -5321,7 +5332,7 @@
5321
5332
  }
5322
5333
  }
5323
5334
  }
5324
- throw new Error(msg);
5335
+ throw new OwlError(msg);
5325
5336
  }
5326
5337
  return doc;
5327
5338
  }
@@ -5375,7 +5386,7 @@
5375
5386
  if (Object.hasOwnProperty.call(data, 0)) {
5376
5387
  const handler = data[0];
5377
5388
  if (typeof handler !== "function") {
5378
- throw new Error(`Invalid handler (expected a function, received: '${handler}')`);
5389
+ throw new OwlError(`Invalid handler (expected a function, received: '${handler}')`);
5379
5390
  }
5380
5391
  let node = data[1] ? data[1].__owl__ : null;
5381
5392
  if (node ? node.status === 1 /* MOUNTED */ : true) {
@@ -5559,10 +5570,10 @@ See https://github.com/odoo/owl/blob/${hash}/doc/reference/app.md#configuration
5559
5570
  if (isStatic) {
5560
5571
  C = parent.constructor.components[name];
5561
5572
  if (!C) {
5562
- throw new Error(`Cannot find the definition of component "${name}"`);
5573
+ throw new OwlError(`Cannot find the definition of component "${name}"`);
5563
5574
  }
5564
5575
  else if (!(C.prototype instanceof Component)) {
5565
- throw new Error(`"${name}" is not a Component. It must inherit from the Component class`);
5576
+ throw new OwlError(`"${name}" is not a Component. It must inherit from the Component class`);
5566
5577
  }
5567
5578
  }
5568
5579
  node = new ComponentNode(C, props, this, ctx, key);
@@ -5721,6 +5732,7 @@ See https://github.com/odoo/owl/blob/${hash}/doc/reference/app.md#configuration
5721
5732
  exports.App = App;
5722
5733
  exports.Component = Component;
5723
5734
  exports.EventBus = EventBus;
5735
+ exports.OwlError = OwlError;
5724
5736
  exports.__info__ = __info__;
5725
5737
  exports.blockDom = blockDom;
5726
5738
  exports.loadFile = loadFile;
@@ -5755,9 +5767,9 @@ See https://github.com/odoo/owl/blob/${hash}/doc/reference/app.md#configuration
5755
5767
  Object.defineProperty(exports, '__esModule', { value: true });
5756
5768
 
5757
5769
 
5758
- __info__.version = '2.0.0-beta-12';
5759
- __info__.date = '2022-06-29T09:13:12.680Z';
5760
- __info__.hash = '6c72e0a';
5770
+ __info__.version = '2.0.0-beta-16';
5771
+ __info__.date = '2022-07-22T07:43:54.584Z';
5772
+ __info__.hash = 'b90aa0e';
5761
5773
  __info__.url = 'https://github.com/odoo/owl';
5762
5774
 
5763
5775