Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 94e978815f | |||
| 9c40ee67e1 |
@@ -15,7 +15,7 @@ yarn-debug.log*
|
|||||||
yarn-error.log*
|
yarn-error.log*
|
||||||
|
|
||||||
#ide's
|
#ide's
|
||||||
**/.vscode/*
|
.vscode
|
||||||
.idea
|
.idea
|
||||||
|
|
||||||
node_modules
|
node_modules
|
||||||
@@ -26,10 +26,3 @@ release-notes.md
|
|||||||
|
|
||||||
# useful in some cases
|
# useful in some cases
|
||||||
/temp
|
/temp
|
||||||
|
|
||||||
# owl-vision
|
|
||||||
*/owl-vision/out/
|
|
||||||
*/owl-vision/.vs/
|
|
||||||
**/*.vsix
|
|
||||||
!*/owl-vision/.vscode/launch.json
|
|
||||||
!*/owl-vision/.vscode/tasks.json
|
|
||||||
|
|||||||
@@ -357,7 +357,7 @@ cleaning operation, since the component may be destroyed before it has even been
|
|||||||
mounted. The `willDestroy` hook is useful in that situation, since it is always
|
mounted. The `willDestroy` hook is useful in that situation, since it is always
|
||||||
called.
|
called.
|
||||||
|
|
||||||
The `onWillDestroy` hook is used to register a function that will be executed at
|
The `onWillUnmount` hook is used to register a function that will be executed at
|
||||||
this moment:
|
this moment:
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
|
|||||||
@@ -51,8 +51,8 @@ that render its content, and a fallback if an error happened.
|
|||||||
```js
|
```js
|
||||||
class ErrorBoundary extends Component {
|
class ErrorBoundary extends Component {
|
||||||
static template = xml`
|
static template = xml`
|
||||||
<t t-if="state.error" t-slot="fallback">An error occurred</t>
|
<t t-if="error" t-slot="fallback">An error occurred</t>
|
||||||
<t t-else="" t-slot="default"/>`;
|
<t t-else="" t-slot="content"`;
|
||||||
|
|
||||||
setup() {
|
setup() {
|
||||||
this.state = useState({ error: false });
|
this.state = useState({ error: false });
|
||||||
|
|||||||
@@ -190,13 +190,12 @@ will then be updated accordingly.
|
|||||||
### `useExternalListener`
|
### `useExternalListener`
|
||||||
|
|
||||||
The `useExternalListener` hook helps solve a very common problem: adding and removing
|
The `useExternalListener` hook helps solve a very common problem: adding and removing
|
||||||
a listener on some target whenever a component is mounted/unmounted. It takes a target
|
a listener on some target whenever a component is mounted/unmounted. For example,
|
||||||
as its first argument, forwards the other arguments to `addEventListener`. For example,
|
|
||||||
a dropdown menu (or its parent) may need to listen to a `click` event on `window`
|
a dropdown menu (or its parent) may need to listen to a `click` event on `window`
|
||||||
to be closed:
|
to be closed:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
useExternalListener(window, "click", this.closeMenu, { capture: true });
|
useExternalListener(window, "click", this.closeMenu);
|
||||||
```
|
```
|
||||||
|
|
||||||
### `useComponent`
|
### `useComponent`
|
||||||
|
|||||||
@@ -35,13 +35,13 @@ The components tab is separated into two sub windows: the components tree in the
|
|||||||
the component details in the right. The components tree will display all the different
|
the component details in the right. The components tree will display all the different
|
||||||
components that are present in the tab in the form of a tree. The root of this tree is
|
components that are present in the tab in the form of a tree. The root of this tree is
|
||||||
actually the app which is not a component but can still be inspected by the devtools like
|
actually the app which is not a component but can still be inspected by the devtools like
|
||||||
one. There can also be multiple apps loaded in the page like in website:
|
one. There can also be multiple apps loaded in the page like in the following:
|
||||||
|
|
||||||
<img src="screenshots/multi_apps.png"/>
|
<img src="screenshots/multi_apps.png"/>
|
||||||
|
|
||||||
There is a convenient search bar at the top of the components tree which will help finding
|
There is a convenient search bar at the top of the components tree which will help finding
|
||||||
the components tou want in the tree and also, an element picker can be used to directly select
|
the components tou want in the tree and also, an element picker can be used to directly select
|
||||||
the component you want to focus on in the page which is especially useful when 1trying to find
|
the component you want to focus on in the page which is especially useful when trying to find
|
||||||
what you want. Just click on the elements picker icon and click on the element you want to focus
|
what you want. Just click on the elements picker icon and click on the element you want to focus
|
||||||
on in the page and it will be selected in the devtools accordingly. Hovering any element in the
|
on in the page and it will be selected in the devtools accordingly. Hovering any element in the
|
||||||
page in this mode will highlight it and the same happens anytime in the components tree.
|
page in this mode will highlight it and the same happens anytime in the components tree.
|
||||||
@@ -64,18 +64,25 @@ as its env, props, observed states and all the other variables that are present
|
|||||||
While the props and the env are already present on the actual instance of the component and are
|
While the props and the env are already present on the actual instance of the component and are
|
||||||
pretty explicit by themselves, the observed state value is a bit more complicated to grasp.
|
pretty explicit by themselves, the observed state value is a bit more complicated to grasp.
|
||||||
|
|
||||||
The observed state is actually information about which variables are being observed by the component:
|
The observed state is actually information about which variables are observed by the component
|
||||||
when any property of a reactive object is being read by the component, the component will subscribe
|
which will trigger a rerender of the component when it is modified. The keys represent which part of the
|
||||||
to this property which means it will listen to any change that can occur on the property and render
|
variable is actually observed and the target is the actual variable. For simplicity, the properties
|
||||||
when such a change occurs. This can be visualized easily within the devtools inside of the observed
|
that are not observed by the component are greyed out while the others are in bold. This means that
|
||||||
state section: observed properties of the reactive object(s) are displayed in bold while the others
|
editing bold ones will trigger a rerender while the greyed out ones will not.
|
||||||
are greyed out. Do keep in mind that a greyed out property in the observed state of one component
|
|
||||||
may be observed by another and the other way around is also possible. Here is an example for some
|
|
||||||
user Field component:
|
|
||||||
|
|
||||||
<img src="screenshots/states.png"/>
|
<img src="screenshots/states.png"/>
|
||||||
|
|
||||||
Navigation inside the properties is also similar to the one in console variables: properties have
|
In the given example, we have two keys/target pairs for two different variables. The first one indicates
|
||||||
|
that adding or removing an element to the array will trigger a rerender since the length will have changed.
|
||||||
|
Replacing the element at index 0, 1 or 2 will also have the same effect as implied by the keys. It doesn't
|
||||||
|
mean that editing the properties of element at index 0, 1 or 2 will rerender the component though. It may
|
||||||
|
be the case for some but this will be described in another keys/target pair. The second keys/target pair
|
||||||
|
is actually the element at index 0 of the first pair. It only has id in the keys meaning that only the
|
||||||
|
id property will actually trigger a rerender the component when modified. Be aware however that the other
|
||||||
|
properties may be in the observed state of another component like a child one in this case. A greyed out
|
||||||
|
property only implies it is not reactive for the selected component and not for the others.
|
||||||
|
|
||||||
|
The navigation inside the properties is also similar to the one in console variables: properties have
|
||||||
their prototype displayed and getters will get their value when clicked on (...). It is also possible to
|
their prototype displayed and getters will get their value when clicked on (...). It is also possible to
|
||||||
send any property to the console using the right-click context menu on it and functions can be inspected
|
send any property to the console using the right-click context menu on it and functions can be inspected
|
||||||
in the sources tab as well.
|
in the sources tab as well.
|
||||||
@@ -89,10 +96,8 @@ component's name. Using the left click on the component's name will focus it in
|
|||||||
It is also possible to edit any of the leaf node properties. To do so, you must double click on the
|
It is also possible to edit any of the leaf node properties. To do so, you must double click on the
|
||||||
property's value and modify it using the freshly created input then press enter to apply the changes.
|
property's value and modify it using the freshly created input then press enter to apply the changes.
|
||||||
Do note that the modified values should be written in JSON format in order to be valid (examples:
|
Do note that the modified values should be written in JSON format in order to be valid (examples:
|
||||||
89, "yes", undefined, null, \["hello", 15\], {"a": 1}, true, ...). Editing any value will produce a
|
89, "yes", undefined, null, \["hello", 15\], {"a": 1}, true, ...). Whether it has an impact on the
|
||||||
manual render of the component (or the root component of the application in the case of env values).
|
component or not and whether it produces an error is the responsability of the user.
|
||||||
Whether the edition has an impact on the component or not and whether it produces an error is the
|
|
||||||
responsability of the user.
|
|
||||||
|
|
||||||
<img src="screenshots/edit.png"/>
|
<img src="screenshots/edit.png"/>
|
||||||
|
|
||||||
@@ -112,8 +117,7 @@ are intercepted by the devtools using the record button.
|
|||||||
The second button is used to clear all the events that have been recorded. The select can be used to
|
The second button is used to clear all the events that have been recorded. The select can be used to
|
||||||
switch between the tree view (which shows the causality between renders) and the events log view which
|
switch between the tree view (which shows the causality between renders) and the events log view which
|
||||||
simply displays the events in the exact order they were triggered. In this view, you can expand the create,
|
simply displays the events in the exact order they were triggered. In this view, you can expand the create,
|
||||||
update and destroy events which reveals the component that initiated the event. Also, a transition line will
|
update and destroy events which reveals the component that initiated the event.
|
||||||
appear each time a new animation frame has been loaded between events.
|
|
||||||
|
|
||||||
<img src="screenshots/events_log.png"/>
|
<img src="screenshots/events_log.png"/>
|
||||||
|
|
||||||
@@ -127,29 +131,20 @@ There is also the Trace Renderings and Trace Subscriptions features. These featu
|
|||||||
recording of events and have no effect on the profiler tab. The Trace Renderings option is used to log in
|
recording of events and have no effect on the profiler tab. The Trace Renderings option is used to log in
|
||||||
the console all the render events and allows to show their traceback information. Similarly, the Trace
|
the console all the render events and allows to show their traceback information. Similarly, the Trace
|
||||||
Subscriptions option logs all the properties that caused a render event and also allows to see the traceback
|
Subscriptions option logs all the properties that caused a render event and also allows to see the traceback
|
||||||
of the modification.
|
of the modification
|
||||||
|
|
||||||
<img src="screenshots/trace_rendering.png"/>
|
<img src="screenshots/trace_rendering.png"/>
|
||||||
<img src="screenshots/trace_subscriptions.png"/>
|
<img src="screenshots/trace_subscriptions.png"/>
|
||||||
|
|
||||||
The Owl Devtools also allow to inspect iframes coded in Owl: when an Owl iframe is detected in the page,
|
|
||||||
the iframe selector will appear next to the tabs. This allows to switch from an iframe to another easily.
|
|
||||||
Be aware that switching iframes will clear all record events from the profiler tab. Iframes detection is
|
|
||||||
currently not working in the firefox version, we are aware of this issue and will try to address it in the
|
|
||||||
future.
|
|
||||||
|
|
||||||
<img src="screenshots/iframes.png"/>
|
|
||||||
|
|
||||||
## Options
|
## Options
|
||||||
|
|
||||||
The owl devtools extension has a dark mode feature which defaults to your general devtools settings and can
|
The owl devtools extension has a dark mode feature which defaults to your general devtools settings and can
|
||||||
be toggled using the sun/moon icon at the top-right corner of the tab. There is also a refresh button to
|
be toggled using the sun/moon icon at the top-right corner of the tab. All the examples above were created
|
||||||
completely reset the owl devtools.
|
with the dark mode enabled. There is also a refresh button to completely reset the owl devtools.
|
||||||
|
|
||||||
<img src="screenshots/darkmode.png"/>
|
<img src="screenshots/darkmode.png"/>
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
If the feedback from the page to the devtools seems to be cut, you can first try to use the refresh
|
If the feedback from the page to the devtools seems to be cut, just close the devtools and refresh the page.
|
||||||
button mentioned above but if it still doesn't seem to work, just close the devtools and refresh the page.
|
|
||||||
This will eventually happen any time a tab stays opened for too long without being refreshed.
|
This will eventually happen any time a tab stays opened for too long without being refreshed.
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 545 KiB After Width: | Height: | Size: 333 KiB |
|
Before Width: | Height: | Size: 387 KiB After Width: | Height: | Size: 210 KiB |
|
Before Width: | Height: | Size: 72 KiB After Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 266 KiB After Width: | Height: | Size: 197 KiB |
|
Before Width: | Height: | Size: 320 KiB After Width: | Height: | Size: 185 KiB |
|
Before Width: | Height: | Size: 206 KiB |
|
Before Width: | Height: | Size: 329 KiB After Width: | Height: | Size: 166 KiB |
|
Before Width: | Height: | Size: 166 KiB After Width: | Height: | Size: 86 KiB |
|
Before Width: | Height: | Size: 536 KiB After Width: | Height: | Size: 311 KiB |
|
Before Width: | Height: | Size: 488 KiB After Width: | Height: | Size: 336 KiB |
|
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 177 KiB After Width: | Height: | Size: 44 KiB |
|
Before Width: | Height: | Size: 182 KiB After Width: | Height: | Size: 146 KiB |
@@ -2073,7 +2073,7 @@ function basicProxyHandler(callback) {
|
|||||||
set(target, key, value, receiver) {
|
set(target, key, value, receiver) {
|
||||||
const hadKey = objectHasOwnProperty.call(target, key);
|
const hadKey = objectHasOwnProperty.call(target, key);
|
||||||
const originalValue = Reflect.get(target, key, receiver);
|
const originalValue = Reflect.get(target, key, receiver);
|
||||||
const ret = Reflect.set(target, key, toRaw(value), receiver);
|
const ret = Reflect.set(target, key, value, receiver);
|
||||||
if (!hadKey && objectHasOwnProperty.call(target, key)) {
|
if (!hadKey && objectHasOwnProperty.call(target, key)) {
|
||||||
notifyReactives(target, KEYCHANGES);
|
notifyReactives(target, KEYCHANGES);
|
||||||
}
|
}
|
||||||
@@ -3197,14 +3197,7 @@ class TemplateSet {
|
|||||||
this.translateFn = config.translateFn;
|
this.translateFn = config.translateFn;
|
||||||
this.translatableAttributes = config.translatableAttributes;
|
this.translatableAttributes = config.translatableAttributes;
|
||||||
if (config.templates) {
|
if (config.templates) {
|
||||||
if (config.templates instanceof Document || typeof config.templates === "string") {
|
this.addTemplates(config.templates);
|
||||||
this.addTemplates(config.templates);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
for (const name in config.templates) {
|
|
||||||
this.addTemplate(name, config.templates[name]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
static registerTemplate(name, fn) {
|
static registerTemplate(name, fn) {
|
||||||
@@ -5286,14 +5279,14 @@ function parseComponent(node, ctx) {
|
|||||||
// be ignored)
|
// be ignored)
|
||||||
let el = slotNode.parentElement;
|
let el = slotNode.parentElement;
|
||||||
let isInSubComponent = false;
|
let isInSubComponent = false;
|
||||||
while (el && el !== clone) {
|
while (el !== clone) {
|
||||||
if (el.hasAttribute("t-component") || el.tagName[0] === el.tagName[0].toUpperCase()) {
|
if (el.hasAttribute("t-component") || el.tagName[0] === el.tagName[0].toUpperCase()) {
|
||||||
isInSubComponent = true;
|
isInSubComponent = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
el = el.parentElement;
|
el = el.parentElement;
|
||||||
}
|
}
|
||||||
if (isInSubComponent || !el) {
|
if (isInSubComponent) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
slotNode.removeAttribute("t-set-slot");
|
slotNode.removeAttribute("t-set-slot");
|
||||||
@@ -5562,7 +5555,7 @@ function compile(template, options = {}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// do not modify manually. This file is generated by the release script.
|
// do not modify manually. This file is generated by the release script.
|
||||||
const version = "2.2.7";
|
const version = "2.2.6";
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// Scheduler
|
// Scheduler
|
||||||
@@ -5909,7 +5902,7 @@ function useChildSubEnv(envExtension) {
|
|||||||
*
|
*
|
||||||
* @template T
|
* @template T
|
||||||
* @param {Effect<T>} effect the effect to run on component mount and/or patch
|
* @param {Effect<T>} effect the effect to run on component mount and/or patch
|
||||||
* @param {()=>[...T]} [computeDependencies=()=>[NaN]] a callback to compute
|
* @param {()=>T} [computeDependencies=()=>[NaN]] a callback to compute
|
||||||
* dependencies that will decide if the effect needs to be cleaned up and
|
* dependencies that will decide if the effect needs to be cleaned up and
|
||||||
* run again. If the dependencies did not change, the effect will not run
|
* run again. If the dependencies did not change, the effect will not run
|
||||||
* again. The default value returns an array containing only NaN because
|
* again. The default value returns an array containing only NaN because
|
||||||
@@ -5991,6 +5984,6 @@ TemplateSet.prototype._compileTemplate = function _compileTemplate(name, templat
|
|||||||
export { App, Component, EventBus, OwlError, __info__, blockDom, loadFile, markRaw, markup, mount, onError, onMounted, onPatched, onRendered, onWillDestroy, onWillPatch, onWillRender, onWillStart, onWillUnmount, onWillUpdateProps, reactive, status, toRaw, useChildSubEnv, useComponent, useEffect, useEnv, useExternalListener, useRef, useState, useSubEnv, validate, validateType, whenReady, xml };
|
export { App, Component, EventBus, OwlError, __info__, blockDom, loadFile, markRaw, markup, mount, onError, onMounted, onPatched, onRendered, onWillDestroy, onWillPatch, onWillRender, onWillStart, onWillUnmount, onWillUpdateProps, reactive, status, toRaw, useChildSubEnv, useComponent, useEffect, useEnv, useExternalListener, useRef, useState, useSubEnv, validate, validateType, whenReady, xml };
|
||||||
|
|
||||||
|
|
||||||
__info__.date = '2023-12-06T13:56:01.636Z';
|
__info__.date = '2023-09-25T11:48:01.531Z';
|
||||||
__info__.hash = 'e94428a';
|
__info__.hash = '752160f';
|
||||||
__info__.url = 'https://github.com/odoo/owl';
|
__info__.url = 'https://github.com/odoo/owl';
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@odoo/owl",
|
"name": "@odoo/owl",
|
||||||
"version": "2.2.7",
|
"version": "2.2.6",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@odoo/owl",
|
"name": "@odoo/owl",
|
||||||
"version": "2.2.7",
|
"version": "2.2.6",
|
||||||
"description": "Odoo Web Library (OWL)",
|
"description": "Odoo Web Library (OWL)",
|
||||||
"main": "dist/owl.cjs.js",
|
"main": "dist/owl.cjs.js",
|
||||||
"module": "dist/owl.es.js",
|
"module": "dist/owl.es.js",
|
||||||
|
|||||||
@@ -1,38 +0,0 @@
|
|||||||
import { OwlError } from "./owl_error";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parses an XML string into an XML document, throwing errors on parser errors
|
|
||||||
* instead of returning an XML document containing the parseerror.
|
|
||||||
*
|
|
||||||
* @param xml the string to parse
|
|
||||||
* @returns an XML document corresponding to the content of the string
|
|
||||||
*/
|
|
||||||
export function parseXML(xml: string): XMLDocument {
|
|
||||||
const parser = new DOMParser();
|
|
||||||
const doc = parser.parseFromString(xml, "text/xml");
|
|
||||||
if (doc.getElementsByTagName("parsererror").length) {
|
|
||||||
let msg = "Invalid XML in template.";
|
|
||||||
const parsererrorText = doc.getElementsByTagName("parsererror")[0].textContent;
|
|
||||||
if (parsererrorText) {
|
|
||||||
msg += "\nThe parser has produced the following error message:\n" + parsererrorText;
|
|
||||||
const re = /\d+/g;
|
|
||||||
const firstMatch = re.exec(parsererrorText);
|
|
||||||
if (firstMatch) {
|
|
||||||
const lineNumber = Number(firstMatch[0]);
|
|
||||||
const line = xml.split("\n")[lineNumber - 1];
|
|
||||||
const secondMatch = re.exec(parsererrorText);
|
|
||||||
if (line && secondMatch) {
|
|
||||||
const columnIndex = Number(secondMatch[0]) - 1;
|
|
||||||
if (line[columnIndex]) {
|
|
||||||
msg +=
|
|
||||||
`\nThe error might be located at xml line ${lineNumber} column ${columnIndex}\n` +
|
|
||||||
`${line}\n${"-".repeat(columnIndex - 1)}^`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw new OwlError(msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
return doc;
|
|
||||||
}
|
|
||||||
@@ -3,7 +3,6 @@ import type { BDom } from "../runtime/blockdom";
|
|||||||
import { CodeGenerator, Config } from "./code_generator";
|
import { CodeGenerator, Config } from "./code_generator";
|
||||||
import { parse } from "./parser";
|
import { parse } from "./parser";
|
||||||
import { OwlError } from "../common/owl_error";
|
import { OwlError } from "../common/owl_error";
|
||||||
import { parseXML } from "../common/utils";
|
|
||||||
|
|
||||||
export type Template = (context: any, vnode: any, key?: string) => BDom;
|
export type Template = (context: any, vnode: any, key?: string) => BDom;
|
||||||
|
|
||||||
@@ -17,13 +16,13 @@ export function compile(
|
|||||||
options: CompileOptions = {}
|
options: CompileOptions = {}
|
||||||
): TemplateFunction {
|
): TemplateFunction {
|
||||||
// parsing
|
// parsing
|
||||||
if (typeof template === "string") {
|
|
||||||
template = parseXML(`<t>${template}</t>`).firstChild as Element;
|
|
||||||
}
|
|
||||||
const ast = parse(template);
|
const ast = parse(template);
|
||||||
|
|
||||||
// some work
|
// some work
|
||||||
const hasSafeContext = template.querySelector("[t-set], [t-call]") === null;
|
const hasSafeContext =
|
||||||
|
template instanceof Node
|
||||||
|
? !(template instanceof Element) || template.querySelector("[t-set], [t-call]") === null
|
||||||
|
: !template.includes("t-set") && !template.includes("t-call");
|
||||||
|
|
||||||
// code generation
|
// code generation
|
||||||
const codeGenerator = new CodeGenerator(ast, { ...options, hasSafeContext });
|
const codeGenerator = new CodeGenerator(ast, { ...options, hasSafeContext });
|
||||||
|
|||||||
@@ -197,7 +197,11 @@ export type AST =
|
|||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
const cache: WeakMap<Element, AST> = new WeakMap();
|
const cache: WeakMap<Element, AST> = new WeakMap();
|
||||||
|
|
||||||
export function parse(xml: Element): AST {
|
export function parse(xml: string | Element): AST {
|
||||||
|
if (typeof xml === "string") {
|
||||||
|
const elem = parseXML(`<t>${xml}</t>`).firstChild as Element;
|
||||||
|
return _parse(elem);
|
||||||
|
}
|
||||||
let ast = cache.get(xml);
|
let ast = cache.get(xml);
|
||||||
if (!ast) {
|
if (!ast) {
|
||||||
// we clone here the xml to prevent modifying it in place
|
// we clone here the xml to prevent modifying it in place
|
||||||
@@ -362,9 +366,9 @@ function parseDOMNode(node: Element, ctx: ParsingContext): AST | null {
|
|||||||
const isSelect = tagName === "select";
|
const isSelect = tagName === "select";
|
||||||
const isCheckboxInput = isInput && typeAttr === "checkbox";
|
const isCheckboxInput = isInput && typeAttr === "checkbox";
|
||||||
const isRadioInput = isInput && typeAttr === "radio";
|
const isRadioInput = isInput && typeAttr === "radio";
|
||||||
const hasTrimMod = attr.includes(".trim");
|
const hasLazyMod = attr.includes(".lazy");
|
||||||
const hasLazyMod = hasTrimMod || attr.includes(".lazy");
|
|
||||||
const hasNumberMod = attr.includes(".number");
|
const hasNumberMod = attr.includes(".number");
|
||||||
|
const hasTrimMod = attr.includes(".trim");
|
||||||
const eventType = isRadioInput ? "click" : isSelect || hasLazyMod ? "change" : "input";
|
const eventType = isRadioInput ? "click" : isSelect || hasLazyMod ? "change" : "input";
|
||||||
|
|
||||||
model = {
|
model = {
|
||||||
@@ -736,14 +740,14 @@ function parseComponent(node: Element, ctx: ParsingContext): AST | null {
|
|||||||
// be ignored)
|
// be ignored)
|
||||||
let el = slotNode.parentElement!;
|
let el = slotNode.parentElement!;
|
||||||
let isInSubComponent = false;
|
let isInSubComponent = false;
|
||||||
while (el && el !== clone) {
|
while (el !== clone) {
|
||||||
if (el!.hasAttribute("t-component") || el!.tagName[0] === el!.tagName[0].toUpperCase()) {
|
if (el!.hasAttribute("t-component") || el!.tagName[0] === el!.tagName[0].toUpperCase()) {
|
||||||
isInSubComponent = true;
|
isInSubComponent = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
el = el.parentElement!;
|
el = el.parentElement!;
|
||||||
}
|
}
|
||||||
if (isInSubComponent || !el) {
|
if (isInSubComponent) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -968,3 +972,40 @@ function normalizeXML(el: Element) {
|
|||||||
normalizeTIf(el);
|
normalizeTIf(el);
|
||||||
normalizeTEscTOut(el);
|
normalizeTEscTOut(el);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses an XML string into an XML document, throwing errors on parser errors
|
||||||
|
* instead of returning an XML document containing the parseerror.
|
||||||
|
*
|
||||||
|
* @param xml the string to parse
|
||||||
|
* @returns an XML document corresponding to the content of the string
|
||||||
|
*/
|
||||||
|
function parseXML(xml: string): XMLDocument {
|
||||||
|
const parser = new DOMParser();
|
||||||
|
const doc = parser.parseFromString(xml, "text/xml");
|
||||||
|
if (doc.getElementsByTagName("parsererror").length) {
|
||||||
|
let msg = "Invalid XML in template.";
|
||||||
|
const parsererrorText = doc.getElementsByTagName("parsererror")[0].textContent;
|
||||||
|
if (parsererrorText) {
|
||||||
|
msg += "\nThe parser has produced the following error message:\n" + parsererrorText;
|
||||||
|
const re = /\d+/g;
|
||||||
|
const firstMatch = re.exec(parsererrorText);
|
||||||
|
if (firstMatch) {
|
||||||
|
const lineNumber = Number(firstMatch[0]);
|
||||||
|
const line = xml.split("\n")[lineNumber - 1];
|
||||||
|
const secondMatch = re.exec(parsererrorText);
|
||||||
|
if (line && secondMatch) {
|
||||||
|
const columnIndex = Number(secondMatch[0]) - 1;
|
||||||
|
if (line[columnIndex]) {
|
||||||
|
msg +=
|
||||||
|
`\nThe error might be located at xml line ${lineNumber} column ${columnIndex}\n` +
|
||||||
|
`${line}\n${"-".repeat(columnIndex - 1)}^`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new OwlError(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
return doc;
|
||||||
|
}
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ export type ComponentConstructor<P extends Props = any, E = any> = (new (
|
|||||||
|
|
||||||
export class Component<Props = any, Env = any> {
|
export class Component<Props = any, Env = any> {
|
||||||
static template: string = "";
|
static template: string = "";
|
||||||
static props?: Schema;
|
static props?: any;
|
||||||
static defaultProps?: any;
|
static defaultProps?: any;
|
||||||
|
|
||||||
props: Props;
|
props: Props;
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { OwlError } from "../common/owl_error";
|
|||||||
import { Fiber, makeChildFiber, makeRootFiber, MountFiber, MountOptions } from "./fibers";
|
import { Fiber, makeChildFiber, makeRootFiber, MountFiber, MountOptions } from "./fibers";
|
||||||
import { clearReactivesForCallback, getSubscriptions, reactive, targets } from "./reactivity";
|
import { clearReactivesForCallback, getSubscriptions, reactive, targets } from "./reactivity";
|
||||||
import { STATUS } from "./status";
|
import { STATUS } from "./status";
|
||||||
import { batched, Callback } from "./utils";
|
import { batched, Callback, possiblySync } from "./utils";
|
||||||
|
|
||||||
let currentNode: ComponentNode | null = null;
|
let currentNode: ComponentNode | null = null;
|
||||||
|
|
||||||
@@ -128,21 +128,29 @@ export class ComponentNode<P extends Props = any, E = any> implements VNode<Comp
|
|||||||
this.initiateRender(fiber);
|
this.initiateRender(fiber);
|
||||||
}
|
}
|
||||||
|
|
||||||
async initiateRender(fiber: Fiber | MountFiber) {
|
initiateRender(fiber: Fiber | MountFiber) {
|
||||||
this.fiber = fiber;
|
this.fiber = fiber;
|
||||||
if (this.mounted.length) {
|
if (this.mounted.length) {
|
||||||
fiber.root!.mounted.push(fiber);
|
fiber.root!.mounted.push(fiber);
|
||||||
}
|
}
|
||||||
const component = this.component;
|
const component = this.component;
|
||||||
try {
|
return possiblySync(
|
||||||
await Promise.all(this.willStart.map((f) => f.call(component)));
|
() => {
|
||||||
} catch (e) {
|
const willStartResults = this.willStart.map((f) => f.call(component));
|
||||||
this.app.handleError({ node: this, error: e });
|
if (willStartResults.some((r) => typeof r?.then === "function")) {
|
||||||
return;
|
return Promise.all(willStartResults);
|
||||||
}
|
}
|
||||||
if (this.status === STATUS.NEW && this.fiber === fiber) {
|
return;
|
||||||
fiber.render();
|
},
|
||||||
}
|
() => {
|
||||||
|
if (this.status === STATUS.NEW && this.fiber === fiber) {
|
||||||
|
fiber.render();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
(e: any) => {
|
||||||
|
this.app.handleError({ node: this, error: e });
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async render(deep: boolean) {
|
async render(deep: boolean) {
|
||||||
@@ -238,7 +246,7 @@ export class ComponentNode<P extends Props = any, E = any> implements VNode<Comp
|
|||||||
this.status = STATUS.DESTROYED;
|
this.status = STATUS.DESTROYED;
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateAndRender(props: P, parentFiber: Fiber) {
|
updateAndRender(props: P, parentFiber: Fiber) {
|
||||||
this.nextProps = props;
|
this.nextProps = props;
|
||||||
props = Object.assign({}, props);
|
props = Object.assign({}, props);
|
||||||
// update
|
// update
|
||||||
@@ -258,20 +266,29 @@ export class ComponentNode<P extends Props = any, E = any> implements VNode<Comp
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
currentNode = null;
|
currentNode = null;
|
||||||
const prom = Promise.all(this.willUpdateProps.map((f) => f.call(component, props)));
|
return possiblySync(
|
||||||
await prom;
|
() => {
|
||||||
if (fiber !== this.fiber) {
|
const willUpdateProps = this.willUpdateProps.map((f) => f.call(component, props));
|
||||||
return;
|
if (willUpdateProps.some((p) => typeof p?.then === "function")) {
|
||||||
}
|
return Promise.all(willUpdateProps);
|
||||||
component.props = props;
|
}
|
||||||
fiber.render();
|
return;
|
||||||
const parentRoot = parentFiber.root!;
|
},
|
||||||
if (this.willPatch.length) {
|
() => {
|
||||||
parentRoot.willPatch.push(fiber);
|
if (fiber !== this.fiber) {
|
||||||
}
|
return;
|
||||||
if (this.patched.length) {
|
}
|
||||||
parentRoot.patched.push(fiber);
|
component.props = props;
|
||||||
}
|
fiber.render();
|
||||||
|
const parentRoot = parentFiber.root!;
|
||||||
|
if (this.willPatch.length) {
|
||||||
|
parentRoot.willPatch.push(fiber);
|
||||||
|
}
|
||||||
|
if (this.patched.length) {
|
||||||
|
parentRoot.patched.push(fiber);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ export function useChildSubEnv(envExtension: Env) {
|
|||||||
// useEffect
|
// useEffect
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
type EffectDeps<T extends unknown[]> = T | (T extends [...infer H, never] ? EffectDeps<H> : never);
|
type EffectDeps<T extends any[]> = T | (T extends [...infer H, never] ? EffectDeps<H> : never);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @template T
|
* @template T
|
||||||
@@ -67,7 +67,7 @@ type EffectDeps<T extends unknown[]> = T | (T extends [...infer H, never] ? Effe
|
|||||||
* @returns {void|(()=>void)} a cleanup function that reverses the side
|
* @returns {void|(()=>void)} a cleanup function that reverses the side
|
||||||
* effects of the effect callback.
|
* effects of the effect callback.
|
||||||
*/
|
*/
|
||||||
type Effect<T extends unknown[]> = (...dependencies: EffectDeps<T>) => void | (() => void);
|
type Effect<T extends [...T]> = (...dependencies: EffectDeps<T>) => void | (() => void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This hook will run a callback when a component is mounted and patched, and
|
* This hook will run a callback when a component is mounted and patched, and
|
||||||
@@ -76,15 +76,15 @@ type Effect<T extends unknown[]> = (...dependencies: EffectDeps<T>) => void | ((
|
|||||||
*
|
*
|
||||||
* @template T
|
* @template T
|
||||||
* @param {Effect<T>} effect the effect to run on component mount and/or patch
|
* @param {Effect<T>} effect the effect to run on component mount and/or patch
|
||||||
* @param {()=>[...T]} [computeDependencies=()=>[NaN]] a callback to compute
|
* @param {()=>T} [computeDependencies=()=>[NaN]] a callback to compute
|
||||||
* dependencies that will decide if the effect needs to be cleaned up and
|
* dependencies that will decide if the effect needs to be cleaned up and
|
||||||
* run again. If the dependencies did not change, the effect will not run
|
* run again. If the dependencies did not change, the effect will not run
|
||||||
* again. The default value returns an array containing only NaN because
|
* again. The default value returns an array containing only NaN because
|
||||||
* NaN !== NaN, which will cause the effect to rerun on every patch.
|
* NaN !== NaN, which will cause the effect to rerun on every patch.
|
||||||
*/
|
*/
|
||||||
export function useEffect<T extends unknown[]>(
|
export function useEffect<T extends [...T]>(
|
||||||
effect: Effect<T>,
|
effect: Effect<T>,
|
||||||
computeDependencies: () => [...T] = () => [NaN] as never
|
computeDependencies: () => T = () => [NaN] as never
|
||||||
) {
|
) {
|
||||||
let cleanup: (() => void) | void;
|
let cleanup: (() => void) | void;
|
||||||
let dependencies: T;
|
let dependencies: T;
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ export class Portal extends Component {
|
|||||||
type: String,
|
type: String,
|
||||||
},
|
},
|
||||||
slots: true,
|
slots: true,
|
||||||
} as const;
|
};
|
||||||
|
|
||||||
setup() {
|
setup() {
|
||||||
const node: any = this.__owl__;
|
const node: any = this.__owl__;
|
||||||
|
|||||||
@@ -249,7 +249,7 @@ function basicProxyHandler<T extends Target>(callback: Callback): ProxyHandler<T
|
|||||||
set(target, key, value, receiver) {
|
set(target, key, value, receiver) {
|
||||||
const hadKey = objectHasOwnProperty.call(target, key);
|
const hadKey = objectHasOwnProperty.call(target, key);
|
||||||
const originalValue = Reflect.get(target, key, receiver);
|
const originalValue = Reflect.get(target, key, receiver);
|
||||||
const ret = Reflect.set(target, key, toRaw(value), receiver);
|
const ret = Reflect.set(target, key, value, receiver);
|
||||||
if (!hadKey && objectHasOwnProperty.call(target, key)) {
|
if (!hadKey && objectHasOwnProperty.call(target, key)) {
|
||||||
notifyReactives(target, KEYCHANGES);
|
notifyReactives(target, KEYCHANGES);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,15 +4,44 @@ import { getCurrent } from "./component_node";
|
|||||||
import { Portal, portalTemplate } from "./portal";
|
import { Portal, portalTemplate } from "./portal";
|
||||||
import { helpers } from "./template_helpers";
|
import { helpers } from "./template_helpers";
|
||||||
import { OwlError } from "../common/owl_error";
|
import { OwlError } from "../common/owl_error";
|
||||||
import { parseXML } from "../common/utils";
|
|
||||||
|
|
||||||
const bdom = { text, createBlock, list, multi, html, toggler, comment };
|
const bdom = { text, createBlock, list, multi, html, toggler, comment };
|
||||||
|
|
||||||
|
function parseXML(xml: string): Document {
|
||||||
|
const parser = new DOMParser();
|
||||||
|
|
||||||
|
const doc = parser.parseFromString(xml, "text/xml");
|
||||||
|
if (doc.getElementsByTagName("parsererror").length) {
|
||||||
|
let msg = "Invalid XML in template.";
|
||||||
|
const parsererrorText = doc.getElementsByTagName("parsererror")[0].textContent;
|
||||||
|
if (parsererrorText) {
|
||||||
|
msg += "\nThe parser has produced the following error message:\n" + parsererrorText;
|
||||||
|
const re = /\d+/g;
|
||||||
|
const firstMatch = re.exec(parsererrorText);
|
||||||
|
if (firstMatch) {
|
||||||
|
const lineNumber = Number(firstMatch[0]);
|
||||||
|
const line = xml.split("\n")[lineNumber - 1];
|
||||||
|
const secondMatch = re.exec(parsererrorText);
|
||||||
|
if (line && secondMatch) {
|
||||||
|
const columnIndex = Number(secondMatch[0]) - 1;
|
||||||
|
if (line[columnIndex]) {
|
||||||
|
msg +=
|
||||||
|
`\nThe error might be located at xml line ${lineNumber} column ${columnIndex}\n` +
|
||||||
|
`${line}\n${"-".repeat(columnIndex - 1)}^`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new OwlError(msg);
|
||||||
|
}
|
||||||
|
return doc;
|
||||||
|
}
|
||||||
|
|
||||||
export interface TemplateSetConfig {
|
export interface TemplateSetConfig {
|
||||||
dev?: boolean;
|
dev?: boolean;
|
||||||
translatableAttributes?: string[];
|
translatableAttributes?: string[];
|
||||||
translateFn?: (s: string) => string;
|
translateFn?: (s: string) => string;
|
||||||
templates?: string | Document | Record<string, string>;
|
templates?: string | Document;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class TemplateSet {
|
export class TemplateSet {
|
||||||
@@ -31,13 +60,7 @@ export class TemplateSet {
|
|||||||
this.translateFn = config.translateFn;
|
this.translateFn = config.translateFn;
|
||||||
this.translatableAttributes = config.translatableAttributes;
|
this.translatableAttributes = config.translatableAttributes;
|
||||||
if (config.templates) {
|
if (config.templates) {
|
||||||
if (config.templates instanceof Document || typeof config.templates === "string") {
|
this.addTemplates(config.templates);
|
||||||
this.addTemplates(config.templates);
|
|
||||||
} else {
|
|
||||||
for (const name in config.templates) {
|
|
||||||
this.addTemplate(name, config.templates[name]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -88,3 +88,24 @@ export class Markup extends String {}
|
|||||||
export function markup(value: any) {
|
export function markup(value: any) {
|
||||||
return new Markup(value);
|
return new Markup(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function possiblySync(computation: Function, onSuccess: Function, onError?: Function) {
|
||||||
|
try {
|
||||||
|
let result;
|
||||||
|
if (onError) {
|
||||||
|
try {
|
||||||
|
result = computation();
|
||||||
|
} catch (e) {
|
||||||
|
return onError(e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result = computation();
|
||||||
|
}
|
||||||
|
if (typeof result?.then === "function") {
|
||||||
|
return result.then(onSuccess, onError);
|
||||||
|
}
|
||||||
|
return onSuccess(result);
|
||||||
|
} catch (e) {
|
||||||
|
return Promise.reject(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ type BaseType =
|
|||||||
| typeof Date
|
| typeof Date
|
||||||
| typeof Object
|
| typeof Object
|
||||||
| typeof Array
|
| typeof Array
|
||||||
| typeof Function
|
|
||||||
| true
|
| true
|
||||||
| "*";
|
| "*";
|
||||||
|
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
// do not modify manually. This file is generated by the release script.
|
// do not modify manually. This file is generated by the release script.
|
||||||
export const version = "2.2.7";
|
export const version = "2.2.6";
|
||||||
|
|||||||
@@ -57,19 +57,6 @@ exports[`app can configure an app with props 1`] = `
|
|||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`app can load templates from an object name-string 1`] = `
|
|
||||||
"function anonymous(app, bdom, helpers
|
|
||||||
) {
|
|
||||||
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
|
||||||
|
|
||||||
let block1 = createBlock(\`<div class=\\"hello\\">hello</div>\`);
|
|
||||||
|
|
||||||
return function template(ctx, node, key = \\"\\") {
|
|
||||||
return block1();
|
|
||||||
}
|
|
||||||
}"
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`app can mount app in an iframe 1`] = `
|
exports[`app can mount app in an iframe 1`] = `
|
||||||
"function anonymous(app, bdom, helpers
|
"function anonymous(app, bdom, helpers
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -167,21 +167,4 @@ describe("app", () => {
|
|||||||
]
|
]
|
||||||
`);
|
`);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("can load templates from an object name-string", async () => {
|
|
||||||
const templates = {
|
|
||||||
hello: `<div class="hello">hello</div>`,
|
|
||||||
world: `<div>world</div>`,
|
|
||||||
};
|
|
||||||
class SomeComponent extends Component {
|
|
||||||
static template = "hello";
|
|
||||||
}
|
|
||||||
|
|
||||||
const app = new App(SomeComponent, { templates });
|
|
||||||
await app.mount(fixture);
|
|
||||||
expect(fixture.querySelector(".hello")).toBeDefined();
|
|
||||||
// Only the "hello" template is used, so the "world" template is not yet loaded
|
|
||||||
expect(Object.keys(app.templates)).toEqual(["hello"]);
|
|
||||||
expect(Object.keys(app.rawTemplates)).toEqual(["hello", "world"]);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,7 +1,4 @@
|
|||||||
import { parseXML } from "../../src/common/utils";
|
import { ASTType, parse } from "../../src/compiler/parser";
|
||||||
import { ASTType, parse as _parse } from "../../src/compiler/parser";
|
|
||||||
|
|
||||||
const parse = (template: string) => _parse(parseXML(`<t>${template}</t>`).firstChild as Element);
|
|
||||||
|
|
||||||
describe("qweb parser", () => {
|
describe("qweb parser", () => {
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -1861,10 +1861,10 @@ exports[`renderings, destruction, patch, stuff, ... yet another variation 3`] =
|
|||||||
) {
|
) {
|
||||||
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
||||||
|
|
||||||
let block3 = createBlock(\`<p block-handler-0=\\"click\\"><block-text-1/></p>\`);
|
let block3 = createBlock(\`<span block-handler-0=\\"click\\"><block-text-1/></span>\`);
|
||||||
|
|
||||||
return function template(ctx, node, key = \\"\\") {
|
return function template(ctx, node, key = \\"\\") {
|
||||||
const b2 = text(\`D\`);
|
const b2 = text(\`C\`);
|
||||||
let hdlr1 = [ctx['increment'], ctx];
|
let hdlr1 = [ctx['increment'], ctx];
|
||||||
let txt1 = ctx['state'].val;
|
let txt1 = ctx['state'].val;
|
||||||
const b3 = block3([hdlr1, txt1]);
|
const b3 = block3([hdlr1, txt1]);
|
||||||
@@ -1878,10 +1878,10 @@ exports[`renderings, destruction, patch, stuff, ... yet another variation 4`] =
|
|||||||
) {
|
) {
|
||||||
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
||||||
|
|
||||||
let block3 = createBlock(\`<span block-handler-0=\\"click\\"><block-text-1/></span>\`);
|
let block3 = createBlock(\`<p block-handler-0=\\"click\\"><block-text-1/></p>\`);
|
||||||
|
|
||||||
return function template(ctx, node, key = \\"\\") {
|
return function template(ctx, node, key = \\"\\") {
|
||||||
const b2 = text(\`C\`);
|
const b2 = text(\`D\`);
|
||||||
let hdlr1 = [ctx['increment'], ctx];
|
let hdlr1 = [ctx['increment'], ctx];
|
||||||
let txt1 = ctx['state'].val;
|
let txt1 = ctx['state'].val;
|
||||||
const b3 = block3([hdlr1, txt1]);
|
const b3 = block3([hdlr1, txt1]);
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ exports[`refs refs are properly bound in slots 1`] = `
|
|||||||
"function anonymous(app, bdom, helpers
|
"function anonymous(app, bdom, helpers
|
||||||
) {
|
) {
|
||||||
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
||||||
let { markRaw } = helpers;
|
let { capture, markRaw } = helpers;
|
||||||
const comp1 = app.createComponent(\`Dialog\`, true, true, false, []);
|
const comp1 = app.createComponent(\`Dialog\`, true, true, false, []);
|
||||||
|
|
||||||
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>\`);
|
||||||
@@ -113,7 +113,8 @@ 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 b3 = comp1({slots: markRaw({'footer': {__render: slot1.bind(this), __ctx: ctx}})}, key + \`__1\`, node, this, null);
|
const ctx1 = capture(ctx);
|
||||||
|
const b3 = comp1({slots: markRaw({'footer': {__render: slot1.bind(this), __ctx: ctx1}})}, key + \`__1\`, node, this, null);
|
||||||
return block1([txt1], [b3]);
|
return block1([txt1], [b3]);
|
||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ exports[`slots can define and call slots 1`] = `
|
|||||||
"function anonymous(app, bdom, helpers
|
"function anonymous(app, bdom, helpers
|
||||||
) {
|
) {
|
||||||
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
||||||
let { markRaw } = helpers;
|
let { capture, markRaw } = helpers;
|
||||||
const comp1 = app.createComponent(\`Dialog\`, true, true, false, []);
|
const comp1 = app.createComponent(\`Dialog\`, true, true, false, []);
|
||||||
|
|
||||||
let block1 = createBlock(\`<div><block-child-0/></div>\`);
|
let block1 = createBlock(\`<div><block-child-0/></div>\`);
|
||||||
@@ -54,7 +54,8 @@ exports[`slots can define and call slots 1`] = `
|
|||||||
}
|
}
|
||||||
|
|
||||||
return function template(ctx, node, key = \\"\\") {
|
return function template(ctx, node, key = \\"\\") {
|
||||||
const b4 = comp1({slots: markRaw({'header': {__render: slot1.bind(this), __ctx: ctx}, 'footer': {__render: slot2.bind(this), __ctx: ctx}})}, key + \`__1\`, node, this, null);
|
const ctx1 = capture(ctx);
|
||||||
|
const b4 = comp1({slots: markRaw({'header': {__render: slot1.bind(this), __ctx: ctx1}, 'footer': {__render: slot2.bind(this), __ctx: ctx1}})}, key + \`__1\`, node, this, null);
|
||||||
return block1([], [b4]);
|
return block1([], [b4]);
|
||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
@@ -80,7 +81,7 @@ exports[`slots can define and call slots with bound params 1`] = `
|
|||||||
"function anonymous(app, bdom, helpers
|
"function anonymous(app, bdom, helpers
|
||||||
) {
|
) {
|
||||||
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
||||||
let { markRaw } = helpers;
|
let { capture, markRaw } = helpers;
|
||||||
const comp1 = app.createComponent(\`Child\`, true, true, false, []);
|
const comp1 = app.createComponent(\`Child\`, true, true, false, []);
|
||||||
|
|
||||||
function slot1(ctx, node, key = \\"\\") {
|
function slot1(ctx, node, key = \\"\\") {
|
||||||
@@ -88,7 +89,8 @@ exports[`slots can define and call slots with bound params 1`] = `
|
|||||||
}
|
}
|
||||||
|
|
||||||
return function template(ctx, node, key = \\"\\") {
|
return function template(ctx, node, key = \\"\\") {
|
||||||
return comp1({slots: markRaw({'abc': {__render: slot1.bind(this), __ctx: ctx, getValue: (ctx['getValue']).bind(this)}})}, key + \`__1\`, node, this, null);
|
const ctx1 = capture(ctx);
|
||||||
|
return comp1({slots: markRaw({'abc': {__render: slot1.bind(this), __ctx: ctx1, getValue: (ctx['getValue']).bind(this)}})}, key + \`__1\`, node, this, null);
|
||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
@@ -111,7 +113,7 @@ exports[`slots can define and call slots with params 1`] = `
|
|||||||
"function anonymous(app, bdom, helpers
|
"function anonymous(app, bdom, helpers
|
||||||
) {
|
) {
|
||||||
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
||||||
let { markRaw } = helpers;
|
let { capture, markRaw } = helpers;
|
||||||
const comp1 = app.createComponent(\`Dialog\`, true, true, false, []);
|
const comp1 = app.createComponent(\`Dialog\`, true, true, false, []);
|
||||||
|
|
||||||
let block1 = createBlock(\`<div><block-child-0/></div>\`);
|
let block1 = createBlock(\`<div><block-child-0/></div>\`);
|
||||||
@@ -127,7 +129,8 @@ exports[`slots can define and call slots with params 1`] = `
|
|||||||
}
|
}
|
||||||
|
|
||||||
return function template(ctx, node, key = \\"\\") {
|
return function template(ctx, node, key = \\"\\") {
|
||||||
const b4 = comp1({slots: markRaw({'header': {__render: slot1.bind(this), __ctx: ctx, param: ctx['var']}, 'footer': {__render: slot2.bind(this), __ctx: ctx, param: '5'}})}, key + \`__1\`, node, this, null);
|
const ctx1 = capture(ctx);
|
||||||
|
const b4 = comp1({slots: markRaw({'header': {__render: slot1.bind(this), __ctx: ctx1, param: ctx['var']}, 'footer': {__render: slot2.bind(this), __ctx: ctx1, param: '5'}})}, key + \`__1\`, node, this, null);
|
||||||
return block1([], [b4]);
|
return block1([], [b4]);
|
||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
@@ -349,7 +352,7 @@ exports[`slots default content is not rendered if named slot is provided 1`] = `
|
|||||||
"function anonymous(app, bdom, helpers
|
"function anonymous(app, bdom, helpers
|
||||||
) {
|
) {
|
||||||
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
||||||
let { markRaw } = helpers;
|
let { capture, markRaw } = helpers;
|
||||||
const comp1 = app.createComponent(\`Dialog\`, true, true, false, []);
|
const comp1 = app.createComponent(\`Dialog\`, true, true, false, []);
|
||||||
|
|
||||||
let block1 = createBlock(\`<div><block-child-0/></div>\`);
|
let block1 = createBlock(\`<div><block-child-0/></div>\`);
|
||||||
@@ -359,7 +362,8 @@ exports[`slots default content is not rendered if named slot is provided 1`] = `
|
|||||||
}
|
}
|
||||||
|
|
||||||
return function template(ctx, node, key = \\"\\") {
|
return function template(ctx, node, key = \\"\\") {
|
||||||
const b3 = comp1({slots: markRaw({'header': {__render: slot1.bind(this), __ctx: ctx}})}, key + \`__1\`, node, this, null);
|
const ctx1 = capture(ctx);
|
||||||
|
const b3 = comp1({slots: markRaw({'header': {__render: slot1.bind(this), __ctx: ctx1}})}, key + \`__1\`, node, this, null);
|
||||||
return block1([], [b3]);
|
return block1([], [b3]);
|
||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
@@ -427,7 +431,7 @@ exports[`slots default slot next to named slot, with default content 1`] = `
|
|||||||
"function anonymous(app, bdom, helpers
|
"function anonymous(app, bdom, helpers
|
||||||
) {
|
) {
|
||||||
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
||||||
let { markRaw } = helpers;
|
let { capture, markRaw } = helpers;
|
||||||
const comp1 = app.createComponent(\`Dialog\`, true, true, false, []);
|
const comp1 = app.createComponent(\`Dialog\`, true, true, false, []);
|
||||||
|
|
||||||
let block1 = createBlock(\`<div><block-child-0/></div>\`);
|
let block1 = createBlock(\`<div><block-child-0/></div>\`);
|
||||||
@@ -437,7 +441,8 @@ exports[`slots default slot next to named slot, with default content 1`] = `
|
|||||||
}
|
}
|
||||||
|
|
||||||
return function template(ctx, node, key = \\"\\") {
|
return function template(ctx, node, key = \\"\\") {
|
||||||
const b3 = comp1({slots: markRaw({'footer': {__render: slot1.bind(this), __ctx: ctx}})}, key + \`__1\`, node, this, null);
|
const ctx1 = capture(ctx);
|
||||||
|
const b3 = comp1({slots: markRaw({'footer': {__render: slot1.bind(this), __ctx: ctx1}})}, key + \`__1\`, node, this, null);
|
||||||
return block1([], [b3]);
|
return block1([], [b3]);
|
||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
@@ -602,7 +607,7 @@ exports[`slots dynamic slot in multiple locations 1`] = `
|
|||||||
"function anonymous(app, bdom, helpers
|
"function anonymous(app, bdom, helpers
|
||||||
) {
|
) {
|
||||||
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
||||||
let { markRaw } = helpers;
|
let { capture, markRaw } = helpers;
|
||||||
const comp1 = app.createComponent(\`Child\`, true, false, false, []);
|
const comp1 = app.createComponent(\`Child\`, true, false, false, []);
|
||||||
const comp2 = app.createComponent(\`Slotter\`, true, true, false, [\\"location\\"]);
|
const comp2 = app.createComponent(\`Slotter\`, true, true, false, [\\"location\\"]);
|
||||||
|
|
||||||
@@ -613,7 +618,8 @@ exports[`slots dynamic slot in multiple locations 1`] = `
|
|||||||
}
|
}
|
||||||
|
|
||||||
return function template(ctx, node, key = \\"\\") {
|
return function template(ctx, node, key = \\"\\") {
|
||||||
return comp2({location: ctx['state'].location,slots: markRaw({'coffee': {__render: slot1.bind(this), __ctx: ctx}})}, key + \`__2\`, node, this, null);
|
const ctx1 = capture(ctx);
|
||||||
|
return comp2({location: ctx['state'].location,slots: markRaw({'coffee': {__render: slot1.bind(this), __ctx: ctx1}})}, key + \`__2\`, node, this, null);
|
||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
@@ -659,7 +665,7 @@ exports[`slots dynamic t-slot call 1`] = `
|
|||||||
"function anonymous(app, bdom, helpers
|
"function anonymous(app, bdom, helpers
|
||||||
) {
|
) {
|
||||||
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
||||||
let { markRaw } = helpers;
|
let { capture, markRaw } = helpers;
|
||||||
const comp1 = app.createComponent(\`Toggler\`, true, true, false, []);
|
const comp1 = app.createComponent(\`Toggler\`, true, true, false, []);
|
||||||
|
|
||||||
let block1 = createBlock(\`<div><block-child-0/></div>\`);
|
let block1 = createBlock(\`<div><block-child-0/></div>\`);
|
||||||
@@ -678,7 +684,8 @@ exports[`slots dynamic t-slot call 1`] = `
|
|||||||
}
|
}
|
||||||
|
|
||||||
return function template(ctx, node, key = \\"\\") {
|
return function template(ctx, node, key = \\"\\") {
|
||||||
const b6 = comp1({slots: markRaw({'slot1': {__render: slot1.bind(this), __ctx: ctx}, 'slot2': {__render: slot2.bind(this), __ctx: ctx}})}, key + \`__1\`, node, this, null);
|
const ctx1 = capture(ctx);
|
||||||
|
const b6 = comp1({slots: markRaw({'slot1': {__render: slot1.bind(this), __ctx: ctx1}, 'slot2': {__render: slot2.bind(this), __ctx: ctx1}})}, key + \`__1\`, node, this, null);
|
||||||
return block1([], [b6]);
|
return block1([], [b6]);
|
||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
@@ -705,7 +712,7 @@ exports[`slots dynamic t-slot call with default 1`] = `
|
|||||||
"function anonymous(app, bdom, helpers
|
"function anonymous(app, bdom, helpers
|
||||||
) {
|
) {
|
||||||
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
||||||
let { markRaw } = helpers;
|
let { capture, markRaw } = helpers;
|
||||||
const comp1 = app.createComponent(\`Toggler\`, true, true, false, []);
|
const comp1 = app.createComponent(\`Toggler\`, true, true, false, []);
|
||||||
|
|
||||||
let block1 = createBlock(\`<div><block-child-0/></div>\`);
|
let block1 = createBlock(\`<div><block-child-0/></div>\`);
|
||||||
@@ -724,7 +731,8 @@ exports[`slots dynamic t-slot call with default 1`] = `
|
|||||||
}
|
}
|
||||||
|
|
||||||
return function template(ctx, node, key = \\"\\") {
|
return function template(ctx, node, key = \\"\\") {
|
||||||
const b6 = comp1({slots: markRaw({'slot1': {__render: slot1.bind(this), __ctx: ctx}, 'slot2': {__render: slot2.bind(this), __ctx: ctx}})}, key + \`__1\`, node, this, null);
|
const ctx1 = capture(ctx);
|
||||||
|
const b6 = comp1({slots: markRaw({'slot1': {__render: slot1.bind(this), __ctx: ctx1}, 'slot2': {__render: slot2.bind(this), __ctx: ctx1}})}, key + \`__1\`, node, this, null);
|
||||||
return block1([], [b6]);
|
return block1([], [b6]);
|
||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
@@ -968,7 +976,7 @@ exports[`slots multiple roots are allowed in a named slot 1`] = `
|
|||||||
"function anonymous(app, bdom, helpers
|
"function anonymous(app, bdom, helpers
|
||||||
) {
|
) {
|
||||||
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
||||||
let { markRaw } = helpers;
|
let { capture, markRaw } = helpers;
|
||||||
const comp1 = app.createComponent(\`Dialog\`, true, true, false, []);
|
const comp1 = app.createComponent(\`Dialog\`, true, true, false, []);
|
||||||
|
|
||||||
let block1 = createBlock(\`<div><block-child-0/></div>\`);
|
let block1 = createBlock(\`<div><block-child-0/></div>\`);
|
||||||
@@ -982,7 +990,8 @@ exports[`slots multiple roots are allowed in a named slot 1`] = `
|
|||||||
}
|
}
|
||||||
|
|
||||||
return function template(ctx, node, key = \\"\\") {
|
return function template(ctx, node, key = \\"\\") {
|
||||||
const b5 = comp1({slots: markRaw({'content': {__render: slot1.bind(this), __ctx: ctx}})}, key + \`__1\`, node, this, null);
|
const ctx1 = capture(ctx);
|
||||||
|
const b5 = comp1({slots: markRaw({'content': {__render: slot1.bind(this), __ctx: ctx1}})}, key + \`__1\`, node, this, null);
|
||||||
return block1([], [b5]);
|
return block1([], [b5]);
|
||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
@@ -1007,7 +1016,7 @@ exports[`slots multiple slots containing components 1`] = `
|
|||||||
"function anonymous(app, bdom, helpers
|
"function anonymous(app, bdom, helpers
|
||||||
) {
|
) {
|
||||||
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
||||||
let { markRaw } = helpers;
|
let { capture, markRaw } = helpers;
|
||||||
const comp1 = app.createComponent(\`C\`, true, false, false, [\\"val\\"]);
|
const comp1 = app.createComponent(\`C\`, true, false, false, [\\"val\\"]);
|
||||||
const comp2 = app.createComponent(\`C\`, true, false, false, [\\"val\\"]);
|
const comp2 = app.createComponent(\`C\`, true, false, false, [\\"val\\"]);
|
||||||
const comp3 = app.createComponent(\`B\`, true, true, false, []);
|
const comp3 = app.createComponent(\`B\`, true, true, false, []);
|
||||||
@@ -1021,7 +1030,8 @@ exports[`slots multiple slots containing components 1`] = `
|
|||||||
}
|
}
|
||||||
|
|
||||||
return function template(ctx, node, key = \\"\\") {
|
return function template(ctx, node, key = \\"\\") {
|
||||||
return comp3({slots: markRaw({'s1': {__render: slot1.bind(this), __ctx: ctx}, 's2': {__render: slot2.bind(this), __ctx: ctx}})}, key + \`__3\`, node, this, null);
|
const ctx1 = capture(ctx);
|
||||||
|
return comp3({slots: markRaw({'s1': {__render: slot1.bind(this), __ctx: ctx1}, 's2': {__render: slot2.bind(this), __ctx: ctx1}})}, key + \`__3\`, node, this, null);
|
||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
@@ -1056,48 +1066,11 @@ exports[`slots multiple slots containing components 3`] = `
|
|||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`slots named slot inside named slot in t-component 1`] = `
|
|
||||||
"function anonymous(app, bdom, helpers
|
|
||||||
) {
|
|
||||||
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
|
||||||
let { markRaw } = helpers;
|
|
||||||
const comp1 = app.createComponent(null, false, true, false, []);
|
|
||||||
const comp2 = app.createComponent(\`Child\`, true, true, false, []);
|
|
||||||
|
|
||||||
function slot1(ctx, node, key = \\"\\") {
|
|
||||||
const b2 = text(\` outer \`);
|
|
||||||
const Comp1 = ctx['Child'];
|
|
||||||
const b4 = toggler(Comp1, comp1({slots: markRaw({'brol': {__render: slot2.bind(this), __ctx: ctx}})}, (Comp1).name + key + \`__1\`, node, this, Comp1));
|
|
||||||
return multi([b2, b4]);
|
|
||||||
}
|
|
||||||
|
|
||||||
function slot2(ctx, node, key = \\"\\") {
|
|
||||||
return text(ctx['value']);
|
|
||||||
}
|
|
||||||
|
|
||||||
return function template(ctx, node, key = \\"\\") {
|
|
||||||
return comp2({slots: markRaw({'brol': {__render: slot1.bind(this), __ctx: ctx}})}, key + \`__2\`, node, this, null);
|
|
||||||
}
|
|
||||||
}"
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`slots named slot inside named slot in t-component 2`] = `
|
|
||||||
"function anonymous(app, bdom, helpers
|
|
||||||
) {
|
|
||||||
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
|
||||||
let { callSlot } = helpers;
|
|
||||||
|
|
||||||
return function template(ctx, node, key = \\"\\") {
|
|
||||||
return callSlot(ctx, node, key, 'brol', false, {});
|
|
||||||
}
|
|
||||||
}"
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`slots named slot inside slot 1`] = `
|
exports[`slots named slot inside slot 1`] = `
|
||||||
"function anonymous(app, bdom, helpers
|
"function anonymous(app, bdom, helpers
|
||||||
) {
|
) {
|
||||||
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
||||||
let { markRaw } = helpers;
|
let { capture, markRaw } = helpers;
|
||||||
const comp1 = app.createComponent(\`Child\`, true, true, false, []);
|
const comp1 = app.createComponent(\`Child\`, true, true, false, []);
|
||||||
const comp2 = app.createComponent(\`Child\`, true, true, false, []);
|
const comp2 = app.createComponent(\`Child\`, true, true, false, []);
|
||||||
|
|
||||||
@@ -1111,7 +1084,8 @@ exports[`slots named slot inside slot 1`] = `
|
|||||||
}
|
}
|
||||||
|
|
||||||
function slot2(ctx, node, key = \\"\\") {
|
function slot2(ctx, node, key = \\"\\") {
|
||||||
return comp1({slots: markRaw({'brol': {__render: slot3.bind(this), __ctx: ctx}})}, key + \`__1\`, node, this, null);
|
const ctx2 = capture(ctx);
|
||||||
|
return comp1({slots: markRaw({'brol': {__render: slot3.bind(this), __ctx: ctx2}})}, key + \`__1\`, node, this, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
function slot3(ctx, node, key = \\"\\") {
|
function slot3(ctx, node, key = \\"\\") {
|
||||||
@@ -1120,7 +1094,8 @@ exports[`slots named slot inside slot 1`] = `
|
|||||||
}
|
}
|
||||||
|
|
||||||
return function template(ctx, node, key = \\"\\") {
|
return function template(ctx, node, key = \\"\\") {
|
||||||
const b5 = comp2({slots: markRaw({'brol': {__render: slot1.bind(this), __ctx: ctx}, 'default': {__render: slot2.bind(this), __ctx: ctx}})}, key + \`__2\`, node, this, null);
|
const ctx1 = capture(ctx);
|
||||||
|
const b5 = comp2({slots: markRaw({'brol': {__render: slot1.bind(this), __ctx: ctx1}, 'default': {__render: slot2.bind(this), __ctx: ctx1}})}, key + \`__2\`, node, this, null);
|
||||||
return block1([], [b5]);
|
return block1([], [b5]);
|
||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
@@ -1146,7 +1121,7 @@ exports[`slots named slot inside slot, part 3 1`] = `
|
|||||||
"function anonymous(app, bdom, helpers
|
"function anonymous(app, bdom, helpers
|
||||||
) {
|
) {
|
||||||
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
||||||
let { markRaw } = helpers;
|
let { capture, markRaw } = helpers;
|
||||||
const comp1 = app.createComponent(\`Child\`, true, true, false, []);
|
const comp1 = app.createComponent(\`Child\`, true, true, false, []);
|
||||||
const comp2 = app.createComponent(\`Child\`, true, true, false, []);
|
const comp2 = app.createComponent(\`Child\`, true, true, false, []);
|
||||||
|
|
||||||
@@ -1160,7 +1135,8 @@ exports[`slots named slot inside slot, part 3 1`] = `
|
|||||||
}
|
}
|
||||||
|
|
||||||
function slot2(ctx, node, key = \\"\\") {
|
function slot2(ctx, node, key = \\"\\") {
|
||||||
return comp1({slots: markRaw({'brol': {__render: slot3.bind(this), __ctx: ctx}})}, key + \`__1\`, node, this, null);
|
const ctx2 = capture(ctx);
|
||||||
|
return comp1({slots: markRaw({'brol': {__render: slot3.bind(this), __ctx: ctx2}})}, key + \`__1\`, node, this, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
function slot3(ctx, node, key = \\"\\") {
|
function slot3(ctx, node, key = \\"\\") {
|
||||||
@@ -1169,7 +1145,8 @@ exports[`slots named slot inside slot, part 3 1`] = `
|
|||||||
}
|
}
|
||||||
|
|
||||||
return function template(ctx, node, key = \\"\\") {
|
return function template(ctx, node, key = \\"\\") {
|
||||||
const b5 = comp2({slots: markRaw({'brol': {__render: slot1.bind(this), __ctx: ctx}, 'default': {__render: slot2.bind(this), __ctx: ctx}})}, key + \`__2\`, node, this, null);
|
const ctx1 = capture(ctx);
|
||||||
|
const b5 = comp2({slots: markRaw({'brol': {__render: slot1.bind(this), __ctx: ctx1}, 'default': {__render: slot2.bind(this), __ctx: ctx1}})}, key + \`__2\`, node, this, null);
|
||||||
return block1([], [b5]);
|
return block1([], [b5]);
|
||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
@@ -1229,7 +1206,7 @@ exports[`slots named slots inside slot, again 1`] = `
|
|||||||
"function anonymous(app, bdom, helpers
|
"function anonymous(app, bdom, helpers
|
||||||
) {
|
) {
|
||||||
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
||||||
let { markRaw } = helpers;
|
let { capture, markRaw } = helpers;
|
||||||
const comp1 = app.createComponent(\`Child\`, true, true, false, []);
|
const comp1 = app.createComponent(\`Child\`, true, true, false, []);
|
||||||
const comp2 = app.createComponent(\`Child\`, true, true, false, []);
|
const comp2 = app.createComponent(\`Child\`, true, true, false, []);
|
||||||
|
|
||||||
@@ -1243,7 +1220,8 @@ exports[`slots named slots inside slot, again 1`] = `
|
|||||||
}
|
}
|
||||||
|
|
||||||
function slot2(ctx, node, key = \\"\\") {
|
function slot2(ctx, node, key = \\"\\") {
|
||||||
return comp1({slots: markRaw({'brol2': {__render: slot3.bind(this), __ctx: ctx}})}, key + \`__1\`, node, this, null);
|
const ctx2 = capture(ctx);
|
||||||
|
return comp1({slots: markRaw({'brol2': {__render: slot3.bind(this), __ctx: ctx2}})}, key + \`__1\`, node, this, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
function slot3(ctx, node, key = \\"\\") {
|
function slot3(ctx, node, key = \\"\\") {
|
||||||
@@ -1252,7 +1230,8 @@ exports[`slots named slots inside slot, again 1`] = `
|
|||||||
}
|
}
|
||||||
|
|
||||||
return function template(ctx, node, key = \\"\\") {
|
return function template(ctx, node, key = \\"\\") {
|
||||||
const b5 = comp2({slots: markRaw({'brol1': {__render: slot1.bind(this), __ctx: ctx}, 'default': {__render: slot2.bind(this), __ctx: ctx}})}, key + \`__2\`, node, this, null);
|
const ctx1 = capture(ctx);
|
||||||
|
const b5 = comp2({slots: markRaw({'brol1': {__render: slot1.bind(this), __ctx: ctx1}, 'default': {__render: slot2.bind(this), __ctx: ctx1}})}, key + \`__2\`, node, this, null);
|
||||||
return block1([], [b5]);
|
return block1([], [b5]);
|
||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
@@ -1575,7 +1554,7 @@ exports[`slots simple dynamic slot with slot scope 1`] = `
|
|||||||
"function anonymous(app, bdom, helpers
|
"function anonymous(app, bdom, helpers
|
||||||
) {
|
) {
|
||||||
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
||||||
let { markRaw } = helpers;
|
let { capture, markRaw } = helpers;
|
||||||
const comp1 = app.createComponent(\`Child\`, true, true, false, []);
|
const comp1 = app.createComponent(\`Child\`, true, true, false, []);
|
||||||
|
|
||||||
function slot1(ctx, node, key = \\"\\") {
|
function slot1(ctx, node, key = \\"\\") {
|
||||||
@@ -1589,7 +1568,8 @@ exports[`slots simple dynamic slot with slot scope 1`] = `
|
|||||||
}
|
}
|
||||||
|
|
||||||
return function template(ctx, node, key = \\"\\") {
|
return function template(ctx, node, key = \\"\\") {
|
||||||
return comp1({slots: markRaw({'slotName': {__render: slot1.bind(this), __ctx: ctx, __scope: \\"slotScope\\"}})}, key + \`__1\`, node, this, null);
|
const ctx1 = capture(ctx);
|
||||||
|
return comp1({slots: markRaw({'slotName': {__render: slot1.bind(this), __ctx: ctx1, __scope: \\"slotScope\\"}})}, key + \`__1\`, node, this, null);
|
||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
@@ -1614,10 +1594,11 @@ exports[`slots simple named and empty slot -- 2 1`] = `
|
|||||||
"function anonymous(app, bdom, helpers
|
"function anonymous(app, bdom, helpers
|
||||||
) {
|
) {
|
||||||
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
||||||
let { markRaw } = helpers;
|
let { capture, markRaw } = helpers;
|
||||||
const comp1 = app.createComponent(\`Child\`, true, true, false, []);
|
const comp1 = app.createComponent(\`Child\`, true, true, false, []);
|
||||||
|
|
||||||
return function template(ctx, node, key = \\"\\") {
|
return function template(ctx, node, key = \\"\\") {
|
||||||
|
const ctx1 = capture(ctx);
|
||||||
return comp1({slots: markRaw({'myEmptySlot': {myProp: 'myProp text'}})}, key + \`__1\`, node, this, null);
|
return comp1({slots: markRaw({'myEmptySlot': {myProp: 'myProp text'}})}, key + \`__1\`, node, this, null);
|
||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
@@ -1646,7 +1627,7 @@ exports[`slots simple named and empty slot 1`] = `
|
|||||||
"function anonymous(app, bdom, helpers
|
"function anonymous(app, bdom, helpers
|
||||||
) {
|
) {
|
||||||
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
||||||
let { markRaw } = helpers;
|
let { capture, markRaw } = helpers;
|
||||||
const comp1 = app.createComponent(\`Child\`, true, true, false, []);
|
const comp1 = app.createComponent(\`Child\`, true, true, false, []);
|
||||||
|
|
||||||
function slot1(ctx, node, key = \\"\\") {
|
function slot1(ctx, node, key = \\"\\") {
|
||||||
@@ -1654,7 +1635,8 @@ exports[`slots simple named and empty slot 1`] = `
|
|||||||
}
|
}
|
||||||
|
|
||||||
return function template(ctx, node, key = \\"\\") {
|
return function template(ctx, node, key = \\"\\") {
|
||||||
return comp1({slots: markRaw({'myEmptySlot': {}, 'default': {__render: slot1.bind(this), __ctx: ctx}})}, key + \`__1\`, node, this, null);
|
const ctx1 = capture(ctx);
|
||||||
|
return comp1({slots: markRaw({'myEmptySlot': {}, 'default': {__render: slot1.bind(this), __ctx: ctx1}})}, key + \`__1\`, node, this, null);
|
||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
@@ -1679,7 +1661,7 @@ exports[`slots simple slot with slot scope 1`] = `
|
|||||||
"function anonymous(app, bdom, helpers
|
"function anonymous(app, bdom, helpers
|
||||||
) {
|
) {
|
||||||
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
||||||
let { markRaw } = helpers;
|
let { capture, markRaw } = helpers;
|
||||||
const comp1 = app.createComponent(\`Child\`, true, true, false, []);
|
const comp1 = app.createComponent(\`Child\`, true, true, false, []);
|
||||||
|
|
||||||
function slot1(ctx, node, key = \\"\\") {
|
function slot1(ctx, node, key = \\"\\") {
|
||||||
@@ -1693,7 +1675,8 @@ exports[`slots simple slot with slot scope 1`] = `
|
|||||||
}
|
}
|
||||||
|
|
||||||
return function template(ctx, node, key = \\"\\") {
|
return function template(ctx, node, key = \\"\\") {
|
||||||
return comp1({slots: markRaw({'slotName': {__render: slot1.bind(this), __ctx: ctx, __scope: \\"slotScope\\"}})}, key + \`__1\`, node, this, null);
|
const ctx1 = capture(ctx);
|
||||||
|
return comp1({slots: markRaw({'slotName': {__render: slot1.bind(this), __ctx: ctx1, __scope: \\"slotScope\\"}})}, key + \`__1\`, node, this, null);
|
||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
@@ -2287,7 +2270,7 @@ exports[`slots slot with slot scope and t-props 1`] = `
|
|||||||
"function anonymous(app, bdom, helpers
|
"function anonymous(app, bdom, helpers
|
||||||
) {
|
) {
|
||||||
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
||||||
let { markRaw } = helpers;
|
let { capture, markRaw } = helpers;
|
||||||
const comp1 = app.createComponent(\`Child\`, true, true, false, []);
|
const comp1 = app.createComponent(\`Child\`, true, true, false, []);
|
||||||
|
|
||||||
let block2 = createBlock(\`<p><block-text-0/></p>\`);
|
let block2 = createBlock(\`<p><block-text-0/></p>\`);
|
||||||
@@ -2302,7 +2285,8 @@ exports[`slots slot with slot scope and t-props 1`] = `
|
|||||||
}
|
}
|
||||||
|
|
||||||
return function template(ctx, node, key = \\"\\") {
|
return function template(ctx, node, key = \\"\\") {
|
||||||
return comp1({slots: markRaw({'slotName': {__render: slot1.bind(this), __ctx: ctx, __scope: \\"info\\"}})}, key + \`__1\`, node, this, null);
|
const ctx1 = capture(ctx);
|
||||||
|
return comp1({slots: markRaw({'slotName': {__render: slot1.bind(this), __ctx: ctx1, __scope: \\"info\\"}})}, key + \`__1\`, node, this, null);
|
||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
@@ -2391,7 +2375,7 @@ exports[`slots slots are rendered with proper context 1`] = `
|
|||||||
"function anonymous(app, bdom, helpers
|
"function anonymous(app, bdom, helpers
|
||||||
) {
|
) {
|
||||||
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
||||||
let { markRaw } = helpers;
|
let { capture, markRaw } = helpers;
|
||||||
const comp1 = app.createComponent(\`Dialog\`, true, true, false, []);
|
const comp1 = app.createComponent(\`Dialog\`, true, true, false, []);
|
||||||
|
|
||||||
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>\`);
|
||||||
@@ -2404,7 +2388,8 @@ exports[`slots slots are rendered with proper context 1`] = `
|
|||||||
|
|
||||||
return function template(ctx, node, key = \\"\\") {
|
return function template(ctx, node, key = \\"\\") {
|
||||||
let txt1 = ctx['state'].val;
|
let txt1 = ctx['state'].val;
|
||||||
const b3 = comp1({slots: markRaw({'footer': {__render: slot1.bind(this), __ctx: ctx}})}, key + \`__1\`, node, this, null);
|
const ctx1 = capture(ctx);
|
||||||
|
const b3 = comp1({slots: markRaw({'footer': {__render: slot1.bind(this), __ctx: ctx1}})}, key + \`__1\`, node, this, null);
|
||||||
return block1([txt1], [b3]);
|
return block1([txt1], [b3]);
|
||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
@@ -2779,7 +2764,7 @@ exports[`slots t-debug on a t-set-slot (defining a slot) 1`] = `
|
|||||||
"function anonymous(app, bdom, helpers
|
"function anonymous(app, bdom, helpers
|
||||||
) {
|
) {
|
||||||
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
||||||
let { markRaw } = helpers;
|
let { capture, markRaw } = helpers;
|
||||||
const comp1 = app.createComponent(\`Dialog\`, true, true, false, []);
|
const comp1 = app.createComponent(\`Dialog\`, true, true, false, []);
|
||||||
|
|
||||||
let block1 = createBlock(\`<div><block-child-0/></div>\`);
|
let block1 = createBlock(\`<div><block-child-0/></div>\`);
|
||||||
@@ -2790,7 +2775,8 @@ exports[`slots t-debug on a t-set-slot (defining a slot) 1`] = `
|
|||||||
}
|
}
|
||||||
|
|
||||||
return function template(ctx, node, key = \\"\\") {
|
return function template(ctx, node, key = \\"\\") {
|
||||||
const b3 = comp1({slots: markRaw({'content': {__render: slot1.bind(this), __ctx: ctx}})}, key + \`__1\`, node, this, null);
|
const ctx1 = capture(ctx);
|
||||||
|
const b3 = comp1({slots: markRaw({'content': {__render: slot1.bind(this), __ctx: ctx1}})}, key + \`__1\`, node, this, null);
|
||||||
return block1([], [b3]);
|
return block1([], [b3]);
|
||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
@@ -2850,40 +2836,11 @@ exports[`slots t-set t-value in a slot 2`] = `
|
|||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`slots t-set-slot doesn't cause context to be captured 1`] = `
|
|
||||||
"function anonymous(app, bdom, helpers
|
|
||||||
) {
|
|
||||||
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
|
||||||
let { markRaw } = helpers;
|
|
||||||
const comp1 = app.createComponent(\`Child\`, true, true, false, []);
|
|
||||||
|
|
||||||
function slot1(ctx, node, key = \\"\\") {
|
|
||||||
return text(ctx['someVal']);
|
|
||||||
}
|
|
||||||
|
|
||||||
return function template(ctx, node, key = \\"\\") {
|
|
||||||
return comp1({slots: markRaw({'default': {__render: slot1.bind(this), __ctx: ctx}})}, key + \`__1\`, node, this, null);
|
|
||||||
}
|
|
||||||
}"
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`slots t-set-slot doesn't cause context to be captured 2`] = `
|
|
||||||
"function anonymous(app, bdom, helpers
|
|
||||||
) {
|
|
||||||
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
|
||||||
let { callSlot } = helpers;
|
|
||||||
|
|
||||||
return function template(ctx, node, key = \\"\\") {
|
|
||||||
return callSlot(ctx, node, key, 'default', false, {});
|
|
||||||
}
|
|
||||||
}"
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`slots t-set-slot=default has priority over rest of the content 1`] = `
|
exports[`slots t-set-slot=default has priority over rest of the content 1`] = `
|
||||||
"function anonymous(app, bdom, helpers
|
"function anonymous(app, bdom, helpers
|
||||||
) {
|
) {
|
||||||
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
||||||
let { markRaw } = helpers;
|
let { capture, markRaw } = helpers;
|
||||||
const comp1 = app.createComponent(\`Child\`, true, true, false, []);
|
const comp1 = app.createComponent(\`Child\`, true, true, false, []);
|
||||||
|
|
||||||
function slot1(ctx, node, key = \\"\\") {
|
function slot1(ctx, node, key = \\"\\") {
|
||||||
@@ -2891,7 +2848,8 @@ exports[`slots t-set-slot=default has priority over rest of the content 1`] = `
|
|||||||
}
|
}
|
||||||
|
|
||||||
return function template(ctx, node, key = \\"\\") {
|
return function template(ctx, node, key = \\"\\") {
|
||||||
return comp1({slots: markRaw({'default': {__render: slot1.bind(this), __ctx: ctx}})}, key + \`__1\`, node, this, null);
|
const ctx1 = capture(ctx);
|
||||||
|
return comp1({slots: markRaw({'default': {__render: slot1.bind(this), __ctx: ctx1}})}, key + \`__1\`, node, this, null);
|
||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -153,7 +153,7 @@ exports[`list of components order is correct when slots are not of same type 1`]
|
|||||||
"function anonymous(app, bdom, helpers
|
"function anonymous(app, bdom, helpers
|
||||||
) {
|
) {
|
||||||
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
||||||
let { markRaw } = helpers;
|
let { capture, markRaw } = helpers;
|
||||||
const comp1 = app.createComponent(\`Child\`, true, true, false, []);
|
const comp1 = app.createComponent(\`Child\`, true, true, false, []);
|
||||||
|
|
||||||
let block2 = createBlock(\`<div>A</div>\`);
|
let block2 = createBlock(\`<div>A</div>\`);
|
||||||
@@ -175,7 +175,8 @@ exports[`list of components order is correct when slots are not of same type 1`]
|
|||||||
}
|
}
|
||||||
|
|
||||||
return function template(ctx, node, key = \\"\\") {
|
return function template(ctx, node, key = \\"\\") {
|
||||||
return comp1({slots: markRaw({'a': {__render: slot1.bind(this), __ctx: ctx, active: !ctx['state'].active}, 'b': {__render: slot2.bind(this), __ctx: ctx, active: true}, 'c': {__render: slot3.bind(this), __ctx: ctx, active: ctx['state'].active}})}, key + \`__1\`, node, this, null);
|
const ctx1 = capture(ctx);
|
||||||
|
return comp1({slots: markRaw({'a': {__render: slot1.bind(this), __ctx: ctx1, active: !ctx['state'].active}, 'b': {__render: slot2.bind(this), __ctx: ctx1, active: true}, 'c': {__render: slot3.bind(this), __ctx: ctx1, active: ctx['state'].active}})}, key + \`__1\`, node, this, null);
|
||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -44,26 +44,7 @@ exports[`t-model directive .trim modifier 1`] = `
|
|||||||
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
||||||
let { toNumber } = helpers;
|
let { toNumber } = helpers;
|
||||||
|
|
||||||
let block1 = createBlock(\`<div><input block-property-0=\\"value\\" block-handler-1=\\"change\\"/><span><block-text-2/></span></div>\`);
|
let block1 = createBlock(\`<div><input block-property-0=\\"value\\" block-handler-1=\\"input\\"/><span><block-text-2/></span></div>\`);
|
||||||
|
|
||||||
return function template(ctx, node, key = \\"\\") {
|
|
||||||
const bExpr1 = ctx['state'];
|
|
||||||
const expr1 = 'text';
|
|
||||||
let prop1 = bExpr1[expr1];
|
|
||||||
let hdlr1 = [(ev) => { bExpr1[expr1] = ev.target.value.trim(); }];
|
|
||||||
let txt1 = ctx['state'].text;
|
|
||||||
return block1([prop1, hdlr1, txt1]);
|
|
||||||
}
|
|
||||||
}"
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`t-model directive .trim modifier implies .lazy modifier 1`] = `
|
|
||||||
"function anonymous(app, bdom, helpers
|
|
||||||
) {
|
|
||||||
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
|
||||||
let { toNumber } = helpers;
|
|
||||||
|
|
||||||
let block1 = createBlock(\`<div><input block-property-0=\\"value\\" block-handler-1=\\"change\\"/><span><block-text-2/></span></div>\`);
|
|
||||||
|
|
||||||
return function template(ctx, node, key = \\"\\") {
|
return function template(ctx, node, key = \\"\\") {
|
||||||
const bExpr1 = ctx['state'];
|
const bExpr1 = ctx['state'];
|
||||||
|
|||||||
@@ -386,7 +386,7 @@ exports[`t-on t-on on t-set-slots 1`] = `
|
|||||||
"function anonymous(app, bdom, helpers
|
"function anonymous(app, bdom, helpers
|
||||||
) {
|
) {
|
||||||
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
|
||||||
let { createCatcher, markRaw } = helpers;
|
let { capture, createCatcher, markRaw } = helpers;
|
||||||
const catcher1 = createCatcher({\\"click\\":0});
|
const catcher1 = createCatcher({\\"click\\":0});
|
||||||
const comp1 = app.createComponent(\`Child\`, true, true, false, []);
|
const comp1 = app.createComponent(\`Child\`, true, true, false, []);
|
||||||
|
|
||||||
@@ -405,7 +405,8 @@ exports[`t-on t-on on t-set-slots 1`] = `
|
|||||||
const b2 = text(\` [\`);
|
const b2 = text(\` [\`);
|
||||||
const b3 = text(ctx['state'].count);
|
const b3 = text(ctx['state'].count);
|
||||||
const b4 = text(\`] \`);
|
const b4 = text(\`] \`);
|
||||||
const b8 = comp1({slots: markRaw({'myslot': {__render: slot1.bind(this), __ctx: ctx}})}, key + \`__1\`, node, this, null);
|
const ctx1 = capture(ctx);
|
||||||
|
const b8 = comp1({slots: markRaw({'myslot': {__render: slot1.bind(this), __ctx: ctx1}})}, key + \`__1\`, node, this, null);
|
||||||
return multi([b2, b3, b4, b8]);
|
return multi([b2, b3, b4, b8]);
|
||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
|
|||||||
@@ -76,8 +76,9 @@ describe("basics", () => {
|
|||||||
}
|
}
|
||||||
const app = new App(Parent);
|
const app = new App(Parent);
|
||||||
let error: Error;
|
let error: Error;
|
||||||
|
const appError = nextAppError(app);
|
||||||
const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
||||||
await expect(nextAppError(app)).resolves.toThrow(
|
await expect(appError).resolves.toThrow(
|
||||||
'Cannot find the definition of component "SomeMispelledComponent"'
|
'Cannot find the definition of component "SomeMispelledComponent"'
|
||||||
);
|
);
|
||||||
await mountProm;
|
await mountProm;
|
||||||
@@ -96,8 +97,9 @@ describe("basics", () => {
|
|||||||
}
|
}
|
||||||
const app = new App(Parent, { test: true });
|
const app = new App(Parent, { test: true });
|
||||||
let error: Error;
|
let error: Error;
|
||||||
|
const appError = nextAppError(app);
|
||||||
const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
||||||
await expect(nextAppError(app)).resolves.toThrow(
|
await expect(appError).resolves.toThrow(
|
||||||
'Cannot find the definition of component "SomeMispelledComponent"'
|
'Cannot find the definition of component "SomeMispelledComponent"'
|
||||||
);
|
);
|
||||||
await mountProm;
|
await mountProm;
|
||||||
@@ -116,8 +118,9 @@ describe("basics", () => {
|
|||||||
}
|
}
|
||||||
const app = new App(Parent as typeof Component);
|
const app = new App(Parent as typeof Component);
|
||||||
let error: Error;
|
let error: Error;
|
||||||
|
const appError = nextAppError(app);
|
||||||
const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
||||||
await expect(nextAppError(app)).resolves.toThrow(
|
await expect(appError).resolves.toThrow(
|
||||||
'"SomeComponent" is not a Component. It must inherit from the Component class'
|
'"SomeComponent" is not a Component. It must inherit from the Component class'
|
||||||
);
|
);
|
||||||
await mountProm;
|
await mountProm;
|
||||||
@@ -133,8 +136,9 @@ describe("basics", () => {
|
|||||||
}
|
}
|
||||||
const app = new App(Parent as typeof Component);
|
const app = new App(Parent as typeof Component);
|
||||||
let error: Error;
|
let error: Error;
|
||||||
|
const appError = nextAppError(app);
|
||||||
const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
||||||
await expect(nextAppError(app)).resolves.toThrow(
|
await expect(appError).resolves.toThrow(
|
||||||
'Cannot find the definition of component "MissingChild", missing static components key in parent'
|
'Cannot find the definition of component "MissingChild", missing static components key in parent'
|
||||||
);
|
);
|
||||||
await mountProm;
|
await mountProm;
|
||||||
@@ -197,8 +201,9 @@ function(app, bdom, helpers) {
|
|||||||
}`;
|
}`;
|
||||||
const app = new App(Parent as typeof Component);
|
const app = new App(Parent as typeof Component);
|
||||||
let error: Error;
|
let error: Error;
|
||||||
|
const appError = nextAppError(app);
|
||||||
const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
||||||
await expect(nextAppError(app)).resolves.toThrow(expectedErrorMessage);
|
await expect(appError).resolves.toThrow(expectedErrorMessage);
|
||||||
await mountProm;
|
await mountProm;
|
||||||
expect(error!).toBeDefined();
|
expect(error!).toBeDefined();
|
||||||
expect(error!.message).toBe(expectedErrorMessage);
|
expect(error!.message).toBe(expectedErrorMessage);
|
||||||
@@ -244,8 +249,9 @@ describe("errors and promises", () => {
|
|||||||
|
|
||||||
const app = new App(Root);
|
const app = new App(Root);
|
||||||
let error: OwlError;
|
let error: OwlError;
|
||||||
|
const appError = nextAppError(app);
|
||||||
const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
||||||
await expect(nextAppError(app)).resolves.toThrow("error occured in the owl lifecycle");
|
await expect(appError).resolves.toThrow("error occured in the owl lifecycle");
|
||||||
await mountProm;
|
await mountProm;
|
||||||
expect(error!).toBeDefined();
|
expect(error!).toBeDefined();
|
||||||
expect(error!.cause).toBeDefined();
|
expect(error!.cause).toBeDefined();
|
||||||
@@ -268,8 +274,9 @@ describe("errors and promises", () => {
|
|||||||
|
|
||||||
const app = new App(Root);
|
const app = new App(Root);
|
||||||
let error: OwlError;
|
let error: OwlError;
|
||||||
|
const appError = nextAppError(app);
|
||||||
const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
||||||
await expect(nextAppError(app)).resolves.toThrow("error occured in the owl lifecycle");
|
await expect(appError).resolves.toThrow("error occured in the owl lifecycle");
|
||||||
await mountProm;
|
await mountProm;
|
||||||
expect(error!).toBeDefined();
|
expect(error!).toBeDefined();
|
||||||
expect(error!.cause).toBeDefined();
|
expect(error!.cause).toBeDefined();
|
||||||
@@ -291,8 +298,9 @@ describe("errors and promises", () => {
|
|||||||
|
|
||||||
const app = new App(Root, { test: true });
|
const app = new App(Root, { test: true });
|
||||||
let error: OwlError;
|
let error: OwlError;
|
||||||
|
const appError = nextAppError(app);
|
||||||
const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
||||||
await expect(nextAppError(app)).resolves.toThrow("error occurred in onMounted");
|
await expect(appError).resolves.toThrow("error occurred in onMounted");
|
||||||
await mountProm;
|
await mountProm;
|
||||||
expect(error!).toBeDefined();
|
expect(error!).toBeDefined();
|
||||||
expect(error!.stack).toContain("Root.setup");
|
expect(error!.stack).toContain("Root.setup");
|
||||||
@@ -317,8 +325,9 @@ describe("errors and promises", () => {
|
|||||||
|
|
||||||
const app = new App(Root, { test: true });
|
const app = new App(Root, { test: true });
|
||||||
let error: OwlError;
|
let error: OwlError;
|
||||||
|
const appError = nextAppError(app);
|
||||||
const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
||||||
await expect(nextAppError(app)).resolves.toThrow("error occurred in onWillRender");
|
await expect(appError).resolves.toThrow("error occurred in onWillRender");
|
||||||
await mountProm;
|
await mountProm;
|
||||||
expect(error!).toBeDefined();
|
expect(error!).toBeDefined();
|
||||||
expect(error!.message).toBe(
|
expect(error!.message).toBe(
|
||||||
@@ -358,8 +367,9 @@ describe("errors and promises", () => {
|
|||||||
|
|
||||||
const app = new App(Root, { test: true });
|
const app = new App(Root, { test: true });
|
||||||
let error: OwlError;
|
let error: OwlError;
|
||||||
|
const appError = nextAppError(app);
|
||||||
const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
||||||
await expect(nextAppError(app)).resolves.toThrow("error occurred in onWillStart");
|
await expect(appError).resolves.toThrow("error occurred in onWillStart");
|
||||||
await mountProm;
|
await mountProm;
|
||||||
expect(error!).toBeDefined();
|
expect(error!).toBeDefined();
|
||||||
expect(error!.message).toBe(
|
expect(error!.message).toBe(
|
||||||
@@ -426,8 +436,9 @@ describe("errors and promises", () => {
|
|||||||
|
|
||||||
const app = new App(Parent);
|
const app = new App(Parent);
|
||||||
let error: OwlError;
|
let error: OwlError;
|
||||||
|
const appError = nextAppError(app);
|
||||||
const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
||||||
await expect(nextAppError(app)).resolves.toThrow("error occured in the owl lifecycle");
|
await expect(appError).resolves.toThrow("error occured in the owl lifecycle");
|
||||||
await mountProm;
|
await mountProm;
|
||||||
expect(error!).toBeDefined();
|
expect(error!).toBeDefined();
|
||||||
expect(error!.cause).toBeDefined();
|
expect(error!.cause).toBeDefined();
|
||||||
@@ -472,8 +483,9 @@ describe("errors and promises", () => {
|
|||||||
|
|
||||||
const app = new App(Parent);
|
const app = new App(Parent);
|
||||||
let error: OwlError;
|
let error: OwlError;
|
||||||
|
const appError = nextAppError(app);
|
||||||
const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
||||||
await expect(nextAppError(app)).resolves.toThrow("error occured in the owl lifecycle");
|
await expect(appError).resolves.toThrow("error occured in the owl lifecycle");
|
||||||
await mountProm;
|
await mountProm;
|
||||||
expect(error!).toBeDefined();
|
expect(error!).toBeDefined();
|
||||||
expect(error!.cause).toBeDefined();
|
expect(error!.cause).toBeDefined();
|
||||||
@@ -502,8 +514,9 @@ describe("errors and promises", () => {
|
|||||||
|
|
||||||
const app = new App(Example, { test: true });
|
const app = new App(Example, { test: true });
|
||||||
let error: OwlError;
|
let error: OwlError;
|
||||||
|
const appError = nextAppError(app);
|
||||||
const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
||||||
await expect(nextAppError(app)).resolves.toThrow("error occurred in onMounted");
|
await expect(appError).resolves.toThrow("error occurred in onMounted");
|
||||||
await mountProm;
|
await mountProm;
|
||||||
expect(error!.message).toBe(`The following error occurred in onMounted: "Error in mounted"`);
|
expect(error!.message).toBe(`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
|
||||||
@@ -577,9 +590,9 @@ describe("can catch errors", () => {
|
|||||||
}
|
}
|
||||||
const app = new App(Root, { test: true });
|
const app = new App(Root, { test: true });
|
||||||
let error: OwlError;
|
let error: OwlError;
|
||||||
const crashProm = expect(nextAppError(app)).resolves.toThrow("error occurred in onWillStart");
|
const appError = nextAppError(app);
|
||||||
await app.mount(fixture).catch((e: Error) => (error = e));
|
await app.mount(fixture).catch((e: Error) => (error = e));
|
||||||
await crashProm;
|
await expect(appError).resolves.toThrow("error occurred in onWillStart");
|
||||||
expect(error!.message).toBe(
|
expect(error!.message).toBe(
|
||||||
`The following error occurred in onWillStart: "No active component (a hook function should only be called in 'setup')"`
|
`The following error occurred in onWillStart: "No active component (a hook function should only be called in 'setup')"`
|
||||||
);
|
);
|
||||||
@@ -599,8 +612,9 @@ describe("can catch errors", () => {
|
|||||||
}
|
}
|
||||||
const app = new App(Root, { test: true });
|
const app = new App(Root, { test: true });
|
||||||
let error: OwlError;
|
let error: OwlError;
|
||||||
|
const appError = nextAppError(app);
|
||||||
const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
||||||
await expect(nextAppError(app)).resolves.toThrow("error occurred in onMounted");
|
await expect(appError).resolves.toThrow("error occurred in onMounted");
|
||||||
await mountProm;
|
await mountProm;
|
||||||
expect(error!.message).toBe(`The following error occurred in onMounted: "test error"`);
|
expect(error!.message).toBe(`The following error occurred in onMounted: "test error"`);
|
||||||
expect(error!.cause).toBe(err);
|
expect(error!.cause).toBe(err);
|
||||||
@@ -621,8 +635,9 @@ describe("can catch errors", () => {
|
|||||||
}
|
}
|
||||||
const app = new App(Root, { test: true });
|
const app = new App(Root, { test: true });
|
||||||
let error: OwlError;
|
let error: OwlError;
|
||||||
|
const appError = nextAppError(app);
|
||||||
const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
||||||
await expect(nextAppError(app)).resolves.toThrow("error occurred in onWillStart");
|
await expect(appError).resolves.toThrow("error occurred in onWillStart");
|
||||||
await mountProm;
|
await mountProm;
|
||||||
expect(error!.message).toBe(`The following error occurred in onWillStart: "test error"`);
|
expect(error!.message).toBe(`The following error occurred in onWillStart: "test error"`);
|
||||||
expect(error!.cause).toBe(err);
|
expect(error!.cause).toBe(err);
|
||||||
@@ -642,8 +657,9 @@ describe("can catch errors", () => {
|
|||||||
}
|
}
|
||||||
const app = new App(Root);
|
const app = new App(Root);
|
||||||
let error: OwlError;
|
let error: OwlError;
|
||||||
|
const appError = nextAppError(app);
|
||||||
const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
||||||
await expect(nextAppError(app)).resolves.toThrow("error occured in the owl lifecycle");
|
await expect(appError).resolves.toThrow("error occured in the owl lifecycle");
|
||||||
await mountProm;
|
await mountProm;
|
||||||
expect(error!.message).toBe(
|
expect(error!.message).toBe(
|
||||||
`An error occured in the owl lifecycle (see this Error's "cause" property)`
|
`An error occured in the owl lifecycle (see this Error's "cause" property)`
|
||||||
@@ -666,8 +682,9 @@ describe("can catch errors", () => {
|
|||||||
}
|
}
|
||||||
const app = new App(Root);
|
const app = new App(Root);
|
||||||
let error: OwlError;
|
let error: OwlError;
|
||||||
|
const appError = nextAppError(app);
|
||||||
const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
||||||
await expect(nextAppError(app)).resolves.toThrow("error occured in the owl lifecycle");
|
await expect(appError).resolves.toThrow("error occured in the owl lifecycle");
|
||||||
await mountProm;
|
await mountProm;
|
||||||
expect(error!.message).toBe(
|
expect(error!.message).toBe(
|
||||||
`An error occured in the owl lifecycle (see this Error's "cause" property)`
|
`An error occured in the owl lifecycle (see this Error's "cause" property)`
|
||||||
@@ -688,8 +705,9 @@ describe("can catch errors", () => {
|
|||||||
}
|
}
|
||||||
const app = new App(Root, { test: true });
|
const app = new App(Root, { test: true });
|
||||||
let error: OwlError;
|
let error: OwlError;
|
||||||
|
const appError = nextAppError(app);
|
||||||
const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
||||||
await expect(nextAppError(app)).resolves.toThrow("not an Error was thrown in onMounted");
|
await expect(appError).resolves.toThrow("not an Error was thrown in onMounted");
|
||||||
await mountProm;
|
await mountProm;
|
||||||
expect(error!.message).toBe(
|
expect(error!.message).toBe(
|
||||||
`Something that is not an Error was thrown in onMounted (see this Error's "cause" property)`
|
`Something that is not an Error was thrown in onMounted (see this Error's "cause" property)`
|
||||||
@@ -710,8 +728,9 @@ describe("can catch errors", () => {
|
|||||||
}
|
}
|
||||||
const app = new App(Root);
|
const app = new App(Root);
|
||||||
let error: OwlError;
|
let error: OwlError;
|
||||||
|
const appError = nextAppError(app);
|
||||||
const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
||||||
await expect(nextAppError(app)).resolves.toThrow("error occured in the owl lifecycle");
|
await expect(appError).resolves.toThrow("error occured in the owl lifecycle");
|
||||||
await mountProm;
|
await mountProm;
|
||||||
expect(error!.message).toBe(
|
expect(error!.message).toBe(
|
||||||
`An error occured in the owl lifecycle (see this Error's "cause" property)`
|
`An error occured in the owl lifecycle (see this Error's "cause" property)`
|
||||||
@@ -956,13 +975,13 @@ describe("can catch errors", () => {
|
|||||||
"Root:willRender",
|
"Root:willRender",
|
||||||
"ErrorBoundary:setup",
|
"ErrorBoundary:setup",
|
||||||
"ErrorBoundary:willStart",
|
"ErrorBoundary:willStart",
|
||||||
"Root:rendered",
|
|
||||||
"ErrorBoundary:willRender",
|
"ErrorBoundary:willRender",
|
||||||
"ErrorComponent:setup",
|
"ErrorComponent:setup",
|
||||||
"ErrorComponent:willStart",
|
"ErrorComponent:willStart",
|
||||||
"ErrorBoundary:rendered",
|
|
||||||
"ErrorComponent:willRender",
|
"ErrorComponent:willRender",
|
||||||
"ErrorComponent:rendered",
|
"ErrorComponent:rendered",
|
||||||
|
"ErrorBoundary:rendered",
|
||||||
|
"Root:rendered",
|
||||||
"ErrorComponent:mounted",
|
"ErrorComponent:mounted",
|
||||||
"boom",
|
"boom",
|
||||||
"ErrorBoundary:willRender",
|
"ErrorBoundary:willRender",
|
||||||
@@ -1008,9 +1027,9 @@ describe("can catch errors", () => {
|
|||||||
"Root:willRender",
|
"Root:willRender",
|
||||||
"ErrorComponent:setup",
|
"ErrorComponent:setup",
|
||||||
"ErrorComponent:willStart",
|
"ErrorComponent:willStart",
|
||||||
"Root:rendered",
|
|
||||||
"ErrorComponent:willRender",
|
"ErrorComponent:willRender",
|
||||||
"ErrorComponent:rendered",
|
"ErrorComponent:rendered",
|
||||||
|
"Root:rendered",
|
||||||
"ErrorComponent:mounted",
|
"ErrorComponent:mounted",
|
||||||
"boom",
|
"boom",
|
||||||
"Root:willRender",
|
"Root:willRender",
|
||||||
@@ -1071,17 +1090,17 @@ describe("can catch errors", () => {
|
|||||||
"A:willRender",
|
"A:willRender",
|
||||||
"B:setup",
|
"B:setup",
|
||||||
"B:willStart",
|
"B:willStart",
|
||||||
"A:rendered",
|
|
||||||
"B:willRender",
|
"B:willRender",
|
||||||
"C:setup",
|
"C:setup",
|
||||||
"C:willStart",
|
"C:willStart",
|
||||||
"B:rendered",
|
|
||||||
"C:willRender",
|
"C:willRender",
|
||||||
"Boom:setup",
|
"Boom:setup",
|
||||||
"Boom:willStart",
|
"Boom:willStart",
|
||||||
"C:rendered",
|
|
||||||
"Boom:willRender",
|
"Boom:willRender",
|
||||||
"Boom:rendered",
|
"Boom:rendered",
|
||||||
|
"C:rendered",
|
||||||
|
"B:rendered",
|
||||||
|
"A:rendered",
|
||||||
"Boom:mounted",
|
"Boom:mounted",
|
||||||
"boom",
|
"boom",
|
||||||
"C:willRender",
|
"C:willRender",
|
||||||
@@ -1144,17 +1163,17 @@ describe("can catch errors", () => {
|
|||||||
"Root:willRender",
|
"Root:willRender",
|
||||||
"OK:setup",
|
"OK:setup",
|
||||||
"OK:willStart",
|
"OK:willStart",
|
||||||
"ErrorBoundary:setup",
|
|
||||||
"ErrorBoundary:willStart",
|
|
||||||
"Root:rendered",
|
|
||||||
"OK:willRender",
|
"OK:willRender",
|
||||||
"OK:rendered",
|
"OK:rendered",
|
||||||
|
"ErrorBoundary:setup",
|
||||||
|
"ErrorBoundary:willStart",
|
||||||
"ErrorBoundary:willRender",
|
"ErrorBoundary:willRender",
|
||||||
"ErrorComponent:setup",
|
"ErrorComponent:setup",
|
||||||
"ErrorComponent:willStart",
|
"ErrorComponent:willStart",
|
||||||
"ErrorBoundary:rendered",
|
|
||||||
"ErrorComponent:willRender",
|
"ErrorComponent:willRender",
|
||||||
"ErrorComponent:rendered",
|
"ErrorComponent:rendered",
|
||||||
|
"ErrorBoundary:rendered",
|
||||||
|
"Root:rendered",
|
||||||
"ErrorComponent:mounted",
|
"ErrorComponent:mounted",
|
||||||
"boom",
|
"boom",
|
||||||
"ErrorBoundary:willRender",
|
"ErrorBoundary:willRender",
|
||||||
@@ -1497,9 +1516,9 @@ describe("can catch errors", () => {
|
|||||||
"Parent:willRender",
|
"Parent:willRender",
|
||||||
"Child:setup",
|
"Child:setup",
|
||||||
"Child:willStart",
|
"Child:willStart",
|
||||||
"Parent:rendered",
|
|
||||||
"Child:willRender",
|
"Child:willRender",
|
||||||
"Child:rendered",
|
"Child:rendered",
|
||||||
|
"Parent:rendered",
|
||||||
"Child:mounted",
|
"Child:mounted",
|
||||||
"Parent:mounted",
|
"Parent:mounted",
|
||||||
]
|
]
|
||||||
@@ -1576,9 +1595,9 @@ describe("can catch errors", () => {
|
|||||||
"Parent:willRender",
|
"Parent:willRender",
|
||||||
"Child:setup",
|
"Child:setup",
|
||||||
"Child:willStart",
|
"Child:willStart",
|
||||||
"Parent:rendered",
|
|
||||||
"Child:willRender",
|
"Child:willRender",
|
||||||
"Child:rendered",
|
"Child:rendered",
|
||||||
|
"Parent:rendered",
|
||||||
]
|
]
|
||||||
`);
|
`);
|
||||||
parent.state.hasChild = false;
|
parent.state.hasChild = false;
|
||||||
|
|||||||
@@ -641,56 +641,6 @@ describe("hooks", () => {
|
|||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("effect types are inferred from dependencies", async () => {
|
|
||||||
// @ts-ignore (declared but never used)
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
||||||
class MyComponent extends Component {
|
|
||||||
static template = xml`<div/>`;
|
|
||||||
|
|
||||||
setup() {
|
|
||||||
useEffect(
|
|
||||||
(a, b) => {
|
|
||||||
expectType<number>(a);
|
|
||||||
expectType<string>(b);
|
|
||||||
},
|
|
||||||
() => [3, "hello"]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
test("effect type allows an effect with partial dependencies parameters", async () => {
|
|
||||||
// @ts-ignore (declared but never used)
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
||||||
class MyComponent extends Component {
|
|
||||||
static template = xml`<div/>`;
|
|
||||||
|
|
||||||
setup() {
|
|
||||||
useEffect(
|
|
||||||
(a) => {
|
|
||||||
expectType<number>(a);
|
|
||||||
},
|
|
||||||
() => [3, "hello"]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
test("effect type allows an effect with no dependency parameter", async () => {
|
|
||||||
// @ts-ignore (declared but never used)
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
||||||
class MyComponent extends Component {
|
|
||||||
static template = xml`<div/>`;
|
|
||||||
|
|
||||||
setup() {
|
|
||||||
useEffect(
|
|
||||||
() => {},
|
|
||||||
() => [3, "hello"]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
test("properly behaves when the effect function throws", async () => {
|
test("properly behaves when the effect function throws", async () => {
|
||||||
let originalconsoleError = console.error;
|
let originalconsoleError = console.error;
|
||||||
let originalconsoleWarn = console.warn;
|
let originalconsoleWarn = console.warn;
|
||||||
@@ -710,8 +660,9 @@ describe("hooks", () => {
|
|||||||
|
|
||||||
let error: OwlError;
|
let error: OwlError;
|
||||||
const app = new App(MyComponent);
|
const app = new App(MyComponent);
|
||||||
|
const appError = nextAppError(app);
|
||||||
const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
||||||
await expect(nextAppError(app)).resolves.toThrow("error occured in the owl lifecycle");
|
await expect(appError).resolves.toThrow("error occured in the owl lifecycle");
|
||||||
await mountProm;
|
await mountProm;
|
||||||
expect(error!.cause.message).toBe("Intentional error");
|
expect(error!.cause.message).toBe("Intentional error");
|
||||||
// no console.error because the error has been caught in this test
|
// no console.error because the error has been caught in this test
|
||||||
@@ -723,5 +674,3 @@ describe("hooks", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
function expectType<T>(t: T) {}
|
|
||||||
|
|||||||
@@ -342,15 +342,16 @@ describe("lifecycle hooks", () => {
|
|||||||
parent.state.n = 2;
|
parent.state.n = 2;
|
||||||
await nextTick();
|
await nextTick();
|
||||||
app.destroy();
|
app.destroy();
|
||||||
expect(steps).toEqual([
|
expect(steps.splice(0)).toMatchInlineSnapshot(`
|
||||||
"parent:willPatch",
|
Array [
|
||||||
"child:willPatch",
|
"parent:willPatch",
|
||||||
"childchild:willPatch",
|
"childchild:willPatch",
|
||||||
"childchild:patched",
|
"child:willPatch",
|
||||||
"child:patched",
|
"child:patched",
|
||||||
"parent:patched",
|
"childchild:patched",
|
||||||
]);
|
"parent:patched",
|
||||||
Object.freeze(steps);
|
]
|
||||||
|
`);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("willStart, mounted on subwidget rendered after main is mounted in some other position", async () => {
|
test("willStart, mounted on subwidget rendered after main is mounted in some other position", async () => {
|
||||||
@@ -463,9 +464,9 @@ describe("lifecycle hooks", () => {
|
|||||||
"Parent:willRender",
|
"Parent:willRender",
|
||||||
"Child:setup",
|
"Child:setup",
|
||||||
"Child:willStart",
|
"Child:willStart",
|
||||||
"Parent:rendered",
|
|
||||||
"Child:willRender",
|
"Child:willRender",
|
||||||
"Child:rendered",
|
"Child:rendered",
|
||||||
|
"Parent:rendered",
|
||||||
"Child:mounted",
|
"Child:mounted",
|
||||||
"Parent:mounted",
|
"Parent:mounted",
|
||||||
]
|
]
|
||||||
@@ -478,9 +479,9 @@ describe("lifecycle hooks", () => {
|
|||||||
Array [
|
Array [
|
||||||
"Parent:willRender",
|
"Parent:willRender",
|
||||||
"Child:willUpdateProps",
|
"Child:willUpdateProps",
|
||||||
"Parent:rendered",
|
|
||||||
"Child:willRender",
|
"Child:willRender",
|
||||||
"Child:rendered",
|
"Child:rendered",
|
||||||
|
"Parent:rendered",
|
||||||
"Parent:willPatch",
|
"Parent:willPatch",
|
||||||
"Child:willPatch",
|
"Child:willPatch",
|
||||||
"Child:patched",
|
"Child:patched",
|
||||||
@@ -528,9 +529,9 @@ describe("lifecycle hooks", () => {
|
|||||||
"Parent:willRender",
|
"Parent:willRender",
|
||||||
"Child:setup",
|
"Child:setup",
|
||||||
"Child:willStart",
|
"Child:willStart",
|
||||||
"Parent:rendered",
|
|
||||||
"Child:willRender",
|
"Child:willRender",
|
||||||
"Child:rendered",
|
"Child:rendered",
|
||||||
|
"Parent:rendered",
|
||||||
"Child:mounted",
|
"Child:mounted",
|
||||||
"Parent:mounted",
|
"Parent:mounted",
|
||||||
]
|
]
|
||||||
@@ -650,9 +651,9 @@ describe("lifecycle hooks", () => {
|
|||||||
"Parent:willRender",
|
"Parent:willRender",
|
||||||
"Child:setup",
|
"Child:setup",
|
||||||
"Child:willStart",
|
"Child:willStart",
|
||||||
"Parent:rendered",
|
|
||||||
"Child:willRender",
|
"Child:willRender",
|
||||||
"Child:rendered",
|
"Child:rendered",
|
||||||
|
"Parent:rendered",
|
||||||
"Child:mounted",
|
"Child:mounted",
|
||||||
"Parent:mounted",
|
"Parent:mounted",
|
||||||
]
|
]
|
||||||
@@ -712,13 +713,13 @@ describe("lifecycle hooks", () => {
|
|||||||
"Parent:willRender",
|
"Parent:willRender",
|
||||||
"Child:setup",
|
"Child:setup",
|
||||||
"Child:willStart",
|
"Child:willStart",
|
||||||
"Parent:rendered",
|
|
||||||
"Child:willRender",
|
"Child:willRender",
|
||||||
"GrandChild:setup",
|
"GrandChild:setup",
|
||||||
"GrandChild:willStart",
|
"GrandChild:willStart",
|
||||||
"Child:rendered",
|
|
||||||
"GrandChild:willRender",
|
"GrandChild:willRender",
|
||||||
"GrandChild:rendered",
|
"GrandChild:rendered",
|
||||||
|
"Child:rendered",
|
||||||
|
"Parent:rendered",
|
||||||
"Parent:willPatch",
|
"Parent:willPatch",
|
||||||
"GrandChild:mounted",
|
"GrandChild:mounted",
|
||||||
"Child:mounted",
|
"Child:mounted",
|
||||||
@@ -834,11 +835,11 @@ describe("lifecycle hooks", () => {
|
|||||||
"Parent:willRender",
|
"Parent:willRender",
|
||||||
"Child:setup",
|
"Child:setup",
|
||||||
"Child:willStart",
|
"Child:willStart",
|
||||||
"Parent:rendered",
|
|
||||||
"Child:willRender",
|
"Child:willRender",
|
||||||
"GrandChild:setup",
|
"GrandChild:setup",
|
||||||
"GrandChild:willStart",
|
"GrandChild:willStart",
|
||||||
"Child:rendered",
|
"Child:rendered",
|
||||||
|
"Parent:rendered",
|
||||||
]
|
]
|
||||||
`);
|
`);
|
||||||
|
|
||||||
@@ -878,9 +879,9 @@ describe("lifecycle hooks", () => {
|
|||||||
"Parent:willRender",
|
"Parent:willRender",
|
||||||
"Child:setup",
|
"Child:setup",
|
||||||
"Child:willStart",
|
"Child:willStart",
|
||||||
"Parent:rendered",
|
|
||||||
"Child:willRender",
|
"Child:willRender",
|
||||||
"Child:rendered",
|
"Child:rendered",
|
||||||
|
"Parent:rendered",
|
||||||
"Child:mounted",
|
"Child:mounted",
|
||||||
"Parent:mounted",
|
"Parent:mounted",
|
||||||
]
|
]
|
||||||
@@ -925,9 +926,9 @@ describe("lifecycle hooks", () => {
|
|||||||
"Parent:willRender",
|
"Parent:willRender",
|
||||||
"Child:setup",
|
"Child:setup",
|
||||||
"Child:willStart",
|
"Child:willStart",
|
||||||
"Parent:rendered",
|
|
||||||
"Child:willRender",
|
"Child:willRender",
|
||||||
"Child:rendered",
|
"Child:rendered",
|
||||||
|
"Parent:rendered",
|
||||||
"Child:mounted",
|
"Child:mounted",
|
||||||
"Parent:mounted",
|
"Parent:mounted",
|
||||||
]
|
]
|
||||||
@@ -939,9 +940,9 @@ describe("lifecycle hooks", () => {
|
|||||||
Array [
|
Array [
|
||||||
"Parent:willRender",
|
"Parent:willRender",
|
||||||
"Child:willUpdateProps",
|
"Child:willUpdateProps",
|
||||||
"Parent:rendered",
|
|
||||||
"Child:willRender",
|
"Child:willRender",
|
||||||
"Child:rendered",
|
"Child:rendered",
|
||||||
|
"Parent:rendered",
|
||||||
"Parent:willPatch",
|
"Parent:willPatch",
|
||||||
"Child:willPatch",
|
"Child:willPatch",
|
||||||
"Child:patched",
|
"Child:patched",
|
||||||
@@ -986,9 +987,9 @@ describe("lifecycle hooks", () => {
|
|||||||
"Parent:willRender",
|
"Parent:willRender",
|
||||||
"Child:setup",
|
"Child:setup",
|
||||||
"Child:willStart",
|
"Child:willStart",
|
||||||
"Parent:rendered",
|
|
||||||
"Child:willRender",
|
"Child:willRender",
|
||||||
"Child:rendered",
|
"Child:rendered",
|
||||||
|
"Parent:rendered",
|
||||||
"Child:mounted",
|
"Child:mounted",
|
||||||
"Parent:mounted",
|
"Parent:mounted",
|
||||||
]
|
]
|
||||||
@@ -1113,21 +1114,21 @@ describe("lifecycle hooks", () => {
|
|||||||
"A:willRender",
|
"A:willRender",
|
||||||
"B:setup",
|
"B:setup",
|
||||||
"B:willStart",
|
"B:willStart",
|
||||||
"C:setup",
|
|
||||||
"C:willStart",
|
|
||||||
"A:rendered",
|
|
||||||
"B:willRender",
|
"B:willRender",
|
||||||
"B:rendered",
|
"B:rendered",
|
||||||
|
"C:setup",
|
||||||
|
"C:willStart",
|
||||||
"C:willRender",
|
"C:willRender",
|
||||||
"D:setup",
|
"D:setup",
|
||||||
"D:willStart",
|
"D:willStart",
|
||||||
"E:setup",
|
|
||||||
"E:willStart",
|
|
||||||
"C:rendered",
|
|
||||||
"D:willRender",
|
"D:willRender",
|
||||||
"D:rendered",
|
"D:rendered",
|
||||||
|
"E:setup",
|
||||||
|
"E:willStart",
|
||||||
"E:willRender",
|
"E:willRender",
|
||||||
"E:rendered",
|
"E:rendered",
|
||||||
|
"C:rendered",
|
||||||
|
"A:rendered",
|
||||||
"E:mounted",
|
"E:mounted",
|
||||||
"D:mounted",
|
"D:mounted",
|
||||||
"C:mounted",
|
"C:mounted",
|
||||||
@@ -1144,9 +1145,9 @@ describe("lifecycle hooks", () => {
|
|||||||
"C:willRender",
|
"C:willRender",
|
||||||
"F:setup",
|
"F:setup",
|
||||||
"F:willStart",
|
"F:willStart",
|
||||||
"C:rendered",
|
|
||||||
"F:willRender",
|
"F:willRender",
|
||||||
"F:rendered",
|
"F:rendered",
|
||||||
|
"C:rendered",
|
||||||
"C:willPatch",
|
"C:willPatch",
|
||||||
"E:willUnmount",
|
"E:willUnmount",
|
||||||
"E:willDestroy",
|
"E:willDestroy",
|
||||||
@@ -1181,9 +1182,9 @@ describe("lifecycle hooks", () => {
|
|||||||
"Parent:willRender",
|
"Parent:willRender",
|
||||||
"Child:setup",
|
"Child:setup",
|
||||||
"Child:willStart",
|
"Child:willStart",
|
||||||
"Parent:rendered",
|
|
||||||
"Child:willRender",
|
"Child:willRender",
|
||||||
"Child:rendered",
|
"Child:rendered",
|
||||||
|
"Parent:rendered",
|
||||||
"Child:mounted",
|
"Child:mounted",
|
||||||
"Parent:mounted",
|
"Parent:mounted",
|
||||||
]
|
]
|
||||||
@@ -1209,9 +1210,9 @@ describe("lifecycle hooks", () => {
|
|||||||
"Parent:willRender",
|
"Parent:willRender",
|
||||||
"Child:setup",
|
"Child:setup",
|
||||||
"Child:willStart",
|
"Child:willStart",
|
||||||
"Parent:rendered",
|
|
||||||
"Child:willRender",
|
"Child:willRender",
|
||||||
"Child:rendered",
|
"Child:rendered",
|
||||||
|
"Parent:rendered",
|
||||||
"Parent:willPatch",
|
"Parent:willPatch",
|
||||||
"Child:mounted",
|
"Child:mounted",
|
||||||
"Parent:patched",
|
"Parent:patched",
|
||||||
@@ -1465,6 +1466,8 @@ describe("lifecycle hooks", () => {
|
|||||||
"Parent:willRender",
|
"Parent:willRender",
|
||||||
"Child:setup",
|
"Child:setup",
|
||||||
"Child:willStart",
|
"Child:willStart",
|
||||||
|
"Child:willRender",
|
||||||
|
"Child:rendered",
|
||||||
"Parent:rendered",
|
"Parent:rendered",
|
||||||
"Parent:willUnmount",
|
"Parent:willUnmount",
|
||||||
"Child:willDestroy",
|
"Child:willDestroy",
|
||||||
|
|||||||
@@ -279,9 +279,9 @@ test("bound functions are considered 'alike'", async () => {
|
|||||||
"Parent:willRender",
|
"Parent:willRender",
|
||||||
"Child:setup",
|
"Child:setup",
|
||||||
"Child:willStart",
|
"Child:willStart",
|
||||||
"Parent:rendered",
|
|
||||||
"Child:willRender",
|
"Child:willRender",
|
||||||
"Child:rendered",
|
"Child:rendered",
|
||||||
|
"Parent:rendered",
|
||||||
"Child:mounted",
|
"Child:mounted",
|
||||||
"Parent:mounted",
|
"Parent:mounted",
|
||||||
]
|
]
|
||||||
@@ -341,9 +341,9 @@ test(".alike suffix in a simple case", async () => {
|
|||||||
"Parent:willRender",
|
"Parent:willRender",
|
||||||
"Child:setup",
|
"Child:setup",
|
||||||
"Child:willStart",
|
"Child:willStart",
|
||||||
"Parent:rendered",
|
|
||||||
"Child:willRender",
|
"Child:willRender",
|
||||||
"Child:rendered",
|
"Child:rendered",
|
||||||
|
"Parent:rendered",
|
||||||
"Child:mounted",
|
"Child:mounted",
|
||||||
"Parent:mounted",
|
"Parent:mounted",
|
||||||
]
|
]
|
||||||
@@ -403,13 +403,13 @@ test(".alike suffix in a list", async () => {
|
|||||||
"Parent:willRender",
|
"Parent:willRender",
|
||||||
"Todo:setup",
|
"Todo:setup",
|
||||||
"Todo:willStart",
|
"Todo:willStart",
|
||||||
|
"Todo:willRender",
|
||||||
|
"Todo:rendered",
|
||||||
"Todo:setup",
|
"Todo:setup",
|
||||||
"Todo:willStart",
|
"Todo:willStart",
|
||||||
|
"Todo:willRender",
|
||||||
|
"Todo:rendered",
|
||||||
"Parent:rendered",
|
"Parent:rendered",
|
||||||
"Todo:willRender",
|
|
||||||
"Todo:rendered",
|
|
||||||
"Todo:willRender",
|
|
||||||
"Todo:rendered",
|
|
||||||
"Todo:mounted",
|
"Todo:mounted",
|
||||||
"Todo:mounted",
|
"Todo:mounted",
|
||||||
"Parent:mounted",
|
"Parent:mounted",
|
||||||
|
|||||||
@@ -51,8 +51,9 @@ describe("props validation", () => {
|
|||||||
|
|
||||||
const app = new App(Parent, { test: true });
|
const app = new App(Parent, { test: true });
|
||||||
let error: OwlError | undefined;
|
let error: OwlError | undefined;
|
||||||
|
const appError = nextAppError(app);
|
||||||
const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
||||||
await expect(nextAppError(app)).resolves.toThrow(
|
await expect(appError).resolves.toThrow(
|
||||||
"Invalid props for component 'SubComp': 'message' is missing"
|
"Invalid props for component 'SubComp': 'message' is missing"
|
||||||
);
|
);
|
||||||
await mountProm;
|
await mountProm;
|
||||||
@@ -80,8 +81,9 @@ describe("props validation", () => {
|
|||||||
|
|
||||||
const app = new App(Parent, { test: true });
|
const app = new App(Parent, { test: true });
|
||||||
let error: OwlError | undefined;
|
let error: OwlError | undefined;
|
||||||
|
const appError = nextAppError(app);
|
||||||
const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
||||||
await expect(nextAppError(app)).resolves.toThrow(
|
await expect(appError).resolves.toThrow(
|
||||||
"Invalid props for component 'SubComp': 'message' is missing"
|
"Invalid props for component 'SubComp': 'message' is missing"
|
||||||
);
|
);
|
||||||
await mountProm;
|
await mountProm;
|
||||||
@@ -131,8 +133,9 @@ describe("props validation", () => {
|
|||||||
props = {};
|
props = {};
|
||||||
let app = new App(Parent, { test: true });
|
let app = new App(Parent, { test: true });
|
||||||
let error: OwlError | undefined;
|
let error: OwlError | undefined;
|
||||||
|
let appError = nextAppError(app);
|
||||||
let mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
let mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
||||||
await expect(nextAppError(app)).resolves.toThrow("Invalid props for component '_a'");
|
await expect(appError).resolves.toThrow("Invalid props for component '_a'");
|
||||||
await mountProm;
|
await mountProm;
|
||||||
expect(error!).toBeDefined();
|
expect(error!).toBeDefined();
|
||||||
expect(error!.message).toBe(
|
expect(error!.message).toBe(
|
||||||
@@ -148,8 +151,9 @@ describe("props validation", () => {
|
|||||||
expect(error!).toBeUndefined();
|
expect(error!).toBeUndefined();
|
||||||
props = { p: test.ko };
|
props = { p: test.ko };
|
||||||
app = new App(Parent, { test: true });
|
app = new App(Parent, { test: true });
|
||||||
|
appError = nextAppError(app);
|
||||||
mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
||||||
await expect(nextAppError(app)).resolves.toThrow("Invalid props for component '_a'");
|
await expect(appError).resolves.toThrow("Invalid props for component '_a'");
|
||||||
await mountProm;
|
await mountProm;
|
||||||
expect(error!).toBeDefined();
|
expect(error!).toBeDefined();
|
||||||
expect(error!.message).toBe(
|
expect(error!.message).toBe(
|
||||||
@@ -183,8 +187,9 @@ describe("props validation", () => {
|
|||||||
props = {};
|
props = {};
|
||||||
let app = new App(Parent, { test: true });
|
let app = new App(Parent, { test: true });
|
||||||
let error: OwlError | undefined;
|
let error: OwlError | undefined;
|
||||||
|
let appError = nextAppError(app);
|
||||||
let mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
let mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
||||||
await expect(nextAppError(app)).resolves.toThrow("Invalid props for component '_a'");
|
await expect(appError).resolves.toThrow("Invalid props for component '_a'");
|
||||||
await mountProm;
|
await mountProm;
|
||||||
expect(error!).toBeDefined();
|
expect(error!).toBeDefined();
|
||||||
expect(error!.message).toBe(
|
expect(error!.message).toBe(
|
||||||
@@ -200,8 +205,9 @@ describe("props validation", () => {
|
|||||||
expect(error!).toBeUndefined();
|
expect(error!).toBeUndefined();
|
||||||
props = { p: test.ko };
|
props = { p: test.ko };
|
||||||
app = new App(Parent, { test: true });
|
app = new App(Parent, { test: true });
|
||||||
|
appError = nextAppError(app);
|
||||||
mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
||||||
await expect(nextAppError(app)).resolves.toThrow("Invalid props for component '_a'");
|
await expect(appError).resolves.toThrow("Invalid props for component '_a'");
|
||||||
await mountProm;
|
await mountProm;
|
||||||
expect(error!).toBeDefined();
|
expect(error!).toBeDefined();
|
||||||
expect(error!.message).toBe(
|
expect(error!.message).toBe(
|
||||||
@@ -240,8 +246,9 @@ describe("props validation", () => {
|
|||||||
expect(error!).toBeUndefined();
|
expect(error!).toBeUndefined();
|
||||||
props = { p: 1 };
|
props = { p: 1 };
|
||||||
const app = new App(Parent, { test: true });
|
const app = new App(Parent, { test: true });
|
||||||
|
const appError = nextAppError(app);
|
||||||
const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
||||||
await expect(nextAppError(app)).resolves.toThrow("Invalid props for component 'SubComp'");
|
await expect(appError).resolves.toThrow("Invalid props for component 'SubComp'");
|
||||||
await mountProm;
|
await mountProm;
|
||||||
expect(error!).toBeDefined();
|
expect(error!).toBeDefined();
|
||||||
expect(error!.message).toBe(
|
expect(error!.message).toBe(
|
||||||
@@ -279,8 +286,9 @@ describe("props validation", () => {
|
|||||||
expect(error!).toBeUndefined();
|
expect(error!).toBeUndefined();
|
||||||
props = { p: 1 };
|
props = { p: 1 };
|
||||||
const app = new App(Parent, { test: true });
|
const app = new App(Parent, { test: true });
|
||||||
|
const appError = nextAppError(app);
|
||||||
const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
||||||
await expect(nextAppError(app)).resolves.toThrow("Invalid props for component 'SubComp'");
|
await expect(appError).resolves.toThrow("Invalid props for component 'SubComp'");
|
||||||
await mountProm;
|
await mountProm;
|
||||||
expect(error!).toBeDefined();
|
expect(error!).toBeDefined();
|
||||||
expect(error!.message).toBe("Invalid props for component 'SubComp': 'p' is not a string");
|
expect(error!.message).toBe("Invalid props for component 'SubComp': 'p' is not a string");
|
||||||
@@ -316,14 +324,16 @@ describe("props validation", () => {
|
|||||||
expect(error!).toBeUndefined();
|
expect(error!).toBeUndefined();
|
||||||
props = { p: [1] };
|
props = { p: [1] };
|
||||||
let app = new App(Parent, { test: true });
|
let app = new App(Parent, { test: true });
|
||||||
|
let appError = nextAppError(app);
|
||||||
let mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
let mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
||||||
await expect(nextAppError(app)).resolves.toThrow("Invalid props for component 'SubComp'");
|
await expect(appError).resolves.toThrow("Invalid props for component 'SubComp'");
|
||||||
await mountProm;
|
await mountProm;
|
||||||
expect(error!).toBeDefined();
|
expect(error!).toBeDefined();
|
||||||
error = undefined;
|
error = undefined;
|
||||||
app = new App(Parent, { test: true });
|
app = new App(Parent, { test: true });
|
||||||
|
appError = nextAppError(app);
|
||||||
mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
||||||
await expect(nextAppError(app)).resolves.toThrow("Invalid props for component 'SubComp'");
|
await expect(appError).resolves.toThrow("Invalid props for component 'SubComp'");
|
||||||
await mountProm;
|
await mountProm;
|
||||||
expect(error!).toBeDefined();
|
expect(error!).toBeDefined();
|
||||||
});
|
});
|
||||||
@@ -365,8 +375,9 @@ describe("props validation", () => {
|
|||||||
expect(error!).toBeUndefined();
|
expect(error!).toBeUndefined();
|
||||||
props = { p: [true, 1] };
|
props = { p: [true, 1] };
|
||||||
const app = new App(Parent, { test: true });
|
const app = new App(Parent, { test: true });
|
||||||
|
const appError = nextAppError(app);
|
||||||
const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
||||||
await expect(nextAppError(app)).resolves.toThrow("Invalid props for component 'SubComp'");
|
await expect(appError).resolves.toThrow("Invalid props for component 'SubComp'");
|
||||||
await mountProm;
|
await mountProm;
|
||||||
expect(error!).toBeDefined();
|
expect(error!).toBeDefined();
|
||||||
expect(error!.message).toBe(
|
expect(error!.message).toBe(
|
||||||
@@ -399,8 +410,9 @@ describe("props validation", () => {
|
|||||||
expect(error!).toBeUndefined();
|
expect(error!).toBeUndefined();
|
||||||
props = { p: { id: 1, url: "url", extra: true } };
|
props = { p: { id: 1, url: "url", extra: true } };
|
||||||
let app = new App(Parent, { test: true });
|
let app = new App(Parent, { test: true });
|
||||||
|
let appError = nextAppError(app);
|
||||||
let mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
let mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
||||||
await expect(nextAppError(app)).resolves.toThrow("Invalid props for component 'SubComp'");
|
await expect(appError).resolves.toThrow("Invalid props for component 'SubComp'");
|
||||||
await mountProm;
|
await mountProm;
|
||||||
expect(error!).toBeDefined();
|
expect(error!).toBeDefined();
|
||||||
expect(error!.message).toBe(
|
expect(error!.message).toBe(
|
||||||
@@ -408,8 +420,9 @@ describe("props validation", () => {
|
|||||||
);
|
);
|
||||||
props = { p: { id: "1", url: "url" } };
|
props = { p: { id: "1", url: "url" } };
|
||||||
app = new App(Parent, { test: true });
|
app = new App(Parent, { test: true });
|
||||||
|
appError = nextAppError(app);
|
||||||
mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
||||||
await expect(nextAppError(app)).resolves.toThrow("Invalid props for component 'SubComp'");
|
await expect(appError).resolves.toThrow("Invalid props for component 'SubComp'");
|
||||||
await mountProm;
|
await mountProm;
|
||||||
expect(error!).toBeDefined();
|
expect(error!).toBeDefined();
|
||||||
expect(error!.message).toBe(
|
expect(error!.message).toBe(
|
||||||
@@ -418,8 +431,9 @@ describe("props validation", () => {
|
|||||||
error = undefined;
|
error = undefined;
|
||||||
props = { p: { id: 1 } };
|
props = { p: { id: 1 } };
|
||||||
app = new App(Parent, { test: true });
|
app = new App(Parent, { test: true });
|
||||||
|
appError = nextAppError(app);
|
||||||
mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
||||||
await expect(nextAppError(app)).resolves.toThrow("Invalid props for component 'SubComp'");
|
await expect(appError).resolves.toThrow("Invalid props for component 'SubComp'");
|
||||||
await mountProm;
|
await mountProm;
|
||||||
expect(error!).toBeDefined();
|
expect(error!).toBeDefined();
|
||||||
expect(error!.message).toBe(
|
expect(error!.message).toBe(
|
||||||
@@ -465,8 +479,9 @@ describe("props validation", () => {
|
|||||||
expect(error!).toBeUndefined();
|
expect(error!).toBeUndefined();
|
||||||
props = { p: { id: 1, url: [12, true] } };
|
props = { p: { id: 1, url: [12, true] } };
|
||||||
const app = new App(Parent, { test: true });
|
const app = new App(Parent, { test: true });
|
||||||
|
const appError = nextAppError(app);
|
||||||
const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
||||||
await expect(nextAppError(app)).resolves.toThrow("Invalid props for component 'SubComp'");
|
await expect(appError).resolves.toThrow("Invalid props for component 'SubComp'");
|
||||||
await mountProm;
|
await mountProm;
|
||||||
expect(error!).toBeDefined();
|
expect(error!).toBeDefined();
|
||||||
expect(error!.message).toBe(
|
expect(error!.message).toBe(
|
||||||
@@ -594,7 +609,7 @@ describe("props validation", () => {
|
|||||||
|
|
||||||
test("props: can be defined with a boolean", async () => {
|
test("props: can be defined with a boolean", async () => {
|
||||||
class SubComp extends Component {
|
class SubComp extends Component {
|
||||||
static props = { message: true } as const;
|
static props = { message: true };
|
||||||
}
|
}
|
||||||
expect(() => {
|
expect(() => {
|
||||||
validateProps(SubComp as any, {});
|
validateProps(SubComp as any, {});
|
||||||
@@ -636,7 +651,7 @@ describe("props validation", () => {
|
|||||||
|
|
||||||
test("props: extra props cause an error, part 2", async () => {
|
test("props: extra props cause an error, part 2", async () => {
|
||||||
class SubComp extends Component {
|
class SubComp extends Component {
|
||||||
static props = { message: true } as const;
|
static props = { message: true };
|
||||||
}
|
}
|
||||||
expect(() => {
|
expect(() => {
|
||||||
validateProps(SubComp as any, { message: 1, flag: true });
|
validateProps(SubComp as any, { message: 1, flag: true });
|
||||||
@@ -675,8 +690,9 @@ describe("props validation", () => {
|
|||||||
}
|
}
|
||||||
let error: Error;
|
let error: Error;
|
||||||
const app = new App(Parent, { test: true });
|
const app = new App(Parent, { test: true });
|
||||||
|
const appError = nextAppError(app);
|
||||||
const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
||||||
await expect(nextAppError(app)).resolves.toThrow("Invalid props for component 'SubComp'");
|
await expect(appError).resolves.toThrow("Invalid props for component 'SubComp'");
|
||||||
await mountProm;
|
await mountProm;
|
||||||
expect(error!).toBeDefined();
|
expect(error!).toBeDefined();
|
||||||
expect(error!.message).toBe("Invalid props for component 'SubComp': 'p' is missing");
|
expect(error!.message).toBe("Invalid props for component 'SubComp': 'p' is missing");
|
||||||
@@ -765,8 +781,9 @@ describe("props validation", () => {
|
|||||||
}
|
}
|
||||||
let error: Error;
|
let error: Error;
|
||||||
const app = new App(Parent, { test: true });
|
const app = new App(Parent, { test: true });
|
||||||
|
const appError = nextAppError(app);
|
||||||
const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
||||||
await expect(nextAppError(app)).resolves.toThrow("Invalid props for component 'Child'");
|
await expect(appError).resolves.toThrow("Invalid props for component 'Child'");
|
||||||
await mountProm;
|
await mountProm;
|
||||||
expect(error!).toBeDefined();
|
expect(error!).toBeDefined();
|
||||||
expect(error!.message).toBe(
|
expect(error!.message).toBe(
|
||||||
@@ -821,8 +838,9 @@ describe("props validation", () => {
|
|||||||
|
|
||||||
const app = new App(Parent, { test: true });
|
const app = new App(Parent, { test: true });
|
||||||
let error: OwlError | undefined;
|
let error: OwlError | undefined;
|
||||||
|
const appError = nextAppError(app);
|
||||||
const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
||||||
await expect(nextAppError(app)).resolves.toThrow(
|
await expect(appError).resolves.toThrow(
|
||||||
"Invalid props for component 'Child': 'message' is missing"
|
"Invalid props for component 'Child': 'message' is missing"
|
||||||
);
|
);
|
||||||
await mountProm;
|
await mountProm;
|
||||||
@@ -895,10 +913,9 @@ describe("default props", () => {
|
|||||||
}
|
}
|
||||||
let error: Error;
|
let error: Error;
|
||||||
const app = new App(Parent, { test: true });
|
const app = new App(Parent, { test: true });
|
||||||
|
const appError = nextAppError(app);
|
||||||
const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
||||||
await expect(nextAppError(app)).resolves.toThrow(
|
await expect(appError).resolves.toThrow("default value cannot be defined for a mandatory prop");
|
||||||
"default value cannot be defined for a mandatory prop"
|
|
||||||
);
|
|
||||||
await mountProm;
|
await mountProm;
|
||||||
expect(error!).toBeDefined();
|
expect(error!).toBeDefined();
|
||||||
expect(error!.message).toBe(
|
expect(error!.message).toBe(
|
||||||
|
|||||||
@@ -151,9 +151,10 @@ describe("reactivity in lifecycle", () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
const prom = mount(Comp, fixture);
|
const prom = mount(Comp, fixture);
|
||||||
|
expect(steps).toEqual([1]);
|
||||||
(STATE as any).val = 2;
|
(STATE as any).val = 2;
|
||||||
await prom;
|
await prom;
|
||||||
expect(steps).toEqual([2]);
|
expect(steps).toEqual([1, 2]);
|
||||||
expect(fixture.innerHTML).toBe("<div>2</div>");
|
expect(fixture.innerHTML).toBe("<div>2</div>");
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -182,9 +183,9 @@ describe("reactivity in lifecycle", () => {
|
|||||||
"Parent:willRender",
|
"Parent:willRender",
|
||||||
"Child:setup",
|
"Child:setup",
|
||||||
"Child:willStart",
|
"Child:willStart",
|
||||||
"Parent:rendered",
|
|
||||||
"Child:willRender",
|
"Child:willRender",
|
||||||
"Child:rendered",
|
"Child:rendered",
|
||||||
|
"Parent:rendered",
|
||||||
"Child:mounted",
|
"Child:mounted",
|
||||||
"Parent:mounted",
|
"Parent:mounted",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -125,10 +125,11 @@ describe("refs", () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const app = new App(Test, { test: true });
|
const app = new App(Test, { test: true });
|
||||||
|
const appError = nextAppError(app);
|
||||||
const mountProm = expect(app.mount(fixture)).rejects.toThrowError(
|
const mountProm = expect(app.mount(fixture)).rejects.toThrowError(
|
||||||
'Cannot set the same ref more than once in the same component, ref "coucou" was set multiple times in Test'
|
'Cannot set the same ref more than once in the same component, ref "coucou" was set multiple times in Test'
|
||||||
);
|
);
|
||||||
await expect(nextAppError(app)).resolves.toThrow(
|
await expect(appError).resolves.toThrow(
|
||||||
'Cannot set the same ref more than once in the same component, ref "coucou" was set multiple times in Test'
|
'Cannot set the same ref more than once in the same component, ref "coucou" was set multiple times in Test'
|
||||||
);
|
);
|
||||||
await mountProm;
|
await mountProm;
|
||||||
|
|||||||
@@ -49,9 +49,9 @@ describe("rendering semantics", () => {
|
|||||||
"Parent:willRender",
|
"Parent:willRender",
|
||||||
"Child:setup",
|
"Child:setup",
|
||||||
"Child:willStart",
|
"Child:willStart",
|
||||||
"Parent:rendered",
|
|
||||||
"Child:willRender",
|
"Child:willRender",
|
||||||
"Child:rendered",
|
"Child:rendered",
|
||||||
|
"Parent:rendered",
|
||||||
"Child:mounted",
|
"Child:mounted",
|
||||||
"Parent:mounted",
|
"Parent:mounted",
|
||||||
]
|
]
|
||||||
@@ -179,9 +179,9 @@ describe("rendering semantics", () => {
|
|||||||
"Parent:willRender",
|
"Parent:willRender",
|
||||||
"Child:setup",
|
"Child:setup",
|
||||||
"Child:willStart",
|
"Child:willStart",
|
||||||
"Parent:rendered",
|
|
||||||
"Child:willRender",
|
"Child:willRender",
|
||||||
"Child:rendered",
|
"Child:rendered",
|
||||||
|
"Parent:rendered",
|
||||||
"Child:mounted",
|
"Child:mounted",
|
||||||
"Parent:mounted",
|
"Parent:mounted",
|
||||||
]
|
]
|
||||||
@@ -198,9 +198,9 @@ describe("rendering semantics", () => {
|
|||||||
Array [
|
Array [
|
||||||
"Parent:willRender",
|
"Parent:willRender",
|
||||||
"Child:willUpdateProps",
|
"Child:willUpdateProps",
|
||||||
"Parent:rendered",
|
|
||||||
"Child:willRender",
|
"Child:willRender",
|
||||||
"Child:rendered",
|
"Child:rendered",
|
||||||
|
"Parent:rendered",
|
||||||
]
|
]
|
||||||
`);
|
`);
|
||||||
|
|
||||||
@@ -213,9 +213,9 @@ describe("rendering semantics", () => {
|
|||||||
Array [
|
Array [
|
||||||
"Parent:willRender",
|
"Parent:willRender",
|
||||||
"Child:willUpdateProps",
|
"Child:willUpdateProps",
|
||||||
"Parent:rendered",
|
|
||||||
"Child:willRender",
|
"Child:willRender",
|
||||||
"Child:rendered",
|
"Child:rendered",
|
||||||
|
"Parent:rendered",
|
||||||
"Parent:willPatch",
|
"Parent:willPatch",
|
||||||
"Child:willPatch",
|
"Child:willPatch",
|
||||||
"Child:patched",
|
"Child:patched",
|
||||||
@@ -253,9 +253,9 @@ describe("rendering semantics", () => {
|
|||||||
"Parent:willRender",
|
"Parent:willRender",
|
||||||
"Child:setup",
|
"Child:setup",
|
||||||
"Child:willStart",
|
"Child:willStart",
|
||||||
"Parent:rendered",
|
|
||||||
"Child:willRender",
|
"Child:willRender",
|
||||||
"Child:rendered",
|
"Child:rendered",
|
||||||
|
"Parent:rendered",
|
||||||
"Child:mounted",
|
"Child:mounted",
|
||||||
"Parent:mounted",
|
"Parent:mounted",
|
||||||
]
|
]
|
||||||
@@ -305,9 +305,9 @@ describe("rendering semantics", () => {
|
|||||||
"Parent:willRender",
|
"Parent:willRender",
|
||||||
"Child:setup",
|
"Child:setup",
|
||||||
"Child:willStart",
|
"Child:willStart",
|
||||||
"Parent:rendered",
|
|
||||||
"Child:willRender",
|
"Child:willRender",
|
||||||
"Child:rendered",
|
"Child:rendered",
|
||||||
|
"Parent:rendered",
|
||||||
"Child:mounted",
|
"Child:mounted",
|
||||||
"Parent:mounted",
|
"Parent:mounted",
|
||||||
]
|
]
|
||||||
@@ -404,13 +404,13 @@ describe("rendering semantics", () => {
|
|||||||
"A:willRender",
|
"A:willRender",
|
||||||
"B:setup",
|
"B:setup",
|
||||||
"B:willStart",
|
"B:willStart",
|
||||||
"A:rendered",
|
|
||||||
"B:willRender",
|
"B:willRender",
|
||||||
"C:setup",
|
"C:setup",
|
||||||
"C:willStart",
|
"C:willStart",
|
||||||
"B:rendered",
|
|
||||||
"C:willRender",
|
"C:willRender",
|
||||||
"C:rendered",
|
"C:rendered",
|
||||||
|
"B:rendered",
|
||||||
|
"A:rendered",
|
||||||
"C:mounted",
|
"C:mounted",
|
||||||
"B:mounted",
|
"B:mounted",
|
||||||
"A:mounted",
|
"A:mounted",
|
||||||
@@ -473,13 +473,13 @@ test("force render in case of existing render", async () => {
|
|||||||
"A:willRender",
|
"A:willRender",
|
||||||
"B:setup",
|
"B:setup",
|
||||||
"B:willStart",
|
"B:willStart",
|
||||||
"A:rendered",
|
|
||||||
"B:willRender",
|
"B:willRender",
|
||||||
"C:setup",
|
"C:setup",
|
||||||
"C:willStart",
|
"C:willStart",
|
||||||
"B:rendered",
|
|
||||||
"C:willRender",
|
"C:willRender",
|
||||||
"C:rendered",
|
"C:rendered",
|
||||||
|
"B:rendered",
|
||||||
|
"A:rendered",
|
||||||
"C:mounted",
|
"C:mounted",
|
||||||
"B:mounted",
|
"B:mounted",
|
||||||
"A:mounted",
|
"A:mounted",
|
||||||
@@ -516,14 +516,14 @@ test("force render in case of existing render", async () => {
|
|||||||
Array [
|
Array [
|
||||||
"B:willRender",
|
"B:willRender",
|
||||||
"C:willUpdateProps",
|
"C:willUpdateProps",
|
||||||
"B:rendered",
|
|
||||||
"C:willRender",
|
"C:willRender",
|
||||||
"C:rendered",
|
"C:rendered",
|
||||||
|
"B:rendered",
|
||||||
"A:willPatch",
|
"A:willPatch",
|
||||||
"B:willPatch",
|
|
||||||
"C:willPatch",
|
"C:willPatch",
|
||||||
"C:patched",
|
"B:willPatch",
|
||||||
"B:patched",
|
"B:patched",
|
||||||
|
"C:patched",
|
||||||
"A:patched",
|
"A:patched",
|
||||||
]
|
]
|
||||||
`);
|
`);
|
||||||
@@ -561,9 +561,9 @@ test("children, default props and renderings", async () => {
|
|||||||
"Parent:willRender",
|
"Parent:willRender",
|
||||||
"Child:setup",
|
"Child:setup",
|
||||||
"Child:willStart",
|
"Child:willStart",
|
||||||
"Parent:rendered",
|
|
||||||
"Child:willRender",
|
"Child:willRender",
|
||||||
"Child:rendered",
|
"Child:rendered",
|
||||||
|
"Parent:rendered",
|
||||||
"Child:mounted",
|
"Child:mounted",
|
||||||
"Parent:mounted",
|
"Parent:mounted",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { App, Component, mount, onMounted, onRendered, useState, xml } from "../../src/index";
|
import { App, Component, mount, onMounted, useState, xml } from "../../src/index";
|
||||||
import { children, makeTestFixture, nextAppError, nextTick, snapshotEverything } from "../helpers";
|
import { children, makeTestFixture, nextAppError, nextTick, snapshotEverything } from "../helpers";
|
||||||
|
|
||||||
snapshotEverything();
|
snapshotEverything();
|
||||||
@@ -62,28 +62,6 @@ describe("slots", () => {
|
|||||||
expect(fixture.innerHTML).toBe("some other text");
|
expect(fixture.innerHTML).toBe("some other text");
|
||||||
});
|
});
|
||||||
|
|
||||||
test("t-set-slot doesn't cause context to be captured", async () => {
|
|
||||||
class Child extends Component {
|
|
||||||
static template = xml`<t t-slot="default"/>`;
|
|
||||||
}
|
|
||||||
|
|
||||||
class Parent extends Component {
|
|
||||||
static template = xml`<Child>
|
|
||||||
<t t-set-slot="default"><t t-esc="someVal"/></t>
|
|
||||||
</Child>`;
|
|
||||||
static components = { Child };
|
|
||||||
someVal = "some text";
|
|
||||||
setup() {
|
|
||||||
onRendered(() => {
|
|
||||||
this.someVal = "some other text";
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
await mount(Parent, fixture);
|
|
||||||
|
|
||||||
expect(fixture.textContent).toBe("some other text");
|
|
||||||
});
|
|
||||||
|
|
||||||
test("simple slot with slot scope", async () => {
|
test("simple slot with slot scope", async () => {
|
||||||
let child: any;
|
let child: any;
|
||||||
class Child extends Component {
|
class Child extends Component {
|
||||||
@@ -245,8 +223,9 @@ describe("slots", () => {
|
|||||||
|
|
||||||
let error: Error;
|
let error: Error;
|
||||||
const app = new App(Parent);
|
const app = new App(Parent);
|
||||||
|
const appError = nextAppError(app);
|
||||||
const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
||||||
await expect(nextAppError(app)).resolves.toThrow("error occured in the owl lifecycle");
|
await expect(appError).resolves.toThrow("error occured in the owl lifecycle");
|
||||||
await mountProm;
|
await mountProm;
|
||||||
expect(error!).not.toBeNull();
|
expect(error!).not.toBeNull();
|
||||||
expect(mockConsoleWarn).toBeCalledTimes(1);
|
expect(mockConsoleWarn).toBeCalledTimes(1);
|
||||||
@@ -1695,31 +1674,6 @@ describe("slots", () => {
|
|||||||
expect(fixture.innerHTML).toBe("<div><div><p>Ablip</p><div><p>Bblip</p></div></div></div>");
|
expect(fixture.innerHTML).toBe("<div><div><p>Ablip</p><div><p>Bblip</p></div></div></div>");
|
||||||
});
|
});
|
||||||
|
|
||||||
test("named slot inside named slot in t-component", async () => {
|
|
||||||
class Child extends Component {
|
|
||||||
static template = xml`<t t-slot="brol"/>`;
|
|
||||||
}
|
|
||||||
class Parent extends Component {
|
|
||||||
static template = xml`
|
|
||||||
<Child>
|
|
||||||
<t t-set-slot="brol">
|
|
||||||
outer
|
|
||||||
<t t-component="Child">
|
|
||||||
<t t-set-slot="brol">
|
|
||||||
<t t-esc="value"/>
|
|
||||||
</t>
|
|
||||||
</t>
|
|
||||||
</t>
|
|
||||||
</Child>`;
|
|
||||||
static components = { Child };
|
|
||||||
Child = Child;
|
|
||||||
value = "inner";
|
|
||||||
}
|
|
||||||
await mount(Parent, fixture);
|
|
||||||
|
|
||||||
expect(fixture.innerHTML).toBe(" outer inner");
|
|
||||||
});
|
|
||||||
|
|
||||||
test("can render only empty slot", async () => {
|
test("can render only empty slot", async () => {
|
||||||
class Parent extends Component {
|
class Parent extends Component {
|
||||||
static template = xml`<t t-slot="default"/>`;
|
static template = xml`<t t-slot="default"/>`;
|
||||||
|
|||||||
@@ -349,8 +349,9 @@ describe("style and class handling", () => {
|
|||||||
}
|
}
|
||||||
let error: OwlError;
|
let error: OwlError;
|
||||||
const app = new App(Parent);
|
const app = new App(Parent);
|
||||||
|
const appError = nextAppError(app);
|
||||||
const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
||||||
await expect(nextAppError(app)).resolves.toThrow("error occured in the owl lifecycle");
|
await expect(appError).resolves.toThrow("error occured in the owl lifecycle");
|
||||||
await mountProm;
|
await mountProm;
|
||||||
expect(error!).toBeDefined();
|
expect(error!).toBeDefined();
|
||||||
expect(error!.cause).toBeDefined();
|
expect(error!.cause).toBeDefined();
|
||||||
|
|||||||
@@ -36,9 +36,9 @@ describe("t-component", () => {
|
|||||||
"Parent:willRender",
|
"Parent:willRender",
|
||||||
"Child:setup",
|
"Child:setup",
|
||||||
"Child:willStart",
|
"Child:willStart",
|
||||||
"Parent:rendered",
|
|
||||||
"Child:willRender",
|
"Child:willRender",
|
||||||
"Child:rendered",
|
"Child:rendered",
|
||||||
|
"Parent:rendered",
|
||||||
"Child:mounted",
|
"Child:mounted",
|
||||||
"Parent:mounted",
|
"Parent:mounted",
|
||||||
]
|
]
|
||||||
@@ -77,9 +77,9 @@ describe("t-component", () => {
|
|||||||
"Parent:willRender",
|
"Parent:willRender",
|
||||||
"ChildA:setup",
|
"ChildA:setup",
|
||||||
"ChildA:willStart",
|
"ChildA:willStart",
|
||||||
"Parent:rendered",
|
|
||||||
"ChildA:willRender",
|
"ChildA:willRender",
|
||||||
"ChildA:rendered",
|
"ChildA:rendered",
|
||||||
|
"Parent:rendered",
|
||||||
"ChildA:mounted",
|
"ChildA:mounted",
|
||||||
"Parent:mounted",
|
"Parent:mounted",
|
||||||
]
|
]
|
||||||
@@ -94,9 +94,9 @@ describe("t-component", () => {
|
|||||||
"Parent:willRender",
|
"Parent:willRender",
|
||||||
"ChildB:setup",
|
"ChildB:setup",
|
||||||
"ChildB:willStart",
|
"ChildB:willStart",
|
||||||
"Parent:rendered",
|
|
||||||
"ChildB:willRender",
|
"ChildB:willRender",
|
||||||
"ChildB:rendered",
|
"ChildB:rendered",
|
||||||
|
"Parent:rendered",
|
||||||
"Parent:willPatch",
|
"Parent:willPatch",
|
||||||
"ChildA:willUnmount",
|
"ChildA:willUnmount",
|
||||||
"ChildA:willDestroy",
|
"ChildA:willDestroy",
|
||||||
|
|||||||
@@ -99,13 +99,13 @@ describe("list of components", () => {
|
|||||||
"Parent:willRender",
|
"Parent:willRender",
|
||||||
"Child:setup",
|
"Child:setup",
|
||||||
"Child:willStart",
|
"Child:willStart",
|
||||||
|
"Child:willRender",
|
||||||
|
"Child:rendered",
|
||||||
"Child:setup",
|
"Child:setup",
|
||||||
"Child:willStart",
|
"Child:willStart",
|
||||||
|
"Child:willRender",
|
||||||
|
"Child:rendered",
|
||||||
"Parent:rendered",
|
"Parent:rendered",
|
||||||
"Child:willRender",
|
|
||||||
"Child:rendered",
|
|
||||||
"Child:willRender",
|
|
||||||
"Child:rendered",
|
|
||||||
"Child:mounted",
|
"Child:mounted",
|
||||||
"Child:mounted",
|
"Child:mounted",
|
||||||
"Parent:mounted",
|
"Parent:mounted",
|
||||||
@@ -326,10 +326,11 @@ describe("list of components", () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const app = new App(Parent, { test: true });
|
const app = new App(Parent, { test: true });
|
||||||
|
const appError = nextAppError(app);
|
||||||
const mountProm = expect(app.mount(fixture)).rejects.toThrow(
|
const mountProm = expect(app.mount(fixture)).rejects.toThrow(
|
||||||
"Got duplicate key in t-foreach: child"
|
"Got duplicate key in t-foreach: child"
|
||||||
);
|
);
|
||||||
await expect(nextAppError(app)).resolves.toThrow("Got duplicate key in t-foreach: child");
|
await expect(appError).resolves.toThrow("Got duplicate key in t-foreach: child");
|
||||||
await mountProm;
|
await mountProm;
|
||||||
console.info = consoleInfo;
|
console.info = consoleInfo;
|
||||||
expect(mockConsoleWarn).toBeCalledTimes(1);
|
expect(mockConsoleWarn).toBeCalledTimes(1);
|
||||||
@@ -352,12 +353,11 @@ describe("list of components", () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const app = new App(Parent, { test: true });
|
const app = new App(Parent, { test: true });
|
||||||
|
const appError = nextAppError(app);
|
||||||
const mountProm = expect(app.mount(fixture)).rejects.toThrow(
|
const mountProm = expect(app.mount(fixture)).rejects.toThrow(
|
||||||
"Got duplicate key in t-foreach: [object Object]"
|
"Got duplicate key in t-foreach: [object Object]"
|
||||||
);
|
);
|
||||||
await expect(nextAppError(app)).resolves.toThrow(
|
await expect(appError).resolves.toThrow("Got duplicate key in t-foreach: [object Object]");
|
||||||
"Got duplicate key in t-foreach: [object Object]"
|
|
||||||
);
|
|
||||||
await mountProm;
|
await mountProm;
|
||||||
console.info = consoleInfo;
|
console.info = consoleInfo;
|
||||||
expect(mockConsoleWarn).toBeCalledTimes(1);
|
expect(mockConsoleWarn).toBeCalledTimes(1);
|
||||||
|
|||||||
@@ -331,32 +331,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(".trim modifier implies .lazy modifier", async () => {
|
|
||||||
class SomeComponent extends Component {
|
|
||||||
static template = xml`
|
|
||||||
<div>
|
|
||||||
<input t-model.trim="state.text"/>
|
|
||||||
<span><t t-esc="state.text"/></span>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
state = useState({ text: "" });
|
|
||||||
}
|
|
||||||
const comp = await mount(SomeComponent, fixture);
|
|
||||||
|
|
||||||
expect(fixture.innerHTML).toBe("<div><input><span></span></div>");
|
|
||||||
|
|
||||||
const input = fixture.querySelector("input")!;
|
|
||||||
input.value = "test ";
|
|
||||||
input.dispatchEvent(new Event("input"));
|
|
||||||
await nextTick();
|
|
||||||
expect(comp.state.text).toBe("");
|
|
||||||
expect(fixture.innerHTML).toBe("<div><input><span></span></div>");
|
|
||||||
input.dispatchEvent(new Event("change"));
|
|
||||||
await nextTick();
|
|
||||||
expect(comp.state.text).toBe("test");
|
|
||||||
expect(fixture.innerHTML).toBe("<div><input><span>test</span></div>");
|
|
||||||
});
|
|
||||||
|
|
||||||
test(".number modifier", async () => {
|
test(".number modifier", async () => {
|
||||||
class SomeComponent extends Component {
|
class SomeComponent extends Component {
|
||||||
static template = xml`
|
static template = xml`
|
||||||
|
|||||||
@@ -235,7 +235,7 @@ expect.extend({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const currentSteps = steps.splice(0);
|
const currentSteps = steps.splice(0);
|
||||||
const pass = this.equals(currentSteps, expected);
|
let pass = this.equals(currentSteps, expected);
|
||||||
|
|
||||||
const message = pass
|
const message = pass
|
||||||
? () =>
|
? () =>
|
||||||
|
|||||||
@@ -270,8 +270,9 @@ describe("Portal", () => {
|
|||||||
|
|
||||||
let error: Error;
|
let error: Error;
|
||||||
const app = new App(Parent);
|
const app = new App(Parent);
|
||||||
|
const appError = nextAppError(app);
|
||||||
const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
||||||
await expect(nextAppError(app)).resolves.toThrow("invalid portal target");
|
await expect(appError).resolves.toThrow("invalid portal target");
|
||||||
await mountProm;
|
await mountProm;
|
||||||
|
|
||||||
expect(error!).toBeDefined();
|
expect(error!).toBeDefined();
|
||||||
@@ -1002,8 +1003,9 @@ describe("Portal: Props validation", () => {
|
|||||||
}
|
}
|
||||||
let error: OwlError;
|
let error: OwlError;
|
||||||
const app = new App(Parent);
|
const app = new App(Parent);
|
||||||
|
const appError = nextAppError(app);
|
||||||
const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
||||||
await expect(nextAppError(app)).resolves.toThrow("error occured in the owl lifecycle");
|
await expect(appError).resolves.toThrow("error occured in the owl lifecycle");
|
||||||
await mountProm;
|
await mountProm;
|
||||||
expect(error!).toBeDefined();
|
expect(error!).toBeDefined();
|
||||||
expect(error!.cause).toBeDefined();
|
expect(error!.cause).toBeDefined();
|
||||||
@@ -1021,8 +1023,9 @@ describe("Portal: Props validation", () => {
|
|||||||
}
|
}
|
||||||
let error: Error;
|
let error: Error;
|
||||||
const app = new App(Parent);
|
const app = new App(Parent);
|
||||||
|
const appError = nextAppError(app);
|
||||||
const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
|
||||||
await expect(nextAppError(app)).resolves.toThrow("invalid portal target");
|
await expect(appError).resolves.toThrow("invalid portal target");
|
||||||
await mountProm;
|
await mountProm;
|
||||||
expect(error!).toBeDefined();
|
expect(error!).toBeDefined();
|
||||||
expect(error!.message).toBe(`invalid portal target`);
|
expect(error!.message).toBe(`invalid portal target`);
|
||||||
|
|||||||
@@ -993,33 +993,32 @@ describe("Reactivity", () => {
|
|||||||
const obj2 = createReactive({ b: {} }, () => n2++);
|
const obj2 = createReactive({ b: {} }, () => n2++);
|
||||||
const obj3 = createReactive({ c: {} }, () => n3++);
|
const obj3 = createReactive({ c: {} }, () => n3++);
|
||||||
|
|
||||||
// assign the same object should'nt notify reactivity
|
|
||||||
obj2.b = obj2.b;
|
obj2.b = obj2.b;
|
||||||
obj2.b;
|
obj2.b;
|
||||||
obj3.c = obj3.c;
|
obj3.c = obj3.c;
|
||||||
obj3.c;
|
obj3.c;
|
||||||
expect(n1).toBe(0);
|
expect(n1).toBe(0);
|
||||||
expect(n2).toBe(0);
|
expect(n2).toBe(1);
|
||||||
expect(n3).toBe(0);
|
expect(n3).toBe(1);
|
||||||
|
|
||||||
obj2.b = obj1;
|
obj2.b = obj1;
|
||||||
obj2.b;
|
obj2.b;
|
||||||
obj3.c = obj1;
|
obj3.c = obj1;
|
||||||
obj3.c;
|
obj3.c;
|
||||||
expect(n1).toBe(0);
|
expect(n1).toBe(0);
|
||||||
expect(n2).toBe(1);
|
expect(n2).toBe(2);
|
||||||
expect(n3).toBe(1);
|
expect(n3).toBe(2);
|
||||||
|
|
||||||
obj1.a = obj1.a + 2;
|
obj1.a = obj1.a + 2;
|
||||||
obj1.a;
|
obj1.a;
|
||||||
expect(n1).toBe(1);
|
expect(n1).toBe(1);
|
||||||
expect(n2).toBe(1);
|
expect(n2).toBe(2);
|
||||||
expect(n3).toBe(1);
|
expect(n3).toBe(2);
|
||||||
|
|
||||||
obj2.b.a = obj2.b.a + 1;
|
obj2.b.a = obj2.b.a + 1;
|
||||||
expect(n1).toBe(2);
|
expect(n1).toBe(2);
|
||||||
expect(n2).toBe(2);
|
expect(n2).toBe(3);
|
||||||
expect(n3).toBe(1);
|
expect(n3).toBe(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("reactive inside other: reading the inner reactive from outer doesn't affect the inner's subscriptions", async () => {
|
test("reactive inside other: reading the inner reactive from outer doesn't affect the inner's subscriptions", async () => {
|
||||||
@@ -1859,13 +1858,13 @@ describe("Reactivity: useState", () => {
|
|||||||
"Parent:willRender",
|
"Parent:willRender",
|
||||||
"Child:setup",
|
"Child:setup",
|
||||||
"Child:willStart",
|
"Child:willStart",
|
||||||
|
"Child:willRender",
|
||||||
|
"Child:rendered",
|
||||||
"Child:setup",
|
"Child:setup",
|
||||||
"Child:willStart",
|
"Child:willStart",
|
||||||
|
"Child:willRender",
|
||||||
|
"Child:rendered",
|
||||||
"Parent:rendered",
|
"Parent:rendered",
|
||||||
"Child:willRender",
|
|
||||||
"Child:rendered",
|
|
||||||
"Child:willRender",
|
|
||||||
"Child:rendered",
|
|
||||||
"Child:mounted",
|
"Child:mounted",
|
||||||
"Child:mounted",
|
"Child:mounted",
|
||||||
"Parent:mounted",
|
"Parent:mounted",
|
||||||
@@ -1917,13 +1916,13 @@ describe("Reactivity: useState", () => {
|
|||||||
"Parent:willRender",
|
"Parent:willRender",
|
||||||
"Child:setup",
|
"Child:setup",
|
||||||
"Child:willStart",
|
"Child:willStart",
|
||||||
|
"Child:willRender",
|
||||||
|
"Child:rendered",
|
||||||
"Child:setup",
|
"Child:setup",
|
||||||
"Child:willStart",
|
"Child:willStart",
|
||||||
|
"Child:willRender",
|
||||||
|
"Child:rendered",
|
||||||
"Parent:rendered",
|
"Parent:rendered",
|
||||||
"Child:willRender",
|
|
||||||
"Child:rendered",
|
|
||||||
"Child:willRender",
|
|
||||||
"Child:rendered",
|
|
||||||
"Child:mounted",
|
"Child:mounted",
|
||||||
"Child:mounted",
|
"Child:mounted",
|
||||||
"Parent:mounted",
|
"Parent:mounted",
|
||||||
@@ -1993,17 +1992,17 @@ describe("Reactivity: useState", () => {
|
|||||||
"GrandFather:willRender",
|
"GrandFather:willRender",
|
||||||
"Child:setup",
|
"Child:setup",
|
||||||
"Child:willStart",
|
"Child:willStart",
|
||||||
"Parent:setup",
|
|
||||||
"Parent:willStart",
|
|
||||||
"GrandFather:rendered",
|
|
||||||
"Child:willRender",
|
"Child:willRender",
|
||||||
"Child:rendered",
|
"Child:rendered",
|
||||||
|
"Parent:setup",
|
||||||
|
"Parent:willStart",
|
||||||
"Parent:willRender",
|
"Parent:willRender",
|
||||||
"Child:setup",
|
"Child:setup",
|
||||||
"Child:willStart",
|
"Child:willStart",
|
||||||
"Parent:rendered",
|
|
||||||
"Child:willRender",
|
"Child:willRender",
|
||||||
"Child:rendered",
|
"Child:rendered",
|
||||||
|
"Parent:rendered",
|
||||||
|
"GrandFather:rendered",
|
||||||
"Child:mounted",
|
"Child:mounted",
|
||||||
"Parent:mounted",
|
"Parent:mounted",
|
||||||
"Child:mounted",
|
"Child:mounted",
|
||||||
@@ -2216,9 +2215,9 @@ describe("Reactivity: useState", () => {
|
|||||||
"Parent:willRender",
|
"Parent:willRender",
|
||||||
"Child:setup",
|
"Child:setup",
|
||||||
"Child:willStart",
|
"Child:willStart",
|
||||||
"Parent:rendered",
|
|
||||||
"Child:willRender",
|
"Child:willRender",
|
||||||
"Child:rendered",
|
"Child:rendered",
|
||||||
|
"Parent:rendered",
|
||||||
"Child:mounted",
|
"Child:mounted",
|
||||||
"Parent:mounted",
|
"Parent:mounted",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "Owl devtools",
|
"name": "Owl devtools",
|
||||||
"version": "1.2.2",
|
"version": "1.2.1",
|
||||||
"manifest_version": 3,
|
"manifest_version": 3,
|
||||||
"description": "Chrome devtools extension for Odoo Owl framework",
|
"description": "Chrome devtools extension for Odoo Owl framework",
|
||||||
"icons": {
|
"icons": {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "Owl devtools",
|
"name": "Owl devtools",
|
||||||
"version": "1.0.0",
|
"version": "1.0",
|
||||||
"description": "Firefox devtools extension for Odoo Owl framework",
|
"description": "Firefox devtools extension for Odoo Owl framework",
|
||||||
"manifest_version": 2,
|
"manifest_version": 2,
|
||||||
"browser_specific_settings": {
|
"browser_specific_settings": {
|
||||||
@@ -29,7 +29,7 @@
|
|||||||
"scripts": ["background.js"]
|
"scripts": ["background.js"]
|
||||||
},
|
},
|
||||||
"devtools_page": "devtools_app/devtools.html",
|
"devtools_page": "devtools_app/devtools.html",
|
||||||
"content_security_policy": "script-src 'self'; object-src 'self'",
|
"content_security_policy": "script-src 'self' 'unsafe-eval' blob:; object-src 'self'",
|
||||||
"content_scripts": [
|
"content_scripts": [
|
||||||
{
|
{
|
||||||
"matches": ["<all_urls>"],
|
"matches": ["<all_urls>"],
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
import { IS_FIREFOX, getActiveTabURL, browserInstance } from "./utils";
|
import { IS_FIREFOX, getActiveTabURL } from "./utils";
|
||||||
|
|
||||||
let owlStatus = 0;
|
let owlStatus = 0;
|
||||||
|
|
||||||
|
const browserInstance = IS_FIREFOX ? browser : chrome;
|
||||||
|
|
||||||
// Used to keep track of the tabs where the owl devtools have been opened
|
// Used to keep track of the tabs where the owl devtools have been opened
|
||||||
const activePanels = new Map();
|
const activePanels = new Map();
|
||||||
|
|
||||||
@@ -69,9 +71,6 @@ function checkOwlStatus(tabId) {
|
|||||||
browserInstance.runtime.onMessage.addListener(async (message, sender, sendResponse) => {
|
browserInstance.runtime.onMessage.addListener(async (message, sender, sendResponse) => {
|
||||||
// Send back the owl status to the sender
|
// Send back the owl status to the sender
|
||||||
if (message.type === "getOwlStatus") {
|
if (message.type === "getOwlStatus") {
|
||||||
if (IS_FIREFOX) {
|
|
||||||
return { result: owlStatus };
|
|
||||||
}
|
|
||||||
sendResponse({ result: owlStatus });
|
sendResponse({ result: owlStatus });
|
||||||
return true;
|
return true;
|
||||||
} else if (message.type === "owlStatus") {
|
} else if (message.type === "owlStatus") {
|
||||||
@@ -113,10 +112,11 @@ browserInstance.runtime.onMessage.addListener(async (message, sender, sendRespon
|
|||||||
}, 750);
|
}, 750);
|
||||||
activePanels.set(message.id, { port: port, expirationTimeout: expirationTimeout });
|
activePanels.set(message.id, { port: port, expirationTimeout: expirationTimeout });
|
||||||
// This is solely for firefox which doesnt allow access to the chrome.tabs api inside devtools
|
// This is solely for firefox which doesnt allow access to the chrome.tabs api inside devtools
|
||||||
// We therefore only use the firefox syntax to send the response here
|
|
||||||
} else if (message.type === "getActiveTabURL") {
|
} else if (message.type === "getActiveTabURL") {
|
||||||
const tab = await getActiveTabURL();
|
getActiveTabURL().then((tab) => {
|
||||||
return { result: tab };
|
sendResponse({ result: tab });
|
||||||
|
});
|
||||||
|
return true;
|
||||||
} else {
|
} else {
|
||||||
const destinationPanel = activePanels.get(sender.tab.id);
|
const destinationPanel = activePanels.get(sender.tab.id);
|
||||||
if (destinationPanel) {
|
if (destinationPanel) {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import globalHook from "./page_scripts/owl_devtools_global_hook";
|
import globalHook from "./page_scripts/owl_devtools_global_hook";
|
||||||
import { IS_FIREFOX, browserInstance } from "./utils";
|
import { IS_FIREFOX } from "./utils";
|
||||||
|
|
||||||
// Relays the owlDevtools__... type top window messages to the background script so that it can relay it to the devtools app
|
// Relays the owlDevtools__... type top window messages to the background script so that it can relay it to the devtools app
|
||||||
window.addEventListener(
|
window.addEventListener(
|
||||||
@@ -7,7 +7,7 @@ window.addEventListener(
|
|||||||
function (event) {
|
function (event) {
|
||||||
if (event.data.type && event.data.source === "owl-devtools") {
|
if (event.data.type && event.data.source === "owl-devtools") {
|
||||||
try {
|
try {
|
||||||
browserInstance.runtime.sendMessage(
|
chrome.runtime.sendMessage(
|
||||||
event.data.data
|
event.data.data
|
||||||
? { type: event.data.type, data: event.data.data, origin: event.data.origin }
|
? { type: event.data.type, data: event.data.data, origin: event.data.origin }
|
||||||
: { type: event.data.type, origin: event.data.origin }
|
: { type: event.data.type, origin: event.data.origin }
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { IS_FIREFOX, browserInstance } from "../utils";
|
import { IS_FIREFOX } from "../utils";
|
||||||
|
|
||||||
let created = false;
|
let created = false;
|
||||||
|
let browserInstance = IS_FIREFOX ? browser : chrome;
|
||||||
|
|
||||||
// Try to load the owl panel each 1000 ms in case it (re)appears on the page later on
|
// Try to load the owl panel each 1000 ms in case it (re)appears on the page later on
|
||||||
const checkInterval = setInterval(createPanelsIfOwl, 1000);
|
const checkInterval = setInterval(createPanelsIfOwl, 1000);
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" ?>
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
<templates xml:space="preserve">
|
<templates xml:space="preserve">
|
||||||
<t t-name="devtools.ComponentSearchBar" owl="1">
|
<t t-name="devtools.ComponentSearchBar" owl="1">
|
||||||
<div class="mouse-icon p-1" t-on-click.stop='() => this.store.toggleSelector()'>
|
<div class="pointer-icon ms-1 px-2 py-1" t-on-click.stop='() => this.store.toggleSelector()'>
|
||||||
<i title="Select an element in the page to inspect the corresponding component" class="fa fa-fw fa-mouse-pointer" t-attf-style="color: {{store.componentSearch.activeSelector ? 'var(--active-icon)' : 'var(--text-color)'}};"></i>
|
<i title="Select an element in the page to inspect the corresponding component" class="fa fa-mouse-pointer" t-attf-style="color: {{store.componentSearch.activeSelector ? 'var(--active-icon)' : 'var(--text-color)'}};"></i>
|
||||||
</div>
|
</div>
|
||||||
<div class="icons-separator"/>
|
<div class="icons-separator"/>
|
||||||
<div class="d-flex align-items-center ms-2 flex-grow-1">
|
<div class="d-flex align-items-center ms-2 flex-grow-1">
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ export class ComponentsTab extends Component {
|
|||||||
this.store = useStore();
|
this.store = useStore();
|
||||||
this.flushRendersTimeout = false;
|
this.flushRendersTimeout = false;
|
||||||
useExternalListener(document, "keydown", this.onKeyboardEvent);
|
useExternalListener(document, "keydown", this.onKeyboardEvent);
|
||||||
useExternalListener(window, "resize", this.onWindowResize);
|
|
||||||
|
|
||||||
onWillUnmount(() => {
|
onWillUnmount(() => {
|
||||||
window.removeEventListener("mousemove", this.onMouseMove);
|
window.removeEventListener("mousemove", this.onMouseMove);
|
||||||
@@ -54,11 +53,9 @@ export class ComponentsTab extends Component {
|
|||||||
|
|
||||||
// Adjust the position of the split between the left and right right window of the components tab
|
// Adjust the position of the split between the left and right right window of the components tab
|
||||||
onMouseMove = (event) => {
|
onMouseMove = (event) => {
|
||||||
const minWidth = (147 / window.innerWidth) * 100;
|
|
||||||
const maxWidth = 100 - (100 / window.innerWidth) * 100;
|
|
||||||
this.store.splitPosition = Math.max(
|
this.store.splitPosition = Math.max(
|
||||||
Math.min((event.clientX / window.innerWidth) * 100, maxWidth),
|
Math.min((event.clientX / window.innerWidth) * 100, 85),
|
||||||
minWidth
|
15
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -67,11 +64,4 @@ export class ComponentsTab extends Component {
|
|||||||
window.removeEventListener("mousemove", this.onMouseMove);
|
window.removeEventListener("mousemove", this.onMouseMove);
|
||||||
window.removeEventListener("mouseup", this.onMouseUp);
|
window.removeEventListener("mouseup", this.onMouseUp);
|
||||||
};
|
};
|
||||||
|
|
||||||
onWindowResize = () => {
|
|
||||||
const minWidth = (147 / window.innerWidth) * 100;
|
|
||||||
if (minWidth <= 100) {
|
|
||||||
this.store.splitPosition = Math.max(this.store.splitPosition, minWidth);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
<templates xml:space="preserve">
|
<templates xml:space="preserve">
|
||||||
<t t-name="devtools.ObjectTreeElement" owl="1">
|
<t t-name="devtools.ObjectTreeElement" owl="1">
|
||||||
<div class="m-0 p-0 text-nowrap w-100 object-line"
|
<div class="m-0 p-0 text-nowrap w-100 object-line"
|
||||||
t-att-class="props.class + (props.object.hasChildren ? ' bg-feedback' : '')"
|
t-att-class="props.class"
|
||||||
t-on-click.stop="() => this.store.toggleObjectTreeElementsDisplay(this.props.object)"
|
t-on-click.stop="() => this.store.toggleObjectTreeElementsDisplay(this.props.object)"
|
||||||
t-on-contextmenu.prevent="openMenu"
|
t-on-contextmenu.prevent="openMenu"
|
||||||
>
|
>
|
||||||
<div t-attf-style="padding-left: {{objectPadding}}rem">
|
<div t-attf-style="padding-left: {{objectPadding}}rem">
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
/** @odoo-module **/
|
/** @odoo-module **/
|
||||||
|
|
||||||
import { isElementInCenterViewport, minimizeKey, browserInstance } from "../../../../utils";
|
import { isElementInCenterViewport, minimizeKey, IS_FIREFOX } from "../../../../utils";
|
||||||
import { useStore } from "../../../store/store";
|
import { useStore } from "../../../store/store";
|
||||||
import { HighlightText } from "./highlight_text/highlight_text";
|
import { HighlightText } from "./highlight_text/highlight_text";
|
||||||
|
|
||||||
|
const browserInstance = IS_FIREFOX ? browser : chrome;
|
||||||
|
|
||||||
const { Component, useRef, useState, useEffect, onMounted } = owl;
|
const { Component, useRef, useState, useEffect, onMounted } = owl;
|
||||||
|
|
||||||
export class TreeElement extends Component {
|
export class TreeElement extends Component {
|
||||||
|
|||||||
@@ -16,9 +16,9 @@
|
|||||||
<option t-att-value="frame"><t t-esc="frame"/></option>
|
<option t-att-value="frame"><t t-esc="frame"/></option>
|
||||||
</t>
|
</t>
|
||||||
</select>
|
</select>
|
||||||
<i class="ms-auto p-1 me-1 lg-icon fa fa-question-circle navbar-icon" title="Open devtools doc" t-on-click.stop="() => this.store.openDocumentation()"></i>
|
<i class="ms-auto p-1 me-1 lg-icon fa fa-question-circle pointer-icon" title="Open devtools doc" t-on-click.stop="() => this.store.openDocumentation()"></i>
|
||||||
<i class="p-1 me-1 lg-icon fa navbar-icon" title="Toggle dark mode" t-att-class="{ 'fa-sun-o': store.settings.darkMode, 'fa-moon-o' : !store.settings.darkMode}" t-on-click.stop="() => this.store.toggleDarkMode()"></i>
|
<i class="p-1 me-1 lg-icon fa pointer-icon" title="Toggle dark mode" t-att-class="{ 'fa-sun-o': store.settings.darkMode, 'fa-moon-o' : !store.settings.darkMode}" t-on-click.stop="() => this.store.toggleDarkMode()"></i>
|
||||||
<i class="p-1 me-1 lg-icon fa fa-repeat navbar-icon" title="Refresh extension" t-on-click.stop="() => this.store.refreshExtension()"></i>
|
<i class="p-1 me-1 lg-icon fa fa-repeat pointer-icon" title="Refresh extension" t-on-click.stop="() => this.store.refreshExtension()"></i>
|
||||||
</div>
|
</div>
|
||||||
<ComponentsTab t-if="store.page === 'ComponentsTab'"/>
|
<ComponentsTab t-if="store.page === 'ComponentsTab'"/>
|
||||||
<ProfilerTab t-if="store.page === 'ProfilerTab'"/>
|
<ProfilerTab t-if="store.page === 'ProfilerTab'"/>
|
||||||
|
|||||||
@@ -3,20 +3,20 @@
|
|||||||
<t t-name="devtools.ProfilerTab" owl="1">
|
<t t-name="devtools.ProfilerTab" owl="1">
|
||||||
<div class="position-relative overflow-hidden d-flex flex-column h-100">
|
<div class="position-relative overflow-hidden d-flex flex-column h-100">
|
||||||
<div class="panel-top d-flex align-items-center">
|
<div class="panel-top d-flex align-items-center">
|
||||||
<i title="Start/Stop Recording" class="fa fa-circle profiler-icon p-2" t-attf-style="color: {{store.activeRecorder ? 'var(--active-recorder)' : 'var(--text-color)'}};" t-on-click.stop="() => this.store.toggleRecording()" aria-hidden="true"></i>
|
<i title="Start/Stop Recording" class="fa fa-circle pointer-icon ms-1 p-1" t-attf-style="color: {{store.activeRecorder ? 'var(--active-recorder)' : 'var(--text-color)'}};" t-on-click.stop="() => this.store.toggleRecording()" aria-hidden="true"></i>
|
||||||
<i title="Clear events" class="fa fa-ban profiler-icon p-2" t-on-click.stop="() => this.store.clearEventsConsole()" aria-hidden="true"></i>
|
<i title="Clear events" class="fa fa-ban pointer-icon p-1 px-2" t-on-click.stop="() => this.store.clearEventsConsole()" aria-hidden="true"></i>
|
||||||
<div class="icons-separator"/>
|
<div class="icons-separator mx-1"/>
|
||||||
<select class="form-select form-select-sm custom-select pointer-icon border-0" t-on-change="selectDisplayMode">
|
<select class="form-select form-select-sm custom-select border-0" t-on-change="selectDisplayMode">
|
||||||
<option t-att-selected="store.eventsTreeView" value="Tree">Tree view</option>
|
<option t-att-selected="store.eventsTreeView" value="Tree">Tree view</option>
|
||||||
<option t-att-selected="!store.eventsTreeView" value="List">Events log</option>
|
<option t-att-selected="!store.eventsTreeView" value="List">Events log</option>
|
||||||
</select>
|
</select>
|
||||||
<i title="Collapse All" class="fa fa-list p-2 profiler-icon" t-on-click="() => this.store.collapseAll()" t-attf-style="{{store.eventsTreeView ? '' : 'display: none;'}}"></i>
|
<i title="Collapse All" type="button" class="fa fa-list me-2" t-on-click="() => this.store.collapseAll()" t-attf-style="{{store.eventsTreeView ? '' : 'visibility: hidden;'}}"></i>
|
||||||
<div class="icons-separator"/>
|
<div class="icons-separator"/>
|
||||||
<label class="p-1 mx-1 form-check-label pointer-icon" title="Trace renderings in console">
|
<label class="mx-2 form-check-label pointer-icon" title="Trace renderings in console">
|
||||||
<input type="checkbox" class="form-check-input me-1 pointer-icon" t-att-checked="store.traceRenderings" t-on-input="() => this.store.toggleTracing()"/> Trace Renderings
|
<input type="checkbox" class="form-check-input me-1" t-att-checked="store.traceRenderings" t-on-input="() => this.store.toggleTracing()"/> Trace Renderings
|
||||||
</label>
|
</label>
|
||||||
<label class="p-1 mx-1 form-check-label pointer-icon" title="Trace subscriptions in console (warning: it is VERY verbose)">
|
<label class="mx-2 form-check-label pointer-icon" title="Trace subscriptions in console (warning: it is VERY verbose)">
|
||||||
<input type="checkbox" class="form-check-input me-1 pointer-icon" t-att-checked="store.traceSubscriptions" t-on-input="() => this.store.toggleSubscriptionTracing()"/> Trace Subscriptions
|
<input type="checkbox" class="form-check-input me-1" t-att-checked="store.traceSubscriptions" t-on-input="() => this.store.toggleSubscriptionTracing()"/> Trace Subscriptions
|
||||||
</label>
|
</label>
|
||||||
<!-- <EventSearchBar/> -->
|
<!-- <EventSearchBar/> -->
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
const { reactive, useState, toRaw } = owl;
|
const { reactive, useState, toRaw } = owl;
|
||||||
import { fuzzySearch, IS_FIREFOX, getActiveTabURL, browserInstance } from "../../utils";
|
import { fuzzySearch, IS_FIREFOX, getActiveTabURL } from "../../utils";
|
||||||
import globalHook from "../../page_scripts/owl_devtools_global_hook";
|
import globalHook from "../../page_scripts/owl_devtools_global_hook";
|
||||||
|
|
||||||
|
const browserInstance = IS_FIREFOX ? browser : chrome;
|
||||||
|
|
||||||
// Main store which contains all states that needs to be maintained throughout all components in the devtools app
|
// Main store which contains all states that needs to be maintained throughout all components in the devtools app
|
||||||
export const store = reactive({
|
export const store = reactive({
|
||||||
devtoolsId: 0,
|
devtoolsId: 0,
|
||||||
@@ -113,9 +115,6 @@ export const store = reactive({
|
|||||||
}
|
}
|
||||||
keepEnvLit(details);
|
keepEnvLit(details);
|
||||||
this.activeComponent = details;
|
this.activeComponent = details;
|
||||||
if (this.componentSearch.search.length) {
|
|
||||||
this.updateSearch(this.componentSearch.search);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// Select a component by retrieving its details from the page based on its path
|
// Select a component by retrieving its details from the page based on its path
|
||||||
@@ -147,7 +146,6 @@ export const store = reactive({
|
|||||||
}
|
}
|
||||||
component.selected = true;
|
component.selected = true;
|
||||||
highlightChildren(component);
|
highlightChildren(component);
|
||||||
this.highlightComponent(path);
|
|
||||||
const details = await evalFunctionInWindow(
|
const details = await evalFunctionInWindow(
|
||||||
"getComponentDetails",
|
"getComponentDetails",
|
||||||
[component.path],
|
[component.path],
|
||||||
@@ -348,7 +346,7 @@ export const store = reactive({
|
|||||||
|
|
||||||
// Expand the children of the input object property and load it from page if necessary
|
// Expand the children of the input object property and load it from page if necessary
|
||||||
async toggleObjectTreeElementsDisplay(obj) {
|
async toggleObjectTreeElementsDisplay(obj) {
|
||||||
if (!obj.hasChildren || window.getSelection().toString().length) {
|
if (!obj.hasChildren) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Since it is sometimes impossible (and always ineffective) to load all descendants of a property
|
// Since it is sometimes impossible (and always ineffective) to load all descendants of a property
|
||||||
@@ -941,9 +939,10 @@ function arraysEqual(arr1, arr2) {
|
|||||||
|
|
||||||
async function getTabURL() {
|
async function getTabURL() {
|
||||||
if (IS_FIREFOX) {
|
if (IS_FIREFOX) {
|
||||||
// It is not possible to run getActiveTabURL inside the devtools when using firefox so we ask the background to execute it instead
|
// This happens in firefox when the method is called inside devtools so we ask the background to execute it instead
|
||||||
const response = await browserInstance.runtime.sendMessage({ type: "getActiveTabURL" });
|
browserInstance.runtime.sendMessage({ type: "getActiveTabURL" }).then((response) => {
|
||||||
return response.result;
|
return response.result;
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
return await getActiveTabURL();
|
return await getActiveTabURL();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,8 +26,6 @@
|
|||||||
--text-selected: white;
|
--text-selected: white;
|
||||||
--menu-highlight-bg: rgb(201, 201, 201);
|
--menu-highlight-bg: rgb(201, 201, 201);
|
||||||
--version-bg: teal;
|
--version-bg: teal;
|
||||||
--hover-bg: #ebebeb;
|
|
||||||
--navbar-hover-bg: #d3d3d3;
|
|
||||||
/* to change the color here, put it in stroke='%23[color in hexadecimal]' */
|
/* to change the color here, put it in stroke='%23[color in hexadecimal]' */
|
||||||
--select-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23444444' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/%3e%3c/svg%3e");
|
--select-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23444444' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/%3e%3c/svg%3e");
|
||||||
}
|
}
|
||||||
@@ -54,8 +52,6 @@
|
|||||||
--text-selected: #c9c9c9;
|
--text-selected: #c9c9c9;
|
||||||
--menu-highlight-bg: rgb(65, 65, 65);
|
--menu-highlight-bg: rgb(65, 65, 65);
|
||||||
--version-bg: #805900ad;
|
--version-bg: #805900ad;
|
||||||
--hover-bg: #575757;
|
|
||||||
--navbar-hover-bg: #6b6b6b;
|
|
||||||
color-scheme: dark;
|
color-scheme: dark;
|
||||||
/* to change the color here, put it in stroke='%23[color in hexadecimal]' */
|
/* to change the color here, put it in stroke='%23[color in hexadecimal]' */
|
||||||
--select-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23c9c9c9' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/%3e%3c/svg%3e");
|
--select-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23c9c9c9' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/%3e%3c/svg%3e");
|
||||||
@@ -86,10 +82,6 @@
|
|||||||
color: var(--text-color) !important;
|
color: var(--text-color) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-check-label {
|
|
||||||
user-select: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.navbar-btn {
|
.navbar-btn {
|
||||||
height: 23px;
|
height: 23px;
|
||||||
padding: 0.5rem;
|
padding: 0.5rem;
|
||||||
@@ -252,7 +244,7 @@
|
|||||||
.search-input {
|
.search-input {
|
||||||
background-color: var(--background-color);
|
background-color: var(--background-color);
|
||||||
color: var(--text-color);
|
color: var(--text-color);
|
||||||
padding: 0.37rem 0rem;
|
padding: 0.4rem 0rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.search-icon {
|
.search-icon {
|
||||||
@@ -263,35 +255,6 @@
|
|||||||
.utility-icon {
|
.utility-icon {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
font-size: 1.2em;
|
font-size: 1.2em;
|
||||||
border-radius: 35%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mouse-icon {
|
|
||||||
border-radius: 35%;
|
|
||||||
cursor: pointer;
|
|
||||||
padding-left: 0.4rem !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.profiler-icon {
|
|
||||||
border-radius: 35%;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.utility-icon:hover, .mouse-icon:hover, .profiler-icon:hover, .bg-feedback:hover {
|
|
||||||
background-color: var(--hover-bg);
|
|
||||||
}
|
|
||||||
|
|
||||||
.navbar-icon {
|
|
||||||
border-radius: 35%;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.navbar-icon:hover {
|
|
||||||
background-color: var(--navbar-hover-bg);
|
|
||||||
}
|
|
||||||
|
|
||||||
.bg-feedback {
|
|
||||||
border-radius: 5%;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.lg-icon {
|
.lg-icon {
|
||||||
@@ -318,7 +281,7 @@
|
|||||||
color: var(--text-color);
|
color: var(--text-color);
|
||||||
background-color: var(--background-color);
|
background-color: var(--background-color);
|
||||||
border: 1px solid gray;
|
border: 1px solid gray;
|
||||||
z-index: 2;
|
z-index: 1;
|
||||||
box-shadow: 1px 2px 5px #888;
|
box-shadow: 1px 2px 5px #888;
|
||||||
font-family: var(--bs-font-sans-serif);
|
font-family: var(--bs-font-sans-serif);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,7 +49,6 @@
|
|||||||
this.traceRenderings = false;
|
this.traceRenderings = false;
|
||||||
this.traceSubscriptions = false;
|
this.traceSubscriptions = false;
|
||||||
this.requestedFrame = false;
|
this.requestedFrame = false;
|
||||||
this.enabledSelector = false;
|
|
||||||
this.eventsBatch = [];
|
this.eventsBatch = [];
|
||||||
// Object which defines how different types of data should be displayed when passed to the devtools
|
// Object which defines how different types of data should be displayed when passed to the devtools
|
||||||
this.serializer = {
|
this.serializer = {
|
||||||
@@ -176,7 +175,6 @@
|
|||||||
|
|
||||||
initDevtools(frame = "top") {
|
initDevtools(frame = "top") {
|
||||||
if (!this.devtoolsInit) {
|
if (!this.devtoolsInit) {
|
||||||
document.addEventListener("mouseover", this.HTMLSelector, { capture: true });
|
|
||||||
this.frame = frame;
|
this.frame = frame;
|
||||||
const self = this;
|
const self = this;
|
||||||
// Flush the events batcher when a root render is completed
|
// Flush the events batcher when a root render is completed
|
||||||
@@ -608,33 +606,28 @@
|
|||||||
// Identify the hovered component based on the corresponding DOM element and send the Select message
|
// Identify the hovered component based on the corresponding DOM element and send the Select message
|
||||||
// when the target changes
|
// when the target changes
|
||||||
HTMLSelector = (ev) => {
|
HTMLSelector = (ev) => {
|
||||||
if (this.enabledSelector) {
|
const target = ev.target;
|
||||||
const target = ev.target;
|
if (!this.currentSelectedElement || !target.isEqualNode(this.currentSelectedElement)) {
|
||||||
if (!this.currentSelectedElement || !target.isEqualNode(this.currentSelectedElement)) {
|
const path = this.getElementPath(target);
|
||||||
const path = this.getElementPath(target);
|
this.highlightComponent(path);
|
||||||
this.highlightComponent(path);
|
this.currentSelectedElement = target;
|
||||||
this.currentSelectedElement = target;
|
window.top.postMessage({
|
||||||
window.top.postMessage({
|
source: "owl-devtools",
|
||||||
source: "owl-devtools",
|
type: "SelectElement",
|
||||||
type: "SelectElement",
|
data: path,
|
||||||
data: path,
|
});
|
||||||
});
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.removeHighlights();
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Activate the HTML selector tool
|
// Activate the HTML selector tool
|
||||||
enableHTMLSelector() {
|
enableHTMLSelector() {
|
||||||
this.enabledSelector = true;
|
document.addEventListener("mouseover", this.HTMLSelector, { capture: true });
|
||||||
document.addEventListener("click", this.disableHTMLSelector, { capture: true });
|
document.addEventListener("click", this.disableHTMLSelector, { capture: true });
|
||||||
document.addEventListener("scroll", this.removeHighlights, { capture: true });
|
document.addEventListener("mouseout", this.removeHighlights, { capture: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Diasble the HTML selector tool
|
// Diasble the HTML selector tool
|
||||||
disableHTMLSelector = (ev = undefined) => {
|
disableHTMLSelector = (ev = undefined) => {
|
||||||
this.enabledSelector = false;
|
|
||||||
if (ev) {
|
if (ev) {
|
||||||
if (!ev.isTrusted) {
|
if (!ev.isTrusted) {
|
||||||
return;
|
return;
|
||||||
@@ -643,8 +636,9 @@
|
|||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
}
|
}
|
||||||
this.removeHighlights();
|
this.removeHighlights();
|
||||||
|
document.removeEventListener("mouseover", this.HTMLSelector, { capture: true });
|
||||||
document.removeEventListener("click", this.disableHTMLSelector, { capture: true });
|
document.removeEventListener("click", this.disableHTMLSelector, { capture: true });
|
||||||
document.removeEventListener("scroll", this.removeHighlights, { capture: true });
|
document.removeEventListener("mouseout", this.removeHighlights, { capture: true });
|
||||||
window.top.postMessage({
|
window.top.postMessage({
|
||||||
source: "owl-devtools",
|
source: "owl-devtools",
|
||||||
type: "StopSelector",
|
type: "StopSelector",
|
||||||
@@ -754,7 +748,7 @@
|
|||||||
child.contentType = "object";
|
child.contentType = "object";
|
||||||
child.content = this.serializer.serializeItem(Object.getPrototypeOf(parentObj), true);
|
child.content = this.serializer.serializeItem(Object.getPrototypeOf(parentObj), true);
|
||||||
child.hasChildren = true;
|
child.hasChildren = true;
|
||||||
if (!oldTree && type === "env" && Object.getPrototypeOf(parentObj) !== Object.prototype) {
|
if (!oldTree && type === "env") {
|
||||||
child.toggled = true;
|
child.toggled = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
export const IS_FIREFOX = navigator.userAgent.indexOf("Firefox") !== -1;
|
export const IS_FIREFOX = navigator.userAgent.indexOf("Firefox") !== -1;
|
||||||
|
|
||||||
export const browserInstance = IS_FIREFOX ? browser : chrome;
|
const browserInstance = IS_FIREFOX ? browser : chrome;
|
||||||
|
|
||||||
export async function getOwlStatus() {
|
export async function getOwlStatus() {
|
||||||
const response = await browserInstance.runtime.sendMessage({ type: "getOwlStatus" });
|
const response = await browserInstance.runtime.sendMessage({ type: "getOwlStatus" });
|
||||||
|
|||||||
@@ -1,24 +0,0 @@
|
|||||||
{
|
|
||||||
"root": true,
|
|
||||||
"parser": "@typescript-eslint/parser",
|
|
||||||
"parserOptions": {
|
|
||||||
"ecmaVersion": 6,
|
|
||||||
"sourceType": "module"
|
|
||||||
},
|
|
||||||
"plugins": [
|
|
||||||
"@typescript-eslint"
|
|
||||||
],
|
|
||||||
"rules": {
|
|
||||||
"@typescript-eslint/naming-convention": "warn",
|
|
||||||
"@typescript-eslint/semi": "warn",
|
|
||||||
"curly": "warn",
|
|
||||||
"eqeqeq": "warn",
|
|
||||||
"no-throw-literal": "warn",
|
|
||||||
"semi": "off"
|
|
||||||
},
|
|
||||||
"ignorePatterns": [
|
|
||||||
"out",
|
|
||||||
"dist",
|
|
||||||
"**/*.d.ts"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
{
|
|
||||||
"version": "0.2.0",
|
|
||||||
"configurations": [
|
|
||||||
{
|
|
||||||
"name": "Run Extension",
|
|
||||||
"type": "extensionHost",
|
|
||||||
"request": "launch",
|
|
||||||
"args": [
|
|
||||||
"--extensionDevelopmentPath=${workspaceFolder}"
|
|
||||||
],
|
|
||||||
"outFiles": [
|
|
||||||
"${workspaceFolder}/out/**/*.js"
|
|
||||||
],
|
|
||||||
"preLaunchTask": "${defaultBuildTask}"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Extension Tests",
|
|
||||||
"type": "extensionHost",
|
|
||||||
"request": "launch",
|
|
||||||
"args": [
|
|
||||||
"--extensionDevelopmentPath=${workspaceFolder}",
|
|
||||||
"--extensionTestsPath=${workspaceFolder}/out/test/suite/index"
|
|
||||||
],
|
|
||||||
"outFiles": [
|
|
||||||
"${workspaceFolder}/out/test/**/*.js"
|
|
||||||
],
|
|
||||||
"preLaunchTask": "${defaultBuildTask}"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
{
|
|
||||||
"version": "2.0.0",
|
|
||||||
"tasks": [
|
|
||||||
{
|
|
||||||
"type": "npm",
|
|
||||||
"script": "watch",
|
|
||||||
"problemMatcher": "$tsc-watch",
|
|
||||||
"isBackground": true,
|
|
||||||
"presentation": {
|
|
||||||
"reveal": "never"
|
|
||||||
},
|
|
||||||
"group": {
|
|
||||||
"kind": "build",
|
|
||||||
"isDefault": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
.vscode/**
|
|
||||||
.vscode-test/**
|
|
||||||
src/**
|
|
||||||
.gitignore
|
|
||||||
.yarnrc
|
|
||||||
vsc-extension-quickstart.md
|
|
||||||
**/tsconfig.json
|
|
||||||
**/.eslintrc.json
|
|
||||||
**/*.map
|
|
||||||
**/*.ts
|
|
||||||
**/*.vsix
|
|
||||||
scripts/**
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
# Change Log
|
|
||||||
|
|
||||||
All notable changes to the "owl-vision" extension will be documented in this file.
|
|
||||||
|
|
||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
||||||
|
|
||||||
## [0.0.2] - 2023-2-11
|
|
||||||
|
|
||||||
### Added
|
|
||||||
|
|
||||||
- Switch Below command
|
|
||||||
- Basic syntax highlight for xpaths
|
|
||||||
- Syntax builder scripts to make syntaxes easier to read and edit
|
|
||||||
- Syntax highlight in single quote attributes
|
|
||||||
- Syntax highlight for slot props
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
|
|
||||||
- Added missing space in component's snippet indentation
|
|
||||||
- Using `Switch Besides` or `Switch Below` does not open a new panel if one was already open
|
|
||||||
|
|
||||||
## [0.0.1] - 2023-03-10
|
|
||||||
|
|
||||||
- Initial release
|
|
||||||
|
|
||||||
### Added
|
|
||||||
|
|
||||||
- Owl templates syntax highlight in xml files
|
|
||||||
- `Find Template` Command - Finds the template file of the currently selected element.
|
|
||||||
- `Find Component` Command - Finds the selected component definition.
|
|
||||||
- `Switch` Command - Finds the corresponding template or component file depending on the current file.
|
|
||||||
- `Switch Besides` Command - Finds the corresponding template or component file depending on the current file and opens it besides.
|
|
||||||
@@ -1,856 +0,0 @@
|
|||||||
OWL-VISION is published under the GNU LESSER GENERAL PUBLIC LICENSE, Version 3
|
|
||||||
(LGPLv3), as included below. Since the LGPL is a set of additional
|
|
||||||
permissions on top of the GPL, the text of the GPL is included at the
|
|
||||||
bottom as well.
|
|
||||||
|
|
||||||
Some external libraries and contributions bundled with OWL-VISION may be published
|
|
||||||
under other GPL-compatible licenses. For these, please refer to the relevant
|
|
||||||
source files and/or license files, in the source code tree.
|
|
||||||
|
|
||||||
**************************************************************************
|
|
||||||
|
|
||||||
GNU LESSER GENERAL PUBLIC LICENSE
|
|
||||||
Version 3, 29 June 2007
|
|
||||||
|
|
||||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
|
||||||
Everyone is permitted to copy and distribute verbatim copies
|
|
||||||
of this license document, but changing it is not allowed.
|
|
||||||
|
|
||||||
|
|
||||||
This version of the GNU Lesser General Public License incorporates
|
|
||||||
the terms and conditions of version 3 of the GNU General Public
|
|
||||||
License, supplemented by the additional permissions listed below.
|
|
||||||
|
|
||||||
0. Additional Definitions.
|
|
||||||
|
|
||||||
As used herein, "this License" refers to version 3 of the GNU Lesser
|
|
||||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
|
||||||
General Public License.
|
|
||||||
|
|
||||||
"The Library" refers to a covered work governed by this License,
|
|
||||||
other than an Application or a Combined Work as defined below.
|
|
||||||
|
|
||||||
An "Application" is any work that makes use of an interface provided
|
|
||||||
by the Library, but which is not otherwise based on the Library.
|
|
||||||
Defining a subclass of a class defined by the Library is deemed a mode
|
|
||||||
of using an interface provided by the Library.
|
|
||||||
|
|
||||||
A "Combined Work" is a work produced by combining or linking an
|
|
||||||
Application with the Library. The particular version of the Library
|
|
||||||
with which the Combined Work was made is also called the "Linked
|
|
||||||
Version".
|
|
||||||
|
|
||||||
The "Minimal Corresponding Source" for a Combined Work means the
|
|
||||||
Corresponding Source for the Combined Work, excluding any source code
|
|
||||||
for portions of the Combined Work that, considered in isolation, are
|
|
||||||
based on the Application, and not on the Linked Version.
|
|
||||||
|
|
||||||
The "Corresponding Application Code" for a Combined Work means the
|
|
||||||
object code and/or source code for the Application, including any data
|
|
||||||
and utility programs needed for reproducing the Combined Work from the
|
|
||||||
Application, but excluding the System Libraries of the Combined Work.
|
|
||||||
|
|
||||||
1. Exception to Section 3 of the GNU GPL.
|
|
||||||
|
|
||||||
You may convey a covered work under sections 3 and 4 of this License
|
|
||||||
without being bound by section 3 of the GNU GPL.
|
|
||||||
|
|
||||||
2. Conveying Modified Versions.
|
|
||||||
|
|
||||||
If you modify a copy of the Library, and, in your modifications, a
|
|
||||||
facility refers to a function or data to be supplied by an Application
|
|
||||||
that uses the facility (other than as an argument passed when the
|
|
||||||
facility is invoked), then you may convey a copy of the modified
|
|
||||||
version:
|
|
||||||
|
|
||||||
a) under this License, provided that you make a good faith effort to
|
|
||||||
ensure that, in the event an Application does not supply the
|
|
||||||
function or data, the facility still operates, and performs
|
|
||||||
whatever part of its purpose remains meaningful, or
|
|
||||||
|
|
||||||
b) under the GNU GPL, with none of the additional permissions of
|
|
||||||
this License applicable to that copy.
|
|
||||||
|
|
||||||
3. Object Code Incorporating Material from Library Header Files.
|
|
||||||
|
|
||||||
The object code form of an Application may incorporate material from
|
|
||||||
a header file that is part of the Library. You may convey such object
|
|
||||||
code under terms of your choice, provided that, if the incorporated
|
|
||||||
material is not limited to numerical parameters, data structure
|
|
||||||
layouts and accessors, or small macros, inline functions and templates
|
|
||||||
(ten or fewer lines in length), you do both of the following:
|
|
||||||
|
|
||||||
a) Give prominent notice with each copy of the object code that the
|
|
||||||
Library is used in it and that the Library and its use are
|
|
||||||
covered by this License.
|
|
||||||
|
|
||||||
b) Accompany the object code with a copy of the GNU GPL and this license
|
|
||||||
document.
|
|
||||||
|
|
||||||
4. Combined Works.
|
|
||||||
|
|
||||||
You may convey a Combined Work under terms of your choice that,
|
|
||||||
taken together, effectively do not restrict modification of the
|
|
||||||
portions of the Library contained in the Combined Work and reverse
|
|
||||||
engineering for debugging such modifications, if you also do each of
|
|
||||||
the following:
|
|
||||||
|
|
||||||
a) Give prominent notice with each copy of the Combined Work that
|
|
||||||
the Library is used in it and that the Library and its use are
|
|
||||||
covered by this License.
|
|
||||||
|
|
||||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
|
||||||
document.
|
|
||||||
|
|
||||||
c) For a Combined Work that displays copyright notices during
|
|
||||||
execution, include the copyright notice for the Library among
|
|
||||||
these notices, as well as a reference directing the user to the
|
|
||||||
copies of the GNU GPL and this license document.
|
|
||||||
|
|
||||||
d) Do one of the following:
|
|
||||||
|
|
||||||
0) Convey the Minimal Corresponding Source under the terms of this
|
|
||||||
License, and the Corresponding Application Code in a form
|
|
||||||
suitable for, and under terms that permit, the user to
|
|
||||||
recombine or relink the Application with a modified version of
|
|
||||||
the Linked Version to produce a modified Combined Work, in the
|
|
||||||
manner specified by section 6 of the GNU GPL for conveying
|
|
||||||
Corresponding Source.
|
|
||||||
|
|
||||||
1) Use a suitable shared library mechanism for linking with the
|
|
||||||
Library. A suitable mechanism is one that (a) uses at run time
|
|
||||||
a copy of the Library already present on the user's computer
|
|
||||||
system, and (b) will operate properly with a modified version
|
|
||||||
of the Library that is interface-compatible with the Linked
|
|
||||||
Version.
|
|
||||||
|
|
||||||
e) Provide Installation Information, but only if you would otherwise
|
|
||||||
be required to provide such information under section 6 of the
|
|
||||||
GNU GPL, and only to the extent that such information is
|
|
||||||
necessary to install and execute a modified version of the
|
|
||||||
Combined Work produced by recombining or relinking the
|
|
||||||
Application with a modified version of the Linked Version. (If
|
|
||||||
you use option 4d0, the Installation Information must accompany
|
|
||||||
the Minimal Corresponding Source and Corresponding Application
|
|
||||||
Code. If you use option 4d1, you must provide the Installation
|
|
||||||
Information in the manner specified by section 6 of the GNU GPL
|
|
||||||
for conveying Corresponding Source.)
|
|
||||||
|
|
||||||
5. Combined Libraries.
|
|
||||||
|
|
||||||
You may place library facilities that are a work based on the
|
|
||||||
Library side by side in a single library together with other library
|
|
||||||
facilities that are not Applications and are not covered by this
|
|
||||||
License, and convey such a combined library under terms of your
|
|
||||||
choice, if you do both of the following:
|
|
||||||
|
|
||||||
a) Accompany the combined library with a copy of the same work based
|
|
||||||
on the Library, uncombined with any other library facilities,
|
|
||||||
conveyed under the terms of this License.
|
|
||||||
|
|
||||||
b) Give prominent notice with the combined library that part of it
|
|
||||||
is a work based on the Library, and explaining where to find the
|
|
||||||
accompanying uncombined form of the same work.
|
|
||||||
|
|
||||||
6. Revised Versions of the GNU Lesser General Public License.
|
|
||||||
|
|
||||||
The Free Software Foundation may publish revised and/or new versions
|
|
||||||
of the GNU Lesser General Public License from time to time. Such new
|
|
||||||
versions will be similar in spirit to the present version, but may
|
|
||||||
differ in detail to address new problems or concerns.
|
|
||||||
|
|
||||||
Each version is given a distinguishing version number. If the
|
|
||||||
Library as you received it specifies that a certain numbered version
|
|
||||||
of the GNU Lesser General Public License "or any later version"
|
|
||||||
applies to it, you have the option of following the terms and
|
|
||||||
conditions either of that published version or of any later version
|
|
||||||
published by the Free Software Foundation. If the Library as you
|
|
||||||
received it does not specify a version number of the GNU Lesser
|
|
||||||
General Public License, you may choose any version of the GNU Lesser
|
|
||||||
General Public License ever published by the Free Software Foundation.
|
|
||||||
|
|
||||||
If the Library as you received it specifies that a proxy can decide
|
|
||||||
whether future versions of the GNU Lesser General Public License shall
|
|
||||||
apply, that proxy's public statement of acceptance of any version is
|
|
||||||
permanent authorization for you to choose that version for the
|
|
||||||
Library.
|
|
||||||
|
|
||||||
**************************************************************************
|
|
||||||
|
|
||||||
GNU GENERAL PUBLIC LICENSE
|
|
||||||
Version 3, 29 June 2007
|
|
||||||
|
|
||||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
|
||||||
Everyone is permitted to copy and distribute verbatim copies
|
|
||||||
of this license document, but changing it is not allowed.
|
|
||||||
|
|
||||||
Preamble
|
|
||||||
|
|
||||||
The GNU General Public License is a free, copyleft license for
|
|
||||||
software and other kinds of works.
|
|
||||||
|
|
||||||
The licenses for most software and other practical works are designed
|
|
||||||
to take away your freedom to share and change the works. By contrast,
|
|
||||||
the GNU General Public License is intended to guarantee your freedom to
|
|
||||||
share and change all versions of a program--to make sure it remains free
|
|
||||||
software for all its users. We, the Free Software Foundation, use the
|
|
||||||
GNU General Public License for most of our software; it applies also to
|
|
||||||
any other work released this way by its authors. You can apply it to
|
|
||||||
your programs, too.
|
|
||||||
|
|
||||||
When we speak of free software, we are referring to freedom, not
|
|
||||||
price. Our General Public Licenses are designed to make sure that you
|
|
||||||
have the freedom to distribute copies of free software (and charge for
|
|
||||||
them if you wish), that you receive source code or can get it if you
|
|
||||||
want it, that you can change the software or use pieces of it in new
|
|
||||||
free programs, and that you know you can do these things.
|
|
||||||
|
|
||||||
To protect your rights, we need to prevent others from denying you
|
|
||||||
these rights or asking you to surrender the rights. Therefore, you have
|
|
||||||
certain responsibilities if you distribute copies of the software, or if
|
|
||||||
you modify it: responsibilities to respect the freedom of others.
|
|
||||||
|
|
||||||
For example, if you distribute copies of such a program, whether
|
|
||||||
gratis or for a fee, you must pass on to the recipients the same
|
|
||||||
freedoms that you received. You must make sure that they, too, receive
|
|
||||||
or can get the source code. And you must show them these terms so they
|
|
||||||
know their rights.
|
|
||||||
|
|
||||||
Developers that use the GNU GPL protect your rights with two steps:
|
|
||||||
(1) assert copyright on the software, and (2) offer you this License
|
|
||||||
giving you legal permission to copy, distribute and/or modify it.
|
|
||||||
|
|
||||||
For the developers' and authors' protection, the GPL clearly explains
|
|
||||||
that there is no warranty for this free software. For both users' and
|
|
||||||
authors' sake, the GPL requires that modified versions be marked as
|
|
||||||
changed, so that their problems will not be attributed erroneously to
|
|
||||||
authors of previous versions.
|
|
||||||
|
|
||||||
Some devices are designed to deny users access to install or run
|
|
||||||
modified versions of the software inside them, although the manufacturer
|
|
||||||
can do so. This is fundamentally incompatible with the aim of
|
|
||||||
protecting users' freedom to change the software. The systematic
|
|
||||||
pattern of such abuse occurs in the area of products for individuals to
|
|
||||||
use, which is precisely where it is most unacceptable. Therefore, we
|
|
||||||
have designed this version of the GPL to prohibit the practice for those
|
|
||||||
products. If such problems arise substantially in other domains, we
|
|
||||||
stand ready to extend this provision to those domains in future versions
|
|
||||||
of the GPL, as needed to protect the freedom of users.
|
|
||||||
|
|
||||||
Finally, every program is threatened constantly by software patents.
|
|
||||||
States should not allow patents to restrict development and use of
|
|
||||||
software on general-purpose computers, but in those that do, we wish to
|
|
||||||
avoid the special danger that patents applied to a free program could
|
|
||||||
make it effectively proprietary. To prevent this, the GPL assures that
|
|
||||||
patents cannot be used to render the program non-free.
|
|
||||||
|
|
||||||
The precise terms and conditions for copying, distribution and
|
|
||||||
modification follow.
|
|
||||||
|
|
||||||
TERMS AND CONDITIONS
|
|
||||||
|
|
||||||
0. Definitions.
|
|
||||||
|
|
||||||
"This License" refers to version 3 of the GNU General Public License.
|
|
||||||
|
|
||||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
|
||||||
works, such as semiconductor masks.
|
|
||||||
|
|
||||||
"The Program" refers to any copyrightable work licensed under this
|
|
||||||
License. Each licensee is addressed as "you". "Licensees" and
|
|
||||||
"recipients" may be individuals or organizations.
|
|
||||||
|
|
||||||
To "modify" a work means to copy from or adapt all or part of the work
|
|
||||||
in a fashion requiring copyright permission, other than the making of an
|
|
||||||
exact copy. The resulting work is called a "modified version" of the
|
|
||||||
earlier work or a work "based on" the earlier work.
|
|
||||||
|
|
||||||
A "covered work" means either the unmodified Program or a work based
|
|
||||||
on the Program.
|
|
||||||
|
|
||||||
To "propagate" a work means to do anything with it that, without
|
|
||||||
permission, would make you directly or secondarily liable for
|
|
||||||
infringement under applicable copyright law, except executing it on a
|
|
||||||
computer or modifying a private copy. Propagation includes copying,
|
|
||||||
distribution (with or without modification), making available to the
|
|
||||||
public, and in some countries other activities as well.
|
|
||||||
|
|
||||||
To "convey" a work means any kind of propagation that enables other
|
|
||||||
parties to make or receive copies. Mere interaction with a user through
|
|
||||||
a computer network, with no transfer of a copy, is not conveying.
|
|
||||||
|
|
||||||
An interactive user interface displays "Appropriate Legal Notices"
|
|
||||||
to the extent that it includes a convenient and prominently visible
|
|
||||||
feature that (1) displays an appropriate copyright notice, and (2)
|
|
||||||
tells the user that there is no warranty for the work (except to the
|
|
||||||
extent that warranties are provided), that licensees may convey the
|
|
||||||
work under this License, and how to view a copy of this License. If
|
|
||||||
the interface presents a list of user commands or options, such as a
|
|
||||||
menu, a prominent item in the list meets this criterion.
|
|
||||||
|
|
||||||
1. Source Code.
|
|
||||||
|
|
||||||
The "source code" for a work means the preferred form of the work
|
|
||||||
for making modifications to it. "Object code" means any non-source
|
|
||||||
form of a work.
|
|
||||||
|
|
||||||
A "Standard Interface" means an interface that either is an official
|
|
||||||
standard defined by a recognized standards body, or, in the case of
|
|
||||||
interfaces specified for a particular programming language, one that
|
|
||||||
is widely used among developers working in that language.
|
|
||||||
|
|
||||||
The "System Libraries" of an executable work include anything, other
|
|
||||||
than the work as a whole, that (a) is included in the normal form of
|
|
||||||
packaging a Major Component, but which is not part of that Major
|
|
||||||
Component, and (b) serves only to enable use of the work with that
|
|
||||||
Major Component, or to implement a Standard Interface for which an
|
|
||||||
implementation is available to the public in source code form. A
|
|
||||||
"Major Component", in this context, means a major essential component
|
|
||||||
(kernel, window system, and so on) of the specific operating system
|
|
||||||
(if any) on which the executable work runs, or a compiler used to
|
|
||||||
produce the work, or an object code interpreter used to run it.
|
|
||||||
|
|
||||||
The "Corresponding Source" for a work in object code form means all
|
|
||||||
the source code needed to generate, install, and (for an executable
|
|
||||||
work) run the object code and to modify the work, including scripts to
|
|
||||||
control those activities. However, it does not include the work's
|
|
||||||
System Libraries, or general-purpose tools or generally available free
|
|
||||||
programs which are used unmodified in performing those activities but
|
|
||||||
which are not part of the work. For example, Corresponding Source
|
|
||||||
includes interface definition files associated with source files for
|
|
||||||
the work, and the source code for shared libraries and dynamically
|
|
||||||
linked subprograms that the work is specifically designed to require,
|
|
||||||
such as by intimate data communication or control flow between those
|
|
||||||
subprograms and other parts of the work.
|
|
||||||
|
|
||||||
The Corresponding Source need not include anything that users
|
|
||||||
can regenerate automatically from other parts of the Corresponding
|
|
||||||
Source.
|
|
||||||
|
|
||||||
The Corresponding Source for a work in source code form is that
|
|
||||||
same work.
|
|
||||||
|
|
||||||
2. Basic Permissions.
|
|
||||||
|
|
||||||
All rights granted under this License are granted for the term of
|
|
||||||
copyright on the Program, and are irrevocable provided the stated
|
|
||||||
conditions are met. This License explicitly affirms your unlimited
|
|
||||||
permission to run the unmodified Program. The output from running a
|
|
||||||
covered work is covered by this License only if the output, given its
|
|
||||||
content, constitutes a covered work. This License acknowledges your
|
|
||||||
rights of fair use or other equivalent, as provided by copyright law.
|
|
||||||
|
|
||||||
You may make, run and propagate covered works that you do not
|
|
||||||
convey, without conditions so long as your license otherwise remains
|
|
||||||
in force. You may convey covered works to others for the sole purpose
|
|
||||||
of having them make modifications exclusively for you, or provide you
|
|
||||||
with facilities for running those works, provided that you comply with
|
|
||||||
the terms of this License in conveying all material for which you do
|
|
||||||
not control copyright. Those thus making or running the covered works
|
|
||||||
for you must do so exclusively on your behalf, under your direction
|
|
||||||
and control, on terms that prohibit them from making any copies of
|
|
||||||
your copyrighted material outside their relationship with you.
|
|
||||||
|
|
||||||
Conveying under any other circumstances is permitted solely under
|
|
||||||
the conditions stated below. Sublicensing is not allowed; section 10
|
|
||||||
makes it unnecessary.
|
|
||||||
|
|
||||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
|
||||||
|
|
||||||
No covered work shall be deemed part of an effective technological
|
|
||||||
measure under any applicable law fulfilling obligations under article
|
|
||||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
|
||||||
similar laws prohibiting or restricting circumvention of such
|
|
||||||
measures.
|
|
||||||
|
|
||||||
When you convey a covered work, you waive any legal power to forbid
|
|
||||||
circumvention of technological measures to the extent such circumvention
|
|
||||||
is effected by exercising rights under this License with respect to
|
|
||||||
the covered work, and you disclaim any intention to limit operation or
|
|
||||||
modification of the work as a means of enforcing, against the work's
|
|
||||||
users, your or third parties' legal rights to forbid circumvention of
|
|
||||||
technological measures.
|
|
||||||
|
|
||||||
4. Conveying Verbatim Copies.
|
|
||||||
|
|
||||||
You may convey verbatim copies of the Program's source code as you
|
|
||||||
receive it, in any medium, provided that you conspicuously and
|
|
||||||
appropriately publish on each copy an appropriate copyright notice;
|
|
||||||
keep intact all notices stating that this License and any
|
|
||||||
non-permissive terms added in accord with section 7 apply to the code;
|
|
||||||
keep intact all notices of the absence of any warranty; and give all
|
|
||||||
recipients a copy of this License along with the Program.
|
|
||||||
|
|
||||||
You may charge any price or no price for each copy that you convey,
|
|
||||||
and you may offer support or warranty protection for a fee.
|
|
||||||
|
|
||||||
5. Conveying Modified Source Versions.
|
|
||||||
|
|
||||||
You may convey a work based on the Program, or the modifications to
|
|
||||||
produce it from the Program, in the form of source code under the
|
|
||||||
terms of section 4, provided that you also meet all of these conditions:
|
|
||||||
|
|
||||||
a) The work must carry prominent notices stating that you modified
|
|
||||||
it, and giving a relevant date.
|
|
||||||
|
|
||||||
b) The work must carry prominent notices stating that it is
|
|
||||||
released under this License and any conditions added under section
|
|
||||||
7. This requirement modifies the requirement in section 4 to
|
|
||||||
"keep intact all notices".
|
|
||||||
|
|
||||||
c) You must license the entire work, as a whole, under this
|
|
||||||
License to anyone who comes into possession of a copy. This
|
|
||||||
License will therefore apply, along with any applicable section 7
|
|
||||||
additional terms, to the whole of the work, and all its parts,
|
|
||||||
regardless of how they are packaged. This License gives no
|
|
||||||
permission to license the work in any other way, but it does not
|
|
||||||
invalidate such permission if you have separately received it.
|
|
||||||
|
|
||||||
d) If the work has interactive user interfaces, each must display
|
|
||||||
Appropriate Legal Notices; however, if the Program has interactive
|
|
||||||
interfaces that do not display Appropriate Legal Notices, your
|
|
||||||
work need not make them do so.
|
|
||||||
|
|
||||||
A compilation of a covered work with other separate and independent
|
|
||||||
works, which are not by their nature extensions of the covered work,
|
|
||||||
and which are not combined with it such as to form a larger program,
|
|
||||||
in or on a volume of a storage or distribution medium, is called an
|
|
||||||
"aggregate" if the compilation and its resulting copyright are not
|
|
||||||
used to limit the access or legal rights of the compilation's users
|
|
||||||
beyond what the individual works permit. Inclusion of a covered work
|
|
||||||
in an aggregate does not cause this License to apply to the other
|
|
||||||
parts of the aggregate.
|
|
||||||
|
|
||||||
6. Conveying Non-Source Forms.
|
|
||||||
|
|
||||||
You may convey a covered work in object code form under the terms
|
|
||||||
of sections 4 and 5, provided that you also convey the
|
|
||||||
machine-readable Corresponding Source under the terms of this License,
|
|
||||||
in one of these ways:
|
|
||||||
|
|
||||||
a) Convey the object code in, or embodied in, a physical product
|
|
||||||
(including a physical distribution medium), accompanied by the
|
|
||||||
Corresponding Source fixed on a durable physical medium
|
|
||||||
customarily used for software interchange.
|
|
||||||
|
|
||||||
b) Convey the object code in, or embodied in, a physical product
|
|
||||||
(including a physical distribution medium), accompanied by a
|
|
||||||
written offer, valid for at least three years and valid for as
|
|
||||||
long as you offer spare parts or customer support for that product
|
|
||||||
model, to give anyone who possesses the object code either (1) a
|
|
||||||
copy of the Corresponding Source for all the software in the
|
|
||||||
product that is covered by this License, on a durable physical
|
|
||||||
medium customarily used for software interchange, for a price no
|
|
||||||
more than your reasonable cost of physically performing this
|
|
||||||
conveying of source, or (2) access to copy the
|
|
||||||
Corresponding Source from a network server at no charge.
|
|
||||||
|
|
||||||
c) Convey individual copies of the object code with a copy of the
|
|
||||||
written offer to provide the Corresponding Source. This
|
|
||||||
alternative is allowed only occasionally and noncommercially, and
|
|
||||||
only if you received the object code with such an offer, in accord
|
|
||||||
with subsection 6b.
|
|
||||||
|
|
||||||
d) Convey the object code by offering access from a designated
|
|
||||||
place (gratis or for a charge), and offer equivalent access to the
|
|
||||||
Corresponding Source in the same way through the same place at no
|
|
||||||
further charge. You need not require recipients to copy the
|
|
||||||
Corresponding Source along with the object code. If the place to
|
|
||||||
copy the object code is a network server, the Corresponding Source
|
|
||||||
may be on a different server (operated by you or a third party)
|
|
||||||
that supports equivalent copying facilities, provided you maintain
|
|
||||||
clear directions next to the object code saying where to find the
|
|
||||||
Corresponding Source. Regardless of what server hosts the
|
|
||||||
Corresponding Source, you remain obligated to ensure that it is
|
|
||||||
available for as long as needed to satisfy these requirements.
|
|
||||||
|
|
||||||
e) Convey the object code using peer-to-peer transmission, provided
|
|
||||||
you inform other peers where the object code and Corresponding
|
|
||||||
Source of the work are being offered to the general public at no
|
|
||||||
charge under subsection 6d.
|
|
||||||
|
|
||||||
A separable portion of the object code, whose source code is excluded
|
|
||||||
from the Corresponding Source as a System Library, need not be
|
|
||||||
included in conveying the object code work.
|
|
||||||
|
|
||||||
A "User Product" is either (1) a "consumer product", which means any
|
|
||||||
tangible personal property which is normally used for personal, family,
|
|
||||||
or household purposes, or (2) anything designed or sold for incorporation
|
|
||||||
into a dwelling. In determining whether a product is a consumer product,
|
|
||||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
|
||||||
product received by a particular user, "normally used" refers to a
|
|
||||||
typical or common use of that class of product, regardless of the status
|
|
||||||
of the particular user or of the way in which the particular user
|
|
||||||
actually uses, or expects or is expected to use, the product. A product
|
|
||||||
is a consumer product regardless of whether the product has substantial
|
|
||||||
commercial, industrial or non-consumer uses, unless such uses represent
|
|
||||||
the only significant mode of use of the product.
|
|
||||||
|
|
||||||
"Installation Information" for a User Product means any methods,
|
|
||||||
procedures, authorization keys, or other information required to install
|
|
||||||
and execute modified versions of a covered work in that User Product from
|
|
||||||
a modified version of its Corresponding Source. The information must
|
|
||||||
suffice to ensure that the continued functioning of the modified object
|
|
||||||
code is in no case prevented or interfered with solely because
|
|
||||||
modification has been made.
|
|
||||||
|
|
||||||
If you convey an object code work under this section in, or with, or
|
|
||||||
specifically for use in, a User Product, and the conveying occurs as
|
|
||||||
part of a transaction in which the right of possession and use of the
|
|
||||||
User Product is transferred to the recipient in perpetuity or for a
|
|
||||||
fixed term (regardless of how the transaction is characterized), the
|
|
||||||
Corresponding Source conveyed under this section must be accompanied
|
|
||||||
by the Installation Information. But this requirement does not apply
|
|
||||||
if neither you nor any third party retains the ability to install
|
|
||||||
modified object code on the User Product (for example, the work has
|
|
||||||
been installed in ROM).
|
|
||||||
|
|
||||||
The requirement to provide Installation Information does not include a
|
|
||||||
requirement to continue to provide support service, warranty, or updates
|
|
||||||
for a work that has been modified or installed by the recipient, or for
|
|
||||||
the User Product in which it has been modified or installed. Access to a
|
|
||||||
network may be denied when the modification itself materially and
|
|
||||||
adversely affects the operation of the network or violates the rules and
|
|
||||||
protocols for communication across the network.
|
|
||||||
|
|
||||||
Corresponding Source conveyed, and Installation Information provided,
|
|
||||||
in accord with this section must be in a format that is publicly
|
|
||||||
documented (and with an implementation available to the public in
|
|
||||||
source code form), and must require no special password or key for
|
|
||||||
unpacking, reading or copying.
|
|
||||||
|
|
||||||
7. Additional Terms.
|
|
||||||
|
|
||||||
"Additional permissions" are terms that supplement the terms of this
|
|
||||||
License by making exceptions from one or more of its conditions.
|
|
||||||
Additional permissions that are applicable to the entire Program shall
|
|
||||||
be treated as though they were included in this License, to the extent
|
|
||||||
that they are valid under applicable law. If additional permissions
|
|
||||||
apply only to part of the Program, that part may be used separately
|
|
||||||
under those permissions, but the entire Program remains governed by
|
|
||||||
this License without regard to the additional permissions.
|
|
||||||
|
|
||||||
When you convey a copy of a covered work, you may at your option
|
|
||||||
remove any additional permissions from that copy, or from any part of
|
|
||||||
it. (Additional permissions may be written to require their own
|
|
||||||
removal in certain cases when you modify the work.) You may place
|
|
||||||
additional permissions on material, added by you to a covered work,
|
|
||||||
for which you have or can give appropriate copyright permission.
|
|
||||||
|
|
||||||
Notwithstanding any other provision of this License, for material you
|
|
||||||
add to a covered work, you may (if authorized by the copyright holders of
|
|
||||||
that material) supplement the terms of this License with terms:
|
|
||||||
|
|
||||||
a) Disclaiming warranty or limiting liability differently from the
|
|
||||||
terms of sections 15 and 16 of this License; or
|
|
||||||
|
|
||||||
b) Requiring preservation of specified reasonable legal notices or
|
|
||||||
author attributions in that material or in the Appropriate Legal
|
|
||||||
Notices displayed by works containing it; or
|
|
||||||
|
|
||||||
c) Prohibiting misrepresentation of the origin of that material, or
|
|
||||||
requiring that modified versions of such material be marked in
|
|
||||||
reasonable ways as different from the original version; or
|
|
||||||
|
|
||||||
d) Limiting the use for publicity purposes of names of licensors or
|
|
||||||
authors of the material; or
|
|
||||||
|
|
||||||
e) Declining to grant rights under trademark law for use of some
|
|
||||||
trade names, trademarks, or service marks; or
|
|
||||||
|
|
||||||
f) Requiring indemnification of licensors and authors of that
|
|
||||||
material by anyone who conveys the material (or modified versions of
|
|
||||||
it) with contractual assumptions of liability to the recipient, for
|
|
||||||
any liability that these contractual assumptions directly impose on
|
|
||||||
those licensors and authors.
|
|
||||||
|
|
||||||
All other non-permissive additional terms are considered "further
|
|
||||||
restrictions" within the meaning of section 10. If the Program as you
|
|
||||||
received it, or any part of it, contains a notice stating that it is
|
|
||||||
governed by this License along with a term that is a further
|
|
||||||
restriction, you may remove that term. If a license document contains
|
|
||||||
a further restriction but permits relicensing or conveying under this
|
|
||||||
License, you may add to a covered work material governed by the terms
|
|
||||||
of that license document, provided that the further restriction does
|
|
||||||
not survive such relicensing or conveying.
|
|
||||||
|
|
||||||
If you add terms to a covered work in accord with this section, you
|
|
||||||
must place, in the relevant source files, a statement of the
|
|
||||||
additional terms that apply to those files, or a notice indicating
|
|
||||||
where to find the applicable terms.
|
|
||||||
|
|
||||||
Additional terms, permissive or non-permissive, may be stated in the
|
|
||||||
form of a separately written license, or stated as exceptions;
|
|
||||||
the above requirements apply either way.
|
|
||||||
|
|
||||||
8. Termination.
|
|
||||||
|
|
||||||
You may not propagate or modify a covered work except as expressly
|
|
||||||
provided under this License. Any attempt otherwise to propagate or
|
|
||||||
modify it is void, and will automatically terminate your rights under
|
|
||||||
this License (including any patent licenses granted under the third
|
|
||||||
paragraph of section 11).
|
|
||||||
|
|
||||||
However, if you cease all violation of this License, then your
|
|
||||||
license from a particular copyright holder is reinstated (a)
|
|
||||||
provisionally, unless and until the copyright holder explicitly and
|
|
||||||
finally terminates your license, and (b) permanently, if the copyright
|
|
||||||
holder fails to notify you of the violation by some reasonable means
|
|
||||||
prior to 60 days after the cessation.
|
|
||||||
|
|
||||||
Moreover, your license from a particular copyright holder is
|
|
||||||
reinstated permanently if the copyright holder notifies you of the
|
|
||||||
violation by some reasonable means, this is the first time you have
|
|
||||||
received notice of violation of this License (for any work) from that
|
|
||||||
copyright holder, and you cure the violation prior to 30 days after
|
|
||||||
your receipt of the notice.
|
|
||||||
|
|
||||||
Termination of your rights under this section does not terminate the
|
|
||||||
licenses of parties who have received copies or rights from you under
|
|
||||||
this License. If your rights have been terminated and not permanently
|
|
||||||
reinstated, you do not qualify to receive new licenses for the same
|
|
||||||
material under section 10.
|
|
||||||
|
|
||||||
9. Acceptance Not Required for Having Copies.
|
|
||||||
|
|
||||||
You are not required to accept this License in order to receive or
|
|
||||||
run a copy of the Program. Ancillary propagation of a covered work
|
|
||||||
occurring solely as a consequence of using peer-to-peer transmission
|
|
||||||
to receive a copy likewise does not require acceptance. However,
|
|
||||||
nothing other than this License grants you permission to propagate or
|
|
||||||
modify any covered work. These actions infringe copyright if you do
|
|
||||||
not accept this License. Therefore, by modifying or propagating a
|
|
||||||
covered work, you indicate your acceptance of this License to do so.
|
|
||||||
|
|
||||||
10. Automatic Licensing of Downstream Recipients.
|
|
||||||
|
|
||||||
Each time you convey a covered work, the recipient automatically
|
|
||||||
receives a license from the original licensors, to run, modify and
|
|
||||||
propagate that work, subject to this License. You are not responsible
|
|
||||||
for enforcing compliance by third parties with this License.
|
|
||||||
|
|
||||||
An "entity transaction" is a transaction transferring control of an
|
|
||||||
organization, or substantially all assets of one, or subdividing an
|
|
||||||
organization, or merging organizations. If propagation of a covered
|
|
||||||
work results from an entity transaction, each party to that
|
|
||||||
transaction who receives a copy of the work also receives whatever
|
|
||||||
licenses to the work the party's predecessor in interest had or could
|
|
||||||
give under the previous paragraph, plus a right to possession of the
|
|
||||||
Corresponding Source of the work from the predecessor in interest, if
|
|
||||||
the predecessor has it or can get it with reasonable efforts.
|
|
||||||
|
|
||||||
You may not impose any further restrictions on the exercise of the
|
|
||||||
rights granted or affirmed under this License. For example, you may
|
|
||||||
not impose a license fee, royalty, or other charge for exercise of
|
|
||||||
rights granted under this License, and you may not initiate litigation
|
|
||||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
|
||||||
any patent claim is infringed by making, using, selling, offering for
|
|
||||||
sale, or importing the Program or any portion of it.
|
|
||||||
|
|
||||||
11. Patents.
|
|
||||||
|
|
||||||
A "contributor" is a copyright holder who authorizes use under this
|
|
||||||
License of the Program or a work on which the Program is based. The
|
|
||||||
work thus licensed is called the contributor's "contributor version".
|
|
||||||
|
|
||||||
A contributor's "essential patent claims" are all patent claims
|
|
||||||
owned or controlled by the contributor, whether already acquired or
|
|
||||||
hereafter acquired, that would be infringed by some manner, permitted
|
|
||||||
by this License, of making, using, or selling its contributor version,
|
|
||||||
but do not include claims that would be infringed only as a
|
|
||||||
consequence of further modification of the contributor version. For
|
|
||||||
purposes of this definition, "control" includes the right to grant
|
|
||||||
patent sublicenses in a manner consistent with the requirements of
|
|
||||||
this License.
|
|
||||||
|
|
||||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
|
||||||
patent license under the contributor's essential patent claims, to
|
|
||||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
|
||||||
propagate the contents of its contributor version.
|
|
||||||
|
|
||||||
In the following three paragraphs, a "patent license" is any express
|
|
||||||
agreement or commitment, however denominated, not to enforce a patent
|
|
||||||
(such as an express permission to practice a patent or covenant not to
|
|
||||||
sue for patent infringement). To "grant" such a patent license to a
|
|
||||||
party means to make such an agreement or commitment not to enforce a
|
|
||||||
patent against the party.
|
|
||||||
|
|
||||||
If you convey a covered work, knowingly relying on a patent license,
|
|
||||||
and the Corresponding Source of the work is not available for anyone
|
|
||||||
to copy, free of charge and under the terms of this License, through a
|
|
||||||
publicly available network server or other readily accessible means,
|
|
||||||
then you must either (1) cause the Corresponding Source to be so
|
|
||||||
available, or (2) arrange to deprive yourself of the benefit of the
|
|
||||||
patent license for this particular work, or (3) arrange, in a manner
|
|
||||||
consistent with the requirements of this License, to extend the patent
|
|
||||||
license to downstream recipients. "Knowingly relying" means you have
|
|
||||||
actual knowledge that, but for the patent license, your conveying the
|
|
||||||
covered work in a country, or your recipient's use of the covered work
|
|
||||||
in a country, would infringe one or more identifiable patents in that
|
|
||||||
country that you have reason to believe are valid.
|
|
||||||
|
|
||||||
If, pursuant to or in connection with a single transaction or
|
|
||||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
|
||||||
covered work, and grant a patent license to some of the parties
|
|
||||||
receiving the covered work authorizing them to use, propagate, modify
|
|
||||||
or convey a specific copy of the covered work, then the patent license
|
|
||||||
you grant is automatically extended to all recipients of the covered
|
|
||||||
work and works based on it.
|
|
||||||
|
|
||||||
A patent license is "discriminatory" if it does not include within
|
|
||||||
the scope of its coverage, prohibits the exercise of, or is
|
|
||||||
conditioned on the non-exercise of one or more of the rights that are
|
|
||||||
specifically granted under this License. You may not convey a covered
|
|
||||||
work if you are a party to an arrangement with a third party that is
|
|
||||||
in the business of distributing software, under which you make payment
|
|
||||||
to the third party based on the extent of your activity of conveying
|
|
||||||
the work, and under which the third party grants, to any of the
|
|
||||||
parties who would receive the covered work from you, a discriminatory
|
|
||||||
patent license (a) in connection with copies of the covered work
|
|
||||||
conveyed by you (or copies made from those copies), or (b) primarily
|
|
||||||
for and in connection with specific products or compilations that
|
|
||||||
contain the covered work, unless you entered into that arrangement,
|
|
||||||
or that patent license was granted, prior to 28 March 2007.
|
|
||||||
|
|
||||||
Nothing in this License shall be construed as excluding or limiting
|
|
||||||
any implied license or other defenses to infringement that may
|
|
||||||
otherwise be available to you under applicable patent law.
|
|
||||||
|
|
||||||
12. No Surrender of Others' Freedom.
|
|
||||||
|
|
||||||
If conditions are imposed on you (whether by court order, agreement or
|
|
||||||
otherwise) that contradict the conditions of this License, they do not
|
|
||||||
excuse you from the conditions of this License. If you cannot convey a
|
|
||||||
covered work so as to satisfy simultaneously your obligations under this
|
|
||||||
License and any other pertinent obligations, then as a consequence you may
|
|
||||||
not convey it at all. For example, if you agree to terms that obligate you
|
|
||||||
to collect a royalty for further conveying from those to whom you convey
|
|
||||||
the Program, the only way you could satisfy both those terms and this
|
|
||||||
License would be to refrain entirely from conveying the Program.
|
|
||||||
|
|
||||||
13. Use with the GNU Affero General Public License.
|
|
||||||
|
|
||||||
Notwithstanding any other provision of this License, you have
|
|
||||||
permission to link or combine any covered work with a work licensed
|
|
||||||
under version 3 of the GNU Affero General Public License into a single
|
|
||||||
combined work, and to convey the resulting work. The terms of this
|
|
||||||
License will continue to apply to the part which is the covered work,
|
|
||||||
but the special requirements of the GNU Affero General Public License,
|
|
||||||
section 13, concerning interaction through a network will apply to the
|
|
||||||
combination as such.
|
|
||||||
|
|
||||||
14. Revised Versions of this License.
|
|
||||||
|
|
||||||
The Free Software Foundation may publish revised and/or new versions of
|
|
||||||
the GNU General Public License from time to time. Such new versions will
|
|
||||||
be similar in spirit to the present version, but may differ in detail to
|
|
||||||
address new problems or concerns.
|
|
||||||
|
|
||||||
Each version is given a distinguishing version number. If the
|
|
||||||
Program specifies that a certain numbered version of the GNU General
|
|
||||||
Public License "or any later version" applies to it, you have the
|
|
||||||
option of following the terms and conditions either of that numbered
|
|
||||||
version or of any later version published by the Free Software
|
|
||||||
Foundation. If the Program does not specify a version number of the
|
|
||||||
GNU General Public License, you may choose any version ever published
|
|
||||||
by the Free Software Foundation.
|
|
||||||
|
|
||||||
If the Program specifies that a proxy can decide which future
|
|
||||||
versions of the GNU General Public License can be used, that proxy's
|
|
||||||
public statement of acceptance of a version permanently authorizes you
|
|
||||||
to choose that version for the Program.
|
|
||||||
|
|
||||||
Later license versions may give you additional or different
|
|
||||||
permissions. However, no additional obligations are imposed on any
|
|
||||||
author or copyright holder as a result of your choosing to follow a
|
|
||||||
later version.
|
|
||||||
|
|
||||||
15. Disclaimer of Warranty.
|
|
||||||
|
|
||||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
|
||||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
|
||||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
|
||||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
|
||||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
||||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
|
||||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
|
||||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
|
||||||
|
|
||||||
16. Limitation of Liability.
|
|
||||||
|
|
||||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
|
||||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
|
||||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
|
||||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
|
||||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
|
||||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
|
||||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
|
||||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
|
||||||
SUCH DAMAGES.
|
|
||||||
|
|
||||||
17. Interpretation of Sections 15 and 16.
|
|
||||||
|
|
||||||
If the disclaimer of warranty and limitation of liability provided
|
|
||||||
above cannot be given local legal effect according to their terms,
|
|
||||||
reviewing courts shall apply local law that most closely approximates
|
|
||||||
an absolute waiver of all civil liability in connection with the
|
|
||||||
Program, unless a warranty or assumption of liability accompanies a
|
|
||||||
copy of the Program in return for a fee.
|
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
|
||||||
|
|
||||||
How to Apply These Terms to Your New Programs
|
|
||||||
|
|
||||||
If you develop a new program, and you want it to be of the greatest
|
|
||||||
possible use to the public, the best way to achieve this is to make it
|
|
||||||
free software which everyone can redistribute and change under these terms.
|
|
||||||
|
|
||||||
To do so, attach the following notices to the program. It is safest
|
|
||||||
to attach them to the start of each source file to most effectively
|
|
||||||
state the exclusion of warranty; and each file should have at least
|
|
||||||
the "copyright" line and a pointer to where the full notice is found.
|
|
||||||
|
|
||||||
<one line to give the program's name and a brief idea of what it does.>
|
|
||||||
Copyright (C) <year> <name of author>
|
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
Also add information on how to contact you by electronic and paper mail.
|
|
||||||
|
|
||||||
If the program does terminal interaction, make it output a short
|
|
||||||
notice like this when it starts in an interactive mode:
|
|
||||||
|
|
||||||
<program> Copyright (C) <year> <name of author>
|
|
||||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
|
||||||
This is free software, and you are welcome to redistribute it
|
|
||||||
under certain conditions; type `show c' for details.
|
|
||||||
|
|
||||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
|
||||||
parts of the General Public License. Of course, your program's commands
|
|
||||||
might be different; for a GUI interface, you would use an "about box".
|
|
||||||
|
|
||||||
You should also get your employer (if you work as a programmer) or school,
|
|
||||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
|
||||||
For more information on this, and how to apply and follow the GNU GPL, see
|
|
||||||
<http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
The GNU General Public License does not permit incorporating your program
|
|
||||||
into proprietary programs. If your program is a subroutine library, you
|
|
||||||
may consider it more useful to permit linking proprietary applications with
|
|
||||||
the library. If this is what you want to do, use the GNU Lesser General
|
|
||||||
Public License instead of this License. But first, please read
|
|
||||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
|
||||||
|
|
||||||
|
|
||||||
**************************************************************************
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
# 🦉 Owl Vision 🕶️
|
|
||||||
|
|
||||||
Owl Vision is an extension for the amazing [Owl framework](https://github.com/odoo/owl) that complements your templates with beautiful colors and allows you to more easily navigate between components and templates.
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
This extension also adds:
|
|
||||||
- A basic component snippent.
|
|
||||||
- "Go to definition" providers for component tags in xml or in inline templates.
|
|
||||||
|
|
||||||
## Commands
|
|
||||||
|
|
||||||
* `Owl Vision: Find Template`:
|
|
||||||
- If the cursor is on a template name, finds the corresponding template.
|
|
||||||
- If the cursor is on a component, finds the template of the selected component.
|
|
||||||
* `Owl Vision: Find Component`: Finds the selected component definition.
|
|
||||||
* `Owl Vision: Switch`: Finds the corresponding template or component depending on the current file.
|
|
||||||
* `Owl Vision: Switch (Besides)`: Finds the corresponding template or component depending on the current file and opens it besides.
|
|
||||||
* `Owl Vision: Switch (Below)`: Finds the corresponding template or component depending on the current file and opens it below.
|
|
||||||
|
|
||||||
## Settings
|
|
||||||
|
|
||||||
* `owl-vision.include`: Glob filter for files to include while searching.
|
|
||||||
* `owl-vision.exclude`: Glob filter for files to exclude while searching.
|
|
||||||
|
|
||||||
## Troubleshooting
|
|
||||||
|
|
||||||
### *The extension cannot find my templates/components*
|
|
||||||
|
|
||||||
The include and exclude settings have default values that may not work with your project structure, try adapting them.
|
|
||||||
|
Before Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 138 KiB |
@@ -1,139 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "owl-vision",
|
|
||||||
"displayName": "Owl Vision",
|
|
||||||
"description": "Owl framework extension that highlights templates and ease navigation between components and templates.",
|
|
||||||
"publisher": "Odoo",
|
|
||||||
"license": "LGPL-3.0-only",
|
|
||||||
"version": "0.0.2",
|
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://github.com/odoo/owl/tree/master/tools/owl-vision"
|
|
||||||
},
|
|
||||||
"icon": "assets/icon128.png",
|
|
||||||
"engines": {
|
|
||||||
"vscode": "^1.73.0"
|
|
||||||
},
|
|
||||||
"categories": [
|
|
||||||
"Other"
|
|
||||||
],
|
|
||||||
"activationEvents": [
|
|
||||||
"onLanguage:xml",
|
|
||||||
"onLanguage:js"
|
|
||||||
],
|
|
||||||
"main": "./out/main.js",
|
|
||||||
"contributes": {
|
|
||||||
"commands": [
|
|
||||||
{
|
|
||||||
"command": "owl-vision.switch",
|
|
||||||
"title": "Switch",
|
|
||||||
"category": "Owl Vision"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "owl-vision.switch-besides",
|
|
||||||
"title": "Switch (Besides)",
|
|
||||||
"category": "Owl Vision"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "owl-vision.switch-below",
|
|
||||||
"title": "Switch (Below)",
|
|
||||||
"category": "Owl Vision"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "owl-vision.find-component",
|
|
||||||
"title": "Find Component",
|
|
||||||
"category": "Owl Vision"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "owl-vision.find-template",
|
|
||||||
"title": "Find Template",
|
|
||||||
"category": "Owl Vision"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"configuration": {
|
|
||||||
"title": "Owl Vision",
|
|
||||||
"properties": {
|
|
||||||
"owl-vision.include": {
|
|
||||||
"order": 0,
|
|
||||||
"type": "string",
|
|
||||||
"default": "**/*.js,**/*.ts,**/*.mjs,**/static/**/*.xml",
|
|
||||||
"description": "Files to include in search"
|
|
||||||
},
|
|
||||||
"owl-vision.exclude": {
|
|
||||||
"order": 1,
|
|
||||||
"type": "string",
|
|
||||||
"default": "**/node_modules/**,**/lib/**,**/tests/**",
|
|
||||||
"description": "Files to exclude in search"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"snippets": [
|
|
||||||
{
|
|
||||||
"language": "javascript",
|
|
||||||
"path": "./snippets/component.json"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"grammars": [
|
|
||||||
{
|
|
||||||
"scopeName": "owl.template",
|
|
||||||
"path": "./syntaxes/owl.template.json",
|
|
||||||
"embeddedLanguages": {
|
|
||||||
"meta.embedded.block.javascript": "source.js"
|
|
||||||
},
|
|
||||||
"injectTo": [
|
|
||||||
"text.xml"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"scopeName": "owl.template.inline",
|
|
||||||
"path": "./syntaxes/owl.template.inline.json",
|
|
||||||
"embeddedLanguages": {
|
|
||||||
"meta.embedded.block.xml": "xml"
|
|
||||||
},
|
|
||||||
"injectTo": [
|
|
||||||
"source.js",
|
|
||||||
"source.jsx",
|
|
||||||
"source.ts",
|
|
||||||
"source.tsx",
|
|
||||||
"text.html"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"scopeName": "owl.markup.inline",
|
|
||||||
"path": "./syntaxes/owl.markup.inline.json",
|
|
||||||
"embeddedLanguages": {
|
|
||||||
"meta.embedded.block.html": "html"
|
|
||||||
},
|
|
||||||
"injectTo": [
|
|
||||||
"source.js",
|
|
||||||
"source.jsx",
|
|
||||||
"source.ts",
|
|
||||||
"source.tsx",
|
|
||||||
"text.html"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"scripts": {
|
|
||||||
"compile": "tsc -p ./",
|
|
||||||
"package": "vsce package",
|
|
||||||
"watch": "tsc -watch -p ./",
|
|
||||||
"lint": "eslint src --ext ts",
|
|
||||||
"pretest": "npm run compile && npm run lint",
|
|
||||||
"vscode:prepublish": "npm run esbuild-base -- --minify",
|
|
||||||
"esbuild-base": "esbuild ./src/extension.ts --bundle --outfile=out/main.js --external:vscode --format=cjs --platform=node",
|
|
||||||
"esbuild": "npm run esbuild-base -- --sourcemap",
|
|
||||||
"esbuild-watch": "npm run esbuild-base -- --sourcemap --watch",
|
|
||||||
"build-syntax": "node ./scripts/owl_template_syntax.mjs"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@types/node": "20.2.5",
|
|
||||||
"@types/vscode": "^1.73.0",
|
|
||||||
"@typescript-eslint/eslint-plugin": "^5.59.8",
|
|
||||||
"@typescript-eslint/parser": "^5.59.8",
|
|
||||||
"@vscode/test-electron": "^2.3.2",
|
|
||||||
"@vscode/vsce": "^2.20.1",
|
|
||||||
"esbuild": "^0.19.5",
|
|
||||||
"eslint": "^8.41.0",
|
|
||||||
"typescript": "^5.1.3"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
import { createTagPattern, exportPatterns } from "./syntax_builder_utils.mjs";
|
|
||||||
import {
|
|
||||||
htmlAttributes,
|
|
||||||
owlAttributesDynamic,
|
|
||||||
owlAttributesFormattedString,
|
|
||||||
owlAttributesStatic,
|
|
||||||
propsAttributes
|
|
||||||
} from "./syntax_parts/owl_attributes.mjs";
|
|
||||||
import { xpathAttributes } from "./syntax_parts/xpath.mjs";
|
|
||||||
|
|
||||||
const componentsTags = createTagPattern("component-tags", {
|
|
||||||
match: "[A-Z][a-zA-Z0-9_]*",
|
|
||||||
name: "entity.name.type.class owl.component",
|
|
||||||
patterns: [
|
|
||||||
owlAttributesDynamic,
|
|
||||||
owlAttributesDynamic,
|
|
||||||
propsAttributes,
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
const htmlTags = createTagPattern("html-tags", {
|
|
||||||
match: "[a-z][a-zA-Z0-9_:.]+|[abiqsuw]",
|
|
||||||
name: "entity.name.tag.localname.xml owl.xml.tag",
|
|
||||||
patterns: [
|
|
||||||
owlAttributesFormattedString,
|
|
||||||
xpathAttributes,
|
|
||||||
owlAttributesDynamic,
|
|
||||||
owlAttributesStatic,
|
|
||||||
htmlAttributes,
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
const tTag = createTagPattern("t-tag", {
|
|
||||||
match: "t(?![a-zA-Z])",
|
|
||||||
name: "entity.name.tag.localname.xml owl.tag",
|
|
||||||
patterns: [
|
|
||||||
propsAttributes,
|
|
||||||
owlAttributesFormattedString,
|
|
||||||
owlAttributesDynamic,
|
|
||||||
owlAttributesStatic,
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
exportPatterns(
|
|
||||||
"L:text.xml -comment",
|
|
||||||
"owl.template",
|
|
||||||
[componentsTags, htmlTags, tTag]
|
|
||||||
);
|
|
||||||
@@ -1,117 +0,0 @@
|
|||||||
import { writeFileSync } from "fs";
|
|
||||||
import { dirname, resolve } from "path";
|
|
||||||
import { fileURLToPath } from 'url';
|
|
||||||
|
|
||||||
const REPOSITORY = {};
|
|
||||||
|
|
||||||
export function exportPatterns(injectionSelector, scopeName, patterns) {
|
|
||||||
const data = {
|
|
||||||
injectionSelector: injectionSelector,
|
|
||||||
scopeName: scopeName,
|
|
||||||
patterns: [],
|
|
||||||
repository: {}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const pattern of patterns) {
|
|
||||||
data.patterns.push({ include: `#${pattern.id}` });
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const id in REPOSITORY) {
|
|
||||||
const pattern = { ...REPOSITORY[id] };
|
|
||||||
|
|
||||||
delete pattern.id;
|
|
||||||
|
|
||||||
data.repository[id] = pattern;
|
|
||||||
}
|
|
||||||
|
|
||||||
const currentDir = dirname(fileURLToPath(import.meta.url));
|
|
||||||
const filePath = resolve(currentDir, "../syntaxes", `${scopeName}.json`);
|
|
||||||
writeFileSync(filePath, JSON.stringify(data, null, 4));
|
|
||||||
console.info(`Sucessfuly build ./syntaxes/${scopeName}.json`);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function createPattern(id, { name, match, begin, end, contentName, beginCaptures, endCaptures, patterns }) {
|
|
||||||
const pattern = { ...arguments[1] };
|
|
||||||
if (id) {
|
|
||||||
pattern.id = id;
|
|
||||||
REPOSITORY[id] = pattern;
|
|
||||||
}
|
|
||||||
|
|
||||||
function mapCaptures(name, captures) {
|
|
||||||
if (!captures) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
pattern[name] = {};
|
|
||||||
for (const key in captures) {
|
|
||||||
pattern[name][key] = { name: captures[key] }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mapCaptures("beginCaptures", beginCaptures);
|
|
||||||
mapCaptures("endCaptures", endCaptures);
|
|
||||||
|
|
||||||
pattern.patterns = [];
|
|
||||||
|
|
||||||
if (patterns) {
|
|
||||||
for (const childPattern of patterns) {
|
|
||||||
if (typeof childPattern === "string") {
|
|
||||||
pattern.patterns.push({ include: childPattern });
|
|
||||||
} else if (childPattern.id) {
|
|
||||||
pattern.patterns.push({ include: `#${childPattern.id}` });
|
|
||||||
} else {
|
|
||||||
pattern.patterns.push(childPattern);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return pattern;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function createTagPattern(id, { match, name, patterns }) {
|
|
||||||
return createPattern(id, {
|
|
||||||
begin: `(</?)(${match})`,
|
|
||||||
beginCaptures: {
|
|
||||||
"1": "punctuation.definition.tag.xml owl.xml.punctuation",
|
|
||||||
"2": name,
|
|
||||||
},
|
|
||||||
end: "\\s*([/?]?>)",
|
|
||||||
endCaptures: {
|
|
||||||
"1": "punctuation.definition.tag.xml punctuation",
|
|
||||||
},
|
|
||||||
patterns,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function createAttributePatterns(id, { match, attributeName, contentName = "", patterns = [] }) {
|
|
||||||
return createPattern(id, {
|
|
||||||
patterns: [
|
|
||||||
createPattern(undefined, {
|
|
||||||
contentName: contentName !== null ? (contentName + " string.quoted.double.xml").trim() : undefined,
|
|
||||||
begin: `(\\s*)(${match})(=)(")`,
|
|
||||||
beginCaptures: {
|
|
||||||
"2": "entity.other.attribute-name.localname.xml " + attributeName,
|
|
||||||
"4": "punctuation.definition.string.begin.xml",
|
|
||||||
},
|
|
||||||
end: `(")`,
|
|
||||||
endCaptures: {
|
|
||||||
"0": "punctuation.definition.string.end.xml",
|
|
||||||
},
|
|
||||||
patterns,
|
|
||||||
}),
|
|
||||||
createPattern(undefined, {
|
|
||||||
contentName: contentName !== null ? (contentName + " string.quoted.single.xml").trim() : undefined,
|
|
||||||
begin: `(\\s*)(${match})(=)(')`,
|
|
||||||
beginCaptures: {
|
|
||||||
"2": "entity.other.attribute-name.localname.xml " + attributeName,
|
|
||||||
"4": "punctuation.definition.string.begin.xml",
|
|
||||||
},
|
|
||||||
end: `(')`,
|
|
||||||
endCaptures: {
|
|
||||||
"0": "punctuation.definition.string.end.xml",
|
|
||||||
},
|
|
||||||
patterns,
|
|
||||||
})
|
|
||||||
]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
@@ -1,103 +0,0 @@
|
|||||||
import { createAttributePatterns, createPattern } from "../syntax_builder_utils.mjs";
|
|
||||||
|
|
||||||
export const inilineJs = [createPattern("inline-js", {
|
|
||||||
patterns: [
|
|
||||||
{
|
|
||||||
match: "\\s(=>)\\s",
|
|
||||||
captures: {
|
|
||||||
"1": {
|
|
||||||
name: "string.quoted.double.xml owl.arrow",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
match: "\\b(props)\\b",
|
|
||||||
captures: {
|
|
||||||
"1": {
|
|
||||||
name: "variable.language.js owl.expression.props",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
match: "\\s(and|or)\\s",
|
|
||||||
captures: {
|
|
||||||
"1": {
|
|
||||||
name: "keyword.operator.logical.js owl.logical",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
include: "source.js"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
})];
|
|
||||||
|
|
||||||
const formattedString = createPattern("formatted-string", {
|
|
||||||
contentName: "meta.embedded.block.javascript",
|
|
||||||
begin: `({{)`,
|
|
||||||
beginCaptures: {
|
|
||||||
"1": "owl.double-curlybrackets",
|
|
||||||
},
|
|
||||||
end: `(}})`,
|
|
||||||
endCaptures: {
|
|
||||||
"1": "owl.double-curlybrackets",
|
|
||||||
},
|
|
||||||
patterns: inilineJs
|
|
||||||
});
|
|
||||||
|
|
||||||
// -------------------------------- Attributes --------------------------------
|
|
||||||
|
|
||||||
export const htmlAttributes = createAttributePatterns("html-attributes", {
|
|
||||||
match: "[a-z]{2}[a-z_:.-]+",
|
|
||||||
attributeName: "owl.xml.attribute",
|
|
||||||
});
|
|
||||||
|
|
||||||
export const propsAttributes = createAttributePatterns("props-attributes", {
|
|
||||||
match: "[a-zA-Z]{2}[a-zA-Z_:.]*",
|
|
||||||
contentName: "meta.embedded.block.javascript",
|
|
||||||
attributeName: "owl.attribute owl.attribute.props",
|
|
||||||
patterns: inilineJs,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const owlAttributesDynamic = createAttributePatterns("owl-attributes-dynamic", {
|
|
||||||
match: [
|
|
||||||
"t-if",
|
|
||||||
"t-else",
|
|
||||||
"t-elif",
|
|
||||||
"t-foreach",
|
|
||||||
"t-as",
|
|
||||||
"t-key",
|
|
||||||
"t-esc",
|
|
||||||
"t-out",
|
|
||||||
"t-props",
|
|
||||||
"t-component",
|
|
||||||
"t-set",
|
|
||||||
"t-value",
|
|
||||||
"t-portal",
|
|
||||||
"t-slot-scope",
|
|
||||||
"t-att-[a-z_:.-]+",
|
|
||||||
"t-on-[a-z_:.-]+"
|
|
||||||
].join("|"),
|
|
||||||
contentName: "meta.embedded.block.javascript",
|
|
||||||
attributeName: "owl.attribute owl.attribute.dynamic",
|
|
||||||
patterns: inilineJs,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const owlAttributesStatic = createAttributePatterns("owl-attributes-static", {
|
|
||||||
match: [
|
|
||||||
"t-name",
|
|
||||||
"t-ref",
|
|
||||||
"t-set-slot",
|
|
||||||
"t-model",
|
|
||||||
"t-inherit",
|
|
||||||
"t-inherit-mode",
|
|
||||||
"t-translation"
|
|
||||||
].join("|"),
|
|
||||||
attributeName: "owl.attribute owl.attribute.static",
|
|
||||||
});
|
|
||||||
|
|
||||||
export const owlAttributesFormattedString = createAttributePatterns("owl-attributes-formatted-string", {
|
|
||||||
match: ["t-call", "t-slot", "t-attf-[a-z_:.-]+"].join("|"),
|
|
||||||
attributeName: "owl.attribute owl.attribute.formatted",
|
|
||||||
patterns: [formattedString],
|
|
||||||
});
|
|
||||||
@@ -1,105 +0,0 @@
|
|||||||
import { createAttributePatterns, createPattern } from "../syntax_builder_utils.mjs";
|
|
||||||
|
|
||||||
const xpathPattern = [createPattern("xpath", {
|
|
||||||
patterns: [
|
|
||||||
{
|
|
||||||
begin: "\\[",
|
|
||||||
beginCaptures: {
|
|
||||||
"0": {
|
|
||||||
name: "punctuation.definition",
|
|
||||||
}
|
|
||||||
},
|
|
||||||
end: "\\]",
|
|
||||||
endCaptures: {
|
|
||||||
"0": {
|
|
||||||
name: "punctuation.definition",
|
|
||||||
}
|
|
||||||
},
|
|
||||||
patterns: [
|
|
||||||
{
|
|
||||||
begin: "'",
|
|
||||||
beginCaptures: {
|
|
||||||
"0": {
|
|
||||||
name: "punctuation.definition",
|
|
||||||
}
|
|
||||||
},
|
|
||||||
end: "'",
|
|
||||||
endCaptures: {
|
|
||||||
"0": {
|
|
||||||
name: "punctuation.definition",
|
|
||||||
}
|
|
||||||
},
|
|
||||||
contentName: "string.quoted.single",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
begin: "\\\"",
|
|
||||||
beginCaptures: {
|
|
||||||
"0": {
|
|
||||||
name: "punctuation.definition",
|
|
||||||
}
|
|
||||||
},
|
|
||||||
end: "\\\"",
|
|
||||||
endCaptures: {
|
|
||||||
"0": {
|
|
||||||
name: "punctuation.definition",
|
|
||||||
}
|
|
||||||
},
|
|
||||||
contentName: "string.quoted.double",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
match: "(@)([a-zA-Z0-9_:\\-]+)\\b",
|
|
||||||
captures: {
|
|
||||||
"1": {
|
|
||||||
name: "punctuation.definition",
|
|
||||||
},
|
|
||||||
"2": {
|
|
||||||
name: "entity.other.attribute-name",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
match: "(\\(|\\))",
|
|
||||||
name: "meta.brace.round",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
match: "[0-9]+(\\.[0-9]+)?",
|
|
||||||
name: "constant.numeric.decimal",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
match: "\\b(hasclass)\\b",
|
|
||||||
captures: {
|
|
||||||
"1": {
|
|
||||||
name: "entity.name.function",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
match: "/{1,2}",
|
|
||||||
name: "text",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
match: "(?<!@)([A-Z][a-zA-Z]+)\\b",
|
|
||||||
captures: {
|
|
||||||
"1": {
|
|
||||||
name: "entity.name.type.class",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
match: "(?<!@)([a-z][a-zA-Z0-9_:.]+|[abiqsuw])\\b",
|
|
||||||
captures: {
|
|
||||||
"1": {
|
|
||||||
name: "entity.name.tag",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
]
|
|
||||||
})];
|
|
||||||
|
|
||||||
export const xpathAttributes = createAttributePatterns("xpath-attributes", {
|
|
||||||
match: "expr",
|
|
||||||
attributeName: "owl.xml.attribute owl.xml.attribute.xpath",
|
|
||||||
patterns: xpathPattern,
|
|
||||||
});
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
{
|
|
||||||
"Basic owl component": {
|
|
||||||
"prefix": "owlcomponent",
|
|
||||||
"body": [
|
|
||||||
"export class ${1:component-name} extends Component {",
|
|
||||||
" static template = \"${2:template-name}\";",
|
|
||||||
" static components = {};",
|
|
||||||
" static props = {};",
|
|
||||||
"",
|
|
||||||
" setup() {",
|
|
||||||
"",
|
|
||||||
" }",
|
|
||||||
"}",
|
|
||||||
""
|
|
||||||
],
|
|
||||||
"description": "The starting base for an owl component"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
import * as vscode from 'vscode';
|
|
||||||
import { getSelectedText, showStatusMessage, hideStatusMessage } from './utils';
|
|
||||||
import { Search } from './search';
|
|
||||||
|
|
||||||
export class ComponentDefinitionProvider implements vscode.DefinitionProvider {
|
|
||||||
|
|
||||||
search: Search;
|
|
||||||
|
|
||||||
constructor(search: Search) {
|
|
||||||
this.search = search;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Interface implementation to provide definition when ctrl+click on Component
|
|
||||||
* tag in template.
|
|
||||||
*/
|
|
||||||
async provideDefinition(document: vscode.TextDocument, position: vscode.Position) {
|
|
||||||
const currentWord = getSelectedText(/<\/?[A-Z][a-zA-Z]+/, document, position);
|
|
||||||
if (!currentWord) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const componentName = currentWord.replace(/[\/<]/g, "").trim();
|
|
||||||
|
|
||||||
showStatusMessage(`Searching for component "${componentName}"`);
|
|
||||||
const result = await this.search.findComponent(componentName);
|
|
||||||
hideStatusMessage();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
import * as vscode from 'vscode';
|
|
||||||
import { Search } from './search';
|
|
||||||
import { ComponentDefinitionProvider } from './definiton_providers';
|
|
||||||
import { OpenDirection } from './utils';
|
|
||||||
|
|
||||||
export async function activate(context: vscode.ExtensionContext) {
|
|
||||||
const search = new Search();
|
|
||||||
|
|
||||||
context.subscriptions.push(vscode.commands.registerCommand('owl-vision.switch', () => search.switch()));
|
|
||||||
context.subscriptions.push(vscode.commands.registerCommand('owl-vision.switch-besides', () => search.switch(OpenDirection.Besides)));
|
|
||||||
context.subscriptions.push(vscode.commands.registerCommand('owl-vision.switch-below', () => search.switch(OpenDirection.Below)));
|
|
||||||
context.subscriptions.push(vscode.commands.registerCommand('owl-vision.find-component', () => search.findComponentCommand()));
|
|
||||||
context.subscriptions.push(vscode.commands.registerCommand('owl-vision.find-template', () => search.findTemplateCommand()));
|
|
||||||
|
|
||||||
const componentDefProvider = new ComponentDefinitionProvider(search);
|
|
||||||
context.subscriptions.push(vscode.languages.registerDefinitionProvider({ language: 'xml' }, componentDefProvider));
|
|
||||||
context.subscriptions.push(vscode.languages.registerDefinitionProvider({ language: 'javascript' }, componentDefProvider));
|
|
||||||
}
|
|
||||||
|
|
||||||
export function deactivate() { }
|
|
||||||
@@ -1,196 +0,0 @@
|
|||||||
import { GlobPattern, Location, Range, Uri, window, workspace } from 'vscode';
|
|
||||||
import { OpenDirection, getClosestMatch, getSelectedText, hideStatusMessage, showResult, showStatusMessage } from './utils';
|
|
||||||
import path = require('path');
|
|
||||||
|
|
||||||
export class Search {
|
|
||||||
|
|
||||||
finderCache = new Map<string, Uri>();
|
|
||||||
|
|
||||||
public async switch(openDirection: OpenDirection = OpenDirection.Active) {
|
|
||||||
if (!this.currentDocument) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let result = undefined;
|
|
||||||
const text = this.currentDocument.getText();
|
|
||||||
const isJs = this.currentDocument.fileName.endsWith(".js");
|
|
||||||
const templateName = this.getTemplateName(text, isJs);
|
|
||||||
|
|
||||||
if (templateName && isJs) {
|
|
||||||
result = await this.findTemplate(templateName);
|
|
||||||
} else if (templateName) {
|
|
||||||
result = await this.findComponentFromTemplateName(templateName);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result !== undefined) {
|
|
||||||
showResult(result, openDirection);
|
|
||||||
} else if (isJs) {
|
|
||||||
window.showWarningMessage(`Could not find a template for current component`);
|
|
||||||
} else {
|
|
||||||
window.showWarningMessage(`Could not find a component for current template`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async findComponentCommand() {
|
|
||||||
const currentWord = getSelectedText();
|
|
||||||
if (!currentWord) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
showStatusMessage(`Searching for component "${currentWord}"`);
|
|
||||||
const result = await this.findComponent(currentWord);
|
|
||||||
if (result) {
|
|
||||||
showResult(result);
|
|
||||||
} else {
|
|
||||||
window.showWarningMessage(`Could not find a component for "${currentWord}"`);
|
|
||||||
}
|
|
||||||
hideStatusMessage();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async findTemplateCommand() {
|
|
||||||
const currentWord = getSelectedText(/[\w.-]+/);
|
|
||||||
if (!currentWord) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
showStatusMessage(`Searching for template "${currentWord}"`);
|
|
||||||
const result = await this.findTemplate(currentWord);
|
|
||||||
if (result) {
|
|
||||||
showResult(result);
|
|
||||||
} else {
|
|
||||||
window.showWarningMessage(`Could not find a template for "${currentWord}"`);
|
|
||||||
}
|
|
||||||
hideStatusMessage();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async findComponent(componentName: string): Promise<Location | undefined> {
|
|
||||||
if (componentName.toLowerCase() === componentName || componentName.includes(".") || componentName.includes("-")) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const query = this.buildQuery(`class\\s+`, componentName, `\\s+extends`);
|
|
||||||
return await this.find(componentName, query, "js");
|
|
||||||
}
|
|
||||||
|
|
||||||
public async findTemplate(templateName: string): Promise<Location | undefined> {
|
|
||||||
const isComponentName = templateName.match(/^[A-Z][a-zA-Z0-9_]*$/);
|
|
||||||
|
|
||||||
if (isComponentName) {
|
|
||||||
const componentResult = await this.findComponent(templateName);
|
|
||||||
if (!componentResult) {
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
const text = (await workspace.openTextDocument(componentResult.uri)).getText();
|
|
||||||
const foundTemplateName = this.getTemplateName(text, true);
|
|
||||||
if (foundTemplateName) {
|
|
||||||
templateName = foundTemplateName;
|
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const query = this.buildQuery(`t-name="`, templateName, `"`);
|
|
||||||
return await this.find(templateName, query, "xml");
|
|
||||||
}
|
|
||||||
|
|
||||||
private findComponentFromTemplateName(templateName: string): Promise<Location | undefined> {
|
|
||||||
const query = this.buildQuery(`template\\s*=\\s*["']`, templateName, `["']`);
|
|
||||||
return this.find(templateName, query, "js");
|
|
||||||
}
|
|
||||||
|
|
||||||
private getTemplateName(str: string, isJsFile: boolean): string | undefined {
|
|
||||||
if (isJsFile) {
|
|
||||||
return getClosestMatch(str, /template\s*=\s*["']([a-zA-Z0-9_\-\.]+)["']/g, +1);
|
|
||||||
} else {
|
|
||||||
return getClosestMatch(str, /t-name="([a-zA-Z0-9_\-\.]+)"/g);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async find(
|
|
||||||
name: string,
|
|
||||||
searchQuery: string,
|
|
||||||
fileType: "js" | "xml",
|
|
||||||
): Promise<Location | undefined> {
|
|
||||||
const key = `${name}-${fileType}`;
|
|
||||||
const cachedUri = this.finderCache.get(key);
|
|
||||||
if (cachedUri) {
|
|
||||||
const result = await this.findInFile(cachedUri, searchQuery);
|
|
||||||
if (result) {
|
|
||||||
return result;
|
|
||||||
} else {
|
|
||||||
this.finderCache.delete(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const include = `{${workspace.getConfiguration().get(`owl-vision.include`)}, *.${fileType}}`;
|
|
||||||
const exclude = `{${workspace.getConfiguration().get(`owl-vision.exclude`)}}`;
|
|
||||||
const files = await this.getFiles(name, include, exclude);
|
|
||||||
|
|
||||||
for (const file of files) {
|
|
||||||
const result = await this.findInFile(file, searchQuery);
|
|
||||||
if (result) {
|
|
||||||
this.finderCache.set(key, result.uri);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async getFiles(
|
|
||||||
searchQuery: string,
|
|
||||||
include: GlobPattern,
|
|
||||||
exclude: GlobPattern,
|
|
||||||
): Promise<Array<Uri>> {
|
|
||||||
const files = await workspace.findFiles(include, exclude);
|
|
||||||
const parts = searchQuery.split(".").flatMap(s => s.split(/(?=[A-Z])/)).map(s => s.toLowerCase());
|
|
||||||
const currentDir = this.currentDocument ? path.dirname(this.currentDocument.uri.path) : "";
|
|
||||||
|
|
||||||
const results = files.map(file => {
|
|
||||||
const filepath = file.path.toLowerCase();
|
|
||||||
let score = 0;
|
|
||||||
if (path.dirname(filepath) === currentDir) {
|
|
||||||
score += 99;
|
|
||||||
}
|
|
||||||
for (const part of parts) {
|
|
||||||
if (filepath.includes(part)) {
|
|
||||||
score++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return { score, file };
|
|
||||||
})
|
|
||||||
.sort((a, b) => a.score > b.score ? -1 : 1)
|
|
||||||
.slice(0, 25);
|
|
||||||
|
|
||||||
return results.map(r => r.file);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async findInFile(
|
|
||||||
file: Uri,
|
|
||||||
searchQuery: string,
|
|
||||||
): Promise<Location | undefined> {
|
|
||||||
const document = await workspace.openTextDocument(file);
|
|
||||||
const text = document.getText();
|
|
||||||
const match = text.match(new RegExp(searchQuery));
|
|
||||||
|
|
||||||
if (match) {
|
|
||||||
const index = match.index || 0;
|
|
||||||
return new Location(file, new Range(
|
|
||||||
document.positionAt(index),
|
|
||||||
document.positionAt(index)
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private get currentDocument() {
|
|
||||||
return window.activeTextEditor?.document;
|
|
||||||
}
|
|
||||||
|
|
||||||
private buildQuery(
|
|
||||||
prefix: string,
|
|
||||||
content: string,
|
|
||||||
postfix: string,
|
|
||||||
): string {
|
|
||||||
return `(?<=${prefix})(${content})(?=${postfix})`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,104 +0,0 @@
|
|||||||
import * as vscode from 'vscode';
|
|
||||||
|
|
||||||
let statusMessage: vscode.StatusBarItem | undefined = undefined;
|
|
||||||
|
|
||||||
export function showStatusMessage(text: string) {
|
|
||||||
if (!statusMessage) {
|
|
||||||
statusMessage = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left);
|
|
||||||
}
|
|
||||||
statusMessage.text = `$(sync~spin) ${text}`;
|
|
||||||
statusMessage.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function hideStatusMessage() {
|
|
||||||
statusMessage?.hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getActiveCursorIndex(lineDelta = 0): number {
|
|
||||||
const editor = vscode.window.activeTextEditor;
|
|
||||||
if (!editor) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
const position = editor.selection.active.translate(lineDelta);
|
|
||||||
return editor.document.offsetAt(position);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getSelectedText(regex?: RegExp, document?: vscode.TextDocument, position?: vscode.Position): string | undefined {
|
|
||||||
const editor = vscode.window.activeTextEditor;
|
|
||||||
if (!document) {
|
|
||||||
if (!editor) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
document = editor.document;
|
|
||||||
}
|
|
||||||
|
|
||||||
position = position || vscode.window.activeTextEditor?.selection.active;
|
|
||||||
|
|
||||||
if (!position) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const wordRange = document.getWordRangeAtPosition(position, regex);
|
|
||||||
if (!wordRange) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
return document.getText(wordRange);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getClosestMatch(str: string, regex: RegExp, lineDelta = 0): string | undefined {
|
|
||||||
const index = getActiveCursorIndex(lineDelta);
|
|
||||||
const matches = [...str.matchAll(regex)];
|
|
||||||
|
|
||||||
if (matches.length === 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let closestMatch = matches[0];
|
|
||||||
let closestDistance = Math.abs(index - (closestMatch.index || 0));
|
|
||||||
|
|
||||||
for (const match of matches) {
|
|
||||||
const matchIndex = match.index || 0;
|
|
||||||
const distance = Math.abs(index - matchIndex);
|
|
||||||
if (matchIndex < index && distance < closestDistance) {
|
|
||||||
closestMatch = match;
|
|
||||||
closestDistance = distance;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return closestMatch[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum OpenDirection {
|
|
||||||
Active,
|
|
||||||
Besides,
|
|
||||||
Below,
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function showResult(result: vscode.Location, openDirection: OpenDirection = OpenDirection.Active) {
|
|
||||||
let editor = undefined;
|
|
||||||
|
|
||||||
if (openDirection == OpenDirection.Active) {
|
|
||||||
editor = await vscode.window.showTextDocument(result.uri);
|
|
||||||
} else {
|
|
||||||
let targetColumn = vscode.ViewColumn.Beside;
|
|
||||||
const existingDocument = vscode.workspace.textDocuments.find(t => t.uri.path === result.uri.path);
|
|
||||||
if (existingDocument) {
|
|
||||||
const currentColumn = vscode.window.activeTextEditor?.viewColumn;
|
|
||||||
if (currentColumn == vscode.ViewColumn.One) {
|
|
||||||
targetColumn = vscode.ViewColumn.Two;
|
|
||||||
} else if (currentColumn == vscode.ViewColumn.Two) {
|
|
||||||
targetColumn = vscode.ViewColumn.One;
|
|
||||||
}
|
|
||||||
editor = await vscode.window.showTextDocument(existingDocument, { viewColumn: targetColumn });
|
|
||||||
} else {
|
|
||||||
editor = await vscode.window.showTextDocument(result.uri, { viewColumn: targetColumn });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (openDirection === OpenDirection.Below) {
|
|
||||||
await vscode.commands.executeCommand('workbench.action.editorLayoutTwoRows');
|
|
||||||
}
|
|
||||||
|
|
||||||
editor.revealRange(result.range);
|
|
||||||
editor.selection = new vscode.Selection(result.range.start, result.range.end);
|
|
||||||
}
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
{
|
|
||||||
"injectionSelector": "L:source.js -comment",
|
|
||||||
"scopeName": "owl.markup.inline",
|
|
||||||
"patterns": [
|
|
||||||
{
|
|
||||||
"include": "#markup"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"repository": {
|
|
||||||
"markup": {
|
|
||||||
"begin": "\\s+(markup)(`)",
|
|
||||||
"contentName": "meta.embedded.block.html",
|
|
||||||
"beginCaptures": {
|
|
||||||
"1": {
|
|
||||||
"name": "entity.name.function.tagged-template.js owl-markup"
|
|
||||||
},
|
|
||||||
"2": {
|
|
||||||
"name": "punctuation.definition.string.template.begin.js string.template.js"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"end": "(`)",
|
|
||||||
"endCaptures": {
|
|
||||||
"1": {
|
|
||||||
"name": "punctuation.definition.string.template.end.js string.template.js"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"patterns": [
|
|
||||||
{
|
|
||||||
"include": "text.html.basic"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
{
|
|
||||||
"injectionSelector": "L:source.js -comment -(string -meta.embedded)",
|
|
||||||
"scopeName": "owl.template.inline",
|
|
||||||
"patterns": [
|
|
||||||
{
|
|
||||||
"include": "#xml-tag"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"repository": {
|
|
||||||
"xml-tag": {
|
|
||||||
"begin": "\\s+(xml)(`)",
|
|
||||||
"contentName": "meta.embedded.block.xml",
|
|
||||||
"beginCaptures": {
|
|
||||||
"1": {
|
|
||||||
"name": "entity.name.function.tagged-template.js"
|
|
||||||
},
|
|
||||||
"2": {
|
|
||||||
"name": "punctuation.definition.string.template.begin.js"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"end": "(`)",
|
|
||||||
"endCaptures": {
|
|
||||||
"0": {
|
|
||||||
"name": "string.js"
|
|
||||||
},
|
|
||||||
"1": {
|
|
||||||
"name": "punctuation.definition.string.template.end.js"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"patterns": [
|
|
||||||
{
|
|
||||||
"include": "owl.template"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"include": "text.xml"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,542 +0,0 @@
|
|||||||
{
|
|
||||||
"injectionSelector": "L:text.xml -comment",
|
|
||||||
"scopeName": "owl.template",
|
|
||||||
"patterns": [
|
|
||||||
{
|
|
||||||
"include": "#component-tags"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"include": "#html-tags"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"include": "#t-tag"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"repository": {
|
|
||||||
"inline-js": {
|
|
||||||
"patterns": [
|
|
||||||
{
|
|
||||||
"match": "\\s(=>)\\s",
|
|
||||||
"captures": {
|
|
||||||
"1": {
|
|
||||||
"name": "string.quoted.double.xml owl.arrow"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"match": "\\b(props)\\b",
|
|
||||||
"captures": {
|
|
||||||
"1": {
|
|
||||||
"name": "variable.language.js owl.expression.props"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"match": "\\s(and|or)\\s",
|
|
||||||
"captures": {
|
|
||||||
"1": {
|
|
||||||
"name": "keyword.operator.logical.js owl.logical"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"include": "source.js"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"formatted-string": {
|
|
||||||
"contentName": "meta.embedded.block.javascript",
|
|
||||||
"begin": "({{)",
|
|
||||||
"beginCaptures": {
|
|
||||||
"1": {
|
|
||||||
"name": "owl.double-curlybrackets"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"end": "(}})",
|
|
||||||
"endCaptures": {
|
|
||||||
"1": {
|
|
||||||
"name": "owl.double-curlybrackets"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"patterns": [
|
|
||||||
{
|
|
||||||
"include": "#inline-js"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"html-attributes": {
|
|
||||||
"patterns": [
|
|
||||||
{
|
|
||||||
"contentName": "string.quoted.double.xml",
|
|
||||||
"begin": "(\\s*)([a-z]{2}[a-z_:.-]+)(=)(\")",
|
|
||||||
"beginCaptures": {
|
|
||||||
"2": {
|
|
||||||
"name": "entity.other.attribute-name.localname.xml owl.xml.attribute"
|
|
||||||
},
|
|
||||||
"4": {
|
|
||||||
"name": "punctuation.definition.string.begin.xml"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"end": "(\")",
|
|
||||||
"endCaptures": {
|
|
||||||
"0": {
|
|
||||||
"name": "punctuation.definition.string.end.xml"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"patterns": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"contentName": "string.quoted.single.xml",
|
|
||||||
"begin": "(\\s*)([a-z]{2}[a-z_:.-]+)(=)(')",
|
|
||||||
"beginCaptures": {
|
|
||||||
"2": {
|
|
||||||
"name": "entity.other.attribute-name.localname.xml owl.xml.attribute"
|
|
||||||
},
|
|
||||||
"4": {
|
|
||||||
"name": "punctuation.definition.string.begin.xml"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"end": "(')",
|
|
||||||
"endCaptures": {
|
|
||||||
"0": {
|
|
||||||
"name": "punctuation.definition.string.end.xml"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"patterns": []
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"props-attributes": {
|
|
||||||
"patterns": [
|
|
||||||
{
|
|
||||||
"contentName": "meta.embedded.block.javascript string.quoted.double.xml",
|
|
||||||
"begin": "(\\s*)([a-zA-Z]{2}[a-zA-Z_:.]*)(=)(\")",
|
|
||||||
"beginCaptures": {
|
|
||||||
"2": {
|
|
||||||
"name": "entity.other.attribute-name.localname.xml owl.attribute owl.attribute.props"
|
|
||||||
},
|
|
||||||
"4": {
|
|
||||||
"name": "punctuation.definition.string.begin.xml"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"end": "(\")",
|
|
||||||
"endCaptures": {
|
|
||||||
"0": {
|
|
||||||
"name": "punctuation.definition.string.end.xml"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"patterns": [
|
|
||||||
{
|
|
||||||
"include": "#inline-js"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"contentName": "meta.embedded.block.javascript string.quoted.single.xml",
|
|
||||||
"begin": "(\\s*)([a-zA-Z]{2}[a-zA-Z_:.]*)(=)(')",
|
|
||||||
"beginCaptures": {
|
|
||||||
"2": {
|
|
||||||
"name": "entity.other.attribute-name.localname.xml owl.attribute owl.attribute.props"
|
|
||||||
},
|
|
||||||
"4": {
|
|
||||||
"name": "punctuation.definition.string.begin.xml"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"end": "(')",
|
|
||||||
"endCaptures": {
|
|
||||||
"0": {
|
|
||||||
"name": "punctuation.definition.string.end.xml"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"patterns": [
|
|
||||||
{
|
|
||||||
"include": "#inline-js"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"owl-attributes-dynamic": {
|
|
||||||
"patterns": [
|
|
||||||
{
|
|
||||||
"contentName": "meta.embedded.block.javascript string.quoted.double.xml",
|
|
||||||
"begin": "(\\s*)(t-if|t-else|t-elif|t-foreach|t-as|t-key|t-esc|t-out|t-props|t-component|t-set|t-value|t-portal|t-slot-scope|t-att-[a-z_:.-]+|t-on-[a-z_:.-]+)(=)(\")",
|
|
||||||
"beginCaptures": {
|
|
||||||
"2": {
|
|
||||||
"name": "entity.other.attribute-name.localname.xml owl.attribute owl.attribute.dynamic"
|
|
||||||
},
|
|
||||||
"4": {
|
|
||||||
"name": "punctuation.definition.string.begin.xml"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"end": "(\")",
|
|
||||||
"endCaptures": {
|
|
||||||
"0": {
|
|
||||||
"name": "punctuation.definition.string.end.xml"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"patterns": [
|
|
||||||
{
|
|
||||||
"include": "#inline-js"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"contentName": "meta.embedded.block.javascript string.quoted.single.xml",
|
|
||||||
"begin": "(\\s*)(t-if|t-else|t-elif|t-foreach|t-as|t-key|t-esc|t-out|t-props|t-component|t-set|t-value|t-portal|t-slot-scope|t-att-[a-z_:.-]+|t-on-[a-z_:.-]+)(=)(')",
|
|
||||||
"beginCaptures": {
|
|
||||||
"2": {
|
|
||||||
"name": "entity.other.attribute-name.localname.xml owl.attribute owl.attribute.dynamic"
|
|
||||||
},
|
|
||||||
"4": {
|
|
||||||
"name": "punctuation.definition.string.begin.xml"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"end": "(')",
|
|
||||||
"endCaptures": {
|
|
||||||
"0": {
|
|
||||||
"name": "punctuation.definition.string.end.xml"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"patterns": [
|
|
||||||
{
|
|
||||||
"include": "#inline-js"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"owl-attributes-static": {
|
|
||||||
"patterns": [
|
|
||||||
{
|
|
||||||
"contentName": "string.quoted.double.xml",
|
|
||||||
"begin": "(\\s*)(t-name|t-ref|t-set-slot|t-model|t-inherit|t-inherit-mode|t-translation)(=)(\")",
|
|
||||||
"beginCaptures": {
|
|
||||||
"2": {
|
|
||||||
"name": "entity.other.attribute-name.localname.xml owl.attribute owl.attribute.static"
|
|
||||||
},
|
|
||||||
"4": {
|
|
||||||
"name": "punctuation.definition.string.begin.xml"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"end": "(\")",
|
|
||||||
"endCaptures": {
|
|
||||||
"0": {
|
|
||||||
"name": "punctuation.definition.string.end.xml"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"patterns": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"contentName": "string.quoted.single.xml",
|
|
||||||
"begin": "(\\s*)(t-name|t-ref|t-set-slot|t-model|t-inherit|t-inherit-mode|t-translation)(=)(')",
|
|
||||||
"beginCaptures": {
|
|
||||||
"2": {
|
|
||||||
"name": "entity.other.attribute-name.localname.xml owl.attribute owl.attribute.static"
|
|
||||||
},
|
|
||||||
"4": {
|
|
||||||
"name": "punctuation.definition.string.begin.xml"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"end": "(')",
|
|
||||||
"endCaptures": {
|
|
||||||
"0": {
|
|
||||||
"name": "punctuation.definition.string.end.xml"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"patterns": []
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"owl-attributes-formatted-string": {
|
|
||||||
"patterns": [
|
|
||||||
{
|
|
||||||
"contentName": "string.quoted.double.xml",
|
|
||||||
"begin": "(\\s*)(t-call|t-slot|t-attf-[a-z_:.-]+)(=)(\")",
|
|
||||||
"beginCaptures": {
|
|
||||||
"2": {
|
|
||||||
"name": "entity.other.attribute-name.localname.xml owl.attribute owl.attribute.formatted"
|
|
||||||
},
|
|
||||||
"4": {
|
|
||||||
"name": "punctuation.definition.string.begin.xml"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"end": "(\")",
|
|
||||||
"endCaptures": {
|
|
||||||
"0": {
|
|
||||||
"name": "punctuation.definition.string.end.xml"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"patterns": [
|
|
||||||
{
|
|
||||||
"include": "#formatted-string"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"contentName": "string.quoted.single.xml",
|
|
||||||
"begin": "(\\s*)(t-call|t-slot|t-attf-[a-z_:.-]+)(=)(')",
|
|
||||||
"beginCaptures": {
|
|
||||||
"2": {
|
|
||||||
"name": "entity.other.attribute-name.localname.xml owl.attribute owl.attribute.formatted"
|
|
||||||
},
|
|
||||||
"4": {
|
|
||||||
"name": "punctuation.definition.string.begin.xml"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"end": "(')",
|
|
||||||
"endCaptures": {
|
|
||||||
"0": {
|
|
||||||
"name": "punctuation.definition.string.end.xml"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"patterns": [
|
|
||||||
{
|
|
||||||
"include": "#formatted-string"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"xpath": {
|
|
||||||
"patterns": [
|
|
||||||
{
|
|
||||||
"begin": "\\[",
|
|
||||||
"beginCaptures": {
|
|
||||||
"0": {
|
|
||||||
"name": "punctuation.definition"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"end": "\\]",
|
|
||||||
"endCaptures": {
|
|
||||||
"0": {
|
|
||||||
"name": "punctuation.definition"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"patterns": [
|
|
||||||
{
|
|
||||||
"begin": "'",
|
|
||||||
"beginCaptures": {
|
|
||||||
"0": {
|
|
||||||
"name": "punctuation.definition"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"end": "'",
|
|
||||||
"endCaptures": {
|
|
||||||
"0": {
|
|
||||||
"name": "punctuation.definition"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"contentName": "string.quoted.single"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"begin": "\\\"",
|
|
||||||
"beginCaptures": {
|
|
||||||
"0": {
|
|
||||||
"name": "punctuation.definition"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"end": "\\\"",
|
|
||||||
"endCaptures": {
|
|
||||||
"0": {
|
|
||||||
"name": "punctuation.definition"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"contentName": "string.quoted.double"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"match": "(@)([a-zA-Z0-9_:\\-]+)\\b",
|
|
||||||
"captures": {
|
|
||||||
"1": {
|
|
||||||
"name": "punctuation.definition"
|
|
||||||
},
|
|
||||||
"2": {
|
|
||||||
"name": "entity.other.attribute-name"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"match": "(\\(|\\))",
|
|
||||||
"name": "meta.brace.round"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"match": "[0-9]+(\\.[0-9]+)?",
|
|
||||||
"name": "constant.numeric.decimal"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"match": "\\b(hasclass)\\b",
|
|
||||||
"captures": {
|
|
||||||
"1": {
|
|
||||||
"name": "entity.name.function"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"match": "/{1,2}",
|
|
||||||
"name": "text"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"match": "(?<!@)([A-Z][a-zA-Z]+)\\b",
|
|
||||||
"captures": {
|
|
||||||
"1": {
|
|
||||||
"name": "entity.name.type.class"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"match": "(?<!@)([a-z][a-zA-Z0-9_:.]+|[abiqsuw])\\b",
|
|
||||||
"captures": {
|
|
||||||
"1": {
|
|
||||||
"name": "entity.name.tag"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"xpath-attributes": {
|
|
||||||
"patterns": [
|
|
||||||
{
|
|
||||||
"contentName": "string.quoted.double.xml",
|
|
||||||
"begin": "(\\s*)(expr)(=)(\")",
|
|
||||||
"beginCaptures": {
|
|
||||||
"2": {
|
|
||||||
"name": "entity.other.attribute-name.localname.xml owl.xml.attribute owl.xml.attribute.xpath"
|
|
||||||
},
|
|
||||||
"4": {
|
|
||||||
"name": "punctuation.definition.string.begin.xml"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"end": "(\")",
|
|
||||||
"endCaptures": {
|
|
||||||
"0": {
|
|
||||||
"name": "punctuation.definition.string.end.xml"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"patterns": [
|
|
||||||
{
|
|
||||||
"include": "#xpath"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"contentName": "string.quoted.single.xml",
|
|
||||||
"begin": "(\\s*)(expr)(=)(')",
|
|
||||||
"beginCaptures": {
|
|
||||||
"2": {
|
|
||||||
"name": "entity.other.attribute-name.localname.xml owl.xml.attribute owl.xml.attribute.xpath"
|
|
||||||
},
|
|
||||||
"4": {
|
|
||||||
"name": "punctuation.definition.string.begin.xml"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"end": "(')",
|
|
||||||
"endCaptures": {
|
|
||||||
"0": {
|
|
||||||
"name": "punctuation.definition.string.end.xml"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"patterns": [
|
|
||||||
{
|
|
||||||
"include": "#xpath"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"component-tags": {
|
|
||||||
"begin": "(</?)([A-Z][a-zA-Z0-9_]*)",
|
|
||||||
"beginCaptures": {
|
|
||||||
"1": {
|
|
||||||
"name": "punctuation.definition.tag.xml owl.xml.punctuation"
|
|
||||||
},
|
|
||||||
"2": {
|
|
||||||
"name": "entity.name.type.class owl.component"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"end": "\\s*([/?]?>)",
|
|
||||||
"endCaptures": {
|
|
||||||
"1": {
|
|
||||||
"name": "punctuation.definition.tag.xml punctuation"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"patterns": [
|
|
||||||
{
|
|
||||||
"include": "#owl-attributes-dynamic"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"include": "#owl-attributes-dynamic"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"include": "#props-attributes"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"html-tags": {
|
|
||||||
"begin": "(</?)([a-z][a-zA-Z0-9_:.]+|[abiqsuw])",
|
|
||||||
"beginCaptures": {
|
|
||||||
"1": {
|
|
||||||
"name": "punctuation.definition.tag.xml owl.xml.punctuation"
|
|
||||||
},
|
|
||||||
"2": {
|
|
||||||
"name": "entity.name.tag.localname.xml owl.xml.tag"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"end": "\\s*([/?]?>)",
|
|
||||||
"endCaptures": {
|
|
||||||
"1": {
|
|
||||||
"name": "punctuation.definition.tag.xml punctuation"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"patterns": [
|
|
||||||
{
|
|
||||||
"include": "#owl-attributes-formatted-string"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"include": "#xpath-attributes"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"include": "#owl-attributes-dynamic"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"include": "#owl-attributes-static"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"include": "#html-attributes"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"t-tag": {
|
|
||||||
"begin": "(</?)(t(?![a-zA-Z]))",
|
|
||||||
"beginCaptures": {
|
|
||||||
"1": {
|
|
||||||
"name": "punctuation.definition.tag.xml owl.xml.punctuation"
|
|
||||||
},
|
|
||||||
"2": {
|
|
||||||
"name": "entity.name.tag.localname.xml owl.tag"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"end": "\\s*([/?]?>)",
|
|
||||||
"endCaptures": {
|
|
||||||
"1": {
|
|
||||||
"name": "punctuation.definition.tag.xml punctuation"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"patterns": [
|
|
||||||
{
|
|
||||||
"include": "#props-attributes"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"include": "#owl-attributes-formatted-string"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"include": "#owl-attributes-dynamic"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"include": "#owl-attributes-static"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
{
|
|
||||||
"compilerOptions": {
|
|
||||||
"module": "commonjs",
|
|
||||||
"target": "ES2020",
|
|
||||||
"outDir": "out",
|
|
||||||
"lib": [
|
|
||||||
"ES2020"
|
|
||||||
],
|
|
||||||
"sourceMap": true,
|
|
||||||
"rootDir": "src",
|
|
||||||
"strict": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||