Commit Graph

176 Commits

Author SHA1 Message Date
Géry Debongnie 4a5316ced5 [FIX] t-model takes precedence over t-on-input
With this commit, we make sure that the code for t-model is run before
t-on-input event handler.  This is useful to make sure that the state
reflected by t-model is up-to-date.

closes #1295
2022-11-22 12:57:36 +01:00
Samuel Degueldre 9a5edb4590 [FIX] compiler: do not look up ComponentNode in the context
With the introduction of t-call-context, there is now no guarantee that
the ComponentNode can be found in the rendering context, any attempt to
do so can crash when combined with t-call-context. This commit fixes
that by using `this` instead, which in compiled templates refers to the
component that is being rendered.
2022-11-22 09:53:40 +01:00
tom hunkapiller 3d49daedcd [IMP] app: throw error when static components key is missing in parent
This commit improves the error message that's thrown when a static
component definition is missing, as outlined in issue #1286.
2022-11-10 11:59:34 +01:00
Bruno Boi bd199971bd [FIX] blockdom: fix event_catcher traceback
When a parent component has an empty child with a t-on
and an event is triggered inside the parent, blockdom
checks if there is an event_catcher to call.
Doing so, an empty child would cause an error.

This commit fixes that.
2022-10-21 09:50:10 +02:00
Samuel Degueldre 2c244aa31a [FIX] blockdom: correctly reorder children in heterogeneous t-foreach
Currently, the `moveBefore` method on VNodes assumes that the `other`
VNode it receives is of the same type, and that the entire VNode tree
below that other VNode has the exact same structure. While this is
correct in most cases, it breaks down when there is a VToggler somewhere
in the VNode tree, as the structure below a VToggler can be very
different from the structure below another VToggler that was created
from the same compiled code. For example, two iterations of a t-foreach
that contains a <t t-component="..."/> may spawn different components,
and different components obviously have different structures.

One way to fix this is to remove the assumption that the structure of
the `this` block tree in moveBefore is the same as the structure
of the `other` block tree, and instead, always give the concrete DOM
node before which we want to move the current VNode instead of giving it
a VNode and an afterNode as a fallback. One problem with this solution
is that it degrades performance in the "standard" case, where a
t-foreach contains no VToggler anywhere in its block tree, as retrieving
the first concrete DOM node requires calling firstNode() which
recursively traverses the entire tree.

To avoid this performance penalty in the standard case, we opt to only
go down this route whenever we encounter a VToggler when calling
`moveBefore`. This requires that we maintain two separate methods, one
to move a VNode before another VNode of assumed similar structure, which
is basically the current implementation of `moveBefore` for all VNode
types except VToggler, and one implementation that moves a VNode before
a concrete DOM node. This method needs to be implemented for all VNode
types, as all VNode types can be descendants of a VToggler. This method
will only be called from one place: the `moveBeforeVNode` method of the
toggler, which is the point where we realize that the assumption of
identical structure breaks down.

Co-authored-by: Bruno Boi <boi@odoo.com>
2022-10-19 13:13:49 +02:00
Samuel Degueldre ba1a270c93 [FIX] parser: give t-set-slot="default" priority over the content
Currently, if a component has a default slot defined with t-set-slot,
and also content that compiles to something (eg, text or even a comment
node), the content takes priority over the t-set-slot. As t-set-slot is
more explicity, it should have priority.
2022-10-10 20:33:18 +02:00
Samuel Degueldre d546244fc3 [FIX] runtime: correctly throw an error for duplicate object keys
Currently when checking for duplicate keys, we insert the value of the
key as is in a set then check for unicity against those. When the key is
an object, we check for duplicates based on object identity, whereas the
keys are used by owl as strings, and so using objects can cause
duplicate key errors that do not throw correctly but crash in the owl
internals.

This commit fixes that by making the duplicate checking code serialize
the key to string before insertion and when comparing against existing
keys.
2022-10-10 13:53:11 +02:00
Géry Debongnie 7ab34c5ca5 [FIX] prevent crash in case with t-foreach and t-out with components
The t-out directive is compiled internally into a LazyValue, which
represents a value that may or may not be created sometimes in the
future.  It can also be reused more than once, and this is where there
may be an issue: if a component is contained in the lazyvalue, it needs
a unique key (coming from the t-foreach) to be properly indexed in the
parent children map.  However, the LazyValue does not keep the key
information, so it is not able to provide it to its content.

The fix is then quite clear: the LazyValue class should store the key
information, and provides it to its content.  This allows the LazyValue
to be used multiple times, in any place in a template.

