Skip to content

Commit 5b4aef1

Browse files
Merge pull request #366 from Workiva/lints-and-implicit-casts-take-2
FED-1569 Prepare for null safety: fix lints and implicit casts
2 parents c02b780 + 60aec37 commit 5b4aef1

File tree

71 files changed

+1659
-1670
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

71 files changed

+1659
-1670
lines changed

.github/workflows/dart_ci.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ jobs:
1515
strategy:
1616
fail-fast: false
1717
matrix:
18-
# Can't run on `beta` (Dart 3) until we're fully null-safe.
19-
sdk: [2.18.7, stable]
18+
# Can't run on `stable` (Dart 3) until we're fully null-safe.
19+
sdk: [2.18.7]
2020
steps:
2121
- uses: actions/checkout@v2
2222
- uses: dart-lang/setup-dart@v1

analysis_options.yaml

+20-7
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,25 @@
1+
include: package:workiva_analysis_options/v2.recommended.yaml
2+
13
analyzer:
24
strong-mode:
5+
# TODO change to false as part of the null safety major, which avoids us having to add a lot more casts
36
implicit-casts: true
4-
implicit-dynamic: true
7+
errors:
8+
must_call_super: error
9+
comment_references: info
10+
# This is too noisy since it warns for all lifecycle methods.
11+
always_declare_return_types: ignore
12+
# We very often need to annotate parameters when they're embedded in Maps
13+
# with dynamic values, so this lint is noisy and wrong in those cases.
14+
# See: https://github.com/dart-lang/linter/issues/1099
15+
avoid_types_on_closure_parameters: ignore
16+
# This makes string concatenation less readable in some cases
17+
prefer_interpolation_to_compose_strings: ignore
18+
# The following are ignored to avoid merge conflicts with null safety branch
19+
directives_ordering: ignore
20+
prefer_typing_uninitialized_variables: ignore
521
linter:
622
rules:
7-
- avoid_private_typedef_functions
8-
- await_only_futures
9-
- cancel_subscriptions
10-
- close_sinks
11-
- unawaited_futures
12-
- avoid_init_to_null
23+
prefer_if_elements_to_conditional_expressions: false
24+
overridden_fields: false
25+
type_annotate_public_apis: false

example/geocodes/geocodes.dart

+39-41
Original file line numberDiff line numberDiff line change
@@ -6,32 +6,30 @@ import 'dart:html';
66
import 'package:react/react.dart' as react;
77
import 'package:react/react_dom.dart' as react_dom;
88

9-
/**
10-
* Hello,
11-
*
12-
* This is the Dart portion of the tutorial for the Dart react package.
13-
*
14-
* We'll go through a simple app that queries the Google Maps API and shows the result to the user.
15-
* It also stores the search history and allows the user to reload past queries.
16-
*
17-
* In this file you'll find the structure and the logic of the app. There is also a `geocodes.html` file which contains
18-
* the mount point.
19-
*
20-
* Be sure that you understand the basic concepts of [React](http://facebook.github.io/react/) before reading this
21-
* tutorial.
22-
*
23-
* Enjoy!
24-
*/
9+
/// Hello,
10+
///
11+
/// This is the Dart portion of the tutorial for the Dart react package.
12+
///
13+
/// We'll go through a simple app that queries the Google Maps API and shows the result to the user.
14+
/// It also stores the search history and allows the user to reload past queries.
15+
///
16+
/// In this file you'll find the structure and the logic of the app. There is also a `geocodes.html` file which contains
17+
/// the mount point.
18+
///
19+
/// Be sure that you understand the basic concepts of [React](https://reactjs.org/) before reading this
20+
/// tutorial.
21+
///
22+
/// Enjoy!
2523
2624
/// Divide your app into components and conquer!
2725
///
28-
/// This is the first custom [Component].
26+
/// This is the first custom `Component`.
2927
///
3028
/// It is just an HTML `<tr>` element displaying a single API response to the user.
3129
class _GeocodesResultItem extends react.Component {
3230
/// The only function you must implement in the custom component is [render].
3331
///
34-
/// Every [Component] has a map of properties called [Component.props]. It can be specified during creation.
32+
/// Every `Component` has a map of properties called `props`. It can be specified during creation.
3533
@override
3634
render() {
3735
return react.tr({}, [
@@ -42,13 +40,13 @@ class _GeocodesResultItem extends react.Component {
4240
}
4341
}
4442

45-
/// Now we need to tell ReactJS that our custom [Component] exists by calling [registerComponent].
43+
/// Now we need to tell ReactJS that our custom `Component` exists by calling `registerComponent`.
4644
///
4745
/// As a reward, it gives us a function, that takes the properties and returns our element. You'll see it in action
4846
/// shortly.
4947
///
50-
/// This is the only correct way to create a [Component]. Do not use the constructor!
51-
var geocodesResultItem = react.registerComponent(() => new _GeocodesResultItem());
48+
/// This is the only correct way to create a `Component`. Do not use the constructor!
49+
var geocodesResultItem = react.registerComponent(() => _GeocodesResultItem());
5250

5351
/// In this component we'll build an HTML `<table>` element full of the `<tr>` elements generated by
5452
/// [_GeocodesResultItem]
@@ -95,13 +93,13 @@ class _GeocodesResultList extends react.Component {
9593
}
9694
}
9795

98-
var geocodesResultList = react.registerComponent(() => new _GeocodesResultList());
96+
var geocodesResultList = react.registerComponent(() => _GeocodesResultList());
9997

100-
/// In this [Component] we'll build a search form.
98+
/// In this `Component` we'll build a search form.
10199
///
102-
/// This [Component] illustrates that:
100+
/// This `Component` illustrates that:
103101
///
104-
/// > The functions can be [Component] parameters _(handy for callbacks)_
102+
/// > The functions can be `Component` parameters _(handy for callbacks)_
105103
///
106104
/// > The DOM [Element]s can be accessed using `ref`s.
107105
class _GeocodesForm extends react.Component {
@@ -158,16 +156,16 @@ class _GeocodesForm extends react.Component {
158156
/// Handle form submission via `props.onSubmit`
159157
onFormSubmit(react.SyntheticEvent event) {
160158
event.preventDefault();
161-
InputElement inputElement = react_dom.findDOMNode(searchInputInstance);
159+
final inputElement = react_dom.findDOMNode(searchInputInstance);
162160
// The input's value is accessed.
163-
var address = inputElement.value;
161+
final address = inputElement.value;
164162
inputElement.value = '';
165163
// Call the callback from the parent element is called.
166164
props['submitter'](address);
167165
}
168166
}
169167

170-
var geocodesForm = react.registerComponent(() => new _GeocodesForm());
168+
var geocodesForm = react.registerComponent(() => _GeocodesForm());
171169

172170
/// Renders an HTML `<li>` to be used as a child within the [_GeocodesHistoryList].
173171
class _GeocodesHistoryItem extends react.Component {
@@ -189,7 +187,7 @@ class _GeocodesHistoryItem extends react.Component {
189187
}
190188
}
191189

192-
var geocodesHistoryItem = react.registerComponent(() => new _GeocodesHistoryItem());
190+
var geocodesHistoryItem = react.registerComponent(() => _GeocodesHistoryItem());
193191

194192
/// Renders the "history list"
195193
///
@@ -203,7 +201,7 @@ class _GeocodesHistoryList extends react.Component {
203201
{
204202
'key': 'list',
205203
},
206-
new List.from(props['data'].keys.map((key) => geocodesHistoryItem({
204+
List.from((props['data'] as Map).keys.map((key) => geocodesHistoryItem({
207205
'key': key,
208206
'query': props['data'][key]['query'],
209207
'status': props['data'][key]['status'],
@@ -214,11 +212,11 @@ class _GeocodesHistoryList extends react.Component {
214212
}
215213
}
216214

217-
var geocodesHistoryList = react.registerComponent(() => new _GeocodesHistoryList());
215+
var geocodesHistoryList = react.registerComponent(() => _GeocodesHistoryList());
218216

219-
/// The root [Component] of our application.
217+
/// The root `Component` of our application.
220218
///
221-
/// Introduces [state]. Both [state] and [props] are valid locations to store [Component] data.
219+
/// Introduces [state]. Both [state] and [props] are valid locations to store `Component` data.
222220
///
223221
/// However, there are some key differences to note:
224222
///
@@ -228,7 +226,7 @@ var geocodesHistoryList = react.registerComponent(() => new _GeocodesHistoryList
228226
///
229227
/// > When [state] is changed, the component will re-render.
230228
///
231-
/// It's a common practice to store the application data in the [state] of the root [Component]. It will re-render
229+
/// It's a common practice to store the application data in the [state] of the root `Component`. It will re-render
232230
/// every time the state is changed. However, it is not required - you can also use normal variables and re-render
233231
/// manually if you wish.
234232
///
@@ -247,23 +245,23 @@ class _GeocodesApp extends react.Component {
247245
/// Sends the [addressQuery] to the API and processes the result
248246
newQuery(String addressQuery) async {
249247
// Once the query is being sent, it appears in the history and is given an id.
250-
var id = addQueryToHistory(addressQuery);
248+
final id = addQueryToHistory(addressQuery);
251249

252250
// Prepare the URL
253251
addressQuery = Uri.encodeQueryComponent(addressQuery);
254-
var path = 'https://maps.googleapis.com/maps/api/geocode/json?address=$addressQuery';
252+
final path = 'https://maps.googleapis.com/maps/api/geocode/json?address=$addressQuery';
255253

256254
try {
257255
// Send the request
258-
var raw = await HttpRequest.getString(path);
256+
final raw = await HttpRequest.getString(path);
259257
// Delay the answer 2 more seconds, for test purposes
260-
await new Future.delayed(new Duration(seconds: 2));
258+
await Future.delayed(Duration(seconds: 2));
261259
// Is this the answer to the last request?
262260
if (id == last_id) {
263261
// If yes, query was `OK` and `shown_addresses` are replaced
264262
state['history'][id]['status'] = 'OK';
265263

266-
var data = json.decode(raw);
264+
final data = json.decode(raw);
267265

268266
// Calling `setState` will update the state and then repaint the component.
269267
//
@@ -291,7 +289,7 @@ class _GeocodesApp extends react.Component {
291289

292290
/// Add a new [addressQuery] to the `state.history` Map with its status set to 'pending', then return its `id`.
293291
addQueryToHistory(String addressQuery) {
294-
var id = ++last_id;
292+
final id = ++last_id;
295293

296294
state['history'][id] = {'query': addressQuery, 'status': 'pending'};
297295

@@ -324,7 +322,7 @@ class _GeocodesApp extends react.Component {
324322
}
325323
}
326324

327-
var geocodesApp = react.registerComponent(() => new _GeocodesApp());
325+
var geocodesApp = react.registerComponent(() => _GeocodesApp());
328326

329327
/// And finally, a few magic commands to wire it all up!
330328
///

example/geocodes/geocodes.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
* In this file you'll find the mount point of the app. There is also a `geocodes.dart` file which contains the
1313
* structure and the application logic.
1414
*
15-
* Be sure that you understand the basic concepts of [React](http://facebook.github.io/react/) before reading this
15+
* Be sure that you understand the basic concepts of [React](https://reactjs.org/) before reading this
1616
* tutorial.
1717
*
1818
* Enjoy!

example/js_components/js_components.dart

+23-21
Original file line numberDiff line numberDiff line change
@@ -10,33 +10,35 @@ import 'package:react/react_client/react_interop.dart';
1010
import 'package:react/react_dom.dart' as react_dom;
1111

1212
main() {
13-
var content = IndexComponent({});
13+
final content = IndexComponent({});
1414

1515
react_dom.render(content, querySelector('#content'));
1616
}
1717

18-
var IndexComponent = react.registerComponent2(() => new _IndexComponent());
18+
var IndexComponent = react.registerComponent2(() => _IndexComponent());
1919

2020
class _IndexComponent extends react.Component2 {
2121
SimpleCustomComponent simpleRef;
2222

23+
@override
2324
get initialState => {
2425
'open': false,
2526
};
2627

2728
handleClose(_) {
28-
this.setState({
29+
setState({
2930
'open': false,
3031
});
3132
}
3233

3334
handleClick(_) {
34-
this.setState({
35+
setState({
3536
'open': true,
3637
});
3738
print(simpleRef.getFoo());
3839
}
3940

41+
@override
4042
render() {
4143
return MuiThemeProvider(
4244
{
@@ -45,7 +47,7 @@ class _IndexComponent extends react.Component2 {
4547
SimpleCustom({
4648
'foo': 'Foo Prop from dart... IN A JAVASCRIPT COMPONENT!',
4749
'ref': (ref) {
48-
simpleRef = ref;
50+
simpleRef = ref as SimpleCustomComponent;
4951
}
5052
}),
5153
CssBaseline({}),
@@ -62,21 +64,21 @@ class _IndexComponent extends react.Component2 {
6264
DialogActions(
6365
{},
6466
Button({
65-
'color': "primary",
67+
'color': 'primary',
6668
'onClick': handleClose,
6769
}, 'OK'),
6870
)),
6971
Typography({
70-
'variant': "h4",
72+
'variant': 'h4',
7173
'gutterBottom': true,
7274
}, 'Material-UI'),
7375
Typography({
74-
'variant': "subtitle1",
76+
'variant': 'subtitle1',
7577
'gutterBottom': true,
7678
}, 'example project'),
7779
Button({
78-
'variant': "contained",
79-
'color': "secondary",
80+
'variant': 'contained',
81+
'color': 'secondary',
8082
'onClick': handleClick,
8183
}, Icon({}, 'fingerprint'), 'Super Secret Password'),
8284
);
@@ -98,7 +100,7 @@ external ReactClass get _SimpleCustomComponent;
98100
///
99101
/// This converts the Dart props [Map] passed into it in the
100102
/// the same way props are converted for DOM components.
101-
final SimpleCustom = new ReactJsComponentFactoryProxy(_SimpleCustomComponent);
103+
final SimpleCustom = ReactJsComponentFactoryProxy(_SimpleCustomComponent);
102104

103105
/// JS interop wrapper class for the component,
104106
/// allowing us to interact with component instances
@@ -131,13 +133,13 @@ class MaterialUI {
131133
external Map get theme;
132134

133135
// All the Material UI components converted to dart Components
134-
final Button = new ReactJsComponentFactoryProxy(MaterialUI.Button);
135-
final CssBaseline = new ReactJsComponentFactoryProxy(MaterialUI.CssBaseline);
136-
final Dialog = new ReactJsComponentFactoryProxy(MaterialUI.Dialog);
137-
final DialogActions = new ReactJsComponentFactoryProxy(MaterialUI.DialogActions);
138-
final DialogContent = new ReactJsComponentFactoryProxy(MaterialUI.DialogContent);
139-
final DialogContentText = new ReactJsComponentFactoryProxy(MaterialUI.DialogContentText);
140-
final DialogTitle = new ReactJsComponentFactoryProxy(MaterialUI.DialogTitle);
141-
final Icon = new ReactJsComponentFactoryProxy(MaterialUI.Icon);
142-
final MuiThemeProvider = new ReactJsComponentFactoryProxy(MaterialUI.MuiThemeProvider);
143-
final Typography = new ReactJsComponentFactoryProxy(MaterialUI.Typography);
136+
final Button = ReactJsComponentFactoryProxy(MaterialUI.Button);
137+
final CssBaseline = ReactJsComponentFactoryProxy(MaterialUI.CssBaseline);
138+
final Dialog = ReactJsComponentFactoryProxy(MaterialUI.Dialog);
139+
final DialogActions = ReactJsComponentFactoryProxy(MaterialUI.DialogActions);
140+
final DialogContent = ReactJsComponentFactoryProxy(MaterialUI.DialogContent);
141+
final DialogContentText = ReactJsComponentFactoryProxy(MaterialUI.DialogContentText);
142+
final DialogTitle = ReactJsComponentFactoryProxy(MaterialUI.DialogTitle);
143+
final Icon = ReactJsComponentFactoryProxy(MaterialUI.Icon);
144+
final MuiThemeProvider = ReactJsComponentFactoryProxy(MaterialUI.MuiThemeProvider);
145+
final Typography = ReactJsComponentFactoryProxy(MaterialUI.Typography);

example/suspense/suspense.dart

+3-2
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ external ReactClass jsLazy(Promise Function() factory);
1818
// Only intended for testing purposes, Please do not copy/paste this into repo.
1919
// This will most likely be added to the PUBLIC api in the future,
2020
// but needs more testing and Typing decisions to be made first.
21-
ReactJsComponentFactoryProxy lazy(Future<ReactComponentFactoryProxy> factory()) => ReactJsComponentFactoryProxy(
21+
ReactJsComponentFactoryProxy lazy(Future<ReactComponentFactoryProxy> Function() factory) =>
22+
ReactJsComponentFactoryProxy(
2223
jsLazy(
2324
allowInterop(
2425
() => futureToPromise(
@@ -32,7 +33,7 @@ ReactJsComponentFactoryProxy lazy(Future<ReactComponentFactoryProxy> factory())
3233
);
3334

3435
main() {
35-
var content = wrapper({});
36+
final content = wrapper({});
3637

3738
react_dom.render(content, querySelector('#content'));
3839
}

example/test/call_and_nosuchmethod_test.dart

+5-4
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
11
// ignore_for_file: deprecated_member_use_from_same_package
2-
import "dart:html";
2+
import 'dart:html';
33

4-
import "package:react/react_dom.dart" as react_dom;
5-
import "package:react/react.dart" as react;
4+
import 'package:react/react_dom.dart' as react_dom;
5+
import 'package:react/react.dart' as react;
66

77
class _CustomComponent extends react.Component {
8+
@override
89
render() {
910
return react.div({}, props['children']);
1011
}
1112
}
1213

13-
var customComponent = react.registerComponent(() => new _CustomComponent());
14+
var customComponent = react.registerComponent(() => _CustomComponent());
1415

1516
void main() {
1617
react_dom.render(

0 commit comments

Comments
 (0)