@odoo/owl 3.0.0-alpha.22 → 3.0.0-alpha.24

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
@@ -2000,51 +2000,11 @@ function untrack(fn) {
2000
2000
  // Maps fibers to thrown errors
2001
2001
  const fibersInError = new WeakMap();
2002
2002
  const nodeErrorHandlers = new WeakMap();
2003
- function destroyApp(app, error) {
2004
- try {
2005
- app.destroy();
2006
- }
2007
- catch (e) {
2008
- // mute all errors here because we are in a corrupted state anyway
2009
- }
2010
- const e = Object.assign(new OwlError(`[Owl] Unhandled error. Destroying the root component`), {
2011
- cause: error,
2012
- });
2013
- return e;
2014
- }
2015
- function _handleError(node, error) {
2016
- if (!node) {
2017
- return false;
2018
- }
2019
- const fiber = node.fiber;
2020
- if (fiber) {
2021
- fibersInError.set(fiber, error);
2022
- }
2023
- const errorHandlers = nodeErrorHandlers.get(node);
2024
- if (errorHandlers) {
2025
- let handled = false;
2026
- // execute in the opposite order
2027
- const finalize = () => destroyApp(node.app, error);
2028
- for (let i = errorHandlers.length - 1; i >= 0; i--) {
2029
- try {
2030
- errorHandlers[i](error, finalize);
2031
- handled = true;
2032
- break;
2033
- }
2034
- catch (e) {
2035
- error = e;
2036
- }
2037
- }
2038
- if (handled) {
2039
- return true;
2040
- }
2041
- }
2042
- return _handleError(node.parent, error);
2043
- }
2044
2003
  function handleError(params) {
2045
2004
  let { error } = params;
2046
- const node = "node" in params ? params.node : params.fiber.node;
2005
+ let node = "node" in params ? params.node : params.fiber.node;
2047
2006
  const fiber = "fiber" in params ? params.fiber : node.fiber;
2007
+ const app = node.app;
2048
2008
  if (fiber) {
2049
2009
  // resets the fibers on components if possible. This is important so that
2050
2010
  // new renderings can be properly included in the initial one, if any.
@@ -2056,10 +2016,43 @@ function handleError(params) {
2056
2016
  } while (current);
2057
2017
  fibersInError.set(fiber.root, error);
2058
2018
  }
2059
- const handled = _handleError(node, error);
2060
- if (!handled) {
2061
- throw destroyApp(node.app, error);
2019
+ const finalize = () => {
2020
+ try {
2021
+ app.destroy();
2022
+ }
2023
+ catch (e) {
2024
+ // mute all errors here because we are in a corrupted state anyway
2025
+ }
2026
+ return Object.assign(new OwlError(`[Owl] Unhandled error. Destroying the root component`), {
2027
+ cause: error,
2028
+ });
2029
+ };
2030
+ // Walk up the component tree looking for error handlers
2031
+ while (node) {
2032
+ const nodeFiber = node.fiber;
2033
+ if (nodeFiber) {
2034
+ fibersInError.set(nodeFiber, error);
2035
+ }
2036
+ const errorHandlers = nodeErrorHandlers.get(node);
2037
+ if (errorHandlers) {
2038
+ // execute in the opposite order
2039
+ for (let i = errorHandlers.length - 1; i >= 0; i--) {
2040
+ try {
2041
+ errorHandlers[i](error, finalize);
2042
+ return; // handled
2043
+ }
2044
+ catch (e) {
2045
+ error = e;
2046
+ }
2047
+ }
2048
+ }
2049
+ node = node.parent;
2062
2050
  }
2051
+ // No handler found — create the OwlError, then let the app handle it.
2052
+ // app._handleError is called after error creation, so it doesn't appear
2053
+ // in the error's .stack property.
2054
+ const owlError = finalize();
2055
+ app._handleError(owlError);
2063
2056
  }
2064
2057
 
2065
2058
  function makeChildFiber(node, parent) {
@@ -2180,13 +2173,9 @@ class Fiber {
2180
2173
  current = current.parent;
2181
2174
  }
2182
2175
  // there are no current rendering from above => we can render
2183
- this._render();
2184
- }
2185
- _render() {
2186
2176
  const node = this.node;
2187
2177
  const root = this.root;
2188
2178
  if (root) {
2189
- // todo: should use updateComputation somewhere else.
2190
2179
  const c = getCurrentComputation();
2191
2180
  removeSources(node.signalComputation);
2192
2181
  setComputation(node.signalComputation);
@@ -2195,10 +2184,14 @@ class Fiber {
2195
2184
  this.bdom = node.renderFn();
2196
2185
  }
2197
2186
  catch (e) {
2198
- node.app.handleError({ node, error: e });
2187
+ handleError({ node, error: e });
2199
2188
  }
2200
2189
  setComputation(c);
2201
- root.setCounter(root.counter - 1);
2190
+ const newCounter = root.counter - 1;
2191
+ root.counter = newCounter;
2192
+ if (newCounter === 0) {
2193
+ this.node.app.scheduler.flush();
2194
+ }
2202
2195
  }
2203
2196
  }
2204
2197
  }
@@ -2265,7 +2258,7 @@ class RootFiber extends Fiber {
2265
2258
  fiber.node.willUnmount = [];
2266
2259
  }
2267
2260
  this.locked = false;
2268
- node.app.handleError({ fiber: current || this, error: e });
2261
+ handleError({ fiber: current || this, error: e });
2269
2262
  }
