@odoo/owl 2.0.0-beta-14 → 2.0.0-beta-15

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"), { 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;
@@ -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,24 @@
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
+ if (cause instanceof Error) {
2480
+ error.cause = cause;
2481
+ error.message += `"${cause.message}"`;
2482
+ }
2483
+ throw error;
2484
+ };
2472
2485
  try {
2473
2486
  const result = fn(...args);
2474
2487
  if (result instanceof Promise) {
2475
2488
  if (hookName === "onWillStart" || hookName === "onWillUpdateProps") {
2476
2489
  const fiber = node.fiber;
2477
2490
  Promise.race([
2478
- result,
2491
+ result.catch(() => { }),
2479
2492
  new Promise((resolve) => setTimeout(() => resolve(TIMEOUT), 3000)),
2480
2493
  ]).then((res) => {
2481
2494
  if (res === TIMEOUT && node.fiber === fiber) {
@@ -2483,21 +2496,12 @@
2483
2496
  }
2484
2497
  });
2485
2498
  }
2486
- return result.catch((cause) => {
2487
- error.cause = cause;
2488
- if (cause instanceof Error) {
2489
- error.message += `"${cause.message}"`;
2490
- }
2491
- throw error;
2492
- });
2499
+ return result.catch(onError);
2493
2500
  }
2494
2501
  return result;
2495
2502
  }
2496
2503
  catch (cause) {
2497
- if (cause instanceof Error) {
2498
- error.message += `"${cause.message}"`;
2499
- }
2500
- throw error;
2504
+ onError(cause);
2501
2505
  }
2502
2506
  };
2503
2507
  }
@@ -2601,7 +2605,7 @@
2601
2605
  }
2602
2606
  this.target = el && el.querySelector(this.selector);
2603
2607
  if (!this.target) {
2604
- throw new Error("invalid portal target");
2608
+ throw new OwlError("invalid portal target");
2605
2609
  }
2606
2610
  }
2607
2611
  this.realBDom.mount(this.target, null);
@@ -2695,7 +2699,7 @@
2695
2699
  function validate(obj, spec) {
2696
2700
  let errors = validateSchema(obj, spec);
2697
2701
  if (errors.length) {
2698
- throw new Error("Invalid object: " + errors.join(", "));
2702
+ throw new OwlError("Invalid object: " + errors.join(", "));
2699
2703
  }
2700
2704
  }
