Skip to content

Centralize dictionary loading policy - #66

Merged
barad1tos merged 3 commits into
mainfrom
refactor/dictionary-loading-owner
Aug 13, 2026
Merged

barad1tos merged 3 commits into
mainfrom
refactor/dictionary-loading-owner

Conversation

@barad1tos

@barad1tos barad1tos commented Aug 13, 2026 •

Copy link
Copy Markdown
Owner

── Summary ─────────────────────────────────

Dictionary loading split error handling, recovery, persistence, and registry initialization between the file provider and cache generator, which made typed failures unreliable and could persist transient copy failures as permanently non-scriptable applications.

Centralize loading policy in SdefFileProvider while keeping SdefDictionaryFileGenerator focused on file production and preserving every existing nullable caller boundary.

── Changes ─────────────────────────────────

  • Refactor: SdefFileProvider.kt — Own typed outcomes, bundled recovery, persistence side effects, interruption handling, and registry initialization.
  • Refactor: SdefDictionaryFileGenerator.kt — Surface generation failures, clean partial cache files, and distinguish a missing bundled SDEF from a failed cache copy.
  • Refactor: DictionaryLoadResult.kt — Document the actual empty, loaded, and failed contracts without stale phase references.
  • Test: DictionaryLoadPolicyTest.kt — Cover recovery, I/O, cancellation, interruption, not-scriptable persistence, malformed SDEF compatibility, programming-error propagation, and cross-platform generator behavior.

── Validation ──────────────────────────────

  • ./gradlew ktlintCheck detekt check build verifyPlugin --warning-mode all — Passed; coverage held, generated sources matched, the service graph remained acyclic, and Plugin Verifier reported compatibility with IC 2025.1, IC 2025.2, and IU 2026.1.
  • ./gradlew test --tests com.intellij.plugin.applescript.test.service.DictionaryLoadPolicyTest --tests com.intellij.plugin.applescript.test.service.SdefFileProviderTest --tests com.intellij.plugin.applescript.test.service.DictionaryStartupPipelineTest --tests com.intellij.plugin.applescript.test.service.CoroutineColdStartTest --tests com.intellij.plugin.applescript.test.service.ParserDictionaryLookupFreezeTest --tests com.intellij.plugin.applescript.test.codeinsight.AppleScriptCodeInsightTest --rerun-tasks ktlintCheck detekt verifyServiceDependencyGraph --warning-mode all — Passed.
  • IntelliJ inspections for all four touched files — 0 warnings or errors.
  • Focused mutation checks — failure mapping and bundled recovery regressions both failed under the intended production mutations and passed after restoration.

── Notes ───────────────────────────────────

The public fetch and createAndInitializeInfo JVM descriptors are preserved. The nullable compatibility path still returns null for expected loading failures, while unexpected programming errors retain their previous propagation boundary.

Pre-existing EDT blocking and shell process-tree teardown remain separate architecture slices so this PR stays limited to loading ownership and transition safety.

- Make SdefFileProvider own recovery, persistence, result mapping, and registry initialization
- Keep cache generation mechanical while distinguishing missing bundled definitions from copy failures
- Cover typed failures, cancellation, interruption, recovery, and legacy compatibility boundaries

Impact: dictionary loads report actionable failures without changing existing nullable caller behavior
@sourcery-ai

sourcery-ai Bot commented Aug 13, 2026

Copy link
Copy Markdown

Reviewer's Guide

Centralizes dictionary loading policy by moving error and recovery handling into SdefFileProvider, simplifying SdefDictionaryFileGenerator, and adding a comprehensive test suite for dictionary load behavior and failure modes.

Sequence diagram for centralized dictionary loading policy

sequenceDiagram
    actor DictionaryClient
    participant SdefFileProvider
    participant SdefDictionaryFileGenerator
    participant RegistryService as AppleScriptSystemDictionaryRegistryService
    participant PersistenceService as SdefPersistenceService

    DictionaryClient->>SdefFileProvider: loadDictionary(applicationIoFile, applicationName)
    SdefFileProvider->>RegistryService: getDictionaryInfoByNameInternal(applicationName)
    RegistryService-->>SdefFileProvider: DictionaryInfo?

    SdefFileProvider->>SdefFileProvider: generateFile(applicationName, applicationIoFile, generateDictionaryFile, recoverDictionaryFile)
    activate SdefFileProvider
    SdefFileProvider->>SdefDictionaryFileGenerator: generateDictionaryFile(applicationName, applicationIoFile)

    alt [generateDictionaryFile succeeds]
        SdefDictionaryFileGenerator-->>SdefFileProvider: dictionaryFile
    else [DeveloperToolsNotInstalledException]
        SdefDictionaryFileGenerator--xSdefFileProvider: DeveloperToolsNotInstalledException
        SdefFileProvider->>SdefFileProvider: recoverDictionaryFile(applicationName, applicationIoFile)
        SdefFileProvider->>SdefDictionaryFileGenerator: recoverDictionaryFile(applicationName, applicationIoFile)
        SdefDictionaryFileGenerator-->>SdefFileProvider: dictionaryFile?
    end
    deactivate SdefFileProvider

    alt [dictionaryFile is null]
        SdefFileProvider-->>DictionaryClient: DictionaryLoadResult.Failed
    else [dictionaryFile available]
        SdefFileProvider->>SdefFileProvider: registerDictionary(applicationName, applicationIoFile, dictionaryFile)
        SdefFileProvider->>PersistenceService: addDictionaryInfo(DictionaryInfo)
        SdefFileProvider->>RegistryService: initializeDictionaryFromInfoInternal(DictionaryInfo)
        RegistryService-->>SdefFileProvider: Boolean
        alt [initialized]
            SdefFileProvider-->>DictionaryClient: DictionaryLoadResult.Loaded
        else [initialization failed]
            SdefFileProvider-->>DictionaryClient: DictionaryLoadResult.Failed
        end
    end
Loading

File-Level Changes

Change Details Files
Refactor dictionary file generation to return cache files only and delegate persistence and policy decisions to the caller.
  • Rename generator entrypoint to generateDictionaryFile and change its return type from DictionaryInfo? to File?.
  • Introduce optional generateCacheFile callback to allow injection of custom generation behavior for tests or alternative strategies.
  • Inline failure handling in the caller and simplify post-generation cleanup to delete partial files when generation fails.
  • Extract recoverDictionaryFile to handle bundled sdef discovery and copying with injectable copy behavior.
  • Narrow generator responsibilities to running the sdef/cat command and throwing typed exceptions instead of catching and persisting state.
src/main/kotlin/com/intellij/plugin/applescript/lang/dictionary/files/SdefDictionaryFileGenerator.kt
Centralize dictionary loading, persistence, and error-policy handling in SdefFileProvider using DictionaryLoadResult.
  • Add loadDictionary API that orchestrates generation, recovery, registration, and initialization, returning DictionaryLoadResult.
  • Use generateFile helper to fall back from generator failures to bundled recovery when Developer Tools are not installed.
  • Move dictionary registration, persistence updates, and ApplicationDiscoveryService ignore-list removal into registerDictionary.
  • Add initializeDictionary helper that converts initialization success/failure into Loaded/Failed results.
  • Encode DeveloperToolsNotInstalledException handling in failedDeveloperToolsLoad, including not-scriptable persistence updates.
  • Simplify createAndInitializeInfo to bridge to the new loadDictionary and preserve legacy null-based contract.
src/main/kotlin/com/intellij/plugin/applescript/lang/dictionary/files/SdefFileProvider.kt
Clarify DictionaryLoadResult semantics to match the centralized load policy.
  • Update KDoc to describe the three outcomes in terms of generation, recovery, and initialization.
  • Adjust Failed.reason documentation to reference generation/initialization predicates instead of fetch-specific guards.
src/main/kotlin/com/intellij/plugin/applescript/lang/dictionary/discovery/DictionaryLoadResult.kt
Add tests that specify and verify the centralized dictionary load and failure policy.
  • Introduce DictionaryLoadPolicyTest to cover malformed sdef handling, I/O failures, interrupts, bundled recovery, missing recovery, cache-copy failures, cancellation and IllegalState propagation, generator failure behavior, and not-scriptable application handling.
  • Use injectable generateDictionaryFile and recoverDictionaryFile callbacks to simulate different failure modes and recovery paths.
  • Verify persistence behavior for not-scriptable applications and that transient I/O failures do not blacklist apps.
  • Assert that interrupted generation preserves the interrupt flag and removes partial cache files.
  • Ensure legacy createAndInitializeInfo continues to collapse initialization failures to null.
src/test/kotlin/com/intellij/plugin/applescript/test/service/DictionaryLoadPolicyTest.kt

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@barad1tos
barad1tos marked this pull request as ready for review August 13, 2026 21:24

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Sorry @barad1tos, you have reached your weekly rate limit of 1500000 diff characters.

Please try again later or upgrade to continue using Sourcery

@codecov

codecov Bot commented Aug 13, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 57.44681% with 40 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
...ng/dictionary/files/SdefDictionaryFileGenerator.kt 40.47% 20 Missing and 5 partials ⚠️
...lescript/lang/dictionary/files/SdefFileProvider.kt 71.15% 11 Missing and 4 partials ⚠️

📢 Thoughts on this report? Let us know!

@barad1tos
barad1tos merged commit e21bbc4 into main Aug 13, 2026
11 checks passed
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.

1 participant