@odoo/owl 3.0.0-alpha.32 → 3.0.0-alpha.33

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
@@ -39,7 +39,7 @@ var owl = (() => {
39
39
  batched: () => batched,
40
40
  blockDom: () => blockDom,
41
41
  computed: () => computed,
42
- config: () => config2,
42
+ config: () => config,
43
43
  effect: () => effect,
44
44
  getScope: () => getScope,
45
45
  globalTemplates: () => globalTemplates,
@@ -65,7 +65,7 @@ var owl = (() => {
65
65
  toRaw: () => toRaw,
66
66
  types: () => types2,
67
67
  untrack: () => untrack,
68
- useApp: () => useApp,
68
+ useApp: () => useApp2,
69
69
  useEffect: () => useEffect,
70
70
  useListener: () => useListener,
71
71
  useScope: () => useScope,
@@ -191,13 +191,15 @@ var owl = (() => {
191
191
  sources.clear();
192
192
  }
193
193
  function disposeComputation(computation) {
194
- for (const source of computation.sources) {
194
+ const sources = computation.sources;
195
+ for (const source of sources) {
195
196
  source.observers.delete(computation);
196
- if ("compute" in source && source.isDerived && source.observers.size === 0) {
197
- disposeComputation(source);
197
+ const derived = source;
198
+ if (derived.isDerived && derived.observers.size === 0) {
199
+ disposeComputation(derived);
198
200
  }
199
201
  }
200
- computation.sources.clear();
202
+ sources.clear();
201
203
  computation.state = 1;
202
204
  }
203
205
  function markDownstream(computation) {
@@ -238,6 +240,7 @@ var owl = (() => {
238
240
  }
239
241
  var Scope = class {
240
242
  app;
243
+ pluginManager;
241
244
  status = STATUS.NEW;
242
245
  computations = [];
243
246
  willStart = [];
@@ -245,6 +248,7 @@ var owl = (() => {
245
248
  _destroyCbs = null;
246
249
  constructor(app) {
247
250
  this.app = app;
251
+ this.pluginManager = app.pluginManager;
248
252
  }
249
253
  /**
250
254
  * Pushes this scope on the stack for the duration of `callback`. Any code
@@ -688,14 +692,19 @@ var owl = (() => {
688
692
  }
689
693
  function effect(fn) {
690
694
  const computation = createComputation(() => {
691
- setComputation(void 0);
692
- unsubscribeEffect(computation);
693
- setComputation(computation);
695
+ if (computation.value || computation.observers.size) {
696
+ setComputation(void 0);
697
+ unsubscribeEffect(computation);
698
+ setComputation(computation);
699
+ } else {
700
+ removeSources(computation);
701
+ }
694
702
  return fn();
695
703
  }, false);
696
704
  getCurrentComputation()?.observers.add(computation);
697
705
  updateComputation(computation);
698
706
  return function cleanupEffect2() {
707
+ computation.state = 0;
699
708
  const previousComputation = getCurrentComputation();
700
709
  setComputation(void 0);
701
710
  unsubscribeEffect(computation);
@@ -707,7 +716,6 @@ var owl = (() => {
707
716
  cleanupEffect(effect2);
708
717
  for (const childEffect of effect2.observers) {
709
718
  childEffect.state = 0;
710
- removeSources(childEffect);
711
719
  unsubscribeEffect(childEffect);
712
720
  }
713
721
  effect2.observers.clear();
@@ -784,19 +792,27 @@ var owl = (() => {
784
792
  read.dispose = dispose;
785
793
  return read;
786
794
  }
795
+ function safeReplacer(knownObjects, _key, value) {
796
+ if (typeof value === "function") {
797
+ return value.name || "[Function]";
798
+ }
799
+ if (value && typeof value === "object") {
800
+ const ctor = value.constructor;
801
+ if (ctor && ctor !== Object && ctor !== Array) {
802
+ return `[Instance of ${ctor.name || "anonymous"}]`;
803
+ }
804
+ if (knownObjects.includes(value)) {
805
+ return `[Known object]`;
806
+ }
807
+ knownObjects.push(value);
808
+ }
809
+ return value;
810
+ }
787
811
  function assertType(value, validation, errorMessage = "Value does not match the type") {
788
812
  const issues = validateType(value, validation);
789
813
  if (issues.length) {
790
- const issueStrings = JSON.stringify(
791
- issues,
792
- (key, value2) => {
793
- if (typeof value2 === "function") {
794
- return value2.name;
795
- }
796
- return value2;
797
- },
798
- 2
799
- );
814
+ const knownObjects = [];
815
+ const issueStrings = JSON.stringify(issues, safeReplacer.bind(null, knownObjects), 2);
800
816
  throw new OwlError(`${errorMessage}
801
817
  ${issueStrings}`);
802
818
  }
@@ -937,15 +953,20 @@ ${issueStrings}`);
937
953
  return;
938
954
  }
939
955
  const isShape = !Array.isArray(schema);
940
- let shape = schema;
941
- if (Array.isArray(schema)) {
956
+ let shape;
957
+ let keys;
958
+ if (isShape) {
959
+ keys = Object.keys(schema);
960
+ shape = schema;
961
+ } else {
962
+ keys = schema;
942
963
  shape = {};
943
- for (const key of schema) {
964
+ for (const key of keys) {
944
965
  shape[key] = null;
945
966
  }
946
967
  }
947
968
  const missingKeys = [];
948
- for (const key in shape) {
969
+ for (const key of keys) {
949
970
  const property = key.endsWith("?") ? key.slice(0, -1) : key;
950
971
  if (context.value[property] === void 0) {
951
972
  if (!key.endsWith("?")) {
@@ -960,20 +981,22 @@ ${issueStrings}`);
960
981
  if (missingKeys.length) {
961
982
  context.addIssue({
962
983
  message: "object value has missing keys",
963
- missingKeys
984
+ missingKeys,
985
+ expectedKeys: keys
964
986
  });
965
987
  }
966
988
  if (isStrict) {
967
989
  const unknownKeys = [];
968
990
  for (const key in context.value) {
969
- if (!(key in shape) && !(`${key}?` in shape)) {
991
+ if (!keys.includes(key) && !(`${key}?` in shape)) {
970
992
  unknownKeys.push(key);
971
993
  }
972
994
  }
973
995
  if (unknownKeys.length) {
974
996
  context.addIssue({
975
997
  message: "object value has unknown keys",
976
- unknownKeys
998
+ unknownKeys,
999
+ expectedKeys: keys
977
1000
  });
978
1001
  }
979
1002
  }
@@ -1191,12 +1214,13 @@ ${issueStrings}`);
1191
1214
  plugins;
1192
1215
  // Resolves once all pending plugin willStart callbacks have settled. The
1193
1216
  // scope transitions to MOUNTED as the last step of this chain. Consumers
1194
- // (App.mount, providePlugins) await this before treating the manager as
1195
- // ready. `willStart` itself is inherited from Scope.
1217
+ // (the root's mount(), providePlugins) await this before treating the
1218
+ // manager as ready. `willStart` itself is inherited from Scope.
1196
1219
  ready = Promise.resolve();
1197
1220
  constructor(app, options = {}) {
1198
1221
  super(app);
1199
1222
  this.config = options.config ?? {};
1223
+ this.pluginManager = this;
1200
1224
  if (options.parent) {
1201
1225
  const parent = options.parent;
1202
1226
  parent.onDestroy(() => this.destroy());
@@ -1265,9 +1289,103 @@ ${issueStrings}`);
1265
1289
  );
1266
1290
  }
1267
1291
  }
1292
+ function onWillStart(fn) {
1293
+ const scope = useScope();
1294
+ scope.willStart.push(scope.decorate(fn, "onWillStart"));
1295
+ }
1296
+ function onWillDestroy(fn) {
1297
+ const scope = useScope();
1298
+ scope.onDestroy(scope.decorate(fn, "onWillDestroy"));
1299
+ }
1300
+ function useEffect(fn) {
1301
+ onWillDestroy(effect(fn));
1302
+ }
1303
+ function useListener(target, eventName, handler, eventParams) {
1304
+ if (typeof target === "function") {
1305
+ useEffect(() => {
1306
+ const el = target();
1307
+ if (el) {
1308
+ el.addEventListener(eventName, handler, eventParams);
1309
+ return () => el.removeEventListener(eventName, handler, eventParams);
1310
+ }
1311
+ return;
1312
+ });
1313
+ } else {
1314
+ target.addEventListener(eventName, handler, eventParams);
1315
+ onWillDestroy(() => target.removeEventListener(eventName, handler, eventParams));
1316
+ }
1317
+ }
1318
+ function useApp() {
1319
+ return useScope().app;
1320
+ }
1321
+ function plugin(pluginType) {
1322
+ const scope = useScope();
1323
+ let plugin2 = scope.pluginManager.getPluginById(pluginType.id);
1324
+ if (!plugin2) {
1325
+ if (scope instanceof PluginManager) {
1326
+ plugin2 = scope.pluginManager.startPlugin(pluginType);
1327
+ } else {
1328
+ throw new OwlError(`Unknown plugin "${pluginType.id}"`);
1329
+ }
1330
+ }
1331
+ return plugin2;
1332
+ }
1333
+ function config(key, type, defaultValue) {
1334
+ const scope = useScope();
1335
+ if (!(scope instanceof PluginManager)) {
1336
+ throw new OwlError("Expected to be in a plugin scope");
1337
+ }
1338
+ if (scope.app.dev && type) {
1339
+ assertType(scope.config, types.object({ [key]: type }), "Config does not match the type");
1340
+ }
1341
+ const configValue = scope.config[key.endsWith("?") ? key.slice(0, -1) : key];
1342
+ return configValue === void 0 ? defaultValue : configValue;
1343
+ }
1344
+ var EventBus = class extends EventTarget {
1345
+ trigger(name, payload) {
1346
+ this.dispatchEvent(new CustomEvent(name, { detail: payload }));
1347
+ }
1348
+ };
1349
+ var Markup = class extends String {
1350
+ };
1351
+ function htmlEscape(str) {
1352
+ if (str instanceof Markup) {
1353
+ return str;
1354
+ }
1355
+ if (str === void 0) {
1356
+ return markup("");
1357
+ }
1358
+ if (typeof str === "number") {
1359
+ return markup(String(str));
1360
+ }
1361
+ [
1362
+ ["&", "&"],
1363
+ ["<", "&lt;"],
1364
+ [">", "&gt;"],
1365
+ ["'", "&#x27;"],
1366
+ ['"', "&quot;"],
1367
+ ["`", "&#x60;"]
1368
+ ].forEach((pairs) => {
1369
+ str = String(str).replace(new RegExp(pairs[0], "g"), pairs[1]);
1370
+ });
1371
+ return markup(str);
1372
+ }
1373
+ function markup(valueOrStrings, ...placeholders) {
1374
+ if (!Array.isArray(valueOrStrings)) {
1375
+ return new Markup(valueOrStrings);
1376
+ }
1377
+ const strings = valueOrStrings;
1378
+ let acc = "";
1379
+ let i = 0;
1380
+ for (; i < placeholders.length; ++i) {
1381
+ acc += strings[i] + htmlEscape(placeholders[i]);
1382
+ }
1383
+ acc += strings[i];
1384
+ return new Markup(acc);
1385
+ }
1268
1386
 
1269
1387
  // ../owl-runtime/dist/owl-runtime.es.js
1270
- var version = "3.0.0-alpha.32";
1388
+ var version = "3.0.0-alpha.33";
1271
1389
  var fibersInError = /* @__PURE__ */ new WeakMap();
1272
1390
  var nodeErrorHandlers = /* @__PURE__ */ new WeakMap();
1273
1391
  function invokeErrorHandlers(node, error, finalize, markFibers) {
@@ -1340,7 +1458,7 @@ ${issueStrings}`);
1340
1458
  }
1341
1459
  return { modifiers, data: dataList };
1342
1460
  }
1343
- var config = {
1461
+ var config2 = {
1344
1462
  // whether or not blockdom should normalize DOM whenever a block is created.
1345
1463
  // Normalizing dom mean removing empty text nodes (or containing only spaces)
1346
1464
  shouldNormalizeDom: true,
@@ -1714,11 +1832,6 @@ ${issueStrings}`);
1714
1832
  }
1715
1833
  throw new OwlError("Cannot mount component: the target is not a valid DOM element");
1716
1834
  }
1717
- var EventBus = class extends EventTarget {
1718
- trigger(name, payload) {
1719
- this.dispatchEvent(new CustomEvent(name, { detail: payload }));
1720
- }
1721
- };
1722
1835
  function whenReady(fn) {
1723
1836
  return new Promise(function(resolve) {
1724
1837
  if (document.readyState !== "loading") {
@@ -1729,43 +1842,6 @@ ${issueStrings}`);
1729
1842
  }).then(fn || function() {
1730
1843
  });
1731
1844
  }
1732
- var Markup = class extends String {
1733
- };
1734
- function htmlEscape(str) {
1735
- if (str instanceof Markup) {
1736
- return str;
1737
- }
1738
- if (str === void 0) {
1739
- return markup("");
1740
- }
1741
- if (typeof str === "number") {
1742
- return markup(String(str));
1743
- }
1744
- [
1745
- ["&", "&amp;"],
1746
- ["<", "&lt;"],
1747
- [">", "&gt;"],
1748
- ["'", "&#x27;"],
1749
- ['"', "&quot;"],
1750
- ["`", "&#x60;"]
1751
- ].forEach((pairs) => {
1752
- str = String(str).replace(new RegExp(pairs[0], "g"), pairs[1]);
1753
- });
1754
- return markup(str);
1755
- }
1756
- function markup(valueOrStrings, ...placeholders) {
1757
- if (!Array.isArray(valueOrStrings)) {
1758
- return new Markup(valueOrStrings);
1759
- }
1760
- const strings = valueOrStrings;
1761
- let acc = "";
1762
- let i = 0;
1763
- for (; i < placeholders.length; ++i) {
1764
- acc += strings[i] + htmlEscape(placeholders[i]);
1765
- }
1766
- acc += strings[i];
1767
- return new Markup(acc);
1768
- }
1769
1845
  function createEventHandler(rawEvent) {
1770
1846
  const eventName = rawEvent.split(".")[0];
1771
1847
  const capture = rawEvent.includes(".capture");
@@ -1787,7 +1863,7 @@ ${issueStrings}`);
1787
1863
  if (!currentTarget || !inOwnerDocument(currentTarget)) return;
1788
1864
  const data = currentTarget[eventKey];
1789
1865
  if (!data) return;
1790
- config.mainEventHandler(data, ev, currentTarget);
1866
+ config2.mainEventHandler(data, ev, currentTarget);
1791
1867
  }
1792
1868
  const options = { capture, passive };
1793
1869
  function setup(data) {
@@ -1827,7 +1903,7 @@ ${issueStrings}`);
1827
1903
  const _data = dom[eventKey];
1828
1904
  if (_data) {
1829
1905
  for (const data of Object.values(_data)) {
1830
- const stopped = config.mainEventHandler(data, event, dom);
1906
+ const stopped = config2.mainEventHandler(data, event, dom);
1831
1907
  if (stopped) return;
1832
1908
  }
1833
1909
  }
@@ -2073,7 +2149,7 @@ ${issueStrings}`);
2073
2149
  }
2074
2150
  const doc = new DOMParser().parseFromString(`<t>${str}</t>`, "text/xml");
2075
2151
  const node = doc.firstChild.firstChild;
2076
- if (config.shouldNormalizeDom) {
2152
+ if (config2.shouldNormalizeDom) {
2077
2153
  normalizeNode(node);
2078
2154
  }
2079
2155
  const tree = buildTree(node);
@@ -3201,7 +3277,6 @@ ${issueStrings}`);
3201
3277
  willPatch = [];
3202
3278
  patched = [];
3203
3279
  signalComputation;
3204
- pluginManager;
3205
3280
  constructor(C, props2, app, parent, parentKey) {
3206
3281
  super(app);
3207
3282
  this.parent = parent;
@@ -4079,10 +4154,6 @@ ${issueStrings}`);
4079
4154
  }
4080
4155
  return stopped;
4081
4156
  };
4082
- function onWillStart(fn) {
4083
- const scope = useScope();
4084
- scope.willStart.push(scope.decorate(fn, "onWillStart"));
4085
- }
4086
4157
  function onWillUpdateProps(fn) {
4087
4158
  const scope = getComponentScope();
4088
4159
  function swapped(s, nextProps) {
@@ -4106,10 +4177,6 @@ ${issueStrings}`);
4106
4177
  const scope = getComponentScope();
4107
4178
  scope.willUnmount.unshift(scope.decorate(fn, "onWillUnmount"));
4108
4179
  }
4109
- function onWillDestroy(fn) {
4110
- const scope = useScope();
4111
- scope.onDestroy(scope.decorate(fn, "onWillDestroy"));
4112
- }
4113
4180
  function onError(callback) {
4114
4181
  const scope = getComponentScope();
4115
4182
  let handlers = nodeErrorHandlers.get(scope);
@@ -4219,27 +4286,7 @@ ${issueStrings}`);
4219
4286
  onError((e) => this.props.error.set(e));
4220
4287
  }
4221
4288
  };
4222
- function useEffect(fn) {
4223
- onWillDestroy(effect(fn));
4224
- }
4225
- function useListener(target, eventName, handler, eventParams) {
4226
- if (typeof target === "function") {
4227
- useEffect(() => {
4228
- const el = target();
4229
- if (el) {
4230
- el.addEventListener(eventName, handler, eventParams);
4231
- return () => el.removeEventListener(eventName, handler, eventParams);
4232
- }
4233
- return;
4234
- });
4235
- } else {
4236
- target.addEventListener(eventName, handler, eventParams);
4237
- onWillDestroy(() => target.removeEventListener(eventName, handler, eventParams));
4238
- }
4239
- }
4240
- function useApp() {
4241
- return useScope().app;
4242
- }
4289
+ var useApp2 = useApp;
4243
4290
  var PortalContent = class extends Component {
4244
4291
  static template = xml`<t t-call-slot="default"/>`;
4245
4292
  };
@@ -4341,29 +4388,6 @@ ${issueStrings}`);
4341
4388
  }
4342
4389
  return propValue === void 0 && hasDefault ? args[0] : propValue;
4343
4390
  }
4344
- function plugin(pluginType) {
4345
- const scope = useScope();
4346
- const manager = scope instanceof ComponentNode ? scope.pluginManager : scope;
4347
- let plugin2 = manager.getPluginById(pluginType.id);
4348
- if (!plugin2) {
4349
- if (scope instanceof PluginManager) {
4350
- plugin2 = manager.startPlugin(pluginType);
4351
- } else {
4352
- throw new OwlError(`Unknown plugin "${pluginType.id}"`);
4353
- }
4354
- }
4355
- return plugin2;
4356
- }
4357
- function config2(name, type) {
4358
- const scope = useScope();
4359
- if (!(scope instanceof PluginManager)) {
4360
- throw new OwlError("Expected to be in a plugin scope");
4361
- }
4362
- if (scope.app.dev && type) {
4363
- assertType(scope.config, types2.object({ [name]: type }), "Config does not match the type");
4364
- }
4365
- return scope.config[name.endsWith("?") ? name.slice(0, -1) : name];
4366
- }
4367
4391
  function providePlugins(pluginConstructors, config3) {
4368
4392
  const node = getComponentScope();
4369
4393
  const manager = new PluginManager(node.app, { parent: node.pluginManager, config: config3 });
@@ -4374,10 +4398,10 @@ ${issueStrings}`);
4374
4398
  onWillStart(() => manager.ready);
4375
4399
  }
4376
4400
  }
4377
- config.shouldNormalizeDom = false;
4378
- config.mainEventHandler = mainEventHandler;
4401
+ config2.shouldNormalizeDom = false;
4402
+ config2.mainEventHandler = mainEventHandler;
4379
4403
  var blockDom = {
4380
- config,
4404
+ config: config2,
4381
4405
  // bdom entry points
4382
4406
  mount,
4383
4407
  patch,
@@ -4392,8 +4416,8 @@ ${issueStrings}`);
4392
4416
  };
4393
4417
  var __info__ = {
4394
4418
  version: App.version,
4395
- date: "2026-05-28T07:14:22.717Z",
4396
- hash: "578ed435",
4419
+ date: "2026-05-28T13:29:02.340Z",
4420
+ hash: "fadc22b7",
4397
4421
  url: "https://github.com/odoo/owl"
4398
4422
  };
4399
4423