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.
@@ -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
- throw new Error("context cannot be undefined");
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 { body: mediaTypes(headers.accept ?? "*/*"), status: 406 };
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(script) {
34
- if (script.path === "paths/$.context.ts") {
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 { ContextCoder } from "./context-coder.js";
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 contextImportName = script.importDefault(new ContextCoder(this.requirement));
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: typeof ${contextImportName}, response: ${responseType}, proxy: ${proxyType} }) => ${this.responseTypes(script)} | { status: 415, contentType: "text/plain", body: string } | void`;
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.26.2",
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.1.1",
48
- "@stryker-mutator/jest-runner": "7.1.1",
49
- "@stryker-mutator/typescript-checker": "7.1.1",
50
- "@swc/core": "1.3.88",
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.50.0",
61
- "eslint-config-hardcore": "41.2.0",
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.0",
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.1",
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.2",
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.0",
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",