-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'master' of github.com:Workiva/over_react_codemod into I…
…NTL-1793
- Loading branch information
Showing
23 changed files
with
2,256 additions
and
91 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
// Copyright 2024 Workiva Inc. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
export 'package:over_react_codemod/src/executables/null_safety_migrator_companion.dart'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
110 changes: 110 additions & 0 deletions
110
lib/src/dart3_suggestors/null_safety_prep/class_component_required_default_props.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
// Adapted from the missing_required_prop diagnostic in over_react/analyzer_plugin | ||
// Permalink: https://github.com/Workiva/over_react/blob/ae8c898650537e49f35f98ad1b065c516207838e/tools/analyzer_plugin/lib/src/util/prop_declarations/defaulted_props.dart | ||
|
||
// Copyright 2024 Workiva Inc. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
import 'package:over_react_codemod/src/util.dart'; | ||
import 'package:over_react_codemod/src/util/component_usage.dart'; | ||
import 'package:analyzer/dart/ast/ast.dart'; | ||
import 'package:over_react_codemod/src/util/get_all_props.dart'; | ||
import 'package:pub_semver/pub_semver.dart'; | ||
|
||
import 'utils/class_component_required_fields.dart'; | ||
|
||
/// Suggestor to assist with preparations for null-safety by adding | ||
/// "requiredness" (`late`) / nullability (`?`/`!`) hints to prop types | ||
/// based on their access within a class component's `defaultProps`. | ||
/// | ||
/// If a prop is defaulted to a non-null value within `defaultProps`, the | ||
/// corresponding prop declaration will gain a `/*late*/` modifier hint to the | ||
/// left of the type, and a non-nullable type hint (`/*!*/`) to the right of | ||
/// the type to assist the `nnbd_migration:migrate` script when it attempts to | ||
/// infer a prop's nullability. | ||
/// | ||
/// **Optionally**, an [sdkVersion] can be passed to the constructor. | ||
/// When set to a version that opts-in to Dart's null safety feature, | ||
/// the `late` / `?` type modifiers will be actual modifiers rather | ||
/// than commented hints. This should only be done using an explicit opt-in | ||
/// flag from the executable as most consumers that have migrated to null-safety | ||
/// will have already run this script prior to the null safety migration and thus | ||
/// the `/*late*/` / `/*?*/` hints will already be converted to actual modifiers. | ||
/// | ||
/// **Before** | ||
/// ```dart | ||
/// mixin FooProps on UiProps { | ||
/// String defaultedNullable; | ||
/// num defaultedNonNullable; | ||
/// } | ||
/// class FooComponent extends UiComponent2<FooProps> { | ||
/// @override | ||
/// get defaultProps => (newProps() | ||
/// ..defaultedNullable = null | ||
/// ..defaultedNonNullable = 2.1 | ||
/// ); | ||
/// | ||
/// // ... | ||
/// } | ||
/// ``` | ||
/// | ||
/// **After** | ||
/// ```dart | ||
/// mixin FooProps on UiProps { | ||
/// /*late*/ String/*?*/ defaultedNullable; | ||
/// /*late*/ num/*!*/ defaultedNonNullable; | ||
/// } | ||
/// class FooComponent extends UiComponent2<FooProps> { | ||
/// @override | ||
/// get defaultProps => (newProps() | ||
/// ..defaultedNullable = null | ||
/// ..defaultedNonNullable = 2.1 | ||
/// ); | ||
/// | ||
/// // ... | ||
/// } | ||
/// ``` | ||
class ClassComponentRequiredDefaultPropsMigrator | ||
extends ClassComponentRequiredFieldsMigrator<PropAssignment> { | ||
ClassComponentRequiredDefaultPropsMigrator([Version? sdkVersion]) | ||
: super('defaultProps', 'getDefaultProps', sdkVersion); | ||
|
||
@override | ||
Future<void> visitCascadeExpression(CascadeExpression node) async { | ||
super.visitCascadeExpression(node); | ||
|
||
final isDefaultProps = node.ancestors.any((ancestor) { | ||
if (ancestor is MethodDeclaration) { | ||
return [relevantGetterName, relevantMethodName] | ||
.contains(ancestor.declaredElement?.name); | ||
} | ||
if (ancestor is VariableDeclaration && | ||
(ancestor.parentFieldDeclaration?.isStatic ?? false)) { | ||
return RegExp(RegExp.escape(relevantGetterName), caseSensitive: false) | ||
.hasMatch(ancestor.name.lexeme); | ||
} | ||
return false; | ||
}); | ||
|
||
// If this cascade is not assigning values to defaultProps, bail. | ||
if (!isDefaultProps) return; | ||
|
||
final cascadedDefaultProps = node.cascadeSections | ||
.whereType<AssignmentExpression>() | ||
.where((assignment) => assignment.leftHandSide is PropertyAccess) | ||
.map((assignment) => PropAssignment(assignment)) | ||
.where((prop) => prop.node.writeElement?.displayName != null); | ||
|
||
patchFieldDeclarations(getAllProps, cascadedDefaultProps, node); | ||
} | ||
} |
100 changes: 100 additions & 0 deletions
100
lib/src/dart3_suggestors/null_safety_prep/class_component_required_initial_state.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
// Adapted from the missing_required_prop diagnostic in over_react/analyzer_plugin | ||
// Permalink: https://github.com/Workiva/over_react/blob/ae8c898650537e49f35f98ad1b065c516207838e/tools/analyzer_plugin/lib/src/util/prop_declarations/defaulted_props.dart | ||
|
||
// Copyright 2024 Workiva Inc. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
import 'package:over_react_codemod/src/util/component_usage.dart'; | ||
import 'package:analyzer/dart/ast/ast.dart'; | ||
import 'package:over_react_codemod/src/util/get_all_props.dart'; | ||
import 'package:over_react_codemod/src/util/get_all_state.dart'; | ||
import 'package:pub_semver/pub_semver.dart'; | ||
|
||
import 'utils/class_component_required_fields.dart'; | ||
|
||
/// Suggestor to assist with preparations for null-safety by adding | ||
/// "requiredness" (`late`) / nullability (`?`/`!`) hints to state field types | ||
/// based on their access within a class component's `initialState`. | ||
/// | ||
/// If a piece of state is initialized to a non-null value within `initialState`, | ||
/// the corresponding declaration will gain a `/*late*/` modifier hint to | ||
/// the left of the type, and a non-nullable type hint (`/*!*/`) to the right of | ||
/// the type to assist the `nnbd_migration:migrate` script when it attempts to | ||
/// infer a state field's nullability. | ||
/// | ||
/// **Optionally**, an [sdkVersion] can be passed to the constructor. | ||
/// When set to a version that opts-in to Dart's null safety feature, | ||
/// the `late` / `?` type modifiers will be actual modifiers rather | ||
/// than commented hints. This should only be done using an explicit opt-in | ||
/// flag from the executable as most consumers that have migrated to null-safety | ||
/// will have already run this script prior to the null safety migration and thus | ||
/// the `/*late*/` / `/*?*/` hints will already be converted to actual modifiers. | ||
/// | ||
/// **Before** | ||
/// ```dart | ||
/// mixin FooState on UiState { | ||
/// String defaultedNullable; | ||
/// num defaultedNonNullable; | ||
/// } | ||
/// class FooComponent extends UiStatefulComponent2<FooProps> { | ||
/// @override | ||
/// get initialState => (newState() | ||
/// ..defaultedNullable = null | ||
/// ..defaultedNonNullable = 2.1 | ||
/// ); | ||
/// | ||
/// // ... | ||
/// } | ||
/// ``` | ||
/// | ||
/// **After** | ||
/// ```dart | ||
/// mixin FooState on UiState { | ||
/// /*late*/ String/*?*/ defaultedNullable; | ||
/// /*late*/ num/*!*/ defaultedNonNullable; | ||
/// } | ||
/// class FooComponent extends UiStatefulComponent2<FooProps> { | ||
/// @override | ||
/// get initialState => (newState() | ||
/// ..defaultedNullable = null | ||
/// ..defaultedNonNullable = 2.1 | ||
/// ); | ||
/// | ||
/// // ... | ||
/// } | ||
/// ``` | ||
class ClassComponentRequiredInitialStateMigrator | ||
extends ClassComponentRequiredFieldsMigrator<StateAssignment> { | ||
ClassComponentRequiredInitialStateMigrator([Version? sdkVersion]) | ||
: super('initialState', 'getInitialState', sdkVersion); | ||
|
||
@override | ||
Future<void> visitCascadeExpression(CascadeExpression node) async { | ||
super.visitCascadeExpression(node); | ||
|
||
final isInitialState = [relevantGetterName, relevantMethodName].contains( | ||
node.thisOrAncestorOfType<MethodDeclaration>()?.declaredElement?.name); | ||
|
||
// If this cascade is not assigning values to defaultProps, bail. | ||
if (!isInitialState) return; | ||
|
||
final cascadedInitialState = node.cascadeSections | ||
.whereType<AssignmentExpression>() | ||
.where((assignment) => assignment.leftHandSide is PropertyAccess) | ||
.map((assignment) => StateAssignment(assignment)) | ||
.where((prop) => prop.node.writeElement?.displayName != null); | ||
|
||
patchFieldDeclarations(getAllState, cascadedInitialState, node); | ||
} | ||
} |
Oops, something went wrong.