@sanity/cli 3.87.1 → 3.88.1-typegen-experimental.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/lib/_chunks-cjs/cli.js +58780 -56791
- package/lib/_chunks-cjs/cli.js.map +1 -1
- package/lib/_chunks-cjs/generateAction.js +113 -111
- package/lib/_chunks-cjs/generateAction.js.map +1 -1
- package/lib/_chunks-cjs/loadEnv.js +3 -3
- package/lib/_chunks-cjs/loadEnv.js.map +1 -1
- package/lib/_chunks-cjs/workerChannel.js +84 -0
- package/lib/_chunks-cjs/workerChannel.js.map +1 -0
- package/lib/workers/typegenGenerate.d.ts +144 -33
- package/lib/workers/typegenGenerate.js +83 -112
- package/lib/workers/typegenGenerate.js.map +1 -1
- package/package.json +20 -22
- package/src/actions/init-project/templates/appQuickstart.ts +2 -2
- package/src/actions/init-project/templates/appSanityUi.ts +2 -2
- package/src/actions/typegen/generate.telemetry.ts +9 -3
- package/src/actions/typegen/generateAction.ts +159 -152
- package/src/cli.ts +0 -0
- package/src/commands/blueprints/addBlueprintsCommand.ts +52 -56
- package/src/commands/blueprints/blueprintsGroup.ts +0 -1
- package/src/commands/blueprints/configBlueprintsCommand.ts +50 -74
- package/src/commands/blueprints/deployBlueprintsCommand.ts +41 -133
- package/src/commands/blueprints/destroyBlueprintsCommand.ts +76 -0
- package/src/commands/blueprints/infoBlueprintsCommand.ts +29 -51
- package/src/commands/blueprints/initBlueprintsCommand.ts +55 -73
- package/src/commands/blueprints/logsBlueprintsCommand.ts +43 -81
- package/src/commands/blueprints/planBlueprintsCommand.ts +26 -36
- package/src/commands/blueprints/stacksBlueprintsCommand.ts +43 -51
- package/src/commands/functions/devFunctionsCommand.ts +1 -2
- package/src/commands/functions/envFunctionsCommand.ts +55 -46
- package/src/commands/functions/functionsGroup.ts +1 -2
- package/src/commands/functions/logsFunctionsCommand.ts +101 -58
- package/src/commands/functions/testFunctionsCommand.ts +56 -36
- package/src/commands/index.ts +6 -4
- package/src/commands/projects/listProjectsCommand.ts +0 -0
- package/src/commands/projects/projectsGroup.ts +0 -0
- package/src/util/__tests__/workerChannel.test.ts +222 -0
- package/src/util/workerChannel.ts +312 -0
- package/src/workers/typegenGenerate.ts +181 -183
- package/templates/app-sanity-ui/src/ExampleComponent.tsx +1 -1
@@ -1,229 +1,227 @@
|
|
1
|
+
/* eslint-disable max-statements */
|
2
|
+
import {stat} from 'node:fs/promises'
|
1
3
|
import {isMainThread, parentPort, workerData as _workerData} from 'node:worker_threads'
|
2
4
|
|
3
5
|
import {
|
6
|
+
DEFAULT_CONFIG,
|
4
7
|
findQueriesInPath,
|
5
8
|
getResolver,
|
6
9
|
readSchema,
|
7
10
|
registerBabel,
|
8
|
-
safeParseQuery,
|
9
11
|
TypeGenerator,
|
10
12
|
} from '@sanity/codegen'
|
11
|
-
import
|
12
|
-
import {typeEvaluate, type TypeNode} from 'groq-js'
|
13
|
+
import {type SchemaType} from 'groq-js'
|
13
14
|
|
14
|
-
|
15
|
-
|
15
|
+
import {
|
16
|
+
createReporter,
|
17
|
+
type WorkerChannel,
|
18
|
+
type WorkerChannelEvent,
|
19
|
+
type WorkerChannelStream,
|
20
|
+
} from '../util/workerChannel'
|
21
|
+
|
22
|
+
const DEFAULT_SCHEMA_PATH = DEFAULT_CONFIG.schemas[0].schemaPath
|
16
23
|
|
17
24
|
export interface TypegenGenerateTypesWorkerData {
|
18
25
|
workDir: string
|
19
|
-
|
20
|
-
schemaPath: string
|
26
|
+
schemas: {schemaPath: string; schemaId: string}[]
|
21
27
|
searchPath: string | string[]
|
22
|
-
overloadClientMethods
|
28
|
+
overloadClientMethods: boolean
|
29
|
+
augmentGroqModule: boolean
|
23
30
|
}
|
24
31
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
type: string
|
40
|
-
unknownTypeNodesGenerated: number
|
41
|
-
typeNodesGenerated: number
|
42
|
-
emptyUnionTypeNodesGenerated: number
|
43
|
-
}[]
|
44
|
-
}
|
45
|
-
| {
|
46
|
-
type: 'schema'
|
47
|
-
filename: string
|
48
|
-
schema: string
|
49
|
-
length: number
|
50
|
-
}
|
51
|
-
| {
|
52
|
-
type: 'typemap'
|
53
|
-
typeMap: string
|
32
|
+
interface QueryProgress {
|
33
|
+
queriesCount: number
|
34
|
+
projectionsCount: number
|
35
|
+
filesCount: number
|
36
|
+
}
|
37
|
+
|
38
|
+
/** @internal */
|
39
|
+
export type TypegenWorkerChannel = WorkerChannel<{
|
40
|
+
loadedSchemas: WorkerChannelEvent
|
41
|
+
generatedSchemaDeclarations: WorkerChannelEvent<{
|
42
|
+
code: string
|
43
|
+
schemaStats: {
|
44
|
+
schemaTypesCount: number
|
45
|
+
schemaCount: number
|
54
46
|
}
|
55
|
-
|
56
|
-
|
47
|
+
}>
|
48
|
+
fileCount: WorkerChannelEvent<{fileCount: number}>
|
49
|
+
generatedQueryResultDeclaration: WorkerChannelStream<
|
50
|
+
| {
|
51
|
+
type: 'progress'
|
52
|
+
progress: QueryProgress
|
53
|
+
}
|
54
|
+
| {
|
55
|
+
type: 'declaration'
|
56
|
+
code: string
|
57
|
+
progress: QueryProgress
|
58
|
+
}
|
59
|
+
| {
|
60
|
+
type: 'error'
|
61
|
+
message: string
|
62
|
+
progress: QueryProgress
|
63
|
+
}
|
64
|
+
>
|
65
|
+
generationComplete: WorkerChannelEvent<{
|
66
|
+
augmentedQueryResultDeclarations: {code: string}
|
67
|
+
queryStats: {
|
68
|
+
queriesCount: number
|
69
|
+
projectionsCount: number
|
70
|
+
totalScannedFilesCount: number
|
71
|
+
queryFilesCount: number
|
72
|
+
projectionFilesCount: number
|
73
|
+
filesWithErrors: number
|
74
|
+
errorCount: number
|
75
|
+
typeNodesGenerated: number
|
76
|
+
unknownTypeNodesGenerated: number
|
77
|
+
unknownTypeNodesRatio: number
|
78
|
+
emptyUnionTypeNodesGenerated: number
|
57
79
|
}
|
80
|
+
}>
|
81
|
+
}>
|
58
82
|
|
59
83
|
if (isMainThread || !parentPort) {
|
60
84
|
throw new Error('This module must be run as a worker thread')
|
61
85
|
}
|
62
86
|
|
87
|
+
const report = createReporter<TypegenWorkerChannel>(parentPort)
|
63
88
|
const opts = _workerData as TypegenGenerateTypesWorkerData
|
64
89
|
|
65
|
-
registerBabel()
|
66
|
-
|
67
90
|
async function main() {
|
68
|
-
const schema =
|
69
|
-
|
70
|
-
const
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
schema: `${schemaTypes.trim()}\n`,
|
79
|
-
filename: 'schema.json',
|
80
|
-
length: schema.length,
|
81
|
-
} satisfies TypegenGenerateTypesWorkerMessage)
|
82
|
-
|
83
|
-
const queries = findQueriesInPath({
|
84
|
-
path: opts.searchPath,
|
85
|
-
resolver,
|
86
|
-
})
|
91
|
+
const schemas: {schema: SchemaType; schemaId: string; filename: string}[] = []
|
92
|
+
|
93
|
+
for (const {schemaId, schemaPath} of opts.schemas) {
|
94
|
+
try {
|
95
|
+
const schemaStats = await stat(schemaPath)
|
96
|
+
if (!schemaStats.isFile()) {
|
97
|
+
throw new Error(
|
98
|
+
`Failed to load schema "${schemaId}". Schema path is not a file: ${schemaPath}`,
|
99
|
+
)
|
100
|
+
}
|
87
101
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
continue
|
99
|
-
}
|
100
|
-
$info(`Processing ${result.queries.length} queries in "${result.filename}"...`)
|
101
|
-
|
102
|
-
const fileQueryTypes: {
|
103
|
-
queryName: string
|
104
|
-
query: string
|
105
|
-
type: string
|
106
|
-
typeName: string
|
107
|
-
typeNode: TypeNode
|
108
|
-
unknownTypeNodesGenerated: number
|
109
|
-
typeNodesGenerated: number
|
110
|
-
emptyUnionTypeNodesGenerated: number
|
111
|
-
}[] = []
|
112
|
-
for (const {name: queryName, result: query} of result.queries) {
|
113
|
-
try {
|
114
|
-
const ast = safeParseQuery(query)
|
115
|
-
const queryTypes = typeEvaluate(ast, schema)
|
116
|
-
|
117
|
-
const typeName = `${queryName}Result`
|
118
|
-
const type = typeGenerator.generateTypeNodeTypes(typeName, queryTypes)
|
119
|
-
|
120
|
-
const queryTypeStats = walkAndCountQueryTypeNodeStats(queryTypes)
|
121
|
-
fileQueryTypes.push({
|
122
|
-
queryName,
|
123
|
-
query,
|
124
|
-
typeName,
|
125
|
-
typeNode: queryTypes,
|
126
|
-
type: `${type.trim()}\n`,
|
127
|
-
unknownTypeNodesGenerated: queryTypeStats.unknownTypes,
|
128
|
-
typeNodesGenerated: queryTypeStats.allTypes,
|
129
|
-
emptyUnionTypeNodesGenerated: queryTypeStats.emptyUnions,
|
130
|
-
})
|
131
|
-
} catch (err) {
|
132
|
-
parentPort?.postMessage({
|
133
|
-
type: 'error',
|
134
|
-
error: new Error(
|
135
|
-
`Error generating types for query "${queryName}" in "${result.filename}": ${err.message}`,
|
136
|
-
{cause: err},
|
137
|
-
),
|
138
|
-
fatal: false,
|
139
|
-
query,
|
140
|
-
} satisfies TypegenGenerateTypesWorkerMessage)
|
102
|
+
const schema = await readSchema(schemaPath)
|
103
|
+
schemas.push({schema, schemaId, filename: schemaPath})
|
104
|
+
} catch (err) {
|
105
|
+
if (err.code === 'ENOENT') {
|
106
|
+
// If the user has not provided a specific schema path (eg we're using the default), give some help
|
107
|
+
const hint =
|
108
|
+
schemaPath === DEFAULT_SCHEMA_PATH ? ` - did you run "sanity schema extract"?` : ''
|
109
|
+
throw new Error(`Schema file not found for schema "${schemaId}": ${schemaPath}${hint}`)
|
110
|
+
} else {
|
111
|
+
throw err
|
141
112
|
}
|
142
113
|
}
|
114
|
+
}
|
115
|
+
report.event.loadedSchemas()
|
143
116
|
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
117
|
+
const generator = new TypeGenerator({
|
118
|
+
schemas,
|
119
|
+
queriesByFile: findQueriesInPath({path: opts.searchPath, resolver: getResolver()}),
|
120
|
+
augmentGroqModule: opts.augmentGroqModule,
|
121
|
+
overloadClientMethods: opts.overloadClientMethods,
|
122
|
+
})
|
123
|
+
|
124
|
+
report.event.generatedSchemaDeclarations({
|
125
|
+
code: [
|
126
|
+
generator.getKnownTypes().code,
|
127
|
+
...generator.getSchemaTypeDeclarations().map((i) => i.code),
|
128
|
+
generator.getAllSanitySchemaTypesDeclaration().code,
|
129
|
+
...generator.getSchemaDeclarations().map((i) => i.code),
|
130
|
+
generator.getAugmentedSchemasDeclarations().code,
|
131
|
+
].join('\n'),
|
132
|
+
schemaStats: {
|
133
|
+
schemaTypesCount: generator.getSchemaTypeDeclarations().length,
|
134
|
+
schemaCount: schemas.length,
|
135
|
+
},
|
136
|
+
})
|
152
137
|
|
153
|
-
|
154
|
-
|
138
|
+
const allFilenames = new Set<string>()
|
139
|
+
const errorFilenames = new Set<string>()
|
140
|
+
const queryFilenames = new Set<string>()
|
141
|
+
const projectionFilenames = new Set<string>()
|
142
|
+
|
143
|
+
let errorCount = 0
|
144
|
+
let queriesCount = 0
|
145
|
+
let projectionsCount = 0
|
146
|
+
let typeNodesGenerated = 0
|
147
|
+
let unknownTypeNodesGenerated = 0
|
148
|
+
let emptyUnionTypeNodesGenerated = 0
|
149
|
+
|
150
|
+
const {fileCount} = await generator.getQueryFileCount()
|
151
|
+
report.event.fileCount({fileCount})
|
152
|
+
|
153
|
+
for await (const {filename, ...result} of generator.getQueryResultDeclarations()) {
|
154
|
+
allFilenames.add(filename)
|
155
|
+
const progress = {
|
156
|
+
queriesCount,
|
157
|
+
projectionsCount,
|
158
|
+
filesCount: allFilenames.size,
|
155
159
|
}
|
156
|
-
}
|
157
160
|
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
typeMap,
|
163
|
-
} satisfies TypegenGenerateTypesWorkerMessage)
|
164
|
-
}
|
161
|
+
switch (result.type) {
|
162
|
+
case 'error': {
|
163
|
+
errorCount += 1
|
164
|
+
errorFilenames.add(filename)
|
165
165
|
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
166
|
+
const errorMessage =
|
167
|
+
typeof result.error === 'object' && result.error !== null && 'message' in result.error
|
168
|
+
? String(result.error.message)
|
169
|
+
: 'Unknown Error'
|
170
170
|
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
emptyUnions: number
|
175
|
-
} {
|
176
|
-
switch (typeNode.type) {
|
177
|
-
case 'unknown': {
|
178
|
-
return {allTypes: 1, unknownTypes: 1, emptyUnions: 0}
|
179
|
-
}
|
180
|
-
case 'array': {
|
181
|
-
const acc = walkAndCountQueryTypeNodeStats(typeNode.of)
|
182
|
-
acc.allTypes += 1 // count the array type itself
|
183
|
-
return acc
|
184
|
-
}
|
185
|
-
case 'object': {
|
186
|
-
// if the rest is unknown, we count it as one unknown type
|
187
|
-
if (typeNode.rest && typeNode.rest.type === 'unknown') {
|
188
|
-
return {allTypes: 2, unknownTypes: 1, emptyUnions: 0} // count the object type itself as well
|
171
|
+
const message = `Error generating types in "${filename}": ${errorMessage}`
|
172
|
+
report.stream.generatedQueryResultDeclaration.emit({type: 'error', message, progress})
|
173
|
+
continue
|
189
174
|
}
|
190
175
|
|
191
|
-
|
192
|
-
|
193
|
-
|
176
|
+
case 'queries': {
|
177
|
+
if (!result.queryResultDeclarations.length) {
|
178
|
+
report.stream.generatedQueryResultDeclaration.emit({type: 'progress', progress})
|
179
|
+
continue
|
180
|
+
}
|
194
181
|
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
182
|
+
for (const {code, type, stats} of result.queryResultDeclarations) {
|
183
|
+
queriesCount += type === 'query' ? 1 : 0
|
184
|
+
projectionsCount += type === 'projection' ? 1 : 0
|
185
|
+
typeNodesGenerated += stats.allTypes
|
186
|
+
unknownTypeNodesGenerated += stats.unknownTypes
|
187
|
+
emptyUnionTypeNodesGenerated += stats.emptyUnions
|
188
|
+
|
189
|
+
if (type === 'projection') {
|
190
|
+
projectionFilenames.add(filename)
|
191
|
+
} else {
|
192
|
+
queryFilenames.add(filename)
|
193
|
+
}
|
194
|
+
|
195
|
+
report.stream.generatedQueryResultDeclaration.emit({type: 'declaration', code, progress})
|
203
196
|
}
|
204
|
-
|
205
|
-
}
|
206
|
-
case 'union': {
|
207
|
-
if (typeNode.of.length === 0) {
|
208
|
-
return {allTypes: 1, unknownTypes: 0, emptyUnions: 1}
|
197
|
+
continue
|
209
198
|
}
|
210
199
|
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
return {
|
215
|
-
allTypes: acc.allTypes + allTypes,
|
216
|
-
unknownTypes: acc.unknownTypes + unknownTypes,
|
217
|
-
emptyUnions: acc.emptyUnions + emptyUnions,
|
218
|
-
}
|
219
|
-
},
|
220
|
-
{allTypes: 1, unknownTypes: 0, emptyUnions: 0}, // count the union type itself
|
221
|
-
)
|
222
|
-
}
|
223
|
-
default: {
|
224
|
-
return {allTypes: 1, unknownTypes: 0, emptyUnions: 0}
|
200
|
+
default: {
|
201
|
+
continue
|
202
|
+
}
|
225
203
|
}
|
226
204
|
}
|
205
|
+
report.stream.generatedQueryResultDeclaration.end()
|
206
|
+
|
207
|
+
report.event.generationComplete({
|
208
|
+
augmentedQueryResultDeclarations: await generator.getAugmentedQueryResultsDeclarations(),
|
209
|
+
queryStats: {
|
210
|
+
errorCount,
|
211
|
+
queriesCount,
|
212
|
+
projectionsCount,
|
213
|
+
typeNodesGenerated,
|
214
|
+
unknownTypeNodesGenerated,
|
215
|
+
emptyUnionTypeNodesGenerated,
|
216
|
+
totalScannedFilesCount: allFilenames.size,
|
217
|
+
filesWithErrors: errorFilenames.size,
|
218
|
+
queryFilesCount: queryFilenames.size,
|
219
|
+
projectionFilesCount: projectionFilenames.size,
|
220
|
+
unknownTypeNodesRatio:
|
221
|
+
typeNodesGenerated > 0 ? unknownTypeNodesGenerated / typeNodesGenerated : 0,
|
222
|
+
},
|
223
|
+
})
|
227
224
|
}
|
228
225
|
|
226
|
+
registerBabel()
|
229
227
|
main()
|
@@ -23,7 +23,7 @@ export function ExampleComponent() {
|
|
23
23
|
</Text>
|
24
24
|
<Text muted>
|
25
25
|
Looking for more guidance? See the <a href="https://sanity.io/ui">Sanity UI docs</a>{' '}
|
26
|
-
and the <a href="https://
|
26
|
+
and the <a href="https://reference.sanity.io/_sanity/sdk-react/">Sanity App SDK docs</a>!
|
27
27
|
</Text>
|
28
28
|
</Stack>
|
29
29
|
</Flex>
|