@tinkoff/router 0.2.7 → 0.2.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/lib/components/react/context.browser.js +7 -0
  2. package/lib/components/react/context.es.js +7 -0
  3. package/lib/components/react/context.js +13 -0
  4. package/lib/components/react/provider.browser.js +12 -0
  5. package/lib/components/react/provider.es.js +12 -0
  6. package/lib/components/react/provider.js +16 -0
  7. package/lib/components/react/useNavigate.browser.js +17 -0
  8. package/lib/components/react/useNavigate.es.js +17 -0
  9. package/lib/components/react/useNavigate.js +21 -0
  10. package/lib/components/react/useRoute.browser.js +8 -0
  11. package/lib/components/react/useRoute.es.js +8 -0
  12. package/lib/components/react/useRoute.js +12 -0
  13. package/lib/components/react/useRouter.browser.js +8 -0
  14. package/lib/components/react/useRouter.es.js +8 -0
  15. package/lib/components/react/useRouter.js +12 -0
  16. package/lib/components/react/useUrl.browser.js +8 -0
  17. package/lib/components/react/useUrl.es.js +8 -0
  18. package/lib/components/react/useUrl.js +12 -0
  19. package/lib/history/base.browser.js +11 -0
  20. package/lib/history/base.es.js +11 -0
  21. package/lib/history/base.js +15 -0
  22. package/lib/history/client.browser.js +121 -0
  23. package/lib/history/client.es.js +121 -0
  24. package/lib/history/client.js +125 -0
  25. package/lib/history/server.es.js +15 -0
  26. package/lib/history/server.js +19 -0
  27. package/lib/history/wrapper.browser.js +72 -0
  28. package/lib/history/wrapper.es.js +72 -0
  29. package/lib/history/wrapper.js +80 -0
  30. package/lib/index.browser.js +12 -1169
  31. package/lib/index.es.js +12 -1097
  32. package/lib/index.js +36 -1124
  33. package/lib/logger.browser.js +15 -0
  34. package/lib/logger.es.js +15 -0
  35. package/lib/logger.js +23 -0
  36. package/lib/router/abstract.browser.js +395 -0
  37. package/lib/router/abstract.es.js +395 -0
  38. package/lib/router/abstract.js +404 -0
  39. package/lib/router/browser.browser.js +166 -0
  40. package/lib/router/client.browser.js +116 -0
  41. package/lib/router/client.es.js +116 -0
  42. package/lib/router/client.js +120 -0
  43. package/lib/router/clientNoSpa.browser.js +17 -0
  44. package/lib/router/clientNoSpa.es.js +17 -0
  45. package/lib/router/clientNoSpa.js +21 -0
  46. package/lib/router/server.es.js +85 -0
  47. package/lib/router/server.js +89 -0
  48. package/lib/tree/constants.browser.js +6 -0
  49. package/lib/tree/constants.es.js +6 -0
  50. package/lib/tree/constants.js +13 -0
  51. package/lib/tree/tree.browser.js +148 -0
  52. package/lib/tree/tree.es.js +148 -0
  53. package/lib/tree/tree.js +158 -0
  54. package/lib/tree/utils.browser.js +77 -0
  55. package/lib/tree/utils.es.js +77 -0
  56. package/lib/tree/utils.js +90 -0
  57. package/lib/utils.browser.js +35 -0
  58. package/lib/utils.es.js +35 -0
  59. package/lib/utils.js +48 -0
  60. package/package.json +5 -6
