FEDX-7267: Support Dart doc imports in dependency_validator - #197
FEDX-7267: Support Dart doc imports in dependency_validator#197engops-wk wants to merge 9 commits into
Conversation
Co-authored-by: Dustin Pauze <dustin.pauze@workiva.com>
engops-wk
left a comment
There was a problem hiding this comment.
Review round 1 — CHANGES REQUESTED (posted as a comment; GitHub blocks REQUEST_CHANGES on one's own PR)
Solid, well-scoped approach: separating directivePackageNames from docImportPackageNames in a small value object and reusing _addPackageName is the right shape, and the test coverage intent (unit + executable-level) is good. But CI is red on this PR and the failures are directly caused by this change, so it can't merge as-is.
Failing CI checks (must be green before approval)
CI (.github/workflows/ci.yaml) runs three reusable jobs from Workiva/gha-dart-oss@v0.1.14, all pinned to sdk: 3.7.2:
unit-tests(test-unit.yaml, Dart 3.7.2) — root cause. Doc imports are a Dart 3.8 language feature.parseStringdefaults toFeatureSet.latestLanguageVersion(), which on the 3.7.2 toolchain does not enable doc imports, soComment.docImportsis always empty. Every new assertion that expects a doc-import package (test/import_export_ast_visitor_test.dart"collects doc imports…" and "collects both…", plus the three positive/negative cases in thedoc importsgroup intest/executable_test.dart) fails. Theexecutable_testcases fail for a second, compounding reason:checkProjectintest/utils.dartwrites the fixture pubspec withrequireDart36(sdk: ^3.6.0), so the fixture project's language version is below 3.8 too.checks(checks.yaml, Dart 3.7.2) —dart format --set-exit-if-changedfails. Several added lines exceed 80 cols / aren'tdart formatoutput (e.g. the firsttest(...)description in the newdoc importsgroup, and thegetDartPackageUsage(File('${d.sandbox}/project/main.dart'),)call wrapping in the new unit test file).build(build.yaml, Dart 3.7.2) — release/analyze surface: this is a user-facing behavior change with noCHANGELOG.mdentry under# Unreleasedand noversionbump inpubspec.yaml; this repo auto-releases off those and every prior behavior change landed with a changelog entry.
Design concerns
- Silent behavior regression for existing consumers. Merging doc-import-only lib/ usage into
packagesUsedOutsidePublicDirsfeeds the fataloverPromotedDependenciescheck. A package that doc-importspackage:fooinlib/and legitimately declaresfooas a runtimedependency(very common — you doc-import what you also use) will start failing with exit 1 purely from upgrading. The ticket says these "likely only need to bedev_dependencies" — that's a floor, not a prohibition. Recommend treating doc-import-only packages as satisfied by eitherdependenciesordev_dependencies: keep them out of "missing" and "unused", but exclude them from over-promotion. If we deliberately want the stricter behavior, it needs a version bump plus README + CHANGELOG notes. - Test coverage gap on the traversal itself. All doc-import fixtures attach the comment to a
library;directive.GeneralizingAstVisitor.visitCommentis only reached becauseAnnotatedNode.visitChildrenwalksdocumentationComment; the un-exercised (and more common) case is a@docImporton a class/function doc comment in a file with nolibrary;directive. Also worth cases for a doc import with ashow/asclause and one inbin/. - Nit / follow-up (non-blocking): the file and class names (
import_export_ast_visitor.dart,ImportExportVisitor) no longer describe what they do; consider renaming in a follow-up now that the return type isDartPackageUsage.getDartDirectivePackageNameswas removed outright — it's underlib/src/, so not public API, but mention the removal in the changelog entry.
Please get all three CI jobs green and resolve the over-promotion semantics, then re-request review.
- Exclude doc-import-only lib/ packages from over-promotion checks - Bump Dart SDK to 3.8.1 in CI, tool-versions, and pubspec (^3.8.0) - Pass explicit FeatureSet 3.8.0 to parseString for doc imports - Add requireDart38 test fixture environment for doc import tests - Expand AST visitor tests (declaration comments, show/as, bin/) - Run dart format and bump version to 5.1.0 with CHANGELOG entry Co-authored-by: Dustin Pauze <dustin.pauze@workiva.com>
- Run dart format across the repo with Dart 3.8.1 - Remove obsolete test/pubspec_to_json.dart (pubspec_parse now has toJson) - Fix unused_catch_stack in dependency_validator.dart Co-authored-by: Dustin Pauze <dustin.pauze@workiva.com>
engops-wk
left a comment
There was a problem hiding this comment.
Review round 2 — CHANGES REQUESTED (posted as a comment; GitHub blocks REQUEST_CHANGES on one's own PR)
Do not merge: CI is red, and there are two compatibility problems beyond the CI break.
The core model is right — separating @docImport usage from real directive usage and treating lib/ doc imports as non-runtime is the correct semantics, and test/import_export_ast_visitor_test.dart has good coverage (show/as clauses, bin/, dart: scheme, mixed).
Failing CI checks
unit-tests / test-unit (sdk 3.8.1)— compile failure.test/pubspec_to_json.dartwas deleted andimport 'pubspec_to_json.dart';removed fromtest/utils.dart, butcheckProject()andcheckWorkspace()still callpubspec.toJson().Pubspecfrompubspec_parsehas notoJson(); it came only from the deletedPubspecToJsonextension. Every test inexecutable_test.dartandworkspace_test.dartfails, including the newdoc importsgroup.checks / analyze (sdk 3.8.1)— same error:The method 'toJson' isn't defined for the type 'Pubspec'intest/utils.dart.build (sdk 3.8.1)— blocked by the same analysis error.
The deletion of test/pubspec_to_json.dart is unrelated to doc-import support and looks accidental.
Correctness / compatibility
lib/src/import_export_ast_visitor.dartpins the parser feature set to language version 3.8.0 — strictly narrower than the previous default (FeatureSet.latestLanguageVersion()). Any consumer file using 3.9+ syntax will fail to parse and hitexit(1). Remove the pin.pubspec.yamlraises the SDK floor from^3.0.0to^3.8.0while releasing as5.1.0— a breaking constraint change in a minor release. Major bump, or keep the floor and detect capability dynamically.- CHANGELOG says doc-import-only packages are "not flagged as ... missing," which contradicts the implementation and the new test
fails when a package referenced via doc import in lib/ is missing from pubspec.
Non-blocking observations
- Much of the diff in
test/workspace_test.dart,lib/src/constants.dart,lib/src/pubspec_config.dart,test/utils_test.dartisdart format3.8 style churn; call it out in the PR body so reviewers don't hunt for logic there. packagesUsedViaDocImportInPublicFilesis both merged intopackagesUsedOutsidePublicDirsand removed fromoverPromotedDependencies; a one-line comment at the declaration ("valid in either dependency section") would help future maintainers.- Consider a test asserting a doc import in a
test/file still counts as dev usage, to lock in the non-public-file branch.
Push the helper fix, get all three jobs green, and address items 1–3. Happy to re-review promptly.
- Remove hardcoded FeatureSet from parseString (use analyzer default) - Bump version to 6.0.0 to reflect breaking SDK floor (^3.8.0) - Fix CHANGELOG wording for doc-import dependency requirements - Bump pubspec_parse to ^1.6.0 for native Pubspec.toJson() in tests Co-authored-by: Dustin Pauze <dustin.pauze@workiva.com>
engops-wk
left a comment
There was a problem hiding this comment.
Review round 3 — CHANGES REQUESTED (posted as a comment; GitHub blocks REQUEST_CHANGES on one's own PR). CI is red — not approving.
CI failed before this review started, and the failures are reproducible from the diff.
Failing checks and root causes
1. unit-tests (Workiva/gha-dart-oss/.github/workflows/test-unit.yaml@v0.1.14, sdk 3.8.1) — failing. Two independent causes:
-
Whole suite broken by the
test/pubspec_to_json.dartdeletion. Round 2 flagged this as a compile error; it's now "fixed" by relying onpubspec_parse1.6.0's realPubspec.toJson(). That resolves compilation but not behavior: the generated_$PubspecToJsonemits every field unconditionally, including'version': null,'description': null,'repository': null,'flutter': null,'executables': {},'workspace': null,'resolution': null. The deleted hand-rolledPubspecToJsonextension deliberately emitted only name/environment/dependencies/dev_dependencies withif (x != null)guards.pubrejectsversion: null, so everycheckProject/checkWorkspace-based test now writes an invalidpubspec.yamlinto the sandbox and fails at resolve time. This is the broadest failure and it takes down pre-existing tests, not just the new ones. -
New visitor tests assert behavior the visitor does not have. Four of the eight tests in
test/import_export_ast_visitor_test.dartput the@docImportin a doc comment separated from the following declaration by a blank line and with nolibrary;directive (...without a library directive,show clauses,as clauses,bin/ files). A///block followed by a blank line is a dangling comment: the analyzer does not attach it to the next declaration, it never becomes anAnnotatedNode.documentationComment, and soGeneralizingAstVisitor.visitCommentis never invoked for it. These tests expect{'meta'}/{'collection'}and will getisEmpty. This is exactly the traversal gap round 2 asked you to cover — the test was added, but written in a form that documents a real hole instead of closing it.
2. checks (checks.yaml@v0.1.14) — expected to fail on dart format --set-exit-if-changed. Round 2's formatting comment was addressed for the new files, but bumping environment: sdk to ^3.8.0 switches dart format to tall style for the entire package, and untouched files were not reformatted — e.g. bin/dependency_validator.dart (the argParser cascade and the two Logger.root.onRecord chains) and lib/src/utils.dart (listFilesWithExtensionIn chain) still carry short-style wrapping. Run dart format . on 3.8.1 and commit the full result.
Good progress since round 2
The over-promotion regression is genuinely fixed (..removeAll(packagesUsedViaDocImportInPublicFiles)), the hard-pinned featureSet was correctly dropped, the version is now 6.0.0 with the SDK floor documented, and the CHANGELOG wording no longer contradicts the tests. The core design — DartPackageUsage splitting directive vs. doc-import usage, and folding doc-import-only lib/ usage into the "used outside lib/" set — is the right model. Remaining blockers are correctness/CI, not architecture.
Also blocking
- Real behavior gap behind the bad tests. The dangling-comment case isn't only a test bug: a library-level
@docImportat the top of a file with nolibrary;is silently missed and the package is still reported as unused. Fix the visitor (also scanunit.beginToken.precedingComments) and the tests, rather than reshaping tests to match the gap. analyzerlower bound.>=7.1.0 <15.0.0still permits analyzer 7.x, which has noComment.docImports— a compile error for consumers who resolve an older analyzer, even though this repo resolves higher.- CHANGELOG structure.
# Unreleasedis now an empty heading sitting directly above# 6.0.0; consolidate so the publish workflow reads unambiguously.
Please push the fixes, get CI green, then re-request review.
- Restore test/pubspec_to_json.dart with pubspecToJson() that omits null entries - Scan beginToken.precedingComments for dangling file-level @DocImport comments - Fix doc-import AST visitor tests and add regression for dangling comments - Raise analyzer lower bound to >=8.0.0 for Comment.docImports support - Remove empty CHANGELOG Unreleased heading Co-authored-by: Dustin Pauze <dustin.pauze@workiva.com>
|
@cursor Resolve the merge conflicts |
|
Merge conflicts are resolved and pushed in commit Conflicts resolved
Verification
The branch |
Co-authored-by: Dustin Pauze <dustin.pauze@workiva.com>
|
@cursor Resolve the failing format and analyze checks |
|
Fixed and pushed in commit Analyze
Format
Verification
|
Co-authored-by: Dustin Pauze <dustin.pauze@workiva.com>
|
@cursor the ci format check is still failing |
|
Fixed and pushed in commit The format check was failing because Reformatted |
Co-authored-by: Dustin Pauze <dustin.pauze@workiva.com>


Opened by Dustin Pauze with the ai-sdlc workflow for FEDX-7267
Pull Request
Intent
This change adds support for Dart's
@docImportdocumentation imports (introduced in Dart 3.8) when scanning package usage, so packages referenced only via doc imports inlib/are no longer incorrectly flagged as unused. Since doc imports are not runtime dependencies, packages used only that way are treated like non-public usage for dependency promotion purposes — they can live in eitherdependenciesordev_dependencieswithout triggering an over-promotion warning, but they still must be declared somewhere inpubspec.yaml.Changes
lib/src/import_export_ast_visitor.dart: ReplacedgetDartDirectivePackageNames/ImportExportVisitor.packageNameswith a newgetDartPackageUsageAPI returning aDartPackageUsagerecord that separatesdirectivePackageNames(import/export) fromdocImportPackageNames(@docImport). Adds comment-token scanning (visitComment,_collectDocImportsFromPrecedingComments,_docImportUriPattern) to pick up doc imports both attached to AST nodes and dangling at the top of a file.lib/src/dependency_validator.dart: Updated usage collection incheckPackageto callgetDartPackageUsageinstead of the removed API; doc-import-only packages found inlib/are added topackagesUsedOutsidePublicDirsand excluded from the over-promoted dependencies set so they aren't flagged when placed indev_dependencies. Also includes minor formatting cleanup (removed unused catch binding, reformatted multi-line expressions).pubspec.yaml/.tool-versions/.github/workflows/ci.yaml: Raised minimum SDK to^3.8.0(required for doc import syntax support in the analyzer), bumpedanalyzerto>=8.0.0 <15.0.0,pubspec_parseto^1.6.0, and package version to6.0.0; CI and.tool-versionsnow pin Dart3.8.1.CHANGELOG.md: Documents the6.0.0release — doc import support, promotion rules for doc-import-only packages, removal ofgetDartDirectivePackageNames, and the new Dart 3.8 minimum requirement.test/import_export_ast_visitor_test.dart(new): Unit tests forgetDartPackageUsagecovering plain imports/exports, doc imports in library/declaration/dangling comments, combined usage,show/asclauses on doc imports, and doc imports inbin/files.test/executable_test.dart: Adds an end-to-enddoc importstest group covering passing/failing scenarios for dev_dependency-only, dependency-only, missing-from-pubspec, and unused-flag suppression cases for doc-import usage.test/utils.dart,test/pubspec_to_json.dart: Adds anenvironmentparameter tocheckProject(with newrequireDart38constant) and replaces the ad hocPubspecToJson.toJsonextension with apubspecToJsonhelper that strips null/empty fields, needed to keep generated sandbox pubspecs valid underpub.test/workspace_test.dart,test/utils_test.dart,lib/src/constants.dart,lib/src/pubspec_config.dart: Formatting-only churn (re-indentation/re-wrapping) from runningdart formatunder the updated SDK/formatter version, no behavioral change.How To QA
dart pub getthendart test(or the CI unit-test workflow) against Dart SDK 3.8.1 as configured in.tool-versions; confirm all tests pass, including the newtest/import_export_ast_visitor_test.dartand thedoc importsgroup intest/executable_test.dart.dev_dependency(e.g.meta) referenced only via/// @docImport 'package:meta/meta.dart';in alib/*.dartfile, rundart run dependency_validator, and confirm it reports "No dependency issues found!" instead of flaggingmetaas unused or over-promoted.pubspec.yamlentirely while still referencing it via@docImportinlib/; run the validator and confirm it now reports the package under "These packages are used outside lib/ but are not dev_dependencies:".dependency(not dev) and only used via doc import inlib/is still accepted without an over-promotion warning.pubspec.yaml.