closes #1270
2022-09-29 08:28:38 +02:00
Géry Debongnie 17fb33475c [FIX] props validation: make it work through slots
A recent commit fixes the props validation code to make it work
regardless of the rendering context (important with the recent
t-call-context directive). Unfortunately, it then breaks props
validation through slots, because it assumed that the parent node in the
virtual node was the parent of the component, but it is not necessarily
true.

To fix this, we can use a simple property of the template functions:
they are bound to the current instance of the component, so we can
simply use "this"
2022-09-26 15:17:58 +02:00
Géry Debongnie d5ed25cd19 [FIX] props validation: does not crash with t-call-context
The code for props validation assumed that the rendering context was a
component.  This was actually true when it was written, but is no longer
true since t-call-context was introduced.

Because of that, it would crash when trying to access the internals of
the component, such as the static components object.

The fix is simple: instead of passing the context to the props
validation code, which can now be anything, we pass the component node,
which is guaranteed to give a reference to the component (and also to
the app).  This also make the code slightly simpler.

closes #1261
2022-09-24 08:34:22 +02:00
Samuel Degueldre cfdf7caa50 [IMP] app: rethrow errors that were not handled
This commit makes it so that when an error occurs in an owl app and none
of the registered error handlers are able to handle it, we rethrow the
error instead of just logging it to the console and swallowing it. This
allows users of owl to handle errors that happen in owl applications by
using event listeners for error and unhandledrejection events on the
window.
2022-09-09 09:23:32 +02:00
Samuel Degueldre 8fe4c0c76e [FIX] events: correctly call handlers in iframes
Previously, event handlers would not work when an app was mounted in an
iframe, this is caused by a guard in the event handler that checks that
the target element is still in the document, but it doesn't check
against the correct document in the case of an iframe.

This commit changes the check to check against the target's
ownerDocument.
2022-09-06 12:06:59 +02:00
Géry Debongnie 3883cec079 [FIX] slots: prevent crash when using same slot in different locations
Before this commit, a crash could occur when a component with no props
is defined in a slot, and that slot is conditionally displayed in
multiple locations.

The reason for that is that the key provided to the callSlot function
was identical, so from the perspective of the component function, it was
not possible to make the difference between a component located in
either places.  With this commit, we make sure that a unique key is used
when a slot is reused in a template (or if it is dynamic, because in
that case, we have no idea at compile time if it will be unique or not)

closes #1246
2022-09-02 12:12:00 +02:00
Samuel Degueldre 163366997c [FIX] components: fix cause left unset when thrown object is not Error
Previously, when wrapping errors in wrapError, if the error was not an
actual error object, we wouldn't set the cause property on the wrapping
error correctly. The "instanceof Error" check is simply there so that we
can know whether we can add the original errors message to the wrapping
error, but the line that sets the error's cause was mistakenly moved
into that condition.

This commit also fixes the wrapping error's message in the case of
non-Error objects, to avoid having "the following error occurred in
hookname:" with nothing after the colon which is confusing/misleading.
2022-07-22 09:21:19 +02:00
Samuel Degueldre 7786077921 [IMP] *: use a custom error class for all errors thrown by owl
This commit makes all errors thrown in owl use a custom error class. The
main point of this is to always wrap user-code errors that happen during
the owl lifecycle so that they can be treated uniformly in onError by
checking the cause property, and also allows user code to differenciate
owl errors from non-owl errors reliably at runtime.
2022-07-18 15:40:14 +02:00
Aaron Bohy 30bc605c84 [FIX] lifecyle_hooks: correctly wrap errors in async code
Before this commit, wrapping an error occurring in async code
would result in an unhandledpromise exception, because we created
another promise, that would be rejected and that we didn't catch.
2022-07-18 15:40:14 +02:00
Géry Debongnie 382e3e4010 [FIX] compiler: properly handle t-set in t-if with no content
Before this commit, whenever Owl encounter a t-if, it generates an
anchor (a "hole") in the current block being compiled. However, in some
cases, the content of the t-if may not have any content at all, and the
anchor is then useless. Worse, the code generating the anchor generates
an index based on the number of sub blocks, but if there is no content,
the next anchor being created will have the same index, which then may
cause weird bugs.

