@sanity/cli
Version:
Sanity CLI tool for managing Sanity installations, managing plugins, schemas and datasets
163 lines (160 loc) • 8.93 kB
JavaScript
;
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