UNPKG

uri-templates-es

Version:

URI Templates (RFC6570) including de-substitution

393 lines (392 loc) 13.8 kB
// main/src/lib/uri-template.ts var _UriTemplate = class _UriTemplate { constructor(template) { this.template = template; var _a, _b; const parts = template.split("{"); this.textParts = [(_a = parts.shift()) != null ? _a : ""]; this.prefixes = []; this.substitutions = []; this.unSubstitutions = []; let varNames = []; while (parts.length > 0) { const part = (_b = parts.shift()) != null ? _b : ""; const spec = part.split("}")[0]; const remainder = part.substring(spec.length + 1); const funcs = this.uriTemplateSubstitution(spec); this.substitutions.push(funcs.substitution); this.unSubstitutions.push(funcs.unSubstitution); this.prefixes.push(funcs.prefix); this.textParts.push(remainder); varNames = varNames.concat(funcs.substitution.varNames); } } fill(valueFunction) { const valueFn = typeof valueFunction === "function" ? valueFunction : (varName) => valueFunction[varName]; let result = this.textParts[0]; for (let i = 0; i < this.substitutions.length; i++) { const substitution = this.substitutions[i]; result += substitution(valueFn); result += this.textParts[i + 1]; } return result; } fillFromObject(obj) { return this.fill(obj); } fromUri(substituted) { const result = {}; for (let i = 0; i < this.textParts.length; i++) { const part = this.textParts[i]; if (substituted.substring(0, part.length) !== part) { return void 0; } substituted = substituted.substring(part.length); if (i >= this.textParts.length - 1) { if (substituted === "") { break; } else { return void 0; } } let nextPart = this.textParts[i + 1]; let offset = i; let stringValue; while (true) { if (offset === this.textParts.length - 2) { const endPart = substituted.substring(substituted.length - nextPart.length); if (endPart !== nextPart) { return void 0; } stringValue = substituted.substring(0, substituted.length - nextPart.length); substituted = endPart; } else if (nextPart) { const nextPartPos = substituted.indexOf(nextPart); stringValue = substituted.substring(0, nextPartPos); substituted = substituted.substring(nextPartPos); } else if (this.prefixes[offset + 1]) { let nextPartPos = substituted.indexOf(this.prefixes[offset + 1]); if (nextPartPos === -1) nextPartPos = substituted.length; stringValue = substituted.substring(0, nextPartPos); substituted = substituted.substring(nextPartPos); } else if (this.textParts.length > offset + 2) { offset++; nextPart = this.textParts[offset + 1]; continue; } else { stringValue = substituted; substituted = ""; } break; } this.unSubstitutions[i](stringValue, result); } return result; } toString() { return this.template; } uriTemplateSubstitution(spec) { let modifier = ""; if (_UriTemplate.uriTemplateGlobalModifiers[spec.charAt(0)]) { modifier = spec.charAt(0); spec = spec.substring(1); } let separator = ""; let prefix = ""; let shouldEscape = true; let showVariables = false; let trimEmptyString = false; if (modifier === "+") { shouldEscape = false; } else if (modifier === ".") { prefix = "."; separator = "."; } else if (modifier === "/") { prefix = "/"; separator = "/"; } else if (modifier === "#") { prefix = "#"; shouldEscape = false; } else if (modifier === ";") { prefix = ";"; separator = ";"; showVariables = true; trimEmptyString = true; } else if (modifier === "?") { prefix = "?"; separator = "&"; showVariables = true; } else if (modifier === "&") { prefix = "&"; separator = "&"; showVariables = true; } const varNames = []; const varList = spec.split(","); const varSpecs = []; const varSpecMap = {}; for (let i = 0; i < varList.length; i++) { let varName = varList[i]; let truncate = null; if (varName.indexOf(":") !== -1) { const parts = varName.split(":"); varName = parts[0]; truncate = parseInt(parts[1], 10); } const suffices = {}; while (_UriTemplate.uriTemplateSuffices[varName.charAt(varName.length - 1)]) { const lastChar = varName.charAt(varName.length - 1); suffices[lastChar] = true; varName = varName.substring(0, varName.length - 1); } const varSpec = { truncate, name: varName, suffices }; varSpecs.push(varSpec); varSpecMap[varName] = varSpec; varNames.push(varName); } const subFunction = (function(valueFunction) { let result = ""; let startIndex = 0; for (let i = 0; i < varSpecs.length; i++) { const varSpec = varSpecs[i]; let value = valueFunction(varSpec.name); if (value == null || Array.isArray(value) && value.length === 0 || typeof value === "object" && Object.keys(value).length === 0) { startIndex++; continue; } if (i === startIndex) { result += prefix; } else { result += separator || ","; } if (Array.isArray(value)) { if (showVariables) { result += varSpec.name + "="; } for (let j = 0; j < value.length; j++) { if (j > 0) { result += varSpec.suffices["*"] ? separator || "," : ","; if (varSpec.suffices["*"] && showVariables) { result += varSpec.name + "="; } } result += shouldEscape ? encodeURIComponent(value[j]).replace(/!/g, "%21") : _UriTemplate.notReallyPercentEncode(value[j]); } } else if (typeof value === "object") { if (showVariables && !varSpec.suffices["*"]) { result += varSpec.name + "="; } let first = true; for (const key in value) { if (!first) { result += varSpec.suffices["*"] ? separator || "," : ","; } first = false; result += shouldEscape ? encodeURIComponent(key).replace(/!/g, "%21") : _UriTemplate.notReallyPercentEncode(key); result += varSpec.suffices["*"] ? "=" : ","; result += shouldEscape ? encodeURIComponent(value[key]).replace(/!/g, "%21") : _UriTemplate.notReallyPercentEncode(value[key]); } } else { if (showVariables) { result += varSpec.name; if (!trimEmptyString || value !== "") { result += "="; } } if (varSpec.truncate != null) { value = value.substring(0, varSpec.truncate); } result += shouldEscape ? encodeURIComponent(value).replace(/!/g, "%21") : _UriTemplate.notReallyPercentEncode(value); } } return result; }); const guessFunction = function(stringValue, resultObj) { if (prefix) { if (stringValue.substring(0, prefix.length) === prefix) { stringValue = stringValue.substring(prefix.length); } else { return null; } } if (varSpecs.length === 1 && varSpecs[0].suffices["*"]) { const varSpec = varSpecs[0]; const varName = varSpec.name; let arrayValue = varSpec.suffices["*"] ? stringValue.split(separator || ",") : [stringValue]; let hasEquals = shouldEscape && stringValue.indexOf("=") !== -1; for (let i = 1; i < arrayValue.length; i++) { const sv = arrayValue[i]; if (hasEquals && sv.indexOf("=") === -1) { arrayValue[i - 1] += (separator || ",") + sv; arrayValue.splice(i, 1); i--; } } for (let i = 0; i < arrayValue.length; i++) { let sv = arrayValue[i]; if (shouldEscape && sv.indexOf("=") !== -1) { hasEquals = true; } const innerArrayValue = sv.split(","); for (let j = 0; j < innerArrayValue.length; j++) { if (shouldEscape) { innerArrayValue[j] = decodeURIComponent(innerArrayValue[j]); } } if (innerArrayValue.length === 1) { arrayValue[i] = innerArrayValue[0]; } else { arrayValue[i] = innerArrayValue; } } if (showVariables || hasEquals) { const objectValue = resultObj[varName] || {}; for (let j = 0; j < arrayValue.length; j++) { let innerValue = stringValue; if (showVariables && !innerValue) { continue; } let innerVarName; if (typeof arrayValue[j] === "string") { let sv = arrayValue[j]; innerVarName = sv.split("=", 1)[0]; sv = sv.substring(innerVarName.length + 1); innerValue = sv; } else if (Array.isArray(arrayValue[j])) { const arr = arrayValue[j]; let sv = arr[0]; innerVarName = sv.split("=", 1)[0]; sv = sv.substring(innerVarName.length + 1); arr[0] = sv; innerValue = arr; } else { continue; } if (objectValue[innerVarName] !== void 0) { if (Array.isArray(objectValue[innerVarName])) { objectValue[innerVarName].push(innerValue); } else { objectValue[innerVarName] = [objectValue[innerVarName], innerValue]; } } else { objectValue[innerVarName] = innerValue; } } if (Object.keys(objectValue).length === 1 && objectValue[varName] !== void 0) { resultObj[varName] = objectValue[varName]; } else { resultObj[varName] = objectValue; } } else { if (resultObj[varName] !== void 0) { if (Array.isArray(resultObj[varName])) { resultObj[varName] = resultObj[varName].concat(arrayValue); } else { resultObj[varName] = [resultObj[varName]].concat(arrayValue); } } else { if (arrayValue.length === 1 && !varSpec.suffices["*"]) { resultObj[varName] = arrayValue[0]; } else { resultObj[varName] = arrayValue; } } } } else { const arrayValue = varSpecs.length === 1 ? [stringValue] : stringValue.split(separator || ","); const specIndexMap = {}; for (let i = 0; i < arrayValue.length; i++) { let firstStarred = 0; for (; firstStarred < varSpecs.length - 1 && firstStarred < i; firstStarred++) { if (varSpecs[firstStarred].suffices["*"]) { break; } } if (firstStarred === i) { specIndexMap[i] = i; continue; } else { for (let lastStarred = varSpecs.length - 1; lastStarred > 0 && varSpecs.length - lastStarred < arrayValue.length - i; lastStarred--) { if (varSpecs[lastStarred].suffices["*"]) { break; } if (varSpecs.length - lastStarred === arrayValue.length - i) { specIndexMap[i] = lastStarred; } } } specIndexMap[i] = firstStarred; } for (let i = 0; i < arrayValue.length; i++) { let sv = arrayValue[i]; if (!sv && showVariables) { continue; } const innerArrayValue = sv.split(","); let varSpec; let varName; if (showVariables) { sv = innerArrayValue[0]; varName = sv.split("=", 1)[0]; sv = sv.substring(varName.length + 1); innerArrayValue[0] = sv; varSpec = varSpecMap[varName] || varSpecs[0]; } else { varSpec = varSpecs[specIndexMap[i]]; varName = varSpec.name; } for (let j = 0; j < innerArrayValue.length; j++) { if (shouldEscape) { innerArrayValue[j] = decodeURIComponent(innerArrayValue[j]); } } if ((showVariables || varSpec.suffices["*"]) && resultObj[varName] !== void 0) { if (Array.isArray(resultObj[varName])) { resultObj[varName] = resultObj[varName].concat(innerArrayValue); } else { resultObj[varName] = [resultObj[varName]].concat(innerArrayValue); } } else { if (innerArrayValue.length === 1 && !varSpec.suffices["*"]) { resultObj[varName] = innerArrayValue[0]; } else { resultObj[varName] = innerArrayValue; } } } } }; subFunction.varNames = varNames; return { prefix, substitution: subFunction, unSubstitution: guessFunction }; } static notReallyPercentEncode(str) { return encodeURI(str).replace(/%25[0-9][0-9]/g, (doubleEncoded) => { return "%" + doubleEncoded.substring(3); }); } }; _UriTemplate.uriTemplateGlobalModifiers = { "+": true, "#": true, ".": true, "/": true, ";": true, "?": true, "&": true }; _UriTemplate.uriTemplateSuffices = { "*": true }; var UriTemplate = _UriTemplate; export { UriTemplate }; //# sourceMappingURL=index.js.map //# sourceMappingURL=index.js.map