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