@0xobelisk/sui-common 1.2.0-pre.99 → 2.0.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.
Files changed (39) hide show
  1. package/LICENSE +92 -0
  2. package/README.md +670 -1
  3. package/dist/index.d.ts +61 -27
  4. package/dist/index.js +1078 -461
  5. package/dist/index.js.map +1 -1
  6. package/package.json +15 -17
  7. package/src/codegen/debug.ts +0 -4
  8. package/src/codegen/types/index.ts +46 -10
  9. package/src/codegen/utils/config.ts +1 -1
  10. package/src/codegen/utils/format.ts +0 -6
  11. package/src/codegen/utils/formatAndWrite.ts +10 -31
  12. package/src/codegen/utils/generateLock.ts +122 -0
  13. package/src/codegen/utils/index.ts +4 -2
  14. package/src/codegen/utils/renderMove/{schemaGen.ts → codegen.ts} +40 -28
  15. package/src/codegen/utils/renderMove/common.ts +0 -65
  16. package/src/codegen/utils/renderMove/dapp.ts +2 -14
  17. package/src/codegen/utils/renderMove/generateDappKey.ts +33 -18
  18. package/src/codegen/utils/renderMove/generateError.ts +32 -15
  19. package/src/codegen/utils/renderMove/generateGenesis.ts +55 -22
  20. package/src/codegen/utils/renderMove/generateInitTest.ts +26 -14
  21. package/src/codegen/utils/renderMove/generateObjects.ts +377 -0
  22. package/src/codegen/utils/renderMove/generatePermits.ts +151 -0
  23. package/src/codegen/utils/renderMove/generateResources.ts +894 -242
  24. package/src/codegen/utils/renderMove/generateScenes.ts +467 -0
  25. package/src/codegen/utils/renderMove/generateScript.ts +18 -13
  26. package/src/codegen/utils/renderMove/generateSystem.ts +0 -2
  27. package/src/codegen/utils/renderMove/generateUserStorageInit.ts +37 -0
  28. package/src/codegen/utils/validateConfig.ts +237 -0
  29. package/src/index.ts +0 -1
  30. package/src/modules.d.ts +0 -10
  31. package/src/codegen/modules.d.ts +0 -1
  32. package/src/codegen/utils/posixPath.ts +0 -8
  33. package/src/codegen/utils/renderMove/generateComponents.ts +0 -802
  34. package/src/codegen/utils/renderMove/generateDefaultSchema.ts +0 -216
  35. package/src/codegen/utils/renderMove/generateEvent.ts +0 -99
  36. package/src/codegen/utils/renderMove/generateSchema.ts +0 -287
  37. package/src/codegen/utils/renderMove/generateSchemaHub.ts +0 -60
  38. package/src/parseData/index.ts +0 -1
  39. package/src/parseData/parser/index.ts +0 -47
