mirror of
https://github.com/danog/dart-sass.git
synced 2024-11-27 04:34:59 +01:00
Add infrastructure for compiling multiple sources at once
This will allow us to use the same code path for --update as we do for normal compilation.
This commit is contained in:
parent
454603d160
commit
beff4a1011
@ -25,67 +25,9 @@ main(List<String> args) async {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
SingleMapping sourceMap;
|
||||
var sourceMapCallback =
|
||||
options.emitSourceMap ? (SingleMapping map) => sourceMap = map : null;
|
||||
|
||||
var text =
|
||||
options.readFromStdin ? await readStdin() : readFile(options.source);
|
||||
var url = options.readFromStdin ? null : p.toUri(options.source);
|
||||
var importer = new FilesystemImporter('.');
|
||||
String css;
|
||||
if (options.asynchronous) {
|
||||
css = await compileStringAsync(text,
|
||||
indented: options.indented,
|
||||
logger: options.logger,
|
||||
style: options.style,
|
||||
importer: importer,
|
||||
loadPaths: options.loadPaths,
|
||||
url: url,
|
||||
sourceMap: sourceMapCallback);
|
||||
} else {
|
||||
css = compileString(text,
|
||||
indented: options.indented,
|
||||
logger: options.logger,
|
||||
style: options.style,
|
||||
importer: importer,
|
||||
loadPaths: options.loadPaths,
|
||||
url: url,
|
||||
sourceMap: sourceMapCallback);
|
||||
}
|
||||
|
||||
css += _writeSourceMap(options, sourceMap);
|
||||
if (options.writeToStdout) {
|
||||
if (css.isNotEmpty) print(css);
|
||||
} else {
|
||||
ensureDir(p.dirname(options.destination));
|
||||
writeFile(options.destination, css + "\n");
|
||||
}
|
||||
} on SassException catch (error, stackTrace) {
|
||||
stderr.writeln(error.toString(color: options.color));
|
||||
|
||||
if (options.trace) {
|
||||
stderr.writeln();
|
||||
stderr.write(new Trace.from(stackTrace).terse.toString());
|
||||
stderr.flush();
|
||||
}
|
||||
|
||||
// Exit code 65 indicates invalid data per
|
||||
// http://www.freebsd.org/cgi/man.cgi?query=sysexits.
|
||||
exitCode = 65;
|
||||
} on FileSystemException catch (error, stackTrace) {
|
||||
stderr.writeln(
|
||||
"Error reading ${p.relative(error.path)}: ${error.message}.");
|
||||
|
||||
// Error 66 indicates no input.
|
||||
exitCode = 66;
|
||||
|
||||
if (options.trace) {
|
||||
stderr.writeln();
|
||||
stderr.write(new Trace.from(stackTrace).terse.toString());
|
||||
stderr.flush();
|
||||
}
|
||||
for (var source in options.sourcesToDestinations.keys) {
|
||||
var destination = options.sourcesToDestinations[source];
|
||||
await _compileStylesheet(options, source, destination);
|
||||
}
|
||||
} on UsageException catch (error) {
|
||||
print("${error.message}\n");
|
||||
@ -125,14 +67,92 @@ Future<String> _loadVersion() async {
|
||||
.last;
|
||||
}
|
||||
|
||||
/// Writes the source map given by [mapping] to disk (if necessary) according to [options].
|
||||
/// Compiles the stylesheet at [source] to [destination].
|
||||
///
|
||||
/// If [source] is `null`, that indicates that the stylesheet should be read
|
||||
/// from stdin. If [destination] is `null`, that indicates that the stylesheet
|
||||
/// should be emitted to stdout.
|
||||
Future _compileStylesheet(
|
||||
ExecutableOptions options, String source, String destination) async {
|
||||
try {
|
||||
SingleMapping sourceMap;
|
||||
var sourceMapCallback =
|
||||
options.emitSourceMap ? (SingleMapping map) => sourceMap = map : null;
|
||||
|
||||
var indented =
|
||||
options.indented ?? (source != null && p.extension(source) == '.sass');
|
||||
var text = source == null ? await readStdin() : readFile(source);
|
||||
var url = source == null ? null : p.toUri(source);
|
||||
var importer = new FilesystemImporter('.');
|
||||
String css;
|
||||
if (options.asynchronous) {
|
||||
css = await compileStringAsync(text,
|
||||
indented: indented,
|
||||
logger: options.logger,
|
||||
style: options.style,
|
||||
importer: importer,
|
||||
loadPaths: options.loadPaths,
|
||||
url: url,
|
||||
sourceMap: sourceMapCallback);
|
||||
} else {
|
||||
css = compileString(text,
|
||||
indented: indented,
|
||||
logger: options.logger,
|
||||
style: options.style,
|
||||
importer: importer,
|
||||
loadPaths: options.loadPaths,
|
||||
url: url,
|
||||
sourceMap: sourceMapCallback);
|
||||
}
|
||||
|
||||
css += _writeSourceMap(options, sourceMap, destination);
|
||||
if (destination == null) {
|
||||
if (css.isNotEmpty) print(css);
|
||||
} else {
|
||||
ensureDir(p.dirname(destination));
|
||||
writeFile(destination, css + "\n");
|
||||
}
|
||||
} on SassException catch (error, stackTrace) {
|
||||
stderr.writeln(error.toString(color: options.color));
|
||||
|
||||
if (options.trace) {
|
||||
stderr.writeln();
|
||||
stderr.write(new Trace.from(stackTrace).terse.toString());
|
||||
stderr.flush();
|
||||
}
|
||||
|
||||
// Exit code 65 indicates invalid data per
|
||||
// http://www.freebsd.org/cgi/man.cgi?query=sysexits.
|
||||
exitCode = 65;
|
||||
} on FileSystemException catch (error, stackTrace) {
|
||||
stderr
|
||||
.writeln("Error reading ${p.relative(error.path)}: ${error.message}.");
|
||||
|
||||
// Error 66 indicates no input.
|
||||
exitCode = 66;
|
||||
|
||||
if (options.trace) {
|
||||
stderr.writeln();
|
||||
stderr.write(new Trace.from(stackTrace).terse.toString());
|
||||
stderr.flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Writes the source map given by [mapping] to disk (if necessary) according to
|
||||
/// [options].
|
||||
///
|
||||
/// The [destination] is the path where the CSS file associated with this source
|
||||
/// map will be written. If it's `null`, that indicates that the CSS will be
|
||||
/// printed to stdout.
|
||||
///
|
||||
/// Returns the source map comment to add to the end of the CSS file.
|
||||
String _writeSourceMap(ExecutableOptions options, SingleMapping sourceMap) {
|
||||
String _writeSourceMap(
|
||||
ExecutableOptions options, SingleMapping sourceMap, String destination) {
|
||||
if (sourceMap == null) return "";
|
||||
|
||||
if (!options.writeToStdout) {
|
||||
sourceMap.targetUrl = p.toUri(p.basename(options.destination)).toString();
|
||||
if (destination != null) {
|
||||
sourceMap.targetUrl = p.toUri(p.basename(destination)).toString();
|
||||
}
|
||||
|
||||
for (var i = 0; i < sourceMap.urls.length; i++) {
|
||||
@ -141,7 +161,8 @@ String _writeSourceMap(ExecutableOptions options, SingleMapping sourceMap) {
|
||||
// The special URL "" indicates a file that came from stdin.
|
||||
if (url == "") continue;
|
||||
|
||||
sourceMap.urls[i] = options.sourceMapUrl(Uri.parse(url)).toString();
|
||||
sourceMap.urls[i] =
|
||||
options.sourceMapUrl(Uri.parse(url), destination).toString();
|
||||
}
|
||||
var sourceMapText = convert.json
|
||||
.encode(sourceMap.toJson(includeSourceContents: options.embedSources));
|
||||
@ -150,7 +171,7 @@ String _writeSourceMap(ExecutableOptions options, SingleMapping sourceMap) {
|
||||
if (options.embedSourceMap) {
|
||||
url = new Uri.dataFromString(sourceMapText, mimeType: 'application/json');
|
||||
} else {
|
||||
var sourceMapPath = options.destination + '.map';
|
||||
var sourceMapPath = destination + '.map';
|
||||
ensureDir(p.dirname(sourceMapPath));
|
||||
writeFile(sourceMapPath, sourceMapText);
|
||||
|
||||
|
@ -101,9 +101,10 @@ class ExecutableOptions {
|
||||
bool get version => _options['version'] as bool;
|
||||
|
||||
/// Whether to parse the source file with the indented syntax.
|
||||
bool get indented =>
|
||||
_ifParsed('indented') as bool ??
|
||||
(source != null && p.extension(source) == '.sass');
|
||||
///
|
||||
/// This may be `null`, indicating that this should be determined by each
|
||||
/// stylesheet's extension.
|
||||
bool get indented => _ifParsed('indented') as bool;
|
||||
|
||||
/// Whether to use ANSI terminal colors.
|
||||
bool get color =>
|
||||
@ -128,32 +129,33 @@ class ExecutableOptions {
|
||||
/// Whether to print the full Dart stack trace on exceptions.
|
||||
bool get trace => _options['trace'] as bool;
|
||||
|
||||
/// The entrypoint Sass file, or `null` if the source should be read from
|
||||
/// stdin.
|
||||
String get source {
|
||||
_ensureSourceAndDestination();
|
||||
return _source;
|
||||
/// A map from source paths to the destination paths where the compiled CSS
|
||||
/// should be written.
|
||||
///
|
||||
/// A `null` source indicates that a stylesheet should be read from standard
|
||||
/// input. A `null` destination indicates that a stylesheet should be written
|
||||
/// to standard output.
|
||||
Map<String, String> get sourcesToDestinations {
|
||||
if (_sourcesToDestinations != null) return _sourcesToDestinations;
|
||||
|
||||
String source;
|
||||
String destination;
|
||||
if (_options['stdin'] as bool) {
|
||||
if (_options.rest.length > 1) _fail("Compile Sass to CSS.");
|
||||
if (_options.rest.isNotEmpty) destination = _options.rest.first;
|
||||
} else if (_options.rest.isEmpty || _options.rest.length > 2) {
|
||||
_fail("Compile Sass to CSS.");
|
||||
} else if (_options.rest.first == '-') {
|
||||
if (_options.rest.length > 1) destination = _options.rest.last;
|
||||
} else {
|
||||
source = _options.rest.first;
|
||||
if (_options.rest.length > 1) destination = _options.rest.last;
|
||||
}
|
||||
_sourcesToDestinations = new Map.unmodifiable({source: destination});
|
||||
return _sourcesToDestinations;
|
||||
}
|
||||
|
||||
String _source;
|
||||
|
||||
/// Whether to read the source file from stdin rather than a file on disk.
|
||||
bool get readFromStdin => source == null;
|
||||
|
||||
/// The path to which to write the CSS, or `null` if the CSS should be printed
|
||||
/// to stdout.
|
||||
String get destination {
|
||||
_ensureSourceAndDestination();
|
||||
return _destination;
|
||||
}
|
||||
|
||||
String _destination;
|
||||
|
||||
/// Whether to write the output CSS to stdout rather than a file on disk.
|
||||
bool get writeToStdout => destination == null;
|
||||
|
||||
/// Whether [_source] and [_destination] have been parsed from [_options] yet.
|
||||
var _parsedSourceAndDestination = false;
|
||||
Map<String, String> _sourcesToDestinations;
|
||||
|
||||
/// Whether to emit a source map file.
|
||||
bool get emitSourceMap {
|
||||
@ -167,7 +169,9 @@ class ExecutableOptions {
|
||||
}
|
||||
}
|
||||
|
||||
if (destination != null) return _options['source-map'] as bool;
|
||||
var writeToStdout = sourcesToDestinations.length == 1 &&
|
||||
sourcesToDestinations.values.single == null;
|
||||
if (!writeToStdout) return _options['source-map'] as bool;
|
||||
|
||||
if (_ifParsed('source-map-urls') == 'relative') {
|
||||
_fail(
|
||||
@ -211,28 +215,9 @@ class ExecutableOptions {
|
||||
|
||||
ExecutableOptions._(this._options);
|
||||
|
||||
/// Parses [source] and [destination] from [_options] if they haven't been
|
||||
/// parsed yet.
|
||||
void _ensureSourceAndDestination() {
|
||||
if (_parsedSourceAndDestination) return;
|
||||
_parsedSourceAndDestination = true;
|
||||
|
||||
if (_options['stdin'] as bool) {
|
||||
if (_options.rest.length > 1) _fail("Compile Sass to CSS.");
|
||||
if (_options.rest.isNotEmpty) _destination = _options.rest.first;
|
||||
} else if (_options.rest.isEmpty || _options.rest.length > 2) {
|
||||
_fail("Compile Sass to CSS.");
|
||||
} else if (_options.rest.first == '-') {
|
||||
if (_options.rest.length > 1) _destination = _options.rest.last;
|
||||
} else {
|
||||
_source = _options.rest.first;
|
||||
if (_options.rest.length > 1) _destination = _options.rest.last;
|
||||
}
|
||||
}
|
||||
|
||||
/// Makes [url] absolute or relative (to [dir]) according to the
|
||||
/// `source-map-urls` option.
|
||||
Uri sourceMapUrl(Uri url) {
|
||||
/// Makes [url] absolute or relative (to the directory containing
|
||||
/// [destination]) according to the `source-map-urls` option.
|
||||
Uri sourceMapUrl(Uri url, String destination) {
|
||||
var path = p.fromUri(url);
|
||||
return p.toUri(_options['source-map-urls'] == 'relative'
|
||||
? p.relative(path, from: p.dirname(destination))
|
||||
|
Loading…
Reference in New Issue
Block a user