Merge branch 'strict-order'

pull/3349/head
Maxim Matyunin 6 years ago
commit 837c93f16a

@ -203,6 +203,7 @@ result: {
}>, }>,
options?: { options?: {
filename?: string filename?: string
strictOrder?: boolean
} }
) )
``` ```
@ -305,6 +306,30 @@ const { code } = svelte.preprocess(source, [
}); });
``` ```
---
User may override default preprocessor order by passing `strictOrder` option.
```js
const svelte = require('svelte/compiler');
const { code } = svelte.preprocess(source, [
{
style: () => {
console.log('this runs first');
}
},
{
markup: () => {
console.log('this runs second');
}
}
], {
filename: 'App.svelte',
strictOrder: true
});
```
### `svelte.walk` ### `svelte.walk`

@ -26,7 +26,8 @@ const valid_options = [
'css', 'css',
'loopGuardTimeout', 'loopGuardTimeout',
'preserveComments', 'preserveComments',
'preserveWhitespace' 'preserveWhitespace',
'strictOrder'
]; ];
function validate_options(options: CompileOptions, warnings: Warning[]) { function validate_options(options: CompileOptions, warnings: Warning[]) {

@ -67,31 +67,30 @@ async function replace_async(str: string, re: RegExp, func: (...any) => Promise<
return out; return out;
} }
export default async function preprocess( async function process_markup(
source: string, source: string,
preprocessor: PreprocessorGroup | PreprocessorGroup[], func: (...any) => Processed | Promise<Processed>,
options?: { filename?: string } filename: string,
) { ) {
// @ts-ignore todo: doublecheck
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 func({
const processed = await fn({
content: source, content: source,
filename filename
}); });
if (processed && processed.dependencies) dependencies.push(...processed.dependencies);
source = processed ? processed.code : source; return {
source: processed ? processed.code : source,
dependencies: processed.dependencies
};
} }
for (const fn of script) { async function process_script(
source: string,
func: (...any) => Processed | Promise<Processed>,
filename: string,
) {
const dependencies = [];
source = await replace_async( source = await replace_async(
source, source,
/<!--[^]*?-->|<script(\s[^]*?)?>([^]*?)<\/script>/gi, /<!--[^]*?-->|<script(\s[^]*?)?>([^]*?)<\/script>/gi,
@ -100,18 +99,32 @@ export default async function preprocess(
return match; return match;
} }
attributes = attributes || ''; attributes = attributes || '';
const processed = await fn({ const processed: Processed = await func({
content, content,
attributes: parse_attributes(attributes), attributes: parse_attributes(attributes),
filename filename
}); });
if (processed && processed.dependencies) dependencies.push(...processed.dependencies); if (processed && processed.dependencies) {
dependencies.push(...processed.dependencies);
}
return processed ? `<script${attributes}>${processed.code}</script>` : match; return processed ? `<script${attributes}>${processed.code}</script>` : match;
} }
); );
return {
source,
dependencies,
};
} }
for (const fn of style) { async function process_style(
source: string,
func: (...any) => Processed | Promise<Processed>,
filename: string,
) {
const dependencies = [];
source = await replace_async( source = await replace_async(
source, source,
/<!--[^]*?-->|<style(\s[^]*?)?>([^]*?)<\/style>/gi, /<!--[^]*?-->|<style(\s[^]*?)?>([^]*?)<\/style>/gi,
@ -119,17 +132,80 @@ export default async function preprocess(
if (!attributes && !content) { if (!attributes && !content) {
return match; return match;
} }
const processed: Processed = await fn({ const processed: Processed = await func({
content, content,
attributes: parse_attributes(attributes), attributes: parse_attributes(attributes),
filename filename
}); });
if (processed && processed.dependencies) dependencies.push(...processed.dependencies);
if (processed && processed.dependencies) {
dependencies.push(...processed.dependencies);
}
return processed ? `<style${attributes}>${processed.code}</style>` : match; return processed ? `<style${attributes}>${processed.code}</style>` : match;
} }
); );
return {
source,
dependencies,
};
}
async function async_for_each(array, callback) {
for (let index = 0; index < array.length; index++) {
await callback(array[index], index, array);
}
}
export default async function preprocess(
source: string,
preprocessor: PreprocessorGroup | PreprocessorGroup[],
options?: { filename?: string; strictOrder?: boolean }
) {
// @ts-ignore todo: doublecheck
const filename = (options && options.filename) || preprocessor.filename; // legacy
const strictOrder = options && options.strictOrder;
const dependencies = [];
const preprocessors = Array.isArray(preprocessor) ? preprocessor : [preprocessor];
const order = strictOrder
? preprocessors
: [
...preprocessors.map(({ markup }) => ({ markup })),
...preprocessors.map(({ script }) => ({ script })),
...preprocessors.map(({ style }) => ({ style })),
];
await async_for_each(order, async p => {
let processed;
if (p.markup) {
processed = await process_markup(source, p.markup, filename);
source = processed.source;
if (processed.dependencies && processed.dependencies.length) {
dependencies.push(...processed.dependencies);
}
} }
if (p.script) {
processed = await process_script(source, p.script, filename);
source = processed.source;
if (processed.dependencies && processed.dependencies.length) {
dependencies.push(...processed.dependencies);
}
}
if (p.style) {
processed = await process_style(source, p.style, filename);
source = processed.source;
if (processed.dependencies && processed.dependencies.length) {
dependencies.push(...processed.dependencies);
}
}
});
return { return {
// TODO return separated output, in future version where svelte.compile supports it: // TODO return separated output, in future version where svelte.compile supports it:
// style: { code: styleCode, map: styleMap }, // style: { code: styleCode, map: styleMap },

@ -14,10 +14,20 @@ describe('preprocess', () => {
} }
(config.skip ? it.skip : solo ? it.only : it)(dir, async () => { (config.skip ? it.skip : solo ? it.only : it)(dir, async () => {
const input = fs.readFileSync(`${__dirname}/samples/${dir}/input.svelte`, 'utf-8'); const input = fs.readFileSync(
const expected = fs.readFileSync(`${__dirname}/samples/${dir}/output.svelte`, 'utf-8'); `${__dirname}/samples/${dir}/input.svelte`,
'utf-8'
);
const expected = fs.readFileSync(
`${__dirname}/samples/${dir}/output.svelte`,
'utf-8'
);
const result = await svelte.preprocess(input, config.preprocess); const result = await svelte.preprocess(
input,
config.preprocess,
config.options
);
fs.writeFileSync(`${__dirname}/samples/${dir}/_actual.html`, result.code); fs.writeFileSync(`${__dirname}/samples/${dir}/_actual.html`, result.code);
assert.equal(result.code, expected); assert.equal(result.code, expected);

@ -0,0 +1,13 @@
export default {
options: {
strictOrder: false,
},
preprocess: [
{
style: ({ content }) => ({ code: content.replace(/one/g, 'two') }),
},
{
markup: ({ content }) => ({ code: content.replace(/two/g, 'three') }),
},
],
};

@ -0,0 +1,11 @@
<p>one</p>
<style>
.one {
color: red;
}
</style>
<script>
console.log('one');
</script>

@ -0,0 +1,11 @@
<p>one</p>
<style>
.two {
color: red;
}
</style>
<script>
console.log('one');
</script>

@ -0,0 +1,13 @@
export default {
options: {
strictOrder: true,
},
preprocess: [
{
style: ({ content }) => ({ code: content.replace(/one/g, 'two') }),
},
{
markup: ({ content }) => ({ code: content.replace(/two/g, 'three') }),
},
],
};

@ -0,0 +1,11 @@
<p>one</p>
<style>
.one {
color: red;
}
</style>
<script>
console.log('one');
</script>

@ -0,0 +1,11 @@
<p>one</p>
<style>
.three {
color: red;
}
</style>
<script>
console.log('one');
</script>
Loading…
Cancel
Save