2270
2263
  }
2271
2264
  setCounter(newValue) {
@@ -2321,7 +2314,7 @@ class MountFiber extends RootFiber {
2321
2314
  }
2322
2315
  }
2323
2316
  catch (e) {
2324
- this.node.app.handleError({ fiber: current, error: e });
2317
+ handleError({ fiber: current, error: e });
2325
2318
  }
2326
2319
  }
2327
2320
  }
@@ -2399,7 +2392,7 @@ class ComponentNode {
2399
2392
  await Promise.all(promises);
2400
2393
  }
2401
2394
  catch (e) {
2402
- this.app.handleError({ node: this, error: e });
2395
+ handleError({ node: this, error: e });
2403
2396
  return;
2404
2397
  }
2405
2398
  if (this.status === 0 /* STATUS.NEW */ && this.fiber === fiber) {
@@ -2489,7 +2482,7 @@ class ComponentNode {
2489
2482
  }
2490
2483
  }
2491
2484
  catch (e) {
2492
- this.app.handleError({ error: e, node: this });
2485
+ handleError({ error: e, node: this });
2493
2486
  }
2494
2487
  }
2495
2488
  for (const computation of this.computations) {
@@ -3208,7 +3201,17 @@ function createComponent(app, name, isStatic, hasSlotsProp, hasDynamicPropList,
3208
3201
  }
3209
3202
  node = new ComponentNode(C, props, app, ctx, key);
3210
3203
  children[key] = node;
3211
- initiateRender.call(node, new Fiber(node, parentFiber));
3204
+ const fiber = new Fiber(node, parentFiber);
3205
+ if (node.willStart.length) {
3206
+ initiateRender.call(node, fiber);
3207
+ }
3208
+ else {
3209
+ node.fiber = fiber;
3210
+ if (node.mounted.length) {
3211
+ fiber.root.mounted.push(fiber);
3212
+ }
3213
+ fiber.render();
3214
+ }
3212
3215
  }
3213
3216
  parentFiber.childrenMap[key] = node;
3214
3217
  return node;
