counterfact 0.26.2 → 0.27.0
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/bin/counterfact.js +5 -0
- package/dist/src/migrations/0.27.js +39 -0
- package/dist/src/server/context-registry.js +5 -1
- package/dist/src/server/dispatcher.js +6 -2
- package/dist/src/server/koa-middleware.js +5 -0
- package/dist/src/typescript-generator/context-coder.js +2 -9
- package/dist/src/typescript-generator/context-type-coder.js +32 -0
- package/dist/src/typescript-generator/generate.js +2 -0
- package/dist/src/typescript-generator/operation-type-coder.js +3 -3
- package/package.json +11 -11
package/bin/counterfact.js
CHANGED
|
@@ -6,6 +6,7 @@ import { program } from "commander";
|
|
|
6
6
|
import createDebug from "debug";
|
|
7
7
|
import open from "open";
|
|
8
8
|
|
|
9
|
+
import { migrate } from "../dist/src/migrations/0.27.js";
|
|
9
10
|
import { startRepl } from "../dist/src/server/repl.js";
|
|
10
11
|
import { start } from "../dist/src/server/start.js";
|
|
11
12
|
import { generate } from "../dist/src/typescript-generator/generate.js";
|
|
@@ -30,6 +31,10 @@ async function main(source, destination) {
|
|
|
30
31
|
.join(process.cwd(), destination)
|
|
31
32
|
.replaceAll("\\", "/");
|
|
32
33
|
|
|
34
|
+
debug("migrating code from before 0.27.0");
|
|
35
|
+
migrate(destinationPath);
|
|
36
|
+
debug("done with migration");
|
|
37
|
+
|
|
33
38
|
debug('generating code at "%s"', destinationPath);
|
|
34
39
|
|
|
35
40
|
await generate(source, destinationPath);
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { existsSync, readdirSync, readFileSync, statSync, writeFileSync, } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
function processFile(filePath) {
|
|
4
|
+
const content = readFileSync(filePath, "utf8");
|
|
5
|
+
if (content.includes("export type ContextType =") ||
|
|
6
|
+
content.includes("export type { ContextType }")) {
|
|
7
|
+
return;
|
|
8
|
+
}
|
|
9
|
+
if (content.includes("export default new Context")) {
|
|
10
|
+
writeFileSync(filePath, "export type ContextType = typeof Context;\n", {
|
|
11
|
+
flag: "a",
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
else {
|
|
15
|
+
writeFileSync(filePath, 'export type { ContextType } from "../$.context";\n');
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
function migrateContextFiles(path) {
|
|
19
|
+
if (!existsSync(path)) {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
const items = readdirSync(path);
|
|
23
|
+
for (const item of items) {
|
|
24
|
+
const itemPath = join(path, item);
|
|
25
|
+
const stats = statSync(itemPath);
|
|
26
|
+
if (stats.isDirectory()) {
|
|
27
|
+
migrateContextFiles(itemPath);
|
|
28
|
+
}
|
|
29
|
+
if (stats.isFile() && item === "$.context.ts") {
|
|
30
|
+
processFile(itemPath);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
export function migrate(rootPath) {
|
|
35
|
+
if (!existsSync(rootPath)) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
migrateContextFiles(join(rootPath, "paths"));
|
|
39
|
+
}
|
|
@@ -8,7 +8,11 @@ export class ContextRegistry {
|
|
|
8
8
|
}
|
|
9
9
|
add(path, context) {
|
|
10
10
|
if (context === undefined) {
|
|
11
|
-
|
|
11
|
+
// If $.context.ts exists but only exports a type, then the context object will be undefined here.
|
|
12
|
+
// This should be handled upstream, so that add() is not called in the first place.
|
|
13
|
+
// But module-loader.ts needs to be refactored a bit using type guards and the is operator
|
|
14
|
+
// before that can be done cleanly.
|
|
15
|
+
return;
|
|
12
16
|
}
|
|
13
17
|
this.entries.set(path, context);
|
|
14
18
|
}
|
|
@@ -75,6 +75,7 @@ export class Dispatcher {
|
|
|
75
75
|
}
|
|
76
76
|
const normalizedResponse = {
|
|
77
77
|
...response,
|
|
78
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
78
79
|
body: content.body,
|
|
79
80
|
contentType: content.type,
|
|
80
81
|
};
|
|
@@ -142,8 +143,11 @@ export class Dispatcher {
|
|
|
142
143
|
tools: new Tools({ headers }),
|
|
143
144
|
});
|
|
144
145
|
const normalizedResponse = this.normalizeResponse(response, headers.accept ?? "*/*");
|
|
145
|
-
if (!mediaTypes(headers.accept ?? "*/*").some((type) => this.isMediaType(normalizedResponse.contentType, type))) {
|
|
146
|
-
return {
|
|
146
|
+
if (!mediaTypes(headers.accept ?? "*/*").some((type) => this.isMediaType(normalizedResponse.contentType ?? "", type))) {
|
|
147
|
+
return {
|
|
148
|
+
body: JSON.stringify(mediaTypes(headers.accept ?? "*/*")),
|
|
149
|
+
status: 406,
|
|
150
|
+
};
|
|
147
151
|
}
|
|
148
152
|
return normalizedResponse;
|
|
149
153
|
}
|
|
@@ -35,6 +35,11 @@ export function koaMiddleware(dispatcher, { proxyEnabled = false, proxyUrl = ""
|
|
|
35
35
|
});
|
|
36
36
|
/* eslint-disable require-atomic-updates */
|
|
37
37
|
ctx.body = response.body;
|
|
38
|
+
if (response.headers) {
|
|
39
|
+
for (const [key, value] of Object.entries(response.headers)) {
|
|
40
|
+
ctx.set(key, value.toString());
|
|
41
|
+
}
|
|
42
|
+
}
|
|
38
43
|
ctx.status = response.status ?? HTTP_STATUS_CODE_OK;
|
|
39
44
|
/* eslint-enable require-atomic-updates */
|
|
40
45
|
return undefined;
|
|
@@ -30,15 +30,8 @@ class Context {
|
|
|
30
30
|
}
|
|
31
31
|
`;
|
|
32
32
|
}
|
|
33
|
-
write(
|
|
34
|
-
|
|
35
|
-
return "new Context()";
|
|
36
|
-
}
|
|
37
|
-
const parentPath = nodePath
|
|
38
|
-
.normalize(nodePath.join(script.path, "../../$.context.ts"))
|
|
39
|
-
.replaceAll("\\", "/");
|
|
40
|
-
script.repository.get(parentPath).exportDefault(this);
|
|
41
|
-
return { raw: 'export { default } from "../$.context.mjs"' };
|
|
33
|
+
write() {
|
|
34
|
+
return "new Context()";
|
|
42
35
|
}
|
|
43
36
|
modulePath() {
|
|
44
37
|
return nodePath
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import nodePath from "node:path";
|
|
2
|
+
import { Coder } from "./coder.js";
|
|
3
|
+
export class ContextTypeCoder extends Coder {
|
|
4
|
+
constructor(requirement, isRoot) {
|
|
5
|
+
super(requirement);
|
|
6
|
+
this.isRoot = isRoot;
|
|
7
|
+
}
|
|
8
|
+
pathString() {
|
|
9
|
+
return this.requirement.url
|
|
10
|
+
.split("/")
|
|
11
|
+
.at(-2)
|
|
12
|
+
.replaceAll("~1", "/")
|
|
13
|
+
.replaceAll("~0", "~");
|
|
14
|
+
}
|
|
15
|
+
get id() {
|
|
16
|
+
return "ContextTypeCoder";
|
|
17
|
+
}
|
|
18
|
+
names() {
|
|
19
|
+
return super.names("ContextType");
|
|
20
|
+
}
|
|
21
|
+
write(script) {
|
|
22
|
+
if (script.path === "paths/$.context.ts") {
|
|
23
|
+
return "typeof Context";
|
|
24
|
+
}
|
|
25
|
+
return { raw: 'export type { ContextType } from "../$.context"' };
|
|
26
|
+
}
|
|
27
|
+
modulePath() {
|
|
28
|
+
return nodePath
|
|
29
|
+
.join("paths", nodePath.dirname(this.pathString()), "$.context.ts")
|
|
30
|
+
.replaceAll("\\", "/");
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -3,6 +3,7 @@ import fs from "node:fs/promises";
|
|
|
3
3
|
import nodePath from "node:path";
|
|
4
4
|
import createDebug from "debug";
|
|
5
5
|
import { ensureDirectoryExists } from "../util/ensure-directory-exists.js";
|
|
6
|
+
import { ContextCoder } from "./context-coder.js";
|
|
6
7
|
import { OperationCoder } from "./operation-coder.js";
|
|
7
8
|
import { Repository } from "./repository.js";
|
|
8
9
|
import { Specification } from "./specification.js";
|
|
@@ -39,6 +40,7 @@ export async function generate(source, destination, repository = new Repository(
|
|
|
39
40
|
repository.get(`paths${key}.ts`).export(new OperationCoder(operation));
|
|
40
41
|
});
|
|
41
42
|
});
|
|
43
|
+
repository.get("paths/$.context.ts").exportDefault(new ContextCoder(paths));
|
|
42
44
|
debug("telling the repository to write the files to %s", destination);
|
|
43
45
|
await repository.writeFiles(destination);
|
|
44
46
|
debug("finished writing the files");
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import nodePath from "node:path";
|
|
2
2
|
import { Coder } from "./coder.js";
|
|
3
|
-
import {
|
|
3
|
+
import { ContextTypeCoder } from "./context-type-coder.js";
|
|
4
4
|
import { ParametersTypeCoder } from "./parameters-type-coder.js";
|
|
5
5
|
import { ResponseTypeCoder } from "./response-type-coder.js";
|
|
6
6
|
import { SchemaTypeCoder } from "./schema-type-coder.js";
|
|
@@ -49,7 +49,7 @@ export class OperationTypeCoder extends Coder {
|
|
|
49
49
|
.replaceAll("\\", "/")}.types.ts`;
|
|
50
50
|
}
|
|
51
51
|
write(script) {
|
|
52
|
-
const
|
|
52
|
+
const contextTypeImportName = script.importType(new ContextTypeCoder(this.requirement));
|
|
53
53
|
const parameters = this.requirement.get("parameters");
|
|
54
54
|
const queryType = parameters === undefined
|
|
55
55
|
? "never"
|
|
@@ -71,6 +71,6 @@ export class OperationTypeCoder extends Coder {
|
|
|
71
71
|
const responseType = new ResponseTypeCoder(this.requirement.get("responses"), this.requirement.get("produces")?.data ??
|
|
72
72
|
this.requirement.specification?.rootRequirement?.get("produces")?.data).write(script);
|
|
73
73
|
const proxyType = "(url: string) => { proxyUrl: string }";
|
|
74
|
-
return `({ query, path, header, body, context, proxy }: { query: ${queryType}, path: ${pathType}, header: ${headerType}, body: ${bodyType}, context:
|
|
74
|
+
return `({ query, path, header, body, context, proxy }: { query: ${queryType}, path: ${pathType}, header: ${headerType}, body: ${bodyType}, context: ${contextTypeImportName}, response: ${responseType}, proxy: ${proxyType} }) => ${this.responseTypes(script)} | { status: 415, contentType: "text/plain", body: string } | void`;
|
|
75
75
|
}
|
|
76
76
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "counterfact",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.27.0",
|
|
4
4
|
"description": "a library for building a fake REST API for testing",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/server/counterfact.js",
|
|
@@ -44,10 +44,10 @@
|
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"@changesets/cli": "2.26.2",
|
|
47
|
-
"@stryker-mutator/core": "7.
|
|
48
|
-
"@stryker-mutator/jest-runner": "7.
|
|
49
|
-
"@stryker-mutator/typescript-checker": "7.
|
|
50
|
-
"@swc/core": "1.3.
|
|
47
|
+
"@stryker-mutator/core": "7.2.0",
|
|
48
|
+
"@stryker-mutator/jest-runner": "7.2.0",
|
|
49
|
+
"@stryker-mutator/typescript-checker": "7.2.0",
|
|
50
|
+
"@swc/core": "1.3.92",
|
|
51
51
|
"@swc/jest": "0.2.29",
|
|
52
52
|
"@testing-library/dom": "9.3.3",
|
|
53
53
|
"@types/jest": "29.5.5",
|
|
@@ -57,14 +57,14 @@
|
|
|
57
57
|
"@types/koa-proxy": "1.0.5",
|
|
58
58
|
"@types/koa-static": "4.0.2",
|
|
59
59
|
"copyfiles": "2.4.1",
|
|
60
|
-
"eslint": "8.
|
|
61
|
-
"eslint-config-hardcore": "41.
|
|
60
|
+
"eslint": "8.51.0",
|
|
61
|
+
"eslint-config-hardcore": "41.3.0",
|
|
62
62
|
"eslint-formatter-github-annotations": "0.1.0",
|
|
63
63
|
"eslint-import-resolver-typescript": "3.6.1",
|
|
64
64
|
"eslint-plugin-etc": "2.0.3",
|
|
65
65
|
"eslint-plugin-file-progress": "1.3.0",
|
|
66
66
|
"eslint-plugin-import": "2.28.1",
|
|
67
|
-
"eslint-plugin-jest": "27.4.
|
|
67
|
+
"eslint-plugin-jest": "27.4.2",
|
|
68
68
|
"eslint-plugin-jest-dom": "5.1.0",
|
|
69
69
|
"eslint-plugin-no-explicit-type-exports": "0.12.1",
|
|
70
70
|
"eslint-plugin-unused-imports": "3.0.0",
|
|
@@ -73,12 +73,12 @@
|
|
|
73
73
|
"node-mocks-http": "1.13.0",
|
|
74
74
|
"nodemon": "3.0.1",
|
|
75
75
|
"patch-package": "8.0.0",
|
|
76
|
-
"rimraf": "5.0.
|
|
76
|
+
"rimraf": "5.0.5",
|
|
77
77
|
"stryker-cli": "1.0.2",
|
|
78
78
|
"supertest": "6.3.3"
|
|
79
79
|
},
|
|
80
80
|
"dependencies": {
|
|
81
|
-
"@hapi/accept": "6.0.
|
|
81
|
+
"@hapi/accept": "6.0.3",
|
|
82
82
|
"@types/json-schema": "7.0.13",
|
|
83
83
|
"chokidar": "3.5.3",
|
|
84
84
|
"commander": "11.0.0",
|
|
@@ -94,7 +94,7 @@
|
|
|
94
94
|
"koa": "2.14.2",
|
|
95
95
|
"koa-bodyparser": "4.4.1",
|
|
96
96
|
"koa-proxy": "1.0.0-alpha.3",
|
|
97
|
-
"koa2-swagger-ui": "5.9.
|
|
97
|
+
"koa2-swagger-ui": "5.9.1",
|
|
98
98
|
"node-fetch": "3.3.2",
|
|
99
99
|
"open": "9.1.0",
|
|
100
100
|
"prettier": "3.0.3",
|