@sanity/cli 8.14.0 → 8.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/actions/init/project/getProjectDetails.js +1 -0
- package/dist/actions/init/project/getProjectDetails.js.map +1 -1
- package/dist/actions/typegen/fetchResourceSchema.js +40 -0
- package/dist/actions/typegen/fetchResourceSchema.js.map +1 -0
- package/dist/actions/typegen/generateResourceTypes.js +115 -0
- package/dist/actions/typegen/generateResourceTypes.js.map +1 -0
- package/dist/actions/typegen/parseTypegenResources.js +92 -0
- package/dist/actions/typegen/parseTypegenResources.js.map +1 -0
- package/dist/commands/typegen/generate.js +59 -5
- package/dist/commands/typegen/generate.js.map +1 -1
- package/dist/generated/apiRoutes.js +2 -0
- package/dist/generated/apiRoutes.js.map +1 -1
- package/dist/server/vite/plugin-typegen.js +10 -0
- package/dist/server/vite/plugin-typegen.js.map +1 -1
- package/dist/services/schemas.js +36 -0
- package/dist/services/schemas.js.map +1 -1
- package/oclif.manifest.json +163 -163
- package/package.json +18 -17
- package/templates/shared/dashboard/app-quickstart/AGENTS.md +1 -1
- package/templates/shared/dashboard/app-quickstart/README.md +1 -1
- package/templates/shared/dashboard/app-sanity-ui/AGENTS.md +1 -1
- package/templates/shared/dashboard/app-sanity-ui/README.md +1 -1
|
@@ -80,6 +80,7 @@ export async function getProjectDetails({ coupon, dataset, datasetDefault, isApp
|
|
|
80
80
|
datasetName: datasetResult.datasetName,
|
|
81
81
|
displayName: projectResult.displayName,
|
|
82
82
|
isFirstProject: projectResult.isFirstProject,
|
|
83
|
+
organizationId: projectResult.organizationId,
|
|
83
84
|
projectId: projectResult.projectId
|
|
84
85
|
};
|
|
85
86
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/actions/init/project/getProjectDetails.ts"],"sourcesContent":["import {type SanityOrgUser, subdebug, type TelemetryUserProperties} from '@sanity/cli-core'\nimport {type TelemetryTrace} from '@sanity/telemetry'\n\nimport {listOrganizations, type ProjectOrganization} from '../../../services/organizations.js'\nimport {type InitStepResult} from '../../../telemetry/init.telemetry.js'\nimport {InitError} from '../initError.js'\nimport {type InitContext} from '../types.js'\nimport {getOrCreateDataset} from './getOrCreateDataset.js'\nimport {getOrCreateProject} from './getOrCreateProject.js'\nimport {promptForAppTemplateSetup} from './promptForAppTemplateSetup.js'\nimport {promptUserForOrganization} from './promptUserForOrganization.js'\n\nconst debug = subdebug('init')\n\nexport async function getProjectDetails({\n coupon,\n dataset,\n datasetDefault,\n isAppTemplate,\n newProject,\n organization,\n output,\n planId,\n project,\n showDefaultConfigPrompt,\n trace,\n unattended,\n user,\n visibility,\n}: {\n coupon: string | undefined\n dataset: string | undefined\n datasetDefault: boolean\n isAppTemplate: boolean\n newProject: string | undefined\n organization: string | undefined\n output: InitContext['output']\n planId: string | undefined\n project: string | undefined\n showDefaultConfigPrompt: boolean\n trace: TelemetryTrace<TelemetryUserProperties, InitStepResult>\n unattended: boolean\n user: SanityOrgUser\n visibility: 'private' | 'public' | undefined\n}): Promise<{\n datasetName: string\n displayName: string\n isFirstProject: boolean\n organizationId?: string\n projectId: string\n schemaUrl?: string\n}> {\n if (isAppTemplate) {\n const hasProjectFlag = Boolean(project || newProject)\n let appOrganizationId: string | undefined = organization\n if (!appOrganizationId && !hasProjectFlag) {\n let organizations: ProjectOrganization[]\n try {\n organizations = await listOrganizations()\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err)\n throw new InitError(`Failed to communicate with the Sanity API:\\n${message}`, 1)\n }\n appOrganizationId = await promptUserForOrganization({\n isAppTemplate: true,\n organizations,\n user,\n })\n }\n\n const {\n datasetName: appDatasetName,\n displayName: appDisplayName,\n organizationId: resolvedOrganizationId,\n projectId: appProjectId,\n } = await promptForAppTemplateSetup({\n coupon,\n dataset,\n datasetDefault,\n newProject,\n organization,\n organizationId: appOrganizationId,\n output,\n planId,\n project,\n trace,\n unattended,\n user,\n visibility,\n })\n\n return {\n datasetName: appDatasetName,\n displayName: appDisplayName,\n isFirstProject: false,\n organizationId: resolvedOrganizationId ?? appOrganizationId,\n projectId: appProjectId,\n }\n }\n\n debug('Prompting user to select or create a project')\n const projectResult = await getOrCreateProject({\n coupon,\n newProject,\n organization,\n planId,\n project,\n unattended,\n user,\n })\n debug(`Project with name ${projectResult.displayName} selected`)\n\n debug('Prompting user to select or create a dataset')\n const datasetResult = await getOrCreateDataset({\n dataset,\n defaultConfig: datasetDefault || undefined,\n displayName: projectResult.displayName,\n output,\n projectId: projectResult.projectId,\n showDefaultConfigPrompt,\n unattended,\n visibility,\n })\n debug(`Dataset with name ${datasetResult.datasetName} selected`)\n\n trace.log({\n datasetName: datasetResult.datasetName,\n selectedOption: datasetResult.userAction,\n step: 'createOrSelectDataset',\n visibility,\n })\n\n return {\n datasetName: datasetResult.datasetName,\n displayName: projectResult.displayName,\n isFirstProject: projectResult.isFirstProject,\n projectId: projectResult.projectId,\n }\n}\n"],"names":["subdebug","listOrganizations","InitError","getOrCreateDataset","getOrCreateProject","promptForAppTemplateSetup","promptUserForOrganization","debug","getProjectDetails","coupon","dataset","datasetDefault","isAppTemplate","newProject","organization","output","planId","project","showDefaultConfigPrompt","trace","unattended","user","visibility","hasProjectFlag","Boolean","appOrganizationId","organizations","err","message","Error","String","datasetName","appDatasetName","displayName","appDisplayName","organizationId","resolvedOrganizationId","projectId","appProjectId","isFirstProject","projectResult","datasetResult","defaultConfig","undefined","log","selectedOption","userAction","step"],"mappings":"AAAA,SAA4BA,QAAQ,QAAqC,mBAAkB;AAG3F,SAAQC,iBAAiB,QAAiC,qCAAoC;AAE9F,SAAQC,SAAS,QAAO,kBAAiB;AAEzC,SAAQC,kBAAkB,QAAO,0BAAyB;AAC1D,SAAQC,kBAAkB,QAAO,0BAAyB;AAC1D,SAAQC,yBAAyB,QAAO,iCAAgC;AACxE,SAAQC,yBAAyB,QAAO,iCAAgC;AAExE,MAAMC,QAAQP,SAAS;AAEvB,OAAO,eAAeQ,kBAAkB,EACtCC,MAAM,EACNC,OAAO,EACPC,cAAc,EACdC,aAAa,EACbC,UAAU,EACVC,YAAY,EACZC,MAAM,EACNC,MAAM,EACNC,OAAO,EACPC,uBAAuB,EACvBC,KAAK,EACLC,UAAU,EACVC,IAAI,EACJC,UAAU,EAgBX;IAQC,IAAIV,eAAe;QACjB,MAAMW,iBAAiBC,QAAQP,WAAWJ;QAC1C,IAAIY,oBAAwCX;QAC5C,IAAI,CAACW,qBAAqB,CAACF,gBAAgB;YACzC,IAAIG;YACJ,IAAI;gBACFA,gBAAgB,MAAMzB;YACxB,EAAE,OAAO0B,KAAc;gBACrB,MAAMC,UAAUD,eAAeE,QAAQF,IAAIC,OAAO,GAAGE,OAAOH;gBAC5D,MAAM,IAAIzB,UAAU,CAAC,4CAA4C,EAAE0B,SAAS,EAAE;YAChF;YACAH,oBAAoB,MAAMnB,0BAA0B;gBAClDM,eAAe;gBACfc;gBACAL;YACF;QACF;QAEA,MAAM,EACJU,aAAaC,cAAc,EAC3BC,aAAaC,cAAc,EAC3BC,gBAAgBC,sBAAsB,EACtCC,WAAWC,YAAY,EACxB,GAAG,MAAMjC,0BAA0B;YAClCI;YACAC;YACAC;YACAE;YACAC;YACAqB,gBAAgBV;YAChBV;YACAC;YACAC;YACAE;YACAC;YACAC;YACAC;QACF;QAEA,OAAO;YACLS,aAAaC;YACbC,aAAaC;YACbK,gBAAgB;YAChBJ,gBAAgBC,0BAA0BX;YAC1CY,WAAWC;QACb;IACF;IAEA/B,MAAM;IACN,MAAMiC,gBAAgB,MAAMpC,mBAAmB;QAC7CK;QACAI;QACAC;QACAE;QACAC;QACAG;QACAC;IACF;IACAd,MAAM,CAAC,kBAAkB,EAAEiC,cAAcP,WAAW,CAAC,SAAS,CAAC;IAE/D1B,MAAM;IACN,MAAMkC,gBAAgB,MAAMtC,mBAAmB;QAC7CO;QACAgC,eAAe/B,kBAAkBgC;QACjCV,aAAaO,cAAcP,WAAW;QACtClB;QACAsB,WAAWG,cAAcH,SAAS;QAClCnB;QACAE;QACAE;IACF;IACAf,MAAM,CAAC,kBAAkB,EAAEkC,cAAcV,WAAW,CAAC,SAAS,CAAC;IAE/DZ,MAAMyB,GAAG,CAAC;QACRb,aAAaU,cAAcV,WAAW;QACtCc,gBAAgBJ,cAAcK,UAAU;QACxCC,MAAM;QACNzB;IACF;IAEA,OAAO;QACLS,aAAaU,cAAcV,WAAW;QACtCE,aAAaO,cAAcP,WAAW;QACtCM,gBAAgBC,cAAcD,cAAc;
|
|
1
|
+
{"version":3,"sources":["../../../../src/actions/init/project/getProjectDetails.ts"],"sourcesContent":["import {type SanityOrgUser, subdebug, type TelemetryUserProperties} from '@sanity/cli-core'\nimport {type TelemetryTrace} from '@sanity/telemetry'\n\nimport {listOrganizations, type ProjectOrganization} from '../../../services/organizations.js'\nimport {type InitStepResult} from '../../../telemetry/init.telemetry.js'\nimport {InitError} from '../initError.js'\nimport {type InitContext} from '../types.js'\nimport {getOrCreateDataset} from './getOrCreateDataset.js'\nimport {getOrCreateProject} from './getOrCreateProject.js'\nimport {promptForAppTemplateSetup} from './promptForAppTemplateSetup.js'\nimport {promptUserForOrganization} from './promptUserForOrganization.js'\n\nconst debug = subdebug('init')\n\nexport async function getProjectDetails({\n coupon,\n dataset,\n datasetDefault,\n isAppTemplate,\n newProject,\n organization,\n output,\n planId,\n project,\n showDefaultConfigPrompt,\n trace,\n unattended,\n user,\n visibility,\n}: {\n coupon: string | undefined\n dataset: string | undefined\n datasetDefault: boolean\n isAppTemplate: boolean\n newProject: string | undefined\n organization: string | undefined\n output: InitContext['output']\n planId: string | undefined\n project: string | undefined\n showDefaultConfigPrompt: boolean\n trace: TelemetryTrace<TelemetryUserProperties, InitStepResult>\n unattended: boolean\n user: SanityOrgUser\n visibility: 'private' | 'public' | undefined\n}): Promise<{\n datasetName: string\n displayName: string\n isFirstProject: boolean\n organizationId?: string\n projectId: string\n schemaUrl?: string\n}> {\n if (isAppTemplate) {\n const hasProjectFlag = Boolean(project || newProject)\n let appOrganizationId: string | undefined = organization\n if (!appOrganizationId && !hasProjectFlag) {\n let organizations: ProjectOrganization[]\n try {\n organizations = await listOrganizations()\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err)\n throw new InitError(`Failed to communicate with the Sanity API:\\n${message}`, 1)\n }\n appOrganizationId = await promptUserForOrganization({\n isAppTemplate: true,\n organizations,\n user,\n })\n }\n\n const {\n datasetName: appDatasetName,\n displayName: appDisplayName,\n organizationId: resolvedOrganizationId,\n projectId: appProjectId,\n } = await promptForAppTemplateSetup({\n coupon,\n dataset,\n datasetDefault,\n newProject,\n organization,\n organizationId: appOrganizationId,\n output,\n planId,\n project,\n trace,\n unattended,\n user,\n visibility,\n })\n\n return {\n datasetName: appDatasetName,\n displayName: appDisplayName,\n isFirstProject: false,\n organizationId: resolvedOrganizationId ?? appOrganizationId,\n projectId: appProjectId,\n }\n }\n\n debug('Prompting user to select or create a project')\n const projectResult = await getOrCreateProject({\n coupon,\n newProject,\n organization,\n planId,\n project,\n unattended,\n user,\n })\n debug(`Project with name ${projectResult.displayName} selected`)\n\n debug('Prompting user to select or create a dataset')\n const datasetResult = await getOrCreateDataset({\n dataset,\n defaultConfig: datasetDefault || undefined,\n displayName: projectResult.displayName,\n output,\n projectId: projectResult.projectId,\n showDefaultConfigPrompt,\n unattended,\n visibility,\n })\n debug(`Dataset with name ${datasetResult.datasetName} selected`)\n\n trace.log({\n datasetName: datasetResult.datasetName,\n selectedOption: datasetResult.userAction,\n step: 'createOrSelectDataset',\n visibility,\n })\n\n return {\n datasetName: datasetResult.datasetName,\n displayName: projectResult.displayName,\n isFirstProject: projectResult.isFirstProject,\n organizationId: projectResult.organizationId,\n projectId: projectResult.projectId,\n }\n}\n"],"names":["subdebug","listOrganizations","InitError","getOrCreateDataset","getOrCreateProject","promptForAppTemplateSetup","promptUserForOrganization","debug","getProjectDetails","coupon","dataset","datasetDefault","isAppTemplate","newProject","organization","output","planId","project","showDefaultConfigPrompt","trace","unattended","user","visibility","hasProjectFlag","Boolean","appOrganizationId","organizations","err","message","Error","String","datasetName","appDatasetName","displayName","appDisplayName","organizationId","resolvedOrganizationId","projectId","appProjectId","isFirstProject","projectResult","datasetResult","defaultConfig","undefined","log","selectedOption","userAction","step"],"mappings":"AAAA,SAA4BA,QAAQ,QAAqC,mBAAkB;AAG3F,SAAQC,iBAAiB,QAAiC,qCAAoC;AAE9F,SAAQC,SAAS,QAAO,kBAAiB;AAEzC,SAAQC,kBAAkB,QAAO,0BAAyB;AAC1D,SAAQC,kBAAkB,QAAO,0BAAyB;AAC1D,SAAQC,yBAAyB,QAAO,iCAAgC;AACxE,SAAQC,yBAAyB,QAAO,iCAAgC;AAExE,MAAMC,QAAQP,SAAS;AAEvB,OAAO,eAAeQ,kBAAkB,EACtCC,MAAM,EACNC,OAAO,EACPC,cAAc,EACdC,aAAa,EACbC,UAAU,EACVC,YAAY,EACZC,MAAM,EACNC,MAAM,EACNC,OAAO,EACPC,uBAAuB,EACvBC,KAAK,EACLC,UAAU,EACVC,IAAI,EACJC,UAAU,EAgBX;IAQC,IAAIV,eAAe;QACjB,MAAMW,iBAAiBC,QAAQP,WAAWJ;QAC1C,IAAIY,oBAAwCX;QAC5C,IAAI,CAACW,qBAAqB,CAACF,gBAAgB;YACzC,IAAIG;YACJ,IAAI;gBACFA,gBAAgB,MAAMzB;YACxB,EAAE,OAAO0B,KAAc;gBACrB,MAAMC,UAAUD,eAAeE,QAAQF,IAAIC,OAAO,GAAGE,OAAOH;gBAC5D,MAAM,IAAIzB,UAAU,CAAC,4CAA4C,EAAE0B,SAAS,EAAE;YAChF;YACAH,oBAAoB,MAAMnB,0BAA0B;gBAClDM,eAAe;gBACfc;gBACAL;YACF;QACF;QAEA,MAAM,EACJU,aAAaC,cAAc,EAC3BC,aAAaC,cAAc,EAC3BC,gBAAgBC,sBAAsB,EACtCC,WAAWC,YAAY,EACxB,GAAG,MAAMjC,0BAA0B;YAClCI;YACAC;YACAC;YACAE;YACAC;YACAqB,gBAAgBV;YAChBV;YACAC;YACAC;YACAE;YACAC;YACAC;YACAC;QACF;QAEA,OAAO;YACLS,aAAaC;YACbC,aAAaC;YACbK,gBAAgB;YAChBJ,gBAAgBC,0BAA0BX;YAC1CY,WAAWC;QACb;IACF;IAEA/B,MAAM;IACN,MAAMiC,gBAAgB,MAAMpC,mBAAmB;QAC7CK;QACAI;QACAC;QACAE;QACAC;QACAG;QACAC;IACF;IACAd,MAAM,CAAC,kBAAkB,EAAEiC,cAAcP,WAAW,CAAC,SAAS,CAAC;IAE/D1B,MAAM;IACN,MAAMkC,gBAAgB,MAAMtC,mBAAmB;QAC7CO;QACAgC,eAAe/B,kBAAkBgC;QACjCV,aAAaO,cAAcP,WAAW;QACtClB;QACAsB,WAAWG,cAAcH,SAAS;QAClCnB;QACAE;QACAE;IACF;IACAf,MAAM,CAAC,kBAAkB,EAAEkC,cAAcV,WAAW,CAAC,SAAS,CAAC;IAE/DZ,MAAMyB,GAAG,CAAC;QACRb,aAAaU,cAAcV,WAAW;QACtCc,gBAAgBJ,cAAcK,UAAU;QACxCC,MAAM;QACNzB;IACF;IAEA,OAAO;QACLS,aAAaU,cAAcV,WAAW;QACtCE,aAAaO,cAAcP,WAAW;QACtCM,gBAAgBC,cAAcD,cAAc;QAC5CJ,gBAAgBK,cAAcL,cAAc;QAC5CE,WAAWG,cAAcH,SAAS;IACpC;AACF"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { convertToDefinition } from '@sanity/schema-descriptor-utils';
|
|
2
|
+
import { createSchemaFromManifestTypes, extractSchema } from '@sanity/schema/_internal';
|
|
3
|
+
import { getDatasetSchemaBinding, getSchemaDescriptor } from '../../services/schemas.js';
|
|
4
|
+
import { getResourceKey } from './parseTypegenResources.js';
|
|
5
|
+
/**
|
|
6
|
+
* Fetches the schema bound to a resource's dataset and extracts it for typegen.
|
|
7
|
+
*
|
|
8
|
+
* Throws when the dataset has no binding, naming the resource so the user can set a local
|
|
9
|
+
* `schema` for it instead.
|
|
10
|
+
*/ export async function fetchResourceSchema(resource) {
|
|
11
|
+
const key = getResourceKey(resource);
|
|
12
|
+
// The binding's own `types` are hydrated for display and do not compile, so only its
|
|
13
|
+
// descriptor ID is used.
|
|
14
|
+
const binding = await getDatasetSchemaBinding(resource.projectId, resource.dataset);
|
|
15
|
+
if (!binding) {
|
|
16
|
+
throw new Error(`No schema is bound to dataset "${key}", or the dataset does not exist. Check its projectId and dataset, or set "schema" for this resource to a file extracted with "sanity schema extract".`);
|
|
17
|
+
}
|
|
18
|
+
const { schemaVersion } = binding._meta;
|
|
19
|
+
const descriptor = await getSchemaDescriptor(schemaVersion);
|
|
20
|
+
return {
|
|
21
|
+
schema: extractDescriptorSchema(descriptor, {
|
|
22
|
+
enforceRequiredFields: resource.enforceRequiredFields ?? false
|
|
23
|
+
}),
|
|
24
|
+
schemaVersion
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Compiles a schema descriptor and extracts it.
|
|
29
|
+
*
|
|
30
|
+
* Uses the `manifest` format because it keeps validation, which `enforceRequiredFields` reads.
|
|
31
|
+
* The `createSchema` format drops validation, so every field would come out optional.
|
|
32
|
+
* `createSchemaFromManifestTypes` compiles on the built-in types, which descriptors omit.
|
|
33
|
+
*/ export function extractDescriptorSchema(descriptor, options) {
|
|
34
|
+
const definition = convertToDefinition(descriptor, {
|
|
35
|
+
format: 'manifest'
|
|
36
|
+
});
|
|
37
|
+
return extractSchema(createSchemaFromManifestTypes(definition), options);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
//# sourceMappingURL=fetchResourceSchema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/actions/typegen/fetchResourceSchema.ts"],"sourcesContent":["import {type TypeGenResource} from '@sanity/cli-core/types'\nimport {type RunTypegenOptions} from '@sanity/codegen'\nimport {convertToDefinition, type SchemaSummary} from '@sanity/schema-descriptor-utils'\nimport {createSchemaFromManifestTypes, extractSchema} from '@sanity/schema/_internal'\n\nimport {getDatasetSchemaBinding, getSchemaDescriptor} from '../../services/schemas.js'\nimport {getResourceKey} from './parseTypegenResources.js'\n\n/** A schema in the format `sanity schema extract` writes. */\nexport type ExtractedSchema = NonNullable<RunTypegenOptions['extractedSchema']>\n\n/**\n * The schema bound to a resource's dataset.\n */\nexport interface FetchedResourceSchema {\n schema: ExtractedSchema\n /** The Lexicon descriptor ID the dataset's binding points at. */\n schemaVersion: string\n}\n\n/**\n * Fetches the schema bound to a resource's dataset and extracts it for typegen.\n *\n * Throws when the dataset has no binding, naming the resource so the user can set a local\n * `schema` for it instead.\n */\nexport async function fetchResourceSchema(\n resource: Pick<TypeGenResource, 'dataset' | 'enforceRequiredFields' | 'projectId'>,\n): Promise<FetchedResourceSchema> {\n const key = getResourceKey(resource)\n\n // The binding's own `types` are hydrated for display and do not compile, so only its\n // descriptor ID is used.\n const binding = await getDatasetSchemaBinding(resource.projectId, resource.dataset)\n if (!binding) {\n throw new Error(\n `No schema is bound to dataset \"${key}\", or the dataset does not exist. Check its projectId and dataset, or set \"schema\" for this resource to a file extracted with \"sanity schema extract\".`,\n )\n }\n\n const {schemaVersion} = binding._meta\n const descriptor = await getSchemaDescriptor(schemaVersion)\n\n return {\n schema: extractDescriptorSchema(descriptor, {\n enforceRequiredFields: resource.enforceRequiredFields ?? false,\n }),\n schemaVersion,\n }\n}\n\n/**\n * Compiles a schema descriptor and extracts it.\n *\n * Uses the `manifest` format because it keeps validation, which `enforceRequiredFields` reads.\n * The `createSchema` format drops validation, so every field would come out optional.\n * `createSchemaFromManifestTypes` compiles on the built-in types, which descriptors omit.\n */\nexport function extractDescriptorSchema(\n descriptor: SchemaSummary,\n options: {enforceRequiredFields: boolean},\n): ExtractedSchema {\n const definition = convertToDefinition(descriptor, {format: 'manifest'})\n return extractSchema(createSchemaFromManifestTypes(definition), options)\n}\n"],"names":["convertToDefinition","createSchemaFromManifestTypes","extractSchema","getDatasetSchemaBinding","getSchemaDescriptor","getResourceKey","fetchResourceSchema","resource","key","binding","projectId","dataset","Error","schemaVersion","_meta","descriptor","schema","extractDescriptorSchema","enforceRequiredFields","options","definition","format"],"mappings":"AAEA,SAAQA,mBAAmB,QAA2B,kCAAiC;AACvF,SAAQC,6BAA6B,EAAEC,aAAa,QAAO,2BAA0B;AAErF,SAAQC,uBAAuB,EAAEC,mBAAmB,QAAO,4BAA2B;AACtF,SAAQC,cAAc,QAAO,6BAA4B;AAczD;;;;;CAKC,GACD,OAAO,eAAeC,oBACpBC,QAAkF;IAElF,MAAMC,MAAMH,eAAeE;IAE3B,qFAAqF;IACrF,yBAAyB;IACzB,MAAME,UAAU,MAAMN,wBAAwBI,SAASG,SAAS,EAAEH,SAASI,OAAO;IAClF,IAAI,CAACF,SAAS;QACZ,MAAM,IAAIG,MACR,CAAC,+BAA+B,EAAEJ,IAAI,sJAAsJ,CAAC;IAEjM;IAEA,MAAM,EAACK,aAAa,EAAC,GAAGJ,QAAQK,KAAK;IACrC,MAAMC,aAAa,MAAMX,oBAAoBS;IAE7C,OAAO;QACLG,QAAQC,wBAAwBF,YAAY;YAC1CG,uBAAuBX,SAASW,qBAAqB,IAAI;QAC3D;QACAL;IACF;AACF;AAEA;;;;;;CAMC,GACD,OAAO,SAASI,wBACdF,UAAyB,EACzBI,OAAyC;IAEzC,MAAMC,aAAapB,oBAAoBe,YAAY;QAACM,QAAQ;IAAU;IACtE,OAAOnB,cAAcD,8BAA8BmB,aAAaD;AAClE"}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import { isAbsolute, join } from 'node:path';
|
|
3
|
+
import { runTypegenGenerate } from '@sanity/codegen';
|
|
4
|
+
import { fetchResourceSchema } from './fetchResourceSchema.js';
|
|
5
|
+
import { getResourceKey } from './parseTypegenResources.js';
|
|
6
|
+
/**
|
|
7
|
+
* Locates the schema for every resource before anything is generated.
|
|
8
|
+
*
|
|
9
|
+
* A resource with a `schema` path uses that file, which must exist and parse. One without
|
|
10
|
+
* fetches the schema bound to its dataset. Doing this first means a missing binding or a
|
|
11
|
+
* missing or malformed file fails the run before any output is written.
|
|
12
|
+
*/ export async function resolveResourceSchemas(options) {
|
|
13
|
+
const { onResolved, onResolving, resources, workDir } = options;
|
|
14
|
+
const resolved = [];
|
|
15
|
+
for (const resource of resources){
|
|
16
|
+
const key = getResourceKey(resource);
|
|
17
|
+
onResolving?.(resource, key);
|
|
18
|
+
let entry;
|
|
19
|
+
if (resource.schema === undefined) {
|
|
20
|
+
try {
|
|
21
|
+
entry = {
|
|
22
|
+
key,
|
|
23
|
+
resource,
|
|
24
|
+
...await fetchResourceSchema(resource)
|
|
25
|
+
};
|
|
26
|
+
} catch (error) {
|
|
27
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
28
|
+
throw new Error(`Failed to get the schema for "${key}": ${message}`, {
|
|
29
|
+
cause: error
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
} else {
|
|
33
|
+
const schemaPath = isAbsolute(resource.schema) ? resource.schema : join(workDir, resource.schema);
|
|
34
|
+
await assertExtractedSchemaFile(schemaPath, {
|
|
35
|
+
key,
|
|
36
|
+
schema: resource.schema
|
|
37
|
+
});
|
|
38
|
+
// Codegen reads the file again, so the generated output names it as its source, as it
|
|
39
|
+
// does without resources.
|
|
40
|
+
entry = {
|
|
41
|
+
key,
|
|
42
|
+
resource,
|
|
43
|
+
schemaPath: resource.schema
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
resolved.push(entry);
|
|
47
|
+
onResolved?.(entry);
|
|
48
|
+
}
|
|
49
|
+
return resolved;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Generates one output file per resource, registering its types under the resource key.
|
|
53
|
+
*/ export async function generateResourceTypes(options) {
|
|
54
|
+
const { config, onProgress, resolved, workDir } = options;
|
|
55
|
+
const results = [];
|
|
56
|
+
for (const entry of resolved){
|
|
57
|
+
const { dataset, generates, path, projectId } = entry.resource;
|
|
58
|
+
let result;
|
|
59
|
+
try {
|
|
60
|
+
result = await runTypegenGenerate({
|
|
61
|
+
config: {
|
|
62
|
+
...config,
|
|
63
|
+
generates,
|
|
64
|
+
path: path ?? config.path,
|
|
65
|
+
schema: 'schemaPath' in entry ? entry.schemaPath : config.schema
|
|
66
|
+
},
|
|
67
|
+
extractedSchema: 'schema' in entry ? entry.schema : undefined,
|
|
68
|
+
onProgress: onProgress?.(entry),
|
|
69
|
+
resource: {
|
|
70
|
+
dataset,
|
|
71
|
+
projectId
|
|
72
|
+
},
|
|
73
|
+
workDir
|
|
74
|
+
});
|
|
75
|
+
} catch (error) {
|
|
76
|
+
// Codegen writes a resource's file once its generation succeeds, so the files of this
|
|
77
|
+
// resource and the ones after it are unchanged. Files of earlier resources are not
|
|
78
|
+
// rolled back.
|
|
79
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
80
|
+
const written = results.map(({ key })=>`"${key}"`).join(', ');
|
|
81
|
+
throw new Error(`Failed to generate types for "${entry.key}": ${message}` + (written ? `\nTypes for ${written} were updated. The other output files are unchanged.` : ''), {
|
|
82
|
+
cause: error
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
results.push({
|
|
86
|
+
key: entry.key,
|
|
87
|
+
result
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
return results;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Checks that a local schema file exists and holds an extracted schema, which is a JSON array.
|
|
94
|
+
*/ async function assertExtractedSchemaFile(schemaPath, { key, schema }) {
|
|
95
|
+
let content;
|
|
96
|
+
try {
|
|
97
|
+
content = await readFile(schemaPath, 'utf8');
|
|
98
|
+
} catch {
|
|
99
|
+
throw new Error(`Schema file not found for "${key}": ${schema}. Run "sanity schema extract" to create it.`);
|
|
100
|
+
}
|
|
101
|
+
let parsed;
|
|
102
|
+
try {
|
|
103
|
+
parsed = JSON.parse(content);
|
|
104
|
+
} catch (error) {
|
|
105
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
106
|
+
throw new Error(`Schema file for "${key}" is not valid JSON: ${schema}. ${message}`, {
|
|
107
|
+
cause: error
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
if (!Array.isArray(parsed)) {
|
|
111
|
+
throw new TypeError(`Schema file for "${key}" is not an extracted schema: ${schema}. Run "sanity schema extract" to recreate it.`);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
//# sourceMappingURL=generateResourceTypes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/actions/typegen/generateResourceTypes.ts"],"sourcesContent":["import {readFile} from 'node:fs/promises'\nimport {isAbsolute, join} from 'node:path'\n\nimport {type TypeGenResource} from '@sanity/cli-core/types'\nimport {\n type GenerationResult,\n runTypegenGenerate,\n type TypeGenConfig,\n type TypegenProgressEvent,\n} from '@sanity/codegen'\n\nimport {type ExtractedSchema, fetchResourceSchema} from './fetchResourceSchema.js'\nimport {getResourceKey} from './parseTypegenResources.js'\n\n/**\n * A resource whose schema has been located, ready to generate.\n */\nexport type ResolvedResource =\n | {key: string; resource: TypeGenResource; schema: ExtractedSchema; schemaVersion: string}\n | {key: string; resource: TypeGenResource; schemaPath: string}\n\n/**\n * Locates the schema for every resource before anything is generated.\n *\n * A resource with a `schema` path uses that file, which must exist and parse. One without\n * fetches the schema bound to its dataset. Doing this first means a missing binding or a\n * missing or malformed file fails the run before any output is written.\n */\nexport async function resolveResourceSchemas(options: {\n /** Called once a resource's schema is located. */\n onResolved?: (resolved: ResolvedResource) => void\n /** Called before a resource's schema is located. */\n onResolving?: (resource: TypeGenResource, key: string) => void\n resources: TypeGenResource[]\n workDir: string\n}): Promise<ResolvedResource[]> {\n const {onResolved, onResolving, resources, workDir} = options\n const resolved: ResolvedResource[] = []\n\n for (const resource of resources) {\n const key = getResourceKey(resource)\n onResolving?.(resource, key)\n let entry: ResolvedResource\n\n if (resource.schema === undefined) {\n try {\n entry = {key, resource, ...(await fetchResourceSchema(resource))}\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n throw new Error(`Failed to get the schema for \"${key}\": ${message}`, {cause: error})\n }\n } else {\n const schemaPath = isAbsolute(resource.schema)\n ? resource.schema\n : join(workDir, resource.schema)\n await assertExtractedSchemaFile(schemaPath, {key, schema: resource.schema})\n // Codegen reads the file again, so the generated output names it as its source, as it\n // does without resources.\n entry = {key, resource, schemaPath: resource.schema}\n }\n\n resolved.push(entry)\n onResolved?.(entry)\n }\n\n return resolved\n}\n\n/**\n * Generates one output file per resource, registering its types under the resource key.\n */\nexport async function generateResourceTypes(options: {\n /** Settings shared by every resource. */\n config: TypeGenConfig\n /** Returns the progress handler for one resource's generation. */\n onProgress?: (resolved: ResolvedResource) => ((event: TypegenProgressEvent) => void) | undefined\n resolved: ResolvedResource[]\n workDir: string\n}): Promise<{key: string; result: GenerationResult}[]> {\n const {config, onProgress, resolved, workDir} = options\n const results: {key: string; result: GenerationResult}[] = []\n\n for (const entry of resolved) {\n const {dataset, generates, path, projectId} = entry.resource\n let result: GenerationResult\n try {\n result = await runTypegenGenerate({\n config: {\n ...config,\n generates,\n path: path ?? config.path,\n schema: 'schemaPath' in entry ? entry.schemaPath : config.schema,\n },\n extractedSchema: 'schema' in entry ? entry.schema : undefined,\n onProgress: onProgress?.(entry),\n resource: {dataset, projectId},\n workDir,\n })\n } catch (error) {\n // Codegen writes a resource's file once its generation succeeds, so the files of this\n // resource and the ones after it are unchanged. Files of earlier resources are not\n // rolled back.\n const message = error instanceof Error ? error.message : String(error)\n const written = results.map(({key}) => `\"${key}\"`).join(', ')\n throw new Error(\n `Failed to generate types for \"${entry.key}\": ${message}` +\n (written\n ? `\\nTypes for ${written} were updated. The other output files are unchanged.`\n : ''),\n {cause: error},\n )\n }\n results.push({key: entry.key, result})\n }\n\n return results\n}\n\n/**\n * Checks that a local schema file exists and holds an extracted schema, which is a JSON array.\n */\nasync function assertExtractedSchemaFile(\n schemaPath: string,\n {key, schema}: {key: string; schema: string},\n): Promise<void> {\n let content: string\n try {\n content = await readFile(schemaPath, 'utf8')\n } catch {\n throw new Error(\n `Schema file not found for \"${key}\": ${schema}. Run \"sanity schema extract\" to create it.`,\n )\n }\n\n let parsed: unknown\n try {\n parsed = JSON.parse(content)\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n throw new Error(`Schema file for \"${key}\" is not valid JSON: ${schema}. ${message}`, {\n cause: error,\n })\n }\n\n if (!Array.isArray(parsed)) {\n throw new TypeError(\n `Schema file for \"${key}\" is not an extracted schema: ${schema}. Run \"sanity schema extract\" to recreate it.`,\n )\n }\n}\n"],"names":["readFile","isAbsolute","join","runTypegenGenerate","fetchResourceSchema","getResourceKey","resolveResourceSchemas","options","onResolved","onResolving","resources","workDir","resolved","resource","key","entry","schema","undefined","error","message","Error","String","cause","schemaPath","assertExtractedSchemaFile","push","generateResourceTypes","config","onProgress","results","dataset","generates","path","projectId","result","extractedSchema","written","map","content","parsed","JSON","parse","Array","isArray","TypeError"],"mappings":"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"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { resolve } from 'node:path';
|
|
2
|
+
import { array, boolean, getDotPath, isValiError, minLength, nonEmpty, optional, parse, pipe, strictObject, string, union } from 'valibot';
|
|
3
|
+
import { parseTypegenConfig } from './parseTypegenConfig.js';
|
|
4
|
+
const requiredString = pipe(string(), nonEmpty('Must not be empty'));
|
|
5
|
+
const resourcesDefinition = pipe(array(// Strict, so a misspelled `schema` fails instead of silently fetching the remote schema.
|
|
6
|
+
strictObject({
|
|
7
|
+
dataset: requiredString,
|
|
8
|
+
enforceRequiredFields: optional(boolean()),
|
|
9
|
+
generates: requiredString,
|
|
10
|
+
path: optional(union([
|
|
11
|
+
string(),
|
|
12
|
+
array(string())
|
|
13
|
+
])),
|
|
14
|
+
projectId: requiredString,
|
|
15
|
+
schema: optional(requiredString)
|
|
16
|
+
})), minLength(1, 'List at least one resource, or remove `resources`'));
|
|
17
|
+
/**
|
|
18
|
+
* The key a resource's types are registered under, matching the SDK runtime.
|
|
19
|
+
*/ export function getResourceKey(resource) {
|
|
20
|
+
return `${resource.projectId}.${resource.dataset}`;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Validates `typegen.resources` and resolves the settings shared by every resource.
|
|
24
|
+
*
|
|
25
|
+
* Returns `undefined` when `resources` is not set, so callers keep the single-schema flow.
|
|
26
|
+
* `overloadClientMethods` defaults to `false` here: with more than one resource the flat query
|
|
27
|
+
* map conflicts across files, and App SDK apps under pnpm cannot resolve `@sanity/client` for it.
|
|
28
|
+
*
|
|
29
|
+
* @param workDir - The project root that `generates` paths are relative to.
|
|
30
|
+
*/ export function parseTypegenResources(typegen, workDir) {
|
|
31
|
+
if (typegen?.resources === undefined) return undefined;
|
|
32
|
+
let resources;
|
|
33
|
+
try {
|
|
34
|
+
resources = parse(resourcesDefinition, typegen.resources);
|
|
35
|
+
} catch (error) {
|
|
36
|
+
if (isValiError(error)) {
|
|
37
|
+
const issues = error.issues.map((issue)=>{
|
|
38
|
+
const path = getDotPath(issue);
|
|
39
|
+
return ` resources${path ? `.${path}` : ''}: ${issue.message}`;
|
|
40
|
+
});
|
|
41
|
+
throw new TypeError(`Error in typegen config\n${issues.join('\n')}`, {
|
|
42
|
+
cause: error
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
throw error;
|
|
46
|
+
}
|
|
47
|
+
const keys = new Set();
|
|
48
|
+
const outputs = new Map();
|
|
49
|
+
for (const resource of resources){
|
|
50
|
+
const key = getResourceKey(resource);
|
|
51
|
+
if (keys.has(key)) {
|
|
52
|
+
throw new TypeError(`Error in typegen config\n resources: "${key}" is listed more than once. Its types are registered under that key, so it can only have one entry.`);
|
|
53
|
+
}
|
|
54
|
+
keys.add(key);
|
|
55
|
+
// Case-insensitive, because two names that differ only in case are the same file on the
|
|
56
|
+
// default macOS and Windows file systems.
|
|
57
|
+
const output = resolve(workDir, resource.generates).toLowerCase();
|
|
58
|
+
const existing = outputs.get(output);
|
|
59
|
+
if (existing) {
|
|
60
|
+
throw new TypeError(`Error in typegen config\n resources: "${existing}" and "${key}" both generate "${resource.generates}". Each resource needs its own output file.`);
|
|
61
|
+
}
|
|
62
|
+
outputs.set(output, key);
|
|
63
|
+
}
|
|
64
|
+
const config = parseTypegenConfig({
|
|
65
|
+
...typegen,
|
|
66
|
+
overloadClientMethods: typegen.overloadClientMethods ?? false
|
|
67
|
+
});
|
|
68
|
+
const warnings = [];
|
|
69
|
+
if (config.overloadClientMethods && resources.length > 1) {
|
|
70
|
+
warnings.push('typegen.overloadClientMethods is enabled with more than one resource. Every generated file adds to the same global query map, so a query whose result differs between datasets fails to compile with TS2717.');
|
|
71
|
+
}
|
|
72
|
+
for (const field of [
|
|
73
|
+
'schema',
|
|
74
|
+
'generates'
|
|
75
|
+
]){
|
|
76
|
+
if (typegen[field] !== undefined) {
|
|
77
|
+
warnings.push(`typegen.${field} is not used when typegen.resources is set. Each resource sets its own.`);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
for (const resource of resources){
|
|
81
|
+
if (resource.enforceRequiredFields !== undefined && resource.schema !== undefined) {
|
|
82
|
+
warnings.push(`typegen.resources: enforceRequiredFields has no effect for "${getResourceKey(resource)}", which uses a local schema file. Pass --enforce-required-fields to "sanity schema extract" instead.`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return {
|
|
86
|
+
config,
|
|
87
|
+
resources,
|
|
88
|
+
warnings
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
//# sourceMappingURL=parseTypegenResources.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/actions/typegen/parseTypegenResources.ts"],"sourcesContent":["import {resolve} from 'node:path'\n\nimport {type CliConfig} from '@sanity/cli-core'\nimport {type TypeGenResource} from '@sanity/cli-core/types'\nimport {type TypeGenConfig} from '@sanity/codegen'\nimport {\n array,\n boolean,\n getDotPath,\n isValiError,\n minLength,\n nonEmpty,\n optional,\n parse,\n pipe,\n strictObject,\n string,\n union,\n} from 'valibot'\n\nimport {parseTypegenConfig} from './parseTypegenConfig.js'\n\nconst requiredString = pipe(string(), nonEmpty('Must not be empty'))\n\nconst resourcesDefinition = pipe(\n array(\n // Strict, so a misspelled `schema` fails instead of silently fetching the remote schema.\n strictObject({\n dataset: requiredString,\n enforceRequiredFields: optional(boolean()),\n generates: requiredString,\n path: optional(union([string(), array(string())])),\n projectId: requiredString,\n schema: optional(requiredString),\n }),\n ),\n minLength(1, 'List at least one resource, or remove `resources`'),\n)\n\n/**\n * Typegen settings for generating types per resource.\n */\nexport interface TypegenResourcesConfig {\n /** Settings shared by every resource. `schema` and `generates` are unused. */\n config: TypeGenConfig\n resources: TypeGenResource[]\n /** Valid configuration that is likely to produce types that do not compile. */\n warnings: string[]\n}\n\n/**\n * The key a resource's types are registered under, matching the SDK runtime.\n */\nexport function getResourceKey(resource: Pick<TypeGenResource, 'dataset' | 'projectId'>): string {\n return `${resource.projectId}.${resource.dataset}`\n}\n\n/**\n * Validates `typegen.resources` and resolves the settings shared by every resource.\n *\n * Returns `undefined` when `resources` is not set, so callers keep the single-schema flow.\n * `overloadClientMethods` defaults to `false` here: with more than one resource the flat query\n * map conflicts across files, and App SDK apps under pnpm cannot resolve `@sanity/client` for it.\n *\n * @param workDir - The project root that `generates` paths are relative to.\n */\nexport function parseTypegenResources(\n typegen: CliConfig['typegen'],\n workDir: string,\n): TypegenResourcesConfig | undefined {\n if (typegen?.resources === undefined) return undefined\n\n let resources: TypeGenResource[]\n try {\n resources = parse(resourcesDefinition, typegen.resources)\n } catch (error) {\n if (isValiError(error)) {\n const issues = error.issues.map((issue) => {\n const path = getDotPath(issue)\n return ` resources${path ? `.${path}` : ''}: ${issue.message}`\n })\n throw new TypeError(`Error in typegen config\\n${issues.join('\\n')}`, {cause: error})\n }\n throw error\n }\n\n const keys = new Set<string>()\n const outputs = new Map<string, string>()\n for (const resource of resources) {\n const key = getResourceKey(resource)\n if (keys.has(key)) {\n throw new TypeError(\n `Error in typegen config\\n resources: \"${key}\" is listed more than once. Its types are registered under that key, so it can only have one entry.`,\n )\n }\n keys.add(key)\n\n // Case-insensitive, because two names that differ only in case are the same file on the\n // default macOS and Windows file systems.\n const output = resolve(workDir, resource.generates).toLowerCase()\n const existing = outputs.get(output)\n if (existing) {\n throw new TypeError(\n `Error in typegen config\\n resources: \"${existing}\" and \"${key}\" both generate \"${resource.generates}\". Each resource needs its own output file.`,\n )\n }\n outputs.set(output, key)\n }\n\n const config = parseTypegenConfig({\n ...typegen,\n overloadClientMethods: typegen.overloadClientMethods ?? false,\n })\n\n const warnings: string[] = []\n if (config.overloadClientMethods && resources.length > 1) {\n warnings.push(\n 'typegen.overloadClientMethods is enabled with more than one resource. Every generated file adds to the same global query map, so a query whose result differs between datasets fails to compile with TS2717.',\n )\n }\n for (const field of ['schema', 'generates'] as const) {\n if (typegen[field] !== undefined) {\n warnings.push(\n `typegen.${field} is not used when typegen.resources is set. Each resource sets its own.`,\n )\n }\n }\n for (const resource of resources) {\n if (resource.enforceRequiredFields !== undefined && resource.schema !== undefined) {\n warnings.push(\n `typegen.resources: enforceRequiredFields has no effect for \"${getResourceKey(resource)}\", which uses a local schema file. Pass --enforce-required-fields to \"sanity schema extract\" instead.`,\n )\n }\n }\n\n return {config, resources, warnings}\n}\n"],"names":["resolve","array","boolean","getDotPath","isValiError","minLength","nonEmpty","optional","parse","pipe","strictObject","string","union","parseTypegenConfig","requiredString","resourcesDefinition","dataset","enforceRequiredFields","generates","path","projectId","schema","getResourceKey","resource","parseTypegenResources","typegen","workDir","resources","undefined","error","issues","map","issue","message","TypeError","join","cause","keys","Set","outputs","Map","key","has","add","output","toLowerCase","existing","get","set","config","overloadClientMethods","warnings","length","push","field"],"mappings":"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"}
|
|
@@ -7,7 +7,10 @@ import { spinner } from '@sanity/cli-core/ux';
|
|
|
7
7
|
import { readConfig, runTypegenGenerate, runTypegenWatcher, TypegenWatchModeTrace, TypesGeneratedTrace } from '@sanity/codegen';
|
|
8
8
|
import omit from 'lodash-es/omit.js';
|
|
9
9
|
import once from 'lodash-es/once.js';
|
|
10
|
+
import { formatPath } from '../../actions/typegen/formatPath.js';
|
|
11
|
+
import { generateResourceTypes, resolveResourceSchemas } from '../../actions/typegen/generateResourceTypes.js';
|
|
10
12
|
import { parseTypegenConfig } from '../../actions/typegen/parseTypegenConfig.js';
|
|
13
|
+
import { parseTypegenResources } from '../../actions/typegen/parseTypegenResources.js';
|
|
11
14
|
import { createTypegenProgressRenderer } from '../../actions/typegen/renderTypegenProgress.js';
|
|
12
15
|
const description = `Sanity TypeGen
|
|
13
16
|
|
|
@@ -26,7 +29,8 @@ This command can utilize configuration settings defined in a \`sanity-typegen.js
|
|
|
26
29
|
The default configuration values listed above are used if not overridden in your \`sanity-typegen.json\` configuration file. To customize the behavior of the type generation, adjust these properties in the configuration file according to your project's needs.
|
|
27
30
|
|
|
28
31
|
${styleText('bold', 'Note:')}
|
|
29
|
-
- The \`sanity schema extract\` command is a prerequisite for extracting your Sanity Studio schema into a \`schema.json\` file, which is then used by the \`sanity typegen generate\` command to generate type definitions
|
|
32
|
+
- The \`sanity schema extract\` command is a prerequisite for extracting your Sanity Studio schema into a \`schema.json\` file, which is then used by the \`sanity typegen generate\` command to generate type definitions.
|
|
33
|
+
- To generate types for several datasets, list them in \`typegen.resources\` in \`sanity.cli.ts\` (beta). Each resource uses its own \`schema\` file, or the schema bound to its dataset when \`schema\` is omitted.`.trim();
|
|
30
34
|
export class TypegenGenerateCommand extends SanityCommand {
|
|
31
35
|
static description = description;
|
|
32
36
|
static examples = [
|
|
@@ -87,9 +91,11 @@ export class TypegenGenerateCommand extends SanityCommand {
|
|
|
87
91
|
|
|
88
92
|
The config from the Sanity CLI config is used.
|
|
89
93
|
`));
|
|
94
|
+
const resources = parseTypegenResources(config.typegen, workDir);
|
|
90
95
|
return {
|
|
91
|
-
config: parseTypegenConfig(config.typegen || {}),
|
|
96
|
+
config: resources?.config ?? parseTypegenConfig(config.typegen || {}),
|
|
92
97
|
path: rootDir.path,
|
|
98
|
+
resources,
|
|
93
99
|
type: 'cli',
|
|
94
100
|
workDir
|
|
95
101
|
};
|
|
@@ -105,10 +111,12 @@ export class TypegenGenerateCommand extends SanityCommand {
|
|
|
105
111
|
workDir
|
|
106
112
|
};
|
|
107
113
|
}
|
|
114
|
+
const resources = parseTypegenResources(config.typegen, workDir);
|
|
108
115
|
spin.succeed(`Config loaded from sanity.cli.ts`);
|
|
109
116
|
return {
|
|
110
|
-
config: parseTypegenConfig(config.typegen || {}),
|
|
117
|
+
config: resources?.config ?? parseTypegenConfig(config.typegen || {}),
|
|
111
118
|
path: rootDir.path,
|
|
119
|
+
resources,
|
|
112
120
|
type: 'cli',
|
|
113
121
|
workDir
|
|
114
122
|
};
|
|
@@ -127,8 +135,47 @@ export class TypegenGenerateCommand extends SanityCommand {
|
|
|
127
135
|
const trace = this.telemetry.trace(TypesGeneratedTrace);
|
|
128
136
|
let spin;
|
|
129
137
|
try {
|
|
130
|
-
const { config: typegenConfig, type: typegenConfigMethod, workDir } = await this.getConfig();
|
|
138
|
+
const { config: typegenConfig, resources, type: typegenConfigMethod, workDir } = await this.getConfig();
|
|
131
139
|
trace.start();
|
|
140
|
+
if (resources) {
|
|
141
|
+
for (const warning of resources.warnings){
|
|
142
|
+
this.output.warn(warning);
|
|
143
|
+
}
|
|
144
|
+
const resourceSpin = spinner({});
|
|
145
|
+
spin = resourceSpin;
|
|
146
|
+
const resolved = await resolveResourceSchemas({
|
|
147
|
+
onResolved: (entry)=>{
|
|
148
|
+
resourceSpin.succeed('schemaPath' in entry ? `Using ${formatPath(entry.schemaPath)} for ${entry.key}` : `Fetched the schema bound to ${entry.key} (${entry.schemaVersion})`);
|
|
149
|
+
},
|
|
150
|
+
onResolving: (resource, key)=>{
|
|
151
|
+
resourceSpin.start(resource.schema === undefined ? `Fetching the schema bound to ${key}…` : `Checking the schema file for ${key}…`);
|
|
152
|
+
},
|
|
153
|
+
resources: resources.resources,
|
|
154
|
+
workDir
|
|
155
|
+
});
|
|
156
|
+
const results = await generateResourceTypes({
|
|
157
|
+
config: typegenConfig,
|
|
158
|
+
onProgress: (entry)=>{
|
|
159
|
+
resourceSpin.start(`Generating types for ${entry.key}…`);
|
|
160
|
+
return createTypegenProgressRenderer(resourceSpin, {
|
|
161
|
+
formatGeneratedCode: typegenConfig.formatGeneratedCode,
|
|
162
|
+
generates: entry.resource.generates,
|
|
163
|
+
schema: 'schemaPath' in entry ? entry.schemaPath : entry.key
|
|
164
|
+
});
|
|
165
|
+
},
|
|
166
|
+
resolved,
|
|
167
|
+
workDir
|
|
168
|
+
});
|
|
169
|
+
for (const { result } of results){
|
|
170
|
+
trace.log({
|
|
171
|
+
configMethod: typegenConfigMethod,
|
|
172
|
+
configOverloadClientMethods: typegenConfig.overloadClientMethods,
|
|
173
|
+
...omit(result, 'code', 'duration')
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
trace.complete();
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
132
179
|
spin = spinner({}).start('Loading schema…');
|
|
133
180
|
const result = await runTypegenGenerate({
|
|
134
181
|
config: typegenConfig,
|
|
@@ -160,7 +207,12 @@ export class TypegenGenerateCommand extends SanityCommand {
|
|
|
160
207
|
const trace = this.telemetry.trace(TypegenWatchModeTrace);
|
|
161
208
|
let spin;
|
|
162
209
|
try {
|
|
163
|
-
const { config: typegenConfig, workDir } = await this.getConfig();
|
|
210
|
+
const { config: typegenConfig, resources, workDir } = await this.getConfig();
|
|
211
|
+
if (resources) {
|
|
212
|
+
this.error('Watch mode does not support typegen.resources yet. Run "sanity typegen generate" without --watch.', {
|
|
213
|
+
exit: exitCodes.USAGE_ERROR
|
|
214
|
+
});
|
|
215
|
+
}
|
|
164
216
|
trace.start();
|
|
165
217
|
let resolve = ()=>{};
|
|
166
218
|
const promise = new Promise((res)=>{
|
|
@@ -213,6 +265,8 @@ export class TypegenGenerateCommand extends SanityCommand {
|
|
|
213
265
|
spin.fail();
|
|
214
266
|
}
|
|
215
267
|
trace.error(error instanceof Error ? error : new Error(String(error)));
|
|
268
|
+
// Errors already reported with `this.error()` keep their own exit code.
|
|
269
|
+
if (error instanceof CLIError) throw error;
|
|
216
270
|
this.error(`${error instanceof Error ? error.message : 'Unknown error'}`, {
|
|
217
271
|
exit: exitCodes.RUNTIME_ERROR
|
|
218
272
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/commands/typegen/generate.ts"],"sourcesContent":["import {stat} from 'node:fs/promises'\nimport {styleText} from 'node:util'\n\nimport {Flags} from '@oclif/core'\nimport {CLIError} from '@oclif/core/errors'\nimport {exitCodes, SanityCommand} from '@sanity/cli-core'\nimport {spinner, type SpinnerInstance} from '@sanity/cli-core/ux'\nimport {\n readConfig,\n runTypegenGenerate,\n runTypegenWatcher,\n type TypeGenConfig,\n TypegenWatchModeTrace,\n TypesGeneratedTrace,\n} from '@sanity/codegen'\nimport omit from 'lodash-es/omit.js'\nimport once from 'lodash-es/once.js'\n\nimport {parseTypegenConfig} from '../../actions/typegen/parseTypegenConfig.js'\nimport {createTypegenProgressRenderer} from '../../actions/typegen/renderTypegenProgress.js'\n\nconst description = `Sanity TypeGen\n\n${styleText('bold', 'Configuration:')}\nThis command can utilize configuration settings defined in a \\`sanity-typegen.json\\` file. These settings include:\n\n- \"path\": Specifies a glob pattern to locate your TypeScript or JavaScript files.\n Default: \"./src/**/*.{ts,tsx,js,jsx}\"\n\n- \"schema\": Defines the path to your Sanity schema file. This file should be generated using the \\`sanity schema extract\\` command.\n Default: \"schema.json\"\n\n- \"generates\": Indicates the path where the generated TypeScript type definitions will be saved.\n Default: \"./sanity.types.ts\"\n\nThe default configuration values listed above are used if not overridden in your \\`sanity-typegen.json\\` configuration file. To customize the behavior of the type generation, adjust these properties in the configuration file according to your project's needs.\n\n${styleText('bold', 'Note:')}\n- The \\`sanity schema extract\\` command is a prerequisite for extracting your Sanity Studio schema into a \\`schema.json\\` file, which is then used by the \\`sanity typegen generate\\` command to generate type definitions.`.trim()\n\nexport class TypegenGenerateCommand extends SanityCommand<typeof TypegenGenerateCommand> {\n static override description = description\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: `Generate TypeScript type definitions from a Sanity Studio schema extracted using the \\`sanity schema extract\\` command.`,\n },\n ]\n\n static override flags = {\n 'config-path': Flags.string({\n description:\n '[Default: sanity-typegen.json] Specifies the path to the typegen configuration file. This file should be a JSON file that contains settings for the type generation process.',\n }),\n watch: Flags.boolean({\n default: false,\n description: '[Default: false] Run the typegen in watch mode',\n }),\n }\n\n static override hiddenAliases: string[] = ['typegen:generate']\n\n public async run(): Promise<void> {\n const {flags} = await this.parse(TypegenGenerateCommand)\n\n if (flags.watch) {\n await this.runWatcher()\n return\n }\n\n await this.runSingle()\n }\n\n private async getConfig(): Promise<{\n config: TypeGenConfig\n path?: string\n type: 'cli' | 'legacy'\n workDir: string\n }> {\n const spin = spinner({}).start('Loading config…')\n\n try {\n const {flags} = await this.parse(TypegenGenerateCommand)\n const rootDir = await this.getProjectRoot()\n const config = await this.getCliConfig()\n\n const configPath = flags['config-path']\n const workDir = rootDir.directory\n\n const legacyConfigPath = configPath || 'sanity-typegen.json'\n let hasLegacyConfig = false\n\n try {\n const file = await stat(legacyConfigPath)\n hasLegacyConfig = file.isFile()\n } catch (err) {\n if (err instanceof Error && 'code' in err && err.code === 'ENOENT' && configPath) {\n spin.fail()\n this.error(`Typegen config file not found: ${configPath}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n\n if (err instanceof Error && 'code' in err && err.code !== 'ENOENT') {\n spin.fail()\n this.error(`Error when checking if typegen config file exists: ${legacyConfigPath}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n }\n\n if (config?.typegen && hasLegacyConfig) {\n spin.warn(\n styleText(\n 'yellow',\n `You've specified typegen in your Sanity CLI config, but also have a typegen config.\n\n The config from the Sanity CLI config is used.\n `,\n ),\n )\n\n return {\n config: parseTypegenConfig(config.typegen || {}),\n path: rootDir.path,\n type: 'cli',\n workDir,\n }\n }\n\n if (hasLegacyConfig) {\n spin.warn(\n styleText(\n 'yellow',\n `The separate typegen config has been deprecated. Use \\`typegen\\` in the sanity CLI config instead.\n\n See: https://www.sanity.io/docs/help/configuring-typegen-in-sanity-cli-config`,\n ),\n )\n return {\n config: await readConfig(legacyConfigPath),\n path: legacyConfigPath,\n type: 'legacy',\n workDir,\n }\n }\n\n spin.succeed(`Config loaded from sanity.cli.ts`)\n\n return {\n config: parseTypegenConfig(config.typegen || {}),\n path: rootDir.path,\n type: 'cli',\n workDir,\n }\n } catch (err) {\n // The config-file checks above already reported a user-facing error via\n // `this.error()` (an oclif CLIError). Re-throw those as-is instead of\n // wrapping them a second time and failing the spinner twice.\n if (err instanceof CLIError) throw err\n spin.fail()\n this.error(`An error occurred during config loading: ${err}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n }\n\n private async runSingle(): Promise<void> {\n const trace = this.telemetry.trace(TypesGeneratedTrace)\n let spin: SpinnerInstance | undefined\n\n try {\n const {config: typegenConfig, type: typegenConfigMethod, workDir} = await this.getConfig()\n trace.start()\n\n spin = spinner({}).start('Loading schema…')\n const result = await runTypegenGenerate({\n config: typegenConfig,\n onProgress: createTypegenProgressRenderer(spin, {\n formatGeneratedCode: typegenConfig.formatGeneratedCode,\n generates: typegenConfig.generates,\n schema: typegenConfig.schema,\n }),\n workDir,\n })\n\n const traceStats = omit(result, 'code', 'duration')\n\n trace.log({\n configMethod: typegenConfigMethod,\n configOverloadClientMethods: typegenConfig.overloadClientMethods,\n ...traceStats,\n })\n trace.complete()\n } catch (error) {\n if (spin?.isSpinning) {\n spin.fail()\n }\n trace.error(error instanceof Error ? error : new Error(String(error)))\n this.error(`${error instanceof Error ? error.message : 'Unknown error'}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n }\n\n private async runWatcher(): Promise<void> {\n const trace = this.telemetry.trace(TypegenWatchModeTrace)\n let spin: SpinnerInstance | undefined\n\n try {\n const {config: typegenConfig, workDir} = await this.getConfig()\n trace.start()\n\n let resolve: () => void = () => {}\n const promise = new Promise<void>((res) => {\n resolve = res\n })\n\n const watchSpin = spinner({}).start('Loading schema…')\n spin = watchSpin\n const rendererContext = {\n formatGeneratedCode: typegenConfig.formatGeneratedCode,\n generates: typegenConfig.generates,\n schema: typegenConfig.schema,\n }\n let renderProgress = createTypegenProgressRenderer(watchSpin, rendererContext)\n\n const typegenWatcher = runTypegenWatcher({\n config: typegenConfig,\n onProgress: (event) => {\n // 'schemaLoaded' is the first event of every generation cycle; the\n // renderer accumulates per-run state, so start each cycle fresh.\n if (event.type === 'schemaLoaded') {\n renderProgress = createTypegenProgressRenderer(watchSpin, rendererContext)\n }\n renderProgress(event)\n },\n workDir,\n })\n\n const stop = once(async () => {\n process.off('SIGINT', stop)\n process.off('SIGTERM', stop)\n\n if (watchSpin.isSpinning) {\n watchSpin.stop()\n }\n\n trace.log({\n step: 'stopped',\n ...typegenWatcher.getStats(),\n })\n trace.complete()\n\n try {\n await typegenWatcher.stop()\n } catch {\n // We're shutting down; a failure to close the watcher shouldn't hang\n // the process or surface as an unhandled rejection.\n }\n resolve()\n })\n\n process.on('SIGINT', stop)\n process.on('SIGTERM', stop)\n\n await promise\n } catch (error) {\n if (spin?.isSpinning) {\n spin.fail()\n }\n trace.error(error instanceof Error ? error : new Error(String(error)))\n this.error(`${error instanceof Error ? error.message : 'Unknown error'}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n }\n}\n"],"names":["stat","styleText","Flags","CLIError","exitCodes","SanityCommand","spinner","readConfig","runTypegenGenerate","runTypegenWatcher","TypegenWatchModeTrace","TypesGeneratedTrace","omit","once","parseTypegenConfig","createTypegenProgressRenderer","description","trim","TypegenGenerateCommand","examples","command","flags","string","watch","boolean","default","hiddenAliases","run","parse","runWatcher","runSingle","getConfig","spin","start","rootDir","getProjectRoot","config","getCliConfig","configPath","workDir","directory","legacyConfigPath","hasLegacyConfig","file","isFile","err","Error","code","fail","error","exit","RUNTIME_ERROR","typegen","warn","path","type","succeed","trace","telemetry","typegenConfig","typegenConfigMethod","result","onProgress","formatGeneratedCode","generates","schema","traceStats","log","configMethod","configOverloadClientMethods","overloadClientMethods","complete","isSpinning","String","message","resolve","promise","Promise","res","watchSpin","rendererContext","renderProgress","typegenWatcher","event","stop","process","off","step","getStats","on"],"mappings":"AAAA,SAAQA,IAAI,QAAO,mBAAkB;AACrC,SAAQC,SAAS,QAAO,YAAW;AAEnC,SAAQC,KAAK,QAAO,cAAa;AACjC,SAAQC,QAAQ,QAAO,qBAAoB;AAC3C,SAAQC,SAAS,EAAEC,aAAa,QAAO,mBAAkB;AACzD,SAAQC,OAAO,QAA6B,sBAAqB;AACjE,SACEC,UAAU,EACVC,kBAAkB,EAClBC,iBAAiB,EAEjBC,qBAAqB,EACrBC,mBAAmB,QACd,kBAAiB;AACxB,OAAOC,UAAU,oBAAmB;AACpC,OAAOC,UAAU,oBAAmB;AAEpC,SAAQC,kBAAkB,QAAO,8CAA6C;AAC9E,SAAQC,6BAA6B,QAAO,iDAAgD;AAE5F,MAAMC,cAAc,CAAC;;AAErB,EAAEf,UAAU,QAAQ,kBAAkB;;;;;;;;;;;;;;AActC,EAAEA,UAAU,QAAQ,SAAS;2NAC8L,CAAC,CAACgB,IAAI;AAEjO,OAAO,MAAMC,+BAA+Bb;IAC1C,OAAgBW,cAAcA,YAAW;IAEzC,OAAgBG,WAAW;QACzB;YACEC,SAAS;YACTJ,aAAa,CAAC,uHAAuH,CAAC;QACxI;KACD,CAAA;IAED,OAAgBK,QAAQ;QACtB,eAAenB,MAAMoB,MAAM,CAAC;YAC1BN,aACE;QACJ;QACAO,OAAOrB,MAAMsB,OAAO,CAAC;YACnBC,SAAS;YACTT,aAAa;QACf;IACF,EAAC;IAED,OAAgBU,gBAA0B;QAAC;KAAmB,CAAA;IAE9D,MAAaC,MAAqB;QAChC,MAAM,EAACN,KAAK,EAAC,GAAG,MAAM,IAAI,CAACO,KAAK,CAACV;QAEjC,IAAIG,MAAME,KAAK,EAAE;YACf,MAAM,IAAI,CAACM,UAAU;YACrB;QACF;QAEA,MAAM,IAAI,CAACC,SAAS;IACtB;IAEA,MAAcC,YAKX;QACD,MAAMC,OAAO1B,QAAQ,CAAC,GAAG2B,KAAK,CAAC;QAE/B,IAAI;YACF,MAAM,EAACZ,KAAK,EAAC,GAAG,MAAM,IAAI,CAACO,KAAK,CAACV;YACjC,MAAMgB,UAAU,MAAM,IAAI,CAACC,cAAc;YACzC,MAAMC,SAAS,MAAM,IAAI,CAACC,YAAY;YAEtC,MAAMC,aAAajB,KAAK,CAAC,cAAc;YACvC,MAAMkB,UAAUL,QAAQM,SAAS;YAEjC,MAAMC,mBAAmBH,cAAc;YACvC,IAAII,kBAAkB;YAEtB,IAAI;gBACF,MAAMC,OAAO,MAAM3C,KAAKyC;gBACxBC,kBAAkBC,KAAKC,MAAM;YAC/B,EAAE,OAAOC,KAAK;gBACZ,IAAIA,eAAeC,SAAS,UAAUD,OAAOA,IAAIE,IAAI,KAAK,YAAYT,YAAY;oBAChFN,KAAKgB,IAAI;oBACT,IAAI,CAACC,KAAK,CAAC,CAAC,+BAA+B,EAAEX,YAAY,EAAE;wBACzDY,MAAM9C,UAAU+C,aAAa;oBAC/B;gBACF;gBAEA,IAAIN,eAAeC,SAAS,UAAUD,OAAOA,IAAIE,IAAI,KAAK,UAAU;oBAClEf,KAAKgB,IAAI;oBACT,IAAI,CAACC,KAAK,CAAC,CAAC,mDAAmD,EAAER,kBAAkB,EAAE;wBACnFS,MAAM9C,UAAU+C,aAAa;oBAC/B;gBACF;YACF;YAEA,IAAIf,QAAQgB,WAAWV,iBAAiB;gBACtCV,KAAKqB,IAAI,CACPpD,UACE,UACA,CAAC;;;IAGT,CAAC;gBAIG,OAAO;oBACLmC,QAAQtB,mBAAmBsB,OAAOgB,OAAO,IAAI,CAAC;oBAC9CE,MAAMpB,QAAQoB,IAAI;oBAClBC,MAAM;oBACNhB;gBACF;YACF;YAEA,IAAIG,iBAAiB;gBACnBV,KAAKqB,IAAI,CACPpD,UACE,UACA,CAAC;;iFAEoE,CAAC;gBAG1E,OAAO;oBACLmC,QAAQ,MAAM7B,WAAWkC;oBACzBa,MAAMb;oBACNc,MAAM;oBACNhB;gBACF;YACF;YAEAP,KAAKwB,OAAO,CAAC,CAAC,gCAAgC,CAAC;YAE/C,OAAO;gBACLpB,QAAQtB,mBAAmBsB,OAAOgB,OAAO,IAAI,CAAC;gBAC9CE,MAAMpB,QAAQoB,IAAI;gBAClBC,MAAM;gBACNhB;YACF;QACF,EAAE,OAAOM,KAAK;YACZ,wEAAwE;YACxE,sEAAsE;YACtE,6DAA6D;YAC7D,IAAIA,eAAe1C,UAAU,MAAM0C;YACnCb,KAAKgB,IAAI;YACT,IAAI,CAACC,KAAK,CAAC,CAAC,yCAAyC,EAAEJ,KAAK,EAAE;gBAC5DK,MAAM9C,UAAU+C,aAAa;YAC/B;QACF;IACF;IAEA,MAAcrB,YAA2B;QACvC,MAAM2B,QAAQ,IAAI,CAACC,SAAS,CAACD,KAAK,CAAC9C;QACnC,IAAIqB;QAEJ,IAAI;YACF,MAAM,EAACI,QAAQuB,aAAa,EAAEJ,MAAMK,mBAAmB,EAAErB,OAAO,EAAC,GAAG,MAAM,IAAI,CAACR,SAAS;YACxF0B,MAAMxB,KAAK;YAEXD,OAAO1B,QAAQ,CAAC,GAAG2B,KAAK,CAAC;YACzB,MAAM4B,SAAS,MAAMrD,mBAAmB;gBACtC4B,QAAQuB;gBACRG,YAAY/C,8BAA8BiB,MAAM;oBAC9C+B,qBAAqBJ,cAAcI,mBAAmB;oBACtDC,WAAWL,cAAcK,SAAS;oBAClCC,QAAQN,cAAcM,MAAM;gBAC9B;gBACA1B;YACF;YAEA,MAAM2B,aAAatD,KAAKiD,QAAQ,QAAQ;YAExCJ,MAAMU,GAAG,CAAC;gBACRC,cAAcR;gBACdS,6BAA6BV,cAAcW,qBAAqB;gBAChE,GAAGJ,UAAU;YACf;YACAT,MAAMc,QAAQ;QAChB,EAAE,OAAOtB,OAAO;YACd,IAAIjB,MAAMwC,YAAY;gBACpBxC,KAAKgB,IAAI;YACX;YACAS,MAAMR,KAAK,CAACA,iBAAiBH,QAAQG,QAAQ,IAAIH,MAAM2B,OAAOxB;YAC9D,IAAI,CAACA,KAAK,CAAC,GAAGA,iBAAiBH,QAAQG,MAAMyB,OAAO,GAAG,iBAAiB,EAAE;gBACxExB,MAAM9C,UAAU+C,aAAa;YAC/B;QACF;IACF;IAEA,MAActB,aAA4B;QACxC,MAAM4B,QAAQ,IAAI,CAACC,SAAS,CAACD,KAAK,CAAC/C;QACnC,IAAIsB;QAEJ,IAAI;YACF,MAAM,EAACI,QAAQuB,aAAa,EAAEpB,OAAO,EAAC,GAAG,MAAM,IAAI,CAACR,SAAS;YAC7D0B,MAAMxB,KAAK;YAEX,IAAI0C,UAAsB,KAAO;YACjC,MAAMC,UAAU,IAAIC,QAAc,CAACC;gBACjCH,UAAUG;YACZ;YAEA,MAAMC,YAAYzE,QAAQ,CAAC,GAAG2B,KAAK,CAAC;YACpCD,OAAO+C;YACP,MAAMC,kBAAkB;gBACtBjB,qBAAqBJ,cAAcI,mBAAmB;gBACtDC,WAAWL,cAAcK,SAAS;gBAClCC,QAAQN,cAAcM,MAAM;YAC9B;YACA,IAAIgB,iBAAiBlE,8BAA8BgE,WAAWC;YAE9D,MAAME,iBAAiBzE,kBAAkB;gBACvC2B,QAAQuB;gBACRG,YAAY,CAACqB;oBACX,mEAAmE;oBACnE,iEAAiE;oBACjE,IAAIA,MAAM5B,IAAI,KAAK,gBAAgB;wBACjC0B,iBAAiBlE,8BAA8BgE,WAAWC;oBAC5D;oBACAC,eAAeE;gBACjB;gBACA5C;YACF;YAEA,MAAM6C,OAAOvE,KAAK;gBAChBwE,QAAQC,GAAG,CAAC,UAAUF;gBACtBC,QAAQC,GAAG,CAAC,WAAWF;gBAEvB,IAAIL,UAAUP,UAAU,EAAE;oBACxBO,UAAUK,IAAI;gBAChB;gBAEA3B,MAAMU,GAAG,CAAC;oBACRoB,MAAM;oBACN,GAAGL,eAAeM,QAAQ,EAAE;gBAC9B;gBACA/B,MAAMc,QAAQ;gBAEd,IAAI;oBACF,MAAMW,eAAeE,IAAI;gBAC3B,EAAE,OAAM;gBACN,qEAAqE;gBACrE,oDAAoD;gBACtD;gBACAT;YACF;YAEAU,QAAQI,EAAE,CAAC,UAAUL;YACrBC,QAAQI,EAAE,CAAC,WAAWL;YAEtB,MAAMR;QACR,EAAE,OAAO3B,OAAO;YACd,IAAIjB,MAAMwC,YAAY;gBACpBxC,KAAKgB,IAAI;YACX;YACAS,MAAMR,KAAK,CAACA,iBAAiBH,QAAQG,QAAQ,IAAIH,MAAM2B,OAAOxB;YAC9D,IAAI,CAACA,KAAK,CAAC,GAAGA,iBAAiBH,QAAQG,MAAMyB,OAAO,GAAG,iBAAiB,EAAE;gBACxExB,MAAM9C,UAAU+C,aAAa;YAC/B;QACF;IACF;AACF"}
|
|
1
|
+
{"version":3,"sources":["../../../src/commands/typegen/generate.ts"],"sourcesContent":["import {stat} from 'node:fs/promises'\nimport {styleText} from 'node:util'\n\nimport {Flags} from '@oclif/core'\nimport {CLIError} from '@oclif/core/errors'\nimport {exitCodes, SanityCommand} from '@sanity/cli-core'\nimport {spinner, type SpinnerInstance} from '@sanity/cli-core/ux'\nimport {\n readConfig,\n runTypegenGenerate,\n runTypegenWatcher,\n type TypeGenConfig,\n TypegenWatchModeTrace,\n TypesGeneratedTrace,\n} from '@sanity/codegen'\nimport omit from 'lodash-es/omit.js'\nimport once from 'lodash-es/once.js'\n\nimport {formatPath} from '../../actions/typegen/formatPath.js'\nimport {\n generateResourceTypes,\n resolveResourceSchemas,\n} from '../../actions/typegen/generateResourceTypes.js'\nimport {parseTypegenConfig} from '../../actions/typegen/parseTypegenConfig.js'\nimport {\n parseTypegenResources,\n type TypegenResourcesConfig,\n} from '../../actions/typegen/parseTypegenResources.js'\nimport {createTypegenProgressRenderer} from '../../actions/typegen/renderTypegenProgress.js'\n\nconst description = `Sanity TypeGen\n\n${styleText('bold', 'Configuration:')}\nThis command can utilize configuration settings defined in a \\`sanity-typegen.json\\` file. These settings include:\n\n- \"path\": Specifies a glob pattern to locate your TypeScript or JavaScript files.\n Default: \"./src/**/*.{ts,tsx,js,jsx}\"\n\n- \"schema\": Defines the path to your Sanity schema file. This file should be generated using the \\`sanity schema extract\\` command.\n Default: \"schema.json\"\n\n- \"generates\": Indicates the path where the generated TypeScript type definitions will be saved.\n Default: \"./sanity.types.ts\"\n\nThe default configuration values listed above are used if not overridden in your \\`sanity-typegen.json\\` configuration file. To customize the behavior of the type generation, adjust these properties in the configuration file according to your project's needs.\n\n${styleText('bold', 'Note:')}\n- The \\`sanity schema extract\\` command is a prerequisite for extracting your Sanity Studio schema into a \\`schema.json\\` file, which is then used by the \\`sanity typegen generate\\` command to generate type definitions.\n- To generate types for several datasets, list them in \\`typegen.resources\\` in \\`sanity.cli.ts\\` (beta). Each resource uses its own \\`schema\\` file, or the schema bound to its dataset when \\`schema\\` is omitted.`.trim()\n\nexport class TypegenGenerateCommand extends SanityCommand<typeof TypegenGenerateCommand> {\n static override description = description\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: `Generate TypeScript type definitions from a Sanity Studio schema extracted using the \\`sanity schema extract\\` command.`,\n },\n ]\n\n static override flags = {\n 'config-path': Flags.string({\n description:\n '[Default: sanity-typegen.json] Specifies the path to the typegen configuration file. This file should be a JSON file that contains settings for the type generation process.',\n }),\n watch: Flags.boolean({\n default: false,\n description: '[Default: false] Run the typegen in watch mode',\n }),\n }\n\n static override hiddenAliases: string[] = ['typegen:generate']\n\n public async run(): Promise<void> {\n const {flags} = await this.parse(TypegenGenerateCommand)\n\n if (flags.watch) {\n await this.runWatcher()\n return\n }\n\n await this.runSingle()\n }\n\n private async getConfig(): Promise<{\n config: TypeGenConfig\n path?: string\n resources?: TypegenResourcesConfig\n type: 'cli' | 'legacy'\n workDir: string\n }> {\n const spin = spinner({}).start('Loading config…')\n\n try {\n const {flags} = await this.parse(TypegenGenerateCommand)\n const rootDir = await this.getProjectRoot()\n const config = await this.getCliConfig()\n\n const configPath = flags['config-path']\n const workDir = rootDir.directory\n\n const legacyConfigPath = configPath || 'sanity-typegen.json'\n let hasLegacyConfig = false\n\n try {\n const file = await stat(legacyConfigPath)\n hasLegacyConfig = file.isFile()\n } catch (err) {\n if (err instanceof Error && 'code' in err && err.code === 'ENOENT' && configPath) {\n spin.fail()\n this.error(`Typegen config file not found: ${configPath}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n\n if (err instanceof Error && 'code' in err && err.code !== 'ENOENT') {\n spin.fail()\n this.error(`Error when checking if typegen config file exists: ${legacyConfigPath}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n }\n\n if (config?.typegen && hasLegacyConfig) {\n spin.warn(\n styleText(\n 'yellow',\n `You've specified typegen in your Sanity CLI config, but also have a typegen config.\n\n The config from the Sanity CLI config is used.\n `,\n ),\n )\n\n const resources = parseTypegenResources(config.typegen, workDir)\n return {\n config: resources?.config ?? parseTypegenConfig(config.typegen || {}),\n path: rootDir.path,\n resources,\n type: 'cli',\n workDir,\n }\n }\n\n if (hasLegacyConfig) {\n spin.warn(\n styleText(\n 'yellow',\n `The separate typegen config has been deprecated. Use \\`typegen\\` in the sanity CLI config instead.\n\n See: https://www.sanity.io/docs/help/configuring-typegen-in-sanity-cli-config`,\n ),\n )\n return {\n config: await readConfig(legacyConfigPath),\n path: legacyConfigPath,\n type: 'legacy',\n workDir,\n }\n }\n\n const resources = parseTypegenResources(config.typegen, workDir)\n spin.succeed(`Config loaded from sanity.cli.ts`)\n\n return {\n config: resources?.config ?? parseTypegenConfig(config.typegen || {}),\n path: rootDir.path,\n resources,\n type: 'cli',\n workDir,\n }\n } catch (err) {\n // The config-file checks above already reported a user-facing error via\n // `this.error()` (an oclif CLIError). Re-throw those as-is instead of\n // wrapping them a second time and failing the spinner twice.\n if (err instanceof CLIError) throw err\n spin.fail()\n this.error(`An error occurred during config loading: ${err}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n }\n\n private async runSingle(): Promise<void> {\n const trace = this.telemetry.trace(TypesGeneratedTrace)\n let spin: SpinnerInstance | undefined\n\n try {\n const {\n config: typegenConfig,\n resources,\n type: typegenConfigMethod,\n workDir,\n } = await this.getConfig()\n trace.start()\n\n if (resources) {\n for (const warning of resources.warnings) {\n this.output.warn(warning)\n }\n\n const resourceSpin = spinner({})\n spin = resourceSpin\n const resolved = await resolveResourceSchemas({\n onResolved: (entry) => {\n resourceSpin.succeed(\n 'schemaPath' in entry\n ? `Using ${formatPath(entry.schemaPath)} for ${entry.key}`\n : `Fetched the schema bound to ${entry.key} (${entry.schemaVersion})`,\n )\n },\n onResolving: (resource, key) => {\n resourceSpin.start(\n resource.schema === undefined\n ? `Fetching the schema bound to ${key}…`\n : `Checking the schema file for ${key}…`,\n )\n },\n resources: resources.resources,\n workDir,\n })\n\n const results = await generateResourceTypes({\n config: typegenConfig,\n onProgress: (entry) => {\n resourceSpin.start(`Generating types for ${entry.key}…`)\n return createTypegenProgressRenderer(resourceSpin, {\n formatGeneratedCode: typegenConfig.formatGeneratedCode,\n generates: entry.resource.generates,\n schema: 'schemaPath' in entry ? entry.schemaPath : entry.key,\n })\n },\n resolved,\n workDir,\n })\n\n for (const {result} of results) {\n trace.log({\n configMethod: typegenConfigMethod,\n configOverloadClientMethods: typegenConfig.overloadClientMethods,\n ...omit(result, 'code', 'duration'),\n })\n }\n trace.complete()\n return\n }\n\n spin = spinner({}).start('Loading schema…')\n const result = await runTypegenGenerate({\n config: typegenConfig,\n onProgress: createTypegenProgressRenderer(spin, {\n formatGeneratedCode: typegenConfig.formatGeneratedCode,\n generates: typegenConfig.generates,\n schema: typegenConfig.schema,\n }),\n workDir,\n })\n\n const traceStats = omit(result, 'code', 'duration')\n\n trace.log({\n configMethod: typegenConfigMethod,\n configOverloadClientMethods: typegenConfig.overloadClientMethods,\n ...traceStats,\n })\n trace.complete()\n } catch (error) {\n if (spin?.isSpinning) {\n spin.fail()\n }\n trace.error(error instanceof Error ? error : new Error(String(error)))\n this.error(`${error instanceof Error ? error.message : 'Unknown error'}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n }\n\n private async runWatcher(): Promise<void> {\n const trace = this.telemetry.trace(TypegenWatchModeTrace)\n let spin: SpinnerInstance | undefined\n\n try {\n const {config: typegenConfig, resources, workDir} = await this.getConfig()\n if (resources) {\n this.error(\n 'Watch mode does not support typegen.resources yet. Run \"sanity typegen generate\" without --watch.',\n {exit: exitCodes.USAGE_ERROR},\n )\n }\n trace.start()\n\n let resolve: () => void = () => {}\n const promise = new Promise<void>((res) => {\n resolve = res\n })\n\n const watchSpin = spinner({}).start('Loading schema…')\n spin = watchSpin\n const rendererContext = {\n formatGeneratedCode: typegenConfig.formatGeneratedCode,\n generates: typegenConfig.generates,\n schema: typegenConfig.schema,\n }\n let renderProgress = createTypegenProgressRenderer(watchSpin, rendererContext)\n\n const typegenWatcher = runTypegenWatcher({\n config: typegenConfig,\n onProgress: (event) => {\n // 'schemaLoaded' is the first event of every generation cycle; the\n // renderer accumulates per-run state, so start each cycle fresh.\n if (event.type === 'schemaLoaded') {\n renderProgress = createTypegenProgressRenderer(watchSpin, rendererContext)\n }\n renderProgress(event)\n },\n workDir,\n })\n\n const stop = once(async () => {\n process.off('SIGINT', stop)\n process.off('SIGTERM', stop)\n\n if (watchSpin.isSpinning) {\n watchSpin.stop()\n }\n\n trace.log({\n step: 'stopped',\n ...typegenWatcher.getStats(),\n })\n trace.complete()\n\n try {\n await typegenWatcher.stop()\n } catch {\n // We're shutting down; a failure to close the watcher shouldn't hang\n // the process or surface as an unhandled rejection.\n }\n resolve()\n })\n\n process.on('SIGINT', stop)\n process.on('SIGTERM', stop)\n\n await promise\n } catch (error) {\n if (spin?.isSpinning) {\n spin.fail()\n }\n trace.error(error instanceof Error ? error : new Error(String(error)))\n // Errors already reported with `this.error()` keep their own exit code.\n if (error instanceof CLIError) throw error\n this.error(`${error instanceof Error ? error.message : 'Unknown error'}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n }\n}\n"],"names":["stat","styleText","Flags","CLIError","exitCodes","SanityCommand","spinner","readConfig","runTypegenGenerate","runTypegenWatcher","TypegenWatchModeTrace","TypesGeneratedTrace","omit","once","formatPath","generateResourceTypes","resolveResourceSchemas","parseTypegenConfig","parseTypegenResources","createTypegenProgressRenderer","description","trim","TypegenGenerateCommand","examples","command","flags","string","watch","boolean","default","hiddenAliases","run","parse","runWatcher","runSingle","getConfig","spin","start","rootDir","getProjectRoot","config","getCliConfig","configPath","workDir","directory","legacyConfigPath","hasLegacyConfig","file","isFile","err","Error","code","fail","error","exit","RUNTIME_ERROR","typegen","warn","resources","path","type","succeed","trace","telemetry","typegenConfig","typegenConfigMethod","warning","warnings","output","resourceSpin","resolved","onResolved","entry","schemaPath","key","schemaVersion","onResolving","resource","schema","undefined","results","onProgress","formatGeneratedCode","generates","result","log","configMethod","configOverloadClientMethods","overloadClientMethods","complete","traceStats","isSpinning","String","message","USAGE_ERROR","resolve","promise","Promise","res","watchSpin","rendererContext","renderProgress","typegenWatcher","event","stop","process","off","step","getStats","on"],"mappings":"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"}
|
|
@@ -80,6 +80,7 @@
|
|
|
80
80
|
'applications/{applicationId}',
|
|
81
81
|
'applications/{applicationId}/access',
|
|
82
82
|
'applications/{applicationId}/deployments',
|
|
83
|
+
'applications/{applicationId}/embeddable',
|
|
83
84
|
'applications/{applicationId}/installations',
|
|
84
85
|
'applications/{applicationId}/interfaces',
|
|
85
86
|
'applications/{applicationId}/workspaces',
|
|
@@ -120,6 +121,7 @@
|
|
|
120
121
|
'applications/{applicationId}',
|
|
121
122
|
'applications/{applicationId}/access',
|
|
122
123
|
'applications/{applicationId}/deployments',
|
|
124
|
+
'applications/{applicationId}/embeddable',
|
|
123
125
|
'applications/{applicationId}/installations',
|
|
124
126
|
'applications/{applicationId}/interfaces',
|
|
125
127
|
'applications/{applicationId}/workspaces',
|