@midwayjs/core 3.4.0-beta.6 → 3.4.0-beta.9
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/baseFramework.d.ts +1 -0
- package/dist/baseFramework.js +28 -13
- package/dist/common/asyncContextManager.d.ts +61 -0
- package/dist/common/asyncContextManager.js +63 -0
- package/dist/common/webGenerator.js +1 -0
- package/dist/config/config.default.d.ts +3 -0
- package/dist/config/config.default.js +3 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +3 -1
- package/dist/interface.d.ts +3 -0
- package/dist/interface.js +2 -1
- package/dist/service/middlewareService.js +4 -0
- package/dist/service/slsFunctionService.js +1 -1
- package/dist/service/webRouterService.d.ts +24 -2
- package/dist/service/webRouterService.js +21 -10
- package/dist/util/index.js +1 -1
- package/dist/util/pathToRegexp.d.ts +110 -11
- package/dist/util/pathToRegexp.js +333 -200
- package/package.json +3 -3
package/dist/baseFramework.d.ts
CHANGED
|
@@ -20,6 +20,7 @@ export declare abstract class BaseFramework<APP extends IMidwayApplication<CTX>,
|
|
|
20
20
|
protected middlewareManager: ContextMiddlewareManager<CTX, ResOrNext, Next>;
|
|
21
21
|
protected filterManager: FilterManager<CTX, ResOrNext, Next>;
|
|
22
22
|
protected composeMiddleware: any;
|
|
23
|
+
protected bootstrapOptions: IMidwayBootstrapOptions;
|
|
23
24
|
loggerService: MidwayLoggerService;
|
|
24
25
|
environmentService: MidwayEnvironmentService;
|
|
25
26
|
configService: MidwayConfigService;
|
package/dist/baseFramework.js
CHANGED
|
@@ -22,6 +22,7 @@ const middlewareService_1 = require("./service/middlewareService");
|
|
|
22
22
|
const filterManager_1 = require("./common/filterManager");
|
|
23
23
|
const mockService_1 = require("./service/mockService");
|
|
24
24
|
const util = require("util");
|
|
25
|
+
const asyncContextManager_1 = require("./common/asyncContextManager");
|
|
25
26
|
const debug = util.debuglog('midway:debug');
|
|
26
27
|
class BaseFramework {
|
|
27
28
|
constructor(applicationContext) {
|
|
@@ -45,6 +46,7 @@ class BaseFramework {
|
|
|
45
46
|
return true;
|
|
46
47
|
}
|
|
47
48
|
async initialize(options) {
|
|
49
|
+
this.bootstrapOptions = options;
|
|
48
50
|
await this.beforeContainerInitialize(options);
|
|
49
51
|
await this.containerInitialize(options);
|
|
50
52
|
await this.afterContainerInitialize(options);
|
|
@@ -231,21 +233,34 @@ class BaseFramework {
|
|
|
231
233
|
*/
|
|
232
234
|
async afterContainerReady(options) { }
|
|
233
235
|
async applyMiddleware(lastMiddleware) {
|
|
236
|
+
var _a;
|
|
237
|
+
const asyncContextManagerEnabled = this.configService.getConfiguration('asyncContextManager.enable') ||
|
|
238
|
+
false;
|
|
239
|
+
const contextManager = asyncContextManagerEnabled
|
|
240
|
+
? ((_a = this.bootstrapOptions) === null || _a === void 0 ? void 0 : _a.contextManager) || new asyncContextManager_1.NoopContextManager()
|
|
241
|
+
: new asyncContextManager_1.NoopContextManager();
|
|
242
|
+
if (asyncContextManagerEnabled) {
|
|
243
|
+
contextManager.enable();
|
|
244
|
+
}
|
|
234
245
|
if (!this.composeMiddleware) {
|
|
235
246
|
this.middlewareManager.insertFirst((async (ctx, next) => {
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
returnResult =
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
247
|
+
// warp with context manager
|
|
248
|
+
const rootContext = asyncContextManager_1.ASYNC_ROOT_CONTEXT.setValue(interface_1.ASYNC_CONTEXT_KEY, ctx);
|
|
249
|
+
return await contextManager.with(rootContext, async () => {
|
|
250
|
+
this.mockService.applyContextMocks(this.app, ctx);
|
|
251
|
+
let returnResult = undefined;
|
|
252
|
+
try {
|
|
253
|
+
const result = await next();
|
|
254
|
+
returnResult = await this.filterManager.runResultFilter(result, ctx);
|
|
255
|
+
}
|
|
256
|
+
catch (err) {
|
|
257
|
+
returnResult = await this.filterManager.runErrorFilter(err, ctx);
|
|
258
|
+
}
|
|
259
|
+
if (returnResult.error) {
|
|
260
|
+
throw returnResult.error;
|
|
261
|
+
}
|
|
262
|
+
return returnResult.result;
|
|
263
|
+
});
|
|
249
264
|
}));
|
|
250
265
|
debug(`[core]: Compose middleware = [${this.middlewareManager.getNames()}]`);
|
|
251
266
|
this.composeMiddleware = await this.middlewareService.compose(this.middlewareManager, this.app);
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
export interface AsyncContext {
|
|
2
|
+
/**
|
|
3
|
+
* Get a value from the context.
|
|
4
|
+
*
|
|
5
|
+
* @param key key which identifies a context value
|
|
6
|
+
*/
|
|
7
|
+
getValue(key: symbol): unknown;
|
|
8
|
+
/**
|
|
9
|
+
* Create a new context which inherits from this context and has
|
|
10
|
+
* the given key set to the given value.
|
|
11
|
+
*
|
|
12
|
+
* @param key context key for which to set the value
|
|
13
|
+
* @param value value to set for the given key
|
|
14
|
+
*/
|
|
15
|
+
setValue(key: symbol, value: unknown): AsyncContext;
|
|
16
|
+
/**
|
|
17
|
+
* Return a new context which inherits from this context but does
|
|
18
|
+
* not contain a value for the given key.
|
|
19
|
+
*
|
|
20
|
+
* @param key context key for which to clear a value
|
|
21
|
+
*/
|
|
22
|
+
deleteValue(key: symbol): AsyncContext;
|
|
23
|
+
}
|
|
24
|
+
export interface AsyncContextManager {
|
|
25
|
+
/**
|
|
26
|
+
* Get the current active context
|
|
27
|
+
*/
|
|
28
|
+
active(): AsyncContext;
|
|
29
|
+
/**
|
|
30
|
+
* Run the fn callback with object set as the current active context
|
|
31
|
+
* @param context Any object to set as the current active context
|
|
32
|
+
* @param fn A callback to be immediately run within a specific context
|
|
33
|
+
* @param thisArg optional receiver to be used for calling fn
|
|
34
|
+
* @param args optional arguments forwarded to fn
|
|
35
|
+
*/
|
|
36
|
+
with<A extends unknown[], F extends (...args: A) => ReturnType<F>>(context: AsyncContext, fn: F, thisArg?: ThisParameterType<F>, ...args: A): ReturnType<F>;
|
|
37
|
+
/**
|
|
38
|
+
* Bind an object as the current context (or a specific one)
|
|
39
|
+
* @param [context] Optionally specify the context which you want to assign
|
|
40
|
+
* @param target Any object to which a context need to be set
|
|
41
|
+
*/
|
|
42
|
+
bind<T>(context: AsyncContext, target: T): T;
|
|
43
|
+
/**
|
|
44
|
+
* Enable context management
|
|
45
|
+
*/
|
|
46
|
+
enable(): this;
|
|
47
|
+
/**
|
|
48
|
+
* Disable context management
|
|
49
|
+
*/
|
|
50
|
+
disable(): this;
|
|
51
|
+
}
|
|
52
|
+
/** The root context is used as the default parent context when there is no active context */
|
|
53
|
+
export declare const ASYNC_ROOT_CONTEXT: AsyncContext;
|
|
54
|
+
export declare class NoopContextManager implements AsyncContextManager {
|
|
55
|
+
active(): AsyncContext;
|
|
56
|
+
with<A extends unknown[], F extends (...args: A) => ReturnType<F>>(_context: AsyncContext, fn: F, thisArg?: ThisParameterType<F>, ...args: A): ReturnType<F>;
|
|
57
|
+
bind<T>(_context: AsyncContext, target: T): T;
|
|
58
|
+
enable(): this;
|
|
59
|
+
disable(): this;
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=asyncContextManager.d.ts.map
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* Copyright The OpenTelemetry Authors
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* https://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
+
exports.NoopContextManager = exports.ASYNC_ROOT_CONTEXT = void 0;
|
|
19
|
+
class AsyncBaseContext {
|
|
20
|
+
/**
|
|
21
|
+
* Construct a new context which inherits values from an optional parent context.
|
|
22
|
+
*
|
|
23
|
+
* @param parentContext a context from which to inherit values
|
|
24
|
+
*/
|
|
25
|
+
constructor(parentContext) {
|
|
26
|
+
// for minification
|
|
27
|
+
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
28
|
+
const self = this;
|
|
29
|
+
self._currentContext = parentContext ? new Map(parentContext) : new Map();
|
|
30
|
+
self.getValue = (key) => self._currentContext.get(key);
|
|
31
|
+
self.setValue = (key, value) => {
|
|
32
|
+
const context = new AsyncBaseContext(self._currentContext);
|
|
33
|
+
context._currentContext.set(key, value);
|
|
34
|
+
return context;
|
|
35
|
+
};
|
|
36
|
+
self.deleteValue = (key) => {
|
|
37
|
+
const context = new AsyncBaseContext(self._currentContext);
|
|
38
|
+
context._currentContext.delete(key);
|
|
39
|
+
return context;
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/** The root context is used as the default parent context when there is no active context */
|
|
44
|
+
exports.ASYNC_ROOT_CONTEXT = new AsyncBaseContext();
|
|
45
|
+
class NoopContextManager {
|
|
46
|
+
active() {
|
|
47
|
+
return exports.ASYNC_ROOT_CONTEXT;
|
|
48
|
+
}
|
|
49
|
+
with(_context, fn, thisArg, ...args) {
|
|
50
|
+
return fn.call(thisArg, ...args);
|
|
51
|
+
}
|
|
52
|
+
bind(_context, target) {
|
|
53
|
+
return target;
|
|
54
|
+
}
|
|
55
|
+
enable() {
|
|
56
|
+
return this;
|
|
57
|
+
}
|
|
58
|
+
disable() {
|
|
59
|
+
return this;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
exports.NoopContextManager = NoopContextManager;
|
|
63
|
+
//# sourceMappingURL=asyncContextManager.js.map
|
|
@@ -101,6 +101,7 @@ class WebControllerGenerator {
|
|
|
101
101
|
methodMiddlewares.push(routeMiddlewareFn);
|
|
102
102
|
}
|
|
103
103
|
if (this.app.getFrameworkType() === decorator_1.MidwayFrameworkType.WEB_KOA) {
|
|
104
|
+
// egg use path-to-regexp v1 but koa use v6
|
|
104
105
|
if (typeof routeInfo.url === 'string' && /\*$/.test(routeInfo.url)) {
|
|
105
106
|
routeInfo.url = routeInfo.url.replace('*', '(.*)');
|
|
106
107
|
}
|
|
@@ -8,6 +8,9 @@ exports.default = (appInfo) => {
|
|
|
8
8
|
const isDevelopment = (0, util_1.isDevelopmentEnvironment)((0, util_1.getCurrentEnvironment)());
|
|
9
9
|
const logRoot = (_a = process.env[interface_1.MIDWAY_LOGGER_WRITEABLE_DIR]) !== null && _a !== void 0 ? _a : appInfo.root;
|
|
10
10
|
return {
|
|
11
|
+
asyncContextManager: {
|
|
12
|
+
enable: false,
|
|
13
|
+
},
|
|
11
14
|
midwayLogger: {
|
|
12
15
|
default: {
|
|
13
16
|
dir: (0, path_1.join)(logRoot, 'logs', appInfo.name),
|
package/dist/index.d.ts
CHANGED
|
@@ -35,6 +35,7 @@ export * from './common/filterManager';
|
|
|
35
35
|
export * from './common/applicationManager';
|
|
36
36
|
export * from './setup';
|
|
37
37
|
export * from './error';
|
|
38
|
+
export { AsyncContextManager, ASYNC_ROOT_CONTEXT, AsyncContext, } from './common/asyncContextManager';
|
|
38
39
|
/**
|
|
39
40
|
* proxy
|
|
40
41
|
*/
|
package/dist/index.js
CHANGED
|
@@ -14,7 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
exports.MidwayFrameworkType = exports.DataSourceManager = exports.WebRouterCollector = exports.MidwayServerlessFunctionService = exports.MidwayWebRouterService = exports.MidwayMockService = exports.MidwayDecoratorService = exports.MidwayMiddlewareService = exports.MidwayLifeCycleService = exports.MidwayAspectService = exports.MidwayFrameworkService = exports.MidwayLoggerService = exports.MidwayInformationService = exports.MidwayEnvironmentService = exports.MidwayConfigService = exports.createConfiguration = exports.extend = exports.wrapAsync = exports.wrapMiddleware = exports.pathMatching = exports.transformRequestObjectByType = exports.deprecatedOutput = exports.delegateTargetAllPrototypeMethod = exports.delegateTargetProperties = exports.delegateTargetMethod = exports.delegateTargetPrototypeMethod = exports.safeRequire = exports.safelyGet = exports.BaseFramework = exports.MidwayRequestContainer = void 0;
|
|
17
|
+
exports.MidwayFrameworkType = exports.ASYNC_ROOT_CONTEXT = exports.DataSourceManager = exports.WebRouterCollector = exports.MidwayServerlessFunctionService = exports.MidwayWebRouterService = exports.MidwayMockService = exports.MidwayDecoratorService = exports.MidwayMiddlewareService = exports.MidwayLifeCycleService = exports.MidwayAspectService = exports.MidwayFrameworkService = exports.MidwayLoggerService = exports.MidwayInformationService = exports.MidwayEnvironmentService = exports.MidwayConfigService = exports.createConfiguration = exports.extend = exports.wrapAsync = exports.wrapMiddleware = exports.pathMatching = exports.transformRequestObjectByType = exports.deprecatedOutput = exports.delegateTargetAllPrototypeMethod = exports.delegateTargetProperties = exports.delegateTargetMethod = exports.delegateTargetPrototypeMethod = exports.safeRequire = exports.safelyGet = exports.BaseFramework = exports.MidwayRequestContainer = void 0;
|
|
18
18
|
__exportStar(require("./interface"), exports);
|
|
19
19
|
__exportStar(require("./context/container"), exports);
|
|
20
20
|
var requestContainer_1 = require("./context/requestContainer");
|
|
@@ -81,6 +81,8 @@ __exportStar(require("./common/filterManager"), exports);
|
|
|
81
81
|
__exportStar(require("./common/applicationManager"), exports);
|
|
82
82
|
__exportStar(require("./setup"), exports);
|
|
83
83
|
__exportStar(require("./error"), exports);
|
|
84
|
+
var asyncContextManager_1 = require("./common/asyncContextManager");
|
|
85
|
+
Object.defineProperty(exports, "ASYNC_ROOT_CONTEXT", { enumerable: true, get: function () { return asyncContextManager_1.ASYNC_ROOT_CONTEXT; } });
|
|
84
86
|
/**
|
|
85
87
|
* proxy
|
|
86
88
|
*/
|
package/dist/interface.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { ILogger, LoggerOptions, LoggerContextFormat } from '@midwayjs/logger';
|
|
|
4
4
|
import * as EventEmitter from 'events';
|
|
5
5
|
import { ContextMiddlewareManager } from './common/middlewareManager';
|
|
6
6
|
import _default from './config/config.default';
|
|
7
|
+
import { AsyncContextManager } from './common/asyncContextManager';
|
|
7
8
|
export declare type PowerPartial<T> = {
|
|
8
9
|
[U in keyof T]?: T[U] extends {} ? PowerPartial<T[U]> : T[U];
|
|
9
10
|
};
|
|
@@ -432,6 +433,7 @@ export interface IMidwayBootstrapOptions {
|
|
|
432
433
|
globalConfig?: Array<{
|
|
433
434
|
[environmentName: string]: Record<string, any>;
|
|
434
435
|
}> | Record<string, any>;
|
|
436
|
+
asyncContextManager?: AsyncContextManager;
|
|
435
437
|
}
|
|
436
438
|
export interface IConfigurationOptions {
|
|
437
439
|
logger?: ILogger;
|
|
@@ -479,5 +481,6 @@ export interface MidwayAppInfo {
|
|
|
479
481
|
export interface MidwayConfig extends FileConfigOption<typeof _default> {
|
|
480
482
|
[customConfigKey: string]: unknown;
|
|
481
483
|
}
|
|
484
|
+
export declare const ASYNC_CONTEXT_KEY: unique symbol;
|
|
482
485
|
export {};
|
|
483
486
|
//# sourceMappingURL=interface.d.ts.map
|
package/dist/interface.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.MIDWAY_LOGGER_WRITEABLE_DIR = exports.MidwayProcessTypeEnum = exports.REQUEST_CTX_LOGGER_CACHE_KEY = exports.HTTP_SERVER_KEY = exports.REQUEST_OBJ_CTX_KEY = exports.REQUEST_CTX_KEY = exports.ObjectLifeCycleEvent = void 0;
|
|
3
|
+
exports.ASYNC_CONTEXT_KEY = exports.MIDWAY_LOGGER_WRITEABLE_DIR = exports.MidwayProcessTypeEnum = exports.REQUEST_CTX_LOGGER_CACHE_KEY = exports.HTTP_SERVER_KEY = exports.REQUEST_OBJ_CTX_KEY = exports.REQUEST_CTX_KEY = exports.ObjectLifeCycleEvent = void 0;
|
|
4
4
|
var ObjectLifeCycleEvent;
|
|
5
5
|
(function (ObjectLifeCycleEvent) {
|
|
6
6
|
ObjectLifeCycleEvent["BEFORE_BIND"] = "beforeBind";
|
|
@@ -19,4 +19,5 @@ var MidwayProcessTypeEnum;
|
|
|
19
19
|
MidwayProcessTypeEnum["AGENT"] = "AGENT";
|
|
20
20
|
})(MidwayProcessTypeEnum = exports.MidwayProcessTypeEnum || (exports.MidwayProcessTypeEnum = {}));
|
|
21
21
|
exports.MIDWAY_LOGGER_WRITEABLE_DIR = 'MIDWAY_LOGGER_WRITEABLE_DIR';
|
|
22
|
+
exports.ASYNC_CONTEXT_KEY = Symbol('ASYNC_CONTEXT_KEY');
|
|
22
23
|
//# sourceMappingURL=interface.js.map
|
|
@@ -32,6 +32,10 @@ let MidwayMiddlewareService = class MidwayMiddlewareService {
|
|
|
32
32
|
const classMiddleware = await this.applicationContext.getAsync(fn);
|
|
33
33
|
if (classMiddleware) {
|
|
34
34
|
fn = await classMiddleware.resolve(app);
|
|
35
|
+
if (!fn) {
|
|
36
|
+
// for middleware enabled
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
35
39
|
if (!classMiddleware.match && !classMiddleware.ignore) {
|
|
36
40
|
if (!fn.name) {
|
|
37
41
|
fn._name = classMiddleware.constructor.name;
|
|
@@ -144,7 +144,7 @@ let MidwayServerlessFunctionService = class MidwayServerlessFunctionService exte
|
|
|
144
144
|
this.routes.set(prefix, []);
|
|
145
145
|
this.routesPriority.push({
|
|
146
146
|
prefix,
|
|
147
|
-
priority:
|
|
147
|
+
priority: 0,
|
|
148
148
|
middleware: [],
|
|
149
149
|
routerOptions: {},
|
|
150
150
|
controllerId: undefined,
|
|
@@ -28,6 +28,9 @@ export interface RouterInfo {
|
|
|
28
28
|
* router description
|
|
29
29
|
*/
|
|
30
30
|
description?: string;
|
|
31
|
+
/**
|
|
32
|
+
* @deprecated
|
|
33
|
+
*/
|
|
31
34
|
summary?: string;
|
|
32
35
|
/**
|
|
33
36
|
* router handler function key,for IoC container load
|
|
@@ -73,10 +76,18 @@ export interface RouterInfo {
|
|
|
73
76
|
* serverless function metadata
|
|
74
77
|
*/
|
|
75
78
|
functionMetadata?: any;
|
|
79
|
+
/**
|
|
80
|
+
* url with prefix
|
|
81
|
+
*/
|
|
82
|
+
fullUrl?: string;
|
|
76
83
|
/**
|
|
77
84
|
* pattern after path-regexp compile
|
|
78
85
|
*/
|
|
79
|
-
|
|
86
|
+
fullUrlCompiledRegexp?: RegExp;
|
|
87
|
+
/**
|
|
88
|
+
* url after wildcard and can be path-to-regexp by path-to-regexp v6
|
|
89
|
+
*/
|
|
90
|
+
fullUrlFlattenString?: string;
|
|
80
91
|
}
|
|
81
92
|
export declare type DynamicRouterInfo = Omit<RouterInfo, 'id' | 'method' | 'controllerId' | 'controllerMiddleware' | 'responseMetadata'>;
|
|
82
93
|
export interface RouterPriority {
|
|
@@ -153,6 +164,9 @@ export declare class MidwayWebRouterService {
|
|
|
153
164
|
* router description
|
|
154
165
|
*/
|
|
155
166
|
description?: string;
|
|
167
|
+
/**
|
|
168
|
+
* @deprecated
|
|
169
|
+
*/
|
|
156
170
|
summary?: string;
|
|
157
171
|
/**
|
|
158
172
|
* router handler function key,for IoC container load
|
|
@@ -198,10 +212,18 @@ export declare class MidwayWebRouterService {
|
|
|
198
212
|
* serverless function metadata
|
|
199
213
|
*/
|
|
200
214
|
functionMetadata?: any;
|
|
215
|
+
/**
|
|
216
|
+
* url with prefix
|
|
217
|
+
*/
|
|
218
|
+
fullUrl?: string;
|
|
201
219
|
/**
|
|
202
220
|
* pattern after path-regexp compile
|
|
203
221
|
*/
|
|
204
|
-
|
|
222
|
+
fullUrlCompiledRegexp?: RegExp;
|
|
223
|
+
/**
|
|
224
|
+
* url after wildcard and can be path-to-regexp by path-to-regexp v6
|
|
225
|
+
*/
|
|
226
|
+
fullUrlFlattenString?: string;
|
|
205
227
|
}[];
|
|
206
228
|
getRoutePriorityList(): Promise<RouterPriority[]>;
|
|
207
229
|
getRouterTable(): Promise<Map<string, RouterInfo[]>>;
|
|
@@ -160,11 +160,12 @@ let MidwayWebRouterService = class MidwayWebRouterService {
|
|
|
160
160
|
*/
|
|
161
161
|
addRouter(routerFunction, routerInfoOption) {
|
|
162
162
|
const prefix = routerInfoOption.prefix || '';
|
|
163
|
+
routerInfoOption.requestMethod = (routerInfoOption.requestMethod || 'GET').toUpperCase();
|
|
163
164
|
if (!this.routes.has(prefix)) {
|
|
164
165
|
this.routes.set(prefix, []);
|
|
165
166
|
this.routesPriority.push({
|
|
166
167
|
prefix,
|
|
167
|
-
priority:
|
|
168
|
+
priority: 0,
|
|
168
169
|
middleware: [],
|
|
169
170
|
routerOptions: {},
|
|
170
171
|
controllerId: undefined,
|
|
@@ -257,10 +258,8 @@ let MidwayWebRouterService = class MidwayWebRouterService {
|
|
|
257
258
|
this.includeCompileUrlPattern = true;
|
|
258
259
|
// attach match pattern function
|
|
259
260
|
for (const item of this.cachedFlattenRouteList) {
|
|
260
|
-
if (item.
|
|
261
|
-
item.
|
|
262
|
-
end: false,
|
|
263
|
-
});
|
|
261
|
+
if (item.fullUrlFlattenString) {
|
|
262
|
+
item.fullUrlCompiledRegexp = pathToRegexp_1.PathToRegexpUtil.toRegexp(item.fullUrlFlattenString);
|
|
264
263
|
}
|
|
265
264
|
}
|
|
266
265
|
}
|
|
@@ -278,9 +277,9 @@ let MidwayWebRouterService = class MidwayWebRouterService {
|
|
|
278
277
|
this.includeCompileUrlPattern = true;
|
|
279
278
|
// attach match pattern function
|
|
280
279
|
for (const item of routeArr) {
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
}
|
|
280
|
+
if (item.fullUrlFlattenString) {
|
|
281
|
+
item.fullUrlCompiledRegexp = pathToRegexp_1.PathToRegexpUtil.toRegexp(item.fullUrlFlattenString);
|
|
282
|
+
}
|
|
284
283
|
}
|
|
285
284
|
}
|
|
286
285
|
this.cachedFlattenRouteList = routeArr;
|
|
@@ -292,9 +291,9 @@ let MidwayWebRouterService = class MidwayWebRouterService {
|
|
|
292
291
|
});
|
|
293
292
|
let matchedRouterInfo;
|
|
294
293
|
for (const item of routes) {
|
|
295
|
-
if (item.
|
|
294
|
+
if (item.fullUrlCompiledRegexp) {
|
|
296
295
|
if (method.toUpperCase() === item['requestMethod'].toUpperCase() &&
|
|
297
|
-
item.
|
|
296
|
+
item.fullUrlCompiledRegexp.test(routerUrl)) {
|
|
298
297
|
matchedRouterInfo = item;
|
|
299
298
|
break;
|
|
300
299
|
}
|
|
@@ -313,6 +312,18 @@ let MidwayWebRouterService = class MidwayWebRouterService {
|
|
|
313
312
|
if (matched && matched.length) {
|
|
314
313
|
throw new error_1.MidwayDuplicateRouteError(`${routerInfo.requestMethod} ${routerInfo.url}`, `${matched[0].handlerName}`, `${routerInfo.handlerName}`);
|
|
315
314
|
}
|
|
315
|
+
// format url
|
|
316
|
+
if (!routerInfo.fullUrlFlattenString &&
|
|
317
|
+
routerInfo.url &&
|
|
318
|
+
typeof routerInfo.url === 'string') {
|
|
319
|
+
routerInfo.fullUrl = (0, util_1.joinURLPath)(prefix, routerInfo.url);
|
|
320
|
+
if (/\*$/.test(routerInfo.fullUrl)) {
|
|
321
|
+
routerInfo.fullUrlFlattenString = routerInfo.fullUrl.replace('*', '(.*)');
|
|
322
|
+
}
|
|
323
|
+
else {
|
|
324
|
+
routerInfo.fullUrlFlattenString = routerInfo.fullUrl;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
316
327
|
prefixList.push(routerInfo);
|
|
317
328
|
}
|
|
318
329
|
};
|
package/dist/util/index.js
CHANGED
|
@@ -238,7 +238,7 @@ function toPathMatch(pattern) {
|
|
|
238
238
|
return ctx => pattern;
|
|
239
239
|
}
|
|
240
240
|
if (typeof pattern === 'string') {
|
|
241
|
-
const reg =
|
|
241
|
+
const reg = pathToRegexp_1.PathToRegexpUtil.toRegexp(pattern.replace('*', '(.*)'));
|
|
242
242
|
if (reg.global)
|
|
243
243
|
reg.lastIndex = 0;
|
|
244
244
|
return ctx => reg.test(ctx.path);
|
|
@@ -1,24 +1,123 @@
|
|
|
1
|
+
interface ParseOptions {
|
|
2
|
+
/**
|
|
3
|
+
* Set the default delimiter for repeat parameters. (default: `'/'`)
|
|
4
|
+
*/
|
|
5
|
+
delimiter?: string;
|
|
6
|
+
/**
|
|
7
|
+
* List of characters to automatically consider prefixes when parsing.
|
|
8
|
+
*/
|
|
9
|
+
prefixes?: string;
|
|
10
|
+
}
|
|
1
11
|
/**
|
|
2
|
-
*
|
|
12
|
+
* Parse a string for the raw tokens.
|
|
3
13
|
*/
|
|
4
|
-
|
|
5
|
-
|
|
14
|
+
declare function parse(str: string, options?: ParseOptions): Token[];
|
|
15
|
+
interface TokensToFunctionOptions {
|
|
16
|
+
/**
|
|
17
|
+
* When `true` the regexp will be case sensitive. (default: `false`)
|
|
18
|
+
*/
|
|
19
|
+
sensitive?: boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Function for encoding input strings for output.
|
|
22
|
+
*/
|
|
23
|
+
encode?: (value: string, token: Key) => string;
|
|
24
|
+
/**
|
|
25
|
+
* When `false` the function can produce an invalid (unmatched) path. (default: `true`)
|
|
26
|
+
*/
|
|
27
|
+
validate?: boolean;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Compile a string to a template function for the path.
|
|
31
|
+
*/
|
|
32
|
+
declare function compile<P extends object = object>(str: string, options?: ParseOptions & TokensToFunctionOptions): PathFunction<P>;
|
|
33
|
+
declare type PathFunction<P extends object = object> = (data?: P) => string;
|
|
34
|
+
interface RegexpToFunctionOptions {
|
|
35
|
+
/**
|
|
36
|
+
* Function for decoding strings for params.
|
|
37
|
+
*/
|
|
38
|
+
decode?: (value: string, token: Key) => string;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* A match result contains data about the path match.
|
|
42
|
+
*/
|
|
43
|
+
interface MatchResult<P extends object = object> {
|
|
44
|
+
path: string;
|
|
45
|
+
index: number;
|
|
46
|
+
params: P;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* A match is either `false` (no match) or a match result.
|
|
50
|
+
*/
|
|
51
|
+
declare type Match<P extends object = object> = false | MatchResult<P>;
|
|
52
|
+
/**
|
|
53
|
+
* The match function takes a string and returns whether it matched the path.
|
|
54
|
+
*/
|
|
55
|
+
declare type MatchFunction<P extends object = object> = (path: string) => Match<P>;
|
|
56
|
+
/**
|
|
57
|
+
* Create path match function from `path-to-regexp` spec.
|
|
58
|
+
*/
|
|
59
|
+
declare function match<P extends object = object>(str: Path, options?: ParseOptions & TokensToRegexpOptions & RegexpToFunctionOptions): MatchFunction<P>;
|
|
60
|
+
/**
|
|
61
|
+
* Metadata about a key.
|
|
62
|
+
*/
|
|
63
|
+
interface Key {
|
|
64
|
+
name: string | number;
|
|
65
|
+
prefix: string;
|
|
66
|
+
suffix: string;
|
|
67
|
+
pattern: string;
|
|
68
|
+
modifier: string;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* A token is a string (nothing special) or key metadata (capture group).
|
|
72
|
+
*/
|
|
73
|
+
declare type Token = string | Key;
|
|
74
|
+
interface TokensToRegexpOptions {
|
|
75
|
+
/**
|
|
76
|
+
* When `true` the regexp will be case sensitive. (default: `false`)
|
|
77
|
+
*/
|
|
78
|
+
sensitive?: boolean;
|
|
79
|
+
/**
|
|
80
|
+
* When `true` the regexp won't allow an optional trailing delimiter to match. (default: `false`)
|
|
81
|
+
*/
|
|
6
82
|
strict?: boolean;
|
|
83
|
+
/**
|
|
84
|
+
* When `true` the regexp will match to the end of the string. (default: `true`)
|
|
85
|
+
*/
|
|
86
|
+
end?: boolean;
|
|
87
|
+
/**
|
|
88
|
+
* When `true` the regexp will match from the beginning of the string. (default: `true`)
|
|
89
|
+
*/
|
|
90
|
+
start?: boolean;
|
|
91
|
+
/**
|
|
92
|
+
* Sets the final character for non-ending optimistic matches. (default: `/`)
|
|
93
|
+
*/
|
|
7
94
|
delimiter?: string;
|
|
8
|
-
|
|
95
|
+
/**
|
|
96
|
+
* List of characters that can also be "end" characters.
|
|
97
|
+
*/
|
|
98
|
+
endsWith?: string;
|
|
99
|
+
/**
|
|
100
|
+
* Encode path tokens for use in the `RegExp`.
|
|
101
|
+
*/
|
|
102
|
+
encode?: (value: string) => string;
|
|
9
103
|
}
|
|
104
|
+
/**
|
|
105
|
+
* Supported `path-to-regexp` input types.
|
|
106
|
+
*/
|
|
107
|
+
declare type Path = string | RegExp | Array<string | RegExp>;
|
|
10
108
|
/**
|
|
11
109
|
* Normalize the given path string, returning a regular expression.
|
|
12
110
|
*
|
|
13
111
|
* An empty array can be passed in for the keys, which will hold the
|
|
14
112
|
* placeholder key descriptions. For example, using `/user/:id`, `keys` will
|
|
15
113
|
* contain `[{ name: 'id', delimiter: '/', optional: false, repeat: false }]`.
|
|
16
|
-
*
|
|
17
|
-
* @param {(string|RegExp|Array)} path
|
|
18
|
-
* @param {(Array|Object)=} keys
|
|
19
|
-
* @param {Object=} options
|
|
20
|
-
* @return {!RegExp}
|
|
21
114
|
*/
|
|
22
|
-
|
|
23
|
-
export declare
|
|
115
|
+
declare function toRegexp(path: Path, keys?: Key[], options?: TokensToRegexpOptions & ParseOptions): RegExp;
|
|
116
|
+
export declare const PathToRegexpUtil: {
|
|
117
|
+
toRegexp: typeof toRegexp;
|
|
118
|
+
compile: typeof compile;
|
|
119
|
+
parse: typeof parse;
|
|
120
|
+
match: typeof match;
|
|
121
|
+
};
|
|
122
|
+
export {};
|
|
24
123
|
//# sourceMappingURL=pathToRegexp.d.ts.map
|
|
@@ -1,268 +1,401 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* this file fork from path-to-regexp package v1.8.0
|
|
4
|
-
*/
|
|
5
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.
|
|
3
|
+
exports.PathToRegexpUtil = void 0;
|
|
7
4
|
/**
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* @type {RegExp}
|
|
5
|
+
* Tokenize input string.
|
|
11
6
|
*/
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
7
|
+
function lexer(str) {
|
|
8
|
+
const tokens = [];
|
|
9
|
+
let i = 0;
|
|
10
|
+
while (i < str.length) {
|
|
11
|
+
const char = str[i];
|
|
12
|
+
if (char === '*' || char === '+' || char === '?') {
|
|
13
|
+
tokens.push({ type: 'MODIFIER', index: i, value: str[i++] });
|
|
14
|
+
continue;
|
|
15
|
+
}
|
|
16
|
+
if (char === '\\') {
|
|
17
|
+
tokens.push({ type: 'ESCAPED_CHAR', index: i++, value: str[i++] });
|
|
18
|
+
continue;
|
|
19
|
+
}
|
|
20
|
+
if (char === '{') {
|
|
21
|
+
tokens.push({ type: 'OPEN', index: i, value: str[i++] });
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
if (char === '}') {
|
|
25
|
+
tokens.push({ type: 'CLOSE', index: i, value: str[i++] });
|
|
26
|
+
continue;
|
|
27
|
+
}
|
|
28
|
+
if (char === ':') {
|
|
29
|
+
let name = '';
|
|
30
|
+
let j = i + 1;
|
|
31
|
+
while (j < str.length) {
|
|
32
|
+
const code = str.charCodeAt(j);
|
|
33
|
+
if (
|
|
34
|
+
// `0-9`
|
|
35
|
+
(code >= 48 && code <= 57) ||
|
|
36
|
+
// `A-Z`
|
|
37
|
+
(code >= 65 && code <= 90) ||
|
|
38
|
+
// `a-z`
|
|
39
|
+
(code >= 97 && code <= 122) ||
|
|
40
|
+
// `_`
|
|
41
|
+
code === 95) {
|
|
42
|
+
name += str[j++];
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
break;
|
|
46
|
+
}
|
|
47
|
+
if (!name)
|
|
48
|
+
throw new TypeError(`Missing parameter name at ${i}`);
|
|
49
|
+
tokens.push({ type: 'NAME', index: i, value: name });
|
|
50
|
+
i = j;
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
if (char === '(') {
|
|
54
|
+
let count = 1;
|
|
55
|
+
let pattern = '';
|
|
56
|
+
let j = i + 1;
|
|
57
|
+
if (str[j] === '?') {
|
|
58
|
+
throw new TypeError(`Pattern cannot start with "?" at ${j}`);
|
|
59
|
+
}
|
|
60
|
+
while (j < str.length) {
|
|
61
|
+
if (str[j] === '\\') {
|
|
62
|
+
pattern += str[j++] + str[j++];
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
if (str[j] === ')') {
|
|
66
|
+
count--;
|
|
67
|
+
if (count === 0) {
|
|
68
|
+
j++;
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
else if (str[j] === '(') {
|
|
73
|
+
count++;
|
|
74
|
+
if (str[j + 1] !== '?') {
|
|
75
|
+
throw new TypeError(`Capturing groups are not allowed at ${j}`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
pattern += str[j++];
|
|
79
|
+
}
|
|
80
|
+
if (count)
|
|
81
|
+
throw new TypeError(`Unbalanced pattern at ${i}`);
|
|
82
|
+
if (!pattern)
|
|
83
|
+
throw new TypeError(`Missing pattern at ${i}`);
|
|
84
|
+
tokens.push({ type: 'PATTERN', index: i, value: pattern });
|
|
85
|
+
i = j;
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
tokens.push({ type: 'CHAR', index: i, value: str[i++] });
|
|
89
|
+
}
|
|
90
|
+
tokens.push({ type: 'END', index: i, value: '' });
|
|
91
|
+
return tokens;
|
|
92
|
+
}
|
|
24
93
|
/**
|
|
25
94
|
* Parse a string for the raw tokens.
|
|
26
|
-
*
|
|
27
|
-
* @param {string} str
|
|
28
|
-
* @param {Object=} options
|
|
29
|
-
* @return {!Array}
|
|
30
95
|
*/
|
|
31
|
-
function parse(str, options) {
|
|
32
|
-
const tokens =
|
|
96
|
+
function parse(str, options = {}) {
|
|
97
|
+
const tokens = lexer(str);
|
|
98
|
+
const { prefixes = './' } = options;
|
|
99
|
+
const defaultPattern = `[^${escapeString(options.delimiter || '/#?')}]+?`;
|
|
100
|
+
const result = [];
|
|
33
101
|
let key = 0;
|
|
34
|
-
let
|
|
102
|
+
let i = 0;
|
|
35
103
|
let path = '';
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
104
|
+
const tryConsume = (type) => {
|
|
105
|
+
if (i < tokens.length && tokens[i].type === type)
|
|
106
|
+
return tokens[i++].value;
|
|
107
|
+
};
|
|
108
|
+
const mustConsume = (type) => {
|
|
109
|
+
const value = tryConsume(type);
|
|
110
|
+
if (value !== undefined)
|
|
111
|
+
return value;
|
|
112
|
+
const { type: nextType, index } = tokens[i];
|
|
113
|
+
throw new TypeError(`Unexpected ${nextType} at ${index}, expected ${type}`);
|
|
114
|
+
};
|
|
115
|
+
const consumeText = () => {
|
|
116
|
+
let result = '';
|
|
117
|
+
let value;
|
|
118
|
+
while ((value = tryConsume('CHAR') || tryConsume('ESCAPED_CHAR'))) {
|
|
119
|
+
result += value;
|
|
120
|
+
}
|
|
121
|
+
return result;
|
|
122
|
+
};
|
|
123
|
+
while (i < tokens.length) {
|
|
124
|
+
const char = tryConsume('CHAR');
|
|
125
|
+
const name = tryConsume('NAME');
|
|
126
|
+
const pattern = tryConsume('PATTERN');
|
|
127
|
+
if (name || pattern) {
|
|
128
|
+
let prefix = char || '';
|
|
129
|
+
if (prefixes.indexOf(prefix) === -1) {
|
|
130
|
+
path += prefix;
|
|
131
|
+
prefix = '';
|
|
132
|
+
}
|
|
133
|
+
if (path) {
|
|
134
|
+
result.push(path);
|
|
135
|
+
path = '';
|
|
136
|
+
}
|
|
137
|
+
result.push({
|
|
138
|
+
name: name || key++,
|
|
139
|
+
prefix,
|
|
140
|
+
suffix: '',
|
|
141
|
+
pattern: pattern || defaultPattern,
|
|
142
|
+
modifier: tryConsume('MODIFIER') || '',
|
|
143
|
+
});
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
const value = char || tryConsume('ESCAPED_CHAR');
|
|
147
|
+
if (value) {
|
|
148
|
+
path += value;
|
|
47
149
|
continue;
|
|
48
150
|
}
|
|
49
|
-
const next = str[index];
|
|
50
|
-
const prefix = res[2];
|
|
51
|
-
const name = res[3];
|
|
52
|
-
const capture = res[4];
|
|
53
|
-
const group = res[5];
|
|
54
|
-
const modifier = res[6];
|
|
55
|
-
const asterisk = res[7];
|
|
56
|
-
// Push the current path onto the tokens.
|
|
57
151
|
if (path) {
|
|
58
|
-
|
|
152
|
+
result.push(path);
|
|
59
153
|
path = '';
|
|
60
154
|
}
|
|
61
|
-
const
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
: '[^' + escapeString(delimiter) + ']+?',
|
|
79
|
-
});
|
|
80
|
-
}
|
|
81
|
-
// Match any characters still remaining.
|
|
82
|
-
if (index < str.length) {
|
|
83
|
-
path += str.slice(index);
|
|
84
|
-
}
|
|
85
|
-
// If the path exists, push it onto the end.
|
|
86
|
-
if (path) {
|
|
87
|
-
tokens.push(path);
|
|
155
|
+
const open = tryConsume('OPEN');
|
|
156
|
+
if (open) {
|
|
157
|
+
const prefix = consumeText();
|
|
158
|
+
const name = tryConsume('NAME') || '';
|
|
159
|
+
const pattern = tryConsume('PATTERN') || '';
|
|
160
|
+
const suffix = consumeText();
|
|
161
|
+
mustConsume('CLOSE');
|
|
162
|
+
result.push({
|
|
163
|
+
name: name || (pattern ? key++ : ''),
|
|
164
|
+
pattern: name && !pattern ? defaultPattern : pattern,
|
|
165
|
+
prefix,
|
|
166
|
+
suffix,
|
|
167
|
+
modifier: tryConsume('MODIFIER') || '',
|
|
168
|
+
});
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
mustConsume('END');
|
|
88
172
|
}
|
|
89
|
-
return
|
|
173
|
+
return result;
|
|
90
174
|
}
|
|
91
175
|
/**
|
|
92
|
-
*
|
|
93
|
-
*
|
|
94
|
-
* @param {string} str
|
|
95
|
-
* @return {string}
|
|
176
|
+
* Compile a string to a template function for the path.
|
|
96
177
|
*/
|
|
97
|
-
function
|
|
98
|
-
return
|
|
178
|
+
function compile(str, options) {
|
|
179
|
+
return tokensToFunction(parse(str, options), options);
|
|
99
180
|
}
|
|
100
181
|
/**
|
|
101
|
-
*
|
|
102
|
-
*
|
|
103
|
-
* @param {string} group
|
|
104
|
-
* @return {string}
|
|
182
|
+
* Expose a method for transforming tokens into the path function.
|
|
105
183
|
*/
|
|
106
|
-
function
|
|
107
|
-
|
|
184
|
+
function tokensToFunction(tokens, options = {}) {
|
|
185
|
+
const reFlags = flags(options);
|
|
186
|
+
const { encode = (x) => x, validate = true } = options;
|
|
187
|
+
// Compile all the tokens into regexps.
|
|
188
|
+
const matches = tokens.map(token => {
|
|
189
|
+
if (typeof token === 'object') {
|
|
190
|
+
return new RegExp(`^(?:${token.pattern})$`, reFlags);
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
return (data) => {
|
|
194
|
+
let path = '';
|
|
195
|
+
for (let i = 0; i < tokens.length; i++) {
|
|
196
|
+
const token = tokens[i];
|
|
197
|
+
if (typeof token === 'string') {
|
|
198
|
+
path += token;
|
|
199
|
+
continue;
|
|
200
|
+
}
|
|
201
|
+
const value = data ? data[token.name] : undefined;
|
|
202
|
+
const optional = token.modifier === '?' || token.modifier === '*';
|
|
203
|
+
const repeat = token.modifier === '*' || token.modifier === '+';
|
|
204
|
+
if (Array.isArray(value)) {
|
|
205
|
+
if (!repeat) {
|
|
206
|
+
throw new TypeError(`Expected "${token.name}" to not repeat, but got an array`);
|
|
207
|
+
}
|
|
208
|
+
if (value.length === 0) {
|
|
209
|
+
if (optional)
|
|
210
|
+
continue;
|
|
211
|
+
throw new TypeError(`Expected "${token.name}" to not be empty`);
|
|
212
|
+
}
|
|
213
|
+
for (let j = 0; j < value.length; j++) {
|
|
214
|
+
const segment = encode(value[j], token);
|
|
215
|
+
if (validate && !matches[i].test(segment)) {
|
|
216
|
+
throw new TypeError(`Expected all "${token.name}" to match "${token.pattern}", but got "${segment}"`);
|
|
217
|
+
}
|
|
218
|
+
path += token.prefix + segment + token.suffix;
|
|
219
|
+
}
|
|
220
|
+
continue;
|
|
221
|
+
}
|
|
222
|
+
if (typeof value === 'string' || typeof value === 'number') {
|
|
223
|
+
const segment = encode(String(value), token);
|
|
224
|
+
if (validate && !matches[i].test(segment)) {
|
|
225
|
+
throw new TypeError(`Expected "${token.name}" to match "${token.pattern}", but got "${segment}"`);
|
|
226
|
+
}
|
|
227
|
+
path += token.prefix + segment + token.suffix;
|
|
228
|
+
continue;
|
|
229
|
+
}
|
|
230
|
+
if (optional)
|
|
231
|
+
continue;
|
|
232
|
+
const typeOfMessage = repeat ? 'an array' : 'a string';
|
|
233
|
+
throw new TypeError(`Expected "${token.name}" to be ${typeOfMessage}`);
|
|
234
|
+
}
|
|
235
|
+
return path;
|
|
236
|
+
};
|
|
108
237
|
}
|
|
109
238
|
/**
|
|
110
|
-
*
|
|
111
|
-
*
|
|
112
|
-
* @param {!RegExp} re
|
|
113
|
-
* @param {Array} keys
|
|
114
|
-
* @return {!RegExp}
|
|
239
|
+
* Create path match function from `path-to-regexp` spec.
|
|
115
240
|
*/
|
|
116
|
-
function
|
|
117
|
-
|
|
118
|
-
|
|
241
|
+
function match(str, options) {
|
|
242
|
+
const keys = [];
|
|
243
|
+
const re = toRegexp(str, keys, options);
|
|
244
|
+
return regexpToFunction(re, keys, options);
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Create a path match function from `path-to-regexp` output.
|
|
248
|
+
*/
|
|
249
|
+
function regexpToFunction(re, keys, options = {}) {
|
|
250
|
+
const { decode = (x) => x } = options;
|
|
251
|
+
return function (pathname) {
|
|
252
|
+
const m = re.exec(pathname);
|
|
253
|
+
if (!m)
|
|
254
|
+
return false;
|
|
255
|
+
const { 0: path, index } = m;
|
|
256
|
+
const params = Object.create(null);
|
|
257
|
+
for (let i = 1; i < m.length; i++) {
|
|
258
|
+
if (m[i] === undefined)
|
|
259
|
+
continue;
|
|
260
|
+
const key = keys[i - 1];
|
|
261
|
+
if (key.modifier === '*' || key.modifier === '+') {
|
|
262
|
+
params[key.name] = m[i].split(key.prefix + key.suffix).map(value => {
|
|
263
|
+
return decode(value, key);
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
else {
|
|
267
|
+
params[key.name] = decode(m[i], key);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
return { path, index, params };
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* Escape a regular expression string.
|
|
275
|
+
*/
|
|
276
|
+
function escapeString(str) {
|
|
277
|
+
return str.replace(/([.+*?=^!:${}()[\]|/\\])/g, '\\$1');
|
|
119
278
|
}
|
|
120
279
|
/**
|
|
121
280
|
* Get the flags for a regexp from the options.
|
|
122
|
-
*
|
|
123
|
-
* @param {Object} options
|
|
124
|
-
* @return {string}
|
|
125
281
|
*/
|
|
126
282
|
function flags(options) {
|
|
127
283
|
return options && options.sensitive ? '' : 'i';
|
|
128
284
|
}
|
|
129
285
|
/**
|
|
130
286
|
* Pull out keys from a regexp.
|
|
131
|
-
*
|
|
132
|
-
* @param {!RegExp} path
|
|
133
|
-
* @param {!Array} keys
|
|
134
|
-
* @return {!RegExp}
|
|
135
287
|
*/
|
|
136
288
|
function regexpToRegexp(path, keys) {
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
289
|
+
if (!keys)
|
|
290
|
+
return path;
|
|
291
|
+
const groupsRegex = /\((?:\?<(.*?)>)?(?!\?)/g;
|
|
292
|
+
let index = 0;
|
|
293
|
+
let execResult = groupsRegex.exec(path.source);
|
|
294
|
+
while (execResult) {
|
|
295
|
+
keys.push({
|
|
296
|
+
// Use parenthesized substring match if available, index otherwise
|
|
297
|
+
name: execResult[1] || index++,
|
|
298
|
+
prefix: '',
|
|
299
|
+
suffix: '',
|
|
300
|
+
modifier: '',
|
|
301
|
+
pattern: '',
|
|
302
|
+
});
|
|
303
|
+
execResult = groupsRegex.exec(path.source);
|
|
152
304
|
}
|
|
153
|
-
return
|
|
305
|
+
return path;
|
|
154
306
|
}
|
|
155
307
|
/**
|
|
156
308
|
* Transform an array into a regexp.
|
|
157
|
-
*
|
|
158
|
-
* @param {!Array} path
|
|
159
|
-
* @param {Array} keys
|
|
160
|
-
* @param {!Object} options
|
|
161
|
-
* @return {!RegExp}
|
|
162
309
|
*/
|
|
163
|
-
function arrayToRegexp(
|
|
164
|
-
const parts =
|
|
165
|
-
|
|
166
|
-
parts.push(pathToRegexp(path[i], keys, options).source);
|
|
167
|
-
}
|
|
168
|
-
const regexp = new RegExp('(?:' + parts.join('|') + ')', flags(options));
|
|
169
|
-
return attachKeys(regexp, keys);
|
|
310
|
+
function arrayToRegexp(paths, keys, options) {
|
|
311
|
+
const parts = paths.map(path => toRegexp(path, keys, options).source);
|
|
312
|
+
return new RegExp(`(?:${parts.join('|')})`, flags(options));
|
|
170
313
|
}
|
|
171
314
|
/**
|
|
172
315
|
* Create a path regexp from string input.
|
|
173
|
-
*
|
|
174
|
-
* @param {string} path
|
|
175
|
-
* @param {!Array} keys
|
|
176
|
-
* @param {!Object} options
|
|
177
|
-
* @return {!RegExp}
|
|
178
316
|
*/
|
|
179
317
|
function stringToRegexp(path, keys, options) {
|
|
180
|
-
return
|
|
318
|
+
return tokensToRegexp(parse(path, options), keys, options);
|
|
181
319
|
}
|
|
182
320
|
/**
|
|
183
321
|
* Expose a function for taking tokens and returning a RegExp.
|
|
184
|
-
*
|
|
185
|
-
* @param {!Array} tokens
|
|
186
|
-
* @param {(Array|Object)=} keys
|
|
187
|
-
* @param {Object=} options
|
|
188
|
-
* @return {!RegExp}
|
|
189
322
|
*/
|
|
190
|
-
function
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
options = options || {};
|
|
196
|
-
const strict = options.strict;
|
|
197
|
-
const end = options.end !== false;
|
|
198
|
-
let route = '';
|
|
323
|
+
function tokensToRegexp(tokens, keys, options = {}) {
|
|
324
|
+
const { strict = false, start = true, end = true, encode = (x) => x, delimiter = '/#?', endsWith = '', } = options;
|
|
325
|
+
const endsWithRe = `[${escapeString(endsWith)}]|$`;
|
|
326
|
+
const delimiterRe = `[${escapeString(delimiter)}]`;
|
|
327
|
+
let route = start ? '^' : '';
|
|
199
328
|
// Iterate over the tokens and create our regexp string.
|
|
200
|
-
for (
|
|
201
|
-
const token = tokens[i];
|
|
329
|
+
for (const token of tokens) {
|
|
202
330
|
if (typeof token === 'string') {
|
|
203
|
-
route += escapeString(token);
|
|
331
|
+
route += escapeString(encode(token));
|
|
204
332
|
}
|
|
205
333
|
else {
|
|
206
|
-
const prefix = escapeString(token.prefix);
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
334
|
+
const prefix = escapeString(encode(token.prefix));
|
|
335
|
+
const suffix = escapeString(encode(token.suffix));
|
|
336
|
+
if (token.pattern) {
|
|
337
|
+
if (keys)
|
|
338
|
+
keys.push(token);
|
|
339
|
+
if (prefix || suffix) {
|
|
340
|
+
if (token.modifier === '+' || token.modifier === '*') {
|
|
341
|
+
const mod = token.modifier === '*' ? '?' : '';
|
|
342
|
+
route += `(?:${prefix}((?:${token.pattern})(?:${suffix}${prefix}(?:${token.pattern}))*)${suffix})${mod}`;
|
|
343
|
+
}
|
|
344
|
+
else {
|
|
345
|
+
route += `(?:${prefix}(${token.pattern})${suffix})${token.modifier}`;
|
|
346
|
+
}
|
|
215
347
|
}
|
|
216
348
|
else {
|
|
217
|
-
|
|
349
|
+
if (token.modifier === '+' || token.modifier === '*') {
|
|
350
|
+
route += `((?:${token.pattern})${token.modifier})`;
|
|
351
|
+
}
|
|
352
|
+
else {
|
|
353
|
+
route += `(${token.pattern})${token.modifier}`;
|
|
354
|
+
}
|
|
218
355
|
}
|
|
219
356
|
}
|
|
220
357
|
else {
|
|
221
|
-
|
|
358
|
+
route += `(?:${prefix}${suffix})${token.modifier}`;
|
|
222
359
|
}
|
|
223
|
-
route += capture;
|
|
224
360
|
}
|
|
225
361
|
}
|
|
226
|
-
const delimiter = escapeString(options.delimiter || '/');
|
|
227
|
-
const endsWithDelimiter = route.slice(-delimiter.length) === delimiter;
|
|
228
|
-
// In non-strict mode we allow a slash at the end of match. If the path to
|
|
229
|
-
// match already ends with a slash, we remove it for consistency. The slash
|
|
230
|
-
// is valid at the end of a path match, not in the middle. This is important
|
|
231
|
-
// in non-ending mode, where "/test/" shouldn't match "/test//route".
|
|
232
|
-
if (!strict) {
|
|
233
|
-
route =
|
|
234
|
-
(endsWithDelimiter ? route.slice(0, -delimiter.length) : route) +
|
|
235
|
-
'(?:' +
|
|
236
|
-
delimiter +
|
|
237
|
-
'(?=$))?';
|
|
238
|
-
}
|
|
239
362
|
if (end) {
|
|
240
|
-
|
|
363
|
+
if (!strict)
|
|
364
|
+
route += `${delimiterRe}?`;
|
|
365
|
+
route += !options.endsWith ? '$' : `(?=${endsWithRe})`;
|
|
241
366
|
}
|
|
242
367
|
else {
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
368
|
+
const endToken = tokens[tokens.length - 1];
|
|
369
|
+
const isEndDelimited = typeof endToken === 'string'
|
|
370
|
+
? delimiterRe.indexOf(endToken[endToken.length - 1]) > -1
|
|
371
|
+
: endToken === undefined;
|
|
372
|
+
if (!strict) {
|
|
373
|
+
route += `(?:${delimiterRe}(?=${endsWithRe}))?`;
|
|
374
|
+
}
|
|
375
|
+
if (!isEndDelimited) {
|
|
376
|
+
route += `(?=${delimiterRe}|${endsWithRe})`;
|
|
377
|
+
}
|
|
246
378
|
}
|
|
247
|
-
return
|
|
379
|
+
return new RegExp(route, flags(options));
|
|
248
380
|
}
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
}
|
|
263
|
-
return stringToRegexp(
|
|
264
|
-
/** @type {string} */ path,
|
|
265
|
-
/** @type {!Array} */ keys, options);
|
|
381
|
+
/**
|
|
382
|
+
* Normalize the given path string, returning a regular expression.
|
|
383
|
+
*
|
|
384
|
+
* An empty array can be passed in for the keys, which will hold the
|
|
385
|
+
* placeholder key descriptions. For example, using `/user/:id`, `keys` will
|
|
386
|
+
* contain `[{ name: 'id', delimiter: '/', optional: false, repeat: false }]`.
|
|
387
|
+
*/
|
|
388
|
+
function toRegexp(path, keys, options) {
|
|
389
|
+
if (path instanceof RegExp)
|
|
390
|
+
return regexpToRegexp(path, keys);
|
|
391
|
+
if (Array.isArray(path))
|
|
392
|
+
return arrayToRegexp(path, keys, options);
|
|
393
|
+
return stringToRegexp(path, keys, options);
|
|
266
394
|
}
|
|
267
|
-
exports.
|
|
395
|
+
exports.PathToRegexpUtil = {
|
|
396
|
+
toRegexp,
|
|
397
|
+
compile,
|
|
398
|
+
parse,
|
|
399
|
+
match,
|
|
400
|
+
};
|
|
268
401
|
//# sourceMappingURL=pathToRegexp.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@midwayjs/core",
|
|
3
|
-
"version": "3.4.0-beta.
|
|
3
|
+
"version": "3.4.0-beta.9",
|
|
4
4
|
"description": "midway core",
|
|
5
5
|
"main": "dist/index",
|
|
6
6
|
"typings": "dist/index.d.ts",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
],
|
|
22
22
|
"license": "MIT",
|
|
23
23
|
"devDependencies": {
|
|
24
|
-
"@midwayjs/decorator": "^3.4.0-beta.
|
|
24
|
+
"@midwayjs/decorator": "^3.4.0-beta.9",
|
|
25
25
|
"koa": "2.13.4",
|
|
26
26
|
"midway-test-component": "*",
|
|
27
27
|
"mm": "3.2.0",
|
|
@@ -45,5 +45,5 @@
|
|
|
45
45
|
"engines": {
|
|
46
46
|
"node": ">=12"
|
|
47
47
|
},
|
|
48
|
-
"gitHead": "
|
|
48
|
+
"gitHead": "41e82a0fba386c6ec42c2eefd1dff4795a81b389"
|
|
49
49
|
}
|