@taqueria/plugin-contract-types 0.0.0-pr-91-a8fa7172
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/Readme.md +212 -0
- package/example/contracts/example-contract-1.tz +1409 -0
- package/example/contracts/example-contract-2.tz +798 -0
- package/example/contracts/example-contract-3.json +7080 -0
- package/example/contracts/example-contract-4.tz +1374 -0
- package/example/contracts/example-contract-5.tz +1424 -0
- package/example/contracts/example-contract-6.tz +675 -0
- package/example/contracts/example-contract-7.tz +384 -0
- package/example/contracts/example-contract-8.tz +28 -0
- package/example/contracts/example-contract-9.tz +1010 -0
- package/example/example-usage-type-utilities.ts +35 -0
- package/example/example-usage.ts +410 -0
- package/example/types-file/example-contract-1.code.ts +6 -0
- package/example/types-file/example-contract-1.types.ts +87 -0
- package/example/types-file/example-contract-2.code.ts +6 -0
- package/example/types-file/example-contract-2.types.ts +122 -0
- package/example/types-file/example-contract-4.code.ts +6 -0
- package/example/types-file/example-contract-4.types.ts +97 -0
- package/example/types-file/example-contract-5.code.ts +6 -0
- package/example/types-file/example-contract-5.types.ts +173 -0
- package/example/types-file/example-contract-6.code.ts +6 -0
- package/example/types-file/example-contract-6.types.ts +122 -0
- package/example/types-file/example-contract-7.code.ts +6 -0
- package/example/types-file/example-contract-7.types.ts +78 -0
- package/example/types-file/example-contract-8.code.ts +6 -0
- package/example/types-file/example-contract-8.types.ts +86 -0
- package/example/types-file/example-contract-9.code.ts +6 -0
- package/example/types-file/example-contract-9.types.ts +29 -0
- package/example/types-file/type-aliases.ts +81 -0
- package/example/types-file/type-utils.ts +36 -0
- package/index.js +969 -0
- package/index.js.map +1 -0
- package/index.ts +32 -0
- package/package.json +55 -0
- package/run.ts +3 -0
- package/src/cli-process.ts +111 -0
- package/src/cli.ts +34 -0
- package/src/generator/common.ts +21 -0
- package/src/generator/contract-name.ts +6 -0
- package/src/generator/contract-parser.ts +358 -0
- package/src/generator/process.ts +66 -0
- package/src/generator/schema-output.ts +54 -0
- package/src/generator/typescript-output.ts +239 -0
- package/src/taquito-contract-type-generator.ts +4 -0
- package/src/type-aliases-file-content.ts +83 -0
- package/src/type-aliases.ts +80 -0
- package/src/type-utils-file-content.ts +38 -0
- package/src/type-utils.ts +35 -0
- package/tasks.ts +127 -0
- package/test/generator.spec.ts +69 -0
- package/tsconfig.json +13 -0
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
import * as M from '@taquito/michel-codec';
|
|
2
|
+
import { assertExhaustive, GenerateApiError, reduceFlatMap } from './common';
|
|
3
|
+
|
|
4
|
+
export type TypedStorage = {
|
|
5
|
+
storage: {
|
|
6
|
+
kind: 'object';
|
|
7
|
+
raw: M.MichelsonType;
|
|
8
|
+
fields: TypedVar[];
|
|
9
|
+
};
|
|
10
|
+
};
|
|
11
|
+
export type TypedParameter = {
|
|
12
|
+
methods: TypedMethod[];
|
|
13
|
+
};
|
|
14
|
+
export type TypedMethod = {
|
|
15
|
+
name: string;
|
|
16
|
+
args: TypedVar[];
|
|
17
|
+
};
|
|
18
|
+
export type TypedVar = {
|
|
19
|
+
name?: string;
|
|
20
|
+
type: TypedType;
|
|
21
|
+
};
|
|
22
|
+
export type TypedType = {
|
|
23
|
+
raw: M.MichelsonType;
|
|
24
|
+
optional?: boolean;
|
|
25
|
+
} & (
|
|
26
|
+
{
|
|
27
|
+
kind: 'unit';
|
|
28
|
+
} | {
|
|
29
|
+
kind: 'never';
|
|
30
|
+
} | {
|
|
31
|
+
kind: 'unknown';
|
|
32
|
+
} | {
|
|
33
|
+
kind: 'value';
|
|
34
|
+
value: string;
|
|
35
|
+
typescriptType: 'string' | 'boolean' | 'number' | 'Date';
|
|
36
|
+
} | {
|
|
37
|
+
kind: 'union';
|
|
38
|
+
union: TypedVar[];
|
|
39
|
+
} | {
|
|
40
|
+
kind: 'object';
|
|
41
|
+
fields: TypedVar[];
|
|
42
|
+
} | {
|
|
43
|
+
kind: 'array';
|
|
44
|
+
array: { item: TypedType };
|
|
45
|
+
} | {
|
|
46
|
+
kind: 'map';
|
|
47
|
+
map: { key: TypedType, value: TypedType, isBigMap: boolean };
|
|
48
|
+
}
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
const toDebugSource = (node: M.MichelsonType) => {
|
|
52
|
+
return JSON.stringify(node);
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export const parseContractStorage = (storage: M.MichelsonContractStorage): TypedStorage => {
|
|
56
|
+
const fields = storage.args
|
|
57
|
+
.map(x => visitVar(x))
|
|
58
|
+
.reduce(reduceFlatMap, []);
|
|
59
|
+
|
|
60
|
+
const fieldsSimple = fields.length === 1 && !fields[0].name && fields[0].type.kind === 'object' ? fields[0].type.fields : fields;
|
|
61
|
+
|
|
62
|
+
return {
|
|
63
|
+
storage: {
|
|
64
|
+
kind: `object`,
|
|
65
|
+
raw: storage as unknown as M.MichelsonType,
|
|
66
|
+
fields: fieldsSimple,
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
export const parseContractParameter = (parameter: M.MichelsonContractParameter): TypedParameter => {
|
|
72
|
+
return {
|
|
73
|
+
methods: parameter.args
|
|
74
|
+
.map(x => visitContractParameterEndpoint(x as MMethod))
|
|
75
|
+
.reduce(reduceFlatMap, []),
|
|
76
|
+
};
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
type MMethod = M.MichelsonTypeOr<[M.MichelsonType, M.MichelsonType]>;
|
|
81
|
+
const visitContractParameterEndpoint = (node: MMethod): TypedMethod[] => {
|
|
82
|
+
|
|
83
|
+
// console.log('visitContractParameterEndpoint', { node });
|
|
84
|
+
|
|
85
|
+
// Sub endpoints (i.e. admin endpoints that are imported)
|
|
86
|
+
if (node.prim === `or`) {
|
|
87
|
+
return node.args.map(x => visitContractParameterEndpoint(x as MMethod)).reduce(reduceFlatMap, []);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Sub endpoints as a list with a single or (i.e. admin endpoints that are imported)
|
|
91
|
+
if (node.prim === `list` && node.args.length as number === 1 && (node.args[0] as MMethod)?.prim === `or`) {
|
|
92
|
+
return node.args.map(x => visitContractParameterEndpoint(x as MMethod)).reduce(reduceFlatMap, []);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const nameRaw = node.annots?.[0];
|
|
96
|
+
const name = nameRaw?.startsWith('%') ? nameRaw.substr(1) : null;
|
|
97
|
+
|
|
98
|
+
if (!name) {
|
|
99
|
+
console.warn(`Unknown method: ${node.prim as string}`, { node, args: node.args });
|
|
100
|
+
return [];
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const nodeType = visitType(node, { ignorePairName: node.prim === 'pair' });
|
|
104
|
+
|
|
105
|
+
// Method args are usually objects
|
|
106
|
+
if (nodeType.kind === 'object') {
|
|
107
|
+
return [{ name, args: nodeType.fields }];
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Simple methods can have a single unnamed argument
|
|
111
|
+
return [{
|
|
112
|
+
name,
|
|
113
|
+
args: [{ type: nodeType }],
|
|
114
|
+
}];
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
// type PrimOf<T extends M.MichelsonType> = T extends { prim: infer U } ? U : never;
|
|
118
|
+
// type WithPrim<T extends M.MichelsonType, P extends PrimOf<T>> = T extends { prim: P } ? T : never;
|
|
119
|
+
// const isPrimType = <TPrim extends PrimOf<M.MichelsonType>>(node: undefined | null | M.MichelsonType, prim: TPrim): node is WithPrim<M.MichelsonType, TPrim> => {
|
|
120
|
+
// return (node && 'prim' in node && node.prim === prim) || false;
|
|
121
|
+
// };
|
|
122
|
+
|
|
123
|
+
type MVarArgs = M.MichelsonType;
|
|
124
|
+
const visitVar = (node: MVarArgs): TypedVar[] => {
|
|
125
|
+
const name = `annots` in node && node.annots?.length === 1 ? node.annots[0].substr(1) : undefined;
|
|
126
|
+
const type = visitType(node);
|
|
127
|
+
|
|
128
|
+
return [{
|
|
129
|
+
name,
|
|
130
|
+
type,
|
|
131
|
+
}];
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
type MType = M.MichelsonType;
|
|
135
|
+
const visitType = (node: MType, options?: { ignorePairName?: boolean }): TypedType => {
|
|
136
|
+
// console.log('visitType', { node });
|
|
137
|
+
// const debug_source = toDebugSource(node);
|
|
138
|
+
|
|
139
|
+
// if (typeof node === `string`) {
|
|
140
|
+
// return { kind: `value`, raw: node, value: node, typescriptType: `string` };
|
|
141
|
+
// }
|
|
142
|
+
|
|
143
|
+
if (!(`prim` in node)) {
|
|
144
|
+
// Unknown
|
|
145
|
+
console.error(`visitType no prim`, { node });
|
|
146
|
+
return { kind: `unknown`, raw: node };
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Union
|
|
150
|
+
if (node.prim === `or`) {
|
|
151
|
+
const unionVars = node.args.map(x => visitVar(x)).reduce(reduceFlatMap, []).map(x => x);
|
|
152
|
+
|
|
153
|
+
// Flatten with child unions
|
|
154
|
+
const union = unionVars.map(x => !x.name && x.type.kind === 'union' ? x.type.union : [x]).reduce(reduceFlatMap, []);
|
|
155
|
+
// const union = unionVars.map(x=>x.type);
|
|
156
|
+
|
|
157
|
+
// const union = unionVars.map(x => x.type);
|
|
158
|
+
|
|
159
|
+
// Flatten with child unions
|
|
160
|
+
|
|
161
|
+
// const rightSide = union[1];
|
|
162
|
+
// if (rightSide.kind === `union`) {
|
|
163
|
+
// union.pop();
|
|
164
|
+
// union.push(...rightSide.union);
|
|
165
|
+
// }
|
|
166
|
+
|
|
167
|
+
if (union.some(x => !x)) {
|
|
168
|
+
throw new GenerateApiError(`or: Some fields are null`, { node });
|
|
169
|
+
}
|
|
170
|
+
return {
|
|
171
|
+
kind: `union`,
|
|
172
|
+
raw: node,
|
|
173
|
+
union,
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Intersect
|
|
178
|
+
if (node.prim === `pair`) {
|
|
179
|
+
const fields = node.args.map(x => visitVar(x)).reduce(reduceFlatMap, []);
|
|
180
|
+
if (fields.some(x => !x)) {
|
|
181
|
+
throw new GenerateApiError(`pair: Some fields are null`, { node, args: node.args, fields });
|
|
182
|
+
}
|
|
183
|
+
if (fields.length !== 2) {
|
|
184
|
+
throw new GenerateApiError(`pair: Expected 2 items`, { node, length: fields.length, fields });
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Flatten with unnamed child pairs
|
|
188
|
+
const fieldsFlat = fields.map(x => (!x.name || options?.ignorePairName) && x.type.kind === 'object' ? x.type.fields : [x]).reduce(reduceFlatMap, []);
|
|
189
|
+
|
|
190
|
+
return {
|
|
191
|
+
kind: `object`,
|
|
192
|
+
raw: node,
|
|
193
|
+
fields: fieldsFlat,
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// list
|
|
198
|
+
if (node.prim === `list`
|
|
199
|
+
|| node.prim === `set`
|
|
200
|
+
) {
|
|
201
|
+
if (node.args.length !== 1) {
|
|
202
|
+
throw new GenerateApiError(`list does not have 1 arg`, { node, args: node.args });
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
const arrayItem = visitType(node.args[0]);
|
|
206
|
+
if (!arrayItem) {
|
|
207
|
+
throw new GenerateApiError(`arrayItem are null`, { node, args: node.args, arrayItem });
|
|
208
|
+
}
|
|
209
|
+
return {
|
|
210
|
+
kind: `array`,
|
|
211
|
+
raw: node,
|
|
212
|
+
array: { item: arrayItem },
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// map
|
|
217
|
+
if (node.prim === `map`
|
|
218
|
+
|| node.prim === `big_map`
|
|
219
|
+
) {
|
|
220
|
+
if (node.args.length !== 2) {
|
|
221
|
+
throw new GenerateApiError(`map does not have 2 args`, { node, args: node.args });
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
const mapKey = visitType(node.args[0]);
|
|
225
|
+
const mapValue = visitType(node.args[1]);
|
|
226
|
+
if (!mapKey || !mapValue) {
|
|
227
|
+
throw new GenerateApiError(`map is missing key or value`, { node, args: node.args, mapKey, mapValue });
|
|
228
|
+
}
|
|
229
|
+
return {
|
|
230
|
+
kind: `map`,
|
|
231
|
+
raw: node,
|
|
232
|
+
map: {
|
|
233
|
+
key: mapKey,
|
|
234
|
+
value: mapValue,
|
|
235
|
+
isBigMap: node.prim === `big_map`,
|
|
236
|
+
},
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// option
|
|
241
|
+
if (node.prim === `option`) {
|
|
242
|
+
return {
|
|
243
|
+
...visitType(node.args[0]),
|
|
244
|
+
optional: true,
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// boolean
|
|
249
|
+
if (node.prim === `bool`) {
|
|
250
|
+
return {
|
|
251
|
+
kind: `value`,
|
|
252
|
+
raw: node,
|
|
253
|
+
value: node.prim,
|
|
254
|
+
typescriptType: `boolean`,
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// numbers
|
|
259
|
+
if (node.prim === `nat`
|
|
260
|
+
|| node.prim === `int`
|
|
261
|
+
|| node.prim === `mutez`
|
|
262
|
+
) {
|
|
263
|
+
return {
|
|
264
|
+
kind: `value`,
|
|
265
|
+
raw: node,
|
|
266
|
+
value: node.prim,
|
|
267
|
+
typescriptType: `number`,
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// Date
|
|
272
|
+
if (node.prim === `timestamp`
|
|
273
|
+
|
|
274
|
+
) {
|
|
275
|
+
return {
|
|
276
|
+
kind: `value`,
|
|
277
|
+
raw: node,
|
|
278
|
+
value: node.prim,
|
|
279
|
+
typescriptType: `Date`,
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// strings
|
|
284
|
+
if (node.prim === `address`
|
|
285
|
+
|| node.prim === `key`
|
|
286
|
+
|| node.prim === `key_hash`
|
|
287
|
+
|| node.prim === `chain_id`
|
|
288
|
+
|| node.prim === `string`
|
|
289
|
+
|| node.prim === `signature`
|
|
290
|
+
|| node.prim === `ticket`
|
|
291
|
+
|| node.prim === `bls12_381_fr`
|
|
292
|
+
|| node.prim === `bls12_381_g1`
|
|
293
|
+
|| node.prim === `bls12_381_g2`
|
|
294
|
+
|| node.prim === `sapling_state`
|
|
295
|
+
|| node.prim === `sapling_transaction`
|
|
296
|
+
|| node.prim === `contract`
|
|
297
|
+
) {
|
|
298
|
+
return {
|
|
299
|
+
kind: `value`,
|
|
300
|
+
raw: node,
|
|
301
|
+
value: node.prim,
|
|
302
|
+
typescriptType: `string`,
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
// void
|
|
308
|
+
if (node.prim === `unit`) {
|
|
309
|
+
return {
|
|
310
|
+
kind: `unit`,
|
|
311
|
+
raw: node,
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
// bytes?
|
|
316
|
+
if (node.prim === `bytes`) {
|
|
317
|
+
return {
|
|
318
|
+
kind: `value`,
|
|
319
|
+
raw: node,
|
|
320
|
+
value: node.prim,
|
|
321
|
+
typescriptType: `string`,
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// misc?
|
|
326
|
+
if (node.prim === `lambda`
|
|
327
|
+
|| node.prim === `operation`
|
|
328
|
+
) {
|
|
329
|
+
return {
|
|
330
|
+
kind: `value`,
|
|
331
|
+
raw: node,
|
|
332
|
+
value: node.prim,
|
|
333
|
+
typescriptType: `string`,
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
// chest
|
|
338
|
+
if(node.prim === 'chest'){
|
|
339
|
+
throw new Error('Not Implemented: chest');
|
|
340
|
+
}
|
|
341
|
+
if(node.prim === 'chest_key'){
|
|
342
|
+
throw new Error('Not Implemented: chest_key');
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// never
|
|
346
|
+
if (node.prim === `never`
|
|
347
|
+
) {
|
|
348
|
+
return {
|
|
349
|
+
kind: `never`,
|
|
350
|
+
raw: node,
|
|
351
|
+
};
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
|
|
355
|
+
// Unknown
|
|
356
|
+
assertExhaustive(node, `Unknown type`);
|
|
357
|
+
throw new GenerateApiError(`Unknown type`, { node });
|
|
358
|
+
};
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import * as M from '@taquito/michel-codec';
|
|
2
|
+
import { GenerateApiError } from './common';
|
|
3
|
+
import { parseContractStorage, parseContractParameter } from './contract-parser';
|
|
4
|
+
import { SchemaOutput, toSchema } from './schema-output';
|
|
5
|
+
import { TypescriptCodeOutput, toTypescriptCode, TypeAliasData, TypeUtilsData } from './typescript-output';
|
|
6
|
+
|
|
7
|
+
const parseContractWithMinimalProtocolLevel = (contractScript: string, format: 'tz' | 'json', contractLevelIndex: number): { contract: M.MichelsonContract, protocol: { name: string, key: string } } => {
|
|
8
|
+
const contractLevels = [
|
|
9
|
+
{ name: 'PsDELPH1', key: M.Protocol.PsDELPH1 },
|
|
10
|
+
{ name: 'PtEdo2Zk', key: M.Protocol.PtEdo2Zk },
|
|
11
|
+
{ name: 'PsFLorena', key: M.Protocol.PsFLorena },
|
|
12
|
+
];
|
|
13
|
+
|
|
14
|
+
const protocol = contractLevels[contractLevelIndex];
|
|
15
|
+
if (!protocol) {
|
|
16
|
+
throw new GenerateApiError(`Could not parse contract script`, contractScript);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const p = new M.Parser({ protocol: protocol.key });
|
|
20
|
+
|
|
21
|
+
try {
|
|
22
|
+
const contract = (format === 'tz' ? p.parseScript(contractScript) : p.parseJSON(JSON.parse(contractScript))) as M.MichelsonContract;
|
|
23
|
+
if (contract) {
|
|
24
|
+
return {
|
|
25
|
+
contract,
|
|
26
|
+
protocol,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
} catch {
|
|
30
|
+
// Ignore parse errors
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Try again with next level
|
|
34
|
+
return parseContractWithMinimalProtocolLevel(contractScript, format, contractLevelIndex + 1);
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export const generateContractTypesFromMichelsonCode = (contractScript: string, contractName: string, format: 'tz' | 'json', typeAliasData: TypeAliasData, typeUtilsData: TypeUtilsData): {
|
|
38
|
+
schema: SchemaOutput;
|
|
39
|
+
typescriptCodeOutput: TypescriptCodeOutput;
|
|
40
|
+
parsedContract: M.MichelsonContract;
|
|
41
|
+
minimalProtocol: string;
|
|
42
|
+
} => {
|
|
43
|
+
|
|
44
|
+
const p = new M.Parser({ protocol: M.Protocol.PsFLorena });
|
|
45
|
+
|
|
46
|
+
const { contract, protocol } = parseContractWithMinimalProtocolLevel(contractScript, format, 0);
|
|
47
|
+
|
|
48
|
+
const contractStorage = contract.find(x => x.prim === `storage`) as undefined | M.MichelsonContractStorage;
|
|
49
|
+
const contractParameter = contract.find(x => x.prim === `parameter`) as undefined | M.MichelsonContractParameter;
|
|
50
|
+
|
|
51
|
+
const storageResult = contractStorage && parseContractStorage(contractStorage);
|
|
52
|
+
const storage = storageResult ?? { storage: { kind: `object`, raw: { prim: `never` } as M.MichelsonType, fields: [] } };
|
|
53
|
+
|
|
54
|
+
const parameterResult = contractParameter && parseContractParameter(contractParameter);
|
|
55
|
+
const methods = parameterResult?.methods ?? [];
|
|
56
|
+
const schemaOutput = toSchema(methods);
|
|
57
|
+
|
|
58
|
+
const typescriptCode = toTypescriptCode(storage, methods, contractName, contract, protocol, typeAliasData, typeUtilsData);
|
|
59
|
+
|
|
60
|
+
return {
|
|
61
|
+
schema: schemaOutput,
|
|
62
|
+
typescriptCodeOutput: typescriptCode,
|
|
63
|
+
parsedContract: contract,
|
|
64
|
+
minimalProtocol: protocol.key,
|
|
65
|
+
};
|
|
66
|
+
};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { GenerateApiError } from './common';
|
|
2
|
+
import { TypedMethod, TypedVar, TypedType } from './contract-parser';
|
|
3
|
+
|
|
4
|
+
type SchemaObjectType = { [name: string]: SchemaType };
|
|
5
|
+
type SchemaType = string | SchemaType[] | SchemaObjectType;
|
|
6
|
+
type SchemaMethods = {
|
|
7
|
+
[name: string]: {
|
|
8
|
+
params: SchemaType;
|
|
9
|
+
};
|
|
10
|
+
};
|
|
11
|
+
export type SchemaOutput = {
|
|
12
|
+
schemaMethods: SchemaMethods;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export const toSchema = (methods: TypedMethod[]): SchemaOutput => {
|
|
16
|
+
|
|
17
|
+
const getSchemaObjectType = (vars: TypedVar[]) => {
|
|
18
|
+
// console.log('getSchemaObjectType', { vars });
|
|
19
|
+
|
|
20
|
+
if (vars.some(x => !x)) {
|
|
21
|
+
throw new GenerateApiError(`getSchemaObjectType has null vars`, { vars });
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return vars.reduce((out, x, i) => {
|
|
25
|
+
out[x.name ?? i] = getSchemaType(x.type);
|
|
26
|
+
return out;
|
|
27
|
+
}, {} as SchemaObjectType);
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const getSchemaType = (t: TypedType): SchemaType => {
|
|
31
|
+
// console.log('getSchemaType', { t });
|
|
32
|
+
|
|
33
|
+
return (t.kind === `value` && t.value ? t.value : null)
|
|
34
|
+
?? (t.kind === `array` && t.array ? [getSchemaType(t.array.item)] : null)
|
|
35
|
+
?? (t.kind === `map` && t.map ? [`map`, getSchemaType(t.map.key), getSchemaType(t.map.value)] : null)
|
|
36
|
+
?? (t.kind === `object` && t.fields ? getSchemaObjectType(t.fields) : null)
|
|
37
|
+
?? (t.kind === `unit` ? `unit` : null)
|
|
38
|
+
?? (t.kind === `never` ? `never` : null)
|
|
39
|
+
?? `${t.raw as unknown as string}`;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const schemaMethods = methods.reduce((out, x) => {
|
|
43
|
+
// console.log('schemaMethods', { x });
|
|
44
|
+
|
|
45
|
+
out[x.name] = {
|
|
46
|
+
params: x.args.length === 1 && !x.args[0].name ? getSchemaType(x.args[0].type) : getSchemaObjectType(x.args ?? []),
|
|
47
|
+
};
|
|
48
|
+
return out;
|
|
49
|
+
}, {} as SchemaMethods);
|
|
50
|
+
|
|
51
|
+
return {
|
|
52
|
+
schemaMethods,
|
|
53
|
+
};
|
|
54
|
+
};
|