2016-05-24 03:01:15 +02:00
|
|
|
// 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.
|
|
|
|
|
2016-05-24 23:01:41 +02:00
|
|
|
import 'dart:collection';
|
|
|
|
|
2016-06-06 08:51:50 +02:00
|
|
|
import 'package:charcode/charcode.dart';
|
2016-05-24 03:01:15 +02:00
|
|
|
import 'package:source_span/source_span.dart';
|
|
|
|
|
|
|
|
import 'ast/node.dart';
|
2016-07-29 02:17:39 +02:00
|
|
|
import 'ast/selector.dart';
|
2016-06-03 22:36:20 +02:00
|
|
|
import 'value/number.dart';
|
|
|
|
|
2016-06-04 01:31:29 +02:00
|
|
|
const _epsilon = 1 / (10 * SassNumber.precision);
|
2016-05-24 03:01:15 +02:00
|
|
|
|
2016-06-10 02:55:04 +02:00
|
|
|
class LinkedListValue<T> extends LinkedListEntry<LinkedListValue<T>> {
|
|
|
|
final T value;
|
|
|
|
|
|
|
|
LinkedListValue(this.value);
|
|
|
|
}
|
|
|
|
|
2016-06-06 09:05:04 +02:00
|
|
|
FileSpan spanForList(List<AstNode> nodes) {
|
2016-05-24 03:01:15 +02:00
|
|
|
if (nodes.isEmpty) return null;
|
2016-06-06 09:05:04 +02:00
|
|
|
return nodes.first.span.expand(nodes.last.span);
|
2016-05-24 03:01:15 +02:00
|
|
|
}
|
2016-05-24 23:01:41 +02:00
|
|
|
|
2016-06-06 08:51:50 +02:00
|
|
|
String unvendor(String name) {
|
|
|
|
assert(!name.isEmpty);
|
|
|
|
if (name.codeUnitAt(0) == $dash) return name;
|
|
|
|
|
|
|
|
for (var i = 1; i < name.length; i++) {
|
|
|
|
if (name.codeUnitAt(0) == $dash) return name.substring(i + 1);
|
|
|
|
}
|
|
|
|
return name;
|
|
|
|
}
|
|
|
|
|
2016-06-10 02:55:04 +02:00
|
|
|
bool equalsIgnoreCase(String string1, String string2) {
|
|
|
|
if (string1 == null) return string2 == null;
|
|
|
|
if (string2 == null) return false;
|
|
|
|
if (string1.length != string2.length) return false;
|
|
|
|
return string1.toUpperCase() == string2.toUpperCase();
|
2016-05-24 23:01:41 +02:00
|
|
|
}
|
2016-06-03 22:36:20 +02:00
|
|
|
|
|
|
|
bool almostEquals(num number1, num number2) =>
|
|
|
|
(number1 - number2).abs() < _epsilon;
|
2016-06-10 02:55:04 +02:00
|
|
|
|
2016-07-29 02:17:39 +02:00
|
|
|
SimpleSelector unifyUniversalAndElement(SimpleSelector selector1,
|
|
|
|
SimpleSelector selector2) {
|
|
|
|
String namespace1;
|
|
|
|
String name1;
|
|
|
|
if (selector1 is UniversalSelector) {
|
|
|
|
namespace1 = selector1.namespace;
|
|
|
|
} else if (selector1 is TypeSelector) {
|
|
|
|
namespace1 = selector1.name.namespace;
|
|
|
|
name1 = selector1.name.name;
|
|
|
|
} else {
|
|
|
|
throw new ArgumentError.value(
|
|
|
|
selector1,
|
|
|
|
'selector1',
|
|
|
|
'must be a UniversalSelector or a TypeSelector');
|
|
|
|
}
|
|
|
|
|
|
|
|
String namespace2;
|
|
|
|
String name2;
|
|
|
|
if (selector2 is UniversalSelector) {
|
|
|
|
namespace2 = selector2.namespace;
|
|
|
|
} else if (selector2 is TypeSelector) {
|
|
|
|
namespace2 = selector2.name.namespace;
|
|
|
|
name2 = selector2.name.name;
|
|
|
|
} else {
|
|
|
|
throw new ArgumentError.value(
|
|
|
|
selector2,
|
|
|
|
'selector2',
|
|
|
|
'must be a UniversalSelector or a TypeSelector');
|
|
|
|
}
|
|
|
|
|
|
|
|
String namespace;
|
|
|
|
if (namespace1 == namespace2 || namespace2 == null || namespace2 == '*') {
|
|
|
|
namespace = namespace1;
|
|
|
|
} else if (namespace1 == null || namespace1 == '*') {
|
|
|
|
namespace = namespace2;
|
|
|
|
} else {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
String namespace;
|
|
|
|
if (name1 == name2 || name2 == null) {
|
|
|
|
namespace = name1;
|
|
|
|
} else if (name1 == null || name1 == '*') {
|
|
|
|
namespace = name2;
|
|
|
|
} else {
|
|
|
|
return null;
|
|
|
|
}
|
2016-06-10 02:55:04 +02:00
|
|
|
|
2016-07-29 02:17:39 +02:00
|
|
|
return name == null
|
|
|
|
? new UniversalSelector(namespace: namespace)
|
|
|
|
: new TypeSelector(
|
|
|
|
new NamespacedIdentifier(name, namespace: namespace));
|
|
|
|
}
|