UNPKG

@sanity/cli

Version:

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

163 lines (160 loc) • 8.93 kB
"use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf, __hasOwnProp = Object.prototype.hasOwnProperty; var __copyProps = (to, from, except, desc) => { if (from && typeof from == "object" || typeof from == "function") for (let key of __getOwnPropNames(from)) !__hasOwnProp.call(to, key) && key !== except && __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: !0 }) : target, mod )); var fs = require("node:fs/promises"), path = require("node:path"), process = require("node:process"), node_worker_threads = require("node:worker_threads"), codegen = require("@sanity/codegen"), workerChannels = require("@sanity/worker-channels"), chalk = require("chalk"), cliWorker = require("./cliWorker.js"), getCliConfig = require("./getCliConfig.js"), telemetry = require("@sanity/telemetry"); function _interopDefaultCompat(e) { return e && typeof e == "object" && "default" in e ? e : { default: e }; } var chalk__default = /* @__PURE__ */ _interopDefaultCompat(chalk); 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 getConfig(workDir, configPath) { const config = await getCliConfig.getCliConfig(workDir), legacyConfigPath = configPath || "sanity-typegen.json"; let hasLegacyConfig = !1; try { hasLegacyConfig = (await fs.stat(legacyConfigPath)).isFile(); } catch (err) { if (err.code === "ENOENT" && configPath) throw new Error(`Typegen config file not found: ${configPath}`, { cause: err }); if (err.code !== "ENOENT") throw new Error(`Error when checking if typegen config file exists: ${legacyConfigPath}`, { cause: err }); } return config?.config?.typegen && hasLegacyConfig ? (console.warn( chalk__default.default.yellow( `You've specified typegen in your Sanity CLI config, but also have a typegen config. The config from the Sanity CLI config is used. ` ) ), { config: codegen.configDefinition.parse(config.config.typegen || {}), path: config.path, type: "cli" }) : hasLegacyConfig ? (console.warn( chalk__default.default.yellow( "The separate typegen config has been deprecated. Use `typegen` in the sanity CLI config instead.\n\nSee: https://www.sanity.io/docs/help/configuring-typegen-in-sanity-cli-config" ) ), { config: await codegen.readConfig(legacyConfigPath), path: legacyConfigPath, type: "legacy" }) : { config: codegen.configDefinition.parse(config?.config?.typegen || {}), path: config?.path, type: "cli" }; } const formatter = new Intl.NumberFormat("en-US", { style: "percent", minimumFractionDigits: 1, maximumFractionDigits: 1 }), percent = (value) => formatter.format(Math.min(value, 1)), count = (amount, plural = "", singular = plural.slice(0, Math.max(0, plural.length - 1))) => [amount.toLocaleString("en-US"), amount === 1 ? singular : plural].filter(Boolean).join(" "), getMessage = (error) => typeof error == "object" && error && "message" in error && typeof error.message == "string" ? error.message : "Unknown error"; async function typegenGenerateAction({ extOptions: flags }, { output, workDir, telemetry: telemetry2 }) { const trace = telemetry2.trace(TypesGeneratedTrace); trace.start(); const spinner = output.spinner({}).start("Loading config\u2026"), { config: typegenConfig, type: typegenConfigMethod, path: configPath } = await getConfig(workDir, flags["config-path"]); spinner.succeed(`Config loaded from ${configPath?.replace(workDir, ".")}`); const { generates, path: searchPath, schema: schemaPath, formatGeneratedCode, overloadClientMethods } = typegenConfig, outputPath = path.isAbsolute(typegenConfig.generates) ? typegenConfig.generates : path.join(workDir, typegenConfig.generates), outputDir = path.dirname(outputPath); await fs.mkdir(outputDir, { recursive: !0 }); const workerPath = await cliWorker.getCliWorkerPath("typegenGenerate"), workerData = { workDir, schemaPath, searchPath, overloadClientMethods }, worker = new node_worker_threads.Worker(workerPath, { workerData, env: process.env }), receiver = workerChannels.WorkerChannelReceiver.from(worker); try { spinner.start("Loading schema\u2026"), await receiver.event.loadedSchema(), spinner.succeed(`Schema loaded from ${schemaPath}`), spinner.start("Generating schema types\u2026"); const { expectedFileCount } = await receiver.event.typegenStarted(), { schemaTypeDeclarations } = await receiver.event.generatedSchemaTypes(), schemaTypesCount = schemaTypeDeclarations.length; spinner.succeed(`Generated ${count(schemaTypesCount, "schema types")}`), spinner.start("Generating query types\u2026"); let queriesCount = 0, evaluatedFiles = 0, filesWithErrors = 0, queryFilesCount = 0, typeNodesGenerated = 0, unknownTypeNodesGenerated = 0, emptyUnionTypeNodesGenerated = 0; for await (const { queries, errors } of receiver.stream.evaluatedModules()) { evaluatedFiles++, queriesCount += queries.length, queryFilesCount += queries.length ? 1 : 0, filesWithErrors += errors.length ? 1 : 0; for (const { stats } of queries) typeNodesGenerated += stats.allTypes, unknownTypeNodesGenerated += stats.unknownTypes, emptyUnionTypeNodesGenerated += stats.emptyUnions; for (const error of errors) spinner.fail(getMessage(error)); spinner.text = `Generating query types\u2026 (${percent(evaluatedFiles / expectedFileCount)}) \u2514\u2500 Processed ${count(evaluatedFiles)} of ${count(expectedFileCount, "files")}. Found ${count(queriesCount, "queries", "query")} from ${count(queryFilesCount, "files")}.`; } const result = await receiver.event.typegenComplete(), code = `${generatedFileWarning}${result.code}`; if (await fs.writeFile(outputPath, code), spinner.succeed( `Generated ${count(queriesCount, "query types")} from ${count(queryFilesCount, "files")} out of ${count(evaluatedFiles, "scanned files")}` ), formatGeneratedCode) { spinner.start("Formatting generated types with prettier\u2026"); try { const prettier = await import("prettier"), prettierConfig = await prettier.resolveConfig(outputPath), formattedCode = await prettier.format(code, { ...prettierConfig, parser: "typescript" }); await fs.writeFile(outputPath, formattedCode), spinner.succeed("Formatted generated types with prettier"); } catch (err) { spinner.warn(`Failed to format generated types with prettier: ${getMessage(err)}`); } } trace.log({ configOverloadClientMethods: overloadClientMethods, outputSize: Buffer.byteLength(result.code), queriesCount, schemaTypesCount, queryFilesCount, filesWithErrors, typeNodesGenerated, unknownTypeNodesGenerated, emptyUnionTypeNodesGenerated, unknownTypeNodesRatio: typeNodesGenerated > 0 ? unknownTypeNodesGenerated / typeNodesGenerated : 0, configMethod: typegenConfigMethod }), filesWithErrors > 0 && spinner.warn( `Encountered errors in ${count(filesWithErrors, "files")} while generating types` ), spinner.succeed(`Successfully generated types to ${generates}`); } catch (err) { throw trace.error(err), err; } finally { receiver.unsubscribe(), trace.complete(), await worker.terminate(); } } exports.default = typegenGenerateAction; //# sourceMappingURL=generateAction.js.map