UNPKG

@sanity/cli

Version:

Sanity CLI tool for managing Sanity installations, managing plugins, schemas and datasets

139 lines (137 loc) 6.32 kB
"use strict"; var fs = require("node:fs/promises"), path = require("node:path"), node_worker_threads = require("node:worker_threads"), codegen = require("@sanity/codegen"), prettier = require("prettier"), cliWorker = require("./cliWorker.js"), telemetry = require("@sanity/telemetry"); const TypesGeneratedTrace = telemetry.defineTrace({ name: "Types Generated", version: 0, description: "Trace emitted when generating TypeScript types for queries" }), generatedFileWarning = `/** * --------------------------------------------------------------------------------- * This file has been generated by Sanity TypeGen. * Command: \`sanity typegen generate\` * * Any modifications made directly to this file will be overwritten the next time * the TypeScript definitions are generated. Please make changes to the Sanity * schema definitions and/or GROQ queries if you need to update these types. * * For more information on how to use Sanity TypeGen, visit the official documentation: * https://www.sanity.io/docs/sanity-typegen * --------------------------------------------------------------------------------- */ `; async function typegenGenerateAction(args, context) { const flags = args.extOptions, { output, workDir, telemetry: telemetry2 } = context, trace = telemetry2.trace(TypesGeneratedTrace); trace.start(); const codegenConfig = await codegen.readConfig(flags["config-path"] || "sanity-typegen.json"); try { if (!(await fs.stat(codegenConfig.schema)).isFile()) throw new Error(`Schema path is not a file: ${codegenConfig.schema}`); } catch (err) { if (err.code === "ENOENT") { const hint = codegenConfig.schema === "./schema.json" ? ' - did you run "sanity schema extract"?' : ""; throw new Error(`Schema file not found: ${codegenConfig.schema}${hint}`); } throw err; } const outputPath = path.join(process.cwd(), codegenConfig.generates), outputDir = path.dirname(outputPath); await fs.mkdir(outputDir, { recursive: !0 }); const workerPath = await cliWorker.getCliWorkerPath("typegenGenerate"), spinner = output.spinner({}).start("Generating types"), worker = new node_worker_threads.Worker(workerPath, { workerData: { workDir, schemaPath: codegenConfig.schema, searchPath: codegenConfig.path, overloadClientMethods: codegenConfig.overloadClientMethods }, env: process.env }), typeFile = await fs.open( outputPath, // eslint-disable-next-line no-bitwise fs.constants.O_TRUNC | fs.constants.O_CREAT | fs.constants.O_WRONLY ); typeFile.write(generatedFileWarning); const stats = { queryFilesCount: 0, errors: 0, queriesCount: 0, schemaTypesCount: 0, unknownTypeNodesGenerated: 0, typeNodesGenerated: 0, emptyUnionTypeNodesGenerated: 0, size: 0 }; await new Promise((resolve, reject) => { worker.addListener("message", (msg) => { if (msg.type === "error") { if (msg.fatal) { trace.error(msg.error), reject(msg.error); return; } const errorMessage = msg.filename ? `${msg.error.message} in "${msg.filename}"` : msg.error.message; spinner.fail(errorMessage), stats.errors++; return; } if (msg.type === "complete") { resolve(); return; } if (msg.type === "typemap") { let typeMapStr = `// Query TypeMap `; typeMapStr += msg.typeMap, typeFile.write(typeMapStr), stats.size += Buffer.byteLength(typeMapStr); return; } let fileTypeString = `// Source: ${msg.filename} `; if (msg.type === "schema") { stats.schemaTypesCount += msg.length, fileTypeString += msg.schema, typeFile.write(fileTypeString); return; } if (msg.type === "types") { stats.queryFilesCount++; for (const { queryName, query, type, typeNodesGenerated, unknownTypeNodesGenerated, emptyUnionTypeNodesGenerated } of msg.types) fileTypeString += `// Variable: ${queryName} `, fileTypeString += `// Query: ${query.replace(/(\r\n|\n|\r)/gm, "").trim()} `, fileTypeString += type, stats.queriesCount++, stats.typeNodesGenerated += typeNodesGenerated, stats.unknownTypeNodesGenerated += unknownTypeNodesGenerated, stats.emptyUnionTypeNodesGenerated += emptyUnionTypeNodesGenerated; typeFile.write(`${fileTypeString} `), stats.size += Buffer.byteLength(fileTypeString); } }), worker.addListener("error", reject); }), await typeFile.close(); const prettierConfig = codegenConfig.formatGeneratedCode ? await prettier.resolveConfig(outputPath).catch((err) => (output.warn(`Failed to load prettier config: ${err.message}`), null)) : null; if (prettierConfig) { const formatFile = await fs.open(outputPath, fs.constants.O_RDWR); try { const code = await formatFile.readFile(), formattedCode = await prettier.format(code.toString(), { ...prettierConfig, parser: "typescript" }); await formatFile.truncate(), await formatFile.write(formattedCode, 0), spinner.info("Formatted generated types with Prettier"); } catch (err) { output.warn(`Failed to format generated types with Prettier: ${err.message}`); } finally { await formatFile.close(); } } trace.log({ outputSize: stats.size, queriesCount: stats.queriesCount, schemaTypesCount: stats.schemaTypesCount, queryFilesCount: stats.queryFilesCount, filesWithErrors: stats.errors, typeNodesGenerated: stats.typeNodesGenerated, unknownTypeNodesGenerated: stats.unknownTypeNodesGenerated, unknownTypeNodesRatio: stats.typeNodesGenerated > 0 ? stats.unknownTypeNodesGenerated / stats.typeNodesGenerated : 0, emptyUnionTypeNodesGenerated: stats.emptyUnionTypeNodesGenerated, configOverloadClientMethods: codegenConfig.overloadClientMethods }), trace.complete(), stats.errors > 0 && spinner.warn(`Encountered errors in ${stats.errors} files while generating types`), spinner.succeed( `Generated TypeScript types for ${stats.schemaTypesCount} schema types and ${stats.queriesCount} GROQ queries in ${stats.queryFilesCount} files into: ${codegenConfig.generates}` ); } exports.default = typegenGenerateAction; //# sourceMappingURL=generateAction.js.map