better directory layout; unification with non-bootstrapping addons
[guerillascript.git] / main / modules / utils / metaparser.js
blobab35cc7257a2a461ea492930b75d7eda9af5d626
1 /* coded by Ketmar // Invisible Vector (psyc://ketmar.no-ip.org/~Ketmar)
2 * Understanding is not required. Only obedience.
4 * This program is free software. It comes without any warranty, to
5 * the extent permitted by applicable law. You can redistribute it
6 * and/or modify it under the terms of the Do What The Fuck You Want
7 * To Public License, Version 2, as published by Sam Hocevar. See
8 * http://www.wtfpl.net/txt/copying/ for more details.
9 */
10 ////////////////////////////////////////////////////////////////////////////////
11 const wholeMetaRE = /^\s*\/\/\s*==UserScript==\s*([\s\S]*?)^\/\/\s*==\/UserScript==/m;
12 const metakvRE = /^\s*@(\S+)\s+(.+?)\s*$/;
13 const metakeyRE = /^\s*@(\S+)\s*$/;
16 // return array of {name, value} objects; value can be null
17 // special: resource value is {name, url}
18 function parseMeta (text) {
19 let res = new Array();
20 // get the stuff between ==UserScript== lines
21 let mt = text.match(wholeMetaRE);
22 if (!mt) return res;
23 let meta = mt[1].replace(/^\s+/, "");
24 for (let line of meta.split("\n")) {
25 // remove slashes
26 if (line.length < 2 || line[0] != "/" || line[1] != "/") continue;
27 line = line.substr(2);
28 let obj = {};
29 let kv = line.match(metakvRE);
30 if (!kv) {
31 kv = line.match(metakeyRE);
32 if (!kv) continue;
33 obj.name = kv[1];
34 obj.value = null;
35 } else {
36 obj.name = kv[1];
37 obj.value = kv[2];
38 if (kv[1] === "resource") {
39 mt = kv[2].match(/^(\S+)\s+(.+)$/);
40 if (mt) obj.value = {name:mt[1], url:mt[2]};
43 res.push(obj);
45 // utilities
46 function isNameEqual (name, pattern) {
47 return (typeof(pattern) === "string" ? name == pattern : pattern.indexOf(name) >= 0);
49 // add methods
50 // get first field with name `name`
51 res.getField = function (name) {
52 for (let kv of this) if (isNameEqual(kv.name, name)) return kv;
53 return null;
55 // get last field with name `name`
56 res.getLastField = function (name) {
57 for (let idx = this.length-1; idx >= 0; --idx) {
58 let kv = this[idx];
59 if (isNameEqual(kv.name, name)) return kv;
61 return null;
63 // for each field with given name
64 // if callbacks return something except undefined, null or false -- exit with this value
65 // callback: {string name, string value}; value can be null for value-less fields
66 res.forEachField = function (name, cb) {
67 for (let kv of this) {
68 if (isNameEqual(kv.name, name)) {
69 let res = cb(kv);
70 if (typeof(res) !== "undefined") {
71 if (res !== false && res !== null) return res;
75 return undefined;
77 // get all fields as array of {name, value}
78 res.getFields = function (name) {
79 let res = new Array();
80 for (let kv of this) if (isNameEqual(kv.name, name)) res.push(kv);
81 return res;
83 return res;
87 ////////////////////////////////////////////////////////////////////////////////
88 exports.parseMeta = parseMeta;