| #!/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 generator import ConstantOutputOrder |
| 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')", |
| ], |
| |
| # querysSelectorAll 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 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() |