Repository navigation
Adopt folder features with flat interface modules #342
Description
Problem
The current layout conflates three separate concerns:
- which public module owns an interface or supporting type,
- which feature bundle a consumer enables, and
- how source files are grouped for ReScript feature compilation.
That has left foundational DOM types spread across broad compatibility modules, source features that do not consistently match domain ownership, and documentation that can imply nested namespaces even though the useful public API is interface-oriented.
Goal
Adopt a structure built around folder features with flat interface modules.
- Keep public modules flat and discoverable, such as
WebAPI.Document,WebAPI.Response, andWebAPI.HTMLInputElement. - Expose exactly 27 supported
WebAPI.*consumer features as practical domain bundles. - Give each source folder one unqualified internal feature and make each public feature imply its owning folder plus its required public dependencies.
- Keep
WebAPI.DOMa small foundation and layer the larger DOM surface through Event, DOMPlatform, DOMNodes, HTML, and Window. - Put interface-specific types and operations in their owning modules instead of broad aggregate modules.
- Use MDN categories for documentation and navigation, not as public namespace segments or permanent ownership rules.
This separates stable public module paths from coarse consumer dependency bundles and from the compiler's internal source graph.
Folder structure examples
Each source folder is a complete internal compiler feature. Files inside the folder continue to produce flat public modules; the folder name does not become a public namespace segment.
A representative DOM and HTML layout is:
src/
├── core/ internal feature: DOM
│ ├── DOM.res public: WebAPI.DOM
│ └── EventType.res public: WebAPI.EventType
├── event/ internal feature: Event
│ ├── Event.res public: WebAPI.Event
│ ├── EventTarget.res public: WebAPI.EventTarget
│ └── AbortController.res
├── dom-platform/ internal feature: DOMPlatform
│ ├── DOMException.res
│ └── DOMTokenList.res
├── dom-nodes/ internal feature: DOMNodes
│ ├── Node.res public: WebAPI.Node
│ ├── Element.res public: WebAPI.Element
│ └── Range.res public: WebAPI.Range
├── html/ internal feature: HTML
│ ├── HTMLElement.res
│ ├── HTMLInputElement.res
│ └── HTMLFormElement.res
└── window/ internal feature: Window
├── Window.res public: WebAPI.Window
├── Document.res public: WebAPI.Document
├── Location.res public: WebAPI.Location
└── History.res public: WebAPI.History
Other browser domains follow the same pattern:
src/
├── fetch/ internal feature: Fetch
│ ├── Fetch.res public: WebAPI.Fetch
│ ├── Request.res public: WebAPI.Request
│ ├── Response.res public: WebAPI.Response
│ └── Headers.res public: WebAPI.Headers
├── file/ internal feature: File
│ ├── Blob.res
│ ├── File.res
│ └── FileList.res
├── media/ internal feature: Media
│ ├── MediaStream.res
│ ├── MediaDevices.res
│ └── HTMLVideoElement.res
├── web-audio/ internal feature: WebAudio
│ ├── AudioContext.res
│ ├── AudioNode.res
│ └── AudioParam.res
└── workers/ internal feature: Workers
├── Worker.res
├── ServiceWorker.res
└── ServiceWorkerScope.res
For example, src/fetch/Response.res remains WebAPI.Response, but consumers enable it through the WebAPI.Fetch feature. It does not become WebAPI.Fetch.Response, and WebAPI.Response does not become a separate supported feature.
Public features expand into the required folder features and public dependencies. Representative relationships include:
WebAPI.DOM -> DOM
WebAPI.Event -> WebAPI.DOM + Event
WebAPI.DOMNodes -> WebAPI.DOMPlatform + WebAPI.Animation + WebAPI.CSSOM
+ WebAPI.Geometry + DOMNodes
WebAPI.HTML -> WebAPI.DOMNodes + WebAPI.File + HTML
WebAPI.Window -> WebAPI.HTML + WebAPI.Media + WebAPI.Storage
+ WebAPI.Messaging + WebAPI.Crypto + WebAPI.Performance
+ WebAPI.ViewTransitions + Window
WebAPI.Fetch -> WebAPI.Event + WebAPI.File + WebAPI.URL + Fetch
WebAPI.WebAudio -> WebAPI.Media + WebAPI.Messaging + WebAudio
WebAPI.Workers -> WebAPI.Messaging + WebAPI.Storage + Workers
Public features
The supported consumer-facing feature surface contains exactly these 27 features:
WebAPI.Animation |
WebAPI.Canvas |
WebAPI.Crypto |
WebAPI.CSSFontLoading |
WebAPI.CSSOM |
WebAPI.Device |
WebAPI.DOM |
WebAPI.DOMNodes |
WebAPI.DOMPlatform |
WebAPI.Event |
WebAPI.Fetch |
WebAPI.File |
WebAPI.Geometry |
WebAPI.HTML |
WebAPI.Media |
WebAPI.Messaging |
WebAPI.Navigator |
WebAPI.Observers |
WebAPI.Performance |
WebAPI.Storage |
WebAPI.SVG |
WebAPI.UIEvents |
WebAPI.URL |
WebAPI.ViewTransitions |
WebAPI.WebAudio |
WebAPI.Window |
WebAPI.Workers |
These are consumer dependency bundles, not an exhaustive list of public modules. A feature can expose many flat interface modules and can imply other features transitively.
Intent
This is primarily an ownership, packaging, and documentation migration. It should preserve existing binding behavior and flat public module paths while making dependencies and type ownership explicit.
Temporary aliases and compatibility modules are acceptable only as incremental migration boundaries. They should be removed by the end of the stack. Where existing public signatures require broader dependencies than the provisional feature map suggested, the implementation should record the compiler-proven dependency closure rather than hide or omit those relationships.
Implementation
The work is split into two reviewable phases:
- Flat interface ownership and compatibility cleanup: starts at refactor: separate EventType feature #298 and ends at refactor: move CSS and stylesheets out of DOM #288. This establishes the flat interface/type boundaries, migrates consumers away from broad
DomTypes/wrapper ownership, and removes the temporary compatibility scaffolding. - Folder and feature graph migration: starts at refactor: establish DOM core folder #311 and ends at test: guard the public feature graph #341. This reorganizes sources into domain folders, defines the 27 public feature bundles and their transitive implications, cleans up shared helpers, updates documentation, and adds CI guardrails.
Non-goals
- Creating one supported consumer feature per interface.
- Introducing nested public paths such as
WebAPI.Fetch.ResponseorWebAPI.DOM.Window. - Adding new browser behavior or broadly redesigning binding signatures as part of the reorganization.
- Adding module-slice exceptions without evidence that a whole-folder dependency is materially too expensive.
- Treating future MDN category changes as public API renames.
Completion criteria
- Public interface modules and supporting types have clear local owners.
- Obsolete aggregate compatibility modules and transitional aliases are removed.
- The source tree has one unqualified internal folder feature for each supported public domain.
- Exactly 27 qualified
WebAPI.*consumer features are supported with explicit, compiler-valid transitive dependencies. - Existing flat public module paths and binding behavior are preserved.
- Every supported public feature compiles independently.
- CI validates folder ownership, feature uniqueness, public module uniqueness, dependency completeness, and the supported feature list.
- API documentation is generated from the public module lists and explains the distinction between feature bundles and flat module paths.
Activity
jderochervlk commentedon Aug 7, 2026
Follow-ups from #287
.taliases for recursive DOM interface modules such asElement,Node, andHTMLElement, and use those aliases in their implementations (review context).AnimationEffect.tare intentionally empty, and audit the other empty types for the same treatment (review comment).Animation.animationTimelineshould be shortened toAnimation.timelinenow that the type lives in the dedicatedAnimationmodule (review comment).jderochervlk commentedon Aug 7, 2026
Follow-ups from #302
private { ...Parent.t }so editor completions include the parent surface, and use an explicit type equation such astype t = Parent.t = private { ...Parent.t }when the interface intentionally has the same type identity. Audit the DOM, HTML, SVG, and other record-backed interface modules and add an automated guard or representative completion/type tests if feasible (review comment).refactor: colocate animation and mutation types (#303)
refactor: define HTML form and table interfaces locally (#304)
refactor: define HTML document interfaces locally (#305)
refactor: define HTML link interfaces locally (#306)
refactor: define embedded resource interfaces locally (#309)
refactor: define HTML media interfaces locally (#307)
refactor: define SVG interfaces locally (#308)
refactor: remove DOM compatibility types (#310)
refactor: move CSS and stylesheets out of DOM (#288)
refactor: establish DOM core folder (#311)
refactor: establish Event folder feature (#312)
refactor: establish DOMPlatform folder feature (#313)
16 remaining items
refactor: establish SVG folder feature (#330)
refactor: establish Observers folder feature (#331)
refactor: establish UIEvents folder feature (#332)
refactor: establish Canvas folder feature (#333)
refactor: establish Storage folder feature (#334)
refactor: establish Workers folder feature (#335)
refactor: establish Navigator folder feature (#336)
refactor: complete Canvas interface ownership (#337)
refactor: complete Device interface ownership (#338)
refactor: establish Window folder feature (#339)
refactor: clean up shared feature helpers (#340)
test: guard the public feature graph (#341)
chore: remove obsolete unmonorepo tooling (#345)
Enforce completion owners for public type aliases (#350)