okai 0.0.11 → 0.0.13
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/cs-apis.js +5 -5
- package/dist/cs-ast.js +37 -0
- package/dist/cs-gen.js +6 -0
- package/dist/index.js +35 -6
- package/dist/ts-parser.js +191 -31
- package/dist/tsd-gen.js +30 -1
- package/package.json +1 -1
package/dist/cs-apis.js
CHANGED
@@ -29,18 +29,18 @@ export class CSharpApiGenerator extends CSharpGenerator {
|
|
29
29
|
}
|
30
30
|
if (op.requiredRoles?.length) {
|
31
31
|
const adminRole = op.requiredRoles.includes('Admin');
|
32
|
-
if (adminRole) {
|
32
|
+
if (adminRole && !this.typeHasAttr(op.request, 'ValidateIsAdmin')) {
|
33
33
|
sb.push(`[ValidateIsAdmin]`);
|
34
34
|
}
|
35
35
|
const roles = op.requiredRoles.filter(r => r !== 'Admin');
|
36
|
-
if (roles.length) {
|
36
|
+
if (roles.length && !this.typeHasAttr(op.request, 'ValidateHasRole')) {
|
37
37
|
sb.push(`[ValidateHasRole("${roles[0]}")]`);
|
38
38
|
}
|
39
39
|
}
|
40
|
-
else if (op.requiresAuth) {
|
40
|
+
else if (op.requiresAuth && !this.typeHasAttr(op.request, 'ValidateIsAuthenticated')) {
|
41
41
|
sb.push(`[ValidateIsAuthenticated]`);
|
42
42
|
}
|
43
|
-
if (cls.description) {
|
43
|
+
if (cls.description && !this.typeHasAttr(op.request, 'Api')) {
|
44
44
|
sb.push(`[Api("${cls.description}")]`);
|
45
45
|
}
|
46
46
|
for (const attr of cls.attributes ?? []) {
|
@@ -55,7 +55,7 @@ export class CSharpApiGenerator extends CSharpGenerator {
|
|
55
55
|
sb.push('{');
|
56
56
|
for (const prop of cls.properties) {
|
57
57
|
this.addNamespace(prop.namespace);
|
58
|
-
if (prop.description) {
|
58
|
+
if (prop.description && !this.propHasAttr(prop, 'ApiMember')) {
|
59
59
|
if (!prop.description.includes('\n')) {
|
60
60
|
sb.push(` [ApiMember(Description="${prop.description.replace(/"/g, '\\"')}")]`);
|
61
61
|
}
|
package/dist/cs-ast.js
CHANGED
@@ -75,6 +75,35 @@ export class CSharpAst {
|
|
75
75
|
}
|
76
76
|
return this.typeMap[type] ?? { name: type, namespace: "MyApp" };
|
77
77
|
}
|
78
|
+
csharpAttribute(attr) {
|
79
|
+
const to = { name: toPascalCase(attr.name) };
|
80
|
+
const attrType = (value) => typeof value == 'string'
|
81
|
+
? (`${value}`.startsWith('typeof') ? "Type" : "string")
|
82
|
+
: typeof value == "object"
|
83
|
+
? (value instanceof Date ? "string" : Array.isArray(value) ? "array" : "object")
|
84
|
+
: typeof value;
|
85
|
+
if (attr.constructorArgs?.length) {
|
86
|
+
to.constructorArgs = attr.constructorArgs.map(x => {
|
87
|
+
const type = attrType(x.value);
|
88
|
+
return {
|
89
|
+
name: 'String',
|
90
|
+
type,
|
91
|
+
value: `${x.value}`
|
92
|
+
};
|
93
|
+
});
|
94
|
+
}
|
95
|
+
if (attr.args && Object.keys(attr.args).length) {
|
96
|
+
to.args = Object.entries(attr.args).map(([name, value]) => {
|
97
|
+
const type = attrType(value);
|
98
|
+
return {
|
99
|
+
name: toPascalCase(name),
|
100
|
+
type,
|
101
|
+
value: `${value}`
|
102
|
+
};
|
103
|
+
});
|
104
|
+
}
|
105
|
+
return to;
|
106
|
+
}
|
78
107
|
addMetadataType(cls) {
|
79
108
|
const type = {
|
80
109
|
name: this.toCsName(cls.name),
|
@@ -110,9 +139,15 @@ export class CSharpAst {
|
|
110
139
|
args: [{ name: "Currency", type: "constant", value: "NumberCurrency.USD" }]
|
111
140
|
});
|
112
141
|
}
|
142
|
+
if (p.annotations?.length) {
|
143
|
+
prop.attributes = p.annotations.map(x => this.csharpAttribute(x));
|
144
|
+
}
|
113
145
|
return prop;
|
114
146
|
}),
|
115
147
|
};
|
148
|
+
if (cls.annotations?.length) {
|
149
|
+
type.attributes = cls.annotations.map(x => this.csharpAttribute(x));
|
150
|
+
}
|
116
151
|
// Add dependent types first
|
117
152
|
type.properties.filter(x => x.namespace === 'MyApp'
|
118
153
|
&& x.name !== cls.name
|
@@ -588,6 +623,8 @@ export class CSharpAst {
|
|
588
623
|
if (icon) {
|
589
624
|
if (!type.attributes)
|
590
625
|
type.attributes = [];
|
626
|
+
if (type.attributes.some(x => x.name === 'Icon'))
|
627
|
+
continue;
|
591
628
|
type.attributes.push({
|
592
629
|
name: "Icon",
|
593
630
|
args: [{ name: "Svg", type: "string", value: icon }]
|
package/dist/cs-gen.js
CHANGED
@@ -5,6 +5,12 @@ export class CSharpGenerator {
|
|
5
5
|
classes = [];
|
6
6
|
enums = [];
|
7
7
|
ast = { namespaces: [], operations: [], types: [] };
|
8
|
+
typeHasAttr(type, name) {
|
9
|
+
return type.attributes?.some(x => x.name === name);
|
10
|
+
}
|
11
|
+
propHasAttr(prop, name) {
|
12
|
+
return prop.attributes?.some(x => x.name === name);
|
13
|
+
}
|
8
14
|
addNamespace(ns) {
|
9
15
|
if (!ns || this.namespaces.includes(ns))
|
10
16
|
return;
|
package/dist/index.js
CHANGED
@@ -45,25 +45,47 @@ function parseArgs(...args) {
|
|
45
45
|
case "/license":
|
46
46
|
ret.license = args[++i];
|
47
47
|
break;
|
48
|
+
case "/url":
|
49
|
+
ret.baseUrl = args[++i];
|
50
|
+
break;
|
51
|
+
case "/cached":
|
52
|
+
ret.cached = true;
|
53
|
+
break;
|
48
54
|
default:
|
49
55
|
ret.unknown = ret.unknown || [];
|
50
56
|
ret.unknown.push(arg);
|
51
57
|
break;
|
52
58
|
}
|
53
59
|
}
|
54
|
-
else if (ret.type === "help" && ["help", "info", "init", "ls", "rm"].includes(arg)) {
|
60
|
+
else if (ret.type === "help" && ["help", "info", "init", "ls", "rm", "update", "accept"].includes(arg)) {
|
55
61
|
if (arg == "help")
|
56
62
|
ret.type = "help";
|
57
63
|
else if (arg == "info")
|
58
64
|
ret.type = "info";
|
59
65
|
else if (arg == "init")
|
60
66
|
ret.type = "init";
|
61
|
-
else if (arg == "
|
67
|
+
else if (arg == "update") {
|
68
|
+
ret.type = "update";
|
69
|
+
ret.tsdFile = args[++i];
|
70
|
+
if (ret.tsdFile && !ret.tsdFile.endsWith('.d.ts')) {
|
71
|
+
ret.tsdFile += '.d.ts';
|
72
|
+
}
|
73
|
+
}
|
74
|
+
else if (arg == "rm") {
|
62
75
|
ret.type = "remove";
|
76
|
+
ret.tsdFile = args[++i];
|
77
|
+
if (ret.tsdFile && !ret.tsdFile.endsWith('.d.ts')) {
|
78
|
+
ret.tsdFile += '.d.ts';
|
79
|
+
}
|
80
|
+
}
|
63
81
|
else if (arg == "ls") {
|
64
82
|
ret.type = "list";
|
65
83
|
ret.list = args[++i];
|
66
84
|
}
|
85
|
+
else if (arg == "accept") {
|
86
|
+
ret.type = "accept";
|
87
|
+
ret.accept = args[++i];
|
88
|
+
}
|
67
89
|
}
|
68
90
|
else if (arg.endsWith('.d.ts')) {
|
69
91
|
if (ret.type == "help")
|
@@ -79,6 +101,9 @@ function parseArgs(...args) {
|
|
79
101
|
}
|
80
102
|
}
|
81
103
|
if (ret.type === "prompt") {
|
104
|
+
if (!ret.cached && process.env.OKAI_CACHED) {
|
105
|
+
ret.cached = true;
|
106
|
+
}
|
82
107
|
if (!ret.models && process.env.OKAI_MODELS) {
|
83
108
|
ret.models = process.env.OKAI_MODELS;
|
84
109
|
}
|
@@ -296,6 +321,12 @@ Options:
|
|
296
321
|
console.log(`Removed: ${tsdPath}`);
|
297
322
|
process.exit(0);
|
298
323
|
}
|
324
|
+
if (command.type == "accept") {
|
325
|
+
const url = new URL('/models/accept', command.baseUrl);
|
326
|
+
url.searchParams.append('add', command.accept);
|
327
|
+
fetch(url);
|
328
|
+
process.exit(0);
|
329
|
+
}
|
299
330
|
if (command.type === 'prompt') {
|
300
331
|
try {
|
301
332
|
if (!info.serviceModelDir)
|
@@ -321,7 +352,7 @@ Options:
|
|
321
352
|
}
|
322
353
|
async function fetchGistFiles(command) {
|
323
354
|
const url = new URL('/models/gist', command.baseUrl);
|
324
|
-
if (
|
355
|
+
if (command.cached) {
|
325
356
|
url.searchParams.append('cached', `1`);
|
326
357
|
}
|
327
358
|
url.searchParams.append('prompt', command.prompt);
|
@@ -489,7 +520,7 @@ async function createGistPreview(title, gist) {
|
|
489
520
|
function chooseFile(ctx, info, gist) {
|
490
521
|
const { screen, titleBar, fileList, preview, statusBar, result } = ctx;
|
491
522
|
const file = gist.files[result.selectedFile];
|
492
|
-
|
523
|
+
console.clear();
|
493
524
|
const tsd = file.content;
|
494
525
|
const tsdAst = toAst(tsd);
|
495
526
|
const csAst = toMetadataTypes(tsdAst);
|
@@ -518,8 +549,6 @@ function chooseFile(ctx, info, gist) {
|
|
518
549
|
const fullTsdPath = path.join(info.slnDir, relativeServiceModelDir, tsdFileName);
|
519
550
|
const fullApiPath = path.join(info.slnDir, relativeServiceModelDir, apiFileName);
|
520
551
|
const fullMigrationPath = path.join(info.slnDir, relativeMigrationDir, migrationFileName);
|
521
|
-
const clearScreen = blessed.screen();
|
522
|
-
clearScreen.render();
|
523
552
|
if (!fs.existsSync(path.dirname(fullTsdPath))) {
|
524
553
|
console.log(`Directory does not exist: ${path.dirname(fullTsdPath)}`);
|
525
554
|
process.exit(0);
|
package/dist/ts-parser.js
CHANGED
@@ -1,9 +1,10 @@
|
|
1
1
|
export class TypeScriptParser {
|
2
|
-
static CLASS_PATTERN = /class\s+(\w+)(?:\s+extends\s+(\w+))?(?:\s+implements\s+([\w,\s]+))?\s*{
|
3
|
-
static INTERFACE_PATTERN = /interface\s+(\w+)(?:\s+extends\s+(\w+))?\s*{
|
2
|
+
static CLASS_PATTERN = /class\s+(\w+)(?:\s+extends\s+(\w+))?(?:\s+implements\s+([\w,\s]+))?\s*{/g;
|
3
|
+
static INTERFACE_PATTERN = /interface\s+(\w+)(?:\s+extends\s+(\w+))?\s*{/g;
|
4
4
|
static ENUM_PATTERN = /enum\s+(\w+)\s*{([^}]*)}/g;
|
5
5
|
static PROPERTY_PATTERN = /(?:(?<modifier>private|public|protected|readonly)\s+)*(?<name>\w+)(?<optional>\?)?\s*:\s*(?<type>[\w<>[\],\s]+)(?<union>\|\s*[\w<>[\],|,\s]+)?\s*;?/;
|
6
6
|
static ENUM_MEMBER_PATTERN = /(\w+)\s*(?:=\s*("[^"]*"|'[^']*'|\d+|[^,\n]+))?\s*/;
|
7
|
+
static ANNOTATION_PATTERN = /@\w+\(.*\)/;
|
7
8
|
classes = [];
|
8
9
|
interfaces = [];
|
9
10
|
enums = [];
|
@@ -23,26 +24,80 @@ export class TypeScriptParser {
|
|
23
24
|
getPreviousLine(content, position) {
|
24
25
|
const beforePosition = content.substring(0, position);
|
25
26
|
const lineNumber = beforePosition.split('\n').length;
|
26
|
-
if (lineNumber >
|
27
|
+
if (lineNumber > 0) {
|
27
28
|
const lines = content.split('\n');
|
28
29
|
return lines[lineNumber - 2]; // -2 because array is 0-based and we want previous line
|
29
30
|
}
|
30
31
|
return undefined;
|
31
32
|
}
|
33
|
+
parseMetadata(body, line) {
|
34
|
+
const annotations = [];
|
35
|
+
const commments = [];
|
36
|
+
const ANNOTATION = TypeScriptParser.ANNOTATION_PATTERN;
|
37
|
+
let previousLine = this.getPreviousLine(body, body.indexOf(line));
|
38
|
+
while (previousLine && (!previousLine.match(TypeScriptParser.PROPERTY_PATTERN) || previousLine.match(ANNOTATION))) {
|
39
|
+
const annotation = previousLine.match(ANNOTATION) ? parseAnnotation(previousLine) : undefined;
|
40
|
+
if (annotation) {
|
41
|
+
if (previousLine.trimStart().startsWith('//')) {
|
42
|
+
annotation.comment = true;
|
43
|
+
}
|
44
|
+
annotations.push(annotation);
|
45
|
+
}
|
46
|
+
else {
|
47
|
+
const comment = this.getLineComment(previousLine);
|
48
|
+
if (comment) {
|
49
|
+
const annotation = comment.match(ANNOTATION) ? parseAnnotation(comment) : undefined;
|
50
|
+
if (annotation) {
|
51
|
+
annotation.comment = true;
|
52
|
+
annotations.push(annotation);
|
53
|
+
}
|
54
|
+
else {
|
55
|
+
commments.unshift(comment);
|
56
|
+
}
|
57
|
+
}
|
58
|
+
}
|
59
|
+
previousLine = this.getPreviousLine(body, body.indexOf(previousLine));
|
60
|
+
}
|
61
|
+
const lineComment = this.getLineComment(line);
|
62
|
+
if (lineComment) {
|
63
|
+
const annotation = lineComment.match(ANNOTATION) ? parseAnnotation(lineComment) : undefined;
|
64
|
+
if (annotation) {
|
65
|
+
annotation.comment = true;
|
66
|
+
annotations.push(annotation);
|
67
|
+
}
|
68
|
+
else {
|
69
|
+
commments.push(lineComment);
|
70
|
+
}
|
71
|
+
}
|
72
|
+
else if (line.match(ANNOTATION)) {
|
73
|
+
const annotation = parseAnnotation(line);
|
74
|
+
if (annotation) {
|
75
|
+
annotations.push(annotation);
|
76
|
+
}
|
77
|
+
}
|
78
|
+
return {
|
79
|
+
comment: commments.length ? commments.join('\n') : undefined,
|
80
|
+
annotations: annotations.length ? annotations : undefined,
|
81
|
+
};
|
82
|
+
}
|
32
83
|
parseClassProperties(classBody) {
|
33
84
|
const props = [];
|
34
85
|
const lines = this.cleanBody(classBody).split('\n');
|
35
86
|
lines.forEach((line, index) => {
|
36
87
|
if (line.trim().startsWith('//'))
|
37
88
|
return;
|
89
|
+
if (line.match(TypeScriptParser.ANNOTATION_PATTERN))
|
90
|
+
return;
|
38
91
|
const match = line.match(TypeScriptParser.PROPERTY_PATTERN);
|
39
92
|
if (match?.groups) {
|
40
93
|
const member = {
|
41
|
-
modifier: match.groups.modifier,
|
42
94
|
name: match.groups.name,
|
43
95
|
type: match.groups.type.trim(),
|
44
|
-
optional: match.groups.optional === '?' || undefined,
|
45
96
|
};
|
97
|
+
if (match.groups.modifier)
|
98
|
+
member.modifier = match.groups.modifier;
|
99
|
+
if (match.groups.optional === '?')
|
100
|
+
member.optional = true;
|
46
101
|
// empty for properties with inline objects `salaryRange: {min:number, max:number};`
|
47
102
|
if (!member.type) {
|
48
103
|
return;
|
@@ -56,49 +111,82 @@ export class TypeScriptParser {
|
|
56
111
|
member.optional = true;
|
57
112
|
}
|
58
113
|
}
|
59
|
-
const
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
previousLine = this.getPreviousLine(classBody, classBody.indexOf(previousLine));
|
66
|
-
}
|
67
|
-
const lineComment = this.getLineComment(line);
|
68
|
-
if (lineComment) {
|
69
|
-
commments.push(lineComment);
|
70
|
-
}
|
71
|
-
if (commments.length) {
|
72
|
-
member.comment = commments.join('\n');
|
73
|
-
}
|
114
|
+
const { comment, annotations } = this.parseMetadata(classBody, line);
|
115
|
+
if (comment)
|
116
|
+
member.comment = comment;
|
117
|
+
if (annotations)
|
118
|
+
member.annotations = annotations;
|
119
|
+
// console.log('member', { comment, annotations, line })
|
74
120
|
props.push(member);
|
75
121
|
}
|
76
122
|
});
|
77
123
|
return props;
|
78
124
|
}
|
125
|
+
getBlockBody(content, startIndex) {
|
126
|
+
const bodyStartPos = content.indexOf('{', startIndex);
|
127
|
+
// console.log('bodyStartPos', `<|${content.substring(bodyStartPos, bodyStartPos + 20)}|>`)
|
128
|
+
// Find the end of the body
|
129
|
+
let depth = 0;
|
130
|
+
let bodyEndPos = bodyStartPos;
|
131
|
+
for (let i = bodyStartPos; i < content.length; i++) {
|
132
|
+
if (content[i] === '{')
|
133
|
+
depth++;
|
134
|
+
if (content[i] === '}')
|
135
|
+
depth--;
|
136
|
+
if (depth === 0) {
|
137
|
+
bodyEndPos = i + 1;
|
138
|
+
break;
|
139
|
+
}
|
140
|
+
}
|
141
|
+
let body = content.substring(bodyStartPos + 1, bodyEndPos - 1);
|
142
|
+
return body;
|
143
|
+
}
|
79
144
|
parseInterfaces(content) {
|
80
145
|
let match;
|
81
146
|
while ((match = TypeScriptParser.INTERFACE_PATTERN.exec(content))) {
|
82
147
|
const previousLine = this.getPreviousLine(content, match.index);
|
83
|
-
this.
|
148
|
+
const body = this.getBlockBody(content, match.index);
|
149
|
+
const cls = {
|
84
150
|
name: match[1],
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
151
|
+
properties: this.parseClassProperties(body),
|
152
|
+
};
|
153
|
+
if (match[2]) {
|
154
|
+
cls.extends = match[2];
|
155
|
+
}
|
156
|
+
if (previousLine) {
|
157
|
+
const { comment, annotations } = this.parseMetadata(content, previousLine);
|
158
|
+
if (comment)
|
159
|
+
cls.comment = comment;
|
160
|
+
if (annotations)
|
161
|
+
cls.annotations = annotations;
|
162
|
+
}
|
163
|
+
this.interfaces.push(cls);
|
89
164
|
}
|
90
165
|
}
|
91
166
|
parseClasses(content) {
|
92
167
|
let match;
|
93
168
|
while ((match = TypeScriptParser.CLASS_PATTERN.exec(content))) {
|
94
169
|
const previousLine = this.getPreviousLine(content, match.index);
|
95
|
-
this.
|
170
|
+
const body = this.getBlockBody(content, match.index);
|
171
|
+
const cls = {
|
96
172
|
name: match[1],
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
}
|
173
|
+
properties: this.parseClassProperties(body),
|
174
|
+
};
|
175
|
+
if (match[2]) {
|
176
|
+
cls.extends = match[2];
|
177
|
+
}
|
178
|
+
const impls = match[3]?.split(',').map(i => i.trim());
|
179
|
+
if (impls) {
|
180
|
+
cls.implements = impls;
|
181
|
+
}
|
182
|
+
if (previousLine) {
|
183
|
+
const { comment, annotations } = this.parseMetadata(content, previousLine);
|
184
|
+
if (comment)
|
185
|
+
cls.comment = comment;
|
186
|
+
if (annotations)
|
187
|
+
cls.annotations = annotations;
|
188
|
+
}
|
189
|
+
this.classes.push(cls);
|
102
190
|
}
|
103
191
|
}
|
104
192
|
parseEnumMembers(enumBody) {
|
@@ -170,3 +258,75 @@ export class TypeScriptParser {
|
|
170
258
|
};
|
171
259
|
}
|
172
260
|
}
|
261
|
+
export function parseAnnotation(annotation) {
|
262
|
+
// Match @name and everything inside ()
|
263
|
+
const regex = /@(\w+)\s*\((.*)\)/;
|
264
|
+
const match = annotation.match(regex);
|
265
|
+
if (!match)
|
266
|
+
return null;
|
267
|
+
const [, name, paramsStr] = match;
|
268
|
+
try {
|
269
|
+
// Handle multiple arguments by splitting on commas outside quotes/braces
|
270
|
+
const rawArgs = splitArgs(paramsStr);
|
271
|
+
// Parse each argument
|
272
|
+
const parsedArgs = rawArgs.map(arg => {
|
273
|
+
if (arg.startsWith('{')) {
|
274
|
+
// Parse object literals
|
275
|
+
return (new Function(`return ${arg}`))();
|
276
|
+
}
|
277
|
+
else if (arg.startsWith('"') || arg.startsWith("'") || arg.startsWith("`")) {
|
278
|
+
// Parse strings
|
279
|
+
return arg.slice(1, -1);
|
280
|
+
}
|
281
|
+
else if (!isNaN(parseInt(arg))) {
|
282
|
+
// Parse numbers
|
283
|
+
return Number(arg);
|
284
|
+
}
|
285
|
+
return arg;
|
286
|
+
});
|
287
|
+
const lastArg = parsedArgs[parsedArgs.length - 1];
|
288
|
+
const args = typeof lastArg === 'object'
|
289
|
+
? lastArg
|
290
|
+
: undefined;
|
291
|
+
const constructorArgs = args ? parsedArgs.slice(0, -1) : parsedArgs;
|
292
|
+
const to = { name };
|
293
|
+
if (constructorArgs.length)
|
294
|
+
to.constructorArgs = constructorArgs;
|
295
|
+
if (args)
|
296
|
+
to.args = args;
|
297
|
+
return to;
|
298
|
+
}
|
299
|
+
catch (e) {
|
300
|
+
return null;
|
301
|
+
}
|
302
|
+
}
|
303
|
+
// Helper to split args while respecting objects/strings
|
304
|
+
function splitArgs(str) {
|
305
|
+
const args = [];
|
306
|
+
let current = '';
|
307
|
+
let depth = 0;
|
308
|
+
let inQuotes = false;
|
309
|
+
let quoteChar = '';
|
310
|
+
for (let char of str) {
|
311
|
+
if ((char === '"' || char === "'") && !inQuotes) {
|
312
|
+
inQuotes = true;
|
313
|
+
quoteChar = char;
|
314
|
+
}
|
315
|
+
else if (char === quoteChar && inQuotes) {
|
316
|
+
inQuotes = false;
|
317
|
+
}
|
318
|
+
else if (char === '{')
|
319
|
+
depth++;
|
320
|
+
else if (char === '}')
|
321
|
+
depth--;
|
322
|
+
else if (char === ',' && depth === 0 && !inQuotes) {
|
323
|
+
args.push(current.trim());
|
324
|
+
current = '';
|
325
|
+
continue;
|
326
|
+
}
|
327
|
+
current += char;
|
328
|
+
}
|
329
|
+
if (current.trim())
|
330
|
+
args.push(current.trim());
|
331
|
+
return args;
|
332
|
+
}
|
package/dist/tsd-gen.js
CHANGED
@@ -8,21 +8,50 @@ export class TsdGenerator {
|
|
8
8
|
name: ast.name,
|
9
9
|
extends: ast.extends,
|
10
10
|
comment: ast.comment,
|
11
|
-
properties: ast.properties
|
11
|
+
properties: ast.properties,
|
12
|
+
annotations: ast.annotations,
|
12
13
|
};
|
13
14
|
return to;
|
14
15
|
}
|
16
|
+
attrValue(type, value) {
|
17
|
+
return type === 'string' ? `"${value}"` : value;
|
18
|
+
}
|
19
|
+
toAttr(attr) {
|
20
|
+
const sbArgs = [];
|
21
|
+
if (attr?.constructorArgs?.length) {
|
22
|
+
for (const arg of attr.constructorArgs) {
|
23
|
+
sbArgs.push(this.attrValue(typeof arg, arg));
|
24
|
+
}
|
25
|
+
}
|
26
|
+
if (attr.args) {
|
27
|
+
for (const [name, value] of Object.entries(attr.args)) {
|
28
|
+
sbArgs.push(`${name}=${this.attrValue(typeof value, value)}`);
|
29
|
+
}
|
30
|
+
}
|
31
|
+
const prefix = attr.comment ? '// ' : '';
|
32
|
+
return `${prefix}@${attr.name}(${sbArgs.join(',')})`;
|
33
|
+
}
|
15
34
|
toInterface(ast) {
|
16
35
|
const sb = [];
|
17
36
|
if (ast.comment) {
|
18
37
|
sb.push(ast.comment.split('\n').map(x => `// ${x}`).join('\n'));
|
19
38
|
}
|
39
|
+
if (ast.annotations?.length) {
|
40
|
+
for (const attr of ast.annotations) {
|
41
|
+
sb.push(this.toAttr(attr));
|
42
|
+
}
|
43
|
+
}
|
20
44
|
const extend = ast.extends ? ` extends ${ast.extends}` : '';
|
21
45
|
sb.push(`export interface ${ast.name}${extend} {`);
|
22
46
|
for (const prop of ast.properties) {
|
23
47
|
if (prop.comment) {
|
24
48
|
sb.push(prop.comment.split('\n').map(x => ` // ${x}`).join('\n'));
|
25
49
|
}
|
50
|
+
if (prop.annotations?.length) {
|
51
|
+
for (const attr of prop.annotations) {
|
52
|
+
sb.push(' ' + this.toAttr(attr));
|
53
|
+
}
|
54
|
+
}
|
26
55
|
sb.push(` ${prop.name}${prop.optional ? '?' : ''}: ${prop.type}`);
|
27
56
|
}
|
28
57
|
sb.push('}');
|