@0xobelisk/sui-common 0.5.15 ā 0.5.18
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 +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +75 -60
- package/dist/index.js.map +1 -1
- package/package.json +5 -4
- package/src/codegen/types/index.ts +1 -1
- package/src/codegen/utils/config.ts +6 -6
- package/src/codegen/utils/errors.ts +1 -1
- package/src/codegen/utils/index.ts +5 -5
- package/src/codegen/utils/renderMove/common.ts +27 -33
- package/src/codegen/utils/renderMove/generateDappKey.ts +23 -14
- package/src/codegen/utils/renderMove/generateSchema.ts +192 -117
- package/src/codegen/utils/renderMove/generateScript.ts +54 -42
- package/src/codegen/utils/renderMove/generateSystem.ts +25 -18
- package/src/codegen/utils/renderMove/generateToml.ts +16 -6
- package/src/codegen/utils/renderMove/schemaGen.ts +69 -0
- package/src/debug.ts +2 -2
- package/src/codegen/utils/renderMove/worldgen.ts +0 -34
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import fs from
|
|
1
|
+
import { MoveType } from '../../types';
|
|
2
|
+
import fs from 'fs';
|
|
3
3
|
|
|
4
4
|
export function deleteFolderRecursive(path: string) {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
5
|
+
if (fs.existsSync(path)) {
|
|
6
|
+
fs.readdirSync(path).forEach(file => {
|
|
7
|
+
const curPath = `${path}/${file}`;
|
|
8
|
+
if (fs.lstatSync(curPath).isDirectory()) {
|
|
9
|
+
deleteFolderRecursive(curPath);
|
|
10
|
+
} else {
|
|
11
|
+
fs.unlinkSync(curPath);
|
|
12
|
+
}
|
|
13
|
+
});
|
|
14
|
+
fs.rmdirSync(path);
|
|
15
|
+
}
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
export function capitalizeFirstLetter(input: string): string {
|
|
19
|
-
|
|
19
|
+
return input.charAt(0).toUpperCase() + input.slice(1);
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
/**
|
|
@@ -26,14 +26,16 @@ export function capitalizeFirstLetter(input: string): string {
|
|
|
26
26
|
* @return [ name, age, birth_time ]
|
|
27
27
|
*/
|
|
28
28
|
export function getStructAttrs(
|
|
29
|
-
|
|
29
|
+
values: Record<string, string> | string
|
|
30
30
|
): string {
|
|
31
|
-
|
|
31
|
+
return Object.entries(values)
|
|
32
|
+
.map(([key, _]) => `${key}`)
|
|
33
|
+
.join(',');
|
|
32
34
|
}
|
|
33
35
|
|
|
34
36
|
function isAddress(str: string): boolean {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
+
const regex = /^0x[a-fA-F0-9]+$/;
|
|
38
|
+
return regex.test(str);
|
|
37
39
|
}
|
|
38
40
|
|
|
39
41
|
/**
|
|
@@ -43,11 +45,9 @@ function isAddress(str: string): boolean {
|
|
|
43
45
|
*/
|
|
44
46
|
// export function getStructTypes(values: SchemaType): string {
|
|
45
47
|
export function getStructTypes(
|
|
46
|
-
|
|
48
|
+
values: Record<string, string>
|
|
47
49
|
): string {
|
|
48
|
-
|
|
49
|
-
? values
|
|
50
|
-
: `(${Object.entries(values).map(([_, type]) => `${type}`)})`;
|
|
50
|
+
return `(${Object.entries(values).map(([_, type]) => `${type}`)})`;
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
/**
|
|
@@ -56,23 +56,17 @@ export function getStructTypes(
|
|
|
56
56
|
* @return Attributes and types of the struct. [ name: string, age: u64 ]
|
|
57
57
|
*/
|
|
58
58
|
export function getStructAttrsWithType(
|
|
59
|
-
|
|
59
|
+
values: Record<string, string>
|
|
60
60
|
): string[] {
|
|
61
|
-
|
|
61
|
+
return Object.entries(values).map(([key, type]) => `${key}: ${type}`);
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
/**
|
|
65
65
|
* @param values
|
|
66
|
-
* @param prefixArgs
|
|
67
66
|
* @return [ data.name, data.age ]
|
|
68
67
|
*/
|
|
69
68
|
export function getStructAttrsQuery(
|
|
70
|
-
|
|
71
|
-
prefixArgs: string
|
|
69
|
+
values: Record<string, string>,
|
|
72
70
|
): string[] {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
: Object.entries(values).map(
|
|
76
|
-
([key, _]) => `${prefixArgs}self.${key}`
|
|
77
|
-
);
|
|
78
|
-
}
|
|
71
|
+
return Object.entries(values).map(([key, _]) => `self.${key}`);
|
|
72
|
+
}
|
|
@@ -1,19 +1,28 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { formatAndWriteMove } from
|
|
1
|
+
import { DubheConfig } from '../../types';
|
|
2
|
+
import { formatAndWriteMove } from '../formatAndWrite';
|
|
3
3
|
|
|
4
|
-
export async function generateDappKey(
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
export async function generateDappKey(
|
|
5
|
+
config: DubheConfig,
|
|
6
|
+
srcPrefix: string
|
|
7
|
+
) {
|
|
8
|
+
console.log('\nš Starting DappKey Generation...');
|
|
9
|
+
console.log(
|
|
10
|
+
` āā Output path: ${srcPrefix}/contracts/${config.name}/sources/codegen/dapp_key.move`
|
|
11
|
+
);
|
|
8
12
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
13
|
+
let code = `module ${config.name}::dapp_key {
|
|
14
|
+
\t/// Authorization token for the app.
|
|
15
|
+
\tpublic struct DappKey has drop {}
|
|
16
|
+
|
|
17
|
+
\tpublic(package) fun new(): DappKey {
|
|
18
|
+
\t\tDappKey { }
|
|
19
|
+
\t}
|
|
12
20
|
}
|
|
13
21
|
`;
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
22
|
+
await formatAndWriteMove(
|
|
23
|
+
code,
|
|
24
|
+
`${srcPrefix}/contracts/${config.name}/sources/codegen/dapp_key.move`,
|
|
25
|
+
'formatAndWriteMove'
|
|
26
|
+
);
|
|
27
|
+
console.log('ā
DappKey Generation Complete\n');
|
|
19
28
|
}
|
|
@@ -1,109 +1,142 @@
|
|
|
1
|
+
import { BaseType, SchemaType } from '../../types';
|
|
2
|
+
import { formatAndWriteMove } from '../formatAndWrite';
|
|
1
3
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
getStructAttrs,
|
|
8
|
-
getStructTypes, getStructAttrsQuery,
|
|
9
|
-
} from "./common";
|
|
4
|
+
getStructAttrsWithType,
|
|
5
|
+
getStructAttrs,
|
|
6
|
+
getStructTypes,
|
|
7
|
+
getStructAttrsQuery,
|
|
8
|
+
} from './common';
|
|
10
9
|
|
|
11
10
|
function capitalizeAndRemoveUnderscores(input: string): string {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
11
|
+
return input
|
|
12
|
+
.split('_')
|
|
13
|
+
.map((word, index) => {
|
|
14
|
+
return index === 0
|
|
15
|
+
? word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()
|
|
16
|
+
: word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
|
|
17
|
+
})
|
|
18
|
+
.join('');
|
|
20
19
|
}
|
|
21
20
|
|
|
22
21
|
export function renderSetAttrsFunc(
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
schemaName: string,
|
|
23
|
+
fields: BaseType | Record<string, BaseType>
|
|
25
24
|
): string {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
25
|
+
return Object.entries(fields)
|
|
26
|
+
.map(
|
|
27
|
+
([key, type]) =>
|
|
28
|
+
`public(package) fun set_${key}(self: &mut ${schemaName}, ${key}: ${type}) {
|
|
30
29
|
self.${key} = ${key};
|
|
31
30
|
}`
|
|
32
|
-
|
|
31
|
+
)
|
|
32
|
+
.join('\n');
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
export function renderSetFunc(
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
schemaName: string,
|
|
37
|
+
fields: Record<string, string>
|
|
38
38
|
): string {
|
|
39
|
-
|
|
39
|
+
return `public(package) fun set(self: &mut ${schemaName}, ${getStructAttrsWithType(
|
|
40
|
+
fields
|
|
41
|
+
)}) {
|
|
40
42
|
${Object.entries(fields)
|
|
41
|
-
|
|
42
|
-
|
|
43
|
+
.map(([fieldName]) => `self.${fieldName} = ${fieldName};`)
|
|
44
|
+
.join('\n')}
|
|
43
45
|
}`;
|
|
44
46
|
}
|
|
45
47
|
|
|
46
48
|
export function renderGetAllFunc(
|
|
47
|
-
|
|
48
|
-
|
|
49
|
+
schemaName: string,
|
|
50
|
+
fields: Record<string, string>
|
|
49
51
|
): string {
|
|
50
|
-
|
|
51
|
-
(${getStructAttrsQuery(fields
|
|
52
|
+
return `public fun get(self: &${schemaName}): ${getStructTypes(fields)} {
|
|
53
|
+
(${getStructAttrsQuery(fields)})
|
|
52
54
|
}`;
|
|
53
55
|
}
|
|
54
56
|
|
|
55
57
|
export function renderGetAttrsFunc(
|
|
56
|
-
|
|
57
|
-
|
|
58
|
+
schemaName: string,
|
|
59
|
+
fields: BaseType | Record<string, BaseType>
|
|
58
60
|
): string {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
61
|
+
return Object.entries(fields)
|
|
62
|
+
.map(
|
|
63
|
+
([
|
|
64
|
+
key,
|
|
65
|
+
type,
|
|
66
|
+
]) => `public fun get_${key}(self: &${schemaName}): ${type} {
|
|
62
67
|
self.${key}
|
|
63
68
|
}`
|
|
64
|
-
|
|
69
|
+
)
|
|
70
|
+
.join('\n');
|
|
65
71
|
}
|
|
66
72
|
|
|
67
73
|
function convertToSnakeCase(input: string): string {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
74
|
+
return input
|
|
75
|
+
.replace(/([A-Z])/g, '_$1')
|
|
76
|
+
.toLowerCase()
|
|
77
|
+
.replace(/^_/, '');
|
|
72
78
|
}
|
|
73
79
|
|
|
74
|
-
export async function generateSchemaData(
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
+
export async function generateSchemaData(
|
|
81
|
+
projectName: string,
|
|
82
|
+
schemas: Record<string, SchemaType>,
|
|
83
|
+
path: string
|
|
84
|
+
) {
|
|
85
|
+
console.log('\nš¦ Starting Schema Data Generation...');
|
|
86
|
+
for (const schemaName in schemas) {
|
|
87
|
+
const schema = schemas[schemaName];
|
|
88
|
+
if (schema.data) {
|
|
89
|
+
console.log(` āā Processing schema: ${schemaName}`);
|
|
90
|
+
for (const item of schema.data) {
|
|
91
|
+
console.log(
|
|
92
|
+
` āā Generating ${item.name} ${
|
|
93
|
+
Array.isArray(item.fields) ? '(enum)' : '(struct)'
|
|
94
|
+
}`
|
|
95
|
+
);
|
|
96
|
+
let code = '';
|
|
80
97
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
98
|
+
const enumNames = schema.data
|
|
99
|
+
.filter(item => Array.isArray(item.fields))
|
|
100
|
+
.map(item => item.name);
|
|
84
101
|
|
|
85
|
-
|
|
86
|
-
|
|
102
|
+
if (Array.isArray(item.fields)) {
|
|
103
|
+
code = `module ${projectName}::${schemaName}_${convertToSnakeCase(
|
|
104
|
+
item.name
|
|
105
|
+
)} {
|
|
87
106
|
public enum ${item.name} has copy, drop , store {
|
|
88
107
|
${item.fields}
|
|
89
108
|
}
|
|
90
109
|
|
|
91
|
-
${item.fields
|
|
92
|
-
|
|
110
|
+
${item.fields
|
|
111
|
+
.map((field: string) => {
|
|
112
|
+
return `public fun new_${convertToSnakeCase(
|
|
113
|
+
field
|
|
114
|
+
)}(): ${item.name} {
|
|
93
115
|
${item.name}::${field}
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
116
|
+
}`;
|
|
117
|
+
})
|
|
118
|
+
.join('')}`;
|
|
119
|
+
} else {
|
|
120
|
+
code = `module ${projectName}::${schemaName}_${convertToSnakeCase(
|
|
121
|
+
item.name
|
|
122
|
+
)} {
|
|
99
123
|
use std::ascii::String;
|
|
100
|
-
${enumNames
|
|
124
|
+
${enumNames
|
|
125
|
+
.map(
|
|
126
|
+
name =>
|
|
127
|
+
`use ${projectName}::${schemaName}_${convertToSnakeCase(
|
|
128
|
+
name
|
|
129
|
+
)}::${name};`
|
|
130
|
+
)
|
|
131
|
+
.join('\n')}
|
|
101
132
|
|
|
102
133
|
public struct ${item.name} has copy, drop , store {
|
|
103
134
|
${getStructAttrsWithType(item.fields)}
|
|
104
135
|
}
|
|
105
136
|
|
|
106
|
-
public fun new(${getStructAttrsWithType(
|
|
137
|
+
public fun new(${getStructAttrsWithType(
|
|
138
|
+
item.fields
|
|
139
|
+
)}): ${item.name} {
|
|
107
140
|
${item.name} {
|
|
108
141
|
${getStructAttrs(item.fields)}
|
|
109
142
|
}
|
|
@@ -114,88 +147,130 @@ export async function generateSchemaData(projectName: string, schemas: Record<st
|
|
|
114
147
|
${renderSetAttrsFunc(item.name, item.fields)}
|
|
115
148
|
${renderSetFunc(item.name, item.fields)}
|
|
116
149
|
}`;
|
|
117
|
-
|
|
150
|
+
}
|
|
118
151
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
152
|
+
await formatAndWriteMove(
|
|
153
|
+
code,
|
|
154
|
+
`${path}/contracts/${projectName}/sources/codegen/schemas/${schemaName}_${convertToSnakeCase(
|
|
155
|
+
item.name
|
|
156
|
+
)}.move`,
|
|
157
|
+
'formatAndWriteMove'
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
console.log('ā
Schema Data Generation Complete\n');
|
|
127
163
|
}
|
|
128
164
|
|
|
129
|
-
function generateImport(
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
165
|
+
function generateImport(
|
|
166
|
+
projectName: string,
|
|
167
|
+
schemaName: string,
|
|
168
|
+
schema: SchemaType
|
|
169
|
+
) {
|
|
170
|
+
if (schema.data) {
|
|
171
|
+
return schema.data
|
|
172
|
+
.map(item => {
|
|
173
|
+
return `use ${projectName}::${schemaName}_${convertToSnakeCase(
|
|
174
|
+
item.name
|
|
175
|
+
)}::${item.name};`;
|
|
176
|
+
})
|
|
177
|
+
.join('\n');
|
|
178
|
+
} else {
|
|
179
|
+
return '';
|
|
180
|
+
}
|
|
137
181
|
}
|
|
138
182
|
|
|
139
|
-
export async function generateSchemaStructure(
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
183
|
+
export async function generateSchemaStructure(
|
|
184
|
+
projectName: string,
|
|
185
|
+
schemas: Record<string, SchemaType>,
|
|
186
|
+
path: string
|
|
187
|
+
) {
|
|
188
|
+
console.log('\nšØ Starting Schema Structure Generation...');
|
|
189
|
+
for (const schemaName in schemas) {
|
|
190
|
+
console.log(` āā Generating schema: ${schemaName}`);
|
|
191
|
+
console.log(
|
|
192
|
+
` āā Output path: ${path}/contracts/${projectName}/sources/codegen/schemas/${schemaName}.move`
|
|
193
|
+
);
|
|
194
|
+
console.log(
|
|
195
|
+
` āā Structure fields: ${
|
|
196
|
+
Object.keys(schemas[schemaName].structure).length
|
|
197
|
+
}`
|
|
198
|
+
);
|
|
199
|
+
const schema = schemas[schemaName];
|
|
200
|
+
const schemaMoudle = `module ${projectName}::${schemaName}_schema {
|
|
144
201
|
use std::ascii::String;
|
|
145
202
|
use std::type_name;
|
|
146
|
-
use
|
|
147
|
-
use
|
|
148
|
-
use
|
|
149
|
-
use
|
|
150
|
-
use
|
|
203
|
+
use dubhe::dapps_system;
|
|
204
|
+
use dubhe::dapps_schema::Dapps;
|
|
205
|
+
use dubhe::storage_value::{Self, StorageValue};
|
|
206
|
+
use dubhe::storage_map::{Self, StorageMap};
|
|
207
|
+
use dubhe::storage_double_map::{Self, StorageDoubleMap};
|
|
151
208
|
use ${projectName}::dapp_key::DappKey;
|
|
152
209
|
${generateImport(projectName, schemaName, schema)}
|
|
153
210
|
|
|
154
|
-
public struct ${capitalizeAndRemoveUnderscores(
|
|
211
|
+
public struct ${capitalizeAndRemoveUnderscores(
|
|
212
|
+
schemaName
|
|
213
|
+
)} has key, store {
|
|
155
214
|
id: UID,
|
|
156
215
|
${getStructAttrsWithType(schema.structure)}
|
|
157
216
|
}
|
|
158
217
|
|
|
159
|
-
${Object.entries(schema.structure)
|
|
160
|
-
|
|
218
|
+
${Object.entries(schema.structure)
|
|
219
|
+
.map(([key, value]) => {
|
|
220
|
+
return `public fun borrow_${key}(self: &${capitalizeAndRemoveUnderscores(
|
|
221
|
+
schemaName
|
|
222
|
+
)}) : &${value} {
|
|
161
223
|
&self.${key}
|
|
162
224
|
}
|
|
163
225
|
|
|
164
|
-
public(package) fun borrow_mut_${key}(self: &mut ${capitalizeAndRemoveUnderscores(
|
|
226
|
+
public(package) fun borrow_mut_${key}(self: &mut ${capitalizeAndRemoveUnderscores(
|
|
227
|
+
schemaName
|
|
228
|
+
)}): &mut ${value} {
|
|
165
229
|
&mut self.${key}
|
|
166
230
|
}
|
|
167
|
-
|
|
168
|
-
|
|
231
|
+
`;
|
|
232
|
+
})
|
|
233
|
+
.join('')}
|
|
169
234
|
|
|
170
|
-
public fun register(dapps: &mut Dapps, ctx: &mut TxContext): ${capitalizeAndRemoveUnderscores(
|
|
235
|
+
public fun register(dapps: &mut Dapps, ctx: &mut TxContext): ${capitalizeAndRemoveUnderscores(
|
|
236
|
+
schemaName
|
|
237
|
+
)} {
|
|
171
238
|
let package_id = dapps_system::current_package_id<DappKey>();
|
|
172
239
|
assert!(dapps.borrow_metadata().contains_key(package_id), 0);
|
|
173
240
|
assert!(dapps.borrow_admin().get(package_id) == ctx.sender(), 0);
|
|
174
|
-
let schema = type_name::get<${capitalizeAndRemoveUnderscores(
|
|
241
|
+
let schema = type_name::get<${capitalizeAndRemoveUnderscores(
|
|
242
|
+
schemaName
|
|
243
|
+
)}>().into_string();
|
|
175
244
|
assert!(!dapps.borrow_schemas().get(package_id).contains(&schema), 0);
|
|
176
|
-
dapps_system::add_schema<${capitalizeAndRemoveUnderscores(
|
|
245
|
+
dapps_system::add_schema<${capitalizeAndRemoveUnderscores(
|
|
246
|
+
schemaName
|
|
247
|
+
)}>(dapps, package_id, ctx);
|
|
177
248
|
${capitalizeAndRemoveUnderscores(schemaName)} {
|
|
178
249
|
id: object::new(ctx),
|
|
179
|
-
${Object.entries(schema.structure)
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
250
|
+
${Object.entries(schema.structure)
|
|
251
|
+
.map(([key, value]) => {
|
|
252
|
+
let storage_type = '';
|
|
253
|
+
if (value.includes('StorageValue')) {
|
|
254
|
+
storage_type = `storage_value::new()`;
|
|
255
|
+
} else if (value.includes('StorageMap')) {
|
|
256
|
+
storage_type = `storage_map::new()`;
|
|
257
|
+
} else if (
|
|
258
|
+
value.includes('StorageDoubleMap')
|
|
259
|
+
) {
|
|
260
|
+
storage_type = `storage_double_map::new()`;
|
|
261
|
+
}
|
|
262
|
+
return `${key}: ${storage_type},`;
|
|
263
|
+
})
|
|
264
|
+
.join(' ')}
|
|
191
265
|
}
|
|
192
266
|
}
|
|
193
267
|
|
|
194
268
|
}`;
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
269
|
+
await formatAndWriteMove(
|
|
270
|
+
schemaMoudle,
|
|
271
|
+
`${path}/contracts/${projectName}/sources/codegen/schemas/${schemaName}.move`,
|
|
272
|
+
'formatAndWriteMove'
|
|
273
|
+
);
|
|
274
|
+
}
|
|
275
|
+
console.log('ā
Schema Structure Generation Complete\n');
|
|
276
|
+
}
|