Skip to content

Static strict analyzer and linter, contains script for fixing errors and formatting Dart code

License

Notifications You must be signed in to change notification settings

ivangalkindeveloper/pedant

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Pedant

A strict static analyzer and script for formatting Dart code.
Designed to solve problems in a project at the design and support stages.

Analyzer:

  • strict architectural rules;
  • strict stylistic rules;
  • not strict rules of approach.

Script:

  • automatic fix of detected linter errors;
  • sorting in alphabetical order of the fields of .arb files;
  • sorting in alphabetical order and converting declarations of imports, exports and parts;
  • sorting in alphabetical order of dependencies, dev_dependencies, dependency_overrides keys in pubspec.yaml;
  • Dart code formatting.

Get started

Installing

  1. Add two packages to the pubspec.yaml file in the dev_dependencies section:
dev_dependencies:
  custom_lint: ^latest_version
  pedant: ^latest_version
  1. Add the inclusion of a custom analyzer to the analysis_options.yaml file:
analyzer:
  plugins:
    - custom_lint

# For rules configuration add this inclusion
custom_lint:
  rules:
    - pedant:

It is advisable to restart the IDE after connecting the analyzer.

Config

Current default configuration:

custom_lint:
  rules:
    - pedant:
      add_bloc_cubit_event_state_file: true
      add_bloc_cubit_state_postfix: true
      add_bloc_cubit_state_sealed: true
      add_bloc_event_postfix: true
      add_bloc_event_sealed: true
      add_bloc_postfix: true
      add_class_postfix_by_keyword_list: null
      add_class_postfix_by_path_list: null
      add_class_prefix_by_keyword_list: null
      add_class_prefix_by_path_list: null
      add_comma: true
      add_const_constructor: true
      add_const: true
      add_constructor: true
      add_controller_postfix: true
      add_cubit_postfix: true
      add_extension_postfix: true
      add_if_braces: true
      add_mixin_postfix: true
      add_override: true
      add_this: true
      add_type: true
      delete_bloc_cubit_dependent_bloc_cubit: true
      delete_bloc_cubit_dependent_flutter: true
      delete_bloc_cubit_public_property: true
      delete_class_postfix_list:
        - Impl
        - Implementation
        - Model
      delete_class_prefix_list: null
      delete_function_list:
        - print
        - debugPrint
        - debugPrintThrottled
      delete_new: true
      # delete_package_list: - Check note
      # delete_type_list: - Check note
      delete_widget_function_method: true
      edit_arrow_function: true
      edit_constructor_private_named_parameter: true
      edit_constructor_public_named_parameter: true
      edit_file_length_by_path_list: null
      edit_function_private_named_parameter: true
      edit_function_public_named_parameter: true
      edit_multiple_variable: true
      edit_private_in_function: true
      edit_relative_import: true
      edit_variable_name_by_type: true
      priority: 100

Note:
Default list of delete_package_list check here.
Default list of delete_type_list check here.

CLI

The script is designed from the point of view of maximum coverage and bringing order to the project.
Run the script:

dart run pedant

Arguments:

 --no-fix - disable fix of analyzed linter problems;
 --no-sort-arb - disable alphabetical sorting of .arb files;
 --no-sort-convert-export-import-part - disable alphabetical sorting of declarations of imports, exports and parts of .dart files;
 --no-sort-pubspec-dependencies - disable alphabetical sorting dependencшуы in the pubspec.yaml file;
 --no-format - disable final formatting at the script completion stage;

Rules

Add

add_bloc_cubit_part

The Bloc/Cubit state and event class must be located either in the same file or in the same visibility area through part/part of.

// BAD:
import 'package:example/example_event.dart';
import 'package:example/example_state.dart';

class ExampleBloc extends Bloc<IExampleEvent, IExampleState> {
  ...
}

// GOOD:
class ExampleBloc extends Bloc<IExampleEvent, IExampleState> {
  ...
}

sealed class IExampleEvent {
  ...
}

sealed class IExampleState {
  ...
}

// GOOD:
part of 'example_event.dart';
part of 'example_state.dart';

class ExampleBloc extends Bloc<IExampleEvent, IExampleState> {
  ...
}

add_bloc_cubit_state_postfix

The Bloc/Cubit state class must have a State postfix.

// BAD:
sealed class IExampleSt {
  ...
}

// GOOD:
sealed class IExampleState {
  ...
}

add_bloc_cubit_state_sealed

The Bloc/Cubit state class must be declared with the 'sealed' keyword.

// BAD:
class ExampleState {
  ...
}

// GOOD:
sealed class IExampleState {
  ...
}

add_bloc_event_postfix

The Bloc event class must have the Event postfix.

// BAD:
sealed class IExampleEv {
  ...
}

// GOOD:
sealed class IExampleEvent {
  ...
}

add_bloc_event_sealed

The Bloc event class must be declared with the 'sealed' keyword.

// BAD:
class ExampleEvent {
  ...
}