A possible way to fix this could be to make sure we increment properly
the anchor index, but we could even do better: not having an anchor at
all.
2022-06-29 11:08:14 +02:00
Géry Debongnie b9ba0abf41 [FIX] test: run prettier 2022-06-28 15:26:55 +02:00
Géry Debongnie d6667ddf2e [FIX] fix some issues with t-out with falsy values, and with default value 2022-06-28 15:10:11 +02:00
Géry Debongnie c7459ef87b [IMP] add support for t-call-context directive 2022-06-22 16:15:54 +02:00
Géry Debongnie 5772b4e9e4 [FIX] properly get component reference instead of context
Before this commit, the generated code for the component directive was
using the current context as the place to look for static informations
(such as the sub components). However, it is not entirely correct, since
the current context may be different than the current component (which
is easily accessed by using the this variable).

Also, while doing this, we fix some issues in the t-set directive, which
as calling lazy values with the wrong this.
2022-06-22 16:15:54 +02:00
Géry Debongnie 55ac43c1db [IMP] app: add fast path for when component has no prop 2022-06-13 09:51:31 +02:00
Géry Debongnie 0e6059467f [REF] move component function to app, improve some code 2022-06-13 09:51:31 +02:00
Géry Debongnie 1fc88f626f [IMP] slots: add support for t-props on slots props 2022-06-07 09:30:45 +02:00
Géry Debongnie 5d5a530505 [FIX] component: props values are own property of props object 2022-06-03 16:41:31 +02:00
Géry Debongnie c7bd0ab85c [FIX] component: fix wrong behaviour when using t-on on t-component
Before this commit, using t-on on t-component was not correctly
implemented by owl: when more than one component shared the same
parentelement and have an handler with the same name, the second handler
would override the first (using an internal key). With this commit, we
simply recreate event handler for each instance of a catcher block. Note
that it means that using t-on on components is slightly slower now.

Also, this commit fixes an additional issue that was noticed: the
catcher block would not update its internal handler properly, so it
would not behave properly after being patched.

closes #1199
2022-06-03 16:12:56 +02:00
Géry Debongnie 31b57cbb40 [FIX] component: fix props comparison code
Before this commit, Owl had a bad interaction with the static
defaultProps code. The props comparison would be done with the new props
object (unmodified) and the current props object (with default props
applied), so the comparison would always return false, which in turn,
causes additional useless renderings.

This commit modifies component node to keep a reference to the
(unmodified) props object so we can compare it as expected.
2022-06-03 15:51:58 +02:00
Géry Debongnie 31fce0926c [FIX] event: no crash when using t-on + modifier on slots/components
closes #1185
2022-06-01 09:58:49 +02:00
Géry Debongnie 22a79cdedd [REF] reorganize file structure
in order to separate compiler/ and runtime/ code
2022-05-31 14:00:01 +02:00
Géry Debongnie 2b4d8874c7 [REF] simplify template definition 2022-05-31 14:00:01 +02:00
Géry Debongnie 586033fd95 [FIX] app: validate props for root component in dev mode
Before this commit, only sub components were validated.
2022-05-24 13:52:42 +02:00
Géry Debongnie 4779707923 [IMP] component: rewrite props validation code
This commit reworks the props validation code in order to extract a
generic validate utility function. The validation should be more robust,
with better error messages, and at the same time, it supports `*` in a
shape object.

And as a bonus, it is now typesafe, and the static props object is now
typed.

closes #1190
2022-05-24 13:52:42 +02:00
Samuel Degueldre 4c77132ae2 [IMP] component: only useState on props that are already reactive
Previously, components would automatically call useState on their props,
so that changes deeply within props would automatically cause the
component to be rendered. This can be useful when passing a piece of
state to children or descendants.

One problem with this is that all props implicitly become reactive, even
if the object that was passed as a props was not. The problem with that
being that since the original object is not reactive, any change made by
the parent will not go through the reactivity system and the children
won't be notified of the change, in essence, this reactive object is
essentially useless, while having a real cost: traversing reactive
objects creates more reactive objects, and those objects are all
proxies. This is expensive for basically no benefit, while also making
it more difficult to debug code that involves those objects.

This commit fixes that by only calling useState on objects that are
already reactive, allowing the usecase described in the first paragraph
without the drawbacks described in the second.
2022-05-18 08:46:27 +02:00
Paul Morelle 32d8b23b9d [IMP] props_validation: have clearer error messages
With this commit, props validation error messages will include a more
developer-friendly error message, avoiding the need to investigate in
the Developer Tools why a complex props structure is invalid.
2022-05-17 09:35:15 +02:00
Lucas Lefèvre 5c71744e19 [IMP] component: display nice error for wrong child component
If you declare a child component which is not actually a Component,
the error message is not very friendly and not very helpfull to find
what happens and which child component is wrong.

