Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
11 changes: 11 additions & 0 deletions tool/dart_skills_lint/.agents/skills/dart-best-practices/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,17 @@ without horizontal scrolling.
Target 80 characters for wrapping text. Exceptions are allowed for long URLs
or identifiers that cannot be broken.

## Discovery

### Multi-line Strings
To find candidates for multi-line strings, search for string concatenation
with `+` involving newlines:
- **Regex**: `['"]\s*\+\s*['"]`
- **Regex**: `\+\s*['"].*\\n`

### Line Length
- Rely on the `lines_longer_than_80_chars` lint from the analyzer.

## Related Skills

- **[dart-modern-features]**: For idiomatic
Expand Down
158 changes: 158 additions & 0 deletions tool/dart_skills_lint/.agents/skills/dart-checks-migration/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
---
name: dart-checks-migration
description: |-
Replace the usage of `expect` and similar functions from `package:matcher`
to `package:checks` equivalents.
license: Apache-2.0
---

# Dart Checks Migration

## When to use this skill
Use this skill when:
- Migrating existing test files from `package:matcher` to `package:checks`.
- A user specifically asks for "modern checks" or similar.

## The Workflow

1. **Analysis**:
- Use `grep` to identify files using `expect` or `package:matcher`.
- Review custom matchers; these may require manual migration.
2. **Tools & Dependencies**:
- Ensure `dev_dependencies` includes `checks`.
- Run `dart pub add --dev checks` if missing.
3. **Discovery**:
- Use the **Strategies for Discovery** below to find candidates.
4. **Replacement**:
- Add `import 'package:checks/checks.dart';`.
- Apply the **Common Patterns** below.
- **Final Step**: Replace `import 'package:test/test.dart';` with
`import 'package:test/scaffolding.dart';` ONLY after all `expect` calls
are replaced. This ensures incremental progress.
5. **Verification**:
- Ensure the code analyzes cleanly.
- Ensure tests pass.

## Strategies for Discovery

To find candidates for migration, use the following search strategies:

### Files using Legacy Matchers
Search for test files that import `package:test/test.dart` or use `expect`:
- **Search Query**: `import 'package:test/test.dart';`
- **Regex**: `expect\(`

### Specific Matchers to Target
Search for specific matchers that are easy to migrate:
- **Regex**: `expect\(.*,\s*equals\(`
- **Regex**: `expect\(.*,\s*isNull\)`
- **Regex**: `expect\(.*,\s*isTrue\)`
- **Regex**: `expect\(.*,\s*isFalse\)`
- **Regex**: `expect\(.*,\s*throwsA`

## Common Patterns

| Legacy `expect` | Modern `check` |
| :--- | :--- |
| `expect(a, equals(b))` | `check(a).equals(b)` |
| `expect(a, isTrue)` | `check(a).isTrue()` |
| `expect(a, isFalse)` | `check(a).isFalse()` |
| `expect(a, isNull)` | `check(a).isNull()` |
| `expect(a, isNotNull)` | `check(a).isNotNull()` |
| `expect(() => fn(), throwsA<T>())` | `check(() => fn()).throws<T>()` |
| `expect(list, hasLength(n))` | `check(list).length.equals(n)` |
| `expect(a, closeTo(b, delta))` | `check(a).isA<num>().isCloseTo(b, delta)` |
| `expect(a, greaterThan(b))` | `check(a).isGreaterThan(b)` |
| `expect(a, lessThan(b))` | `check(a).isLessThan(b)` |
| `expect(list, isEmpty)` | `check(list).isEmpty()` |
| `expect(list, isNotEmpty)` | `check(list).isNotEmpty()` |
| `expect(list, contains(item))` | `check(list).contains(item)` |
| `expect(map, equals(otherMap))` | `check(map).deepEquals(otherMap)` |
| `expect(list, equals(otherList))` | `check(list).deepEquals(otherList)` |
| `expect(future, completes)` | `await check(future).completes()` |
| `expect(stream, emitsInOrder(...))` | `await check(stream).withQueue.inOrder(...)` |