@@ -1,802 +0,0 @@
1
- import { DubheConfig } from '../../types';
2
- import { ComponentType } from '../../types';
3
- import { formatAndWriteMove } from '../formatAndWrite';
4
-
5
- function getDappModuleName(projectName: string): string {
6
- return projectName === 'dubhe' ? 'dapp_service' : `dapp_system`;
7
- }
8
-
9
- export async function generateComponents(config: DubheConfig, path: string) {
10
- console.log('\nšŸ“¦ Starting Components Generation...');
11
-
12
- for (const [componentName, component] of Object.entries(config.components)) {
13
- console.log(` └─ ${componentName}: ${JSON.stringify(component)}`);
14
-
15
- // Handle simple type cases
16
- if (typeof component === 'string') {
17
- const code = generateSimpleComponentCode(config.name, componentName, component, 'Onchain');
18
- await formatAndWriteMove(code, `${path}/${componentName}.move`, 'formatAndWriteMove');
19
- continue;
20
- }
21
-
22
- // Handle empty object cases, representing components with only entity_id key
23
- if (Object.keys(component).length === 0) {
24
- const code = generateComponentCode(config.name, componentName, {
25
- fields: {
26
- entity_id: 'address'
27
- },
28
- keys: ['entity_id'],
29
- offchain: false
30
- });
31
- await formatAndWriteMove(code, `${path}/${componentName}.move`, 'formatAndWriteMove');
32
- continue;
33
- }
34
-
35
- // Handle cases where keys are not defined - default to entity_id for components
36
- if (!component.keys) {
37
- component.keys = ['entity_id'];
38
- if (!component.fields['entity_id']) {
39
- component.fields = {
40
- entity_id: 'address',
41
- ...component.fields
42
- };
43
- }
44
- }
45
-
46
- // Validate that components only have one key
47
- if (component.keys && component.keys.length > 1) {
48
- throw new Error(
49
- `Component '${componentName}' can only have one key, but found ${
50
- component.keys.length
51
- } keys: ${component.keys.join(', ')}`
52
- );
53
- }
54
-
55
- const code = generateComponentCode(config.name, componentName, component);
56
- await formatAndWriteMove(code, `${path}/${componentName}.move`, 'formatAndWriteMove');
57
- }
58
- }
59
-
60
- function generateSimpleComponentCode(
61
- projectName: string,
62
- componentName: string,
63
- valueType: string,
64
- type: ComponentType = 'Onchain'
65
- ): string {
66
- // Check if it's an enum type
67
- const isEnum = !isBasicType(valueType);
68
- const enumModule = isEnum ? `${toSnakeCase(valueType)}` : '';
69
-
70
- return `module ${projectName}::${componentName} {
71
- use sui::bcs::{to_bytes};
72
- use std::ascii::{string, String, into_bytes};
73
- use dubhe::table_id;
74
- use dubhe::dapp_service::{Self, DappHub};
75
- use dubhe::dapp_system;
76
- use ${projectName}::dapp_key;
77
- use ${projectName}::dapp_key::DappKey;
78
- ${
79
- isEnum && valueType !== 'string' && valueType !== 'String'
80
- ? ` use ${projectName}::${enumModule};
81
- use ${projectName}::${enumModule}::{${valueType}};`
82
- : ''
83
- }
84
-
85
- const TABLE_NAME: vector<u8> = b"${componentName}";
86
- const TABLE_TYPE: vector<u8> = b"Component";
87
- const OFFCHAIN: bool = ${type === 'Offchain'};
88
-
89
- public fun get_table_id(): String {
90
- string(TABLE_NAME)
91
- }
92
-
93
- public fun get_key_schemas(): vector<String> {
94
- vector[string(b"address")]
95
- }
96
-
97
- public fun get_value_schemas(): vector<String> {
98
- vector[string(b"${valueType}")]
99
- }
100
-
101
- public fun get_key_names(): vector<String> {
102
- vector[string(b"entity_id")]
103
- }
104
-
105
- public fun get_value_names(): vector<String> {
106
- vector[string(b"value")]
107
- }
108
-
109
- public(package) fun register_table(dapp_hub: &mut DappHub, ctx: &mut TxContext) {
110
- let dapp_key = dapp_key::new();
111
- ${getDappModuleName(projectName)}::register_table(
112
- dapp_hub,
113
- dapp_key,
114
- string(TABLE_TYPE),
115
- get_table_id(),
116
- get_key_schemas(),
117
- get_key_names(),
118
- get_value_schemas(),
119
- get_value_names(),
120
- OFFCHAIN,
121
- ctx
122
- );
123
- }
124
-
125
- public fun has(dapp_hub: &DappHub, entity_id: address): bool {
126
- let mut key_tuple = vector::empty();
127
- key_tuple.push_back(to_bytes(&entity_id));
128
- ${getDappModuleName(projectName)}::has_record<DappKey>(dapp_hub, get_table_id(), key_tuple)
129
- }
130
-
131
- public(package) fun delete(dapp_hub: &mut DappHub, entity_id: address) {
132
- let mut key_tuple = vector::empty();
133
- key_tuple.push_back(to_bytes(&entity_id));
134
- ${getDappModuleName(
135
- projectName
136
- )}::delete_record<DappKey>(dapp_hub, dapp_key::new(), get_table_id(), key_tuple, OFFCHAIN);
137
- }
138
-
139
- public fun get(dapp_hub: &DappHub, entity_id: address): (${
140
- valueType === 'string' || valueType === 'String' ? 'String' : valueType
141
- }) {
142
- let mut key_tuple = vector::empty();
143
- key_tuple.push_back(to_bytes(&entity_id));
144
- let value_tuple = ${getDappModuleName(
145
- projectName
146
- )}::get_record<DappKey>(dapp_hub, get_table_id(), key_tuple);
147
- let mut bsc_type = sui::bcs::new(value_tuple);
148
- ${
149
- valueType === 'string' || valueType === 'String'
150
- ? `let value = dubhe::bcs::peel_string(&mut bsc_type);`
151
- : valueType === 'vector<String>'
152
- ? `let value = dubhe::bcs::peel_vec_string(&mut bsc_type);`
153
- : isEnum
154
- ? `let value = ${projectName}::${enumModule}::decode(&mut bsc_type);`
155
- : `let value = sui::bcs::peel_${getBcsType(valueType)}(&mut bsc_type);`
156
- }
157
- (value)
158
- }
159
-
160
- public(package) fun set(dapp_hub: &mut DappHub, entity_id: address, value: ${
161
- valueType === 'string' || valueType === 'String' ? 'String' : valueType
162
- }) {
163
- let mut key_tuple = vector::empty();
164
- key_tuple.push_back(to_bytes(&entity_id));
165
- let value_tuple = encode(value);
166
- ${getDappModuleName(
167
- projectName
168
- )}::set_record(dapp_hub, dapp_key::new(), get_table_id(), key_tuple, value_tuple, OFFCHAIN);
169
- }
170
-
171
- public fun encode(value: ${
172
- valueType === 'string' || valueType === 'String' ? 'String' : valueType
173
- }): vector<vector<u8>> {
174
- let mut value_tuple = vector::empty();
175
- value_tuple.push_back(${
176
- valueType === 'string' || valueType === 'String'
177
- ? `to_bytes(&into_bytes(value))`
178
- : valueType === 'vector<String>'
179
- ? `to_bytes(&value)`
180
- : isEnum
181
- ? `${projectName}::${enumModule}::encode(value)`
182
- : `to_bytes(&value)`
183
- });
184
- value_tuple
185
- }
186
- }`;
187
- }
188
-
189
- function toSnakeCase(str: string): string {
190
- return str.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`).replace(/^_/, '');
191
- }
192
-
193
- function generateComponentCode(projectName: string, componentName: string, component: any): string {
194
- const fields = component.fields;
195
- const keys = component.keys || ['entity_id'];
196
- const offchain = component.offchain || false;
197
- const type: ComponentType = offchain ? 'Offchain' : 'Onchain';
198
-
199
- // Check if all fields are keys
200
- const isAllKeys = Object.keys(fields).every((name) => keys.includes(name));
201
-
202
- // Generate field type and name lists, excluding fields in keys
203
- const valueFields = Object.entries(fields).filter(([name]) => !keys.includes(name));
204
- const valueFieldNames = valueFields.map(([name]) => name);
205
-
206
- // If there is only one value field, do not generate struct
207
- const isSingleValue = valueFieldNames.length === 1;
208
-
209
- // Get all enum type fields (both key fields and value fields) and their corresponding module names
210
- const allEnumTypes = Object.entries(fields)
211
- .filter(([_, type]) => !isBasicType(type as string) && type !== 'string' && type !== 'String')
212
- .map(([_, type]) => ({
213
- type: type as string,
214
- module: `${toSnakeCase(type as string)}`
215
- }))
216
- .filter((item, index, self) => self.findIndex((t) => t.type === item.type) === index);
217
-
218
- // Generate table related functions
219
- const tableFunctions = generateTableFunctions(
220
- projectName,
221
- componentName,
222
- fields,
223
- keys,
224
- !isAllKeys && !isSingleValue,
225
- allEnumTypes,
226
- type
227
- );
228
-
229
- // If all fields are keys or there is only one value field, do not generate struct related code
230
- if (isAllKeys || isSingleValue) {
231
- return `module ${projectName}::${componentName} {
232
- use sui::bcs::{to_bytes};
233
- use std::ascii::{string, String, into_bytes};
234
- use dubhe::table_id;
235
- use dubhe::dapp_service::{Self, DappHub};
236
- use dubhe::dapp_system;
237
- use ${projectName}::dapp_key;
238
- use ${projectName}::dapp_key::DappKey;
239
- ${
240
- allEnumTypes.length > 0
241
- ? allEnumTypes
242
- .map(
243
- (e) => ` use ${projectName}::${e.module};
244
- use ${projectName}::${e.module}::{${e.type}};`
245
- )
246
- .join('\n')
247
- : ''
248
- }
249
-
250
- const TABLE_NAME: vector<u8> = b"${componentName}";
251
- const TABLE_TYPE: vector<u8> = b"Component";
252
- const OFFCHAIN: bool = ${type === 'Offchain'};
253
- ${tableFunctions}
254
- }`;
255
- }
256
-
257
- // Generate struct fields, excluding fields in keys
258
- const structFields = valueFieldNames
259
- .map(
260
- (name) =>
261
- ` ${name}: ${
262
- fields[name] === 'string' || fields[name] === 'String'
263
- ? 'String'
264
- : fields[name] === 'vector<String>'
265
- ? 'vector<String>'
266
- : fields[name]
267
- },`
268
- )
269
- .join('\n');
270
-
271
- // Generate constructor parameters, only containing non-key fields
272
- const constructorParams = valueFieldNames
273
- .map(
274
- (name) =>
275
- `${name}: ${
276
- fields[name] === 'string' || fields[name] === 'String'
277
- ? 'String'
278
- : fields[name] === 'vector<String>'
279
- ? 'vector<String>'
280
- : fields[name]
281
- }`
282
- )
283
- .join(', ');
284
-
285
- // Generate constructor field assignments, only containing non-key fields
286
- const constructorAssignments = valueFieldNames.map((name) => ` ${name},`).join('\n');
287
-
288
- // Generate getter functions, excluding fields in keys
289
- const getters = valueFieldNames
290
- .map(
291
- (name) => ` public fun ${name}(self: &${toPascalCase(componentName)}): ${
292
- fields[name] === 'string' || fields[name] === 'String'
293
- ? 'String'
294
- : fields[name] === 'vector<String>'
295
- ? 'vector<String>'
296
- : fields[name]
297
- } {
298
- self.${name}
299
- }`
300
- )
301
- .join('\n\n');
302
-
303
- // Generate setter functions, excluding fields in keys
304
- const setters = valueFieldNames
305
- .map(
306
- (name) => ` public fun update_${name}(self: &mut ${toPascalCase(
307
- componentName
308
- )}, ${name}: ${
309
- fields[name] === 'string' || fields[name] === 'String'
310
- ? 'String'
311
- : fields[name] === 'vector<String>'
312
- ? 'vector<String>'
313
- : fields[name]
314
- }) {
315
- self.${name} = ${name}
316
- }`
317
- )
318
- .join('\n\n');
319
-
320
- return `module ${projectName}::${componentName} {
321
- use sui::bcs::{to_bytes};
322
- use std::ascii::{string, String, into_bytes};
323
- use dubhe::table_id;
324
- use dubhe::dapp_service::{Self, DappHub};
325
- use dubhe::dapp_system;
326
- use ${projectName}::dapp_key;
327
- use ${projectName}::dapp_key::DappKey;
328
- ${
329
- allEnumTypes.length > 0
330
- ? allEnumTypes
331
- .map(
332
- (e) => ` use ${projectName}::${e.module};
333
- use ${projectName}::${e.module}::{${e.type}};`
334
- )
335
- .join('\n')
336
- : ''
337
- }
338
-
339
- const TABLE_NAME: vector<u8> = b"${componentName}";
340
- const TABLE_TYPE: vector<u8> = b"Component";
341
- const OFFCHAIN: bool = ${type === 'Offchain'};
342
-
343
- public struct ${toPascalCase(componentName)} has copy, drop, store {
344
- ${structFields}
345
- }
346
-
347
- public fun new(${constructorParams}): ${toPascalCase(componentName)} {
348
- ${toPascalCase(componentName)} {
349
- ${constructorAssignments}
350
- }
351
- }
352
-
353
- ${getters}
354
-
355
- ${setters}
356
-
357
- ${tableFunctions}
358
- }`;
359
- }
360
-
361
- // Check if it is a basic type
362
- function isBasicType(type: string): boolean {
363
- return [
364
- 'address',
365
- 'bool',
366
- 'u8',
367
- 'u16',
368
- 'u32',
369
- 'u64',
370
- 'u128',
371
- 'u256',
372
- 'string',
373
- 'String',
374
- 'vector<address>',
375
- 'vector<bool>',
376
- 'vector<u8>',
377
- 'vector<u16>',
378
- 'vector<u32>',
379
- 'vector<u64>',
380
- 'vector<u128>',
381
- 'vector<u256>',
382
- 'vector<String>',
383
- 'vector<vector<address>>',
384
- 'vector<vector<bool>>',
385
- 'vector<vector<u8>>',
386
- 'vector<vector<u16>>',
387
- 'vector<vector<u32>>',
388
- 'vector<vector<u64>>',
389
- 'vector<vector<u128>>',
390
- 'vector<vector<u256>>'
391
- ].includes(type);
392
- }
393
-
394
- function generateTableFunctions(
395
- projectName: string,
396
- componentName: string,
397
- fields: Record<string, string>,
398
- keys: string[],
399
- includeStruct: boolean = true,
400
- enumTypes: Array<{ type: string; module: string }> = [],
401
- _type: ComponentType = 'Onchain'
402
- ): string {
403
- // Separate key fields and non-key fields
404
- const keyFields = keys.reduce((acc, key) => ({ ...acc, [key]: fields[key] }), {});
405
- const valueFields = Object.entries(fields)
406
- .filter(([name]) => !keys.includes(name))
407
- .reduce((acc, [name, type]) => ({ ...acc, [name]: type }), {});
408
-
409
- const _keyNames = Object.keys(keyFields);
410
- const valueNames = Object.keys(valueFields);
411
-
412
- // Check if all fields are keys
413
- const isAllKeys = Object.keys(fields).every((name) => keys.includes(name));
414
- // Check if there is only one value field
415
- const isSingleValue = valueNames.length === 1;
416
-
417
- // Generate key parameter list, if keys are empty, return empty string
418
- const keyParams = keys.length > 0 ? keys.map((k) => `${k}: ${fields[k]}`).join(', ') : '';
419
-
420
- // Generate key tuple related code, if keys are empty, return empty string
421
- const keyTupleCode =
422
- keys.length > 0
423
- ? `let mut key_tuple = vector::empty();
424
- ${keys.map((k) => `key_tuple.push_back(to_bytes(&${k}));`).join('\n ')}`
425
- : 'let key_tuple = vector::empty();';
426
-
427
- // Generate table ID related functions
428
- const tableIdFunctions = ` public fun get_table_id(): String {
429
- string(TABLE_NAME)
430
- }
431
-
432
- public fun get_key_schemas(): vector<String> {
433
- vector[${keys.map((k) => `string(b"${fields[k]}")`).join(', ')}]
434
- }
435
-
436
- public fun get_value_schemas(): vector<String> {
437
- vector[${Object.values(valueFields)
438
- .map((t) => `string(b"${t}")`)
439
- .join(', ')}]
440
- }
441
-
442
- public fun get_key_names(): vector<String> {
443
- vector[${keys.map((k) => `string(b"${k}")`).join(', ')}]
444
- }
445
-
446
- public fun get_value_names(): vector<String> {
447
- vector[${valueNames.map((n) => `string(b"${n}")`).join(', ')}]
448
- }`;
449
-
450
- // Generate register table function
451
- const registerFunction = ` public(package) fun register_table(dapp_hub: &mut DappHub, ctx: &mut TxContext) {
452
- let dapp_key = dapp_key::new();
453
- ${getDappModuleName(projectName)}::register_table(
454
- dapp_hub,
455
- dapp_key,
456
- string(TABLE_TYPE),
457
- get_table_id(),
458
- get_key_schemas(),
459
- get_key_names(),
460
- get_value_schemas(),
461
- get_value_names(),
462
- OFFCHAIN,
463
- ctx
464
- );
465
- }`;
466
-
467
- // Generate has series functions
468
- const hasFunctions = ` public fun has(dapp_hub: &DappHub${
469
- keyParams ? ', ' + keyParams : ''
470
- }): bool {
471
- ${keyTupleCode}
472
- ${getDappModuleName(projectName)}::has_record<DappKey>(dapp_hub, get_table_id(), key_tuple)
473
- }
474
-
475
- public fun ensure_has(dapp_hub: &DappHub${keyParams ? ', ' + keyParams : ''}) {
476
- ${keyTupleCode}
477
- ${getDappModuleName(
478
- projectName
479
- )}::ensure_has_record<DappKey>(dapp_hub, get_table_id(), key_tuple)
480
- }
481
-
482
- public fun ensure_not_has(dapp_hub: &DappHub${keyParams ? ', ' + keyParams : ''}) {
483
- ${keyTupleCode}
484
- ${getDappModuleName(
485
- projectName
486
- )}::ensure_not_has_record<DappKey>(dapp_hub, get_table_id(), key_tuple)
487
- }
488
- `;
489
-
490
- // Generate delete function
491
- const deleteFunction = ` public(package) fun delete(dapp_hub: &mut DappHub${
492
- keyParams ? ', ' + keyParams : ''
493
- }) {
494
- ${keyTupleCode}
495
- ${getDappModuleName(
496
- projectName
497
- )}::delete_record<DappKey>(dapp_hub, dapp_key::new(), get_table_id(), key_tuple, OFFCHAIN);
498
- }`;
499
-
500
- // Generate getter and setter functions, only generated when there are multiple value fields
501
- const getterSetters = !isSingleValue
502
- ? valueNames
503
- .map((name) => {
504
- const index = valueNames.indexOf(name);
505
- const fieldType = fields[name];
506
- const isEnum = !isBasicType(fieldType as string);
507
- const enumType = isEnum ? enumTypes.find((e) => e.type === fieldType) : null;
508
-
509
- return ` public fun get_${name}(dapp_hub: &DappHub${
510
- keyParams ? ', ' + keyParams : ''
511
- }): ${fieldType === 'string' || fieldType === 'String' ? 'String' : fieldType} {
512
- ${keyTupleCode}
513
- let value = ${getDappModuleName(
514
- projectName
515
- )}::get_field<DappKey>(dapp_hub, get_table_id(), key_tuple, ${index});
516
- let mut bsc_type = sui::bcs::new(value);
517
- ${
518
- fieldType === 'string' || fieldType === 'String'
519
- ? `let ${name} = dubhe::bcs::peel_string(&mut bsc_type);`
520
- : fieldType === 'vector<String>'
521
- ? `let ${name} = dubhe::bcs::peel_vec_string(&mut bsc_type);`
522
- : isEnum
523
- ? `let ${name} = ${projectName}::${enumType?.module}::decode(&mut bsc_type);`
524
- : `let ${name} = sui::bcs::peel_${getBcsType(fieldType)}(&mut bsc_type);`
525
- }
526
- ${name}
527
- }
528
-
529
- public(package) fun set_${name}(dapp_hub: &mut DappHub${
530
- keyParams ? ', ' + keyParams : ''
531
- }, ${name}: ${fieldType === 'string' || fieldType === 'String' ? 'String' : fieldType}) {
532
- ${keyTupleCode}
533
- let value = ${
534
- fieldType === 'string' || fieldType === 'String'
535
- ? `to_bytes(&into_bytes(${name}))`
536
- : fieldType === 'vector<String>'
537
- ? `to_bytes(&${name})`
538
- : isEnum
539
- ? `${projectName}::${enumType?.module}::encode(${name})`
540
- : `to_bytes(&${name})`
541
- };
542
- ${getDappModuleName(
543
- projectName
544
- )}::set_field(dapp_hub, dapp_key::new(), get_table_id(), key_tuple, ${index}, value, OFFCHAIN);
545
- }`;
546
- })
547
- .join('\n\n')
548
- : '';
549
-
550
- // Generate get and set functions
551
- const getSetFunctions = isAllKeys
552
- ? ` public(package) fun set(dapp_hub: &mut DappHub${keyParams ? ', ' + keyParams : ''}) {
553
- ${keyTupleCode}
554
- let value_tuple = vector::empty();
555
- ${getDappModuleName(
556
- projectName
557
- )}::set_record(dapp_hub, dapp_key::new(), get_table_id(), key_tuple, value_tuple, OFFCHAIN);
558
- }`
559
- : isSingleValue
560
- ? ` public fun get(dapp_hub: &DappHub${keyParams ? ', ' + keyParams : ''}): ${
561
- Object.values(valueFields)[0] === 'string' || Object.values(valueFields)[0] === 'String'
562
- ? 'String'
563
- : Object.values(valueFields)[0]
564
- } {
565
- ${keyTupleCode}
566
- let value = ${getDappModuleName(
567
- projectName
568
- )}::get_field<DappKey>(dapp_hub, get_table_id(), key_tuple, 0);
569
- let mut bsc_type = sui::bcs::new(value);
570
- ${
571
- Object.values(valueFields)[0] === 'string' || Object.values(valueFields)[0] === 'String'
572
- ? `let value = dubhe::bcs::peel_string(&mut bsc_type);`
573
- : Object.values(valueFields)[0] === 'vector<String>'
574
- ? `let value = dubhe::bcs::peel_vec_string(&mut bsc_type);`
575
- : !isBasicType(Object.values(valueFields)[0] as string)
576
- ? `let value = ${projectName}::${
577
- enumTypes.find((e) => e.type === Object.values(valueFields)[0])?.module
578
- }::decode(&mut bsc_type);`
579
- : `let value = sui::bcs::peel_${getBcsType(
580
- Object.values(valueFields)[0] as string
581
- )}(&mut bsc_type);`
582
- }
583
- value
584
- }
585
-
586
- public(package) fun set(dapp_hub: &mut DappHub${keyParams ? ', ' + keyParams : ''}, value: ${
587
- Object.values(valueFields)[0] === 'string' || Object.values(valueFields)[0] === 'String'
588
- ? 'String'
589
- : Object.values(valueFields)[0]
590
- }) {
591
- ${keyTupleCode}
592
- let value_tuple = encode(value);
593
- ${getDappModuleName(
594
- projectName
595
- )}::set_record(dapp_hub, dapp_key::new(), get_table_id(), key_tuple, value_tuple, OFFCHAIN);
596
- }`
597
- : ` public fun get(dapp_hub: &DappHub${keyParams ? ', ' + keyParams : ''}): (${Object.values(
598
- valueFields
599
- )
600
- .map((t) => (t === 'string' || t === 'String' ? 'String' : t))
601
- .join(', ')}) {
602
- ${keyTupleCode}
603
- let value_tuple = ${getDappModuleName(
604
- projectName
605
- )}::get_record<DappKey>(dapp_hub, get_table_id(), key_tuple);
606
- let mut bsc_type = sui::bcs::new(value_tuple);
607
- ${valueNames
608
- .map((name) => {
609
- const fieldType = fields[name];
610
- const isEnum = !isBasicType(fieldType as string);
611
- const enumType = isEnum ? enumTypes.find((e) => e.type === fieldType) : null;
612
- return `let ${name} = ${
613
- fieldType === 'string' || fieldType === 'String'
614
- ? `dubhe::bcs::peel_string(&mut bsc_type)`
615
- : fieldType === 'vector<String>'
616
- ? `dubhe::bcs::peel_vec_string(&mut bsc_type)`
617
- : isEnum
618
- ? `${projectName}::${enumType?.module}::decode(&mut bsc_type)`
619
- : `sui::bcs::peel_${getBcsType(fieldType)}(&mut bsc_type)`
620
- };`;
621
- })
622
- .join('\n ')}
623
- (${valueNames.join(', ')})
624
- }
625
-
626
- public(package) fun set(dapp_hub: &mut DappHub${keyParams ? ', ' + keyParams : ''}, ${valueNames
627
- .map(
628
- (n) => `${n}: ${fields[n] === 'string' || fields[n] === 'String' ? 'String' : fields[n]}`
629
- )
630
- .join(', ')}) {
631
- ${keyTupleCode}
632
- let value_tuple = encode(${valueNames.join(', ')});
633
- ${getDappModuleName(
634
- projectName
635
- )}::set_record(dapp_hub, dapp_key::new(), get_table_id(), key_tuple, value_tuple, OFFCHAIN);
636
- }`;
637
-
638
- // Generate struct related functions
639
- const structFunctions = includeStruct
640
- ? ` public fun get_struct(dapp_hub: &DappHub${
641
- keyParams ? ', ' + keyParams : ''
642
- }): ${toPascalCase(componentName)} {
643
- ${keyTupleCode}
644
- let value_tuple = ${getDappModuleName(
645
- projectName
646
- )}::get_record<DappKey>(dapp_hub, get_table_id(), key_tuple);
647
- decode(value_tuple)
648
- }
649
-
650
- public(package) fun set_struct(dapp_hub: &mut DappHub${
651
- keyParams ? ', ' + keyParams : ''
652
- }, ${componentName}: ${toPascalCase(componentName)}) {
653
- ${keyTupleCode}
654
- let value_tuple = encode_struct(${componentName});
655
- ${getDappModuleName(
656
- projectName
657
- )}::set_record(dapp_hub, dapp_key::new(), get_table_id(), key_tuple, value_tuple, OFFCHAIN);
658
- }`
659
- : '';
660
-
661
- // Generate encode and decode functions
662
- const encodeDecodeFunctions = isSingleValue
663
- ? ` public fun encode(value: ${
664
- Object.values(valueFields)[0] === 'string' || Object.values(valueFields)[0] === 'String'
665
- ? 'String'
666
- : Object.values(valueFields)[0]
667
- }): vector<vector<u8>> {
668
- let mut value_tuple = vector::empty();
669
- value_tuple.push_back( ${
670
- Object.values(valueFields)[0] === 'string' || Object.values(valueFields)[0] === 'String'
671
- ? `to_bytes(&into_bytes(value))`
672
- : Object.values(valueFields)[0] === 'vector<String>'
673
- ? `to_bytes(&value)`
674
- : !isBasicType(Object.values(valueFields)[0] as string)
675
- ? `${projectName}::${
676
- enumTypes.find((e) => e.type === Object.values(valueFields)[0])?.module
677
- }::encode(value)`
678
- : `to_bytes(&value)`
679
- });
680
- value_tuple
681
- }`
682
- : includeStruct
683
- ? ` public fun encode(${valueNames
684
- .map(
685
- (n) => `${n}: ${fields[n] === 'string' || fields[n] === 'String' ? 'String' : fields[n]}`
686
- )
687
- .join(', ')}): vector<vector<u8>> {
688
- let mut value_tuple = vector::empty();
689
- ${valueNames
690
- .map((n) => {
691
- const fieldType = fields[n];
692
- const isEnum = !isBasicType(fieldType as string);
693
- const enumType = isEnum ? enumTypes.find((e) => e.type === fieldType) : null;
694
- return `value_tuple.push_back(${
695
- fieldType === 'string' || fieldType === 'String'
696
- ? `to_bytes(&into_bytes(${n}))`
697
- : fieldType === 'vector<String>'
698
- ? `to_bytes(&${n})`
699
- : isEnum
700
- ? `${projectName}::${enumType?.module}::encode(${n})`
701
- : `to_bytes(&${n})`
702
- });`;
703
- })
704
- .join('\n ')}
705
- value_tuple
706
- }
707
-
708
- public fun encode_struct(${componentName}: ${toPascalCase(componentName)}): vector<vector<u8>> {
709
- encode(${valueNames.map((n) => `${componentName}.${n}`).join(', ')})
710
- }
711
-
712
- public fun decode(data: vector<u8>): ${toPascalCase(componentName)} {
713
- let mut bsc_type = sui::bcs::new(data);
714
- ${valueNames
715
- .map((n) => {
716
- const fieldType = fields[n];
717
- const isEnum = !isBasicType(fieldType as string);
718
- const enumType = isEnum ? enumTypes.find((e) => e.type === fieldType) : null;
719
- return `let ${n} = ${
720
- fieldType === 'string' || fieldType === 'String'
721
- ? `string(sui::bcs::peel_vec_u8(&mut bsc_type))`
722
- : fieldType === 'vector<String>'
723
- ? `dubhe::bcs::peel_vec_string(&mut bsc_type)`
724
- : isEnum
725
- ? `${projectName}::${enumType?.module}::decode(&mut bsc_type)`
726
- : `sui::bcs::peel_${getBcsType(fieldType)}(&mut bsc_type)`
727
- };`;
728
- })
729
- .join('\n ')}
730
- ${toPascalCase(componentName)} {
731
- ${valueNames.map((n) => `${n},`).join('\n ')}
732
- }
733
- }`
734
- : '';
735
-
736
- return `${tableIdFunctions}
737
-
738
- ${registerFunction}
739
-
740
- ${hasFunctions}
741
-
742
- ${deleteFunction}
743
-
744
- ${getterSetters}
745
-
746
- ${getSetFunctions}
747
-
748
- ${structFunctions}
749
-
750
- ${encodeDecodeFunctions}`;
751
- }
752
-
753
- function toPascalCase(str: string): string {
754
- // Split the underscore-separated string into words
755
- return str
756
- .split('_')
757
- .map((word, _index) => {
758
- // If the word is a pure number, return it as is
759
- if (/^\d+$/.test(word)) {
760
- return word;
761
- }
762
- // Otherwise, capitalize the first letter and lowercase the rest
763
- return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
764
- })
765
- .join('');
766
- }
767
-
768
- function getBcsType(type: string): string {
769
- if (type.startsWith('vector<')) {
770
- const innerType = type.slice(7, -1);
771
- if (innerType === 'vector<u8>') {
772
- return 'vec_vec_u8';
773
- }
774
- if (innerType === 'String') {
775
- return 'vec_string';
776
- }
777
- return `vec_${getBcsType(innerType)}`;
778
- }
779
-
780
- switch (type) {
781
- case 'u8':
782
- return 'u8';
783
- case 'u16':
784
- return 'u16';
785
- case 'u32':
786
- return 'u32';
787
- case 'u64':
788
- return 'u64';
789
- case 'u128':
790
- return 'u128';
791
- case 'u256':
792
- return 'u256';
793
- case 'bool':
794
- return 'bool';
795
- case 'address':
796
- return 'address';
797
- case 'String':
798
- return 'string';
799
- default:
800
- return type;
801
- }
802
- }