counterfact 0.30.0 → 0.32.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 +8 -18
- package/dist/server/module-tree.js +130 -0
- package/dist/server/registry.js +11 -70
- package/dist/server/types.d.ts +201 -0
- package/dist/typescript-generator/repository.js +2 -3
- package/package.json +16 -16
package/bin/counterfact.js
CHANGED
|
@@ -57,29 +57,19 @@ async function main(source, destination) {
|
|
|
57
57
|
|
|
58
58
|
debug("loaded counterfact", config);
|
|
59
59
|
|
|
60
|
-
const waysToInteract = [
|
|
61
|
-
`Call the REST APIs at ${url} (with your front end app, curl, Postman, etc.)`,
|
|
62
|
-
`Change the implementation of the APIs by editing files under ${nodePath
|
|
63
|
-
.join(basePath, "paths")
|
|
64
|
-
.replaceAll("\\", "/")} (no need to restart)`,
|
|
65
|
-
`Use the GUI at ${guiUrl}`,
|
|
66
|
-
"Use the REPL below (type .counterfact for more information)",
|
|
67
|
-
];
|
|
68
|
-
|
|
69
60
|
const introduction = [
|
|
61
|
+
"____ ____ _ _ _ _ ___ ____ ____ ____ ____ ____ ___",
|
|
62
|
+
"|___ [__] |__| |\\| | |=== |--< |--- |--| |___ | ",
|
|
63
|
+
" High code, low effort mock REST APIs",
|
|
70
64
|
"",
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
"
|
|
74
|
-
"There are several ways to poke and prod the server in order to make it behave the way you need for testing.",
|
|
65
|
+
`| API Base URL ==> ${url}`,
|
|
66
|
+
`| Admin Console ==> ${guiUrl}`,
|
|
67
|
+
"| Instructions ==> https://counterfact.dev/docs/usage.html",
|
|
75
68
|
"",
|
|
69
|
+
"Starting REPL, type .help for more info",
|
|
76
70
|
];
|
|
77
71
|
|
|
78
|
-
process.stdout.write(
|
|
79
|
-
|
|
80
|
-
process.stdout.write(
|
|
81
|
-
waysToInteract.map((text, index) => `${index + 1}. ${text}`).join("\n"),
|
|
82
|
-
);
|
|
72
|
+
process.stdout.write(introduction.join("\n"));
|
|
83
73
|
|
|
84
74
|
process.stdout.write("\n\n");
|
|
85
75
|
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
function isDirectory(test) {
|
|
2
|
+
return test !== undefined;
|
|
3
|
+
}
|
|
4
|
+
export class ModuleTree {
|
|
5
|
+
root = {
|
|
6
|
+
directories: {},
|
|
7
|
+
files: {},
|
|
8
|
+
isWildcard: false,
|
|
9
|
+
name: "",
|
|
10
|
+
rawName: "",
|
|
11
|
+
};
|
|
12
|
+
addModuleToDirectory(directory, segments, module) {
|
|
13
|
+
if (directory === undefined) {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
const [segment, ...remainingSegments] = segments;
|
|
17
|
+
if (segment === undefined) {
|
|
18
|
+
throw new Error("segments array is empty");
|
|
19
|
+
}
|
|
20
|
+
if (remainingSegments.length === 0) {
|
|
21
|
+
directory.files[segment.toLowerCase()] = {
|
|
22
|
+
isWildcard: segment.startsWith("{"),
|
|
23
|
+
module,
|
|
24
|
+
name: segment.replace(/^\{(?<name>.*)\}$/u, "$<name>"),
|
|
25
|
+
rawName: segment,
|
|
26
|
+
};
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
30
|
+
directory.directories[segment.toLowerCase()] ??= {
|
|
31
|
+
directories: {},
|
|
32
|
+
files: {},
|
|
33
|
+
isWildcard: segment.startsWith("{"),
|
|
34
|
+
name: segment.replace(/^\{(?<name>.*)\}$/u, "$<name>"),
|
|
35
|
+
rawName: segment,
|
|
36
|
+
};
|
|
37
|
+
this.addModuleToDirectory(directory.directories[segment.toLocaleLowerCase()], remainingSegments, module);
|
|
38
|
+
}
|
|
39
|
+
add(url, module) {
|
|
40
|
+
this.addModuleToDirectory(this.root, url.split("/").slice(1), module);
|
|
41
|
+
}
|
|
42
|
+
removeModuleFromDirectory(directory, segments) {
|
|
43
|
+
if (!isDirectory(directory)) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
const [segment, ...remainingSegments] = segments;
|
|
47
|
+
if (segment === undefined) {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
if (remainingSegments.length === 0) {
|
|
51
|
+
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
|
|
52
|
+
delete directory.files[segment.toLowerCase()];
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
this.removeModuleFromDirectory(directory.directories[segment.toLowerCase()], remainingSegments);
|
|
56
|
+
}
|
|
57
|
+
remove(url) {
|
|
58
|
+
const segments = url.split("/").slice(1);
|
|
59
|
+
this.removeModuleFromDirectory(this.root, segments);
|
|
60
|
+
}
|
|
61
|
+
// eslint-disable-next-line max-params
|
|
62
|
+
buildMatch(directory, segment, pathVariables, matchedPath) {
|
|
63
|
+
const match = directory.files[segment.toLowerCase()] ??
|
|
64
|
+
Object.values(directory.files).find((file) => file.isWildcard);
|
|
65
|
+
if (match === undefined) {
|
|
66
|
+
return undefined;
|
|
67
|
+
}
|
|
68
|
+
if (match.isWildcard) {
|
|
69
|
+
return {
|
|
70
|
+
...match,
|
|
71
|
+
matchedPath: `${matchedPath}/${match.rawName}`,
|
|
72
|
+
pathVariables: {
|
|
73
|
+
...pathVariables,
|
|
74
|
+
[match.name]: segment,
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
return {
|
|
79
|
+
...match,
|
|
80
|
+
matchedPath: `${matchedPath}/${match.rawName}`,
|
|
81
|
+
pathVariables,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
// eslint-disable-next-line max-statements, max-params
|
|
85
|
+
matchWithinDirectory(directory, segments, pathVariables, matchedPath) {
|
|
86
|
+
if (segments.length === 0) {
|
|
87
|
+
return undefined;
|
|
88
|
+
}
|
|
89
|
+
const [segment, ...remainingSegments] = segments;
|
|
90
|
+
if (segment === undefined) {
|
|
91
|
+
throw new Error("segment cannot be undefined but TypeScript doesn't know that");
|
|
92
|
+
}
|
|
93
|
+
if (remainingSegments.length === 0) {
|
|
94
|
+
return this.buildMatch(directory, segment, pathVariables, matchedPath);
|
|
95
|
+
}
|
|
96
|
+
const exactMatch = directory.directories[segment.toLowerCase()];
|
|
97
|
+
if (isDirectory(exactMatch)) {
|
|
98
|
+
return this.matchWithinDirectory(exactMatch, remainingSegments, pathVariables, `${matchedPath}/${segment}`);
|
|
99
|
+
}
|
|
100
|
+
const wildcardDirectory = Object.values(directory.directories).find((subdirectory) => subdirectory.isWildcard);
|
|
101
|
+
if (wildcardDirectory) {
|
|
102
|
+
return this.matchWithinDirectory(wildcardDirectory, remainingSegments, {
|
|
103
|
+
...pathVariables,
|
|
104
|
+
[wildcardDirectory.name]: segment,
|
|
105
|
+
}, `${matchedPath}/${wildcardDirectory.rawName}`);
|
|
106
|
+
}
|
|
107
|
+
return undefined;
|
|
108
|
+
}
|
|
109
|
+
match(url) {
|
|
110
|
+
return this.matchWithinDirectory(this.root, url.split("/").slice(1), {}, "");
|
|
111
|
+
}
|
|
112
|
+
get routes() {
|
|
113
|
+
const routes = [];
|
|
114
|
+
function traverse(directory, path) {
|
|
115
|
+
Object.values(directory.directories).forEach((subdirectory) => {
|
|
116
|
+
traverse(subdirectory, `${path}/${subdirectory.rawName}`);
|
|
117
|
+
});
|
|
118
|
+
Object.values(directory.files).forEach((file) => {
|
|
119
|
+
routes.push(`${path}/${file.rawName}`);
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
// eslint-disable-next-line unicorn/consistent-function-scoping
|
|
123
|
+
function stripBrackets(string) {
|
|
124
|
+
return string.replaceAll(/\{|\}/gu, "");
|
|
125
|
+
}
|
|
126
|
+
traverse(this.root, "");
|
|
127
|
+
// eslint-disable-next-line etc/no-assign-mutated-array
|
|
128
|
+
return routes.sort((first, second) => stripBrackets(first).localeCompare(stripBrackets(second)));
|
|
129
|
+
}
|
|
130
|
+
}
|
package/dist/server/registry.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import createDebugger from "debug";
|
|
2
|
+
import { ModuleTree } from "./module-tree.js";
|
|
2
3
|
const debug = createDebugger("counterfact:server:registry");
|
|
3
4
|
function castParameters(parameters, parameterTypes) {
|
|
4
5
|
const copy = { ...parameters };
|
|
@@ -11,87 +12,27 @@ function castParameters(parameters, parameterTypes) {
|
|
|
11
12
|
});
|
|
12
13
|
return copy;
|
|
13
14
|
}
|
|
14
|
-
function maybe(flag, value) {
|
|
15
|
-
return flag ? [value] : [];
|
|
16
|
-
}
|
|
17
|
-
function stripBrackets(string) {
|
|
18
|
-
return string.replaceAll(/\{|\}/gu, "");
|
|
19
|
-
}
|
|
20
|
-
function routesForNode(node) {
|
|
21
|
-
if (!node.children) {
|
|
22
|
-
return [];
|
|
23
|
-
}
|
|
24
|
-
return Object.entries(node.children)
|
|
25
|
-
.flatMap(([segment, child]) => [
|
|
26
|
-
...maybe(child.module, `/${segment}`),
|
|
27
|
-
...routesForNode(child).map((route) => `/${segment}${route}`),
|
|
28
|
-
])
|
|
29
|
-
.sort((segment1, segment2) => stripBrackets(segment1).localeCompare(stripBrackets(segment2)));
|
|
30
|
-
}
|
|
31
15
|
export class Registry {
|
|
32
|
-
|
|
33
|
-
moduleTree = { children: {} };
|
|
16
|
+
moduleTree = new ModuleTree();
|
|
34
17
|
get routes() {
|
|
35
|
-
return
|
|
18
|
+
return this.moduleTree.routes;
|
|
36
19
|
}
|
|
37
20
|
add(url, module) {
|
|
38
|
-
|
|
39
|
-
for (const segment of url.split("/").slice(1)) {
|
|
40
|
-
node.children ??= {};
|
|
41
|
-
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
42
|
-
node.children[segment] ??= {};
|
|
43
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
44
|
-
node = node.children[segment];
|
|
45
|
-
}
|
|
46
|
-
node.module = module;
|
|
21
|
+
this.moduleTree.add(url, module);
|
|
47
22
|
}
|
|
48
23
|
remove(url) {
|
|
49
|
-
|
|
50
|
-
for (const segment of url.split("/").slice(1)) {
|
|
51
|
-
node = node.children?.[segment];
|
|
52
|
-
if (!node) {
|
|
53
|
-
return false;
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
delete node.module;
|
|
57
|
-
return true;
|
|
24
|
+
this.moduleTree.remove(url);
|
|
58
25
|
}
|
|
59
26
|
exists(method, url) {
|
|
60
27
|
return Boolean(this.handler(url).module?.[method]);
|
|
61
28
|
}
|
|
62
|
-
// eslint-disable-next-line max-statements, sonarjs/cognitive-complexity
|
|
63
29
|
handler(url) {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
}
|
|
71
|
-
if (node.children === undefined) {
|
|
72
|
-
throw new Error("node or node node.children cannot be undefined");
|
|
73
|
-
}
|
|
74
|
-
const matchingChild = Object.keys(node.children).find((candidate) => candidate.toLowerCase() === segment.toLowerCase());
|
|
75
|
-
debug("segment: %s", segment);
|
|
76
|
-
debug("matching child: %s", matchingChild);
|
|
77
|
-
if (matchingChild === undefined) {
|
|
78
|
-
const dynamicSegment = Object.keys(node.children).find((ds) => ds.startsWith("{") && ds.endsWith("}"));
|
|
79
|
-
if (dynamicSegment !== undefined) {
|
|
80
|
-
const variableName = dynamicSegment.slice(1, -1);
|
|
81
|
-
path[variableName] = segment;
|
|
82
|
-
node = node.children[dynamicSegment];
|
|
83
|
-
matchedParts.push(dynamicSegment);
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
else {
|
|
87
|
-
node = node.children[matchingChild];
|
|
88
|
-
matchedParts.push(matchingChild);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
if (node === undefined) {
|
|
92
|
-
throw new Error("node cannot be undefined");
|
|
93
|
-
}
|
|
94
|
-
return { matchedPath: matchedParts.join("/"), module: node.module, path };
|
|
30
|
+
const match = this.moduleTree.match(url);
|
|
31
|
+
return {
|
|
32
|
+
matchedPath: match?.matchedPath ?? "",
|
|
33
|
+
module: match?.module,
|
|
34
|
+
path: match?.pathVariables ?? {},
|
|
35
|
+
};
|
|
95
36
|
}
|
|
96
37
|
endpoint(httpRequestMethod, url, parameterTypes = {}) {
|
|
97
38
|
const handler = this.handler(url);
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
interface OpenApiHeader {
|
|
2
|
+
schema: unknown;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
interface OpenApiContent {
|
|
6
|
+
schema: unknown;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
interface Example {
|
|
10
|
+
description: string;
|
|
11
|
+
summary: string;
|
|
12
|
+
value: unknown;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
type MediaType = `${string}/${string}`;
|
|
16
|
+
|
|
17
|
+
type OmitValueWhenNever<Base> = Pick<
|
|
18
|
+
Base,
|
|
19
|
+
{
|
|
20
|
+
[Key in keyof Base]: [Base[Key]] extends [never] ? never : Key;
|
|
21
|
+
}[keyof Base]
|
|
22
|
+
>;
|
|
23
|
+
|
|
24
|
+
interface OpenApiResponse {
|
|
25
|
+
content: { [key: MediaType]: OpenApiContent };
|
|
26
|
+
headers: { [key: string]: OpenApiHeader };
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
interface OpenApiResponses {
|
|
30
|
+
[key: string]: OpenApiResponse;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
type IfHasKey<SomeObject, Key, Yes, No> = Key extends keyof SomeObject
|
|
34
|
+
? Yes
|
|
35
|
+
: No;
|
|
36
|
+
|
|
37
|
+
type MaybeShortcut<
|
|
38
|
+
ContentType extends MediaType,
|
|
39
|
+
Response extends OpenApiResponse,
|
|
40
|
+
> = IfHasKey<
|
|
41
|
+
Response["content"],
|
|
42
|
+
ContentType,
|
|
43
|
+
(body: Response["content"][ContentType]["schema"]) => GenericResponseBuilder<{
|
|
44
|
+
content: Omit<Response["content"], ContentType>;
|
|
45
|
+
headers: Response["headers"];
|
|
46
|
+
}>,
|
|
47
|
+
never
|
|
48
|
+
>;
|
|
49
|
+
|
|
50
|
+
type MatchFunction<Response extends OpenApiResponse> = <
|
|
51
|
+
ContentType extends MediaType & keyof Response["content"],
|
|
52
|
+
>(
|
|
53
|
+
contentType: ContentType,
|
|
54
|
+
body: Response["content"][ContentType]["schema"],
|
|
55
|
+
) => GenericResponseBuilder<{
|
|
56
|
+
content: Omit<Response["content"], ContentType>;
|
|
57
|
+
headers: Response["headers"];
|
|
58
|
+
}>;
|
|
59
|
+
|
|
60
|
+
type HeaderFunction<Response extends OpenApiResponse> = <
|
|
61
|
+
Header extends string & keyof Response["headers"],
|
|
62
|
+
>(
|
|
63
|
+
header: Header,
|
|
64
|
+
value: Response["headers"][Header]["schema"],
|
|
65
|
+
) => GenericResponseBuilder<{
|
|
66
|
+
content: Response["content"];
|
|
67
|
+
headers: Omit<Response["headers"], Header>;
|
|
68
|
+
}>;
|
|
69
|
+
|
|
70
|
+
interface ResponseBuilder {
|
|
71
|
+
[status: number | `${number} ${string}`]: ResponseBuilder;
|
|
72
|
+
content?: { body: unknown; type: string }[];
|
|
73
|
+
header: (name: string, value: string) => ResponseBuilder;
|
|
74
|
+
headers: { [name: string]: string };
|
|
75
|
+
html: (body: unknown) => ResponseBuilder;
|
|
76
|
+
json: (body: unknown) => ResponseBuilder;
|
|
77
|
+
match: (contentType: string, body: unknown) => ResponseBuilder;
|
|
78
|
+
random: () => ResponseBuilder;
|
|
79
|
+
randomLegacy: () => ResponseBuilder;
|
|
80
|
+
status?: number;
|
|
81
|
+
text: (body: unknown) => ResponseBuilder;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
type GenericResponseBuilder<
|
|
85
|
+
Response extends OpenApiResponse = OpenApiResponse,
|
|
86
|
+
> = [keyof Response["content"]] extends [never]
|
|
87
|
+
? // eslint-disable-next-line @typescript-eslint/no-invalid-void-type
|
|
88
|
+
void
|
|
89
|
+
: OmitValueWhenNever<{
|
|
90
|
+
header: [keyof Response["headers"]] extends [never]
|
|
91
|
+
? never
|
|
92
|
+
: HeaderFunction<Response>;
|
|
93
|
+
html: MaybeShortcut<"text/html", Response>;
|
|
94
|
+
json: MaybeShortcut<"application/json", Response>;
|
|
95
|
+
match: [keyof Response["content"]] extends [never]
|
|
96
|
+
? never
|
|
97
|
+
: MatchFunction<Response>;
|
|
98
|
+
random: [keyof Response["content"]] extends [never] ? never : () => void;
|
|
99
|
+
text: MaybeShortcut<"text/plain", Response>;
|
|
100
|
+
}>;
|
|
101
|
+
|
|
102
|
+
type ResponseBuilderFactory<
|
|
103
|
+
Responses extends OpenApiResponses = OpenApiResponses,
|
|
104
|
+
> = {
|
|
105
|
+
[StatusCode in keyof Responses]: GenericResponseBuilder<
|
|
106
|
+
Responses[StatusCode]
|
|
107
|
+
>;
|
|
108
|
+
} & { [key: string]: GenericResponseBuilder<Responses["default"]> };
|
|
109
|
+
|
|
110
|
+
type HttpStatusCode =
|
|
111
|
+
| 100
|
|
112
|
+
| 101
|
|
113
|
+
| 102
|
|
114
|
+
| 200
|
|
115
|
+
| 201
|
|
116
|
+
| 202
|
|
117
|
+
| 203
|
|
118
|
+
| 204
|
|
119
|
+
| 205
|
|
120
|
+
| 206
|
|
121
|
+
| 207
|
|
122
|
+
| 226
|
|
123
|
+
| 300
|
|
124
|
+
| 301
|
|
125
|
+
| 302
|
|
126
|
+
| 303
|
|
127
|
+
| 304
|
|
128
|
+
| 305
|
|
129
|
+
| 307
|
|
130
|
+
| 308
|
|
131
|
+
| 400
|
|
132
|
+
| 401
|
|
133
|
+
| 402
|
|
134
|
+
| 403
|
|
135
|
+
| 404
|
|
136
|
+
| 405
|
|
137
|
+
| 406
|
|
138
|
+
| 407
|
|
139
|
+
| 408
|
|
140
|
+
| 409
|
|
141
|
+
| 410
|
|
142
|
+
| 411
|
|
143
|
+
| 412
|
|
144
|
+
| 413
|
|
145
|
+
| 414
|
|
146
|
+
| 415
|
|
147
|
+
| 416
|
|
148
|
+
| 417
|
|
149
|
+
| 418
|
|
150
|
+
| 422
|
|
151
|
+
| 423
|
|
152
|
+
| 424
|
|
153
|
+
| 426
|
|
154
|
+
| 428
|
|
155
|
+
| 429
|
|
156
|
+
| 431
|
|
157
|
+
| 451
|
|
158
|
+
| 500
|
|
159
|
+
| 501
|
|
160
|
+
| 502
|
|
161
|
+
| 503
|
|
162
|
+
| 504
|
|
163
|
+
| 505
|
|
164
|
+
| 506
|
|
165
|
+
| 507
|
|
166
|
+
| 511;
|
|
167
|
+
|
|
168
|
+
interface OpenApiParameters {
|
|
169
|
+
in: "body" | "cookie" | "formData" | "header" | "path" | "query";
|
|
170
|
+
name: string;
|
|
171
|
+
schema?: {
|
|
172
|
+
type: string;
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
interface OpenApiOperation {
|
|
177
|
+
parameters?: OpenApiParameters[];
|
|
178
|
+
produces?: string[];
|
|
179
|
+
responses: {
|
|
180
|
+
[status: string]: {
|
|
181
|
+
content?: {
|
|
182
|
+
[type: number | string]: {
|
|
183
|
+
examples?: { [key: string]: Example };
|
|
184
|
+
schema: unknown;
|
|
185
|
+
};
|
|
186
|
+
};
|
|
187
|
+
examples?: { [key: string]: unknown };
|
|
188
|
+
schema?: unknown;
|
|
189
|
+
};
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
export type {
|
|
194
|
+
HttpStatusCode,
|
|
195
|
+
MediaType,
|
|
196
|
+
OpenApiOperation,
|
|
197
|
+
OpenApiParameters,
|
|
198
|
+
OpenApiResponse,
|
|
199
|
+
ResponseBuilder,
|
|
200
|
+
ResponseBuilderFactory,
|
|
201
|
+
};
|
|
@@ -32,7 +32,7 @@ export class Repository {
|
|
|
32
32
|
}
|
|
33
33
|
copyCoreFiles(destination) {
|
|
34
34
|
return fs.copyFile(nodePath
|
|
35
|
-
.join(__dirname, "../../
|
|
35
|
+
.join(__dirname, "../../dist/server/types.d.ts")
|
|
36
36
|
.replaceAll("\\", "/"), nodePath.join(destination, "types.d.ts").replaceAll("\\", "/"));
|
|
37
37
|
}
|
|
38
38
|
async writeFiles(destination) {
|
|
@@ -48,13 +48,12 @@ export class Repository {
|
|
|
48
48
|
.stat(fullPath)
|
|
49
49
|
.then((stat) => stat.isFile())
|
|
50
50
|
.catch(() => false))) {
|
|
51
|
-
|
|
51
|
+
debug(`not overwriting ${fullPath}\n`);
|
|
52
52
|
return;
|
|
53
53
|
}
|
|
54
54
|
debug("about to write", fullPath);
|
|
55
55
|
await fs.writeFile(fullPath, contents);
|
|
56
56
|
debug("did write", fullPath);
|
|
57
|
-
process.stdout.write(`writing ${fullPath}\n`);
|
|
58
57
|
});
|
|
59
58
|
await Promise.all(writeFiles);
|
|
60
59
|
await this.copyCoreFiles(destination);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "counterfact",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.32.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",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"test": "yarn node --experimental-vm-modules ./node_modules/jest-cli/bin/jest --testPathIgnorePatterns=black-box --forceExit",
|
|
32
32
|
"test:black-box": "rimraf dist && rimraf out && yarn build && yarn node --experimental-vm-modules ./node_modules/jest-cli/bin/jest black-box --forceExit --coverage=false",
|
|
33
33
|
"test:mutants": "stryker run stryker.config.json",
|
|
34
|
-
"build": "tsc && copyfiles -f \"src/client/**\" dist/client",
|
|
34
|
+
"build": "tsc && copyfiles -f \"src/client/**\" dist/client && copyfiles -f \"src/server/*.d.ts\" dist/server",
|
|
35
35
|
"prepack": "yarn build",
|
|
36
36
|
"release": "npx changeset publish",
|
|
37
37
|
"prepare": "husky install",
|
|
@@ -43,21 +43,21 @@
|
|
|
43
43
|
"counterfact": "./bin/counterfact.js"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
|
-
"@changesets/cli": "2.
|
|
47
|
-
"@stryker-mutator/core": "
|
|
48
|
-
"@stryker-mutator/jest-runner": "
|
|
49
|
-
"@stryker-mutator/typescript-checker": "
|
|
50
|
-
"@swc/core": "1.3.
|
|
46
|
+
"@changesets/cli": "2.27.1",
|
|
47
|
+
"@stryker-mutator/core": "8.0.0",
|
|
48
|
+
"@stryker-mutator/jest-runner": "8.0.0",
|
|
49
|
+
"@stryker-mutator/typescript-checker": "8.0.0",
|
|
50
|
+
"@swc/core": "1.3.100",
|
|
51
51
|
"@swc/jest": "0.2.29",
|
|
52
52
|
"@testing-library/dom": "9.3.3",
|
|
53
|
-
"@types/jest": "29.5.
|
|
53
|
+
"@types/jest": "29.5.10",
|
|
54
54
|
"@types/js-yaml": "4.0.9",
|
|
55
|
-
"@types/koa": "2.13.
|
|
55
|
+
"@types/koa": "2.13.12",
|
|
56
56
|
"@types/koa-bodyparser": "4.3.12",
|
|
57
57
|
"@types/koa-proxy": "1.0.7",
|
|
58
58
|
"@types/koa-static": "4.0.4",
|
|
59
59
|
"copyfiles": "2.4.1",
|
|
60
|
-
"eslint": "8.
|
|
60
|
+
"eslint": "8.55.0",
|
|
61
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",
|
|
@@ -71,7 +71,7 @@
|
|
|
71
71
|
"husky": "8.0.3",
|
|
72
72
|
"jest": "29.7.0",
|
|
73
73
|
"node-mocks-http": "1.13.0",
|
|
74
|
-
"nodemon": "3.0.
|
|
74
|
+
"nodemon": "3.0.2",
|
|
75
75
|
"patch-package": "8.0.0",
|
|
76
76
|
"rimraf": "5.0.5",
|
|
77
77
|
"stryker-cli": "1.0.2",
|
|
@@ -84,20 +84,20 @@
|
|
|
84
84
|
"commander": "11.1.0",
|
|
85
85
|
"debug": "4.3.4",
|
|
86
86
|
"fetch": "1.1.0",
|
|
87
|
-
"fs-extra": "11.
|
|
87
|
+
"fs-extra": "11.2.0",
|
|
88
88
|
"handlebars": "4.7.8",
|
|
89
89
|
"http-terminator": "3.2.0",
|
|
90
90
|
"js-yaml": "4.1.0",
|
|
91
|
-
"json-schema-faker": "0.5.
|
|
91
|
+
"json-schema-faker": "0.5.4",
|
|
92
92
|
"json-schema-ref-parser": "9.0.9",
|
|
93
93
|
"jsonwebtoken": "9.0.2",
|
|
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.
|
|
97
|
+
"koa2-swagger-ui": "5.10.0",
|
|
98
98
|
"node-fetch": "3.3.2",
|
|
99
99
|
"open": "9.1.0",
|
|
100
|
-
"prettier": "3.0
|
|
101
|
-
"typescript": "5.
|
|
100
|
+
"prettier": "3.1.0",
|
|
101
|
+
"typescript": "5.3.2"
|
|
102
102
|
}
|
|
103
103
|
}
|