@builder.io/mitosis 0.9.5 → 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.
Files changed (34) hide show
  1. package/dist/src/generators/angular/helpers/index.d.ts +1 -1
  2. package/dist/src/generators/angular/helpers/index.js +6 -3
  3. package/dist/src/generators/angular/signals/blocks.js +141 -6
  4. package/dist/src/generators/angular/signals/component.js +109 -23
  5. package/dist/src/generators/angular/signals/helpers/get-computed.d.ts +6 -0
  6. package/dist/src/generators/angular/signals/helpers/get-computed.js +79 -0
  7. package/dist/src/generators/angular/signals/helpers/get-dynamic-template-refs.d.ts +2 -0
  8. package/dist/src/generators/angular/signals/helpers/get-dynamic-template-refs.js +25 -0
  9. package/dist/src/generators/angular/signals/helpers/get-inputs.js +1 -1
  10. package/dist/src/generators/angular/signals/helpers/index.d.ts +6 -1
  11. package/dist/src/generators/angular/signals/helpers/index.js +9 -4
  12. package/dist/src/generators/angular/signals/plugins/get-code-processor-plugins.js +364 -11
  13. package/dist/src/generators/angular/types.d.ts +6 -1
  14. package/dist/src/generators/angular/types.js +1 -0
  15. package/dist/src/generators/builder/generator.js +9 -0
  16. package/dist/src/generators/mitosis/generator.js +39 -1
  17. package/dist/src/generators/react/generator.js +1 -1
  18. package/dist/src/generators/react/helpers/state.d.ts +1 -1
  19. package/dist/src/generators/react/helpers/state.js +47 -4
  20. package/dist/src/helpers/event-handlers.js +1 -1
  21. package/dist/src/helpers/is-hook-empty.d.ts +2 -0
  22. package/dist/src/helpers/is-hook-empty.js +14 -0
  23. package/dist/src/parsers/builder/builder.d.ts +7 -0
  24. package/dist/src/parsers/builder/builder.js +38 -7
  25. package/dist/src/parsers/jsx/element-parser.d.ts +2 -1
  26. package/dist/src/parsers/jsx/element-parser.js +92 -14
  27. package/dist/src/parsers/jsx/function-parser.d.ts +2 -2
  28. package/dist/src/parsers/jsx/function-parser.js +2 -2
  29. package/dist/src/parsers/jsx/jsx.js +2 -2
  30. package/dist/src/parsers/jsx/types.d.ts +7 -0
  31. package/dist/src/parsers/svelte/html/text.d.ts +3 -0
  32. package/dist/src/types/config.d.ts +4 -3
  33. package/dist/src/types/mitosis-node.d.ts +8 -0
  34. 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
- AfterViewInit: true,
8
- viewChild: refs,
9
- ElementRef: refs,
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 transformHooksAndState = (code, isHookDepArray) => {
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 isImportCall = json.imports.find((imp) => imp.imports[importName]);
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('"', '&quot;');
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 = ((_c = (_b = (_a = context === null || context === void 0 ? void 0 : context.parent) === null || _a === void 0 ? void 0 : _a.parent) === null || _b === void 0 ? void 0 : _b.node) === null || _c === void 0 ? void 0 : _c.name) === mitosis_node_1.ForNodeName;
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
- return (0, class_components_1.processClassComponentBinding)(json, transformBindings(json, code), {
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
  */
@@ -8,4 +8,5 @@ exports.DEFAULT_ANGULAR_OPTIONS = {
8
8
  preserveImports: false,
9
9
  preserveFileExtensions: false,
10
10
  visuallyIgnoreHostElement: true,
11
+ defaultExportComponents: false,
11
12
  };
@@ -541,6 +541,15 @@ const blockToBuilder = (json, options = {}, _internalOptions = {}) => {
541
541
  for (const key in json.slots) {
542
542
  componentOptions[key] = json.slots[key].map((node) => (0, exports.blockToBuilder)(node, options));
543
543
  }
544
+ for (const key in json.blocksSlots) {
545
+ const value = json.blocksSlots[key];
546
+ (0, legacy_1.default)(value).forEach(function (v) {
547
+ if ((0, is_mitosis_node_1.isMitosisNode)(v)) {
548
+ this.update((0, exports.blockToBuilder)(v, options, _internalOptions));
549
+ }
550
+ });
551
+ componentOptions[key] = value;
552
+ }
544
553
  const hasCss = !!((_l = bindings.css) === null || _l === void 0 ? void 0 : _l.code);
545
554
  let responsiveStyles = {
546
555
  large: {},
@@ -20,6 +20,7 @@ const state_1 = require("../../helpers/state");
20
20
  const plugins_1 = require("../../modules/plugins");
21
21
  const mitosis_node_1 = require("../../types/mitosis-node");
22
22
  const json5_1 = __importDefault(require("json5"));
23
+ const legacy_1 = __importDefault(require("neotraverse/legacy"));
23
24
  const standalone_1 = require("prettier/standalone");
24
25
  const react_1 = require("../react");
25
26
  exports.DEFAULT_FORMAT = 'legacy';
@@ -186,7 +187,14 @@ const blockToMitosis = (json, toMitosisOptions = {}, component, insideJsx) => {
186
187
  for (const key in json.slots) {
187
188
  const value = json.slots[key];
188
189
  str += ` ${key}={`;
189
- if (value.length > 1) {
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) {
190
198
  str += '<>';
191
199
  }
192
200
  str += json.slots[key]
@@ -197,6 +205,15 @@ const blockToMitosis = (json, toMitosisOptions = {}, component, insideJsx) => {
197
205
  }
198
206
  str += `}`;
199
207
  }
208
+ for (const key in json.blocksSlots) {
209
+ const value = json.blocksSlots[key];
210
+ (0, legacy_1.default)(value).forEach(function (v) {
211
+ if ((0, is_mitosis_node_1.isMitosisNode)(v)) {
212
+ this.update((0, exports.blockToMitosis)(v, toMitosisOptions, component, insideJsx));
213
+ }
214
+ });
215
+ str += `${key}={${generateBlockSlotsCode(value)}}`;
216
+ }
200
217
  if (html_tags_1.SELF_CLOSING_HTML_TAGS.has(json.name)) {
201
218
  return str + ' />';
202
219
  }
@@ -213,6 +230,27 @@ const blockToMitosis = (json, toMitosisOptions = {}, component, insideJsx) => {
213
230
  return str;
214
231
  };
215
232
  exports.blockToMitosis = blockToMitosis;
233
+ const generateBlockSlotsCode = (blockSlot) => {
234
+ let code = '';
235
+ // generate array props (foo=[...])
236
+ if (Array.isArray(blockSlot)) {
237
+ code += `[${blockSlot.map(generateBlockSlotsCode).join(',')}]`;
238
+ // generate object props (foo={{ ... }})
239
+ }
240
+ else if (typeof blockSlot === 'object' && blockSlot !== null) {
241
+ code += '{';
242
+ for (const key in blockSlot) {
243
+ if (blockSlot.hasOwnProperty(key)) {
244
+ code += `${key}: ${generateBlockSlotsCode(blockSlot[key])},`;
245
+ }
246
+ }
247
+ code += '}';
248
+ }
249
+ else {
250
+ code += blockSlot;
251
+ }
252
+ return code;
253
+ };
216
254
  const getRefsString = (json, refs = Array.from((0, get_refs_1.getRefs)(json))) => {
217
255
  var _a, _b;
218
256
  let str = '';
@@ -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;