The dart_code_linter `prefer-match-file-name` rule fires on Windows
when a file declares a class whose name (after snake_case conversion)
doesn't match the file's basename. The previous `_Row` class triggered
that rule on the Windows analyze_and_test job, even though macOS and
Linux passed clean.
Convert `_Row` to `typedef _BenchResult = (...)`, a record. Typedefs
aren't class declarations, so the rule has nothing to flag, and the
record literal at the return site is just as terse as the old
constructor call.
- Fix stale doc comment that pointed at CONTRIBUTING.md; the docs live in
bench/README.md.
- Wrap arg parsing (including int.parse calls and the main loop) in a
single FormatException try/catch, and validate that --runs >= 1 and
--warmup >= 0 so bad input produces a clear message instead of a
crash. _parseSizes now reports unparseable or non-positive entries
with a specific message and rejects an empty list.
- Use p.absolute('synthetic-abs-path') for the errors-per-skill=3
link rather than the hardcoded POSIX path '/etc/hosts', so the
benchmark's absolute-paths rule trigger works the same way on
Windows as on Linux/macOS.
Verified 3 distinct baseline entries are recorded when
--errors-per-skill 3 (check-absolute-paths, description-too-long,
invalid-skill-name).
Adds tool/dart_skills_lint/bench/baseline_throughput.dart, a standalone
script that calls validateSkills(generateBaseline: true) in-process
across synthetic skill sizes and prints a wall-clock table. Documents
its usage in tool/dart_skills_lint/bench/README.md.
The benchmark is local-only (not wired into CI) since wall-clock on
hosted runners is too noisy to enforce.
Fixes#114
Two pieces of feedback from the maintainer:
1. entry_point.dart: collapse the explicit `export ... show <list>;` to
a plain `export 'validation_session.dart';`. There are no name
conflicts to disambiguate, so the show clause was just noise.
2. validation_session.dart: rewrite three doc comments that compared
the new behavior to the "original CLI semantics" or "legacy
_generateBaselineFile". Such comparisons go stale as the code
evolves. Describe current behavior directly:
- processIndividualSkill: drop "(matches the original CLI
semantics)"
- processSkillRoot: same
- _saveBaseline: replace "match the legacy _generateBaselineFile
behavior" with a direct statement of what the method does
Verified locally:
- dart format --output=none --set-exit-if-changed . exits 0
- dart analyze --fatal-infos clean
- dart run dart_code_linter:metrics analyze lib reports no issues
- dart test: all 110 tests pass
CI on PR #113 surfaced two issues my local analyze missed:
1. dart format reported lib/src/validation_session.dart needed
reformatting. Apply it.
2. dart_code_linter:metrics (the cyclomatic-complexity check that
runs on Linux/macOS, and which Windows surfaces via
`dart analyze --fatal-infos` because it's wired through
analysis_options.yaml) flagged the inner loop in _applyIgnores
for repeated `pair.entry.*` access. Hoist `pair.entry` to a
local IgnoreEntry inside the loop.
Verified locally:
- dart format --output=none --set-exit-if-changed . exits 0
- dart run dart_code_linter:metrics analyze lib reports no issues
- dart analyze --fatal-infos clean
- dart test: all 110 tests pass
Three review comments from the gemini-code-assist bot, all in
validation_session.dart:
1. (HIGH) generateBaseline did O(N^2) I/O — _generateBaselineFile
read+modified+wrote the entire ignore JSON per skill. Restructured
so processSkillRoot / processIndividualSkill load the SkillsIgnores
once, mutate it in memory across all skills via the new
_updateBaselineForSkill helper, and write it once at the end via
the new _saveBaseline helper.
2. (MED) _resolveRulesForPath / _resolveIgnoreFile re-normalized every
directoryConfig path on every call. Pre-normalize once in the
constructor's initializer list and store as
_normalizedDirectoryConfigs.
3. (MED) _applyIgnores re-normalized paths inside its nested loop.
Pre-normalize the ignore filenames once at the top of the call,
and hoist p.normalize(error.file) outside the inner loop.
Behavior preserved exactly; baseline file contents on disk are
identical to the pre-fix output. Only the timing and number of writes
change. All 110 existing tests pass; analyzer clean with --fatal-infos.
entry_point.dart had grown to ~900 lines, mixing CLI argument parsing,
config loading, and the per-skill validation workflow. The two processors
(_processSkillPaths and _processSkillDirectories) duplicated significant
per-root setup, ignore loading, and stale-ignore reporting.
Extract a new ValidationSession class that owns per-invocation state
(config, resolved rules, customRules, flags, anyFailed/anySkillsValidated)
and exposes processIndividualSkill / processSkillRoot / reportNoSkillsValidated.
entry_point.dart drops to ~360 lines and becomes a thin orchestrator.
Behavior preserved exactly:
- Original fast-fail semantics: missing-directory errors contribute to
anyFailed but don't trigger fast-fail in their own iteration; only
validation failures do. The session methods return bool keepGoing to
signal this to the caller.
- Public test-visible constants (skillIsValidMsg, evaluatingDirMsg, etc.)
moved to validation_session.dart and re-exported from entry_point.dart
via `export ... show` so test imports keep working unchanged.
- defaultIgnoreFileName loses its @visibleForTesting annotation: it's
used in the --generate-baseline help text in production code, so the
original annotation was a mis-application that the move exposed.
Verified:
- dart analyze --fatal-infos reports no issues
- dart test passes all 110 tests, including the fast-fail integration test
and all fixer tests
- dart run bin/cli.dart --skills-directory ../../skills validates all 10
Flutter skills cleanly
One place to run "flutter pub get".
Brings up the lower end dart to ^3.10.8, upgrades lints and packages.
Removes lock files.
Fixes formatting for new lower bounds.