diff --git a/docs/owl.js b/docs/owl.js index 860abddd1..50e17d918 100644 --- a/docs/owl.js +++ b/docs/owl.js @@ -82,67 +82,6 @@ function toggler(key, child) { // Custom error class that wraps error that happen in the owl lifecycle class OwlError extends Error { -} -// Maps fibers to thrown errors -const fibersInError = new WeakMap(); -const nodeErrorHandlers = new WeakMap(); -function _handleError(node, error) { - if (!node) { - return false; - } - const fiber = node.fiber; - if (fiber) { - fibersInError.set(fiber, error); - } - const errorHandlers = nodeErrorHandlers.get(node); - if (errorHandlers) { - let handled = false; - // execute in the opposite order - for (let i = errorHandlers.length - 1; i >= 0; i--) { - try { - errorHandlers[i](error); - handled = true; - break; - } - catch (e) { - error = e; - } - } - if (handled) { - return true; - } - } - return _handleError(node.parent, error); -} -function handleError(params) { - let { error } = params; - // Wrap error if it wasn't wrapped by wrapError (ie when not in dev mode) - if (!(error instanceof OwlError)) { - error = Object.assign(new OwlError(`An error occured in the owl lifecycle (see this Error's "cause" property)`), { cause: error }); - } - const node = "node" in params ? params.node : params.fiber.node; - const fiber = "fiber" in params ? params.fiber : node.fiber; - if (fiber) { - // resets the fibers on components if possible. This is important so that - // new renderings can be properly included in the initial one, if any. - let current = fiber; - do { - current.node.fiber = current; - current = current.parent; - } while (current); - fibersInError.set(fiber.root, error); - } - const handled = _handleError(node, error); - if (!handled) { - console.warn(`[Owl] Unhandled error. Destroying the root component`); - try { - node.app.destroy(); - } - catch (e) { - console.error(e); - } - throw error; - } } const { setAttribute: elemSetAttribute, removeAttribute } = Element.prototype; @@ -1603,6 +1542,68 @@ function remove(vnode, withBeforeRemove = false) { vnode.remove(); } +// Maps fibers to thrown errors +const fibersInError = new WeakMap(); +const nodeErrorHandlers = new WeakMap(); +function _handleError(node, error) { + if (!node) { + return false; + } + const fiber = node.fiber; + if (fiber) { + fibersInError.set(fiber, error); + } + const errorHandlers = nodeErrorHandlers.get(node); + if (errorHandlers) { + let handled = false; + // execute in the opposite order + for (let i = errorHandlers.length - 1; i >= 0; i--) { + try { + errorHandlers[i](error); + handled = true; + break; + } + catch (e) { + error = e; + } + } + if (handled) { + return true; + } + } + return _handleError(node.parent, error); +} +function handleError(params) { + let { error } = params; + // Wrap error if it wasn't wrapped by wrapError (ie when not in dev mode) + if (!(error instanceof OwlError)) { + error = Object.assign(new OwlError(`An error occured in the owl lifecycle (see this Error's "cause" property)`), { cause: error }); + } + const node = "node" in params ? params.node : params.fiber.node; + const fiber = "fiber" in params ? params.fiber : node.fiber; + if (fiber) { + // resets the fibers on components if possible. This is important so that + // new renderings can be properly included in the initial one, if any. + let current = fiber; + do { + current.node.fiber = current; + current = current.parent; + } while (current); + fibersInError.set(fiber.root, error); + } + const handled = _handleError(node, error); + if (!handled) { + console.warn(`[Owl] Unhandled error. Destroying the root component`); + try { + node.app.destroy(); + } + catch (e) { + console.error(e); + } + throw error; + } +} + function makeChildFiber(node, parent) { let current = node.fiber; if (current) { @@ -3007,8 +3008,8 @@ function prepareList(collection) { values = keys; } else { - values = Object.keys(collection); - keys = Object.values(collection); + values = Object.values(collection); + keys = Object.keys(collection); } } else { @@ -4346,18 +4347,18 @@ class CodeGenerator { } this.addLine(`for (let ${loopVar} = 0; ${loopVar} < ${l}; ${loopVar}++) {`); this.target.indentLevel++; - this.addLine(`ctx[\`${ast.elem}\`] = ${vals}[${loopVar}];`); + this.addLine(`ctx[\`${ast.elem}\`] = ${keys}[${loopVar}];`); if (!ast.hasNoFirst) { this.addLine(`ctx[\`${ast.elem}_first\`] = ${loopVar} === 0;`); } if (!ast.hasNoLast) { - this.addLine(`ctx[\`${ast.elem}_last\`] = ${loopVar} === ${vals}.length - 1;`); + this.addLine(`ctx[\`${ast.elem}_last\`] = ${loopVar} === ${keys}.length - 1;`); } if (!ast.hasNoIndex) { this.addLine(`ctx[\`${ast.elem}_index\`] = ${loopVar};`); } if (!ast.hasNoValue) { - this.addLine(`ctx[\`${ast.elem}_value\`] = ${keys}[${loopVar}];`); + this.addLine(`ctx[\`${ast.elem}_value\`] = ${vals}[${loopVar}];`); } this.define(`key${this.target.loopLevel}`, ast.key ? compileExpr(ast.key) : loopVar); if (this.dev) { @@ -5547,11 +5548,20 @@ function compile(template, options = {}) { const codeGenerator = new CodeGenerator(ast, { ...options, hasSafeContext }); const code = codeGenerator.generateCode(); // template function - return new Function("app, bdom, helpers", code); + try { + return new Function("app, bdom, helpers", code); + } + catch (originalError) { + const { name } = options; + const nameStr = name ? `template "${name}"` : "anonymous template"; + const err = new OwlError(`Failed to compile ${nameStr}: ${originalError.message}\n\ngenerated code:\nfunction(app, bdom, helpers) {\n${code}\n}`); + err.cause = originalError; + throw err; + } } // do not modify manually. This file is generated by the release script. -const version = "2.2.3"; +const version = "2.2.4"; // ----------------------------------------------------------------------------- // Scheduler @@ -5984,6 +5994,6 @@ TemplateSet.prototype._compileTemplate = function _compileTemplate(name, templat 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, validateType, whenReady, xml }; -__info__.date = '2023-07-20T06:05:29.796Z'; -__info__.hash = 'b1a3b32'; +__info__.date = '2023-08-02T06:20:03.634Z'; +__info__.hash = '8f9ad98'; __info__.url = 'https://github.com/odoo/owl'; diff --git a/package-lock.json b/package-lock.json index 8db33fa52..bf5fd7fca 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@odoo/owl", - "version": "2.2.3", + "version": "2.2.4", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 7750ca83f..23bb37bfc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@odoo/owl", - "version": "2.2.3", + "version": "2.2.4", "description": "Odoo Web Library (OWL)", "main": "dist/owl.cjs.js", "module": "dist/owl.es.js", diff --git a/src/version.ts b/src/version.ts index 854542f3e..26be93b56 100644 --- a/src/version.ts +++ b/src/version.ts @@ -1,2 +1,2 @@ // do not modify manually. This file is generated by the release script. -export const version = "2.2.3"; +export const version = "2.2.4";