From 0f52103da5abdc299292cb56b6115d29b1b0d8c3 Mon Sep 17 00:00:00 2001 From: Nate Abele Date: Mon, 31 Aug 2015 17:14:00 -0400 Subject: [PATCH] feat(urlMatcher): add raw encoding flag to Type Closes #1119 --- src/params/param.ts | 14 +++++++-- src/params/type.ts | 1 + src/url/urlMatcher.ts | 67 +++++++++++++++++++++---------------------- 3 files changed, 44 insertions(+), 38 deletions(-) diff --git a/src/params/param.ts b/src/params/param.ts index e06b61d22..20c4772fa 100644 --- a/src/params/param.ts +++ b/src/params/param.ts @@ -1,4 +1,4 @@ -import {isInjectable, extend, isDefined, isString, isArray, filter, map, prop} from "../common/common"; +import {isInjectable, extend, isDefined, isString, isArray, filter, map, prop, curry} from "../common/common"; import {runtime} from "../common/angular1"; import matcherConfig from "../url/urlMatcherConfig"; import paramTypes from "./paramTypes"; @@ -76,6 +76,10 @@ export default class Param { extend(this, {id, type, location, squash, replace, isOptional, dynamic, config, array: arrayMode}); } + isDefaultValue(value: any) { + return this.isOptional && this.type.equals(this.value(), value); + } + /** * [Internal] Gets the decoded representation of a value if the value is defined, otherwise, returns the * default value, which may be the result of an injectable function. @@ -92,15 +96,19 @@ export default class Param { return defaultValue; }; - function hasReplaceVal(val) { return function(obj) { return obj.from === val; }; } + const hasReplaceVal = curry((val, obj) => obj.from === val); + const $replace = (value) => { var replacement: any = map(filter(this.replace, hasReplaceVal(value)), prop("to")); return replacement.length ? replacement[0] : value; }; + value = $replace(value); return !isDefined(value) ? $$getDefaultValue() : this.type.$normalize(value); } - toString() { return `{Param:${this.id} ${this.type} squash: '${this.squash}' optional: ${this.isOptional}}`; } + toString() { + return `{Param:${this.id} ${this.type} squash: '${this.squash}' optional: ${this.isOptional}}`; + } } diff --git a/src/params/type.ts b/src/params/type.ts index e528e6951..02c54231b 100644 --- a/src/params/type.ts +++ b/src/params/type.ts @@ -33,6 +33,7 @@ import {extend, isArray, isDefined, filter, map} from "../common/common"; export default class Type { pattern: RegExp; name: string; + raw: boolean; constructor(config) { extend(this, config); diff --git a/src/url/urlMatcher.ts b/src/url/urlMatcher.ts index 7050bc36a..1a9735726 100644 --- a/src/url/urlMatcher.ts +++ b/src/url/urlMatcher.ts @@ -138,12 +138,11 @@ export default class UrlMatcher { segment = pattern.substring(last, m.index); regexp = isSearch ? m[4] : m[4] || (m[1] == '*' ? '.*' : null); type = paramTypes.type(regexp || "string") || inherit(paramTypes.type("string"), { pattern: new RegExp(regexp, config.caseInsensitive ? 'i' : undefined) }); - return { - id: id, regexp: regexp, segment: segment, type: type, cfg: cfg - }; + return {id, regexp, segment, type, cfg}; } var p, param, segment; + while ((m = placeholder.exec(pattern))) { p = matchDetails(m, false); if (p.segment.indexOf('?') >= 0) break; // we're into the search part @@ -339,49 +338,47 @@ export default class UrlMatcher { * @param {Object} values the values to substitute for the parameters in this pattern. * @returns {string} the formatted URL (path and optionally search part). */ - format(values) { - values = values || {}; - var segments = this.segments, params = this.parameters(), paramset = this.params; - if (!this.validates(values)) return null; + format(values = {}) { + const url = { + params: this.parameters(), + paramSet: this.params, + nPath: this.segments.length - 1 + }; + var i, search = false, result = this.segments[0]; - var i, search = false, nPath = segments.length - 1, nTotal = params.length, result = segments[0]; + if (!this.validates(values)) return null; function encodeDashes(str) { // Replace dashes with encoded "\-" - return encodeURIComponent(str).replace(/-/g, function(c) { return `%5C%${c.charCodeAt(0).toString(16).toUpperCase()}`; }); + return encodeURIComponent(str).replace(/-/g, c => `%5C%${c.charCodeAt(0).toString(16).toUpperCase()}`); } - for (i = 0; i < nTotal; i++) { - var isPathParam = i < nPath; - var name = params[i], param: Param = paramset[name], value = param.value(values[name]); - var isDefaultValue = param.isOptional && param.type.equals(param.value(), value); + url.params.map((name, i) => { + var isPathParam = i < url.nPath; + var param: Param = url.paramSet[name], value = param.value(values[name]); + var isDefaultValue = param.isDefaultValue(value); var squash = isDefaultValue ? param.squash : false; var encoded = param.type.encode(value); - if (isPathParam) { - var nextSegment = segments[i + 1]; - if (squash === false) { - if (encoded != null) { - if (isArray(encoded)) { - result += map( encoded, encodeDashes).join("-"); - } else { - result += encodeURIComponent(encoded); - } - } - result += nextSegment; - } else if (squash === true) { - var capture = result.match(/\/$/) ? /\/?(.*)/ : /(.*)/; - result += nextSegment.match(capture)[1]; - } else if (isString(squash)) { - result += squash + nextSegment; - } - } else { - if (encoded == null || (isDefaultValue && squash !== false)) continue; - if (!isArray(encoded)) encoded = [ encoded ]; - encoded = map(encoded, encodeURIComponent).join(`&${name}=`); + if (!isPathParam) { + if (encoded == null || (isDefaultValue && squash !== false)) return; + if (!isArray(encoded)) encoded = [ encoded]; + + encoded = map( encoded, encodeURIComponent).join(`&${name}=`); result += (search ? '&' : '?') + (`${name}=${encoded}`); search = true; + return; } - } + + result += ((segment, result) => { + if (squash === true) return segment.match(result.match(/\/$/) ? /\/?(.*)/ : /(.*)/)[1]; + if (isString(squash)) return squash + segment; + if (squash !== false) return ""; + if (encoded == null) return segment; + if (isArray(encoded)) return map( encoded, encodeDashes).join("-") + segment; + if (param.type.raw) return encoded + segment; + return encodeURIComponent( encoded) + segment; + })(this.segments[i + 1], result); + }); if (values["#"]) result += "#" + values["#"];