@@ -0,0 +1,148 @@
1
+ import each from '@tinkoff/utils/array/each';
2
+ import find from '@tinkoff/utils/array/find';
3
+ import findIndex from '@tinkoff/utils/array/findIndex';
4
+ import { getParts, parse } from './utils.es.js';
5
+ import { HISTORY_FALLBACK_REGEXP } from './constants.es.js';
6
+
7
+ const createTree = (route) => {
8
+ return {
9
+ route,
10
+ children: Object.create(null),
11
+ parameters: [],
12
+ };
13
+ };
14
+ const createNavigationRoute = (route, pathname, params) => {
15
+ return {
16
+ ...route,
17
+ actualPath: pathname,
18
+ params: params !== null && params !== void 0 ? params : {},
19
+ };
20
+ };
21
+ class RouteTree {
22
+ constructor(routes) {
23
+ this.tree = createTree();
24
+ each((route) => this.addRoute(route), routes);
25
+ }
26
+ // eslint-disable-next-line max-statements
27
+ addRoute(route) {
28
+ const parts = getParts(route.path);
29
+ let currentTree = this.tree;
30
+ for (let i = 0; i < parts.length; i++) {
31
+ const part = parts[i];
32
+ const parsed = parse(part);
33
+ if (parsed.type === 1 /* PartType.historyFallback */) {
34
+ currentTree.historyFallbackRoute = route;
35
+ return;
36
+ }
37
+ if (parsed.type === 2 /* PartType.wildcard */) {
38
+ currentTree.wildcardRoute = route;
39
+ return;
40
+ }
41
+ if (parsed.type === 3 /* PartType.parameter */) {
42
+ const { paramName, regexp, optional } = parsed;
43
+ // prevent from creating new entries for same route
44
+ const found = find((par) => par.key === part, currentTree.parameters);
45
+ if (found) {
46
+ currentTree = found.tree;
47
+ }
48
+ else {
49
+ const parameter = {
50
+ key: part,
51
+ paramName,
52
+ regexp,
53
+ optional,
54
+ tree: createTree(),
55
+ };
56
+ if (regexp && !optional) {
57
+ // insert parameters with regexp before
58
+ const index = findIndex((par) => !par.regexp, currentTree.parameters);
59
+ currentTree.parameters.splice(index, 0, parameter);
60
+ }
61
+ else {
62
+ currentTree.parameters.push(parameter);
63
+ }
64
+ currentTree = parameter.tree;
65
+ }
66
+ }
67
+ else {
68
+ if (!currentTree.children[part]) {
69
+ currentTree.children[part] = createTree();
70
+ }
71
+ currentTree = currentTree.children[part];
72
+ }
73
+ }
74
+ currentTree.route = route;
75
+ }
76
+ getRoute(pathname) {
77
+ return this.findRoute(pathname, 'route');
78
+ }
79
+ getWildcard(pathname) {
80
+ return this.findRoute(pathname, 'wildcardRoute');
81
+ }
82
+ getHistoryFallback(pathname) {
83
+ const route = this.findRoute(pathname, 'historyFallbackRoute');
84
+ return (route && {
85
+ ...route,
86
+ // remove <history-fallback> from path
87
+ actualPath: route.path.replace(HISTORY_FALLBACK_REGEXP, '') || '/',
88
+ });
89
+ }
90
+ // eslint-disable-next-line max-statements
91
+ findRoute(pathname, propertyName) {
92
+ // we should use exact match only for classic route
93
+ // as special routes (for not-found and history-fallback) are defined for whole subtree
94
+ const exactMatch = propertyName === 'route';
95
+ const parts = getParts(pathname);
96
+ const queue = [
97
+ [this.tree, 0],
98
+ ];
99
+ while (queue.length) {
100
+ const [currentTree, index, params] = queue.pop();
101
+ const { children, parameters } = currentTree;
102
+ // this flag mean we can only check for optional parameters
103
+ // as we didn't find static route for this path, but still may find
104
+ // some inner route inside optional branch
105
+ // the value of parameter will be empty in this case ofc
106
+ let optionalOnly = false;
107
+ if (index >= parts.length) {
108
+ if (currentTree[propertyName]) {
109
+ return createNavigationRoute(currentTree[propertyName], pathname, params);
110
+ }
111
+ // here we cant check any options except for optional parameters
112
+ optionalOnly = true;
113
+ }
114
+ // first add to queue special routes (not-found or history-fallback) to check it after other cases, as it will be processed last
115
+ if (!exactMatch && currentTree[propertyName]) {
116
+ queue.push([currentTree, parts.length, params]);
117
+ }
118
+ const part = parts[index];
119
+ const child = children[part];
120
+ // then add checks for only optional
121
+ for (const param of parameters) {
122
+ const { optional, tree } = param;
123
+ if (optional) {
124
+ queue.push([tree, index, params]);
125
+ }
126
+ }
127
+ if (optionalOnly) {
128
+ continue;
129
+ }
130
+ // for non-optional cases
131
+ for (let i = parameters.length - 1; i >= 0; i--) {
132
+ const param = parameters[i];
133
+ const { paramName, tree, regexp } = param;
134
+ const match = regexp === null || regexp === void 0 ? void 0 : regexp.exec(part);
135
+ const paramValue = regexp ? match === null || match === void 0 ? void 0 : match[1] : part;
136
+ if (paramValue) {
137
+ queue.push([tree, index + 1, { ...params, [paramName]: paramValue }]);
138
+ }
139
+ }
140
+ if (child) {
141
+ // add checks for static child subtree last as it will be processed first after queue.pop
142
+ queue.push([child, index + 1, params]);
143
+ }
144
+ }
145
+ }
146
+ }
147
+
148
+ export { RouteTree };
@@ -0,0 +1,158 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var each = require('@tinkoff/utils/array/each');
6
+ var find = require('@tinkoff/utils/array/find');
7
+ var findIndex = require('@tinkoff/utils/array/findIndex');
8
+ var utils = require('./utils.js');
9
+ var constants = require('./constants.js');
10
+
11
+ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
12
+
13
+ var each__default = /*#__PURE__*/_interopDefaultLegacy(each);
14
+ var find__default = /*#__PURE__*/_interopDefaultLegacy(find);
15
+ var findIndex__default = /*#__PURE__*/_interopDefaultLegacy(findIndex);
16
+
17
+ const createTree = (route) => {
18
+ return {
19
+ route,
20
+ children: Object.create(null),
21
+ parameters: [],
22
+ };
23
+ };
24
+ const createNavigationRoute = (route, pathname, params) => {
25
+ return {
26
+ ...route,
27
+ actualPath: pathname,
28
+ params: params !== null && params !== void 0 ? params : {},
29
+ };
30
+ };
31
+ class RouteTree {
32
+ constructor(routes) {
33
+ this.tree = createTree();
34
+ each__default["default"]((route) => this.addRoute(route), routes);
35
+ }
36
+ // eslint-disable-next-line max-statements
37
+ addRoute(route) {
38
+ const parts = utils.getParts(route.path);
39
+ let currentTree = this.tree;
40
+ for (let i = 0; i < parts.length; i++) {
41
+ const part = parts[i];
42
+ const parsed = utils.parse(part);
43
+ if (parsed.type === 1 /* PartType.historyFallback */) {
44
+ currentTree.historyFallbackRoute = route;
45
+ return;
46
+ }
47
+ if (parsed.type === 2 /* PartType.wildcard */) {
48
+ currentTree.wildcardRoute = route;
49
+ return;
50
+ }
51
+ if (parsed.type === 3 /* PartType.parameter */) {
52
+ const { paramName, regexp, optional } = parsed;
53
+ // prevent from creating new entries for same route
54
+ const found = find__default["default"]((par) => par.key === part, currentTree.parameters);
55
+ if (found) {
56
+ currentTree = found.tree;
57
+ }
58
+ else {
59
+ const parameter = {
60
+ key: part,
61
+ paramName,
62
+ regexp,
63
+ optional,
64
+ tree: createTree(),
65
+ };
66
+ if (regexp && !optional) {
67
+ // insert parameters with regexp before
68
+ const index = findIndex__default["default"]((par) => !par.regexp, currentTree.parameters);
69
+ currentTree.parameters.splice(index, 0, parameter);
70
+ }
71
+ else {
72
+ currentTree.parameters.push(parameter);
73
+ }
74
+ currentTree = parameter.tree;
75
+ }
76
+ }
77
+ else {
78
+ if (!currentTree.children[part]) {
79
+ currentTree.children[part] = createTree();
80
+ }
81
+ currentTree = currentTree.children[part];
82
+ }
83
+ }
84
+ currentTree.route = route;
85
+ }
86
+ getRoute(pathname) {
87
+ return this.findRoute(pathname, 'route');
88
+ }
89
+ getWildcard(pathname) {
90
+ return this.findRoute(pathname, 'wildcardRoute');
91
+ }
92
+ getHistoryFallback(pathname) {
93
+ const route = this.findRoute(pathname, 'historyFallbackRoute');
94
+ return (route && {
95
+ ...route,
96
+ // remove <history-fallback> from path
97
+ actualPath: route.path.replace(constants.HISTORY_FALLBACK_REGEXP, '') || '/',
98
+ });
99
+ }
100
+ // eslint-disable-next-line max-statements
101
+ findRoute(pathname, propertyName) {
102
+ // we should use exact match only for classic route
103
+ // as special routes (for not-found and history-fallback) are defined for whole subtree
104
+ const exactMatch = propertyName === 'route';
105
+ const parts = utils.getParts(pathname);
106
+ const queue = [
107
+ [this.tree, 0],
108
+ ];
109
+ while (queue.length) {
110
+ const [currentTree, index, params] = queue.pop();
111
+ const { children, parameters } = currentTree;
112
+ // this flag mean we can only check for optional parameters
113
+ // as we didn't find static route for this path, but still may find
114
+ // some inner route inside optional branch
115
+ // the value of parameter will be empty in this case ofc
116
+ let optionalOnly = false;
117
+ if (index >= parts.length) {
118
+ if (currentTree[propertyName]) {
119
+ return createNavigationRoute(currentTree[propertyName], pathname, params);
120
+ }
121
+ // here we cant check any options except for optional parameters
122
+ optionalOnly = true;
123
+ }
124
+ // first add to queue special routes (not-found or history-fallback) to check it after other cases, as it will be processed last
125
+ if (!exactMatch && currentTree[propertyName]) {
126
+ queue.push([currentTree, parts.length, params]);
127
+ }
128
+ const part = parts[index];
129
+ const child = children[part];
130
+ // then add checks for only optional
131
+ for (const param of parameters) {
132
+ const { optional, tree } = param;
133
+ if (optional) {
134
+ queue.push([tree, index, params]);
135
+ }
136
+ }
137
+ if (optionalOnly) {
138
+ continue;
139
+ }
140
+ // for non-optional cases
141
+ for (let i = parameters.length - 1; i >= 0; i--) {
142
+ const param = parameters[i];
143
+ const { paramName, tree, regexp } = param;
144
+ const match = regexp === null || regexp === void 0 ? void 0 : regexp.exec(part);
145
+ const paramValue = regexp ? match === null || match === void 0 ? void 0 : match[1] : part;
146
+ if (paramValue) {
147
+ queue.push([tree, index + 1, { ...params, [paramName]: paramValue }]);
148
+ }
149
+ }
150
+ if (child) {
151
+ // add checks for static child subtree last as it will be processed first after queue.pop
152
+ queue.push([child, index + 1, params]);
153
+ }
154
+ }
155
+ }
156
+ }
157
+
158
+ exports.RouteTree = RouteTree;
@@ -0,0 +1,77 @@
1
+ import map from '@tinkoff/utils/array/map';
2
+ import { HISTORY_FALLBACK_REGEXP, WILDCARD_REGEXP, PARAMETER_DELIMITER, PARAM_PARSER_REGEXP } from './constants.browser.js';
3
+ import { normalizeTrailingSlash } from '../utils.browser.js';
4
+
5
+ const getParts = (pathname) => pathname
6
+ .split('/')
7
+ .slice(pathname.startsWith('/') ? 1 : 0, pathname.endsWith('/') ? -1 : Infinity);
8
+ const isHistoryFallback = (part) => {
9
+ return HISTORY_FALLBACK_REGEXP.test(part);
10
+ };
11
+ const isWildcard = (part) => {
12
+ return WILDCARD_REGEXP.test(part);
13
+ };
14
+ const isParameterized = (part) => {
15
+ return part.includes(PARAMETER_DELIMITER);
16
+ };
17
+ const parseParameter = (part) => {
18
+ const [prefix = '', param, postfix = ''] = part.split(PARAMETER_DELIMITER);
19
+ const match = PARAM_PARSER_REGEXP.exec(param);
20
+ if (!match) {
21
+ throw new Error('parameters should satisfy pattern "prefix:paramName(regexp)\\?:postfix"');
22
+ }
23
+ const [, paramName, regexp, optional] = match;
24
+ const useRegexp = prefix || postfix || regexp;
25
+ return {
26
+ type: 3 /* PartType.parameter */,
27
+ paramName,
28
+ regexp: useRegexp
29
+ ? new RegExp(`^${prefix}(${regexp || '.+'})${optional ? '?' : ''}${postfix}$`)
30
+ : undefined,
31
+ optional: !!optional && !prefix && !postfix,
32
+ };
33
+ };
34
+ const parse = (part) => {
35
+ if (isHistoryFallback(part)) {
36
+ return { type: 1 /* PartType.historyFallback */ };
37
+ }
38
+ if (isWildcard(part)) {
39
+ return { type: 2 /* PartType.wildcard */ };
40
+ }
41
+ if (isParameterized(part)) {
42
+ return parseParameter(part);
43
+ }
44
+ return { type: 0 /* PartType.literal */, value: part };
45
+ };
46
+ const makePath = (pathname, params) => {
47
+ const parts = getParts(pathname);
48
+ const result = map((part) => {
49
+ var _a;
50
+ if (isHistoryFallback(part) || isWildcard(part)) {
51
+ throw new Error(`Pathname should be only a string with dynamic parameters, not a special string, got ${pathname}`);
52
+ }
53
+ if (isParameterized(part)) {
54
+ const [prefix = '', param = '', postfix = ''] = part.split(PARAMETER_DELIMITER);
55
+ const match = PARAM_PARSER_REGEXP.exec(param);
56
+ if (!match) {
57
+ throw new Error('parameters should satisfy pattern "prefix:paramName(regexp)\\?:postfix"');
58
+ }
59
+ const [, paramName, regexp, optional] = match;
60
+ const value = (_a = params[paramName]) === null || _a === void 0 ? void 0 : _a.toString();
61
+ if (optional && !value) {
62
+ return '';
63
+ }
64
+ if (!value) {
65
+ throw new Error(`value for parameter for ${paramName} should be defined in params`);
66
+ }
67
+ if (regexp && !new RegExp(regexp).test(value)) {
68
+ throw new Error(`passed parameter for ${paramName} should satisfy regxep: ${regexp}, got: ${value}`);
69
+ }
70
+ return prefix + value + postfix || part;
71
+ }
72
+ return part;
73
+ }, parts).join('/');
74
+ return normalizeTrailingSlash(`/${result}`, pathname.endsWith('/'));
75
+ };
76
+
77
+ export { getParts, isHistoryFallback, isParameterized, isWildcard, makePath, parse };
@@ -0,0 +1,77 @@
1
+ import map from '@tinkoff/utils/array/map';
2
+ import { HISTORY_FALLBACK_REGEXP, WILDCARD_REGEXP, PARAMETER_DELIMITER, PARAM_PARSER_REGEXP } from './constants.es.js';
3
+ import { normalizeTrailingSlash } from '../utils.es.js';
4
+
5
+ const getParts = (pathname) => pathname
6
+ .split('/')
7
+ .slice(pathname.startsWith('/') ? 1 : 0, pathname.endsWith('/') ? -1 : Infinity);
8
+ const isHistoryFallback = (part) => {
9
+ return HISTORY_FALLBACK_REGEXP.test(part);
10
+ };
11
+ const isWildcard = (part) => {
12
+ return WILDCARD_REGEXP.test(part);
13
+ };
14
+ const isParameterized = (part) => {
15
+ return part.includes(PARAMETER_DELIMITER);
16
+ };
17
+ const parseParameter = (part) => {
18
+ const [prefix = '', param, postfix = ''] = part.split(PARAMETER_DELIMITER);
19
+ const match = PARAM_PARSER_REGEXP.exec(param);
20
+ if (!match) {
21
+ throw new Error('parameters should satisfy pattern "prefix:paramName(regexp)\\?:postfix"');
22
+ }
23
+ const [, paramName, regexp, optional] = match;
24
+ const useRegexp = prefix || postfix || regexp;
25
+ return {
26
+ type: 3 /* PartType.parameter */,
27
+ paramName,
28
+ regexp: useRegexp
29
+ ? new RegExp(`^${prefix}(${regexp || '.+'})${optional ? '?' : ''}${postfix}$`)
30
+ : undefined,
31
+ optional: !!optional && !prefix && !postfix,
32
+ };
33
+ };
34
+ const parse = (part) => {
35
+ if (isHistoryFallback(part)) {
36
+ return { type: 1 /* PartType.historyFallback */ };
37
+ }
38
+ if (isWildcard(part)) {
39
+ return { type: 2 /* PartType.wildcard */ };
40
+ }
41
+ if (isParameterized(part)) {
42
+ return parseParameter(part);
43
+ }
44
+ return { type: 0 /* PartType.literal */, value: part };
45
+ };
46
+ const makePath = (pathname, params) => {
47
+ const parts = getParts(pathname);
48
+ const result = map((part) => {
49
+ var _a;
50
+ if (isHistoryFallback(part) || isWildcard(part)) {
51
+ throw new Error(`Pathname should be only a string with dynamic parameters, not a special string, got ${pathname}`);
52
+ }
53
+ if (isParameterized(part)) {
54
+ const [prefix = '', param = '', postfix = ''] = part.split(PARAMETER_DELIMITER);
55
+ const match = PARAM_PARSER_REGEXP.exec(param);
56
+ if (!match) {
57
+ throw new Error('parameters should satisfy pattern "prefix:paramName(regexp)\\?:postfix"');
58
+ }
59
+ const [, paramName, regexp, optional] = match;
60
+ const value = (_a = params[paramName]) === null || _a === void 0 ? void 0 : _a.toString();
61
+ if (optional && !value) {
62
+ return '';
63
+ }
64
+ if (!value) {
65
+ throw new Error(`value for parameter for ${paramName} should be defined in params`);
66
+ }
67
+ if (regexp && !new RegExp(regexp).test(value)) {
68
+ throw new Error(`passed parameter for ${paramName} should satisfy regxep: ${regexp}, got: ${value}`);
69
+ }
70
+ return prefix + value + postfix || part;
71
+ }
72
+ return part;
73
+ }, parts).join('/');
74
+ return normalizeTrailingSlash(`/${result}`, pathname.endsWith('/'));
75
+ };
76
+
77
+ export { getParts, isHistoryFallback, isParameterized, isWildcard, makePath, parse };
@@ -0,0 +1,90 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var map = require('@tinkoff/utils/array/map');
6
+ var constants = require('./constants.js');
7
+ var utils = require('../utils.js');
8
+
9
+ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
10
+
11
+ var map__default = /*#__PURE__*/_interopDefaultLegacy(map);
12
+
13
+ const getParts = (pathname) => pathname
14
+ .split('/')
15
+ .slice(pathname.startsWith('/') ? 1 : 0, pathname.endsWith('/') ? -1 : Infinity);
16
+ const isHistoryFallback = (part) => {
17
+ return constants.HISTORY_FALLBACK_REGEXP.test(part);
18
+ };
19
+ const isWildcard = (part) => {
20
+ return constants.WILDCARD_REGEXP.test(part);
21
+ };
22
+ const isParameterized = (part) => {
23
+ return part.includes(constants.PARAMETER_DELIMITER);
24
+ };
25
+ const parseParameter = (part) => {
26
+ const [prefix = '', param, postfix = ''] = part.split(constants.PARAMETER_DELIMITER);
27
+ const match = constants.PARAM_PARSER_REGEXP.exec(param);
28
+ if (!match) {
29
+ throw new Error('parameters should satisfy pattern "prefix:paramName(regexp)\\?:postfix"');
30
+ }
31
+ const [, paramName, regexp, optional] = match;
32
+ const useRegexp = prefix || postfix || regexp;
33
+ return {
34
+ type: 3 /* PartType.parameter */,
35
+ paramName,
36
+ regexp: useRegexp
37
+ ? new RegExp(`^${prefix}(${regexp || '.+'})${optional ? '?' : ''}${postfix}$`)
38
+ : undefined,
39
+ optional: !!optional && !prefix && !postfix,
40
+ };
41
+ };
42
+ const parse = (part) => {
43
+ if (isHistoryFallback(part)) {
44
+ return { type: 1 /* PartType.historyFallback */ };
45
+ }
46
+ if (isWildcard(part)) {
47
+ return { type: 2 /* PartType.wildcard */ };
48
+ }
49
+ if (isParameterized(part)) {
50
+ return parseParameter(part);
51
+ }
52
+ return { type: 0 /* PartType.literal */, value: part };
53
+ };
54
+ const makePath = (pathname, params) => {
55
+ const parts = getParts(pathname);
56
+ const result = map__default["default"]((part) => {
57
+ var _a;
58
+ if (isHistoryFallback(part) || isWildcard(part)) {
59
+ throw new Error(`Pathname should be only a string with dynamic parameters, not a special string, got ${pathname}`);
60
+ }
61
+ if (isParameterized(part)) {
62
+ const [prefix = '', param = '', postfix = ''] = part.split(constants.PARAMETER_DELIMITER);
63
+ const match = constants.PARAM_PARSER_REGEXP.exec(param);
64
+ if (!match) {
65
+ throw new Error('parameters should satisfy pattern "prefix:paramName(regexp)\\?:postfix"');
66
+ }
67
+ const [, paramName, regexp, optional] = match;
68
+ const value = (_a = params[paramName]) === null || _a === void 0 ? void 0 : _a.toString();
69
+ if (optional && !value) {
70
+ return '';
71
+ }
72
+ if (!value) {
73
+ throw new Error(`value for parameter for ${paramName} should be defined in params`);
74
+ }
75
+ if (regexp && !new RegExp(regexp).test(value)) {
76
+ throw new Error(`passed parameter for ${paramName} should satisfy regxep: ${regexp}, got: ${value}`);
77
+ }
78
+ return prefix + value + postfix || part;
79
+ }
80
+ return part;
81
+ }, parts).join('/');
82
+ return utils.normalizeTrailingSlash(`/${result}`, pathname.endsWith('/'));
83
+ };
84
+
85
+ exports.getParts = getParts;
86
+ exports.isHistoryFallback = isHistoryFallback;
87
+ exports.isParameterized = isParameterized;
88
+ exports.isWildcard = isWildcard;
89
+ exports.makePath = makePath;
90
+ exports.parse = parse;
@@ -0,0 +1,35 @@
1
+ import T from '@tinkoff/utils/function/T';
2
+
3
+ const isFilePath = (pathname) => {
4
+ return /\/.+\.[^/]+$/.test(pathname);
5
+ };
6
+ const normalizeTrailingSlash = (pathname, trailingSlash = false) => {
7
+ const hasTrailingSlash = pathname.endsWith('/');
8
+ if (trailingSlash) {
9
+ return hasTrailingSlash || isFilePath(pathname) ? pathname : `${pathname}/`;
10
+ }
11
+ return pathname.length > 1 && hasTrailingSlash ? pathname.slice(0, -1) : pathname;
12
+ };
13
+ const normalizeManySlashes = (hrefOrPath) => {
14
+ const [href, ...search] = hrefOrPath.split('?');
15
+ return [href.replace(/\/+/g, '/').replace(/^(\w+):\//, '$1://'), ...search].join('?');
16
+ };
17
+ const isSameHost = typeof window === 'undefined'
18
+ ? T
19
+ : (url) => {
20
+ return !url.host || url.host === window.location.host;
21
+ };
22
+ const makeNavigateOptions = (options) => {
23
+ if (typeof options === 'string') {
24
+ return { url: options };
25
+ }
26
+ return options;
27
+ };
28
+ const registerHook = (hooksSet, hook) => {
29
+ hooksSet.add(hook);
30
+ return () => {
31
+ hooksSet.delete(hook);
32
+ };
33
+ };
34
+
35
+ export { isFilePath, isSameHost, makeNavigateOptions, normalizeManySlashes, normalizeTrailingSlash, registerHook };
@@ -0,0 +1,35 @@
1
+ import T from '@tinkoff/utils/function/T';
2
+
3
+ const isFilePath = (pathname) => {
4
+ return /\/.+\.[^/]+$/.test(pathname);
5
+ };
6
+ const normalizeTrailingSlash = (pathname, trailingSlash = false) => {
7
+ const hasTrailingSlash = pathname.endsWith('/');
8
+ if (trailingSlash) {
9
+ return hasTrailingSlash || isFilePath(pathname) ? pathname : `${pathname}/`;
10
+ }
11
+ return pathname.length > 1 && hasTrailingSlash ? pathname.slice(0, -1) : pathname;
12
+ };
13
+ const normalizeManySlashes = (hrefOrPath) => {
14
+ const [href, ...search] = hrefOrPath.split('?');
15
+ return [href.replace(/\/+/g, '/').replace(/^(\w+):\//, '$1://'), ...search].join('?');
16
+ };
17
+ const isSameHost = typeof window === 'undefined'
18
+ ? T
19
+ : (url) => {
20
+ return !url.host || url.host === window.location.host;
21
+ };
22
+ const makeNavigateOptions = (options) => {
23
+ if (typeof options === 'string') {
24
+ return { url: options };
25
+ }
26
+ return options;
27
+ };
28
+ const registerHook = (hooksSet, hook) => {
29
+ hooksSet.add(hook);
30
+ return () => {
31
+ hooksSet.delete(hook);
32
+ };
33
+ };
34
+
35
+ export { isFilePath, isSameHost, makeNavigateOptions, normalizeManySlashes, normalizeTrailingSlash, registerHook };
package/lib/utils.js ADDED
@@ -0,0 +1,48 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var T = require('@tinkoff/utils/function/T');
6
+
7
+ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
8
+
9
+ var T__default = /*#__PURE__*/_interopDefaultLegacy(T);
10
+
11
+ const isFilePath = (pathname) => {
12
+ return /\/.+\.[^/]+$/.test(pathname);
13
+ };
14
+ const normalizeTrailingSlash = (pathname, trailingSlash = false) => {
15
+ const hasTrailingSlash = pathname.endsWith('/');
16
+ if (trailingSlash) {
17
+ return hasTrailingSlash || isFilePath(pathname) ? pathname : `${pathname}/`;
18
+ }
19
+ return pathname.length > 1 && hasTrailingSlash ? pathname.slice(0, -1) : pathname;
20
+ };
21
+ const normalizeManySlashes = (hrefOrPath) => {
22
+ const [href, ...search] = hrefOrPath.split('?');
23
+ return [href.replace(/\/+/g, '/').replace(/^(\w+):\//, '$1://'), ...search].join('?');
24
+ };
25
+ const isSameHost = typeof window === 'undefined'
26
+ ? T__default["default"]
27
+ : (url) => {
28
+ return !url.host || url.host === window.location.host;
29
+ };
30
+ const makeNavigateOptions = (options) => {
31
+ if (typeof options === 'string') {
32
+ return { url: options };
33
+ }
34
+ return options;
35
+ };
36
+ const registerHook = (hooksSet, hook) => {
37
+ hooksSet.add(hook);
38
+ return () => {
39
+ hooksSet.delete(hook);
40
+ };
41
+ };
42
+
43
+ exports.isFilePath = isFilePath;
44
+ exports.isSameHost = isSameHost;
45
+ exports.makeNavigateOptions = makeNavigateOptions;
46
+ exports.normalizeManySlashes = normalizeManySlashes;
47
+ exports.normalizeTrailingSlash = normalizeTrailingSlash;
48
+ exports.registerHook = registerHook;