UNPKG

@builder.io/mitosis

Version:

Write components once, run everywhere. Compiles to Vue, React, Solid, and Liquid. Import code from Figma and Builder.io

357 lines (340 loc) 19.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.componentToAngularClassic = void 0; const blocks_1 = require("../../../generators/angular/classic/blocks"); const get_class_properties_plugin_1 = require("../../../generators/angular/classic/plugins/get-class-properties-plugin"); const get_code_processor_plugins_1 = require("../../../generators/angular/classic/plugins/get-code-processor-plugins"); const helpers_1 = require("../../../generators/angular/helpers"); const get_inputs_1 = require("../../../generators/angular/helpers/get-inputs"); const get_outputs_1 = require("../../../generators/angular/helpers/get-outputs"); const get_refs_1 = require("../../../generators/angular/helpers/get-refs"); const get_styles_1 = require("../../../generators/angular/helpers/get-styles"); const types_1 = require("../../../generators/angular/types"); const on_mount_1 = require("../../../generators/helpers/on-mount"); const dedent_1 = require("../../../helpers/dedent"); const fast_clone_1 = require("../../../helpers/fast-clone"); const get_child_components_1 = require("../../../helpers/get-child-components"); const get_components_used_1 = require("../../../helpers/get-components-used"); const get_custom_imports_1 = require("../../../helpers/get-custom-imports"); const get_prop_functions_1 = require("../../../helpers/get-prop-functions"); const get_props_1 = require("../../../helpers/get-props"); const get_props_ref_1 = require("../../../helpers/get-props-ref"); const get_refs_2 = require("../../../helpers/get-refs"); const get_state_object_string_1 = require("../../../helpers/get-state-object-string"); const get_typed_function_1 = require("../../../helpers/get-typed-function"); const is_upper_case_1 = require("../../../helpers/is-upper-case"); const merge_options_1 = require("../../../helpers/merge-options"); const render_imports_1 = require("../../../helpers/render-imports"); const strip_meta_properties_1 = require("../../../helpers/strip-meta-properties"); const attribute_passing_1 = require("../../../helpers/web-components/attribute-passing"); const plugins_1 = require("../../../modules/plugins"); const lodash_1 = require("lodash"); const format_1 = require("../helpers/format"); const componentToAngularClassic = (userOptions = {}) => { return ({ component: _component }) => { var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x; // Make a copy we can safely mutate, similar to babel's toolchain let json = (0, fast_clone_1.fastClone)(_component); const useMetadata = (_a = json.meta) === null || _a === void 0 ? void 0 : _a.useMetadata; const contextVars = Object.keys(((_b = json === null || json === void 0 ? void 0 : json.context) === null || _b === void 0 ? void 0 : _b.get) || {}); const metaOutputVars = (useMetadata === null || useMetadata === void 0 ? void 0 : useMetadata.outputs) || []; const outputVars = (0, lodash_1.uniq)([...metaOutputVars, ...(0, get_prop_functions_1.getPropFunctions)(json)]); const options = (0, merge_options_1.initializeOptions)({ target: 'angular', component: _component, defaults: types_1.DEFAULT_ANGULAR_OPTIONS, userOptions, }); options.plugins = (0, get_code_processor_plugins_1.getCodeProcessorPlugins)({ json, options, outputVars, contextVars }); if (options.state === 'class-properties') { options.plugins.push((0, get_class_properties_plugin_1.getClassPropertiesPlugin)()); } if (options.plugins) { json = (0, plugins_1.runPreJsonPlugins)({ json, plugins: options.plugins }); } // Prepare Props const [forwardProp, hasPropRef] = (0, get_props_ref_1.getPropsRef)(json, true); const props = (0, get_props_1.getProps)(json); // prevent jsx props from showing up as @Input if (hasPropRef) { props.delete(forwardProp); } props.delete('children'); // remove props for outputs for (const variableName of outputVars) { props.delete(variableName); } const childComponents = (0, get_child_components_1.getChildComponents)(json); const customImports = (0, get_custom_imports_1.getCustomImports)(json); const { exports: localExports = {} } = json; const localExportVars = Object.keys(localExports) .filter((key) => localExports[key].usedInLocal) .map((key) => `${key} = ${key};`); // Context handling const injectables = contextVars.map((variableName) => { var _a, _b, _c, _d; const variableType = (_a = json === null || json === void 0 ? void 0 : json.context) === null || _a === void 0 ? void 0 : _a.get[variableName].name; if ((_b = options === null || options === void 0 ? void 0 : options.experimental) === null || _b === void 0 ? void 0 : _b.injectables) { return (_c = options === null || options === void 0 ? void 0 : options.experimental) === null || _c === void 0 ? void 0 : _c.injectables(variableName, variableType); } if ((_d = options === null || options === void 0 ? void 0 : options.experimental) === null || _d === void 0 ? void 0 : _d.inject) { return `@Inject(forwardRef(() => ${variableType})) public ${variableName}: ${variableType}`; } return `public ${variableName} : ${variableType}`; }); // Handle refs const withAttributePassing = (0, attribute_passing_1.shouldAddAttributePassing)(json, options); const rootRef = (0, attribute_passing_1.getAddAttributePassingRef)(json, options); const domRefs = (0, get_refs_1.getDomRefs)({ json, options, withAttributePassing, rootRef }); const jsRefs = Object.keys(json.refs).filter((ref) => !domRefs.has(ref)); if (options.plugins) { json = (0, plugins_1.runPostJsonPlugins)({ json, plugins: options.plugins }); } // CSS const styles = (0, get_styles_1.getAngularStyles)({ json, options }); const helperFunctions = new Set(); const shouldUseSanitizer = !((_c = useMetadata === null || useMetadata === void 0 ? void 0 : useMetadata.angular) === null || _c === void 0 ? void 0 : _c.sanitizeInnerHTML) && (0, helpers_1.traverseAndCheckIfInnerHTMLIsUsed)(json); const changeDetectionStrategy = (_d = useMetadata === null || useMetadata === void 0 ? void 0 : useMetadata.angular) === null || _d === void 0 ? void 0 : _d.changeDetection; let template = json.children .map((item) => { var _a, _b, _c, _d; const tmpl = (0, blocks_1.blockToAngular)({ root: json, json: item, options, rootRef: withAttributePassing && rootRef === attribute_passing_1.ROOT_REF ? rootRef : undefined, // only pass rootRef if it's not the default blockOptions: { childComponents, nativeAttributes: (_b = (_a = useMetadata === null || useMetadata === void 0 ? void 0 : useMetadata.angular) === null || _a === void 0 ? void 0 : _a.nativeAttributes) !== null && _b !== void 0 ? _b : [], nativeEvents: (_d = (_c = useMetadata === null || useMetadata === void 0 ? void 0 : useMetadata.angular) === null || _c === void 0 ? void 0 : _c.nativeEvents) !== null && _d !== void 0 ? _d : [], sanitizeInnerHTML: !shouldUseSanitizer, }, }); if (options.state === 'inline-with-wrappers') { (0, helpers_1.getAppropriateTemplateFunctionKeys)(tmpl).forEach((key) => helperFunctions.add((0, helpers_1.HELPER_FUNCTIONS)(options.typescript)[key])); } return tmpl; }) .join('\n'); if (options.prettier !== false) { template = (0, format_1.tryFormat)(template, 'html'); } (0, strip_meta_properties_1.stripMetaProperties)(json); const { components: dynamicComponents, dynamicTemplate } = (0, helpers_1.traverseToGetAllDynamicComponents)(json, options, { childComponents, nativeAttributes: (_f = (_e = useMetadata === null || useMetadata === void 0 ? void 0 : useMetadata.angular) === null || _e === void 0 ? void 0 : _e.nativeAttributes) !== null && _f !== void 0 ? _f : [], nativeEvents: (_h = (_g = useMetadata === null || useMetadata === void 0 ? void 0 : useMetadata.angular) === null || _g === void 0 ? void 0 : _g.nativeEvents) !== null && _h !== void 0 ? _h : [], }); (0, helpers_1.transformState)(json); const dataString = (0, get_state_object_string_1.getStateObjectStringFromComponent)(json, { format: 'class', withType: options.typescript, valueMapper: (code, type, typeParameter) => { let value = code; if (type !== 'data') { value = (0, get_typed_function_1.getTypedFunction)(code, options.typescript, typeParameter); } return (0, helpers_1.processAngularCode)({ replaceWith: 'this', contextVars, outputVars, domRefs: Array.from(domRefs), })(value); }, }); const refsForObjSpread = (0, get_refs_2.getRefs)(json, 'spreadRef'); // Preparing built in component metadata parameters const componentsUsed = Array.from((0, get_components_used_1.getComponentsUsed)(json)).filter((item) => item.length && (0, is_upper_case_1.isUpperCase)(item[0]) && !types_1.BUILT_IN_COMPONENTS.has(item)); const componentMetadata = { selector: ((_j = useMetadata === null || useMetadata === void 0 ? void 0 : useMetadata.angular) === null || _j === void 0 ? void 0 : _j.selector) ? `'${(_k = useMetadata === null || useMetadata === void 0 ? void 0 : useMetadata.angular) === null || _k === void 0 ? void 0 : _k.selector}'` : `'${(0, lodash_1.kebabCase)(json.name || 'my-component')}'`, template: `\` ${(0, helpers_1.getTemplateFormat)(dynamicTemplate)} ${(0, helpers_1.getTemplateFormat)(template)} \``, ...(changeDetectionStrategy === 'OnPush' ? { changeDetection: 'ChangeDetectionStrategy.OnPush', } : {}), ...(styles ? { styles: `[\`${styles}\`]`, } : {}), ...(options.standalone ? // TODO: also add child component imports here as well { standalone: 'true', imports: `[${['CommonModule', ...componentsUsed].join(', ')}]`, } : {}), }; // Taking into consideration what user has passed in options and allowing them to override the default generated metadata Object.entries(json.meta.angularConfig || {}).forEach(([key, value]) => { componentMetadata[key] = value; }); const hasConstructor = Boolean(injectables.length) || dynamicComponents.size || refsForObjSpread.size || shouldUseSanitizer; const angularCoreImports = [ ...(outputVars.length ? ['Output', 'EventEmitter'] : []), ...(((_l = options === null || options === void 0 ? void 0 : options.experimental) === null || _l === void 0 ? void 0 : _l.inject) ? ['Inject', 'forwardRef'] : []), 'Component', ...(domRefs.size || dynamicComponents.size || refsForObjSpread.size ? ['ViewChild', 'ElementRef'] : []), ...(refsForObjSpread.size ? ['Renderer2'] : []), ...(props.size ? ['Input'] : []), ...(dynamicComponents.size ? ['ViewContainerRef', 'TemplateRef'] : []), ...(((_m = json.hooks.onUpdate) === null || _m === void 0 ? void 0 : _m.length) && options.typescript ? ['SimpleChanges'] : []), ...(changeDetectionStrategy === 'OnPush' ? ['ChangeDetectionStrategy'] : []), ].join(', '); const constructorInjectables = [ ...injectables, ...(dynamicComponents.size ? [`private vcRef${options.typescript ? ': ViewContainerRef' : ''}`] : []), ...(refsForObjSpread.size ? [`private renderer${options.typescript ? ': Renderer2' : ''}`] : []), ...(shouldUseSanitizer ? [`protected sanitizer${options.typescript ? ': DomSanitizer' : ''}`] : []), ].join(',\n'); let str = (0, dedent_1.dedent) ` import { ${angularCoreImports} } from '@angular/core'; ${shouldUseSanitizer ? `import { DomSanitizer } from '@angular/platform-browser';` : ''} ${options.standalone ? `import { CommonModule } from '@angular/common';` : ''} ${json.types ? json.types.join('\n') : ''} ${(0, helpers_1.getDefaultProps)(json)} ${(0, render_imports_1.renderPreComponent)({ explicitImportFileExtension: options.explicitImportFileExtension, component: json, target: 'angular', excludeMitosisComponents: !options.standalone && !options.preserveImports, preserveFileExtensions: options.preserveFileExtensions, componentsUsed, importMapper: options === null || options === void 0 ? void 0 : options.importMapper, })} @Component({ ${Object.entries(componentMetadata) .map(([k, v]) => `${k}: ${v}`) .join(',')} }) export default class ${json.name} { ${localExportVars.join('\n')} ${customImports.map((name) => `${name} = ${name}`).join('\n')} ${(0, get_inputs_1.getInputs)({ json, options, props: Array.from(props), })} ${(0, get_outputs_1.getOutputs)({ json, outputVars })} ${[...Array.from(domRefs), ...Array.from(refsForObjSpread)] .map((refName) => `@ViewChild('${refName}') ${refName}${options.typescript ? '!: ElementRef' : ''}`) .join('\n')} ${Array.from(dynamicComponents) .map((component) => `@ViewChild('${component .split('.')[1] .toLowerCase()}Template', { static: true }) ${component .split('.')[1] .toLowerCase()}TemplateRef${options.typescript ? '!: TemplateRef<any>' : ''}`) .join('\n')} ${dynamicComponents.size ? `myContent${options.typescript ? '?: any[][];' : ''}` : ''} ${refsForObjSpread.size ? `_listenerFns = new Map${options.typescript ? '<string, () => void>' : ''}()` : ''} ${dataString} ${helperFunctions.size ? Array.from(helperFunctions).join('\n') : ''} ${jsRefs .map((ref) => { const argument = json.refs[ref].argument; const typeParameter = json.refs[ref].typeParameter; return `private _${ref}${typeParameter ? `: ${typeParameter}` : ''}${argument ? ` = ${(0, helpers_1.processAngularCode)({ replaceWith: 'this.', contextVars, outputVars, domRefs: Array.from(domRefs), })(argument)}` : ''};`; }) .join('\n')} ${!hasConstructor ? '' : `constructor(\n${constructorInjectables}) {}`} ${withAttributePassing ? (0, attribute_passing_1.getAttributePassingString)(options.typescript) : ''} ${!json.hooks.onMount.length && !dynamicComponents.size && !((_o = json.hooks.onInit) === null || _o === void 0 ? void 0 : _o.code) ? '' : `ngOnInit() { ${!((_p = json.hooks) === null || _p === void 0 ? void 0 : _p.onInit) ? '' : ` ${(_q = json.hooks.onInit) === null || _q === void 0 ? void 0 : _q.code} `} ${json.hooks.onMount.length > 0 ? ` if (typeof window !== 'undefined') { ${(0, on_mount_1.stringifySingleScopeOnMount)(json)} } ` : ''} ${dynamicComponents.size ? ` this.myContent = [${Array.from(dynamicComponents) .map((component) => `this.vcRef.createEmbeddedView(this.${component .split('.')[1] .toLowerCase()}TemplateRef).rootNodes`) .join(', ')}]; ` : ''} }`} ${ // hooks specific to Angular ((_s = (_r = json.compileContext) === null || _r === void 0 ? void 0 : _r.angular) === null || _s === void 0 ? void 0 : _s.hooks) ? Object.entries((_u = (_t = json.compileContext) === null || _t === void 0 ? void 0 : _t.angular) === null || _u === void 0 ? void 0 : _u.hooks) .map(([key, value]) => { return `${key}() { ${value.code} }`; }) .join('\n') : ''} ${!((_v = json.hooks.onUpdate) === null || _v === void 0 ? void 0 : _v.length) ? '' : `ngOnChanges(changes${options.typescript ? ': SimpleChanges' : ''}) { if (typeof window !== 'undefined') { ${(_w = json.hooks.onUpdate) === null || _w === void 0 ? void 0 : _w.reduce((code, hook) => { code += hook.code; return code + '\n'; }, '')} } } `} ${!json.hooks.onUnMount && !refsForObjSpread.size ? '' : `ngOnDestroy() { ${((_x = json.hooks.onUnMount) === null || _x === void 0 ? void 0 : _x.code) || ''} ${refsForObjSpread.size ? `for (const fn of this._listenerFns.values()) { fn(); }` : ''} }`} } `; if (options.standalone !== true) { str = (0, helpers_1.generateNgModule)(str, json.name, componentsUsed, json, options.bootstrapMapper); } if (options.plugins) { str = (0, plugins_1.runPreCodePlugins)({ json, code: str, plugins: options.plugins }); } if (options.prettier !== false) { str = (0, format_1.tryFormat)(str, 'typescript'); } if (options.plugins) { str = (0, plugins_1.runPostCodePlugins)({ json, code: str, plugins: options.plugins }); } return str; }; }; exports.componentToAngularClassic = componentToAngularClassic;