@0xobelisk/sui-common 1.2.0-pre.98 ā 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.
- package/LICENSE +92 -0
- package/README.md +670 -1
- package/dist/index.d.ts +61 -27
- package/dist/index.js +1078 -461
- package/dist/index.js.map +1 -1
- package/package.json +15 -17
- package/src/codegen/debug.ts +0 -4
- package/src/codegen/types/index.ts +46 -10
- package/src/codegen/utils/config.ts +1 -1
- package/src/codegen/utils/format.ts +0 -6
- package/src/codegen/utils/formatAndWrite.ts +10 -31
- package/src/codegen/utils/generateLock.ts +122 -0
- package/src/codegen/utils/index.ts +4 -2
- package/src/codegen/utils/renderMove/{schemaGen.ts ā codegen.ts} +40 -28
- package/src/codegen/utils/renderMove/common.ts +0 -65
- package/src/codegen/utils/renderMove/dapp.ts +2 -14
- package/src/codegen/utils/renderMove/generateDappKey.ts +33 -18
- package/src/codegen/utils/renderMove/generateError.ts +32 -15
- package/src/codegen/utils/renderMove/generateGenesis.ts +55 -22
- package/src/codegen/utils/renderMove/generateInitTest.ts +26 -14
- package/src/codegen/utils/renderMove/generateObjects.ts +377 -0
- package/src/codegen/utils/renderMove/generatePermits.ts +151 -0
- package/src/codegen/utils/renderMove/generateResources.ts +894 -242
- package/src/codegen/utils/renderMove/generateScenes.ts +467 -0
- package/src/codegen/utils/renderMove/generateScript.ts +18 -13
- package/src/codegen/utils/renderMove/generateSystem.ts +0 -2
- package/src/codegen/utils/renderMove/generateUserStorageInit.ts +37 -0
- package/src/codegen/utils/validateConfig.ts +237 -0
- package/src/index.ts +0 -1
- package/src/modules.d.ts +0 -10
- package/src/codegen/modules.d.ts +0 -1
- package/src/codegen/utils/posixPath.ts +0 -8
- package/src/codegen/utils/renderMove/generateComponents.ts +0 -802
- package/src/codegen/utils/renderMove/generateDefaultSchema.ts +0 -216
- package/src/codegen/utils/renderMove/generateEvent.ts +0 -99
- package/src/codegen/utils/renderMove/generateSchema.ts +0 -287
- package/src/codegen/utils/renderMove/generateSchemaHub.ts +0 -60
- package/src/parseData/index.ts +0 -1
- 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
|
-
}
|