Compare commits

..

210 Commits

Author SHA1 Message Date
Samuel Degueldre c8f7274977 [IMP] index: export batched utils function 2022-01-28 11:18:41 +01:00
Géry Debongnie 924dffeb36 [TEST] component: add test to make sure a specific issue does not arise 2022-01-27 15:02:44 +01:00
Géry Debongnie 0dbc807e01 [IMP] typing: make app and mount method properly generic 2022-01-27 14:43:33 +01:00
Bruno Boi 4b88787a72 [FIX] compiler: never add _ prefix to non variable token 2022-01-27 14:41:16 +01:00
Samuel Degueldre 6f0a4b1c92 [FIX] compiler: do not pass dynamic props object as is
The child receiving the props can observe changes made to the passed
t-props object which is not desirable.
2022-01-27 13:19:14 +01:00
Bruno Boi 3f575148b6 [FIX] compiler: add _ prefix to local variables while compiling an expression 2022-01-27 10:57:13 +01:00
Géry Debongnie 4a971f2963 [IMP] hooks: introduce useChildSubEnv and change useSubEnv 2022-01-27 10:35:06 +01:00
Géry Debongnie d7850aaf7a [FIX] compiler: does not modify xml doc in place 2022-01-27 10:34:41 +01:00
Bruno Boi 0e13b859d0 [FIX] component: properly capture expression of t-model 2022-01-27 09:23:52 +01:00
Géry Debongnie c813a1ce03 [DOC] fix error in slot documentation 2022-01-25 12:37:07 +01:00
Géry Debongnie 54d69c2dde [FIX] reactivity: clear callbacks at destroy time instead of unmount 2022-01-24 16:36:32 +01:00
Géry Debongnie 11d4aae8d2 [FIX] compiler: add missing ; in some places 2022-01-24 14:51:12 +01:00
Géry Debongnie b159a073d9 [FIX] component: proper error message in dev mode in some cases 2022-01-24 13:18:19 +01:00
Lucas Perais (lpe) d9b189bcba [FIX] compiler: force new block for svg nested in html 2022-01-24 12:56:43 +01:00
Géry Debongnie 7ef1fe0b99 [FIX] svg: allow path as root tag 2022-01-24 10:29:22 +01:00
Samuel Degueldre 211ecdf689 [FIX] blockdom: fix VHtml patching not setting its html correctly 2022-01-24 09:36:43 +01:00
Lucas Perais (lpe) b208894d38 [FIX] compiler: t-model on select with options with dynamic values 2022-01-21 16:38:58 +01:00
Géry Debongnie 0737bb39b4 [DOC] update changelog renderToString example 2022-01-21 15:40:27 +01:00
Géry Debongnie de584b01a8 [FIX] reactivity: do not observe eventtarget and other stuff 2022-01-21 15:40:27 +01:00
Géry Debongnie 525029b682 [IMP] reactivity: introduces markRaw and toRaw functions 2022-01-21 15:40:27 +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
109 changed files with 1937 additions and 5192 deletions
+1 -1
View File
@@ -5,7 +5,7 @@ name: Node.js CI
on: on:
pull_request: pull_request:
branches: [ master ] branches: [ master, owl-next ]
jobs: jobs:
build: build:
+68 -44
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: `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)) - 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)) - 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** **Templates**
- breaking: `t-foreach` should always have a corresponding `t-key` ([details](#20-t-foreach-should-always-have-a-corresponding-t-key)) - 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-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)) - 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)) - 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)) - 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)) - new: components can use the `.bind` suffix to bind function props ([doc](doc/reference/props.md#binding-function-props))
- breaking: `t-on` does not accept expressions, only functions ([details](#30-t-on-does-not-accept-expressions-only-functions)) - breaking: `t-on` does not work on components any more ([details](#12-t-on-does-not-work-on-components-any-more))
- new: an error is thrown if an handler defined in a `t-on-` directive is not a function (failed silently previously in some cases)
- breaking: `t-component` no longer accepts strings ([details](#17-t-component-no-longer-accepts-strings)) - 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** **Slots**
@@ -79,7 +66,10 @@ All changes are documented here in no particular order.
- improved performance - improved performance
- much simpler code - 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 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)) - new `useEffect` hook ([doc](doc/reference/hooks.md#useeffect))
- breaking: `Context` is removed ([details](#15-context-is-removed)) - 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 totally empty ([details](#16-env-is-now-totally-empty))
@@ -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), 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 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 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, a much more powerful reactivity system.
it's like each Owl 2 component has a `shouldUpdate` method that precisely tracks
every value used by the component.
Migration code: remove the `shouldUpdate` methods, and it should work as well Migration code: remove the `shouldUpdate` methods. Then, maybe the following
as before. 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 ### 9. component.el is removed
@@ -312,6 +325,41 @@ Documentation:
- [Mounting a component](doc/reference/app.md#mount-helper) - [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 ### 13. Portal does no longer transfer DOM events
In Owl 1, a Portal component would listen to events emitted on its portalled In Owl 1, a Portal component would listen to events emitted on its portalled
@@ -740,27 +788,3 @@ 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, Migration: code should just be adapted to either use another browser object,
or to use native browser function (and then, just mock them directly). or to use native browser function (and then, just mock them directly).
## 40. Rendering a component does not necessarily render child components
Before, if one had the following component tree:
```mermaid
graph TD;
A-->B;
A-->C;
```
when `A` would render, it would also render `B` and `C`. Now, in Owl 2, it will
(shallow) compare the before and after props, and `B` or `C` will only be rerendered
if their props have changed.
Now, the question is what happens if the props have changed, but in a deeper way?
In that case, Owl will know, because each props are now reactive. So, if some
inner value read by `B` was changed, then only `B` will be updated.
Rationale: This was just not possible in Owl 1, but it now possible. This is
due to the rewriteof the underlying rendering engine and the reactivity
system. The goal is to have a big performance boost in large screen with many
components: now Owl only rerender what is strictly useful.
+1 -2
View File
@@ -110,7 +110,6 @@ Are you new to Owl? This is the place to start!
- [Comparison with React/Vue](doc/miscellaneous/comparison.md) - [Comparison with React/Vue](doc/miscellaneous/comparison.md)
- [Why did Odoo build Owl?](doc/miscellaneous/why_owl.md) - [Why did Odoo build Owl?](doc/miscellaneous/why_owl.md)
- [Changelog (from owl 1.x to 2.x)](CHANGELOG.md) - [Changelog (from owl 1.x to 2.x)](CHANGELOG.md)
- [Notes on compiled templates](doc/miscellaneous/compiled_template.md)
## Installing Owl ## Installing Owl
@@ -122,5 +121,5 @@ npm install @odoo/owl
If you want to use a simple `<script>` tag, the last release can be downloaded here: 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)
-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.
+16 -21
View File
@@ -3,7 +3,6 @@
## Content ## Content
- [Overview](#overview) - [Overview](#overview)
- [API](#api)
- [Configuration](#configuration) - [Configuration](#configuration)
- [`mount` helper](#mount-helper) - [`mount` helper](#mount-helper)
- [Loading templates](#loading-templates) - [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 component, the templates, and possibly other settings. Then, we mount that
instance somewhere in the DOM. instance somewhere in the DOM.
## API ## Configuration
- **`constructor(Root[, config])`**: first argument should be a component class (not - **`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 - **`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 second argument is an object with mounting options (see below). Mount the app
@@ -45,24 +58,6 @@ instance somewhere in the DOM.
- **`destroy()`**: destroys the application - **`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, which activates some additional checks (in particular, the props validation
code is only performed in dev mode)
- **`test (boolean, default=false)`**: `test` mode is the same as `dev` mode, except
that Owll 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 ## `mount` helper
Note that there is a `mount` helper to do that in just a line: Note that there is a `mount` helper to do that in just a line:
+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`, component will go through the following lifecycle methods: `willUpdateProps`,
`willPatch` and `patched`. `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. 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 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 slightly later (at the next animation frame, if no component delays the
rendering) 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 ## Static Properties
- **`template (string)`**: this is the name of the template that - **`template (string)`**: this is the name of the template that
+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) - [Event Handling](#event-handling)
- [Modifiers](#modifiers) - [Modifiers](#modifiers)
- [Synthetic Events](#synthetic-events) - [Synthetic Events](#synthetic-events)
- [On Components](#on-components)
## Event Handling ## Event Handling
@@ -101,19 +100,3 @@ To enable it, one can just use the `.synthetic` suffix:
</t> </t>
</div> </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).
+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, - `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 - `validate`: this is a function which should return a boolean to determine if
the value is valid or not. Useful for custom validation logic. 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 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 sometimes useful for generic components that will propagate some or all their
props to their child components. 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: Examples:
```js ```js
@@ -194,8 +190,7 @@ class ComponentB extends owl.Component {
element: {type: Object, shape: {id: Boolean, text: String } element: {type: Object, shape: {id: Boolean, text: String }
}, },
date: Date, date: Date,
combinedVal: [Number, Boolean], combinedVal: [Number, Boolean]
optionalProp: { type: Number, optional: true }
}; };
... ...
-12
View File
@@ -25,11 +25,6 @@ To solve this issue, Owl provides two reactivity primitives:
Most of the time, the `useState` hook is the best solution. 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` ## `useState`
Let us start by an example of how `useState` could be used: Let us start by an example of how `useState` could be used:
@@ -122,10 +117,3 @@ 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 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 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! 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
```
+9 -25
View File
@@ -87,8 +87,8 @@ grandparent of the slot content).
## Default Slot ## Default Slot
All elements inside the component which are not a named slot will be treated as The first element inside the component which is not a named slot will
part of the content of the `default` slot. For example: be considered the `default` slot. For example:
```xml ```xml
<div t-name="Parent"> <div t-name="Parent">
@@ -110,7 +110,6 @@ One can mix default slot and named slots:
default content default content
<t t-set-slot="footer"> <t t-set-slot="footer">
content for footer slot here content for footer slot here
</t>
</Child> </Child>
</div> </div>
``` ```
@@ -210,45 +209,30 @@ use this `Notebook` component:
</Notebook> </Notebook>
``` ```
Slot params works like normal props, so one can use the `.bind` suffix to
bind a function if needed.
## Slot scopes ## Slot scopes
For other kinds of advanced use cases, the content of a slot may depends on some For other kind 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 specific information specific to the generic component. This is the opposite
params. 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-slot-scope` directive along
with the `t-set-slot`. This defines the name of a variable that can access with the `t-set-slot`. This defines the name of a variable that can access
everything given by the child component: everything given by the child component:
```xml ```xml
<MyComponent> <div>
<t t-set-slot="foo" t-slot-scope="scope"> <t t-set-slot="foo" t-slot-scope="scope">
content content
<t t-esc="scope.bool"/> <t t-esc="scope.bool"/>
<t t-esc="scope.num"/> <t t-esc="scope.num"/>
</t> </t>
</MyComponent> </div>
``` ```
And the child component that includes the slot can provide values like this: And the child component that includes the slot can provide values like this:
```xml ```xml
<div>
<t t-slot="foo" bool="other_var" num="5"> <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.
-11
View File
@@ -21,7 +21,6 @@
- [Fragments](#fragments) - [Fragments](#fragments)
- [Inline templates](#inline-templates) - [Inline templates](#inline-templates)
- [Rendering svg](#rendering-svg) - [Rendering svg](#rendering-svg)
- [Restrictions](#restrictions)
## Overview ## Overview
@@ -681,13 +680,3 @@ 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 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 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. templates (included with `t-call`) should have one of these tag as root tag.
## Restrictions
Note that Owl templates forbid the use of tag and or attributes starting with
the `block-` string. This restriction prevents name collision with the internal
code of Owl.
```xml
<div><block-1>this will not be accepted by Owl</block-1></div>
```
+1 -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: we can define additional attributes with the `translatableAttributes` option:
```js ```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", "name": "@odoo/owl",
"version": "2.0.0-beta.3", "version": "2.0.0-alpha1",
"description": "Odoo Web Library (OWL)", "description": "Odoo Web Library (OWL)",
"main": "dist/owl.cjs.js", "main": "dist/owl.cjs.js",
"browser": "dist/owl.iife.js", "browser": "dist/owl.iife.js",
+1 -1
View File
@@ -1,6 +1,6 @@
# 🦉 OWL Roadmap 🦉 # 🦉 OWL Roadmap 🦉
- Current version: 1.4.10 - Current version: 1.4.7
- Status: stable - Status: stable
This roadmap is only an attempt at predicting Owl's future. Everything may This roadmap is only an attempt at predicting Owl's future. Everything may
+18 -28
View File
@@ -4,7 +4,6 @@ import { MountOptions } from "../component/fibers";
import { Scheduler } from "../component/scheduler"; import { Scheduler } from "../component/scheduler";
import { TemplateSet, TemplateSetConfig } from "./template_set"; import { TemplateSet, TemplateSetConfig } from "./template_set";
import { nodeErrorHandlers } from "../component/error_handling"; import { nodeErrorHandlers } from "../component/error_handling";
import { validateTarget } from "../utils";
// reimplement dev mode stuff see last change in 0f7a8289a6fb8387c3c1af41c6664b2a8448758f // reimplement dev mode stuff see last change in 0f7a8289a6fb8387c3c1af41c6664b2a8448758f
@@ -15,27 +14,18 @@ export interface Env {
export interface AppConfig<P, E> extends TemplateSetConfig { export interface AppConfig<P, E> extends TemplateSetConfig {
props?: P; props?: P;
env?: E; env?: E;
test?: boolean;
} }
let hasBeenLogged = false; export const DEV_MSG = `Owl is running in 'dev' mode.
export const DEV_MSG = () => {
const hash = (window as any).owl ? (window as any).owl.__info__.hash : "master";
return `Owl is running in 'dev' mode.
This is not suitable for production use. 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< export class App<
T extends abstract new (...args: any) => any = any, T extends abstract new (...args: any) => any = any,
P extends object = any, P = any,
E = any E = any
> extends TemplateSet { > extends TemplateSet {
static validateTarget = validateTarget;
Root: ComponentConstructor<P, E>; Root: ComponentConstructor<P, E>;
props: P; props: P;
env: E; env: E;
@@ -45,27 +35,31 @@ export class App<
constructor(Root: ComponentConstructor<P, E>, config: AppConfig<P, E> = {}) { constructor(Root: ComponentConstructor<P, E>, config: AppConfig<P, E> = {}) {
super(config); super(config);
this.Root = Root; this.Root = Root;
if (config.test) { if (config.dev) {
this.dev = true; console.info(DEV_MSG);
} }
if (this.dev && !config.test && !hasBeenLogged) { const descrs = Object.getOwnPropertyDescriptors(config.env || {});
console.info(DEV_MSG()); this.env = Object.freeze(Object.defineProperties({}, descrs)) as E;
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); this.props = config.props || ({} as P);
} }
mount(target: HTMLElement, options?: MountOptions): Promise<Component<P, E> & InstanceType<T>> { mount(target: HTMLElement, options?: MountOptions): Promise<Component<P, E> & InstanceType<T>> {
App.validateTarget(target); this.checkTarget(target);
const node = this.makeNode(this.Root, this.props); const node = this.makeNode(this.Root, this.props);
const prom = this.mountNode(node, target, options); const prom = this.mountNode(node, target, options);
this.root = node; this.root = node;
return prom; return prom;
} }
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: ComponentConstructor, props: any): ComponentNode { makeNode(Component: ComponentConstructor, props: any): ComponentNode {
return new ComponentNode(Component, props, this); return new ComponentNode(Component, props, this);
} }
@@ -106,11 +100,7 @@ export class App<
} }
} }
export async function mount< export async function mount<T extends abstract new (...args: any) => any = any, P = any, E = any>(
T extends abstract new (...args: any) => any = any,
P extends object = any,
E = any
>(
C: T & ComponentConstructor<P, E>, C: T & ComponentConstructor<P, E>,
target: HTMLElement, target: HTMLElement,
config: AppConfig<P, E> & MountOptions = {} config: AppConfig<P, E> & MountOptions = {}
+5 -8
View File
@@ -1,9 +1,7 @@
import { BDom, multi, text, toggler, createCatcher } from "../blockdom"; import { BDom, multi, text, toggler } from "../blockdom";
import { validateProps } from "../component/props_validation"; import { validateProps } from "../component/props_validation";
import { Markup } from "../utils"; import { Markup } from "../utils";
import { html } from "../blockdom/index"; import { html } from "../blockdom/index";
import { TARGET } from "../reactivity";
/** /**
* This file contains utility functions that will be injected in each template, * This file contains utility functions that will be injected in each template,
* to perform various useful tasks in the compiled code. * to perform various useful tasks in the compiled code.
@@ -23,11 +21,11 @@ function callSlot(
defaultContent?: (ctx: any, node: any, key: string) => BDom defaultContent?: (ctx: any, node: any, key: string) => BDom
): BDom { ): BDom {
key = key + "__slot_" + name; key = key + "__slot_" + name;
const slots = ctx.props[TARGET].slots || {}; const slots = (ctx.props && ctx.props.slots) || {};
const { __render, __ctx, __scope } = slots[name] || {}; const { __render, __ctx, __scope } = slots[name] || {};
const slotScope = Object.create(__ctx || {}); const slotScope = Object.create(__ctx || {});
if (__scope) { if (__scope) {
slotScope[__scope] = extra; slotScope[__scope] = extra || {};
} }
const slotBDom = __render ? __render.call(__ctx.__owl__.component, slotScope, parent, key) : null; const slotBDom = __render ? __render.call(__ctx.__owl__.component, slotScope, parent, key) : null;
if (defaultContent) { if (defaultContent) {
@@ -137,7 +135,7 @@ export function safeOutput(value: any): ReturnType<typeof toggler> {
} else if (value instanceof LazyValue) { } else if (value instanceof LazyValue) {
safeKey = `lazy_value`; safeKey = `lazy_value`;
block = value.evaluate(); block = value.evaluate();
} else if (value instanceof String || typeof value === "string") { } else if (typeof value === "string") {
safeKey = "string_unsafe"; safeKey = "string_unsafe";
block = text(value); block = text(value);
} else { } else {
@@ -183,7 +181,7 @@ function multiRefSetter(refs: RefMap, name: string): RefSetter {
}; };
} }
export const helpers = { export const UTILS = {
withDefault, withDefault,
zero: Symbol("zero"), zero: Symbol("zero"),
isBoundary, isBoundary,
@@ -199,5 +197,4 @@ export const helpers = {
LazyValue, LazyValue,
safeOutput, safeOutput,
bind, bind,
createCatcher,
}; };
+25 -30
View File
@@ -1,13 +1,12 @@
import { createBlock, html, list, multi, text, toggler, comment } from "../blockdom"; import { createBlock, html, list, multi, text, toggler, comment } from "../blockdom";
import { compile, Template } from "../compiler"; import { compile, Template } from "../compiler";
import { markRaw } from "../reactivity"; import { component } from "../component/component_node";
import { Portal } from "../portal"; import { UTILS } from "./template_helpers";
import { component, getCurrent } from "../component/component_node";
import { helpers } from "./template_helpers";
import { globalTemplates } from "../utils";
const bdom = { text, createBlock, list, multi, html, toggler, component, comment }; const bdom = { text, createBlock, list, multi, html, toggler, component, comment };
export const globalTemplates: { [key: string]: string | Element } = {};
function parseXML(xml: string): Document { function parseXML(xml: string): Document {
const parser = new DOMParser(); const parser = new DOMParser();
@@ -38,22 +37,6 @@ function parseXML(xml: string): Document {
return doc; 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 { export interface TemplateSetConfig {
dev?: boolean; dev?: boolean;
translatableAttributes?: string[]; translatableAttributes?: string[];
@@ -67,7 +50,13 @@ export class TemplateSet {
templates: { [name: string]: Template } = {}; templates: { [name: string]: Template } = {};
translateFn?: (s: string) => string; translateFn?: (s: string) => string;
translatableAttributes?: 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 = {}) { constructor(config: TemplateSetConfig = {}) {
this.dev = config.dev || false; this.dev = config.dev || false;
@@ -76,7 +65,6 @@ export class TemplateSet {
if (config.templates) { if (config.templates) {
this.addTemplates(config.templates); this.addTemplates(config.templates);
} }
this.helpers = makeHelpers(this.getTemplate.bind(this));
} }
addTemplate( addTemplate(
@@ -106,12 +94,7 @@ export class TemplateSet {
if (!(name in this.templates)) { if (!(name in this.templates)) {
const rawTemplate = this.rawTemplates[name]; const rawTemplate = this.rawTemplates[name];
if (rawTemplate === undefined) { if (rawTemplate === undefined) {
let extraInfo = ""; throw new Error(`Missing template: "${name}"`);
try {
const componentName = getCurrent().component.constructor.name;
extraInfo = ` (for component "${componentName}")`;
} catch {}
throw new Error(`Missing template: "${name}"${extraInfo}`);
} }
const templateFn = this._compileTemplate(name, rawTemplate); const templateFn = this._compileTemplate(name, rawTemplate);
// first add a function to lazily get the template, in case there is a // first add a function to lazily get the template, in case there is a
@@ -120,7 +103,7 @@ export class TemplateSet {
this.templates[name] = function (context, parent) { this.templates[name] = function (context, parent) {
return templates[name].call(this, 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; this.templates[name] = template;
} }
return this.templates[name]; return this.templates[name];
@@ -135,3 +118,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 -1
View File
@@ -139,7 +139,7 @@ export function updateClass(this: HTMLElement, val: any, oldVal: any) {
export function makePropSetter(name: string): Setter<HTMLElement> { export function makePropSetter(name: string): Setter<HTMLElement> {
return function setProp(this: HTMLElement, value: any) { return function setProp(this: HTMLElement, value: any) {
(this as any)[name] = value || ""; (this as any)[name] = value;
}; };
} }
+23 -47
View File
@@ -299,13 +299,12 @@ interface BlockCtx {
locations: IndexedLocation[]; locations: IndexedLocation[];
children: Child[]; children: Child[];
cbRefs: number[]; cbRefs: number[];
refList: (() => void)[][];
} }
function buildContext(tree: IntermediateTree, ctx?: BlockCtx, fromIdx?: number): BlockCtx { function buildContext(tree: IntermediateTree, ctx?: BlockCtx, fromIdx?: number): BlockCtx {
if (!ctx) { if (!ctx) {
const children = new Array(tree.info.filter((v) => v.type === "child").length); 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; fromIdx = 0;
} }
if (tree.refN) { if (tree.refN) {
@@ -409,11 +408,11 @@ function updateCtx(ctx: BlockCtx, tree: IntermediateTree) {
break; break;
} }
case "ref": case "ref":
const index = ctx.cbRefs.push(info.idx) - 1; ctx.cbRefs.push(info.idx);
ctx.locations.push({ ctx.locations.push({
idx: info.idx, idx: info.idx,
refIdx: info.refIdx!, refIdx: info.refIdx!,
setData: makeRefSetter(index, ctx.refList), setData: setRef,
updateData: NO_OP, updateData: NO_OP,
}); });
} }
@@ -427,21 +426,12 @@ function buildBlock(template: HTMLElement, ctx: BlockCtx): BlockType {
let B = createBlockClass(template, ctx); let B = createBlockClass(template, ctx);
if (ctx.cbRefs.length) { if (ctx.cbRefs.length) {
const cbRefs = ctx.cbRefs; const refs = ctx.cbRefs;
const refList = ctx.refList;
let cbRefsNumber = cbRefs.length;
B = class extends B { 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() { remove() {
super.remove(); super.remove();
for (let cbRef of cbRefs) { for (let ref of refs) {
let fn = (this as any).data[cbRef]; let fn = (this as any).data[ref];
fn(null); fn(null);
} }
} }
@@ -486,12 +476,12 @@ function createBlockClass(template: HTMLElement, ctx: BlockCtx): BlockClass {
const nodeInsertBefore = nodeProto.insertBefore; const nodeInsertBefore = nodeProto.insertBefore;
const elementRemove = elementProto.remove; const elementRemove = elementProto.remove;
class Block { return class Block {
el: HTMLElement | undefined; el: HTMLElement | undefined;
parentEl?: HTMLElement | undefined;
data: any[] | undefined;
children?: (VNode | undefined)[];
refs: Node[] | undefined; refs: Node[] | undefined;
data: any[] | undefined;
parentEl?: HTMLElement | undefined;
children?: (VNode | undefined)[];
constructor(data?: any[]) { constructor(data?: any[]) {
this.data = data; this.data = data;
@@ -512,24 +502,10 @@ function createBlockClass(template: HTMLElement, ctx: BlockCtx): BlockClass {
nodeInsertBefore.call(this.parentEl, this.el!, target); 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) { 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); const el = nodeCloneNode.call(template, true);
nodeInsertBefore.call(parent, el, afterNode);
if (isDynamic) {
// collecting references // collecting references
const refs: Node[] = new Array(refN); const refs: Node[] = new Array(refN);
this.refs = refs; this.refs = refs;
@@ -548,8 +524,6 @@ function createBlockClass(template: HTMLElement, ctx: BlockCtx): BlockClass {
} }
} }
nodeInsertBefore.call(parent, el, afterNode);
// preparing all children // preparing all children
if (childN) { if (childN) {
const children = this.children; const children = this.children;
@@ -563,11 +537,11 @@ function createBlockClass(template: HTMLElement, ctx: BlockCtx): BlockClass {
} }
} }
} }
}
this.el = el as HTMLElement; this.el = el as HTMLElement;
this.parentEl = parent; this.parentEl = parent;
}; }
patch(other: Block, withBeforeRemove: boolean) {
Block.prototype.patch = function patch(other: Block, withBeforeRemove: boolean) {
if (this === other) { if (this === other) {
return; 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) { function setText(this: Text, value: any) {
characterDataSetData.call(this, toText(value)); characterDataSetData.call(this, toText(value));
} }
function makeRefSetter(index: number, refs: (() => void)[][]): Setter<HTMLElement> { function setRef(this: HTMLElement, fn: any) {
return function setRef(this: HTMLElement, fn: any) { fn(this);
refs[refs.length - 1][index] = () => 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 { interface EventHandlerCreator {
setup: EventHandlerSetter; setup: EventHandlerSetter;
update: EventHandlerSetter; update: EventHandlerSetter;
remove: (this: HTMLElement) => void;
} }
export function createEventHandler(rawEvent: string): EventHandlerCreator { export function createEventHandler(rawEvent: string): EventHandlerCreator {
@@ -39,15 +38,11 @@ function createElementHandler(evName: string, capture: boolean = false): EventHa
this.addEventListener(evName, listener, { capture }); 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) { function update(this: HTMLElement, data: any) {
(this as any)[eventKey] = data; (this as any)[eventKey] = data;
} }
return { setup, update, remove }; return { setup, update };
} }
// Synthetic handler: a form of event delegation that allows placing only one // 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; _data[currentId] = data;
(this as any)[eventKey] = _data; (this as any)[eventKey] = _data;
} }
return { setup, update: setup };
function remove(this: HTMLElement) {
delete (this as any)[eventKey];
}
return { setup, update: setup, remove };
} }
function nativeToSyntheticEvent(eventKey: string, event: Event) { function nativeToSyntheticEvent(eventKey: string, event: Event) {
-1
View File
@@ -6,7 +6,6 @@ export { list } from "./list";
export { multi } from "./multi"; export { multi } from "./multi";
export { text, comment } from "./text"; export { text, comment } from "./text";
export { html } from "./html"; export { html } from "./html";
export { createCatcher } from "./event_catcher";
export interface VNode<T = any> { export interface VNode<T = any> {
mount(parent: HTMLElement, afterNode: Node | null): void; 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; const nodeRemoveChild = nodeProto.removeChild;
abstract class VSimpleNode { abstract class VSimpleNode {
text: string | String; text: string;
parentEl?: HTMLElement | undefined; parentEl?: HTMLElement | undefined;
el?: any; el?: any;
constructor(text: string | String) { constructor(text: string) {
this.text = text; this.text = text;
} }
@@ -65,7 +65,7 @@ class VComment extends VSimpleNode {
patch() {} patch() {}
} }
export function text(str: string | String): VNode<VText> { export function text(str: string): VNode<VText> {
return new VText(str); return new VText(str);
} }
+82 -136
View File
@@ -20,8 +20,6 @@ import {
ASTTranslation, ASTTranslation,
ASTType, ASTType,
ASTTPortal, ASTTPortal,
EventHandlers,
Attrs,
} from "./parser"; } from "./parser";
type BlockType = "block" | "text" | "multi" | "list" | "html" | "comment"; type BlockType = "block" | "text" | "multi" | "list" | "html" | "comment";
@@ -159,11 +157,9 @@ class CodeTarget {
// maps ref name to [id, expr] // maps ref name to [id, expr]
refInfo: { [name: string]: [string, string] } = {}; refInfo: { [name: string]: [string, string] } = {};
shouldProtectScope: boolean = false; shouldProtectScope: boolean = false;
on: EventHandlers | null;
constructor(name: string, on?: EventHandlers | null) { constructor(name: string) {
this.name = name; this.name = name;
this.on = on || null;
} }
addLine(line: string, idx?: number) { addLine(line: string, idx?: number) {
@@ -218,24 +214,14 @@ export class CodeGenerator {
templateName?: string; templateName?: string;
dev: boolean; dev: boolean;
translateFn: (s: string) => string; translateFn: (s: string) => string;
translatableAttributes: string[] = TRANSLATABLE_ATTRS; translatableAttributes: string[];
ast: AST; ast: AST;
staticDefs: { id: string; expr: string }[] = []; staticCalls: { id: string; template: string }[] = [];
helpers: Set<string> = new Set(); helpers: Set<string> = new Set();
constructor(ast: AST, options: CodeGenOptions) { constructor(ast: AST, options: CodeGenOptions) {
this.translateFn = options.translateFn || ((s: string) => s); this.translateFn = options.translateFn || ((s: string) => s);
if (options.translatableAttributes) { this.translatableAttributes = options.translatableAttributes || TRANSLATABLE_ATTRS;
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.hasSafeContext = options.hasSafeContext || false; this.hasSafeContext = options.hasSafeContext || false;
this.dev = options.dev || false; this.dev = options.dev || false;
this.ast = ast; this.ast = ast;
@@ -266,8 +252,8 @@ export class CodeGenerator {
mainCode.push(`// Template name: "${this.templateName}"`); mainCode.push(`// Template name: "${this.templateName}"`);
} }
for (let { id, expr } of this.staticDefs) { for (let { id, template } of this.staticCalls) {
mainCode.push(`const ${id} = ${expr};`); mainCode.push(`const ${id} = getTemplate(${template});`);
} }
// define all blocks // define all blocks
@@ -307,23 +293,20 @@ export class CodeGenerator {
return code; 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 name = this.generateId(prefix);
const initialTarget = this.target; const initialTarget = this.target;
const target = new CodeTarget(name, on); const target = new CodeTarget(name);
this.targets.push(target); this.targets.push(target);
this.target = target; this.target = target;
this.compileAST(ast, createContext(ctx)); const subCtx: Context = createContext(ctx);
this.compileAST(ast, subCtx);
this.target = initialTarget; this.target = initialTarget;
return name; return name;
} }
addLine(line: string, idx?: number) { addLine(line: string) {
this.target.addLine(line, idx); this.target.addLine(line);
}
define(varName: string, expr: string) {
this.addLine(`const ${varName} = ${expr};`);
} }
generateId(prefix: string = ""): string { generateId(prefix: string = ""): string {
@@ -375,12 +358,9 @@ export class CodeGenerator {
} }
if (block.isRoot && !ctx.preventRoot) { if (block.isRoot && !ctx.preventRoot) {
if (this.target.on) {
blockExpr = this.wrapWithEventCatcher(blockExpr, this.target.on);
}
this.addLine(`return ${blockExpr};`); this.addLine(`return ${blockExpr};`);
} else { } else {
this.define(block.varName, blockExpr); this.addLine(`let ${block.varName} = ${blockExpr};`);
} }
} }
@@ -409,7 +389,7 @@ export class CodeGenerator {
if (!mapping.has(tok.varName)) { if (!mapping.has(tok.varName)) {
const varId = this.generateId("v"); const varId = this.generateId("v");
mapping.set(tok.varName, varId); mapping.set(tok.varName, varId);
this.define(varId, tok.value); this.addLine(`const ${varId} = ${tok.value};`);
} }
tok.value = mapping.get(tok.varName)!; tok.value = mapping.get(tok.varName)!;
} }
@@ -554,12 +534,12 @@ export class CodeGenerator {
this.blocks.push(block); this.blocks.push(block);
if (ast.dynamicTag) { if (ast.dynamicTag) {
const tagExpr = this.generateId("tag"); const tagExpr = this.generateId("tag");
this.define(tagExpr, compileExpr(ast.dynamicTag)); this.addLine(`let ${tagExpr} = ${compileExpr(ast.dynamicTag)};`);
block.dynamicTagName = tagExpr; block.dynamicTagName = tagExpr;
} }
} }
// attributes // attributes
const attrs: Attrs = {}; const attrs: { [key: string]: string } = {};
const nameSpace = ast.ns || ctx.nameSpace; const nameSpace = ast.ns || ctx.nameSpace;
if (nameSpace && isNewBlock) { if (nameSpace && isNewBlock) {
// specific namespace uri // specific namespace uri
@@ -649,11 +629,11 @@ export class CodeGenerator {
const baseExpression = compileExpr(baseExpr); const baseExpression = compileExpr(baseExpr);
const bExprId = this.generateId("bExpr"); const bExprId = this.generateId("bExpr");
this.define(bExprId, baseExpression); this.addLine(`const ${bExprId} = ${baseExpression};`);
const expression = compileExpr(expr); const expression = compileExpr(expr);
const exprId = this.generateId("expr"); const exprId = this.generateId("expr");
this.define(exprId, expression); this.addLine(`const ${exprId} = ${expression};`);
const fullExpression = `${bExprId}[${exprId}]`; const fullExpression = `${bExprId}[${exprId}]`;
@@ -664,7 +644,7 @@ export class CodeGenerator {
} else if (hasDynamicChildren) { } else if (hasDynamicChildren) {
const bValueId = this.generateId("bValue"); const bValueId = this.generateId("bValue");
tModelSelectedExpr = `${bValueId}`; tModelSelectedExpr = `${bValueId}`;
this.define(tModelSelectedExpr, fullExpression); this.addLine(`let ${tModelSelectedExpr} = ${fullExpression}`);
} else { } else {
idx = block!.insertData(`${fullExpression}`, "attr"); idx = block!.insertData(`${fullExpression}`, "attr");
attrs[`block-attribute-${idx}`] = targetAttr; attrs[`block-attribute-${idx}`] = targetAttr;
@@ -714,13 +694,13 @@ export class CodeGenerator {
const children = block!.children.slice(); const children = block!.children.slice();
let current = children.shift(); let current = children.shift();
for (let i = codeIdx; i < code.length; i++) { for (let i = codeIdx; i < code.length; i++) {
if (code[i].trimStart().startsWith(`const ${current!.varName} `)) { if (code[i].trimStart().startsWith(`let ${current!.varName} `)) {
code[i] = code[i].replace(`const ${current!.varName}`, current!.varName); code[i] = code[i].replace(`let ${current!.varName}`, current!.varName);
current = children.shift(); current = children.shift();
if (!current) break; 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 +789,13 @@ export class CodeGenerator {
const children = block!.children.slice(); const children = block!.children.slice();
let current = children.shift(); let current = children.shift();
for (let i = codeIdx; i < code.length; i++) { for (let i = codeIdx; i < code.length; i++) {
if (code[i].trimStart().startsWith(`const ${current!.varName} `)) { if (code[i].trimStart().startsWith(`let ${current!.varName} `)) {
code[i] = code[i].replace(`const ${current!.varName}`, current!.varName); code[i] = code[i].replace(`let ${current!.varName}`, current!.varName);
current = children.shift(); current = children.shift();
if (!current) break; 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: // note: this part is duplicated from end of compilemulti:
@@ -838,10 +818,12 @@ export class CodeGenerator {
const l = `l_block${block.id}`; const l = `l_block${block.id}`;
const c = `c_block${block.id}`; const c = `c_block${block.id}`;
this.helpers.add("prepareList"); 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 // Throw errors on duplicate keys in dev mode
if (this.dev) { 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.addLine(`for (let ${loopVar} = 0; ${loopVar} < ${l}; ${loopVar}++) {`);
this.target.indentLevel++; this.target.indentLevel++;
@@ -858,7 +840,7 @@ export class CodeGenerator {
if (!ast.hasNoValue) { if (!ast.hasNoValue) {
this.addLine(`ctx[\`${ast.elem}_value\`] = ${keys}[${loopVar}];`); 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) { if (this.dev) {
// Throw error on duplicate keys in dev mode // Throw error on duplicate keys in dev mode
this.addLine( this.addLine(
@@ -870,8 +852,8 @@ export class CodeGenerator {
if (ast.memo) { if (ast.memo) {
this.target.hasCache = true; this.target.hasCache = true;
id = this.generateId(); id = this.generateId();
this.define(`memo${id}`, compileExpr(ast.memo)); this.addLine(`let memo${id} = ${compileExpr(ast.memo)}`);
this.define(`vnode${id}`, `cache[key${this.target.loopLevel}];`); this.addLine(`let vnode${id} = cache[key${this.target.loopLevel}];`);
this.addLine(`if (vnode${id}) {`); this.addLine(`if (vnode${id}) {`);
this.target.indentLevel++; this.target.indentLevel++;
this.addLine(`if (shallowEqual(vnode${id}.memo, memo${id})) {`); this.addLine(`if (shallowEqual(vnode${id}.memo, memo${id})) {`);
@@ -905,7 +887,7 @@ export class CodeGenerator {
compileTKey(ast: ASTTKey, ctx: Context) { compileTKey(ast: ASTTKey, ctx: Context) {
const tKeyExpr = this.generateId("tKey_"); const tKeyExpr = this.generateId("tKey_");
this.define(tKeyExpr, compileExpr(ast.expr)); this.addLine(`const ${tKeyExpr} = ${compileExpr(ast.expr)};`);
ctx = createContext(ctx, { ctx = createContext(ctx, {
tKeyExpr, tKeyExpr,
block: ctx.block, block: ctx.block,
@@ -951,13 +933,13 @@ export class CodeGenerator {
const children = block!.children.slice(); const children = block!.children.slice();
let current = children.shift(); let current = children.shift();
for (let i = codeIdx; i < code.length; i++) { for (let i = codeIdx; i < code.length; i++) {
if (code[i].trimStart().startsWith(`const ${current!.varName} `)) { if (code[i].trimStart().startsWith(`let ${current!.varName} `)) {
code[i] = code[i].replace(`const ${current!.varName}`, current!.varName); code[i] = code[i].replace(`let ${current!.varName}`, current!.varName);
current = children.shift(); current = children.shift();
if (!current) break; 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 +972,7 @@ export class CodeGenerator {
const key = `key + \`${this.generateComponentKey()}\``; const key = `key + \`${this.generateComponentKey()}\``;
if (isDynamic) { if (isDynamic) {
const templateVar = this.generateId("template"); const templateVar = this.generateId("template");
this.define(templateVar, subTemplate); this.addLine(`const ${templateVar} = ${subTemplate};`);
block = this.createBlock(block, "multi", ctx); block = this.createBlock(block, "multi", ctx);
this.helpers.add("call"); this.helpers.add("call");
this.insertBlock(`call(this, ${templateVar}, ctx, node, ${key})`, block!, { this.insertBlock(`call(this, ${templateVar}, ctx, node, ${key})`, block!, {
@@ -1000,7 +982,7 @@ export class CodeGenerator {
} else { } else {
const id = this.generateId(`callTemplate_`); const id = this.generateId(`callTemplate_`);
this.helpers.add("getTemplate"); this.helpers.add("getTemplate");
this.staticDefs.push({ id, expr: `getTemplate(${subTemplate})` }); this.staticCalls.push({ id, template: subTemplate });
block = this.createBlock(block, "multi", ctx); block = this.createBlock(block, "multi", ctx);
this.insertBlock(`${id}.call(this, ctx, node, ${key})`, block!, { this.insertBlock(`${id}.call(this, ctx, node, ${key})`, block!, {
...ctx, ...ctx,
@@ -1058,71 +1040,54 @@ export class CodeGenerator {
return parts.join("__"); return parts.join("__");
} }
/** compileComponent(ast: ASTComponent, ctx: Context) {
* Formats a prop name and value into a string suitable to be inserted in the let { block } = ctx;
* generated code. For example:
* // props
* Name Value Result const props: string[] = [];
* --------------------------------------------------------- let hasSlotsProp = false;
* "number" "state" "number: ctx['state']" for (let propName in ast.props) {
* "something" "" "something: undefined" let propValue = this.captureExpression(ast.props[propName]) || undefined;
* "some-prop" "state" "'some-prop': ctx['state']" if (propName.includes(".")) {
* "onClick.bind" "onClick" "onClick: bind(ctx, ctx['onClick'])" let [name, suffix] = propName.split(".");
*/
formatProp(name: string, value: string): string {
value = this.captureExpression(value);
if (name.includes(".")) {
let [_name, suffix] = name.split(".");
if (suffix === "bind") { if (suffix === "bind") {
this.helpers.add("bind"); this.helpers.add("bind");
name = _name; propName = name;
value = `bind(ctx, ${value || undefined})`; propValue = `bind(ctx, ${propValue})`;
} else { } else {
throw new Error("Invalid prop suffix"); throw new Error("Invalid prop suffix");
} }
} }
name = /^[a-z_]+$/i.test(name) ? name : `'${name}'`; propName = /^[a-z_]+$/i.test(propName) ? propName : `'${propName}'`;
return `${name}: ${value || undefined}`; props.push(`${propName}: ${propValue}`);
if (propName === "slots") {
hasSlotsProp = true;
} }
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);
} }
// slots // slots
const hasSlot = !!Object.keys(ast.slots).length;
let slotDef: string = ""; let slotDef: string = "";
if (ast.slots) { if (hasSlot) {
let ctxStr = "ctx"; let ctxStr = "ctx";
if (this.target.loopLevel || !this.hasSafeContext) { if (this.target.loopLevel || !this.hasSafeContext) {
ctxStr = this.generateId("ctx"); ctxStr = this.generateId("ctx");
this.helpers.add("capture"); this.helpers.add("capture");
this.define(ctxStr, `capture(ctx)`); this.addLine(`const ${ctxStr} = capture(ctx);`);
} }
let slotStr: string[] = []; let slotStr: string[] = [];
for (let slotName in ast.slots) { for (let slotName in ast.slots) {
const slotAst = ast.slots[slotName]; const slotAst = ast.slots[slotName].content;
const name = this.compileInNewTarget("slot", slotAst.content, ctx, slotAst.on); const name = this.compileInNewTarget("slot", slotAst, ctx);
const params = [`__render: ${name}, __ctx: ${ctxStr}`]; const params = [`__render: ${name}, __ctx: ${ctxStr}`];
const scope = ast.slots[slotName].scope; const scope = ast.slots[slotName].scope;
if (scope) { if (scope) {
params.push(`__scope: "${scope}"`); params.push(`__scope: "${scope}"`);
} }
if (ast.slots[slotName].attrs) { 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(", ")}}`; const slotInfo = `{${params.join(", ")}}`;
slotStr.push(`'${slotName}': ${slotInfo}`); slotStr.push(`'${slotName}': ${slotInfo}`);
@@ -1131,29 +1096,29 @@ export class CodeGenerator {
} }
if (slotDef && !(ast.dynamicProps || hasSlotsProp)) { if (slotDef && !(ast.dynamicProps || hasSlotsProp)) {
this.helpers.add("markRaw"); props.push(`slots: ${slotDef}`);
props.push(`slots: markRaw(${slotDef})`);
} }
const propStr = `{${props.join(",")}}`; const propStr = `{${props.join(",")}}`;
let propString = propStr; let propString = propStr;
if (ast.dynamicProps) { if (ast.dynamicProps) {
propString = `Object.assign({}, ${compileExpr(ast.dynamicProps)}${ if (!props.length) {
props.length ? ", " + propStr : "" propString = `Object.assign({}, ${compileExpr(ast.dynamicProps)})`;
})`; } else {
propString = `Object.assign({}, ${compileExpr(ast.dynamicProps)}, ${propStr})`;
}
} }
let propVar: string; let propVar: string;
if ((slotDef && (ast.dynamicProps || hasSlotsProp)) || this.dev) { if ((slotDef && (ast.dynamicProps || hasSlotsProp)) || this.dev) {
propVar = this.generateId("props"); propVar = this.generateId("props");
this.define(propVar!, propString); this.addLine(`const ${propVar!} = ${propString};`);
propString = propVar!; propString = propVar!;
} }
if (slotDef && (ast.dynamicProps || hasSlotsProp)) { if (slotDef && (ast.dynamicProps || hasSlotsProp)) {
this.helpers.add("markRaw"); this.addLine(`${propVar!}.slots = Object.assign(${slotDef}, ${propVar!}.slots)`);
this.addLine(`${propVar!}.slots = markRaw(Object.assign(${slotDef}, ${propVar!}.slots))`);
} }
// cmap key // cmap key
@@ -1161,7 +1126,7 @@ export class CodeGenerator {
let expr: string; let expr: string;
if (ast.isDynamic) { if (ast.isDynamic) {
expr = this.generateId("Comp"); expr = this.generateId("Comp");
this.define(expr, compileExpr(ast.name)); this.addLine(`let ${expr} = ${compileExpr(ast.name)};`);
} else { } else {
expr = `\`${ast.name}\``; expr = `\`${ast.name}\``;
} }
@@ -1184,32 +1149,10 @@ export class CodeGenerator {
if (ast.isDynamic) { if (ast.isDynamic) {
blockExpr = `toggler(${expr}, ${blockExpr})`; blockExpr = `toggler(${expr}, ${blockExpr})`;
} }
// event handling
if (ast.on) {
blockExpr = this.wrapWithEventCatcher(blockExpr, ast.on);
}
block = this.createBlock(block, "multi", ctx); block = this.createBlock(block, "multi", ctx);
this.insertBlock(blockExpr, block, 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) { compileTSlot(ast: ASTSlot, ctx: Context) {
this.helpers.add("callSlot"); this.helpers.add("callSlot");
let { block } = ctx; let { block } = ctx;
@@ -1223,24 +1166,27 @@ export class CodeGenerator {
slotName = "'" + ast.name + "'"; 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) { if (ast.defaultContent) {
const name = this.compileInNewTarget("defaultContent", ast.defaultContent, ctx); const name = this.compileInNewTarget("defaultContent", ast.defaultContent, ctx);
blockString = `callSlot(ctx, node, key, ${slotName}, ${dynamic}, ${scope}, ${name})`; blockString = `callSlot(ctx, node, key, ${slotName}, ${dynamic}, ${scope}, ${name})`;
} else { } else {
if (dynamic) { if (dynamic) {
let name = this.generateId("slot"); let name = this.generateId("slot");
this.define(name, slotName); this.addLine(`const ${name} = ${slotName};`);
blockString = `toggler(${name}, callSlot(ctx, node, key, ${name}), ${dynamic}, ${scope})`; blockString = `toggler(${name}, callSlot(ctx, node, key, ${name}), ${dynamic}, ${scope})`;
} else { } else {
blockString = `callSlot(ctx, node, key, ${slotName}, ${dynamic}, ${scope})`; blockString = `callSlot(ctx, node, key, ${slotName}, ${dynamic}, ${scope})`;
} }
} }
// event handling
if (ast.on) {
blockString = this.wrapWithEventCatcher(blockString, ast.on);
}
if (block) { if (block) {
this.insertAnchor(block); this.insertAnchor(block);
} }
@@ -1263,7 +1209,7 @@ export class CodeGenerator {
if (this.target.loopLevel || !this.hasSafeContext) { if (this.target.loopLevel || !this.hasSafeContext) {
ctxStr = this.generateId("ctx"); ctxStr = this.generateId("ctx");
this.helpers.add("capture"); 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)`; const blockString = `component(Portal, {target: ${ast.target},slots: {'default': {__render: ${name}, __ctx: ${ctxStr}}}}, key + \`${key}\`, node, ctx)`;
if (block) { if (block) {
+6 -12
View File
@@ -199,18 +199,15 @@ const TOKENIZERS = [
export function tokenize(expr: string): Token[] { export function tokenize(expr: string): Token[] {
const result: Token[] = []; const result: Token[] = [];
let token: boolean | Token = true; let token: boolean | Token = true;
let error: any;
let current = expr;
try {
while (token) { while (token) {
current = current.trim(); expr = expr.trim();
if (current) { if (expr) {
for (let tokenizer of TOKENIZERS) { for (let tokenizer of TOKENIZERS) {
token = tokenizer(current); token = tokenizer(expr);
if (token) { if (token) {
result.push(token); result.push(token);
current = current.slice(token.size || token.value.length); expr = expr.slice(token.size || token.value.length);
break; break;
} }
} }
@@ -218,11 +215,8 @@ export function tokenize(expr: string): Token[] {
token = false; token = false;
} }
} }
} catch (e) { if (expr.length) {
error = e; // Silence all errors and throw a generic error below throw new Error(`Tokenizer error: could not tokenize "${expr}"`);
}
if (current.length || error) {
throw new Error(`Tokenizer error: could not tokenize \`${expr}\``);
} }
return result; return result;
} }
+27 -69
View File
@@ -2,9 +2,6 @@
// AST Type definition // AST Type definition
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
export type EventHandlers = { [eventName: string]: string };
export type Attrs = { [attrs: string]: string };
export const enum ASTType { export const enum ASTType {
Text, Text,
Comment, Comment,
@@ -37,25 +34,25 @@ export interface ASTComment {
} }
interface TModelInfo { interface TModelInfo {
hasDynamicChildren?: boolean;
baseExpr: string; baseExpr: string;
expr: string; expr: string;
targetAttr: string; targetAttr: string;
specialInitTargetAttr: string | null;
eventType: "change" | "click" | "input"; eventType: "change" | "click" | "input";
shouldTrim: boolean; shouldTrim: boolean;
shouldNumberize: boolean; shouldNumberize: boolean;
hasDynamicChildren: boolean;
specialInitTargetAttr: string | null;
} }
export interface ASTDomNode { export interface ASTDomNode {
type: ASTType.DomNode; type: ASTType.DomNode;
tag: string; tag: string;
content: AST[];
attrs: Attrs | null;
ref: string | null;
on: EventHandlers | null;
model: TModelInfo | null;
dynamicTag: string | null; dynamicTag: string | null;
attrs: { [key: string]: string };
content: AST[];
ref: string | null;
on: { [key: string]: string };
model?: TModelInfo | null;
ns: string | null; ns: string | null;
} }
@@ -96,13 +93,13 @@ export interface ASTTForEach {
type: ASTType.TForEach; type: ASTType.TForEach;
collection: string; collection: string;
elem: string; elem: string;
key: string | null;
body: AST; body: AST;
memo: string; memo: string;
hasNoFirst: boolean; hasNoFirst: boolean;
hasNoLast: boolean; hasNoLast: boolean;
hasNoIndex: boolean; hasNoIndex: boolean;
hasNoValue: boolean; hasNoValue: boolean;
key: string | null;
} }
export interface ASTTKey { export interface ASTTKey {
@@ -117,28 +114,19 @@ export interface ASTTCall {
body: AST[] | null; body: AST[] | null;
} }
interface SlotDefinition {
content: AST;
scope: string | null;
on: EventHandlers | null;
attrs: Attrs | null;
}
export interface ASTComponent { export interface ASTComponent {
type: ASTType.TComponent; type: ASTType.TComponent;
name: string; name: string;
isDynamic: boolean; isDynamic: boolean;
dynamicProps: string | null; dynamicProps: string | null;
on: EventHandlers | null; props: { [name: string]: string };
props: { [name: string]: string } | null; slots: { [name: string]: { content: AST; attrs?: { [key: string]: string }; scope?: string } };
slots: { [name: string]: SlotDefinition } | null;
} }
export interface ASTSlot { export interface ASTSlot {
type: ASTType.TSlot; type: ASTType.TSlot;
name: string; name: string;
attrs: Attrs | null; attrs: { [key: string]: string };
on: EventHandlers | null;
defaultContent: AST | null; defaultContent: AST | null;
} }
@@ -317,9 +305,6 @@ function parseDOMNode(node: Element, ctx: ParsingContext): AST | null {
if (tagName === "t" && !dynamicTag) { if (tagName === "t" && !dynamicTag) {
return null; return null;
} }
if (tagName.startsWith("block-")) {
throw new Error(`Invalid tag name: '${tagName}'`);
}
ctx = Object.assign({}, ctx); ctx = Object.assign({}, ctx);
if (tagName === "pre") { if (tagName === "pre") {
ctx.inPreTag = true; ctx.inPreTag = true;
@@ -331,8 +316,8 @@ function parseDOMNode(node: Element, ctx: ParsingContext): AST | null {
node.removeAttribute("t-ref"); node.removeAttribute("t-ref");
const nodeAttrsNames = node.getAttributeNames(); const nodeAttrsNames = node.getAttributeNames();
let attrs: ASTDomNode["attrs"] = null; const attrs: ASTDomNode["attrs"] = {};
let on: EventHandlers | null = null; const on: ASTDomNode["on"] = {};
let model: TModelInfo | null = null; let model: TModelInfo | null = null;
for (let attr of nodeAttrsNames) { for (let attr of nodeAttrsNames) {
@@ -341,7 +326,6 @@ function parseDOMNode(node: Element, ctx: ParsingContext): AST | null {
if (attr === "t-on") { if (attr === "t-on") {
throw new Error("Missing event name with t-on directive"); throw new Error("Missing event name with t-on directive");
} }
on = on || {};
on[attr.slice(5)] = value; on[attr.slice(5)] = value;
} else if (attr.startsWith("t-model")) { } else if (attr.startsWith("t-model")) {
if (!["input", "select", "textarea"].includes(tagName)) { if (!["input", "select", "textarea"].includes(tagName)) {
@@ -379,7 +363,6 @@ function parseDOMNode(node: Element, ctx: ParsingContext): AST | null {
targetAttr: isCheckboxInput ? "checked" : "value", targetAttr: isCheckboxInput ? "checked" : "value",
specialInitTargetAttr: isRadioInput ? "checked" : null, specialInitTargetAttr: isRadioInput ? "checked" : null,
eventType, eventType,
hasDynamicChildren: false,
shouldTrim: hasTrimMod && (isOtherInput || isTextarea), shouldTrim: hasTrimMod && (isOtherInput || isTextarea),
shouldNumberize: hasNumberMod && (isOtherInput || isTextarea), shouldNumberize: hasNumberMod && (isOtherInput || isTextarea),
}; };
@@ -388,8 +371,6 @@ function parseDOMNode(node: Element, ctx: ParsingContext): AST | null {
ctx = Object.assign({}, ctx); ctx = Object.assign({}, ctx);
ctx.tModelInfo = model; ctx.tModelInfo = model;
} }
} else if (attr.startsWith("block-")) {
throw new Error(`Invalid attribute: '${attr}'`);
} else if (attr !== "t-name") { } else if (attr !== "t-name") {
if (attr.startsWith("t-") && !attr.startsWith("t-att")) { if (attr.startsWith("t-") && !attr.startsWith("t-att")) {
throw new Error(`Unknown QWeb directive: '${attr}'`); throw new Error(`Unknown QWeb directive: '${attr}'`);
@@ -398,7 +379,6 @@ function parseDOMNode(node: Element, ctx: ParsingContext): AST | null {
if (tModel && ["t-att-value", "t-attf-value"].includes(attr)) { if (tModel && ["t-att-value", "t-attf-value"].includes(attr)) {
tModel.hasDynamicChildren = true; tModel.hasDynamicChildren = true;
} }
attrs = attrs || {};
attrs[attr] = value; attrs[attr] = value;
} }
} }
@@ -569,7 +549,7 @@ function parseTCall(node: Element, ctx: ParsingContext): AST | null {
if (ast && ast.type === ASTType.TComponent) { if (ast && ast.type === ASTType.TComponent) {
return { return {
...ast, ...ast,
slots: { default: { content: tcall, scope: null, on: null, attrs: null } }, slots: { default: { content: tcall } },
}; };
} }
} }
@@ -665,6 +645,7 @@ function parseTSetNode(node: Element, ctx: ParsingContext): AST | null {
// Error messages when trying to use an unsupported directive on a component // Error messages when trying to use an unsupported directive on a component
const directiveErrorMap = new Map([ const directiveErrorMap = new Map([
["t-on", "t-on is no longer supported on components. Consider passing a callback in props."],
[ [
"t-ref", "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.", "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 +677,18 @@ function parseComponent(node: Element, ctx: ParsingContext): AST | null {
const dynamicProps = node.getAttribute("t-props"); const dynamicProps = node.getAttribute("t-props");
node.removeAttribute("t-props"); node.removeAttribute("t-props");
const defaultSlotScope = node.getAttribute("t-slot-scope"); const props: ASTComponent["props"] = {};
node.removeAttribute("t-slot-scope");
let on: ASTComponent["on"] = null;
let props: ASTComponent["props"] = null;
for (let name of node.getAttributeNames()) { for (let name of node.getAttributeNames()) {
const value = node.getAttribute(name)!; const value = node.getAttribute(name)!;
if (name.startsWith("t-")) { 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("-")); const message = directiveErrorMap.get(name.split("-").slice(0, 2).join("-"));
throw new Error(message || `unsupported directive on Component: ${name}`); throw new Error(message || `unsupported directive on Component: ${name}`);
}
} else { } else {
props = props || {};
props[name] = value; props[name] = value;
} }
} }
let slots: ASTComponent["slots"] | null = null; const slots: ASTComponent["slots"] = {};
if (node.hasChildNodes()) { if (node.hasChildNodes()) {
const clone = <Element>node.cloneNode(true); const clone = <Element>node.cloneNode(true);
@@ -750,35 +721,30 @@ function parseComponent(node: Element, ctx: ParsingContext): AST | null {
slotNode.remove(); slotNode.remove();
const slotAst = parseNode(slotNode, ctx); const slotAst = parseNode(slotNode, ctx);
if (slotAst) { if (slotAst) {
let on: SlotDefinition["on"] = null; const slotInfo: any = { content: slotAst };
let attrs: Attrs | null = null; const attrs: { [key: string]: string } = {};
let scope: string | null = null;
for (let attributeName of slotNode.getAttributeNames()) { for (let attributeName of slotNode.getAttributeNames()) {
const value = slotNode.getAttribute(attributeName)!; const value = slotNode.getAttribute(attributeName)!;
if (attributeName === "t-slot-scope") { if (attributeName === "t-slot-scope") {
scope = value; slotInfo.scope = value;
continue; continue;
} else if (attributeName.startsWith("t-on-")) { }
on = on || {};
on[attributeName.slice(5)] = value;
} else {
attrs = attrs || {};
attrs[attributeName] = value; attrs[attributeName] = value;
} }
if (Object.keys(attrs).length) {
slotInfo.attrs = attrs;
} }
slots = slots || {}; slots[name] = slotInfo;
slots[name] = { content: slotAst, on, attrs, scope };
} }
} }
// default slot // default slot
const defaultContent = parseChildNodes(clone, ctx); const defaultContent = parseChildNodes(clone, ctx);
if (defaultContent) { if (defaultContent) {
slots = slots || {}; slots.default = { content: defaultContent };
slots.default = { content: defaultContent, on, attrs: null, scope: defaultSlotScope };
} }
} }
return { type: ASTType.TComponent, name, isDynamic, dynamicProps, props, slots, on }; return { type: ASTType.TComponent, name, isDynamic, dynamicProps, props, slots };
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@@ -791,23 +757,15 @@ function parseTSlot(node: Element, ctx: ParsingContext): AST | null {
} }
const name = node.getAttribute("t-slot")!; const name = node.getAttribute("t-slot")!;
node.removeAttribute("t-slot"); node.removeAttribute("t-slot");
let attrs: Attrs | null = null; const attrs: { [key: string]: string } = {};
let on: ASTComponent["on"] = null;
for (let attributeName of node.getAttributeNames()) { for (let attributeName of node.getAttributeNames()) {
const value = node.getAttribute(attributeName)!; 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 { return {
type: ASTType.TSlot, type: ASTType.TSlot,
name, name,
attrs, attrs,
on,
defaultContent: parseChildNodes(node, ctx), defaultContent: parseChildNodes(node, ctx),
}; };
} }
+2 -2
View File
@@ -36,7 +36,7 @@ export class Component<Props = any, Env = any> {
setup() {} setup() {}
render(deep: boolean = false) { render() {
this.__owl__.render(deep); this.__owl__.render();
} }
} }
+13 -104
View File
@@ -1,16 +1,6 @@
import type { App, Env } from "../app/app"; import type { App, Env } from "../app/app";
import { BDom, VNode } from "../blockdom"; import { BDom, VNode } from "../blockdom";
import {
clearReactivesForCallback,
Reactive,
reactive,
TARGET,
NonReactive,
getSubscriptions,
} from "../reactivity";
import { batched, Callback } from "../utils";
import { Component, ComponentConstructor } from "./component"; import { Component, ComponentConstructor } from "./component";
import { fibersInError, handleError } from "./error_handling";
import { import {
Fiber, Fiber,
makeChildFiber, makeChildFiber,
@@ -19,15 +9,13 @@ import {
MountOptions, MountOptions,
RootFiber, RootFiber,
} from "./fibers"; } from "./fibers";
import { handleError, fibersInError } from "./error_handling";
import { applyDefaultProps } from "./props_validation"; import { applyDefaultProps } from "./props_validation";
import { STATUS } from "./status"; import { STATUS } from "./status";
let currentNode: ComponentNode | null = null; let currentNode: ComponentNode | null = null;
export function getCurrent(): ComponentNode { export function getCurrent(): ComponentNode | null {
if (!currentNode) {
throw new Error("No active component (a hook function should only be called in 'setup')");
}
return currentNode; return currentNode;
} }
@@ -35,61 +23,13 @@ export function useComponent(): Component {
return currentNode!.component; return currentNode!.component;
} }
// ----------------------------------------------------------------------------- export function component(
// Integration with reactivity system (useState) name: string | typeof Component,
// ----------------------------------------------------------------------------- props: any,
const batchedRenderFunctions = new WeakMap<ComponentNode, Callback>();
/**
* Creates a reactive object that will be observed by the current component.
* Reading data from the returned object (eg during rendering) will cause the
* component to subscribe to that data and be rerendered when it changes.
*
* @param state the state to observe
* @returns a reactive object that will cause the component to re-render on
* relevant changes
* @see reactive
*/
export function useState<T extends object>(state: T): Reactive<T> | NonReactive<T> {
const node = getCurrent();
let render = batchedRenderFunctions.get(node)!;
if (!render) {
render = batched(node.render.bind(node));
batchedRenderFunctions.set(node, render);
// manual implementation of onWillDestroy to break cyclic dependency
node.willDestroy.push(clearReactivesForCallback.bind(null, render));
if (node.app.dev) {
Object.defineProperty(node, "subscriptions", {
get() {
return getSubscriptions(render);
},
});
}
}
return reactive(state, render);
}
// -----------------------------------------------------------------------------
// component function (used in compiled template code)
// -----------------------------------------------------------------------------
type Props = { [key: string]: any };
function arePropsDifferent(props1: Props, props2: Props): boolean {
for (let k in props1) {
if (props1[k] !== props2[k]) {
return true;
}
}
return Object.keys(props1).length !== Object.keys(props2).length;
}
export function component<P extends object>(
name: string | ComponentConstructor<P>,
props: P,
key: string, key: string,
ctx: ComponentNode, ctx: ComponentNode,
parent: any parent: any
): ComponentNode<P> { ): ComponentNode {
let node: any = ctx.children[key]; let node: any = ctx.children[key];
let isDynamic = typeof name !== "string"; let isDynamic = typeof name !== "string";
@@ -107,16 +47,7 @@ export function component<P extends object>(
const parentFiber = ctx.fiber!; const parentFiber = ctx.fiber!;
if (node) { 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) {
node.updateAndRender(props, parentFiber); node.updateAndRender(props, parentFiber);
}
} else { } else {
// new component // new component
let C; let C;
@@ -131,25 +62,25 @@ export function component<P extends object>(
node = new ComponentNode(C, props, ctx.app, ctx); node = new ComponentNode(C, props, ctx.app, ctx);
ctx.children[key] = node; ctx.children[key] = node;
node.initiateRender(new Fiber(node, parentFiber)); const fiber = makeChildFiber(node, parentFiber);
node.initiateRender(fiber);
} }
return node; return node;
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Component VNode class // Component VNode
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
type LifecycleHook = Function; type LifecycleHook = Function;
export class ComponentNode<P extends object = any, E = any> implements VNode<ComponentNode<P, E>> { export class ComponentNode<P = any, E = any> implements VNode<ComponentNode<P, E>> {
el?: HTMLElement | Text | undefined; el?: HTMLElement | Text | undefined;
app: App; app: App;
fiber: Fiber | null = null; fiber: Fiber | null = null;
component: Component<P, E>; component: Component<P, E>;
bdom: BDom | null = null; bdom: BDom | null = null;
status: STATUS = STATUS.NEW; status: STATUS = STATUS.NEW;
forceNextRender: boolean = false;
renderFn: Function; renderFn: Function;
parent: ComponentNode | null; parent: ComponentNode | null;
@@ -174,11 +105,9 @@ export class ComponentNode<P extends object = any, E = any> implements VNode<Com
applyDefaultProps(props, C); applyDefaultProps(props, C);
const env = (parent && parent.childEnv) || app.env; const env = (parent && parent.childEnv) || app.env;
this.childEnv = env; this.childEnv = env;
props = useState(props);
this.component = new C(props, env, this) as any; this.component = new C(props, env, this) as any;
this.renderFn = app.getTemplate(C.template).bind(this.component, this.component, this); this.renderFn = app.getTemplate(C.template).bind(this.component, this.component, this);
this.component.setup(); this.component.setup();
currentNode = null;
} }
mountComponent(target: any, options?: MountOptions) { mountComponent(target: any, options?: MountOptions) {
@@ -204,29 +133,21 @@ export class ComponentNode<P extends object = any, E = any> implements VNode<Com
} }
} }
async render(deep: boolean = false) { async render() {
let current = this.fiber; let current = this.fiber;
if (current && current.root!.locked) { if (current && current.root!.locked) {
await Promise.resolve(); await Promise.resolve();
// situation may have changed after the microtask tick // situation may have changed after the microtask tick
current = this.fiber; current = this.fiber;
} }
if (current) { if (current && !current.bdom && !fibersInError.has(current)) {
if (!current.bdom && !fibersInError.has(current)) {
if (deep) {
// we want the render from this point on to be with deep=true
current.deep = deep;
}
return; return;
} }
// if current rendering was with deep=true, we want this one to be the same if (!this.bdom && !current) {
deep = deep || current.deep;
} else if (!this.bdom) {
return; return;
} }
const fiber = makeRootFiber(this); const fiber = makeRootFiber(this);
fiber.deep = deep;
this.fiber = fiber; this.fiber = fiber;
this.app.scheduler.addFiber(fiber); this.app.scheduler.addFiber(fiber);
await Promise.resolve(); await Promise.resolve();
@@ -288,10 +209,6 @@ export class ComponentNode<P extends object = any, E = any> implements VNode<Com
this.fiber = fiber; this.fiber = fiber;
const component = this.component; const component = this.component;
applyDefaultProps(props, component.constructor as any); applyDefaultProps(props, component.constructor as any);
currentNode = this;
props = useState(props);
currentNode = null;
const prom = Promise.all(this.willUpdateProps.map((f) => f.call(component, props))); const prom = Promise.all(this.willUpdateProps.map((f) => f.call(component, props)));
await prom; await prom;
if (fiber !== this.fiber) { if (fiber !== this.fiber) {
@@ -356,14 +273,6 @@ export class ComponentNode<P extends object = any, E = any> implements VNode<Com
} }
patch() { patch() {
if (this.fiber && this.fiber.parent) {
// we only patch here renderings coming from above. renderings initiated
// by the component will be patched independently in the appropriate
// fiber.complete
this._patch();
}
}
_patch() {
const hasChildren = Object.keys(this.children).length > 0; const hasChildren = Object.keys(this.children).length > 0;
this.bdom!.patch(this!.fiber!.bdom!, hasChildren); this.bdom!.patch(this!.fiber!.bdom!, hasChildren);
if (hasChildren) { if (hasChildren) {
+10 -17
View File
@@ -6,7 +6,8 @@ import { STATUS } from "./status";
export function makeChildFiber(node: ComponentNode, parent: Fiber): Fiber { export function makeChildFiber(node: ComponentNode, parent: Fiber): Fiber {
let current = node.fiber; let current = node.fiber;
if (current) { if (current) {
cancelFibers(current.children); let root = parent.root;
cancelFibers(root, current.children);
current.root = null; current.root = null;
} }
return new Fiber(node, parent); return new Fiber(node, parent);
@@ -16,8 +17,9 @@ export function makeRootFiber(node: ComponentNode): Fiber {
let current = node.fiber; let current = node.fiber;
if (current) { if (current) {
let root = current.root!; let root = current.root!;
root.counter = root.counter + 1 - cancelFibers(current.children); root.counter -= cancelFibers(root, current.children);
current.children = []; current.children = [];
root.counter++;
current.bdom = null; current.bdom = null;
if (fibersInError.has(current)) { if (fibersInError.has(current)) {
fibersInError.delete(current); fibersInError.delete(current);
@@ -33,28 +35,22 @@ export function makeRootFiber(node: ComponentNode): Fiber {
if (node.patched.length) { if (node.patched.length) {
fiber.patched.push(fiber); fiber.patched.push(fiber);
} }
return fiber; return fiber;
} }
/** /**
* @returns number of not-yet rendered fibers cancelled * @returns number of not-yet rendered fibers cancelled
*/ */
function cancelFibers(fibers: Fiber[]): number { function cancelFibers(root: any, fibers: Fiber[]): number {
let result = 0; let result = 0;
for (let fiber of fibers) { for (let fiber of fibers) {
fiber.node.fiber = null; fiber.node.fiber = null;
if (fiber.bdom) { fiber.root = root;
// if fiber has been rendered, this means that the component props have if (!fiber.bdom) {
// been updated. however, this fiber will not be patched to the dom, so
// it could happen that the next render compare the current props with
// the same props, and skip the render completely. With the next line,
// we kindly request the component code to force a render, so it works as
// expected.
fiber.node.forceNextRender = true;
} else {
result++; result++;
} }
result += cancelFibers(fiber.children); result += cancelFibers(root, fiber.children);
} }
return result; return result;
} }
@@ -66,13 +62,11 @@ export class Fiber {
parent: Fiber | null; parent: Fiber | null;
children: Fiber[] = []; children: Fiber[] = [];
appliedToDom = false; appliedToDom = false;
deep: boolean = false;
constructor(node: ComponentNode, parent: Fiber | null) { constructor(node: ComponentNode, parent: Fiber | null) {
this.node = node; this.node = node;
this.parent = parent; this.parent = parent;
if (parent) { if (parent) {
this.deep = parent.deep;
const root = parent.root!; const root = parent.root!;
root.counter++; root.counter++;
this.root = root; this.root = root;
@@ -115,7 +109,7 @@ export class RootFiber extends Fiber {
current = undefined; current = undefined;
// Step 2: patching the dom // Step 2: patching the dom
node._patch(); node.patch();
this.locked = false; this.locked = false;
// Step 4: calling all mounted lifecycle hooks // Step 4: calling all mounted lifecycle hooks
@@ -165,7 +159,6 @@ export class MountFiber extends RootFiber {
let current: Fiber | undefined = this; let current: Fiber | undefined = this;
try { try {
const node = this.node; const node = this.node;
(node.app.constructor as any).validateTarget(this.target);
if (node.bdom) { if (node.bdom) {
// this is a complicated situation: if we mount a fiber with an existing // this is a complicated situation: if we mount a fiber with an existing
// bdom, this means that this same fiber was already completed, mounted, // bdom, this means that this same fiber was already completed, mounted,
+19 -56
View File
@@ -1,104 +1,67 @@
import { getCurrent } from "./component_node"; import { getCurrent } from "./component_node";
import { nodeErrorHandlers } from "./error_handling"; import { nodeErrorHandlers } from "./error_handling";
function wrapError(fn: (...args: any[]) => any, hookName: string) {
const error = new Error(`The following error occurred in ${hookName}: `) as Error & {
cause: any;
};
return (...args: any[]) => {
try {
const result = fn(...args);
if (result instanceof Promise) {
return result.catch((cause) => {
error.cause = cause;
if (cause instanceof Error) {
error.message += `"${cause.message}"`;
}
throw error;
});
}
return result;
} catch (cause) {
if (cause instanceof Error) {
error.message += `"${cause.message}"`;
}
throw error;
}
};
}
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// hooks // hooks
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
export function onWillStart(fn: () => Promise<void> | void | any) { export function onWillStart(fn: () => Promise<void> | void | any) {
const node = getCurrent(); const node = getCurrent()!;
const decorate = node.app.dev ? wrapError : (fn: any) => fn; node.willStart.push(fn.bind(node.component));
node.willStart.push(decorate(fn.bind(node.component), "onWillStart"));
} }
export function onWillUpdateProps(fn: (nextProps: any) => Promise<void> | void | any) { export function onWillUpdateProps(fn: (nextProps: any) => Promise<void> | void | any) {
const node = getCurrent(); const node = getCurrent()!;
const decorate = node.app.dev ? wrapError : (fn: any) => fn; node.willUpdateProps.push(fn.bind(node.component));
node.willUpdateProps.push(decorate(fn.bind(node.component), "onWillUpdateProps"));
} }
export function onMounted(fn: () => void | any) { export function onMounted(fn: () => void | any) {
const node = getCurrent(); const node = getCurrent()!;
const decorate = node.app.dev ? wrapError : (fn: any) => fn; node.mounted.push(fn.bind(node.component));
node.mounted.push(decorate(fn.bind(node.component), "onMounted"));
} }
export function onWillPatch(fn: () => Promise<void> | any | void) { export function onWillPatch(fn: () => Promise<void> | any | void) {
const node = getCurrent(); const node = getCurrent()!;
const decorate = node.app.dev ? wrapError : (fn: any) => fn; node.willPatch.unshift(fn.bind(node.component));
node.willPatch.unshift(decorate(fn.bind(node.component), "onWillPatch"));
} }
export function onPatched(fn: () => void | any) { export function onPatched(fn: () => void | any) {
const node = getCurrent(); const node = getCurrent()!;
const decorate = node.app.dev ? wrapError : (fn: any) => fn; node.patched.push(fn.bind(node.component));
node.patched.push(decorate(fn.bind(node.component), "onPatched"));
} }
export function onWillUnmount(fn: () => Promise<void> | void | any) { export function onWillUnmount(fn: () => Promise<void> | void | any) {
const node = getCurrent(); const node = getCurrent()!;
const decorate = node.app.dev ? wrapError : (fn: any) => fn; node.willUnmount.unshift(fn.bind(node.component));
node.willUnmount.unshift(decorate(fn.bind(node.component), "onWillUnmount"));
} }
export function onWillDestroy(fn: () => Promise<void> | void | any) { export function onWillDestroy(fn: () => Promise<void> | void | any) {
const node = getCurrent(); const node = getCurrent()!;
const decorate = node.app.dev ? wrapError : (fn: any) => fn; node.willDestroy.push(fn.bind(node.component));
node.willDestroy.push(decorate(fn.bind(node.component), "onWillDestroy"));
} }
export function onWillRender(fn: () => void | any) { export function onWillRender(fn: () => void | any) {
const node = getCurrent(); const node = getCurrent()!;
const renderFn = node.renderFn; const renderFn = node.renderFn;
const decorate = node.app.dev ? wrapError : (fn: any) => fn;
fn = decorate(fn.bind(node.component), "onWillRender");
node.renderFn = () => { node.renderFn = () => {
fn(); fn.call(node.component);
return renderFn(); return renderFn();
}; };
} }
export function onRendered(fn: () => void | any) { export function onRendered(fn: () => void | any) {
const node = getCurrent(); const node = getCurrent()!;
const renderFn = node.renderFn; const renderFn = node.renderFn;
const decorate = node.app.dev ? wrapError : (fn: any) => fn;
fn = decorate(fn.bind(node.component), "onRendered");
node.renderFn = () => { node.renderFn = () => {
const result = renderFn(); const result = renderFn();
fn(); fn.call(node.component);
return result; return result;
}; };
} }
type OnErrorCallback = (error: any) => void | any; type OnErrorCallback = (error: any) => void | any;
export function onError(callback: OnErrorCallback) { export function onError(callback: OnErrorCallback) {
const node = getCurrent(); const node = getCurrent()!;
let handlers = nodeErrorHandlers.get(node); let handlers = nodeErrorHandlers.get(node);
if (!handlers) { if (!handlers) {
handlers = []; handlers = [];
+2 -13
View File
@@ -47,7 +47,6 @@ export function validateProps<P>(name: string | ComponentConstructor<P>, props:
} }
applyDefaultProps(props, ComponentClass); applyDefaultProps(props, ComponentClass);
const defaultProps = ComponentClass.defaultProps || {};
let propsDef = getPropDescription(ComponentClass.props); let propsDef = getPropDescription(ComponentClass.props);
const allowAdditionalProps = "*" in propsDef; const allowAdditionalProps = "*" in propsDef;
@@ -55,18 +54,8 @@ export function validateProps<P>(name: string | ComponentConstructor<P>, props:
if (propName === "*") { if (propName === "*") {
continue; 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 ((props as any)[propName] === undefined) {
if (isMandatory) { if (propsDef[propName] && !propsDef[propName].optional) {
throw new Error(`Missing props '${propName}' (component '${ComponentClass.name}')`); throw new Error(`Missing props '${propName}' (component '${ComponentClass.name}')`);
} else { } else {
continue; continue;
@@ -74,7 +63,7 @@ export function validateProps<P>(name: string | ComponentConstructor<P>, props:
} }
let isValid; let isValid;
try { try {
isValid = isValidProp((props as any)[propName], propDef); isValid = isValidProp((props as any)[propName], propsDef[propName]);
} catch (e) { } catch (e) {
(e as Error).message = `Invalid prop '${propName}' in component ${ComponentClass.name} (${ (e as Error).message = `Invalid prop '${propName}' in component ${ComponentClass.name} (${
(e as Error).message (e as Error).message
+7 -6
View File
@@ -11,7 +11,7 @@ import { onMounted, onPatched, onWillUnmount } from "./component/lifecycle_hooks
* html node or component. * html node or component.
*/ */
export function useRef<T extends HTMLElement = HTMLElement>(name: string): { el: T | null } { export function useRef<T extends HTMLElement = HTMLElement>(name: string): { el: T | null } {
const node = getCurrent(); const node = getCurrent()!;
const refs = node.refs; const refs = node.refs;
return { return {
get el(): T | null { get el(): T | null {
@@ -29,7 +29,7 @@ export function useRef<T extends HTMLElement = HTMLElement>(name: string): { el:
* need a reference to the env of the component calling them. * need a reference to the env of the component calling them.
*/ */
export function useEnv<E extends Env>(): E { export function useEnv<E extends Env>(): E {
return getCurrent().component.env as any; return getCurrent()!.component.env as any;
} }
function extendEnv(currentEnv: Object, extension: Object): Object { function extendEnv(currentEnv: Object, extension: Object): Object {
@@ -44,13 +44,14 @@ function extendEnv(currentEnv: Object, extension: Object): Object {
* constructor method. * constructor method.
*/ */
export function useSubEnv(envExtension: Env) { export function useSubEnv(envExtension: Env) {
const node = getCurrent(); const node = getCurrent()!;
const newEnv = extendEnv(node.component.env as any, envExtension);
node.component.env = extendEnv(node.component.env as any, envExtension); node.component.env = extendEnv(node.component.env as any, envExtension);
useChildSubEnv(envExtension); node.childEnv = newEnv;
} }
export function useChildSubEnv(envExtension: Env) { export function useChildSubEnv(envExtension: Env) {
const node = getCurrent(); const node = getCurrent()!;
node.childEnv = extendEnv(node.childEnv, envExtension); node.childEnv = extendEnv(node.childEnv, envExtension);
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@@ -121,7 +122,7 @@ export function useExternalListener(
handler: EventListener, handler: EventListener,
eventParams?: AddEventListenerOptions eventParams?: AddEventListenerOptions
) { ) {
const node = getCurrent(); const node = getCurrent()!;
const boundHandler = handler.bind(node.component); const boundHandler = handler.bind(node.component);
onMounted(() => target.addEventListener(eventName, boundHandler, eventParams)); onMounted(() => target.addEventListener(eventName, boundHandler, eventParams));
onWillUnmount(() => target.removeEventListener(eventName, boundHandler, eventParams)); onWillUnmount(() => target.removeEventListener(eventName, boundHandler, eventParams));
+8 -3
View File
@@ -1,3 +1,4 @@
import { UTILS } from "./app/template_helpers";
import { import {
config, config,
createBlock, createBlock,
@@ -12,10 +13,12 @@ import {
comment, comment,
} from "./blockdom"; } from "./blockdom";
import { mainEventHandler } from "./component/handler"; import { mainEventHandler } from "./component/handler";
import { Portal } from "./portal";
export type { Reactive } from "./reactivity"; export type { Reactive } from "./reactivity";
config.shouldNormalizeDom = false; config.shouldNormalizeDom = false;
config.mainEventHandler = mainEventHandler; config.mainEventHandler = mainEventHandler;
(UTILS as any).Portal = Portal;
export const blockDom = { export const blockDom = {
config, config,
@@ -35,11 +38,13 @@ export const blockDom = {
export { App, mount } from "./app/app"; export { App, mount } from "./app/app";
export { Component } from "./component/component"; export { Component } from "./component/component";
export { useComponent, useState } from "./component/component_node"; export { useComponent } from "./component/component_node";
export { status } from "./component/status"; export { status } from "./component/status";
export { reactive, markRaw, toRaw } from "./reactivity"; export { Memo } from "./memo";
export { xml } from "./app/template_set";
export { useState, reactive, markRaw, toRaw } from "./reactivity";
export { useEffect, useEnv, useExternalListener, useRef, useChildSubEnv, useSubEnv } from "./hooks"; export { useEffect, useEnv, useExternalListener, useRef, useChildSubEnv, useSubEnv } from "./hooks";
export { EventBus, whenReady, loadFile, markup, xml } from "./utils"; export { batched, EventBus, whenReady, loadFile, markup } from "./utils";
export { export {
onWillStart, onWillStart,
onMounted, 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 { onWillUnmount } from "./component/lifecycle_hooks";
import { xml } from "./utils"; import { xml } from "./app/template_set";
import { BDom, text, VNode } from "./blockdom"; import { BDom, text, VNode } from "./blockdom";
import { Component } from "./component/component"; import { Component } from "./component/component";
+49 -224
View File
@@ -1,42 +1,27 @@
import { Callback } from "./utils"; import { onWillDestroy } from "./component/lifecycle_hooks";
import { ComponentNode, getCurrent } from "./component/component_node";
import { batched, Callback } from "./utils";
// Allows to get the target of a Reactive (used for making a new Reactive from the underlying object) // Allows to get the target of a Reactive (used for making a new Reactive from the underlying object)
export const TARGET = Symbol("Target"); const TARGET = Symbol("Target");
// Escape hatch to prevent reactivity system to turn something into a reactive // Escape hatch to prevent reactivity system to turn something into a reactive
const SKIP = Symbol("Skip"); const SKIP = Symbol("Skip");
// Special key to subscribe to, to be notified of key creation/deletion // Special key to subscribe to, to be notified of key creation/deletion
const KEYCHANGES = Symbol("Key changes"); const KEYCHANGES = Symbol("Key changes");
type ObjectKey = string | number | symbol;
type Target = object; 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 & { export type Reactive<T extends Target = Target> = T & {
[TARGET]: any; [TARGET]: any;
}; };
export type NonReactive<T extends Target = Target> = T & { type NonReactive<T extends Target = Target> = T & {
[SKIP]: any; [SKIP]: any;
}; };
const objectToString = Object.prototype.toString; const objectToString = Object.prototype.toString;
const objectHasOwnProperty = Object.prototype.hasOwnProperty;
const SUPPORTED_RAW_TYPES = new Set(["Object", "Array", "Set", "Map", "WeakMap"]);
const COLLECTION_RAWTYPES = new Set(["Set", "Map", "WeakMap"]);
/**
* extract "RawType" from strings like "[object RawType]" => this lets us ignore
* many native objects such as Promise (whose toString is [object Promise])
* or Date ([object Date]), while also supporting collections without using
* instanceof in a loop
*
* @param obj the object to check
* @returns the raw type of the object
*/
function rawType(obj: any) {
return objectToString.call(obj).slice(8, -1);
}
/** /**
* Checks whether a given value can be made into a reactive object. * Checks whether a given value can be made into a reactive object.
* *
@@ -47,17 +32,11 @@ function canBeMadeReactive(value: any): boolean {
if (typeof value !== "object") { if (typeof value !== "object") {
return false; return false;
} }
return SUPPORTED_RAW_TYPES.has(rawType(value)); // 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]).
* Creates a reactive from the given object/callback if possible and returns it, const rawType = objectToString.call(value).slice(8, -1);
* returns the original object otherwise. return rawType === "Object" || rawType === "Array";
*
* @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;
} }
/** /**
@@ -78,10 +57,10 @@ export function markRaw<T extends Target>(value: T): NonReactive<T> {
* @returns the underlying value * @returns the underlying value
*/ */
export function toRaw<T extends object>(value: Reactive<T>): T { export function toRaw<T extends object>(value: Reactive<T>): T {
return value[TARGET] || value; return value[TARGET];
} }
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 * Observes a given key on a target with an callback. The callback will be
* called when the given key changes on the target. * called when the given key changes on the target.
@@ -91,7 +70,7 @@ const targetToKeysToCallbacks = new WeakMap<Target, Map<PropertyKey, Set<Callbac
* or deletion) * or deletion)
* @param callback the function to call when the key changes * @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)) { if (!targetToKeysToCallbacks.get(target)) {
targetToKeysToCallbacks.set(target, new Map()); targetToKeysToCallbacks.set(target, new Map());
} }
@@ -114,7 +93,7 @@ function observeTargetKey(target: Target, key: PropertyKey, callback: Callback):
* @param key the key that changed (or Symbol `KEYCHANGES` if a key was created * @param key the key that changed (or Symbol `KEYCHANGES` if a key was created
* or deleted) * or deleted)
*/ */
function notifyReactives(target: Target, key: PropertyKey): void { function notifyReactives(target: Target, key: ObjectKey): void {
const keyToCallbacks = targetToKeysToCallbacks.get(target); const keyToCallbacks = targetToKeysToCallbacks.get(target);
if (!keyToCallbacks) { if (!keyToCallbacks) {
return; return;
@@ -136,7 +115,7 @@ const callbacksToTargets = new WeakMap<Callback, Set<Target>>();
* *
* @param callback the callback for which the reactives need to be cleared * @param callback the callback for which the reactives need to be cleared
*/ */
export function clearReactivesForCallback(callback: Callback): void { function clearReactivesForCallback(callback: Callback): void {
const targetsToClear = callbacksToTargets.get(callback); const targetsToClear = callbacksToTargets.get(callback);
if (!targetsToClear) { if (!targetsToClear) {
return; return;
@@ -153,17 +132,6 @@ export function clearReactivesForCallback(callback: Callback): void {
targetsToClear.clear(); 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>>(); const reactiveCache = new WeakMap<Target, WeakMap<Callback, Reactive>>();
/** /**
* Creates a reactive proxy for an object. Reading data on the reactive object * Creates a reactive proxy for an object. Reading data on the reactive object
@@ -211,32 +179,20 @@ export function reactive<T extends Target>(
} }
const reactivesForTarget = reactiveCache.get(target)!; const reactivesForTarget = reactiveCache.get(target)!;
if (!reactivesForTarget.has(callback)) { if (!reactivesForTarget.has(callback)) {
const targetRawType = rawType(target); const proxy = new Proxy(target, {
const handler = COLLECTION_RAWTYPES.has(targetRawType) get(target: any, key: ObjectKey, proxy: Reactive<T>) {
? collectionsProxyHandler(target as Collection, callback, targetRawType as CollectionRawType)
: basicProxyHandler<T>(callback);
const proxy = new Proxy(target, handler as ProxyHandler<T>) as Reactive<T>;
reactivesForTarget.set(callback, proxy);
}
return reactivesForTarget.get(callback) as Reactive<T>;
}
/**
* 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) { if (key === TARGET) {
return target; return target;
} }
observeTargetKey(target, key, callback); observeTargetKey(target, key, callback);
return possiblyReactive(Reflect.get(target, key, proxy), callback); const value = Reflect.get(target, key, proxy);
if (!canBeMadeReactive(value)) {
return value;
}
return reactive(value, callback);
}, },
set(target, key, value, proxy) { set(target, key, value, proxy) {
const isNewKey = !objectHasOwnProperty.call(target, key); const isNewKey = !Object.hasOwnProperty.call(target, key);
const originalValue = Reflect.get(target, key, proxy); const originalValue = Reflect.get(target, key, proxy);
const ret = Reflect.set(target, key, value, proxy); const ret = Reflect.set(target, key, value, proxy);
if (isNewKey) { if (isNewKey) {
@@ -252,7 +208,6 @@ function basicProxyHandler<T extends Target>(callback: Callback): ProxyHandler<T
}, },
deleteProperty(target, key) { deleteProperty(target, key) {
const ret = Reflect.deleteProperty(target, key); const ret = Reflect.deleteProperty(target, key);
// TODO: only notify when something was actually deleted
notifyReactives(target, KEYCHANGES); notifyReactives(target, KEYCHANGES);
notifyReactives(target, key); notifyReactives(target, key);
return ret; return ret;
@@ -263,166 +218,36 @@ function basicProxyHandler<T extends Target>(callback: Callback): ProxyHandler<T
}, },
has(target, key) { has(target, key) {
// TODO: this observes all key changes instead of only the presence of the argument 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); observeTargetKey(target, KEYCHANGES, callback);
return Reflect.has(target, key); return Reflect.has(target, key);
}, },
} as ProxyHandler<T>; });
reactivesForTarget.set(callback, proxy);
} }
return reactivesForTarget.get(callback) as Reactive<T>;
}
const batchedRenderFunctions = new WeakMap<ComponentNode, Callback>();
/** /**
* Creates a function that will observe the key that is passed to it when called * Creates a reactive object that will be observed by the current component.
* and delegates to the underlying method. * Reading data from the returned object (eg during rendering) will cause the
* component to subscribe to that data and be rerendered when it changes.
* *
* @param methodName name of the method to delegate to * @param state the state to observe
* @param target @see reactive * @returns a reactive object that will cause the component to re-render on
* @param callback @see reactive * relevant changes
* @see reactive
*/ */
function makeKeyObserver(methodName: "has" | "get", target: any, callback: Callback) { export function useState<T extends object>(state: T): Reactive<T> | NonReactive<T> {
return (key: any) => { const node = getCurrent()!;
key = toRaw(key); if (!batchedRenderFunctions.has(node)) {
observeTargetKey(target, key, callback); batchedRenderFunctions.set(
return possiblyReactive(target[methodName](key), callback); node,
}; batched(() => node.render())
);
onWillDestroy(() => clearReactivesForCallback(render));
} }
/** const render = batchedRenderFunctions.get(node)!;
* Creates an iterable that will delegate to the underlying iteration method and const reactiveState = reactive(state, render);
* observe keys as necessary. return reactiveState;
*
* @param methodName name of the method to delegate to
* @param target @see reactive
* @param callback @see reactive
*/
function makeIteratorObserver(
methodName: "keys" | "values" | "entries" | typeof Symbol.iterator,
target: any,
callback: Callback
) {
return function* () {
observeTargetKey(target, KEYCHANGES, callback);
const keys = target.keys();
for (const item of target[methodName]()) {
const key = keys.next().value;
observeTargetKey(target, key, callback);
yield possiblyReactive(item, callback);
}
};
}
/**
* Creates a function that will delegate to an underlying method, and check if
* that method has modified the presence or value of a key, and notify the
* reactives appropriately.
*
* @param setterName name of the method to delegate to
* @param getterName name of the method which should be used to retrieve the
* value before calling the delegate method for comparison purposes
* @param target @see reactive
*/
function delegateAndNotify(
setterName: "set" | "add" | "delete",
getterName: "has" | "get",
target: any
) {
return (key: any, value: any) => {
key = toRaw(key);
const hadKey = target.has(key);
const originalValue = target[getterName](key);
const ret = target[setterName](key, value);
const hasKey = target.has(key);
if (hadKey !== hasKey) {
notifyReactives(target, KEYCHANGES);
}
if (originalValue !== value) {
notifyReactives(target, key);
}
return ret;
};
}
/**
* Creates a function that will clear the underlying collection and notify that
* the keys of the collection have changed.
*
* @param target @see reactive
*/
function makeClearNotifier(target: Map<any, any> | Set<any>) {
return () => {
const allKeys = [...target.keys()];
target.clear();
notifyReactives(target, KEYCHANGES);
for (const key of allKeys) {
notifyReactives(target, key);
}
};
}
/**
* Maps raw type of an object to an object containing functions that can be used
* to build an appropritate proxy handler for that raw type. Eg: when making a
* reactive set, calling the has method should mark the key that is being
* retrieved as observed, and calling the add or delete method should notify the
* reactives that the key which is being added or deleted has been modified.
*/
const rawTypeToFuncHandlers = {
Set: (target: any, callback: Callback) => ({
has: makeKeyObserver("has", target, callback),
add: delegateAndNotify("add", "has", target),
delete: delegateAndNotify("delete", "has", target),
keys: makeIteratorObserver("keys", target, callback),
values: makeIteratorObserver("values", target, callback),
entries: makeIteratorObserver("entries", target, callback),
[Symbol.iterator]: makeIteratorObserver(Symbol.iterator, target, callback),
clear: makeClearNotifier(target),
get size() {
observeTargetKey(target, KEYCHANGES, callback);
return target.size;
},
}),
Map: (target: any, callback: Callback) => ({
has: makeKeyObserver("has", target, callback),
get: makeKeyObserver("get", target, callback),
set: delegateAndNotify("set", "get", target),
delete: delegateAndNotify("delete", "has", target),
keys: makeIteratorObserver("keys", target, callback),
values: makeIteratorObserver("values", target, callback),
entries: makeIteratorObserver("entries", target, callback),
[Symbol.iterator]: makeIteratorObserver(Symbol.iterator, target, callback),
clear: makeClearNotifier(target),
get size() {
observeTargetKey(target, KEYCHANGES, callback);
return target.size;
},
}),
WeakMap: (target: any, callback: Callback) => ({
has: makeKeyObserver("has", target, callback),
get: makeKeyObserver("get", target, callback),
set: delegateAndNotify("set", "get", target),
delete: delegateAndNotify("delete", "has", target),
}),
};
/**
* Creates a proxy handler for collections (Set/Map/WeakMap)
*
* @param callback @see reactive
* @param target @see reactive
* @returns a proxy handler object
*/
function collectionsProxyHandler<T extends Collection>(
target: T,
callback: Callback,
targetRawType: CollectionRawType
): ProxyHandler<T> {
// TODO: if performance is an issue we can create the special handlers lazily when each
// property is read.
const specialHandlers = rawTypeToFuncHandlers[targetRawType](target, callback);
return Object.assign(basicProxyHandler(callback), {
get(target: any, key: PropertyKey) {
if (key === TARGET) {
return target;
}
if (objectHasOwnProperty.call(specialHandlers, key)) {
return (specialHandlers as any)[key];
}
observeTargetKey(target, key, callback);
return possiblyReactive(target[key], callback);
},
}) as ProxyHandler<T>;
} }
-23
View File
@@ -24,15 +24,6 @@ export function batched(callback: Callback): Callback {
}; };
} }
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 { export class EventBus extends EventTarget {
trigger(name: string, payload?: any) { trigger(name: string, payload?: any) {
this.dispatchEvent(new CustomEvent(name, { detail: payload })); this.dispatchEvent(new CustomEvent(name, { detail: payload }));
@@ -71,17 +62,3 @@ export class Markup extends String {}
export function markup(value: any) { export function markup(value: any) {
return new Markup(value); 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>\`); let block1 = createBlock(\`<div><block-child-0/><block-text-0/></div>\`);
return function template(ctx, node, key = \\"\\") { 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; let txt1 = ctx['contextObj'].b;
return block1([txt1], [b2]); 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>\`); let block1 = createBlock(\`<div><block-child-0/><block-child-1/></div>\`);
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const b2 = component(\`Child\`, {}, key + \`__1\`, node, ctx); let b2 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
const b3 = component(\`Child\`, {}, key + \`__2\`, node, ctx); let b3 = component(\`Child\`, {}, key + \`__2\`, node, ctx);
return block1([], [b2, b3]); 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>\`); let block1 = createBlock(\`<div><block-child-0/><block-child-1/></div>\`);
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const b2 = component(\`Child\`, {}, key + \`__1\`, node, ctx); let b2 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
const b3 = component(\`Child\`, {}, key + \`__2\`, node, ctx); let b3 = component(\`Child\`, {}, key + \`__2\`, node, ctx);
return block1([], [b2, b3]); 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>\`); let block1 = createBlock(\`<div><block-child-0/><block-child-1/></div>\`);
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const b2 = component(\`Child\`, {}, key + \`__1\`, node, ctx); let b2 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
const b3 = component(\`Parent\`, {}, key + \`__2\`, node, ctx); let b3 = component(\`Parent\`, {}, key + \`__2\`, node, ctx);
return block1([], [b2, b3]); 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>\`); let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") { 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]); return block1([], [b2]);
} }
}" }"
@@ -340,14 +340,14 @@ exports[`Reactivity: useState useless atoms should be deleted 1`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx); 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++) { for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`id\`] = v_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); c_block2[i1] = withKey(component(\`Quantity\`, {id: ctx['id']}, key + \`__1__\${key1}\`, node, ctx), key1);
} }
ctx = ctx.__proto__; ctx = ctx.__proto__;
const b2 = list(c_block2); let b2 = list(c_block2);
let txt1 = ctx['total']; let txt1 = ctx['total'];
let txt2 = Object.keys(ctx['state']).length; let txt2 = Object.keys(ctx['state']).length;
return block1([txt1, txt2], [b2]); return block1([txt1, txt2], [b2]);
-9
View File
@@ -169,15 +169,6 @@ describe("properties", () => {
expect(input.value).toBe("potato"); expect(input.value).toBe("potato");
}); });
test("input with value attribute, and undefined given", () => {
const block = createBlock(`<input block-attribute-0="value"/>`);
const tree = block([undefined]);
mount(tree, fixture);
const input = fixture.querySelector("input")!;
expect(input.value).toBe("");
});
test("input type=checkbox with checked attribute", () => { test("input type=checkbox with checked attribute", () => {
// render input with initial value // render input with initial value
const block = createBlock(`<input type="checkbox" block-attribute-0="checked"/>`); 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 { createBlock, mount, patch, remove } from "../../src/blockdom";
import { logStep } from "../helpers";
import { makeTestFixture } from "./helpers"; import { makeTestFixture } from "./helpers";
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@@ -56,15 +55,3 @@ test("is in dom when callback is called", async () => {
mount(tree, fixture); 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 = \\"\\") { return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx); 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++) { for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`action\`] = v_block2[i1]; ctx[\`action\`] = v_block2[i1];
ctx[\`action_index\`] = i1; ctx[\`action_index\`] = i1;
const key1 = ctx['action_index']; let key1 = ctx['action_index'];
const v1 = ctx['activate']; const v1 = ctx['activate'];
const v2 = ctx['action']; const v2 = ctx['action'];
let hdlr1 = [()=>v1(v2), ctx]; let hdlr1 = [()=>v1(v2), ctx];
c_block2[i1] = withKey(block3([hdlr1]), key1); c_block2[i1] = withKey(block3([hdlr1]), key1);
} }
const b2 = list(c_block2); let b2 = list(c_block2);
return block1([], [b2]); 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 = \\"\\") { return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx); 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++) { for (let i1 = 0; i1 < l_block1; i1++) {
ctx[\`value\`] = v_block1[i1]; ctx[\`value\`] = v_block1[i1];
const key1 = ctx['value']; let key1 = ctx['value'];
let hdlr1 = [ctx['add'], ctx]; let hdlr1 = [ctx['add'], ctx];
c_block1[i1] = withKey(block2([hdlr1]), key1); 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 = \\"\\") { return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx); 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++) { for (let i1 = 0; i1 < l_block1; i1++) {
ctx[\`value\`] = v_block1[i1]; ctx[\`value\`] = v_block1[i1];
ctx[\`value_first\`] = i1 === 0; ctx[\`value_first\`] = i1 === 0;
ctx[\`value_last\`] = i1 === v_block1.length - 1; ctx[\`value_last\`] = i1 === v_block1.length - 1;
ctx[\`value_index\`] = i1; ctx[\`value_index\`] = i1;
ctx[\`value_value\`] = k_block1[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); c_block1[i1] = withKey(callTemplate_1.call(this, ctx, node, key + \`__1__\${key1}\`), key1);
} }
return list(c_block1); 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 = \\"\\") { return function template(ctx, node, key = \\"\\") {
let hdlr1 = [ctx['onClick'], ctx]; let hdlr1 = [ctx['onClick'], ctx];
const b2 = safeOutput(ctx['html']); let b2 = safeOutput(ctx['html']);
return block1([hdlr1], [b2]); 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 = \\"\\") { return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx); 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++) { for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`project\`] = v_block2[i1]; ctx[\`project\`] = v_block2[i1];
const key1 = ctx['project']; let key1 = ctx['project'];
const v1 = ctx['onEdit']; const v1 = ctx['onEdit'];
const v2 = ctx['project']; 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; let txt1 = ctx['project'].name;
c_block2[i1] = withKey(block3([hdlr1, txt1]), key1); c_block2[i1] = withKey(block3([hdlr1, txt1]), key1);
} }
const b2 = list(c_block2); let b2 = list(c_block2);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -478,7 +478,7 @@ exports[`t-on t-on with t-call 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`); let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") { 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]); 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>\`); let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") { 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]); return block1([], [b2]);
} }
}" }"
+34 -34
View File
@@ -30,28 +30,28 @@ exports[`misc complex template 1`] = `
b3 = block3(); b3 = block3();
} }
ctx = Object.create(ctx); 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++) { for (let i1 = 0; i1 < l_block4; i1++) {
ctx[\`slot\`] = v_block4[i1]; ctx[\`slot\`] = v_block4[i1];
const key1 = ctx['slot'].id; let key1 = ctx['slot'].id;
c_block4[i1] = withKey(component(\`SlotButton\`, {class: ctx['slot_container'],slot: ctx['slot']}, key + \`__1__\${key1}\`, node, ctx), key1); c_block4[i1] = withKey(component(\`SlotButton\`, {class: ctx['slot_container'],slot: ctx['slot']}, key + \`__1__\${key1}\`, node, ctx), key1);
} }
ctx = ctx.__proto__; ctx = ctx.__proto__;
b4 = list(c_block4); b4 = list(c_block4);
ctx = Object.create(ctx); 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++) { for (let i1 = 0; i1 < l_block6; i1++) {
ctx[\`x\`] = v_block6[i1]; ctx[\`x\`] = v_block6[i1];
const key1 = ctx['x']; let key1 = ctx['x'];
c_block6[i1] = withKey(block7(), key1); c_block6[i1] = withKey(block7(), key1);
} }
ctx = ctx.__proto__; ctx = ctx.__proto__;
b6 = list(c_block6); b6 = list(c_block6);
ctx = Object.create(ctx); 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++) { for (let i1 = 0; i1 < l_block8; i1++) {
ctx[\`commit_link\`] = v_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 b10,b11,b12,b13;
let attr5 = \`/runbot/commit/\${ctx['commit_link'].commit_id}\`; let attr5 = \`/runbot/commit/\${ctx['commit_link'].commit_id}\`;
let attr6 = \`badge badge-light batch_commit match_type_\${ctx['commit_link'].match_type}\`; 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 = Object.create(ctx);
ctx[isBoundary] = 1 ctx[isBoundary] = 1
ctx = Object.create(ctx); 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++) { for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`value\`] = v_block2[i1]; ctx[\`value\`] = v_block2[i1];
ctx[\`value_first\`] = i1 === 0; ctx[\`value_first\`] = i1 === 0;
ctx[\`value_last\`] = i1 === v_block2.length - 1; ctx[\`value_last\`] = i1 === v_block2.length - 1;
ctx[\`value_index\`] = i1; ctx[\`value_index\`] = i1;
ctx[\`value_value\`] = k_block2[i1]; ctx[\`value_value\`] = k_block2[i1];
const key1 = ctx['value']; let key1 = ctx['value'];
let txt1 = ctx['value']; let txt1 = ctx['value'];
const b4 = block4([txt1]); let b4 = block4([txt1]);
ctx = Object.create(ctx); ctx = Object.create(ctx);
ctx[isBoundary] = 1; ctx[isBoundary] = 1;
ctx = Object.create(ctx); ctx = Object.create(ctx);
ctx[isBoundary] = 1; ctx[isBoundary] = 1;
setContextValue(ctx, \\"foo\\", 'aaa'); 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__; 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'); setContextValue(ctx, \\"foo\\", 'bbb');
const b8 = callTemplate_3.call(this, ctx, node, key + \`__3__\${key1}\`); let b8 = callTemplate_3.call(this, ctx, node, key + \`__3__\${key1}\`);
const b5 = multi([b6, b7, b8]); let b5 = multi([b6, b7, b8]);
ctx[zero] = b5; 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__; ctx = ctx.__proto__;
c_block2[i1] = withKey(multi([b4, b9]), key1); c_block2[i1] = withKey(multi([b4, b9]), key1);
} }
ctx = ctx.__proto__; ctx = ctx.__proto__;
const b2 = list(c_block2); let b2 = list(c_block2);
const b10 = callTemplate_5.call(this, ctx, node, key + \`__5\`); let b10 = callTemplate_5.call(this, ctx, node, key + \`__5\`);
return block1([], [b2, b10]); return block1([], [b2, b10]);
} }
}" }"
@@ -155,7 +155,7 @@ exports[`misc global 3`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
let attr1 = 'agüero'; let attr1 = 'agüero';
const b2 = ctx[zero]; let b2 = ctx[zero];
return block1([attr1], [b2]); return block1([attr1], [b2]);
} }
}" }"
@@ -170,8 +170,8 @@ exports[`misc global 4`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`); let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const b3 = text(\`toto default\`); let b3 = text(\`toto default\`);
const b2 = withDefault(safeOutput(ctx['toto']), b3); let b2 = withDefault(safeOutput(ctx['toto']), b3);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -221,10 +221,10 @@ exports[`misc other complex template 1`] = `
let attr1 = \`/runbot/\${ctx['project'].slug}\`; let attr1 = \`/runbot/\${ctx['project'].slug}\`;
let txt1 = ctx['project'].name; let txt1 = ctx['project'].name;
ctx = Object.create(ctx); 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++) { for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`project\`] = v_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 hdlr1 = [ctx['selectProject'](ctx['project']), ctx];
let txt2 = ctx['project'].name; let txt2 = ctx['project'].name;
c_block2[i1] = withKey(block3([hdlr1, txt2]), key1); 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) { if (ctx['nb_assigned_errors']&&ctx['nb_assigned_errors']>0) {
let attr3 = \`You have \${ctx['nb_assigned_errors']} random bug assigned\`; let attr3 = \`You have \${ctx['nb_assigned_errors']} random bug assigned\`;
let txt3 = ctx['nb_assigned_errors']; let txt3 = ctx['nb_assigned_errors'];
const b8 = block8([attr3, txt3]); let b8 = block8([attr3, txt3]);
const b9 = block9(); let b9 = block9();
b7 = multi([b8, b9]); b7 = multi([b8, b9]);
} else if (ctx['nb_build_errors']&&ctx['nb_build_errors']>0) { } else if (ctx['nb_build_errors']&&ctx['nb_build_errors']>0) {
const b11 = block11(); let b11 = block11();
const b12 = block12(); let b12 = block12();
b10 = multi([b11, b12]); b10 = multi([b11, b12]);
} }
let txt4 = ctx['user'].name.length>25?ctx['user'].namesubstring(0,23)+'...':ctx['user'].name; 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]; let hdlr3 = [ctx['toggleMore'], ctx];
if (ctx['categories']&&ctx['categories'].length>1) { if (ctx['categories']&&ctx['categories'].length>1) {
ctx = Object.create(ctx); 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++) { for (let i1 = 0; i1 < l_block15; i1++) {
ctx[\`category\`] = v_block15[i1]; ctx[\`category\`] = v_block15[i1];
const key1 = ctx['category'].id; let key1 = ctx['category'].id;
let attr6 = ctx['category'].id; let attr6 = ctx['category'].id;
let attr7 = ctx['category'].id==ctx['options'].active_category_id; let attr7 = ctx['category'].id==ctx['options'].active_category_id;
let txt5 = ctx['category'].name; let txt5 = ctx['category'].name;
c_block15[i1] = withKey(block16([attr6, attr7, txt5]), key1); c_block15[i1] = withKey(block16([attr6, attr7, txt5]), key1);
} }
ctx = ctx.__proto__; ctx = ctx.__proto__;
const b15 = list(c_block15); let b15 = list(c_block15);
b14 = block14([], [b15]); b14 = block14([], [b15]);
} }
let attr8 = ctx['search'].value; let attr8 = ctx['search'].value;
@@ -280,10 +280,10 @@ exports[`misc other complex template 1`] = `
let hdlr6 = [ctx['clearSearch'], ctx]; let hdlr6 = [ctx['clearSearch'], ctx];
if (ctx['triggers']) { if (ctx['triggers']) {
ctx = Object.create(ctx); 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++) { for (let i1 = 0; i1 < l_block18; i1++) {
ctx[\`trigger\`] = v_block18[i1]; ctx[\`trigger\`] = v_block18[i1];
const key1 = ctx['trigger'].id; let key1 = ctx['trigger'].id;
let b20; let b20;
if (!ctx['trigger'].manual&&ctx['trigger'].project_id===ctx['project'].id&&ctx['trigger'].category_id===ctx['options'].active_category_id) { 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}\`; let attr9 = \`trigger_\${ctx['trigger'].id}\`;
@@ -298,12 +298,12 @@ exports[`misc other complex template 1`] = `
c_block18[i1] = withKey(multi([b20]), key1); c_block18[i1] = withKey(multi([b20]), key1);
} }
ctx = ctx.__proto__; ctx = ctx.__proto__;
const b18 = list(c_block18); let b18 = list(c_block18);
let hdlr8 = [ctx['triggerAll'], ctx]; let hdlr8 = [ctx['triggerAll'], ctx];
let hdlr9 = [ctx['triggerNone'], ctx]; let hdlr9 = [ctx['triggerNone'], ctx];
let hdlr10 = [ctx['triggerDefault'], ctx]; let hdlr10 = [ctx['triggerDefault'], ctx];
let hdlr11 = [ctx['toggleSettingsMenu'], ctx]; let hdlr11 = [ctx['toggleSettingsMenu'], ctx];
const b21 = block21([hdlr8, hdlr9, hdlr10, hdlr11]); let b21 = block21([hdlr8, hdlr9, hdlr10, hdlr11]);
b17 = multi([b18, b21]); b17 = multi([b18, b21]);
} }
if (ctx['load_infos']) { if (ctx['load_infos']) {
@@ -316,8 +316,8 @@ exports[`misc other complex template 1`] = `
if (!ctx['project']) { if (!ctx['project']) {
b24 = block24(); b24 = block24();
} else { } else {
const b26 = component(\`BundlesList\`, {bundles: ctx['bundles'].sticky, category_custom_views: ctx['category_custom_views'], search: ctx['search']}, key + \`__2\`, node, ctx); let 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 b27 = component(\`BundlesList\`, {bundles: ctx['bundles'].dev,search: ctx['search']}, key + \`__3\`, node, ctx);
b25 = block25([], [b26, b27]); b25 = block25([], [b26, b27]);
} }
return block1([attr1, txt1, hdlr2, hdlr3, attr8, hdlr4, hdlr5, ref1, hdlr6, ref2], [b2, b4, b14, b17, b22, b23, b24, b25]); 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 = \\"\\") { return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx); 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++) { for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`item\`] = v_block2[i1]; ctx[\`item\`] = v_block2[i1];
ctx[\`item_index\`] = i1; ctx[\`item_index\`] = i1;
const key1 = ctx['item_index']; let key1 = ctx['item_index'];
c_block2[i1] = withKey(text(ctx['item']), key1); c_block2[i1] = withKey(text(ctx['item']), key1);
} }
const b2 = list(c_block2); let b2 = list(c_block2);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -211,8 +211,8 @@ exports[`simple templates, mostly static multiple root nodes 1`] = `
let block3 = createBlock(\`<span>hey</span>\`); let block3 = createBlock(\`<span>hey</span>\`);
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const b2 = block2(); let b2 = block2();
const b3 = block3(); let b3 = block3();
return multi([b2, b3]); 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; let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const b2 = text(\`hello \`); let b2 = text(\`hello \`);
const b3 = text(ctx['text']); let b3 = text(ctx['text']);
return multi([b2, b3]); 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; let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const b2 = text(\`hello \`); let b2 = text(\`hello \`);
const b3 = text(ctx['text']); let b3 = text(ctx['text']);
return multi([b2, b3]); 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; let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const b2 = text(ctx['text1']); let b2 = text(ctx['text1']);
const b3 = text(ctx['text2']); let b3 = text(ctx['text2']);
return multi([b2, b3]); 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; let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const b2 = text(ctx['text1']); let b2 = text(ctx['text1']);
const b3 = text(ctx['text2']); let b3 = text(ctx['text2']);
return multi([b2, b3]); return multi([b2, b3]);
} }
}" }"
@@ -66,7 +66,7 @@ exports[`properly support svg svg creates new block if it is within html -- 2 1`
if (ctx['hasPath']) { if (ctx['hasPath']) {
b3 = block3(); b3 = block3();
} }
const b2 = block2([], [b3]); let b2 = block2([], [b3]);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -81,7 +81,7 @@ exports[`properly support svg svg creates new block if it is within html 1`] = `
let block2 = createBlock(\`<svg block-ns=\\"http://www.w3.org/2000/svg\\"><polygon fill=\\"#000000\\" points=\\"0 0 4 4 8 0\\" transform=\\"translate(5 7)\\"/></svg>\`); 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 = \\"\\") { return function template(ctx, node, key = \\"\\") {
const b2 = block2(); let b2 = block2();
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -97,7 +97,7 @@ exports[`properly support svg svg namespace added to sub templates if root tag i
let block1 = createBlock(\`<svg block-ns=\\"http://www.w3.org/2000/svg\\"><block-child-0/></svg>\`); let block1 = createBlock(\`<svg block-ns=\\"http://www.w3.org/2000/svg\\"><block-child-0/></svg>\`);
return function template(ctx, node, key = \\"\\") { 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]); return block1([], [b2]);
} }
}" }"
@@ -10,7 +10,7 @@ exports[`t-call (template calling) basic caller 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`); let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") { 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]); 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 = \\"\\") { return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx); ctx = Object.create(ctx);
ctx[isBoundary] = 1; ctx[isBoundary] = 1;
const b3 = block3(); let b3 = block3();
const b4 = text(\` \`); let b4 = text(\` \`);
const b5 = block5(); let b5 = block5();
const b2 = multi([b3, b4, b5]); let b2 = multi([b3, b4, b5]);
ctx[zero] = b2; 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]); 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>\`); let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const b2 = ctx[zero]; let b2 = ctx[zero];
return block1([], [b2]); 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 = \\"\\") { return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx); ctx = Object.create(ctx);
ctx[isBoundary] = 1; ctx[isBoundary] = 1;
const b3 = block3(); let b3 = block3();
const b4 = text(\` \`); let b4 = text(\` \`);
const b5 = block5(); let b5 = block5();
const b2 = multi([b3, b4, b5]); let b2 = multi([b3, b4, b5]);
ctx[zero] = b2; 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]); 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 = \\"\\") { return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx); ctx = Object.create(ctx);
ctx[isBoundary] = 1; ctx[isBoundary] = 1;
const b3 = block3(); let b3 = block3();
const b4 = ctx[zero]; let b4 = ctx[zero];
const b2 = multi([b3, b4]); let b2 = multi([b3, b4]);
ctx[zero] = b2; 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]); 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 = \\"\\") { return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx); ctx = Object.create(ctx);
ctx[isBoundary] = 1; ctx[isBoundary] = 1;
const b3 = block3(); let b3 = block3();
const b4 = ctx[zero]; let b4 = ctx[zero];
const b2 = multi([b3, b4]); let b2 = multi([b3, b4]);
ctx[zero] = b2; 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]); 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>\`); let block1 = createBlock(\`<div><span>cascade 2</span><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const b2 = ctx[zero]; let b2 = ctx[zero];
return block1([], [b2]); 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 = \\"\\") { return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx); ctx = Object.create(ctx);
ctx[isBoundary] = 1; ctx[isBoundary] = 1;
const b2 = block2(); let b2 = block2();
const b3 = text(\` \`); let b3 = text(\` \`);
const b4 = block4(); let b4 = block4();
const b1 = multi([b2, b3, b4]); let b1 = multi([b2, b3, b4]);
ctx[zero] = b1; ctx[zero] = b1;
return callTemplate_1.call(this, ctx, node, key + \`__1\`); 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 = \\"\\") { return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx); ctx = Object.create(ctx);
ctx[isBoundary] = 1; ctx[isBoundary] = 1;
const b2 = block2(); let b2 = block2();
const b3 = ctx[zero]; let b3 = ctx[zero];
const b1 = multi([b2, b3]); let b1 = multi([b2, b3]);
ctx[zero] = b1; ctx[zero] = b1;
return callTemplate_1.call(this, ctx, node, key + \`__1\`); 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 = \\"\\") { return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx); ctx = Object.create(ctx);
ctx[isBoundary] = 1; ctx[isBoundary] = 1;
const b2 = block2(); let b2 = block2();
const b3 = ctx[zero]; let b3 = ctx[zero];
const b1 = multi([b2, b3]); let b1 = multi([b2, b3]);
ctx[zero] = b1; ctx[zero] = b1;
return callTemplate_1.call(this, ctx, node, key + \`__1\`); 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>\`); let block2 = createBlock(\`<span>cascade 2</span>\`);
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const b2 = block2(); let b2 = block2();
const b3 = ctx[zero]; let b3 = ctx[zero];
return multi([b2, b3]); return multi([b2, b3]);
} }
}" }"
@@ -272,7 +272,7 @@ exports[`t-call (template calling) dynamic t-call 1`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const template1 = (ctx['template']); 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]); return block1([], [b2]);
} }
}" }"
@@ -319,7 +319,7 @@ exports[`t-call (template calling) inherit context 1`] = `
ctx = Object.create(ctx); ctx = Object.create(ctx);
ctx[isBoundary] = 1 ctx[isBoundary] = 1
setContextValue(ctx, \\"foo\\", 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]); return block1([], [b2]);
} }
}" }"
@@ -370,7 +370,7 @@ exports[`t-call (template calling) recursive template, part 2 1`] = `
ctx = Object.create(ctx); ctx = Object.create(ctx);
ctx[isBoundary] = 1; ctx[isBoundary] = 1;
setContextValue(ctx, \\"node\\", ctx['root']); 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]); return block1([], [b2]);
} }
}" }"
@@ -390,21 +390,21 @@ exports[`t-call (template calling) recursive template, part 2 2`] = `
ctx[isBoundary] = 1 ctx[isBoundary] = 1
let txt1 = ctx['node'].val; let txt1 = ctx['node'].val;
ctx = Object.create(ctx); 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++) { for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`subtree\`] = v_block2[i1]; ctx[\`subtree\`] = v_block2[i1];
ctx[\`subtree_first\`] = i1 === 0; ctx[\`subtree_first\`] = i1 === 0;
ctx[\`subtree_last\`] = i1 === v_block2.length - 1; ctx[\`subtree_last\`] = i1 === v_block2.length - 1;
ctx[\`subtree_index\`] = i1; ctx[\`subtree_index\`] = i1;
ctx[\`subtree_value\`] = k_block2[i1]; ctx[\`subtree_value\`] = k_block2[i1];
const key1 = ctx['subtree_index']; let key1 = ctx['subtree_index'];
ctx = Object.create(ctx); ctx = Object.create(ctx);
ctx[isBoundary] = 1; ctx[isBoundary] = 1;
setContextValue(ctx, \\"node\\", ctx['subtree']); setContextValue(ctx, \\"node\\", ctx['subtree']);
c_block2[i1] = withKey(callTemplate_1.call(this, ctx, node, key + \`__1__\${key1}\`), key1); c_block2[i1] = withKey(callTemplate_1.call(this, ctx, node, key + \`__1__\${key1}\`), key1);
ctx = ctx.__proto__; ctx = ctx.__proto__;
} }
const b2 = list(c_block2); let b2 = list(c_block2);
return block1([txt1], [b2]); return block1([txt1], [b2]);
} }
}" }"
@@ -425,7 +425,7 @@ exports[`t-call (template calling) recursive template, part 3 1`] = `
ctx = Object.create(ctx); ctx = Object.create(ctx);
ctx[isBoundary] = 1; ctx[isBoundary] = 1;
setContextValue(ctx, \\"node\\", ctx['root']); 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]); return block1([], [b2]);
} }
}" }"
@@ -445,21 +445,21 @@ exports[`t-call (template calling) recursive template, part 3 2`] = `
ctx[isBoundary] = 1 ctx[isBoundary] = 1
let txt1 = ctx['node'].val; let txt1 = ctx['node'].val;
ctx = Object.create(ctx); 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++) { for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`subtree\`] = v_block2[i1]; ctx[\`subtree\`] = v_block2[i1];
ctx[\`subtree_first\`] = i1 === 0; ctx[\`subtree_first\`] = i1 === 0;
ctx[\`subtree_last\`] = i1 === v_block2.length - 1; ctx[\`subtree_last\`] = i1 === v_block2.length - 1;
ctx[\`subtree_index\`] = i1; ctx[\`subtree_index\`] = i1;
ctx[\`subtree_value\`] = k_block2[i1]; ctx[\`subtree_value\`] = k_block2[i1];
const key1 = ctx['subtree_index']; let key1 = ctx['subtree_index'];
ctx = Object.create(ctx); ctx = Object.create(ctx);
ctx[isBoundary] = 1; ctx[isBoundary] = 1;
setContextValue(ctx, \\"node\\", ctx['subtree']); setContextValue(ctx, \\"node\\", ctx['subtree']);
c_block2[i1] = withKey(callTemplate_1.call(this, ctx, node, key + \`__1__\${key1}\`), key1); c_block2[i1] = withKey(callTemplate_1.call(this, ctx, node, key + \`__1__\${key1}\`), key1);
ctx = ctx.__proto__; ctx = ctx.__proto__;
} }
const b2 = list(c_block2); let b2 = list(c_block2);
return block1([txt1], [b2]); return block1([txt1], [b2]);
} }
}" }"
@@ -481,7 +481,7 @@ exports[`t-call (template calling) recursive template, part 4: with t-set recurs
ctx[isBoundary] = 1; ctx[isBoundary] = 1;
setContextValue(ctx, \\"recursive_idx\\", 1); setContextValue(ctx, \\"recursive_idx\\", 1);
setContextValue(ctx, \\"node\\", ctx['root']); 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]); 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 txt1 = ctx['node'].val;
let txt2 = ctx['recursive_idx']; let txt2 = ctx['recursive_idx'];
ctx = Object.create(ctx); 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++) { for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`subtree\`] = v_block2[i1]; ctx[\`subtree\`] = v_block2[i1];
ctx[\`subtree_first\`] = i1 === 0; ctx[\`subtree_first\`] = i1 === 0;
ctx[\`subtree_last\`] = i1 === v_block2.length - 1; ctx[\`subtree_last\`] = i1 === v_block2.length - 1;
ctx[\`subtree_index\`] = i1; ctx[\`subtree_index\`] = i1;
ctx[\`subtree_value\`] = k_block2[i1]; ctx[\`subtree_value\`] = k_block2[i1];
const key1 = ctx['subtree_index']; let key1 = ctx['subtree_index'];
ctx = Object.create(ctx); ctx = Object.create(ctx);
ctx[isBoundary] = 1; ctx[isBoundary] = 1;
setContextValue(ctx, \\"node\\", ctx['subtree']); setContextValue(ctx, \\"node\\", ctx['subtree']);
c_block2[i1] = withKey(callTemplate_1.call(this, ctx, node, key + \`__1__\${key1}\`), key1); c_block2[i1] = withKey(callTemplate_1.call(this, ctx, node, key + \`__1__\${key1}\`), key1);
ctx = ctx.__proto__; ctx = ctx.__proto__;
} }
const b2 = list(c_block2); let b2 = list(c_block2);
return block1([txt1, txt2], [b2]); return block1([txt1, txt2], [b2]);
} }
}" }"
@@ -538,7 +538,7 @@ exports[`t-call (template calling) scoped parameters 1`] = `
ctx = Object.create(ctx); ctx = Object.create(ctx);
ctx[isBoundary] = 1; ctx[isBoundary] = 1;
setContextValue(ctx, \\"foo\\", 42); 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__; ctx = ctx.__proto__;
let txt1 = ctx['foo']; let txt1 = ctx['foo'];
return block1([txt1], [b2]); return block1([txt1], [b2]);
@@ -573,7 +573,7 @@ exports[`t-call (template calling) scoped parameters, part 2 1`] = `
ctx = Object.create(ctx); ctx = Object.create(ctx);
ctx[isBoundary] = 1; ctx[isBoundary] = 1;
setContextValue(ctx, \\"foo\\", 42); 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__; ctx = ctx.__proto__;
let txt1 = ctx['foo']; let txt1 = ctx['foo'];
return block1([txt1], [b2]); 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>\`); let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") { 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]); 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 = \\"\\") { return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx); ctx = Object.create(ctx);
ctx[isBoundary] = 1; ctx[isBoundary] = 1;
const b1 = block1(); let b1 = block1();
ctx[zero] = b1; ctx[zero] = b1;
return callTemplate_1.call(this, ctx, node, key + \`__1\`); 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>\`); let block1 = createBlock(\`<foo><block-child-0/></foo>\`);
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const b2 = ctx[zero]; let b2 = ctx[zero];
return block1([], [b2]); 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 = Object.create(ctx);
ctx[isBoundary] = 1; ctx[isBoundary] = 1;
setContextValue(ctx, \\"val\\", \`yip yip\`); 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]); 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 = Object.create(ctx);
ctx[isBoundary] = 1 ctx[isBoundary] = 1
ctx = Object.create(ctx); 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++) { for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`v\`] = v_block2[i1]; ctx[\`v\`] = v_block2[i1];
ctx[\`v_first\`] = i1 === 0; ctx[\`v_first\`] = i1 === 0;
ctx[\`v_last\`] = i1 === v_block2.length - 1; ctx[\`v_last\`] = i1 === v_block2.length - 1;
ctx[\`v_index\`] = i1; ctx[\`v_index\`] = i1;
ctx[\`v_value\`] = k_block2[i1]; ctx[\`v_value\`] = k_block2[i1];
const key1 = ctx['v_index']; let key1 = ctx['v_index'];
setContextValue(ctx, \\"val\\", ctx['v'].val); setContextValue(ctx, \\"val\\", ctx['v'].val);
ctx = Object.create(ctx); ctx = Object.create(ctx);
ctx[isBoundary] = 1; 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); c_block2[i1] = withKey(callTemplate_1.call(this, ctx, node, key + \`__1__\${key1}\`), key1);
ctx = ctx.__proto__; ctx = ctx.__proto__;
} }
const b2 = list(c_block2); let b2 = list(c_block2);
return block1([], [b2]); 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 = Object.create(ctx);
ctx[isBoundary] = 1 ctx[isBoundary] = 1
setContextValue(ctx, \\"w\\", 'fromwrapper'); 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]); 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 = Object.create(ctx);
ctx[isBoundary] = 1 ctx[isBoundary] = 1
ctx = Object.create(ctx); 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++) { for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`v\`] = v_block2[i1]; ctx[\`v\`] = v_block2[i1];
ctx[\`v_first\`] = i1 === 0; ctx[\`v_first\`] = i1 === 0;
ctx[\`v_last\`] = i1 === v_block2.length - 1; ctx[\`v_last\`] = i1 === v_block2.length - 1;
ctx[\`v_index\`] = i1; ctx[\`v_index\`] = i1;
ctx[\`v_value\`] = k_block2[i1]; ctx[\`v_value\`] = k_block2[i1];
const key1 = ctx['v_index']; let key1 = ctx['v_index'];
setContextValue(ctx, \\"val\\", ctx['v'].val); setContextValue(ctx, \\"val\\", ctx['v'].val);
ctx = Object.create(ctx); ctx = Object.create(ctx);
ctx[isBoundary] = 1; 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); c_block2[i1] = withKey(callTemplate_1.call(this, ctx, node, key + \`__1__\${key1}\`), key1);
ctx = ctx.__proto__; ctx = ctx.__proto__;
} }
const b2 = list(c_block2); let b2 = list(c_block2);
return block1([], [b2]); 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 = \\"\\") { return function template(ctx, node, key = \\"\\") {
let txt1 = ctx['val3']; let txt1 = ctx['val3'];
const b2 = block2([txt1]); let b2 = block2([txt1]);
const b3 = text(ctx['w']); let b3 = text(ctx['w']);
return multi([b2, b3]); 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 = Object.create(ctx);
ctx[isBoundary] = 1 ctx[isBoundary] = 1
setContextValue(ctx, \\"v\\", \`Hi\`); 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]); return block1([], [b2]);
} }
}" }"
@@ -938,7 +938,7 @@ exports[`t-call (template calling) with unused body 1`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx); ctx = Object.create(ctx);
ctx[isBoundary] = 1; ctx[isBoundary] = 1;
const b1 = text(\`WHEEE\`); let b1 = text(\`WHEEE\`);
ctx[zero] = b1; ctx[zero] = b1;
return callTemplate_1.call(this, ctx, node, key + \`__1\`); 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 = \\"\\") { return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx); ctx = Object.create(ctx);
ctx[isBoundary] = 1; ctx[isBoundary] = 1;
const b1 = text(\`ok\`); let b1 = text(\`ok\`);
ctx[zero] = b1; ctx[zero] = b1;
return callTemplate_1.call(this, ctx, node, key + \`__1\`); 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 = Object.create(ctx);
ctx[isBoundary] = 1; ctx[isBoundary] = 1;
setContextValue(ctx, \\"foo\\", 'ok'); 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]); return block1([], [b2]);
} }
}" }"
@@ -44,7 +44,7 @@ exports[`debugging t-debug on sub template 2`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`); let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") { 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]); 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; let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const b2 = text(ctx['v1']); let b2 = text(ctx['v1']);
const b3 = text(\`:\`); let b3 = text(\`:\`);
const b4 = text(ctx['v2']); let b4 = text(ctx['v2']);
const b5 = text(\`:\`); let b5 = text(\`:\`);
const b6 = text(ctx['v3']); let b6 = text(ctx['v3']);
const b7 = text(\`:\`); let b7 = text(\`:\`);
const b8 = text(ctx['v4']); let b8 = text(ctx['v4']);
const b9 = text(\`:\`); let b9 = text(\`:\`);
const b10 = text(ctx['v5']); let b10 = text(ctx['v5']);
return multi([b2, b3, b4, b5, b6, b7, b8, b9, b10]); 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 = \\"\\") { return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx); ctx = Object.create(ctx);
ctx[isBoundary] = 1; ctx[isBoundary] = 1;
const b2 = block2(); let b2 = block2();
ctx[zero] = b2; 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]); return block1([], [b3]);
} }
}" }"
@@ -10,13 +10,13 @@ exports[`t-foreach does not pollute the rendering context 1`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx); 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++) { for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`item\`] = v_block2[i1]; ctx[\`item\`] = v_block2[i1];
const key1 = ctx['item']; let key1 = ctx['item'];
c_block2[i1] = withKey(text(ctx['item']), key1); c_block2[i1] = withKey(text(ctx['item']), key1);
} }
const b2 = list(c_block2); let b2 = list(c_block2);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -33,14 +33,14 @@ exports[`t-foreach iterate on items (on a element node) 1`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx); 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++) { for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`item\`] = v_block2[i1]; ctx[\`item\`] = v_block2[i1];
const key1 = ctx['item']; let key1 = ctx['item'];
let txt1 = ctx['item']; let txt1 = ctx['item'];
c_block2[i1] = withKey(block3([txt1]), key1); c_block2[i1] = withKey(block3([txt1]), key1);
} }
const b2 = list(c_block2); let b2 = list(c_block2);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -56,22 +56,22 @@ exports[`t-foreach iterate on items 1`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx); 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++) { for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`item\`] = v_block2[i1]; ctx[\`item\`] = v_block2[i1];
ctx[\`item_index\`] = i1; ctx[\`item_index\`] = i1;
ctx[\`item_value\`] = k_block2[i1]; ctx[\`item_value\`] = k_block2[i1];
const key1 = ctx['item']; let key1 = ctx['item'];
const b4 = text(\` [\`); let b4 = text(\` [\`);
const b5 = text(ctx['item_index']); let b5 = text(ctx['item_index']);
const b6 = text(\`: \`); let b6 = text(\`: \`);
const b7 = text(ctx['item']); let b7 = text(ctx['item']);
const b8 = text(\` \`); let b8 = text(\` \`);
const b9 = text(ctx['item_value']); let b9 = text(ctx['item_value']);
const b10 = text(\`] \`); let b10 = text(\`] \`);
c_block2[i1] = withKey(multi([b4, b5, b6, b7, b8, b9, b10]), key1); 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]); return block1([], [b2]);
} }
}" }"
@@ -87,22 +87,22 @@ exports[`t-foreach iterate, dict param 1`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx); 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++) { for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`item\`] = v_block2[i1]; ctx[\`item\`] = v_block2[i1];
ctx[\`item_index\`] = i1; ctx[\`item_index\`] = i1;
ctx[\`item_value\`] = k_block2[i1]; ctx[\`item_value\`] = k_block2[i1];
const key1 = ctx['item_index']; let key1 = ctx['item_index'];
const b4 = text(\` [\`); let b4 = text(\` [\`);
const b5 = text(ctx['item_index']); let b5 = text(ctx['item_index']);
const b6 = text(\`: \`); let b6 = text(\`: \`);
const b7 = text(ctx['item']); let b7 = text(ctx['item']);
const b8 = text(\` \`); let b8 = text(\` \`);
const b9 = text(ctx['item_value']); let b9 = text(ctx['item_value']);
const b10 = text(\`] \`); let b10 = text(\`] \`);
c_block2[i1] = withKey(multi([b4, b5, b6, b7, b8, b9, b10]), key1); 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]); return block1([], [b2]);
} }
}" }"
@@ -118,13 +118,13 @@ exports[`t-foreach iterate, position 1`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx); 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++) { for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`elem\`] = v_block2[i1]; ctx[\`elem\`] = v_block2[i1];
ctx[\`elem_first\`] = i1 === 0; ctx[\`elem_first\`] = i1 === 0;
ctx[\`elem_last\`] = i1 === v_block2.length - 1; ctx[\`elem_last\`] = i1 === v_block2.length - 1;
ctx[\`elem_index\`] = i1; ctx[\`elem_index\`] = i1;
const key1 = ctx['elem']; let key1 = ctx['elem'];
let b4,b5,b6,b7,b8,b9; let b4,b5,b6,b7,b8,b9;
b4 = text(\` -\`); b4 = text(\` -\`);
if (ctx['elem_first']) { if (ctx['elem_first']) {
@@ -138,7 +138,7 @@ exports[`t-foreach iterate, position 1`] = `
b9 = text(\`) \`); b9 = text(\`) \`);
c_block2[i1] = withKey(multi([b4, b5, b6, b7, b8, b9]), key1); 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]); return block1([], [b2]);
} }
}" }"
@@ -154,13 +154,13 @@ exports[`t-foreach simple iteration (in a node) 1`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx); 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++) { for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`item\`] = v_block2[i1]; ctx[\`item\`] = v_block2[i1];
const key1 = ctx['item']; let key1 = ctx['item'];
c_block2[i1] = withKey(text(ctx['item']), key1); c_block2[i1] = withKey(text(ctx['item']), key1);
} }
const b2 = list(c_block2); let b2 = list(c_block2);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -174,10 +174,10 @@ exports[`t-foreach simple iteration 1`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx); 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++) { for (let i1 = 0; i1 < l_block1; i1++) {
ctx[\`item\`] = v_block1[i1]; ctx[\`item\`] = v_block1[i1];
const key1 = ctx['item']; let key1 = ctx['item'];
c_block1[i1] = withKey(text(ctx['item']), key1); c_block1[i1] = withKey(text(ctx['item']), key1);
} }
return list(c_block1); return list(c_block1);
@@ -196,14 +196,14 @@ exports[`t-foreach simple iteration with two nodes inside 1`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx); 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++) { for (let i1 = 0; i1 < l_block1; i1++) {
ctx[\`item\`] = v_block1[i1]; ctx[\`item\`] = v_block1[i1];
const key1 = ctx['item']; let key1 = ctx['item'];
let txt1 = ctx['item']; let txt1 = ctx['item'];
const b3 = block3([txt1]); let b3 = block3([txt1]);
let txt2 = ctx['item']; let txt2 = ctx['item'];
const b4 = block4([txt2]); let b4 = block4([txt2]);
c_block1[i1] = withKey(multi([b3, b4]), key1); c_block1[i1] = withKey(multi([b3, b4]), key1);
} }
return list(c_block1); 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 = Object.create(ctx);
ctx[isBoundary] = 1 ctx[isBoundary] = 1
ctx = Object.create(ctx); 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++) { for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`a\`] = v_block2[i1]; ctx[\`a\`] = v_block2[i1];
ctx[\`a_first\`] = i1 === 0; ctx[\`a_first\`] = i1 === 0;
ctx[\`a_last\`] = i1 === v_block2.length - 1; ctx[\`a_last\`] = i1 === v_block2.length - 1;
ctx[\`a_index\`] = i1; ctx[\`a_index\`] = i1;
ctx[\`a_value\`] = k_block2[i1]; ctx[\`a_value\`] = k_block2[i1];
const key1 = ctx['a']; let key1 = ctx['a'];
ctx = Object.create(ctx); 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++) { for (let i2 = 0; i2 < l_block4; i2++) {
ctx[\`b\`] = v_block4[i2]; ctx[\`b\`] = v_block4[i2];
ctx[\`b_first\`] = i2 === 0; ctx[\`b_first\`] = i2 === 0;
ctx[\`b_last\`] = i2 === v_block4.length - 1; ctx[\`b_last\`] = i2 === v_block4.length - 1;
ctx[\`b_index\`] = i2; ctx[\`b_index\`] = i2;
ctx[\`b_value\`] = k_block4[i2]; ctx[\`b_value\`] = k_block4[i2];
const key2 = ctx['b']; let key2 = ctx['b'];
ctx = Object.create(ctx); ctx = Object.create(ctx);
ctx[isBoundary] = 1; ctx[isBoundary] = 1;
setContextValue(ctx, \\"c\\", 'x'+'_'+ctx['a']+'_'+ctx['b']); 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__;
} }
ctx = ctx.__proto__; ctx = ctx.__proto__;
const b4 = list(c_block4); let b4 = list(c_block4);
let txt1 = ctx['c']; let txt1 = ctx['c'];
const b6 = block6([txt1]); let b6 = block6([txt1]);
c_block2[i1] = withKey(multi([b4, b6]), key1); c_block2[i1] = withKey(multi([b4, b6]), key1);
} }
ctx = ctx.__proto__; ctx = ctx.__proto__;
const b2 = list(c_block2); let b2 = list(c_block2);
let txt2 = ctx['a']; let txt2 = ctx['a'];
let txt3 = ctx['b']; let txt3 = ctx['b'];
let txt4 = ctx['c']; 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; let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const b2 = text(\` [\`); let b2 = text(\` [\`);
const b3 = text(ctx['a']); let b3 = text(ctx['a']);
const b4 = text(\`] [\`); let b4 = text(\`] [\`);
const b5 = text(ctx['b']); let b5 = text(ctx['b']);
const b6 = text(\`] [\`); let b6 = text(\`] [\`);
const b7 = text(ctx['c']); let b7 = text(ctx['c']);
const b8 = text(\`] \`); let b8 = text(\`] \`);
return multi([b2, b3, b4, b5, b6, b7, b8]); 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 = \\"\\") { return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx); 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++) { for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`a\`] = v_block2[i1]; ctx[\`a\`] = v_block2[i1];
ctx[\`a_first\`] = i1 === 0; ctx[\`a_first\`] = i1 === 0;
ctx[\`a_last\`] = i1 === v_block2.length - 1; ctx[\`a_last\`] = i1 === v_block2.length - 1;
ctx[\`a_index\`] = i1; ctx[\`a_index\`] = i1;
ctx[\`a_value\`] = k_block2[i1]; ctx[\`a_value\`] = k_block2[i1];
const key1 = ctx['a']; let key1 = ctx['a'];
ctx = Object.create(ctx); 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++) { for (let i2 = 0; i2 < l_block4; i2++) {
ctx[\`b\`] = v_block4[i2]; ctx[\`b\`] = v_block4[i2];
ctx[\`b_first\`] = i2 === 0; ctx[\`b_first\`] = i2 === 0;
ctx[\`b_last\`] = i2 === v_block4.length - 1; ctx[\`b_last\`] = i2 === v_block4.length - 1;
ctx[\`b_index\`] = i2; ctx[\`b_index\`] = i2;
ctx[\`b_value\`] = k_block4[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); c_block4[i2] = withKey(callTemplate_1.call(this, ctx, node, key + \`__1__\${key1}__\${key2}\`), key2);
} }
ctx = ctx.__proto__; ctx = ctx.__proto__;
const b4 = list(c_block4); let b4 = list(c_block4);
let txt1 = ctx['c']; let txt1 = ctx['c'];
const b6 = block6([txt1]); let b6 = block6([txt1]);
c_block2[i1] = withKey(multi([b4, b6]), key1); c_block2[i1] = withKey(multi([b4, b6]), key1);
} }
ctx = ctx.__proto__; ctx = ctx.__proto__;
const b2 = list(c_block2); let b2 = list(c_block2);
let txt2 = ctx['a']; let txt2 = ctx['a'];
let txt3 = ctx['b']; let txt3 = ctx['b'];
let txt4 = ctx['c']; 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 = Object.create(ctx);
ctx[isBoundary] = 1 ctx[isBoundary] = 1
setContextValue(ctx, \\"c\\", 'x'+'_'+ctx['a']+'_'+ctx['b']); setContextValue(ctx, \\"c\\", 'x'+'_'+ctx['a']+'_'+ctx['b']);
const b2 = text(\` [\`); let b2 = text(\` [\`);
const b3 = text(ctx['a']); let b3 = text(ctx['a']);
const b4 = text(\`] [\`); let b4 = text(\`] [\`);
const b5 = text(ctx['b']); let b5 = text(ctx['b']);
const b6 = text(\`] [\`); let b6 = text(\`] [\`);
const b7 = text(ctx['c']); let b7 = text(ctx['c']);
const b8 = text(\`] \`); let b8 = text(\`] \`);
return multi([b2, b3, b4, b5, b6, b7, b8]); 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 = \\"\\") { return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx); 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++) { for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`number\`] = v_block2[i1]; ctx[\`number\`] = v_block2[i1];
const key1 = ctx['number']; let key1 = ctx['number'];
ctx = Object.create(ctx); 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++) { for (let i2 = 0; i2 < l_block3; i2++) {
ctx[\`letter\`] = v_block3[i2]; ctx[\`letter\`] = v_block3[i2];
const key2 = ctx['letter']; let key2 = ctx['letter'];
const b5 = text(\` [\`); let b5 = text(\` [\`);
const b6 = text(ctx['number']); let b6 = text(ctx['number']);
const b7 = text(ctx['letter']); let b7 = text(ctx['letter']);
const b8 = text(\`] \`); let b8 = text(\`] \`);
c_block3[i2] = withKey(multi([b5, b6, b7, b8]), key2); c_block3[i2] = withKey(multi([b5, b6, b7, b8]), key2);
} }
ctx = ctx.__proto__; ctx = ctx.__proto__;
c_block2[i1] = withKey(list(c_block3), key1); c_block2[i1] = withKey(list(c_block3), key1);
} }
const b2 = list(c_block2); let b2 = list(c_block2);
return block1([], [b2]); 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 = \\"\\") { return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx); 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++) { for (let i1 = 0; i1 < l_block1; i1++) {
ctx[\`elem\`] = v_block1[i1]; ctx[\`elem\`] = v_block1[i1];
const key1 = ctx['elem'].id; let key1 = ctx['elem'].id;
let b3; let b3;
if (ctx['elem'].id<3) { if (ctx['elem'].id<3) {
let txt1 = ctx['elem'].text; 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 = \\"\\") { return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx); 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++) { for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`elem\`] = v_block2[i1]; ctx[\`elem\`] = v_block2[i1];
const key1 = ctx['elem'].id; let key1 = ctx['elem'].id;
let b4; let b4;
if (ctx['elem'].id<3) { if (ctx['elem'].id<3) {
let txt1 = ctx['elem'].text; 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); c_block2[i1] = withKey(multi([b4]), key1);
} }
const b2 = list(c_block2); let b2 = list(c_block2);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -450,13 +450,13 @@ exports[`t-foreach t-key on t-foreach 1`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx); 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++) { for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`thing\`] = v_block2[i1]; ctx[\`thing\`] = v_block2[i1];
const key1 = ctx['thing']; let key1 = ctx['thing'];
c_block2[i1] = withKey(block3(), key1); c_block2[i1] = withKey(block3(), key1);
} }
const b2 = list(c_block2); let b2 = list(c_block2);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -473,15 +473,15 @@ exports[`t-foreach throws error if invalid loop expression 1`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx); 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++) { for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`item\`] = v_block2[i1]; ctx[\`item\`] = v_block2[i1];
ctx[\`item_index\`] = i1; ctx[\`item_index\`] = i1;
const key1 = ctx['item']; let key1 = ctx['item'];
const tKey_1 = ctx['item_index']; const tKey_1 = ctx['item_index'];
c_block2[i1] = withKey(block3(), tKey_1 + key1); c_block2[i1] = withKey(block3(), tKey_1 + key1);
} }
const b2 = list(c_block2); let b2 = list(c_block2);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -500,12 +500,12 @@ exports[`t-foreach with t-memo 1`] = `
let cache = ctx.cache || {}; let cache = ctx.cache || {};
let nextCache = ctx.cache = {}; let nextCache = ctx.cache = {};
ctx = Object.create(ctx); 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++) { for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`item\`] = v_block2[i1]; ctx[\`item\`] = v_block2[i1];
const key1 = ctx['item'].id; let key1 = ctx['item'].id;
const memo1 = [ctx['item'].x]; let memo1 = [ctx['item'].x]
const vnode1 = cache[key1];; let vnode1 = cache[key1];
if (vnode1) { if (vnode1) {
if (shallowEqual(vnode1.memo, memo1)) { if (shallowEqual(vnode1.memo, memo1)) {
c_block2[i1] = vnode1; c_block2[i1] = vnode1;
@@ -518,7 +518,7 @@ exports[`t-foreach with t-memo 1`] = `
c_block2[i1] = withKey(block3([txt1, txt2]), key1); c_block2[i1] = withKey(block3([txt1, txt2]), key1);
nextCache[key1] = Object.assign(c_block2[i1], {memo: memo1}); nextCache[key1] = Object.assign(c_block2[i1], {memo: memo1});
} }
const b2 = list(c_block2); let b2 = list(c_block2);
return block1([], [b2]); 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 = \\"\\") { return function template(ctx, node, key = \\"\\") {
let b2; let b2;
if (ctx['condition']) { if (ctx['condition']) {
const b3 = block3(); let b3 = block3();
const b4 = block4(); let b4 = block4();
b2 = multi([b3, b4]); b2 = multi([b3, b4]);
} }
return multi([b2]); 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 = \\"\\") { return function template(ctx, node, key = \\"\\") {
let b2; let b2;
if (ctx['condition']) { if (ctx['condition']) {
const b3 = block3(); let b3 = block3();
const b4 = block4(); let b4 = block4();
b2 = multi([b3, b4]); b2 = multi([b3, b4]);
} }
return block1([], [b2]); 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 = \\"\\") { return function template(ctx, node, key = \\"\\") {
let b2; let b2;
if (ctx['condition']) { if (ctx['condition']) {
const b3 = block3(); let b3 = block3();
const b4 = block4(); let b4 = block4();
b2 = multi([b3, b4]); b2 = multi([b3, b4]);
} }
let txt1 = ctx['text']; let txt1 = ctx['text'];
@@ -318,8 +318,8 @@ exports[`t-if t-if and t-else with two nodes 1`] = `
if (ctx['condition']) { if (ctx['condition']) {
b2 = text(\`1\`); b2 = text(\`1\`);
} else { } else {
const b4 = block4(); let b4 = block4();
const b5 = block5(); let b5 = block5();
b3 = multi([b4, b5]); b3 = multi([b4, b5]);
} }
return multi([b2, b3]); return multi([b2, b3]);
@@ -526,8 +526,8 @@ exports[`t-if two t-ifs next to each other 1`] = `
b2 = block2([txt1]); b2 = block2([txt1]);
} }
if (ctx['condition']) { if (ctx['condition']) {
const b4 = block4(); let b4 = block4();
const b5 = block5(); let b5 = block5();
b3 = multi([b4, b5]); b3 = multi([b4, b5]);
} }
return block1([], [b2, b3]); return block1([], [b2, b3]);
@@ -56,14 +56,14 @@ exports[`t-key t-key directive in a list 1`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx); 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++) { for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`beer\`] = v_block2[i1]; ctx[\`beer\`] = v_block2[i1];
const key1 = ctx['beer'].id; let key1 = ctx['beer'].id;
let txt1 = ctx['beer'].name; let txt1 = ctx['beer'].name;
c_block2[i1] = withKey(block3([txt1]), key1); c_block2[i1] = withKey(block3([txt1]), key1);
} }
const b2 = list(c_block2); let b2 = list(c_block2);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
+30 -60
View File
@@ -9,7 +9,7 @@ exports[`t-out literal 1`] = `
let block1 = createBlock(\`<span><block-child-0/></span>\`); let block1 = createBlock(\`<span><block-child-0/></span>\`);
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const b2 = safeOutput('ok'); let b2 = safeOutput('ok');
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -40,9 +40,9 @@ exports[`t-out multiple calls to t-out 1`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx); ctx = Object.create(ctx);
ctx[isBoundary] = 1; ctx[isBoundary] = 1;
const b2 = block2(); let b2 = block2();
ctx[zero] = b2; 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]); 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>\`); let block1 = createBlock(\`<div><block-child-0/><div>Greeter</div><block-child-1/></div>\`);
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const b2 = ctx[zero]; let b2 = ctx[zero];
const b3 = ctx[zero]; let b3 = ctx[zero];
return block1([], [b2, b3]); return block1([], [b2, b3]);
} }
}" }"
@@ -73,7 +73,7 @@ exports[`t-out not escaping 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`); let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const b2 = safeOutput(ctx['var']); let b2 = safeOutput(ctx['var']);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -92,9 +92,9 @@ exports[`t-out t-out 0 1`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx); ctx = Object.create(ctx);
ctx[isBoundary] = 1; ctx[isBoundary] = 1;
const b2 = block2(); let b2 = block2();
ctx[zero] = b2; 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]); return block1([], [b3]);
} }
}" }"
@@ -109,7 +109,7 @@ exports[`t-out t-out 0 2`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`); let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const b2 = ctx[zero]; let b2 = ctx[zero];
return block1([], [b2]); 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>\`); let block1 = createBlock(\`<span><span>hello</span><block-child-0/></span>\`);
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const b2 = safeOutput(ctx['var']); let b2 = safeOutput(ctx['var']);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -147,7 +147,7 @@ exports[`t-out t-out bdom 1`] = `
ctx = Object.create(ctx); ctx = Object.create(ctx);
ctx[isBoundary] = 1 ctx[isBoundary] = 1
ctx[\`var\`] = new LazyValue(value1, ctx, node); ctx[\`var\`] = new LazyValue(value1, ctx, node);
const b3 = safeOutput(ctx['var']); let b3 = safeOutput(ctx['var']);
return block1([], [b3]); return block1([], [b3]);
} }
}" }"
@@ -162,7 +162,7 @@ exports[`t-out t-out block 1`] = `
let block1 = createBlock(\`<span><block-child-0/></span>\`); let block1 = createBlock(\`<span><block-child-0/></span>\`);
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const b2 = safeOutput(ctx['bdom']); let b2 = safeOutput(ctx['bdom']);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -177,7 +177,7 @@ exports[`t-out t-out escaped 1`] = `
let block1 = createBlock(\`<span><block-child-0/></span>\`); let block1 = createBlock(\`<span><block-child-0/></span>\`);
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const b2 = safeOutput(ctx['var']); let b2 = safeOutput(ctx['var']);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -192,7 +192,7 @@ exports[`t-out t-out markedup 1`] = `
let block1 = createBlock(\`<span><block-child-0/></span>\`); let block1 = createBlock(\`<span><block-child-0/></span>\`);
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const b2 = safeOutput(ctx['var']); let b2 = safeOutput(ctx['var']);
return block1([], [b2]); 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>\`); let block1 = createBlock(\`<span><block-child-0/></span>\`);
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const b3 = text(\`nope\`); let b3 = text(\`nope\`);
const b2 = withDefault(safeOutput(ctx['var']), b3); let b2 = withDefault(safeOutput(ctx['var']), b3);
return block1([], [b2]); 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>\`); let block3 = createBlock(\`<div>nope</div>\`);
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const b3 = block3(); let b3 = block3();
const b2 = withDefault(safeOutput(ctx['var']), b3); let b2 = withDefault(safeOutput(ctx['var']), b3);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -240,7 +240,7 @@ exports[`t-out t-out switch escaped 1`] = `
let block1 = createBlock(\`<span><block-child-0/></span>\`); let block1 = createBlock(\`<span><block-child-0/></span>\`);
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const b2 = safeOutput(ctx['var']); let b2 = safeOutput(ctx['var']);
return block1([], [b2]); 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>\`); let block1 = createBlock(\`<span><block-child-0/></span>\`);
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const b2 = safeOutput(ctx['var']); let b2 = safeOutput(ctx['var']);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -270,7 +270,7 @@ exports[`t-out t-out switch markup 1`] = `
let block1 = createBlock(\`<span><block-child-0/></span>\`); let block1 = createBlock(\`<span><block-child-0/></span>\`);
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const b2 = safeOutput(ctx['var']); let b2 = safeOutput(ctx['var']);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -297,10 +297,10 @@ exports[`t-out t-out switch markup on bdom 1`] = `
let b3,b5; let b3,b5;
ctx[\`bdom\`] = new LazyValue(value1, ctx, node); ctx[\`bdom\`] = new LazyValue(value1, ctx, node);
if (ctx['hasBdom']) { if (ctx['hasBdom']) {
const b4 = safeOutput(ctx['bdom']); let b4 = safeOutput(ctx['bdom']);
b3 = block3([], [b4]); b3 = block3([], [b4]);
} else { } else {
const b6 = safeOutput(ctx['var']); let b6 = safeOutput(ctx['var']);
b5 = block5([], [b6]); b5 = block5([], [b6]);
} }
return block1([], [b3, b5]); 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>\`); let block1 = createBlock(\`<span><block-child-0/></span>\`);
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const b2 = safeOutput(ctx['var']); let b2 = safeOutput(ctx['var']);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -344,7 +344,7 @@ exports[`t-out t-out with arbitrary object 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`); let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const b2 = safeOutput(ctx['var']); let b2 = safeOutput(ctx['var']);
return block1([], [b2]); 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>\`); let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const b2 = safeOutput(ctx['var']); let b2 = safeOutput(ctx['var']);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -374,7 +374,7 @@ exports[`t-out t-out with comment 1`] = `
let block1 = createBlock(\`<span><block-child-0/></span>\`); let block1 = createBlock(\`<span><block-child-0/></span>\`);
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const b2 = safeOutput(ctx['var']); let b2 = safeOutput(ctx['var']);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -401,37 +401,7 @@ exports[`t-out variable 1`] = `
let block1 = createBlock(\`<span><block-child-0/></span>\`); let block1 = createBlock(\`<span><block-child-0/></span>\`);
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const b2 = safeOutput(ctx['var']); let 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']);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -446,7 +416,7 @@ exports[`t-raw is deprecated should warn 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`); let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const b2 = safeOutput(ctx['var']); let b2 = safeOutput(ctx['var']);
return block1([], [b2]); 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>\`); let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const b2 = safeOutput(ctx['var']); let b2 = safeOutput(ctx['var']);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -41,7 +41,7 @@ exports[`t-ref ref in a t-call 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`); let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") { 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]); return block1([], [b2]);
} }
}" }"
@@ -94,17 +94,17 @@ exports[`t-ref refs in a loop 1`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const refs = ctx.__owl__.refs; const refs = ctx.__owl__.refs;
ctx = Object.create(ctx); 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++) { for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`item\`] = v_block2[i1]; ctx[\`item\`] = v_block2[i1];
const key1 = ctx['item']; let key1 = ctx['item'];
const tKey_1 = ctx['item']; const tKey_1 = ctx['item'];
const v1 = ctx['item']; const v1 = ctx['item'];
let ref1 = (el) => refs[\`\${v1}\`] = el; let ref1 = (el) => refs[\`\${v1}\`] = el;
let txt1 = ctx['item']; let txt1 = ctx['item'];
c_block2[i1] = withKey(block3([ref1, txt1]), tKey_1 + key1); c_block2[i1] = withKey(block3([ref1, txt1]), tKey_1 + key1);
} }
const b2 = list(c_block2); let b2 = list(c_block2);
return block1([], [b2]); 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'); setContextValue(ctx, \\"v1\\", 'before');
ctx[\`v2\`] = new LazyValue(value1, ctx, node); ctx[\`v2\`] = new LazyValue(value1, ctx, node);
setContextValue(ctx, \\"v1\\", 'after'); setContextValue(ctx, \\"v1\\", 'after');
const b3 = safeOutput(ctx['v2']); let b3 = safeOutput(ctx['v2']);
return block1([], [b3]); return block1([], [b3]);
} }
}" }"
@@ -228,7 +228,7 @@ exports[`t-set t-set can't alter from within callee 1`] = `
ctx[isBoundary] = 1 ctx[isBoundary] = 1
setContextValue(ctx, \\"iter\\", 'source'); setContextValue(ctx, \\"iter\\", 'source');
let txt1 = ctx['iter']; 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']; let txt2 = ctx['iter'];
return block1([txt1, txt2], [b2]); 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 = Object.create(ctx);
ctx[isBoundary] = 1; ctx[isBoundary] = 1;
setContextValue(ctx, \\"iter\\", 'inCall'); 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__; ctx = ctx.__proto__;
let txt2 = ctx['iter']; let txt2 = ctx['iter'];
return block1([txt1, txt2], [b2]); return block1([txt1, txt2], [b2]);
@@ -349,16 +349,16 @@ exports[`t-set t-set outside modified in t-foreach 1`] = `
ctx[isBoundary] = 1 ctx[isBoundary] = 1
setContextValue(ctx, \\"iter\\", 0); setContextValue(ctx, \\"iter\\", 0);
ctx = Object.create(ctx); 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++) { for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`val\`] = v_block2[i1]; ctx[\`val\`] = v_block2[i1];
const key1 = ctx['val']; let key1 = ctx['val'];
let txt1 = ctx['iter']; let txt1 = ctx['iter'];
c_block2[i1] = withKey(block3([txt1]), key1); c_block2[i1] = withKey(block3([txt1]), key1);
setContextValue(ctx, \\"iter\\", ctx['iter']+1); setContextValue(ctx, \\"iter\\", ctx['iter']+1);
} }
ctx = ctx.__proto__; ctx = ctx.__proto__;
const b2 = list(c_block2); let b2 = list(c_block2);
let txt2 = ctx['iter']; let txt2 = ctx['iter'];
return block1([txt2], [b2]); 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 ctx[isBoundary] = 1
setContextValue(ctx, \\"iter\\", 0); setContextValue(ctx, \\"iter\\", 0);
ctx = Object.create(ctx); 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++) { for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`val\`] = v_block2[i1]; ctx[\`val\`] = v_block2[i1];
const key1 = ctx['val']; let key1 = ctx['val'];
let txt1 = ctx['iter']; let txt1 = ctx['iter'];
c_block2[i1] = withKey(block3([txt1]), key1); c_block2[i1] = withKey(block3([txt1]), key1);
setContextValue(ctx, \\"iter\\", ctx['iter']++); setContextValue(ctx, \\"iter\\", ctx['iter']++);
} }
ctx = ctx.__proto__; ctx = ctx.__proto__;
const b2 = list(c_block2); let b2 = list(c_block2);
let txt2 = ctx['iter']; let txt2 = ctx['iter'];
return block1([txt2], [b2]); 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 ctx[isBoundary] = 1
setContextValue(ctx, \\"iter\\", 0); setContextValue(ctx, \\"iter\\", 0);
ctx = Object.create(ctx); 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++) { for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`val\`] = v_block2[i1]; ctx[\`val\`] = v_block2[i1];
const key1 = ctx['val']; let key1 = ctx['val'];
let txt1 = ctx['iter']; let txt1 = ctx['iter'];
c_block2[i1] = withKey(block3([txt1]), key1); c_block2[i1] = withKey(block3([txt1]), key1);
setContextValue(ctx, \\"iter\\", ++ctx['iter']); setContextValue(ctx, \\"iter\\", ++ctx['iter']);
} }
ctx = ctx.__proto__; ctx = ctx.__proto__;
const b2 = list(c_block2); let b2 = list(c_block2);
let txt2 = ctx['iter']; let txt2 = ctx['iter'];
return block1([txt2], [b2]); return block1([txt2], [b2]);
} }
@@ -439,16 +439,16 @@ exports[`t-set t-set should reuse variable if possible 1`] = `
ctx[isBoundary] = 1 ctx[isBoundary] = 1
setContextValue(ctx, \\"v\\", 1); setContextValue(ctx, \\"v\\", 1);
ctx = Object.create(ctx); 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++) { for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`elem\`] = v_block2[i1]; ctx[\`elem\`] = v_block2[i1];
ctx[\`elem_index\`] = i1; ctx[\`elem_index\`] = i1;
const key1 = ctx['elem_index']; let key1 = ctx['elem_index'];
let txt1 = ctx['v']; let txt1 = ctx['v'];
setContextValue(ctx, \\"v\\", ctx['elem']); setContextValue(ctx, \\"v\\", ctx['elem']);
c_block2[i1] = withKey(block3([txt1]), key1); c_block2[i1] = withKey(block3([txt1]), key1);
} }
const b2 = list(c_block2); let b2 = list(c_block2);
return block1([], [b2]); 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>\`); let block1 = createBlock(\`<div><block-text-0/></div>\`);
function value1(ctx, node, key = \\"\\") { function value1(ctx, node, key = \\"\\") {
const b3 = text(ctx['beep']); let b3 = text(ctx['beep']);
const b4 = text(\` boop\`); let b4 = text(\` boop\`);
return multi([b3, b4]); 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)); ctx[\`v2\`] = withDefault(ctx['v3'], new LazyValue(value1, ctx, node));
setContextValue(ctx, \\"v1\\", 'after'); setContextValue(ctx, \\"v1\\", 'after');
setContextValue(ctx, \\"v3\\", true); setContextValue(ctx, \\"v3\\", true);
const b3 = safeOutput(ctx['v2']); let b3 = safeOutput(ctx['v2']);
return block1([], [b3]); 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)); ctx[\`v2\`] = withDefault(ctx['v3'], new LazyValue(value1, ctx, node));
setContextValue(ctx, \\"v1\\", 'after'); setContextValue(ctx, \\"v1\\", 'after');
setContextValue(ctx, \\"v3\\", false); setContextValue(ctx, \\"v3\\", false);
const b3 = safeOutput(ctx['v2']); let b3 = safeOutput(ctx['v2']);
return block1([], [b3]); 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'}/>\`); let block1 = tag => createBlock(\`<\${tag || 'fallback'}/>\`);
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const tag1 = ctx['tag']; let tag1 = ctx['tag'];
return toggler(tag1, block1(tag1)()); return toggler(tag1, block1(tag1)());
} }
}" }"
@@ -22,7 +22,7 @@ exports[`qweb t-tag can update 1`] = `
let block1 = tag => createBlock(\`<\${tag || 't'}/>\`); let block1 = tag => createBlock(\`<\${tag || 't'}/>\`);
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const tag1 = ctx['tag']; let tag1 = ctx['tag'];
return toggler(tag1, block1(tag1)()); return toggler(tag1, block1(tag1)());
} }
}" }"
@@ -36,7 +36,7 @@ exports[`qweb t-tag simple usecases 1`] = `
let block1 = tag => createBlock(\`<\${tag || 't'}/>\`); let block1 = tag => createBlock(\`<\${tag || 't'}/>\`);
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const tag1 = 'div'; let tag1 = 'div';
return toggler(tag1, block1(tag1)()); 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'}>\`); let block1 = tag => createBlock(\`<\${tag || 't'}>text</\${tag || 't'}>\`);
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const tag1 = ctx['tag']; let tag1 = ctx['tag'];
return toggler(tag1, block1(tag1)()); 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'}>\`); let block1 = tag => createBlock(\`<\${tag || 't'} class=\\"blueberry\\" taste=\\"raspberry\\">gooseberry</\${tag || 't'}>\`);
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const tag1 = ctx['tag']; let tag1 = ctx['tag'];
return toggler(tag1, block1(tag1)()); 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'}>\`); let block1 = tag => createBlock(\`<\${tag || 't'}> pear <span>apple</span> strawberry </\${tag || 't'}>\`);
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const tag1 = ctx['tag']; let tag1 = ctx['tag'];
return toggler(tag1, block1(tag1)()); 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'}>\`); let block2 = tag => createBlock(\`<\${tag || 't'}>baz</\${tag || 't'}>\`);
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const tag1 = ctx['outer']; let tag1 = ctx['outer'];
const tag2 = ctx['inner']; let tag2 = ctx['inner'];
const b2 = toggler(tag2, block2(tag2)()); let b2 = toggler(tag2, block2(tag2)());
return toggler(tag1, block1(tag1)([], [b2])); 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'}>\`); let block3 = tag => createBlock(\`<\${tag || 't'}>baz</\${tag || 't'}>\`);
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const tag1 = ctx['brother']; let tag1 = ctx['brother'];
const b2 = toggler(tag1, block2(tag1)()); let b2 = toggler(tag1, block2(tag1)());
const tag2 = ctx['brother']; let tag2 = ctx['brother'];
const b3 = toggler(tag2, block3(tag2)()); let b3 = toggler(tag2, block3(tag2)());
return multi([b2, b3]); return multi([b2, b3]);
} }
}" }"
@@ -50,7 +50,7 @@ exports[`loading templates can load a few templates from a xml string 1`] = `
let block1 = createBlock(\`<ul><block-child-0/></ul>\`); let block1 = createBlock(\`<ul><block-child-0/></ul>\`);
return function template(ctx, node, key = \\"\\") { 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]); return block1([], [b2]);
} }
}" }"
@@ -65,8 +65,8 @@ exports[`loading templates can load a few templates from a xml string 2`] = `
let block3 = createBlock(\`<li>foo</li>\`); let block3 = createBlock(\`<li>foo</li>\`);
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const b2 = block2(); let b2 = block2();
const b3 = block3(); let b3 = block3();
return multi([b2, b3]); return multi([b2, b3]);
} }
}" }"
@@ -82,7 +82,7 @@ exports[`loading templates can load a few templates from an XMLDocument 1`] = `
let block1 = createBlock(\`<ul><block-child-0/></ul>\`); let block1 = createBlock(\`<ul><block-child-0/></ul>\`);
return function template(ctx, node, key = \\"\\") { 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]); return block1([], [b2]);
} }
}" }"
@@ -97,8 +97,8 @@ exports[`loading templates can load a few templates from an XMLDocument 2`] = `
let block3 = createBlock(\`<li>foo</li>\`); let block3 = createBlock(\`<li>foo</li>\`);
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const b2 = block2(); let b2 = block2();
const b3 = block3(); let b3 = block3();
return multi([b2, b3]); return multi([b2, b3]);
} }
}" }"
@@ -1,11 +1,11 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP // 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 "function anonymous(bdom, helpers
) { ) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom; 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 function template(ctx, node, key = \\"\\") {
return block1(); 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'");
});
});
+5 -5
View File
@@ -65,14 +65,14 @@ describe("tokenizer", () => {
}); });
test("strings", () => { test("strings", () => {
expect(() => tokenize("'")).toThrow("Tokenizer error: could not tokenize `'`"); expect(() => tokenize("'")).toThrow("Invalid expression");
expect(() => tokenize("'\\")).toThrow("Tokenizer error: could not tokenize `'\\`"); expect(() => tokenize("'\\")).toThrow("Invalid expression");
expect(() => tokenize("'\\'")).toThrow("Tokenizer error: could not tokenize `'\\'`"); 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("'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("Invalid expression");
expect(() => tokenize('"\\"')).toThrow('Tokenizer error: could not tokenize `"\\"`'); 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('"hello ged"}')).toEqual([ expect(tokenize('"hello ged"}')).toEqual([
{ type: "VALUE", value: '"hello ged"' }, { type: "VALUE", value: '"hello ged"' },
+145 -267
View File
@@ -42,8 +42,8 @@ describe("qweb parser", () => {
tag: "div", tag: "div",
dynamicTag: null, dynamicTag: null,
content: [], content: [],
attrs: null, attrs: {},
on: null, on: {},
ref: null, ref: null,
model: null, model: null,
ns: null, ns: null,
@@ -69,8 +69,8 @@ describe("qweb parser", () => {
type: ASTType.DomNode, type: ASTType.DomNode,
tag: "div", tag: "div",
dynamicTag: null, dynamicTag: null,
attrs: null, attrs: {},
on: null, on: {},
ref: null, ref: null,
model: null, model: null,
content: [], content: [],
@@ -83,8 +83,8 @@ describe("qweb parser", () => {
type: ASTType.DomNode, type: ASTType.DomNode,
tag: "div", tag: "div",
dynamicTag: null, dynamicTag: null,
attrs: null, attrs: {},
on: null, on: {},
ref: null, ref: null,
model: null, model: null,
content: [{ type: ASTType.Text, value: "some text" }], content: [{ type: ASTType.Text, value: "some text" }],
@@ -97,8 +97,8 @@ describe("qweb parser", () => {
type: ASTType.DomNode, type: ASTType.DomNode,
tag: "div", tag: "div",
dynamicTag: null, dynamicTag: null,
attrs: null, attrs: {},
on: null, on: {},
ref: null, ref: null,
model: null, model: null,
ns: null, ns: null,
@@ -108,8 +108,8 @@ describe("qweb parser", () => {
type: ASTType.DomNode, type: ASTType.DomNode,
tag: "span", tag: "span",
dynamicTag: null, dynamicTag: null,
attrs: null, attrs: {},
on: null, on: {},
ref: null, ref: null,
model: null, model: null,
ns: null, ns: null,
@@ -127,8 +127,8 @@ describe("qweb parser", () => {
type: ASTType.DomNode, type: ASTType.DomNode,
tag: "div", tag: "div",
dynamicTag: null, dynamicTag: null,
attrs: null, attrs: {},
on: null, on: {},
ref: null, ref: null,
model: null, model: null,
ns: null, ns: null,
@@ -138,8 +138,8 @@ describe("qweb parser", () => {
type: ASTType.DomNode, type: ASTType.DomNode,
tag: "span", tag: "span",
dynamicTag: null, dynamicTag: null,
attrs: null, attrs: {},
on: null, on: {},
ref: null, ref: null,
model: null, model: null,
ns: null, ns: null,
@@ -155,8 +155,8 @@ describe("qweb parser", () => {
type: ASTType.DomNode, type: ASTType.DomNode,
tag: "div", tag: "div",
dynamicTag: null, dynamicTag: null,
attrs: null, attrs: {},
on: null, on: {},
ref: null, ref: null,
model: null, model: null,
ns: null, ns: null,
@@ -180,8 +180,8 @@ describe("qweb parser", () => {
type: ASTType.DomNode, type: ASTType.DomNode,
tag: "div", tag: "div",
dynamicTag: null, dynamicTag: null,
attrs: null, attrs: {},
on: null, on: {},
ref: null, ref: null,
model: null, model: null,
ns: null, ns: null,
@@ -200,8 +200,8 @@ describe("qweb parser", () => {
type: ASTType.DomNode, type: ASTType.DomNode,
tag: "div", tag: "div",
dynamicTag: null, dynamicTag: null,
attrs: null, attrs: {},
on: null, on: {},
ref: null, ref: null,
model: null, model: null,
ns: null, ns: null,
@@ -222,8 +222,8 @@ describe("qweb parser", () => {
type: ASTType.DomNode, type: ASTType.DomNode,
tag: "div", tag: "div",
dynamicTag: null, dynamicTag: null,
attrs: null, attrs: {},
on: null, on: {},
ref: null, ref: null,
model: null, model: null,
ns: null, ns: null,
@@ -245,8 +245,8 @@ describe("qweb parser", () => {
type: ASTType.DomNode, type: ASTType.DomNode,
tag: "span", tag: "span",
dynamicTag: null, dynamicTag: null,
attrs: null, attrs: {},
on: null, on: {},
ref: null, ref: null,
model: null, model: null,
ns: null, ns: null,
@@ -262,7 +262,7 @@ describe("qweb parser", () => {
tag: "div", tag: "div",
dynamicTag: null, dynamicTag: null,
attrs: { class: "abc" }, attrs: { class: "abc" },
on: null, on: {},
ref: null, ref: null,
model: null, model: null,
ns: null, ns: null,
@@ -294,7 +294,7 @@ describe("qweb parser", () => {
dynamicTag: null, dynamicTag: null,
model: null, model: null,
ns: null, ns: null,
on: null, on: {},
ref: null, ref: null,
tag: "circle", tag: "circle",
type: 2, type: 2,
@@ -303,7 +303,7 @@ describe("qweb parser", () => {
dynamicTag: null, dynamicTag: null,
model: null, model: null,
ns: "http://www.w3.org/2000/svg", ns: "http://www.w3.org/2000/svg",
on: null, on: {},
ref: null, ref: null,
tag: "svg", tag: "svg",
type: 2, type: 2,
@@ -311,7 +311,7 @@ describe("qweb parser", () => {
expect( expect(
parse(`<g><circle cx="50" cy="50" r="4" stroke="green" stroke-width="1" fill="yellow"/></g>`) parse(`<g><circle cx="50" cy="50" r="4" stroke="green" stroke-width="1" fill="yellow"/></g>`)
).toEqual({ ).toEqual({
attrs: null, attrs: {},
content: [ content: [
{ {
attrs: { attrs: {
@@ -326,7 +326,7 @@ describe("qweb parser", () => {
dynamicTag: null, dynamicTag: null,
model: null, model: null,
ns: null, ns: null,
on: null, on: {},
ref: null, ref: null,
tag: "circle", tag: "circle",
type: 2, type: 2,
@@ -335,7 +335,7 @@ describe("qweb parser", () => {
dynamicTag: null, dynamicTag: null,
model: null, model: null,
ns: "http://www.w3.org/2000/svg", ns: "http://www.w3.org/2000/svg",
on: null, on: {},
ref: null, ref: null,
tag: "g", tag: "g",
type: 2, type: 2,
@@ -347,16 +347,16 @@ describe("qweb parser", () => {
type: 2, type: 2,
tag: "div", tag: "div",
dynamicTag: null, dynamicTag: null,
attrs: null, attrs: {},
on: null, on: {},
ref: null, ref: null,
content: [ content: [
{ {
type: 2, type: 2,
tag: "pre", tag: "pre",
dynamicTag: null, dynamicTag: null,
attrs: null, attrs: {},
on: null, on: {},
ref: null, ref: null,
content: [], content: [],
model: null, model: null,
@@ -390,8 +390,8 @@ describe("qweb parser", () => {
type: ASTType.DomNode, type: ASTType.DomNode,
tag: "span", tag: "span",
dynamicTag: null, dynamicTag: null,
attrs: null, attrs: {},
on: null, on: {},
ref: null, ref: null,
model: null, model: null,
ns: null, ns: null,
@@ -412,8 +412,8 @@ describe("qweb parser", () => {
type: ASTType.DomNode, type: ASTType.DomNode,
tag: "div", tag: "div",
dynamicTag: null, dynamicTag: null,
attrs: null, attrs: {},
on: null, on: {},
ref: null, ref: null,
model: null, model: null,
ns: null, ns: null,
@@ -454,8 +454,8 @@ describe("qweb parser", () => {
type: ASTType.DomNode, type: ASTType.DomNode,
tag: "div", tag: "div",
dynamicTag: null, dynamicTag: null,
attrs: null, attrs: {},
on: null, on: {},
ref: null, ref: null,
model: null, model: null,
ns: null, ns: null,
@@ -468,8 +468,8 @@ describe("qweb parser", () => {
type: ASTType.DomNode, type: ASTType.DomNode,
tag: "div", tag: "div",
dynamicTag: null, dynamicTag: null,
attrs: null, attrs: {},
on: null, on: {},
ref: null, ref: null,
model: null, model: null,
ns: null, ns: null,
@@ -488,8 +488,8 @@ describe("qweb parser", () => {
type: ASTType.DomNode, type: ASTType.DomNode,
tag: "div", tag: "div",
dynamicTag: null, dynamicTag: null,
attrs: null, attrs: {},
on: null, on: {},
ref: null, ref: null,
model: null, model: null,
ns: null, ns: null,
@@ -529,8 +529,8 @@ describe("qweb parser", () => {
type: ASTType.DomNode, type: ASTType.DomNode,
tag: "div", tag: "div",
dynamicTag: null, dynamicTag: null,
attrs: null, attrs: {},
on: null, on: {},
ref: null, ref: null,
model: null, model: null,
ns: null, ns: null,
@@ -606,8 +606,8 @@ describe("qweb parser", () => {
type: ASTType.DomNode, type: ASTType.DomNode,
tag: "div", tag: "div",
dynamicTag: null, dynamicTag: null,
attrs: null, attrs: {},
on: null, on: {},
ref: null, ref: null,
model: null, model: null,
ns: null, ns: null,
@@ -625,8 +625,8 @@ describe("qweb parser", () => {
type: ASTType.DomNode, type: ASTType.DomNode,
tag: "h1", tag: "h1",
dynamicTag: null, dynamicTag: null,
attrs: null, attrs: {},
on: null, on: {},
ref: null, ref: null,
model: null, model: null,
ns: null, ns: null,
@@ -638,8 +638,8 @@ describe("qweb parser", () => {
type: ASTType.DomNode, type: ASTType.DomNode,
tag: "h2", tag: "h2",
dynamicTag: null, dynamicTag: null,
attrs: null, attrs: {},
on: null, on: {},
ref: null, ref: null,
model: null, model: null,
ns: null, ns: null,
@@ -684,8 +684,8 @@ describe("qweb parser", () => {
body: [ body: [
{ {
type: ASTType.DomNode, type: ASTType.DomNode,
attrs: null, attrs: {},
on: null, on: {},
tag: "div", tag: "div",
dynamicTag: null, dynamicTag: null,
ref: null, ref: null,
@@ -704,8 +704,8 @@ describe("qweb parser", () => {
body: [ body: [
{ {
type: ASTType.DomNode, type: ASTType.DomNode,
attrs: null, attrs: {},
on: null, on: {},
tag: "div", tag: "div",
dynamicTag: null, dynamicTag: null,
ref: null, ref: null,
@@ -741,8 +741,8 @@ describe("qweb parser", () => {
type: ASTType.DomNode, type: ASTType.DomNode,
tag: "div", tag: "div",
dynamicTag: null, dynamicTag: null,
attrs: null, attrs: {},
on: null, on: {},
ref: null, ref: null,
model: null, model: null,
ns: null, ns: null,
@@ -810,8 +810,8 @@ describe("qweb parser", () => {
type: ASTType.DomNode, type: ASTType.DomNode,
tag: "div", tag: "div",
dynamicTag: null, dynamicTag: null,
attrs: null, attrs: {},
on: null, on: {},
ref: null, ref: null,
model: null, model: null,
ns: null, ns: null,
@@ -852,8 +852,8 @@ describe("qweb parser", () => {
type: ASTType.DomNode, type: ASTType.DomNode,
tag: "span", tag: "span",
dynamicTag: null, dynamicTag: null,
attrs: null, attrs: {},
on: null, on: {},
ref: null, ref: null,
model: null, model: null,
ns: null, ns: null,
@@ -886,8 +886,8 @@ describe("qweb parser", () => {
type: ASTType.DomNode, type: ASTType.DomNode,
tag: "span", tag: "span",
dynamicTag: null, dynamicTag: null,
attrs: null, attrs: {},
on: null, on: {},
ref: null, ref: null,
model: null, model: null,
ns: null, ns: null,
@@ -920,7 +920,7 @@ describe("qweb parser", () => {
"t-att-selected": "category.id==options.active_category_id", "t-att-selected": "category.id==options.active_category_id",
"t-att-value": "category.id", "t-att-value": "category.id",
}, },
on: null, on: {},
ref: null, ref: null,
model: null, model: null,
ns: null, ns: null,
@@ -939,8 +939,8 @@ describe("qweb parser", () => {
parse(`<div><t t-foreach="list" t-as="item" t-key="item_index"><t t-esc="item"/></t></div>`) parse(`<div><t t-foreach="list" t-as="item" t-key="item_index"><t t-esc="item"/></t></div>`)
).toEqual({ ).toEqual({
type: ASTType.DomNode, type: ASTType.DomNode,
attrs: null, attrs: {},
on: null, on: {},
ref: null, ref: null,
model: null, model: null,
tag: "div", tag: "div",
@@ -983,10 +983,10 @@ describe("qweb parser", () => {
type: ASTType.DomNode, type: ASTType.DomNode,
tag: "span", tag: "span",
dynamicTag: null, dynamicTag: null,
on: null, on: {},
ref: null, ref: null,
model: null, model: null,
attrs: null, attrs: {},
ns: null, ns: null,
content: [{ type: ASTType.TEsc, expr: "item", defaultValue: "" }], content: [{ type: ASTType.TEsc, expr: "item", defaultValue: "" }],
}, },
@@ -1009,9 +1009,8 @@ describe("qweb parser", () => {
isDynamic: false, isDynamic: false,
name: "Comp", name: "Comp",
dynamicProps: null, dynamicProps: null,
props: null, props: {},
slots: null, slots: {},
on: null,
}, },
memo: "", memo: "",
hasNoFirst: true, hasNoFirst: true,
@@ -1086,8 +1085,8 @@ describe("qweb parser", () => {
type: ASTType.DomNode, type: ASTType.DomNode,
tag: "div", tag: "div",
dynamicTag: null, dynamicTag: null,
attrs: null, attrs: {},
on: null, on: {},
ref: null, ref: null,
model: null, model: null,
ns: null, ns: null,
@@ -1124,7 +1123,7 @@ describe("qweb parser", () => {
type: ASTType.DomNode, type: ASTType.DomNode,
tag: "button", tag: "button",
dynamicTag: null, dynamicTag: null,
attrs: null, attrs: {},
on: { click: "add" }, on: { click: "add" },
ref: null, ref: null,
model: null, model: null,
@@ -1142,8 +1141,8 @@ describe("qweb parser", () => {
type: 2, type: 2,
tag: "select", tag: "select",
dynamicTag: null, dynamicTag: null,
attrs: null, attrs: {},
on: null, on: {},
ref: null, ref: null,
content: [ content: [
{ {
@@ -1151,7 +1150,7 @@ describe("qweb parser", () => {
tag: "option", tag: "option",
dynamicTag: null, dynamicTag: null,
attrs: { value: "1" }, attrs: { value: "1" },
on: null, on: {},
ref: null, ref: null,
content: [], content: [],
model: null, model: null,
@@ -1162,7 +1161,6 @@ describe("qweb parser", () => {
baseExpr: "state", baseExpr: "state",
expr: "'model'", expr: "'model'",
targetAttr: "value", targetAttr: "value",
hasDynamicChildren: false,
specialInitTargetAttr: null, specialInitTargetAttr: null,
eventType: "change", eventType: "change",
shouldTrim: false, shouldTrim: false,
@@ -1179,8 +1177,8 @@ describe("qweb parser", () => {
type: 2, type: 2,
tag: "select", tag: "select",
dynamicTag: null, dynamicTag: null,
attrs: null, attrs: {},
on: null, on: {},
ref: null, ref: null,
content: [ content: [
{ {
@@ -1188,7 +1186,7 @@ describe("qweb parser", () => {
tag: "option", tag: "option",
dynamicTag: null, dynamicTag: null,
attrs: { "t-att-value": "valueVar" }, attrs: { "t-att-value": "valueVar" },
on: null, on: {},
ref: null, ref: null,
content: [], content: [],
model: null, model: null,
@@ -1218,9 +1216,8 @@ describe("qweb parser", () => {
type: ASTType.TComponent, type: ASTType.TComponent,
name: "MyComponent", name: "MyComponent",
dynamicProps: null, dynamicProps: null,
props: null, props: {},
on: null, slots: {},
slots: null,
isDynamic: false, isDynamic: false,
}); });
}); });
@@ -1232,8 +1229,7 @@ describe("qweb parser", () => {
dynamicProps: null, dynamicProps: null,
props: { a: "1", b: "'b'" }, props: { a: "1", b: "'b'" },
isDynamic: false, isDynamic: false,
on: null, slots: {},
slots: null,
}); });
}); });
@@ -1244,21 +1240,14 @@ describe("qweb parser", () => {
dynamicProps: "state", dynamicProps: "state",
props: { a: "1" }, props: { a: "1" },
isDynamic: false, isDynamic: false,
on: null, slots: {},
slots: null,
}); });
}); });
test("component with event handler", async () => { test("component with event handler", async () => {
expect(parse(`<MyComponent t-on-click="someMethod"/>`)).toEqual({ expect(() => parse(`<MyComponent t-on-click="someMethod"/>`)).toThrow(
type: ASTType.TComponent, "t-on is no longer supported on components. Consider passing a callback in props."
name: "MyComponent", );
dynamicProps: null,
props: null,
isDynamic: false,
on: { click: "someMethod" },
slots: null,
});
}); });
test("component with t-ref", async () => { test("component with t-ref", async () => {
@@ -1290,17 +1279,9 @@ describe("qweb parser", () => {
type: ASTType.TComponent, type: ASTType.TComponent,
name: "MyComponent", name: "MyComponent",
dynamicProps: null, dynamicProps: null,
props: null, props: {},
isDynamic: false, isDynamic: false,
on: null, slots: { default: { content: { type: ASTType.Text, value: "foo" } } },
slots: {
default: {
content: { type: ASTType.Text, value: "foo" },
attrs: null,
on: null,
scope: null,
},
},
}); });
}); });
@@ -1311,16 +1292,10 @@ describe("qweb parser", () => {
type: ASTType.TComponent, type: ASTType.TComponent,
name: "MyComponent", name: "MyComponent",
dynamicProps: null, dynamicProps: null,
props: null, props: {},
isDynamic: false, isDynamic: false,
on: null,
slots: { slots: {
default: { default: { content: { type: ASTType.Text, value: "foo" }, attrs: { param: "param" } },
content: { type: ASTType.Text, value: "foo" },
attrs: { param: "param" },
on: null,
scope: null,
},
}, },
}); });
}); });
@@ -1331,8 +1306,7 @@ describe("qweb parser", () => {
name: "MyComponent", name: "MyComponent",
isDynamic: false, isDynamic: false,
dynamicProps: null, dynamicProps: null,
props: null, props: {},
on: null,
slots: { slots: {
default: { default: {
content: { content: {
@@ -1342,29 +1316,26 @@ describe("qweb parser", () => {
type: ASTType.DomNode, type: ASTType.DomNode,
tag: "span", tag: "span",
dynamicTag: null, dynamicTag: null,
attrs: null, attrs: {},
content: [], content: [],
ref: null, ref: null,
model: null, model: null,
on: null, on: {},
ns: null, ns: null,
}, },
{ {
type: ASTType.DomNode, type: ASTType.DomNode,
tag: "div", tag: "div",
dynamicTag: null, dynamicTag: null,
attrs: null, attrs: {},
content: [], content: [],
ref: null, ref: null,
model: null, model: null,
on: null, on: {},
ns: null, ns: null,
}, },
], ],
}, },
attrs: null,
on: null,
scope: null,
}, },
}, },
}); });
@@ -1376,11 +1347,8 @@ describe("qweb parser", () => {
name: "MyComponent", name: "MyComponent",
isDynamic: false, isDynamic: false,
dynamicProps: null, dynamicProps: null,
props: null, props: {},
on: null, slots: { name: { content: { type: ASTType.Text, value: "foo" } } },
slots: {
name: { content: { type: ASTType.Text, value: "foo" }, attrs: null, on: null, scope: null },
},
}); });
}); });
@@ -1390,37 +1358,8 @@ describe("qweb parser", () => {
name: "MyComponent", name: "MyComponent",
isDynamic: false, isDynamic: false,
dynamicProps: null, dynamicProps: null,
props: null, props: {},
on: null, slots: { name: { content: { type: ASTType.Text, value: "foo" }, attrs: { param: "param" } } },
slots: {
name: {
content: { type: ASTType.Text, value: "foo" },
attrs: { param: "param" },
on: null,
scope: null,
},
},
});
});
test("a component with a named slot with t-on", async () => {
expect(
parse(`<MyComponent><t t-set-slot="name" t-on-click="doStuff">foo</t></MyComponent>`)
).toEqual({
type: ASTType.TComponent,
name: "MyComponent",
isDynamic: false,
dynamicProps: null,
props: null,
on: null,
slots: {
name: {
content: { type: ASTType.Text, value: "foo" },
on: { click: "doStuff" },
attrs: null,
scope: null,
},
},
}); });
}); });
@@ -1435,17 +1374,11 @@ describe("qweb parser", () => {
type: ASTType.TComponent, type: ASTType.TComponent,
name: "MyComponent", name: "MyComponent",
dynamicProps: null, dynamicProps: null,
props: null, props: {},
isDynamic: false, isDynamic: false,
on: null,
slots: { slots: {
default: { default: { content: { type: ASTType.Text, value: " " } },
content: { type: ASTType.Text, value: " " }, name: { content: { type: ASTType.Text, value: "foo" } },
attrs: null,
on: null,
scope: null,
},
name: { content: { type: ASTType.Text, value: "foo" }, attrs: null, on: null, scope: null },
}, },
}); });
}); });
@@ -1460,12 +1393,11 @@ describe("qweb parser", () => {
type: ASTType.TComponent, type: ASTType.TComponent,
name: "MyComponent", name: "MyComponent",
dynamicProps: null, dynamicProps: null,
props: null, props: {},
isDynamic: false, isDynamic: false,
on: null,
slots: { slots: {
a: { content: { type: ASTType.Text, value: "foo" }, attrs: null, on: null, scope: null }, a: { content: { type: ASTType.Text, value: "foo" } },
b: { content: { type: ASTType.Text, value: "bar" }, attrs: null, on: null, scope: null }, b: { content: { type: ASTType.Text, value: "bar" } },
}, },
}); });
}); });
@@ -1475,10 +1407,9 @@ describe("qweb parser", () => {
type: ASTType.TComponent, type: ASTType.TComponent,
name: "myComponent", name: "myComponent",
dynamicProps: null, dynamicProps: null,
props: null, props: {},
isDynamic: true, isDynamic: true,
on: null, slots: {},
slots: null,
}); });
}); });
@@ -1489,8 +1420,7 @@ describe("qweb parser", () => {
dynamicProps: null, dynamicProps: null,
props: { a: "1", b: "'b'" }, props: { a: "1", b: "'b'" },
isDynamic: true, isDynamic: true,
on: null, slots: {},
slots: null,
}); });
}); });
@@ -1501,8 +1431,7 @@ describe("qweb parser", () => {
dynamicProps: "state", dynamicProps: "state",
props: { a: "1" }, props: { a: "1" },
isDynamic: true, isDynamic: true,
on: null, slots: {},
slots: null,
}); });
}); });
@@ -1523,17 +1452,9 @@ describe("qweb parser", () => {
type: ASTType.TComponent, type: ASTType.TComponent,
name: "MyComponent", name: "MyComponent",
dynamicProps: null, dynamicProps: null,
props: null, props: {},
isDynamic: false, isDynamic: false,
on: null, slots: { default: { content: { body: null, name: "subTemplate", type: ASTType.TCall } } },
slots: {
default: {
content: { body: null, name: "subTemplate", type: ASTType.TCall },
attrs: null,
scope: null,
on: null,
},
},
}); });
}); });
@@ -1549,29 +1470,17 @@ describe("qweb parser", () => {
type: ASTType.TComponent, type: ASTType.TComponent,
name: "MyComponent", name: "MyComponent",
dynamicProps: null, dynamicProps: null,
props: null, props: {},
isDynamic: false, isDynamic: false,
on: null,
slots: { slots: {
default: { default: {
attrs: null,
on: null,
scope: null,
content: { content: {
type: ASTType.TComponent, type: ASTType.TComponent,
isDynamic: false, isDynamic: false,
name: "Child", name: "Child",
dynamicProps: null, dynamicProps: null,
props: null, props: {},
on: null, slots: { brol: { content: { type: ASTType.Text, value: "coucou" } } },
slots: {
brol: {
content: { type: ASTType.Text, value: "coucou" },
attrs: null,
scope: null,
on: null,
},
},
}, },
}, },
}, },
@@ -1590,29 +1499,17 @@ describe("qweb parser", () => {
type: ASTType.TComponent, type: ASTType.TComponent,
name: "MyComponent", name: "MyComponent",
dynamicProps: null, dynamicProps: null,
props: null, props: {},
isDynamic: false, isDynamic: false,
on: null,
slots: { slots: {
default: { default: {
attrs: null,
on: null,
scope: null,
content: { content: {
type: ASTType.TComponent, type: ASTType.TComponent,
isDynamic: false, isDynamic: false,
name: "Child", name: "Child",
dynamicProps: null, dynamicProps: null,
props: null, props: {},
on: null, slots: { brol: { content: { type: ASTType.Text, value: "coucou" } } },
slots: {
brol: {
content: { type: ASTType.Text, value: "coucou" },
attrs: null,
on: null,
scope: null,
},
},
}, },
}, },
}, },
@@ -1627,8 +1524,7 @@ describe("qweb parser", () => {
expect(parse(`<t t-slot="default"/>`)).toEqual({ expect(parse(`<t t-slot="default"/>`)).toEqual({
type: ASTType.TSlot, type: ASTType.TSlot,
name: "default", name: "default",
attrs: null, attrs: {},
on: null,
defaultContent: null, defaultContent: null,
}); });
}); });
@@ -1637,22 +1533,11 @@ describe("qweb parser", () => {
expect(parse(`<t t-slot="header">default content</t>`)).toEqual({ expect(parse(`<t t-slot="header">default content</t>`)).toEqual({
type: ASTType.TSlot, type: ASTType.TSlot,
name: "header", name: "header",
attrs: null, attrs: {},
on: null,
defaultContent: { type: ASTType.Text, value: "default content" }, defaultContent: { type: ASTType.Text, value: "default content" },
}); });
}); });
test("t-slot with t-on-", async () => {
expect(parse(`<t t-slot="default" t-on-click.prevent="doSomething"/>`)).toEqual({
type: ASTType.TSlot,
name: "default",
attrs: null,
on: { "click.prevent": "doSomething" },
defaultContent: null,
});
});
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// t-debug // t-debug
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@@ -1664,8 +1549,8 @@ describe("qweb parser", () => {
type: ASTType.DomNode, type: ASTType.DomNode,
tag: "div", tag: "div",
dynamicTag: null, dynamicTag: null,
attrs: null, attrs: {},
on: null, on: {},
ref: null, ref: null,
model: null, model: null,
ns: null, ns: null,
@@ -1682,8 +1567,8 @@ describe("qweb parser", () => {
type: ASTType.DomNode, type: ASTType.DomNode,
tag: "div", tag: "div",
dynamicTag: null, dynamicTag: null,
attrs: null, attrs: {},
on: null, on: {},
ref: null, ref: null,
model: null, model: null,
ns: null, ns: null,
@@ -1701,8 +1586,8 @@ describe("qweb parser", () => {
type: ASTType.DomNode, type: ASTType.DomNode,
tag: "div", tag: "div",
dynamicTag: null, dynamicTag: null,
attrs: null, attrs: {},
on: null, on: {},
ref: "name", ref: "name",
model: null, model: null,
ns: null, ns: null,
@@ -1715,8 +1600,8 @@ describe("qweb parser", () => {
type: ASTType.DomNode, type: ASTType.DomNode,
tag: "div", tag: "div",
dynamicTag: null, dynamicTag: null,
attrs: null, attrs: {},
on: null, on: {},
ref: "name", ref: "name",
model: null, model: null,
ns: null, ns: null,
@@ -1731,8 +1616,8 @@ describe("qweb parser", () => {
type: ASTType.DomNode, type: ASTType.DomNode,
tag: "div", tag: "div",
dynamicTag: null, dynamicTag: null,
attrs: null, attrs: {},
on: null, on: {},
ref: "name", ref: "name",
model: null, model: null,
ns: null, ns: null,
@@ -1767,14 +1652,14 @@ describe("qweb parser", () => {
).toEqual({ ).toEqual({
body: { body: {
content: { content: {
attrs: null, attrs: {},
content: [ content: [
{ {
type: ASTType.Text, type: ASTType.Text,
value: "word", value: "word",
}, },
], ],
on: null, on: {},
ref: null, ref: null,
model: null, model: null,
tag: "div", tag: "div",
@@ -1802,9 +1687,9 @@ describe("qweb parser", () => {
test("t-model", async () => { test("t-model", async () => {
expect(parse(`<input t-model="state.stuff" />`)).toEqual({ expect(parse(`<input t-model="state.stuff" />`)).toEqual({
type: ASTType.DomNode, type: ASTType.DomNode,
attrs: null, attrs: {},
content: [], content: [],
on: null, on: {},
ref: null, ref: null,
tag: "input", tag: "input",
dynamicTag: null, dynamicTag: null,
@@ -1815,16 +1700,15 @@ describe("qweb parser", () => {
eventType: "input", eventType: "input",
shouldNumberize: false, shouldNumberize: false,
shouldTrim: false, shouldTrim: false,
hasDynamicChildren: false,
targetAttr: "value", targetAttr: "value",
specialInitTargetAttr: null, specialInitTargetAttr: null,
}, },
}); });
expect(parse(`<input t-model="state['stuff']" />`)).toEqual({ expect(parse(`<input t-model="state['stuff']" />`)).toEqual({
type: ASTType.DomNode, type: ASTType.DomNode,
attrs: null, attrs: {},
content: [], content: [],
on: null, on: {},
ref: null, ref: null,
tag: "input", tag: "input",
dynamicTag: null, dynamicTag: null,
@@ -1837,14 +1721,13 @@ describe("qweb parser", () => {
shouldTrim: false, shouldTrim: false,
targetAttr: "value", targetAttr: "value",
specialInitTargetAttr: null, specialInitTargetAttr: null,
hasDynamicChildren: false,
}, },
}); });
expect(parse(`<input t-model.lazy.trim.number="state.stuff" />`)).toEqual({ expect(parse(`<input t-model.lazy.trim.number="state.stuff" />`)).toEqual({
type: ASTType.DomNode, type: ASTType.DomNode,
attrs: null, attrs: {},
content: [], content: [],
on: null, on: {},
ref: null, ref: null,
tag: "input", tag: "input",
dynamicTag: null, dynamicTag: null,
@@ -1856,16 +1739,15 @@ describe("qweb parser", () => {
shouldNumberize: true, shouldNumberize: true,
shouldTrim: true, shouldTrim: true,
targetAttr: "value", targetAttr: "value",
hasDynamicChildren: false,
specialInitTargetAttr: null, specialInitTargetAttr: null,
}, },
}); });
}); });
expect(parse(`<textarea t-model="state.stuff" />`)).toEqual({ expect(parse(`<textarea t-model="state.stuff" />`)).toEqual({
type: ASTType.DomNode, type: ASTType.DomNode,
attrs: null, attrs: {},
content: [], content: [],
on: null, on: {},
ref: null, ref: null,
tag: "textarea", tag: "textarea",
dynamicTag: null, dynamicTag: null,
@@ -1877,7 +1759,6 @@ describe("qweb parser", () => {
shouldNumberize: false, shouldNumberize: false,
shouldTrim: false, shouldTrim: false,
targetAttr: "value", targetAttr: "value",
hasDynamicChildren: false,
specialInitTargetAttr: null, specialInitTargetAttr: null,
}, },
}); });
@@ -1885,7 +1766,7 @@ describe("qweb parser", () => {
type: ASTType.DomNode, type: ASTType.DomNode,
attrs: { type: "checkbox" }, attrs: { type: "checkbox" },
content: [], content: [],
on: null, on: {},
ref: null, ref: null,
tag: "input", tag: "input",
dynamicTag: null, dynamicTag: null,
@@ -1897,7 +1778,6 @@ describe("qweb parser", () => {
shouldNumberize: false, shouldNumberize: false,
shouldTrim: false, shouldTrim: false,
targetAttr: "checked", targetAttr: "checked",
hasDynamicChildren: false,
specialInitTargetAttr: null, specialInitTargetAttr: null,
}, },
}); });
@@ -1905,7 +1785,7 @@ describe("qweb parser", () => {
type: ASTType.DomNode, type: ASTType.DomNode,
attrs: { type: "radio" }, attrs: { type: "radio" },
content: [], content: [],
on: null, on: {},
ref: null, ref: null,
tag: "input", tag: "input",
dynamicTag: null, dynamicTag: null,
@@ -1917,7 +1797,6 @@ describe("qweb parser", () => {
shouldNumberize: false, shouldNumberize: false,
shouldTrim: false, shouldTrim: false,
targetAttr: "value", targetAttr: "value",
hasDynamicChildren: false,
specialInitTargetAttr: "checked", specialInitTargetAttr: "checked",
}, },
}); });
@@ -1925,7 +1804,7 @@ describe("qweb parser", () => {
type: ASTType.DomNode, type: ASTType.DomNode,
attrs: { type: "radio" }, attrs: { type: "radio" },
content: [], content: [],
on: null, on: {},
ref: null, ref: null,
tag: "input", tag: "input",
dynamicTag: null, dynamicTag: null,
@@ -1937,7 +1816,6 @@ describe("qweb parser", () => {
shouldNumberize: false, shouldNumberize: false,
shouldTrim: false, shouldTrim: false,
targetAttr: "value", targetAttr: "value",
hasDynamicChildren: false,
specialInitTargetAttr: "checked", specialInitTargetAttr: "checked",
}, },
}); });
@@ -1948,9 +1826,9 @@ describe("qweb parser", () => {
test("t-tag", async () => { test("t-tag", async () => {
expect(parse(`<div t-tag="theTag" />`)).toEqual({ expect(parse(`<div t-tag="theTag" />`)).toEqual({
type: ASTType.DomNode, type: ASTType.DomNode,
attrs: null, attrs: {},
content: [], content: [],
on: null, on: {},
ref: null, ref: null,
tag: "div", tag: "div",
dynamicTag: "theTag", dynamicTag: "theTag",
-20
View File
@@ -37,26 +37,6 @@ describe("t-out", () => {
expect(renderToString(template, { var: "ok" })).toBe("<span>ok</span>"); 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", () => { test("not escaping", () => {
const template = `<div><t t-out="var"/></div>`; const template = `<div><t t-out="var"/></div>`;
expect(renderToString(template, { var: markup("<ok></ok>") })).toBe("<div><ok></ok></div>"); expect(renderToString(template, { var: markup("<ok></ok>") })).toBe("<div><ok></ok></div>");
+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 { class SomeComponent extends Component {
static template = xml` 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, { await mount(SomeComponent, fixture, {
translateFn: (expr: string) => (expr === "word" ? "mot" : expr), translateFn: (expr: string) => (expr === "word" ? "mot" : expr),
translatableAttributes: ["potato", "-label"], translatableAttributes: ["potato"],
}); });
expect(fixture.innerHTML).toBe( expect(fixture.innerHTML).toBe('<div tomato="word" potato="mot" title="word">text</div>');
'<div tomato="word" potato="mot" title="mot" label="word">text</div>'
);
}); });
test("translation is done on the trimmed text, with extra spaces readded after", async () => { 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; let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") { 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)); 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>\`); let block4 = createBlock(\`<span>2</span>\`);
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const b2 = block2(); let b2 = block2();
const b3 = text(\`text\`); let b3 = text(\`text\`);
const b4 = block4(); let b4 = block4();
return multi([b2, b3, b4]); 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`] = ` exports[`basics a component inside a component 1`] = `
"function anonymous(bdom, helpers "function anonymous(bdom, helpers
) { ) {
@@ -102,7 +89,7 @@ exports[`basics a component inside a component 1`] = `
let block1 = createBlock(\`<span><block-child-0/></span>\`); let block1 = createBlock(\`<span><block-child-0/></span>\`);
return function template(ctx, node, key = \\"\\") { 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]); return block1([], [b2]);
} }
}" }"
@@ -145,7 +132,7 @@ exports[`basics can handle empty props 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`); let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") { 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]); return block1([], [b2]);
} }
}" }"
@@ -236,8 +223,8 @@ exports[`basics can mount a simple component with multiple roots 1`] = `
let block3 = createBlock(\`<div/>\`); let block3 = createBlock(\`<div/>\`);
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const b2 = block2(); let b2 = block2();
const b3 = block3(); let b3 = block3();
return multi([b2, b3]); 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 = \\"\\") { return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx); 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++) { for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`blip\`] = v_block2[i1]; ctx[\`blip\`] = v_block2[i1];
const key1 = ctx['blip'].id; let key1 = ctx['blip'].id;
const b4 = component(\`SubWidget\`, {}, key + \`__1__\${key1}\`, node, ctx); let b4 = component(\`SubWidget\`, {}, key + \`__1__\${key1}\`, node, ctx);
const b5 = component(\`SubWidget\`, {}, key + \`__2__\${key1}\`, node, ctx); let b5 = component(\`SubWidget\`, {}, key + \`__2__\${key1}\`, node, ctx);
c_block2[i1] = withKey(block3([], [b4, b5]), key1); c_block2[i1] = withKey(block3([], [b4, b5]), key1);
} }
const b2 = list(c_block2); let b2 = list(c_block2);
return block1([], [b2]); 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>\`); let block1 = createBlock(\`<div><block-child-0/><block-child-1/></div>\`);
return function template(ctx, node, key = \\"\\") { 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 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]); return block1([], [b2, b3]);
} }
}" }"
@@ -617,9 +604,9 @@ exports[`basics same t-keys in two different places 1`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const tKey_1 = 1; 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 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]); return block1([], [b2, b3]);
} }
}" }"
@@ -952,8 +939,8 @@ exports[`basics two child components 1`] = `
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom; let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const b2 = component(\`Child\`, {}, key + \`__1\`, node, ctx); let b2 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
const b3 = component(\`Child\`, {}, key + \`__2\`, node, ctx); let b3 = component(\`Child\`, {}, key + \`__2\`, node, ctx);
return multi([b2, b3]); 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 = \\"\\") { return function template(ctx, node, key = \\"\\") {
const tKey_1 = ctx['childProps'].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]); return block1([], [b2]);
} }
}" }"
@@ -1022,10 +1009,10 @@ exports[`basics updating a component with t-foreach as root 1`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx); 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++) { for (let i1 = 0; i1 < l_block1; i1++) {
ctx[\`item\`] = v_block1[i1]; ctx[\`item\`] = v_block1[i1];
const key1 = ctx['item']; let key1 = ctx['item'];
c_block1[i1] = withKey(text(ctx['item']), key1); c_block1[i1] = withKey(text(ctx['item']), key1);
} }
return list(c_block1); return list(c_block1);
@@ -1071,16 +1058,16 @@ exports[`basics widget after a t-foreach 1`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx); 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++) { for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`elem\`] = v_block2[i1]; ctx[\`elem\`] = v_block2[i1];
ctx[\`elem_index\`] = i1; ctx[\`elem_index\`] = i1;
const key1 = ctx['elem_index']; let key1 = ctx['elem_index'];
c_block2[i1] = withKey(text(\`txt\`), key1); c_block2[i1] = withKey(text(\`txt\`), key1);
} }
ctx = ctx.__proto__; ctx = ctx.__proto__;
const b2 = list(c_block2); let b2 = list(c_block2);
const b4 = component(\`SomeComponent\`, {}, key + \`__1\`, node, ctx); let b4 = component(\`SomeComponent\`, {}, key + \`__1\`, node, ctx);
return block1([], [b2, b4]); 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>\`); let block1 = createBlock(\`<svg block-ns=\\"http://www.w3.org/2000/svg\\"><block-child-0/></svg>\`);
return function template(ctx, node, key = \\"\\") { 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]); return block1([], [b2]);
} }
}" }"
@@ -1216,15 +1203,15 @@ exports[`t-out in components can render list of t-out 1`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx); 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++) { for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`item\`] = v_block2[i1]; ctx[\`item\`] = v_block2[i1];
const key1 = ctx['item']; let key1 = ctx['item'];
const b4 = text(ctx['item']); let b4 = text(ctx['item']);
const b5 = safeOutput(ctx['item']); let b5 = safeOutput(ctx['item']);
c_block2[i1] = withKey(multi([b4, b5]), key1); c_block2[i1] = withKey(multi([b4, b5]), key1);
} }
const b2 = list(c_block2); let b2 = list(c_block2);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -1237,8 +1224,8 @@ exports[`t-out in components can switch the contents of two t-out repeatedly 1`]
let { safeOutput } = helpers; let { safeOutput } = helpers;
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const b2 = safeOutput(ctx['state'].a); let b2 = safeOutput(ctx['state'].a);
const b3 = safeOutput(ctx['state'].b); let b3 = safeOutput(ctx['state'].b);
return multi([b2, b3]); return multi([b2, b3]);
} }
}" }"
@@ -1253,7 +1240,7 @@ exports[`t-out in components update properly on state changes 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`); let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const b2 = safeOutput(ctx['state'].value); let b2 = safeOutput(ctx['state'].value);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -7,16 +7,16 @@ exports[`Cascading renders after microtaskTick 1`] = `
let { prepareList, withKey } = helpers; let { prepareList, withKey } = helpers;
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const b2 = component(\`Child\`, {}, key + \`__1\`, node, ctx); let b2 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
const b3 = text(\` _ \`); let b3 = text(\` _ \`);
ctx = Object.create(ctx); 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++) { for (let i1 = 0; i1 < l_block4; i1++) {
ctx[\`elem\`] = v_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); c_block4[i1] = withKey(text(ctx['elem'].id), key1);
} }
const b4 = list(c_block4); let b4 = list(c_block4);
return multi([b2, b3, b4]); return multi([b2, b3, b4]);
} }
}" }"
@@ -30,10 +30,10 @@ exports[`Cascading renders after microtaskTick 2`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx); 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++) { for (let i1 = 0; i1 < l_block1; i1++) {
ctx[\`elem\`] = v_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); c_block1[i1] = withKey(component(\`Element\`, {id: ctx['elem'].id}, key + \`__1__\${key1}\`, node, ctx), key1);
} }
return list(c_block1); return list(c_block1);
@@ -169,7 +169,7 @@ exports[`concurrent renderings scenario 1 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`); let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") { 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]); return block1([], [b2]);
} }
}" }"
@@ -183,7 +183,7 @@ exports[`concurrent renderings scenario 1 2`] = `
let block1 = createBlock(\`<p><block-child-0/></p>\`); let block1 = createBlock(\`<p><block-child-0/></p>\`);
return function template(ctx, node, key = \\"\\") { 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]); return block1([], [b2]);
} }
}" }"
@@ -213,7 +213,7 @@ exports[`concurrent renderings scenario 2 1`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
let txt1 = ctx['state'].fromA; 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]); return block1([txt1], [b2]);
} }
}" }"
@@ -227,7 +227,7 @@ exports[`concurrent renderings scenario 2 2`] = `
let block1 = createBlock(\`<p><block-child-0/></p>\`); let block1 = createBlock(\`<p><block-child-0/></p>\`);
return function template(ctx, node, key = \\"\\") { 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]); return block1([], [b2]);
} }
}" }"
@@ -256,7 +256,7 @@ exports[`concurrent renderings scenario 2bis 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`); let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") { 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]); return block1([], [b2]);
} }
}" }"
@@ -270,7 +270,7 @@ exports[`concurrent renderings scenario 2bis 2`] = `
let block1 = createBlock(\`<p><block-child-0/></p>\`); let block1 = createBlock(\`<p><block-child-0/></p>\`);
return function template(ctx, node, key = \\"\\") { 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]); return block1([], [b2]);
} }
}" }"
@@ -299,7 +299,7 @@ exports[`concurrent renderings scenario 3 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`); let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") { 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]); return block1([], [b2]);
} }
}" }"
@@ -313,7 +313,7 @@ exports[`concurrent renderings scenario 3 2`] = `
let block1 = createBlock(\`<p><block-child-0/></p>\`); let block1 = createBlock(\`<p><block-child-0/></p>\`);
return function template(ctx, node, key = \\"\\") { 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]); return block1([], [b2]);
} }
}" }"
@@ -327,7 +327,7 @@ exports[`concurrent renderings scenario 3 3`] = `
let block1 = createBlock(\`<span><block-child-0/></span>\`); let block1 = createBlock(\`<span><block-child-0/></span>\`);
return function template(ctx, node, key = \\"\\") { 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]); return block1([], [b2]);
} }
}" }"
@@ -356,7 +356,7 @@ exports[`concurrent renderings scenario 4 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`); let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") { 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]); return block1([], [b2]);
} }
}" }"
@@ -370,7 +370,7 @@ exports[`concurrent renderings scenario 4 2`] = `
let block1 = createBlock(\`<p><block-child-0/></p>\`); let block1 = createBlock(\`<p><block-child-0/></p>\`);
return function template(ctx, node, key = \\"\\") { 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]); return block1([], [b2]);
} }
}" }"
@@ -384,7 +384,7 @@ exports[`concurrent renderings scenario 4 3`] = `
let block1 = createBlock(\`<span><block-child-0/></span>\`); let block1 = createBlock(\`<span><block-child-0/></span>\`);
return function template(ctx, node, key = \\"\\") { 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]); return block1([], [b2]);
} }
}" }"
@@ -413,7 +413,7 @@ exports[`concurrent renderings scenario 5 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`); let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") { 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]); return block1([], [b2]);
} }
}" }"
@@ -441,7 +441,7 @@ exports[`concurrent renderings scenario 6 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`); let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") { 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]); return block1([], [b2]);
} }
}" }"
@@ -469,7 +469,7 @@ exports[`concurrent renderings scenario 7 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`); let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") { 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]); return block1([], [b2]);
} }
}" }"
@@ -498,7 +498,7 @@ exports[`concurrent renderings scenario 8 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`); let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") { 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]); return block1([], [b2]);
} }
}" }"
@@ -528,8 +528,8 @@ exports[`concurrent renderings scenario 9 1`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
let txt1 = ctx['state'].fromA; 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);
const b3 = component(\`ComponentC\`, {fromA: ctx['state'].fromA}, key + \`__2\`, node, ctx); let b3 = component(\`ComponentC\`, {fromA: ctx['state'].fromA}, key + \`__2\`, node, ctx);
return block1([txt1], [b2, b3]); return block1([txt1], [b2, b3]);
} }
}" }"
@@ -557,7 +557,7 @@ exports[`concurrent renderings scenario 9 3`] = `
let block1 = createBlock(\`<p><block-child-0/></p>\`); let block1 = createBlock(\`<p><block-child-0/></p>\`);
return function template(ctx, node, key = \\"\\") { 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]); return block1([], [b2]);
} }
}" }"
@@ -586,7 +586,7 @@ exports[`concurrent renderings scenario 10 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`); let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") { 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]); return block1([], [b2]);
} }
}" }"
@@ -631,7 +631,7 @@ exports[`concurrent renderings scenario 11 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`); let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") { 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]); return block1([], [b2]);
} }
}" }"
@@ -660,7 +660,7 @@ exports[`concurrent renderings scenario 12 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`); let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") { 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]); return block1([], [b2]);
} }
}" }"
@@ -720,7 +720,7 @@ exports[`concurrent renderings scenario 14 1`] = `
let block1 = createBlock(\`<p><block-child-0/></p>\`); let block1 = createBlock(\`<p><block-child-0/></p>\`);
return function template(ctx, node, key = \\"\\") { 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]); return block1([], [b2]);
} }
}" }"
@@ -734,7 +734,7 @@ exports[`concurrent renderings scenario 14 2`] = `
let block1 = createBlock(\`<p><block-child-0/></p>\`); let block1 = createBlock(\`<p><block-child-0/></p>\`);
return function template(ctx, node, key = \\"\\") { 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]); return block1([], [b2]);
} }
}" }"
@@ -764,7 +764,7 @@ exports[`concurrent renderings scenario 15 1`] = `
let block1 = createBlock(\`<p><block-child-0/></p>\`); let block1 = createBlock(\`<p><block-child-0/></p>\`);
return function template(ctx, node, key = \\"\\") { 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]); return block1([], [b2]);
} }
}" }"
@@ -778,7 +778,7 @@ exports[`concurrent renderings scenario 15 2`] = `
let block1 = createBlock(\`<p><block-child-0/></p>\`); let block1 = createBlock(\`<p><block-child-0/></p>\`);
return function template(ctx, node, key = \\"\\") { 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]); return block1([], [b2]);
} }
}" }"
@@ -1008,9 +1008,9 @@ exports[`delay willUpdateProps 2`] = `
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom; let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const b2 = text(ctx['props'].value); let b2 = text(ctx['props'].value);
const b3 = text(\`_\`); let b3 = text(\`_\`);
const b4 = text(ctx['state'].int); let b4 = text(ctx['state'].int);
return multi([b2, b3, b4]); return multi([b2, b3, b4]);
} }
}" }"
@@ -1033,8 +1033,8 @@ exports[`delay willUpdateProps with rendering grandchild 2`] = `
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom; let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const b2 = component(\`DelayedChild\`, {value: ctx['props'].state.value}, key + \`__1\`, node, ctx); let b2 = component(\`DelayedChild\`, {value: ctx['props'].state.value}, key + \`__1\`, node, ctx);
const b3 = component(\`ReactiveChild\`, {}, key + \`__2\`, node, ctx); let b3 = component(\`ReactiveChild\`, {}, key + \`__2\`, node, ctx);
return multi([b2, b3]); return multi([b2, b3]);
} }
}" }"
@@ -1046,9 +1046,9 @@ exports[`delay willUpdateProps with rendering grandchild 3`] = `
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom; let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const b2 = text(ctx['props'].value); let b2 = text(ctx['props'].value);
const b3 = text(\`_\`); let b3 = text(\`_\`);
const b4 = text(ctx['state'].int); let b4 = text(ctx['state'].int);
return multi([b2, b3, b4]); return multi([b2, b3, b4]);
} }
}" }"
@@ -1067,33 +1067,6 @@ exports[`delay willUpdateProps with rendering grandchild 4`] = `
}" }"
`; `;
exports[`destroying/recreating a subcomponent, other scenario 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
let b2,b3;
b2 = text(\`parent\`);
if (ctx['state'].hasChild) {
b3 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
}
return multi([b2, b3]);
}
}"
`;
exports[`destroying/recreating a subcomponent, other scenario 2`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
return text(\`child\`);
}
}"
`;
exports[`destroying/recreating a subwidget with different props (if start is not over) 1`] = ` exports[`destroying/recreating a subwidget with different props (if start is not over) 1`] = `
"function anonymous(bdom, helpers "function anonymous(bdom, helpers
) { ) {
@@ -1172,7 +1145,7 @@ exports[`properly behave when destroyed/unmounted while rendering 2`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`); let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const b2 = component(\`SubChild\`, {val: ctx['props'].val}, key + \`__1\`, node, ctx); let b2 = component(\`SubChild\`, {}, key + \`__1\`, node, ctx);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -1222,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`] = ` exports[`t-foreach with dynamic async component 1`] = `
"function anonymous(bdom, helpers "function anonymous(bdom, helpers
) { ) {
@@ -1252,14 +1203,14 @@ exports[`t-foreach with dynamic async component 1`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx); 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++) { for (let i1 = 0; i1 < l_block1; i1++) {
ctx[\`arr\`] = v_block1[i1]; ctx[\`arr\`] = v_block1[i1];
ctx[\`arr_index\`] = i1; ctx[\`arr_index\`] = i1;
const key1 = ctx['arr_index']; let key1 = ctx['arr_index'];
let b3; let b3;
if (ctx['arr']) { 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)); b3 = toggler(Comp1, component(Comp1, {key: ctx['arr'][0]}, key + \`__1__\${key1}\`, node, ctx));
} }
c_block1[i1] = withKey(multi([b3]), key1); c_block1[i1] = withKey(multi([b3]), key1);
@@ -1292,8 +1243,8 @@ exports[`t-key on dom node having a component 1`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const tKey_1 = ctx['key']; const tKey_1 = ctx['key'];
const Comp1 = ctx['myComp']; let Comp1 = ctx['myComp'];
const b2 = toggler(tKey_1, toggler(Comp1, component(Comp1, {key: ctx['key']}, tKey_1 + key + \`__1\`, node, ctx))); let b2 = toggler(tKey_1, toggler(Comp1, component(Comp1, {key: ctx['key']}, tKey_1 + key + \`__1\`, node, ctx)));
return toggler(tKey_1, block1([], [b2])); return toggler(tKey_1, block1([], [b2]));
} }
}" }"
@@ -1317,7 +1268,7 @@ exports[`t-key on dynamic async component (toggler is never patched) 1`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const tKey_1 = ctx['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))); return toggler(tKey_1, toggler(Comp1, component(Comp1, {key: ctx['key']}, tKey_1 + key + \`__1\`, node, ctx)));
} }
}" }"
@@ -1400,7 +1351,7 @@ exports[`update a sub-component twice in the same frame 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`); let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") { 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]); return block1([], [b2]);
} }
}" }"
@@ -1428,7 +1379,7 @@ exports[`update a sub-component twice in the same frame, 2 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`); let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") { 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]); return block1([], [b2]);
} }
}" }"
@@ -32,7 +32,7 @@ exports[`basics no component catching error lead to full app destruction 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`); let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") { 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]); return block1([], [b2]);
} }
}" }"
@@ -85,22 +85,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`] = ` exports[`can catch errors can catch an error in a component render function 1`] = `
"function anonymous(bdom, helpers "function anonymous(bdom, helpers
) { ) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom; let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { markRaw } = helpers;
let block1 = createBlock(\`<div><block-child-0/></div>\`); let block1 = createBlock(\`<div><block-child-0/></div>\`);
@@ -109,7 +97,7 @@ exports[`can catch errors can catch an error in a component render function 1`]
} }
return function template(ctx, node, key = \\"\\") { 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]); return block1([], [b3]);
} }
}" }"
@@ -128,7 +116,7 @@ exports[`can catch errors can catch an error in a component render function 2`]
if (ctx['state'].error) { if (ctx['state'].error) {
b2 = text(\`Error handled\`); b2 = text(\`Error handled\`);
} else { } else {
b3 = callSlot(ctx, node, key, 'default', false, null); b3 = callSlot(ctx, node, key, 'default', false, {});
} }
return block1([], [b2, b3]); return block1([], [b2, b3]);
} }
@@ -153,7 +141,6 @@ exports[`can catch errors can catch an error in the constructor call of a compon
"function anonymous(bdom, helpers "function anonymous(bdom, helpers
) { ) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom; let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { markRaw } = helpers;
let block1 = createBlock(\`<div><block-child-0/></div>\`); let block1 = createBlock(\`<div><block-child-0/></div>\`);
@@ -162,7 +149,7 @@ exports[`can catch errors can catch an error in the constructor call of a compon
} }
return function template(ctx, node, key = \\"\\") { 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]); return block1([], [b3]);
} }
}" }"
@@ -181,7 +168,7 @@ exports[`can catch errors can catch an error in the constructor call of a compon
if (ctx['state'].error) { if (ctx['state'].error) {
b2 = text(\`Error handled\`); b2 = text(\`Error handled\`);
} else { } else {
b3 = callSlot(ctx, node, key, 'default', false, null); b3 = callSlot(ctx, node, key, 'default', false, {});
} }
return block1([], [b2, b3]); return block1([], [b2, b3]);
} }
@@ -192,18 +179,17 @@ exports[`can catch errors can catch an error in the constructor call of a compon
"function anonymous(bdom, helpers "function anonymous(bdom, helpers
) { ) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom; let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { markRaw } = helpers;
let block1 = createBlock(\`<div><block-child-0/></div>\`); let block1 = createBlock(\`<div><block-child-0/></div>\`);
function slot1(ctx, node, key = \\"\\") { function slot1(ctx, node, key = \\"\\") {
const b3 = component(\`ClassicCompoent\`, {}, key + \`__1\`, node, ctx); let b3 = component(\`ClassicCompoent\`, {}, key + \`__1\`, node, ctx);
const b4 = component(\`ErrorComponent\`, {}, key + \`__2\`, node, ctx); let b4 = component(\`ErrorComponent\`, {}, key + \`__2\`, node, ctx);
return multi([b3, b4]); return multi([b3, b4]);
} }
return function template(ctx, node, key = \\"\\") { 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]); return block1([], [b5]);
} }
}" }"
@@ -222,7 +208,7 @@ exports[`can catch errors can catch an error in the constructor call of a compon
if (ctx['state'].error) { if (ctx['state'].error) {
b2 = text(\`Error handled\`); b2 = text(\`Error handled\`);
} else { } else {
b3 = callSlot(ctx, node, key, 'default', false, null); b3 = callSlot(ctx, node, key, 'default', false, {});
} }
return block1([], [b2, b3]); return block1([], [b2, b3]);
} }
@@ -272,7 +258,6 @@ exports[`can catch errors can catch an error in the initial call of a component
"function anonymous(bdom, helpers "function anonymous(bdom, helpers
) { ) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom; let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { markRaw } = helpers;
let block1 = createBlock(\`<div><block-child-0/></div>\`); let block1 = createBlock(\`<div><block-child-0/></div>\`);
@@ -281,7 +266,7 @@ exports[`can catch errors can catch an error in the initial call of a component
} }
return function template(ctx, node, key = \\"\\") { 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]); return block1([], [b3]);
} }
}" }"
@@ -300,7 +285,7 @@ exports[`can catch errors can catch an error in the initial call of a component
if (ctx['state'].error) { if (ctx['state'].error) {
b2 = text(\`Error handled\`); b2 = text(\`Error handled\`);
} else { } else {
b3 = callSlot(ctx, node, key, 'default', false, null); b3 = callSlot(ctx, node, key, 'default', false, {});
} }
return block1([], [b2, b3]); return block1([], [b2, b3]);
} }
@@ -325,7 +310,6 @@ exports[`can catch errors can catch an error in the initial call of a component
"function anonymous(bdom, helpers "function anonymous(bdom, helpers
) { ) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom; let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { markRaw } = helpers;
let block1 = createBlock(\`<div><block-child-0/></div>\`); let block1 = createBlock(\`<div><block-child-0/></div>\`);
@@ -336,7 +320,7 @@ exports[`can catch errors can catch an error in the initial call of a component
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
let b3; let b3;
if (ctx['state'].flag) { 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]); return block1([], [b3]);
} }
@@ -356,7 +340,7 @@ exports[`can catch errors can catch an error in the initial call of a component
if (ctx['state'].error) { if (ctx['state'].error) {
b2 = text(\`Error handled\`); b2 = text(\`Error handled\`);
} else { } else {
b3 = callSlot(ctx, node, key, 'default', false, null); b3 = callSlot(ctx, node, key, 'default', false, {});
} }
return block1([], [b2, b3]); return block1([], [b2, b3]);
} }
@@ -396,7 +380,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>\`); let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") { 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]); return block1([], [b2]);
} }
}" }"
@@ -470,7 +454,6 @@ exports[`can catch errors can catch an error in the mounted call 1`] = `
"function anonymous(bdom, helpers "function anonymous(bdom, helpers
) { ) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom; let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { markRaw } = helpers;
let block1 = createBlock(\`<div><block-child-0/></div>\`); let block1 = createBlock(\`<div><block-child-0/></div>\`);
@@ -479,7 +462,7 @@ exports[`can catch errors can catch an error in the mounted call 1`] = `
} }
return function template(ctx, node, key = \\"\\") { 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]); return block1([], [b3]);
} }
}" }"
@@ -498,7 +481,7 @@ exports[`can catch errors can catch an error in the mounted call 2`] = `
if (ctx['state'].error) { if (ctx['state'].error) {
b2 = text(\`Error handled\`); b2 = text(\`Error handled\`);
} else { } else {
b3 = callSlot(ctx, node, key, 'default', false, null); b3 = callSlot(ctx, node, key, 'default', false, {});
} }
return block1([], [b2, b3]); return block1([], [b2, b3]);
} }
@@ -522,7 +505,6 @@ exports[`can catch errors can catch an error in the willPatch call 1`] = `
"function anonymous(bdom, helpers "function anonymous(bdom, helpers
) { ) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom; 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>\`); let block1 = createBlock(\`<div><span><block-text-0/></span><block-child-0/></div>\`);
@@ -532,7 +514,7 @@ exports[`can catch errors can catch an error in the willPatch call 1`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
let txt1 = ctx['state'].message; 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]); return block1([txt1], [b3]);
} }
}" }"
@@ -551,7 +533,7 @@ exports[`can catch errors can catch an error in the willPatch call 2`] = `
if (ctx['state'].error) { if (ctx['state'].error) {
b2 = text(\`Error handled\`); b2 = text(\`Error handled\`);
} else { } else {
b3 = callSlot(ctx, node, key, 'default', false, null); b3 = callSlot(ctx, node, key, 'default', false, {});
} }
return block1([], [b2, b3]); return block1([], [b2, b3]);
} }
@@ -576,7 +558,6 @@ exports[`can catch errors can catch an error in the willStart call 1`] = `
"function anonymous(bdom, helpers "function anonymous(bdom, helpers
) { ) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom; let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { markRaw } = helpers;
let block1 = createBlock(\`<div><block-child-0/></div>\`); let block1 = createBlock(\`<div><block-child-0/></div>\`);
@@ -585,7 +566,7 @@ exports[`can catch errors can catch an error in the willStart call 1`] = `
} }
return function template(ctx, node, key = \\"\\") { 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]); return block1([], [b3]);
} }
}" }"
@@ -604,7 +585,7 @@ exports[`can catch errors can catch an error in the willStart call 2`] = `
if (ctx['state'].error) { if (ctx['state'].error) {
b2 = text(\`Error handled\`); b2 = text(\`Error handled\`);
} else { } else {
b3 = callSlot(ctx, node, key, 'default', false, null); b3 = callSlot(ctx, node, key, 'default', false, {});
} }
return block1([], [b2, b3]); return block1([], [b2, b3]);
} }
@@ -628,18 +609,17 @@ exports[`can catch errors can catch an error origination from a child's willStar
"function anonymous(bdom, helpers "function anonymous(bdom, helpers
) { ) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom; let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { markRaw } = helpers;
let block1 = createBlock(\`<div><block-child-0/></div>\`); let block1 = createBlock(\`<div><block-child-0/></div>\`);
function slot1(ctx, node, key = \\"\\") { function slot1(ctx, node, key = \\"\\") {
const b3 = component(\`ClassicCompoent\`, {}, key + \`__1\`, node, ctx); let b3 = component(\`ClassicCompoent\`, {}, key + \`__1\`, node, ctx);
const b4 = component(\`ErrorComponent\`, {}, key + \`__2\`, node, ctx); let b4 = component(\`ErrorComponent\`, {}, key + \`__2\`, node, ctx);
return multi([b3, b4]); return multi([b3, b4]);
} }
return function template(ctx, node, key = \\"\\") { 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]); return block1([], [b5]);
} }
}" }"
@@ -658,7 +638,7 @@ exports[`can catch errors can catch an error origination from a child's willStar
if (ctx['state'].error) { if (ctx['state'].error) {
b2 = text(\`Error handled\`); b2 = text(\`Error handled\`);
} else { } else {
b3 = callSlot(ctx, node, key, 'default', false, null); b3 = callSlot(ctx, node, key, 'default', false, {});
} }
return block1([], [b2, b3]); return block1([], [b2, b3]);
} }
@@ -718,7 +698,7 @@ exports[`can catch errors catchError in catchError 2`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`); let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") { 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]); return block1([], [b2]);
} }
}" }"
@@ -742,22 +722,22 @@ exports[`can catch errors catching error, rethrow, render parent -- a main comp
"function anonymous(bdom, helpers "function anonymous(bdom, helpers
) { ) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom; 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 = \\"\\") { 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 toggler(Comp1, component(Comp1, {}, key + \`__1\`, node, ctx));
} }
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx); 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++) { for (let i1 = 0; i1 < l_block1; i1++) {
ctx[\`cp\`] = v_block1[i1]; ctx[\`cp\`] = v_block1[i1];
const key1 = ctx['cp'].id; let key1 = ctx['cp'].id;
const v1 = ctx['cp']; const v1 = ctx['cp'];
const ctx1 = capture(ctx); 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); return list(c_block1);
} }
@@ -771,7 +751,7 @@ exports[`can catch errors catching error, rethrow, render parent -- a main comp
let { callSlot } = helpers; let { callSlot } = helpers;
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
return callSlot(ctx, node, key, 'default', false, null); return callSlot(ctx, node, key, 'default', false, {});
} }
}" }"
`; `;
@@ -817,22 +797,22 @@ exports[`can catch errors catching in child makes parent render 1`] = `
"function anonymous(bdom, helpers "function anonymous(bdom, helpers
) { ) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom; 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 = \\"\\") { 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 toggler(Comp1, component(Comp1, {id: ctx['elem'][0]}, key + \`__1\`, node, ctx));
} }
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx); 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++) { for (let i1 = 0; i1 < l_block1; i1++) {
ctx[\`elem\`] = v_block1[i1]; ctx[\`elem\`] = v_block1[i1];
const key1 = ctx['elem'][0]; let key1 = ctx['elem'][0];
const v1 = ctx['elem']; const v1 = ctx['elem'];
const ctx1 = capture(ctx); 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); return list(c_block1);
} }
@@ -846,7 +826,7 @@ exports[`can catch errors catching in child makes parent render 2`] = `
let { callSlot } = helpers; let { callSlot } = helpers;
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
return callSlot(ctx, node, key, 'default', false, null); return callSlot(ctx, node, key, 'default', false, {});
} }
}" }"
`; `;
@@ -882,7 +862,6 @@ exports[`can catch errors error in mounted on a component with a sibling (proper
"function anonymous(bdom, helpers "function anonymous(bdom, helpers
) { ) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom; let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { markRaw } = helpers;
let block1 = createBlock(\`<div><block-child-0/><block-child-1/></div>\`); let block1 = createBlock(\`<div><block-child-0/><block-child-1/></div>\`);
@@ -891,8 +870,8 @@ exports[`can catch errors error in mounted on a component with a sibling (proper
} }
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const b2 = component(\`OK\`, {}, key + \`__1\`, node, ctx); let b2 = component(\`OK\`, {}, key + \`__1\`, node, ctx);
const b4 = component(\`ErrorBoundary\`, {slots: markRaw({'default': {__render: slot1, __ctx: ctx}})}, key + \`__3\`, node, ctx); let b4 = component(\`ErrorBoundary\`, {slots: {'default': {__render: slot1, __ctx: ctx}}}, key + \`__3\`, node, ctx);
return block1([], [b2, b4]); return block1([], [b2, b4]);
} }
}" }"
@@ -922,7 +901,7 @@ exports[`can catch errors error in mounted on a component with a sibling (proper
if (ctx['state'].error) { if (ctx['state'].error) {
b2 = text(\`Error handled\`); b2 = text(\`Error handled\`);
} else { } else {
b3 = callSlot(ctx, node, key, 'default', false, null); b3 = callSlot(ctx, node, key, 'default', false, {});
} }
return block1([], [b2, b3]); return block1([], [b2, b3]);
} }
@@ -1010,7 +989,7 @@ exports[`errors and promises a rendering error in a sub component will reject th
let block1 = createBlock(\`<div><block-child-0/></div>\`); let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") { 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]); return block1([], [b2]);
} }
}" }"
@@ -1052,7 +1031,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>\`); let block1 = createBlock(\`<div><block-child-0/><block-text-0/></div>\`);
return function template(ctx, node, key = \\"\\") { 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; let txt1 = ctx['x'].y;
return block1([txt1], [b2]); return block1([txt1], [b2]);
} }
@@ -1102,19 +1081,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`] = ` exports[`errors and promises an error in patched call will reject the render promise 1`] = `
"function anonymous(bdom, helpers "function anonymous(bdom, helpers
) { ) {
@@ -1156,19 +1122,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`] = ` exports[`errors and promises errors in rerender 1`] = `
"function anonymous(bdom, helpers "function anonymous(bdom, helpers
) { ) {
@@ -37,7 +37,7 @@ exports[`event handling handler receive the event as argument 1`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
let hdlr1 = [ctx['inc'], ctx]; 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; let txt1 = ctx['state'].value;
return block1([hdlr1, txt1], [b2]); 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 = \\"\\") { return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx); 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++) { for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`item\`] = v_block2[i1]; ctx[\`item\`] = v_block2[i1];
const key1 = ctx['item']; let key1 = ctx['item'];
const v1 = ctx['onClick']; const v1 = ctx['onClick'];
const v2 = ctx['item']; 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); c_block2[i1] = withKey(block3([hdlr1]), key1);
} }
const b2 = list(c_block2); let b2 = list(c_block2);
return block1([], [b2]); 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 = \\"\\") { return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx); 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++) { for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`item\`] = v_block2[i1]; ctx[\`item\`] = v_block2[i1];
const key1 = ctx['item']; let key1 = ctx['item'];
const v1 = ctx['onClick']; const v1 = ctx['onClick'];
const v2 = ctx['item']; 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); c_block2[i1] = withKey(block3([hdlr1]), key1);
} }
const b2 = list(c_block2); let b2 = list(c_block2);
return block1([], [b2]); 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>\`); let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") { 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]); return block1([], [b2]);
} }
}" }"
@@ -103,45 +103,14 @@ exports[`hooks mounted callbacks should be called in reverse order from willUnmo
}" }"
`; `;
exports[`hooks parent and child env (with useChildSubEnv then 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 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`] = ` exports[`hooks parent and child env (with useChildSubEnv) 1`] = `
"function anonymous(bdom, helpers "function anonymous(bdom, helpers
) { ) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom; let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const b2 = text(ctx['env'].val); let b2 = text(ctx['env'].val);
const b3 = component(\`Child\`, {}, key + \`__1\`, node, ctx); let b3 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
return multi([b2, b3]); return multi([b2, b3]);
} }
}" }"
@@ -167,8 +136,8 @@ exports[`hooks parent and child env (with useSubEnv) 1`] = `
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom; let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const b2 = text(ctx['env'].val); let b2 = text(ctx['env'].val);
const b3 = component(\`Child\`, {}, key + \`__1\`, node, ctx); let b3 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
return multi([b2, b3]); return multi([b2, b3]);
} }
}" }"
@@ -21,8 +21,8 @@ exports[`lifecycle hooks component semantics 1`] = `
let block1 = createBlock(\`<div>A<block-child-0/><block-child-1/></div>\`); let block1 = createBlock(\`<div>A<block-child-0/><block-child-1/></div>\`);
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const b2 = component(\`B\`, {}, key + \`__1\`, node, ctx); let b2 = component(\`B\`, {}, key + \`__1\`, node, ctx);
const b3 = component(\`C\`, {}, key + \`__2\`, node, ctx); let b3 = component(\`C\`, {}, key + \`__2\`, node, ctx);
return block1([], [b2, b3]); 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 = \\"\\") { return function template(ctx, node, key = \\"\\") {
let b2; let b2;
if (ctx['state'].flag) { 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]); b2 = block2([], [b3]);
} }
return multi([b2]); return multi([b2]);
@@ -196,7 +196,7 @@ exports[`lifecycle hooks hooks are called in proper order in widget creation/des
let block1 = createBlock(\`<div><block-child-0/></div>\`); let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") { 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]); return block1([], [b2]);
} }
}" }"
@@ -245,7 +245,7 @@ exports[`lifecycle hooks lifecycle semantics 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`); let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") { 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]); return block1([], [b2]);
} }
}" }"
@@ -458,7 +458,7 @@ exports[`lifecycle hooks mounted hook is called on subcomponents, in proper orde
let block1 = createBlock(\`<div><block-child-0/></div>\`); let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") { 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]); return block1([], [b2]);
} }
}" }"
@@ -502,7 +502,7 @@ exports[`lifecycle hooks mounted hook is called on subsubcomponents, in proper o
let block1 = createBlock(\`<div><block-child-0/></div>\`); let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") { 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]); return block1([], [b2]);
} }
}" }"
@@ -527,7 +527,7 @@ exports[`lifecycle hooks onWillRender 1`] = `
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom; let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
return component(\`Child\`, {someValue: ctx['state'].value}, key + \`__1\`, node, ctx); return component(\`Child\`, {}, key + \`__1\`, node, ctx);
} }
}" }"
`; `;
@@ -555,7 +555,7 @@ exports[`lifecycle hooks patched hook is called after updateProps 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`); let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") { 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]); return block1([], [b2]);
} }
}" }"
@@ -666,7 +666,7 @@ exports[`lifecycle hooks willPatch, patched hook are called on subsubcomponents,
let block1 = createBlock(\`<div><block-child-0/></div>\`); let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") { 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]); return block1([], [b2]);
} }
}" }"
@@ -680,7 +680,7 @@ exports[`lifecycle hooks willPatch, patched hook are called on subsubcomponents,
let block1 = createBlock(\`<div><block-child-0/></div>\`); let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") { 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]); 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>\`); let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") { 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]); return block1([], [b2]);
} }
}" }"
@@ -36,10 +36,10 @@ exports[`basics arrow functions as prop correctly capture their scope 1`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx); 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++) { for (let i1 = 0; i1 < l_block1; i1++) {
ctx[\`item\`] = v_block1[i1]; ctx[\`item\`] = v_block1[i1];
const key1 = ctx['item'].val; let key1 = ctx['item'].val;
const v1 = ctx['onClick']; const v1 = ctx['onClick'];
const v2 = ctx['item']; 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);
@@ -71,7 +71,7 @@ exports[`basics explicit object prop 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`); let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") { 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]); 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 = Object.create(ctx);
ctx[isBoundary] = 1 ctx[isBoundary] = 1
ctx[\`abc\`] = new LazyValue(value1, ctx, node); 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]); 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 = \\"\\") { return function template(ctx, node, key = \\"\\") {
let txt1 = ctx['props'].val; let txt1 = ctx['props'].val;
const b2 = safeOutput(ctx['props'].val); let b2 = safeOutput(ctx['props'].val);
return block1([txt1], [b2]); 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 = Object.create(ctx);
ctx[isBoundary] = 1 ctx[isBoundary] = 1
setContextValue(ctx, \\"abc\\", \`42\`); 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]); return block1([], [b2]);
} }
}" }"
@@ -224,7 +224,7 @@ exports[`basics t-set works 1`] = `
ctx = Object.create(ctx); ctx = Object.create(ctx);
ctx[isBoundary] = 1 ctx[isBoundary] = 1
setContextValue(ctx, \\"val\\", 42); 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]); return block1([], [b2]);
} }
}" }"
@@ -1,19 +1,6 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP // Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`default props a default prop cannot be defined on a mandatory prop 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;
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`] = `
"function anonymous(bdom, helpers "function anonymous(bdom, helpers
) { ) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom; let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
@@ -23,13 +10,13 @@ exports[`default props can set default boolean values 1`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const props1 = {}; const props1 = {};
helpers.validateProps(\`SubComp\`, props1, ctx); helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx); let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]); 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 "function anonymous(bdom, helpers
) { ) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom; let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
@@ -59,7 +46,7 @@ exports[`default props can set default values 1`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const props1 = {}; const props1 = {};
helpers.validateProps(\`SubComp\`, props1, ctx); helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx); let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -89,7 +76,7 @@ exports[`default props default values are also set whenever component is updated
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['state'].p}; const props1 = {p: ctx['state'].p};
helpers.validateProps(\`SubComp\`, props1, ctx); helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx); let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -171,7 +158,7 @@ exports[`props validation can validate a prop with multiple types 1`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']}; const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx); helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx); let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -200,7 +187,7 @@ exports[`props validation can validate a prop with multiple types 3`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']}; const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx); helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx); let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -229,7 +216,7 @@ exports[`props validation can validate a prop with multiple types 5`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']}; const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx); helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx); let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -245,7 +232,7 @@ exports[`props validation can validate an array with given primitive type 1`] =
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']}; const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx); helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx); let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -274,7 +261,7 @@ exports[`props validation can validate an array with given primitive type 3`] =
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']}; const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx); helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx); let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -303,7 +290,7 @@ exports[`props validation can validate an array with given primitive type 5`] =
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']}; const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx); helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx); let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -319,7 +306,7 @@ exports[`props validation can validate an array with given primitive type 6`] =
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']}; const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx); helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx); let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -335,7 +322,7 @@ exports[`props validation can validate an array with multiple sub element types
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']}; const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx); helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx); let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -364,7 +351,7 @@ exports[`props validation can validate an array with multiple sub element types
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']}; const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx); helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx); let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -393,7 +380,7 @@ exports[`props validation can validate an array with multiple sub element types
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']}; const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx); helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx); let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -422,7 +409,7 @@ exports[`props validation can validate an array with multiple sub element types
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']}; const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx); helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx); let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -438,7 +425,7 @@ exports[`props validation can validate an object with simple shape 1`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']}; const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx); helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx); let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -467,7 +454,7 @@ exports[`props validation can validate an object with simple shape 3`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']}; const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx); helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx); let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -483,7 +470,7 @@ exports[`props validation can validate an object with simple shape 4`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']}; const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx); helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx); let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -499,7 +486,7 @@ exports[`props validation can validate an object with simple shape 5`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']}; const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx); helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx); let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -515,7 +502,7 @@ exports[`props validation can validate an optional props 1`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']}; const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx); helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx); let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -544,7 +531,7 @@ exports[`props validation can validate an optional props 3`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']}; const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx); helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx); let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -573,7 +560,7 @@ exports[`props validation can validate an optional props 5`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']}; const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx); helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx); let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -589,7 +576,7 @@ exports[`props validation can validate recursively complicated prop def 1`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']}; const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx); helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx); let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -618,7 +605,7 @@ exports[`props validation can validate recursively complicated prop def 3`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']}; const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx); helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx); let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -647,7 +634,7 @@ exports[`props validation can validate recursively complicated prop def 5`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']}; const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx); helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx); let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -663,7 +650,7 @@ exports[`props validation default values are applied before validating props at
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['state'].p}; const props1 = {p: ctx['state'].p};
helpers.validateProps(\`SubComp\`, props1, ctx); helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx); let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -693,7 +680,7 @@ exports[`props validation missing required boolean prop causes an error 1`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const props1 = {}; const props1 = {};
helpers.validateProps(\`SubComp\`, props1, ctx); helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx); let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -709,7 +696,7 @@ exports[`props validation mix of optional and mandatory 1`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const props1 = {}; const props1 = {};
helpers.validateProps(\`Child\`, props1, ctx); helpers.validateProps(\`Child\`, props1, ctx);
const b2 = component(\`Child\`, props1, key + \`__1\`, node, ctx); let b2 = component(\`Child\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -725,7 +712,7 @@ exports[`props validation props are validated in dev mode (code snapshot) 1`] =
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const props1 = {message: 1}; const props1 = {message: 1};
helpers.validateProps(\`Child\`, props1, ctx); helpers.validateProps(\`Child\`, props1, ctx);
const b2 = component(\`Child\`, props1, key + \`__1\`, node, ctx); let b2 = component(\`Child\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -755,7 +742,7 @@ exports[`props validation props are validated whenever component is updated 1`]
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['state'].p}; const props1 = {p: ctx['state'].p};
helpers.validateProps(\`SubComp\`, props1, ctx); helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx); let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -785,7 +772,7 @@ exports[`props validation props: list of strings 1`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const props1 = {}; const props1 = {};
helpers.validateProps(\`SubComp\`, props1, ctx); helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx); let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -801,7 +788,7 @@ exports[`props validation validate simple types 1`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']}; const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx); helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx); let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -817,7 +804,7 @@ exports[`props validation validate simple types 2`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']}; const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx); helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx); let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -846,7 +833,7 @@ exports[`props validation validate simple types 4`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']}; const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx); helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx); let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -862,7 +849,7 @@ exports[`props validation validate simple types 5`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']}; const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx); helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx); let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -878,7 +865,7 @@ exports[`props validation validate simple types 6`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']}; const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx); helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx); let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -907,7 +894,7 @@ exports[`props validation validate simple types 8`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']}; const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx); helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx); let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -923,7 +910,7 @@ exports[`props validation validate simple types 9`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']}; const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx); helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx); let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -939,7 +926,7 @@ exports[`props validation validate simple types 10`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']}; const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx); helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx); let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -968,7 +955,7 @@ exports[`props validation validate simple types 12`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']}; const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx); helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx); let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -984,7 +971,7 @@ exports[`props validation validate simple types 13`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']}; const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx); helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx); let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -1000,7 +987,7 @@ exports[`props validation validate simple types 14`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']}; const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx); helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx); let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -1029,7 +1016,7 @@ exports[`props validation validate simple types 16`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']}; const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx); helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx); let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -1045,7 +1032,7 @@ exports[`props validation validate simple types 17`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']}; const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx); helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx); let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -1061,7 +1048,7 @@ exports[`props validation validate simple types 18`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']}; const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx); helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx); let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -1090,7 +1077,7 @@ exports[`props validation validate simple types 20`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']}; const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx); helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx); let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -1106,7 +1093,7 @@ exports[`props validation validate simple types 21`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']}; const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx); helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx); let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -1122,7 +1109,7 @@ exports[`props validation validate simple types 22`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']}; const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx); helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx); let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -1151,7 +1138,7 @@ exports[`props validation validate simple types 24`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']}; const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx); helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx); let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -1167,7 +1154,7 @@ exports[`props validation validate simple types, alternate form 1`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']}; const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx); helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx); let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -1183,7 +1170,7 @@ exports[`props validation validate simple types, alternate form 2`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']}; const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx); helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx); let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -1212,7 +1199,7 @@ exports[`props validation validate simple types, alternate form 4`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']}; const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx); helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx); let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -1228,7 +1215,7 @@ exports[`props validation validate simple types, alternate form 5`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']}; const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx); helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx); let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -1244,7 +1231,7 @@ exports[`props validation validate simple types, alternate form 6`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']}; const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx); helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx); let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -1273,7 +1260,7 @@ exports[`props validation validate simple types, alternate form 8`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']}; const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx); helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx); let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -1289,7 +1276,7 @@ exports[`props validation validate simple types, alternate form 9`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']}; const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx); helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx); let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -1305,7 +1292,7 @@ exports[`props validation validate simple types, alternate form 10`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']}; const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx); helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx); let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -1334,7 +1321,7 @@ exports[`props validation validate simple types, alternate form 12`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']}; const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx); helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx); let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -1350,7 +1337,7 @@ exports[`props validation validate simple types, alternate form 13`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']}; const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx); helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx); let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -1366,7 +1353,7 @@ exports[`props validation validate simple types, alternate form 14`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']}; const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx); helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx); let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -1395,7 +1382,7 @@ exports[`props validation validate simple types, alternate form 16`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']}; const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx); helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx); let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -1411,7 +1398,7 @@ exports[`props validation validate simple types, alternate form 17`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']}; const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx); helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx); let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -1427,7 +1414,7 @@ exports[`props validation validate simple types, alternate form 18`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']}; const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx); helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx); let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -1456,7 +1443,7 @@ exports[`props validation validate simple types, alternate form 20`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']}; const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx); helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx); let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -1472,7 +1459,7 @@ exports[`props validation validate simple types, alternate form 21`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']}; const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx); helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx); let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -1488,7 +1475,7 @@ exports[`props validation validate simple types, alternate form 22`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']}; const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx); helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx); let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -1517,7 +1504,7 @@ exports[`props validation validate simple types, alternate form 24`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const props1 = {p: ctx['p']}; const props1 = {p: ctx['p']};
helpers.validateProps(\`SubComp\`, props1, ctx); helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx); let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -1533,7 +1520,7 @@ exports[`props validation validation is only done in dev mode 1`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const props1 = {}; const props1 = {};
helpers.validateProps(\`SubComp\`, props1, ctx); helpers.validateProps(\`SubComp\`, props1, ctx);
const b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx); let b2 = component(\`SubComp\`, props1, key + \`__1\`, node, ctx);
return block1([], [b2]); 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>\`); let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") { 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]); return block1([], [b2]);
} }
}" }"
@@ -28,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`] = ` exports[`reactivity in lifecycle change state while mounting component 1`] = `
"function anonymous(bdom, helpers "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`] = ` exports[`refs refs are properly bound in slots 1`] = `
"function anonymous(bdom, helpers "function anonymous(bdom, helpers
) { ) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom; 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 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>\`); 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 = \\"\\") { return function template(ctx, node, key = \\"\\") {
let txt1 = ctx['state'].val; let txt1 = ctx['state'].val;
const ctx1 = capture(ctx); 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]); 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>\`); let block1 = createBlock(\`<span><block-child-0/></span>\`);
return function template(ctx, node, key = \\"\\") { 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]); 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 = \\"\\") { return function template(ctx, node, key = \\"\\") {
const refs = ctx.__owl__.refs; const refs = ctx.__owl__.refs;
const ref1 = multiRefSetter(refs, \`coucou\`); const ref1 = multiRefSetter(refs, \`coucou\`);
const b2 = block2([ref1]); let b2 = block2([ref1]);
const b3 = block3([ref1]); let b3 = block3([ref1]);
return multi([b2, b3]); return multi([b2, b3]);
} }
}" }"
@@ -1,212 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`force render in case of existing render 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
return component(\`B\`, {val: ctx['state'].val}, key + \`__1\`, node, ctx);
}
}"
`;
exports[`force render in case of existing render 2`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
const b2 = component(\`C\`, {}, key + \`__1\`, node, ctx);
const b3 = text(ctx['props'].val);
return multi([b2, b3]);
}
}"
`;
exports[`force render in case of existing render 3`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
return text(\`C\`);
}
}"
`;
exports[`rendering semantics can force a render to update sub tree 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
const b2 = text(ctx['state'].value);
const b3 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
return multi([b2, b3]);
}
}"
`;
exports[`rendering semantics can force a render to update sub tree 2`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
return text(\`child\`);
}
}"
`;
exports[`rendering semantics can render a parent without rendering child 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
const b2 = text(ctx['state'].value);
const b3 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
return multi([b2, b3]);
}
}"
`;
exports[`rendering semantics can render a parent without rendering child 2`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
return text(\`child\`);
}
}"
`;
exports[`rendering semantics props are reactive (nested prop) 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
return component(\`Child\`, {a: ctx['state']}, key + \`__1\`, node, ctx);
}
}"
`;
exports[`rendering semantics props are reactive (nested prop) 2`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
return text(ctx['props'].a.b.c);
}
}"
`;
exports[`rendering semantics props are reactive 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
return component(\`Child\`, {a: ctx['state']}, key + \`__1\`, node, ctx);
}
}"
`;
exports[`rendering semantics props are reactive 2`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
return text(ctx['props'].a.b);
}
}"
`;
exports[`rendering semantics render with deep=true followed by render with deep=false work as expected 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
const b2 = text(\`parent\`);
const b3 = text(ctx['state'].value);
const b4 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
return multi([b2, b3, b4]);
}
}"
`;
exports[`rendering semantics render with deep=true followed by render with deep=false work as expected 2`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
const b2 = text(\`child\`);
const b3 = text(ctx['env'].getValue());
return multi([b2, b3]);
}
}"
`;
exports[`rendering semantics rendering is atomic (for one subtree) 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
const b2 = text(ctx['state'].obj.val);
const b3 = component(\`B\`, {obj: ctx['state'].obj}, key + \`__1\`, node, ctx);
return multi([b2, b3]);
}
}"
`;
exports[`rendering semantics rendering is atomic (for one subtree) 2`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
return component(\`C\`, {obj: ctx['props'].obj}, key + \`__1\`, node, ctx);
}
}"
`;
exports[`rendering semantics rendering is atomic (for one subtree) 3`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
return text(ctx['props'].obj.val);
}
}"
`;
exports[`rendering semantics works as expected for dynamic number of props 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
return component(\`Child\`, Object.assign({}, ctx['state']), key + \`__1\`, node, ctx);
}
}"
`;
exports[`rendering semantics works as expected for dynamic number of props 2`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
return text(Object.keys(ctx['props']).length);
}
}"
`;
File diff suppressed because it is too large Load Diff
@@ -20,9 +20,9 @@ exports[`style and class handling can set class on multi root component 2`] = `
let block3 = createBlock(\`<span block-attribute-0=\\"class\\">b</span>\`); let block3 = createBlock(\`<span block-attribute-0=\\"class\\">b</span>\`);
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const b2 = block2(); let b2 = block2();
let attr1 = ctx['props'].class; let attr1 = ctx['props'].class;
const b3 = block3([attr1]); let b3 = block3([attr1]);
return multi([b2, b3]); return multi([b2, b3]);
} }
}" }"
@@ -205,7 +205,7 @@ exports[`style and class handling class with extra whitespaces (variation) 1`] =
let block1 = createBlock(\`<p><block-child-0/></p>\`); let block1 = createBlock(\`<p><block-child-0/></p>\`);
return function template(ctx, node, key = \\"\\") { 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]); 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>\`); let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") { 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]); 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>\`); let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") { 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]); return block1([], [b2]);
} }
}" }"
@@ -9,7 +9,7 @@ exports[`t-call dynamic t-call 1`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx); ctx = Object.create(ctx);
ctx[isBoundary] = 1; ctx[isBoundary] = 1;
const b1 = text(\` owl \`); let b1 = text(\` owl \`);
ctx[zero] = b1; ctx[zero] = b1;
const template1 = (ctx['current'].template); const template1 = (ctx['current'].template);
return call(this, template1, ctx, node, key + \`__1\`); 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; let { call } = helpers;
return function template(ctx, node, key = \\"\\") { 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 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]); 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 = \\"\\") { return function template(ctx, node, key = \\"\\") {
const template1 = ('__template__999'); 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']; let txt1 = ctx['counter'];
return block1([txt1], [b2]); 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>\`); let block1 = createBlock(\`<div><block-child-0/><block-text-0/></div>\`);
return function template(ctx, node, key = \\"\\") { 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']; let txt1 = ctx['counter'];
return block1([txt1], [b2]); 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>\`); let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") { 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]); 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>\`); let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") { 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]); return block1([], [b2]);
} }
}" }"
@@ -266,7 +266,7 @@ exports[`t-call recursive t-call binding this -- static t-call 1`] = `
ctx = Object.create(ctx); ctx = Object.create(ctx);
ctx[isBoundary] = 1; ctx[isBoundary] = 1;
setContextValue(ctx, \\"level\\", 0); 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]); return block1([], [b2]);
} }
}" }"
@@ -288,11 +288,11 @@ exports[`t-call recursive t-call binding this -- static t-call 2`] = `
if (ctx['level']<2) { if (ctx['level']<2) {
let hdlr1 = [\\"stop\\", ctx['onClicked'].bind(this), ctx]; let hdlr1 = [\\"stop\\", ctx['onClicked'].bind(this), ctx];
let txt1 = ctx['level']; let txt1 = ctx['level'];
const b3 = block3([hdlr1, txt1]); let b3 = block3([hdlr1, txt1]);
ctx = Object.create(ctx); ctx = Object.create(ctx);
ctx[isBoundary] = 1; ctx[isBoundary] = 1;
setContextValue(ctx, \\"level\\", ctx['level']+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__; ctx = ctx.__proto__;
b2 = multi([b3, b4]); b2 = multi([b3, b4]);
} }
@@ -316,7 +316,7 @@ exports[`t-call sub components in two t-calls 1`] = `
if (ctx['state'].val===1) { if (ctx['state'].val===1) {
b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`); b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
} else { } else {
const b4 = callTemplate_2.call(this, ctx, node, key + \`__2\`); let b4 = callTemplate_2.call(this, ctx, node, key + \`__2\`);
b3 = block3([], [b4]); b3 = block3([], [b4]);
} }
return multi([b2, b3]); 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 = \\"\\") { return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx); 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++) { for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`val\`] = v_block2[i1]; ctx[\`val\`] = v_block2[i1];
ctx[\`val_first\`] = i1 === 0; ctx[\`val_first\`] = i1 === 0;
ctx[\`val_last\`] = i1 === v_block2.length - 1; ctx[\`val_last\`] = i1 === v_block2.length - 1;
ctx[\`val_index\`] = i1; ctx[\`val_index\`] = i1;
ctx[\`val_value\`] = k_block2[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); 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]); 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>\`); let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const b2 = ctx['myBlock'](); let b2 = ctx['myBlock']();
return block1([], [b2]); 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>\`); let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const Comp1 = ctx['constructor'].components[ctx['state'].child]; let Comp1 = ctx['constructor'].components[ctx['state'].child];
const b2 = toggler(Comp1, component(Comp1, {}, key + \`__1\`, node, ctx)); let b2 = toggler(Comp1, component(Comp1, {}, key + \`__1\`, node, ctx));
return block1([], [b2]); 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 = \\"\\") { return function template(ctx, node, key = \\"\\") {
const tKey_1 = ctx['state'].child; 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))); 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 = \\"\\") { return function template(ctx, node, key = \\"\\") {
const tKey_1 = ctx['state'].child; 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))); 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>\`); let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const Comp1 = ctx['Counter']; let Comp1 = ctx['Counter'];
const b2 = toggler(Comp1, component(Comp1, {}, key + \`__1\`, node, ctx)); let b2 = toggler(Comp1, component(Comp1, {}, key + \`__1\`, node, ctx));
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -156,7 +156,7 @@ exports[`t-component switching dynamic component 1`] = `
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom; let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const Comp1 = ctx['Child']; let Comp1 = ctx['Child'];
return toggler(Comp1, component(Comp1, {}, key + \`__1\`, node, ctx)); 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; let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const Comp1 = ctx['Child']; let Comp1 = ctx['Child'];
return toggler(Comp1, component(Comp1, {}, key + \`__1\`, node, ctx)); 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 = \\"\\") { return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx); 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++) { for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`item\`] = v_block2[i1]; ctx[\`item\`] = v_block2[i1];
const key1 = 'li_'+ctx['item']; let key1 = 'li_'+ctx['item'];
const b4 = component(\`Child\`, {item: ctx['item']}, key + \`__1__\${key1}\`, node, ctx); let b4 = component(\`Child\`, {item: ctx['item']}, key + \`__1__\${key1}\`, node, ctx);
c_block2[i1] = withKey(block3([], [b4]), key1); c_block2[i1] = withKey(block3([], [b4]), key1);
} }
const b2 = list(c_block2); let b2 = list(c_block2);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -46,11 +46,11 @@ exports[`list of components crash on duplicate key in dev mode 1`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx); 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(); const keys1 = new Set();
for (let i1 = 0; i1 < l_block1; i1++) { for (let i1 = 0; i1 < l_block1; i1++) {
ctx[\`item\`] = v_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}\`)} if (keys1.has(key1)) { throw new Error(\`Got duplicate key in t-foreach: \${key1}\`)}
keys1.add(key1); keys1.add(key1);
const props1 = {}; const props1 = {};
@@ -84,14 +84,14 @@ exports[`list of components list of sub components inside other nodes 1`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx); 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++) { for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`blip\`] = v_block2[i1]; ctx[\`blip\`] = v_block2[i1];
const key1 = ctx['blip'].id; let key1 = ctx['blip'].id;
const b4 = component(\`SubComponent\`, {}, key + \`__1__\${key1}\`, node, ctx); let b4 = component(\`SubComponent\`, {}, key + \`__1__\${key1}\`, node, ctx);
c_block2[i1] = withKey(block3([], [b4]), key1); c_block2[i1] = withKey(block3([], [b4]), key1);
} }
const b2 = list(c_block2); let b2 = list(c_block2);
return block1([], [b2]); 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 = \\"\\") { return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx); 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++) { for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`section\`] = v_block2[i1]; ctx[\`section\`] = v_block2[i1];
ctx[\`section_index\`] = i1; ctx[\`section_index\`] = i1;
const key1 = ctx['section_index']; let key1 = ctx['section_index'];
ctx = Object.create(ctx); 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++) { for (let i2 = 0; i2 < l_block3; i2++) {
ctx[\`blip\`] = v_block3[i2]; ctx[\`blip\`] = v_block3[i2];
ctx[\`blip_index\`] = 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); c_block3[i2] = withKey(component(\`Child\`, {blip: ctx['blip']}, key + \`__1__\${key1}__\${key2}\`, node, ctx), key2);
} }
ctx = ctx.__proto__; ctx = ctx.__proto__;
c_block2[i1] = withKey(list(c_block3), key1); c_block2[i1] = withKey(list(c_block3), key1);
} }
const b2 = list(c_block2); let b2 = list(c_block2);
return block1([], [b2]); 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 = \\"\\") { return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx); 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++) { for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`row\`] = v_block2[i1]; ctx[\`row\`] = v_block2[i1];
const key1 = ctx['row']; let key1 = ctx['row'];
ctx = Object.create(ctx); 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++) { for (let i2 = 0; i2 < l_block4; i2++) {
ctx[\`col\`] = v_block4[i2]; ctx[\`col\`] = v_block4[i2];
const key2 = ctx['col']; let key2 = ctx['col'];
const b6 = component(\`Child\`, {row: ctx['row'], col: ctx['col']}, key + \`__1__\${key1}__\${key2}\`, node, ctx); let b6 = component(\`Child\`, {row: ctx['row'],col: ctx['col']}, key + \`__1__\${key1}__\${key2}\`, node, ctx);
c_block4[i2] = withKey(block5([], [b6]), key2); c_block4[i2] = withKey(block5([], [b6]), key2);
} }
ctx = ctx.__proto__; ctx = ctx.__proto__;
const b4 = list(c_block4); let b4 = list(c_block4);
c_block2[i1] = withKey(block3([], [b4]), key1); c_block2[i1] = withKey(block3([], [b4]), key1);
} }
const b2 = list(c_block2); let b2 = list(c_block2);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -212,10 +212,10 @@ exports[`list of components simple list 1`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx); 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++) { for (let i1 = 0; i1 < l_block1; i1++) {
ctx[\`elem\`] = v_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); c_block1[i1] = withKey(component(\`Child\`, {value: ctx['elem'].value}, key + \`__1__\${key1}\`, node, ctx), key1);
} }
return list(c_block1); 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 = \\"\\") { return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx); 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++) { for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`number\`] = v_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); 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]); 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 = \\"\\") { return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx); 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++) { for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`number\`] = v_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); 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]); return block1([], [b2]);
} }
}" }"
@@ -319,13 +319,13 @@ exports[`list of components switch component position 1`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx); 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++) { for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`c\`] = v_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); 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]); 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 = \\"\\") { return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx); 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++) { for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`n\`] = v_block2[i1]; ctx[\`n\`] = v_block2[i1];
ctx[\`n_index\`] = 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); 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]); 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 = \\"\\") { return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx); 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++) { for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`c\`] = v_block2[i1]; ctx[\`c\`] = v_block2[i1];
const key1 = ctx['c']; let key1 = ctx['c'];
const tKey_1 = ctx['key1']; 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); 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]); return block1([], [b2]);
} }
}" }"
@@ -72,7 +72,7 @@ exports[`t-key t-key on Component as a function 1`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const tKey_1 = ctx['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]); return block1([], [b2]);
} }
}" }"
@@ -101,9 +101,9 @@ exports[`t-key t-key on multiple Components 1`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const tKey_1 = ctx['key1']; 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 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]); 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 = Object.create(ctx);
ctx[isBoundary] = 1; ctx[isBoundary] = 1;
setContextValue(ctx, \\"key\\", ctx['key1']); 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 = ctx.__proto__;
ctx = Object.create(ctx); ctx = Object.create(ctx);
ctx[isBoundary] = 1; ctx[isBoundary] = 1;
setContextValue(ctx, \\"key\\", ctx['key2']); 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]); 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>\`); let block1 = createBlock(\`<span><block-child-0/></span>\`);
return function template(ctx, node, key = \\"\\") { 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]); 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 = \\"\\") { return function template(ctx, node, key = \\"\\") {
const tKey_1 = ctx['key1']; 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 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]); return multi([b2, b3]);
} }
}" }"
@@ -194,17 +194,17 @@ exports[`t-model directive in a t-foreach 1`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx); 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++) { for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`thing\`] = v_block2[i1]; ctx[\`thing\`] = v_block2[i1];
const key1 = ctx['thing'].id; let key1 = ctx['thing'].id;
const bExpr1 = ctx['thing']; const bExpr1 = ctx['thing'];
const expr1 = 'f'; const expr1 = 'f';
let attr1 = bExpr1[expr1]; let attr1 = bExpr1[expr1];
let hdlr1 = [(ev) => { bExpr1[expr1] = ev.target.checked; }]; let hdlr1 = [(ev) => { bExpr1[expr1] = ev.target.checked; }];
c_block2[i1] = withKey(block3([attr1, hdlr1]), key1); c_block2[i1] = withKey(block3([attr1, hdlr1]), key1);
} }
const b2 = list(c_block2); let b2 = list(c_block2);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -221,18 +221,18 @@ exports[`t-model directive in a t-foreach, part 2 1`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx); 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++) { for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`thing\`] = v_block2[i1]; ctx[\`thing\`] = v_block2[i1];
ctx[\`thing_index\`] = i1; ctx[\`thing_index\`] = i1;
const key1 = ctx['thing_index']; let key1 = ctx['thing_index'];
const bExpr1 = ctx['state']; const bExpr1 = ctx['state'];
const expr1 = ctx['thing_index']; const expr1 = ctx['thing_index'];
let attr1 = bExpr1[expr1]; let attr1 = bExpr1[expr1];
let hdlr1 = [(ev) => { bExpr1[expr1] = ev.target.value; }]; let hdlr1 = [(ev) => { bExpr1[expr1] = ev.target.value; }];
c_block2[i1] = withKey(block3([attr1, hdlr1]), key1); c_block2[i1] = withKey(block3([attr1, hdlr1]), key1);
} }
const b2 = list(c_block2); let b2 = list(c_block2);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -249,18 +249,18 @@ exports[`t-model directive in a t-foreach, part 3 1`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx); ctx = Object.create(ctx);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['names']);; const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['names']);
for (let i1 = 0; i1 < l_block2; i1++) { for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`name\`] = v_block2[i1]; ctx[\`name\`] = v_block2[i1];
ctx[\`name_index\`] = i1; ctx[\`name_index\`] = i1;
const key1 = ctx['name_index']; let key1 = ctx['name_index'];
const bExpr1 = ctx['state'].values; const bExpr1 = ctx['state'].values;
const expr1 = ctx['name']; const expr1 = ctx['name'];
let attr1 = bExpr1[expr1]; let attr1 = bExpr1[expr1];
let hdlr1 = [(ev) => { bExpr1[expr1] = ev.target.value; }]; let hdlr1 = [(ev) => { bExpr1[expr1] = ev.target.value; }];
c_block2[i1] = withKey(block3([attr1, hdlr1]), key1); c_block2[i1] = withKey(block3([attr1, hdlr1]), key1);
} }
const b2 = list(c_block2); let b2 = list(c_block2);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -410,24 +410,6 @@ exports[`t-model directive on an textarea 1`] = `
}" }"
`; `;
exports[`t-model directive t-model on an input with an undefined value 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { toNumber } = helpers;
let block1 = createBlock(\`<input block-attribute-0=\\"value\\" block-handler-1=\\"input\\"/>\`);
return function template(ctx, node, key = \\"\\") {
const bExpr1 = ctx['state'];
const expr1 = 'text';
let attr1 = bExpr1[expr1];
let hdlr1 = [(ev) => { bExpr1[expr1] = ev.target.value; }];
return block1([attr1, hdlr1]);
}
}"
`;
exports[`t-model directive t-model on select with static options 1`] = ` exports[`t-model directive t-model on select with static options 1`] = `
"function anonymous(bdom, helpers "function anonymous(bdom, helpers
) { ) {
@@ -460,7 +442,7 @@ exports[`t-model directive t-model with dynamic values on select options -- 2 1`
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const bExpr1 = ctx['state']; const bExpr1 = ctx['state'];
const expr1 = 'model'; const expr1 = 'model';
const bValue1 = bExpr1[expr1]; let bValue1 = bExpr1[expr1]
let hdlr1 = [(ev) => { bExpr1[expr1] = ev.target.value; }]; let hdlr1 = [(ev) => { bExpr1[expr1] = ev.target.value; }];
let attr1 = ctx['options'][0]; let attr1 = ctx['options'][0];
let attr2 = bValue1 === ctx['options'][0]; let attr2 = bValue1 === ctx['options'][0];
@@ -484,7 +466,7 @@ exports[`t-model directive t-model with dynamic values on select options -- 3 1`
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const bExpr1 = ctx['state']; const bExpr1 = ctx['state'];
const expr1 = 'model'; const expr1 = 'model';
const bValue1 = bExpr1[expr1]; let bValue1 = bExpr1[expr1]
let hdlr1 = [(ev) => { bExpr1[expr1] = ev.target.value; }]; let hdlr1 = [(ev) => { bExpr1[expr1] = ev.target.value; }];
let attr1 = ctx['options'][0]; let attr1 = ctx['options'][0];
let attr2 = bValue1 === ctx['options'][0]; let attr2 = bValue1 === ctx['options'][0];
@@ -507,7 +489,7 @@ exports[`t-model directive t-model with dynamic values on select options 1`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const bExpr1 = ctx['state']; const bExpr1 = ctx['state'];
const expr1 = 'model'; const expr1 = 'model';
const bValue1 = bExpr1[expr1]; let bValue1 = bExpr1[expr1]
let hdlr1 = [(ev) => { bExpr1[expr1] = ev.target.value; }]; let hdlr1 = [(ev) => { bExpr1[expr1] = ev.target.value; }];
let attr1 = ctx['options'][0]; let attr1 = ctx['options'][0];
let attr2 = bValue1 === ctx['options'][0]; let attr2 = bValue1 === ctx['options'][0];
@@ -532,19 +514,19 @@ exports[`t-model directive t-model with dynamic values on select options in fore
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const bExpr1 = ctx['state']; const bExpr1 = ctx['state'];
const expr1 = 'model'; const expr1 = 'model';
const bValue1 = bExpr1[expr1]; let bValue1 = bExpr1[expr1]
let hdlr1 = [(ev) => { bExpr1[expr1] = ev.target.value; }]; let hdlr1 = [(ev) => { bExpr1[expr1] = ev.target.value; }];
ctx = Object.create(ctx); ctx = Object.create(ctx);
const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['options']);; const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['options']);
for (let i1 = 0; i1 < l_block2; i1++) { for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`v\`] = v_block2[i1]; ctx[\`v\`] = v_block2[i1];
const key1 = ctx['v']; let key1 = ctx['v'];
let attr1 = ctx['v']; let attr1 = ctx['v'];
let attr2 = bValue1 === ctx['v']; let attr2 = bValue1 === ctx['v'];
let txt1 = ctx['v']; let txt1 = ctx['v'];
c_block2[i1] = withKey(block3([attr1, attr2, txt1]), key1); c_block2[i1] = withKey(block3([attr1, attr2, txt1]), key1);
} }
const b2 = list(c_block2); let b2 = list(c_block2);
return block1([hdlr1], [b2]); return block1([hdlr1], [b2]);
} }
}" }"
+12 -147
View File
@@ -14,17 +14,17 @@ exports[`t-on t-on expression captured in t-foreach 1`] = `
ctx[isBoundary] = 1 ctx[isBoundary] = 1
setContextValue(ctx, \\"iter\\", 0); setContextValue(ctx, \\"iter\\", 0);
ctx = Object.create(ctx); 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++) { for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`val\`] = v_block2[i1]; ctx[\`val\`] = v_block2[i1];
const key1 = ctx['val']; let key1 = ctx['val'];
const v1 = ctx['otherState']; const v1 = ctx['otherState'];
const v2 = ctx['iter']; const v2 = ctx['iter'];
let hdlr1 = [()=>v1.vals.push(v2+'_'+v2), ctx]; let hdlr1 = [()=>v1.vals.push(v2+'_'+v2), ctx];
setContextValue(ctx, \\"iter\\", ctx['iter']+1); setContextValue(ctx, \\"iter\\", ctx['iter']+1);
c_block2[i1] = withKey(block3([hdlr1]), key1); c_block2[i1] = withKey(block3([hdlr1]), key1);
} }
const b2 = list(c_block2); let b2 = list(c_block2);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -41,11 +41,11 @@ exports[`t-on t-on expression in t-foreach 1`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx); 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++) { for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`val\`] = v_block2[i1]; ctx[\`val\`] = v_block2[i1];
ctx[\`val_index\`] = i1; ctx[\`val_index\`] = i1;
const key1 = ctx['val']; let key1 = ctx['val'];
let txt1 = ctx['val_index']; let txt1 = ctx['val_index'];
let txt2 = ctx['val']+''; let txt2 = ctx['val']+'';
const v1 = ctx['otherState']; 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]; let hdlr1 = [()=>v1.vals.push(v2), ctx];
c_block2[i1] = withKey(block3([txt1, txt2, hdlr1]), key1); c_block2[i1] = withKey(block3([txt1, txt2, hdlr1]), key1);
} }
const b2 = list(c_block2); let b2 = list(c_block2);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -73,11 +73,11 @@ exports[`t-on t-on expression in t-foreach with t-set 1`] = `
ctx[isBoundary] = 1 ctx[isBoundary] = 1
setContextValue(ctx, \\"bossa\\", 'nova'); setContextValue(ctx, \\"bossa\\", 'nova');
ctx = Object.create(ctx); 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++) { for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`val\`] = v_block2[i1]; ctx[\`val\`] = v_block2[i1];
ctx[\`val_index\`] = i1; ctx[\`val_index\`] = i1;
const key1 = ctx['val']; let key1 = ctx['val'];
setContextValue(ctx, \\"bossa\\", ctx['bossa']+'_'+ctx['val_index']); setContextValue(ctx, \\"bossa\\", ctx['bossa']+'_'+ctx['val_index']);
let txt1 = ctx['val_index']; let txt1 = ctx['val_index'];
let txt2 = ctx['val']+''; 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]; let hdlr1 = [()=>v1.vals.push(v2+'_'+v3), ctx];
c_block2[i1] = withKey(block3([txt1, txt2, hdlr1]), key1); c_block2[i1] = withKey(block3([txt1, txt2, hdlr1]), key1);
} }
const b2 = list(c_block2); let b2 = list(c_block2);
return block1([], [b2]); return block1([], [b2]);
} }
}" }"
@@ -104,82 +104,23 @@ exports[`t-on t-on method call in t-foreach 1`] = `
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx); 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++) { for (let i1 = 0; i1 < l_block2; i1++) {
ctx[\`val\`] = v_block2[i1]; ctx[\`val\`] = v_block2[i1];
ctx[\`val_index\`] = i1; ctx[\`val_index\`] = i1;
const key1 = ctx['val']; let key1 = ctx['val'];
let txt1 = ctx['val_index']; let txt1 = ctx['val_index'];
let txt2 = ctx['val']+''; let txt2 = ctx['val']+'';
const v1 = ctx['val']; const v1 = ctx['val'];
let hdlr1 = [()=>this.addVal(v1), ctx]; let hdlr1 = [()=>this.addVal(v1), ctx];
c_block2[i1] = withKey(block3([txt1, txt2, hdlr1]), key1); c_block2[i1] = withKey(block3([txt1, txt2, hdlr1]), key1);
} }
const b2 = list(c_block2); let b2 = list(c_block2);
return block1([], [b2]); 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`] = ` exports[`t-on t-on on destroyed components 1`] = `
"function anonymous(bdom, helpers "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>\`); let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") { 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]); return block1([], [b2]);
} }
}" }"
@@ -60,7 +60,7 @@ exports[`t-props t-props and other props 1`] = `
let block1 = createBlock(\`<div><div><block-child-0/></div></div>\`); let block1 = createBlock(\`<div><div><block-child-0/></div></div>\`);
return function template(ctx, node, key = \\"\\") { 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]); return block1([], [b2]);
} }
}" }"
@@ -89,7 +89,7 @@ exports[`t-props t-props only 1`] = `
let block1 = createBlock(\`<div><div><block-child-0/></div></div>\`); let block1 = createBlock(\`<div><div><block-child-0/></div></div>\`);
return function template(ctx, node, key = \\"\\") { 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]); return block1([], [b2]);
} }
}" }"
@@ -117,7 +117,7 @@ exports[`t-props t-props with props 1`] = `
let block1 = createBlock(\`<div><block-child-0/></div>\`); let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") { 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]); 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 "function anonymous(bdom, helpers
) { ) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom; 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>\`); 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'); setContextValue(ctx, \\"iter\\", 'source');
let txt1 = ctx['iter']; let txt1 = ctx['iter'];
const ctx1 = capture(ctx); 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']; let txt2 = ctx['iter'];
return block1([txt1, txt2], [b2]); 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 "function anonymous(bdom, helpers
) { ) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom; 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 = \\"\\") { function slot1(ctx, node, key = \\"\\") {
ctx = Object.create(ctx); ctx = Object.create(ctx);
ctx[isBoundary] = 1 ctx[isBoundary] = 1
ctx[\`v\`] = new LazyValue(value1, ctx, node); ctx[\`v\`] = new LazyValue(value1, ctx, node);
const b3 = text(\` in slot \`); let b3 = text(\` in slot \`);
const b4 = safeOutput(ctx['v']); let b4 = safeOutput(ctx['v']);
return multi([b3, b4]); 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 = \\"\\") { return function template(ctx, node, key = \\"\\") {
const ctx1 = capture(ctx); 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; let { callSlot } = helpers;
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const b2 = text(\`Child \`); let b2 = text(\`Child \`);
const b3 = callSlot(ctx, node, key, 'default', false, null); let b3 = callSlot(ctx, node, key, 'default', false, {});
return multi([b2, b3]); 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 "function anonymous(bdom, helpers
) { ) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom; 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>\`); 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 = Object.create(ctx);
ctx[isBoundary] = 1 ctx[isBoundary] = 1
ctx[\`v\`] = new LazyValue(value1, ctx, node); ctx[\`v\`] = new LazyValue(value1, ctx, node);
const b5 = text(\` tea \`); let b5 = text(\` tea \`);
const b6 = safeOutput(ctx['v']); let b6 = safeOutput(ctx['v']);
return multi([b5, b6]); return multi([b5, b6]);
} }
function value1(ctx, node, key = \\"\\") { function value1(ctx, node, key = \\"\\") {
const b3 = component(\`Child\`, {}, key + \`__1\`, node, ctx); let b3 = component(\`Child\`, {}, key + \`__1\`, node, ctx);
const b4 = block4(); let b4 = block4();
return multi([b3, b4]); return multi([b3, b4]);
} }
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const ctx1 = capture(ctx); 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; let { callSlot } = helpers;
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const b2 = text(\`Blorg \`); let b2 = text(\`Blorg \`);
const b3 = callSlot(ctx, node, key, 'default', false, null); let b3 = callSlot(ctx, node, key, 'default', false, {});
return multi([b2, b3]); 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 "function anonymous(bdom, helpers
) { ) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom; 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 = \\"\\") { function slot1(ctx, node, key = \\"\\") {
ctx = Object.create(ctx); 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 = \\"\\") { return function template(ctx, node, key = \\"\\") {
const ctx1 = capture(ctx); 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; let { callSlot } = helpers;
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
const b2 = text(\`Child \`); let b2 = text(\`Child \`);
const b3 = callSlot(ctx, node, key, 'default', false, null); let b3 = callSlot(ctx, node, key, 'default', false, {});
return multi([b2, b3]); return multi([b2, b3]);
} }
}" }"
@@ -267,7 +267,7 @@ exports[`t-set t-set not altered by child comp 1`] = `
ctx[isBoundary] = 1 ctx[isBoundary] = 1
setContextValue(ctx, \\"iter\\", 'source'); setContextValue(ctx, \\"iter\\", 'source');
let txt1 = ctx['iter']; let txt1 = ctx['iter'];
const b2 = component(\`Childcomp\`, {}, key + \`__1\`, node, ctx); let b2 = component(\`Childcomp\`, {}, key + \`__1\`, node, ctx);
let txt2 = ctx['iter']; let txt2 = ctx['iter'];
return block1([txt1, txt2], [b2]); 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 = Object.create(ctx);
ctx[isBoundary] = 1 ctx[isBoundary] = 1
ctx[\`v\`] = new LazyValue(value1, ctx, node); ctx[\`v\`] = new LazyValue(value1, ctx, node);
const b3 = safeOutput(ctx['v']); let b3 = safeOutput(ctx['v']);
return block1([], [b3]); return block1([], [b3]);
} }
}" }"
@@ -369,7 +369,7 @@ exports[`t-set t-set with something in body 1`] = `
ctx = Object.create(ctx); ctx = Object.create(ctx);
ctx[isBoundary] = 1 ctx[isBoundary] = 1
ctx[\`v\`] = new LazyValue(value1, ctx, node); ctx[\`v\`] = new LazyValue(value1, ctx, node);
const b3 = safeOutput(ctx['v']); let b3 = safeOutput(ctx['v']);
return block1([], [b3]); return block1([], [b3]);
} }
}" }"
+3 -24
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 { elem, makeTestFixture, nextTick, snapshotEverything, useLogLifecycle } from "../helpers";
import { markup } from "../../src/utils"; import { markup } from "../../src/utils";
@@ -121,7 +121,7 @@ describe("basics", () => {
class Test extends Component { class Test extends Component {
static template = xml`<span>simple vnode</span>`; static template = xml`<span>simple vnode</span>`;
setup() { setup() {
expect(toRaw(this.props)).toBe(p); expect(this.props).toBe(p);
} }
} }
@@ -171,27 +171,6 @@ describe("basics", () => {
expect(error!.message).toBe("Cannot mount a component on a detached dom node"); 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 () => { test("crashes if it cannot find a template", async () => {
class Test extends Component { class Test extends Component {
static template = "wrongtemplate"; static template = "wrongtemplate";
@@ -204,7 +183,7 @@ describe("basics", () => {
error = e as Error; error = e as Error;
} }
expect(error!).toBeDefined(); 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 () => { test("class component with dynamic text", async () => {
+18 -143
View File
@@ -39,8 +39,6 @@ Scheduler.prototype.addFiber = function (fiber: Fiber) {
afterEach(() => { afterEach(() => {
if (lastScheduler && lastScheduler.tasks.size > 0) { if (lastScheduler && lastScheduler.tasks.size > 0) {
// we still clear the scheduler to prevent additional noise
lastScheduler.tasks.clear();
throw new Error("we got a memory leak..."); throw new Error("we got a memory leak...");
} }
}); });
@@ -133,58 +131,6 @@ test("destroying/recreating a subwidget with different props (if start is not ov
]).toBeLogged(); ]).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 () => { test("creating two async components, scenario 1", async () => {
let defA = makeDeferred(); let defA = makeDeferred();
let defB = makeDeferred(); let defB = makeDeferred();
@@ -575,7 +521,7 @@ test("properly behave when destroyed/unmounted while rendering ", async () => {
} }
class Child extends Component { class Child extends Component {
static template = xml`<div><SubChild val="props.val"/></div>`; static template = xml`<div><SubChild /></div>`;
static components = { SubChild }; static components = { SubChild };
setup() { setup() {
useLogLifecycle(); useLogLifecycle();
@@ -1961,13 +1907,18 @@ test("concurrent renderings scenario 13", async () => {
await nextTick(); // wait for this change to be applied await nextTick(); // wait for this change to be applied
expect([ expect([
"Parent:willRender", "Parent:willRender",
"Child:willUpdateProps",
"Child:setup", "Child:setup",
"Child:willStart", "Child:willStart",
"Parent:rendered", "Parent:rendered",
"Child:willRender", "Child:willRender",
"Child:rendered", "Child:rendered",
"Child:willRender",
"Child:rendered",
"Parent:willPatch", "Parent:willPatch",
"Child:willPatch",
"Child:mounted", "Child:mounted",
"Child:patched",
"Parent:patched", "Parent:patched",
"Child:willRender", "Child:willRender",
"Child:rendered", "Child:rendered",
@@ -2521,9 +2472,9 @@ test("two renderings initiated between willPatch and patched", async () => {
useLogLifecycle(); useLogLifecycle();
onMounted(() => { onMounted(() => {
this.mounted = "Mounted"; this.mounted = "Mounted";
parent.render(true); parent.render();
}); });
onWillUnmount(() => parent.render(true)); onWillUnmount(() => parent.render());
} }
} }
@@ -2556,11 +2507,15 @@ test("two renderings initiated between willPatch and patched", async () => {
"Parent:rendered", "Parent:rendered",
]).toBeLogged(); ]).toBeLogged();
await nextMicroTick();
expect(["Panel:willRender", "Panel:rendered"]).toBeLogged();
await nextTick(); await nextTick();
expect(["Parent:willPatch", "Panel:willPatch", "Panel:patched", "Parent:patched"]).toBeLogged(); expect([
"Panel:willRender",
"Panel:rendered",
"Parent:willPatch",
"Panel:willPatch",
"Panel:patched",
"Parent:patched",
]).toBeLogged();
expect(fixture.innerHTML).toBe("<div><abc>Panel1Mounted</abc></div>"); expect(fixture.innerHTML).toBe("<div><abc>Panel1Mounted</abc></div>");
parent.state.panel = "Panel2"; parent.state.panel = "Panel2";
@@ -2798,20 +2753,12 @@ test("delay willUpdateProps with rendering grandchild", async () => {
static template = xml`<Parent state="state"/>`; static template = xml`<Parent state="state"/>`;
static components = { Parent }; static components = { Parent };
state = { value: 0 }; state = { value: 0 };
setup() {
useLogLifecycle();
} }
}
const parent = await mount(GrandParent, fixture); const parent = await mount(GrandParent, fixture);
expect(fixture.innerHTML).toBe("0_0<div></div>"); expect(fixture.innerHTML).toBe("0_0<div></div>");
expect([ expect([
"GrandParent:setup",
"GrandParent:willStart",
"GrandParent:willRender",
"Parent:setup", "Parent:setup",
"Parent:willStart", "Parent:willStart",
"GrandParent:rendered",
"Parent:willRender", "Parent:willRender",
"DelayedChild:setup", "DelayedChild:setup",
"DelayedChild:willStart", "DelayedChild:willStart",
@@ -2825,23 +2772,20 @@ test("delay willUpdateProps with rendering grandchild", async () => {
"ReactiveChild:mounted", "ReactiveChild:mounted",
"DelayedChild:mounted", "DelayedChild:mounted",
"Parent:mounted", "Parent:mounted",
"GrandParent:mounted",
]).toBeLogged(); ]).toBeLogged();
promise = makeDeferred(); promise = makeDeferred();
const prom1 = promise; const prom1 = promise;
parent.state.value = 1; parent.state.value = 1;
child.render(); // trigger a root rendering first child.render(); // trigger a root rendering first
parent.render(true); parent.render();
reactiveChild.render(); reactiveChild.render();
await nextTick(); await nextTick();
expect(fixture.innerHTML).toBe("0_0<div></div>"); expect(fixture.innerHTML).toBe("0_0<div></div>");
expect([ expect([
"DelayedChild:willRender", "DelayedChild:willRender",
"DelayedChild:rendered", "DelayedChild:rendered",
"GrandParent:willRender",
"Parent:willUpdateProps", "Parent:willUpdateProps",
"GrandParent:rendered",
"ReactiveChild:willRender", "ReactiveChild:willRender",
"ReactiveChild:rendered", "ReactiveChild:rendered",
"Parent:willRender", "Parent:willRender",
@@ -2856,14 +2800,12 @@ test("delay willUpdateProps with rendering grandchild", async () => {
const prom2 = promise; const prom2 = promise;
child.render(); // trigger a root rendering first child.render(); // trigger a root rendering first
parent.state.value = 2; parent.state.value = 2;
parent.render(true); parent.render();
reactiveChild.render(); reactiveChild.render();
await nextTick(); await nextTick();
expect(fixture.innerHTML).toBe("0_0<div></div>"); expect(fixture.innerHTML).toBe("0_0<div></div>");
expect([ expect([
"GrandParent:willRender",
"Parent:willUpdateProps", "Parent:willUpdateProps",
"GrandParent:rendered",
"ReactiveChild:willRender", "ReactiveChild:willRender",
"ReactiveChild:rendered", "ReactiveChild:rendered",
"Parent:willRender", "Parent:willRender",
@@ -2880,14 +2822,12 @@ test("delay willUpdateProps with rendering grandchild", async () => {
expect([ expect([
"DelayedChild:willRender", "DelayedChild:willRender",
"DelayedChild:rendered", "DelayedChild:rendered",
"GrandParent:willPatch",
"Parent:willPatch", "Parent:willPatch",
"ReactiveChild:willPatch", "ReactiveChild:willPatch",
"DelayedChild:willPatch", "DelayedChild:willPatch",
"DelayedChild:patched", "DelayedChild:patched",
"ReactiveChild:patched", "ReactiveChild:patched",
"Parent:patched", "Parent:patched",
"GrandParent:patched",
]).toBeLogged(); ]).toBeLogged();
prom1.resolve(); prom1.resolve();
@@ -3189,71 +3129,6 @@ test("Cascading renders after microtaskTick", async () => {
await nextTick(); await nextTick();
expect(fixture.innerHTML).toBe("0123 _ 0123"); expect(fixture.innerHTML).toBe("0123 _ 0123");
}); });
test("rendering parent twice, with different props on child and stuff", async () => {
class Child extends Component {
static template = xml`<t t-esc="props.value"/>`;
setup() {
useLogLifecycle();
}
}
class Parent extends Component {
static template = xml`<Child value="state.value"/>`;
static components = { Child };
state = useState({ value: 1 });
setup() {
useLogLifecycle();
}
}
const parent = await mount(Parent, fixture);
expect(fixture.innerHTML).toBe("1");
expect([
"Parent:setup",
"Parent:willStart",
"Parent:willRender",
"Child:setup",
"Child:willStart",
"Parent:rendered",
"Child:willRender",
"Child:rendered",
"Child:mounted",
"Parent:mounted",
]).toBeLogged();
parent.state.value = 2;
// wait for child to be rendered
await nextMicroTick();
await nextMicroTick();
await nextMicroTick();
await nextMicroTick();
expect([
"Parent:willRender",
"Child:willUpdateProps",
"Parent:rendered",
"Child:willRender",
"Child:rendered",
]).toBeLogged();
expect(fixture.innerHTML).toBe("1");
// trigger a render, but keep the props for child the same
parent.render();
await nextTick();
expect(fixture.innerHTML).toBe("2");
expect([
"Parent:willRender",
"Child:willUpdateProps",
"Parent:rendered",
"Child:willRender",
"Child:rendered",
"Parent:willPatch",
"Child:willPatch",
"Child:patched",
"Parent:patched",
]).toBeLogged();
});
// test.skip("components with shouldUpdate=false", async () => { // test.skip("components with shouldUpdate=false", async () => {
// const state = { p: 1, cc: 10 }; // const state = { p: 1, cc: 10 };
-2
View File
@@ -49,7 +49,5 @@ describe("env handling", () => {
await new App(Test, { env }).mount(fixture); await new App(Test, { env }).mount(fixture);
expect(child.env).toEqual(env); 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));
}); });
}); });
+12 -101
View File
@@ -5,8 +5,6 @@ import {
onPatched, onPatched,
onWillPatch, onWillPatch,
onWillStart, onWillStart,
onWillRender,
onRendered,
onWillUnmount, onWillUnmount,
useState, useState,
xml, xml,
@@ -84,6 +82,8 @@ describe("basics", () => {
}); });
test("display a nice error if it cannot find component (in dev mode)", async () => { test("display a nice error if it cannot find component (in dev mode)", async () => {
const info = console.info;
console.info = jest.fn(() => {}); // dev mode message
class SomeComponent extends Component {} class SomeComponent extends Component {}
class Parent extends Component { class Parent extends Component {
static template = xml`<SomeMispelledComponent />`; static template = xml`<SomeMispelledComponent />`;
@@ -91,7 +91,7 @@ describe("basics", () => {
} }
let error: Error; let error: Error;
try { try {
await mount(Parent, fixture, { test: true }); await mount(Parent, fixture, { dev: true });
} catch (e) { } catch (e) {
error = e as Error; error = e as Error;
} }
@@ -100,6 +100,8 @@ describe("basics", () => {
expect(console.error).toBeCalledTimes(0); expect(console.error).toBeCalledTimes(0);
expect(mockConsoleError).toBeCalledTimes(0); expect(mockConsoleError).toBeCalledTimes(0);
expect(mockConsoleWarn).toBeCalledTimes(1); expect(mockConsoleWarn).toBeCalledTimes(1);
expect(console.info).toBeCalledTimes(1);
console.info = info;
}); });
test("simple catchError", async () => { test("simple catchError", async () => {
@@ -177,74 +179,6 @@ describe("errors and promises", () => {
expect(mockConsoleWarn).toBeCalledTimes(1); expect(mockConsoleWarn).toBeCalledTimes(1);
}); });
test("an error in onMounted callback will have the component's setup in its stack trace", async () => {
class App extends Component {
static template = xml`<div>abc</div>`;
setup() {
onMounted(() => {
throw new Error("boom");
});
}
}
let error: Error;
try {
await mount(App, fixture, { test: true });
} catch (e) {
error = e as Error;
}
expect(error!).toBeDefined();
expect(error!.stack).toContain("App.setup");
expect(error!.stack).toContain("error_handling.test.ts");
expect(fixture.innerHTML).toBe("");
expect(mockConsoleError).toBeCalledTimes(0);
expect(mockConsoleWarn).toBeCalledTimes(1);
});
test("errors in onWillRender/onRender aren't wrapped more than once", async () => {
class App extends Component {
static template = xml`<div>abc</div>`;
setup() {
onWillRender(() => {
throw new Error("boom in onWillRender");
});
onRendered(() => {
throw new Error("boom in onRendered");
});
}
}
let error: Error;
try {
await mount(App, fixture, { test: true });
} catch (e) {
error = e as Error;
}
expect(error!).toBeDefined();
expect(error!.message).toBe(
`The following error occurred in onWillRender: "boom in onWillRender"`
);
});
test("error while rendering component isn't wrapped by onWillRender/onRendered", async () => {
class App extends Component {
static template = xml`<div t-att-class="{ 'invalid: 5 }">abc</div>`;
setup() {
onWillRender(() => {});
onRendered(() => {});
}
}
let error: Error;
try {
await mount(App, fixture, { test: true });
} catch (e) {
error = e as Error;
}
expect(error!).toBeDefined();
expect(error!.message).toBe("Tokenizer error: could not tokenize `{ 'invalid: 5 }`");
});
test("an error in willPatch call will reject the render promise", async () => { test("an error in willPatch call will reject the render promise", async () => {
class Root extends Component { class Root extends Component {
static template = xml`<div><t t-esc="val"/></div>`; static template = xml`<div><t t-esc="val"/></div>`;
@@ -257,13 +191,13 @@ describe("errors and promises", () => {
} }
} }
const root = await mount(Root, fixture, { test: true }); const root = await mount(Root, fixture);
root.val = 4; root.val = 4;
let error: Error; let error: Error;
root.render(); root.render();
await nextTick(); await nextTick();
expect(error!).toBeDefined(); expect(error!).toBeDefined();
expect(error!.message).toBe(`The following error occurred in onWillPatch: "boom"`); expect(error!.message).toBe("boom");
expect(mockConsoleError).toBeCalledTimes(0); expect(mockConsoleError).toBeCalledTimes(0);
expect(mockConsoleWarn).toBeCalledTimes(0); expect(mockConsoleWarn).toBeCalledTimes(0);
}); });
@@ -280,13 +214,13 @@ describe("errors and promises", () => {
} }
} }
const root = await mount(Root, fixture, { test: true }); const root = await mount(Root, fixture);
root.val = 4; root.val = 4;
let error: Error; let error: Error;
root.render(); root.render();
await nextTick(); await nextTick();
expect(error!).toBeDefined(); expect(error!).toBeDefined();
expect(error!.message).toBe(`The following error occurred in onPatched: "boom"`); expect(error!.message).toBe("boom");
expect(mockConsoleError).toBeCalledTimes(0); expect(mockConsoleError).toBeCalledTimes(0);
expect(mockConsoleWarn).toBeCalledTimes(0); expect(mockConsoleWarn).toBeCalledTimes(0);
}); });
@@ -362,6 +296,7 @@ describe("errors and promises", () => {
}); });
test("errors in mounted and in willUnmount", async () => { test("errors in mounted and in willUnmount", async () => {
expect.assertions(4);
class Example extends Component { class Example extends Component {
static template = xml`<div/>`; static template = xml`<div/>`;
val: any; val: any;
@@ -378,11 +313,9 @@ describe("errors and promises", () => {
} }
try { try {
await mount(Example, fixture, { test: true }); await mount(Example, fixture);
} catch (e) { } catch (e) {
expect((e as Error).message).toBe( expect((e as Error).message).toBe("Error in mounted");
`The following error occurred in onMounted: "Error in mounted"`
);
} }
// 1 additional error is logged because the destruction of the app causes // 1 additional error is logged because the destruction of the app causes
// the onWillUnmount hook to be called and to fail // the onWillUnmount hook to be called and to fail
@@ -441,28 +374,6 @@ describe("can catch errors", () => {
expect(mockConsoleWarn).toBeCalledTimes(0); expect(mockConsoleWarn).toBeCalledTimes(0);
}); });
test("calling a hook outside setup should crash", async () => {
class Root extends Component {
static template = xml`<t t-esc="state.value"/>`;
state = useState({ value: 1 });
setup() {
onWillStart(() => {
this.state = useState({ value: 2 });
});
}
}
let e: Error;
try {
await mount(Root, fixture, { test: true });
} catch (error) {
e = error as Error;
}
expect(e!.message).toBe(
`The following error occurred in onWillStart: "No active component (a hook function should only be called in 'setup')"`
);
});
test("can catch an error in the initial call of a component render function (parent mounted)", async () => { test("can catch an error in the initial call of a component render function (parent mounted)", async () => {
class ErrorComponent extends Component { class ErrorComponent extends Component {
static template = xml`<div>hey<t t-esc="state.this.will.crash"/></div>`; static template = xml`<div>hey<t t-esc="state.this.will.crash"/></div>`;
+2 -20
View File
@@ -238,7 +238,7 @@ describe("hooks", () => {
expect(fixture.innerHTML).toBe("<div>maggot brain</div>"); expect(fixture.innerHTML).toBe("<div>maggot brain</div>");
someVal = "brain"; someVal = "brain";
someVal2 = "maggot"; someVal2 = "maggot";
component.render(true); component.render();
await nextTick(); await nextTick();
expect(fixture.innerHTML).toBe("<div>brain maggot</div>"); expect(fixture.innerHTML).toBe("<div>brain maggot</div>");
}); });
@@ -272,7 +272,7 @@ describe("hooks", () => {
expect(fixture.innerHTML).toBe("<div>maggot brain</div>"); expect(fixture.innerHTML).toBe("<div>maggot brain</div>");
someVal = "brain"; someVal = "brain";
someVal2 = "maggot"; someVal2 = "maggot";
component.render(true); component.render();
await nextTick(); await nextTick();
expect(fixture.innerHTML).toBe("<div>brain maggot</div>"); expect(fixture.innerHTML).toBe("<div>brain maggot</div>");
}); });
@@ -322,24 +322,6 @@ describe("hooks", () => {
expect(fixture.innerHTML).toBe("3<div>5</div>"); expect(fixture.innerHTML).toBe("3<div>5</div>");
}); });
test("parent and child env (with useChildSubEnv then useSubEnv)", async () => {
class Child extends Component {
static template = xml`<div t-if="env.hasParent"><t t-esc="env.val"/></div>`;
}
class Parent extends Component {
static template = xml`<t t-esc="env.val"/><Child/>`;
static components = { Child };
setup() {
useChildSubEnv({ hasParent: true });
useSubEnv({ val: 5 });
}
}
const env = { val: 3 };
await mount(Parent, fixture, { env });
expect(fixture.innerHTML).toBe("5<div>5</div>");
});
test("can use onWillStart, onWillUpdateProps", async () => { test("can use onWillStart, onWillUpdateProps", async () => {
const steps: string[] = []; const steps: string[] = [];
async function slow(): Promise<string> { async function slow(): Promise<string> {
+7 -3
View File
@@ -849,9 +849,8 @@ describe("lifecycle hooks", () => {
class Parent extends Component { class Parent extends Component {
static template = xml` static template = xml`
<Child someValue="state.value" />`; <Child />`;
static components = { Child }; static components = { Child };
state = useState({ value: 1 });
setup() { setup() {
useLogLifecycle(); useLogLifecycle();
} }
@@ -872,7 +871,7 @@ describe("lifecycle hooks", () => {
"Parent:mounted", "Parent:mounted",
]).toBeLogged(); ]).toBeLogged();
parent.state.value++; // to block child render parent.render(); // to block child render
await nextTick(); await nextTick();
expect(["Parent:willRender", "Child:willUpdateProps", "Parent:rendered"]).toBeLogged(); expect(["Parent:willRender", "Child:willUpdateProps", "Parent:rendered"]).toBeLogged();
@@ -1009,15 +1008,20 @@ describe("lifecycle hooks", () => {
await nextTick(); await nextTick();
expect([ expect([
"C:willRender", "C:willRender",
"D:willUpdateProps",
"F:setup", "F:setup",
"F:willStart", "F:willStart",
"C:rendered", "C:rendered",
"D:willRender",
"D:rendered",
"F:willRender", "F:willRender",
"F:rendered", "F:rendered",
"C:willPatch", "C:willPatch",
"D:willPatch",
"E:willUnmount", "E:willUnmount",
"E:willDestroy", "E:willDestroy",
"F:mounted", "F:mounted",
"D:patched",
"C:patched", "C:patched",
]).toBeLogged(); ]).toBeLogged();
}); });
+4 -28
View File
@@ -12,7 +12,7 @@ let mockConsoleWarn: any;
beforeAll(() => { beforeAll(() => {
console.info = (message: any) => { console.info = (message: any) => {
if (message === DEV_MSG()) { if (message === DEV_MSG) {
return; return;
} }
info(message); info(message);
@@ -684,7 +684,7 @@ describe("props validation", () => {
test("default values are applied before validating props at update", async () => { test("default values are applied before validating props at update", async () => {
// need to do something about errors catched in render // need to do something about errors catched in render
class SubComp extends Component { class SubComp extends Component {
static props = { p: { type: Number, optional: true } }; static props = { p: { type: Number } };
static template = xml`<div><t t-esc="props.p"/></div>`; static template = xml`<div><t t-esc="props.p"/></div>`;
static defaultProps = { p: 4 }; static defaultProps = { p: 4 };
} }
@@ -791,9 +791,9 @@ describe("default props", () => {
expect(fixture.innerHTML).toBe("<div><div>4</div></div>"); expect(fixture.innerHTML).toBe("<div><div>4</div></div>");
}); });
test("can set default boolean values", async () => { test("can set default required boolean values", async () => {
class SubComp extends Component { class SubComp extends Component {
static props = ["p?", "q?"]; static props = ["p", "q"];
static defaultProps = { p: true, q: false }; static defaultProps = { p: true, q: false };
static template = xml`<span><t t-if="props.p">hey</t><t t-if="!props.q">hey</t></span>`; static template = xml`<span><t t-if="props.p">hey</t><t t-if="!props.q">hey</t></span>`;
} }
@@ -804,28 +804,4 @@ describe("default props", () => {
await mount(Parent, fixture, { dev: true }); await mount(Parent, fixture, { dev: true });
expect(fixture.innerHTML).toBe("<div><span>heyhey</span></div>"); expect(fixture.innerHTML).toBe("<div><span>heyhey</span></div>");
}); });
test("a default prop cannot be defined on a mandatory prop", async () => {
class Child extends Component {
static props = {
mandatory: Number,
};
static defaultProps = { mandatory: 3 };
static template = xml` <div><t t-esc="props.mandatory"/></div>`;
}
class Parent extends Component {
static components = { Child };
static template = xml`<Child/>`;
}
let error: Error;
try {
await mount(Parent, fixture, { dev: true });
} catch (e) {
error = e as Error;
}
expect(error!).toBeDefined();
expect(error!.message).toBe(
"A default value cannot be defined for a mandatory prop (name: 'mandatory', component: Child)"
);
});
}); });
-12
View File
@@ -53,18 +53,6 @@ describe("reactivity in lifecycle", () => {
expect(n).toBe(2); // no new rendering occured: b was never read via state! expect(n).toBe(2); // no new rendering occured: b was never read via state!
}); });
test("can use a state hook on Map", async () => {
class Counter extends Component {
static template = xml`<div><t t-esc="counter.get('value')"/></div>`;
counter = useState(new Map([["value", 42]]));
}
const counter = await mount(Counter, fixture);
expect(fixture.innerHTML).toBe("<div>42</div>");
counter.counter.set("value", 3);
await nextTick();
expect(fixture.innerHTML).toBe("<div>3</div>");
});
test("state changes in willUnmount do not trigger rerender", async () => { test("state changes in willUnmount do not trigger rerender", async () => {
const steps: string[] = []; const steps: string[] = [];
class Child extends Component { class Child extends Component {
+2 -25
View File
@@ -1,5 +1,5 @@
import { Component, mount, onMounted, useRef, useState } from "../../src/index"; import { Component, mount, useRef, useState } from "../../src/index";
import { logStep, makeTestFixture, nextTick, snapshotEverything } from "../helpers"; import { makeTestFixture, nextTick, snapshotEverything } from "../helpers";
import { xml } from "../../src/index"; import { xml } from "../../src/index";
snapshotEverything(); snapshotEverything();
@@ -100,27 +100,4 @@ describe("refs", () => {
expect(console.warn).toBeCalledTimes(1); expect(console.warn).toBeCalledTimes(1);
console.warn = consoleWarn; console.warn = consoleWarn;
}); });
test("refs and recursive templates", async () => {
class Test extends Component {
static components = {};
static template = xml`
<p t-ref="root">
<t t-esc="props.tree.value"/>
<t t-if="props.tree.child"><Test tree="props.tree.child"/></t>
</p>`;
root = useRef("root");
setup() {
onMounted(() => logStep(this.root.el!.outerHTML));
}
}
Test.components = { Test };
const tree = { value: "a", child: { value: "b", child: null } };
await mount(Test, fixture, { props: { tree } });
expect(fixture.innerHTML).toBe("<p>a<p>b</p></p>");
expect(["<p>b</p>", "<p>a<p>b</p></p>"]).toBeLogged();
});
}); });
-442
View File
@@ -1,442 +0,0 @@
import { Component, mount, onRendered, onWillUpdateProps, useState, xml } from "../../src";
import {
makeTestFixture,
snapshotEverything,
nextTick,
useLogLifecycle,
makeDeferred,
nextMicroTick,
} from "../helpers";
let fixture: HTMLElement;
snapshotEverything();
beforeEach(() => {
fixture = makeTestFixture();
});
describe("rendering semantics", () => {
test("can render a parent without rendering child", async () => {
class Child extends Component {
static template = xml`child`;
setup() {
useLogLifecycle();
}
}
class Parent extends Component {
static template = xml`
<t t-esc="state.value"/>
<Child/>
`;
static components = { Child };
state = useState({ value: "A" });
setup() {
useLogLifecycle();
}
}
const parent = await mount(Parent, fixture);
expect(fixture.innerHTML).toBe("Achild");
expect([
"Parent:setup",
"Parent:willStart",
"Parent:willRender",
"Child:setup",
"Child:willStart",
"Parent:rendered",
"Child:willRender",
"Child:rendered",
"Child:mounted",
"Parent:mounted",
]).toBeLogged();
parent.state.value = "B";
await nextTick();
expect(fixture.innerHTML).toBe("Bchild");
expect([
"Parent:willRender",
"Parent:rendered",
"Parent:willPatch",
"Parent:patched",
]).toBeLogged();
});
test("can force a render to update sub tree", async () => {
let childN = 0;
let parentN = 0;
class Child extends Component {
static template = xml`child`;
setup() {
onRendered(() => childN++);
}
}
class Parent extends Component {
static template = xml`
<t t-esc="state.value"/>
<Child/>
`;
static components = { Child };
state = { value: "A" };
setup() {
onRendered(() => parentN++);
}
}
const parent = await mount(Parent, fixture);
expect(fixture.innerHTML).toBe("Achild");
expect(parentN).toBe(1);
expect(childN).toBe(1);
parent.state.value = "B";
parent.render(true);
await nextTick();
expect(fixture.innerHTML).toBe("Bchild");
expect(parentN).toBe(2);
expect(childN).toBe(2);
});
test("render with deep=true followed by render with deep=false work as expected", async () => {
class Child extends Component {
static template = xml`child<t t-esc="env.getValue()"/>`;
setup() {
useLogLifecycle();
}
}
class Parent extends Component {
static template = xml`parent<t t-esc="state.value"/><Child/>`;
static components = { Child };
state = useState({ value: "A" });
setup() {
useLogLifecycle();
}
}
let value = 3;
const env = {
getValue() {
return value;
},
};
const parent = await mount(Parent, fixture, { env });
expect(fixture.innerHTML).toBe("parentAchild3");
expect([
"Parent:setup",
"Parent:willStart",
"Parent:willRender",
"Child:setup",
"Child:willStart",
"Parent:rendered",
"Child:willRender",
"Child:rendered",
"Child:mounted",
"Parent:mounted",
]).toBeLogged();
value = 4;
parent.render(true);
// wait for child to be rendered, but dom not yet patched
await nextMicroTick();
await nextMicroTick();
await nextMicroTick();
expect([
"Parent:willRender",
"Child:willUpdateProps",
"Parent:rendered",
"Child:willRender",
"Child:rendered",
]).toBeLogged();
parent.state.value = "B";
await nextTick();
expect(fixture.innerHTML).toBe("parentBchild4");
expect([
"Parent:willRender",
"Child:willUpdateProps",
"Parent:rendered",
"Child:willRender",
"Child:rendered",
"Parent:willPatch",
"Child:willPatch",
"Child:patched",
"Parent:patched",
]).toBeLogged();
});
test("props are reactive", async () => {
class Child extends Component {
static template = xml`<t t-esc="props.a.b"/>`;
setup() {
useLogLifecycle();
}
}
class Parent extends Component {
static template = xml`
<Child a="state"/>
`;
static components = { Child };
state = useState({ b: 1 });
setup() {
useLogLifecycle();
}
}
const parent = await mount(Parent, fixture);
expect(fixture.innerHTML).toBe("1");
expect([
"Parent:setup",
"Parent:willStart",
"Parent:willRender",
"Child:setup",
"Child:willStart",
"Parent:rendered",
"Child:willRender",
"Child:rendered",
"Child:mounted",
"Parent:mounted",
]).toBeLogged();
parent.state.b = 3;
await nextTick();
expect(fixture.innerHTML).toBe("3");
expect(["Child:willRender", "Child:rendered", "Child:willPatch", "Child:patched"]).toBeLogged();
});
test("props are reactive (nested prop)", async () => {
class Child extends Component {
static template = xml`<t t-esc="props.a.b.c"/>`;
setup() {
useLogLifecycle();
}
}
class Parent extends Component {
static template = xml`
<Child a="state"/>
`;
static components = { Child };
state = useState({ b: { c: 1 } });
setup() {
useLogLifecycle();
}
}
const parent = await mount(Parent, fixture);
expect(fixture.innerHTML).toBe("1");
expect([
"Parent:setup",
"Parent:willStart",
"Parent:willRender",
"Child:setup",
"Child:willStart",
"Parent:rendered",
"Child:willRender",
"Child:rendered",
"Child:mounted",
"Parent:mounted",
]).toBeLogged();
parent.state.b.c = 3; // parent is now subscribed to 'b' key
await nextTick();
expect(fixture.innerHTML).toBe("3");
expect(["Child:willRender", "Child:rendered", "Child:willPatch", "Child:patched"]).toBeLogged();
parent.state.b = { c: 444 }; // triggers a parent and a child render
await nextTick();
expect(fixture.innerHTML).toBe("444");
expect([
"Parent:willRender",
"Parent:rendered",
"Child:willRender",
"Child:rendered",
"Parent:willPatch",
"Parent:patched",
"Child:willPatch",
"Child:patched",
]).toBeLogged();
});
test("works as expected for dynamic number of props", async () => {
class Child extends Component {
static template = xml`<t t-esc="Object.keys(props).length"/>`;
}
class Parent extends Component {
static template = xml`
<Child t-props="state"/>
`;
static components = { Child };
state: any = useState({ b: 1 });
}
const parent = await mount(Parent, fixture);
expect(fixture.innerHTML).toBe("1");
parent.state.newkey = 3;
await nextTick();
expect(fixture.innerHTML).toBe("2");
});
test("rendering is atomic (for one subtree)", async () => {
const def = makeDeferred();
class C extends Component {
static template = xml`<t t-esc="props.obj.val"/>`;
setup() {
useLogLifecycle();
}
}
class B extends Component {
static template = xml`<C obj="props.obj"/>`;
static components = { C };
setup() {
useLogLifecycle();
onWillUpdateProps(() => def);
}
}
class A extends Component {
static template = xml`<t t-esc="state.obj.val"/><B obj="state.obj"/>`;
static components = { B };
state = useState({ obj: { val: 1 } });
setup() {
useLogLifecycle();
}
}
const parent = await mount(A, fixture);
expect(fixture.innerHTML).toBe("11");
expect([
"A:setup",
"A:willStart",
"A:willRender",
"B:setup",
"B:willStart",
"A:rendered",
"B:willRender",
"C:setup",
"C:willStart",
"B:rendered",
"C:willRender",
"C:rendered",
"C:mounted",
"B:mounted",
"A:mounted",
]).toBeLogged();
parent.state.obj.val = 3;
await nextTick();
expect(fixture.innerHTML).toBe("33");
expect([
"A:willRender",
"A:rendered",
"C:willRender",
"C:rendered",
"A:willPatch",
"A:patched",
"C:willPatch",
"C:patched",
]).toBeLogged();
def.resolve();
await nextTick();
expect([]).toBeLogged();
});
});
test("force render in case of existing render", async () => {
const def = makeDeferred();
class C extends Component {
static template = xml`C`;
setup() {
useLogLifecycle();
}
}
class B extends Component {
static template = xml`<C/><t t-esc="props.val"/>`;
static components = { C };
setup() {
useLogLifecycle();
onWillUpdateProps(() => def);
}
}
class A extends Component {
static template = xml`<B val="state.val"/>`;
static components = { B };
state = useState({ val: 1 });
setup() {
useLogLifecycle();
}
}
const parent = await mount(A, fixture);
expect(fixture.innerHTML).toBe("C1");
expect([
"A:setup",
"A:willStart",
"A:willRender",
"B:setup",
"B:willStart",
"A:rendered",
"B:willRender",
"C:setup",
"C:willStart",
"B:rendered",
"C:willRender",
"C:rendered",
"C:mounted",
"B:mounted",
"A:mounted",
]).toBeLogged();
// trigger a new rendering, blocked in B
parent.state.val = 2;
await nextTick();
expect(["A:willRender", "B:willUpdateProps", "A:rendered"]).toBeLogged();
// initiate a new render with deep=true. it should cancel the current render
// and also be blocked in B
parent.render(true);
await nextTick();
expect(["A:willRender", "B:willUpdateProps", "A:rendered"]).toBeLogged();
def.resolve();
await nextTick();
// we check here that the render reaches C (so, that it was properly forced)
expect([
"B:willRender",
"C:willUpdateProps",
"B:rendered",
"C:willRender",
"C:rendered",
"A:willPatch",
"B:willPatch",
"C:willPatch",
"C:patched",
"B:patched",
"A:patched",
]).toBeLogged();
});
+4 -146
View File
@@ -45,36 +45,7 @@ describe("slots", () => {
expect(fixture.innerHTML).toBe("some text"); expect(fixture.innerHTML).toBe("some text");
}); });
test("simple slot with slot scope", async () => { test("simple default slot with params", async () => {
let child: any;
class Child extends Component {
static template = xml`<span><t t-slot="slotName" bool="state.bool"/></span>`;
state = useState({ bool: true });
setup() {
child = this;
}
}
class Parent extends Component {
static template = xml`
<Child>
<t t-set-slot="slotName" t-slot-scope="slotScope">
<t t-if="slotScope.bool">some text</t>
<t t-else="slotScope.bool">other text</t>
</t>
</Child>`;
static components = { Child };
}
await mount(Parent, fixture);
expect(fixture.innerHTML).toBe("<span>some text</span>");
child.state.bool = false;
await nextTick();
expect(fixture.innerHTML).toBe("<span>other text</span>");
});
test("default slot with slot scope: shorthand syntax", async () => {
let child: any; let child: any;
class Child extends Component { class Child extends Component {
static template = xml`<span><t t-slot="default" bool="state.bool"/></span>`; static template = xml`<span><t t-slot="default" bool="state.bool"/></span>`;
@@ -86,9 +57,11 @@ describe("slots", () => {
class Parent extends Component { class Parent extends Component {
static template = xml` static template = xml`
<Child t-slot-scope="slotScope"> <Child>
<t t-set-slot="default" t-slot-scope="slotScope">
<t t-if="slotScope.bool">some text</t> <t t-if="slotScope.bool">some text</t>
<t t-else="slotScope.bool">other text</t> <t t-else="slotScope.bool">other text</t>
</t>
</Child>`; </Child>`;
static components = { Child }; static components = { Child };
} }
@@ -126,41 +99,6 @@ describe("slots", () => {
expect(mockConsoleWarn).toBeCalledTimes(1); expect(mockConsoleWarn).toBeCalledTimes(1);
}); });
test("simple default slot with params and bound function", async () => {
class Child extends Component {
static template = xml`<t t-slot="default" fn.bind="getValue"/>`;
state = useState({ value: 123 });
getValue() {
return this.state.value;
}
}
class Parent extends Component {
static template = xml`
<Child t-slot-scope="slotScope"><t t-esc="slotScope.fn()"/></Child>`;
static components = { Child };
}
await mount(Parent, fixture);
expect(fixture.innerHTML).toBe("123");
});
test("default slot with params with - in it", async () => {
class Child extends Component {
static template = xml`<t t-slot="default" some-value="state.value"/>`;
state = useState({ value: 123 });
}
class Parent extends Component {
static template = xml`
<Child t-slot-scope="slotScope"><t t-esc="slotScope['some-value']"/></Child>`;
static components = { Child };
}
await mount(Parent, fixture);
expect(fixture.innerHTML).toBe("123");
});
test("fun: two calls to the same slot", async () => { test("fun: two calls to the same slot", async () => {
class Child extends Component { class Child extends Component {
static template = xml`<t t-slot="default"/><t t-slot="default"/>`; static template = xml`<t t-slot="default"/><t t-slot="default"/>`;
@@ -277,30 +215,6 @@ describe("slots", () => {
); );
}); });
test("can define and call slots with bound params", async () => {
class Child extends Component {
static template = xml`
<t t-slot="abc"/>
<t t-esc="props.slots['abc'].getValue()"/>`;
}
class Parent extends Component {
static components = { Child };
static template = xml`
<Child>
<t t-set-slot="abc" getValue.bind="getValue">abc</t>
</Child>`;
state = useState({ value: 444 });
getValue() {
return this.state.value;
}
}
await mount(Parent, fixture);
expect(fixture.innerHTML).toBe("abc444");
});
test("no named slot content => just no children", async () => { test("no named slot content => just no children", async () => {
class Dialog extends Component { class Dialog extends Component {
static template = xml`<span><t t-slot="header"/></span>`; static template = xml`<span><t t-slot="header"/></span>`;
@@ -1675,60 +1589,4 @@ describe("slots", () => {
await mount(Parent, fixture); await mount(Parent, fixture);
expect(fixture.innerHTML).toBe("<div>SlotDisplay</div><div>Parent</div>"); expect(fixture.innerHTML).toBe("<div>SlotDisplay</div><div>Parent</div>");
}); });
test("mix of slots, t-call, t-call with body, and giving own props child", async () => {
expect.assertions(11);
class C extends Component {
static template = xml`[C]<t t-slot="default" />`;
}
class B extends Component {
static template = xml`[B]<C slots="props.slots" />`;
static components = { C };
}
const subTemplate2 = xml`[sub2<t t-esc="v"/>]`;
const subTemplate1 = xml`[sub1]
<t t-set="dummy" t-value="validate"/>
<t t-call="${subTemplate2}">
<t t-set="v" t-value="props.number"/>
</t>`;
let a: any;
class A extends Component {
static components = { B };
static template = xml`<B>[A]<t t-call="${subTemplate1}"/></B>`;
setup() {
a = this;
}
get validate() {
// we check here that the actual component was not lost somehow
expect(this.__owl__.component === a).toBe(true);
return 1;
}
}
class P extends Component {
static components = { A };
static template = xml`<button t-on-click="inc">inc</button><A number="state.number"/>`;
state = useState({ number: 333 });
inc() {
this.state.number++;
}
}
class Parent extends Component {
static template = xml`<P/>`;
static components = { P };
}
await mount(Parent, fixture);
expect(fixture.innerHTML).toBe("<button>inc</button>[B][C][A][sub1] [sub2333]");
fixture.querySelector("button")!.click();
await nextTick();
expect(fixture.innerHTML).toBe("<button>inc</button>[B][C][A][sub1] [sub2334]");
});
}); });
-13
View File
@@ -30,19 +30,6 @@ describe("t-model directive", () => {
expect(fixture.innerHTML).toBe("<div><input><span>test</span></div>"); expect(fixture.innerHTML).toBe("<div><input><span>test</span></div>");
}); });
test("t-model on an input with an undefined value", async () => {
class SomeComponent extends Component {
static template = xml`<input t-model="state.text"/>`;
state = useState({ text: undefined });
}
await mount(SomeComponent, fixture);
expect(fixture.innerHTML).toBe("<input>");
const input = fixture.querySelector("input")!;
expect(input.value).toBe("");
});
test("basic use, on an input with bracket expression", async () => { test("basic use, on an input with bracket expression", async () => {
class SomeComponent extends Component { class SomeComponent extends Component {
static template = xml` static template = xml`
-103
View File
@@ -142,107 +142,4 @@ describe("t-on", () => {
buttons[1].click(); buttons[1].click();
expect(comp.otherState.vals).toStrictEqual(["0_0", "1_1"]); expect(comp.otherState.vals).toStrictEqual(["0_0", "1_1"]);
}); });
test("t-on on components", async () => {
class Child extends Component {
static template = xml`<button t-esc="props.value"/>`;
}
class Parent extends Component {
static template = xml`<Child t-on-click="increment" value="state.value"/>`;
static components = { Child };
state = useState({ value: 1 });
increment() {
this.state.value++;
}
}
await mount(Parent, fixture);
expect(fixture.innerHTML).toBe("<button>1</button>");
fixture.querySelector("button")!.click();
await nextTick();
expect(fixture.innerHTML).toBe("<button>2</button>");
});
test("t-on on components, variation", async () => {
class Child extends Component {
static template = xml`<button t-esc="props.value"/>`;
}
class Parent extends Component {
static template = xml`
<div>
<span/>
<Child t-on-click="increment" value="state.value"/>
<p/>
</div>`;
static components = { Child };
state = useState({ value: 1 });
increment() {
this.state.value++;
}
}
await mount(Parent, fixture);
expect(fixture.innerHTML).toBe("<div><span></span><button>1</button><p></p></div>");
fixture.querySelector("span")!.click();
await nextTick();
expect(fixture.innerHTML).toBe("<div><span></span><button>1</button><p></p></div>");
fixture.querySelector("button")!.click();
await nextTick();
expect(fixture.innerHTML).toBe("<div><span></span><button>2</button><p></p></div>");
fixture.querySelector("p")!.click();
await nextTick();
expect(fixture.innerHTML).toBe("<div><span></span><button>2</button><p></p></div>");
});
test("t-on on t-slots", async () => {
class Child extends Component {
static template = xml`
[<t t-esc="state.count"/>]
<t t-slot="default" t-on-click="() => this.state.count++"/>`;
state = useState({ count: 0 });
}
class Parent extends Component {
static template = xml`
<Child>
<p>something</p>
</Child>`;
static components = { Child };
}
await mount(Parent, fixture);
expect(fixture.innerHTML).toBe(" [0] <p>something</p>");
fixture.querySelector("p")!.click();
await nextTick();
expect(fixture.innerHTML).toBe(" [1] <p>something</p>");
});
test("t-on on t-set-slots", async () => {
class Child extends Component {
static template = xml`<t t-slot="myslot"/>`;
}
class Parent extends Component {
static template = xml`
[<t t-esc="state.count"/>]
<Child>
<t t-set-slot="myslot" t-on-click="() => this.state.count++">
<p>something</p>
<p>paragraph</p>
</t>
</Child>`;
static components = { Child };
state = useState({ count: 0 });
}
await mount(Parent, fixture);
expect(fixture.innerHTML).toBe(" [0] <p>something</p><p>paragraph</p>");
fixture.querySelector("p")!.click();
await nextTick();
expect(fixture.innerHTML).toBe(" [1] <p>something</p><p>paragraph</p>");
});
}); });

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