Compare commits

..

192 Commits

Author SHA1 Message Date
Géry Debongnie e1fc513249 [IMP] big change: shallow render
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-01-21 09:48:53 +01:00
Géry Debongnie 73c37c025c [REF] move useState into component_node.ts 2022-01-21 09:48:53 +01:00
Lucas Perais (lpe) b88f7a03e9 [FIX] compiler: svg in new block takes the right namespace 2022-01-21 09:32:22 +01:00
Lucas Perais (lpe) 055cbda750 [FIX] compiler: t-key on a sub-domnode pushes an anchor in parent block 2022-01-20 18:13:01 +01:00
Géry Debongnie 45f6a8e97a [REF] utils: move batched from reactivity to utils 2022-01-20 15:48:50 +01:00
Géry Debongnie 6091912c54 [IMP] component: improve error message when invalid handler 2022-01-20 15:48:50 +01:00
Géry Debongnie 586f90f6d1 [FIX] doc: fix broken link, and fix doc link checker test 2022-01-20 12:41:31 +01:00
Géry Debongnie e62a0ca2d9 [DOC] update changelog (add browser removal to changes) 2022-01-20 12:29:51 +01:00
Géry Debongnie 3a4ee160ed [FIX] playground: update window management example 2022-01-20 12:29:51 +01:00
Géry Debongnie 5f24caf40d [FIX] scheduler: make sure raf is bound to window 2022-01-20 11:06:59 +01:00
Géry Debongnie 8e36a11b6e [REF] scheduler: capture requestAnimationFrame asap
This is useful to prevent interactions with other testing code.
2022-01-20 10:19:55 +01:00
Géry Debongnie 9a54afcdf5 [FIX] playground: update example to owl 2 2022-01-19 16:50:08 +01:00
Géry Debongnie 3eefa4b153 [DOC] improve useEffect doc 2022-01-19 16:50:08 +01:00
Géry Debongnie 2ffb94ed98 [FIX] reactivity: export Reactive type 2022-01-19 16:50:08 +01:00
Géry Debongnie 6a15874d23 [FIX] typing: Component class should be generic on Props and Env
Otherwise, it prevents proper typing with typescript
2022-01-19 14:46:26 +01:00
Géry Debongnie 07d34248ae [DOC] update changelog content 2022-01-19 14:45:53 +01:00
Géry Debongnie dfc090bb12 [IMP] portal: ensure that destroy is synchronous 2022-01-19 14:11:59 +01:00
Géry Debongnie 7b3593ff8f [DOC] document synthetic events 2022-01-19 14:00:24 +01:00
Géry Debongnie b06791c950 [IMP] components: crash when using unknown suffix/modifiers 2022-01-19 14:00:24 +01:00
Lucas Perais (lpe) f7843c7c00 [FIX] component, error_handling: do not cancel the error fiber twice 2022-01-19 12:28:28 +01:00
Géry Debongnie ca9d4ea762 [IMP] doc: add changelog to doc test, update changelog 2022-01-19 11:31:53 +01:00
Géry Debongnie 7a407a762d [IMP] ci: fails if circular dependencies are found in build 2022-01-19 10:29:41 +01:00
Géry Debongnie 8847824fb7 [FIX] remove circular dependency 2022-01-19 10:03:30 +01:00
Géry Debongnie 55b068faeb [DOC] remove reference to catchError, fix mistake in changelog 2022-01-19 10:03:30 +01:00
Lucas Perais (lpe) dbee8f50d1 [FIX] components: cascading render after microtaskTick (makeChildFiber)
Co-authored-by: Samuel Degueldre <sad@odoo.com>
Co-authored-by: François Georis <fge@odoo.com>
2022-01-19 09:23:17 +01:00
Géry Debongnie f5fec02d4c [DOC] update changelog 2022-01-19 09:12:26 +01:00
Géry Debongnie 651c53ebbf [DOC] update translations page 2022-01-19 09:12:26 +01:00
Géry Debongnie 3119497508 [DOC] add more information to the slots page 2022-01-19 09:12:26 +01:00
Michael (mcm) 057e6944d6 [FIX] bind lifecycle callbacks to component
Before this commit, some of the callbacks were bound to the component
and some were not.
This commit makes all the callbacks bind to the component.
2022-01-18 15:02:07 +01:00
Géry Debongnie 83d38a6f48 [DOC] reorganize and update documentation to owl 2 2022-01-18 11:07:35 +01:00
Jorge Pinna Puissant 9577d70b4b [IMP] portal: compile t-portal in an internal Component Portal
This commit also clean-up the deepRemove for the Portal that is not
needed any more.
2022-01-17 16:04:01 +01:00
Géry Debongnie 6ff6d59895 [FIX] components: only call handlers if component is mounted 2022-01-17 15:46:18 +01:00
Géry Debongnie 7ba0c9f8ba [FIX] blockdom: toString method in multi could crash 2022-01-17 13:55:39 +01:00
Lucas Perais (lpe) 79a51f2317 [FIX] app: t_call recursive template is bound to the correct this 2022-01-17 10:46:08 +01:00
Lucas Perais (lpe) 483335df6c [FIX] compiler: slot are called with a specific and different key 2022-01-14 15:46:02 +01:00
Samuel Degueldre 287a6d5ac4 [FIX] code_generator: stop matching other variables prefix
Previously, we would replace block declarations in some contexts with
the variable alone, and decalres the variable higher in the generated
code. Issues arise because whe sometimes try to replace "let b2" with
"b2" but end up matching "let b20" which is incorrect.

This commit fixes that by adding a space to the text that we are trying
to match ("let b2 " won't match "let b20")
2022-01-14 09:58:28 +01:00
Lucas Perais (lpe) 68684a9a45 [FIX] component, fiber: subchildren should also patch and destroy their children
Have a GrandParent which controls whether one of its GrandChildren is displayed or not.
First, the GrandChild is displayed. Then, change the state of the GrandParent in order to kill
the GrandChild.

Before this commit the GrandChild is only removed from the DOM, as bdom correctly works.
But it is not destroyed.

After this commit, the GrandChild is correctly destroyed.
2022-01-14 09:51:55 +01:00
Lucas Perais (lpe) e5d773daa8 [FIX] components tests: place tests in right submodule 2022-01-14 09:51:55 +01:00
Jorge Pinna Puissant 00ffab1f64 [IMP] portal: portal as a Directive
Before this commit, portal was a Component, now is a directive.
This commit also clean some unused code, and fix an issue on the clean
optimization when a portal is found in a condition or a loop.
2022-01-13 15:02:11 +01:00
Lucas Perais (lpe) a226f92def [FIX] components: avoid leaks when children are outdated/destroyed
Every use case involving some sort of key set on a component would give birth to a leak in an async context:
- If a key of a component changed, the outdated one was never destroyed.
- destroyed component were never removed from their parent's reference map.

This commit solves both issues, that are tightly linked anyway.
2022-01-13 10:17:47 +01:00
Lucas Perais (lpe) 1749bce155 [FIX] test/helpers: useLogLifeCycle supports custom key 2022-01-13 10:17:47 +01:00
Géry Debongnie c00127fa1e [IMP] tooling: add testTimeout argument to test:debug command 2022-01-13 10:05:10 +01:00
Géry Debongnie 0b4b7899f6 [FIX] portal: properly handle errors
Before this commit, Portal overrode the _render function for its
component node, which means it bypassed the error handling mechanism
that was implemented in that method.  It could have been fixed by
duplicating the error handling code as well, but a better solution in my
opinion is to simply override the renderFn function.  This is closer to
the actual intent of the portal implementation: wrap the result of the
rendering in a VPortal vnode.
2022-01-12 08:51:28 +01:00
Lucas Perais (lpe) 5c324fa075 [FIX] app, components: dynamic t-call should propagate the key
Have a Component which has a Component node, and a dynamic t-call itself having
a Component node.

Before this commit, both children had the same `key`, (as in the key in parent.children, which registers on the parent all its children).

As a result, the scheduler was endlessly hanging.

After this commit, it works as expected.
2022-01-10 15:29:25 +01:00
Géry Debongnie 3945c009ed [REF] compiler: factorize a common pattern 2022-01-10 12:31:37 +01:00
Géry Debongnie 5b1132f01a [FIX] compiler: handle t-set as functions 2021-12-28 13:50:35 +01:00
Géry Debongnie f014b1a33e [DOC] update quick_start and how to test pages 2021-12-22 15:03:38 +01:00
Géry Debongnie 3f09a953b0 [REM] doc: remove overview page 2021-12-22 15:03:38 +01:00
Géry Debongnie b8e7ee5ff7 [DOC] update the tutorial todo app 2021-12-22 15:03:38 +01:00
Géry Debongnie 7fdca35a74 [FIX] reactivity: work even if no callback is given 2021-12-22 14:59:28 +01:00
Géry Debongnie 489e20843c [FIX] components: make sure t-ref work with t-if/t-else 2021-12-22 13:58:02 +01:00
Samuel Degueldre 34b781aeed [IMP] compiler: scope generated ids to their prefix
This means that unrelated ids (eg the id of a template, variable or key)
not longer share the same incrementing counter, meaning that you no
longer see a variable named "v2" unless another variable "v1" was
generated previously, this is also true for block data.
2021-12-22 13:30:09 +01:00
Géry Debongnie e8b0f31da6 [IMP] compiler: improve generated compiled code 2021-12-22 13:30:09 +01:00
Géry Debongnie d160c4a628 [FIX] useEffect: can depend on dom dependencies
Because the dependencies are now computed in patched.
2021-12-22 10:47:28 +01:00
Géry Debongnie 4542171a31 [FIX] portal: do not crash in dev mode
Before this commit, the props validation would fail in dev mode because
it did not expect a slot prop.
2021-12-21 21:43:46 +01:00
Géry Debongnie 0b1c4dd4ef [IMP] app: improve API, small refactoring 2021-12-21 12:12:48 +01:00
Géry Debongnie f4da50d350 [REF] build: do not output const enum definitions
We only use 2 const enums in the codebase, but they are defined in the
output, even though this is not useful in any way. This commit reduces
the final output by about 30 loc.
2021-12-21 09:09:36 +01:00
Géry Debongnie f2921abda8 [REM] component: remove support for css tag 2021-12-21 09:09:36 +01:00
Géry Debongnie 107200fd94 [IMP] components: improve props validation
to be able to specify that additional props are allowed
2021-12-21 09:02:45 +01:00
Lucas Perais (lpe) 0f8c859d5f [FIX] component: error_handling when an error is rethrown 2021-12-20 16:55:50 +01:00
Géry Debongnie cca8438d38 [REF] components: remove .el 2021-12-20 14:43:21 +01:00
Géry Debongnie a727347d60 [REF] tests: improve test helpers
- remove snapshotApp
- remove addTemplates
- simplify helpers
- make sure snapshotted templates are snapshotted with the app config
2021-12-20 12:43:36 +01:00
Lucas Perais (lpe) f19de73b0f [FIX] fiber, lifecycle: trigger a render during the fiber.complete
Have a component which does a render in its onWillPatch, onPatched, onMounted hooks.

Before this commit, the result was incorrect: the second rendering was not taken into account.

After this commit, those renderings are correctly applied at the price of a delayed render when the fiber
is in a critical state.
2021-12-20 10:54:51 +01:00
Géry Debongnie a8ffcafd23 [FIX] blockdom: properly handle falsy attributes
This commit fixes some issues with falsy attributes not being properly
set/removed in various situations. Also, the behaviour was not
consistent between normal attribute (key/value) and generic attributes
(pair or object)
2021-12-16 15:07:27 +01:00
Géry Debongnie a2f01ef4ad [FIX] components: improve error handling
Owl provides a way to manage errors occuring in component lifecycle
methods. However, before this commit, these errors were not always
logged or visible, which is very annoying in the common developer
workflow (doing something, checking it works, seeing no error but a
broken interface).

In this commit, we make sure errors are logged/throws in all cases:

- if an error occurs in a mounting operation => the promise is rejected
(which will log the error)
- if an error occurs after the mounting operation and is not handled by
any error handlers => the error will be logged (with console.error).
Also, in that case, this commit adds a warning to explain that owl
destroys the root component, which will help developers understanding
what happened.
2021-12-16 13:29:31 +01:00
Géry Debongnie d7de25e867 [FIX] compiler: properly handle <t> tags in some cases
The problem was that the compiler is based on the assumption that the
multi block received by the parser only occurs in some cases
where the structure of the template require a multi block, and it does
not work when we have random multiblock elsewhere.

We could fix the issue by modifying the code generator code to support
these usecases, or by simply removing these cases in the parser. Since
this seems more efficient, this is the approach taken by this commit.

Note that it was a good opportunity to simplify the parser.
2021-12-15 15:32:56 +01:00
Géry Debongnie 424bc480e2 [DOC] update changelog 2021-12-14 16:03:10 +01:00
Géry Debongnie 421f400766 [DOC] reorganize doc, unskip test, fix some links 2021-12-14 09:45:25 +01:00
Géry Debongnie c37f3445f6 [FIX] blockdom: ignore attributes with undefined value 2021-12-13 15:07:03 +01:00
Géry Debongnie 4cde06d685 [IMP] component: add .bind suffix to props for easy binding 2021-12-13 12:43:23 +01:00
Lucas Perais (lpe) 7b95315b87 adapt to fix and to fixup 2021-12-13 12:39:43 +01:00
Géry Debongnie 09761ddd8e fixup, maybe 2021-12-13 12:39:43 +01:00
Lucas Perais (lpe) b3c6ec2b48 [FIX] component: render in delayed willUpdateProps
Have a child component on which a render is triggered.
This component delays its willUpdateProps and makes a rendering during the willUpdateProps

Before this commit, renderings of the child were inconsistent across
its parent's renderings.

After this commit, it works as expected.
2021-12-13 12:39:43 +01:00
Lucas Perais (lpe) b20462ada6 [FIX] app: factorize to allow smoother developments in projects
It should be usefull to allow developpers to implement mounting/unmounting
if they wish to.
2021-12-13 09:49:48 +01:00
Lucas Perais (lpe) 25000b36be [FIX] blockdom: do not propagate svg namespace to siblings 2021-12-03 14:01:44 +01:00
Lucas Perais (lpe) 144d4a253c [FIX] hooks: useSubEnv supports arbitrary descriptors in env
Before this commit, when defining a getter in the env passed to useSubEnv,
the value was read, losing the definition of the property.

After this commit, declaring a getter in the env works as expected:
the property stays a getter.
2021-12-03 08:06:29 +01:00
Lucas Perais (lpe) 9d48bda227 [FIX] app: support for arbitrary descriptors in env
Before this commit, when defining a getter in the env passed to the App,
the value was read, losing the definition of the property.

After this commit, declaring a getter in the env works as expected:
the property stays a getter.
2021-12-03 08:06:29 +01:00
Lucas Perais (lpe) c8db663869 [FIX] parser: correctly parse pre node within a div with new lines 2021-12-03 08:03:45 +01:00
Lucas Perais (lpe) 247200194f [FIX] component: error handling in class inheritance
Before this commit, class inheritance when using the onError hook was unclear nay wrong.

After this commit, error handlers are called from the bottom up  in the inheritance hierarchy.
If a handler doesn't rethrow the error, the handling stops there and no other handler is called.
If a handler does rethrow, the handlers declared in a parent class are executed.
2021-12-01 17:29:26 +01:00
Géry Debongnie 60b8817ac0 [REF] compiler: simplify all compiled templates 2021-12-01 17:25:31 +01:00
Géry Debongnie e008966291 [FIX] compiler: allow t-if with empty content 2021-12-01 13:22:32 +01:00
Géry Debongnie e2fedc6eff [REF] components: unskip concurrency test 2021-12-01 13:22:32 +01:00
Géry Debongnie b3fb9a35bf [FIX] move error handling out of fiber, fix complicated mounted issues 2021-12-01 12:07:26 +01:00
Géry Debongnie 240259568e [FIX] component: improve error handling
In the following situation: A parent of B, B parent of C, with an error
when C is mounted, caught by B and retriggering a rendering in B, then
the onMounted hook of A wasn't properly called. This commit fixes this
problem.
2021-12-01 12:07:26 +01:00
Géry Debongnie 18fb67eaad [FIX] blockdom: properly handle references
Before this commit, there were situations where the reference numbers
were not properly set, which caused the blocks generated to crash
because the algorithm could not get correct references.
2021-12-01 09:34:55 +01:00
Géry Debongnie e946967867 [IMP] component: render does not return a promise anymore 2021-11-30 08:03:17 +01:00
Géry Debongnie 777b2aae5e [IMP] add support for top level comments 2021-11-29 15:36:45 +01:00
Géry Debongnie 0831bb54e3 [REF] component: remove onDestroyed, implement onWillDestroy 2021-11-29 14:59:01 +01:00
Géry Debongnie 03f34a38dc [TESTS] test lifecycle in reactivity tests 2021-11-29 08:42:47 +01:00
Géry Debongnie dcefd26bee [REF] tests: improve useLogLifecycle and helpers 2021-11-29 08:42:47 +01:00
Samuel Degueldre 922dab8e8f [FIX] reactivity: only call clearReactivesForCallback once on unmount 2021-11-26 16:22:38 +01:00
Samuel Degueldre 99740f9993 [FIX] reactivity: fix memory leak 2021-11-26 15:55:02 +01:00
Géry Debongnie 0b79b1c8fd [FIX] compiler: readd template name in compiled code 2021-11-26 09:17:49 +01:00
Géry Debongnie 5b0dce94cf [REF] code_generator: move generating code to CodeTarget
Before this commit, we had two places with code that generate a function
code. Now, all this code is moved in a method 'generateCode' on
CodeTarget.
2021-11-26 09:17:49 +01:00
Géry Debongnie a1d435c5a5 [FIX] compiler: call dynamic templates with correct this 2021-11-25 17:29:30 +01:00
Géry Debongnie 13c3178760 [FIX] slots: properly bind this in t-on arrow functions 2021-11-25 14:45:30 +01:00
Géry Debongnie 2b565ce1b4 [REF] component: small cleanup
This commit makes it simpler to understand the way fibers are assigned
to nodes.
2021-11-25 11:34:23 +01:00
Géry Debongnie cfcf2c6714 [FIX] component: concurrency issue
When a parent and a child were rendered at the same time, it was
possible for the 2 renders to decrement the same fiber internal
counter, which meant that the render was stalled.
2021-11-25 11:12:31 +01:00
Samuel Degueldre 92174559a1 [FIX] slots: allow t-call and components in slot default content 2021-11-24 15:47:51 +01:00
Bruno Boi 840348892f [IMP] owl: upgrade rollup-plugin-typescript2 to version 0.31.1 2021-11-24 11:45:12 +01:00
Samuel Degueldre b988a68b6f [IMP] parser: normalize document before parsing 2021-11-24 11:19:45 +01:00
Samuel Degueldre 7869a1f2c6 [IMP] components: add test for template string in props 2021-11-24 10:09:52 +01:00
Samuel Degueldre 9e81d14d50 [IMP] parser: throw when using unsupported directive on component 2021-11-24 10:09:52 +01:00
Samuel Degueldre 0e4a55ba09 [FIX] components: allow prop names that are not valid bare property name 2021-11-24 10:09:52 +01:00
Mathieu Duckerts-Antoine 6e9b68dafa [FIX] props: prop names can contain - 2021-11-23 10:20:45 +01:00
Bruno Boi ba7c9063c0 Update CHANGELOG.md 2021-11-23 10:09:39 +01:00
Mathieu Duckerts-Antoine 3a361876ad [IMP] slots: via prop 'slots'
The slot inner working has been reworked. A prop "slots" is now passed
explicitely to the component. It looks like

{ slotName_1: slotInfo_1, ..., slotName_m: slotInfo_m }

with the objects slotInfo_i with mandatory keys "__render", "__ctx",
and optional key "__scope" and possibly others.

Here is how a slotInfo object can be created:
A slotInfo object is normally created by setting in a template something
like

<div>
    <t t-set-slot="foo" t-set-scope="scope" param_1="var" param_2="3">
        content
        <t t-esc="scope.bool"/>
        <t t-esc="scope.num"/>
    </t>
</div>

and it will be used somewhere like

<div>
    <t t-esc="props.slots.foo.param_1"/>
    <t t-slot="foo" bool="other_var" num="5">
</div>

In the above example, the function "__render" produces the block dom
element for the content of the t-set-slot.
The context "__ctx" will have a key "scope" with value { bool: ..., num: 5 }
and "__scope" will be set to "scope".
2021-11-22 16:36:43 +01:00
Samuel Degueldre 58b8572f0a [FIX] components: capture context in prop expressions 2021-11-22 13:18:17 +01:00
Samuel Degueldre c23637e6d8 [FIX] components: throw on duplicate t-key instead of hanging the app 2021-11-22 11:11:49 +01:00
Géry Debongnie 4a4b1fbba5 [IMP] app: add templates in app config
Also, improve the parsing code
2021-11-22 10:56:16 +01:00
Géry Debongnie 536d9e1762 [REM] tools: remove benchmarks/debug script
They are either no longer relevant, or less useful than some
alternatives (such as the js framework benchmark project)
2021-11-22 10:56:16 +01:00
Lucas Perais (lpe) 6ed68372a6 [FIX] package: bump owl version to 2.0.0-alpha1 2021-11-22 10:49:51 +01:00
Lucas Perais (lpe) efd934d2b1 [FIX] tools: adapt playground to owl 2 2021-11-19 16:11:28 +01:00
Lucas Perais (lpe) dabc24cee3 [FIX] index, reactivity: export reactive function in index 2021-11-19 16:11:28 +01:00
Samuel Degueldre 7f49796a07 [IMP] misc: update typescript to 4.5.2 2021-11-19 14:42:37 +01:00
Géry Debongnie 757dffefac [IMP] components: rename onRender->onWillRender, add onRendered 2021-11-19 13:26:44 +01:00
Samuel Degueldre bdfe058279 [IMP] reactivity: overhaul reactivity system
This commit makes the reactivity system more fine grained and makes it
more eager to stop observing keys or objects when they are modified,
this results in fewer "false positive" notifications.
2021-11-19 13:20:37 +01:00
Bruno Boi 345c44b952 fixup! [IMP] svg namespace support 2021-11-19 12:47:51 +01:00
Bruno Boi ea74739d46 [IMP] svg namespace support 2021-11-19 11:55:18 +01:00
Géry Debongnie 93b53d8017 [FIX] remove cyclic dependency, improve error typing (#982) 2021-11-18 10:44:49 +01:00
Lucas Perais (lpe) c2284bc6f5 [FIX] component, fiber: error_handling at the Fiber level
Before this commit, errors triggered at the level of the fiber (as opposed to at the level
of a component's rendering), were handled as the very top level of the rendering, that is,
in the scheduler.
This was wrong because components below in the rendering tree would not have a chance to handle their
children's or their own errors.

After this commit, error triggered in willPatch, onMounted and onPatched are correctly handled
at the closest component to where they were thrown.
2021-11-17 11:40:29 +01:00
Géry Debongnie 48650da62e [REM] remove some outdated tests 2021-11-17 09:21:55 +01:00
Géry Debongnie 2edd6cb8f3 [MOV] move memo and portal to root folder 2021-11-17 09:21:55 +01:00
Géry Debongnie 4b0a37c542 [REM] tests: remove async root tests 2021-11-17 09:21:55 +01:00
Lucas Perais (lpe) 50c0e30936 [FIX] component: error_handling on current component
Have a Child Compnent which has one component that succeeds and another
one that fails at its instanciation.
The Child component handles the Errors by rendering itself.

Before this commit, the error handling algorithm made impossible for the scheduler to finish.
This was because the current fiber was still counted as ongoing, when it was actually completed.

After this commit, this use case is handled correctly.
2021-11-16 17:05:25 +01:00
Géry Debongnie e97335d7ab [DOC] add a change log 2021-11-16 16:36:20 +01:00
Lucas Perais (lpe) 6ea40a66da [IMP] app, compiler: introduce t-out
t-out automatically escaped content when it is a string not marked
with the `markup` function

t-out renders the raw content if it is a Block, or if it has been marked
with the `markup` funtion.

t-esc has been kept since it is safe and is optimized to render text nodes.

all t-raw calls are in fact the same as t-out.
2021-11-16 14:37:53 +01:00
Lucas Perais (lpe) 2806cda420 [FIX][BREAKING] t-esc on component is not supported anymore 2021-11-16 14:37:53 +01:00
Bruno Boi cb0b525f32 [IMP] templates: can load multiple at once and also from XMLDocument 2021-11-16 13:10:09 +01:00
Mathieu Duckerts-Antoine 30d28670e8 [REF] reactivity: new API 2021-11-15 17:14:19 +01:00
Mathieu Duckerts-Antoine 7b761a2f8b [REF] tests: remove debugger 2021-11-15 17:14:19 +01:00
Mathieu Duckerts-Antoine d834bb2ac4 [FIX] reactivity: memory leak
The deletion of a key in an observed object did clear the observers of
that key but did not clear the atoms created (if any) when the key existed
(e.g. on the key value if it was trackable). This can lead to a growing
set of atoms that are useless but kept in memory if a lot of keys are
added/deleted. The same thing can happen if a key value is changed many
times and the values are trackable.

Here we fix the problem by
- keeping tracks of the objects that have been observed by an external call
  to the method "atom" (we call them seeds).
- remove all observer atoms that are not seeds for observers of at least
  one key deletion or key value change.

Note the fix is in some sense partial: a user could use the "atom" primitive
making the new system uncapable of avoiding a leak (see test "atom on an
object with a getter 3" where a getter is used in a weird way in an
observed object).
2021-11-15 17:14:19 +01:00
Bruno Boi 6ae92fa4b3 [IMP] hooks: reintroduce useExternalListener 2021-11-15 16:15:14 +01:00
Bruno Boi 3ceb118ace [IMP] hooks: introduce useEffect
Co-Authored-By: Samuel Degueldre <sad@odoo.com>
2021-11-15 16:07:25 +01:00
Bruno Boi fa426b7fc0 [IMP] owl: mount util now takes an AppConfig 2021-11-15 16:07:25 +01:00
Bruno Boi d7403871fc [IMP] env: env is now frozen, useSubEnv does not affect user env 2021-11-15 13:21:46 +01:00
Géry Debongnie 6aeff21d9a [FIX] tests: remove useless log 2021-11-15 09:35:13 +01:00
Géry Debongnie 429e145b68 [FIX] portal: unskip some tests 2021-11-15 09:35:13 +01:00
Géry Debongnie fb6aab8b70 [FIX] component: fix lifecycle order 2021-11-15 09:35:13 +01:00
Géry Debongnie 9e285e1e0a [FIX] unskip tests 2021-11-15 09:35:13 +01:00
Géry Debongnie 63bfdfb8db [REF] move event_bus into utils, readd 2 functions 2021-11-15 09:35:13 +01:00
Géry Debongnie d4c4fe853e [REM] tests: remove debug script tests 2021-11-15 09:35:13 +01:00
Géry Debongnie 9163bb1e08 [REF] app: move TemplateSet into its own file 2021-11-15 09:35:13 +01:00
Géry Debongnie a187a376a0 [REF] move app and compiler code around 2021-11-15 09:35:13 +01:00
Géry Debongnie 06ea6d2490 [REF] component: fix typescript error 2021-11-15 09:35:13 +01:00
Géry Debongnie 04334e23d7 [REF] compiler: rename qweb/ into compiler/ 2021-11-15 09:35:13 +01:00
Géry Debongnie 4efe1ae166 [IMP] reactivity: slightly improve code and typing 2021-11-15 09:35:13 +01:00
Lucas Perais (lpe) ad4673cb36 [IMP] component: re-introduce error handling in lifecycle 2021-11-12 16:54:40 +01:00
Samuel Degueldre e611c20ab4 [IMP] qweb: turn handlers into function expressions only
For the sake of consistency with vanilla JS, and to allow some things
that were previously not possible.
2021-11-12 13:17:43 +01:00
Mathieu Duckerts-Antoine d60a5a414e [IMP] reactivity: Context replacement
Aim to replace the abstraction "Context" from OWL 1 with the new primitives
"atom" and "useState":

- notification is done only after a batch of modifications.
- observers are notified at most once for a batch.
- an observer of type component is notified (and rerendered)
  only if it does not have an ancestor that has to be notified for the
  same batch of operations (anywhere in the web of references!).
- notification of components is done on all levels "simultaneously".

Co-authored-by: Aaron Bohy <aab@odoo.com>
Co-authored-by: Géry Debongnie <ged@odoo.com>
Co-authored-by: Mathieu Duckerts-Antoine <dam@odoo.com>
2021-11-10 15:08:08 +01:00
Géry Debongnie d47dcf6be2 [IMP] pin prettier version to ensure consistent results 2021-11-10 14:03:17 +01:00
Samuel Degueldre 3e70b17da1 [FIX] qweb: fix crash with ref an component in same slot 2021-11-10 13:36:13 +01:00
Samuel Degueldre c718d8e6c6 [FIX] qweb: fix crash when component only renders empty slot 2021-11-10 13:36:13 +01:00
Samuel Degueldre a122a94180 [IMP] qweb/components: remove t-ref on components
Refs to component expose a lot of implementation details that should be
private to parents. Parent to child communication should go through
props.
2021-11-10 13:36:13 +01:00
Bruno Boi ca139166ab [IMP] qweb: reintroduce t-tag directive
will not be compatible with t-model directive !
2021-11-09 16:36:03 +01:00
Lucas Perais (lpe) ae71db28e4 [IMP] qweb: compiler: support t-key on node and component without t-foreach 2021-11-09 14:53:19 +01:00
Bruno Boi 779fc6b02b fixup! [IMP] bdom: support multiple synthetic events on one node 2021-11-08 13:36:09 +01:00
Bruno Boi 84913593b2 [IMP] bdom: support multiple synthetic events on one node 2021-11-08 13:36:09 +01:00
Bruno Boi 8d4eb21536 [IMP] qweb/attributes: uncomment two tests
- textarea with t-att-value
- select with t-att-value
2021-11-08 11:25:14 +01:00
Bruno Boi 4bdfaf96f3 fixup! [IMP] qweb: introduce t-model directive 2021-11-03 15:25:21 +01:00
Bruno Boi 233c953243 [IMP] qweb: introduce t-model directive
supported modifiers: lazy, trim, number
2021-11-03 15:25:21 +01:00
Bruno Boi ee5ad354ff [IMP] tags: reintroduce inline css tag
The CSS tag is useful to define a css stylesheet in the javascript file:
```js
class MyComponent extends Component {
  static template = xml`
        <div class="my-component">some template</div>
    `;
  static style = css`
    .my-component {
      color: red;
    }
  `;
}
```

The `css` tag registers internally the css information. Then, whenever the first instance of the component is created, will add a <style> tag to the document <head>.

Original commit in Owl v1: 953778dc5
2021-11-03 10:07:14 +01:00
Mathieu Duckerts-Antoine 4e4b85e2a9 [IMP] reactivity: new primitives for reactivity
fine grained reactivity:

existing key in source changes --> only observer having read the key are notified

add/delete key in source changes --> all source observers are notified

Co-authored-by: Aaron Bohy <aab@odoo.com>
Co-authored-by: Géry Debongnie <ged@odoo.com>
Co-authored-by: Mathieu Duckerts-Antoine <dam@odoo.com>
2021-10-29 14:52:20 +02:00
Mathieu Duckerts-Antoine 6479631983 Code prettification 2021-10-29 14:52:20 +02:00
Lucas Perais (lpe) 2a0c410014 [IMP] qweb, blockdom, components: t-on with modifiers
supported modifiers: capture, prevent, stop, self.
2021-10-28 13:38:56 +02:00
Lucas Perais (lpe) bb4aecf638 [IMP] blockdom: t-on supports synthetic and native event handler
Synthetic handler is a sort of event delegation that allows placing
only one listener on the document to improve performance. It is an opt-in option.

Native listener places the listener on the node itself.
2021-10-28 13:38:56 +02:00
Lucas Perais (lpe) a1adfd5a1b [FIX] qweb, component: remove support for t-on on component node 2021-10-27 13:38:35 +02:00
Lucas Perais (lpe) dd4848f602 [FIX] qweb: t-key in t-foreach is mandatory, throws otherwise 2021-10-27 13:38:35 +02:00
Bruno Boi b25f476c22 [FIX] qweb: reintroduce test on t-debug 2021-10-26 09:33:56 +02:00
Mathieu Duckerts-Antoine 90cdb97b49 [IMP] tests: component mounting
We re-add some tests for component mounting.
2021-10-26 09:05:33 +02:00
Mathieu Duckerts-Antoine 7d7568d254 [IMP] app: mount app in "first-child" position
We reintroduce the possibility to mount the app in first position in
a target. The option "self" has been dropped since it is now possible
for a component to have several top level nodes.
2021-10-26 09:05:33 +02:00
Bruno Boi 06d207f60e [IMP] package.json: add watch arg to test:debug command
Before this commit
The command "npm run test:debug" runs the tests once.

After this commit
Jest runs in watch mode
2021-10-22 15:57:23 +02:00
Bruno Boi ff564421da [IMP] package.json: add remote test:debug command
Usage:
Open chrome://inspect then run in console:
> npm run test:debug ./path/to/your/testfile.ts
2021-10-22 14:51:23 +02:00
Mathieu Duckerts-Antoine c3695ec8db [IMP] component: defaultProps application
We re-add the application of defaultProps. Note that the application
is done twice in dev mode.
2021-10-22 12:46:57 +02:00
Mathieu Duckerts-Antoine 6e0834ce5e [IMP] component,qweb: props validation
We re-add the possibility to validate props when dev mode is active.
No change in the API right Now. The dev mode is activated via the
configure method of App class.
2021-10-22 12:46:57 +02:00
Samuel Degueldre d1425c7100 [FIX] component: correctly create a new node when previous is destroyed
Previously, when a component node had been created and destroyed, and
the corresponding component was then recreated, the destroyed node was
reused. This commit fixes that
2021-10-22 10:00:35 +02:00
Samuel Degueldre e01fe301c0 [IMP] *: re-add a bunch of tests 2021-10-21 10:34:54 +02:00
Mathieu Duckerts-Antoine ba2fe3ff55 [IMP] qweb: t-props directive
We reimplement the directive "t-props" and add some tests for it.
2021-10-20 15:52:43 +02:00
Géry Debongnie 700d574314 [MOV] move lifecycle_hooks into component/ 2021-10-20 15:16:28 +02:00
Mathieu Duckerts-Antoine ba32772a92 [FIX] qweb: re-add test on memory leak
Re-add test from 6e185f9.
2021-10-20 15:16:26 +02:00
Mathieu Duckerts-Antoine e4a0277f68 [FIX] qweb: t-set directive
This commit reintroduces some tests for the t-set directive and make
them pass. For that, it was necessary to adapt the qweb compiler in
order to get the following behaviors:

A t-set can affect parent contexts (up to the first parent tagged as
boundary) when the key changed is found in one of the parent contexts.
Some context are marked as boundaries in such a way that

   - rendering contexts (e.g. components) cannot be modified via a t-set.
   - a t-set in a t-call body or in a called template can never change a
     context above the t-call context.

Code prettification has been done.
Snapshots have been modified.
2021-10-20 15:16:25 +02:00
Lucas Perais (lpe) abe3748825 [FIX] re-introduce tests 2021-10-20 15:16:24 +02:00
Mathieu Duckerts-Antoine ee64de8b3f [IMP] qweb: throw error when t-component is not used with a 't' tag 2021-10-20 15:16:22 +02:00
Lucas Perais (lpe) ed831320db [FIX] re-introduce some missing tests
The point is to have visibility on the development of the owl2 features.
This commit reintroduces some tests keeping them skipped in order to fulfill that purpose.

There still are some missing tests though.
2021-10-20 15:16:21 +02:00
Mathieu Duckerts-Antoine 5f1e1e189f [IMP] qweb: re-add support of t-on directive
We add some test for the t-on directive.

For making them pass, it was necessary to change the code produced by
compileTForeach: the const declaration is not done by using generateId
and there was some conflict with the variable names produced in
captureExpression. Consequently, many snapshots had to be changed.

Code prettification has been done too.
2021-10-20 15:16:20 +02:00
Mathieu Duckerts-Antoine 55ef9ca116 [ADD] components: re-add a test for t-foreach directive 2021-10-20 15:16:18 +02:00
Samuel Degueldre 642ecf0ccd [IMP] components: re-add a bunch of components tests from owl 1
Some tests are skipped because they rely on not-yet-implemented
features.
2021-10-20 15:16:16 +02:00
Samuel Degueldre c9cc789f1d [IMP] components: add back style_class tests
The tests have been adapted to the new way of doing things, some tests
are skipped because they rely on features that are not implemented yet
2021-10-20 15:16:14 +02:00
Mathieu Duckerts-Antoine b8649f1add [ADD] Translation feature
This commit brings back the possibility to translate text nodes and
the attributes "label", "title", "placeholder", and "alt" in an app
configured with a suitable translation function.

It is also possible to deactivate translations under a node via
the directive t-translation="off".

For flexibility it is possible to define the list of translatable
attributes in the app.
2021-10-20 15:16:12 +02:00
Samuel Degueldre e2d98e4c26 [REF] doc: remove references to router and store
Owl 2 will not have a router or store implemented inside the library
2021-10-20 15:16:06 +02:00
Samuel Degueldre e6bb4ef286 [REF] qweb: use native Node and Element instead of custom Dom types 2021-10-20 15:11:32 +02:00
Géry Debongnie 7ac20f4fc2 [REF] initial prototype of owl 2 2021-10-20 15:11:25 +02:00
120 changed files with 2297 additions and 7476 deletions
+1 -1
View File
@@ -5,7 +5,7 @@ name: Node.js CI
on:
pull_request:
branches: [ master ]
branches: [ master, owl-next ]
jobs:
build:
+80 -81
View File
@@ -30,32 +30,19 @@ All changes are documented here in no particular order.
- breaking: `catchError` method is replaced by `onError` hook ([details](#36-catcherror-method-is-replaced-by-onerror-hook))
- 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))
**Templates**
- breaking: `t-foreach` should always have a corresponding `t-key` ([details](#20-t-foreach-should-always-have-a-corresponding-t-key))
- breaking: `t-ref` does not work on components ([details](#29-t-ref-does-not-work-on-component))
- breaking: `t-on` does not accept expressions, only functions ([details](#30-t-on-does-not-accept-expressions-only-functions))
- breaking: `t-raw` directive has been removed (replaced by `t-out`) ([details](#38-t-raw-directive-has-been-removed-replaced-by-t-out))
- new: add support for synthetic events ([doc](doc/reference/event_handling.md#synthetic-events))
- 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))
- 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-on` does not work on components any more ([details](#12-t-on-does-not-work-on-components-any-more))
- 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
**Reactivity**
- finer grained reactivity: owl 2 tracks change per key/component
- finer grained reactivity: sub components can reobserve state ([doc](doc/reference/reactivity.md))
- new: `reactive` function: create reactive state (without being linked to a component) ([doc](doc/reference/reactivity.md#reactive))
- new: `markRaw` function: mark an object or array so that it is ignored by the reactivity system ([doc](doc/reference/reactivity.md#markraw))
- new: `toRaw` function: given a reactive objet, return the raw (non reactive) underlying object ([doc](doc/reference/reactivity.md#toraw))
**Slots**
@@ -79,12 +66,13 @@ All changes are documented here in no particular order.
- improved performance
- much simpler code
- finer grained reactivity: owl 2 tracks change per key/component
- finer grained reactivity: sub components can reobserve state
- 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))
- breaking: `env` is now frozen ([details](#28-env-is-now-frozen))
- new hook: `useChildSubEnv` (only applies to child components) ([details](#27-usechildsubenv-only-applies-to-child-components))
- breaking: most exports are exported at top level ([details](#18-most-exports-are-exported-at-top-level))
- breaking: properties are no longer set as attributes ([details](#19-properties-are-no-longer-set-as-attributes))
- breaking: `EventBus` api changed: it is now an `EventTarget` ([details](#21-eventbus-api-changed-it-is-now-an-eventtarget))
@@ -93,6 +81,8 @@ All changes are documented here in no particular order.
- breaking: transition system is removed ([details](#24-transition-system-is-removed))
- breaking: no more global components or templates ([details](#25-no-more-global-components-or-templates))
- breaking: `AsyncRoot` utility component is removed ([details](#26-asyncroot-utility-component-is-removed))
- breaking: `useSubEnv` only applies to child components ([details](#27-usesubenv-only-applies-to-child-components))
- breaking: `env` is now frozen ([details](#28-env-is-now-frozen))
- breaking: `renderToString` function on qweb has been removed ([details](#32-rendertostring-on-qweb-has-been-removed))
- breaking: `debounce` utility function has been removed ([details](#34-debounce-utility-function-has-been-removed))
- breaking: `browser` object has been removed ([details](#39-browser-object-has-been-removed))
@@ -247,12 +237,35 @@ 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, 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.
a much more powerful reactivity system.
Migration code: remove the `shouldUpdate` methods, and it should work as well
as before.
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>
```
### 9. component.el is removed
@@ -312,6 +325,41 @@ 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
@@ -517,12 +565,15 @@ either a fallback when the data is not ready, or the actual component with data
as props. If there is no escape, and `AsyncRoot` is needed, please reach out to
us so we can study this usecase.
### 27. `useChildSubEnv` (only applies to child components)
### 27. `useSubEnv` only applies to child components
In Owl, a call to `useSubEnv` would define a new environment for the children
AND the component. It is very useful, but in some cases, one only need to update
the children component environment. This can now be done with a new hook:
[`useChildSubEnv`](doc/reference/hooks.md#usesubenv-and-usechildsubenv)
In Owl 1, a call to `useSubEnv` would define a new environment for the children
AND the component. It now only defines an environment for the children.
Rationale: This was a subtle cause for bugs: some code had to be rrun
before the call to `useSubEnv`, otherwise it could interfere with the sub environment.
Documentation: [Hooks](doc/reference/hooks.md#usesubenv)
### 28. `env` is now frozen
@@ -608,14 +659,10 @@ Also, this can easily be done in userspace, by mounting a component in a div. F
export async function renderToString(template, context) {
class C extends Component {
static template = template;
setup () {
Object.assign(this, context);
}
}
const div = document.createElement('div');
document.body.appendChild(div);
const app = new App(C);
await app.mount(div);
const component = await mount(C, div);
const result = div.innerHTML;
app.destroy();
div.remove();
@@ -623,30 +670,6 @@ export async function renderToString(template, context) {
}
```
The function above works for most cases, but is asynchronous. An alternative
function could look like this:
```js
const { App, blockDom } = owl;
const app = new App(Component); // act as a template repository
function renderToString(template, context = {}) {
app.addTemplate(template, template, { allowDuplicate: true });
const templateFn = app.getTemplate(template);
const bdom = templateFn(context, {});
const div = document.createElement('div')
blockDom.mount(bdom, div);
return div.innerHTML;
}
```
This is a synchronous function, so it will not work with components, but it should
be useful for most simple templates.
Also note that these two examples do not translate their templates. To do that,
they need to be modified to pass the proper translate function to the `App`
configuration.
### 33. Portal are now defined with `t-portal`
Before Owl 2, one could use the `Portal` component by importing it and using it.
@@ -739,28 +762,4 @@ 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).
## 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.
or to use native browser function (and then, just mock them directly).
+1 -3
View File
@@ -82,7 +82,6 @@ Are you new to Owl? This is the place to start!
- [Component](doc/reference/component.md)
- [Component Lifecycle](doc/reference/component.md#lifecycle)
- [Concurrency Model](doc/reference/concurrency_model.md)
- [Dev mode](doc/reference/app.md#dev-mode)
- [Dynamic sub components](doc/reference/component.md#dynamic-sub-components)
- [Environment](doc/reference/environment.md)
- [Error Handling](doc/reference/error_handling.md)
@@ -111,7 +110,6 @@ 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
@@ -123,5 +121,5 @@ npm install @odoo/owl
If you want to use a simple `<script>` tag, the last release can be downloaded here:
- [owl-1.4.10](https://github.com/odoo/owl/releases/tag/v1.4.10)
- [owl-1.4.7](https://github.com/odoo/owl/releases/tag/v1.4.7)
+2 -2
View File
@@ -240,7 +240,7 @@ class Task extends Component {
static template = xml /* xml */`
<div class="task" t-att-class="props.task.isCompleted ? 'done' : ''">
<input type="checkbox" t-att-checked="props.task.isCompleted"/>
<span><t t-esc="props.task.text"/></span>
<span><t t-esc="props.task.title"/></span>
</div>`;
static props = ["task"];
}
@@ -743,7 +743,7 @@ the user experience.
```xml
<input type="checkbox" t-att-checked="props.task.isCompleted"
t-att-id="props.task.id"
t-on-click="() => store.toggleTask(props.task)"/>
t-on-click="dispatch('toggleTask', props.task.id)"/>
<label t-att-for="props.task.id"><t t-esc="props.task.text"/></label>
```
-98
View File
@@ -1,98 +0,0 @@
# 🦉 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.
+2 -8
View File
@@ -7,14 +7,9 @@ Main entities:
- [`App`](reference/app.md): represent an Owl application (mainly a root component,a set of templates, and a config)
- [`Component`](reference/component.md): the main class to define a concrete Owl component
- [`mount`](reference/app.md#mount-helper): main entry point for most application: mount a component to a target
- [`xml`](reference/templates.md#inline-templates): helper to define an inline template
Reactivity
- [`useState`](reference/reactivity.md#usestate): create a reactive object (hook, linked to a specific component)
- [`reactive`](reference/reactivity.md#reactive): create a reactive object (not linked to any component)
- [`markRaw`](reference/reactivity.md#markraw): mark an object or array so that it is ignored by the reactivity system
- [`toRaw`](reference/reactivity.md#toraw): given a reactive objet, return the raw (non reactive) underlying object
- [`xml`](reference/templates.md#inline-templates): helper to define an inline template
Lifecycle hooks:
@@ -36,8 +31,7 @@ Other hooks:
- [`useEnv`](reference/hooks.md#useenv): return a reference to the current env
- [`useExternalListener`](reference/hooks.md#useexternallistener): add a listener outside of a component DOM
- [`useRef`](reference/hooks.md#useref): get an object representing a reference (`t-ref`)
- [`useChildSubEnv`](reference/hooks.md#usesubenv-and-usechildsubenv): extend the current env with additional information (for child components)
- [`useSubEnv`](reference/hooks.md#usesubenv-and-usechildsubenv): extend the current env with additional information (for current component and child components)
- [`useSubEnv`](reference/hooks.md#usesubenv): extend the current env with additional information for child components
Utility/helpers:
+16 -30
View File
@@ -3,7 +3,6 @@
## Content
- [Overview](#overview)
- [API](#api)
- [Configuration](#configuration)
- [`mount` helper](#mount-helper)
- [Loading templates](#loading-templates)
@@ -27,10 +26,24 @@ The basic workflow is: create an `App` instance configured with the root
component, the templates, and possibly other settings. Then, we mount that
instance somewhere in the DOM.
## API
## Configuration
- **`constructor(Root[, config])`**: first argument should be a component class (not
an instance), and the optional second argument is a configuration object (see below).
an instance), and the optional second argument is a configuration object.
The `config` object is an object with some of the following keys:
- **`env (object)`**: if given, this will be the shared `env` given to each component
- **`props (object)`**: the props given to the root component
- **`dev (boolean, default=false)`**: if `true`, the application is rendered in `dev`
mode, which activates some additional checks (in particular, the props validation
code is only performed in dev mode)
- **`translatableAttributes (string[])`**: a list of additional attributes that should
be translated (see [translations](translations.md))
- **`translateFn (function)`**: a function that will be called by owl to translate
templates (see [translations](translations.md))
- **`templates (string | xml document)`**: all the templates that will be used by
the components created by the application.
- **`mount(target, options)`**: first argument is an html element, and the optional
second argument is an object with mounting options (see below). Mount the app
@@ -45,23 +58,6 @@ instance somewhere in the DOM.
- **`destroy()`**: destroys the application
## Configuration
The `config` object is an object with some of the following keys:
- **`env (object)`**: if given, this will be the shared `env` given to each component
- **`props (object)`**: the props given to the root component
- **`dev (boolean, default=false)`**: if `true`, the application is rendered in
[`dev` mode](#dev-mode);
- **`test (boolean, default=false)`**: `test` mode is the same as `dev` mode, except
that Owl will not log a message to warn that Owl is in `dev` mode.
- **`translatableAttributes (string[])`**: a list of additional attributes that should
be translated (see [translations](translations.md))
- **`translateFn (function)`**: a function that will be called by owl to translate
templates (see [translations](translations.md))
- **`templates (string | xml document)`**: all the templates that will be used by
the components created by the application.
## `mount` helper
Note that there is a `mount` helper to do that in just a line:
@@ -109,13 +105,3 @@ const { loadFile, mount } = owl;
mount(Root, document.body, { env });
})();
```
## Dev mode
Dev mode activates some additional checks and developer amenities:
- [Props validation](./props.md#props-validation) is performed
- [t-foreach](./templates.md#loops) loops check for key unicity
- Lifecycle hooks are wrapped to report their errors in a more developer-friendly way
- onWillStart and onWillUpdateProps will emit a warning in the console when they
take longer than 3 seconds in an effort to ease debugging the presence of deadlocks
+1 -5
View File
@@ -68,16 +68,12 @@ The `Component` class has a very small API.
component will go through the following lifecycle methods: `willUpdateProps`,
`willPatch` and `patched`.
* **`render(deep[=false])`**: calling this method directly will cause a rerender. Note
* **`render()`**: 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
+1 -1
View File
@@ -52,7 +52,7 @@ It is sometimes useful to add one (or more) specific keys to the environment,
from the perspective of a specific component and its children. In that case, the
solution presented above will not work, since it sets the global environment.
There are two hooks for this situation: [`useSubEnv` and `useChildSubEnv`](hooks.md#usesubenv-and-usechildsubenv).
There is a hook for this situation: [`useSubEnv`](hooks.md#usesubenv).
```js
class SomeComponent extends Component {
+25
View File
@@ -0,0 +1,25 @@
# 🦉 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,7 +5,6 @@
- [Event Handling](#event-handling)
- [Modifiers](#modifiers)
- [Synthetic Events](#synthetic-events)
- [On Components](#on-components)
## Event Handling
@@ -101,19 +100,3 @@ 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).
+7 -18
View File
@@ -8,7 +8,7 @@
- [Other hooks](#other-hooks)
- [`useState`](#usestate)
- [`useRef`](#useref)
- [`useSubEnv` and `useChildSubEnv`](#usesubenv-and-usechildsubenv)
- [`useSubEnv`](#usesubenv)
- [`useExternalListener`](#useexternallistener)
- [`useComponent`](#usecomponent)
- [`useEnv`](#useenv)
@@ -152,14 +152,14 @@ this.ref2 = useRef("component_2");
References are only guaranteed to be active while the parent component is mounted.
If this is not the case, accessing `el` or `comp` on it will return `null`.
### `useSubEnv` and `useChildSubEnv`
### `useSubEnv`
The environment is sometimes useful to share some common information between
all components. But sometimes, we want to _scope_ that knowledge to a subtree.
For example, if we have a form view component, maybe we would like to make some
`model` object available to all sub components, but not to the whole application.
This is where the `useChildSubEnv` hook may be useful: it lets a component add some
This is where the `useSubEnv` hook may be useful: it lets a component add some
information to the environment in a way that only its children
can access it:
@@ -167,26 +167,15 @@ can access it:
class FormComponent extends Component {
setup() {
const model = makeModel();
// model will be available on this.env for this component and all children
useSubEnv({ model });
// someKey will be available on this.env for all children
useChildSubEnv({ someKey: "value" });
}
}
```
The `useSubEnv` and `useChildSubEnv` hooks take one argument: an object which
contains some key/value that will be added to the current environment. These hooks
will create a new env object with the new information:
- `useSubEnv` will assign this new `env` to itself and to all children components
- `useChildSubEnv` will only assign this new `env` to all children components.
As usual in Owl, [environments](environment.md) created with these two hooks are
frozen, to prevent unwanted modifications.
Note that both these hooks can be called an arbitrary number of times. The `env`
will then be updated accordingly.
The `useSubEnv` takes one argument: an object which contains some key/value that
will be added to the parent environment. Note that it will extend, not replace
the parent environment. And of course, the parent environment will not be
affected.
### `useExternalListener`
+1 -6
View File
@@ -168,15 +168,11 @@ For each key, a `prop` definition is either a boolean, a constructor, a list of
- `shape`: if the type was `Object`, then the `shape` key describes the interface of the object. If it is not set, then we only validate the object, not its elements,
- `validate`: this is a function which should return a boolean to determine if
the value is valid or not. Useful for custom validation logic.
- `optional`: if true, the prop is not mandatory
There is a special `*` prop that means that additional prop are allowed. This is
sometimes useful for generic components that will propagate some or all their
props to their child components.
Note that default values cannot be defined for a mandatory props. Doing so will
result in a prop validation error.
Examples:
```js
@@ -194,8 +190,7 @@ class ComponentB extends owl.Component {
element: {type: Object, shape: {id: Boolean, text: String }
},
date: Date,
combinedVal: [Number, Boolean],
optionalProp: { type: Number, optional: true }
combinedVal: [Number, Boolean]
};
...
-51
View File
@@ -5,8 +5,6 @@
- [Overview](#overview)
- [`useState`](#usestate)
- [`reactive`](#reactive)
- [`markRaw`](#markraw)
- [`toRaw`](#toraw)
## Overview
@@ -25,11 +23,6 @@ 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:
@@ -85,47 +78,3 @@ obj2.b = 3; // log 'observer1' and 'observer2'
Obviously, one can use `reactive` on the result of a `useState` if wanted, this
is the proper way to watch for some state changes.
## `markRaw`
Marks an object so that it is ignored by the reactivity system. This function returns its argument.
```js
const someObject = markRaw(...);
const state = useState({
a: 1,
obj: someObject
});
// here, state.obj === someObject
```
This is useful in some rare cases. For example, some complex and large object such
that going through the reactivity system may cause a non trivial performance slowdown.
However, use this function with caution: this is an escape hatch from the reactivity
system, and as such, using it may cause subtle and unintended issues!
## `toRaw`
Given a reactive object, this function returns the underlying, non-reactive,
corresponding object.
```js
// in setup
const state = useState({ value: 1 });
// later:
const rawState = toRaw(this.state);
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
```
+12 -28
View File
@@ -87,8 +87,8 @@ grandparent of the slot content).
## Default Slot
All elements inside the component which are not a named slot will be treated as
part of the content of the `default` slot. For example:
The first element inside the component which is not a named slot will
be considered the `default` slot. For example:
```xml
<div t-name="Parent">
@@ -110,7 +110,6 @@ One can mix default slot and named slots:
default content
<t t-set-slot="footer">
content for footer slot here
</t>
</Child>
</div>
```
@@ -210,45 +209,30 @@ use this `Notebook` component:
</Notebook>
```
Slot params works like normal props, so one can use the `.bind` suffix to
bind a function if needed.
## Slot scopes
For other kinds of advanced use cases, the content of a slot may depends on some
information specific to the generic component. This is the opposite of the slot
params.
For other kind of advanced use cases, the content of a slot may depends on some
specific information specific to the generic component. This is the opposite
of the slot params.
To solve this kind of problems, one can use the `t-slot-scope` directive along
To solve this kind of problems, one can use the `t-set-scope` directive along
with the `t-set-slot`. This defines the name of a variable that can access
everything given by the child component:
```xml
<MyComponent>
<t t-set-slot="foo" t-slot-scope="scope">
<div>
<t t-set-slot="foo" t-set-scope="scope">
content
<t t-esc="scope.bool"/>
<t t-esc="scope.num"/>
</t>
</MyComponent>
</div>
```
And the child component that includes the slot can provide values like this:
```xml
<t t-slot="foo" bool="other_var" num="5">
<div>
<t t-slot="foo" bool="other_var" num="5">
</div>
```
In the case of the default slot, you may declare the slot scope directly on the
component itself:
```xml
<MyComponent t-slot-scope="scope">
content
<t t-esc="scope.bool"/>
<t t-esc="scope.num"/>
</MyComponent>
```
Slot values works like normal props, so one can use the `.bind` suffix to
bind a function if needed.
+4 -17
View File
@@ -21,7 +21,6 @@
- [Fragments](#fragments)
- [Inline templates](#inline-templates)
- [Rendering svg](#rendering-svg)
- [Restrictions](#restrictions)
## Overview
@@ -675,19 +674,7 @@ This `RootNode` component will then display a live SVG representation of the
graph described by the `graph` property. Note that there is a recursive structure
here: the `Node` component uses itself as a subcomponent.
**Important note:** Owl needs to properly set the namespace for each svg elements.
Since Owl compile each template separately, it is not able to determine easily
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>
```
Note that since SVG needs to be handled in a specific way (its namespace needs
to be properly set), there is a small constraint for Owl components: if an owl
component is supposed to be a part of an svg graph, then its root node needs to
be a `g` tag, so Owl can properly set the namespace.
+1 -12
View File
@@ -54,17 +54,6 @@ For example, one may want to also translate `data-title` attributes. To do that,
we can define additional attributes with the `translatableAttributes` option:
```js
const app = new App(Root, { templates, tranaslateFn, translatableAttributes: ["data-title"] });
const app = new App(Root, { templates, tranaslateFn, translatalbeAttributes: ["data-title"] });
// ...
```
It is also possible to remove an attribute from the default list by prefixing it with `-`:
```js
const app = new App(Root, {
templates,
tranaslateFn,
translatableAttributes: ["data-title", "-title"],
});
// data-title attribute will be translated, but not title attribute...
```
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@odoo/owl",
"version": "2.0.0-beta-4",
"version": "2.0.0-alpha1",
"description": "Odoo Web Library (OWL)",
"main": "dist/owl.cjs.js",
"browser": "dist/owl.iife.js",
+1 -1
View File
@@ -1,6 +1,6 @@
# 🦉 OWL Roadmap 🦉
- Current version: 1.4.10
- Current version: 1.4.7
- Status: stable
This roadmap is only an attempt at predicting Owl's future. Everything may
+33 -48
View File
@@ -1,10 +1,9 @@
import { Component, ComponentConstructor } from "../component/component";
import { Component } from "../component/component";
import { ComponentNode } from "../component/component_node";
import { MountOptions } from "../component/fibers";
import { Scheduler } from "../component/scheduler";
import { TemplateSet, TemplateSetConfig } from "./template_set";
import { nodeErrorHandlers } from "../component/error_handling";
import { validateTarget } from "../utils";
// reimplement dev mode stuff see last change in 0f7a8289a6fb8387c3c1af41c6664b2a8448758f
@@ -12,61 +11,52 @@ export interface Env {
[key: string]: any;
}
export interface AppConfig<P, E> extends TemplateSetConfig {
props?: P;
env?: E;
test?: boolean;
export interface AppConfig extends TemplateSetConfig {
env?: Env;
props?: any;
}
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.
export const DEV_MSG = `Owl is running in 'dev' mode.
This is not suitable for production use.
See https://github.com/odoo/owl/blob/${hash}/doc/reference/app.md#configuration for more information.`;
};
See https://github.com/odoo/owl/blob/master/doc/reference/config.md#mode for more information.`;
export class App<
T extends abstract new (...args: any) => any = any,
P extends object = any,
E = any
> extends TemplateSet {
static validateTarget = validateTarget;
Root: ComponentConstructor<P, E>;
props: P;
env: E;
export class App<T extends typeof Component = any> extends TemplateSet {
Root: T;
props: any;
env: Env;
scheduler = new Scheduler();
root: ComponentNode<P, E> | null = null;
root: ComponentNode | null = null;
constructor(Root: ComponentConstructor<P, E>, config: AppConfig<P, E> = {}) {
constructor(Root: T, config: AppConfig = {}) {
super(config);
this.Root = Root;
if (config.test) {
this.dev = true;
if (config.dev) {
console.info(DEV_MSG);
}
if (this.dev && !config.test && !hasBeenLogged) {
console.info(DEV_MSG());
hasBeenLogged = true;
}
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);
const descrs = Object.getOwnPropertyDescriptors(config.env || {});
this.env = Object.freeze(Object.defineProperties({}, descrs));
this.props = config.props || {};
}
mount(target: HTMLElement, options?: MountOptions): Promise<Component<P, E> & InstanceType<T>> {
App.validateTarget(target);
mount(target: HTMLElement, options?: MountOptions): Promise<InstanceType<T>> {
this.checkTarget(target);
const node = this.makeNode(this.Root, this.props);
const prom = this.mountNode(node, target, options);
this.root = node;
return prom;
}
makeNode(Component: ComponentConstructor, props: any): ComponentNode {
checkTarget(target: HTMLElement) {
if (!(target instanceof HTMLElement)) {
throw new Error("Cannot mount component: the target is not a valid DOM element");
}
if (!document.body.contains(target)) {
throw new Error("Cannot mount a component on a detached dom node");
}
}
makeNode(Component: T, props: any): ComponentNode {
return new ComponentNode(Component, props, this);
}
@@ -101,20 +91,15 @@ export class App<
destroy() {
if (this.root) {
this.scheduler.flush();
this.root.destroy();
}
}
}
export async function mount<
T extends abstract new (...args: any) => any = any,
P extends object = any,
E = any
>(
C: T & ComponentConstructor<P, E>,
export async function mount<T extends typeof Component>(
C: T,
target: HTMLElement,
config: AppConfig<P, E> & MountOptions = {}
): Promise<Component<P, E> & InstanceType<T>> {
config: AppConfig & MountOptions = {}
): Promise<InstanceType<T>> {
return new App(C, config).mount(target, config);
}
+6 -6
View File
@@ -1,4 +1,4 @@
import { BDom, multi, text, toggler, createCatcher } from "../blockdom";
import { BDom, multi, text, toggler } from "../blockdom";
import { validateProps } from "../component/props_validation";
import { Markup } from "../utils";
import { html } from "../blockdom/index";
@@ -23,11 +23,12 @@ function callSlot(
defaultContent?: (ctx: any, node: any, key: string) => BDom
): BDom {
key = key + "__slot_" + name;
const slots = ctx.props[TARGET].slots || {};
const nonReactiveProps = ctx.props && ctx.props[TARGET];
const slots = nonReactiveProps ? nonReactiveProps.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) {
@@ -137,7 +138,7 @@ export function safeOutput(value: any): ReturnType<typeof toggler> {
} else if (value instanceof LazyValue) {
safeKey = `lazy_value`;
block = value.evaluate();
} else if (value instanceof String || typeof value === "string") {
} else if (typeof value === "string") {
safeKey = "string_unsafe";
block = text(value);
} else {
@@ -183,7 +184,7 @@ function multiRefSetter(refs: RefMap, name: string): RefSetter {
};
}
export const helpers = {
export const UTILS = {
withDefault,
zero: Symbol("zero"),
isBoundary,
@@ -199,5 +200,4 @@ export const helpers = {
LazyValue,
safeOutput,
bind,
createCatcher,
};
+28 -36
View File
@@ -1,13 +1,12 @@
import { createBlock, html, list, multi, text, toggler, comment } from "../blockdom";
import { compile, Template } from "../compiler";
import { markRaw } from "../reactivity";
import { Portal } from "../portal";
import { component, getCurrent } from "../component/component_node";
import { helpers } from "./template_helpers";
import { globalTemplates } from "../utils";
import { component } from "../component/component_node";
import { UTILS } from "./template_helpers";
const bdom = { text, createBlock, list, multi, html, toggler, component, comment };
export const globalTemplates: { [key: string]: string | Node } = {};
function parseXML(xml: string): Document {
const parser = new DOMParser();
@@ -38,22 +37,6 @@ 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[];
@@ -67,7 +50,13 @@ export class TemplateSet {
templates: { [name: string]: Template } = {};
translateFn?: (s: string) => string;
translatableAttributes?: string[];
helpers: any;
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),
});
constructor(config: TemplateSetConfig = {}) {
this.dev = config.dev || false;
@@ -76,14 +65,9 @@ export class TemplateSet {
if (config.templates) {
this.addTemplates(config.templates);
}
this.helpers = makeHelpers(this.getTemplate.bind(this));
}
addTemplate(
name: string,
template: string | Element,
options: { allowDuplicate?: boolean } = {}
) {
addTemplate(name: string, template: string | Node, options: { allowDuplicate?: boolean } = {}) {
if (name in this.rawTemplates && !options.allowDuplicate) {
throw new Error(`Template ${name} already defined`);
}
@@ -98,6 +82,7 @@ export class TemplateSet {
xml = xml instanceof Document ? xml : parseXML(xml);
for (const template of xml.querySelectorAll("[t-name]")) {
const name = template.getAttribute("t-name")!;
template.removeAttribute("t-name");
this.addTemplate(name, template, options);
}
}
@@ -106,12 +91,7 @@ export class TemplateSet {
if (!(name in this.templates)) {
const rawTemplate = this.rawTemplates[name];
if (rawTemplate === undefined) {
let extraInfo = "";
try {
const componentName = getCurrent().component.constructor.name;
extraInfo = ` (for component "${componentName}")`;
} catch {}
throw new Error(`Missing template: "${name}"${extraInfo}`);
throw new Error(`Missing template: "${name}"`);
}
const templateFn = this._compileTemplate(name, rawTemplate);
// first add a function to lazily get the template, in case there is a
@@ -120,13 +100,13 @@ export class TemplateSet {
this.templates[name] = function (context, parent) {
return templates[name].call(this, context, parent);
};
const template = templateFn(bdom, this.helpers);
const template = templateFn(bdom, this.utils);
this.templates[name] = template;
}
return this.templates[name];
}
_compileTemplate(name: string, template: string | Element) {
_compileTemplate(name: string, template: string | Node) {
return compile(template, {
name,
dev: this.dev,
@@ -135,3 +115,15 @@ 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 -2
View File
@@ -139,8 +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) {
// support 0, fallback to empty string for other falsy values
(this as any)[name] = value === 0 ? 0 : value || "";
(this as any)[name] = value;
};
}
+50 -74
View File
@@ -299,13 +299,12 @@ interface BlockCtx {
locations: IndexedLocation[];
children: Child[];
cbRefs: number[];
refList: (() => void)[][];
}
function buildContext(tree: IntermediateTree, ctx?: BlockCtx, fromIdx?: number): BlockCtx {
if (!ctx) {
const children = new Array(tree.info.filter((v) => v.type === "child").length);
ctx = { collectors: [], locations: [], children, cbRefs: [], refN: tree.refN, refList: [] };
ctx = { collectors: [], locations: [], children, cbRefs: [], refN: tree.refN };
fromIdx = 0;
}
if (tree.refN) {
@@ -409,11 +408,11 @@ function updateCtx(ctx: BlockCtx, tree: IntermediateTree) {
break;
}
case "ref":
const index = ctx.cbRefs.push(info.idx) - 1;
ctx.cbRefs.push(info.idx);
ctx.locations.push({
idx: info.idx,
refIdx: info.refIdx!,
setData: makeRefSetter(index, ctx.refList),
setData: setRef,
updateData: NO_OP,
});
}
@@ -427,21 +426,12 @@ function buildBlock(template: HTMLElement, ctx: BlockCtx): BlockType {
let B = createBlockClass(template, ctx);
if (ctx.cbRefs.length) {
const cbRefs = ctx.cbRefs;
const refList = ctx.refList;
let cbRefsNumber = cbRefs.length;
const refs = ctx.cbRefs;
B = class extends B {
mount(parent: HTMLElement, afterNode: Node | null) {
refList.push(new Array(cbRefsNumber));
super.mount(parent, afterNode);
for (let cbRef of refList.pop()!) {
cbRef();
}
}
remove() {
super.remove();
for (let cbRef of cbRefs) {
let fn = (this as any).data[cbRef];
for (let ref of refs) {
let fn = (this as any).data[ref];
fn(null);
}
}
@@ -486,12 +476,12 @@ function createBlockClass(template: HTMLElement, ctx: BlockCtx): BlockClass {
const nodeInsertBefore = nodeProto.insertBefore;
const elementRemove = elementProto.remove;
class Block {
return class Block {
el: HTMLElement | undefined;
parentEl?: HTMLElement | undefined;
data: any[] | undefined;
children?: (VNode | undefined)[];
refs: Node[] | undefined;
data: any[] | undefined;
parentEl?: HTMLElement | undefined;
children?: (VNode | undefined)[];
constructor(data?: any[]) {
this.data = data;
@@ -512,62 +502,46 @@ function createBlockClass(template: HTMLElement, ctx: BlockCtx): BlockClass {
nodeInsertBefore.call(this.parentEl, this.el!, target);
}
toString() {
const div = document.createElement("div");
this.mount(div, null);
return div.innerHTML;
}
mount(parent: HTMLElement, afterNode: Node | null) {
const el = nodeCloneNode.call(template, true) as HTMLElement;
nodeInsertBefore.call(parent, el, afterNode);
this.el = el;
this.parentEl = parent;
}
patch(other: Block, withBeforeRemove: boolean) {}
}
if (isDynamic) {
Block.prototype.mount = function mount(parent: HTMLElement, afterNode: Node | null) {
const el = nodeCloneNode.call(template, true);
// collecting references
const refs: Node[] = new Array(refN);
this.refs = refs;
refs[0] = el;
for (let i = 0; i < colN; i++) {
const w = collectors[i];
refs[w.idx] = w.getVal.call(refs[w.prevIdx]);
}
// applying data to all update points
if (locN) {
const data = this.data!;
for (let i = 0; i < locN; i++) {
const loc = locations[i];
loc.setData.call(refs[loc.refIdx], data[i]);
}
}
nodeInsertBefore.call(parent, el, afterNode);
if (isDynamic) {
// collecting references
const refs: Node[] = new Array(refN);
this.refs = refs;
refs[0] = el;
for (let i = 0; i < colN; i++) {
const w = collectors[i];
refs[w.idx] = w.getVal.call(refs[w.prevIdx]);
}
// preparing all children
if (childN) {
const children = this.children;
for (let i = 0; i < childN; i++) {
const child = children![i];
if (child) {
const loc = childrenLocs[i];
const afterNode = loc.afterRefIdx ? refs[loc.afterRefIdx] : null;
child.isOnlyChild = loc.isOnlyChild;
child.mount(refs[loc.parentRefIdx] as any, afterNode);
// applying data to all update points
if (locN) {
const data = this.data!;
for (let i = 0; i < locN; i++) {
const loc = locations[i];
loc.setData.call(refs[loc.refIdx], data[i]);
}
}
// preparing all children
if (childN) {
const children = this.children;
for (let i = 0; i < childN; i++) {
const child = children![i];
if (child) {
const loc = childrenLocs[i];
const afterNode = loc.afterRefIdx ? refs[loc.afterRefIdx] : null;
child.isOnlyChild = loc.isOnlyChild;
child.mount(refs[loc.parentRefIdx] as any, afterNode);
}
}
}
}
this.el = el as HTMLElement;
this.parentEl = parent;
};
Block.prototype.patch = function patch(other: Block, withBeforeRemove: boolean) {
}
patch(other: Block, withBeforeRemove: boolean) {
if (this === other) {
return;
}
@@ -612,17 +586,19 @@ function createBlockClass(template: HTMLElement, ctx: BlockCtx): BlockClass {
}
}
}
};
}
return Block;
}
toString() {
const div = document.createElement("div");
this.mount(div, null);
return div.innerHTML;
}
};
}
function setText(this: Text, value: any) {
characterDataSetData.call(this, toText(value));
}
function makeRefSetter(index: number, refs: (() => void)[][]): Setter<HTMLElement> {
return function setRef(this: HTMLElement, fn: any) {
refs[refs.length - 1][index] = () => fn(this);
};
function setRef(this: HTMLElement, fn: any) {
fn(this);
}
-89
View File
@@ -1,89 +0,0 @@
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);
};
}
+2 -12
View File
@@ -5,7 +5,6 @@ type EventHandlerSetter = (this: HTMLElement, data: any) => void;
interface EventHandlerCreator {
setup: EventHandlerSetter;
update: EventHandlerSetter;
remove: (this: HTMLElement) => void;
}
export function createEventHandler(rawEvent: string): EventHandlerCreator {
@@ -39,15 +38,11 @@ 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, remove };
return { setup, update };
}
// Synthetic handler: a form of event delegation that allows placing only one
@@ -65,12 +60,7 @@ function createSyntheticHandler(evName: string, capture: boolean = false): Event
_data[currentId] = data;
(this as any)[eventKey] = _data;
}
function remove(this: HTMLElement) {
delete (this as any)[eventKey];
}
return { setup, update: setup, remove };
return { setup, update: setup };
}
function nativeToSyntheticEvent(eventKey: string, event: Event) {
-1
View File
@@ -61,7 +61,6 @@ class VHtml {
// remove current content
this.remove();
this.content = content;
this.html = other.html;
}
}
-1
View File
@@ -6,7 +6,6 @@ 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;
+3 -3
View File
@@ -9,11 +9,11 @@ const characterDataSetData = getDescriptor(characterDataProto, "data").set!;
const nodeRemoveChild = nodeProto.removeChild;
abstract class VSimpleNode {
text: string | String;
text: string;
parentEl?: HTMLElement | undefined;
el?: any;
constructor(text: string | String) {
constructor(text: string) {
this.text = text;
}
@@ -65,7 +65,7 @@ class VComment extends VSimpleNode {
patch() {}
}
export function text(str: string | String): VNode<VText> {
export function text(str: string): VNode<VText> {
return new VText(str);
}
+94 -175
View File
@@ -20,8 +20,6 @@ import {
ASTTranslation,
ASTType,
ASTTPortal,
EventHandlers,
Attrs,
} from "./parser";
type BlockType = "block" | "text" | "multi" | "list" | "html" | "comment";
@@ -130,7 +128,6 @@ interface Context {
translate: boolean;
tKeyExpr: string | null;
nameSpace?: string;
tModelSelectedExpr?: string;
}
function createContext(parentCtx: Context, params?: Partial<Context>) {
@@ -142,7 +139,6 @@ function createContext(parentCtx: Context, params?: Partial<Context>) {
translate: parentCtx.translate,
tKeyExpr: null,
nameSpace: parentCtx.nameSpace,
tModelSelectedExpr: parentCtx.tModelSelectedExpr,
},
params
);
@@ -159,11 +155,9 @@ class CodeTarget {
// maps ref name to [id, expr]
refInfo: { [name: string]: [string, string] } = {};
shouldProtectScope: boolean = false;
on: EventHandlers | null;
constructor(name: string, on?: EventHandlers | null) {
constructor(name: string) {
this.name = name;
this.on = on || null;
}
addLine(line: string, idx?: number) {
@@ -218,24 +212,14 @@ export class CodeGenerator {
templateName?: string;
dev: boolean;
translateFn: (s: string) => string;
translatableAttributes: string[] = TRANSLATABLE_ATTRS;
translatableAttributes: string[];
ast: AST;
staticDefs: { id: string; expr: string }[] = [];
staticCalls: { id: string; template: string }[] = [];
helpers: Set<string> = new Set();
constructor(ast: AST, options: CodeGenOptions) {
this.translateFn = options.translateFn || ((s: string) => s);
if (options.translatableAttributes) {
const attrs = new Set(TRANSLATABLE_ATTRS);
for (let attr of options.translatableAttributes) {
if (attr.startsWith("-")) {
attrs.delete(attr.slice(1));
} else {
attrs.add(attr);
}
}
this.translatableAttributes = [...attrs];
}
this.translatableAttributes = options.translatableAttributes || TRANSLATABLE_ATTRS;
this.hasSafeContext = options.hasSafeContext || false;
this.dev = options.dev || false;
this.ast = ast;
@@ -266,8 +250,8 @@ export class CodeGenerator {
mainCode.push(`// Template name: "${this.templateName}"`);
}
for (let { id, expr } of this.staticDefs) {
mainCode.push(`const ${id} = ${expr};`);
for (let { id, template } of this.staticCalls) {
mainCode.push(`const ${id} = getTemplate(${template});`);
}
// define all blocks
@@ -307,23 +291,20 @@ export class CodeGenerator {
return code;
}
compileInNewTarget(prefix: string, ast: AST, ctx: Context, on?: EventHandlers | null): string {
compileInNewTarget(prefix: string, ast: AST, ctx: Context): string {
const name = this.generateId(prefix);
const initialTarget = this.target;
const target = new CodeTarget(name, on);
const target = new CodeTarget(name);
this.targets.push(target);
this.target = target;
this.compileAST(ast, createContext(ctx));
const subCtx: Context = createContext(ctx);
this.compileAST(ast, subCtx);
this.target = initialTarget;
return name;
}
addLine(line: string, idx?: number) {
this.target.addLine(line, idx);
}
define(varName: string, expr: string) {
this.addLine(`const ${varName} = ${expr};`);
addLine(line: string) {
this.target.addLine(line);
}
generateId(prefix: string = ""): string {
@@ -375,12 +356,9 @@ 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.define(block.varName, blockExpr);
this.addLine(`let ${block.varName} = ${blockExpr};`);
}
}
@@ -409,7 +387,7 @@ export class CodeGenerator {
if (!mapping.has(tok.varName)) {
const varId = this.generateId("v");
mapping.set(tok.varName, varId);
this.define(varId, tok.value);
this.addLine(`const ${varId} = ${tok.value};`);
}
tok.value = mapping.get(tok.varName)!;
}
@@ -544,57 +522,45 @@ export class CodeGenerator {
compileTDomNode(ast: ASTDomNode, ctx: Context) {
let { block, forceNewBlock } = ctx;
const isNewBlock = !block || forceNewBlock || ast.dynamicTag !== null || ast.ns;
const isNewBlock = !block || forceNewBlock || ast.dynamicTag !== null;
let codeIdx = this.target.code.length;
if (isNewBlock) {
if ((ast.dynamicTag || ctx.tKeyExpr || ast.ns) && ctx.block) {
if ((ast.dynamicTag || ctx.tKeyExpr) && ctx.block) {
this.insertAnchor(ctx.block!);
}
block = this.createBlock(block, "block", ctx);
this.blocks.push(block);
if (ast.dynamicTag) {
const tagExpr = this.generateId("tag");
this.define(tagExpr, compileExpr(ast.dynamicTag));
this.addLine(`let ${tagExpr} = ${compileExpr(ast.dynamicTag)};`);
block.dynamicTagName = tagExpr;
}
}
// attributes
const attrs: Attrs = {};
const attrs: { [key: string]: string } = {};
const nameSpace = ast.ns || ctx.nameSpace;
if (nameSpace && isNewBlock) {
// specific namespace uri
attrs["block-ns"] = nameSpace;
}
for (let key in ast.attrs) {
let expr, attrName;
if (key.startsWith("t-attf")) {
expr = interpolate(ast.attrs[key]);
let expr = interpolate(ast.attrs[key]);
const idx = block!.insertData(expr, "attr");
attrName = key.slice(7);
attrs["block-attribute-" + idx] = attrName;
attrs["block-attribute-" + idx] = key.slice(7);
} else if (key.startsWith("t-att")) {
expr = compileExpr(ast.attrs[key]);
let expr = compileExpr(ast.attrs[key]);
const idx = block!.insertData(expr, "attr");
if (key === "t-att") {
attrs[`block-attributes`] = String(idx);
} else {
attrName = key.slice(6);
attrs[`block-attribute-${idx}`] = attrName;
attrs[`block-attribute-${idx}`] = key.slice(6);
}
} else if (this.translatableAttributes.includes(key)) {
attrs[key] = this.translateFn(ast.attrs[key]);
} else {
expr = `"${ast.attrs[key]}"`;
attrName = key;
attrs[key] = ast.attrs[key];
}
if (attrName === "value" && ctx.tModelSelectedExpr) {
let selectedId = block!.insertData(`${ctx.tModelSelectedExpr} === ${expr}`, "attr");
attrs[`block-attribute-${selectedId}`] = "selected";
}
}
// event handlers
@@ -634,10 +600,8 @@ export class CodeGenerator {
}
// t-model
let tModelSelectedExpr;
if (ast.model) {
const {
hasDynamicChildren,
baseExpr,
expr,
eventType,
@@ -648,25 +612,20 @@ export class CodeGenerator {
} = ast.model;
const baseExpression = compileExpr(baseExpr);
const bExprId = this.generateId("bExpr");
this.define(bExprId, baseExpression);
const id = this.generateId();
this.addLine(`const bExpr${id} = ${baseExpression};`);
const expression = compileExpr(expr);
const exprId = this.generateId("expr");
this.define(exprId, expression);
const fullExpression = `${bExprId}[${exprId}]`;
let idx: number;
if (specialInitTargetAttr) {
idx = block!.insertData(`${fullExpression} === '${attrs[targetAttr]}'`, "attr");
idx = block!.insertData(
`${baseExpression}[${expression}] === '${attrs[targetAttr]}'`,
"attr"
);
attrs[`block-attribute-${idx}`] = specialInitTargetAttr;
} else if (hasDynamicChildren) {
const bValueId = this.generateId("bValue");
tModelSelectedExpr = `${bValueId}`;
this.define(tModelSelectedExpr, fullExpression);
} else {
idx = block!.insertData(`${fullExpression}`, "attr");
idx = block!.insertData(`${baseExpression}[${expression}]`, "attr");
attrs[`block-attribute-${idx}`] = targetAttr;
}
this.helpers.add("toNumber");
@@ -674,7 +633,7 @@ export class CodeGenerator {
valueCode = shouldTrim ? `${valueCode}.trim()` : valueCode;
valueCode = shouldNumberize ? `toNumber(${valueCode})` : valueCode;
const handler = `[(ev) => { ${fullExpression} = ${valueCode}; }]`;
const handler = `[(ev) => { bExpr${id}[${expression}] = ${valueCode}; }]`;
idx = block!.insertData(handler, "hdlr");
attrs[`block-handler-${idx}`] = eventType;
}
@@ -699,7 +658,6 @@ export class CodeGenerator {
isLast: ctx.isLast && i === children.length - 1,
tKeyExpr: ctx.tKeyExpr,
nameSpace,
tModelSelectedExpr,
});
this.compileAST(child, subCtx);
}
@@ -714,13 +672,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(`const ${current!.varName} `)) {
code[i] = code[i].replace(`const ${current!.varName}`, current!.varName);
if (code[i].trimStart().startsWith(`let ${current!.varName} `)) {
code[i] = code[i].replace(`let ${current!.varName}`, current!.varName);
current = children.shift();
if (!current) break;
}
}
this.addLine(`let ${block!.children.map((c) => c.varName)};`, codeIdx);
this.target.addLine(`let ${block!.children.map((c) => c.varName)};`, codeIdx);
}
}
}
@@ -809,13 +767,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(`const ${current!.varName} `)) {
code[i] = code[i].replace(`const ${current!.varName}`, current!.varName);
if (code[i].trimStart().startsWith(`let ${current!.varName} `)) {
code[i] = code[i].replace(`let ${current!.varName}`, current!.varName);
current = children.shift();
if (!current) break;
}
}
this.addLine(`let ${block!.children.map((c) => c.varName)};`, codeIdx);
this.target.addLine(`let ${block!.children.map((c) => c.varName)};`, codeIdx);
}
// note: this part is duplicated from end of compilemulti:
@@ -838,10 +796,12 @@ export class CodeGenerator {
const l = `l_block${block.id}`;
const c = `c_block${block.id}`;
this.helpers.add("prepareList");
this.define(`[${keys}, ${vals}, ${l}, ${c}]`, `prepareList(${compileExpr(ast.collection)});`);
this.addLine(
`const [${keys}, ${vals}, ${l}, ${c}] = prepareList(${compileExpr(ast.collection)});`
);
// Throw errors on duplicate keys in dev mode
if (this.dev) {
this.define(`keys${block.id}`, `new Set()`);
this.addLine(`const keys${block.id} = new Set();`);
}
this.addLine(`for (let ${loopVar} = 0; ${loopVar} < ${l}; ${loopVar}++) {`);
this.target.indentLevel++;
@@ -858,7 +818,7 @@ export class CodeGenerator {
if (!ast.hasNoValue) {
this.addLine(`ctx[\`${ast.elem}_value\`] = ${keys}[${loopVar}];`);
}
this.define(`key${this.target.loopLevel}`, ast.key ? compileExpr(ast.key) : loopVar);
this.addLine(`let key${this.target.loopLevel} = ${ast.key ? compileExpr(ast.key) : loopVar};`);
if (this.dev) {
// Throw error on duplicate keys in dev mode
this.addLine(
@@ -870,8 +830,8 @@ export class CodeGenerator {
if (ast.memo) {
this.target.hasCache = true;
id = this.generateId();
this.define(`memo${id}`, compileExpr(ast.memo));
this.define(`vnode${id}`, `cache[key${this.target.loopLevel}];`);
this.addLine(`let memo${id} = ${compileExpr(ast.memo)}`);
this.addLine(`let vnode${id} = cache[key${this.target.loopLevel}];`);
this.addLine(`if (vnode${id}) {`);
this.target.indentLevel++;
this.addLine(`if (shallowEqual(vnode${id}.memo, memo${id})) {`);
@@ -905,7 +865,7 @@ export class CodeGenerator {
compileTKey(ast: ASTTKey, ctx: Context) {
const tKeyExpr = this.generateId("tKey_");
this.define(tKeyExpr, compileExpr(ast.expr));
this.addLine(`const ${tKeyExpr} = ${compileExpr(ast.expr)};`);
ctx = createContext(ctx, {
tKeyExpr,
block: ctx.block,
@@ -951,13 +911,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(`const ${current!.varName} `)) {
code[i] = code[i].replace(`const ${current!.varName}`, current!.varName);
if (code[i].trimStart().startsWith(`let ${current!.varName} `)) {
code[i] = code[i].replace(`let ${current!.varName}`, current!.varName);
current = children.shift();
if (!current) break;
}
}
this.addLine(`let ${block!.children.map((c) => c.varName)};`, codeIdx);
this.target.addLine(`let ${block!.children.map((c) => c.varName)};`, codeIdx);
}
}
@@ -990,7 +950,7 @@ export class CodeGenerator {
const key = `key + \`${this.generateComponentKey()}\``;
if (isDynamic) {
const templateVar = this.generateId("template");
this.define(templateVar, subTemplate);
this.addLine(`const ${templateVar} = ${subTemplate};`);
block = this.createBlock(block, "multi", ctx);
this.helpers.add("call");
this.insertBlock(`call(this, ${templateVar}, ctx, node, ${key})`, block!, {
@@ -1000,7 +960,7 @@ export class CodeGenerator {
} else {
const id = this.generateId(`callTemplate_`);
this.helpers.add("getTemplate");
this.staticDefs.push({ id, expr: `getTemplate(${subTemplate})` });
this.staticCalls.push({ id, template: subTemplate });
block = this.createBlock(block, "multi", ctx);
this.insertBlock(`${id}.call(this, ctx, node, ${key})`, block!, {
...ctx,
@@ -1058,74 +1018,54 @@ export class CodeGenerator {
return parts.join("__");
}
/**
* Formats a prop name and value into a string suitable to be inserted in the
* generated code. For example:
*
* Name Value Result
* ---------------------------------------------------------
* "number" "state" "number: ctx['state']"
* "something" "" "something: undefined"
* "some-prop" "state" "'some-prop': ctx['state']"
* "onClick.bind" "onClick" "onClick: bind(ctx, ctx['onClick'])"
*/
formatProp(name: string, value: string): string {
value = this.captureExpression(value);
if (name.includes(".")) {
let [_name, suffix] = name.split(".");
if (suffix === "bind") {
this.helpers.add("bind");
name = _name;
value = `bind(ctx, ${value || undefined})`;
} else {
throw new Error("Invalid prop suffix");
}
}
name = /^[a-z_]+$/i.test(name) ? name : `'${name}'`;
return `${name}: ${value || undefined}`;
}
formatPropObject(obj: { [prop: string]: any }): string {
const params = [];
for (const [n, v] of Object.entries(obj)) {
params.push(this.formatProp(n, v));
}
return params.join(", ");
}
compileComponent(ast: ASTComponent, ctx: Context) {
let { block } = ctx;
// props
const hasSlotsProp = "slots" in (ast.props || {});
const props: string[] = [];
const propExpr = this.formatPropObject(ast.props || {});
if (propExpr) {
props.push(propExpr);
let hasSlotsProp = false;
for (let propName in ast.props) {
let propValue = this.captureExpression(ast.props[propName]) || undefined;
if (propName.includes(".")) {
let [name, suffix] = propName.split(".");
if (suffix === "bind") {
this.helpers.add("bind");
propName = name;
propValue = `bind(ctx, ${propValue})`;
} else {
throw new Error("Invalid prop suffix");
}
}
propName = /^[a-z_]+$/i.test(propName) ? propName : `'${propName}'`;
props.push(`${propName}: ${propValue}`);
if (propName === "slots") {
hasSlotsProp = true;
}
}
// slots
const hasSlot = !!Object.keys(ast.slots).length;
let slotDef: string = "";
if (ast.slots) {
if (hasSlot) {
let ctxStr = "ctx";
if (this.target.loopLevel || !this.hasSafeContext) {
ctxStr = this.generateId("ctx");
this.helpers.add("capture");
this.define(ctxStr, `capture(ctx)`);
this.addLine(`const ${ctxStr} = capture(ctx);`);
}
let slotStr: string[] = [];
for (let slotName in ast.slots) {
const slotAst = ast.slots[slotName];
const params = [];
if (slotAst.content) {
const name = this.compileInNewTarget("slot", slotAst.content, ctx, slotAst.on);
params.push(`__render: ${name}, __ctx: ${ctxStr}`);
}
const slotAst = ast.slots[slotName].content;
const name = this.compileInNewTarget("slot", slotAst, ctx);
const params = [`__render: ${name}, __ctx: ${ctxStr}`];
const scope = ast.slots[slotName].scope;
if (scope) {
params.push(`__scope: "${scope}"`);
}
if (ast.slots[slotName].attrs) {
params.push(this.formatPropObject(ast.slots[slotName].attrs!));
for (const [n, v] of Object.entries(ast.slots[slotName].attrs!)) {
params.push(`${n}: ${compileExpr(v) || undefined}`);
}
}
const slotInfo = `{${params.join(", ")}}`;
slotStr.push(`'${slotName}': ${slotInfo}`);
@@ -1134,8 +1074,7 @@ export class CodeGenerator {
}
if (slotDef && !(ast.dynamicProps || hasSlotsProp)) {
this.helpers.add("markRaw");
props.push(`slots: markRaw(${slotDef})`);
props.push(`slots: ${slotDef}`);
}
const propStr = `{${props.join(",")}}`;
@@ -1150,13 +1089,12 @@ export class CodeGenerator {
let propVar: string;
if ((slotDef && (ast.dynamicProps || hasSlotsProp)) || this.dev) {
propVar = this.generateId("props");
this.define(propVar!, propString);
this.addLine(`const ${propVar!} = ${propString}`);
propString = propVar!;
}
if (slotDef && (ast.dynamicProps || hasSlotsProp)) {
this.helpers.add("markRaw");
this.addLine(`${propVar!}.slots = markRaw(Object.assign(${slotDef}, ${propVar!}.slots))`);
this.addLine(`${propVar!}.slots = Object.assign(${slotDef}, ${propVar!}.slots)`);
}
// cmap key
@@ -1164,13 +1102,13 @@ export class CodeGenerator {
let expr: string;
if (ast.isDynamic) {
expr = this.generateId("Comp");
this.define(expr, compileExpr(ast.name));
this.addLine(`let ${expr} = ${compileExpr(ast.name)};`);
} else {
expr = `\`${ast.name}\``;
}
if (this.dev) {
this.addLine(`helpers.validateProps(${expr}, ${propVar!}, ctx);`);
this.addLine(`helpers.validateProps(${expr}, ${propVar!}, ctx)`);
}
if (block && (ctx.forceNewBlock === false || ctx.tKeyExpr)) {
@@ -1187,32 +1125,10 @@ 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;
@@ -1226,24 +1142,27 @@ export class CodeGenerator {
slotName = "'" + ast.name + "'";
}
const scope = ast.attrs ? `{${this.formatPropObject(ast.attrs)}}` : null;
let scope = null;
if (ast.attrs) {
const params = [];
for (const [n, v] of Object.entries(ast.attrs!)) {
params.push(`${n}: ${compileExpr(v) || undefined}`);
}
scope = `{${params.join(", ")}}`;
}
if (ast.defaultContent) {
const name = this.compileInNewTarget("defaultContent", ast.defaultContent, ctx);
blockString = `callSlot(ctx, node, key, ${slotName}, ${dynamic}, ${scope}, ${name})`;
} else {
if (dynamic) {
let name = this.generateId("slot");
this.define(name, slotName);
blockString = `toggler(${name}, callSlot(ctx, node, key, ${name}, ${dynamic}, ${scope}))`;
this.addLine(`const ${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);
}
@@ -1266,7 +1185,7 @@ export class CodeGenerator {
if (this.target.loopLevel || !this.hasSafeContext) {
ctxStr = this.generateId("ctx");
this.helpers.add("capture");
this.define(ctxStr, `capture(ctx);`);
this.addLine(`const ${ctxStr} = capture(ctx);`);
}
const blockString = `component(Portal, {target: ${ast.target},slots: {'default': {__render: ${name}, __ctx: ${ctxStr}}}}, key + \`${key}\`, node, ctx)`;
if (block) {
+1 -4
View File
@@ -9,10 +9,7 @@ export type TemplateFunction = (blocks: any, utils: any) => Template;
interface CompileOptions extends Config {
name?: string;
}
export function compile(
template: string | Element,
options: CompileOptions = {}
): TemplateFunction {
export function compile(template: string | Node, options: CompileOptions = {}): TemplateFunction {
// parsing
const ast = parse(template);
+14 -22
View File
@@ -199,30 +199,24 @@ const TOKENIZERS = [
export function tokenize(expr: string): Token[] {
const result: Token[] = [];
let token: boolean | Token = true;
let error: any;
let current = expr;
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;
}
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;
}
} else {
token = false;
}
} else {
token = false;
}
} catch (e) {
error = e; // Silence all errors and throw a generic error below
}
if (current.length || error) {
throw new Error(`Tokenizer error: could not tokenize \`${expr}\``);
if (expr.length) {
throw new Error(`Tokenizer error: could not tokenize "${expr}"`);
}
return result;
}
@@ -335,9 +329,7 @@ export function compileExprToArray(expr: string): Token[] {
// Mark all variables that have been used locally.
// This assumes the expression has only one scope (incorrect but "good enough for now")
for (const token of tokens) {
if (token.type === "SYMBOL" && token.varName && localVars.has(token.value)) {
token.originalValue = token.value;
token.value = `_${token.value}`;
if (token.type === "SYMBOL" && localVars.has(token.value)) {
token.isLocal = true;
}
}
+62 -128
View File
@@ -2,9 +2,6 @@
// AST Type definition
// -----------------------------------------------------------------------------
export type EventHandlers = { [eventName: string]: string };
export type Attrs = { [attrs: string]: string };
export const enum ASTType {
Text,
Comment,
@@ -36,26 +33,23 @@ export interface ASTComment {
value: string;
}
interface TModelInfo {
baseExpr: string;
expr: string;
targetAttr: string;
eventType: "change" | "click" | "input";
shouldTrim: boolean;
shouldNumberize: boolean;
hasDynamicChildren: boolean;
specialInitTargetAttr: string | null;
}
export interface ASTDomNode {
type: ASTType.DomNode;
tag: string;
content: AST[];
attrs: Attrs | null;
ref: string | null;
on: EventHandlers | null;
model: TModelInfo | null;
dynamicTag: string | null;
attrs: { [key: string]: string };
content: AST[];
ref: string | null;
on: { [key: string]: string };
model: {
baseExpr: string;
expr: string;
targetAttr: string;
specialInitTargetAttr: string | null;
eventType: "change" | "click" | "input";
shouldTrim: boolean;
shouldNumberize: boolean;
} | null;
ns: string | null;
}
@@ -96,13 +90,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 {
@@ -117,28 +111,19 @@ export interface ASTTCall {
body: AST[] | null;
}
interface SlotDefinition {
content: AST | null;
scope: string | null;
on: EventHandlers | null;
attrs: Attrs | null;
}
export interface ASTComponent {
type: ASTType.TComponent;
name: string;
isDynamic: boolean;
dynamicProps: string | null;
on: EventHandlers | null;
props: { [name: string]: string } | null;
slots: { [name: string]: SlotDefinition } | null;
props: { [name: string]: string };
slots: { [name: string]: { content: AST; attrs?: { [key: string]: string }; scope?: string } };
}
export interface ASTSlot {
type: ASTType.TSlot;
name: string;
attrs: Attrs | null;
on: EventHandlers | null;
attrs: { [key: string]: string };
defaultContent: AST | null;
}
@@ -192,35 +177,23 @@ export type AST =
// -----------------------------------------------------------------------------
// Parser
// -----------------------------------------------------------------------------
const cache: WeakMap<Element, AST> = new WeakMap();
export function parse(xml: string | Element): AST {
if (typeof xml === "string") {
const elem = parseXML(`<t>${xml}</t>`).firstChild as Element;
return _parse(elem);
}
let ast = cache.get(xml);
if (!ast) {
// we clone here the xml to prevent modifying it in place
ast = _parse(xml.cloneNode(true) as Element);
cache.set(xml, ast);
}
return ast;
}
function _parse(xml: Element): AST {
normalizeXML(xml);
const ctx = { inPreTag: false, inSVG: false };
return parseNode(xml, ctx) || { type: ASTType.Text, value: "" };
}
interface ParsingContext {
tModelInfo?: TModelInfo | null;
inPreTag: boolean;
inSVG: boolean;
}
function parseNode(node: Node, ctx: ParsingContext): AST | null {
export function parse(xml: string | Node): AST {
const node = xml instanceof Element ? xml : (parseXML(`<t>${xml}</t>`).firstChild! as Element);
normalizeXML(node);
const ctx = { inPreTag: false, inSVG: false };
const ast = parseNode(node, ctx);
if (!ast) {
return { type: ASTType.Text, value: "" };
}
return ast;
}
function parseNode(node: ChildNode, ctx: ParsingContext): AST | null {
if (!(node instanceof Element)) {
return parseTextCommentNode(node, ctx);
}
@@ -260,7 +233,7 @@ function parseTNode(node: Element, ctx: ParsingContext): AST | null {
const lineBreakRE = /[\r\n]/;
const whitespaceRE = /\s+/g;
function parseTextCommentNode(node: Node, ctx: ParsingContext): AST | null {
function parseTextCommentNode(node: ChildNode, ctx: ParsingContext): AST | null {
if (node.nodeType === Node.TEXT_NODE) {
let value = node.textContent || "";
if (!ctx.inPreTag) {
@@ -308,8 +281,6 @@ function parseTDebugLog(node: Element, ctx: ParsingContext): AST | null {
const hasDotAtTheEnd = /\.[\w_]+\s*$/;
const hasBracketsAtTheEnd = /\[[^\[]+\]\s*$/;
const ROOT_SVG_TAGS = new Set(["svg", "g", "path"]);
function parseDOMNode(node: Element, ctx: ParsingContext): AST | null {
const { tagName } = node;
const dynamicTag = node.getAttribute("t-tag");
@@ -317,23 +288,22 @@ 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;
}
const shouldAddSVGNS = ROOT_SVG_TAGS.has(tagName) && !ctx.inSVG;
const shouldAddSVGNS = tagName === "svg" || (tagName === "g" && !ctx.inSVG);
ctx.inSVG = ctx.inSVG || shouldAddSVGNS;
const ns = shouldAddSVGNS ? "http://www.w3.org/2000/svg" : null;
const ref = node.getAttribute("t-ref");
node.removeAttribute("t-ref");
const children = parseChildren(node, ctx);
const nodeAttrsNames = node.getAttributeNames();
let attrs: ASTDomNode["attrs"] = null;
let on: EventHandlers | null = null;
let model: TModelInfo | null = null;
const attrs: ASTDomNode["attrs"] = {};
const on: ASTDomNode["on"] = {};
let model: ASTDomNode["model"] = null;
for (let attr of nodeAttrsNames) {
const value = node.getAttribute(attr)!;
@@ -341,7 +311,6 @@ 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)) {
@@ -379,31 +348,16 @@ 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),
};
if (isSelect) {
// don't pollute the original ctx
ctx = Object.assign({}, ctx);
ctx.tModelInfo = model;
}
} else if (attr.startsWith("block-")) {
throw new Error(`Invalid attribute: '${attr}'`);
} else if (attr !== "t-name") {
} else {
if (attr.startsWith("t-") && !attr.startsWith("t-att")) {
throw new Error(`Unknown QWeb directive: '${attr}'`);
}
const tModel = ctx.tModelInfo;
if (tModel && ["t-att-value", "t-attf-value"].includes(attr)) {
tModel.hasDynamicChildren = true;
}
attrs = attrs || {};
attrs[attr] = value;
}
}
const children = parseChildren(node, ctx);
return {
type: ASTType.DomNode,
tag: tagName,
@@ -569,7 +523,7 @@ function parseTCall(node: Element, ctx: ParsingContext): AST | null {
if (ast && ast.type === ASTType.TComponent) {
return {
...ast,
slots: { default: { content: tcall, scope: null, on: null, attrs: null } },
slots: { default: { content: tcall } },
};
}
}
@@ -665,6 +619,7 @@ 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.",
@@ -696,28 +651,18 @@ function parseComponent(node: Element, ctx: ParsingContext): AST | null {
const dynamicProps = node.getAttribute("t-props");
node.removeAttribute("t-props");
const defaultSlotScope = node.getAttribute("t-slot-scope");
node.removeAttribute("t-slot-scope");
let on: ASTComponent["on"] = null;
let props: ASTComponent["props"] = null;
const props: ASTComponent["props"] = {};
for (let name of node.getAttributeNames()) {
const value = node.getAttribute(name)!;
if (name.startsWith("t-")) {
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}`);
}
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;
}
}
let slots: ASTComponent["slots"] | null = null;
const slots: ASTComponent["slots"] = {};
if (node.hasChildNodes()) {
const clone = <Element>node.cloneNode(true);
@@ -749,34 +694,31 @@ function parseComponent(node: Element, ctx: ParsingContext): AST | null {
slotNode.removeAttribute("t-set-slot");
slotNode.remove();
const slotAst = parseNode(slotNode, ctx);
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") {
scope = value;
continue;
} else if (attributeName.startsWith("t-on-")) {
on = on || {};
on[attributeName.slice(5)] = value;
} else {
attrs = attrs || {};
if (slotAst) {
const slotInfo: any = { content: slotAst };
const attrs: { [key: string]: string } = {};
for (let attributeName of slotNode.getAttributeNames()) {
const value = slotNode.getAttribute(attributeName)!;
if (attributeName === "t-slot-scope") {
slotInfo.scope = value;
continue;
}
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 = slots || {};
slots.default = { content: defaultContent, on, attrs: null, scope: defaultSlotScope };
slots.default = { content: defaultContent };
}
}
return { type: ASTType.TComponent, name, isDynamic, dynamicProps, props, slots, on };
return { type: ASTType.TComponent, name, isDynamic, dynamicProps, props, slots };
}
// -----------------------------------------------------------------------------
@@ -789,23 +731,15 @@ function parseTSlot(node: Element, ctx: ParsingContext): AST | null {
}
const name = node.getAttribute("t-slot")!;
node.removeAttribute("t-slot");
let attrs: Attrs | null = null;
let on: ASTComponent["on"] = null;
const attrs: { [key: string]: string } = {};
for (let attributeName of node.getAttributeNames()) {
const value = node.getAttribute(attributeName)!;
if (attributeName.startsWith("t-on-")) {
on = on || {};
on[attributeName.slice(5)] = value;
} else {
attrs = attrs || {};
attrs[attributeName] = value;
}
attrs[attributeName] = value;
}
return {
type: ASTType.TSlot,
name,
attrs,
on,
defaultContent: parseChildNodes(node, ctx),
};
}
@@ -852,7 +786,7 @@ function parseTPortal(node: Element, ctx: ParsingContext): AST | null {
/**
* Parse all the child nodes of a given node and return a list of ast elements
*/
function parseChildren(node: Element, ctx: ParsingContext): AST[] {
function parseChildren(node: Node, ctx: ParsingContext): AST[] {
const children: AST[] = [];
for (let child of node.childNodes) {
const childAst = parseNode(child, ctx);
@@ -871,7 +805,7 @@ function parseChildren(node: Element, ctx: ParsingContext): AST[] {
* Parse all the child nodes of a given node and return an ast if possible.
* In the case there are multiple children, they are wrapped in a astmulti.
*/
function parseChildNodes(node: Element, ctx: ParsingContext): AST | null {
function parseChildNodes(node: Node, ctx: ParsingContext): AST | null {
const children = parseChildren(node, ctx);
switch (children.length) {
case 0:
+2 -18
View File
@@ -4,25 +4,9 @@ import type { ComponentNode } from "./component_node";
// Component Class
// -----------------------------------------------------------------------------
type Props = { [key: string]: any };
interface StaticComponentProperties {
template: string;
defaultProps?: any;
props?: any;
}
export type ComponentConstructor<P extends Props = any, E = any> = (new (
props: P,
env: E,
node: ComponentNode
) => Component<P, E>) &
StaticComponentProperties;
export class Component<Props = any, Env = any> {
static template: string = "";
static props?: any;
static defaultProps?: any;
props: Props;
env: Env;
@@ -36,7 +20,7 @@ export class Component<Props = any, Env = any> {
setup() {}
render(deep: boolean = false) {
this.__owl__.render(deep);
render(force: boolean = false) {
this.__owl__.render(force);
}
}
+63 -69
View File
@@ -1,26 +1,23 @@
import type { App, Env } from "../app/app";
import { BDom, VNode } from "../blockdom";
import {
clearReactivesForCallback,
getSubscriptions,
NonReactive,
Reactive,
reactive,
TARGET,
} from "../reactivity";
import { clearReactivesForCallback, Reactive, reactive, TARGET } from "../reactivity";
import { batched, Callback } from "../utils";
import { Component, ComponentConstructor } from "./component";
import { Component } from "./component";
import { fibersInError, handleError } from "./error_handling";
import { Fiber, makeChildFiber, makeRootFiber, MountFiber, MountOptions } from "./fibers";
import {
Fiber,
makeChildFiber,
makeRootFiber,
MountFiber,
MountOptions,
RootFiber,
} from "./fibers";
import { applyDefaultProps } from "./props_validation";
import { STATUS } from "./status";
let currentNode: ComponentNode | null = null;
export function getCurrent(): ComponentNode {
if (!currentNode) {
throw new Error("No active component (a hook function should only be called in 'setup')");
}
export function getCurrent(): ComponentNode | null {
return currentNode;
}
@@ -43,14 +40,14 @@ const batchedRenderFunctions = new WeakMap<ComponentNode, Callback>();
* relevant changes
* @see reactive
*/
export function useState<T extends object>(state: T): Reactive<T> | NonReactive<T> {
const node = getCurrent();
export function useState<T extends object>(state: T): Reactive<T> {
const node = currentNode!;
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));
// manual implementation of onWillUnmount to break cyclic dependency
node.willUnmount.unshift(clearReactivesForCallback.bind(null, render));
}
return reactive(state, render);
}
@@ -66,16 +63,15 @@ function arePropsDifferent(props1: Props, props2: Props): boolean {
return true;
}
}
return Object.keys(props1).length !== Object.keys(props2).length;
return false;
}
export function component<P extends object>(
name: string | ComponentConstructor<P>,
props: P,
export function component(
name: string | typeof Component,
props: any,
key: string,
ctx: ComponentNode,
parent: any
): ComponentNode<P> {
): ComponentNode {
let node: any = ctx.children[key];
let isDynamic = typeof name !== "string";
@@ -93,14 +89,8 @@ export function component<P extends object>(
const parentFiber = ctx.fiber!;
if (node) {
let shouldRender = node.forceNextRender;
if (shouldRender) {
node.forceNextRender = false;
} else {
const currentProps = node.component.props[TARGET];
shouldRender = parentFiber.deep || arePropsDifferent(currentProps, props);
}
if (shouldRender) {
const currentProps = node.component.props[TARGET];
if (parentFiber.force || arePropsDifferent(currentProps, props)) {
node.updateAndRender(props, parentFiber);
}
} else {
@@ -116,11 +106,10 @@ export function component<P extends object>(
}
node = new ComponentNode(C, props, ctx.app, ctx);
ctx.children[key] = node;
node.initiateRender(new Fiber(node, parentFiber));
}
parentFiber.childrenMap[key] = node;
parentFiber.root!.reachedChildren.add(node);
const fiber = makeChildFiber(node, parentFiber);
node.initiateRender(fiber);
}
return node;
}
@@ -130,14 +119,15 @@ export function component<P extends object>(
type LifecycleHook = Function;
export class ComponentNode<P extends object = any, E = any> implements VNode<ComponentNode<P, E>> {
export class ComponentNode<T extends typeof Component = typeof Component>
implements VNode<ComponentNode>
{
el?: HTMLElement | Text | undefined;
app: App;
fiber: Fiber | null = null;
component: Component<P, E>;
component: InstanceType<T>;
bdom: BDom | null = null;
status: STATUS = STATUS.NEW;
forceNextRender: boolean = false;
renderFn: Function;
parent: ComponentNode | null;
@@ -154,7 +144,7 @@ export class ComponentNode<P extends object = any, E = any> implements VNode<Com
patched: LifecycleHook[] = [];
willDestroy: LifecycleHook[] = [];
constructor(C: ComponentConstructor<P, E>, props: P, app: App, parent?: ComponentNode) {
constructor(C: T, props: any, app: App, parent?: ComponentNode) {
currentNode = this;
this.app = app;
this.parent = parent || null;
@@ -166,7 +156,6 @@ export class ComponentNode<P extends object = any, E = any> implements VNode<Com
this.component = new C(props, env, this) as any;
this.renderFn = app.getTemplate(C.template).bind(this.component, this.component, this);
this.component.setup();
currentNode = null;
}
mountComponent(target: any, options?: MountOptions) {
@@ -188,33 +177,27 @@ export class ComponentNode<P extends object = any, E = any> implements VNode<Com
return;
}
if (this.status === STATUS.NEW && this.fiber === fiber) {
fiber.render();
this._render(fiber);
}
}
async render(deep: boolean = false) {
async render(force: 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) {
if (!current.bdom && !fibersInError.has(current)) {
if (deep) {
// we want the render from this point on to be with deep=true
current.deep = deep;
}
if (current && !current.bdom && !fibersInError.has(current)) {
if (current.force || force === false) {
return;
}
// if current rendering was with deep=true, we want this one to be the same
deep = deep || current.deep;
} else if (!this.bdom) {
}
if (!this.bdom && !current) {
return;
}
const fiber = makeRootFiber(this);
fiber.deep = deep;
const fiber = makeRootFiber(this, force);
this.fiber = fiber;
this.app.scheduler.addFiber(fiber);
await Promise.resolve();
@@ -233,7 +216,16 @@ export class ComponentNode<P extends object = any, E = any> implements VNode<Com
// embedded in a rendering coming from above, so the fiber will be rendered
// in the next microtick anyway, so we should not render it again.
if (this.fiber === fiber && (current || !fiber.parent)) {
fiber.render();
this._render(fiber);
}
}
_render(fiber: Fiber | RootFiber) {
try {
fiber.bdom = this.renderFn();
fiber.root!.counter--;
} catch (e) {
handleError({ node: this, error: e });
}
}
@@ -270,14 +262,13 @@ export class ComponentNode<P extends object = any, E = any> implements VNode<Com
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) {
return;
}
component.props = props;
fiber.render();
this._render(fiber);
const parentRoot = parentFiber.root!;
if (this.willPatch.length) {
parentRoot.willPatch.push(fiber);
@@ -327,7 +318,6 @@ export class ComponentNode<P extends object = any, E = any> implements VNode<Com
bdom.mount(parent, anchor);
this.status = STATUS.MOUNTED;
this.fiber!.appliedToDom = true;
this.children = this.fiber!.childrenMap;
this.fiber = null;
}
@@ -345,8 +335,10 @@ export class ComponentNode<P extends object = any, E = any> implements VNode<Com
}
_patch() {
const hasChildren = Object.keys(this.children).length > 0;
this.children = this.fiber!.childrenMap;
this.bdom!.patch(this!.fiber!.bdom!, hasChildren);
if (hasChildren) {
this.cleanOutdatedChildren();
}
this.fiber!.appliedToDom = true;
this.fiber = null;
}
@@ -359,15 +351,17 @@ export class ComponentNode<P extends object = any, E = any> implements VNode<Com
this.bdom!.remove();
}
// ---------------------------------------------------------------------------
// Some debug helpers
// ---------------------------------------------------------------------------
get name(): string {
return this.component.constructor.name;
}
get subscriptions(): ReturnType<typeof getSubscriptions> {
const render = batchedRenderFunctions.get(this);
return render ? getSubscriptions(render) : [];
cleanOutdatedChildren() {
const children = this.children;
for (const key in children) {
const node = children[key];
const status = node.status;
if (status !== STATUS.MOUNTED) {
delete children[key];
if (status !== STATUS.DESTROYED) {
node.destroy();
}
}
}
}
}
+1 -2
View File
@@ -30,8 +30,7 @@ function _handleError(node: ComponentNode | null, error: any, isFirstRound = fal
if (stopped) {
if (isFirstRound && fiber && fiber.node.fiber) {
const root = fiber.root!;
root.setCounter(root.counter - 1);
fiber.root!.counter--;
}
return true;
}
+15 -82
View File
@@ -6,23 +6,22 @@ import { STATUS } from "./status";
export function makeChildFiber(node: ComponentNode, parent: Fiber): Fiber {
let current = node.fiber;
if (current) {
cancelFibers(current.children);
let root = parent.root;
cancelFibers(root, current.children);
current.root = null;
}
return new Fiber(node, parent);
}
export function makeRootFiber(node: ComponentNode): Fiber {
export function makeRootFiber(node: ComponentNode, force: boolean): Fiber {
let current = node.fiber;
if (current) {
let root = current.root!;
root.setCounter(root.counter + 1 - cancelFibers(current.children));
root.counter -= cancelFibers(root, current.children);
current.children = [];
current.childrenMap = {};
root.counter++;
current.bdom = null;
if (current === root) {
root.reachedChildren = new WeakSet();
}
current.force = force;
if (fibersInError.has(current)) {
fibersInError.delete(current);
fibersInError.delete(root);
@@ -37,32 +36,22 @@ export function makeRootFiber(node: ComponentNode): Fiber {
if (node.patched.length) {
fiber.patched.push(fiber);
}
fiber.force = force;
return fiber;
}
/**
* @returns number of not-yet rendered fibers cancelled
*/
function cancelFibers(fibers: Fiber[]): number {
function cancelFibers(root: any, fibers: Fiber[]): number {
let result = 0;
for (let fiber of fibers) {
let node = fiber.node;
if (node.status === STATUS.NEW) {
node.destroy();
}
node.fiber = null;
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.
node.forceNextRender = true;
} else {
fiber.node.fiber = null;
fiber.root = root;
if (!fiber.bdom) {
result++;
}
result += cancelFibers(fiber.children);
result += cancelFibers(root, fiber.children);
}
return result;
}
@@ -74,66 +63,21 @@ export class Fiber {
parent: Fiber | null;
children: Fiber[] = [];
appliedToDom = false;
deep: boolean = false;
childrenMap: ComponentNode["children"] = {};
force: boolean = false;
constructor(node: ComponentNode, parent: Fiber | null) {
this.node = node;
this.parent = parent;
if (parent) {
this.deep = parent.deep;
this.force = parent.force;
const root = parent.root!;
root.setCounter(root.counter + 1);
root.counter++;
this.root = root;
parent.children.push(this);
} else {
this.root = this as any;
}
}
render() {
// if some parent has a fiber => register in followup
let prev = this.root!.node;
let scheduler = prev.app.scheduler;
let current = prev.parent;
while (current) {
if (current.fiber) {
let root = current.fiber.root!;
if (root.counter) {
scheduler.delayedRenders.push(this);
return;
} else {
if (!root.reachedChildren.has(prev)) {
// is dead. but we keep the render around just in case
scheduler.delayedRenders.push(this);
return;
}
current = root.node;
}
}
prev = current;
current = current.parent;
}
// there are no current rendering from above => we can render
this._render();
}
_render() {
const node = this.node;
if (node.status > STATUS.MOUNTED) {
return;
}
const root = this.root;
if (root) {
try {
this.bdom = node.renderFn();
root.setCounter(root.counter - 1);
} catch (e) {
handleError({ node, error: e });
}
}
}
}
export class RootFiber extends Fiber {
@@ -147,8 +91,6 @@ export class RootFiber extends Fiber {
// i.e.: render triggered in onWillUnmount or in willPatch will be delayed
locked: boolean = false;
reachedChildren: WeakSet<ComponentNode> = new WeakSet();
complete() {
const node = this.node;
this.locked = true;
@@ -199,13 +141,6 @@ export class RootFiber extends Fiber {
handleError({ fiber: current || this, error: e });
}
}
setCounter(newValue: number) {
this.counter = newValue;
if (newValue === 0) {
this.node.app.scheduler.flush();
}
}
}
type Position = "first-child" | "last-child";
@@ -227,8 +162,6 @@ export class MountFiber extends RootFiber {
let current: Fiber | undefined = this;
try {
const node = this.node;
node.children = this.childrenMap;
(node.app.constructor as any).validateTarget(this.target);
if (node.bdom) {
// this is a complicated situation: if we mount a fiber with an existing
// bdom, this means that this same fiber was already completed, mounted,
+19 -70
View File
@@ -1,118 +1,67 @@
import { getCurrent } from "./component_node";
import { nodeErrorHandlers } from "./error_handling";
const TIMEOUT = Symbol("timeout");
function wrapError(fn: (...args: any[]) => any, hookName: string) {
const error = new Error(`The following error occurred in ${hookName}: `) as Error & {
cause: any;
};
const timeoutError = new Error(`${hookName}'s promise hasn't resolved after 3 seconds`);
const node = getCurrent();
return (...args: any[]) => {
try {
const result = fn(...args);
if (result instanceof Promise) {
if (hookName === "onWillStart" || hookName === "onWillUpdateProps") {
const fiber = node.fiber;
Promise.race([
result,
new Promise((resolve) => setTimeout(() => resolve(TIMEOUT), 3000)),
]).then((res) => {
if (res === TIMEOUT && node.fiber === fiber) {
console.warn(timeoutError);
}
});
}
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();
const decorate = node.app.dev ? wrapError : (fn: any) => fn;
node.willStart.push(decorate(fn.bind(node.component), "onWillStart"));
const node = getCurrent()!;
node.willStart.push(fn.bind(node.component));
}
export function onWillUpdateProps(fn: (nextProps: any) => Promise<void> | void | any) {
const node = getCurrent();
const decorate = node.app.dev ? wrapError : (fn: any) => fn;
node.willUpdateProps.push(decorate(fn.bind(node.component), "onWillUpdateProps"));
const node = getCurrent()!;
node.willUpdateProps.push(fn.bind(node.component));
}
export function onMounted(fn: () => void | any) {
const node = getCurrent();
const decorate = node.app.dev ? wrapError : (fn: any) => fn;
node.mounted.push(decorate(fn.bind(node.component), "onMounted"));
const node = getCurrent()!;
node.mounted.push(fn.bind(node.component));
}
export function onWillPatch(fn: () => Promise<void> | any | void) {
const node = getCurrent();
const decorate = node.app.dev ? wrapError : (fn: any) => fn;
node.willPatch.unshift(decorate(fn.bind(node.component), "onWillPatch"));
const node = getCurrent()!;
node.willPatch.unshift(fn.bind(node.component));
}
export function onPatched(fn: () => void | any) {
const node = getCurrent();
const decorate = node.app.dev ? wrapError : (fn: any) => fn;
node.patched.push(decorate(fn.bind(node.component), "onPatched"));
const node = getCurrent()!;
node.patched.push(fn.bind(node.component));
}
export function onWillUnmount(fn: () => Promise<void> | void | any) {
const node = getCurrent();
const decorate = node.app.dev ? wrapError : (fn: any) => fn;
node.willUnmount.unshift(decorate(fn.bind(node.component), "onWillUnmount"));
const node = getCurrent()!;
node.willUnmount.unshift(fn.bind(node.component));
}
export function onWillDestroy(fn: () => Promise<void> | void | any) {
const node = getCurrent();
const decorate = node.app.dev ? wrapError : (fn: any) => fn;
node.willDestroy.push(decorate(fn.bind(node.component), "onWillDestroy"));
const node = getCurrent()!;
node.willDestroy.push(fn.bind(node.component));
}
export function onWillRender(fn: () => void | any) {
const node = getCurrent();
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();
fn.call(node.component);
return renderFn();
};
}
export function onRendered(fn: () => void | any) {
const node = getCurrent();
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();
fn.call(node.component);
return result;
};
}
type OnErrorCallback = (error: any) => void | any;
export function onError(callback: OnErrorCallback) {
const node = getCurrent();
const node = getCurrent()!;
let handlers = nodeErrorHandlers.get(node);
if (!handlers) {
handlers = [];
+13 -30
View File
@@ -1,16 +1,16 @@
import { ComponentConstructor } from "./component";
import { Component } from "./component";
/**
* Apply default props (only top level).
*
* Note that this method does modify in place the props
*/
export function applyDefaultProps<P>(props: P, ComponentClass: ComponentConstructor<P>) {
const defaultProps = ComponentClass.defaultProps;
export function applyDefaultProps(props: { [key: string]: any }, ComponentClass: typeof Component) {
const defaultProps = (ComponentClass as any).defaultProps;
if (defaultProps) {
for (let propName in defaultProps) {
if ((props as any)[propName] === undefined) {
(props as any)[propName] = defaultProps[propName];
if (props![propName] === undefined) {
props![propName] = defaultProps[propName];
}
}
}
@@ -34,20 +34,13 @@ function getPropDescription(staticProps: any) {
* visit recursively the props and all the children to check if they are valid.
* This is why it is only done in 'dev' mode.
*/
export function validateProps<P>(name: string | ComponentConstructor<P>, props: P, parent?: any) {
const ComponentClass =
typeof name !== "string"
? name
: (parent.constructor.components[name] as ComponentConstructor<P> | undefined);
export const validateProps = function (name: string | typeof Component, props: any, parent?: any) {
const ComponentClass = (
typeof name !== "string" ? name : parent.constructor.components[name]
) as typeof Component;
if (!ComponentClass) {
// this is an error, wrong component. We silently return here instead so the
// error is triggered by the usual path ('component' function)
return;
}
applyDefaultProps(props, ComponentClass);
const defaultProps = ComponentClass.defaultProps || {};
let propsDef = getPropDescription(ComponentClass.props);
const allowAdditionalProps = "*" in propsDef;
@@ -55,18 +48,8 @@ export function validateProps<P>(name: string | ComponentConstructor<P>, props:
if (propName === "*") {
continue;
}
const propDef = propsDef[propName];
let isMandatory = !!propDef;
if (typeof propDef === "object" && "optional" in propDef) {
isMandatory = !propDef.optional;
}
if (isMandatory && propName in defaultProps) {
throw new Error(
`A default value cannot be defined for a mandatory prop (name: '${propName}', component: ${ComponentClass.name})`
);
}
if ((props as any)[propName] === undefined) {
if (isMandatory) {
if (props[propName] === undefined) {
if (propsDef[propName] && !propsDef[propName].optional) {
throw new Error(`Missing props '${propName}' (component '${ComponentClass.name}')`);
} else {
continue;
@@ -74,7 +57,7 @@ export function validateProps<P>(name: string | ComponentConstructor<P>, props:
}
let isValid;
try {
isValid = isValidProp((props as any)[propName], propDef);
isValid = isValidProp(props[propName], propsDef[propName]);
} catch (e) {
(e as Error).message = `Invalid prop '${propName}' in component ${ComponentClass.name} (${
(e as Error).message
@@ -92,7 +75,7 @@ export function validateProps<P>(name: string | ComponentConstructor<P>, props:
}
}
}
}
};
/**
* Check if an invidual prop value matches its (static) prop definition
+40 -39
View File
@@ -11,16 +11,27 @@ export class Scheduler {
// interactions with other code, such as test frameworks that override them
static requestAnimationFrame = window.requestAnimationFrame.bind(window);
tasks: Set<RootFiber> = new Set();
isRunning: boolean = false;
requestAnimationFrame: Window["requestAnimationFrame"];
frame: number = 0;
delayedRenders: Fiber[] = [];
constructor() {
this.requestAnimationFrame = Scheduler.requestAnimationFrame;
}
start() {
this.isRunning = true;
this.scheduleTasks();
}
stop() {
this.isRunning = false;
}
addFiber(fiber: Fiber) {
this.tasks.add(fiber.root!);
if (!this.isRunning) {
this.start();
}
}
/**
@@ -28,49 +39,39 @@ export class Scheduler {
* Other tasks are left unchanged.
*/
flush() {
if (this.delayedRenders.length) {
let renders = this.delayedRenders;
this.delayedRenders = [];
for (let f of renders) {
if (f.root) {
f.render();
}
this.tasks.forEach((fiber) => {
if (fiber.root !== fiber) {
this.tasks.delete(fiber);
return;
}
const hasError = fibersInError.has(fiber);
if (hasError && fiber.counter !== 0) {
this.tasks.delete(fiber);
return;
}
if (fiber.node.status === STATUS.DESTROYED) {
this.tasks.delete(fiber);
return;
}
}
if (this.frame === 0) {
this.frame = this.requestAnimationFrame(() => {
this.frame = 0;
this.tasks.forEach((fiber) => this.processFiber(fiber));
for (let task of this.tasks) {
if (task.node.status === STATUS.DESTROYED) {
this.tasks.delete(task);
}
if (fiber.counter === 0) {
if (!hasError) {
fiber.complete();
}
});
this.tasks.delete(fiber);
}
});
if (this.tasks.size === 0) {
this.stop();
}
}
processFiber(fiber: RootFiber) {
if (fiber.root !== fiber) {
this.tasks.delete(fiber);
return;
}
const hasError = fibersInError.has(fiber);
if (hasError && fiber.counter !== 0) {
this.tasks.delete(fiber);
return;
}
if (fiber.node.status === STATUS.DESTROYED) {
this.tasks.delete(fiber);
return;
}
if (fiber.counter === 0) {
if (!hasError) {
fiber.complete();
scheduleTasks() {
this.requestAnimationFrame(() => {
this.flush();
if (this.isRunning) {
this.scheduleTasks();
}
this.tasks.delete(fiber);
}
});
}
}
+13 -23
View File
@@ -11,7 +11,7 @@ import { onMounted, onPatched, onWillUnmount } from "./component/lifecycle_hooks
* html node or component.
*/
export function useRef<T extends HTMLElement = HTMLElement>(name: string): { el: T | null } {
const node = getCurrent();
const node = getCurrent()!;
const refs = node.refs;
return {
get el(): T | null {
@@ -29,13 +29,7 @@ export function useRef<T extends HTMLElement = HTMLElement>(name: string): { el:
* need a reference to the env of the component calling them.
*/
export function useEnv<E extends Env>(): E {
return getCurrent().component.env as any;
}
function extendEnv(currentEnv: Object, extension: Object): Object {
const env = Object.create(currentEnv);
const descrs = Object.getOwnPropertyDescriptors(extension);
return Object.freeze(Object.defineProperties(env, descrs));
return getCurrent()!.component.env as any;
}
/**
@@ -44,19 +38,17 @@ function extendEnv(currentEnv: Object, extension: Object): Object {
* constructor method.
*/
export function useSubEnv(envExtension: Env) {
const node = getCurrent();
node.component.env = extendEnv(node.component.env as any, envExtension);
useChildSubEnv(envExtension);
const node = getCurrent()!;
const env = Object.create(node.childEnv);
const descrs = Object.getOwnPropertyDescriptors(envExtension);
node.childEnv = Object.freeze(Object.defineProperties(env, descrs));
}
export function useChildSubEnv(envExtension: Env) {
const node = getCurrent();
node.childEnv = extendEnv(node.childEnv, envExtension);
}
// -----------------------------------------------------------------------------
// useEffect
// -----------------------------------------------------------------------------
const NO_OP = () => {};
/**
* @param {...any} dependencies the dependencies computed by computeDependencies
* @returns {void|(()=>void)} a cleanup function that reverses the side
@@ -77,11 +69,11 @@ type Effect = (...dependencies: any[]) => void | (() => void);
* NaN !== NaN, which will cause the effect to rerun on every patch.
*/
export function useEffect(effect: Effect, computeDependencies: () => any[] = () => [NaN]) {
let cleanup: (() => void) | void;
let cleanup: () => void;
let dependencies: any[];
onMounted(() => {
dependencies = computeDependencies();
cleanup = effect(...dependencies);
cleanup = effect(...dependencies) || NO_OP;
});
onPatched(() => {
@@ -89,14 +81,12 @@ export function useEffect(effect: Effect, computeDependencies: () => any[] = ()
const shouldReapply = newDeps.some((val, i) => val !== dependencies[i]);
if (shouldReapply) {
dependencies = newDeps;
if (cleanup) {
cleanup();
}
cleanup = effect(...dependencies);
cleanup();
cleanup = effect(...dependencies) || NO_OP;
}
});
onWillUnmount(() => cleanup && cleanup());
onWillUnmount(() => cleanup());
}
// -----------------------------------------------------------------------------
@@ -122,7 +112,7 @@ export function useExternalListener(
handler: EventListener,
eventParams?: AddEventListenerOptions
) {
const node = getCurrent();
const node = getCurrent()!;
const boundHandler = handler.bind(node.component);
onMounted(() => target.addEventListener(eventName, boundHandler, eventParams));
onWillUnmount(() => target.removeEventListener(eventName, boundHandler, eventParams));
+10 -4
View File
@@ -1,3 +1,4 @@
import { UTILS } from "./app/template_helpers";
import {
config,
createBlock,
@@ -12,10 +13,12 @@ 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,
@@ -35,11 +38,14 @@ export const blockDom = {
export { App, mount } from "./app/app";
export { Component } from "./component/component";
export { useComponent, useState } from "./component/component_node";
export { useComponent } from "./component/component_node";
export { status } from "./component/status";
export { reactive, markRaw, toRaw } from "./reactivity";
export { useEffect, useEnv, useExternalListener, useRef, useChildSubEnv, useSubEnv } from "./hooks";
export { EventBus, whenReady, loadFile, markup, xml } from "./utils";
export { Memo } from "./memo";
export { xml } from "./app/template_set";
export { reactive } from "./reactivity";
export { useState } from "./component/component_node";
export { useEffect, useEnv, useExternalListener, useRef, useSubEnv } from "./hooks";
export { EventBus, whenReady, loadFile, markup } from "./utils";
export {
onWillStart,
onMounted,
+47
View File
@@ -0,0 +1,47 @@
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 "./utils";
import { xml } from "./app/template_set";
import { BDom, text, VNode } from "./blockdom";
import { Component } from "./component/component";
+56 -323
View File
@@ -2,41 +2,15 @@ import { Callback } from "./utils";
// Allows to get the target of a Reactive (used for making a new Reactive from the underlying object)
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;
};
export type NonReactive<T extends Target = Target> = T & {
[SKIP]: any;
};
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.
*
@@ -44,44 +18,17 @@ function rawType(obj: any) {
* @returns whether the value can be made reactive
*/
function canBeMadeReactive(value: any): boolean {
if (typeof value !== "object") {
return false;
}
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;
return (
typeof value === "object" &&
value !== null &&
!(value instanceof Date) &&
!(value instanceof Promise) &&
!(value instanceof String) &&
!(value instanceof Number)
);
}
/**
* Mark an object or array so that it is ignored by the reactivity system
*
* @param value the value to mark
* @returns the object itself
*/
export function markRaw<T extends Target>(value: T): NonReactive<T> {
(value as any)[SKIP] = true;
return value as NonReactive<T>;
}
/**
* Given a reactive objet, return the raw (non reactive) underlying object
*
* @param value a reactive value
* @returns the underlying value
*/
export function toRaw<T extends object>(value: Reactive<T>): T {
return value[TARGET] || value;
}
const targetToKeysToCallbacks = new WeakMap<Target, Map<PropertyKey, Set<Callback>>>();
const targetToKeysToCallbacks = new WeakMap<Target, Map<ObjectKey, 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.
@@ -91,7 +38,7 @@ const targetToKeysToCallbacks = new WeakMap<Target, Map<PropertyKey, Set<Callbac
* or deletion)
* @param callback the function to call when the key changes
*/
function observeTargetKey(target: Target, key: PropertyKey, callback: Callback): void {
function observeTargetKey(target: Target, key: ObjectKey, callback: Callback): void {
if (!targetToKeysToCallbacks.get(target)) {
targetToKeysToCallbacks.set(target, new Map());
}
@@ -114,7 +61,7 @@ function observeTargetKey(target: Target, key: PropertyKey, callback: Callback):
* @param key the key that changed (or Symbol `KEYCHANGES` if a key was created
* or deleted)
*/
function notifyReactives(target: Target, key: PropertyKey): void {
function notifyReactives(target: Target, key: ObjectKey): void {
const keyToCallbacks = targetToKeysToCallbacks.get(target);
if (!keyToCallbacks) {
return;
@@ -153,17 +100,6 @@ export 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
@@ -192,16 +128,10 @@ const reactiveCache = new WeakMap<Target, WeakMap<Callback, Reactive>>();
* reactive has changed
* @returns a proxy that tracks changes to it
*/
export function reactive<T extends Target>(
target: T,
callback: Callback = () => {}
): Reactive<T> | NonReactive<T> {
export function reactive<T extends Target>(target: T, callback: Callback = () => {}): Reactive<T> {
if (!canBeMadeReactive(target)) {
throw new Error(`Cannot make the given value reactive`);
}
if (SKIP in target) {
return target as NonReactive<T>;
}
const originalTarget = (target as Reactive)[TARGET];
if (originalTarget) {
return reactive(originalTarget, callback);
@@ -211,247 +141,50 @@ export function reactive<T extends Target>(
}
const reactivesForTarget = reactiveCache.get(target)!;
if (!reactivesForTarget.has(callback)) {
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>;
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);
},
});
reactivesForTarget.set(callback, proxy);
}
return reactivesForTarget.get(callback) as Reactive<T>;
}
/**
* Creates a basic proxy handler for regular objects and arrays.
*
* @param callback @see reactive
* @returns a proxy handler object
*/
function basicProxyHandler<T extends Target>(callback: Callback): ProxyHandler<T> {
return {
get(target: any, key: PropertyKey, proxy: Reactive<T>) {
if (key === TARGET) {
return target;
}
// non-writable non-configurable properties cannot be made reactive
const desc = Object.getOwnPropertyDescriptor(target, key);
if (desc && !desc.writable && !desc.configurable) {
return Reflect.get(target, key, proxy);
}
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 forEach function that will delegate to forEach on the underlying
* collection while observing key changes, and keys as they're iterated over,
* and making the passed keys/values reactive.
*
* @param target @see reactive
* @param callback @see reactive
*/
function makeForEachObserver(target: any, callback: Callback) {
return function forEach(forEachCb: (val: any, key: any, target: any) => void, thisArg: any) {
observeTargetKey(target, KEYCHANGES, callback);
target.forEach(function (val: any, key: any, targetObj: any) {
observeTargetKey(target, key, callback);
forEachCb.call(
thisArg,
possiblyReactive(val, callback),
possiblyReactive(key, callback),
possiblyReactive(targetObj, callback)
);
}, thisArg);
};
}
/**
* 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),
forEach: makeForEachObserver(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),
forEach: makeForEachObserver(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>;
}
+4 -29
View File
@@ -15,26 +15,15 @@ export function batched(callback: Callback): Callback {
await Promise.resolve();
if (!called) {
called = true;
// wait for all calls in this microtick to fall through before resetting "called"
// so that only the first call to the batched function calls the original callback.
// Schedule this before calling the callback so that calls to the batched function
// within the callback will proceed only after resetting called to false, and have
// a chance to execute the callback again
Promise.resolve().then(() => (called = false));
callback();
// wait for all calls in this microtick to fall through before resetting "called"
// so that only the first call to the batched function calls the original callback
await Promise.resolve();
called = false;
}
};
}
export function validateTarget(target: HTMLElement) {
if (!(target instanceof HTMLElement)) {
throw new Error("Cannot mount component: the target is not a valid DOM element");
}
if (!document.body.contains(target)) {
throw new Error("Cannot mount a component on a detached dom node");
}
}
export class EventBus extends EventTarget {
trigger(name: string, payload?: any) {
this.dispatchEvent(new CustomEvent(name, { detail: payload }));
@@ -73,17 +62,3 @@ 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 = \\"\\") {
const b2 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
let 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 = \\"\\") {
const b2 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
const b3 = component(\`Child\`, {}, key + \`__2\`, node, ctx);
let b2 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
let 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 = \\"\\") {
const b2 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
const b3 = component(\`Child\`, {}, key + \`__2\`, node, ctx);
let b2 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
let 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 = \\"\\") {
const b2 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
const b3 = component(\`Parent\`, {}, key + \`__2\`, node, ctx);
let b2 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
let 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 = \\"\\") {
const b2 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
let 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];
const key1 = ctx['id'];
let key1 = ctx['id'];
c_block2[i1] = withKey(component(\`Quantity\`, {id: ctx['id']}, key + \`__1__\${key1}\`, node, ctx), key1);
}
ctx = ctx.__proto__;
const b2 = list(c_block2);
let b2 = list(c_block2);
let txt1 = ctx['total'];
let txt2 = Object.keys(ctx['state']).length;
return block1([txt1, txt2], [b2]);
-21
View File
@@ -169,27 +169,6 @@ describe("properties", () => {
expect(input.value).toBe("potato");
});
test("input with value attribute, and falsy value 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("");
patch(tree, block([null]));
expect(input.value).toBe("");
patch(tree, block([0]));
expect(input.value).toBe("0");
patch(tree, block([""]));
expect(input.value).toBe("");
patch(tree, block([false]));
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"/>`);
-13
View File
@@ -1,5 +1,4 @@
import { createBlock, mount, patch, remove } from "../../src/blockdom";
import { logStep } from "../helpers";
import { makeTestFixture } from "./helpers";
//------------------------------------------------------------------------------
@@ -56,15 +55,3 @@ test("is in dom when callback is called", async () => {
mount(tree, fixture);
});
test("callback ref in callback ref with same block", async () => {
const block = createBlock('<p block-ref="0"><block-text-1/><block-child-0/></p>');
let refFn = (el: HTMLParagraphElement) => logStep(el.outerHTML);
const child = block([refFn, "child"], []);
const parent = block([refFn, "parent"], [child]);
mount(parent, fixture);
expect(fixture.innerHTML).toBe("<p>parent<p>child</p></p>");
expect(["<p>child</p>", "<p>parent<p>child</p></p>"]).toBeLogged();
});
-54
View File
@@ -1,54 +0,0 @@
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;
const key1 = ctx['action_index'];
let key1 = ctx['action_index'];
const v1 = ctx['activate'];
const v2 = ctx['action'];
let hdlr1 = [()=>v1(v2), ctx];
c_block2[i1] = withKey(block3([hdlr1]), key1);
}
const b2 = list(c_block2);
let 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];
const key1 = ctx['value'];
let 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];
const key1 = ctx['value'];
let 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];
const b2 = safeOutput(ctx['html']);
let 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];
const key1 = ctx['project'];
let key1 = ctx['project'];
const v1 = ctx['onEdit'];
const v2 = ctx['project'];
let hdlr1 = [\\"prevent\\", _ev=>v1(v2.id,_ev), ctx];
let hdlr1 = [\\"prevent\\", ev=>v1(v2.id,ev), ctx];
let txt1 = ctx['project'].name;
c_block2[i1] = withKey(block3([hdlr1, txt1]), key1);
}
const b2 = list(c_block2);
let 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 = \\"\\") {
const b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
let 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 = \\"\\") {
const b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
let b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
return block1([], [b2]);
}
}"
+35 -35
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];
const key1 = ctx['slot'].id;
c_block4[i1] = withKey(component(\`SlotButton\`, {class: ctx['slot_container'], slot: ctx['slot']}, key + \`__1__\${key1}\`, node, ctx), key1);
let 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];
const key1 = ctx['x'];
let 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];
const key1 = ctx['commit_link'].id;
let 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];
const key1 = ctx['value'];
let key1 = ctx['value'];
let txt1 = ctx['value'];
const b4 = block4([txt1]);
let b4 = block4([txt1]);
ctx = Object.create(ctx);
ctx[isBoundary] = 1;
ctx = Object.create(ctx);
ctx[isBoundary] = 1;
setContextValue(ctx, \\"foo\\", 'aaa');
const b6 = callTemplate_1.call(this, ctx, node, key + \`__1__\${key1}\`);
let b6 = callTemplate_1.call(this, ctx, node, key + \`__1__\${key1}\`);
ctx = ctx.__proto__;
const b7 = callTemplate_2.call(this, ctx, node, key + \`__2__\${key1}\`);
let b7 = callTemplate_2.call(this, ctx, node, key + \`__2__\${key1}\`);
setContextValue(ctx, \\"foo\\", 'bbb');
const b8 = callTemplate_3.call(this, ctx, node, key + \`__3__\${key1}\`);
const b5 = multi([b6, b7, b8]);
let b8 = callTemplate_3.call(this, ctx, node, key + \`__3__\${key1}\`);
let b5 = multi([b6, b7, b8]);
ctx[zero] = b5;
const b9 = callTemplate_4.call(this, ctx, node, key + \`__4__\${key1}\`);
let b9 = callTemplate_4.call(this, ctx, node, key + \`__4__\${key1}\`);
ctx = ctx.__proto__;
c_block2[i1] = withKey(multi([b4, b9]), key1);
}
ctx = ctx.__proto__;
const b2 = list(c_block2);
const b10 = callTemplate_5.call(this, ctx, node, key + \`__5\`);
let b2 = list(c_block2);
let 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';
const b2 = ctx[zero];
let 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 = \\"\\") {
const b3 = text(\`toto default\`);
const b2 = withDefault(safeOutput(ctx['toto']), b3);
let b3 = text(\`toto default\`);
let 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];
const key1 = ctx['project'].id;
let 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'];
const b8 = block8([attr3, txt3]);
const b9 = block9();
let b8 = block8([attr3, txt3]);
let b9 = block9();
b7 = multi([b8, b9]);
} else if (ctx['nb_build_errors']&&ctx['nb_build_errors']>0) {
const b11 = block11();
const b12 = block12();
let b11 = block11();
let 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];
const key1 = ctx['category'].id;
let 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__;
const b15 = list(c_block15);
let 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];
const key1 = ctx['trigger'].id;
let 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__;
const b18 = list(c_block18);
let b18 = list(c_block18);
let hdlr8 = [ctx['triggerAll'], ctx];
let hdlr9 = [ctx['triggerNone'], ctx];
let hdlr10 = [ctx['triggerDefault'], ctx];
let hdlr11 = [ctx['toggleSettingsMenu'], ctx];
const b21 = block21([hdlr8, hdlr9, hdlr10, hdlr11]);
let 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 {
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);
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);
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;
const key1 = ctx['item_index'];
let key1 = ctx['item_index'];
c_block2[i1] = withKey(text(ctx['item']), key1);
}
const b2 = list(c_block2);
let 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 = \\"\\") {
const b2 = block2();
const b3 = block3();
let b2 = block2();
let 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 = \\"\\") {
const b2 = text(\`hello \`);
const b3 = text(ctx['text']);
let b2 = text(\`hello \`);
let 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 = \\"\\") {
const b2 = text(\`hello \`);
const b3 = text(ctx['text']);
let b2 = text(\`hello \`);
let 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 = \\"\\") {
const b2 = text(ctx['text1']);
const b3 = text(ctx['text2']);
let b2 = text(ctx['text1']);
let 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 = \\"\\") {
const b2 = text(ctx['text1']);
const b3 = text(ctx['text2']);
let b2 = text(ctx['text1']);
let b3 = text(ctx['text2']);
return multi([b2, b3]);
}
}"
@@ -52,70 +52,6 @@ exports[`properly support svg namespace to svg tags added even if already in svg
}"
`;
exports[`properly support svg svg creates new block if it is within html -- 2 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let block1 = createBlock(\`<div><block-child-0/></div>\`);
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)\\"/><block-child-0/></svg>\`);
let block3 = createBlock(\`<path block-ns=\\"http://www.w3.org/2000/svg\\"/>\`);
return function template(ctx, node, key = \\"\\") {
let b3;
if (ctx['hasPath']) {
b3 = block3();
}
const b2 = block2([], [b3]);
return block1([], [b2]);
}
}"
`;
exports[`properly support svg svg creates new block if it is within html 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let block1 = createBlock(\`<div><block-child-0/></div>\`);
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 = \\"\\") {
const b2 = block2();
return block1([], [b2]);
}
}"
`;
exports[`properly support svg svg namespace added to sub templates if root tag is path 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { getTemplate } = helpers;
const callTemplate_1 = getTemplate(\`path\`);
let block1 = createBlock(\`<svg block-ns=\\"http://www.w3.org/2000/svg\\"><block-child-0/></svg>\`);
return function template(ctx, node, key = \\"\\") {
const b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
return block1([], [b2]);
}
}"
`;
exports[`properly support svg svg namespace added to sub templates if root tag is path 2`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let block1 = createBlock(\`<path block-ns=\\"http://www.w3.org/2000/svg\\"/>\`);
return function template(ctx, node, key = \\"\\") {
return block1();
}
}"
`;
exports[`properly support svg svg namespace added to sub-blocks 1`] = `
"function anonymous(bdom, helpers
) {
@@ -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 = \\"\\") {
const b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
let 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;
const b3 = block3();
const b4 = text(\` \`);
const b5 = block5();
const b2 = multi([b3, b4, b5]);
let b3 = block3();
let b4 = text(\` \`);
let b5 = block5();
let b2 = multi([b3, b4, b5]);
ctx[zero] = b2;
const b6 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
let 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 = \\"\\") {
const b2 = ctx[zero];
let 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;
const b3 = block3();
const b4 = text(\` \`);
const b5 = block5();
const b2 = multi([b3, b4, b5]);
let b3 = block3();
let b4 = text(\` \`);
let b5 = block5();
let b2 = multi([b3, b4, b5]);
ctx[zero] = b2;
const b6 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
let 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;
const b3 = block3();
const b4 = ctx[zero];
const b2 = multi([b3, b4]);
let b3 = block3();
let b4 = ctx[zero];
let b2 = multi([b3, b4]);
ctx[zero] = b2;
const b5 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
let 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;
const b3 = block3();
const b4 = ctx[zero];
const b2 = multi([b3, b4]);
let b3 = block3();
let b4 = ctx[zero];
let b2 = multi([b3, b4]);
ctx[zero] = b2;
const b5 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
let 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 = \\"\\") {
const b2 = ctx[zero];
let 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;
const b2 = block2();
const b3 = text(\` \`);
const b4 = block4();
const b1 = multi([b2, b3, b4]);
let b2 = block2();
let b3 = text(\` \`);
let b4 = block4();
let 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;
const b2 = block2();
const b3 = ctx[zero];
const b1 = multi([b2, b3]);
let b2 = block2();
let b3 = ctx[zero];
let 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;
const b2 = block2();
const b3 = ctx[zero];
const b1 = multi([b2, b3]);
let b2 = block2();
let b3 = ctx[zero];
let 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 = \\"\\") {
const b2 = block2();
const b3 = ctx[zero];
let b2 = block2();
let 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']);
const b2 = call(this, template1, ctx, node, key + \`__1\`);
let 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);
const b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
let 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']);
const b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
let 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];
const key1 = ctx['subtree_index'];
let 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__;
}
const b2 = list(c_block2);
let 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']);
const b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
let 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];
const key1 = ctx['subtree_index'];
let 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__;
}
const b2 = list(c_block2);
let 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']);
const b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
let 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];
const key1 = ctx['subtree_index'];
let 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__;
}
const b2 = list(c_block2);
let 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);
const b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
let 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);
const b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
let 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 = \\"\\") {
const b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
let 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;
const b1 = block1();
let 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 = \\"\\") {
const b2 = ctx[zero];
let 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\`);
const b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
let 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];
const key1 = ctx['v_index'];
let 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__;
}
const b2 = list(c_block2);
let 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');
const b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
let 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];
const key1 = ctx['v_index'];
let 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__;
}
const b2 = list(c_block2);
let 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'];
const b2 = block2([txt1]);
const b3 = text(ctx['w']);
let b2 = block2([txt1]);
let 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\`);
const b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
let 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;
const b1 = text(\`WHEEE\`);
let 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;
const b1 = text(\`ok\`);
let 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');
const b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
let 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 = \\"\\") {
const b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
let 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 = \\"\\") {
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']);
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']);
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;
const b2 = block2();
let b2 = block2();
ctx[zero] = b2;
const b3 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
let 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];
const key1 = ctx['item'];
let key1 = ctx['item'];
c_block2[i1] = withKey(text(ctx['item']), key1);
}
const b2 = list(c_block2);
let 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];
const key1 = ctx['item'];
let key1 = ctx['item'];
let txt1 = ctx['item'];
c_block2[i1] = withKey(block3([txt1]), key1);
}
const b2 = list(c_block2);
let 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];
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(\`] \`);
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(\`] \`);
c_block2[i1] = withKey(multi([b4, b5, b6, b7, b8, b9, b10]), key1);
}
const b2 = list(c_block2);
let 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];
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(\`] \`);
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(\`] \`);
c_block2[i1] = withKey(multi([b4, b5, b6, b7, b8, b9, b10]), key1);
}
const b2 = list(c_block2);
let 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;
const key1 = ctx['elem'];
let 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);
}
const b2 = list(c_block2);
let 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];
const key1 = ctx['item'];
let key1 = ctx['item'];
c_block2[i1] = withKey(text(ctx['item']), key1);
}
const b2 = list(c_block2);
let 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];
const key1 = ctx['item'];
let 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];
const key1 = ctx['item'];
let key1 = ctx['item'];
let txt1 = ctx['item'];
const b3 = block3([txt1]);
let b3 = block3([txt1]);
let txt2 = ctx['item'];
const b4 = block4([txt2]);
let 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];
const key1 = ctx['a'];
let 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];
const key2 = ctx['b'];
let 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__;
const b4 = list(c_block4);
let b4 = list(c_block4);
let txt1 = ctx['c'];
const b6 = block6([txt1]);
let b6 = block6([txt1]);
c_block2[i1] = withKey(multi([b4, b6]), key1);
}
ctx = ctx.__proto__;
const b2 = list(c_block2);
let 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 = \\"\\") {
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(\`] \`);
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(\`] \`);
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];
const key1 = ctx['a'];
let 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];
const key2 = ctx['b'];
let key2 = ctx['b'];
c_block4[i2] = withKey(callTemplate_1.call(this, ctx, node, key + \`__1__\${key1}__\${key2}\`), key2);
}
ctx = ctx.__proto__;
const b4 = list(c_block4);
let b4 = list(c_block4);
let txt1 = ctx['c'];
const b6 = block6([txt1]);
let b6 = block6([txt1]);
c_block2[i1] = withKey(multi([b4, b6]), key1);
}
ctx = ctx.__proto__;
const b2 = list(c_block2);
let 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']);
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(\`] \`);
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(\`] \`);
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];
const key1 = ctx['number'];
let 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];
const key2 = ctx['letter'];
const b5 = text(\` [\`);
const b6 = text(ctx['number']);
const b7 = text(ctx['letter']);
const b8 = text(\`] \`);
let key2 = ctx['letter'];
let b5 = text(\` [\`);
let b6 = text(ctx['number']);
let b7 = text(ctx['letter']);
let b8 = text(\`] \`);
c_block3[i2] = withKey(multi([b5, b6, b7, b8]), key2);
}
ctx = ctx.__proto__;
c_block2[i1] = withKey(list(c_block3), key1);
}
const b2 = list(c_block2);
let 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];
const key1 = ctx['elem'].id;
let 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];
const key1 = ctx['elem'].id;
let 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);
}
const b2 = list(c_block2);
let 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];
const key1 = ctx['thing'];
let key1 = ctx['thing'];
c_block2[i1] = withKey(block3(), key1);
}
const b2 = list(c_block2);
let 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;
const key1 = ctx['item'];
let key1 = ctx['item'];
const tKey_1 = ctx['item_index'];
c_block2[i1] = withKey(block3(), tKey_1 + key1);
}
const b2 = list(c_block2);
let 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];
const key1 = ctx['item'].id;
const memo1 = [ctx['item'].x];
const vnode1 = cache[key1];;
let key1 = ctx['item'].id;
let memo1 = [ctx['item'].x]
let 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});
}
const b2 = list(c_block2);
let 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']) {
const b3 = block3();
const b4 = block4();
let b3 = block3();
let 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']) {
const b3 = block3();
const b4 = block4();
let b3 = block3();
let 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']) {
const b3 = block3();
const b4 = block4();
let b3 = block3();
let 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 {
const b4 = block4();
const b5 = block5();
let b4 = block4();
let 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']) {
const b4 = block4();
const b5 = block5();
let b4 = block4();
let 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];
const key1 = ctx['beer'].id;
let key1 = ctx['beer'].id;
let txt1 = ctx['beer'].name;
c_block2[i1] = withKey(block3([txt1]), key1);
}
const b2 = list(c_block2);
let b2 = list(c_block2);
return block1([], [b2]);
}
}"
+30 -60
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 = \\"\\") {
const b2 = safeOutput('ok');
let 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;
const b2 = block2();
let b2 = block2();
ctx[zero] = b2;
const b3 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
let 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 = \\"\\") {
const b2 = ctx[zero];
const b3 = ctx[zero];
let b2 = ctx[zero];
let 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 = \\"\\") {
const b2 = safeOutput(ctx['var']);
let 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;
const b2 = block2();
let b2 = block2();
ctx[zero] = b2;
const b3 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
let 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 = \\"\\") {
const b2 = ctx[zero];
let 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 = \\"\\") {
const b2 = safeOutput(ctx['var']);
let 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);
const b3 = safeOutput(ctx['var']);
let 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 = \\"\\") {
const b2 = safeOutput(ctx['bdom']);
let 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 = \\"\\") {
const b2 = safeOutput(ctx['var']);
let 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 = \\"\\") {
const b2 = safeOutput(ctx['var']);
let 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 = \\"\\") {
const b3 = text(\`nope\`);
const b2 = withDefault(safeOutput(ctx['var']), b3);
let b3 = text(\`nope\`);
let 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 = \\"\\") {
const b3 = block3();
const b2 = withDefault(safeOutput(ctx['var']), b3);
let b3 = block3();
let 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 = \\"\\") {
const b2 = safeOutput(ctx['var']);
let 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 = \\"\\") {
const b2 = safeOutput(ctx['var']);
let 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 = \\"\\") {
const b2 = safeOutput(ctx['var']);
let 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']) {
const b4 = safeOutput(ctx['bdom']);
let b4 = safeOutput(ctx['bdom']);
b3 = block3([], [b4]);
} else {
const b6 = safeOutput(ctx['var']);
let 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 = \\"\\") {
const b2 = safeOutput(ctx['var']);
let 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 = \\"\\") {
const b2 = safeOutput(ctx['var']);
let 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 = \\"\\") {
const b2 = safeOutput(ctx['var']);
let 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 = \\"\\") {
const b2 = safeOutput(ctx['var']);
let b2 = safeOutput(ctx['var']);
return block1([], [b2]);
}
}"
@@ -401,37 +401,7 @@ exports[`t-out variable 1`] = `
let block1 = createBlock(\`<span><block-child-0/></span>\`);
return function template(ctx, node, key = \\"\\") {
const b2 = safeOutput(ctx['var']);
return block1([], [b2]);
}
}"
`;
exports[`t-out with a String class 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { safeOutput } = helpers;
let block1 = createBlock(\`<span><block-child-0/></span>\`);
return function template(ctx, node, key = \\"\\") {
const b2 = safeOutput(ctx['var']);
return block1([], [b2]);
}
}"
`;
exports[`t-out with an extended String class 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { safeOutput } = helpers;
let block1 = createBlock(\`<span><block-child-0/></span>\`);
return function template(ctx, node, key = \\"\\") {
const b2 = safeOutput(ctx['var']);
let b2 = safeOutput(ctx['var']);
return block1([], [b2]);
}
}"
@@ -446,7 +416,7 @@ exports[`t-raw is deprecated should warn 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const b2 = safeOutput(ctx['var']);
let b2 = safeOutput(ctx['var']);
return block1([], [b2]);
}
}"
@@ -461,7 +431,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 = \\"\\") {
const b2 = safeOutput(ctx['var']);
let 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 = \\"\\") {
const b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
let 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];
const key1 = ctx['item'];
let 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);
}
const b2 = list(c_block2);
let 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');
const b3 = safeOutput(ctx['v2']);
let 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'];
const b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
let 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');
const b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
let 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];
const key1 = ctx['val'];
let key1 = ctx['val'];
let txt1 = ctx['iter'];
c_block2[i1] = withKey(block3([txt1]), key1);
setContextValue(ctx, \\"iter\\", ctx['iter']+1);
}
ctx = ctx.__proto__;
const b2 = list(c_block2);
let 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];
const key1 = ctx['val'];
let key1 = ctx['val'];
let txt1 = ctx['iter'];
c_block2[i1] = withKey(block3([txt1]), key1);
setContextValue(ctx, \\"iter\\", ctx['iter']++);
}
ctx = ctx.__proto__;
const b2 = list(c_block2);
let 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];
const key1 = ctx['val'];
let key1 = ctx['val'];
let txt1 = ctx['iter'];
c_block2[i1] = withKey(block3([txt1]), key1);
setContextValue(ctx, \\"iter\\", ++ctx['iter']);
}
ctx = ctx.__proto__;
const b2 = list(c_block2);
let 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;
const key1 = ctx['elem_index'];
let key1 = ctx['elem_index'];
let txt1 = ctx['v'];
setContextValue(ctx, \\"v\\", ctx['elem']);
c_block2[i1] = withKey(block3([txt1]), key1);
}
const b2 = list(c_block2);
let 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 = \\"\\") {
const b3 = text(ctx['beep']);
const b4 = text(\` boop\`);
let b3 = text(ctx['beep']);
let 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);
const b3 = safeOutput(ctx['v2']);
let 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);
const b3 = safeOutput(ctx['v2']);
let 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 = \\"\\") {
const tag1 = ctx['tag'];
let 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 = \\"\\") {
const tag1 = ctx['tag'];
let 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 = \\"\\") {
const tag1 = 'div';
let 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 = \\"\\") {
const tag1 = ctx['tag'];
let 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 = \\"\\") {
const tag1 = ctx['tag'];
let 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 = \\"\\") {
const tag1 = ctx['tag'];
let 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 = \\"\\") {
const tag1 = ctx['outer'];
const tag2 = ctx['inner'];
const b2 = toggler(tag2, block2(tag2)());
let tag1 = ctx['outer'];
let tag2 = ctx['inner'];
let 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 = \\"\\") {
const tag1 = ctx['brother'];
const b2 = toggler(tag1, block2(tag1)());
const tag2 = ctx['brother'];
const b3 = toggler(tag2, block3(tag2)());
let tag1 = ctx['brother'];
let b2 = toggler(tag1, block2(tag1)());
let tag2 = ctx['brother'];
let b3 = toggler(tag2, block3(tag2)());
return multi([b2, b3]);
}
}"
@@ -1,19 +1,5 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`loading templates addTemplates does not modify its xml document in place 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['value'];
return block1([txt1]);
}
}"
`;
exports[`loading templates can initialize qweb with a string 1`] = `
"function anonymous(bdom, helpers
) {
@@ -50,7 +36,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 = \\"\\") {
const b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
let b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
return block1([], [b2]);
}
}"
@@ -65,8 +51,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 = \\"\\") {
const b2 = block2();
const b3 = block3();
let b2 = block2();
let b3 = block3();
return multi([b2, b3]);
}
}"
@@ -82,7 +68,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 = \\"\\") {
const b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
let b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
return block1([], [b2]);
}
}"
@@ -97,8 +83,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 = \\"\\") {
const b2 = block2();
const b3 = block3();
let b2 = block2();
let b3 = block3();
return multi([b2, b3]);
}
}"
@@ -1,11 +1,11 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`translation support can set and remove translatable attributes 1`] = `
exports[`translation support can set translatable attributes 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let block1 = createBlock(\`<div tomato=\\"word\\" potato=\\"mot\\" title=\\"mot\\" label=\\"word\\">text</div>\`);
let block1 = createBlock(\`<div tomato=\\"word\\" potato=\\"mot\\" title=\\"word\\">text</div>\`);
return function template(ctx, node, key = \\"\\") {
return block1();
-13
View File
@@ -1,13 +0,0 @@
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'");
});
});
+11 -15
View File
@@ -65,14 +65,14 @@ describe("tokenizer", () => {
});
test("strings", () => {
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("'")).toThrow("Invalid expression");
expect(() => tokenize("'\\")).toThrow("Invalid expression");
expect(() => tokenize("'\\'")).toThrow("Invalid expression");
expect(tokenize("'hello ged'")).toEqual([{ type: "VALUE", value: "'hello ged'" }]);
expect(tokenize("'hello \\'ged\\''")).toEqual([{ type: "VALUE", value: "'hello \\'ged\\''" }]);
expect(() => tokenize('"')).toThrow('Tokenizer error: could not tokenize `"`');
expect(() => tokenize('"\\"')).toThrow('Tokenizer error: could not tokenize `"\\"`');
expect(() => tokenize('"')).toThrow("Invalid expression");
expect(() => tokenize('"\\"')).toThrow("Invalid expression");
expect(tokenize('"hello ged"')).toEqual([{ type: "VALUE", value: '"hello ged"' }]);
expect(tokenize('"hello ged"}')).toEqual([
{ type: "VALUE", value: '"hello ged"' },
@@ -163,21 +163,17 @@ describe("expression evaluation", () => {
});
test("arrow functions", () => {
expect(compileExpr("list.map(e => e.val)")).toBe("ctx['list'].map(_e=>_e.val)");
expect(compileExpr("list.map(e => a + e)")).toBe("ctx['list'].map(_e=>ctx['a']+_e)");
expect(compileExpr("list.map((e) => e)")).toBe("ctx['list'].map((_e)=>_e)");
expect(compileExpr("list.map(e => e.val)")).toBe("ctx['list'].map(e=>e.val)");
expect(compileExpr("list.map(e => a + e)")).toBe("ctx['list'].map(e=>ctx['a']+e)");
expect(compileExpr("list.map((e) => e)")).toBe("ctx['list'].map((e)=>e)");
expect(compileExpr("list.map((elem, index) => elem + index)")).toBe(
"ctx['list'].map((_elem,_index)=>_elem+_index)"
);
expect(compileExpr("(ev => ev)(e)")).toBe("(_ev=>_ev)(ctx['e'])");
expect(compileExpr("(v1) => myFunc(v1)")).toBe("(_v1)=>ctx['myFunc'](_v1)");
expect(compileExpr("list.data.map((data) => data)")).toBe(
"ctx['list'].data.map((_data)=>_data)"
"ctx['list'].map((elem,index)=>elem+index)"
);
expect(compileExpr("(ev => ev)(e)")).toBe("(ev=>ev)(ctx['e'])");
});
test.skip("arrow functions: not yet supported", () => {
// e is added to localvars in inline_expression but not removed after the arrow func body
expect(compileExpr("(e => e)(e)")).toBe("(_e=>_e)(ctx['e'])");
expect(compileExpr("(e => e)(e)")).toBe("(e=>e)(ctx['e'])");
});
test("assignation", () => {
File diff suppressed because it is too large Load Diff
-62
View File
@@ -1,7 +1,5 @@
import { renderToString, renderToBdom, snapshotEverything, makeTestFixture } from "../helpers";
import { mount } from "../../src/blockdom";
import { mount as mountComponent, Component, xml } from "../../src/index";
// NB: check the snapshots to see where the SVG namespaces are added
snapshotEverything();
@@ -54,64 +52,4 @@ describe("properly support svg", () => {
expect(el.namespaceURI).toBe("http://www.w3.org/2000/svg");
}
});
test("svg namespace added to sub templates if root tag is path", async () => {
const templates = `<t>
<t t-name="svg"><svg><t t-call="path" /></svg></t>
<t t-name="path"><path /></t>
</t>
`;
const fixture = makeTestFixture();
class Svg extends Component {
static template = "svg";
}
await mountComponent(Svg, fixture, { templates });
const elems = fixture.querySelectorAll("svg, path");
expect(elems.length).toEqual(2);
for (const el of elems) {
expect(el.namespaceURI).toBe("http://www.w3.org/2000/svg");
}
});
test("svg creates new block if it is within html", async () => {
class Test extends Component {
static template = xml`
<div>
<svg>
<polygon fill="#000000" points="0 0 4 4 8 0" transform="translate(5 7)"/>
</svg>
</div>
`;
}
const fixture = makeTestFixture();
await mountComponent(Test, fixture);
const elems = fixture.querySelectorAll("svg, polygon");
expect(elems.length).toEqual(2);
for (const el of elems) {
expect(el.namespaceURI).toBe("http://www.w3.org/2000/svg");
}
});
test("svg creates new block if it is within html -- 2", async () => {
class Test extends Component {
static template = xml`
<div>
<svg>
<polygon fill="#000000" points="0 0 4 4 8 0" transform="translate(5 7)"/>
<path t-if="hasPath" />
</svg>
</div>
`;
hasPath = true;
}
const fixture = makeTestFixture();
await mountComponent(Test, fixture);
const elems = fixture.querySelectorAll("svg, polygon, path");
expect(elems.length).toEqual(3);
for (const el of elems) {
expect(el.namespaceURI).toBe("http://www.w3.org/2000/svg");
}
});
});
-20
View File
@@ -37,26 +37,6 @@ describe("t-out", () => {
expect(renderToString(template, { var: "ok" })).toBe("<span>ok</span>");
});
test("with a String class", () => {
const template = `<span><t t-out="var"/></span>`;
expect(renderToString(template, { var: new String("ok") })).toBe("<span>ok</span>");
});
test("with an extended String class", () => {
class LoveString extends String {
valueOf(): string {
return `<3 ${super.valueOf()} <3`;
}
toString(): string {
return this.valueOf();
}
}
const template = `<span><t t-out="var"/></span>`;
expect(renderToString(template, { var: new LoveString("ok") })).toBe(
"<span>&lt;3 ok &lt;3</span>"
);
});
test("not escaping", () => {
const template = `<div><t t-out="var"/></div>`;
expect(renderToString(template, { var: markup("<ok></ok>") })).toBe("<div><ok></ok></div>");
-11
View File
@@ -24,17 +24,6 @@ describe("loading templates", () => {
expect(context.renderToString("hey")).toBe("<div>jupiler</div>");
});
test("addTemplates does not modify its xml document in place", () => {
const data = `<?xml version="1.0" encoding="UTF-8"?>
<templates id="template" xml:space="preserve"><div t-name="hey"><t t-esc="value"/></div></templates>`;
const xml = new DOMParser().parseFromString(data, "text/xml");
const context = new TestContext();
expect(xml.firstElementChild!.innerHTML).toBe(`<div t-name="hey"><t t-esc="value"/></div>`);
context.addTemplates(xml);
expect(context.renderToString("hey", { value: 123 })).toBe("<div>123</div>");
expect(xml.firstElementChild!.innerHTML).toBe(`<div t-name="hey"><t t-esc="value"/></div>`);
});
test("can load a few templates from a xml string", () => {
const data = `<?xml version="1.0" encoding="UTF-8"?>
<templates id="template" xml:space="preserve">
+4 -6
View File
@@ -59,20 +59,18 @@ describe("translation support", () => {
);
});
test("can set and remove translatable attributes", async () => {
test("can set translatable attributes", async () => {
class SomeComponent extends Component {
static template = xml`
<div tomato="word" potato="word" title="word" label="word">text</div>
<div tomato="word" potato="word" title="word">text</div>
`;
}
await mount(SomeComponent, fixture, {
translateFn: (expr: string) => (expr === "word" ? "mot" : expr),
translatableAttributes: ["potato", "-label"],
translatableAttributes: ["potato"],
});
expect(fixture.innerHTML).toBe(
'<div tomato="word" potato="mot" title="mot" label="word">text</div>'
);
expect(fixture.innerHTML).toBe('<div tomato="word" potato="mot" title="word">text</div>');
});
test("translation is done on the trimmed text, with extra spaces readded after", async () => {
@@ -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 = \\"\\") {
const Comp1 = ctx['myComp'];
let 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 = \\"\\") {
const b2 = block2();
const b3 = text(\`text\`);
const b4 = block4();
let b2 = block2();
let b3 = text(\`text\`);
let b4 = block4();
return multi([b2, b3, b4]);
}
}"
@@ -81,19 +81,6 @@ exports[`basics a class component inside a class component, no external dom 2`]
}"
`;
exports[`basics a component cannot be mounted in a detached node (even if node is detached later) 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let block1 = createBlock(\`<div/>\`);
return function template(ctx, node, key = \\"\\") {
return block1();
}
}"
`;
exports[`basics a component inside a component 1`] = `
"function anonymous(bdom, helpers
) {
@@ -102,7 +89,7 @@ exports[`basics a component inside a component 1`] = `
let block1 = createBlock(\`<span><block-child-0/></span>\`);
return function template(ctx, node, key = \\"\\") {
const b2 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
let b2 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -145,7 +132,7 @@ exports[`basics can handle empty props 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const b2 = component(\`Child\`, {val: undefined}, key + \`__1\`, node, ctx);
let b2 = component(\`Child\`, {val: undefined}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -236,8 +223,8 @@ exports[`basics can mount a simple component with multiple roots 1`] = `
let block3 = createBlock(\`<div/>\`);
return function template(ctx, node, key = \\"\\") {
const b2 = block2();
const b3 = block3();
let b2 = block2();
let b3 = block3();
return multi([b2, b3]);
}
}"
@@ -477,15 +464,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];
const key1 = ctx['blip'].id;
const b4 = component(\`SubWidget\`, {}, key + \`__1__\${key1}\`, node, ctx);
const b5 = component(\`SubWidget\`, {}, key + \`__2__\${key1}\`, node, ctx);
let key1 = ctx['blip'].id;
let b4 = component(\`SubWidget\`, {}, key + \`__1__\${key1}\`, node, ctx);
let b5 = component(\`SubWidget\`, {}, key + \`__2__\${key1}\`, node, ctx);
c_block2[i1] = withKey(block3([], [b4, b5]), key1);
}
const b2 = list(c_block2);
let b2 = list(c_block2);
return block1([], [b2]);
}
}"
@@ -560,9 +547,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 = \\"\\") {
const b2 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
let b2 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
const tKey_1 = 4;
const b3 = toggler(tKey_1, component(\`Child\`, {}, tKey_1 + key + \`__2\`, node, ctx));
let b3 = toggler(tKey_1, component(\`Child\`, {}, tKey_1 + key + \`__2\`, node, ctx));
return block1([], [b2, b3]);
}
}"
@@ -617,9 +604,9 @@ exports[`basics same t-keys in two different places 1`] = `
return function template(ctx, node, key = \\"\\") {
const tKey_1 = 1;
const b2 = toggler(tKey_1, component(\`Child\`, {blip: '1'}, tKey_1 + key + \`__1\`, node, ctx));
let b2 = toggler(tKey_1, component(\`Child\`, {blip: '1'}, tKey_1 + key + \`__1\`, node, ctx));
const tKey_2 = 1;
const b3 = toggler(tKey_2, component(\`Child\`, {blip: '2'}, tKey_2 + key + \`__2\`, node, ctx));
let b3 = toggler(tKey_2, component(\`Child\`, {blip: '2'}, tKey_2 + key + \`__2\`, node, ctx));
return block1([], [b2, b3]);
}
}"
@@ -952,8 +939,8 @@ exports[`basics two child components 1`] = `
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
const b2 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
const b3 = component(\`Child\`, {}, key + \`__2\`, node, ctx);
let b2 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
let b3 = component(\`Child\`, {}, key + \`__2\`, node, ctx);
return multi([b2, b3]);
}
}"
@@ -981,7 +968,7 @@ exports[`basics update props of component without concrete own node 1`] = `
return function template(ctx, node, key = \\"\\") {
const tKey_1 = ctx['childProps'].key;
const b2 = toggler(tKey_1, component(\`Child\`, Object.assign({}, ctx['childProps']), tKey_1 + key + \`__1\`, node, ctx));
let b2 = toggler(tKey_1, component(\`Child\`, Object.assign({}, ctx['childProps']), tKey_1 + key + \`__1\`, node, ctx));
return block1([], [b2]);
}
}"
@@ -994,7 +981,7 @@ exports[`basics update props of component without concrete own node 2`] = `
return function template(ctx, node, key = \\"\\") {
const tKey_1 = ctx['props'].subKey;
return toggler(tKey_1, component(\`Custom\`, {key: ctx['props'].key, subKey: ctx['props'].subKey}, tKey_1 + key + \`__1\`, node, ctx));
return toggler(tKey_1, component(\`Custom\`, {key: ctx['props'].key,subKey: ctx['props'].subKey}, tKey_1 + key + \`__1\`, node, ctx));
}
}"
`;
@@ -1022,10 +1009,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];
const key1 = ctx['item'];
let key1 = ctx['item'];
c_block1[i1] = withKey(text(ctx['item']), key1);
}
return list(c_block1);
@@ -1071,16 +1058,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;
const key1 = ctx['elem_index'];
let key1 = ctx['elem_index'];
c_block2[i1] = withKey(text(\`txt\`), key1);
}
ctx = ctx.__proto__;
const b2 = list(c_block2);
const b4 = component(\`SomeComponent\`, {}, key + \`__1\`, node, ctx);
let b2 = list(c_block2);
let b4 = component(\`SomeComponent\`, {}, key + \`__1\`, node, ctx);
return block1([], [b2, b4]);
}
}"
@@ -1187,7 +1174,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 = \\"\\") {
const b2 = component(\`GComp\`, {}, key + \`__1\`, node, ctx);
let b2 = component(\`GComp\`, {}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -1216,34 +1203,20 @@ 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];
const key1 = ctx['item'];
const b4 = text(ctx['item']);
const b5 = safeOutput(ctx['item']);
let key1 = ctx['item'];
let b4 = text(ctx['item']);
let b5 = safeOutput(ctx['item']);
c_block2[i1] = withKey(multi([b4, b5]), key1);
}
const b2 = list(c_block2);
let b2 = list(c_block2);
return block1([], [b2]);
}
}"
`;
exports[`t-out in components can switch the contents of two t-out repeatedly 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { safeOutput } = helpers;
return function template(ctx, node, key = \\"\\") {
const b2 = safeOutput(ctx['state'].a);
const b3 = safeOutput(ctx['state'].b);
return multi([b2, b3]);
}
}"
`;
exports[`t-out in components update properly on state changes 1`] = `
"function anonymous(bdom, helpers
) {
@@ -1253,7 +1226,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 = \\"\\") {
const b2 = safeOutput(ctx['state'].value);
let 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 = \\"\\") {
const b2 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
const b3 = text(\` _ \`);
let b2 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
let 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];
const key1 = ctx['elem'].id;
let key1 = ctx['elem'].id;
c_block4[i1] = withKey(text(ctx['elem'].id), key1);
}
const b4 = list(c_block4);
let 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];
const key1 = ctx['elem'].id;
let key1 = ctx['elem'].id;
c_block1[i1] = withKey(component(\`Element\`, {id: ctx['elem'].id}, key + \`__1__\${key1}\`, node, ctx), key1);
}
return list(c_block1);
@@ -52,50 +52,6 @@ exports[`Cascading renders after microtaskTick 3`] = `
}"
`;
exports[`another scenario with delayed rendering 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(\`A\`);
if (ctx['state'].value<15) {
b3 = component(\`B\`, {value: ctx['state'].value}, key + \`__1\`, node, ctx);
}
return multi([b2, b3]);
}
}"
`;
exports[`another scenario with delayed rendering 2`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
const b2 = text(ctx['props'].value);
const b3 = component(\`C\`, {}, key + \`__1\`, node, ctx);
return multi([b2, b3]);
}
}"
`;
exports[`another scenario with delayed rendering 3`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let block1 = createBlock(\`<button block-handler-0=\\"click\\"><block-text-1/></button>\`);
return function template(ctx, node, key = \\"\\") {
let hdlr1 = [ctx['increment'], ctx];
let txt1 = ctx['state'].val;
return block1([hdlr1, txt1]);
}
}"
`;
exports[`async rendering destroying a widget before start is over 1`] = `
"function anonymous(bdom, helpers
) {
@@ -213,7 +169,7 @@ exports[`concurrent renderings scenario 1 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const b2 = component(\`ComponentB\`, {fromA: ctx['state'].fromA}, key + \`__1\`, node, ctx);
let b2 = component(\`ComponentB\`, {fromA: ctx['state'].fromA}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -227,7 +183,7 @@ exports[`concurrent renderings scenario 1 2`] = `
let block1 = createBlock(\`<p><block-child-0/></p>\`);
return function template(ctx, node, key = \\"\\") {
const b2 = component(\`ComponentC\`, {fromA: ctx['props'].fromA, fromB: ctx['state'].fromB}, key + \`__1\`, node, ctx);
let b2 = component(\`ComponentC\`, {fromA: ctx['props'].fromA,fromB: ctx['state'].fromB}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -257,7 +213,7 @@ exports[`concurrent renderings scenario 2 1`] = `
return function template(ctx, node, key = \\"\\") {
let txt1 = ctx['state'].fromA;
const b2 = component(\`ComponentB\`, {fromA: ctx['state'].fromA}, key + \`__1\`, node, ctx);
let b2 = component(\`ComponentB\`, {fromA: ctx['state'].fromA}, key + \`__1\`, node, ctx);
return block1([txt1], [b2]);
}
}"
@@ -271,7 +227,7 @@ exports[`concurrent renderings scenario 2 2`] = `
let block1 = createBlock(\`<p><block-child-0/></p>\`);
return function template(ctx, node, key = \\"\\") {
const b2 = component(\`ComponentC\`, {fromA: ctx['props'].fromA, fromB: ctx['state'].fromB}, key + \`__1\`, node, ctx);
let b2 = component(\`ComponentC\`, {fromA: ctx['props'].fromA,fromB: ctx['state'].fromB}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -300,7 +256,7 @@ exports[`concurrent renderings scenario 2bis 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const b2 = component(\`ComponentB\`, {fromA: ctx['state'].fromA}, key + \`__1\`, node, ctx);
let b2 = component(\`ComponentB\`, {fromA: ctx['state'].fromA}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -314,7 +270,7 @@ exports[`concurrent renderings scenario 2bis 2`] = `
let block1 = createBlock(\`<p><block-child-0/></p>\`);
return function template(ctx, node, key = \\"\\") {
const b2 = component(\`ComponentC\`, {fromA: ctx['props'].fromA, fromB: ctx['state'].fromB}, key + \`__1\`, node, ctx);
let b2 = component(\`ComponentC\`, {fromA: ctx['props'].fromA,fromB: ctx['state'].fromB}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -343,7 +299,7 @@ exports[`concurrent renderings scenario 3 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const b2 = component(\`ComponentB\`, {fromA: ctx['state'].fromA}, key + \`__1\`, node, ctx);
let b2 = component(\`ComponentB\`, {fromA: ctx['state'].fromA}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -357,7 +313,7 @@ exports[`concurrent renderings scenario 3 2`] = `
let block1 = createBlock(\`<p><block-child-0/></p>\`);
return function template(ctx, node, key = \\"\\") {
const b2 = component(\`ComponentC\`, {fromA: ctx['props'].fromA}, key + \`__1\`, node, ctx);
let b2 = component(\`ComponentC\`, {fromA: ctx['props'].fromA}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -371,7 +327,7 @@ exports[`concurrent renderings scenario 3 3`] = `
let block1 = createBlock(\`<span><block-child-0/></span>\`);
return function template(ctx, node, key = \\"\\") {
const b2 = component(\`ComponentD\`, {fromA: ctx['props'].fromA, fromC: ctx['state'].fromC}, key + \`__1\`, node, ctx);
let b2 = component(\`ComponentD\`, {fromA: ctx['props'].fromA,fromC: ctx['state'].fromC}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -400,7 +356,7 @@ exports[`concurrent renderings scenario 4 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const b2 = component(\`ComponentB\`, {fromA: ctx['state'].fromA}, key + \`__1\`, node, ctx);
let b2 = component(\`ComponentB\`, {fromA: ctx['state'].fromA}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -414,7 +370,7 @@ exports[`concurrent renderings scenario 4 2`] = `
let block1 = createBlock(\`<p><block-child-0/></p>\`);
return function template(ctx, node, key = \\"\\") {
const b2 = component(\`ComponentC\`, {fromA: ctx['props'].fromA}, key + \`__1\`, node, ctx);
let b2 = component(\`ComponentC\`, {fromA: ctx['props'].fromA}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -428,7 +384,7 @@ exports[`concurrent renderings scenario 4 3`] = `
let block1 = createBlock(\`<span><block-child-0/></span>\`);
return function template(ctx, node, key = \\"\\") {
const b2 = component(\`ComponentD\`, {fromA: ctx['props'].fromA, fromC: ctx['state'].fromC}, key + \`__1\`, node, ctx);
let b2 = component(\`ComponentD\`, {fromA: ctx['props'].fromA,fromC: ctx['state'].fromC}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -457,7 +413,7 @@ exports[`concurrent renderings scenario 5 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const b2 = component(\`ComponentB\`, {fromA: ctx['state'].fromA}, key + \`__1\`, node, ctx);
let b2 = component(\`ComponentB\`, {fromA: ctx['state'].fromA}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -485,7 +441,7 @@ exports[`concurrent renderings scenario 6 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const b2 = component(\`ComponentB\`, {fromA: ctx['state'].fromA}, key + \`__1\`, node, ctx);
let b2 = component(\`ComponentB\`, {fromA: ctx['state'].fromA}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -513,7 +469,7 @@ exports[`concurrent renderings scenario 7 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const b2 = component(\`ComponentB\`, {fromA: ctx['state'].fromA}, key + \`__1\`, node, ctx);
let b2 = component(\`ComponentB\`, {fromA: ctx['state'].fromA}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -542,7 +498,7 @@ exports[`concurrent renderings scenario 8 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const b2 = component(\`ComponentB\`, {fromA: ctx['state'].fromA}, key + \`__1\`, node, ctx);
let b2 = component(\`ComponentB\`, {fromA: ctx['state'].fromA}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -572,8 +528,8 @@ exports[`concurrent renderings scenario 9 1`] = `
return function template(ctx, node, key = \\"\\") {
let txt1 = ctx['state'].fromA;
const b2 = component(\`ComponentB\`, {fromA: ctx['state'].fromA}, key + \`__1\`, node, ctx);
const b3 = component(\`ComponentC\`, {fromA: ctx['state'].fromA}, key + \`__2\`, node, ctx);
let b2 = component(\`ComponentB\`, {fromA: ctx['state'].fromA}, key + \`__1\`, node, ctx);
let b3 = component(\`ComponentC\`, {fromA: ctx['state'].fromA}, key + \`__2\`, node, ctx);
return block1([txt1], [b2, b3]);
}
}"
@@ -601,7 +557,7 @@ exports[`concurrent renderings scenario 9 3`] = `
let block1 = createBlock(\`<p><block-child-0/></p>\`);
return function template(ctx, node, key = \\"\\") {
const b2 = component(\`ComponentD\`, {fromA: ctx['props'].fromA, fromC: ctx['state'].fromC}, key + \`__1\`, node, ctx);
let b2 = component(\`ComponentD\`, {fromA: ctx['props'].fromA,fromC: ctx['state'].fromC}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -630,7 +586,7 @@ exports[`concurrent renderings scenario 10 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const b2 = component(\`ComponentB\`, {value: ctx['state'].value}, key + \`__1\`, node, ctx);
let b2 = component(\`ComponentB\`, {value: ctx['state'].value}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -675,7 +631,7 @@ exports[`concurrent renderings scenario 11 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const b2 = component(\`Child\`, {val: ctx['state'].valA}, key + \`__1\`, node, ctx);
let b2 = component(\`Child\`, {val: ctx['state'].valA}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -704,7 +660,7 @@ exports[`concurrent renderings scenario 12 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const b2 = component(\`Child\`, {val: ctx['val']}, key + \`__1\`, node, ctx);
let b2 = component(\`Child\`, {val: ctx['val']}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -764,7 +720,7 @@ exports[`concurrent renderings scenario 14 1`] = `
let block1 = createBlock(\`<p><block-child-0/></p>\`);
return function template(ctx, node, key = \\"\\") {
const b2 = component(\`B\`, {fromA: ctx['state'].fromA}, key + \`__1\`, node, ctx);
let b2 = component(\`B\`, {fromA: ctx['state'].fromA}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -778,7 +734,7 @@ exports[`concurrent renderings scenario 14 2`] = `
let block1 = createBlock(\`<p><block-child-0/></p>\`);
return function template(ctx, node, key = \\"\\") {
const b2 = component(\`C\`, {fromB: ctx['state'].fromB, fromA: ctx['props'].fromA}, key + \`__1\`, node, ctx);
let b2 = component(\`C\`, {fromB: ctx['state'].fromB,fromA: ctx['props'].fromA}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -808,7 +764,7 @@ exports[`concurrent renderings scenario 15 1`] = `
let block1 = createBlock(\`<p><block-child-0/></p>\`);
return function template(ctx, node, key = \\"\\") {
const b2 = component(\`B\`, {fromA: ctx['state'].fromA}, key + \`__1\`, node, ctx);
let b2 = component(\`B\`, {fromA: ctx['state'].fromA}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -822,7 +778,7 @@ exports[`concurrent renderings scenario 15 2`] = `
let block1 = createBlock(\`<p><block-child-0/></p>\`);
return function template(ctx, node, key = \\"\\") {
const b2 = component(\`C\`, {fromB: ctx['state'].fromB, fromA: ctx['props'].fromA}, key + \`__1\`, node, ctx);
let b2 = component(\`C\`, {fromB: ctx['state'].fromB,fromA: ctx['props'].fromA}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -861,7 +817,7 @@ exports[`concurrent renderings scenario 16 2`] = `
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
return component(\`C\`, {fromB: ctx['state'].fromB, fromA: ctx['props'].fromA}, key + \`__1\`, node, ctx);
return component(\`C\`, {fromB: ctx['state'].fromB,fromA: ctx['props'].fromA}, key + \`__1\`, node, ctx);
}
}"
`;
@@ -1052,9 +1008,9 @@ exports[`delay willUpdateProps 2`] = `
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
const b2 = text(ctx['props'].value);
const b3 = text(\`_\`);
const b4 = text(ctx['state'].int);
let b2 = text(ctx['props'].value);
let b3 = text(\`_\`);
let b4 = text(ctx['state'].int);
return multi([b2, b3, b4]);
}
}"
@@ -1077,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 = \\"\\") {
const b2 = component(\`DelayedChild\`, {value: ctx['props'].state.value}, key + \`__1\`, node, ctx);
const b3 = component(\`ReactiveChild\`, {}, key + \`__2\`, node, ctx);
let b2 = component(\`DelayedChild\`, {value: ctx['props'].state.value}, key + \`__1\`, node, ctx);
let b3 = component(\`ReactiveChild\`, {}, key + \`__2\`, node, ctx);
return multi([b2, b3]);
}
}"
@@ -1090,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 = \\"\\") {
const b2 = text(ctx['props'].value);
const b3 = text(\`_\`);
const b4 = text(ctx['state'].int);
let b2 = text(ctx['props'].value);
let b3 = text(\`_\`);
let b4 = text(ctx['state'].int);
return multi([b2, b3, b4]);
}
}"
@@ -1111,211 +1067,6 @@ exports[`delay willUpdateProps with rendering grandchild 4`] = `
}"
`;
exports[`delayed rendering, but then initial rendering is cancelled by yet another 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\`, {value: ctx['state'].value}, key + \`__1\`, node, ctx);
}
}"
`;
exports[`delayed rendering, but then initial rendering is cancelled by yet another render 2`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
return component(\`C\`, {value: ctx['state'].someValue+ctx['props'].value}, key + \`__1\`, node, ctx);
}
}"
`;
exports[`delayed rendering, but then initial rendering is cancelled by yet another render 3`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let block3 = createBlock(\`<p><block-text-0/></p>\`);
return function template(ctx, node, key = \\"\\") {
const b2 = component(\`D\`, {}, key + \`__1\`, node, ctx);
let txt1 = ctx['props'].value;
const b3 = block3([txt1]);
return multi([b2, b3]);
}
}"
`;
exports[`delayed rendering, but then initial rendering is cancelled by yet another render 4`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let block1 = createBlock(\`<button block-handler-0=\\"click\\"><block-text-1/></button>\`);
return function template(ctx, node, key = \\"\\") {
let hdlr1 = [ctx['increment'], ctx];
let txt1 = ctx['state'].val;
return block1([hdlr1, txt1]);
}
}"
`;
exports[`delayed rendering, reusing fiber 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(\`B\`, {value: ctx['state'].value}, key + \`__1\`, node, ctx);
}
}"
`;
exports[`delayed rendering, reusing fiber and stuff 2`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
const b2 = text(ctx['props'].value);
const b3 = component(\`C\`, {}, key + \`__1\`, node, ctx);
return multi([b2, b3]);
}
}"
`;
exports[`delayed rendering, reusing fiber and stuff 3`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let block1 = createBlock(\`<button block-handler-0=\\"click\\"><block-text-1/></button>\`);
return function template(ctx, node, key = \\"\\") {
let hdlr1 = [ctx['increment'], ctx];
let txt1 = ctx['state'].val;
return block1([hdlr1, txt1]);
}
}"
`;
exports[`delayed rendering, reusing fiber then component is destroyed and stuff 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(\`A\`);
if (ctx['state'].value<15) {
b3 = component(\`B\`, {value: ctx['state'].value}, key + \`__1\`, node, ctx);
}
return multi([b2, b3]);
}
}"
`;
exports[`delayed rendering, reusing fiber then component is destroyed and stuff 2`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
const b2 = text(ctx['props'].value);
const b3 = component(\`C\`, {}, key + \`__1\`, node, ctx);
return multi([b2, b3]);
}
}"
`;
exports[`delayed rendering, reusing fiber then component is destroyed and stuff 3`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let block1 = createBlock(\`<button block-handler-0=\\"click\\"><block-text-1/></button>\`);
return function template(ctx, node, key = \\"\\") {
let hdlr1 = [ctx['increment'], ctx];
let txt1 = ctx['state'].val;
return block1([hdlr1, txt1]);
}
}"
`;
exports[`delayed rendering, then component is destroyed 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(\`B\`, {value: ctx['state'].value}, key + \`__1\`, node, ctx);
}
}"
`;
exports[`delayed rendering, then component is destroyed and stuff 2`] = `
"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(ctx['props'].value);
if (ctx['props'].value<10) {
b3 = component(\`C\`, {}, key + \`__1\`, node, ctx);
}
return multi([b2, b3]);
}
}"
`;
exports[`delayed rendering, then component is destroyed and stuff 3`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let block1 = createBlock(\`<button block-handler-0=\\"click\\"><block-text-1/></button>\`);
return function template(ctx, node, key = \\"\\") {
let hdlr1 = [ctx['increment'], ctx];
let txt1 = ctx['state'].val;
return block1([hdlr1, txt1]);
}
}"
`;
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
) {
@@ -1394,7 +1145,7 @@ exports[`properly behave when destroyed/unmounted while rendering 2`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const b2 = component(\`SubChild\`, {val: ctx['props'].val}, key + \`__1\`, node, ctx);
let b2 = component(\`SubChild\`, {val: ctx['props'].val}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -1444,28 +1195,6 @@ 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
) {
@@ -1474,14 +1203,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;
const key1 = ctx['arr_index'];
let key1 = ctx['arr_index'];
let b3;
if (ctx['arr']) {
const Comp1 = ctx['myComp'];
let Comp1 = ctx['myComp'];
b3 = toggler(Comp1, component(Comp1, {key: ctx['arr'][0]}, key + \`__1__\${key1}\`, node, ctx));
}
c_block1[i1] = withKey(multi([b3]), key1);
@@ -1514,8 +1243,8 @@ exports[`t-key on dom node having a component 1`] = `
return function template(ctx, node, key = \\"\\") {
const tKey_1 = ctx['key'];
const Comp1 = ctx['myComp'];
const b2 = toggler(tKey_1, toggler(Comp1, component(Comp1, {key: ctx['key']}, tKey_1 + key + \`__1\`, node, ctx)));
let Comp1 = ctx['myComp'];
let b2 = toggler(tKey_1, toggler(Comp1, component(Comp1, {key: ctx['key']}, tKey_1 + key + \`__1\`, node, ctx)));
return toggler(tKey_1, block1([], [b2]));
}
}"
@@ -1539,7 +1268,7 @@ exports[`t-key on dynamic async component (toggler is never patched) 1`] = `
return function template(ctx, node, key = \\"\\") {
const tKey_1 = ctx['key'];
const Comp1 = ctx['myComp'];
let Comp1 = ctx['myComp'];
return toggler(tKey_1, toggler(Comp1, component(Comp1, {key: ctx['key']}, tKey_1 + key + \`__1\`, node, ctx)));
}
}"
@@ -1622,7 +1351,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 = \\"\\") {
const b2 = component(\`ChildA\`, {val: ctx['state'].valA}, key + \`__1\`, node, ctx);
let b2 = component(\`ChildA\`, {val: ctx['state'].valA}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -1650,7 +1379,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 = \\"\\") {
const b2 = component(\`ChildA\`, {val: ctx['state'].valA}, key + \`__1\`, node, ctx);
let b2 = component(\`ChildA\`, {val: ctx['state'].valA}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -1,18 +1,5 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`basics display a nice error if it cannot find component (in dev mode) 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
const props1 = {};
helpers.validateProps(\`SomeMispelledComponent\`, props1, ctx);
return component(\`SomeMispelledComponent\`, props1, key + \`__1\`, node, ctx);
}
}"
`;
exports[`basics display a nice error if it cannot find component 1`] = `
"function anonymous(bdom, helpers
) {
@@ -32,7 +19,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 = \\"\\") {
const b2 = component(\`ErrorComponent\`, {flag: ctx['state'].flag}, key + \`__1\`, node, ctx);
let b2 = component(\`ErrorComponent\`, {flag: ctx['state'].flag}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -85,22 +72,10 @@ exports[`basics simple catchError 2`] = `
}"
`;
exports[`can catch errors calling a hook outside setup should crash 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
return text(ctx['state'].value);
}
}"
`;
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>\`);
@@ -109,7 +84,7 @@ exports[`can catch errors can catch an error in a component render function 1`]
}
return function template(ctx, node, key = \\"\\") {
const b3 = component(\`ErrorBoundary\`, {slots: markRaw({'default': {__render: slot1, __ctx: ctx}})}, key + \`__2\`, node, ctx);
let b3 = component(\`ErrorBoundary\`, {slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__2\`, node, ctx);
return block1([], [b3]);
}
}"
@@ -128,7 +103,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, null);
b3 = callSlot(ctx, node, key, 'default', false, {});
}
return block1([], [b2, b3]);
}
@@ -153,7 +128,6 @@ 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>\`);
@@ -162,7 +136,7 @@ exports[`can catch errors can catch an error in the constructor call of a compon
}
return function template(ctx, node, key = \\"\\") {
const b3 = component(\`ErrorBoundary\`, {slots: markRaw({'default': {__render: slot1, __ctx: ctx}})}, key + \`__2\`, node, ctx);
let b3 = component(\`ErrorBoundary\`, {slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__2\`, node, ctx);
return block1([], [b3]);
}
}"
@@ -181,7 +155,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, null);
b3 = callSlot(ctx, node, key, 'default', false, {});
}
return block1([], [b2, b3]);
}
@@ -192,18 +166,17 @@ 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 = \\"\\") {
const b3 = component(\`ClassicCompoent\`, {}, key + \`__1\`, node, ctx);
const b4 = component(\`ErrorComponent\`, {}, key + \`__2\`, node, ctx);
let b3 = component(\`ClassicCompoent\`, {}, key + \`__1\`, node, ctx);
let b4 = component(\`ErrorComponent\`, {}, key + \`__2\`, node, ctx);
return multi([b3, b4]);
}
return function template(ctx, node, key = \\"\\") {
const b5 = component(\`ErrorBoundary\`, {slots: markRaw({'default': {__render: slot1, __ctx: ctx}})}, key + \`__3\`, node, ctx);
let b5 = component(\`ErrorBoundary\`, {slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__3\`, node, ctx);
return block1([], [b5]);
}
}"
@@ -222,7 +195,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, null);
b3 = callSlot(ctx, node, key, 'default', false, {});
}
return block1([], [b2, b3]);
}
@@ -272,7 +245,6 @@ 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>\`);
@@ -281,7 +253,7 @@ exports[`can catch errors can catch an error in the initial call of a component
}
return function template(ctx, node, key = \\"\\") {
const b3 = component(\`ErrorBoundary\`, {slots: markRaw({'default': {__render: slot1, __ctx: ctx}})}, key + \`__2\`, node, ctx);
let b3 = component(\`ErrorBoundary\`, {slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__2\`, node, ctx);
return block1([], [b3]);
}
}"
@@ -300,7 +272,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, null);
b3 = callSlot(ctx, node, key, 'default', false, {});
}
return block1([], [b2, b3]);
}
@@ -325,7 +297,6 @@ 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>\`);
@@ -336,7 +307,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: markRaw({'default': {__render: slot1, __ctx: ctx}})}, key + \`__2\`, node, ctx);
b3 = component(\`ErrorBoundary\`, {slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__2\`, node, ctx);
}
return block1([], [b3]);
}
@@ -356,7 +327,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, null);
b3 = callSlot(ctx, node, key, 'default', false, {});
}
return block1([], [b2, b3]);
}
@@ -396,7 +367,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 = \\"\\") {
const b2 = component(\`C\`, {}, key + \`__1\`, node, ctx);
let b2 = component(\`C\`, {}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -470,7 +441,6 @@ 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>\`);
@@ -479,7 +449,7 @@ exports[`can catch errors can catch an error in the mounted call 1`] = `
}
return function template(ctx, node, key = \\"\\") {
const b3 = component(\`ErrorBoundary\`, {slots: markRaw({'default': {__render: slot1, __ctx: ctx}})}, key + \`__2\`, node, ctx);
let b3 = component(\`ErrorBoundary\`, {slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__2\`, node, ctx);
return block1([], [b3]);
}
}"
@@ -498,7 +468,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, null);
b3 = callSlot(ctx, node, key, 'default', false, {});
}
return block1([], [b2, b3]);
}
@@ -522,7 +492,6 @@ 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>\`);
@@ -532,7 +501,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;
const b3 = component(\`ErrorBoundary\`, {slots: markRaw({'default': {__render: slot1, __ctx: ctx}})}, key + \`__2\`, node, ctx);
let b3 = component(\`ErrorBoundary\`, {slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__2\`, node, ctx);
return block1([txt1], [b3]);
}
}"
@@ -551,7 +520,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, null);
b3 = callSlot(ctx, node, key, 'default', false, {});
}
return block1([], [b2, b3]);
}
@@ -576,7 +545,6 @@ 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>\`);
@@ -585,7 +553,7 @@ exports[`can catch errors can catch an error in the willStart call 1`] = `
}
return function template(ctx, node, key = \\"\\") {
const b3 = component(\`ErrorBoundary\`, {slots: markRaw({'default': {__render: slot1, __ctx: ctx}})}, key + \`__2\`, node, ctx);
let b3 = component(\`ErrorBoundary\`, {slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__2\`, node, ctx);
return block1([], [b3]);
}
}"
@@ -604,7 +572,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, null);
b3 = callSlot(ctx, node, key, 'default', false, {});
}
return block1([], [b2, b3]);
}
@@ -628,18 +596,17 @@ 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 = \\"\\") {
const b3 = component(\`ClassicCompoent\`, {}, key + \`__1\`, node, ctx);
const b4 = component(\`ErrorComponent\`, {}, key + \`__2\`, node, ctx);
let b3 = component(\`ClassicCompoent\`, {}, key + \`__1\`, node, ctx);
let b4 = component(\`ErrorComponent\`, {}, key + \`__2\`, node, ctx);
return multi([b3, b4]);
}
return function template(ctx, node, key = \\"\\") {
const b5 = component(\`ErrorBoundary\`, {slots: markRaw({'default': {__render: slot1, __ctx: ctx}})}, key + \`__3\`, node, ctx);
let b5 = component(\`ErrorBoundary\`, {slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__3\`, node, ctx);
return block1([], [b5]);
}
}"
@@ -658,7 +625,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, null);
b3 = callSlot(ctx, node, key, 'default', false, {});
}
return block1([], [b2, b3]);
}
@@ -718,7 +685,7 @@ exports[`can catch errors catchError in catchError 2`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const b2 = component(\`Boom\`, {}, key + \`__1\`, node, ctx);
let b2 = component(\`Boom\`, {}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -742,22 +709,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, markRaw, withKey } = helpers;
let { prepareList, capture, withKey } = helpers;
function slot1(ctx, node, key = \\"\\") {
const Comp1 = ctx['cp'].Comp;
let 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];
const key1 = ctx['cp'].id;
let key1 = ctx['cp'].id;
const v1 = ctx['cp'];
const ctx1 = capture(ctx);
c_block1[i1] = withKey(component(\`ErrorHandler\`, {onError: ()=>this.cleanUp(v1.id),slots: markRaw({'default': {__render: slot1, __ctx: ctx1}})}, key + \`__2__\${key1}\`, node, ctx), key1);
c_block1[i1] = withKey(component(\`ErrorHandler\`, {onError: ()=>this.cleanUp(v1.id),slots: {'default': {__render: slot1, __ctx: ctx1}}}, key + \`__2__\${key1}\`, node, ctx), key1);
}
return list(c_block1);
}
@@ -771,7 +738,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, null);
return callSlot(ctx, node, key, 'default', false, {});
}
}"
`;
@@ -817,22 +784,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, markRaw, withKey } = helpers;
let { prepareList, capture, withKey } = helpers;
function slot1(ctx, node, key = \\"\\") {
const Comp1 = ctx['elem'][1];
let 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];
const key1 = ctx['elem'][0];
let 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: markRaw({'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: {'default': {__render: slot1, __ctx: ctx1}}}, key + \`__2__\${key1}\`, node, ctx), key1);
}
return list(c_block1);
}
@@ -846,7 +813,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, null);
return callSlot(ctx, node, key, 'default', false, {});
}
}"
`;
@@ -882,7 +849,6 @@ 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>\`);
@@ -891,8 +857,8 @@ exports[`can catch errors error in mounted on a component with a sibling (proper
}
return function template(ctx, node, key = \\"\\") {
const b2 = component(\`OK\`, {}, key + \`__1\`, node, ctx);
const b4 = component(\`ErrorBoundary\`, {slots: markRaw({'default': {__render: slot1, __ctx: ctx}})}, key + \`__3\`, node, ctx);
let b2 = component(\`OK\`, {}, key + \`__1\`, node, ctx);
let b4 = component(\`ErrorBoundary\`, {slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__3\`, node, ctx);
return block1([], [b2, b4]);
}
}"
@@ -922,7 +888,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, null);
b3 = callSlot(ctx, node, key, 'default', false, {});
}
return block1([], [b2, b3]);
}
@@ -1010,7 +976,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 = \\"\\") {
const b2 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
let b2 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -1052,7 +1018,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 = \\"\\") {
const b2 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
let b2 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
let txt1 = ctx['x'].y;
return block1([txt1], [b2]);
}
@@ -1102,19 +1068,6 @@ 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
) {
@@ -1156,19 +1109,6 @@ 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];
const b2 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
let 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];
const key1 = ctx['item'];
let key1 = ctx['item'];
const v1 = ctx['onClick'];
const v2 = ctx['item'];
let hdlr1 = [_ev=>v1(v2.val,_ev), ctx];
let hdlr1 = [ev=>v1(v2.val,ev), ctx];
c_block2[i1] = withKey(block3([hdlr1]), key1);
}
const b2 = list(c_block2);
let 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];
const key1 = ctx['item'];
let key1 = ctx['item'];
const v1 = ctx['onClick'];
const v2 = ctx['item'];
let hdlr1 = [_ev=>v1(v2,_ev), ctx];
let hdlr1 = [ev=>v1(v2,ev), ctx];
c_block2[i1] = withKey(block3([hdlr1]), key1);
}
const b2 = list(c_block2);
let 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 = \\"\\") {
const b2 = component(\`ComponentB\`, {}, key + \`__1\`, node, ctx);
let b2 = component(\`ComponentB\`, {}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -103,78 +103,20 @@ exports[`hooks mounted callbacks should be called in reverse order from willUnmo
}"
`;
exports[`hooks parent and child env (with useChildSubEnv then useSubEnv) 1`] = `
exports[`hooks parent and child env 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['env'].val);
const b3 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
let b2 = text(ctx['env'].val);
let b3 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
return multi([b2, b3]);
}
}"
`;
exports[`hooks parent and child env (with useChildSubEnv then useSubEnv) 2`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let block2 = createBlock(\`<div><block-text-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
let b2;
if (ctx['env'].hasParent) {
let txt1 = ctx['env'].val;
b2 = block2([txt1]);
}
return multi([b2]);
}
}"
`;
exports[`hooks parent and child env (with useChildSubEnv) 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['env'].val);
const b3 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
return multi([b2, b3]);
}
}"
`;
exports[`hooks parent and child env (with useChildSubEnv) 2`] = `
"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['env'].val;
return block1([txt1]);
}
}"
`;
exports[`hooks parent and child env (with useSubEnv) 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['env'].val);
const b3 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
return multi([b2, b3]);
}
}"
`;
exports[`hooks parent and child env (with useSubEnv) 2`] = `
exports[`hooks parent and child env 2`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
@@ -202,7 +144,7 @@ exports[`hooks two different call to willPatch/patched should work 1`] = `
}"
`;
exports[`hooks useChildSubEnv does not pollute user env 1`] = `
exports[`hooks use sub env does not pollute user env 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
@@ -216,7 +158,7 @@ exports[`hooks useChildSubEnv does not pollute user env 1`] = `
}"
`;
exports[`hooks useChildSubEnv supports arbitrary descriptor 1`] = `
exports[`hooks use sub env supports arbitrary descriptor 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
@@ -227,7 +169,7 @@ exports[`hooks useChildSubEnv supports arbitrary descriptor 1`] = `
}"
`;
exports[`hooks useChildSubEnv supports arbitrary descriptor 2`] = `
exports[`hooks use sub env supports arbitrary descriptor 2`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
@@ -301,19 +243,6 @@ exports[`hooks useEffect hook effect with empty dependency list never reruns 1`]
}"
`;
exports[`hooks useEffect hook properly behaves when the effect function throws 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let block1 = createBlock(\`<div/>\`);
return function template(ctx, node, key = \\"\\") {
return block1();
}
}"
`;
exports[`hooks useExternalListener 1`] = `
"function anonymous(bdom, helpers
) {
@@ -358,43 +287,3 @@ exports[`hooks useRef hook: basic use 1`] = `
}
}"
`;
exports[`hooks useSubEnv modifies user env 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['env'].val;
return block1([txt1]);
}
}"
`;
exports[`hooks useSubEnv supports arbitrary descriptor 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
return component(\`Child\`, {}, key + \`__1\`, node, ctx);
}
}"
`;
exports[`hooks useSubEnv supports arbitrary descriptor 2`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let block1 = createBlock(\`<div><block-text-0/> <block-text-1/></div>\`);
return function template(ctx, node, key = \\"\\") {
let txt1 = ctx['env'].someVal;
let txt2 = ctx['env'].someVal2;
return block1([txt1, txt2]);
}
}"
`;
@@ -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 = \\"\\") {
const b2 = component(\`B\`, {}, key + \`__1\`, node, ctx);
const b3 = component(\`C\`, {}, key + \`__2\`, node, ctx);
let b2 = component(\`B\`, {}, key + \`__1\`, node, ctx);
let 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) {
const b3 = component(\`Child\`, {n: ctx['state'].n}, key + \`__1\`, node, ctx);
let b3 = component(\`Child\`, {n: ctx['state'].n}, key + \`__1\`, node, ctx);
b2 = block2([], [b3]);
}
return multi([b2]);
@@ -160,34 +160,6 @@ exports[`lifecycle hooks components are unmounted destroyed if no longer in DOM
}"
`;
exports[`lifecycle hooks destroy new children before being mountged 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
let b2,b3,b4;
b2 = text(\`before\`);
if (ctx['state'].flag) {
b3 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
}
b4 = text(\`after\`);
return multi([b2, b3, b4]);
}
}"
`;
exports[`lifecycle hooks destroy new children before being mountged 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[`lifecycle hooks hooks are called in proper order in widget creation/destruction 1`] = `
"function anonymous(bdom, helpers
) {
@@ -196,7 +168,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 = \\"\\") {
const b2 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
let b2 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -245,7 +217,7 @@ exports[`lifecycle hooks lifecycle semantics 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const b2 = component(\`Child\`, {a: ctx['state'].a}, key + \`__1\`, node, ctx);
let b2 = component(\`Child\`, {a: ctx['state'].a}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -458,7 +430,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 = \\"\\") {
const b2 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
let b2 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -502,7 +474,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 = \\"\\") {
const b2 = component(\`ChildChild\`, {}, key + \`__1\`, node, ctx);
let b2 = component(\`ChildChild\`, {}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -555,7 +527,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 = \\"\\") {
const b2 = component(\`Child\`, {a: ctx['state'].a}, key + \`__1\`, node, ctx);
let b2 = component(\`Child\`, {a: ctx['state'].a}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -658,43 +630,6 @@ exports[`lifecycle hooks sub widget (inside sub node): hooks are correctly calle
}"
`;
exports[`lifecycle hooks timeout in onWillStart emits a warning 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let block1 = createBlock(\`<span/>\`);
return function template(ctx, node, key = \\"\\") {
return block1();
}
}"
`;
exports[`lifecycle hooks timeout in onWillUpdateProps emits a warning 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
const props1 = {prop: ctx['state'].prop};
helpers.validateProps(\`Child\`, props1, ctx);
return component(\`Child\`, props1, key + \`__1\`, node, ctx);
}
}"
`;
exports[`lifecycle hooks timeout in onWillUpdateProps emits a warning 2`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
return text(\`\`);
}
}"
`;
exports[`lifecycle hooks willPatch, patched hook are called on subsubcomponents, in proper order 1`] = `
"function anonymous(bdom, helpers
) {
@@ -703,7 +638,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 = \\"\\") {
const b2 = component(\`Child\`, {n: ctx['state'].n}, key + \`__1\`, node, ctx);
let b2 = component(\`Child\`, {n: ctx['state'].n}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -717,7 +652,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 = \\"\\") {
const b2 = component(\`ChildChild\`, {n: ctx['props'].n}, key + \`__1\`, node, ctx);
let 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 = \\"\\") {
const b2 = component(\`Child\`, {greetings: ctx['greetings']}, key + \`__1\`, node, ctx);
let b2 = component(\`Child\`, {greetings: ctx['greetings']}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -36,13 +36,13 @@ 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];
const key1 = ctx['item'].val;
let 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);
c_block1[i1] = withKey(component(\`Child\`, {onClick: ev=>v1(v2.val,ev)}, key + \`__1__\${key1}\`, node, ctx), key1);
}
return list(c_block1);
}
@@ -71,7 +71,7 @@ exports[`basics explicit object prop 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const b2 = component(\`Child\`, {value: ctx['state'].val}, key + \`__1\`, node, ctx);
let 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);
const b3 = component(\`Child\`, {val: ctx['abc']}, key + \`__1\`, node, ctx);
let 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;
const b2 = safeOutput(ctx['props'].val);
let 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\`);
const b2 = component(\`Child\`, {val: ctx['abc']}, key + \`__1\`, node, ctx);
let 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);
const b2 = component(\`Child\`, {val: ctx['val']}, key + \`__1\`, node, ctx);
let b2 = component(\`Child\`, {val: ctx['val']}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -273,7 +273,7 @@ exports[`bound functions is referentially equal after update 1`] = `
let { bind } = helpers;
return function template(ctx, node, key = \\"\\") {
return component(\`Child\`, {val: ctx['state'].val, fn: bind(ctx, ctx['someFunction'])}, key + \`__1\`, node, ctx);
return component(\`Child\`, {val: ctx['state'].val,fn: bind(ctx, ctx['someFunction'])}, key + \`__1\`, node, ctx);
}
}"
`;
@@ -1,19 +1,6 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`default props a default prop cannot be defined on a mandatory prop 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
const props1 = {};
helpers.validateProps(\`Child\`, props1, ctx);
return component(\`Child\`, props1, key + \`__1\`, node, ctx);
}
}"
`;
exports[`default props can set default boolean values 1`] = `
exports[`default props can set default required boolean values 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
@@ -21,15 +8,15 @@ exports[`default props can set default boolean values 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const props1 = {};
helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const props1 = {}
helpers.validateProps(\`SubComp\`, props1, ctx)
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
`;
exports[`default props can set default boolean values 2`] = `
exports[`default props can set default required boolean values 2`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
@@ -57,9 +44,9 @@ exports[`default props can set default values 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const props1 = {};
helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const props1 = {}
helpers.validateProps(\`SubComp\`, props1, ctx)
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -87,9 +74,9 @@ exports[`default props default values are also set whenever component is updated
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['state'].p};
helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const props1 = {p: ctx['state'].p}
helpers.validateProps(\`SubComp\`, props1, ctx)
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -115,8 +102,8 @@ exports[`props validation can specify that additional props are allowed (array)
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
const props1 = {message: 'm', otherProp: 'o'};
helpers.validateProps(\`Child\`, props1, ctx);
const props1 = {message: 'm',otherProp: 'o'}
helpers.validateProps(\`Child\`, props1, ctx)
return component(\`Child\`, props1, key + \`__1\`, node, ctx);
}
}"
@@ -141,8 +128,8 @@ exports[`props validation can specify that additional props are allowed (object)
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
const props1 = {message: 'm', otherProp: 'o'};
helpers.validateProps(\`Child\`, props1, ctx);
const props1 = {message: 'm',otherProp: 'o'}
helpers.validateProps(\`Child\`, props1, ctx)
return component(\`Child\`, props1, key + \`__1\`, node, ctx);
}
}"
@@ -169,9 +156,9 @@ exports[`props validation can validate a prop with multiple types 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const props1 = {p: ctx['p']}
helpers.validateProps(\`SubComp\`, props1, ctx)
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -198,9 +185,9 @@ exports[`props validation can validate a prop with multiple types 3`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const props1 = {p: ctx['p']}
helpers.validateProps(\`SubComp\`, props1, ctx)
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -227,9 +214,9 @@ exports[`props validation can validate a prop with multiple types 5`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const props1 = {p: ctx['p']}
helpers.validateProps(\`SubComp\`, props1, ctx)
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -243,9 +230,9 @@ exports[`props validation can validate an array with given primitive type 1`] =
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const props1 = {p: ctx['p']}
helpers.validateProps(\`SubComp\`, props1, ctx)
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -272,9 +259,9 @@ exports[`props validation can validate an array with given primitive type 3`] =
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const props1 = {p: ctx['p']}
helpers.validateProps(\`SubComp\`, props1, ctx)
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -301,9 +288,9 @@ exports[`props validation can validate an array with given primitive type 5`] =
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const props1 = {p: ctx['p']}
helpers.validateProps(\`SubComp\`, props1, ctx)
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -317,9 +304,9 @@ exports[`props validation can validate an array with given primitive type 6`] =
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const props1 = {p: ctx['p']}
helpers.validateProps(\`SubComp\`, props1, ctx)
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -333,9 +320,9 @@ exports[`props validation can validate an array with multiple sub element types
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const props1 = {p: ctx['p']}
helpers.validateProps(\`SubComp\`, props1, ctx)
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -362,9 +349,9 @@ exports[`props validation can validate an array with multiple sub element types
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const props1 = {p: ctx['p']}
helpers.validateProps(\`SubComp\`, props1, ctx)
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -391,9 +378,9 @@ exports[`props validation can validate an array with multiple sub element types
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const props1 = {p: ctx['p']}
helpers.validateProps(\`SubComp\`, props1, ctx)
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -420,9 +407,9 @@ exports[`props validation can validate an array with multiple sub element types
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const props1 = {p: ctx['p']}
helpers.validateProps(\`SubComp\`, props1, ctx)
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -436,9 +423,9 @@ exports[`props validation can validate an object with simple shape 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const props1 = {p: ctx['p']}
helpers.validateProps(\`SubComp\`, props1, ctx)
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -465,9 +452,9 @@ exports[`props validation can validate an object with simple shape 3`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const props1 = {p: ctx['p']}
helpers.validateProps(\`SubComp\`, props1, ctx)
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -481,9 +468,9 @@ exports[`props validation can validate an object with simple shape 4`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const props1 = {p: ctx['p']}
helpers.validateProps(\`SubComp\`, props1, ctx)
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -497,9 +484,9 @@ exports[`props validation can validate an object with simple shape 5`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const props1 = {p: ctx['p']}
helpers.validateProps(\`SubComp\`, props1, ctx)
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -513,9 +500,9 @@ exports[`props validation can validate an optional props 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const props1 = {p: ctx['p']}
helpers.validateProps(\`SubComp\`, props1, ctx)
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -542,9 +529,9 @@ exports[`props validation can validate an optional props 3`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const props1 = {p: ctx['p']}
helpers.validateProps(\`SubComp\`, props1, ctx)
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -571,9 +558,9 @@ exports[`props validation can validate an optional props 5`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const props1 = {p: ctx['p']}
helpers.validateProps(\`SubComp\`, props1, ctx)
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -587,9 +574,9 @@ exports[`props validation can validate recursively complicated prop def 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const props1 = {p: ctx['p']}
helpers.validateProps(\`SubComp\`, props1, ctx)
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -616,9 +603,9 @@ exports[`props validation can validate recursively complicated prop def 3`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const props1 = {p: ctx['p']}
helpers.validateProps(\`SubComp\`, props1, ctx)
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -645,9 +632,9 @@ exports[`props validation can validate recursively complicated prop def 5`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const props1 = {p: ctx['p']}
helpers.validateProps(\`SubComp\`, props1, ctx)
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -661,9 +648,9 @@ exports[`props validation default values are applied before validating props at
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['state'].p};
helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const props1 = {p: ctx['state'].p}
helpers.validateProps(\`SubComp\`, props1, ctx)
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -691,9 +678,9 @@ exports[`props validation missing required boolean prop causes an error 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const props1 = {};
helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const props1 = {}
helpers.validateProps(\`SubComp\`, props1, ctx)
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -707,9 +694,9 @@ exports[`props validation mix of optional and mandatory 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const props1 = {};
helpers.validateProps(\`Child\`, props1, ctx);
const b2 = component(\`Child\`, props1, key + \`__1\`, node, ctx);
const props1 = {}
helpers.validateProps(\`Child\`, props1, ctx)
let b2 = component(\`Child\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -723,9 +710,9 @@ exports[`props validation props are validated in dev mode (code snapshot) 1`] =
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const props1 = {message: 1};
helpers.validateProps(\`Child\`, props1, ctx);
const b2 = component(\`Child\`, props1, key + \`__1\`, node, ctx);
const props1 = {message: 1}
helpers.validateProps(\`Child\`, props1, ctx)
let b2 = component(\`Child\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -753,9 +740,9 @@ exports[`props validation props are validated whenever component is updated 1`]
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['state'].p};
helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const props1 = {p: ctx['state'].p}
helpers.validateProps(\`SubComp\`, props1, ctx)
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -783,9 +770,9 @@ exports[`props validation props: list of strings 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const props1 = {};
helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const props1 = {}
helpers.validateProps(\`SubComp\`, props1, ctx)
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -799,9 +786,9 @@ exports[`props validation validate simple types 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const props1 = {p: ctx['p']}
helpers.validateProps(\`SubComp\`, props1, ctx)
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -815,9 +802,9 @@ exports[`props validation validate simple types 2`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const props1 = {p: ctx['p']}
helpers.validateProps(\`SubComp\`, props1, ctx)
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -844,9 +831,9 @@ exports[`props validation validate simple types 4`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const props1 = {p: ctx['p']}
helpers.validateProps(\`SubComp\`, props1, ctx)
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -860,9 +847,9 @@ exports[`props validation validate simple types 5`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const props1 = {p: ctx['p']}
helpers.validateProps(\`SubComp\`, props1, ctx)
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -876,9 +863,9 @@ exports[`props validation validate simple types 6`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const props1 = {p: ctx['p']}
helpers.validateProps(\`SubComp\`, props1, ctx)
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -905,9 +892,9 @@ exports[`props validation validate simple types 8`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const props1 = {p: ctx['p']}
helpers.validateProps(\`SubComp\`, props1, ctx)
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -921,9 +908,9 @@ exports[`props validation validate simple types 9`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const props1 = {p: ctx['p']}
helpers.validateProps(\`SubComp\`, props1, ctx)
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -937,9 +924,9 @@ exports[`props validation validate simple types 10`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const props1 = {p: ctx['p']}
helpers.validateProps(\`SubComp\`, props1, ctx)
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -966,9 +953,9 @@ exports[`props validation validate simple types 12`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const props1 = {p: ctx['p']}
helpers.validateProps(\`SubComp\`, props1, ctx)
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -982,9 +969,9 @@ exports[`props validation validate simple types 13`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const props1 = {p: ctx['p']}
helpers.validateProps(\`SubComp\`, props1, ctx)
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -998,9 +985,9 @@ exports[`props validation validate simple types 14`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const props1 = {p: ctx['p']}
helpers.validateProps(\`SubComp\`, props1, ctx)
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -1027,9 +1014,9 @@ exports[`props validation validate simple types 16`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const props1 = {p: ctx['p']}
helpers.validateProps(\`SubComp\`, props1, ctx)
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -1043,9 +1030,9 @@ exports[`props validation validate simple types 17`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const props1 = {p: ctx['p']}
helpers.validateProps(\`SubComp\`, props1, ctx)
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -1059,9 +1046,9 @@ exports[`props validation validate simple types 18`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const props1 = {p: ctx['p']}
helpers.validateProps(\`SubComp\`, props1, ctx)
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -1088,9 +1075,9 @@ exports[`props validation validate simple types 20`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const props1 = {p: ctx['p']}
helpers.validateProps(\`SubComp\`, props1, ctx)
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -1104,9 +1091,9 @@ exports[`props validation validate simple types 21`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const props1 = {p: ctx['p']}
helpers.validateProps(\`SubComp\`, props1, ctx)
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -1120,9 +1107,9 @@ exports[`props validation validate simple types 22`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const props1 = {p: ctx['p']}
helpers.validateProps(\`SubComp\`, props1, ctx)
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -1149,9 +1136,9 @@ exports[`props validation validate simple types 24`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const props1 = {p: ctx['p']}
helpers.validateProps(\`SubComp\`, props1, ctx)
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -1165,9 +1152,9 @@ exports[`props validation validate simple types, alternate form 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const props1 = {p: ctx['p']}
helpers.validateProps(\`SubComp\`, props1, ctx)
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -1181,9 +1168,9 @@ exports[`props validation validate simple types, alternate form 2`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const props1 = {p: ctx['p']}
helpers.validateProps(\`SubComp\`, props1, ctx)
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -1210,9 +1197,9 @@ exports[`props validation validate simple types, alternate form 4`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const props1 = {p: ctx['p']}
helpers.validateProps(\`SubComp\`, props1, ctx)
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -1226,9 +1213,9 @@ exports[`props validation validate simple types, alternate form 5`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const props1 = {p: ctx['p']}
helpers.validateProps(\`SubComp\`, props1, ctx)
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -1242,9 +1229,9 @@ exports[`props validation validate simple types, alternate form 6`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const props1 = {p: ctx['p']}
helpers.validateProps(\`SubComp\`, props1, ctx)
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -1271,9 +1258,9 @@ exports[`props validation validate simple types, alternate form 8`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const props1 = {p: ctx['p']}
helpers.validateProps(\`SubComp\`, props1, ctx)
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -1287,9 +1274,9 @@ exports[`props validation validate simple types, alternate form 9`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const props1 = {p: ctx['p']}
helpers.validateProps(\`SubComp\`, props1, ctx)
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -1303,9 +1290,9 @@ exports[`props validation validate simple types, alternate form 10`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const props1 = {p: ctx['p']}
helpers.validateProps(\`SubComp\`, props1, ctx)
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -1332,9 +1319,9 @@ exports[`props validation validate simple types, alternate form 12`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const props1 = {p: ctx['p']}
helpers.validateProps(\`SubComp\`, props1, ctx)
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -1348,9 +1335,9 @@ exports[`props validation validate simple types, alternate form 13`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const props1 = {p: ctx['p']}
helpers.validateProps(\`SubComp\`, props1, ctx)
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -1364,9 +1351,9 @@ exports[`props validation validate simple types, alternate form 14`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const props1 = {p: ctx['p']}
helpers.validateProps(\`SubComp\`, props1, ctx)
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -1393,9 +1380,9 @@ exports[`props validation validate simple types, alternate form 16`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const props1 = {p: ctx['p']}
helpers.validateProps(\`SubComp\`, props1, ctx)
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -1409,9 +1396,9 @@ exports[`props validation validate simple types, alternate form 17`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const props1 = {p: ctx['p']}
helpers.validateProps(\`SubComp\`, props1, ctx)
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -1425,9 +1412,9 @@ exports[`props validation validate simple types, alternate form 18`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const props1 = {p: ctx['p']}
helpers.validateProps(\`SubComp\`, props1, ctx)
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -1454,9 +1441,9 @@ exports[`props validation validate simple types, alternate form 20`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const props1 = {p: ctx['p']}
helpers.validateProps(\`SubComp\`, props1, ctx)
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -1470,9 +1457,9 @@ exports[`props validation validate simple types, alternate form 21`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const props1 = {p: ctx['p']}
helpers.validateProps(\`SubComp\`, props1, ctx)
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -1486,9 +1473,9 @@ exports[`props validation validate simple types, alternate form 22`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const props1 = {p: ctx['p']}
helpers.validateProps(\`SubComp\`, props1, ctx)
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -1515,9 +1502,9 @@ exports[`props validation validate simple types, alternate form 24`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const props1 = {p: ctx['p']}
helpers.validateProps(\`SubComp\`, props1, ctx)
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -1531,9 +1518,9 @@ exports[`props validation validation is only done in dev mode 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const props1 = {};
helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
const props1 = {}
helpers.validateProps(\`SubComp\`, props1, ctx)
let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -1547,7 +1534,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 = \\"\\") {
const b2 = component(\`SubComp\`, {}, key + \`__1\`, node, ctx);
let b2 = component(\`SubComp\`, {}, key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -1,31 +1,5 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`reactivity in lifecycle Child component doesn't render when state they depend on changes but their parent is about to unmount them 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
let b2;
if (ctx['state'].renderChild) {
b2 = component(\`Child\`, {state: ctx['state']}, key + \`__1\`, node, ctx);
}
return multi([b2]);
}
}"
`;
exports[`reactivity in lifecycle Child component doesn't render when state they depend on changes but their parent is about to unmount them 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'].state.content.a);
}
}"
`;
exports[`reactivity in lifecycle can use a state hook 1`] = `
"function anonymous(bdom, helpers
) {
@@ -54,20 +28,6 @@ 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
) {
@@ -38,31 +38,11 @@ exports[`refs can use 2 refs with same name in a t-if/t-else situation 1`] = `
}"
`;
exports[`refs refs and recursive templates 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let block1 = createBlock(\`<p block-ref=\\"0\\"><block-text-1/><block-child-0/></p>\`);
return function template(ctx, node, key = \\"\\") {
const refs = ctx.__owl__.refs;
const ref1 = (el) => refs[\`root\`] = el;
let b2;
let txt1 = ctx['props'].tree.value;
if (ctx['props'].tree.child) {
b2 = component(\`Test\`, {tree: ctx['props'].tree.child}, key + \`__1\`, node, ctx);
}
return block1([ref1, txt1], [b2]);
}
}"
`;
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, markRaw } = helpers;
let { capture } = 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 +57,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);
const b3 = component(\`Dialog\`, {slots: markRaw({'footer': {__render: slot1, __ctx: ctx1}})}, key + \`__1\`, node, ctx);
let b3 = component(\`Dialog\`, {slots: {'footer': {__render: slot1, __ctx: ctx1}}}, key + \`__1\`, node, ctx);
return block1([txt1], [b3]);
}
}"
@@ -92,7 +72,7 @@ exports[`refs refs are properly bound in slots 2`] = `
let block1 = createBlock(\`<span><block-child-0/></span>\`);
return function template(ctx, node, key = \\"\\") {
const b2 = callSlot(ctx, node, key, 'footer', false, null);
let b2 = callSlot(ctx, node, key, 'footer', false, {});
return block1([], [b2]);
}
}"
@@ -110,8 +90,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\`);
const b2 = block2([ref1]);
const b3 = block3([ref1]);
let b2 = block2([ref1]);
let b3 = block3([ref1]);
return multi([b2, b3]);
}
}"
@@ -17,8 +17,8 @@ exports[`force render in case of existing render 2`] = `
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);
let b2 = component(\`C\`, {}, key + \`__1\`, node, ctx);
let b3 = text(ctx['props'].val);
return multi([b2, b3]);
}
}"
@@ -41,8 +41,8 @@ exports[`rendering semantics can force a render to update sub tree 1`] = `
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);
let b2 = text(ctx['state'].value);
let b3 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
return multi([b2, b3]);
}
}"
@@ -65,8 +65,8 @@ exports[`rendering semantics can render a parent without rendering child 1`] = `
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);
let b2 = text(ctx['state'].value);
let b3 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
return multi([b2, b3]);
}
}"
@@ -127,41 +127,14 @@ exports[`rendering semantics props are reactive 2`] = `
}"
`;
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);
let b2 = text(ctx['state'].obj.val);
let b3 = component(\`B\`, {obj: ctx['state'].obj}, key + \`__1\`, node, ctx);
return multi([b2, b3]);
}
}"
@@ -188,25 +161,3 @@ exports[`rendering semantics rendering is atomic (for one subtree) 3`] = `
}
}"
`;
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 = \\"\\") {
const b2 = block2();
let b2 = block2();
let attr1 = ctx['props'].class;
const b3 = block3([attr1]);
let b3 = block3([attr1]);
return multi([b2, b3]);
}
}"
@@ -147,7 +147,7 @@ exports[`style and class handling class on sub component, which is switched to a
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
return component(\`Child\`, {class: 'someclass', child: ctx['state'].child}, key + \`__1\`, node, ctx);
return component(\`Child\`, {class: 'someclass',child: ctx['state'].child}, key + \`__1\`, node, ctx);
}
}"
`;
@@ -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 = \\"\\") {
const b2 = component(\`Child\`, {class: 'a b c d'}, key + \`__1\`, node, ctx);
let 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 = \\"\\") {
const b2 = component(\`Child\`, {class: undefined}, key + \`__1\`, node, ctx);
let 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 = \\"\\") {
const b2 = component(\`Child\`, {class: {b:ctx['state'].b}}, key + \`__1\`, node, ctx);
let 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;
const b1 = text(\` owl \`);
let 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 = \\"\\") {
const b2 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
let b2 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
const template1 = (ctx['sub']);
const b3 = call(this, template1, ctx, node, key + \`__2\`);
let 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');
const b2 = call(this, template1, ctx, node, key + \`__1\`);
let 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 = \\"\\") {
const b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
let 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 = \\"\\") {
const b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
let 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 = \\"\\") {
const b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
let 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);
const b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
let 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'];
const b3 = block3([hdlr1, txt1]);
let b3 = block3([hdlr1, txt1]);
ctx = Object.create(ctx);
ctx[isBoundary] = 1;
setContextValue(ctx, \\"level\\", ctx['level']+1);
const b4 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
let 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 {
const b4 = callTemplate_2.call(this, ctx, node, key + \`__2\`);
let 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];
const key1 = ctx['val'];
let key1 = ctx['val'];
c_block2[i1] = withKey(callTemplate_1.call(this, ctx, node, key + \`__1__\${key1}\`), key1);
}
const b2 = list(c_block2);
let 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 = \\"\\") {
const b2 = ctx['myBlock']();
let 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 = \\"\\") {
const Comp1 = ctx['constructor'].components[ctx['state'].child];
const b2 = toggler(Comp1, component(Comp1, {}, key + \`__1\`, node, ctx));
let Comp1 = ctx['constructor'].components[ctx['state'].child];
let 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;
const Comp1 = ctx['myComponent'];
let 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;
const Comp1 = ctx['myComponent'];
let 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 = \\"\\") {
const Comp1 = ctx['Counter'];
const b2 = toggler(Comp1, component(Comp1, {}, key + \`__1\`, node, ctx));
let Comp1 = ctx['Counter'];
let 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 = \\"\\") {
const Comp1 = ctx['Child'];
let 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 = \\"\\") {
const Comp1 = ctx['Child'];
let 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];
const key1 = 'li_'+ctx['item'];
const b4 = component(\`Child\`, {item: ctx['item']}, key + \`__1__\${key1}\`, node, ctx);
let key1 = 'li_'+ctx['item'];
let b4 = component(\`Child\`, {item: ctx['item']}, key + \`__1__\${key1}\`, node, ctx);
c_block2[i1] = withKey(block3([], [b4]), key1);
}
const b2 = list(c_block2);
let b2 = list(c_block2);
return block1([], [b2]);
}
}"
@@ -46,15 +46,15 @@ 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];
const key1 = 'child';
let key1 = 'child';
if (keys1.has(key1)) { throw new Error(\`Got duplicate key in t-foreach: \${key1}\`)}
keys1.add(key1);
const props1 = {};
helpers.validateProps(\`Child\`, props1, ctx);
const props1 = {}
helpers.validateProps(\`Child\`, props1, ctx)
c_block1[i1] = withKey(component(\`Child\`, props1, key + \`__1__\${key1}\`, node, ctx), key1);
}
return list(c_block1);
@@ -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];
const key1 = ctx['blip'].id;
const b4 = component(\`SubComponent\`, {}, key + \`__1__\${key1}\`, node, ctx);
let key1 = ctx['blip'].id;
let b4 = component(\`SubComponent\`, {}, key + \`__1__\${key1}\`, node, ctx);
c_block2[i1] = withKey(block3([], [b4]), key1);
}
const b2 = list(c_block2);
let 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;
const key1 = ctx['section_index'];
let 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;
const key2 = ctx['blip_index'];
let 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);
}
const b2 = list(c_block2);
let 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];
const key1 = ctx['row'];
let 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];
const key2 = ctx['col'];
const b6 = component(\`Child\`, {row: ctx['row'], col: ctx['col']}, key + \`__1__\${key1}__\${key2}\`, node, ctx);
let key2 = ctx['col'];
let 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__;
const b4 = list(c_block4);
let b4 = list(c_block4);
c_block2[i1] = withKey(block3([], [b4]), key1);
}
const b2 = list(c_block2);
let 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];
const key1 = ctx['elem'].id;
let 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];
const key1 = ctx['number'];
let key1 = ctx['number'];
c_block2[i1] = withKey(component(\`Child\`, {n: ctx['number']}, key + \`__1__\${key1}\`, node, ctx), key1);
}
const b2 = list(c_block2);
let 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];
const key1 = ctx['number'];
let key1 = ctx['number'];
c_block2[i1] = withKey(component(\`Child\`, {}, key + \`__1__\${key1}\`, node, ctx), key1);
}
const b2 = list(c_block2);
let 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];
const key1 = ctx['c'];
let key1 = ctx['c'];
c_block2[i1] = withKey(component(\`Child\`, {key: ctx['c']}, key + \`__1__\${key1}\`, node, ctx), key1);
}
const b2 = list(c_block2);
let 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;
const key1 = ctx['n_index'];
let key1 = ctx['n_index'];
c_block2[i1] = withKey(component(\`Child\`, {val: ctx['n_index']}, key + \`__1__\${key1}\`, node, ctx), key1);
}
const b2 = list(c_block2);
let 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];
const key1 = ctx['c'];
let 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);
}
const b2 = list(c_block2);
let 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'];
const b2 = toggler(tKey_1, component(\`Child\`, {key: ctx['key']}, tKey_1 + key + \`__1\`, node, ctx));
let 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'];
const b2 = toggler(tKey_1, component(\`Child\`, {key: ctx['key1']}, tKey_1 + key + \`__1\`, node, ctx));
let b2 = toggler(tKey_1, component(\`Child\`, {key: ctx['key1']}, tKey_1 + key + \`__1\`, node, ctx));
const tKey_2 = ctx['key2'];
const b3 = toggler(tKey_2, component(\`Child\`, {key: ctx['key2']}, tKey_2 + key + \`__2\`, node, ctx));
let 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']);
const b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
let b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
ctx = ctx.__proto__;
ctx = Object.create(ctx);
ctx[isBoundary] = 1;
setContextValue(ctx, \\"key\\", ctx['key2']);
const b3 = callTemplate_2.call(this, ctx, node, key + \`__2\`);
let 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 = \\"\\") {
const b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
let 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'];
const b2 = toggler(tKey_1, component(\`Child\`, {key: ctx['key1']}, tKey_1 + key + \`__1\`, node, ctx));
let b2 = toggler(tKey_1, component(\`Child\`, {key: ctx['key1']}, tKey_1 + key + \`__1\`, node, ctx));
const tKey_2 = ctx['key2'];
const b3 = toggler(tKey_2, component(\`Child\`, {key: ctx['key2']}, tKey_2 + key + \`__2\`, node, ctx));
let b3 = toggler(tKey_2, component(\`Child\`, {key: ctx['key2']}, tKey_2 + key + \`__2\`, node, ctx));
return multi([b2, b3]);
}
}"
@@ -10,9 +10,8 @@ exports[`t-model directive .lazy modifier 1`] = `
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; }];
let attr1 = ctx['state']['text'];
let hdlr1 = [(ev) => { bExpr1['text'] = ev.target.value; }];
let txt1 = ctx['state'].text;
return block1([attr1, hdlr1, txt1]);
}
@@ -29,9 +28,8 @@ exports[`t-model directive .number modifier 1`] = `
return function template(ctx, node, key = \\"\\") {
const bExpr1 = ctx['state'];
const expr1 = 'number';
let attr1 = bExpr1[expr1];
let hdlr1 = [(ev) => { bExpr1[expr1] = toNumber(ev.target.value); }];
let attr1 = ctx['state']['number'];
let hdlr1 = [(ev) => { bExpr1['number'] = toNumber(ev.target.value); }];
let txt1 = ctx['state'].number;
return block1([attr1, hdlr1, txt1]);
}
@@ -48,9 +46,8 @@ exports[`t-model directive .trim modifier 1`] = `
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.trim(); }];
let attr1 = ctx['state']['text'];
let hdlr1 = [(ev) => { bExpr1['text'] = ev.target.value.trim(); }];
let txt1 = ctx['state'].text;
return block1([attr1, hdlr1, txt1]);
}
@@ -67,9 +64,8 @@ exports[`t-model directive basic use, on an input 1`] = `
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; }];
let attr1 = ctx['state']['text'];
let hdlr1 = [(ev) => { bExpr1['text'] = ev.target.value; }];
let txt1 = ctx['state'].text;
return block1([attr1, hdlr1, txt1]);
}
@@ -86,9 +82,8 @@ exports[`t-model directive basic use, on an input with bracket expression 1`] =
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; }];
let attr1 = ctx['state']['text'];
let hdlr1 = [(ev) => { bExpr1['text'] = ev.target.value; }];
let txt1 = ctx['state'].text;
return block1([attr1, hdlr1, txt1]);
}
@@ -105,9 +100,8 @@ exports[`t-model directive basic use, on another key in component 1`] = `
return function template(ctx, node, key = \\"\\") {
const bExpr1 = ctx['some'];
const expr1 = 'text';
let attr1 = bExpr1[expr1];
let hdlr1 = [(ev) => { bExpr1[expr1] = ev.target.value; }];
let attr1 = ctx['some']['text'];
let hdlr1 = [(ev) => { bExpr1['text'] = ev.target.value; }];
let txt1 = ctx['some'].text;
return block1([attr1, hdlr1, txt1]);
}
@@ -125,9 +119,8 @@ exports[`t-model directive can also define t-on directive on same event, part 1
return function template(ctx, node, key = \\"\\") {
let hdlr1 = [ctx['onInput'], ctx];
const bExpr1 = ctx['state'];
const expr1 = 'text';
let attr1 = bExpr1[expr1];
let hdlr2 = [(ev) => { bExpr1[expr1] = ev.target.value; }];
let attr1 = ctx['state']['text'];
let hdlr2 = [(ev) => { bExpr1['text'] = ev.target.value; }];
return block1([hdlr1, attr1, hdlr2]);
}
}"
@@ -144,19 +137,16 @@ exports[`t-model directive can also define t-on directive on same event, part 2
return function template(ctx, node, key = \\"\\") {
let hdlr1 = [ctx['onClick'], ctx];
const bExpr1 = ctx['state'];
const expr1 = 'choice';
let attr1 = bExpr1[expr1] === 'One';
let hdlr2 = [(ev) => { bExpr1[expr1] = ev.target.value; }];
let attr1 = ctx['state']['choice'] === 'One';
let hdlr2 = [(ev) => { bExpr1['choice'] = ev.target.value; }];
let hdlr3 = [ctx['onClick'], ctx];
const bExpr2 = ctx['state'];
const expr2 = 'choice';
let attr2 = bExpr2[expr2] === 'Two';
let hdlr4 = [(ev) => { bExpr2[expr2] = ev.target.value; }];
let attr2 = ctx['state']['choice'] === 'Two';
let hdlr4 = [(ev) => { bExpr2['choice'] = ev.target.value; }];
let hdlr5 = [ctx['onClick'], ctx];
const bExpr3 = ctx['state'];
const expr3 = 'choice';
let attr3 = bExpr3[expr3] === 'Three';
let hdlr6 = [(ev) => { bExpr3[expr3] = ev.target.value; }];
let attr3 = ctx['state']['choice'] === 'Three';
let hdlr6 = [(ev) => { bExpr3['choice'] = ev.target.value; }];
return block1([hdlr1, attr1, hdlr2, hdlr3, attr2, hdlr4, hdlr5, attr3, hdlr6]);
}
}"
@@ -175,9 +165,8 @@ exports[`t-model directive following a scope protecting directive (e.g. t-set) 1
ctx[isBoundary] = 1
setContextValue(ctx, \\"admiral\\", 'Bruno');
const bExpr1 = ctx['state'];
const expr1 = 'text';
let attr1 = bExpr1[expr1];
let hdlr1 = [(ev) => { bExpr1[expr1] = ev.target.value; }];
let attr1 = ctx['state']['text'];
let hdlr1 = [(ev) => { bExpr1['text'] = ev.target.value; }];
return block1([attr1, hdlr1]);
}
}"
@@ -194,17 +183,16 @@ 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];
const key1 = ctx['thing'].id;
let key1 = ctx['thing'].id;
const bExpr1 = ctx['thing'];
const expr1 = 'f';
let attr1 = bExpr1[expr1];
let hdlr1 = [(ev) => { bExpr1[expr1] = ev.target.checked; }];
let attr1 = ctx['thing']['f'];
let hdlr1 = [(ev) => { bExpr1['f'] = ev.target.checked; }];
c_block2[i1] = withKey(block3([attr1, hdlr1]), key1);
}
const b2 = list(c_block2);
let b2 = list(c_block2);
return block1([], [b2]);
}
}"
@@ -221,46 +209,17 @@ 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;
const key1 = ctx['thing_index'];
let 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; }];
let attr1 = ctx['state'][ctx['thing_index']];
let hdlr1 = [(ev) => { bExpr1[ctx['thing_index']] = ev.target.value; }];
c_block2[i1] = withKey(block3([attr1, hdlr1]), key1);
}
const b2 = list(c_block2);
return block1([], [b2]);
}
}"
`;
exports[`t-model directive in a t-foreach, part 3 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { prepareList, toNumber, withKey } = helpers;
let block1 = createBlock(\`<div><block-child-0/></div>\`);
let block3 = createBlock(\`<input block-attribute-0=\\"value\\" block-handler-1=\\"input\\"/>\`);
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
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;
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);
}
const b2 = list(c_block2);
let b2 = list(c_block2);
return block1([], [b2]);
}
}"
@@ -276,9 +235,8 @@ exports[`t-model directive on a select 1`] = `
return function template(ctx, node, key = \\"\\") {
const bExpr1 = ctx['state'];
const expr1 = 'color';
let attr1 = bExpr1[expr1];
let hdlr1 = [(ev) => { bExpr1[expr1] = ev.target.value; }];
let attr1 = ctx['state']['color'];
let hdlr1 = [(ev) => { bExpr1['color'] = ev.target.value; }];
let txt1 = ctx['state'].color;
return block1([attr1, hdlr1, txt1]);
}
@@ -295,9 +253,8 @@ exports[`t-model directive on a select, initial state 1`] = `
return function template(ctx, node, key = \\"\\") {
const bExpr1 = ctx['state'];
const expr1 = 'color';
let attr1 = bExpr1[expr1];
let hdlr1 = [(ev) => { bExpr1[expr1] = ev.target.value; }];
let attr1 = ctx['state']['color'];
let hdlr1 = [(ev) => { bExpr1['color'] = ev.target.value; }];
return block1([attr1, hdlr1]);
}
}"
@@ -313,9 +270,8 @@ exports[`t-model directive on a sub state key 1`] = `
return function template(ctx, node, key = \\"\\") {
const bExpr1 = ctx['state'].something;
const expr1 = 'text';
let attr1 = bExpr1[expr1];
let hdlr1 = [(ev) => { bExpr1[expr1] = ev.target.value; }];
let attr1 = ctx['state'].something['text'];
let hdlr1 = [(ev) => { bExpr1['text'] = ev.target.value; }];
let txt1 = ctx['state'].something.text;
return block1([attr1, hdlr1, txt1]);
}
@@ -332,13 +288,11 @@ exports[`t-model directive on an input type=radio 1`] = `
return function template(ctx, node, key = \\"\\") {
const bExpr1 = ctx['state'];
const expr1 = 'choice';
let attr1 = bExpr1[expr1] === 'One';
let hdlr1 = [(ev) => { bExpr1[expr1] = ev.target.value; }];
let attr1 = ctx['state']['choice'] === 'One';
let hdlr1 = [(ev) => { bExpr1['choice'] = ev.target.value; }];
const bExpr2 = ctx['state'];
const expr2 = 'choice';
let attr2 = bExpr2[expr2] === 'Two';
let hdlr2 = [(ev) => { bExpr2[expr2] = ev.target.value; }];
let attr2 = ctx['state']['choice'] === 'Two';
let hdlr2 = [(ev) => { bExpr2['choice'] = ev.target.value; }];
let txt1 = ctx['state'].choice;
return block1([attr1, hdlr1, attr2, hdlr2, txt1]);
}
@@ -355,13 +309,11 @@ exports[`t-model directive on an input type=radio, with initial value 1`] = `
return function template(ctx, node, key = \\"\\") {
const bExpr1 = ctx['state'];
const expr1 = 'choice';
let attr1 = bExpr1[expr1] === 'One';
let hdlr1 = [(ev) => { bExpr1[expr1] = ev.target.value; }];
let attr1 = ctx['state']['choice'] === 'One';
let hdlr1 = [(ev) => { bExpr1['choice'] = ev.target.value; }];
const bExpr2 = ctx['state'];
const expr2 = 'choice';
let attr2 = bExpr2[expr2] === 'Two';
let hdlr2 = [(ev) => { bExpr2[expr2] = ev.target.value; }];
let attr2 = ctx['state']['choice'] === 'Two';
let hdlr2 = [(ev) => { bExpr2['choice'] = ev.target.value; }];
return block1([attr1, hdlr1, attr2, hdlr2]);
}
}"
@@ -378,9 +330,8 @@ exports[`t-model directive on an input, type=checkbox 1`] = `
return function template(ctx, node, key = \\"\\") {
let b2,b3;
const bExpr1 = ctx['state'];
const expr1 = 'flag';
let attr1 = bExpr1[expr1];
let hdlr1 = [(ev) => { bExpr1[expr1] = ev.target.checked; }];
let attr1 = ctx['state']['flag'];
let hdlr1 = [(ev) => { bExpr1['flag'] = ev.target.checked; }];
if (ctx['state'].flag) {
b2 = text(\`yes\`);
} else {
@@ -401,155 +352,14 @@ exports[`t-model directive on an textarea 1`] = `
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; }];
let attr1 = ctx['state']['text'];
let hdlr1 = [(ev) => { bExpr1['text'] = ev.target.value; }];
let txt1 = ctx['state'].text;
return block1([attr1, hdlr1, txt1]);
}
}"
`;
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
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { toNumber } = helpers;
let block1 = createBlock(\`<div><select block-attribute-0=\\"value\\" block-handler-1=\\"change\\"><option value=\\"a\\"><block-text-2/></option><option value=\\"b\\"><block-text-3/></option><option value=\\"c\\"><block-text-4/></option></select></div>\`);
return function template(ctx, node, key = \\"\\") {
const bExpr1 = ctx['state'];
const expr1 = 'model';
let attr1 = bExpr1[expr1];
let hdlr1 = [(ev) => { bExpr1[expr1] = ev.target.value; }];
let txt1 = 'a';
let txt2 = 'b';
let txt3 = 'c';
return block1([attr1, hdlr1, txt1, txt2, txt3]);
}
}"
`;
exports[`t-model directive t-model with dynamic values on select options -- 2 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { toNumber } = helpers;
let block1 = createBlock(\`<div><select block-handler-0=\\"change\\"><option block-attribute-1=\\"value\\" block-attribute-2=\\"selected\\"><block-text-3/></option><option block-attribute-4=\\"value\\" block-attribute-5=\\"selected\\"><block-text-6/></option></select></div>\`);
return function template(ctx, node, key = \\"\\") {
const bExpr1 = ctx['state'];
const expr1 = 'model';
const bValue1 = bExpr1[expr1];
let hdlr1 = [(ev) => { bExpr1[expr1] = ev.target.value; }];
let attr1 = ctx['options'][0];
let attr2 = bValue1 === ctx['options'][0];
let txt1 = ctx['options'][0];
let attr3 = (ctx['options'][1]);
let attr4 = bValue1 === (ctx['options'][1]);
let txt2 = ctx['options'][1];
return block1([hdlr1, attr1, attr2, txt1, attr3, attr4, txt2]);
}
}"
`;
exports[`t-model directive t-model with dynamic values on select options -- 3 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { toNumber } = helpers;
let block1 = createBlock(\`<div><select block-handler-0=\\"change\\"><option block-attribute-1=\\"value\\" block-attribute-2=\\"selected\\"><block-text-3/></option><option value=\\"b\\" block-attribute-4=\\"selected\\"><block-text-5/></option></select></div>\`);
return function template(ctx, node, key = \\"\\") {
const bExpr1 = ctx['state'];
const expr1 = 'model';
const bValue1 = bExpr1[expr1];
let hdlr1 = [(ev) => { bExpr1[expr1] = ev.target.value; }];
let attr1 = ctx['options'][0];
let attr2 = bValue1 === ctx['options'][0];
let txt1 = ctx['options'][0];
let attr3 = bValue1 === \\"b\\";
let txt2 = ctx['options'][1];
return block1([hdlr1, attr1, attr2, txt1, attr3, txt2]);
}
}"
`;
exports[`t-model directive t-model with dynamic values on select options 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { toNumber } = helpers;
let block1 = createBlock(\`<div><select block-handler-0=\\"change\\"><option block-attribute-1=\\"value\\" block-attribute-2=\\"selected\\"><block-text-3/></option><option block-attribute-4=\\"value\\" block-attribute-5=\\"selected\\"><block-text-6/></option></select></div>\`);
return function template(ctx, node, key = \\"\\") {
const bExpr1 = ctx['state'];
const expr1 = 'model';
const bValue1 = bExpr1[expr1];
let hdlr1 = [(ev) => { bExpr1[expr1] = ev.target.value; }];
let attr1 = ctx['options'][0];
let attr2 = bValue1 === ctx['options'][0];
let txt1 = ctx['options'][0];
let attr3 = ctx['options'][1];
let attr4 = bValue1 === ctx['options'][1];
let txt2 = ctx['options'][1];
return block1([hdlr1, attr1, attr2, txt1, attr3, attr4, txt2]);
}
}"
`;
exports[`t-model directive t-model with dynamic values on select options in foreach 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { toNumber, prepareList, withKey } = helpers;
let block1 = createBlock(\`<div><select block-handler-0=\\"change\\"><block-child-0/></select></div>\`);
let block3 = createBlock(\`<option block-attribute-0=\\"value\\" block-attribute-1=\\"selected\\"><block-text-2/></option>\`);
return function template(ctx, node, key = \\"\\") {
const bExpr1 = ctx['state'];
const expr1 = 'model';
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']);;
for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`v\`] = v_block2[i1];
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);
}
const b2 = list(c_block2);
return block1([hdlr1], [b2]);
}
}"
`;
exports[`t-model directive two inputs in a div alternating with a t-if 1`] = `
"function anonymous(bdom, helpers
) {
@@ -564,38 +374,17 @@ exports[`t-model directive two inputs in a div alternating with a t-if 1`] = `
let b2,b3;
if (ctx['state'].flag) {
const bExpr1 = ctx['state'];
const expr1 = 'text1';
let attr1 = bExpr1[expr1];
let hdlr1 = [(ev) => { bExpr1[expr1] = ev.target.value; }];
let attr1 = ctx['state']['text1'];
let hdlr1 = [(ev) => { bExpr1['text1'] = ev.target.value; }];
b2 = block2([attr1, hdlr1]);
}
if (!ctx['state'].flag) {
const bExpr2 = ctx['state'];
const expr2 = 'text2';
let attr2 = bExpr2[expr2];
let hdlr2 = [(ev) => { bExpr2[expr2] = ev.target.value; }];
let attr2 = ctx['state']['text2'];
let hdlr2 = [(ev) => { bExpr2['text2'] = ev.target.value; }];
b3 = block3([attr2, hdlr2]);
}
return block1([], [b2, b3]);
}
}"
`;
exports[`t-model directive with expression having a changing key 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { toNumber } = helpers;
let block1 = createBlock(\`<div><input block-attribute-0=\\"value\\" block-handler-1=\\"input\\"/><span><block-text-2/></span></div>\`);
return function template(ctx, node, key = \\"\\") {
const bExpr1 = ctx['state'].something;
const expr1 = ctx['text'].key;
let attr1 = bExpr1[expr1];
let hdlr1 = [(ev) => { bExpr1[expr1] = ev.target.value; }];
let txt1 = ctx['state'].something[ctx['text'].key];
return block1([attr1, hdlr1, txt1]);
}
}"
`;
+12 -147
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];
const key1 = ctx['val'];
let 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);
}
const b2 = list(c_block2);
let 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;
const key1 = ctx['val'];
let 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);
}
const b2 = list(c_block2);
let 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;
const key1 = ctx['val'];
let 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);
}
const b2 = list(c_block2);
let b2 = list(c_block2);
return block1([], [b2]);
}
}"
@@ -104,82 +104,23 @@ 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;
const key1 = ctx['val'];
let 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);
}
const b2 = list(c_block2);
let 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
) {
@@ -210,79 +151,3 @@ 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 = \\"\\") {
const b2 = component(\`Child\`, Object.assign({}, ctx['some'].obj), key + \`__1\`, node, ctx);
let b2 = component(\`Child\`, Object.assign({}, ctx['some'].obj), key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -28,30 +28,6 @@ exports[`t-props basic use 2`] = `
}"
`;
exports[`t-props child receives a copy of the t-props object, not the original 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['childProps']), key + \`__1\`, node, ctx);
}
}"
`;
exports[`t-props child receives a copy of the t-props object, not the original 2`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let block1 = createBlock(\`<div/>\`);
return function template(ctx, node, key = \\"\\") {
return block1();
}
}"
`;
exports[`t-props t-props and other props 1`] = `
"function anonymous(bdom, helpers
) {
@@ -60,7 +36,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 = \\"\\") {
const b2 = component(\`Comp\`, Object.assign({}, ctx['state1'], {a: ctx['a']}), key + \`__1\`, node, ctx);
let b2 = component(\`Comp\`, Object.assign({}, ctx['state1'], {a: ctx['a']}), key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -89,7 +65,7 @@ exports[`t-props t-props only 1`] = `
let block1 = createBlock(\`<div><div><block-child-0/></div></div>\`);
return function template(ctx, node, key = \\"\\") {
const b2 = component(\`Comp\`, Object.assign({}, ctx['state']), key + \`__1\`, node, ctx);
let b2 = component(\`Comp\`, Object.assign({}, ctx['state']), key + \`__1\`, node, ctx);
return block1([], [b2]);
}
}"
@@ -117,7 +93,7 @@ exports[`t-props t-props with props 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const b2 = component(\`Child\`, Object.assign({}, ctx['childProps'], {a: 1, b: 2}), key + \`__1\`, node, ctx);
let 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, markRaw } = helpers;
let { isBoundary, withDefault, setContextValue, capture } = 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);
const b2 = component(\`Childcomp\`, {slots: markRaw({'default': {__render: slot1, __ctx: ctx1}})}, key + \`__1\`, node, ctx);
let b2 = component(\`Childcomp\`, {slots: {'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, markRaw } = helpers;
let { capture, isBoundary, withDefault, LazyValue, safeOutput } = helpers;
function slot1(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
ctx[isBoundary] = 1
ctx[\`v\`] = new LazyValue(value1, ctx, node);
const b3 = text(\` in slot \`);
const b4 = safeOutput(ctx['v']);
let b3 = text(\` in slot \`);
let 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: markRaw({'default': {__render: slot1, __ctx: ctx1}})}, key + \`__2\`, node, ctx);
return component(\`Child\`, {slots: {'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 = \\"\\") {
const b2 = text(\`Child \`);
const b3 = callSlot(ctx, node, key, 'default', false, null);
let b2 = text(\`Child \`);
let b3 = callSlot(ctx, node, key, 'default', false, {});
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, markRaw } = helpers;
let { capture, isBoundary, withDefault, LazyValue, safeOutput } = 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);
const b5 = text(\` tea \`);
const b6 = safeOutput(ctx['v']);
let b5 = text(\` tea \`);
let b6 = safeOutput(ctx['v']);
return multi([b5, b6]);
}
function value1(ctx, node, key = \\"\\") {
const b3 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
const b4 = block4();
let b3 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
let b4 = block4();
return multi([b3, b4]);
}
return function template(ctx, node, key = \\"\\") {
const ctx1 = capture(ctx);
return component(\`Blorg\`, {slots: markRaw({'default': {__render: slot1, __ctx: ctx1}})}, key + \`__2\`, node, ctx);
return component(\`Blorg\`, {slots: {'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 = \\"\\") {
const b2 = text(\`Blorg \`);
const b3 = callSlot(ctx, node, key, 'default', false, null);
let b2 = text(\`Blorg \`);
let b3 = callSlot(ctx, node, key, 'default', false, {});
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, markRaw } = helpers;
let { capture, isBoundary, withDefault, LazyValue } = 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: markRaw({'default': {__render: slot1, __ctx: ctx1}})}, key + \`__2\`, node, ctx);
return component(\`Child\`, {slots: {'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 = \\"\\") {
const b2 = text(\`Child \`);
const b3 = callSlot(ctx, node, key, 'default', false, null);
let b2 = text(\`Child \`);
let b3 = callSlot(ctx, node, key, 'default', false, {});
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'];
const b2 = component(\`Childcomp\`, {}, key + \`__1\`, node, ctx);
let 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);
const b3 = safeOutput(ctx['v']);
let 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);
const b3 = safeOutput(ctx['v']);
let b3 = safeOutput(ctx['v']);
return block1([], [b3]);
}
}"
+3 -51
View File
@@ -1,4 +1,4 @@
import { App, Component, mount, status, toRaw, useState, xml } from "../../src";
import { App, Component, mount, status, 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(toRaw(this.props)).toBe(p);
expect(this.props).not.toBe(p);
}
}
@@ -171,27 +171,6 @@ describe("basics", () => {
expect(error!.message).toBe("Cannot mount a component on a detached dom node");
});
test("a component cannot be mounted in a detached node (even if node is detached later)", async () => {
const warn = console.warn;
console.warn = jest.fn();
class Test extends Component {
static template = xml`<div/>`;
}
let error: Error;
const prom = mount(Test, fixture);
await Promise.resolve();
fixture.remove();
try {
await prom;
} catch (e) {
error = e as Error;
}
expect(error!).toBeDefined();
expect(error!.message).toBe("Cannot mount a component on a detached dom node");
expect(console.warn).toBeCalledTimes(1);
console.warn = warn;
});
test("crashes if it cannot find a template", async () => {
class Test extends Component {
static template = "wrongtemplate";
@@ -204,7 +183,7 @@ describe("basics", () => {
error = e as Error;
}
expect(error!).toBeDefined();
expect(error!.message).toBe('Missing template: "wrongtemplate" (for component "Test")');
expect(error!.message).toBe('Missing template: "wrongtemplate"');
});
test("class component with dynamic text", async () => {
@@ -1027,31 +1006,4 @@ describe("t-out in components", () => {
"<div>&lt;b&gt;one&lt;/b&gt;<b>one</b>&lt;b&gt;two&lt;/b&gt;<b>two</b>&lt;b&gt;tree&lt;/b&gt;<b>tree</b></div>"
);
});
test("can switch the contents of two t-out repeatedly", async () => {
class Test extends Component {
static template = xml`
<t t-out="state.a"/>
<t t-out="state.b"/>
`;
state = useState({
a: markup("<div>1</div>"),
b: markup("<div>2</div>"),
});
reverse() {
const { state } = this;
[state.a, state.b] = [state.b, state.a];
}
}
const comp = await mount(Test, fixture);
expect(fixture.innerHTML).toBe("<div>1</div><div>2</div>");
comp.reverse();
await nextTick();
expect(fixture.innerHTML).toBe("<div>2</div><div>1</div>");
comp.reverse();
await nextTick();
expect(fixture.innerHTML).toBe("<div>1</div><div>2</div>");
});
});
+44 -597
View File
@@ -3,7 +3,6 @@ import {
Component,
mount,
onMounted,
onRendered,
onWillStart,
onWillUnmount,
onWillUpdateProps,
@@ -114,8 +113,8 @@ test("destroying/recreating a subwidget with different props (if start is not ov
expect(n).toBe(2);
expect([
"Child:willDestroy",
"W:willRender",
"Child:willDestroy",
"Child:setup",
"Child:willStart",
"W:rendered",
@@ -134,58 +133,6 @@ 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();
@@ -244,8 +191,8 @@ test("creating two async components, scenario 1", async () => {
await nextTick();
expect(fixture.innerHTML).toBe("");
expect([
"ChildA:willDestroy",
"Parent:willRender",
"ChildA:willDestroy",
"ChildA:setup",
"ChildA:willStart",
"ChildB:setup",
@@ -696,8 +643,8 @@ test("rendering component again in next microtick", async () => {
"Child:setup",
"Child:willStart",
"Parent:rendered",
"Child:willDestroy",
"Parent:willRender",
"Child:willDestroy",
"Child:setup",
"Child:willStart",
"Parent:rendered",
@@ -1080,7 +1027,11 @@ test("concurrent renderings scenario 3", async () => {
stateC.fromC = "d";
await nextTick();
expect(fixture.innerHTML).toBe("<div><p><span><i>1c</i></span></p></div>");
expect([]).toBeLogged();
expect([
"ComponentC:willRender",
"ComponentD:willUpdateProps",
"ComponentC:rendered",
]).toBeLogged();
defB.resolve(); // resolve rendering initiated in A (still blocked in D)
await nextTick();
@@ -1096,7 +1047,14 @@ test("concurrent renderings scenario 3", async () => {
defsD[0].resolve(); // resolve rendering initiated in C (should be ignored)
await nextTick();
expect(ComponentD.prototype.someValue).toBeCalledTimes(1);
expect(fixture.innerHTML).toBe("<div><p><span><i>1c</i></span></p></div>");
expect([]).toBeLogged();
defsD[1].resolve(); // completely resolve rendering initiated in A
await nextTick();
expect(fixture.innerHTML).toBe("<div><p><span><i>2d</i></span></p></div>");
expect(ComponentD.prototype.someValue).toBeCalledTimes(2);
expect([
"ComponentD:willRender",
"ComponentD:rendered",
@@ -1109,7 +1067,6 @@ test("concurrent renderings scenario 3", async () => {
"ComponentB:patched",
"ComponentA:patched",
]).toBeLogged();
expect(ComponentD.prototype.someValue).toBeCalledTimes(2);
});
test("concurrent renderings scenario 4", async () => {
@@ -1198,7 +1155,11 @@ test("concurrent renderings scenario 4", async () => {
stateC.fromC = "d";
await nextTick();
expect(fixture.innerHTML).toBe("<div><p><span><i>1c</i></span></p></div>");
expect([]).toBeLogged();
expect([
"ComponentC:willRender",
"ComponentD:willUpdateProps",
"ComponentC:rendered",
]).toBeLogged();
defB.resolve(); // resolve rendering initiated in A (still blocked in D)
await nextTick();
@@ -1214,12 +1175,6 @@ test("concurrent renderings scenario 4", async () => {
defsD[1].resolve(); // completely resolve rendering initiated in A
await nextTick();
expect(fixture.innerHTML).toBe("<div><p><span><i>1c</i></span></p></div>");
expect(ComponentD.prototype.someValue).toBeCalledTimes(1);
expect([]).toBeLogged();
defsD[0].resolve(); // resolve rendering initiated in C (should be ignored)
await nextTick();
expect(fixture.innerHTML).toBe("<div><p><span><i>2d</i></span></p></div>");
expect(ComponentD.prototype.someValue).toBeCalledTimes(2);
expect([
@@ -1234,6 +1189,12 @@ test("concurrent renderings scenario 4", async () => {
"ComponentB:patched",
"ComponentA:patched",
]).toBeLogged();
defsD[0].resolve(); // resolve rendering initiated in C (should be ignored)
await nextTick();
expect(fixture.innerHTML).toBe("<div><p><span><i>2d</i></span></p></div>");
expect(ComponentD.prototype.someValue).toBeCalledTimes(2);
expect([]).toBeLogged();
});
test("concurrent renderings scenario 5", async () => {
@@ -1725,7 +1686,6 @@ test("concurrent renderings scenario 10", async () => {
expect(fixture.innerHTML).toBe("<div><p></p></div>");
expect([
"ComponentA:willRender",
"ComponentC:willDestroy",
"ComponentB:willUpdateProps",
"ComponentA:rendered",
]).toBeLogged();
@@ -1736,6 +1696,7 @@ test("concurrent renderings scenario 10", async () => {
expect(rendered).toBe(1);
expect([
"ComponentB:willRender",
"ComponentC:willDestroy",
"ComponentC:setup",
"ComponentC:willStart",
"ComponentB:rendered",
@@ -2275,11 +2236,11 @@ test("concurrent renderings scenario 16", async () => {
"D:setup",
"D:willStart",
"C:rendered",
"D:willDestroy",
"B:willRender",
"C:willUpdateProps",
"B:rendered",
"C:willRender",
"D:willDestroy",
"D:setup",
"D:willStart",
"C:rendered",
@@ -2701,7 +2662,13 @@ test("delay willUpdateProps", async () => {
parent.render();
await nextTick();
expect(fixture.innerHTML).toBe("0_0");
expect(["Parent:willRender", "Child:willUpdateProps", "Parent:rendered"]).toBeLogged();
expect([
"Child:willRender",
"Child:rendered",
"Parent:willRender",
"Child:willUpdateProps",
"Parent:rendered",
]).toBeLogged();
promise = makeDeferred();
const prom2 = promise;
@@ -2818,9 +2785,13 @@ test("delay willUpdateProps with rendering grandchild", async () => {
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",
"DelayedChild:willUpdateProps",
"ReactiveChild:willUpdateProps",
@@ -2841,6 +2812,8 @@ test("delay willUpdateProps with rendering grandchild", async () => {
"GrandParent:willRender",
"Parent:willUpdateProps",
"GrandParent:rendered",
"ReactiveChild:willRender",
"ReactiveChild:rendered",
"Parent:willRender",
"DelayedChild:willUpdateProps",
"ReactiveChild:willUpdateProps",
@@ -2990,13 +2963,13 @@ test("t-key on dom node having a component", async () => {
expect(fixture.innerHTML).toBe("<div>3</div>");
expect([
"Child (2):willDestroy",
"Child (3):setup",
"Child (3):willStart",
"Child (3):willRender",
"Child (3):rendered",
"Child (1):willUnmount",
"Child (1):willDestroy",
"Child (2):willDestroy",
"Child (3):mounted",
]).toBeLogged();
});
@@ -3048,13 +3021,13 @@ test("t-key on dynamic async component (toggler is never patched)", async () =>
expect(fixture.innerHTML).toBe("<div>3</div>");
expect([
"Child (2):willDestroy",
"Child (3):setup",
"Child (3):willStart",
"Child (3):willRender",
"Child (3):rendered",
"Child (1):willUnmount",
"Child (1):willDestroy",
"Child (2):willDestroy",
"Child (3):mounted",
]).toBeLogged();
});
@@ -3107,13 +3080,13 @@ test("t-foreach with dynamic async component", async () => {
expect(fixture.innerHTML).toBe("<div>3</div>");
expect([
"Child (2):willDestroy",
"Child (3):setup",
"Child (3):willStart",
"Child (3):willRender",
"Child (3):rendered",
"Child (1):willUnmount",
"Child (1):willDestroy",
"Child (2):willDestroy",
"Child (3):mounted",
]).toBeLogged();
});
@@ -3164,532 +3137,6 @@ 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("delayed rendering, but then initial rendering is cancelled by yet another render", async () => {
const promC = makeDeferred();
let stateB: any = null;
class D extends Component {
static template = xml`<button t-on-click="increment"><t t-esc="state.val"/></button>`;
state = useState({ val: 1 });
setup() {
useLogLifecycle();
}
increment() {
this.state.val++;
}
}
class C extends Component {
static template = xml`<D/><p><t t-esc="props.value"/></p>`;
static components = { D };
setup() {
useLogLifecycle();
onWillUpdateProps(() => promC);
}
}
class B extends Component {
static template = xml`<C value="state.someValue + props.value"/>`;
static components = { C };
state = useState({ someValue: 3 });
setup() {
useLogLifecycle();
stateB = this.state;
}
}
class A extends Component {
static template = xml`<B value="state.value"/>`;
static components = { B };
state = useState({ value: 33 });
setup() {
useLogLifecycle();
}
}
const parent = await mount(A, fixture);
expect(fixture.innerHTML).toBe("<button>1</button><p>36</p>");
expect([
"A:setup",
"A:willStart",
"A:willRender",
"B:setup",
"B:willStart",
"A:rendered",
"B:willRender",
"C:setup",
"C:willStart",
"B:rendered",
"C:willRender",
"D:setup",
"D:willStart",
"C:rendered",
"D:willRender",
"D:rendered",
"D:mounted",
"C:mounted",
"B:mounted",
"A:mounted",
]).toBeLogged();
// update B and C, but render is blocked by C willupdateProps
stateB.someValue = 5;
await nextTick();
expect(["B:willRender", "C:willUpdateProps", "B:rendered"]).toBeLogged();
// update D => render should be delayed, because B is currently rendering
fixture.querySelector("button")!.click();
await nextTick();
expect([]).toBeLogged();
// update A => render should go to B and cancel it
parent.state.value = 34;
await nextTick();
expect([
"A:willRender",
"B:willUpdateProps",
"A:rendered",
"B:willRender",
"C:willUpdateProps",
"B:rendered",
]).toBeLogged();
promC.resolve();
await nextTick();
expect([
"C:willRender",
"C:rendered",
"D:willRender",
"D:rendered",
"D:willPatch",
"D:patched",
"A:willPatch",
"B:willPatch",
"C:willPatch",
"C:patched",
"B:patched",
"A:patched",
]).toBeLogged();
expect(fixture.innerHTML).toBe("<button>2</button><p>39</p>");
});
test("delayed rendering, reusing fiber and stuff", async () => {
let prom1 = makeDeferred();
let prom2 = makeDeferred();
class C extends Component {
static template = xml`<button t-on-click="increment"><t t-esc="state.val"/></button>`;
state = useState({ val: 1 });
setup() {
useLogLifecycle();
}
increment() {
this.state.val++;
}
}
class B extends Component {
static template = xml`<t t-esc="props.value"/><C />`;
static components = { C };
setup() {
useLogLifecycle();
let flag = false;
onWillUpdateProps(() => {
flag = true;
return prom1;
});
onRendered(async () => {
if (flag) {
await nextMicroTick();
prom2.resolve();
}
});
}
}
class A extends Component {
static template = xml`<B value="state.value"/>`;
static components = { B };
state = useState({ value: 33 });
setup() {
useLogLifecycle();
}
}
const parent = await mount(A, fixture);
expect(fixture.innerHTML).toBe("33<button>1</button>");
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();
// initiate a render in A, but is blocked in B
parent.state.value = 34;
await nextTick();
expect(["A:willRender", "B:willUpdateProps", "A:rendered"]).toBeLogged();
// initiate a render in C => delayed because of render in A
fixture.querySelector("button")!.click();
await nextTick();
expect([]).toBeLogged();
// wait for render in A to be completed
prom1.resolve();
await prom2;
expect(["B:willRender", "B:rendered", "C:willRender", "C:rendered"]).toBeLogged();
// initiate a new render in A => fiber will be reused
parent.state.value = 355;
await nextTick();
expect(fixture.innerHTML).toBe("355<button>2</button>");
expect([
"A:willRender",
"B:willUpdateProps",
"A:rendered",
"B:willRender",
"B:rendered",
"A:willPatch",
"B:willPatch",
"B:patched",
"A:patched",
"C:willPatch",
"C:patched",
]).toBeLogged();
});
test("delayed rendering, then component is destroyed and stuff", async () => {
let prom1 = makeDeferred();
class C extends Component {
static template = xml`<button t-on-click="increment"><t t-esc="state.val"/></button>`;
state = useState({ val: 1 });
setup() {
useLogLifecycle();
}
increment() {
this.state.val++;
}
}
class B extends Component {
static template = xml`<t t-esc="props.value"/><t t-if="props.value lt 10"><C /></t>`;
static components = { C };
setup() {
useLogLifecycle();
onWillUpdateProps(() => prom1);
}
}
class A extends Component {
static template = xml`<B value="state.value"/>`;
static components = { B };
state = useState({ value: 3 });
setup() {
useLogLifecycle();
}
}
const parent = await mount(A, fixture);
expect(fixture.innerHTML).toBe("3<button>1</button>");
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();
// initiate a render in C (so will be first task)
fixture.querySelector("button")!.click();
// initiate a render in A, but is blocked in B. the render will destroy c. also,
// it blocks the render C
parent.state.value = 34;
await nextTick();
expect(["A:willRender", "B:willUpdateProps", "A:rendered"]).toBeLogged();
// wait for render in A to be completed
prom1.resolve();
await nextTick();
expect(fixture.innerHTML).toBe("34");
expect([
"B:willRender",
"B:rendered",
"A:willPatch",
"B:willPatch",
"C:willUnmount",
"C:willDestroy",
"B:patched",
"A:patched",
]).toBeLogged();
await nextTick();
});
test("delayed rendering, reusing fiber then component is destroyed and stuff", async () => {
let prom1 = makeDeferred();
class C extends Component {
static template = xml`<button t-on-click="increment"><t t-esc="state.val"/></button>`;
state = useState({ val: 1 });
setup() {
useLogLifecycle();
}
increment() {
this.state.val++;
}
}
class B extends Component {
static template = xml`<t t-esc="props.value"/><C />`;
static components = { C };
setup() {
useLogLifecycle();
onWillUpdateProps(() => prom1);
}
}
class A extends Component {
static template = xml`A<t t-if="state.value lt 15"><B value="state.value"/></t>`;
static components = { B };
state = useState({ value: 3 });
setup() {
useLogLifecycle();
}
}
const parent = await mount(A, fixture);
expect(fixture.innerHTML).toBe("A3<button>1</button>");
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();
// initiate a render in A, but is blocked in B
parent.state.value = 5;
await nextTick();
expect(["A:willRender", "B:willUpdateProps", "A:rendered"]).toBeLogged();
// initiate a render in C (will be delayed because of render in A)
fixture.querySelector("button")!.click();
await nextTick();
expect([]).toBeLogged();
// initiate a render in A, that will destroy B
parent.state.value = 23;
await nextTick();
expect(fixture.innerHTML).toBe("A");
expect([
"A:willRender",
"A:rendered",
"A:willPatch",
"B:willUnmount",
"C:willUnmount",
"C:willDestroy",
"B:willDestroy",
"A:patched",
]).toBeLogged();
});
test("another scenario with delayed rendering", async () => {
let prom1 = makeDeferred();
let onSecondRenderA = makeDeferred();
class C extends Component {
static template = xml`<button t-on-click="increment"><t t-esc="state.val"/></button>`;
state = useState({ val: 1 });
setup() {
useLogLifecycle();
}
increment() {
this.state.val++;
}
}
class B extends Component {
static template = xml`<t t-esc="props.value"/><C />`;
static components = { C };
setup() {
useLogLifecycle();
onWillUpdateProps(() => prom1);
}
}
class A extends Component {
static template = xml`A<t t-if="state.value lt 15"><B value="state.value"/></t>`;
static components = { B };
state = useState({ value: 3 });
setup() {
useLogLifecycle();
let n = 0;
onRendered(() => {
n++;
if (n === 2) {
onSecondRenderA.resolve();
}
});
}
}
const parent = await mount(A, fixture);
expect(fixture.innerHTML).toBe("A3<button>1</button>");
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();
// initiate a render in A, but is blocked in B
parent.state.value = 5;
await nextTick();
expect(["A:willRender", "B:willUpdateProps", "A:rendered"]).toBeLogged();
// initiate a render in C (will be delayed because of render in A)
fixture.querySelector("button")!.click();
await nextTick();
expect([]).toBeLogged();
// initiate a render in A, that will destroy B
parent.state.value = 23;
await onSecondRenderA;
await nextMicroTick();
expect(["A:willRender", "A:rendered"]).toBeLogged();
// rerender A, but without destroying B
parent.state.value = 7;
await nextTick();
expect(["A:willRender", "B:willUpdateProps", "A:rendered"]).toBeLogged();
prom1.resolve();
await nextTick();
expect(fixture.innerHTML).toBe("A7<button>2</button>");
expect([
"B:willRender",
"B:rendered",
"C:willRender",
"C:rendered",
"A:willPatch",
"B:willPatch",
"B:patched",
"A:patched",
"C:willPatch",
"C:patched",
]).toBeLogged();
});
// test.skip("components with shouldUpdate=false", async () => {
// const state = { p: 1, cc: 10 };
-2
View File
@@ -49,7 +49,5 @@ 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));
});
});

Some files were not shown because too many files have changed in this diff Show More