You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
140 lines
2.9 KiB
140 lines
2.9 KiB
const valueParser = require("postcss-value-parser"); |
|
|
|
const { stringify } = valueParser; |
|
|
|
function getUrl(nodes) { |
|
let url = ""; |
|
let urlEnd = 0; |
|
|
|
for (let i = 0; i < nodes.length; i += 1) { |
|
const node = nodes[i]; |
|
if (node.type === "string") { |
|
if (i !== 0) { |
|
throw Error(`Invalid "svg-load(${stringify(nodes)})" definition`); |
|
} |
|
url = node.value; |
|
urlEnd = i + 1; |
|
break; |
|
} |
|
if (node.type === "div" && node.value === ",") { |
|
if (i === 0) { |
|
throw Error(`Invalid "svg-load(${stringify(nodes)})" definition`); |
|
} |
|
urlEnd = i; |
|
break; |
|
} |
|
url += stringify(node); |
|
urlEnd += 1; |
|
} |
|
|
|
return { |
|
url, |
|
urlEnd |
|
}; |
|
} |
|
|
|
function getParamChunks(nodes) { |
|
const list = []; |
|
const lastArg = nodes.reduce((arg, node) => { |
|
if (node.type === "word" || node.type === "string") { |
|
return arg + node.value; |
|
} |
|
if (node.type === "space") { |
|
return arg + " "; |
|
} |
|
if (node.type === "div" && node.value === ",") { |
|
list.push(arg); |
|
return ""; |
|
} |
|
return arg + stringify(node); |
|
}, ""); |
|
|
|
return list.concat(lastArg); |
|
} |
|
|
|
function splitParams(list) { |
|
const params = {}; |
|
|
|
list.reduce((sep, arg) => { |
|
if (!arg) { |
|
throw Error(`Expected parameter`); |
|
} |
|
|
|
if (!sep) { |
|
if (arg.indexOf(":") !== -1) { |
|
sep = ":"; |
|
} else if (arg.indexOf("=") !== -1) { |
|
sep = "="; |
|
} else { |
|
throw Error(`Expected ":" or "=" separator in "${arg}"`); |
|
} |
|
} |
|
|
|
const pair = arg.split(sep); |
|
if (pair.length !== 2) { |
|
throw Error(`Expected "${sep}" separator in "${arg}"`); |
|
} |
|
params[pair[0].trim()] = pair[1].trim(); |
|
|
|
return sep; |
|
}, null); |
|
|
|
return params; |
|
} |
|
|
|
function getLoader(parsedValue, valueNode) { |
|
if (!valueNode.nodes.length) { |
|
throw Error(`Invalid "svg-load()" statement`); |
|
} |
|
|
|
// parse url |
|
const { url, urlEnd } = getUrl(valueNode.nodes); |
|
|
|
// parse params |
|
const paramsNodes = valueNode.nodes.slice(urlEnd + 1); |
|
const params = |
|
urlEnd !== valueNode.nodes.length |
|
? splitParams(getParamChunks(paramsNodes)) |
|
: {}; |
|
|
|
return { |
|
url, |
|
params, |
|
valueNode, |
|
parsedValue |
|
}; |
|
} |
|
|
|
function getInliner(parsedValue, valueNode) { |
|
if (!valueNode.nodes.length) { |
|
throw Error(`Invalid "svg-inline()" statement`); |
|
} |
|
const name = valueNode.nodes[0].value; |
|
|
|
return { |
|
name, |
|
valueNode, |
|
parsedValue |
|
}; |
|
} |
|
|
|
module.exports = function parseDeclValue(value) { |
|
const loaders = []; |
|
const inliners = []; |
|
const parsedValue = valueParser(value); |
|
|
|
parsedValue.walk(valueNode => { |
|
if (valueNode.type === "function") { |
|
if (valueNode.value === "svg-load") { |
|
loaders.push(getLoader(parsedValue, valueNode)); |
|
} else if (valueNode.value === "svg-inline") { |
|
inliners.push(getInliner(parsedValue, valueNode)); |
|
} |
|
} |
|
}); |
|
|
|
return { |
|
loaders, |
|
inliners |
|
}; |
|
};
|
|
|