@builder.io/mitosis 0.10.0 → 0.11.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/src/generators/angular/helpers/index.d.ts +1 -1
- package/dist/src/generators/angular/helpers/index.js +6 -3
- package/dist/src/generators/angular/signals/blocks.js +141 -6
- package/dist/src/generators/angular/signals/component.js +109 -23
- package/dist/src/generators/angular/signals/helpers/get-computed.d.ts +6 -0
- package/dist/src/generators/angular/signals/helpers/get-computed.js +79 -0
- package/dist/src/generators/angular/signals/helpers/get-dynamic-template-refs.d.ts +2 -0
- package/dist/src/generators/angular/signals/helpers/get-dynamic-template-refs.js +25 -0
- package/dist/src/generators/angular/signals/helpers/get-inputs.js +1 -1
- package/dist/src/generators/angular/signals/helpers/index.d.ts +6 -1
- package/dist/src/generators/angular/signals/helpers/index.js +9 -4
- package/dist/src/generators/angular/signals/plugins/get-code-processor-plugins.js +364 -11
- package/dist/src/generators/angular/types.d.ts +6 -1
- package/dist/src/generators/angular/types.js +1 -0
- package/dist/src/generators/mitosis/generator.js +8 -1
- package/dist/src/generators/react/generator.js +1 -1
- package/dist/src/generators/react/helpers/state.d.ts +1 -1
- package/dist/src/generators/react/helpers/state.js +47 -4
- package/dist/src/helpers/event-handlers.js +1 -1
- package/dist/src/helpers/is-hook-empty.d.ts +2 -0
- package/dist/src/helpers/is-hook-empty.js +14 -0
- package/dist/src/types/config.d.ts +4 -3
- package/package.json +1 -1
|
@@ -1,18 +1,23 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.getAngularCoreImportsAsString = void 0;
|
|
4
|
-
const getAngularCoreImportsAsString = ({ refs, output, input, model, onPush, effect, signal, }) => {
|
|
4
|
+
const getAngularCoreImportsAsString = ({ refs, output, input, model, onPush, effect, signal, computed, viewChild, viewContainerRef, templateRef, renderer, }) => {
|
|
5
5
|
const angularCoreImports = {
|
|
6
6
|
Component: true,
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
viewChild: refs || viewChild,
|
|
8
|
+
ElementRef: refs || viewChild,
|
|
9
|
+
ViewContainerRef: viewContainerRef,
|
|
10
|
+
TemplateRef: templateRef,
|
|
11
|
+
Renderer2: !!renderer,
|
|
10
12
|
model,
|
|
11
13
|
output,
|
|
12
14
|
input,
|
|
13
15
|
effect,
|
|
14
16
|
signal,
|
|
17
|
+
computed,
|
|
15
18
|
ChangeDetectionStrategy: onPush,
|
|
19
|
+
InputSignal: input,
|
|
20
|
+
ModelSignal: model,
|
|
16
21
|
};
|
|
17
22
|
return Object.entries(angularCoreImports)
|
|
18
23
|
.map(([key, bool]) => (bool ? key : ''))
|
|
@@ -1,18 +1,81 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.getCodeProcessorPlugins = void 0;
|
|
4
|
+
const get_computed_1 = require("../../../../generators/angular/signals/helpers/get-computed");
|
|
4
5
|
const babel_transform_1 = require("../../../../helpers/babel-transform");
|
|
5
6
|
const class_components_1 = require("../../../../helpers/class-components");
|
|
6
7
|
const event_handlers_1 = require("../../../../helpers/event-handlers");
|
|
7
8
|
const process_code_1 = require("../../../../helpers/plugins/process-code");
|
|
9
|
+
const symbol_processor_1 = require("../../../../symbols/symbol-processor");
|
|
8
10
|
const mitosis_node_1 = require("../../../../types/mitosis-node");
|
|
9
11
|
const types_1 = require("@babel/types");
|
|
12
|
+
// Helper functions for handling nested state updates
|
|
13
|
+
const getBaseObject = (node) => {
|
|
14
|
+
if (!node)
|
|
15
|
+
return null;
|
|
16
|
+
if (!(0, types_1.isMemberExpression)(node))
|
|
17
|
+
return node;
|
|
18
|
+
return getBaseObject(node.object);
|
|
19
|
+
};
|
|
20
|
+
const getPropertyFromStateChain = (node) => {
|
|
21
|
+
// Start at the leftmost object and traverse up to find the first property after 'state'
|
|
22
|
+
let current = node;
|
|
23
|
+
while ((0, types_1.isMemberExpression)(current)) {
|
|
24
|
+
if ((0, types_1.isMemberExpression)(current.object) &&
|
|
25
|
+
(0, types_1.isIdentifier)(current.object.object) &&
|
|
26
|
+
current.object.object.name === 'state' &&
|
|
27
|
+
(0, types_1.isIdentifier)(current.object.property)) {
|
|
28
|
+
return current.object.property.name;
|
|
29
|
+
}
|
|
30
|
+
current = current.object;
|
|
31
|
+
}
|
|
32
|
+
return null;
|
|
33
|
+
};
|
|
34
|
+
const getNestedPath = (node, topLevelProp) => {
|
|
35
|
+
const path = [];
|
|
36
|
+
let current = node;
|
|
37
|
+
// Collect all property names starting after the top-level property
|
|
38
|
+
let foundTopLevel = false;
|
|
39
|
+
while ((0, types_1.isMemberExpression)(current)) {
|
|
40
|
+
if ((0, types_1.isIdentifier)(current.property)) {
|
|
41
|
+
path.unshift(current.property.name);
|
|
42
|
+
}
|
|
43
|
+
if ((0, types_1.isMemberExpression)(current.object) &&
|
|
44
|
+
(0, types_1.isIdentifier)(current.object.object) &&
|
|
45
|
+
current.object.object.name === 'state' &&
|
|
46
|
+
(0, types_1.isIdentifier)(current.object.property) &&
|
|
47
|
+
current.object.property.name === topLevelProp) {
|
|
48
|
+
foundTopLevel = true;
|
|
49
|
+
break;
|
|
50
|
+
}
|
|
51
|
+
current = current.object;
|
|
52
|
+
}
|
|
53
|
+
return foundTopLevel ? path : [];
|
|
54
|
+
};
|
|
55
|
+
const buildPathAccess = (baseParam, propertyPath) => {
|
|
56
|
+
return propertyPath.reduce((acc, prop) => {
|
|
57
|
+
return (0, types_1.memberExpression)(acc, (0, types_1.identifier)(prop));
|
|
58
|
+
}, baseParam);
|
|
59
|
+
};
|
|
10
60
|
const isStateOrPropsExpression = (path) => {
|
|
11
61
|
return ((0, types_1.isMemberExpression)(path.node) &&
|
|
12
62
|
(0, types_1.isIdentifier)(path.node.object) &&
|
|
13
63
|
(0, types_1.isIdentifier)(path.node.property) &&
|
|
14
64
|
(path.node.object.name === 'props' || path.node.object.name === 'state'));
|
|
15
65
|
};
|
|
66
|
+
const isAFunctionOrMethod = (json, path) => {
|
|
67
|
+
var _a, _b, _c;
|
|
68
|
+
return (json &&
|
|
69
|
+
(0, types_1.isIdentifier)(path.node.object) &&
|
|
70
|
+
(0, types_1.isIdentifier)(path.node.property) &&
|
|
71
|
+
path.node.object.name === 'state' &&
|
|
72
|
+
json.state &&
|
|
73
|
+
typeof path.node.property.name === 'string' &&
|
|
74
|
+
json.state[path.node.property.name] &&
|
|
75
|
+
((_a = json.state[path.node.property.name]) === null || _a === void 0 ? void 0 : _a.type) &&
|
|
76
|
+
(((_b = json.state[path.node.property.name]) === null || _b === void 0 ? void 0 : _b.type) === 'method' ||
|
|
77
|
+
((_c = json.state[path.node.property.name]) === null || _c === void 0 ? void 0 : _c.type) === 'function'));
|
|
78
|
+
};
|
|
16
79
|
const handleAssignmentExpression = (path) => {
|
|
17
80
|
if ((0, types_1.isMemberExpression)(path.node.left) &&
|
|
18
81
|
(0, types_1.isIdentifier)(path.node.left.object) &&
|
|
@@ -23,8 +86,96 @@ const handleAssignmentExpression = (path) => {
|
|
|
23
86
|
const call = (0, types_1.callExpression)(root, [path.node.right]);
|
|
24
87
|
path.replaceWith(call);
|
|
25
88
|
}
|
|
89
|
+
else if ((0, types_1.isMemberExpression)(path.node.left) &&
|
|
90
|
+
path.node.left.computed &&
|
|
91
|
+
(((0, types_1.isMemberExpression)(path.node.left.object) &&
|
|
92
|
+
(0, types_1.isIdentifier)(path.node.left.object.object) &&
|
|
93
|
+
path.node.left.object.object.name === 'state') ||
|
|
94
|
+
((0, types_1.isIdentifier)(path.node.left.object) && path.node.left.object.name === 'state'))) {
|
|
95
|
+
/**
|
|
96
|
+
* Handle array element assignments like: state.arr[0] = '123'
|
|
97
|
+
* Example:
|
|
98
|
+
* Input: state.arr[0] = '123'
|
|
99
|
+
* Output: state.arr.update(arr => {
|
|
100
|
+
* arr[0] = '123';
|
|
101
|
+
* return arr;
|
|
102
|
+
* })
|
|
103
|
+
*/
|
|
104
|
+
let stateProp;
|
|
105
|
+
let baseObject;
|
|
106
|
+
if ((0, types_1.isIdentifier)(path.node.left.object) && path.node.left.object.name === 'state') {
|
|
107
|
+
stateProp = path.node.left.property;
|
|
108
|
+
baseObject = path.node.left.object;
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
stateProp = getPropertyFromStateChain(path.node.left);
|
|
112
|
+
if (!stateProp)
|
|
113
|
+
return;
|
|
114
|
+
baseObject = (0, types_1.memberExpression)((0, types_1.identifier)('state'), (0, types_1.identifier)(stateProp));
|
|
115
|
+
}
|
|
116
|
+
const root = (0, types_1.memberExpression)(baseObject, (0, types_1.identifier)('update'));
|
|
117
|
+
root.extra = { ...root.extra, updateExpression: true };
|
|
118
|
+
const paramName = typeof stateProp === 'string' ? stateProp : (0, types_1.isIdentifier)(stateProp) ? stateProp.name : 'item';
|
|
119
|
+
const param = (0, types_1.identifier)(paramName);
|
|
120
|
+
let assignTarget;
|
|
121
|
+
if ((0, types_1.isIdentifier)(path.node.left.object) && path.node.left.object.name === 'state') {
|
|
122
|
+
// Direct state array: state[index] = value
|
|
123
|
+
assignTarget = (0, types_1.memberExpression)(param, path.node.left.property, true);
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
// Property array: state.arr[index] = value
|
|
127
|
+
assignTarget = (0, types_1.memberExpression)(param, path.node.left.property, true);
|
|
128
|
+
}
|
|
129
|
+
const block = (0, types_1.blockStatement)([
|
|
130
|
+
(0, types_1.expressionStatement)((0, types_1.assignmentExpression)('=', assignTarget, path.node.right)),
|
|
131
|
+
(0, types_1.returnStatement)(param),
|
|
132
|
+
]);
|
|
133
|
+
const arrowFunction = (0, types_1.arrowFunctionExpression)([param], block);
|
|
134
|
+
const call = (0, types_1.callExpression)(root, [arrowFunction]);
|
|
135
|
+
path.replaceWith(call);
|
|
136
|
+
}
|
|
137
|
+
else if ((0, types_1.isMemberExpression)(path.node.left) &&
|
|
138
|
+
(0, types_1.isMemberExpression)(path.node.left.object) &&
|
|
139
|
+
(0, types_1.isIdentifier)(getBaseObject(path.node.left)) &&
|
|
140
|
+
getBaseObject(path.node.left).name === 'state') {
|
|
141
|
+
/**
|
|
142
|
+
* Handle any level of nested updates like state.store.something.nested = newVal
|
|
143
|
+
* Example:
|
|
144
|
+
* Input: state.store.something.nested = newVal
|
|
145
|
+
* Output: state.store.update(obj => ({
|
|
146
|
+
* ...obj,
|
|
147
|
+
* store: {
|
|
148
|
+
* ...obj.store,
|
|
149
|
+
* something: {
|
|
150
|
+
* ...obj.store.something,
|
|
151
|
+
* nested: newVal
|
|
152
|
+
* }
|
|
153
|
+
* }
|
|
154
|
+
* }))
|
|
155
|
+
*/
|
|
156
|
+
const stateProp = getPropertyFromStateChain(path.node.left);
|
|
157
|
+
if (!stateProp)
|
|
158
|
+
return;
|
|
159
|
+
const topLevelProp = (0, types_1.memberExpression)((0, types_1.identifier)('state'), (0, types_1.identifier)(stateProp));
|
|
160
|
+
const nestedPaths = getNestedPath(path.node.left, stateProp);
|
|
161
|
+
const root = (0, types_1.memberExpression)(topLevelProp, (0, types_1.identifier)('update'));
|
|
162
|
+
root.extra = { ...root.extra, updateExpression: true };
|
|
163
|
+
const paramName = stateProp;
|
|
164
|
+
const param = (0, types_1.identifier)(paramName);
|
|
165
|
+
let innerValue = path.node.right;
|
|
166
|
+
for (let i = nestedPaths.length - 1; i >= 0; i--) {
|
|
167
|
+
const spreadTarget = i === 0 ? param : buildPathAccess(param, nestedPaths.slice(0, i));
|
|
168
|
+
innerValue = (0, types_1.objectExpression)([
|
|
169
|
+
(0, types_1.spreadElement)(spreadTarget),
|
|
170
|
+
(0, types_1.objectProperty)((0, types_1.identifier)(nestedPaths[i]), innerValue, false, false),
|
|
171
|
+
]);
|
|
172
|
+
}
|
|
173
|
+
const arrowFunction = (0, types_1.arrowFunctionExpression)([param], innerValue, false);
|
|
174
|
+
const call = (0, types_1.callExpression)(root, [arrowFunction]);
|
|
175
|
+
path.replaceWith(call);
|
|
176
|
+
}
|
|
26
177
|
};
|
|
27
|
-
const handleMemberExpression = (path) => {
|
|
178
|
+
const handleMemberExpression = (path, json) => {
|
|
28
179
|
var _a, _b, _c, _d;
|
|
29
180
|
if (((_a = path.node.extra) === null || _a === void 0 ? void 0 : _a.makeCallExpressionDone) || ((_c = (_b = path.parentPath) === null || _b === void 0 ? void 0 : _b.node.extra) === null || _c === void 0 ? void 0 : _c.updateExpression)) {
|
|
30
181
|
// Don't add a function if we've done it already
|
|
@@ -39,6 +190,12 @@ const handleMemberExpression = (path) => {
|
|
|
39
190
|
return;
|
|
40
191
|
}
|
|
41
192
|
if (isStateOrPropsExpression(path)) {
|
|
193
|
+
// Check if the state property is a method or function type, and if so, bind it to 'this'
|
|
194
|
+
if (isAFunctionOrMethod(json, path)) {
|
|
195
|
+
const bindExpr = `${path.toString()}.bind(this)`;
|
|
196
|
+
path.replaceWith((0, types_1.identifier)(bindExpr));
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
42
199
|
path.node.extra = { ...path.node.extra, makeCallExpressionDone: true };
|
|
43
200
|
path.replaceWith((0, types_1.callExpression)(path.node, []));
|
|
44
201
|
}
|
|
@@ -66,7 +223,74 @@ const handleHookAndStateOnEvents = (path, isHookDepArray) => {
|
|
|
66
223
|
}
|
|
67
224
|
return false;
|
|
68
225
|
};
|
|
69
|
-
const
|
|
226
|
+
const handleTemplateLiteral = (path, json, context) => {
|
|
227
|
+
var _a;
|
|
228
|
+
const fnName = `templateStr_${(0, symbol_processor_1.hashCodeAsString)(path.toString())}`;
|
|
229
|
+
const extraParams = new Set();
|
|
230
|
+
// Collect loop variables from context
|
|
231
|
+
let currentContext = context;
|
|
232
|
+
while (currentContext === null || currentContext === void 0 ? void 0 : currentContext.parent) {
|
|
233
|
+
if (((_a = currentContext.parent.node) === null || _a === void 0 ? void 0 : _a.name) === mitosis_node_1.ForNodeName) {
|
|
234
|
+
const forNode = currentContext.parent.node;
|
|
235
|
+
if (forNode.scope.forName)
|
|
236
|
+
extraParams.add(forNode.scope.forName);
|
|
237
|
+
if (forNode.scope.indexName)
|
|
238
|
+
extraParams.add(forNode.scope.indexName);
|
|
239
|
+
}
|
|
240
|
+
currentContext = currentContext.parent;
|
|
241
|
+
}
|
|
242
|
+
const processedExpressions = path.node.expressions.map((expr) => {
|
|
243
|
+
let exprCode = '';
|
|
244
|
+
try {
|
|
245
|
+
const { code } = require('@babel/generator').default(expr);
|
|
246
|
+
exprCode = code;
|
|
247
|
+
}
|
|
248
|
+
catch (e) {
|
|
249
|
+
exprCode = expr.toString();
|
|
250
|
+
}
|
|
251
|
+
// Replace state.x with this.x() for signals
|
|
252
|
+
return exprCode
|
|
253
|
+
.replace(/\bstate\.(\w+)(?!\()/g, 'this.$1()')
|
|
254
|
+
.replace(/\bprops\.(\w+)(?!\()/g, 'this.$1()');
|
|
255
|
+
});
|
|
256
|
+
// Convert Set to Array for final usage
|
|
257
|
+
const paramsList = Array.from(extraParams);
|
|
258
|
+
json.state[fnName] = {
|
|
259
|
+
code: `${fnName}(${paramsList.join(', ')}) {
|
|
260
|
+
return \`${path.node.quasis
|
|
261
|
+
.map((quasi, i) => {
|
|
262
|
+
const escapedRaw = quasi.value.raw.replace(/\\/g, '\\\\').replace(/\$/g, '\\$');
|
|
263
|
+
return (escapedRaw +
|
|
264
|
+
(i < processedExpressions.length ? '${' + processedExpressions[i] + '}' : ''));
|
|
265
|
+
})
|
|
266
|
+
.join('')}\`;
|
|
267
|
+
}`,
|
|
268
|
+
type: 'method',
|
|
269
|
+
};
|
|
270
|
+
// Return the function call with any needed parameters
|
|
271
|
+
return `${fnName}(${paramsList.join(', ')})`;
|
|
272
|
+
};
|
|
273
|
+
const handleCallExpressionArgument = (json, arg) => {
|
|
274
|
+
var _a;
|
|
275
|
+
if ((0, types_1.isMemberExpression)(arg) &&
|
|
276
|
+
(0, types_1.isIdentifier)(arg.object) &&
|
|
277
|
+
(0, types_1.isIdentifier)(arg.property) &&
|
|
278
|
+
(arg.object.name === 'state' || arg.object.name === 'props') &&
|
|
279
|
+
!((_a = arg.extra) === null || _a === void 0 ? void 0 : _a.makeCallExpressionDone)) {
|
|
280
|
+
if (arg.object.name === 'state' && json) {
|
|
281
|
+
const argPath = { node: arg };
|
|
282
|
+
if (isAFunctionOrMethod(json, argPath)) {
|
|
283
|
+
const argStr = arg.object.name + '.' + arg.property.name;
|
|
284
|
+
return (0, types_1.identifier)(`${argStr}.bind(this)`);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
const newArg = (0, types_1.callExpression)(arg, []);
|
|
288
|
+
newArg.extra = { makeCallExpressionDone: true };
|
|
289
|
+
return newArg;
|
|
290
|
+
}
|
|
291
|
+
return arg;
|
|
292
|
+
};
|
|
293
|
+
const transformHooksAndState = (code, isHookDepArray, json) => {
|
|
70
294
|
return (0, babel_transform_1.babelTransformExpression)(code, {
|
|
71
295
|
AssignmentExpression(path) {
|
|
72
296
|
handleAssignmentExpression(path);
|
|
@@ -95,24 +319,87 @@ const transformHooksAndState = (code, isHookDepArray) => {
|
|
|
95
319
|
const call = (0, types_1.callExpression)(root, [arrowFunction]);
|
|
96
320
|
path.replaceWith(call);
|
|
97
321
|
}
|
|
322
|
+
else if ((0, types_1.isMemberExpression)(path.node.argument) &&
|
|
323
|
+
(0, types_1.isMemberExpression)(path.node.argument.object) &&
|
|
324
|
+
(0, types_1.isIdentifier)(getBaseObject(path.node.argument)) &&
|
|
325
|
+
getBaseObject(path.node.argument).name === 'state') {
|
|
326
|
+
// Handle nested update expressions like: state.obj.counter++
|
|
327
|
+
// Example:
|
|
328
|
+
// Input: state.obj.counter++
|
|
329
|
+
// Output: state.obj.update(obj => {
|
|
330
|
+
// Object.assign(obj, {
|
|
331
|
+
// counter: obj.counter + 1
|
|
332
|
+
// });
|
|
333
|
+
// return obj;
|
|
334
|
+
// });
|
|
335
|
+
//
|
|
336
|
+
const stateProp = getPropertyFromStateChain(path.node.argument);
|
|
337
|
+
if (!stateProp)
|
|
338
|
+
return;
|
|
339
|
+
const topLevelProp = (0, types_1.memberExpression)((0, types_1.identifier)('state'), (0, types_1.identifier)(stateProp));
|
|
340
|
+
const nestedPaths = getNestedPath(path.node.argument, stateProp);
|
|
341
|
+
const root = (0, types_1.memberExpression)(topLevelProp, (0, types_1.identifier)('update'));
|
|
342
|
+
root.extra = { ...root.extra, updateExpression: true };
|
|
343
|
+
const paramName = stateProp;
|
|
344
|
+
const param = (0, types_1.identifier)(paramName);
|
|
345
|
+
const lastPropName = nestedPaths[nestedPaths.length - 1];
|
|
346
|
+
const innerParamName = lastPropName + '_value';
|
|
347
|
+
const nestedPathAccess = buildPathAccess(param, nestedPaths.slice(0, -1));
|
|
348
|
+
let innerValue = (0, types_1.objectExpression)([
|
|
349
|
+
(0, types_1.spreadElement)(nestedPathAccess),
|
|
350
|
+
(0, types_1.objectProperty)((0, types_1.identifier)(lastPropName), (0, types_1.updateExpression)(path.node.operator, (0, types_1.identifier)(innerParamName), path.node.prefix), false, false),
|
|
351
|
+
]);
|
|
352
|
+
for (let i = nestedPaths.length - 2; i >= 0; i--) {
|
|
353
|
+
const spreadTarget = i === 0 ? param : buildPathAccess(param, nestedPaths.slice(0, i));
|
|
354
|
+
innerValue = (0, types_1.objectExpression)([
|
|
355
|
+
(0, types_1.spreadElement)(spreadTarget),
|
|
356
|
+
(0, types_1.objectProperty)((0, types_1.identifier)(nestedPaths[i]), innerValue, false, false),
|
|
357
|
+
]);
|
|
358
|
+
}
|
|
359
|
+
const block = (0, types_1.blockStatement)([
|
|
360
|
+
(0, types_1.expressionStatement)((0, types_1.callExpression)((0, types_1.memberExpression)((0, types_1.identifier)('Object'), (0, types_1.identifier)('assign')), [
|
|
361
|
+
param,
|
|
362
|
+
innerValue,
|
|
363
|
+
])),
|
|
364
|
+
(0, types_1.returnStatement)(param),
|
|
365
|
+
]);
|
|
366
|
+
const arrowFunction = (0, types_1.arrowFunctionExpression)([param], block);
|
|
367
|
+
const call = (0, types_1.callExpression)(root, [arrowFunction]);
|
|
368
|
+
path.replaceWith(call);
|
|
369
|
+
}
|
|
98
370
|
},
|
|
99
371
|
MemberExpression(path) {
|
|
100
372
|
const skip = handleHookAndStateOnEvents(path, isHookDepArray);
|
|
101
373
|
if (skip) {
|
|
102
374
|
return;
|
|
103
375
|
}
|
|
104
|
-
handleMemberExpression(path);
|
|
376
|
+
handleMemberExpression(path, json);
|
|
377
|
+
},
|
|
378
|
+
CallExpression(path) {
|
|
379
|
+
// if args has a state.x or props.x, we need to add this.x() to the args
|
|
380
|
+
if (path.node.arguments.length > 0) {
|
|
381
|
+
const newArgs = path.node.arguments.map((arg) => handleCallExpressionArgument(json, arg));
|
|
382
|
+
// Only replace arguments if we made any changes
|
|
383
|
+
if (newArgs.some((arg, i) => arg !== path.node.arguments[i])) {
|
|
384
|
+
path.node.arguments = newArgs;
|
|
385
|
+
}
|
|
386
|
+
}
|
|
105
387
|
},
|
|
106
388
|
});
|
|
107
389
|
};
|
|
108
390
|
const addToImportCall = (json, importName) => {
|
|
109
|
-
const
|
|
391
|
+
const importInstance = json.imports.find((imp) => imp.imports[importName]);
|
|
392
|
+
// Check if this is a type import - if it is, don't add it to importCalls
|
|
393
|
+
if ((importInstance === null || importInstance === void 0 ? void 0 : importInstance.importKind) === 'type') {
|
|
394
|
+
return;
|
|
395
|
+
}
|
|
396
|
+
const isImportCall = !!importInstance;
|
|
110
397
|
const isExportCall = json.exports ? !!json.exports[importName] : false;
|
|
111
398
|
if (isImportCall || isExportCall) {
|
|
112
399
|
json.compileContext.angular.extra.importCalls.push(importName);
|
|
113
400
|
}
|
|
114
401
|
};
|
|
115
|
-
const transformBindings = (json, code) => {
|
|
402
|
+
const transformBindings = (json, code, key, context) => {
|
|
116
403
|
return (0, babel_transform_1.babelTransformExpression)(code, {
|
|
117
404
|
BlockStatement() {
|
|
118
405
|
console.error(`
|
|
@@ -126,6 +413,13 @@ ${code}`);
|
|
|
126
413
|
if ((0, types_1.isIdentifier)(path.node.callee)) {
|
|
127
414
|
addToImportCall(json, path.node.callee.name);
|
|
128
415
|
}
|
|
416
|
+
if (path.node.arguments.length > 0) {
|
|
417
|
+
const newArgs = path.node.arguments.map((arg) => handleCallExpressionArgument(json, arg));
|
|
418
|
+
// Only replace arguments if we made any changes
|
|
419
|
+
if (newArgs.some((arg, i) => arg !== path.node.arguments[i])) {
|
|
420
|
+
path.node.arguments = newArgs;
|
|
421
|
+
}
|
|
422
|
+
}
|
|
129
423
|
},
|
|
130
424
|
Identifier(path) {
|
|
131
425
|
// If we use a constant from an import we need to add it to the Component as well
|
|
@@ -137,14 +431,28 @@ ${code}`);
|
|
|
137
431
|
var _a;
|
|
138
432
|
// We cannot use " for string literal in template
|
|
139
433
|
if ((_a = path.node.extra) === null || _a === void 0 ? void 0 : _a.raw) {
|
|
140
|
-
path.node.extra.raw = path.node.extra.raw.replaceAll('"',
|
|
434
|
+
path.node.extra.raw = path.node.extra.raw.replaceAll('"', '"');
|
|
141
435
|
}
|
|
142
436
|
},
|
|
143
437
|
AssignmentExpression(path) {
|
|
144
438
|
handleAssignmentExpression(path);
|
|
145
439
|
},
|
|
146
440
|
MemberExpression(path) {
|
|
147
|
-
handleMemberExpression(path);
|
|
441
|
+
handleMemberExpression(path, json);
|
|
442
|
+
},
|
|
443
|
+
TemplateLiteral(path) {
|
|
444
|
+
var _a, _b, _c;
|
|
445
|
+
// they are already created as trackBy functions
|
|
446
|
+
if (key === 'key') {
|
|
447
|
+
return;
|
|
448
|
+
}
|
|
449
|
+
// skip template literals in spread bindings
|
|
450
|
+
if (key && ((_c = (_b = (_a = context === null || context === void 0 ? void 0 : context.node) === null || _a === void 0 ? void 0 : _a.bindings) === null || _b === void 0 ? void 0 : _b[key]) === null || _c === void 0 ? void 0 : _c.code.includes('...'))) {
|
|
451
|
+
return;
|
|
452
|
+
}
|
|
453
|
+
// When we encounter a template literal, convert it to a function
|
|
454
|
+
const fnCall = handleTemplateLiteral(path, json, context);
|
|
455
|
+
path.replaceWith((0, types_1.identifier)(fnCall));
|
|
148
456
|
},
|
|
149
457
|
});
|
|
150
458
|
};
|
|
@@ -155,7 +463,49 @@ const getCodeProcessorPlugins = (json, options, processBindingOptions) => {
|
|
|
155
463
|
switch (codeType) {
|
|
156
464
|
case 'bindings':
|
|
157
465
|
return (code, key, context) => {
|
|
158
|
-
var _a, _b, _c;
|
|
466
|
+
var _a, _b, _c, _d, _e, _f;
|
|
467
|
+
// Handle object spread expressions or TypeScript type assertions
|
|
468
|
+
if ((code.startsWith('{') && code.includes('...')) || code.includes(' as ')) {
|
|
469
|
+
if (((_a = context === null || context === void 0 ? void 0 : context.node) === null || _a === void 0 ? void 0 : _a.bindings) && key) {
|
|
470
|
+
const binding = context.node.bindings[key];
|
|
471
|
+
let isForContext = false;
|
|
472
|
+
let forName = '';
|
|
473
|
+
let indexName = '';
|
|
474
|
+
let currentContext = context;
|
|
475
|
+
while (currentContext === null || currentContext === void 0 ? void 0 : currentContext.parent) {
|
|
476
|
+
if (((_b = currentContext.parent.node) === null || _b === void 0 ? void 0 : _b.name) === mitosis_node_1.ForNodeName) {
|
|
477
|
+
isForContext = true;
|
|
478
|
+
const forNode = currentContext.parent.node;
|
|
479
|
+
forName = forNode.scope.forName || '_';
|
|
480
|
+
indexName = forNode.scope.indexName || '_';
|
|
481
|
+
break;
|
|
482
|
+
}
|
|
483
|
+
currentContext = currentContext.parent;
|
|
484
|
+
}
|
|
485
|
+
const computedName = (0, get_computed_1.createObjectSpreadComputed)(json, binding, key, isForContext, forName, indexName);
|
|
486
|
+
if (isForContext) {
|
|
487
|
+
const params = [];
|
|
488
|
+
if (forName)
|
|
489
|
+
params.push(forName);
|
|
490
|
+
if (indexName)
|
|
491
|
+
params.push(indexName);
|
|
492
|
+
if (params.length > 0) {
|
|
493
|
+
return (0, class_components_1.processClassComponentBinding)(json, `${computedName}(${params.join(', ')})`, {
|
|
494
|
+
...processBindingOptions,
|
|
495
|
+
replaceWith: 'this.',
|
|
496
|
+
});
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
return (0, class_components_1.processClassComponentBinding)(json, `${computedName}()`, {
|
|
500
|
+
...processBindingOptions,
|
|
501
|
+
replaceWith: 'this.',
|
|
502
|
+
});
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
const needsToReplaceWithThis = (code.startsWith('{') && code.includes('...')) ||
|
|
506
|
+
code.includes(' as ') ||
|
|
507
|
+
(context === null || context === void 0 ? void 0 : context.node.name.includes('.')) ||
|
|
508
|
+
((_c = context === null || context === void 0 ? void 0 : context.node.bindings[key]) === null || _c === void 0 ? void 0 : _c.type) === 'spread';
|
|
159
509
|
let replaceWith = '';
|
|
160
510
|
if (key === 'key') {
|
|
161
511
|
/**
|
|
@@ -163,12 +513,15 @@ const getCodeProcessorPlugins = (json, options, processBindingOptions) => {
|
|
|
163
513
|
* We will create a new function for the key attribute.
|
|
164
514
|
* Therefore, we need to add "this" to state and props.
|
|
165
515
|
*/
|
|
166
|
-
const isForParent = ((
|
|
516
|
+
const isForParent = ((_f = (_e = (_d = context === null || context === void 0 ? void 0 : context.parent) === null || _d === void 0 ? void 0 : _d.parent) === null || _e === void 0 ? void 0 : _e.node) === null || _f === void 0 ? void 0 : _f.name) === mitosis_node_1.ForNodeName;
|
|
167
517
|
if (isForParent) {
|
|
168
518
|
replaceWith = 'this.';
|
|
169
519
|
}
|
|
170
520
|
}
|
|
171
|
-
|
|
521
|
+
if (needsToReplaceWithThis) {
|
|
522
|
+
replaceWith = 'this.';
|
|
523
|
+
}
|
|
524
|
+
return (0, class_components_1.processClassComponentBinding)(json, transformBindings(json, code, key, context), {
|
|
172
525
|
...processBindingOptions,
|
|
173
526
|
replaceWith,
|
|
174
527
|
});
|
|
@@ -177,7 +530,7 @@ const getCodeProcessorPlugins = (json, options, processBindingOptions) => {
|
|
|
177
530
|
case 'hooks':
|
|
178
531
|
case 'state':
|
|
179
532
|
return (code) => {
|
|
180
|
-
return (0, class_components_1.processClassComponentBinding)(json, transformHooksAndState(code, codeType === 'hooks-deps-array'), processBindingOptions);
|
|
533
|
+
return (0, class_components_1.processClassComponentBinding)(json, transformHooksAndState(code, codeType === 'hooks-deps-array', json), processBindingOptions);
|
|
181
534
|
};
|
|
182
535
|
case 'properties':
|
|
183
536
|
case 'hooks-deps':
|
|
@@ -10,6 +10,7 @@ export interface ToAngularOptions extends BaseTranspilerOptions {
|
|
|
10
10
|
importMapper?: Function;
|
|
11
11
|
bootstrapMapper?: Function;
|
|
12
12
|
visuallyIgnoreHostElement?: boolean;
|
|
13
|
+
defaultExportComponents?: boolean;
|
|
13
14
|
experimental?: {
|
|
14
15
|
injectables?: (variableName: string, variableType: string) => string;
|
|
15
16
|
inject?: boolean;
|
|
@@ -28,7 +29,6 @@ export type AngularMetadata = {
|
|
|
28
29
|
*/
|
|
29
30
|
nativeEvents?: string[];
|
|
30
31
|
/**
|
|
31
|
-
* @deprecated Rename component in *.lite.tsx
|
|
32
32
|
* Overwrite default selector for component. Default will be kebab case (MyComponent -> my-component)
|
|
33
33
|
*/
|
|
34
34
|
selector?: string;
|
|
@@ -47,6 +47,11 @@ export type AngularMetadata = {
|
|
|
47
47
|
* Can be used with `useTarget({angular: ()=> ...})` if needed.
|
|
48
48
|
*/
|
|
49
49
|
outputs?: string[];
|
|
50
|
+
/**
|
|
51
|
+
* Skip hydration for the component.
|
|
52
|
+
* Adds `host: { ngSkipHydration: "true" }` to the component decorator.
|
|
53
|
+
*/
|
|
54
|
+
skipHydration?: boolean;
|
|
50
55
|
/**
|
|
51
56
|
* Only for api=signals
|
|
52
57
|
*/
|
|
@@ -187,7 +187,14 @@ const blockToMitosis = (json, toMitosisOptions = {}, component, insideJsx) => {
|
|
|
187
187
|
for (const key in json.slots) {
|
|
188
188
|
const value = json.slots[key];
|
|
189
189
|
str += ` ${key}={`;
|
|
190
|
-
|
|
190
|
+
/**
|
|
191
|
+
* Pass the empty array as foo={[]} could be treated differently than not
|
|
192
|
+
* passing the prop at all.
|
|
193
|
+
*/
|
|
194
|
+
if (value.length === 0) {
|
|
195
|
+
str += '[]';
|
|
196
|
+
}
|
|
197
|
+
else if (value.length > 1) {
|
|
191
198
|
str += '<>';
|
|
192
199
|
}
|
|
193
200
|
str += json.slots[key]
|
|
@@ -358,7 +358,7 @@ const _componentToReact = (json, options, isSubComponent = false) => {
|
|
|
358
358
|
`;
|
|
359
359
|
const str = (0, dedent_1.dedent) `
|
|
360
360
|
${shouldAddUseClientDirective ? `'use client';` : ''}
|
|
361
|
-
${(0, state_2.getDefaultImport)(options)}
|
|
361
|
+
${(0, state_2.getDefaultImport)(options, json)}
|
|
362
362
|
${styledComponentsCode ? `import styled from 'styled-components';\n` : ''}
|
|
363
363
|
${reactLibImports.size
|
|
364
364
|
? `import { ${Array.from(reactLibImports).join(', ')} } from '${options.preact ? 'preact/hooks' : 'react'}'`
|
|
@@ -14,4 +14,4 @@ export declare const getReactVariantStateString: ({ hasState, options, json, use
|
|
|
14
14
|
json: MitosisComponent;
|
|
15
15
|
options: ToReactOptions;
|
|
16
16
|
}) => string;
|
|
17
|
-
export declare const getDefaultImport: (options: ToReactOptions) => string;
|
|
17
|
+
export declare const getDefaultImport: (options: ToReactOptions, json: MitosisComponent) => string;
|
|
@@ -10,11 +10,12 @@ const get_state_object_string_1 = require("../../../helpers/get-state-object-str
|
|
|
10
10
|
const get_typed_function_1 = require("../../../helpers/get-typed-function");
|
|
11
11
|
const is_mitosis_node_1 = require("../../../helpers/is-mitosis-node");
|
|
12
12
|
const patterns_1 = require("../../../helpers/patterns");
|
|
13
|
+
const helpers_1 = require("../../../helpers/styles/helpers");
|
|
13
14
|
const transform_state_setters_1 = require("../../../helpers/transform-state-setters");
|
|
14
15
|
const core_1 = require("@babel/core");
|
|
15
16
|
const function_1 = require("fp-ts/lib/function");
|
|
16
17
|
const legacy_1 = __importDefault(require("neotraverse/legacy"));
|
|
17
|
-
const
|
|
18
|
+
const helpers_2 = require("../helpers");
|
|
18
19
|
/**
|
|
19
20
|
* Removes all `this.` references.
|
|
20
21
|
*/
|
|
@@ -24,7 +25,7 @@ const stripThisRefs = (str, options) => {
|
|
|
24
25
|
}
|
|
25
26
|
return str.replace(/this\.([a-zA-Z_\$0-9]+)/g, '$1');
|
|
26
27
|
};
|
|
27
|
-
const processHookCode = ({ str, options }) => (0,
|
|
28
|
+
const processHookCode = ({ str, options }) => (0, helpers_2.processBinding)((0, exports.updateStateSettersInCode)(str, options), options);
|
|
28
29
|
exports.processHookCode = processHookCode;
|
|
29
30
|
const valueMapper = (options) => (val) => {
|
|
30
31
|
const x = (0, exports.processHookCode)({ str: val, options });
|
|
@@ -132,7 +133,7 @@ const getReactVariantStateString = ({ hasState, options, json, useStateCode, })
|
|
|
132
133
|
: `const state = useLocalProxy(${(0, get_state_object_string_1.getStateObjectStringFromComponent)(json)});`
|
|
133
134
|
: '';
|
|
134
135
|
exports.getReactVariantStateString = getReactVariantStateString;
|
|
135
|
-
const getDefaultImport = (options) => {
|
|
136
|
+
const getDefaultImport = (options, json) => {
|
|
136
137
|
const { preact, type } = options;
|
|
137
138
|
if (preact) {
|
|
138
139
|
return `
|
|
@@ -141,9 +142,51 @@ const getDefaultImport = (options) => {
|
|
|
141
142
|
`;
|
|
142
143
|
}
|
|
143
144
|
if (type === 'native') {
|
|
145
|
+
const namesUsed = new Set(), knownImports = new Set();
|
|
146
|
+
json.imports.forEach((imported) => {
|
|
147
|
+
if (imported.imports) {
|
|
148
|
+
Object.keys(imported.imports).forEach((name) => {
|
|
149
|
+
knownImports.add(name);
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
if ((0, helpers_1.hasCss)(json)) {
|
|
154
|
+
namesUsed.add('StyleSheet');
|
|
155
|
+
}
|
|
156
|
+
(0, legacy_1.default)(json).forEach((node) => {
|
|
157
|
+
var _a, _b, _c, _d;
|
|
158
|
+
if (!(0, is_mitosis_node_1.isMitosisNode)(node)) {
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
// ReactNative has a special case for converting _text to Text
|
|
162
|
+
if (((_a = node.properties._text) === null || _a === void 0 ? void 0 : _a.trim().length) || ((_d = (_c = (_b = node.bindings._text) === null || _b === void 0 ? void 0 : _b.code) === null || _c === void 0 ? void 0 : _c.trim()) === null || _d === void 0 ? void 0 : _d.length)) {
|
|
163
|
+
namesUsed.add('Text');
|
|
164
|
+
}
|
|
165
|
+
if (node.name === 'TouchableOpacity' &&
|
|
166
|
+
('href' in node.bindings || 'href' in node.properties)) {
|
|
167
|
+
namesUsed.add('Linking');
|
|
168
|
+
}
|
|
169
|
+
namesUsed.add(node.name);
|
|
170
|
+
});
|
|
171
|
+
const components = [
|
|
172
|
+
'FlatList',
|
|
173
|
+
'ScrollView',
|
|
174
|
+
'View',
|
|
175
|
+
'StyleSheet',
|
|
176
|
+
'Image',
|
|
177
|
+
'Text',
|
|
178
|
+
'Pressable',
|
|
179
|
+
'TextInput',
|
|
180
|
+
'TouchableOpacity',
|
|
181
|
+
'Button',
|
|
182
|
+
'Linking',
|
|
183
|
+
].filter((name) => {
|
|
184
|
+
// Ony import if the name is used and not imported from somewhere else
|
|
185
|
+
return namesUsed.has(name) && !knownImports.has(name);
|
|
186
|
+
});
|
|
144
187
|
return `
|
|
145
188
|
import * as React from 'react';
|
|
146
|
-
import {
|
|
189
|
+
import { ${components.join(', ')} } from 'react-native';
|
|
147
190
|
`;
|
|
148
191
|
}
|
|
149
192
|
if (type === 'taro') {
|