1
1
import stripIndent from 'strip-indent' ;
2
- import { version } from 'svelte/package.json' ;
3
2
4
- import {
3
+ import { PreprocessorArgs , Transformer } from './types/index' ;
4
+ import type {
5
+ Transformers ,
5
6
PreprocessorGroup ,
6
- TransformerOptions ,
7
- Preprocessor ,
8
- Options ,
9
7
Processed ,
8
+ AutoPreprocessOptions ,
9
+ TransformerArgs ,
10
+ TransformerOptions ,
10
11
} from './types' ;
11
12
import { hasPostCssInstalled } from './modules/hasPostcssInstalled' ;
12
13
import { concat } from './modules/concat' ;
13
14
import { parseFile } from './modules/parseFile' ;
14
15
import { addLanguageAlias } from './modules/language' ;
15
- import { runTransformer } from './modules/transformers' ;
16
- import { throwUnsupportedError } from './modules/errors' ;
17
-
18
- interface Transformers {
19
- typescript ?: TransformerOptions < Options . Typescript > ;
20
- scss ?: TransformerOptions < Options . Sass > ;
21
- sass ?: TransformerOptions < Options . Sass > ;
22
- less ?: TransformerOptions < Options . Less > ;
23
- stylus ?: TransformerOptions < Options . Stylus > ;
24
- postcss ?: TransformerOptions < Options . Postcss > ;
25
- coffeescript ?: TransformerOptions < Options . Coffeescript > ;
26
- pug ?: TransformerOptions < Options . Pug > ;
27
- globalStyle ?: Options . GlobalStyle ;
28
- replace ?: Options . Replace ;
29
- [ languageName : string ] : TransformerOptions ;
30
- }
31
-
32
- type AutoPreprocessOptions = {
33
- /** @deprecated for svelte v3 use instead a array of processors */
34
- onBefore ?: ( {
35
- content,
36
- filename,
37
- } : {
38
- content : string ;
39
- filename : string ;
40
- } ) => Promise < string > | string ;
41
- markupTagName ?: string ;
42
- /** @deprecated add transformer config directly to svelte-preprocess options object */
43
- transformers ?: Transformers ;
44
- aliases ?: Array < [ string , string ] > ;
45
- preserve ?: string [ ] ;
46
- typescript ?: TransformerOptions < Options . Typescript > ;
47
- scss ?: TransformerOptions < Options . Sass > ;
48
- sass ?: TransformerOptions < Options . Sass > ;
49
- less ?: TransformerOptions < Options . Less > ;
50
- stylus ?: TransformerOptions < Options . Stylus > ;
51
- postcss ?: TransformerOptions < Options . Postcss > ;
52
- babel ?: TransformerOptions < Options . Babel > ;
53
- coffeescript ?: TransformerOptions < Options . Coffeescript > ;
54
- pug ?: TransformerOptions < Options . Pug > ;
55
- globalStyle ?: Options . GlobalStyle ;
56
- // workaround while we don't have this
57
- // https://github.com/microsoft/TypeScript/issues/17867
58
- [ languageName : string ] :
59
- | string
60
- | Promise < string >
61
- | Array < [ string , string ] >
62
- | string [ ]
63
- | TransformerOptions ;
64
- } ;
16
+ import { parseAttrs } from './modules/parseAttrs' ;
17
+ import { throwError } from './modules/errors' ;
65
18
66
- const SVELTE_MAJOR_VERSION = + version [ 0 ] ;
67
19
const ALIAS_OPTION_OVERRIDES : Record < string , any > = {
68
20
sass : {
69
21
indentedSyntax : true ,
70
22
} ,
71
23
} ;
72
24
73
- export function autoPreprocess (
74
- {
75
- onBefore,
76
- aliases,
77
- markupTagName = 'template' ,
78
- preserve = [ ] ,
79
- ...rest
80
- } : AutoPreprocessOptions = { } as AutoPreprocessOptions ,
81
- ) : PreprocessorGroup {
82
- markupTagName = markupTagName . toLocaleLowerCase ( ) ;
25
+ async function runTransformer (
26
+ name : string ,
27
+ options : TransformerOptions ,
28
+ { content, map, filename, attributes } : TransformerArgs < any > ,
29
+ ) : Promise < Processed > {
30
+ // remove any unnecessary indentation (useful for coffee, pug and sugarss)
31
+ content = stripIndent ( content ) ;
83
32
84
- const optionsCache : Record < string , any > = { } ;
85
- const transformers = rest . transformers || ( rest as Transformers ) ;
86
- const markupPattern = new RegExp (
87
- `<${ markupTagName } ([\\s\\S]*?)(?:>([\\s\\S]*)<\\/${ markupTagName } >|/>)` ,
88
- ) ;
33
+ try {
34
+ const { default : transformer } = await import ( `./transformers/${ name } ` ) ;
89
35
90
- if ( aliases ?. length ) {
91
- addLanguageAlias ( aliases ) ;
36
+ return transformer ( {
37
+ content,
38
+ filename,
39
+ map,
40
+ attributes,
41
+ options : typeof options === 'boolean' ? null : options ,
42
+ } ) ;
43
+ } catch ( e ) {
44
+ throwError (
45
+ `Error transforming '${ name } '.\n\nMessage:\n${ e . message } \n\nStack:\n${ e . stack } ` ,
46
+ ) ;
92
47
}
48
+ }
93
49
94
- const getTransformerOptions = (
95
- lang : string ,
96
- alias : string ,
97
- ) : TransformerOptions < unknown > => {
98
- if ( typeof transformers [ alias ] === 'function' ) return transformers [ alias ] ;
99
- if ( typeof transformers [ lang ] === 'function' ) return transformers [ lang ] ;
100
- if ( optionsCache [ alias ] != null ) return optionsCache [ alias ] ;
101
-
102
- const opts : TransformerOptions < unknown > = { } ;
103
-
104
- if ( typeof transformers [ lang ] === 'object' ) {
105
- Object . assign ( opts , transformers [ lang ] ) ;
106
- }
107
-
108
- if ( lang !== alias ) {
109
- Object . assign ( opts , ALIAS_OPTION_OVERRIDES [ alias ] || null ) ;
50
+ async function autoTransform ( {
51
+ target : targetLanguage ,
52
+ transformers,
53
+ preserve,
54
+ args : processorArgs ,
55
+ } : {
56
+ target : string ;
57
+ transformers : Transformers ;
58
+ preserve : string [ ] ;
59
+ args ?: PreprocessorArgs ;
60
+ } ) : Promise < Processed > {
61
+ const {
62
+ content,
63
+ filename,
64
+ lang,
65
+ alias,
66
+ dependencies,
67
+ attributes,
68
+ } = await parseFile ( processorArgs , targetLanguage ) ;
69
+
70
+ if ( preserve . includes ( lang ) || preserve . includes ( alias ) ) {
71
+ return { code : content } ;
72
+ }
110
73
111
- if ( typeof transformers [ alias ] === 'object' ) {
112
- Object . assign ( opts , transformers [ alias ] ) ;
113
- }
114
- }
74
+ if ( lang === targetLanguage ) {
75
+ return { code : content , dependencies } ;
76
+ }
115
77
116
- return ( optionsCache [ alias ] = opts ) ;
78
+ const transformerArgs = {
79
+ content : stripIndent ( content ) ,
80
+ filename,
81
+ attributes,
117
82
} ;
118
83
119
- const getTransformerTo = ( targetLanguage : string ) : Preprocessor => async (
120
- svelteFile ,
121
- ) => {
122
- const {
123
- content,
124
- filename,
125
- lang,
126
- alias,
127
- dependencies,
128
- attributes,
129
- } = await parseFile ( svelteFile , targetLanguage ) ;
130
-
131
- if ( preserve . includes ( lang ) || preserve . includes ( alias ) ) {
132
- return ;
133
- }
84
+ const { [ lang ] : langTransformer , [ alias ] : aliasTransformer } = transformers ;
134
85
135
- if ( lang === targetLanguage ) {
136
- return { code : content , dependencies } ;
137
- }
86
+ if ( typeof aliasTransformer === 'function' ) {
87
+ return aliasTransformer ( transformerArgs ) ;
88
+ }
138
89
139
- if ( transformers [ lang ] === false || transformers [ alias ] === false ) {
140
- throwUnsupportedError ( alias , filename ) ;
141
- }
90
+ if ( typeof langTransformer === 'function' ) {
91
+ return langTransformer ( transformerArgs ) ;
92
+ }
142
93
143
- const transformed = await runTransformer (
144
- lang ,
145
- getTransformerOptions ( lang , alias ) ,
146
- { content : stripIndent ( content ) , filename, attributes } ,
147
- ) ;
94
+ const transformed = await runTransformer (
95
+ lang ,
96
+ {
97
+ ...( langTransformer as object ) ,
98
+ ...ALIAS_OPTION_OVERRIDES [ alias ] ,
99
+ ...( aliasTransformer as object ) ,
100
+ } ,
101
+ transformerArgs ,
102
+ ) ;
148
103
149
- return {
150
- ...transformed ,
151
- dependencies : concat ( dependencies , transformed . dependencies ) ,
152
- } ;
104
+ return {
105
+ ...transformed ,
106
+ dependencies : concat ( dependencies , transformed . dependencies ) ,
153
107
} ;
108
+ }
109
+
110
+ export function autoPreprocess ( {
111
+ aliases,
112
+ markupTagName = 'template' ,
113
+ preserve = [ ] ,
114
+ ...rest
115
+ } : AutoPreprocessOptions = { } ) : PreprocessorGroup {
116
+ markupTagName = markupTagName . toLocaleLowerCase ( ) ;
117
+
118
+ const transformers = rest as Transformers ;
119
+ const markupPattern = new RegExp (
120
+ `<${ markupTagName } ([\\s\\S]*?)(?:>([\\s\\S]*)<\\/${ markupTagName } >|/>)` ,
121
+ ) ;
154
122
155
- const scriptTransformer = getTransformerTo ( 'javascript' ) ;
156
- const cssTransformer = getTransformerTo ( 'css' ) ;
157
- const markupTransformer = getTransformerTo ( 'html' ) ;
123
+ if ( aliases ?. length ) {
124
+ addLanguageAlias ( aliases ) ;
125
+ }
158
126
159
127
return {
160
128
async markup ( { content, filename } ) {
161
- if ( typeof onBefore === 'function' ) {
162
- // istanbul ignore next
163
- if ( SVELTE_MAJOR_VERSION >= 3 ) {
164
- console . warn (
165
- '[svelte-preprocess] For svelte >= v3, instead of onBefore(), prefer to prepend a preprocess object to your array of preprocessors' ,
166
- ) ;
167
- }
168
- content = await onBefore ( { content, filename } ) ;
169
- }
170
-
171
129
if ( transformers . replace ) {
172
130
const transformed = await runTransformer (
173
131
'replace' ,
@@ -188,23 +146,18 @@ export function autoPreprocess(
188
146
const [ fullMatch , attributesStr , templateCode ] = templateMatch ;
189
147
190
148
/** Transform an attribute string into a key-value object */
191
- const attributes = attributesStr
192
- . split ( / \s + / )
193
- . filter ( Boolean )
194
- . reduce ( ( acc : Record < string , string | boolean > , attr ) => {
195
- const [ name , value ] = attr . split ( '=' ) ;
196
-
197
- // istanbul ignore next
198
- acc [ name ] = value ? value . replace ( / [ ' " ] / g, '' ) : true ;
199
-
200
- return acc ;
201
- } , { } ) ;
149
+ const attributes = parseAttrs ( attributesStr ) ;
202
150
203
151
/** Transform the found template code */
204
- let { code, map, dependencies } = await markupTransformer ( {
205
- content : templateCode ,
206
- attributes,
207
- filename,
152
+ let { code, map, dependencies } = await autoTransform ( {
153
+ target : 'html' ,
154
+ transformers,
155
+ preserve,
156
+ args : {
157
+ content : templateCode ,
158
+ attributes,
159
+ filename,
160
+ } ,
208
161
} ) ;
209
162
210
163
code =
@@ -215,14 +168,13 @@ export function autoPreprocess(
215
168
return { code, map, dependencies } ;
216
169
} ,
217
170
async script ( { content, attributes, filename } ) {
218
- const transformResult : Processed = await scriptTransformer ( {
219
- content,
220
- attributes,
221
- filename,
171
+ const transformResult : Processed = await autoTransform ( {
172
+ target : 'javascript' ,
173
+ transformers,
174
+ preserve,
175
+ args : { content, attributes, filename } ,
222
176
} ) ;
223
177
224
- if ( transformResult == null ) return ;
225
-
226
178
let { code, map, dependencies, diagnostics } = transformResult ;
227
179
228
180
if ( transformers . babel ) {
@@ -242,42 +194,37 @@ export function autoPreprocess(
242
194
return { code, map, dependencies, diagnostics } ;
243
195
} ,
244
196
async style ( { content, attributes, filename } ) {
245
- const transformResult = await cssTransformer ( {
246
- content,
247
- attributes,
248
- filename,
197
+ const transformResult = await autoTransform ( {
198
+ target : 'css' ,
199
+ transformers,
200
+ preserve,
201
+ args : { content, attributes, filename } ,
249
202
} ) ;
250
203
251
- if ( transformResult == null ) return ;
252
-
253
204
let { code, map, dependencies } = transformResult ;
254
205
255
- if ( transformers . postcss ) {
256
- const transformed = await runTransformer (
257
- 'postcss' ,
258
- transformers . postcss ,
259
- { content : code , map, filename, attributes } ,
260
- ) ;
261
-
262
- code = transformed . code ;
263
- map = transformed . map ;
264
- dependencies = concat ( dependencies , transformed . dependencies ) ;
265
- }
266
-
267
206
if ( await hasPostCssInstalled ( ) ) {
268
- const transformed = await runTransformer (
269
- 'globalStyle' ,
270
- transformers ?. globalStyle ,
271
- {
272
- content : code ,
273
- map,
274
- filename,
275
- attributes,
276
- } ,
277
- ) ;
207
+ {
208
+ const transformed = await runTransformer (
209
+ 'postcss' ,
210
+ transformers ?. postcss ,
211
+ { content : code , map, filename, attributes } ,
212
+ ) ;
278
213
279
- code = transformed . code ;
280
- map = transformed . map ;
214
+ code = transformed . code ;
215
+ map = transformed . map ;
216
+ dependencies = concat ( dependencies , transformed . dependencies ) ;
217
+ }
218
+ {
219
+ const transformed = await runTransformer (
220
+ 'globalStyle' ,
221
+ transformers ?. globalStyle ,
222
+ { content : code , map, filename, attributes } ,
223
+ ) ;
224
+
225
+ code = transformed . code ;
226
+ map = transformed . map ;
227
+ }
281
228
}
282
229
283
230
return { code, map, dependencies } ;
0 commit comments