@openwebf/webf 0.22.13 → 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
@@ -233,11 +271,17 @@ function createCommand(target, options) {
233
271
  fs_1.default.mkdirSync(srcDir, { recursive: true });
234
272
  }
235
273
  const indexFilePath = path_1.default.join(srcDir, 'index.ts');
236
- const indexContent = lodash_1.default.template(reactIndexTpl)({
237
- components: [],
238
- });
239
- writeFileIfChanged(indexFilePath, indexContent);
240
- (0, child_process_1.spawnSync)(NPM, ['install', '--omit=peer'], {
274
+ if (!fs_1.default.existsSync(indexFilePath)) {
275
+ const indexContent = lodash_1.default.template(reactIndexTpl)({
276
+ components: [],
277
+ });
278
+ writeFileIfChanged(indexFilePath, indexContent);
279
+ }
280
+ else {
281
+ // Do not overwrite existing index.ts created by the user
282
+ // Leave merge to the codegen step which appends exports safely
283
+ }
284
+ (0, child_process_1.spawnSync)(NPM, ['install'], {
241
285
  cwd: target,
242
286
  stdio: 'inherit'
243
287
  });
@@ -503,7 +547,9 @@ function generateCommand(distPath, options) {
503
547
  target: resolvedDistPath,
504
548
  command,
505
549
  exclude: options.exclude,
506
- packageName: reactPackageName,
550
+ // Prefer CLI-provided packageName (validated/sanitized above),
551
+ // fallback to detected name from package.json
552
+ packageName: packageName || reactPackageName,
507
553
  });
508
554
  }
509
555
  else if (framework === 'vue') {
@@ -519,6 +565,18 @@ function generateCommand(distPath, options) {
519
565
  if (framework) {
520
566
  try {
521
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
+ }
522
580
  }
523
581
  catch (error) {
524
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
+ }
package/dist/dart.js CHANGED
@@ -80,6 +80,12 @@ ${enumValues};
80
80
  }`;
81
81
  }
82
82
  function generateReturnType(type, enumName) {
83
+ // Handle union types first (e.g., 'left' | 'center' | 'right')
84
+ // so we don't incorrectly treat string literal unions as pointer types.
85
+ if (Array.isArray(type.value)) {
86
+ // If we have an enum name, use it; otherwise fall back to String
87
+ return enumName || 'String';
88
+ }
83
89
  if ((0, utils_1.isPointerType)(type)) {
84
90
  const pointerType = (0, utils_1.getPointerType)(type);
85
91
  return pointerType;
@@ -87,11 +93,6 @@ function generateReturnType(type, enumName) {
87
93
  if (type.isArray && typeof type.value === 'object' && !Array.isArray(type.value)) {
88
94
  return `${(0, utils_1.getPointerType)(type.value)}[]`;
89
95
  }
90
- // Handle union types (e.g., 'left' | 'center' | 'right')
91
- if (Array.isArray(type.value)) {
92
- // If we have an enum name, use it; otherwise fall back to String
93
- return enumName || 'String';
94
- }
95
96
  // Handle when type.value is a ParameterType object (nested type)
96
97
  if (typeof type.value === 'object' && !Array.isArray(type.value) && type.value !== null) {
97
98
  // This might be a nested ParameterType, recurse
@@ -250,7 +251,7 @@ interface ${object.name} {
250
251
  }
251
252
  // Generate enums for union types
252
253
  const enums = [];
253
- const enumMap = new Map(); // prop name -> enum name
254
+ const enumMap = new Map(); // camelCase prop name -> enum name
254
255
  if (componentProperties) {
255
256
  for (const prop of componentProperties.props) {
256
257
  if (isStringUnionType(prop.type)) {
@@ -261,7 +262,8 @@ interface ${object.name} {
261
262
  name: enumName,
262
263
  definition: generateDartEnum(enumName, values)
263
264
  });
264
- enumMap.set(prop.name, enumName);
265
+ // Store by camelCase prop name to match template usage
266
+ enumMap.set(lodash_1.default.camelCase(prop.name), enumName);
265
267
  }
266
268
  }
267
269
  }
@@ -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;