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.
Files changed (48) hide show
  1. package/.eslintrc.cjs +71 -63
  2. package/CHANGELOG.md +6 -0
  3. package/bin/counterfact.js +10 -9
  4. package/package.json +4 -4
  5. package/src/server/counterfact.js +8 -9
  6. package/src/server/dispatcher.js +34 -33
  7. package/src/server/koa-middleware.js +5 -5
  8. package/src/server/module-loader.js +21 -16
  9. package/src/server/registry.js +17 -6
  10. package/src/server/repl.js +10 -10
  11. package/src/server/response-builder.js +21 -21
  12. package/src/server/start.js +22 -15
  13. package/src/server/transpiler.js +6 -6
  14. package/src/typescript-generator/generate.js +2 -2
  15. package/src/typescript-generator/operation-coder.js +1 -1
  16. package/src/typescript-generator/operation-type-coder.js +9 -9
  17. package/src/typescript-generator/parameters-type-coder.js +1 -1
  18. package/src/typescript-generator/repository.js +8 -11
  19. package/src/typescript-generator/requirement.js +2 -2
  20. package/src/typescript-generator/response-type-coder.js +7 -7
  21. package/src/typescript-generator/schema-coder.js +2 -2
  22. package/src/typescript-generator/schema-type-coder.js +8 -8
  23. package/src/typescript-generator/script.js +18 -18
  24. package/src/typescript-generator/specification.js +1 -2
  25. package/src/util/read-file.js +1 -1
  26. package/templates/response-builder-factory.ts +12 -12
  27. package/test/lib/with-temporary-files.js +4 -3
  28. package/test/server/counterfact.test.js +5 -4
  29. package/test/server/dispatcher.proxy.test.js +2 -2
  30. package/test/server/dispatcher.test.js +77 -69
  31. package/test/server/koa-middleware.test.js +29 -26
  32. package/test/server/module-loader.test.js +14 -14
  33. package/test/server/registry.test.js +3 -3
  34. package/test/server/response-builder.test.js +31 -31
  35. package/test/server/tools.test.js +5 -5
  36. package/test/server/transpiler.test.js +7 -7
  37. package/test/typescript-generator/coder.test.js +3 -3
  38. package/test/typescript-generator/context-coder.test.js +8 -7
  39. package/test/typescript-generator/integration.test.js +6 -6
  40. package/test/typescript-generator/operation-coder.test.js +25 -26
  41. package/test/typescript-generator/operation-type-coder.test.js +52 -52
  42. package/test/typescript-generator/parameters-type-coder.test.js +34 -33
  43. package/test/typescript-generator/requirement.test.js +7 -7
  44. package/test/typescript-generator/response-type-coder.test.js +4 -4
  45. package/test/typescript-generator/schema-coder.test.js +26 -22
  46. package/test/typescript-generator/schema-type-coder.test.js +111 -85
  47. package/test/typescript-generator/script.test.js +6 -6
  48. 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
- "n/shebang": "off",
5
- "putout/putout": "off",
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
- // too slow
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
- "id-length": ["off"],
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
- "@typescript-eslint/no-magic-numbers": "off",
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
@@ -1,5 +1,11 @@
1
1
  # counterfact
2
2
 
3
+ ## 0.25.4
4
+
5
+ ### Patch Changes
6
+
7
+ - 7f2e19e: fixed an issue in which routes on the start page weren't rendered correctly in Windows
8
+
3
9
  ## 0.25.3
4
10
 
5
11
  ### Patch Changes
@@ -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
- proxyUrl: options.proxyUrl,
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",
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.47.0",
46
- "eslint-config-hardcore": "36.4.0",
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": "^2.7.1",
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 { ContextRegistry } from "./context-registry.js";
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
- contextRegistry,
65
+ registry,
67
66
  };
68
67
  }
@@ -1,6 +1,5 @@
1
- // eslint-disable-next-line import/order
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
- path: {},
17
- query: {},
18
- header: {},
15
+ body: {},
19
16
  cookie: {},
20
17
  formData: {},
21
- body: {},
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({ method, path, headers, body, query, req }) {
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
- status: fetchResponse.status,
94
+ body: await fetchResponse.text(),
105
95
  contentType: responseHeaders["content-type"] ?? "unknown/unknown",
106
96
  headers: responseHeaders,
107
- body: await fetchResponse.text(),
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 { status: 406, body: Accept.mediaTypes(headers?.accept ?? "*/*") };
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 { method, path, headers, body, query } = ctx.request;
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 fs from "node:fs/promises";
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 = nodePath
45
- .normalize(`/${nodePath.join(parts.dir, parts.name)}`)
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", "ts", "mts"].includes(extension)) {
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(`/${directory}`, endpoint.default);
135
- } else {
136
- this.registry.add(
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"));