dart-sass/bin/sass.dart
Natalie Weizenbaum 55cb4fd509
Track stack traces through rethrows (#1545)
This requires a lot of manual machinery when displaying stack traces
to the user, but it should make debugging errors (especially in JS)
much easier.

Works around dart-lang/sdk#10297 using expandos.
2021-11-05 06:05:50 +00:00

143 lines
4.6 KiB
Dart

// Copyright 2016 Google Inc. Use of this source code is governed by an
// MIT-style license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.
import 'dart:isolate';
import 'package:path/path.dart' as p;
import 'package:stack_trace/stack_trace.dart';
import 'package:term_glyph/term_glyph.dart' as term_glyph;
import 'package:sass/src/exception.dart';
import 'package:sass/src/executable/compile_stylesheet.dart';
import 'package:sass/src/executable/options.dart';
import 'package:sass/src/executable/repl.dart';
import 'package:sass/src/executable/watch.dart';
import 'package:sass/src/import_cache.dart';
import 'package:sass/src/io.dart';
import 'package:sass/src/stylesheet_graph.dart';
import 'package:sass/src/utils.dart';
Future<void> main(List<String> args) async {
var printedError = false;
// Prints [error] to stderr, along with a preceding newline if anything else
// has been printed to stderr.
//
// If [trace] is passed, its terse representation is printed after the error.
void printError(String error, StackTrace? stackTrace) {
if (printedError) stderr.writeln();
printedError = true;
stderr.writeln(error);
if (stackTrace != null) {
stderr.writeln();
stderr.writeln(Trace.from(stackTrace).terse.toString().trimRight());
}
}
ExecutableOptions? options;
try {
options = ExecutableOptions.parse(args);
term_glyph.ascii = !options.unicode;
if (options.version) {
print(await _loadVersion());
exitCode = 0;
return;
}
if (options.interactive) {
await repl(options);
return;
}
var graph = StylesheetGraph(
ImportCache(loadPaths: options.loadPaths, logger: options.logger));
if (options.watch) {
await watch(options, graph);
return;
}
for (var source in options.sourcesToDestinations.keys) {
var destination = options.sourcesToDestinations[source];
try {
await compileStylesheet(options, graph, source, destination,
ifModified: options.update);
} on SassException catch (error, stackTrace) {
// This is an immediately-invoked function expression to work around
// dart-lang/sdk#33400.
() {
try {
if (destination != null &&
// dart-lang/sdk#45348
!options!.emitErrorCss) {
deleteFile(destination);
}
} on FileSystemException {
// If the file doesn't exist, that's fine.
}
}();
printError(error.toString(color: options.color),
options.trace ? getTrace(error) ?? stackTrace : null);
// Exit code 65 indicates invalid data per
// http://www.freebsd.org/cgi/man.cgi?query=sysexits.
//
// We let exitCode 66 take precedence for deterministic behavior.
if (exitCode != 66) exitCode = 65;
if (options.stopOnError) return;
} on FileSystemException catch (error, stackTrace) {
var path = error.path;
printError(
path == null
? error.message
: "Error reading ${p.relative(path)}: ${error.message}.",
options.trace ? getTrace(error) ?? stackTrace : null);
// Error 66 indicates no input.
exitCode = 66;
if (options.stopOnError) return;
}
}
} on UsageException catch (error) {
print("${error.message}\n");
print("Usage: sass <input.scss> [output.css]\n"
" sass <input.scss>:<output.css> <input/>:<output/> <dir/>\n");
print(ExecutableOptions.usage);
exitCode = 64;
} catch (error, stackTrace) {
var buffer = StringBuffer();
if (options != null && options.color) buffer.write('\u001b[31m\u001b[1m');
buffer.write('Unexpected exception:');
if (options != null && options.color) buffer.write('\u001b[0m');
buffer.writeln();
buffer.writeln(error);
printError(buffer.toString(), getTrace(error) ?? stackTrace);
exitCode = 255;
}
}
/// Loads and returns the current version of Sass.
Future<String> _loadVersion() async {
if (const bool.hasEnvironment('version')) {
var version = const String.fromEnvironment('version');
if (const bool.fromEnvironment('node')) {
version += " compiled with dart2js "
"${const String.fromEnvironment('dart-version')}";
}
return version;
}
var libDir =
p.fromUri(await Isolate.resolvePackageUri(Uri.parse('package:sass/')));
var pubspec = readFile(p.join(libDir, '..', 'pubspec.yaml'));
return pubspec
.split("\n")
.firstWhere((line) => line.startsWith('version: '))
.split(" ")
.last;
}