Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
128 changes: 0 additions & 128 deletions inputfiles/addedTypes.jsonc
Original file line number Diff line number Diff line change
@@ -1,40 +1,6 @@
{
"interfaces": {
"interface": {
// ImportMeta is not a true DOM interface, but we are forced to declare it as one in order to emit method definitions.
// We cannot define methods as dictionary properties with function types,
// as this would cause conflicts with ImportMeta method overrides in places like @types/node.
"ImportMeta": {
"name": "ImportMeta",
"exposed": "Window Worker",
"noInterfaceObject": true,
"properties": {
"property": {
"url": {
"name": "url",
"type": "DOMString"
}
}
},
"methods": {
"method": {
"resolve": {
"name": "resolve",
"signature": [
{
"param": [
{
"name": "specifier",
"type": "DOMString"
}
],
"type": "DOMString"
}
]
}
}
}
},
"AudioWorkletProcessorImpl": {
"name": "AudioWorkletProcessorImpl",
"extends": "AudioWorkletProcessor",
Expand Down Expand Up @@ -332,48 +298,6 @@
}
}
},
// This is used in many DT libraries, via ckeditor
"ClientRect": {
"name": "ClientRect",
"exposed": "Window",
"deprecated": true,
"extends": "DOMRect",
"noInterfaceObject": true
},
/*
Keeping EventListener and EventListenerObject isn't the most elegant way to handle
the event listeners, but we need to keep the EventListener as an extendable interface
for libraries like angular.
*/
"EventListener": {
"name": "EventListener",
"noInterfaceObject": true,
"methods": {
"method": {
// This is a hack to add a call signature, but I think it's reasonable
// as it means we don't have to add a call signatures section to the
// emitter for this one case.
"callable": {
"overrideSignatures": [
"(evt: Event): void"
]
}
}
}
},
"EventListenerObject": {
"name": "EventListenerObject",
"noInterfaceObject": true,
"methods": {
"method": {
"handleEvent": {
"overrideSignatures": [
"handleEvent(object: Event): void"
]
}
}
}
},
"Document": {
"methods": {
"method": {
Expand Down Expand Up @@ -415,32 +339,6 @@
]
}
},
// This is used in the React d.ts files, and not including
// it would force an update for anyone using React.
"StyleMedia": {
"name": "StyleMedia",
"exposed": "Window",
"noInterfaceObject": true,
"deprecated": true,
"properties": {
"property": {
"type": {
"name": "type",
"type": "DOMString"
}
}
},
"methods": {
"method": {
"matchMedium": {
"name": "matchMedium",
"overrideSignatures": [
"matchMedium(mediaquery: string): boolean"
]
}
}
}
},
"Navigator": {
"name": "Navigator",
"properties": {
Expand Down Expand Up @@ -610,32 +508,6 @@
"OVR_multiview2": {
"overrideExposed": "Window Worker"
},
// The spec removed `timestamp` but browsers still have it.
// https://github.com/w3c/webrtc-encoded-transform/pull/204
"RTCEncodedAudioFrame": {
"properties": {
"property": {
"timestamp": {
"mdnUrl": "https://developer.mozilla.org/docs/Web/API/RTCEncodedAudioFrame/timestamp",
"name": "timestamp",
"type": "long long",
"readonly": true
}
}
}
},
"RTCEncodedVideoFrame": {
"properties": {
"property": {
"timestamp": {
"mdnUrl": "https://developer.mozilla.org/docs/Web/API/RTCEncodedVideoFrame/timestamp",
"name": "timestamp",
"type": "long long",
"readonly": true
}
}
}
},
"RTCDTMFSender": {
"events": {
"event": [
Expand Down
48 changes: 48 additions & 0 deletions inputfiles/patches/forced-declare.kdl
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// This is used in many DT libraries, via ckeditor
interface ClientRect exposed=Window deprecated=#true extends=DOMRect noInterfaceObject=#true

// Keeping EventListener and EventListenerObject isn't the most elegant way to handle the event listeners, but we need to keep the EventListener as an extendable interface for libraries like angular.
interface EventListener noInterfaceObject=#true {
method callable {
type void
param evt type=Event
}
}

interface EventListenerObject noInterfaceObject=#true {
method handleEvent {
type void
param object type=Event
}
}

// ImportMeta is not a true DOM interface, but we are forced to declare it as one in order to emit method definitions.
// We cannot define methods as dictionary properties with function types, as this would cause conflicts with ImportMeta method overrides in places like @types/node.
interface ImportMeta exposed="Window Worker" noInterfaceObject=#true {
property url type=DOMString
method resolve {
type DOMString
param specifier type=DOMString
}
}

// The spec removed `timestamp` but browsers still have it.
// https://github.com/w3c/webrtc-encoded-transform/pull/204
interface RTCEncodedAudioFrame {
property timestamp type="long long" readonly=#true mdnUrl="https://developer.mozilla.org/docs/Web/API/RTCEncodedAudioFrame/timestamp"
}

interface RTCEncodedVideoFrame {
property timestamp type="long long" readonly=#true mdnUrl="https://developer.mozilla.org/docs/Web/API/RTCEncodedVideoFrame/timestamp"
}


// This is used in the React.d.ts files, and not includin
// it would force an update for anyone using React.
interface StyleMedia exposed=Window noInterfaceObject=#true deprecated=#true {
property type type=DOMString
method matchMedium {
type boolean
param mediaquery type=DOMString
}
}
39 changes: 33 additions & 6 deletions src/build/patches.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,21 +15,41 @@ type DeepPartial<T> = T extends object
? { [K in keyof T]?: DeepPartial<T[K]> }
: T;

function optionalMember<const T>(prop: string, type: T, value?: Value) {
function optionalMember<T extends Value | Value[]>(
prop: string,
type: T,
value?: unknown,
) {
if (value === undefined) {
return {};
}
if (typeof value !== type) {
throw new Error(`Expected type ${value} for ${prop}`);

// Normalize to array
const types = Array.isArray(type) ? type : [type];

// Check if value matches one of the types
if (!types.some((t) => typeof value === t)) {
throw new Error(
`Expected ${types.join(" or ")} for ${prop}, got ${typeof value}`,
);
}

return {
[prop]: value as T extends "string"
? string
: T extends "number"
? number
: T extends "boolean"
? boolean
: never,
: T extends (infer U)[]
? U extends "string"
? string
: U extends "number"
? number
: U extends "boolean"
? boolean
: never
: never,
};
}

Expand Down Expand Up @@ -169,7 +189,11 @@ function handleMixinandInterfaces(

const interfaceObject = type === "interface" && {
...optionalMember("exposed", "string", node.properties?.exposed),
...optionalMember("deprecated", "string", node.properties?.deprecated),
...optionalMember(
"deprecated",
["string", "boolean"],
node.properties?.deprecated,
),
...optionalMember(
"noInterfaceObject",
"boolean",
Expand Down Expand Up @@ -210,6 +234,8 @@ function handleProperty(child: Node): Partial<Property> {
...optionalMember("optional", "boolean", child.properties?.optional),
...optionalMember("overrideType", "string", child.properties?.overrideType),
...optionalMember("type", "string", child.properties?.type),
...optionalMember("readonly", "boolean", child.properties?.readonly),
...optionalMember("mdnUrl", "string", child.properties?.mdnUrl),
};
}

Expand Down Expand Up @@ -254,7 +280,8 @@ function handleMethod(child: Node): Partial<Method> {
...handleTyped(typeNode),
},
];
return { name, signature };
// Added special handling for "callable" methods to omit the name for EventListener
return { name: name === "callable" ? undefined : name, signature };
}

/**
Expand Down