### Async & Futures (CRITICAL)

- **Checking async functions:**
`check(() => asyncFunc()).throws<T>()` causes **FALSE POSITIVES** because the
closure returns a `Future`, which is a value, so it "completes normally"
(as a Future).
**Correct Usage:**
```dart
await check(asyncFunc()).throws<T>();
```

- **Chaining on void returns:**
Many async check methods (like `throws`) return `Future<void>`. You cannot
chain directly on them. Use cascades or callbacks.
**Wrong:**
```dart
await check(future)
.throws<Error>()
.has((e) => e.message, 'message')
.equals('foo');
```
**Correct:**
```dart
await check(future).throws<Error>(
(it) => it.has((e) => e.message, 'message').equals('foo'));
```

## Complex Examples

*Deep Verification with `isA` and `having`:*

**Legacy:**
```dart
expect(() => foo(), throwsA(isA<ArgumentError>()
.having((e) => e.message, 'message', contains('MSG'))));
```

**Modern:**
```dart
check(() => foo())
.throws<ArgumentError>()
.has((e) => e.message, 'message')
.contains('MSG');
```

*Property Extraction:*

**Legacy:**
```dart
expect(obj.prop, equals(value)); // When checking multiple props
```

**Modern:**
```dart
check(obj)
..has((e) => e.prop, 'prop').equals(value)
..has((e) => e.other, 'other').equals(otherValue);
```

*One-line Cascades:*
Since checks often return `void`, use cascades for multiple assertions on the
same subject.
```dart
check(it)..isGreaterThan(10)..isLessThan(20);
```

## Constraints

- **Scope**: Only modify files in `test/` (and `pubspec.yaml`).
- **Correctness**: One failing test is unacceptable. If a test fails after
migration and you cannot fix it immediately, REVERT that specific change.
- **Type Safety**: `package:checks` is stricter about types than `matcher`.
You may need to add explicit `as T` casts or `isA<T>()` checks in the chain.

## Related Skills

- **[dart-test-fundamentals]**: Core
concepts for structuring tests, lifecycles, and configuration.
- **[dart-matcher-best-practices]**:
Best practices for the traditional `package:matcher` that is being migrated
away from.

[dart-test-fundamentals]: https://github.com/kevmoo/dash_skills/blob/main/.agent/skills/dart-test-fundamentals/SKILL.md
[dart-matcher-best-practices]: https://github.com/kevmoo/dash_skills/blob/main/.agent/skills/dart-matcher-best-practices/SKILL.md
Comment on lines +157 to +158

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The URLs for the related skills are likely broken. They use the singular .agent directory name instead of the plural .agents used in this repository, and they are missing the tool/dart_skills_lint/ path prefix. This will result in 404 errors when following the links on GitHub.

Suggested change
[dart-test-fundamentals]: https://github.com/kevmoo/dash_skills/blob/main/.agent/skills/dart-test-fundamentals/SKILL.md
[dart-matcher-best-practices]: https://github.com/kevmoo/dash_skills/blob/main/.agent/skills/dart-matcher-best-practices/SKILL.md
[dart-test-fundamentals]: https://github.com/kevmoo/dash_skills/blob/main/tool/dart_skills_lint/.agents/skills/dart-test-fundamentals/SKILL.md
[dart-matcher-best-practices]: https://github.com/kevmoo/dash_skills/blob/main/tool/dart_skills_lint/.agents/skills/dart-matcher-best-practices/SKILL.md

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

These urls resolve and are correct. See kevmoo/dash_skills#17

Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,27 @@ Future<void> main(List<String> arguments) async {
- Put complex logic directly in `bin/my_app.dart`.
- Define classes or heavy functions in the entrypoint.

### Executable Scripts
### Put an `executable` entry in `pubspec.yaml`

List your executables in `pubspec.yaml` to make them available for global
activation and clean invocation via `dart run`.

**DO:**
Add an `executables` section mapping the command name to the Dart file in
`bin/` (excluding the `.dart` extension).

```yaml
executables:
my_app: # Maps to bin/my_app.dart
custom_name: main # Maps to bin/main.dart
```

Then run via `dart run my_app` or `dart run custom_name`.

### CONSIDER `#!` for other scripts on *nix systems

This is NOT a hard and fast rule, but it is something to consider.

For CLI tools intended to be run directly on Linux and Mac, add a shebang and
ensure the file is executable.

Expand Down Expand Up @@ -95,12 +115,28 @@ Future<void> main(List<String> arguments) async {

### Cross-Platform Compatibility (Windows Support)
When writing CLI applications and tests, ensure compatibility with Windows:
- **Paths**: Never hardcode path separators like `/`. Use `package:path`'s
`p.join` or `p.normalize` to construct paths portably.
- **Paths**: Avoid hardcoding path separators like `/` because Windows uses `\`.
Use `package:path`'s `p.join` or `p.normalize` to construct paths portably.
- **File Permissions**: When testing file permission errors, remember that
`chmod` is not available on Windows. Use `icacls` on Windows or appropriate
mock libraries. Never skip tests on Windows simply because of permission
commands if a Windows equivalent exists.
mock libraries to simulate permission errors. Never skip tests on Windows
simply because of permission commands if a Windows equivalent exists.

## Discovery

To find areas to apply these best practices:

### Heavy Entrypoints
Inspect files in `bin/` to see if they contain logic that should be in `lib/`:
- **Target**: Files matching `bin/*.dart`.

### Direct Process Termination
Search for calls to `exit()` instead of setting `exitCode`:
- **Regex**: `\bexit\(`

### Hardcoded Path Separators
Search for hardcoded `/` in strings that appear to be file paths:
- **Regex**: `['"][^'"]+/[^'"]+['"]` (Verify context as this may match URLs).

## 3. Recommended Packages

Expand Down
42 changes: 42 additions & 0 deletions tool/dart_skills_lint/.agents/skills/dart-doc-validation/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,33 @@ Use this skill when:
- Checking for broken documentation links, references, or macros.
- Preparing a package for publishing to pub.dev.

## Discovery

To find documentation issues:

### Missing Lint
Verify if the `comment_references` lint is enabled:
- **Target**: `analysis_options.yaml`
- **Search Query**: `comment_references`

### Automated Validation
Run the documentation generator to surface warnings:
- **Command**: `dart doc -o $(mktemp -d)`
- **Keywords to look for**: `warning:`, `unresolved doc reference`,
`undefined macro`

## 2. Best Practices

### Enable the doc validation lint

In your `analysis_options.yaml`, enable the `comment_references` lint.

```yaml
linter:
rules:
- comment_references
```

### Validating Documentation Locally

Use the `dart doc` command with a temporary output directory to validate
Expand All @@ -27,14 +52,31 @@ This command parses all documentation comments and reports warnings such as:
- `warning: undefined macro`

**Command to run:**

```bash
dart doc -o $(mktemp -d)
```

*This will work on Mac and Linux.*

This ensures that the generated HTML files are stored in a temporary location
and don't clutter the package directory, while still surfacing all validation
warnings in the terminal output.

**Browsing the docs:**

Our docs use features designed to be run on a web server. If you want to browse
the generated docs locally, install the `dhttpd` package.


```shell
pub global activate dhttpd
TMP_DIR=$(mktemp -d) && dart doc -o "$TMP_DIR" && dhttpd --path "$TMP_DIR"
```

*(Or use another HTTP server, such as `python3 -m http.server`.)*


### Fixing Common Warnings

- **Unresolved doc reference**: Ensure that any identifier wrapped in square
Expand Down
Loading
Loading