@eggjs/router 2.0.1 → 3.0.1

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.
@@ -0,0 +1,230 @@
1
+ import { debuglog } from 'node:util';
2
+ import pathToRegExp from 'path-to-regexp';
3
+ import URI from 'urijs';
4
+ import { decodeURIComponent as safeDecodeURIComponent } from 'utility';
5
+ import { isGeneratorFunction } from 'is-type-of';
6
+ const debug = debuglog('egg-router:layer');
7
+ export class Layer {
8
+ opts;
9
+ name;
10
+ methods = [];
11
+ stack;
12
+ path;
13
+ regexp;
14
+ paramNames = [];
15
+ /**
16
+ * Initialize a new routing Layer with given `method`, `path`, and `middleware`.
17
+ *
18
+ * @param {String|RegExp} path Path string or regular expression.
19
+ * @param {Array} methods Array of HTTP verbs.
20
+ * @param {Array|Function} middlewares Layer callback/middleware or series of.
21
+ * @param {Object=} opts optional params
22
+ * @param {String=} opts.name route name
23
+ * @param {String=} opts.sensitive case sensitive (default: false)
24
+ * @param {String=} opts.strict require the trailing slash (default: false)
25
+ * @private
26
+ */
27
+ constructor(path, methods, middlewares, opts) {
28
+ if (typeof opts === 'string') {
29
+ // new Layer(path, methods, middlewares, name);
30
+ opts = { name: opts };
31
+ }
32
+ this.opts = opts ?? {};
33
+ this.opts.prefix = this.opts.prefix ?? '';
34
+ this.name = this.opts.name;
35
+ this.stack = Array.isArray(middlewares) ? middlewares : [middlewares];
36
+ for (const method of methods) {
37
+ const l = this.methods.push(method.toUpperCase());
38
+ if (this.methods[l - 1] === 'GET') {
39
+ this.methods.unshift('HEAD');
40
+ }
41
+ }
42
+ // ensure middleware is a function
43
+ this.stack.forEach(fn => {
44
+ const type = typeof fn;
45
+ if (type !== 'function') {
46
+ throw new TypeError(methods.toString() + ' `' + (this.opts.name || path) + '`: `middleware` '
47
+ + 'must be a function, not `' + type + '`');
48
+ }
49
+ if (isGeneratorFunction(fn)) {
50
+ throw new TypeError(methods.toString() + ' `' + (this.opts.name || path) + '`: Please use async function instead of generator function');
51
+ }
52
+ });
53
+ this.path = path;
54
+ this.regexp = pathToRegExp(path, this.paramNames, this.opts);
55
+ debug('defined route %s %s', this.methods, this.opts.prefix + this.path);
56
+ }
57
+ /**
58
+ * Returns whether request `path` matches route.
59
+ *
60
+ * @param {String} path path string
61
+ * @return {Boolean} matched or not
62
+ * @private
63
+ */
64
+ match(path) {
65
+ return this.regexp.test(path);
66
+ }
67
+ /**
68
+ * Returns map of URL parameters for given `path` and `paramNames`.
69
+ *
70
+ * @param {String} _path path string
71
+ * @param {Array.<String>} captures captures strings
72
+ * @param {Object=} [existingParams] existing params
73
+ * @return {Object} params object
74
+ * @private
75
+ */
76
+ params(_path, captures, existingParams) {
77
+ const params = existingParams ?? {};
78
+ for (let len = captures.length, i = 0; i < len; i++) {
79
+ const paramName = this.paramNames[i];
80
+ if (paramName) {
81
+ const c = captures[i];
82
+ params[paramName.name] = c ? safeDecodeURIComponent(c) : c;
83
+ }
84
+ }
85
+ return params;
86
+ }
87
+ /**
88
+ * Returns array of regexp url path captures.
89
+ *
90
+ * @param {String} path path string
91
+ * @return {Array.<String>} captures strings
92
+ * @private
93
+ */
94
+ captures(path) {
95
+ if (this.opts.ignoreCaptures)
96
+ return [];
97
+ const m = path.match(this.regexp);
98
+ return m ? m.slice(1) : [];
99
+ }
100
+ /**
101
+ * Generate URL for route using given `params`.
102
+ *
103
+ * @example
104
+ *
105
+ * ```javascript
106
+ * var route = new Layer(['GET'], '/users/:id', fn);
107
+ *
108
+ * route.url(123); // => "/users/123"
109
+ * route.url('123'); // => "/users/123"
110
+ * route.url({ id: 123 }); // => "/users/123"
111
+ * ```
112
+ *
113
+ * @param {Object} params url parameters
114
+ * @param {Object} paramsOrOptions optional parameters
115
+ * @return {String} url string
116
+ * @private
117
+ */
118
+ url(params, ...paramsOrOptions) {
119
+ let args = params;
120
+ const url = this.path.replace(/\(\.\*\)/g, '');
121
+ const toPath = pathToRegExp.compile(url);
122
+ let options;
123
+ if (params !== undefined && typeof params !== 'object') {
124
+ args = [params, ...paramsOrOptions];
125
+ // route.url(stringOrNumber, params1, ..., options);
126
+ if (Array.isArray(args)) {
127
+ const lastIndex = args.length - 1;
128
+ if (typeof args[lastIndex] === 'object') {
129
+ options = args[lastIndex];
130
+ args = args.slice(0, lastIndex);
131
+ }
132
+ }
133
+ }
134
+ else if (typeof params === 'object') {
135
+ if (typeof paramsOrOptions[0] === 'object' && 'query' in paramsOrOptions[0]) {
136
+ // route.url(param, options);
137
+ options = paramsOrOptions[0];
138
+ }
139
+ }
140
+ const tokens = pathToRegExp.parse(url);
141
+ let replace = {};
142
+ if (Array.isArray(args)) {
143
+ for (let len = tokens.length, i = 0, j = 0; i < len; i++) {
144
+ const token = tokens[i];
145
+ if (typeof token === 'object' && token.name) {
146
+ replace[token.name] = args[j++];
147
+ }
148
+ }
149
+ }
150
+ else if (tokens.some(token => typeof token === 'object' && token.name)) {
151
+ // route.url(params);
152
+ replace = params;
153
+ }
154
+ else {
155
+ // route.url(options);
156
+ options = params;
157
+ }
158
+ const replaced = toPath(replace);
159
+ if (options?.query) {
160
+ const urlObject = new URI(replaced);
161
+ urlObject.search(options.query);
162
+ return urlObject.toString();
163
+ }
164
+ return replaced;
165
+ }
166
+ /**
167
+ * Run validations on route named parameters.
168
+ *
169
+ * @example
170
+ *
171
+ * ```javascript
172
+ * router
173
+ * .param('user', function (id, ctx, next) {
174
+ * ctx.user = users[id];
175
+ * if (!user) return ctx.status = 404;
176
+ * next();
177
+ * })
178
+ * .get('/users/:user', function (ctx, next) {
179
+ * ctx.body = ctx.user;
180
+ * });
181
+ * ```
182
+ *
183
+ * @param {String} param param string
184
+ * @param {Function} fn middleware function
185
+ * @return {Layer} layer instance
186
+ * @private
187
+ */
188
+ param(param, fn) {
189
+ const stack = this.stack;
190
+ const params = this.paramNames;
191
+ const middleware = function (ctx, next) {
192
+ return fn.call(this, ctx.params[param], ctx, next);
193
+ };
194
+ middleware.param = param;
195
+ const names = params.map(p => {
196
+ return p.name;
197
+ });
198
+ const x = names.indexOf(param);
199
+ if (x > -1) {
200
+ // iterate through the stack, to figure out where to place the handler fn
201
+ stack.some(function (fn, i) {
202
+ // param handlers are always first, so when we find an fn w/o a param property, stop here
203
+ // if the param handler at this part of the stack comes after the one we are adding, stop here
204
+ if (!fn.param || names.indexOf(fn.param) > x) {
205
+ // inject this param handler right before the current item
206
+ stack.splice(i, 0, middleware);
207
+ return true; // then break the loop
208
+ }
209
+ return false;
210
+ });
211
+ }
212
+ return this;
213
+ }
214
+ /**
215
+ * Prefix route path.
216
+ *
217
+ * @param {String} prefix prefix string
218
+ * @return {Layer} layer instance
219
+ * @private
220
+ */
221
+ setPrefix(prefix) {
222
+ if (this.path) {
223
+ this.path = prefix + this.path;
224
+ this.paramNames = [];
225
+ this.regexp = pathToRegExp(this.path, this.paramNames, this.opts);
226
+ }
227
+ return this;
228
+ }
229
+ }
230
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTGF5ZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvTGF5ZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLFdBQVcsQ0FBQztBQUNyQyxPQUFPLFlBQTBCLE1BQU0sZ0JBQWdCLENBQUM7QUFDeEQsT0FBTyxHQUFHLE1BQU0sT0FBTyxDQUFDO0FBQ3hCLE9BQU8sRUFBRSxrQkFBa0IsSUFBSSxzQkFBc0IsRUFBRSxNQUFNLFNBQVMsQ0FBQztBQUN2RSxPQUFPLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSxZQUFZLENBQUM7QUFPakQsTUFBTSxLQUFLLEdBQUcsUUFBUSxDQUFDLGtCQUFrQixDQUFDLENBQUM7QUFrQjNDLE1BQU0sT0FBTyxLQUFLO0lBQ1AsSUFBSSxDQUFlO0lBQ25CLElBQUksQ0FBVTtJQUNkLE9BQU8sR0FBYSxFQUFFLENBQUM7SUFDdkIsS0FBSyxDQUFvQztJQUNsRCxJQUFJLENBQWtCO0lBQ3RCLE1BQU0sQ0FBUztJQUNmLFVBQVUsR0FBVSxFQUFFLENBQUM7SUFFdkI7Ozs7Ozs7Ozs7O09BV0c7SUFDSCxZQUFZLElBQXFCLEVBQUUsT0FBaUIsRUFBRSxXQUE4QyxFQUNsRyxJQUE0QjtRQUM1QixJQUFJLE9BQU8sSUFBSSxLQUFLLFFBQVEsRUFBRSxDQUFDO1lBQzdCLCtDQUErQztZQUMvQyxJQUFJLEdBQUcsRUFBRSxJQUFJLEVBQUUsSUFBSSxFQUFFLENBQUM7UUFDeEIsQ0FBQztRQUNELElBQUksQ0FBQyxJQUFJLEdBQUcsSUFBSSxJQUFJLEVBQUUsQ0FBQztRQUN2QixJQUFJLENBQUMsSUFBSSxDQUFDLE1BQU0sR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLE1BQU0sSUFBSSxFQUFFLENBQUM7UUFDMUMsSUFBSSxDQUFDLElBQUksR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQztRQUMzQixJQUFJLENBQUMsS0FBSyxHQUFHLEtBQUssQ0FB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