Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Event.currentTarget type #207

Closed
wants to merge 12 commits into from
92 changes: 73 additions & 19 deletions TS.fsx
Original file line number Diff line number Diff line change
Expand Up @@ -670,6 +670,10 @@ module Data =
let extendConflictsBaseTypes =
extendConflicts |> List.map (fun ec -> (ec.BaseType, ec)) |> Map.ofList

// these types are only mixins to define shared events, they don't extend the EventTarget interface, therefore no need to
// emit "addEventListener" for them
let nonEventTargetTypes = ["GlobalEventHandlers"; "AbstractWorker"; "XMLHttpRequestEventTarget"; "MSBaseReader"]

module Emit =
open Data
open Types
Expand Down Expand Up @@ -698,7 +702,7 @@ module Emit =
| "DOMString" -> "string"
| "DOMTimeStamp" -> "number"
| "EndOfStreamError" -> "number"
| "EventListener" -> "EventListenerOrEventListenerObject"
| "EventListener" -> "EventListenerOrEventListenerObject<this>"
| "double" | "float" -> "number"
| "Function" -> "Function"
| "long" | "long long" | "signed long" | "signed long long" | "unsigned long" | "unsigned long long" -> "number"
Expand Down Expand Up @@ -854,8 +858,17 @@ module Emit =
String.Join(", ", (List.map paramToString ps))

let EmitCallBackInterface (i:Browser.Interface) =
Pt.Printl "interface %s {" i.Name
Pt.PrintWithAddedIndent "(evt: Event): void;"
if i.Name = "EventListener" then
Pt.Printl "interface %s<T extends EventTarget> {" i.Name
Pt.PrintWithAddedIndent "(evt: Event<T>): void;"
else
Pt.Printl "interface %s {" i.Name
let handleEventMethod = i.Methods.Value.Methods |> Array.find (fun m -> m.Name.Value = "handleEvent")
let paramList =
[for p in handleEventMethod.Params do
yield {Type = p.Type; Name = p.Name; Optional = p.Optional.IsSome; Variadic = p.Variadic.IsSome; Nullable = p.Nullable.IsSome}]
Pt.PrintWithAddedIndent "(%s): void;" (ParamsToString paramList)

Pt.Printl "}"
Pt.Printl ""

Expand Down Expand Up @@ -892,6 +905,11 @@ module Emit =
| Some pollutor -> "this: " + pollutor.Name + ", "
| _ -> ""

let ComputeEventTypeParameter containingInterfaceName flavor (prefix: string) =
if prefix.StartsWith("declare ") then "<" + GetGlobalPollutorName flavor + ">"
elif List.contains containingInterfaceName nonEventTargetTypes then "<T>"
else "<this>"

let EmitProperties flavor prefix (emitScope: EmitScope) (i: Browser.Interface) (conflictedMembers: Set<string>) =
let emitPropertyFromJson (p: InputJsonType.Root) =
let readOnlyModifier =
Expand Down Expand Up @@ -928,7 +946,11 @@ module Emit =
getEventTypeInInterface p.EventHandler.Value i
else
"Event"
String.Format("({0}ev: {1}) => any", EmitEventHandlerThis flavor prefix i, eType)
String.Format(
"({0}ev: {1}{2}) => any",
EmitEventHandlerThis flavor prefix i,
eType,
ComputeEventTypeParameter i.Name flavor prefix)
| _ -> DomTypeToTsType p.Type
let pTypeAndNull = if p.Nullable.IsSome then makeNullable pType else pType
let readOnlyModifier = if p.ReadOnly.IsSome && prefix = "" then "readonly " else ""
Expand Down Expand Up @@ -968,7 +990,7 @@ module Emit =
matchScope emitScope m &&
not (prefix <> "" && OptionCheckValue "addEventListener" m.Name)

let emitMethod flavor prefix (i:Browser.Interface) (m:Browser.Method) =
let emitMethod flavor (prefix: string) (i:Browser.Interface) (m:Browser.Method) =
let printLine content =
if m.Name.IsSome && conflictedMembers.Contains m.Name.Value then Pt.PrintlToStack content else Pt.Printl content
// print comment
Expand All @@ -982,6 +1004,13 @@ module Emit =
let removedType = Option.bind (fun name -> InputJson.getRemovedItemByName name InputJson.ItemKind.Method i.Name) m.Name
let overridenType = Option.bind (fun mName -> InputJson.getOverriddenItemByName mName InputJson.ItemKind.Method i.Name) m.Name

let replaceThisWithGlobalPollutor (signature: string) =
if prefix.StartsWith "declare " then
let regex = Regex(@"\bthis\b")
regex.Replace(signature, GetGlobalPollutorName flavor)
else
signature

if removedType.IsNone then
match overridenType with
| Some t ->
Expand All @@ -1005,7 +1034,7 @@ module Emit =

