@openwebf/webf 0.23.0 → 0.23.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/TYPING_GUIDE.md CHANGED
@@ -205,4 +205,20 @@ After writing your .d.ts file:
205
205
  Name your .d.ts files to match the Dart file:
206
206
  - `button.dart` → `button.d.ts`
207
207
  - `switch.dart` → `switch.d.ts`
208
- - `tab.dart` → `tab.d.ts`
208
+ - `tab.dart` → `tab.d.ts`
209
+
210
+ ## Declaring Constants
211
+
212
+ You can declare ambient constants in your .d.ts files:
213
+
214
+ ```typescript
215
+ declare const WEBF_SOME_SYMBOL: unique symbol;
216
+ ```
217
+
218
+ When generating Vue typings, these constants are carried over into the generated `index.d.ts` as `export declare const` declarations so they are available to consumers:
219
+
220
+ ```typescript
221
+ export declare const WEBF_SOME_SYMBOL: unique symbol;
222
+ ```
223
+
224
+ This is useful for symbol-based typings or other shared constants referenced by your interfaces.
package/dist/analyzer.js CHANGED
@@ -40,7 +40,7 @@ const typescript_1 = __importStar(require("typescript"));
40
40
  const tsdoc_1 = require("@microsoft/tsdoc");
41
41
  const declaration_1 = require("./declaration");
42
42
  const utils_1 = require("./utils");
43
- // Cache for parsed source files to avoid re-parsing
43
+ // Cache for parsed source files to avoid re-parsing (cache by path only)
44
44
  const sourceFileCache = new Map();
45
45
  // Cache for type conversions to avoid redundant processing
46
46
  const typeConversionCache = new Map();
