@nattyjs/core 0.0.1-beta.67 → 0.0.1-beta.69

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.
package/dist/index.cjs CHANGED
@@ -92,6 +92,7 @@ const nattyContainer = new class {
92
92
  }
93
93
  createCompiledRoutes(routes) {
94
94
  const compiledRoutes = {};
95
+ let declarationOrder = 0;
95
96
  for (const method of HTTP_METHODS)
96
97
  compiledRoutes[method] = [];
97
98
  for (const [rootPath, routeConfig] of Object.entries(routes)) {
@@ -103,22 +104,66 @@ const nattyContainer = new class {
103
104
  const childPath = this.normalizeChildPath(childRoutePath);
104
105
  const configuredRoutePath = `${rootPath}${childPath}`;
105
106
  compiledRoutes[method].push({
107
+ declarationOrder: declarationOrder++,
106
108
  requestMethod: method,
107
109
  configuredRoutePath,
108
110
  matcher: pathToRegexp.match(configuredRoutePath, { decode: decodeURIComponent }),
109
111
  routeConfig,
110
- methodInfo: routeInfo
112
+ methodInfo: routeInfo,
113
+ specificity: this.getRouteSpecificity(configuredRoutePath)
111
114
  });
112
115
  }
113
116
  }
114
117
  }
115
- return compiledRoutes;
118
+ const sortedCompiledRoutes = {};
119
+ for (const method of HTTP_METHODS) {
120
+ sortedCompiledRoutes[method] = compiledRoutes[method].sort((routeA, routeB) => this.compareCompiledRoutes(routeA, routeB)).map(({ declarationOrder: declarationOrder2, specificity, ...route }) => route);
121
+ }
122
+ return sortedCompiledRoutes;
116
123
  }
117
124
  normalizeChildPath(childRoutePath) {
118
125
  if (childRoutePath.indexOf("/") === 0)
119
126
  return childRoutePath === "/" ? BLANK : childRoutePath;
120
127
  return `/${childRoutePath}`;
121
128
  }
129
+ getRouteSpecificity(routePath) {
130
+ const segments = routePath.split("/").filter(Boolean);
131
+ const segmentKinds = segments.map((segment) => this.getSegmentKind(segment));
132
+ return {
133
+ segments,
134
+ segmentKinds,
135
+ staticSegmentCount: segmentKinds.filter((kind) => kind === 2).length,
136
+ dynamicSegmentCount: segmentKinds.filter((kind) => kind === 1).length,
137
+ literalLength: segments.filter((segment) => !segment.startsWith(":")).reduce((length, segment) => length + segment.length, 0)
138
+ };
139
+ }
140
+ getSegmentKind(segment) {
141
+ if (!segment)
142
+ return 0;
143
+ if (segment.startsWith(":"))
144
+ return 1;
145
+ return 2;
146
+ }
147
+ compareCompiledRoutes(routeA, routeB) {
148
+ const bySegmentSpecificity = this.compareSegmentSpecificity(routeA.specificity, routeB.specificity);
149
+ if (bySegmentSpecificity !== 0)
150
+ return bySegmentSpecificity;
151
+ if (routeA.specificity.staticSegmentCount !== routeB.specificity.staticSegmentCount)
152
+ return routeB.specificity.staticSegmentCount - routeA.specificity.staticSegmentCount;
153
+ if (routeA.specificity.dynamicSegmentCount !== routeB.specificity.dynamicSegmentCount)
154
+ return routeA.specificity.dynamicSegmentCount - routeB.specificity.dynamicSegmentCount;
155
+ if (routeA.specificity.literalLength !== routeB.specificity.literalLength)
156
+ return routeB.specificity.literalLength - routeA.specificity.literalLength;
157
+ return routeA.declarationOrder - routeB.declarationOrder;
158
+ }
159
+ compareSegmentSpecificity(routeA, routeB) {
160
+ const maxSharedSegments = Math.min(routeA.segmentKinds.length, routeB.segmentKinds.length);
161
+ for (let index = 0; index < maxSharedSegments; index++) {
162
+ if (routeA.segmentKinds[index] !== routeB.segmentKinds[index])
163
+ return routeB.segmentKinds[index] - routeA.segmentKinds[index];
164
+ }
165
+ return 0;
166
+ }
122
167
  getCompiledRoutes(method) {
123
168
  return this.compiledRoutes[method] || [];
124
169
  }
package/dist/index.mjs CHANGED
@@ -86,6 +86,7 @@ const nattyContainer = new class {
86
86
  }
