Skip to content

Commit c073810

Browse files
committed
feat: impl pickJSXFormProps
1 parent 329347a commit c073810

File tree

2 files changed

+178
-3
lines changed

2 files changed

+178
-3
lines changed
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
// Copyright 2025 The Lynx Authors. All rights reserved.
2+
// Licensed under the Apache License Version 2.0 that can be found in the
3+
// LICENSE file in the root directory of this source tree.
4+
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi } from 'vitest';
5+
import { pickJSXFromProps } from '../../src/mtc/pickJSXFromProps';
6+
7+
function BTC1() {
8+
return <view>BTC1</view>;
9+
}
10+
function BTC2() {
11+
return <view>BTC2</view>;
12+
}
13+
function BTC3() {
14+
return <view>BTC3</view>;
15+
}
16+
function BTC4() {
17+
return <view>BTC4</view>;
18+
}
19+
function BTC5() {
20+
return <view>BTC5</view>;
21+
}
22+
function BTC6() {
23+
return <view>BTC6</view>;
24+
}
25+
const mtcProps = {
26+
p1: <BTC1 />,
27+
p2: { x1: <BTC2 /> },
28+
p3: [<BTC3 />, <BTC5 />],
29+
p4: () => <BTC4 />,
30+
children: <BTC6 />,
31+
p5: {
32+
a: 1,
33+
b: 'string',
34+
c: null,
35+
d: undefined,
36+
e: true,
37+
f: false,
38+
g: () => {},
39+
h: 123,
40+
i: { x: 1, y: 2 },
41+
}
42+
};
43+
function RealMTC(props) {
44+
const foo = true;
45+
return (
46+
<>
47+
{props.p2.x1}
48+
{props.children}
49+
{foo && props.p1}
50+
{...props.p3}
51+
{props.p4()}
52+
{props.p5}
53+
</>
54+
);
55+
}
56+
function RootBTC() {
57+
return (
58+
<RealMTC {...mtcProps}>
59+
<BTC6 />
60+
</RealMTC>
61+
);
62+
}
63+
64+
it('pickJSXFromProps', () => {
65+
const result = pickJSXFromProps(mtcProps);
66+
expect(result).toMatchInlineSnapshot(`
67+
[
68+
[
69+
<BTC1 />,
70+
<BTC2 />,
71+
<BTC3 />,
72+
<BTC5 />,
73+
<BTC4 />,
74+
<BTC6 />,
75+
],
76+
{
77+
"children": {
78+
"$$typeof": Symbol(mtc-slot),
79+
"i": 5,
80+
},
81+
"p1": {
82+
"$$typeof": Symbol(mtc-slot),
83+
"i": 0,
84+
},
85+
"p2": {
86+
"x1": {
87+
"$$typeof": Symbol(mtc-slot),
88+
"i": 1,
89+
},
90+
},
91+
"p3": [
92+
{
93+
"$$typeof": Symbol(mtc-slot),
94+
"i": 2,
95+
},
96+
{
97+
"$$typeof": Symbol(mtc-slot),
98+
"i": 3,
99+
},
100+
],
101+
"p4": [Function],
102+
"p5": {
103+
"a": 1,
104+
"b": "string",
105+
"c": null,
106+
"d": undefined,
107+
"e": true,
108+
"f": false,
109+
"g": [Function],
110+
"h": 123,
111+
"i": {
112+
"x": 1,
113+
"y": 2,
114+
},
115+
},
116+
},
117+
]
118+
`);
119+
});
Lines changed: 59 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,69 @@
11
// Copyright 2025 The Lynx Authors. All rights reserved.
22
// Licensed under the Apache License Version 2.0 that can be found in the
33
// LICENSE file in the root directory of this source tree.
4-
import type { ReactNode } from 'react';
4+
import type { VNode } from 'preact';
55

66
type JSXRecord = Record<string, {
77
$$typeof: symbol;
88
i: number;
99
}>;
1010

11-
function pickJSXfromProps(props): [ReactNode, JSXRecord] {
12-
// transform jsx to { $$typeof: Symbol, i: 0 } in Record
11+
function isPreactVnode(value: any): value is VNode {
12+
return (
13+
typeof Symbol != 'undefined' && Symbol.for && value && typeof value === 'object'
14+
&& value.$$typeof === Symbol.for('react.element')
15+
);
16+
}
17+
18+
export function pickJSXFromProps(props: Record<string, any>): [VNode[], JSXRecord] {
19+
const jsxs: VNode[] = [];
20+
let index = 0;
21+
22+
function traverse(item: any): any {
23+
if (item === null || item === undefined) {
24+
return item;
25+
}
26+
27+
if (isPreactVnode(item)) {
28+
jsxs.push(item);
29+
const placeholder = {
30+
$$typeof: Symbol.for('mtc-slot'),
31+
i: index,
32+
};
33+
index++;
34+
return placeholder;
35+
}
36+
37+
if (typeof item === 'function') {
38+
const jsx = item();
39+
if (isPreactVnode(jsx)) {
40+
jsxs.push(jsx);
41+
const wrapperFunction = (...args: any[]) => {
42+
item(...args);
43+
return {
44+
$$typeof: Symbol.for('mtc-slot'),
45+
i: index,
46+
};
47+
};
48+
index++;
49+
return wrapperFunction;
50+
}
51+
}
52+
53+
if (Array.isArray(item)) {
54+
return item.map((item) => traverse(item));
55+
}
56+
57+
if (typeof item === 'object') {
58+
const result: any = {};
59+
for (const [key, value] of Object.entries(item)) {
60+
result[key] = traverse(value);
61+
}
62+
return result;
63+
}
64+
return item;
65+
}
66+
67+
const transformedProps = traverse(props);
68+
return [jsxs, transformedProps];
1369
}

0 commit comments

Comments
 (0)