counterfact 0.25.3 → 0.25.4
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/.eslintrc.cjs +71 -63
- package/CHANGELOG.md +6 -0
- package/bin/counterfact.js +10 -9
- package/package.json +4 -4
- package/src/server/counterfact.js +8 -9
- package/src/server/dispatcher.js +34 -33
- package/src/server/koa-middleware.js +5 -5
- package/src/server/module-loader.js +21 -16
- package/src/server/registry.js +17 -6
- package/src/server/repl.js +10 -10
- package/src/server/response-builder.js +21 -21
- package/src/server/start.js +22 -15
- package/src/server/transpiler.js +6 -6
- package/src/typescript-generator/generate.js +2 -2
- package/src/typescript-generator/operation-coder.js +1 -1
- package/src/typescript-generator/operation-type-coder.js +9 -9
- package/src/typescript-generator/parameters-type-coder.js +1 -1
- package/src/typescript-generator/repository.js +8 -11
- package/src/typescript-generator/requirement.js +2 -2
- package/src/typescript-generator/response-type-coder.js +7 -7
- package/src/typescript-generator/schema-coder.js +2 -2
- package/src/typescript-generator/schema-type-coder.js +8 -8
- package/src/typescript-generator/script.js +18 -18
- package/src/typescript-generator/specification.js +1 -2
- package/src/util/read-file.js +1 -1
- package/templates/response-builder-factory.ts +12 -12
- package/test/lib/with-temporary-files.js +4 -3
- package/test/server/counterfact.test.js +5 -4
- package/test/server/dispatcher.proxy.test.js +2 -2
- package/test/server/dispatcher.test.js +77 -69
- package/test/server/koa-middleware.test.js +29 -26
- package/test/server/module-loader.test.js +14 -14
- package/test/server/registry.test.js +3 -3
- package/test/server/response-builder.test.js +31 -31
- package/test/server/tools.test.js +5 -5
- package/test/server/transpiler.test.js +7 -7
- package/test/typescript-generator/coder.test.js +3 -3
- package/test/typescript-generator/context-coder.test.js +8 -7
- package/test/typescript-generator/integration.test.js +6 -6
- package/test/typescript-generator/operation-coder.test.js +25 -26
- package/test/typescript-generator/operation-type-coder.test.js +52 -52
- package/test/typescript-generator/parameters-type-coder.test.js +34 -33
- package/test/typescript-generator/requirement.test.js +7 -7
- package/test/typescript-generator/response-type-coder.test.js +4 -4
- package/test/typescript-generator/schema-coder.test.js +26 -22
- package/test/typescript-generator/schema-type-coder.test.js +111 -85
- package/test/typescript-generator/script.test.js +6 -6
- package/test/typescript-generator/specification.test.js +17 -17
package/.eslintrc.cjs
CHANGED
|
@@ -1,20 +1,35 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
const rules = {
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
"import/prefer-default-export": "off",
|
|
4
|
+
"@microsoft/sdl/no-html-method": "off",
|
|
5
|
+
"@typescript-eslint/lines-around-comment": "off",
|
|
7
6
|
"@typescript-eslint/naming-convention": "off",
|
|
7
|
+
"import/default": "off",
|
|
8
|
+
|
|
9
|
+
"import/namespace": "off",
|
|
10
|
+
|
|
11
|
+
// too slow
|
|
12
|
+
"import/no-cycle": "off",
|
|
13
|
+
|
|
14
|
+
"import/no-deprecated": "off",
|
|
15
|
+
"import/no-named-as-default": "off",
|
|
16
|
+
"import/no-named-as-default-member": "off",
|
|
17
|
+
|
|
18
|
+
"import/no-unused-modules": "off",
|
|
19
|
+
|
|
20
|
+
"import/prefer-default-export": "off",
|
|
8
21
|
|
|
9
22
|
"max-len": [
|
|
10
23
|
"warn",
|
|
11
24
|
{
|
|
25
|
+
code: 120,
|
|
12
26
|
ignorePattern: "eslint|it\\(|describe\\(",
|
|
13
27
|
ignoreTemplateLiterals: true,
|
|
14
|
-
code: 120,
|
|
15
28
|
},
|
|
16
29
|
],
|
|
17
30
|
|
|
31
|
+
"n/shebang": "off",
|
|
32
|
+
|
|
18
33
|
"no-magic-numbers": [
|
|
19
34
|
"error",
|
|
20
35
|
{
|
|
@@ -22,8 +37,8 @@ const rules = {
|
|
|
22
37
|
},
|
|
23
38
|
],
|
|
24
39
|
|
|
25
|
-
"node/no-callback-literal": "off",
|
|
26
40
|
"node/file-extension-in-import": "off",
|
|
41
|
+
"node/no-callback-literal": "off",
|
|
27
42
|
"node/no-missing-import": "off",
|
|
28
43
|
|
|
29
44
|
"prettier/prettier": [
|
|
@@ -33,19 +48,17 @@ const rules = {
|
|
|
33
48
|
},
|
|
34
49
|
],
|
|
35
50
|
|
|
36
|
-
|
|
37
|
-
"import/no-cycle": "off",
|
|
38
|
-
"import/no-unused-modules": "off",
|
|
39
|
-
"import/namespace": "off",
|
|
40
|
-
"import/no-named-as-default": "off",
|
|
41
|
-
"import/no-deprecated": "off",
|
|
42
|
-
"import/default": "off",
|
|
43
|
-
"import/no-named-as-default-member": "off",
|
|
44
|
-
"@microsoft/sdl/no-html-method": "off",
|
|
45
|
-
"@typescript-eslint/lines-around-comment": "off",
|
|
51
|
+
"putout/putout": "off",
|
|
46
52
|
};
|
|
47
53
|
|
|
48
54
|
module.exports = {
|
|
55
|
+
env: {
|
|
56
|
+
es2021: true,
|
|
57
|
+
node: true,
|
|
58
|
+
},
|
|
59
|
+
|
|
60
|
+
extends: ["hardcore", "hardcore/ts", "hardcore/node"],
|
|
61
|
+
|
|
49
62
|
ignorePatterns: [
|
|
50
63
|
"/node_modules/",
|
|
51
64
|
"/coverage/",
|
|
@@ -55,112 +68,101 @@ module.exports = {
|
|
|
55
68
|
".stryker-tmp",
|
|
56
69
|
],
|
|
57
70
|
|
|
58
|
-
extends: ["hardcore", "hardcore/ts", "hardcore/node"],
|
|
59
|
-
|
|
60
|
-
parserOptions: {
|
|
61
|
-
sourceType: "module",
|
|
62
|
-
},
|
|
63
|
-
|
|
64
|
-
env: {
|
|
65
|
-
es2021: true,
|
|
66
|
-
node: true,
|
|
67
|
-
},
|
|
68
|
-
|
|
69
|
-
rules,
|
|
70
|
-
|
|
71
71
|
overrides: [
|
|
72
72
|
{
|
|
73
|
-
files: ["*.cjs"],
|
|
74
73
|
extends: ["hardcore", "hardcore/node"],
|
|
75
|
-
|
|
76
|
-
rules: {
|
|
77
|
-
"import/no-commonjs": "off",
|
|
78
|
-
},
|
|
74
|
+
files: ["*.cjs"],
|
|
79
75
|
|
|
80
76
|
parserOptions: {
|
|
81
77
|
sourceType: "script",
|
|
82
78
|
},
|
|
79
|
+
|
|
80
|
+
rules: {
|
|
81
|
+
"import/no-commonjs": "off",
|
|
82
|
+
},
|
|
83
83
|
},
|
|
84
84
|
|
|
85
85
|
{
|
|
86
|
-
files: ["*.test.js"],
|
|
87
|
-
|
|
88
86
|
extends: ["hardcore", "hardcore/ts", "hardcore/node", "hardcore/jest"],
|
|
89
87
|
|
|
88
|
+
files: ["*.test.js"],
|
|
89
|
+
|
|
90
90
|
rules: {
|
|
91
91
|
...rules,
|
|
92
|
+
"@typescript-eslint/naming-convention": "off",
|
|
93
|
+
"id-length": ["off"],
|
|
94
|
+
|
|
92
95
|
"import/unambiguous": "off",
|
|
96
|
+
|
|
93
97
|
"jest/prefer-expect-assertions": "off",
|
|
94
98
|
|
|
99
|
+
"jest/unbound-method": "off",
|
|
100
|
+
|
|
101
|
+
"max-lines": "off",
|
|
102
|
+
|
|
95
103
|
"new-cap": [
|
|
96
104
|
"error",
|
|
97
105
|
{ capIsNewExceptionPattern: "GET|PUT|POST|DELETE" },
|
|
98
106
|
],
|
|
99
107
|
|
|
100
|
-
"@typescript-eslint/naming-convention": "off",
|
|
101
|
-
|
|
102
|
-
"node/no-unpublished-import": "off",
|
|
103
|
-
|
|
104
108
|
"no-magic-numbers": ["off"],
|
|
105
|
-
"
|
|
106
|
-
"max-lines": "off",
|
|
107
|
-
"jest/unbound-method": "off",
|
|
109
|
+
"node/no-unpublished-import": "off",
|
|
108
110
|
},
|
|
109
111
|
},
|
|
110
112
|
|
|
111
113
|
{
|
|
112
|
-
files: ["demo/**/*.js"],
|
|
113
114
|
extends: ["hardcore", "hardcore/node"],
|
|
115
|
+
files: ["demo/**/*.js"],
|
|
114
116
|
|
|
115
117
|
rules: {
|
|
116
118
|
...rules,
|
|
117
119
|
"import/no-extraneous-dependencies": "off",
|
|
118
120
|
"import/no-unused-modules": "off",
|
|
119
121
|
"import/prefer-default-export": "off",
|
|
120
|
-
"no-param-reassign": "off",
|
|
121
122
|
"no-console": "off",
|
|
123
|
+
"no-param-reassign": "off",
|
|
122
124
|
"node/no-unpublished-import": "off",
|
|
123
125
|
},
|
|
124
126
|
},
|
|
125
127
|
|
|
126
128
|
{
|
|
127
|
-
files: ["*.cjs"],
|
|
128
129
|
extends: ["hardcore", "hardcore/node"],
|
|
130
|
+
files: ["*.cjs"],
|
|
131
|
+
|
|
132
|
+
parserOptions: {
|
|
133
|
+
sourceType: "script",
|
|
134
|
+
},
|
|
129
135
|
|
|
130
136
|
rules: {
|
|
131
137
|
...rules,
|
|
132
138
|
"import/no-commonjs": "off",
|
|
133
139
|
},
|
|
134
|
-
|
|
135
|
-
parserOptions: {
|
|
136
|
-
sourceType: "script",
|
|
137
|
-
},
|
|
138
140
|
},
|
|
139
141
|
|
|
140
142
|
{
|
|
141
|
-
files: ["**/*.ts"],
|
|
142
143
|
extends: ["hardcore", "hardcore/node", "hardcore/ts"],
|
|
144
|
+
files: ["**/*.ts"],
|
|
143
145
|
|
|
144
146
|
parserOptions: {
|
|
145
|
-
sourceType: "module",
|
|
146
147
|
project: "./tsconfig.json",
|
|
148
|
+
sourceType: "module",
|
|
147
149
|
},
|
|
148
150
|
|
|
149
151
|
rules: {
|
|
150
152
|
...rules,
|
|
151
|
-
"import/prefer-default-export": "off",
|
|
152
|
-
"import/no-unused-modules": "off",
|
|
153
|
-
"func-style": "off",
|
|
154
|
-
camelcase: "off",
|
|
155
153
|
"@typescript-eslint/naming-convention": "off",
|
|
156
|
-
"no-magic-numbers": "off",
|
|
157
|
-
"no-param-reassign": "off",
|
|
158
|
-
"import/group-exports": "off",
|
|
159
|
-
"max-len": "off",
|
|
160
|
-
"etc/prefer-interface": "off",
|
|
154
|
+
"@typescript-eslint/no-magic-numbers": "off",
|
|
161
155
|
"@typescript-eslint/prefer-readonly-parameter-types": "off",
|
|
156
|
+
camelcase: "off",
|
|
162
157
|
"eslint-comments/no-unused-disable": "off",
|
|
163
|
-
"
|
|
158
|
+
"etc/prefer-interface": "off",
|
|
159
|
+
"func-style": "off",
|
|
160
|
+
"import/group-exports": "off",
|
|
161
|
+
"import/no-unused-modules": "off",
|
|
162
|
+
"import/prefer-default-export": "off",
|
|
163
|
+
"max-len": "off",
|
|
164
|
+
"no-magic-numbers": "off",
|
|
165
|
+
"no-param-reassign": "off",
|
|
164
166
|
},
|
|
165
167
|
|
|
166
168
|
settings: {
|
|
@@ -178,8 +180,6 @@ module.exports = {
|
|
|
178
180
|
},
|
|
179
181
|
|
|
180
182
|
{
|
|
181
|
-
files: ["templates/**/*.ts"],
|
|
182
|
-
|
|
183
183
|
env: {
|
|
184
184
|
es2021: true,
|
|
185
185
|
node: true,
|
|
@@ -187,6 +187,8 @@ module.exports = {
|
|
|
187
187
|
|
|
188
188
|
extends: ["eslint:recommended", "plugin:@typescript-eslint/recommended"],
|
|
189
189
|
|
|
190
|
+
files: ["templates/**/*.ts"],
|
|
191
|
+
|
|
190
192
|
parserOptions: {
|
|
191
193
|
ecmaVersion: "latest",
|
|
192
194
|
sourceType: "module",
|
|
@@ -195,4 +197,10 @@ module.exports = {
|
|
|
195
197
|
rules: {},
|
|
196
198
|
},
|
|
197
199
|
],
|
|
200
|
+
|
|
201
|
+
parserOptions: {
|
|
202
|
+
sourceType: "module",
|
|
203
|
+
},
|
|
204
|
+
|
|
205
|
+
rules,
|
|
198
206
|
};
|
package/CHANGELOG.md
CHANGED
package/bin/counterfact.js
CHANGED
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
import nodePath from "node:path";
|
|
4
4
|
|
|
5
|
-
import createDebug from "debug";
|
|
6
5
|
import { program } from "commander";
|
|
6
|
+
import createDebug from "debug";
|
|
7
7
|
import open from "open";
|
|
8
8
|
|
|
9
|
-
import { generate } from "../src/typescript-generator/generate.js";
|
|
10
|
-
import { start } from "../src/server/start.js";
|
|
11
9
|
import { startRepl } from "../src/server/repl.js";
|
|
10
|
+
import { start } from "../src/server/start.js";
|
|
11
|
+
import { generate } from "../src/typescript-generator/generate.js";
|
|
12
12
|
|
|
13
13
|
const DEFAULT_PORT = 3100;
|
|
14
14
|
|
|
@@ -36,7 +36,7 @@ async function main(source, destination) {
|
|
|
36
36
|
|
|
37
37
|
debug("generated code", destinationPath);
|
|
38
38
|
|
|
39
|
-
const basePath = nodePath.resolve(destinationPath);
|
|
39
|
+
const basePath = nodePath.resolve(destinationPath).replaceAll("\\", "/");
|
|
40
40
|
|
|
41
41
|
const openBrowser = options.open;
|
|
42
42
|
|
|
@@ -46,11 +46,11 @@ async function main(source, destination) {
|
|
|
46
46
|
|
|
47
47
|
const config = {
|
|
48
48
|
basePath,
|
|
49
|
-
port: options.port,
|
|
50
|
-
openApiPath: source,
|
|
51
49
|
includeSwaggerUi: true,
|
|
52
|
-
|
|
50
|
+
openApiPath: source,
|
|
51
|
+
port: options.port,
|
|
53
52
|
proxyEnabled: Boolean(options.proxyUrl),
|
|
53
|
+
proxyUrl: options.proxyUrl,
|
|
54
54
|
};
|
|
55
55
|
|
|
56
56
|
debug("starting server (%o)", config);
|
|
@@ -80,7 +80,7 @@ async function main(source, destination) {
|
|
|
80
80
|
process.stdout.write(`${introduction.join("\n")}\n`);
|
|
81
81
|
|
|
82
82
|
process.stdout.write(
|
|
83
|
-
waysToInteract.map((text, index) => `${index + 1}. ${text}`).join("\n")
|
|
83
|
+
waysToInteract.map((text, index) => `${index + 1}. ${text}`).join("\n"),
|
|
84
84
|
);
|
|
85
85
|
|
|
86
86
|
process.stdout.write("\n\n");
|
|
@@ -103,7 +103,7 @@ async function main(source, destination) {
|
|
|
103
103
|
program
|
|
104
104
|
.name("counterfact")
|
|
105
105
|
.description(
|
|
106
|
-
"Counterfact is a tool for generating a REST API from an OpenAPI document."
|
|
106
|
+
"Counterfact is a tool for generating a REST API from an OpenAPI document.",
|
|
107
107
|
)
|
|
108
108
|
.argument("<openapi.yaml>", "path or URL to OpenAPI document")
|
|
109
109
|
.argument("[destination]", "path to generated code", ".")
|
|
@@ -112,4 +112,5 @@ program
|
|
|
112
112
|
.option("--open", "open a browser")
|
|
113
113
|
.option("--proxy-url <string>", "proxy URL")
|
|
114
114
|
.action(main)
|
|
115
|
+
// eslint-disable-next-line sonar/process-argv
|
|
115
116
|
.parse(process.argv);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "counterfact",
|
|
3
|
-
"version": "0.25.
|
|
3
|
+
"version": "0.25.4",
|
|
4
4
|
"description": "a library for building a fake REST API for testing",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/server/counterfact.js",
|
|
@@ -42,8 +42,8 @@
|
|
|
42
42
|
"@testing-library/dom": "^9.3.0",
|
|
43
43
|
"@types/koa": "2.13.8",
|
|
44
44
|
"@types/koa-static": "^4.0.2",
|
|
45
|
-
"eslint": "8.
|
|
46
|
-
"eslint-config-hardcore": "
|
|
45
|
+
"eslint": "8.48.0",
|
|
46
|
+
"eslint-config-hardcore": "41.2.0",
|
|
47
47
|
"eslint-formatter-github-annotations": "0.1.0",
|
|
48
48
|
"eslint-import-resolver-typescript": "^3.2.5",
|
|
49
49
|
"eslint-plugin-etc": "^2.0.2",
|
|
@@ -79,7 +79,7 @@
|
|
|
79
79
|
"koa2-swagger-ui": "^5.6.0",
|
|
80
80
|
"node-fetch": "^3.2.10",
|
|
81
81
|
"open": "^9.0.0",
|
|
82
|
-
"prettier": "^
|
|
82
|
+
"prettier": "^3.0.0",
|
|
83
83
|
"typescript": "^5.0.0"
|
|
84
84
|
}
|
|
85
85
|
}
|
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
import nodePath from "node:path";
|
|
2
2
|
|
|
3
|
-
import $RefParser from "json-schema-ref-parser";
|
|
4
3
|
import yaml from "js-yaml";
|
|
4
|
+
import $RefParser from "json-schema-ref-parser";
|
|
5
5
|
|
|
6
6
|
import { readFile } from "../util/read-file.js";
|
|
7
|
-
|
|
8
|
-
import { Registry } from "./registry.js";
|
|
7
|
+
import { ContextRegistry } from "./context-registry.js";
|
|
9
8
|
import { Dispatcher } from "./dispatcher.js";
|
|
10
9
|
import { koaMiddleware } from "./koa-middleware.js";
|
|
11
10
|
import { ModuleLoader } from "./module-loader.js";
|
|
12
|
-
import {
|
|
11
|
+
import { Registry } from "./registry.js";
|
|
13
12
|
import { Transpiler } from "./transpiler.js";
|
|
14
13
|
|
|
15
14
|
async function loadOpenApiDocument(source) {
|
|
@@ -26,7 +25,7 @@ export async function counterfact(
|
|
|
26
25
|
openApiPath = nodePath
|
|
27
26
|
.join(basePath, "../openapi.yaml")
|
|
28
27
|
.replaceAll("\\", "/"),
|
|
29
|
-
options = {}
|
|
28
|
+
options = {},
|
|
30
29
|
) {
|
|
31
30
|
const openApiDocument = await loadOpenApiDocument(openApiPath);
|
|
32
31
|
|
|
@@ -44,7 +43,7 @@ export async function counterfact(
|
|
|
44
43
|
|
|
45
44
|
const transpiler = new Transpiler(
|
|
46
45
|
nodePath.join(modulesPath, "paths").replaceAll("\\", "/"),
|
|
47
|
-
compiledPathsDirectory
|
|
46
|
+
compiledPathsDirectory,
|
|
48
47
|
);
|
|
49
48
|
|
|
50
49
|
await transpiler.watch();
|
|
@@ -52,7 +51,7 @@ export async function counterfact(
|
|
|
52
51
|
const moduleLoader = new ModuleLoader(
|
|
53
52
|
compiledPathsDirectory,
|
|
54
53
|
registry,
|
|
55
|
-
contextRegistry
|
|
54
|
+
contextRegistry,
|
|
56
55
|
);
|
|
57
56
|
|
|
58
57
|
await moduleLoader.load();
|
|
@@ -60,9 +59,9 @@ export async function counterfact(
|
|
|
60
59
|
await moduleLoader.watch();
|
|
61
60
|
|
|
62
61
|
return {
|
|
62
|
+
contextRegistry,
|
|
63
63
|
koaMiddleware: koaMiddleware(dispatcher, options),
|
|
64
|
-
registry,
|
|
65
64
|
moduleLoader,
|
|
66
|
-
|
|
65
|
+
registry,
|
|
67
66
|
};
|
|
68
67
|
}
|
package/src/server/dispatcher.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
// eslint-disable-next-line import/
|
|
1
|
+
// eslint-disable-next-line import/newline-after-import
|
|
2
2
|
import Accept from "@hapi/accept";
|
|
3
|
-
|
|
4
3
|
// eslint-disable-next-line no-shadow
|
|
5
4
|
import fetch, { Headers } from "node-fetch";
|
|
6
5
|
|
|
@@ -13,12 +12,12 @@ function parameterTypes(parameters) {
|
|
|
13
12
|
}
|
|
14
13
|
|
|
15
14
|
const types = {
|
|
16
|
-
|
|
17
|
-
query: {},
|
|
18
|
-
header: {},
|
|
15
|
+
body: {},
|
|
19
16
|
cookie: {},
|
|
20
17
|
formData: {},
|
|
21
|
-
|
|
18
|
+
header: {},
|
|
19
|
+
path: {},
|
|
20
|
+
query: {},
|
|
22
21
|
};
|
|
23
22
|
|
|
24
23
|
for (const parameter of parameters) {
|
|
@@ -57,27 +56,18 @@ export class Dispatcher {
|
|
|
57
56
|
return operation;
|
|
58
57
|
}
|
|
59
58
|
|
|
60
|
-
async request({
|
|
59
|
+
async request({ body, headers, method, path, query, req }) {
|
|
61
60
|
const { matchedPath } = this.registry.handler(path);
|
|
62
61
|
const operation = this.operationForPathAndMethod(matchedPath, method);
|
|
63
62
|
|
|
64
63
|
const response = await this.registry.endpoint(
|
|
65
64
|
method,
|
|
66
65
|
path,
|
|
67
|
-
parameterTypes(operation?.parameters)
|
|
66
|
+
parameterTypes(operation?.parameters),
|
|
68
67
|
)({
|
|
69
|
-
tools: new Tools({ headers }),
|
|
70
68
|
body,
|
|
71
|
-
query,
|
|
72
|
-
headers,
|
|
73
69
|
context: this.contextRegistry.find(path),
|
|
74
|
-
|
|
75
|
-
response: createResponseBuilder(
|
|
76
|
-
this.operationForPathAndMethod(
|
|
77
|
-
this.registry.handler(path).matchedPath,
|
|
78
|
-
method
|
|
79
|
-
)
|
|
80
|
-
),
|
|
70
|
+
headers,
|
|
81
71
|
|
|
82
72
|
proxy: async (url) => {
|
|
83
73
|
if (
|
|
@@ -86,40 +76,51 @@ export class Dispatcher {
|
|
|
86
76
|
headers.contentType !== "application/json"
|
|
87
77
|
) {
|
|
88
78
|
throw new Error(
|
|
89
|
-
`$.proxy() is currently limited to application/json requests. You tried to proxy to ${url} with a Content-Type of ${headers.contentType}. Please open an issue at https://github.com/pmcelhaney/counterfact/issues and prod me to fix this limitation
|
|
79
|
+
`$.proxy() is currently limited to application/json requests. You tried to proxy to ${url} with a Content-Type of ${headers.contentType}. Please open an issue at https://github.com/pmcelhaney/counterfact/issues and prod me to fix this limitation.`,
|
|
90
80
|
);
|
|
91
81
|
}
|
|
92
82
|
|
|
93
83
|
const fetchResponse = await this.fetch(url + req.path, {
|
|
94
|
-
method,
|
|
95
|
-
headers: new Headers(headers),
|
|
96
84
|
body: body ? JSON.stringify(body) : undefined,
|
|
85
|
+
headers: new Headers(headers),
|
|
86
|
+
method,
|
|
97
87
|
});
|
|
98
88
|
|
|
99
89
|
const responseHeaders = Object.fromEntries(
|
|
100
|
-
fetchResponse.headers.entries()
|
|
90
|
+
fetchResponse.headers.entries(),
|
|
101
91
|
);
|
|
102
92
|
|
|
103
93
|
return {
|
|
104
|
-
|
|
94
|
+
body: await fetchResponse.text(),
|
|
105
95
|
contentType: responseHeaders["content-type"] ?? "unknown/unknown",
|
|
106
96
|
headers: responseHeaders,
|
|
107
|
-
|
|
97
|
+
status: fetchResponse.status,
|
|
108
98
|
};
|
|
109
99
|
},
|
|
100
|
+
|
|
101
|
+
query,
|
|
102
|
+
|
|
103
|
+
response: createResponseBuilder(
|
|
104
|
+
this.operationForPathAndMethod(
|
|
105
|
+
this.registry.handler(path).matchedPath,
|
|
106
|
+
method,
|
|
107
|
+
),
|
|
108
|
+
),
|
|
109
|
+
|
|
110
|
+
tools: new Tools({ headers }),
|
|
110
111
|
});
|
|
111
112
|
|
|
112
113
|
const normalizedResponse = this.normalizeResponse(
|
|
113
114
|
response,
|
|
114
|
-
headers?.accept ?? "*/*"
|
|
115
|
+
headers?.accept ?? "*/*",
|
|
115
116
|
);
|
|
116
117
|
|
|
117
118
|
if (
|
|
118
119
|
!Accept.mediaTypes(headers?.accept ?? "*/*").some((type) =>
|
|
119
|
-
this.isMediaType(normalizedResponse.contentType, type)
|
|
120
|
+
this.isMediaType(normalizedResponse.contentType, type),
|
|
120
121
|
)
|
|
121
122
|
) {
|
|
122
|
-
return {
|
|
123
|
+
return { body: Accept.mediaTypes(headers?.accept ?? "*/*"), status: 406 };
|
|
123
124
|
}
|
|
124
125
|
|
|
125
126
|
return normalizedResponse;
|
|
@@ -128,10 +129,10 @@ export class Dispatcher {
|
|
|
128
129
|
normalizeResponse(response, acceptHeader) {
|
|
129
130
|
if (typeof response === "string") {
|
|
130
131
|
return {
|
|
131
|
-
status: 200,
|
|
132
|
-
headers: {},
|
|
133
|
-
contentType: "text/plain",
|
|
134
132
|
body: response,
|
|
133
|
+
contentType: "text/plain",
|
|
134
|
+
headers: {},
|
|
135
|
+
status: 200,
|
|
135
136
|
};
|
|
136
137
|
}
|
|
137
138
|
|
|
@@ -146,8 +147,8 @@ export class Dispatcher {
|
|
|
146
147
|
|
|
147
148
|
const normalizedResponse = {
|
|
148
149
|
...response,
|
|
149
|
-
contentType: content.type,
|
|
150
150
|
body: content.body,
|
|
151
|
+
contentType: content.type,
|
|
151
152
|
};
|
|
152
153
|
|
|
153
154
|
delete normalizedResponse.content;
|
|
@@ -163,7 +164,7 @@ export class Dispatcher {
|
|
|
163
164
|
|
|
164
165
|
for (const mediaType of preferredMediaTypes) {
|
|
165
166
|
const contentItem = content.find((item) =>
|
|
166
|
-
this.isMediaType(item.type, mediaType)
|
|
167
|
+
this.isMediaType(item.type, mediaType),
|
|
167
168
|
);
|
|
168
169
|
|
|
169
170
|
if (contentItem) {
|
|
@@ -172,8 +173,8 @@ export class Dispatcher {
|
|
|
172
173
|
}
|
|
173
174
|
|
|
174
175
|
return {
|
|
175
|
-
type: preferredMediaTypes,
|
|
176
176
|
body: "no match",
|
|
177
|
+
type: preferredMediaTypes,
|
|
177
178
|
};
|
|
178
179
|
}
|
|
179
180
|
|
|
@@ -8,18 +8,18 @@ function addCors(ctx, headers) {
|
|
|
8
8
|
ctx.set("Access-Control-Allow-Methods", "GET,HEAD,PUT,POST,DELETE,PATCH");
|
|
9
9
|
ctx.set(
|
|
10
10
|
"Access-Control-Allow-Headers",
|
|
11
|
-
headers?.["access-control-request-headers"]
|
|
11
|
+
headers?.["access-control-request-headers"],
|
|
12
12
|
);
|
|
13
13
|
ctx.set(
|
|
14
14
|
"Access-Control-Expose-Headers",
|
|
15
|
-
headers?.["access-control-request-headers"]
|
|
15
|
+
headers?.["access-control-request-headers"],
|
|
16
16
|
);
|
|
17
17
|
ctx.set("Access-Control-Allow-Credentials", "true");
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
export function koaMiddleware(dispatcher, options = {}, proxy = koaProxy) {
|
|
21
21
|
return async function middleware(ctx, next) {
|
|
22
|
-
const {
|
|
22
|
+
const { body, headers, method, path, query } = ctx.request;
|
|
23
23
|
|
|
24
24
|
if (options.proxyEnabled && options.proxyUrl) {
|
|
25
25
|
return proxy({ host: options.proxyUrl })(ctx, next);
|
|
@@ -32,10 +32,10 @@ export function koaMiddleware(dispatcher, options = {}, proxy = koaProxy) {
|
|
|
32
32
|
ctx.status = HTTP_STATUS_CODE_OK;
|
|
33
33
|
} else {
|
|
34
34
|
const response = await dispatcher.request({
|
|
35
|
+
body,
|
|
36
|
+
headers,
|
|
35
37
|
method,
|
|
36
38
|
path,
|
|
37
|
-
headers,
|
|
38
|
-
body,
|
|
39
39
|
query,
|
|
40
40
|
req: ctx.req,
|
|
41
41
|
});
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { once } from "node:events";
|
|
2
2
|
import { existsSync } from "node:fs";
|
|
3
|
+
import fs from "node:fs/promises";
|
|
3
4
|
import nodePath from "node:path";
|
|
4
|
-
import { once } from "node:events";
|
|
5
5
|
import { pathToFileURL } from "node:url";
|
|
6
6
|
|
|
7
7
|
import chokidar from "chokidar";
|
|
8
8
|
import createDebug from "debug";
|
|
9
9
|
|
|
10
|
-
import { ContextRegistry } from "./context-registry.js";
|
|
11
10
|
import { CHOKIDAR_OPTIONS } from "./constants.js";
|
|
11
|
+
import { ContextRegistry } from "./context-registry.js";
|
|
12
12
|
|
|
13
13
|
const debug = createDebug("counterfact:typescript-generator:module-loader");
|
|
14
14
|
|
|
@@ -41,9 +41,9 @@ export class ModuleLoader extends EventTarget {
|
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
const parts = nodePath.parse(pathName.replace(this.basePath, ""));
|
|
44
|
-
const url =
|
|
45
|
-
.
|
|
46
|
-
.replaceAll(
|
|
44
|
+
const url = `/${parts.dir}/${parts.name}`
|
|
45
|
+
.replaceAll("\\", "/")
|
|
46
|
+
.replaceAll(/\/+/gu, "/");
|
|
47
47
|
|
|
48
48
|
if (eventName === "unlink") {
|
|
49
49
|
this.registry.remove(url);
|
|
@@ -97,7 +97,7 @@ export class ModuleLoader extends EventTarget {
|
|
|
97
97
|
nodePath.join(this.basePath, directory).replaceAll("\\", "/"),
|
|
98
98
|
{
|
|
99
99
|
withFileTypes: true,
|
|
100
|
-
}
|
|
100
|
+
},
|
|
101
101
|
);
|
|
102
102
|
|
|
103
103
|
// eslint-disable-next-line max-statements
|
|
@@ -106,13 +106,13 @@ export class ModuleLoader extends EventTarget {
|
|
|
106
106
|
|
|
107
107
|
if (file.isDirectory()) {
|
|
108
108
|
await this.load(
|
|
109
|
-
nodePath.join(directory, file.name).replaceAll("\\", "/")
|
|
109
|
+
nodePath.join(directory, file.name).replaceAll("\\", "/"),
|
|
110
110
|
);
|
|
111
111
|
|
|
112
112
|
return;
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
-
if (!["js", "mjs", "
|
|
115
|
+
if (!["js", "mjs", "mts", "ts"].includes(extension)) {
|
|
116
116
|
return;
|
|
117
117
|
}
|
|
118
118
|
|
|
@@ -131,14 +131,19 @@ export class ModuleLoader extends EventTarget {
|
|
|
131
131
|
debug("* imported module: %s", fileUrl);
|
|
132
132
|
|
|
133
133
|
if (file.name.includes("$.context")) {
|
|
134
|
-
this.contextRegistry.add(
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
`/${nodePath
|
|
138
|
-
.join(directory, nodePath.parse(file.name).name)
|
|
139
|
-
.replaceAll("\\", "/")}`,
|
|
140
|
-
endpoint
|
|
134
|
+
this.contextRegistry.add(
|
|
135
|
+
`/${directory.replaceAll("\\", "/")}`.replaceAll(/\/+/gu, "/"),
|
|
136
|
+
endpoint.default,
|
|
141
137
|
);
|
|
138
|
+
} else {
|
|
139
|
+
const url = `/${nodePath.join(
|
|
140
|
+
directory,
|
|
141
|
+
nodePath.parse(file.name).name,
|
|
142
|
+
)}`
|
|
143
|
+
.replaceAll("\\", "/")
|
|
144
|
+
.replaceAll(/\/+/gu, "/");
|
|
145
|
+
|
|
146
|
+
this.registry.add(url, endpoint);
|
|
142
147
|
}
|
|
143
148
|
} catch (error) {
|
|
144
149
|
process.stdout.write(["Error loading", fullPath, error].join("\n"));
|