@atproto/lex-cli 0.10.1 → 0.10.3
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/CHANGELOG.md +26 -0
- package/bin.js +8 -4
- package/dist/codegen/client.d.ts +1 -1
- package/dist/codegen/client.d.ts.map +1 -1
- package/dist/codegen/client.js +1 -1
- package/dist/codegen/client.js.map +1 -1
- package/dist/codegen/common.d.ts +4 -4
- package/dist/codegen/common.d.ts.map +1 -1
- package/dist/codegen/common.js +1 -1
- package/dist/codegen/common.js.map +1 -1
- package/dist/codegen/lex-gen.js +2 -1
- package/dist/codegen/lex-gen.js.map +1 -1
- package/dist/codegen/server.d.ts +1 -1
- package/dist/codegen/server.d.ts.map +1 -1
- package/dist/codegen/server.js +1 -1
- package/dist/codegen/server.js.map +1 -1
- package/dist/codegen/util.js +1 -0
- package/dist/codegen/util.js.map +1 -1
- package/dist/mdgen/index.js +3 -2
- package/dist/mdgen/index.js.map +1 -1
- package/dist/util.d.ts +1 -1
- package/dist/util.d.ts.map +1 -1
- package/dist/util.js.map +1 -1
- package/package.json +17 -13
- package/src/codegen/client.ts +0 -566
- package/src/codegen/common.ts +0 -283
- package/src/codegen/lex-gen.ts +0 -720
- package/src/codegen/server.ts +0 -448
- package/src/codegen/util.ts +0 -84
- package/src/index.ts +0 -105
- package/src/mdgen/index.ts +0 -77
- package/src/types.ts +0 -14
- package/src/util.ts +0 -151
- package/tsconfig.build.json +0 -8
- package/tsconfig.build.tsbuildinfo +0 -1
- package/tsconfig.json +0 -4
package/src/codegen/client.ts
DELETED
|
@@ -1,566 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
IndentationText,
|
|
3
|
-
Project,
|
|
4
|
-
SourceFile,
|
|
5
|
-
VariableDeclarationKind,
|
|
6
|
-
} from 'ts-morph'
|
|
7
|
-
import { type LexRecord, type LexiconDoc, Lexicons } from '@atproto/lexicon'
|
|
8
|
-
import { NSID } from '@atproto/syntax'
|
|
9
|
-
import { type GeneratedAPI } from '../types.js'
|
|
10
|
-
import { gen, lexiconsTs, utilTs } from './common.js'
|
|
11
|
-
import {
|
|
12
|
-
genCommonImports,
|
|
13
|
-
genImports,
|
|
14
|
-
genRecord,
|
|
15
|
-
genUserType,
|
|
16
|
-
genXrpcInput,
|
|
17
|
-
genXrpcOutput,
|
|
18
|
-
genXrpcParams,
|
|
19
|
-
} from './lex-gen.js'
|
|
20
|
-
import {
|
|
21
|
-
type DefTreeNode,
|
|
22
|
-
lexiconsToDefTree,
|
|
23
|
-
schemasToNsidTokens,
|
|
24
|
-
toCamelCase,
|
|
25
|
-
toScreamingSnakeCase,
|
|
26
|
-
toTitleCase,
|
|
27
|
-
} from './util.js'
|
|
28
|
-
|
|
29
|
-
const ATP_METHODS = {
|
|
30
|
-
list: 'com.atproto.repo.listRecords',
|
|
31
|
-
get: 'com.atproto.repo.getRecord',
|
|
32
|
-
create: 'com.atproto.repo.createRecord',
|
|
33
|
-
put: 'com.atproto.repo.putRecord',
|
|
34
|
-
delete: 'com.atproto.repo.deleteRecord',
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export async function genClientApi(
|
|
38
|
-
lexiconDocs: LexiconDoc[],
|
|
39
|
-
): Promise<GeneratedAPI> {
|
|
40
|
-
const project = new Project({
|
|
41
|
-
useInMemoryFileSystem: true,
|
|
42
|
-
manipulationSettings: { indentationText: IndentationText.TwoSpaces },
|
|
43
|
-
})
|
|
44
|
-
const api: GeneratedAPI = { files: [] }
|
|
45
|
-
const lexicons = new Lexicons(lexiconDocs)
|
|
46
|
-
const nsidTree = lexiconsToDefTree(lexiconDocs)
|
|
47
|
-
const nsidTokens = schemasToNsidTokens(lexiconDocs)
|
|
48
|
-
for (const lexiconDoc of lexiconDocs) {
|
|
49
|
-
api.files.push(await lexiconTs(project, lexicons, lexiconDoc))
|
|
50
|
-
}
|
|
51
|
-
api.files.push(await utilTs(project))
|
|
52
|
-
api.files.push(await lexiconsTs(project, lexiconDocs))
|
|
53
|
-
api.files.push(await indexTs(project, lexiconDocs, nsidTree, nsidTokens))
|
|
54
|
-
return api
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
const indexTs = (
|
|
58
|
-
project: Project,
|
|
59
|
-
lexiconDocs: LexiconDoc[],
|
|
60
|
-
nsidTree: DefTreeNode[],
|
|
61
|
-
nsidTokens: Record<string, string[]>,
|
|
62
|
-
) =>
|
|
63
|
-
gen(project, '/index.ts', async (file) => {
|
|
64
|
-
//= import { XrpcClient, type FetchHandler, type FetchHandlerOptions } from '@atproto/xrpc'
|
|
65
|
-
const xrpcImport = file.addImportDeclaration({
|
|
66
|
-
moduleSpecifier: '@atproto/xrpc',
|
|
67
|
-
})
|
|
68
|
-
xrpcImport.addNamedImports([
|
|
69
|
-
{ name: 'XrpcClient' },
|
|
70
|
-
{ name: 'FetchHandler', isTypeOnly: true },
|
|
71
|
-
{ name: 'FetchHandlerOptions', isTypeOnly: true },
|
|
72
|
-
])
|
|
73
|
-
//= import {schemas} from './lexicons.js'
|
|
74
|
-
file
|
|
75
|
-
.addImportDeclaration({ moduleSpecifier: './lexicons.js' })
|
|
76
|
-
.addNamedImports([{ name: 'schemas' }])
|
|
77
|
-
//= import {CID} from 'multiformats/cid'
|
|
78
|
-
file
|
|
79
|
-
.addImportDeclaration({
|
|
80
|
-
moduleSpecifier: 'multiformats/cid',
|
|
81
|
-
})
|
|
82
|
-
.addNamedImports([{ name: 'CID' }])
|
|
83
|
-
|
|
84
|
-
//= import { type OmitKey, type Un$Typed } from './util.js'
|
|
85
|
-
file
|
|
86
|
-
.addImportDeclaration({ moduleSpecifier: `./util.js` })
|
|
87
|
-
.addNamedImports([
|
|
88
|
-
{ name: 'OmitKey', isTypeOnly: true },
|
|
89
|
-
{ name: 'Un$Typed', isTypeOnly: true },
|
|
90
|
-
])
|
|
91
|
-
|
|
92
|
-
// generate type imports and re-exports
|
|
93
|
-
for (const lexicon of lexiconDocs) {
|
|
94
|
-
const moduleSpecifier = `./types/${lexicon.id.split('.').join('/')}.js`
|
|
95
|
-
file
|
|
96
|
-
.addImportDeclaration({ moduleSpecifier })
|
|
97
|
-
.setNamespaceImport(toTitleCase(lexicon.id))
|
|
98
|
-
file
|
|
99
|
-
.addExportDeclaration({ moduleSpecifier })
|
|
100
|
-
.setNamespaceExport(toTitleCase(lexicon.id))
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
// generate token enums
|
|
104
|
-
for (const nsidAuthority in nsidTokens) {
|
|
105
|
-
// export const {THE_AUTHORITY} = {
|
|
106
|
-
// {Name}: "{authority.the.name}"
|
|
107
|
-
// }
|
|
108
|
-
file.addVariableStatement({
|
|
109
|
-
isExported: true,
|
|
110
|
-
declarationKind: VariableDeclarationKind.Const,
|
|
111
|
-
declarations: [
|
|
112
|
-
{
|
|
113
|
-
name: toScreamingSnakeCase(nsidAuthority),
|
|
114
|
-
initializer: [
|
|
115
|
-
'{',
|
|
116
|
-
...nsidTokens[nsidAuthority].map(
|
|
117
|
-
(nsidName) =>
|
|
118
|
-
`${toTitleCase(nsidName)}: "${nsidAuthority}.${nsidName}",`,
|
|
119
|
-
),
|
|
120
|
-
'}',
|
|
121
|
-
].join('\n'),
|
|
122
|
-
},
|
|
123
|
-
],
|
|
124
|
-
})
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
//= export class AtpBaseClient {...}
|
|
128
|
-
const clientCls = file.addClass({
|
|
129
|
-
name: 'AtpBaseClient',
|
|
130
|
-
isExported: true,
|
|
131
|
-
extends: 'XrpcClient',
|
|
132
|
-
})
|
|
133
|
-
|
|
134
|
-
for (const ns of nsidTree) {
|
|
135
|
-
//= ns: NS
|
|
136
|
-
clientCls.addProperty({
|
|
137
|
-
name: ns.propName,
|
|
138
|
-
type: ns.className,
|
|
139
|
-
})
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
//= constructor (options: FetchHandler | FetchHandlerOptions) {
|
|
143
|
-
//= super(options, schemas)
|
|
144
|
-
//= {namespace declarations}
|
|
145
|
-
//= }
|
|
146
|
-
clientCls.addConstructor({
|
|
147
|
-
parameters: [
|
|
148
|
-
{ name: 'options', type: 'FetchHandler | FetchHandlerOptions' },
|
|
149
|
-
],
|
|
150
|
-
statements: [
|
|
151
|
-
'super(options, schemas)',
|
|
152
|
-
...nsidTree.map(
|
|
153
|
-
(ns) => `this.${ns.propName} = new ${ns.className}(this)`,
|
|
154
|
-
),
|
|
155
|
-
],
|
|
156
|
-
})
|
|
157
|
-
|
|
158
|
-
//= /** @deprecated use `this` instead */
|
|
159
|
-
//= get xrpc(): XrpcClient {
|
|
160
|
-
//= return this
|
|
161
|
-
//= }
|
|
162
|
-
clientCls
|
|
163
|
-
.addGetAccessor({
|
|
164
|
-
name: 'xrpc',
|
|
165
|
-
returnType: 'XrpcClient',
|
|
166
|
-
statements: ['return this'],
|
|
167
|
-
})
|
|
168
|
-
.addJsDoc('@deprecated use `this` instead')
|
|
169
|
-
|
|
170
|
-
// generate classes for the schemas
|
|
171
|
-
for (const ns of nsidTree) {
|
|
172
|
-
genNamespaceCls(file, ns)
|
|
173
|
-
}
|
|
174
|
-
})
|
|
175
|
-
|
|
176
|
-
function genNamespaceCls(file: SourceFile, ns: DefTreeNode) {
|
|
177
|
-
//= export class {ns}NS {...}
|
|
178
|
-
const cls = file.addClass({
|
|
179
|
-
name: ns.className,
|
|
180
|
-
isExported: true,
|
|
181
|
-
})
|
|
182
|
-
//= _client: XrpcClient
|
|
183
|
-
cls.addProperty({
|
|
184
|
-
name: '_client',
|
|
185
|
-
type: 'XrpcClient',
|
|
186
|
-
})
|
|
187
|
-
|
|
188
|
-
for (const userType of ns.userTypes) {
|
|
189
|
-
if (userType.def.type !== 'record') {
|
|
190
|
-
continue
|
|
191
|
-
}
|
|
192
|
-
//= type: TypeRecord
|
|
193
|
-
const name = NSID.parse(userType.nsid).name || ''
|
|
194
|
-
cls.addProperty({
|
|
195
|
-
name: toCamelCase(name),
|
|
196
|
-
type: `${toTitleCase(userType.nsid)}Record`,
|
|
197
|
-
})
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
for (const child of ns.children) {
|
|
201
|
-
//= child: ChildNS
|
|
202
|
-
cls.addProperty({
|
|
203
|
-
name: child.propName,
|
|
204
|
-
type: child.className,
|
|
205
|
-
})
|
|
206
|
-
|
|
207
|
-
// recurse
|
|
208
|
-
genNamespaceCls(file, child)
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
//= constructor(public client: XrpcClient) {
|
|
212
|
-
//= this._client = client
|
|
213
|
-
//= {child namespace prop declarations}
|
|
214
|
-
//= {record prop declarations}
|
|
215
|
-
//= }
|
|
216
|
-
cls.addConstructor({
|
|
217
|
-
parameters: [
|
|
218
|
-
{
|
|
219
|
-
name: 'client',
|
|
220
|
-
type: 'XrpcClient',
|
|
221
|
-
},
|
|
222
|
-
],
|
|
223
|
-
statements: [
|
|
224
|
-
`this._client = client`,
|
|
225
|
-
...ns.children.map(
|
|
226
|
-
(ns) => `this.${ns.propName} = new ${ns.className}(client)`,
|
|
227
|
-
),
|
|
228
|
-
...ns.userTypes
|
|
229
|
-
.filter((ut) => ut.def.type === 'record')
|
|
230
|
-
.map((ut) => {
|
|
231
|
-
const name = NSID.parse(ut.nsid).name || ''
|
|
232
|
-
return `this.${toCamelCase(name)} = new ${toTitleCase(
|
|
233
|
-
ut.nsid,
|
|
234
|
-
)}Record(client)`
|
|
235
|
-
}),
|
|
236
|
-
],
|
|
237
|
-
})
|
|
238
|
-
|
|
239
|
-
// methods
|
|
240
|
-
for (const userType of ns.userTypes) {
|
|
241
|
-
if (userType.def.type !== 'query' && userType.def.type !== 'procedure') {
|
|
242
|
-
continue
|
|
243
|
-
}
|
|
244
|
-
const isGetReq = userType.def.type === 'query'
|
|
245
|
-
const moduleName = toTitleCase(userType.nsid)
|
|
246
|
-
const name = toCamelCase(NSID.parse(userType.nsid).name || '')
|
|
247
|
-
const method = cls.addMethod({
|
|
248
|
-
name,
|
|
249
|
-
returnType: `Promise<${moduleName}.Response>`,
|
|
250
|
-
})
|
|
251
|
-
if (isGetReq) {
|
|
252
|
-
method.addParameter({
|
|
253
|
-
name: 'params?',
|
|
254
|
-
type: `${moduleName}.QueryParams`,
|
|
255
|
-
})
|
|
256
|
-
} else if (userType.def.type === 'procedure') {
|
|
257
|
-
method.addParameter({
|
|
258
|
-
name: 'data?',
|
|
259
|
-
type: `${moduleName}.InputSchema`,
|
|
260
|
-
})
|
|
261
|
-
}
|
|
262
|
-
method.addParameter({
|
|
263
|
-
name: 'opts?',
|
|
264
|
-
type: `${moduleName}.CallOptions`,
|
|
265
|
-
})
|
|
266
|
-
method.setBodyText(
|
|
267
|
-
[
|
|
268
|
-
`return this._client`,
|
|
269
|
-
isGetReq
|
|
270
|
-
? `.call('${userType.nsid}', params, undefined, opts)`
|
|
271
|
-
: `.call('${userType.nsid}', opts?.qp, data, opts)`,
|
|
272
|
-
userType.def.errors?.length
|
|
273
|
-
? // Only add a catch block if there are custom errors
|
|
274
|
-
` .catch((e) => { throw ${moduleName}.toKnownErr(e) })`
|
|
275
|
-
: '',
|
|
276
|
-
].join('\n'),
|
|
277
|
-
)
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
// record api classes
|
|
281
|
-
for (const userType of ns.userTypes) {
|
|
282
|
-
if (userType.def.type !== 'record') {
|
|
283
|
-
continue
|
|
284
|
-
}
|
|
285
|
-
genRecordCls(file, userType.nsid, userType.def)
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
function genRecordCls(file: SourceFile, nsid: string, lexRecord: LexRecord) {
|
|
290
|
-
//= export class {type}Record {...}
|
|
291
|
-
const cls = file.addClass({
|
|
292
|
-
name: `${toTitleCase(nsid)}Record`,
|
|
293
|
-
isExported: true,
|
|
294
|
-
})
|
|
295
|
-
//= _client: XrpcClient
|
|
296
|
-
cls.addProperty({
|
|
297
|
-
name: '_client',
|
|
298
|
-
type: 'XrpcClient',
|
|
299
|
-
})
|
|
300
|
-
|
|
301
|
-
//= constructor(client: XrpcClient) {
|
|
302
|
-
//= this._client = client
|
|
303
|
-
//= }
|
|
304
|
-
const cons = cls.addConstructor()
|
|
305
|
-
cons.addParameter({
|
|
306
|
-
name: 'client',
|
|
307
|
-
type: 'XrpcClient',
|
|
308
|
-
})
|
|
309
|
-
cons.setBodyText(`this._client = client`)
|
|
310
|
-
|
|
311
|
-
// methods
|
|
312
|
-
const typeModule = toTitleCase(nsid)
|
|
313
|
-
{
|
|
314
|
-
//= list()
|
|
315
|
-
const method = cls.addMethod({
|
|
316
|
-
isAsync: true,
|
|
317
|
-
name: 'list',
|
|
318
|
-
returnType: `Promise<{cursor?: string, records: ({uri: string, value: ${typeModule}.Record})[]}>`,
|
|
319
|
-
})
|
|
320
|
-
method.addParameter({
|
|
321
|
-
name: 'params',
|
|
322
|
-
type: `OmitKey<${toTitleCase(ATP_METHODS.list)}.QueryParams, "collection">`,
|
|
323
|
-
})
|
|
324
|
-
method.setBodyText(
|
|
325
|
-
[
|
|
326
|
-
`const res = await this._client.call('${ATP_METHODS.list}', { collection: '${nsid}', ...params })`,
|
|
327
|
-
`return res.data`,
|
|
328
|
-
].join('\n'),
|
|
329
|
-
)
|
|
330
|
-
}
|
|
331
|
-
{
|
|
332
|
-
//= get()
|
|
333
|
-
const method = cls.addMethod({
|
|
334
|
-
isAsync: true,
|
|
335
|
-
name: 'get',
|
|
336
|
-
returnType: `Promise<{uri: string, cid: string, value: ${typeModule}.Record}>`,
|
|
337
|
-
})
|
|
338
|
-
method.addParameter({
|
|
339
|
-
name: 'params',
|
|
340
|
-
type: `OmitKey<${toTitleCase(ATP_METHODS.get)}.QueryParams, "collection">`,
|
|
341
|
-
})
|
|
342
|
-
method.setBodyText(
|
|
343
|
-
[
|
|
344
|
-
`const res = await this._client.call('${ATP_METHODS.get}', { collection: '${nsid}', ...params })`,
|
|
345
|
-
`return res.data`,
|
|
346
|
-
].join('\n'),
|
|
347
|
-
)
|
|
348
|
-
}
|
|
349
|
-
{
|
|
350
|
-
//= create()
|
|
351
|
-
const method = cls.addMethod({
|
|
352
|
-
isAsync: true,
|
|
353
|
-
name: 'create',
|
|
354
|
-
returnType: 'Promise<{uri: string, cid: string}>',
|
|
355
|
-
})
|
|
356
|
-
method.addParameter({
|
|
357
|
-
name: 'params',
|
|
358
|
-
type: `OmitKey<${toTitleCase(
|
|
359
|
-
ATP_METHODS.create,
|
|
360
|
-
)}.InputSchema, "collection" | "record">`,
|
|
361
|
-
})
|
|
362
|
-
method.addParameter({
|
|
363
|
-
name: 'record',
|
|
364
|
-
type: `Un$Typed<${typeModule}.Record>`,
|
|
365
|
-
})
|
|
366
|
-
method.addParameter({
|
|
367
|
-
name: 'headers?',
|
|
368
|
-
type: `Record<string, string>`,
|
|
369
|
-
})
|
|
370
|
-
const maybeRkeyPart = lexRecord.key?.startsWith('literal:')
|
|
371
|
-
? `rkey: '${lexRecord.key.replace('literal:', '')}', `
|
|
372
|
-
: ''
|
|
373
|
-
method.setBodyText(
|
|
374
|
-
[
|
|
375
|
-
`const collection = '${nsid}'`,
|
|
376
|
-
`const res = await this._client.call('${ATP_METHODS.create}', undefined, { collection, ${maybeRkeyPart}...params, record: { ...record, $type: collection } }, { encoding: 'application/json', headers })`,
|
|
377
|
-
`return res.data`,
|
|
378
|
-
].join('\n'),
|
|
379
|
-
)
|
|
380
|
-
}
|
|
381
|
-
{
|
|
382
|
-
//= put()
|
|
383
|
-
const method = cls.addMethod({
|
|
384
|
-
isAsync: true,
|
|
385
|
-
name: 'put',
|
|
386
|
-
returnType: 'Promise<{uri: string, cid: string}>',
|
|
387
|
-
})
|
|
388
|
-
method.addParameter({
|
|
389
|
-
name: 'params',
|
|
390
|
-
type: `OmitKey<${toTitleCase(ATP_METHODS.put)}.InputSchema, "collection" | "record">`,
|
|
391
|
-
})
|
|
392
|
-
method.addParameter({
|
|
393
|
-
name: 'record',
|
|
394
|
-
type: `Un$Typed<${typeModule}.Record>`,
|
|
395
|
-
})
|
|
396
|
-
method.addParameter({
|
|
397
|
-
name: 'headers?',
|
|
398
|
-
type: `Record<string, string>`,
|
|
399
|
-
})
|
|
400
|
-
method.setBodyText(
|
|
401
|
-
[
|
|
402
|
-
`const collection = '${nsid}'`,
|
|
403
|
-
`const res = await this._client.call('${ATP_METHODS.put}', undefined, { collection, ...params, record: { ...record, $type: collection } }, { encoding: 'application/json', headers })`,
|
|
404
|
-
`return res.data`,
|
|
405
|
-
].join('\n'),
|
|
406
|
-
)
|
|
407
|
-
}
|
|
408
|
-
{
|
|
409
|
-
//= delete()
|
|
410
|
-
const method = cls.addMethod({
|
|
411
|
-
isAsync: true,
|
|
412
|
-
name: 'delete',
|
|
413
|
-
returnType: 'Promise<void>',
|
|
414
|
-
})
|
|
415
|
-
method.addParameter({
|
|
416
|
-
name: 'params',
|
|
417
|
-
type: `OmitKey<${toTitleCase(
|
|
418
|
-
ATP_METHODS.delete,
|
|
419
|
-
)}.InputSchema, "collection">`,
|
|
420
|
-
})
|
|
421
|
-
method.addParameter({
|
|
422
|
-
name: 'headers?',
|
|
423
|
-
type: `Record<string, string>`,
|
|
424
|
-
})
|
|
425
|
-
|
|
426
|
-
method.setBodyText(
|
|
427
|
-
[
|
|
428
|
-
`await this._client.call('${ATP_METHODS.delete}', undefined, { collection: '${nsid}', ...params }, { headers })`,
|
|
429
|
-
].join('\n'),
|
|
430
|
-
)
|
|
431
|
-
}
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
const lexiconTs = (project, lexicons: Lexicons, lexiconDoc: LexiconDoc) =>
|
|
435
|
-
gen(
|
|
436
|
-
project,
|
|
437
|
-
`/types/${lexiconDoc.id.split('.').join('/')}.ts`,
|
|
438
|
-
async (file) => {
|
|
439
|
-
const main = lexiconDoc.defs.main
|
|
440
|
-
if (
|
|
441
|
-
main?.type === 'query' ||
|
|
442
|
-
main?.type === 'subscription' ||
|
|
443
|
-
main?.type === 'procedure'
|
|
444
|
-
) {
|
|
445
|
-
//= import {HeadersMap, XRPCError} from '@atproto/xrpc'
|
|
446
|
-
const xrpcImport = file.addImportDeclaration({
|
|
447
|
-
moduleSpecifier: '@atproto/xrpc',
|
|
448
|
-
})
|
|
449
|
-
xrpcImport.addNamedImports([
|
|
450
|
-
{ name: 'HeadersMap' },
|
|
451
|
-
{ name: 'XRPCError' },
|
|
452
|
-
])
|
|
453
|
-
}
|
|
454
|
-
|
|
455
|
-
genCommonImports(file, lexiconDoc.id)
|
|
456
|
-
|
|
457
|
-
const imports: Set<string> = new Set()
|
|
458
|
-
for (const defId in lexiconDoc.defs) {
|
|
459
|
-
const def = lexiconDoc.defs[defId]
|
|
460
|
-
const lexUri = `${lexiconDoc.id}#${defId}`
|
|
461
|
-
if (defId === 'main') {
|
|
462
|
-
if (def.type === 'query' || def.type === 'procedure') {
|
|
463
|
-
genXrpcParams(file, lexicons, lexUri, false)
|
|
464
|
-
genXrpcInput(file, imports, lexicons, lexUri, false)
|
|
465
|
-
genXrpcOutput(file, imports, lexicons, lexUri)
|
|
466
|
-
genClientXrpcCommon(file, lexicons, lexUri)
|
|
467
|
-
} else if (def.type === 'subscription') {
|
|
468
|
-
continue
|
|
469
|
-
} else if (def.type === 'record') {
|
|
470
|
-
genRecord(file, imports, lexicons, lexUri)
|
|
471
|
-
} else {
|
|
472
|
-
genUserType(file, imports, lexicons, lexUri)
|
|
473
|
-
}
|
|
474
|
-
} else {
|
|
475
|
-
genUserType(file, imports, lexicons, lexUri)
|
|
476
|
-
}
|
|
477
|
-
}
|
|
478
|
-
genImports(file, imports, lexiconDoc.id)
|
|
479
|
-
},
|
|
480
|
-
)
|
|
481
|
-
|
|
482
|
-
function genClientXrpcCommon(
|
|
483
|
-
file: SourceFile,
|
|
484
|
-
lexicons: Lexicons,
|
|
485
|
-
lexUri: string,
|
|
486
|
-
) {
|
|
487
|
-
const def = lexicons.getDefOrThrow(lexUri, ['query', 'procedure'])
|
|
488
|
-
|
|
489
|
-
//= export interface CallOptions {...}
|
|
490
|
-
const opts = file.addInterface({
|
|
491
|
-
name: 'CallOptions',
|
|
492
|
-
isExported: true,
|
|
493
|
-
})
|
|
494
|
-
opts.addProperty({ name: 'signal?', type: 'AbortSignal' })
|
|
495
|
-
opts.addProperty({ name: 'headers?', type: 'HeadersMap' })
|
|
496
|
-
if (def.type === 'procedure') {
|
|
497
|
-
opts.addProperty({ name: 'qp?', type: 'QueryParams' })
|
|
498
|
-
}
|
|
499
|
-
if (def.type === 'procedure' && def.input) {
|
|
500
|
-
let encodingType = 'string'
|
|
501
|
-
if (def.input.encoding !== '*/*') {
|
|
502
|
-
encodingType = def.input.encoding
|
|
503
|
-
.split(',')
|
|
504
|
-
.map((v) => `'${v.trim()}'`)
|
|
505
|
-
.join(' | ')
|
|
506
|
-
}
|
|
507
|
-
opts.addProperty({
|
|
508
|
-
name: 'encoding?',
|
|
509
|
-
type: encodingType,
|
|
510
|
-
})
|
|
511
|
-
}
|
|
512
|
-
|
|
513
|
-
// export interface Response {...}
|
|
514
|
-
const res = file.addInterface({
|
|
515
|
-
name: 'Response',
|
|
516
|
-
isExported: true,
|
|
517
|
-
})
|
|
518
|
-
res.addProperty({ name: 'success', type: 'boolean' })
|
|
519
|
-
res.addProperty({ name: 'headers', type: 'HeadersMap' })
|
|
520
|
-
if (def.output?.schema) {
|
|
521
|
-
if (def.output.encoding?.includes(',')) {
|
|
522
|
-
res.addProperty({ name: 'data', type: 'OutputSchema | Uint8Array' })
|
|
523
|
-
} else {
|
|
524
|
-
res.addProperty({ name: 'data', type: 'OutputSchema' })
|
|
525
|
-
}
|
|
526
|
-
} else if (def.output?.encoding) {
|
|
527
|
-
res.addProperty({ name: 'data', type: 'Uint8Array' })
|
|
528
|
-
}
|
|
529
|
-
|
|
530
|
-
// export class {errcode}Error {...}
|
|
531
|
-
const customErrors: { name: string; cls: string }[] = []
|
|
532
|
-
for (const error of def.errors || []) {
|
|
533
|
-
let name = toTitleCase(error.name)
|
|
534
|
-
if (!name.endsWith('Error')) name += 'Error'
|
|
535
|
-
const errCls = file.addClass({
|
|
536
|
-
name,
|
|
537
|
-
extends: 'XRPCError',
|
|
538
|
-
isExported: true,
|
|
539
|
-
})
|
|
540
|
-
errCls.addConstructor({
|
|
541
|
-
parameters: [{ name: 'src', type: 'XRPCError' }],
|
|
542
|
-
statements: [
|
|
543
|
-
'super(src.status, src.error, src.message, src.headers, { cause: src })',
|
|
544
|
-
],
|
|
545
|
-
})
|
|
546
|
-
|
|
547
|
-
customErrors.push({ name: error.name, cls: name })
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
// export function toKnownErr(err: any) {...}
|
|
551
|
-
file.addFunction({
|
|
552
|
-
name: 'toKnownErr',
|
|
553
|
-
isExported: true,
|
|
554
|
-
parameters: [{ name: 'e', type: 'any' }],
|
|
555
|
-
statements: customErrors.length
|
|
556
|
-
? [
|
|
557
|
-
'if (e instanceof XRPCError) {',
|
|
558
|
-
...customErrors.map(
|
|
559
|
-
(err) => `if (e.error === '${err.name}') return new ${err.cls}(e)`,
|
|
560
|
-
),
|
|
561
|
-
'}',
|
|
562
|
-
'return e',
|
|
563
|
-
]
|
|
564
|
-
: ['return e'],
|
|
565
|
-
})
|
|
566
|
-
}
|