@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.es.js CHANGED
@@ -77,6 +77,68 @@ function toggler(key, child) {
77
77
  return new VToggler(key, child);
78
78
  }
79
79
 
80
+ // Custom error class that wraps error that happen in the owl lifecycle
81
+ class OwlError extends Error {
82
+ }
83
+ // Maps fibers to thrown errors
84
+ const fibersInError = new WeakMap();
85
+ const nodeErrorHandlers = new WeakMap();
86
+ function _handleError(node, error) {
87
+ if (!node) {
88
+ return false;
89
+ }
90
+ const fiber = node.fiber;
91
+ if (fiber) {
92
+ fibersInError.set(fiber, error);
93
+ }
94
+ const errorHandlers = nodeErrorHandlers.get(node);
95
+ if (errorHandlers) {
96
+ let handled = false;
97
+ // execute in the opposite order
98
+ for (let i = errorHandlers.length - 1; i >= 0; i--) {
99
+ try {
100
+ errorHandlers[i](error);
101
+ handled = true;
102
+ break;
103
+ }
104
+ catch (e) {
105
+ error = e;
106
+ }
107
+ }
108
+ if (handled) {
109
+ return true;
110
+ }
111
+ }
112
+ return _handleError(node.parent, error);
113
+ }
114
+ function handleError(params) {
115
+ let { error } = params;
116
+ // Wrap error if it wasn't wrapped by wrapError (ie when not in dev mode)
117
+ if (!(error instanceof OwlError)) {
118
+ error = Object.assign(new OwlError("An error occured in the owl lifecycle"), { cause: error });
119
+ }
120
+ const node = "node" in params ? params.node : params.fiber.node;
121
+ const fiber = "fiber" in params ? params.fiber : node.fiber;
122
+ // resets the fibers on components if possible. This is important so that
123
+ // new renderings can be properly included in the initial one, if any.
124
+ let current = fiber;
125
+ do {
126
+ current.node.fiber = current;
127
+ current = current.parent;
128
+ } while (current);
129
+ fibersInError.set(fiber.root, error);
130
+ const handled = _handleError(node, error);
131
+ if (!handled) {
132
+ console.warn(`[Owl] Unhandled error. Destroying the root component`);
133
+ try {
134
+ node.app.destroy();
135
+ }
136
+ catch (e) {
137
+ console.error(e);
138
+ }
139
+ }
140
+ }
141
+
80
142
  const { setAttribute: elemSetAttribute, removeAttribute } = Element.prototype;
81
143
  const tokenList = DOMTokenList.prototype;
82
144
  const tokenListAdd = tokenList.add;
@@ -698,7 +760,7 @@ function buildTree(node, parent = null, domParentTree = null) {
698
760
  };
699
761
  }
700
762
  }
701
- throw new Error("boom");
763
+ throw new OwlError("boom");
702
764
  }
