diff --git a/src/preprocess/index.ts b/src/preprocess/index.ts index 5537b30ea1..4aaa033270 100644 --- a/src/preprocess/index.ts +++ b/src/preprocess/index.ts @@ -1,25 +1,25 @@ import { SourceMap } from 'magic-string'; import replaceAsync from '../utils/replaceAsync'; -export interface PreprocessOptions { +export interface PreprocessorGroup { markup?: (options: { content: string, filename: string - }) => { code: string, map?: SourceMap | string }; + }) => { code: string, map?: SourceMap | string, dependencies?: string[] }; style?: Preprocessor; script?: Preprocessor; - filename?: string } export type Preprocessor = (options: { content: string, attributes: Record, filename?: string -}) => { code: string, map?: SourceMap | string }; +}) => { code: string, map?: SourceMap | string, dependencies?: string[] }; interface Processed { code: string; map?: SourceMap | string; + dependencies?: string[]; } function parseAttributeValue(value: string) { @@ -39,28 +39,55 @@ function parseAttributes(str: string) { export default async function preprocess( source: string, - options: PreprocessOptions + preprocessor: PreprocessorGroup | PreprocessorGroup[], + options?: { filename?: string } ) { - if (options.markup) { - const processed: Processed = await options.markup({ + const filename = (options && options.filename) || preprocessor.filename; // legacy + const dependencies = []; + + const preprocessors = Array.isArray(preprocessor) ? preprocessor : [preprocessor]; + + const markup = preprocessors.map(p => p.markup).filter(Boolean); + const script = preprocessors.map(p => p.script).filter(Boolean); + const style = preprocessors.map(p => p.style).filter(Boolean); + + for (const fn of markup) { + const processed: Processed = await fn({ content: source, - filename: options.filename, + filename }); + if (processed && processed.dependencies) dependencies.push(...processed.dependencies); source = processed ? processed.code : source; } - if (options.style || options.script) { + + for (const fn of script) { + source = await replaceAsync( + source, + /([^]*?)<\/script>/gi, + async (match, attributes, content) => { + const processed: Processed = await fn({ + content, + attributes: parseAttributes(attributes), + filename + }); + if (processed && processed.dependencies) dependencies.push(...processed.dependencies); + return processed ? `${processed.code}` : match; + } + ); + } + + for (const fn of style) { source = await replaceAsync( source, - /<(script|style)([^]*?)>([^]*?)<\/\1>/gi, - async (match, type, attributes, content) => { - const processed: Processed = - type in options && - (await options[type]({ - content, - attributes: parseAttributes(attributes), - filename: options.filename, - })); - return processed ? `<${type}${attributes}>${processed.code}` : match; + /([^]*?)<\/style>/gi, + async (match, attributes, content) => { + const processed: Processed = await fn({ + content, + attributes: parseAttributes(attributes), + filename + }); + if (processed && processed.dependencies) dependencies.push(...processed.dependencies); + return processed ? `${processed.code}` : match; } ); } @@ -71,6 +98,9 @@ export default async function preprocess( // script { code: scriptCode, map: scriptMap }, // markup { code: markupCode, map: markupMap }, + code: source, + dependencies: [...new Set(dependencies)], + toString() { return source; } diff --git a/test/preprocess/index.js b/test/preprocess/index.js index 9d1e8b01c0..e24c96a0c4 100644 --- a/test/preprocess/index.js +++ b/test/preprocess/index.js @@ -16,10 +16,12 @@ describe.only('preprocess', () => { const input = fs.readFileSync(`test/preprocess/samples/${dir}/input.html`, 'utf-8'); const expected = fs.readFileSync(`test/preprocess/samples/${dir}/output.html`, 'utf-8'); - const actual = await svelte.preprocess(input, config.preprocess); - fs.writeFileSync(`test/preprocess/samples/${dir}/_actual.html`, actual); + const result = await svelte.preprocess(input, config.preprocess); + fs.writeFileSync(`test/preprocess/samples/${dir}/_actual.html`, result.code); - assert.equal(actual, expected); + assert.equal(result.code, expected); + + assert.deepEqual(result.dependencies, config.dependencies || []); }); }); }); diff --git a/test/preprocess/samples/dependencies/_config.js b/test/preprocess/samples/dependencies/_config.js new file mode 100644 index 0000000000..fa2d8b40c9 --- /dev/null +++ b/test/preprocess/samples/dependencies/_config.js @@ -0,0 +1,15 @@ +export default { + preprocess: { + style: ({ content }) => { + const dependencies = []; + const code = content.replace(/@import '(.+)';/g, (match, $1) => { + dependencies.push($1); + return '/* removed */'; + }); + + return { code, dependencies }; + } + }, + + dependencies: ['./foo.css'] +}; \ No newline at end of file diff --git a/test/preprocess/samples/dependencies/input.html b/test/preprocess/samples/dependencies/input.html new file mode 100644 index 0000000000..34a12faff6 --- /dev/null +++ b/test/preprocess/samples/dependencies/input.html @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/test/preprocess/samples/dependencies/output.html b/test/preprocess/samples/dependencies/output.html new file mode 100644 index 0000000000..d80d51a6fc --- /dev/null +++ b/test/preprocess/samples/dependencies/output.html @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/test/preprocess/samples/multiple-preprocessors/_config.js b/test/preprocess/samples/multiple-preprocessors/_config.js new file mode 100644 index 0000000000..8a57567f6b --- /dev/null +++ b/test/preprocess/samples/multiple-preprocessors/_config.js @@ -0,0 +1,14 @@ +export default { + preprocess: [ + { + markup: ({ content }) => ({ code: content.replace(/one/g, 'two') }), + script: ({ content }) => ({ code: content.replace(/three/g, 'four') }), + style: ({ content }) => ({ code: content.replace(/four/g, 'five') }) + }, + { + markup: ({ content }) => ({ code: content.replace(/two/g, 'three') }), + script: ({ content }) => ({ code: content.replace(/four/g, 'five') }), + style: ({ content }) => ({ code: content.replace(/three/g, 'four') }) + } + ] +}; \ No newline at end of file diff --git a/test/preprocess/samples/multiple-preprocessors/input.html b/test/preprocess/samples/multiple-preprocessors/input.html new file mode 100644 index 0000000000..6dbbfb47a9 --- /dev/null +++ b/test/preprocess/samples/multiple-preprocessors/input.html @@ -0,0 +1,11 @@ +

one

+ + + + \ No newline at end of file diff --git a/test/preprocess/samples/multiple-preprocessors/output.html b/test/preprocess/samples/multiple-preprocessors/output.html new file mode 100644 index 0000000000..dd6f3e9de8 --- /dev/null +++ b/test/preprocess/samples/multiple-preprocessors/output.html @@ -0,0 +1,11 @@ +

three

+ + + + \ No newline at end of file