let overloads = GetOverloads (Function.Method m) false
for { ParamCombinations = pCombList; ReturnTypes = rTypes; Nullable = isNullable } in overloads do
let paramsString = ParamsToString pCombList
let paramsString = ParamsToString pCombList |> replaceThisWithGlobalPollutor
let returnString =
let returnType = rTypes |> List.map DomTypeToTsType |> String.concat " | "
if isNullable then makeNullable returnType else returnType
Expand Down Expand Up @@ -1058,7 +1087,9 @@ module Emit =
prefix iParent.Name i.Name iParent.Name

let shouldEmitStringEventHandler =
if iNameToEhList.ContainsKey i.Name && not iNameToEhList.[i.Name].IsEmpty then
if List.contains i.Name nonEventTargetTypes then
false
elif iNameToEhList.ContainsKey i.Name && not iNameToEhList.[i.Name].IsEmpty then
emitEventHandler fPrefix i
true
elif iNameToEhParents.ContainsKey i.Name && not iNameToEhParents.[i.Name].IsEmpty then
Expand All @@ -1071,8 +1102,9 @@ module Emit =

if shouldEmitStringEventHandler then
Pt.Printl
"%saddEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void;"
"%saddEventListener(type: string, listener: EventListenerOrEventListenerObject%s, useCapture?: boolean): void;"
fPrefix
(ComputeEventTypeParameter i.Name flavor prefix)

let EmitConstructorSignature (i:Browser.Interface) =
let emitConstructorSigFromJson (c: InputJsonType.Root) =
Expand Down Expand Up @@ -1123,16 +1155,18 @@ module Emit =
Pt.Printl "declare var %s: {new(%s): %s; };" nc.Name (ParamsToString ncParams) i.Name)

let EmitInterfaceDeclaration (i:Browser.Interface) =
let processIName iName =
let generateBaseTypeNameIfNecessary iName =
match Map.tryFind iName extendConflictsBaseTypes with
| Some _ -> iName + "Base"
| _ -> iName

let processedIName = processIName i.Name
if processedIName <> i.Name then
Pt.PrintlToStack "interface %s extends %s {" i.Name processedIName
let baseTypeName = generateBaseTypeNameIfNecessary i.Name
if baseTypeName <> i.Name then
Pt.PrintlToStack "interface %s extends %s {" i.Name baseTypeName
Pt.Printl "interface %s" baseTypeName
else
Pt.Printl "interface %s" i.Name

Pt.Printl "interface %s" processedIName
let finalExtends =
let overridenExtendsFromJson =
InputJson.getOverriddenItemsByInterfaceName ItemKind.Extends Flavor.All i.Name
Expand All @@ -1151,11 +1185,31 @@ module Emit =
else
overridenExtendsFromJson

combinedExtends |> List.map processIName

match finalExtends with
| [] -> ()
| allExtends -> Pt.Print " extends %s" (String.Join(", ", allExtends))
combinedExtends |> List.map generateBaseTypeNameIfNecessary

let mutable typeParameter = ""
let mutable extendsToPrint = finalExtends
if List.contains i.Name nonEventTargetTypes || i.Name = "Event" then
typeParameter <- "<T extends EventTarget = EventTarget>"

if not (List.isEmpty finalExtends) then
// Cases:
// 1. Direct inheritance of "Event"
// interface XYZEvent<T> extends EventTarget = EventTarget> extends Event<T>
// 2. Indirect inheritance of "Event"
// interface XYZEvent<T> extends EventTarget = EventTarget> extends UIEvent<T>
if IsDependsOn i.Name "Event" then
typeParameter <- "<T extends EventTarget = EventTarget>"
extendsToPrint <- extendsToPrint |> List.map (fun baseType -> if baseType = "Event" || IsDependsOn baseType "Event" then baseType + "<T>" else baseType)
// If the current interface inherits from one of the non-eventtarget mixin types, the
// type argument should be the interface itself, if it also extends EventTarget. E.g.
//
// interface XYZEventTarget extends EventTarget, GlobalEventHandlers<XYZEventTarget>
if IsDependsOn i.Name "EventTarget" then
extendsToPrint <- extendsToPrint |> List.map (fun extends -> if List.contains extends nonEventTargetTypes then extends + "<" + i.Name + ">" else extends)
Pt.Print "%s" typeParameter
if not (List.isEmpty extendsToPrint) then
Pt.Print " extends %s" (String.Join(", ", extendsToPrint))
Pt.Print " {"

/// To decide if a given method is an indexer and should be emited
Expand Down Expand Up @@ -1466,7 +1520,7 @@ module Emit =
// Add missed interface definition from the spec
InputJson.getAddedItems InputJson.Interface flavor |> Array.iter EmitAddedInterface

Pt.Printl "declare type EventListenerOrEventListenerObject = EventListener | EventListenerObject;"
Pt.Printl "declare type EventListenerOrEventListenerObject<T extends EventTarget> = EventListener<T> | EventListenerObject<T>;"
Pt.Printl ""

EmitCallBackFunctions flavor
Expand Down
Loading