stable null safety release (#355)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 16b95ac..a8d494f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,7 +1,7 @@
-## 4.0.0-dev
+## 4.0.0
 
-* Update `args` dep to allow the latest stable, update all `-nullsafety`
-  pre-release deps to depend on stable versions.
+* Stable null safety release.
+* Require the latest `args`, update the markdown executable to be opted in.
 
 ## 4.0.0-nullsafety.0
 
diff --git a/bin/markdown.dart b/bin/markdown.dart
index 5844354..fd4eee2 100644
--- a/bin/markdown.dart
+++ b/bin/markdown.dart
@@ -2,8 +2,6 @@
 // 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.
 
-// @dart=2.9
-
 import 'dart:async';
 import 'dart:io';
 
@@ -60,7 +58,7 @@
 
   // Read from stdin.
   var buffer = StringBuffer();
-  String line;
+  String? line;
   while ((line = stdin.readLineSync()) != null) {
     buffer.writeln(line);
   }
diff --git a/lib/src/version.dart b/lib/src/version.dart
index e460372..66803ec 100644
--- a/lib/src/version.dart
+++ b/lib/src/version.dart
@@ -1,2 +1,2 @@
 // Generated code. Do not modify.
-const packageVersion = '4.0.0-dev';
+const packageVersion = '4.0.0';
diff --git a/pubspec.yaml b/pubspec.yaml
index e93f86a..2832eb5 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,5 +1,5 @@
 name: markdown
-version: 4.0.0-dev
+version: 4.0.0
 
 description: A portable Markdown library written in Dart that can parse
  Markdown into HTML.
@@ -12,7 +12,7 @@
   sdk: '>=2.12.0-0 <3.0.0'
 
 dependencies:
-  args: '>=1.0.0 <3.0.0'
+  args: ^2.0.0
   charcode: ^1.2.0
   meta: ^1.3.0
 
@@ -21,7 +21,7 @@
   build_version: ^2.0.0
   build_web_compilers: '>=1.0.0 <3.0.0'
   collection: ^1.15.0
-  html: '>=0.12.2 <0.15.0'
+  html: ^0.15.0-nullsafety
   io: ^0.3.2+1
   js: ^0.6.3
   path: ^1.8.0
diff --git a/tool/dartdoc-compare.dart b/tool/dartdoc-compare.dart
index dcd2bb0..052ca5e 100644
--- a/tool/dartdoc-compare.dart
+++ b/tool/dartdoc-compare.dart
@@ -2,8 +2,6 @@
 // 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.
 
-// @dart=2.9
-
 import 'dart:convert' show jsonEncode, jsonDecode;
 import 'dart:io' show Directory, File, Platform, Process, exitCode;
 
@@ -49,7 +47,7 @@
       absolute(options[_dartdocDir] as String, 'pubspec.yaml'),
       options[_sdk] as bool);
 
-  String path;
+  String? path;
   if (comparer.sdk) {
     if (options.rest.isNotEmpty) {
       path = options.rest.single;
@@ -77,7 +75,7 @@
   DartdocCompare(this.dartdocDir, this.markdownBefore, this.markdownAfter,
       this.dartdocBin, this.dartdocPubspecPath, this.sdk);
 
-  bool compare(String package) {
+  bool compare(String? package) {
     // Generate docs with Markdown "Before".
     var outBefore = _runDartdoc(markdownBefore, package);
 
@@ -93,7 +91,7 @@
     return result.exitCode == 0;
   }
 
-  String _runDartdoc(String markdownRef, String path) {
+  String _runDartdoc(String markdownRef, String? path) {
     print('==========================================================');
     print('Running dartdoc for $markdownRef...');
     print('==========================================================');
@@ -159,7 +157,7 @@
   return result.exitCode;
 }
 
-T _doInPath<T>(String path, T Function() f) {
+T _doInPath<T>(String? path, T Function() f) {
   if (path == null) {
     return f();
   }