diff options
-rwxr-xr-x | upd8.js | 307 |
1 files changed, 155 insertions, 152 deletions
diff --git a/upd8.js b/upd8.js index 3bb2e018..7b66215e 100755 --- a/upd8.js +++ b/upd8.js @@ -971,202 +971,205 @@ const replacerSpec = { \]\] // Closing ]]. `, 'g'); - transformInline.parse = function(input) { - const makeNode = (i, type, props) => ({i, type, ...props}); - const makeError = (i, message) => makeNode(i, 'error', {message}); - const endOfInput = (i, comment) => makeError(i, `Unexpected end of input (${comment}).`); - - let stopped, - stop_iMatch, - stop_iParse, - stop_literal; - - const parseOneTextNode = function(i, opts) { - const nodes = parseNodes(i, { - ...opts, - textOnly: true - }); + // Syntax literals. + const tagBeginning = '[['; + const tagEnding = ']]'; + const tagReplacerValue = ':'; + const tagArgument = '*'; + const tagArgumentValue = '='; + const tagLabel = '|'; + + const makeNode = (i, type, props) => ({i, type, ...props}); + const makeError = (i, message) => makeNode(i, 'error', {message}); + const endOfInput = (i, comment) => makeError(i, `Unexpected end of input (${comment}).`); + + // These are 8asically stored on the glo8al scope, which might seem odd + // for a recursive function, 8ut the values are only ever used immediately + // after they're set. + let stopped, + stop_iMatch, + stop_iParse, + stop_literal; + + const parseOneTextNode = function(input, i, opts) { + const nodes = parseNodes(input, i, { + ...opts, + textOnly: true + }); - return ( - nodes.length === 0 ? null : - nodes.length === 1 ? nodes[0] : - makeNode(i, 'text', { - string: nodes.map(node => node.string).join(' ') - }) - ); - }; + return ( + nodes.length === 0 ? null : + nodes.length === 1 ? nodes[0] : + makeNode(i, 'text', { + string: nodes.map(node => node.string).join(' ') + }) + ); + }; - const parseNodes = function(i, { - stopAt = null, - textOnly = false - } = {}) { - let nodes = []; - let escapeNext = false; - let string = ''; - let iString = 0; - - // Syntax literals. - const tagBeginning = '[['; - const tagEnding = ']]'; - const tagReplacerValue = ':'; - const tagArgument = '*'; - const tagArgumentValue = '='; - const tagLabel = '|'; - - const pushNode = (...args) => nodes.push(makeNode(...args)); - const pushTextNode = () => { - if (string.length) { - pushNode(iString, 'text', {string}); - string = ''; - } - }; + const parseNodes = function(input, i, { + stopAt = null, + textOnly = false + } = {}) { + let nodes = []; + let escapeNext = false; + let string = ''; + let iString = 0; + + const pushNode = (...args) => nodes.push(makeNode(...args)); + const pushTextNode = () => { + if (string.length) { + pushNode(iString, 'text', {string}); + string = ''; + } + }; - while (i < input.length) { - if (escapeNext) { - string += input[i]; - i++; - continue; - } + while (i < input.length) { + if (escapeNext) { + string += input[i]; + i++; + continue; + } - if (input[i] === '\\') { - escapeNext = true; - i++; - continue; - } + if (input[i] === '\\') { + escapeNext = true; + i++; + continue; + } - if (stopAt) { - for (const literal of stopAt) { - if (input.slice(i, i + literal.length) === literal) { - pushTextNode(); - stopped = true; - stop_iMatch = i; - stop_iParse = i + literal.length; - stop_literal = literal; - return nodes; - } + if (stopAt) { + for (const literal of stopAt) { + if (input.slice(i, i + literal.length) === literal) { + pushTextNode(); + stopped = true; + stop_iMatch = i; + stop_iParse = i + literal.length; + stop_literal = literal; + return nodes; } } + } - if (input.slice(i, i + tagBeginning.length) === tagBeginning) { - if (textOnly) - throw makeError(i, `Unexpected [[tag]] - expected only text here.`); + if (input.slice(i, i + tagBeginning.length) === tagBeginning) { + if (textOnly) + throw makeError(i, `Unexpected [[tag]] - expected only text here.`); - pushTextNode(); - const iTag = i; - i += tagBeginning.length; + pushTextNode(); + const iTag = i; + i += tagBeginning.length; - let N; + let N; - // Replacer key (or value) + // Replacer key (or value) - N = parseOneTextNode(i, { - stopAt: [tagReplacerValue, tagArgument, tagLabel, tagEnding] - }); + N = parseOneTextNode(input, i, { + stopAt: [tagReplacerValue, tagArgument, tagLabel, tagEnding] + }); - if (!stopped) throw endOfInput(i, `reading replacer key`); + if (!stopped) throw endOfInput(i, `reading replacer key`); - if (!N) { - switch (stop_literal) { - case tagReplacerValue: - case tagArgument: - case tagLabel: - throw makeError(i, `Expected text (replacer key).`); - case tagEnding: - throw makeError(i, `Expected text (replacer key/value).`); - } + if (!N) { + switch (stop_literal) { + case tagReplacerValue: + case tagArgument: + case tagLabel: + throw makeError(i, `Expected text (replacer key).`); + case tagEnding: + throw makeError(i, `Expected text (replacer key/value).`); } + } - const replacerFirst = N; - i = stop_iParse; - - // Replacer value (if explicit) - - let replacerSecond; + const replacerFirst = N; + i = stop_iParse; - if (stop_literal === tagReplacerValue) { - N = parseNodes(i, { - stopAt: [tagArgument, tagLabel, tagEnding] - }); + // Replacer value (if explicit) - if (!stopped) throw endOfInput(i, `reading replacer value`); - if (!N.length) throw makeError(i, `Expected content (replacer value).`); + let replacerSecond; - replacerSecond = N; - i = stop_iParse - } + if (stop_literal === tagReplacerValue) { + N = parseNodes(input, i, { + stopAt: [tagArgument, tagLabel, tagEnding] + }); - // Assign first & second to replacer key/value + if (!stopped) throw endOfInput(i, `reading replacer value`); + if (!N.length) throw makeError(i, `Expected content (replacer value).`); - // Value is an array of nodes, 8ut key is just one (or null). - // So if we use replacerFirst as the value, we need to stick - // it in an array (on its own). - const [ replacerKey, replacerValue ] = - (replacerSecond - ? [replacerFirst, replacerSecond] - : [null, [replacerFirst]]); + replacerSecond = N; + i = stop_iParse + } - // Arguments + // Assign first & second to replacer key/value - const args = []; + // Value is an array of nodes, 8ut key is just one (or null). + // So if we use replacerFirst as the value, we need to stick + // it in an array (on its own). + const [ replacerKey, replacerValue ] = + (replacerSecond + ? [replacerFirst, replacerSecond] + : [null, [replacerFirst]]); - while (stop_literal === tagArgument) { - N = parseOneTextNode(i, { - stopAt: [tagArgumentValue, tagArgument, tagLabel, tagEnding] - }); + // Arguments - if (!stopped) throw endOfInput(i, `reading argument key`); + const args = []; - if (stop_literal !== tagArgumentValue) - throw makeError(i, `Expected ${tagArgumentValue.literal} (tag argument).`); + while (stop_literal === tagArgument) { + N = parseOneTextNode(input, i, { + stopAt: [tagArgumentValue, tagArgument, tagLabel, tagEnding] + }); - if (!N) - throw makeError(i, `Expected text (argument key).`); + if (!stopped) throw endOfInput(i, `reading argument key`); - const key = N; - i = stop_iParse; + if (stop_literal !== tagArgumentValue) + throw makeError(i, `Expected ${tagArgumentValue.literal} (tag argument).`); - N = parseNodes(i, { - stopAt: [tagArgument, tagLabel, tagEnding] - }); + if (!N) + throw makeError(i, `Expected text (argument key).`); - if (!stopped) throw endOfInput(i, `reading argument value`); - if (!N.length) throw makeError(i, `Expected content (argument value).`); + const key = N; + i = stop_iParse; - const value = N; - i = stop_iParse; + N = parseNodes(input, i, { + stopAt: [tagArgument, tagLabel, tagEnding] + }); - args.push({key, value}); - } + if (!stopped) throw endOfInput(i, `reading argument value`); + if (!N.length) throw makeError(i, `Expected content (argument value).`); - let label; + const value = N; + i = stop_iParse; - if (stop_literal === tagLabel) { - N = parseOneTextNode(i, { - stopAt: [tagEnding] - }); + args.push({key, value}); + } - if (!stopped) throw endOfInput(i, `reading label`); - if (!N) throw makeError(i, `Expected text (label).`); + let label; - label = N; - i = stop_iParse; - } + if (stop_literal === tagLabel) { + N = parseOneTextNode(input, i, { + stopAt: [tagEnding] + }); - nodes.push(makeNode(iTag, 'tag', {replacerKey, replacerValue, args, label})); + if (!stopped) throw endOfInput(i, `reading label`); + if (!N) throw makeError(i, `Expected text (label).`); - continue; + label = N; + i = stop_iParse; } - string += input[i]; - i++; + nodes.push(makeNode(iTag, 'tag', {replacerKey, replacerValue, args, label})); + + continue; } - pushTextNode(); - return nodes; - }; + string += input[i]; + i++; + } + pushTextNode(); + return nodes; + }; + + transformInline.parse = function(input) { try { - return parseNodes(0); + return parseNodes(input, 0); } catch (errorNode) { if (errorNode.type !== 'error') { throw errorNode; |