Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add assists for macro documentation comments #78

Merged
merged 6 commits into from
Dec 17, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"bools",
"combinators",
"diffscrape",
"endtemplate",
"gocolly",
"interps",
"ints",
Expand Down
79 changes: 79 additions & 0 deletions packages/altive_lints/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ There are also Altive-made rules by custom_lint.
- [prefer\_dedicated\_media\_query\_methods](#prefer_dedicated_media_query_methods)
- [prefer\_to\_include\_sliver\_in\_name](#prefer_to_include_sliver_in_name)
- [prefer\_space\_between\_elements](#prefer_space_between_elements)
- [All assists in altive\_lints](#all-assists-in-altive_lints)
- [Add macro template documentation comment](#add-macro-template-documentation-comment)
- [Add macro documentation comment](#add-macro-documentation-comment)
- [Wrap with macro template documentation comment](#wrap-with-macro-template-documentation-comment)
- [Lint rules adopted by altive\_lints and why](#lint-rules-adopted-by-altive_lints-and-why)
- [public\_member\_api\_docs](#public_member_api_docs)
- [Migration guide](#migration-guide)
Expand Down Expand Up @@ -318,6 +322,81 @@ class MyWidget extends StatelessWidget {
}
```

## All assists in altive_lints

### Add macro template documentation comment

Adds a Macros template to class declarations.
When you place the cursor on the class declaration and execute **"Add macro template documentation comment"**, the documentation is created.

**Before:**

```dart
class MyClass {
// Class implementation
}
```

**After applying the assist:**

```dart
/// {@template my_package.MyClass}
///
/// {@endtemplate}
class MyClass {
// Class implementation
}
```

### Add macro documentation comment

Adds Macros comments to constructors and method declarations.
When you place the cursor on a constructor or method declaration and execute **"Add macro documentation comment"**, the documentation is created.

**Before:**

```dart
void myFunction() {
// Function implementation
}
```

**After applying the assist:**

```dart
/// {@macro my_package.myFunction}
void myFunction() {
// Function implementation
}
```

### Wrap with macro template documentation comment

Wraps existing documentation comments with a Macros template.
When you select the documentation comment and execute **"Wrap with macro template documentation comment"**, the documentation is created.

**Before:**

```dart
/// Some comment
/// More comments
class MyClass {
// Class implementation
}
```

**After applying the assist:**

```dart
/// {@template my_package.MyClass}
/// Some comment
/// More comments
/// {@endtemplate}
class MyClass {
// Class implementation
}
```

## Lint rules adopted by altive_lints and why

Reasons for adopting each lint rule.
Expand Down
10 changes: 10 additions & 0 deletions packages/altive_lints/lib/altive_lints.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import 'package:custom_lint_builder/custom_lint_builder.dart';

import 'src/assists/add_macro_document_comments.dart';
import 'src/assists/add_macro_template_document_comment.dart';
import 'src/assists/wrap_with_macro_template_document_comment.dart';
import 'src/lints/avoid_consecutive_sliver_to_box_adapter.dart';
import 'src/lints/avoid_hardcoded_color.dart';
import 'src/lints/avoid_hardcoded_japanese.dart';
Expand All @@ -26,4 +29,11 @@ class _AltivePlugin extends PluginBase {
const PreferSpaceBetweenElements(),
const PreferToIncludeSliverInName(),
];

@override
List<Assist> getAssists() => [
AddMacroDocumentComment(),
AddMacroTemplateDocumentComment(),
WrapWithMacroTemplateDocumentComment(),
];
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/source/source_range.dart';
import 'package:custom_lint_builder/custom_lint_builder.dart';

/// {@template altive_lints.AddMacroDocumentComment}
/// An assist to add macro template documentation comments to function
/// or constructor declarations.
///
/// This assist helps maintain consistent documentation across
/// the entire codebase by adding macro template comments
/// to each function or constructor. These comments can be used
/// for documentation generation or by other tools.
///
/// Macro template comments follow this format:
///
/// ```dart
/// /// {[@]macro packageName.functionName}
/// ```
///
/// Example:
///
/// Before:
/// ```dart
/// void myFunction() {
/// // Function implementation
/// }
/// ```
///
/// After applying the assist:
/// ```dart
/// /// {[@]macro my_package.myFunction}
/// void myFunction() {
/// // Function implementation
/// }
/// ```
///
/// {@endtemplate}
class AddMacroDocumentComment extends DartAssist {
/// {@macro altive_lints.AddMacroDocumentComment}
AddMacroDocumentComment();

@override
void run(
CustomLintResolver resolver,
ChangeReporter reporter,
CustomLintContext context,
SourceRange target,
) {
context.registry.addFunctionDeclaration((node) {
_processNode(node, target, reporter, context);
});

context.registry.addConstructorDeclaration((node) {
_processNode(node, target, reporter, context);
});
}

void _processNode(
AstNode node,
SourceRange target,
ChangeReporter reporter,
CustomLintContext context,
) {
if (!target.intersects(node.sourceRange)) {
return;
}

final changeBuilder = reporter.createChangeBuilder(
message: 'Add macro documentation comment',
priority: 20,
);

final packageName = context.pubspec.name;
var name = '';

if (node is FunctionDeclaration) {
name = node.name.lexeme;
} else if (node is ConstructorDeclaration) {
name = node.returnType.name;
}

final macroComment = '/// {@macro $packageName.$name}';

changeBuilder.addDartFileEdit((builder) {
builder.addSimpleInsertion(node.offset, '$macroComment\n');
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import 'package:analyzer/source/source_range.dart';
import 'package:custom_lint_builder/custom_lint_builder.dart';

/// {@template altive_lints.AddMacroTemplateDocumentComment}
/// A Dart assist that adds a macro template documentation comment to a class
/// declaration if it does not already have one.
///
/// This assist helps in maintaining consistent documentation across the
/// codebase by ensuring that each class has a macro template comment, which
/// can be used for generating documentation or for other tooling purposes.
///
/// The macro template comment follows the format:
///
/// ```dart
/// /// {[@]template packageName.className}
/// ///
/// /// {[@]endtemplate}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the example, using @endtemplate as is would be interpreted as the end of the template, so I’ve enclosed it in [] to avoid this!

/// ```
///
/// Example usage:
///
/// Before:
/// ```dart
/// class MyClass {
/// // Class implementation
/// }
/// ```
///
/// After running the assist:
/// ```dart
/// /// {[@]template my_package.MyClass}
/// ///
/// /// {[@]endtemplate}
/// class MyClass {
/// // Class implementation
/// }
/// ```
///
/// {@endtemplate}
class AddMacroTemplateDocumentComment extends DartAssist {
/// {@macro altive_lints.AddMacroTemplateDocumentComment}
AddMacroTemplateDocumentComment();

@override
void run(
CustomLintResolver resolver,
ChangeReporter reporter,
CustomLintContext context,
SourceRange target,
) {
context.registry.addClassDeclaration((node) {
if (!target.intersects(node.sourceRange)) {
return;
}

final docComment = node.documentationComment;
if (docComment != null) {
return;
}

final changeBuilder = reporter.createChangeBuilder(
message: 'Add macro template documentation comment',
priority: 20,
);

final packageName = context.pubspec.name;
final className = node.name.lexeme;

final template = [
'/// {@template $packageName.$className}',
'/// ',
'/// {@endtemplate}',
].join('\n');

changeBuilder.addDartFileEdit((builder) {
builder.addSimpleInsertion(node.offset, '$template\n');
});
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/source/source_range.dart';
import 'package:custom_lint_builder/custom_lint_builder.dart';

/// {@template altive_lints.WrapWithMacroTemplateDocumentComment}
/// A Dart assist that wraps an existing documentation comment with a macro
/// template comment.
///
/// This assist helps in maintaining consistent documentation across the
/// codebase by ensuring that each documentation comment is wrapped with a
/// macro template, which can be used for generating documentation or for
/// other tooling purposes.
///
/// The macro template comment follows the format:
///
/// ```dart
/// /// {[@]template packageName.className}
/// /// Existing documentation comment.
/// /// {[@]endtemplate}
/// ```
///
/// Example usage:
///
/// Before:
/// ```dart
/// /// This is a class.
/// class MyClass {
/// // Class implementation
/// }
/// ```
///
/// After running the assist:
/// ```dart
/// /// {[@]template my_package.MyClass}
/// /// This is a class.
/// /// {[@]endtemplate}
/// class MyClass {
/// // Class implementation
/// }
/// ```
///
/// {@endtemplate}
class WrapWithMacroTemplateDocumentComment extends DartAssist {
/// {@macro altive_lints.WrapWithMacroTemplateDocumentComment}
WrapWithMacroTemplateDocumentComment();

@override
void run(
CustomLintResolver resolver,
ChangeReporter reporter,
CustomLintContext context,
SourceRange target,
) {
context.registry.addComment((node) {
if (!target.intersects(node.sourceRange)) {
return;
}

if (!node.isDocumentation) {
return;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

badge

Suggested change
if (!target.intersects(node.sourceRange)) {
return;
}
if (!node.isDocumentation) {
return;
}
if (!target.intersects(node.sourceRange)) {
return;
}
if (node.toSource().contains('{@template') &&
node.toSource().contains('{@endtemplate}')) {
return;
}
if (!node.isDocumentation) {
return;
}

I thought it might be worth considering adding this early return.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you!
It certainly seems like a good idea. ✍️

Since toSource was an empty string and couldn't be evaluated, I changed it to use tokens for evaluation!
feat: Prevent wrapping of existing macro template documentation comments

      final currentComment = node.tokens.join();
      if (currentComment.contains('{@template') &&
          currentComment.contains('{@endtemplate}')) {
        return;
      }


final changeBuilder = reporter.createChangeBuilder(
message: 'Wrap with macro template documentation comment',
priority: 20,
);

final packageName = context.pubspec.name;
final classNode = node.parent;
var className = '';
if (classNode is ClassDeclaration) {
className = classNode.name.lexeme;
}

final templateStart = '/// {@template $packageName.$className}';
const templateEnd = '/// {@endtemplate}';

changeBuilder.addDartFileEdit((builder) {
builder
..addSimpleInsertion(node.offset, '$templateStart\n')
..addSimpleInsertion(node.end, '\n$templateEnd');
});
});
}
}
Loading