mirror of
https://github.com/danog/dart-sass.git
synced 2024-11-26 20:24:42 +01:00
Support package: URLs as a Dart library (#53)
This commit is contained in:
parent
be44245a84
commit
cfc3a15041
@ -5,7 +5,7 @@
|
||||
import 'package:path/path.dart' as p;
|
||||
|
||||
import 'src/ast/sass.dart';
|
||||
import 'src/exception.dart';
|
||||
import 'src/sync_package_resolver.dart';
|
||||
import 'src/utils.dart';
|
||||
import 'src/visitor/perform.dart';
|
||||
import 'src/visitor/serialize.dart';
|
||||
@ -14,13 +14,21 @@ import 'src/visitor/serialize.dart';
|
||||
///
|
||||
/// If [color] is `true`, this will use terminal colors in warnings.
|
||||
///
|
||||
/// Throws a [SassException] if conversion fails.
|
||||
String render(String path, {bool color: false}) {
|
||||
/// 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
|
||||
///
|
||||
/// Finally throws a [SassException] if conversion fails.
|
||||
String render(String path,
|
||||
{bool color: false, SyncPackageResolver packageResolver}) {
|
||||
var contents = readSassFile(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);
|
||||
var cssTree = evaluate(sassTree, color: color);
|
||||
var cssTree =
|
||||
evaluate(sassTree, color: color, packageResolver: packageResolver);
|
||||
return toCss(cssTree);
|
||||
}
|
||||
|
@ -37,5 +37,8 @@ String readFileAsString(String path) => null;
|
||||
/// Returns whether a file at [path] exists.
|
||||
bool fileExists(String path) => null;
|
||||
|
||||
/// Returns whether a dir at [path] exists.
|
||||
bool dirExists(String path) => null;
|
||||
|
||||
/// Gets and sets the exit code that the process will use when it exits.
|
||||
int exitCode;
|
||||
|
@ -74,6 +74,8 @@ String _cleanErrorMessage(_SystemError error) {
|
||||
|
||||
bool fileExists(String path) => _fs.existsSync(path);
|
||||
|
||||
bool dirExists(String path) => _fs.existsSync(path);
|
||||
|
||||
@JS("process.stderr")
|
||||
external _Stderr get _stderr;
|
||||
|
||||
|
@ -15,3 +15,5 @@ List<int> readFileAsBytes(String path) => new io.File(path).readAsBytesSync();
|
||||
String readFileAsString(String path) => new io.File(path).readAsStringSync();
|
||||
|
||||
bool fileExists(String path) => new io.File(path).existsSync();
|
||||
|
||||
bool dirExists(String path) => new io.Directory(path).existsSync();
|
||||
|
2
lib/src/sync_package_resolver.dart
Normal file
2
lib/src/sync_package_resolver.dart
Normal file
@ -0,0 +1,2 @@
|
||||
export 'package:package_resolver/package_resolver.dart'
|
||||
if (node) 'sync_package_resolver/node.dart';
|
17
lib/src/sync_package_resolver/node.dart
Normal file
17
lib/src/sync_package_resolver/node.dart
Normal file
@ -0,0 +1,17 @@
|
||||
// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
class SyncPackageResolver {
|
||||
static final _error =
|
||||
new UnsupportedError('SyncPackageResolver is not supported in JS.');
|
||||
|
||||
static Future<SyncPackageResolver> get current => throw _error;
|
||||
|
||||
Uri resolveUri(packageUri) => throw _error;
|
||||
|
||||
factory SyncPackageResolver.config(Map<String, Uri> configMap) =>
|
||||
throw _error;
|
||||
}
|
@ -21,6 +21,7 @@ import '../exception.dart';
|
||||
import '../extend/extender.dart';
|
||||
import '../io.dart';
|
||||
import '../parse/keyframe_selector.dart';
|
||||
import '../sync_package_resolver.dart';
|
||||
import '../utils.dart';
|
||||
import '../value.dart';
|
||||
import 'interface/statement.dart';
|
||||
@ -43,9 +44,13 @@ typedef _ScopeCallback(callback());
|
||||
CssStylesheet evaluate(Stylesheet stylesheet,
|
||||
{Iterable<String> loadPaths,
|
||||
Environment environment,
|
||||
bool color: false}) =>
|
||||
bool color: false,
|
||||
SyncPackageResolver packageResolver}) =>
|
||||
new _PerformVisitor(
|
||||
loadPaths: loadPaths, environment: environment, color: color)
|
||||
loadPaths: loadPaths,
|
||||
environment: environment,
|
||||
color: color,
|
||||
packageResolver: packageResolver)
|
||||
.run(stylesheet);
|
||||
|
||||
/// A visitor that executes Sass code to produce a CSS tree.
|
||||
@ -131,11 +136,18 @@ class _PerformVisitor
|
||||
/// invocations, and imports surrounding the current context.
|
||||
final _stack = <Frame>[];
|
||||
|
||||
/// The resolver to use for `package:` URLs, or `null` if no resolver exists.
|
||||
final SyncPackageResolver _packageResolver;
|
||||
|
||||
_PerformVisitor(
|
||||
{Iterable<String> loadPaths, Environment environment, bool color: false})
|
||||
{Iterable<String> loadPaths,
|
||||
Environment environment,
|
||||
bool color: false,
|
||||
SyncPackageResolver packageResolver})
|
||||
: _loadPaths = loadPaths == null ? const [] : new List.from(loadPaths),
|
||||
_environment = environment ?? new Environment(),
|
||||
_color = color {
|
||||
_color = color,
|
||||
_packageResolver = packageResolver {
|
||||
_environment.defineFunction("variable-exists", r"$name", (arguments) {
|
||||
var variable = arguments[0].assertString("name");
|
||||
return new SassBoolean(_environment.variableExists(variable.text));
|
||||
@ -581,11 +593,27 @@ class _PerformVisitor
|
||||
_activeImports.remove(url);
|
||||
}
|
||||
|
||||
/// Returns [import]'s URL, resolved to a `file:` URL if possible.
|
||||
Uri _resolveImportUrl(DynamicImport import) {
|
||||
var packageUrl = import.url;
|
||||
if (packageUrl.scheme != 'package') return packageUrl;
|
||||
|
||||
if (_packageResolver == null) {
|
||||
throw _exception(
|
||||
'"package:" URLs aren\'t supported on this platform.', import.span);
|
||||
}
|
||||
|
||||
var resolvedPackageUrl = _packageResolver.resolveUri(packageUrl);
|
||||
if (resolvedPackageUrl != null) return resolvedPackageUrl;
|
||||
|
||||
throw _exception("Unknown package.", import.span);
|
||||
}
|
||||
|
||||
/// Loads the [Stylesheet] imported by [import], or throws a
|
||||
/// [SassRuntimeException] if loading fails.
|
||||
Stylesheet _loadImport(DynamicImport import) {
|
||||
var path = _importPaths.putIfAbsent(import, () {
|
||||
var path = p.fromUri(import.url);
|
||||
var path = p.fromUri(_resolveImportUrl(import));
|
||||
var extension = p.extension(path);
|
||||
var tryPath = extension == '.sass' || extension == '.scss'
|
||||
? _tryImportPath
|
||||
|
@ -19,6 +19,7 @@ dependencies:
|
||||
string_scanner: ">=0.1.5 <2.0.0"
|
||||
stack_trace: ">=0.9.0 <2.0.0"
|
||||
tuple: "^1.0.0"
|
||||
package_resolver: ^1.0.0
|
||||
|
||||
dev_dependencies:
|
||||
archive: "^1.0.0"
|
||||
|
@ -95,4 +95,17 @@ void sharedTests(ScheduledProcess runSass(List arguments)) {
|
||||
sass.stderr.expect(consumeThrough(contains("\.dart")));
|
||||
sass.shouldExit(65);
|
||||
});
|
||||
|
||||
test("fails to import a package url", () {
|
||||
d.file("test.scss", "@import 'package:nope/test';").create();
|
||||
|
||||
var sass = runSass(["test.scss", "test.css"]);
|
||||
sass.stderr.expect(inOrder([
|
||||
"Error: \"package:\" URLs aren't supported on this platform.",
|
||||
"@import 'package:nope/test';",
|
||||
" ^^^^^^^^^^^^^^^^^^^",
|
||||
" test.scss 1:9 root stylesheet"
|
||||
]));
|
||||
sass.shouldExit(65);
|
||||
});
|
||||
}
|
||||
|
40
test/dart_script_test.dart
Normal file
40
test/dart_script_test.dart
Normal file
@ -0,0 +1,40 @@
|
||||
// Copyright 2017 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 'package:package_resolver/package_resolver.dart';
|
||||
import 'package:path/path.dart' as p;
|
||||
import 'package:scheduled_test/descriptor.dart' as d;
|
||||
import 'package:scheduled_test/scheduled_test.dart';
|
||||
|
||||
import 'package:sass/sass.dart';
|
||||
import 'package:sass/src/exception.dart';
|
||||
|
||||
import 'utils.dart';
|
||||
|
||||
main() {
|
||||
useSandbox();
|
||||
|
||||
test("successfully imports a package URL", () {
|
||||
d.dir("subdir", [d.file("test.scss", "a {b: 1 + 2}")]).create();
|
||||
|
||||
d.file("test.scss", '@import "package:fake_package/test";').create();
|
||||
var resolver = new SyncPackageResolver.config(
|
||||
{"fake_package": p.toUri(p.join(sandbox, 'subdir'))});
|
||||
|
||||
schedule(() {
|
||||
var css = render(p.join(sandbox, "test.scss"), packageResolver: resolver);
|
||||
expect(css, equals("a {\n b: 3;\n}"));
|
||||
});
|
||||
});
|
||||
|
||||
test("imports a package URL from a missing package", () {
|
||||
d.file("test.scss", '@import "package:fake_package/test_aux";').create();
|
||||
var resolver = new SyncPackageResolver.config({});
|
||||
|
||||
schedule(() {
|
||||
expect(() => render(sandbox + "/test.scss", packageResolver: resolver),
|
||||
throwsA(new isInstanceOf<SassRuntimeException>()));
|
||||
});
|
||||
});
|
||||
}
|
Loading…
Reference in New Issue
Block a user