703
765
  function addRef(tree) {
704
766
  tree.isRef = true;
@@ -1382,61 +1444,6 @@ function remove(vnode, withBeforeRemove = false) {
1382
1444
  vnode.remove();
1383
1445
  }
1384
1446
 
1385
- // Maps fibers to thrown errors
1386
- const fibersInError = new WeakMap();
1387
- const nodeErrorHandlers = new WeakMap();
1388
- function _handleError(node, error) {
1389
- if (!node) {
1390
- return false;
1391
- }
1392
- const fiber = node.fiber;
1393
- if (fiber) {
1394
- fibersInError.set(fiber, error);
1395
- }
1396
- const errorHandlers = nodeErrorHandlers.get(node);
1397
- if (errorHandlers) {
1398
- let handled = false;
1399
- // execute in the opposite order
1400
- for (let i = errorHandlers.length - 1; i >= 0; i--) {
1401
- try {
1402
- errorHandlers[i](error);
1403
- handled = true;
1404
- break;
1405
- }
1406
- catch (e) {
1407
- error = e;
1408
- }
1409
- }
1410
- if (handled) {
1411
- return true;
1412
- }
1413
- }
1414
- return _handleError(node.parent, error);
1415
- }
1416
- function handleError(params) {
1417
- const error = params.error;
1418
- const node = "node" in params ? params.node : params.fiber.node;
1419
- const fiber = "fiber" in params ? params.fiber : node.fiber;
1420
- // resets the fibers on components if possible. This is important so that
1421
- // new renderings can be properly included in the initial one, if any.
1422
- let current = fiber;
1423
- do {
1424
- current.node.fiber = current;
1425
- current = current.parent;
1426
- } while (current);
1427
- fibersInError.set(fiber.root, error);
1428
- const handled = _handleError(node, error);
1429
- if (!handled) {
1430
- console.warn(`[Owl] Unhandled error. Destroying the root component`);
1431
- try {
1432
- node.app.destroy();
1433
- }
1434
- catch (e) {
1435
- console.error(e);
1436
- }
1437
- }
1438
- }
1439
-
1440
1447
  function makeChildFiber(node, parent) {
1441
1448
  let current = node.fiber;
1442
1449
  if (current) {
@@ -1475,7 +1482,7 @@ function makeRootFiber(node) {
1475
1482
  return fiber;
1476
1483
  }
1477
1484
  function throwOnRender() {
1478
- throw new Error("Attempted to render cancelled fiber");
1485
+ throw new OwlError("Attempted to render cancelled fiber");
1479
1486
  }
1480
1487
  /**
1481
1488
  * @returns number of not-yet rendered fibers cancelled
@@ -1852,7 +1859,7 @@ const reactiveCache = new WeakMap();
1852
1859
  */
1853
1860
  function reactive(target, callback = () => { }) {
1854
1861
  if (!canBeMadeReactive(target)) {
1855
- throw new Error(`Cannot make the given value reactive`);
1862
+ throw new OwlError(`Cannot make the given value reactive`);
1856
1863
  }
1857
1864
  if (SKIP in target) {
1858
1865
  return target;
@@ -2121,10 +2128,10 @@ function batched(callback) {
2121
2128
  }
2122
2129
  function validateTarget(target) {
2123
2130
  if (!(target instanceof HTMLElement)) {
2124
- throw new Error("Cannot mount component: the target is not a valid DOM element");
2131
+ throw new OwlError("Cannot mount component: the target is not a valid DOM element");
2125
2132
  }
2126
2133
  if (!document.body.contains(target)) {
2127
- throw new Error("Cannot mount a component on a detached dom node");
2134
+ throw new OwlError("Cannot mount a component on a detached dom node");
2128
2135
  }
2129
2136
  }
2130
2137
  class EventBus extends EventTarget {
@@ -2145,7 +2152,7 @@ function whenReady(fn) {
2145
2152
  async function loadFile(url) {
2146
2153
  const result = await fetch(url);
2147
2154
  if (!result.ok) {
2148
- throw new Error("Error while fetching xml templates");
2155
+ throw new OwlError("Error while fetching xml templates");
2149
2156
  }
2150
2157
  return await result.text();
2151
2158
  }
@@ -2167,7 +2174,7 @@ function markup(value) {
2167
2174
  let currentNode = null;
2168
2175
  function getCurrent() {
2169
2176
  if (!currentNode) {
2170
- throw new Error("No active component (a hook function should only be called in 'setup')");
2177
+ throw new OwlError("No active component (a hook function should only be called in 'setup')");
2171
2178
  }
2172
2179
  return currentNode;
2173
2180
  }
@@ -2229,7 +2236,6 @@ class ComponentNode {
2229
2236
  this.parent = parent;
2230
2237
  this.props = props;
2231
2238
  this.parentKey = parentKey;
2232
- this.level = parent ? parent.level + 1 : 0;
2233
2239
  const defaultProps = C.defaultProps;
2234
2240
  props = Object.assign({}, props);
2235
2241
  if (defaultProps) {
@@ -2462,17 +2468,24 @@ class ComponentNode {
2462
2468
 
2463
2469
  const TIMEOUT = Symbol("timeout");
2464
2470
  function wrapError(fn, hookName) {
2465
- const error = new Error(`The following error occurred in ${hookName}: `);
2466
- const timeoutError = new Error(`${hookName}'s promise hasn't resolved after 3 seconds`);
2471
+ const error = new OwlError(`The following error occurred in ${hookName}: `);
2472
+ const timeoutError = new OwlError(`${hookName}'s promise hasn't resolved after 3 seconds`);
2467
2473
  const node = getCurrent();
2468
2474
  return (...args) => {
2475
+ const onError = (cause) => {
2476
+ if (cause instanceof Error) {
2477
+ error.cause = cause;
2478
+ error.message += `"${cause.message}"`;
2479
+ }
2480
+ throw error;
2481
+ };
2469
2482
  try {
2470
2483
  const result = fn(...args);
2471
2484
  if (result instanceof Promise) {
2472
2485
  if (hookName === "onWillStart" || hookName === "onWillUpdateProps") {
2473
2486
  const fiber = node.fiber;
2474
2487
  Promise.race([
2475
- result,
2488
+ result.catch(() => { }),
2476
2489
  new Promise((resolve) => setTimeout(() => resolve(TIMEOUT), 3000)),
2477
2490
  ]).then((res) => {
2478
2491
  if (res === TIMEOUT && node.fiber === fiber) {
@@ -2480,21 +2493,12 @@ function wrapError(fn, hookName) {
2480
2493
  }
2481
2494
  });
2482
2495
  }
2483
- return result.catch((cause) => {
2484
- error.cause = cause;
2485
- if (cause instanceof Error) {
2486
- error.message += `"${cause.message}"`;
2487
- }
2488
- throw error;
2489
- });
2496
+ return result.catch(onError);
2490
2497
  }
2491
2498
  return result;
2492
2499
  }
2493
2500
  catch (cause) {
2494
- if (cause instanceof Error) {
2495
- error.message += `"${cause.message}"`;
2496
- }
2497
- throw error;
2501
+ onError(cause);
2498
2502
  }
2499
2503
  };
2500
2504
  }
@@ -2598,7 +2602,7 @@ class VPortal extends VText {
2598
2602
  }
2599
2603
  this.target = el && el.querySelector(this.selector);
2600
2604
  if (!this.target) {
2601
- throw new Error("invalid portal target");
2605
+ throw new OwlError("invalid portal target");
2602
2606
  }
2603
2607
  }
2604
2608
  this.realBDom.mount(this.target, null);
@@ -2692,7 +2696,7 @@ function toSchema(spec) {
2692
2696
  function validate(obj, spec) {
2693
2697
  let errors = validateSchema(obj, spec);
2694
2698
  if (errors.length) {
2695
- throw new Error("Invalid object: " + errors.join(", "));
2699
+ throw new OwlError("Invalid object: " + errors.join(", "));
2696
2700
  }
2697
2701
  }
2698
2702
  /**
@@ -2845,7 +2849,7 @@ function prepareList(collection) {
2845
2849
  keys = Object.values(collection);
2846
2850
  }
2847
2851
  else {
2848
- throw new Error("Invalid loop expression");
2852
+ throw new OwlError("Invalid loop expression");
2849
2853
  }
2850
2854
  const n = values.length;
2851
2855
  return [keys, values, n, new Array(n)];
@@ -2951,7 +2955,7 @@ function multiRefSetter(refs, name) {
2951
2955
  if (el) {
2952
2956
  count++;
2953
2957
  if (count > 1) {
2954
- throw new Error("Cannot have 2 elements with same ref name at the same time");
2958
+ throw new OwlError("Cannot have 2 elements with same ref name at the same time");
2955
2959
  }
2956
2960
  }
2957
2961
  if (count === 0 || el) {
@@ -2988,13 +2992,13 @@ function validateProps(name, props, parent) {
2988
2992
  : name in schema && !("*" in schema) && !isOptional(schema[name]);
2989
2993
  for (let p in defaultProps) {
2990
2994
  if (isMandatory(p)) {
2991
- throw new Error(`A default value cannot be defined for a mandatory prop (name: '${p}', component: ${ComponentClass.name})`);
2995
+ throw new OwlError(`A default value cannot be defined for a mandatory prop (name: '${p}', component: ${ComponentClass.name})`);
2992
2996
  }
2993
2997
  }
2994
2998
  }
2995
2999
  const errors = validateSchema(props, schema);
2996
3000
  if (errors.length) {
2997
- throw new Error(`Invalid props for component '${ComponentClass.name}': ` + errors.join(", "));
3001
+ throw new OwlError(`Invalid props for component '${ComponentClass.name}': ` + errors.join(", "));
2998
3002
  }
2999
3003
  }
3000
3004
  const helpers = {
@@ -3015,6 +3019,7 @@ const helpers = {
3015
3019
  bind,
3016
3020
  createCatcher,
3017
3021
  markRaw,
3022
+ OwlError,
3018
3023
  };
3019
3024
 
3020
3025
  const bdom = { text, createBlock, list, multi, html, toggler, comment };
@@ -3042,7 +3047,7 @@ function parseXML$1(xml) {
3042
3047
  }
3043
3048
  }
3044
3049
  }
3045
- throw new Error(msg);
3050
+ throw new OwlError(msg);
3046
3051
  }
3047
3052
  return doc;
3048
3053
  }
@@ -3073,7 +3078,7 @@ class TemplateSet {
3073
3078
  if (currentAsString === newAsString) {
3074
3079
  return;
3075
3080
  }
3076
- throw new Error(`Template ${name} already defined with different content`);
3081
+ throw new OwlError(`Template ${name} already defined with different content`);
3077
3082
  }
3078
3083
  this.rawTemplates[name] = template;
3079
3084
  }
@@ -3098,7 +3103,7 @@ class TemplateSet {
3098
3103
  extraInfo = ` (for component "${componentName}")`;
3099
3104
  }
3100
3105
  catch { }
3101
- throw new Error(`Missing template: "${name}"${extraInfo}`);
3106
+ throw new OwlError(`Missing template: "${name}"${extraInfo}`);
3102
3107
  }
3103
3108
  const isFn = typeof rawTemplate === "function" && !(rawTemplate instanceof Element);
3104
3109
  const templateFn = isFn ? rawTemplate : this._compileTemplate(name, rawTemplate);
@@ -3114,7 +3119,7 @@ class TemplateSet {
3114
3119
  return this.templates[name];
3115
3120
  }
3116
3121
  _compileTemplate(name, template) {
3117
- throw new Error(`Unable to compile a template. Please use owl full build instead`);
3122
+ throw new OwlError(`Unable to compile a template. Please use owl full build instead`);
3118
3123
  }
3119
3124
  callTemplate(owner, subTemplate, ctx, parent, key) {
3120
3125
  const template = this.getTemplate(subTemplate);
@@ -3196,14 +3201,14 @@ let tokenizeString = function (expr) {
3196
3201
  i++;
3197
3202
  cur = expr[i];
3198
3203
  if (!cur) {
3199
- throw new Error("Invalid expression");
3204
+ throw new OwlError("Invalid expression");
3200
3205
  }
3201
3206
  s += cur;
3202
3207
  }
3203
3208
  i++;
3204
3209
  }
3205
3210
  if (expr[i] !== start) {
3206
- throw new Error("Invalid expression");
3211
+ throw new OwlError("Invalid expression");
3207
3212
  }
3208
3213
  s += start;
3209
3214
  if (start === "`") {
@@ -3310,7 +3315,7 @@ function tokenize(expr) {
3310
3315
  error = e; // Silence all errors and throw a generic error below
3311
3316
  }
3312
3317
  if (current.length || error) {
3313
- throw new Error(`Tokenizer error: could not tokenize \`${expr}\``);
3318
+ throw new OwlError(`Tokenizer error: could not tokenize \`${expr}\``);
3314
3319
  }
3315
3320
  return result;
3316
3321
  }
@@ -3861,7 +3866,7 @@ class CodeGenerator {
3861
3866
  .slice(1)
3862
3867
  .map((m) => {
3863
3868
  if (!MODS.has(m)) {
3864
- throw new Error(`Unknown event modifier: '${m}'`);
3869
+ throw new OwlError(`Unknown event modifier: '${m}'`);
3865
3870
  }
3866
3871
  return `"${m}"`;
3867
3872
  });
@@ -4182,7 +4187,8 @@ class CodeGenerator {
4182
4187
  this.define(`key${this.target.loopLevel}`, ast.key ? compileExpr(ast.key) : loopVar);
4183
4188
  if (this.dev) {
4184
4189
  // Throw error on duplicate keys in dev mode
4185
- this.addLine(`if (keys${block.id}.has(key${this.target.loopLevel})) { throw new Error(\`Got duplicate key in t-foreach: \${key${this.target.loopLevel}}\`)}`);
4190
+ this.helpers.add("OwlError");
4191
+ this.addLine(`if (keys${block.id}.has(key${this.target.loopLevel})) { throw new OwlError(\`Got duplicate key in t-foreach: \${key${this.target.loopLevel}}\`)}`);
4186
4192
  this.addLine(`keys${block.id}.add(key${this.target.loopLevel});`);
4187
4193
  }
4188
4194
  let id;
@@ -4396,7 +4402,7 @@ class CodeGenerator {
4396
4402
  value = `bind(ctx, ${value || undefined})`;
4397
4403
  }
4398
4404
  else {
4399
- throw new Error("Invalid prop suffix");
4405
+ throw new OwlError("Invalid prop suffix");
4400
4406
  }
4401
4407
  }
4402
4408
  name = /^[a-z_]+$/i.test(name) ? name : `'${name}'`;
@@ -4589,9 +4595,6 @@ class CodeGenerator {
4589
4595
  }
4590
4596
  }
4591
4597
 
4592
- // -----------------------------------------------------------------------------
4593
- // AST Type definition
4594
- // -----------------------------------------------------------------------------
4595
4598
  // -----------------------------------------------------------------------------
4596
4599
  // Parser
4597
4600
  // -----------------------------------------------------------------------------
@@ -4700,7 +4703,7 @@ function parseDOMNode(node, ctx) {
4700
4703
  return null;
4701
4704
  }
4702
4705
  if (tagName.startsWith("block-")) {
4703
- throw new Error(`Invalid tag name: '${tagName}'`);
4706
+ throw new OwlError(`Invalid tag name: '${tagName}'`);
4704
4707
  }
4705
4708
  ctx = Object.assign({}, ctx);
4706
4709
  if (tagName === "pre") {
@@ -4719,14 +4722,14 @@ function parseDOMNode(node, ctx) {
4719
4722
  const value = node.getAttribute(attr);
4720
4723
  if (attr.startsWith("t-on")) {
4721
4724
  if (attr === "t-on") {
4722
- throw new Error("Missing event name with t-on directive");
4725
+ throw new OwlError("Missing event name with t-on directive");
4723
4726
  }
4724
4727
  on = on || {};
4725
4728
  on[attr.slice(5)] = value;
4726
4729
  }
4727
4730
  else if (attr.startsWith("t-model")) {
4728
4731
  if (!["input", "select", "textarea"].includes(tagName)) {
4729
- throw new Error("The t-model directive only works with <input>, <textarea> and <select>");
4732
+ throw new OwlError("The t-model directive only works with <input>, <textarea> and <select>");
4730
4733
  }
4731
4734
  let baseExpr, expr;
4732
4735
  if (hasDotAtTheEnd.test(value)) {
@@ -4740,7 +4743,7 @@ function parseDOMNode(node, ctx) {
4740
4743
  expr = value.slice(index + 1, -1);
4741
4744
  }
4742
4745
  else {
4743
- throw new Error(`Invalid t-model expression: "${value}" (it should be assignable)`);
4746
+ throw new OwlError(`Invalid t-model expression: "${value}" (it should be assignable)`);
4744
4747
  }
4745
4748
  const typeAttr = node.getAttribute("type");
4746
4749
  const isInput = tagName === "input";
@@ -4770,11 +4773,11 @@ function parseDOMNode(node, ctx) {
4770
4773
  }
4771
4774
  }
4772
4775
  else if (attr.startsWith("block-")) {
4773
- throw new Error(`Invalid attribute: '${attr}'`);
4776
+ throw new OwlError(`Invalid attribute: '${attr}'`);
4774
4777
  }
4775
4778
  else if (attr !== "t-name") {
4776
4779
  if (attr.startsWith("t-") && !attr.startsWith("t-att")) {
4777
- throw new Error(`Unknown QWeb directive: '${attr}'`);
4780
+ throw new OwlError(`Unknown QWeb directive: '${attr}'`);
4778
4781
  }
4779
4782
  const tModel = ctx.tModelInfo;
4780
4783
  if (tModel && ["t-att-value", "t-attf-value"].includes(attr)) {
@@ -4825,7 +4828,7 @@ function parseTEscNode(node, ctx) {
4825
4828
  };
4826
4829
  }
4827
4830
  if (ast.type === 11 /* TComponent */) {
4828
- throw new Error("t-esc is not supported on Component nodes");
4831
+ throw new OwlError("t-esc is not supported on Component nodes");
4829
4832
  }
4830
4833
  return tesc;
4831
4834
  }
@@ -4873,7 +4876,7 @@ function parseTForEach(node, ctx) {
4873
4876
  node.removeAttribute("t-as");
4874
4877
  const key = node.getAttribute("t-key");
4875
4878
  if (!key) {
4876
- throw new Error(`"Directive t-foreach should always be used with a t-key!" (expression: t-foreach="${collection}" t-as="${elem}")`);
4879
+ throw new OwlError(`"Directive t-foreach should always be used with a t-key!" (expression: t-foreach="${collection}" t-as="${elem}")`);
4877
4880
  }
4878
4881
  node.removeAttribute("t-key");
4879
4882
  const memo = node.getAttribute("t-memo") || "";
@@ -5033,7 +5036,7 @@ function parseComponent(node, ctx) {
5033
5036
  const firstLetter = name[0];
5034
5037
  let isDynamic = node.hasAttribute("t-component");
5035
5038
  if (isDynamic && name !== "t") {
5036
- throw new Error(`Directive 't-component' can only be used on <t> nodes (used on a <${name}>)`);
5039
+ throw new OwlError(`Directive 't-component' can only be used on <t> nodes (used on a <${name}>)`);
5037
5040
  }
5038
5041
  if (!(firstLetter === firstLetter.toUpperCase() || isDynamic)) {
5039
5042
  return null;
@@ -5057,7 +5060,7 @@ function parseComponent(node, ctx) {
5057
5060
  }
5058
5061
  else {
5059
5062
  const message = directiveErrorMap.get(name.split("-").slice(0, 2).join("-"));
5060
- throw new Error(message || `unsupported directive on Component: ${name}`);
5063
+ throw new OwlError(message || `unsupported directive on Component: ${name}`);
5061
5064
  }
5062
5065
  }
5063
5066
  else {
@@ -5072,7 +5075,7 @@ function parseComponent(node, ctx) {
5072
5075
  const slotNodes = Array.from(clone.querySelectorAll("[t-set-slot]"));
5073
5076
  for (let slotNode of slotNodes) {
5074
5077
  if (slotNode.tagName !== "t") {
5075
- throw new Error(`Directive 't-set-slot' can only be used on <t> nodes (used on a <${slotNode.tagName}>)`);
5078
+ throw new OwlError(`Directive 't-set-slot' can only be used on <t> nodes (used on a <${slotNode.tagName}>)`);
5076
5079
  }
5077
5080
  const name = slotNode.getAttribute("t-set-slot");
5078
5081
  // check if this is defined in a sub component (in which case it should
@@ -5237,25 +5240,25 @@ function normalizeTIf(el) {
5237
5240
  let nattr = (name) => +!!node.getAttribute(name);
5238
5241
  if (prevElem && (pattr("t-if") || pattr("t-elif"))) {
5239
5242
  if (pattr("t-foreach")) {
5240
- throw new Error("t-if cannot stay at the same level as t-foreach when using t-elif or t-else");
5243
+ throw new OwlError("t-if cannot stay at the same level as t-foreach when using t-elif or t-else");
5241
5244
  }
5242
5245
  if (["t-if", "t-elif", "t-else"].map(nattr).reduce(function (a, b) {
5243
5246
  return a + b;
5244
5247
  }) > 1) {
5245
- throw new Error("Only one conditional branching directive is allowed per node");
5248
+ throw new OwlError("Only one conditional branching directive is allowed per node");
5246
5249
  }
5247
5250
  // All text (with only spaces) and comment nodes (nodeType 8) between
5248
5251
  // branch nodes are removed
5249
5252
  let textNode;
5250
5253
  while ((textNode = node.previousSibling) !== prevElem) {
5251
5254
  if (textNode.nodeValue.trim().length && textNode.nodeType !== 8) {
5252
- throw new Error("text is not allowed between branching directives");
5255
+ throw new OwlError("text is not allowed between branching directives");
5253
5256
  }
5254
5257
  textNode.remove();
5255
5258
  }
5256
5259
  }
5257
5260
  else {
5258
- throw new Error("t-elif and t-else directives must be preceded by a t-if or t-elif directive");
5261
+ throw new OwlError("t-elif and t-else directives must be preceded by a t-if or t-elif directive");
5259
5262
  }
5260
5263
  }
5261
5264
  }
@@ -5271,7 +5274,7 @@ function normalizeTEsc(el) {
5271
5274
  const elements = [...el.querySelectorAll("[t-esc]")].filter((el) => el.tagName[0] === el.tagName[0].toUpperCase() || el.hasAttribute("t-component"));
5272
5275
  for (const el of elements) {
5273
5276
  if (el.childNodes.length) {
5274
- throw new Error("Cannot have t-esc on a component that already has content");
5277
+ throw new OwlError("Cannot have t-esc on a component that already has content");
5275
5278
  }
5276
5279
  const value = el.getAttribute("t-esc");
5277
5280
  el.removeAttribute("t-esc");
@@ -5323,7 +5326,7 @@ function parseXML(xml) {
5323
5326
  }
5324
5327
  }
5325
5328
  }
5326
- throw new Error(msg);
5329
+ throw new OwlError(msg);
5327
5330
  }
5328
5331
  return doc;
5329
5332
  }
@@ -5377,7 +5380,7 @@ const mainEventHandler = (data, ev, currentTarget) => {
5377
5380
  if (Object.hasOwnProperty.call(data, 0)) {
5378
5381
  const handler = data[0];
5379
5382
  if (typeof handler !== "function") {
5380
- throw new Error(`Invalid handler (expected a function, received: '${handler}')`);
5383
+ throw new OwlError(`Invalid handler (expected a function, received: '${handler}')`);
5381
5384
  }
5382
5385
  let node = data[1] ? data[1].__owl__ : null;
5383
5386
  if (node ? node.status === 1 /* MOUNTED */ : true) {
@@ -5561,10 +5564,10 @@ class App extends TemplateSet {
5561
5564
  if (isStatic) {
5562
5565
  C = parent.constructor.components[name];
5563
5566
  if (!C) {
5564
- throw new Error(`Cannot find the definition of component "${name}"`);
5567
+ throw new OwlError(`Cannot find the definition of component "${name}"`);
5565
5568
  }
5566
5569
  else if (!(C.prototype instanceof Component)) {
5567
- throw new Error(`"${name}" is not a Component. It must inherit from the Component class`);
5570
+ throw new OwlError(`"${name}" is not a Component. It must inherit from the Component class`);
5568
5571
  }
5569
5572
  }
5570
5573
  node = new ComponentNode(C, props, this, ctx, key);
@@ -5720,10 +5723,10 @@ TemplateSet.prototype._compileTemplate = function _compileTemplate(name, templat
5720
5723
  });
5721
5724
  };
5722
5725
 
5723
- export { App, Component, EventBus, __info__, blockDom, loadFile, markRaw, markup, mount, onError, onMounted, onPatched, onRendered, onWillDestroy, onWillPatch, onWillRender, onWillStart, onWillUnmount, onWillUpdateProps, reactive, status, toRaw, useChildSubEnv, useComponent, useEffect, useEnv, useExternalListener, useRef, useState, useSubEnv, validate, whenReady, xml };
5726
+ export { App, Component, EventBus, OwlError, __info__, blockDom, loadFile, markRaw, markup, mount, onError, onMounted, onPatched, onRendered, onWillDestroy, onWillPatch, onWillRender, onWillStart, onWillUnmount, onWillUpdateProps, reactive, status, toRaw, useChildSubEnv, useComponent, useEffect, useEnv, useExternalListener, useRef, useState, useSubEnv, validate, whenReady, xml };
5724
5727
 
5725
5728
 
5726
- __info__.version = '2.0.0-beta-14';
5727
- __info__.date = '2022-07-08T14:17:53.900Z';
5728
- __info__.hash = 'd111845';
5729
+ __info__.version = '2.0.0-beta-15';
5730
+ __info__.date = '2022-07-20T08:02:36.538Z';
5731
+ __info__.hash = '588b655';
5729
5732
  __info__.url = 'https://github.com/odoo/owl';