Home | History | Annotate | Download | only in sdk
      1 /*
      2  * Copyright (C) 2008 Apple Inc. All Rights Reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  * 1. Redistributions of source code must retain the above copyright
      8  *    notice, this list of conditions and the following disclaimer.
      9  * 2. Redistributions in binary form must reproduce the above copyright
     10  *    notice, this list of conditions and the following disclaimer in the
     11  *    documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
     14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
     17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     24  */
     25 
     26 /**
     27  * @constructor
     28  * @extends {WebInspector.SDKObject}
     29  * @implements {WebInspector.ContentProvider}
     30  * @param {!WebInspector.Target} target
     31  * @param {string} scriptId
     32  * @param {string} sourceURL
     33  * @param {number} startLine
     34  * @param {number} startColumn
     35  * @param {number} endLine
     36  * @param {number} endColumn
     37  * @param {boolean} isContentScript
     38  * @param {string=} sourceMapURL
     39  * @param {boolean=} hasSourceURL
     40  */
     41 WebInspector.Script = function(target, scriptId, sourceURL, startLine, startColumn, endLine, endColumn, isContentScript, sourceMapURL, hasSourceURL)
     42 {
     43     WebInspector.SDKObject.call(this, target);
     44     this.scriptId = scriptId;
     45     this.sourceURL = sourceURL;
     46     this.lineOffset = startLine;
     47     this.columnOffset = startColumn;
     48     this.endLine = endLine;
     49     this.endColumn = endColumn;
     50     this._isContentScript = isContentScript;
     51     this.sourceMapURL = sourceMapURL;
     52     this.hasSourceURL = hasSourceURL;
     53 }
     54 
     55 WebInspector.Script.Events = {
     56     ScriptEdited: "ScriptEdited",
     57     SourceMapURLAdded: "SourceMapURLAdded",
     58 }
     59 
     60 WebInspector.Script.snippetSourceURLPrefix = "snippets:///";
     61 
     62 WebInspector.Script.sourceURLRegex = /\n[\040\t]*\/\/[@#]\ssourceURL=\s*(\S*?)\s*$/mg;
     63 
     64 /**
     65  * @param {string} source
     66  * @return {string}
     67  */
     68 WebInspector.Script._trimSourceURLComment = function(source)
     69 {
     70     return source.replace(WebInspector.Script.sourceURLRegex, "");
     71 }
     72 
     73 
     74 WebInspector.Script.prototype = {
     75     /**
     76      * @return {boolean}
     77      */
     78     isContentScript: function()
     79     {
     80         return this._isContentScript;
     81     },
     82 
     83     /**
     84      * @return {string}
     85      */
     86     contentURL: function()
     87     {
     88         return this.sourceURL;
     89     },
     90 
     91     /**
     92      * @return {!WebInspector.ResourceType}
     93      */
     94     contentType: function()
     95     {
     96         return WebInspector.resourceTypes.Script;
     97     },
     98 
     99     /**
    100      * @param {function(?string)} callback
    101      */
    102     requestContent: function(callback)
    103     {
    104         if (this._source) {
    105             callback(this._source);
    106             return;
    107         }
    108 
    109         /**
    110          * @this {WebInspector.Script}
    111          * @param {?Protocol.Error} error
    112          * @param {string} source
    113          */
    114         function didGetScriptSource(error, source)
    115         {
    116             this._source = WebInspector.Script._trimSourceURLComment(error ? "" : source);
    117             callback(this._source);
    118         }
    119         if (this.scriptId) {
    120             // Script failed to parse.
    121             this.target().debuggerAgent().getScriptSource(this.scriptId, didGetScriptSource.bind(this));
    122         } else
    123             callback("");
    124     },
    125 
    126     /**
    127      * @param {string} query
    128      * @param {boolean} caseSensitive
    129      * @param {boolean} isRegex
    130      * @param {function(!Array.<!PageAgent.SearchMatch>)} callback
    131      */
    132     searchInContent: function(query, caseSensitive, isRegex, callback)
    133     {
    134         /**
    135          * @param {?Protocol.Error} error
    136          * @param {!Array.<!PageAgent.SearchMatch>} searchMatches
    137          */
    138         function innerCallback(error, searchMatches)
    139         {
    140             if (error)
    141                 console.error(error);
    142             var result = [];
    143             for (var i = 0; i < searchMatches.length; ++i) {
    144                 var searchMatch = new WebInspector.ContentProvider.SearchMatch(searchMatches[i].lineNumber, searchMatches[i].lineContent);
    145                 result.push(searchMatch);
    146             }
    147             callback(result || []);
    148         }
    149 
    150         if (this.scriptId) {
    151             // Script failed to parse.
    152             this.target().debuggerAgent().searchInContent(this.scriptId, query, caseSensitive, isRegex, innerCallback);
    153         } else {
    154             callback([]);
    155         }
    156     },
    157 
    158     /**
    159      * @param {string} source
    160      * @return {string}
    161      */
    162     _appendSourceURLCommentIfNeeded: function(source)
    163     {
    164         if (!this.hasSourceURL)
    165             return source;
    166         return source + "\n //# sourceURL=" + this.sourceURL;
    167     },
    168 
    169     /**
    170      * @param {string} newSource
    171      * @param {function(?Protocol.Error, !DebuggerAgent.SetScriptSourceError=, !Array.<!DebuggerAgent.CallFrame>=, !DebuggerAgent.StackTrace=, boolean=)} callback
    172      */
    173     editSource: function(newSource, callback)
    174     {
    175         /**
    176          * @this {WebInspector.Script}
    177          * @param {?Protocol.Error} error
    178          * @param {!DebuggerAgent.SetScriptSourceError=} errorData
    179          * @param {!Array.<!DebuggerAgent.CallFrame>=} callFrames
    180          * @param {!Object=} debugData
    181          * @param {!DebuggerAgent.StackTrace=} asyncStackTrace
    182          */
    183         function didEditScriptSource(error, errorData, callFrames, debugData, asyncStackTrace)
    184         {
    185             // FIXME: support debugData.stack_update_needs_step_in flag by calling WebInspector.debugger_model.callStackModified
    186             if (!error)
    187                 this._source = newSource;
    188             var needsStepIn = !!debugData && debugData["stack_update_needs_step_in"] === true;
    189             callback(error, errorData, callFrames, asyncStackTrace, needsStepIn);
    190             if (!error)
    191                 this.dispatchEventToListeners(WebInspector.Script.Events.ScriptEdited, newSource);
    192         }
    193 
    194         newSource = WebInspector.Script._trimSourceURLComment(newSource);
    195         // We append correct sourceURL to script for consistency only. It's not actually needed for things to work correctly.
    196         newSource = this._appendSourceURLCommentIfNeeded(newSource);
    197 
    198         if (this.scriptId)
    199             this.target().debuggerAgent().setScriptSource(this.scriptId, newSource, undefined, didEditScriptSource.bind(this));
    200         else
    201             callback("Script failed to parse");
    202     },
    203 
    204     /**
    205      * @param {number} lineNumber
    206      * @param {number=} columnNumber
    207      * @return {!WebInspector.DebuggerModel.Location}
    208      */
    209     rawLocation: function(lineNumber, columnNumber)
    210     {
    211         return new WebInspector.DebuggerModel.Location(this.target(), this.scriptId, lineNumber, columnNumber || 0);
    212     },
    213 
    214     /**
    215      * @return {boolean}
    216      */
    217     isInlineScript: function()
    218     {
    219         var startsAtZero = !this.lineOffset && !this.columnOffset;
    220         return !!this.sourceURL && !startsAtZero;
    221     },
    222 
    223     /**
    224      * @param {string} sourceMapURL
    225      */
    226     addSourceMapURL: function(sourceMapURL)
    227     {
    228         if (this.sourceMapURL)
    229             return;
    230         this.sourceMapURL = sourceMapURL;
    231         this.dispatchEventToListeners(WebInspector.Script.Events.SourceMapURLAdded, this.sourceMapURL);
    232     },
    233 
    234     /**
    235      * @return {boolean}
    236      */
    237     isAnonymousScript: function()
    238     {
    239         return !this.sourceURL;
    240     },
    241 
    242     /**
    243      * @return {boolean}
    244      */
    245     isSnippet: function()
    246     {
    247         return !!this.sourceURL && this.sourceURL.startsWith(WebInspector.Script.snippetSourceURLPrefix);
    248     },
    249 
    250     /**
    251      * @return {boolean}
    252      */
    253     isInlineScriptWithSourceURL: function()
    254     {
    255         return !!this.hasSourceURL && this.isInlineScript()
    256     },
    257 
    258     __proto__: WebInspector.SDKObject.prototype
    259 }
    260