Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // Regular segments do not begin with / : or *
- // But they can start with ?:, which is when they are optional
- var regular = '([^/:\*](?:\\?:)?\\w+)';
- // Dynamic segments match letters and hyphens
- var dynamicSegment = ':(\\w+)';
- // Specify a custom regex for the dynamic segment by
- // wrapping it in {} after the name of the segment
- var dynamicRegex = '(?:=([^\\/]+))?';
- // Combine the two dynamic pieces together
- var dynamic = dynamicSegment + dynamicRegex;
- // Like dynamic segments, letters and hyphens are allowed
- var splat = '\\*(\\w+)';
- // Create our RegExp from our base strings
- var regexStr = [regular, dynamic, splat].join('|');
- var regex = new RegExp(regexStr, 'g');
- // These are the built-in expressions that folks can use
- // for the most commonly-used data types. For instance,
- // you could write `/:id=int` to specify an integer.
- var builtInRegExp = {
- int: '\\d+',
- string: '[a-zA-Z]+',
- alphanum: '[\\da-zA-Z]+',
- bool: '0|1'
- };
- // Optional parameters are anything wrapped in parentheses
- var optionalParam = /\((.*?)\)/g;
- // Takes in a routePath, and returns an array of named segments and a RegExp to match against
- function compile(path, namedRegex = {}) {
- // The individual segments of the route's url
- var parts = [];
- // We build our specificity as a string. Comparing magnitude of numbers written in positional
- // notation is a similar algorithm to comparing routes. The string "721", when converted to a
- // number, is larger then any number where the leading value is less than "7". In other words,
- // numbers to the left are a magnitude greater than numbers to the right. So it goes with routes:
- // the specificity of segments to the left are a magnitude greater than segments to the right.
- var specificity = '';
- // Begin by replacing the optional pieces
- path = path.replace(optionalParam, '(?:$1)?');
- var str = '^' + path.replace(regex, (matched, regular, dynamic, customRegex, splat, location) => {
- var part = {};
- // Regular
- if (regular) {
- part = {
- type: 'regular',
- value: regular
- };
- parts.push(part);
- specificity += '4';
- return regular;
- }
- // Dynamic
- else if (dynamic) {
- part = {
- type: 'dynamic',
- value: dynamic
- };
- parts.push(part);
- var regex = customRegex || '[^/]+';
- var builtIn = namedRegex[regex] || builtInRegExp[regex];
- regex = builtIn ? builtIn : regex;
- // Custom RegExp are more specific than the default
- specificity += customRegex ? '3' : '2';
- return `(${regex})`;
- }
- // Splats
- else if (splat) {
- part = {
- type: 'splat',
- value: splat
- };
- parts.push(part);
- specificity += '1';
- return '([^?]*?)';
- }
- }) + '$';
- return {
- parts,
- specificity: +specificity,
- regex: new RegExp(str)
- };
- }
- // Takes a routeRegex generated by `compile` and a URL,
- // and returns an array of matched values
- function match(routeRegex, url) {
- url = decodeURI(url);
- var matches = routeRegex.regex.exec(url);
- // Bail if there are no matches
- if (!matches) { return; }
- // Otherwise, we match up our named params through a loop
- matches.shift();
- // Filter out our non-static parts of the route
- var nonStaticParts = routeRegex.parts.filter(part => part.type !== 'regular');
- var values = {}, item;
- for (var i = 0; i < matches.length; i++) {
- item = matches[i];
- values[nonStaticParts[i].value] = item ? item : undefined;
- }
- return values;
- }
- function generate(routeRegex, parts = {}) {
- return routeRegex.parts.reduce((memo, part) => {
- var dynamicValue;
- if (part.type === 'regular') {
- return memo + part.value + '/';
- } else {
- dynamicValue = parts[part.value] || '';
- if (dynamicValue) {
- dynamicValue += '/';
- }
- return memo + dynamicValue;
- }
- // We start with a `/`, then remove a trailing `/`. Immediately after we
- // ensure that the route is at least a `/`.
- }, '/').slice(0, -1) || '/';
- }
- export default {compile, match, generate};
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement