Skip to content

feat(urlMatcher): add raw encoding flag to Type #2218

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 17, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 11 additions & 3 deletions src/params/param.ts
Original file line number Diff line number Diff line change
@@ -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";
Expand Down Expand Up @@ -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.
Expand All @@ -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}}`;
}

}
1 change: 1 addition & 0 deletions src/params/type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
67 changes: 32 additions & 35 deletions src/url/urlMatcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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(<string[]> encoded, encodeDashes).join("-");
} else {
result += encodeURIComponent(<string>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 = [ <string> encoded ];
encoded = map(<string[]>encoded, encodeURIComponent).join(`&${name}=`);
if (!isPathParam) {
if (encoded == null || (isDefaultValue && squash !== false)) return;
if (!isArray(encoded)) encoded = [<string> encoded];

encoded = map(<string[]> 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(<string[]> encoded, encodeDashes).join("-") + segment;
if (param.type.raw) return encoded + segment;
return encodeURIComponent(<string> encoded) + segment;
})(this.segments[i + 1], result);
});

if (values["#"]) result += "#" + values["#"];

Expand Down