typescript-mock-server 1.10.0 → 1.11.2
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/README.md +13 -3
- package/dist/command-line.js +9 -0
- package/dist/impl/command-line-impl.js +28 -0
- package/dist/impl/logger-impl.js +31 -0
- package/dist/impl/typescript-mock-server-impl.js +212 -0
- package/dist/index.js +6 -0
- package/dist/logger.js +2 -0
- package/dist/models/config.js +2 -0
- package/dist/models/registered-endpoint.js +2 -0
- package/dist/src/command-line.js +9 -0
- package/dist/src/impl/command-line-impl.js +28 -0
- package/dist/src/impl/logger-impl.js +31 -0
- package/dist/src/impl/typescript-mock-server-impl.js +208 -0
- package/dist/src/index.js +6 -0
- package/dist/src/logger.js +2 -0
- package/dist/src/models/config.js +2 -0
- package/dist/src/models/registered-endpoint.js +2 -0
- package/dist/src/types/http-verbs.js +2 -0
- package/dist/src/typescript-mock-server.js +2 -0
- package/dist/test/impl/command-line-impl.spec.js +40 -0
- package/dist/test/impl/typescript-mock-server-impl.spec.js +182 -0
- package/dist/tms-models/dash-example/get-dash-in-id.js +6 -0
- package/dist/tms-models/dash-example/get-test1.js +6 -0
- package/dist/tms-models/dash-example/get.js +20 -0
- package/dist/tms-models/users/delete-1.js +8 -0
- package/dist/tms-models/users/get-1.js +14 -0
- package/dist/tms-models/users/get-dynamic.js +15 -0
- package/dist/tms-models/users/get.js +20 -0
- package/dist/tms-models/users/head-1.js +4 -0
- package/dist/tms-models/users/options-1.js +4 -0
- package/dist/tms-models/users/patch-1.js +8 -0
- package/dist/tms-models/users/post-1.js +8 -0
- package/dist/tms-models/users/profile/get-1.js +12 -0
- package/dist/tms-models/users/put-1.js +8 -0
- package/dist/types/http-verbs.js +2 -0
- package/dist/typescript-mock-server.js +2 -0
- package/jest.config.js +12 -0
- package/package.json +9 -4
- package/src/impl/typescript-mock-server-impl.ts +72 -31
- package/src/index.ts +1 -1
- package/src/models/config.ts +10 -0
- package/test/impl/command-line-impl.spec.ts +49 -0
- package/test/impl/typescript-mock-server-impl.spec.ts +181 -0
- package/tms-models/users/get-dynamic.ts +22 -0
- package/tsconfig.json +5 -1
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@ have to update your mock, otherwise you will receive compile errors.
|
|
|
6
6
|
# Quickstart
|
|
7
7
|
The easiest way to check out this stub/mock server is by installing it as a (dev)dependency and then
|
|
8
8
|
add a script to you scripts section: `npm run --prefix node_modules/typescript-mock-server start -- --path=$INIT_CWD/tms-models`.
|
|
9
|
-
Your models should export a data const and your file should be named as `^(get|post){1}(-\d)?.ts$`.
|
|
9
|
+
Your models should export a data const (or a function receiving `req` and `res`) and your file should be named as `^(get|post){1}(-\d)?.ts$`.
|
|
10
10
|
Changes are being picked up automatically, so no need for a restart. When you add files, you have to restart.
|
|
11
11
|
|
|
12
12
|
Check out the [working example project](https://github.com/GuyT07/typescript-mock-server-examle) and [the source](https://github.com/GuyT07/typescript-mock-server/tree/main/tms-models/users).
|
|
@@ -38,7 +38,7 @@ You should have the following structure:
|
|
|
38
38
|
|
|
39
39
|
Within the model file you can import/create your model:
|
|
40
40
|
|
|
41
|
-
```
|
|
41
|
+
```typescript
|
|
42
42
|
export interface User {
|
|
43
43
|
id: number;
|
|
44
44
|
firstName: string;
|
|
@@ -48,6 +48,7 @@ export interface User {
|
|
|
48
48
|
|
|
49
49
|
const newDate = () => new Date();
|
|
50
50
|
|
|
51
|
+
// You can export a static object
|
|
51
52
|
export const data: User[] = [{
|
|
52
53
|
id: 1,
|
|
53
54
|
firstName: 'Guy',
|
|
@@ -60,6 +61,12 @@ export const data: User[] = [{
|
|
|
60
61
|
creationDate: newDate()
|
|
61
62
|
}];
|
|
62
63
|
|
|
64
|
+
// OR you can export a function to access request/response context
|
|
65
|
+
export const data = (req: Request, res: Response): User[] => {
|
|
66
|
+
console.log(req.query);
|
|
67
|
+
return [{ id: 1, firstName: 'Dynamic', lastName: 'User', creationDate: new Date() }];
|
|
68
|
+
}
|
|
69
|
+
|
|
63
70
|
export const config: RequestConfig = {
|
|
64
71
|
delay: 2000, // or you can use an interval like {min: 2000, max: 5000}
|
|
65
72
|
statusCode: 418
|
|
@@ -80,17 +87,20 @@ Following dependencies are being used:
|
|
|
80
87
|
- [x] Improve paths/way to start
|
|
81
88
|
- [x] Support different headers/configurations (delays, status codes, ...)
|
|
82
89
|
- [x] Support most used HTTP methods
|
|
83
|
-
- [
|
|
90
|
+
- [x] Add tests
|
|
84
91
|
- [x] Refactor, split up in separate classes (first check if people actually want to use the tool)
|
|
85
92
|
- [ ] Setup CI/CD (+code quality + coverage tooling)
|
|
86
93
|
- [ ] Setup website
|
|
87
94
|
- [ ] Create a JVM compatible version
|
|
88
95
|
- [x] Create interface to force implementation of required properties and make it more stable
|
|
89
96
|
- [x] Improve error handling (missing properties etc.)
|
|
97
|
+
- [x] Support dynamic responses via request/response context
|
|
90
98
|
- [ ] Create an optional persistent state
|
|
91
99
|
|
|
92
100
|
|
|
93
101
|
## Release notes (will be moved to GitHub in the future)
|
|
102
|
+
- v1.11.0 - Support dynamic responses via request/response context, added comprehensive tests, and switched to a faster build-and-serve workflow
|
|
103
|
+
- v1.10.0 - Improved path resolution and library usage support
|
|
94
104
|
- v1.0.8 - Minor bugfixes
|
|
95
105
|
- v1.0.7 - Minor bugfixes
|
|
96
106
|
- v1.0.6 - Bugfix: accidentally included "npm" and "install" dependency, removed again
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Command = void 0;
|
|
4
|
+
var Command;
|
|
5
|
+
(function (Command) {
|
|
6
|
+
Command["PATH"] = "path";
|
|
7
|
+
Command["PORT"] = "port";
|
|
8
|
+
Command["CORS"] = "cors";
|
|
9
|
+
})(Command || (exports.Command = Command = {}));
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CommandLineImpl = void 0;
|
|
4
|
+
const logger_impl_1 = require("./logger-impl");
|
|
5
|
+
class CommandLineImpl {
|
|
6
|
+
constructor() {
|
|
7
|
+
this.arguments = new Map();
|
|
8
|
+
this.log = new logger_impl_1.LoggerImpl();
|
|
9
|
+
this.parseCommandLineArguments();
|
|
10
|
+
}
|
|
11
|
+
getCommands() {
|
|
12
|
+
return this.arguments;
|
|
13
|
+
}
|
|
14
|
+
getCommand(command) {
|
|
15
|
+
return this.arguments.get(command);
|
|
16
|
+
}
|
|
17
|
+
parseCommandLineArguments() {
|
|
18
|
+
process.argv.slice(2).map((element) => {
|
|
19
|
+
const matches = element.match('--([a-zA-Z0-9]+)=(.*)');
|
|
20
|
+
if (matches) {
|
|
21
|
+
const value = matches[2].replace(/^['"]/, '').replace(/['"]$/, '');
|
|
22
|
+
this.arguments.set(matches[1], value);
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
this.log.debug(`Passed arguments ${[...this.arguments.keys()].join(',')}`);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
exports.CommandLineImpl = CommandLineImpl;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.LoggerImpl = void 0;
|
|
4
|
+
const tslog_1 = require("tslog");
|
|
5
|
+
class LoggerImpl {
|
|
6
|
+
constructor() {
|
|
7
|
+
this.log = new tslog_1.Logger({ ignoreStackLevels: 4, displayFunctionName: false });
|
|
8
|
+
}
|
|
9
|
+
static getArgumentsToPass(args) {
|
|
10
|
+
return LoggerImpl.getNumberOfArguments(args) === 1 ? args[0] : args;
|
|
11
|
+
}
|
|
12
|
+
static getNumberOfArguments(args) {
|
|
13
|
+
return args.length;
|
|
14
|
+
}
|
|
15
|
+
debug(...args) {
|
|
16
|
+
this.log.debug(LoggerImpl.getArgumentsToPass(args));
|
|
17
|
+
}
|
|
18
|
+
error(...args) {
|
|
19
|
+
this.log.error(LoggerImpl.getArgumentsToPass(args));
|
|
20
|
+
}
|
|
21
|
+
trace(...args) {
|
|
22
|
+
this.log.trace(LoggerImpl.getArgumentsToPass(args));
|
|
23
|
+
}
|
|
24
|
+
warn(...args) {
|
|
25
|
+
this.log.warn(LoggerImpl.getArgumentsToPass(args));
|
|
26
|
+
}
|
|
27
|
+
info(...args) {
|
|
28
|
+
this.log.info(LoggerImpl.getArgumentsToPass(args));
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
exports.LoggerImpl = LoggerImpl;
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
36
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
37
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
38
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
39
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
40
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
41
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
42
|
+
});
|
|
43
|
+
};
|
|
44
|
+
var __asyncValues = (this && this.__asyncValues) || function (o) {
|
|
45
|
+
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
|
|
46
|
+
var m = o[Symbol.asyncIterator], i;
|
|
47
|
+
return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
|
|
48
|
+
function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
|
|
49
|
+
function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
|
|
50
|
+
};
|
|
51
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
52
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
53
|
+
};
|
|
54
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
55
|
+
exports.TypescriptMockServerImpl = void 0;
|
|
56
|
+
const express_1 = __importDefault(require("express"));
|
|
57
|
+
const cors_1 = __importDefault(require("cors"));
|
|
58
|
+
const command_line_impl_1 = require("./command-line-impl");
|
|
59
|
+
const command_line_1 = require("../command-line");
|
|
60
|
+
const promises_1 = require("fs/promises");
|
|
61
|
+
const logger_impl_1 = require("./logger-impl");
|
|
62
|
+
const path_1 = __importDefault(require("path"));
|
|
63
|
+
class TypescriptMockServerImpl {
|
|
64
|
+
constructor(config) {
|
|
65
|
+
this.log = new logger_impl_1.LoggerImpl();
|
|
66
|
+
this.commandLine = new command_line_impl_1.CommandLineImpl();
|
|
67
|
+
this.registeredEndpoints = [];
|
|
68
|
+
if (config && 'use' in config) {
|
|
69
|
+
this.app = config;
|
|
70
|
+
this.basePath = this.getPath();
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
const serverConfig = config;
|
|
74
|
+
this.app = (serverConfig === null || serverConfig === void 0 ? void 0 : serverConfig.app) || (0, express_1.default)();
|
|
75
|
+
this.basePath = this.getPath(serverConfig === null || serverConfig === void 0 ? void 0 : serverConfig.path);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
static loadModule(moduleName) {
|
|
79
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
80
|
+
if (moduleName.endsWith('.ts')) {
|
|
81
|
+
require('ts-node').register({ transpileOnly: true });
|
|
82
|
+
}
|
|
83
|
+
return yield Promise.resolve(`${moduleName}`).then(s => __importStar(require(s)));
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
start() {
|
|
87
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
88
|
+
this.log.info(`basePath: ${this.basePath}`);
|
|
89
|
+
const port = this.commandLine.getCommand(command_line_1.Command.PORT) || 3000;
|
|
90
|
+
const corsSetting = {
|
|
91
|
+
origin: this.commandLine.getCommand(command_line_1.Command.CORS) || '*'
|
|
92
|
+
};
|
|
93
|
+
this.app.use((0, cors_1.default)(corsSetting));
|
|
94
|
+
// add started endpoint
|
|
95
|
+
this.addEndpoint('state', 'get', { data: { status: 'started' } });
|
|
96
|
+
yield this.readRoutes(this.basePath).catch(error => this.log.error(error));
|
|
97
|
+
this.app.listen(port, () => {
|
|
98
|
+
this.log.info(`App is listening on port ${port}!`);
|
|
99
|
+
});
|
|
100
|
+
this.log.info(`Started mock server on port ${port}`);
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
readRoutes(dirPath) {
|
|
104
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
105
|
+
var _a, e_1, _b, _c;
|
|
106
|
+
const dir = yield (0, promises_1.opendir)(dirPath);
|
|
107
|
+
try {
|
|
108
|
+
for (var _d = true, dir_1 = __asyncValues(dir), dir_1_1; dir_1_1 = yield dir_1.next(), _a = dir_1_1.done, !_a; _d = true) {
|
|
109
|
+
_c = dir_1_1.value;
|
|
110
|
+
_d = false;
|
|
111
|
+
const dirent = _c;
|
|
112
|
+
if (dirent.isDirectory()) {
|
|
113
|
+
yield this.readRoutes(`${dirPath}/${dirent.name}`);
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
yield this.handleFile(dirPath, dirent);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
121
|
+
finally {
|
|
122
|
+
try {
|
|
123
|
+
if (!_d && !_a && (_b = dir_1.return)) yield _b.call(dir_1);
|
|
124
|
+
}
|
|
125
|
+
finally { if (e_1) throw e_1.error; }
|
|
126
|
+
}
|
|
127
|
+
const port = this.commandLine.getCommand(command_line_1.Command.PORT) || 3000;
|
|
128
|
+
this.registeredEndpoints.forEach(endpoint => this.log.info(`${endpoint.httpVerb.toUpperCase()} http://localhost:${port}${endpoint.endpoint}`));
|
|
129
|
+
this.registeredEndpoints = [];
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
handleFile(dirPath, dirent) {
|
|
133
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
134
|
+
const httpVerb = (dirent.name.indexOf('-') > -1 ? dirent.name.split('-')[0] : dirent.name.split('.')[0]);
|
|
135
|
+
yield this.handleRequest(dirPath, dirent, httpVerb);
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
addEndpoint(endpoint, httpVerb, model) {
|
|
139
|
+
const route = endpoint.startsWith('/') ? endpoint : `/${endpoint}`;
|
|
140
|
+
this.app[httpVerb](route, (req, res) => {
|
|
141
|
+
var _a, _b;
|
|
142
|
+
let responseData = model.data;
|
|
143
|
+
let statusCode = (_a = model === null || model === void 0 ? void 0 : model.config) === null || _a === void 0 ? void 0 : _a.statusCode;
|
|
144
|
+
let delay = (_b = model === null || model === void 0 ? void 0 : model.config) === null || _b === void 0 ? void 0 : _b.delay;
|
|
145
|
+
if (typeof model.data === 'function') {
|
|
146
|
+
responseData = model.data(req, res);
|
|
147
|
+
}
|
|
148
|
+
if (statusCode) {
|
|
149
|
+
res.statusCode = statusCode;
|
|
150
|
+
}
|
|
151
|
+
if (delay) {
|
|
152
|
+
setTimeout(() => res.send(responseData), this.getDelayValue(delay));
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
return res.send(responseData);
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
getDelayValue(delay) {
|
|
160
|
+
if (typeof delay === 'number') {
|
|
161
|
+
return delay;
|
|
162
|
+
}
|
|
163
|
+
else if (delay.min && delay.max) {
|
|
164
|
+
return Math.floor(delay.min + Math.random() * delay.max);
|
|
165
|
+
}
|
|
166
|
+
return 0;
|
|
167
|
+
}
|
|
168
|
+
handleRequest(dirPath, dirent, httpVerb) {
|
|
169
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
170
|
+
const endpoint = this.convertFileNameToEndpoint(dirPath, dirent, httpVerb);
|
|
171
|
+
let modulePath = `${dirPath}/${dirent.name}`;
|
|
172
|
+
this.registeredEndpoints.push({ httpVerb, endpoint });
|
|
173
|
+
if (__filename.endsWith('.js') && modulePath.endsWith('.ts')) {
|
|
174
|
+
const distPath = path_1.default.join(process.cwd(), 'dist');
|
|
175
|
+
const potentialJsPath = modulePath
|
|
176
|
+
.replace(process.cwd(), distPath)
|
|
177
|
+
.replace(/\.ts$/, '.js');
|
|
178
|
+
const fs = require('fs');
|
|
179
|
+
if (fs.existsSync(potentialJsPath)) {
|
|
180
|
+
modulePath = potentialJsPath;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
yield TypescriptMockServerImpl.loadModule(modulePath)
|
|
184
|
+
.then(model => this.addEndpoint(endpoint, httpVerb, model))
|
|
185
|
+
.catch(error => this.log.error(error));
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
convertFileNameToEndpoint(dirPath, dirent, httpVerb) {
|
|
189
|
+
const endpoint = `${dirPath.replace(this.basePath, '')}/${dirent.name}`
|
|
190
|
+
.replace('.ts', '')
|
|
191
|
+
.replace(`${httpVerb}-`, '')
|
|
192
|
+
.replace(httpVerb, '');
|
|
193
|
+
if (endpoint.endsWith('/')) {
|
|
194
|
+
return endpoint.substring(0, endpoint.length - 1);
|
|
195
|
+
}
|
|
196
|
+
return endpoint;
|
|
197
|
+
}
|
|
198
|
+
getPath(defaultPath = 'tms-models') {
|
|
199
|
+
let definedPath = defaultPath;
|
|
200
|
+
if (!this.commandLine.getCommands().has(command_line_1.Command.PATH)) {
|
|
201
|
+
this.log.warn(`Path parameter not set, fallback to default ${defaultPath}`);
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
definedPath = this.commandLine.getCommand(command_line_1.Command.PATH);
|
|
205
|
+
}
|
|
206
|
+
if (path_1.default.isAbsolute(definedPath)) {
|
|
207
|
+
return definedPath;
|
|
208
|
+
}
|
|
209
|
+
return path_1.default.join(process.cwd(), definedPath);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
exports.TypescriptMockServerImpl = TypescriptMockServerImpl;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
const typescript_mock_server_impl_1 = require("./impl/typescript-mock-server-impl");
|
|
5
|
+
const server = new typescript_mock_server_impl_1.TypescriptMockServerImpl();
|
|
6
|
+
server.start().then(() => console.log('Server started')).catch(console.error);
|
package/dist/logger.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Command = void 0;
|
|
4
|
+
var Command;
|
|
5
|
+
(function (Command) {
|
|
6
|
+
Command["PATH"] = "path";
|
|
7
|
+
Command["PORT"] = "port";
|
|
8
|
+
Command["CORS"] = "cors";
|
|
9
|
+
})(Command || (exports.Command = Command = {}));
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CommandLineImpl = void 0;
|
|
4
|
+
const logger_impl_1 = require("./logger-impl");
|
|
5
|
+
class CommandLineImpl {
|
|
6
|
+
constructor() {
|
|
7
|
+
this.arguments = new Map();
|
|
8
|
+
this.log = new logger_impl_1.LoggerImpl();
|
|
9
|
+
this.parseCommandLineArguments();
|
|
10
|
+
}
|
|
11
|
+
getCommands() {
|
|
12
|
+
return this.arguments;
|
|
13
|
+
}
|
|
14
|
+
getCommand(command) {
|
|
15
|
+
return this.arguments.get(command);
|
|
16
|
+
}
|
|
17
|
+
parseCommandLineArguments() {
|
|
18
|
+
process.argv.slice(2).map((element) => {
|
|
19
|
+
const matches = element.match('--([a-zA-Z0-9]+)=(.*)');
|
|
20
|
+
if (matches) {
|
|
21
|
+
const value = matches[2].replace(/^['"]/, '').replace(/['"]$/, '');
|
|
22
|
+
this.arguments.set(matches[1], value);
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
this.log.debug(`Passed arguments ${[...this.arguments.keys()].join(',')}`);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
exports.CommandLineImpl = CommandLineImpl;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.LoggerImpl = void 0;
|
|
4
|
+
const tslog_1 = require("tslog");
|
|
5
|
+
class LoggerImpl {
|
|
6
|
+
constructor() {
|
|
7
|
+
this.log = new tslog_1.Logger({ ignoreStackLevels: 4, displayFunctionName: false });
|
|
8
|
+
}
|
|
9
|
+
static getArgumentsToPass(args) {
|
|
10
|
+
return LoggerImpl.getNumberOfArguments(args) === 1 ? args[0] : args;
|
|
11
|
+
}
|
|
12
|
+
static getNumberOfArguments(args) {
|
|
13
|
+
return args.length;
|
|
14
|
+
}
|
|
15
|
+
debug(...args) {
|
|
16
|
+
this.log.debug(LoggerImpl.getArgumentsToPass(args));
|
|
17
|
+
}
|
|
18
|
+
error(...args) {
|
|
19
|
+
this.log.error(LoggerImpl.getArgumentsToPass(args));
|
|
20
|
+
}
|
|
21
|
+
trace(...args) {
|
|
22
|
+
this.log.trace(LoggerImpl.getArgumentsToPass(args));
|
|
23
|
+
}
|
|
24
|
+
warn(...args) {
|
|
25
|
+
this.log.warn(LoggerImpl.getArgumentsToPass(args));
|
|
26
|
+
}
|
|
27
|
+
info(...args) {
|
|
28
|
+
this.log.info(LoggerImpl.getArgumentsToPass(args));
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
exports.LoggerImpl = LoggerImpl;
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
36
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
37
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
38
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
39
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
40
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
41
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
42
|
+
});
|
|
43
|
+
};
|
|
44
|
+
var __asyncValues = (this && this.__asyncValues) || function (o) {
|
|
45
|
+
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
|
|
46
|
+
var m = o[Symbol.asyncIterator], i;
|
|
47
|
+
return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
|
|
48
|
+
function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
|
|
49
|
+
function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
|
|
50
|
+
};
|
|
51
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
52
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
53
|
+
};
|
|
54
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
55
|
+
exports.TypescriptMockServerImpl = void 0;
|
|
56
|
+
const express_1 = __importDefault(require("express"));
|
|
57
|
+
const cors_1 = __importDefault(require("cors"));
|
|
58
|
+
const command_line_impl_1 = require("./command-line-impl");
|
|
59
|
+
const command_line_1 = require("../command-line");
|
|
60
|
+
const promises_1 = require("fs/promises");
|
|
61
|
+
const logger_impl_1 = require("./logger-impl");
|
|
62
|
+
const path_1 = __importDefault(require("path"));
|
|
63
|
+
class TypescriptMockServerImpl {
|
|
64
|
+
constructor(config) {
|
|
65
|
+
this.log = new logger_impl_1.LoggerImpl();
|
|
66
|
+
this.commandLine = new command_line_impl_1.CommandLineImpl();
|
|
67
|
+
this.registeredEndpoints = [];
|
|
68
|
+
if (config && 'use' in config) {
|
|
69
|
+
this.app = config;
|
|
70
|
+
this.basePath = this.getPath();
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
const serverConfig = config;
|
|
74
|
+
this.app = (serverConfig === null || serverConfig === void 0 ? void 0 : serverConfig.app) || (0, express_1.default)();
|
|
75
|
+
this.basePath = this.getPath(serverConfig === null || serverConfig === void 0 ? void 0 : serverConfig.path);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
static loadModule(moduleName) {
|
|
79
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
80
|
+
return yield Promise.resolve(`${moduleName}`).then(s => __importStar(require(s)));
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
start() {
|
|
84
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
85
|
+
this.log.info(`basePath: ${this.basePath}`);
|
|
86
|
+
const port = this.commandLine.getCommand(command_line_1.Command.PORT) || 3000;
|
|
87
|
+
const corsSetting = {
|
|
88
|
+
origin: this.commandLine.getCommand(command_line_1.Command.CORS) || '*'
|
|
89
|
+
};
|
|
90
|
+
this.app.use((0, cors_1.default)(corsSetting));
|
|
91
|
+
// add started endpoint
|
|
92
|
+
this.addEndpoint('state', 'get', { data: { status: 'started' } });
|
|
93
|
+
yield this.readRoutes(this.basePath).catch(error => this.log.error(error));
|
|
94
|
+
this.app.listen(port, () => {
|
|
95
|
+
this.log.info(`App is listening on port ${port}!`);
|
|
96
|
+
});
|
|
97
|
+
this.log.info(`Started mock server on port ${port}`);
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
readRoutes(dirPath) {
|
|
101
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
102
|
+
var _a, e_1, _b, _c;
|
|
103
|
+
const dir = yield (0, promises_1.opendir)(dirPath);
|
|
104
|
+
try {
|
|
105
|
+
for (var _d = true, dir_1 = __asyncValues(dir), dir_1_1; dir_1_1 = yield dir_1.next(), _a = dir_1_1.done, !_a; _d = true) {
|
|
106
|
+
_c = dir_1_1.value;
|
|
107
|
+
_d = false;
|
|
108
|
+
const dirent = _c;
|
|
109
|
+
if (dirent.isDirectory()) {
|
|
110
|
+
yield this.readRoutes(`${dirPath}/${dirent.name}`);
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
yield this.handleFile(dirPath, dirent);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
118
|
+
finally {
|
|
119
|
+
try {
|
|
120
|
+
if (!_d && !_a && (_b = dir_1.return)) yield _b.call(dir_1);
|
|
121
|
+
}
|
|
122
|
+
finally { if (e_1) throw e_1.error; }
|
|
123
|
+
}
|
|
124
|
+
const port = this.commandLine.getCommand(command_line_1.Command.PORT) || 3000;
|
|
125
|
+
this.registeredEndpoints.forEach(endpoint => this.log.info(`${endpoint.httpVerb.toUpperCase()} http://localhost:${port}${endpoint.endpoint}`));
|
|
126
|
+
this.registeredEndpoints = [];
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
handleFile(dirPath, dirent) {
|
|
130
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
131
|
+
const httpVerb = (dirent.name.indexOf('-') > -1 ? dirent.name.split('-')[0] : dirent.name.split('.')[0]);
|
|
132
|
+
yield this.handleRequest(dirPath, dirent, httpVerb);
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
addEndpoint(endpoint, httpVerb, model) {
|
|
136
|
+
const route = endpoint.startsWith('/') ? endpoint : `/${endpoint}`;
|
|
137
|
+
this.app[httpVerb](route, (req, res) => {
|
|
138
|
+
var _a, _b;
|
|
139
|
+
let responseData = model.data;
|
|
140
|
+
let statusCode = (_a = model === null || model === void 0 ? void 0 : model.config) === null || _a === void 0 ? void 0 : _a.statusCode;
|
|
141
|
+
let delay = (_b = model === null || model === void 0 ? void 0 : model.config) === null || _b === void 0 ? void 0 : _b.delay;
|
|
142
|
+
if (typeof model.data === 'function') {
|
|
143
|
+
responseData = model.data(req, res);
|
|
144
|
+
}
|
|
145
|
+
if (statusCode) {
|
|
146
|
+
res.statusCode = statusCode;
|
|
147
|
+
}
|
|
148
|
+
if (delay) {
|
|
149
|
+
setTimeout(() => res.send(responseData), this.getDelayValue(delay));
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
return res.send(responseData);
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
getDelayValue(delay) {
|
|
157
|
+
if (typeof delay === 'number') {
|
|
158
|
+
return delay;
|
|
159
|
+
}
|
|
160
|
+
else if (delay.min && delay.max) {
|
|
161
|
+
return Math.floor(delay.min + Math.random() * delay.max);
|
|
162
|
+
}
|
|
163
|
+
return 0;
|
|
164
|
+
}
|
|
165
|
+
handleRequest(dirPath, dirent, httpVerb) {
|
|
166
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
167
|
+
const endpoint = this.convertFileNameToEndpoint(dirPath, dirent, httpVerb);
|
|
168
|
+
let modulePath = `${dirPath}/${dirent.name}`;
|
|
169
|
+
this.registeredEndpoints.push({ httpVerb, endpoint });
|
|
170
|
+
if (__filename.endsWith('.js')) {
|
|
171
|
+
const distPath = path_1.default.join(process.cwd(), 'dist');
|
|
172
|
+
if (modulePath.startsWith(process.cwd()) && !modulePath.startsWith(distPath)) {
|
|
173
|
+
modulePath = modulePath.replace(process.cwd(), distPath);
|
|
174
|
+
}
|
|
175
|
+
if (modulePath.endsWith('.ts')) {
|
|
176
|
+
modulePath = modulePath.replace(/\.ts$/, '.js');
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
yield TypescriptMockServerImpl.loadModule(modulePath)
|
|
180
|
+
.then(model => this.addEndpoint(endpoint, httpVerb, model))
|
|
181
|
+
.catch(error => this.log.error(error));
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
convertFileNameToEndpoint(dirPath, dirent, httpVerb) {
|
|
185
|
+
const endpoint = `${dirPath.replace(this.basePath, '')}/${dirent.name}`
|
|
186
|
+
.replace('.ts', '')
|
|
187
|
+
.replace(`${httpVerb}-`, '')
|
|
188
|
+
.replace(httpVerb, '');
|
|
189
|
+
if (endpoint.endsWith('/')) {
|
|
190
|
+
return endpoint.substring(0, endpoint.length - 1);
|
|
191
|
+
}
|
|
192
|
+
return endpoint;
|
|
193
|
+
}
|
|
194
|
+
getPath(defaultPath = 'tms-models') {
|
|
195
|
+
let definedPath = defaultPath;
|
|
196
|
+
if (!this.commandLine.getCommands().has(command_line_1.Command.PATH)) {
|
|
197
|
+
this.log.warn(`Path parameter not set, fallback to default ${defaultPath}`);
|
|
198
|
+
}
|
|
199
|
+
else {
|
|
200
|
+
definedPath = this.commandLine.getCommand(command_line_1.Command.PATH);
|
|
201
|
+
}
|
|
202
|
+
if (path_1.default.isAbsolute(definedPath)) {
|
|
203
|
+
return definedPath;
|
|
204
|
+
}
|
|
205
|
+
return path_1.default.join(process.cwd(), definedPath);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
exports.TypescriptMockServerImpl = TypescriptMockServerImpl;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
const typescript_mock_server_impl_1 = require("./impl/typescript-mock-server-impl");
|
|
5
|
+
const server = new typescript_mock_server_impl_1.TypescriptMockServerImpl();
|
|
6
|
+
server.start().then(() => console.log('Server started')).catch(console.error);
|