@openwebf/webf 0.23.2 → 0.23.10
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 +33 -1
- package/bin/webf.js +13 -1
- package/dist/analyzer.js +65 -1
- package/dist/commands.js +437 -99
- package/dist/dart.js +91 -25
- package/dist/declaration.js +1 -0
- package/dist/generator.js +28 -18
- package/dist/module.js +458 -0
- package/dist/react.js +272 -25
- package/dist/vue.js +89 -11
- package/package.json +2 -2
- package/src/analyzer.ts +58 -2
- package/src/commands.ts +587 -199
- package/src/dart.ts +95 -20
- package/src/declaration.ts +1 -0
- package/src/generator.ts +27 -19
- package/src/module.ts +600 -0
- package/src/react.ts +288 -29
- package/src/vue.ts +100 -13
- package/templates/class.dart.tpl +1 -1
- package/templates/module.package.json.tpl +36 -0
- package/templates/module.tsconfig.json.tpl +25 -0
- package/templates/module.tsup.config.ts.tpl +13 -0
- package/templates/vue.components.d.ts.tpl +2 -0
- package/test/commands.test.ts +86 -4
- package/test/dart-nullable-props.test.ts +58 -0
- package/test/generator.test.ts +16 -14
- package/test/react-consts.test.ts +1 -1
- package/test/react-vue-nullable-props.test.ts +66 -0
- package/test/react.test.ts +46 -4
package/README.md
CHANGED
|
@@ -25,6 +25,7 @@ webf codegen [output-dir] [options]
|
|
|
25
25
|
- `--flutter-package-src <path>`: Flutter package source path containing TypeScript definitions
|
|
26
26
|
- `--framework <framework>`: Target framework - 'react' or 'vue'
|
|
27
27
|
- `--package-name <name>`: Package name for the webf typings
|
|
28
|
+
- `--dart-only`: Only generate Dart bindings in the Flutter package (skip React/Vue code and npm package generation)
|
|
28
29
|
- `--publish-to-npm`: Automatically publish the generated package to npm
|
|
29
30
|
- `--npm-registry <url>`: Custom npm registry URL (defaults to https://registry.npmjs.org/)
|
|
30
31
|
|
|
@@ -40,6 +41,9 @@ webf codegen my-vue-app --flutter-package-src=./flutter_pkg --framework=vue --pa
|
|
|
40
41
|
|
|
41
42
|
# Use temporary directory (auto-created)
|
|
42
43
|
webf codegen --flutter-package-src=../webf_cupertino_ui
|
|
44
|
+
|
|
45
|
+
# Generate only Dart bindings inside the Flutter package
|
|
46
|
+
webf codegen --flutter-package-src=../webf_cupertino_ui --dart-only
|
|
43
47
|
```
|
|
44
48
|
|
|
45
49
|
**Create a new project without code generation:**
|
|
@@ -60,6 +64,34 @@ webf codegen my-typings --flutter-package-src=../webf_ui --publish-to-npm
|
|
|
60
64
|
webf codegen my-typings --flutter-package-src=../webf_ui --publish-to-npm --npm-registry=https://custom.registry.com/
|
|
61
65
|
```
|
|
62
66
|
|
|
67
|
+
### Generate Module Packages
|
|
68
|
+
|
|
69
|
+
The `webf module-codegen` command generates a typed npm package and Dart bindings for a WebF module based on a TypeScript interface file (`*.module.d.ts`) in your Flutter package.
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
webf module-codegen [output-dir] [options]
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
#### Options:
|
|
76
|
+
- `--flutter-package-src <path>`: Flutter module package path containing `*.module.d.ts`
|
|
77
|
+
- `--package-name <name>`: NPM package name for the module (defaults to a name derived from `pubspec.yaml`)
|
|
78
|
+
- `--publish-to-npm`: Automatically publish the generated package to npm
|
|
79
|
+
- `--npm-registry <url>`: Custom npm registry URL (defaults to https://registry.npmjs.org/)
|
|
80
|
+
- `--exclude <patterns...>`: Additional glob patterns to exclude from scanning (e.g. build directories)
|
|
81
|
+
|
|
82
|
+
#### Example:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
# From the CLI repo root
|
|
86
|
+
webf module-codegen ../packages/webf-share --flutter-package-src=../webf_modules/share --package-name=@openwebf/webf-share
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
This will:
|
|
90
|
+
- Scaffold an npm package at `../packages/webf-share`
|
|
91
|
+
- Read `*.module.d.ts` from `../webf_modules/share`
|
|
92
|
+
- Generate `src/index.ts` and `src/types.ts` that wrap `webf.invokeModuleAsync('Share', ...)`
|
|
93
|
+
- Generate Dart bindings in `../webf_modules/share/lib/src/share_module_bindings_generated.dart`
|
|
94
|
+
|
|
63
95
|
### Interactive Mode
|
|
64
96
|
|
|
65
97
|
If you don't provide all required options, the CLI will prompt you interactively:
|
|
@@ -229,4 +261,4 @@ npm link # Link for local testing
|
|
|
229
261
|
|
|
230
262
|
## License
|
|
231
263
|
|
|
232
|
-
ISC
|
|
264
|
+
ISC
|
package/bin/webf.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const { Command } = require('commander');
|
|
4
4
|
const version = require('../package.json').version;
|
|
5
|
-
const { generateCommand } = require('../dist/commands');
|
|
5
|
+
const { generateCommand, generateModuleCommand } = require('../dist/commands');
|
|
6
6
|
|
|
7
7
|
const program = new Command();
|
|
8
8
|
|
|
@@ -16,6 +16,7 @@ program
|
|
|
16
16
|
.option('--flutter-package-src <src>', 'Flutter package source path (for code generation)')
|
|
17
17
|
.option('--framework <framework>', 'Target framework (react or vue)')
|
|
18
18
|
.option('--package-name <name>', 'Package name for the webf typings')
|
|
19
|
+
.option('--dart-only', 'Only generate Dart bindings in the Flutter package (skip React/Vue code and npm package generation)')
|
|
19
20
|
.option('--publish-to-npm', 'Automatically publish the generated package to npm')
|
|
20
21
|
.option('--npm-registry <url>', 'Custom npm registry URL (defaults to https://registry.npmjs.org/)')
|
|
21
22
|
.option('--exclude <patterns...>', 'Additional glob patterns to exclude from code generation')
|
|
@@ -23,4 +24,15 @@ program
|
|
|
23
24
|
.description('Generate dart abstract classes and React/Vue components (auto-creates project if needed)')
|
|
24
25
|
.action(generateCommand);
|
|
25
26
|
|
|
27
|
+
program
|
|
28
|
+
.command('module-codegen')
|
|
29
|
+
.option('--flutter-package-src <src>', 'Flutter module package source path (for module code generation)')
|
|
30
|
+
.option('--package-name <name>', 'NPM package name for the WebF module')
|
|
31
|
+
.option('--publish-to-npm', 'Automatically publish the generated module package to npm')
|
|
32
|
+
.option('--npm-registry <url>', 'Custom npm registry URL (defaults to https://registry.npmjs.org/)')
|
|
33
|
+
.option('--exclude <patterns...>', 'Additional glob patterns to exclude from code generation')
|
|
34
|
+
.argument('[distPath]', 'Path to output generated files', '.')
|
|
35
|
+
.description('Generate NPM package and Dart bindings for a WebF module from TypeScript interfaces (*.module.d.ts)')
|
|
36
|
+
.action(generateModuleCommand);
|
|
37
|
+
|
|
26
38
|
program.parse();
|
package/dist/analyzer.js
CHANGED
|
@@ -256,6 +256,20 @@ function getParameterBaseType(type, mode) {
|
|
|
256
256
|
if (basicType !== undefined) {
|
|
257
257
|
return basicType;
|
|
258
258
|
}
|
|
259
|
+
// Handle `typeof SomeIdentifier` (TypeQuery) by preserving the textual form
|
|
260
|
+
// so React/Vue can keep strong typing (e.g., `typeof CupertinoIcons`).
|
|
261
|
+
// Dart mapping will convert this to `dynamic` later.
|
|
262
|
+
if (type.kind === typescript_1.default.SyntaxKind.TypeQuery) {
|
|
263
|
+
const tq = type;
|
|
264
|
+
const getEntityNameText = (name) => {
|
|
265
|
+
if (typescript_1.default.isIdentifier(name))
|
|
266
|
+
return name.text;
|
|
267
|
+
// Qualified name: A.B.C
|
|
268
|
+
return `${getEntityNameText(name.left)}.${name.right.text}`;
|
|
269
|
+
};
|
|
270
|
+
const nameText = getEntityNameText(tq.exprName);
|
|
271
|
+
return `typeof ${nameText}`;
|
|
272
|
+
}
|
|
259
273
|
if (type.kind === typescript_1.default.SyntaxKind.TypeReference) {
|
|
260
274
|
const typeReference = type;
|
|
261
275
|
const typeName = typeReference.typeName;
|
|
@@ -352,13 +366,58 @@ function handleGenericWrapper(typeReference, mode) {
|
|
|
352
366
|
return getParameterBaseType(argument, mode);
|
|
353
367
|
}
|
|
354
368
|
function handleCustomEventType(typeReference) {
|
|
369
|
+
var _a;
|
|
355
370
|
// Handle CustomEvent<T> by returning the full type with generic parameter
|
|
356
371
|
if (!typeReference.typeArguments || !typeReference.typeArguments[0]) {
|
|
357
372
|
return 'CustomEvent';
|
|
358
373
|
}
|
|
359
374
|
const argument = typeReference.typeArguments[0];
|
|
360
375
|
let genericType;
|
|
361
|
-
|
|
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
|
|
416
|
+
return 'any';
|
|
417
|
+
});
|
|
418
|
+
genericType = parts.join(' | ');
|
|
419
|
+
}
|
|
420
|
+
else if (typescript_1.default.isTypeReferenceNode(argument) && typescript_1.default.isIdentifier(argument.typeName)) {
|
|
362
421
|
const typeName = argument.typeName.text;
|
|
363
422
|
// Check if it's a mapped type reference like 'int' or 'double'
|
|
364
423
|
const mappedType = TYPE_REFERENCE_MAP[typeName];
|
|
@@ -627,6 +686,11 @@ function processEnumDeclaration(statement, blob) {
|
|
|
627
686
|
}
|
|
628
687
|
return mem;
|
|
629
688
|
});
|
|
689
|
+
// Register globally for cross-file lookups (e.g., Dart mapping decisions)
|
|
690
|
+
try {
|
|
691
|
+
declaration_1.EnumObject.globalEnumSet.add(enumObj.name);
|
|
692
|
+
}
|
|
693
|
+
catch (_a) { }
|
|
630
694
|
return enumObj;
|
|
631
695
|
}
|
|
632
696
|
function processInterfaceDeclaration(statement, blob, sourceFile, definedPropertyCollector, unionTypeCollector) {
|