| // 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 'specs/directive.dart'; | |
| import 'specs/reference.dart'; | |
| /// Collects references and automatically allocates prefixes and imports. | |
| /// | |
| /// `Allocator` takes out the manual work of deciding whether a symbol will | |
| /// clash with other imports in your generated code, or what imports are needed | |
| /// to resolve all symbols in your generated code. | |
| abstract class Allocator { | |
| /// An allocator that does not prefix symbols nor collects imports. | |
| static const Allocator none = _NullAllocator(); | |
| /// Creates a new default allocator that applies no prefixing. | |
| factory Allocator() = _Allocator; | |
| /// Creates a new allocator that applies naive prefixing to avoid conflicts. | |
| /// | |
| /// This implementation is not optimized for any particular code generation | |
| /// style and instead takes a conservative approach of prefixing _every_ | |
| /// import except references to `dart:core` (which are considered always | |
| /// imported). | |
| /// | |
| /// The prefixes are not guaranteed to be stable and cannot be expected to | |
| /// have any particular value. | |
| factory Allocator.simplePrefixing() = _PrefixedAllocator; | |
| /// Returns a reference string given a [reference] object. | |
| /// | |
| /// For example, a no-op implementation: | |
| /// ```dart | |
| /// allocate(const Reference('List', 'dart:core')); // Returns 'List'. | |
| /// ``` | |
| /// | |
| /// Where-as an implementation that prefixes imports might output: | |
| /// ```dart | |
| /// allocate(const Reference('Foo', 'package:foo')); // Returns '_i1.Foo'. | |
| /// ``` | |
| String allocate(Reference reference); | |
| /// All imports that have so far been added implicitly via [allocate]. | |
| /// | |
| /// As a special case, imports of `package:fixnum/src/*` are changed to refer | |
| /// to the public `package:fixnum/fixnum.dart`. Version 1.2.0 of the package | |
| /// introduces platform-specific implementation libraries that must not be | |
| /// imported directly. | |
| Iterable<Directive> get imports; | |
| } | |
| class _Allocator implements Allocator { | |
| final _imports = <String>{}; | |
| @override | |
| String allocate(Reference reference) { | |
| var url = reference.url; | |
| if (url != null) { | |
| url = _fixUrl(url); | |
| _imports.add(url); | |
| } | |
| return reference.symbol!; | |
| } | |
| @override | |
| Iterable<Directive> get imports => _imports.map(Directive.import); | |
| } | |
| class _NullAllocator implements Allocator { | |
| const _NullAllocator(); | |
| @override | |
| String allocate(Reference reference) => reference.symbol!; | |
| @override | |
| Iterable<Directive> get imports => const []; | |
| } | |
| class _PrefixedAllocator implements Allocator { | |
| static const _doNotPrefix = ['dart:core']; | |
| final _imports = <String, int>{}; | |
| var _keys = 1; | |
| @override | |
| String allocate(Reference reference) { | |
| final symbol = reference.symbol; | |
| var url = reference.url; | |
| if (url == null || _doNotPrefix.contains(url)) { | |
| return symbol!; | |
| } | |
| url = _fixUrl(url); | |
| return '_i${_imports.putIfAbsent(url, _nextKey)}.$symbol'; | |
| } | |
| int _nextKey() => _keys++; | |
| @override | |
| Iterable<Directive> get imports => | |
| _imports.keys.map((u) => Directive.import(u, as: '_i${_imports[u]}')); | |
| } | |
| /// Applies hardcoded fixes to [url]. | |
| /// | |
| /// See [Allocator.imports] for explanations. | |
| String _fixUrl(String url) { | |
| if (url.startsWith('package:fixnum/src/')) { | |
| return 'package:fixnum/fixnum.dart'; | |
| } | |
| return url; | |
| } |