Skip to content

refactor(domain): enrich NoteInput with extractScopeAndTags (#210) - #216

Merged
pajoma merged 2 commits into
developfrom
feat/210-rich-domain-models
May 18, 2026
Merged

refactor(domain): enrich NoteInput with extractScopeAndTags (#210)#216
pajoma merged 2 commits into
developfrom
feat/210-rich-domain-models

Conversation

@pajoma

@pajoma pajoma commented May 18, 2026

Copy link
Copy Markdown
Owner

Summary

  • Moves SCOPE_DEFAULT from src/vscode/conf.tssrc/model/config.ts (re-exported for backward compat)
  • Changes Input._text/_scope/_tags from privateprotected; _scope initializes to SCOPE_DEFAULT at field declaration (no more empty-string default)
  • Adds NoteInput.extractScopeAndTags(availableScopes: string[]): void with hardened regex /#\w+(?:\s|$)/g (handles end-of-string tags)
  • Parser.resolveNotePathForInput delegates to extractScopeAndTags; removes inline tag loop and now-unused imports
  • LoadNotes constructor narrowed to NoteInput; callers updated with type assertions
  • 5 unit tests added (no vscode API needed; pure sync)

Closes #210

Spec: docs/specs/2026-05-17-210-rich-domain-models.md
Plan: docs/plans/2026-05-17-210-rich-domain-models.md

Test plan

  • npm run compile — clean build
  • npx tsc --noEmit — no type errors
  • Run extension tests: NoteInput.extractScopeAndTags suite (5 scenarios including end-of-string regex coverage)
  • Manual smoke test: open note with #scope tag, verify scope routing and tag stripping

🤖 Generated with Claude Code

Move tag/scope extraction from Parser into NoteInput, making the domain
layer the primary owner of this invariant.

- SCOPE_DEFAULT migrated from src/vscode/conf.ts to src/model/config.ts
  (re-exported from vscode layer for backward compat)
- Input._text/_scope/_tags changed private → protected to enable subclass
  method; _scope initializes to SCOPE_DEFAULT at field declaration
- NoteInput.extractScopeAndTags(availableScopes) added: uses hardened
  regex /#\w+(?:\s|$)/g to handle end-of-string tags; no state reset
- Parser.resolveNotePathForInput delegates to extractScopeAndTags;
  removes inline tag loop and SCOPE_DEFAULT/isNullOrUndefined imports
- LoadNotes constructor narrowed from Input to NoteInput; callers updated
  with type assertions where parseInput() return type is still Input
- 5 unit tests added to input.test.ts (no vscode API needed)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@pajoma

pajoma commented May 18, 2026

Copy link
Copy Markdown
Owner Author

Architecture Review: Final Approval (PR #216)

I have performed a critical architectural and OOP-focused review of this PR. The implementation is technically sound and represents a significant maturity leap for our domain layer.

Key Achievements:

  • OOP Maturity: Successfully transitioned to a Rich Domain Model by moving internal state normalization (extractScopeAndTags) into the model. The use of protected fields correctly balances encapsulation with subclass extensibility.
  • Structural Integrity: Migrating SCOPE_DEFAULT to model/config.ts ensures our business invariants are decoupled from the platform integration layer.
  • Regex Robustness: The hardened regex (/#\w+(?:\s|$)/g) resolves a long-standing edge case for end-of-string tags, improving the reliability of the "Smart Input" feature.
  • Improved Testability: The addition of pure, dependency-free unit tests for the model demonstrates the immediate value of this refactoring for our CI feedback loop.

Final Observation:

While the type assertions (as NoteInput) in the UI and Action layers are a temporary byproduct of our transition, they are acceptable pragmatic tradeoffs that allow us to enforce correct subclassing in our core features (LoadNotes).

This is a high-quality, domain-driven refactor. LGTM.


Note: Gemini was involved in creating this comment (but not without consulting me).

The (input as NoteInput) cast is TypeScript-only; at runtime Parser
receives plain Input objects from parseInput(), causing
"extractScopeAndTags is not a function". The service contract
resolveNotePathForInput(input: Input) requires the method on Input.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@pajoma
pajoma merged commit e3e99b6 into develop May 18, 2026
2 checks passed
@pajoma
pajoma deleted the feat/210-rich-domain-models branch May 18, 2026 06:22
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.

Arch: Move business logic from Actions/Util to Rich Domain Models

1 participant