|
| 1 | +// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 | +// for details. All rights reserved. Use of this source code is governed by a |
| 3 | +// BSD-style license that can be found in the LICENSE file. |
| 4 | + |
| 5 | +/// Contains a builder object useful for creating source maps programatically. |
| 6 | +library source_maps.builder; |
| 7 | + |
| 8 | +// TODO(sigmund): add a builder for multi-section mappings. |
| 9 | + |
| 10 | +import 'dart:convert'; |
| 11 | + |
| 12 | +import 'package:source_span/source_span.dart'; |
| 13 | + |
| 14 | +import 'parser.dart'; |
| 15 | +import 'src/source_map_span.dart'; |
| 16 | + |
| 17 | +/// Builds a source map given a set of mappings. |
| 18 | +class SourceMapBuilder { |
| 19 | + final List<Entry> _entries = <Entry>[]; |
| 20 | + |
| 21 | + /// Adds an entry mapping the [targetOffset] to [source]. |
| 22 | + void addFromOffset(SourceLocation source, SourceFile targetFile, |
| 23 | + int targetOffset, String identifier) { |
| 24 | + ArgumentError.checkNotNull(targetFile, 'targetFile'); |
| 25 | + _entries.add(Entry(source, targetFile.location(targetOffset), identifier)); |
| 26 | + } |
| 27 | + |
| 28 | + /// Adds an entry mapping [target] to [source]. |
| 29 | + /// |
| 30 | + /// If [isIdentifier] is true or if [target] is a [SourceMapSpan] with |
| 31 | + /// `isIdentifier` set to true, this entry is considered to represent an |
| 32 | + /// identifier whose value will be stored in the source map. [isIdentifier] |
| 33 | + /// takes precedence over [target]'s `isIdentifier` value. |
| 34 | + void addSpan(SourceSpan source, SourceSpan target, {bool? isIdentifier}) { |
| 35 | + isIdentifier ??= source is SourceMapSpan ? source.isIdentifier : false; |
| 36 | + |
| 37 | + var name = isIdentifier ? source.text : null; |
| 38 | + _entries.add(Entry(source.start, target.start, name)); |
| 39 | + } |
| 40 | + |
| 41 | + /// Adds an entry mapping [target] to [source]. |
| 42 | + void addLocation( |
| 43 | + SourceLocation source, SourceLocation target, String? identifier) { |
| 44 | + _entries.add(Entry(source, target, identifier)); |
| 45 | + } |
| 46 | + |
| 47 | + /// Encodes all mappings added to this builder as a json map. |
| 48 | + Map<String, dynamic> build(String fileUrl) { |
| 49 | + return SingleMapping.fromEntries(_entries, fileUrl).toJson(); |
| 50 | + } |
| 51 | + |
| 52 | + /// Encodes all mappings added to this builder as a json string. |
| 53 | + String toJson(String fileUrl) => jsonEncode(build(fileUrl)); |
| 54 | +} |
| 55 | + |
| 56 | +/// An entry in the source map builder. |
| 57 | +class Entry implements Comparable<Entry> { |
| 58 | + /// Span denoting the original location in the input source file |
| 59 | + final SourceLocation source; |
| 60 | + |
| 61 | + /// Span indicating the corresponding location in the target file. |
| 62 | + final SourceLocation target; |
| 63 | + |
| 64 | + /// An identifier name, when this location is the start of an identifier. |
| 65 | + final String? identifierName; |
| 66 | + |
| 67 | + /// Creates a new [Entry] mapping [target] to [source]. |
| 68 | + Entry(this.source, this.target, this.identifierName); |
| 69 | + |
| 70 | + /// Implements [Comparable] to ensure that entries are ordered by their |
| 71 | + /// location in the target file. We sort primarily by the target offset |
| 72 | + /// because source map files are encoded by printing each mapping in order as |
| 73 | + /// they appear in the target file. |
| 74 | + @override |
| 75 | + int compareTo(Entry other) { |
| 76 | + var res = target.compareTo(other.target); |
| 77 | + if (res != 0) return res; |
| 78 | + res = source.sourceUrl |
| 79 | + .toString() |
| 80 | + .compareTo(other.source.sourceUrl.toString()); |
| 81 | + if (res != 0) return res; |
| 82 | + return source.compareTo(other.source); |
| 83 | + } |
| 84 | +} |
0 commit comments