87
87
  createCompiledRoutes(routes) {
88
88
  const compiledRoutes = {};
89
+ let declarationOrder = 0;
89
90
  for (const method of HTTP_METHODS)
90
91
  compiledRoutes[method] = [];
91
92
  for (const [rootPath, routeConfig] of Object.entries(routes)) {
@@ -97,22 +98,66 @@ const nattyContainer = new class {
97
98
  const childPath = this.normalizeChildPath(childRoutePath);
98
99
  const configuredRoutePath = `${rootPath}${childPath}`;
99
100
  compiledRoutes[method].push({
101
+ declarationOrder: declarationOrder++,
100
102
  requestMethod: method,
101
103
  configuredRoutePath,
102
104
  matcher: match(configuredRoutePath, { decode: decodeURIComponent }),
103
105
  routeConfig,
104
- methodInfo: routeInfo
106
+ methodInfo: routeInfo,
107
+ specificity: this.getRouteSpecificity(configuredRoutePath)
105
108
  });
106
109
  }
107
110
  }
108
111
  }
109
- return compiledRoutes;
112
+ const sortedCompiledRoutes = {};
113
+ for (const method of HTTP_METHODS) {
114
+ sortedCompiledRoutes[method] = compiledRoutes[method].sort((routeA, routeB) => this.compareCompiledRoutes(routeA, routeB)).map(({ declarationOrder: declarationOrder2, specificity, ...route }) => route);
115
+ }
116
+ return sortedCompiledRoutes;
110
117
  }
111
118
  normalizeChildPath(childRoutePath) {
112
119
  if (childRoutePath.indexOf("/") === 0)
113
120
  return childRoutePath === "/" ? BLANK : childRoutePath;
114
121
  return `/${childRoutePath}`;
115
122
  }
123
+ getRouteSpecificity(routePath) {
124
+ const segments = routePath.split("/").filter(Boolean);
125
+ const segmentKinds = segments.map((segment) => this.getSegmentKind(segment));
126
+ return {
127
+ segments,
128
+ segmentKinds,
129
+ staticSegmentCount: segmentKinds.filter((kind) => kind === 2).length,
130
+ dynamicSegmentCount: segmentKinds.filter((kind) => kind === 1).length,
131
+ literalLength: segments.filter((segment) => !segment.startsWith(":")).reduce((length, segment) => length + segment.length, 0)
132
+ };
133
+ }
134
+ getSegmentKind(segment) {
135
+ if (!segment)
136
+ return 0;
137
+ if (segment.startsWith(":"))
138
+ return 1;
139
+ return 2;
140
+ }
141
+ compareCompiledRoutes(routeA, routeB) {
142
+ const bySegmentSpecificity = this.compareSegmentSpecificity(routeA.specificity, routeB.specificity);
143
+ if (bySegmentSpecificity !== 0)
144
+ return bySegmentSpecificity;
145
+ if (routeA.specificity.staticSegmentCount !== routeB.specificity.staticSegmentCount)
146
+ return routeB.specificity.staticSegmentCount - routeA.specificity.staticSegmentCount;
147
+ if (routeA.specificity.dynamicSegmentCount !== routeB.specificity.dynamicSegmentCount)
148
+ return routeA.specificity.dynamicSegmentCount - routeB.specificity.dynamicSegmentCount;
149
+ if (routeA.specificity.literalLength !== routeB.specificity.literalLength)
150
+ return routeB.specificity.literalLength - routeA.specificity.literalLength;
151
+ return routeA.declarationOrder - routeB.declarationOrder;
152
+ }
153
+ compareSegmentSpecificity(routeA, routeB) {
154
+ const maxSharedSegments = Math.min(routeA.segmentKinds.length, routeB.segmentKinds.length);
155
+ for (let index = 0; index < maxSharedSegments; index++) {
156
+ if (routeA.segmentKinds[index] !== routeB.segmentKinds[index])
157
+ return routeB.segmentKinds[index] - routeA.segmentKinds[index];
158
+ }
159
+ return 0;
160
+ }
116
161
  getCompiledRoutes(method) {
117
162
  return this.compiledRoutes[method] || [];
118
163
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nattyjs/core",
3
- "version": "0.0.1-beta.67",
3
+ "version": "0.0.1-beta.69",
4
4
  "description": "",
5
5
  "keywords": [],
6
6
  "author": "ajayojha",
@@ -17,7 +17,7 @@
17
17
  "dependencies": {
18
18
  "reflect-metadata": "0.2.2",
19
19
  "path-to-regexp": "6.2.1",
20
- "@nattyjs/common": "0.0.1-beta.67"
20
+ "@nattyjs/common": "0.0.1-beta.69"
21
21
  },
22
22
  "devDependencies": {
23
23
  "unbuild": "1.2.1"