diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index f3dfcbe5..efe16477 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -6,4 +6,4 @@ ### Tests -- [ ] Run the tests tests with `npm test` or `yarn test` +- [ ] Run the tests with `npm test` or `yarn test` diff --git a/src/autoProcess.ts b/src/autoProcess.ts index b357ea44..dfbf6656 100644 --- a/src/autoProcess.ts +++ b/src/autoProcess.ts @@ -55,7 +55,7 @@ type AutoPreprocessOptions = { [languageName: string]: TransformerOptions; }; -export const runTransformer = async ( +export const transform = async ( name: string, options: TransformerOptions, { content, map, filename, attributes }: TransformerArgs, @@ -68,6 +68,7 @@ export const runTransformer = async ( return options({ content, map, filename, attributes }); } + // todo: maybe add a try-catch here looking for module-not-found errors const { transformer } = await import(`./transformers/${name}`); return transformer({ @@ -166,7 +167,7 @@ export function sveltePreprocess( return { code: content, dependencies }; } - const transformed = await runTransformer(lang, transformerOptions, { + const transformed = await transform(lang, transformerOptions, { content, filename, attributes, @@ -184,11 +185,10 @@ export function sveltePreprocess( const markup: PreprocessorGroup['markup'] = async ({ content, filename }) => { if (transformers.replace) { - const transformed = await runTransformer( - 'replace', - transformers.replace, - { content, filename }, - ); + const transformed = await transform('replace', transformers.replace, { + content, + filename, + }); content = transformed.code; } @@ -214,7 +214,7 @@ export function sveltePreprocess( let { code, map, dependencies, diagnostics } = transformResult; if (transformers.babel) { - const transformed = await runTransformer( + const transformed = await transform( 'babel', getTransformerOptions('babel'), { @@ -250,7 +250,7 @@ export function sveltePreprocess( // istanbul ignore else if (await hasDepInstalled('postcss')) { if (transformers.postcss) { - const transformed = await runTransformer( + const transformed = await transform( 'postcss', getTransformerOptions('postcss'), { content: code, map, filename, attributes }, @@ -261,7 +261,7 @@ export function sveltePreprocess( dependencies = concat(dependencies, transformed.dependencies); } - const transformed = await runTransformer( + const transformed = await transform( 'globalStyle', getTransformerOptions('globalStyle'), { content: code, map, filename, attributes }, diff --git a/src/modules/language.ts b/src/modules/language.ts index f64f7014..83552068 100644 --- a/src/modules/language.ts +++ b/src/modules/language.ts @@ -1,6 +1,7 @@ import { basename } from 'path'; import { PreprocessorArgs } from '../types'; +import { isValidLocalPath } from './utils'; export const LANG_SPECIFIC_OPTIONS: Record = { sass: { @@ -63,12 +64,10 @@ export const getLanguage = (attributes: PreprocessorArgs['attributes']) => { } alias = attributes.type.replace(/^(text|application)\/(.*)$/, '$2'); - } else if (attributes.src) { - // istanbul ignore if - if (typeof attributes.src !== 'string') { - throw new Error('src attribute must be string'); - } - + } else if ( + typeof attributes.src === 'string' && + isValidLocalPath(attributes.src) + ) { const parts = basename(attributes.src).split('.'); if (parts.length > 1) { diff --git a/src/modules/tagInfo.ts b/src/modules/tagInfo.ts index 2419ff9e..ce9fcb07 100644 --- a/src/modules/tagInfo.ts +++ b/src/modules/tagInfo.ts @@ -3,6 +3,7 @@ import { resolve, dirname } from 'path'; import { PreprocessorArgs } from '../types'; import { getLanguage } from './language'; +import { isValidLocalPath } from './utils'; const resolveSrc = (importerFile: string, srcPath: string) => resolve(dirname(importerFile), srcPath); @@ -40,7 +41,7 @@ export const getTagInfo = async ({ let path = attributes.src; /** Only try to get local files (path starts with ./ or ../) */ - if (path.match(/^(https?:)?\/\//) == null) { + if (isValidLocalPath(path)) { path = resolveSrc(filename, path); if (await doesFileExist(path)) { content = await getSrcContent(path); diff --git a/src/modules/utils.ts b/src/modules/utils.ts index f75f8f3a..0ce0dc9b 100644 --- a/src/modules/utils.ts +++ b/src/modules/utils.ts @@ -56,3 +56,14 @@ export async function hasDepInstalled(dep: string) { return (cachedResult[dep] = result); } + +const REMOTE_SRC_PATTERN = /^(https?:)?\/\//; + +export function isValidLocalPath(path: string) { + return ( + path.match(REMOTE_SRC_PATTERN) == null && + // only literal strings allowed + !path.startsWith('{') && + !path.endsWith('}') + ); +} diff --git a/test/autoProcess/autoProcess.test.ts b/test/autoProcess/autoProcess.test.ts index bad55c30..a35eb373 100644 --- a/test/autoProcess/autoProcess.test.ts +++ b/test/autoProcess/autoProcess.test.ts @@ -18,6 +18,10 @@ describe('detect - mimetype', () => { lang: 'customLanguage', targetLanguage: 'customLanguage', }, + { + src: '{_potato("foo")}', + targetLanguage: null, + }, ]; MIMETYPES.forEach(({ type, lang, src, targetLanguage }) => { diff --git a/test/autoProcess/externalFiles.test.ts b/test/autoProcess/externalFiles.test.ts index 974285bd..c736575d 100644 --- a/test/autoProcess/externalFiles.test.ts +++ b/test/autoProcess/externalFiles.test.ts @@ -8,7 +8,7 @@ import { spyConsole, } from '../utils'; -const { warnSpy } = spyConsole(); +const { warnSpy } = spyConsole({ silent: true }); const { markup: markupProcessor, @@ -23,6 +23,8 @@ const REMOTE_JS = [ ]; describe('external files', () => { + afterEach(warnSpy.mockClear); + it('should insert external file content and add as deps', async () => { const [markup, script, style] = [ await markupProcessor({