// GOOD:
sealed class IExampleEvent {
  ...
}

add_bloc_postfix

The Bloc class must have a Bloc postfix.

// BAD:
class ExampleBlc extends Bloc<IExampleEvent, IExampleState> {
  ...
}

// GOOD:
class ExampleBloc extends Bloc<IExampleEvent, IExampleState> {
  ...
}

add_class_postfix_by_keyword_list

Classes that contain keywords from the list must have the appropriate postfix.
Example:

add_class_postfix_by_keyword_list:
  -
    keywordList:
      - base
    name: Base
// BAD:
base class Example {
  ...
}

// GOOD:
base class ExampleBase {
  ...
}

add_class_postfix_by_path_list

Classes that are located along the path from the list must have the appropriate postfix.

// BAD:
base class Example {
  ...
}

// GOOD:
base class ExampleBase {
  ...
}

add_class_prefix_by_keyword_list

Classes that contain keywords from the list must be prefixed accordingly.
Example:

add_class_prefix_by_keyword_list:
  -
    keywordList:
      - abstract
      - interface
      - sealed
    name: I
// BAD:
interface class Example {
  ...
}

// GOOD:
interface class IExample {
  ...
}

add_class_prefix_by_path_list

Classes that are located along the path from the list must have the appropriate prefix.

// BAD:
interface class Example {
  ...
}

// GOOD:
interface class IExample {
  ...
}

add_comma

There must be a comma at the end of the parameter list.

// BAD:
(a, b) {}

void exampleFunction({required String argument}) {
  print("Hello World!");
}

// GOOD:
(
  a, 
  b,
) {}

void exampleFunction({
  required String argument,
}) {
  print(
    "Hello World!",
  );
}

add_const_constructor

A class that has all final fields must have a const constructor.

// BAD:
class Example {
  Example({
    required this.title,
  });

  final String title;
}


// GOOD:
class Example {
  const Example({
    required this.title,
  });

  final String title;
}

add_const

Global variables, static fields, variables in functions, and objects that have the final keyword and can be constants must have the 'const' keyword.

// BAD:
final Example topLevel = Example(
  title: "Title",
);

class Example {
  static final String subTitle = "SubTitle";

  const Example({
    required this.title,
  });

  final String title;
}

void exampleFunction() {
  final Example function = Example(
    title: "Title",
  );
}

// GOOD:
const Example topLevel = Example(
  title: "Title",
);

class Example {
  static const String title = "SubTitle";

  const Example();
}

void exampleFunction() {
  const Example function = Example(
    title: "Title",
  );
}

add_constructor

All classes must have an explicit constructor.

// BAD:
class Example {}

// GOOD:
class Example {
  Example();
}

add_controller_postfix

The ChangeNotifier/ValueNotifier class must have a Controller postfix.

// BAD:
class ExampleNotifier extends ChangeNotifier {}

// GOOD:
class ExampleController extends ChangeNotifier {}

add_cubit_postfix

The Cubit class must have the Cubit postfix.

// BAD:
class ExampleCub extends Cubit<ExampleState> {
  ...
}

// GOOD:
class ExampleCubit extends Cubit<ExampleState> {
  ...
}

add_extension_postfix

The extension must have the Extension postfix.

// BAD:
extension ExampleX on Object {}

// GOOD:
extension ExampleExtension on Object {}

add_if_braces

The if expression must have parentheses.

// BAD:
if (list.isEmpty) return;

// GOOD:
if (list.isEmpty) {
  return;
}

add_mixin_postfix

A mixin must have a Mixin postfix.

// BAD:
mixin StringMix on Object {}

// GOOD:
mixin StringMixin on Object {}

add_override

Fields and methods of a class overridden from the base one must have the @override annotation.

// BAD:
class Example {
  String toString() => "";
}

// GOOD:
class Example {
  @override
  String toString() => "";
}

add_this

Within a class, access to internal fields and methods must begin with the this keyword.

// BAD:
class Example {
  ...

  final String title;

  @override
  String toString() => title;
}


// GOOD:
class Example {
  ...

  final String title;

  @override
  String toString() => this.title;
}

add_type

Variables and parameters of closures must have a type.

// BAD:
void exampleFunction(
  field,
) {
  final variable = "";
}

// GOOD:
void exampleFunction(
  dynamic field,
) {
  final String variable = "";
}

Delete

delete_bloc_cubit_dependent_bloc_cubit

Need to remove the Bloc/Cubit dependency in the Bloc/Cubit class.

// BAD:
class ExampleBloc extends Bloc<IExampleEvent, IExampleState> {
  ExampleBloc({
    required AnotherBloc anotherbloc,
  })  : this._anotherbloc = anotherbloc,
        super(
          const ExampleLoadingState(),
        );

  final AnotherBloc _anotherbloc;
}

// GOOD:
class ExampleBloc extends Bloc<IExampleEvent, IExampleState> {
  ExampleBloc() : super(
    const ExampleLoadingState(),
  );
}

