@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/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 dartType = member.type ? mapTsPropertyTypeToDart(member.type) : 'dynamic';
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 => `this.${p.fieldName}`).join(', ');
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
- if (prop.dartType.startsWith('String')) {
409
- lines.push(` ${prop.fieldName}: map['${prop.key}']?.toString(),`);
410
- } else if (prop.dartType.startsWith('bool')) {
411
- lines.push(
412
- ` ${prop.fieldName}: map['${prop.key}'] is bool ? map['${prop.key}'] as bool : null,`
413
- );
414
- } else if (prop.dartType.startsWith('num')) {
415
- lines.push(
416
- ` ${prop.fieldName}: map['${prop.key}'] is num ? map['${prop.key}'] as num : null,`
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
- lines.push(
430
- ` if (${prop.fieldName} != null) { map['${prop.key}'] = ${prop.fieldName}; }`
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(' }');
@@ -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 = getPointerType(type.value);
56
- // Map arrays of Dart `Type` to `any[]` in TS; parenthesize typeof
57
- if (elemType === 'Type') return 'any[]';
58
- if (typeof elemType === 'string' && elemType.startsWith('typeof ')) {
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 `${elemType}[]`;
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 = getPointerType(type.value);
391
- if (elemType === 'Type') return 'any[]';
392
- if (typeof elemType === 'string' && elemType.startsWith('typeof ')) {
393
- const ident = elemType.substring('typeof '.length).trim();
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 `${elemType}[]`;
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 { debug } from './logger';
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 __webfTypes.${ident}`;
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 = getPointerType(type.value);
58
- if (elemType === 'Type') return 'any[]';
59
- if (typeof elemType === 'string' && elemType.startsWith('typeof ')) {
60
- const ident = elemType.substring('typeof '.length).trim();
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 `${elemType}[]`;
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
- function generateVueComponent(blob: IDLBlob) {
116
- const classObjects = blob.objects as ClassObject[];
117
-
118
- // Skip if no class objects
119
- if (!classObjects || classObjects.length === 0) {
120
- return '';
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
- const properties = classObjects.filter(object => {
129
- return object.name.endsWith('Properties');
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 others = classObjects.filter(object => {
136
- return !object.name.endsWith('Properties')
137
- && !object.name.endsWith('Events');
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 dependencies = others.map(object => {
141
- if (!object || !object.props || object.props.length === 0) {
142
- return '';
143
- }
128
+ const componentMap = new Map<string, VueComponentSpec>();
144
129
 
145
- const interfaceLines: string[] = [];
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
- if (object.documentation && object.documentation.trim().length > 0) {
148
- interfaceLines.push('/**');
149
- object.documentation.split('\n').forEach(line => {
150
- interfaceLines.push(` * ${line}`);
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
- interfaceLines.push(`interface ${object.name} {`);
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
- const propLines = object.props.map(prop => {
158
- const lines: string[] = [];
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
- if (prop.documentation && prop.documentation.trim().length > 0) {
161
- lines.push(' /**');
162
- prop.documentation.split('\n').forEach(line => {
163
- lines.push(` * ${line}`);
164
- });
165
- lines.push(' */');
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
- const optionalToken = prop.optional ? '?' : '';
169
- lines.push(` ${prop.name}${optionalToken}: ${generateReturnType(prop.type)};`);
160
+ const interfaceLines: string[] = [];
170
161
 
171
- return lines.join('\n');
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
- interfaceLines.push(propLines.join('\n'));
175
- interfaceLines.push('}');
170
+ interfaceLines.push(`export interface ${object.name} {`);
176
171
 
177
- return interfaceLines.join('\n');
178
- }).filter(dep => dep.trim() !== '').join('\n\n');
172
+ const propLines = (object.props || []).map(prop => {
173
+ const lines: string[] = [];
179
174
 
180
- const componentProperties = properties.length > 0 ? properties[0] : undefined;
181
- const componentEvents = events.length > 0 ? events[0] : undefined;
182
- const className = (() => {
183
- if (componentProperties) {
184
- return componentProperties.name.replace(/Properties$/, '');
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
- if (!className) {
193
- return '';
194
- }
183
+ const optionalToken = prop.optional ? '?' : '';
184
+ lines.push(` ${prop.name}${optionalToken}: ${generateReturnType(prop.type)};`);
195
185
 
196
- const content = _.template(readTemplate('vue.component.partial'))({
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
- const result = content.split('\n').filter(str => {
209
- return str.trim().length > 0;
210
- }).join('\n');
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 result;
200
+ return interfaceLines.join('\n');
213
201
  }
214
202
 
215
- function toVueTagName(className: string): string {
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
- return 'web-f-' + _.kebabCase(withoutPrefix);
219
- } else if (className.startsWith('Flutter')) {
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
- return 'flutter-' + _.kebabCase(withoutPrefix);
214
+ const suffix = _.kebabCase(withoutPrefix);
215
+ return suffix.length > 0 ? 'flutter-' + suffix : 'flutter';
222
216
  }
223
- return _.kebabCase(className);
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 componentNames = blobs.map(blob => {
228
- const classObjects = blob.objects as ClassObject[];
229
-
230
- const properties = classObjects.filter(object => {
231
- return object.name.endsWith('Properties');
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
- const events = classObjects.filter(object => {
234
- return object.name.endsWith('Events');
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
- const componentProperties = properties.length > 0 ? properties[0] : undefined;
238
- const componentEvents = events.length > 0 ? events[0] : undefined;
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 enumDeclarations = enums.map(e => {
279
- const members = e.members.map(m => m.initializer ? `${m.name} = ${m.initializer}` : `${m.name}`).join(', ');
280
- return `export declare enum ${e.name} { ${members} }`;
281
- }).join('\n');
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
- // Compute relative import path from the generated typings file (index.d.ts at dist root)
284
- // to the aggregated React types module (src/types.ts) when present.
285
- let typesImportPath = './src/types';
286
- try {
287
- if (blobs.length > 0) {
288
- const distRoot = blobs[0].dist;
289
- const typingsDir = distRoot; // index.d.ts is written directly under distRoot
290
- const typesFilePath = path.join(distRoot, 'src', 'types');
291
- const rel = path.relative(typingsDir, typesFilePath).replace(/\\/g, '/');
292
- typesImportPath = rel.startsWith('.') ? rel : `./${rel}`;
293
- }
294
- } catch {
295
- typesImportPath = './src/types';
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
- // Always import the types namespace to support typeof references
299
- const typesImport = `import * as __webfTypes from '${typesImportPath}';`;
300
- debug(`[vue] Generating typings; importing types from ${typesImportPath}`);
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
- typesImport,
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((event as <%= getEventType(prop.type) %>));
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 %>, <%= component.className %>Element } from "./<%= component.relativeDir ? component.relativeDir + '/' : '' %><%= component.fileName %>";
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
  }
@@ -6,5 +6,5 @@ export default defineConfig({
6
6
  dts: true,
7
7
  sourcemap: true,
8
8
  clean: true,
9
- external: ['react', 'react-dom'],
9
+ external: ['react', 'react-dom', '@openwebf/react-core-ui'],
10
10
  })