Skip to content

Commit adf5ac7

Browse files
committed
WIP
1 parent a161712 commit adf5ac7

File tree

3 files changed

+120
-0
lines changed

3 files changed

+120
-0
lines changed
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import type { JSX } from "solid-js";
2+
3+
function ErrorFree(props: { children: JSX.Element & Errorable<never> }) {
4+
return (<>{props.children}</>) as JSX.Element & Errorable<never>;
5+
}
6+
7+
function ErrorBoundary<T, U, V = U extends undefined ? never : U>(props: {
8+
children: JSX.Element & Errorable<T>;
9+
handle: (error: T) => U;
10+
}) {
11+
return (<>{props.children}</>) as JSX.Element & Errorable<V>;
12+
}
13+
14+
const ErrorTag = Symbol("Error");
15+
type Errorable<T> = { [ErrorTag]: T };
16+
17+
function Comp<T>(props: { children: JSX.Element & Errorable<T> }) {
18+
return (<>{props.children}</>) as JSX.Element & Errorable<T>;
19+
}
20+
21+
function WithError(props: { foo?: string }) {
22+
return (<div>WithError {props.foo}</div>) as unknown as JSX.Element &
23+
Errorable<"foo">;
24+
}
25+
26+
export default function App() {
27+
return (
28+
<ErrorFree>
29+
<Comp>
30+
<WithError foo="bar" />
31+
</Comp>
32+
</ErrorFree>
33+
);
34+
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import type { Code, Context, TsmLanguagePlugin } from "ts-macro";
2+
3+
export const jsxToFn = ({ ts }: Context): TsmLanguagePlugin => ({
4+
name: "@solid-macros/volar/jsx-to-fn",
5+
enforce: "post",
6+
resolveVirtualCode({ ast, codes, lang }) {
7+
if (!lang.endsWith("x")) return;
8+
ast.forEachChild(function walk(node) {
9+
if (ts.isJsxElement(node) || ts.isJsxSelfClosingElement(node)) {
10+
const openingLike = ts.isJsxElement(node) ? node.openingElement : node;
11+
if (/^[A-Z]/.test(openingLike.tagName.getText(ast))) {
12+
const props = openingLike.attributes.properties;
13+
const contentfulChildren = ts.isJsxElement(node)
14+
? node.children.filter(
15+
(child) =>
16+
!ts.isJsxText(child) || child.getText(ast).trim().length > 0,
17+
)
18+
: [];
19+
20+
codes.replaceRange(
21+
node.pos,
22+
node.end,
23+
[
24+
openingLike.tagName.getText(ast),
25+
openingLike.tagName.getStart(ast),
26+
{ semantic: { shouldHighlight: () => false } },
27+
],
28+
"({\n",
29+
...props.flatMap<Code>((prop) => {
30+
if (ts.isJsxAttribute(prop)) {
31+
return [
32+
[
33+
prop.name.getText(ast),
34+
prop.name.getStart(ast),
35+
{ semantic: { shouldHighlight: () => false } },
36+
],
37+
":",
38+
prop.initializer
39+
? ts.isJsxExpression(prop.initializer)
40+
? prop.initializer.expression
41+
? [
42+
prop.initializer.expression.getText(ast),
43+
prop.initializer.getStart(ast),
44+
]
45+
: "undefined"
46+
: [
47+
prop.initializer.getText(ast),
48+
prop.initializer.getStart(ast),
49+
]
50+
: "true",
51+
",\n",
52+
];
53+
}
54+
return [];
55+
}),
56+
...(ts.isJsxElement(node) && contentfulChildren.length > 0
57+
? ([
58+
..."children"
59+
.split("")
60+
.map((char): Code => [char, node.openingElement.end - 1]),
61+
":",
62+
...(contentfulChildren.length > 1
63+
? ([
64+
"[",
65+
...contentfulChildren.flatMap<Code>((node) => [
66+
[node.getFullText(ast), node.pos],
67+
",",
68+
]),
69+
"]",
70+
] satisfies Code[])
71+
: contentfulChildren.map<Code>((node) => [
72+
node.getFullText(ast),
73+
node.pos,
74+
])),
75+
] satisfies Code[])
76+
: []),
77+
"})",
78+
);
79+
}
80+
}
81+
node.forEachChild(walk);
82+
});
83+
},
84+
});

packages/volar/src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
type UnwrappedAccessorsOptions,
77
unwrappedAccessors,
88
} from "./features/unwrappedAccessors";
9+
import { jsxToFn } from "./features/jsxToFn";
910

1011
interface Options {
1112
/** Whether to make `<Show>` narrow the types with the condition */
@@ -30,5 +31,6 @@ export default createPlugin<Options | undefined>((ctx, options) => {
3031
? options.unwrappedAccessors
3132
: undefined,
3233
),
34+
jsxToFn(ctx),
3335
].filter((v) => !!v);
3436
});

0 commit comments

Comments
 (0)