@openwebf/webf 0.23.10 → 0.24.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/dist/commands.js +135 -7
- package/dist/generator.js +37 -36
- package/dist/module.js +43 -14
- package/dist/peerDeps.js +27 -0
- package/dist/react.js +10 -18
- package/dist/vue.js +138 -132
- package/package.json +1 -1
- package/src/commands.ts +153 -7
- package/src/generator.ts +38 -37
- package/src/module.ts +53 -21
- package/src/peerDeps.ts +21 -0
- package/src/react.ts +10 -18
- package/src/vue.ts +157 -142
- package/templates/react.component.tsx.tpl +2 -2
- package/templates/react.index.ts.tpl +2 -1
- package/templates/react.package.json.tpl +4 -5
- package/templates/react.tsconfig.json.tpl +8 -1
- package/templates/react.tsup.config.ts.tpl +1 -1
- package/templates/vue.component.partial.tpl +4 -4
- package/templates/vue.components.d.ts.tpl +24 -9
- package/templates/vue.package.json.tpl +4 -2
- package/test/commands.test.ts +77 -12
- package/test/generator.test.ts +17 -10
- package/test/peerDeps.test.ts +30 -0
- package/test/react-consts.test.ts +9 -3
- package/test/standard-props.test.ts +14 -14
- package/test/templates.test.ts +17 -0
- package/test/vue.test.ts +36 -11
- package/dist/constants.js +0 -242
package/src/module.ts
CHANGED
|
@@ -335,14 +335,14 @@ function mapTsParamTypeToDart(
|
|
|
335
335
|
return { dartType: 'dynamic', isByteData: false };
|
|
336
336
|
}
|
|
337
337
|
|
|
338
|
-
function mapTsPropertyTypeToDart(type: ts.TypeNode): string {
|
|
338
|
+
function mapTsPropertyTypeToDart(type: ts.TypeNode, optional: boolean): string {
|
|
339
339
|
switch (type.kind) {
|
|
340
340
|
case ts.SyntaxKind.StringKeyword:
|
|
341
|
-
return 'String?';
|
|
341
|
+
return optional ? 'String?' : 'String';
|
|
342
342
|
case ts.SyntaxKind.NumberKeyword:
|
|
343
|
-
return 'num?';
|
|
343
|
+
return optional ? 'num?' : 'num';
|
|
344
344
|
case ts.SyntaxKind.BooleanKeyword:
|
|
345
|
-
return 'bool?';
|
|
345
|
+
return optional ? 'bool?' : 'bool';
|
|
346
346
|
default:
|
|
347
347
|
return 'dynamic';
|
|
348
348
|
}
|
|
@@ -380,16 +380,17 @@ function buildDartBindings(def: ModuleDefinition, command: string): string {
|
|
|
380
380
|
|
|
381
381
|
for (const iface of optionInterfaces) {
|
|
382
382
|
const name = iface.name.text;
|
|
383
|
-
const propInfos: { fieldName: string; key: string; dartType: string }[] = [];
|
|
383
|
+
const propInfos: { fieldName: string; key: string; dartType: string; optional: boolean }[] = [];
|
|
384
384
|
|
|
385
385
|
for (const member of iface.members) {
|
|
386
386
|
if (!ts.isPropertySignature(member) || !member.name) continue;
|
|
387
387
|
|
|
388
388
|
const key = member.name.getText(def.sourceFile).replace(/['"]/g, '');
|
|
389
389
|
const fieldName = key;
|
|
390
|
-
const
|
|
390
|
+
const optional = !!member.questionToken;
|
|
391
|
+
const dartType = member.type ? mapTsPropertyTypeToDart(member.type, optional) : 'dynamic';
|
|
391
392
|
|
|
392
|
-
propInfos.push({ fieldName, key, dartType });
|
|
393
|
+
propInfos.push({ fieldName, key, dartType, optional });
|
|
393
394
|
}
|
|
394
395
|
|
|
395
396
|
lines.push(`class ${name} {`);
|
|
@@ -398,23 +399,50 @@ function buildDartBindings(def: ModuleDefinition, command: string): string {
|
|
|
398
399
|
}
|
|
399
400
|
lines.push('');
|
|
400
401
|
|
|
401
|
-
const ctorParams = propInfos.map(p =>
|
|
402
|
+
const ctorParams = propInfos.map(p => {
|
|
403
|
+
if (p.optional || p.dartType === 'dynamic') {
|
|
404
|
+
return `this.${p.fieldName}`;
|
|
405
|
+
}
|
|
406
|
+
return `required this.${p.fieldName}`;
|
|
407
|
+
}).join(', ');
|
|
402
408
|
lines.push(` const ${name}({${ctorParams}});`);
|
|
403
409
|
lines.push('');
|
|
404
410
|
|
|
405
411
|
lines.push(` factory ${name}.fromMap(Map<String, dynamic> map) {`);
|
|
406
412
|
lines.push(` return ${name}(`);
|
|
407
413
|
for (const prop of propInfos) {
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
)
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
414
|
+
const isString = prop.dartType.startsWith('String');
|
|
415
|
+
const isBool = prop.dartType.startsWith('bool');
|
|
416
|
+
const isNum = prop.dartType.startsWith('num');
|
|
417
|
+
|
|
418
|
+
if (isString) {
|
|
419
|
+
if (prop.optional) {
|
|
420
|
+
lines.push(` ${prop.fieldName}: map['${prop.key}']?.toString(),`);
|
|
421
|
+
} else {
|
|
422
|
+
lines.push(
|
|
423
|
+
` ${prop.fieldName}: map['${prop.key}']?.toString() ?? '',`
|
|
424
|
+
);
|
|
425
|
+
}
|
|
426
|
+
} else if (isBool) {
|
|
427
|
+
if (prop.optional) {
|
|
428
|
+
lines.push(
|
|
429
|
+
` ${prop.fieldName}: map['${prop.key}'] is bool ? map['${prop.key}'] as bool : null,`
|
|
430
|
+
);
|
|
431
|
+
} else {
|
|
432
|
+
lines.push(
|
|
433
|
+
` ${prop.fieldName}: map['${prop.key}'] is bool ? map['${prop.key}'] as bool : false,`
|
|
434
|
+
);
|
|
435
|
+
}
|
|
436
|
+
} else if (isNum) {
|
|
437
|
+
if (prop.optional) {
|
|
438
|
+
lines.push(
|
|
439
|
+
` ${prop.fieldName}: map['${prop.key}'] is num ? map['${prop.key}'] as num : null,`
|
|
440
|
+
);
|
|
441
|
+
} else {
|
|
442
|
+
lines.push(
|
|
443
|
+
` ${prop.fieldName}: map['${prop.key}'] is num ? map['${prop.key}'] as num : 0,`
|
|
444
|
+
);
|
|
445
|
+
}
|
|
418
446
|
} else {
|
|
419
447
|
lines.push(` ${prop.fieldName}: map['${prop.key}'],`);
|
|
420
448
|
}
|
|
@@ -426,9 +454,13 @@ function buildDartBindings(def: ModuleDefinition, command: string): string {
|
|
|
426
454
|
lines.push(' Map<String, dynamic> toMap() {');
|
|
427
455
|
lines.push(' final map = <String, dynamic>{};');
|
|
428
456
|
for (const prop of propInfos) {
|
|
429
|
-
|
|
430
|
-
`
|
|
431
|
-
|
|
457
|
+
if (!prop.optional && (prop.dartType === 'String' || prop.dartType === 'bool' || prop.dartType === 'num')) {
|
|
458
|
+
lines.push(` map['${prop.key}'] = ${prop.fieldName};`);
|
|
459
|
+
} else {
|
|
460
|
+
lines.push(
|
|
461
|
+
` if (${prop.fieldName} != null) { map['${prop.key}'] = ${prop.fieldName}; }`
|
|
462
|
+
);
|
|
463
|
+
}
|
|
432
464
|
}
|
|
433
465
|
lines.push(' return map;');
|
|
434
466
|
lines.push(' }');
|
package/src/peerDeps.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
|
|
4
|
+
export function readJsonFile(jsonPath: string): any {
|
|
5
|
+
return JSON.parse(fs.readFileSync(jsonPath, 'utf-8'));
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function getPackageTypesFileFromDir(pkgDir: string): string | null {
|
|
9
|
+
const pkgJsonPath = path.join(pkgDir, 'package.json');
|
|
10
|
+
if (!fs.existsSync(pkgJsonPath)) return null;
|
|
11
|
+
const pkgJson = readJsonFile(pkgJsonPath);
|
|
12
|
+
const typesRel: string | undefined = pkgJson.types;
|
|
13
|
+
if (!typesRel) return null;
|
|
14
|
+
return path.join(pkgDir, typesRel);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function isPackageTypesReady(pkgDir: string): boolean {
|
|
18
|
+
const typesFile = getPackageTypesFileFromDir(pkgDir);
|
|
19
|
+
return typesFile ? fs.existsSync(typesFile) : true;
|
|
20
|
+
}
|
|
21
|
+
|
package/src/react.ts
CHANGED
|
@@ -52,13 +52,12 @@ function generateReturnType(type: ParameterType): string {
|
|
|
52
52
|
return pointerType;
|
|
53
53
|
}
|
|
54
54
|
if (type.isArray && typeof type.value === 'object' && !Array.isArray(type.value)) {
|
|
55
|
-
const elemType =
|
|
56
|
-
|
|
57
|
-
if (elemType
|
|
58
|
-
|
|
59
|
-
return `(${elemType})[]`;
|
|
55
|
+
const elemType = generateReturnType(type.value);
|
|
56
|
+
if (!elemType) return 'any[]';
|
|
57
|
+
if (/^[A-Za-z_][A-Za-z0-9_]*(?:\\.[A-Za-z_][A-Za-z0-9_]*)*$/.test(elemType)) {
|
|
58
|
+
return `${elemType}[]`;
|
|
60
59
|
}
|
|
61
|
-
return
|
|
60
|
+
return `(${elemType})[]`;
|
|
62
61
|
}
|
|
63
62
|
switch (type.value) {
|
|
64
63
|
case FunctionArgumentType.int:
|
|
@@ -387,19 +386,12 @@ export function generateReactComponent(blob: IDLBlob, packageName?: string, rela
|
|
|
387
386
|
return pointerType;
|
|
388
387
|
}
|
|
389
388
|
if (type.isArray && typeof type.value === 'object' && !Array.isArray(type.value)) {
|
|
390
|
-
const elemType =
|
|
391
|
-
if (elemType
|
|
392
|
-
if (
|
|
393
|
-
|
|
394
|
-
return `(typeof __webfTypes.${ident})[]`;
|
|
395
|
-
}
|
|
396
|
-
if (typeof elemType === 'string' && /^(?:[A-Za-z_][A-Za-z0-9_]*)(?:\.[A-Za-z_][A-Za-z0-9_]*)*$/.test(elemType)) {
|
|
397
|
-
const base = elemType.split('.')[0];
|
|
398
|
-
if (!localTypeNames.has(base)) {
|
|
399
|
-
return `__webfTypes.${elemType}[]`;
|
|
400
|
-
}
|
|
389
|
+
const elemType = genRT(type.value);
|
|
390
|
+
if (!elemType) return 'any[]';
|
|
391
|
+
if (/^[A-Za-z_][A-Za-z0-9_]*(?:\\.[A-Za-z_][A-Za-z0-9_]*)*$/.test(elemType)) {
|
|
392
|
+
return `${elemType}[]`;
|
|
401
393
|
}
|
|
402
|
-
return
|
|
394
|
+
return `(${elemType})[]`;
|
|
403
395
|
}
|
|
404
396
|
switch (type.value) {
|
|
405
397
|
case FunctionArgumentType.int:
|
package/src/vue.ts
CHANGED
|
@@ -2,10 +2,9 @@ import _ from "lodash";
|
|
|
2
2
|
import fs from 'fs';
|
|
3
3
|
import path from 'path';
|
|
4
4
|
import {ParameterType} from "./analyzer";
|
|
5
|
-
import {ClassObject, FunctionArgumentType, FunctionDeclaration, ConstObject, EnumObject} from "./declaration";
|
|
5
|
+
import {ClassObject, FunctionArgumentType, FunctionDeclaration, ConstObject, EnumObject, TypeAliasObject} from "./declaration";
|
|
6
6
|
import {IDLBlob} from "./IDLBlob";
|
|
7
|
-
import {
|
|
8
|
-
import {getPointerType, isPointerType, isUnionType, trimNullTypeFromType} from "./utils";
|
|
7
|
+
import {getPointerType, isPointerType, isUnionType} from "./utils";
|
|
9
8
|
|
|
10
9
|
function readTemplate(name: string) {
|
|
11
10
|
return fs.readFileSync(path.join(__dirname, '../templates/' + name + '.tpl'), {encoding: 'utf-8'});
|
|
@@ -49,18 +48,17 @@ function generateReturnType(type: ParameterType): string {
|
|
|
49
48
|
if (pointerType === 'Type') return 'any';
|
|
50
49
|
if (typeof pointerType === 'string' && pointerType.startsWith('typeof ')) {
|
|
51
50
|
const ident = pointerType.substring('typeof '.length).trim();
|
|
52
|
-
return `typeof
|
|
51
|
+
return `typeof ${ident}`;
|
|
53
52
|
}
|
|
54
53
|
return pointerType;
|
|
55
54
|
}
|
|
56
55
|
if (type.isArray && typeof type.value === 'object' && !Array.isArray(type.value)) {
|
|
57
|
-
const elemType =
|
|
58
|
-
if (elemType
|
|
59
|
-
if (
|
|
60
|
-
|
|
61
|
-
return `(typeof __webfTypes.${ident})[]`;
|
|
56
|
+
const elemType = generateReturnType(type.value);
|
|
57
|
+
if (!elemType) return 'any[]';
|
|
58
|
+
if (/^[A-Za-z_][A-Za-z0-9_]*(?:\\.[A-Za-z_][A-Za-z0-9_]*)*$/.test(elemType)) {
|
|
59
|
+
return `${elemType}[]`;
|
|
62
60
|
}
|
|
63
|
-
return
|
|
61
|
+
return `(${elemType})[]`;
|
|
64
62
|
}
|
|
65
63
|
switch (type.value) {
|
|
66
64
|
case FunctionArgumentType.int:
|
|
@@ -112,148 +110,139 @@ function generateMethodDeclaration(method: FunctionDeclaration) {
|
|
|
112
110
|
return `${methodName}(${args}): ${returnType};`;
|
|
113
111
|
}
|
|
114
112
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
}
|
|
122
|
-
const classObjectDictionary = Object.fromEntries(
|
|
123
|
-
classObjects.map(object => {
|
|
124
|
-
return [object.name, object];
|
|
125
|
-
})
|
|
126
|
-
);
|
|
113
|
+
type VueComponentSpec = {
|
|
114
|
+
className: string;
|
|
115
|
+
properties?: ClassObject;
|
|
116
|
+
events?: ClassObject;
|
|
117
|
+
methods?: ClassObject;
|
|
118
|
+
};
|
|
127
119
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
const events = classObjects.filter(object => {
|
|
132
|
-
return object.name.endsWith('Events');
|
|
133
|
-
});
|
|
120
|
+
function getVueComponentSpecs(blob: IDLBlob): VueComponentSpec[] {
|
|
121
|
+
const classObjects = blob.objects.filter(obj => obj instanceof ClassObject) as ClassObject[];
|
|
122
|
+
if (classObjects.length === 0) return [];
|
|
134
123
|
|
|
135
|
-
const
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
});
|
|
124
|
+
const properties = classObjects.filter(object => object.name.endsWith('Properties'));
|
|
125
|
+
const events = classObjects.filter(object => object.name.endsWith('Events'));
|
|
126
|
+
const methods = classObjects.filter(object => object.name.endsWith('Methods'));
|
|
139
127
|
|
|
140
|
-
const
|
|
141
|
-
if (!object || !object.props || object.props.length === 0) {
|
|
142
|
-
return '';
|
|
143
|
-
}
|
|
128
|
+
const componentMap = new Map<string, VueComponentSpec>();
|
|
144
129
|
|
|
145
|
-
|
|
130
|
+
properties.forEach(prop => {
|
|
131
|
+
const className = prop.name.replace(/Properties$/, '');
|
|
132
|
+
if (!componentMap.has(className)) componentMap.set(className, { className });
|
|
133
|
+
componentMap.get(className)!.properties = prop;
|
|
134
|
+
});
|
|
146
135
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
interfaceLines.push(' */');
|
|
153
|
-
}
|
|
136
|
+
events.forEach(ev => {
|
|
137
|
+
const className = ev.name.replace(/Events$/, '');
|
|
138
|
+
if (!componentMap.has(className)) componentMap.set(className, { className });
|
|
139
|
+
componentMap.get(className)!.events = ev;
|
|
140
|
+
});
|
|
154
141
|
|
|
155
|
-
|
|
142
|
+
methods.forEach(m => {
|
|
143
|
+
const className = m.name.replace(/Methods$/, '');
|
|
144
|
+
if (!componentMap.has(className)) componentMap.set(className, { className });
|
|
145
|
+
componentMap.get(className)!.methods = m;
|
|
146
|
+
});
|
|
156
147
|
|
|
157
|
-
|
|
158
|
-
|
|
148
|
+
return Array.from(componentMap.values())
|
|
149
|
+
.filter(spec => spec.className.trim().length > 0)
|
|
150
|
+
.sort((a, b) => a.className.localeCompare(b.className));
|
|
151
|
+
}
|
|
159
152
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
}
|
|
153
|
+
function renderSupportingInterface(object: ClassObject): string {
|
|
154
|
+
const hasProps = !!object.props && object.props.length > 0;
|
|
155
|
+
const hasMethods = !!object.methods && object.methods.length > 0;
|
|
156
|
+
if (!hasProps && !hasMethods) {
|
|
157
|
+
return '';
|
|
158
|
+
}
|
|
167
159
|
|
|
168
|
-
|
|
169
|
-
lines.push(` ${prop.name}${optionalToken}: ${generateReturnType(prop.type)};`);
|
|
160
|
+
const interfaceLines: string[] = [];
|
|
170
161
|
|
|
171
|
-
|
|
162
|
+
if (object.documentation && object.documentation.trim().length > 0) {
|
|
163
|
+
interfaceLines.push('/**');
|
|
164
|
+
object.documentation.split('\n').forEach(line => {
|
|
165
|
+
interfaceLines.push(` * ${line}`);
|
|
172
166
|
});
|
|
167
|
+
interfaceLines.push(' */');
|
|
168
|
+
}
|
|
173
169
|
|
|
174
|
-
|
|
175
|
-
interfaceLines.push('}');
|
|
170
|
+
interfaceLines.push(`export interface ${object.name} {`);
|
|
176
171
|
|
|
177
|
-
|
|
178
|
-
|
|
172
|
+
const propLines = (object.props || []).map(prop => {
|
|
173
|
+
const lines: string[] = [];
|
|
179
174
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
if (componentEvents) {
|
|
187
|
-
return componentEvents.name.replace(/Events$/, '');
|
|
175
|
+
if (prop.documentation && prop.documentation.trim().length > 0) {
|
|
176
|
+
lines.push(' /**');
|
|
177
|
+
prop.documentation.split('\n').forEach(line => {
|
|
178
|
+
lines.push(` * ${line}`);
|
|
179
|
+
});
|
|
180
|
+
lines.push(' */');
|
|
188
181
|
}
|
|
189
|
-
return '';
|
|
190
|
-
})();
|
|
191
182
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
}
|
|
183
|
+
const optionalToken = prop.optional ? '?' : '';
|
|
184
|
+
lines.push(` ${prop.name}${optionalToken}: ${generateReturnType(prop.type)};`);
|
|
195
185
|
|
|
196
|
-
|
|
197
|
-
className: className,
|
|
198
|
-
properties: componentProperties,
|
|
199
|
-
events: componentEvents,
|
|
200
|
-
classObjectDictionary,
|
|
201
|
-
dependencies,
|
|
202
|
-
blob,
|
|
203
|
-
generateReturnType,
|
|
204
|
-
generateMethodDeclaration,
|
|
205
|
-
generateEventHandlerType,
|
|
186
|
+
return lines.join('\n');
|
|
206
187
|
});
|
|
207
188
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
189
|
+
interfaceLines.push(propLines.join('\n'));
|
|
190
|
+
|
|
191
|
+
if (object.methods && object.methods.length > 0) {
|
|
192
|
+
const methodLines = object.methods.map(method => {
|
|
193
|
+
return ` ${generateMethodDeclaration(method)}`;
|
|
194
|
+
});
|
|
195
|
+
interfaceLines.push(methodLines.join('\n'));
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
interfaceLines.push('}');
|
|
211
199
|
|
|
212
|
-
return
|
|
200
|
+
return interfaceLines.join('\n');
|
|
213
201
|
}
|
|
214
202
|
|
|
215
|
-
function toVueTagName(
|
|
203
|
+
function toVueTagName(rawClassName: string): string {
|
|
204
|
+
const className = rawClassName.trim();
|
|
205
|
+
|
|
216
206
|
if (className.startsWith('WebF')) {
|
|
217
207
|
const withoutPrefix = className.substring(4);
|
|
218
|
-
|
|
219
|
-
|
|
208
|
+
const suffix = _.kebabCase(withoutPrefix);
|
|
209
|
+
return suffix.length > 0 ? 'webf-' + suffix : 'webf';
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
if (className.startsWith('Flutter')) {
|
|
220
213
|
const withoutPrefix = className.substring(7);
|
|
221
|
-
|
|
214
|
+
const suffix = _.kebabCase(withoutPrefix);
|
|
215
|
+
return suffix.length > 0 ? 'flutter-' + suffix : 'flutter';
|
|
222
216
|
}
|
|
223
|
-
|
|
217
|
+
|
|
218
|
+
const kebab = _.kebabCase(className);
|
|
219
|
+
return kebab.replace(/^web-f-/, 'webf-');
|
|
224
220
|
}
|
|
225
221
|
|
|
226
222
|
export function generateVueTypings(blobs: IDLBlob[]) {
|
|
227
|
-
const
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
223
|
+
const componentSpecMap = new Map<string, VueComponentSpec>();
|
|
224
|
+
blobs
|
|
225
|
+
.flatMap(blob => getVueComponentSpecs(blob))
|
|
226
|
+
.forEach(spec => {
|
|
227
|
+
if (!componentSpecMap.has(spec.className)) componentSpecMap.set(spec.className, spec);
|
|
232
228
|
});
|
|
233
|
-
|
|
234
|
-
|
|
229
|
+
|
|
230
|
+
const componentSpecs = Array.from(componentSpecMap.values()).sort((a, b) => a.className.localeCompare(b.className));
|
|
231
|
+
const componentNames = componentSpecs.map(spec => spec.className);
|
|
232
|
+
|
|
233
|
+
const components = componentSpecs.map(spec => {
|
|
234
|
+
const content = _.template(readTemplate('vue.component.partial'))({
|
|
235
|
+
className: spec.className,
|
|
236
|
+
properties: spec.properties,
|
|
237
|
+
events: spec.events,
|
|
238
|
+
methods: spec.methods,
|
|
239
|
+
generateReturnType,
|
|
240
|
+
generateMethodDeclaration,
|
|
241
|
+
generateEventHandlerType,
|
|
235
242
|
});
|
|
236
243
|
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
const className = (() => {
|
|
240
|
-
if (componentProperties) {
|
|
241
|
-
return componentProperties.name.replace(/Properties$/, '');
|
|
242
|
-
}
|
|
243
|
-
if (componentEvents) {
|
|
244
|
-
return componentEvents.name.replace(/Events$/, '');
|
|
245
|
-
}
|
|
246
|
-
return '';
|
|
247
|
-
})();
|
|
248
|
-
return className;
|
|
249
|
-
}).filter(name => {
|
|
250
|
-
return name.length > 0;
|
|
251
|
-
});
|
|
252
|
-
const components = blobs.map(blob => {
|
|
253
|
-
return generateVueComponent(blob);
|
|
254
|
-
}).filter(component => {
|
|
255
|
-
return component.length > 0;
|
|
256
|
-
}).join('\n\n');
|
|
244
|
+
return content.split('\n').filter(str => str.trim().length > 0).join('\n');
|
|
245
|
+
}).filter(Boolean).join('\n\n');
|
|
257
246
|
|
|
258
247
|
// Collect declare consts across blobs and render as exported ambient declarations
|
|
259
248
|
const consts = blobs
|
|
@@ -267,6 +256,7 @@ export function generateVueTypings(blobs: IDLBlob[]) {
|
|
|
267
256
|
});
|
|
268
257
|
|
|
269
258
|
const constDeclarations = Array.from(uniqueConsts.values())
|
|
259
|
+
.sort((a, b) => a.name.localeCompare(b.name))
|
|
270
260
|
.map(c => `export declare const ${c.name}: ${c.type};`)
|
|
271
261
|
.join('\n');
|
|
272
262
|
|
|
@@ -275,29 +265,53 @@ export function generateVueTypings(blobs: IDLBlob[]) {
|
|
|
275
265
|
.flatMap(blob => blob.objects)
|
|
276
266
|
.filter(obj => obj instanceof EnumObject) as EnumObject[];
|
|
277
267
|
|
|
278
|
-
const
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
})
|
|
268
|
+
const uniqueEnums = new Map<string, EnumObject>();
|
|
269
|
+
enums.forEach(e => {
|
|
270
|
+
if (!uniqueEnums.has(e.name)) uniqueEnums.set(e.name, e);
|
|
271
|
+
});
|
|
282
272
|
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
273
|
+
const enumDeclarations = Array.from(uniqueEnums.values())
|
|
274
|
+
.sort((a, b) => a.name.localeCompare(b.name))
|
|
275
|
+
.map(e => {
|
|
276
|
+
const members = e.members.map(m => m.initializer ? `${m.name} = ${m.initializer}` : `${m.name}`).join(', ');
|
|
277
|
+
return `export declare enum ${e.name} { ${members} }`;
|
|
278
|
+
})
|
|
279
|
+
.join('\n');
|
|
280
|
+
|
|
281
|
+
// Collect type aliases across blobs and render as exported declarations.
|
|
282
|
+
const typeAliases = blobs
|
|
283
|
+
.flatMap(blob => blob.objects)
|
|
284
|
+
.filter(obj => obj instanceof TypeAliasObject) as TypeAliasObject[];
|
|
285
|
+
|
|
286
|
+
const uniqueTypeAliases = new Map<string, TypeAliasObject>();
|
|
287
|
+
typeAliases.forEach(t => {
|
|
288
|
+
if (!uniqueTypeAliases.has(t.name)) uniqueTypeAliases.set(t.name, t);
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
const typeAliasDeclarations = Array.from(uniqueTypeAliases.values())
|
|
292
|
+
.sort((a, b) => a.name.localeCompare(b.name))
|
|
293
|
+
.map(t => `export type ${t.name} = ${t.type};`)
|
|
294
|
+
.join('\n');
|
|
295
|
+
|
|
296
|
+
// Collect supporting interfaces (non-component interfaces) so referenced types exist.
|
|
297
|
+
const supportingInterfaces = blobs
|
|
298
|
+
.flatMap(blob => blob.objects)
|
|
299
|
+
.filter(obj => obj instanceof ClassObject) as ClassObject[];
|
|
300
|
+
|
|
301
|
+
const supporting = supportingInterfaces.filter(obj => {
|
|
302
|
+
return !obj.name.endsWith('Properties') && !obj.name.endsWith('Events') && !obj.name.endsWith('Methods');
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
const uniqueSupporting = new Map<string, ClassObject>();
|
|
306
|
+
supporting.forEach(obj => {
|
|
307
|
+
if (!uniqueSupporting.has(obj.name)) uniqueSupporting.set(obj.name, obj);
|
|
308
|
+
});
|
|
297
309
|
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
310
|
+
const supportingDeclarations = Array.from(uniqueSupporting.values())
|
|
311
|
+
.sort((a, b) => a.name.localeCompare(b.name))
|
|
312
|
+
.map(obj => renderSupportingInterface(obj))
|
|
313
|
+
.filter(Boolean)
|
|
314
|
+
.join('\n\n');
|
|
301
315
|
|
|
302
316
|
// Build mapping of template tag names to class names for GlobalComponents
|
|
303
317
|
const componentMetas = componentNames.map(className => ({
|
|
@@ -315,7 +329,8 @@ export function generateVueTypings(blobs: IDLBlob[]) {
|
|
|
315
329
|
components,
|
|
316
330
|
consts: constDeclarations,
|
|
317
331
|
enums: enumDeclarations,
|
|
318
|
-
|
|
332
|
+
typeAliases: typeAliasDeclarations,
|
|
333
|
+
dependencies: supportingDeclarations,
|
|
319
334
|
});
|
|
320
335
|
|
|
321
336
|
return content.split('\n').filter(str => {
|
|
@@ -146,8 +146,8 @@ export const <%= className %> = createWebFComponent<<%= className %>Element, <%=
|
|
|
146
146
|
{
|
|
147
147
|
propName: '<%= propName %>',
|
|
148
148
|
eventName: '<%= prop.name %>',
|
|
149
|
-
handler: (callback) => (event) => {
|
|
150
|
-
callback(
|
|
149
|
+
handler: (callback: (event: <%= getEventType(prop.type) %>) => void) => (event: Event) => {
|
|
150
|
+
callback(event as <%= getEventType(prop.type) %>);
|
|
151
151
|
},
|
|
152
152
|
},
|
|
153
153
|
<% }); %>
|
|
@@ -3,5 +3,6 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
<% components.forEach(component => { %>
|
|
6
|
-
export { <%= component.className
|
|
6
|
+
export { <%= component.className %> } from "./<%= component.relativeDir ? component.relativeDir + '/' : '' %><%= component.fileName %>";
|
|
7
|
+
export type { <%= component.className %>Element } from "./<%= component.relativeDir ? component.relativeDir + '/' : '' %><%= component.fileName %>";
|
|
7
8
|
<% }); %>
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
8
|
-
"files": ["dist"],
|
|
8
|
+
"files": ["dist", "README.md"],
|
|
9
9
|
"scripts": {
|
|
10
10
|
"build": "tsup"
|
|
11
11
|
},
|
|
@@ -15,12 +15,11 @@
|
|
|
15
15
|
"type": "commonjs",
|
|
16
16
|
"peerDependencies": {
|
|
17
17
|
"react": ">=16.8.0",
|
|
18
|
-
"react-dom": ">=16.8.0"
|
|
19
|
-
|
|
20
|
-
"dependencies": {
|
|
21
|
-
"@openwebf/react-core-ui": "^0.2.1"
|
|
18
|
+
"react-dom": ">=16.8.0",
|
|
19
|
+
"@openwebf/react-core-ui": "^0.24.1"
|
|
22
20
|
},
|
|
23
21
|
"devDependencies": {
|
|
22
|
+
"@openwebf/react-core-ui": "^0.24.1",
|
|
24
23
|
"@types/react": "^19.1.0",
|
|
25
24
|
"@types/react-dom": "^19.1.2",
|
|
26
25
|
"picomatch": "^4.0.2",
|
|
@@ -10,7 +10,14 @@
|
|
|
10
10
|
"esModuleInterop": true,
|
|
11
11
|
"skipLibCheck": true,
|
|
12
12
|
"moduleResolution": "node",
|
|
13
|
-
"allowSyntheticDefaultImports": true
|
|
13
|
+
"allowSyntheticDefaultImports": true,
|
|
14
|
+
"baseUrl": ".",
|
|
15
|
+
"paths": {
|
|
16
|
+
"react": ["./node_modules/@types/react/index.d.ts"],
|
|
17
|
+
"react-dom": ["./node_modules/@types/react-dom/index.d.ts"],
|
|
18
|
+
"react/jsx-runtime": ["./node_modules/@types/react/jsx-runtime.d.ts"],
|
|
19
|
+
"react/jsx-dev-runtime": ["./node_modules/@types/react/jsx-dev-runtime.d.ts"]
|
|
20
|
+
}
|
|
14
21
|
},
|
|
15
22
|
"include": ["src"]
|
|
16
23
|
}
|