@counterfact/generator 0.1.1
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/License.md +21 -0
- package/README.md +18 -0
- package/dist/code-generator.d.ts +60 -0
- package/dist/code-generator.js +182 -0
- package/dist/coder.d.ts +107 -0
- package/dist/coder.js +132 -0
- package/dist/context-file-token.d.ts +1 -0
- package/dist/context-file-token.js +1 -0
- package/dist/ensure-directory-exists.d.ts +1 -0
- package/dist/ensure-directory-exists.js +12 -0
- package/dist/forward-slash-path.d.ts +9 -0
- package/dist/forward-slash-path.js +13 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +5 -0
- package/dist/jsdoc.d.ts +5 -0
- package/dist/jsdoc.js +49 -0
- package/dist/openapi-path.d.ts +11 -0
- package/dist/openapi-path.js +23 -0
- package/dist/operation-coder.d.ts +23 -0
- package/dist/operation-coder.js +73 -0
- package/dist/operation-type-coder.d.ts +140 -0
- package/dist/operation-type-coder.js +387 -0
- package/dist/operation-type-name-mapping.d.ts +7 -0
- package/dist/operation-type-name-mapping.js +53 -0
- package/dist/parameter-export-type-coder.d.ts +13 -0
- package/dist/parameter-export-type-coder.js +27 -0
- package/dist/parameters-type-coder.d.ts +10 -0
- package/dist/parameters-type-coder.js +44 -0
- package/dist/printers.d.ts +2 -0
- package/dist/printers.js +10 -0
- package/dist/prune.d.ts +20 -0
- package/dist/prune.js +146 -0
- package/dist/read-only-comments.d.ts +1 -0
- package/dist/read-only-comments.js +5 -0
- package/dist/repository.d.ts +87 -0
- package/dist/repository.js +264 -0
- package/dist/requirement.d.ts +104 -0
- package/dist/requirement.js +191 -0
- package/dist/reserved-words.d.ts +1 -0
- package/dist/reserved-words.js +50 -0
- package/dist/response-type-coder.d.ts +16 -0
- package/dist/response-type-coder.js +104 -0
- package/dist/responses-type-coder.d.ts +11 -0
- package/dist/responses-type-coder.js +43 -0
- package/dist/scenario-file-generator.d.ts +31 -0
- package/dist/scenario-file-generator.js +368 -0
- package/dist/schema-coder.d.ts +10 -0
- package/dist/schema-coder.js +49 -0
- package/dist/schema-type-coder.d.ts +20 -0
- package/dist/schema-type-coder.js +121 -0
- package/dist/script.d.ts +130 -0
- package/dist/script.js +322 -0
- package/dist/specification.d.ts +40 -0
- package/dist/specification.js +58 -0
- package/dist/templates/counterfact-types/cookie-options.ts +14 -0
- package/dist/templates/counterfact-types/counterfact-response.ts +15 -0
- package/dist/templates/counterfact-types/example-names.ts +13 -0
- package/dist/templates/counterfact-types/example.ts +14 -0
- package/dist/templates/counterfact-types/generic-response-builder.ts +167 -0
- package/dist/templates/counterfact-types/http-status-code.ts +62 -0
- package/dist/templates/counterfact-types/if-has-key.ts +19 -0
- package/dist/templates/counterfact-types/index.ts +30 -0
- package/dist/templates/counterfact-types/maybe-promise.ts +6 -0
- package/dist/templates/counterfact-types/media-type.ts +6 -0
- package/dist/templates/counterfact-types/middleware.ts +87 -0
- package/dist/templates/counterfact-types/omit-all.ts +11 -0
- package/dist/templates/counterfact-types/omit-value-when-never.ts +11 -0
- package/dist/templates/counterfact-types/open-api-content.ts +8 -0
- package/dist/templates/counterfact-types/open-api-header.ts +4 -0
- package/dist/templates/counterfact-types/open-api-operation.ts +36 -0
- package/dist/templates/counterfact-types/open-api-parameters.ts +26 -0
- package/dist/templates/counterfact-types/open-api-response.ts +22 -0
- package/dist/templates/counterfact-types/random-function.ts +9 -0
- package/dist/templates/counterfact-types/response-builder-factory.ts +16 -0
- package/dist/templates/counterfact-types/response-builder.ts +36 -0
- package/dist/templates/counterfact-types/wide-operation-argument.ts +20 -0
- package/dist/templates/counterfact-types/wide-response-builder.ts +28 -0
- package/dist/type-coder.d.ts +5 -0
- package/dist/type-coder.js +9 -0
- package/dist/versions-ts-generator.d.ts +10 -0
- package/dist/versions-ts-generator.js +82 -0
- package/dist/wait-for-event.d.ts +2 -0
- package/dist/wait-for-event.js +17 -0
- package/dist/watch-options.d.ts +5 -0
- package/dist/watch-options.js +5 -0
- package/dist/windows-escape.d.ts +1 -0
- package/dist/windows-escape.js +9 -0
- package/examples/generate-routes.mjs +40 -0
- package/package.json +61 -0
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generates the TypeScript source text for `types/versions.ts`.
|
|
3
|
+
*
|
|
4
|
+
* Returns an empty string when `versions` is empty.
|
|
5
|
+
* The returned string is formatted with Prettier.
|
|
6
|
+
*
|
|
7
|
+
* @param versions - Ordered list of unique, non-empty version strings.
|
|
8
|
+
* The first entry is the oldest version.
|
|
9
|
+
*/
|
|
10
|
+
export declare function generateVersionsTsContent(versions: readonly string[]): Promise<string>;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { format } from "prettier";
|
|
2
|
+
/**
|
|
3
|
+
* Builds the `VersionsGTE` map: for each version V at index i,
|
|
4
|
+
* maps V to all versions at indices >= i (i.e. V and all later-declared
|
|
5
|
+
* versions, where "later" means "newer").
|
|
6
|
+
*/
|
|
7
|
+
function buildVersionsGTE(versions) {
|
|
8
|
+
const result = new Map();
|
|
9
|
+
versions.forEach((version, index) => {
|
|
10
|
+
result.set(version, versions.slice(index));
|
|
11
|
+
});
|
|
12
|
+
return result;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Generates the TypeScript source text for `types/versions.ts`.
|
|
16
|
+
*
|
|
17
|
+
* Returns an empty string when `versions` is empty.
|
|
18
|
+
* The returned string is formatted with Prettier.
|
|
19
|
+
*
|
|
20
|
+
* @param versions - Ordered list of unique, non-empty version strings.
|
|
21
|
+
* The first entry is the oldest version.
|
|
22
|
+
*/
|
|
23
|
+
export async function generateVersionsTsContent(versions) {
|
|
24
|
+
if (versions.length === 0) {
|
|
25
|
+
return "";
|
|
26
|
+
}
|
|
27
|
+
const versionsUnion = versions.map((v) => `"${v}"`).join(" | ");
|
|
28
|
+
const versionsGTE = buildVersionsGTE(versions);
|
|
29
|
+
const versionsGTEBody = Array.from(versionsGTE, ([v, gte]) => ` "${v}": ${gte.map((g) => `"${g}"`).join(" | ")};`).join("\n");
|
|
30
|
+
const source = [
|
|
31
|
+
"// This file is auto-generated by Counterfact. Do not edit.",
|
|
32
|
+
"",
|
|
33
|
+
'/** Union of all version strings declared for this API group (e.g. `"v1" | "v2" | "v3"`). */',
|
|
34
|
+
`export type Versions = ${versionsUnion};`,
|
|
35
|
+
"",
|
|
36
|
+
"/**",
|
|
37
|
+
" * Maps each version to the set of versions that are greater than or equal to it.",
|
|
38
|
+
" * Used by `Versioned.minVersion()` to narrow which versions a handler must support.",
|
|
39
|
+
" */",
|
|
40
|
+
"export type VersionsGTE = {",
|
|
41
|
+
versionsGTEBody,
|
|
42
|
+
"};",
|
|
43
|
+
"",
|
|
44
|
+
"type VersionMap = Partial<Record<Versions, object>>;",
|
|
45
|
+
"",
|
|
46
|
+
"/**",
|
|
47
|
+
" * The type of the `$` argument in a versioned route handler.",
|
|
48
|
+
" *",
|
|
49
|
+
" * @typeParam T - A map from version string to the `$`-arg type for that version",
|
|
50
|
+
" * (e.g. `{ v1: $v1Type; v2: $v2Type }`). Generated by Counterfact from the spec.",
|
|
51
|
+
" * @typeParam V - The union of currently active version keys; defaults to all keys of `T`.",
|
|
52
|
+
" *",
|
|
53
|
+
" * An instance of `Versioned<T, V>` exposes:",
|
|
54
|
+
" * - All properties of the intersection `T[V]` (request data, response builders, etc.)",
|
|
55
|
+
' * - `version` — the version string for the current request (e.g. `"v2"`).',
|
|
56
|
+
" * - `minVersion(min)` — type predicate that returns `true` when the current version",
|
|
57
|
+
" * is at or after `min` in the declared version order and narrows `$` accordingly.",
|
|
58
|
+
" *",
|
|
59
|
+
" * @example",
|
|
60
|
+
" * ```ts",
|
|
61
|
+
" * export const GET: HTTP_GET = ($) => {",
|
|
62
|
+
' * if ($.minVersion("v2")) {',
|
|
63
|
+
" * // $ is now typed as the v2+ arg — v2-only fields are available",
|
|
64
|
+
" * return $.response[200].json({ id: $.path.id, extra: $.body.extra });",
|
|
65
|
+
" * }",
|
|
66
|
+
" * return $.response[200].json({ id: $.path.id });",
|
|
67
|
+
" * };",
|
|
68
|
+
" * ```",
|
|
69
|
+
" */",
|
|
70
|
+
"export type Versioned<",
|
|
71
|
+
" T extends VersionMap,",
|
|
72
|
+
" V extends keyof T & Versions = keyof T & Versions,",
|
|
73
|
+
"> = T[V] & {",
|
|
74
|
+
" version: V;",
|
|
75
|
+
" minVersion<M extends keyof T & Versions>(",
|
|
76
|
+
" min: M,",
|
|
77
|
+
" ): this is Versioned<T, Extract<V, VersionsGTE[M]>>;",
|
|
78
|
+
"};",
|
|
79
|
+
"",
|
|
80
|
+
].join("\n");
|
|
81
|
+
return format(source, { parser: "typescript" });
|
|
82
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { EventEmitter } from "node:events";
|
|
2
|
+
export async function waitForEvent(target, eventName) {
|
|
3
|
+
return await new Promise((resolve) => {
|
|
4
|
+
const handler = (event) => {
|
|
5
|
+
if (target instanceof EventTarget) {
|
|
6
|
+
target.removeEventListener(eventName, handler);
|
|
7
|
+
}
|
|
8
|
+
resolve(event);
|
|
9
|
+
};
|
|
10
|
+
if (target instanceof EventEmitter) {
|
|
11
|
+
target.once(eventName, handler);
|
|
12
|
+
}
|
|
13
|
+
else {
|
|
14
|
+
target.addEventListener(eventName, handler);
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function escapePathForWindows(path: string): string;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
const UNICODE_RATIO_SYMBOL = "∶";
|
|
2
|
+
const REGULAR_COLON = ":";
|
|
3
|
+
export function escapePathForWindows(path) {
|
|
4
|
+
if (path.at(1) === ":") {
|
|
5
|
+
return (path.slice(0, 2) +
|
|
6
|
+
path.slice(2).replaceAll(REGULAR_COLON, UNICODE_RATIO_SYMBOL));
|
|
7
|
+
}
|
|
8
|
+
return path.replaceAll(REGULAR_COLON, UNICODE_RATIO_SYMBOL);
|
|
9
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
|
|
6
|
+
import { CodeGenerator } from "@counterfact/generator";
|
|
7
|
+
|
|
8
|
+
const directory = await mkdtemp(path.join(tmpdir(), "counterfact-generator-"));
|
|
9
|
+
|
|
10
|
+
try {
|
|
11
|
+
const specPath = path.join(directory, "openapi.yaml");
|
|
12
|
+
const outputPath = path.join(directory, "generated");
|
|
13
|
+
await writeFile(
|
|
14
|
+
specPath,
|
|
15
|
+
`openapi: 3.0.3
|
|
16
|
+
info:
|
|
17
|
+
title: Package example
|
|
18
|
+
version: 1.0.0
|
|
19
|
+
paths:
|
|
20
|
+
/health:
|
|
21
|
+
get:
|
|
22
|
+
operationId: getHealth
|
|
23
|
+
responses:
|
|
24
|
+
"204":
|
|
25
|
+
description: Healthy
|
|
26
|
+
`,
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
await new CodeGenerator(specPath, outputPath, {
|
|
30
|
+
routes: true,
|
|
31
|
+
types: true,
|
|
32
|
+
}).generate();
|
|
33
|
+
|
|
34
|
+
assert.match(
|
|
35
|
+
await readFile(path.join(outputPath, "routes", "health.ts"), "utf8"),
|
|
36
|
+
/export const GET/u,
|
|
37
|
+
);
|
|
38
|
+
} finally {
|
|
39
|
+
await rm(directory, { force: true, recursive: true });
|
|
40
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@counterfact/generator",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "Generate Counterfact route scaffolds and OpenAPI-derived TypeScript contracts.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist",
|
|
16
|
+
"examples",
|
|
17
|
+
"README.md",
|
|
18
|
+
"License.md"
|
|
19
|
+
],
|
|
20
|
+
"sideEffects": false,
|
|
21
|
+
"author": "Patrick McElhaney <pmcelhaney@gmail.com>",
|
|
22
|
+
"license": "MIT",
|
|
23
|
+
"repository": {
|
|
24
|
+
"type": "git",
|
|
25
|
+
"url": "git+https://github.com/counterfact/api-simulator.git",
|
|
26
|
+
"directory": "packages/generator"
|
|
27
|
+
},
|
|
28
|
+
"bugs": "https://github.com/counterfact/api-simulator/issues",
|
|
29
|
+
"homepage": "https://counterfact.dev",
|
|
30
|
+
"funding": {
|
|
31
|
+
"type": "github",
|
|
32
|
+
"url": "https://github.com/sponsors/pmcelhaney"
|
|
33
|
+
},
|
|
34
|
+
"keywords": [
|
|
35
|
+
"counterfact",
|
|
36
|
+
"openapi",
|
|
37
|
+
"code-generator",
|
|
38
|
+
"api-mocking",
|
|
39
|
+
"typescript",
|
|
40
|
+
"testing"
|
|
41
|
+
],
|
|
42
|
+
"engines": {
|
|
43
|
+
"node": ">=22"
|
|
44
|
+
},
|
|
45
|
+
"publishConfig": {
|
|
46
|
+
"access": "public"
|
|
47
|
+
},
|
|
48
|
+
"scripts": {
|
|
49
|
+
"build": "rimraf dist && tsc --build --force && copyfiles -f \"../types/src/*.ts\" dist/templates/counterfact-types && rimraf dist/templates/counterfact-types/streaming-content-types.ts",
|
|
50
|
+
"prepack": "yarn build",
|
|
51
|
+
"test": "node --experimental-vm-modules ../../node_modules/jest-cli/bin/jest.js --config ../../jest.config.js packages/generator/test",
|
|
52
|
+
"test:packed-consumer": "node test/package/generator-consumer-smoke.mjs"
|
|
53
|
+
},
|
|
54
|
+
"dependencies": {
|
|
55
|
+
"@counterfact/openapi": "0.1.1",
|
|
56
|
+
"@counterfact/types": "0.1.0",
|
|
57
|
+
"chokidar": "5.0.0",
|
|
58
|
+
"debug": "4.4.3",
|
|
59
|
+
"prettier": "3.9.6"
|
|
60
|
+
}
|
|
61
|
+
}
|