okai 0.0.24 → 0.0.25
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/dist/api.d.ts +12 -1
- package/dist/cs-apis.js +5 -0
- package/dist/cs-ast.js +326 -283
- package/dist/cs-gen.js +15 -9
- package/dist/cs-migrations.js +14 -5
- package/dist/index.js +80 -38
- package/dist/info.js +76 -0
- package/dist/ts-ast.js +32 -1
- package/dist/ts-once.js +240 -0
- package/dist/ts-parser.js +36 -27
- package/dist/tsd-gen.js +18 -81
- package/dist/utils.js +26 -1
- package/package.json +1 -1
package/dist/cs-gen.js
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
import { unwrap } from "./cs-ast";
|
1
2
|
import { leftPart } from "./utils.js";
|
2
3
|
export class CSharpGenerator {
|
3
4
|
namespaces = [];
|
@@ -25,7 +26,7 @@ export class CSharpGenerator {
|
|
25
26
|
}
|
26
27
|
const optional = name.endsWith('?');
|
27
28
|
return genericArgs?.length
|
28
|
-
? `${leftPart(name, '`')}<${genericArgs.join(',')}>` + (optional ? '?' : '')
|
29
|
+
? `${unwrap(leftPart(name, '`'))}<${genericArgs.join(',')}>` + (optional ? '?' : '')
|
29
30
|
: name;
|
30
31
|
}
|
31
32
|
toAttribtue(attr) {
|
@@ -36,7 +37,7 @@ export class CSharpGenerator {
|
|
36
37
|
if (body)
|
37
38
|
body += ',';
|
38
39
|
const value = arg.type.toLowerCase() === 'string'
|
39
|
-
?
|
40
|
+
? this.toQuotedString(arg.value)
|
40
41
|
: arg.value;
|
41
42
|
body += value;
|
42
43
|
}
|
@@ -47,7 +48,7 @@ export class CSharpGenerator {
|
|
47
48
|
if (body)
|
48
49
|
body += ',';
|
49
50
|
const value = arg.type.toLowerCase() === 'string'
|
50
|
-
?
|
51
|
+
? this.toQuotedString(arg.value)
|
51
52
|
: arg.value;
|
52
53
|
body += `${arg.name}=${value}`;
|
53
54
|
}
|
@@ -55,7 +56,7 @@ export class CSharpGenerator {
|
|
55
56
|
return `[${attr.name}${body ? `(${body})` : ''}]`;
|
56
57
|
}
|
57
58
|
toClass(cls, opt) {
|
58
|
-
const showDesc = !opt || !opt.
|
59
|
+
const showDesc = !opt || !opt.hideAttrs?.includes('description');
|
59
60
|
const sb = [];
|
60
61
|
let clsDef = `public class ${cls.name}`;
|
61
62
|
if (cls.inherits) {
|
@@ -71,7 +72,7 @@ export class CSharpGenerator {
|
|
71
72
|
sb.push(`/// </summary>`);
|
72
73
|
}
|
73
74
|
for (const attr of cls.attributes ?? []) {
|
74
|
-
if (opt?.
|
75
|
+
if (opt?.hideAttrs?.includes(attr.name.toLowerCase()))
|
75
76
|
continue;
|
76
77
|
const def = this.toAttribtue(attr);
|
77
78
|
sb.push(`${def}`);
|
@@ -79,6 +80,8 @@ export class CSharpGenerator {
|
|
79
80
|
sb.push(clsDef);
|
80
81
|
sb.push('{');
|
81
82
|
for (const prop of cls.properties ?? []) {
|
83
|
+
if (opt?.ignoreProp?.(prop))
|
84
|
+
continue;
|
82
85
|
this.addNamespace(prop.namespace);
|
83
86
|
if (showDesc && prop.description) {
|
84
87
|
sb.push(` /// <summary>`);
|
@@ -95,11 +98,14 @@ export class CSharpGenerator {
|
|
95
98
|
sb.push('}');
|
96
99
|
return sb.join('\n');
|
97
100
|
}
|
101
|
+
toQuotedString(s, defaultValue = '""') {
|
102
|
+
return s ? `"${s.replaceAll('\n', '\\n').replaceAll('"', '\\"')}"` : defaultValue;
|
103
|
+
}
|
98
104
|
toEnum(enumType, opt) {
|
99
|
-
const showDesc = !opt || !opt.
|
105
|
+
const showDesc = !opt || !opt.hideAttrs?.includes('description');
|
100
106
|
const sb = [];
|
101
107
|
if (showDesc && enumType.description) {
|
102
|
-
sb.push(`[Description(
|
108
|
+
sb.push(`[Description(${this.toQuotedString(enumType.description)})]`);
|
103
109
|
}
|
104
110
|
sb.push(`public enum ${enumType.name}`);
|
105
111
|
sb.push('{');
|
@@ -112,10 +118,10 @@ export class CSharpGenerator {
|
|
112
118
|
: value;
|
113
119
|
let desc = enumType.enumDescriptions?.[i];
|
114
120
|
if (desc) {
|
115
|
-
sb.push(` [Description(
|
121
|
+
sb.push(` [Description(${this.toQuotedString(desc)})]`);
|
116
122
|
}
|
117
123
|
if (memberValue && memberValue !== value && memberValue !== name) {
|
118
|
-
sb.push(` [EnumMember(Value =
|
124
|
+
sb.push(` [EnumMember(Value = ${this.toQuotedString(memberValue)})]`);
|
119
125
|
}
|
120
126
|
sb.push(value
|
121
127
|
? ` ${name} = ${value},`
|
package/dist/cs-migrations.js
CHANGED
@@ -9,9 +9,12 @@ export class CSharpMigrationGenerator extends CSharpGenerator {
|
|
9
9
|
'ServiceStack.OrmLite',
|
10
10
|
...ast.namespaces
|
11
11
|
]));
|
12
|
-
|
13
|
-
|
14
|
-
|
12
|
+
// props with [Reference] attribute don't need to be included in the migration (ignore to avoid missing references e.g. User)
|
13
|
+
const ignoreProp = (prop) => prop.attributes?.some(x => x.name === 'Reference');
|
14
|
+
const hideAttrs = ['description', 'icon'];
|
15
|
+
const opt = { hideAttrs, ignoreProp };
|
16
|
+
this.classes = ast.types.filter(t => !t.isEnum && !t.isInterface).map(x => this.toClass(x, opt));
|
17
|
+
this.enums = ast.types.filter(t => t.isEnum).map(x => this.toEnum(x, opt));
|
15
18
|
const sb = [];
|
16
19
|
if (this.classes.length) {
|
17
20
|
for (const cls of this.classes) {
|
@@ -80,16 +83,17 @@ export class CSharpMigrationGenerator extends CSharpGenerator {
|
|
80
83
|
orderedTypes.push(type.name);
|
81
84
|
}
|
82
85
|
});
|
86
|
+
const ignoreTables = ['User'];
|
83
87
|
sb.push(' public override void Up()');
|
84
88
|
sb.push(' {');
|
85
|
-
for (const typeName of orderedTypes) {
|
89
|
+
for (const typeName of orderedTypes.filter(x => !ignoreTables.includes(x))) {
|
86
90
|
sb.push(` Db.CreateTable<${typeName}>();`);
|
87
91
|
}
|
88
92
|
sb.push(' }');
|
89
93
|
sb.push('');
|
90
94
|
sb.push(' public override void Down()');
|
91
95
|
sb.push(' {');
|
92
|
-
for (const typeName of orderedTypes.reverse()) {
|
96
|
+
for (const typeName of orderedTypes.filter(x => !ignoreTables.includes(x)).reverse()) {
|
93
97
|
sb.push(` Db.DropTable<${typeName}>();`);
|
94
98
|
}
|
95
99
|
sb.push(' }');
|
@@ -100,3 +104,8 @@ export class CSharpMigrationGenerator extends CSharpGenerator {
|
|
100
104
|
};
|
101
105
|
}
|
102
106
|
}
|
107
|
+
export function toCSharpMigration(csAst) {
|
108
|
+
const csFiles = new CSharpMigrationGenerator().generate(csAst);
|
109
|
+
const cs = csFiles[Object.keys(csFiles)[0]];
|
110
|
+
return cs;
|
111
|
+
}
|
package/dist/index.js
CHANGED
@@ -2,13 +2,12 @@ import fs from "fs";
|
|
2
2
|
import path from "path";
|
3
3
|
import blessed from 'blessed';
|
4
4
|
import { projectInfo } from './info.js';
|
5
|
-
import { parseTsdHeader, toTsdHeader,
|
6
|
-
import { toAst } from "./ts-ast.js";
|
7
|
-
import { toMetadataTypes } from "./cs-ast.js";
|
5
|
+
import { parseTsdHeader, toTsdHeader, leftPart, replaceMyApp, trimStart, toPascalCase, plural } from "./utils.js";
|
6
|
+
import { generateCsAstFromTsd, toAst, astForProject } from "./ts-ast.js";
|
8
7
|
import { CSharpApiGenerator } from "./cs-apis.js";
|
9
8
|
import { CSharpMigrationGenerator } from "./cs-migrations.js";
|
10
|
-
import { TsdDataModelGenerator } from "./tsd-gen.js";
|
11
9
|
import { getFileContent } from "./client.js";
|
10
|
+
import { toTsd } from "./tsd-gen.js";
|
12
11
|
function normalizeSwitches(cmd) { return cmd.replace(/^-+/, '/'); }
|
13
12
|
function parseArgs(...args) {
|
14
13
|
const ret = {
|
@@ -62,8 +61,12 @@ function parseArgs(...args) {
|
|
62
61
|
ret.type = "help";
|
63
62
|
else if (arg == "info")
|
64
63
|
ret.type = "info";
|
65
|
-
else if (arg == "init")
|
64
|
+
else if (arg == "init") {
|
66
65
|
ret.type = "init";
|
66
|
+
if (args[i + 1]) {
|
67
|
+
ret.init = args[++i];
|
68
|
+
}
|
69
|
+
}
|
67
70
|
else if (arg == "update") {
|
68
71
|
ret.type = "update";
|
69
72
|
ret.tsdFile = args[++i];
|
@@ -136,7 +139,7 @@ export async function cli(cmdArgs) {
|
|
136
139
|
process.exit(0);
|
137
140
|
return;
|
138
141
|
}
|
139
|
-
if (command.type === "init") {
|
142
|
+
if (command.type === "init" && !command.init) {
|
140
143
|
let info = projectInfo(process.cwd()) ?? {
|
141
144
|
projectName: "<MyApp>",
|
142
145
|
slnDir: "/path/to/.sln/folder",
|
@@ -146,6 +149,7 @@ export async function cli(cmdArgs) {
|
|
146
149
|
serviceInterfaceDir: "/path/to/MyApp.ServiceInterfaces",
|
147
150
|
};
|
148
151
|
fs.writeFileSync('okai.json', JSON.stringify(info, undefined, 2));
|
152
|
+
console.log(`Added: okai.json`);
|
149
153
|
process.exit(0);
|
150
154
|
return;
|
151
155
|
}
|
@@ -166,6 +170,7 @@ ${bin} <models>.d.ts Regenerate C# *.cs files for Data Models defined in
|
|
166
170
|
${bin} rm <models>.d.ts Remove <models>.d.ts and its generated *.cs files
|
167
171
|
${bin} ls models Display list of available premium LLM models
|
168
172
|
${bin} init Initialize okai.json with project info to override default paths
|
173
|
+
${bin} init <model> Create an empty <model>.d.ts file for the specified model
|
169
174
|
${bin} info Display current project info
|
170
175
|
|
171
176
|
Options:
|
@@ -212,6 +217,37 @@ Options:
|
|
212
217
|
process.exit(0);
|
213
218
|
}
|
214
219
|
}
|
220
|
+
if (command.type == "init" && command.info) {
|
221
|
+
const toApiFile = path.join(info.serviceModelDir, 'api.d.ts');
|
222
|
+
fs.copyFileSync(path.join(import.meta.dirname, 'api.d.ts'), toApiFile);
|
223
|
+
console.log(`Added: ${toApiFile}`);
|
224
|
+
let model = toPascalCase(leftPart(command.init, '.'));
|
225
|
+
let groupName = plural(model);
|
226
|
+
if (model == groupName) {
|
227
|
+
if (model.endsWith('s')) {
|
228
|
+
model = model.substring(0, model.length - 1);
|
229
|
+
}
|
230
|
+
}
|
231
|
+
let tsd = `
|
232
|
+
export class ${model} {
|
233
|
+
id:number
|
234
|
+
name:string
|
235
|
+
}
|
236
|
+
`;
|
237
|
+
const tsdAst = toAst(tsd);
|
238
|
+
if (tsdAst.references.length == 0) {
|
239
|
+
tsdAst.references.push({ path: './api.d.ts' });
|
240
|
+
}
|
241
|
+
tsd = toTsd(tsdAst);
|
242
|
+
const tsdContent = createTsdFile(info, {
|
243
|
+
prompt: `New ${model}`,
|
244
|
+
apiFileName: `${groupName}.cs`,
|
245
|
+
tsd,
|
246
|
+
});
|
247
|
+
command.type = "update"; // let update handle the rest
|
248
|
+
command.tsdFile = groupName + '.d.ts';
|
249
|
+
fs.writeFileSync(path.join(info.serviceModelDir, command.tsdFile), tsdContent, { encoding: 'utf-8' });
|
250
|
+
}
|
215
251
|
if (command.type === "add") {
|
216
252
|
if (command.add == "types" || command.add?.startsWith("api")) {
|
217
253
|
const apiFile = path.join(import.meta.dirname, 'api.d.ts');
|
@@ -263,14 +299,10 @@ Options:
|
|
263
299
|
if (command.verbose)
|
264
300
|
console.log(JSON.stringify(header, undefined, 2));
|
265
301
|
function regenerate(header, tsdContent, logPrefix = '') {
|
266
|
-
const
|
267
|
-
|
268
|
-
tsdContent = tsdGenerator.generate(tsdAst);
|
269
|
-
const csAst = toMetadataTypes(tsdAst);
|
270
|
-
// const groupName = path.basename(command.tsdFile, '.d.ts')
|
271
|
-
// console.log('groupName', groupName)
|
302
|
+
const result = generateCsAstFromTsd(tsdContent);
|
303
|
+
tsdContent = result.tsd;
|
272
304
|
const genApis = new CSharpApiGenerator();
|
273
|
-
const csApiFiles = genApis.generate(csAst);
|
305
|
+
const csApiFiles = genApis.generate(result.csAst);
|
274
306
|
const apiContent = replaceMyApp(csApiFiles[Object.keys(csApiFiles)[0]], info.projectName);
|
275
307
|
const apiPath = resolveApiFile(header.api);
|
276
308
|
console.log(`${logPrefix}${apiPath}`);
|
@@ -278,14 +310,14 @@ Options:
|
|
278
310
|
if (header?.migration) {
|
279
311
|
const migrationCls = leftPart(path.basename(header.migration), '.');
|
280
312
|
const getMigrations = new CSharpMigrationGenerator();
|
281
|
-
const csMigrationFiles = getMigrations.generate(csAst);
|
313
|
+
const csMigrationFiles = getMigrations.generate(result.csAst);
|
282
314
|
const migrationContent = replaceMyApp(csMigrationFiles[Object.keys(csMigrationFiles)[0]].replaceAll('Migration1000', migrationCls), info.projectName);
|
283
315
|
const migrationPath = resolveApiFile(header.migration);
|
284
316
|
console.log(`${logPrefix}${migrationPath}`);
|
285
317
|
fs.writeFileSync(migrationPath, migrationContent, { encoding: 'utf-8' });
|
286
318
|
}
|
287
319
|
console.log(`${logPrefix}${tsdPath}`);
|
288
|
-
const newTsdContent = toTsdHeader(header) + '\n\n' + tsdContent;
|
320
|
+
const newTsdContent = toTsdHeader(header) + (tsdContent.startsWith('///') ? '' : '\n\n') + tsdContent;
|
289
321
|
fs.writeFileSync(tsdPath, newTsdContent, { encoding: 'utf-8' });
|
290
322
|
return newTsdContent;
|
291
323
|
}
|
@@ -300,7 +332,7 @@ Options:
|
|
300
332
|
console.log(`No change detected`);
|
301
333
|
return;
|
302
334
|
}
|
303
|
-
console.log(`\n${++i}. ${leftPart(new Date().toTimeString(), ' ')}
|
335
|
+
console.log(`\n${++i}. regenerated files at ${leftPart(new Date().toTimeString(), ' ')}:`);
|
304
336
|
lastTsdContent = regenerate(header, tsdContent);
|
305
337
|
});
|
306
338
|
return;
|
@@ -620,35 +652,29 @@ function chooseFile(ctx, info, gist, comamnd) {
|
|
620
652
|
acceptTask = fetch(acceptUrl, { method: 'POST' });
|
621
653
|
}
|
622
654
|
const origTsd = file.content;
|
623
|
-
const tsdAst = toAst(origTsd);
|
624
|
-
const
|
625
|
-
const tsd = generator.generate(tsdAst);
|
626
|
-
const csAst = toMetadataTypes(tsdAst);
|
627
|
-
const groupName = getGroupName(csAst);
|
655
|
+
const tsdAst = astForProject(toAst(origTsd), info);
|
656
|
+
const res = generateCsAstFromTsd(toTsd(tsdAst));
|
628
657
|
const genApis = new CSharpApiGenerator();
|
629
|
-
const csApiFiles = genApis.generate(csAst);
|
658
|
+
const csApiFiles = genApis.generate(res.csAst);
|
630
659
|
const getMigrations = new CSharpMigrationGenerator();
|
631
|
-
const csMigrationFiles = getMigrations.generate(csAst);
|
660
|
+
const csMigrationFiles = getMigrations.generate(res.csAst);
|
632
661
|
const relativeServiceModelDir = trimStart(info.serviceModelDir.substring(info.slnDir.length), '~/');
|
633
662
|
const relativeMigrationDir = trimStart(info.migrationsDir.substring(info.slnDir.length), '~/');
|
634
|
-
const apiFileName = `${groupName}.cs`;
|
663
|
+
const apiFileName = `${res.groupName}.cs`;
|
635
664
|
const apiContent = replaceMyApp(csApiFiles[Object.keys(csApiFiles)[0]], info.projectName);
|
636
665
|
const migrationPath = resolveMigrationFile(path.join(info.migrationsDir, `Migration1000.cs`));
|
637
666
|
const migrationFileName = path.basename(migrationPath);
|
638
667
|
const migrationCls = leftPart(migrationFileName, '.');
|
639
668
|
const migrationContent = replaceMyApp(csMigrationFiles[Object.keys(csMigrationFiles)[0]].replaceAll('Migration1000', migrationCls), info.projectName);
|
640
|
-
const
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
const tsdContent = sb.join('\n');
|
650
|
-
const tsdFileName = `${groupName}.d.ts`;
|
651
|
-
const typesApiPath = path.join(info.slnDir, relativeServiceModelDir, `api.d.ts`);
|
669
|
+
const apiTypesPath = path.join(info.slnDir, relativeServiceModelDir, `api.d.ts`);
|
670
|
+
const apiFile = path.join(import.meta.dirname, 'api.d.ts');
|
671
|
+
fs.writeFileSync(apiTypesPath, fs.readFileSync(apiFile, 'utf-8'));
|
672
|
+
const tsdContent = createTsdFile(info, {
|
673
|
+
prompt: titleBar.content.replaceAll('/*', '').replaceAll('*/', ''),
|
674
|
+
apiFileName,
|
675
|
+
tsd: res.tsd,
|
676
|
+
});
|
677
|
+
const tsdFileName = `${res.groupName}.d.ts`;
|
652
678
|
const fullTsdPath = path.join(info.slnDir, relativeServiceModelDir, tsdFileName);
|
653
679
|
const fullApiPath = path.join(info.slnDir, relativeServiceModelDir, apiFileName);
|
654
680
|
const fullMigrationPath = path.join(info.slnDir, relativeMigrationDir, migrationFileName);
|
@@ -667,8 +693,6 @@ function chooseFile(ctx, info, gist, comamnd) {
|
|
667
693
|
fs.writeFileSync(fullMigrationPath, migrationContent, { encoding: 'utf-8' });
|
668
694
|
console.log(`Saved: ${fullMigrationPath}`);
|
669
695
|
}
|
670
|
-
const apiFile = path.join(import.meta.dirname, 'api.d.ts');
|
671
|
-
fs.writeFileSync(typesApiPath, fs.readFileSync(apiFile, 'utf-8'));
|
672
696
|
const script = path.basename(process.argv[1]);
|
673
697
|
console.log(`\nTo regenerate classes, update '${tsdFileName}' then run:`);
|
674
698
|
console.log(`$ ${script} ${tsdFileName}`);
|
@@ -742,6 +766,24 @@ function exit(screen, info, gist) {
|
|
742
766
|
}
|
743
767
|
process.exit(0);
|
744
768
|
}
|
769
|
+
function createTsdFile(info, opt) {
|
770
|
+
const migrationPath = resolveMigrationFile(path.join(info.migrationsDir, `Migration1000.cs`));
|
771
|
+
const migrationFileName = path.basename(migrationPath);
|
772
|
+
const relativeServiceModelDir = trimStart(info.serviceModelDir.substring(info.slnDir.length), '~/');
|
773
|
+
const relativeMigrationDir = info.migrationsDir && fs.existsSync(info.migrationsDir)
|
774
|
+
? trimStart(info.migrationsDir.substring(info.slnDir.length), '~/')
|
775
|
+
: null;
|
776
|
+
const sb = [
|
777
|
+
`/*prompt: ${opt.prompt}`,
|
778
|
+
`api: ~/${path.join(relativeServiceModelDir, opt.apiFileName)}`,
|
779
|
+
];
|
780
|
+
if (relativeMigrationDir) {
|
781
|
+
sb.push(`migration: ~/${path.join(relativeMigrationDir, migrationFileName)}`);
|
782
|
+
}
|
783
|
+
sb.push('*/');
|
784
|
+
sb.push('');
|
785
|
+
return sb.join('\n') + (opt.tsd.startsWith('///') ? '' : '\n\n') + opt.tsd;
|
786
|
+
}
|
745
787
|
function applyCSharpGist(ctx, info, gist, { accept = false, acceptAll = false, discard = false }) {
|
746
788
|
const { screen, titleBar, fileList, preview, statusBar, result } = ctx;
|
747
789
|
function removeSelected() {
|
package/dist/info.js
CHANGED
@@ -53,7 +53,83 @@ export function projectInfo(cwd) {
|
|
53
53
|
serviceModelDir,
|
54
54
|
serviceInterfaceDir,
|
55
55
|
};
|
56
|
+
for (const file of walk(serviceInterfaceDir, [], {
|
57
|
+
include: (path) => path.endsWith(".cs"),
|
58
|
+
excludeDirs: ["obj", "bin"]
|
59
|
+
})) {
|
60
|
+
const content = fs.readFileSync(file).toString();
|
61
|
+
const userInfo = parseUserType(content);
|
62
|
+
if (userInfo) {
|
63
|
+
info.userType = userInfo.userType;
|
64
|
+
info.userIdType = userInfo.userIdType ?? 'string';
|
65
|
+
break;
|
66
|
+
}
|
67
|
+
}
|
68
|
+
for (const file of walk(serviceModelDir, [], {
|
69
|
+
include: (path) => path.endsWith(".cs"),
|
70
|
+
excludeDirs: ["obj", "bin"]
|
71
|
+
})) {
|
72
|
+
const content = fs.readFileSync(file).toString();
|
73
|
+
const dtoInfo = parseUserDtoType(content);
|
74
|
+
if (dtoInfo?.userType) {
|
75
|
+
info.userType = dtoInfo.userType;
|
76
|
+
if (dtoInfo.userIdType)
|
77
|
+
info.userIdType = dtoInfo.userIdType;
|
78
|
+
if (dtoInfo.userLabel)
|
79
|
+
info.userLabel = dtoInfo.userLabel;
|
80
|
+
break;
|
81
|
+
}
|
82
|
+
}
|
56
83
|
return config
|
57
84
|
? Object.assign({}, info, config)
|
58
85
|
: info;
|
59
86
|
}
|
87
|
+
export function parseUserType(cs) {
|
88
|
+
const typePattern = /class\s+(\w+)\s*:\s*IdentityUser(?:<(.+)>)?/;
|
89
|
+
const match = cs.match(typePattern);
|
90
|
+
if (!match)
|
91
|
+
return null;
|
92
|
+
return {
|
93
|
+
userType: match[1], // Type name
|
94
|
+
userIdType: match[2] || null // Generic arguments (content between < >)
|
95
|
+
};
|
96
|
+
}
|
97
|
+
export function parseUserDtoType(cs) {
|
98
|
+
const userAliasPos = cs.indexOf('[Alias("AspNetUsers")]');
|
99
|
+
if (userAliasPos === -1)
|
100
|
+
return null;
|
101
|
+
const typeMatch = cs.substring(userAliasPos).match(/class\s+(\w+)\s*/);
|
102
|
+
if (!typeMatch)
|
103
|
+
return null;
|
104
|
+
const idMatch = cs.substring(userAliasPos).match(/\s+(\w+\??)\s+Id\s+/i);
|
105
|
+
const nameMatch = Array.from(cs.substring(userAliasPos).matchAll(/\s+(\w+Name)\s+/ig))
|
106
|
+
.find(x => x[1].toLowerCase() !== 'username')?.[1];
|
107
|
+
const userLabel = cs.includes('DisplayName')
|
108
|
+
? 'DisplayName'
|
109
|
+
: nameMatch
|
110
|
+
? nameMatch
|
111
|
+
: undefined;
|
112
|
+
return {
|
113
|
+
userType: typeMatch[1], // DTO Type name
|
114
|
+
userIdType: idMatch ? idMatch[1] : null,
|
115
|
+
userLabel,
|
116
|
+
};
|
117
|
+
}
|
118
|
+
function walk(dir, fileList = [], opt) {
|
119
|
+
const files = fs.readdirSync(dir);
|
120
|
+
for (const file of files) {
|
121
|
+
const filePath = path.join(dir, file);
|
122
|
+
const stat = fs.statSync(filePath);
|
123
|
+
if (stat.isDirectory()) {
|
124
|
+
if (!opt?.excludeDirs || !opt.excludeDirs.includes(file)) {
|
125
|
+
walk(filePath, fileList, opt);
|
126
|
+
}
|
127
|
+
}
|
128
|
+
else {
|
129
|
+
if (!opt?.include || opt?.include(filePath)) {
|
130
|
+
fileList.push(filePath);
|
131
|
+
}
|
132
|
+
}
|
133
|
+
}
|
134
|
+
return fileList;
|
135
|
+
}
|
package/dist/ts-ast.js
CHANGED
@@ -1,5 +1,10 @@
|
|
1
|
+
import { toMetadataTypes } from "./cs-ast.js";
|
2
|
+
import { createTdAstFromAIAst, transformUserRefs } from "./ts-once.js";
|
1
3
|
import { TypeScriptParser } from "./ts-parser.js";
|
2
|
-
|
4
|
+
import { toTsd } from "./tsd-gen.js";
|
5
|
+
import { getGroupName } from "./utils.js";
|
6
|
+
// Extract TypeScript source code from a AI Response
|
7
|
+
export function extractTypeScriptSrc(msg) {
|
3
8
|
msg = msg.trim();
|
4
9
|
const startPos = msg.indexOf("```typescript");
|
5
10
|
if (startPos >= 0) {
|
@@ -12,7 +17,33 @@ export function toTypeScriptSrc(msg) {
|
|
12
17
|
return msg;
|
13
18
|
}
|
14
19
|
}
|
20
|
+
// Parse TypeScript source code into AST
|
15
21
|
export function toAst(src) {
|
16
22
|
const parser = new TypeScriptParser();
|
17
23
|
return parser.parse(src);
|
18
24
|
}
|
25
|
+
// Tranforms that are only applied once on AI TypeScript AST
|
26
|
+
export function createAstFromAITypeScript(ts) {
|
27
|
+
const parser = new TypeScriptParser();
|
28
|
+
const tdAst = parser.parse(ts);
|
29
|
+
return createTdAstFromAIAst(tdAst);
|
30
|
+
}
|
31
|
+
// Apply Project Info to the AST once after it's downloaded
|
32
|
+
export function astForProject(tsAst, info) {
|
33
|
+
transformUserRefs(tsAst, info);
|
34
|
+
return tsAst;
|
35
|
+
}
|
36
|
+
// Convert User TypeScript into CS AST and Updated TSD
|
37
|
+
export function generateCsAstFromTsd(userTs) {
|
38
|
+
const userTsAst = toAst(userTs); // user modified tsd
|
39
|
+
const tsd = toTsd(userTsAst);
|
40
|
+
const tsdAst = toAst(tsd);
|
41
|
+
const csAst = toMetadataTypes(tsdAst);
|
42
|
+
const result = {
|
43
|
+
tsdAst,
|
44
|
+
tsd,
|
45
|
+
csAst,
|
46
|
+
groupName: getGroupName(csAst)
|
47
|
+
};
|
48
|
+
return result;
|
49
|
+
}
|