Add support for the data option to the JS API (#159)

Also add renderString to the Dart API.

Partially addresses #7
This commit is contained in:
Natalie Weizenbaum 2017-07-07 00:57:10 -07:00 committed by GitHub
parent 91ebf98c7f
commit 8f836df66c
7 changed files with 139 additions and 24 deletions

View File

@ -8,9 +8,14 @@
### Node JS API
* Add support for `lineFeed`, `indentWidth`, and `indentType` options to
* Add support for `data`, `lineFeed`, `indentWidth`, and `indentType` options to
`render()` and `renderSync()`.
### Dart API
* Add a `renderString()` method for rendering Sass source that's not in a file
on disk.
## 1.0.0-beta.1
* Drop support for the reference combinator. This has been removed from the

View File

@ -16,7 +16,34 @@ import 'src/sync_package_resolver.dart';
///
/// [SyncPackageResolver]: https://www.dartdocs.org/documentation/package_resolver/latest/package_resolver/SyncPackageResolver-class.html
///
/// Finally throws a [SassException] if conversion fails.
/// Throws a [SassException] if conversion fails.
String render(String path,
{bool color: false, SyncPackageResolver packageResolver}) =>
r.render(path, color: color, packageResolver: packageResolver);
/// Converts [source] to CSS and returns the result.
///
/// If [indented] is `true`, this parses [source] using indented syntax;
/// otherwise (and by default) it uses SCSS. If [color] is `true`, this will use
/// terminal colors in warnings.
///
/// If [packageResolver] is provided, it's used to resolve `package:` imports.
/// Otherwise, they aren't supported. It takes a [SyncPackageResolver][] from
/// the `package_resolver` package.
///
/// [SyncPackageResolver]: https://www.dartdocs.org/documentation/package_resolver/latest/package_resolver/SyncPackageResolver-class.html
///
/// The [url] indicates the location from which [source] was loaded. It may may
/// be a [String] or a [Uri].
///
/// Throws a [SassException] if conversion fails.
String renderString(String source,
{bool indented: false,
bool color: false,
SyncPackageResolver packageResolver,
url}) =>
r.renderString(source,
indented: indented,
color: color,
packageResolver: packageResolver,
url: url);

View File

@ -39,14 +39,12 @@ void main() {
void _render(RenderOptions options,
void callback(RenderError error, RenderResult result)) {
try {
var result = newRenderResult(render(options.file,
useSpaces: options.indentType != 'tab',
indentWidth: _parseIndentWidth(options.indentWidth),
lineFeed: _parseLineFeed(options.linefeed)));
callback(null, result);
callback(null, _doRender(options));
} on SassException catch (error) {
// TODO: populate the error more thoroughly if possible.
callback(newRenderError(message: error.message), null);
callback(newRenderError(error.message), null);
} catch (error) {
callback(newRenderError(error.toString()), null);
}
}
@ -58,15 +56,42 @@ void _render(RenderOptions options,
/// [render]: https://github.com/sass/node-sass#options
RenderResult _renderSync(RenderOptions options) {
try {
return newRenderResult(render(options.file,
useSpaces: options.indentType != 'tab',
indentWidth: _parseIndentWidth(options.indentWidth),
lineFeed: _parseLineFeed(options.linefeed)));
return _doRender(options);
} on SassException catch (error) {
// TODO: populate the error more thoroughly if possible.
jsThrow(newRenderError(message: error.message));
throw "unreachable";
jsThrow(newRenderError(error.message));
} catch (error) {
jsThrow(newRenderError(error.toString()));
}
throw "unreachable";
}
/// Converts Sass to CSS.
///
/// Unlike [_render] and [_renderSync], this doesn't do any special handling for
/// Dart exceptions.
RenderResult _doRender(RenderOptions options) {
String output;
if (options.data != null) {
if (options.file != null) {
throw new ArgumentError(
"options.data and options.file may not both be set.");
}
output = renderString(options.data,
useSpaces: options.indentType != 'tab',
indentWidth: _parseIndentWidth(options.indentWidth),
lineFeed: _parseLineFeed(options.linefeed));
} else if (options.file != null) {
output = render(options.file,
useSpaces: options.indentType != 'tab',
indentWidth: _parseIndentWidth(options.indentWidth),
lineFeed: _parseLineFeed(options.linefeed));
} else {
throw new ArgumentError("Either options.data or options.file must be set.");
}
return newRenderResult(output);
}
/// Parses the indentation width into an [int].

View File

@ -19,8 +19,8 @@ class RenderError {
{String message, int line, int column, int status, String file});
}
RenderError newRenderError(
{String message, int line, int column, int status, String file}) {
RenderError newRenderError(String message,
{int line, int column, int status, String file}) {
var error = new RenderError._(
message: message, line: line, column: column, status: status, file: file);
setToString(error, () => "Error: $message");

View File

@ -8,10 +8,15 @@ import 'package:js/js.dart';
@anonymous
class RenderOptions {
external String get file;
external String get data;
external String get indentType;
external dynamic get indentWidth;
external String get linefeed;
external factory RenderOptions(
{String file, String indentType, indentWidth, String linefeed});
{String file,
String data,
String indentType,
indentWidth,
String linefeed});
}

View File

@ -12,16 +12,33 @@ import 'visitor/serialize.dart';
/// Like [render] in `lib/sass.dart`, but provides more options to support the
/// node-sass compatible API.
String render(String path,
{bool color: false,
{bool color: false,
SyncPackageResolver packageResolver,
bool useSpaces: true,
int indentWidth,
LineFeed lineFeed}) =>
renderString(readFile(path),
indented: p.extension(path) == '.sass',
color: color,
packageResolver: packageResolver,
useSpaces: useSpaces,
indentWidth: indentWidth,
lineFeed: lineFeed,
url: p.toUri(path));
/// Like [renderString] in `lib/sass.dart`, but provides more options to support
/// the node-sass compatible API.
String renderString(String source,
{bool indented: false,
bool color: false,
SyncPackageResolver packageResolver,
bool useSpaces: true,
int indentWidth,
LineFeed lineFeed}) {
var contents = readFile(path);
var url = p.toUri(path);
var sassTree = p.extension(path) == '.sass'
? new Stylesheet.parseSass(contents, url: url, color: color)
: new Stylesheet.parseScss(contents, url: url, color: color);
LineFeed lineFeed,
url}) {
var sassTree = indented
? new Stylesheet.parseSass(source, url: url, color: color)
: new Stylesheet.parseScss(source, url: url, color: color);
var cssTree =
evaluate(sassTree, color: color, packageResolver: packageResolver);
return toCss(cssTree,

View File

@ -41,6 +41,42 @@ a {
}'''));
});
test("supports relative imports for a file", () async {
var importerPath = p.join(sandbox, 'importer.scss');
await writeTextFile(importerPath, '@import "test"');
expect(_renderSync(new RenderOptions(file: importerPath)), equals('''
a {
b: c;
}'''));
});
test("renders a string", () {
expect(_renderSync(new RenderOptions(data: "a {b: c}")), equals('''
a {
b: c;
}'''));
});
test("data and file may not both be set", () {
var error =
_renderSyncError(new RenderOptions(data: "x {y: z}", file: sassPath));
expect(error.toString(),
contains('options.data and options.file may not both be set.'));
});
test("one of data and file must be set", () {
var error = _renderSyncError(new RenderOptions());
expect(error.toString(),
contains('Either options.data or options.file must be set.'));
});
test("rejects both a file and a string", () {
expect(_renderSync(new RenderOptions(data: "a {b: c}")), equals('''
a {
b: c;
}'''));
});
test("allows tab indentation", () {
expect(_renderSync(new RenderOptions(file: sassPath, indentType: 'tab')),
equals('''