// Copyright (c) 2017, 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 'package:built_value/built_value.dart'; import 'package:collection/collection.dart'; import 'package:meta/meta.dart'; import '../base.dart'; import '../visitors.dart'; part 'directive.g.dart'; @immutable abstract class Directive implements Built, Spec, Comparable { factory Directive([void Function(DirectiveBuilder) updates]) = _$Directive; factory Directive.import( String url, { String? as, List show = const [], List hide = const [], }) => Directive( (builder) => builder ..as = as ..type = DirectiveType.import ..url = url ..show.addAll(show) ..hide.addAll(hide), ); factory Directive.importDeferredAs( String url, String as, { List show = const [], List hide = const [], }) => Directive( (builder) => builder ..as = as ..type = DirectiveType.import ..url = url ..deferred = true ..show.addAll(show) ..hide.addAll(hide), ); factory Directive.export( String url, { List show = const [], List hide = const [], }) => Directive( (builder) => builder ..type = DirectiveType.export ..url = url ..show.addAll(show) ..hide.addAll(hide), ); factory Directive.part(String url) => Directive( (builder) => builder ..type = DirectiveType.part ..url = url, ); factory Directive.partOf(String url) => Directive( (builder) => builder ..type = DirectiveType.partOf ..url = url, ); Directive._(); String? get as; String get url; DirectiveType get type; List get show; List get hide; bool get deferred; @override R accept(SpecVisitor visitor, [R? context]) => visitor.visitDirective(this, context); @override int compareTo(Directive other) => _compareDirectives(this, other); } abstract class DirectiveBuilder implements Builder { factory DirectiveBuilder() = _$DirectiveBuilder; DirectiveBuilder._(); bool deferred = false; String? as; String? url; List show = []; List hide = []; DirectiveType? type; } enum DirectiveType { import, export, part, partOf } /// Sort import URIs represented by [a] and [b] to honor the /// "Effective Dart" ordering rules which are enforced by the /// `directives_ordering` lint. /// /// 1. `import`s before `export`s /// 2. `dart:` /// 3. `package:` /// 4. relative /// 5. `part`s int _compareDirectives(Directive a, Directive b) { // NOTE: using the fact that `import` is before `export` in the // `DirectiveType` enum – which allows us to compare using `indexOf`. var value = DirectiveType.values .indexOf(a.type) .compareTo(DirectiveType.values.indexOf(b.type)); if (value == 0) { final uriA = Uri.parse(a.url); final uriB = Uri.parse(b.url); if (uriA.hasScheme) { if (uriB.hasScheme) { // If both import URIs have schemes, compare them based on scheme // `dart` will sort before `package` which is what we want // schemes are case-insensitive, so compare accordingly value = compareAsciiLowerCase(uriA.scheme, uriB.scheme); } else { value = -1; } } else if (uriB.hasScheme) { value = 1; } // If both schemes are the same, compare based on path if (value == 0) { value = compareAsciiLowerCase(uriA.path, uriB.path); } assert((value == 0) == (a.url == b.url)); } return value; }