Changeset 625

Show
Ignore:
Timestamp:
01/19/08 14:13:14 (11 months ago)
Author:
oyasu..@gmail.com
Message:

Refactoring: centralizing @header parsing code to utils.js::GM_parseScriptHeaders, in preparation of improved @require/@resource handling. Still no functional changes, though; it's just as incomplete as it ever was.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • branches/jhs1/chrome/chromeFiles/content/config.js

    r548 r625  
    283283}; 
    284284 
    285 function ScriptDependency()
    286   this.url = null 
     285function ScriptDependency(url)
     286  this.url = url || null; 
    287287  this.file = null; 
    288288  this.filename = null; 
    289289}; 
    290290 
    291 function ScriptResource()
    292   this.url = null; 
    293   this.name = null; 
     291function ScriptResource(name, url)
     292  this.url = url || null; 
     293  this.name = name || null; 
    294294  this.file = null; 
    295295  this.filename = null; 
  • branches/jhs1/chrome/chromeFiles/content/scriptdownloader.js

    r609 r625  
    227227 
    228228ScriptDownloader.prototype.parseScript = function(source, uri) { 
     229  function resolveURL(url, baseurl) { 
     230    url = ioservice.newURI(url, null, baseurl); 
     231    return url.spec; 
     232  } 
    229233  var ioservice = Components.classes["@mozilla.org/network/io-service;1"] 
    230234                            .getService(); 
     
    233237  script.uri = uri; 
    234238  script.enabled = true; 
    235   script.includes = []; 
    236   script.excludes = []; 
    237  
    238   // read one line at a time looking for start meta delimiter or EOF 
    239   var lines = source.match(/.+/g); 
    240   var lnIdx = 0; 
    241   var result = {}; 
    242   var foundMeta = false; 
    243  
    244   while ((result = lines[lnIdx++])) { 
    245     if (result.indexOf("// ==UserScript==") == 0) { 
    246       foundMeta = true; 
    247       break; 
    248     } 
    249   } 
    250  
    251   // gather up meta lines 
    252   if (foundMeta) { 
    253     // used for duplicate resource name detection 
    254     var previousResourceNames = {}; 
    255  
    256     while ((result = lines[lnIdx++])) { 
    257       if (result.indexOf("// ==/UserScript==") == 0) { 
    258         break; 
     239  var headers = GM_parseScriptHeaders(source, { 
     240    // verbatim string, last value only: 
     241    name:1, 
     242    namespace:1, 
     243    description:1, 
     244 
     245    // verbatim array of strings, all occurrences: 
     246    include:0, 
     247    exclude:0, 
     248 
     249    // derived data, all occurrences: 
     250    require:function(url, prior) { 
     251      url = resolveURL(url, uri); 
     252      if (url == uri.spec) 
     253        return null; 
     254      for (var i = 0; i < prior.length; i++) { 
     255        var seen = prior[i]; 
     256        if (seen && seen.url == url) 
     257          return null; 
    259258      } 
    260  
    261       var match = result.match(/\/\/ \@(\S+)\s+([^\n]+)/); 
    262       if (match != null) { 
    263         switch (match[1]) { 
    264           case "name": 
    265           case "namespace": 
    266           case "description": 
    267             script[match[1]] = match[2]; 
    268             break; 
    269           case "include": 
    270           case "exclude": 
    271             script[match[1]+"s"].push(match[2]); 
    272             break; 
    273           case "require": 
    274             var reqUri = ioservice.newURI(match[2], null, uri); 
    275             var scriptDependency = new ScriptDependency(); 
    276             scriptDependency.url = reqUri.spec; 
    277             script.requires.push(scriptDependency); 
    278             break; 
    279           case "resource": 
    280             var res = match[2].match(/(\S+)\s+(.*)/); 
    281             if (res === null) { 
    282               // NOTE: Unlocalized strings 
    283               throw new Error("Invalid syntax for @resource declaration '" + 
    284                               match[2] + "'. Resources are declared like: " + 
    285                               "@resource <name> <url>."); 
    286             } 
    287  
    288             var resName = res[1]; 
    289             if (previousResourceNames[resName]) { 
    290               throw new Error("Duplicate resource name '" + resName + "' " + 
    291                               "detected. Each resource must have a unique " + 
    292                               "name."); 
    293             } else { 
    294               previousResourceNames[resName] = true; 
    295             } 
    296  
    297             var resUri = ioservice.newURI(res[2], null, uri); 
    298             var scriptResource = new ScriptResource(); 
    299             scriptResource.name = resName; 
    300             scriptResource.url = resUri.spec; 
    301             script.resources.push(scriptResource); 
    302             break; 
    303         } 
     259      return new ScriptDependency(url); 
     260    }, 
     261    resource:function(name_url, prior) { 
     262      var args = name_url.match(/(\S+)\s+(.*)/); 
     263      if (args === null) { 
     264        throw new Error("Invalid syntax for @resource declaration '" + 
     265                        name_url + "'. Resources are declared like: " + 
     266                        "@resource <name> <url>."); // TODO: i18n 
    304267      } 
    305     } 
    306   } 
    307  
    308   // if no meta info, default to reasonable values 
    309   if (script.name == null) { 
    310     script.name = parseScriptName(uri); 
    311   } 
    312  
    313   if (script.namespace == null) { 
    314     script.namespace = uri.host; 
    315   } 
    316  
    317   if (script.includes.length == 0) { 
    318     script.includes.push("*"); 
    319   } 
     268      var name = args[1]; 
     269      for (var i = 0; i < prior.length; i++) { 
     270        if (prior[i].name == name) 
     271          throw new Error("Duplicate resource name '" + resName + "' " + 
     272                          "detected. Each resource must have a unique " + 
     273                          "name."); // TODO: i18n 
     274      } 
     275      var url = args[2]; 
     276      return new ScriptResource(name, resolveURL(url, uri)); 
     277    } 
     278  }); 
     279 
     280  script.name = headers.name || parseScriptName(uri); 
     281  script.namespace = headers.namespace || uri.host; 
     282  script.description = headers.description || ""; 
     283  script.includes = headers.include || ["*"]; 
     284  script.excludes = headers.exclude || []; 
     285  script.requires = (headers.require || []).filter(function(r) { return r; }); 
     286  script.resources = headers.resource || []; 
    320287 
    321288  this.script = script; 
  • branches/jhs1/chrome/chromeFiles/content/utils.js

    r621 r625  
    474474}; 
    475475 
     476/** 
     477 * Returns true if the given script should be invoked on url, otherwise false. 
     478 */ 
    476479function GM_scriptMatchesUrl(script, url) { 
    477480  for (var i = 0, glob; glob = script.includes[i]; i++) { 
     
    488491  return false; 
    489492} 
     493 
     494/** 
     495 * Returns an associative array from header name (sans @ prefix) to value. 
     496 * Values are arrays, unless headerSpec[name] was 1, in which case the value 
     497 * is a string only (the value of the last header with that name). 
     498 * 
     499 * If, instead of 1, a callback function is provided, the return value of that 
     500 * callback is becomes appended to the array instead. This callback is invoked 
     501 * with two arguments: the raw header, and the array with all prior callback 
     502 * results for this header (or the empty array). 
     503 * 
     504 * oldHeaders (optional) is used as the target object headers are appended to. 
     505 */ 
     506function GM_parseScriptHeaders(source, headerSpec, oldHeaders) { 
     507  var headerRe = /.*/; 
     508  if (headerSpec) { 
     509    var allHeaders = []; 
     510    for (var header in headerSpec) 
     511      allHeaders.push(header); 
     512    headerRe = new RegExp("^(" + allHeaders.join("|") + ")$"); 
     513  } 
     514 
     515  // read one line at a time looking for start meta delimiter or EOF 
     516  var lines = source.match(/.+/g); 
     517  var lnIdx = 0; 
     518  var result; 
     519  var foundMeta = false; 
     520  var headers = oldHeaders || {}; 
     521 
     522  while ((result = lines[lnIdx++])) { 
     523    if (result.indexOf("// ==UserScript==") == 0) { 
     524      GM_log("* found metadata"); 
     525      foundMeta = true; 
     526      break; 
     527    } 
     528  } 
     529 
     530  // gather up meta lines 
     531  if (foundMeta) { 
     532    while ((result = lines[lnIdx++])) { 
     533      if (result.indexOf("// ==/UserScript==") == 0) { 
     534        break; 
     535      } 
     536 
     537      var match = result.match(/\/\/ \@(\S+)\s+([^\n]+)/); 
     538      if (match != null) { 
     539        var name = match[1], value = match[2]; 
     540        if (!name.match(headerRe)) 
     541          continue; 
     542        if (headerSpec && headerSpec[name] == 1) { 
     543          headers[name] = value; // only wanted the last value 
     544        } 
     545        else { // want an array of all values 
     546          if (!headers.hasOwnProperty(name)) 
     547            headers[name] = []; 
     548          var callback = headerSpec && headerSpec[name] || 
     549            function(header) { return header; }; 
     550          headers[name].push(callback(value, headers[name])); 
     551        } 
     552      } 
     553    } 
     554  } 
     555  return headers; 
     556};