@@ -3879,6 +3882,9 @@ class CodeGenerator {
3879
3882
  this.dev = options.dev || false;
3880
3883
  this.ast = ast;
3881
3884
  this.templateName = options.name;
3885
+ if (options.name && !options.name.startsWith("__")) {
3886
+ this.target.name = `template_${options.name.replace(/\./g, "_")}`;
3887
+ }
3882
3888
  if (options.hasGlobalValues) {
3883
3889
  this.helpers.add("__globals__");
3884
3890
  }
@@ -5672,7 +5678,7 @@ function compile(template, options = {
5672
5678
  }
5673
5679
 
5674
5680
  // do not modify manually. This file is generated by the release script.
5675
- const version = "3.0.0-alpha.22";
5681
+ const version = "3.0.0-alpha.24";
5676
5682
 
5677
5683
  function effect(fn) {
5678
5684
  const computation = createComputation(() => {
@@ -5832,6 +5838,7 @@ class Scheduler {
5832
5838
  processing = false;
5833
5839
  constructor() {
5834
5840
  this.requestAnimationFrame = Scheduler.requestAnimationFrame;
5841
+ this.processTasks = this.processTasks.bind(this);
5835
5842
  }
5836
5843
  addFiber(fiber) {
5837
5844
  this.tasks.add(fiber.root);
@@ -5839,7 +5846,7 @@ class Scheduler {
5839
5846
  scheduleDestroy(node) {
5840
5847
  this.cancelledNodes.add(node);
5841
5848
  if (this.frame === 0) {
5842
- this.frame = this.requestAnimationFrame(() => this.processTasks());
5849
+ this.frame = this.requestAnimationFrame(this.processTasks);
5843
5850
  }
5844
5851
  }
5845
5852
  /**
@@ -5857,7 +5864,7 @@ class Scheduler {
5857
5864
  }
5858
5865
  }
5859
5866
  if (this.frame === 0) {
5860
- this.frame = this.requestAnimationFrame(() => this.processTasks());
5867
+ this.frame = this.requestAnimationFrame(this.processTasks);
5861
5868
  }
5862
5869
  }
5863
5870
  processTasks() {
@@ -5870,8 +5877,33 @@ class Scheduler {
5870
5877
  node._destroy();
5871
5878
  }
5872
5879
  this.cancelledNodes.clear();
5873
- for (let task of this.tasks) {
5874
- this.processFiber(task);
5880
+ for (let fiber of this.tasks) {
5881
+ if (fiber.root !== fiber) {
5882
+ this.tasks.delete(fiber);
5883
+ continue;
5884
+ }
5885
+ const hasError = fibersInError.has(fiber);
5886
+ if (hasError && fiber.counter !== 0) {
5887
+ this.tasks.delete(fiber);
5888
+ continue;
5889
+ }
5890
+ if (fiber.node.status === 3 /* STATUS.DESTROYED */) {
5891
+ this.tasks.delete(fiber);
5892
+ continue;
5893
+ }
5894
+ if (fiber.counter === 0) {
5895
+ if (!hasError) {
5896
+ fiber.complete();
5897
+ }
5898
+ // at this point, the fiber should have been applied to the DOM, so we can
5899
+ // remove it from the task list. If it is not the case, it means that there
5900
+ // was an error and an error handler triggered a new rendering that recycled
5901
+ // the fiber, so in that case, we actually want to keep the fiber around,
5902
+ // otherwise it will just be ignored.
5903
+ if (fiber.appliedToDom) {
5904
+ this.tasks.delete(fiber);
5905
+ }
5906
+ }
5875
5907
  }
5876
5908
  for (let task of this.tasks) {
5877
5909
  if (task.node.status === 3 /* STATUS.DESTROYED */) {
@@ -5880,34 +5912,6 @@ class Scheduler {
5880
5912
  }
5881
5913
  this.processing = false;
5882
5914
  }
5883
- processFiber(fiber) {
5884
- if (fiber.root !== fiber) {
5885
- this.tasks.delete(fiber);
5886
- return;
5887
- }
5888
- const hasError = fibersInError.has(fiber);
5889
- if (hasError && fiber.counter !== 0) {
5890
- this.tasks.delete(fiber);
5891
- return;
5892
- }
5893
- if (fiber.node.status === 3 /* STATUS.DESTROYED */) {
5894
- this.tasks.delete(fiber);
5895
- return;
5896
- }
5897
- if (fiber.counter === 0) {
5898
- if (!hasError) {
5899
- fiber.complete();
5900
- }
5901
- // at this point, the fiber should have been applied to the DOM, so we can
5902
- // remove it from the task list. If it is not the case, it means that there
5903
- // was an error and an error handler triggered a new rendering that recycled
5904
- // the fiber, so in that case, we actually want to keep the fiber around,
5905
- // otherwise it will just be ignored.
5906
- if (fiber.appliedToDom) {
5907
- this.tasks.delete(fiber);
5908
- }
5909
- }
5910
- }
5911
5915
  }
5912
5916
 
5913
5917
  let hasBeenLogged = false;
@@ -6007,8 +6011,8 @@ class App extends TemplateSet {
6007
6011
  this.scheduler.processTasks();
6008
6012
  apps.delete(this);
6009
6013
  }
6010
- handleError(...args) {
6011
- return handleError(...args);
6014
+ _handleError(error) {
6015
+ throw error;
6012
6016
  }
6013
6017
  }
6014
6018
  async function mount(C, target, config = {}) {
@@ -6066,14 +6070,20 @@ const mainEventHandler = (data, ev, currentTarget) => {
6066
6070
  // hooks
6067
6071
  // -----------------------------------------------------------------------------
6068
6072
  function decorate(node, f, hookName) {
6069
- const result = f.bind(node.component);
6070
6073
  if (node.app.dev) {
6071
- const suffix = f.name ? ` <${f.name}>` : "";
6072
- Reflect.defineProperty(result, "name", {
6073
- value: hookName + suffix,
6074
- });
6074
+ const component = node.component;
6075
+ const componentName = component ? component.constructor.name : "Component";
6076
+ const name = `${componentName}.${hookName}`;
6077
+ // Create a named wrapper so the name appears in stack traces.
6078
+ // V8 uses computed property keys as inferred function names.
6079
+ const wrapper = {
6080
+ [name](...args) {
6081
+ return f.call(component, ...args);
6082
+ },
6083
+ };
6084
+ return wrapper[name];
6075
6085
  }
6076
- return result;
6086
+ return f.bind(node.component);
6077
6087
  }
6078
6088
  function onWillStart(fn) {
6079
6089
  const { node } = getContext("component");
@@ -6331,22 +6341,30 @@ class Registry {
6331
6341
  }
6332
6342
  }
6333
6343
 
6334
- const anyType = function validateAny() { };
6335
- const booleanType = function validateBoolean(context) {
6336
- if (typeof context.value !== "boolean") {
6337
- context.addIssue({ message: "value is not a boolean" });
6338
- }
6339
- };
6340
- const numberType = function validateNumber(context) {
6341
- if (typeof context.value !== "number") {
6342
- context.addIssue({ message: "value is not a number" });
6343
- }
6344
- };
6345
- const stringType = function validateString(context) {
6346
- if (typeof context.value !== "string") {
6347
- context.addIssue({ message: "value is not a string" });
6348
- }
6349
- };
6344
+ function anyType() {
6345
+ return function validateAny() { };
6346
+ }
6347
+ function booleanType() {
6348
+ return function validateBoolean(context) {
6349
+ if (typeof context.value !== "boolean") {
6350
+ context.addIssue({ message: "value is not a boolean" });
6351
+ }
6352
+ };
6353
+ }
6354
+ function numberType() {
6355
+ return function validateNumber(context) {
6356
+ if (typeof context.value !== "number") {
6357
+ context.addIssue({ message: "value is not a number" });
6358
+ }
6359
+ };
6360
+ }
6361
+ function stringType() {
6362
+ return function validateString(context) {
6363
+ if (typeof context.value !== "string") {
6364
+ context.addIssue({ message: "value is not a string" });
6365
+ }
6366
+ };
6367
+ }
6350
6368
  function arrayType(elementType) {
6351
6369
  return function validateArray(context) {
6352
6370
  if (!Array.isArray(context.value)) {
@@ -6537,6 +6555,9 @@ function reactiveValueType(type) {
6537
6555
  }
6538
6556
  };
6539
6557
  }
6558
+ function componentType() {
6559
+ return constructorType(Component);
6560
+ }
6540
6561
  function ref(type) {
6541
6562
  return union([literalType(null), instanceType(type)]);
6542
6563
  }
@@ -6545,6 +6566,7 @@ const types = {
6545
6566
  any: anyType,
6546
6567
  array: arrayType,
6547
6568
  boolean: booleanType,
6569
+ component: componentType,
6548
6570
  constructor: constructorType,
6549
6571
  customValidator: customValidator,
6550
6572
  function: functionType,
@@ -6771,6 +6793,6 @@ TemplateSet.prototype._compileTemplate = function _compileTemplate(name, templat
6771
6793
  export { App, Component, EventBus, OwlError, Plugin, Registry, Resource, __info__, assertType, batched, blockDom, computed, config, effect, htmlEscape, markRaw, markup, mount, onError, onMounted, onPatched, onWillDestroy, onWillPatch, onWillStart, onWillUnmount, onWillUpdateProps, plugin, props, providePlugins, proxy, signal, status, toRaw, types, untrack, useApp, useContext, useEffect, useListener, useResource, validateType, whenReady, xml };
6772
6794
 
6773
6795
 
6774
- __info__.date = '2026-04-08T13:31:02.500Z';
6775
- __info__.hash = '2e9164e';
6796
+ __info__.date = '2026-04-10T09:24:05.169Z';
6797
+ __info__.hash = 'd325807';
6776
6798
  __info__.url = 'https://github.com/odoo/owl';