2701
2705
  /**
@@ -2848,7 +2852,7 @@
2848
2852
  keys = Object.values(collection);
2849
2853
  }
2850
2854
  else {
2851
- throw new Error("Invalid loop expression");
2855
+ throw new OwlError("Invalid loop expression");
2852
2856
  }
2853
2857
  const n = values.length;
2854
2858
  return [keys, values, n, new Array(n)];
@@ -2954,7 +2958,7 @@
2954
2958
  if (el) {
2955
2959
  count++;
2956
2960
  if (count > 1) {
2957
- throw new Error("Cannot have 2 elements with same ref name at the same time");
2961
+ throw new OwlError("Cannot have 2 elements with same ref name at the same time");
2958
2962
  }
2959
2963
  }
2960
2964
  if (count === 0 || el) {
@@ -2991,13 +2995,13 @@
2991
2995
  : name in schema && !("*" in schema) && !isOptional(schema[name]);
2992
2996
  for (let p in defaultProps) {
2993
2997
  if (isMandatory(p)) {
2994
- throw new Error(`A default value cannot be defined for a mandatory prop (name: '${p}', component: ${ComponentClass.name})`);
2998
+ throw new OwlError(`A default value cannot be defined for a mandatory prop (name: '${p}', component: ${ComponentClass.name})`);
2995
2999
  }
2996
3000
  }
2997
3001
  }
2998
3002
  const errors = validateSchema(props, schema);
2999
3003
  if (errors.length) {
3000
- throw new Error(`Invalid props for component '${ComponentClass.name}': ` + errors.join(", "));
3004
+ throw new OwlError(`Invalid props for component '${ComponentClass.name}': ` + errors.join(", "));
3001
3005
  }
3002
3006
  }
3003
3007
  const helpers = {
@@ -3018,6 +3022,7 @@
3018
3022
  bind,
3019
3023
  createCatcher,
3020
3024
  markRaw,
3025
+ OwlError,
3021
3026
  };
3022
3027
 
3023
3028
  const bdom = { text, createBlock, list, multi, html, toggler, comment };
@@ -3045,7 +3050,7 @@
3045
3050
  }
3046
3051
  }
3047
3052
  }
3048
- throw new Error(msg);
3053
+ throw new OwlError(msg);
3049
3054
  }
3050
3055
  return doc;
3051
3056
  }
@@ -3076,7 +3081,7 @@
3076
3081
  if (currentAsString === newAsString) {
3077
3082
  return;
3078
3083
  }
3079
- throw new Error(`Template ${name} already defined with different content`);
3084
+ throw new OwlError(`Template ${name} already defined with different content`);
3080
3085
  }
3081
3086
  this.rawTemplates[name] = template;
3082
3087
  }
@@ -3101,7 +3106,7 @@
3101
3106
  extraInfo = ` (for component "${componentName}")`;
3102
3107
  }
3103
3108
  catch { }
3104
- throw new Error(`Missing template: "${name}"${extraInfo}`);
3109
+ throw new OwlError(`Missing template: "${name}"${extraInfo}`);
3105
3110
  }
3106
3111
  const isFn = typeof rawTemplate === "function" && !(rawTemplate instanceof Element);
3107
3112
  const templateFn = isFn ? rawTemplate : this._compileTemplate(name, rawTemplate);
@@ -3117,7 +3122,7 @@
3117
3122
  return this.templates[name];
3118
3123
  }
3119
3124
  _compileTemplate(name, template) {
3120
- throw new Error(`Unable to compile a template. Please use owl full build instead`);
3125
+ throw new OwlError(`Unable to compile a template. Please use owl full build instead`);
3121
3126
  }
3122
3127
  callTemplate(owner, subTemplate, ctx, parent, key) {
3123
3128
  const template = this.getTemplate(subTemplate);
@@ -3199,14 +3204,14 @@
3199
3204
  i++;
3200
3205
  cur = expr[i];
3201
3206
  if (!cur) {
3202
- throw new Error("Invalid expression");
3207
+ throw new OwlError("Invalid expression");
3203
3208
  }
3204
3209
  s += cur;
3205
3210
  }
3206
3211
  i++;
3207
3212
  }
3208
3213
  if (expr[i] !== start) {
3209
- throw new Error("Invalid expression");
3214
+ throw new OwlError("Invalid expression");
3210
3215
  }
3211
3216
  s += start;
3212
3217
  if (start === "`") {
@@ -3313,7 +3318,7 @@
3313
3318
  error = e; // Silence all errors and throw a generic error below
3314
3319
  }
3315
3320
  if (current.length || error) {
3316
- throw new Error(`Tokenizer error: could not tokenize \`${expr}\``);
3321
+ throw new OwlError(`Tokenizer error: could not tokenize \`${expr}\``);
3317
3322
  }
3318
3323
  return result;
3319
3324
  }
@@ -3864,7 +3869,7 @@
3864
3869
  .slice(1)
3865
3870
  .map((m) => {
3866
3871
  if (!MODS.has(m)) {
3867
- throw new Error(`Unknown event modifier: '${m}'`);
3872
+ throw new OwlError(`Unknown event modifier: '${m}'`);
3868
3873
  }
3869
3874
  return `"${m}"`;
3870
3875
  });
@@ -4185,7 +4190,8 @@
4185
4190
  this.define(`key${this.target.loopLevel}`, ast.key ? compileExpr(ast.key) : loopVar);
4186
4191
  if (this.dev) {
4187
4192
  // Throw error on duplicate keys in dev mode
4188
- this.addLine(`if (keys${block.id}.has(key${this.target.loopLevel})) { throw new Error(\`Got duplicate key in t-foreach: \${key${this.target.loopLevel}}\`)}`);
4193
+ this.helpers.add("OwlError");
4194
+ this.addLine(`if (keys${block.id}.has(key${this.target.loopLevel})) { throw new OwlError(\`Got duplicate key in t-foreach: \${key${this.target.loopLevel}}\`)}`);
4189
4195
  this.addLine(`keys${block.id}.add(key${this.target.loopLevel});`);
4190
4196
  }
4191
4197
  let id;
@@ -4399,7 +4405,7 @@
4399
4405
  value = `bind(ctx, ${value || undefined})`;
4400
4406
  }
4401
4407
  else {
4402
- throw new Error("Invalid prop suffix");
4408
+ throw new OwlError("Invalid prop suffix");
4403
4409
  }
4404
4410
  }
4405
4411
  name = /^[a-z_]+$/i.test(name) ? name : `'${name}'`;
@@ -4592,9 +4598,6 @@
4592
4598
  }
4593
4599
  }
4594
4600
 
4595
- // -----------------------------------------------------------------------------
4596
- // AST Type definition
4597
- // -----------------------------------------------------------------------------
4598
4601
  // -----------------------------------------------------------------------------
4599
4602
  // Parser
4600
4603
  // -----------------------------------------------------------------------------
@@ -4703,7 +4706,7 @@
4703
4706
  return null;
4704
4707
  }
4705
4708
  if (tagName.startsWith("block-")) {
4706
- throw new Error(`Invalid tag name: '${tagName}'`);
4709
+ throw new OwlError(`Invalid tag name: '${tagName}'`);
4707
4710
  }
4708
4711
  ctx = Object.assign({}, ctx);
4709
4712
  if (tagName === "pre") {
@@ -4722,14 +4725,14 @@
4722
4725
  const value = node.getAttribute(attr);
4723
4726
  if (attr.startsWith("t-on")) {
4724
4727
  if (attr === "t-on") {
4725
- throw new Error("Missing event name with t-on directive");
4728
+ throw new OwlError("Missing event name with t-on directive");
4726
4729
  }
4727
4730
  on = on || {};
4728
4731
  on[attr.slice(5)] = value;
4729
4732
  }
4730
4733
  else if (attr.startsWith("t-model")) {
4731
4734
  if (!["input", "select", "textarea"].includes(tagName)) {
4732
- throw new Error("The t-model directive only works with <input>, <textarea> and <select>");
4735
+ throw new OwlError("The t-model directive only works with <input>, <textarea> and <select>");
4733
4736
  }
4734
4737
  let baseExpr, expr;
4735
4738
  if (hasDotAtTheEnd.test(value)) {
@@ -4743,7 +4746,7 @@
4743
4746
  expr = value.slice(index + 1, -1);
4744
4747
  }
4745
4748
  else {
4746
- throw new Error(`Invalid t-model expression: "${value}" (it should be assignable)`);
4749
+ throw new OwlError(`Invalid t-model expression: "${value}" (it should be assignable)`);
4747
4750
  }
4748
4751
  const typeAttr = node.getAttribute("type");
4749
4752
  const isInput = tagName === "input";
@@ -4773,11 +4776,11 @@
4773
4776
  }
4774
4777
  }
4775
4778
  else if (attr.startsWith("block-")) {
4776
- throw new Error(`Invalid attribute: '${attr}'`);
4779
+ throw new OwlError(`Invalid attribute: '${attr}'`);
4777
4780
  }
4778
4781
  else if (attr !== "t-name") {
4779
4782
  if (attr.startsWith("t-") && !attr.startsWith("t-att")) {
4780
- throw new Error(`Unknown QWeb directive: '${attr}'`);
4783
+ throw new OwlError(`Unknown QWeb directive: '${attr}'`);
4781
4784
  }
4782
4785
  const tModel = ctx.tModelInfo;
4783
4786
  if (tModel && ["t-att-value", "t-attf-value"].includes(attr)) {
@@ -4828,7 +4831,7 @@
4828
4831
  };
4829
4832
  }
4830
4833
  if (ast.type === 11 /* TComponent */) {
4831
- throw new Error("t-esc is not supported on Component nodes");
4834
+ throw new OwlError("t-esc is not supported on Component nodes");
4832
4835
  }
