- THRIFT-5712 - Added Dart 3 Compatibility
diff --git a/tutorial/dart/Makefile.am b/tutorial/dart/Makefile.am
index e29e3c5..17c16ab 100644
--- a/tutorial/dart/Makefile.am
+++ b/tutorial/dart/Makefile.am
@@ -19,6 +19,9 @@
 
 BUILT_SOURCES = gen-dart/tutorial/lib/tutorial.dart gen-dart/shared/lib/shared.dart
 
+# Use 'dart pub' if 'pub' command is not available
+DARTPUB = dart pub
+
 gen-dart/tutorial/lib/tutorial.dart gen-dart/shared/lib/shared.dart: $(top_srcdir)/tutorial/tutorial.thrift
 	$(THRIFT) --gen dart -r $<
 
diff --git a/tutorial/dart/client/pubspec.yaml b/tutorial/dart/client/pubspec.yaml
index a8c148d..4ffaa42 100644
--- a/tutorial/dart/client/pubspec.yaml
+++ b/tutorial/dart/client/pubspec.yaml
@@ -22,7 +22,7 @@
 homepage: http://thrift.apache.org
 
 environment:
-  sdk: ">=1.13.0 <3.0.0"
+  sdk: ">=2.12.0 <4.0.0"
 
 dependencies:
   shared:
diff --git a/tutorial/dart/client/web/client.dart b/tutorial/dart/client/web/client.dart
index 4f02d0d..be5cfe6 100644
--- a/tutorial/dart/client/web/client.dart
+++ b/tutorial/dart/client/web/client.dart
@@ -24,7 +24,7 @@
 
 /// Adapted from the AS3 tutorial
 void main() {
-  new CalculatorUI(querySelector('#output')).start();
+  new CalculatorUI(querySelector('#output') as DivElement ).start();
 }
 
 class CalculatorUI {
@@ -32,8 +32,8 @@
 
   CalculatorUI(this.output);
 
-  TTransport _transport;
-  Calculator _calculatorClient;
+  late TTransport _transport;
+  late Calculator _calculatorClient;
 
   void start() {
     _buildInterface();
@@ -120,12 +120,12 @@
   void _onAddClick(MouseEvent e) {
     _validate();
 
-    InputElement num1 = querySelector("#add1");
-    InputElement num2 = querySelector("#add2");
-    SpanElement result = querySelector("#addResult");
+    InputElement num1 = querySelector("#add1") as InputElement;
+    InputElement num2 = querySelector("#add2")as InputElement;
+    SpanElement result = querySelector("#addResult") as SpanElement;
 
     _calculatorClient
-        .add(int.parse(num1.value), int.parse(num2.value))
+        .add(int.parse(num1.value ?? "0"), int.parse(num2.value ?? "0"))
         .then((int n) {
       result.text = "$n";
     });
@@ -211,21 +211,21 @@
   void _onCalcClick(MouseEvent e) {
     _validate();
 
-    InputElement num1 = querySelector("#calc1");
-    InputElement num2 = querySelector("#calc2");
-    SelectElement op = querySelector("#calcOp");
-    SpanElement result = querySelector("#calcResult");
-    InputElement logId = querySelector("#logId");
-    InputElement comment = querySelector("#comment");
+    InputElement num1 = querySelector("#calc1") as InputElement;
+    InputElement num2 = querySelector("#calc2")as InputElement;
+    SelectElement op = querySelector("#calcOp") as SelectElement;
+    SpanElement result = querySelector("#calcResult") as SpanElement;
+    InputElement logId = querySelector("#logId") as InputElement;
+    InputElement comment = querySelector("#comment") as InputElement;
 
-    int logIdValue = int.parse(logId.value);
+    int logIdValue = int.parse(logId.value ?? "0");
     logId.value = (logIdValue + 1).toString();
 
     Work work = new Work();
-    work.num1 = int.parse(num1.value);
-    work.num2 = int.parse(num2.value);
-    work.op = int.parse(op.options[op.selectedIndex].value);
-    work.comment = comment.value;
+    work.num1 = int.parse(num1.value!);
+    work.num2 = int.parse(num2.value!);
+    work.op = int.parse(op.options[op.selectedIndex!].value);
+    work.comment = comment.value!;
 
     _calculatorClient.calculate(logIdValue, work).then((int n) {
       result.text = "$n";
@@ -266,13 +266,13 @@
   void _onGetStructClick(MouseEvent e) {
     _validate();
 
-    InputElement structKey = querySelector("#structKey");
-    TextAreaElement result = querySelector("#getStructResult");
+    InputElement structKey = querySelector("#structKey") as InputElement;
+    TextAreaElement result = querySelector("#getStructResult") as TextAreaElement;
 
     _calculatorClient
-        .getStruct(int.parse(structKey.value))
-        .then((SharedStruct s) {
-      result.text = "${s.toString()}";
+        .getStruct(int.parse(structKey.value!))
+        .then((SharedStruct? s) {
+      result.text = "${s?.toString()}";
     });
   }
 }
diff --git a/tutorial/dart/console_client/bin/main.dart b/tutorial/dart/console_client/bin/main.dart
index fda206a..992c3f8 100644
--- a/tutorial/dart/console_client/bin/main.dart
+++ b/tutorial/dart/console_client/bin/main.dart
@@ -24,8 +24,8 @@
 import 'package:thrift/thrift_console.dart';
 import 'package:tutorial/tutorial.dart';
 
-TTransport _transport;
-Calculator _calculator;
+late TTransport _transport;
+late Calculator _calculator;
 int logid = 0;
 
 const Map<String, int> operationLookup = const {
@@ -44,7 +44,7 @@
   var parser = new ArgParser();
   parser.addOption('port', defaultsTo: '9090', help: 'The port to connect to');
 
-  ArgResults results;
+  ArgResults? results;
   try {
     results = parser.parse(args);
   } catch (e) {
@@ -77,9 +77,9 @@
   while (true) {
     stdout.write("> ");
     var input = stdin.readLineSync();
-    var parts = input.split(' ');
-    var command = parts[0];
-    var args = parts.length > 1 ? parts.sublist(1) : [];
+    var parts = input?.split(' ');
+    var command = parts?[0];
+    var args = parts!.length > 1 ? parts.sublist(1) : [];
 
     switch (command) {
       case 'ping':
@@ -91,7 +91,7 @@
         break;
 
       case 'calc':
-        int op = operationLookup[args[1]];
+        int? op = operationLookup[args[1]];
         if (!Operation.VALID_VALUES.contains(op)) {
           stdout.writeln('Unknown operator ${args[1]}');
           break;
@@ -99,7 +99,7 @@
 
         var work = new Work()
           ..num1 = int.parse(args[0])
-          ..op = op
+          ..op = op!
           ..num2 = int.parse(args[2])
           ..comment = args.length > 3 ? args[3] : '';
 
diff --git a/tutorial/dart/console_client/pubspec.yaml b/tutorial/dart/console_client/pubspec.yaml
index 0e2389b..9125e23 100644
--- a/tutorial/dart/console_client/pubspec.yaml
+++ b/tutorial/dart/console_client/pubspec.yaml
@@ -23,10 +23,10 @@
 homepage: http://thrift.apache.org
 
 environment:
-  sdk: ">=1.13.0 <3.0.0"
+  sdk: ">=2.12.0 <4.0.0"
 
 dependencies:
-  args: ">=0.13.0 <2.0.0"
+  args: ^2.4.2
   collection: ^1.1.0
   shared:
     path: ../gen-dart/shared
diff --git a/tutorial/dart/server/bin/main.dart b/tutorial/dart/server/bin/main.dart
index b8ac30d..3926777 100644
--- a/tutorial/dart/server/bin/main.dart
+++ b/tutorial/dart/server/bin/main.dart
@@ -25,9 +25,9 @@
 import 'package:tutorial/tutorial.dart';
 import 'package:shared/shared.dart';
 
-TProtocol _protocol;
-TProcessor _processor;
-WebSocket _webSocket;
+late TProtocol _protocol;
+late TProcessor _processor;
+late WebSocket _webSocket;
 
 main(List<String> args) {
   Logger.root.level = Level.ALL;
@@ -38,12 +38,12 @@
   var parser = new ArgParser();
   parser.addOption('port', defaultsTo: '9090', help: 'The port to listen on');
   parser.addOption('type',
-      defaultsTo: 'ws',
+      defaultsTo: 'tcp',
       allowed: ['ws', 'tcp'],
       help: 'The type of socket',
       allowedHelp: {'ws': 'WebSocket', 'tcp': 'TCP Socket'});
 
-  ArgResults results;
+  ArgResults? results;
   try {
     results = parser.parse(args);
   } catch (e) {
@@ -114,12 +114,12 @@
     return num1 + num2;
   }
 
-  Future<int> calculate(int logid, Work work) async {
+  Future<int> calculate(int logid, Work? work) async {
     print('calulate($logid, ${work.toString()})');
 
-    int val;
+    late int val;
 
-    switch (work.op) {
+    switch (work!.op) {
       case Operation.ADD:
         val = work.num1 + work.num2;
         break;
@@ -155,7 +155,7 @@
     print('zip()');
   }
 
-  Future<SharedStruct> getStruct(int key) async {
+  Future<SharedStruct?> getStruct(int key) async {
     print('getStruct($key)');
 
     return _log[key];
diff --git a/tutorial/dart/server/pubspec.yaml b/tutorial/dart/server/pubspec.yaml
index 3cca54e..e15874a 100644
--- a/tutorial/dart/server/pubspec.yaml
+++ b/tutorial/dart/server/pubspec.yaml
@@ -22,10 +22,10 @@
 homepage: http://thrift.apache.org
 
 environment:
-  sdk: ">=1.13.0 <3.0.0"
+  sdk: ">=2.12.0 <4.0.0"
 
 dependencies:
-  args: ">=0.13.0 <2.0.0"
+  args: "^2.4.2"
   shared:
     path: ../gen-dart/shared
   thrift: