'use strict'; class StdUriTemplate { static expand(template, substitutions) { return StdUriTemplate.expandImpl(template, substitutions); } static validateLiteral(c, col) { switch (c) { case "+": case "#": case "/": case ";": case "?": case "&": case " ": case "!": case "=": case "$": case "|": case "*": case ":": case "~": case "-": throw new Error(`Illegal character identified in the token at col: ${col}`); } } static getMaxChar(buffer, col) { if (!buffer) { return -1; } else { const value = buffer.join(""); if (value.length === 0) { return -1; } else { try { return parseInt(value, 10); } catch (e) { throw new Error(`Cannot parse max chars at col: ${col}`); } } } } static getOperator(c, token, col) { switch (c) { case "+": return 1 /* PLUS */; case "#": return 2 /* HASH */; case ".": return 3 /* DOT */; case "/": return 4 /* SLASH */; case ";": return 5 /* SEMICOLON */; case "?": return 6 /* QUESTION_MARK */; case "&": return 7 /* AMP */; default: StdUriTemplate.validateLiteral(c, col); token.push(c); return 0 /* NO_OP */; } } static expandImpl(str, substitutions) { const result = []; let token = null; let operator = null; let composite = false; let maxCharBuffer = null; let firstToken = true; for (let i = 0; i < str.length; i++) { const character = str.charAt(i); switch (character) { case "{": token = []; firstToken = true; break; case "}": if (token !== null) { const expanded = StdUriTemplate.expandToken( operator, token.join(""), composite, StdUriTemplate.getMaxChar(maxCharBuffer, i), firstToken, substitutions, result, i ); if (expanded && firstToken) { firstToken = false; } token = null; operator = null; composite = false; maxCharBuffer = null; } else { throw new Error(`Failed to expand token, invalid at col: ${i}`); } break; case ",": if (token !== null) { const expanded = StdUriTemplate.expandToken( operator, token.join(""), composite, StdUriTemplate.getMaxChar(maxCharBuffer, i), firstToken, substitutions, result, i ); if (expanded && firstToken) { firstToken = false; } token = []; composite = false; maxCharBuffer = null; break; } default: if (token !== null) { if (operator === null) { operator = StdUriTemplate.getOperator(character, token, i); } else if (maxCharBuffer !== null) { if (character.match(/^\d$/)) { maxCharBuffer.push(character); } else { throw new Error(`Illegal character identified in the token at col: ${i}`); } } else { if (character === ":") { maxCharBuffer = []; } else if (character === "*") { composite = true; } else { StdUriTemplate.validateLiteral(character, i); token.push(character); } } } else { result.push(character); } break; } } if (token === null) { return result.join(""); } else { throw new Error("Unterminated token"); } } static addPrefix(op, result) { switch (op) { case 2 /* HASH */: result.push("#"); break; case 3 /* DOT */: result.push("."); break; case 4 /* SLASH */: result.push("/"); break; case 5 /* SEMICOLON */: result.push(";"); break; case 6 /* QUESTION_MARK */: result.push("?"); break; case 7 /* AMP */: result.push("&"); break; default: return; } } static addSeparator(op, result) { switch (op) { case 3 /* DOT */: result.push("."); break; case 4 /* SLASH */: result.push("/"); break; case 5 /* SEMICOLON */: result.push(";"); break; case 6 /* QUESTION_MARK */: case 7 /* AMP */: result.push("&"); break; default: result.push(","); return; } } static addValue(op, token, value, result, maxChar) { switch (op) { case 1 /* PLUS */: case 2 /* HASH */: StdUriTemplate.addExpandedValue(null, value, result, maxChar, false); break; case 6 /* QUESTION_MARK */: case 7 /* AMP */: result.push(`${token}=`); StdUriTemplate.addExpandedValue(null, value, result, maxChar, true); break; case 5 /* SEMICOLON */: result.push(token); StdUriTemplate.addExpandedValue("=", value, result, maxChar, true); break; case 3 /* DOT */: case 4 /* SLASH */: case 0 /* NO_OP */: StdUriTemplate.addExpandedValue(null, value, result, maxChar, true); break; } } static addValueElement(op, token, value, result, maxChar) { switch (op) { case 1 /* PLUS */: case 2 /* HASH */: StdUriTemplate.addExpandedValue(null, value, result, maxChar, false); break; case 6 /* QUESTION_MARK */: case 7 /* AMP */: case 5 /* SEMICOLON */: case 3 /* DOT */: case 4 /* SLASH */: case 0 /* NO_OP */: StdUriTemplate.addExpandedValue(null, value, result, maxChar, true); break; } } static isSurrogate(cp) { const codeUnit = cp.charCodeAt(0); return codeUnit >= 55296 && codeUnit <= 56319; } static isIprivate(cp) { return 57344 <= cp.charCodeAt(0) && cp.charCodeAt(0) <= 63743; } static isUcschar(cp) { const codePoint = cp.codePointAt(0) || 0; return 160 <= codePoint && codePoint <= 55295 || 63744 <= codePoint && codePoint <= 64975 || 65008 <= codePoint && codePoint <= 65519; } static addExpandedValue(prefix, value, result, maxChar, replaceReserved) { const stringValue = StdUriTemplate.convertNativeTypes(value); const max = maxChar !== -1 ? Math.min(maxChar, stringValue.length) : stringValue.length; let reservedBuffer = void 0; if (max > 0 && prefix != null) { result.push(prefix); } for (let i = 0; i < max; i++) { const character = stringValue.charAt(i); if (character === "%" && !replaceReserved) { reservedBuffer = []; } let toAppend = character; if (StdUriTemplate.isSurrogate(character)) { toAppend = encodeURIComponent(stringValue.charAt(i) + stringValue.charAt(i + 1)); i++; } else if (replaceReserved || StdUriTemplate.isUcschar(character) || StdUriTemplate.isIprivate(character)) { if (character === "!") { toAppend = "%21"; } else { toAppend = encodeURIComponent(toAppend); } } if (reservedBuffer) { reservedBuffer.push(toAppend); if (reservedBuffer.length === 3) { let isEncoded = false; try { const reserved = reservedBuffer.join(""); const decoded = decodeURIComponent(reservedBuffer.join("")); isEncoded = reserved !== decoded; } catch (e) { } if (isEncoded) { result.push(reservedBuffer.join("")); } else { result.push("%25"); result.push(reservedBuffer.slice(1).join("")); } reservedBuffer = void 0; } } else { if (character === " ") { result.push("%20"); } else if (character === "%") { result.push("%25"); } else { result.push(toAppend); } } } if (reservedBuffer) { result.push("%25"); result.push(reservedBuffer.slice(1).join("")); } } static isList(value) { return Array.isArray(value) || value instanceof Set; } static isMap(value) { return value instanceof Map || typeof value === "object"; } static getSubstitutionType(value, col) { if (value === void 0 || value === null) { return 0 /* EMPTY */; } else if (StdUriTemplate.isNativeType(value)) { return 1 /* STRING */; } else if (StdUriTemplate.isList(value)) { return 2 /* LIST */; } else if (StdUriTemplate.isMap(value)) { return 3 /* MAP */; } else { throw new Error(`Illegal class passed as substitution, found ${typeof value} at col: ${col}`); } } static isEmpty(substType, value) { if (value === void 0 || value === null) { return true; } else { switch (substType) { case 1 /* STRING */: return false; case 2 /* LIST */: return value.length === 0; case 3 /* MAP */: return Object.keys(value).length === 0; default: return true; } } } static isNativeType(value) { return typeof value === "string" || typeof value === "number" || typeof value === "boolean"; } static convertNativeTypes(value) { if (typeof value === "string") { return value; } else if (typeof value === "number" || typeof value === "boolean") { return value.toString(); } else { throw new Error(`Illegal class passed as substitution, found ${typeof value}`); } } static expandToken(operator, token, composite, maxChar, firstToken, substitutions, result, col) { if (token.length === 0) { throw new Error(`Found an empty token at col: ${col}`); } const value = substitutions[token]; const substType = StdUriTemplate.getSubstitutionType(value, col); if (substType === 0 /* EMPTY */ || StdUriTemplate.isEmpty(substType, value)) { return false; } if (firstToken) { StdUriTemplate.addPrefix(operator, result); } else { StdUriTemplate.addSeparator(operator, result); } switch (substType) { case 1 /* STRING */: StdUriTemplate.addStringValue(operator, token, value, result, maxChar); break; case 2 /* LIST */: StdUriTemplate.addListValue(operator, token, value, result, maxChar, composite); break; case 3 /* MAP */: StdUriTemplate.addMapValue(operator, token, value, result, maxChar, composite); break; } return true; } static addStringValue(operator, token, value, result, maxChar) { StdUriTemplate.addValue(operator, token, value, result, maxChar); } static addListValue(operator, token, value, result, maxChar, composite) { let first = true; for (const v of value) { if (first) { StdUriTemplate.addValue(operator, token, v, result, maxChar); first = false; } else { if (composite) { StdUriTemplate.addSeparator(operator, result); StdUriTemplate.addValue(operator, token, v, result, maxChar); } else { result.push(","); StdUriTemplate.addValueElement(operator, token, v, result, maxChar); } } } } static addMapValue(operator, token, value, result, maxChar, composite) { let first = true; if (maxChar !== -1) { throw new Error("Value trimming is not allowed on Maps"); } for (const key in value) { const v = value[key]; if (composite) { if (!first) { StdUriTemplate.addSeparator(operator, result); } StdUriTemplate.addValueElement(operator, token, key, result, maxChar); result.push("="); } else { if (first) { StdUriTemplate.addValue(operator, token, key, result, maxChar); } else { result.push(","); StdUriTemplate.addValueElement(operator, token, key, result, maxChar); } result.push(","); } StdUriTemplate.addValueElement(operator, token, v, result, maxChar); first = false; } } } exports.StdUriTemplate = StdUriTemplate;