pkg/csslib: fixes for args

R=jmesserly@google.com, rnystrom@google.com

Review URL: https://codereview.chromium.org//1022963002
diff --git a/CHANGELOG.md b/CHANGELOG.md
index df9123c..beac1ec 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,10 @@
+## 0.12.0
+
+* Top-level methods in `parser.dart` now take `PreprocessorOptions` instead of
+  `List<String>`.
+
+* `PreprocessorOptions.inputFile` is now final.
+
 ## 0.11.0+4
 
 * Cleanup some ambiguous and some incorrect type signatures.
diff --git a/example/call_parser.dart b/example/call_parser.dart
index 3248f7f..7179a17 100644
--- a/example/call_parser.dart
+++ b/example/call_parser.dart
@@ -4,17 +4,22 @@
 import 'package:csslib/parser.dart' as css;
 import 'package:csslib/visitor.dart';
 
+const _default = const css.PreprocessorOptions(
+    useColors: false,
+    checked: true,
+    warningsAsErrors: true,
+    inputFile: 'memory');
+
 /**
  * Spin-up CSS parser in checked mode to detect any problematic CSS.  Normally,
  * CSS will allow any property/value pairs regardless of validity; all of our
  * tests (by default) will ensure that the CSS is really valid.
  */
-StyleSheet parseCss(String cssInput, {List errors, List opts}) => css.parse(
-    cssInput,
-    errors: errors,
-    options: opts == null
-        ? ['--no-colors', '--checked', '--warnings_as_errors', 'memory']
-        : opts);
+StyleSheet parseCss(String cssInput,
+    {List errors, css.PreprocessorOptions opts}) {
+  return css.parse(cssInput,
+      errors: errors, options: opts == null ? _default : opts);
+}
 
 // Pretty printer for CSS.
 var emitCss = new CssPrinter();
diff --git a/lib/parser.dart b/lib/parser.dart
index 25c329d..9d27e97 100644
--- a/lib/parser.dart
+++ b/lib/parser.dart
@@ -12,6 +12,8 @@
 import 'src/messages.dart';
 import 'src/options.dart';
 
+export 'src/options.dart';
+
 part 'src/analyzer.dart';
 part 'src/polyfill.dart';
 part 'src/property.dart';
@@ -30,14 +32,14 @@
 }
 
 // TODO(jmesserly): this should not be global
