@builder.io/mitosis 0.9.3 → 0.9.5
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/swift/blocks.d.ts +8 -0
- package/dist/src/generators/swift/blocks.js +304 -0
- package/dist/src/generators/swift/generator.d.ts +1 -1
- package/dist/src/generators/swift/generator.js +256 -303
- package/dist/src/generators/swift/helpers.d.ts +42 -0
- package/dist/src/generators/swift/helpers.js +412 -0
- package/dist/src/generators/swift/types.d.ts +25 -0
- package/package.json +1 -1
|
@@ -0,0 +1,412 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.convertJsFunctionToSwift = exports.extractFunctionSignature = exports.getBindingType = exports.camelToSnakeCase = exports.getForEachParams = exports.isForEachBlock = exports.needsScrollView = exports.getEventHandlerName = exports.getStatePropertyTypeAnnotation = exports.cssToSwiftUIModifiers = exports.jsxElementToSwiftUIView = exports.getSwiftType = exports.stripStateAndProps = exports.ensureSwiftStringFormat = exports.convertConsoleLogToPrint = void 0;
|
|
4
|
+
const capitalize_1 = require("../../helpers/capitalize");
|
|
5
|
+
const strip_state_and_props_refs_1 = require("../../helpers/strip-state-and-props-refs");
|
|
6
|
+
// TODO(kyle): use babel here to do ast
|
|
7
|
+
const convertConsoleLogToPrint = (code) => {
|
|
8
|
+
if (!code)
|
|
9
|
+
return code;
|
|
10
|
+
// Match console.log statements with various argument patterns
|
|
11
|
+
return code.replace(/console\.log\s*\(\s*(.*?)\s*\)/g, (match, args) => {
|
|
12
|
+
// Handle empty console.log()
|
|
13
|
+
if (!args.trim()) {
|
|
14
|
+
return 'print()';
|
|
15
|
+
}
|
|
16
|
+
// Simple handling for basic console.log calls
|
|
17
|
+
// For complex cases, we'd need a more sophisticated parser
|
|
18
|
+
return `print(${(0, exports.ensureSwiftStringFormat)(args)})`;
|
|
19
|
+
});
|
|
20
|
+
};
|
|
21
|
+
exports.convertConsoleLogToPrint = convertConsoleLogToPrint;
|
|
22
|
+
// Helper function to ensure Swift strings use double quotes
|
|
23
|
+
const ensureSwiftStringFormat = (code) => {
|
|
24
|
+
if (!code)
|
|
25
|
+
return code;
|
|
26
|
+
// We need a more reliable approach to handle nested quotes
|
|
27
|
+
// This uses a state machine approach to track whether we're inside double quotes
|
|
28
|
+
let result = '';
|
|
29
|
+
let insideDoubleQuotes = false;
|
|
30
|
+
for (let i = 0; i < code.length; i++) {
|
|
31
|
+
const char = code[i];
|
|
32
|
+
const prevChar = i > 0 ? code[i - 1] : '';
|
|
33
|
+
// Handle quote state tracking
|
|
34
|
+
if (char === '"' && prevChar !== '\\') {
|
|
35
|
+
insideDoubleQuotes = !insideDoubleQuotes;
|
|
36
|
+
result += char;
|
|
37
|
+
}
|
|
38
|
+
// Only replace single quotes when not inside double quotes
|
|
39
|
+
else if (char === "'" && prevChar !== '\\' && !insideDoubleQuotes) {
|
|
40
|
+
// Start of a single-quoted string
|
|
41
|
+
result += '"';
|
|
42
|
+
// Find the end of the single-quoted string, accounting for escaped quotes
|
|
43
|
+
let j = i + 1;
|
|
44
|
+
while (j < code.length) {
|
|
45
|
+
if (code[j] === "'" && code[j - 1] !== '\\') {
|
|
46
|
+
break;
|
|
47
|
+
}
|
|
48
|
+
j++;
|
|
49
|
+
}
|
|
50
|
+
// Add the string content
|
|
51
|
+
result += code.substring(i + 1, j);
|
|
52
|
+
// Add closing double quote if we found the end
|
|
53
|
+
if (j < code.length) {
|
|
54
|
+
result += '"';
|
|
55
|
+
i = j; // Skip to the end of the single-quoted string
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
// If no closing quote was found, just add the single quote as is
|
|
59
|
+
result = result.substring(0, result.length - 1) + "'";
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
result += char;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return result;
|
|
67
|
+
};
|
|
68
|
+
exports.ensureSwiftStringFormat = ensureSwiftStringFormat;
|
|
69
|
+
const stripStateAndProps = ({ json, options, }) => {
|
|
70
|
+
return (code) => {
|
|
71
|
+
// Convert console.log statements to Swift print
|
|
72
|
+
code = (0, exports.convertConsoleLogToPrint)(code);
|
|
73
|
+
// Ensure Swift strings use double quotes
|
|
74
|
+
code = (0, exports.ensureSwiftStringFormat)(code);
|
|
75
|
+
// In Swift, we use self.propertyName for accessing properties
|
|
76
|
+
return (0, strip_state_and_props_refs_1.stripStateAndPropsRefs)(code, {
|
|
77
|
+
includeState: true,
|
|
78
|
+
includeProps: true,
|
|
79
|
+
replaceWith: (name) => {
|
|
80
|
+
// In Swift, we access properties with self.propertyName
|
|
81
|
+
return `self.${name}`;
|
|
82
|
+
},
|
|
83
|
+
});
|
|
84
|
+
};
|
|
85
|
+
};
|
|
86
|
+
exports.stripStateAndProps = stripStateAndProps;
|
|
87
|
+
const getSwiftType = (type) => {
|
|
88
|
+
if (!type)
|
|
89
|
+
return 'Any';
|
|
90
|
+
// Handle array types with proper Swift syntax
|
|
91
|
+
if (type.includes('Array<') || type.includes('[]') || type.toLowerCase().startsWith('array')) {
|
|
92
|
+
// Extract the element type from Array<ElementType>
|
|
93
|
+
let elementType = 'Any';
|
|
94
|
+
// Match different array type patterns
|
|
95
|
+
const arrayMatch = type.match(/Array<([^>]+)>/i) ||
|
|
96
|
+
type.match(/([^[\]]+)\[\]/i) ||
|
|
97
|
+
type.match(/array\s*<([^>]+)>/i);
|
|
98
|
+
if (arrayMatch && arrayMatch[1]) {
|
|
99
|
+
elementType = (0, exports.getSwiftType)(arrayMatch[1].trim());
|
|
100
|
+
}
|
|
101
|
+
// Return Swift array type: [ElementType]
|
|
102
|
+
return `[${elementType}]`;
|
|
103
|
+
}
|
|
104
|
+
// Handle primitive types
|
|
105
|
+
switch (type.toLowerCase()) {
|
|
106
|
+
case 'string':
|
|
107
|
+
return 'String';
|
|
108
|
+
case 'number':
|
|
109
|
+
return 'Double';
|
|
110
|
+
case 'boolean':
|
|
111
|
+
case 'bool':
|
|
112
|
+
return 'Bool';
|
|
113
|
+
case 'any':
|
|
114
|
+
return 'Any';
|
|
115
|
+
case 'void':
|
|
116
|
+
return 'Void';
|
|
117
|
+
case 'object':
|
|
118
|
+
return '[String: Any]';
|
|
119
|
+
case 'null':
|
|
120
|
+
case 'undefined':
|
|
121
|
+
return 'Optional<Any>';
|
|
122
|
+
default:
|
|
123
|
+
// For complex types, return as is with first letter capitalized
|
|
124
|
+
return type.charAt(0).toUpperCase() + type.slice(1);
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
exports.getSwiftType = getSwiftType;
|
|
128
|
+
const jsxElementToSwiftUIView = (tagName) => {
|
|
129
|
+
// Map JSX/HTML elements to SwiftUI components
|
|
130
|
+
switch (tagName.toLowerCase()) {
|
|
131
|
+
case 'div':
|
|
132
|
+
return 'VStack';
|
|
133
|
+
case 'span':
|
|
134
|
+
case 'p':
|
|
135
|
+
case 'h1':
|
|
136
|
+
case 'h2':
|
|
137
|
+
case 'h3':
|
|
138
|
+
case 'h4':
|
|
139
|
+
case 'h5':
|
|
140
|
+
case 'h6':
|
|
141
|
+
return 'Text';
|
|
142
|
+
case 'img':
|
|
143
|
+
return 'Image';
|
|
144
|
+
case 'input':
|
|
145
|
+
return 'TextField';
|
|
146
|
+
case 'button':
|
|
147
|
+
return 'Button';
|
|
148
|
+
case 'a':
|
|
149
|
+
return 'Link';
|
|
150
|
+
case 'ul':
|
|
151
|
+
return 'List';
|
|
152
|
+
case 'li':
|
|
153
|
+
return 'Text'; // Will be wrapped in List
|
|
154
|
+
case 'form':
|
|
155
|
+
return 'Form';
|
|
156
|
+
case 'select':
|
|
157
|
+
return 'Picker';
|
|
158
|
+
case 'option':
|
|
159
|
+
return 'Text'; // Options in SwiftUI are part of the Picker content
|
|
160
|
+
default:
|
|
161
|
+
// For custom components or unrecognized tags
|
|
162
|
+
return (0, capitalize_1.capitalize)(tagName);
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
exports.jsxElementToSwiftUIView = jsxElementToSwiftUIView;
|
|
166
|
+
const cssToSwiftUIModifiers = (style) => {
|
|
167
|
+
const modifiers = [];
|
|
168
|
+
// Map CSS properties to SwiftUI modifiers
|
|
169
|
+
Object.entries(style).forEach(([key, value]) => {
|
|
170
|
+
switch (key) {
|
|
171
|
+
case 'backgroundColor':
|
|
172
|
+
modifiers.push(`.background(Color("${value}"))`);
|
|
173
|
+
break;
|
|
174
|
+
case 'color':
|
|
175
|
+
modifiers.push(`.foregroundColor(Color("${value}"))`);
|
|
176
|
+
break;
|
|
177
|
+
case 'fontSize':
|
|
178
|
+
const fontSize = parseInt(value);
|
|
179
|
+
if (!isNaN(fontSize)) {
|
|
180
|
+
modifiers.push(`.font(.system(size: ${fontSize}))`);
|
|
181
|
+
}
|
|
182
|
+
break;
|
|
183
|
+
case 'fontWeight':
|
|
184
|
+
modifiers.push(`.fontWeight(.${value})`);
|
|
185
|
+
break;
|
|
186
|
+
case 'padding':
|
|
187
|
+
modifiers.push(`.padding(${value})`);
|
|
188
|
+
break;
|
|
189
|
+
case 'margin':
|
|
190
|
+
// Swift doesn't have direct margin equivalent, we'll use padding
|
|
191
|
+
modifiers.push(`// Note: 'margin' converted to padding: ${value}`);
|
|
192
|
+
modifiers.push(`.padding(${value})`);
|
|
193
|
+
break;
|
|
194
|
+
case 'width':
|
|
195
|
+
modifiers.push(`.frame(width: ${value})`);
|
|
196
|
+
break;
|
|
197
|
+
case 'height':
|
|
198
|
+
modifiers.push(`.frame(height: ${value})`);
|
|
199
|
+
break;
|
|
200
|
+
// Add more CSS to SwiftUI modifier mappings as needed
|
|
201
|
+
default:
|
|
202
|
+
modifiers.push(`// Unmapped style: ${key}: ${value}`);
|
|
203
|
+
}
|
|
204
|
+
});
|
|
205
|
+
return modifiers;
|
|
206
|
+
};
|
|
207
|
+
exports.cssToSwiftUIModifiers = cssToSwiftUIModifiers;
|
|
208
|
+
const getStatePropertyTypeAnnotation = (propertyType, type) => {
|
|
209
|
+
// Use appropriate SwiftUI property wrappers
|
|
210
|
+
switch (propertyType) {
|
|
211
|
+
case 'reactive':
|
|
212
|
+
// For reactive state, use @State for simple values
|
|
213
|
+
// @Observable would be used for classes but requires Swift 5.9+/iOS 17+
|
|
214
|
+
return `@State private var`;
|
|
215
|
+
case 'normal':
|
|
216
|
+
// For normal state, use @State for simple values
|
|
217
|
+
return `@State private var`;
|
|
218
|
+
default:
|
|
219
|
+
// For non-reactive values, use a regular property
|
|
220
|
+
return `var`;
|
|
221
|
+
}
|
|
222
|
+
};
|
|
223
|
+
exports.getStatePropertyTypeAnnotation = getStatePropertyTypeAnnotation;
|
|
224
|
+
const getEventHandlerName = (eventName) => {
|
|
225
|
+
switch (eventName) {
|
|
226
|
+
case 'onClick':
|
|
227
|
+
return 'onTapGesture';
|
|
228
|
+
case 'onChange':
|
|
229
|
+
return 'onChange';
|
|
230
|
+
case 'onInput':
|
|
231
|
+
return 'onEditingChanged';
|
|
232
|
+
case 'onBlur':
|
|
233
|
+
return 'onSubmit';
|
|
234
|
+
case 'onFocus':
|
|
235
|
+
return 'onEditingChanged';
|
|
236
|
+
default:
|
|
237
|
+
return eventName;
|
|
238
|
+
}
|
|
239
|
+
};
|
|
240
|
+
exports.getEventHandlerName = getEventHandlerName;
|
|
241
|
+
const needsScrollView = (json) => {
|
|
242
|
+
// Check if overflow property indicates scrolling
|
|
243
|
+
if (json.properties.style) {
|
|
244
|
+
try {
|
|
245
|
+
const styleObj = JSON.parse(json.properties.style);
|
|
246
|
+
return (styleObj.overflow === 'auto' ||
|
|
247
|
+
styleObj.overflow === 'scroll' ||
|
|
248
|
+
styleObj.overflowY === 'auto' ||
|
|
249
|
+
styleObj.overflowY === 'scroll' ||
|
|
250
|
+
styleObj.overflowX === 'auto' ||
|
|
251
|
+
styleObj.overflowX === 'scroll');
|
|
252
|
+
}
|
|
253
|
+
catch (e) {
|
|
254
|
+
// If style can't be parsed, check for overflow directly in the style string
|
|
255
|
+
const styleStr = json.properties.style;
|
|
256
|
+
return (styleStr.includes('overflow:auto') ||
|
|
257
|
+
styleStr.includes('overflow:scroll') ||
|
|
258
|
+
styleStr.includes('overflow-y:auto') ||
|
|
259
|
+
styleStr.includes('overflow-y:scroll') ||
|
|
260
|
+
styleStr.includes('overflow-x:auto') ||
|
|
261
|
+
styleStr.includes('overflow-x:scroll'));
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
return false;
|
|
265
|
+
};
|
|
266
|
+
exports.needsScrollView = needsScrollView;
|
|
267
|
+
const isForEachBlock = (json) => {
|
|
268
|
+
var _a;
|
|
269
|
+
// Check if this is a ForEach binding using the bindings.each pattern
|
|
270
|
+
return !!((_a = json.bindings.each) === null || _a === void 0 ? void 0 : _a.code);
|
|
271
|
+
};
|
|
272
|
+
exports.isForEachBlock = isForEachBlock;
|
|
273
|
+
const getForEachParams = (json, processCode) => {
|
|
274
|
+
var _a, _b;
|
|
275
|
+
if (!((_a = json.bindings.each) === null || _a === void 0 ? void 0 : _a.code)) {
|
|
276
|
+
return { collection: '', itemName: 'item', indexName: null };
|
|
277
|
+
}
|
|
278
|
+
const eachCode = json.bindings.each.code;
|
|
279
|
+
let itemName = 'item';
|
|
280
|
+
let indexName = null;
|
|
281
|
+
// Extract collection, item name, and index name from each binding
|
|
282
|
+
try {
|
|
283
|
+
// Parse expressions like: items.map(item => ...)
|
|
284
|
+
// or items.map((item, index) => ...)
|
|
285
|
+
const match = eachCode.match(/(\w+)\.map\(\s*(?:\()?([^,)]+)(?:,\s*([^)]+))?\)?/);
|
|
286
|
+
if (match) {
|
|
287
|
+
const collection = processCode(match[1]);
|
|
288
|
+
itemName = match[2].trim();
|
|
289
|
+
indexName = ((_b = match[3]) === null || _b === void 0 ? void 0 : _b.trim()) || null;
|
|
290
|
+
return { collection, itemName, indexName };
|
|
291
|
+
}
|
|
292
|
+
// Fallback to the whole code as collection if pattern doesn't match
|
|
293
|
+
return {
|
|
294
|
+
collection: processCode(eachCode),
|
|
295
|
+
itemName,
|
|
296
|
+
indexName,
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
catch (e) {
|
|
300
|
+
console.warn('Failed to parse each binding:', eachCode);
|
|
301
|
+
return {
|
|
302
|
+
collection: processCode(eachCode),
|
|
303
|
+
itemName,
|
|
304
|
+
indexName,
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
};
|
|
308
|
+
exports.getForEachParams = getForEachParams;
|
|
309
|
+
const camelToSnakeCase = (str) => {
|
|
310
|
+
return str.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);
|
|
311
|
+
};
|
|
312
|
+
exports.camelToSnakeCase = camelToSnakeCase;
|
|
313
|
+
const getBindingType = (key) => {
|
|
314
|
+
if (key.startsWith('bind:')) {
|
|
315
|
+
return key.substring(5);
|
|
316
|
+
}
|
|
317
|
+
return key;
|
|
318
|
+
};
|
|
319
|
+
exports.getBindingType = getBindingType;
|
|
320
|
+
/**
|
|
321
|
+
* Extract function signature information from JavaScript function code
|
|
322
|
+
*/
|
|
323
|
+
const extractFunctionSignature = (code) => {
|
|
324
|
+
// Default values
|
|
325
|
+
let name = '';
|
|
326
|
+
let params = [];
|
|
327
|
+
let returnType = 'Void';
|
|
328
|
+
let body = '';
|
|
329
|
+
// Extract function name, parameters, and body
|
|
330
|
+
const funcMatch = code.match(/(?:function\s+)?([a-zA-Z_$][a-zA-Z0-9_$]*)?\s*\(([^)]*)\)\s*(?:=>)?\s*(?:{([\s\S]*)}|(.*))/);
|
|
331
|
+
if (funcMatch) {
|
|
332
|
+
name = funcMatch[1] || '';
|
|
333
|
+
// Extract parameters
|
|
334
|
+
const paramsStr = funcMatch[2].trim();
|
|
335
|
+
if (paramsStr) {
|
|
336
|
+
params = paramsStr.split(',').map((param) => {
|
|
337
|
+
// Handle TypeScript-style parameter types if present
|
|
338
|
+
const paramParts = param.trim().split(':');
|
|
339
|
+
const paramName = paramParts[0].trim();
|
|
340
|
+
const paramType = paramParts.length > 1 ? (0, exports.getSwiftType)(paramParts[1].trim()) : 'Any';
|
|
341
|
+
return { name: paramName, type: paramType };
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
// Extract function body
|
|
345
|
+
body = funcMatch[3] || funcMatch[4] || '';
|
|
346
|
+
// Try to determine return type from TypeScript annotations or infer from return statements
|
|
347
|
+
const returnTypeMatch = code.match(/\)\s*:\s*([^{]+)/);
|
|
348
|
+
if (returnTypeMatch) {
|
|
349
|
+
returnType = (0, exports.getSwiftType)(returnTypeMatch[1].trim());
|
|
350
|
+
}
|
|
351
|
+
else if (body.includes('return')) {
|
|
352
|
+
// Try to infer from return statements
|
|
353
|
+
const returnValueMatch = body.match(/return\s+(["'].*["']|true|false|\d+|\d+\.\d+|\[.*\])/);
|
|
354
|
+
if (returnValueMatch) {
|
|
355
|
+
const returnValue = returnValueMatch[1];
|
|
356
|
+
if (returnValue.startsWith('"') || returnValue.startsWith("'")) {
|
|
357
|
+
returnType = 'String';
|
|
358
|
+
}
|
|
359
|
+
else if (returnValue === 'true' || returnValue === 'false') {
|
|
360
|
+
returnType = 'Bool';
|
|
361
|
+
}
|
|
362
|
+
else if (returnValue.match(/^\d+$/)) {
|
|
363
|
+
returnType = 'Int';
|
|
364
|
+
}
|
|
365
|
+
else if (returnValue.match(/^\d+\.\d+$/)) {
|
|
366
|
+
returnType = 'Double';
|
|
367
|
+
}
|
|
368
|
+
else if (returnValue.startsWith('[')) {
|
|
369
|
+
returnType = '[Any]';
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
return { name, params, returnType, body };
|
|
375
|
+
};
|
|
376
|
+
exports.extractFunctionSignature = extractFunctionSignature;
|
|
377
|
+
/**
|
|
378
|
+
* Convert JavaScript function code to Swift function syntax
|
|
379
|
+
*/
|
|
380
|
+
const convertJsFunctionToSwift = (code, functionName) => {
|
|
381
|
+
// Extract the function signature
|
|
382
|
+
const { name, params, returnType, body } = (0, exports.extractFunctionSignature)(code);
|
|
383
|
+
// Use provided name or extracted name
|
|
384
|
+
const finalName = functionName || name || 'function';
|
|
385
|
+
// Convert function body to Swift
|
|
386
|
+
let swiftBody = body
|
|
387
|
+
// Convert variable declarations
|
|
388
|
+
.replace(/\bvar\s+(\w+)/g, 'var $1')
|
|
389
|
+
.replace(/\blet\s+(\w+)/g, 'let $1')
|
|
390
|
+
.replace(/\bconst\s+(\w+)/g, 'let $1')
|
|
391
|
+
// Convert common array methods
|
|
392
|
+
.replace(/\.push\(/g, '.append(')
|
|
393
|
+
.replace(/\.map\(/g, '.map(')
|
|
394
|
+
.replace(/\.filter\(/g, '.filter(')
|
|
395
|
+
.replace(/\.includes\(/g, '.contains(')
|
|
396
|
+
.replace(/\.indexOf\(/g, '.firstIndex(of: ')
|
|
397
|
+
// Convert null/undefined checks
|
|
398
|
+
.replace(/=== null/g, '== nil')
|
|
399
|
+
.replace(/!== null/g, '!= nil')
|
|
400
|
+
.replace(/=== undefined/g, '== nil')
|
|
401
|
+
.replace(/!== undefined/g, '!= nil')
|
|
402
|
+
// Convert console.log
|
|
403
|
+
.replace(/console\.log\((.+?)\)/g, 'print($1)');
|
|
404
|
+
// Create parameter list with Swift types
|
|
405
|
+
const paramList = params.map((p) => `${p.name}: ${p.type}`).join(', ');
|
|
406
|
+
// Build the Swift function signature
|
|
407
|
+
const signature = `func ${finalName}(${paramList}) -> ${returnType}`;
|
|
408
|
+
// Build the complete Swift function
|
|
409
|
+
const swiftCode = `${signature} {\n ${swiftBody}\n}`;
|
|
410
|
+
return { swiftCode, signature };
|
|
411
|
+
};
|
|
412
|
+
exports.convertJsFunctionToSwift = convertJsFunctionToSwift;
|
|
@@ -1,4 +1,29 @@
|
|
|
1
1
|
import { BaseTranspilerOptions } from '../../types/transpiler';
|
|
2
2
|
export interface ToSwiftOptions extends BaseTranspilerOptions {
|
|
3
|
+
/**
|
|
4
|
+
* Format generated Swift code
|
|
5
|
+
* @default true
|
|
6
|
+
*/
|
|
7
|
+
formatCode?: boolean;
|
|
8
|
+
/**
|
|
9
|
+
* Include type annotations in Swift code
|
|
10
|
+
* @default true
|
|
11
|
+
*/
|
|
12
|
+
includeTypes?: boolean;
|
|
13
|
+
/**
|
|
14
|
+
* Type of state management to use
|
|
15
|
+
* @default 'state'
|
|
16
|
+
*/
|
|
17
|
+
stateType?: 'state' | 'stateObject' | 'observable';
|
|
18
|
+
/**
|
|
19
|
+
* Prefix for class names
|
|
20
|
+
* @default ''
|
|
21
|
+
*/
|
|
22
|
+
classPrefix?: string;
|
|
23
|
+
/**
|
|
24
|
+
* Whether to include SwiftUI preview code
|
|
25
|
+
* @default true
|
|
26
|
+
*/
|
|
27
|
+
includePreview?: boolean;
|
|
3
28
|
}
|
|
4
29
|
export type SwiftMetadata = {};
|