@@ -43,14 +43,20 @@ export const taskGenerate = async (config: ValidatedConfig): Promise<void> => {
43
43
config . logger . error ( tagError ) ;
44
44
return config . sys . exit ( 1 ) ;
45
45
}
46
- const filesToGenerateExt = await chooseFilesToGenerate ( ) ;
47
- if ( undefined === filesToGenerateExt ) {
46
+
47
+ let cssExtension : GeneratableStylingExtension = 'css' ;
48
+ if ( ! ! config . plugins . find ( ( plugin ) => plugin . name === 'sass' ) ) {
49
+ cssExtension = await chooseSassExtension ( ) ;
50
+ } else if ( ! ! config . plugins . find ( ( plugin ) => plugin . name === 'less' ) ) {
51
+ cssExtension = 'less' ;
52
+ }
53
+ const filesToGenerateExt = await chooseFilesToGenerate ( cssExtension ) ;
54
+ if ( ! filesToGenerateExt ) {
48
55
// in some shells (e.g. Windows PowerShell), hitting Ctrl+C results in a TypeError printed to the console.
49
56
// explicitly return here to avoid printing the error message.
50
57
return ;
51
58
}
52
- const extensionsToGenerate : GenerableExtension [ ] = [ 'tsx' , ...filesToGenerateExt ] ;
53
-
59
+ const extensionsToGenerate : GeneratableExtension [ ] = [ 'tsx' , ...filesToGenerateExt ] ;
54
60
const testFolder = extensionsToGenerate . some ( isTest ) ? 'test' : '' ;
55
61
56
62
const outDir = join ( absoluteSrcDir , 'components' , dir , componentName ) ;
@@ -64,7 +70,16 @@ export const taskGenerate = async (config: ValidatedConfig): Promise<void> => {
64
70
65
71
const writtenFiles = await Promise . all (
66
72
filesToGenerate . map ( ( file ) =>
67
- getBoilerplateAndWriteFile ( config , componentName , extensionsToGenerate . includes ( 'css' ) , file ) ,
73
+ getBoilerplateAndWriteFile (
74
+ config ,
75
+ componentName ,
76
+ extensionsToGenerate . includes ( 'css' ) ||
77
+ extensionsToGenerate . includes ( 'sass' ) ||
78
+ extensionsToGenerate . includes ( 'scss' ) ||
79
+ extensionsToGenerate . includes ( 'less' ) ,
80
+ file ,
81
+ cssExtension ,
82
+ ) ,
68
83
) ,
69
84
) . catch ( ( error ) => config . logger . error ( error ) ) ;
70
85
@@ -88,25 +103,42 @@ export const taskGenerate = async (config: ValidatedConfig): Promise<void> => {
88
103
/**
89
104
* Show a checkbox prompt to select the files to be generated.
90
105
*
91
- * @returns a read-only array of `GenerableExtension`, the extensions that the user has decided
106
+ * @param cssExtension the extension of the CSS file to be generated
107
+ * @returns a read-only array of `GeneratableExtension`, the extensions that the user has decided
92
108
* to generate
93
109
*/
94
- const chooseFilesToGenerate = async ( ) : Promise < ReadonlyArray < GenerableExtension > > => {
110
+ const chooseFilesToGenerate = async ( cssExtension : string ) : Promise < ReadonlyArray < GeneratableExtension > > => {
95
111
const { prompt } = await import ( 'prompts' ) ;
96
112
return (
97
113
await prompt ( {
98
114
name : 'filesToGenerate' ,
99
115
type : 'multiselect' ,
100
116
message : 'Which additional files do you want to generate?' ,
101
117
choices : [
102
- { value : 'css' , title : ' Stylesheet (.css)' , selected : true } ,
118
+ { value : cssExtension , title : ` Stylesheet (.${ cssExtension } )` , selected : true } ,
103
119
{ value : 'spec.tsx' , title : 'Spec Test (.spec.tsx)' , selected : true } ,
104
120
{ value : 'e2e.ts' , title : 'E2E Test (.e2e.ts)' , selected : true } ,
105
121
] ,
106
122
} )
107
123
) . filesToGenerate ;
108
124
} ;
109
125
126
+ const chooseSassExtension = async ( ) => {
127
+ const { prompt } = await import ( 'prompts' ) ;
128
+ return (
129
+ await prompt ( {
130
+ name : 'sassFormat' ,
131
+ type : 'select' ,
132
+ message :
133
+ 'Which Sass format would you like to use? (More info: https://sass-lang.com/documentation/syntax/#the-indented-syntax)' ,
134
+ choices : [
135
+ { value : 'sass' , title : `*.sass Format` , selected : true } ,
136
+ { value : 'scss' , title : '*.scss Format' } ,
137
+ ] ,
138
+ } )
139
+ ) . sassFormat ;
140
+ } ;
141
+
110
142
/**
111
143
* Get a filepath for a file we want to generate!
112
144
*
@@ -119,7 +151,7 @@ const chooseFilesToGenerate = async (): Promise<ReadonlyArray<GenerableExtension
119
151
* @returns the full filepath to the component (with a possible `test` directory
120
152
* added)
121
153
*/
122
- const getFilepathForFile = ( filePath : string , componentName : string , extension : GenerableExtension ) : string =>
154
+ const getFilepathForFile = ( filePath : string , componentName : string , extension : GeneratableExtension ) : string =>
123
155
isTest ( extension )
124
156
? normalizePath ( join ( filePath , 'test' , `${ componentName } .${ extension } ` ) )
125
157
: normalizePath ( join ( filePath , `${ componentName } .${ extension } ` ) ) ;
@@ -131,6 +163,7 @@ const getFilepathForFile = (filePath: string, componentName: string, extension:
131
163
* @param componentName the component name (user-supplied)
132
164
* @param withCss are we generating CSS?
133
165
* @param file the file we want to write
166
+ * @param styleExtension extension used for styles
134
167
* @returns a `Promise<string>` which holds the full filepath we've written to,
135
168
* used to print out a little summary of our activity to the user.
136
169
*/
@@ -139,8 +172,9 @@ const getBoilerplateAndWriteFile = async (
139
172
componentName : string ,
140
173
withCss : boolean ,
141
174
file : BoilerplateFile ,
175
+ styleExtension : GeneratableStylingExtension ,
142
176
) : Promise < string > => {
143
- const boilerplate = getBoilerplateByExtension ( componentName , file . extension , withCss ) ;
177
+ const boilerplate = getBoilerplateByExtension ( componentName , file . extension , withCss , styleExtension ) ;
144
178
await config . sys . writeFile ( normalizePath ( file . path ) , boilerplate ) ;
145
179
return file . path ;
146
180
} ;
@@ -183,7 +217,7 @@ const checkForOverwrite = async (files: readonly BoilerplateFile[], config: Vali
183
217
* @param extension the extension we want to check
184
218
* @returns a boolean indicating whether or not its a test
185
219
*/
186
- const isTest = ( extension : GenerableExtension ) : boolean => {
220
+ const isTest = ( extension : GeneratableExtension ) : boolean => {
187
221
return extension === 'e2e.ts' || extension === 'spec.tsx' ;
188
222
} ;
189
223
@@ -193,15 +227,24 @@ const isTest = (extension: GenerableExtension): boolean => {
193
227
* @param tagName the name of the component we're generating
194
228
* @param extension the file extension we want boilerplate for (.css, tsx, etc)
195
229
* @param withCss a boolean indicating whether we're generating a CSS file
230
+ * @param styleExtension extension used for styles
196
231
* @returns a string container the file boilerplate for the supplied extension
197
232
*/
198
- export const getBoilerplateByExtension = ( tagName : string , extension : GenerableExtension , withCss : boolean ) : string => {
233
+ export const getBoilerplateByExtension = (
234
+ tagName : string ,
235
+ extension : GeneratableExtension ,
236
+ withCss : boolean ,
237
+ styleExtension : GeneratableStylingExtension ,
238
+ ) : string => {
199
239
switch ( extension ) {
200
240
case 'tsx' :
201
- return getComponentBoilerplate ( tagName , withCss ) ;
241
+ return getComponentBoilerplate ( tagName , withCss , styleExtension ) ;
202
242
203
243
case 'css' :
204
- return getStyleUrlBoilerplate ( ) ;
244
+ case 'less' :
245
+ case 'sass' :
246
+ case 'scss' :
247
+ return getStyleUrlBoilerplate ( styleExtension ) ;
205
248
206
249
case 'spec.tsx' :
207
250
return getSpecTestBoilerplate ( tagName ) ;
@@ -218,13 +261,18 @@ export const getBoilerplateByExtension = (tagName: string, extension: GenerableE
218
261
* Get the boilerplate for a file containing the definition of a component
219
262
* @param tagName the name of the tag to give the component
220
263
* @param hasStyle designates if the component has an external stylesheet or not
264
+ * @param styleExtension extension used for styles
221
265
* @returns the contents of a file that defines a component
222
266
*/
223
- const getComponentBoilerplate = ( tagName : string , hasStyle : boolean ) : string => {
267
+ const getComponentBoilerplate = (
268
+ tagName : string ,
269
+ hasStyle : boolean ,
270
+ styleExtension : GeneratableStylingExtension ,
271
+ ) : string => {
224
272
const decorator = [ `{` ] ;
225
273
decorator . push ( ` tag: '${ tagName } ',` ) ;
226
274
if ( hasStyle ) {
227
- decorator . push ( ` styleUrl: '${ tagName } .css ',` ) ;
275
+ decorator . push ( ` styleUrl: '${ tagName } .${ styleExtension } ',` ) ;
228
276
}
229
277
decorator . push ( ` shadow: true,` ) ;
230
278
decorator . push ( `}` ) ;
@@ -233,25 +281,28 @@ const getComponentBoilerplate = (tagName: string, hasStyle: boolean): string =>
233
281
234
282
@Component(${ decorator . join ( '\n' ) } )
235
283
export class ${ toPascalCase ( tagName ) } {
236
-
237
284
render() {
238
285
return (
239
286
<Host>
240
287
<slot></slot>
241
288
</Host>
242
289
);
243
290
}
244
-
245
291
}
246
292
` ;
247
293
} ;
248
294
249
295
/**
250
296
* Get the boilerplate for style for a generated component
297
+ * @param ext extension used for styles
251
298
* @returns a boilerplate CSS block
252
299
*/
253
- const getStyleUrlBoilerplate = ( ) : string =>
254
- `:host {
300
+ const getStyleUrlBoilerplate = ( ext : GeneratableExtension ) : string =>
301
+ ext === 'sass'
302
+ ? `:host
303
+ display: block
304
+ `
305
+ : `:host {
255
306
display: block;
256
307
}
257
308
` ;
@@ -312,14 +363,19 @@ const toPascalCase = (str: string): string =>
312
363
/**
313
364
* Extensions available to generate.
314
365
*/
315
- export type GenerableExtension = 'tsx' | 'css' | 'spec.tsx' | 'e2e.ts' ;
366
+ export type GeneratableExtension = 'tsx' | 'spec.tsx' | 'e2e.ts' | GeneratableStylingExtension ;
367
+
368
+ /**
369
+ * Extensions available to generate.
370
+ */
371
+ export type GeneratableStylingExtension = 'css' | 'sass' | 'scss' | 'less' ;
316
372
317
373
/**
318
374
* A little interface to wrap up the info we need to pass around for generating
319
375
* and writing boilerplate.
320
376
*/
321
377
export interface BoilerplateFile {
322
- extension : GenerableExtension ;
378
+ extension : GeneratableExtension ;
323
379
/**
324
380
* The full path to the file we want to generate.
325
381
*/
0 commit comments