Add: parse more metas, add variable type

This commit is contained in:
eight 2017-09-05 08:16:08 +08:00
parent b3b47697ca
commit 78264a1c34

View File

@ -4,6 +4,12 @@
// eslint-disable-next-line no-var // eslint-disable-next-line no-var
var usercss = (function () { var usercss = (function () {
const METAS = [
'author', 'description', 'homepageURL', 'icon', 'license', 'name',
'namespace', 'noframes', 'preprocessor', 'supportURL', 'var', 'version'
];
// FIXME: use a real semver module
function semverTest(a, b) { function semverTest(a, b) {
a = a.split('.').map(Number); a = a.split('.').map(Number);
b = b.split('.').map(Number); b = b.split('.').map(Number);
@ -27,23 +33,6 @@ var usercss = (function () {
return 0; return 0;
} }
function guessType(value) {
if (/^url\(.+\)$/i.test(value)) {
return 'image';
}
if (/^#[0-9a-f]{3,8}$/i.test(value)) {
return 'color';
}
if (/^hsla?\(.+\)$/i.test(value)) {
return 'color';
}
if (/^rgba?\(.+\)$/i.test(value)) {
return 'color';
}
// should we use a color-name table to guess type?
return 'text';
}
const BUILDER = { const BUILDER = {
default: { default: {
postprocess(sections, vars) { postprocess(sections, vars) {
@ -102,6 +91,70 @@ var usercss = (function () {
return style; return style;
} }
function *parseMetas(source) {
for (const line of source.split(/\r?\n/)) {
const match = line.match(/@(\w+)/);
if (!match) {
continue;
}
yield [match[1], line.slice(match.index + match[0].length).trim()];
}
}
function matchString(s) {
const match = matchFollow(s, /^(?:\w+|(['"])(?:\\\1|.)*?\1)/);
match.value = match[1] ? match[0].slice(1, -1) : match[0];
return match;
}
function matchFollow(s, re) {
const match = s.match(re);
match.follow = s.slice(match.index + match[0].length).trim();
return match;
}
// FIXME: need color converter
function normalizeColor(color) {
return color;
}
function parseVar(source) {
const result = {
label: null,
name: null,
value: null,
default: null,
select: null
};
{
// type & name
const match = matchFollow(source, /^([\w-]+)\s+([\w-]+)/);
([, result.type, result.name] = match);
source = match.follow;
}
{
// label
const match = matchString(source);
result.label = match.value;
source = match.follow;
}
// value
if (result.type === 'color') {
source = normalizeColor(source);
} else if (result.type === 'select') {
const match = matchString(source);
result.select = JSON.parse(match.follow);
source = match.value;
}
result.default = source;
return result;
}
function _buildMeta(source) { function _buildMeta(source) {
const style = { const style = {
name: null, name: null,
@ -111,52 +164,27 @@ var usercss = (function () {
enabled: true, enabled: true,
sections: [], sections: [],
vars: {}, vars: {},
preprocessor: null preprocessor: null,
noframes: false
}; };
const metaSource = getMetaSource(source); const metaSource = getMetaSource(source);
const match = (re, callback) => { for (const [key, value] of parseMetas(metaSource)) {
let m; if (!METAS.includes(key)) {
if (!re.global) { continue;
if ((m = metaSource.match(re))) {
if (m.length === 1) {
callback(m[0]);
} else {
callback(...m.slice(1));
}
}
} else {
const result = [];
while ((m = re.exec(metaSource))) {
if (m.length <= 2) {
result.push(m[m.length - 1]);
} else {
result.push(m.slice(1));
}
}
if (result.length) {
callback(result);
}
} }
}; if (key === 'noframes') {
style.noframes = true;
// FIXME: finish all metas } else if (key === 'var') {
match(/@name[^\S\r\n]+(.+?)[^\S\r\n]*$/m, m => (style.name = m)); const va = parseVar(value);
match(/@namespace[^\S\r\n]+(\S+)/, m => (style.namespace = m)); style.vars[va.name] = va;
match(/@preprocessor[^\S\r\n]+(\S+)/, m => (style.preprocessor = m)); } else if (key === 'homepageURL') {
match(/@version[^\S\r\n]+(\S+)/, m => (style.version = m)); style.url = value;
match( } else {
/@var[^\S\r\n]+(\S+)[^\S\r\n]+(?:(['"])((?:\\\2|.)*?)\2|(\S+))[^\S\r\n]+(.+?)[^\S\r\n]*$/gm, style[key] = value;
ms => ms.forEach(([key,, label1, label2, value]) => ( }
style.vars[key] = { }
type: guessType(value),
label: label1 || label2,
value: null, // '.value' holds the value set by users.
default: value // '.default' holds the value extract from meta.
}
))
);
return style; return style;
} }
@ -212,6 +240,7 @@ var usercss = (function () {
throw new Error(chrome.i18n.getMessage('styleMissingMeta', prop)); throw new Error(chrome.i18n.getMessage('styleMissingMeta', prop));
} }
} }
// FIXME: validate variable formats
} }
return {buildMeta, buildCode, semverTest}; return {buildMeta, buildCode, semverTest};