```
const ChildComponent = "not a component constructor";

class MyComponent extends Component {
    static components = { ChildComponent };
}
```

This commit improves the type declaration for those working with Typescript
and adds a runtime check for javascript codebases
2022-05-06 17:09:30 +02:00
Géry Debongnie d09771b04b [FIX] compiler: fix issue with identifiers with same name
Before this commit, there were 2 different ways of generating variable
identifiers. And it was possible to have a situation with two different
variable in a template with the same identifier, which caused a crash.

This commit ensures that we go through a unique helper method, so this
cannot occur anymore. Also, the code is slightly simpler.
2022-05-04 14:19:42 +02:00
Samuel Degueldre 41f1262eb7 [FIX] concurrency: do not render delayed fibers when cancelled
Previously, if a fiber was delayed because one of its ancestors was
rendering, and that fiber was not a root fiber, it would be rendered
after all its ancestors had finished rendering even if one of those
ancestor renderings cancelled it.

This commit fixes that by simply checking that a delayed fiber is still
its component node's current fiber before rendering it.
2022-04-19 12:07:35 +02:00
Géry Debongnie 7d14db7d31 [FIX] component: strict check of deep argument truth value
With this commit, we make sure that the `render` method was explicitely
called with the deep === true argument, instead of assuming that it is a
boolean.  This prevents errors when some unrelated value is given to the
render method. This could happen in some cases, such as

useBus(someBus, 'someevent', this.render)

In that case, the `useBus` code would simply call the this.render with a
customevent, which would be considered truthy before, and not anymore
2022-04-11 10:58:44 +02:00
Géry Debongnie 24b1ea7604 [FIX] components: prevent rendering destroyed children in some cases 2022-04-01 15:02:57 +02:00
Géry Debongnie 859748aed9 [FIX] concurrency issue (more robust handling of children per render)
Before this commit, the list of all children was managed at the level of
the root fiber, but this could cause issue when subfibers would be
reused. With this commit, we use the childrenMap object that exists on
each fiber instead.
2022-04-01 13:40:24 +02:00
Géry Debongnie fd13277e1d [FIX] component: protect against user code executing in critical section
Canceling a fiber may cause user code to be run, which means that some
new renderings could be scheduled, but this could interfere with the
current renderings!
2022-04-01 13:40:24 +02:00
Géry Debongnie 7fb166bd50 [FIX] component: protect against errors in onWillDestroy 2022-04-01 13:40:24 +02:00
Lucas Perais (lpe) decf42c742 [FIX] compiler, component: dynamic t-slot with scope
A little typo was preventing a dynamic t-slot with a scope
(`<t t-slot="{{ state.name }}" myScope="someValue" />`)
to work properly.

This commit corrects this.
2022-03-31 16:15:47 +02:00
Géry Debongnie 989b0d6709 [REF] improve children handling in components/fibers 2022-03-31 08:54:59 +02:00
Géry Debongnie 9b93521da4 [FIX] issue with delayed renders being left pending forever 2022-03-31 08:54:59 +02:00
Lucas Perais (lpe) de240b1ebc [FIX] compiler, components: allow empty slot
Before this commit, a t-set-slot that has no content was not even compiled, and thus not passed
to the component for which it has was defined

After this commit, we allow a t-set-slot to have no content (because it can have slot props)
2022-03-29 16:24:05 +02:00
Géry Debongnie e3b1566943 [IMP] component: wait for parent rendering to be complete before doing child
This is a breaking semantic change.  With this commit, the UI is frozen
whenever owl is waiting for a parent to change

Also, this allows Owl not to render components that will be removed
later.
2022-03-29 15:45:27 +02:00
Samuel Degueldre 77ff5ee895 [IMP] component: emit warning when async hooks take too long
This commit adds a warning when an async hook
(onWillUpdateProps/onWillStart) takes longer than 3 seconds, as these
hooks block the rendering and patching of the application, it is rarely
desirable and often a sign of a deadlock. This warning will contain the
stack trace of the call to the hook to help in debugging.
2022-03-14 09:51:47 +01:00
Géry Debongnie 53ab54b1ec [FIX] useEffect: properly handle errors in effect function
Before this commit, if the effect function would throw, then the cleanup
function would not be properly assigned, which caused additional errors
later, when the cleanup code would try to call it.

closes #1149
2022-03-08 15:23:49 +01:00
Géry Debongnie b3062d29f1 [REF] parser: make AST definition more consistent 2022-03-08 12:24:57 +01:00