Compare commits

..

32 Commits

Author SHA1 Message Date
Samuel Degueldre c356351de2 [REL] v2.0.0-beta.3
# 2.0.0-beta.3

- improve error message for tokenization errors
- fix a bug where errors during rendering were incorrectly reported
- add support for t-on on components and slots (t-slot and t-set-slot)
2022-03-08 12:47:36 +01:00
Géry Debongnie f04423da23 [FIX] playground: properly set dev flag in examples 2022-03-08 12:24:57 +01:00
Géry Debongnie b3062d29f1 [REF] parser: make AST definition more consistent 2022-03-08 12:24:57 +01:00
Géry Debongnie 56086242bb [IMP] compiler: add support for t-on- on t-slots and t-set-slots 2022-03-08 12:24:57 +01:00
Géry Debongnie 998ecbb337 [REF] compiler: introduce define helper, slightly refactor code 2022-03-08 12:24:57 +01:00
Géry Debongnie 50355e6a3d [IMP] component: add support for t-on on compnents 2022-03-08 12:24:57 +01:00
Samuel Degueldre 67f86a4ab8 [FIX] components: wrap onWillRender/onRendered hooks instead of renderFn
Previously, we were wrapping the entire renderFn in a try/catch, causing
errors during template execution to be caught and wrapped by
onWillRender/onRendered which is undesirable. Now we only wrap the hook
that's being registered.
2022-03-08 10:18:15 +01:00
Samuel Degueldre 14d2328c88 [IMP] compiler: improve error message for tokenization errors 2022-03-08 10:18:15 +01:00
Géry Debongnie e4fdd32f22 [REL] v2.0.0-beta.2
# 2.0.0-beta.2

- only log dev message once, instead of once per app
- add subscriptions getter in dev mode on component node
- fix: issue with missing renderings
- fix: env now preserves prototype chain
2022-03-03 16:21:57 +01:00
Géry Debongnie 8d1d0a2244 [FIX] app: make sure we maintain the correct prototype chain in env 2022-03-03 16:19:05 +01:00
Géry Debongnie 0457e5d4ed [FIX] component: missing renderings in some cases 2022-03-03 16:19:05 +01:00
Samuel Degueldre 8920b4b93a [IMP] component, reactivity: add subscription getter in dev mode
This allows to see which objects and which keys in those objects a
component is observing, so that issues with missing renders or extra
renders can be more easily diagnosed.
2022-03-03 10:33:39 +01:00
Géry Debongnie 6908102a72 [IMP] app: only log dev message once
Before this commit, it was logged for every app created, which is
annoying in odoo: because of the compatibility layer, there are many
apps being created.
2022-03-03 08:48:37 +01:00
Géry Debongnie d6348b8310 [REL] v2.0.0-beta.1
# 2.0.0-beta.1

First beta release! The last missing feature has been merged (support for
sets/maps/weakmaps in the reactivity system).
2022-03-02 13:28:50 +01:00
Géry Debongnie 79738e00c7 [REF] small cleanup for template helpers 2022-03-02 13:26:22 +01:00
Géry Debongnie 2a1b99be2d [REM] remove the Memo component
With the new fine grained reactivity system, it was no longer useful.
2022-03-02 13:26:22 +01:00
Géry Debongnie 8a472231cf [FIX] release script was using a hardcoded value for notes
instead of the value that was actually provided by the user
2022-03-02 13:26:22 +01:00
Géry Debongnie bb373e6a7a [DOC] add explanation on structure of compiled template 2022-03-01 15:46:09 +01:00
Samuel Degueldre d735213758 [IMP] reactivity: add support for collections (Set/Map WeakSet/WeakMap) 2022-02-28 15:43:41 +01:00
Géry Debongnie 076b0d774e [REL] v2.0.0-alpha.3
# v2.0.0-alpha.3

A new release, with the fine grained reactivity applied to component props,
and changes in the way Owl render subcomponents: it can now skip patching and
or rendering child components if needed.
2022-02-25 10:57:25 +01:00
Géry Debongnie f405fe9323 [DOC] add information about reactivity 2022-02-25 10:32:25 +01:00
Géry Debongnie 1ae9d514b9 [IMP] component: use reactivity to allow shallow renderings
With this commit, component only render child
components if they have different props (shallow
equality). Otherwise, we trust the reactivity
system to make sure that all impacted components
are updated
2022-02-25 10:32:25 +01:00
Géry Debongnie 592d9a458e [REF] move useState into component_node.ts 2022-02-25 10:32:25 +01:00
Géry Debongnie 0dbd2bd463 [REF] component: slightly simplify fiber code 2022-02-18 16:21:34 +01:00
Géry Debongnie 8ec7a6f9bf [FIX] compiler: prevent block- attributes and tags 2022-02-16 17:32:59 +01:00
Géry Debongnie 12b8ce963e [IMP] reactivity: toRaw now works with non reactive objects 2022-02-16 09:35:36 +01:00
Géry Debongnie bb9d65e95b [IMP] app: better error message when missing template 2022-02-16 09:35:36 +01:00
Géry Debongnie 73c339fff1 [DOC] remove outdated event bus doc 2022-02-15 10:31:03 +01:00
Géry Debongnie 406be446a5 [FIX] app: display correct url in dev mode message
closes #850
2022-02-15 10:15:07 +01:00
Géry Debongnie bd2aa8a72f [MISC] playground: improve benchmarking code 2022-02-15 09:07:32 +01:00
Géry Debongnie 3536f41f00 [FIX] blockdom: undefined properties are treated as empty strings 2022-02-15 09:07:32 +01:00
Samuel Degueldre 804ad3c35e [IMP] component: improve errors when thrown from lifecycle hooks
Previously, a crash in a lifecycle hook for any reason would throw an
error whose stack trace started from the scheduler and contained only
the place where the hook was called by owl, but not the place where the
hook was registered by the user. This proved very difficult for users to
debug as they cannot really tell which component registered that hook.

This commit alleviates the issue by creating a new Error when the hook
is originally called, and wrapping the registered callback in a try
catch, throwing an error with the correct stack trace instead of the
error in the hook, and setting the error in the hook as the cause of
this synthetic error.
2022-02-14 13:54:17 +01:00
94 changed files with 4232 additions and 1756 deletions
+31 -66
View File
@@ -31,6 +31,7 @@ All changes are documented here in no particular order.
- breaking: Support for inline css (`css` tag and static `style`) has been removed ([details](#37-support-for-inline-css-css-tag-and-static-style-has-been-removed))
- new: prop validation system can now describe that additional props are allowed (with `*`) ([doc](doc/reference/props.md#props-validation))
- breaking: prop validation system does not allow default prop on a mandatory (not optional) prop ([doc](doc/reference/props.md#props-validation))
- breaking: rendering a component does not necessarily render child components ([details](#40-rendering-a-component-does-not-necessarily-render-child-components))
@@ -43,7 +44,6 @@ All changes are documented here in no particular order.
- breaking: style/class on components are now regular props ([details](#10-styleclass-on-components-are-now-regular-props))
- new: components can use the `.bind` suffix to bind function props ([doc](doc/reference/props.md#binding-function-props))
- breaking: `t-on` does not accept expressions, only functions ([details](#30-t-on-does-not-accept-expressions-only-functions))
- breaking: `t-on` does not work on components any more ([details](#12-t-on-does-not-work-on-components-any-more))
- new: an error is thrown if an handler defined in a `t-on-` directive is not a function (failed silently previously in some cases)
- breaking: `t-component` no longer accepts strings ([details](#17-t-component-no-longer-accepts-strings))
- new: the `this` variable in template expressions is now bound to the component
@@ -80,7 +80,6 @@ All changes are documented here in no particular order.
- improved performance
- much simpler code
- new App class to encapsulate a root Owl component (with the config for that application) ([doc](doc/reference/app.md))
- new `Memo` component
- new `useEffect` hook ([doc](doc/reference/hooks.md#useeffect))
- breaking: `Context` is removed ([details](#15-context-is-removed))
- breaking: `env` is now totally empty ([details](#16-env-is-now-totally-empty))
@@ -248,35 +247,12 @@ Rationale: `shouldUpdate` is a dangerous method to use, that may cause a lot of
issues. Vue does not have such a mechanism (see https://github.com/vuejs/vue/issues/4255),
because the reactivity system in Vue is smart enough to only rerender the minimal
subset of components that is subscribed to a piece of state. Now, Owl 2 features
a much more powerful reactivity system.
a much more powerful reactivity system, so the same rationale applies: in a way,
it's like each Owl 2 component has a `shouldUpdate` method that precisely tracks
every value used by the component.
Migration code: remove the `shouldUpdate` methods. Then, maybe the following
ideas may help:
- try to organize the state/architecture to minimize the number of state updates
- take advantage of the finer reactivity system. For example, if we have a list
of items, with a component for each item, we can write this:
```js
class Item extends Component {
setup() {
this.item = useState(this.props.item); // and only use this, not props.item
}
}
```
Doing so will make it that each `Item` component will register itself as an
observer of its own item, and will be the only component being rerendered when
its item object is updated.
- use the `Memo` component to wrap some piece of template. `Memo` memoize its
content, and only update itself if its props are different (shallow comparison):
```xml
<Memo a="state.a" b="state.b">
<t t-esc="state.a"/>
<t t-esc="state.b"/>
<t t-esc="state.c"/>
</Memo>
```
Migration code: remove the `shouldUpdate` methods, and it should work as well
as before.
### 9. component.el is removed
@@ -336,41 +312,6 @@ Documentation:
- [Mounting a component](doc/reference/app.md#mount-helper)
### 12. `t-on` does not work on components any more
In owl 1, it was possible to bind an event listener on a component tag in a
template:
```xml
<SomeComponent t-on-some-event="doSomething"/>
```
This does not work any more.
Rationale: with the support of fragments, there is no longer a canonical html
element that we can refer. So, this makes it difficult to implement correctly
and efficiently. Also, we noticed in practice that the event system was an issue
in some cases, when components need to communicate before they are mounted. In
those cases, the better solution is to directly use a callback. Also, another
conceptual issue with this is that it kind of breaks the component encapsulation.
The child component kind of leak its own implementation to the outside world.
Migration: a quick fix that may work in some cases is to simply bind the event
handler on a parent htmlelement. A better way to do it, if possible, is to change
the component API to accept explicitely a callback as props.
```xml
<SomeComponent onSomeEvent="doSomething"/>
<!-- or alternatively: -->
<SomeComponent onSomeEvent.bind="doSomething"/>
```
Note that one of the example above uses the `.bind` suffix, to bind the function
prop to the component. Most of the time, binding the function is necessary, and
using the `.bind` suffix is very helpful in that case.
Documentation: [Binding function props](doc/reference/props.md#binding-function-props)
### 13. Portal does no longer transfer DOM events
In Owl 1, a Portal component would listen to events emitted on its portalled
@@ -798,4 +739,28 @@ Rationale: the `browser` object caused more trouble than it was worth. Also, it
seems like this should be done in user space, not at the framework level.
Migration: code should just be adapted to either use another browser object,
or to use native browser function (and then, just mock them directly).
or to use native browser function (and then, just mock them directly).
## 40. Rendering a component does not necessarily render child components
Before, if one had the following component tree:
```mermaid
graph TD;
A-->B;
A-->C;
```
when `A` would render, it would also render `B` and `C`. Now, in Owl 2, it will
(shallow) compare the before and after props, and `B` or `C` will only be rerendered
if their props have changed.
Now, the question is what happens if the props have changed, but in a deeper way?
In that case, Owl will know, because each props are now reactive. So, if some
inner value read by `B` was changed, then only `B` will be updated.
Rationale: This was just not possible in Owl 1, but it now possible. This is
due to the rewriteof the underlying rendering engine and the reactivity
system. The goal is to have a big performance boost in large screen with many
components: now Owl only rerender what is strictly useful.
+1
View File
@@ -110,6 +110,7 @@ Are you new to Owl? This is the place to start!
- [Comparison with React/Vue](doc/miscellaneous/comparison.md)
- [Why did Odoo build Owl?](doc/miscellaneous/why_owl.md)
- [Changelog (from owl 1.x to 2.x)](CHANGELOG.md)
- [Notes on compiled templates](doc/miscellaneous/compiled_template.md)
## Installing Owl
+98
View File
@@ -0,0 +1,98 @@
# 🦉 Notes On Owl Compiled Templates 🦉
This page will explain what an Owl compiled template look like. This is a
technical document intended for developers interested in understanding how Owl
works internally.
Broadly speaking, Owl compiles templates into a javascript function (a closure)
that returns a function (the "render" function). The point of the closure is to
have a place to store all values specific to the template (in particular, "blocks").
Once a template is compiled, its closure function is called once to get the
render function, and from then on, only the render function is used.
The render function takes some context (and some additional information) and
return a virtual dom representation of the rendered template, as a block tree.
A block tree is a very light weight representation that only contains the dynamic
part of the template, and its structure. It is actually independant of the
static part of the templates (which are contained in the blocks captured by the
closure). This means that the work performed at render time is only to collect
dynamic data, and to describe the block structure of the result.
It looks like this, in pseudo code:
```js
function closure(bdom, helpers) {
// here is some place to put stuff specific to the template, such as
// blocks
...
return function render(context, node, key) {
// only build here all dynamic parts of the template
// build a block tree
return tree;
}
}
```
Now, let us see an example. Consider the following template:
```xml
<div class="some-class">
<div class="blabla">
<span><t t-esc="state.value"/></span>
</div>
<t t-if="state.info">
<p class="info" t-att-class="someAttribute">
<t t-esc="state.info"/>
</p>
</t>
<SomeComponent value="value"/>
</div>
```
If you look carefully, there are 5 dynamic things:
- a text value (the first `t-esc`),
- a sub block (the `t-if`),
- a dynamic attribute (the `t-att-class` attribute),
- another text value (the second `t-esc`),
- and finally, a sub component
Here is the compiled code for this template:
```js
function closure(bdom, helpers) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let block1 = createBlock(
`<div class="some-class"><div class="blabla"><span><block-text-0/></span></div><block-child-0/><block-child-1/></div>`
);
let block2 = createBlock(`<p class="info" block-attribute-0="class"><block-text-1/></p>`);
return function render(ctx, node, key = "") {
let b2, b3;
let txt1 = ctx["state"].value;
if (ctx["state"].info) {
let attr1 = ctx["someAttribute"];
let txt2 = ctx["state"].info;
b2 = block2([attr1, txt2]);
}
b3 = component(`SomeComponent`, { value: ctx["value"] }, key + `__1`, node, ctx);
return block1([txt1], [b2, b3]);
};
}
```
The values captured in the closure capture the static part of the template: we
define here two blocks (which contains a template node, that can be deep cloned
whenever a block is mounted). Then the render function only describes the block
tree structure of the result, depending on the context. This means that we
minimize the amount of work done at render time.
Then, when we want to patch the dom, Owl will uses the `patch` function from
blockdom, which then will diff the block tree, and deep clone new blocks whenever
a new block is inserted, keep track of dynamic parts of each block, and update
them accordingly.
With this design, the cost of rendering a template is proportional to the number
of dynamic values, and not to the size of the template.
+5 -1
View File
@@ -68,12 +68,16 @@ The `Component` class has a very small API.
component will go through the following lifecycle methods: `willUpdateProps`,
`willPatch` and `patched`.
* **`render()`**: calling this method directly will cause a rerender. Note
* **`render(deep[=false])`**: calling this method directly will cause a rerender. Note
that with the reactivity system, this should be rare to have to do it manually.
Also, the rendering operation is asynchronous, so the DOM will only be updated
slightly later (at the next animation frame, if no component delays the
rendering)
By default, the render initiated by this method will stop at each child
component if their props are (shallow) equal. To force a render to update
all child components, one can use the optional `deep` argument.
## Static Properties
- **`template (string)`**: this is the name of the template that
-25
View File
@@ -1,25 +0,0 @@
# 🦉 Event Bus 🦉
It is sometimes useful to use a `Bus` to communicate informations between various
parts of the code. Owl has a very simple bus class, which manages subscriptions,
triggering events, and callbacks.
```js
const bus = new owl.core.EventBus();
bus.on("some-event", null, function (...args) {
console.log(...args);
});
bus.trigger("some-event", 1, 2, 3);
// [1,2,3] will be logged to the console
```
Its API is:
| Method | Description |
| -------------------------------- | --------------------------------- |
| `on(eventType, owner, callback)` | add a listener |
| `off(eventType, owner)` | remove all listeners for an owner |
| `trigger(eventType, ...args)` | trigger an event |
| `clear` | remove all subscriptions |
+17
View File
@@ -5,6 +5,7 @@
- [Event Handling](#event-handling)
- [Modifiers](#modifiers)
- [Synthetic Events](#synthetic-events)
- [On Components](#on-components)
## Event Handling
@@ -100,3 +101,19 @@ To enable it, one can just use the `.synthetic` suffix:
</t>
</div>
```
## On Components
The `t-on` directive also works on a child component:
```xml
<div>
in some template
<Child t-on-click="dosomething"/>
</div>
```
This will catch all click events on any html element contained in the `Child`
sub component. Note that if the child component is reduced to one (or more) text
nodes, then clicking on it will not call the handler, since the event will be
dispatched by the browser on the parent element (a `div` in this case).
+12
View File
@@ -25,6 +25,11 @@ To solve this issue, Owl provides two reactivity primitives:
Most of the time, the `useState` hook is the best solution.
Since version 2.0, Owl applies the fine grained reactivity at the component
level: props are automatically turned into reactive object, so Owl can track
which part of these props are consumed by each component, and is therefore able
to only rerender the impacted components.
## `useState`
Let us start by an example of how `useState` could be used:
@@ -117,3 +122,10 @@ rawState.value = 3; // will NOT be picked up by the reactivity system!!!
Here again, this is useful in some situations where we want to explicitely bypass
Owl, but using this function means that the responsability of coordinating
state update is given to the user code, instead of Owl. Subtle bugs may arise!
Also, normal (non-reactive objects) will be directly returned by `toRaw`:
```js
const obj = { a: 1 };
console.log(toRaw(obj) === obj); // true
```
+11
View File
@@ -21,6 +21,7 @@
- [Fragments](#fragments)
- [Inline templates](#inline-templates)
- [Rendering svg](#rendering-svg)
- [Restrictions](#restrictions)
## Overview
@@ -680,3 +681,13 @@ if a template is supposed to be included in a svg namespace or not. Therefore,
Owl depends on a heuristic: if a tag is either `svg`, `g` or `path`, then it will
be considered as svg. In practice, this means that each component or each sub
templates (included with `t-call`) should have one of these tag as root tag.
## Restrictions
Note that Owl templates forbid the use of tag and or attributes starting with
the `block-` string. This restriction prevents name collision with the internal
code of Owl.
```xml
<div><block-1>this will not be accepted by Owl</block-1></div>
```
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@odoo/owl",
"version": "2.0.0-alpha.2",
"version": "2.0.0-beta.3",
"description": "Odoo Web Library (OWL)",
"main": "dist/owl.cjs.js",
"browser": "dist/owl.iife.js",
+20 -8
View File
@@ -18,14 +18,20 @@ export interface AppConfig<P, E> extends TemplateSetConfig {
test?: boolean;
}
export const DEV_MSG = `Owl is running in 'dev' mode.
let hasBeenLogged = false;
export const DEV_MSG = () => {
const hash = (window as any).owl ? (window as any).owl.__info__.hash : "master";
return `Owl is running in 'dev' mode.
This is not suitable for production use.
See https://github.com/odoo/owl/blob/master/doc/reference/config.md#mode for more information.`;
See https://github.com/odoo/owl/blob/${hash}/doc/reference/app.md#configuration for more information.`;
};
export class App<
T extends abstract new (...args: any) => any = any,
P = any,
P extends object = any,
E = any
> extends TemplateSet {
static validateTarget = validateTarget;
@@ -42,11 +48,13 @@ export class App<
if (config.test) {
this.dev = true;
}
if (this.dev && !config.test) {
console.info(DEV_MSG);
if (this.dev && !config.test && !hasBeenLogged) {
console.info(DEV_MSG());
hasBeenLogged = true;
}
const descrs = Object.getOwnPropertyDescriptors(config.env || {});
this.env = Object.freeze(Object.defineProperties({}, descrs)) as E;
const env = config.env || {};
const descrs = Object.getOwnPropertyDescriptors(env);
this.env = Object.freeze(Object.create(Object.getPrototypeOf(env), descrs));
this.props = config.props || ({} as P);
}
@@ -98,7 +106,11 @@ export class App<
}
}
export async function mount<T extends abstract new (...args: any) => any = any, P = any, E = any>(
export async function mount<
T extends abstract new (...args: any) => any = any,
P extends object = any,
E = any
>(
C: T & ComponentConstructor<P, E>,
target: HTMLElement,
config: AppConfig<P, E> & MountOptions = {}
+7 -4
View File
@@ -1,7 +1,9 @@
import { BDom, multi, text, toggler } from "../blockdom";
import { BDom, multi, text, toggler, createCatcher } from "../blockdom";
import { validateProps } from "../component/props_validation";
import { Markup } from "../utils";
import { html } from "../blockdom/index";
import { TARGET } from "../reactivity";
/**
* This file contains utility functions that will be injected in each template,
* to perform various useful tasks in the compiled code.
@@ -21,11 +23,11 @@ function callSlot(
defaultContent?: (ctx: any, node: any, key: string) => BDom
): BDom {
key = key + "__slot_" + name;
const slots = (ctx.props && ctx.props.slots) || {};
const slots = ctx.props[TARGET].slots || {};
const { __render, __ctx, __scope } = slots[name] || {};
const slotScope = Object.create(__ctx || {});
if (__scope) {
slotScope[__scope] = extra || {};
slotScope[__scope] = extra;
}
const slotBDom = __render ? __render.call(__ctx.__owl__.component, slotScope, parent, key) : null;
if (defaultContent) {
@@ -181,7 +183,7 @@ function multiRefSetter(refs: RefMap, name: string): RefSetter {
};
}
export const UTILS = {
export const helpers = {
withDefault,
zero: Symbol("zero"),
isBoundary,
@@ -197,4 +199,5 @@ export const UTILS = {
LazyValue,
safeOutput,
bind,
createCatcher,
};
+30 -25
View File
@@ -1,12 +1,13 @@
import { createBlock, html, list, multi, text, toggler, comment } from "../blockdom";
import { compile, Template } from "../compiler";
import { component } from "../component/component_node";
import { UTILS } from "./template_helpers";
import { markRaw } from "../reactivity";
import { Portal } from "../portal";
import { component, getCurrent } from "../component/component_node";
import { helpers } from "./template_helpers";
import { globalTemplates } from "../utils";
const bdom = { text, createBlock, list, multi, html, toggler, component, comment };
export const globalTemplates: { [key: string]: string | Element } = {};
function parseXML(xml: string): Document {
const parser = new DOMParser();
@@ -37,6 +38,22 @@ function parseXML(xml: string): Document {
return doc;
}
/**
* Returns the helpers object that will be injected in each template closure
* function
*/
function makeHelpers(getTemplate: (name: string) => Template): any {
return Object.assign({}, helpers, {
Portal,
markRaw,
getTemplate,
call: (owner: any, subTemplate: string, ctx: any, parent: any, key: any) => {
const template = getTemplate(subTemplate);
return toggler(subTemplate, template.call(owner, ctx, parent, key));
},
});
}
export interface TemplateSetConfig {
dev?: boolean;
translatableAttributes?: string[];
@@ -50,13 +67,7 @@ export class TemplateSet {
templates: { [name: string]: Template } = {};
translateFn?: (s: string) => string;
translatableAttributes?: string[];
utils: typeof UTILS = Object.assign({}, UTILS, {
call: (owner: any, subTemplate: string, ctx: any, parent: any, key: any) => {
const template = this.getTemplate(subTemplate);
return toggler(subTemplate, template.call(owner, ctx, parent, key));
},
getTemplate: (name: string) => this.getTemplate(name),
});
helpers: any;
constructor(config: TemplateSetConfig = {}) {
this.dev = config.dev || false;
@@ -65,6 +76,7 @@ export class TemplateSet {
if (config.templates) {
this.addTemplates(config.templates);
}
this.helpers = makeHelpers(this.getTemplate.bind(this));
}
addTemplate(
@@ -94,7 +106,12 @@ export class TemplateSet {
if (!(name in this.templates)) {
const rawTemplate = this.rawTemplates[name];
if (rawTemplate === undefined) {
throw new Error(`Missing template: "${name}"`);
let extraInfo = "";
try {
const componentName = getCurrent().component.constructor.name;
extraInfo = ` (for component "${componentName}")`;
} catch {}
throw new Error(`Missing template: "${name}"${extraInfo}`);
}
const templateFn = this._compileTemplate(name, rawTemplate);
// first add a function to lazily get the template, in case there is a
@@ -103,7 +120,7 @@ export class TemplateSet {
this.templates[name] = function (context, parent) {
return templates[name].call(this, context, parent);
};
const template = templateFn(bdom, this.utils);
const template = templateFn(bdom, this.helpers);
this.templates[name] = template;
}
return this.templates[name];
@@ -118,15 +135,3 @@ export class TemplateSet {
});
}
}
// -----------------------------------------------------------------------------
// xml tag helper
// -----------------------------------------------------------------------------
export function xml(...args: Parameters<typeof String.raw>) {
const name = `__template__${xml.nextId++}`;
const value = String.raw(...args);
globalTemplates[name] = value;
return name;
}
xml.nextId = 1;
+1 -1
View File
@@ -139,7 +139,7 @@ export function updateClass(this: HTMLElement, val: any, oldVal: any) {
export function makePropSetter(name: string): Setter<HTMLElement> {
return function setProp(this: HTMLElement, value: any) {
(this as any)[name] = value;
(this as any)[name] = value || "";
};
}
+89
View File
@@ -0,0 +1,89 @@
import { createEventHandler } from "./events";
import type { VNode } from "./index";
type EventsSpec = { [name: string]: number };
type Catcher = (child: VNode, handlers: any[]) => VNode;
export function createCatcher(eventsSpec: EventsSpec): Catcher {
let setupFns: any[] = [];
let removeFns: any[] = [];
for (let name in eventsSpec) {
let index = eventsSpec[name];
let { setup, remove } = createEventHandler(name);
setupFns[index] = setup;
removeFns[index] = remove;
}
let n = setupFns.length;
class VCatcher {
child: VNode;
handlers: any[];
parentEl?: HTMLElement | undefined;
afterNode: Node | null = null;
constructor(child: VNode, handlers: any[]) {
this.child = child;
this.handlers = handlers;
}
mount(parent: HTMLElement, afterNode: Node | null) {
this.parentEl = parent;
this.afterNode = afterNode;
this.child.mount(parent, afterNode);
for (let i = 0; i < n; i++) {
let origFn = this.handlers[i][0];
const self = this;
this.handlers[i][0] = function (ev: any) {
const target = ev.target;
let currentNode: any = self.child.firstNode();
const afterNode = self.afterNode;
while (currentNode !== afterNode) {
if (currentNode.contains(target)) {
return origFn.call(this, ev);
}
currentNode = currentNode.nextSibling;
}
};
setupFns[i].call(parent, this.handlers[i]);
}
}
moveBefore(other: VCatcher | null, afterNode: Node | null) {
this.afterNode = null;
this.child.moveBefore(other ? other.child : null, afterNode);
}
patch(other: VCatcher, withBeforeRemove: boolean) {
if (this === other) {
return;
}
this.handlers = other.handlers;
this.child.patch(other.child, withBeforeRemove);
}
beforeRemove() {
this.child.beforeRemove();
}
remove() {
for (let i = 0; i < n; i++) {
removeFns[i].call(this.parentEl!);
}
this.child.remove();
}
firstNode(): Node | undefined {
return this.child.firstNode();
}
toString(): string {
return this.child.toString();
}
}
return function (child: VNode, handlers: any[]): VNode<VCatcher> {
return new VCatcher(child, handlers);
};
}
+12 -2
View File
@@ -5,6 +5,7 @@ type EventHandlerSetter = (this: HTMLElement, data: any) => void;
interface EventHandlerCreator {
setup: EventHandlerSetter;
update: EventHandlerSetter;
remove: (this: HTMLElement) => void;
}
export function createEventHandler(rawEvent: string): EventHandlerCreator {
@@ -38,11 +39,15 @@ function createElementHandler(evName: string, capture: boolean = false): EventHa
this.addEventListener(evName, listener, { capture });
}
function remove(this: HTMLElement) {
delete (this as any)[eventKey];
this.removeEventListener(evName, listener, { capture });
}
function update(this: HTMLElement, data: any) {
(this as any)[eventKey] = data;
}
return { setup, update };
return { setup, update, remove };
}
// Synthetic handler: a form of event delegation that allows placing only one
@@ -60,7 +65,12 @@ function createSyntheticHandler(evName: string, capture: boolean = false): Event
_data[currentId] = data;
(this as any)[eventKey] = _data;
}
return { setup, update: setup };
function remove(this: HTMLElement) {
delete (this as any)[eventKey];
}
return { setup, update: setup, remove };
}
function nativeToSyntheticEvent(eventKey: string, event: Event) {
+1
View File
@@ -6,6 +6,7 @@ export { list } from "./list";
export { multi } from "./multi";
export { text, comment } from "./text";
export { html } from "./html";
export { createCatcher } from "./event_catcher";
export interface VNode<T = any> {
mount(parent: HTMLElement, afterNode: Node | null): void;
+88 -55
View File
@@ -20,6 +20,8 @@ import {
ASTTranslation,
ASTType,
ASTTPortal,
EventHandlers,
Attrs,
} from "./parser";
type BlockType = "block" | "text" | "multi" | "list" | "html" | "comment";
@@ -157,9 +159,11 @@ class CodeTarget {
// maps ref name to [id, expr]
refInfo: { [name: string]: [string, string] } = {};
shouldProtectScope: boolean = false;
on: EventHandlers | null;
constructor(name: string) {
constructor(name: string, on?: EventHandlers | null) {
this.name = name;
this.on = on || null;
}
addLine(line: string, idx?: number) {
@@ -216,7 +220,7 @@ export class CodeGenerator {
translateFn: (s: string) => string;
translatableAttributes: string[] = TRANSLATABLE_ATTRS;
ast: AST;
staticCalls: { id: string; template: string }[] = [];
staticDefs: { id: string; expr: string }[] = [];
helpers: Set<string> = new Set();
constructor(ast: AST, options: CodeGenOptions) {
@@ -262,8 +266,8 @@ export class CodeGenerator {
mainCode.push(`// Template name: "${this.templateName}"`);
}
for (let { id, template } of this.staticCalls) {
mainCode.push(`const ${id} = getTemplate(${template});`);
for (let { id, expr } of this.staticDefs) {
mainCode.push(`const ${id} = ${expr};`);
}
// define all blocks
@@ -303,20 +307,23 @@ export class CodeGenerator {
return code;
}
compileInNewTarget(prefix: string, ast: AST, ctx: Context): string {
compileInNewTarget(prefix: string, ast: AST, ctx: Context, on?: EventHandlers | null): string {
const name = this.generateId(prefix);
const initialTarget = this.target;
const target = new CodeTarget(name);
const target = new CodeTarget(name, on);
this.targets.push(target);
this.target = target;
const subCtx: Context = createContext(ctx);
this.compileAST(ast, subCtx);
this.compileAST(ast, createContext(ctx));
this.target = initialTarget;
return name;
}
addLine(line: string) {
this.target.addLine(line);
addLine(line: string, idx?: number) {
this.target.addLine(line, idx);
}
define(varName: string, expr: string) {
this.addLine(`const ${varName} = ${expr};`);
}
generateId(prefix: string = ""): string {
@@ -368,9 +375,12 @@ export class CodeGenerator {
}
if (block.isRoot && !ctx.preventRoot) {
if (this.target.on) {
blockExpr = this.wrapWithEventCatcher(blockExpr, this.target.on);
}
this.addLine(`return ${blockExpr};`);
} else {
this.addLine(`let ${block.varName} = ${blockExpr};`);
this.define(block.varName, blockExpr);
}
}
@@ -399,7 +409,7 @@ export class CodeGenerator {
if (!mapping.has(tok.varName)) {
const varId = this.generateId("v");
mapping.set(tok.varName, varId);
this.addLine(`const ${varId} = ${tok.value};`);
this.define(varId, tok.value);
}
tok.value = mapping.get(tok.varName)!;
}
@@ -544,12 +554,12 @@ export class CodeGenerator {
this.blocks.push(block);
if (ast.dynamicTag) {
const tagExpr = this.generateId("tag");
this.addLine(`let ${tagExpr} = ${compileExpr(ast.dynamicTag)};`);
this.define(tagExpr, compileExpr(ast.dynamicTag));
block.dynamicTagName = tagExpr;
}
}
// attributes
const attrs: { [key: string]: string } = {};
const attrs: Attrs = {};
const nameSpace = ast.ns || ctx.nameSpace;
if (nameSpace && isNewBlock) {
// specific namespace uri
@@ -639,11 +649,11 @@ export class CodeGenerator {
const baseExpression = compileExpr(baseExpr);
const bExprId = this.generateId("bExpr");
this.addLine(`const ${bExprId} = ${baseExpression};`);
this.define(bExprId, baseExpression);
const expression = compileExpr(expr);
const exprId = this.generateId("expr");
this.addLine(`const ${exprId} = ${expression};`);
this.define(exprId, expression);
const fullExpression = `${bExprId}[${exprId}]`;
@@ -654,7 +664,7 @@ export class CodeGenerator {
} else if (hasDynamicChildren) {
const bValueId = this.generateId("bValue");
tModelSelectedExpr = `${bValueId}`;
this.addLine(`let ${tModelSelectedExpr} = ${fullExpression}`);
this.define(tModelSelectedExpr, fullExpression);
} else {
idx = block!.insertData(`${fullExpression}`, "attr");
attrs[`block-attribute-${idx}`] = targetAttr;
@@ -704,13 +714,13 @@ export class CodeGenerator {
const children = block!.children.slice();
let current = children.shift();
for (let i = codeIdx; i < code.length; i++) {
if (code[i].trimStart().startsWith(`let ${current!.varName} `)) {
code[i] = code[i].replace(`let ${current!.varName}`, current!.varName);
if (code[i].trimStart().startsWith(`const ${current!.varName} `)) {
code[i] = code[i].replace(`const ${current!.varName}`, current!.varName);
current = children.shift();
if (!current) break;
}
}
this.target.addLine(`let ${block!.children.map((c) => c.varName)};`, codeIdx);
this.addLine(`let ${block!.children.map((c) => c.varName)};`, codeIdx);
}
}
}
@@ -799,13 +809,13 @@ export class CodeGenerator {
const children = block!.children.slice();
let current = children.shift();
for (let i = codeIdx; i < code.length; i++) {
if (code[i].trimStart().startsWith(`let ${current!.varName} `)) {
code[i] = code[i].replace(`let ${current!.varName}`, current!.varName);
if (code[i].trimStart().startsWith(`const ${current!.varName} `)) {
code[i] = code[i].replace(`const ${current!.varName}`, current!.varName);
current = children.shift();
if (!current) break;
}
}
this.target.addLine(`let ${block!.children.map((c) => c.varName)};`, codeIdx);
this.addLine(`let ${block!.children.map((c) => c.varName)};`, codeIdx);
}
// note: this part is duplicated from end of compilemulti:
@@ -828,12 +838,10 @@ export class CodeGenerator {
const l = `l_block${block.id}`;
const c = `c_block${block.id}`;
this.helpers.add("prepareList");
this.addLine(
`const [${keys}, ${vals}, ${l}, ${c}] = prepareList(${compileExpr(ast.collection)});`
);
this.define(`[${keys}, ${vals}, ${l}, ${c}]`, `prepareList(${compileExpr(ast.collection)});`);
// Throw errors on duplicate keys in dev mode
if (this.dev) {
this.addLine(`const keys${block.id} = new Set();`);
this.define(`keys${block.id}`, `new Set()`);
}
this.addLine(`for (let ${loopVar} = 0; ${loopVar} < ${l}; ${loopVar}++) {`);
this.target.indentLevel++;
@@ -850,7 +858,7 @@ export class CodeGenerator {
if (!ast.hasNoValue) {
this.addLine(`ctx[\`${ast.elem}_value\`] = ${keys}[${loopVar}];`);
}
this.addLine(`let key${this.target.loopLevel} = ${ast.key ? compileExpr(ast.key) : loopVar};`);
this.define(`key${this.target.loopLevel}`, ast.key ? compileExpr(ast.key) : loopVar);
if (this.dev) {
// Throw error on duplicate keys in dev mode
this.addLine(
@@ -862,8 +870,8 @@ export class CodeGenerator {
if (ast.memo) {
this.target.hasCache = true;
id = this.generateId();
this.addLine(`let memo${id} = ${compileExpr(ast.memo)}`);
this.addLine(`let vnode${id} = cache[key${this.target.loopLevel}];`);
this.define(`memo${id}`, compileExpr(ast.memo));
this.define(`vnode${id}`, `cache[key${this.target.loopLevel}];`);
this.addLine(`if (vnode${id}) {`);
this.target.indentLevel++;
this.addLine(`if (shallowEqual(vnode${id}.memo, memo${id})) {`);
@@ -897,7 +905,7 @@ export class CodeGenerator {
compileTKey(ast: ASTTKey, ctx: Context) {
const tKeyExpr = this.generateId("tKey_");
this.addLine(`const ${tKeyExpr} = ${compileExpr(ast.expr)};`);
this.define(tKeyExpr, compileExpr(ast.expr));
ctx = createContext(ctx, {
tKeyExpr,
block: ctx.block,
@@ -943,13 +951,13 @@ export class CodeGenerator {
const children = block!.children.slice();
let current = children.shift();
for (let i = codeIdx; i < code.length; i++) {
if (code[i].trimStart().startsWith(`let ${current!.varName} `)) {
code[i] = code[i].replace(`let ${current!.varName}`, current!.varName);
if (code[i].trimStart().startsWith(`const ${current!.varName} `)) {
code[i] = code[i].replace(`const ${current!.varName}`, current!.varName);
current = children.shift();
if (!current) break;
}
}
this.target.addLine(`let ${block!.children.map((c) => c.varName)};`, codeIdx);
this.addLine(`let ${block!.children.map((c) => c.varName)};`, codeIdx);
}
}
@@ -982,7 +990,7 @@ export class CodeGenerator {
const key = `key + \`${this.generateComponentKey()}\``;
if (isDynamic) {
const templateVar = this.generateId("template");
this.addLine(`const ${templateVar} = ${subTemplate};`);
this.define(templateVar, subTemplate);
block = this.createBlock(block, "multi", ctx);
this.helpers.add("call");
this.insertBlock(`call(this, ${templateVar}, ctx, node, ${key})`, block!, {
@@ -992,7 +1000,7 @@ export class CodeGenerator {
} else {
const id = this.generateId(`callTemplate_`);
this.helpers.add("getTemplate");
this.staticCalls.push({ id, template: subTemplate });
this.staticDefs.push({ id, expr: `getTemplate(${subTemplate})` });
block = this.createBlock(block, "multi", ctx);
this.insertBlock(`${id}.call(this, ctx, node, ${key})`, block!, {
...ctx,
@@ -1087,29 +1095,27 @@ export class CodeGenerator {
compileComponent(ast: ASTComponent, ctx: Context) {
let { block } = ctx;
// props
const hasSlotsProp = "slots" in ast.props;
const hasSlotsProp = "slots" in (ast.props || {});
const props: string[] = [];
const propExpr = this.formatPropObject(ast.props);
const propExpr = this.formatPropObject(ast.props || {});
if (propExpr) {
props.push(propExpr);
}
// slots
const hasSlot = !!Object.keys(ast.slots).length;
let slotDef: string = "";
if (hasSlot) {
if (ast.slots) {
let ctxStr = "ctx";
if (this.target.loopLevel || !this.hasSafeContext) {
ctxStr = this.generateId("ctx");
this.helpers.add("capture");
this.addLine(`const ${ctxStr} = capture(ctx);`);
this.define(ctxStr, `capture(ctx)`);
}
let slotStr: string[] = [];
for (let slotName in ast.slots) {
const slotAst = ast.slots[slotName].content;
const name = this.compileInNewTarget("slot", slotAst, ctx);
const slotAst = ast.slots[slotName];
const name = this.compileInNewTarget("slot", slotAst.content, ctx, slotAst.on);
const params = [`__render: ${name}, __ctx: ${ctxStr}`];
const scope = ast.slots[slotName].scope;
if (scope) {
@@ -1125,29 +1131,29 @@ export class CodeGenerator {
}
if (slotDef && !(ast.dynamicProps || hasSlotsProp)) {
props.push(`slots: ${slotDef}`);
this.helpers.add("markRaw");
props.push(`slots: markRaw(${slotDef})`);
}
const propStr = `{${props.join(",")}}`;
let propString = propStr;
if (ast.dynamicProps) {
if (!props.length) {
propString = `Object.assign({}, ${compileExpr(ast.dynamicProps)})`;
} else {
propString = `Object.assign({}, ${compileExpr(ast.dynamicProps)}, ${propStr})`;
}
propString = `Object.assign({}, ${compileExpr(ast.dynamicProps)}${
props.length ? ", " + propStr : ""
})`;
}
let propVar: string;
if ((slotDef && (ast.dynamicProps || hasSlotsProp)) || this.dev) {
propVar = this.generateId("props");
this.addLine(`const ${propVar!} = ${propString};`);
this.define(propVar!, propString);
propString = propVar!;
}
if (slotDef && (ast.dynamicProps || hasSlotsProp)) {
this.addLine(`${propVar!}.slots = Object.assign(${slotDef}, ${propVar!}.slots)`);
this.helpers.add("markRaw");
this.addLine(`${propVar!}.slots = markRaw(Object.assign(${slotDef}, ${propVar!}.slots))`);
}
// cmap key
@@ -1155,7 +1161,7 @@ export class CodeGenerator {
let expr: string;
if (ast.isDynamic) {
expr = this.generateId("Comp");
this.addLine(`let ${expr} = ${compileExpr(ast.name)};`);
this.define(expr, compileExpr(ast.name));
} else {
expr = `\`${ast.name}\``;
}
@@ -1178,10 +1184,32 @@ export class CodeGenerator {
if (ast.isDynamic) {
blockExpr = `toggler(${expr}, ${blockExpr})`;
}
// event handling
if (ast.on) {
blockExpr = this.wrapWithEventCatcher(blockExpr, ast.on);
}
block = this.createBlock(block, "multi", ctx);
this.insertBlock(blockExpr, block, ctx);
}
wrapWithEventCatcher(expr: string, on: EventHandlers): string {
this.helpers.add("createCatcher");
let name = this.generateId("catcher");
let spec: any = {};
let handlers: any[] = [];
for (let ev in on) {
let handlerId = this.generateId("hdlr");
let idx = handlers.push(handlerId) - 1;
spec[ev] = idx;
const handler = this.generateHandlerCode(ev, on[ev]);
this.define(handlerId, handler);
}
this.staticDefs.push({ id: name, expr: `createCatcher(${JSON.stringify(spec)})` });
return `${name}(${expr}, [${handlers.join(",")}])`;
}
compileTSlot(ast: ASTSlot, ctx: Context) {
this.helpers.add("callSlot");
let { block } = ctx;
@@ -1202,12 +1230,17 @@ export class CodeGenerator {
} else {
if (dynamic) {
let name = this.generateId("slot");
this.addLine(`const ${name} = ${slotName};`);
this.define(name, slotName);
blockString = `toggler(${name}, callSlot(ctx, node, key, ${name}), ${dynamic}, ${scope})`;
} else {
blockString = `callSlot(ctx, node, key, ${slotName}, ${dynamic}, ${scope})`;
}
}
// event handling
if (ast.on) {
blockString = this.wrapWithEventCatcher(blockString, ast.on);
}
if (block) {
this.insertAnchor(block);
}
@@ -1230,7 +1263,7 @@ export class CodeGenerator {
if (this.target.loopLevel || !this.hasSafeContext) {
ctxStr = this.generateId("ctx");
this.helpers.add("capture");
this.addLine(`const ${ctxStr} = capture(ctx);`);
this.define(ctxStr, `capture(ctx);`);
}
const blockString = `component(Portal, {target: ${ast.target},slots: {'default': {__render: ${name}, __ctx: ${ctxStr}}}}, key + \`${key}\`, node, ctx)`;
if (block) {
+19 -13
View File
@@ -199,24 +199,30 @@ const TOKENIZERS = [
export function tokenize(expr: string): Token[] {
const result: Token[] = [];
let token: boolean | Token = true;
let error: any;
let current = expr;
while (token) {
expr = expr.trim();
if (expr) {
for (let tokenizer of TOKENIZERS) {
token = tokenizer(expr);
if (token) {
result.push(token);
expr = expr.slice(token.size || token.value.length);
break;
try {
while (token) {
current = current.trim();
if (current) {
for (let tokenizer of TOKENIZERS) {
token = tokenizer(current);
if (token) {
result.push(token);
current = current.slice(token.size || token.value.length);
break;
}
}
} else {
token = false;
}
} else {
token = false;
}
} catch (e) {
error = e; // Silence all errors and throw a generic error below
}
if (expr.length) {
throw new Error(`Tokenizer error: could not tokenize "${expr}"`);
if (current.length || error) {
throw new Error(`Tokenizer error: could not tokenize \`${expr}\``);
}
return result;
}
+69 -33
View File
@@ -2,6 +2,9 @@
// AST Type definition
// -----------------------------------------------------------------------------
export type EventHandlers = { [eventName: string]: string };
export type Attrs = { [attrs: string]: string };
export const enum ASTType {
Text,
Comment,
@@ -34,25 +37,25 @@ export interface ASTComment {
}
interface TModelInfo {
hasDynamicChildren?: boolean;
baseExpr: string;
expr: string;
targetAttr: string;
specialInitTargetAttr: string | null;
eventType: "change" | "click" | "input";
shouldTrim: boolean;
shouldNumberize: boolean;
hasDynamicChildren: boolean;
specialInitTargetAttr: string | null;
}
export interface ASTDomNode {
type: ASTType.DomNode;
tag: string;
dynamicTag: string | null;
attrs: { [key: string]: string };
content: AST[];
attrs: Attrs | null;
ref: string | null;
on: { [key: string]: string };
model?: TModelInfo | null;
on: EventHandlers | null;
model: TModelInfo | null;
dynamicTag: string | null;
ns: string | null;
}
@@ -93,13 +96,13 @@ export interface ASTTForEach {
type: ASTType.TForEach;
collection: string;
elem: string;
key: string | null;
body: AST;
memo: string;
hasNoFirst: boolean;
hasNoLast: boolean;
hasNoIndex: boolean;
hasNoValue: boolean;
key: string | null;
}
export interface ASTTKey {
@@ -114,19 +117,28 @@ export interface ASTTCall {
body: AST[] | null;
}
interface SlotDefinition {
content: AST;
scope: string | null;
on: EventHandlers | null;
attrs: Attrs | null;
}
export interface ASTComponent {
type: ASTType.TComponent;
name: string;
isDynamic: boolean;
dynamicProps: string | null;
props: { [name: string]: string };
slots: { [name: string]: { content: AST; attrs?: { [key: string]: string }; scope?: string } };
on: EventHandlers | null;
props: { [name: string]: string } | null;
slots: { [name: string]: SlotDefinition } | null;
}
export interface ASTSlot {
type: ASTType.TSlot;
name: string;
attrs: { [key: string]: string };
attrs: Attrs | null;
on: EventHandlers | null;
defaultContent: AST | null;
}
@@ -305,6 +317,9 @@ function parseDOMNode(node: Element, ctx: ParsingContext): AST | null {
if (tagName === "t" && !dynamicTag) {
return null;
}
if (tagName.startsWith("block-")) {
throw new Error(`Invalid tag name: '${tagName}'`);
}
ctx = Object.assign({}, ctx);
if (tagName === "pre") {
ctx.inPreTag = true;
@@ -316,8 +331,8 @@ function parseDOMNode(node: Element, ctx: ParsingContext): AST | null {
node.removeAttribute("t-ref");
const nodeAttrsNames = node.getAttributeNames();
const attrs: ASTDomNode["attrs"] = {};
const on: ASTDomNode["on"] = {};
let attrs: ASTDomNode["attrs"] = null;
let on: EventHandlers | null = null;
let model: TModelInfo | null = null;
for (let attr of nodeAttrsNames) {
@@ -326,6 +341,7 @@ function parseDOMNode(node: Element, ctx: ParsingContext): AST | null {
if (attr === "t-on") {
throw new Error("Missing event name with t-on directive");
}
on = on || {};
on[attr.slice(5)] = value;
} else if (attr.startsWith("t-model")) {
if (!["input", "select", "textarea"].includes(tagName)) {
@@ -363,6 +379,7 @@ function parseDOMNode(node: Element, ctx: ParsingContext): AST | null {
targetAttr: isCheckboxInput ? "checked" : "value",
specialInitTargetAttr: isRadioInput ? "checked" : null,
eventType,
hasDynamicChildren: false,
shouldTrim: hasTrimMod && (isOtherInput || isTextarea),
shouldNumberize: hasNumberMod && (isOtherInput || isTextarea),
};
@@ -371,6 +388,8 @@ function parseDOMNode(node: Element, ctx: ParsingContext): AST | null {
ctx = Object.assign({}, ctx);
ctx.tModelInfo = model;
}
} else if (attr.startsWith("block-")) {
throw new Error(`Invalid attribute: '${attr}'`);
} else if (attr !== "t-name") {
if (attr.startsWith("t-") && !attr.startsWith("t-att")) {
throw new Error(`Unknown QWeb directive: '${attr}'`);
@@ -379,6 +398,7 @@ function parseDOMNode(node: Element, ctx: ParsingContext): AST | null {
if (tModel && ["t-att-value", "t-attf-value"].includes(attr)) {
tModel.hasDynamicChildren = true;
}
attrs = attrs || {};
attrs[attr] = value;
}
}
@@ -549,7 +569,7 @@ function parseTCall(node: Element, ctx: ParsingContext): AST | null {
if (ast && ast.type === ASTType.TComponent) {
return {
...ast,
slots: { default: { content: tcall } },
slots: { default: { content: tcall, scope: null, on: null, attrs: null } },
};
}
}
@@ -645,7 +665,6 @@ function parseTSetNode(node: Element, ctx: ParsingContext): AST | null {
// Error messages when trying to use an unsupported directive on a component
const directiveErrorMap = new Map([
["t-on", "t-on is no longer supported on components. Consider passing a callback in props."],
[
"t-ref",
"t-ref is no longer supported on components. Consider exposing only the public part of the component's API through a callback prop.",
@@ -679,19 +698,26 @@ function parseComponent(node: Element, ctx: ParsingContext): AST | null {
const defaultSlotScope = node.getAttribute("t-slot-scope");
node.removeAttribute("t-slot-scope");
let on: ASTComponent["on"] = null;
const props: ASTComponent["props"] = {};
let props: ASTComponent["props"] = null;
for (let name of node.getAttributeNames()) {
const value = node.getAttribute(name)!;
if (name.startsWith("t-")) {
const message = directiveErrorMap.get(name.split("-").slice(0, 2).join("-"));
throw new Error(message || `unsupported directive on Component: ${name}`);
if (name.startsWith("t-on-")) {
on = on || {};
on[name.slice(5)] = value;
} else {
const message = directiveErrorMap.get(name.split("-").slice(0, 2).join("-"));
throw new Error(message || `unsupported directive on Component: ${name}`);
}
} else {
props = props || {};
props[name] = value;
}
}
const slots: ASTComponent["slots"] = {};
let slots: ASTComponent["slots"] | null = null;
if (node.hasChildNodes()) {
const clone = <Element>node.cloneNode(true);
@@ -724,33 +750,35 @@ function parseComponent(node: Element, ctx: ParsingContext): AST | null {
slotNode.remove();
const slotAst = parseNode(slotNode, ctx);
if (slotAst) {
const slotInfo: any = { content: slotAst };
const attrs: { [key: string]: string } = {};
let on: SlotDefinition["on"] = null;
let attrs: Attrs | null = null;
let scope: string | null = null;
for (let attributeName of slotNode.getAttributeNames()) {
const value = slotNode.getAttribute(attributeName)!;
if (attributeName === "t-slot-scope") {
slotInfo.scope = value;
scope = value;
continue;
} else if (attributeName.startsWith("t-on-")) {
on = on || {};
on[attributeName.slice(5)] = value;
} else {
attrs = attrs || {};
attrs[attributeName] = value;
}
attrs[attributeName] = value;
}
if (Object.keys(attrs).length) {
slotInfo.attrs = attrs;
}
slots[name] = slotInfo;
slots = slots || {};
slots[name] = { content: slotAst, on, attrs, scope };
}
}
// default slot
const defaultContent = parseChildNodes(clone, ctx);
if (defaultContent) {
slots.default = { content: defaultContent };
if (defaultSlotScope) {
slots.default.scope = defaultSlotScope;
}
slots = slots || {};
slots.default = { content: defaultContent, on, attrs: null, scope: defaultSlotScope };
}
}
return { type: ASTType.TComponent, name, isDynamic, dynamicProps, props, slots };
return { type: ASTType.TComponent, name, isDynamic, dynamicProps, props, slots, on };
}
// -----------------------------------------------------------------------------
@@ -763,15 +791,23 @@ function parseTSlot(node: Element, ctx: ParsingContext): AST | null {
}
const name = node.getAttribute("t-slot")!;
node.removeAttribute("t-slot");
const attrs: { [key: string]: string } = {};
let attrs: Attrs | null = null;
let on: ASTComponent["on"] = null;
for (let attributeName of node.getAttributeNames()) {
const value = node.getAttribute(attributeName)!;
attrs[attributeName] = value;
if (attributeName.startsWith("t-on-")) {
on = on || {};
on[attributeName.slice(5)] = value;
} else {
attrs = attrs || {};
attrs[attributeName] = value;
}
}
return {
type: ASTType.TSlot,
name,
attrs,
on,
defaultContent: parseChildNodes(node, ctx),
};
}
+2 -2
View File
@@ -36,7 +36,7 @@ export class Component<Props = any, Env = any> {
setup() {}
render() {
this.__owl__.render();
render(deep: boolean = false) {
this.__owl__.render(deep);
}
}
+102 -15
View File
@@ -1,6 +1,16 @@
import type { App, Env } from "../app/app";
import { BDom, VNode } from "../blockdom";
import {
clearReactivesForCallback,
Reactive,
reactive,
TARGET,
NonReactive,
getSubscriptions,
} from "../reactivity";
import { batched, Callback } from "../utils";
import { Component, ComponentConstructor } from "./component";
import { fibersInError, handleError } from "./error_handling";
import {
Fiber,
makeChildFiber,
@@ -9,7 +19,6 @@ import {
MountOptions,
RootFiber,
} from "./fibers";
import { handleError, fibersInError } from "./error_handling";
import { applyDefaultProps } from "./props_validation";
import { STATUS } from "./status";
@@ -26,13 +35,61 @@ export function useComponent(): Component {
return currentNode!.component;
}
export function component(
name: string | typeof Component,
props: any,
// -----------------------------------------------------------------------------
// Integration with reactivity system (useState)
// -----------------------------------------------------------------------------
const batchedRenderFunctions = new WeakMap<ComponentNode, Callback>();
/**
* Creates a reactive object that will be observed by the current component.
* Reading data from the returned object (eg during rendering) will cause the
* component to subscribe to that data and be rerendered when it changes.
*
* @param state the state to observe
* @returns a reactive object that will cause the component to re-render on
* relevant changes
* @see reactive
*/
export function useState<T extends object>(state: T): Reactive<T> | NonReactive<T> {
const node = getCurrent();
let render = batchedRenderFunctions.get(node)!;
if (!render) {
render = batched(node.render.bind(node));
batchedRenderFunctions.set(node, render);
// manual implementation of onWillDestroy to break cyclic dependency
node.willDestroy.push(clearReactivesForCallback.bind(null, render));
if (node.app.dev) {
Object.defineProperty(node, "subscriptions", {
get() {
return getSubscriptions(render);
},
});
}
}
return reactive(state, render);
}
// -----------------------------------------------------------------------------
// component function (used in compiled template code)
// -----------------------------------------------------------------------------
type Props = { [key: string]: any };
function arePropsDifferent(props1: Props, props2: Props): boolean {
for (let k in props1) {
if (props1[k] !== props2[k]) {
return true;
}
}
return Object.keys(props1).length !== Object.keys(props2).length;
}
export function component<P extends object>(
name: string | ComponentConstructor<P>,
props: P,
key: string,
ctx: ComponentNode,
parent: any
): ComponentNode {
): ComponentNode<P> {
let node: any = ctx.children[key];
let isDynamic = typeof name !== "string";
@@ -50,7 +107,16 @@ export function component(
const parentFiber = ctx.fiber!;
if (node) {
node.updateAndRender(props, parentFiber);
let shouldRender = node.forceNextRender;
if (shouldRender) {
node.forceNextRender = false;
} else {
const currentProps = node.component.props[TARGET];
shouldRender = parentFiber.deep || arePropsDifferent(currentProps, props);
}
if (shouldRender) {
node.updateAndRender(props, parentFiber);
}
} else {
// new component
let C;
@@ -65,25 +131,25 @@ export function component(
node = new ComponentNode(C, props, ctx.app, ctx);
ctx.children[key] = node;
const fiber = makeChildFiber(node, parentFiber);
node.initiateRender(fiber);
node.initiateRender(new Fiber(node, parentFiber));
}
return node;
}
// -----------------------------------------------------------------------------
// Component VNode
// Component VNode class
// -----------------------------------------------------------------------------
type LifecycleHook = Function;
export class ComponentNode<P = any, E = any> implements VNode<ComponentNode<P, E>> {
export class ComponentNode<P extends object = any, E = any> implements VNode<ComponentNode<P, E>> {
el?: HTMLElement | Text | undefined;
app: App;
fiber: Fiber | null = null;
component: Component<P, E>;
bdom: BDom | null = null;
status: STATUS = STATUS.NEW;
forceNextRender: boolean = false;
renderFn: Function;
parent: ComponentNode | null;
@@ -108,6 +174,7 @@ export class ComponentNode<P = any, E = any> implements VNode<ComponentNode<P, E
applyDefaultProps(props, C);
const env = (parent && parent.childEnv) || app.env;
this.childEnv = env;
props = useState(props);
this.component = new C(props, env, this) as any;
this.renderFn = app.getTemplate(C.template).bind(this.component, this.component, this);
this.component.setup();
@@ -137,21 +204,29 @@ export class ComponentNode<P = any, E = any> implements VNode<ComponentNode<P, E
}
}
async render() {
async render(deep: boolean = false) {
let current = this.fiber;
if (current && current.root!.locked) {
await Promise.resolve();
// situation may have changed after the microtask tick
current = this.fiber;
}
if (current && !current.bdom && !fibersInError.has(current)) {
return;
}
if (!this.bdom && !current) {
if (current) {
if (!current.bdom && !fibersInError.has(current)) {
if (deep) {
// we want the render from this point on to be with deep=true
current.deep = deep;
}
return;
}
// if current rendering was with deep=true, we want this one to be the same
deep = deep || current.deep;
} else if (!this.bdom) {
return;
}
const fiber = makeRootFiber(this);
fiber.deep = deep;
this.fiber = fiber;
this.app.scheduler.addFiber(fiber);
await Promise.resolve();
@@ -213,6 +288,10 @@ export class ComponentNode<P = any, E = any> implements VNode<ComponentNode<P, E
this.fiber = fiber;
const component = this.component;
applyDefaultProps(props, component.constructor as any);
currentNode = this;
props = useState(props);
currentNode = null;
const prom = Promise.all(this.willUpdateProps.map((f) => f.call(component, props)));
await prom;
if (fiber !== this.fiber) {
@@ -277,6 +356,14 @@ export class ComponentNode<P = any, E = any> implements VNode<ComponentNode<P, E
}
patch() {
if (this.fiber && this.fiber.parent) {
// we only patch here renderings coming from above. renderings initiated
// by the component will be patched independently in the appropriate
// fiber.complete
this._patch();
}
}
_patch() {
const hasChildren = Object.keys(this.children).length > 0;
this.bdom!.patch(this!.fiber!.bdom!, hasChildren);
if (hasChildren) {
+16 -10
View File
@@ -6,8 +6,7 @@ import { STATUS } from "./status";
export function makeChildFiber(node: ComponentNode, parent: Fiber): Fiber {
let current = node.fiber;
if (current) {
let root = parent.root;
cancelFibers(root, current.children);
cancelFibers(current.children);
current.root = null;
}
return new Fiber(node, parent);
@@ -17,9 +16,8 @@ export function makeRootFiber(node: ComponentNode): Fiber {
let current = node.fiber;
if (current) {
let root = current.root!;
root.counter -= cancelFibers(root, current.children);
root.counter = root.counter + 1 - cancelFibers(current.children);
current.children = [];
root.counter++;
current.bdom = null;
if (fibersInError.has(current)) {
fibersInError.delete(current);
@@ -35,22 +33,28 @@ export function makeRootFiber(node: ComponentNode): Fiber {
if (node.patched.length) {
fiber.patched.push(fiber);
}
return fiber;
}
/**
* @returns number of not-yet rendered fibers cancelled
*/
function cancelFibers(root: any, fibers: Fiber[]): number {
function cancelFibers(fibers: Fiber[]): number {
let result = 0;
for (let fiber of fibers) {
fiber.node.fiber = null;
fiber.root = root;
if (!fiber.bdom) {
if (fiber.bdom) {
// if fiber has been rendered, this means that the component props have
// been updated. however, this fiber will not be patched to the dom, so
// it could happen that the next render compare the current props with
// the same props, and skip the render completely. With the next line,
// we kindly request the component code to force a render, so it works as
// expected.
fiber.node.forceNextRender = true;
} else {
result++;
}
result += cancelFibers(root, fiber.children);
result += cancelFibers(fiber.children);
}
return result;
}
@@ -62,11 +66,13 @@ export class Fiber {
parent: Fiber | null;
children: Fiber[] = [];
appliedToDom = false;
deep: boolean = false;
constructor(node: ComponentNode, parent: Fiber | null) {
this.node = node;
this.parent = parent;
if (parent) {
this.deep = parent.deep;
const root = parent.root!;
root.counter++;
this.root = root;
@@ -109,7 +115,7 @@ export class RootFiber extends Fiber {
current = undefined;
// Step 2: patching the dom
node.patch();
node._patch();
this.locked = false;
// Step 4: calling all mounted lifecycle hooks
+46 -9
View File
@@ -1,50 +1,85 @@
import { getCurrent } from "./component_node";
import { nodeErrorHandlers } from "./error_handling";
function wrapError(fn: (...args: any[]) => any, hookName: string) {
const error = new Error(`The following error occurred in ${hookName}: `) as Error & {
cause: any;
};
return (...args: any[]) => {
try {
const result = fn(...args);
if (result instanceof Promise) {
return result.catch((cause) => {
error.cause = cause;
if (cause instanceof Error) {
error.message += `"${cause.message}"`;
}
throw error;
});
}
return result;
} catch (cause) {
if (cause instanceof Error) {
error.message += `"${cause.message}"`;
}
throw error;
}
};
}
// -----------------------------------------------------------------------------
// hooks
// -----------------------------------------------------------------------------
export function onWillStart(fn: () => Promise<void> | void | any) {
const node = getCurrent();
node.willStart.push(fn.bind(node.component));
const decorate = node.app.dev ? wrapError : (fn: any) => fn;
node.willStart.push(decorate(fn.bind(node.component), "onWillStart"));
}
export function onWillUpdateProps(fn: (nextProps: any) => Promise<void> | void | any) {
const node = getCurrent();
node.willUpdateProps.push(fn.bind(node.component));
const decorate = node.app.dev ? wrapError : (fn: any) => fn;
node.willUpdateProps.push(decorate(fn.bind(node.component), "onWillUpdateProps"));
}
export function onMounted(fn: () => void | any) {
const node = getCurrent();
node.mounted.push(fn.bind(node.component));
const decorate = node.app.dev ? wrapError : (fn: any) => fn;
node.mounted.push(decorate(fn.bind(node.component), "onMounted"));
}
export function onWillPatch(fn: () => Promise<void> | any | void) {
const node = getCurrent();
node.willPatch.unshift(fn.bind(node.component));
const decorate = node.app.dev ? wrapError : (fn: any) => fn;
node.willPatch.unshift(decorate(fn.bind(node.component), "onWillPatch"));
}
export function onPatched(fn: () => void | any) {
const node = getCurrent();
node.patched.push(fn.bind(node.component));
const decorate = node.app.dev ? wrapError : (fn: any) => fn;
node.patched.push(decorate(fn.bind(node.component), "onPatched"));
}
export function onWillUnmount(fn: () => Promise<void> | void | any) {
const node = getCurrent();
node.willUnmount.unshift(fn.bind(node.component));
const decorate = node.app.dev ? wrapError : (fn: any) => fn;
node.willUnmount.unshift(decorate(fn.bind(node.component), "onWillUnmount"));
}
export function onWillDestroy(fn: () => Promise<void> | void | any) {
const node = getCurrent();
node.willDestroy.push(fn.bind(node.component));
const decorate = node.app.dev ? wrapError : (fn: any) => fn;
node.willDestroy.push(decorate(fn.bind(node.component), "onWillDestroy"));
}
export function onWillRender(fn: () => void | any) {
const node = getCurrent();
const renderFn = node.renderFn;
const decorate = node.app.dev ? wrapError : (fn: any) => fn;
fn = decorate(fn.bind(node.component), "onWillRender");
node.renderFn = () => {
fn.call(node.component);
fn();
return renderFn();
};
}
@@ -52,9 +87,11 @@ export function onWillRender(fn: () => void | any) {
export function onRendered(fn: () => void | any) {
const node = getCurrent();
const renderFn = node.renderFn;
const decorate = node.app.dev ? wrapError : (fn: any) => fn;
fn = decorate(fn.bind(node.component), "onRendered");
node.renderFn = () => {
const result = renderFn();
fn.call(node.component);
fn();
return result;
};
}
+3 -8
View File
@@ -1,4 +1,3 @@
import { UTILS } from "./app/template_helpers";
import {
config,
createBlock,
@@ -13,12 +12,10 @@ import {
comment,
} from "./blockdom";
import { mainEventHandler } from "./component/handler";
import { Portal } from "./portal";
export type { Reactive } from "./reactivity";
config.shouldNormalizeDom = false;
config.mainEventHandler = mainEventHandler;
(UTILS as any).Portal = Portal;
export const blockDom = {
config,
@@ -38,13 +35,11 @@ export const blockDom = {
export { App, mount } from "./app/app";
export { Component } from "./component/component";
export { useComponent } from "./component/component_node";
export { useComponent, useState } from "./component/component_node";
export { status } from "./component/status";
export { Memo } from "./memo";
export { xml } from "./app/template_set";
export { useState, reactive, markRaw, toRaw } from "./reactivity";
export { reactive, markRaw, toRaw } from "./reactivity";
export { useEffect, useEnv, useExternalListener, useRef, useChildSubEnv, useSubEnv } from "./hooks";
export { EventBus, whenReady, loadFile, markup } from "./utils";
export { EventBus, whenReady, loadFile, markup, xml } from "./utils";
export {
onWillStart,
onMounted,
-47
View File
@@ -1,47 +0,0 @@
import { Component } from "./component/component";
import type { ComponentNode } from "./component/component_node";
import { xml } from "./app/template_set";
import { Fiber } from "./component/fibers";
export class Memo extends Component {
static template = xml`<t t-slot="default"/>`;
constructor(props: any, env: any, node: ComponentNode) {
super(props, env, node);
// prevent patching process conditionally
let applyPatch = false;
const patchFn = node.patch;
node.patch = () => {
if (applyPatch) {
patchFn.call(node);
applyPatch = false;
}
};
// check props change, and render/apply patch if it changed
let prevProps = props;
const updateAndRender = node.updateAndRender;
node.updateAndRender = function (props: any, parentFiber: Fiber) {
const shouldUpdate = !shallowEqual(prevProps, props);
if (shouldUpdate) {
prevProps = props;
updateAndRender.call(node, props, parentFiber);
applyPatch = true;
}
return Promise.resolve();
};
}
}
/**
* we assume that each object have the same set of keys
*/
function shallowEqual(p1: any, p2: any): boolean {
for (let k in p1) {
if (k !== "slots" && p1[k] !== p2[k]) {
return false;
}
}
return true;
}
+1 -1
View File
@@ -1,5 +1,5 @@
import { onWillUnmount } from "./component/lifecycle_hooks";
import { xml } from "./app/template_set";
import { xml } from "./utils";
import { BDom, text, VNode } from "./blockdom";
import { Component } from "./component/component";
+257 -82
View File
@@ -1,27 +1,42 @@
import { onWillDestroy } from "./component/lifecycle_hooks";
import { ComponentNode, getCurrent } from "./component/component_node";
import { batched, Callback } from "./utils";
import { Callback } from "./utils";
// Allows to get the target of a Reactive (used for making a new Reactive from the underlying object)
const TARGET = Symbol("Target");
export const TARGET = Symbol("Target");
// Escape hatch to prevent reactivity system to turn something into a reactive
const SKIP = Symbol("Skip");
// Special key to subscribe to, to be notified of key creation/deletion
const KEYCHANGES = Symbol("Key changes");
type ObjectKey = string | number | symbol;
type Target = object;
type Collection = Set<any> | Map<any, any> | WeakMap<any, any>;
type CollectionRawType = "Set" | "Map" | "WeakMap";
export type Reactive<T extends Target = Target> = T & {
[TARGET]: any;
};
type NonReactive<T extends Target = Target> = T & {
export type NonReactive<T extends Target = Target> = T & {
[SKIP]: any;
};
const objectToString = Object.prototype.toString;
const objectToString = Object.prototype.toString;
const objectHasOwnProperty = Object.prototype.hasOwnProperty;
const SUPPORTED_RAW_TYPES = new Set(["Object", "Array", "Set", "Map", "WeakMap"]);
const COLLECTION_RAWTYPES = new Set(["Set", "Map", "WeakMap"]);
/**
* extract "RawType" from strings like "[object RawType]" => this lets us ignore
* many native objects such as Promise (whose toString is [object Promise])
* or Date ([object Date]), while also supporting collections without using
* instanceof in a loop
*
* @param obj the object to check
* @returns the raw type of the object
*/
function rawType(obj: any) {
return objectToString.call(obj).slice(8, -1);
}
/**
* Checks whether a given value can be made into a reactive object.
*
@@ -32,11 +47,17 @@ function canBeMadeReactive(value: any): boolean {
if (typeof value !== "object") {
return false;
}
// extract "RawType" from strings like "[object RawType]" => this lets us
// ignore many native objects such as Promise (whose toString is [object Promise])
// or Date ([object Date]).
const rawType = objectToString.call(value).slice(8, -1);
return rawType === "Object" || rawType === "Array";
return SUPPORTED_RAW_TYPES.has(rawType(value));
}
/**
* Creates a reactive from the given object/callback if possible and returns it,
* returns the original object otherwise.
*
* @param value the value make reactive
* @returns a reactive for the given object when possible, the original otherwise
*/
function possiblyReactive(val: any, cb: Callback) {
return canBeMadeReactive(val) ? reactive(val, cb) : val;
}
/**
@@ -57,10 +78,10 @@ export function markRaw<T extends Target>(value: T): NonReactive<T> {
* @returns the underlying value
*/
export function toRaw<T extends object>(value: Reactive<T>): T {
return value[TARGET];
return value[TARGET] || value;
}
const targetToKeysToCallbacks = new WeakMap<Target, Map<ObjectKey, Set<Callback>>>();
const targetToKeysToCallbacks = new WeakMap<Target, Map<PropertyKey, Set<Callback>>>();
/**
* Observes a given key on a target with an callback. The callback will be
* called when the given key changes on the target.
@@ -70,7 +91,7 @@ const targetToKeysToCallbacks = new WeakMap<Target, Map<ObjectKey, Set<Callback>
* or deletion)
* @param callback the function to call when the key changes
*/
function observeTargetKey(target: Target, key: ObjectKey, callback: Callback): void {
function observeTargetKey(target: Target, key: PropertyKey, callback: Callback): void {
if (!targetToKeysToCallbacks.get(target)) {
targetToKeysToCallbacks.set(target, new Map());
}
@@ -93,7 +114,7 @@ function observeTargetKey(target: Target, key: ObjectKey, callback: Callback): v
* @param key the key that changed (or Symbol `KEYCHANGES` if a key was created
* or deleted)
*/
function notifyReactives(target: Target, key: ObjectKey): void {
function notifyReactives(target: Target, key: PropertyKey): void {
const keyToCallbacks = targetToKeysToCallbacks.get(target);
if (!keyToCallbacks) {
return;
@@ -115,7 +136,7 @@ const callbacksToTargets = new WeakMap<Callback, Set<Target>>();
*
* @param callback the callback for which the reactives need to be cleared
*/
function clearReactivesForCallback(callback: Callback): void {
export function clearReactivesForCallback(callback: Callback): void {
const targetsToClear = callbacksToTargets.get(callback);
if (!targetsToClear) {
return;
@@ -132,6 +153,17 @@ function clearReactivesForCallback(callback: Callback): void {
targetsToClear.clear();
}
export function getSubscriptions(callback: Callback) {
const targets = callbacksToTargets.get(callback) || [];
return [...targets].map((target) => {
const keysToCallbacks = targetToKeysToCallbacks.get(target);
return {
target,
keys: keysToCallbacks ? [...keysToCallbacks.keys()] : [],
};
});
}
const reactiveCache = new WeakMap<Target, WeakMap<Callback, Reactive>>();
/**
* Creates a reactive proxy for an object. Reading data on the reactive object
@@ -179,75 +211,218 @@ export function reactive<T extends Target>(
}
const reactivesForTarget = reactiveCache.get(target)!;
if (!reactivesForTarget.has(callback)) {
const proxy = new Proxy(target, {
get(target: any, key: ObjectKey, proxy: Reactive<T>) {
if (key === TARGET) {
return target;
}
observeTargetKey(target, key, callback);
const value = Reflect.get(target, key, proxy);
if (!canBeMadeReactive(value)) {
return value;
}
return reactive(value, callback);
},
set(target, key, value, proxy) {
const isNewKey = !Object.hasOwnProperty.call(target, key);
const originalValue = Reflect.get(target, key, proxy);
const ret = Reflect.set(target, key, value, proxy);
if (isNewKey) {
notifyReactives(target, KEYCHANGES);
}
// While Array length may trigger the set trap, it's not actually set by this
// method but is updated behind the scenes, and the trap is not called with the
// new value. We disable the "same-value-optimization" for it because of that.
if (originalValue !== value || (Array.isArray(target) && key === "length")) {
notifyReactives(target, key);
}
return ret;
},
deleteProperty(target, key) {
const ret = Reflect.deleteProperty(target, key);
notifyReactives(target, KEYCHANGES);
notifyReactives(target, key);
return ret;
},
ownKeys(target) {
observeTargetKey(target, KEYCHANGES, callback);
return Reflect.ownKeys(target);
},
has(target, key) {
// TODO: this observes all key changes instead of only the presence of the argument key
observeTargetKey(target, KEYCHANGES, callback);
return Reflect.has(target, key);
},
});
const targetRawType = rawType(target);
const handler = COLLECTION_RAWTYPES.has(targetRawType)
? collectionsProxyHandler(target as Collection, callback, targetRawType as CollectionRawType)
: basicProxyHandler<T>(callback);
const proxy = new Proxy(target, handler as ProxyHandler<T>) as Reactive<T>;
reactivesForTarget.set(callback, proxy);
}
return reactivesForTarget.get(callback) as Reactive<T>;
}
const batchedRenderFunctions = new WeakMap<ComponentNode, Callback>();
/**
* Creates a reactive object that will be observed by the current component.
* Reading data from the returned object (eg during rendering) will cause the
* component to subscribe to that data and be rerendered when it changes.
* Creates a basic proxy handler for regular objects and arrays.
*
* @param state the state to observe
* @returns a reactive object that will cause the component to re-render on
* relevant changes
* @see reactive
* @param callback @see reactive
* @returns a proxy handler object
*/
export function useState<T extends object>(state: T): Reactive<T> | NonReactive<T> {
const node = getCurrent();
if (!batchedRenderFunctions.has(node)) {
batchedRenderFunctions.set(
node,
batched(() => node.render())
);
onWillDestroy(() => clearReactivesForCallback(render));
}
const render = batchedRenderFunctions.get(node)!;
const reactiveState = reactive(state, render);
return reactiveState;
function basicProxyHandler<T extends Target>(callback: Callback): ProxyHandler<T> {
return {
get(target: any, key: PropertyKey, proxy: Reactive<T>) {
if (key === TARGET) {
return target;
}
observeTargetKey(target, key, callback);
return possiblyReactive(Reflect.get(target, key, proxy), callback);
},
set(target, key, value, proxy) {
const isNewKey = !objectHasOwnProperty.call(target, key);
const originalValue = Reflect.get(target, key, proxy);
const ret = Reflect.set(target, key, value, proxy);
if (isNewKey) {
notifyReactives(target, KEYCHANGES);
}
// While Array length may trigger the set trap, it's not actually set by this
// method but is updated behind the scenes, and the trap is not called with the
// new value. We disable the "same-value-optimization" for it because of that.
if (originalValue !== value || (Array.isArray(target) && key === "length")) {
notifyReactives(target, key);
}
return ret;
},
deleteProperty(target, key) {
const ret = Reflect.deleteProperty(target, key);
// TODO: only notify when something was actually deleted
notifyReactives(target, KEYCHANGES);
notifyReactives(target, key);
return ret;
},
ownKeys(target) {
observeTargetKey(target, KEYCHANGES, callback);
return Reflect.ownKeys(target);
},
has(target, key) {
// TODO: this observes all key changes instead of only the presence of the argument key
// observing the key itself would observe value changes instead of presence changes
// so we may need a finer grained system to distinguish observing value vs presence.
observeTargetKey(target, KEYCHANGES, callback);
return Reflect.has(target, key);
},
} as ProxyHandler<T>;
}
/**
* Creates a function that will observe the key that is passed to it when called
* and delegates to the underlying method.
*
* @param methodName name of the method to delegate to
* @param target @see reactive
* @param callback @see reactive
*/
function makeKeyObserver(methodName: "has" | "get", target: any, callback: Callback) {
return (key: any) => {
key = toRaw(key);
observeTargetKey(target, key, callback);
return possiblyReactive(target[methodName](key), callback);
};
}
/**
* Creates an iterable that will delegate to the underlying iteration method and
* observe keys as necessary.
*
* @param methodName name of the method to delegate to
* @param target @see reactive
* @param callback @see reactive
*/
function makeIteratorObserver(
methodName: "keys" | "values" | "entries" | typeof Symbol.iterator,
target: any,
callback: Callback
) {
return function* () {
observeTargetKey(target, KEYCHANGES, callback);
const keys = target.keys();
for (const item of target[methodName]()) {
const key = keys.next().value;
observeTargetKey(target, key, callback);
yield possiblyReactive(item, callback);
}
};
}
/**
* Creates a function that will delegate to an underlying method, and check if
* that method has modified the presence or value of a key, and notify the
* reactives appropriately.
*
* @param setterName name of the method to delegate to
* @param getterName name of the method which should be used to retrieve the
* value before calling the delegate method for comparison purposes
* @param target @see reactive
*/
function delegateAndNotify(
setterName: "set" | "add" | "delete",
getterName: "has" | "get",
target: any
) {
return (key: any, value: any) => {
key = toRaw(key);
const hadKey = target.has(key);
const originalValue = target[getterName](key);
const ret = target[setterName](key, value);
const hasKey = target.has(key);
if (hadKey !== hasKey) {
notifyReactives(target, KEYCHANGES);
}
if (originalValue !== value) {
notifyReactives(target, key);
}
return ret;
};
}
/**
* Creates a function that will clear the underlying collection and notify that
* the keys of the collection have changed.
*
* @param target @see reactive
*/
function makeClearNotifier(target: Map<any, any> | Set<any>) {
return () => {
const allKeys = [...target.keys()];
target.clear();
notifyReactives(target, KEYCHANGES);
for (const key of allKeys) {
notifyReactives(target, key);
}
};
}
/**
* Maps raw type of an object to an object containing functions that can be used
* to build an appropritate proxy handler for that raw type. Eg: when making a
* reactive set, calling the has method should mark the key that is being
* retrieved as observed, and calling the add or delete method should notify the
* reactives that the key which is being added or deleted has been modified.
*/
const rawTypeToFuncHandlers = {
Set: (target: any, callback: Callback) => ({
has: makeKeyObserver("has", target, callback),
add: delegateAndNotify("add", "has", target),
delete: delegateAndNotify("delete", "has", target),
keys: makeIteratorObserver("keys", target, callback),
values: makeIteratorObserver("values", target, callback),
entries: makeIteratorObserver("entries", target, callback),
[Symbol.iterator]: makeIteratorObserver(Symbol.iterator, target, callback),
clear: makeClearNotifier(target),
get size() {
observeTargetKey(target, KEYCHANGES, callback);
return target.size;
},
}),
Map: (target: any, callback: Callback) => ({
has: makeKeyObserver("has", target, callback),
get: makeKeyObserver("get", target, callback),
set: delegateAndNotify("set", "get", target),
delete: delegateAndNotify("delete", "has", target),
keys: makeIteratorObserver("keys", target, callback),
values: makeIteratorObserver("values", target, callback),
entries: makeIteratorObserver("entries", target, callback),
[Symbol.iterator]: makeIteratorObserver(Symbol.iterator, target, callback),
clear: makeClearNotifier(target),
get size() {
observeTargetKey(target, KEYCHANGES, callback);
return target.size;
},
}),
WeakMap: (target: any, callback: Callback) => ({
has: makeKeyObserver("has", target, callback),
get: makeKeyObserver("get", target, callback),
set: delegateAndNotify("set", "get", target),
delete: delegateAndNotify("delete", "has", target),
}),
};
/**
* Creates a proxy handler for collections (Set/Map/WeakMap)
*
* @param callback @see reactive
* @param target @see reactive
* @returns a proxy handler object
*/
function collectionsProxyHandler<T extends Collection>(
target: T,
callback: Callback,
targetRawType: CollectionRawType
): ProxyHandler<T> {
// TODO: if performance is an issue we can create the special handlers lazily when each
// property is read.
const specialHandlers = rawTypeToFuncHandlers[targetRawType](target, callback);
return Object.assign(basicProxyHandler(callback), {
get(target: any, key: PropertyKey) {
if (key === TARGET) {
return target;
}
if (objectHasOwnProperty.call(specialHandlers, key)) {
return (specialHandlers as any)[key];
}
observeTargetKey(target, key, callback);
return possiblyReactive(target[key], callback);
},
}) as ProxyHandler<T>;
}
+14
View File
@@ -71,3 +71,17 @@ export class Markup extends String {}
export function markup(value: any) {
return new Markup(value);
}
// -----------------------------------------------------------------------------
// xml tag helper
// -----------------------------------------------------------------------------
export const globalTemplates: { [key: string]: string | Element } = {};
export function xml(...args: Parameters<typeof String.raw>) {
const name = `__template__${xml.nextId++}`;
const value = String.raw(...args);
globalTemplates[name] = value;
return name;
}
xml.nextId = 1;
+11 -11
View File
@@ -131,7 +131,7 @@ exports[`Reactivity: useState parent and children subscribed to same context 1`]
let block1 = createBlock(\`<div><block-child-0/><block-text-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
const b2 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
let txt1 = ctx['contextObj'].b;
return block1([txt1], [b2]);
}
@@ -223,8 +223,8 @@ exports[`Reactivity: useState two components are updated in parallel 1`] = `
let block1 = createBlock(\`<div><block-child-0/><block-child-1/></div>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
let b3 = component(\`Child\`, {}, key + \`__2\`, node, ctx);
const b2 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
const b3 = component(\`Child\`, {}, key + \`__2\`, node, ctx);
return block1([], [b2, b3]);
}
}"
@@ -252,8 +252,8 @@ exports[`Reactivity: useState two components can subscribe to same context 1`] =
let block1 = createBlock(\`<div><block-child-0/><block-child-1/></div>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
let b3 = component(\`Child\`, {}, key + \`__2\`, node, ctx);
const b2 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
const b3 = component(\`Child\`, {}, key + \`__2\`, node, ctx);
return block1([], [b2, b3]);
}
}"
@@ -281,8 +281,8 @@ exports[`Reactivity: useState two independent components on different levels are
let block1 = createBlock(\`<div><block-child-0/><block-child-1/></div>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
let b3 = component(\`Parent\`, {}, key + \`__2\`, node, ctx);
const b2 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
const b3 = component(\`Parent\`, {}, key + \`__2\`, node, ctx);
return block1([], [b2, b3]);
}
}"
@@ -310,7 +310,7 @@ exports[`Reactivity: useState two independent components on different levels are
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
const b2 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -340,14 +340,14 @@ exports[`Reactivity: useState useless atoms should be deleted 1`] = `
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(Object.keys(ctx['state']));
const [k_block2, v_block2, l_block2, c_block2] = prepareList(Object.keys(ctx['state']));;
for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`id\`] = v_block2[i1];
let key1 = ctx['id'];
const key1 = ctx['id'];
c_block2[i1] = withKey(component(\`Quantity\`, {id: ctx['id']}, key + \`__1__\${key1}\`, node, ctx), key1);
}
ctx = ctx.__proto__;
let b2 = list(c_block2);
const b2 = list(c_block2);
let txt1 = ctx['total'];
let txt2 = Object.keys(ctx['state']).length;
return block1([txt1, txt2], [b2]);
+9
View File
@@ -169,6 +169,15 @@ describe("properties", () => {
expect(input.value).toBe("potato");
});
test("input with value attribute, and undefined given", () => {
const block = createBlock(`<input block-attribute-0="value"/>`);
const tree = block([undefined]);
mount(tree, fixture);
const input = fixture.querySelector("input")!;
expect(input.value).toBe("");
});
test("input type=checkbox with checked attribute", () => {
// render input with initial value
const block = createBlock(`<input type="checkbox" block-attribute-0="checked"/>`);
+54
View File
@@ -0,0 +1,54 @@
import { config, createBlock, createCatcher, mount } from "../../src/blockdom";
import { makeTestFixture } from "./helpers";
import { mainEventHandler } from "../../src/component/handler";
//------------------------------------------------------------------------------
// Setup and helpers
//------------------------------------------------------------------------------
let fixture: HTMLElement;
config.mainEventHandler = mainEventHandler;
beforeEach(() => {
fixture = makeTestFixture();
});
afterEach(() => {
fixture.remove();
});
test("simple event catcher", async () => {
const catcher = createCatcher({ click: 0 });
const block = createBlock("<div></div>");
let n = 0;
let ctx = {};
let handler = [() => n++, ctx];
const tree = catcher(block(), [handler]);
mount(tree, fixture);
expect(fixture.innerHTML).toBe("<div></div>");
expect(fixture.firstChild).toBeInstanceOf(HTMLDivElement);
expect(n).toBe(0);
(fixture.firstChild as HTMLDivElement).click();
expect(n).toBe(1);
});
test("do not catch events outside of itself", async () => {
const catcher = createCatcher({ click: 0 });
const childBlock = createBlock("<div></div>");
const parentBlock = createBlock("<button><block-child-0/></button>");
let n = 0;
let ctx = {};
let handler = [() => n++, ctx];
const tree = parentBlock([], [catcher(childBlock(), [handler])]);
mount(tree, fixture);
expect(fixture.innerHTML).toBe("<button><div></div></button>");
expect(n).toBe(0);
fixture.querySelector("div")!.click();
expect(n).toBe(1);
fixture.querySelector("button")!.click();
expect(n).toBe(1);
});
@@ -70,17 +70,17 @@ exports[`t-on can bind handlers with empty object (with non empty inner string)
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(['someval']);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(['someval']);;
for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`action\`] = v_block2[i1];
ctx[\`action_index\`] = i1;
let key1 = ctx['action_index'];
const key1 = ctx['action_index'];
const v1 = ctx['activate'];
const v2 = ctx['action'];
let hdlr1 = [()=>v1(v2), ctx];
c_block2[i1] = withKey(block3([hdlr1]), key1);
}
let b2 = list(c_block2);
const b2 = list(c_block2);
return block1([], [b2]);
}
}"
@@ -140,10 +140,10 @@ exports[`t-on handler is bound to proper owner, part 2 1`] = `
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
const [k_block1, v_block1, l_block1, c_block1] = prepareList([1]);
const [k_block1, v_block1, l_block1, c_block1] = prepareList([1]);;
for (let i1 = 0; i1 < l_block1; i1++) {
ctx[\`value\`] = v_block1[i1];
let key1 = ctx['value'];
const key1 = ctx['value'];
let hdlr1 = [ctx['add'], ctx];
c_block1[i1] = withKey(block2([hdlr1]), key1);
}
@@ -188,14 +188,14 @@ exports[`t-on handler is bound to proper owner, part 4 1`] = `
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
const [k_block1, v_block1, l_block1, c_block1] = prepareList([1]);
const [k_block1, v_block1, l_block1, c_block1] = prepareList([1]);;
for (let i1 = 0; i1 < l_block1; i1++) {
ctx[\`value\`] = v_block1[i1];
ctx[\`value_first\`] = i1 === 0;
ctx[\`value_last\`] = i1 === v_block1.length - 1;
ctx[\`value_index\`] = i1;
ctx[\`value_value\`] = k_block1[i1];
let key1 = ctx['value'];
const key1 = ctx['value'];
c_block1[i1] = withKey(callTemplate_1.call(this, ctx, node, key + \`__1__\${key1}\`), key1);
}
return list(c_block1);
@@ -271,7 +271,7 @@ exports[`t-on t-on modifiers (native listener) t-on combined with t-out 1`] = `
return function template(ctx, node, key = \\"\\") {
let hdlr1 = [ctx['onClick'], ctx];
let b2 = safeOutput(ctx['html']);
const b2 = safeOutput(ctx['html']);
return block1([hdlr1], [b2]);
}
}"
@@ -347,17 +347,17 @@ exports[`t-on t-on modifiers (native listener) t-on with prevent modifier in t-f
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['projects']);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['projects']);;
for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`project\`] = v_block2[i1];
let key1 = ctx['project'];
const key1 = ctx['project'];
const v1 = ctx['onEdit'];
const v2 = ctx['project'];
let hdlr1 = [\\"prevent\\", _ev=>v1(v2.id,_ev), ctx];
let txt1 = ctx['project'].name;
c_block2[i1] = withKey(block3([hdlr1, txt1]), key1);
}
let b2 = list(c_block2);
const b2 = list(c_block2);
return block1([], [b2]);
}
}"
@@ -478,7 +478,7 @@ exports[`t-on t-on with t-call 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
const b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
return block1([], [b2]);
}
}"
@@ -508,7 +508,7 @@ exports[`t-on t-on, with arguments and t-call 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
const b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
return block1([], [b2]);
}
}"
+34 -34
View File
@@ -30,28 +30,28 @@ exports[`misc complex template 1`] = `
b3 = block3();
}
ctx = Object.create(ctx);
const [k_block4, v_block4, l_block4, c_block4] = prepareList(ctx['batch'].slot_ids.filter(_slot=>_slot.build_id.id&&!_slot.trigger_id.manual&&(ctx['options'].trigger_display[_slot.trigger_id.id])));
const [k_block4, v_block4, l_block4, c_block4] = prepareList(ctx['batch'].slot_ids.filter(_slot=>_slot.build_id.id&&!_slot.trigger_id.manual&&(ctx['options'].trigger_display[_slot.trigger_id.id])));;
for (let i1 = 0; i1 < l_block4; i1++) {
ctx[\`slot\`] = v_block4[i1];
let key1 = ctx['slot'].id;
const key1 = ctx['slot'].id;
c_block4[i1] = withKey(component(\`SlotButton\`, {class: ctx['slot_container'], slot: ctx['slot']}, key + \`__1__\${key1}\`, node, ctx), key1);
}
ctx = ctx.__proto__;
b4 = list(c_block4);
ctx = Object.create(ctx);
const [k_block6, v_block6, l_block6, c_block6] = prepareList([1,2,3,4]);
const [k_block6, v_block6, l_block6, c_block6] = prepareList([1,2,3,4]);;
for (let i1 = 0; i1 < l_block6; i1++) {
ctx[\`x\`] = v_block6[i1];
let key1 = ctx['x'];
const key1 = ctx['x'];
c_block6[i1] = withKey(block7(), key1);
}
ctx = ctx.__proto__;
b6 = list(c_block6);
ctx = Object.create(ctx);
const [k_block8, v_block8, l_block8, c_block8] = prepareList(ctx['commit_links']);
const [k_block8, v_block8, l_block8, c_block8] = prepareList(ctx['commit_links']);;
for (let i1 = 0; i1 < l_block8; i1++) {
ctx[\`commit_link\`] = v_block8[i1];
let key1 = ctx['commit_link'].id;
const key1 = ctx['commit_link'].id;
let b10,b11,b12,b13;
let attr5 = \`/runbot/commit/\${ctx['commit_link'].commit_id}\`;
let attr6 = \`badge badge-light batch_commit match_type_\${ctx['commit_link'].match_type}\`;
@@ -96,35 +96,35 @@ exports[`misc global 1`] = `
ctx = Object.create(ctx);
ctx[isBoundary] = 1
ctx = Object.create(ctx);
const [k_block2, v_block2, l_block2, c_block2] = prepareList([4,5,6]);
const [k_block2, v_block2, l_block2, c_block2] = prepareList([4,5,6]);;
for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`value\`] = v_block2[i1];
ctx[\`value_first\`] = i1 === 0;
ctx[\`value_last\`] = i1 === v_block2.length - 1;
ctx[\`value_index\`] = i1;
ctx[\`value_value\`] = k_block2[i1];
let key1 = ctx['value'];
const key1 = ctx['value'];
let txt1 = ctx['value'];
let b4 = block4([txt1]);
const b4 = block4([txt1]);
ctx = Object.create(ctx);
ctx[isBoundary] = 1;
ctx = Object.create(ctx);
ctx[isBoundary] = 1;
setContextValue(ctx, \\"foo\\", 'aaa');
let b6 = callTemplate_1.call(this, ctx, node, key + \`__1__\${key1}\`);
const b6 = callTemplate_1.call(this, ctx, node, key + \`__1__\${key1}\`);
ctx = ctx.__proto__;
let b7 = callTemplate_2.call(this, ctx, node, key + \`__2__\${key1}\`);
const b7 = callTemplate_2.call(this, ctx, node, key + \`__2__\${key1}\`);
setContextValue(ctx, \\"foo\\", 'bbb');
let b8 = callTemplate_3.call(this, ctx, node, key + \`__3__\${key1}\`);
let b5 = multi([b6, b7, b8]);
const b8 = callTemplate_3.call(this, ctx, node, key + \`__3__\${key1}\`);
const b5 = multi([b6, b7, b8]);
ctx[zero] = b5;
let b9 = callTemplate_4.call(this, ctx, node, key + \`__4__\${key1}\`);
const b9 = callTemplate_4.call(this, ctx, node, key + \`__4__\${key1}\`);
ctx = ctx.__proto__;
c_block2[i1] = withKey(multi([b4, b9]), key1);
}
ctx = ctx.__proto__;
let b2 = list(c_block2);
let b10 = callTemplate_5.call(this, ctx, node, key + \`__5\`);
const b2 = list(c_block2);
const b10 = callTemplate_5.call(this, ctx, node, key + \`__5\`);
return block1([], [b2, b10]);
}
}"
@@ -155,7 +155,7 @@ exports[`misc global 3`] = `
return function template(ctx, node, key = \\"\\") {
let attr1 = 'agüero';
let b2 = ctx[zero];
const b2 = ctx[zero];
return block1([attr1], [b2]);
}
}"
@@ -170,8 +170,8 @@ exports[`misc global 4`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
let b3 = text(\`toto default\`);
let b2 = withDefault(safeOutput(ctx['toto']), b3);
const b3 = text(\`toto default\`);
const b2 = withDefault(safeOutput(ctx['toto']), b3);
return block1([], [b2]);
}
}"
@@ -221,10 +221,10 @@ exports[`misc other complex template 1`] = `
let attr1 = \`/runbot/\${ctx['project'].slug}\`;
let txt1 = ctx['project'].name;
ctx = Object.create(ctx);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['projects']);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['projects']);;
for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`project\`] = v_block2[i1];
let key1 = ctx['project'].id;
const key1 = ctx['project'].id;
let hdlr1 = [ctx['selectProject'](ctx['project']), ctx];
let txt2 = ctx['project'].name;
c_block2[i1] = withKey(block3([hdlr1, txt2]), key1);
@@ -241,12 +241,12 @@ exports[`misc other complex template 1`] = `
if (ctx['nb_assigned_errors']&&ctx['nb_assigned_errors']>0) {
let attr3 = \`You have \${ctx['nb_assigned_errors']} random bug assigned\`;
let txt3 = ctx['nb_assigned_errors'];
let b8 = block8([attr3, txt3]);
let b9 = block9();
const b8 = block8([attr3, txt3]);
const b9 = block9();
b7 = multi([b8, b9]);
} else if (ctx['nb_build_errors']&&ctx['nb_build_errors']>0) {
let b11 = block11();
let b12 = block12();
const b11 = block11();
const b12 = block12();
b10 = multi([b11, b12]);
}
let txt4 = ctx['user'].name.length>25?ctx['user'].namesubstring(0,23)+'...':ctx['user'].name;
@@ -261,17 +261,17 @@ exports[`misc other complex template 1`] = `
let hdlr3 = [ctx['toggleMore'], ctx];
if (ctx['categories']&&ctx['categories'].length>1) {
ctx = Object.create(ctx);
const [k_block15, v_block15, l_block15, c_block15] = prepareList(ctx['categories']);
const [k_block15, v_block15, l_block15, c_block15] = prepareList(ctx['categories']);;
for (let i1 = 0; i1 < l_block15; i1++) {
ctx[\`category\`] = v_block15[i1];
let key1 = ctx['category'].id;
const key1 = ctx['category'].id;
let attr6 = ctx['category'].id;
let attr7 = ctx['category'].id==ctx['options'].active_category_id;
let txt5 = ctx['category'].name;
c_block15[i1] = withKey(block16([attr6, attr7, txt5]), key1);
}
ctx = ctx.__proto__;
let b15 = list(c_block15);
const b15 = list(c_block15);
b14 = block14([], [b15]);
}
let attr8 = ctx['search'].value;
@@ -280,10 +280,10 @@ exports[`misc other complex template 1`] = `
let hdlr6 = [ctx['clearSearch'], ctx];
if (ctx['triggers']) {
ctx = Object.create(ctx);
const [k_block18, v_block18, l_block18, c_block18] = prepareList(ctx['triggers']);
const [k_block18, v_block18, l_block18, c_block18] = prepareList(ctx['triggers']);;
for (let i1 = 0; i1 < l_block18; i1++) {
ctx[\`trigger\`] = v_block18[i1];
let key1 = ctx['trigger'].id;
const key1 = ctx['trigger'].id;
let b20;
if (!ctx['trigger'].manual&&ctx['trigger'].project_id===ctx['project'].id&&ctx['trigger'].category_id===ctx['options'].active_category_id) {
let attr9 = \`trigger_\${ctx['trigger'].id}\`;
@@ -298,12 +298,12 @@ exports[`misc other complex template 1`] = `
c_block18[i1] = withKey(multi([b20]), key1);
}
ctx = ctx.__proto__;
let b18 = list(c_block18);
const b18 = list(c_block18);
let hdlr8 = [ctx['triggerAll'], ctx];
let hdlr9 = [ctx['triggerNone'], ctx];
let hdlr10 = [ctx['triggerDefault'], ctx];
let hdlr11 = [ctx['toggleSettingsMenu'], ctx];
let b21 = block21([hdlr8, hdlr9, hdlr10, hdlr11]);
const b21 = block21([hdlr8, hdlr9, hdlr10, hdlr11]);
b17 = multi([b18, b21]);
}
if (ctx['load_infos']) {
@@ -316,8 +316,8 @@ exports[`misc other complex template 1`] = `
if (!ctx['project']) {
b24 = block24();
} else {
let b26 = component(\`BundlesList\`, {bundles: ctx['bundles'].sticky, category_custom_views: ctx['category_custom_views'], search: ctx['search']}, key + \`__2\`, node, ctx);
let b27 = component(\`BundlesList\`, {bundles: ctx['bundles'].dev, search: ctx['search']}, key + \`__3\`, node, ctx);
const b26 = component(\`BundlesList\`, {bundles: ctx['bundles'].sticky, category_custom_views: ctx['category_custom_views'], search: ctx['search']}, key + \`__2\`, node, ctx);
const b27 = component(\`BundlesList\`, {bundles: ctx['bundles'].dev, search: ctx['search']}, key + \`__3\`, node, ctx);
b25 = block25([], [b26, b27]);
}
return block1([attr1, txt1, hdlr2, hdlr3, attr8, hdlr4, hdlr5, ref1, hdlr6, ref2], [b2, b4, b14, b17, b22, b23, b24, b25]);
@@ -10,14 +10,14 @@ exports[`memory t-foreach does not leak stuff in global scope 1`] = `
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
const [k_block2, v_block2, l_block2, c_block2] = prepareList([3,2,1]);
const [k_block2, v_block2, l_block2, c_block2] = prepareList([3,2,1]);;
for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`item\`] = v_block2[i1];
ctx[\`item_index\`] = i1;
let key1 = ctx['item_index'];
const key1 = ctx['item_index'];
c_block2[i1] = withKey(text(ctx['item']), key1);
}
let b2 = list(c_block2);
const b2 = list(c_block2);
return block1([], [b2]);
}
}"
@@ -211,8 +211,8 @@ exports[`simple templates, mostly static multiple root nodes 1`] = `
let block3 = createBlock(\`<span>hey</span>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = block2();
let b3 = block3();
const b2 = block2();
const b3 = block3();
return multi([b2, b3]);
}
}"
@@ -246,8 +246,8 @@ exports[`simple templates, mostly static static text and dynamic text (no t tag)
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
let b2 = text(\`hello \`);
let b3 = text(ctx['text']);
const b2 = text(\`hello \`);
const b3 = text(ctx['text']);
return multi([b2, b3]);
}
}"
@@ -259,8 +259,8 @@ exports[`simple templates, mostly static static text and dynamic text 1`] = `
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
let b2 = text(\`hello \`);
let b3 = text(ctx['text']);
const b2 = text(\`hello \`);
const b3 = text(ctx['text']);
return multi([b2, b3]);
}
}"
@@ -347,8 +347,8 @@ exports[`simple templates, mostly static two t-escs next to each other 1`] = `
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
let b2 = text(ctx['text1']);
let b3 = text(ctx['text2']);
const b2 = text(ctx['text1']);
const b3 = text(ctx['text2']);
return multi([b2, b3]);
}
}"
@@ -360,8 +360,8 @@ exports[`simple templates, mostly static two t-escs next to each other 2`] = `
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
let b2 = text(ctx['text1']);
let b3 = text(ctx['text2']);
const b2 = text(ctx['text1']);
const b3 = text(ctx['text2']);
return multi([b2, b3]);
}
}"
@@ -66,7 +66,7 @@ exports[`properly support svg svg creates new block if it is within html -- 2 1`
if (ctx['hasPath']) {
b3 = block3();
}
let b2 = block2([], [b3]);
const b2 = block2([], [b3]);
return block1([], [b2]);
}
}"
@@ -81,7 +81,7 @@ exports[`properly support svg svg creates new block if it is within html 1`] = `
let block2 = createBlock(\`<svg block-ns=\\"http://www.w3.org/2000/svg\\"><polygon fill=\\"#000000\\" points=\\"0 0 4 4 8 0\\" transform=\\"translate(5 7)\\"/></svg>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = block2();
const b2 = block2();
return block1([], [b2]);
}
}"
@@ -97,7 +97,7 @@ exports[`properly support svg svg namespace added to sub templates if root tag i
let block1 = createBlock(\`<svg block-ns=\\"http://www.w3.org/2000/svg\\"><block-child-0/></svg>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
const b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
return block1([], [b2]);
}
}"
@@ -10,7 +10,7 @@ exports[`t-call (template calling) basic caller 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
const b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
return block1([], [b2]);
}
}"
@@ -69,12 +69,12 @@ exports[`t-call (template calling) call with several sub nodes on same line 1`]
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
ctx[isBoundary] = 1;
let b3 = block3();
let b4 = text(\` \`);
let b5 = block5();
let b2 = multi([b3, b4, b5]);
const b3 = block3();
const b4 = text(\` \`);
const b5 = block5();
const b2 = multi([b3, b4, b5]);
ctx[zero] = b2;
let b6 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
const b6 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
return block1([], [b6]);
}
}"
@@ -89,7 +89,7 @@ exports[`t-call (template calling) call with several sub nodes on same line 2`]
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = ctx[zero];
const b2 = ctx[zero];
return block1([], [b2]);
}
}"
@@ -109,12 +109,12 @@ exports[`t-call (template calling) cascading t-call t-out='0' 1`] = `
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
ctx[isBoundary] = 1;
let b3 = block3();
let b4 = text(\` \`);
let b5 = block5();
let b2 = multi([b3, b4, b5]);
const b3 = block3();
const b4 = text(\` \`);
const b5 = block5();
const b2 = multi([b3, b4, b5]);
ctx[zero] = b2;
let b6 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
const b6 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
return block1([], [b6]);
}
}"
@@ -133,11 +133,11 @@ exports[`t-call (template calling) cascading t-call t-out='0' 2`] = `
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
ctx[isBoundary] = 1;
let b3 = block3();
let b4 = ctx[zero];
let b2 = multi([b3, b4]);
const b3 = block3();
const b4 = ctx[zero];
const b2 = multi([b3, b4]);
ctx[zero] = b2;
let b5 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
const b5 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
return block1([], [b5]);
}
}"
@@ -156,11 +156,11 @@ exports[`t-call (template calling) cascading t-call t-out='0' 3`] = `
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
ctx[isBoundary] = 1;
let b3 = block3();
let b4 = ctx[zero];
let b2 = multi([b3, b4]);
const b3 = block3();
const b4 = ctx[zero];
const b2 = multi([b3, b4]);
ctx[zero] = b2;
let b5 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
const b5 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
return block1([], [b5]);
}
}"
@@ -175,7 +175,7 @@ exports[`t-call (template calling) cascading t-call t-out='0' 4`] = `
let block1 = createBlock(\`<div><span>cascade 2</span><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = ctx[zero];
const b2 = ctx[zero];
return block1([], [b2]);
}
}"
@@ -194,10 +194,10 @@ exports[`t-call (template calling) cascading t-call t-out='0', without external
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
ctx[isBoundary] = 1;
let b2 = block2();
let b3 = text(\` \`);
let b4 = block4();
let b1 = multi([b2, b3, b4]);
const b2 = block2();
const b3 = text(\` \`);
const b4 = block4();
const b1 = multi([b2, b3, b4]);
ctx[zero] = b1;
return callTemplate_1.call(this, ctx, node, key + \`__1\`);
}
@@ -216,9 +216,9 @@ exports[`t-call (template calling) cascading t-call t-out='0', without external
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
ctx[isBoundary] = 1;
let b2 = block2();
let b3 = ctx[zero];
let b1 = multi([b2, b3]);
const b2 = block2();
const b3 = ctx[zero];
const b1 = multi([b2, b3]);
ctx[zero] = b1;
return callTemplate_1.call(this, ctx, node, key + \`__1\`);
}
@@ -237,9 +237,9 @@ exports[`t-call (template calling) cascading t-call t-out='0', without external
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
ctx[isBoundary] = 1;
let b2 = block2();
let b3 = ctx[zero];
let b1 = multi([b2, b3]);
const b2 = block2();
const b3 = ctx[zero];
const b1 = multi([b2, b3]);
ctx[zero] = b1;
return callTemplate_1.call(this, ctx, node, key + \`__1\`);
}
@@ -255,8 +255,8 @@ exports[`t-call (template calling) cascading t-call t-out='0', without external
let block2 = createBlock(\`<span>cascade 2</span>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = block2();
let b3 = ctx[zero];
const b2 = block2();
const b3 = ctx[zero];
return multi([b2, b3]);
}
}"
@@ -272,7 +272,7 @@ exports[`t-call (template calling) dynamic t-call 1`] = `
return function template(ctx, node, key = \\"\\") {
const template1 = (ctx['template']);
let b2 = call(this, template1, ctx, node, key + \`__1\`);
const b2 = call(this, template1, ctx, node, key + \`__1\`);
return block1([], [b2]);
}
}"
@@ -319,7 +319,7 @@ exports[`t-call (template calling) inherit context 1`] = `
ctx = Object.create(ctx);
ctx[isBoundary] = 1
setContextValue(ctx, \\"foo\\", 1);
let b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
const b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
return block1([], [b2]);
}
}"
@@ -370,7 +370,7 @@ exports[`t-call (template calling) recursive template, part 2 1`] = `
ctx = Object.create(ctx);
ctx[isBoundary] = 1;
setContextValue(ctx, \\"node\\", ctx['root']);
let b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
const b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
return block1([], [b2]);
}
}"
@@ -390,21 +390,21 @@ exports[`t-call (template calling) recursive template, part 2 2`] = `
ctx[isBoundary] = 1
let txt1 = ctx['node'].val;
ctx = Object.create(ctx);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['node'].children||[]);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['node'].children||[]);;
for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`subtree\`] = v_block2[i1];
ctx[\`subtree_first\`] = i1 === 0;
ctx[\`subtree_last\`] = i1 === v_block2.length - 1;
ctx[\`subtree_index\`] = i1;
ctx[\`subtree_value\`] = k_block2[i1];
let key1 = ctx['subtree_index'];
const key1 = ctx['subtree_index'];
ctx = Object.create(ctx);
ctx[isBoundary] = 1;
setContextValue(ctx, \\"node\\", ctx['subtree']);
c_block2[i1] = withKey(callTemplate_1.call(this, ctx, node, key + \`__1__\${key1}\`), key1);
ctx = ctx.__proto__;
}
let b2 = list(c_block2);
const b2 = list(c_block2);
return block1([txt1], [b2]);
}
}"
@@ -425,7 +425,7 @@ exports[`t-call (template calling) recursive template, part 3 1`] = `
ctx = Object.create(ctx);
ctx[isBoundary] = 1;
setContextValue(ctx, \\"node\\", ctx['root']);
let b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
const b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
return block1([], [b2]);
}
}"
@@ -445,21 +445,21 @@ exports[`t-call (template calling) recursive template, part 3 2`] = `
ctx[isBoundary] = 1
let txt1 = ctx['node'].val;
ctx = Object.create(ctx);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['node'].children||[]);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['node'].children||[]);;
for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`subtree\`] = v_block2[i1];
ctx[\`subtree_first\`] = i1 === 0;
ctx[\`subtree_last\`] = i1 === v_block2.length - 1;
ctx[\`subtree_index\`] = i1;
ctx[\`subtree_value\`] = k_block2[i1];
let key1 = ctx['subtree_index'];
const key1 = ctx['subtree_index'];
ctx = Object.create(ctx);
ctx[isBoundary] = 1;
setContextValue(ctx, \\"node\\", ctx['subtree']);
c_block2[i1] = withKey(callTemplate_1.call(this, ctx, node, key + \`__1__\${key1}\`), key1);
ctx = ctx.__proto__;
}
let b2 = list(c_block2);
const b2 = list(c_block2);
return block1([txt1], [b2]);
}
}"
@@ -481,7 +481,7 @@ exports[`t-call (template calling) recursive template, part 4: with t-set recurs
ctx[isBoundary] = 1;
setContextValue(ctx, \\"recursive_idx\\", 1);
setContextValue(ctx, \\"node\\", ctx['root']);
let b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
const b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
return block1([], [b2]);
}
}"
@@ -503,21 +503,21 @@ exports[`t-call (template calling) recursive template, part 4: with t-set recurs
let txt1 = ctx['node'].val;
let txt2 = ctx['recursive_idx'];
ctx = Object.create(ctx);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['node'].children||[]);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['node'].children||[]);;
for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`subtree\`] = v_block2[i1];
ctx[\`subtree_first\`] = i1 === 0;
ctx[\`subtree_last\`] = i1 === v_block2.length - 1;
ctx[\`subtree_index\`] = i1;
ctx[\`subtree_value\`] = k_block2[i1];
let key1 = ctx['subtree_index'];
const key1 = ctx['subtree_index'];
ctx = Object.create(ctx);
ctx[isBoundary] = 1;
setContextValue(ctx, \\"node\\", ctx['subtree']);
c_block2[i1] = withKey(callTemplate_1.call(this, ctx, node, key + \`__1__\${key1}\`), key1);
ctx = ctx.__proto__;
}
let b2 = list(c_block2);
const b2 = list(c_block2);
return block1([txt1, txt2], [b2]);
}
}"
@@ -538,7 +538,7 @@ exports[`t-call (template calling) scoped parameters 1`] = `
ctx = Object.create(ctx);
ctx[isBoundary] = 1;
setContextValue(ctx, \\"foo\\", 42);
let b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
const b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
ctx = ctx.__proto__;
let txt1 = ctx['foo'];
return block1([txt1], [b2]);
@@ -573,7 +573,7 @@ exports[`t-call (template calling) scoped parameters, part 2 1`] = `
ctx = Object.create(ctx);
ctx[isBoundary] = 1;
setContextValue(ctx, \\"foo\\", 42);
let b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
const b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
ctx = ctx.__proto__;
let txt1 = ctx['foo'];
return block1([txt1], [b2]);
@@ -602,7 +602,7 @@ exports[`t-call (template calling) t-call allowed on a non t node 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
const b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
return block1([], [b2]);
}
}"
@@ -633,7 +633,7 @@ exports[`t-call (template calling) t-call with body content as root of a templat
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
ctx[isBoundary] = 1;
let b1 = block1();
const b1 = block1();
ctx[zero] = b1;
return callTemplate_1.call(this, ctx, node, key + \`__1\`);
}
@@ -649,7 +649,7 @@ exports[`t-call (template calling) t-call with body content as root of a templat
let block1 = createBlock(\`<foo><block-child-0/></foo>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = ctx[zero];
const b2 = ctx[zero];
return block1([], [b2]);
}
}"
@@ -702,7 +702,7 @@ exports[`t-call (template calling) t-call with t-set inside and body text conten
ctx = Object.create(ctx);
ctx[isBoundary] = 1;
setContextValue(ctx, \\"val\\", \`yip yip\`);
let b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
const b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
return block1([], [b2]);
}
}"
@@ -735,14 +735,14 @@ exports[`t-call (template calling) t-call with t-set inside and outside 1`] = `
ctx = Object.create(ctx);
ctx[isBoundary] = 1
ctx = Object.create(ctx);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['list']);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['list']);;
for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`v\`] = v_block2[i1];
ctx[\`v_first\`] = i1 === 0;
ctx[\`v_last\`] = i1 === v_block2.length - 1;
ctx[\`v_index\`] = i1;
ctx[\`v_value\`] = k_block2[i1];
let key1 = ctx['v_index'];
const key1 = ctx['v_index'];
setContextValue(ctx, \\"val\\", ctx['v'].val);
ctx = Object.create(ctx);
ctx[isBoundary] = 1;
@@ -750,7 +750,7 @@ exports[`t-call (template calling) t-call with t-set inside and outside 1`] = `
c_block2[i1] = withKey(callTemplate_1.call(this, ctx, node, key + \`__1__\${key1}\`), key1);
ctx = ctx.__proto__;
}
let b2 = list(c_block2);
const b2 = list(c_block2);
return block1([], [b2]);
}
}"
@@ -783,7 +783,7 @@ exports[`t-call (template calling) t-call with t-set inside and outside. 2 1`] =
ctx = Object.create(ctx);
ctx[isBoundary] = 1
setContextValue(ctx, \\"w\\", 'fromwrapper');
let b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
const b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
return block1([], [b2]);
}
}"
@@ -802,14 +802,14 @@ exports[`t-call (template calling) t-call with t-set inside and outside. 2 2`] =
ctx = Object.create(ctx);
ctx[isBoundary] = 1
ctx = Object.create(ctx);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['list']);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['list']);;
for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`v\`] = v_block2[i1];
ctx[\`v_first\`] = i1 === 0;
ctx[\`v_last\`] = i1 === v_block2.length - 1;
ctx[\`v_index\`] = i1;
ctx[\`v_value\`] = k_block2[i1];
let key1 = ctx['v_index'];
const key1 = ctx['v_index'];
setContextValue(ctx, \\"val\\", ctx['v'].val);
ctx = Object.create(ctx);
ctx[isBoundary] = 1;
@@ -817,7 +817,7 @@ exports[`t-call (template calling) t-call with t-set inside and outside. 2 2`] =
c_block2[i1] = withKey(callTemplate_1.call(this, ctx, node, key + \`__1__\${key1}\`), key1);
ctx = ctx.__proto__;
}
let b2 = list(c_block2);
const b2 = list(c_block2);
return block1([], [b2]);
}
}"
@@ -832,8 +832,8 @@ exports[`t-call (template calling) t-call with t-set inside and outside. 2 3`] =
return function template(ctx, node, key = \\"\\") {
let txt1 = ctx['val3'];
let b2 = block2([txt1]);
let b3 = text(ctx['w']);
const b2 = block2([txt1]);
const b3 = text(ctx['w']);
return multi([b2, b3]);
}
}"
@@ -908,7 +908,7 @@ exports[`t-call (template calling) t-esc inside t-call, with t-set outside 1`] =
ctx = Object.create(ctx);
ctx[isBoundary] = 1
setContextValue(ctx, \\"v\\", \`Hi\`);
let b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
const b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
return block1([], [b2]);
}
}"
@@ -938,7 +938,7 @@ exports[`t-call (template calling) with unused body 1`] = `
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
ctx[isBoundary] = 1;
let b1 = text(\`WHEEE\`);
const b1 = text(\`WHEEE\`);
ctx[zero] = b1;
return callTemplate_1.call(this, ctx, node, key + \`__1\`);
}
@@ -999,7 +999,7 @@ exports[`t-call (template calling) with used body 1`] = `
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
ctx[isBoundary] = 1;
let b1 = text(\`ok\`);
const b1 = text(\`ok\`);
ctx[zero] = b1;
return callTemplate_1.call(this, ctx, node, key + \`__1\`);
}
@@ -1036,7 +1036,7 @@ exports[`t-call (template calling) with used setbody 1`] = `
ctx = Object.create(ctx);
ctx[isBoundary] = 1;
setContextValue(ctx, \\"foo\\", 'ok');
let b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
const b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
return block1([], [b2]);
}
}"
@@ -44,7 +44,7 @@ exports[`debugging t-debug on sub template 2`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
const b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
return block1([], [b2]);
}
}"
+11 -11
View File
@@ -82,15 +82,15 @@ exports[`t-esc falsy values in text nodes 1`] = `
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
let b2 = text(ctx['v1']);
let b3 = text(\`:\`);
let b4 = text(ctx['v2']);
let b5 = text(\`:\`);
let b6 = text(ctx['v3']);
let b7 = text(\`:\`);
let b8 = text(ctx['v4']);
let b9 = text(\`:\`);
let b10 = text(ctx['v5']);
const b2 = text(ctx['v1']);
const b3 = text(\`:\`);
const b4 = text(ctx['v2']);
const b5 = text(\`:\`);
const b6 = text(ctx['v3']);
const b7 = text(\`:\`);
const b8 = text(ctx['v4']);
const b9 = text(\`:\`);
const b10 = text(ctx['v5']);
return multi([b2, b3, b4, b5, b6, b7, b8, b9, b10]);
}
}"
@@ -160,9 +160,9 @@ exports[`t-esc t-esc=0 is escaped 1`] = `
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
ctx[isBoundary] = 1;
let b2 = block2();
const b2 = block2();
ctx[zero] = b2;
let b3 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
const b3 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
return block1([], [b3]);
}
}"
@@ -10,13 +10,13 @@ exports[`t-foreach does not pollute the rendering context 1`] = `
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
const [k_block2, v_block2, l_block2, c_block2] = prepareList([1]);
const [k_block2, v_block2, l_block2, c_block2] = prepareList([1]);;
for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`item\`] = v_block2[i1];
let key1 = ctx['item'];
const key1 = ctx['item'];
c_block2[i1] = withKey(text(ctx['item']), key1);
}
let b2 = list(c_block2);
const b2 = list(c_block2);
return block1([], [b2]);
}
}"
@@ -33,14 +33,14 @@ exports[`t-foreach iterate on items (on a element node) 1`] = `
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
const [k_block2, v_block2, l_block2, c_block2] = prepareList([1,2]);
const [k_block2, v_block2, l_block2, c_block2] = prepareList([1,2]);;
for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`item\`] = v_block2[i1];
let key1 = ctx['item'];
const key1 = ctx['item'];
let txt1 = ctx['item'];
c_block2[i1] = withKey(block3([txt1]), key1);
}
let b2 = list(c_block2);
const b2 = list(c_block2);
return block1([], [b2]);
}
}"
@@ -56,22 +56,22 @@ exports[`t-foreach iterate on items 1`] = `
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
const [k_block2, v_block2, l_block2, c_block2] = prepareList([3,2,1]);
const [k_block2, v_block2, l_block2, c_block2] = prepareList([3,2,1]);;
for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`item\`] = v_block2[i1];
ctx[\`item_index\`] = i1;
ctx[\`item_value\`] = k_block2[i1];
let key1 = ctx['item'];
let b4 = text(\` [\`);
let b5 = text(ctx['item_index']);
let b6 = text(\`: \`);
let b7 = text(ctx['item']);
let b8 = text(\` \`);
let b9 = text(ctx['item_value']);
let b10 = text(\`] \`);
const key1 = ctx['item'];
const b4 = text(\` [\`);
const b5 = text(ctx['item_index']);
const b6 = text(\`: \`);
const b7 = text(ctx['item']);
const b8 = text(\` \`);
const b9 = text(ctx['item_value']);
const b10 = text(\`] \`);
c_block2[i1] = withKey(multi([b4, b5, b6, b7, b8, b9, b10]), key1);
}
let b2 = list(c_block2);
const b2 = list(c_block2);
return block1([], [b2]);
}
}"
@@ -87,22 +87,22 @@ exports[`t-foreach iterate, dict param 1`] = `
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['value']);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['value']);;
for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`item\`] = v_block2[i1];
ctx[\`item_index\`] = i1;
ctx[\`item_value\`] = k_block2[i1];
let key1 = ctx['item_index'];
let b4 = text(\` [\`);
let b5 = text(ctx['item_index']);
let b6 = text(\`: \`);
let b7 = text(ctx['item']);
let b8 = text(\` \`);
let b9 = text(ctx['item_value']);
let b10 = text(\`] \`);
const key1 = ctx['item_index'];
const b4 = text(\` [\`);
const b5 = text(ctx['item_index']);
const b6 = text(\`: \`);
const b7 = text(ctx['item']);
const b8 = text(\` \`);
const b9 = text(ctx['item_value']);
const b10 = text(\`] \`);
c_block2[i1] = withKey(multi([b4, b5, b6, b7, b8, b9, b10]), key1);
}
let b2 = list(c_block2);
const b2 = list(c_block2);
return block1([], [b2]);
}
}"
@@ -118,13 +118,13 @@ exports[`t-foreach iterate, position 1`] = `
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(Array(5));
const [k_block2, v_block2, l_block2, c_block2] = prepareList(Array(5));;
for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`elem\`] = v_block2[i1];
ctx[\`elem_first\`] = i1 === 0;
ctx[\`elem_last\`] = i1 === v_block2.length - 1;
ctx[\`elem_index\`] = i1;
let key1 = ctx['elem'];
const key1 = ctx['elem'];
let b4,b5,b6,b7,b8,b9;
b4 = text(\` -\`);
if (ctx['elem_first']) {
@@ -138,7 +138,7 @@ exports[`t-foreach iterate, position 1`] = `
b9 = text(\`) \`);
c_block2[i1] = withKey(multi([b4, b5, b6, b7, b8, b9]), key1);
}
let b2 = list(c_block2);
const b2 = list(c_block2);
return block1([], [b2]);
}
}"
@@ -154,13 +154,13 @@ exports[`t-foreach simple iteration (in a node) 1`] = `
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
const [k_block2, v_block2, l_block2, c_block2] = prepareList([3,2,1]);
const [k_block2, v_block2, l_block2, c_block2] = prepareList([3,2,1]);;
for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`item\`] = v_block2[i1];
let key1 = ctx['item'];
const key1 = ctx['item'];
c_block2[i1] = withKey(text(ctx['item']), key1);
}
let b2 = list(c_block2);
const b2 = list(c_block2);
return block1([], [b2]);
}
}"
@@ -174,10 +174,10 @@ exports[`t-foreach simple iteration 1`] = `
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
const [k_block1, v_block1, l_block1, c_block1] = prepareList([3,2,1]);
const [k_block1, v_block1, l_block1, c_block1] = prepareList([3,2,1]);;
for (let i1 = 0; i1 < l_block1; i1++) {
ctx[\`item\`] = v_block1[i1];
let key1 = ctx['item'];
const key1 = ctx['item'];
c_block1[i1] = withKey(text(ctx['item']), key1);
}
return list(c_block1);
@@ -196,14 +196,14 @@ exports[`t-foreach simple iteration with two nodes inside 1`] = `
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
const [k_block1, v_block1, l_block1, c_block1] = prepareList([3,2,1]);
const [k_block1, v_block1, l_block1, c_block1] = prepareList([3,2,1]);;
for (let i1 = 0; i1 < l_block1; i1++) {
ctx[\`item\`] = v_block1[i1];
let key1 = ctx['item'];
const key1 = ctx['item'];
let txt1 = ctx['item'];
let b3 = block3([txt1]);
const b3 = block3([txt1]);
let txt2 = ctx['item'];
let b4 = block4([txt2]);
const b4 = block4([txt2]);
c_block1[i1] = withKey(multi([b3, b4]), key1);
}
return list(c_block1);
@@ -225,23 +225,23 @@ exports[`t-foreach t-call with body in t-foreach in t-foreach 1`] = `
ctx = Object.create(ctx);
ctx[isBoundary] = 1
ctx = Object.create(ctx);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['numbers']);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['numbers']);;
for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`a\`] = v_block2[i1];
ctx[\`a_first\`] = i1 === 0;
ctx[\`a_last\`] = i1 === v_block2.length - 1;
ctx[\`a_index\`] = i1;
ctx[\`a_value\`] = k_block2[i1];
let key1 = ctx['a'];
const key1 = ctx['a'];
ctx = Object.create(ctx);
const [k_block4, v_block4, l_block4, c_block4] = prepareList(ctx['letters']);
const [k_block4, v_block4, l_block4, c_block4] = prepareList(ctx['letters']);;
for (let i2 = 0; i2 < l_block4; i2++) {
ctx[\`b\`] = v_block4[i2];
ctx[\`b_first\`] = i2 === 0;
ctx[\`b_last\`] = i2 === v_block4.length - 1;
ctx[\`b_index\`] = i2;
ctx[\`b_value\`] = k_block4[i2];
let key2 = ctx['b'];
const key2 = ctx['b'];
ctx = Object.create(ctx);
ctx[isBoundary] = 1;
setContextValue(ctx, \\"c\\", 'x'+'_'+ctx['a']+'_'+ctx['b']);
@@ -249,13 +249,13 @@ exports[`t-foreach t-call with body in t-foreach in t-foreach 1`] = `
ctx = ctx.__proto__;
}
ctx = ctx.__proto__;
let b4 = list(c_block4);
const b4 = list(c_block4);
let txt1 = ctx['c'];
let b6 = block6([txt1]);
const b6 = block6([txt1]);
c_block2[i1] = withKey(multi([b4, b6]), key1);
}
ctx = ctx.__proto__;
let b2 = list(c_block2);
const b2 = list(c_block2);
let txt2 = ctx['a'];
let txt3 = ctx['b'];
let txt4 = ctx['c'];
@@ -270,13 +270,13 @@ exports[`t-foreach t-call with body in t-foreach in t-foreach 2`] = `
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
let b2 = text(\` [\`);
let b3 = text(ctx['a']);
let b4 = text(\`] [\`);
let b5 = text(ctx['b']);
let b6 = text(\`] [\`);
let b7 = text(ctx['c']);
let b8 = text(\`] \`);
const b2 = text(\` [\`);
const b3 = text(ctx['a']);
const b4 = text(\`] [\`);
const b5 = text(ctx['b']);
const b6 = text(\`] [\`);
const b7 = text(ctx['c']);
const b8 = text(\`] \`);
return multi([b2, b3, b4, b5, b6, b7, b8]);
}
}"
@@ -294,33 +294,33 @@ exports[`t-foreach t-call without body in t-foreach in t-foreach 1`] = `
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['numbers']);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['numbers']);;
for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`a\`] = v_block2[i1];
ctx[\`a_first\`] = i1 === 0;
ctx[\`a_last\`] = i1 === v_block2.length - 1;
ctx[\`a_index\`] = i1;
ctx[\`a_value\`] = k_block2[i1];
let key1 = ctx['a'];
const key1 = ctx['a'];
ctx = Object.create(ctx);
const [k_block4, v_block4, l_block4, c_block4] = prepareList(ctx['letters']);
const [k_block4, v_block4, l_block4, c_block4] = prepareList(ctx['letters']);;
for (let i2 = 0; i2 < l_block4; i2++) {
ctx[\`b\`] = v_block4[i2];
ctx[\`b_first\`] = i2 === 0;
ctx[\`b_last\`] = i2 === v_block4.length - 1;
ctx[\`b_index\`] = i2;
ctx[\`b_value\`] = k_block4[i2];
let key2 = ctx['b'];
const key2 = ctx['b'];
c_block4[i2] = withKey(callTemplate_1.call(this, ctx, node, key + \`__1__\${key1}__\${key2}\`), key2);
}
ctx = ctx.__proto__;
let b4 = list(c_block4);
const b4 = list(c_block4);
let txt1 = ctx['c'];
let b6 = block6([txt1]);
const b6 = block6([txt1]);
c_block2[i1] = withKey(multi([b4, b6]), key1);
}
ctx = ctx.__proto__;
let b2 = list(c_block2);
const b2 = list(c_block2);
let txt2 = ctx['a'];
let txt3 = ctx['b'];
let txt4 = ctx['c'];
@@ -339,13 +339,13 @@ exports[`t-foreach t-call without body in t-foreach in t-foreach 2`] = `
ctx = Object.create(ctx);
ctx[isBoundary] = 1
setContextValue(ctx, \\"c\\", 'x'+'_'+ctx['a']+'_'+ctx['b']);
let b2 = text(\` [\`);
let b3 = text(ctx['a']);
let b4 = text(\`] [\`);
let b5 = text(ctx['b']);
let b6 = text(\`] [\`);
let b7 = text(ctx['c']);
let b8 = text(\`] \`);
const b2 = text(\` [\`);
const b3 = text(ctx['a']);
const b4 = text(\`] [\`);
const b5 = text(ctx['b']);
const b6 = text(\`] [\`);
const b7 = text(ctx['c']);
const b8 = text(\`] \`);
return multi([b2, b3, b4, b5, b6, b7, b8]);
}
}"
@@ -361,25 +361,25 @@ exports[`t-foreach t-foreach in t-foreach 1`] = `
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['numbers']);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['numbers']);;
for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`number\`] = v_block2[i1];
let key1 = ctx['number'];
const key1 = ctx['number'];
ctx = Object.create(ctx);
const [k_block3, v_block3, l_block3, c_block3] = prepareList(ctx['letters']);
const [k_block3, v_block3, l_block3, c_block3] = prepareList(ctx['letters']);;
for (let i2 = 0; i2 < l_block3; i2++) {
ctx[\`letter\`] = v_block3[i2];
let key2 = ctx['letter'];
let b5 = text(\` [\`);
let b6 = text(ctx['number']);
let b7 = text(ctx['letter']);
let b8 = text(\`] \`);
const key2 = ctx['letter'];
const b5 = text(\` [\`);
const b6 = text(ctx['number']);
const b7 = text(ctx['letter']);
const b8 = text(\`] \`);
c_block3[i2] = withKey(multi([b5, b6, b7, b8]), key2);
}
ctx = ctx.__proto__;
c_block2[i1] = withKey(list(c_block3), key1);
}
let b2 = list(c_block2);
const b2 = list(c_block2);
return block1([], [b2]);
}
}"
@@ -395,10 +395,10 @@ exports[`t-foreach t-foreach with t-if inside (no external node) 1`] = `
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
const [k_block1, v_block1, l_block1, c_block1] = prepareList(ctx['elems']);
const [k_block1, v_block1, l_block1, c_block1] = prepareList(ctx['elems']);;
for (let i1 = 0; i1 < l_block1; i1++) {
ctx[\`elem\`] = v_block1[i1];
let key1 = ctx['elem'].id;
const key1 = ctx['elem'].id;
let b3;
if (ctx['elem'].id<3) {
let txt1 = ctx['elem'].text;
@@ -422,10 +422,10 @@ exports[`t-foreach t-foreach with t-if inside 1`] = `
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['elems']);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['elems']);;
for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`elem\`] = v_block2[i1];
let key1 = ctx['elem'].id;
const key1 = ctx['elem'].id;
let b4;
if (ctx['elem'].id<3) {
let txt1 = ctx['elem'].text;
@@ -433,7 +433,7 @@ exports[`t-foreach t-foreach with t-if inside 1`] = `
}
c_block2[i1] = withKey(multi([b4]), key1);
}
let b2 = list(c_block2);
const b2 = list(c_block2);
return block1([], [b2]);
}
}"
@@ -450,13 +450,13 @@ exports[`t-foreach t-key on t-foreach 1`] = `
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['things']);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['things']);;
for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`thing\`] = v_block2[i1];
let key1 = ctx['thing'];
const key1 = ctx['thing'];
c_block2[i1] = withKey(block3(), key1);
}
let b2 = list(c_block2);
const b2 = list(c_block2);
return block1([], [b2]);
}
}"
@@ -473,15 +473,15 @@ exports[`t-foreach throws error if invalid loop expression 1`] = `
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['abc']);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['abc']);;
for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`item\`] = v_block2[i1];
ctx[\`item_index\`] = i1;
let key1 = ctx['item'];
const key1 = ctx['item'];
const tKey_1 = ctx['item_index'];
c_block2[i1] = withKey(block3(), tKey_1 + key1);
}
let b2 = list(c_block2);
const b2 = list(c_block2);
return block1([], [b2]);
}
}"
@@ -500,12 +500,12 @@ exports[`t-foreach with t-memo 1`] = `
let cache = ctx.cache || {};
let nextCache = ctx.cache = {};
ctx = Object.create(ctx);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['items']);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['items']);;
for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`item\`] = v_block2[i1];
let key1 = ctx['item'].id;
let memo1 = [ctx['item'].x]
let vnode1 = cache[key1];
const key1 = ctx['item'].id;
const memo1 = [ctx['item'].x];
const vnode1 = cache[key1];;
if (vnode1) {
if (shallowEqual(vnode1.memo, memo1)) {
c_block2[i1] = vnode1;
@@ -518,7 +518,7 @@ exports[`t-foreach with t-memo 1`] = `
c_block2[i1] = withKey(block3([txt1, txt2]), key1);
nextCache[key1] = Object.assign(c_block2[i1], {memo: memo1});
}
let b2 = list(c_block2);
const b2 = list(c_block2);
return block1([], [b2]);
}
}"
+10 -10
View File
@@ -29,8 +29,8 @@ exports[`t-if a t-if with two inner nodes 1`] = `
return function template(ctx, node, key = \\"\\") {
let b2;
if (ctx['condition']) {
let b3 = block3();
let b4 = block4();
const b3 = block3();
const b4 = block4();
b2 = multi([b3, b4]);
}
return multi([b2]);
@@ -187,8 +187,8 @@ exports[`t-if div containing a t-if with two inner nodes 1`] = `
return function template(ctx, node, key = \\"\\") {
let b2;
if (ctx['condition']) {
let b3 = block3();
let b4 = block4();
const b3 = block3();
const b4 = block4();
b2 = multi([b3, b4]);
}
return block1([], [b2]);
@@ -208,8 +208,8 @@ exports[`t-if dynamic content after t-if with two children nodes 1`] = `
return function template(ctx, node, key = \\"\\") {
let b2;
if (ctx['condition']) {
let b3 = block3();
let b4 = block4();
const b3 = block3();
const b4 = block4();
b2 = multi([b3, b4]);
}
let txt1 = ctx['text'];
@@ -318,8 +318,8 @@ exports[`t-if t-if and t-else with two nodes 1`] = `
if (ctx['condition']) {
b2 = text(\`1\`);
} else {
let b4 = block4();
let b5 = block5();
const b4 = block4();
const b5 = block5();
b3 = multi([b4, b5]);
}
return multi([b2, b3]);
@@ -526,8 +526,8 @@ exports[`t-if two t-ifs next to each other 1`] = `
b2 = block2([txt1]);
}
if (ctx['condition']) {
let b4 = block4();
let b5 = block5();
const b4 = block4();
const b5 = block5();
b3 = multi([b4, b5]);
}
return block1([], [b2, b3]);
@@ -56,14 +56,14 @@ exports[`t-key t-key directive in a list 1`] = `
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['beers']);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['beers']);;
for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`beer\`] = v_block2[i1];
let key1 = ctx['beer'].id;
const key1 = ctx['beer'].id;
let txt1 = ctx['beer'].name;
c_block2[i1] = withKey(block3([txt1]), key1);
}
let b2 = list(c_block2);
const b2 = list(c_block2);
return block1([], [b2]);
}
}"
+32 -32
View File
@@ -9,7 +9,7 @@ exports[`t-out literal 1`] = `
let block1 = createBlock(\`<span><block-child-0/></span>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = safeOutput('ok');
const b2 = safeOutput('ok');
return block1([], [b2]);
}
}"
@@ -40,9 +40,9 @@ exports[`t-out multiple calls to t-out 1`] = `
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
ctx[isBoundary] = 1;
let b2 = block2();
const b2 = block2();
ctx[zero] = b2;
let b3 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
const b3 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
return block1([], [b3]);
}
}"
@@ -57,8 +57,8 @@ exports[`t-out multiple calls to t-out 2`] = `
let block1 = createBlock(\`<div><block-child-0/><div>Greeter</div><block-child-1/></div>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = ctx[zero];
let b3 = ctx[zero];
const b2 = ctx[zero];
const b3 = ctx[zero];
return block1([], [b2, b3]);
}
}"
@@ -73,7 +73,7 @@ exports[`t-out not escaping 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = safeOutput(ctx['var']);
const b2 = safeOutput(ctx['var']);
return block1([], [b2]);
}
}"
@@ -92,9 +92,9 @@ exports[`t-out t-out 0 1`] = `
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
ctx[isBoundary] = 1;
let b2 = block2();
const b2 = block2();
ctx[zero] = b2;
let b3 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
const b3 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
return block1([], [b3]);
}
}"
@@ -109,7 +109,7 @@ exports[`t-out t-out 0 2`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = ctx[zero];
const b2 = ctx[zero];
return block1([], [b2]);
}
}"
@@ -124,7 +124,7 @@ exports[`t-out t-out and another sibling node 1`] = `
let block1 = createBlock(\`<span><span>hello</span><block-child-0/></span>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = safeOutput(ctx['var']);
const b2 = safeOutput(ctx['var']);
return block1([], [b2]);
}
}"
@@ -147,7 +147,7 @@ exports[`t-out t-out bdom 1`] = `
ctx = Object.create(ctx);
ctx[isBoundary] = 1
ctx[\`var\`] = new LazyValue(value1, ctx, node);
let b3 = safeOutput(ctx['var']);
const b3 = safeOutput(ctx['var']);
return block1([], [b3]);
}
}"
@@ -162,7 +162,7 @@ exports[`t-out t-out block 1`] = `
let block1 = createBlock(\`<span><block-child-0/></span>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = safeOutput(ctx['bdom']);
const b2 = safeOutput(ctx['bdom']);
return block1([], [b2]);
}
}"
@@ -177,7 +177,7 @@ exports[`t-out t-out escaped 1`] = `
let block1 = createBlock(\`<span><block-child-0/></span>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = safeOutput(ctx['var']);
const b2 = safeOutput(ctx['var']);
return block1([], [b2]);
}
}"
@@ -192,7 +192,7 @@ exports[`t-out t-out markedup 1`] = `
let block1 = createBlock(\`<span><block-child-0/></span>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = safeOutput(ctx['var']);
const b2 = safeOutput(ctx['var']);
return block1([], [b2]);
}
}"
@@ -207,8 +207,8 @@ exports[`t-out t-out on a node with a body, as a default 1`] = `
let block1 = createBlock(\`<span><block-child-0/></span>\`);
return function template(ctx, node, key = \\"\\") {
let b3 = text(\`nope\`);
let b2 = withDefault(safeOutput(ctx['var']), b3);
const b3 = text(\`nope\`);
const b2 = withDefault(safeOutput(ctx['var']), b3);
return block1([], [b2]);
}
}"
@@ -224,8 +224,8 @@ exports[`t-out t-out on a node with a dom node in body, as a default 1`] = `
let block3 = createBlock(\`<div>nope</div>\`);
return function template(ctx, node, key = \\"\\") {
let b3 = block3();
let b2 = withDefault(safeOutput(ctx['var']), b3);
const b3 = block3();
const b2 = withDefault(safeOutput(ctx['var']), b3);
return block1([], [b2]);
}
}"
@@ -240,7 +240,7 @@ exports[`t-out t-out switch escaped 1`] = `
let block1 = createBlock(\`<span><block-child-0/></span>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = safeOutput(ctx['var']);
const b2 = safeOutput(ctx['var']);
return block1([], [b2]);
}
}"
@@ -255,7 +255,7 @@ exports[`t-out t-out switch escaped on markup 1`] = `
let block1 = createBlock(\`<span><block-child-0/></span>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = safeOutput(ctx['var']);
const b2 = safeOutput(ctx['var']);
return block1([], [b2]);
}
}"
@@ -270,7 +270,7 @@ exports[`t-out t-out switch markup 1`] = `
let block1 = createBlock(\`<span><block-child-0/></span>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = safeOutput(ctx['var']);
const b2 = safeOutput(ctx['var']);
return block1([], [b2]);
}
}"
@@ -297,10 +297,10 @@ exports[`t-out t-out switch markup on bdom 1`] = `
let b3,b5;
ctx[\`bdom\`] = new LazyValue(value1, ctx, node);
if (ctx['hasBdom']) {
let b4 = safeOutput(ctx['bdom']);
const b4 = safeOutput(ctx['bdom']);
b3 = block3([], [b4]);
} else {
let b6 = safeOutput(ctx['var']);
const b6 = safeOutput(ctx['var']);
b5 = block5([], [b6]);
}
return block1([], [b3, b5]);
@@ -317,7 +317,7 @@ exports[`t-out t-out switch markup on escaped 1`] = `
let block1 = createBlock(\`<span><block-child-0/></span>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = safeOutput(ctx['var']);
const b2 = safeOutput(ctx['var']);
return block1([], [b2]);
}
}"
@@ -344,7 +344,7 @@ exports[`t-out t-out with arbitrary object 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = safeOutput(ctx['var']);
const b2 = safeOutput(ctx['var']);
return block1([], [b2]);
}
}"
@@ -359,7 +359,7 @@ exports[`t-out t-out with arbitrary object 2 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = safeOutput(ctx['var']);
const b2 = safeOutput(ctx['var']);
return block1([], [b2]);
}
}"
@@ -374,7 +374,7 @@ exports[`t-out t-out with comment 1`] = `
let block1 = createBlock(\`<span><block-child-0/></span>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = safeOutput(ctx['var']);
const b2 = safeOutput(ctx['var']);
return block1([], [b2]);
}
}"
@@ -401,7 +401,7 @@ exports[`t-out variable 1`] = `
let block1 = createBlock(\`<span><block-child-0/></span>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = safeOutput(ctx['var']);
const b2 = safeOutput(ctx['var']);
return block1([], [b2]);
}
}"
@@ -416,7 +416,7 @@ exports[`t-out with a String class 1`] = `
let block1 = createBlock(\`<span><block-child-0/></span>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = safeOutput(ctx['var']);
const b2 = safeOutput(ctx['var']);
return block1([], [b2]);
}
}"
@@ -431,7 +431,7 @@ exports[`t-out with an extended String class 1`] = `
let block1 = createBlock(\`<span><block-child-0/></span>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = safeOutput(ctx['var']);
const b2 = safeOutput(ctx['var']);
return block1([], [b2]);
}
}"
@@ -446,7 +446,7 @@ exports[`t-raw is deprecated should warn 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = safeOutput(ctx['var']);
const b2 = safeOutput(ctx['var']);
return block1([], [b2]);
}
}"
@@ -461,7 +461,7 @@ exports[`t-raw is deprecated t-out is actually called in t-raw's place 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = safeOutput(ctx['var']);
const b2 = safeOutput(ctx['var']);
return block1([], [b2]);
}
}"
@@ -41,7 +41,7 @@ exports[`t-ref ref in a t-call 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
const b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
return block1([], [b2]);
}
}"
@@ -94,17 +94,17 @@ exports[`t-ref refs in a loop 1`] = `
return function template(ctx, node, key = \\"\\") {
const refs = ctx.__owl__.refs;
ctx = Object.create(ctx);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['items']);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['items']);;
for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`item\`] = v_block2[i1];
let key1 = ctx['item'];
const key1 = ctx['item'];
const tKey_1 = ctx['item'];
const v1 = ctx['item'];
let ref1 = (el) => refs[\`\${v1}\`] = el;
let txt1 = ctx['item'];
c_block2[i1] = withKey(block3([ref1, txt1]), tKey_1 + key1);
}
let b2 = list(c_block2);
const b2 = list(c_block2);
return block1([], [b2]);
}
}"
+19 -19
View File
@@ -208,7 +208,7 @@ exports[`t-set t-set body is evaluated immediately 1`] = `
setContextValue(ctx, \\"v1\\", 'before');
ctx[\`v2\`] = new LazyValue(value1, ctx, node);
setContextValue(ctx, \\"v1\\", 'after');
let b3 = safeOutput(ctx['v2']);
const b3 = safeOutput(ctx['v2']);
return block1([], [b3]);
}
}"
@@ -228,7 +228,7 @@ exports[`t-set t-set can't alter from within callee 1`] = `
ctx[isBoundary] = 1
setContextValue(ctx, \\"iter\\", 'source');
let txt1 = ctx['iter'];
let b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
const b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
let txt2 = ctx['iter'];
return block1([txt1, txt2], [b2]);
}
@@ -271,7 +271,7 @@ exports[`t-set t-set can't alter in t-call body 1`] = `
ctx = Object.create(ctx);
ctx[isBoundary] = 1;
setContextValue(ctx, \\"iter\\", 'inCall');
let b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
const b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
ctx = ctx.__proto__;
let txt2 = ctx['iter'];
return block1([txt1, txt2], [b2]);
@@ -349,16 +349,16 @@ exports[`t-set t-set outside modified in t-foreach 1`] = `
ctx[isBoundary] = 1
setContextValue(ctx, \\"iter\\", 0);
ctx = Object.create(ctx);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(['a','b']);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(['a','b']);;
for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`val\`] = v_block2[i1];
let key1 = ctx['val'];
const key1 = ctx['val'];
let txt1 = ctx['iter'];
c_block2[i1] = withKey(block3([txt1]), key1);
setContextValue(ctx, \\"iter\\", ctx['iter']+1);
}
ctx = ctx.__proto__;
let b2 = list(c_block2);
const b2 = list(c_block2);
let txt2 = ctx['iter'];
return block1([txt2], [b2]);
}
@@ -379,16 +379,16 @@ exports[`t-set t-set outside modified in t-foreach increment-after operator 1`]
ctx[isBoundary] = 1
setContextValue(ctx, \\"iter\\", 0);
ctx = Object.create(ctx);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(['a','b']);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(['a','b']);;
for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`val\`] = v_block2[i1];
let key1 = ctx['val'];
const key1 = ctx['val'];
let txt1 = ctx['iter'];
c_block2[i1] = withKey(block3([txt1]), key1);
setContextValue(ctx, \\"iter\\", ctx['iter']++);
}
ctx = ctx.__proto__;
let b2 = list(c_block2);
const b2 = list(c_block2);
let txt2 = ctx['iter'];
return block1([txt2], [b2]);
}
@@ -409,16 +409,16 @@ exports[`t-set t-set outside modified in t-foreach increment-before operator 1`]
ctx[isBoundary] = 1
setContextValue(ctx, \\"iter\\", 0);
ctx = Object.create(ctx);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(['a','b']);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(['a','b']);;
for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`val\`] = v_block2[i1];
let key1 = ctx['val'];
const key1 = ctx['val'];
let txt1 = ctx['iter'];
c_block2[i1] = withKey(block3([txt1]), key1);
setContextValue(ctx, \\"iter\\", ++ctx['iter']);
}
ctx = ctx.__proto__;
let b2 = list(c_block2);
const b2 = list(c_block2);
let txt2 = ctx['iter'];
return block1([txt2], [b2]);
}
@@ -439,16 +439,16 @@ exports[`t-set t-set should reuse variable if possible 1`] = `
ctx[isBoundary] = 1
setContextValue(ctx, \\"v\\", 1);
ctx = Object.create(ctx);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['list']);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['list']);;
for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`elem\`] = v_block2[i1];
ctx[\`elem_index\`] = i1;
let key1 = ctx['elem_index'];
const key1 = ctx['elem_index'];
let txt1 = ctx['v'];
setContextValue(ctx, \\"v\\", ctx['elem']);
c_block2[i1] = withKey(block3([txt1]), key1);
}
let b2 = list(c_block2);
const b2 = list(c_block2);
return block1([], [b2]);
}
}"
@@ -463,8 +463,8 @@ exports[`t-set t-set with content and sub t-esc 1`] = `
let block1 = createBlock(\`<div><block-text-0/></div>\`);
function value1(ctx, node, key = \\"\\") {
let b3 = text(ctx['beep']);
let b4 = text(\` boop\`);
const b3 = text(ctx['beep']);
const b4 = text(\` boop\`);
return multi([b3, b4]);
}
@@ -500,7 +500,7 @@ exports[`t-set t-set with t-value (falsy) and body 1`] = `
ctx[\`v2\`] = withDefault(ctx['v3'], new LazyValue(value1, ctx, node));
setContextValue(ctx, \\"v1\\", 'after');
setContextValue(ctx, \\"v3\\", true);
let b3 = safeOutput(ctx['v2']);
const b3 = safeOutput(ctx['v2']);
return block1([], [b3]);
}
}"
@@ -528,7 +528,7 @@ exports[`t-set t-set with t-value (truthy) and body 1`] = `
ctx[\`v2\`] = withDefault(ctx['v3'], new LazyValue(value1, ctx, node));
setContextValue(ctx, \\"v1\\", 'after');
setContextValue(ctx, \\"v3\\", false);
let b3 = safeOutput(ctx['v2']);
const b3 = safeOutput(ctx['v2']);
return block1([], [b3]);
}
}"
+13 -13
View File
@@ -8,7 +8,7 @@ exports[`qweb t-tag can fallback if falsy tag 1`] = `
let block1 = tag => createBlock(\`<\${tag || 'fallback'}/>\`);
return function template(ctx, node, key = \\"\\") {
let tag1 = ctx['tag'];
const tag1 = ctx['tag'];
return toggler(tag1, block1(tag1)());
}
}"
@@ -22,7 +22,7 @@ exports[`qweb t-tag can update 1`] = `
let block1 = tag => createBlock(\`<\${tag || 't'}/>\`);
return function template(ctx, node, key = \\"\\") {
let tag1 = ctx['tag'];
const tag1 = ctx['tag'];
return toggler(tag1, block1(tag1)());
}
}"
@@ -36,7 +36,7 @@ exports[`qweb t-tag simple usecases 1`] = `
let block1 = tag => createBlock(\`<\${tag || 't'}/>\`);
return function template(ctx, node, key = \\"\\") {
let tag1 = 'div';
const tag1 = 'div';
return toggler(tag1, block1(tag1)());
}
}"
@@ -50,7 +50,7 @@ exports[`qweb t-tag simple usecases 2`] = `
let block1 = tag => createBlock(\`<\${tag || 't'}>text</\${tag || 't'}>\`);
return function template(ctx, node, key = \\"\\") {
let tag1 = ctx['tag'];
const tag1 = ctx['tag'];
return toggler(tag1, block1(tag1)());
}
}"
@@ -64,7 +64,7 @@ exports[`qweb t-tag with multiple attributes 1`] = `
let block1 = tag => createBlock(\`<\${tag || 't'} class=\\"blueberry\\" taste=\\"raspberry\\">gooseberry</\${tag || 't'}>\`);
return function template(ctx, node, key = \\"\\") {
let tag1 = ctx['tag'];
const tag1 = ctx['tag'];
return toggler(tag1, block1(tag1)());
}
}"
@@ -78,7 +78,7 @@ exports[`qweb t-tag with multiple child nodes 1`] = `
let block1 = tag => createBlock(\`<\${tag || 't'}> pear <span>apple</span> strawberry </\${tag || 't'}>\`);
return function template(ctx, node, key = \\"\\") {
let tag1 = ctx['tag'];
const tag1 = ctx['tag'];
return toggler(tag1, block1(tag1)());
}
}"
@@ -93,9 +93,9 @@ exports[`qweb t-tag with multiple t-tag in same template 1`] = `
let block2 = tag => createBlock(\`<\${tag || 't'}>baz</\${tag || 't'}>\`);
return function template(ctx, node, key = \\"\\") {
let tag1 = ctx['outer'];
let tag2 = ctx['inner'];
let b2 = toggler(tag2, block2(tag2)());
const tag1 = ctx['outer'];
const tag2 = ctx['inner'];
const b2 = toggler(tag2, block2(tag2)());
return toggler(tag1, block1(tag1)([], [b2]));
}
}"
@@ -110,10 +110,10 @@ exports[`qweb t-tag with multiple t-tag in same template, part 2 1`] = `
let block3 = tag => createBlock(\`<\${tag || 't'}>baz</\${tag || 't'}>\`);
return function template(ctx, node, key = \\"\\") {
let tag1 = ctx['brother'];
let b2 = toggler(tag1, block2(tag1)());
let tag2 = ctx['brother'];
let b3 = toggler(tag2, block3(tag2)());
const tag1 = ctx['brother'];
const b2 = toggler(tag1, block2(tag1)());
const tag2 = ctx['brother'];
const b3 = toggler(tag2, block3(tag2)());
return multi([b2, b3]);
}
}"
@@ -50,7 +50,7 @@ exports[`loading templates can load a few templates from a xml string 1`] = `
let block1 = createBlock(\`<ul><block-child-0/></ul>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
const b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
return block1([], [b2]);
}
}"
@@ -65,8 +65,8 @@ exports[`loading templates can load a few templates from a xml string 2`] = `
let block3 = createBlock(\`<li>foo</li>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = block2();
let b3 = block3();
const b2 = block2();
const b3 = block3();
return multi([b2, b3]);
}
}"
@@ -82,7 +82,7 @@ exports[`loading templates can load a few templates from an XMLDocument 1`] = `
let block1 = createBlock(\`<ul><block-child-0/></ul>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
const b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
return block1([], [b2]);
}
}"
@@ -97,8 +97,8 @@ exports[`loading templates can load a few templates from an XMLDocument 2`] = `
let block3 = createBlock(\`<li>foo</li>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = block2();
let b3 = block3();
const b2 = block2();
const b3 = block3();
return multi([b2, b3]);
}
}"
+13
View File
@@ -0,0 +1,13 @@
import { renderToString } from "../helpers";
describe("blacklisted tags and attributes", () => {
test("template with block-text tag", () => {
const template = `<div><block-text-0/>hello</div>`;
expect(() => renderToString(template)).toThrow("Invalid tag name: 'block-text-0'");
});
test("template with block-handler tag", () => {
const template = `<div block-handler-0="click">hello</div>`;
expect(() => renderToString(template)).toThrow("Invalid attribute: 'block-handler-0'");
});
});
+5 -5
View File
@@ -65,14 +65,14 @@ describe("tokenizer", () => {
});
test("strings", () => {
expect(() => tokenize("'")).toThrow("Invalid expression");
expect(() => tokenize("'\\")).toThrow("Invalid expression");
expect(() => tokenize("'\\'")).toThrow("Invalid expression");
expect(() => tokenize("'")).toThrow("Tokenizer error: could not tokenize `'`");
expect(() => tokenize("'\\")).toThrow("Tokenizer error: could not tokenize `'\\`");
expect(() => tokenize("'\\'")).toThrow("Tokenizer error: could not tokenize `'\\'`");
expect(tokenize("'hello ged'")).toEqual([{ type: "VALUE", value: "'hello ged'" }]);
expect(tokenize("'hello \\'ged\\''")).toEqual([{ type: "VALUE", value: "'hello \\'ged\\''" }]);
expect(() => tokenize('"')).toThrow("Invalid expression");
expect(() => tokenize('"\\"')).toThrow("Invalid expression");
expect(() => tokenize('"')).toThrow('Tokenizer error: could not tokenize `"`');
expect(() => tokenize('"\\"')).toThrow('Tokenizer error: could not tokenize `"\\"`');
expect(tokenize('"hello ged"')).toEqual([{ type: "VALUE", value: '"hello ged"' }]);
expect(tokenize('"hello ged"}')).toEqual([
{ type: "VALUE", value: '"hello ged"' },
+267 -145
View File
@@ -42,8 +42,8 @@ describe("qweb parser", () => {
tag: "div",
dynamicTag: null,
content: [],
attrs: {},
on: {},
attrs: null,
on: null,
ref: null,
model: null,
ns: null,
@@ -69,8 +69,8 @@ describe("qweb parser", () => {
type: ASTType.DomNode,
tag: "div",
dynamicTag: null,
attrs: {},
on: {},
attrs: null,
on: null,
ref: null,
model: null,
content: [],
@@ -83,8 +83,8 @@ describe("qweb parser", () => {
type: ASTType.DomNode,
tag: "div",
dynamicTag: null,
attrs: {},
on: {},
attrs: null,
on: null,
ref: null,
model: null,
content: [{ type: ASTType.Text, value: "some text" }],
@@ -97,8 +97,8 @@ describe("qweb parser", () => {
type: ASTType.DomNode,
tag: "div",
dynamicTag: null,
attrs: {},
on: {},
attrs: null,
on: null,
ref: null,
model: null,
ns: null,
@@ -108,8 +108,8 @@ describe("qweb parser", () => {
type: ASTType.DomNode,
tag: "span",
dynamicTag: null,
attrs: {},
on: {},
attrs: null,
on: null,
ref: null,
model: null,
ns: null,
@@ -127,8 +127,8 @@ describe("qweb parser", () => {
type: ASTType.DomNode,
tag: "div",
dynamicTag: null,
attrs: {},
on: {},
attrs: null,
on: null,
ref: null,
model: null,
ns: null,
@@ -138,8 +138,8 @@ describe("qweb parser", () => {
type: ASTType.DomNode,
tag: "span",
dynamicTag: null,
attrs: {},
on: {},
attrs: null,
on: null,
ref: null,
model: null,
ns: null,
@@ -155,8 +155,8 @@ describe("qweb parser", () => {
type: ASTType.DomNode,
tag: "div",
dynamicTag: null,
attrs: {},
on: {},
attrs: null,
on: null,
ref: null,
model: null,
ns: null,
@@ -180,8 +180,8 @@ describe("qweb parser", () => {
type: ASTType.DomNode,
tag: "div",
dynamicTag: null,
attrs: {},
on: {},
attrs: null,
on: null,
ref: null,
model: null,
ns: null,
@@ -200,8 +200,8 @@ describe("qweb parser", () => {
type: ASTType.DomNode,
tag: "div",
dynamicTag: null,
attrs: {},
on: {},
attrs: null,
on: null,
ref: null,
model: null,
ns: null,
@@ -222,8 +222,8 @@ describe("qweb parser", () => {
type: ASTType.DomNode,
tag: "div",
dynamicTag: null,
attrs: {},
on: {},
attrs: null,
on: null,
ref: null,
model: null,
ns: null,
@@ -245,8 +245,8 @@ describe("qweb parser", () => {
type: ASTType.DomNode,
tag: "span",
dynamicTag: null,
attrs: {},
on: {},
attrs: null,
on: null,
ref: null,
model: null,
ns: null,
@@ -262,7 +262,7 @@ describe("qweb parser", () => {
tag: "div",
dynamicTag: null,
attrs: { class: "abc" },
on: {},
on: null,
ref: null,
model: null,
ns: null,
@@ -294,7 +294,7 @@ describe("qweb parser", () => {
dynamicTag: null,
model: null,
ns: null,
on: {},
on: null,
ref: null,
tag: "circle",
type: 2,
@@ -303,7 +303,7 @@ describe("qweb parser", () => {
dynamicTag: null,
model: null,
ns: "http://www.w3.org/2000/svg",
on: {},
on: null,
ref: null,
tag: "svg",
type: 2,
@@ -311,7 +311,7 @@ describe("qweb parser", () => {
expect(
parse(`<g><circle cx="50" cy="50" r="4" stroke="green" stroke-width="1" fill="yellow"/></g>`)
).toEqual({
attrs: {},
attrs: null,
content: [
{
attrs: {
@@ -326,7 +326,7 @@ describe("qweb parser", () => {
dynamicTag: null,
model: null,
ns: null,
on: {},
on: null,
ref: null,
tag: "circle",
type: 2,
@@ -335,7 +335,7 @@ describe("qweb parser", () => {
dynamicTag: null,
model: null,
ns: "http://www.w3.org/2000/svg",
on: {},
on: null,
ref: null,
tag: "g",
type: 2,
@@ -347,16 +347,16 @@ describe("qweb parser", () => {
type: 2,
tag: "div",
dynamicTag: null,
attrs: {},
on: {},
attrs: null,
on: null,
ref: null,
content: [
{
type: 2,
tag: "pre",
dynamicTag: null,
attrs: {},
on: {},
attrs: null,
on: null,
ref: null,
content: [],
model: null,
@@ -390,8 +390,8 @@ describe("qweb parser", () => {
type: ASTType.DomNode,
tag: "span",
dynamicTag: null,
attrs: {},
on: {},
attrs: null,
on: null,
ref: null,
model: null,
ns: null,
@@ -412,8 +412,8 @@ describe("qweb parser", () => {
type: ASTType.DomNode,
tag: "div",
dynamicTag: null,
attrs: {},
on: {},
attrs: null,
on: null,
ref: null,
model: null,
ns: null,
@@ -454,8 +454,8 @@ describe("qweb parser", () => {
type: ASTType.DomNode,
tag: "div",
dynamicTag: null,
attrs: {},
on: {},
attrs: null,
on: null,
ref: null,
model: null,
ns: null,
@@ -468,8 +468,8 @@ describe("qweb parser", () => {
type: ASTType.DomNode,
tag: "div",
dynamicTag: null,
attrs: {},
on: {},
attrs: null,
on: null,
ref: null,
model: null,
ns: null,
@@ -488,8 +488,8 @@ describe("qweb parser", () => {
type: ASTType.DomNode,
tag: "div",
dynamicTag: null,
attrs: {},
on: {},
attrs: null,
on: null,
ref: null,
model: null,
ns: null,
@@ -529,8 +529,8 @@ describe("qweb parser", () => {
type: ASTType.DomNode,
tag: "div",
dynamicTag: null,
attrs: {},
on: {},
attrs: null,
on: null,
ref: null,
model: null,
ns: null,
@@ -606,8 +606,8 @@ describe("qweb parser", () => {
type: ASTType.DomNode,
tag: "div",
dynamicTag: null,
attrs: {},
on: {},
attrs: null,
on: null,
ref: null,
model: null,
ns: null,
@@ -625,8 +625,8 @@ describe("qweb parser", () => {
type: ASTType.DomNode,
tag: "h1",
dynamicTag: null,
attrs: {},
on: {},
attrs: null,
on: null,
ref: null,
model: null,
ns: null,
@@ -638,8 +638,8 @@ describe("qweb parser", () => {
type: ASTType.DomNode,
tag: "h2",
dynamicTag: null,
attrs: {},
on: {},
attrs: null,
on: null,
ref: null,
model: null,
ns: null,
@@ -684,8 +684,8 @@ describe("qweb parser", () => {
body: [
{
type: ASTType.DomNode,
attrs: {},
on: {},
attrs: null,
on: null,
tag: "div",
dynamicTag: null,
ref: null,
@@ -704,8 +704,8 @@ describe("qweb parser", () => {
body: [
{
type: ASTType.DomNode,
attrs: {},
on: {},
attrs: null,
on: null,
tag: "div",
dynamicTag: null,
ref: null,
@@ -741,8 +741,8 @@ describe("qweb parser", () => {
type: ASTType.DomNode,
tag: "div",
dynamicTag: null,
attrs: {},
on: {},
attrs: null,
on: null,
ref: null,
model: null,
ns: null,
@@ -810,8 +810,8 @@ describe("qweb parser", () => {
type: ASTType.DomNode,
tag: "div",
dynamicTag: null,
attrs: {},
on: {},
attrs: null,
on: null,
ref: null,
model: null,
ns: null,
@@ -852,8 +852,8 @@ describe("qweb parser", () => {
type: ASTType.DomNode,
tag: "span",
dynamicTag: null,
attrs: {},
on: {},
attrs: null,
on: null,
ref: null,
model: null,
ns: null,
@@ -886,8 +886,8 @@ describe("qweb parser", () => {
type: ASTType.DomNode,
tag: "span",
dynamicTag: null,
attrs: {},
on: {},
attrs: null,
on: null,
ref: null,
model: null,
ns: null,
@@ -920,7 +920,7 @@ describe("qweb parser", () => {
"t-att-selected": "category.id==options.active_category_id",
"t-att-value": "category.id",
},
on: {},
on: null,
ref: null,
model: null,
ns: null,
@@ -939,8 +939,8 @@ describe("qweb parser", () => {
parse(`<div><t t-foreach="list" t-as="item" t-key="item_index"><t t-esc="item"/></t></div>`)
).toEqual({
type: ASTType.DomNode,
attrs: {},
on: {},
attrs: null,
on: null,
ref: null,
model: null,
tag: "div",
@@ -983,10 +983,10 @@ describe("qweb parser", () => {
type: ASTType.DomNode,
tag: "span",
dynamicTag: null,
on: {},
on: null,
ref: null,
model: null,
attrs: {},
attrs: null,
ns: null,
content: [{ type: ASTType.TEsc, expr: "item", defaultValue: "" }],
},
@@ -1009,8 +1009,9 @@ describe("qweb parser", () => {
isDynamic: false,
name: "Comp",
dynamicProps: null,
props: {},
slots: {},
props: null,
slots: null,
on: null,
},
memo: "",
hasNoFirst: true,
@@ -1085,8 +1086,8 @@ describe("qweb parser", () => {
type: ASTType.DomNode,
tag: "div",
dynamicTag: null,
attrs: {},
on: {},
attrs: null,
on: null,
ref: null,
model: null,
ns: null,
@@ -1123,7 +1124,7 @@ describe("qweb parser", () => {
type: ASTType.DomNode,
tag: "button",
dynamicTag: null,
attrs: {},
attrs: null,
on: { click: "add" },
ref: null,
model: null,
@@ -1141,8 +1142,8 @@ describe("qweb parser", () => {
type: 2,
tag: "select",
dynamicTag: null,
attrs: {},
on: {},
attrs: null,
on: null,
ref: null,
content: [
{
@@ -1150,7 +1151,7 @@ describe("qweb parser", () => {
tag: "option",
dynamicTag: null,
attrs: { value: "1" },
on: {},
on: null,
ref: null,
content: [],
model: null,
@@ -1161,6 +1162,7 @@ describe("qweb parser", () => {
baseExpr: "state",
expr: "'model'",
targetAttr: "value",
hasDynamicChildren: false,
specialInitTargetAttr: null,
eventType: "change",
shouldTrim: false,
@@ -1177,8 +1179,8 @@ describe("qweb parser", () => {
type: 2,
tag: "select",
dynamicTag: null,
attrs: {},
on: {},
attrs: null,
on: null,
ref: null,
content: [
{
@@ -1186,7 +1188,7 @@ describe("qweb parser", () => {
tag: "option",
dynamicTag: null,
attrs: { "t-att-value": "valueVar" },
on: {},
on: null,
ref: null,
content: [],
model: null,
@@ -1216,8 +1218,9 @@ describe("qweb parser", () => {
type: ASTType.TComponent,
name: "MyComponent",
dynamicProps: null,
props: {},
slots: {},
props: null,
on: null,
slots: null,
isDynamic: false,
});
});
@@ -1229,7 +1232,8 @@ describe("qweb parser", () => {
dynamicProps: null,
props: { a: "1", b: "'b'" },
isDynamic: false,
slots: {},
on: null,
slots: null,
});
});
@@ -1240,14 +1244,21 @@ describe("qweb parser", () => {
dynamicProps: "state",
props: { a: "1" },
isDynamic: false,
slots: {},
on: null,
slots: null,
});
});
test("component with event handler", async () => {
expect(() => parse(`<MyComponent t-on-click="someMethod"/>`)).toThrow(
"t-on is no longer supported on components. Consider passing a callback in props."
);
expect(parse(`<MyComponent t-on-click="someMethod"/>`)).toEqual({
type: ASTType.TComponent,
name: "MyComponent",
dynamicProps: null,
props: null,
isDynamic: false,
on: { click: "someMethod" },
slots: null,
});
});
test("component with t-ref", async () => {
@@ -1279,9 +1290,17 @@ describe("qweb parser", () => {
type: ASTType.TComponent,
name: "MyComponent",
dynamicProps: null,
props: {},
props: null,
isDynamic: false,
slots: { default: { content: { type: ASTType.Text, value: "foo" } } },
on: null,
slots: {
default: {
content: { type: ASTType.Text, value: "foo" },
attrs: null,
on: null,
scope: null,
},
},
});
});
@@ -1292,10 +1311,16 @@ describe("qweb parser", () => {
type: ASTType.TComponent,
name: "MyComponent",
dynamicProps: null,
props: {},
props: null,
isDynamic: false,
on: null,
slots: {
default: { content: { type: ASTType.Text, value: "foo" }, attrs: { param: "param" } },
default: {
content: { type: ASTType.Text, value: "foo" },
attrs: { param: "param" },
on: null,
scope: null,
},
},
});
});
@@ -1306,7 +1331,8 @@ describe("qweb parser", () => {
name: "MyComponent",
isDynamic: false,
dynamicProps: null,
props: {},
props: null,
on: null,
slots: {
default: {
content: {
@@ -1316,26 +1342,29 @@ describe("qweb parser", () => {
type: ASTType.DomNode,
tag: "span",
dynamicTag: null,
attrs: {},
attrs: null,
content: [],
ref: null,
model: null,
on: {},
on: null,
ns: null,
},
{
type: ASTType.DomNode,
tag: "div",
dynamicTag: null,
attrs: {},
attrs: null,
content: [],
ref: null,
model: null,
on: {},
on: null,
ns: null,
},
],
},
attrs: null,
on: null,
scope: null,
},
},
});
@@ -1347,8 +1376,11 @@ describe("qweb parser", () => {
name: "MyComponent",
isDynamic: false,
dynamicProps: null,
props: {},
slots: { name: { content: { type: ASTType.Text, value: "foo" } } },
props: null,
on: null,
slots: {
name: { content: { type: ASTType.Text, value: "foo" }, attrs: null, on: null, scope: null },
},
});
});
@@ -1358,8 +1390,37 @@ describe("qweb parser", () => {
name: "MyComponent",
isDynamic: false,
dynamicProps: null,
props: {},
slots: { name: { content: { type: ASTType.Text, value: "foo" }, attrs: { param: "param" } } },
props: null,
on: null,
slots: {
name: {
content: { type: ASTType.Text, value: "foo" },
attrs: { param: "param" },
on: null,
scope: null,
},
},
});
});
test("a component with a named slot with t-on", async () => {
expect(
parse(`<MyComponent><t t-set-slot="name" t-on-click="doStuff">foo</t></MyComponent>`)
).toEqual({
type: ASTType.TComponent,
name: "MyComponent",
isDynamic: false,
dynamicProps: null,
props: null,
on: null,
slots: {
name: {
content: { type: ASTType.Text, value: "foo" },
on: { click: "doStuff" },
attrs: null,
scope: null,
},
},
});
});
@@ -1374,11 +1435,17 @@ describe("qweb parser", () => {
type: ASTType.TComponent,
name: "MyComponent",
dynamicProps: null,
props: {},
props: null,
isDynamic: false,
on: null,
slots: {
default: { content: { type: ASTType.Text, value: " " } },
name: { content: { type: ASTType.Text, value: "foo" } },
default: {
content: { type: ASTType.Text, value: " " },
attrs: null,
on: null,
scope: null,
},
name: { content: { type: ASTType.Text, value: "foo" }, attrs: null, on: null, scope: null },
},
});
});
@@ -1393,11 +1460,12 @@ describe("qweb parser", () => {
type: ASTType.TComponent,
name: "MyComponent",
dynamicProps: null,
props: {},
props: null,
isDynamic: false,
on: null,
slots: {
a: { content: { type: ASTType.Text, value: "foo" } },
b: { content: { type: ASTType.Text, value: "bar" } },
a: { content: { type: ASTType.Text, value: "foo" }, attrs: null, on: null, scope: null },
b: { content: { type: ASTType.Text, value: "bar" }, attrs: null, on: null, scope: null },
},
});
});
@@ -1407,9 +1475,10 @@ describe("qweb parser", () => {
type: ASTType.TComponent,
name: "myComponent",
dynamicProps: null,
props: {},
props: null,
isDynamic: true,
slots: {},
on: null,
slots: null,
});
});
@@ -1420,7 +1489,8 @@ describe("qweb parser", () => {
dynamicProps: null,
props: { a: "1", b: "'b'" },
isDynamic: true,
slots: {},
on: null,
slots: null,
});
});
@@ -1431,7 +1501,8 @@ describe("qweb parser", () => {
dynamicProps: "state",
props: { a: "1" },
isDynamic: true,
slots: {},
on: null,
slots: null,
});
});
@@ -1452,9 +1523,17 @@ describe("qweb parser", () => {
type: ASTType.TComponent,
name: "MyComponent",
dynamicProps: null,
props: {},
props: null,
isDynamic: false,
slots: { default: { content: { body: null, name: "subTemplate", type: ASTType.TCall } } },
on: null,
slots: {
default: {
content: { body: null, name: "subTemplate", type: ASTType.TCall },
attrs: null,
scope: null,
on: null,
},
},
});
});
@@ -1470,17 +1549,29 @@ describe("qweb parser", () => {
type: ASTType.TComponent,
name: "MyComponent",
dynamicProps: null,
props: {},
props: null,
isDynamic: false,
on: null,
slots: {
default: {
attrs: null,
on: null,
scope: null,
content: {
type: ASTType.TComponent,
isDynamic: false,
name: "Child",
dynamicProps: null,
props: {},
slots: { brol: { content: { type: ASTType.Text, value: "coucou" } } },
props: null,
on: null,
slots: {
brol: {
content: { type: ASTType.Text, value: "coucou" },
attrs: null,
scope: null,
on: null,
},
},
},
},
},
@@ -1499,17 +1590,29 @@ describe("qweb parser", () => {
type: ASTType.TComponent,
name: "MyComponent",
dynamicProps: null,
props: {},
props: null,
isDynamic: false,
on: null,
slots: {
default: {
attrs: null,
on: null,
scope: null,
content: {
type: ASTType.TComponent,
isDynamic: false,
name: "Child",
dynamicProps: null,
props: {},
slots: { brol: { content: { type: ASTType.Text, value: "coucou" } } },
props: null,
on: null,
slots: {
brol: {
content: { type: ASTType.Text, value: "coucou" },
attrs: null,
on: null,
scope: null,
},
},
},
},
},
@@ -1524,7 +1627,8 @@ describe("qweb parser", () => {
expect(parse(`<t t-slot="default"/>`)).toEqual({
type: ASTType.TSlot,
name: "default",
attrs: {},
attrs: null,
on: null,
defaultContent: null,
});
});
@@ -1533,11 +1637,22 @@ describe("qweb parser", () => {
expect(parse(`<t t-slot="header">default content</t>`)).toEqual({
type: ASTType.TSlot,
name: "header",
attrs: {},
attrs: null,
on: null,
defaultContent: { type: ASTType.Text, value: "default content" },
});
});
test("t-slot with t-on-", async () => {
expect(parse(`<t t-slot="default" t-on-click.prevent="doSomething"/>`)).toEqual({
type: ASTType.TSlot,
name: "default",
attrs: null,
on: { "click.prevent": "doSomething" },
defaultContent: null,
});
});
// ---------------------------------------------------------------------------
// t-debug
// ---------------------------------------------------------------------------
@@ -1549,8 +1664,8 @@ describe("qweb parser", () => {
type: ASTType.DomNode,
tag: "div",
dynamicTag: null,
attrs: {},
on: {},
attrs: null,
on: null,
ref: null,
model: null,
ns: null,
@@ -1567,8 +1682,8 @@ describe("qweb parser", () => {
type: ASTType.DomNode,
tag: "div",
dynamicTag: null,
attrs: {},
on: {},
attrs: null,
on: null,
ref: null,
model: null,
ns: null,
@@ -1586,8 +1701,8 @@ describe("qweb parser", () => {
type: ASTType.DomNode,
tag: "div",
dynamicTag: null,
attrs: {},
on: {},
attrs: null,
on: null,
ref: "name",
model: null,
ns: null,
@@ -1600,8 +1715,8 @@ describe("qweb parser", () => {
type: ASTType.DomNode,
tag: "div",
dynamicTag: null,
attrs: {},
on: {},
attrs: null,
on: null,
ref: "name",
model: null,
ns: null,
@@ -1616,8 +1731,8 @@ describe("qweb parser", () => {
type: ASTType.DomNode,
tag: "div",
dynamicTag: null,
attrs: {},
on: {},
attrs: null,
on: null,
ref: "name",
model: null,
ns: null,
@@ -1652,14 +1767,14 @@ describe("qweb parser", () => {
).toEqual({
body: {
content: {
attrs: {},
attrs: null,
content: [
{
type: ASTType.Text,
value: "word",
},
],
on: {},
on: null,
ref: null,
model: null,
tag: "div",
@@ -1687,9 +1802,9 @@ describe("qweb parser", () => {
test("t-model", async () => {
expect(parse(`<input t-model="state.stuff" />`)).toEqual({
type: ASTType.DomNode,
attrs: {},
attrs: null,
content: [],
on: {},
on: null,
ref: null,
tag: "input",
dynamicTag: null,
@@ -1700,15 +1815,16 @@ describe("qweb parser", () => {
eventType: "input",
shouldNumberize: false,
shouldTrim: false,
hasDynamicChildren: false,
targetAttr: "value",
specialInitTargetAttr: null,
},
});
expect(parse(`<input t-model="state['stuff']" />`)).toEqual({
type: ASTType.DomNode,
attrs: {},
attrs: null,
content: [],
on: {},
on: null,
ref: null,
tag: "input",
dynamicTag: null,
@@ -1721,13 +1837,14 @@ describe("qweb parser", () => {
shouldTrim: false,
targetAttr: "value",
specialInitTargetAttr: null,
hasDynamicChildren: false,
},
});
expect(parse(`<input t-model.lazy.trim.number="state.stuff" />`)).toEqual({
type: ASTType.DomNode,
attrs: {},
attrs: null,
content: [],
on: {},
on: null,
ref: null,
tag: "input",
dynamicTag: null,
@@ -1739,15 +1856,16 @@ describe("qweb parser", () => {
shouldNumberize: true,
shouldTrim: true,
targetAttr: "value",
hasDynamicChildren: false,
specialInitTargetAttr: null,
},
});
});
expect(parse(`<textarea t-model="state.stuff" />`)).toEqual({
type: ASTType.DomNode,
attrs: {},
attrs: null,
content: [],
on: {},
on: null,
ref: null,
tag: "textarea",
dynamicTag: null,
@@ -1759,6 +1877,7 @@ describe("qweb parser", () => {
shouldNumberize: false,
shouldTrim: false,
targetAttr: "value",
hasDynamicChildren: false,
specialInitTargetAttr: null,
},
});
@@ -1766,7 +1885,7 @@ describe("qweb parser", () => {
type: ASTType.DomNode,
attrs: { type: "checkbox" },
content: [],
on: {},
on: null,
ref: null,
tag: "input",
dynamicTag: null,
@@ -1778,6 +1897,7 @@ describe("qweb parser", () => {
shouldNumberize: false,
shouldTrim: false,
targetAttr: "checked",
hasDynamicChildren: false,
specialInitTargetAttr: null,
},
});
@@ -1785,7 +1905,7 @@ describe("qweb parser", () => {
type: ASTType.DomNode,
attrs: { type: "radio" },
content: [],
on: {},
on: null,
ref: null,
tag: "input",
dynamicTag: null,
@@ -1797,6 +1917,7 @@ describe("qweb parser", () => {
shouldNumberize: false,
shouldTrim: false,
targetAttr: "value",
hasDynamicChildren: false,
specialInitTargetAttr: "checked",
},
});
@@ -1804,7 +1925,7 @@ describe("qweb parser", () => {
type: ASTType.DomNode,
attrs: { type: "radio" },
content: [],
on: {},
on: null,
ref: null,
tag: "input",
dynamicTag: null,
@@ -1816,6 +1937,7 @@ describe("qweb parser", () => {
shouldNumberize: false,
shouldTrim: false,
targetAttr: "value",
hasDynamicChildren: false,
specialInitTargetAttr: "checked",
},
});
@@ -1826,9 +1948,9 @@ describe("qweb parser", () => {
test("t-tag", async () => {
expect(parse(`<div t-tag="theTag" />`)).toEqual({
type: ASTType.DomNode,
attrs: {},
attrs: null,
content: [],
on: {},
on: null,
ref: null,
tag: "div",
dynamicTag: "theTag",
@@ -6,7 +6,7 @@ exports[`basics GrandChild display is controlled by its GrandParent 1`] = `
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
let Comp1 = ctx['myComp'];
const Comp1 = ctx['myComp'];
return toggler(Comp1, component(Comp1, {displayGrandChild: ctx['displayGrandChild']}, key + \`__1\`, node, ctx));
}
}"
@@ -49,9 +49,9 @@ exports[`basics Multi root component 1`] = `
let block4 = createBlock(\`<span>2</span>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = block2();
let b3 = text(\`text\`);
let b4 = block4();
const b2 = block2();
const b3 = text(\`text\`);
const b4 = block4();
return multi([b2, b3, b4]);
}
}"
@@ -102,7 +102,7 @@ exports[`basics a component inside a component 1`] = `
let block1 = createBlock(\`<span><block-child-0/></span>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
const b2 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -145,7 +145,7 @@ exports[`basics can handle empty props 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = component(\`Child\`, {val: undefined}, key + \`__1\`, node, ctx);
const b2 = component(\`Child\`, {val: undefined}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -236,8 +236,8 @@ exports[`basics can mount a simple component with multiple roots 1`] = `
let block3 = createBlock(\`<div/>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = block2();
let b3 = block3();
const b2 = block2();
const b3 = block3();
return multi([b2, b3]);
}
}"
@@ -477,15 +477,15 @@ exports[`basics list of two sub components inside other nodes 1`] = `
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['state'].blips);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['state'].blips);;
for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`blip\`] = v_block2[i1];
let key1 = ctx['blip'].id;
let b4 = component(\`SubWidget\`, {}, key + \`__1__\${key1}\`, node, ctx);
let b5 = component(\`SubWidget\`, {}, key + \`__2__\${key1}\`, node, ctx);
const key1 = ctx['blip'].id;
const b4 = component(\`SubWidget\`, {}, key + \`__1__\${key1}\`, node, ctx);
const b5 = component(\`SubWidget\`, {}, key + \`__2__\${key1}\`, node, ctx);
c_block2[i1] = withKey(block3([], [b4, b5]), key1);
}
let b2 = list(c_block2);
const b2 = list(c_block2);
return block1([], [b2]);
}
}"
@@ -560,9 +560,9 @@ exports[`basics reconciliation alg is not confused in some specific situation 1`
let block1 = createBlock(\`<div><block-child-0/><block-child-1/></div>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
const b2 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
const tKey_1 = 4;
let b3 = toggler(tKey_1, component(\`Child\`, {}, tKey_1 + key + \`__2\`, node, ctx));
const b3 = toggler(tKey_1, component(\`Child\`, {}, tKey_1 + key + \`__2\`, node, ctx));
return block1([], [b2, b3]);
}
}"
@@ -617,9 +617,9 @@ exports[`basics same t-keys in two different places 1`] = `
return function template(ctx, node, key = \\"\\") {
const tKey_1 = 1;
let b2 = toggler(tKey_1, component(\`Child\`, {blip: '1'}, tKey_1 + key + \`__1\`, node, ctx));
const b2 = toggler(tKey_1, component(\`Child\`, {blip: '1'}, tKey_1 + key + \`__1\`, node, ctx));
const tKey_2 = 1;
let b3 = toggler(tKey_2, component(\`Child\`, {blip: '2'}, tKey_2 + key + \`__2\`, node, ctx));
const b3 = toggler(tKey_2, component(\`Child\`, {blip: '2'}, tKey_2 + key + \`__2\`, node, ctx));
return block1([], [b2, b3]);
}
}"
@@ -952,8 +952,8 @@ exports[`basics two child components 1`] = `
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
let b2 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
let b3 = component(\`Child\`, {}, key + \`__2\`, node, ctx);
const b2 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
const b3 = component(\`Child\`, {}, key + \`__2\`, node, ctx);
return multi([b2, b3]);
}
}"
@@ -981,7 +981,7 @@ exports[`basics update props of component without concrete own node 1`] = `
return function template(ctx, node, key = \\"\\") {
const tKey_1 = ctx['childProps'].key;
let b2 = toggler(tKey_1, component(\`Child\`, Object.assign({}, ctx['childProps']), tKey_1 + key + \`__1\`, node, ctx));
const b2 = toggler(tKey_1, component(\`Child\`, Object.assign({}, ctx['childProps']), tKey_1 + key + \`__1\`, node, ctx));
return block1([], [b2]);
}
}"
@@ -1022,10 +1022,10 @@ exports[`basics updating a component with t-foreach as root 1`] = `
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
const [k_block1, v_block1, l_block1, c_block1] = prepareList(ctx['items']);
const [k_block1, v_block1, l_block1, c_block1] = prepareList(ctx['items']);;
for (let i1 = 0; i1 < l_block1; i1++) {
ctx[\`item\`] = v_block1[i1];
let key1 = ctx['item'];
const key1 = ctx['item'];
c_block1[i1] = withKey(text(ctx['item']), key1);
}
return list(c_block1);
@@ -1071,16 +1071,16 @@ exports[`basics widget after a t-foreach 1`] = `
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(Array(2));
const [k_block2, v_block2, l_block2, c_block2] = prepareList(Array(2));;
for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`elem\`] = v_block2[i1];
ctx[\`elem_index\`] = i1;
let key1 = ctx['elem_index'];
const key1 = ctx['elem_index'];
c_block2[i1] = withKey(text(\`txt\`), key1);
}
ctx = ctx.__proto__;
let b2 = list(c_block2);
let b4 = component(\`SomeComponent\`, {}, key + \`__1\`, node, ctx);
const b2 = list(c_block2);
const b4 = component(\`SomeComponent\`, {}, key + \`__1\`, node, ctx);
return block1([], [b2, b4]);
}
}"
@@ -1187,7 +1187,7 @@ exports[`support svg components add proper namespace to svg 1`] = `
let block1 = createBlock(\`<svg block-ns=\\"http://www.w3.org/2000/svg\\"><block-child-0/></svg>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = component(\`GComp\`, {}, key + \`__1\`, node, ctx);
const b2 = component(\`GComp\`, {}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -1216,15 +1216,15 @@ exports[`t-out in components can render list of t-out 1`] = `
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['state'].items);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['state'].items);;
for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`item\`] = v_block2[i1];
let key1 = ctx['item'];
let b4 = text(ctx['item']);
let b5 = safeOutput(ctx['item']);
const key1 = ctx['item'];
const b4 = text(ctx['item']);
const b5 = safeOutput(ctx['item']);
c_block2[i1] = withKey(multi([b4, b5]), key1);
}
let b2 = list(c_block2);
const b2 = list(c_block2);
return block1([], [b2]);
}
}"
@@ -1237,8 +1237,8 @@ exports[`t-out in components can switch the contents of two t-out repeatedly 1`]
let { safeOutput } = helpers;
return function template(ctx, node, key = \\"\\") {
let b2 = safeOutput(ctx['state'].a);
let b3 = safeOutput(ctx['state'].b);
const b2 = safeOutput(ctx['state'].a);
const b3 = safeOutput(ctx['state'].b);
return multi([b2, b3]);
}
}"
@@ -1253,7 +1253,7 @@ exports[`t-out in components update properly on state changes 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = safeOutput(ctx['state'].value);
const b2 = safeOutput(ctx['state'].value);
return block1([], [b2]);
}
}"
@@ -7,16 +7,16 @@ exports[`Cascading renders after microtaskTick 1`] = `
let { prepareList, withKey } = helpers;
return function template(ctx, node, key = \\"\\") {
let b2 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
let b3 = text(\` _ \`);
const b2 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
const b3 = text(\` _ \`);
ctx = Object.create(ctx);
const [k_block4, v_block4, l_block4, c_block4] = prepareList(ctx['state']);
const [k_block4, v_block4, l_block4, c_block4] = prepareList(ctx['state']);;
for (let i1 = 0; i1 < l_block4; i1++) {
ctx[\`elem\`] = v_block4[i1];
let key1 = ctx['elem'].id;
const key1 = ctx['elem'].id;
c_block4[i1] = withKey(text(ctx['elem'].id), key1);
}
let b4 = list(c_block4);
const b4 = list(c_block4);
return multi([b2, b3, b4]);
}
}"
@@ -30,10 +30,10 @@ exports[`Cascading renders after microtaskTick 2`] = `
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
const [k_block1, v_block1, l_block1, c_block1] = prepareList(ctx['state']);
const [k_block1, v_block1, l_block1, c_block1] = prepareList(ctx['state']);;
for (let i1 = 0; i1 < l_block1; i1++) {
ctx[\`elem\`] = v_block1[i1];
let key1 = ctx['elem'].id;
const key1 = ctx['elem'].id;
c_block1[i1] = withKey(component(\`Element\`, {id: ctx['elem'].id}, key + \`__1__\${key1}\`, node, ctx), key1);
}
return list(c_block1);
@@ -169,7 +169,7 @@ exports[`concurrent renderings scenario 1 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = component(\`ComponentB\`, {fromA: ctx['state'].fromA}, key + \`__1\`, node, ctx);
const b2 = component(\`ComponentB\`, {fromA: ctx['state'].fromA}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -183,7 +183,7 @@ exports[`concurrent renderings scenario 1 2`] = `
let block1 = createBlock(\`<p><block-child-0/></p>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = component(\`ComponentC\`, {fromA: ctx['props'].fromA, fromB: ctx['state'].fromB}, key + \`__1\`, node, ctx);
const b2 = component(\`ComponentC\`, {fromA: ctx['props'].fromA, fromB: ctx['state'].fromB}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -213,7 +213,7 @@ exports[`concurrent renderings scenario 2 1`] = `
return function template(ctx, node, key = \\"\\") {
let txt1 = ctx['state'].fromA;
let b2 = component(\`ComponentB\`, {fromA: ctx['state'].fromA}, key + \`__1\`, node, ctx);
const b2 = component(\`ComponentB\`, {fromA: ctx['state'].fromA}, key + \`__1\`, node, ctx);
return block1([txt1], [b2]);
}
}"
@@ -227,7 +227,7 @@ exports[`concurrent renderings scenario 2 2`] = `
let block1 = createBlock(\`<p><block-child-0/></p>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = component(\`ComponentC\`, {fromA: ctx['props'].fromA, fromB: ctx['state'].fromB}, key + \`__1\`, node, ctx);
const b2 = component(\`ComponentC\`, {fromA: ctx['props'].fromA, fromB: ctx['state'].fromB}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -256,7 +256,7 @@ exports[`concurrent renderings scenario 2bis 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = component(\`ComponentB\`, {fromA: ctx['state'].fromA}, key + \`__1\`, node, ctx);
const b2 = component(\`ComponentB\`, {fromA: ctx['state'].fromA}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -270,7 +270,7 @@ exports[`concurrent renderings scenario 2bis 2`] = `
let block1 = createBlock(\`<p><block-child-0/></p>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = component(\`ComponentC\`, {fromA: ctx['props'].fromA, fromB: ctx['state'].fromB}, key + \`__1\`, node, ctx);
const b2 = component(\`ComponentC\`, {fromA: ctx['props'].fromA, fromB: ctx['state'].fromB}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -299,7 +299,7 @@ exports[`concurrent renderings scenario 3 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = component(\`ComponentB\`, {fromA: ctx['state'].fromA}, key + \`__1\`, node, ctx);
const b2 = component(\`ComponentB\`, {fromA: ctx['state'].fromA}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -313,7 +313,7 @@ exports[`concurrent renderings scenario 3 2`] = `
let block1 = createBlock(\`<p><block-child-0/></p>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = component(\`ComponentC\`, {fromA: ctx['props'].fromA}, key + \`__1\`, node, ctx);
const b2 = component(\`ComponentC\`, {fromA: ctx['props'].fromA}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -327,7 +327,7 @@ exports[`concurrent renderings scenario 3 3`] = `
let block1 = createBlock(\`<span><block-child-0/></span>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = component(\`ComponentD\`, {fromA: ctx['props'].fromA, fromC: ctx['state'].fromC}, key + \`__1\`, node, ctx);
const b2 = component(\`ComponentD\`, {fromA: ctx['props'].fromA, fromC: ctx['state'].fromC}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -356,7 +356,7 @@ exports[`concurrent renderings scenario 4 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = component(\`ComponentB\`, {fromA: ctx['state'].fromA}, key + \`__1\`, node, ctx);
const b2 = component(\`ComponentB\`, {fromA: ctx['state'].fromA}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -370,7 +370,7 @@ exports[`concurrent renderings scenario 4 2`] = `
let block1 = createBlock(\`<p><block-child-0/></p>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = component(\`ComponentC\`, {fromA: ctx['props'].fromA}, key + \`__1\`, node, ctx);
const b2 = component(\`ComponentC\`, {fromA: ctx['props'].fromA}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -384,7 +384,7 @@ exports[`concurrent renderings scenario 4 3`] = `
let block1 = createBlock(\`<span><block-child-0/></span>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = component(\`ComponentD\`, {fromA: ctx['props'].fromA, fromC: ctx['state'].fromC}, key + \`__1\`, node, ctx);
const b2 = component(\`ComponentD\`, {fromA: ctx['props'].fromA, fromC: ctx['state'].fromC}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -413,7 +413,7 @@ exports[`concurrent renderings scenario 5 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = component(\`ComponentB\`, {fromA: ctx['state'].fromA}, key + \`__1\`, node, ctx);
const b2 = component(\`ComponentB\`, {fromA: ctx['state'].fromA}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -441,7 +441,7 @@ exports[`concurrent renderings scenario 6 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = component(\`ComponentB\`, {fromA: ctx['state'].fromA}, key + \`__1\`, node, ctx);
const b2 = component(\`ComponentB\`, {fromA: ctx['state'].fromA}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -469,7 +469,7 @@ exports[`concurrent renderings scenario 7 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = component(\`ComponentB\`, {fromA: ctx['state'].fromA}, key + \`__1\`, node, ctx);
const b2 = component(\`ComponentB\`, {fromA: ctx['state'].fromA}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -498,7 +498,7 @@ exports[`concurrent renderings scenario 8 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = component(\`ComponentB\`, {fromA: ctx['state'].fromA}, key + \`__1\`, node, ctx);
const b2 = component(\`ComponentB\`, {fromA: ctx['state'].fromA}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -528,8 +528,8 @@ exports[`concurrent renderings scenario 9 1`] = `
return function template(ctx, node, key = \\"\\") {
let txt1 = ctx['state'].fromA;
let b2 = component(\`ComponentB\`, {fromA: ctx['state'].fromA}, key + \`__1\`, node, ctx);
let b3 = component(\`ComponentC\`, {fromA: ctx['state'].fromA}, key + \`__2\`, node, ctx);
const b2 = component(\`ComponentB\`, {fromA: ctx['state'].fromA}, key + \`__1\`, node, ctx);
const b3 = component(\`ComponentC\`, {fromA: ctx['state'].fromA}, key + \`__2\`, node, ctx);
return block1([txt1], [b2, b3]);
}
}"
@@ -557,7 +557,7 @@ exports[`concurrent renderings scenario 9 3`] = `
let block1 = createBlock(\`<p><block-child-0/></p>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = component(\`ComponentD\`, {fromA: ctx['props'].fromA, fromC: ctx['state'].fromC}, key + \`__1\`, node, ctx);
const b2 = component(\`ComponentD\`, {fromA: ctx['props'].fromA, fromC: ctx['state'].fromC}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -586,7 +586,7 @@ exports[`concurrent renderings scenario 10 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = component(\`ComponentB\`, {value: ctx['state'].value}, key + \`__1\`, node, ctx);
const b2 = component(\`ComponentB\`, {value: ctx['state'].value}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -631,7 +631,7 @@ exports[`concurrent renderings scenario 11 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = component(\`Child\`, {val: ctx['state'].valA}, key + \`__1\`, node, ctx);
const b2 = component(\`Child\`, {val: ctx['state'].valA}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -660,7 +660,7 @@ exports[`concurrent renderings scenario 12 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = component(\`Child\`, {val: ctx['val']}, key + \`__1\`, node, ctx);
const b2 = component(\`Child\`, {val: ctx['val']}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -720,7 +720,7 @@ exports[`concurrent renderings scenario 14 1`] = `
let block1 = createBlock(\`<p><block-child-0/></p>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = component(\`B\`, {fromA: ctx['state'].fromA}, key + \`__1\`, node, ctx);
const b2 = component(\`B\`, {fromA: ctx['state'].fromA}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -734,7 +734,7 @@ exports[`concurrent renderings scenario 14 2`] = `
let block1 = createBlock(\`<p><block-child-0/></p>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = component(\`C\`, {fromB: ctx['state'].fromB, fromA: ctx['props'].fromA}, key + \`__1\`, node, ctx);
const b2 = component(\`C\`, {fromB: ctx['state'].fromB, fromA: ctx['props'].fromA}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -764,7 +764,7 @@ exports[`concurrent renderings scenario 15 1`] = `
let block1 = createBlock(\`<p><block-child-0/></p>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = component(\`B\`, {fromA: ctx['state'].fromA}, key + \`__1\`, node, ctx);
const b2 = component(\`B\`, {fromA: ctx['state'].fromA}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -778,7 +778,7 @@ exports[`concurrent renderings scenario 15 2`] = `
let block1 = createBlock(\`<p><block-child-0/></p>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = component(\`C\`, {fromB: ctx['state'].fromB, fromA: ctx['props'].fromA}, key + \`__1\`, node, ctx);
const b2 = component(\`C\`, {fromB: ctx['state'].fromB, fromA: ctx['props'].fromA}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -1008,9 +1008,9 @@ exports[`delay willUpdateProps 2`] = `
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
let b2 = text(ctx['props'].value);
let b3 = text(\`_\`);
let b4 = text(ctx['state'].int);
const b2 = text(ctx['props'].value);
const b3 = text(\`_\`);
const b4 = text(ctx['state'].int);
return multi([b2, b3, b4]);
}
}"
@@ -1033,8 +1033,8 @@ exports[`delay willUpdateProps with rendering grandchild 2`] = `
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
let b2 = component(\`DelayedChild\`, {value: ctx['props'].state.value}, key + \`__1\`, node, ctx);
let b3 = component(\`ReactiveChild\`, {}, key + \`__2\`, node, ctx);
const b2 = component(\`DelayedChild\`, {value: ctx['props'].state.value}, key + \`__1\`, node, ctx);
const b3 = component(\`ReactiveChild\`, {}, key + \`__2\`, node, ctx);
return multi([b2, b3]);
}
}"
@@ -1046,9 +1046,9 @@ exports[`delay willUpdateProps with rendering grandchild 3`] = `
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
let b2 = text(ctx['props'].value);
let b3 = text(\`_\`);
let b4 = text(ctx['state'].int);
const b2 = text(ctx['props'].value);
const b3 = text(\`_\`);
const b4 = text(ctx['state'].int);
return multi([b2, b3, b4]);
}
}"
@@ -1067,6 +1067,33 @@ exports[`delay willUpdateProps with rendering grandchild 4`] = `
}"
`;
exports[`destroying/recreating a subcomponent, other scenario 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
let b2,b3;
b2 = text(\`parent\`);
if (ctx['state'].hasChild) {
b3 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
}
return multi([b2, b3]);
}
}"
`;
exports[`destroying/recreating a subcomponent, other scenario 2`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
return text(\`child\`);
}
}"
`;
exports[`destroying/recreating a subwidget with different props (if start is not over) 1`] = `
"function anonymous(bdom, helpers
) {
@@ -1145,7 +1172,7 @@ exports[`properly behave when destroyed/unmounted while rendering 2`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = component(\`SubChild\`, {}, key + \`__1\`, node, ctx);
const b2 = component(\`SubChild\`, {val: ctx['props'].val}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -1195,6 +1222,28 @@ exports[`rendering component again in next microtick 2`] = `
}"
`;
exports[`rendering parent twice, with different props on child and stuff 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
return component(\`Child\`, {value: ctx['state'].value}, key + \`__1\`, node, ctx);
}
}"
`;
exports[`rendering parent twice, with different props on child and stuff 2`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
return text(ctx['props'].value);
}
}"
`;
exports[`t-foreach with dynamic async component 1`] = `
"function anonymous(bdom, helpers
) {
@@ -1203,14 +1252,14 @@ exports[`t-foreach with dynamic async component 1`] = `
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
const [k_block1, v_block1, l_block1, c_block1] = prepareList(ctx['list']);
const [k_block1, v_block1, l_block1, c_block1] = prepareList(ctx['list']);;
for (let i1 = 0; i1 < l_block1; i1++) {
ctx[\`arr\`] = v_block1[i1];
ctx[\`arr_index\`] = i1;
let key1 = ctx['arr_index'];
const key1 = ctx['arr_index'];
let b3;
if (ctx['arr']) {
let Comp1 = ctx['myComp'];
const Comp1 = ctx['myComp'];
b3 = toggler(Comp1, component(Comp1, {key: ctx['arr'][0]}, key + \`__1__\${key1}\`, node, ctx));
}
c_block1[i1] = withKey(multi([b3]), key1);
@@ -1243,8 +1292,8 @@ exports[`t-key on dom node having a component 1`] = `
return function template(ctx, node, key = \\"\\") {
const tKey_1 = ctx['key'];
let Comp1 = ctx['myComp'];
let b2 = toggler(tKey_1, toggler(Comp1, component(Comp1, {key: ctx['key']}, tKey_1 + key + \`__1\`, node, ctx)));
const Comp1 = ctx['myComp'];
const b2 = toggler(tKey_1, toggler(Comp1, component(Comp1, {key: ctx['key']}, tKey_1 + key + \`__1\`, node, ctx)));
return toggler(tKey_1, block1([], [b2]));
}
}"
@@ -1268,7 +1317,7 @@ exports[`t-key on dynamic async component (toggler is never patched) 1`] = `
return function template(ctx, node, key = \\"\\") {
const tKey_1 = ctx['key'];
let Comp1 = ctx['myComp'];
const Comp1 = ctx['myComp'];
return toggler(tKey_1, toggler(Comp1, component(Comp1, {key: ctx['key']}, tKey_1 + key + \`__1\`, node, ctx)));
}
}"
@@ -1351,7 +1400,7 @@ exports[`update a sub-component twice in the same frame 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = component(\`ChildA\`, {val: ctx['state'].valA}, key + \`__1\`, node, ctx);
const b2 = component(\`ChildA\`, {val: ctx['state'].valA}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -1379,7 +1428,7 @@ exports[`update a sub-component twice in the same frame, 2 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = component(\`ChildA\`, {val: ctx['state'].valA}, key + \`__1\`, node, ctx);
const b2 = component(\`ChildA\`, {val: ctx['state'].valA}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -32,7 +32,7 @@ exports[`basics no component catching error lead to full app destruction 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = component(\`ErrorComponent\`, {flag: ctx['state'].flag}, key + \`__1\`, node, ctx);
const b2 = component(\`ErrorComponent\`, {flag: ctx['state'].flag}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -100,6 +100,7 @@ exports[`can catch errors can catch an error in a component render function 1`]
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { markRaw } = helpers;
let block1 = createBlock(\`<div><block-child-0/></div>\`);
@@ -108,7 +109,7 @@ exports[`can catch errors can catch an error in a component render function 1`]
}
return function template(ctx, node, key = \\"\\") {
let b3 = component(\`ErrorBoundary\`, {slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__2\`, node, ctx);
const b3 = component(\`ErrorBoundary\`, {slots: markRaw({'default': {__render: slot1, __ctx: ctx}})}, key + \`__2\`, node, ctx);
return block1([], [b3]);
}
}"
@@ -127,7 +128,7 @@ exports[`can catch errors can catch an error in a component render function 2`]
if (ctx['state'].error) {
b2 = text(\`Error handled\`);
} else {
b3 = callSlot(ctx, node, key, 'default', false, {});
b3 = callSlot(ctx, node, key, 'default', false, null);
}
return block1([], [b2, b3]);
}
@@ -152,6 +153,7 @@ exports[`can catch errors can catch an error in the constructor call of a compon
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { markRaw } = helpers;
let block1 = createBlock(\`<div><block-child-0/></div>\`);
@@ -160,7 +162,7 @@ exports[`can catch errors can catch an error in the constructor call of a compon
}
return function template(ctx, node, key = \\"\\") {
let b3 = component(\`ErrorBoundary\`, {slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__2\`, node, ctx);
const b3 = component(\`ErrorBoundary\`, {slots: markRaw({'default': {__render: slot1, __ctx: ctx}})}, key + \`__2\`, node, ctx);
return block1([], [b3]);
}
}"
@@ -179,7 +181,7 @@ exports[`can catch errors can catch an error in the constructor call of a compon
if (ctx['state'].error) {
b2 = text(\`Error handled\`);
} else {
b3 = callSlot(ctx, node, key, 'default', false, {});
b3 = callSlot(ctx, node, key, 'default', false, null);
}
return block1([], [b2, b3]);
}
@@ -190,17 +192,18 @@ exports[`can catch errors can catch an error in the constructor call of a compon
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { markRaw } = helpers;
let block1 = createBlock(\`<div><block-child-0/></div>\`);
function slot1(ctx, node, key = \\"\\") {
let b3 = component(\`ClassicCompoent\`, {}, key + \`__1\`, node, ctx);
let b4 = component(\`ErrorComponent\`, {}, key + \`__2\`, node, ctx);
const b3 = component(\`ClassicCompoent\`, {}, key + \`__1\`, node, ctx);
const b4 = component(\`ErrorComponent\`, {}, key + \`__2\`, node, ctx);
return multi([b3, b4]);
}
return function template(ctx, node, key = \\"\\") {
let b5 = component(\`ErrorBoundary\`, {slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__3\`, node, ctx);
const b5 = component(\`ErrorBoundary\`, {slots: markRaw({'default': {__render: slot1, __ctx: ctx}})}, key + \`__3\`, node, ctx);
return block1([], [b5]);
}
}"
@@ -219,7 +222,7 @@ exports[`can catch errors can catch an error in the constructor call of a compon
if (ctx['state'].error) {
b2 = text(\`Error handled\`);
} else {
b3 = callSlot(ctx, node, key, 'default', false, {});
b3 = callSlot(ctx, node, key, 'default', false, null);
}
return block1([], [b2, b3]);
}
@@ -269,6 +272,7 @@ exports[`can catch errors can catch an error in the initial call of a component
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { markRaw } = helpers;
let block1 = createBlock(\`<div><block-child-0/></div>\`);
@@ -277,7 +281,7 @@ exports[`can catch errors can catch an error in the initial call of a component
}
return function template(ctx, node, key = \\"\\") {
let b3 = component(\`ErrorBoundary\`, {slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__2\`, node, ctx);
const b3 = component(\`ErrorBoundary\`, {slots: markRaw({'default': {__render: slot1, __ctx: ctx}})}, key + \`__2\`, node, ctx);
return block1([], [b3]);
}
}"
@@ -296,7 +300,7 @@ exports[`can catch errors can catch an error in the initial call of a component
if (ctx['state'].error) {
b2 = text(\`Error handled\`);
} else {
b3 = callSlot(ctx, node, key, 'default', false, {});
b3 = callSlot(ctx, node, key, 'default', false, null);
}
return block1([], [b2, b3]);
}
@@ -321,6 +325,7 @@ exports[`can catch errors can catch an error in the initial call of a component
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { markRaw } = helpers;
let block1 = createBlock(\`<div><block-child-0/></div>\`);
@@ -331,7 +336,7 @@ exports[`can catch errors can catch an error in the initial call of a component
return function template(ctx, node, key = \\"\\") {
let b3;
if (ctx['state'].flag) {
b3 = component(\`ErrorBoundary\`, {slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__2\`, node, ctx);
b3 = component(\`ErrorBoundary\`, {slots: markRaw({'default': {__render: slot1, __ctx: ctx}})}, key + \`__2\`, node, ctx);
}
return block1([], [b3]);
}
@@ -351,7 +356,7 @@ exports[`can catch errors can catch an error in the initial call of a component
if (ctx['state'].error) {
b2 = text(\`Error handled\`);
} else {
b3 = callSlot(ctx, node, key, 'default', false, {});
b3 = callSlot(ctx, node, key, 'default', false, null);
}
return block1([], [b2, b3]);
}
@@ -391,7 +396,7 @@ exports[`can catch errors can catch an error in the mounted call (in child of ch
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = component(\`C\`, {}, key + \`__1\`, node, ctx);
const b2 = component(\`C\`, {}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -465,6 +470,7 @@ exports[`can catch errors can catch an error in the mounted call 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { markRaw } = helpers;
let block1 = createBlock(\`<div><block-child-0/></div>\`);
@@ -473,7 +479,7 @@ exports[`can catch errors can catch an error in the mounted call 1`] = `
}
return function template(ctx, node, key = \\"\\") {
let b3 = component(\`ErrorBoundary\`, {slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__2\`, node, ctx);
const b3 = component(\`ErrorBoundary\`, {slots: markRaw({'default': {__render: slot1, __ctx: ctx}})}, key + \`__2\`, node, ctx);
return block1([], [b3]);
}
}"
@@ -492,7 +498,7 @@ exports[`can catch errors can catch an error in the mounted call 2`] = `
if (ctx['state'].error) {
b2 = text(\`Error handled\`);
} else {
b3 = callSlot(ctx, node, key, 'default', false, {});
b3 = callSlot(ctx, node, key, 'default', false, null);
}
return block1([], [b2, b3]);
}
@@ -516,6 +522,7 @@ exports[`can catch errors can catch an error in the willPatch call 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { markRaw } = helpers;
let block1 = createBlock(\`<div><span><block-text-0/></span><block-child-0/></div>\`);
@@ -525,7 +532,7 @@ exports[`can catch errors can catch an error in the willPatch call 1`] = `
return function template(ctx, node, key = \\"\\") {
let txt1 = ctx['state'].message;
let b3 = component(\`ErrorBoundary\`, {slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__2\`, node, ctx);
const b3 = component(\`ErrorBoundary\`, {slots: markRaw({'default': {__render: slot1, __ctx: ctx}})}, key + \`__2\`, node, ctx);
return block1([txt1], [b3]);
}
}"
@@ -544,7 +551,7 @@ exports[`can catch errors can catch an error in the willPatch call 2`] = `
if (ctx['state'].error) {
b2 = text(\`Error handled\`);
} else {
b3 = callSlot(ctx, node, key, 'default', false, {});
b3 = callSlot(ctx, node, key, 'default', false, null);
}
return block1([], [b2, b3]);
}
@@ -569,6 +576,7 @@ exports[`can catch errors can catch an error in the willStart call 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { markRaw } = helpers;
let block1 = createBlock(\`<div><block-child-0/></div>\`);
@@ -577,7 +585,7 @@ exports[`can catch errors can catch an error in the willStart call 1`] = `
}
return function template(ctx, node, key = \\"\\") {
let b3 = component(\`ErrorBoundary\`, {slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__2\`, node, ctx);
const b3 = component(\`ErrorBoundary\`, {slots: markRaw({'default': {__render: slot1, __ctx: ctx}})}, key + \`__2\`, node, ctx);
return block1([], [b3]);
}
}"
@@ -596,7 +604,7 @@ exports[`can catch errors can catch an error in the willStart call 2`] = `
if (ctx['state'].error) {
b2 = text(\`Error handled\`);
} else {
b3 = callSlot(ctx, node, key, 'default', false, {});
b3 = callSlot(ctx, node, key, 'default', false, null);
}
return block1([], [b2, b3]);
}
@@ -620,17 +628,18 @@ exports[`can catch errors can catch an error origination from a child's willStar
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { markRaw } = helpers;
let block1 = createBlock(\`<div><block-child-0/></div>\`);
function slot1(ctx, node, key = \\"\\") {
let b3 = component(\`ClassicCompoent\`, {}, key + \`__1\`, node, ctx);
let b4 = component(\`ErrorComponent\`, {}, key + \`__2\`, node, ctx);
const b3 = component(\`ClassicCompoent\`, {}, key + \`__1\`, node, ctx);
const b4 = component(\`ErrorComponent\`, {}, key + \`__2\`, node, ctx);
return multi([b3, b4]);
}
return function template(ctx, node, key = \\"\\") {
let b5 = component(\`ErrorBoundary\`, {slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__3\`, node, ctx);
const b5 = component(\`ErrorBoundary\`, {slots: markRaw({'default': {__render: slot1, __ctx: ctx}})}, key + \`__3\`, node, ctx);
return block1([], [b5]);
}
}"
@@ -649,7 +658,7 @@ exports[`can catch errors can catch an error origination from a child's willStar
if (ctx['state'].error) {
b2 = text(\`Error handled\`);
} else {
b3 = callSlot(ctx, node, key, 'default', false, {});
b3 = callSlot(ctx, node, key, 'default', false, null);
}
return block1([], [b2, b3]);
}
@@ -709,7 +718,7 @@ exports[`can catch errors catchError in catchError 2`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = component(\`Boom\`, {}, key + \`__1\`, node, ctx);
const b2 = component(\`Boom\`, {}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -733,22 +742,22 @@ exports[`can catch errors catching error, rethrow, render parent -- a main comp
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { prepareList, capture, withKey } = helpers;
let { prepareList, capture, markRaw, withKey } = helpers;
function slot1(ctx, node, key = \\"\\") {
let Comp1 = ctx['cp'].Comp;
const Comp1 = ctx['cp'].Comp;
return toggler(Comp1, component(Comp1, {}, key + \`__1\`, node, ctx));
}
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
const [k_block1, v_block1, l_block1, c_block1] = prepareList(Object.values(ctx['state'].cps));
const [k_block1, v_block1, l_block1, c_block1] = prepareList(Object.values(ctx['state'].cps));;
for (let i1 = 0; i1 < l_block1; i1++) {
ctx[\`cp\`] = v_block1[i1];
let key1 = ctx['cp'].id;
const key1 = ctx['cp'].id;
const v1 = ctx['cp'];
const ctx1 = capture(ctx);
c_block1[i1] = withKey(component(\`ErrorHandler\`, {onError: ()=>this.cleanUp(v1.id),slots: {'default': {__render: slot1, __ctx: ctx1}}}, key + \`__2__\${key1}\`, node, ctx), key1);
c_block1[i1] = withKey(component(\`ErrorHandler\`, {onError: ()=>this.cleanUp(v1.id),slots: markRaw({'default': {__render: slot1, __ctx: ctx1}})}, key + \`__2__\${key1}\`, node, ctx), key1);
}
return list(c_block1);
}
@@ -762,7 +771,7 @@ exports[`can catch errors catching error, rethrow, render parent -- a main comp
let { callSlot } = helpers;
return function template(ctx, node, key = \\"\\") {
return callSlot(ctx, node, key, 'default', false, {});
return callSlot(ctx, node, key, 'default', false, null);
}
}"
`;
@@ -808,22 +817,22 @@ exports[`can catch errors catching in child makes parent render 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { prepareList, capture, withKey } = helpers;
let { prepareList, capture, markRaw, withKey } = helpers;
function slot1(ctx, node, key = \\"\\") {
let Comp1 = ctx['elem'][1];
const Comp1 = ctx['elem'][1];
return toggler(Comp1, component(Comp1, {id: ctx['elem'][0]}, key + \`__1\`, node, ctx));
}
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
const [k_block1, v_block1, l_block1, c_block1] = prepareList(Object.entries(this.elements));
const [k_block1, v_block1, l_block1, c_block1] = prepareList(Object.entries(this.elements));;
for (let i1 = 0; i1 < l_block1; i1++) {
ctx[\`elem\`] = v_block1[i1];
let key1 = ctx['elem'][0];
const key1 = ctx['elem'][0];
const v1 = ctx['elem'];
const ctx1 = capture(ctx);
c_block1[i1] = withKey(component(\`Catch\`, {onError: (_error)=>this.onError(v1[0],_error),slots: {'default': {__render: slot1, __ctx: ctx1}}}, key + \`__2__\${key1}\`, node, ctx), key1);
c_block1[i1] = withKey(component(\`Catch\`, {onError: (_error)=>this.onError(v1[0],_error),slots: markRaw({'default': {__render: slot1, __ctx: ctx1}})}, key + \`__2__\${key1}\`, node, ctx), key1);
}
return list(c_block1);
}
@@ -837,7 +846,7 @@ exports[`can catch errors catching in child makes parent render 2`] = `
let { callSlot } = helpers;
return function template(ctx, node, key = \\"\\") {
return callSlot(ctx, node, key, 'default', false, {});
return callSlot(ctx, node, key, 'default', false, null);
}
}"
`;
@@ -873,6 +882,7 @@ exports[`can catch errors error in mounted on a component with a sibling (proper
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { markRaw } = helpers;
let block1 = createBlock(\`<div><block-child-0/><block-child-1/></div>\`);
@@ -881,8 +891,8 @@ exports[`can catch errors error in mounted on a component with a sibling (proper
}
return function template(ctx, node, key = \\"\\") {
let b2 = component(\`OK\`, {}, key + \`__1\`, node, ctx);
let b4 = component(\`ErrorBoundary\`, {slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__3\`, node, ctx);
const b2 = component(\`OK\`, {}, key + \`__1\`, node, ctx);
const b4 = component(\`ErrorBoundary\`, {slots: markRaw({'default': {__render: slot1, __ctx: ctx}})}, key + \`__3\`, node, ctx);
return block1([], [b2, b4]);
}
}"
@@ -912,7 +922,7 @@ exports[`can catch errors error in mounted on a component with a sibling (proper
if (ctx['state'].error) {
b2 = text(\`Error handled\`);
} else {
b3 = callSlot(ctx, node, key, 'default', false, {});
b3 = callSlot(ctx, node, key, 'default', false, null);
}
return block1([], [b2, b3]);
}
@@ -1000,7 +1010,7 @@ exports[`errors and promises a rendering error in a sub component will reject th
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
const b2 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -1042,7 +1052,7 @@ exports[`errors and promises a rendering error will reject the render promise (w
let block1 = createBlock(\`<div><block-child-0/><block-text-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
const b2 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
let txt1 = ctx['x'].y;
return block1([txt1], [b2]);
}
@@ -1092,6 +1102,19 @@ exports[`errors and promises an error in mounted call will reject the mount prom
}"
`;
exports[`errors and promises an error in onMounted callback will have the component's setup in its stack trace 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let block1 = createBlock(\`<div>abc</div>\`);
return function template(ctx, node, key = \\"\\") {
return block1();
}
}"
`;
exports[`errors and promises an error in patched call will reject the render promise 1`] = `
"function anonymous(bdom, helpers
) {
@@ -1133,6 +1156,19 @@ exports[`errors and promises errors in mounted and in willUnmount 1`] = `
}"
`;
exports[`errors and promises errors in onWillRender/onRender aren't wrapped more than once 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let block1 = createBlock(\`<div>abc</div>\`);
return function template(ctx, node, key = \\"\\") {
return block1();
}
}"
`;
exports[`errors and promises errors in rerender 1`] = `
"function anonymous(bdom, helpers
) {
@@ -37,7 +37,7 @@ exports[`event handling handler receive the event as argument 1`] = `
return function template(ctx, node, key = \\"\\") {
let hdlr1 = [ctx['inc'], ctx];
let b2 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
const b2 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
let txt1 = ctx['state'].value;
return block1([hdlr1, txt1], [b2]);
}
@@ -99,16 +99,16 @@ exports[`event handling objects from scope are properly captured by t-on 1`] = `
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['items']);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['items']);;
for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`item\`] = v_block2[i1];
let key1 = ctx['item'];
const key1 = ctx['item'];
const v1 = ctx['onClick'];
const v2 = ctx['item'];
let hdlr1 = [_ev=>v1(v2.val,_ev), ctx];
c_block2[i1] = withKey(block3([hdlr1]), key1);
}
let b2 = list(c_block2);
const b2 = list(c_block2);
return block1([], [b2]);
}
}"
@@ -140,16 +140,16 @@ exports[`event handling t-on with handler bound to dynamic argument on a t-forea
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['items']);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['items']);;
for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`item\`] = v_block2[i1];
let key1 = ctx['item'];
const key1 = ctx['item'];
const v1 = ctx['onClick'];
const v2 = ctx['item'];
let hdlr1 = [_ev=>v1(v2,_ev), ctx];
c_block2[i1] = withKey(block3([hdlr1]), key1);
}
let b2 = list(c_block2);
const b2 = list(c_block2);
return block1([], [b2]);
}
}"
@@ -147,7 +147,7 @@ exports[`basics top level sub widget with a parent 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = component(\`ComponentB\`, {}, key + \`__1\`, node, ctx);
const b2 = component(\`ComponentB\`, {}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -109,8 +109,8 @@ exports[`hooks parent and child env (with useChildSubEnv then useSubEnv) 1`] = `
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
let b2 = text(ctx['env'].val);
let b3 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
const b2 = text(ctx['env'].val);
const b3 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
return multi([b2, b3]);
}
}"
@@ -140,8 +140,8 @@ exports[`hooks parent and child env (with useChildSubEnv) 1`] = `
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
let b2 = text(ctx['env'].val);
let b3 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
const b2 = text(ctx['env'].val);
const b3 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
return multi([b2, b3]);
}
}"
@@ -167,8 +167,8 @@ exports[`hooks parent and child env (with useSubEnv) 1`] = `
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
let b2 = text(ctx['env'].val);
let b3 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
const b2 = text(ctx['env'].val);
const b3 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
return multi([b2, b3]);
}
}"
@@ -21,8 +21,8 @@ exports[`lifecycle hooks component semantics 1`] = `
let block1 = createBlock(\`<div>A<block-child-0/><block-child-1/></div>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = component(\`B\`, {}, key + \`__1\`, node, ctx);
let b3 = component(\`C\`, {}, key + \`__2\`, node, ctx);
const b2 = component(\`B\`, {}, key + \`__1\`, node, ctx);
const b3 = component(\`C\`, {}, key + \`__2\`, node, ctx);
return block1([], [b2, b3]);
}
}"
@@ -110,7 +110,7 @@ exports[`lifecycle hooks components are unmounted and destroyed if no longer in
return function template(ctx, node, key = \\"\\") {
let b2;
if (ctx['state'].flag) {
let b3 = component(\`Child\`, {n: ctx['state'].n}, key + \`__1\`, node, ctx);
const b3 = component(\`Child\`, {n: ctx['state'].n}, key + \`__1\`, node, ctx);
b2 = block2([], [b3]);
}
return multi([b2]);
@@ -196,7 +196,7 @@ exports[`lifecycle hooks hooks are called in proper order in widget creation/des
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
const b2 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -245,7 +245,7 @@ exports[`lifecycle hooks lifecycle semantics 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = component(\`Child\`, {a: ctx['state'].a}, key + \`__1\`, node, ctx);
const b2 = component(\`Child\`, {a: ctx['state'].a}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -458,7 +458,7 @@ exports[`lifecycle hooks mounted hook is called on subcomponents, in proper orde
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
const b2 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -502,7 +502,7 @@ exports[`lifecycle hooks mounted hook is called on subsubcomponents, in proper o
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = component(\`ChildChild\`, {}, key + \`__1\`, node, ctx);
const b2 = component(\`ChildChild\`, {}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -527,7 +527,7 @@ exports[`lifecycle hooks onWillRender 1`] = `
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
return component(\`Child\`, {}, key + \`__1\`, node, ctx);
return component(\`Child\`, {someValue: ctx['state'].value}, key + \`__1\`, node, ctx);
}
}"
`;
@@ -555,7 +555,7 @@ exports[`lifecycle hooks patched hook is called after updateProps 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = component(\`Child\`, {a: ctx['state'].a}, key + \`__1\`, node, ctx);
const b2 = component(\`Child\`, {a: ctx['state'].a}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -666,7 +666,7 @@ exports[`lifecycle hooks willPatch, patched hook are called on subsubcomponents,
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = component(\`Child\`, {n: ctx['state'].n}, key + \`__1\`, node, ctx);
const b2 = component(\`Child\`, {n: ctx['state'].n}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -680,7 +680,7 @@ exports[`lifecycle hooks willPatch, patched hook are called on subsubcomponents,
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = component(\`ChildChild\`, {n: ctx['props'].n}, key + \`__1\`, node, ctx);
const b2 = component(\`ChildChild\`, {n: ctx['props'].n}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -8,7 +8,7 @@ exports[`basics accept ES6-like syntax for props (with getters) 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = component(\`Child\`, {greetings: ctx['greetings']}, key + \`__1\`, node, ctx);
const b2 = component(\`Child\`, {greetings: ctx['greetings']}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -36,10 +36,10 @@ exports[`basics arrow functions as prop correctly capture their scope 1`] = `
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
const [k_block1, v_block1, l_block1, c_block1] = prepareList(ctx['items']);
const [k_block1, v_block1, l_block1, c_block1] = prepareList(ctx['items']);;
for (let i1 = 0; i1 < l_block1; i1++) {
ctx[\`item\`] = v_block1[i1];
let key1 = ctx['item'].val;
const key1 = ctx['item'].val;
const v1 = ctx['onClick'];
const v2 = ctx['item'];
c_block1[i1] = withKey(component(\`Child\`, {onClick: _ev=>v1(v2.val,_ev)}, key + \`__1__\${key1}\`, node, ctx), key1);
@@ -71,7 +71,7 @@ exports[`basics explicit object prop 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = component(\`Child\`, {value: ctx['state'].val}, key + \`__1\`, node, ctx);
const b2 = component(\`Child\`, {value: ctx['state'].val}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -158,7 +158,7 @@ exports[`basics t-set with a body expression can be passed in props, and then t-
ctx = Object.create(ctx);
ctx[isBoundary] = 1
ctx[\`abc\`] = new LazyValue(value1, ctx, node);
let b3 = component(\`Child\`, {val: ctx['abc']}, key + \`__1\`, node, ctx);
const b3 = component(\`Child\`, {val: ctx['abc']}, key + \`__1\`, node, ctx);
return block1([], [b3]);
}
}"
@@ -174,7 +174,7 @@ exports[`basics t-set with a body expression can be passed in props, and then t-
return function template(ctx, node, key = \\"\\") {
let txt1 = ctx['props'].val;
let b2 = safeOutput(ctx['props'].val);
const b2 = safeOutput(ctx['props'].val);
return block1([txt1], [b2]);
}
}"
@@ -192,7 +192,7 @@ exports[`basics t-set with a body expression can be used as textual prop 1`] = `
ctx = Object.create(ctx);
ctx[isBoundary] = 1
setContextValue(ctx, \\"abc\\", \`42\`);
let b2 = component(\`Child\`, {val: ctx['abc']}, key + \`__1\`, node, ctx);
const b2 = component(\`Child\`, {val: ctx['abc']}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -224,7 +224,7 @@ exports[`basics t-set works 1`] = `
ctx = Object.create(ctx);
ctx[isBoundary] = 1
setContextValue(ctx, \\"val\\", 42);
let b2 = component(\`Child\`, {val: ctx['val']}, key + \`__1\`, node, ctx);
const b2 = component(\`Child\`, {val: ctx['val']}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -23,7 +23,7 @@ exports[`default props can set default boolean values 1`] = `
return function template(ctx, node, key = \\"\\") {
const props1 = {};
helpers.validateProps(\`SubComp\`, props1, ctx);
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -59,7 +59,7 @@ exports[`default props can set default values 1`] = `
return function template(ctx, node, key = \\"\\") {
const props1 = {};
helpers.validateProps(\`SubComp\`, props1, ctx);
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -89,7 +89,7 @@ exports[`default props default values are also set whenever component is updated
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['state'].p};
helpers.validateProps(\`SubComp\`, props1, ctx);
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -171,7 +171,7 @@ exports[`props validation can validate a prop with multiple types 1`] = `
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -200,7 +200,7 @@ exports[`props validation can validate a prop with multiple types 3`] = `
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -229,7 +229,7 @@ exports[`props validation can validate a prop with multiple types 5`] = `
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -245,7 +245,7 @@ exports[`props validation can validate an array with given primitive type 1`] =
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -274,7 +274,7 @@ exports[`props validation can validate an array with given primitive type 3`] =
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -303,7 +303,7 @@ exports[`props validation can validate an array with given primitive type 5`] =
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -319,7 +319,7 @@ exports[`props validation can validate an array with given primitive type 6`] =
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -335,7 +335,7 @@ exports[`props validation can validate an array with multiple sub element types
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -364,7 +364,7 @@ exports[`props validation can validate an array with multiple sub element types
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -393,7 +393,7 @@ exports[`props validation can validate an array with multiple sub element types
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -422,7 +422,7 @@ exports[`props validation can validate an array with multiple sub element types
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -438,7 +438,7 @@ exports[`props validation can validate an object with simple shape 1`] = `
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -467,7 +467,7 @@ exports[`props validation can validate an object with simple shape 3`] = `
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -483,7 +483,7 @@ exports[`props validation can validate an object with simple shape 4`] = `
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -499,7 +499,7 @@ exports[`props validation can validate an object with simple shape 5`] = `
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -515,7 +515,7 @@ exports[`props validation can validate an optional props 1`] = `
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -544,7 +544,7 @@ exports[`props validation can validate an optional props 3`] = `
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -573,7 +573,7 @@ exports[`props validation can validate an optional props 5`] = `
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -589,7 +589,7 @@ exports[`props validation can validate recursively complicated prop def 1`] = `
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -618,7 +618,7 @@ exports[`props validation can validate recursively complicated prop def 3`] = `
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -647,7 +647,7 @@ exports[`props validation can validate recursively complicated prop def 5`] = `
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -663,7 +663,7 @@ exports[`props validation default values are applied before validating props at
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['state'].p};
helpers.validateProps(\`SubComp\`, props1, ctx);
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -693,7 +693,7 @@ exports[`props validation missing required boolean prop causes an error 1`] = `
return function template(ctx, node, key = \\"\\") {
const props1 = {};
helpers.validateProps(\`SubComp\`, props1, ctx);
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -709,7 +709,7 @@ exports[`props validation mix of optional and mandatory 1`] = `
return function template(ctx, node, key = \\"\\") {
const props1 = {};
helpers.validateProps(\`Child\`, props1, ctx);
let b2 = component(\`Child\`, props1, key + \`__1\`, node, ctx);
const b2 = component(\`Child\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -725,7 +725,7 @@ exports[`props validation props are validated in dev mode (code snapshot) 1`] =
return function template(ctx, node, key = \\"\\") {
const props1 = {message: 1};
helpers.validateProps(\`Child\`, props1, ctx);
let b2 = component(\`Child\`, props1, key + \`__1\`, node, ctx);
const b2 = component(\`Child\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -755,7 +755,7 @@ exports[`props validation props are validated whenever component is updated 1`]
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['state'].p};
helpers.validateProps(\`SubComp\`, props1, ctx);
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -785,7 +785,7 @@ exports[`props validation props: list of strings 1`] = `
return function template(ctx, node, key = \\"\\") {
const props1 = {};
helpers.validateProps(\`SubComp\`, props1, ctx);
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -801,7 +801,7 @@ exports[`props validation validate simple types 1`] = `
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -817,7 +817,7 @@ exports[`props validation validate simple types 2`] = `
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -846,7 +846,7 @@ exports[`props validation validate simple types 4`] = `
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -862,7 +862,7 @@ exports[`props validation validate simple types 5`] = `
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -878,7 +878,7 @@ exports[`props validation validate simple types 6`] = `
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -907,7 +907,7 @@ exports[`props validation validate simple types 8`] = `
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -923,7 +923,7 @@ exports[`props validation validate simple types 9`] = `
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -939,7 +939,7 @@ exports[`props validation validate simple types 10`] = `
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -968,7 +968,7 @@ exports[`props validation validate simple types 12`] = `
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -984,7 +984,7 @@ exports[`props validation validate simple types 13`] = `
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -1000,7 +1000,7 @@ exports[`props validation validate simple types 14`] = `
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -1029,7 +1029,7 @@ exports[`props validation validate simple types 16`] = `
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -1045,7 +1045,7 @@ exports[`props validation validate simple types 17`] = `
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -1061,7 +1061,7 @@ exports[`props validation validate simple types 18`] = `
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -1090,7 +1090,7 @@ exports[`props validation validate simple types 20`] = `
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -1106,7 +1106,7 @@ exports[`props validation validate simple types 21`] = `
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -1122,7 +1122,7 @@ exports[`props validation validate simple types 22`] = `
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -1151,7 +1151,7 @@ exports[`props validation validate simple types 24`] = `
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -1167,7 +1167,7 @@ exports[`props validation validate simple types, alternate form 1`] = `
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -1183,7 +1183,7 @@ exports[`props validation validate simple types, alternate form 2`] = `
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -1212,7 +1212,7 @@ exports[`props validation validate simple types, alternate form 4`] = `
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -1228,7 +1228,7 @@ exports[`props validation validate simple types, alternate form 5`] = `
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -1244,7 +1244,7 @@ exports[`props validation validate simple types, alternate form 6`] = `
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -1273,7 +1273,7 @@ exports[`props validation validate simple types, alternate form 8`] = `
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -1289,7 +1289,7 @@ exports[`props validation validate simple types, alternate form 9`] = `
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -1305,7 +1305,7 @@ exports[`props validation validate simple types, alternate form 10`] = `
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -1334,7 +1334,7 @@ exports[`props validation validate simple types, alternate form 12`] = `
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -1350,7 +1350,7 @@ exports[`props validation validate simple types, alternate form 13`] = `
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -1366,7 +1366,7 @@ exports[`props validation validate simple types, alternate form 14`] = `
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -1395,7 +1395,7 @@ exports[`props validation validate simple types, alternate form 16`] = `
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -1411,7 +1411,7 @@ exports[`props validation validate simple types, alternate form 17`] = `
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -1427,7 +1427,7 @@ exports[`props validation validate simple types, alternate form 18`] = `
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -1456,7 +1456,7 @@ exports[`props validation validate simple types, alternate form 20`] = `
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -1472,7 +1472,7 @@ exports[`props validation validate simple types, alternate form 21`] = `
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -1488,7 +1488,7 @@ exports[`props validation validate simple types, alternate form 22`] = `
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -1517,7 +1517,7 @@ exports[`props validation validate simple types, alternate form 24`] = `
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -1533,7 +1533,7 @@ exports[`props validation validation is only done in dev mode 1`] = `
return function template(ctx, node, key = \\"\\") {
const props1 = {};
helpers.validateProps(\`SubComp\`, props1, ctx);
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -1547,7 +1547,7 @@ exports[`props validation validation is only done in dev mode 2`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = component(\`SubComp\`, {}, key + \`__1\`, node, ctx);
const b2 = component(\`SubComp\`, {}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -28,6 +28,20 @@ exports[`reactivity in lifecycle can use a state hook 2 1`] = `
}"
`;
exports[`reactivity in lifecycle can use a state hook on Map 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let block1 = createBlock(\`<div><block-text-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
let txt1 = ctx['counter'].get('value');
return block1([txt1]);
}
}"
`;
exports[`reactivity in lifecycle change state while mounting component 1`] = `
"function anonymous(bdom, helpers
) {
@@ -62,7 +62,7 @@ exports[`refs refs are properly bound in slots 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { capture } = helpers;
let { capture, markRaw } = helpers;
let block1 = createBlock(\`<div><span class=\\"counter\\"><block-text-0/></span><block-child-0/></div>\`);
let block2 = createBlock(\`<button block-handler-0=\\"click\\" block-ref=\\"1\\">do something</button>\`);
@@ -77,7 +77,7 @@ exports[`refs refs are properly bound in slots 1`] = `
return function template(ctx, node, key = \\"\\") {
let txt1 = ctx['state'].val;
const ctx1 = capture(ctx);
let b3 = component(\`Dialog\`, {slots: {'footer': {__render: slot1, __ctx: ctx1}}}, key + \`__1\`, node, ctx);
const b3 = component(\`Dialog\`, {slots: markRaw({'footer': {__render: slot1, __ctx: ctx1}})}, key + \`__1\`, node, ctx);
return block1([txt1], [b3]);
}
}"
@@ -92,7 +92,7 @@ exports[`refs refs are properly bound in slots 2`] = `
let block1 = createBlock(\`<span><block-child-0/></span>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = callSlot(ctx, node, key, 'footer', false, {});
const b2 = callSlot(ctx, node, key, 'footer', false, null);
return block1([], [b2]);
}
}"
@@ -110,8 +110,8 @@ exports[`refs throws if there are 2 same refs at the same time 1`] = `
return function template(ctx, node, key = \\"\\") {
const refs = ctx.__owl__.refs;
const ref1 = multiRefSetter(refs, \`coucou\`);
let b2 = block2([ref1]);
let b3 = block3([ref1]);
const b2 = block2([ref1]);
const b3 = block3([ref1]);
return multi([b2, b3]);
}
}"
@@ -0,0 +1,212 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`force render in case of existing render 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
return component(\`B\`, {val: ctx['state'].val}, key + \`__1\`, node, ctx);
}
}"
`;
exports[`force render in case of existing render 2`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
const b2 = component(\`C\`, {}, key + \`__1\`, node, ctx);
const b3 = text(ctx['props'].val);
return multi([b2, b3]);
}
}"
`;
exports[`force render in case of existing render 3`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
return text(\`C\`);
}
}"
`;
exports[`rendering semantics can force a render to update sub tree 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
const b2 = text(ctx['state'].value);
const b3 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
return multi([b2, b3]);
}
}"
`;
exports[`rendering semantics can force a render to update sub tree 2`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
return text(\`child\`);
}
}"
`;
exports[`rendering semantics can render a parent without rendering child 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
const b2 = text(ctx['state'].value);
const b3 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
return multi([b2, b3]);
}
}"
`;
exports[`rendering semantics can render a parent without rendering child 2`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
return text(\`child\`);
}
}"
`;
exports[`rendering semantics props are reactive (nested prop) 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
return component(\`Child\`, {a: ctx['state']}, key + \`__1\`, node, ctx);
}
}"
`;
exports[`rendering semantics props are reactive (nested prop) 2`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
return text(ctx['props'].a.b.c);
}
}"
`;
exports[`rendering semantics props are reactive 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
return component(\`Child\`, {a: ctx['state']}, key + \`__1\`, node, ctx);
}
}"
`;
exports[`rendering semantics props are reactive 2`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
return text(ctx['props'].a.b);
}
}"
`;
exports[`rendering semantics render with deep=true followed by render with deep=false work as expected 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
const b2 = text(\`parent\`);
const b3 = text(ctx['state'].value);
const b4 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
return multi([b2, b3, b4]);
}
}"
`;
exports[`rendering semantics render with deep=true followed by render with deep=false work as expected 2`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
const b2 = text(\`child\`);
const b3 = text(ctx['env'].getValue());
return multi([b2, b3]);
}
}"
`;
exports[`rendering semantics rendering is atomic (for one subtree) 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
const b2 = text(ctx['state'].obj.val);
const b3 = component(\`B\`, {obj: ctx['state'].obj}, key + \`__1\`, node, ctx);
return multi([b2, b3]);
}
}"
`;
exports[`rendering semantics rendering is atomic (for one subtree) 2`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
return component(\`C\`, {obj: ctx['props'].obj}, key + \`__1\`, node, ctx);
}
}"
`;
exports[`rendering semantics rendering is atomic (for one subtree) 3`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
return text(ctx['props'].obj.val);
}
}"
`;
exports[`rendering semantics works as expected for dynamic number of props 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
return component(\`Child\`, Object.assign({}, ctx['state']), key + \`__1\`, node, ctx);
}
}"
`;
exports[`rendering semantics works as expected for dynamic number of props 2`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
return text(Object.keys(ctx['props']).length);
}
}"
`;
File diff suppressed because it is too large Load Diff
@@ -20,9 +20,9 @@ exports[`style and class handling can set class on multi root component 2`] = `
let block3 = createBlock(\`<span block-attribute-0=\\"class\\">b</span>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = block2();
const b2 = block2();
let attr1 = ctx['props'].class;
let b3 = block3([attr1]);
const b3 = block3([attr1]);
return multi([b2, b3]);
}
}"
@@ -205,7 +205,7 @@ exports[`style and class handling class with extra whitespaces (variation) 1`] =
let block1 = createBlock(\`<p><block-child-0/></p>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = component(\`Child\`, {class: 'a b c d'}, key + \`__1\`, node, ctx);
const b2 = component(\`Child\`, {class: 'a b c d'}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -310,7 +310,7 @@ exports[`style and class handling empty class attribute is not added on widget r
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = component(\`Child\`, {class: undefined}, key + \`__1\`, node, ctx);
const b2 = component(\`Child\`, {class: undefined}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -438,7 +438,7 @@ exports[`style and class handling t-att-class is properly added/removed on widge
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = component(\`Child\`, {class: {b:ctx['state'].b}}, key + \`__1\`, node, ctx);
const b2 = component(\`Child\`, {class: {b:ctx['state'].b}}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -9,7 +9,7 @@ exports[`t-call dynamic t-call 1`] = `
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
ctx[isBoundary] = 1;
let b1 = text(\` owl \`);
const b1 = text(\` owl \`);
ctx[zero] = b1;
const template1 = (ctx['current'].template);
return call(this, template1, ctx, node, key + \`__1\`);
@@ -48,9 +48,9 @@ exports[`t-call dynamic t-call: key is propagated 1`] = `
let { call } = helpers;
return function template(ctx, node, key = \\"\\") {
let b2 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
const b2 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
const template1 = (ctx['sub']);
let b3 = call(this, template1, ctx, node, key + \`__2\`);
const b3 = call(this, template1, ctx, node, key + \`__2\`);
return multi([b2, b3]);
}
}"
@@ -91,7 +91,7 @@ exports[`t-call handlers are properly bound through a dynamic t-call 1`] = `
return function template(ctx, node, key = \\"\\") {
const template1 = ('__template__999');
let b2 = call(this, template1, ctx, node, key + \`__1\`);
const b2 = call(this, template1, ctx, node, key + \`__1\`);
let txt1 = ctx['counter'];
return block1([txt1], [b2]);
}
@@ -122,7 +122,7 @@ exports[`t-call handlers are properly bound through a t-call 1`] = `
let block1 = createBlock(\`<div><block-child-0/><block-text-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
const b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
let txt1 = ctx['counter'];
return block1([txt1], [b2]);
}
@@ -153,7 +153,7 @@ exports[`t-call handlers with arguments are properly bound through a t-call 1`]
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
const b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
return block1([], [b2]);
}
}"
@@ -184,7 +184,7 @@ exports[`t-call parent is set within t-call 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
const b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
return block1([], [b2]);
}
}"
@@ -266,7 +266,7 @@ exports[`t-call recursive t-call binding this -- static t-call 1`] = `
ctx = Object.create(ctx);
ctx[isBoundary] = 1;
setContextValue(ctx, \\"level\\", 0);
let b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
const b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
return block1([], [b2]);
}
}"
@@ -288,11 +288,11 @@ exports[`t-call recursive t-call binding this -- static t-call 2`] = `
if (ctx['level']<2) {
let hdlr1 = [\\"stop\\", ctx['onClicked'].bind(this), ctx];
let txt1 = ctx['level'];
let b3 = block3([hdlr1, txt1]);
const b3 = block3([hdlr1, txt1]);
ctx = Object.create(ctx);
ctx[isBoundary] = 1;
setContextValue(ctx, \\"level\\", ctx['level']+1);
let b4 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
const b4 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
ctx = ctx.__proto__;
b2 = multi([b3, b4]);
}
@@ -316,7 +316,7 @@ exports[`t-call sub components in two t-calls 1`] = `
if (ctx['state'].val===1) {
b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
} else {
let b4 = callTemplate_2.call(this, ctx, node, key + \`__2\`);
const b4 = callTemplate_2.call(this, ctx, node, key + \`__2\`);
b3 = block3([], [b4]);
}
return multi([b2, b3]);
@@ -360,17 +360,17 @@ exports[`t-call t-call in t-foreach and children component 1`] = `
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(['a','b','c']);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(['a','b','c']);;
for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`val\`] = v_block2[i1];
ctx[\`val_first\`] = i1 === 0;
ctx[\`val_last\`] = i1 === v_block2.length - 1;
ctx[\`val_index\`] = i1;
ctx[\`val_value\`] = k_block2[i1];
let key1 = ctx['val'];
const key1 = ctx['val'];
c_block2[i1] = withKey(callTemplate_1.call(this, ctx, node, key + \`__1__\${key1}\`), key1);
}
let b2 = list(c_block2);
const b2 = list(c_block2);
return block1([], [b2]);
}
}"
@@ -8,7 +8,7 @@ exports[`t-call-block simple t-call-block with static text 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = ctx['myBlock']();
const b2 = ctx['myBlock']();
return block1([], [b2]);
}
}"
@@ -8,8 +8,8 @@ exports[`t-component can switch between dynamic components without the need for
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
let Comp1 = ctx['constructor'].components[ctx['state'].child];
let b2 = toggler(Comp1, component(Comp1, {}, key + \`__1\`, node, ctx));
const Comp1 = ctx['constructor'].components[ctx['state'].child];
const b2 = toggler(Comp1, component(Comp1, {}, key + \`__1\`, node, ctx));
return block1([], [b2]);
}
}"
@@ -48,7 +48,7 @@ exports[`t-component can use dynamic components (the class) if given (with diffe
return function template(ctx, node, key = \\"\\") {
const tKey_1 = ctx['state'].child;
let Comp1 = ctx['myComponent'];
const Comp1 = ctx['myComponent'];
return toggler(tKey_1, toggler(Comp1, component(Comp1, {}, tKey_1 + key + \`__1\`, node, ctx)));
}
}"
@@ -87,7 +87,7 @@ exports[`t-component can use dynamic components (the class) if given 1`] = `
return function template(ctx, node, key = \\"\\") {
const tKey_1 = ctx['state'].child;
let Comp1 = ctx['myComponent'];
const Comp1 = ctx['myComponent'];
return toggler(tKey_1, toggler(Comp1, component(Comp1, {}, tKey_1 + key + \`__1\`, node, ctx)));
}
}"
@@ -127,8 +127,8 @@ exports[`t-component modifying a sub widget 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
let Comp1 = ctx['Counter'];
let b2 = toggler(Comp1, component(Comp1, {}, key + \`__1\`, node, ctx));
const Comp1 = ctx['Counter'];
const b2 = toggler(Comp1, component(Comp1, {}, key + \`__1\`, node, ctx));
return block1([], [b2]);
}
}"
@@ -156,7 +156,7 @@ exports[`t-component switching dynamic component 1`] = `
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
let Comp1 = ctx['Child'];
const Comp1 = ctx['Child'];
return toggler(Comp1, component(Comp1, {}, key + \`__1\`, node, ctx));
}
}"
@@ -192,7 +192,7 @@ exports[`t-component t-component works in simple case 1`] = `
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
let Comp1 = ctx['Child'];
const Comp1 = ctx['Child'];
return toggler(Comp1, component(Comp1, {}, key + \`__1\`, node, ctx));
}
}"
@@ -11,14 +11,14 @@ exports[`list of components components in a node in a t-foreach 1`] = `
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['items']);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['items']);;
for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`item\`] = v_block2[i1];
let key1 = 'li_'+ctx['item'];
let b4 = component(\`Child\`, {item: ctx['item']}, key + \`__1__\${key1}\`, node, ctx);
const key1 = 'li_'+ctx['item'];
const b4 = component(\`Child\`, {item: ctx['item']}, key + \`__1__\${key1}\`, node, ctx);
c_block2[i1] = withKey(block3([], [b4]), key1);
}
let b2 = list(c_block2);
const b2 = list(c_block2);
return block1([], [b2]);
}
}"
@@ -46,11 +46,11 @@ exports[`list of components crash on duplicate key in dev mode 1`] = `
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
const [k_block1, v_block1, l_block1, c_block1] = prepareList([1,2]);
const [k_block1, v_block1, l_block1, c_block1] = prepareList([1,2]);;
const keys1 = new Set();
for (let i1 = 0; i1 < l_block1; i1++) {
ctx[\`item\`] = v_block1[i1];
let key1 = 'child';
const key1 = 'child';
if (keys1.has(key1)) { throw new Error(\`Got duplicate key in t-foreach: \${key1}\`)}
keys1.add(key1);
const props1 = {};
@@ -84,14 +84,14 @@ exports[`list of components list of sub components inside other nodes 1`] = `
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['state'].blips);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['state'].blips);;
for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`blip\`] = v_block2[i1];
let key1 = ctx['blip'].id;
let b4 = component(\`SubComponent\`, {}, key + \`__1__\${key1}\`, node, ctx);
const key1 = ctx['blip'].id;
const b4 = component(\`SubComponent\`, {}, key + \`__1__\${key1}\`, node, ctx);
c_block2[i1] = withKey(block3([], [b4]), key1);
}
let b2 = list(c_block2);
const b2 = list(c_block2);
return block1([], [b2]);
}
}"
@@ -120,23 +120,23 @@ exports[`list of components reconciliation alg works for t-foreach in t-foreach
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['state'].s);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['state'].s);;
for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`section\`] = v_block2[i1];
ctx[\`section_index\`] = i1;
let key1 = ctx['section_index'];
const key1 = ctx['section_index'];
ctx = Object.create(ctx);
const [k_block3, v_block3, l_block3, c_block3] = prepareList(ctx['section'].blips);
const [k_block3, v_block3, l_block3, c_block3] = prepareList(ctx['section'].blips);;
for (let i2 = 0; i2 < l_block3; i2++) {
ctx[\`blip\`] = v_block3[i2];
ctx[\`blip_index\`] = i2;
let key2 = ctx['blip_index'];
const key2 = ctx['blip_index'];
c_block3[i2] = withKey(component(\`Child\`, {blip: ctx['blip']}, key + \`__1__\${key1}__\${key2}\`, node, ctx), key2);
}
ctx = ctx.__proto__;
c_block2[i1] = withKey(list(c_block3), key1);
}
let b2 = list(c_block2);
const b2 = list(c_block2);
return block1([], [b2]);
}
}"
@@ -168,23 +168,23 @@ exports[`list of components reconciliation alg works for t-foreach in t-foreach,
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['state'].rows);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['state'].rows);;
for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`row\`] = v_block2[i1];
let key1 = ctx['row'];
const key1 = ctx['row'];
ctx = Object.create(ctx);
const [k_block4, v_block4, l_block4, c_block4] = prepareList(ctx['state'].cols);
const [k_block4, v_block4, l_block4, c_block4] = prepareList(ctx['state'].cols);;
for (let i2 = 0; i2 < l_block4; i2++) {
ctx[\`col\`] = v_block4[i2];
let key2 = ctx['col'];
let b6 = component(\`Child\`, {row: ctx['row'], col: ctx['col']}, key + \`__1__\${key1}__\${key2}\`, node, ctx);
const key2 = ctx['col'];
const b6 = component(\`Child\`, {row: ctx['row'], col: ctx['col']}, key + \`__1__\${key1}__\${key2}\`, node, ctx);
c_block4[i2] = withKey(block5([], [b6]), key2);
}
ctx = ctx.__proto__;
let b4 = list(c_block4);
const b4 = list(c_block4);
c_block2[i1] = withKey(block3([], [b4]), key1);
}
let b2 = list(c_block2);
const b2 = list(c_block2);
return block1([], [b2]);
}
}"
@@ -212,10 +212,10 @@ exports[`list of components simple list 1`] = `
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
const [k_block1, v_block1, l_block1, c_block1] = prepareList(ctx['state'].elems);
const [k_block1, v_block1, l_block1, c_block1] = prepareList(ctx['state'].elems);;
for (let i1 = 0; i1 < l_block1; i1++) {
ctx[\`elem\`] = v_block1[i1];
let key1 = ctx['elem'].id;
const key1 = ctx['elem'].id;
c_block1[i1] = withKey(component(\`Child\`, {value: ctx['elem'].value}, key + \`__1__\${key1}\`, node, ctx), key1);
}
return list(c_block1);
@@ -247,13 +247,13 @@ exports[`list of components sub components rendered in a loop 1`] = `
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['state'].numbers);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['state'].numbers);;
for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`number\`] = v_block2[i1];
let key1 = ctx['number'];
const key1 = ctx['number'];
c_block2[i1] = withKey(component(\`Child\`, {n: ctx['number']}, key + \`__1__\${key1}\`, node, ctx), key1);
}
let b2 = list(c_block2);
const b2 = list(c_block2);
return block1([], [b2]);
}
}"
@@ -283,13 +283,13 @@ exports[`list of components sub components with some state rendered in a loop 1`
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['state'].numbers);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['state'].numbers);;
for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`number\`] = v_block2[i1];
let key1 = ctx['number'];
const key1 = ctx['number'];
c_block2[i1] = withKey(component(\`Child\`, {}, key + \`__1__\${key1}\`, node, ctx), key1);
}
let b2 = list(c_block2);
const b2 = list(c_block2);
return block1([], [b2]);
}
}"
@@ -319,13 +319,13 @@ exports[`list of components switch component position 1`] = `
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['clist']);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['clist']);;
for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`c\`] = v_block2[i1];
let key1 = ctx['c'];
const key1 = ctx['c'];
c_block2[i1] = withKey(component(\`Child\`, {key: ctx['c']}, key + \`__1__\${key1}\`, node, ctx), key1);
}
let b2 = list(c_block2);
const b2 = list(c_block2);
return block1([], [b2]);
}
}"
@@ -355,14 +355,14 @@ exports[`list of components t-foreach with t-component, and update 1`] = `
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(Array(2));
const [k_block2, v_block2, l_block2, c_block2] = prepareList(Array(2));;
for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`n\`] = v_block2[i1];
ctx[\`n_index\`] = i1;
let key1 = ctx['n_index'];
const key1 = ctx['n_index'];
c_block2[i1] = withKey(component(\`Child\`, {val: ctx['n_index']}, key + \`__1__\${key1}\`, node, ctx), key1);
}
let b2 = list(c_block2);
const b2 = list(c_block2);
return block1([], [b2]);
}
}"
@@ -10,14 +10,14 @@ exports[`t-key t-foreach with t-key switch component position 1`] = `
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['clist']);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['clist']);;
for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`c\`] = v_block2[i1];
let key1 = ctx['c'];
const key1 = ctx['c'];
const tKey_1 = ctx['key1'];
c_block2[i1] = withKey(component(\`Child\`, {key: ctx['c']+ctx['key1']}, tKey_1 + key + \`__1__\${key1}\`, node, ctx), tKey_1 + key1);
}
let b2 = list(c_block2);
const b2 = list(c_block2);
return block1([], [b2]);
}
}"
@@ -72,7 +72,7 @@ exports[`t-key t-key on Component as a function 1`] = `
return function template(ctx, node, key = \\"\\") {
const tKey_1 = ctx['key'];
let b2 = toggler(tKey_1, component(\`Child\`, {key: ctx['key']}, tKey_1 + key + \`__1\`, node, ctx));
const b2 = toggler(tKey_1, component(\`Child\`, {key: ctx['key']}, tKey_1 + key + \`__1\`, node, ctx));
return block1([], [b2]);
}
}"
@@ -101,9 +101,9 @@ exports[`t-key t-key on multiple Components 1`] = `
return function template(ctx, node, key = \\"\\") {
const tKey_1 = ctx['key1'];
let b2 = toggler(tKey_1, component(\`Child\`, {key: ctx['key1']}, tKey_1 + key + \`__1\`, node, ctx));
const b2 = toggler(tKey_1, component(\`Child\`, {key: ctx['key1']}, tKey_1 + key + \`__1\`, node, ctx));
const tKey_2 = ctx['key2'];
let b3 = toggler(tKey_2, component(\`Child\`, {key: ctx['key2']}, tKey_2 + key + \`__2\`, node, ctx));
const b3 = toggler(tKey_2, component(\`Child\`, {key: ctx['key2']}, tKey_2 + key + \`__2\`, node, ctx));
return block1([], [b2, b3]);
}
}"
@@ -139,12 +139,12 @@ exports[`t-key t-key on multiple Components with t-call 1 1`] = `
ctx = Object.create(ctx);
ctx[isBoundary] = 1;
setContextValue(ctx, \\"key\\", ctx['key1']);
let b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
const b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
ctx = ctx.__proto__;
ctx = Object.create(ctx);
ctx[isBoundary] = 1;
setContextValue(ctx, \\"key\\", ctx['key2']);
let b3 = callTemplate_2.call(this, ctx, node, key + \`__2\`);
const b3 = callTemplate_2.call(this, ctx, node, key + \`__2\`);
return block1([], [b2, b3]);
}
}"
@@ -186,7 +186,7 @@ exports[`t-key t-key on multiple Components with t-call 2 1`] = `
let block1 = createBlock(\`<span><block-child-0/></span>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
const b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
return block1([], [b2]);
}
}"
@@ -199,9 +199,9 @@ exports[`t-key t-key on multiple Components with t-call 2 2`] = `
return function template(ctx, node, key = \\"\\") {
const tKey_1 = ctx['key1'];
let b2 = toggler(tKey_1, component(\`Child\`, {key: ctx['key1']}, tKey_1 + key + \`__1\`, node, ctx));
const b2 = toggler(tKey_1, component(\`Child\`, {key: ctx['key1']}, tKey_1 + key + \`__1\`, node, ctx));
const tKey_2 = ctx['key2'];
let b3 = toggler(tKey_2, component(\`Child\`, {key: ctx['key2']}, tKey_2 + key + \`__2\`, node, ctx));
const b3 = toggler(tKey_2, component(\`Child\`, {key: ctx['key2']}, tKey_2 + key + \`__2\`, node, ctx));
return multi([b2, b3]);
}
}"
@@ -194,17 +194,17 @@ exports[`t-model directive in a t-foreach 1`] = `
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['state']);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['state']);;
for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`thing\`] = v_block2[i1];
let key1 = ctx['thing'].id;
const key1 = ctx['thing'].id;
const bExpr1 = ctx['thing'];
const expr1 = 'f';
let attr1 = bExpr1[expr1];
let hdlr1 = [(ev) => { bExpr1[expr1] = ev.target.checked; }];
c_block2[i1] = withKey(block3([attr1, hdlr1]), key1);
}
let b2 = list(c_block2);
const b2 = list(c_block2);
return block1([], [b2]);
}
}"
@@ -221,18 +221,18 @@ exports[`t-model directive in a t-foreach, part 2 1`] = `
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['state']);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['state']);;
for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`thing\`] = v_block2[i1];
ctx[\`thing_index\`] = i1;
let key1 = ctx['thing_index'];
const key1 = ctx['thing_index'];
const bExpr1 = ctx['state'];
const expr1 = ctx['thing_index'];
let attr1 = bExpr1[expr1];
let hdlr1 = [(ev) => { bExpr1[expr1] = ev.target.value; }];
c_block2[i1] = withKey(block3([attr1, hdlr1]), key1);
}
let b2 = list(c_block2);
const b2 = list(c_block2);
return block1([], [b2]);
}
}"
@@ -249,18 +249,18 @@ exports[`t-model directive in a t-foreach, part 3 1`] = `
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['names']);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['names']);;
for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`name\`] = v_block2[i1];
ctx[\`name_index\`] = i1;
let key1 = ctx['name_index'];
const key1 = ctx['name_index'];
const bExpr1 = ctx['state'].values;
const expr1 = ctx['name'];
let attr1 = bExpr1[expr1];
let hdlr1 = [(ev) => { bExpr1[expr1] = ev.target.value; }];
c_block2[i1] = withKey(block3([attr1, hdlr1]), key1);
}
let b2 = list(c_block2);
const b2 = list(c_block2);
return block1([], [b2]);
}
}"
@@ -410,6 +410,24 @@ exports[`t-model directive on an textarea 1`] = `
}"
`;
exports[`t-model directive t-model on an input with an undefined value 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { toNumber } = helpers;
let block1 = createBlock(\`<input block-attribute-0=\\"value\\" block-handler-1=\\"input\\"/>\`);
return function template(ctx, node, key = \\"\\") {
const bExpr1 = ctx['state'];
const expr1 = 'text';
let attr1 = bExpr1[expr1];
let hdlr1 = [(ev) => { bExpr1[expr1] = ev.target.value; }];
return block1([attr1, hdlr1]);
}
}"
`;
exports[`t-model directive t-model on select with static options 1`] = `
"function anonymous(bdom, helpers
) {
@@ -442,7 +460,7 @@ exports[`t-model directive t-model with dynamic values on select options -- 2 1`
return function template(ctx, node, key = \\"\\") {
const bExpr1 = ctx['state'];
const expr1 = 'model';
let bValue1 = bExpr1[expr1]
const bValue1 = bExpr1[expr1];
let hdlr1 = [(ev) => { bExpr1[expr1] = ev.target.value; }];
let attr1 = ctx['options'][0];
let attr2 = bValue1 === ctx['options'][0];
@@ -466,7 +484,7 @@ exports[`t-model directive t-model with dynamic values on select options -- 3 1`
return function template(ctx, node, key = \\"\\") {
const bExpr1 = ctx['state'];
const expr1 = 'model';
let bValue1 = bExpr1[expr1]
const bValue1 = bExpr1[expr1];
let hdlr1 = [(ev) => { bExpr1[expr1] = ev.target.value; }];
let attr1 = ctx['options'][0];
let attr2 = bValue1 === ctx['options'][0];
@@ -489,7 +507,7 @@ exports[`t-model directive t-model with dynamic values on select options 1`] = `
return function template(ctx, node, key = \\"\\") {
const bExpr1 = ctx['state'];
const expr1 = 'model';
let bValue1 = bExpr1[expr1]
const bValue1 = bExpr1[expr1];
let hdlr1 = [(ev) => { bExpr1[expr1] = ev.target.value; }];
let attr1 = ctx['options'][0];
let attr2 = bValue1 === ctx['options'][0];
@@ -514,19 +532,19 @@ exports[`t-model directive t-model with dynamic values on select options in fore
return function template(ctx, node, key = \\"\\") {
const bExpr1 = ctx['state'];
const expr1 = 'model';
let bValue1 = bExpr1[expr1]
const bValue1 = bExpr1[expr1];
let hdlr1 = [(ev) => { bExpr1[expr1] = ev.target.value; }];
ctx = Object.create(ctx);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['options']);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['options']);;
for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`v\`] = v_block2[i1];
let key1 = ctx['v'];
const key1 = ctx['v'];
let attr1 = ctx['v'];
let attr2 = bValue1 === ctx['v'];
let txt1 = ctx['v'];
c_block2[i1] = withKey(block3([attr1, attr2, txt1]), key1);
}
let b2 = list(c_block2);
const b2 = list(c_block2);
return block1([hdlr1], [b2]);
}
}"
+147 -12
View File
@@ -14,17 +14,17 @@ exports[`t-on t-on expression captured in t-foreach 1`] = `
ctx[isBoundary] = 1
setContextValue(ctx, \\"iter\\", 0);
ctx = Object.create(ctx);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['arr']);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['arr']);;
for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`val\`] = v_block2[i1];
let key1 = ctx['val'];
const key1 = ctx['val'];
const v1 = ctx['otherState'];
const v2 = ctx['iter'];
let hdlr1 = [()=>v1.vals.push(v2+'_'+v2), ctx];
setContextValue(ctx, \\"iter\\", ctx['iter']+1);
c_block2[i1] = withKey(block3([hdlr1]), key1);
}
let b2 = list(c_block2);
const b2 = list(c_block2);
return block1([], [b2]);
}
}"
@@ -41,11 +41,11 @@ exports[`t-on t-on expression in t-foreach 1`] = `
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['state'].values);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['state'].values);;
for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`val\`] = v_block2[i1];
ctx[\`val_index\`] = i1;
let key1 = ctx['val'];
const key1 = ctx['val'];
let txt1 = ctx['val_index'];
let txt2 = ctx['val']+'';
const v1 = ctx['otherState'];
@@ -53,7 +53,7 @@ exports[`t-on t-on expression in t-foreach 1`] = `
let hdlr1 = [()=>v1.vals.push(v2), ctx];
c_block2[i1] = withKey(block3([txt1, txt2, hdlr1]), key1);
}
let b2 = list(c_block2);
const b2 = list(c_block2);
return block1([], [b2]);
}
}"
@@ -73,11 +73,11 @@ exports[`t-on t-on expression in t-foreach with t-set 1`] = `
ctx[isBoundary] = 1
setContextValue(ctx, \\"bossa\\", 'nova');
ctx = Object.create(ctx);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['state'].values);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['state'].values);;
for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`val\`] = v_block2[i1];
ctx[\`val_index\`] = i1;
let key1 = ctx['val'];
const key1 = ctx['val'];
setContextValue(ctx, \\"bossa\\", ctx['bossa']+'_'+ctx['val_index']);
let txt1 = ctx['val_index'];
let txt2 = ctx['val']+'';
@@ -87,7 +87,7 @@ exports[`t-on t-on expression in t-foreach with t-set 1`] = `
let hdlr1 = [()=>v1.vals.push(v2+'_'+v3), ctx];
c_block2[i1] = withKey(block3([txt1, txt2, hdlr1]), key1);
}
let b2 = list(c_block2);
const b2 = list(c_block2);
return block1([], [b2]);
}
}"
@@ -104,23 +104,82 @@ exports[`t-on t-on method call in t-foreach 1`] = `
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['state'].values);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['state'].values);;
for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`val\`] = v_block2[i1];
ctx[\`val_index\`] = i1;
let key1 = ctx['val'];
const key1 = ctx['val'];
let txt1 = ctx['val_index'];
let txt2 = ctx['val']+'';
const v1 = ctx['val'];
let hdlr1 = [()=>this.addVal(v1), ctx];
c_block2[i1] = withKey(block3([txt1, txt2, hdlr1]), key1);
}
let b2 = list(c_block2);
const b2 = list(c_block2);
return block1([], [b2]);
}
}"
`;
exports[`t-on t-on on components 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { createCatcher } = helpers;
const catcher1 = createCatcher({\\"click\\":0});
return function template(ctx, node, key = \\"\\") {
const hdlr1 = [ctx['increment'], ctx];
return catcher1(component(\`Child\`, {value: ctx['state'].value}, key + \`__1\`, node, ctx), [hdlr1]);
}
}"
`;
exports[`t-on t-on on components 2`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let block1 = createBlock(\`<button><block-text-0/></button>\`);
return function template(ctx, node, key = \\"\\") {
let txt1 = ctx['props'].value;
return block1([txt1]);
}
}"
`;
exports[`t-on t-on on components, variation 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { createCatcher } = helpers;
const catcher1 = createCatcher({\\"click\\":0});
let block1 = createBlock(\`<div><span/><block-child-0/><p/></div>\`);
return function template(ctx, node, key = \\"\\") {
const hdlr1 = [ctx['increment'], ctx];
const b2 = catcher1(component(\`Child\`, {value: ctx['state'].value}, key + \`__1\`, node, ctx), [hdlr1]);
return block1([], [b2]);
}
}"
`;
exports[`t-on t-on on components, variation 2`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let block1 = createBlock(\`<button><block-text-0/></button>\`);
return function template(ctx, node, key = \\"\\") {
let txt1 = ctx['props'].value;
return block1([txt1]);
}
}"
`;
exports[`t-on t-on on destroyed components 1`] = `
"function anonymous(bdom, helpers
) {
@@ -151,3 +210,79 @@ exports[`t-on t-on on destroyed components 2`] = `
}
}"
`;
exports[`t-on t-on on t-set-slots 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { capture, createCatcher, markRaw } = helpers;
const catcher1 = createCatcher({\\"click\\":0});
let block6 = createBlock(\`<p>something</p>\`);
let block7 = createBlock(\`<p>paragraph</p>\`);
function slot1(ctx, node, key = \\"\\") {
const b6 = block6();
const b7 = block7();
const hdlr1 = [()=>this.state.count++, ctx];
return catcher1(multi([b6, b7]), [hdlr1]);
}
return function template(ctx, node, key = \\"\\") {
const b2 = text(\` [\`);
const b3 = text(ctx['state'].count);
const b4 = text(\`] \`);
const ctx1 = capture(ctx);
const b8 = component(\`Child\`, {slots: markRaw({'myslot': {__render: slot1, __ctx: ctx1}})}, key + \`__1\`, node, ctx);
return multi([b2, b3, b4, b8]);
}
}"
`;
exports[`t-on t-on on t-set-slots 2`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { callSlot } = helpers;
return function template(ctx, node, key = \\"\\") {
return callSlot(ctx, node, key, 'myslot', false, null);
}
}"
`;
exports[`t-on t-on on t-slots 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { markRaw } = helpers;
let block1 = createBlock(\`<p>something</p>\`);
function slot1(ctx, node, key = \\"\\") {
return block1();
}
return function template(ctx, node, key = \\"\\") {
return component(\`Child\`, {slots: markRaw({'default': {__render: slot1, __ctx: ctx}})}, key + \`__1\`, node, ctx);
}
}"
`;
exports[`t-on t-on on t-slots 2`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { callSlot, createCatcher } = helpers;
const catcher1 = createCatcher({\\"click\\":0});
return function template(ctx, node, key = \\"\\") {
const b2 = text(\` [\`);
const b3 = text(ctx['state'].count);
const b4 = text(\`] \`);
const hdlr1 = [()=>this.state.count++, ctx];
const b5 = catcher1(callSlot(ctx, node, key, 'default', false, null), [hdlr1]);
return multi([b2, b3, b4, b5]);
}
}"
`;
@@ -8,7 +8,7 @@ exports[`t-props basic use 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = component(\`Child\`, Object.assign({}, ctx['some'].obj), key + \`__1\`, node, ctx);
const b2 = component(\`Child\`, Object.assign({}, ctx['some'].obj), key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -60,7 +60,7 @@ exports[`t-props t-props and other props 1`] = `
let block1 = createBlock(\`<div><div><block-child-0/></div></div>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = component(\`Comp\`, Object.assign({}, ctx['state1'], {a: ctx['a']}), key + \`__1\`, node, ctx);
const b2 = component(\`Comp\`, Object.assign({}, ctx['state1'], {a: ctx['a']}), key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -89,7 +89,7 @@ exports[`t-props t-props only 1`] = `
let block1 = createBlock(\`<div><div><block-child-0/></div></div>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = component(\`Comp\`, Object.assign({}, ctx['state']), key + \`__1\`, node, ctx);
const b2 = component(\`Comp\`, Object.assign({}, ctx['state']), key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -117,7 +117,7 @@ exports[`t-props t-props with props 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
let b2 = component(\`Child\`, Object.assign({}, ctx['childProps'], {a: 1, b: 2}), key + \`__1\`, node, ctx);
const b2 = component(\`Child\`, Object.assign({}, ctx['childProps'], {a: 1, b: 2}), key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -4,7 +4,7 @@ exports[`t-set slot setted value (with t-set) not accessible with t-esc 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { isBoundary, withDefault, setContextValue, capture } = helpers;
let { isBoundary, withDefault, setContextValue, capture, markRaw } = helpers;
let block1 = createBlock(\`<div><p><block-text-0/></p><block-child-0/><p><block-text-1/></p></div>\`);
@@ -21,7 +21,7 @@ exports[`t-set slot setted value (with t-set) not accessible with t-esc 1`] = `
setContextValue(ctx, \\"iter\\", 'source');
let txt1 = ctx['iter'];
const ctx1 = capture(ctx);
let b2 = component(\`Childcomp\`, {slots: {'default': {__render: slot1, __ctx: ctx1}}}, key + \`__1\`, node, ctx);
const b2 = component(\`Childcomp\`, {slots: markRaw({'default': {__render: slot1, __ctx: ctx1}})}, key + \`__1\`, node, ctx);
let txt2 = ctx['iter'];
return block1([txt1, txt2], [b2]);
}
@@ -51,14 +51,14 @@ exports[`t-set slots with a t-set with a component in body 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { capture, isBoundary, withDefault, LazyValue, safeOutput } = helpers;
let { capture, isBoundary, withDefault, LazyValue, safeOutput, markRaw } = helpers;
function slot1(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
ctx[isBoundary] = 1
ctx[\`v\`] = new LazyValue(value1, ctx, node);
let b3 = text(\` in slot \`);
let b4 = safeOutput(ctx['v']);
const b3 = text(\` in slot \`);
const b4 = safeOutput(ctx['v']);
return multi([b3, b4]);
}
@@ -68,7 +68,7 @@ exports[`t-set slots with a t-set with a component in body 1`] = `
return function template(ctx, node, key = \\"\\") {
const ctx1 = capture(ctx);
return component(\`Child\`, {slots: {'default': {__render: slot1, __ctx: ctx1}}}, key + \`__2\`, node, ctx);
return component(\`Child\`, {slots: markRaw({'default': {__render: slot1, __ctx: ctx1}})}, key + \`__2\`, node, ctx);
}
}"
`;
@@ -80,8 +80,8 @@ exports[`t-set slots with a t-set with a component in body 2`] = `
let { callSlot } = helpers;
return function template(ctx, node, key = \\"\\") {
let b2 = text(\`Child \`);
let b3 = callSlot(ctx, node, key, 'default', false, {});
const b2 = text(\`Child \`);
const b3 = callSlot(ctx, node, key, 'default', false, null);
return multi([b2, b3]);
}
}"
@@ -102,7 +102,7 @@ exports[`t-set slots with an t-set with a component in body 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { capture, isBoundary, withDefault, LazyValue, safeOutput } = helpers;
let { capture, isBoundary, withDefault, LazyValue, safeOutput, markRaw } = helpers;
let block4 = createBlock(\`<div>coffee</div>\`);
@@ -110,20 +110,20 @@ exports[`t-set slots with an t-set with a component in body 1`] = `
ctx = Object.create(ctx);
ctx[isBoundary] = 1
ctx[\`v\`] = new LazyValue(value1, ctx, node);
let b5 = text(\` tea \`);
let b6 = safeOutput(ctx['v']);
const b5 = text(\` tea \`);
const b6 = safeOutput(ctx['v']);
return multi([b5, b6]);
}
function value1(ctx, node, key = \\"\\") {
let b3 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
let b4 = block4();
const b3 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
const b4 = block4();
return multi([b3, b4]);
}
return function template(ctx, node, key = \\"\\") {
const ctx1 = capture(ctx);
return component(\`Blorg\`, {slots: {'default': {__render: slot1, __ctx: ctx1}}}, key + \`__2\`, node, ctx);
return component(\`Blorg\`, {slots: markRaw({'default': {__render: slot1, __ctx: ctx1}})}, key + \`__2\`, node, ctx);
}
}"
`;
@@ -135,8 +135,8 @@ exports[`t-set slots with an t-set with a component in body 2`] = `
let { callSlot } = helpers;
return function template(ctx, node, key = \\"\\") {
let b2 = text(\`Blorg \`);
let b3 = callSlot(ctx, node, key, 'default', false, {});
const b2 = text(\`Blorg \`);
const b3 = callSlot(ctx, node, key, 'default', false, null);
return multi([b2, b3]);
}
}"
@@ -157,7 +157,7 @@ exports[`t-set slots with an unused t-set with a component in body 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { capture, isBoundary, withDefault, LazyValue } = helpers;
let { capture, isBoundary, withDefault, LazyValue, markRaw } = helpers;
function slot1(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
@@ -172,7 +172,7 @@ exports[`t-set slots with an unused t-set with a component in body 1`] = `
return function template(ctx, node, key = \\"\\") {
const ctx1 = capture(ctx);
return component(\`Child\`, {slots: {'default': {__render: slot1, __ctx: ctx1}}}, key + \`__2\`, node, ctx);
return component(\`Child\`, {slots: markRaw({'default': {__render: slot1, __ctx: ctx1}})}, key + \`__2\`, node, ctx);
}
}"
`;
@@ -184,8 +184,8 @@ exports[`t-set slots with an unused t-set with a component in body 2`] = `
let { callSlot } = helpers;
return function template(ctx, node, key = \\"\\") {
let b2 = text(\`Child \`);
let b3 = callSlot(ctx, node, key, 'default', false, {});
const b2 = text(\`Child \`);
const b3 = callSlot(ctx, node, key, 'default', false, null);
return multi([b2, b3]);
}
}"
@@ -267,7 +267,7 @@ exports[`t-set t-set not altered by child comp 1`] = `
ctx[isBoundary] = 1
setContextValue(ctx, \\"iter\\", 'source');
let txt1 = ctx['iter'];
let b2 = component(\`Childcomp\`, {}, key + \`__1\`, node, ctx);
const b2 = component(\`Childcomp\`, {}, key + \`__1\`, node, ctx);
let txt2 = ctx['iter'];
return block1([txt1, txt2], [b2]);
}
@@ -335,7 +335,7 @@ exports[`t-set t-set with a component in body 1`] = `
ctx = Object.create(ctx);
ctx[isBoundary] = 1
ctx[\`v\`] = new LazyValue(value1, ctx, node);
let b3 = safeOutput(ctx['v']);
const b3 = safeOutput(ctx['v']);
return block1([], [b3]);
}
}"
@@ -369,7 +369,7 @@ exports[`t-set t-set with something in body 1`] = `
ctx = Object.create(ctx);
ctx[isBoundary] = 1
ctx[\`v\`] = new LazyValue(value1, ctx, node);
let b3 = safeOutput(ctx['v']);
const b3 = safeOutput(ctx['v']);
return block1([], [b3]);
}
}"
+3 -3
View File
@@ -1,4 +1,4 @@
import { App, Component, mount, status, useState, xml } from "../../src";
import { App, Component, mount, status, toRaw, useState, xml } from "../../src";
import { elem, makeTestFixture, nextTick, snapshotEverything, useLogLifecycle } from "../helpers";
import { markup } from "../../src/utils";
@@ -121,7 +121,7 @@ describe("basics", () => {
class Test extends Component {
static template = xml`<span>simple vnode</span>`;
setup() {
expect(this.props).toBe(p);
expect(toRaw(this.props)).toBe(p);
}
}
@@ -204,7 +204,7 @@ describe("basics", () => {
error = e as Error;
}
expect(error!).toBeDefined();
expect(error!.message).toBe('Missing template: "wrongtemplate"');
expect(error!.message).toBe('Missing template: "wrongtemplate" (for component "Test")');
});
test("class component with dynamic text", async () => {
+143 -18
View File
@@ -39,6 +39,8 @@ Scheduler.prototype.addFiber = function (fiber: Fiber) {
afterEach(() => {
if (lastScheduler && lastScheduler.tasks.size > 0) {
// we still clear the scheduler to prevent additional noise
lastScheduler.tasks.clear();
throw new Error("we got a memory leak...");
}
});
@@ -131,6 +133,58 @@ test("destroying/recreating a subwidget with different props (if start is not ov
]).toBeLogged();
});
test("destroying/recreating a subcomponent, other scenario", async () => {
let flag = false;
class Child extends Component {
static template = xml`child`;
setup() {
if (!flag) {
flag = true;
parent.render(true);
}
useLogLifecycle();
}
}
class Parent extends Component {
static template = xml`parent<Child t-if="state.hasChild"/>`;
static components = { Child };
state = useState({ hasChild: false });
setup() {
useLogLifecycle();
}
}
const parent = await mount(Parent, fixture);
expect([
"Parent:setup",
"Parent:willStart",
"Parent:willRender",
"Parent:rendered",
"Parent:mounted",
]).toBeLogged();
expect(fixture.innerHTML).toBe("parent");
parent.state.hasChild = true;
await nextTick();
expect([
"Parent:willRender",
"Child:setup",
"Child:willStart",
"Parent:rendered",
"Child:willRender",
"Child:rendered",
"Parent:willPatch",
"Child:mounted",
"Parent:patched",
]).toBeLogged();
expect(fixture.innerHTML).toBe("parentchild");
});
test("creating two async components, scenario 1", async () => {
let defA = makeDeferred();
let defB = makeDeferred();
@@ -521,7 +575,7 @@ test("properly behave when destroyed/unmounted while rendering ", async () => {
}
class Child extends Component {
static template = xml`<div><SubChild /></div>`;
static template = xml`<div><SubChild val="props.val"/></div>`;
static components = { SubChild };
setup() {
useLogLifecycle();
@@ -1907,18 +1961,13 @@ test("concurrent renderings scenario 13", async () => {
await nextTick(); // wait for this change to be applied
expect([
"Parent:willRender",
"Child:willUpdateProps",
"Child:setup",
"Child:willStart",
"Parent:rendered",
"Child:willRender",
"Child:rendered",
"Child:willRender",
"Child:rendered",
"Parent:willPatch",
"Child:willPatch",
"Child:mounted",
"Child:patched",
"Parent:patched",
"Child:willRender",
"Child:rendered",
@@ -2472,9 +2521,9 @@ test("two renderings initiated between willPatch and patched", async () => {
useLogLifecycle();
onMounted(() => {
this.mounted = "Mounted";
parent.render();
parent.render(true);
});
onWillUnmount(() => parent.render());
onWillUnmount(() => parent.render(true));
}
}
@@ -2507,15 +2556,11 @@ test("two renderings initiated between willPatch and patched", async () => {
"Parent:rendered",
]).toBeLogged();
await nextMicroTick();
expect(["Panel:willRender", "Panel:rendered"]).toBeLogged();
await nextTick();
expect([
"Panel:willRender",
"Panel:rendered",
"Parent:willPatch",
"Panel:willPatch",
"Panel:patched",
"Parent:patched",
]).toBeLogged();
expect(["Parent:willPatch", "Panel:willPatch", "Panel:patched", "Parent:patched"]).toBeLogged();
expect(fixture.innerHTML).toBe("<div><abc>Panel1Mounted</abc></div>");
parent.state.panel = "Panel2";
@@ -2753,12 +2798,20 @@ test("delay willUpdateProps with rendering grandchild", async () => {
static template = xml`<Parent state="state"/>`;
static components = { Parent };
state = { value: 0 };
setup() {
useLogLifecycle();
}
}
const parent = await mount(GrandParent, fixture);
expect(fixture.innerHTML).toBe("0_0<div></div>");
expect([
"GrandParent:setup",
"GrandParent:willStart",
"GrandParent:willRender",
"Parent:setup",
"Parent:willStart",
"GrandParent:rendered",
"Parent:willRender",
"DelayedChild:setup",
"DelayedChild:willStart",
@@ -2772,20 +2825,23 @@ test("delay willUpdateProps with rendering grandchild", async () => {
"ReactiveChild:mounted",
"DelayedChild:mounted",
"Parent:mounted",
"GrandParent:mounted",
]).toBeLogged();
promise = makeDeferred();
const prom1 = promise;
parent.state.value = 1;
child.render(); // trigger a root rendering first
parent.render();
parent.render(true);
reactiveChild.render();
await nextTick();
expect(fixture.innerHTML).toBe("0_0<div></div>");
expect([
"DelayedChild:willRender",
"DelayedChild:rendered",
"GrandParent:willRender",
"Parent:willUpdateProps",
"GrandParent:rendered",
"ReactiveChild:willRender",
"ReactiveChild:rendered",
"Parent:willRender",
@@ -2800,12 +2856,14 @@ test("delay willUpdateProps with rendering grandchild", async () => {
const prom2 = promise;
child.render(); // trigger a root rendering first
parent.state.value = 2;
parent.render();
parent.render(true);
reactiveChild.render();
await nextTick();
expect(fixture.innerHTML).toBe("0_0<div></div>");
expect([
"GrandParent:willRender",
"Parent:willUpdateProps",
"GrandParent:rendered",
"ReactiveChild:willRender",
"ReactiveChild:rendered",
"Parent:willRender",
@@ -2822,12 +2880,14 @@ test("delay willUpdateProps with rendering grandchild", async () => {
expect([
"DelayedChild:willRender",
"DelayedChild:rendered",
"GrandParent:willPatch",
"Parent:willPatch",
"ReactiveChild:willPatch",
"DelayedChild:willPatch",
"DelayedChild:patched",
"ReactiveChild:patched",
"Parent:patched",
"GrandParent:patched",
]).toBeLogged();
prom1.resolve();
@@ -3129,6 +3189,71 @@ test("Cascading renders after microtaskTick", async () => {
await nextTick();
expect(fixture.innerHTML).toBe("0123 _ 0123");
});
test("rendering parent twice, with different props on child and stuff", async () => {
class Child extends Component {
static template = xml`<t t-esc="props.value"/>`;
setup() {
useLogLifecycle();
}
}
class Parent extends Component {
static template = xml`<Child value="state.value"/>`;
static components = { Child };
state = useState({ value: 1 });
setup() {
useLogLifecycle();
}
}
const parent = await mount(Parent, fixture);
expect(fixture.innerHTML).toBe("1");
expect([
"Parent:setup",
"Parent:willStart",
"Parent:willRender",
"Child:setup",
"Child:willStart",
"Parent:rendered",
"Child:willRender",
"Child:rendered",
"Child:mounted",
"Parent:mounted",
]).toBeLogged();
parent.state.value = 2;
// wait for child to be rendered
await nextMicroTick();
await nextMicroTick();
await nextMicroTick();
await nextMicroTick();
expect([
"Parent:willRender",
"Child:willUpdateProps",
"Parent:rendered",
"Child:willRender",
"Child:rendered",
]).toBeLogged();
expect(fixture.innerHTML).toBe("1");
// trigger a render, but keep the props for child the same
parent.render();
await nextTick();
expect(fixture.innerHTML).toBe("2");
expect([
"Parent:willRender",
"Child:willUpdateProps",
"Parent:rendered",
"Child:willRender",
"Child:rendered",
"Parent:willPatch",
"Child:willPatch",
"Child:patched",
"Parent:patched",
]).toBeLogged();
});
// test.skip("components with shouldUpdate=false", async () => {
// const state = { p: 1, cc: 10 };
+2
View File
@@ -49,5 +49,7 @@ describe("env handling", () => {
await new App(Test, { env }).mount(fixture);
expect(child.env).toEqual(env);
// we check that the frozen env maintain the same prototype chain
expect(Object.getPrototypeOf(child.env)).toBe(Object.getPrototypeOf(env));
});
});
+84 -17
View File
@@ -5,6 +5,8 @@ import {
onPatched,
onWillPatch,
onWillStart,
onWillRender,
onRendered,
onWillUnmount,
useState,
xml,
@@ -82,8 +84,6 @@ describe("basics", () => {
});
test("display a nice error if it cannot find component (in dev mode)", async () => {
const info = console.info;
console.info = jest.fn(() => {}); // dev mode message
class SomeComponent extends Component {}
class Parent extends Component {
static template = xml`<SomeMispelledComponent />`;
@@ -91,7 +91,7 @@ describe("basics", () => {
}
let error: Error;
try {
await mount(Parent, fixture, { dev: true });
await mount(Parent, fixture, { test: true });
} catch (e) {
error = e as Error;
}
@@ -100,8 +100,6 @@ describe("basics", () => {
expect(console.error).toBeCalledTimes(0);
expect(mockConsoleError).toBeCalledTimes(0);
expect(mockConsoleWarn).toBeCalledTimes(1);
expect(console.info).toBeCalledTimes(1);
console.info = info;
});
test("simple catchError", async () => {
@@ -179,6 +177,74 @@ describe("errors and promises", () => {
expect(mockConsoleWarn).toBeCalledTimes(1);
});
test("an error in onMounted callback will have the component's setup in its stack trace", async () => {
class App extends Component {
static template = xml`<div>abc</div>`;
setup() {
onMounted(() => {
throw new Error("boom");
});
}
}
let error: Error;
try {
await mount(App, fixture, { test: true });
} catch (e) {
error = e as Error;
}
expect(error!).toBeDefined();
expect(error!.stack).toContain("App.setup");
expect(error!.stack).toContain("error_handling.test.ts");
expect(fixture.innerHTML).toBe("");
expect(mockConsoleError).toBeCalledTimes(0);
expect(mockConsoleWarn).toBeCalledTimes(1);
});
test("errors in onWillRender/onRender aren't wrapped more than once", async () => {
class App extends Component {
static template = xml`<div>abc</div>`;
setup() {
onWillRender(() => {
throw new Error("boom in onWillRender");
});
onRendered(() => {
throw new Error("boom in onRendered");
});
}
}
let error: Error;
try {
await mount(App, fixture, { test: true });
} catch (e) {
error = e as Error;
}
expect(error!).toBeDefined();
expect(error!.message).toBe(
`The following error occurred in onWillRender: "boom in onWillRender"`
);
});
test("error while rendering component isn't wrapped by onWillRender/onRendered", async () => {
class App extends Component {
static template = xml`<div t-att-class="{ 'invalid: 5 }">abc</div>`;
setup() {
onWillRender(() => {});
onRendered(() => {});
}
}
let error: Error;
try {
await mount(App, fixture, { test: true });
} catch (e) {
error = e as Error;
}
expect(error!).toBeDefined();
expect(error!.message).toBe("Tokenizer error: could not tokenize `{ 'invalid: 5 }`");
});
test("an error in willPatch call will reject the render promise", async () => {
class Root extends Component {
static template = xml`<div><t t-esc="val"/></div>`;
@@ -191,13 +257,13 @@ describe("errors and promises", () => {
}
}
const root = await mount(Root, fixture);
const root = await mount(Root, fixture, { test: true });
root.val = 4;
let error: Error;
root.render();
await nextTick();
expect(error!).toBeDefined();
expect(error!.message).toBe("boom");
expect(error!.message).toBe(`The following error occurred in onWillPatch: "boom"`);
expect(mockConsoleError).toBeCalledTimes(0);
expect(mockConsoleWarn).toBeCalledTimes(0);
});
@@ -214,13 +280,13 @@ describe("errors and promises", () => {
}
}
const root = await mount(Root, fixture);
const root = await mount(Root, fixture, { test: true });
root.val = 4;
let error: Error;
root.render();
await nextTick();
expect(error!).toBeDefined();
expect(error!.message).toBe("boom");
expect(error!.message).toBe(`The following error occurred in onPatched: "boom"`);
expect(mockConsoleError).toBeCalledTimes(0);
expect(mockConsoleWarn).toBeCalledTimes(0);
});
@@ -296,7 +362,6 @@ describe("errors and promises", () => {
});
test("errors in mounted and in willUnmount", async () => {
expect.assertions(4);
class Example extends Component {
static template = xml`<div/>`;
val: any;
@@ -313,9 +378,11 @@ describe("errors and promises", () => {
}
try {
await mount(Example, fixture);
await mount(Example, fixture, { test: true });
} catch (e) {
expect((e as Error).message).toBe("Error in mounted");
expect((e as Error).message).toBe(
`The following error occurred in onMounted: "Error in mounted"`
);
}
// 1 additional error is logged because the destruction of the app causes
// the onWillUnmount hook to be called and to fail
@@ -385,14 +452,14 @@ describe("can catch errors", () => {
});
}
}
let e: any = null;
let e: Error;
try {
await mount(Root, fixture);
await mount(Root, fixture, { test: true });
} catch (error) {
e = error;
e = error as Error;
}
expect(e.message).toBe(
"No active component (a hook function should only be called in 'setup')"
expect(e!.message).toBe(
`The following error occurred in onWillStart: "No active component (a hook function should only be called in 'setup')"`
);
});
+2 -2
View File
@@ -238,7 +238,7 @@ describe("hooks", () => {
expect(fixture.innerHTML).toBe("<div>maggot brain</div>");
someVal = "brain";
someVal2 = "maggot";
component.render();
component.render(true);
await nextTick();
expect(fixture.innerHTML).toBe("<div>brain maggot</div>");
});
@@ -272,7 +272,7 @@ describe("hooks", () => {
expect(fixture.innerHTML).toBe("<div>maggot brain</div>");
someVal = "brain";
someVal2 = "maggot";
component.render();
component.render(true);
await nextTick();
expect(fixture.innerHTML).toBe("<div>brain maggot</div>");
});
+3 -7
View File
@@ -849,8 +849,9 @@ describe("lifecycle hooks", () => {
class Parent extends Component {
static template = xml`
<Child />`;
<Child someValue="state.value" />`;
static components = { Child };
state = useState({ value: 1 });
setup() {
useLogLifecycle();
}
@@ -871,7 +872,7 @@ describe("lifecycle hooks", () => {
"Parent:mounted",
]).toBeLogged();
parent.render(); // to block child render
parent.state.value++; // to block child render
await nextTick();
expect(["Parent:willRender", "Child:willUpdateProps", "Parent:rendered"]).toBeLogged();
@@ -1008,20 +1009,15 @@ describe("lifecycle hooks", () => {
await nextTick();
expect([
"C:willRender",
"D:willUpdateProps",
"F:setup",
"F:willStart",
"C:rendered",
"D:willRender",
"D:rendered",
"F:willRender",
"F:rendered",
"C:willPatch",
"D:willPatch",
"E:willUnmount",
"E:willDestroy",
"F:mounted",
"D:patched",
"C:patched",
]).toBeLogged();
});
+1 -1
View File
@@ -12,7 +12,7 @@ let mockConsoleWarn: any;
beforeAll(() => {
console.info = (message: any) => {
if (message === DEV_MSG) {
if (message === DEV_MSG()) {
return;
}
info(message);
+12
View File
@@ -53,6 +53,18 @@ describe("reactivity in lifecycle", () => {
expect(n).toBe(2); // no new rendering occured: b was never read via state!
});
test("can use a state hook on Map", async () => {
class Counter extends Component {
static template = xml`<div><t t-esc="counter.get('value')"/></div>`;
counter = useState(new Map([["value", 42]]));
}
const counter = await mount(Counter, fixture);
expect(fixture.innerHTML).toBe("<div>42</div>");
counter.counter.set("value", 3);
await nextTick();
expect(fixture.innerHTML).toBe("<div>3</div>");
});
test("state changes in willUnmount do not trigger rerender", async () => {
const steps: string[] = [];
class Child extends Component {
+442
View File
@@ -0,0 +1,442 @@
import { Component, mount, onRendered, onWillUpdateProps, useState, xml } from "../../src";
import {
makeTestFixture,
snapshotEverything,
nextTick,
useLogLifecycle,
makeDeferred,
nextMicroTick,
} from "../helpers";
let fixture: HTMLElement;
snapshotEverything();
beforeEach(() => {
fixture = makeTestFixture();
});
describe("rendering semantics", () => {
test("can render a parent without rendering child", async () => {
class Child extends Component {
static template = xml`child`;
setup() {
useLogLifecycle();
}
}
class Parent extends Component {
static template = xml`
<t t-esc="state.value"/>
<Child/>
`;
static components = { Child };
state = useState({ value: "A" });
setup() {
useLogLifecycle();
}
}
const parent = await mount(Parent, fixture);
expect(fixture.innerHTML).toBe("Achild");
expect([
"Parent:setup",
"Parent:willStart",
"Parent:willRender",
"Child:setup",
"Child:willStart",
"Parent:rendered",
"Child:willRender",
"Child:rendered",
"Child:mounted",
"Parent:mounted",
]).toBeLogged();
parent.state.value = "B";
await nextTick();
expect(fixture.innerHTML).toBe("Bchild");
expect([
"Parent:willRender",
"Parent:rendered",
"Parent:willPatch",
"Parent:patched",
]).toBeLogged();
});
test("can force a render to update sub tree", async () => {
let childN = 0;
let parentN = 0;
class Child extends Component {
static template = xml`child`;
setup() {
onRendered(() => childN++);
}
}
class Parent extends Component {
static template = xml`
<t t-esc="state.value"/>
<Child/>
`;
static components = { Child };
state = { value: "A" };
setup() {
onRendered(() => parentN++);
}
}
const parent = await mount(Parent, fixture);
expect(fixture.innerHTML).toBe("Achild");
expect(parentN).toBe(1);
expect(childN).toBe(1);
parent.state.value = "B";
parent.render(true);
await nextTick();
expect(fixture.innerHTML).toBe("Bchild");
expect(parentN).toBe(2);
expect(childN).toBe(2);
});
test("render with deep=true followed by render with deep=false work as expected", async () => {
class Child extends Component {
static template = xml`child<t t-esc="env.getValue()"/>`;
setup() {
useLogLifecycle();
}
}
class Parent extends Component {
static template = xml`parent<t t-esc="state.value"/><Child/>`;
static components = { Child };
state = useState({ value: "A" });
setup() {
useLogLifecycle();
}
}
let value = 3;
const env = {
getValue() {
return value;
},
};
const parent = await mount(Parent, fixture, { env });
expect(fixture.innerHTML).toBe("parentAchild3");
expect([
"Parent:setup",
"Parent:willStart",
"Parent:willRender",
"Child:setup",
"Child:willStart",
"Parent:rendered",
"Child:willRender",
"Child:rendered",
"Child:mounted",
"Parent:mounted",
]).toBeLogged();
value = 4;
parent.render(true);
// wait for child to be rendered, but dom not yet patched
await nextMicroTick();
await nextMicroTick();
await nextMicroTick();
expect([
"Parent:willRender",
"Child:willUpdateProps",
"Parent:rendered",
"Child:willRender",
"Child:rendered",
]).toBeLogged();
parent.state.value = "B";
await nextTick();
expect(fixture.innerHTML).toBe("parentBchild4");
expect([
"Parent:willRender",
"Child:willUpdateProps",
"Parent:rendered",
"Child:willRender",
"Child:rendered",
"Parent:willPatch",
"Child:willPatch",
"Child:patched",
"Parent:patched",
]).toBeLogged();
});
test("props are reactive", async () => {
class Child extends Component {
static template = xml`<t t-esc="props.a.b"/>`;
setup() {
useLogLifecycle();
}
}
class Parent extends Component {
static template = xml`
<Child a="state"/>
`;
static components = { Child };
state = useState({ b: 1 });
setup() {
useLogLifecycle();
}
}
const parent = await mount(Parent, fixture);
expect(fixture.innerHTML).toBe("1");
expect([
"Parent:setup",
"Parent:willStart",
"Parent:willRender",
"Child:setup",
"Child:willStart",
"Parent:rendered",
"Child:willRender",
"Child:rendered",
"Child:mounted",
"Parent:mounted",
]).toBeLogged();
parent.state.b = 3;
await nextTick();
expect(fixture.innerHTML).toBe("3");
expect(["Child:willRender", "Child:rendered", "Child:willPatch", "Child:patched"]).toBeLogged();
});
test("props are reactive (nested prop)", async () => {
class Child extends Component {
static template = xml`<t t-esc="props.a.b.c"/>`;
setup() {
useLogLifecycle();
}
}
class Parent extends Component {
static template = xml`
<Child a="state"/>
`;
static components = { Child };
state = useState({ b: { c: 1 } });
setup() {
useLogLifecycle();
}
}
const parent = await mount(Parent, fixture);
expect(fixture.innerHTML).toBe("1");
expect([
"Parent:setup",
"Parent:willStart",
"Parent:willRender",
"Child:setup",
"Child:willStart",
"Parent:rendered",
"Child:willRender",
"Child:rendered",
"Child:mounted",
"Parent:mounted",
]).toBeLogged();
parent.state.b.c = 3; // parent is now subscribed to 'b' key
await nextTick();
expect(fixture.innerHTML).toBe("3");
expect(["Child:willRender", "Child:rendered", "Child:willPatch", "Child:patched"]).toBeLogged();
parent.state.b = { c: 444 }; // triggers a parent and a child render
await nextTick();
expect(fixture.innerHTML).toBe("444");
expect([
"Parent:willRender",
"Parent:rendered",
"Child:willRender",
"Child:rendered",
"Parent:willPatch",
"Parent:patched",
"Child:willPatch",
"Child:patched",
]).toBeLogged();
});
test("works as expected for dynamic number of props", async () => {
class Child extends Component {
static template = xml`<t t-esc="Object.keys(props).length"/>`;
}
class Parent extends Component {
static template = xml`
<Child t-props="state"/>
`;
static components = { Child };
state: any = useState({ b: 1 });
}
const parent = await mount(Parent, fixture);
expect(fixture.innerHTML).toBe("1");
parent.state.newkey = 3;
await nextTick();
expect(fixture.innerHTML).toBe("2");
});
test("rendering is atomic (for one subtree)", async () => {
const def = makeDeferred();
class C extends Component {
static template = xml`<t t-esc="props.obj.val"/>`;
setup() {
useLogLifecycle();
}
}
class B extends Component {
static template = xml`<C obj="props.obj"/>`;
static components = { C };
setup() {
useLogLifecycle();
onWillUpdateProps(() => def);
}
}
class A extends Component {
static template = xml`<t t-esc="state.obj.val"/><B obj="state.obj"/>`;
static components = { B };
state = useState({ obj: { val: 1 } });
setup() {
useLogLifecycle();
}
}
const parent = await mount(A, fixture);
expect(fixture.innerHTML).toBe("11");
expect([
"A:setup",
"A:willStart",
"A:willRender",
"B:setup",
"B:willStart",
"A:rendered",
"B:willRender",
"C:setup",
"C:willStart",
"B:rendered",
"C:willRender",
"C:rendered",
"C:mounted",
"B:mounted",
"A:mounted",
]).toBeLogged();
parent.state.obj.val = 3;
await nextTick();
expect(fixture.innerHTML).toBe("33");
expect([
"A:willRender",
"A:rendered",
"C:willRender",
"C:rendered",
"A:willPatch",
"A:patched",
"C:willPatch",
"C:patched",
]).toBeLogged();
def.resolve();
await nextTick();
expect([]).toBeLogged();
});
});
test("force render in case of existing render", async () => {
const def = makeDeferred();
class C extends Component {
static template = xml`C`;
setup() {
useLogLifecycle();
}
}
class B extends Component {
static template = xml`<C/><t t-esc="props.val"/>`;
static components = { C };
setup() {
useLogLifecycle();
onWillUpdateProps(() => def);
}
}
class A extends Component {
static template = xml`<B val="state.val"/>`;
static components = { B };
state = useState({ val: 1 });
setup() {
useLogLifecycle();
}
}
const parent = await mount(A, fixture);
expect(fixture.innerHTML).toBe("C1");
expect([
"A:setup",
"A:willStart",
"A:willRender",
"B:setup",
"B:willStart",
"A:rendered",
"B:willRender",
"C:setup",
"C:willStart",
"B:rendered",
"C:willRender",
"C:rendered",
"C:mounted",
"B:mounted",
"A:mounted",
]).toBeLogged();
// trigger a new rendering, blocked in B
parent.state.val = 2;
await nextTick();
expect(["A:willRender", "B:willUpdateProps", "A:rendered"]).toBeLogged();
// initiate a new render with deep=true. it should cancel the current render
// and also be blocked in B
parent.render(true);
await nextTick();
expect(["A:willRender", "B:willUpdateProps", "A:rendered"]).toBeLogged();
def.resolve();
await nextTick();
// we check here that the render reaches C (so, that it was properly forced)
expect([
"B:willRender",
"C:willUpdateProps",
"B:rendered",
"C:willRender",
"C:rendered",
"A:willPatch",
"B:willPatch",
"C:willPatch",
"C:patched",
"B:patched",
"A:patched",
]).toBeLogged();
});
+56
View File
@@ -1675,4 +1675,60 @@ describe("slots", () => {
await mount(Parent, fixture);
expect(fixture.innerHTML).toBe("<div>SlotDisplay</div><div>Parent</div>");
});
test("mix of slots, t-call, t-call with body, and giving own props child", async () => {
expect.assertions(11);
class C extends Component {
static template = xml`[C]<t t-slot="default" />`;
}
class B extends Component {
static template = xml`[B]<C slots="props.slots" />`;
static components = { C };
}
const subTemplate2 = xml`[sub2<t t-esc="v"/>]`;
const subTemplate1 = xml`[sub1]
<t t-set="dummy" t-value="validate"/>
<t t-call="${subTemplate2}">
<t t-set="v" t-value="props.number"/>
</t>`;
let a: any;
class A extends Component {
static components = { B };
static template = xml`<B>[A]<t t-call="${subTemplate1}"/></B>`;
setup() {
a = this;
}
get validate() {
// we check here that the actual component was not lost somehow
expect(this.__owl__.component === a).toBe(true);
return 1;
}
}
class P extends Component {
static components = { A };
static template = xml`<button t-on-click="inc">inc</button><A number="state.number"/>`;
state = useState({ number: 333 });
inc() {
this.state.number++;
}
}
class Parent extends Component {
static template = xml`<P/>`;
static components = { P };
}
await mount(Parent, fixture);
expect(fixture.innerHTML).toBe("<button>inc</button>[B][C][A][sub1] [sub2333]");
fixture.querySelector("button")!.click();
await nextTick();
expect(fixture.innerHTML).toBe("<button>inc</button>[B][C][A][sub1] [sub2334]");
});
});
+13
View File
@@ -30,6 +30,19 @@ describe("t-model directive", () => {
expect(fixture.innerHTML).toBe("<div><input><span>test</span></div>");
});
test("t-model on an input with an undefined value", async () => {
class SomeComponent extends Component {
static template = xml`<input t-model="state.text"/>`;
state = useState({ text: undefined });
}
await mount(SomeComponent, fixture);
expect(fixture.innerHTML).toBe("<input>");
const input = fixture.querySelector("input")!;
expect(input.value).toBe("");
});
test("basic use, on an input with bracket expression", async () => {
class SomeComponent extends Component {
static template = xml`
+103
View File
@@ -142,4 +142,107 @@ describe("t-on", () => {
buttons[1].click();
expect(comp.otherState.vals).toStrictEqual(["0_0", "1_1"]);
});
test("t-on on components", async () => {
class Child extends Component {
static template = xml`<button t-esc="props.value"/>`;
}
class Parent extends Component {
static template = xml`<Child t-on-click="increment" value="state.value"/>`;
static components = { Child };
state = useState({ value: 1 });
increment() {
this.state.value++;
}
}
await mount(Parent, fixture);
expect(fixture.innerHTML).toBe("<button>1</button>");
fixture.querySelector("button")!.click();
await nextTick();
expect(fixture.innerHTML).toBe("<button>2</button>");
});
test("t-on on components, variation", async () => {
class Child extends Component {
static template = xml`<button t-esc="props.value"/>`;
}
class Parent extends Component {
static template = xml`
<div>
<span/>
<Child t-on-click="increment" value="state.value"/>
<p/>
</div>`;
static components = { Child };
state = useState({ value: 1 });
increment() {
this.state.value++;
}
}
await mount(Parent, fixture);
expect(fixture.innerHTML).toBe("<div><span></span><button>1</button><p></p></div>");
fixture.querySelector("span")!.click();
await nextTick();
expect(fixture.innerHTML).toBe("<div><span></span><button>1</button><p></p></div>");
fixture.querySelector("button")!.click();
await nextTick();
expect(fixture.innerHTML).toBe("<div><span></span><button>2</button><p></p></div>");
fixture.querySelector("p")!.click();
await nextTick();
expect(fixture.innerHTML).toBe("<div><span></span><button>2</button><p></p></div>");
});
test("t-on on t-slots", async () => {
class Child extends Component {
static template = xml`
[<t t-esc="state.count"/>]
<t t-slot="default" t-on-click="() => this.state.count++"/>`;
state = useState({ count: 0 });
}
class Parent extends Component {
static template = xml`
<Child>
<p>something</p>
</Child>`;
static components = { Child };
}
await mount(Parent, fixture);
expect(fixture.innerHTML).toBe(" [0] <p>something</p>");
fixture.querySelector("p")!.click();
await nextTick();
expect(fixture.innerHTML).toBe(" [1] <p>something</p>");
});
test("t-on on t-set-slots", async () => {
class Child extends Component {
static template = xml`<t t-slot="myslot"/>`;
}
class Parent extends Component {
static template = xml`
[<t t-esc="state.count"/>]
<Child>
<t t-set-slot="myslot" t-on-click="() => this.state.count++">
<p>something</p>
<p>paragraph</p>
</t>
</Child>`;
static components = { Child };
state = useState({ count: 0 });
}
await mount(Parent, fixture);
expect(fixture.innerHTML).toBe(" [0] <p>something</p><p>paragraph</p>");
fixture.querySelector("p")!.click();
await nextTick();
expect(fixture.innerHTML).toBe(" [1] <p>something</p><p>paragraph</p>");
});
});
+2 -1
View File
@@ -53,7 +53,7 @@ describe("t-props", () => {
});
test("basic use", async () => {
expect.assertions(4);
expect.assertions(5);
let props = { a: 1, b: 2 };
@@ -65,6 +65,7 @@ describe("t-props", () => {
`;
setup() {
expect(this.props).toEqual({ a: 1, b: 2 });
expect(this.props).not.toBe(props);
}
}
class Parent extends Component {
+4 -3
View File
@@ -15,10 +15,11 @@ import {
useComponent,
xml,
} from "../src";
import { UTILS } from "../src/app/template_helpers";
import { globalTemplates, TemplateSet } from "../src/app/template_set";
import { helpers } from "../src/app/template_helpers";
import { TemplateSet } from "../src/app/template_set";
import { BDom } from "../src/blockdom";
import { compile } from "../src/compiler";
import { globalTemplates } from "../src/utils";
const mount = blockDom.mount;
@@ -91,7 +92,7 @@ export function renderToBdom(template: string, context: any = {}, node?: any): B
snapshottedTemplates.add(template);
expect(fn.toString()).toMatchSnapshot();
}
return fn(blockDom, UTILS)(context, node);
return fn(blockDom, helpers)(context, node);
}
export function renderToString(template: string, context: any = {}, node?: any): string {
@@ -1,68 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Memo if no prop change, prevent renderings from above 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
function slot1(ctx, node, key = \\"\\") {
let b6 = text(ctx['state'].a);
let b7 = text(ctx['state'].b);
let b8 = text(ctx['state'].c);
return multi([b6, b7, b8]);
}
return function template(ctx, node, key = \\"\\") {
let b2 = text(ctx['state'].a);
let b3 = text(ctx['state'].b);
let b4 = text(ctx['state'].c);
let b9 = component(\`Memo\`, {a: ctx['state'].a, b: ctx['state'].b,slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__1\`, node, ctx);
return multi([b2, b3, b4, b9]);
}
}"
`;
exports[`Memo if no props, prevent renderings from above 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
function slot1(ctx, node, key = \\"\\") {
return component(\`Child\`, {value: ctx['state'].value}, key + \`__2\`, node, ctx);
}
return function template(ctx, node, key = \\"\\") {
let b2 = component(\`Child\`, {value: ctx['state'].value}, key + \`__1\`, node, ctx);
let b4 = component(\`Memo\`, {slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__3\`, node, ctx);
return multi([b2, b4]);
}
}"
`;
exports[`Memo if no props, prevent renderings from above 2`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
return text(ctx['props'].value);
}
}"
`;
exports[`Memo if no props, prevent renderings from above (work with simple html) 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
function slot1(ctx, node, key = \\"\\") {
return text(ctx['state'].value);
}
return function template(ctx, node, key = \\"\\") {
let b2 = text(ctx['state'].value);
let b4 = component(\`Memo\`, {slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__1\`, node, ctx);
return multi([b2, b4]);
}
}"
`;
+61 -60
View File
@@ -7,18 +7,18 @@ exports[`Portal Add and remove portals 1`] = `
let { prepareList, Portal, capture, withKey } = helpers;
function slot1(ctx, node, key = \\"\\") {
let b3 = text(\` Portal\`);
let b4 = text(ctx['portalId']);
const b3 = text(\` Portal\`);
const b4 = text(ctx['portalId']);
return multi([b3, b4]);
}
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
const [k_block1, v_block1, l_block1, c_block1] = prepareList(ctx['portalIds']);
const [k_block1, v_block1, l_block1, c_block1] = prepareList(ctx['portalIds']);;
for (let i1 = 0; i1 < l_block1; i1++) {
ctx[\`portalId\`] = v_block1[i1];
let key1 = ctx['portalId'];
const ctx1 = capture(ctx);
const key1 = ctx['portalId'];
const ctx1 = capture(ctx);;
c_block1[i1] = withKey(component(Portal, {target: '#outside',slots: {'default': {__render: slot1, __ctx: ctx1}}}, key + \`__1__\${key1}\`, node, ctx), key1);
}
return list(c_block1);
@@ -41,11 +41,11 @@ exports[`Portal Add and remove portals on div 1`] = `
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
const [k_block1, v_block1, l_block1, c_block1] = prepareList(ctx['portalIds']);
const [k_block1, v_block1, l_block1, c_block1] = prepareList(ctx['portalIds']);;
for (let i1 = 0; i1 < l_block1; i1++) {
ctx[\`portalId\`] = v_block1[i1];
let key1 = ctx['portalId'];
const ctx1 = capture(ctx);
const key1 = ctx['portalId'];
const ctx1 = capture(ctx);;
c_block1[i1] = withKey(component(Portal, {target: '#outside',slots: {'default': {__render: slot1, __ctx: ctx1}}}, key + \`__1__\${key1}\`, node, ctx), key1);
}
return list(c_block1);
@@ -62,20 +62,20 @@ exports[`Portal Add and remove portals with t-foreach 1`] = `
let block2 = createBlock(\`<div><block-text-0/><block-child-0/></div>\`);
function slot1(ctx, node, key = \\"\\") {
let b4 = text(\` Portal\`);
let b5 = text(ctx['portalId']);
const b4 = text(\` Portal\`);
const b5 = text(ctx['portalId']);
return multi([b4, b5]);
}
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
const [k_block1, v_block1, l_block1, c_block1] = prepareList(ctx['portalIds']);
const [k_block1, v_block1, l_block1, c_block1] = prepareList(ctx['portalIds']);;
for (let i1 = 0; i1 < l_block1; i1++) {
ctx[\`portalId\`] = v_block1[i1];
let key1 = ctx['portalId'];
const key1 = ctx['portalId'];
let txt1 = ctx['portalId'];
const ctx1 = capture(ctx);
let b6 = component(Portal, {target: '#outside',slots: {'default': {__render: slot1, __ctx: ctx1}}}, key + \`__1__\${key1}\`, node, ctx);
const ctx1 = capture(ctx);;
const b6 = component(Portal, {target: '#outside',slots: {'default': {__render: slot1, __ctx: ctx1}}}, key + \`__1__\${key1}\`, node, ctx);
c_block1[i1] = withKey(block2([txt1], [b6]), key1);
}
return list(c_block1);
@@ -92,20 +92,20 @@ exports[`Portal Add and remove portals with t-foreach and destroy 1`] = `
let block2 = createBlock(\`<div><block-text-0/><block-child-0/></div>\`);
function slot1(ctx, node, key = \\"\\") {
let b4 = text(\` Portal\`);
let b5 = text(ctx['portalId']);
const b4 = text(\` Portal\`);
const b5 = text(ctx['portalId']);
return multi([b4, b5]);
}
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
const [k_block1, v_block1, l_block1, c_block1] = prepareList(ctx['portalIds']);
const [k_block1, v_block1, l_block1, c_block1] = prepareList(ctx['portalIds']);;
for (let i1 = 0; i1 < l_block1; i1++) {
ctx[\`portalId\`] = v_block1[i1];
let key1 = ctx['portalId'];
const key1 = ctx['portalId'];
let txt1 = ctx['portalId'];
const ctx1 = capture(ctx);
let b6 = component(Portal, {target: '#outside',slots: {'default': {__render: slot1, __ctx: ctx1}}}, key + \`__1__\${key1}\`, node, ctx);
const ctx1 = capture(ctx);;
const b6 = component(Portal, {target: '#outside',slots: {'default': {__render: slot1, __ctx: ctx1}}}, key + \`__1__\${key1}\`, node, ctx);
c_block1[i1] = withKey(block2([txt1], [b6]), key1);
}
return list(c_block1);
@@ -123,23 +123,23 @@ exports[`Portal Add and remove portals with t-foreach inside div 1`] = `
let block3 = createBlock(\`<div><block-text-0/><block-child-0/></div>\`);
function slot1(ctx, node, key = \\"\\") {
let b5 = text(\` Portal\`);
let b6 = text(ctx['portalId']);
const b5 = text(\` Portal\`);
const b6 = text(ctx['portalId']);
return multi([b5, b6]);
}
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['portalIds']);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['portalIds']);;
for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`portalId\`] = v_block2[i1];
let key1 = ctx['portalId'];
const key1 = ctx['portalId'];
let txt1 = ctx['portalId'];
const ctx1 = capture(ctx);
let b7 = component(Portal, {target: '#outside',slots: {'default': {__render: slot1, __ctx: ctx1}}}, key + \`__1__\${key1}\`, node, ctx);
const ctx1 = capture(ctx);;
const b7 = component(Portal, {target: '#outside',slots: {'default': {__render: slot1, __ctx: ctx1}}}, key + \`__1__\${key1}\`, node, ctx);
c_block2[i1] = withKey(block3([txt1], [b7]), key1);
}
let b2 = list(c_block2);
const b2 = list(c_block2);
return block1([], [b2]);
}
}"
@@ -149,6 +149,7 @@ exports[`Portal Portal composed with t-slot 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { markRaw } = helpers;
let block1 = createBlock(\`<div><block-child-0/></div>\`);
@@ -157,7 +158,7 @@ exports[`Portal Portal composed with t-slot 1`] = `
}
return function template(ctx, node, key = \\"\\") {
let b3 = component(\`Child\`, {slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__2\`, node, ctx);
const b3 = component(\`Child\`, {slots: markRaw({'default': {__render: slot1, __ctx: ctx}})}, key + \`__2\`, node, ctx);
return block1([], [b3]);
}
}"
@@ -170,7 +171,7 @@ exports[`Portal Portal composed with t-slot 2`] = `
let { Portal, callSlot } = helpers;
function slot1(ctx, node, key = \\"\\") {
return callSlot(ctx, node, key, 'default', false, {});
return callSlot(ctx, node, key, 'default', false, null);
}
return function template(ctx, node, key = \\"\\") {
@@ -207,7 +208,7 @@ exports[`Portal basic use of portal 1`] = `
}
return function template(ctx, node, key = \\"\\") {
let b3 = component(Portal, {target: '#outside',slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__1\`, node, ctx);
const b3 = component(Portal, {target: '#outside',slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__1\`, node, ctx);
return block1([], [b3]);
}
}"
@@ -227,7 +228,7 @@ exports[`Portal basic use of portal in dev mode 1`] = `
}
return function template(ctx, node, key = \\"\\") {
let b3 = component(Portal, {target: '#outside',slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__1\`, node, ctx);
const b3 = component(Portal, {target: '#outside',slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__1\`, node, ctx);
return block1([], [b3]);
}
}"
@@ -247,7 +248,7 @@ exports[`Portal basic use of portal on div 1`] = `
}
return function template(ctx, node, key = \\"\\") {
let b3 = component(Portal, {target: '#outside',slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__1\`, node, ctx);
const b3 = component(Portal, {target: '#outside',slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__1\`, node, ctx);
return block1([], [b3]);
}
}"
@@ -344,14 +345,14 @@ exports[`Portal conditional use of Portal with child and div 2`] = `
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
const [k_block2, v_block2, l_block2, c_block2] = prepareList([1]);
const [k_block2, v_block2, l_block2, c_block2] = prepareList([1]);;
for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`elem\`] = v_block2[i1];
let key1 = ctx['elem'];
const ctx1 = capture(ctx);
const key1 = ctx['elem'];
const ctx1 = capture(ctx);;
c_block2[i1] = withKey(component(Portal, {target: '#outside',slots: {'default': {__render: slot1, __ctx: ctx1}}}, key + \`__1__\${key1}\`, node, ctx), key1);
}
let b2 = list(c_block2);
const b2 = list(c_block2);
return block1([], [b2]);
}
}"
@@ -367,7 +368,7 @@ exports[`Portal conditional use of Portal with child and div, variation 1`] = `
return function template(ctx, node, key = \\"\\") {
let b2;
if (ctx['state'].hasPortal) {
let b3 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
const b3 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
b2 = block2([], [b3]);
}
return multi([b2]);
@@ -389,16 +390,16 @@ exports[`Portal conditional use of Portal with child and div, variation 2`] = `
}
return function template(ctx, node, key = \\"\\") {
let b2 = block2();
const b2 = block2();
ctx = Object.create(ctx);
const [k_block3, v_block3, l_block3, c_block3] = prepareList([1]);
const [k_block3, v_block3, l_block3, c_block3] = prepareList([1]);;
for (let i1 = 0; i1 < l_block3; i1++) {
ctx[\`elem\`] = v_block3[i1];
let key1 = ctx['elem'];
const ctx1 = capture(ctx);
const key1 = ctx['elem'];
const ctx1 = capture(ctx);;
c_block3[i1] = withKey(component(Portal, {target: '#outside',slots: {'default': {__render: slot1, __ctx: ctx1}}}, key + \`__1__\${key1}\`, node, ctx), key1);
}
let b3 = list(c_block3);
const b3 = list(c_block3);
return multi([b2, b3]);
}
}"
@@ -420,7 +421,7 @@ exports[`Portal conditional use of Portal with div 1`] = `
return function template(ctx, node, key = \\"\\") {
let b2;
if (ctx['state'].hasPortal) {
let b4 = component(Portal, {target: '#outside',slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__1\`, node, ctx);
const b4 = component(Portal, {target: '#outside',slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__1\`, node, ctx);
b2 = block2([], [b4]);
}
return multi([b2]);
@@ -483,7 +484,7 @@ exports[`Portal portal could have dynamically no content 1`] = `
}
return function template(ctx, node, key = \\"\\") {
let b4 = component(Portal, {target: '#outside',slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__1\`, node, ctx);
const b4 = component(Portal, {target: '#outside',slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__1\`, node, ctx);
return block1([], [b4]);
}
}"
@@ -502,7 +503,7 @@ exports[`Portal portal destroys on crash 1`] = `
}
return function template(ctx, node, key = \\"\\") {
let b3 = component(Portal, {target: '#outside',slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__2\`, node, ctx);
const b3 = component(Portal, {target: '#outside',slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__2\`, node, ctx);
return block1([], [b3]);
}
}"
@@ -535,7 +536,7 @@ exports[`Portal portal with child and props 1`] = `
}
return function template(ctx, node, key = \\"\\") {
let b3 = component(Portal, {target: '#outside',slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__2\`, node, ctx);
const b3 = component(Portal, {target: '#outside',slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__2\`, node, ctx);
return block1([], [b3]);
}
}"
@@ -577,7 +578,7 @@ exports[`Portal portal with dynamic body 1`] = `
}
return function template(ctx, node, key = \\"\\") {
let b5 = component(Portal, {target: '#outside',slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__1\`, node, ctx);
const b5 = component(Portal, {target: '#outside',slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__1\`, node, ctx);
return block1([], [b5]);
}
}"
@@ -594,13 +595,13 @@ exports[`Portal portal with many children 1`] = `
let block4 = createBlock(\`<p>2</p>\`);
function slot1(ctx, node, key = \\"\\") {
let b3 = block3();
let b4 = block4();
const b3 = block3();
const b4 = block4();
return multi([b3, b4]);
}
return function template(ctx, node, key = \\"\\") {
let b5 = component(Portal, {target: '#outside',slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__1\`, node, ctx);
const b5 = component(Portal, {target: '#outside',slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__1\`, node, ctx);
return block1([], [b5]);
}
}"
@@ -623,7 +624,7 @@ exports[`Portal portal with no content 1`] = `
}
return function template(ctx, node, key = \\"\\") {
let b4 = component(Portal, {target: '#outside',slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__1\`, node, ctx);
const b4 = component(Portal, {target: '#outside',slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__1\`, node, ctx);
return block1([], [b4]);
}
}"
@@ -642,7 +643,7 @@ exports[`Portal portal with only text as content 1`] = `
}
return function template(ctx, node, key = \\"\\") {
let b3 = component(Portal, {target: '#outside',slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__1\`, node, ctx);
const b3 = component(Portal, {target: '#outside',slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__1\`, node, ctx);
return block1([], [b3]);
}
}"
@@ -662,7 +663,7 @@ exports[`Portal portal with target not in dom 1`] = `
}
return function template(ctx, node, key = \\"\\") {
let b3 = component(Portal, {target: '#does-not-exist',slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__1\`, node, ctx);
const b3 = component(Portal, {target: '#does-not-exist',slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__1\`, node, ctx);
return block1([], [b3]);
}
}"
@@ -681,7 +682,7 @@ exports[`Portal portal's parent's env is not polluted 1`] = `
}
return function template(ctx, node, key = \\"\\") {
let b3 = component(Portal, {target: '#outside',slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__2\`, node, ctx);
const b3 = component(Portal, {target: '#outside',slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__2\`, node, ctx);
return block1([], [b3]);
}
}"
@@ -734,7 +735,7 @@ exports[`Portal simple catchError with portal 2`] = `
}
return function template(ctx, node, key = \\"\\") {
let b3 = component(Portal, {target: '#outside',slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__1\`, node, ctx);
const b3 = component(Portal, {target: '#outside',slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__1\`, node, ctx);
return block1([], [b3]);
}
}"
@@ -754,7 +755,7 @@ exports[`Portal with target in template (after portal) 1`] = `
}
return function template(ctx, node, key = \\"\\") {
let b3 = component(Portal, {target: '#local-target',slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__1\`, node, ctx);
const b3 = component(Portal, {target: '#local-target',slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__1\`, node, ctx);
return block1([], [b3]);
}
}"
@@ -774,7 +775,7 @@ exports[`Portal with target in template (before portal) 1`] = `
}
return function template(ctx, node, key = \\"\\") {
let b3 = component(Portal, {target: '#local-target',slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__1\`, node, ctx);
const b3 = component(Portal, {target: '#local-target',slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__1\`, node, ctx);
return block1([], [b3]);
}
}"
@@ -794,7 +795,7 @@ exports[`Portal: Props validation target must be a valid selector 1`] = `
}
return function template(ctx, node, key = \\"\\") {
let b3 = component(Portal, {target: ' ',slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__1\`, node, ctx);
const b3 = component(Portal, {target: ' ',slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__1\`, node, ctx);
return block1([], [b3]);
}
}"
@@ -814,7 +815,7 @@ exports[`Portal: Props validation target must be a valid selector 2 1`] = `
}
return function template(ctx, node, key = \\"\\") {
let b3 = component(Portal, {target: 'aa',slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__1\`, node, ctx);
const b3 = component(Portal, {target: 'aa',slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__1\`, node, ctx);
return block1([], [b3]);
}
}"
@@ -833,7 +834,7 @@ exports[`Portal: UI/UX focus is kept across re-renders 1`] = `
}
return function template(ctx, node, key = \\"\\") {
let b3 = component(Portal, {target: '#outside',slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__2\`, node, ctx);
const b3 = component(Portal, {target: '#outside',slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__2\`, node, ctx);
return block1([], [b3]);
}
}"
-92
View File
@@ -1,92 +0,0 @@
import { Component, mount, useState, xml } from "../../src";
import { Memo } from "../../src/";
import { makeTestFixture, nextTick, snapshotEverything } from "../helpers";
let fixture: HTMLElement;
snapshotEverything();
beforeEach(() => {
fixture = makeTestFixture();
});
describe("Memo", () => {
test("if no props, prevent renderings from above ", async () => {
class Child extends Component {
static template = xml`<t t-esc="props.value"/>`;
}
class Test extends Component {
static template = xml`
<Child value="state.value"/>
<Memo>
<Child value="state.value"/>
</Memo>`;
static components = { Memo, Child };
state = useState({ value: 1 });
}
const component = await mount(Test, fixture);
expect(fixture.innerHTML).toBe("11");
component.state.value = 2;
await nextTick();
expect(fixture.innerHTML).toBe("21");
});
test("if no props, prevent renderings from above (work with simple html) ", async () => {
class Test extends Component {
static template = xml`
<t t-esc="state.value"/>
<Memo>
<t t-esc="state.value"/>
</Memo>`;
static components = { Memo };
state = useState({ value: 1 });
}
const component = await mount(Test, fixture);
expect(fixture.innerHTML).toBe("11");
component.state.value = 2;
await nextTick();
expect(fixture.innerHTML).toBe("21");
});
test("if no prop change, prevent renderings from above ", async () => {
class Child extends Component {
static template = xml`<t t-esc="props.value"/>`;
}
class Test extends Component {
static template = xml`
<t t-esc="state.a"/>
<t t-esc="state.b"/>
<t t-esc="state.c"/>
<Memo a="state.a" b="state.b">
<t t-esc="state.a"/>
<t t-esc="state.b"/>
<t t-esc="state.c"/>
</Memo>`;
static components = { Memo, Child };
state = useState({ a: "a", b: "b", c: "c" });
}
const component = await mount(Test, fixture);
expect(fixture.innerHTML).toBe("abcabc");
component.state.c = "C";
await nextTick();
expect(fixture.innerHTML).toBe("abCabc");
component.state.a = "A";
await nextTick();
expect(fixture.innerHTML).toBe("AbCAbC");
});
});
+5 -1
View File
@@ -29,7 +29,7 @@ snapshotEverything();
beforeAll(() => {
console.info = (message: any) => {
if (message === DEV_MSG) {
if (message === DEV_MSG()) {
return;
}
info(message);
@@ -421,6 +421,7 @@ describe("Portal", () => {
addOutsideDiv(fixture);
const parent = await mount(Parent, fixture);
expect(steps).toEqual(["parent:mounted"]);
expect(fixture.innerHTML).toBe('<div id="outside"></div><div></div>');
parent.state.hasChild = true;
await nextTick();
@@ -430,6 +431,7 @@ describe("Portal", () => {
"child:mounted",
"parent:patched",
]);
expect(fixture.innerHTML).toBe('<div id="outside"><span>1</span></div><div></div>');
parent.state.val = 2;
await nextTick();
@@ -443,6 +445,7 @@ describe("Portal", () => {
"child:patched",
"parent:patched",
]);
expect(fixture.innerHTML).toBe('<div id="outside"><span>2</span></div><div></div>');
parent.state.hasChild = false;
await nextTick();
@@ -459,6 +462,7 @@ describe("Portal", () => {
"child:willUnmount",
"parent:patched",
]);
expect(fixture.innerHTML).toBe('<div id="outside"></div><div></div>');
});
test("portal destroys on crash", async () => {
+482 -11
View File
@@ -171,6 +171,8 @@ describe("Reactivity", () => {
expect(n).toBe(2);
});
// Skipped because the hasOwnProperty trap is tripped by *writing*. We
// (probably) do not want to subscribe to changes on writes.
test.skip("hasOwnProperty causes the key's presence to be observed", async () => {
let n = 0;
const state = createReactive({}, () => n++);
@@ -1093,18 +1095,482 @@ describe("Reactivity", () => {
expect(n).toBe(1);
expect(state.k).toEqual({ n: 2 });
});
});
test("can add collections set/weakset/map/weakmap in a reactive object", () => {
const rawSet = new Set();
const rawWeakSet = new WeakSet();
const rawMap = new Map();
const rawWeakMap = new WeakMap();
describe("Collections", () => {
describe("Set", () => {
test("can make reactive Set", () => {
const set = new Set<number>();
const obj = reactive(set);
expect(obj).not.toBe(set);
});
const obj = reactive({ rawSet, rawWeakSet, rawMap, rawWeakMap });
expect(obj.rawSet).toBe(rawSet);
expect(obj.rawWeakSet).toBe(rawWeakSet);
expect(obj.rawMap).toBe(rawMap);
expect(obj.rawWeakMap).toBe(rawWeakMap);
test("can read", async () => {
const state = reactive(new Set([1]));
expect(state.has(1)).toBe(true);
expect(state.has(0)).toBe(false);
});
test("can add entries", () => {
const state = reactive(new Set());
state.add(1);
expect(state.has(1)).toBe(true);
});
test("can remove entries", () => {
const state = reactive(new Set([1]));
state.delete(1);
expect(state.has(1)).toBe(false);
});
test("can clear entries", () => {
const state = reactive(new Set([1]));
expect(state.size).toBe(1);
state.clear();
expect(state.size).toBe(0);
});
test("act like a Set", () => {
const state = reactive(new Set([1]));
expect([...state.entries()]).toEqual([[1, 1]]);
expect([...state.values()]).toEqual([1]);
expect([...state.keys()]).toEqual([1]);
expect([...state]).toEqual([1]); // Checks Symbol.iterator
expect(state.size).toBe(1);
expect(typeof state).toBe("object");
expect(state).toBeInstanceOf(Set);
});
test("reactive Set contains its keys", () => {
const state = reactive(new Set([{}]));
expect(state.has(state.keys().next().value)).toBe(true);
});
test("reactive Set contains its values", () => {
const state = reactive(new Set([{}]));
expect(state.has(state.values().next().value)).toBe(true);
});
test("reactive Set contains its entries' keys and values", () => {
const state = reactive(new Set([{}]));
const [key, val] = state.entries().next().value;
expect(state.has(key)).toBe(true);
expect(state.has(val)).toBe(true);
});
test("checking for a key subscribes the callback to changes to that key", () => {
const observer = jest.fn();
const state = reactive(new Set([1]), observer);
expect(state.has(2)).toBe(false); // subscribe to 2
expect(observer).toHaveBeenCalledTimes(0);
state.add(2);
expect(observer).toHaveBeenCalledTimes(1);
expect(state.has(2)).toBe(true); // subscribe to 2
state.delete(2);
expect(observer).toHaveBeenCalledTimes(2);
state.add(2);
expect(state.has(2)).toBe(true); // subscribe to 2
state.clear();
expect(observer).toHaveBeenCalledTimes(3);
expect(state.has(2)).toBe(false); // subscribe to 2
state.clear(); // clearing again doesn't notify again
expect(observer).toHaveBeenCalledTimes(3);
state.add(3); // setting unobserved key doesn't notify
expect(observer).toHaveBeenCalledTimes(3);
});
test("iterating on keys returns reactives", async () => {
const obj = { a: 2 };
const observer = jest.fn();
const state = reactive(new Set([obj]), observer);
const reactiveObj = state.keys().next().value;
expect(reactiveObj).not.toBe(obj);
expect(toRaw(reactiveObj as any)).toBe(obj);
reactiveObj.a = 0;
expect(observer).toHaveBeenCalledTimes(0);
reactiveObj.a; // observe key "a" in sub-reactive;
reactiveObj.a = 1;
expect(observer).toHaveBeenCalledTimes(1);
reactiveObj.a = 1; // setting same value again shouldn't notify
expect(observer).toHaveBeenCalledTimes(1);
});
test("iterating on values returns reactives", async () => {
const obj = { a: 2 };
const observer = jest.fn();
const state = reactive(new Set([obj]), observer);
const reactiveObj = state.values().next().value;
expect(reactiveObj).not.toBe(obj);
expect(toRaw(reactiveObj as any)).toBe(obj);
reactiveObj.a = 0;
expect(observer).toHaveBeenCalledTimes(0);
reactiveObj.a; // observe key "a" in sub-reactive;
reactiveObj.a = 1;
expect(observer).toHaveBeenCalledTimes(1);
reactiveObj.a = 1; // setting same value again shouldn't notify
expect(observer).toHaveBeenCalledTimes(1);
});
test("iterating on entries returns reactives", async () => {
const obj = { a: 2 };
const observer = jest.fn();
const state = reactive(new Set([obj]), observer);
const [reactiveObj, reactiveObj2] = state.entries().next().value;
expect(reactiveObj2).toBe(reactiveObj);
expect(reactiveObj).not.toBe(obj);
expect(toRaw(reactiveObj as any)).toBe(obj);
reactiveObj.a = 0;
expect(observer).toHaveBeenCalledTimes(0);
reactiveObj.a; // observe key "a" in sub-reactive;
reactiveObj.a = 1;
expect(observer).toHaveBeenCalledTimes(1);
reactiveObj.a = 1; // setting same value again shouldn't notify
expect(observer).toHaveBeenCalledTimes(1);
});
test("iterating on reactive Set returns reactives", async () => {
const obj = { a: 2 };
const observer = jest.fn();
const state = reactive(new Set([obj]), observer);
const reactiveObj = state[Symbol.iterator]().next().value;
expect(reactiveObj).not.toBe(obj);
expect(toRaw(reactiveObj as any)).toBe(obj);
reactiveObj.a = 0;
expect(observer).toHaveBeenCalledTimes(0);
reactiveObj.a; // observe key "a" in sub-reactive;
reactiveObj.a = 1;
expect(observer).toHaveBeenCalledTimes(1);
reactiveObj.a = 1; // setting same value again shouldn't notify
expect(observer).toHaveBeenCalledTimes(1);
});
});
describe("WeakSet", () => {
test("cannot make reactive WeakSet", () => {
const set = new WeakSet();
expect(() => reactive(set)).toThrowError("Cannot make the given value reactive");
});
test("WeakSet in reactive is original WeakSet", () => {
const obj = { set: new WeakSet() };
const state = reactive(obj);
expect(state.set).toBe(obj.set);
});
});
describe("Map", () => {
test("can make reactive Map", () => {
const map = new Map();
const obj = reactive(map);
expect(obj).not.toBe(map);
});
test("can read", async () => {
const state = reactive(new Map([[1, 0]]));
expect(state.has(1)).toBe(true);
expect(state.has(0)).toBe(false);
expect(state.get(1)).toBe(0);
expect(state.get(0)).toBeUndefined();
});
test("can add entries", () => {
const state = reactive(new Map());
state.set(1, 2);
expect(state.has(1)).toBe(true);
expect(state.get(1)).toBe(2);
});
test("can remove entries", () => {
const state = reactive(new Map([[1, 2]]));
state.delete(1);
expect(state.has(1)).toBe(false);
expect(state.get(1)).toBeUndefined();
});
test("can clear entries", () => {
const state = reactive(new Map([[1, 2]]));
expect(state.size).toBe(1);
state.clear();
expect(state.size).toBe(0);
});
test("act like a Map", () => {
const state = reactive(new Map([[1, 2]]));
expect([...state.entries()]).toEqual([[1, 2]]);
expect([...state.values()]).toEqual([2]);
expect([...state.keys()]).toEqual([1]);
expect([...state]).toEqual([[1, 2]]); // Checks Symbol.iterator
expect(state.size).toBe(1);
expect(typeof state).toBe("object");
expect(state).toBeInstanceOf(Map);
});
test("reactive Map contains its keys", () => {
const state = reactive(new Map([[{}, 1]]));
expect(state.has(state.keys().next().value)).toBe(true);
});
test("reactive Map values are equal to doing a get on the appropriate key", () => {
const state = reactive(new Map([[1, {}]]));
expect(state.get(1)).toBe(state.values().next().value);
});
test("reactive Map contains its entries' keys, and the associated value is the same as doing get", () => {
const state = reactive(new Map([[{}, {}]]));
const [key, val] = state.entries().next().value;
expect(state.has(key)).toBe(true);
expect(val).toBe(state.get(key));
});
test("checking for a key with 'has' subscribes the callback to changes to that key", () => {
const observer = jest.fn();
const state = reactive(new Map([[1, 2]]), observer);
expect(state.has(2)).toBe(false); // subscribe to 2
expect(observer).toHaveBeenCalledTimes(0);
state.set(2, 3);
expect(observer).toHaveBeenCalledTimes(1);
expect(state.has(2)).toBe(true); // subscribe to 2
state.delete(2);
expect(observer).toHaveBeenCalledTimes(2);
state.set(2, 3);
expect(state.has(2)).toBe(true); // subscribe to 2
state.clear();
expect(observer).toHaveBeenCalledTimes(3);
expect(state.has(2)).toBe(false); // subscribe to 2
state.clear(); // clearing again doesn't notify again
expect(observer).toHaveBeenCalledTimes(3);
state.set(3, 4); // setting unobserved key doesn't notify
expect(observer).toHaveBeenCalledTimes(3);
});
test("checking for a key with 'get' subscribes the callback to changes to that key", () => {
const observer = jest.fn();
const state = reactive(new Map([[1, 2]]), observer);
expect(state.get(2)).toBeUndefined(); // subscribe to 2
expect(observer).toHaveBeenCalledTimes(0);
state.set(2, 3);
expect(observer).toHaveBeenCalledTimes(1);
expect(state.get(2)).toBe(3); // subscribe to 2
state.delete(2);
expect(observer).toHaveBeenCalledTimes(2);
state.delete(2); // deleting again doesn't notify again
expect(observer).toHaveBeenCalledTimes(2);
state.set(2, 3);
expect(state.get(2)).toBe(3); // subscribe to 2
state.clear();
expect(observer).toHaveBeenCalledTimes(3);
expect(state.get(2)).toBeUndefined(); // subscribe to 2
state.clear(); // clearing again doesn't notify again
expect(observer).toHaveBeenCalledTimes(3);
state.set(3, 4); // setting unobserved key doesn't notify
expect(observer).toHaveBeenCalledTimes(3);
});
test("getting values returns a reactive", async () => {
const obj = { a: 2 };
const observer = jest.fn();
const state = reactive(new Map([[1, obj]]), observer);
const reactiveObj = state.get(1)!;
expect(reactiveObj).not.toBe(obj);
expect(toRaw(reactiveObj as any)).toBe(obj);
reactiveObj.a = 0;
expect(observer).toHaveBeenCalledTimes(0);
reactiveObj.a; // observe key "a" in sub-reactive;
reactiveObj.a = 1;
expect(observer).toHaveBeenCalledTimes(1);
reactiveObj.a = 1; // setting same value again shouldn't notify
expect(observer).toHaveBeenCalledTimes(1);
});
test("iterating on values returns reactives", async () => {
const obj = { a: 2 };
const observer = jest.fn();
const state = reactive(new Map([[1, obj]]), observer);
const reactiveObj = state.values().next().value;
expect(reactiveObj).not.toBe(obj);
expect(toRaw(reactiveObj as any)).toBe(obj);
reactiveObj.a = 0;
expect(observer).toHaveBeenCalledTimes(0);
reactiveObj.a; // observe key "a" in sub-reactive;
reactiveObj.a = 1;
expect(observer).toHaveBeenCalledTimes(1);
reactiveObj.a = 1; // setting same value again shouldn't notify
expect(observer).toHaveBeenCalledTimes(1);
});
test("iterating on keys returns reactives", async () => {
const obj = { a: 2 };
const observer = jest.fn();
const state = reactive(new Map([[obj, 1]]), observer);
const reactiveObj = state.keys().next().value;
expect(reactiveObj).not.toBe(obj);
expect(toRaw(reactiveObj as any)).toBe(obj);
reactiveObj.a = 0;
expect(observer).toHaveBeenCalledTimes(0);
reactiveObj.a; // observe key "a" in sub-reactive;
reactiveObj.a = 1;
expect(observer).toHaveBeenCalledTimes(1);
reactiveObj.a = 1; // setting same value again shouldn't notify
expect(observer).toHaveBeenCalledTimes(1);
});
test("iterating on reactive map returns reactives", async () => {
const keyObj = { a: 2 };
const valObj = { a: 2 };
const observer = jest.fn();
const state = reactive(new Map([[keyObj, valObj]]), observer);
const [reactiveKeyObj, reactiveValObj] = state[Symbol.iterator]().next().value;
expect(reactiveKeyObj).not.toBe(keyObj);
expect(reactiveValObj).not.toBe(valObj);
expect(toRaw(reactiveKeyObj as any)).toBe(keyObj);
expect(toRaw(reactiveValObj as any)).toBe(valObj);
reactiveKeyObj.a = 0;
reactiveValObj.a = 0;
expect(observer).toHaveBeenCalledTimes(0);
reactiveKeyObj.a; // observe key "a" in key sub-reactive;
reactiveKeyObj.a = 1;
expect(observer).toHaveBeenCalledTimes(1);
reactiveValObj.a; // observe key "a" in val sub-reactive;
reactiveValObj.a = 1;
expect(observer).toHaveBeenCalledTimes(2);
reactiveKeyObj.a = 1; // setting same value again shouldn't notify
reactiveValObj.a = 1;
expect(observer).toHaveBeenCalledTimes(2);
});
test("iterating on entries returns reactives", async () => {
const keyObj = { a: 2 };
const valObj = { a: 2 };
const observer = jest.fn();
const state = reactive(new Map([[keyObj, valObj]]), observer);
const [reactiveKeyObj, reactiveValObj] = state.entries().next().value;
expect(reactiveKeyObj).not.toBe(keyObj);
expect(reactiveValObj).not.toBe(valObj);
expect(toRaw(reactiveKeyObj as any)).toBe(keyObj);
expect(toRaw(reactiveValObj as any)).toBe(valObj);
reactiveKeyObj.a = 0;
reactiveValObj.a = 0;
expect(observer).toHaveBeenCalledTimes(0);
reactiveKeyObj.a; // observe key "a" in key sub-reactive;
reactiveKeyObj.a = 1;
expect(observer).toHaveBeenCalledTimes(1);
reactiveValObj.a; // observe key "a" in val sub-reactive;
reactiveValObj.a = 1;
expect(observer).toHaveBeenCalledTimes(2);
reactiveKeyObj.a = 1; // setting same value again shouldn't notify
reactiveValObj.a = 1;
expect(observer).toHaveBeenCalledTimes(2);
});
});
describe("WeakMap", () => {
test("can make reactive WeakMap", () => {
const map = new WeakMap();
const obj = reactive(map);
expect(obj).not.toBe(map);
});
test("can read", async () => {
const obj = {};
const obj2 = {};
const state = reactive(new WeakMap([[obj, 0]]));
expect(state.has(obj)).toBe(true);
expect(state.has(obj2)).toBe(false);
expect(state.get(obj)).toBe(0);
expect(state.get(obj2)).toBeUndefined();
});
test("can add entries", () => {
const obj = {};
const state = reactive(new WeakMap());
state.set(obj, 2);
expect(state.has(obj)).toBe(true);
expect(state.get(obj)).toBe(2);
});
test("can remove entries", () => {
const obj = {};
const state = reactive(new WeakMap([[obj, 2]]));
state.delete(obj);
expect(state.has(obj)).toBe(false);
expect(state.get(obj)).toBeUndefined();
});
test("act like a WeakMap", () => {
const obj = {};
const state = reactive(new WeakMap([[obj, 2]]));
expect(typeof state).toBe("object");
expect(state).toBeInstanceOf(WeakMap);
});
test("checking for a key with 'has' subscribes the callback to changes to that key", () => {
const observer = jest.fn();
const obj = {};
const obj2 = {};
const obj3 = {};
const state = reactive(new WeakMap([[obj2, 2]]), observer);
expect(state.has(obj)).toBe(false); // subscribe to obj
expect(observer).toHaveBeenCalledTimes(0);
state.set(obj, 3);
expect(observer).toHaveBeenCalledTimes(1);
expect(state.has(obj)).toBe(true); // subscribe to obj
state.delete(obj);
expect(observer).toHaveBeenCalledTimes(2);
state.set(obj, 3);
state.delete(obj);
expect(observer).toHaveBeenCalledTimes(2);
expect(state.has(obj)).toBe(false); // subscribe to obj
state.set(obj3, 4); // setting unobserved key doesn't notify
expect(observer).toHaveBeenCalledTimes(2);
});
test("checking for a key with 'get' subscribes the callback to changes to that key", () => {
const observer = jest.fn();
const obj = {};
const obj2 = {};
const obj3 = {};
const state = reactive(new WeakMap([[obj2, 2]]), observer);
expect(state.get(obj)).toBeUndefined(); // subscribe to obj
expect(observer).toHaveBeenCalledTimes(0);
state.set(obj, 3);
expect(observer).toHaveBeenCalledTimes(1);
expect(state.get(obj)).toBe(3); // subscribe to obj
state.delete(obj);
expect(observer).toHaveBeenCalledTimes(2);
state.set(obj, 3);
state.delete(obj);
expect(observer).toHaveBeenCalledTimes(2);
expect(state.get(obj)).toBeUndefined(); // subscribe to obj
state.set(obj3, 4); // setting unobserved key doesn't notify
expect(observer).toHaveBeenCalledTimes(2);
});
test("getting values returns a reactive", async () => {
const keyObj = {};
const valObj = { a: 2 };
const observer = jest.fn();
const state = reactive(new WeakMap([[keyObj, valObj]]), observer);
const reactiveObj = state.get(keyObj)!;
expect(reactiveObj).not.toBe(valObj);
expect(toRaw(reactiveObj as any)).toBe(valObj);
reactiveObj.a = 0;
expect(observer).toHaveBeenCalledTimes(0);
reactiveObj.a; // observe key "a" in sub-reactive;
reactiveObj.a = 1;
expect(observer).toHaveBeenCalledTimes(1);
reactiveObj.a = 1; // setting same value again shouldn't notify
expect(observer).toHaveBeenCalledTimes(1);
});
});
});
@@ -1131,6 +1597,11 @@ describe("toRaw", () => {
expect(reactiveObj).not.toBe(obj);
expect(toRaw(reactiveObj as Reactive<typeof obj>)).toBe(obj);
});
test("giving a non reactive to toRaw return the object itself", () => {
const obj = { value: 1 };
expect(toRaw(obj as Reactive<typeof obj>)).toBe(obj);
});
});
describe("Reactivity: useState", () => {
@@ -1652,7 +2123,7 @@ describe("Reactivity: useState", () => {
expect([...steps]).toEqual(["list"]);
await nextTick();
expect(fixture.innerHTML).toBe("<div><div>3</div> Total: 3 Count: 1</div>");
expect([...steps]).toEqual(["list", "quantity1"]);
expect([...steps]).toEqual(["list"]);
steps.clear();
secondQuantity.quantity = 2;
+3 -3
View File
@@ -24,7 +24,6 @@ class Root extends Component {
}
}
// Application setup
mount(Root, document.body, { templates: TEMPLATES, dev: true });`;
const COMPONENTS_XML = /*xml*/`
@@ -934,7 +933,7 @@ const env = {
ui: createUI()
};
mount(Root, document.body, { templates: TEMPLATES, env });
mount(Root, document.body, { templates: TEMPLATES, env, dev: true });
`;
const RESPONSIVE_XML = /*xml*/`
@@ -1741,7 +1740,8 @@ class Root extends Component {
}
mount(Root, document.body, { templates: TEMPLATES, dev: true });
// dev=false for benchmarking. we don't want to benchmark dev code!
mount(Root, document.body, { templates: TEMPLATES, dev: false });
`;
+1 -1
View File
@@ -106,7 +106,7 @@ async function startRelease() {
// ---------------------------------------------------------------------------
log(`Step 7/${STEPS}: Creating the release...`);
const relaseResult = await execCommand(`gh release create v${next} dist/*.js ${draft} -F release-notes.md`);
const relaseResult = await execCommand(`gh release create v${next} dist/*.js ${draft} -F ${REL_NOTES_FILE}`);
if (relaseResult !== 0) {
logError("github release failed. Aborting.");
return;