delete_bloc_cubit_dependent_flutter

Need to remove the Flutter resource dependency in the Bloc/Cubit class.

// BAD:
class ExampleBloc extends Bloc<IExampleEvent, IExampleState> {
  ExampleBloc({
    required TextEditingController textController,
  })  : this._textController = textController,
        super(
          const ExampleLoadingState(),
        );

  final TextEditingController _textController;
}

// GOOD:
class ExampleBloc extends Bloc<IExampleEvent, IExampleState> {
  ExampleBloc() : super(
    const ExampleLoadingState(),
  );
}

delete_bloc_cubit_public_property

Need to remove public properties in the Bloc/Cubit class.

// BAD:
class ExampleBloc extends Bloc<IExampleEvent, IExampleState> {
  ExampleBloc({
    required this.publicProperty,
  })  :  super(
          const ExampleLoadingState(),
        );

  final String publicProperty;
}

// GOOD:
class ExampleBloc extends Bloc<IExampleEvent, IExampleState> {
  ExampleBloc() : super(
    const ExampleLoadingState(),
  );
}

delete_class_postfix_list

Need to remove the class postfix included in the list.

// BAD:
class ExampleModel {
  const ExampleModel();
}

// GOOD:
class Example {
  const Example();
}

delete_class_prefix_list

Need to remove the class prefix included in the list.

// BAD:
class ModelExample {
  const ModelExample();
}

// GOOD:
class Example {
  const Example();
}

delete_function_list

Need to remove a function from the list.

// BAD:
void exampleFunction() {
  print(something);
}

// GOOD:
void exampleFunction() {}

delete_new

Need to remove the 'new' keyword when creating the instance.

// BAD:
final ExampleClass example = new ExampleClass();

// GOOD:
final ExampleClass example = ExampleClass();

delete_package_list

Need to remove the package that is on the list.

# BAD:
dependencies:
  bloc:
  get:
  get_it:
  fpdart:
  hive:

# GOOD:
dependencies:
  bloc:

delete_type_list

Need to remove a type from the list.

// BAD:
return Scaffold(
  body: Container(
    ... ,
  ),
);

// GOOD:
return Scaffold(
  body: Padding(
    padding: ... ,
    child: ColorBox(
      color: ... ,
    ),
  ),
);

delete_widget_function_method

Need to remove the function that returns Widget.

// BAD:
Widget _buildRow() => Row(
  ... ,
);

// GOOD:
List<String> _entityList() => [
  ... ,
];

Edit

edit_arrow_function

Need to edit the arrow function.

// BAD:
int exampleFunction() {
  return 1 + 1;
}

// GOOD:
int exampleFunction() => 1 + 1;

edit_constructor_private_named_parameter

Need to edit all parameters of the private constructor into named ones.

// BAD:
class _ExampleClass {
  const _ExampleClass(
    this.property0,
    this.property1,
  );

  ...
}

// GOOD:
class _ExampleClass {
  const _ExampleClass({
    required this.property0,
    required this.property1,
  });

  ...
}

edit_constructor_public_named_parameter

Need to edit all parameters of the public constructor into named ones.

// BAD:
class ExampleClass {
  const ExampleClass(
    this.property0,
    this.property1,
  );

  ...
}

// GOOD:
class ExampleClass {
  const ExampleClass({
    required this.property0,
    required this.property1,
  });

  ...
}

edit_file_length_by_path_list

Need to edit the file located along the path to the allowable code length.

edit_function_private_named_parameter

Need to edit all parameters of a private function into named ones.

// BAD:
void _exampleFunction(
  String argument0,
  String argument1,
) {
  ...
}

// GOOD:
void _exampleFunction({
  required String argument0,
  required String argument1,
}) {
  ...
}

edit_function_public_named_parameter

Need to edit all parameters of a public function into named ones.

// BAD:
void exampleFunction(
  String argument0,
  String argument1,
) {
  ...
}

// GOOD:
void exampleFunction({
  required String argument0,
  required String argument1,
}) {
  ...
}

edit_multiple_variable

Need to edit the declaration of the list of variables into separate ones.

// BAD:
final String variable0, variable1, variable2 = "";

// GOOD:
final String variable0 = "";
final String variable1 = "";
final String variable2 = "";

edit_private_in_function

Need to edit a private variable to public in a function.

// BAD:
void exampleFunction() {
  final String _variable = "";
}

// GOOD:
void exampleFunction() {
  final String variable = "";
}

edit_relative_import

Need to edit relative import to absolute.

// BAD:
import '../src/example.dart';

// GOOD:
import 'package:example/src/example.dart';

edit_variable_name_by_type

You need to edit the variable name based on its type.

// BAD:
final ExampleClass a = ExampleClass();

// GOOD:
final ExampleClass example = ExampleClass();

Other

Priority

The priority of displayed commands in the IDE.

About

Static strict analyzer and linter, contains script for fixing errors and formatting Dart code

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages