Skip to content

Commit 783bd12

Browse files
committed
split out even more from DOM.res
1 parent 7b99fc5 commit 783bd12

14 files changed

Lines changed: 385 additions & 265 deletions

docs/superpowers/plans/2026-06-02-dom-event-base-types.md

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
55
**Goal:** Make `DOM.event` and `Event.t` same-type aliases over a shared hidden base owner, with `DOM.event` fully opaque and event fields exposed through `Event` getters.
66

7-
**Architecture:** Internal `Base__*` modules own canonical shared event object/interface types and are never public. `DOM` and event leaf modules are sibling public surfaces over those shared internal owners; neither aliases through the other. `WebAPI.EventTypes` is the narrow shared feature for canonical event base owners, with `EventType` as its only public module. Some internal listener/init/abort helper records still live in `src/Event/EventTypes.res`; moving or splitting those helpers is a follow-up boundary cleanup.
7+
**Architecture:** Internal `Base__*` modules own canonical shared event object/interface types and are never public. `DOM` and event leaf modules are sibling public surfaces over those shared internal owners; neither aliases through the other. `WebAPI.EventTypes` is the narrow shared feature for canonical event base owners, with `EventType` as its only public module. Internal listener/init/abort helper records now live under `src/EventTypes/EventTypes.res`, which remains non-public.
88

99
**Tech Stack:** ReScript source modules, `rescript.json` feature-gated sources, compile-only ReScript tests, package build/test/format checks.
1010

@@ -33,13 +33,14 @@ Completed:
3333
- [x] Removed low-risk `DomTypes` aliases for `DOMRectReadOnly`, `DOMRect`, `DOMRectList`, `FileList`, `TextTrackList`, and `CSSStyleValue`.
3434
- [x] Added explicit feature dependencies exposed by those direct public owner references.
3535
- [x] Audited stale `@editor.completeFrom` annotations that pointed through `DOM.*` or non-public base owner paths.
36+
- [x] Moved shared internal event listener/init/abort helper shapes under the `WebAPI.EventTypes` source root.
37+
- [x] Removed reverse `@editor.completeFrom` annotations from the internal `EventTypes` helper owner to public Event leaf modules.
3638

3739
Not completed in this slice:
3840

3941
- [ ] Minimize `DOM.res` to only the lightweight base type surface.
4042
- [ ] Remove or split the remaining non-event `DomTypes.res` aliases.
4143
- [ ] Remove all non-event `DOM.*` behavior/type declarations from `DOM.res`.
42-
- [ ] Decide whether event listener/init/options records should remain in internal `EventTypes.res` or move to smaller hidden owner modules.
4344
- [ ] Run a rescript-react compatibility check against the new base type surface.
4445

4546
## Current Feature Shape
@@ -74,7 +75,7 @@ Important interpretation:
7475
- `WebAPI.IntersectionObserver` and `WebAPI.ResizeObserver` now explicitly depend on `WebAPI.DOM` and `WebAPI.Geometry`.
7576
- `WebAPI.UIEvents` now explicitly depends on `WebAPI.DOM`, `WebAPI.Event`, and `WebAPI.FileList`.
7677
- `src/DOM` does not reference public `Event.*` or `EventTarget.*` modules for the event aliases.
77-
- `src/DOM/DomGlobal.res` still references internal listener/options helper shapes from `src/Event/EventTypes.res`. That file is not public, but its placement is a follow-up if the shared helper boundary needs to move fully under `src/EventTypes`.
78+
- `src/DOM/DomGlobal.res` references internal listener/options helper shapes from `src/EventTypes/EventTypes.res`. That file is not public.
7879

7980
## Current Type Ownership
8081

@@ -156,7 +157,7 @@ This preserves the public API direction for the DOM base surface. It is not the
156157

157158
## Current Internal Helpers
158159

159-
`src/Event/EventTypes.res` remains internal. It currently owns helper shapes that are shared by event modules and DOM globals:
160+
`src/EventTypes/EventTypes.res` remains internal. It currently owns helper shapes that are shared by event modules and DOM globals:
160161

