@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 +1 -1
- package/dist/analyzer.js +183 -121
- package/dist/commands.js +54 -9
- package/dist/generator.js +39 -16
- package/package.json +1 -1
- package/src/analyzer.ts +186 -114
- package/src/commands.ts +65 -11
- package/src/generator.ts +32 -12
- package/templates/module.package.json.tpl +17 -6
- package/templates/{module.tsup.config.ts.tpl → module.tsdown.config.ts.tpl} +2 -7
- package/templates/react.component.tsx.tpl +18 -2
- package/templates/react.package.json.tpl +17 -5
- package/templates/{react.tsup.config.ts.tpl → react.tsdown.config.ts.tpl} +2 -4
- package/templates/vue.package.json.tpl +1 -1
- package/test/analyzer.test.ts +45 -1
- package/test/commands.test.ts +76 -4
- package/test/generator.test.ts +37 -0
- package/test/react.test.ts +5 -0
package/README.md
CHANGED
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
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
if (
|
|
372
|
-
return
|
|
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
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
if (
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
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
|
-
|
|
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
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
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
|
-
|
|
453
|
-
// For other type references, use the type name directly
|
|
454
|
-
genericType = typeName;
|
|
455
|
-
}
|
|
526
|
+
return `{ ${members.join('; ')} }`;
|
|
456
527
|
}
|
|
457
|
-
|
|
458
|
-
|
|
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
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
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
|
|
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
|
|
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
|
|
337
|
-
const
|
|
338
|
-
writeFileIfChanged(
|
|
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
|
|
404
|
-
const
|
|
405
|
-
writeFileIfChanged(
|
|
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,
|
|
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
|
|
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 (!
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
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
|
|
348
|
-
|
|
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
|
-
|
|
353
|
-
|
|
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
|
-
|
|
360
|
-
|
|
361
|
-
|
|
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
|
-
|
|
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 (
|
|
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 (
|
|
464
|
+
catch (_e) { }
|
|
442
465
|
}
|
|
443
466
|
}
|
|
444
467
|
catch (e) {
|