@openwebf/webf 0.24.1 → 0.24.2

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/README.md CHANGED
@@ -150,7 +150,7 @@ my-webf-app/
150
150
  │ └── index.ts
151
151
  ├── package.json
152
152
  ├── tsconfig.json
153
- ├── tsup.config.ts
153
+ ├── tsdown.config.ts
154
154
  ├── global.d.ts
155
155
  └── .gitignore
156
156
  ```
package/dist/analyzer.js CHANGED
@@ -365,134 +365,196 @@ function handleGenericWrapper(typeReference, mode) {
365
365
  const argument = typeReference.typeArguments[0];
366
366
  return getParameterBaseType(argument, mode);
367
367
  }
368
- function handleCustomEventType(typeReference) {
369
- var _a;
370
- // Handle CustomEvent<T> by returning the full type with generic parameter
371
- if (!typeReference.typeArguments || !typeReference.typeArguments[0]) {
372
- return 'CustomEvent';
368
+ const customEventTypePrinter = typescript_1.default.createPrinter({ removeComments: true });
369
+ function mapTypeReferenceIdentifierToTsType(identifier) {
370
+ const mappedType = TYPE_REFERENCE_MAP[identifier];
371
+ if (mappedType === undefined)
372
+ return null;
373
+ switch (mappedType) {
374
+ case declaration_1.FunctionArgumentType.boolean:
375
+ return 'boolean';
376
+ case declaration_1.FunctionArgumentType.dom_string:
377
+ return 'string';
378
+ case declaration_1.FunctionArgumentType.double:
379
+ case declaration_1.FunctionArgumentType.int:
380
+ return 'number';
381
+ case declaration_1.FunctionArgumentType.any:
382
+ return 'any';
383
+ case declaration_1.FunctionArgumentType.void:
384
+ return 'void';
385
+ case declaration_1.FunctionArgumentType.function:
386
+ return 'Function';
387
+ case declaration_1.FunctionArgumentType.promise:
388
+ return 'Promise<any>';
389
+ default:
390
+ return null;
373
391
  }
374
- const argument = typeReference.typeArguments[0];
375
- let genericType;
376
- // Preserve simple union/compound generic types (e.g., boolean | null)
377
- if (typescript_1.default.isUnionTypeNode(argument) || typescript_1.default.isIntersectionTypeNode(argument)) {
378
- const unionTypes = (_a = argument.types) !== null && _a !== void 0 ? _a : [];
379
- const parts = unionTypes.map(t => {
380
- // Literal union members: handle null/undefined explicitly
381
- if (typescript_1.default.isLiteralTypeNode(t)) {
382
- const lit = t.literal;
383
- if (lit.kind === typescript_1.default.SyntaxKind.NullKeyword)
384
- return 'null';
385
- if (lit.kind === typescript_1.default.SyntaxKind.UndefinedKeyword)
386
- return 'undefined';
387
- if (typescript_1.default.isStringLiteral(lit))
388
- return JSON.stringify(lit.text);
389
- return 'any';
390
- }
391
- // Basic keywords: boolean, string, number, null, undefined
392
- const basic = BASIC_TYPE_MAP[t.kind];
393
- if (basic !== undefined) {
394
- switch (basic) {
395
- case declaration_1.FunctionArgumentType.boolean:
396
- return 'boolean';
397
- case declaration_1.FunctionArgumentType.dom_string:
398
- return 'string';
399
- case declaration_1.FunctionArgumentType.double:
400
- case declaration_1.FunctionArgumentType.int:
401
- return 'number';
402
- case declaration_1.FunctionArgumentType.null:
403
- return 'null';
404
- case declaration_1.FunctionArgumentType.undefined:
405
- return 'undefined';
406
- default:
407
- return 'any';
408
- }
409
- }
410
- // Literal null/undefined keywords that BASIC_TYPE_MAP may not cover
411
- if (t.kind === typescript_1.default.SyntaxKind.NullKeyword)
412
- return 'null';
413
- if (t.kind === typescript_1.default.SyntaxKind.UndefinedKeyword)
414
- return 'undefined';
415
- // Fallback: rely on toString of node kind
392
+ }
393
+ function getBasicTypeKindAsTsType(kind) {
394
+ const basicType = BASIC_TYPE_MAP[kind];
395
+ if (basicType === undefined)
396
+ return null;
397
+ switch (basicType) {
398
+ case declaration_1.FunctionArgumentType.boolean:
399
+ return 'boolean';
400
+ case declaration_1.FunctionArgumentType.dom_string:
401
+ return 'string';
402
+ case declaration_1.FunctionArgumentType.double:
403
+ case declaration_1.FunctionArgumentType.int:
404
+ return 'number';
405
+ case declaration_1.FunctionArgumentType.any:
416
406
  return 'any';
417
- });
418
- genericType = parts.join(' | ');
407
+ case declaration_1.FunctionArgumentType.void:
408
+ return 'void';
409
+ case declaration_1.FunctionArgumentType.null:
410
+ return 'null';
411
+ case declaration_1.FunctionArgumentType.undefined:
412
+ return 'undefined';
413
+ default:
414
+ return null;
419
415
  }
420
- else if (typescript_1.default.isTypeReferenceNode(argument) && typescript_1.default.isIdentifier(argument.typeName)) {
421
- const typeName = argument.typeName.text;
422
- // Check if it's a mapped type reference like 'int' or 'double'
423
- const mappedType = TYPE_REFERENCE_MAP[typeName];
424
- if (mappedType !== undefined) {
425
- switch (mappedType) {
426
- case declaration_1.FunctionArgumentType.boolean:
427
- genericType = 'boolean';
428
- break;
429
- case declaration_1.FunctionArgumentType.dom_string:
430
- genericType = 'string';
431
- break;
432
- case declaration_1.FunctionArgumentType.double:
433
- case declaration_1.FunctionArgumentType.int:
434
- genericType = 'number';
435
- break;
436
- case declaration_1.FunctionArgumentType.any:
437
- genericType = 'any';
438
- break;
439
- case declaration_1.FunctionArgumentType.void:
440
- genericType = 'void';
441
- break;
442
- case declaration_1.FunctionArgumentType.function:
443
- genericType = 'Function';
444
- break;
445
- case declaration_1.FunctionArgumentType.promise:
446
- genericType = 'Promise<any>';
447
- break;
448
- default:
449
- genericType = typeName;
416
+ }
417
+ function stringifyEntityName(name) {
418
+ if (typescript_1.default.isIdentifier(name))
419
+ return name.text;
420
+ return `${stringifyEntityName(name.left)}.${name.right.text}`;
421
+ }
422
+ function safePrintCustomEventNode(node) {
423
+ const sourceFile = node.getSourceFile();
424
+ const printed = customEventTypePrinter.printNode(typescript_1.default.EmitHint.Unspecified, node, sourceFile);
425
+ // Ensure WebF IDL-like aliases used in type definitions do not leak into generated TypeScript packages.
426
+ return printed.replace(/\bint\b/g, 'number').replace(/\bdouble\b/g, 'number');
427
+ }
428
+ function stringifyCustomEventGenericTypeNode(typeNode) {
429
+ if (typescript_1.default.isParenthesizedTypeNode(typeNode)) {
430
+ const inner = stringifyCustomEventGenericTypeNode(typeNode.type);
431
+ return inner ? `(${inner})` : null;
432
+ }
433
+ if (typescript_1.default.isUnionTypeNode(typeNode)) {
434
+ const parts = typeNode.types.map(t => stringifyCustomEventGenericTypeNode(t)).filter((t) => Boolean(t));
435
+ return parts.length === typeNode.types.length ? parts.join(' | ') : null;
436
+ }
437
+ if (typescript_1.default.isIntersectionTypeNode(typeNode)) {
438
+ const parts = typeNode.types.map(t => stringifyCustomEventGenericTypeNode(t)).filter((t) => Boolean(t));
439
+ return parts.length === typeNode.types.length ? parts.join(' & ') : null;
440
+ }
441
+ if (typescript_1.default.isArrayTypeNode(typeNode)) {
442
+ const element = stringifyCustomEventGenericTypeNode(typeNode.elementType);
443
+ return element ? `${element}[]` : null;
444
+ }
445
+ if (typescript_1.default.isTupleTypeNode(typeNode)) {
446
+ const elements = typeNode.elements.map(e => stringifyCustomEventGenericTypeNode(e)).filter((t) => Boolean(t));
447
+ return elements.length === typeNode.elements.length ? `[${elements.join(', ')}]` : null;
448
+ }
449
+ if (typescript_1.default.isLiteralTypeNode(typeNode)) {
450
+ const literal = typeNode.literal;
451
+ if (literal.kind === typescript_1.default.SyntaxKind.NullKeyword)
452
+ return 'null';
453
+ if (literal.kind === typescript_1.default.SyntaxKind.UndefinedKeyword)
454
+ return 'undefined';
455
+ if (literal.kind === typescript_1.default.SyntaxKind.TrueKeyword)
456
+ return 'true';
457
+ if (literal.kind === typescript_1.default.SyntaxKind.FalseKeyword)
458
+ return 'false';
459
+ if (typescript_1.default.isStringLiteral(literal))
460
+ return JSON.stringify(literal.text);
461
+ if (typescript_1.default.isNumericLiteral(literal))
462
+ return literal.text;
463
+ return null;
464
+ }
465
+ const basic = getBasicTypeKindAsTsType(typeNode.kind);
466
+ if (basic)
467
+ return basic;
468
+ if (typescript_1.default.isTypeReferenceNode(typeNode)) {
469
+ const typeName = stringifyEntityName(typeNode.typeName);
470
+ // Unwrap internal helpers used by WebF typings.
471
+ if (typeName === 'DartImpl' && typeNode.typeArguments && typeNode.typeArguments[0]) {
472
+ return stringifyCustomEventGenericTypeNode(typeNode.typeArguments[0]);
473
+ }
474
+ if (typeName === 'Promise') {
475
+ if (!typeNode.typeArguments || !typeNode.typeArguments[0])
476
+ return 'Promise<any>';
477
+ const inner = stringifyCustomEventGenericTypeNode(typeNode.typeArguments[0]);
478
+ return inner ? `Promise<${inner}>` : null;
479
+ }
480
+ const mapped = mapTypeReferenceIdentifierToTsType(typeName);
481
+ if (mapped)
482
+ return mapped;
483
+ if (!typeNode.typeArguments || typeNode.typeArguments.length === 0) {
484
+ return typeName;
485
+ }
486
+ const args = typeNode.typeArguments
487
+ .map(arg => stringifyCustomEventGenericTypeNode(arg))
488
+ .filter((t) => Boolean(t));
489
+ if (args.length !== typeNode.typeArguments.length)
490
+ return null;
491
+ return `${typeName}<${args.join(', ')}>`;
492
+ }
493
+ if (typescript_1.default.isTypeLiteralNode(typeNode)) {
494
+ const members = [];
495
+ for (const member of typeNode.members) {
496
+ if (typescript_1.default.isPropertySignature(member) && member.type) {
497
+ const typeString = stringifyCustomEventGenericTypeNode(member.type);
498
+ if (!typeString)
499
+ return null;
500
+ let nameText;
501
+ if (typescript_1.default.isIdentifier(member.name))
502
+ nameText = member.name.text;
503
+ else if (typescript_1.default.isStringLiteral(member.name))
504
+ nameText = JSON.stringify(member.name.text);
505
+ else if (typescript_1.default.isNumericLiteral(member.name))
506
+ nameText = member.name.text;
507
+ else
508
+ nameText = member.name.getText();
509
+ const optional = member.questionToken ? '?' : '';
510
+ members.push(`${nameText}${optional}: ${typeString}`);
511
+ continue;
450
512
  }
513
+ if (typescript_1.default.isIndexSignatureDeclaration(member) && member.type && member.parameters.length === 1) {
514
+ const param = member.parameters[0];
515
+ const paramName = typescript_1.default.isIdentifier(param.name) ? param.name.text : param.name.getText();
516
+ const paramType = param.type ? stringifyCustomEventGenericTypeNode(param.type) : 'string';
517
+ const valueType = stringifyCustomEventGenericTypeNode(member.type);
518
+ if (!paramType || !valueType)
519
+ return null;
520
+ members.push(`[${paramName}: ${paramType}]: ${valueType}`);
521
+ continue;
522
+ }
523
+ // Fallback for uncommon members (call signatures, method signatures, etc.).
524
+ members.push(safePrintCustomEventNode(member));
451
525
  }
452
- else {
453
- // For other type references, use the type name directly
454
- genericType = typeName;
455
- }
526
+ return `{ ${members.join('; ')} }`;
456
527
  }
457
- else if (typescript_1.default.isLiteralTypeNode(argument) && typescript_1.default.isStringLiteral(argument.literal)) {
458
- genericType = argument.literal.text;
528
+ if (typescript_1.default.isTypeOperatorNode(typeNode)) {
529
+ const inner = stringifyCustomEventGenericTypeNode(typeNode.type);
530
+ if (!inner)
531
+ return null;
532
+ const operator = typeNode.operator === typescript_1.default.SyntaxKind.KeyOfKeyword ? 'keyof' :
533
+ typeNode.operator === typescript_1.default.SyntaxKind.ReadonlyKeyword ? 'readonly' :
534
+ typeNode.operator === typescript_1.default.SyntaxKind.UniqueKeyword ? 'unique' :
535
+ null;
536
+ return operator ? `${operator} ${inner}` : null;
537
+ }
538
+ if (typescript_1.default.isIndexedAccessTypeNode(typeNode)) {
539
+ const objectType = stringifyCustomEventGenericTypeNode(typeNode.objectType);
540
+ const indexType = stringifyCustomEventGenericTypeNode(typeNode.indexType);
541
+ if (!objectType || !indexType)
542
+ return null;
543
+ return `${objectType}[${indexType}]`;
459
544
  }
460
- else {
461
- // Handle basic types (boolean, string, number, etc.)
462
- const basicType = BASIC_TYPE_MAP[argument.kind];
463
- if (basicType !== undefined) {
464
- switch (basicType) {
465
- case declaration_1.FunctionArgumentType.boolean:
466
- genericType = 'boolean';
467
- break;
468
- case declaration_1.FunctionArgumentType.dom_string:
469
- genericType = 'string';
470
- break;
471
- case declaration_1.FunctionArgumentType.double:
472
- case declaration_1.FunctionArgumentType.int:
473
- genericType = 'number';
474
- break;
475
- case declaration_1.FunctionArgumentType.any:
476
- genericType = 'any';
477
- break;
478
- case declaration_1.FunctionArgumentType.void:
479
- genericType = 'void';
480
- break;
481
- case declaration_1.FunctionArgumentType.null:
482
- genericType = 'null';
483
- break;
484
- case declaration_1.FunctionArgumentType.undefined:
485
- genericType = 'undefined';
486
- break;
487
- default:
488
- genericType = 'any';
489
- }
490
- }
491
- else {
492
- // For truly complex types, fallback to 'any' to avoid errors
493
- console.warn('Complex generic type in CustomEvent, using any');
494
- genericType = 'any';
495
- }
545
+ // As a last resort, keep the original syntax but normalize known WebF aliases.
546
+ return safePrintCustomEventNode(typeNode);
547
+ }
548
+ function handleCustomEventType(typeReference) {
549
+ // Handle CustomEvent<T> by returning the full type with generic parameter
550
+ if (!typeReference.typeArguments || !typeReference.typeArguments[0]) {
551
+ return 'CustomEvent';
552
+ }
553
+ const argument = typeReference.typeArguments[0];
554
+ const genericType = stringifyCustomEventGenericTypeNode(argument);
555
+ if (!genericType) {
556
+ console.warn('Complex generic type in CustomEvent, using any');
557
+ return 'CustomEvent<any>';
496
558
  }
497
559
  return `CustomEvent<${genericType}>`;
498
560
  }
package/dist/commands.js CHANGED
@@ -149,10 +149,10 @@ const tsConfig = fs_1.default.readFileSync(path_1.default.resolve(__dirname, '..
149
149
  const gitignore = fs_1.default.readFileSync(path_1.default.resolve(__dirname, '../templates/gitignore.tpl'), 'utf-8');
150
150
  const modulePackageJson = fs_1.default.readFileSync(path_1.default.resolve(__dirname, '../templates/module.package.json.tpl'), 'utf-8');
151
151
  const moduleTsConfig = fs_1.default.readFileSync(path_1.default.resolve(__dirname, '../templates/module.tsconfig.json.tpl'), 'utf-8');
152
- const moduleTsUpConfig = fs_1.default.readFileSync(path_1.default.resolve(__dirname, '../templates/module.tsup.config.ts.tpl'), 'utf-8');
152
+ const moduleTsDownConfig = fs_1.default.readFileSync(path_1.default.resolve(__dirname, '../templates/module.tsdown.config.ts.tpl'), 'utf-8');
153
153
  const reactPackageJson = fs_1.default.readFileSync(path_1.default.resolve(__dirname, '../templates/react.package.json.tpl'), 'utf-8');
154
154
  const reactTsConfig = fs_1.default.readFileSync(path_1.default.resolve(__dirname, '../templates/react.tsconfig.json.tpl'), 'utf-8');
155
- const reactTsUpConfig = fs_1.default.readFileSync(path_1.default.resolve(__dirname, '../templates/react.tsup.config.ts.tpl'), 'utf-8');
155
+ const reactTsDownConfig = fs_1.default.readFileSync(path_1.default.resolve(__dirname, '../templates/react.tsdown.config.ts.tpl'), 'utf-8');
156
156
  const reactIndexTpl = fs_1.default.readFileSync(path_1.default.resolve(__dirname, '../templates/react.index.ts.tpl'), 'utf-8');
157
157
  const vuePackageJson = fs_1.default.readFileSync(path_1.default.resolve(__dirname, '../templates/vue.package.json.tpl'), 'utf-8');
158
158
  const vueTsConfig = fs_1.default.readFileSync(path_1.default.resolve(__dirname, '../templates/vue.tsconfig.json.tpl'), 'utf-8');
@@ -181,6 +181,33 @@ function readFlutterPackageMetadata(packagePath) {
181
181
  return null;
182
182
  }
183
183
  }
184
+ function copyReadmeToPackageRoot(params) {
185
+ const { sourceRoot, targetRoot } = params;
186
+ const targetPath = path_1.default.join(targetRoot, 'README.md');
187
+ if (fs_1.default.existsSync(targetPath)) {
188
+ return { copied: false, targetPath };
189
+ }
190
+ const candidateNames = ['README.md', 'Readme.md', 'readme.md'];
191
+ let sourcePath = null;
192
+ for (const candidate of candidateNames) {
193
+ const abs = path_1.default.join(sourceRoot, candidate);
194
+ if (fs_1.default.existsSync(abs)) {
195
+ sourcePath = abs;
196
+ break;
197
+ }
198
+ }
199
+ if (!sourcePath) {
200
+ return { copied: false, targetPath };
201
+ }
202
+ try {
203
+ const content = fs_1.default.readFileSync(sourcePath, 'utf-8');
204
+ writeFileIfChanged(targetPath, content);
205
+ return { copied: true, sourcePath, targetPath };
206
+ }
207
+ catch (_a) {
208
+ return { copied: false, targetPath };
209
+ }
210
+ }
184
211
  // Copy markdown docs that match .d.ts basenames from source to the built dist folder,
185
212
  // and generate an aggregated README.md in the dist directory.
186
213
  function copyMarkdownDocsToDist(params) {
@@ -333,9 +360,9 @@ function createCommand(target, options) {
333
360
  const tsConfigPath = path_1.default.join(target, 'tsconfig.json');
334
361
  const tsConfigContent = lodash_1.default.template(reactTsConfig)({});
335
362
  writeFileIfChanged(tsConfigPath, tsConfigContent);
336
- const tsupConfigPath = path_1.default.join(target, 'tsup.config.ts');
337
- const tsupConfigContent = lodash_1.default.template(reactTsUpConfig)({});
338
- writeFileIfChanged(tsupConfigPath, tsupConfigContent);
363
+ const tsdownConfigPath = path_1.default.join(target, 'tsdown.config.ts');
364
+ const tsdownConfigContent = lodash_1.default.template(reactTsDownConfig)({});
365
+ writeFileIfChanged(tsdownConfigPath, tsdownConfigContent);
339
366
  const gitignorePath = path_1.default.join(target, '.gitignore');
340
367
  const gitignoreContent = lodash_1.default.template(gitignore)({});
341
368
  writeFileIfChanged(gitignorePath, gitignoreContent);
@@ -400,9 +427,9 @@ function createModuleProject(target, options) {
400
427
  const tsConfigPath = path_1.default.join(target, 'tsconfig.json');
401
428
  const tsConfigContent = lodash_1.default.template(moduleTsConfig)({});
402
429
  writeFileIfChanged(tsConfigPath, tsConfigContent);
403
- const tsupConfigPath = path_1.default.join(target, 'tsup.config.ts');
404
- const tsupConfigContent = lodash_1.default.template(moduleTsUpConfig)({});
405
- writeFileIfChanged(tsupConfigPath, tsupConfigContent);
430
+ const tsdownConfigPath = path_1.default.join(target, 'tsdown.config.ts');
431
+ const tsdownConfigContent = lodash_1.default.template(moduleTsDownConfig)({});
432
+ writeFileIfChanged(tsdownConfigPath, tsdownConfigContent);
406
433
  if (!skipGitignore) {
407
434
  const gitignorePath = path_1.default.join(target, '.gitignore');
408
435
  const gitignoreContent = lodash_1.default.template(gitignore)({});
@@ -660,6 +687,16 @@ function generateCommand(distPath, options) {
660
687
  }
661
688
  // Auto-initialize typings in the output directory if needed
662
689
  ensureInitialized(resolvedDistPath);
690
+ // Copy README.md from the source Flutter package into the npm package root (so `npm publish` includes it).
691
+ if (options.flutterPackageSrc) {
692
+ const { copied } = copyReadmeToPackageRoot({
693
+ sourceRoot: options.flutterPackageSrc,
694
+ targetRoot: resolvedDistPath,
695
+ });
696
+ if (copied) {
697
+ console.log('📄 Copied README.md to package root');
698
+ }
699
+ }
663
700
  console.log(`\nGenerating ${framework} code from ${options.flutterPackageSrc}...`);
664
701
  yield (0, generator_1.dartGen)({
665
702
  source: options.flutterPackageSrc,
@@ -880,7 +917,7 @@ function generateModuleCommand(distPath, options) {
880
917
  }]);
881
918
  packageName = packageNameAnswer.packageName;
882
919
  }
883
- // Prevent npm scaffolding (package.json, tsup.config.ts, etc.) from being written into
920
+ // Prevent npm scaffolding (package.json, tsdown.config.ts, etc.) from being written into
884
921
  // the Flutter package itself. Force users to choose a separate output directory.
885
922
  if (resolvedDistPath === flutterPackageSrc) {
886
923
  console.error('\n❌ Output directory must not be the Flutter package root.');
@@ -920,6 +957,14 @@ function generateModuleCommand(distPath, options) {
920
957
  flutterPackageDir: flutterPackageSrc,
921
958
  command,
922
959
  });
960
+ // Copy README.md from the source Flutter package into the npm package root
961
+ const { copied } = copyReadmeToPackageRoot({
962
+ sourceRoot: flutterPackageSrc,
963
+ targetRoot: resolvedDistPath,
964
+ });
965
+ if (copied) {
966
+ console.log('📄 Copied README.md to package root');
967
+ }
923
968
  console.log('\nModule code generation completed successfully!');
924
969
  try {
925
970
  yield buildPackage(resolvedDistPath);
package/dist/generator.js CHANGED
@@ -220,6 +220,7 @@ function dartGen(_a) {
220
220
  }
221
221
  function reactGen(_a) {
222
222
  return __awaiter(this, arguments, void 0, function* ({ source, target, exclude, packageName }) {
223
+ var _b, _c;
223
224
  (0, logger_1.group)('React Code Generation');
224
225
  (0, logger_1.time)('reactGen');
225
226
  const { source: normalizedSource, target: normalizedTarget } = validatePaths(source, target);
@@ -296,7 +297,8 @@ function reactGen(_a) {
296
297
  // Always build the full index content string for downstream tooling/logging
297
298
  const newExports = (0, react_1.generateReactIndex)(blobs);
298
299
  // Build desired export map: moduleSpecifier -> Set of names
299
- const desiredExports = new Map();
300
+ const desiredValueExports = new Map();
301
+ const desiredTypeExports = new Map();
300
302
  const components = blobs.flatMap(blob => {
301
303
  const classObjects = blob.objects.filter(obj => obj instanceof declaration_1.ClassObject);
302
304
  const properties = classObjects.filter(object => object.name.endsWith('Properties'));
@@ -318,11 +320,12 @@ function reactGen(_a) {
318
320
  }
319
321
  for (const { className, fileName, relativeDir } of unique.values()) {
320
322
  const spec = `./${relativeDir ? `${relativeDir}/` : ''}${fileName}`;
321
- if (!desiredExports.has(spec))
322
- desiredExports.set(spec, new Set());
323
- const set = desiredExports.get(spec);
324
- set.add(className);
325
- set.add(`${className}Element`);
323
+ if (!desiredValueExports.has(spec))
324
+ desiredValueExports.set(spec, new Set());
325
+ if (!desiredTypeExports.has(spec))
326
+ desiredTypeExports.set(spec, new Set());
327
+ desiredValueExports.get(spec).add(className);
328
+ desiredTypeExports.get(spec).add(`${className}Element`);
326
329
  }
327
330
  if (!fs_1.default.existsSync(indexFilePath)) {
328
331
  // No index.ts -> generate fresh file from template
@@ -344,24 +347,44 @@ function reactGen(_a) {
344
347
  : undefined;
345
348
  if (!moduleSpecifier)
346
349
  continue;
347
- const desired = desiredExports.get(moduleSpecifier);
348
- if (!desired)
350
+ const desiredValues = desiredValueExports.get(moduleSpecifier);
351
+ const desiredTypes = desiredTypeExports.get(moduleSpecifier);
352
+ if (!desiredValues && !desiredTypes)
349
353
  continue;
354
+ const declIsTypeOnly = Boolean(stmt.isTypeOnly);
350
355
  for (const el of stmt.exportClause.elements) {
351
356
  const name = el.name.getText(sourceFile);
352
- if (desired.has(name))
353
- desired.delete(name);
357
+ const specIsTypeOnly = Boolean(el.isTypeOnly);
358
+ const isTypeOnly = declIsTypeOnly || specIsTypeOnly;
359
+ if (isTypeOnly) {
360
+ if (desiredTypes === null || desiredTypes === void 0 ? void 0 : desiredTypes.has(name))
361
+ desiredTypes.delete(name);
362
+ }
363
+ else {
364
+ if (desiredValues === null || desiredValues === void 0 ? void 0 : desiredValues.has(name))
365
+ desiredValues.delete(name);
366
+ }
354
367
  }
355
368
  }
356
369
  }
357
370
  // Prepare new export lines for any remaining names
358
371
  const lines = [];
359
- for (const [spec, names] of desiredExports) {
360
- const missing = Array.from(names);
361
- if (missing.length === 0)
372
+ const specs = new Set([
373
+ ...desiredValueExports.keys(),
374
+ ...desiredTypeExports.keys()
375
+ ]);
376
+ for (const spec of specs) {
377
+ const missingValues = Array.from((_b = desiredValueExports.get(spec)) !== null && _b !== void 0 ? _b : []);
378
+ const missingTypes = Array.from((_c = desiredTypeExports.get(spec)) !== null && _c !== void 0 ? _c : []);
379
+ if (missingValues.length === 0 && missingTypes.length === 0)
362
380
  continue;
363
381
  const specEscaped = spec.replace(/\\/g, '/');
364
- lines.push(`export { ${missing.join(', ')} } from "${specEscaped}";`);
382
+ if (missingValues.length > 0) {
383
+ lines.push(`export { ${missingValues.join(', ')} } from "${specEscaped}";`);
384
+ }
385
+ if (missingTypes.length > 0) {
386
+ lines.push(`export type { ${missingTypes.join(', ')} } from "${specEscaped}";`);
387
+ }
365
388
  }
366
389
  if (lines.length > 0) {
367
390
  const appended = (existing.endsWith('\n') ? '' : '\n') + lines.join('\n') + '\n';
@@ -420,7 +443,7 @@ function reactGen(_a) {
420
443
  (0, logger_1.debug)(`[react] Aggregated types - consts: ${constNames.join(', ') || '(none)'}; typeAliases: ${aliasNames.join(', ') || '(none)'}; enums: ${enumNames.join(', ') || '(none)'}\n`);
421
444
  (0, logger_1.debug)(`[react] src/types.ts preview:\n` + typesContent.split('\n').slice(0, 20).join('\n'));
422
445
  }
423
- catch (_b) { }
446
+ catch (_d) { }
424
447
  }
425
448
  // Only re-export from index.ts when there are actual declarations to surface.
426
449
  if (hasAny) {
@@ -438,7 +461,7 @@ function reactGen(_a) {
438
461
  }
439
462
  }
440
463
  }
441
- catch (_c) { }
464
+ catch (_e) { }
442
465
  }
443
466
  }
444
467
  catch (e) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openwebf/webf",
3
- "version": "0.24.1",
3
+ "version": "0.24.2",
4
4
  "description": "Command line tools for WebF",
5
5
  "main": "index.js",
6
6
  "bin": {