@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.
@@ -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
  };
@@ -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
- 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) {
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 helpers_1 = require("../helpers");
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, helpers_1.processBinding)((0, exports.updateStateSettersInCode)(str, options), options);
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 { FlatList, ScrollView, View, StyleSheet, Image, Text, Pressable, TextInput, TouchableOpacity, Button, Linking } from 'react-native';
189
+ import { ${components.join(', ')} } from 'react-native';
147
190
  `;
148
191
  }
149
192
  if (type === 'taro') {