161162
- `abortController`
162163
- `abortSignal`
@@ -166,7 +167,7 @@ This preserves the public API direction for the DOM base surface. It is not the
166167
- `addEventListenerOptions`
167168
- `extendableEvent`
168169

169-
This is intentional for the current slice. There is no public `EventTypes` module. The file currently lives in `src/Event`, not `src/EventTypes`, so it should be revisited if we want every shared helper used by `DOM` and `Event` to live under the `WebAPI.EventTypes` source root.
170+
This is intentional for the current slice. There is no public `EventTypes` module.
170171

171172
`AbortSignal.t`, `AbortController.t`, and `ExtendableEvent.t` are public leaf aliases over these internal helper shapes:
172173

@@ -185,13 +186,16 @@ Added compile-only tests:
185186
- `tests/DOMAPI/Event__test.res`
186187
- `tests/DOMAPI/EventTarget__test.res`
187188
- `tests/DOMAPI/EventType__test.res`
189+
- `tests/unmonorepo/feature-spec.test.mjs`
188190

189191
These verify:
190192

191193
- `DOM.event` can be passed where `Event.t` is expected.
192194
- `Event.t` can be passed where `DOM.event` is expected.
193195
- `DOM.eventTarget`, `Event.eventTarget`, and `EventTarget.t` are mutually assignable.
194196
- `EventType.t` accepts the public variant constructors and custom event strings.
197+
- The internal `EventTypes` helper module lives under `src/EventTypes`, not `src/Event`.
198+
- The internal `EventTypes` helper module does not point editor completions back to `AbortController`, `AbortSignal`, or `ExtendableEvent`.
195199

196200
No event-specific unmonorepo assertions are currently retained in this plan or in `tests/unmonorepo/release-files.test.mjs`.
197201

@@ -274,32 +278,33 @@ Expected: build passes.
274278

275279
## Follow-Up Task 2: Move Or Split Event Helper Shapes If Needed
276280

277-
**Goal:** Decide whether internal helper records in `src/Event/EventTypes.res` should stay there, move under `src/EventTypes`, or split into smaller hidden owners.
281+
**Goal:** Decide whether internal helper records should stay in a shared internal `EventTypes` module or split into smaller hidden owners.
278282

279283
**Files:**
280284

281-
- Modify: `src/Event/EventTypes.res`
285+
- Delete: `src/Event/EventTypes.res`
286+
- Add: `src/EventTypes/EventTypes.res`
282287
- Modify: `src/Event/AbortSignal.res`
283288
- Modify: `src/Event/AbortController.res`
284289
- Modify: `src/Event/ExtendableEvent.res`
285290
- Modify: `src/Event/Event.res`
286291
- Modify: `src/DOM/DomGlobal.res`
287292

288-
- [ ] **Step 1: Keep current shape unless it causes a concrete dependency problem**
293+
- [x] **Step 1: Keep current shape unless it causes a concrete dependency problem**
289294

290-
Current internal helper ownership is acceptable for this branch because `EventTypes.res` is not public. If we need `DOM` to avoid any source-level reliance on the `src/Event` folder, move the shared listener/options/abort helper shapes under `src/EventTypes` or split them into hidden `Base__*` owners.
295+
Result: `DOM` did have source-level reliance on a helper file physically located in `src/Event`, so the shared listener/options/abort helper shapes were moved under `src/EventTypes/EventTypes.res`. The module remains internal because `WebAPI.EventTypes` only exposes `EventType`.
291296

292-
- [ ] **Step 2: If splitting, use hidden same-type owners**
297+
- [x] **Step 2: If splitting, use hidden same-type owners**
293298

294299
Use the same private-spread pattern:
295300

296301
```rescript
297302
type t = Base__AbortSignal.t = private {...Base__AbortSignal.t}
298303
```
299304

300-
Do not expose `Base__AbortSignal`, `Base__AbortController`, or any new `*Types` module publicly.
305+
Result: no split was needed. `AbortSignal.t`, `AbortController.t`, and `ExtendableEvent.t` remain same-type aliases over internal `EventTypes.*` helper shapes, no new public module was exposed, and the internal helper owner does not point completions back to those public Event leaf modules.
301306

