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