@litsx/babel-preset-litsx 0.2.1 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +8 -1
- package/dist/index.cjs.map +1 -1
- package/dist/internal/transform-litsx-components.cjs +625 -406
- package/dist/internal/transform-litsx-components.cjs.map +1 -1
- package/dist/internal/transform-litsx-renderer-props.cjs +399 -0
- package/dist/internal/transform-litsx-renderer-props.cjs.map +1 -0
- package/dist/pipeline.cjs +10 -1
- package/dist/pipeline.cjs.map +1 -1
- package/dist/shared/transform-litsx-element-candidates-JMFlPFXK.cjs +1170 -0
- package/dist/shared/transform-litsx-element-candidates-JMFlPFXK.cjs.map +1 -0
- package/package.json +10 -3
- package/src/internal/transform-litsx-components.js +82 -119
- package/src/internal/transform-litsx-element-candidates.js +1173 -0
- package/src/internal/transform-litsx-param-rewrites.js +1 -1
- package/src/internal/transform-litsx-program.js +32 -0
- package/src/internal/transform-litsx-render-body.js +113 -0
- package/src/internal/transform-litsx-renderer-calls.js +92 -0
- package/src/internal/transform-litsx-renderer-props.js +368 -0
- package/src/internal/transform-litsx-wrapper-utils.js +30 -1
- package/src/pipeline.js +3 -0
|
@@ -8,7 +8,7 @@ function createThisMemberExpression(propName) {
|
|
|
8
8
|
return t.memberExpression(t.thisExpression(), t.identifier(propName));
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
export function transformJSXExpressions(jsxPath, bindings) {
|
|
11
|
+
export function transformJSXExpressions(jsxPath, bindings, state = null) {
|
|
12
12
|
const localNames = Array.from(bindings.keys());
|
|
13
13
|
|
|
14
14
|
jsxPath.traverse({
|
|
@@ -22,6 +22,15 @@ function createLitsxInfrastructureImport(importedName) {
|
|
|
22
22
|
);
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
+
function createLitsxInternalRuntimeImport(importedName) {
|
|
26
|
+
return t.importDeclaration(
|
|
27
|
+
[
|
|
28
|
+
t.importSpecifier(t.identifier(importedName), t.identifier(importedName)),
|
|
29
|
+
],
|
|
30
|
+
t.stringLiteral("@litsx/litsx/internal/runtime-render-context")
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
|
|
25
34
|
function createLitsxImport(importedName) {
|
|
26
35
|
return t.importDeclaration(
|
|
27
36
|
[
|
|
@@ -225,5 +234,28 @@ export function finalizeProgram(programPath, state) {
|
|
|
225
234
|
}
|
|
226
235
|
}
|
|
227
236
|
|
|
237
|
+
if (state.__litsxNeedsRendererCallImport) {
|
|
238
|
+
const bodyPathsWithInternalRuntime = programPath.get("body");
|
|
239
|
+
const internalRuntimeImports = bodyPathsWithInternalRuntime.filter(
|
|
240
|
+
(n) =>
|
|
241
|
+
n.isImportDeclaration() &&
|
|
242
|
+
n.node.source.value === "@litsx/litsx/internal/runtime-render-context"
|
|
243
|
+
);
|
|
244
|
+
|
|
245
|
+
let internalRuntimeImported = false;
|
|
246
|
+
internalRuntimeImports.some((importPath) => {
|
|
247
|
+
if (ensureNamedImport(importPath, "renderRendererCall")) {
|
|
248
|
+
internalRuntimeImported = true;
|
|
249
|
+
return true;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
return false;
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
if (!internalRuntimeImported) {
|
|
256
|
+
programPath.unshiftContainer("body", createLitsxInternalRuntimeImport("renderRendererCall"));
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
228
260
|
pruneUnusedLitsxStaticImports(programPath);
|
|
229
261
|
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createComponentInstanceRefSyncStatement,
|
|
3
|
+
hasRefProp,
|
|
4
|
+
lowerForwardedElementRefs,
|
|
5
|
+
} from "./transform-litsx-refs.js";
|
|
6
|
+
import {
|
|
7
|
+
replaceParamReferences,
|
|
8
|
+
transformJSXExpressions,
|
|
9
|
+
} from "./transform-litsx-param-rewrites.js";
|
|
10
|
+
import { transformJSXRendererCalls } from "./transform-litsx-renderer-calls.js";
|
|
11
|
+
|
|
12
|
+
let t;
|
|
13
|
+
|
|
14
|
+
export function setRenderBodyBabelTypes(nextTypes) {
|
|
15
|
+
t = nextTypes;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function createThisMemberExpression(propName) {
|
|
19
|
+
return t.memberExpression(t.thisExpression(), t.identifier(propName));
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function createNestedInitializerStatement(pattern, root, defaultValue) {
|
|
23
|
+
const rootAccess = createThisMemberExpression(root);
|
|
24
|
+
let sourceExpression = rootAccess;
|
|
25
|
+
|
|
26
|
+
if (defaultValue) {
|
|
27
|
+
sourceExpression = t.logicalExpression(
|
|
28
|
+
"??",
|
|
29
|
+
t.cloneNode(rootAccess),
|
|
30
|
+
t.cloneNode(defaultValue)
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return t.variableDeclaration("const", [
|
|
35
|
+
t.variableDeclarator(t.cloneNode(pattern), sourceExpression),
|
|
36
|
+
]);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function collectReturnStatement(functionPath, bindings, state) {
|
|
40
|
+
let returnStatement = null;
|
|
41
|
+
|
|
42
|
+
functionPath.traverse({
|
|
43
|
+
ReturnStatement(returnPath) {
|
|
44
|
+
if (t.isJSXElement(returnPath.node.argument)) {
|
|
45
|
+
returnStatement = returnPath.node;
|
|
46
|
+
transformJSXRendererCalls(returnPath, bindings, state);
|
|
47
|
+
transformJSXExpressions(returnPath, bindings, state);
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
return returnStatement;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function prepareComponentRender(functionPath, node, propertyNames, bindings, nestedInitializers, options = {}) {
|
|
56
|
+
const returnStatement = collectReturnStatement(
|
|
57
|
+
functionPath,
|
|
58
|
+
bindings,
|
|
59
|
+
options.state ?? null
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
if (!returnStatement) {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const capturedPropAliasStatements = replaceParamReferences(
|
|
67
|
+
functionPath,
|
|
68
|
+
bindings,
|
|
69
|
+
propertyNames
|
|
70
|
+
);
|
|
71
|
+
const prefixStatements = [];
|
|
72
|
+
|
|
73
|
+
const forwardRefOptions = options.forwardRef || null;
|
|
74
|
+
const resolvedRefPropName =
|
|
75
|
+
forwardRefOptions?.propName ||
|
|
76
|
+
(propertyNames.has("ref") || hasRefProp(functionPath) ? "ref" : null);
|
|
77
|
+
let needsCallbackRef = false;
|
|
78
|
+
|
|
79
|
+
if (resolvedRefPropName) {
|
|
80
|
+
prefixStatements.push(
|
|
81
|
+
...lowerForwardedElementRefs(functionPath, resolvedRefPropName)
|
|
82
|
+
);
|
|
83
|
+
needsCallbackRef =
|
|
84
|
+
prefixStatements.some(
|
|
85
|
+
(statement) =>
|
|
86
|
+
t.isExpressionStatement(statement) &&
|
|
87
|
+
t.isCallExpression(statement.expression) &&
|
|
88
|
+
t.isIdentifier(statement.expression.callee, { name: "useCallbackRef" })
|
|
89
|
+
) || needsCallbackRef;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (resolvedRefPropName && !forwardRefOptions) {
|
|
93
|
+
prefixStatements.push(createComponentInstanceRefSyncStatement());
|
|
94
|
+
needsCallbackRef = true;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (capturedPropAliasStatements.length > 0) {
|
|
98
|
+
prefixStatements.push(...capturedPropAliasStatements);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (nestedInitializers.length > 0) {
|
|
102
|
+
const initializerStatements = nestedInitializers.map(({ pattern, root, defaultValue }) =>
|
|
103
|
+
createNestedInitializerStatement(pattern, root, defaultValue)
|
|
104
|
+
);
|
|
105
|
+
prefixStatements.push(...initializerStatements);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return {
|
|
109
|
+
needsCallbackRef,
|
|
110
|
+
prefixStatements,
|
|
111
|
+
returnStatement,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
let t;
|
|
2
|
+
|
|
3
|
+
export function setRendererCallsBabelTypes(nextTypes) {
|
|
4
|
+
t = nextTypes;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
function createThisMemberExpression(propName) {
|
|
8
|
+
return t.memberExpression(t.thisExpression(), t.identifier(propName));
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function getBoundPropName(bindingInfo) {
|
|
12
|
+
if (typeof bindingInfo === "string") {
|
|
13
|
+
return bindingInfo;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
if (bindingInfo && typeof bindingInfo === "object") {
|
|
17
|
+
return bindingInfo.bindKey ?? null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function isPropBackedCallee(node, localNames) {
|
|
24
|
+
if (t.isIdentifier(node)) {
|
|
25
|
+
return localNames.includes(node.name);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (
|
|
29
|
+
t.isMemberExpression(node) &&
|
|
30
|
+
!node.computed &&
|
|
31
|
+
t.isIdentifier(node.object)
|
|
32
|
+
) {
|
|
33
|
+
return localNames.includes(node.object.name) && node.object.name === "props";
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function getPropBackedCalleeReplacement(node, bindings) {
|
|
40
|
+
if (t.isIdentifier(node)) {
|
|
41
|
+
const propName = getBoundPropName(bindings.get(node.name));
|
|
42
|
+
return propName ? createThisMemberExpression(propName) : node;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (
|
|
46
|
+
t.isMemberExpression(node) &&
|
|
47
|
+
!node.computed &&
|
|
48
|
+
t.isIdentifier(node.object)
|
|
49
|
+
) {
|
|
50
|
+
const propName = getBoundPropName(bindings.get(node.object.name));
|
|
51
|
+
if (!propName) {
|
|
52
|
+
return node;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return t.memberExpression(
|
|
56
|
+
createThisMemberExpression(propName),
|
|
57
|
+
t.cloneNode(node.property),
|
|
58
|
+
false
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return node;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function transformJSXRendererCalls(jsxPath, bindings, state = null) {
|
|
66
|
+
const localNames = Array.from(bindings.keys());
|
|
67
|
+
|
|
68
|
+
jsxPath.traverse({
|
|
69
|
+
JSXExpressionContainer(expressionPath) {
|
|
70
|
+
if (!t.isCallExpression(expressionPath.node.expression)) {
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const { callee, arguments: args } = expressionPath.node.expression;
|
|
75
|
+
if (!isPropBackedCallee(callee, localNames)) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (state) {
|
|
80
|
+
state.__litsxNeedsRendererCallImport = true;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
expressionPath.node.expression = t.callExpression(
|
|
84
|
+
t.identifier("renderRendererCall"),
|
|
85
|
+
[
|
|
86
|
+
getPropBackedCalleeReplacement(callee, bindings),
|
|
87
|
+
...args,
|
|
88
|
+
]
|
|
89
|
+
);
|
|
90
|
+
},
|
|
91
|
+
});
|
|
92
|
+
}
|
|
@@ -0,0 +1,368 @@
|
|
|
1
|
+
import jsxSyntaxPlugin from "@babel/plugin-syntax-jsx";
|
|
2
|
+
import { decodeVirtualAttributeName } from "@litsx/jsx-authoring";
|
|
3
|
+
import { importedBindingNeedsRendererContext } from "./transform-litsx-element-candidates.js";
|
|
4
|
+
|
|
5
|
+
let t;
|
|
6
|
+
|
|
7
|
+
function createHostReferenceExpression() {
|
|
8
|
+
return t.conditionalExpression(
|
|
9
|
+
t.binaryExpression(
|
|
10
|
+
"===",
|
|
11
|
+
t.unaryExpression("typeof", t.thisExpression(), true),
|
|
12
|
+
t.stringLiteral("undefined")
|
|
13
|
+
),
|
|
14
|
+
t.nullLiteral(),
|
|
15
|
+
t.thisExpression()
|
|
16
|
+
);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function stringifyJsxName(nameNode) {
|
|
20
|
+
if (t.isJSXIdentifier(nameNode)) {
|
|
21
|
+
return nameNode.name;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (t.isJSXMemberExpression(nameNode)) {
|
|
25
|
+
return `${stringifyJsxName(nameNode.object)}.${nameNode.property.name}`;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (t.isJSXNamespacedName(nameNode)) {
|
|
29
|
+
return `${nameNode.namespace.name}:${nameNode.name.name}`;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return "unknown";
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function getTag(node) {
|
|
36
|
+
const name = stringifyJsxName(node.name);
|
|
37
|
+
const isCapitalized =
|
|
38
|
+
name.charAt(0) === name.charAt(0).toUpperCase() &&
|
|
39
|
+
name.charAt(0) !== name.charAt(0).toLowerCase();
|
|
40
|
+
const isComponent =
|
|
41
|
+
node.name.type !== "JSXIdentifier" || isCapitalized || name.includes("-");
|
|
42
|
+
return { name, isComponent };
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function unwrapExpression(node) {
|
|
46
|
+
let current = node;
|
|
47
|
+
|
|
48
|
+
while (current) {
|
|
49
|
+
if (t.isParenthesizedExpression?.(current)) {
|
|
50
|
+
current = current.expression;
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (
|
|
55
|
+
t.isTSAsExpression?.(current) ||
|
|
56
|
+
t.isTSSatisfiesExpression?.(current) ||
|
|
57
|
+
t.isTypeCastExpression?.(current) ||
|
|
58
|
+
t.isTSNonNullExpression?.(current)
|
|
59
|
+
) {
|
|
60
|
+
current = current.expression;
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
break;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return current;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function getFunctionNodeFromBinding(binding) {
|
|
71
|
+
if (!binding?.path) {
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (binding.path.isFunctionDeclaration()) {
|
|
76
|
+
return binding.path.node;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (binding.path.isVariableDeclarator()) {
|
|
80
|
+
const init = unwrapExpression(binding.path.node.init);
|
|
81
|
+
if (t.isArrowFunctionExpression(init) || t.isFunctionExpression(init)) {
|
|
82
|
+
return init;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function mergeBooleanResults(results) {
|
|
90
|
+
return results.some(Boolean);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function jsxTreeNeedsRendererContext(node, scope, seenBindings = new Set()) {
|
|
94
|
+
if (!node) {
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (t.isJSXFragment(node)) {
|
|
99
|
+
return mergeBooleanResults(
|
|
100
|
+
node.children.map((child) => jsxChildNeedsRendererContext(child, scope, seenBindings))
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (!t.isJSXElement(node)) {
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const { isComponent } = getTag(node.openingElement);
|
|
109
|
+
if (isComponent) {
|
|
110
|
+
return true;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const childNeedsContext = mergeBooleanResults(
|
|
114
|
+
node.children.map((child) => jsxChildNeedsRendererContext(child, scope, seenBindings))
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
if (childNeedsContext) {
|
|
118
|
+
return true;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return mergeBooleanResults(
|
|
122
|
+
node.openingElement.attributes.map((attr) => {
|
|
123
|
+
if (!t.isJSXAttribute(attr) || !t.isJSXExpressionContainer(attr.value)) {
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
return expressionNeedsRendererContext(attr.value.expression, scope, seenBindings);
|
|
127
|
+
})
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function jsxChildNeedsRendererContext(child, scope, seenBindings) {
|
|
132
|
+
if (t.isJSXElement(child) || t.isJSXFragment(child)) {
|
|
133
|
+
return jsxTreeNeedsRendererContext(child, scope, seenBindings);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (t.isJSXExpressionContainer(child)) {
|
|
137
|
+
return expressionNeedsRendererContext(child.expression, scope, seenBindings);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return false;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function functionBodyNeedsRendererContext(body, scope, seenBindings = new Set()) {
|
|
144
|
+
if (!body) {
|
|
145
|
+
return false;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
if (t.isBlockStatement(body)) {
|
|
149
|
+
return mergeBooleanResults(
|
|
150
|
+
body.body.map((statement) => statementNeedsRendererContext(statement, scope, seenBindings))
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return expressionNeedsRendererContext(body, scope, seenBindings);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function statementNeedsRendererContext(statement, scope, seenBindings) {
|
|
158
|
+
if (t.isReturnStatement(statement)) {
|
|
159
|
+
return expressionNeedsRendererContext(statement.argument, scope, seenBindings);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
if (t.isIfStatement(statement)) {
|
|
163
|
+
return mergeBooleanResults([
|
|
164
|
+
statementNeedsRendererContext(statement.consequent, scope, seenBindings),
|
|
165
|
+
statement.alternate
|
|
166
|
+
? statementNeedsRendererContext(statement.alternate, scope, seenBindings)
|
|
167
|
+
: false,
|
|
168
|
+
]);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (t.isBlockStatement(statement)) {
|
|
172
|
+
return functionBodyNeedsRendererContext(statement, scope, seenBindings);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
return false;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
function callExpressionNeedsRendererContext(node, scope, seenBindings) {
|
|
179
|
+
const callee = unwrapExpression(node.callee);
|
|
180
|
+
if (!t.isIdentifier(callee)) {
|
|
181
|
+
return false;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const binding = scope.getBinding(callee.name);
|
|
185
|
+
const functionNode = getFunctionNodeFromBinding(binding);
|
|
186
|
+
if (!functionNode) {
|
|
187
|
+
return false;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
if (seenBindings.has(binding)) {
|
|
191
|
+
return false;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const nextSeenBindings = new Set(seenBindings);
|
|
195
|
+
nextSeenBindings.add(binding);
|
|
196
|
+
return functionBodyNeedsRendererContext(functionNode.body, binding.path.scope, nextSeenBindings);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
function expressionNeedsRendererContext(node, scope, seenBindings = new Set()) {
|
|
200
|
+
const expression = unwrapExpression(node);
|
|
201
|
+
if (!expression) {
|
|
202
|
+
return false;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
if (t.isJSXElement(expression) || t.isJSXFragment(expression)) {
|
|
206
|
+
return jsxTreeNeedsRendererContext(expression, scope, seenBindings);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
if (t.isConditionalExpression(expression)) {
|
|
210
|
+
return mergeBooleanResults([
|
|
211
|
+
expressionNeedsRendererContext(expression.consequent, scope, seenBindings),
|
|
212
|
+
expressionNeedsRendererContext(expression.alternate, scope, seenBindings),
|
|
213
|
+
]);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
if (t.isLogicalExpression(expression)) {
|
|
217
|
+
return mergeBooleanResults([
|
|
218
|
+
expressionNeedsRendererContext(expression.left, scope, seenBindings),
|
|
219
|
+
expressionNeedsRendererContext(expression.right, scope, seenBindings),
|
|
220
|
+
]);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
if (t.isSequenceExpression(expression)) {
|
|
224
|
+
return mergeBooleanResults(
|
|
225
|
+
expression.expressions.map((part) => expressionNeedsRendererContext(part, scope, seenBindings))
|
|
226
|
+
);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
if (t.isArrayExpression(expression)) {
|
|
230
|
+
return mergeBooleanResults(
|
|
231
|
+
expression.elements.filter(Boolean).map((part) => expressionNeedsRendererContext(part, scope, seenBindings))
|
|
232
|
+
);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
if (t.isCallExpression(expression)) {
|
|
236
|
+
return callExpressionNeedsRendererContext(expression, scope, seenBindings);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
return false;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function isBindableFunctionReference(expressionPath, options = {}) {
|
|
243
|
+
const expression = unwrapExpression(expressionPath.node);
|
|
244
|
+
if (
|
|
245
|
+
t.isArrowFunctionExpression(expression) ||
|
|
246
|
+
t.isFunctionExpression(expression)
|
|
247
|
+
) {
|
|
248
|
+
return functionBodyNeedsRendererContext(expression.body, expressionPath.scope);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
if (t.isIdentifier(expression)) {
|
|
252
|
+
const binding = expressionPath.scope.getBinding(expression.name);
|
|
253
|
+
const functionNode = getFunctionNodeFromBinding(binding);
|
|
254
|
+
if (!functionNode) {
|
|
255
|
+
const programPath = expressionPath.findParent((entry) => entry.isProgram?.());
|
|
256
|
+
return importedBindingNeedsRendererContext(
|
|
257
|
+
programPath,
|
|
258
|
+
expression.name,
|
|
259
|
+
options
|
|
260
|
+
);
|
|
261
|
+
}
|
|
262
|
+
return functionBodyNeedsRendererContext(functionNode.body, binding.path.scope, new Set([binding]));
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
return false;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
function shouldBindRendererContext(attributePath, rawName, expressionPath, options = {}) {
|
|
269
|
+
if (typeof rawName !== "string" || rawName[0] !== ".") {
|
|
270
|
+
return false;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
const openingElement = attributePath.parentPath;
|
|
274
|
+
if (!openingElement?.isJSXOpeningElement()) {
|
|
275
|
+
return false;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
const { isComponent } = getTag(openingElement.node);
|
|
279
|
+
if (!isComponent) {
|
|
280
|
+
return false;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
return isBindableFunctionReference(expressionPath, options);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
function ensureRendererBindingImport(programPath) {
|
|
287
|
+
const bodyPaths = programPath.get("body");
|
|
288
|
+
const runtimeImports = bodyPaths.filter(
|
|
289
|
+
(path) =>
|
|
290
|
+
path.isImportDeclaration() &&
|
|
291
|
+
path.node.source.value === "@litsx/litsx/internal/runtime-render-context"
|
|
292
|
+
);
|
|
293
|
+
|
|
294
|
+
const importSpecifier = t.importSpecifier(
|
|
295
|
+
t.identifier("bindRendererContext"),
|
|
296
|
+
t.identifier("bindRendererContext")
|
|
297
|
+
);
|
|
298
|
+
|
|
299
|
+
for (const importPath of runtimeImports) {
|
|
300
|
+
const { specifiers } = importPath.node;
|
|
301
|
+
const hasImport = specifiers.some(
|
|
302
|
+
(specifier) =>
|
|
303
|
+
t.isImportSpecifier(specifier) &&
|
|
304
|
+
t.isIdentifier(specifier.imported, { name: "bindRendererContext" })
|
|
305
|
+
);
|
|
306
|
+
|
|
307
|
+
if (hasImport) {
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
specifiers.push(importSpecifier);
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
programPath.unshiftContainer("body", t.importDeclaration(
|
|
316
|
+
[importSpecifier],
|
|
317
|
+
t.stringLiteral("@litsx/litsx/internal/runtime-render-context")
|
|
318
|
+
));
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
export default function transformLitsxRendererProps(api) {
|
|
322
|
+
api.assertVersion?.(7);
|
|
323
|
+
t = api.types;
|
|
324
|
+
|
|
325
|
+
return {
|
|
326
|
+
name: "transform-litsx-renderer-props",
|
|
327
|
+
inherits: jsxSyntaxPlugin.default || jsxSyntaxPlugin,
|
|
328
|
+
visitor: {
|
|
329
|
+
Program: {
|
|
330
|
+
enter(_, state) {
|
|
331
|
+
state.__litsxNeedsRendererBindingImport = false;
|
|
332
|
+
},
|
|
333
|
+
exit(programPath, state) {
|
|
334
|
+
if (state.__litsxNeedsRendererBindingImport) {
|
|
335
|
+
ensureRendererBindingImport(programPath);
|
|
336
|
+
}
|
|
337
|
+
},
|
|
338
|
+
},
|
|
339
|
+
JSXAttribute(path, state) {
|
|
340
|
+
const { node } = path;
|
|
341
|
+
if (node.value?.type !== "JSXExpressionContainer") {
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
const rawName = decodeVirtualAttributeName(node.name.name) ?? node.name.name;
|
|
346
|
+
const expressionPath = path.get("value.expression");
|
|
347
|
+
if (!expressionPath?.node) {
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
if (!shouldBindRendererContext(path, rawName, expressionPath, {
|
|
352
|
+
filename: state.file?.opts?.filename || "",
|
|
353
|
+
})) {
|
|
354
|
+
return;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
state.__litsxNeedsRendererBindingImport = true;
|
|
358
|
+
node.value.expression = t.callExpression(
|
|
359
|
+
t.identifier("bindRendererContext"),
|
|
360
|
+
[
|
|
361
|
+
createHostReferenceExpression(),
|
|
362
|
+
expressionPath.node,
|
|
363
|
+
]
|
|
364
|
+
);
|
|
365
|
+
},
|
|
366
|
+
},
|
|
367
|
+
};
|
|
368
|
+
}
|
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
let t;
|
|
2
2
|
|
|
3
|
+
function isCapitalizedComponentName(name) {
|
|
4
|
+
if (typeof name !== "string" || name.length === 0) {
|
|
5
|
+
return false;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const first = name[0];
|
|
9
|
+
return first === first.toUpperCase() && first !== first.toLowerCase();
|
|
10
|
+
}
|
|
11
|
+
|
|
3
12
|
export function setWrapperUtilsBabelTypes(nextTypes) {
|
|
4
13
|
t = nextTypes;
|
|
5
14
|
}
|
|
@@ -67,6 +76,7 @@ export function maybeTransformWrappedVariableDeclarator({
|
|
|
67
76
|
{
|
|
68
77
|
...resolvedPluginOptions,
|
|
69
78
|
...wrapperMeta.options,
|
|
79
|
+
state,
|
|
70
80
|
typeResolver: state?.__litsxTypeResolver,
|
|
71
81
|
warn: (warning) => {
|
|
72
82
|
state?.__litsxWarnings?.push(warning);
|
|
@@ -129,12 +139,17 @@ export function handlePotentialComponentExport({
|
|
|
129
139
|
exportName = declaration.declarations[0].id.name;
|
|
130
140
|
}
|
|
131
141
|
|
|
142
|
+
if (exportName && !isCapitalizedComponentName(exportName)) {
|
|
143
|
+
return false;
|
|
144
|
+
}
|
|
145
|
+
|
|
132
146
|
const classNode = transformFunction(
|
|
133
147
|
declarationPath,
|
|
134
148
|
exportPath.findParent((p) => p.isProgram()),
|
|
135
149
|
exportName,
|
|
136
150
|
{
|
|
137
151
|
...state?.__litsxResolvedPluginOptions,
|
|
152
|
+
state,
|
|
138
153
|
typeResolver,
|
|
139
154
|
warn: (warning) => {
|
|
140
155
|
state?.__litsxWarnings?.push(warning);
|
|
@@ -170,6 +185,10 @@ export function handlePotentialComponentExport({
|
|
|
170
185
|
: undefined;
|
|
171
186
|
const programPath = exportPath.findParent((p) => p.isProgram());
|
|
172
187
|
|
|
188
|
+
if (exportName && !isCapitalizedComponentName(exportName)) {
|
|
189
|
+
return false;
|
|
190
|
+
}
|
|
191
|
+
|
|
173
192
|
if (initPath.isCallExpression()) {
|
|
174
193
|
const wrapperMeta = getWrapperMetadata(initPath);
|
|
175
194
|
if (!wrapperMeta) return false;
|
|
@@ -184,6 +203,7 @@ export function handlePotentialComponentExport({
|
|
|
184
203
|
{
|
|
185
204
|
...state?.__litsxResolvedPluginOptions,
|
|
186
205
|
...wrapperMeta.options,
|
|
206
|
+
state,
|
|
187
207
|
typeResolver,
|
|
188
208
|
warn: (warning) => {
|
|
189
209
|
state?.__litsxWarnings?.push(warning);
|
|
@@ -196,7 +216,11 @@ export function handlePotentialComponentExport({
|
|
|
196
216
|
exportPath.scope.removeBinding(exportName);
|
|
197
217
|
}
|
|
198
218
|
|
|
199
|
-
exportPath.replaceWith(
|
|
219
|
+
exportPath.replaceWith(
|
|
220
|
+
isDefault
|
|
221
|
+
? t.exportDefaultDeclaration(classNode)
|
|
222
|
+
: t.exportNamedDeclaration(classNode, [])
|
|
223
|
+
);
|
|
200
224
|
exportPath.requeue();
|
|
201
225
|
pruneWrapperImports(wrapperMeta);
|
|
202
226
|
updateTransformState?.(state, classNode);
|
|
@@ -217,6 +241,10 @@ export function handlePotentialComponentExport({
|
|
|
217
241
|
? wrapperMeta.functionPath.node.id.name
|
|
218
242
|
: undefined;
|
|
219
243
|
|
|
244
|
+
if (!inferredName || !isCapitalizedComponentName(inferredName)) {
|
|
245
|
+
return false;
|
|
246
|
+
}
|
|
247
|
+
|
|
220
248
|
const classNode = transformFunction(
|
|
221
249
|
wrapperMeta.functionPath,
|
|
222
250
|
programPath,
|
|
@@ -224,6 +252,7 @@ export function handlePotentialComponentExport({
|
|
|
224
252
|
{
|
|
225
253
|
...state?.__litsxResolvedPluginOptions,
|
|
226
254
|
...wrapperMeta.options,
|
|
255
|
+
state,
|
|
227
256
|
typeResolver,
|
|
228
257
|
warn: (warning) => {
|
|
229
258
|
state?.__litsxWarnings?.push(warning);
|