4833
4836
  return tesc;
4834
4837
  }
@@ -4876,7 +4879,7 @@
4876
4879
  node.removeAttribute("t-as");
4877
4880
  const key = node.getAttribute("t-key");
4878
4881
  if (!key) {
4879
- throw new Error(`"Directive t-foreach should always be used with a t-key!" (expression: t-foreach="${collection}" t-as="${elem}")`);
4882
+ throw new OwlError(`"Directive t-foreach should always be used with a t-key!" (expression: t-foreach="${collection}" t-as="${elem}")`);
4880
4883
  }
4881
4884
  node.removeAttribute("t-key");
4882
4885
  const memo = node.getAttribute("t-memo") || "";
@@ -5036,7 +5039,7 @@
5036
5039
  const firstLetter = name[0];
5037
5040
  let isDynamic = node.hasAttribute("t-component");
5038
5041
  if (isDynamic && name !== "t") {
5039
- throw new Error(`Directive 't-component' can only be used on <t> nodes (used on a <${name}>)`);
5042
+ throw new OwlError(`Directive 't-component' can only be used on <t> nodes (used on a <${name}>)`);
5040
5043
  }
5041
5044
  if (!(firstLetter === firstLetter.toUpperCase() || isDynamic)) {
5042
5045
  return null;
@@ -5060,7 +5063,7 @@
5060
5063
  }
