All checks were successful
JaCoCo Coverage #### Project Overview
No changes detected, that affect the code coverage.
* Line Coverage: 61.49% (17397/28294)
* Branch Coverage: 52.32% (6724/12852)
* Lines of Code: 28294
* Cyclomatic Complexity: 11339
#### Quality Gates Summary
Output truncated.
Test / Build skipped: 15, passed: 608
Intrepid/Prometeu/Studio/pipeline/pr-master This commit looks good
75 lines
4.2 KiB
Markdown
75 lines
4.2 KiB
Markdown
---
|
|
id: LSN-0055
|
|
ticket: multi-frontend-provider-contract
|
|
title: Static frontend providers before plugin architecture
|
|
created: 2026-07-15
|
|
tags: [compiler, compiler-general, studio, frontend, registry, multi-frontend]
|
|
---
|
|
|
|
## Context
|
|
|
|
Prometeu needed a multi-frontend boundary without turning the compiler or Studio into a dynamic plugin platform. Before this work, shared code could ask the registry for frontend specs or phase services, and PBS was registered directly as the default language. That worked for a single frontend, but it made the next frontend harder because common code could still depend on PBS-specific construction details.
|
|
|
|
The durable ownership rule is now: common compiler and Studio code select a frontend by `languageId`, then consume a provider contract. PBS remains the first and only real provider, but it is no longer the shape of the shared abstraction.
|
|
|
|
## Key Decisions
|
|
|
|
### `FrontendProvider` is the common registration unit
|
|
|
|
**What:** Each registered frontend is represented by a `FrontendProvider` with:
|
|
|
|
- `specification()`, for the static frontend contract and `languageId`;
|
|
- `compiler()`, for compiler-facing frontend execution;
|
|
- `languageService()`, as an optional editor-facing capability.
|
|
|
|
**Why:** This groups the frontend identity, compiler entrypoint, and optional tooling capability without forcing every frontend to implement Studio/editor services.
|
|
|
|
**Trade-offs:** The provider is intentionally small. It does not solve dynamic discovery, plugin installation, external loading, or all future language-service APIs. Those are separate architectural decisions.
|
|
|
|
### Registration is explicit
|
|
|
|
**What:** Frontend registration is static and composition-root-owned. The application composition path bootstraps the default provider set, and the registry resolves providers by `languageId`.
|
|
|
|
**Why:** Explicit registration keeps dependencies visible and testable. It lets composition know about PBS while preventing common compiler and Studio consumers from directly constructing PBS services.
|
|
|
|
**Trade-offs:** Adding a new in-repository frontend still requires a code change in composition. That is acceptable because this decision optimizes for repository-internal multi-frontend readiness, not external plugin extensibility.
|
|
|
|
### PBS is a provider, not the shared model
|
|
|
|
**What:** PBS is wrapped by `PBSFrontendProvider`. Shared build and Studio consumers obtain frontend behavior through `FrontendRegistryService.require(languageId)` or provider-derived listings.
|
|
|
|
**Why:** PBS remains the correctness baseline, but it must not become the exclusive owner of compiler pipeline semantics.
|
|
|
|
**Trade-offs:** PBS-specific tests may still instantiate `PBSFrontendPhaseService` directly because they test PBS internals. Common modules should not.
|
|
|
|
## Patterns and Algorithms
|
|
|
|
Use this path for common compiler execution:
|
|
|
|
1. Resolve the project language from the manifest or default provider.
|
|
2. Resolve `FrontendProvider` by `languageId`.
|
|
3. Use `provider.specification()` for static metadata.
|
|
4. Use `provider.compiler()` for frontend compilation.
|
|
5. Use `provider.languageService()` only when a tooling consumer needs optional editor services.
|
|
|
|
Use this path for Studio language catalogs:
|
|
|
|
1. List providers from the registry.
|
|
2. Derive templates from `provider.specification()`.
|
|
3. Do not hardcode PBS templates in Studio catalog code.
|
|
|
|
## Pitfalls
|
|
|
|
- Do not add reflection, classpath scanning, external JAR loading, or runtime plugin installation to solve repository-internal frontend registration.
|
|
- Do not make `languageService()` mandatory. Compilation and editor assistance are separate capabilities.
|
|
- Do not instantiate `PBSFrontendPhaseService` from common build, dependency, Studio, or app code.
|
|
- Do not use PBS as a fallback for unknown `languageId`. Unknown languages must fail explicitly.
|
|
- Do not move frontend semantic ownership into Studio just because Studio consumes provider metadata.
|
|
|
|
## Takeaways
|
|
|
|
- Static providers are enough to prepare for multiple in-repository frontends.
|
|
- The registry boundary is provider-based, not PBS-based.
|
|
- Composition may know which frontends exist; common consumers should only know `FrontendProvider`.
|
|
- Optional editor capabilities keep compiler readiness independent from Studio feature depth.
|