| #!/usr/bin/env python3 | |
| # Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | |
| # for details. All rights reserved. Use of this source code is governed by a | |
| # BSD-style license that can be found in the LICENSE file. | |
| """This module provides shared functionality to provide Dart metadata for | |
| DOM APIs. | |
| """ | |
| import copy | |
| import json | |
| import logging | |
| import monitored | |
| import os | |
| import re | |
| from htmlrenamer import renamed_html_members, html_interface_renames | |
| _logger = logging.getLogger('dartmetadata') | |
| # Annotations to be placed on native members. The table is indexed by the IDL | |
| # interface and member name, and by IDL return or field type name. Both are | |
| # used to assemble the annotations: | |
| # | |
| # INTERFACE.MEMBER: annotations for member. | |
| # +TYPE: add annotations only if there are member annotations. | |
| # -TYPE: add annotations only if there are no member annotations. | |
| # TYPE: add regardless of member annotations. | |
| _dart2js_annotations = monitored.Dict( | |
| 'dartmetadata._dart2js_annotations', | |
| { | |
| 'AnimationEffectTiming.duration': [ | |
| "@Returns('num|String|Null')", | |
| ], | |
| 'ArrayBufferView': [ | |
| "@Creates('TypedData')", | |
| "@Returns('TypedData|Null')", | |
| ], | |
| 'CanvasRenderingContext2D.createImageData': [ | |
| "@Creates('ImageData|=Object')", | |
| ], | |
| 'CanvasRenderingContext2D.getImageData': [ | |
| "@Creates('ImageData|=Object')", | |
| ], | |
| 'CanvasRenderingContext2D.webkitGetImageDataHD': [ | |
| "@Creates('ImageData|=Object')", | |
| ], | |
| 'CanvasRenderingContext2D.fillStyle': [ | |
| "@Creates('String|CanvasGradient|CanvasPattern')", | |
| "@Returns('String|CanvasGradient|CanvasPattern')", | |
| ], | |
| 'CanvasRenderingContext2D.strokeStyle': [ | |
| "@Creates('String|CanvasGradient|CanvasPattern')", | |
| "@Returns('String|CanvasGradient|CanvasPattern')", | |
| ], | |
| 'CryptoKey.algorithm': [ | |
| "@Creates('Null')", | |
| ], | |
| 'CustomEvent._detail': [ | |
| "@Creates('Null')", | |
| ], | |
| # Normally Window is never null, but starting from a <template> element in | |
| # JavaScript, this will be null: | |
| # template.content.ownerDocument.defaultView | |
| 'Document.window': [ | |
| "@Creates('Window|=Object|Null')", | |
| "@Returns('Window|=Object|Null')", | |
| ], | |
| 'Document.getElementsByClassName': [ | |
| "@Creates('NodeList|HtmlCollection')", | |
| "@Returns('NodeList|HtmlCollection')", | |
| ], | |
| 'Document.getElementsByName': [ | |
| "@Creates('NodeList|HtmlCollection')", | |
| "@Returns('NodeList|HtmlCollection')", | |
| ], | |
| 'Document.getElementsByTagName': [ | |
| "@Creates('NodeList|HtmlCollection')", | |
| "@Returns('NodeList|HtmlCollection')", | |
| ], | |
| # querySelectorAll never returns `null`. | |
| 'Document.querySelectorAll': [ | |
| "@Creates('NodeList')", | |
| "@Returns('NodeList')", | |
| ], | |
| 'DocumentFragment.querySelectorAll': [ | |
| "@Creates('NodeList')", | |
| "@Returns('NodeList')", | |
| ], | |
| 'Element.querySelectorAll': [ | |
| "@Creates('NodeList')", | |
| "@Returns('NodeList')", | |
| ], | |
| 'Element.getBoundingClientRect': [ | |
| "@Creates('_DomRect')", | |
| "@Returns('_DomRect|Null')", # TODO(sra): Verify and remove Null. | |
| ], | |
| 'Element.getClientRects': [ | |
| "@Creates('DomRectList')", | |
| "@Returns('DomRectList|Null')", | |
| ], | |
| # Methods returning Window can return a local window, or a cross-frame | |
| # window (=Object) that needs wrapping. | |
| 'Window': [ | |
| "@Creates('Window|=Object')", | |
| "@Returns('Window|=Object')", | |
| ], | |
| 'Window.openDatabase': [ | |
| "@Creates('SqlDatabase')", | |
| ], | |
| 'Window.showModalDialog': [ | |
| "@Creates('Null')", | |
| ], | |
| 'Element.webkitGetRegionFlowRanges': [ | |
| "@Creates('JSExtendableArray')", | |
| "@Returns('JSExtendableArray')", | |
| ], | |
| 'Element.getElementsByClassName': [ | |
| "@Creates('NodeList|HtmlCollection')", | |
| "@Returns('NodeList|HtmlCollection')", | |
| ], | |
| 'Element.getElementsByName': [ | |
| "@Creates('NodeList|HtmlCollection')", | |
| "@Returns('NodeList|HtmlCollection')", | |
| ], | |
| 'Element.getElementsByTagName': [ | |
| "@Creates('NodeList|HtmlCollection')", | |
| "@Returns('NodeList|HtmlCollection')", | |
| ], | |
| "ErrorEvent.error": [ | |
| "@Creates('Null')", # Only returns values created elsewhere. | |
| ], | |
| # To be in callback with the browser-created Event, we had to have called | |
| # addEventListener on the target, so we avoid | |
| 'Event.currentTarget': [ | |
| "@Creates('Null')", | |
| "@Returns('EventTarget|=Object|Null')", | |
| ], | |
| # Only nodes in the DOM bubble and have target !== currentTarget. | |
| 'Event.target': [ | |
| "@Creates('Node')", | |
| "@Returns('EventTarget|=Object')", | |
| ], | |
| # TODO(sra): Investigate how ExtendableMessageEvent.data is different from | |
| # MessageEvent.data. It might be necessary to put in a method to translate | |
| # the JavaScript wire type into a Dart type. | |
| 'ExtendableMessageEvent.data': [ | |
| "@annotation_Creates_SerializedScriptValue", | |
| "@annotation_Returns_SerializedScriptValue", | |
| ], | |
| # TODO(sra): We could determine the following by parsing the compound IDL | |
| # type. | |
| 'ExtendableMessageEvent.source': [ | |
| "@Creates('Client|ServiceWorker|MessagePort')", | |
| "@Returns('Client|ServiceWorker|MessagePort|Null')", | |
| ], | |
| 'File.lastModifiedDate': [ | |
| "@Creates('Null')", # JS date object. | |
| ], | |
| 'FocusEvent.relatedTarget': [ | |
| "@Creates('Null')", | |
| ], | |
| 'Gamepad.buttons': [ | |
| "@Creates('JSExtendableArray|GamepadButton')", | |
| "@Returns('JSExtendableArray')", | |
| ], | |
| # Creates a GeolocationPosition or a GeolocationPositionError for a | |
| # callback. See issue #45562. | |
| 'Geolocation.getCurrentPosition': [ | |
| "@Creates('Geoposition')", | |
| "@Creates('PositionError')", | |
| ], | |
| 'Geolocation.watchPosition': [ | |
| "@Creates('Geoposition')", | |
| "@Creates('PositionError')", | |
| ], | |
| 'HTMLCanvasElement.getContext': [ | |
| "@Creates('CanvasRenderingContext2D|RenderingContext|RenderingContext2')", | |
| "@Returns('CanvasRenderingContext2D|RenderingContext|RenderingContext2|Null')", | |
| ], | |
| 'HTMLInputElement.valueAsDate': [ | |
| "@Creates('Null')", # JS date object. | |
| ], | |
| # Rather than have the result of an IDBRequest as a union over all possible | |
| # results, we mark the result as instantiating any classes, and mark | |
| # each operation with the classes that it could cause to be asynchronously | |
| # instantiated. | |
| 'IDBRequest.result': ["@Creates('Null')"], | |
| # The source is usually a participant in the operation that generated the | |
| # IDBRequest. | |
| 'IDBRequest.source': ["@Creates('Null')"], | |
| 'IDBFactory.open': ["@Creates('Database')"], | |
| 'IDBFactory.webkitGetDatabaseNames': ["@Creates('DomStringList')"], | |
| 'IDBObjectStore.put': ["@_annotation_Creates_IDBKey"], | |
| 'IDBObjectStore.add': ["@_annotation_Creates_IDBKey"], | |
| 'IDBObjectStore.get': ["@annotation_Creates_SerializedScriptValue"], | |
| 'IDBObjectStore.openCursor': ["@Creates('Cursor')"], | |
| 'IDBIndex.get': ["@annotation_Creates_SerializedScriptValue"], | |
| 'IDBIndex.getKey': [ | |
| "@annotation_Creates_SerializedScriptValue", | |
| # The source is the object store behind the index. | |
| "@Creates('ObjectStore')", | |
| ], | |
| 'IDBIndex.openCursor': ["@Creates('Cursor')"], | |
| 'IDBIndex.openKeyCursor': ["@Creates('Cursor')"], | |
| 'IDBCursorWithValue.value': [ | |
| '@annotation_Creates_SerializedScriptValue', | |
| '@annotation_Returns_SerializedScriptValue', | |
| ], | |
| 'IDBCursor.key': [ | |
| "@_annotation_Creates_IDBKey", | |
| "@_annotation_Returns_IDBKey", | |
| ], | |
| 'IDBCursor.primaryKey': [ | |
| "@_annotation_Creates_IDBKey", | |
| "@_annotation_Returns_IDBKey", | |
| ], | |
| 'IDBCursor.source': [ | |
| "@Creates('Null')", | |
| "@Returns('ObjectStore|Index|Null')", | |
| ], | |
| 'IDBDatabase.version': [ | |
| "@Creates('int|String|Null')", | |
| "@Returns('int|String|Null')", | |
| ], | |
| 'IDBIndex.keyPath': [ | |
| "@annotation_Creates_SerializedScriptValue", | |
| ], | |
| 'IDBKeyRange.lower': [ | |
| "@annotation_Creates_SerializedScriptValue", | |
| ], | |
| 'IDBKeyRange.upper': [ | |
| "@annotation_Creates_SerializedScriptValue", | |
| ], | |
| 'IDBObjectStore.keyPath': [ | |
| "@annotation_Creates_SerializedScriptValue", | |
| ], | |
| '+IDBOpenDBRequest': [ | |
| "@Returns('Request')", | |
| "@Creates('Request')", | |
| ], | |
| '+IDBRequest': [ | |
| "@Returns('Request')", | |
| "@Creates('Request')", | |
| ], | |
| 'IDBVersionChangeEvent.newVersion': [ | |
| "@Creates('int|String|Null')", | |
| "@Returns('int|String|Null')", | |
| ], | |
| 'IDBVersionChangeEvent.oldVersion': [ | |
| "@Creates('int|String|Null')", | |
| "@Returns('int|String|Null')", | |
| ], | |
| 'ImageData.data': [ | |
| "@Creates('NativeUint8ClampedList')", | |
| "@Returns('NativeUint8ClampedList')", | |
| ], | |
| 'MediaStream.getAudioTracks': [ | |
| "@Creates('JSExtendableArray|MediaStreamTrack')", | |
| "@Returns('JSExtendableArray')", | |
| ], | |
| 'MediaStream.getVideoTracks': [ | |
| "@Creates('JSExtendableArray|MediaStreamTrack')", | |
| "@Returns('JSExtendableArray')", | |
| ], | |
| 'MessageEvent.data': [ | |
| "@annotation_Creates_SerializedScriptValue", | |
| "@annotation_Returns_SerializedScriptValue", | |
| ], | |
| 'MessageEvent.ports': ["@Creates('JSExtendableArray')"], | |
| 'MessageEvent.source': [ | |
| "@Creates('Null')", | |
| "@Returns('EventTarget|=Object')", | |
| ], | |
| 'Metadata.modificationTime': [ | |
| "@Creates('Null')", # JS date object. | |
| ], | |
| 'MouseEvent.relatedTarget': [ | |
| "@Creates('Node')", | |
| "@Returns('EventTarget|=Object|Null')", | |
| ], | |
| 'Notification.data': [ | |
| "@annotation_Creates_SerializedScriptValue", | |
| "@annotation_Returns_SerializedScriptValue", | |
| ], | |
| 'PopStateEvent.state': [ | |
| "@annotation_Creates_SerializedScriptValue", | |
| "@annotation_Returns_SerializedScriptValue", | |
| ], | |
| 'RTCStatsReport.timestamp': [ | |
| "@Creates('Null')", # JS date object. | |
| ], | |
| 'SerializedScriptValue': [ | |
| "@annotation_Creates_SerializedScriptValue", | |
| "@annotation_Returns_SerializedScriptValue", | |
| ], | |
| 'ServiceWorkerMessageEvent.data': [ | |
| "@annotation_Creates_SerializedScriptValue", | |
| "@annotation_Returns_SerializedScriptValue", | |
| ], | |
| 'ServiceWorkerMessageEvent.source': [ | |
| "@Creates('Null')", | |
| "@Returns('ServiceWorker|MessagePort')", | |
| ], | |
| 'ShadowRoot.getElementsByClassName': [ | |
| "@Creates('NodeList|HtmlCollection')", | |
| "@Returns('NodeList|HtmlCollection')", | |
| ], | |
| 'ShadowRoot.getElementsByName': [ | |
| "@Creates('NodeList|HtmlCollection')", | |
| "@Returns('NodeList|HtmlCollection')", | |
| ], | |
| 'ShadowRoot.getElementsByTagName': [ | |
| "@Creates('NodeList|HtmlCollection')", | |
| "@Returns('NodeList|HtmlCollection')", | |
| ], | |
| # Touch targets are Elements in a Document, or the Document. | |
| 'Touch.target': [ | |
| "@Creates('Element|Document')", | |
| "@Returns('Element|Document')", | |
| ], | |
| 'TrackEvent.track': [ | |
| "@Creates('Null')", | |
| ], | |
| 'VTTCue.line': [ | |
| "@Creates('Null')", | |
| "@Returns('num|String')", | |
| ], | |
| 'VTTCue.position': [ | |
| "@Creates('Null')", | |
| "@Returns('num|String')", | |
| ], | |
| 'WebGLRenderingContext.getBufferParameter': [ | |
| "@Creates('int|Null')", | |
| "@Returns('int|Null')", | |
| ], | |
| 'WebGLRenderingContext.getFramebufferAttachmentParameter': [ | |
| "@Creates('int|Renderbuffer|Texture|Null')", | |
| "@Returns('int|Renderbuffer|Texture|Null')", | |
| ], | |
| 'WebGLRenderingContext.getProgramParameter': [ | |
| "@Creates('int|bool|Null')", | |
| "@Returns('int|bool|Null')", | |
| ], | |
| 'WebGLRenderingContext.getRenderbufferParameter': [ | |
| "@Creates('int|Null')", | |
| "@Returns('int|Null')", | |
| ], | |
| 'WebGLRenderingContext.getShaderParameter': [ | |
| "@Creates('int|bool|Null')", | |
| "@Returns('int|bool|Null')", | |
| ], | |
| 'WebGLRenderingContext.getTexParameter': [ | |
| "@Creates('int|Null')", | |
| "@Returns('int|Null')", | |
| ], | |
| 'WebGLRenderingContext.getUniform': [ | |
| "@Creates('Null|num|String|bool|JSExtendableArray|" | |
| "NativeFloat32List|NativeInt32List|NativeUint32List')", | |
| "@Returns('Null|num|String|bool|JSExtendableArray|" | |
| "NativeFloat32List|NativeInt32List|NativeUint32List')", | |
| ], | |
| 'WebGLRenderingContext.getVertexAttrib': [ | |
| "@Creates('Null|num|bool|NativeFloat32List|Buffer')", | |
| "@Returns('Null|num|bool|NativeFloat32List|Buffer')", | |
| ], | |
| 'WebGLRenderingContext.getParameter': [ | |
| # Taken from http://www.khronos.org/registry/webgl/specs/latest/ | |
| # Section 5.14.3 Setting and getting state | |
| "@Creates('Null|num|String|bool|JSExtendableArray|" | |
| "NativeFloat32List|NativeInt32List|NativeUint32List|" | |
| "Framebuffer|Renderbuffer|Texture')", | |
| "@Returns('Null|num|String|bool|JSExtendableArray|" | |
| "NativeFloat32List|NativeInt32List|NativeUint32List|" | |
| "Framebuffer|Renderbuffer|Texture')", | |
| ], | |
| 'WebGLRenderingContext.getContextAttributes': [ | |
| "@Creates('ContextAttributes|Null')", | |
| ], | |
| 'XMLHttpRequest.response': [ | |
| "@Creates('NativeByteBuffer|Blob|Document|=Object|JSExtendableArray" | |
| "|String|num')", | |
| ], | |
| }, | |
| dart2jsOnly=True) | |
| _blink_experimental_annotations = [ | |
| "@SupportedBrowser(SupportedBrowser.CHROME)", | |
| ] | |
| _indexed_db_annotations = [ | |
| "@SupportedBrowser(SupportedBrowser.CHROME)", | |
| "@SupportedBrowser(SupportedBrowser.FIREFOX, '15')", | |
| "@SupportedBrowser(SupportedBrowser.IE, '10')", | |
| ] | |
| _file_system_annotations = [ | |
| "@SupportedBrowser(SupportedBrowser.CHROME)", | |
| ] | |
| _all_but_ie9_annotations = [ | |
| "@SupportedBrowser(SupportedBrowser.CHROME)", | |
| "@SupportedBrowser(SupportedBrowser.FIREFOX)", | |
| "@SupportedBrowser(SupportedBrowser.IE, '10')", | |
| "@SupportedBrowser(SupportedBrowser.SAFARI)", | |
| ] | |
| _history_annotations = _all_but_ie9_annotations | |
| _no_ie_annotations = [ | |
| "@SupportedBrowser(SupportedBrowser.CHROME)", | |
| "@SupportedBrowser(SupportedBrowser.FIREFOX)", | |
| "@SupportedBrowser(SupportedBrowser.SAFARI)", | |
| ] | |
| _performance_annotations = [ | |
| "@SupportedBrowser(SupportedBrowser.CHROME)", | |
| "@SupportedBrowser(SupportedBrowser.FIREFOX)", | |
| "@SupportedBrowser(SupportedBrowser.IE)", | |
| ] | |
| _rtc_annotations = [ # Note: Firefox nightly builds also support this. | |
| "@SupportedBrowser(SupportedBrowser.CHROME)", | |
| ] | |
| _shadow_dom_annotations = [ | |
| "@SupportedBrowser(SupportedBrowser.CHROME, '26')", | |
| ] | |
| _speech_recognition_annotations = [ | |
| "@SupportedBrowser(SupportedBrowser.CHROME, '25')", | |
| ] | |
| _svg_annotations = _all_but_ie9_annotations | |
| _web_sql_annotations = [ | |
| "@SupportedBrowser(SupportedBrowser.CHROME)", | |
| "@SupportedBrowser(SupportedBrowser.SAFARI)", | |
| ] | |
| _webgl_annotations = [ | |
| "@SupportedBrowser(SupportedBrowser.CHROME)", | |
| "@SupportedBrowser(SupportedBrowser.FIREFOX)", | |
| ] | |
| _web_audio_annotations = _webgl_annotations | |
| _webkit_experimental_annotations = [ | |
| "@SupportedBrowser(SupportedBrowser.CHROME)", | |
| "@SupportedBrowser(SupportedBrowser.SAFARI)", | |
| ] | |
| # Annotations to be placed on generated members. | |
| # The table is indexed as: | |
| # INTERFACE: annotations to be added to the interface declaration | |
| # INTERFACE.MEMBER: annotation to be added to the member declaration | |
| _annotations = monitored.Dict( | |
| 'dartmetadata._annotations', | |
| { | |
| 'CSSHostRule': | |
| _shadow_dom_annotations, | |
| 'WebKitCSSMatrix': | |
| _webkit_experimental_annotations, | |
| 'Crypto': | |
| _webkit_experimental_annotations, | |
| 'Database': | |
| _web_sql_annotations, | |
| 'DatabaseSync': | |
| _web_sql_annotations, | |
| 'ApplicationCache': [ | |
| "@SupportedBrowser(SupportedBrowser.CHROME)", | |
| "@SupportedBrowser(SupportedBrowser.FIREFOX)", | |
| "@SupportedBrowser(SupportedBrowser.IE, '10')", | |
| "@SupportedBrowser(SupportedBrowser.OPERA)", | |
| "@SupportedBrowser(SupportedBrowser.SAFARI)", | |
| ], | |
| 'AudioBufferSourceNode': | |
| _web_audio_annotations, | |
| 'AudioContext': | |
| _web_audio_annotations, | |
| 'DOMFileSystem': | |
| _file_system_annotations, | |
| 'DOMFileSystemSync': | |
| _file_system_annotations, | |
| 'Window.indexedDB': | |
| _indexed_db_annotations, | |
| 'Window.openDatabase': | |
| _web_sql_annotations, | |
| 'Window.performance': | |
| _performance_annotations, | |
| 'Window.webkitNotifications': | |
| _webkit_experimental_annotations, | |
| 'Window.webkitRequestFileSystem': | |
| _file_system_annotations, | |
| 'Window.webkitResolveLocalFileSystemURL': | |
| _file_system_annotations, | |
| 'Element.createShadowRoot': [ | |
| "@SupportedBrowser(SupportedBrowser.CHROME, '25')", | |
| ], | |
| 'Element.ontransitionend': | |
| _all_but_ie9_annotations, | |
| # Placeholder to add experimental flag, implementation for this is | |
| # pending in a separate CL. | |
| 'Element.webkitMatchesSelector': [], | |
| 'Event.clipboardData': [ | |
| "@SupportedBrowser(SupportedBrowser.CHROME)", | |
| "@SupportedBrowser(SupportedBrowser.FIREFOX)", | |
| "@SupportedBrowser(SupportedBrowser.SAFARI)", | |
| ], | |
| 'FormData': | |
| _all_but_ie9_annotations, | |
| 'HashChangeEvent': [ | |
| "@SupportedBrowser(SupportedBrowser.CHROME)", | |
| "@SupportedBrowser(SupportedBrowser.FIREFOX)", | |
| "@SupportedBrowser(SupportedBrowser.SAFARI)", | |
| ], | |
| 'History.pushState': | |
| _history_annotations, | |
| 'History.replaceState': | |
| _history_annotations, | |
| 'HTMLContentElement': | |
| _shadow_dom_annotations, | |
| 'HTMLDataListElement': | |
| _all_but_ie9_annotations, | |
| 'HTMLDetailsElement': | |
| _webkit_experimental_annotations, | |
| 'HTMLEmbedElement': [ | |
| "@SupportedBrowser(SupportedBrowser.CHROME)", | |
| "@SupportedBrowser(SupportedBrowser.IE)", | |
| "@SupportedBrowser(SupportedBrowser.SAFARI)", | |
| ], | |
| 'HTMLKeygenElement': | |
| _webkit_experimental_annotations, | |
| 'HTMLMeterElement': | |
| _no_ie_annotations, | |
| 'HTMLObjectElement': [ | |
| "@SupportedBrowser(SupportedBrowser.CHROME)", | |
| "@SupportedBrowser(SupportedBrowser.IE)", | |
| "@SupportedBrowser(SupportedBrowser.SAFARI)", | |
| ], | |
| 'HTMLOutputElement': | |
| _no_ie_annotations, | |
| 'HTMLProgressElement': | |
| _all_but_ie9_annotations, | |
| 'HTMLShadowElement': | |
| _shadow_dom_annotations, | |
| 'HTMLTemplateElement': | |
| _blink_experimental_annotations, | |
| 'HTMLTrackElement': [ | |
| "@SupportedBrowser(SupportedBrowser.CHROME)", | |
| "@SupportedBrowser(SupportedBrowser.IE, '10')", | |
| "@SupportedBrowser(SupportedBrowser.SAFARI)", | |
| ], | |
| 'IDBFactory': | |
| _indexed_db_annotations, | |
| 'IDBDatabase': | |
| _indexed_db_annotations, | |
| 'MediaStream': | |
| _rtc_annotations, | |
| 'MediaStreamEvent': | |
| _rtc_annotations, | |
| 'MediaStreamTrack': | |
| _rtc_annotations, | |
| 'MediaStreamTrackEvent': | |
| _rtc_annotations, | |
| 'MediaSource': [ | |
| # TODO(alanknight): This works on Firefox 33 behind a flag and in Safari | |
| # desktop, but not mobile. On theory that static false positives are worse | |
| # than negatives, leave those out for now. Update once they're available. | |
| "@SupportedBrowser(SupportedBrowser.CHROME)", | |
| "@SupportedBrowser(SupportedBrowser.IE, '11')", | |
| ], | |
| 'MutationObserver': [ | |
| "@SupportedBrowser(SupportedBrowser.CHROME)", | |
| "@SupportedBrowser(SupportedBrowser.FIREFOX)", | |
| "@SupportedBrowser(SupportedBrowser.SAFARI)", | |
| ], | |
| 'Performance': | |
| _performance_annotations, | |
| 'PopStateEvent': | |
| _history_annotations, | |
| 'RTCIceCandidate': | |
| _rtc_annotations, | |
| 'RTCPeerConnection': | |
| _rtc_annotations, | |
| 'RTCSessionDescription': | |
| _rtc_annotations, | |
| 'ShadowRoot': | |
| _shadow_dom_annotations, | |
| 'SpeechRecognition': | |
| _speech_recognition_annotations, | |
| 'SpeechRecognitionAlternative': | |
| _speech_recognition_annotations, | |
| 'SpeechRecognitionError': | |
| _speech_recognition_annotations, | |
| 'SpeechRecognitionEvent': | |
| _speech_recognition_annotations, | |
| 'SpeechRecognitionResult': | |
| _speech_recognition_annotations, | |
| 'SVGAltGlyphElement': | |
| _no_ie_annotations, | |
| 'SVGAnimateElement': | |
| _no_ie_annotations, | |
| 'SVGAnimateMotionElement': | |
| _no_ie_annotations, | |
| 'SVGAnimateTransformElement': | |
| _no_ie_annotations, | |
| 'SVGFEBlendElement': | |
| _svg_annotations, | |
| 'SVGFEColorMatrixElement': | |
| _svg_annotations, | |
| 'SVGFEComponentTransferElement': | |
| _svg_annotations, | |
| 'SVGFEConvolveMatrixElement': | |
| _svg_annotations, | |
| 'SVGFEDiffuseLightingElement': | |
| _svg_annotations, | |
| 'SVGFEDisplacementMapElement': | |
| _svg_annotations, | |
| 'SVGFEDistantLightElement': | |
| _svg_annotations, | |
| 'SVGFEFloodElement': | |
| _svg_annotations, | |
| 'SVGFEFuncAElement': | |
| _svg_annotations, | |
| 'SVGFEFuncBElement': | |
| _svg_annotations, | |
| 'SVGFEFuncGElement': | |
| _svg_annotations, | |
| 'SVGFEFuncRElement': | |
| _svg_annotations, | |
| 'SVGFEGaussianBlurElement': | |
| _svg_annotations, | |
| 'SVGFEImageElement': | |
| _svg_annotations, | |
| 'SVGFEMergeElement': | |
| _svg_annotations, | |
| 'SVGFEMergeNodeElement': | |
| _svg_annotations, | |
| 'SVGFEMorphologyElement': | |
| _svg_annotations, | |
| 'SVGFEOffsetElement': | |
| _svg_annotations, | |
| 'SVGFEPointLightElement': | |
| _svg_annotations, | |
| 'SVGFESpecularLightingElement': | |
| _svg_annotations, | |
| 'SVGFESpotLightElement': | |
| _svg_annotations, | |
| 'SVGFETileElement': | |
| _svg_annotations, | |
| 'SVGFETurbulenceElement': | |
| _svg_annotations, | |
| 'SVGFilterElement': | |
| _svg_annotations, | |
| 'SVGForeignObjectElement': | |
| _no_ie_annotations, | |
| 'SVGSetElement': | |
| _no_ie_annotations, | |
| 'SQLTransaction': | |
| _web_sql_annotations, | |
| 'SQLTransactionSync': | |
| _web_sql_annotations, | |
| 'WebGLRenderingContext': | |
| _webgl_annotations, | |
| 'WebSocket': | |
| _all_but_ie9_annotations, | |
| 'Worker': | |
| _all_but_ie9_annotations, | |
| 'XMLHttpRequest.overrideMimeType': | |
| _no_ie_annotations, | |
| 'XMLHttpRequest.response': | |
| _all_but_ie9_annotations, | |
| 'XMLHttpRequestEventTarget.onloadend': | |
| _all_but_ie9_annotations, | |
| 'XMLHttpRequestEventTarget.onprogress': | |
| _all_but_ie9_annotations, | |
| 'XSLTProcessor': [ | |
| "@SupportedBrowser(SupportedBrowser.CHROME)", | |
| "@SupportedBrowser(SupportedBrowser.FIREFOX)", | |
| "@SupportedBrowser(SupportedBrowser.SAFARI)", | |
| ], | |
| }) | |
| # TODO(blois): minimize noise and enable by default. | |
| _monitor_type_metadata = False | |
| class DartMetadata(object): | |
| def __init__(self, | |
| api_status_path, | |
| doc_comments_path, | |
| logging_level=logging.WARNING): | |
| _logger.setLevel(logging_level) | |
| self._api_status_path = api_status_path | |
| status_file = open(self._api_status_path, 'r+') | |
| self._types = json.load(status_file) | |
| status_file.close() | |
| comments_file = open(doc_comments_path, 'r+') | |
| self._doc_comments = json.load(comments_file) | |
| comments_file.close() | |
| if _monitor_type_metadata: | |
| monitored_interfaces = {} | |
| for interface_id, interface_data in list(self._types.items()): | |
| monitored_interface = interface_data.copy() | |
| monitored_interface['members'] = monitored.Dict( | |
| 'dartmetadata.%s' % interface_id, interface_data['members']) | |
| monitored_interfaces[interface_id] = monitored_interface | |
| self._monitored_types = monitored.Dict( | |
| 'dartmetadata._monitored_types', monitored_interfaces) | |
| else: | |
| self._monitored_types = self._types | |
| def GetFormattedMetadata(self, | |
| library_name, | |
| interface, | |
| member_id=None, | |
| indentation=''): | |
| """ Gets all comments and annotations for an interface or member. | |
| """ | |
| return self.FormatMetadata( | |
| self.GetMetadata(library_name, interface, member_id), indentation) | |
| def GetMetadata(self, | |
| library_name, | |
| interface, | |
| member_name=None, | |
| source_member_name=None): | |
| """ Gets all comments and annotations for an interface or member. | |
| Args: | |
| source_member_name: If the member is dependent on a different member | |
| then this is used to apply the support annotations from the other | |
| member. | |
| """ | |
| annotations = self._GetComments(library_name, interface, member_name) | |
| annotations = annotations + self._GetCommonAnnotations( | |
| interface, member_name, source_member_name) | |
| return annotations | |
| def GetDart2JSMetadata( | |
| self, | |
| idl_type, | |
| library_name, | |
| interface, | |
| member_name, | |
| ): | |
| """ Gets all annotations for Dart2JS members- including annotations for | |
| both dart2js and dartium. | |
| """ | |
| annotations = self.GetMetadata(library_name, interface, member_name) | |
| ann2 = self._GetDart2JSSpecificAnnotations(idl_type, interface.id, | |
| member_name) | |
| if ann2: | |
| if annotations: | |
| annotations.extend(ann2) | |
| else: | |
| annotations = ann2 | |
| return annotations | |
| def IsSuppressed(self, interface, member_name): | |
| annotations = self._GetSupportLevelAnnotations(interface.id, | |
| member_name) | |
| return any( | |
| annotation.startswith('@removed') for annotation in annotations) | |
| def _GetCommonAnnotations(self, | |
| interface, | |
| member_name=None, | |
| source_member_name=None): | |
| annotations = [] | |
| if member_name: | |
| key = '%s.%s' % (interface.id, member_name) | |
| dom_name = '%s.%s' % (interface.javascript_binding_name, | |
| member_name) | |
| # DomName annotation is needed for dblclick ACX plugin analyzer. | |
| if member_name == 'dblclickEvent' or member_name == 'ondblclick': | |
| annotations.append("@DomName('" + dom_name + "')") | |
| else: | |
| key = interface.id | |
| if key in _annotations: | |
| annotations.extend(_annotations[key]) | |
| if (not member_name and | |
| interface.javascript_binding_name.startswith('WebKit') and | |
| interface.id not in html_interface_renames): | |
| annotations.extend(_webkit_experimental_annotations) | |
| if (member_name and member_name.startswith('webkit') and | |
| key not in renamed_html_members): | |
| annotations.extend(_webkit_experimental_annotations) | |
| if source_member_name: | |
| member_name = source_member_name | |
| support_annotations = self._GetSupportLevelAnnotations( | |
| interface.id, member_name) | |
| for annotation in support_annotations: | |
| if annotation not in annotations: | |
| annotations.append(annotation) | |
| return annotations | |
| def _GetComments(self, library_name, interface, member_name=None): | |
| """ Gets all comments for the interface or member and returns a list. """ | |
| # Add documentation from JSON. | |
| comments = [] | |
| library_name = 'dart.dom.%s' % library_name | |
| if library_name in self._doc_comments: | |
| library_info = self._doc_comments[library_name] | |
| if interface.id in library_info: | |
| interface_info = library_info[interface.id] | |
| if member_name: | |
| if 'members' in interface_info and member_name in interface_info[ | |
| 'members']: | |
| comments = interface_info['members'][member_name] | |
| elif 'comment' in interface_info: | |
| comments = interface_info['comment'] | |
| if comments: | |
| comments = ['\n'.join(comments)] | |
| return comments | |
| def AnyConversionAnnotations(self, idl_type, interface_name, member_name): | |
| if (_annotations.get('%s.%s' % (interface_name, member_name)) or | |
| self._GetDart2JSSpecificAnnotations(idl_type, interface_name, | |
| member_name)): | |
| return True | |
| else: | |
| return False | |
| def FormatMetadata(self, metadata, indentation): | |
| if metadata: | |
| newline = '\n%s' % indentation | |
| result = newline.join(metadata) + newline | |
| return result | |
| return '' | |
| def _GetDart2JSSpecificAnnotations(self, idl_type, interface_name, | |
| member_name): | |
| """ Finds dart2js-specific annotations. This does not include ones shared with | |
| dartium. | |
| """ | |
| ann1 = _dart2js_annotations.get("%s.%s" % (interface_name, member_name)) | |
| if ann1: | |
| ann2 = _dart2js_annotations.get('+' + idl_type) | |
| if ann2: | |
| return ann2 + ann1 | |
| ann2 = _dart2js_annotations.get(idl_type) | |
| if ann2: | |
| return ann2 + ann1 | |
| return ann1 | |
| ann2 = _dart2js_annotations.get('-' + idl_type) | |
| if ann2: | |
| return ann2 | |
| ann2 = _dart2js_annotations.get(idl_type) | |
| return ann2 | |
| def _GetSupportInfo(self, interface_id, member_id=None): | |
| """ Looks up the interface or member in the DOM status list and returns the | |
| support level for it. | |
| """ | |
| if interface_id in self._monitored_types: | |
| type_info = self._monitored_types[interface_id] | |
| else: | |
| type_info = { | |
| 'members': {}, | |
| 'support_level': 'untriaged', | |
| } | |
| self._types[interface_id] = type_info | |
| if not member_id: | |
| return type_info | |
| members = type_info['members'] | |
| if member_id in members: | |
| member_info = members[member_id] | |
| else: | |
| if member_id == interface_id: | |
| member_info = {} | |
| else: | |
| member_info = {'support_level': 'untriaged'} | |
| members[member_id] = member_info | |
| return member_info | |
| def _GetSupportLevelAnnotations(self, interface_id, member_id=None): | |
| """ Gets annotations for API support status. | |
| """ | |
| support_info = self._GetSupportInfo(interface_id, member_id) | |
| dart_action = support_info.get('dart_action') | |
| support_level = support_info.get('support_level') | |
| comment = support_info.get('comment') | |
| annotations = [] | |
| # TODO(blois): should add an annotation for the comment, but keeping out | |
| # to keep the initial diff a bit more localized. | |
| #if comment: | |
| # annotations.append('// %s' % comment) | |
| if dart_action: | |
| if dart_action == 'unstable': | |
| annotations.append('@Unstable()') | |
| elif dart_action == 'suppress': | |
| if comment: | |
| annotations.append('// %s' % comment) | |
| anAnnotation = 'deprecated' | |
| if member_id: | |
| anAnnotation = 'removed' | |
| annotations.append('@%s // %s' % (anAnnotation, support_level)) | |
| pass | |
| elif dart_action == 'stable': | |
| pass | |
| else: | |
| _logger.warn( | |
| 'Unknown dart_action - %s:%s' % (interface_id, member_id)) | |
| elif support_level == 'stable': | |
| pass | |
| elif support_level == 'deprecated': | |
| if comment: | |
| annotations.append('// %s' % comment) | |
| annotations.append('@deprecated') | |
| elif support_level is None: | |
| pass | |
| else: | |
| _logger.warn( | |
| 'Unknown support_level - %s:%s' % (interface_id, member_id)) | |
| return annotations | |
| def Flush(self): | |
| json_file = open(self._api_status_path, 'w+') | |
| json.dump( | |
| self._types, | |
| json_file, | |
| indent=2, | |
| separators=(',', ': '), | |
| sort_keys=True) | |
| json_file.close() |