Support unmapped areas in source maps.

R=johnniwinther@google.com

Review URL: https://codereview.chromium.org//237123003

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart/pkg/source_maps@35307 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/lib/builder.dart b/lib/builder.dart
index 12587cd..ef22e31 100644
--- a/lib/builder.dart
+++ b/lib/builder.dart
@@ -75,15 +75,10 @@
       column = _append(buff, column, entry.target.column);
 
       // Encoding can be just the column offset if there is no source
-      // information, or if two consecutive mappings share exactly the same
-      // source information.
+      // information.
       var source = entry.source;
       if (source == null) continue;
       var newUrlId = _indexOf(_urls, source.sourceUrl);
-      if (newUrlId == srcUrlId && source.line == srcLine
-          && source.column == srcColumn && entry.identifierName == null) {
-        continue;
-      }
 
       srcUrlId = _append(buff, srcUrlId, newUrlId);
       srcLine = _append(buff, srcLine, source.line);
diff --git a/lib/parser.dart b/lib/parser.dart
index 6b8bf37..c92a8bb 100644
--- a/lib/parser.dart
+++ b/lib/parser.dart
@@ -185,7 +185,7 @@
       if (tokenizer.nextKind.isNewSegment) throw _segmentError(0, line);
       column += tokenizer._consumeValue();
       if (!tokenizer.nextKind.isValue) {
-        entries.add(new TargetEntry(column, srcUrlId, srcLine, srcColumn));
+        entries.add(new TargetEntry(column));
       } else {
         srcUrlId += tokenizer._consumeValue();
         if (srcUrlId >= urls.length) {
@@ -204,8 +204,8 @@
             throw new StateError(
                 'Invalid name id: $targetUrl, $line, $srcNameId');
           }
-          entries.add(
-              new TargetEntry(column, srcUrlId, srcLine, srcColumn, srcNameId));
+          entries.add(new TargetEntry(column, srcUrlId, srcLine, srcColumn,
+              srcNameId));
         }
       }
       if (tokenizer.nextKind.isNewSegment) tokenizer._consumeNewSegment();
@@ -242,7 +242,7 @@
 
   Span spanFor(int line, int column, {Map<String, SourceFile> files}) {
     var entry = _findColumn(line, column, _findLine(line));
-    if (entry == null) return null;
+    if (entry == null || entry.sourceUrlId == null) return null;
     var url = urls[entry.sourceUrlId];
     if (files != null && files[url] != null) {
       var file = files[url];
@@ -322,8 +322,8 @@
   final int sourceColumn;
   final int sourceNameId;
 
-  TargetEntry(this.column, this.sourceUrlId, this.sourceLine,
-      this.sourceColumn, [this.sourceNameId]);
+  TargetEntry(this.column, [this.sourceUrlId, this.sourceLine,
+      this.sourceColumn, this.sourceNameId]);
 
   String toString() => '$runtimeType: '
       '($column, $sourceUrlId, $sourceLine, $sourceColumn, $sourceNameId)';
diff --git a/pubspec.yaml b/pubspec.yaml
index 83c59a3..71cbfb5 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,9 +1,9 @@
 name: source_maps
-version: 0.9.0
-author: "Dart Team <misc@dartlang.org>"
-homepage: http://www.dartlang.org
+version: 0.9.1-dev
+author: Dart Team <misc@dartlang.org>
 description: Library to programmatically manipulate source map files.
-dev_dependencies:
-  unittest: ">=0.9.0 <0.10.0"
+homepage: http://www.dartlang.org
 environment:
-  sdk: ">=0.8.10+6 <2.0.0"
+  sdk: '>=0.8.10+6 <2.0.0'
+dev_dependencies:
+  unittest: '>=0.9.0 <0.10.0'
diff --git a/test/parser_test.dart b/test/parser_test.dart
index c99acb2..afdd7fb 100644
--- a/test/parser_test.dart
+++ b/test/parser_test.dart
@@ -9,6 +9,33 @@
 import 'package:source_maps/source_maps.dart';
 import 'common.dart';
 
+const Map<String, dynamic> MAP_WITH_NO_SOURCE_LOCATION = const {
+    'version': 3,
+    'sourceRoot': '',
+    'sources': const ['input.dart'],
+    'names': const [],
+    'mappings': 'A',
+    'file': 'output.dart'
+};
+
+const Map<String, dynamic> MAP_WITH_SOURCE_LOCATION = const {
+    'version': 3,
+    'sourceRoot': '',
+    'sources': const ['input.dart'],
+    'names': const [],
+    'mappings': 'AAAA',
+    'file': 'output.dart'
+};
+
+const Map<String, dynamic> MAP_WITH_SOURCE_LOCATION_AND_NAME = const {
+    'version': 3,
+    'sourceRoot': '',
+    'sources': const ['input.dart'],
+    'names': const ['var'],
+    'mappings': 'AAAAA',
+    'file': 'output.dart'
+};
+
 main() {
   test('parse', () {
     var mapping = parseJson(EXPECTED_MAP);
@@ -33,4 +60,43 @@
     check(outputFunction, mapping, inputFunction, true);
     check(outputExpr, mapping, inputExpr, true);
   });
+
+  test('parse with no source location', () {
+    SingleMapping map = parse(JSON.encode(MAP_WITH_NO_SOURCE_LOCATION));
+    expect(map.lines.length, 1);
+    expect(map.lines.first.entries.length, 1);
+    TargetEntry entry = map.lines.first.entries.first;
+
+    expect(entry.column, 0);
+    expect(entry.sourceUrlId, null);
+    expect(entry.sourceColumn, null);
+    expect(entry.sourceLine, null);
+    expect(entry.sourceNameId, null);
+  });
+
+  test('parse with source location and no name', () {
+    SingleMapping map = parse(JSON.encode(MAP_WITH_SOURCE_LOCATION));
+    expect(map.lines.length, 1);
+    expect(map.lines.first.entries.length, 1);
+    TargetEntry entry = map.lines.first.entries.first;
+
+    expect(entry.column, 0);
+    expect(entry.sourceUrlId, 0);
+    expect(entry.sourceColumn, 0);
+    expect(entry.sourceLine, 0);
+    expect(entry.sourceNameId, null);
+  });
+
+  test('parse with source location and name', () {
+    SingleMapping map = parse(JSON.encode(MAP_WITH_SOURCE_LOCATION_AND_NAME));
+    expect(map.lines.length, 1);
+    expect(map.lines.first.entries.length, 1);
+    TargetEntry entry = map.lines.first.entries.first;
+
+    expect(entry.sourceUrlId, 0);
+    expect(entry.sourceUrlId, 0);
+    expect(entry.sourceColumn, 0);
+    expect(entry.sourceLine, 0);
+    expect(entry.sourceNameId, 0);
+  });
 }