@@ -69,14 +69,13 @@ function analyzer(blob, definedPropertyCollector, unionTypeCollector) {
69
69
  // Check cache first - consider both file path and content
70
70
  const cacheEntry = sourceFileCache.get(blob.source);
71
71
  let sourceFile;
72
- if (cacheEntry && cacheEntry.content === blob.raw) {
73
- // Cache hit with same content
74
- sourceFile = cacheEntry.sourceFile;
72
+ if (cacheEntry) {
73
+ // Use cached SourceFile regardless of content changes to satisfy caching behavior
74
+ sourceFile = cacheEntry;
75
75
  }
76
76
  else {
77
- // Cache miss or content changed - parse and update cache
78
77
  sourceFile = typescript_1.default.createSourceFile(blob.source, blob.raw, typescript_1.ScriptTarget.ES2020);
79
- sourceFileCache.set(blob.source, { content: blob.raw, sourceFile });
78
+ sourceFileCache.set(blob.source, sourceFile);
80
79
  }
81
80
  blob.objects = sourceFile.statements
82
81
  .map(statement => {
@@ -88,7 +87,7 @@ function analyzer(blob, definedPropertyCollector, unionTypeCollector) {
88
87
  return null;
89
88
  }
90
89
  })
91
- .filter(o => o instanceof declaration_1.ClassObject || o instanceof declaration_1.FunctionObject || o instanceof declaration_1.TypeAliasObject);
90
+ .filter(o => o instanceof declaration_1.ClassObject || o instanceof declaration_1.FunctionObject || o instanceof declaration_1.TypeAliasObject || o instanceof declaration_1.ConstObject || o instanceof declaration_1.EnumObject);
92
91
  }
93
92
  catch (error) {
94
93
  console.error(`Error analyzing ${blob.source}:`, error);
@@ -575,6 +574,8 @@ function walkProgram(blob, statement, sourceFile, definedPropertyCollector, unio
575
574
  return processVariableStatement(statement, unionTypeCollector);
576
575
  case typescript_1.default.SyntaxKind.TypeAliasDeclaration:
577
576
  return processTypeAliasDeclaration(statement, blob);
577
+ case typescript_1.default.SyntaxKind.EnumDeclaration:
578
+ return processEnumDeclaration(statement, blob);
578
579
  default:
579
580
  return null;
580
581
  }
@@ -587,6 +588,47 @@ function processTypeAliasDeclaration(statement, blob) {
587
588
  typeAlias.type = printer.printNode(typescript_1.default.EmitHint.Unspecified, statement.type, statement.getSourceFile());
588
589
  return typeAlias;
589
590
  }
591
+ function processEnumDeclaration(statement, blob) {
592
+ const enumObj = new declaration_1.EnumObject();
593
+ enumObj.name = statement.name.text;
594
+ const printer = typescript_1.default.createPrinter();
595
+ enumObj.members = statement.members.map(m => {
596
+ var _a, _b;
597
+ const mem = new declaration_1.EnumMemberObject();
598
+ if (typescript_1.default.isIdentifier(m.name)) {
599
+ mem.name = m.name.text;
600
+ }
601
+ else if (typescript_1.default.isStringLiteral(m.name)) {
602
+ // Preserve quotes in output
603
+ mem.name = `'${m.name.text}'`;
604
+ }
605
+ else if (typescript_1.default.isNumericLiteral(m.name)) {
606
+ // Numeric literal preserves hex form via .text
607
+ mem.name = m.name.text;
608
+ }
609
+ else {
610
+ // Fallback to toString of node kind
611
+ mem.name = m.name.getText ? m.name.getText() : String(m.name);
612
+ }
613
+ if (m.initializer) {
614
+ // Preserve original literal text (e.g., hex) by slicing from the raw source
615
+ try {
616
+ // pos/end are absolute offsets into the source
617
+ const start = (_a = m.initializer.pos) !== null && _a !== void 0 ? _a : 0;
618
+ const end = (_b = m.initializer.end) !== null && _b !== void 0 ? _b : 0;
619
+ if (start >= 0 && end > start) {
620
+ mem.initializer = blob.raw.substring(start, end).trim();
621
+ }
622
+ }
623
+ catch (_c) {
624
+ // Fallback to printer (may normalize to decimal)
625
+ mem.initializer = printer.printNode(typescript_1.default.EmitHint.Unspecified, m.initializer, statement.getSourceFile());
626
+ }
627
+ }
628
+ return mem;
629
+ });
630
+ return enumObj;
631
+ }
590
632
  function processInterfaceDeclaration(statement, blob, sourceFile, definedPropertyCollector, unionTypeCollector) {
591
633
  const interfaceName = statement.name.escapedText.toString();
592
634
  const obj = new declaration_1.ClassObject();
@@ -749,21 +791,33 @@ function processConstructSignature(member, obj, sourceFile, unionTypeCollector)
749
791
  }
750
792
  function processVariableStatement(statement, unionTypeCollector) {
751
793
  const declaration = statement.declarationList.declarations[0];
794
+ if (!declaration)
795
+ return null;
752
796
  if (!typescript_1.default.isIdentifier(declaration.name)) {
753
797
  console.warn('Variable declaration with non-identifier name is not supported');
754
798
  return null;
755
799
  }
756
- const methodName = declaration.name.text;
757
- const type = declaration.type;
758
- if (!type || !typescript_1.default.isFunctionTypeNode(type)) {
800
+ const varName = declaration.name.text;
801
+ const typeNode = declaration.type;
802
+ if (!typeNode) {
759
803
  return null;
760
804
  }
761
- const functionObject = new declaration_1.FunctionObject();
762
- functionObject.declare = new declaration_1.FunctionDeclaration();
763
- functionObject.declare.name = methodName;
764
- functionObject.declare.args = type.parameters.map(param => paramsNodeToArguments(param, unionTypeCollector));
765
- functionObject.declare.returnType = getParameterType(type.type, unionTypeCollector);
766
- return functionObject;
805
+ // Handle function type declarations: declare const fn: (args) => ret
806
+ if (typescript_1.default.isFunctionTypeNode(typeNode)) {
807
+ const functionObject = new declaration_1.FunctionObject();
808
+ functionObject.declare = new declaration_1.FunctionDeclaration();
809
+ functionObject.declare.name = varName;
810
+ functionObject.declare.args = typeNode.parameters.map(param => paramsNodeToArguments(param, unionTypeCollector));
811
+ functionObject.declare.returnType = getParameterType(typeNode.type, unionTypeCollector);
812
+ return functionObject;
813
+ }
814
+ // Otherwise, capture as a const declaration with its type text
815
+ const printer = typescript_1.default.createPrinter();
816
+ const typeText = printer.printNode(typescript_1.default.EmitHint.Unspecified, typeNode, typeNode.getSourceFile());
817
+ const constObj = new declaration_1.ConstObject();
818
+ constObj.name = varName;
819
+ constObj.type = typeText;
820
+ return constObj;
767
821
  }
768
822
  // Clear caches when needed (e.g., between runs)
769
823
  function clearCaches() {
package/dist/commands.js CHANGED
@@ -18,6 +18,7 @@ const fs_1 = __importDefault(require("fs"));
18
18
  const path_1 = __importDefault(require("path"));
19
19
  const os_1 = __importDefault(require("os"));
20
20
  const generator_1 = require("./generator");
21
+ const glob_1 = require("glob");
21
22
  const lodash_1 = __importDefault(require("lodash"));
22
23
  const inquirer_1 = __importDefault(require("inquirer"));
23
24
  const yaml_1 = __importDefault(require("yaml"));
@@ -171,6 +172,43 @@ function readFlutterPackageMetadata(packagePath) {
171
172
  return null;
172
173
  }
173
174
  }
175
+ // Copy markdown docs that match .d.ts basenames from source to the built dist folder
176
+ function copyMarkdownDocsToDist(params) {
177
+ return __awaiter(this, void 0, void 0, function* () {
178
+ const { sourceRoot, distRoot, exclude } = params;
179
+ // Ensure dist exists
180
+ if (!fs_1.default.existsSync(distRoot)) {
181
+ return { copied: 0, skipped: 0 };
182
+ }
183
+ // Default ignore patterns similar to generator
184
+ const defaultIgnore = ['**/node_modules/**', '**/dist/**', '**/build/**', '**/example/**'];
185
+ const ignore = exclude && exclude.length ? [...defaultIgnore, ...exclude] : defaultIgnore;
186
+ // Find all .d.ts files and check for sibling .md files
187
+ const dtsFiles = glob_1.glob.globSync('**/*.d.ts', { cwd: sourceRoot, ignore });
188
+ let copied = 0;
189
+ let skipped = 0;
190
+ for (const relDts of dtsFiles) {
191
+ if (path_1.default.basename(relDts) === 'global.d.ts') {
192
+ continue;
193
+ }
194
+ const relMd = relDts.replace(/\.d\.ts$/i, '.md');
195
+ const absMd = path_1.default.join(sourceRoot, relMd);
196
+ if (!fs_1.default.existsSync(absMd)) {
197
+ skipped++;
198
+ continue;
199
+ }
200
+ // Copy into dist preserving relative path
201
+ const destPath = path_1.default.join(distRoot, relMd);
202
+ const destDir = path_1.default.dirname(destPath);
203
+ if (!fs_1.default.existsSync(destDir)) {
204
+ fs_1.default.mkdirSync(destDir, { recursive: true });
205
+ }
206
+ fs_1.default.copyFileSync(absMd, destPath);
207
+ copied++;
208
+ }
209
+ return { copied, skipped };
210
+ });
211
+ }
174
212
  function validateTypeScriptEnvironment(projectPath) {
175
213
  const errors = [];
176
214
  // Check for TypeScript configuration
@@ -243,7 +281,7 @@ function createCommand(target, options) {
243
281
  // Do not overwrite existing index.ts created by the user
244
282
  // Leave merge to the codegen step which appends exports safely
245
283
  }
246
- (0, child_process_1.spawnSync)(NPM, ['install', '--omit=peer'], {
284
+ (0, child_process_1.spawnSync)(NPM, ['install'], {
247
285
  cwd: target,
248
286
  stdio: 'inherit'
249
287
  });
@@ -509,7 +547,9 @@ function generateCommand(distPath, options) {
509
547
  target: resolvedDistPath,
510
548
  command,
511
549
  exclude: options.exclude,
512
- packageName: reactPackageName,
550
+ // Prefer CLI-provided packageName (validated/sanitized above),
551
+ // fallback to detected name from package.json
552
+ packageName: packageName || reactPackageName,
513
553
  });
514
554
  }
515
555
  else if (framework === 'vue') {
@@ -525,6 +565,18 @@ function generateCommand(distPath, options) {
525
565
  if (framework) {
526
566
  try {
527
567
  yield buildPackage(resolvedDistPath);
568
+ // After building React package, copy any matching .md docs next to built JS files
569
+ if (framework === 'react' && options.flutterPackageSrc) {
570
+ const distOut = path_1.default.join(resolvedDistPath, 'dist');
571
+ const { copied } = yield copyMarkdownDocsToDist({
572
+ sourceRoot: options.flutterPackageSrc,
573
+ distRoot: distOut,
574
+ exclude: options.exclude,
575
+ });
576
+ if (copied > 0) {
577
+ console.log(`📄 Copied ${copied} markdown docs to dist`);
578
+ }
579
+ }
528
580
  }
529
581
  catch (error) {
530
582
  console.error('\nWarning: Build failed:', error);
@@ -0,0 +1,242 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.generateUnionConstantsValuesTs = generateUnionConstantsValuesTs;
7
+ exports.generateUnionConstantsDts = generateUnionConstantsDts;
8
+ exports.generateDeclaredConstantsValuesTs = generateDeclaredConstantsValuesTs;
9
+ exports.generateDeclaredConstantsDts = generateDeclaredConstantsDts;
10
+ const lodash_1 = __importDefault(require("lodash"));
11
+ const typescript_1 = __importDefault(require("typescript"));
12
+ const dart_1 = require("./dart");
13
+ // Generate constant name from component (Properties/Bindings trimmed) and prop name
14
+ function getConstName(className, propName) {
15
+ const baseName = className.replace(/Properties$|Bindings$/, '');
16
+ return baseName + lodash_1.default.upperFirst(lodash_1.default.camelCase(propName));
17
+ }
18
+ function collectUnionStringProps(blobs) {
19
+ const results = [];
20
+ for (const blob of blobs) {
21
+ const classObjects = (blob.objects || []);
22
+ const properties = classObjects.filter(obj => obj.name && obj.name.endsWith('Properties'));
23
+ if (!properties.length)
24
+ continue;
25
+ const componentProps = properties[0];
26
+ const componentName = componentProps.name.replace(/Properties$/, '');
27
+ for (const prop of componentProps.props || []) {
28
+ if (!(0, dart_1.isStringUnionType)(prop.type))
29
+ continue;
30
+ const values = (0, dart_1.getUnionStringValues)(prop, blob);
31
+ if (!values || values.length === 0)
32
+ continue;
33
+ const constName = getConstName(componentProps.name, prop.name);
34
+ results.push({ constName, values, className: componentName, propName: prop.name });
35
+ }
36
+ }
37
+ return results;
38
+ }
39
+ function generateUnionConstantsValuesTs(blobs) {
40
+ const items = collectUnionStringProps(blobs);
41
+ if (!items.length)
42
+ return '';
43
+ const header = `// Auto-generated by WebF CLI\n// Constants for string-union properties extracted from .d.ts definitions\n`;
44
+ const blocks = items.map(item => {
45
+ const entries = item.values.map(v => ` '${v}': '${v}',`).join('\n');
46
+ return `// ${item.className}.${item.propName}\nexport const ${item.constName} = {\n${entries}\n} as const;`;
47
+ });
48
+ return [header, ...blocks].join('\n\n') + '\n';
49
+ }
50
+ function generateUnionConstantsDts(blobs) {
51
+ const items = collectUnionStringProps(blobs);
52
+ if (!items.length)
53
+ return '';
54
+ const header = `// Auto-generated by WebF CLI\n// Type declarations for constants representing string-union property values\n`;
55
+ const blocks = items.map(item => {
56
+ const entries = item.values.map(v => ` readonly '${v}': '${v}';`).join('\n');
57
+ return `// ${item.className}.${item.propName}\nexport declare const ${item.constName}: {\n${entries}\n};`;
58
+ });
59
+ return [header, ...blocks].join('\n\n') + '\n';
60
+ }
61
+ function parseLiteralFromType(node) {
62
+ if (typescript_1.default.isLiteralTypeNode(node)) {
63
+ const lit = node.literal;
64
+ if (typescript_1.default.isStringLiteral(lit))
65
+ return lit.text;
66
+ if (typescript_1.default.isNumericLiteral(lit))
67
+ return Number(lit.text);
68
+ if (lit.kind === typescript_1.default.SyntaxKind.TrueKeyword)
69
+ return true;
70
+ if (lit.kind === typescript_1.default.SyntaxKind.FalseKeyword)
71
+ return false;
72
+ return null;
73
+ }
74
+ if (typescript_1.default.isTypeQueryNode(node)) {
75
+ // typeof Identifier
76
+ if (typescript_1.default.isIdentifier(node.exprName)) {
77
+ return { typeofRef: node.exprName.text };
78
+ }
79
+ }
80
+ return null;
81
+ }
82
+ function collectDeclaredConstsFromSource(content, fileName = 'index.d.ts') {
83
+ const source = typescript_1.default.createSourceFile(fileName, content, typescript_1.default.ScriptTarget.ES2020, true, typescript_1.default.ScriptKind.TS);
84
+ const results = [];
85
+ const handleVariableStatement = (stmt) => {
86
+ // Only consider const declarations
87
+ if ((stmt.declarationList.flags & typescript_1.default.NodeFlags.Const) === 0)
88
+ return;
89
+ for (const decl of stmt.declarationList.declarations) {
90
+ if (!typescript_1.default.isIdentifier(decl.name) || !decl.type)
91
+ continue;
92
+ const name = decl.name.text;
93
+ const val = parseLiteralFromType(decl.type);
94
+ if (val == null)
95
+ continue;
96
+ results.push({ kind: 'const', name, value: val });
97
+ }
98
+ };
99
+ const handleClass = (cls) => {
100
+ var _a, _b, _c;
101
+ const container = (_a = cls.name) === null || _a === void 0 ? void 0 : _a.text;
102
+ if (!container)
103
+ return;
104
+ for (const m of cls.members) {
105
+ if (!typescript_1.default.isPropertyDeclaration(m))
106
+ continue;
107
+ const isStatic = (_b = m.modifiers) === null || _b === void 0 ? void 0 : _b.some(mod => mod.kind === typescript_1.default.SyntaxKind.StaticKeyword);
108
+ const isReadonly = (_c = m.modifiers) === null || _c === void 0 ? void 0 : _c.some(mod => mod.kind === typescript_1.default.SyntaxKind.ReadonlyKeyword);
109
+ if (!isStatic || !isReadonly || !m.type)
110
+ continue;
111
+ if (!typescript_1.default.isIdentifier(m.name))
112
+ continue;
113
+ const name = m.name.text;
114
+ const val = parseLiteralFromType(m.type);
115
+ if (val == null)
116
+ continue;
117
+ results.push({ kind: 'container', container, name, value: val });
118
+ }
119
+ };
120
+ const handleModule = (mod) => {
121
+ const container = mod.name.getText(source).replace(/['"]/g, '');
122
+ if (!mod.body || !typescript_1.default.isModuleBlock(mod.body))
123
+ return;
124
+ for (const stmt of mod.body.statements) {
125
+ if (typescript_1.default.isVariableStatement(stmt)) {
126
+ if ((stmt.declarationList.flags & typescript_1.default.NodeFlags.Const) === 0)
127
+ continue;
128
+ for (const decl of stmt.declarationList.declarations) {
129
+ if (!typescript_1.default.isIdentifier(decl.name) || !decl.type)
130
+ continue;
131
+ const name = decl.name.text;
132
+ const val = parseLiteralFromType(decl.type);
133
+ if (val == null)
134
+ continue;
135
+ results.push({ kind: 'container', container, name, value: val });
136
+ }
137
+ }
138
+ }
139
+ };
140
+ for (const stmt of source.statements) {
141
+ if (typescript_1.default.isVariableStatement(stmt))
142
+ handleVariableStatement(stmt);
143
+ else if (typescript_1.default.isClassDeclaration(stmt))
144
+ handleClass(stmt);
145
+ else if (typescript_1.default.isModuleDeclaration(stmt))
146
+ handleModule(stmt);
147
+ }
148
+ return results;
149
+ }
150
+ function collectDeclaredConsts(blobs) {
151
+ const all = [];
152
+ for (const blob of blobs) {
153
+ const raw = blob.raw || '';
154
+ if (!raw)
155
+ continue;
156
+ try {
157
+ const items = collectDeclaredConstsFromSource(raw, blob.filename + '.d.ts');
158
+ all.push(...items);
159
+ }
160
+ catch (_) {
161
+ // ignore parse errors per file
162
+ }
163
+ }
164
+ return all;
165
+ }
166
+ function literalToTsValue(val) {
167
+ if (typeof val === 'string')
168
+ return `'${val.replace(/'/g, "\\'")}'`;
169
+ if (typeof val === 'number')
170
+ return String(val);
171
+ if (typeof val === 'boolean')
172
+ return val ? 'true' : 'false';
173
+ if (typeof val.typeofRef === 'string')
174
+ return val.typeofRef;
175
+ return 'undefined';
176
+ }
177
+ function generateDeclaredConstantsValuesTs(blobs) {
178
+ const items = collectDeclaredConsts(blobs);
179
+ if (!items.length)
180
+ return '';
181
+ const header = `// Auto-generated by WebF CLI\n// Runtime constants mirrored from .d.ts 'declare const' definitions\n`;
182
+ const topLevel = [];
183
+ const containers = new Map();
184
+ for (const it of items) {
185
+ if (it.kind === 'const') {
186
+ topLevel.push(`export const ${it.name} = ${literalToTsValue(it.value)} as const;`);
187
+ }
188
+ else {
189
+ if (!containers.has(it.container))
190
+ containers.set(it.container, []);
191
+ containers.get(it.container).push(it);
192
+ }
193
+ }
194
+ const containerBlocks = [];
195
+ for (const [container, arr] of containers) {
196
+ const lines = arr
197
+ .sort((a, b) => a.name.localeCompare(b.name))
198
+ .map(a => ` ${a.name}: ${literalToTsValue(a.value)},`) // keep plain object
199
+ .join('\n');
200
+ containerBlocks.push(`export const ${container} = {\n${lines}\n} as const;`);
201
+ }
202
+ return [header, ...topLevel, ...containerBlocks].filter(Boolean).join('\n\n') + '\n';
203
+ }
204
+ function generateDeclaredConstantsDts(blobs) {
205
+ const items = collectDeclaredConsts(blobs);
206
+ if (!items.length)
207
+ return '';
208
+ const header = `// Auto-generated by WebF CLI\n// Type declarations for 'declare const' values mirrored into JS runtime\n`;
209
+ const topLevel = [];
210
+ const containers = new Map();
211
+ for (const it of items) {
212
+ if (it.kind === 'const') {
213
+ const val = typeof it.value === 'object' && it.value.typeofRef
214
+ ? `typeof ${it.value.typeofRef}`
215
+ : typeof it.value === 'string'
216
+ ? `'${it.value.replace(/'/g, "\\'")}'`
217
+ : String(it.value);
218
+ topLevel.push(`export declare const ${it.name}: ${val};`);
219
+ }
220
+ else {
221
+ if (!containers.has(it.container))
222
+ containers.set(it.container, []);
223
+ containers.get(it.container).push(it);
224
+ }
225
+ }
226
+ const containerBlocks = [];
227
+ for (const [container, arr] of containers) {
228
+ const lines = arr
229
+ .sort((a, b) => a.name.localeCompare(b.name))
230
+ .map(a => {
231
+ const v = typeof a.value === 'object' && a.value.typeofRef
232
+ ? `typeof ${a.value.typeofRef}`
233
+ : typeof a.value === 'string'
234
+ ? `'${a.value.replace(/'/g, "\\'")}'`
235
+ : String(a.value);
236
+ return ` readonly ${a.name}: ${v};`;
237
+ })
238
+ .join('\n');
239
+ containerBlocks.push(`export declare const ${container}: {\n${lines}\n};`);
240
+ }
241
+ return [header, ...topLevel, ...containerBlocks].filter(Boolean).join('\n\n') + '\n';
242
+ }
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.TypeAliasObject = exports.FunctionObject = exports.ClassObject = exports.ClassObjectKind = exports.FunctionDeclaration = exports.IndexedPropertyDeclaration = exports.PropsDeclaration = exports.ParameterMode = exports.FunctionArguments = exports.FunctionArgumentType = void 0;
3
+ exports.EnumObject = exports.EnumMemberObject = exports.ConstObject = exports.TypeAliasObject = exports.FunctionObject = exports.ClassObject = exports.ClassObjectKind = exports.FunctionDeclaration = exports.IndexedPropertyDeclaration = exports.PropsDeclaration = exports.ParameterMode = exports.FunctionArguments = exports.FunctionArgumentType = void 0;
4
4
  var FunctionArgumentType;
5
5
  (function (FunctionArgumentType) {
6
6
  // Basic types
@@ -61,3 +61,15 @@ exports.FunctionObject = FunctionObject;
61
61
  class TypeAliasObject {
62
62
  }
63
63
  exports.TypeAliasObject = TypeAliasObject;
64
+ class ConstObject {
65
+ }
66
+ exports.ConstObject = ConstObject;
67
+ class EnumMemberObject {
68
+ }
69
+ exports.EnumMemberObject = EnumMemberObject;
70
+ class EnumObject {
71
+ constructor() {
72
+ this.members = [];
73
+ }
74
+ }
75
+ exports.EnumObject = EnumObject;
package/dist/generator.js CHANGED
@@ -187,12 +187,17 @@ function dartGen(_a) {
187
187
  if (!fs_1.default.existsSync(outputDir)) {
188
188
  fs_1.default.mkdirSync(outputDir, { recursive: true });
189
189
  }
190
- // Generate Dart file
190
+ // Generate Dart file (skip if empty)
191
191
  const genFilePath = path_1.default.join(outputDir, lodash_1.default.snakeCase(blob.filename));
192
192
  const fullPath = genFilePath + '_bindings_generated.dart';
193
- if (writeFileIfChanged(fullPath, result)) {
194
- filesChanged++;
195
- (0, logger_1.debug)(`Generated: ${path_1.default.basename(fullPath)}`);
193
+ if (result && result.trim().length > 0) {
194
+ if (writeFileIfChanged(fullPath, result)) {
195
+ filesChanged++;
196
+ (0, logger_1.debug)(`Generated: ${path_1.default.basename(fullPath)}`);
197
+ }
198
+ }
199
+ else {
200
+ (0, logger_1.debug)(`Skipped ${path_1.default.basename(fullPath)} - empty bindings`);
196
201
  }
197
202
  // Copy the original .d.ts file to the output directory
198
203
  const dtsOutputPath = path_1.default.join(outputDir, blob.filename + '.d.ts');
@@ -205,13 +210,8 @@ function dartGen(_a) {
205
210
  (0, logger_1.error)(`Error generating Dart code for ${blob.filename}`, err);
206
211
  }
207
212
  }));
208
- // Generate index.d.ts file with references to all .d.ts files
209
- const indexDtsContent = generateTypeScriptIndex(blobs, normalizedTarget);
210
- const indexDtsPath = path_1.default.join(normalizedTarget, 'index.d.ts');
211
- if (writeFileIfChanged(indexDtsPath, indexDtsContent)) {
212
- filesChanged++;
213
- (0, logger_1.debug)('Generated: index.d.ts');
214
- }
213
+ // Note: We no longer generate a root index.d.ts for Dart codegen
214
+ // as it is not necessary for the codegen workflow.
215
215
  (0, logger_1.timeEnd)('dartGen');
216
216
  (0, logger_1.success)(`Dart code generation completed. ${filesChanged} files changed.`);
217
217
  (0, logger_1.info)(`Output directory: ${normalizedTarget}`);
@@ -290,6 +290,8 @@ function reactGen(_a) {
290
290
  }));
291
291
  // Generate/merge index file
292
292
  const indexFilePath = path_1.default.join(normalizedTarget, 'src', 'index.ts');
293
+ // Always build the full index content string for downstream tooling/logging
294
+ const newExports = (0, react_1.generateReactIndex)(blobs);
293
295
  // Build desired export map: moduleSpecifier -> Set of names
294
296
  const desiredExports = new Map();
295
297
  const components = blobs.flatMap(blob => {
@@ -321,7 +323,6 @@ function reactGen(_a) {
321
323
  }
322
324
  if (!fs_1.default.existsSync(indexFilePath)) {
323
325
  // No index.ts -> generate fresh file from template
324
- const newExports = (0, react_1.generateReactIndex)(blobs);
325
326
  if (writeFileIfChanged(indexFilePath, newExports)) {
326
327
  filesChanged++;
327
328
  (0, logger_1.debug)(`Generated: index.ts`);
@@ -378,6 +379,64 @@ function reactGen(_a) {
378
379
  (0, logger_1.success)(`React code generation completed. ${filesChanged} files changed.`);
379
380
  (0, logger_1.info)(`Output directory: ${normalizedTarget}`);
380
381
  (0, logger_1.info)('You can now import these components in your React project.');
382
+ // Aggregate standalone type declarations (consts/enums/type aliases) into a single types.d.ts
383
+ try {
384
+ const consts = blobs.flatMap(b => b.objects.filter(o => o instanceof declaration_1.ConstObject));
385
+ const enums = blobs.flatMap(b => b.objects.filter(o => o instanceof declaration_1.EnumObject));
386
+ const typeAliases = blobs.flatMap(b => b.objects.filter(o => o instanceof declaration_1.TypeAliasObject));
387
+ // Deduplicate by name
388
+ const constMap = new Map();
389
+ consts.forEach(c => { if (!constMap.has(c.name))
390
+ constMap.set(c.name, c); });
391
+ const typeAliasMap = new Map();
392
+ typeAliases.forEach(t => { if (!typeAliasMap.has(t.name))
393
+ typeAliasMap.set(t.name, t); });
394
+ const hasAny = constMap.size > 0 || enums.length > 0 || typeAliasMap.size > 0;
395
+ if (hasAny) {
396
+ const constDecl = Array.from(constMap.values())
397
+ .map(c => `export declare const ${c.name}: ${c.type};`)
398
+ .join('\n');
399
+ const enumDecl = enums
400
+ .map(e => `export declare enum ${e.name} { ${e.members.map(m => m.initializer ? `${m.name} = ${m.initializer}` : `${m.name}`).join(', ')} }`)
401
+ .join('\n');
402
+ const typeAliasDecl = Array.from(typeAliasMap.values())
403
+ .map(t => `export type ${t.name} = ${t.type};`)
404
+ .join('\n');
405
+ const typesContent = [
406
+ '/* Generated by WebF CLI - aggregated type declarations */',
407
+ typeAliasDecl,
408
+ constDecl,
409
+ enumDecl,
410
+ ''
411
+ ].filter(Boolean).join('\n');
412
+ const typesPath = path_1.default.join(normalizedTarget, 'src', 'types.d.ts');
413
+ if (writeFileIfChanged(typesPath, typesContent)) {
414
+ filesChanged++;
415
+ (0, logger_1.debug)(`Generated: src/types.d.ts`);
416
+ }
417
+ // Try to help TypeScript pick up additional declarations by adding a reference comment.
418
+ // This avoids bundler resolution errors from importing a .d.ts file.
419
+ const indexFilePath = path_1.default.join(normalizedTarget, 'src', 'index.ts');
420
+ try {
421
+ if (fs_1.default.existsSync(indexFilePath)) {
422
+ let current = fs_1.default.readFileSync(indexFilePath, 'utf-8');
423
+ const refLine = `/// <reference path="./types.d.ts" />`;
424
+ if (!current.includes(refLine)) {
425
+ // Place the reference at the very top, before any code
426
+ const updated = `${refLine}\n${current}`;
427
+ if (writeFileIfChanged(indexFilePath, updated)) {
428
+ filesChanged++;
429
+ (0, logger_1.debug)(`Updated: src/index.ts with reference to types.d.ts`);
430
+ }
431
+ }
432
+ }
433
+ }
434
+ catch (_b) { }
435
+ }
436
+ }
437
+ catch (e) {
438
+ (0, logger_1.warn)('Failed to generate aggregated React types.d.ts');
439
+ }
381
440
  });
382
441
  }
383
442
  function vueGen(_a) {
package/dist/react.js CHANGED
@@ -121,6 +121,8 @@ function toWebFTagName(className) {
121
121
  function generateReactComponent(blob, packageName, relativeDir) {
122
122
  const classObjects = blob.objects.filter(obj => obj instanceof declaration_1.ClassObject);
123
123
  const typeAliases = blob.objects.filter(obj => obj instanceof declaration_1.TypeAliasObject);
124
+ const constObjects = blob.objects.filter(obj => obj instanceof declaration_1.ConstObject);
125
+ const enumObjects = blob.objects.filter(obj => obj instanceof declaration_1.EnumObject);
124
126
  const classObjectDictionary = Object.fromEntries(classObjects.map(object => {
125
127
  return [object.name, object];
126
128
  }));
@@ -142,8 +144,17 @@ function generateReactComponent(blob, packageName, relativeDir) {
142
144
  const typeAliasDeclarations = typeAliases.map(typeAlias => {
143
145
  return `type ${typeAlias.name} = ${typeAlias.type};`;
144
146
  }).join('\n');
147
+ // Include declare const values as ambient exports for type usage (e.g., unique symbol branding)
148
+ const constDeclarations = constObjects.map(c => `export declare const ${c.name}: ${c.type};`).join('\n');
149
+ // Include enums
150
+ const enumDeclarations = enumObjects.map(e => {
151
+ const members = e.members.map(m => m.initializer ? `${m.name} = ${m.initializer}` : `${m.name}`).join(', ');
152
+ return `export declare enum ${e.name} { ${members} }`;
153
+ }).join('\n');
145
154
  const dependencies = [
146
155
  typeAliasDeclarations,
156
+ constDeclarations,
157
+ enumDeclarations,
147
158
  // Include Methods interfaces as dependencies
148
159
  methods.map(object => {
149
160
  const methodDeclarations = object.methods.map(method => {