@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 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
- if (typescript_1.default.isTypeReferenceNode(argument) && typescript_1.default.isIdentifier(argument.typeName)) {
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) {