-void _createMessages({List<Message> errors, List<String> options}) {
+void _createMessages({List<Message> errors, PreprocessorOptions options}) {
   if (errors == null) errors = [];
 
   if (options == null) {
-    options = ['--no-colors', 'memory'];
+    options = new PreprocessorOptions(useColors: false, inputFile: 'memory');
   }
-  var opt = PreprocessorOptions.parse(options);
-  messages = new Messages(options: opt, printHandler: errors.add);
+
+  messages = new Messages(options: options, printHandler: errors.add);
 }
 
 /** CSS checked mode enabled. */
@@ -45,7 +47,7 @@
 
 // TODO(terry): Remove nested name parameter.
 /** Parse and analyze the CSS file. */
-StyleSheet compile(input, {List<Message> errors, List<String> options,
+StyleSheet compile(input, {List<Message> errors, PreprocessorOptions options,
     bool nested: true, bool polyfill: false, List<StyleSheet> includes: null}) {
   if (includes == null) {
     includes = [];
@@ -71,7 +73,7 @@
 
 /** Analyze the CSS file. */
 void analyze(List<StyleSheet> styleSheets,
-    {List<Message> errors, List<String> options}) {
+    {List<Message> errors, PreprocessorOptions options}) {
   _createMessages(errors: errors, options: options);
   new Analyzer(styleSheets, messages).run();
 }
@@ -81,7 +83,7 @@
  * or [List<int>] of bytes and returns a [StyleSheet] AST.  The optional
  * [errors] list will contain each error/warning as a [Message].
  */
-StyleSheet parse(input, {List<Message> errors, List<String> options}) {
+StyleSheet parse(input, {List<Message> errors, PreprocessorOptions options}) {
   var source = _inputAsString(input);
 
   _createMessages(errors: errors, options: options);
diff --git a/lib/src/messages.dart b/lib/src/messages.dart
index d8abcab..595bf6c 100644
--- a/lib/src/messages.dart
+++ b/lib/src/messages.dart
@@ -124,10 +124,7 @@
   void mergeMessages(Messages newMessages) {
     messages.addAll(newMessages.messages);
     newMessages.messages
-        .where(
-            (message) => message.level.value == Level.SEVERE || options.verbose)
-        .forEach((message) {
-      printHandler(message);
-    });
+        .where((message) => message.level == Level.SEVERE || options.verbose)
+        .forEach(printHandler);
   }
 }
diff --git a/lib/src/options.dart b/lib/src/options.dart
index 0ebb5b4..95e8a2f 100644
--- a/lib/src/options.dart
+++ b/lib/src/options.dart
@@ -38,10 +38,12 @@
   final bool useColors;
 
   /** File to process by the compiler. */
-  String inputFile;
+  final String inputFile;
 
-  // We could make this faster, if it ever matters.
-  factory PreprocessorOptions() => parse(['']);
+  const PreprocessorOptions({this.verbose: false, this.checked: false,
+      this.lessSupport: true, this.warningsAsErrors: false,
+      this.throwOnErrors: false, this.throwOnWarnings: false,
+      this.useColors: true, this.polyfill: false, this.inputFile});
 
   PreprocessorOptions.fromArgs(ArgResults args)
       : warningsAsErrors = args['warnings_as_errors'],
diff --git a/pubspec.yaml b/pubspec.yaml
index b168432..5ef264a 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,15 +1,15 @@
 name: csslib
-version: 0.11.1-dev
+version: 0.12.0
 author: Polymer.dart Team <web-ui-dev@dartlang.org>
 description: A library for parsing CSS.
 homepage: https://github.com/dart-lang/csslib
 environment:
   sdk: '>=1.1.0 <2.0.0'
 dependencies:
-  args: '>=0.9.0 <0.13.0'
+  args: '>=0.9.0 <0.14.0'
   logging: '>=0.9.0 <0.10.0'
   path: '>=0.9.0 <2.0.0'
   source_span: '>=1.0.0 <2.0.0'
 dev_dependencies:
-  browser: '>=0.9.0 <0.10.0'
-  unittest: '>=0.9.0 <0.10.0'
+  browser: '>=0.9.0 <0.11.0'
+  unittest: '>=0.9.0 <0.12.0'
diff --git a/test/big_1_test.dart b/test/big_1_test.dart
index ed1c271..5f38ba0 100644
--- a/test/big_1_test.dart
+++ b/test/big_1_test.dart
@@ -7,8 +7,6 @@
 import 'package:unittest/unittest.dart';
 import 'testing.dart';
 
-var options = ['--warnings_as_errors', '--no-colors', 'memory'];
-
 compilePolyfillAndValidate(String input, String generated) {
   var errors = [];
   var stylesheet = polyFillCompileCss(input, errors: errors, opts: options);
diff --git a/test/compiler_test.dart b/test/compiler_test.dart
index a7cdf4a..5d5dcf5 100644
--- a/test/compiler_test.dart
+++ b/test/compiler_test.dart
@@ -584,8 +584,7 @@
 div:nth-child(2n) { color : red; }
 ''';
 
-  var stylesheet =
-      parseCss(input, errors: errors, opts: ['--no-colors', 'memory']);
+  var stylesheet = parseCss(input, errors: errors, opts: simpleOptions);
 
   expect(stylesheet != null, true);
   expect(errors.isEmpty, true, reason: errors.toString());
@@ -655,8 +654,7 @@
       '*:hover { font-weight: bold; }'
       ':nth-child(odd) { color: blue; }'
       '}';
-  var stylesheet =
-      parseCss(input, errors: errors, opts: ['--no-colors', 'memory']);
+  var stylesheet = parseCss(input, errors: errors, opts: simpleOptions);
 
   expect(stylesheet != null, true);
   expect(errors.isEmpty, true, reason: errors.toString());
diff --git a/test/declaration_test.dart b/test/declaration_test.dart
index 0cf012c..f01b804 100644
--- a/test/declaration_test.dart
+++ b/test/declaration_test.dart
@@ -7,9 +7,6 @@
 import 'package:unittest/unittest.dart';
 import 'testing.dart';
 
-/** CSS compiler options no checks in in memory style sheet. */
-List options = ['--no-colors', 'memory'];
-
 void testSimpleTerms() {
   var errors = [];
   final String input = r'''
@@ -236,7 +233,7 @@
   transform: rotatez(20turn);
 }''';
 
-  var stylesheet = parseCss(input, errors: errors, opts: options);
+  var stylesheet = parseCss(input, errors: errors, opts: simpleOptions);
 
   expect(stylesheet != null, true);
   expect(errors.isEmpty, true, reason: errors.toString());
@@ -339,7 +336,7 @@
 }
 }''';
 
-  var stylesheet = parseCss(input, errors: errors, opts: options);
+  var stylesheet = parseCss(input, errors: errors, opts: simpleOptions);
   expect(stylesheet != null, true);
   expect(errors.isEmpty, true, reason: errors.toString());
   expect(prettyPrint(stylesheet), generated);
@@ -384,7 +381,7 @@
 }
 }''';
 
-  stylesheet = parseCss(input, errors: errors..clear(), opts: options);
+  stylesheet = parseCss(input, errors: errors..clear(), opts: simpleOptions);
 
   expect(stylesheet != null, true);
   expect(errors.isEmpty, true, reason: errors.toString());
@@ -401,7 +398,7 @@
       'AND (min-device-height:2000px), screen (another:100px) {\n'
       'html {\n  font-size: 10em;\n}\n}';
 
-  stylesheet = parseCss(input, errors: errors..clear(), opts: options);
+  stylesheet = parseCss(input, errors: errors..clear(), opts: simpleOptions);
 
   expect(stylesheet != null, true);
   expect(errors.isEmpty, true, reason: errors.toString());
@@ -418,7 +415,7 @@
       '(min-device-height:2000px), screen (another:100px) {\n'
       'html {\n  font-size: 10em;\n}\n}';
 
-  stylesheet = parseCss(input, errors: errors..clear(), opts: options);
+  stylesheet = parseCss(input, errors: errors..clear(), opts: simpleOptions);
 
   expect(stylesheet != null, true);
   expect(errors.isEmpty, true, reason: errors.toString());
@@ -429,7 +426,7 @@
   generated =
       '@import "test.css" ONLY screen, NOT print (min-device-width:4000px);';
 
-  stylesheet = parseCss(input, errors: errors..clear(), opts: options);
+  stylesheet = parseCss(input, errors: errors..clear(), opts: simpleOptions);
 
   expect(stylesheet != null, true);
   expect(errors.isEmpty, true, reason: errors.toString());
@@ -450,7 +447,7 @@
   src: url("fonts/BBCBengali.ttf") format("opentype");
   unicode-range: U+0A-FF, U+980-9FF, U+????, U+3???;
 }''';
-  var stylesheet = parseCss(input, errors: errors, opts: options);
+  var stylesheet = parseCss(input, errors: errors, opts: simpleOptions);
 
   expect(stylesheet != null, true);
   expect(errors.isEmpty, true, reason: errors.toString());
@@ -468,7 +465,7 @@
   src: url("http://example.com/fonts/Gentium.ttf");
 }''';
 
-  stylesheet = parseCss(input1, errors: errors..clear(), opts: options);
+  stylesheet = parseCss(input1, errors: errors..clear(), opts: simpleOptions);
 
   expect(stylesheet != null, true);
   expect(errors.isEmpty, true, reason: errors.toString());
@@ -485,7 +482,7 @@
       'format("woff"), url("basic-sans-serif.ttf") '
       'format("opentype"), local(Gentium Bold);\n}';
 
-  stylesheet = parseCss(input2, errors: errors..clear(), opts: options);
+  stylesheet = parseCss(input2, errors: errors..clear(), opts: simpleOptions);
 
   expect(stylesheet != null, true);
   expect(errors.isEmpty, true, reason: errors.toString());
@@ -504,7 +501,7 @@
   font-weight: bold;
 }''';
 
-  stylesheet = parseCss(input3, errors: errors..clear(), opts: options);
+  stylesheet = parseCss(input3, errors: errors..clear(), opts: simpleOptions);
 
   expect(stylesheet != null, true);
   expect(errors.isEmpty, true, reason: errors.toString());
@@ -521,7 +518,7 @@
   src: local(STIXGeneral), url("/stixfonts/STIXGeneral.otf");
   unicode-range: U+000-49F, U+2000-27FF, U+2900-2BFF, U+1D400-1D7FF;
 }''';
-  stylesheet = parseCss(input4, errors: errors..clear(), opts: options);
+  stylesheet = parseCss(input4, errors: errors..clear(), opts: simpleOptions);
 
   expect(stylesheet != null, true);
   expect(errors.isEmpty, true, reason: errors.toString());
@@ -703,7 +700,7 @@
   color: #00f;
 }''';
 
-  var stylesheet = parseCss(input, errors: errors, opts: options);
+  var stylesheet = parseCss(input, errors: errors, opts: simpleOptions);
 
   expect(stylesheet != null, true);
   expect(errors.isEmpty, true, reason: errors.toString());
@@ -721,7 +718,7 @@
       "(GradientType=0,StartColorStr='#9d8b83', EndColorStr='#847670');\n"
       "}";
 
-  var stylesheet = parseCss(input, errors: errors, opts: options);
+  var stylesheet = parseCss(input, errors: errors, opts: simpleOptions);
 
   expect(stylesheet != null, true);
   expect(errors.isEmpty, true, reason: errors.toString());
@@ -739,7 +736,7 @@
       "         progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1);\n"
       "}";
 
-  stylesheet = parseCss(input2, errors: errors..clear(), opts: options);
+  stylesheet = parseCss(input2, errors: errors..clear(), opts: simpleOptions);
 
   expect(stylesheet != null, true);
   expect(errors.isEmpty, true, reason: errors.toString());
@@ -769,7 +766,7 @@
       '      FinishX=0, FinishY=0)  Wave(Add=0, Freq=5, LightStrength=20, \n'
       '      Phase=220, Strength=10);\n}';
 
-  stylesheet = parseCss(input3, errors: errors..clear(), opts: options);
+  stylesheet = parseCss(input3, errors: errors..clear(), opts: simpleOptions);
 
   expect(stylesheet != null, true);
   expect(errors.isEmpty, true, reason: errors.toString());
@@ -946,19 +943,18 @@
   }
 }''';
 
-  var stylesheet = parseCss(input, errors: errors, opts: options);
+  var stylesheet = parseCss(input, errors: errors, opts: simpleOptions);
   expect(stylesheet != null, true);
   expect(errors.isEmpty, true, reason: errors.toString());
   expect(prettyPrint(stylesheet), generated);
 }
 
 void testHangs() {
-  final optionErrors = ['--no-colors', '--warnings_as_errors', 'memory'];
   var errors = [];
 
   // Bad hexvalue had caused a hang in processTerm.
   final input = r'''#a { color: #ebebeburl(0/IE8+9+); }''';
