mirror of
https://github.com/danog/dart-sass.git
synced 2025-01-21 21:31:11 +01:00
Merge pull request #709 from sass/analysis
Enable stricter analysis options, especially around typing
This commit is contained in:
commit
11e3749721
@ -92,7 +92,7 @@ jobs:
|
||||
# Miscellaneous checks.
|
||||
- name: static analysis
|
||||
language: dart
|
||||
dart_task: {dartanalyzer: --fatal-warnings lib tool test}
|
||||
dart_task: {dartanalyzer: --fatal-warnings --fatal-infos lib tool test}
|
||||
- name: code formatting
|
||||
language: dart
|
||||
dart_task: dartfmt
|
||||
|
@ -1,5 +1,17 @@
|
||||
analyzer:
|
||||
strong-mode:
|
||||
implicit-casts: false
|
||||
language:
|
||||
strict-inference: true
|
||||
strict-raw-types: true
|
||||
errors:
|
||||
missing_js_lib_annotation: ignore
|
||||
deprecated_member_use_from_same_package: ignore
|
||||
|
||||
# These are necessary for matching the JS API.
|
||||
avoid_types_as_parameter_names: ignore
|
||||
|
||||
# This has tons of false positives for StreamSubscription.close().
|
||||
unawaited_futures: ignore
|
||||
|
||||
include: package:pedantic/analysis_options.yaml
|
||||
|
@ -13,7 +13,7 @@ class Interpolation implements SassNode {
|
||||
///
|
||||
/// This contains [String]s and [Expression]s. It never contains two adjacent
|
||||
/// [String]s.
|
||||
final List contents;
|
||||
final List<Object /* String | Expression */ > contents;
|
||||
|
||||
final FileSpan span;
|
||||
|
||||
@ -33,7 +33,7 @@ class Interpolation implements SassNode {
|
||||
return first is String ? first : '';
|
||||
}
|
||||
|
||||
Interpolation(Iterable /*(String|Expression)*/ contents, this.span)
|
||||
Interpolation(Iterable<Object /* String | Expression */ > contents, this.span)
|
||||
: contents = List.unmodifiable(contents) {
|
||||
for (var i = 0; i < this.contents.length; i++) {
|
||||
if (this.contents[i] is! String && this.contents[i] is! Expression) {
|
||||
|
@ -505,8 +505,8 @@ class AsyncEnvironment {
|
||||
}
|
||||
|
||||
/// Sets [content] as [this.content] for the duration of [callback].
|
||||
Future withContent(
|
||||
UserDefinedCallable<AsyncEnvironment> content, Future callback()) async {
|
||||
Future<void> withContent(UserDefinedCallable<AsyncEnvironment> content,
|
||||
Future<void> callback()) async {
|
||||
var oldContent = _content;
|
||||
_content = content;
|
||||
await callback();
|
||||
@ -514,7 +514,7 @@ class AsyncEnvironment {
|
||||
}
|
||||
|
||||
/// Sets [inMixin] to `true` for the duration of [callback].
|
||||
Future asMixin(Future callback()) async {
|
||||
Future<void> asMixin(Future<void> callback()) async {
|
||||
var oldInMixin = _inMixin;
|
||||
_inMixin = true;
|
||||
await callback();
|
||||
|
@ -35,6 +35,6 @@ abstract class AsyncCallable {
|
||||
AsyncBuiltInCallable(name, arguments, (arguments) {
|
||||
var result = callback(arguments);
|
||||
if (result is ext.Value) return result as Value;
|
||||
return (result as Future).then((value) => value as Value);
|
||||
return (result as Future<ext.Value>).then((value) => value as Value);
|
||||
});
|
||||
}
|
||||
|
@ -5,7 +5,7 @@
|
||||
// DO NOT EDIT. This file was generated from async_environment.dart.
|
||||
// See tool/grind/synchronize.dart for details.
|
||||
//
|
||||
// Checksum: 3210a5c0528eac456ae8ca7827b65f3976f6b29d
|
||||
// Checksum: 23c920bd76d38c4ccf2024a0740aeae9672143d0
|
||||
//
|
||||
// ignore_for_file: unused_import
|
||||
|
||||
|
@ -30,7 +30,7 @@ import 'options.dart';
|
||||
/// If [ifModified] is `true`, only recompiles if [source]'s modification time
|
||||
/// or that of a file it imports is more recent than [destination]'s
|
||||
/// modification time. Note that these modification times are cached by [graph].
|
||||
Future compileStylesheet(ExecutableOptions options, StylesheetGraph graph,
|
||||
Future<void> compileStylesheet(ExecutableOptions options, StylesheetGraph graph,
|
||||
String source, String destination,
|
||||
{bool ifModified = false}) async {
|
||||
var importer = FilesystemImporter('.');
|
||||
|
@ -253,7 +253,7 @@ class ExecutableOptions {
|
||||
(!_isWindowsPath(argument, 0) ||
|
||||
// Look for colons after index 1, since that's where the drive
|
||||
// letter is on Windows paths.
|
||||
argument.indexOf(":", 2) != -1)) {
|
||||
argument.contains(":", 2))) {
|
||||
colonArgs = true;
|
||||
} else if (dirExists(argument)) {
|
||||
directories.add(argument);
|
||||
|
@ -16,7 +16,7 @@ import '../value.dart' as internal;
|
||||
import '../visitor/evaluate.dart';
|
||||
|
||||
/// Runs an interactive SassScript shell according to [options].
|
||||
Future repl(ExecutableOptions options) async {
|
||||
Future<void> repl(ExecutableOptions options) async {
|
||||
var repl = Repl(prompt: '>> ');
|
||||
var variables = <String, internal.Value>{};
|
||||
await for (String line in repl.runAsync()) {
|
||||
|
@ -19,7 +19,7 @@ import 'compile_stylesheet.dart';
|
||||
import 'options.dart';
|
||||
|
||||
/// Watches all the files in [graph] for changes and updates them as necessary.
|
||||
Future watch(ExecutableOptions options, StylesheetGraph graph) async {
|
||||
Future<void> watch(ExecutableOptions options, StylesheetGraph graph) async {
|
||||
var directoriesToWatch = [
|
||||
...options.sourceDirectoriesToDestinations.keys,
|
||||
...options.sourcesToDestinations.keys.map(p.dirname),
|
||||
@ -30,7 +30,9 @@ Future watch(ExecutableOptions options, StylesheetGraph graph) async {
|
||||
await Future.wait(directoriesToWatch.map((dir) {
|
||||
// If a directory doesn't exist, watch its parent directory so that we're
|
||||
// notified once it starts existing.
|
||||
while (!dirExists(dir)) dir = p.dirname(dir);
|
||||
while (!dirExists(dir)) {
|
||||
dir = p.dirname(dir);
|
||||
}
|
||||
return dirWatcher.watch(dir);
|
||||
}));
|
||||
|
||||
@ -117,7 +119,7 @@ class _Watcher {
|
||||
/// Listens to `watcher.events` and updates the filesystem accordingly.
|
||||
///
|
||||
/// Returns a future that will only complete if an unexpected error occurs.
|
||||
Future watch(MultiDirWatcher watcher) async {
|
||||
Future<void> watch(MultiDirWatcher watcher) async {
|
||||
await for (var event in _debounceEvents(watcher.events)) {
|
||||
var extension = p.extension(event.path);
|
||||
if (extension != '.sass' && extension != '.scss') continue;
|
||||
@ -226,7 +228,7 @@ class _Watcher {
|
||||
var toRecompile = Queue.of(nodes);
|
||||
|
||||
var allSucceeded = true;
|
||||
while (!toRecompile.isEmpty) {
|
||||
while (toRecompile.isNotEmpty) {
|
||||
var node = toRecompile.removeFirst();
|
||||
if (!seen.add(node)) continue;
|
||||
|
||||
|
@ -76,8 +76,9 @@ class Extension {
|
||||
/// query context for this extender.
|
||||
void assertCompatibleMediaContext(List<CssMediaQuery> mediaContext) {
|
||||
if (this.mediaContext == null) return;
|
||||
if (mediaContext != null && listEquals(this.mediaContext, mediaContext))
|
||||
if (mediaContext != null && listEquals(this.mediaContext, mediaContext)) {
|
||||
return;
|
||||
}
|
||||
|
||||
throw SassException(
|
||||
"You may not @extend selectors across media queries.", span);
|
||||
|
@ -48,9 +48,10 @@ class NodeImporter {
|
||||
/// The importer functions passed in by the user.
|
||||
final List<JSFunction> _importers;
|
||||
|
||||
NodeImporter(this._context, Iterable<String> includePaths, Iterable importers)
|
||||
NodeImporter(
|
||||
this._context, Iterable<String> includePaths, Iterable<Object> importers)
|
||||
: _includePaths = List.unmodifiable(_addSassPath(includePaths)),
|
||||
_importers = List.unmodifiable(importers);
|
||||
_importers = List.unmodifiable(importers.cast());
|
||||
|
||||
/// Returns [includePaths] followed by any paths loaded from the `SASS_PATH`
|
||||
/// environment variable.
|
||||
@ -184,7 +185,7 @@ class NodeImporter {
|
||||
/// Calls an importer that may or may not be asynchronous.
|
||||
Future<Object> _callImporterAsync(
|
||||
JSFunction importer, String url, String previousString) async {
|
||||
var completer = Completer();
|
||||
var completer = Completer<Object>();
|
||||
|
||||
var result = call3(importer, _context, url, previousString,
|
||||
allowInterop(completer.complete));
|
||||
|
@ -7,8 +7,8 @@ import 'dart:async';
|
||||
import 'package:tuple/tuple.dart';
|
||||
|
||||
class NodeImporter {
|
||||
NodeImporter(
|
||||
Object context, Iterable<String> includePaths, Iterable importers);
|
||||
NodeImporter(Object context, Iterable<String> includePaths,
|
||||
Iterable<Object> importers);
|
||||
|
||||
Tuple2<String, String> load(String url, Uri previous) => null;
|
||||
|
||||
|
@ -48,7 +48,7 @@ class InterpolationBuffer implements StringSink {
|
||||
void addInterpolation(Interpolation interpolation) {
|
||||
if (interpolation.contents.isEmpty) return;
|
||||
|
||||
Iterable toAdd = interpolation.contents;
|
||||
Iterable<Object> toAdd = interpolation.contents;
|
||||
var first = interpolation.contents.first;
|
||||
if (first is String) {
|
||||
_text.write(first);
|
||||
|
@ -22,7 +22,7 @@ class _FS {
|
||||
external void mkdirSync(String path);
|
||||
external _Stat statSync(String path);
|
||||
external void unlinkSync(String path);
|
||||
external List readdirSync(String path);
|
||||
external List<Object> readdirSync(String path);
|
||||
}
|
||||
|
||||
@JS()
|
||||
|
@ -40,7 +40,7 @@ import 'visitor/serialize.dart';
|
||||
/// to run the executable when installed from npm.
|
||||
void main() {
|
||||
exports.run_ =
|
||||
allowInterop((args) => executable.main(List.from(args as List)));
|
||||
allowInterop((args) => executable.main(List.from(args as List<Object>)));
|
||||
exports.render = allowInterop(_render);
|
||||
exports.renderSync = allowInterop(_renderSync);
|
||||
exports.info =
|
||||
@ -225,7 +225,7 @@ List<AsyncCallable> _parseFunctions(RenderOptions options,
|
||||
} else {
|
||||
result.add(AsyncBuiltInCallable.parsed(tuple.item1, tuple.item2,
|
||||
(arguments) async {
|
||||
var completer = Completer();
|
||||
var completer = Completer<Object>();
|
||||
var jsArguments = [
|
||||
...arguments.map(wrapValue),
|
||||
allowInterop(([result]) => completer.complete(result))
|
||||
@ -245,8 +245,8 @@ NodeImporter _parseImporter(RenderOptions options, DateTime start) {
|
||||
List<JSFunction> importers;
|
||||
if (options.importer == null) {
|
||||
importers = [];
|
||||
} else if (options.importer is List) {
|
||||
importers = (options.importer as List).cast();
|
||||
} else if (options.importer is List<Object>) {
|
||||
importers = (options.importer as List<Object>).cast();
|
||||
} else {
|
||||
importers = [options.importer as JSFunction];
|
||||
}
|
||||
|
@ -12,5 +12,5 @@ class JSFunction implements Function {
|
||||
// than calling `Function.prototype.call()`. See sdk#31271.
|
||||
external call([arg1, arg2, arg3]);
|
||||
|
||||
external apply(thisArg, [List args]);
|
||||
external apply(thisArg, [List<Object> args]);
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ class RenderOptions {
|
||||
external String get data;
|
||||
external dynamic get importer;
|
||||
external dynamic get functions;
|
||||
external List get includePaths; // contains Strings
|
||||
external List<Object /* String */ > get includePaths;
|
||||
external bool get indentedSyntax;
|
||||
external bool get omitSourceMapUrl;
|
||||
external String get outFile;
|
||||
|
@ -24,7 +24,7 @@ class RenderResultStats {
|
||||
external int get start;
|
||||
external int get end;
|
||||
external int get duration;
|
||||
external List get includedFiles; // contains Strings
|
||||
external List<Object /* String */ > get includedFiles;
|
||||
|
||||
external factory RenderResultStats(
|
||||
{String entry,
|
||||
|
@ -1459,7 +1459,7 @@ relase. For details, see http://bit.ly/moz-document.
|
||||
|
||||
resolveOperations() {
|
||||
if (operators == null) return;
|
||||
while (!operators.isEmpty) {
|
||||
while (operators.isNotEmpty) {
|
||||
resolveOneOperation();
|
||||
}
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ class MultiDirWatcher {
|
||||
///
|
||||
/// Returns a [Future] that completes when [events] is ready to emit events
|
||||
/// from [directory].
|
||||
Future watch(String directory) {
|
||||
Future<void> watch(String directory) {
|
||||
var isParentOfExistingDir = false;
|
||||
for (var existingDir in _watchers.keys.toList()) {
|
||||
if (!isParentOfExistingDir &&
|
||||
|
@ -19,7 +19,7 @@ class NoSourceMapBuffer implements SourceMapBuffer {
|
||||
|
||||
T forSpan<T>(SourceSpan span, T callback()) => callback();
|
||||
void write(Object object) => _buffer.write(object);
|
||||
void writeAll(Iterable objects, [String separator = ""]) =>
|
||||
void writeAll(Iterable<Object> objects, [String separator = ""]) =>
|
||||
_buffer.writeAll(objects, separator);
|
||||
void writeCharCode(int charCode) => _buffer.writeCharCode(charCode);
|
||||
void writeln([Object object = ""]) => _buffer.writeln(object);
|
||||
|
@ -102,7 +102,7 @@ class SourceMapBuffer implements StringBuffer {
|
||||
}
|
||||
}
|
||||
|
||||
void writeAll(Iterable objects, [String separator = ""]) =>
|
||||
void writeAll(Iterable<Object> objects, [String separator = ""]) =>
|
||||
write(objects.join(separator));
|
||||
|
||||
void writeCharCode(int charCode) {
|
||||
|
@ -18,7 +18,7 @@ import 'util/character.dart';
|
||||
final _noSourceUrl = Uri.parse("-");
|
||||
|
||||
/// Converts [iter] into a sentence, separating each word with [conjunction].
|
||||
String toSentence(Iterable iter, [String conjunction]) {
|
||||
String toSentence(Iterable<Object> iter, [String conjunction]) {
|
||||
conjunction ??= "and";
|
||||
if (iter.length == 1) return iter.first.toString();
|
||||
return iter.take(iter.length - 1).join(", ") + " $conjunction ${iter.last}";
|
||||
@ -165,11 +165,19 @@ int codeUnitIndexToCodepointIndex(String string, int codeUnitIndex) {
|
||||
}
|
||||
|
||||
/// Returns whether [list1] and [list2] have the same contents.
|
||||
bool listEquals<T>(List<T> list1, List<T> list2) =>
|
||||
const ListEquality().equals(list1, list2);
|
||||
bool listEquals(List<Object> list1, List<Object> list2) =>
|
||||
const ListEquality<Object>().equals(list1, list2);
|
||||
|
||||
/// Returns a hash code for [list] that matches [listEquals].
|
||||
int listHash(List list) => const ListEquality().hash(list);
|
||||
int listHash(List<Object> list) => const ListEquality<Object>().hash(list);
|
||||
|
||||
/// Returns whether [map1] and [map2] have the same contents.
|
||||
bool mapEquals(Map<Object, Object> map1, Map<Object, Object> map2) =>
|
||||
const MapEquality<Object, Object>().equals(map1, map2);
|
||||
|
||||
/// Returns a hash code for [map] that matches [mapEquals].
|
||||
int mapHash(Map<Object, Object> map) =>
|
||||
const MapEquality<Object, Object>().hash(map);
|
||||
|
||||
/// Returns a stack frame for the given [span] with the given [member] name.
|
||||
///
|
||||
@ -395,7 +403,7 @@ void mapAddAll2<K1, K2, V>(
|
||||
|
||||
/// Rotates the element in list from [start] (inclusive) to [end] (exclusive)
|
||||
/// one index higher, looping the final element back to [start].
|
||||
void rotateSlice(List list, int start, int end) {
|
||||
void rotateSlice(List<Object> list, int start, int end) {
|
||||
var element = list[end - 1];
|
||||
for (var i = start; i < end; i++) {
|
||||
var next = list[i];
|
||||
|
@ -2,10 +2,9 @@
|
||||
// MIT-style license that can be found in the LICENSE file or at
|
||||
// https://opensource.org/licenses/MIT.
|
||||
|
||||
import 'package:collection/collection.dart';
|
||||
|
||||
import '../visitor/interface/value.dart';
|
||||
import '../value.dart';
|
||||
import '../utils.dart';
|
||||
import 'external/value.dart' as ext;
|
||||
|
||||
class SassMap extends Value implements ext.SassMap {
|
||||
@ -33,11 +32,9 @@ class SassMap extends Value implements ext.SassMap {
|
||||
SassMap assertMap([String name]) => this;
|
||||
|
||||
bool operator ==(other) =>
|
||||
(other is SassMap &&
|
||||
const MapEquality().equals(other.contents, contents)) ||
|
||||
(other is SassMap && mapEquals(other.contents, contents)) ||
|
||||
(contents.isEmpty && other is SassList && other.asList.isEmpty);
|
||||
|
||||
int get hashCode => contents.isEmpty
|
||||
? const SassList.empty().hashCode
|
||||
: const MapEquality().hash(contents);
|
||||
int get hashCode =>
|
||||
contents.isEmpty ? const SassList.empty().hashCode : mapHash(contents);
|
||||
}
|
||||
|
@ -42,7 +42,8 @@ import 'interface/modifiable_css.dart';
|
||||
import 'interface/statement.dart';
|
||||
|
||||
/// A function that takes a callback with no arguments.
|
||||
typedef _ScopeCallback = Future Function(Future Function() callback);
|
||||
typedef _ScopeCallback = Future<void> Function(
|
||||
Future<void> Function() callback);
|
||||
|
||||
/// Converts [stylesheet] to a plain CSS tree.
|
||||
///
|
||||
@ -675,7 +676,7 @@ class _EvaluateVisitor
|
||||
ModifiableCssParentNode newParent,
|
||||
AtRootQuery query,
|
||||
List<ModifiableCssParentNode> included) {
|
||||
var scope = (Future callback()) async {
|
||||
var scope = (Future<void> callback()) async {
|
||||
// We can't use [_withParent] here because it'll add the node to the tree
|
||||
// in the wrong place.
|
||||
var oldParent = _parent;
|
||||
@ -985,7 +986,7 @@ class _EvaluateVisitor
|
||||
}
|
||||
|
||||
/// Adds the stylesheet imported by [import] to the current document.
|
||||
Future _visitDynamicImport(DynamicImport import) async {
|
||||
Future<void> _visitDynamicImport(DynamicImport import) async {
|
||||
var result = await _loadStylesheet(import.url, import.span);
|
||||
var importer = result.item1;
|
||||
var stylesheet = result.item2;
|
||||
@ -1104,7 +1105,7 @@ class _EvaluateVisitor
|
||||
}
|
||||
|
||||
/// Adds a CSS import for [import].
|
||||
Future _visitStaticImport(StaticImport import) async {
|
||||
Future<void> _visitStaticImport(StaticImport import) async {
|
||||
// NOTE: this logic is largely duplicated in [visitCssImport]. Most changes
|
||||
// here should be mirrored there.
|
||||
|
||||
@ -1580,6 +1581,7 @@ class _EvaluateVisitor
|
||||
|
||||
_verifyArguments(positional.length, named, IfExpression.declaration, node);
|
||||
|
||||
// ignore: prefer_is_empty
|
||||
var condition = positional.length > 0 ? positional[0] : named["condition"];
|
||||
var ifTrue = positional.length > 1 ? positional[1] : named["if-true"];
|
||||
var ifFalse = positional.length > 2 ? positional[2] : named["if-false"];
|
||||
|
@ -5,7 +5,7 @@
|
||||
// DO NOT EDIT. This file was generated from async_evaluate.dart.
|
||||
// See tool/grind/synchronize.dart for details.
|
||||
//
|
||||
// Checksum: 71e3dfeef2683bd246e21ddfd25b21df408cf18e
|
||||
// Checksum: f316e802a42334d416c62f1d60d281a8262016f2
|
||||
//
|
||||
// ignore_for_file: unused_import
|
||||
|
||||
@ -1574,6 +1574,7 @@ class _EvaluateVisitor
|
||||
|
||||
_verifyArguments(positional.length, named, IfExpression.declaration, node);
|
||||
|
||||
// ignore: prefer_is_empty
|
||||
var condition = positional.length > 0 ? positional[0] : named["condition"];
|
||||
var ifTrue = positional.length > 1 ? positional[1] : named["if-true"];
|
||||
var ifFalse = positional.length > 2 ? positional[2] : named["if-false"];
|
||||
|
@ -11,7 +11,7 @@ List<DynamicImport> findImports(Stylesheet stylesheet) =>
|
||||
|
||||
/// A visitor that traverses a stylesheet and records all the [DynamicImport]s
|
||||
/// it contains.
|
||||
class _FindImportsVisitor extends RecursiveStatementVisitor {
|
||||
class _FindImportsVisitor extends RecursiveStatementVisitor<void> {
|
||||
final _imports = <DynamicImport>[];
|
||||
|
||||
List<DynamicImport> run(Stylesheet stylesheet) {
|
||||
|
@ -106,7 +106,8 @@ String serializeSelector(Selector selector, {bool inspect = false}) {
|
||||
}
|
||||
|
||||
/// A visitor that converts CSS syntax trees to plain strings.
|
||||
class _SerializeVisitor implements CssVisitor, ValueVisitor, SelectorVisitor {
|
||||
class _SerializeVisitor
|
||||
implements CssVisitor<void>, ValueVisitor<void>, SelectorVisitor<void> {
|
||||
/// A buffer that contains the CSS produced so far.
|
||||
final SourceMapBuffer _buffer;
|
||||
|
||||
|
@ -17,7 +17,7 @@ void sharedTests(
|
||||
{Map<String, String> environment})) {
|
||||
/// 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,
|
||||
Future<void> expectCompiles(List<String> arguments, expected,
|
||||
{Map<String, String> environment}) async {
|
||||
var sass = await runSass([...arguments, "out.css", "--no-source-map"],
|
||||
environment: environment);
|
||||
|
@ -31,7 +31,7 @@ void sharedTests(Future<TestProcess> runSass(Iterable<String> arguments)) {
|
||||
/// Modifying a file very quickly after it was processed can go
|
||||
/// unrecognized, especially on Windows where filesystem operations can have
|
||||
/// very high delays.
|
||||
Future tickIfPoll() => poll ? tick : Future.value();
|
||||
Future<void> tickIfPoll() => poll ? tick : Future.value();
|
||||
|
||||
group("${poll ? 'with' : 'without'} --poll", () {
|
||||
group("when started", () {
|
||||
|
@ -11,7 +11,7 @@ import 'package:sass/src/io.dart';
|
||||
|
||||
import 'io.dart';
|
||||
|
||||
hybridMain(StreamChannel channel) async {
|
||||
void hybridMain(StreamChannel<Object> channel) async {
|
||||
ensureUpToDate("build/npm/sass.dart.js", "pub run grinder npm-package");
|
||||
channel.sink.close();
|
||||
}
|
||||
@ -19,7 +19,7 @@ hybridMain(StreamChannel channel) async {
|
||||
/// Ensures that the NPM package is compiled and up-to-date.
|
||||
///
|
||||
/// This is safe to call even outside the Dart VM.
|
||||
Future ensureNpmPackage() async {
|
||||
Future<void> ensureNpmPackage() async {
|
||||
// spawnHybridUri() doesn't currently work on Windows and Node due to busted
|
||||
// path handling in the SDK.
|
||||
if (isNode && isWindows) return;
|
||||
|
@ -12,21 +12,21 @@ Future<String> createTempDir() async => (await runHybridExpression(
|
||||
'(await Directory.systemTemp.createTemp("dart_sass_")).path')) as String;
|
||||
|
||||
/// Writes [text] to [path].
|
||||
Future writeTextFile(String path, String text) => runHybridExpression(
|
||||
Future<void> writeTextFile(String path, String text) => runHybridExpression(
|
||||
'new File(message[0]).writeAsString(message[1])', [path, text]);
|
||||
|
||||
/// Creates a directoy at [path].
|
||||
Future createDirectory(String path) =>
|
||||
Future<void> createDirectory(String path) =>
|
||||
runHybridExpression('new Directory(message).create()', path);
|
||||
|
||||
/// Recursively deletes the directoy at [path].
|
||||
Future deleteDirectory(String path) =>
|
||||
Future<void> deleteDirectory(String path) =>
|
||||
runHybridExpression('new Directory(message).delete(recursive: true)', path);
|
||||
|
||||
/// Runs [expression], which may be asynchronous, in a hybrid isolate.
|
||||
///
|
||||
/// Returns the result of [expression] if it's JSON-serializable.
|
||||
Future runHybridExpression(String expression, [message]) async {
|
||||
Future<Object> runHybridExpression(String expression, [message]) async {
|
||||
var channel = spawnHybridCode('''
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
|
@ -180,7 +180,7 @@ void main() {
|
||||
data: "a {b: foo()}",
|
||||
functions: jsify({
|
||||
"foo": allowInterop((done) {
|
||||
Future.delayed(Duration.zero).then((_) {
|
||||
Timer(Duration.zero, () {
|
||||
done(callConstructor(sass.types.Number, [1]));
|
||||
});
|
||||
})
|
||||
@ -210,7 +210,7 @@ void main() {
|
||||
data: "a {b: foo()}",
|
||||
functions: jsify({
|
||||
"foo": allowInterop((done) {
|
||||
Future.delayed(Duration.zero).then((_) {
|
||||
Timer(Duration.zero, () {
|
||||
done(JSError("aw beans"));
|
||||
});
|
||||
})
|
||||
@ -223,7 +223,7 @@ void main() {
|
||||
data: "a {b: foo()}",
|
||||
functions: jsify({
|
||||
"foo": allowInterop((done) {
|
||||
Future.delayed(Duration.zero).then((_) {
|
||||
Timer(Duration.zero, () {
|
||||
done(callConstructor(sass.types.Error, ["aw beans"]));
|
||||
});
|
||||
})
|
||||
@ -236,7 +236,7 @@ void main() {
|
||||
data: "a {b: foo()}",
|
||||
functions: jsify({
|
||||
"foo": allowInterop((done) {
|
||||
Future.delayed(Duration.zero).then((_) {
|
||||
Timer(Duration.zero, () {
|
||||
done(null);
|
||||
});
|
||||
})
|
||||
@ -249,7 +249,7 @@ void main() {
|
||||
data: "a {b: foo()}",
|
||||
functions: jsify({
|
||||
"foo": allowInterop((done) {
|
||||
Future.delayed(Duration.zero).then((_) {
|
||||
Timer(Duration.zero, () {
|
||||
done();
|
||||
});
|
||||
})
|
||||
@ -291,7 +291,7 @@ void main() {
|
||||
data: "a {b: foo()}",
|
||||
functions: jsify({
|
||||
"foo": allowInterop((done) {
|
||||
Future.delayed(Duration.zero).then((_) {
|
||||
Timer(Duration.zero, () {
|
||||
done(callConstructor(sass.types.Number, [1]));
|
||||
});
|
||||
})
|
||||
@ -313,7 +313,7 @@ void main() {
|
||||
data: "a {b: foo()}",
|
||||
functions: jsify({
|
||||
"foo": allowInterop((done) {
|
||||
Future.delayed(Duration.zero).then((_) {
|
||||
Timer(Duration.zero, () {
|
||||
done(JSError("aw beans"));
|
||||
});
|
||||
})
|
||||
@ -327,7 +327,7 @@ void main() {
|
||||
data: "a {b: foo()}",
|
||||
functions: jsify({
|
||||
"foo": allowInterop((done) {
|
||||
Future.delayed(Duration.zero).then((_) {
|
||||
Timer(Duration.zero, () {
|
||||
done(null);
|
||||
});
|
||||
})
|
||||
@ -341,7 +341,7 @@ void main() {
|
||||
data: "a {b: foo()}",
|
||||
functions: jsify({
|
||||
"foo": allowInterop((done) {
|
||||
Future.delayed(Duration.zero).then((_) {
|
||||
Timer(Duration.zero, () {
|
||||
done();
|
||||
});
|
||||
})
|
||||
|
@ -589,7 +589,7 @@ void main() {
|
||||
render(RenderOptions(
|
||||
data: "@import 'foo'",
|
||||
importer: allowInterop((_, __, done) {
|
||||
Future.delayed(Duration.zero).then((_) {
|
||||
Timer(Duration.zero, () {
|
||||
done(NodeImporterResult(contents: 'a {b: c}'));
|
||||
});
|
||||
}))),
|
||||
@ -601,7 +601,7 @@ void main() {
|
||||
renderError(RenderOptions(
|
||||
data: "@import 'foo'",
|
||||
importer: allowInterop((_, __, done) {
|
||||
Future.delayed(Duration.zero).then((_) {
|
||||
Timer(Duration.zero, () {
|
||||
done(JSError('oh no'));
|
||||
});
|
||||
}))),
|
||||
@ -651,7 +651,7 @@ void main() {
|
||||
render(RenderOptions(
|
||||
data: "@import 'foo'",
|
||||
importer: allowInterop((_, __, done) {
|
||||
Future.delayed(Duration.zero).then((_) {
|
||||
Timer(Duration.zero, () {
|
||||
done(NodeImporterResult(contents: 'a {b: c}'));
|
||||
});
|
||||
}),
|
||||
@ -686,7 +686,7 @@ void main() {
|
||||
renderError(RenderOptions(
|
||||
data: "@import 'foo'",
|
||||
importer: allowInterop((_, __, done) {
|
||||
Future.delayed(Duration.zero).then((_) {
|
||||
Timer(Duration.zero, () {
|
||||
done(JSError('oh no'));
|
||||
});
|
||||
}),
|
||||
|
@ -12,7 +12,7 @@ import 'package:path/path.dart' as p;
|
||||
import 'package:source_maps/source_maps.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import 'package:sass/sass.dart' as dartSass;
|
||||
import 'package:sass/sass.dart' as dart_sass;
|
||||
|
||||
import '../ensure_npm_package.dart';
|
||||
import '../hybrid.dart';
|
||||
@ -39,7 +39,8 @@ void main() {
|
||||
|
||||
test("includes correct mappings", () {
|
||||
SingleMapping expectedMap;
|
||||
dartSass.compileString("a {b: c}", sourceMap: (map) => expectedMap = map);
|
||||
dart_sass.compileString("a {b: c}",
|
||||
sourceMap: (map) => expectedMap = map);
|
||||
expectedMap.targetUrl = "out.css";
|
||||
|
||||
expect(map, containsPair("mappings", expectedMap.toJson()["mappings"]));
|
||||
|
@ -108,8 +108,7 @@ void setEnvironmentVariable(String name, String value) {
|
||||
|
||||
// Runs [callback] with the `SASS_PATH` environment variable set to [paths].
|
||||
T withSassPath<T>(List<String> paths, T callback()) {
|
||||
var oldSassPath =
|
||||
setEnvironmentVariable("SASS_PATH", paths.join(isWindows ? ';' : ':'));
|
||||
setEnvironmentVariable("SASS_PATH", paths.join(isWindows ? ';' : ':'));
|
||||
|
||||
try {
|
||||
return callback();
|
||||
|
@ -14,7 +14,7 @@ import 'utils.dart';
|
||||
|
||||
void main() {
|
||||
group("from a parameter", () {
|
||||
var value;
|
||||
Object value;
|
||||
setUp(() {
|
||||
value = parseValue("null");
|
||||
});
|
||||
|
@ -17,7 +17,7 @@ final _sourceMapCommentRegExp = RegExp(r"/\*# sourceMappingURL=(.*) \*/\s*$");
|
||||
///
|
||||
/// Windows (or at least Appveyor) seems to require a more coarse-grained time
|
||||
/// than Unixes.
|
||||
Future get tick =>
|
||||
Future<void> get tick =>
|
||||
Future.delayed(Duration(milliseconds: isWindows ? 1000 : 50));
|
||||
|
||||
/// Loads and decodes the source map embedded as a `data:` URI in [css].
|
||||
|
@ -68,7 +68,7 @@ benchmarkGenerate() async {
|
||||
/// If [header] is passed, it's written before [text]. If [footer] is passed,
|
||||
/// it's written after [text]. If the file already exists and is the expected
|
||||
/// length, it's not written.
|
||||
Future _writeNTimes(String path, String text, num times,
|
||||
Future<void> _writeNTimes(String path, String text, num times,
|
||||
{String header, String footer}) async {
|
||||
var file = File(path);
|
||||
var expectedLength = (header == null ? 0 : header.length + 1) +
|
||||
|
@ -69,7 +69,7 @@ npmReleasePackage() => _npm(release: true);
|
||||
void _npm({@required bool release}) {
|
||||
var json = {
|
||||
...(jsonDecode(File('package/package.json').readAsStringSync())
|
||||
as Map<String, dynamic>),
|
||||
as Map<String, Object>),
|
||||
"version": version
|
||||
};
|
||||
|
||||
|
@ -4,10 +4,11 @@
|
||||
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:grinder/grinder.dart';
|
||||
import 'package:pub_semver/pub_semver.dart';
|
||||
|
||||
import 'package:sass/src/utils.dart';
|
||||
|
||||
import 'utils.dart';
|
||||
|
||||
@Task('Verify that the package is in a good state to release.')
|
||||
@ -17,7 +18,7 @@ sanityCheckBeforeRelease() {
|
||||
fail("TRAVIS_TAG $travisTag is different than pubspec version $version.");
|
||||
}
|
||||
|
||||
if (const ListEquality().equals(Version.parse(version).preRelease, ["dev"])) {
|
||||
if (listEquals(Version.parse(version).preRelease, ["dev"])) {
|
||||
fail("$version is a dev release.");
|
||||
}
|
||||
|
||||
|
@ -7,7 +7,6 @@ import 'dart:io';
|
||||
|
||||
import 'package:archive/archive.dart';
|
||||
import 'package:grinder/grinder.dart';
|
||||
import 'package:meta/meta.dart';
|
||||
import 'package:path/path.dart' as p;
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
@ -61,7 +60,7 @@ packageMacOs() => _buildPackage("macos");
|
||||
packageWindows() => _buildPackage("windows");
|
||||
|
||||
/// Builds standalone 32- and 64-bit Sass packages for the given [os].
|
||||
Future _buildPackage(String os) async {
|
||||
Future<void> _buildPackage(String os) async {
|
||||
var client = http.Client();
|
||||
await Future.wait(["ia32", "x64"].map((architecture) async {
|
||||
// TODO: Compile a single executable that embeds the Dart VM and the
|
||||
|
@ -5,6 +5,9 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
// See https://groups.google.com/a/dartlang.org/d/msg/misc/bZ0AGuEo41c/u05-1M7yAgAJ.
|
||||
//
|
||||
// ignore: deprecated_member_use
|
||||
import 'package:analyzer/analyzer.dart';
|
||||
import 'package:analyzer/dart/ast/ast.dart';
|
||||
import 'package:analyzer/dart/ast/token.dart';
|
||||
@ -56,7 +59,7 @@ synchronize() {
|
||||
/// original source where possible. It tracks the [_position] at the end of the
|
||||
/// text that's been written, and writes from that position to the new position
|
||||
/// whenever text needs to be emitted.
|
||||
class _Visitor extends RecursiveAstVisitor {
|
||||
class _Visitor extends RecursiveAstVisitor<void> {
|
||||
/// The source of the original asynchronous file.
|
||||
final String _source;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user