@builder.io/mitosis
Version: 
Write components once, run everywhere. Compiles to Vue, React, Solid, and Liquid. Import code from Figma and Builder.io
170 lines (169 loc) • 6.85 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.renderPreComponent = exports.renderImport = exports.transformImportPath = exports.checkIsComponentImport = void 0;
const component_file_extensions_1 = require("./component-file-extensions");
const DEFAULT_IMPORT = 'default';
const STAR_IMPORT = '*';
const getStarImport = ({ theImport }) => {
    for (const key in theImport.imports) {
        const value = theImport.imports[key];
        if (value === STAR_IMPORT) {
            return key;
        }
    }
    return null;
};
const getDefaultImport = ({ theImport }) => {
    for (const key in theImport.imports) {
        const value = theImport.imports[key];
        if (value === DEFAULT_IMPORT) {
            return key;
        }
    }
    return null;
};
const CONTEXT_IMPORTS = ['context.lite', 'context.lite.ts', 'context.lite.js'];
const checkIsContextImport = (theImport) => CONTEXT_IMPORTS.some((contextPath) => theImport.path.endsWith(contextPath));
const checkIsComponentImport = (theImport) => !checkIsContextImport(theImport) &&
    component_file_extensions_1.COMPONENT_IMPORT_EXTENSIONS.some((contextPath) => theImport.path.endsWith(contextPath));
exports.checkIsComponentImport = checkIsComponentImport;
const transformImportPath = ({ theImport, target, preserveFileExtensions, explicitImportFileExtension, }) => {
    // We need to drop the `.lite` from context files, because the context generator does so as well.
    if (checkIsContextImport(theImport)) {
        let path = theImport.path;
        CONTEXT_IMPORTS.forEach((contextPath) => {
            if (path.endsWith(contextPath)) {
                path = path.replace(contextPath, 'context.js');
            }
        });
        return path;
    }
    if (preserveFileExtensions)
        return theImport.path;
    if ((0, exports.checkIsComponentImport)(theImport)) {
        return theImport.path.replace(component_file_extensions_1.INPUT_EXTENSION_REGEX, (0, component_file_extensions_1.getComponentFileExtensionForTarget)({ target, type: 'import', explicitImportFileExtension }));
    }
    return theImport.path;
};
exports.transformImportPath = transformImportPath;
const getNamedImports = ({ theImport }) => {
    const namedImports = Object.entries(theImport.imports)
        .filter(([, value]) => ![DEFAULT_IMPORT, STAR_IMPORT].includes(value))
        .map(([key, value]) => {
        return key !== value ? `${value} as ${key}` : value;
    });
    if (namedImports.length > 0) {
        return `{ ${namedImports.join(', ')} }`;
    }
    else {
        return null;
    }
};
const getImportedValues = ({ theImport }) => {
    const starImport = getStarImport({ theImport });
    const defaultImport = getDefaultImport({ theImport });
    const namedImports = getNamedImports({ theImport });
    return { starImport, defaultImport, namedImports };
};
const getImportValue = ({ defaultImport, namedImports, starImport }) => {
    if (starImport) {
        return ` * as ${starImport} `;
    }
    else {
        return [defaultImport, namedImports].filter(Boolean).join(', ');
    }
};
const renderImport = ({ theImport, target, asyncComponentImports, preserveFileExtensions = false, component = undefined, componentsUsed = [], importMapper, explicitImportFileExtension = false, }) => {
    const importedValues = getImportedValues({ theImport });
    const path = (0, exports.transformImportPath)({
        theImport,
        target,
        preserveFileExtensions,
        explicitImportFileExtension,
    });
    const importValue = getImportValue(importedValues);
    const isComponentImport = (0, exports.checkIsComponentImport)(theImport);
    const shouldBeAsyncImport = asyncComponentImports && isComponentImport;
    const isTypeImport = theImport.importKind === 'type';
    // For lit (components) we just want to do a plain import
    // https://lit.dev/docs/components/rendering/#composing-templates
    if (isComponentImport && target === 'lit') {
        return `import '${path}';`;
    }
    if (shouldBeAsyncImport) {
        const isVueImport = target === 'vue';
        if (isVueImport && importedValues.namedImports) {
            console.warn('Vue: Async Component imports cannot include named imports. Dropping async import. This might break your code.');
        }
        else {
            return `const ${importValue} = () => import('${path}')
      .then(x => x.default)
      .catch(err => {
        console.error('Error while attempting to dynamically import component ${importValue} at ${path}', err);
        throw err;
      });`;
        }
    }
    if (importMapper) {
        const importMapperResult = importMapper(component, theImport, importedValues, componentsUsed);
        // If import mapper has no result we skip this
        if (importMapperResult) {
            return importMapperResult;
        }
    }
    return importValue
        ? `import ${isTypeImport ? 'type' : ''} ${importValue} from '${path}';`
        : `import '${path}';`;
};
exports.renderImport = renderImport;
const renderImports = ({ imports, target, asyncComponentImports, excludeMitosisComponents, preserveFileExtensions = false, component, componentsUsed, importMapper, explicitImportFileExtension, }) => imports
    .filter((theImport) => {
    if (
    // Remove compile away components
    theImport.path === '@builder.io/components' ||
        // TODO: Mitosis output needs this
        theImport.path.startsWith('@builder.io/mitosis')) {
        return false;
    }
    else if (excludeMitosisComponents && theImport.path.includes('.lite')) {
        return false;
    }
    else {
        return true;
    }
})
    .map((theImport) => (0, exports.renderImport)({
    theImport,
    target,
    asyncComponentImports,
    preserveFileExtensions,
    component,
    componentsUsed,
    importMapper,
    explicitImportFileExtension,
}))
    .join('\n');
const renderPreComponent = ({ component, target, excludeMitosisComponents, asyncComponentImports = false, preserveFileExtensions = false, componentsUsed = [], importMapper, explicitImportFileExtension = false, excludeExportAndLocal = false, }) => {
    var _a;
    return `
    ${renderImports({
        imports: component.imports,
        target,
        asyncComponentImports,
        excludeMitosisComponents,
        preserveFileExtensions,
        component,
        componentsUsed,
        importMapper,
        explicitImportFileExtension,
    })}
    ${excludeExportAndLocal ? '' : renderExportAndLocal(component)}
    ${((_a = component.hooks.preComponent) === null || _a === void 0 ? void 0 : _a.code) || ''}
  `;
};
exports.renderPreComponent = renderPreComponent;
const renderExportAndLocal = (component) => {
    return Object.keys(component.exports || {})
        .map((key) => component.exports[key].code)
        .join('\n');
};