-  var stylesheet = parseCss(input, errors: errors, opts: optionErrors);
+  var stylesheet = parseCss(input, errors: errors, opts: options);
 
   expect(stylesheet != null, true);
   expect(errors.length, 3, reason: errors.toString());
@@ -994,7 +990,7 @@
   }
 ''';
 
-  stylesheet = parseCss(input2, errors: errors..clear(), opts: optionErrors);
+  stylesheet = parseCss(input2, errors: errors..clear(), opts: options);
 
   expect(stylesheet != null, true);
 
diff --git a/test/extend_test.dart b/test/extend_test.dart
index ed24b35..94d9e7b 100644
--- a/test/extend_test.dart
+++ b/test/extend_test.dart
@@ -7,8 +7,6 @@
 import 'package:unittest/unittest.dart';
 import 'testing.dart';
 
-var options = ['--warnings_as_errors', '--no-colors', 'memory'];
-
 compileAndValidate(String input, String generated) {
   var errors = [];
   var stylesheet = compileCss(input, errors: errors, opts: options);
diff --git a/test/mixin_test.dart b/test/mixin_test.dart
index 5c5a0fc..937ed44 100644
--- a/test/mixin_test.dart
+++ b/test/mixin_test.dart
@@ -7,8 +7,6 @@
 import 'package:unittest/unittest.dart';
 import 'testing.dart';
 
-final options = ['--warnings_as_errors', '--no-colors', 'memory'];
-
 compileAndValidate(String input, String generated) {
   var errors = [];
   var stylesheet = compileCss(input, errors: errors, opts: options);
diff --git a/test/nested_test.dart b/test/nested_test.dart
index 2a46da7..db25679 100644
--- a/test/nested_test.dart
+++ b/test/nested_test.dart
@@ -7,11 +7,9 @@
 import 'package:unittest/unittest.dart';
 import 'testing.dart';
 
-List optionsCss = ['--no-colors', 'memory'];
-
 compileAndValidate(String input, String generated) {
   var errors = [];
-  var stylesheet = compileCss(input, errors: errors, opts: optionsCss);
+  var stylesheet = compileCss(input, errors: errors, opts: simpleOptions);
   expect(stylesheet != null, true);
   expect(errors.isEmpty, true, reason: errors.toString());
   expect(prettyPrint(stylesheet), generated);
diff --git a/test/testing.dart b/test/testing.dart
index b9a6738..df65532 100644
--- a/test/testing.dart
+++ b/test/testing.dart
@@ -8,6 +8,21 @@
 import 'package:csslib/parser.dart';
 import 'package:csslib/visitor.dart';
 import 'package:csslib/src/messages.dart';
+import 'package:csslib/src/options.dart';
+
+export 'package:csslib/src/options.dart';
+
+const simpleOptionsWithCheckedAndWarningsAsErrors = const PreprocessorOptions(
+    useColors: false,
+    checked: true,
+    warningsAsErrors: true,
+    inputFile: 'memory');
+
+const simpleOptions =
+    const PreprocessorOptions(useColors: false, inputFile: 'memory');
+
+const options = const PreprocessorOptions(
+    useColors: false, warningsAsErrors: true, inputFile: 'memory');
 
 void useMockMessages() {
   messages = new Messages(printHandler: (message) {});
@@ -19,10 +34,10 @@
  * tests (by default) will ensure that the CSS is really valid.
  */
 StyleSheet parseCss(String cssInput,
-    {List<Message> errors, List<String> opts}) => parse(cssInput,
+    {List<Message> errors, PreprocessorOptions opts}) => parse(cssInput,
         errors: errors,
         options: opts == null
-            ? ['--no-colors', '--checked', '--warnings_as_errors', 'memory']
+            ? simpleOptionsWithCheckedAndWarningsAsErrors
             : opts);
 
 /**
@@ -30,17 +45,18 @@
  * CSS will allow any property/value pairs regardless of validity; all of our
  * tests (by default) will ensure that the CSS is really valid.
  */
-StyleSheet compileCss(String cssInput, {List<Message> errors, List<String> opts,
-    bool polyfill: false, List<StyleSheet> includes: null}) => compile(cssInput,
+StyleSheet compileCss(String cssInput, {List<Message> errors,
+    PreprocessorOptions opts, bool polyfill: false,
+    List<StyleSheet> includes: null}) => compile(cssInput,
         errors: errors,
         options: opts == null
-            ? ['--no-colors', '--checked', '--warnings_as_errors', 'memory']
+            ? simpleOptionsWithCheckedAndWarningsAsErrors
             : opts,
         polyfill: polyfill,
         includes: includes);
 
 StyleSheet polyFillCompileCss(input,
-        {List<Message> errors, List<String> opts}) =>
+        {List<Message> errors, PreprocessorOptions opts}) =>
     compileCss(input, errors: errors, polyfill: true, opts: opts);
 
 /** CSS emitter walks the style sheet tree and emits readable CSS. */
diff --git a/test/var_test.dart b/test/var_test.dart
index 17349b8..657459d 100644
--- a/test/var_test.dart
+++ b/test/var_test.dart
@@ -7,8 +7,6 @@
 import 'package:unittest/unittest.dart';
 import 'testing.dart';
 
-List options = ['--no-colors', '--warnings_as_errors', 'memory'];
-
 compileAndValidate(String input, String generated) {
   var errors = [];
   var stylesheet = compileCss(input, errors: errors, opts: options);
@@ -644,8 +642,7 @@
   color: var(color-foreground);
 }''';
 
-  var stylesheet =
-      parseCss(input, errors: errors, opts: ['--no-colors', 'memory']);
+  var stylesheet = parseCss(input, errors: errors, opts: simpleOptions);
 
   expect(stylesheet != null, true);
   expect(errors.isEmpty, true, reason: errors.toString());
@@ -670,8 +667,7 @@
   color: var(color-foreground);
 }''';
 
-  stylesheet =
-      parseCss(input, errors: errors..clear(), opts: ['--no-colors', 'memory']);
+  stylesheet = parseCss(input, errors: errors..clear(), opts: simpleOptions);
 
   expect(stylesheet != null, true);
   expect(errors.isEmpty, true, reason: errors.toString());
@@ -699,8 +695,7 @@
   color: var(color-foreground);
 }''';
 
-  var stylesheet =
-      parseCss(input, errors: errors, opts: ['--no-colors', 'memory']);
+  var stylesheet = parseCss(input, errors: errors, opts: simpleOptions);
 
   expect(stylesheet != null, true);
   expect(errors.isEmpty, true, reason: errors.toString());
@@ -725,8 +720,7 @@
   color: var(color-foreground);
 }''';
 
-  stylesheet =
-      parseCss(input, errors: errors..clear(), opts: ['--no-colors', 'memory']);
+  stylesheet = parseCss(input, errors: errors..clear(), opts: simpleOptions);
 
   expect(stylesheet != null, true);
   expect(errors.isEmpty, true, reason: errors.toString());
diff --git a/test/visitor_test.dart b/test/visitor_test.dart
index 1777748..e7102de 100644
--- a/test/visitor_test.dart
+++ b/test/visitor_test.dart
@@ -49,7 +49,7 @@
       div.hello { font: arial; }
     ''';
 
-  s = parseCss(in1, errors: errors..clear(), opts: ['--no-colors', 'memory']);
+  s = parseCss(in1, errors: errors..clear(), opts: simpleOptions);
 
   expect(s != null, true);
   expect(errors.isEmpty, true, reason: errors.toString());