5061
5064
  else {
5062
5065
  const message = directiveErrorMap.get(name.split("-").slice(0, 2).join("-"));
5063
- throw new Error(message || `unsupported directive on Component: ${name}`);
5066
+ throw new OwlError(message || `unsupported directive on Component: ${name}`);
5064
5067
  }
5065
5068
  }
5066
5069
  else {
@@ -5075,7 +5078,7 @@
5075
5078
  const slotNodes = Array.from(clone.querySelectorAll("[t-set-slot]"));
5076
5079
  for (let slotNode of slotNodes) {
5077
5080
  if (slotNode.tagName !== "t") {
5078
- throw new Error(`Directive 't-set-slot' can only be used on <t> nodes (used on a <${slotNode.tagName}>)`);
5081
+ throw new OwlError(`Directive 't-set-slot' can only be used on <t> nodes (used on a <${slotNode.tagName}>)`);
5079
5082
  }
5080
5083
  const name = slotNode.getAttribute("t-set-slot");
5081
5084
  // check if this is defined in a sub component (in which case it should
@@ -5240,25 +5243,25 @@
5240
5243
  let nattr = (name) => +!!node.getAttribute(name);
5241
5244
  if (prevElem && (pattr("t-if") || pattr("t-elif"))) {
5242
5245
  if (pattr("t-foreach")) {
5243
- throw new Error("t-if cannot stay at the same level as t-foreach when using t-elif or t-else");
5246
+ throw new OwlError("t-if cannot stay at the same level as t-foreach when using t-elif or t-else");
5244
5247
  }
5245
5248
  if (["t-if", "t-elif", "t-else"].map(nattr).reduce(function (a, b) {
5246
5249
  return a + b;
5247
5250
  }) > 1) {
5248
- throw new Error("Only one conditional branching directive is allowed per node");
5251
+ throw new OwlError("Only one conditional branching directive is allowed per node");
5249
5252
  }
5250
5253
  // All text (with only spaces) and comment nodes (nodeType 8) between
5251
5254
  // branch nodes are removed
5252
5255
  let textNode;
5253
5256
  while ((textNode = node.previousSibling) !== prevElem) {
5254
5257
  if (textNode.nodeValue.trim().length && textNode.nodeType !== 8) {
5255
- throw new Error("text is not allowed between branching directives");
5258
+ throw new OwlError("text is not allowed between branching directives");
5256
5259
  }
5257
5260
  textNode.remove();
5258
5261
  }
5259
5262
  }
5260
5263
  else {
5261
- throw new Error("t-elif and t-else directives must be preceded by a t-if or t-elif directive");
5264
+ throw new OwlError("t-elif and t-else directives must be preceded by a t-if or t-elif directive");
5262
5265
  }
5263
5266
  }
5264
5267
  }