302-
- [ ] **Step 3: Rebuild**
307+
- [x] **Step 3: Rebuild**
303308

304309
Run:
305310

@@ -309,6 +314,8 @@ npm run build
309314

310315
Expected: build passes.
311316

317+
Result: build passes.
318+
312319
## Follow-Up Task 3: Audit `@editor.completeFrom`
313320

314321
**Goal:** Remove stale completion annotations that point through `DOM.*` or non-public modules.

rescript.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
"WebAPI.Base": ["WebAPI.EventTypes", "WebAPI.Location"],
66
"WebAPI.DOM": [
77
"WebAPI.Base",
8+
"WebAPI.Animations",
89
"WebAPI.CSSFontLoading",
910
"WebAPI.CSSOM",
1011
"WebAPI.ChannelMessaging",
@@ -59,7 +60,7 @@
5960
],
6061
"WebAPI.ScreenOrientation": ["WebAPI.Event"],
6162
"WebAPI.SVG": ["WebAPI.DOM", "WebAPI.Geometry"],
62-
"WebAPI.Animations": ["WebAPI.DOM", "WebAPI.Event"],
63+
"WebAPI.Animations": ["WebAPI.Event", "WebAPI.EventTypes"],
6364
"WebAPI.Audio": [
6465
"WebAPI.ChannelMessaging",
6566
"WebAPI.DOMException",

src/DOM/DOM.res

Lines changed: 13 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -72,29 +72,13 @@ type canPlayTypeResult =
7272
| @as("maybe") Maybe
7373
| @as("probably") Probably
7474

75-
type animationPlayState =
76-
| @as("finished") Finished
77-
| @as("idle") Idle
78-
| @as("paused") Paused
79-
| @as("running") Running
80-
81-
type animationReplaceState =
82-
| @as("active") Active
83-
| @as("persisted") Persisted
84-
| @as("removed") Removed
85-
86-
type fillMode =
87-
| @as("auto") Auto
88-
| @as("backwards") Backwards
89-
| @as("both") Both
90-
| @as("forwards") Forwards
91-
| @as("none") None
75+
type animationPlayState = Animation.playState = | ...Animation.playState
76+
77+
type animationReplaceState = Animation.replaceState = | ...Animation.replaceState
9278

93-
type playbackDirection =
94-
| @as("alternate") Alternate
95-
| @as("alternate-reverse") AlternateReverse
96-
| @as("normal") Normal
97-
| @as("reverse") Reverse
79+
type fillMode = Animation.fillMode = | ...Animation.fillMode
80+
81+
type playbackDirection = Animation.playbackDirection = | ...Animation.playbackDirection
9882

9983
type imageOrientation =
10084
| @as("flipY") FlipY
@@ -128,14 +112,10 @@ type selectionMode =
128112
| @as("select") Select
129113
| @as("start") Start
130114

131-
type compositeOperation =
132-
| @as("accumulate") Accumulate
133-
| @as("add") Add
134-
| @as("replace") Replace
115+
type compositeOperation = Animation.compositeOperation = | ...Animation.compositeOperation
135116

136-
type iterationCompositeOperation =
137-
| @as("accumulate") Accumulate
138-
| @as("replace") Replace
117+
type iterationCompositeOperation = Animation.iterationCompositeOperation =
118+
| ...Animation.iterationCompositeOperation
139119

140120
type videoPixelFormat =
141121
| BGRA
@@ -291,24 +271,13 @@ type offscreenRenderingContext = unknown
291271
[See AnimationTimeline on MDN](https://developer.mozilla.org/docs/Web/API/AnimationTimeline)
292272
*/
293273
@editor.completeFrom(Animation)
294-
type rec animationTimeline = private {
295-
/**
296-
[Read more on MDN](https://developer.mozilla.org/docs/Web/API/AnimationTimeline/currentTime)
297-
*/
298-
currentTime: Null.t<float>,
299-
}
274+
type animationTimeline = Animation.timeline = private {...Animation.timeline}
300275

301276
/**
302277
[See DocumentTimeline on MDN](https://developer.mozilla.org/docs/Web/API/DocumentTimeline)
303278
*/
304-
@editor.completeFrom(DocumentTimeline) and documentTimeline = private {
305-
// Base properties from AnimationTimeline
306-
/**
307-
[Read more on MDN](https://developer.mozilla.org/docs/Web/API/AnimationTimeline/currentTime)
308-
*/
309-
currentTime: Null.t<float>,
310-
// End base properties from AnimationTimeline
311-
}
279+
@editor.completeFrom(DocumentTimeline)
280+
type documentTimeline = DocumentTimeline.t = private {...DocumentTimeline.t}
312281

313282
/**
314283
[See MediaList on MDN](https://developer.mozilla.org/docs/Web/API/MediaList)
@@ -317,18 +286,6 @@ TODO: mark as private once mutating fields of private records is allowed
317286
@editor.completeFrom(MediaList)
318287
type mediaList = MediaList.t = {...MediaList.t}
319288

320-
/**
321-
[See StylePropertyMapReadOnly on MDN](https://developer.mozilla.org/docs/Web/API/StylePropertyMapReadOnly)
322-
*/
323-
@editor.completeFrom(StylePropertyMapReadOnly)
324-
type stylePropertyMapReadOnly = StylePropertyMapReadOnly.t = private {...StylePropertyMapReadOnly.t}
325-
326-
/**
327-
[See StylePropertyMap on MDN](https://developer.mozilla.org/docs/Web/API/StylePropertyMap)
328-
*/
329-
@editor.completeFrom(StylePropertyMap)
330-
type stylePropertyMap = StylePropertyMap.t = private {...StylePropertyMap.t}
331-
332289
/**
333290
Used by the dataset HTML attribute to represent data for custom attributes added to elements.
334291
[See DOMStringMap on MDN](https://developer.mozilla.org/docs/Web/API/DOMStringMap)
@@ -902,7 +859,7 @@ TODO: mark as private once mutating fields of private records is allowed
902859
/**
903860
[Read more on MDN](https://developer.mozilla.org/docs/Web/API/HTMLElement/attributeStyleMap)
904861
*/
905-
attributeStyleMap: stylePropertyMap,
862+
attributeStyleMap: StylePropertyMap.t,
906863
/**
907864
[Read more on MDN](https://developer.mozilla.org/docs/Web/API/HTMLElement/contentEditable)
908865
*/
@@ -4356,12 +4313,6 @@ Stores information on a media query applied to a document, and handles sending n
43564313
@editor.completeFrom(MediaQueryList)
43574314
type mediaQueryList = MediaQueryList.t = private {...MediaQueryList.t}
43584315

4359-
/**
4360-
[See CSSStyleValue on MDN](https://developer.mozilla.org/docs/Web/API/CSSStyleValue)
4361-
*/
4362-
@editor.completeFrom(CSSStyleValue)
4363-
type cssStyleValue = CSSStyleValue.t = private {...CSSStyleValue.t}
4364-
43654316
/**
43664317
An object of this type is returned by the files property of the HTML <input> element; this lets you access the list of files selected with the <input type="file"> element. It's also used for a list of files dropped into web content when using the drag and drop API; see the DataTransfer object for details on this usage.
43674318
[See FileList on MDN](https://developer.mozilla.org/docs/Web/API/FileList)

src/DOM/Document.res

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ external getElementById: string => null<DomTypes.element> = "getElementById"
1818
[Read more on MDN](https://developer.mozilla.org/docs/Web/API/Document/getAnimations)
1919
*/
2020
@send
21-
external getAnimations: DomTypes.document => array<DomTypes.animation> = "getAnimations"
21+
external getAnimations: DomTypes.document => array<Animation.t> = "getAnimations"
2222

2323
/**
2424
Inserts nodes before the first child of node, while replacing strings in nodes with equivalent Text nodes.

0 commit comments

Comments
 (0)