Skip to content

Commit 9f2c1e6

Browse files
committed
refactor: 💡 split utils in separate modules
1 parent 29a5bec commit 9f2c1e6

25 files changed

+216
-194
lines changed

‎README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -526,12 +526,14 @@ const options = {
526526
/** Use a custom preprocess method by passing a function. */
527527
pug({ content, filename }) {
528528
const code = pug.render(content);
529+
529530
return { code, map: null };
530531
},
531532
532533
/** Add a custom language preprocessor */
533534
customLanguage({ content, filename }) {
534535
const { code, map } = require('custom-language-compiler')(content);
536+
535537
return { code, map };
536538
},
537539

‎src/autoProcess.ts

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,6 @@
11
import stripIndent from 'strip-indent';
22
import { version } from 'svelte/package.json';
33

4-
import {
5-
concat,
6-
addLanguageAlias,
7-
parseFile,
8-
runTransformer,
9-
isFn,
10-
throwUnsupportedError,
11-
} from './utils';
124
import {
135
PreprocessorGroup,
146
TransformerOptions,
@@ -17,6 +9,11 @@ import {
179
Processed,
1810
} from './types';
1911
import { hasPostCssInstalled } from './modules/hasPostcssInstalled';
12+
import { concat } from './modules/concat';
13+
import { parseFile } from './modules/parseFile';
14+
import { addLanguageAlias } from './modules/language';
15+
import { runTransformer } from './modules/transformers';
16+
import { throwUnsupportedError } from './modules/errors';
2017

2118
interface Transformers {
2219
typescript?: TransformerOptions<Options.Typescript>;
@@ -100,8 +97,8 @@ export function autoPreprocess(
10097
lang: string,
10198
alias: string,
10299
): TransformerOptions<unknown> => {
103-
if (isFn(transformers[alias])) return transformers[alias];
104-
if (isFn(transformers[lang])) return transformers[lang];
100+
if (typeof transformers[alias] === 'function') return transformers[alias];
101+
if (typeof transformers[lang] === 'function') return transformers[lang];
105102
if (optionsCache[alias] != null) return optionsCache[alias];
106103

107104
const opts: TransformerOptions<unknown> = {};
@@ -159,7 +156,7 @@ export function autoPreprocess(
159156

160157
return {
161158
async markup({ content, filename }) {
162-
if (isFn(onBefore)) {
159+
if (typeof onBefore === 'function') {
163160
// istanbul ignore next
164161
if (SVELTE_MAJOR_VERSION >= 3) {
165162
console.warn(

‎src/modules/concat.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
export function concat(...arrs: any[]): any[] {
2+
return arrs.reduce((acc: [], a) => {
3+
if (a) {
4+
return acc.concat(a);
5+
}
6+
return acc;
7+
}, []);
8+
}

‎src/modules/errors.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
export const throwError = (msg: string) => {
2+
throw new Error(`[svelte-preprocess] ${msg}`);
3+
};
4+
5+
export const throwUnsupportedError = (lang: string, filename: string) =>
6+
throwError(`Unsupported script language '${lang}' in file '${filename}'`);

‎src/modules/getIncludePaths.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { dirname } from 'path';
2+
3+
/** Paths used by preprocessors to resolve @imports */
4+
export function getIncludePaths(fromFilename: string, base: string[] = []) {
5+
return [
6+
...new Set([...base, 'node_modules', process.cwd(), dirname(fromFilename)]),
7+
];
8+
}

‎src/modules/importAny.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ export async function importAny(...modules: string[]) {
44
(acc, moduleName) => acc.catch(() => import(moduleName)),
55
Promise.reject(),
66
);
7+
78
return mod;
89
} catch (e) {
910
throw new Error(`Cannot find any of modules: ${modules}`);

‎src/modules/language.ts

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import { basename } from 'path';
2+
3+
import { PreprocessorArgs } from '../types';
4+
5+
export const LANG_DICT = new Map([
6+
['pcss', 'css'],
7+
['postcss', 'css'],
8+
['sass', 'scss'],
9+
['styl', 'stylus'],
10+
['js', 'javascript'],
11+
['coffee', 'coffeescript'],
12+
['ts', 'typescript'],
13+
]);
14+
15+
export const addLanguageAlias = (entries: Array<[string, string]>) =>
16+
entries.forEach((entry) => LANG_DICT.set(...entry));
17+
18+
export const getLanguage = (
19+
attributes: PreprocessorArgs['attributes'],
20+
defaultLang: string,
21+
) => {
22+
let lang = defaultLang;
23+
24+
if (attributes.lang) {
25+
// istanbul ignore if
26+
if (typeof attributes.lang !== 'string') {
27+
throw new Error('lang attribute must be string');
28+
}
29+
lang = attributes.lang;
30+
} else if (attributes.type) {
31+
// istanbul ignore if
32+
if (typeof attributes.type !== 'string') {
33+
throw new Error('type attribute must be string');
34+
}
35+
lang = attributes.type.replace(/^(text|application)\/(.*)$/, '$2');
36+
} else if (attributes.src) {
37+
// istanbul ignore if
38+
if (typeof attributes.src !== 'string') {
39+
throw new Error('src attribute must be string');
40+
}
41+
const parts = basename(attributes.src).split('.');
42+
lang = parts.length > 1 ? parts.pop() : defaultLang;
43+
}
44+
45+
return {
46+
lang: LANG_DICT.get(lang) || lang,
47+
alias: lang,
48+
};
49+
};

‎src/modules/parseFile.ts

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import { readFile, access } from 'fs';
2+
import { resolve, dirname } from 'path';
3+
4+
import { PreprocessorArgs } from '../types';
5+
6+
import { getLanguage } from './language';
7+
8+
export const resolveSrc = (importerFile: string, srcPath: string) =>
9+
resolve(dirname(importerFile), srcPath);
10+
11+
export const getSrcContent = (file: string): Promise<string> => {
12+
return new Promise((resolve, reject) => {
13+
readFile(file, (error: Error, data: unknown) => {
14+
// istanbul ignore if
15+
if (error) reject(error);
16+
else resolve(data.toString());
17+
});
18+
});
19+
};
20+
21+
async function doesFileExist(file: string) {
22+
return new Promise((resolve) => access(file, 0, (err) => resolve(!err)));
23+
}
24+
25+
export const parseFile = async (
26+
{ attributes, filename, content }: PreprocessorArgs,
27+
language: string,
28+
) => {
29+
const dependencies = [];
30+
if (attributes.src) {
31+
// istanbul ignore if
32+
if (typeof attributes.src !== 'string') {
33+
throw new Error('src attribute must be string');
34+
}
35+
let path = attributes.src;
36+
/** Only try to get local files (path starts with ./ or ../) */
37+
if (path.match(/^(https?:)?\/\//) == null) {
38+
path = resolveSrc(filename, path);
39+
if (await doesFileExist(path)) {
40+
content = await getSrcContent(path);
41+
dependencies.push(path);
42+
}
43+
}
44+
}
45+
46+
const { lang, alias } = getLanguage(attributes, language);
47+
48+
return {
49+
filename,
50+
attributes,
51+
content,
52+
lang,
53+
alias,
54+
dependencies,
55+
};
56+
};

‎src/modules/transformers.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import stripIndent from 'strip-indent';
2+
3+
import { Transformer, TransformerArgs, TransformerOptions } from '../types';
4+
5+
import { throwError } from './errors';
6+
7+
const TRANSFORMERS = {} as {
8+
[key: string]: Transformer<any>;
9+
};
10+
11+
export const runTransformer = async (
12+
name: string,
13+
options: TransformerOptions<any>,
14+
{ content, map, filename }: TransformerArgs<any>,
15+
): Promise<ReturnType<Transformer<unknown>>> => {
16+
// remove any unnecessary indentation (useful for coffee, pug and sugarss)
17+
content = stripIndent(content);
18+
19+
if (typeof options === 'function') {
20+
return options({ content, map, filename });
21+
}
22+
23+
try {
24+
if (!TRANSFORMERS[name]) {
25+
await import(`../transformers/${name}`).then((mod) => {
26+
// istanbul ignore else
27+
TRANSFORMERS[name] = mod.default;
28+
});
29+
}
30+
31+
return TRANSFORMERS[name]({
32+
content,
33+
filename,
34+
map,
35+
options: typeof options === 'boolean' ? null : options,
36+
});
37+
} catch (e) {
38+
throwError(
39+
`Error transforming '${name}'.\n\nMessage:\n${e.message}\n\nStack:\n${e.stack}`,
40+
);
41+
}
42+
};

‎src/processors/babel.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
import { concat, parseFile } from '../utils';
21
import { PreprocessorGroup, Options } from '../types';
2+
import { concat } from '../modules/concat';
3+
import { parseFile } from '../modules/parseFile';
34

45
export default (options: Options.Babel): PreprocessorGroup => ({
56
async script(svelteFile) {
@@ -11,6 +12,7 @@ export default (options: Options.Babel): PreprocessorGroup => ({
1112
);
1213

1314
const transformed = await transformer({ content, filename, options });
15+
1416
return {
1517
...transformed,
1618
dependencies: concat(dependencies, transformed.dependencies),

‎src/processors/coffeescript.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { PreprocessorGroup, Options } from '../types';
2-
import { concat, parseFile } from '../utils';
2+
import { parseFile } from '../modules/parseFile';
3+
import { concat } from '../modules/concat';
34

45
export default (options: Options.Coffeescript): PreprocessorGroup => ({
56
async script(svelteFile) {
@@ -15,6 +16,7 @@ export default (options: Options.Coffeescript): PreprocessorGroup => ({
1516
if (lang !== 'coffeescript') return { code: content };
1617

1718
const transformed = await transformer({ content, filename, options });
19+
1820
return {
1921
...transformed,
2022
dependencies: concat(dependencies, transformed.dependencies),

‎src/processors/less.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { PreprocessorGroup, Options } from '../types';
2-
import { concat, parseFile } from '../utils';
2+
import { parseFile } from '../modules/parseFile';
3+
import { concat } from '../modules/concat';
34

45
export default (options: Options.Less): PreprocessorGroup => ({
56
async style(svelteFile) {
@@ -16,6 +17,7 @@ export default (options: Options.Less): PreprocessorGroup => ({
1617
filename,
1718
options,
1819
});
20+
1921
return {
2022
...transformed,
2123
dependencies: concat(dependencies, transformed.dependencies),

‎src/processors/postcss.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
import { concat, parseFile } from '../utils';
1+
import { parseFile } from '../modules/parseFile';
22
import { PreprocessorGroup, Options } from '../types';
3+
import { concat } from '../modules/concat';
34

45
/** Adapted from https://github.com/TehShrike/svelte-preprocess-postcss */
56
export default (options: Options.Postcss): PreprocessorGroup => ({
@@ -12,6 +13,7 @@ export default (options: Options.Postcss): PreprocessorGroup => ({
1213

1314
/** If manually passed a plugins array, use it as the postcss config */
1415
const transformed = await transformer({ content, filename, options });
16+
1517
return {
1618
...transformed,
1719
dependencies: concat(dependencies, transformed.dependencies),

‎src/processors/pug.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { Options, PreprocessorGroup } from '../types';
33
export default (options: Options.Pug): PreprocessorGroup => ({
44
async markup({ content, filename }) {
55
const { default: transformer } = await import('../transformers/pug');
6+
67
return transformer({ content, filename, options });
78
},
89
});

‎src/processors/replace.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { PreprocessorGroup, Options } from '../types';
33
export default (options: Options.Replace): PreprocessorGroup => ({
44
async markup({ content, filename }) {
55
const { default: transformer } = await import('../transformers/replace');
6+
67
return transformer({ content, filename, options });
78
},
89
});

‎src/processors/scss.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
import { concat, parseFile } from '../utils';
1+
import { parseFile } from '../modules/parseFile';
22
import { PreprocessorGroup, Options } from '../types';
3+
import { concat } from '../modules/concat';
34

45
export default (options: Options.Sass): PreprocessorGroup => ({
56
async style(svelteFile) {
@@ -23,6 +24,7 @@ export default (options: Options.Sass): PreprocessorGroup => ({
2324
filename,
2425
options,
2526
});
27+
2628
return {
2729
...transformed,
2830
dependencies: concat(dependencies, transformed.dependencies),

‎src/processors/stylus.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
import { concat, parseFile } from '../utils';
1+
import { parseFile } from '../modules/parseFile';
22
import { Options, PreprocessorGroup } from '../types';
3+
import { concat } from '../modules/concat';
34

45
export default (options: Options.Stylus): PreprocessorGroup => ({
56
async style(svelteFile) {
@@ -11,6 +12,7 @@ export default (options: Options.Stylus): PreprocessorGroup => ({
1112
if (lang !== 'stylus') return { code: content };
1213

1314
const transformed = await transformer({ content, filename, options });
15+
1416
return {
1517
...transformed,
1618
dependencies: concat(dependencies, transformed.dependencies),

‎src/processors/typescript.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { Options, PreprocessorGroup } from '../types';
2-
import { concat, parseFile } from '../utils';
2+
import { parseFile } from '../modules/parseFile';
3+
import { concat } from '../modules/concat';
34

45
export default (options: Options.Typescript): PreprocessorGroup => ({
56
async script(svelteFile) {
@@ -11,6 +12,7 @@ export default (options: Options.Typescript): PreprocessorGroup => ({
1112
if (lang !== 'typescript') return { code: content };
1213

1314
const transformed = await transformer({ content, filename, options });
15+
1416
return {
1517
...transformed,
1618
dependencies: concat(dependencies, transformed.dependencies),

‎src/transformers/less.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import less from 'less';
22

3-
import { getIncludePaths } from '../utils';
3+
import { getIncludePaths } from '../modules/getIncludePaths';
44
import { Transformer, Options } from '../types';
55

66
const transformer: Transformer<Options.Less> = async ({

‎src/transformers/postcss.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ const process = async (
1919
// istanbul ignore if
2020
if (msg.type !== 'dependency') return acc;
2121
acc.push(msg.file);
22+
2223
return acc;
2324
}, []);
2425

‎src/transformers/scss.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { Result } from 'sass';
22

3-
import { getIncludePaths } from '../utils';
43
import { Transformer, Processed, Options } from '../types';
4+
import { getIncludePaths } from '../modules/getIncludePaths';
55
import { importAny } from '../modules/importAny';
66

77
let sass: Options.Sass['implementation'];

0 commit comments

Comments
 (0)