@@ -5274,7 +5277,7 @@
5274
5277
  const elements = [...el.querySelectorAll("[t-esc]")].filter((el) => el.tagName[0] === el.tagName[0].toUpperCase() || el.hasAttribute("t-component"));
5275
5278
  for (const el of elements) {
5276
5279
  if (el.childNodes.length) {
5277
- throw new Error("Cannot have t-esc on a component that already has content");
5280
+ throw new OwlError("Cannot have t-esc on a component that already has content");
5278
5281
  }
5279
5282
  const value = el.getAttribute("t-esc");
5280
5283
  el.removeAttribute("t-esc");
@@ -5326,7 +5329,7 @@
5326
5329
  }
5327
5330
  }
5328
5331
  }
5329
- throw new Error(msg);
5332
+ throw new OwlError(msg);
5330
5333
  }
5331
5334
  return doc;
5332
5335
  }
@@ -5380,7 +5383,7 @@
5380
5383
  if (Object.hasOwnProperty.call(data, 0)) {
5381
5384
  const handler = data[0];
5382
5385
  if (typeof handler !== "function") {
5383
- throw new Error(`Invalid handler (expected a function, received: '${handler}')`);
5386
+ throw new OwlError(`Invalid handler (expected a function, received: '${handler}')`);
5384
5387
  }
5385
5388
  let node = data[1] ? data[1].__owl__ : null;
5386
5389
  if (node ? node.status === 1 /* MOUNTED */ : true) {
@@ -5564,10 +5567,10 @@ See https://github.com/odoo/owl/blob/${hash}/doc/reference/app.md#configuration
5564
5567
  if (isStatic) {
5565
5568
  C = parent.constructor.components[name];
5566
5569
  if (!C) {
5567
- throw new Error(`Cannot find the definition of component "${name}"`);
5570
+ throw new OwlError(`Cannot find the definition of component "${name}"`);
5568
5571
  }
5569
5572
  else if (!(C.prototype instanceof Component)) {
5570
- throw new Error(`"${name}" is not a Component. It must inherit from the Component class`);
5573
+ throw new OwlError(`"${name}" is not a Component. It must inherit from the Component class`);
5571
5574
  }
5572
5575
  }
5573
5576
  node = new ComponentNode(C, props, this, ctx, key);
@@ -5726,6 +5729,7 @@ See https://github.com/odoo/owl/blob/${hash}/doc/reference/app.md#configuration
5726
5729
  exports.App = App;
5727
5730
  exports.Component = Component;
5728
5731
  exports.EventBus = EventBus;
5732
+ exports.OwlError = OwlError;
5729
5733
  exports.__info__ = __info__;
5730
5734
  exports.blockDom = blockDom;
5731
5735
  exports.loadFile = loadFile;
@@ -5760,9 +5764,9 @@ See https://github.com/odoo/owl/blob/${hash}/doc/reference/app.md#configuration
5760
5764
  Object.defineProperty(exports, '__esModule', { value: true });
5761
5765
 
5762
5766
 
5763
- __info__.version = '2.0.0-beta-14';
5764
- __info__.date = '2022-07-08T14:17:53.900Z';
5765
- __info__.hash = 'd111845';
5767
+ __info__.version = '2.0.0-beta-15';
5768
+ __info__.date = '2022-07-20T08:02:36.538Z';
5769
+ __info__.hash = '588b655';
5766
5770
  __info__.url = 'https://github.com/odoo/owl';
5767
5771
 
5768
5772