UNPKG

convex

Version:

Client for the Convex Cloud

291 lines (290 loc) 8.47 kB
"use strict"; import path from "path"; import prettier from "prettier"; import { withTmpDir } from "../../bundler/fs.js"; import { entryPoints } from "../../bundler/index.js"; import { apiCodegen } from "../codegen_templates/api.js"; import { apiCjsCodegen } from "../codegen_templates/api_cjs.js"; import { dataModel, dataModelWithoutSchema } from "../codegen_templates/dataModel.js"; import { readmeCodegen } from "../codegen_templates/readme.js"; import { serverCodegen } from "../codegen_templates/server.js"; import { tsconfigCodegen } from "../codegen_templates/tsconfig.js"; import { logError, logMessage, logOutput } from "../../bundler/context.js"; import { typeCheckFunctionsInMode } from "./typecheck.js"; import { readProjectConfig } from "./config.js"; import { recursivelyDelete } from "./fsUtils.js"; import { componentServerDTS, componentServerJS, componentServerStubDTS } from "../codegen_templates/component_server.js"; export async function doInitCodegen(ctx, functionsDir, skipIfExists, opts) { await withTmpDir(async (tmpDir) => { await doReadmeCodegen(ctx, tmpDir, functionsDir, skipIfExists, opts); await doTsconfigCodegen(ctx, tmpDir, functionsDir, skipIfExists, opts); }); } export async function doCodegen(ctx, functionsDir, typeCheckMode, opts) { const { projectConfig } = await readProjectConfig(ctx); const legacyCodegenPath = path.join(functionsDir, "_generated.ts"); if (ctx.fs.exists(legacyCodegenPath)) { if (opts?.dryRun) { logError( ctx, `Command would delete legacy codegen file: ${legacyCodegenPath}}` ); } else { logError(ctx, `Deleting legacy codegen file: ${legacyCodegenPath}}`); ctx.fs.unlink(legacyCodegenPath); } } const codegenDir = path.join(functionsDir, "_generated"); ctx.fs.mkdir(codegenDir, { allowExisting: true, recursive: true }); await withTmpDir(async (tmpDir) => { const writtenFiles = []; const schemaFiles = await doDataModelCodegen( ctx, tmpDir, functionsDir, codegenDir, opts ); writtenFiles.push(...schemaFiles); const serverFiles = await doServerCodegen(ctx, tmpDir, codegenDir, opts); writtenFiles.push(...serverFiles); const apiFiles = await doApiCodegen( ctx, tmpDir, functionsDir, codegenDir, opts?.generateCommonJSApi || projectConfig.generateCommonJSApi, opts ); writtenFiles.push(...apiFiles); for (const file of ctx.fs.listDir(codegenDir)) { if (!writtenFiles.includes(file.name)) { recursivelyDelete(ctx, path.join(codegenDir, file.name), opts); } } await typeCheckFunctionsInMode(ctx, typeCheckMode, functionsDir); }); } export async function doInitialComponentCodegen(ctx, tmpDir, componentDirectory, opts) { const { projectConfig } = await readProjectConfig(ctx); const codegenDir = path.join(componentDirectory.path, "_generated"); ctx.fs.mkdir(codegenDir, { allowExisting: true, recursive: true }); const writtenFiles = []; const schemaFiles = await doDataModelCodegen( ctx, tmpDir, componentDirectory.path, codegenDir, opts ); writtenFiles.push(...schemaFiles); const serverFiles = await doInitialComponentServerCodegen( ctx, componentDirectory.isRoot, tmpDir, codegenDir, opts ); writtenFiles.push(...serverFiles); const apiFiles = await doApiCodegen( ctx, tmpDir, componentDirectory.path, codegenDir, opts?.generateCommonJSApi || projectConfig.generateCommonJSApi, opts ); writtenFiles.push(...apiFiles); for (const file of ctx.fs.listDir(codegenDir)) { if (!writtenFiles.includes(file.name)) { recursivelyDelete(ctx, path.join(codegenDir, file.name), opts); } } } export async function doFinalComponentCodegen(ctx, tmpDir, rootComponent, componentDirectory, startPushResponse, opts) { const codegenDir = path.join(componentDirectory.path, "_generated"); ctx.fs.mkdir(codegenDir, { allowExisting: true, recursive: true }); const serverDTSPath = path.join(codegenDir, "server.d.ts"); const serverContents = await componentServerDTS( ctx, startPushResponse, rootComponent, componentDirectory ); await writeFormattedFile( ctx, tmpDir, serverContents, "typescript", serverDTSPath, opts ); } async function doReadmeCodegen(ctx, tmpDir, functionsDir, skipIfExists, opts) { const readmePath = path.join(functionsDir, "README.md"); if (skipIfExists && ctx.fs.exists(readmePath)) { logMessage(ctx, `Not overwriting README.md.`); return; } await writeFormattedFile( ctx, tmpDir, readmeCodegen(), "markdown", readmePath, opts ); } async function doTsconfigCodegen(ctx, tmpDir, functionsDir, skipIfExists, opts) { const tsconfigPath = path.join(functionsDir, "tsconfig.json"); if (skipIfExists && ctx.fs.exists(tsconfigPath)) { logMessage(ctx, `Not overwriting tsconfig.json.`); return; } await writeFormattedFile( ctx, tmpDir, tsconfigCodegen(), "json", tsconfigPath, opts ); } async function doDataModelCodegen(ctx, tmpDir, functionsDir, codegenDir, opts) { const schemaPath = path.join(functionsDir, "schema.ts"); const hasSchemaFile = ctx.fs.exists(schemaPath); const schemaContent = hasSchemaFile ? dataModel : dataModelWithoutSchema; await writeFormattedFile( ctx, tmpDir, schemaContent.DTS, "typescript", path.join(codegenDir, "dataModel.d.ts"), opts ); return ["dataModel.d.ts"]; } async function doServerCodegen(ctx, tmpDir, codegenDir, opts) { const serverContent = serverCodegen(); await writeFormattedFile( ctx, tmpDir, serverContent.JS, "typescript", path.join(codegenDir, "server.js"), opts ); await writeFormattedFile( ctx, tmpDir, serverContent.DTS, "typescript", path.join(codegenDir, "server.d.ts"), opts ); return ["server.js", "server.d.ts"]; } async function doInitialComponentServerCodegen(ctx, isRoot, tmpDir, codegenDir, opts) { await writeFormattedFile( ctx, tmpDir, componentServerJS(isRoot), "typescript", path.join(codegenDir, "server.js"), opts ); const serverDTSPath = path.join(codegenDir, "server.d.ts"); if (!ctx.fs.exists(serverDTSPath)) { await writeFormattedFile( ctx, tmpDir, componentServerStubDTS(isRoot), "typescript", path.join(codegenDir, "server.d.ts"), opts ); } return ["server.js", "server.d.ts"]; } async function doApiCodegen(ctx, tmpDir, functionsDir, codegenDir, generateCommonJSApi, opts) { const absModulePaths = await entryPoints(ctx, functionsDir, false); const modulePaths = absModulePaths.map((p) => path.relative(functionsDir, p)); const apiContent = apiCodegen(modulePaths); await writeFormattedFile( ctx, tmpDir, apiContent.JS, "typescript", path.join(codegenDir, "api.js"), opts ); await writeFormattedFile( ctx, tmpDir, apiContent.DTS, "typescript", path.join(codegenDir, "api.d.ts"), opts ); const writtenFiles = ["api.js", "api.d.ts"]; if (generateCommonJSApi) { const apiCjsContent = apiCjsCodegen(modulePaths); await writeFormattedFile( ctx, tmpDir, apiCjsContent.JS, "typescript", path.join(codegenDir, "api_cjs.cjs"), opts ); await writeFormattedFile( ctx, tmpDir, apiCjsContent.DTS, "typescript", path.join(codegenDir, "api_cjs.d.cts"), opts ); writtenFiles.push("api_cjs.cjs", "api_cjs.d.cts"); } return writtenFiles; } async function writeFormattedFile(ctx, tmpDir, contents, filetype, destination, options) { const formattedContents = await prettier.format(contents, { parser: filetype, pluginSearchDirs: false }); if (options?.debug) { logOutput(ctx, `# ${path.basename(destination)}`); logOutput(ctx, formattedContents); return; } try { const existing = ctx.fs.readUtf8File(destination); if (existing === formattedContents) { return; } } catch (err) { if (err.code !== "ENOENT") { throw err; } } if (options?.dryRun) { logOutput(ctx, `Command would write file: ${destination}`); return; } const tmpPath = tmpDir.writeUtf8File(formattedContents); ctx.fs.swapTmpFile(tmpPath, destination); } //# sourceMappingURL=codegen.js.map