Skip to content

Commit 0f88d85

Browse files
authored
types refactor (#7817)
1 parent f6cc029 commit 0f88d85

File tree

2 files changed

+123
-126
lines changed

2 files changed

+123
-126
lines changed

packages/wrangler/src/index.ts

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ import {
140140
} from "./sentry";
141141
import { tailCommand } from "./tail";
142142
import registerTriggersSubcommands from "./triggers";
143-
import { typesHandler, typesOptions } from "./type-generation";
143+
import { typesCommand } from "./type-generation";
144144
import { getAuthFromEnv } from "./user";
145145
import { loginCommand, logoutCommand, whoamiCommand } from "./user/commands";
146146
import { whoami } from "./user/whoami";
@@ -473,12 +473,8 @@ export function createCLIParser(argv: string[]) {
473473
);
474474

475475
// types
476-
wrangler.command(
477-
"types [path]",
478-
"📝 Generate types from bindings and module rules in configuration\n",
479-
typesOptions,
480-
typesHandler
481-
);
476+
registry.define([{ command: "wrangler types", definition: typesCommand }]);
477+
registry.registerNamespace("types");
482478

483479
/******************** CMD GROUP ***********************/
484480
registry.define([

packages/wrangler/src/type-generation/index.ts

Lines changed: 120 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -2,159 +2,160 @@ import * as fs from "node:fs";
22
import { basename, dirname, extname, join, relative, resolve } from "node:path";
33
import { findUpSync } from "find-up";
44
import { getNodeCompat } from "miniflare";
5-
import { experimental_readRawConfig, readConfig } from "../config";
5+
import { experimental_readRawConfig } from "../config";
6+
import { createCommand } from "../core/create-command";
67
import { getEntry } from "../deployment-bundle/entry";
78
import { getVarsForDev } from "../dev/dev-vars";
89
import { CommandLineArgsError, UserError } from "../errors";
910
import { logger } from "../logger";
1011
import { parseJSONC } from "../parse";
11-
import { printWranglerBanner } from "../wrangler-banner";
1212
import { generateRuntimeTypes } from "./runtime";
1313
import { logRuntimeTypesMessage } from "./runtime/log-runtime-types-message";
1414
import type { Config, RawEnvironment } from "../config";
1515
import type { Entry } from "../deployment-bundle/entry";
1616
import type { CfScriptFormat } from "../deployment-bundle/worker";
17-
import type {
18-
CommonYargsArgv,
19-
StrictYargsOptionsToInterface,
20-
} from "../yargs-types";
21-
22-
export function typesOptions(yargs: CommonYargsArgv) {
23-
return yargs
24-
.positional("path", {
17+
18+
export const typesCommand = createCommand({
19+
metadata: {
20+
description:
21+
"📝 Generate types from bindings and module rules in configuration\n",
22+
status: "stable",
23+
owner: "Workers: Authoring and Testing",
24+
},
25+
positionalArgs: ["path"],
26+
args: {
27+
path: {
2528
describe: "The path to the declaration file to generate",
2629
type: "string",
2730
default: "worker-configuration.d.ts",
2831
demandOption: false,
29-
})
30-
.option("env-interface", {
32+
},
33+
"env-interface": {
3134
type: "string",
3235
default: "Env",
3336
describe: "The name of the generated environment interface",
3437
requiresArg: true,
35-
})
36-
.option("experimental-include-runtime", {
38+
},
39+
"experimental-include-runtime": {
3740
alias: "x-include-runtime",
3841
type: "string",
3942
describe: "The path of the generated runtime types file",
4043
demandOption: false,
41-
})
42-
.option("strict-vars", {
44+
},
45+
"strict-vars": {
4346
type: "boolean",
4447
default: true,
4548
describe: "Generate literal and union types for variables",
46-
});
47-
}
49+
},
50+
},
51+
validateArgs(args) {
52+
const { envInterface, path: outputPath } = args;
4853

49-
export async function typesHandler(
50-
args: StrictYargsOptionsToInterface<typeof typesOptions>
51-
) {
52-
const { envInterface, path: outputPath } = args;
54+
const validInterfaceRegex = /^[a-zA-Z][a-zA-Z0-9_]*$/;
5355

54-
const validInterfaceRegex = /^[a-zA-Z][a-zA-Z0-9_]*$/;
56+
if (!validInterfaceRegex.test(envInterface)) {
57+
throw new CommandLineArgsError(
58+
`The provided env-interface value ("${envInterface}") does not satisfy the validation regex: ${validInterfaceRegex}`
59+
);
60+
}
5561

56-
if (!validInterfaceRegex.test(envInterface)) {
57-
throw new CommandLineArgsError(
58-
`The provided env-interface value ("${envInterface}") does not satisfy the validation regex: ${validInterfaceRegex}`
59-
);
60-
}
62+
if (!outputPath.endsWith(".d.ts")) {
63+
throw new CommandLineArgsError(
64+
`The provided path value ("${outputPath}") does not point to a declaration file (please use the 'd.ts' extension)`
65+
);
66+
}
67+
},
68+
async handler(args, { config }) {
69+
const { envInterface, path: outputPath } = args;
6170

62-
if (!outputPath.endsWith(".d.ts")) {
63-
throw new CommandLineArgsError(
64-
`The provided path value ("${outputPath}") does not point to a declaration file (please use the 'd.ts' extension)`
65-
);
66-
}
71+
if (
72+
!config.configPath ||
73+
!fs.existsSync(config.configPath) ||
74+
fs.statSync(config.configPath).isDirectory()
75+
) {
76+
logger.warn(
77+
`No config file detected${
78+
args.config ? ` (at ${args.config})` : ""
79+
}, aborting`
80+
);
81+
return;
82+
}
6783

68-
await printWranglerBanner();
84+
// args.xRuntime will be a string if the user passes "--x-include-runtime" or "--x-include-runtime=..."
85+
if (typeof args.experimentalIncludeRuntime === "string") {
86+
logger.log(`Generating runtime types...`);
87+
88+
const { outFile } = await generateRuntimeTypes({
89+
config,
90+
outFile: args.experimentalIncludeRuntime || undefined,
91+
});
92+
93+
const tsconfigPath =
94+
config.tsconfig ?? join(dirname(config.configPath), "tsconfig.json");
95+
const tsconfigTypes = readTsconfigTypes(tsconfigPath);
96+
const { mode } = getNodeCompat(
97+
config.compatibility_date,
98+
config.compatibility_flags,
99+
{
100+
nodeCompat: config.node_compat,
101+
}
102+
);
69103

70-
const config = readConfig(args);
71-
if (
72-
!config.configPath ||
73-
!fs.existsSync(config.configPath) ||
74-
fs.statSync(config.configPath).isDirectory()
75-
) {
76-
logger.warn(
77-
`No config file detected${
78-
args.config ? ` (at ${args.config})` : ""
79-
}, aborting`
80-
);
81-
return;
82-
}
104+
logRuntimeTypesMessage(
105+
outFile,
106+
tsconfigTypes,
107+
mode !== null,
108+
config.configPath
109+
);
110+
}
83111

84-
// args.xRuntime will be a string if the user passes "--x-include-runtime" or "--x-include-runtime=..."
85-
if (typeof args.experimentalIncludeRuntime === "string") {
86-
logger.log(`Generating runtime types...`);
112+
const secrets = getVarsForDev(
113+
// We do not want `getVarsForDev()` to merge in the standard vars into the dev vars
114+
// because we want to be able to work with secrets differently to vars.
115+
// So we pass in a fake vars object here.
116+
{ ...config, vars: {} },
117+
args.env,
118+
true
119+
) as Record<string, string>;
120+
121+
const configBindingsWithSecrets = {
122+
kv_namespaces: config.kv_namespaces ?? [],
123+
vars: collectAllVars(args),
124+
wasm_modules: config.wasm_modules,
125+
text_blobs: {
126+
...config.text_blobs,
127+
},
128+
data_blobs: config.data_blobs,
129+
durable_objects: config.durable_objects,
130+
r2_buckets: config.r2_buckets,
131+
d1_databases: config.d1_databases,
132+
services: config.services,
133+
analytics_engine_datasets: config.analytics_engine_datasets,
134+
dispatch_namespaces: config.dispatch_namespaces,
135+
logfwdr: config.logfwdr,
136+
unsafe: config.unsafe,
137+
rules: config.rules,
138+
queues: config.queues,
139+
send_email: config.send_email,
140+
vectorize: config.vectorize,
141+
hyperdrive: config.hyperdrive,
142+
mtls_certificates: config.mtls_certificates,
143+
browser: config.browser,
144+
ai: config.ai,
145+
version_metadata: config.version_metadata,
146+
secrets,
147+
assets: config.assets,
148+
workflows: config.workflows,
149+
};
87150

88-
const { outFile } = await generateRuntimeTypes({
151+
await generateTypes(
152+
configBindingsWithSecrets,
89153
config,
90-
outFile: args.experimentalIncludeRuntime || undefined,
91-
});
92-
93-
const tsconfigPath =
94-
config.tsconfig ?? join(dirname(config.configPath), "tsconfig.json");
95-
const tsconfigTypes = readTsconfigTypes(tsconfigPath);
96-
const { mode } = getNodeCompat(
97-
config.compatibility_date,
98-
config.compatibility_flags,
99-
{
100-
nodeCompat: config.node_compat,
101-
}
102-
);
103-
104-
logRuntimeTypesMessage(
105-
outFile,
106-
tsconfigTypes,
107-
mode !== null,
108-
config.configPath
154+
envInterface,
155+
outputPath
109156
);
110-
}
111-
112-
const secrets = getVarsForDev(
113-
// We do not want `getVarsForDev()` to merge in the standard vars into the dev vars
114-
// because we want to be able to work with secrets differently to vars.
115-
// So we pass in a fake vars object here.
116-
{ ...config, vars: {} },
117-
args.env,
118-
true
119-
) as Record<string, string>;
120-
121-
const configBindingsWithSecrets = {
122-
kv_namespaces: config.kv_namespaces ?? [],
123-
vars: collectAllVars(args),
124-
wasm_modules: config.wasm_modules,
125-
text_blobs: {
126-
...config.text_blobs,
127-
},
128-
data_blobs: config.data_blobs,
129-
durable_objects: config.durable_objects,
130-
r2_buckets: config.r2_buckets,
131-
d1_databases: config.d1_databases,
132-
services: config.services,
133-
analytics_engine_datasets: config.analytics_engine_datasets,
134-
dispatch_namespaces: config.dispatch_namespaces,
135-
logfwdr: config.logfwdr,
136-
unsafe: config.unsafe,
137-
rules: config.rules,
138-
queues: config.queues,
139-
send_email: config.send_email,
140-
vectorize: config.vectorize,
141-
hyperdrive: config.hyperdrive,
142-
mtls_certificates: config.mtls_certificates,
143-
browser: config.browser,
144-
ai: config.ai,
145-
version_metadata: config.version_metadata,
146-
secrets,
147-
assets: config.assets,
148-
workflows: config.workflows,
149-
};
150-
151-
await generateTypes(
152-
configBindingsWithSecrets,
153-
config,
154-
envInterface,
155-
outputPath
156-
);
157-
}
157+
},
158+
});
158159

159160
/**
160161
* Check if a string is a valid TypeScript identifier. This is a naive check and doesn't cover all cases
@@ -584,7 +585,7 @@ type VarTypes = Record<string, string[]>;
584585
* @returns an object which keys are the variable names and values are arrays containing all the computed types for such variables
585586
*/
586587
function collectAllVars(
587-
args: StrictYargsOptionsToInterface<typeof typesOptions>
588+
args: (typeof typesCommand)["args"]
588589
): Record<string, string[]> {
589590
const varsInfo: Record<string, Set<string>> = {};
590591

0 commit comments

Comments
 (0)