diff --git a/JS.fsx b/JS.fsx
deleted file mode 100644
index c72e35899..000000000
--- a/JS.fsx
+++ /dev/null
@@ -1,720 +0,0 @@
-#load "Shared.fsx"
-
-open System
-open System.IO
-open System.Text
-open System.Collections.Generic
-open Shared
-
-// Global Pt.print target
-let Pt = StringPrinter()
-
-// When emit webworker interfaces dom types are ignored
-let mutable ignoreDomType = false
-
-/// Return a stringbuilder
-let LoadTemplate path =
- (new StringBuilder()).Append(File.ReadAllText path)
-
-let DomTypeToPrimitiveJsType domType =
- match domType with
- | "AbortMode" -> "String"
- | "any" -> "Object"
- | "ArrayBuffer" -> "ArrayBuffer"
- | "ArrayBufferView" -> "Uint8Array"
- | "bool" -> "Boolean"
- | "boolean" -> "Boolean"
- | "Boolean" -> "Boolean"
- | "CanvasPixelArray" -> "UInt8ClampedArray"
- | "Date" -> "Date"
- | "DOMHighResTimeStamp" -> "Number"
- | "DOMString" -> "String"
- | "DOMTimeStamp" -> "Number"
- | "double" -> "Number"
- | "EndOfStreamError" -> "Number"
- | "EventHandler" -> "Function"
- | "float" -> "Number"
- | "Float32Array" -> "Float32Array"
- | "Function" -> "Function"
- | "Int32Array" -> "Int32Array"
- | "long long" -> "Number"
- | "long" -> "Number"
- | "object" -> "Object"
- | "ReadyState" -> "String"
- | "short" -> "Number"
- | "signed long" -> "Number"
- | "signed long long" -> "Number"
- | "signed short" -> "Number"
- | "Uint8Array" -> "Uint8Array"
- | "UnrestrictedDouble" -> "Number"
- | "unsigned long" -> "Number"
- | "unsigned long long" -> "Number"
- | "unsigned short" -> "Number"
- | "void" -> "undefined"
- | _ -> ""
- |> (fun x -> if x <> "" then Some x else None)
-
-/// Get javascript type using object dom type
-let DomTypeToJsType objDomType =
- match DomTypeToPrimitiveJsType objDomType with
- | Some jsType -> jsType
- | None ->
- match objDomType with
- // Todo: remove this after the definition of "WindowProxy" has been added to the spec
- | "WindowProxy" -> "Window"
- | domType when domType.Contains("Promise") -> "Promise"
- | arrayType when arrayType.StartsWith("sequence") -> "Array"
- | _ ->
- if ignoreDomType && Seq.contains objDomType ["Element"; "Window"; "Document"] then "Object"
- else
- // Check if it is interface
- match GetInterfaceByName objDomType with
- | Some i -> objDomType
- | None ->
- // Check if it is dictionary
- match allDictionariesMap.TryFind objDomType with
- | Some d -> objDomType
- | None ->
- match allCallbackFuncs.TryFind objDomType with
- | Some cb -> objDomType
- | None->
- // Check if it is enum (namely string)
- match allEnumsMap.TryFind objDomType with
- | Some e -> "String"
- | None -> "Object"
-
-/// Get default values for primitive js types
-let GetJsTypeDefaultValue jsType =
- match jsType with
- | "Number" -> "0"
- | "Boolean" -> "false"
- | "String" -> "''"
- | "Function" -> "function() {}"
- | "Object" -> "{}"
- | "undefined" -> "undefined"
- | "Promise" -> "new Promise(function(resolve, reject) { })"
- // many methods and properties are declared to return Element but in fact return HTMLElement-derived objects.
- | "Element" -> "HTMLElement"
- | "Array" -> "[]"
- | _ -> ""
- |> (fun x -> if x <> "" then Some x else None)
-
-let GetElementTypeForArray (input : string) =
- if DomTypeToJsType input <> "Array" then raise (Exception "Bot an array type!")
- // so the input string starts with "sequence<"
- DomTypeToJsType (input.Substring(9, input.Length - 10))
-
-let GetDefaultValue jsType =
- let (|HasJsDefaultValue|_|) str = GetJsTypeDefaultValue str
- let (|InterfaceName|_|) str = GetInterfaceByName str
- let (|DictionaryName|_|) str = allDictionariesMap.TryFind str
-
- match jsType with
- | HasJsDefaultValue defaultValue -> defaultValue
- | InterfaceName i -> i.Name
- | DictionaryName d -> d.Name
- | other -> "new " + other + "()"
-
-let GetJsDefaultValueForDomType (domType:string) = domType |> DomTypeToJsType |> GetDefaultValue
-
-/// Emit event handlers that associated with an interface
-let EmitEvents (i:Browser.Interface) =
- match iNameToEhList.TryFind i.Name with
- | Some ehList ->
- ehList
- |> List.map (fun e -> "\"" + e.Name + "\"")
- |> (fun x ->
- if x.Length > 0 then
- if i.Name.EndsWith("GlobalScope") then
- x |> List.iter (fun eName -> Pt.printl "%s.%s = function () {};" i.Name (eName.Trim('\"')))
- else
- Pt.printl "_events(%s, %s);" i.Name (String.Join(", ", x))
- else ())
- | None -> ()
-
-let EmitProperties flavor (i:Browser.Interface) =
- let propNameToElmentMap = function
- | "images" -> Some "img"
- | "rows" -> Some "tr"
- | "cells" -> Some "td"
- | "scripts" -> Some "script"
- | "applets" -> Some "applet"
- | "forms" -> Some "form"
- | "embeds" -> Some "embed"
- | "links" | "anchors" -> Some "a"
- | "options" -> Some "option"
- | "tBodies" -> Some "tbody"
- | _ -> None
-
- let EmitProperty (p: Browser.Property) =
- let value = p.Type |> DomTypeToJsType |> GetDefaultValue
- match p with
- | _ when p.Type = "EventHandler" -> ()
- | _ ->
- match p.Name, i.Name with
- | "nodeType", "Node" ->
- Pt.printl "Node.nodeType = 1;"
- | "ownerDocument", _ | "contentDocument", _ ->
- Pt.printl "%s.%s = document;" i.Name p.Name
- | pName, _ when Seq.contains pName ["firstChild";"lastChild";"childNodes";"firstElementChild";"lastElementChild";"nextElementSibling";"previousElementSibling";"parentElement"] ->
- Pt.printl "Object.defineProperty(%s,\"%s\", { get: function () { return _%s(this, %s); } });" i.Name p.Name p.Name value
- | "childElementCount", _ ->
- Pt.printl "Object.defineProperty(%s,\"%s\", { get: function () { return _childElementCount(this); } });" i.Name p.Name
- | "elements", "HTMLFormElement" ->
- Pt.printl "Object.defineProperty(%s,\"%s\", { get: function () { return _formElements(this); } });" i.Name p.Name
- | "options", "HTMLSelectElement" ->
- Pt.printl "Object.defineProperty(%s,\"%s\", { get: function () { return _selectOptions(this); } });" i.Name p.Name
- | "innerHTML", _ ->
- Pt.printl "Object.defineProperty(%s,\"%s\", { get: function () { return ''; }, set: function (v) { _setInnerHTML(this, v); } });" i.Name p.Name
- | pName, _ when (propNameToElmentMap pName).IsSome && p.Type = "HTMLCollection" ->
- Pt.printl "%s.%s = _createHTMLCollection('%s');" i.Name pName (propNameToElmentMap pName).Value
- | pName, iName
- when iName = value ||
- ((allInterfacesMap.ContainsKey p.Type) && IsDependsOn p.Type i.Name) ->
- Pt.printl "%s.%s = _$getTrackingNull(Object.create(%s));" i.Name p.Name value
- | _, _ ->
- Pt.printl "%s.%s = %s;" i.Name p.Name value
-
- match i.Properties with
- | Some propCollection ->
- propCollection.Properties
- |> Array.filter (ShouldKeep flavor)
- |> Array.iter EmitProperty
- | None -> ()
-
-let EmitConstants suffix (i:Browser.Interface) =
- match i.Constants with
- | Some cCollection ->
- for c in cCollection.Constants do
- let cJsType = DomTypeToJsType c.Type
- match cJsType with
- | "String" -> Pt.printl "%s%s.%s = \"%s\";" i.Name suffix c.Name c.Value.Value
- | _ -> Pt.printl "%s%s.%s = %s;" i.Name suffix c.Name c.Value.Value
- | None -> ()
-
-let EmitSignatureCommentDocs (jsFunction:Function) =
- let EmitSignatureDocForSingleParam (p: Param) =
- let pJsType = DomTypeToJsType p.Type
-
- (sprintf "/// "
- |> Pt.printl "%s"
-
- let EmitSignatureDocForSingleOverload (ol: Overload) =
- if not ol.IsEmpty then
- Pt.increaseIndent()
- match ol.ReturnTypes.Length with
- | 0 ->
- Pt.printl "/// "
- ol.ParamCombinations |> List.iter EmitSignatureDocForSingleParam
- Pt.printl "/// "
- | 1 ->
- Pt.printl "/// "
- ol.ParamCombinations |> List.iter EmitSignatureDocForSingleParam
- match ol.ReturnTypes.[0] with
- | "void" | "" -> ()
- | arrayType when arrayType.StartsWith("sequence<") -> Pt.printl "/// " (GetElementTypeForArray arrayType)
- | _ -> Pt.printl "/// " (DomTypeToJsType ol.ReturnTypes.[0])
- Pt.printl "/// "
- | _ ->
- ol.ReturnTypes
- |> List.iter
- (fun r ->
- Pt.printl "/// "
- ol.ParamCombinations |> List.iter EmitSignatureDocForSingleParam
- match r with
- | "void" | "" -> ()
- | arrayType when arrayType.StartsWith("sequence<") -> Pt.printl "/// " (GetElementTypeForArray arrayType)
- | _ -> Pt.printl "/// " (DomTypeToJsType r)
- Pt.printl "/// "
- )
- Pt.decreaseIndent()
- else ()
-
- let overloads = GetOverloads jsFunction true
- if not overloads.IsEmpty then List.iter EmitSignatureDocForSingleOverload overloads
-
-let EmitMethods (i:Browser.Interface) =
- let EmitMethod (m:Browser.Method) =
- // print declaration
- let paramsStr = String.concat ", " [for p in m.Params do yield AdjustParamName p.Name]
- Pt.printl "%s.%s = function(%s) {" i.Name m.Name.Value paramsStr
- // print comment docs
- EmitSignatureCommentDocs (Method m)
- // print body
- match i.Name, m.Name.Value with
- | "EventTarget", "addEventListener" -> Pt.printWithAddedIndent "_eventManager.add(this, type, listener);"
- | _, "insertAdjacentHTML" -> Pt.printWithAddedIndent "_setInnerHTML(this, html);"
- | _, "removeChild" -> Pt.printWithAddedIndent "return _removeChild(this, oldChild);"
- | _, "appendChild" -> Pt.printWithAddedIndent "return _appendChild(this, newChild);"
- | _, "hasChildNodes" -> Pt.printWithAddedIndent "return _hasChildNodes(this);"
- | _, "replaceChild" -> Pt.printWithAddedIndent "return _replaceChild(this, newChild, oldChild);"
- | _, "insertBefore" -> Pt.printWithAddedIndent "return _insertBefore(this, newChild, refChild);"
- | _, "querySelectorAll" -> Pt.printWithAddedIndent "return _querySelectorAll(this, selectors);"
- | _, "querySelector" -> Pt.printWithAddedIndent "return _querySelector(this, selectors);"
- | _, "getAttribute" ->
- Pt.printWithAddedIndent "return _getAttribute(this, name);"
- | _, "setAttribute" ->
- Pt.printWithAddedIndent "_setAttribute(this, name, value);"
- | _, "hasAttribute" ->
- Pt.printWithAddedIndent "return _hasAttribute(this, name);"
- | _, "createEvent" ->
- Pt.printWithAddedIndent "return _createEvent(%s);" m.Params.[0].Name
- | _, "createElement" ->
- Pt.printWithAddedIndent "return _createElementByTagName(%s);" m.Params.[0].Name
- | "Document", "msElementsFromPoint" | "Document", "msElementsFromRect" ->
- Pt.printWithAddedIndent "return _wrapInList([Object.create(HTMLElement)], NodeList);"
- | "Document", "write" | "Document", "writeln" ->
- Pt.printWithAddedIndent "_setInnerHTML(this, content);"
- | _, "getElementsByTagName" ->
- Pt.printWithAddedIndent "return _getElementsByTagName(this, %s);" m.Params.[0].Name
- | _, "replaceNode" ->
- Pt.printWithAddedIndent "return _replaceChild(this, %s, this);" m.Params.[0].Name
- | _, "applyElement" ->
- Pt.printWithAddedIndent "return _applyElement(this, %s, %s);" m.Params.[0].Name m.Params.[1].Name
- | _, "getElementById" ->
- Pt.printWithAddedIndent "return _getElementById(%s);" m.Params.[0].Name
- | "WindowTimersExtension", "setImmediate" | "WindowTimersExtension", "msSetImmediate" ->
- Pt.printWithAddedIndent "return _$setTimeout(expression, null, args);"
- | "WorkerUtils", "setImmediate" ->
- Pt.printWithAddedIndent "return _$setTimeout(handler, 0, args);"
- | _, "clearImmediate" | "WindowTimersExtension", "msClearImmediate" | _, "clearTimeout" ->
- Pt.printWithAddedIndent "_$clearTimeout(%s);" m.Params.[0].Name
- | "WorkerUtils", "importScripts" ->
- Pt.printWithAddedIndent "for (var i = 0; i < arguments.length; i++) _$asyncRequests.add({ src: arguments[i] });"
- | "IDBCursor", "delete" ->
- Pt.printWithAddedIndent "return _createIDBRequest(IDBRequest, this, undefined);"
- | "IDBCursor", "update" ->
- Pt.printWithAddedIndent "return _createIDBRequest(IDBRequest, this, value);"
- | "IDBIndex", "count" ->
- Pt.printWithAddedIndent "return _createIDBRequest(IDBRequest, this, 0);"
- | "IDBIndex", "getKey" ->
- Pt.printWithAddedIndent "return _createIDBRequest(IDBRequest, this.objectStore, {});"
- | "IDBIndex", "openKeyCursor" ->
- Pt.printWithAddedIndent "var cursor = Object.create(IDBCursor); cursor.source = this; return _createIDBRequest(IDBRequest, this.objectStore, cursor);"
- | "IDBIndex", "get" ->
- Pt.printWithAddedIndent "return _createIDBRequest(IDBRequest, this.objectStore, {});"
- | "IDBIndex", "openCursor" ->
- Pt.printWithAddedIndent "var cursor = Object.create(IDBCursorWithValue); cursor.source = this; return _createIDBRequest(IDBRequest, this, cursor);"
- | "IDBFactory", "open" ->
- Pt.printWithAddedIndent "return _createIDBRequest(IDBOpenDBRequest, null, Object.create(IDBDatabase));"
- | "IDBFactory", "deleteDatabase" ->
- Pt.printWithAddedIndent "return _createIDBRequest(IDBOpenDBRequest, null, null);"
- | "IDBObjectStore", "count" ->
- Pt.printWithAddedIndent "return _createIDBRequest(IDBRequest, this, 0);"
- | "IDBObjectStore", "add" ->
- Pt.printWithAddedIndent "return _createIDBRequest(IDBRequest, this, key);"
- | "IDBObjectStore", "clear" ->
- Pt.printWithAddedIndent "return _createIDBRequest(IDBRequest, this, undefined);"
- | "IDBObjectStore", "put" ->
- Pt.printWithAddedIndent "return _createIDBRequest(IDBRequest, this, key);"
- | "IDBObjectStore", "openCursor" ->
- Pt.printWithAddedIndent "var cursor = Object.create(IDBCursorWithValue); cursor.source = this; return _createIDBRequest(IDBRequest, this, cursor);"
- | "IDBObjectStore", "get" ->
- Pt.printWithAddedIndent "return _createIDBRequest(IDBRequest, this, {});"
- | "IDBObjectStore", "delete" ->
- Pt.printWithAddedIndent "return _createIDBRequest(IDBRequest, this, undefined);"
- | _, "setTimeout" | _, "setInterval" ->
- Pt.printWithAddedIndent "return _$setTimeout(handler, timeout, args);"
- | _, "clearInterval" ->
- Pt.printWithAddedIndent "_$clearTimeout(handle);"
- | "XMLHttpRequest", "send" ->
- Pt.printWithAddedIndent "this.status = 200; this.readyState = XMLHttpRequest.DONE; this.status = 4; this.statusText = \"OK\";"
- | "HTMLCanvasElement", "getContext" ->
- Pt.printWithAddedIndent "switch (contextId) { case '2d': return CanvasRenderingContext2D; case 'experimental-webgl': return WebGLRenderingContext; default: return {}; }"
- | _, _ ->
- match m.Type with
- |"void" -> ()
- | _ ->
- if (i.Name.EndsWith("List") || i.Name.EndsWith("Collection")) && (OptionCheckValue "item" m.Name) then
- match DomTypeToPrimitiveJsType m.Type with
- | Some jsType -> Pt.printWithAddedIndent "return this[index] || _$getTrackingNull(%s);" ((GetJsTypeDefaultValue jsType).Value)
- | _ -> Pt.printWithAddedIndent "return this[index] || _$getTrackingNull(Object.create(%s));" (GetJsDefaultValueForDomType m.Type)
- else
- Pt.printWithAddedIndent "return %s;" (GetJsDefaultValueForDomType m.Type)
- // print last line
- Pt.printl "};"
-
- match i.Methods with
- | Some ms -> Seq.iter EmitMethod ms.Methods
- | _ -> ()
-
- // Explicitly expose 'toString' method for 'window'
- // because the method is inherited from js "Object"
- // but it wouldn't show up at the top level if it is
- // not the window's own property
- if i.Name = "Window" then
- Pt.print "
- Window.toString = function() {
- ///
- ///
- ///
- return '';
- };"
-
-let EmitInterfaceInit (i:Browser.Interface) =
- let nodeType, nodeName =
- match i.Name with
- | "Text" -> "TEXT_NODE", "#text"
- | "Comment" -> "COMMENT_NODE", "#comment"
- | "CDATASection" -> "CDATA_SECTION_NODE", "#cdata-section"
- | "ProcessingInstruction" -> "PROCESSING_INSTRUCTION_NODE", ""
- | "DocumentFragment" -> "DOCUMENT_FRAGMENT_NODE", "#document-fragment"
- | "DocumentType" -> "DOCUMENT_TYPE_NODE", "html"
- | _ -> "", ""
- match nodeType, nodeName with
- | "", "" ->
- if i.Elements.Length > 0 then
- let firstElem = i.Elements.[0].Name
- Pt.printl "%s.nodeName = %s.tagName = '%s';" i.Name i.Name (firstElem.ToUpper())
- Pt.printl "%s.localName = '%s';" i.Name (firstElem.ToLower())
- | _, "" ->
- Pt.printl "%s.nodeType = Node.%s;" i.Name nodeType
- | _, _ ->
- Pt.printl "%s.nodeType = Node.%s;" i.Name nodeType
- Pt.printl "%s.nodeName = '%s';" i.Name nodeName
-/// Sort interfaces to make base interfaces locate before inherited ones
-let SortInterfaces (iAray:Browser.Interface []) =
- let tSet = HashSet (iAray)
-
- let IsIndependentFromAny (ts:seq) (t:Browser.Interface) =
- not (Seq.exists (fun (element:Browser.Interface) -> IsDependsOn t.Name element.Name) ts)
-
- let findIndependentInterfaces tArray =
- tArray |> Seq.filter (IsIndependentFromAny tArray)
-
- let resArray = ResizeArray()
-
- while not (tSet.Count = 0) do
- let independentTypes = findIndependentInterfaces tSet
- if Seq.isEmpty independentTypes then
- raise (Exception "Cyclic dependencies between types detected!")
- else
- let indeArray = Array.ofSeq independentTypes
- resArray.AddRange indeArray
- tSet.ExceptWith indeArray
- resArray.ToArray()
-
-let SortDicts (ds: Browser.Dictionary []) =
- let dSet = HashSet (ds)
-
- let IsIndependentFromAny (ts:seq) (t:Browser.Dictionary) =
- not (Seq.exists (fun (element:Browser.Dictionary) -> IsDependsOn t.Name element.Name) ts)
-
- let findIndependentInterfaces tArray =
- tArray |> Seq.filter (IsIndependentFromAny tArray)
-
- let resArray = ResizeArray()
-
- while not (dSet.Count = 0) do
- let independentTypes = findIndependentInterfaces dSet
- if Seq.isEmpty independentTypes then
- raise (Exception "Cyclic dependencies between types detected!")
- else
- let indeArray = Array.ofSeq independentTypes
- resArray.AddRange indeArray
- dSet.ExceptWith indeArray
- resArray.ToArray()
-
-let RegisterPublicInterfaces flavor =
- // The order of the publicInterface registration need to be reverse of the dependency relationship
- // e.g. base interfaces show up later than inherited interfaces
- let sortedIs = GetPublicInterfacesByFlavor flavor |> SortInterfaces |> Array.rev
- for i in sortedIs do
- // Static interfaces are objects
- match i.Static.IsSome with
- | true ->
- Pt.printl "_publicObject('%s', %s);" i.Name i.Name
- | false ->
- if i.Constructor.IsNone &&
- i.NoInterfaceObject.IsNone then
- Pt.printl "_publicInterface('%s', {" i.Name
-
- // Emit constants
- let cEmit =
- match i.Constants with
- | Some (cs) ->
- [for c in cs.Constants do
- yield "'" + c.Name + "' : " + c.Value.String.Value]
- | _ -> []
-
- // Emit static methods
- let mEmit =
- match i.Methods with
- | Some (ms) ->
- [for m in ms.Methods do
- if m.Static.IsSome then
- yield String.Format("'{0}' : {1}.{0}", m.Name.Value, i.Name)]
- | _ -> []
-
- let combined = String.concat "," (List.append cEmit mEmit)
- Pt.print "%s" (combined.Trim(','))
- Pt.print "}, %s);" i.Name
-
-let RegisterConstructors flavor =
- let sortedCtors = GetAllInterfacesByFlavor flavor |> SortInterfaces |> Array.rev
- for i in sortedCtors do
- match i.Constructor with
- | Some _ -> Pt.printl "_publicInterface('%s', %sCtor , %s);" i.Name i.Name i.Name
- | _ -> ()
-
-let EmitConstructor (i: Browser.Interface) =
- match i.Constructor with
- | Some _ -> EmitConstants "Ctor" i
- | None -> ()
-
-let EmitInterface flavor (i:Browser.Interface) =
- Pt.printl ""
- Pt.printl "/* -- type: %s -- */" i.Name
- Pt.printl ""
-
- // Emit impletented interfaces
- i.Implements |> Array.iter (fun im -> Pt.printl "_$implement(%s, %s);" i.Name im)
- if i.Name = GetGlobalPollutorName flavor then
- // if the interface is the global pollutor, inherits becomes implements
- Pt.printl "_$implement(%s, %s);" i.Name i.Extends
-
- // Emit other contents
- EmitConstructor i
- EmitProperties flavor i
- EmitConstants "" i
- EmitMethods i
- EmitInterfaceInit i
- EmitEvents i
-
- // Deal with array types
- if i.Name.EndsWith("List") || i.Name.EndsWith("Collection") then
- match i.Methods with
- | Some ms ->
- let item = Array.tryFind (fun (m:Browser.Method) -> m.Name.Value = "item") ms.Methods
- match item with
- | Some item ->
- Pt.printl "/* Add a single array element */"
- match DomTypeToPrimitiveJsType item.Type with
- | Some jsType -> Pt.printl "%s[0] = _$getTrackingNull(%s);" i.Name ((GetJsTypeDefaultValue jsType).Value)
- | None -> Pt.printl "%s[0] = _$getTrackingNull(Object.create(%s));" i.Name (GetJsDefaultValueForDomType item.Type)
- | None -> ()
- | None -> ()
-
-let EmitCallBackFunctions flavor =
- let EmitCallBackFunction (cb: Browser.CallbackFunction) =
- let paramsStr = cb.Params |> Array.map (fun p -> p.Name) |> String.concat ", "
- Pt.printl "var %s = function(%s) {" cb.Name paramsStr
- EmitSignatureCommentDocs (CallBackFun cb)
- if cb.Type <> "void" then Pt.printWithAddedIndent "return %s;" (DomTypeToJsType cb.Type)
- Pt.printl "};"
- GetCallbackFuncsByFlavor flavor
- |> Array.iter EmitCallBackFunction
-
-let RegisterCallBackFunctions flavor =
- let RegisterCallBackFunction (cb: Browser.CallbackFunction) =
- Pt.printl "_publicInterface('%s', {}, %s);" cb.Name cb.Name
- browser.CallbackFunctions
- |> Array.filter (ShouldKeep flavor)
- |> Array.iter RegisterCallBackFunction
-
-let RegisterDictionaries () =
- let RegisterDictionary (d: Browser.Dictionary) =
- Pt.printl "_publicInterface('%s', {}, %s);" d.Name d.Name
-
- browser.Dictionaries
- |> Array.iter RegisterDictionary
-
-let EmitDictionaries () =
- let EmitDictionary (d:Browser.Dictionary) =
- Pt.printl ""
- Pt.printl "/* -- type: %s -- */" d.Name
- Pt.printl ""
-
- // Emit members
- for m in d.Members do
- let defaultValue = match m.Default.String with
- | Some dv -> dv
- | None -> GetJsDefaultValueForDomType m.Type
- Pt.printl "%s.%s = %s;" d.Name m.Name defaultValue
-
- browser.Dictionaries |> Array.iter EmitDictionary
-
-let EmitInterfaces flavor =
- let sortedTypes = SortInterfaces (GetAllInterfacesByFlavor flavor)
- for t in sortedTypes do EmitInterface flavor t
-
-let EmitEventTypeToObjSwitchStatement flavor ignoreCase =
- Pt.printl "switch (type) {"
- Pt.increaseIndent()
-
- match flavor with
- | Worker ->
- for KeyValue(eName, eType) in workerEventsMap do
- Pt.printl "case '%s': return %s;" eName eType
- | _ ->
- // Note:
- // in the XML file, the event handler name and the event name it handles
- // doesn't just differ by a "on" prefix. for example,
- //
- // this event handler handles event "SVGZoom". But, we need to provide intellisense
- // for both "SVGZoom" and "zoom" event in the VS intellisense. Therefore
- // both of them should be in the switch case statement.
- // The "SVGZoom" event is included in the global eNameToEType map;
- for KeyValue(eName, eType) in eNameToEType do
- let eNameCaseSensitive = if ignoreCase then eName.ToLower() else eName
- Pt.printl "case '%s': return %s;" eNameCaseSensitive eType
-
- // while the fake "zoom" event can only be generated on the fly.
- for KeyValue(ehName, eType) in ehNameToEType do
- let ehNameTrimOn = if ignoreCase then (ehName.TrimStartString "on").ToLower() else ehName.TrimStartString "on"
- if not (eNameToETypeWithoutCase.ContainsKey(ehNameTrimOn.ToLower())) then
- Pt.printl "case '%s': return %s;" ehNameTrimOn eType
-
- Pt.decreaseIndent()
- Pt.printl "}"
-
-let EmitGetElementByTagNameSwitchStatement () =
- Pt.printl "switch (tagName.toLowerCase()) {"
-
- Pt.increaseIndent()
- for KeyValue(tagName, eleName) in tagNameToEleName do
- Pt.printl "case '%s': return %s;" tagName eleName
- Pt.printl "default: return HTMLElement;"
- Pt.decreaseIndent()
-
- Pt.print "}"
-
-/// Emit the _createEvent function
-let EmitCreateEventSwitchStatement () =
- // Emit the switch statements
- Pt.printl "switch(eventType.toLowerCase()) {"
-
- distinctETypeList
- |> List.iter
- (fun e ->
- Pt.printWithAddedIndent "case '%s': return %s;" (e.ToLower()) e
- Pt.printWithAddedIndent "case '%ss': return %s;" (e.ToLower()) e)
-
- allWebNonCallbackInterfaces
- |> Array.filter (fun (i:Browser.Interface) ->
- i.Name.EndsWith("Event") &&
- not (Seq.contains i.Name distinctETypeList))
- |> Array.iter
- (fun i ->
- Pt.printWithAddedIndent "case '%s': return %s;" (i.Name.ToLower()) i.Name
- Pt.printWithAddedIndent "case '%ss': return %s;" (i.Name.ToLower()) i.Name)
-
- Pt.printl "}"
-
-let EmitDeclarations flavor =
- let EmitInterfaceDeclaration (i:Browser.Interface) =
- let init =
- match i.Name with
- | name when name = GetGlobalPollutorName flavor -> "this"
- | _ when i.Extends = "Object" -> "{}"
- | _ -> "_$inherit(" + i.Extends + ")"
-
- Pt.printl "var %s = %s;" i.Name init
-
- match i.Constructor with
- | Some ctor ->
- let functionDeclare =
- match ctor.Params with
- | [||] -> "function()"
- | _ ->
- let pList = ctor.Params |> Array.map (fun p -> p.Name) |> String.concat ", "
- "function(" + pList + ")"
- Pt.printl "var %sCtor = %s { " i.Name functionDeclare
- if ctor.Params.Length > 0 then
- EmitSignatureCommentDocs (Ctor ctor)
- Pt.printWithAddedIndent "return Object.create(%s);" i.Name
- Pt.printl "};"
- else
- Pt.print "return Object.create(%s); };" i.Name
- | None -> ()
-
-
- GetAllInterfacesByFlavor flavor
- |> SortInterfaces
- |> Array.iter EmitInterfaceDeclaration
-
- if flavor <> Worker then
- let EmitDictDeclaration (d: Browser.Dictionary) =
- match d.Extends with
- | "Object" -> Pt.printl "var %s = {};" d.Name
- | _ -> Pt.printl "var %s = _$inherit(%s);" d.Name d.Extends
- browser.Dictionaries
- |> SortDicts
- |> Array.iter EmitDictDeclaration
-
-let EmitXmlContent flavor =
- EmitDeclarations flavor
- EmitCallBackFunctions flavor
- EmitInterfaces flavor
- if flavor <> Worker then
- EmitDictionaries ()
-
-
-let RegisterPublicObjs flavor =
- RegisterPublicInterfaces flavor
- RegisterConstructors flavor
-
-/// Adjust the indention of the printer, and emit the indented content in the printer,
-/// and then replace the place holder text with the content in printer
-let ReplaceWithIndentedFuncResult (placeHolder: String) func (sb: StringBuilder) =
- let curText = sb.ToString()
- let phStartPos = curText.IndexOf(placeHolder)
- let lineStartPos = curText.LastIndexOf('\n', phStartPos)
- Pt.setIndent ((phStartPos - lineStartPos) / 4)
- Pt.clear()
- func() |> ignore
- sb.Replace(placeHolder, Pt.getResult())
-
-let EmitTheWholeThing flavor (target: TextWriter) =
- Pt.reset()
-
- let template = LoadTemplate ( __SOURCE_DIRECTORY__ + @"\inputfiles\jsTemplate.js")
-
- let content =
- template
- |> ReplaceWithIndentedFuncResult "<@ EventTypeToObjSwitchStatements @>"
- (fun () -> EmitEventTypeToObjSwitchStatement flavor false)
- |> ReplaceWithIndentedFuncResult "<@ EventTypeToObjSwitchStatementsIgnoreCase @>"
- (fun () -> EmitEventTypeToObjSwitchStatement flavor true)
- |> ReplaceWithIndentedFuncResult "<@ CreateEventSwitchStatements @>"
- EmitCreateEventSwitchStatement
- |> ReplaceWithIndentedFuncResult "<@ GetElementsByTagNameSwitchStatements @>"
- EmitGetElementByTagNameSwitchStatement
- |> ReplaceWithIndentedFuncResult "<@ XMLContents @>"
- (fun () -> EmitXmlContent flavor)
- |> ReplaceWithIndentedFuncResult "<@ Public Interfaces @>"
- (fun () -> RegisterPublicObjs flavor)
- |> (fun sb -> sb.Replace("<@ GlobalPolluter @>", GetGlobalPollutorName flavor))
- |> (fun sb -> sb.ToString())
-
- fprintf target "%s" content
- target.Flush()
- target.Close()
-
-let EmitDomWeb () =
- EmitTheWholeThing Flavor.Web GlobalVars.jsWebOutput
-
-let EmitDomWin () =
- EmitTheWholeThing Flavor.All GlobalVars.jsWinOutput
-
-let EmitDomWorker () =
- Pt.reset()
-
- ignoreDomType <- true
- let template = LoadTemplate ( __SOURCE_DIRECTORY__ + @"\inputfiles\jsTemplate_worker.js")
-
- let content =
- template
- |> ReplaceWithIndentedFuncResult "<@ EventTypeToObjSwitchStatements @>"
- (fun () -> EmitEventTypeToObjSwitchStatement Worker false)
- |> ReplaceWithIndentedFuncResult "<@ XMLContents @>"
- (fun () -> EmitXmlContent Worker)
- |> ReplaceWithIndentedFuncResult "<@ Public Interfaces @>"
- (fun () -> RegisterPublicObjs Worker)
- |> (fun sb -> sb.Replace("<@ GlobalPolluter @>", GetGlobalPollutorName Worker))
- |> (fun sb -> sb.ToString())
-
- fprintf GlobalVars.jsWorkerOutput "%s" content
- GlobalVars.jsWorkerOutput.Flush()
\ No newline at end of file
diff --git a/Shared.fsx b/Shared.fsx
deleted file mode 100644
index 06603dc0d..000000000
--- a/Shared.fsx
+++ /dev/null
@@ -1,673 +0,0 @@
-#r "packages/FSharp.Data/lib/net40/FSharp.Data.dll"
-#r "System.Xml.Linq.dll"
-
-open FSharp.Data
-open System.IO
-open System
-open System.Text
-open System.Collections.Generic
-open Microsoft.FSharp.Reflection
-
-/// ===========================================
-/// Global variables
-/// ===========================================
-module GlobalVars =
- if not (Directory.Exists(__SOURCE_DIRECTORY__ + @"/generated")) then
- Directory.CreateDirectory(__SOURCE_DIRECTORY__ + @"/generated") |> ignore
-
- let inputFolder = __SOURCE_DIRECTORY__ + @"/inputfiles"
- let makeTextWriter fileName = File.CreateText(__SOURCE_DIRECTORY__ + @"/generated/" + fileName) :> TextWriter
- // let jsWebOutput = makeTextWriter "domWeb.js"
- // let jsWinOutput = makeTextWriter "domWindows.js"
- // let jsWorkerOutput = makeTextWriter "dedicatedworker.js"
- let tsWebOutput = makeTextWriter "dom.generated.d.ts"
- let tsWorkerOutput = makeTextWriter "webworker.generated.d.ts"
- let defaultEventType = "Event"
-
-/// ===========================================
-/// Types
-/// ===========================================
-
-/// Quick checker for option type values
-let OptionCheckValue value = function
- | Some v when v = value -> true
- | _ -> false
-
-let unionToString (x: 'a) =
- match FSharpValue.GetUnionFields(x, typeof<'a>) with
- | case, _ -> case.Name
-
-type Flavor =
- | Worker
- | Web
- | All
- override x.ToString() = unionToString x
-
-type Browser = XmlProvider<"sample.xml", Global=true>
-
-module JsonItems =
- type ItemsType = JsonProvider<"inputfiles/sample.json">
-
- let overriddenItems =
- File.ReadAllText(GlobalVars.inputFolder + @"/overridingTypes.json") |> ItemsType.Parse
-
- let removedItems =
- File.ReadAllText(GlobalVars.inputFolder + @"/removedTypes.json") |> ItemsType.Parse
-
- let addedItems =
- File.ReadAllText(GlobalVars.inputFolder + @"/addedTypes.json") |> ItemsType.Parse
-
- // This is the kind of items in the external json files that are used as a
- // correction for the spec.
- type ItemKind =
- | Property
- | Method
- | Constant
- | Constructor
- | Interface
- | Callback
- | Indexer
- | SignatureOverload
- | TypeDef
- | Extends
- override x.ToString() =
- match x with
- | Property _ -> "property"
- | Method _ -> "method"
- | Constant _ -> "constant"
- | Constructor _ -> "constructor"
- | Interface _ -> "interface"
- | Callback _ -> "callback"
- | Indexer _ -> "indexer"
- | SignatureOverload _ -> "signatureoverload"
- | TypeDef _ -> "typedef"
- | Extends _ -> "extends"
-
- let findItem (allItems: ItemsType.Root []) (itemName: string) (kind: ItemKind) otherFilter =
- let filter (item: ItemsType.Root) =
- OptionCheckValue itemName item.Name &&
- item.Kind.ToLower() = kind.ToString() &&
- otherFilter item
- allItems |> Array.tryFind filter
-
- let matchInterface iName (item: ItemsType.Root) =
- item.Interface.IsNone || item.Interface.Value = iName
-
- let findOverriddenItem itemName (kind: ItemKind) iName =
- findItem overriddenItems itemName kind (matchInterface iName)
-
- let findRemovedItem itemName (kind: ItemKind) iName =
- findItem removedItems itemName kind (matchInterface iName)
-
- let findAddedItem itemName (kind: ItemKind) iName =
- findItem addedItems itemName kind (matchInterface iName)
-
- let getItems (allItems: ItemsType.Root []) (kind: ItemKind) (flavor: Flavor) =
- allItems
- |> Array.filter (fun t ->
- t.Kind.ToLower() = kind.ToString() &&
- (t.Flavor.IsNone || t.Flavor.Value = flavor.ToString() || flavor = All))
-
- let getOverriddenItems = getItems overriddenItems
- let getAddedItems = getItems addedItems
- let getRemovedItems = getItems removedItems
-
- let getAddedItemsByInterfaceName kind flavor iName =
- getAddedItems kind flavor |> Array.filter (matchInterface iName)
- let getOverriddenItemsByInterfaceName kind flavor iName =
- getOverriddenItems kind flavor |> Array.filter (matchInterface iName)
- let getRemovedItemsByInterfaceName kind flavor iName =
- getRemovedItems kind flavor |> Array.filter (matchInterface iName)
-
-module Comments =
- type CommentType = JsonProvider<"inputfiles/comments.json">
-
- let comments = File.ReadAllText(__SOURCE_DIRECTORY__ + @"/inputfiles/comments.json") |> CommentType.Parse
-
- let GetCommentForProperty iName pName =
- match comments.Interfaces |> Array.tryFind (fun i -> i.Name = iName) with
- | Some i ->
- match i.Members.Property |> Array.tryFind (fun p -> p.Name = pName) with
- | Some p -> Some p.Comment
- | _ -> None
- | _ -> None
-
- let GetCommentForMethod iName mName =
- match comments.Interfaces |> Array.tryFind (fun i -> i.Name = iName) with
- | Some i ->
- match i.Members.Method |> Array.tryFind (fun m -> m.Name = mName) with
- | Some m -> Some m.Comment
- | _ -> None
- | _ -> None
-
-// Printer for print to file
-type Printer(target : TextWriter) =
- let output = StringBuilder()
- let mutable curTabCount = 0
- member this.getCurIndent() = String.replicate curTabCount " "
- member this.target = target
- member this.print content = Printf.kprintf (fun s -> output.Append s |> ignore) content
- member this.printl content =
- Printf.kprintf (fun s -> output.Append("\r\n" + this.getCurIndent() + s) |> ignore) content
- member this.increaseIndent() = curTabCount <- curTabCount + 1
- member this.decreaseIndent() = curTabCount <- Math.Max(curTabCount - 1, 0)
-
- member this.startBrace() =
- this.printl "{"
- this.increaseIndent()
-
- member this.endBrace() =
- this.decreaseIndent()
- this.printl "}"
-
- member this.resetIndent() = curTabCount <- 0
- member this.printWithAddedIndent content =
- Printf.kprintf (fun s -> output.Append("\r\n" + this.getCurIndent() + " " + s) |> ignore) content
-
- member this.emit() =
- fprintf this.target "%s" (output.ToString())
- this.target.Flush()
-
- member this.close() = this.target.Close()
-
-// Printer for print to string
-type StringPrinter() =
- let output = StringBuilder()
- let mutable curTabCount = 0
- member this.getCurIndent() = String.replicate curTabCount " "
- member this.print content = Printf.kprintf (fun s -> output.Append s |> ignore) content
- member this.printl content =
- Printf.kprintf (fun s -> output.Append("\r\n" + this.getCurIndent() + s) |> ignore) content
- member this.increaseIndent() = curTabCount <- curTabCount + 1
- member this.setIndent indentNum = curTabCount <- indentNum
- member this.decreaseIndent() = curTabCount <- Math.Max(curTabCount - 1, 0)
- member this.resetIndent() = curTabCount <- 0
- member this.printWithAddedIndent content =
- Printf.kprintf (fun s -> output.Append("\r\n" + this.getCurIndent() + " " + s) |> ignore) content
- member this.getResult() = output.ToString()
- member this.clear() = output.Clear() |> ignore
- member this.reset() =
- this.clear()
- this.resetIndent()
-
-type Event =
- { Name : string
- Type : string }
-
-/// Method parameter
-type Param =
- { Type : string
- Name : string
- Optional : bool
- Variadic : bool
- Nullable : bool }
-
-/// Function overload
-type Overload =
- { ParamCombinations : Param list
- ReturnTypes : string list
- Nullable : Boolean }
- member this.IsEmpty = this.ParamCombinations.IsEmpty && (this.ReturnTypes = [ "void" ] || this.ReturnTypes = [ "" ])
-
-type Function =
- | Method of Browser.Method
- | Ctor of Browser.Constructor
- | CallBackFun of Browser.CallbackFunction
-
-// Note:
-// Eventhandler's name and the eventName are not just off by "on".
-// For example, handlers named "onabort" may handle "SVGAbort" event in the XML file
-type EventHandler =
- { Name : string
- EventName : string
- EventType : string }
-
-/// Decide which members of a function to emit
-type EmitScope =
- | StaticOnly
- | InstanceOnly
- | All
-
-// Used to decide if a member should be emitted given its static property and
-// the intended scope level.
-let inline matchScope scope (x: ^a when ^a: (member Static: Option<'b>)) =
- if scope = EmitScope.All then true
- else
- let isStatic = (^a: (member Static: Option<'b>)x)
- if isStatic.IsSome then scope = EmitScope.StaticOnly
- else scope = EmitScope.InstanceOnly
-
-let matchInterface iName (x: JsonItems.ItemsType.Root) =
- x.Interface.IsNone || x.Interface.Value = iName
-
-/// ===========================================
-/// Shared data and helper functions
-/// ===========================================
-/// Add the 'Seq.contains' method to the Seq module
-module Seq =
- let contains e s = Seq.exists ((=) e) s
-
-type String with
- member this.TrimStartString str =
- if this.StartsWith(str) then this.Substring(str.Length)
- else this
-
-/// Parameter cannot be named "default" in JavaScript/Typescript so we need to rename it.
-let AdjustParamName name =
- match name with
- | "default" -> "_default"
- | "delete" -> "_delete"
- | "continue" -> "_continue"
- | _ -> name
-
-/// Parse the xml input file
-let browser =
- (new StreamReader(Path.Combine(GlobalVars.inputFolder, "browser.webidl.xml"))).ReadToEnd() |> Browser.Parse
-
-let worker =
- (new StreamReader(Path.Combine(GlobalVars.inputFolder, "webworkers.specidl.xml"))).ReadToEnd() |> Browser.Parse
-
-/// Check if the given element should be disabled or not
-/// (Member constraint aka duck typing)
-/// reason is that ^a can be an interface, property or method, but they
-/// all share a 'tag' property
-let inline ShouldKeep flavor (i : ^a when ^a : (member Tags : string option)) =
- let filterByTag =
- match ((((((^a : (member Tags : string option) i)))))) with
- | Some tags ->
- // Check if should be included
- match flavor with
- | Flavor.Web ->
- [ "MSAppOnly"; "WinPhoneOnly" ]
- |> Seq.exists (fun t -> tags.Contains t)
- |> not
- | Flavor.All -> true
- | Flavor.Worker ->
- [ "IEOnly" ]
- |> Seq.exists (fun t -> tags.Contains t)
- |> not
- | _ -> true
- filterByTag
-
-// Global interfacename to interface object map
-let allWebNonCallbackInterfaces = Array.concat [| browser.Interfaces; browser.MixinInterfaces.Interfaces |]
-
-let allWebInterfaces =
- Array.concat [| browser.Interfaces; [| browser.CallbackInterfaces.Interface |]; browser.MixinInterfaces.Interfaces |]
-
-let allWorkerAdditionalInterfaces = Array.concat [| worker.Interfaces; worker.MixinInterfaces.Interfaces |]
-let allInterfaces = Array.concat [| allWebInterfaces; allWorkerAdditionalInterfaces |]
-
-let allInterfacesMap =
- [ for i in allInterfaces do
- yield (i.Name, i) ]
- |> Map.ofList
-
-let allDictionariesMap =
- Array.concat [| browser.Dictionaries; worker.Dictionaries |]
- |> Array.map (fun d -> (d.Name, d))
- |> Map.ofArray
-
-let allEnumsMap =
- Array.concat [| browser.Enums; worker.Enums |]
- |> Array.map (fun e -> (e.Name, e))
- |> Map.ofArray
-
-let allCallbackFuncs =
- Array.concat [| browser.CallbackFunctions; worker.CallbackFunctions |]
- |> Array.map (fun c -> (c.Name, c))
- |> Map.ofArray
-
-let GetInterfaceByName = allInterfacesMap.TryFind
-let knownWorkerInterfaces =
- [ "Algorithm"; "AlgorithmIdentifier"; "KeyAlgorithm"; "CryptoKey"; "AbstractWorker"; "AudioBuffer"; "Blob";
- "CloseEvent"; "Console"; "Coordinates"; "DecodeSuccessCallback";
- "DecodeErrorCallback"; "DOMError"; "DOMException"; "DOMStringList"; "ErrorEvent"; "Event"; "ErrorEventHandler";
- "EventException"; "EventInit"; "EventListener"; "EventTarget"; "File"; "FileList"; "FileReader";
- "FunctionStringCallback"; "IDBCursor"; "IDBCursorWithValue"; "IDBDatabase"; "IDBFactory"; "IDBIndex";
- "IDBKeyRange"; "IDBObjectStore"; "IDBOpenDBRequest"; "IDBRequest"; "IDBTransaction"; "IDBVersionChangeEvent";
- "ImageData"; "MediaQueryList"; "MediaQueryListListener"; "MessageChannel"; "MessageEvent"; "MessagePort"; "MSApp";
- "MSAppAsyncOperation"; "MSAppView"; "MSBaseReader"; "MSBlobBuilder"; "MSExecAtPriorityFunctionCallback";
- "MSLaunchUriCallback"; "MSStream"; "MSStreamReader"; "MSUnsafeFunctionCallback"; "NavigatorID"; "NavigatorOnLine";
- "Position"; "PositionCallback"; "PositionError"; "PositionErrorCallback"; "ProgressEvent"; "WebSocket";
- "WindowBase64"; "WindowConsole"; "Worker"; "XMLHttpRequest"; "XMLHttpRequestEventTarget"; "XMLHttpRequestUpload";
- "IDBObjectStoreParameters"; "IDBIndexParameters"; "IDBKeyPath"]
- |> set
-
-let GetAllInterfacesByFlavor flavor =
- match flavor with
- | Flavor.Web -> allWebInterfaces |> Array.filter (ShouldKeep Web)
- | Flavor.All -> allWebInterfaces |> Array.filter (ShouldKeep Flavor.All)
- | Flavor.Worker ->
- let isFromBrowserXml = allWebInterfaces |> Array.filter (fun i -> knownWorkerInterfaces.Contains i.Name)
- Array.append isFromBrowserXml allWorkerAdditionalInterfaces
-
-let GetNonCallbackInterfacesByFlavor flavor =
- match flavor with
- | Flavor.Web -> allWebNonCallbackInterfaces |> Array.filter (ShouldKeep Flavor.Web)
- | Flavor.All -> allWebNonCallbackInterfaces |> Array.filter (ShouldKeep Flavor.All)
- | Flavor.Worker ->
- let isFromBrowserXml =
- allWebNonCallbackInterfaces |> Array.filter (fun i -> knownWorkerInterfaces.Contains i.Name)
- Array.append isFromBrowserXml allWorkerAdditionalInterfaces
-
-let GetPublicInterfacesByFlavor flavor =
- match flavor with
- | Flavor.Web | Flavor.All -> browser.Interfaces |> Array.filter (ShouldKeep flavor)
- | Flavor.Worker ->
- let isFromBrowserXml = browser.Interfaces |> Array.filter (fun i -> knownWorkerInterfaces.Contains i.Name)
- Array.append isFromBrowserXml worker.Interfaces
-
-let GetCallbackFuncsByFlavor flavor =
- browser.CallbackFunctions
- |> Array.filter (ShouldKeep flavor)
- |> Array.filter (fun cb -> flavor <> Flavor.Worker || knownWorkerInterfaces.Contains cb.Name)
-
-/// Event name to event type map
-let eNameToEType =
- [ for i in allWebNonCallbackInterfaces do
- if i.Events.IsSome then yield! i.Events.Value.Events ]
- |> List.map (fun (e : Browser.Event) ->
- let eType =
- match e.Name with
- | "abort" -> "UIEvent"
- | "complete" -> "Event"
- | "error" -> "ErrorEvent"
- | "load" -> "Event"
- | "loadstart" -> "Event"
- | "progress" -> "ProgressEvent"
- | "readystatechange" -> "ProgressEvent"
- | "resize" -> "UIEvent"
- | "timeout" -> "ProgressEvent"
- | _ -> e.Type
- (e.Name, eType))
- |> Map.ofList
-
-let eNameToETypeWithoutCase =
- eNameToEType
- |> Map.toList
- |> List.map (fun (k, v) -> (k.ToLower(), v))
- |> Map.ofList
-
-let getEventTypeInInterface eName iName =
- match iName, eName with
- | "IDBDatabase", "abort"
- | "IDBTransaction", "abort"
- | "MSBaseReader", "abort"
- | "XMLHttpRequestEventTarget", "abort"
- -> "Event"
- | "XMLHttpRequest", "readystatechange"
- -> "Event"
- | "XMLHttpRequest", _
- -> "ProgressEvent"
- | _ ->
- match eNameToEType.TryFind eName with
- | Some eType' -> eType'
- | _ -> "Event"
-
-/// Tag name to element name map
-let tagNameToEleName =
- let preferedElementMap =
- function
- | "script" -> "HTMLScriptElement"
- | "a" -> "HTMLAnchorElement"
- | "title" -> "HTMLTitleElement"
- | "style" -> "HTMLStyleElement"
- | _ -> ""
-
- let resolveElementConflict tagName (iNames : seq) =
- match preferedElementMap tagName with
- | name when Seq.contains name iNames -> name
- | _ -> raise (Exception("Element conflict occured! Typename: " + tagName))
-
- [ for i in GetNonCallbackInterfacesByFlavor Flavor.All do
- yield! [ for e in i.Elements do
- yield (e.Name, i.Name) ] ]
- |> Seq.groupBy fst
- |> Seq.map (fun (key, group) -> (key, Seq.map snd group))
- |> Seq.map (fun (key, group) ->
- key,
- match Seq.length group with
- | 1 -> Seq.head group
- | _ -> resolveElementConflict key group)
- |> Map.ofSeq
-
-/// Interface name to all its implemented / inherited interfaces name list map
-/// e.g. If i1 depends on i2, i2 should be in dependencyMap.[i1.Name]
-let iNameToIDependList =
- let rec GetExtendList(iName : string) =
- match GetInterfaceByName iName with
- | Some i ->
- match i.Extends with
- | "Object" -> []
- | super -> super :: (GetExtendList super)
- | _ -> []
-
- let GetImplementList(iName : string) =
- match GetInterfaceByName iName with
- | Some i -> List.ofArray i.Implements
- | _ -> []
-
- Array.concat [| allWebNonCallbackInterfaces; worker.Interfaces; worker.MixinInterfaces.Interfaces |]
- |> Array.map (fun i ->
- (i.Name,
- List.concat [ (GetExtendList i.Name)
- (GetImplementList i.Name) ]))
- |> Map.ofArray
-
-/// Distinct event type list, used in the "createEvent" function
-let distinctETypeList =
- let usedEvents =
- [ for i in GetNonCallbackInterfacesByFlavor Flavor.All do
- match i.Events with
- | Some es -> yield! es.Events
- | _ -> () ]
- |> List.map (fun e -> e.Type)
- |> List.distinct
-
- let unUsedEvents =
- GetNonCallbackInterfacesByFlavor Flavor.All
- |> Array.filter (fun i -> i.Extends = "Event")
- |> Array.map (fun i -> i.Name)
- |> Array.filter (fun n -> n.EndsWith("Event") && not (List.contains n usedEvents))
- |> Array.distinct
- |> List.ofArray
-
- List.concat [ usedEvents; unUsedEvents ] |> List.sort
-
-/// Determine if interface1 depends on interface2
-let IsDependsOn i1Name i2Name =
- match (iNameToIDependList.ContainsKey i2Name) && (iNameToIDependList.ContainsKey i1Name) with
- | true -> Seq.contains i2Name iNameToIDependList.[i1Name]
- | false -> i2Name = "Object"
-
-/// Interface name to its related eventhandler name list map
-/// Note:
-/// In the xml file, each event handler has
-/// 1. eventhanlder name: "onready", "onabort" etc.
-/// 2. the event name that it handles: "ready", "SVGAbort" etc.
-/// And they don't NOT just differ by an "on" prefix!
-let iNameToEhList =
- let GetEventTypeFromHandler (p : Browser.Property) (i : Browser.Interface) =
- let eType =
- // Check the "event-handler" attribute of the event handler property,
- // which is the corresponding event name
- match p.EventHandler with
- | Some eName ->
- // The list is partly obtained from the table at
- // http://www.w3.org/TR/DOM-Level-3-Events/#dom-events-conformance #4.1
- match eNameToEType.TryFind eName with
- | Some v -> v
- | _ -> GlobalVars.defaultEventType
- | _ -> GlobalVars.defaultEventType
- match eType with
- | "Event" -> "Event"
- | name when (IsDependsOn name "Event") -> eType
- | _ -> GlobalVars.defaultEventType
-
- // Get all the event handlers from an interface and also from its inherited / implemented interfaces
- let rec GetEventHandler(i : Browser.Interface) =
- let ownEventHandler =
- match i.Properties with
- | Some ps ->
- ps.Properties
- |> Array.choose (fun p' ->
- if p'.Type = "EventHandler" && p'.EventHandler.IsSome then
- Some({ Name = p'.Name
- EventName = p'.EventHandler.Value
- EventType = GetEventTypeFromHandler p' i })
- else None)
- |> List.ofArray
- | None -> []
- if ownEventHandler.Length > 0 then ownEventHandler else []
-
- allInterfaces
- |> Array.map (fun i -> (i.Name, GetEventHandler i))
- |> Map.ofArray
-
-let iNameToEhParents =
- let hasHandler (i : Browser.Interface) =
- iNameToEhList.ContainsKey i.Name && not iNameToEhList.[i.Name].IsEmpty
-
- // Get all the event handlers from an interface and also from its inherited / implemented interfaces
- let rec GetEventHandler(i : Browser.Interface) =
- let extendedEventHandler =
- match GetInterfaceByName i.Extends with
- | Some i when hasHandler i -> [i]
- | _ -> []
-
- let implementedEventHandler =
- let implementis = i.Implements |> Array.map GetInterfaceByName
- [ for i' in implementis do
- yield! match i' with
- | Some i -> if hasHandler i then [i] else []
- | None -> [] ]
-
- List.concat [ extendedEventHandler; implementedEventHandler ]
-
- allInterfaces
- |> Array.map (fun i -> (i.Name, GetEventHandler i))
- |> Map.ofArray
-
-/// Event handler name to event type map
-let ehNameToEType =
- let t =
- [ for KeyValue(_, ehList) in iNameToEhList do
- yield! (List.map (fun eh -> (eh.Name, eh.EventType)) ehList) ]
- |> List.distinct
- t |> Map.ofList
-
-let GetGlobalPollutor flavor =
- match flavor with
- | Flavor.Web | Flavor.All -> browser.Interfaces |> Array.tryFind (fun i -> i.PrimaryGlobal.IsSome)
- | Flavor.Worker -> worker.Interfaces |> Array.tryFind (fun i -> i.Global.IsSome)
-
-let GetGlobalPollutorName flavor =
- match GetGlobalPollutor flavor with
- | Some gp -> gp.Name
- | _ -> "Window"
-
-/// Return a sequence of returntype * HashSet tuple
-let GetOverloads (f : Function) (decomposeMultipleTypes : bool) =
- let getParams (f : Function) =
- match f with
- | Method m ->
- [ for p in m.Params do
- yield { Type = p.Type
- Name = p.Name
- Optional = p.Optional.IsSome
- Variadic = p.Variadic.IsSome
- Nullable = p.Nullable.IsSome } ]
- | Ctor c ->
- [ for p in c.Params do
- yield { Type = p.Type
- Name = p.Name
- Optional = p.Optional.IsSome
- Variadic = p.Variadic.IsSome
- Nullable = p.Nullable.IsSome } ]
- | CallBackFun cb ->
- [ for p in cb.Params do
- yield { Type = p.Type
- Name = p.Name
- Optional = p.Optional.IsSome
- Variadic = p.Variadic.IsSome
- Nullable = p.Nullable.IsSome } ]
-
- let getReturnType (f : Function) =
- match f with
- | Method m -> m.Type
- | Ctor _ -> ""
- | CallBackFun cb -> cb.Type
-
- let isNullable =
- match f with
- | Method m -> m.Nullable.IsSome
- | Ctor _ -> false
- | CallBackFun cb -> true
-
- // Some params have the type of "(DOMString or DOMString [] or Number)"
- // we need to transform it into [“DOMString", "DOMString []", "Number"]
- let decomposeTypes (t : string) = t.Trim([| '('; ')' |]).Split([| " or " |], StringSplitOptions.None)
-
- let decomposeParam (p : Param) =
- [ for t in (decomposeTypes p.Type) do
- yield { Type = t
- Name = p.Name
- Optional = p.Optional
- Variadic = p.Variadic
- Nullable = p.Nullable } ]
-
- let pCombList =
- let pCombs = List<_>()
-
- let rec enumParams (acc : Param list) (rest : Param list) =
- match rest with
- | p :: ps when p.Type.Contains("or") ->
- let pOptions = decomposeParam p
- for pOption in pOptions do
- enumParams (pOption :: acc) ps
- | p :: ps -> enumParams (p :: acc) ps
- | [] ->
- // Iteration is completed and time to print every param now
- pCombs.Add(List.rev acc) |> ignore
- enumParams [] (getParams f)
- List.ofSeq pCombs
-
- let rTypes =
- getReturnType f
- |> decomposeTypes
- |> List.ofArray
-
- if decomposeMultipleTypes then
- [ for pComb in pCombList do
- yield { ParamCombinations = pComb
- ReturnTypes = rTypes
- Nullable = isNullable } ]
- else
- [ { ParamCombinations = getParams f
- ReturnTypes = rTypes
- Nullable = isNullable } ]
-
-/// Define the subset of events that dedicated workers will use
-let workerEventsMap =
- [ ("close", "CloseEvent")
- ("error", "ErrorEvent")
- ("upgradeneeded", "IDBVersionChangeEvent")
- ("message", "MessageEvent")
- ("loadend", "ProgressEvent")
- ("progress", "ProgressEvent") ]
- |> Map.ofList
-
-let typeDefSet =
- browser.Typedefs |> Array.map (fun td -> td.NewType) |> Set.ofArray
-
-module Option =
- let runIfSome f x =
- match x with
- | Some x' -> f x'
- | _ -> ()
-
- let toBool f x =
- match x with
- | Some x' -> f x'
- | _ -> false
\ No newline at end of file
diff --git a/TS.fsx b/TS.fsx
index 41e7f3afb..1cb46d1e8 100644
--- a/TS.fsx
+++ b/TS.fsx
@@ -1,775 +1,1438 @@
-#load "Shared.fsx"
+#r "packages/FSharp.Data/lib/net40/FSharp.Data.dll"
+#r "System.Xml.Linq.dll"
open System
-open System.Text.RegularExpressions
-open Shared
-open Shared.Comments
-open Shared.JsonItems
+open System.Collections.Generic
open System.IO
+open System.Text
+open System.Text.RegularExpressions
open System.Web
+open Microsoft.FSharp.Reflection
+open FSharp.Data
+
+module GlobalVars =
+ let inputFolder = Path.Combine(__SOURCE_DIRECTORY__, "inputfiles")
+ let outputFolder = Path.Combine(__SOURCE_DIRECTORY__, "generated")
+
+ // Create output folder
+ if not (Directory.Exists(outputFolder)) then
+ Directory.CreateDirectory(outputFolder) |> ignore
+
+ let makeTextWriter fileName = File.CreateText(Path.Combine(outputFolder, fileName)) :> TextWriter
+ let tsWebOutput = makeTextWriter "dom.generated.d.ts"
+ let tsWorkerOutput = makeTextWriter "webworker.generated.d.ts"
+ let defaultEventType = "Event"
+
+module Helpers =
+ /// Quick checker for option type values
+ let OptionCheckValue value = function
+ | Some v when v = value -> true
+ | _ -> false
-// Global print target
-let Pt = StringPrinter()
-
-// When emit webworker types the dom types are ignored
-let mutable ignoreDOMTypes = false
-
-// Extended types used but not defined in the spec
-let extendedTypes =
- ["ArrayBuffer";"ArrayBufferView";"Int8Array";"Uint8Array";"Int16Array";"Uint16Array";"Int32Array";"Uint32Array";"Float32Array";"Float64Array"]
-
-/// Get typescript type using object dom type, object name, and it's associated interface name
-let rec DomTypeToTsType (objDomType: string) =
- match objDomType.Trim('?') with
- | "AbortMode" -> "String"
- | "any" -> "any"
- | "bool" | "boolean" | "Boolean" -> "boolean"
- | "CanvasPixelArray" -> "number[]"
- | "Date" -> "Date"
- | "DOMHighResTimeStamp" -> "number"
- | "DOMString" -> "string"
- | "DOMTimeStamp" -> "number"
- | "EndOfStreamError" -> "number"
- | "EventListener" -> "EventListenerOrEventListenerObject"
- | "double" | "float" -> "number"
- | "Function" -> "Function"
- | "long" | "long long" | "signed long" | "signed long long" | "unsigned long" | "unsigned long long" -> "number"
- | "octet" | "byte" -> "number"
- | "object" -> "any"
- | "Promise" -> "Promise"
- | "ReadyState" -> "string"
- | "sequence" -> "Array"
- | "short" | "signed short" | "unsigned short" -> "number"
- | "UnrestrictedDouble" -> "number"
- | "void" -> "void"
- | extendedType when List.contains extendedType extendedTypes -> extendedType
- | _ ->
- if ignoreDOMTypes && Seq.contains objDomType ["Element"; "Window"; "Document"] then "any"
- else
- // Name of an interface / enum / dict. Just return itself
- if allInterfacesMap.ContainsKey objDomType ||
- allCallbackFuncs.ContainsKey objDomType ||
- allDictionariesMap.ContainsKey objDomType then
- objDomType
- // Name of a type alias. Just return itself
- elif typeDefSet.Contains objDomType then objDomType
- // Enum types are all treated as string
- elif allEnumsMap.ContainsKey objDomType then "string"
- // Union types
- elif objDomType.Contains(" or ") then
- let allTypes = objDomType.Trim('(', ')').Split([|" or "|], StringSplitOptions.None)
- |> Array.map (fun t -> DomTypeToTsType (t.Trim('?', ' ')))
- if Seq.contains "any" allTypes then "any" else String.concat " | " allTypes
- else
- // Check if is array type, which looks like "sequence"
- let unescaped = System.Web.HttpUtility.HtmlDecode(objDomType)
- let genericMatch = Regex.Match(unescaped, @"^(\w+)<(\w+)>$")
- if genericMatch.Success then
- let tName = DomTypeToTsType (genericMatch.Groups.[1].Value)
- let paramName = DomTypeToTsType (genericMatch.Groups.[2].Value)
- match tName with
- | "Promise" ->
- "PromiseLike<" + paramName + ">"
- | _ ->
- if tName = "Array" then paramName + "[]"
- else tName + "<" + paramName + ">"
- elif objDomType.EndsWith("[]") then
- let elementType = objDomType.Replace("[]", "").Trim() |> DomTypeToTsType
- elementType + "[]"
- else "any"
-
-
-let makeNullable (originalType: string) =
- match originalType with
- | "any" -> "any"
- | "void" -> "void"
- | t when t.Contains "| null" -> t
- | functionType when functionType.Contains "=>" -> "(" + functionType + ") | null"
- | _ -> originalType + " | null"
-
-let DomTypeToNullableTsType (objDomType: string) (nullable: bool) =
- let resolvedType = DomTypeToTsType objDomType
- if nullable then makeNullable resolvedType else resolvedType
-
-let EmitConstants (i: Browser.Interface) =
- let emitConstantFromJson (c: ItemsType.Root) = Pt.printl "readonly %s: %s;" c.Name.Value c.Type.Value
-
- let emitConstant (c: Browser.Constant) =
- if Option.isNone (findRemovedItem c.Name ItemKind.Constant i.Name) then
- match findOverriddenItem c.Name ItemKind.Constant i.Name with
- | Some c' -> emitConstantFromJson c'
- | None -> Pt.printl "readonly %s: %s;" c.Name (DomTypeToTsType c.Type)
-
- // Emit the constants added in the json files
-
- let addedConstants = getAddedItems ItemKind.Constant Flavor.All
- Array.iter emitConstantFromJson addedConstants
-
- if i.Constants.IsSome then
- Array.iter emitConstant i.Constants.Value.Constants
-
-let matchSingleParamMethodSignature (m: Browser.Method) expectedMName expectedMType expectedParamType =
- OptionCheckValue expectedMName m.Name &&
- (DomTypeToNullableTsType m.Type m.Nullable.IsSome) = expectedMType &&
- m.Params.Length = 1 &&
- (DomTypeToTsType m.Params.[0].Type) = expectedParamType
-
-/// Emit overloads for the createElement method
-let EmitCreateElementOverloads (m: Browser.Method) =
- if matchSingleParamMethodSignature m "createElement" "Element" "string" then
- Pt.printl "createElement(tagName: K): HTMLElementTagNameMap[K];"
- Pt.printl "createElement(tagName: string): HTMLElement;"
-
-/// Emit overloads for the getElementsByTagName method
-let EmitGetElementsByTagNameOverloads (m: Browser.Method) =
- if matchSingleParamMethodSignature m "getElementsByTagName" "NodeList" "string" then
- Pt.printl "getElementsByTagName(%s: K): ElementListTagNameMap[K];" m.Params.[0].Name
- Pt.printl "getElementsByTagName(%s: string): NodeListOf;" m.Params.[0].Name
-
-/// Emit overloads for the querySelector method
-let EmitQuerySelectorOverloads (m: Browser.Method) =
- if matchSingleParamMethodSignature m "querySelector" "Element" "string" then
- Pt.printl "querySelector(selectors: K): ElementTagNameMap[K] | null;"
- Pt.printl "querySelector(selectors: string): Element | null;"
-
-/// Emit overloads for the querySelectorAll method
-let EmitQuerySelectorAllOverloads (m: Browser.Method) =
- if matchSingleParamMethodSignature m "querySelectorAll" "NodeList" "string" then
- Pt.printl "querySelectorAll(selectors: K): ElementListTagNameMap[K];"
- Pt.printl "querySelectorAll(selectors: string): NodeListOf;"
-
-let EmitHTMLElementTagNameMap () =
- Pt.printl "interface HTMLElementTagNameMap {"
- Pt.increaseIndent()
- for e in tagNameToEleName do
- if iNameToIDependList.ContainsKey e.Value && Seq.contains "HTMLElement" iNameToIDependList.[e.Value] then
- Pt.printl "\"%s\": %s;" (e.Key.ToLower()) e.Value
- Pt.decreaseIndent()
- Pt.printl "}"
- Pt.printl ""
-
-let EmitElementTagNameMap () =
- Pt.printl "interface ElementTagNameMap {"
- Pt.increaseIndent()
- for e in tagNameToEleName do
- Pt.printl "\"%s\": %s;" (e.Key.ToLower()) e.Value
- Pt.decreaseIndent()
- Pt.printl "}"
- Pt.printl ""
-
-let EmitElementListTagNameMap () =
- Pt.printl "interface ElementListTagNameMap {"
- Pt.increaseIndent()
- for e in tagNameToEleName do
- Pt.printl "\"%s\": NodeListOf<%s>;" (e.Key.ToLower()) e.Value
- Pt.decreaseIndent()
- Pt.printl "}"
- Pt.printl ""
-
-/// Emit overloads for the createEvent method
-let EmitCreateEventOverloads (m: Browser.Method) =
- if matchSingleParamMethodSignature m "createEvent" "Event" "string" then
- // Emit plurals. For example, "Events", "MutationEvents"
- let hasPlurals = ["Event"; "MutationEvent"; "MouseEvent"; "SVGZoomEvent"; "UIEvent"]
- for x in distinctETypeList do
- Pt.printl "createEvent(eventInterface:\"%s\"): %s;" x x
- if List.contains x hasPlurals then
- Pt.printl "createEvent(eventInterface:\"%ss\"): %s;" x x
- Pt.printl "createEvent(eventInterface: string): Event;"
-
-/// Generate the parameters string for function signatures
-let ParamsToString (ps: Param list) =
- let paramToString (p: Param) =
- let isOptional = not p.Variadic && p.Optional
- let pType = if isOptional then DomTypeToTsType p.Type else DomTypeToNullableTsType p.Type p.Nullable
- (if p.Variadic then "..." else "") +
- (AdjustParamName p.Name) +
- (if isOptional then "?: " else ": ") +
- pType +
- (if p.Variadic then "[]" else "")
- String.Join(", ", (List.map paramToString ps))
-
-let EmitMethod flavor prefix (i:Browser.Interface) (m:Browser.Method) =
- // print comment
- if m.Name.IsSome then
- match GetCommentForMethod i.Name m.Name.Value with
- | Some comment -> Pt.printl "%s" comment
- | _ -> ()
+ let unionToString (x: 'a) =
+ match FSharpValue.GetUnionFields(x, typeof<'a>) with
+ | case, _ -> case.Name
- // Find if there are overriding signatures in the external json file
- // - overriddenType: meaning there is a better definition of this type in the json file
- // - removedType: meaning the type is marked as removed in the json file
- // if there is any conflicts between the two, the "removedType" has a higher priority over
- // the "overridenType".
- let removedType = Option.bind (fun name -> JsonItems.findRemovedItem name JsonItems.ItemKind.Method i.Name) m.Name
- let overridenType = Option.bind (fun mName -> JsonItems.findOverriddenItem mName JsonItems.ItemKind.Method i.Name) m.Name
-
- if removedType.IsNone then
- match overridenType with
- | Some t ->
- match flavor with
- | Flavor.All | Flavor.Web -> t.WebOnlySignatures |> Array.iter (Pt.printl "%s%s;" prefix)
+ module Option =
+ let runIfSome f x =
+ match x with
+ | Some x' -> f x'
| _ -> ()
- t.Signatures |> Array.iter (Pt.printl "%s%s;" prefix)
- | None ->
- match i.Name, m.Name with
- | _, Some "createElement" -> EmitCreateElementOverloads m
- | _, Some "createEvent" -> EmitCreateEventOverloads m
- | _, Some "getElementsByTagName" -> EmitGetElementsByTagNameOverloads m
- | _, Some "querySelector" -> EmitQuerySelectorOverloads m
- | _, Some "querySelectorAll" -> EmitQuerySelectorAllOverloads m
- | _ ->
- if m.Name.IsSome then
- // If there are added overloads from the json files, print them first
- match findAddedItem m.Name.Value ItemKind.SignatureOverload i.Name with
- | Some ol -> ol.Signatures |> Array.iter (Pt.printl "%s")
- | _ -> ()
- let overloads = GetOverloads (Function.Method m) false
- for { ParamCombinations = pCombList; ReturnTypes = rTypes; Nullable = isNullable } in overloads do
- let paramsString = ParamsToString pCombList
- let returnString =
- let returnType = rTypes |> List.map DomTypeToTsType |> String.concat " | "
- if isNullable then makeNullable returnType else returnType
- Pt.printl "%s%s(%s): %s;" prefix (if m.Name.IsSome then m.Name.Value else "") paramsString returnString
-
-let EmitCallBackInterface (i:Browser.Interface) =
- Pt.printl "interface %s {" i.Name
- Pt.printWithAddedIndent "(evt: Event): void;"
- Pt.printl "}"
- Pt.printl ""
-
-let EmitCallBackFunctions flavor =
- let emitCallbackFunctionsFromJson (cb: JsonItems.ItemsType.Root) =
- Pt.printl "interface %s {" cb.Name.Value
- cb.Signatures |> Array.iter (Pt.printWithAddedIndent "%s;")
- Pt.printl "}"
-
- let emitCallBackFunction (cb: Browser.CallbackFunction) =
- if Option.isNone (findRemovedItem cb.Name ItemKind.Callback "")then
- match findOverriddenItem cb.Name ItemKind.Callback "" with
- | Some cb' -> emitCallbackFunctionsFromJson cb'
- | _ ->
- Pt.printl "interface %s {" cb.Name
- let overloads = GetOverloads (CallBackFun cb) false
- for { ParamCombinations = pCombList } in overloads do
- let paramsString = ParamsToString pCombList
- Pt.printWithAddedIndent "(%s): %s;" paramsString (DomTypeToTsType cb.Type)
- Pt.printl "}"
-
- getAddedItems ItemKind.Callback flavor
- |> Array.iter emitCallbackFunctionsFromJson
-
- GetCallbackFuncsByFlavor flavor |> Array.iter emitCallBackFunction
-
-let EmitEnums () =
- let emitEnum (e: Browser.Enum) = Pt.printl "declare var %s: string;" e.Name
- browser.Enums |> Array.iter emitEnum
-
-let EmitEventHandlerThis flavor (prefix: string) (i: Browser.Interface) =
- if prefix = "" then "this: " + i.Name + ", "
- else match GetGlobalPollutor flavor with
- | Some pollutor -> "this: " + pollutor.Name + ", "
- | _ -> ""
-let EmitProperties flavor prefix (emitScope: EmitScope) (i: Browser.Interface)=
- let emitPropertyFromJson (p: ItemsType.Root) =
- let readOnlyModifier =
- match p.Readonly with
- | Some(true) -> "readonly "
- | _ -> ""
- Pt.printl "%s%s%s: %s;" prefix readOnlyModifier p.Name.Value p.Type.Value
+ let toBool f x =
+ match x with
+ | Some x' -> f x'
+ | _ -> false
- let emitProperty (p: Browser.Property) =
- match GetCommentForProperty i.Name p.Name with
- | Some comment -> Pt.printl "%s" comment
- | _ -> ()
+ type String with
+ member this.TrimStartString str =
+ if this.StartsWith(str) then this.Substring(str.Length)
+ else this
- // Treat window.name specially because of https://github.com/Microsoft/TypeScript/issues/9850
- if p.Name = "name" && i.Name = "Window" && emitScope = EmitScope.All then
- Pt.printl "declare const name: never;"
- elif Option.isNone (findRemovedItem p.Name ItemKind.Property i.Name) then
- match findOverriddenItem p.Name ItemKind.Property i.Name with
- | Some p' -> emitPropertyFromJson p'
- | None ->
- let pType =
- match p.Type with
- | "EventHandler" ->
- // Sometimes event handlers with the same name may actually handle different
- // events in different interfaces. For example, "onerror" handles "ErrorEvent"
- // normally, but in "SVGSVGElement" it handles "SVGError" event instead.
- let eType =
- if p.EventHandler.IsSome then
- getEventTypeInInterface p.EventHandler.Value i.Name
- else
- "Event"
- String.Format("({0}ev: {1}) => any", EmitEventHandlerThis flavor prefix i, eType)
- | _ -> DomTypeToTsType p.Type
- let pTypeAndNull = if p.Nullable.IsSome then makeNullable pType else pType
- let readOnlyModifier = if p.ReadOnly.IsSome && prefix = "" then "readonly " else ""
- Pt.printl "%s%s%s: %s;" prefix readOnlyModifier p.Name pTypeAndNull
-
- // Note: the schema file shows the property doesn't have "static" attribute,
- // therefore all properties are emited for the instance type.
- if emitScope <> StaticOnly then
- match i.Properties with
- | Some ps ->
- ps.Properties
- |> Array.filter (ShouldKeep flavor)
- |> Array.iter emitProperty
- | None -> ()
-
- getAddedItems ItemKind.Property flavor
- |> Array.filter (fun addedItem -> (matchInterface i.Name addedItem) && (prefix <> "declare var " || not(OptionCheckValue false addedItem.ExposeGlobally)))
- |> Array.iter emitPropertyFromJson
-
-let EmitMethods flavor prefix (emitScope: EmitScope) (i: Browser.Interface) =
- // Note: two cases:
- // 1. emit the members inside a interface -> no need to add prefix
- // 2. emit the members outside to expose them (for "Window") -> need to add "declare"
- let emitMethodFromJson (m: ItemsType.Root) =
- m.Signatures |> Array.iter (Pt.printl "%s%s;" prefix)
-
- // If prefix is not empty, then this is the global declare function addEventListener, we want to override this
- // Otherwise, this is EventTarget.addEventListener, we want to keep that.
- let mFilter (m:Browser.Method) =
- matchScope emitScope m &&
- not (prefix <> "" && OptionCheckValue "addEventListener" m.Name)
-
- if i.Methods.IsSome then
- i.Methods.Value.Methods
- |> Array.filter mFilter
- |> Array.iter (EmitMethod flavor prefix i)
-
- getAddedItems ItemKind.Method flavor
- |> Array.filter (fun m -> matchInterface i.Name m && matchScope emitScope m)
- |> Array.iter emitMethodFromJson
-
- // The window interface inherited some methods from "Object",
- // which need to explicitly exposed
- if i.Name = "Window" && prefix = "declare function " then
- Pt.printl "%stoString(): string;" prefix
-
-/// Emit the properties and methods of a given interface
-let EmitMembers flavor (prefix: string) (emitScope: EmitScope) (i:Browser.Interface) =
- EmitProperties flavor prefix emitScope i
- let methodPrefix = if prefix.StartsWith("declare var") then "declare function " else ""
- EmitMethods flavor methodPrefix emitScope i
-
-/// Emit all members of every interfaces at the root level.
-/// Called only once on the global polluter object
-let rec EmitAllMembers flavor (i:Browser.Interface) =
- let prefix = "declare var "
- EmitMembers flavor prefix EmitScope.All i
-
- for relatedIName in iNameToIDependList.[i.Name] do
- match GetInterfaceByName relatedIName with
- | Some i' -> EmitAllMembers flavor i'
- | _ -> ()
+module Types =
+ open Helpers
-let EmitEventHandlers (flavor: Flavor) (prefix: string) (i:Browser.Interface) =
- let fPrefix =
- if prefix.StartsWith "declare var" then "declare function " else ""
-
- let emitEventHandler prefix (i:Browser.Interface) =
- Pt.printl
- "%saddEventListener(type: K, listener: (this: %s, ev: %sEventMap[K]) => any, useCapture?: boolean): void;"
- prefix i.Name i.Name i.Name
-
- let shouldEmitStringEventHandler =
- if 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
- iNameToEhParents.[i.Name]
- |> List.sortBy (fun i -> i.Name)
- |> List.iter (emitEventHandler fPrefix)
- true
- else
- false
+ type Flavor = Worker | Web | All with
+ override x.ToString() = unionToString x
+
+ type Browser = XmlProvider<"sample.xml", Global=true>
+
+ // Printer for print to string
+ type StringPrinter() =
+ let output = StringBuilder()
+ let mutable curTabCount = 0
+ member this.GetCurIndent() = String.replicate curTabCount " "
+
+ member this.Print content = Printf.kprintf (output.Append >> ignore) content
+
+ member this.Printl content =
+ Printf.kprintf (fun s -> output.Append("\r\n" + this.GetCurIndent() + s) |> ignore) content
+
+ member this.IncreaseIndent() = curTabCount <- curTabCount + 1
+
+ member this.SetIndent indentNum = curTabCount <- indentNum
+
+ member this.DecreaseIndent() = curTabCount <- Math.Max(curTabCount - 1, 0)
+
+ member this.ResetIndent() = curTabCount <- 0
+
+ member this.PrintWithAddedIndent content =
+ Printf.kprintf (fun s -> output.Append("\r\n" + this.GetCurIndent() + " " + s) |> ignore) content
+
+ member this.GetResult() = output.ToString()
+
+ member this.Clear() = output.Clear() |> ignore
+
+ member this.Reset() =
+ this.Clear()
+ this.ResetIndent()
+
+ type Event = { Name : string; Type : string }
+
+ /// Method parameter
+ type Param = {
+ Type : string
+ Name : string
+ Optional : bool
+ Variadic : bool
+ Nullable : bool }
+
+ /// Function overload
+ type Overload = { ParamCombinations : Param list; ReturnTypes : string list; Nullable : Boolean } with
+ member this.IsEmpty = this.ParamCombinations.IsEmpty && (this.ReturnTypes = [ "void" ] || this.ReturnTypes = [ "" ])
- if shouldEmitStringEventHandler then
- Pt.printl
- "%saddEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void;"
- fPrefix
+ type Function =
+ | Method of Browser.Method
+ | Ctor of Browser.Constructor
+ | CallBackFun of Browser.CallbackFunction
-let EmitConstructorSignature (i:Browser.Interface) =
- let emitConstructorSigFromJson (c: ItemsType.Root) =
- c.Signatures |> Array.iter (Pt.printl "%s;")
+ // Note:
+ // Eventhandler's name and the eventName are not just off by "on".
+ // For example, handlers named "onabort" may handle "SVGAbort" event in the XML file
+ type EventHandler = { Name : string; EventName : string; EventType : string }
- let removedCtor = getRemovedItems ItemKind.Constructor Flavor.All |> Array.tryFind (matchInterface i.Name)
- if Option.isNone removedCtor then
- let overriddenCtor = getOverriddenItems ItemKind.Constructor Flavor.All |> Array.tryFind (matchInterface i.Name)
- match overriddenCtor with
- | Some c' -> emitConstructorSigFromJson c'
+ /// Decide which members of a function to emit
+ type EmitScope =
+ | StaticOnly
+ | InstanceOnly
+ | All
+
+module InputJson =
+ open Helpers
+ open Types
+
+ type InputJsonType = JsonProvider<"inputfiles/sample.json">
+
+ let overriddenItems =
+ File.ReadAllText(GlobalVars.inputFolder + @"/overridingTypes.json") |> InputJsonType.Parse
+
+ let removedItems =
+ File.ReadAllText(GlobalVars.inputFolder + @"/removedTypes.json") |> InputJsonType.Parse
+
+ let addedItems =
+ File.ReadAllText(GlobalVars.inputFolder + @"/addedTypes.json") |> InputJsonType.Parse
+
+ // This is the kind of items in the external json files that are used as a
+ // correction for the spec.
+ type ItemKind =
+ | Property
+ | Method
+ | Constant
+ | Constructor
+ | Interface
+ | Callback
+ | Indexer
+ | SignatureOverload
+ | TypeDef
+ | Extends
+ override x.ToString() =
+ match x with
+ | Property _ -> "property"
+ | Method _ -> "method"
+ | Constant _ -> "constant"
+ | Constructor _ -> "constructor"
+ | Interface _ -> "interface"
+ | Callback _ -> "callback"
+ | Indexer _ -> "indexer"
+ | SignatureOverload _ -> "signatureoverload"
+ | TypeDef _ -> "typedef"
+ | Extends _ -> "extends"
+
+ let getItemByName (allItems: InputJsonType.Root []) (itemName: string) (kind: ItemKind) otherFilter =
+ let filter (item: InputJsonType.Root) =
+ OptionCheckValue itemName item.Name &&
+ item.Kind.ToLower() = kind.ToString() &&
+ otherFilter item
+ allItems |> Array.tryFind filter
+
+ let matchInterface iName (item: InputJsonType.Root) =
+ item.Interface.IsNone || item.Interface.Value = iName
+
+ let getOverriddenItemByName itemName (kind: ItemKind) iName =
+ getItemByName overriddenItems itemName kind (matchInterface iName)
+
+ let getRemovedItemByName itemName (kind: ItemKind) iName =
+ getItemByName removedItems itemName kind (matchInterface iName)
+
+ let getAddedItemByName itemName (kind: ItemKind) iName =
+ getItemByName addedItems itemName kind (matchInterface iName)
+
+ let getItems (allItems: InputJsonType.Root []) (kind: ItemKind) (flavor: Flavor) =
+ allItems
+ |> Array.filter (fun t ->
+ t.Kind.ToLower() = kind.ToString() &&
+ (t.Flavor.IsNone || t.Flavor.Value = flavor.ToString() || flavor = Flavor.All))
+
+ let getOverriddenItems = getItems overriddenItems
+
+ let getAddedItems = getItems addedItems
+
+ let getRemovedItems = getItems removedItems
+
+ let getAddedItemsByInterfaceName kind flavor iName =
+ getAddedItems kind flavor |> Array.filter (matchInterface iName)
+
+ let getOverriddenItemsByInterfaceName kind flavor iName =
+ getOverriddenItems kind flavor |> Array.filter (matchInterface iName)
+
+ let getRemovedItemsByInterfaceName kind flavor iName =
+ getRemovedItems kind flavor |> Array.filter (matchInterface iName)
+
+module CommentJson =
+ type CommentJsonType = JsonProvider<"inputfiles/comments.json", InferTypesFromValues=false>
+
+ let comments = File.ReadAllText(Path.Combine(GlobalVars.inputFolder, "comments.json")) |> CommentJsonType.Parse
+
+ type InterfaceCommentItem = { Property: Map; Method: Map; Constructor: string option }
+
+ let commentMap =
+ comments.Interfaces
+ |> Array.map (fun i ->
+ let propertyMap = i.Members.Property |> Array.map (fun p -> (p.Name, p.Comment)) |> Map.ofArray
+ let methodMap = i.Members.Method |> Array.map (fun m -> (m.Name, m.Comment)) |> Map.ofArray
+ (i.Name, { Property = propertyMap; Method = methodMap; Constructor = i.Members.Constructor }))
+ |> Map.ofArray
+
+ let GetCommentForProperty iName pName =
+ match commentMap.TryFind iName with
+ | Some i -> i.Property.TryFind pName
+ | _ -> None
+
+ let GetCommentForMethod iName mName =
+ match commentMap.TryFind iName with
+ | Some i -> i.Method.TryFind mName
+ | _ -> None
+
+ let GetCommentForConstructor iName =
+ match commentMap.TryFind iName with
+ | Some i -> i.Constructor
+ | _ -> None
+
+module Data =
+ open Helpers
+ open Types
+
+ // Used to decide if a member should be emitted given its static property and
+ // the intended scope level.
+ let inline matchScope scope (x: ^a when ^a: (member Static: Option<'b>)) =
+ if scope = EmitScope.All then true
+ else
+ let isStatic = (^a: (member Static: Option<'b>)x)
+ if isStatic.IsSome then scope = EmitScope.StaticOnly
+ else scope = EmitScope.InstanceOnly
+
+ let matchInterface iName (x: InputJson.InputJsonType.Root) =
+ x.Interface.IsNone || x.Interface.Value = iName
+
+ /// Parameter cannot be named "default" in JavaScript/Typescript so we need to rename it.
+ let AdjustParamName name =
+ match name with
+ | "default" -> "_default"
+ | "delete" -> "_delete"
+ | "continue" -> "_continue"
+ | _ -> name
+
+ /// Parse the xml input file
+ let browser =
+ (new StreamReader(Path.Combine(GlobalVars.inputFolder, "browser.webidl.xml"))).ReadToEnd() |> Browser.Parse
+
+ let worker =
+ (new StreamReader(Path.Combine(GlobalVars.inputFolder, "webworkers.specidl.xml"))).ReadToEnd() |> Browser.Parse
+
+ /// Check if the given element should be disabled or not
+ /// reason is that ^a can be an interface, property or method, but they
+ /// all share a 'tag' property
+ let inline ShouldKeep flavor (i: ^a when ^a: (member Tags: string option)) =
+ let filterByTag =
+ match (^a: (member Tags: string option) i) with
+ | Some tags ->
+ match flavor with
+ | Flavor.All -> true
+ | Flavor.Web -> tags <> "MSAppOnly" && tags <> "WinPhoneOnly"
+ | Flavor.Worker -> tags <> "IEOnly"
+ | _ -> true
+ filterByTag
+
+ // Global interfacename to interface object map
+ let allWebNonCallbackInterfaces =
+ Array.concat [| browser.Interfaces; browser.MixinInterfaces.Interfaces |]
+
+ let allWebInterfaces =
+ Array.concat [| browser.Interfaces; [| browser.CallbackInterfaces.Interface |]; browser.MixinInterfaces.Interfaces |]
+
+ let allWorkerAdditionalInterfaces =
+ Array.concat [| worker.Interfaces; worker.MixinInterfaces.Interfaces |]
+
+ let allInterfaces =
+ Array.concat [| allWebInterfaces; allWorkerAdditionalInterfaces |]
+
+ let inline toNameMap< ^a when ^a: (member Name: string) > (data: array< ^a > ) =
+ data
+ |> Array.map (fun x -> ((^a: (member Name: string) x), x))
+ |> Map.ofArray
+
+ let allInterfacesMap =
+ allInterfaces |> toNameMap
+
+ let allDictionariesMap =
+ Array.concat [| browser.Dictionaries; worker.Dictionaries |]
+ |> toNameMap
+
+ let allEnumsMap =
+ Array.concat [| browser.Enums; worker.Enums |]
+ |> toNameMap
+
+ let allCallbackFuncs =
+ Array.concat [| browser.CallbackFunctions; worker.CallbackFunctions |]
+ |> toNameMap
+
+ let GetInterfaceByName = allInterfacesMap.TryFind
+
+ let knownWorkerInterfaces =
+ [ "Algorithm"; "AlgorithmIdentifier"; "KeyAlgorithm"; "CryptoKey"; "AbstractWorker"; "AudioBuffer"; "Blob";
+ "CloseEvent"; "Console"; "Coordinates"; "DecodeSuccessCallback";
+ "DecodeErrorCallback"; "DOMError"; "DOMException"; "DOMStringList"; "ErrorEvent"; "Event"; "ErrorEventHandler";
+ "EventException"; "EventInit"; "EventListener"; "EventTarget"; "File"; "FileList"; "FileReader";
+ "FunctionStringCallback"; "IDBCursor"; "IDBCursorWithValue"; "IDBDatabase"; "IDBFactory"; "IDBIndex";
+ "IDBKeyRange"; "IDBObjectStore"; "IDBOpenDBRequest"; "IDBRequest"; "IDBTransaction"; "IDBVersionChangeEvent";
+ "ImageData"; "MediaQueryList"; "MediaQueryListListener"; "MessageChannel"; "MessageEvent"; "MessagePort"; "MSApp";
+ "MSAppAsyncOperation"; "MSAppView"; "MSBaseReader"; "MSBlobBuilder"; "MSExecAtPriorityFunctionCallback";
+ "MSLaunchUriCallback"; "MSStream"; "MSStreamReader"; "MSUnsafeFunctionCallback"; "NavigatorID"; "NavigatorOnLine";
+ "Position"; "PositionCallback"; "PositionError"; "PositionErrorCallback"; "ProgressEvent"; "WebSocket";
+ "WindowBase64"; "WindowConsole"; "Worker"; "XMLHttpRequest"; "XMLHttpRequestEventTarget"; "XMLHttpRequestUpload";
+ "IDBObjectStoreParameters"; "IDBIndexParameters"; "IDBKeyPath"]
+ |> set
+
+ let GetAllInterfacesByFlavor flavor =
+ match flavor with
+ | Flavor.Web -> allWebInterfaces |> Array.filter (ShouldKeep Web)
+ | Flavor.All -> allWebInterfaces |> Array.filter (ShouldKeep Flavor.All)
+ | Flavor.Worker ->
+ let isFromBrowserXml = allWebInterfaces |> Array.filter (fun i -> knownWorkerInterfaces.Contains i.Name)
+ Array.append isFromBrowserXml allWorkerAdditionalInterfaces
+
+ let GetNonCallbackInterfacesByFlavor flavor =
+ match flavor with
+ | Flavor.Web -> allWebNonCallbackInterfaces |> Array.filter (ShouldKeep Flavor.Web)
+ | Flavor.All -> allWebNonCallbackInterfaces |> Array.filter (ShouldKeep Flavor.All)
+ | Flavor.Worker ->
+ let isFromBrowserXml = allWebNonCallbackInterfaces |> Array.filter (fun i -> knownWorkerInterfaces.Contains i.Name)
+ Array.append isFromBrowserXml allWorkerAdditionalInterfaces
+
+ let GetPublicInterfacesByFlavor flavor =
+ match flavor with
+ | Flavor.Web | Flavor.All -> browser.Interfaces |> Array.filter (ShouldKeep flavor)
+ | Flavor.Worker ->
+ let isFromBrowserXml = browser.Interfaces |> Array.filter (fun i -> knownWorkerInterfaces.Contains i.Name)
+ Array.append isFromBrowserXml worker.Interfaces
+
+ let GetCallbackFuncsByFlavor flavor =
+ browser.CallbackFunctions
+ |> Array.filter (fun cb -> (flavor <> Flavor.Worker || knownWorkerInterfaces.Contains cb.Name) && ShouldKeep flavor cb)
+
+ /// Event name to event type map
+ let eNameToEType =
+ [ for i in allWebNonCallbackInterfaces do
+ if i.Events.IsSome then yield! i.Events.Value.Events ]
+ |> List.map (fun (e : Browser.Event) ->
+ let eType =
+ match e.Name with
+ | "abort" -> "UIEvent"
+ | "complete" -> "Event"
+ | "error" -> "ErrorEvent"
+ | "load" -> "Event"
+ | "loadstart" -> "Event"
+ | "progress" -> "ProgressEvent"
+ | "readystatechange" -> "ProgressEvent"
+ | "resize" -> "UIEvent"
+ | "timeout" -> "ProgressEvent"
+ | _ -> e.Type
+ (e.Name, eType))
+ |> Map.ofList
+
+ let eNameToETypeWithoutCase =
+ eNameToEType
+ |> Map.toList
+ |> List.map (fun (k, v) -> (k.ToLower(), v))
+ |> Map.ofList
+
+ let getEventTypeInInterface eName iName =
+ match iName, eName with
+ | "IDBDatabase", "abort"
+ | "IDBTransaction", "abort"
+ | "MSBaseReader", "abort"
+ | "XMLHttpRequestEventTarget", "abort"
+ -> "Event"
+ | "XMLHttpRequest", "readystatechange"
+ -> "Event"
+ | "XMLHttpRequest", _
+ -> "ProgressEvent"
| _ ->
- //Emit constructor signature
- match i.Constructor with
- | Some ctor ->
- for { ParamCombinations = pCombList } in GetOverloads (Ctor ctor) false do
- let paramsString = ParamsToString pCombList
- Pt.printl "new(%s): %s;" paramsString i.Name
- | _ -> Pt.printl "new(): %s;" i.Name
-
- getAddedItems ItemKind.Constructor Flavor.All
- |> Array.filter (matchInterface i.Name)
- |> Array.iter emitConstructorSigFromJson
-
-let EmitConstructor flavor (i:Browser.Interface) =
- Pt.printl "declare var %s: {" i.Name
- Pt.increaseIndent()
-
- Pt.printl "prototype: %s;" i.Name
- EmitConstructorSignature i
- EmitConstants i
- let prefix = ""
- EmitMembers flavor prefix EmitScope.StaticOnly i
-
- Pt.decreaseIndent()
- Pt.printl "}"
- Pt.printl ""
-
-/// Emit all the named constructors at root level
-let EmitNamedConstructors () =
- browser.Interfaces
- |> Array.filter (fun i -> i.NamedConstructor.IsSome)
- |> Array.iter
- (fun i ->
- let nc = i.NamedConstructor.Value
- let ncParams =
- [for p in nc.Params do
- yield {Type = p.Type; Name = p.Name; Optional = p.Optional.IsSome; Variadic = p.Variadic.IsSome; Nullable = p.Nullable.IsSome}]
- Pt.printl "declare var %s: {new(%s): %s; };" nc.Name (ParamsToString ncParams) i.Name)
-
-let EmitInterfaceDeclaration (i:Browser.Interface) =
- Pt.printl "interface %s" i.Name
- let finalExtends =
- let overridenExtendsFromJson =
- JsonItems.getOverriddenItemsByInterfaceName ItemKind.Extends Flavor.All i.Name
- |> Array.map (fun e -> e.BaseInterface.Value) |> List.ofArray
- if List.isEmpty overridenExtendsFromJson then
- let extendsFromSpec =
- match i.Extends::(List.ofArray i.Implements) with
- | [""] | [] | ["Object"] -> []
- | specExtends -> specExtends
- let extendsFromJson =
- JsonItems.getAddedItemsByInterfaceName ItemKind.Extends Flavor.All i.Name
- |> Array.map (fun e -> e.BaseInterface.Value) |> List.ofArray
- List.concat [extendsFromSpec; extendsFromJson]
+ match eNameToEType.TryFind eName with
+ | Some eType' -> eType'
+ | _ -> "Event"
+
+ /// Tag name to element name map
+ let tagNameToEleName =
+ let preferedElementMap =
+ function
+ | "script" -> "HTMLScriptElement"
+ | "a" -> "HTMLAnchorElement"
+ | "title" -> "HTMLTitleElement"
+ | "style" -> "HTMLStyleElement"
+ | _ -> ""
+
+ let resolveElementConflict tagName (iNames : seq) =
+ match preferedElementMap tagName with
+ | name when Seq.contains name iNames -> name
+ | _ -> raise (Exception("Element conflict occured! Typename: " + tagName))
+
+ [ for i in GetNonCallbackInterfacesByFlavor Flavor.All do
+ yield! [ for e in i.Elements do
+ yield (e.Name, i.Name) ] ]
+ |> Seq.groupBy fst
+ |> Seq.map (fun (key, group) -> (key, Seq.map snd group))
+ |> Seq.map (fun (key, group) ->
+ key,
+ match Seq.length group with
+ | 1 -> Seq.head group
+ | _ -> resolveElementConflict key group)
+ |> Map.ofSeq
+
+ /// Interface name to all its implemented / inherited interfaces name list map
+ /// e.g. If i1 depends on i2, i2 should be in dependencyMap.[i1.Name]
+ let iNameToIDependList =
+ let rec getExtendList(iName : string) =
+ match GetInterfaceByName iName with
+ | Some i ->
+ match i.Extends with
+ | "Object" -> []
+ | super -> super :: (getExtendList super)
+ | _ -> []
+
+ let getImplementList(iName : string) =
+ match GetInterfaceByName iName with
+ | Some i -> List.ofArray i.Implements
+ | _ -> []
+
+ Array.concat [| allWebNonCallbackInterfaces; worker.Interfaces; worker.MixinInterfaces.Interfaces |]
+ |> Array.map (fun i -> (i.Name, List.concat [ (getExtendList i.Name); (getImplementList i.Name) ]))
+ |> Map.ofArray
+
+ /// Distinct event type list, used in the "createEvent" function
+ let distinctETypeList =
+ let usedEvents =
+ [ for i in GetNonCallbackInterfacesByFlavor Flavor.All do
+ match i.Events with
+ | Some es -> yield! es.Events
+ | _ -> () ]
+ |> List.map (fun e -> e.Type)
+ |> List.distinct
+
+ let unUsedEvents =
+ GetNonCallbackInterfacesByFlavor Flavor.All
+ |> Array.choose (fun i ->
+ if i.Extends = "Event" && i.Name.EndsWith("Event") && not (List.contains i.Name usedEvents) then Some(i.Name) else None)
+ |> Array.distinct
+ |> List.ofArray
+
+ List.concat [ usedEvents; unUsedEvents ] |> List.sort
+
+ /// Determine if interface1 depends on interface2
+ let IsDependsOn i1Name i2Name =
+ match (iNameToIDependList.ContainsKey i2Name) && (iNameToIDependList.ContainsKey i1Name) with
+ | true -> Seq.contains i2Name iNameToIDependList.[i1Name]
+ | false -> i2Name = "Object"
+
+ /// Interface name to its related eventhandler name list map
+ /// Note:
+ /// In the xml file, each event handler has
+ /// 1. eventhanlder name: "onready", "onabort" etc.
+ /// 2. the event name that it handles: "ready", "SVGAbort" etc.
+ /// And they don't NOT just differ by an "on" prefix!
+ let iNameToEhList =
+ let getEventTypeFromHandler (p : Browser.Property) (i : Browser.Interface) =
+ let eType =
+ // Check the "event-handler" attribute of the event handler property,
+ // which is the corresponding event name
+ match p.EventHandler with
+ | Some eName ->
+ // The list is partly obtained from the table at
+ // http://www.w3.org/TR/DOM-Level-3-Events/#dom-events-conformance #4.1
+ match eNameToEType.TryFind eName with
+ | Some v -> v
+ | _ -> GlobalVars.defaultEventType
+ | _ -> GlobalVars.defaultEventType
+ match eType with
+ | "Event" -> "Event"
+ | name when (IsDependsOn name "Event") -> eType
+ | _ -> GlobalVars.defaultEventType
+
+ // Get all the event handlers from an interface and also from its inherited / implemented interfaces
+ let rec getEventHandler(i : Browser.Interface) =
+ let ownEventHandler =
+ match i.Properties with
+ | Some ps ->
+ ps.Properties
+ |> Array.choose (fun p' ->
+ if p'.Type = "EventHandler" && p'.EventHandler.IsSome then
+ Some({ Name = p'.Name; EventName = p'.EventHandler.Value; EventType = getEventTypeFromHandler p' i })
+ else None)
+ |> List.ofArray
+ | None -> []
+ if ownEventHandler.Length > 0 then ownEventHandler else []
+
+ allInterfaces
+ |> Array.map (fun i -> (i.Name, getEventHandler i))
+ |> Map.ofArray
+
+ let iNameToEhParents =
+ let hasHandler (i : Browser.Interface) =
+ iNameToEhList.ContainsKey i.Name && not iNameToEhList.[i.Name].IsEmpty
+
+ // Get all the event handlers from an interface and also from its inherited / implemented interfaces
+ let rec getEventHandler(i : Browser.Interface) =
+ let extendedEventHandler =
+ match GetInterfaceByName i.Extends with
+ | Some i when hasHandler i -> [i]
+ | _ -> []
+
+ let implementedEventHandler =
+ let implementis = i.Implements |> Array.map GetInterfaceByName
+ [ for i' in implementis do
+ yield! match i' with
+ | Some i -> if hasHandler i then [i] else []
+ | None -> [] ]
+
+ List.concat [ extendedEventHandler; implementedEventHandler ]
+
+ allInterfaces
+ |> Array.map (fun i -> (i.Name, getEventHandler i))
+ |> Map.ofArray
+
+ /// Event handler name to event type map
+ let ehNameToEType =
+ let t =
+ [ for KeyValue(_, ehList) in iNameToEhList do
+ yield! (List.map (fun eh -> (eh.Name, eh.EventType)) ehList) ]
+ |> List.distinct
+ t |> Map.ofList
+
+ let GetGlobalPollutor flavor =
+ match flavor with
+ | Flavor.Web | Flavor.All -> browser.Interfaces |> Array.tryFind (fun i -> i.PrimaryGlobal.IsSome)
+ | Flavor.Worker -> worker.Interfaces |> Array.tryFind (fun i -> i.Global.IsSome)
+
+ let GetGlobalPollutorName flavor =
+ match GetGlobalPollutor flavor with
+ | Some gp -> gp.Name
+ | _ -> "Window"
+
+ /// Return a sequence of returntype * HashSet tuple
+ let GetOverloads (f : Function) (decomposeMultipleTypes : bool) =
+ let getParams (f : Function) =
+ match f with
+ | Method m ->
+ [ for p in m.Params do
+ yield { Type = p.Type
+ Name = p.Name
+ Optional = p.Optional.IsSome
+ Variadic = p.Variadic.IsSome
+ Nullable = p.Nullable.IsSome } ]
+ | Ctor c ->
+ [ for p in c.Params do
+ yield { Type = p.Type
+ Name = p.Name
+ Optional = p.Optional.IsSome
+ Variadic = p.Variadic.IsSome
+ Nullable = p.Nullable.IsSome } ]
+ | CallBackFun cb ->
+ [ for p in cb.Params do
+ yield { Type = p.Type
+ Name = p.Name
+ Optional = p.Optional.IsSome
+ Variadic = p.Variadic.IsSome
+ Nullable = p.Nullable.IsSome } ]
+
+ let getReturnType (f : Function) =
+ match f with
+ | Method m -> m.Type
+ | Ctor _ -> ""
+ | CallBackFun cb -> cb.Type
+
+ let isNullable =
+ match f with
+ | Method m -> m.Nullable.IsSome
+ | Ctor _ -> false
+ | CallBackFun cb -> true
+
+ // Some params have the type of "(DOMString or DOMString [] or Number)"
+ // we need to transform it into [“DOMString", "DOMString []", "Number"]
+ let decomposeTypes (t : string) = t.Trim([| '('; ')' |]).Split([| " or " |], StringSplitOptions.None)
+
+ let decomposeParam (p : Param) =
+ [ for t in (decomposeTypes p.Type) do
+ yield { Type = t
+ Name = p.Name
+ Optional = p.Optional
+ Variadic = p.Variadic
+ Nullable = p.Nullable } ]
+
+ let pCombList =
+ let pCombs = List<_>()
+
+ let rec enumParams (acc : Param list) (rest : Param list) =
+ match rest with
+ | p :: ps when p.Type.Contains("or") ->
+ let pOptions = decomposeParam p
+ for pOption in pOptions do
+ enumParams (pOption :: acc) ps
+ | p :: ps -> enumParams (p :: acc) ps
+ | [] ->
+ // Iteration is completed and time to print every param now
+ pCombs.Add(List.rev acc) |> ignore
+ enumParams [] (getParams f)
+ List.ofSeq pCombs
+
+ let rTypes =
+ getReturnType f
+ |> decomposeTypes
+ |> List.ofArray
+
+ if decomposeMultipleTypes then
+ [ for pComb in pCombList do
+ yield { ParamCombinations = pComb
+ ReturnTypes = rTypes
+ Nullable = isNullable } ]
else
- overridenExtendsFromJson
- match finalExtends with
- | [] -> ()
- | allExtends -> Pt.print " extends %s" (String.Join(", ", allExtends))
- Pt.print " {"
-
-/// To decide if a given method is an indexer and should be emited
-let ShouldEmitIndexerSignature (i: Browser.Interface) (m: Browser.Method) =
- if m.Getter.IsSome && m.Params.Length = 1 then
- // TypeScript array indexer can only be number or string
- // for string, it must return a more generic type then all
- // the other properties, following the Dictionary pattern
- match DomTypeToTsType m.Params.[0].Type with
- | "number" -> true
- | "string" ->
- match DomTypeToTsType m.Type with
- | "any" -> true
+ [ { ParamCombinations = getParams f
+ ReturnTypes = rTypes
+ Nullable = isNullable } ]
+
+ /// Define the subset of events that dedicated workers will use
+ let workerEventsMap =
+ [
+ ("close", "CloseEvent");
+ ("error", "ErrorEvent");
+ ("upgradeneeded", "IDBVersionChangeEvent");
+ ("message", "MessageEvent");
+ ("loadend", "ProgressEvent");
+ ("progress", "ProgressEvent");
+ ]
+ |> Map.ofList
+
+ let typeDefSet =
+ browser.Typedefs |> Array.map (fun td -> td.NewType) |> Set.ofArray
+
+module Emit =
+ open Data
+ open Types
+ open Helpers
+ open InputJson
+
+ // Global print target
+ let Pt = StringPrinter()
+
+ // When emit webworker types the dom types are ignored
+ let mutable ignoreDOMTypes = false
+
+ // Extended types used but not defined in the spec
+ let extendedTypes =
+ ["ArrayBuffer";"ArrayBufferView";"Int8Array";"Uint8Array";"Int16Array";"Uint16Array";"Int32Array";"Uint32Array";"Float32Array";"Float64Array"]
+
+ /// Get typescript type using object dom type, object name, and it's associated interface name
+ let rec DomTypeToTsType (objDomType: string) =
+ match objDomType.Trim('?') with
+ | "AbortMode" -> "String"
+ | "any" -> "any"
+ | "bool" | "boolean" | "Boolean" -> "boolean"
+ | "CanvasPixelArray" -> "number[]"
+ | "Date" -> "Date"
+ | "DOMHighResTimeStamp" -> "number"
+ | "DOMString" -> "string"
+ | "DOMTimeStamp" -> "number"
+ | "EndOfStreamError" -> "number"
+ | "EventListener" -> "EventListenerOrEventListenerObject"
+ | "double" | "float" -> "number"
+ | "Function" -> "Function"
+ | "long" | "long long" | "signed long" | "signed long long" | "unsigned long" | "unsigned long long" -> "number"
+ | "octet" | "byte" -> "number"
+ | "object" -> "any"
+ | "Promise" -> "Promise"
+ | "ReadyState" -> "string"
+ | "sequence" -> "Array"
+ | "short" | "signed short" | "unsigned short" -> "number"
+ | "UnrestrictedDouble" -> "number"
+ | "void" -> "void"
+ | extendedType when List.contains extendedType extendedTypes -> extendedType
+ | _ ->
+ if ignoreDOMTypes && Seq.contains objDomType ["Element"; "Window"; "Document"] then "any"
+ else
+ // Name of an interface / enum / dict. Just return itself
+ if allInterfacesMap.ContainsKey objDomType ||
+ allCallbackFuncs.ContainsKey objDomType ||
+ allDictionariesMap.ContainsKey objDomType then
+ objDomType
+ // Name of a type alias. Just return itself
+ elif typeDefSet.Contains objDomType then objDomType
+ // Enum types are all treated as string
+ elif allEnumsMap.ContainsKey objDomType then "string"
+ // Union types
+ elif objDomType.Contains(" or ") then
+ let allTypes = objDomType.Trim('(', ')').Split([|" or "|], StringSplitOptions.None)
+ |> Array.map (fun t -> DomTypeToTsType (t.Trim('?', ' ')))
+ if Seq.contains "any" allTypes then "any" else String.concat " | " allTypes
+ else
+ // Check if is array type, which looks like "sequence"
+ let unescaped = System.Web.HttpUtility.HtmlDecode(objDomType)
+ let genericMatch = Regex.Match(unescaped, @"^(\w+)<(\w+)>$")
+ if genericMatch.Success then
+ let tName = DomTypeToTsType (genericMatch.Groups.[1].Value)
+ let paramName = DomTypeToTsType (genericMatch.Groups.[2].Value)
+ match tName with
+ | "Promise" ->
+ "PromiseLike<" + paramName + ">"
+ | _ ->
+ if tName = "Array" then paramName + "[]"
+ else tName + "<" + paramName + ">"
+ elif objDomType.EndsWith("[]") then
+ let elementType = objDomType.Replace("[]", "").Trim() |> DomTypeToTsType
+ elementType + "[]"
+ else "any"
+
+
+ let makeNullable (originalType: string) =
+ match originalType with
+ | "any" -> "any"
+ | "void" -> "void"
+ | t when t.Contains "| null" -> t
+ | functionType when functionType.Contains "=>" -> "(" + functionType + ") | null"
+ | _ -> originalType + " | null"
+
+ let DomTypeToNullableTsType (objDomType: string) (nullable: bool) =
+ let resolvedType = DomTypeToTsType objDomType
+ if nullable then makeNullable resolvedType else resolvedType
+
+ let EmitConstants (i: Browser.Interface) =
+ let emitConstantFromJson (c: InputJsonType.Root) = Pt.Printl "readonly %s: %s;" c.Name.Value c.Type.Value
+
+ let emitConstant (c: Browser.Constant) =
+ if Option.isNone (getRemovedItemByName c.Name ItemKind.Constant i.Name) then
+ match getOverriddenItemByName c.Name ItemKind.Constant i.Name with
+ | Some c' -> emitConstantFromJson c'
+ | None -> Pt.Printl "readonly %s: %s;" c.Name (DomTypeToTsType c.Type)
+
+ let addedConstants = getAddedItems ItemKind.Constant Flavor.All
+ Array.iter emitConstantFromJson addedConstants
+
+ if i.Constants.IsSome then
+ Array.iter emitConstant i.Constants.Value.Constants
+
+ let matchSingleParamMethodSignature (m: Browser.Method) expectedMName expectedMType expectedParamType =
+ OptionCheckValue expectedMName m.Name &&
+ (DomTypeToNullableTsType m.Type m.Nullable.IsSome) = expectedMType &&
+ m.Params.Length = 1 &&
+ (DomTypeToTsType m.Params.[0].Type) = expectedParamType
+
+ /// Emit overloads for the createElement method
+ let EmitCreateElementOverloads (m: Browser.Method) =
+ if matchSingleParamMethodSignature m "createElement" "Element" "string" then
+ Pt.Printl "createElement(tagName: K): HTMLElementTagNameMap[K];"
+ Pt.Printl "createElement(tagName: string): HTMLElement;"
+
+ /// Emit overloads for the getElementsByTagName method
+ let EmitGetElementsByTagNameOverloads (m: Browser.Method) =
+ if matchSingleParamMethodSignature m "getElementsByTagName" "NodeList" "string" then
+ Pt.Printl "getElementsByTagName(%s: K): ElementListTagNameMap[K];" m.Params.[0].Name
+ Pt.Printl "getElementsByTagName(%s: string): NodeListOf;" m.Params.[0].Name
+
+ /// Emit overloads for the querySelector method
+ let EmitQuerySelectorOverloads (m: Browser.Method) =
+ if matchSingleParamMethodSignature m "querySelector" "Element" "string" then
+ Pt.Printl "querySelector(selectors: K): ElementTagNameMap[K] | null;"
+ Pt.Printl "querySelector(selectors: string): Element | null;"
+
+ /// Emit overloads for the querySelectorAll method
+ let EmitQuerySelectorAllOverloads (m: Browser.Method) =
+ if matchSingleParamMethodSignature m "querySelectorAll" "NodeList" "string" then
+ Pt.Printl "querySelectorAll(selectors: K): ElementListTagNameMap[K];"
+ Pt.Printl "querySelectorAll(selectors: string): NodeListOf;"
+
+ let EmitHTMLElementTagNameMap () =
+ Pt.Printl "interface HTMLElementTagNameMap {"
+ Pt.IncreaseIndent()
+ for e in tagNameToEleName do
+ if iNameToIDependList.ContainsKey e.Value && Seq.contains "HTMLElement" iNameToIDependList.[e.Value] then
+ Pt.Printl "\"%s\": %s;" (e.Key.ToLower()) e.Value
+ Pt.DecreaseIndent()
+ Pt.Printl "}"
+ Pt.Printl ""
+
+ let EmitElementTagNameMap () =
+ Pt.Printl "interface ElementTagNameMap {"
+ Pt.IncreaseIndent()
+ for e in tagNameToEleName do
+ Pt.Printl "\"%s\": %s;" (e.Key.ToLower()) e.Value
+ Pt.DecreaseIndent()
+ Pt.Printl "}"
+ Pt.Printl ""
+
+ let EmitElementListTagNameMap () =
+ Pt.Printl "interface ElementListTagNameMap {"
+ Pt.IncreaseIndent()
+ for e in tagNameToEleName do
+ Pt.Printl "\"%s\": NodeListOf<%s>;" (e.Key.ToLower()) e.Value
+ Pt.DecreaseIndent()
+ Pt.Printl "}"
+ Pt.Printl ""
+
+ /// Emit overloads for the createEvent method
+ let EmitCreateEventOverloads (m: Browser.Method) =
+ if matchSingleParamMethodSignature m "createEvent" "Event" "string" then
+ // Emit plurals. For example, "Events", "MutationEvents"
+ let hasPlurals = ["Event"; "MutationEvent"; "MouseEvent"; "SVGZoomEvent"; "UIEvent"]
+ for x in distinctETypeList do
+ Pt.Printl "createEvent(eventInterface:\"%s\"): %s;" x x
+ if List.contains x hasPlurals then
+ Pt.Printl "createEvent(eventInterface:\"%ss\"): %s;" x x
+ Pt.Printl "createEvent(eventInterface: string): Event;"
+
+ /// Generate the parameters string for function signatures
+ let ParamsToString (ps: Param list) =
+ let paramToString (p: Param) =
+ let isOptional = not p.Variadic && p.Optional
+ let pType = if isOptional then DomTypeToTsType p.Type else DomTypeToNullableTsType p.Type p.Nullable
+ (if p.Variadic then "..." else "") +
+ (AdjustParamName p.Name) +
+ (if isOptional then "?: " else ": ") +
+ pType +
+ (if p.Variadic then "[]" else "")
+ String.Join(", ", (List.map paramToString ps))
+
+ let EmitCallBackInterface (i:Browser.Interface) =
+ Pt.Printl "interface %s {" i.Name
+ Pt.PrintWithAddedIndent "(evt: Event): void;"
+ Pt.Printl "}"
+ Pt.Printl ""
+
+ let EmitCallBackFunctions flavor =
+ let emitCallbackFunctionsFromJson (cb: InputJson.InputJsonType.Root) =
+ Pt.Printl "interface %s {" cb.Name.Value
+ cb.Signatures |> Array.iter (Pt.PrintWithAddedIndent "%s;")
+ Pt.Printl "}"
+
+ let emitCallBackFunction (cb: Browser.CallbackFunction) =
+ if Option.isNone (getRemovedItemByName cb.Name ItemKind.Callback "")then
+ match getOverriddenItemByName cb.Name ItemKind.Callback "" with
+ | Some cb' -> emitCallbackFunctionsFromJson cb'
+ | _ ->
+ Pt.Printl "interface %s {" cb.Name
+ let overloads = GetOverloads (CallBackFun cb) false
+ for { ParamCombinations = pCombList } in overloads do
+ let paramsString = ParamsToString pCombList
+ Pt.PrintWithAddedIndent "(%s): %s;" paramsString (DomTypeToTsType cb.Type)
+ Pt.Printl "}"
+
+ getAddedItems ItemKind.Callback flavor
+ |> Array.iter emitCallbackFunctionsFromJson
+
+ GetCallbackFuncsByFlavor flavor |> Array.iter emitCallBackFunction
+
+ let EmitEnums () =
+ let emitEnum (e: Browser.Enum) = Pt.Printl "declare var %s: string;" e.Name
+ browser.Enums |> Array.iter emitEnum
+
+ let EmitEventHandlerThis flavor (prefix: string) (i: Browser.Interface) =
+ if prefix = "" then "this: " + i.Name + ", "
+ else match GetGlobalPollutor flavor with
+ | Some pollutor -> "this: " + pollutor.Name + ", "
+ | _ -> ""
+ let EmitProperties flavor prefix (emitScope: EmitScope) (i: Browser.Interface)=
+ let emitPropertyFromJson (p: InputJsonType.Root) =
+ let readOnlyModifier =
+ match p.Readonly with
+ | Some(true) -> "readonly "
+ | _ -> ""
+ Pt.Printl "%s%s%s: %s;" prefix readOnlyModifier p.Name.Value p.Type.Value
+
+ let emitCommentForProperty pName =
+ match CommentJson.GetCommentForProperty i.Name pName with
+ | Some comment -> Pt.Printl "%s" comment
+ | _ -> ()
+
+ let emitProperty (p: Browser.Property) =
+ emitCommentForProperty p.Name
+
+ // Treat window.name specially because of https://github.com/Microsoft/TypeScript/issues/9850
+ if p.Name = "name" && i.Name = "Window" && emitScope = EmitScope.All then
+ Pt.Printl "declare const name: never;"
+ elif Option.isNone (getRemovedItemByName p.Name ItemKind.Property i.Name) then
+ match getOverriddenItemByName p.Name ItemKind.Property i.Name with
+ | Some p' -> emitPropertyFromJson p'
+ | None ->
+ let pType =
+ match p.Type with
+ | "EventHandler" ->
+ // Sometimes event handlers with the same name may actually handle different
+ // events in different interfaces. For example, "onerror" handles "ErrorEvent"
+ // normally, but in "SVGSVGElement" it handles "SVGError" event instead.
+ let eType =
+ if p.EventHandler.IsSome then
+ getEventTypeInInterface p.EventHandler.Value i.Name
+ else
+ "Event"
+ String.Format("({0}ev: {1}) => any", EmitEventHandlerThis flavor prefix i, eType)
+ | _ -> DomTypeToTsType p.Type
+ let pTypeAndNull = if p.Nullable.IsSome then makeNullable pType else pType
+ let readOnlyModifier = if p.ReadOnly.IsSome && prefix = "" then "readonly " else ""
+ Pt.Printl "%s%s%s: %s;" prefix readOnlyModifier p.Name pTypeAndNull
+
+ // Note: the schema file shows the property doesn't have "static" attribute,
+ // therefore all properties are emited for the instance type.
+ if emitScope <> StaticOnly then
+ match i.Properties with
+ | Some ps ->
+ ps.Properties
+ |> Array.filter (ShouldKeep flavor)
+ |> Array.iter emitProperty
+ | None -> ()
+
+ for addedItem in getAddedItems ItemKind.Property flavor do
+ if (matchInterface i.Name addedItem) && (prefix <> "declare var " || addedItem.ExposeGlobally.IsNone || addedItem.ExposeGlobally.Value) then
+ emitCommentForProperty addedItem.Name.Value
+ emitPropertyFromJson addedItem
+
+ let EmitMethods flavor prefix (emitScope: EmitScope) (i: Browser.Interface) =
+ // Note: two cases:
+ // 1. emit the members inside a interface -> no need to add prefix
+ // 2. emit the members outside to expose them (for "Window") -> need to add "declare"
+ let emitMethodFromJson (m: InputJsonType.Root) =
+ m.Signatures |> Array.iter (Pt.Printl "%s%s;" prefix)
+
+ let emitCommentForMethod (mName: string option) =
+ if mName.IsSome then
+ match CommentJson.GetCommentForMethod i.Name mName.Value with
+ | Some comment -> Pt.Printl "%s" comment
+ | _ -> ()
+
+ // If prefix is not empty, then this is the global declare function addEventListener, we want to override this
+ // Otherwise, this is EventTarget.addEventListener, we want to keep that.
+ let mFilter (m:Browser.Method) =
+ matchScope emitScope m &&
+ not (prefix <> "" && OptionCheckValue "addEventListener" m.Name)
+
+ let emitMethod flavor prefix (i:Browser.Interface) (m:Browser.Method) =
+ // print comment
+ emitCommentForMethod m.Name
+
+ // Find if there are overriding signatures in the external json file
+ // - overriddenType: meaning there is a better definition of this type in the json file
+ // - removedType: meaning the type is marked as removed in the json file
+ // if there is any conflicts between the two, the "removedType" has a higher priority over
+ // the "overridenType".
+ 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
+
+ if removedType.IsNone then
+ match overridenType with
+ | Some t ->
+ match flavor with
+ | Flavor.All | Flavor.Web -> t.WebOnlySignatures |> Array.iter (Pt.Printl "%s%s;" prefix)
+ | _ -> ()
+ t.Signatures |> Array.iter (Pt.Printl "%s%s;" prefix)
+ | None ->
+ match i.Name, m.Name with
+ | _, Some "createElement" -> EmitCreateElementOverloads m
+ | _, Some "createEvent" -> EmitCreateEventOverloads m
+ | _, Some "getElementsByTagName" -> EmitGetElementsByTagNameOverloads m
+ | _, Some "querySelector" -> EmitQuerySelectorOverloads m
+ | _, Some "querySelectorAll" -> EmitQuerySelectorAllOverloads m
+ | _ ->
+ if m.Name.IsSome then
+ // If there are added overloads from the json files, print them first
+ match getAddedItemByName m.Name.Value ItemKind.SignatureOverload i.Name with
+ | Some ol -> ol.Signatures |> Array.iter (Pt.Printl "%s")
+ | _ -> ()
+
+ let overloads = GetOverloads (Function.Method m) false
+ for { ParamCombinations = pCombList; ReturnTypes = rTypes; Nullable = isNullable } in overloads do
+ let paramsString = ParamsToString pCombList
+ let returnString =
+ let returnType = rTypes |> List.map DomTypeToTsType |> String.concat " | "
+ if isNullable then makeNullable returnType else returnType
+ Pt.Printl "%s%s(%s): %s;" prefix (if m.Name.IsSome then m.Name.Value else "") paramsString returnString
+
+ if i.Methods.IsSome then
+ i.Methods.Value.Methods
+ |> Array.filter mFilter
+ |> Array.iter (emitMethod flavor prefix i)
+
+ for addedItem in getAddedItems ItemKind.Method flavor do
+ if (matchInterface i.Name addedItem && matchScope emitScope addedItem) then
+ emitCommentForMethod addedItem.Name
+ emitMethodFromJson addedItem
+
+ // The window interface inherited some methods from "Object",
+ // which need to explicitly exposed
+ if i.Name = "Window" && prefix = "declare function " then
+ Pt.Printl "declare function toString(): string;"
+
+ /// Emit the properties and methods of a given interface
+ let EmitMembers flavor (prefix: string) (emitScope: EmitScope) (i:Browser.Interface) =
+ EmitProperties flavor prefix emitScope i
+ let methodPrefix = if prefix.StartsWith("declare var") then "declare function " else ""
+ EmitMethods flavor methodPrefix emitScope i
+
+ /// Emit all members of every interfaces at the root level.
+ /// Called only once on the global polluter object
+ let rec EmitAllMembers flavor (i:Browser.Interface) =
+ let prefix = "declare var "
+ EmitMembers flavor prefix EmitScope.All i
+
+ for relatedIName in iNameToIDependList.[i.Name] do
+ match GetInterfaceByName relatedIName with
+ | Some i' -> EmitAllMembers flavor i'
+ | _ -> ()
+
+ let EmitEventHandlers (flavor: Flavor) (prefix: string) (i:Browser.Interface) =
+ let fPrefix =
+ if prefix.StartsWith "declare var" then "declare function " else ""
+
+ let emitEventHandler prefix (i:Browser.Interface) =
+ Pt.Printl
+ "%saddEventListener(type: K, listener: (this: %s, ev: %sEventMap[K]) => any, useCapture?: boolean): void;"
+ prefix i.Name i.Name i.Name
+
+ let shouldEmitStringEventHandler =
+ if 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
+ iNameToEhParents.[i.Name]
+ |> List.sortBy (fun i -> i.Name)
+ |> List.iter (emitEventHandler fPrefix)
+ true
+ else
+ false
+
+ if shouldEmitStringEventHandler then
+ Pt.Printl
+ "%saddEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void;"
+ fPrefix
+
+ let EmitConstructorSignature (i:Browser.Interface) =
+ let emitConstructorSigFromJson (c: InputJsonType.Root) =
+ c.Signatures |> Array.iter (Pt.Printl "%s;")
+
+ let removedCtor = getRemovedItems ItemKind.Constructor Flavor.All |> Array.tryFind (matchInterface i.Name)
+ if Option.isNone removedCtor then
+ let overriddenCtor = getOverriddenItems ItemKind.Constructor Flavor.All |> Array.tryFind (matchInterface i.Name)
+ match overriddenCtor with
+ | Some c' -> emitConstructorSigFromJson c'
| _ ->
- let mTypes =
- match i.Methods with
- | Some ms ->
- ms.Methods |> Array.map (fun m' -> m'.Type) |> Array.filter (fun t -> t <> "void") |> Array.distinct
- | _ -> [||]
- let amTypes =
- match i.AnonymousMethods with
- | Some ms ->
- ms.Methods |> Array.map (fun m' -> m'.Type) |> Array.filter (fun t -> t <> "void") |> Array.distinct
- | _ -> [||]
- let pTypes =
- match i.Properties with
- | Some ps ->
- ps.Properties |> Array.map (fun m' -> m'.Type) |> Array.filter (fun t -> t <> "void") |> Array.distinct
- | _ -> [||]
-
- match mTypes, amTypes, pTypes with
- | [||], [|y|], [||] -> y = m.Type
- | [|x|], [|y|], [||] -> x = y && y = m.Type
- | [||], [|y|], [|z|] -> y = z && y = m.Type
- | [|x|], [|y|], [|z|] -> x = y && y = z && y = m.Type
- | _ -> false
+ //Emit constructor signature
+ match i.Constructor with
+ | Some ctor ->
+ for { ParamCombinations = pCombList } in GetOverloads (Ctor ctor) false do
+ let paramsString = ParamsToString pCombList
+ Pt.Printl "new(%s): %s;" paramsString i.Name
+ | _ -> Pt.Printl "new(): %s;" i.Name
+
+ getAddedItems ItemKind.Constructor Flavor.All
+ |> Array.filter (matchInterface i.Name)
+ |> Array.iter emitConstructorSigFromJson
+
+ let EmitConstructor flavor (i:Browser.Interface) =
+ Pt.Printl "declare var %s: {" i.Name
+ Pt.IncreaseIndent()
+
+ Pt.Printl "prototype: %s;" i.Name
+ EmitConstructorSignature i
+ EmitConstants i
+ let prefix = ""
+ EmitMembers flavor prefix EmitScope.StaticOnly i
- | _ -> false
- else
- false
-
-let EmitIndexers emitScope (i: Browser.Interface) =
- let emitIndexerFromJson (id: ItemsType.Root) =
- id.Signatures |> Array.iter (Pt.printl "%s;")
-
- let removedIndexer = getRemovedItems ItemKind.Indexer Flavor.All |> Array.tryFind (matchInterface i.Name)
- if removedIndexer.IsNone then
- let overriddenIndexer = getOverriddenItems ItemKind.Indexer Flavor.All |> Array.tryFind (matchInterface i.Name)
- match overriddenIndexer with
- | Some id -> emitIndexerFromJson id
- | _ ->
- // The indices could be within either Methods or Anonymous Methods
- let ms = if i.Methods.IsSome then i.Methods.Value.Methods else [||]
- let ams = if i.AnonymousMethods.IsSome then i.AnonymousMethods.Value.Methods else [||]
+ Pt.DecreaseIndent()
+ Pt.Printl "}"
+ Pt.Printl ""
+
+ /// Emit all the named constructors at root level
+ let EmitNamedConstructors () =
+ browser.Interfaces
+ |> Array.filter (fun i -> i.NamedConstructor.IsSome)
+ |> Array.iter
+ (fun i ->
+ let nc = i.NamedConstructor.Value
+ let ncParams =
+ [for p in nc.Params do
+ yield {Type = p.Type; Name = p.Name; Optional = p.Optional.IsSome; Variadic = p.Variadic.IsSome; Nullable = p.Nullable.IsSome}]
+ Pt.Printl "declare var %s: {new(%s): %s; };" nc.Name (ParamsToString ncParams) i.Name)
+
+ let EmitInterfaceDeclaration (i:Browser.Interface) =
+ Pt.Printl "interface %s" i.Name
+ let finalExtends =
+ let overridenExtendsFromJson =
+ InputJson.getOverriddenItemsByInterfaceName ItemKind.Extends Flavor.All i.Name
+ |> Array.map (fun e -> e.BaseInterface.Value) |> List.ofArray
+ if List.isEmpty overridenExtendsFromJson then
+ let extendsFromSpec =
+ match i.Extends::(List.ofArray i.Implements) with
+ | [""] | [] | ["Object"] -> []
+ | specExtends -> specExtends
+ let extendsFromJson =
+ InputJson.getAddedItemsByInterfaceName ItemKind.Extends Flavor.All i.Name
+ |> Array.map (fun e -> e.BaseInterface.Value) |> List.ofArray
+ List.concat [extendsFromSpec; extendsFromJson]
+ else
+ overridenExtendsFromJson
+ match finalExtends with
+ | [] -> ()
+ | allExtends -> Pt.Print " extends %s" (String.Join(", ", allExtends))
+ Pt.Print " {"
+
+ /// To decide if a given method is an indexer and should be emited
+ let ShouldEmitIndexerSignature (i: Browser.Interface) (m: Browser.Method) =
+ if m.Getter.IsSome && m.Params.Length = 1 then
+ // TypeScript array indexer can only be number or string
+ // for string, it must return a more generic type then all
+ // the other properties, following the Dictionary pattern
+ match DomTypeToTsType m.Params.[0].Type with
+ | "number" -> true
+ | "string" ->
+ match DomTypeToTsType m.Type with
+ | "any" -> true
+ | _ ->
+ let mTypes =
+ match i.Methods with
+ | Some ms ->
+ ms.Methods |> Array.map (fun m' -> m'.Type) |> Array.filter (fun t -> t <> "void") |> Array.distinct
+ | _ -> [||]
+ let amTypes =
+ match i.AnonymousMethods with
+ | Some ms ->
+ ms.Methods |> Array.map (fun m' -> m'.Type) |> Array.filter (fun t -> t <> "void") |> Array.distinct
+ | _ -> [||]
+ let pTypes =
+ match i.Properties with
+ | Some ps ->
+ ps.Properties |> Array.map (fun m' -> m'.Type) |> Array.filter (fun t -> t <> "void") |> Array.distinct
+ | _ -> [||]
+
+ match mTypes, amTypes, pTypes with
+ | [||], [|y|], [||] -> y = m.Type
+ | [|x|], [|y|], [||] -> x = y && y = m.Type
+ | [||], [|y|], [|z|] -> y = z && y = m.Type
+ | [|x|], [|y|], [|z|] -> x = y && y = z && y = m.Type
+ | _ -> false
+
+ | _ -> false
+ else
+ false
- Array.concat [|ms; ams|]
- |> Array.filter (fun m -> ShouldEmitIndexerSignature i m && matchScope emitScope m)
- |> Array.iter (fun m ->
- let indexer = m.Params.[0]
- Pt.printl "[%s: %s]: %s;"
- indexer.Name
- (DomTypeToTsType indexer.Type)
- (DomTypeToTsType m.Type))
-
- getAddedItems ItemKind.Indexer Flavor.All
- |> Array.filter (matchInterface i.Name)
- |> Array.iter emitIndexerFromJson
-
-let EmitInterfaceEventMap flavor (i:Browser.Interface) =
- let EmitInterfaceEventMapEntry (eHandler: EventHandler) =
- let eventType =
- getEventTypeInInterface eHandler.EventName i.Name
- Pt.printl "\"%s\": %s;" eHandler.EventName eventType
-
- let ownEventHandles = if iNameToEhList.ContainsKey i.Name && not iNameToEhList.[i.Name].IsEmpty then iNameToEhList.[i.Name] else []
- if ownEventHandles.Length > 0 then
- Pt.printl "interface %sEventMap" i.Name
- if iNameToEhParents.ContainsKey i.Name && not iNameToEhParents.[i.Name].IsEmpty then
- let extends = iNameToEhParents.[i.Name] |> List.map (fun i -> i.Name + "EventMap")
- Pt.print " extends %s" (String.Join(", ", extends))
- Pt.print " {"
- Pt.increaseIndent()
- ownEventHandles |> List.iter EmitInterfaceEventMapEntry
- Pt.decreaseIndent()
- Pt.printl "}"
- Pt.printl ""
-let EmitInterface flavor (i:Browser.Interface) =
- EmitInterfaceEventMap flavor i
-
- Pt.resetIndent()
- EmitInterfaceDeclaration i
- Pt.increaseIndent()
-
- let prefix = ""
- EmitMembers flavor prefix EmitScope.InstanceOnly i
- EmitConstants i
- EmitEventHandlers flavor prefix i
- EmitIndexers EmitScope.InstanceOnly i
-
- Pt.decreaseIndent()
- Pt.printl "}"
- Pt.printl ""
-
-let EmitStaticInterface flavor (i:Browser.Interface) =
- // Some types are static types with non-static members. For example,
- // NodeFilter is a static method itself, however it has an "acceptNode" method
- // that expects the user to implement.
- let hasNonStaticMember =
- let hasNonStaticMethod =
- let hasOwnNonStaticMethod =
- i.Methods.IsSome &&
- i.Methods.Value.Methods
- |> Array.filter (fun m -> m.Name.IsNone || (findRemovedItem m.Name.Value ItemKind.Method i.Name) |> Option.isNone)
- |> Array.exists (fun m -> m.Static.IsNone)
- let hasAddedNonStaticMethod =
- match JsonItems.getAddedItemsByInterfaceName ItemKind.Method flavor i.Name with
- | [||] -> false
- | addedMs -> addedMs |> Array.exists (fun m -> m.Static.IsNone || m.Static.Value = false)
- hasOwnNonStaticMethod || hasAddedNonStaticMethod
- let hasProperty =
- let hasOwnNonStaticProperty =
- i.Properties.IsSome &&
- i.Properties.Value.Properties
- |> Array.filter (fun p -> findRemovedItem p.Name ItemKind.Method i.Name |> Option.isNone)
- |> Array.isEmpty |> not
- let hasAddedNonStaticMethod =
- match JsonItems.getAddedItemsByInterfaceName ItemKind.Property flavor i.Name with
- | [||] -> false
- | addedPs -> addedPs |> Array.exists (fun p -> p.Static.IsNone || p.Static.Value = false)
- hasOwnNonStaticProperty || hasAddedNonStaticMethod
- hasNonStaticMethod || hasProperty
-
- let emitAddedConstructor () =
- match JsonItems.getAddedItemsByInterfaceName ItemKind.Constructor flavor i.Name with
- | [||] -> ()
- | ctors ->
- Pt.printl "prototype: %s;" i.Name
- ctors |> Array.iter (fun ctor -> ctor.Signatures |> Array.iter (Pt.printl "%s;"))
-
- // For static types with non-static members, we put the non-static members into an
- // interface, and put the static members into the object literal type of 'declare var'
- // For static types with only static members, we put everything in the interface.
- // Because in the two cases the interface contains different things, it might be easier to
- // read to separate them into two functions.
- let emitStaticInterfaceWithNonStaticMembers () =
- Pt.resetIndent()
+ let EmitIndexers emitScope (i: Browser.Interface) =
+ let emitIndexerFromJson (id: InputJsonType.Root) =
+ id.Signatures |> Array.iter (Pt.Printl "%s;")
+
+ let removedIndexer = getRemovedItems ItemKind.Indexer Flavor.All |> Array.tryFind (matchInterface i.Name)
+ if removedIndexer.IsNone then
+ let overriddenIndexer = getOverriddenItems ItemKind.Indexer Flavor.All |> Array.tryFind (matchInterface i.Name)
+ match overriddenIndexer with
+ | Some id -> emitIndexerFromJson id
+ | _ ->
+ // The indices could be within either Methods or Anonymous Methods
+ let ms = if i.Methods.IsSome then i.Methods.Value.Methods else [||]
+ let ams = if i.AnonymousMethods.IsSome then i.AnonymousMethods.Value.Methods else [||]
+
+ Array.concat [|ms; ams|]
+ |> Array.filter (fun m -> ShouldEmitIndexerSignature i m && matchScope emitScope m)
+ |> Array.iter (fun m ->
+ let indexer = m.Params.[0]
+ Pt.Printl "[%s: %s]: %s;"
+ indexer.Name
+ (DomTypeToTsType indexer.Type)
+ (DomTypeToTsType m.Type))
+
+ getAddedItems ItemKind.Indexer Flavor.All
+ |> Array.filter (matchInterface i.Name)
+ |> Array.iter emitIndexerFromJson
+
+ let EmitInterfaceEventMap flavor (i:Browser.Interface) =
+ let emitInterfaceEventMapEntry (eHandler: EventHandler) =
+ let eventType =
+ getEventTypeInInterface eHandler.EventName i.Name
+ Pt.Printl "\"%s\": %s;" eHandler.EventName eventType
+
+ let ownEventHandles = if iNameToEhList.ContainsKey i.Name && not iNameToEhList.[i.Name].IsEmpty then iNameToEhList.[i.Name] else []
+ if ownEventHandles.Length > 0 then
+ Pt.Printl "interface %sEventMap" i.Name
+ if iNameToEhParents.ContainsKey i.Name && not iNameToEhParents.[i.Name].IsEmpty then
+ let extends = iNameToEhParents.[i.Name] |> List.map (fun i -> i.Name + "EventMap")
+ Pt.Print " extends %s" (String.Join(", ", extends))
+ Pt.Print " {"
+ Pt.IncreaseIndent()
+ ownEventHandles |> List.iter emitInterfaceEventMapEntry
+ Pt.DecreaseIndent()
+ Pt.Printl "}"
+ Pt.Printl ""
+
+ let EmitInterface flavor (i:Browser.Interface) =
+ EmitInterfaceEventMap flavor i
+
+ Pt.ResetIndent()
EmitInterfaceDeclaration i
- Pt.increaseIndent()
+ Pt.IncreaseIndent()
let prefix = ""
EmitMembers flavor prefix EmitScope.InstanceOnly i
+ EmitConstants i
EmitEventHandlers flavor prefix i
EmitIndexers EmitScope.InstanceOnly i
- Pt.decreaseIndent()
- Pt.printl "}"
- Pt.printl ""
- Pt.printl "declare var %s: {" i.Name
- Pt.increaseIndent()
- EmitConstants i
- EmitMembers flavor prefix EmitScope.StaticOnly i
- emitAddedConstructor ()
- Pt.decreaseIndent()
- Pt.printl "}"
- Pt.printl ""
+ Pt.DecreaseIndent()
+ Pt.Printl "}"
+ Pt.Printl ""
+
+ let EmitStaticInterface flavor (i:Browser.Interface) =
+ // Some types are static types with non-static members. For example,
+ // NodeFilter is a static method itself, however it has an "acceptNode" method
+ // that expects the user to implement.
+ let hasNonStaticMember =
+ let hasNonStaticMethod =
+ let hasOwnNonStaticMethod =
+ i.Methods.IsSome &&
+ i.Methods.Value.Methods
+ |> Array.exists (fun m -> m.Static.IsNone && (m.Name.IsNone || (getRemovedItemByName m.Name.Value ItemKind.Method i.Name) |> Option.isNone))
+ let hasAddedNonStaticMethod =
+ match InputJson.getAddedItemsByInterfaceName ItemKind.Method flavor i.Name with
+ | [||] -> false
+ | addedMs -> addedMs |> Array.exists (fun m -> m.Static.IsNone || not m.Static.Value)
+ hasOwnNonStaticMethod || hasAddedNonStaticMethod
+ let hasProperty =
+ let hasOwnNonStaticProperty =
+ i.Properties.IsSome &&
+ i.Properties.Value.Properties
+ |> Array.exists (fun p -> getRemovedItemByName p.Name ItemKind.Method i.Name |> Option.isNone)
+ let hasAddedNonStaticMethod =
+ match InputJson.getAddedItemsByInterfaceName ItemKind.Property flavor i.Name with
+ | [||] -> false
+ | addedPs -> addedPs |> Array.exists (fun p -> p.Static.IsNone || not p.Static.Value)
+ hasOwnNonStaticProperty || hasAddedNonStaticMethod
+ hasNonStaticMethod || hasProperty
+
+ let emitAddedConstructor () =
+ match InputJson.getAddedItemsByInterfaceName ItemKind.Constructor flavor i.Name with
+ | [||] -> ()
+ | ctors ->
+ Pt.Printl "prototype: %s;" i.Name
+ ctors |> Array.iter (fun ctor -> ctor.Signatures |> Array.iter (Pt.Printl "%s;"))
+
+ // For static types with non-static members, we put the non-static members into an
+ // interface, and put the static members into the object literal type of 'declare var'
+ // For static types with only static members, we put everything in the interface.
+ // Because in the two cases the interface contains different things, it might be easier to
+ // read to separate them into two functions.
+ let emitStaticInterfaceWithNonStaticMembers () =
+ Pt.ResetIndent()
+ EmitInterfaceDeclaration i
+ Pt.IncreaseIndent()
+
+ let prefix = ""
+ EmitMembers flavor prefix EmitScope.InstanceOnly i
+ EmitEventHandlers flavor prefix i
+ EmitIndexers EmitScope.InstanceOnly i
+
+ Pt.DecreaseIndent()
+ Pt.Printl "}"
+ Pt.Printl ""
+ Pt.Printl "declare var %s: {" i.Name
+ Pt.IncreaseIndent()
+ EmitConstants i
+ EmitMembers flavor prefix EmitScope.StaticOnly i
+ emitAddedConstructor ()
+ Pt.DecreaseIndent()
+ Pt.Printl "}"
+ Pt.Printl ""
+
+ let emitPureStaticInterface () =
+ Pt.ResetIndent()
+ EmitInterfaceDeclaration i
+ Pt.IncreaseIndent()
+
+ let prefix = ""
+ EmitMembers flavor prefix EmitScope.StaticOnly i
+ EmitConstants i
+ EmitEventHandlers flavor prefix i
+ EmitIndexers EmitScope.StaticOnly i
+ emitAddedConstructor ()
+ Pt.DecreaseIndent()
+ Pt.Printl "}"
+ Pt.Printl "declare var %s: %s;" i.Name i.Name
+ Pt.Printl ""
+
+ if hasNonStaticMember then emitStaticInterfaceWithNonStaticMembers() else emitPureStaticInterface()
+
+ let EmitNonCallbackInterfaces flavor =
+ for i in GetNonCallbackInterfacesByFlavor flavor do
+ // If the static attribute has a value, it means the type doesn't have a constructor
+ if i.Static.IsSome then
+ EmitStaticInterface flavor i
+ elif i.NoInterfaceObject.IsSome then
+ EmitInterface flavor i
+ else
+ EmitInterface flavor i
+ EmitConstructor flavor i
+
+ let EmitDictionaries flavor =
+ let emitDictionary (dict:Browser.Dictionary) =
+ match dict.Extends with
+ | "Object" -> Pt.Printl "interface %s {" dict.Name
+ | _ -> Pt.Printl "interface %s extends %s {" dict.Name dict.Extends
+
+ let emitJsonProperty (p: InputJsonType.Root) =
+ Pt.Printl "%s: %s;" p.Name.Value p.Type.Value
+
+ let removedPropNames =
+ getRemovedItems ItemKind.Property flavor
+ |> Array.choose (fun rp -> if matchInterface dict.Name rp then Some(rp.Name.Value) else None)
+ |> Set.ofArray
+ let addedProps =
+ getAddedItems ItemKind.Property flavor
+ |> Array.filter (matchInterface dict.Name)
+
+ Pt.IncreaseIndent()
+ Array.iter emitJsonProperty addedProps
+ dict.Members
+ |> Array.filter (fun m -> not (Set.contains m.Name removedPropNames))
+ |> Array.iter (fun m ->
+ match (getOverriddenItemByName m.Name ItemKind.Property dict.Name) with
+ | Some om -> emitJsonProperty om
+ | None -> Pt.Printl "%s?: %s;" m.Name (DomTypeToTsType m.Type))
+ Pt.DecreaseIndent()
+ Pt.Printl "}"
+ Pt.Printl ""
+
+ browser.Dictionaries
+ |> Array.filter (fun dict -> flavor <> Worker || knownWorkerInterfaces.Contains dict.Name)
+ |> Array.iter emitDictionary
+
+ let EmitAddedInterface (ai: InputJsonType.Root) =
+ match ai.Extends with
+ | Some e -> Pt.Printl "interface %s extends %s {" ai.Name.Value ai.Extends.Value
+ | None -> Pt.Printl "interface %s {" ai.Name.Value
+
+ let emitProperty (p: InputJsonType.Property) =
+ let readOnlyModifier =
+ match p.Readonly with
+ | Some(true) -> "readonly "
+ | _ -> ""
+ match CommentJson.GetCommentForProperty ai.Name.Value p.Name with
+ | Some comment -> Pt.PrintWithAddedIndent "%s" comment
+ | _ -> ()
+ Pt.PrintWithAddedIndent "%s%s: %s;" readOnlyModifier p.Name p.Type
- let emitPureStaticInterface () =
- Pt.resetIndent()
- EmitInterfaceDeclaration i
- Pt.increaseIndent()
+ let emitMethod (m: InputJsonType.Method) =
+ match CommentJson.GetCommentForMethod ai.Name.Value m.Name with
+ | Some comment -> Pt.PrintWithAddedIndent "%s" comment
+ | _ -> ()
+ m.Signatures |> Array.iter (Pt.PrintWithAddedIndent "%s;")
- let prefix = ""
- EmitMembers flavor prefix EmitScope.StaticOnly i
- EmitConstants i
- EmitEventHandlers flavor prefix i
- EmitIndexers EmitScope.StaticOnly i
- emitAddedConstructor ()
- Pt.decreaseIndent()
- Pt.printl "}"
- Pt.printl "declare var %s: %s;" i.Name i.Name
- Pt.printl ""
-
- if hasNonStaticMember then emitStaticInterfaceWithNonStaticMembers() else emitPureStaticInterface()
-
-let EmitNonCallbackInterfaces flavor =
- for i in GetNonCallbackInterfacesByFlavor flavor do
- // If the static attribute has a value, it means the type doesn't have a constructor
- if i.Static.IsSome then
- EmitStaticInterface flavor i
- elif i.NoInterfaceObject.IsSome then
- EmitInterface flavor i
- else
- EmitInterface flavor i
- EmitConstructor flavor i
-
-let EmitDictionaries flavor =
- let emitDictionary (dict:Browser.Dictionary) =
- match dict.Extends with
- | "Object" -> Pt.printl "interface %s {" dict.Name
- | _ -> Pt.printl "interface %s extends %s {" dict.Name dict.Extends
-
- let emitJsonProperty (p: ItemsType.Root) =
- Pt.printl "%s: %s;" p.Name.Value p.Type.Value
-
- let removedPropNames =
- getRemovedItems ItemKind.Property flavor
- |> Array.filter (matchInterface dict.Name)
- |> Array.map (fun rp -> rp.Name.Value)
- |> Set.ofArray
- let addedProps =
- getAddedItems ItemKind.Property flavor
- |> Array.filter (matchInterface dict.Name)
-
- Pt.increaseIndent()
- Array.iter emitJsonProperty addedProps
- dict.Members
- |> Array.filter (fun m -> not (Set.contains m.Name removedPropNames))
- |> Array.iter (fun m ->
- match (findOverriddenItem m.Name ItemKind.Property dict.Name) with
- | Some om -> emitJsonProperty om
- | None -> Pt.printl "%s?: %s;" m.Name (DomTypeToTsType m.Type))
- Pt.decreaseIndent()
- Pt.printl "}"
- Pt.printl ""
-
- browser.Dictionaries
- |> Array.filter (fun dict -> flavor <> Worker || knownWorkerInterfaces.Contains dict.Name)
- |> Array.iter emitDictionary
-
-let EmitAddedInterface (ai: JsonItems.ItemsType.Root) =
- match ai.Extends with
- | Some e -> Pt.printl "interface %s extends %s {" ai.Name.Value ai.Extends.Value
- | None -> Pt.printl "interface %s {" ai.Name.Value
-
- for p in ai.Properties do
- let readOnlyModifier =
- match p.Readonly with
- | Some(true) -> "readonly "
- | _ -> ""
- Pt.printWithAddedIndent "%s%s: %s;" readOnlyModifier p.Name p.Type
-
- ai.Methods |> Array.collect (fun m -> m.Signatures) |> Array.iter (Pt.printWithAddedIndent "%s;")
- ai.Indexer |> Array.collect (fun i -> i.Signatures) |> Array.iter (Pt.printWithAddedIndent "%s;")
- Pt.printl "}"
- Pt.printl ""
-
- if ai.ConstructorSignatures.Length > 0 then
- Pt.printl "declare var %s: {" ai.Name.Value
- Pt.printWithAddedIndent "prototype: %s;" ai.Name.Value
- ai.ConstructorSignatures |> Array.iter (Pt.printWithAddedIndent "%s;")
- Pt.printl "}"
- Pt.printl ""
-
-let EmitTypeDefs flavor =
- let EmitTypeDef (typeDef: Browser.Typedef) =
- Pt.printl "type %s = %s;" typeDef.NewType (DomTypeToTsType typeDef.Type)
- let EmitTypeDefFromJson (typeDef: ItemsType.Root) =
- Pt.printl "type %s = %s;" typeDef.Name.Value typeDef.Type.Value
-
- match flavor with
- | Flavor.Worker ->
- browser.Typedefs |> Array.filter (fun typedef -> knownWorkerInterfaces.Contains typedef.NewType) |> Array.iter EmitTypeDef
- | _ ->
- browser.Typedefs |> Array.iter EmitTypeDef
-
- JsonItems.getAddedItems ItemKind.TypeDef flavor
- |> Array.iter EmitTypeDefFromJson
-
-let EmitTheWholeThing flavor (target:TextWriter) =
- Pt.reset()
- Pt.printl "/////////////////////////////"
- match flavor with
- | Worker -> Pt.printl "/// IE Worker APIs"
- | _ -> Pt.printl "/// IE DOM APIs"
- Pt.printl "/////////////////////////////"
- Pt.printl ""
-
- EmitDictionaries flavor
- EmitCallBackInterface browser.CallbackInterfaces.Interface
- EmitNonCallbackInterfaces flavor
-
- // Add missed interface definition from the spec
- JsonItems.getAddedItems JsonItems.Interface flavor |> Array.iter EmitAddedInterface
-
- Pt.printl "declare type EventListenerOrEventListenerObject = EventListener | EventListenerObject;"
- Pt.printl ""
-
- EmitCallBackFunctions flavor
-
- if flavor <> Worker then
- EmitHTMLElementTagNameMap()
- EmitElementTagNameMap()
- EmitElementListTagNameMap()
- EmitNamedConstructors()
-
- match GetGlobalPollutor flavor with
- | Some gp ->
- EmitAllMembers flavor gp
- EmitEventHandlers flavor "declare var " gp
- | _ -> ()
-
- EmitTypeDefs flavor
-
- fprintf target "%s" (Pt.getResult())
- target.Flush()
- target.Close()
-
-let EmitDomWeb () =
- EmitTheWholeThing Flavor.All GlobalVars.tsWebOutput
-
-let EmitDomWorker () =
- ignoreDOMTypes <- true
- EmitTheWholeThing Flavor.Worker GlobalVars.tsWorkerOutput
+
+ ai.Properties |> Array.iter emitProperty
+ ai.Methods |> Array.iter emitMethod
+ ai.Indexer |> Array.collect (fun i -> i.Signatures) |> Array.iter (Pt.PrintWithAddedIndent "%s;")
+ Pt.Printl "}"
+ Pt.Printl ""
+
+ if ai.ConstructorSignatures.Length > 0 then
+ Pt.Printl "declare var %s: {" ai.Name.Value
+ Pt.PrintWithAddedIndent "prototype: %s;" ai.Name.Value
+ match CommentJson.GetCommentForConstructor ai.Name.Value with
+ | Some comment -> Pt.PrintWithAddedIndent "%s" comment
+ | _ -> ()
+ ai.ConstructorSignatures |> Array.iter (Pt.PrintWithAddedIndent "%s;")
+ Pt.Printl "}"
+ Pt.Printl ""
+
+ let EmitTypeDefs flavor =
+ let emitTypeDef (typeDef: Browser.Typedef) =
+ Pt.Printl "type %s = %s;" typeDef.NewType (DomTypeToTsType typeDef.Type)
+ let emitTypeDefFromJson (typeDef: InputJsonType.Root) =
+ Pt.Printl "type %s = %s;" typeDef.Name.Value typeDef.Type.Value
+
+ match flavor with
+ | Flavor.Worker ->
+ browser.Typedefs
+ |> Array.filter (fun typedef -> knownWorkerInterfaces.Contains typedef.NewType)
+ |> Array.iter emitTypeDef
+ | _ ->
+ browser.Typedefs
+ |> Array.iter emitTypeDef
+
+ InputJson.getAddedItems ItemKind.TypeDef flavor
+ |> Array.iter emitTypeDefFromJson
+
+ let EmitTheWholeThing flavor (target:TextWriter) =
+ Pt.Reset()
+ Pt.Printl "/////////////////////////////"
+ match flavor with
+ | Worker -> Pt.Printl "/// IE Worker APIs"
+ | _ -> Pt.Printl "/// IE DOM APIs"
+ Pt.Printl "/////////////////////////////"
+ Pt.Printl ""
+
+ EmitDictionaries flavor
+ EmitCallBackInterface browser.CallbackInterfaces.Interface
+ EmitNonCallbackInterfaces flavor
+
+ // Add missed interface definition from the spec
+ InputJson.getAddedItems InputJson.Interface flavor |> Array.iter EmitAddedInterface
+
+ Pt.Printl "declare type EventListenerOrEventListenerObject = EventListener | EventListenerObject;"
+ Pt.Printl ""
+
+ EmitCallBackFunctions flavor
+
+ if flavor <> Worker then
+ EmitHTMLElementTagNameMap()
+ EmitElementTagNameMap()
+ EmitElementListTagNameMap()
+ EmitNamedConstructors()
+
+ match GetGlobalPollutor flavor with
+ | Some gp ->
+ EmitAllMembers flavor gp
+ EmitEventHandlers flavor "declare var " gp
+ | _ -> ()
+
+ EmitTypeDefs flavor
+
+ fprintf target "%s" (Pt.GetResult())
+ target.Flush()
+ target.Close()
+
+ let EmitDomWeb () =
+ EmitTheWholeThing Flavor.All GlobalVars.tsWebOutput
+
+ let EmitDomWorker () =
+ ignoreDOMTypes <- true
+ EmitTheWholeThing Flavor.Worker GlobalVars.tsWorkerOutput
diff --git a/baselines/dom.generated.d.ts b/baselines/dom.generated.d.ts
index 16bc6d9e6..cb3a94a17 100644
--- a/baselines/dom.generated.d.ts
+++ b/baselines/dom.generated.d.ts
@@ -12732,16 +12732,37 @@ interface Canvas2DContextAttributes {
}
interface URLSearchParams {
+ /**
+ * Appends a specified key/value pair as a new search parameter.
+ */
append(name: string, value: string): void;
+ /**
+ * Deletes the given search parameter, and its associated value, from the list of all search parameters.
+ */
delete(name: string): void;
+ /**
+ * Returns the first value associated to the given search parameter.
+ */
get(name: string): string | null;
+ /**
+ * Returns all the values association with a given search parameter.
+ */
getAll(name: string): string[];
+ /**
+ * Returns a Boolean indicating if such a search parameter exists.
+ */
has(name: string): boolean;
+ /**
+ * Sets the value associated to a given search parameter to the given value. If there were several values, delete the others.
+ */
set(name: string, value: string): void;
}
declare var URLSearchParams: {
prototype: URLSearchParams;
+ /**
+ * Constructor returning a URLSearchParams object.
+ */
new (init?: string | URLSearchParams): URLSearchParams;
}
diff --git a/build.fsx b/build.fsx
index 98f3e6e1a..7e46ca1c3 100644
--- a/build.fsx
+++ b/build.fsx
@@ -1,16 +1,14 @@
#r "packages/FAKE/tools/FakeLib.dll"
-#load "Shared.fsx"
#load "TS.fsx"
open Fake
-open TS
+open TS.Emit
open System
open System.IO
Target "Run" (fun _ ->
- // For typescript only generate for Dom
- TS.EmitDomWeb()
- TS.EmitDomWorker()
+ TS.Emit.EmitDomWeb()
+ TS.Emit.EmitDomWorker()
)
let testFile file =
diff --git a/inputfiles/comments.json b/inputfiles/comments.json
index 8346aea1d..a004c8dba 100644
--- a/inputfiles/comments.json
+++ b/inputfiles/comments.json
@@ -3043,6 +3043,39 @@
],
"method": []
}
+ },
+ {
+ "name": "URLSearchParams",
+ "members": {
+ "method": [
+ {
+ "name": "append",
+ "comment": "/**\r\n * Appends a specified key/value pair as a new search parameter.\r\n */"
+ },
+ {
+ "name": "delete",
+ "comment": "/**\r\n * Deletes the given search parameter, and its associated value, from the list of all search parameters.\r\n */"
+ },
+ {
+ "name": "get",
+ "comment": "/**\r\n * Returns the first value associated to the given search parameter.\r\n */"
+ },
+ {
+ "name": "getAll",
+ "comment": "/**\r\n * Returns all the values association with a given search parameter.\r\n */"
+ },
+ {
+ "name": "has",
+ "comment": "/**\r\n * Returns a Boolean indicating if such a search parameter exists.\r\n */"
+ },
+ {
+ "name": "set",
+ "comment": "/**\r\n * Sets the value associated to a given search parameter to the given value. If there were several values, delete the others.\r\n */"
+ }
+ ],
+ "property": [],
+ "constructor": "/**\r\n * Constructor returning a URLSearchParams object.\r\n */"
+ }
}
]
}
\ No newline at end of file
diff --git a/inputfiles/jsTemplate.js b/inputfiles/jsTemplate.js
deleted file mode 100644
index 04fbaefc5..000000000
--- a/inputfiles/jsTemplate.js
+++ /dev/null
@@ -1,744 +0,0 @@
-var document = { };
-(function () {
- var _eventManager = _$createEventManager(
- function getEventObject(type, attach, obj, ignoreCase) {
- function _eventTypeToObject(type, attach) {
- if (attach) return Event;
- <@ EventTypeToObjSwitchStatements @>
- return Event;
- }
- function _eventTypeToObjectIgnoreCase(type, attach) {
- if (attach) return Event;
- type = type.toLowerCase();
- <@ EventTypeToObjSwitchStatementsIgnoreCase @>
- return Event;
- }
- var e = ignoreCase ? _eventTypeToObjectIgnoreCase(type, attach) : _eventTypeToObject(type, attach);
- var eventObject = Object.create(e);
- eventObject.target = obj;
- eventObject.currentTarget = obj;
- eventObject.type = type;
- if (eventObject.relatedTarget)
- eventObject.relatedTarget = obj;
- return eventObject;
- });
- var _events = _eventManager.createEventProperties;
-
-
- function _createEvent(eventType) {
- function _eventTypeToObject(eventType) {
- if (eventType && typeof eventType === 'string') {
- <@ CreateEventSwitchStatements @>
- }
- }
- var e = _eventTypeToObject(eventType);
- if (!e) e = Event;
- return Object.create(e);
- }
-
- function _getElementByTagName(tagName) {
- if (typeof tagName !== 'string') return;
- <@ GetElementsByTagNameSwitchStatements @>
- }
-
- function _getNewElementByTagName(tagName) {
- if (typeof tagName !== 'string') return;
- var element = Object.create(_getElementByTagName(tagName));
- element.localName = tagName;
- element.tagName = element.nodeName = tagName.toUpperCase();
- return element;
- }
-
- function _createDomObject(name) {
- return Window[name] && Window[name].prototype && Object.create(Window[name].prototype);
- }
-
- function _isAsyncScript(object) {
- return object && HTMLScriptElement.isPrototypeOf(object);
- }
-
- function _createElementByTagName(tagName) {
- if (typeof tagName !== 'string') return;
- var element = _getNewElementByTagName(tagName);
- element._$searchable = true;
- return element;
- }
-
- function _wrapInList(list, resultListType, missingValueType, outputList) {
- var nodeList = typeof outputList !== 'undefined' ? outputList : Object.create(resultListType);
- var originalOutputListLength = typeof outputList !== 'undefined' ? outputList.length : 0;
- if (list) {
- for (var i = 0; i< list.length; i++) {
- nodeList[i] = list[i];
- }
- // clear any remaining items in outputList
- for (var i = list.length; i< originalOutputListLength; i++) {
- nodeList[i] = undefined;
- }
- nodeList.length = list.length;
- }
- if (missingValueType && nodeList.length === 0)
- nodeList[0] = _$getTrackingUndefined(missingValueType);
- return nodeList;
- }
-
- function _createHTMLCollection(elementType) {
- var result = Object.create(HTMLCollection);
- result[0] = _$getTrackingNull(_createElementByTagName(elementType));
- return result;
- }
-
- var _defaultScripts = [];
-
- function _scriptInDefaultList(scriptElement) {
- var found = false;
- if (scriptElement && scriptElement.src && _defaultScripts && _defaultScripts.length > 0) {
- _defaultScripts.forEach(function (entry) {
- if (scriptElement.src == entry.src)
- found = true;
- });
- }
- return found;
- }
-
- function _getElementsByTagName(source, tagName) {
- var result = [];
- if (typeof tagName === 'string') {
- tagName = tagName.toLowerCase();
- if (source && source._$searchable)
- return _findElementsByTagName(source, tagName);
- else if (tagName === 'script') {
- if (_defaultScripts.length > 0)
- result = _$asyncRequests.getItems().length == 1 ? _defaultScripts : _defaultScripts.concat(_$asyncRequests.getItems());
- else
- result = _$asyncRequests.getItems();
- }
- else
- result = [ _getNewElementByTagName(tagName) ];
- }
- return _wrapInList(result, NodeList, _getNewElementByTagName(tagName));
- }
-
- function _findElementsByTagName(source, tagName, outputList) {
- var elements = [];
- _visitChildNodes(source, function(e) {
- if (_isElement(e) && ('*' == tagName || e.tagName.toLowerCase() == tagName)) elements.push(e);
- });
- var result = _wrapInList(elements, NodeList, _getNewElementByTagName(tagName), outputList);
- if (typeof outputList === 'undefined') {
- if (typeof source._$queries === 'undefined')
- source._$queries = [];
- source._$queries.push({queryString: tagName, result: result});
- }
- return result;
- }
-
- function _visitChildNodes(start, callback) {
- if (_isNode(start) && _hasChildNodes(start)) {
- var q = [];
- q = q.concat(_childNodeList(start));
- var c = 0;
- while (q.length > 0 && c++ < 1000) {
- var e = q.shift();
- if (_isNode(e)) {
- callback(e);
- if (_hasChildNodes(e)) q = q.concat(_childNodeList(e));
- }
- }
- }
- }
-
- function _refreshQueries(node){
- if (_isNode(node)){
- if (node._$queries)
- for(var i =0; i < node._$queries.length; i++)
- _findElementsByTagName(node, node._$queries[i].queryString, node._$queries[i].result);
- // referesh the parent queries
- _refreshQueries(node.parentNode);
- }
- }
-
- function _embedAsyncRequest(originalObject, asyncRequest) {
- if (originalObject) {
- var newObject = Object.create(originalObject);
- _$defineProperty(newObject, '_$asyncRequest', asyncRequest);
- return newObject;
- }
- return originalObject;
- }
-
- function _getEmbeddedAsyncRequest(obj) {
- return (obj && obj._$asyncRequest) ? obj._$asyncRequest : obj;
- }
-
- function _isNode(n) {
- return typeof n !== 'undefined' && n && Node.isPrototypeOf(n);
- }
-
- function _isElement(e) {
- return typeof e !== 'undefined' && e && Element.isPrototypeOf(e);
- }
-
- function _getMatchingNull(obj) {
- return _$getTrackingNull(Object.create(_isElement(obj) ? HTMLElement : Node));
- }
-
- function _isParentOf(parent, obj) {
- if (obj) {
- var cur = obj.parentNode;
- while (cur) {
- if (cur == parent)
- return true;
- cur = cur.parentNode;
- }
- }
- return false;
- }
-
- function _childNodes(obj, resultListType) {
- if (typeof obj._$children === 'undefined')
- obj._$children = Object.create(resultListType);
- return obj._$children;
- }
-
- function _childNodeList(obj) {
- return typeof obj._$children !== 'undefined'? Array.prototype.slice.call(obj._$children) : [];
- }
-
- function _hasChildNodes(obj) {
- return typeof obj._$children !== 'undefined' && obj._$children.length > 0;
- }
-
- function _firstChild(obj, defaultObj) {
- return _hasChildNodes(obj) ? obj._$children[0] : _$getTrackingNull(Object.create(_isElement(obj) ? HTMLElement : defaultObj));
- }
-
- function _lastChild(obj, defaultObj) {
- return _hasChildNodes(obj) ? obj._$children[obj._$children.length - 1] : _$getTrackingNull(Object.create(_isElement(obj) ? HTMLElement : defaultObj));
- }
-
- function _clearElement(obj) {
- if (_hasChildNodes(obj)) {
- for (var i = 0; i < obj._$children.length; i++)
- obj._$children[i].parentNode = obj._$children[i].nextSibling = obj._$children[i].previousSibling = _getMatchingNull(obj._$children[i]);
- obj._$children = undefined;
- _refreshQueries(obj);
- }
- }
-
- function _removeChild(obj, oldChild) {
- if (_isNode(oldChild) && _hasChildNodes(obj)) {
- for (var i = 0; i < obj._$children.length; i++) {
- if (oldChild == obj._$children[i]) {
- if (oldChild.previousSibling) {
- oldChild.previousSibling.nextSibling = oldChild.nextSibling;
- }
- if (oldChild.nextSibling) {
- oldChild.nextSibling.previousSibling = oldChild.previousSibling;
- }
- Array.prototype.splice.call(obj._$children, i, 1);
- oldChild.parentNode = oldChild.nextSibling = oldChild.previousSibling = _getMatchingNull(obj);
- _refreshQueries(obj);
- break;
- }
- }
- }
- return oldChild;
- }
-
- function _appendChildInternal(obj, newChild) {
- if (_isNode(newChild) && obj != newChild && !_isParentOf(newChild, obj)) {
- if (newChild.parentNode)
- _removeChild(newChild.parentNode, newChild);
- if (typeof obj._$children === 'undefined')
- obj._$children = Object.create(NodeList);
- var previousSibling = obj._$children.length >= 1 ? obj._$children[obj._$children.length - 1] : null;
- Array.prototype.push.call(obj._$children, newChild);
- newChild.parentNode = obj;
- if (previousSibling) {
- newChild.previousSibling = previousSibling;
- previousSibling.nextSibling = newChild;
- }
- _refreshQueries(obj);
- }
- return newChild;
- }
-
- function _appendChild(obj, newChild) {
- if (_isAsyncScript(newChild) && !_scriptInDefaultList(newChild))
- _$asyncRequests.add(newChild);
- return _appendChildInternal(obj, newChild);
- }
-
- function _insertBefore(obj, newChild, refChild) {
- if (_isNode(newChild) && obj != newChild && !_isParentOf(newChild, obj)) {
- if (newChild.parentNode)
- _removeChild(newChild.parentNode, newChild);
- if (typeof obj._$children === 'undefined')
- obj._$children = Object.create(NodeList);
- var index = 0;
- var nextSibling = null;
- var previousSibling = null;
- for (index = 0; index < obj._$children.length; index++) {
- if (refChild == obj._$children[index]) {
- nextSibling = refChild;
- break;
- }
- previousSibling = obj._$children[index];
- }
- Array.prototype.splice.call(obj._$children, index, 0, newChild);
- newChild.parentNode = obj;
- if (nextSibling) {
- newChild.nextSibling = nextSibling;
- nextSibling.previousSibling = newChild;
- }
- if (previousSibling) {
- newChild.previousSibling = previousSibling;
- previousSibling.nextSibling = newChild;
- }
- _refreshQueries(obj);
- }
- if (_isAsyncScript(newChild) && !_scriptInDefaultList(newChild))
- _$asyncRequests.insertBefore(newChild, _getEmbeddedAsyncRequest(refChild));
- return newChild;
- }
-
- function _replaceChild(obj, newChild, oldChild) {
- if (_isNode(newChild) && obj != newChild && !_isParentOf(newChild, obj) && _isNode(oldChild) && _hasChildNodes(obj)) {
- for (var i = 0; i < obj._$children.length; i++) {
- if (oldChild == obj._$children[i]) {
- if (newChild.parentNode)
- _removeChild(newChild.parentNode, newChild);
- newChild.previousSibling = oldChild.previousSibling;
- newChild.nextSibling = oldChild.nextSibling;
- if (oldChild.previousSibling) {
- oldChild.previousSibling.nextSibling = newChild;
- }
- if (oldChild.nextSibling) {
- oldChild.nextSibling.previousSibling = newChild;
- }
- newChild.parentNode = obj;
- obj._$children[i] = newChild;
- oldChild.parentNode = oldChild.nextSibling = oldChild.previousSibling = _getMatchingNull(obj);
- _refreshQueries(obj);
- break;
- }
- }
- }
- if (_isAsyncScript(newChild) && !_scriptInDefaultList(newChild))
- _$asyncRequests.replace(newChild, _getEmbeddedAsyncRequest(oldChild));
- return oldChild;
- }
-
- function _firstElementChild(obj) {
- if (_isNode(obj)) {
- var cur = _firstChild(obj);
- do {
- if (_isElement(cur))
- return cur;
- cur = cur.nextSibling;
- } while (cur);
- }
- return _$getTrackingNull(Object.create(HTMLElement));
- }
-
- function _lastElementChild(obj) {
- if (_isNode(obj)) {
- var cur = _lastChild(obj);
- do {
- if (_isElement(cur))
- return cur;
- cur = cur.previousSibling;
- } while (cur);
- }
- return _$getTrackingNull(Object.create(HTMLElement));
- }
-
- function _nextElementSibling(obj) {
- if (_isNode(obj)) {
- var cur = obj.nextSibling;
- do {
- if (_isElement(cur))
- return cur;
- cur = cur.nextSibling;
- } while (cur);
- }
- return _$getTrackingNull(Object.create(HTMLElement));
- }
-
- function _previousElementSibling(obj) {
- if (_isNode(obj)) {
- var cur = obj.previousSibling;
- do {
- if (_isElement(cur))
- return cur;
- cur = cur.previousSibling;
- } while (cur);
- }
- return _$getTrackingNull(Object.create(HTMLElement));
- }
-
- function _parentElement(obj) {
- if (_isNode(obj)) {
- var cur = obj.parentNode;
- do {
- if (_isElement(cur))
- return cur;
- cur = cur.parentNode;
- } while (cur);
- }
- return _$getTrackingNull(Object.create(HTMLElement));
- }
-
- function _childElementCount(obj) {
- var count = 0;
- if (_isNode(obj)) {
- var cur = _firstChild(obj);
- do {
- if (_isElement(cur))
- count ++;
- cur = cur.nextSibling;
- } while (cur);
- }
- return count;
- }
-
- function _applyElement(obj, apply, where) {
- if (!obj || !apply) return;
- if (where === undefined || where == "outside") {
- if (!obj.parentNode) return;
- _replaceChild(obj.parentNode, apply, obj);
- _appendChild(apply, obj);
- }
- else if (where == 'inside') {
- var children = obj._$children !== undefined ? Array.prototype.slice.call(obj._$children) : [];
- for(i=0; i]*src[\s]*=[\s]*['"]([^'">]+)['"]/gim;
- function _setInnerHTML(source, content) {
- // since we are not parsing the inner html, mark the node as unsearchable
- source._$searchable = false;
- var scriptTag = null;
- while (scriptTag = scriptTagRegEx.exec(content)) {
- var scriptElement = Object.create(HTMLScriptElement);
- scriptElement.src = scriptTag[1];
- if (!_scriptInDefaultList(scriptElement))
- _$asyncRequests.add(scriptElement);
- }
- }
-
- function _formElements(form) {
- var elements = [];
- _visitChildNodes(form, function(node) {
- if (_isElement(node)) {
- var tagName = node.tagName.toLowerCase();
- if (tagName == 'input' || tagName == 'select' || tagName == 'button' || tagName == 'textarea' || tagName == 'fieldset') elements.push(node);
- }
- });
- return _wrapInList(elements, HTMLCollection, Object.create(HTMLElement));
- }
-
- function _selectOptions(select) {
- var options = [];
- _visitChildNodes(select, function(node) {
- var tagName = node.tagName.toLowerCase();
- if (tagName == 'option') options.push(node);
- else if (tagName != 'optgroup') return false;
- });
- return _wrapInList(options, HTMLCollection, _createElementByTagName('option'));
- }
-
- var queryIdSelectorRegEx = /^\s*#([^<>\s]+)\s*$/;
- function _queryIdSelector(selectors, returnFirstElementOnly) {
- var results = [];
- if (typeof selectors === 'string') {
- var parts = selectors.split(',');
- for (var i = 0; i < parts.length; i++) {
- var m = queryIdSelectorRegEx.exec(parts[i]);
- if (m && m[1]) {
- var e = _lookupElement(m[1]);
- if (e) {
- if (returnFirstElementOnly) return e;
- results.push(e);
- }
- }
- }
- }
- if (!returnFirstElementOnly)
- return results;
- }
-
- function _querySelectorAll(obj, selectors) {
- var results = _queryIdSelector(selectors);
- if (results.length === 0)
- results = [Object.create(_getElementByTagName(selectors) || HTMLElement)];
- return _wrapInList(results, NodeList);
- }
-
- function _querySelector(obj, selectors) {
- var results = _queryIdSelector(selectors, true);
- if (!result)
- result = _$getTrackingNull(Object.create(_getElementByTagName(selectors) || HTMLElement));
- return results;
- }
-
- function _extend(obj, original, filter) {
- if (obj && original) {
- var propertyNames = Object.getOwnPropertyNames(original);
- if (propertyNames && propertyNames.length > 0) {
- for (var p in propertyNames) {
- var name = propertyNames[p];
- if (typeof name != 'string' || (filter && name.match(filter))) continue;
- Object.defineProperty(obj, name, Object.getOwnPropertyDescriptor(original, name));
- }
- }
- }
- }
-
-
- function _getConstructorFromString(type) {
- if (typeof type !== "string") {
- return;
- }
-
- var typeParts = type.split(".");
- var ctor = _$globalObject;
- var i;
- for (i = 0; i < typeParts.length && ctor; i++) {
- ctor = ctor[typeParts[i]];
- }
-
- if (typeof ctor === "function") {
- return ctor;
- }
- }
-
- function _recordChildren(parent, elementDefinitions, parentForm) {
- if (_isElement(parent) && elementDefinitions && elementDefinitions.length > 0) {
- for (var i = 0 ; i < elementDefinitions.length; i++) {
- var e = elementDefinitions[i];
- if (e) {
- var element = _createElementByTagName(e.$tag);
-
- // Insert in global lists
- if (typeof e.id == 'string') {
- _recordElementId(e.id, element);
- // Simulate IE behaviour by exposing the element on the parent using its id
- if (parentForm && e.$formElement)
- parentForm[e.id] = element;
- else
- window[e.id] = element;
- }
-
- if (_isAsyncScript(element))
- _defaultScripts.push(element);
-
- // Initialize children
- if (e.$children)
- _recordChildren(element, e.$children, e.$tag.toLowerCase() == 'form' ? element : parentForm);
-
- // Copy properties
- _extend(element, e, /(^[\$].+)|(^_\$fieldDoc\$\$.+)/);
-
- if (e.$object) {
- _extend(element, e.$object);
- }
-
- // Add winControl property if there is a data-win-control attribute
- if (typeof e["data-win-control"] === "string") {
- var winControlType = e["data-win-control"];
- element.winControl = _$initVar(undefined, {
- ctor: _getConstructorFromString(winControlType),
- type: winControlType,
- isUnsafeType: true
- });
- }
-
- _appendChildInternal(parent, element);
- }
- }
- }
- }
-
- function _recordDomStructure(elementDefinitions) {
- if (elementDefinitions && elementDefinitions.length > 0) {
- _clearElement(document.body);
- _clearElement(document.head);
- _defaultScripts = [];
-
- for (var i = 0 ; i < elementDefinitions.length; i++) {
- var e = elementDefinitions[i];
- if (e && e.$tag && e.$children) {
- if (e.$tag == 'body')
- _recordChildren(document.body, e.$children);
- else if (e.$tag == 'head')
- _recordChildren(document.head, e.$children);
- }
- }
- }
- }
-
- function _createIDBRequest(requestType, source, result){
- var request = Object.create(requestType);
- request.source = source;
- request.result = result;
- return request;
- }
-
- <@ XMLContents @>
-
- // Assign variables to emulate browser host
- Document._$createDomObject = _createDomObject;
- Document._$recordDomStructure = _recordDomStructure;
- this.window = Window;
- _$nonRemovable(this.window);
- document = Document;
- _publicObject('document', Document);
- document.nodeName = '#document';
- document.localName = _$getTrackingNull('');
- document.nodeType = Node.DOCUMENT_NODE;
- document.ownerDocument = _$getTrackingNull(document);
- document.parentNode = _$getTrackingNull(document);
- document.previousSibling = _$getTrackingNull(document);
- document.nextSibling = _$getTrackingNull(document);
- document.nodeValue = _$getTrackingNull('');
- document.defaultView = window;
-
- document.head = _createElementByTagName('head');
- document.body = document.activeElement = _createElementByTagName('body');
- document.documentElement = _createElementByTagName('html');
- _appendChildInternal(document.documentElement, document.head);
- _appendChildInternal(document.documentElement, document.body);
- _appendChildInternal(document, document.documentElement);
- _appendChildInternal(document.head, _createElementByTagName('title'));
- _appendChildInternal(document.head, _createElementByTagName('script'));
-
- window.navigator.userAgent = 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET4.0C; .NET4.0E; MS-RTC LM 8; InfoPath.3; Override:IE9_DEFAULT_20091014';
- window.location.href = 'about:blank';
- window.location.pathname = '/blank';
- window.location.protocol = 'about:';
- window.location.toString = function() { return this.href; };
-
- /* Wire all elements to have the body as their parent node */
- Node.parentNode = document.body;
- Node.ownerDocument = document;
-
- function _publicInterface(name, interface, interfacePrototype) {
- _$nonRemovable(interface);
- <@ GlobalPolluter @>[name] = interface;
- <@ GlobalPolluter @>[name].prototype = interfacePrototype;
- }
-
- function _publicObject(name, obj) {
- _$nonRemovable(obj);
- <@ GlobalPolluter @>[name] = obj;
- }
- <@ Public Interfaces @>
-
-
- function HTMLOptionElementFactory (text, value, defaultSelected, selected) {
- ///
- ///
- ///
- ///
- ///
- ///
- return Object.create(HTMLOptionElement);
- }
-
- function HTMLImageElementFactory(width, height) {
- ///
- ///
- ///
- ///
- return Object.create(HTMLImageElement);
- }
-
- function HTMLAudioElementFactory(src) {
- ///
- ///
- ///
- return Object.create(HTMLAudioElement);
- }
-
- _publicInterface('Option', HTMLOptionElementFactory, HTMLOptionElement);
- _publicInterface('Image', HTMLImageElementFactory, HTMLImageElement);
- _publicInterface('Audio', HTMLAudioElementFactory, HTMLAudioElement);
-
- intellisense.annotate(window, {
- Worker: function() {
- ///
- ///
- ///
- },
- MSCSSMatrix: function () {
- ///
- ///
- ///
- },
- WebSocket: function() {
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- }
- });
-
- window.Option.create = window.Option;
- window.Image.create = window.Image;
- window.XDomainRequest.create = window.XDomainRequest;
- window.XMLHttpRequest.create = window.XMLHttpRequest;
-
-})();
-
-function _$getActiveXObject(className, location) {
- if ((/XMLHTTP/i).test(className))
- return new window.XMLHttpRequest();
-}
diff --git a/inputfiles/jsTemplate_worker.js b/inputfiles/jsTemplate_worker.js
deleted file mode 100644
index 9852fec79..000000000
--- a/inputfiles/jsTemplate_worker.js
+++ /dev/null
@@ -1,40 +0,0 @@
-(function () {
- var _eventManager = _$createEventManager(
- function getEventObject(type, attach, obj, ignoreCase) {
- function _eventTypeToObject(type, attach) {
- if (attach) return Event;
- <@ EventTypeToObjSwitchStatements @>
- return Event;
- }
- var e = _eventTypeToObject(type, attach);
- var eventObject = Object.create(e);
- eventObject.target = obj;
- eventObject.currentTarget = obj;
- eventObject.type = type;
- if (eventObject.relatedTarget)
- eventObject.relatedTarget = obj;
- return eventObject;
- });
- var _events = _eventManager.createEventProperties;
-
- <@ XMLContents @>
-
- function _publicInterface(name, interface, interfacePrototype) {
- _$nonRemovable(interface);
- <@ GlobalPolluter @>[name] = interface;
- <@ GlobalPolluter @>[name].prototype = interfacePrototype;
- }
-
- function _publicObject(name, obj) {
- _$nonRemovable(obj);
- <@ GlobalPolluter @>[name] = obj;
- }
- <@ Public Interfaces @>
-
- this.XMLHttpRequest.create = this.XMLHttpRequest;
-})();
-
-function _$getActiveXObject(className, location) {
- if ((/XMLHTTP/i).test(className))
- return new window.XMLHttpRequest();
-}