stylus/vendor/usercss-meta/usercss-meta.js
2022-03-31 14:00:12 +03:00

1068 lines
28 KiB
JavaScript

var usercssMeta = (function (exports) {
'use strict';
class ParseError extends Error {
constructor(err) {
super(err.message);
delete err.message;
this.name = 'ParseError';
Object.assign(this, err);
}
}
class MissingCharError extends ParseError {
constructor(chars, index) {
super({
code: 'missingChar',
args: chars,
message: `Missing character: ${chars.map(c => `'${c}'`).join(', ')}`,
index
});
}
}
class EOFError extends ParseError {
constructor(index) {
super({
code: 'EOF',
message: 'Unexpected end of file',
index
});
}
}
const RX_EOT = /<<<EOT([\s\S]+?)EOT;/y;
const RX_LINE = /.*/y;
const RX_NUMBER = /-?(\d+(\.\d+)?|\.\d+)([eE]-?\d+)?\s*/y;
const RX_WHITESPACE = /\s*/y;
const RX_WHITESPACE_SAMELINE = /[^\S\n]*/y;
const RX_WORD = /([\w-]+)\s*/y;
const RX_STRING_BACKTICK = /(`(?:\\`|[\s\S])*?`)/y;
const RX_STRING_QUOTED = /((['"])(?:\\\2|[^\n])*?\2|\w+)/y;
const RX_STRING_UNQUOTED = /[^"]*/y;
/** Relaxed semver:
* dot-separated digits sequence e.g. 1 or 1.2 or 1.2.3.4.5
* optional pre-release chunk: "-" followed by dot-separated word characters, "-"
* optional build chunk: "+" followed by dot-separated word characters, "-"
*/
// FIXME: should we allow leading 'v'?
const RX_VERSION = /^v?\d+(\.\d+)*(?:-(\w[-\w]*(\.[-\w]+)*))?(?:\+(\w[-\w]*(\.[-\w]+)*))?$/;
const JSON_PRIME = {
__proto__: null,
'null': null,
'true': true,
'false': false
};
function unescapeComment(s) {
return s.replace(/\*\\\//g, '*/');
}
function unquote(s) {
const q = s[0];
if (q === s[s.length - 1] && (q === '"' || q === "'" || q === '`')) {
// http://www.json.org/
return s.slice(1, -1).replace(
new RegExp(`\\\\([${q}\\\\/bfnrt]|u[0-9a-fA-F]{4})`, 'g'),
s => {
if (s[1] === q) {
return q;
}
return JSON.parse(`"${s}"`);
}
);
}
return unescapeComment(s);
}
function eatLine(state) {
RX_LINE.lastIndex = state.lastIndex;
RX_LINE.exec(state.text);
state.lastIndex = RX_LINE.lastIndex;
}
function eatWhitespace(state) {
RX_WHITESPACE.lastIndex = state.lastIndex;
state.lastIndex += RX_WHITESPACE.exec(state.text)[0].length;
}
function eatSameLineWhitespace(state) {
RX_WHITESPACE_SAMELINE.lastIndex = state.lastIndex;
state.lastIndex += RX_WHITESPACE_SAMELINE.exec(state.text)[0].length;
}
function parseChar(state) {
if (state.lastIndex >= state.text.length) {
throw new EOFError(state.lastIndex);
}
state.index = state.lastIndex;
state.value = state.text[state.lastIndex];
state.lastIndex++;
eatWhitespace(state);
}
function parseWord(state) {
const pos = state.lastIndex;
RX_WORD.lastIndex = pos;
const match = RX_WORD.exec(state.text);
if (!match) {
throw new ParseError({
code: 'invalidWord',
message: 'Invalid word',
index: pos
});
}
state.index = pos;
state.value = match[1];
state.lastIndex += match[0].length;
}
function parseJSON(state) {
const pos = state.lastIndex;
try {
parseJSONValue(state);
} catch (err) {
err.message = `Invalid JSON: ${err.message}`;
throw err;
}
state.index = pos;
}
function parseEOT(state) {
const pos = state.lastIndex;
RX_EOT.lastIndex = pos;
const match = RX_EOT.exec(state.text);
if (!match) {
throw new ParseError({
code: 'missingEOT',
message: 'Missing EOT',
index: pos
});
}
state.index = pos;
state.lastIndex += match[0].length;
state.value = unescapeComment(match[1].trim());
eatWhitespace(state);
}
function parseStringUnquoted(state) {
RX_STRING_UNQUOTED.lastIndex = state.lastIndex;
const match = RX_STRING_UNQUOTED.exec(state.text);
state.index = state.lastIndex;
state.lastIndex = RX_STRING_UNQUOTED.lastIndex;
state.value = match[0].trim().replace(/\s+/g, '-');
}
function parseString(state, sameLine = false) {
const pos = state.lastIndex;
const rx = state.text[pos] === '`' ? RX_STRING_BACKTICK : RX_STRING_QUOTED;
rx.lastIndex = pos;
const match = rx.exec(state.text);
if (!match) {
throw new ParseError({
code: 'invalidString',
message: 'Invalid string',
index: pos
});
}
state.index = pos;
state.lastIndex += match[0].length;
state.value = unquote(match[1]);
if (sameLine) {
eatSameLineWhitespace(state);
} else {
eatWhitespace(state);
}
}
function parseJSONValue(state) {
const {text} = state;
if (text[state.lastIndex] === '{') {
// object
const object = {};
state.lastIndex++;
eatWhitespace(state);
while (text[state.lastIndex] !== '}') {
parseString(state);
const key = state.value;
if (text[state.lastIndex] !== ':') {
throw new MissingCharError([':'], state.lastIndex);
}
state.lastIndex++;
eatWhitespace(state);
parseJSONValue(state);
object[key] = state.value;
if (text[state.lastIndex] === ',') {
state.lastIndex++;
eatWhitespace(state);
} else if (text[state.lastIndex] !== '}') {
throw new MissingCharError([',', '}'], state.lastIndex);
}
}
state.lastIndex++;
eatWhitespace(state);
state.value = object;
} else if (text[state.lastIndex] === '[') {
// array
const array = [];
state.lastIndex++;
eatWhitespace(state);
while (text[state.lastIndex] !== ']') {
parseJSONValue(state);
array.push(state.value);
if (text[state.lastIndex] === ',') {
state.lastIndex++;
eatWhitespace(state);
} else if (text[state.lastIndex] !== ']') {
throw new MissingCharError([',', ']'], state.lastIndex);
}
}
state.lastIndex++;
eatWhitespace(state);
state.value = array;
} else if (text[state.lastIndex] === '"' || text[state.lastIndex] === "'" || text[state.lastIndex] === '`') {
// string
parseString(state);
} else if (/[-\d.]/.test(text[state.lastIndex])) {
// number
parseNumber(state);
} else {
parseWord(state);
if (!(state.value in JSON_PRIME)) {
throw new ParseError({
code: 'unknownJSONLiteral',
args: [state.value],
message: `Unknown literal '${state.value}'`,
index: state.index
});
}
state.value = JSON_PRIME[state.value];
}
}
function parseNumber(state) {
const pos = state.lastIndex;
RX_NUMBER.lastIndex = pos;
const match = RX_NUMBER.exec(state.text);
if (!match) {
throw new ParseError({
code: 'invalidNumber',
message: 'Invalid number',
index: pos
});
}
state.index = pos;
state.value = Number(match[0].trim());
state.lastIndex += match[0].length;
}
function parseStringToEnd(state) {
RX_LINE.lastIndex = state.lastIndex;
const match = RX_LINE.exec(state.text);
const value = match[0].trim();
if (!value) {
throw new ParseError({
code: 'missingValue',
message: 'Missing value',
index: RX_LINE.lastIndex
});
}
state.index = state.lastIndex;
state.value = unquote(value);
state.lastIndex = RX_LINE.lastIndex;
}
function isValidVersion(version) {
return RX_VERSION.test(version);
}
var parseUtil = {
__proto__: null,
eatLine: eatLine,
eatWhitespace: eatWhitespace,
parseChar: parseChar,
parseEOT: parseEOT,
parseJSON: parseJSON,
parseNumber: parseNumber,
parseString: parseString,
parseStringToEnd: parseStringToEnd,
parseStringUnquoted: parseStringUnquoted,
parseWord: parseWord,
unquote: unquote,
isValidVersion: isValidVersion
};
/* eslint-env browser */
// eslint-disable-next-line node/no-unsupported-features/node-builtins
const _export_URL_ = self.URL;
var UNITS = ['em', 'ex', 'cap', 'ch', 'ic', 'rem', 'lh', 'rlh', 'vw', 'vh', 'vi', 'vb', 'vmin', 'vmax', 'cm', 'mm', 'Q', 'in', 'pt', 'pc', 'px', 'deg', 'grad', 'rad', 'turn', 's', 'ms', 'Hz', 'kHz', 'dpi', 'dpcm', 'dppx', '%'];
/**
* Gives you a array with filled with 0...amount - 1.
* @param {number} amount
* @returns {number[]}
*/
function range(amount) {
const range = Array(amount);
for (let i = 0; i < amount; i++) {
range[i] = i;
}
return range;
}
/**
* Check if the amount of edits between firstString and secondString is <= maxEdits.
* It uses the Levenshtein distance algorithm with the two matrix rows variant.
* @param {string} firstString First string to be checked against the other string
* @param {string} secondString Second string to be checked against the other string
* @param {number} maxEdit The maximum amount of edits that these 2 string should have.
* @returns {boolean} indicate if the 2 strings's edits are less or equal to maxEdits
*/
function LevenshteinDistanceWithMax(firstString, secondString, maxEdit) {
const lenOne = firstString.length;
const lenTwo = secondString.length;
const lenDiff = Math.abs(lenOne - lenTwo);
// Are the difference between 2 lengths greater than
// maxEdit, we know to bail out early on.
if (lenDiff > maxEdit) {
return false;
}
let prevRowDistance = range(lenOne + 1);
let currentRowDistance = Array(lenOne + 1);
for (let i = 1; i <= lenTwo; i++) {
// Calculate the current row distances from the previous row.
currentRowDistance[0] = i;
let minDistance = i;
for (let j = 1; j <= lenOne; j++) {
const editCost = firstString[j - 1] === secondString[i - 1] ? 0 : 1;
const addCost = prevRowDistance[j] + 1;
const delCost = currentRowDistance[j - 1] + 1;
const substitionCost = prevRowDistance[j - 1] + editCost;
currentRowDistance[j] = Math.min(addCost, delCost, substitionCost);
if (currentRowDistance[j] < minDistance) {
minDistance = currentRowDistance[j];
}
}
if (minDistance > maxEdit) {
return false;
}
// Swap the vectors
const vtemp = currentRowDistance;
currentRowDistance = prevRowDistance;
prevRowDistance = vtemp;
}
return prevRowDistance[lenOne] <= maxEdit;
}
const UNITS_SET = new Set(UNITS);
const DEFAULT_PARSER = {
name: parseStringToEnd,
version: parseStringToEnd,
namespace: parseStringToEnd,
author: parseStringToEnd,
description: parseStringToEnd,
homepageURL: parseStringToEnd,
supportURL: parseStringToEnd,
updateURL: parseStringToEnd,
license: parseStringToEnd,
preprocessor: parseStringToEnd
};
const DEFAULT_VALIDATOR = {
version: validateVersion,
homepageURL: validateURL,
supportURL: validateURL,
updateURL: validateURL
};
const DEFAULT_VAR_PARSER = {
text: parseStringToEnd,
color: parseStringToEnd,
checkbox: parseChar,
select: parseSelect,
dropdown: {
advanced: parseVarXStyle
},
image: {
var: parseSelect,
advanced: parseVarXStyle
},
number: parseRange,
range: parseRange
};
const DEFAULT_VAR_VALIDATOR = {
checkbox: validateCheckbox,
number: validateRange,
range: validateRange
};
const MANDATORY_META = ['name', 'namespace', 'version'];
const RANGE_PROPS = ['default', 'min', 'max', 'step'];
function parseRange(state) {
parseJSON(state);
const result = {
min: null,
max: null,
step: null,
units: null
};
if (typeof state.value === 'number') {
result.default = state.value;
} else if (Array.isArray(state.value)) {
let i = 0;
for (const item of state.value) {
if (typeof item === 'string') {
if (result.units != null) {
throw new ParseError({
code: 'invalidRangeMultipleUnits',
message: 'units is alredy defined',
args: [state.type],
index: state.valueIndex
});
}
result.units = item;
} else if (typeof item === 'number' || item === null) {
if (i >= RANGE_PROPS.length) {
throw new ParseError({
code: 'invalidRangeTooManyValues',
message: 'the array contains too many values',
args: [state.type],
index: state.valueIndex
});
}
result[RANGE_PROPS[i++]] = item;
} else {
throw new ParseError({
code: 'invalidRangeValue',
message: 'value must be number, string, or null',
args: [state.type],
index: state.valueIndex
});
}
}
} else {
throw new ParseError({
code: 'invalidRange',
message: 'the default value must be an array or a number',
index: state.valueIndex,
args: [state.type]
});
}
state.value = result.default;
Object.assign(state.varResult, result);
}
function parseSelect(state) {
parseJSON(state);
if (typeof state.value !== 'object' || !state.value) {
throw new ParseError({
code: 'invalidSelect',
message: 'The value must be an array or object'
});
}
const options = Array.isArray(state.value) ?
state.value.map(key => createOption(key)) :
Object.keys(state.value).map(key => createOption(key, state.value[key]));
if (new Set(options.map(o => o.name)).size < options.length) {
throw new ParseError({
code: 'invalidSelectNameDuplicated',
message: 'Option name is duplicated'
});
}
if (options.length === 0) {
throw new ParseError({
code: 'invalidSelectEmptyOptions',
message: 'Option list is empty'
});
}
const defaults = options.filter(o => o.isDefault);
if (defaults.length > 1) {
throw new ParseError({
code: 'invalidSelectMultipleDefaults',
message: 'multiple default values'
});
}
options.forEach(o => {
delete o.isDefault;
});
state.varResult.options = options;
state.value = (defaults.length > 0 ? defaults[0] : options[0]).name;
}
function parseVarXStyle(state) {
const pos = state.lastIndex;
if (state.text[state.lastIndex] !== '{') {
throw new MissingCharError(['{'], pos);
}
const options = [];
state.lastIndex++;
while (state.text[state.lastIndex] !== '}') {
const option = {};
parseStringUnquoted(state);
option.name = state.value;
parseString(state);
option.label = state.value;
if (state.type === 'dropdown') {
parseEOT(state);
} else {
parseString(state);
}
option.value = state.value;
options.push(option);
}
state.lastIndex++;
eatWhitespace(state);
if (options.length === 0) {
throw new ParseError({
code: 'invalidSelectEmptyOptions',
message: 'Option list is empty',
index: pos
});
}
if (state.type === 'dropdown') {
state.varResult.type = 'select';
state.type = 'select';
}
state.varResult.options = options;
state.value = options[0].name;
}
function createOption(label, value) {
if (typeof label !== 'string' || value && typeof value !== 'string') {
throw new ParseError({
code: 'invalidSelectValue',
message: 'Values in the object/array must be strings'
});
}
let isDefault = false;
if (label.endsWith('*')) {
isDefault = true;
label = label.slice(0, -1);
}
let name;
const match = label.match(/^(\w+):(.*)/);
if (match) {
([, name, label] = match);
}
if (!name) {
name = label;
}
if (!label) {
throw new ParseError({
code: 'invalidSelectLabel',
message: 'Option label is empty'
});
}
if (value == null) {
value = name;
}
return {name, label, value, isDefault};
}
function collectErrors(fn, errors) {
if (errors) {
try {
fn();
} catch (err) {
errors.push(err);
}
} else {
fn();
}
}
function validateVersion(state) {
if (!isValidVersion(state.value)) {
throw new ParseError({
code: 'invalidVersion',
args: [state.value],
message: `Invalid version: ${state.value}`,
index: state.valueIndex
});
}
state.value = normalizeVersion(state.value);
}
function validateURL(state) {
let url;
try {
url = new _export_URL_(state.value);
} catch (err) {
err.args = [state.value];
err.index = state.valueIndex;
throw err;
}
if (!/^https?:/.test(url.protocol)) {
throw new ParseError({
code: 'invalidURLProtocol',
args: [url.protocol],
message: `Invalid protocol: ${url.protocol}`,
index: state.valueIndex
});
}
}
function validateCheckbox(state) {
if (state.value !== '1' && state.value !== '0') {
throw new ParseError({
code: 'invalidCheckboxDefault',
message: 'value must be 0 or 1',
index: state.valueIndex
});
}
}
function validateRange(state) {
const value = state.value;
if (typeof value !== 'number') {
throw new ParseError({
code: 'invalidRangeDefault',
message: `the default value of @var ${state.type} must be a number`,
index: state.valueIndex,
args: [state.type]
});
}
const result = state.varResult;
if (result.min != null && value < result.min) {
throw new ParseError({
code: 'invalidRangeMin',
message: 'the value is smaller than the minimum',
index: state.valueIndex,
args: [state.type]
});
}
if (result.max != null && value > result.max) {
throw new ParseError({
code: 'invalidRangeMax',
message: 'the value is larger than the maximum',
index: state.valueIndex,
args: [state.type]
});
}
if (
result.step != null &&
[value, result.min, result.max]
.some(n => n != null && !isMultipleOf(n, result.step))
) {
throw new ParseError({
code: 'invalidRangeStep',
message: 'the value is not a multiple of the step',
index: state.valueIndex,
args: [state.type]
});
}
if (result.units && !UNITS_SET.has(result.units)) {
throw new ParseError({
code: 'invalidRangeUnits',
message: `Invalid CSS unit: ${result.units}`,
index: state.valueIndex,
args: [state.type, result.units]
});
}
}
function isMultipleOf(value, step) {
const n = Math.abs(value / step);
const nInt = Math.round(n);
// IEEE 754 double-precision numbers can reliably store 15 decimal digits
// of which some are already occupied by the integer part
return Math.abs(n - nInt) < Math.pow(10, (`${nInt}`.length - 16));
}
function createParser({
unknownKey = 'ignore',
mandatoryKeys = MANDATORY_META,
parseKey: userParseKey,
parseVar: userParseVar,
validateKey: userValidateKey,
validateVar: userValidateVar,
allowErrors = false
} = {}) {
if (!['ignore', 'assign', 'throw'].includes(unknownKey)) {
throw new TypeError("unknownKey must be 'ignore', 'assign', or 'throw'");
}
const parser = Object.assign(Object.create(null), DEFAULT_PARSER, userParseKey);
const keysOfParser = [...Object.keys(parser), 'advanced', 'var'];
const varParser = Object.assign({}, DEFAULT_VAR_PARSER, userParseVar);
const validator = Object.assign({}, DEFAULT_VALIDATOR, userValidateKey);
const varValidator = Object.assign({}, DEFAULT_VAR_VALIDATOR, userValidateVar);
return {parse, validateVar};
function validateVar(varObject) {
const state = {
key: 'var',
type: varObject.type,
value: varObject.value,
varResult: varObject
};
_validateVar(state);
}
function _validateVar(state) {
const validate = typeof varValidator[state.type] === 'object' ?
varValidator[state.type][state.key] : varValidator[state.type];
if (validate) {
validate(state);
}
}
function parseVar(state) {
const result = {
type: null,
label: null,
name: null,
value: null,
default: null,
options: null
};
state.varResult = result;
parseWord(state);
state.type = state.value;
result.type = state.type;
const doParse = typeof varParser[state.type] === 'object' ?
varParser[state.type][state.key] : varParser[state.type];
if (!doParse) {
throw new ParseError({
code: 'unknownVarType',
message: `Unknown @${state.key} type: ${state.type}`,
args: [state.key, state.type],
index: state.index
});
}
parseWord(state);
result.name = state.value;
parseString(state, true);
result.label = state.value;
state.valueIndex = state.lastIndex;
doParse(state);
_validateVar(state);
result.default = state.value;
if (!state.usercssData.vars) {
state.usercssData.vars = {};
}
state.usercssData.vars[result.name] = result;
if (state.key === 'advanced') {
state.maybeUSO = true;
}
}
function parse(text) {
if (text.includes('\r')) {
throw new TypeError("metadata includes invalid character: '\\r'");
}
const usercssData = {};
const errors = [];
const re = /@([\w-]+)[^\S\r\n]*/gm;
const state = {
index: 0,
lastIndex: 0,
text,
usercssData,
warn: err => errors.push(err)
};
// parse
let match;
while ((match = re.exec(text))) {
state.index = match.index;
state.lastIndex = re.lastIndex;
state.key = match[1];
state.shouldIgnore = false;
collectErrors(() => {
try {
if (state.key === 'var' || state.key === 'advanced') {
parseVar(state);
} else {
parseKey(state);
}
} catch (err) {
if (err.index === undefined) {
err.index = state.index;
}
throw err;
}
if (state.key !== 'var' && state.key !== 'advanced' && !state.shouldIgnore) {
usercssData[state.key] = state.value;
}
}, allowErrors && errors);
re.lastIndex = state.lastIndex;
}
if (state.maybeUSO && !usercssData.preprocessor) {
usercssData.preprocessor = 'uso';
}
collectErrors(() => {
const missing = mandatoryKeys.filter(k =>
!Object.prototype.hasOwnProperty.call(usercssData, k) || !usercssData[k]
);
if (missing.length > 0) {
throw new ParseError({
code: 'missingMandatory',
args: missing,
message: `Missing metadata: ${missing.map(k => `@${k}`).join(', ')}`
});
}
}, allowErrors && errors);
return {
metadata: usercssData,
errors
};
}
function parseKey(state) {
let doParse = parser[state.key];
if (!doParse) {
if (unknownKey === 'assign') {
doParse = parseStringToEnd;
} else {
eatLine(state);
if (unknownKey === 'ignore') {
state.shouldIgnore = true;
return;
}
// TODO: Suggest the item with the smallest distance or even multiple results?
// Implementation note: swtich to Levenshtein automaton variation.
const MAX_EDIT = Math.log2(state.key.length);
const maybeSuggestion = keysOfParser.find(metaKey => LevenshteinDistanceWithMax(metaKey, state.key, MAX_EDIT));
// throw
throw new ParseError({
code: 'unknownMeta',
args: [state.key, maybeSuggestion],
message: `Unknown metadata: @${state.key}${maybeSuggestion ? `, did you mean @${maybeSuggestion}?` : ''}`,
index: state.index
});
}
}
state.valueIndex = state.lastIndex;
doParse(state);
if (validator[state.key]) {
validator[state.key](state);
}
}
}
function normalizeVersion(version) {
// https://docs.npmjs.com/misc/semver#versions
if (version[0] === 'v' || version[0] === '=') {
return version.slice(1);
}
return version;
}
const _export_parse_ = function (text, options) {
return createParser(options).parse(text);
};
function createStringifier({
alignKeys = false,
space = 2,
format = 'stylus',
stringifyKey: userStringifyKey = {},
stringifyVar: userStringifyVar = {}
} = {}) {
function stringify(meta) {
let varKey;
if (format === 'stylus') {
varKey = 'var';
} else if (format === 'xstyle') {
varKey = 'advanced';
} else {
throw new TypeError("options.format must be 'stylus' or 'xstyle'");
}
const lines = [];
for (const key of Object.keys(meta)) {
const value = meta[key];
if (Object.prototype.hasOwnProperty.call(userStringifyKey, key)) {
const result = userStringifyKey[key](value);
if (Array.isArray(result)) {
lines.push.apply(lines, result.map(v => [key, v]));
} else {
lines.push([key, result]);
}
} else if (key === 'vars') {
for (const va of Object.values(value)) {
lines.push([varKey, stringifyVar(va, format, userStringifyVar, space)]);
}
} else if (Array.isArray(value)) {
for (const subLine of value) {
lines.push([key, quoteIfNeeded(subLine)]);
}
} else {
lines.push([key, quoteIfNeeded(value)]);
}
}
const maxKeyLength = alignKeys ? Math.max.apply(null, lines.map(l => l[0].length)) : 0;
return `/* ==UserStyle==\n${
escapeComment(lines.map(([key, text]) => `@${key.padEnd(maxKeyLength)} ${text}`).join('\n'))
}\n==/UserStyle== */`;
}
return {stringify};
}
function stringifyVar(va, format, userStringifyVar, space) {
return `${vaType()} ${va.name} ${JSON.stringify(va.label)} ${vaDefault()}`;
function vaType() {
if (format === 'xstyle' && va.type === 'select') {
return 'dropdown';
}
return va.type;
}
function vaDefault() {
if (Object.prototype.hasOwnProperty.call(userStringifyVar, va.type)) {
return userStringifyVar[va.type](va, format, space);
}
if (va.options) {
if (format === 'stylus') {
return JSON.stringify(va.options.reduce((object, opt) => {
const isDefault = opt.name === va.default ? '*' : '';
object[`${opt.name}:${opt.label}${isDefault}`] = opt.value;
return object;
}, {}), null, space);
}
return stringifyEOT(va.options, va.type === 'image', space);
}
if (va.type === 'text' && format === 'xstyle') {
return JSON.stringify(va.default);
}
if (va.type === 'number' || va.type === 'range') {
const output = [va.default, va.min, va.max, va.step];
if (va.units) {
output.push(va.units);
}
return JSON.stringify(output);
}
return va.default;
}
}
function quoteIfNeeded(text) {
if (typeof text === 'string' && text.includes('\n')) {
return JSON.stringify(text);
}
return text;
}
function escapeComment(text) {
return text.replace(/\*\//g, '*\\/');
}
function stringifyEOT(options, singleLine = false, space = 0) {
const pad = typeof space === 'string' ? space : ' '.repeat(space);
return `{\n${options.map(
o => `${pad}${o.name} ${JSON.stringify(o.label)} ${oValue(o.value)}`
).join('\n')}\n}`;
function oValue(value) {
if (singleLine) {
return JSON.stringify(value);
}
return `<<<EOT\n${value} EOT;`;
}
}
const _export_stringify_ = function (meta, options) {
return createStringifier(options).stringify(meta);
};
exports.ParseError = ParseError;
exports.createParser = createParser;
exports.createStringifier = createStringifier;
exports.parse = _export_parse_;
exports.stringify = _export_stringify_;
exports.util = parseUtil;
Object.defineProperty(exports, '__esModule', { value: true });
return exports;
}({}));