Skip to content
This repository was archived by the owner on Jan 25, 2024. It is now read-only.

Commit 2dab40b

Browse files
committed
fix(cli): revise mount logics
1 parent 70365dc commit 2dab40b

File tree

3 files changed

+66
-49
lines changed

3 files changed

+66
-49
lines changed

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,8 @@
6161
"emscripten-wasm-loader": "^2.1.1",
6262
"get-stdin": "^6.0.0",
6363
"source-map-support": "^0.5.6",
64-
"tslib": "^1.9.3"
64+
"tslib": "^1.9.3",
65+
"unixify": "^1.0.0"
6566
},
6667
"devDependencies": {
6768
"@commitlint/cli": "^7.0.0",

src/ambient.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
declare module '*/bin/libsass';
22
declare module 'nanoid';
3+
declare module 'unixify';

src/cli.ts

Lines changed: 63 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@ import * as commandLineArgs from 'command-line-args';
44
import * as debug from 'debug';
55
import * as fs from 'fs';
66
import * as path from 'path';
7+
import * as unixify from 'unixify';
78
import * as util from 'util';
89
import { OutputStyle } from './index';
910
import { buildContext } from './interop/context';
1011
import { SassOptionsInterface } from './interop/options/sassOptions';
1112
import { SassContextInterface } from './interop/sassContext';
12-
import { SassFactory } from './SassFactory';
1313
import './verbose';
1414

1515
const d = debug('libsass:cli');
@@ -40,6 +40,12 @@ const optionDefinitions = [
4040
type: String,
4141
multiple: true,
4242
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
4349
}
4450
];
4551

@@ -84,7 +90,7 @@ const buildDisplayVersion = async () => {
8490
const buildSassOption = (
8591
context: ReturnType<typeof buildContext>,
8692
options: commandLineArgs.CommandLineOptions,
87-
outFile: string | undefined
93+
outFile?: string | null
8894
) => {
8995
const sassOption = context.options.create();
9096
//Set default values
@@ -143,32 +149,34 @@ const buildSassOption = (
143149

144150
const writeCompileResult = async (
145151
context: SassContextInterface,
146-
outputPath: string | undefined,
147-
sourceMapFile?: string | undefined
152+
outputPath: string | null,
153+
sourceMapFile?: string | null
148154
) => {
149155
const { errorStatus, errorMessage, outputString, sourceMapString } = context;
150156

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+
151163
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-
}
156164
try {
157165
d(`writeCompileResult: writing file`, { outputPath });
158166
await util.promisify(fs.writeFile)(outputPath, content, 'utf-8');
159167
return 0;
160168
} catch (e) {
161-
console.log(`Failed to write output to ${outputPath}`, { e });
169+
console.error(`Failed to write output to ${outputPath}`, { e });
162170
return 2;
163171
}
164172
};
165173

166-
if (!outputPath) {
174+
if (!outputPath && !!outputString) {
167175
d(`writeCompileResult: path to output file not specified, print to stdout`);
168176
console.log(outputString);
169177
}
170178

171-
if (!sourceMapFile) {
179+
if (!sourceMapFile && !!sourceMapString) {
172180
d(`writeCompileResult: path to source map file not specified, print to stdout`);
173181
console.log(sourceMapString);
174182
}
@@ -184,64 +192,50 @@ const writeCompileResult = async (
184192
return outputResult;
185193
}
186194

187-
return 0;
195+
return errorStatus;
188196
};
189197

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+
) => {
192203
const stdin = await import('get-stdin');
193204
const input = await stdin();
194205

195-
const mountPath = !!outputPath ? interop.mount(path.dirname(outputPath)) : null;
196-
197206
const dataContext = context.data.create(input);
198207
const sassContext = dataContext.getContext();
199208
dataContext.options = options;
200209

201210
dataContext.compile();
202-
const result = await writeCompileResult(sassContext, outputPath);
211+
const result = await writeCompileResult(sassContext, !!outputPath ? outputPath.raw : null);
203212

204213
dataContext.dispose();
205214

206-
if (!!mountPath) {
207-
interop.unmount(mountPath);
208-
}
209-
210215
return result;
211216
};
212217

213218
const compile = async (
214-
factory: SassFactory,
219+
context: ReturnType<typeof buildContext>,
215220
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 }
218223
) => {
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;
230226
}
231227

232228
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);
235231
const sassContext = fileContext.getContext();
236232
fileContext.options = options;
237233
fileContext.compile();
238234

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);
245239

246240
fileContext.dispose();
247241

@@ -263,19 +257,40 @@ const main = async (argv: Array<string> = process.argv) => {
263257
}
264258

265259
const { loadModule } = await import('./loadModule');
266-
const factory = await loadModule();
260+
const { context, interop } = await loadModule();
267261
const files: Array<string> = options.files || [];
268262
if (files.length > 2) {
269263
throw new Error(`Unexpected arguments provided, '${files.slice(2)}'`);
270264
}
271265

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+
274282
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);
277285

278286
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+
279294
process.exit(result);
280295
};
281296

0 commit comments

Comments
 (0)