Skip to content

Commit

Permalink
appstate optimization
Browse files Browse the repository at this point in the history
  • Loading branch information
ilyapro committed Jul 26, 2016
1 parent 0beef5c commit 4711324
Show file tree
Hide file tree
Showing 10 changed files with 94 additions and 145 deletions.
2 changes: 1 addition & 1 deletion components/appState/stateConf.js
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@ StateConf.prototype.permalink = function(type, params, domain, strict) {
}

var uri = lastPattern.inject(params);
return (domain || '') + helpers.transform(uri, this);
return (domain || '') + uri;
};

module.exports = StateConf;
22 changes: 0 additions & 22 deletions components/appState/uri/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,25 +24,3 @@ exports.makeAlias = function(uriPart, params, alias) {
};
};

/**
* Transorm uri: take uri, parse it, create new uri
* Use if you change uri format and support old and new formats
*
* @param uri - start uri
* @param stateConf
* @returns {string} - transformed uri
*/
exports.transform = function(uri, stateConf) {
var slugEntries = parser.parse(stateConf.patterns, uri, [], stateConf.get('queryParamName'));
var state = {};
stateConf.invokeInjectors(slugEntries, state);

// Поскольку в notParsed может быть всё, что угодно, то приведем его в порядок
var cleanNotParsed = _.compact(slugEntries.notParsed.join('/').split('/')).join('/');
var newUri = _.compact([cleanNotParsed, resolver(stateConf, state)]).join('/');
if (newUri.charAt(0) != '/') {
return '/' + newUri;
}
return newUri;
};

2 changes: 1 addition & 1 deletion components/appState/uri/parser.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@

var _ = require('lodash');
var urlParse = require('url-parse');
var urlParse = require('url').parse;
var serializer = require('./serializer');

/**
Expand Down
65 changes: 25 additions & 40 deletions components/appState/uri/pattern.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,14 @@ var compileCache = {};
* @returns {RegExp} Регесп для разбора готовой строки, но не паттерна!
*/
function compile(pattern) {
if (!(pattern in compileCache)) {
var parts = pattern.split('/'),
reStr = stuff.escapeRegExp(parts[0]) + (parts.length > 1 ? '/' : '') + parts.slice(1).join('/');
var compiledPattern = compileCache[pattern];
if (!compiledPattern) {
var reStr = pattern.replace(/([.*+?^=!${}()|\[\]\\])/g, '\\$1');
reStr = reStr.replace(paramReG, '([^\/]+)');

compileCache[pattern] = new RegExp(reStr);
compiledPattern = new RegExp(reStr)
compileCache[pattern] = compiledPattern;
}

return compileCache[pattern];
return compiledPattern;
}

/**
Expand All @@ -34,28 +33,15 @@ function compile(pattern) {
function Pattern(pattern, validators) {
this.pattern = pattern;

this.patternRe = compile(pattern);

var parts = pattern.split('/');
this.slug = parts[0];
this.validators = validators;
var params = [];

for (var i = 1, len = parts.length; i < len; i++) {
var paramStr = parts[i];
var matchList = paramStr.match(paramReG);
if (!matchList) continue; // its just text, skip
this.slug = pattern.split('/')[0];

_.each(matchList, function(paramDef) {
var match = paramReN.exec(paramDef);

var name = match[1];

params.push(name);
});
}
this.params = _.map(pattern.match(paramReG), function(param) {
return param.slice(1);
});

this.params = params;
this.patternRe = compile(pattern);
}

/**
Expand All @@ -79,21 +65,21 @@ Pattern.prototype.checkData = function(data) {
var errorKeys = [];

_.each(this.params, function(name) {
if (name in data) {
var value = data[name];
if (name in data) {
var value = data[name];

var validator = this.validatorFor(name);
var validator = this.validatorFor(name);

if (validator && validator.toUrl) {
value = validator.toUrl(value);
}
if (validator && validator.toUrl) {
value = validator.toUrl(value);
}

if (validator && !validator(value)) {
errorKeys.push(name);
}
} else {
errorKeys.push(name); // key is missing
}
if (validator && !validator(value)) {
errorKeys.push(name);
}
} else {
errorKeys.push(name); // key is missing
}
}, this);

return errorKeys.length ? errorKeys : null;
Expand Down Expand Up @@ -152,7 +138,7 @@ Pattern.prototype.inject = function(data, encode) {
encode = encode == null ? true : encode;
var self = this;

var str = this.pattern.replace(paramReG, function(match, name) {
return this.pattern.replace(paramReG, function(match, name) {
var value = data[name] != null ? data[name] : '';
var validator = self.validatorFor(name);

Expand All @@ -161,11 +147,10 @@ Pattern.prototype.inject = function(data, encode) {
}

if (encode) {
value = serializer.encodeSlashes(value);
value = serializer.encodeComponent(value);
}
return value;
});
return encode ? serializer.encode(str) : str;
};

module.exports = Pattern;
2 changes: 1 addition & 1 deletion components/stateTracker.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ StateTracker.prototype.resolveURL = function(url) {
url = url || document.location.pathname;

if (!history.emulate) { // если у нас не hash url, добавляем query string чтобы не потерялась
url = stuff.extendQuery(location.href, url, this.forcedRenewParam);
url = stuff.extendQuery(url, location.href, this.forcedRenewParam);
}

return url;
Expand Down
58 changes: 20 additions & 38 deletions lib/expandString.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,52 +4,34 @@ var _ = require('lodash');

var optionalRe = /\[([^\]]+)\]/;

function stripSlashes(str) {
return str.replace(/\/+$/, '').replace(/^\/+/, '');
function replaceMatch(str, match, value) {
return str.slice(0, match.index) + value + str.slice(match.index + match[0].length);
}

function joinParts(parts) {
return _.chain(parts)
.map(stripSlashes)
.compact()
.value()
.join('/');
function expandFirst(str) {
var match = str.match(optionalRe);
if (!match) {
return [str];
} else {
return [
replaceMatch(str, match, match[1]),
replaceMatch(str, match, '')
];
}
}

function replaceMatch(str, match, value) {
return joinParts([str.substring(0, match.index), value, str.substr(match.index + match[0].length)]);
function doExpand(str) {
var parts = expandFirst(str);
if (parts.length > 1) {
return _.flatten(_.map(parts, doExpand));
} else {
return parts;
}
}

/**
* Превращает строку вида foo/[:id], в массив ['foo', 'foo/:id']
* @param str
* @returns {String[]}
*/
function expand(str) {
var prefix = str.charAt(0) == '/' ? '/' : '';

function expandFirst(str) {
var match = str.match(optionalRe);
if (!match) {
return [str];
} else {
return [
prefix + replaceMatch(str, match, match[1]),
prefix + replaceMatch(str, match, '')
];
}
}

function doExpand(str) {
var parts = expandFirst(str);
if (parts.length > 1) {
return _.flatten(_.map(parts, doExpand));
} else {
return parts;
}
}

return doExpand(str);
}

module.exports = expand;
module.exports = doExpand;
67 changes: 36 additions & 31 deletions lib/stuff.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
* @module stuff
*/

var querystring = require('querystring');
var _ = require('lodash');

/**
Expand Down Expand Up @@ -46,16 +47,16 @@ function logToChannel(channel, type, args) {
}
}

/**
* Форматирует строку.
*
* @example
* _.format('Hello %1 and %2', 'Vasya', 'Petya'); // => 'Hello Vasya and Petya'
*
* @param {string} str - Форматируемая строка.
* @param {...Array} values - Значения для форматирования.
* @returns {string} Отформатированная строка.
*/
/**
* Форматирует строку.
*
* @example
* _.format('Hello %1 and %2', 'Vasya', 'Petya'); // => 'Hello Vasya and Petya'
*
* @param {string} str - Форматируемая строка.
* @param {...Array} values - Значения для форматирования.
* @returns {string} Отформатированная строка.
*/
exports.format = function(str) {
var values = arguments;

Expand Down Expand Up @@ -182,31 +183,35 @@ exports.uri2state = function(uri) {
/**
* Extend query string
*
* @param [String] urlOld
* @param [String] urlNew
* @param [String] newUrl
* @param [String|Object] oldUrl
* @returns {String}
*/
exports.extendQuery = function(urlOld, urlNew, forcedRenewParam) {
if (!urlOld && !urlNew) return '';
if (!urlOld) return urlNew;
if (!urlNew) return urlOld;

var urlParse = require('url-parse');
var newLocation = urlParse(urlNew, true);
var currentLocation = urlParse(urlOld, true);
if (forcedRenewParam) {
delete currentLocation.query[forcedRenewParam];
exports.extendQuery = function(newUrl, oldUrl, forcedRenewParam) {
if (_.isEmpty(oldUrl) && _.isEmpty(newUrl)) return '';
if (_.isEmpty(oldUrl)) return newUrl;
if (_.isEmpty(newUrl)) return oldUrl;

var newQueryIndex = newUrl.indexOf('?');
var newQuery = newQueryIndex != -1 ? newUrl.slice(newQueryIndex + 1) : '';
var newQueryParsed = newQuery ? querystring.parse(newQuery) : {};

var oldQueryParsed;
if (_.isString(oldUrl)) {
var oldQueryIndex = oldUrl.indexOf('?');
var oldQuery = oldQueryIndex != -1 ? oldUrl.slice(oldQueryIndex + 1) : '';
oldQueryParsed = oldQuery ? querystring.parse(oldQuery) : {};
} else {
oldQueryParsed = oldUrl;
}

if (!newLocation.protocol) { // some of these params can be absent
newLocation.set('protocol', currentLocation.protocol);
}
if (!newLocation.host) {
newLocation.set('host', currentLocation.host);
}
if (!newLocation.hostname) {
newLocation.set('hostname', currentLocation.hostname);
if (forcedRenewParam) {
delete oldQueryParsed[forcedRenewParam];
}

return newLocation.set('query', _.extend(currentLocation.query, newLocation.query)).toString();
var resQueryParsed = _.extend(oldQueryParsed, newQueryParsed);
var resBase = newQueryIndex != -1 ? newUrl.slice(0, newQueryIndex) : newUrl;
var resQuery = _.isEmpty(resQueryParsed) ? '' : '?' + querystring.stringify(resQueryParsed);

return resBase + resQuery;
};
10 changes: 5 additions & 5 deletions lib/tests/expandString.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,21 @@ describe('expandString', function() {
});

it('не должен терять слэши в начале строки', function() {
assert.deepEqual(expand('/city/:city/[page/:page]'), [
assert.deepEqual(expand('/city/:city[/page/:page]'), [
'/city/:city/page/:page',
'/city/:city'
]);
});

it('очень простой пример', function() {
assert.deepEqual(expand('foo/[:id]'), [
assert.deepEqual(expand('foo[/:id]'), [
'foo/:id',
'foo'
]);
});

it("простой пример", function() {
assert.deepEqual(expand('foo/[:ab]/[firms/:id]'), [
assert.deepEqual(expand('foo[/:ab][/firms/:id]'), [
'foo/:ab/firms/:id',
'foo/:ab',
'foo/firms/:id',
Expand All @@ -33,7 +33,7 @@ describe('expandString', function() {
});

it('слэш внутри опциона (нежелательно, но работать должно)', function() {
assert.deepEqual(expand('foo/[:ab/][firms/:id]'), [
assert.deepEqual(expand('foo[/:ab][/firms/:id]'), [
'foo/:ab/firms/:id',
'foo/:ab',
'foo/firms/:id',
Expand All @@ -42,7 +42,7 @@ describe('expandString', function() {
});

it('пример из трех опционов', function() {
assert.deepEqual(expand('foo/[id/:id]/[ab/:page]/[filters/:text]'), [
assert.deepEqual(expand('foo[/id/:id][/ab/:page][/filters/:text]'), [
'foo/id/:id/ab/:page/filters/:text',
'foo/id/:id/ab/:page',
'foo/id/:id/filters/:text',
Expand Down

0 comments on commit 4711324

Please sign in to comment.