@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,53 @@
|
|
|
1
|
+
import createDebug from "debug";
|
|
2
|
+
import { OperationTypeCoder, } from "./operation-type-coder.js";
|
|
3
|
+
import { Specification } from "./specification.js";
|
|
4
|
+
const debug = createDebug("counterfact:typescript-generator:operation-type-name-mapping");
|
|
5
|
+
const HTTP_METHODS = new Set([
|
|
6
|
+
"GET",
|
|
7
|
+
"POST",
|
|
8
|
+
"PUT",
|
|
9
|
+
"DELETE",
|
|
10
|
+
"PATCH",
|
|
11
|
+
"HEAD",
|
|
12
|
+
"OPTIONS",
|
|
13
|
+
"QUERY",
|
|
14
|
+
]);
|
|
15
|
+
function openApiPathToFilePath(openApiPath) {
|
|
16
|
+
if (openApiPath === "/") {
|
|
17
|
+
return "index";
|
|
18
|
+
}
|
|
19
|
+
return openApiPath.startsWith("/") ? openApiPath.slice(1) : openApiPath;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Resolves the generated operation type name for each route and HTTP method.
|
|
23
|
+
* This is the migration-facing API; concrete coder and specification classes
|
|
24
|
+
* remain internal implementation details.
|
|
25
|
+
*/
|
|
26
|
+
export async function buildOperationTypeNameMapping(source, overlays = []) {
|
|
27
|
+
debug("building operation type name mapping from %s", source);
|
|
28
|
+
const specification = await Specification.fromFile(source, overlays);
|
|
29
|
+
const mapping = new Map();
|
|
30
|
+
const paths = specification.getRequirement("#/paths");
|
|
31
|
+
if (!paths) {
|
|
32
|
+
return mapping;
|
|
33
|
+
}
|
|
34
|
+
const securityRequirement = specification.getRequirement("#/components/securitySchemes");
|
|
35
|
+
const securitySchemes = Object.values(securityRequirement?.data ?? {});
|
|
36
|
+
paths.forEach((pathDefinition, openApiPath) => {
|
|
37
|
+
const methodMap = new Map();
|
|
38
|
+
pathDefinition.forEach((operation, requestMethod) => {
|
|
39
|
+
const method = requestMethod.toUpperCase();
|
|
40
|
+
if (!HTTP_METHODS.has(method)) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
const typeName = new OperationTypeCoder(operation, "", requestMethod, securitySchemes)
|
|
44
|
+
.names()
|
|
45
|
+
.next().value;
|
|
46
|
+
methodMap.set(method, typeName);
|
|
47
|
+
});
|
|
48
|
+
if (methodMap.size > 0) {
|
|
49
|
+
mapping.set(openApiPathToFilePath(openApiPath), methodMap);
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
return mapping;
|
|
53
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { TypeCoder } from "./type-coder.js";
|
|
2
|
+
import type { Requirement } from "./requirement.js";
|
|
3
|
+
export declare class ParameterExportTypeCoder extends TypeCoder {
|
|
4
|
+
_typeName: string;
|
|
5
|
+
_typeCode: string;
|
|
6
|
+
_parameterKind: string;
|
|
7
|
+
_modulePath: string;
|
|
8
|
+
constructor(requirement: Requirement, version: string, typeName: string, typeCode: string, parameterKind: string);
|
|
9
|
+
get id(): string;
|
|
10
|
+
names(): Generator<string>;
|
|
11
|
+
writeCode(): string;
|
|
12
|
+
modulePath(): string;
|
|
13
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { TypeCoder } from "./type-coder.js";
|
|
2
|
+
export class ParameterExportTypeCoder extends TypeCoder {
|
|
3
|
+
_typeName;
|
|
4
|
+
_typeCode;
|
|
5
|
+
_parameterKind;
|
|
6
|
+
_modulePath;
|
|
7
|
+
constructor(requirement, version, typeName, typeCode, parameterKind) {
|
|
8
|
+
super(requirement, version);
|
|
9
|
+
this._typeName = typeName;
|
|
10
|
+
this._typeCode = typeCode;
|
|
11
|
+
this._parameterKind = parameterKind;
|
|
12
|
+
}
|
|
13
|
+
get id() {
|
|
14
|
+
// Make the id unique by including the parameter kind
|
|
15
|
+
return `${super.id}:${this._parameterKind}`;
|
|
16
|
+
}
|
|
17
|
+
*names() {
|
|
18
|
+
yield this._typeName;
|
|
19
|
+
}
|
|
20
|
+
writeCode() {
|
|
21
|
+
return this._typeCode;
|
|
22
|
+
}
|
|
23
|
+
modulePath() {
|
|
24
|
+
// Use the same module path as the parent operation
|
|
25
|
+
return this._modulePath;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { TypeCoder } from "./type-coder.js";
|
|
2
|
+
import type { Requirement } from "./requirement.js";
|
|
3
|
+
import type { Script } from "./script.js";
|
|
4
|
+
export declare class ParametersTypeCoder extends TypeCoder {
|
|
5
|
+
placement: string;
|
|
6
|
+
constructor(requirement: Requirement, version?: string, placement?: string);
|
|
7
|
+
names(): Generator<string>;
|
|
8
|
+
writeCode(script: Script): string;
|
|
9
|
+
modulePath(): string;
|
|
10
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { pathJoin } from "./forward-slash-path.js";
|
|
2
|
+
import { buildJsDoc } from "./jsdoc.js";
|
|
3
|
+
import { SchemaTypeCoder } from "./schema-type-coder.js";
|
|
4
|
+
import { TypeCoder } from "./type-coder.js";
|
|
5
|
+
export class ParametersTypeCoder extends TypeCoder {
|
|
6
|
+
placement;
|
|
7
|
+
constructor(requirement, version = "", placement = "") {
|
|
8
|
+
super(requirement, version);
|
|
9
|
+
this.placement = placement;
|
|
10
|
+
}
|
|
11
|
+
names() {
|
|
12
|
+
return super.names("parameters");
|
|
13
|
+
}
|
|
14
|
+
writeCode(script) {
|
|
15
|
+
const typeDefinitions = (this.requirement?.data ?? [])
|
|
16
|
+
.map((_, index) => {
|
|
17
|
+
return this.requirement.get(index);
|
|
18
|
+
})
|
|
19
|
+
.filter((parameter) => parameter.get("in").data === this.placement)
|
|
20
|
+
.map((parameter) => {
|
|
21
|
+
const name = parameter.get("name")?.data;
|
|
22
|
+
const required = parameter.get("required")?.data;
|
|
23
|
+
const optionalFlag = required ? "" : "?";
|
|
24
|
+
const schema = parameter.has("schema")
|
|
25
|
+
? parameter.get("schema")
|
|
26
|
+
: parameter;
|
|
27
|
+
const comment = buildJsDoc(parameter.data);
|
|
28
|
+
const commentPrefix = comment ? `\n${comment}` : "";
|
|
29
|
+
const typeString = new SchemaTypeCoder(schema, this.version).write(script);
|
|
30
|
+
return `${commentPrefix}"${name}"${optionalFlag}: ${typeString}`;
|
|
31
|
+
});
|
|
32
|
+
if (typeDefinitions.length === 0) {
|
|
33
|
+
return "never";
|
|
34
|
+
}
|
|
35
|
+
return `{${typeDefinitions.join(", ")}}`;
|
|
36
|
+
}
|
|
37
|
+
modulePath() {
|
|
38
|
+
const pathString = this.requirement.url
|
|
39
|
+
.split("/")
|
|
40
|
+
.at(-2)
|
|
41
|
+
.replaceAll("~1", "/");
|
|
42
|
+
return `${pathJoin("parameters", pathString)}.types.ts`;
|
|
43
|
+
}
|
|
44
|
+
}
|
package/dist/printers.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export function printObjectWithoutQuotes(entries) {
|
|
2
|
+
return `{\n${entries
|
|
3
|
+
.map(([key, value]) => `${key}: ${value}`)
|
|
4
|
+
.join(",\n")}\n}`;
|
|
5
|
+
}
|
|
6
|
+
export function printObject(entries) {
|
|
7
|
+
return `{\n${entries
|
|
8
|
+
.map(([key, value]) => `"${key}": ${value}`)
|
|
9
|
+
.join(",\n")}\n}`;
|
|
10
|
+
}
|
package/dist/prune.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prunes route files that no longer correspond to any path in the OpenAPI spec.
|
|
3
|
+
* Context files (_.context.ts) are never pruned.
|
|
4
|
+
* @param destination - Base destination directory (contains the routes/ sub-directory)
|
|
5
|
+
* @param openApiPaths - Iterable of OpenAPI path strings (e.g. "/pet/{id}")
|
|
6
|
+
* @returns Number of files removed
|
|
7
|
+
*/
|
|
8
|
+
export declare function pruneRoutes(destination: string, openApiPaths: Iterable<string>): Promise<number>;
|
|
9
|
+
/**
|
|
10
|
+
* Prunes obsolete files from the OpenAPI generator-owned namespaces below
|
|
11
|
+
* `types/`. Hidden files are included by the recursive directory walk.
|
|
12
|
+
*
|
|
13
|
+
* `types/_.context.ts` and paths outside the known generated namespaces are
|
|
14
|
+
* preserved because separate generators or users own them.
|
|
15
|
+
*
|
|
16
|
+
* @param destination - Base destination directory (contains `types/`).
|
|
17
|
+
* @param expectedPaths - Repository-relative generated paths to retain.
|
|
18
|
+
* @returns Number of files removed.
|
|
19
|
+
*/
|
|
20
|
+
export declare function pruneTypes(destination: string, expectedPaths: Iterable<string>): Promise<number>;
|
package/dist/prune.js
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import nodePath from "node:path";
|
|
3
|
+
/* eslint-disable security/detect-non-literal-fs-filename -- pruning only traverses and removes files under generator-owned destination subdirectories. */
|
|
4
|
+
import createDebug from "debug";
|
|
5
|
+
import { toForwardSlashPath } from "./forward-slash-path.js";
|
|
6
|
+
import { normalizeOpenApiPath } from "./openapi-path.js";
|
|
7
|
+
const debug = createDebug("counterfact:typescript-generator:prune");
|
|
8
|
+
/**
|
|
9
|
+
* Collects all .ts route files in a directory recursively.
|
|
10
|
+
* Context files (_.context.ts) are excluded.
|
|
11
|
+
* @param routesDir - Path to routes directory
|
|
12
|
+
* @param currentPath - Current subdirectory being processed (relative to routesDir)
|
|
13
|
+
* @returns Array of relative paths (using forward slashes)
|
|
14
|
+
*/
|
|
15
|
+
async function collectTypeScriptFiles(rootDir, currentPath = "") {
|
|
16
|
+
const files = [];
|
|
17
|
+
try {
|
|
18
|
+
const fullDir = currentPath ? nodePath.join(rootDir, currentPath) : rootDir;
|
|
19
|
+
const entries = await fs.readdir(fullDir, { withFileTypes: true });
|
|
20
|
+
for (const entry of entries) {
|
|
21
|
+
const relativePath = currentPath
|
|
22
|
+
? `${currentPath}/${entry.name}`
|
|
23
|
+
: entry.name;
|
|
24
|
+
if (entry.isDirectory()) {
|
|
25
|
+
files.push(...(await collectTypeScriptFiles(rootDir, relativePath)));
|
|
26
|
+
}
|
|
27
|
+
else if (entry.name.endsWith(".ts")) {
|
|
28
|
+
files.push(relativePath);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
if (error.code !== "ENOENT") {
|
|
34
|
+
throw error;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return files;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Recursively removes empty directories under rootDir, but not rootDir itself.
|
|
41
|
+
* @param dir - Directory to check
|
|
42
|
+
* @param rootDir - Root directory that should never be removed
|
|
43
|
+
*/
|
|
44
|
+
async function removeEmptyDirectories(dir, rootDir) {
|
|
45
|
+
let entries;
|
|
46
|
+
try {
|
|
47
|
+
entries = await fs.readdir(dir, { withFileTypes: true });
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
debug("could not read directory %s: %o", dir, error);
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
for (const entry of entries) {
|
|
54
|
+
if (entry.isDirectory()) {
|
|
55
|
+
await removeEmptyDirectories(nodePath.join(dir, entry.name), rootDir);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
if (nodePath.resolve(dir) === nodePath.resolve(rootDir)) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
const remaining = await fs.readdir(dir);
|
|
62
|
+
if (remaining.length === 0) {
|
|
63
|
+
await fs.rmdir(dir);
|
|
64
|
+
debug("removed empty directory: %s", dir);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Converts an OpenAPI path to the expected route file path (relative to routesDir).
|
|
69
|
+
* e.g. "/pet/{id}" -> "pet/{id}.ts", "/" -> "index.ts"
|
|
70
|
+
* @param openApiPath - The OpenAPI path string
|
|
71
|
+
*/
|
|
72
|
+
function openApiPathToRouteFile(openApiPath) {
|
|
73
|
+
const normalizedPath = normalizeOpenApiPath(openApiPath);
|
|
74
|
+
const filePath = normalizedPath === "/" ? "index" : normalizedPath.slice(1);
|
|
75
|
+
return `${filePath}.ts`;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Prunes route files that no longer correspond to any path in the OpenAPI spec.
|
|
79
|
+
* Context files (_.context.ts) are never pruned.
|
|
80
|
+
* @param destination - Base destination directory (contains the routes/ sub-directory)
|
|
81
|
+
* @param openApiPaths - Iterable of OpenAPI path strings (e.g. "/pet/{id}")
|
|
82
|
+
* @returns Number of files removed
|
|
83
|
+
*/
|
|
84
|
+
export async function pruneRoutes(destination, openApiPaths) {
|
|
85
|
+
const routesDir = nodePath.join(destination, "routes");
|
|
86
|
+
const expectedFiles = new Set(Array.from(openApiPaths).map(openApiPathToRouteFile));
|
|
87
|
+
debug("expected route files: %o", Array.from(expectedFiles));
|
|
88
|
+
const actualFiles = (await collectTypeScriptFiles(routesDir)).filter((file) => nodePath.basename(file) !== "_.context.ts");
|
|
89
|
+
debug("actual route files: %o", actualFiles);
|
|
90
|
+
let prunedCount = 0;
|
|
91
|
+
for (const file of actualFiles) {
|
|
92
|
+
const normalizedFile = toForwardSlashPath(file);
|
|
93
|
+
if (!expectedFiles.has(normalizedFile)) {
|
|
94
|
+
const fullPath = nodePath.join(routesDir, file);
|
|
95
|
+
debug("pruning %s", fullPath);
|
|
96
|
+
await fs.rm(fullPath);
|
|
97
|
+
prunedCount++;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
await removeEmptyDirectories(routesDir, routesDir);
|
|
101
|
+
debug("pruned %d files", prunedCount);
|
|
102
|
+
return prunedCount;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Returns whether a path below `types/` belongs to a namespace populated by
|
|
106
|
+
* the OpenAPI generator. Context support and arbitrary user-authored type
|
|
107
|
+
* modules are deliberately outside this ownership policy.
|
|
108
|
+
*/
|
|
109
|
+
function isGeneratorOwnedTypePath(path) {
|
|
110
|
+
const [first, second] = toForwardSlashPath(path).split("/");
|
|
111
|
+
const generatedCategory = (segment) => segment === "paths" || segment === "components" || segment === "#";
|
|
112
|
+
return (path === "versions.ts" ||
|
|
113
|
+
generatedCategory(first) ||
|
|
114
|
+
generatedCategory(second));
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Prunes obsolete files from the OpenAPI generator-owned namespaces below
|
|
118
|
+
* `types/`. Hidden files are included by the recursive directory walk.
|
|
119
|
+
*
|
|
120
|
+
* `types/_.context.ts` and paths outside the known generated namespaces are
|
|
121
|
+
* preserved because separate generators or users own them.
|
|
122
|
+
*
|
|
123
|
+
* @param destination - Base destination directory (contains `types/`).
|
|
124
|
+
* @param expectedPaths - Repository-relative generated paths to retain.
|
|
125
|
+
* @returns Number of files removed.
|
|
126
|
+
*/
|
|
127
|
+
export async function pruneTypes(destination, expectedPaths) {
|
|
128
|
+
const typesDir = nodePath.join(destination, "types");
|
|
129
|
+
const expectedFiles = new Set(Array.from(expectedPaths, (path) => toForwardSlashPath(path).replace(/^types\//u, "")));
|
|
130
|
+
const actualFiles = (await collectTypeScriptFiles(typesDir)).filter(isGeneratorOwnedTypePath);
|
|
131
|
+
let prunedCount = 0;
|
|
132
|
+
debug("expected type files: %o", Array.from(expectedFiles));
|
|
133
|
+
debug("actual generated type files: %o", actualFiles);
|
|
134
|
+
for (const file of actualFiles) {
|
|
135
|
+
const normalizedFile = toForwardSlashPath(file);
|
|
136
|
+
if (!expectedFiles.has(normalizedFile)) {
|
|
137
|
+
const fullPath = nodePath.join(typesDir, file);
|
|
138
|
+
debug("pruning %s", fullPath);
|
|
139
|
+
await fs.rm(fullPath);
|
|
140
|
+
prunedCount++;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
await removeEmptyDirectories(typesDir, typesDir);
|
|
144
|
+
debug("pruned %d type files", prunedCount);
|
|
145
|
+
return prunedCount;
|
|
146
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const READ_ONLY_COMMENTS: string[];
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { Script } from "./script.js";
|
|
2
|
+
interface WriteFilesOptions {
|
|
3
|
+
routes?: boolean;
|
|
4
|
+
types?: boolean;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Collection of {@link Script} objects keyed by their repository-relative
|
|
8
|
+
* path.
|
|
9
|
+
*
|
|
10
|
+
* Coders call {@link get} to obtain (or create) the script where they should
|
|
11
|
+
* export their generated TypeScript. After all coders have been registered,
|
|
12
|
+
* {@link writeFiles} waits for every script to finish and writes the output to
|
|
13
|
+
* disk.
|
|
14
|
+
*/
|
|
15
|
+
export declare class Repository {
|
|
16
|
+
scripts: Map<string, Script>;
|
|
17
|
+
constructor();
|
|
18
|
+
/**
|
|
19
|
+
* Returns the {@link Script} for `path`, creating it if it does not yet
|
|
20
|
+
* exist.
|
|
21
|
+
*
|
|
22
|
+
* @param path - Repository-relative path (e.g. `"routes/pets.ts"`).
|
|
23
|
+
*/
|
|
24
|
+
get(path: string): Script;
|
|
25
|
+
/** Waits until all scripts have resolved all of their pending export promises. */
|
|
26
|
+
finished(): Promise<void>;
|
|
27
|
+
/**
|
|
28
|
+
* Copies the compiled `counterfact-types` directory from the Counterfact
|
|
29
|
+
* distribution into the generated output tree.
|
|
30
|
+
*
|
|
31
|
+
* Returns `false` when the source directory does not exist (e.g. running
|
|
32
|
+
* from source without a prior build).
|
|
33
|
+
*
|
|
34
|
+
* @param destination - The root of the generated output tree.
|
|
35
|
+
*/
|
|
36
|
+
copyCoreFiles(destination: string): Promise<boolean | void>;
|
|
37
|
+
/**
|
|
38
|
+
* Waits for all scripts to finish, then writes each one to disk.
|
|
39
|
+
*
|
|
40
|
+
* Route files (`routes/…`) are never fully overwritten if they already exist
|
|
41
|
+
* on disk, preserving user edits. However, if the generated script contains
|
|
42
|
+
* HTTP-method handler exports that are absent from the existing file, those
|
|
43
|
+
* new exports (and their `import type` statements) are appended to the file.
|
|
44
|
+
* Type files (`types/…`) are always overwritten.
|
|
45
|
+
*
|
|
46
|
+
* @param destination - Absolute path to the output root directory.
|
|
47
|
+
* @param options - Controls which artefacts are written.
|
|
48
|
+
*/
|
|
49
|
+
writeFiles(destination: string, { routes, types }: WriteFilesOptions): Promise<void>;
|
|
50
|
+
/**
|
|
51
|
+
* Creates the default `routes/_.context.ts` file if it does not already
|
|
52
|
+
* exist.
|
|
53
|
+
*
|
|
54
|
+
* @param destination - Absolute path to the output root directory.
|
|
55
|
+
*/
|
|
56
|
+
createDefaultContextFile(destination: string): Promise<void>;
|
|
57
|
+
/**
|
|
58
|
+
* Appends any HTTP-method handler exports that appear in `generatedContent`
|
|
59
|
+
* but are absent from the existing file at `fullPath`.
|
|
60
|
+
*
|
|
61
|
+
* For each new export the corresponding `import type` statement is inserted
|
|
62
|
+
* after the last existing import line (or prepended when no imports exist),
|
|
63
|
+
* and the export block is appended at the end of the file.
|
|
64
|
+
*
|
|
65
|
+
* @param fullPath - Absolute path of the route file to update.
|
|
66
|
+
* @param generatedContent - The fully-generated file content (used as the
|
|
67
|
+
* source of new import and export statements).
|
|
68
|
+
*/
|
|
69
|
+
private appendNewHandlers;
|
|
70
|
+
/**
|
|
71
|
+
* Returns the path of the `_.context.ts` file that is nearest to `path` in
|
|
72
|
+
* the directory hierarchy, relative to the script's output directory.
|
|
73
|
+
*
|
|
74
|
+
* @param destination - Output root directory.
|
|
75
|
+
* @param path - Repository-relative path of the script being generated.
|
|
76
|
+
*/
|
|
77
|
+
findContextPath(destination: string, path: string): string;
|
|
78
|
+
/**
|
|
79
|
+
* Walks up the directory tree from `path` to find the nearest
|
|
80
|
+
* `_.context.ts` file, falling back to `routes/_.context.ts` at the root.
|
|
81
|
+
*
|
|
82
|
+
* @param destination - Output root directory.
|
|
83
|
+
* @param path - Repository-relative path to start from.
|
|
84
|
+
*/
|
|
85
|
+
nearestContextFile(destination: string, path: string): string;
|
|
86
|
+
}
|
|
87
|
+
export {};
|