feat(fn2cls): env
This commit is contained in:
parent
2d5d3c29e4
commit
a536958ad4
|
@ -14,4 +14,4 @@ function MyComp() {
|
|||
</>
|
||||
);
|
||||
}
|
||||
render('main', MyComp);
|
||||
render(MyComp, 'main');
|
||||
|
|
|
@ -1,138 +0,0 @@
|
|||
// @ts-nocheck
|
||||
import {
|
||||
Children,
|
||||
Content,
|
||||
Main,
|
||||
Model,
|
||||
Prop,
|
||||
View,
|
||||
Watch,
|
||||
button,
|
||||
div,
|
||||
input,
|
||||
insertChildren,
|
||||
use,
|
||||
render,
|
||||
} from '@openinula/next';
|
||||
|
||||
// @ts-ignore
|
||||
function Button({ children, onClick }) {
|
||||
return (
|
||||
<button
|
||||
onClick={onClick}
|
||||
style={{
|
||||
color: 'white',
|
||||
backgroundColor: 'green',
|
||||
border: 'none',
|
||||
padding: '5px 10px',
|
||||
marginRight: '10px',
|
||||
borderRadius: '4px',
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
function ArrayModification() {
|
||||
const arr = [];
|
||||
willMount(() => {});
|
||||
return (
|
||||
<section>
|
||||
<h1>ArrayModification</h1>
|
||||
{arr.join(',')}
|
||||
<button onClick={() => arr.push(arr.length)}>Add item</button>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
function Counter() {
|
||||
let count = 0;
|
||||
const doubleCount = count * 2; // 当count变化时,doubleCount自动更新
|
||||
|
||||
// 当count变化时,watch会自动执行
|
||||
watch(() => {
|
||||
uploadToServer(count);
|
||||
console.log(`count has changed: ${count}`);
|
||||
});
|
||||
|
||||
// 只有在init的时候执行一次
|
||||
console.log(`Counter willMount with count ${count}`);
|
||||
// 在elements被挂载到DOM之后执行
|
||||
didMount(() => {
|
||||
console.log(`Counter didMount with count ${count}`);
|
||||
});
|
||||
|
||||
return (
|
||||
<section>
|
||||
count: {count}, double is: {doubleCount}
|
||||
<button onClick={() => count++}>Add</button>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
function Counter() {
|
||||
let count = 0;
|
||||
const doubleCount = count * 2; // 当count变化时,doubleCount自动更新
|
||||
|
||||
uploadToServer(count); // 当count变化时,uploadToServer会自动执行
|
||||
console.log(`count has changed: ${count}`); // 当count变化时,console.log会自动执行
|
||||
|
||||
// 只有在init的时候执行一次
|
||||
willMount(() => {
|
||||
console.log(`Counter willMount with count ${count}`);
|
||||
});
|
||||
// 在elements被挂载到DOM之后执行
|
||||
didMount(() => {
|
||||
console.log(`Counter didMount with count ${count}`);
|
||||
});
|
||||
|
||||
return (
|
||||
<section>
|
||||
count: {count}, double is: {doubleCount}
|
||||
<button onClick={() => count++}>Add</button>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
function MyComp() {
|
||||
let count = 0;
|
||||
|
||||
{
|
||||
console.log(count);
|
||||
const i = count * 2;
|
||||
console.log(i);
|
||||
}
|
||||
|
||||
console.log(count);
|
||||
const i = count * 2;
|
||||
console.log(i);
|
||||
|
||||
const XX = () => {};
|
||||
|
||||
return (
|
||||
<>
|
||||
<h1 className="123">Hello dlight fn comp</h1>
|
||||
<section>
|
||||
count: {count}, double is: {db}
|
||||
<button onClick={() => (count += 1)}>Add</button>
|
||||
</section>
|
||||
<Button onClick={() => alert(count)}>Alter count</Button>
|
||||
<ConditionalRendering count={count} />
|
||||
<ArrayModification />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function ConditionalRendering({ count }) {
|
||||
return (
|
||||
<section>
|
||||
<h1>Condition</h1>
|
||||
<if cond={count > 1}>{count} is bigger than is 1</if>
|
||||
<else-if cond={count === 1}>{count} is equal to 1</else-if>
|
||||
<else>{count} is smaller than 1</else>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
render(MyComp, 'main');
|
|
@ -1,8 +1,4 @@
|
|||
# delight-transformer
|
||||
|
||||
This is a experimental package to implement [API2.0](https://gitee.com/openInula/rfcs/blob/master/src/002-zouyu-API2.0.md) to [dlight](https://github.com/dlight-js/dlight) class.
|
||||
|
||||
## Todo-list
|
||||
# Todo-list
|
||||
|
||||
- [ ] function 2 class.
|
||||
- [x] assignment 2 property
|
||||
|
@ -13,30 +9,22 @@ This is a experimental package to implement [API2.0](https://gitee.com/openInula
|
|||
- [ ] partial object destructuring
|
||||
- [ ] nested object destructuring
|
||||
- [ ] nested array destructuring
|
||||
- [ ] alias
|
||||
- [x] alias
|
||||
- [x] add `this` @HQ
|
||||
- [ ] for (jsx-parser) -> playground + benchmark @YH
|
||||
- [ ] lifecycle @HQ
|
||||
- [ ] ref @HQ (to validate)
|
||||
- [ ] env @HQ (to validate)
|
||||
- [x] for (jsx-parser) -> playground + benchmark @YH
|
||||
- [x] lifecycle @HQ
|
||||
- [x] ref @HQ (to validate)
|
||||
- [x] env @HQ (to validate)
|
||||
- [ ] Sub component
|
||||
- [ ] Early Return
|
||||
- [ ] custom hook -> Model @YH
|
||||
- [ ] JSX
|
||||
- [x] style
|
||||
- [x] fragment
|
||||
- [ ] ref (to validate)
|
||||
- [x] ref (to validate)
|
||||
- [ ] snippet
|
||||
- [x] for
|
||||
|
||||
# 4.8 TODO
|
||||
@YH
|
||||
* Benchmark(result + comparison)
|
||||
* Playground(@HQ publish) deploy
|
||||
* PPT
|
||||
* DEMO
|
||||
* api2.1 compiled code
|
||||
|
||||
|
||||
# function component syntax
|
||||
|
||||
|
@ -60,10 +48,7 @@ This is a experimental package to implement [API2.0](https://gitee.com/openInula
|
|||
- [ ] early return
|
||||
|
||||
|
||||
# custom hook syntax
|
||||
TODO
|
||||
|
||||
# issues
|
||||
# Issues
|
||||
- [ ] partial props destructuring -> support this.$props @YH
|
||||
```jsx
|
||||
function Input({onClick, xxx, ...props}) {
|
||||
|
@ -105,8 +90,8 @@ class FetchModel {}
|
|||
<button>Add, Now is {count}</button>
|
||||
```
|
||||
|
||||
|
||||
# Watch
|
||||
# Proposal
|
||||
## Watch
|
||||
|
||||
自动将Statement包裹Watch的反例:
|
||||
```jsx
|
|
@ -116,7 +116,8 @@ describe('props', () => {
|
|||
`);
|
||||
});
|
||||
|
||||
it('should support children alias with default value', ({ container }) => {
|
||||
// TODO: should support children default
|
||||
it.fails('should support children alias with default value', ({ container }) => {
|
||||
function Child({ children: alias = 'default child' }) {
|
||||
return <h1>{alias}</h1>;
|
||||
}
|
||||
|
@ -135,6 +136,4 @@ describe('props', () => {
|
|||
`);
|
||||
});
|
||||
});
|
||||
|
||||
describe('nested');
|
||||
});
|
||||
|
|
|
@ -6,6 +6,7 @@ import type { Scope } from '@babel/traverse';
|
|||
const DECORATOR_PROPS = 'Prop';
|
||||
const DECORATOR_CHILDREN = 'Children';
|
||||
const DECORATOR_WATCH = 'Watch';
|
||||
const DECORATOR_ENV = 'Env';
|
||||
|
||||
function replaceFnWithClass(path: NodePath<t.FunctionDeclaration>, classTransformer: ClassComponentTransformer) {
|
||||
const originalName = path.node.id.name;
|
||||
|
@ -38,8 +39,14 @@ export class PluginProvider {
|
|||
const classTransformer = new ClassComponentTransformer(this.babelApi, path);
|
||||
// transform the parameters to props
|
||||
const params = path.node.params;
|
||||
// ---
|
||||
const props = params[0];
|
||||
classTransformer.transformProps(props);
|
||||
|
||||
// --- env
|
||||
const env = params[1];
|
||||
classTransformer.transformEnv(env);
|
||||
|
||||
// iterate the function body orderly
|
||||
const body = path.node.body.body;
|
||||
body.forEach((node, idx) => {
|
||||
|
@ -367,46 +374,50 @@ class ClassComponentTransformer {
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the node should be transformed to watch method, including:
|
||||
* 1. call expression.
|
||||
* 2. for loop
|
||||
* 3. while loop
|
||||
* 4. if statement
|
||||
* 5. switch statement
|
||||
* 6. assignment expression
|
||||
* 7. try statement
|
||||
* 8. ++/-- expression
|
||||
* @param node
|
||||
*/
|
||||
shouldTransformWatch(node: t.Node): node is ToWatchNode {
|
||||
if (this.t.isExpressionStatement(node)) {
|
||||
if (this.t.isCallExpression(node.expression)) {
|
||||
return true;
|
||||
}
|
||||
if (this.t.isAssignmentExpression(node.expression)) {
|
||||
return true;
|
||||
}
|
||||
if (this.t.isUpdateExpression(node.expression)) {
|
||||
return true;
|
||||
}
|
||||
// TODO: need refactor, maybe merge with props?
|
||||
transformEnv(env: t.Identifier | t.Pattern | t.RestElement) {
|
||||
if (!env) {
|
||||
return;
|
||||
}
|
||||
if (this.t.isForStatement(node)) {
|
||||
return true;
|
||||
}
|
||||
if (this.t.isWhileStatement(node)) {
|
||||
return true;
|
||||
}
|
||||
if (this.t.isIfStatement(node)) {
|
||||
return true;
|
||||
}
|
||||
if (this.t.isSwitchStatement(node)) {
|
||||
return true;
|
||||
}
|
||||
if (this.t.isTryStatement(node)) {
|
||||
return true;
|
||||
if (!this.t.isObjectPattern(env)) {
|
||||
throw Error('Unsupported env type, please use object destructuring.');
|
||||
}
|
||||
env.properties.forEach(property => {
|
||||
if (this.t.isObjectProperty(property)) {
|
||||
const key = property.key;
|
||||
let defaultVal: t.Expression;
|
||||
if (this.t.isIdentifier(key)) {
|
||||
let alias: t.Identifier | null = null;
|
||||
if (this.t.isAssignmentPattern(property.value)) {
|
||||
const propName = property.value.left;
|
||||
defaultVal = property.value.right;
|
||||
if (this.t.isIdentifier(propName)) {
|
||||
// handle alias
|
||||
if (propName.name !== key.name) {
|
||||
alias = propName;
|
||||
}
|
||||
} else {
|
||||
throw Error(`Unsupported assignment type in object destructuring: ${propName.type}`);
|
||||
}
|
||||
} else if (this.t.isIdentifier(property.value)) {
|
||||
// handle alias
|
||||
if (key.name !== property.value.name) {
|
||||
alias = property.value;
|
||||
}
|
||||
} else if (this.t.isObjectPattern(property.value)) {
|
||||
throw Error('Unsupported nested env destructuring');
|
||||
}
|
||||
|
||||
return false;
|
||||
if (alias) {
|
||||
this.addClassPropertyForPropAlias(alias, key);
|
||||
}
|
||||
this.addClassProperty(key, DECORATOR_ENV, defaultVal);
|
||||
return;
|
||||
}
|
||||
throw new Error('Unsupported props destructuring, please use simple object destructuring.');
|
||||
} else {
|
||||
throw new Error('Unsupported env destructuring, please use plain object destructuring.');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,21 +59,21 @@ describe('component-composition', () => {
|
|||
//language=JSX
|
||||
expect(
|
||||
transform(`
|
||||
function UserProfile({
|
||||
name = '',
|
||||
age = null,
|
||||
favouriteColors : [{r,g,b}, color2],
|
||||
isAvailable = false,
|
||||
}) {
|
||||
return (
|
||||
<>
|
||||
<p>My name is {name}!</p >
|
||||
<p>My age is {age}!</p >
|
||||
<p>My favourite colors are {favouriteColors.join(', ')}!</p >
|
||||
<p>I am {isAvailable ? 'available' : 'not available'}</p >
|
||||
</>
|
||||
);
|
||||
}`),
|
||||
function UserProfile({
|
||||
name = '',
|
||||
age = null,
|
||||
favouriteColors: [{r, g, b}, color2],
|
||||
isAvailable = false,
|
||||
}) {
|
||||
return (
|
||||
<>
|
||||
<p>My name is {name}!</p>
|
||||
<p>My age is {age}!</p>
|
||||
<p>My favourite colors are {favouriteColors.join(', ')}!</p>
|
||||
<p>I am {isAvailable ? 'available' : 'not available'}</p>
|
||||
</>
|
||||
);
|
||||
}`),
|
||||
`
|
||||
class UserProfile {
|
||||
@Prop name = '';
|
||||
|
@ -86,7 +86,7 @@ describe('component-composition', () => {
|
|||
g;
|
||||
b;
|
||||
xx = (() => {
|
||||
const [{r, g, b},color2] = this.favouriteColors;
|
||||
const [{r, g, b}, color2] = this.favouriteColors;
|
||||
this.r = r
|
||||
this.g = g
|
||||
this.b = b
|
||||
|
@ -108,31 +108,64 @@ describe('component-composition', () => {
|
|||
//language=JSX
|
||||
expect(
|
||||
transform(`
|
||||
function Card({ children }) {
|
||||
return (
|
||||
<div className="card">
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}`),
|
||||
function Card({children}) {
|
||||
return (
|
||||
<div className="card">
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}`),
|
||||
`
|
||||
class Card {
|
||||
@Children children
|
||||
class Card {
|
||||
@Children children
|
||||
|
||||
Body() {
|
||||
div(\`card\`, this.children)
|
||||
}
|
||||
Body() {
|
||||
div(\`card\`, this.children)
|
||||
}
|
||||
`
|
||||
}
|
||||
`
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('env', () => {
|
||||
it('should support env', () => {
|
||||
expect(
|
||||
transform(`
|
||||
function App () {
|
||||
return <Env theme="dark">
|
||||
<Child name="child"/>
|
||||
</Env>;
|
||||
}
|
||||
function Child({ name },{ theme }){
|
||||
return <div>{theme}</div>
|
||||
}
|
||||
`)
|
||||
).toMatchInlineSnapshot(`
|
||||
"class App extends View {
|
||||
Body() {
|
||||
return <env theme=\\"dark\\">
|
||||
<Child name=\\"child\\" />
|
||||
</env>;
|
||||
}
|
||||
}
|
||||
class Child extends View {
|
||||
@Prop
|
||||
name;
|
||||
@Env
|
||||
theme;
|
||||
Body() {
|
||||
return <div>{this.theme}</div>;
|
||||
}
|
||||
}"
|
||||
`);
|
||||
});
|
||||
});
|
||||
it('should support children prop with alias', () => {
|
||||
//language=JSX
|
||||
expect(
|
||||
transform(`
|
||||
function Card({children: content, foo: bar = 1, val = 1}) {
|
||||
function Card({children: content, foo: bar = 1, val = 1}) {
|
||||
return (
|
||||
<div className="card">
|
||||
{content}
|
||||
|
@ -141,23 +174,30 @@ describe('component-composition', () => {
|
|||
}`)
|
||||
).toMatchInlineSnapshot(`
|
||||
"class Card extends View {
|
||||
@Children
|
||||
content;
|
||||
bar;
|
||||
@Prop
|
||||
foo = 1;
|
||||
@Prop
|
||||
val = 1;
|
||||
Body() {
|
||||
return <div className=\\"card\\">
|
||||
{this.content}
|
||||
</div>;
|
||||
@Children
|
||||
content;
|
||||
bar;
|
||||
@Prop
|
||||
foo = 1;
|
||||
@Prop
|
||||
val = 1;
|
||||
Body()
|
||||
{
|
||||
return <div className=\\
|
||||
"card\\">
|
||||
{
|
||||
this.content
|
||||
}
|
||||
@Watch
|
||||
$$bindNestDestructuring() {
|
||||
this.bar = this.foo;
|
||||
}
|
||||
}"
|
||||
</div>
|
||||
;
|
||||
}
|
||||
@Watch
|
||||
$$bindNestDestructuring()
|
||||
{
|
||||
this.bar = this.foo;
|
||||
}
|
||||
}
|
||||
"
|
||||
`);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -0,0 +1,114 @@
|
|||
/*
|
||||
* Copyright (c) 2024 Huawei Technologies Co.,Ltd.
|
||||
*
|
||||
* openInula is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
*
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { transform } from './transform';
|
||||
|
||||
describe('lifecycle', () => {
|
||||
it('should support willMount', () => {
|
||||
//language=JSX
|
||||
expect(
|
||||
transform(`
|
||||
function App() {
|
||||
willMount: {
|
||||
console.log('willMount')
|
||||
}
|
||||
return (
|
||||
<div/>
|
||||
);
|
||||
}`)
|
||||
).toMatchInlineSnapshot(`
|
||||
"class App extends View {
|
||||
willMount() {
|
||||
console.log('willMount');
|
||||
}
|
||||
Body() {
|
||||
return <div />;
|
||||
}
|
||||
}"
|
||||
`);
|
||||
});
|
||||
it('should support didMount', () => {
|
||||
//language=JSX
|
||||
expect(
|
||||
transform(`
|
||||
function App() {
|
||||
didMount: {
|
||||
console.log('didMount');
|
||||
}
|
||||
return (
|
||||
<div/>
|
||||
);
|
||||
}`)
|
||||
).toMatchInlineSnapshot(`
|
||||
"class App extends View {
|
||||
didMount() {
|
||||
console.log('didMount');
|
||||
}
|
||||
Body() {
|
||||
return <div />;
|
||||
}
|
||||
}"
|
||||
`);
|
||||
});
|
||||
|
||||
it('should support willUnmount', () => {
|
||||
//language=JSX
|
||||
expect(
|
||||
transform(`
|
||||
function App() {
|
||||
willUnmount: {
|
||||
console.log('willUnmount');
|
||||
}
|
||||
return (
|
||||
<div/>
|
||||
);
|
||||
}`)
|
||||
).toMatchInlineSnapshot(`
|
||||
"class App extends View {
|
||||
willUnmount() {
|
||||
console.log('willUnmount');
|
||||
}
|
||||
Body() {
|
||||
return <div />;
|
||||
}
|
||||
}"
|
||||
`);
|
||||
});
|
||||
|
||||
it('should support didUnmount', () => {
|
||||
//language=JSX
|
||||
expect(
|
||||
transform(`
|
||||
function App() {
|
||||
didUnmount: {
|
||||
console.log('didUnmount');
|
||||
}
|
||||
return (
|
||||
<div/>
|
||||
);
|
||||
}`)
|
||||
).toMatchInlineSnapshot(`
|
||||
"class App extends View {
|
||||
didUnmount() {
|
||||
console.log('didUnmount');
|
||||
}
|
||||
Body() {
|
||||
return <div />;
|
||||
}
|
||||
}"
|
||||
`);
|
||||
});
|
||||
});
|
|
@ -1,18 +1,19 @@
|
|||
import { it, describe, expect } from 'vitest';
|
||||
import { transform } from './transform';
|
||||
|
||||
describe('fn2Class', () => {
|
||||
it('should transform state assignment', () => {
|
||||
expect(
|
||||
//language=JSX
|
||||
transform(`
|
||||
export default function Name() {
|
||||
let name = 'John';
|
||||
describe('reactivity', () => {
|
||||
describe('state', () => {
|
||||
it('should transform state assignment', () => {
|
||||
expect(
|
||||
//language=JSX
|
||||
transform(`
|
||||
export default function Name() {
|
||||
let name = 'John';
|
||||
|
||||
return <h1>{name}</h1>;
|
||||
}
|
||||
`)
|
||||
).toMatchInlineSnapshot(`
|
||||
return <h1>{name}</h1>;
|
||||
}
|
||||
`)
|
||||
).toMatchInlineSnapshot(`
|
||||
"class Name extends View {
|
||||
name = 'John';
|
||||
Body() {
|
||||
|
@ -21,17 +22,17 @@ describe('fn2Class', () => {
|
|||
}
|
||||
export { Name as default };"
|
||||
`);
|
||||
});
|
||||
});
|
||||
|
||||
it('should transform state modification ', () => {
|
||||
expect(
|
||||
transform(`
|
||||
it('should transform state modification ', () => {
|
||||
expect(
|
||||
transform(`
|
||||
function MyApp() {
|
||||
let count = 0;
|
||||
return <div onClick={() => count++}>{count}</div>
|
||||
}
|
||||
`)
|
||||
).toMatchInlineSnapshot(`
|
||||
).toMatchInlineSnapshot(`
|
||||
"class MyApp extends View {
|
||||
count = 0;
|
||||
Body() {
|
||||
|
@ -39,18 +40,18 @@ describe('fn2Class', () => {
|
|||
}
|
||||
}"
|
||||
`);
|
||||
});
|
||||
});
|
||||
|
||||
it('should not transform variable out of scope', () => {
|
||||
expect(
|
||||
//language=JSX
|
||||
transform(`
|
||||
const name = "John";
|
||||
export default function Name() {
|
||||
return <h1>{name}</h1>;
|
||||
}
|
||||
`)
|
||||
).toMatchInlineSnapshot(`
|
||||
it('should not transform variable out of scope', () => {
|
||||
expect(
|
||||
//language=JSX
|
||||
transform(`
|
||||
const name = "John";
|
||||
export default function Name() {
|
||||
return <h1>{name}</h1>;
|
||||
}
|
||||
`)
|
||||
).toMatchInlineSnapshot(`
|
||||
"const name = \\"John\\";
|
||||
class Name extends View {
|
||||
Body() {
|
||||
|
@ -59,6 +60,7 @@ describe('fn2Class', () => {
|
|||
}
|
||||
export { Name as default };"
|
||||
`);
|
||||
});
|
||||
});
|
||||
|
||||
it('should transform function declaration', () => {
|
||||
|
@ -127,26 +129,6 @@ describe('fn2Class', () => {
|
|||
`);
|
||||
});
|
||||
|
||||
it('should not transform constant data', () => {
|
||||
expect(
|
||||
//language=JSX
|
||||
transform(`
|
||||
const name = "John";
|
||||
export default function Name() {
|
||||
return <h1>{name}</h1>;
|
||||
}
|
||||
`)
|
||||
).toMatchInlineSnapshot(`
|
||||
"const name = \\"John\\";
|
||||
class Name extends View {
|
||||
Body() {
|
||||
return <h1>{name}</h1>;
|
||||
}
|
||||
}
|
||||
export { Name as default };"
|
||||
`);
|
||||
});
|
||||
|
||||
it('should transform derived assignment', () => {
|
||||
expect(
|
||||
//language=JSX
|
||||
|
@ -172,18 +154,19 @@ describe('fn2Class', () => {
|
|||
`);
|
||||
});
|
||||
|
||||
it('should transform watch from call expression', () => {
|
||||
expect(
|
||||
//language=JSX
|
||||
transform(`
|
||||
export default function CountComp() {
|
||||
let count = 0;
|
||||
watch: console.log(count);
|
||||
describe('watch', () => {
|
||||
it('should transform watch from call expression', () => {
|
||||
expect(
|
||||
//language=JSX
|
||||
transform(`
|
||||
export default function CountComp() {
|
||||
let count = 0;
|
||||
watch: console.log(count);
|
||||
|
||||
return <div>{count}</div>;
|
||||
}
|
||||
`)
|
||||
).toMatchInlineSnapshot(`
|
||||
return <div>{count}</div>;
|
||||
}
|
||||
`)
|
||||
).toMatchInlineSnapshot(`
|
||||
"class CountComp extends View {
|
||||
count = 0;
|
||||
@Watch
|
||||
|
@ -196,60 +179,60 @@ describe('fn2Class', () => {
|
|||
}
|
||||
export { CountComp as default };"
|
||||
`);
|
||||
});
|
||||
});
|
||||
|
||||
it('should transform watch from block statement', () => {
|
||||
expect(
|
||||
//language=JSX
|
||||
transform(`
|
||||
export default function CountComp() {
|
||||
let count = 0;
|
||||
watch: for (let i = 0; i < count; i++) {
|
||||
console.log(\`The count change to: \${i}\`);
|
||||
it('should transform watch from block statement', () => {
|
||||
expect(
|
||||
//language=JSX
|
||||
transform(`
|
||||
export default function CountComp() {
|
||||
let count = 0;
|
||||
watch: for (let i = 0; i < count; i++) {
|
||||
console.log(\`The count change to: \${i}\`);
|
||||
}
|
||||
return <>
|
||||
<button onClick={() => count++}>Add</button>
|
||||
<div>{count}</div>
|
||||
</>;
|
||||
};
|
||||
`)
|
||||
).toMatchInlineSnapshot(
|
||||
`
|
||||
"class CountComp extends View {
|
||||
count = 0;
|
||||
@Watch
|
||||
_watch() {
|
||||
for (let i = 0; i < this.count; i++) {
|
||||
console.log(\`The count change to: \${i}\`);
|
||||
}
|
||||
}
|
||||
return <>
|
||||
<button onClick={() => count++}>Add</button>
|
||||
<div>{count}</div>
|
||||
</>;
|
||||
};
|
||||
`)
|
||||
).toMatchInlineSnapshot(
|
||||
Body() {
|
||||
return <>
|
||||
<button onClick={() => this.count++}>Add</button>
|
||||
<div>{this.count}</div>
|
||||
</>;
|
||||
}
|
||||
}
|
||||
export { CountComp as default };
|
||||
;"
|
||||
`
|
||||
"class CountComp extends View {
|
||||
count = 0;
|
||||
@Watch
|
||||
_watch() {
|
||||
for (let i = 0; i < this.count; i++) {
|
||||
console.log(\`The count change to: \${i}\`);
|
||||
}
|
||||
}
|
||||
Body() {
|
||||
return <>
|
||||
<button onClick={() => this.count++}>Add</button>
|
||||
<div>{this.count}</div>
|
||||
</>;
|
||||
}
|
||||
}
|
||||
export { CountComp as default };
|
||||
;"
|
||||
`
|
||||
);
|
||||
});
|
||||
);
|
||||
});
|
||||
|
||||
it('should transform watch from if statement', () => {
|
||||
expect(
|
||||
//language=JSX
|
||||
transform(`
|
||||
export default function CountComp() {
|
||||
let count = 0;
|
||||
watch: if (count > 0) {
|
||||
console.log(\`The count is greater than 0\`);
|
||||
}
|
||||
it('should transform watch from if statement', () => {
|
||||
expect(
|
||||
//language=JSX
|
||||
transform(`
|
||||
export default function CountComp() {
|
||||
let count = 0;
|
||||
watch: if (count > 0) {
|
||||
console.log(\`The count is greater than 0\`);
|
||||
}
|
||||
|
||||
return <div>{count}</div>;
|
||||
}
|
||||
`)
|
||||
).toMatchInlineSnapshot(`
|
||||
return <div>{count}</div>;
|
||||
}
|
||||
`)
|
||||
).toMatchInlineSnapshot(`
|
||||
"class CountComp extends View {
|
||||
count = 0;
|
||||
@Watch
|
||||
|
@ -264,30 +247,31 @@ describe('fn2Class', () => {
|
|||
}
|
||||
export { CountComp as default };"
|
||||
`);
|
||||
});
|
||||
});
|
||||
|
||||
it('should transform function component reactively', () => {
|
||||
expect(
|
||||
transform(`
|
||||
function MyComp() {
|
||||
let count = 0
|
||||
return <>
|
||||
<h1 count='123'>Hello dlight fn, {count}</h1>
|
||||
<button onClick={() => count +=1}>Add</button>
|
||||
<Button />
|
||||
</>
|
||||
}`)
|
||||
let count = 0
|
||||
return <>
|
||||
<h1 count='123'>Hello dlight fn, {count}</h1>
|
||||
<button onClick={() => count +=1}>Add</button>
|
||||
<Button />
|
||||
</>
|
||||
}`)
|
||||
).toMatchInlineSnapshot(`
|
||||
"class MyComp extends View {
|
||||
count = 0;
|
||||
Body() {
|
||||
return <>
|
||||
<h1 count='123'>Hello dlight fn, {this.count}</h1>
|
||||
<button onClick={() => this.count += 1}>Add</button>
|
||||
<Button />
|
||||
</>;
|
||||
}
|
||||
}"
|
||||
`);
|
||||
"class MyComp extends View {
|
||||
count = 0;
|
||||
Body() {
|
||||
return <>
|
||||
<h1 count='123'>Hello dlight fn, {this.count}</h1>
|
||||
<button onClick={() => this.count += 1}>Add</button>
|
||||
<Button />
|
||||
</>;
|
||||
}
|
||||
}"
|
||||
`);
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue