Skip to content

feat(parsers): add Dart public API parser via package:analyzer (alternative to #35)#41

Merged
grdsdev merged 10 commits into
mainfrom
feat/dart-parser-analyzer
Jun 22, 2026
Merged

feat(parsers): add Dart public API parser via package:analyzer (alternative to #35)#41
grdsdev merged 10 commits into
mainfrom
feat/dart-parser-analyzer

Conversation

@spydon

@spydon spydon commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

Summary

Alternative to #35. Adds Dart/Flutter public API surface parsing to the SDK compliance workflow using a small package:analyzer tool (dart_symbol_extractor) instead of the dartdoc_json CLI plus a Node.js normalizer.

Same goal as #35 (gate supabase-flutter PRs via validate-sdk-compliance.yml with language: dart), same ParseResult output contract, but a different implementation. Pick one.

Design spec: docs/specs/2026-06-22-dart-parser-analyzer.md.

Approach

A Dart tool parses each package's lib/**.dart files syntactically with the real analyzer front end and emits the existing ParseResult shape directly. It is invoked via a parse-dart npm script, exactly like parse-ts/parse-swift, so the reusable workflow's generic parse step is unchanged.

supabase-flutter PR
  → validate-sdk-compliance.yml
      [dart-only] dart-lang/setup-dart
      [dart-only] dart pub get   (in dart_symbol_extractor/)
      → npm run parse-dart -- <sdk-root>   # PR   → pr-symbols.json
      → npm run parse-dart -- <sdk-root>   # base → base-symbols.json
      → check-api-symbols pr-symbols.json base-symbols.json sdk-compliance.yaml

Why this instead of dartdoc_json (#35)

  • No third-party CLI. The tool is owned in-repo and pinned via pubspec.lock. dartdoc_json 0.5.0 was last published ~18 months ago.
  • Handles extension type (Dart 3.3+) by construction. dartdoc_json 0.5.0 throws on it, which is why feat(parsers): add Dart/Flutter public API surface parser via dartdoc_json #35 has to assert supabase-flutter never uses one.
  • Fewer moving parts. Removes the global tool activation, per-package flutter pub get, the per-package JSON files, the jq -s merge, and the Node normalizer. The workflow diff is correspondingly smaller.
  • Syntactic parse → no pub get on the target packages, no network, no resolvable dependency graph. Only the Dart SDK and the tool's own deps are needed.
  • Honors .sdk-parse-ignore (the feat(parsers): add Dart/Flutter public API surface parser via dartdoc_json #35 Dart path bypasses it), matching the TypeScript and Swift parsers.

Symbol model

Matches the mapping used by the other parsers and #35's normalizer, so it is a drop-in at the ParseResult boundary: classes/mixins/enums/extension-types/named-extensions → class; methods/operators → method; getters/setters/fields → property; constructors → Owner.name (unnamed → Owner.Owner); top-level functions → function; top-level variables/typedefs → variable. Name-based privacy (_-prefixed excluded). Enum constants are not emitted (matching #35).

Changes

Added

  • scripts/capability-matrix/dart_symbol_extractor/ — the Dart tool (lib/src/extractor.dart, parsed_symbol.dart, ignore_matcher.dart, bin/extract.dart)
  • test/extractor_test.dart + a fixture package — unit tests for the symbol model and ignore matcher, plus discovery/exclusion/relative-path integration tests
  • docs/specs/2026-06-22-dart-parser-analyzer.md — design spec

Modified

  • .github/workflows/validate-sdk-compliance.ymldart case plus two dart-only setup steps (dart-lang/setup-dart, dart pub get)
  • scripts/capability-matrix/package.json — adds parse-dart
  • CLAUDE.md, README.md — document the Dart parser and language: dart

Test plan

  • dart test (9) and dart analyze clean; dart format applied
  • Node suite unaffected: npm test (99) and npm run typecheck pass
  • E2E: run against a local supabase-flutter checkout, extracts the expected surface (1379 symbols, e.g. SupabaseClient and members, correct constructor/getter/field kinds)

Trade-offs

  • Adds a Dart package and a Dart SDK setup step to a primarily Node toolchain.
  • The .sdk-parse-ignore matcher reimplements a documented subset of gitignore rather than reusing the npm ignore package.
  • Syntactic and per-file like the other parsers: does not resolve export directives, so a public-named declaration in lib/src counts even if never exported (same altitude as the existing parsers).

Alternative to #35: extract the Dart/Flutter public API surface with a small
package:analyzer tool instead of the dartdoc_json CLI plus a Node normalizer.

The tool parses lib/**.dart syntactically (no pub get, no network), emits the
existing ParseResult shape, and is invoked via a parse-dart npm script so the
reusable workflow's generic parse step is unchanged. It handles extension types
and enhanced enums by construction, and honors .sdk-parse-ignore for parity with
the TypeScript and Swift parsers.

Removes the need for dartdoc_json activation, per-package flutter pub get, the jq
merge, and the Node normalizer.
@spydon spydon requested review from a team as code owners June 22, 2026 06:54
spydon added 4 commits June 22, 2026 08:54
The supabase/sdk Actions policy only permits GitHub-owned and verified-creator
actions, so dart-lang/setup-dart caused a workflow startup failure. Install the
SDK with a plain download instead, which also keeps the reusable workflow
independent of each calling repo's allowed-actions policy.
Self-review found three issues:
- A class-type alias (class C = A with B;) was emitted with kind variable
  instead of class, because ClassTypeAlias is a subtype of TypeAlias.
- Directory ignore patterns (build/, examples/) excluded only the directory
  entry itself, not the files nested beneath it, so contents leaked into the
  surface.
- A single unreadable or unparseable lib file aborted the whole extraction;
  it is now skipped with a stderr warning.

Adds regression tests for each.
Install the Dart SDK with the dart-lang/setup-dart action instead of a manual
download. Replace the SymbolKindJson extension with SymbolKind.name, special
casing only classKind since 'class' is a reserved word.
@spydon spydon closed this Jun 22, 2026
@spydon spydon reopened this Jun 22, 2026
spydon added 3 commits June 22, 2026 10:24
Replace the if-else type ladder in _visitTopLevel with a switch on Dart 3
patterns: the five class-like containers share one case, and a small _emit
helper centralizes the private-name guard for simple symbols. Output is
unchanged.

@grdsdev grdsdev left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

parsing AST directly is fine for me, I'd just move the dart_symbol_extractor dart package out of the capability-matrix, to not mix different languages in the same folder, what do you think?

Relocate the package from scripts/capability-matrix/dart_symbol_extractor to
scripts/dart_symbol_extractor as a sibling of the Node validator. Update the
parse-dart npm script path, both workflows' working directories, the
validate-capabilities paths filter, and the CLAUDE.md reference.
The reusable workflow now runs 'dart run bin/extract.dart' from the extractor
package for the dart language, instead of dispatching through an npm script.
Removes the parse-dart entry from package.json.
@grdsdev grdsdev merged commit e3ba07a into main Jun 22, 2026
3 checks passed
@grdsdev grdsdev deleted the feat/dart-parser-analyzer branch June 22, 2026 11:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants