Add support for "sass input.scss output.css" (#275)

Closes #274
This commit is contained in:
Natalie Weizenbaum 2018-03-27 13:45:03 -07:00 committed by GitHub
parent 7b2dfef289
commit 880c91444e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 94 additions and 52 deletions

View File

@ -1,3 +1,8 @@
## 1.1.0
* The command-line executable can now be used to write an output file to disk
using `sass input.scss output.css`.
## 1.0.0
**Initial stable release.**

View File

@ -61,7 +61,10 @@ main(List<String> args) async {
}
var stdinFlag = options['stdin'] as bool;
if (options['help'] as bool || (options.rest.isEmpty && !stdinFlag)) {
if (options['help'] as bool ||
(stdinFlag
? options.rest.length > 1
: options.rest.isEmpty || options.rest.length > 2)) {
_printUsage(argParser, "Compile Sass to CSS.");
exitCode = 64;
return;
@ -80,7 +83,9 @@ main(List<String> args) async {
var asynchronous = options['async'] as bool;
try {
String css;
String destination;
if (stdinFlag) {
if (options.rest.isNotEmpty) destination = options.rest.first;
css = await _compileStdin(
indented: indented,
logger: logger,
@ -88,8 +93,9 @@ main(List<String> args) async {
loadPaths: loadPaths,
asynchronous: asynchronous);
} else {
var input = options.rest.first;
if (input == '-') {
var source = options.rest.first;
if (options.rest.length > 1) destination = options.rest.last;
if (source == '-') {
css = await _compileStdin(
indented: indented,
logger: logger,
@ -97,15 +103,19 @@ main(List<String> args) async {
loadPaths: loadPaths,
asynchronous: asynchronous);
} else if (asynchronous) {
css = await compileAsync(input,
css = await compileAsync(source,
logger: logger, style: style, loadPaths: loadPaths);
} else {
css =
compile(input, logger: logger, style: style, loadPaths: loadPaths);
compile(source, logger: logger, style: style, loadPaths: loadPaths);
}
}
if (css.isNotEmpty) print(css);
if (destination != null) {
writeFile(destination, css + "\n");
} else if (css.isNotEmpty) {
print(css);
}
} on SassException catch (error, stackTrace) {
stderr.writeln(error.toString(color: color));
@ -192,6 +202,6 @@ Future<String> _compileStdin(
/// Print the usage information for Sass, with [message] as a header.
void _printUsage(ArgParser parser, String message) {
print("$message\n");
print("Usage: dart-sass <input>\n");
print("Usage: sass <input> [output]\n");
print(parser.usage);
}

View File

@ -46,6 +46,11 @@ String get currentPath => null;
/// the file isn't valid UTF-8.
String readFile(String path) => null;
/// Writes [contents] to the file at [path], encoded as UTF-8.
///
/// Throws a [FileSystemException] if writing fails.
void writeFile(String path, String contents) => null;
/// Reads from the standard input for the current process until it closes,
/// returning the contents.
Future<String> readStdin() async => null;

View File

@ -14,7 +14,7 @@ import '../util/path.dart';
@JS()
class _FS {
external readFileSync(String path, [String encoding]);
external void writeFileSync(String path, String data);
external bool existsSync(String path);
}
@ -102,6 +102,16 @@ _readFile(String path, [String encoding]) {
}
}
void writeFile(String path, String contents) {
try {
return _fs.writeFileSync(path, contents);
} catch (error) {
var systemError = error as _SystemError;
throw new FileSystemException._(
_cleanErrorMessage(systemError), systemError.path);
}
}
Future<String> readStdin() async {
var completer = new Completer<String>();
String contents;

View File

@ -41,6 +41,9 @@ String readFile(String path) {
}
}
void writeFile(String path, String contents) =>
new io.File(path).writeAsStringSync(contents);
Future<String> readStdin() async {
var completer = new Completer<String>();
completer.complete(await io.SYSTEM_ENCODING.decodeStream(io.stdin));

View File

@ -1,5 +1,5 @@
name: sass
version: 1.0.0
version: 1.1.0-dev
description: A Sass implementation in Dart.
author: Dart Team <misc@dartlang.org>
homepage: https://github.com/sass/dart-sass

View File

@ -10,6 +10,14 @@ import 'package:test_process/test_process.dart';
/// Defines test that are shared between the Dart and Node.js CLI test suites.
void sharedTests(Future<TestProcess> runSass(Iterable<String> arguments)) {
/// Runs the executable on [arguments] plus an output file, then verifies that
/// the contents of the output file match [expected].
Future expectCompiles(List<String> arguments, expected) async {
var sass = await runSass(arguments.toList()..add("out.css"));
await sass.shouldExit(0);
await d.file("out.css", expected).validate();
}
test("--help prints the usage documentation", () async {
// Checking the entire output is brittle, so just do a sanity check to make
// sure it's not totally busted.
@ -34,6 +42,15 @@ void sharedTests(Future<TestProcess> runSass(Iterable<String> arguments)) {
await sass.shouldExit(0);
});
test("writes a CSS file to disk", () async {
await d.file("test.scss", "a {b: 1 + 2}").create();
var sass = await runSass(["test.scss", "out.css"]);
expect(sass.stdout, emitsDone);
await sass.shouldExit(0);
await d.file("out.css", equalsIgnoringWhitespace("a { b: 3; }")).validate();
});
test("compiles from stdin with the magic path -", () async {
var sass = await runSass(["-"]);
sass.stdin.writeln("a {b: 1 + 2}");
@ -54,15 +71,8 @@ void sharedTests(Future<TestProcess> runSass(Iterable<String> arguments)) {
await d.dir("dir", [d.file("test.scss", "a {b: 1 + 2}")]).create();
var sass = await runSass(["test.scss", "test.css"]);
expect(
sass.stdout,
emitsInOrder([
"a {",
" b: 3;",
"}",
]));
await sass.shouldExit(0);
await expectCompiles(
["test.scss"], equalsIgnoringWhitespace("a { b: 3; }"));
});
test("from the load path", () async {
@ -70,15 +80,8 @@ void sharedTests(Future<TestProcess> runSass(Iterable<String> arguments)) {
await d.dir("dir", [d.file("test2.scss", "a {b: c}")]).create();
var sass = await runSass(["--load-path", "dir", "test.scss", "test.css"]);
expect(
sass.stdout,
emitsInOrder([
"a {",
" b: c;",
"}",
]));
await sass.shouldExit(0);
await expectCompiles(["--load-path", "dir", "test.scss"],
equalsIgnoringWhitespace("a { b: c; }"));
});
test("relative in preference to from the load path", () async {
@ -87,15 +90,8 @@ void sharedTests(Future<TestProcess> runSass(Iterable<String> arguments)) {
await d.dir("dir", [d.file("test2.scss", "a {b: c}")]).create();
var sass = await runSass(["--load-path", "dir", "test.scss", "test.css"]);
expect(
sass.stdout,
emitsInOrder([
"x {",
" y: z;",
"}",
]));
await sass.shouldExit(0);
await expectCompiles(["--load-path", "dir", "test.scss"],
equalsIgnoringWhitespace("x { y: z; }"));
});
test("in load path order", () async {
@ -104,22 +100,9 @@ void sharedTests(Future<TestProcess> runSass(Iterable<String> arguments)) {
await d.dir("dir1", [d.file("test2.scss", "a {b: c}")]).create();
await d.dir("dir2", [d.file("test2.scss", "x {y: z}")]).create();
var sass = await runSass([
"--load-path",
"dir2",
"--load-path",
"dir1",
"test.scss",
"test.css"
]);
expect(
sass.stdout,
emitsInOrder([
"x {",
" y: z;",
"}",
]));
await sass.shouldExit(0);
await expectCompiles(
["--load-path", "dir2", "--load-path", "dir1", "test.scss"],
equalsIgnoringWhitespace("x { y: z; }"));
});
});
@ -138,6 +121,18 @@ void sharedTests(Future<TestProcess> runSass(Iterable<String> arguments)) {
await sass.shouldExit(0);
});
test("writes a CSS file to disk", () async {
var sass = await runSass(["--stdin", "out.css"]);
sass.stdin.writeln("a {b: 1 + 2}");
sass.stdin.close();
expect(sass.stdout, emitsDone);
await sass.shouldExit(0);
await d
.file("out.css", equalsIgnoringWhitespace("a { b: 3; }"))
.validate();
});
test("uses the indented syntax with --indented", () async {
var sass = await runSass(["--stdin", "--indented"]);
sass.stdin.writeln("a\n b: 1 + 2");
@ -226,6 +221,20 @@ void sharedTests(Future<TestProcess> runSass(Iterable<String> arguments)) {
await sass.shouldExit(64);
});
test("from too many positional arguments", () async {
var sass = await runSass(["abc", "def", "ghi"]);
expect(
sass.stdout, emitsThrough(contains("Print this usage information.")));
await sass.shouldExit(64);
});
test("from too many positional arguments with --stdin", () async {
var sass = await runSass(["--stdin", "abc", "def"]);
expect(
sass.stdout, emitsThrough(contains("Print this usage information.")));
await sass.shouldExit(64);
});
test("from a file that doesn't exist", () async {
var sass = await runSass(["asdf"]);
expect(sass.stderr, emits(startsWith("Error reading asdf:")));