@builder.io/mitosis 0.5.12 → 0.5.14

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.
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.componentToAngular = exports.blockToAngular = void 0;
7
7
  const html_tags_1 = require("../../constants/html_tags");
8
+ const bindings_1 = require("../../helpers/bindings");
8
9
  const dedent_1 = require("../../helpers/dedent");
9
10
  const fast_clone_1 = require("../../helpers/fast-clone");
10
11
  const get_child_components_1 = require("../../helpers/get-child-components");
@@ -364,10 +365,10 @@ const blockToAngular = ({ root, json, options = {}, blockOptions = {
364
365
  const spreadRefIndex = root.meta._spreadRefIndex || 0;
365
366
  refName = `elRef${spreadRefIndex}`;
366
367
  root.meta._spreadRefIndex = spreadRefIndex + 1;
367
- json.bindings['spreadRef'] = { code: refName, type: 'single' };
368
+ json.bindings['spreadRef'] = (0, bindings_1.createSingleBinding)({ code: refName });
368
369
  root.refs[refName] = { argument: '' };
369
370
  }
370
- json.bindings['spreadRef'] = { code: refName, type: 'single' };
371
+ json.bindings['spreadRef'] = (0, bindings_1.createSingleBinding)({ code: refName });
371
372
  root.refs[refName] = { argument: '' };
372
373
  root.meta.onViewInit = (root.meta.onViewInit || { code: '' });
373
374
  let spreadCode = '';
@@ -530,7 +531,7 @@ const handleProperties = (json, item, index) => {
530
531
  }
531
532
  const newBindingName = generateNewBindingName(index, item.name);
532
533
  json.state[newBindingName] = { code: '`' + `${item.properties[key]}` + '`', type: 'property' };
533
- item.bindings[key] = { code: `state.${newBindingName}`, type: 'single' };
534
+ item.bindings[key] = (0, bindings_1.createSingleBinding)({ code: `state.${newBindingName}` });
534
535
  delete item.properties[key];
535
536
  index++;
536
537
  }
@@ -13,12 +13,14 @@ const has_props_1 = require("../../helpers/has-props");
13
13
  const is_component_1 = require("../../helpers/is-component");
14
14
  const is_mitosis_node_1 = require("../../helpers/is-mitosis-node");
15
15
  const is_upper_case_1 = require("../../helpers/is-upper-case");
16
+ const parsers_1 = require("../../helpers/parsers");
16
17
  const remove_surrounding_block_1 = require("../../helpers/remove-surrounding-block");
17
18
  const replace_identifiers_1 = require("../../helpers/replace-identifiers");
18
19
  const state_1 = require("../../helpers/state");
19
20
  const builder_1 = require("../../parsers/builder");
20
21
  const symbol_processor_1 = require("../../symbols/symbol-processor");
21
22
  const core_1 = require("@babel/core");
23
+ const generator_1 = __importDefault(require("@babel/generator"));
22
24
  const json5_1 = __importDefault(require("json5"));
23
25
  const lodash_1 = require("lodash");
24
26
  const legacy_1 = __importDefault(require("neotraverse/legacy"));
@@ -74,7 +76,6 @@ const componentMappers = {
74
76
  },
75
77
  PersonalizationContainer(node, options) {
76
78
  const block = (0, exports.blockToBuilder)(node, options, { skipMapper: true });
77
- // console.log('block', node);
78
79
  const variants = [];
79
80
  let defaultVariant = [];
80
81
  const validFakeNodeNames = [
@@ -127,24 +128,78 @@ const componentMappers = {
127
128
  For(_node, options) {
128
129
  var _a;
129
130
  const node = _node;
131
+ const replaceIndexNode = (str) => (0, replace_identifiers_1.replaceNodes)({
132
+ code: str,
133
+ nodeMaps: [
134
+ {
135
+ from: core_1.types.identifier(target),
136
+ to: core_1.types.memberExpression(core_1.types.identifier('state'), core_1.types.identifier('$index')),
137
+ },
138
+ ],
139
+ });
130
140
  // rename `index` var to `state.$index`
131
141
  const target = node.scope.indexName || 'index';
132
142
  const replaceIndex = (node) => {
133
143
  (0, legacy_1.default)(node).forEach(function (thing) {
134
- if ((0, is_mitosis_node_1.isMitosisNode)(thing)) {
135
- for (const [key, value] of Object.entries(thing.bindings)) {
136
- if (value === null || value === void 0 ? void 0 : value.code.includes(target)) {
137
- thing.bindings[key].code = (0, replace_identifiers_1.replaceNodes)({
138
- code: value.code,
139
- nodeMaps: [
140
- {
141
- from: core_1.types.identifier(target),
142
- to: core_1.types.memberExpression(core_1.types.identifier('state'), core_1.types.identifier('$index')),
144
+ if (!(0, is_mitosis_node_1.isMitosisNode)(thing))
145
+ return;
146
+ for (const [key, value] of Object.entries(thing.bindings)) {
147
+ if (!value)
148
+ continue;
149
+ if (!value.code.includes(target))
150
+ continue;
151
+ if (value.type === 'single' && value.bindingType === 'function') {
152
+ try {
153
+ const code = value.code;
154
+ const processedLines = [];
155
+ let stopProcessing = false;
156
+ const newLocal = (0, parsers_1.parseCode)(code);
157
+ const lines = newLocal.length === 1 && newLocal[0].type === 'BlockStatement'
158
+ ? newLocal[0].body
159
+ : newLocal;
160
+ const appendSemicolonIfNeeded = (code) => code.endsWith(';') ? code : code + ';';
161
+ for (const line of lines) {
162
+ const generatedLine = appendSemicolonIfNeeded((0, generator_1.default)(line).code);
163
+ if (stopProcessing) {
164
+ processedLines.push(generatedLine);
165
+ continue;
166
+ }
167
+ /**
168
+ * Check if this statement re-declares our `target` variable, i.e.
169
+ * if there is a variable in this function shadowing the `target` variable.
170
+ */
171
+ let hasTargetDeclaration = false;
172
+ core_1.types.traverse(line, {
173
+ enter(path) {
174
+ if (hasTargetDeclaration) {
175
+ return;
176
+ }
177
+ if (core_1.types.isVariableDeclarator(path) &&
178
+ core_1.types.isIdentifier(path.id) &&
179
+ path.id.name === target) {
180
+ hasTargetDeclaration = true;
181
+ }
143
182
  },
144
- ],
145
- });
183
+ });
184
+ if (hasTargetDeclaration) {
185
+ stopProcessing = true;
186
+ processedLines.push(generatedLine);
187
+ }
188
+ else {
189
+ // Replace identifiers in this statement
190
+ processedLines.push(appendSemicolonIfNeeded(replaceIndexNode(generatedLine)));
191
+ }
192
+ }
193
+ thing.bindings[key].code = '{' + processedLines.join('\n') + '}';
194
+ }
195
+ catch (error) {
196
+ console.error('Error processing function binding. Falling back to simple replacement.', error);
197
+ thing.bindings[key].code = replaceIndexNode(value.code);
146
198
  }
147
199
  }
200
+ else {
201
+ thing.bindings[key].code = replaceIndexNode(value.code);
202
+ }
148
203
  }
149
204
  });
150
205
  return node;
@@ -240,7 +295,7 @@ function tryFormat(code) {
240
295
  return str;
241
296
  }
242
297
  const blockToBuilder = (json, options = {}, _internalOptions = {}) => {
243
- var _a, _b, _c, _d, _e, _f, _g, _h, _j;
298
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
244
299
  const mapper = !_internalOptions.skipMapper && componentMappers[json.name];
245
300
  if (mapper) {
246
301
  return mapper(json, options);
@@ -272,8 +327,18 @@ const blockToBuilder = (json, options = {}, _internalOptions = {}) => {
272
327
  const eventBindingKeyRegex = /^on([A-Z])/;
273
328
  const firstCharMatchForEventBindingKey = (_d = key.match(eventBindingKeyRegex)) === null || _d === void 0 ? void 0 : _d[1];
274
329
  if (firstCharMatchForEventBindingKey) {
330
+ let actionBody = ((_e = bindings[key]) === null || _e === void 0 ? void 0 : _e.async)
331
+ ? `(async () => ${(_f = bindings[key]) === null || _f === void 0 ? void 0 : _f.code})()`
332
+ : (0, remove_surrounding_block_1.removeSurroundingBlock)((_g = bindings[key]) === null || _g === void 0 ? void 0 : _g.code);
333
+ const eventIdentifier = (_j = (_h = bindings[key]) === null || _h === void 0 ? void 0 : _h.arguments) === null || _j === void 0 ? void 0 : _j[0];
334
+ if (typeof eventIdentifier === 'string' && eventIdentifier !== 'event') {
335
+ actionBody = (0, replace_identifiers_1.replaceNodes)({
336
+ code: actionBody,
337
+ nodeMaps: [{ from: core_1.types.identifier(eventIdentifier), to: core_1.types.identifier('event') }],
338
+ });
339
+ }
275
340
  actions[key.replace(eventBindingKeyRegex, firstCharMatchForEventBindingKey.toLowerCase())] =
276
- (0, remove_surrounding_block_1.removeSurroundingBlock)((_e = bindings[key]) === null || _e === void 0 ? void 0 : _e.code);
341
+ actionBody;
277
342
  delete bindings[key];
278
343
  }
279
344
  }
@@ -290,7 +355,7 @@ const blockToBuilder = (json, options = {}, _internalOptions = {}) => {
290
355
  componentOptions[key] = parsed;
291
356
  }
292
357
  else {
293
- if (!((_f = json.slots) === null || _f === void 0 ? void 0 : _f[key])) {
358
+ if (!((_k = json.slots) === null || _k === void 0 ? void 0 : _k[key])) {
294
359
  builderBindings[`component.options.${key}`] = bindings[key].code;
295
360
  }
296
361
  }
@@ -299,12 +364,12 @@ const blockToBuilder = (json, options = {}, _internalOptions = {}) => {
299
364
  for (const key in json.slots) {
300
365
  componentOptions[key] = json.slots[key].map((node) => (0, exports.blockToBuilder)(node, options));
301
366
  }
302
- const hasCss = !!((_g = bindings.css) === null || _g === void 0 ? void 0 : _g.code);
367
+ const hasCss = !!((_l = bindings.css) === null || _l === void 0 ? void 0 : _l.code);
303
368
  let responsiveStyles = {
304
369
  large: {},
305
370
  };
306
371
  if (hasCss) {
307
- const cssRules = json5_1.default.parse((_h = bindings.css) === null || _h === void 0 ? void 0 : _h.code);
372
+ const cssRules = json5_1.default.parse((_m = bindings.css) === null || _m === void 0 ? void 0 : _m.code);
308
373
  const cssRuleKeys = Object.keys(cssRules);
309
374
  for (const ruleKey of cssRuleKeys) {
310
375
  const mediaQueryMatch = ruleKey.match(media_sizes_1.mediaQueryRegex);
@@ -328,7 +393,7 @@ const blockToBuilder = (json, options = {}, _internalOptions = {}) => {
328
393
  }
329
394
  if (thisIsComponent) {
330
395
  for (const key in json.bindings) {
331
- if (!((_j = json.slots) === null || _j === void 0 ? void 0 : _j[key])) {
396
+ if (!((_o = json.slots) === null || _o === void 0 ? void 0 : _o[key])) {
332
397
  builderBindings[`component.options.${key}`] = json.bindings[key].code;
333
398
  }
334
399
  }
@@ -192,7 +192,7 @@ const addOnChangeJs = (id, options, code) => {
192
192
  };
193
193
  // TODO: spread support
194
194
  const blockToHtml = (json, options, blockOptions = {}) => {
195
- var _a, _b, _c, _d, _e, _f, _g;
195
+ var _a, _b, _c, _d, _e, _f, _g, _h;
196
196
  const ComponentName = blockOptions.ComponentName;
197
197
  const scopeVars = (blockOptions === null || blockOptions === void 0 ? void 0 : blockOptions.scopeVars) || [];
198
198
  const childComponents = (blockOptions === null || blockOptions === void 0 ? void 0 : blockOptions.childComponents) || [];
@@ -303,11 +303,12 @@ const blockToHtml = (json, options, blockOptions = {}) => {
303
303
  }
304
304
  const fnName = (0, lodash_1.camelCase)(`on-${elId}-${event}`);
305
305
  const codeContent = (0, remove_surrounding_block_1.removeSurroundingBlock)(updateReferencesInCode(useValue, options, blockOptions));
306
+ const asyncKeyword = ((_h = json.bindings[key]) === null || _h === void 0 ? void 0 : _h.async) ? 'async ' : '';
306
307
  options.js += `
307
308
  // Event handler for '${event}' event on ${elId}
308
309
  ${options.format === 'class'
309
- ? `this.${fnName} = (${cusArg.join(',')}) => {`
310
- : `function ${fnName} (${cusArg.join(',')}) {`}
310
+ ? `this.${fnName} = ${asyncKeyword}(${cusArg.join(',')}) => {`
311
+ : `${asyncKeyword}function ${fnName} (${cusArg.join(',')}) {`}
311
312
  ${addScopeVars(scopeVars, codeContent, (scopeVar) => `const ${scopeVar} = ${options.format === 'class' ? 'this.' : ''}getScope(event.currentTarget, "${scopeVar}");`)}
312
313
  ${codeContent}
313
314
  }
@@ -469,7 +470,7 @@ const componentToHtml = (_options = {}) => ({ component }) => {
469
470
  ${!hasChangeListeners
470
471
  ? ''
471
472
  : `
472
-
473
+
473
474
  // Function to update data bindings and loops
474
475
  // call update() when you mutate state and need the updates to reflect
475
476
  // in the dom
@@ -500,7 +501,7 @@ const componentToHtml = (_options = {}) => ({ component }) => {
500
501
  ${json.hooks.onUpdate.reduce((code, hook) => {
501
502
  code += addUpdateAfterSetInCode(updateReferencesInCode(hook.code, options), options);
502
503
  return code + '\n';
503
- }, '')}
504
+ }, '')}
504
505
  `}
505
506
 
506
507
  pendingUpdate = false;
@@ -526,7 +527,7 @@ const componentToHtml = (_options = {}) => ({ component }) => {
526
527
  : // TODO: make prettier by grabbing only the function body
527
528
  `
528
529
  // onMount
529
- ${updateReferencesInCode(addUpdateAfterSetInCode((0, on_mount_1.stringifySingleScopeOnMount)(json), options), options)}
530
+ ${updateReferencesInCode(addUpdateAfterSetInCode((0, on_mount_1.stringifySingleScopeOnMount)(json), options), options)}
530
531
  `}
531
532
 
532
533
  ${!hasShow
@@ -537,8 +538,8 @@ const componentToHtml = (_options = {}) => ({ component }) => {
537
538
  // grabs the content of a node that is between <template> tags
538
539
  // iterates through child nodes to register all content including text elements
539
540
  // attaches the content after the template
540
-
541
-
541
+
542
+
542
543
  const elementFragment = el.content.cloneNode(true);
543
544
  const children = Array.from(elementFragment.childNodes)
544
545
  children.forEach(child => {
@@ -552,7 +553,7 @@ const componentToHtml = (_options = {}) => ({ component }) => {
552
553
  });
553
554
  el.after(elementFragment);
554
555
  }
555
-
556
+
556
557
  `}
557
558
  ${!hasTextBinding
558
559
  ? ''
@@ -770,9 +771,9 @@ const componentToCustomElement = (_options = {}) => ({ component }) => {
770
771
  })}
771
772
  /**
772
773
  * Usage:
773
- *
774
+ *
774
775
  * <${kebabName}></${kebabName}>
775
- *
776
+ *
776
777
  */
777
778
  class ${ComponentName} extends ${((_h = options === null || options === void 0 ? void 0 : options.experimental) === null || _h === void 0 ? void 0 : _h.classExtends)
778
779
  ? (_j = options === null || options === void 0 ? void 0 : options.experimental) === null || _j === void 0 ? void 0 : _j.classExtends(json, options)
@@ -940,8 +941,8 @@ const componentToCustomElement = (_options = {}) => ({ component }) => {
940
941
  // grabs the content of a node that is between <template> tags
941
942
  // iterates through child nodes to register all content including text elements
942
943
  // attaches the content after the template
943
-
944
-
944
+
945
+
945
946
  const elementFragment = el.content.cloneNode(true);
946
947
  const children = Array.from(elementFragment.childNodes)
947
948
  children.forEach(child => {
@@ -1008,7 +1009,7 @@ const componentToCustomElement = (_options = {}) => ({ component }) => {
1008
1009
  `;
1009
1010
  }
1010
1011
  return code + '\n';
1011
- }, '')}
1012
+ }, '')}
1012
1013
  `}
1013
1014
  }
1014
1015
 
@@ -1099,7 +1100,7 @@ const componentToCustomElement = (_options = {}) => ({ component }) => {
1099
1100
  ? `
1100
1101
  ${(_g = options === null || options === void 0 ? void 0 : options.experimental) === null || _g === void 0 ? void 0 : _g.generateQuerySelectorAll(key, code)}
1101
1102
  `
1102
- : `
1103
+ : `
1103
1104
  this._root.querySelectorAll("[data-el='${key}']").forEach((el) => {
1104
1105
  ${code}
1105
1106
  })
@@ -36,7 +36,7 @@ const getCustomTagName = (name, options) => {
36
36
  return kebabCaseName;
37
37
  };
38
38
  const blockToLit = (json, options = {}) => {
39
- var _a, _b, _c, _d, _e, _f;
39
+ var _a, _b, _c, _d, _e, _f, _g;
40
40
  if (json.properties._text) {
41
41
  return json.properties._text;
42
42
  }
@@ -82,8 +82,9 @@ const blockToLit = (json, options = {}) => {
82
82
  }
83
83
  else if (key.startsWith('on')) {
84
84
  let useKey = key === 'onChange' && json.name === 'input' ? 'onInput' : key;
85
+ const asyncKeyword = ((_g = json.bindings[key]) === null || _g === void 0 ? void 0 : _g.async) ? 'async ' : '';
85
86
  useKey = '@' + useKey.substring(2).toLowerCase();
86
- str += ` ${useKey}=\${${cusArgs.join(',')} => ${processBinding(code)}} `;
87
+ str += ` ${useKey}=\${${asyncKeyword}(${cusArgs.join(',')}) => ${processBinding(code)}} `;
87
88
  }
88
89
  else {
89
90
  const value = processBinding(code);
@@ -172,7 +173,7 @@ const componentToLit = (_options = {}) => ({ component }) => {
172
173
  }
173
174
  catch (err) {
174
175
  // If can't format HTML (this can happen with lit given it is tagged template strings),
175
- // at least remove excess space
176
+ // at least remove excess fspace
176
177
  html = html.replace(/\n{3,}/g, '\n\n');
177
178
  }
178
179
  }
@@ -69,7 +69,7 @@ const blockToMarko = (json, options) => {
69
69
  str += ` ${key}="${value}" `;
70
70
  }
71
71
  for (const key in json.bindings) {
72
- const { code, arguments: cusArgs = ['event'], type } = json.bindings[key];
72
+ const { code, arguments: cusArgs = ['event'], type, async } = json.bindings[key];
73
73
  if (type === 'spread') {
74
74
  str += ` ...(${code}) `;
75
75
  }
@@ -77,8 +77,9 @@ const blockToMarko = (json, options) => {
77
77
  str += ` key="${(0, lodash_1.camelCase)(code)}" `;
78
78
  }
79
79
  else if (key.startsWith('on')) {
80
+ const asyncKeyword = async ? 'async ' : '';
80
81
  const useKey = key === 'onChange' && json.name === 'input' ? 'onInput' : key;
81
- str += ` ${(0, dash_case_1.dashCase)(useKey)}=(${cusArgs.join(',')} => ${processBinding(options.component, code)}) `;
82
+ str += ` ${(0, dash_case_1.dashCase)(useKey)}=(${asyncKeyword}(${cusArgs.join(',')}) => ${processBinding(options.component, code)}) `;
82
83
  }
83
84
  else if (key !== 'innerHTML') {
84
85
  str += ` ${key}=(${processBinding(options.component, code)}) `;
@@ -187,11 +188,11 @@ const componentToMarko = (userOptions = {}) => ({ component }) => {
187
188
  }`}
188
189
 
189
190
  ${Array.from(domRefs)
190
- .map((refName) => `get ${(0, lodash_1.camelCase)(refName)}() {
191
+ .map((refName) => `get ${(0, lodash_1.camelCase)(refName)}() {
191
192
  return this.getEl('${(0, lodash_1.camelCase)(refName)}')
192
193
  }`)
193
194
  .join('\n')}
194
-
195
+
195
196
  ${!json.hooks.onMount.length
196
197
  ? ''
197
198
  : `onMount() { ${processBinding(json, (0, on_mount_1.stringifySingleScopeOnMount)(json), 'class')} }`}
@@ -207,7 +208,7 @@ const componentToMarko = (userOptions = {}) => ({ component }) => {
207
208
  `;
208
209
  let htmlString = json.children.map((item) => blockToMarko(item, options)).join('\n');
209
210
  const cssString = css.length
210
- ? `style {
211
+ ? `style {
211
212
  ${(0, indent_1.indent)(css, 2).trim()}
212
213
  }`
213
214
  : '';
@@ -121,7 +121,9 @@ const blockToMitosis = (json, toMitosisOptions = {}, component, insideJsx) => {
121
121
  str += ` {...(${(_h = json.bindings[key]) === null || _h === void 0 ? void 0 : _h.code})} `;
122
122
  }
123
123
  else if (key.startsWith('on')) {
124
- str += ` ${key}={event => ${value.replace(/\s*;$/, '')}} `;
124
+ const { arguments: cusArgs = ['event'], async } = json.bindings[key];
125
+ const asyncKeyword = async ? 'async ' : '';
126
+ str += ` ${key}={${asyncKeyword}(${cusArgs.join(',')}) => ${value.replace(/\s*;$/, '')}} `;
125
127
  }
126
128
  else {
127
129
  if (!isValidAttributeName(key)) {
@@ -139,7 +139,7 @@ const NATIVE_EVENT_MAPPER = {
139
139
  onClick: 'onPress',
140
140
  };
141
141
  const blockToReact = (json, options, component, insideJsx, parentSlots = []) => {
142
- var _a, _b, _c, _d;
142
+ var _a, _b, _c, _d, _e;
143
143
  const needsToRenderSlots = [];
144
144
  if (NODE_MAPPERS[json.name]) {
145
145
  return NODE_MAPPERS[json.name](json, options, component, insideJsx, parentSlots);
@@ -244,9 +244,10 @@ const blockToReact = (json, options, component, insideJsx, parentSlots = []) =>
244
244
  str += ` {...(${value})} `;
245
245
  }
246
246
  else if (key.startsWith('on')) {
247
+ const asyncKeyword = ((_e = json.bindings[key]) === null || _e === void 0 ? void 0 : _e.async) ? 'async ' : '';
247
248
  const { arguments: cusArgs = ['event'] } = json.bindings[key];
248
249
  const eventName = options.type === 'native' ? NATIVE_EVENT_MAPPER[key] || key : key;
249
- str += ` ${eventName}={(${cusArgs.join(',')}) => ${(0, state_1.updateStateSettersInCode)(useBindingValue, options)} } `;
250
+ str += ` ${eventName}={${asyncKeyword}(${cusArgs.join(',')}) => ${(0, state_1.updateStateSettersInCode)(useBindingValue, options)} } `;
250
251
  }
251
252
  else if (key.startsWith('slot')) {
252
253
  // <Component slotProjected={<AnotherComponent />} />
@@ -19,7 +19,7 @@ const transformAttributeName = (name) => {
19
19
  return name;
20
20
  };
21
21
  const blockToSolid = (json, component, options, insideJsx) => {
22
- var _a, _b, _c;
22
+ var _a, _b, _c, _d;
23
23
  if (insideJsx) {
24
24
  if (json.properties._text) {
25
25
  return json.properties._text;
@@ -77,7 +77,8 @@ const blockToSolid = (json, component, options, insideJsx) => {
77
77
  }
78
78
  else if (key.startsWith('on')) {
79
79
  const useKey = key === 'onChange' && json.name === 'input' ? 'onInput' : key;
80
- str += ` ${useKey}={(${cusArg.join(',')}) => ${code}} `;
80
+ const asyncKeyword = ((_d = json.bindings[key]) === null || _d === void 0 ? void 0 : _d.async) ? 'async ' : '';
81
+ str += ` ${useKey}={${asyncKeyword}(${cusArg.join(',')}) => ${code}} `;
81
82
  }
82
83
  else if (key === 'ref' && options.typescript) {
83
84
  str += ` ${key}={${code}!} `;
@@ -8,7 +8,7 @@ const filter_empty_text_nodes_1 = require("../../helpers/filter-empty-text-nodes
8
8
  const for_1 = require("../../helpers/nodes/for");
9
9
  const mitosis_node_1 = require("../../types/mitosis-node");
10
10
  const blockToStencil = (json, options = {}, insideJsx, childComponents) => {
11
- var _a, _b, _c, _d, _e, _f;
11
+ var _a, _b, _c, _d, _e, _f, _g;
12
12
  let blockName = childComponents.find((impName) => impName === json.name)
13
13
  ? (0, helpers_1.getTagName)(json.name, options)
14
14
  : json.name;
@@ -87,7 +87,8 @@ const blockToStencil = (json, options = {}, insideJsx, childComponents) => {
87
87
  }
88
88
  else if ((0, helpers_1.isEvent)(key)) {
89
89
  const useKey = key === 'onChange' && blockName === 'input' ? 'onInput' : key;
90
- str += ` ${useKey}={(${cusArgs.join(',')}) => ${code}} `;
90
+ const asyncKeyword = ((_g = json.bindings[key]) === null || _g === void 0 ? void 0 : _g.async) ? 'async ' : '';
91
+ str += ` ${useKey}={${asyncKeyword}(${cusArgs.join(',')}) => ${code}} `;
91
92
  }
92
93
  else {
93
94
  str += ` ${key}={${code}} `;
@@ -175,15 +175,17 @@ const stringifyBinding = (node, options) => ([key, binding]) => {
175
175
  return ` {...${spreadValue}} `;
176
176
  }
177
177
  else if (key.startsWith('on') && isValidHtmlTag) {
178
+ const { async } = binding;
178
179
  // handle html native on[event] props
179
180
  const event = key.replace('on', '').toLowerCase();
180
181
  // TODO: handle quotes in event handler values
181
182
  const valueWithoutBlock = (0, remove_surrounding_block_1.removeSurroundingBlock)(code);
182
- if (valueWithoutBlock === key) {
183
+ if (valueWithoutBlock === key && !async) {
183
184
  return ` on:${event}={${valueWithoutBlock}} `;
184
185
  }
185
186
  else {
186
- return ` on:${event}="{${cusArgs.join(',')} => {${valueWithoutBlock}}}" `;
187
+ const asyncKeyword = async ? 'async ' : '';
188
+ return ` on:${event}="{${asyncKeyword}(${cusArgs.join(',')}) => {${valueWithoutBlock}}}" `;
187
189
  }
188
190
  }
189
191
  else if (key.startsWith('on')) {
@@ -4,6 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.blockToVue = void 0;
7
+ const bindings_1 = require("../../helpers/bindings");
7
8
  const filter_empty_text_nodes_1 = require("../../helpers/filter-empty-text-nodes");
8
9
  const is_children_1 = __importDefault(require("../../helpers/is-children"));
9
10
  const is_mitosis_node_1 = require("../../helpers/is-mitosis-node");
@@ -105,14 +106,20 @@ const stringifyBinding = (node, options) => ([key, value]) => {
105
106
  const useValue = (value === null || value === void 0 ? void 0 : value.code) || '';
106
107
  if (key.startsWith('on') && isValidHtmlTag) {
107
108
  // handle html native on[event] props
108
- const { arguments: cusArgs = ['event'] } = value;
109
+ const { arguments: cusArgs = ['event'], async } = value;
109
110
  let event = key.replace('on', '').toLowerCase();
110
111
  const isAssignmentExpression = useValue.includes('=');
111
- const eventHandlerValue = (0, function_1.pipe)((0, replace_identifiers_1.replaceIdentifiers)({
112
- code: useValue,
113
- from: cusArgs[0],
114
- to: '$event',
115
- }), isAssignmentExpression ? function_1.identity : remove_surrounding_block_1.removeSurroundingBlock, remove_surrounding_block_1.removeSurroundingBlock, helpers_1.encodeQuotes);
112
+ let eventHandlerValue;
113
+ if (async) {
114
+ eventHandlerValue = (0, function_1.pipe)((0, replace_identifiers_1.replaceIdentifiers)({
115
+ code: useValue,
116
+ from: cusArgs[0],
117
+ to: '$event',
118
+ }), isAssignmentExpression ? function_1.identity : remove_surrounding_block_1.removeSurroundingBlock, remove_surrounding_block_1.removeSurroundingBlock, helpers_1.encodeQuotes);
119
+ }
120
+ else {
121
+ eventHandlerValue = `async (${cusArgs.join(', ')}) => ${useValue}`;
122
+ }
116
123
  const eventHandlerKey = `${SPECIAL_PROPERTIES.V_ON_AT}${event}`;
117
124
  return `${eventHandlerKey}="${eventHandlerValue}"`;
118
125
  }
@@ -179,7 +186,7 @@ const blockToVue = (node, options, scope) => {
179
186
  }
180
187
  if (SPECIAL_HTML_TAGS.includes(node.name)) {
181
188
  // Vue doesn't allow style/script tags in templates, but does support them through dynamic components.
182
- node.bindings.is = { code: `'${node.name}'`, type: 'single' };
189
+ node.bindings.is = (0, bindings_1.createSingleBinding)({ code: `'${node.name}'` });
183
190
  node.name = 'component';
184
191
  }
185
192
  if (node.properties._text) {
@@ -1,2 +1,6 @@
1
1
  import { Binding } from '../types/mitosis-node';
2
- export declare const createSingleBinding: (args: Omit<Binding, 'type'>) => Binding;
2
+ type SingleBinding = Omit<Binding & {
3
+ type: 'single';
4
+ }, 'type'>;
5
+ export declare const createSingleBinding: (args: Omit<SingleBinding, 'bindingType'> & Partial<Pick<SingleBinding, 'bindingType'>>) => Binding;
6
+ export {};
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createSingleBinding = void 0;
4
4
  const createSingleBinding = (args) => ({
5
5
  ...args,
6
+ bindingType: args.bindingType || 'expression',
6
7
  type: 'single',
7
8
  });
8
9
  exports.createSingleBinding = createSingleBinding;
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.processOnEventHooksPlugin = exports.getOnEventHooksForNode = exports.getOnEventHandlerName = void 0;
4
+ const bindings_1 = require("./bindings");
4
5
  const capitalize_1 = require("./capitalize");
5
6
  const traverse_nodes_1 = require("./traverse-nodes");
6
7
  const checkIsEventHandlerNode = (node, hook) => {
@@ -37,11 +38,11 @@ const processOnEventHooksPlugin = (args = {}) => () => ({
37
38
  type: 'method',
38
39
  };
39
40
  if (setBindings) {
40
- node.bindings[handlerName] = {
41
+ node.bindings[handlerName] = (0, bindings_1.createSingleBinding)({
41
42
  code: `state.${fnName}(${hook.eventArgName})`,
42
43
  arguments: [hook.eventArgName],
43
- type: 'single',
44
- };
44
+ bindingType: 'function',
45
+ });
45
46
  }
46
47
  });
47
48
  });
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.processTargetBlocks = void 0;
4
4
  const use_target_1 = require("../../parsers/jsx/hooks/use-target");
5
+ const bindings_1 = require("../bindings");
5
6
  const process_code_1 = require("./process-code");
6
7
  const getBlockForTarget = ({ target, targetBlock, }) => {
7
8
  switch (target) {
@@ -20,10 +21,7 @@ const processTargetBlocks = (target) => {
20
21
  const property = node === null || node === void 0 ? void 0 : node.properties[key];
21
22
  if (!matches || !property)
22
23
  return code;
23
- node.bindings[key] = {
24
- code: '"' + property + '"',
25
- type: 'single',
26
- };
24
+ node.bindings[key] = (0, bindings_1.createSingleBinding)({ code: `"${property}"` });
27
25
  return () => {
28
26
  delete node.properties[key];
29
27
  };
@@ -92,7 +92,7 @@ const getActionBindingsFromBlock = (block, options) => {
92
92
  const actionKeys = Object.keys(actions);
93
93
  if (actionKeys.length) {
94
94
  for (const key of actionKeys) {
95
- const value = actions[key];
95
+ let value = actions[key];
96
96
  // Skip empty values
97
97
  if (!value.trim()) {
98
98
  continue;
@@ -103,7 +103,16 @@ const getActionBindingsFromBlock = (block, options) => {
103
103
  continue;
104
104
  }
105
105
  const useKey = `on${(0, lodash_1.upperFirst)(key)}`;
106
- bindings[useKey] = (0, bindings_1.createSingleBinding)({ code: `${wrapBindingIfNeeded(value, options)}` });
106
+ const asyncPrefix = `(async () =>`;
107
+ const asyncSuffix = ')()';
108
+ const isAsync = value.startsWith(asyncPrefix) && value.endsWith(asyncSuffix);
109
+ if (isAsync) {
110
+ value = value.slice(asyncPrefix.length, -asyncSuffix.length);
111
+ }
112
+ bindings[useKey] = (0, bindings_1.createSingleBinding)({
113
+ code: `${wrapBindingIfNeeded(value, options)}`,
114
+ async: isAsync ? true : undefined,
115
+ });
107
116
  }
108
117
  }
109
118
  return bindings;
@@ -355,16 +364,14 @@ const componentMappers = {
355
364
  });
356
365
  const queryOptions = variant.query;
357
366
  if (Array.isArray(queryOptions)) {
358
- variantNode.bindings.query = {
359
- type: 'single',
367
+ variantNode.bindings.query = (0, bindings_1.createSingleBinding)({
360
368
  code: JSON.stringify(queryOptions.map((q) => (0, lodash_1.omit)(q, '@type'))),
361
- };
369
+ });
362
370
  }
363
371
  else if (queryOptions) {
364
- variantNode.bindings.query = {
365
- type: 'single',
372
+ variantNode.bindings.query = (0, bindings_1.createSingleBinding)({
366
373
  code: JSON.stringify((0, lodash_1.omit)(queryOptions, '@type')),
367
- };
374
+ });
368
375
  }
369
376
  return variantNode;
370
377
  })) || [];
@@ -280,7 +280,9 @@ const jsxElementToJson = (node) => {
280
280
  : [];
281
281
  memo.bindings[key] = (0, bindings_1.createSingleBinding)({
282
282
  code: (0, generator_1.default)(expression.body, { compact: true }).code,
283
+ async: expression.async === true ? true : undefined,
283
284
  arguments: args.length ? args : undefined,
285
+ bindingType: 'function',
284
286
  });
285
287
  }
286
288
  else if (types.isJSXElement(expression)) {
@@ -1,14 +1,32 @@
1
1
  import { JSONObject } from './json';
2
2
  export type SpreadType = 'normal' | 'event-handlers';
3
+ export type BindingType = 'function' | 'expression';
3
4
  type BindingProperties = {
4
5
  type: 'spread';
5
6
  spreadType: SpreadType;
7
+ /**
8
+ * TODO: remove these once we've cleaned up the code that uses them.
9
+ * they don't need to be here since they only exist for functions
10
+ */
11
+ async?: boolean;
12
+ arguments?: string[];
13
+ } | {
14
+ type: 'single';
15
+ bindingType: Extract<BindingType, 'function'>;
16
+ async?: boolean;
17
+ arguments?: string[];
6
18
  } | {
7
19
  type: 'single';
20
+ bindingType: Extract<BindingType, 'expression'>;
21
+ /**
22
+ * TODO: remove these once we've cleaned up the code that uses them.
23
+ * they don't need to be here since they only exist for functions
24
+ */
25
+ async?: boolean;
26
+ arguments?: string[];
8
27
  };
9
28
  export type Binding = {
10
29
  code: string;
11
- arguments?: string[];
12
30
  } & BindingProperties;
13
31
  export type BaseNode = {
14
32
  '@type': '@builder.io/mitosis/node';
package/package.json CHANGED
@@ -22,7 +22,7 @@
22
22
  "name": "Builder.io",
23
23
  "url": "https://www.builder.io"
24
24
  },
25
- "version": "0.5.12",
25
+ "version": "0.5.14",
26
26
  "homepage": "https://github.com/BuilderIO/mitosis",
27
27
  "main": "./dist/src/index.js",
28
28
  "exports": {