@@ -4,12 +4,12 @@ import * as commandLineArgs from 'command-line-args';
4
4
import * as debug from 'debug' ;
5
5
import * as fs from 'fs' ;
6
6
import * as path from 'path' ;
7
+ import * as unixify from 'unixify' ;
7
8
import * as util from 'util' ;
8
9
import { OutputStyle } from './index' ;
9
10
import { buildContext } from './interop/context' ;
10
11
import { SassOptionsInterface } from './interop/options/sassOptions' ;
11
12
import { SassContextInterface } from './interop/sassContext' ;
12
- import { SassFactory } from './SassFactory' ;
13
13
import './verbose' ;
14
14
15
15
const d = debug ( 'libsass:cli' ) ;
@@ -40,6 +40,12 @@ const optionDefinitions = [
40
40
type : String ,
41
41
multiple : true ,
42
42
defaultOption : true
43
+ } ,
44
+ {
45
+ name : 'mount' ,
46
+ description : 'Additional path to be mounted other than direct dir to input path' ,
47
+ type : String ,
48
+ multiple : true
43
49
}
44
50
] ;
45
51
@@ -84,7 +90,7 @@ const buildDisplayVersion = async () => {
84
90
const buildSassOption = (
85
91
context : ReturnType < typeof buildContext > ,
86
92
options : commandLineArgs . CommandLineOptions ,
87
- outFile : string | undefined
93
+ outFile ? : string | null
88
94
) => {
89
95
const sassOption = context . options . create ( ) ;
90
96
//Set default values
@@ -143,32 +149,34 @@ const buildSassOption = (
143
149
144
150
const writeCompileResult = async (
145
151
context : SassContextInterface ,
146
- outputPath : string | undefined ,
147
- sourceMapFile ?: string | undefined
152
+ outputPath : string | null ,
153
+ sourceMapFile ?: string | null
148
154
) => {
149
155
const { errorStatus, errorMessage, outputString, sourceMapString } = context ;
150
156
157
+ if ( errorStatus > 0 ) {
158
+ //To conform sass-spec's matcher, explicitly emit via stderr
159
+ process . stderr . write ( errorMessage || `An error occurred; no error message available.\n` ) ;
160
+ return 1 ;
161
+ }
162
+
151
163
const write = async ( outputPath : string , content : string ) => {
152
- if ( errorStatus > 0 ) {
153
- console . log ( errorMessage || `An error occurred; no error message available.\n` ) ;
154
- return 1 ;
155
- }
156
164
try {
157
165
d ( `writeCompileResult: writing file` , { outputPath } ) ;
158
166
await util . promisify ( fs . writeFile ) ( outputPath , content , 'utf-8' ) ;
159
167
return 0 ;
160
168
} catch ( e ) {
161
- console . log ( `Failed to write output to ${ outputPath } ` , { e } ) ;
169
+ console . error ( `Failed to write output to ${ outputPath } ` , { e } ) ;
162
170
return 2 ;
163
171
}
164
172
} ;
165
173
166
- if ( ! outputPath ) {
174
+ if ( ! outputPath && ! ! outputString ) {
167
175
d ( `writeCompileResult: path to output file not specified, print to stdout` ) ;
168
176
console . log ( outputString ) ;
169
177
}
170
178
171
- if ( ! sourceMapFile ) {
179
+ if ( ! sourceMapFile && ! ! sourceMapString ) {
172
180
d ( `writeCompileResult: path to source map file not specified, print to stdout` ) ;
173
181
console . log ( sourceMapString ) ;
174
182
}
@@ -184,64 +192,50 @@ const writeCompileResult = async (
184
192
return outputResult ;
185
193
}
186
194
187
- return 0 ;
195
+ return errorStatus ;
188
196
} ;
189
197
190
- const compileStdin = async ( factory : SassFactory , options : SassOptionsInterface , outputPath : string | undefined ) => {
191
- const { interop, context } = factory ;
198
+ const compileStdin = async (
199
+ context : ReturnType < typeof buildContext > ,
200
+ options : SassOptionsInterface ,
201
+ outputPath : { raw : string ; mountedDir : string ; mountedFullPath : string }
202
+ ) => {
192
203
const stdin = await import ( 'get-stdin' ) ;
193
204
const input = await stdin ( ) ;
194
205
195
- const mountPath = ! ! outputPath ? interop . mount ( path . dirname ( outputPath ) ) : null ;
196
-
197
206
const dataContext = context . data . create ( input ) ;
198
207
const sassContext = dataContext . getContext ( ) ;
199
208
dataContext . options = options ;
200
209
201
210
dataContext . compile ( ) ;
202
- const result = await writeCompileResult ( sassContext , outputPath ) ;
211
+ const result = await writeCompileResult ( sassContext , ! ! outputPath ? outputPath . raw : null ) ;
203
212
204
213
dataContext . dispose ( ) ;
205
214
206
- if ( ! ! mountPath ) {
207
- interop . unmount ( mountPath ) ;
208
- }
209
-
210
215
return result ;
211
216
} ;
212
217
213
218
const compile = async (
214
- factory : SassFactory ,
219
+ context : ReturnType < typeof buildContext > ,
215
220
options : SassOptionsInterface ,
216
- inputPath : string ,
217
- outputPath : string | undefined
221
+ inputPath : { raw : string ; mountedDir : string ; mountedFullPath : string } ,
222
+ outputPath : { raw : string ; mountedDir : string ; mountedFullPath : string }
218
223
) => {
219
- const { interop, context } = factory ;
220
- const mountedPath = [ inputPath , outputPath ]
221
- . filter ( x => ! ! x )
222
- . map ( p => path . dirname ( p ! ) )
223
- . map ( dir => {
224
- d ( `mount directory '${ dir } '` ) ;
225
- return interop . mount ( dir ) ;
226
- } ) ;
227
-
228
- if ( ! ! outputPath ) {
229
- options . outputPath = outputPath ;
224
+ if ( ! ! outputPath && ! ! outputPath . mountedFullPath ) {
225
+ options . outputPath = outputPath . mountedFullPath ;
230
226
}
231
227
232
228
const sourceMapFile = options . sourceMapFile ;
233
- options . inputPath = inputPath ;
234
- const fileContext = context . file . create ( inputPath ) ;
229
+ options . inputPath = inputPath . mountedFullPath ;
230
+ const fileContext = context . file . create ( inputPath . mountedFullPath ) ;
235
231
const sassContext = fileContext . getContext ( ) ;
236
232
fileContext . options = options ;
237
233
fileContext . compile ( ) ;
238
234
239
- const result = await writeCompileResult ( sassContext , outputPath , sourceMapFile ) ;
240
-
241
- mountedPath . forEach ( dir => {
242
- interop . unmount ( dir ) ;
243
- d ( `unmount directory '${ dir } '` ) ;
244
- } ) ;
235
+ //writeCompileResult's output path should be raw path instead of mounted virtual, it uses fs.write directly
236
+ const rawOutputPath = ! ! outputPath ? outputPath . raw : null ;
237
+ const rawSourceMapPath = ! ! rawOutputPath && ! ! sourceMapFile ? `${ rawOutputPath } .map` : null ;
238
+ const result = await writeCompileResult ( sassContext , rawOutputPath , rawSourceMapPath ) ;
245
239
246
240
fileContext . dispose ( ) ;
247
241
@@ -263,19 +257,40 @@ const main = async (argv: Array<string> = process.argv) => {
263
257
}
264
258
265
259
const { loadModule } = await import ( './loadModule' ) ;
266
- const factory = await loadModule ( ) ;
260
+ const { context , interop } = await loadModule ( ) ;
267
261
const files : Array < string > = options.files || [];
268
262
if (files.length > 2 ) {
269
263
throw new Error ( `Unexpected arguments provided, '${ files . slice ( 2 ) } '` ) ;
270
264
}
271
265
272
- const [inputPath, outputPath] = files;
273
- const sassOption = buildSassOption(factory.context, options, outputPath);
266
+ //Mount specified paths
267
+ const additionalMountPath = (Array.isArray(options.mount) ? options.mount : []).map(x => interop . mount ( x ) ) ;
268
+ const [ mountedInput , mountedOutput ] = files
269
+ . filter ( x => ! ! x )
270
+ . map ( p => ( { raw : p , dir : path . dirname ( p ! ) , file : path . basename ( p ! ) } ) )
271
+ . map ( ( { raw, dir, file } ) => {
272
+ const mountedDir = interop . mount ( dir ) ;
273
+ return {
274
+ raw,
275
+ mountedDir : mountedDir ,
276
+ mountedFullPath : unixify ( path . join ( mountedDir , file ) ) as string
277
+ } ;
278
+ } ) ;
279
+
280
+ const sassOption = buildSassOption ( context , options , ! ! mountedOutput ? mountedOutput . mountedFullPath : undefined ) ;
281
+
274
282
const result = options . stdin
275
- ? await compileStdin(factory , sassOption, outputPath )
276
- : await compile(factory , sassOption, inputPath, outputPath );
283
+ ? await compileStdin ( context , sassOption , mountedOutput )
284
+ : await compile ( context , sassOption , mountedInput , mountedOutput ) ;
277
285
278
286
sassOption . dispose ( ) ;
287
+
288
+ additionalMountPath . forEach ( x => interop . unmount ( x ) ) ;
289
+ [ mountedInput , mountedOutput ]
290
+ . filter ( x => ! ! x )
291
+ . map ( ( { mountedDir } ) => mountedDir )
292
+ . forEach ( dir => interop . unmount ( dir ) ) ;
293
+
279
294
process . exit ( result ) ;
280
295
} ;
281
296
0 commit comments