diff --git a/src/autoProcess.ts b/src/autoProcess.ts index 20400cad..25e57e82 100644 --- a/src/autoProcess.ts +++ b/src/autoProcess.ts @@ -1,14 +1,15 @@ +/* eslint-disable @typescript-eslint/naming-convention */ +import { PreprocessorOptions } from 'svelte/types/compiler/preprocess'; + import { PreprocessorGroup, - Preprocessor, - Processed, TransformerArgs, TransformerOptions, Transformers, Options, } from './types'; import { hasDepInstalled, concat } from './modules/utils'; -import { getTagInfo } from './modules/tagInfo'; +import { getTagInfoSync } from './modules/tagInfo'; import { addLanguageAlias, getLanguageFromAlias, @@ -18,6 +19,7 @@ import { } from './modules/language'; import { prepareContent } from './modules/prepareContent'; import { transformMarkup } from './modules/markup'; +import { default as pipe, EventuallyProcessed } from './pipe'; type AutoPreprocessGroup = PreprocessorGroup & { defaultLanguages: Readonly<{ @@ -56,13 +58,16 @@ type AutoPreprocessOptions = { [languageName: string]: TransformerOptions; }; -export const transform = async ( +export function transform( name: string, options: TransformerOptions, { content, map, filename, attributes }: TransformerArgs, -): Promise => { + sync: Sync, +): EventuallyProcessed { if (options === false) { - return { code: content }; + const res = { code: content }; + + return (sync ? res : Promise.resolve(res)) as any; } if (typeof options === 'function') { @@ -70,7 +75,17 @@ export const transform = async ( } // todo: maybe add a try-catch here looking for module-not-found errors - const { transformer } = await import(`./transformers/${name}`); + const { transformer, is_sync } = require(`./transformers/${name}`); + + if (sync && !is_sync) { + console.error(`Transfomer ${name} does not support sync calls.`) + + return { + code: content, + map, + dependencies: [], + } as EventuallyProcessed; + } return transformer({ content, @@ -79,7 +94,7 @@ export const transform = async ( attributes, options: typeof options === 'boolean' ? null : options, }); -}; +} export function sveltePreprocess( { @@ -135,10 +150,11 @@ export function sveltePreprocess( return opts; }; - const getTransformerTo = ( + const getTransformerTo = ( type: 'markup' | 'script' | 'style', targetLanguage: string, - ): Preprocessor => async (svelteFile) => { + sync: Sync, + ) => (svelteFile): EventuallyProcessed => { let { content, filename, @@ -146,7 +162,7 @@ export function sveltePreprocess( alias, dependencies, attributes, - } = await getTagInfo(svelteFile); + } = getTagInfoSync(svelteFile); if (lang == null || alias == null) { alias = defaultLanguages[type]; @@ -154,7 +170,7 @@ export function sveltePreprocess( } if (preserve.includes(lang) || preserve.includes(alias)) { - return { code: content }; + return { code: content } as EventuallyProcessed; } const transformerOptions = getTransformerOptions(lang, alias); @@ -165,122 +181,216 @@ export function sveltePreprocess( }); if (lang === targetLanguage) { - return { code: content, dependencies }; + return { code: content, dependencies } as EventuallyProcessed; } - const transformed = await transform(lang, transformerOptions, { - content, - filename, - attributes, - }); - - return { - ...transformed, - dependencies: concat(dependencies, transformed.dependencies), - }; + return pipe( + sync, + () => + transform( + lang, + transformerOptions, + { + content, + filename, + attributes, + }, + sync, + ), + (processed) => + ({ + ...processed, + dependencies: concat(dependencies, processed.dependencies), + } as EventuallyProcessed), + ); }; - const scriptTransformer = getTransformerTo('script', 'javascript'); - const cssTransformer = getTransformerTo('style', 'css'); - const markupTransformer = getTransformerTo('markup', 'html'); - - const markup: PreprocessorGroup['markup'] = async ({ content, filename }) => { - if (transformers.replace) { - const transformed = await transform('replace', transformers.replace, { - content, - filename, - }); - - content = transformed.code; - } - - return transformMarkup({ content, filename }, markupTransformer, { - // we only pass the markupTagName because the rest of options - // is fetched internally by the `markupTransformer` - markupTagName, - }); - }; - - const script: PreprocessorGroup['script'] = async ({ - content, - attributes, - filename, - }) => { - const transformResult: Processed = await scriptTransformer({ - content, - attributes, - filename, - }); - - let { code, map, dependencies, diagnostics } = transformResult; - - if (transformers.babel) { - const transformed = await transform( - 'babel', - getTransformerOptions('babel'), - { - content: code, - map, - filename, - attributes, + const markupTransformer = getTransformerTo('markup', 'html', false); + + function buildMarkupProcessor( + sync: Sync, + ): (options: PreprocessorOptions) => EventuallyProcessed { + return ({ content, filename }) => { + return pipe( + sync, + () => { + if (transformers.replace) { + return transform( + 'replace', + transformers.replace, + { + content, + filename, + }, + sync, + ); + } + + return { code: content } as EventuallyProcessed; }, + ({ code }) => + transformMarkup( + sync, + { content: code, filename }, + markupTransformer, + { + // we only pass the markupTagName because the rest of options + // is fetched internally by the `markupTransformer` + markupTagName, + }, + ), ); + }; + } - code = transformed.code; - map = transformed.map; - dependencies = concat(dependencies, transformed.dependencies); - diagnostics = concat(diagnostics, transformed.diagnostics); - } - - return { code, map, dependencies, diagnostics }; - }; - - const style: PreprocessorGroup['style'] = async ({ - content, - attributes, - filename, - }) => { - const transformResult = await cssTransformer({ - content, - attributes, - filename, - }); - - let { code, map, dependencies } = transformResult; - - // istanbul ignore else - if (await hasDepInstalled('postcss')) { - if (transformers.postcss) { - const { alias } = getLanguage(attributes); - - const transformed = await transform( - 'postcss', - getTransformerOptions('postcss', alias), - { content: code, map, filename, attributes }, - ); - - code = transformed.code; - map = transformed.map; - dependencies = concat(dependencies, transformed.dependencies); - } + function buildScriptProcessor( + sync: Sync, + ): (options: PreprocessorOptions) => EventuallyProcessed { + return ({ content, attributes, filename }) => + pipe( + sync, + () => + getTransformerTo( + 'script', + 'javascript', + sync, + )({ + content, + attributes, + filename, + }), + ({ code, map, dependencies, diagnostics }) => { + if (transformers.babel) { + return pipe( + sync, + () => + transform( + 'babel', + getTransformerOptions('babel'), + { + content: code, + map, + filename, + attributes, + }, + sync, + ), + (transformed) => { + code = transformed.code; + map = transformed.map; + dependencies = concat(dependencies, transformed.dependencies); + diagnostics = concat(diagnostics, transformed.diagnostics); + + return { + code, + map, + dependencies, + diagnostics, + } as EventuallyProcessed; + }, + ); + } + + return { + code, + map, + dependencies, + diagnostics, + } as EventuallyProcessed; + }, + ); + } - const transformed = await transform( - 'globalStyle', - getTransformerOptions('globalStyle'), - { content: code, map, filename, attributes }, + function buildStyleProcessor( + sync: Sync, + ): (options: PreprocessorOptions) => EventuallyProcessed { + return ({ content, attributes, filename }) => { + const hasPostCss = hasDepInstalled('postcss'); + + return pipe( + sync, + () => + getTransformerTo( + 'style', + 'css', + sync, + )({ + content, + attributes, + filename, + }), + ({ code, map, dependencies }) => { + if (hasPostCss && transformers.postcss) { + const { alias } = getLanguage(attributes); + + return pipe( + sync, + () => + transform( + 'postcss', + getTransformerOptions('postcss', alias), + { content: code, map, filename, attributes }, + sync, + ), + (t) => + ({ + code: t.code, + map: t.map, + dependencies: concat(dependencies, t.dependencies), + } as EventuallyProcessed), + ); + } + + return { code, map, dependencies } as EventuallyProcessed; + }, + ({ code, map, dependencies }) => { + if (hasPostCss) { + return pipe( + sync, + () => + transform( + 'globalStyle', + getTransformerOptions('globalStyle'), + { content: code, map, filename, attributes }, + sync, + ), + (t) => + ({ + code: t.code, + map: t.map, + dependencies, + } as EventuallyProcessed), + ); + } + + return { code, map, dependencies } as EventuallyProcessed; + }, ); + }; + } - code = transformed.code; - map = transformed.map; - } + const markup: PreprocessorGroup['markup'] = buildMarkupProcessor(false); + const markup_sync: PreprocessorGroup['markup_sync'] = buildMarkupProcessor< + true + >(true); - return { code, map, dependencies }; - }; + const script: PreprocessorGroup['script'] = buildScriptProcessor(false); + const script_sync: PreprocessorGroup['script_sync'] = buildScriptProcessor< + true + >(true); + + const style: PreprocessorGroup['style'] = buildStyleProcessor(false); + const style_sync: PreprocessorGroup['style_sync'] = buildStyleProcessor( + true, + ); return { defaultLanguages, markup, + markup_sync, script, + script_sync, style, + style_sync, }; } diff --git a/src/modules/markup.ts b/src/modules/markup.ts index 2ffa2c41..87805b11 100644 --- a/src/modules/markup.ts +++ b/src/modules/markup.ts @@ -1,10 +1,12 @@ +import pipe, { EventuallyProcessed } from '../pipe'; import { Transformer, Preprocessor } from '../types'; -export async function transformMarkup( +export function transformMarkup( + sync: S, { content, filename }: { content: string; filename: string }, transformer: Preprocessor | Transformer, options: Record = {}, -) { +): EventuallyProcessed { let { markupTagName = 'template' } = options; markupTagName = markupTagName.toLocaleLowerCase(); @@ -17,7 +19,12 @@ export async function transformMarkup( /** If no