diff --git a/x-pack/plugins/observability_solution/synthetics/server/synthetics_service/formatters/formatting_utils.test.ts b/x-pack/plugins/observability_solution/synthetics/server/synthetics_service/formatters/formatting_utils.test.ts index 84e073731aef20..ba3da63244556e 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/synthetics_service/formatters/formatting_utils.test.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/synthetics_service/formatters/formatting_utils.test.ts @@ -40,10 +40,10 @@ describe('replaceStringWithParams', () => { expect(result).toEqual('https://elastic.co'); }); - it('returns empty value in case no param', () => { + it('returns same value in case no param', () => { const result = replaceStringWithParams('${homePageUrl}', {}, logger); - expect(result).toEqual(''); + expect(result).toEqual('${homePageUrl}'); }); it('works on objects', () => { @@ -76,6 +76,46 @@ describe('replaceStringWithParams', () => { expect(result).toEqual('Basic https://elastic.co https://elastic.co/product'); }); + it('works on multiple without spaces', () => { + const result = replaceStringWithParams( + 'Basic ${homePageUrl}${homePageUrl1}', + { homePageUrl: 'https://elastic.co', homePageUrl1: 'https://elastic.co/product' }, + logger + ); + + expect(result).toEqual('Basic https://elastic.cohttps://elastic.co/product'); + }); + + it('works on multiple without spaces and one missing', () => { + const result = replaceStringWithParams( + 'Basic ${homePageUrl}${homePageUrl1}', + { homePageUrl: 'https://elastic.co', homePageUrl2: 'https://elastic.co/product' }, + logger + ); + + expect(result).toEqual('Basic https://elastic.co${homePageUrl1}'); + }); + + it('works on multiple without with default', () => { + const result = replaceStringWithParams( + 'Basic ${homePageUrl}${homePageUrl1:test}', + { homePageUrl: 'https://elastic.co', homePageUrl2: 'https://elastic.co/product' }, + logger + ); + + expect(result).toEqual('Basic https://elastic.cotest'); + }); + + it('works on multiple with multiple defaults', () => { + const result = replaceStringWithParams( + 'Basic ${homePageUrl:test}${homePageUrl1:test4}', + { homePageUrl3: 'https://elastic.co', homePageUrl2: 'https://elastic.co/product' }, + logger + ); + + expect(result).toEqual('Basic testtest4'); + }); + it('works with default value', () => { const result = replaceStringWithParams( 'Basic ${homePageUrl:https://elastic.co} ${homePageUrl1}', @@ -143,6 +183,36 @@ describe('replaceStringWithParams', () => { expect(result).toEqual('Basic ${} value'); }); + it('works with ${host.name} for missing params', () => { + const result = replaceStringWithParams( + 'Basic ${host.name} value', + { homePageUrl1: 'https://elastic.co/product' }, + logger + ); + + expect(result).toEqual('Basic ${host.name} value'); + }); + + it('works with ${host.name} one missing params', () => { + const result = replaceStringWithParams( + 'Basic ${host.name} ${homePageUrl1} value', + { homePageUrl1: 'https://elastic.co/product' }, + logger + ); + + expect(result).toEqual('Basic ${host.name} https://elastic.co/product value'); + }); + + it('works with ${host.name} just missing params', () => { + const result = replaceStringWithParams( + '${host.name} ${homePageUrl1}', + { homePageUrl1: 'https://elastic.co/product' }, + logger + ); + + expect(result).toEqual('${host.name} https://elastic.co/product'); + }); + it('works with } ${abc} as part of value', () => { const result = replaceStringWithParams( 'Basic } ${homePageUrl1} value', @@ -162,4 +232,10 @@ describe('replaceStringWithParams', () => { expect(result).toEqual('Basic https://elastic.co/product { value'); }); + + it("returns value as string | null when no params and it's an object", () => { + const result = replaceStringWithParams({}, { param: '1' }, logger); + + expect(result).toEqual({}); + }); }); diff --git a/x-pack/plugins/observability_solution/synthetics/server/synthetics_service/formatters/formatting_utils.ts b/x-pack/plugins/observability_solution/synthetics/server/synthetics_service/formatters/formatting_utils.ts index 57d742d08deb04..be6dd40e738dc5 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/synthetics_service/formatters/formatting_utils.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/synthetics_service/formatters/formatting_utils.ts @@ -6,6 +6,7 @@ */ import { Logger } from '@kbn/logging'; +import { isEmpty } from 'lodash'; import { ConfigKey, MonitorFields } from '../../../common/runtime_types'; import { ParsedVars, replaceVarsWithParams } from './lightweight_param_formatter'; import variableParser from './variable_parser'; @@ -20,7 +21,7 @@ export const replaceStringWithParams = ( params: Record, logger?: Logger ) => { - if (!value || typeof value === 'boolean') { + if (!value || typeof value === 'boolean' || isEmpty(params)) { return value as string | null; } @@ -42,6 +43,10 @@ export const replaceStringWithParams = ( const parsedVars: ParsedVars = variableParser.parse(value); + if (allParamsAreMissing(parsedVars, params)) { + return value as string | null; + } + return replaceVarsWithParams(parsedVars, params); } catch (e) { logger?.error(`error parsing vars for value ${JSON.stringify(value)}, ${e}`); @@ -50,6 +55,19 @@ export const replaceStringWithParams = ( return value as string | null; }; +const allParamsAreMissing = (parsedVars: ParsedVars, params: Record) => { + const hasDefault = parsedVars.some( + (parsedVar) => parsedVar.type === 'var' && parsedVar.content.default + ); + if (hasDefault) { + return false; + } + const varKeys = parsedVars + .filter((parsedVar) => parsedVar.type === 'var') + .map((v) => (typeof v.content === 'string' ? v.content : v.content.name)); + return varKeys.every((v) => !params[v]); +}; + const SHELL_PARAMS_REGEX = /\$\{[a-zA-Z_][a-zA-Z0-9\._\-?:]*\}/g; export const hasNoParams = (strVal: string) => { diff --git a/x-pack/plugins/observability_solution/synthetics/server/synthetics_service/formatters/lightweight_param_formatter.test.ts b/x-pack/plugins/observability_solution/synthetics/server/synthetics_service/formatters/lightweight_param_formatter.test.ts index facfd9d5e65367..7d59c5dd90c876 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/synthetics_service/formatters/lightweight_param_formatter.test.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/synthetics_service/formatters/lightweight_param_formatter.test.ts @@ -162,4 +162,11 @@ describe('LightweightParamFormatter', () => { const result = replaceVarsWithParams(formatter, params); expect(result).toEqual('https://default:1234'); }); + it('wraps content name when no default', () => { + const result = replaceVarsWithParams( + [{ type: 'var', content: { name: 'missing', default: null } }], + {} + ); + expect(result).toEqual('${missing}'); + }); }); diff --git a/x-pack/plugins/observability_solution/synthetics/server/synthetics_service/formatters/lightweight_param_formatter.ts b/x-pack/plugins/observability_solution/synthetics/server/synthetics_service/formatters/lightweight_param_formatter.ts index e7ee00433cc873..511a5c2ac1aa33 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/synthetics_service/formatters/lightweight_param_formatter.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/synthetics_service/formatters/lightweight_param_formatter.ts @@ -16,7 +16,7 @@ export function replaceVarsWithParams(vars: ParsedVars, params: Record targetLength) { + return str; } + targetLength -= str.length; + padString += padString.repeat(targetLength); + return str + padString.slice(0, targetLength); } -peg$subclass(pegSyntaxError, Error); +peg$SyntaxError.prototype.format = function (sources) { + let str = 'Error: ' + this.message; + if (this.location) { + let src = null; + let k; + for (k = 0; k < sources.length; k++) { + if (sources[k].source === this.location.source) { + src = sources[k].text.split(/\r\n|\n|\r/g); + break; + } + } + const s = this.location.start; + const offsetS = + this.location.source && typeof this.location.source.offset === 'function' + ? this.location.source.offset(s) + : s; + const loc = this.location.source + ':' + offsetS.line + ':' + offsetS.column; + if (src) { + const e = this.location.end; + const filler = peg$padEnd('', offsetS.line.toString().length, ' '); + const line = src[s.line - 1]; + const last = s.line === e.line ? e.column : line.length + 1; + const hatLen = last - s.column || 1; + str += + '\n --> ' + + loc + + '\n' + + filler + + ' |\n' + + offsetS.line + + ' | ' + + line + + '\n' + + filler + + ' | ' + + peg$padEnd('', s.column - 1, ' ') + + peg$padEnd('', hatLen, '^'); + } else { + str += '\n at ' + loc; + } + } + return str; +}; -pegSyntaxError.buildMessage = function (expected, found) { +peg$SyntaxError.buildMessage = function (expected, found) { const DESCRIBE_EXPECTATION_FNS = { literal: function (expectation) { return '"' + literalEscape(expectation.text) + '"'; }, class: function (expectation) { - let escapedParts = ''; - let i; - - for (i = 0; i < expectation.parts.length; i++) { - escapedParts += - expectation.parts[i] instanceof Array - ? classEscape(expectation.parts[i][0]) + '-' + classEscape(expectation.parts[i][1]) - : classEscape(expectation.parts[i]); - } + const escapedParts = expectation.parts.map(function (part) { + return Array.isArray(part) + ? classEscape(part[0]) + '-' + classEscape(part[1]) + : classEscape(part); + }); - return '[' + (expectation.inverted ? '^' : '') + escapedParts + ']'; + return '[' + (expectation.inverted ? '^' : '') + escapedParts.join('') + ']'; }, - // eslint-disable-next-line no-unused-vars - any: function (expectation) { + any: function () { return 'any character'; }, - // eslint-disable-next-line no-unused-vars - end: function (expectation) { + end: function () { return 'end of input'; }, @@ -111,14 +158,10 @@ pegSyntaxError.buildMessage = function (expected, found) { } function describeExpected(expected) { - const descriptions = new Array(expected.length); + const descriptions = expected.map(describeExpectation); let i; let j; - for (i = 0; i < expected.length; i++) { - descriptions[i] = describeExpectation(expected[i]); - } - descriptions.sort(); if (descriptions.length > 0) { @@ -152,22 +195,43 @@ pegSyntaxError.buildMessage = function (expected, found) { return 'Expected ' + describeExpected(expected) + ' but ' + describeFound(found) + ' found.'; }; -function pegParse(input, options) { - options = options !== void 0 ? options : {}; +function peg$parse(input, options) { + options = options !== undefined ? options : {}; const peg$FAILED = {}; + const peg$source = options.grammarSource; const peg$startRuleFunctions = { Exps: peg$parseExps }; let peg$startRuleFunction = peg$parseExps; - const peg$c0 = function (e) { - return e.map((x) => x[0]); + const peg$c0 = '${'; + const peg$c1 = '}'; + const peg$c2 = ':'; + const peg$c3 = '\\'; + const peg$c4 = '$'; + + const peg$r0 = /^[^}:\\\r\n]/; + const peg$r1 = /^[^}\\\r\n]/; + const peg$r2 = /^[^$]/; + const peg$r3 = /^[^{]/; + const peg$r4 = /^[ \t\n\r]/; + + const peg$e0 = peg$literalExpectation('${', false); + const peg$e1 = peg$literalExpectation('}', false); + const peg$e2 = peg$literalExpectation(':', false); + const peg$e3 = peg$classExpectation(['}', ':', '\\', '\r', '\n'], true, false); + const peg$e4 = peg$literalExpectation('\\', false); + const peg$e5 = peg$classExpectation(['}', '\\', '\r', '\n'], true, false); + const peg$e6 = peg$classExpectation(['$'], true, false); + const peg$e7 = peg$literalExpectation('$', false); + const peg$e8 = peg$classExpectation(['{'], true, false); + const peg$e9 = peg$otherExpectation('whitespace'); + const peg$e10 = peg$classExpectation([' ', '\t', '\n', '\r'], false, false); + + const peg$f0 = function (e) { + return e; }; - const peg$c1 = '${'; - const peg$c2 = peg$literalExpectation('${', false); - const peg$c3 = '}'; - const peg$c4 = peg$literalExpectation('}', false); - const peg$c5 = function (varCont) { + const peg$f1 = function (varCont) { return { type: 'var', content: { @@ -176,52 +240,44 @@ function pegParse(input, options) { }, }; }; - const peg$c6 = function (varCont) { + const peg$f2 = function (varCont) { return { type: 'varname', content: varCont.map((c) => c.char || c).join('') }; }; - const peg$c7 = ':'; - const peg$c8 = peg$literalExpectation(':', false); - const peg$c9 = function (defCont) { + const peg$f3 = function (defCont) { return { type: 'vardefault', content: defCont.join('') }; }; - const peg$c10 = /^[^}:\\\r\n]/; - const peg$c11 = peg$classExpectation(['}', ':', '\\', '\r', '\n'], true, false); - const peg$c12 = '\\'; - const peg$c13 = peg$literalExpectation('\\', false); - const peg$c14 = function () { + const peg$f4 = function () { + return { type: 'char', char: '\\' }; + }; + const peg$f5 = function () { + return { type: 'char', char: '\x7d' }; + }; + const peg$f6 = function (sequence) { + return sequence.char; + }; + const peg$f7 = function () { return { type: 'char', char: '\\' }; }; - const peg$c15 = function () { + const peg$f8 = function () { return { type: 'char', char: '\x7d' }; }; - const peg$c16 = function (sequence) { + const peg$f9 = function (sequence) { return sequence.char; }; - const peg$c17 = /^[^}\\\r\n]/; - const peg$c18 = peg$classExpectation(['}', '\\', '\r', '\n'], true, false); - const peg$c19 = function (nonVarCont) { + const peg$f10 = function (nonVarCont) { return { type: 'nonvar', content: nonVarCont.map((c) => c.char || c).join('') }; }; - const peg$c20 = /^[^$]/; - const peg$c21 = peg$classExpectation(['$'], true, false); - const peg$c22 = '$'; - const peg$c23 = peg$literalExpectation('$', false); - const peg$c24 = /^[^{]/; - const peg$c25 = peg$classExpectation(['{'], true, false); - const peg$c26 = peg$otherExpectation('whitespace'); - const peg$c27 = /^[ \t\n\r]/; - const peg$c28 = peg$classExpectation([' ', '\t', '\n', '\r'], false, false); - - let peg$currPos = 0; - let peg$savedPos = 0; + let peg$currPos = options.peg$currPos | 0; + // eslint-disable-next-line no-unused-vars + let peg$savedPos = peg$currPos; const peg$posDetailsCache = [{ line: 1, column: 1 }]; - let peg$maxFailPos = 0; - let peg$maxFailExpected = []; - let peg$silentFails = 0; + let peg$maxFailPos = peg$currPos; + let peg$maxFailExpected = options.peg$maxFailExpected || []; + let peg$silentFails = options.peg$silentFails | 0; let peg$result; - if ('startRule' in options) { + if (options.startRule) { if (!(options.startRule in peg$startRuleFunctions)) { throw new Error('Can\'t start parsing from rule "' + options.startRule + '".'); } @@ -229,31 +285,6 @@ function pegParse(input, options) { peg$startRuleFunction = peg$startRuleFunctions[options.startRule]; } - // eslint-disable-next-line no-unused-vars - function text() { - return input.substring(peg$savedPos, peg$currPos); - } - // eslint-disable-next-line no-unused-vars - function location() { - return peg$computeLocation(peg$savedPos, peg$currPos); - } - // eslint-disable-next-line no-unused-vars - function expected(description, location) { - location = location !== void 0 ? location : peg$computeLocation(peg$savedPos, peg$currPos); - - throw peg$buildStructuredError( - [peg$otherExpectation(description)], - input.substring(peg$savedPos, peg$currPos), - location - ); - } - // eslint-disable-next-line no-unused-vars - function error(message, location) { - location = location !== void 0 ? location : peg$computeLocation(peg$savedPos, peg$currPos); - - throw peg$buildSimpleError(message, location); - } - function peg$literalExpectation(text, ignoreCase) { return { type: 'literal', text: text, ignoreCase: ignoreCase }; } @@ -262,11 +293,6 @@ function pegParse(input, options) { return { type: 'class', parts: parts, inverted: inverted, ignoreCase: ignoreCase }; } - // eslint-disable-next-line no-unused-vars - function peg$anyExpectation() { - return { type: 'any' }; - } - function peg$endExpectation() { return { type: 'end' }; } @@ -282,9 +308,13 @@ function pegParse(input, options) { if (details) { return details; } else { - p = pos - 1; - while (!peg$posDetailsCache[p]) { - p--; + if (pos >= peg$posDetailsCache.length) { + p = peg$posDetailsCache.length - 1; + } else { + p = pos; + while (!peg$posDetailsCache[--p]) { + /* empty */ + } } details = peg$posDetailsCache[p]; @@ -305,15 +335,17 @@ function pegParse(input, options) { } peg$posDetailsCache[pos] = details; + return details; } } - function peg$computeLocation(startPos, endPos) { + function peg$computeLocation(startPos, endPos, offset) { const startPosDetails = peg$computePosDetails(startPos); const endPosDetails = peg$computePosDetails(endPos); - return { + const res = { + source: peg$source, start: { offset: startPos, line: startPosDetails.line, @@ -325,6 +357,11 @@ function pegParse(input, options) { column: endPosDetails.column, }, }; + if (offset && peg$source && typeof peg$source.offset === 'function') { + res.start = peg$source.offset(res.start); + res.end = peg$source.offset(res.end); + } + return res; } function peg$fail(expected) { @@ -340,15 +377,10 @@ function pegParse(input, options) { peg$maxFailExpected.push(expected); } - function peg$buildSimpleError(message, location) { - // eslint-disable-next-line new-cap - return new pegSyntaxError(message, null, null, location); - } - function peg$buildStructuredError(expected, found, location) { // eslint-disable-next-line new-cap - return new pegSyntaxError( - pegSyntaxError.buildMessage(expected, found), + return new peg$SyntaxError( + peg$SyntaxError.buildMessage(expected, found), expected, found, location @@ -373,7 +405,7 @@ function pegParse(input, options) { } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$c0(s1); + s1 = peg$f0(s1); } s0 = s1; @@ -382,29 +414,10 @@ function pegParse(input, options) { function peg$parseExp() { let s0; - let s1; - s0 = []; - s1 = peg$parseVar(); - if (s1 !== peg$FAILED) { - while (s1 !== peg$FAILED) { - s0.push(s1); - s1 = peg$parseVar(); - } - } else { - s0 = peg$FAILED; - } + s0 = peg$parseVar(); if (s0 === peg$FAILED) { - s0 = []; - s1 = peg$parseNonVar(); - if (s1 !== peg$FAILED) { - while (s1 !== peg$FAILED) { - s0.push(s1); - s1 = peg$parseNonVar(); - } - } else { - s0 = peg$FAILED; - } + s0 = peg$parseNonVar(); } return s0; @@ -413,58 +426,46 @@ function pegParse(input, options) { function peg$parseVar() { let s0; let s1; - let s2; let s3; let s4; let s5; s0 = peg$currPos; - if (input.substr(peg$currPos, 2) === peg$c1) { - s1 = peg$c1; + if (input.substr(peg$currPos, 2) === peg$c0) { + s1 = peg$c0; peg$currPos += 2; } else { s1 = peg$FAILED; if (peg$silentFails === 0) { - peg$fail(peg$c2); + peg$fail(peg$e0); } } if (s1 !== peg$FAILED) { - s2 = peg$parse_(); - if (s2 !== peg$FAILED) { - s3 = []; - s4 = peg$parseVarInner(); - if (s4 !== peg$FAILED) { - while (s4 !== peg$FAILED) { - s3.push(s4); - s4 = peg$parseVarInner(); - } - } else { - s3 = peg$FAILED; + peg$parse_(); + s3 = []; + s4 = peg$parseVarInner(); + if (s4 !== peg$FAILED) { + while (s4 !== peg$FAILED) { + s3.push(s4); + s4 = peg$parseVarInner(); } - if (s3 !== peg$FAILED) { - s4 = peg$parse_(); - if (s4 !== peg$FAILED) { - if (input.charCodeAt(peg$currPos) === 125) { - s5 = peg$c3; - peg$currPos++; - } else { - s5 = peg$FAILED; - if (peg$silentFails === 0) { - peg$fail(peg$c4); - } - } - if (s5 !== peg$FAILED) { - peg$savedPos = s0; - s1 = peg$c5(s3); - s0 = s1; - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - } else { - peg$currPos = s0; - s0 = peg$FAILED; + } else { + s3 = peg$FAILED; + } + if (s3 !== peg$FAILED) { + s4 = peg$parse_(); + if (input.charCodeAt(peg$currPos) === 125) { + s5 = peg$c1; + peg$currPos++; + } else { + s5 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e1); } + } + if (s5 !== peg$FAILED) { + peg$savedPos = s0; + s0 = peg$f1(s3); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -493,13 +494,8 @@ function pegParse(input, options) { if (s2 === peg$FAILED) { s2 = null; } - if (s2 !== peg$FAILED) { - s1 = [s1, s2]; - s0 = s1; - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } + s1 = [s1, s2]; + s0 = s1; } else { peg$currPos = s0; s0 = peg$FAILED; @@ -526,7 +522,7 @@ function pegParse(input, options) { } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$c6(s1); + s1 = peg$f2(s1); } s0 = s1; @@ -541,12 +537,12 @@ function pegParse(input, options) { s0 = peg$currPos; if (input.charCodeAt(peg$currPos) === 58) { - s1 = peg$c7; + s1 = peg$c2; peg$currPos++; } else { s1 = peg$FAILED; if (peg$silentFails === 0) { - peg$fail(peg$c8); + peg$fail(peg$e2); } } if (s1 !== peg$FAILED) { @@ -562,8 +558,7 @@ function pegParse(input, options) { } if (s2 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$c9(s2); - s0 = s1; + s0 = peg$f3(s2); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -582,13 +577,13 @@ function pegParse(input, options) { let s2; let s3; - if (peg$c10.test(input.charAt(peg$currPos))) { - s0 = input.charAt(peg$currPos); + s0 = input.charAt(peg$currPos); + if (peg$r0.test(s0)) { peg$currPos++; } else { s0 = peg$FAILED; if (peg$silentFails === 0) { - peg$fail(peg$c11); + peg$fail(peg$e3); } } if (s0 === peg$FAILED) { @@ -597,40 +592,39 @@ function pegParse(input, options) { if (s1 !== peg$FAILED) { s2 = peg$currPos; if (input.charCodeAt(peg$currPos) === 92) { - s3 = peg$c12; + s3 = peg$c3; peg$currPos++; } else { s3 = peg$FAILED; if (peg$silentFails === 0) { - peg$fail(peg$c13); + peg$fail(peg$e4); } } if (s3 !== peg$FAILED) { peg$savedPos = s2; - s3 = peg$c14(); + s3 = peg$f4(); } s2 = s3; if (s2 === peg$FAILED) { s2 = peg$currPos; if (input.charCodeAt(peg$currPos) === 125) { - s3 = peg$c3; + s3 = peg$c1; peg$currPos++; } else { s3 = peg$FAILED; if (peg$silentFails === 0) { - peg$fail(peg$c4); + peg$fail(peg$e1); } } if (s3 !== peg$FAILED) { peg$savedPos = s2; - s3 = peg$c15(); + s3 = peg$f5(); } s2 = s3; } if (s2 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$c16(s2); - s0 = s1; + s0 = peg$f6(s2); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -650,13 +644,13 @@ function pegParse(input, options) { let s2; let s3; - if (peg$c17.test(input.charAt(peg$currPos))) { - s0 = input.charAt(peg$currPos); + s0 = input.charAt(peg$currPos); + if (peg$r1.test(s0)) { peg$currPos++; } else { s0 = peg$FAILED; if (peg$silentFails === 0) { - peg$fail(peg$c18); + peg$fail(peg$e5); } } if (s0 === peg$FAILED) { @@ -665,40 +659,39 @@ function pegParse(input, options) { if (s1 !== peg$FAILED) { s2 = peg$currPos; if (input.charCodeAt(peg$currPos) === 92) { - s3 = peg$c12; + s3 = peg$c3; peg$currPos++; } else { s3 = peg$FAILED; if (peg$silentFails === 0) { - peg$fail(peg$c13); + peg$fail(peg$e4); } } if (s3 !== peg$FAILED) { peg$savedPos = s2; - s3 = peg$c14(); + s3 = peg$f7(); } s2 = s3; if (s2 === peg$FAILED) { s2 = peg$currPos; if (input.charCodeAt(peg$currPos) === 125) { - s3 = peg$c3; + s3 = peg$c1; peg$currPos++; } else { s3 = peg$FAILED; if (peg$silentFails === 0) { - peg$fail(peg$c4); + peg$fail(peg$e1); } } if (s3 !== peg$FAILED) { peg$savedPos = s2; - s3 = peg$c15(); + s3 = peg$f8(); } s2 = s3; } if (s2 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$c16(s2); - s0 = s1; + s0 = peg$f9(s2); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -730,7 +723,7 @@ function pegParse(input, options) { } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$c19(s1); + s1 = peg$f10(s1); } s0 = s1; @@ -751,13 +744,13 @@ function pegParse(input, options) { function peg$parseNotDollar() { let s0; - if (peg$c20.test(input.charAt(peg$currPos))) { - s0 = input.charAt(peg$currPos); + s0 = input.charAt(peg$currPos); + if (peg$r2.test(s0)) { peg$currPos++; } else { s0 = peg$FAILED; if (peg$silentFails === 0) { - peg$fail(peg$c21); + peg$fail(peg$e6); } } @@ -772,35 +765,35 @@ function pegParse(input, options) { s0 = peg$currPos; if (input.charCodeAt(peg$currPos) === 36) { - s1 = peg$c22; + s1 = peg$c4; peg$currPos++; } else { s1 = peg$FAILED; if (peg$silentFails === 0) { - peg$fail(peg$c23); + peg$fail(peg$e7); } } if (s1 !== peg$FAILED) { s2 = []; - if (peg$c24.test(input.charAt(peg$currPos))) { - s3 = input.charAt(peg$currPos); + s3 = input.charAt(peg$currPos); + if (peg$r3.test(s3)) { peg$currPos++; } else { s3 = peg$FAILED; if (peg$silentFails === 0) { - peg$fail(peg$c25); + peg$fail(peg$e8); } } if (s3 !== peg$FAILED) { while (s3 !== peg$FAILED) { s2.push(s3); - if (peg$c24.test(input.charAt(peg$currPos))) { - s3 = input.charAt(peg$currPos); + s3 = input.charAt(peg$currPos); + if (peg$r3.test(s3)) { peg$currPos++; } else { s3 = peg$FAILED; if (peg$silentFails === 0) { - peg$fail(peg$c25); + peg$fail(peg$e8); } } } @@ -829,33 +822,31 @@ function pegParse(input, options) { peg$silentFails++; // eslint-disable-next-line prefer-const s0 = []; - if (peg$c27.test(input.charAt(peg$currPos))) { - s1 = input.charAt(peg$currPos); + s1 = input.charAt(peg$currPos); + if (peg$r4.test(s1)) { peg$currPos++; } else { s1 = peg$FAILED; if (peg$silentFails === 0) { - peg$fail(peg$c28); + peg$fail(peg$e10); } } while (s1 !== peg$FAILED) { s0.push(s1); - if (peg$c27.test(input.charAt(peg$currPos))) { - s1 = input.charAt(peg$currPos); + s1 = input.charAt(peg$currPos); + if (peg$r4.test(s1)) { peg$currPos++; } else { s1 = peg$FAILED; if (peg$silentFails === 0) { - peg$fail(peg$c28); + peg$fail(peg$e10); } } } peg$silentFails--; - if (s0 === peg$FAILED) { - s1 = peg$FAILED; - if (peg$silentFails === 0) { - peg$fail(peg$c26); - } + s1 = peg$FAILED; + if (peg$silentFails === 0) { + peg$fail(peg$e9); } return s0; @@ -865,12 +856,12 @@ function pegParse(input, options) { let s0; if (input.charCodeAt(peg$currPos) === 92) { - s0 = peg$c12; + s0 = peg$c3; peg$currPos++; } else { s0 = peg$FAILED; if (peg$silentFails === 0) { - peg$fail(peg$c13); + peg$fail(peg$e4); } } @@ -880,6 +871,15 @@ function pegParse(input, options) { // eslint-disable-next-line prefer-const peg$result = peg$startRuleFunction(); + if (options.peg$library) { + return /** @type {any} */ ({ + peg$result, + peg$currPos, + peg$FAILED, + peg$maxFailExpected, + peg$maxFailPos, + }); + } if (peg$result !== peg$FAILED && peg$currPos === input.length) { return peg$result; } else { @@ -897,7 +897,72 @@ function pegParse(input, options) { } } -export default { - SyntaxError: pegSyntaxError, - parse: pegParse, -}; +export default { parse: peg$parse }; + +/** + Exps + = e:Exp+ { + return e; + } + + Exp + = Var / NonVar + + Var + = "${" _ varCont:VarInner+ _ "}" { + return { type: "var", content: {name: varCont[0][0].content, default: varCont[0][1] ? varCont[0][1].content : null} } + } + + VarInner + = VarName VarDefault? + + VarName + = varCont:VarNameChar+ { + return { type: "varname", content: varCont.map(c => c.char || c).join('') } + } + + VarDefault + = ":" defCont:VarDefaultChar+ { + return { type: "vardefault", content: defCont.join('')} + } + + VarNameChar + = [^}:\\\r\n] + / Escape + sequence:( + "\\" { return {type: "char", char: "\\"}; } + / "}" { return {type: "char", char: "\x7d"}; } + ) + { return sequence.char; } + + VarDefaultChar + = [^}\\\r\n] + / Escape + sequence:( + "\\" { return {type: "char", char: "\\"}; } + / "}" { return {type: "char", char: "\x7d"}; } + ) + { return sequence.char; } + + NonVar + = nonVarCont:NonVarCont+ { + return { type: "nonvar", content: nonVarCont.map(c => c.char || c).join('') } + } + + NonVarCont + = DollarNotVarStart / NotDollar + + NotDollar + = [^$] + + DollarNotVarStart + = "$" [^{]+ + + _ "whitespace" + = [ \t\n\r]* + + Escape + = "\\" + + + */