@openwebf/webf 0.23.7 → 0.24.0

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/dist/module.js ADDED
@@ -0,0 +1,487 @@
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.generateModuleArtifacts = generateModuleArtifacts;
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const typescript_1 = __importDefault(require("typescript"));
10
+ const lodash_1 = __importDefault(require("lodash"));
11
+ const generator_1 = require("./generator");
12
+ function parseModuleDefinition(modulePath) {
13
+ const sourceText = fs_1.default.readFileSync(modulePath, 'utf-8');
14
+ const sourceFile = typescript_1.default.createSourceFile(modulePath, sourceText, typescript_1.default.ScriptTarget.ES2020, true, typescript_1.default.ScriptKind.TS);
15
+ let interfaceDecl;
16
+ const supporting = [];
17
+ for (const stmt of sourceFile.statements) {
18
+ if (typescript_1.default.isInterfaceDeclaration(stmt)) {
19
+ const name = stmt.name.text;
20
+ if (!interfaceDecl && name.startsWith('WebF')) {
21
+ interfaceDecl = stmt;
22
+ }
23
+ supporting.push(stmt);
24
+ }
25
+ else if (typescript_1.default.isTypeAliasDeclaration(stmt) ||
26
+ typescript_1.default.isEnumDeclaration(stmt) ||
27
+ typescript_1.default.isVariableStatement(stmt)) {
28
+ supporting.push(stmt);
29
+ }
30
+ }
31
+ if (!interfaceDecl) {
32
+ throw new Error(`No interface starting with "WebF" found in module interface file: ${modulePath}`);
33
+ }
34
+ const interfaceName = interfaceDecl.name.text;
35
+ const moduleName = interfaceName.startsWith('WebF')
36
+ ? interfaceName.substring('WebF'.length)
37
+ : interfaceName;
38
+ const printer = typescript_1.default.createPrinter();
39
+ const methods = [];
40
+ for (const member of interfaceDecl.members) {
41
+ if (!typescript_1.default.isMethodSignature(member))
42
+ continue;
43
+ const nameNode = member.name;
44
+ const methodName = nameNode.getText(sourceFile);
45
+ if (!methodName || methodName === 'constructor')
46
+ continue;
47
+ const params = member.parameters.map(param => ({
48
+ name: param.name.getText(sourceFile),
49
+ text: printer.printNode(typescript_1.default.EmitHint.Unspecified, param, sourceFile),
50
+ typeText: param.type
51
+ ? printer.printNode(typescript_1.default.EmitHint.Unspecified, param.type, sourceFile)
52
+ : 'any',
53
+ }));
54
+ const returnTypeText = member.type
55
+ ? printer.printNode(typescript_1.default.EmitHint.Unspecified, member.type, sourceFile)
56
+ : 'Promise<any>';
57
+ let documentation;
58
+ const jsDocs = member.jsDoc;
59
+ if (jsDocs && jsDocs.length > 0) {
60
+ documentation = jsDocs
61
+ .map(doc => doc.comment)
62
+ .filter(Boolean)
63
+ .join('\n');
64
+ }
65
+ methods.push({
66
+ name: methodName,
67
+ jsName: methodName,
68
+ params,
69
+ returnTypeText,
70
+ documentation,
71
+ });
72
+ }
73
+ if (methods.length === 0) {
74
+ throw new Error(`Interface ${interfaceName} in ${modulePath} does not declare any methods`);
75
+ }
76
+ return { interfaceName, moduleName, methods, supportingStatements: supporting, sourceFile };
77
+ }
78
+ function buildTypesFile(def) {
79
+ const printer = typescript_1.default.createPrinter();
80
+ const lines = [];
81
+ lines.push('// AUTO GENERATED FILE, DO NOT EDIT.');
82
+ lines.push('//');
83
+ lines.push('// Generated by `webf module-codegen`');
84
+ lines.push('');
85
+ for (const stmt of def.supportingStatements) {
86
+ // Skip the main module interface (e.g. WebFShare); we only want supporting types.
87
+ if (typescript_1.default.isInterfaceDeclaration(stmt) && stmt.name.text === def.interfaceName) {
88
+ continue;
89
+ }
90
+ let printed = printer.printNode(typescript_1.default.EmitHint.Unspecified, stmt, def.sourceFile);
91
+ // Ensure declarations are exported so types.ts is a proper module.
92
+ if (typescript_1.default.isInterfaceDeclaration(stmt) ||
93
+ typescript_1.default.isTypeAliasDeclaration(stmt) ||
94
+ typescript_1.default.isEnumDeclaration(stmt)) {
95
+ const trimmed = printed.trimStart();
96
+ if (!trimmed.startsWith('export ')) {
97
+ const leadingLength = printed.length - trimmed.length;
98
+ const leading = printed.slice(0, leadingLength);
99
+ printed = `${leading}export ${trimmed}`;
100
+ }
101
+ }
102
+ lines.push(printed);
103
+ }
104
+ lines.push('');
105
+ // Ensure file is treated as a module even if no declarations were emitted.
106
+ lines.push('export {};');
107
+ return lines.join('\n');
108
+ }
109
+ function buildIndexFile(def) {
110
+ const lines = [];
111
+ lines.push('/**');
112
+ lines.push(` * Auto-generated WebF module wrapper for "${def.moduleName}".`);
113
+ lines.push(' *');
114
+ lines.push(' * This file is generated from a TypeScript interface that describes');
115
+ lines.push(' * the module API. It forwards calls to `webf.invokeModuleAsync` at runtime.');
116
+ lines.push(' */');
117
+ lines.push('');
118
+ lines.push(`import { webf } from '@openwebf/webf-enterprise-typings';`);
119
+ // Import option/result types purely as types so this stays tree-shake friendly.
120
+ const typeImportNames = new Set();
121
+ for (const stmt of def.supportingStatements) {
122
+ if (typescript_1.default.isInterfaceDeclaration(stmt) ||
123
+ typescript_1.default.isTypeAliasDeclaration(stmt) ||
124
+ typescript_1.default.isEnumDeclaration(stmt)) {
125
+ const name = stmt.name.text;
126
+ if (name === def.interfaceName)
127
+ continue;
128
+ typeImportNames.add(name);
129
+ }
130
+ }
131
+ const typeImportsSorted = Array.from(typeImportNames).sort();
132
+ if (typeImportsSorted.length > 0) {
133
+ lines.push(`import type { ${typeImportsSorted.join(', ')} } from './types';`);
134
+ }
135
+ lines.push('');
136
+ lines.push(`export class ${def.interfaceName} {`);
137
+ lines.push(' static isAvailable(): boolean {');
138
+ lines.push(" return typeof webf !== 'undefined' && typeof (webf as any).invokeModuleAsync === 'function';");
139
+ lines.push(' }');
140
+ lines.push('');
141
+ for (const method of def.methods) {
142
+ if (method.documentation) {
143
+ lines.push(' /**');
144
+ for (const line of method.documentation.split('\n')) {
145
+ lines.push(' * ' + line);
146
+ }
147
+ lines.push(' */');
148
+ }
149
+ const paramsText = method.params.map(p => p.text).join(', ');
150
+ const argNames = method.params.map(p => p.name).join(', ');
151
+ lines.push(` static async ${method.name}(${paramsText}): ${method.returnTypeText} {`);
152
+ lines.push(' if (!this.isAvailable()) {');
153
+ lines.push(` throw new Error('WebF module "${def.moduleName}" is not available. Make sure it is registered via WebF.defineModule().');`);
154
+ lines.push(' }');
155
+ const argsPart = argNames ? `, ${argNames}` : '';
156
+ lines.push(` return webf.invokeModuleAsync('${def.moduleName}', '${method.jsName}'${argsPart});`);
157
+ lines.push(' }');
158
+ lines.push('');
159
+ }
160
+ lines.push('}');
161
+ lines.push('');
162
+ lines.push(`export type {`);
163
+ const typeExportNames = new Set();
164
+ for (const stmt of def.supportingStatements) {
165
+ if (typescript_1.default.isInterfaceDeclaration(stmt) ||
166
+ typescript_1.default.isTypeAliasDeclaration(stmt) ||
167
+ typescript_1.default.isEnumDeclaration(stmt)) {
168
+ const name = stmt.name.text;
169
+ // Do not re-export the main module interface (e.g. WebFShare) to avoid clashes
170
+ // with the generated class of the same name.
171
+ if (name === def.interfaceName)
172
+ continue;
173
+ typeExportNames.add(stmt.name.text);
174
+ }
175
+ }
176
+ const sorted = Array.from(typeExportNames).sort();
177
+ if (sorted.length) {
178
+ lines.push(' ' + sorted.join(','));
179
+ }
180
+ lines.push(`} from './types';`);
181
+ lines.push('');
182
+ return lines.join('\n');
183
+ }
184
+ function mapTsReturnTypeToDart(typeText) {
185
+ const raw = typeText.trim();
186
+ // Expect Promise<...> for async module methods
187
+ const promiseMatch = raw.match(/^Promise<(.+)>$/);
188
+ if (!promiseMatch) {
189
+ return 'Future<dynamic>';
190
+ }
191
+ const inner = promiseMatch[1].trim();
192
+ const innerLower = inner.toLowerCase();
193
+ if (innerLower === 'boolean' || innerLower === 'bool') {
194
+ return 'Future<bool>';
195
+ }
196
+ return 'Future<dynamic>';
197
+ }
198
+ function isTsByteArrayUnion(typeText) {
199
+ if (!typeText)
200
+ return false;
201
+ // Remove parentheses and whitespace
202
+ const cleaned = typeText.replace(/[()]/g, '').trim();
203
+ if (!cleaned)
204
+ return false;
205
+ const parts = cleaned.split('|').map(p => p.trim()).filter(Boolean);
206
+ if (parts.length === 0)
207
+ return false;
208
+ const byteTypes = new Set(['ArrayBuffer', 'Uint8Array']);
209
+ const nullable = new Set(['null', 'undefined']);
210
+ let hasByte = false;
211
+ for (const part of parts) {
212
+ if (byteTypes.has(part)) {
213
+ hasByte = true;
214
+ continue;
215
+ }
216
+ if (nullable.has(part))
217
+ continue;
218
+ return false;
219
+ }
220
+ return hasByte;
221
+ }
222
+ function getBaseTypeName(typeText) {
223
+ if (!typeText)
224
+ return null;
225
+ const cleaned = typeText.replace(/[()]/g, '').trim();
226
+ if (!cleaned)
227
+ return null;
228
+ const parts = cleaned.split('|').map(p => p.trim()).filter(Boolean);
229
+ const nullable = new Set(['null', 'undefined', 'void', 'never']);
230
+ const nonNullable = parts.filter(p => !nullable.has(p));
231
+ if (nonNullable.length !== 1)
232
+ return null;
233
+ const candidate = nonNullable[0];
234
+ if (/^[A-Za-z_][A-Za-z0-9_]*$/.test(candidate)) {
235
+ return candidate;
236
+ }
237
+ return null;
238
+ }
239
+ function mapTsParamTypeToDart(typeText, optionNames) {
240
+ const raw = typeText.trim();
241
+ if (isTsByteArrayUnion(raw)) {
242
+ return { dartType: 'NativeByteData', isByteData: true };
243
+ }
244
+ const base = getBaseTypeName(raw);
245
+ if (base && optionNames.has(base)) {
246
+ return { dartType: `${base}?`, isByteData: false, optionClassName: base };
247
+ }
248
+ return { dartType: 'dynamic', isByteData: false };
249
+ }
250
+ function mapTsPropertyTypeToDart(type, optional) {
251
+ switch (type.kind) {
252
+ case typescript_1.default.SyntaxKind.StringKeyword:
253
+ return optional ? 'String?' : 'String';
254
+ case typescript_1.default.SyntaxKind.NumberKeyword:
255
+ return optional ? 'num?' : 'num';
256
+ case typescript_1.default.SyntaxKind.BooleanKeyword:
257
+ return optional ? 'bool?' : 'bool';
258
+ default:
259
+ return 'dynamic';
260
+ }
261
+ }
262
+ function buildDartBindings(def, command) {
263
+ const dartClassBase = `${def.moduleName}Module`;
264
+ const dartBindingsClass = `${dartClassBase}Bindings`;
265
+ const lines = [];
266
+ lines.push('// AUTO GENERATED FILE, DO NOT EDIT.');
267
+ lines.push('//');
268
+ lines.push('// Generated by `webf module-codegen`');
269
+ lines.push('');
270
+ lines.push("import 'package:webf/module.dart';");
271
+ if (def.methods.some(m => m.params.some(p => isTsByteArrayUnion(p.typeText)))) {
272
+ lines.push("import 'package:webf/bridge.dart';");
273
+ }
274
+ lines.push('');
275
+ // Generate Dart classes for supporting TS interfaces (compound option types).
276
+ const optionInterfaces = [];
277
+ for (const stmt of def.supportingStatements) {
278
+ if (typescript_1.default.isInterfaceDeclaration(stmt) && stmt.name.text !== def.interfaceName) {
279
+ optionInterfaces.push(stmt);
280
+ }
281
+ }
282
+ const optionTypeNames = new Set(optionInterfaces.map(i => i.name.text));
283
+ for (const iface of optionInterfaces) {
284
+ const name = iface.name.text;
285
+ const propInfos = [];
286
+ for (const member of iface.members) {
287
+ if (!typescript_1.default.isPropertySignature(member) || !member.name)
288
+ continue;
289
+ const key = member.name.getText(def.sourceFile).replace(/['"]/g, '');
290
+ const fieldName = key;
291
+ const optional = !!member.questionToken;
292
+ const dartType = member.type ? mapTsPropertyTypeToDart(member.type, optional) : 'dynamic';
293
+ propInfos.push({ fieldName, key, dartType, optional });
294
+ }
295
+ lines.push(`class ${name} {`);
296
+ for (const prop of propInfos) {
297
+ lines.push(` final ${prop.dartType} ${prop.fieldName};`);
298
+ }
299
+ lines.push('');
300
+ const ctorParams = propInfos.map(p => {
301
+ if (p.optional || p.dartType === 'dynamic') {
302
+ return `this.${p.fieldName}`;
303
+ }
304
+ return `required this.${p.fieldName}`;
305
+ }).join(', ');
306
+ lines.push(` const ${name}({${ctorParams}});`);
307
+ lines.push('');
308
+ lines.push(` factory ${name}.fromMap(Map<String, dynamic> map) {`);
309
+ lines.push(` return ${name}(`);
310
+ for (const prop of propInfos) {
311
+ const isString = prop.dartType.startsWith('String');
312
+ const isBool = prop.dartType.startsWith('bool');
313
+ const isNum = prop.dartType.startsWith('num');
314
+ if (isString) {
315
+ if (prop.optional) {
316
+ lines.push(` ${prop.fieldName}: map['${prop.key}']?.toString(),`);
317
+ }
318
+ else {
319
+ lines.push(` ${prop.fieldName}: map['${prop.key}']?.toString() ?? '',`);
320
+ }
321
+ }
322
+ else if (isBool) {
323
+ if (prop.optional) {
324
+ lines.push(` ${prop.fieldName}: map['${prop.key}'] is bool ? map['${prop.key}'] as bool : null,`);
325
+ }
326
+ else {
327
+ lines.push(` ${prop.fieldName}: map['${prop.key}'] is bool ? map['${prop.key}'] as bool : false,`);
328
+ }
329
+ }
330
+ else if (isNum) {
331
+ if (prop.optional) {
332
+ lines.push(` ${prop.fieldName}: map['${prop.key}'] is num ? map['${prop.key}'] as num : null,`);
333
+ }
334
+ else {
335
+ lines.push(` ${prop.fieldName}: map['${prop.key}'] is num ? map['${prop.key}'] as num : 0,`);
336
+ }
337
+ }
338
+ else {
339
+ lines.push(` ${prop.fieldName}: map['${prop.key}'],`);
340
+ }
341
+ }
342
+ lines.push(' );');
343
+ lines.push(' }');
344
+ lines.push('');
345
+ lines.push(' Map<String, dynamic> toMap() {');
346
+ lines.push(' final map = <String, dynamic>{};');
347
+ for (const prop of propInfos) {
348
+ if (!prop.optional && (prop.dartType === 'String' || prop.dartType === 'bool' || prop.dartType === 'num')) {
349
+ lines.push(` map['${prop.key}'] = ${prop.fieldName};`);
350
+ }
351
+ else {
352
+ lines.push(` if (${prop.fieldName} != null) { map['${prop.key}'] = ${prop.fieldName}; }`);
353
+ }
354
+ }
355
+ lines.push(' return map;');
356
+ lines.push(' }');
357
+ lines.push('');
358
+ lines.push(' Map<String, dynamic> toJson() => toMap();');
359
+ lines.push('}');
360
+ lines.push('');
361
+ }
362
+ lines.push(`abstract class ${dartBindingsClass} extends WebFBaseModule {`);
363
+ lines.push(` ${dartBindingsClass}(super.moduleManager);`);
364
+ lines.push('');
365
+ lines.push(` @override`);
366
+ lines.push(` String get name => '${def.moduleName}';`);
367
+ lines.push('');
368
+ for (const method of def.methods) {
369
+ const dartMethodName = lodash_1.default.camelCase(method.name);
370
+ let dartReturnType = mapTsReturnTypeToDart(method.returnTypeText);
371
+ // If the Promise inner type is one of the option interfaces, map return type to that Dart class.
372
+ const promiseMatch = method.returnTypeText.trim().match(/^Promise<(.+)>$/);
373
+ if (promiseMatch) {
374
+ const inner = promiseMatch[1].trim();
375
+ const baseInner = getBaseTypeName(inner);
376
+ if (baseInner && optionTypeNames.has(baseInner)) {
377
+ dartReturnType = `Future<${baseInner}>`;
378
+ }
379
+ }
380
+ const paramInfos = [];
381
+ method.params.forEach((p, index) => {
382
+ const mapped = mapTsParamTypeToDart(p.typeText, optionTypeNames);
383
+ paramInfos.push({
384
+ name: p.name,
385
+ index,
386
+ dartType: mapped.dartType,
387
+ optionClass: mapped.optionClassName,
388
+ });
389
+ });
390
+ const dartParams = paramInfos
391
+ .map(info => `${info.dartType} ${info.name}`)
392
+ .join(', ');
393
+ lines.push(` ${dartReturnType} ${dartMethodName}(${dartParams});`);
394
+ }
395
+ lines.push('');
396
+ lines.push(' @override');
397
+ lines.push(' Future<dynamic> invoke(String method, List<dynamic> params) async {');
398
+ lines.push(' switch (method) {');
399
+ for (const method of def.methods) {
400
+ const dartMethodName = lodash_1.default.camelCase(method.name);
401
+ const paramInfos = [];
402
+ method.params.forEach((p, index) => {
403
+ const mapped = mapTsParamTypeToDart(p.typeText, optionTypeNames);
404
+ paramInfos.push({
405
+ name: p.name,
406
+ index,
407
+ dartType: mapped.dartType,
408
+ optionClass: mapped.optionClassName,
409
+ });
410
+ });
411
+ // Detect if this method returns a structured Dart class (from TS interface),
412
+ // in which case we should convert the result back to a Map for JS.
413
+ let structuredReturnClass = null;
414
+ const retMatch = method.returnTypeText.trim().match(/^Promise<(.+)>$/);
415
+ if (retMatch) {
416
+ const inner = retMatch[1].trim();
417
+ const baseInner = getBaseTypeName(inner);
418
+ if (baseInner && optionTypeNames.has(baseInner)) {
419
+ structuredReturnClass = baseInner;
420
+ }
421
+ }
422
+ lines.push(` case '${method.jsName}': {`);
423
+ // Preprocess option-type parameters (Map -> Dart class instance)
424
+ for (const info of paramInfos) {
425
+ if (!info.optionClass)
426
+ continue;
427
+ const rawVar = `_raw${info.index}`;
428
+ lines.push(` final ${rawVar} = params.length > ${info.index} ? params[${info.index}] : null;`);
429
+ lines.push(` final ${info.name} = ${rawVar} is Map`
430
+ + ` ? ${info.optionClass}.fromMap(Map<String, dynamic>.from(${rawVar} as Map))`
431
+ + ` : (${rawVar} as ${info.optionClass}?);`);
432
+ }
433
+ if (paramInfos.length === 0) {
434
+ if (structuredReturnClass) {
435
+ lines.push(` final result = await ${dartMethodName}();`);
436
+ lines.push(' return result.toMap();');
437
+ }
438
+ else {
439
+ lines.push(` return ${dartMethodName}();`);
440
+ }
441
+ }
442
+ else {
443
+ const callArgs = paramInfos
444
+ .map(info => info.optionClass
445
+ ? info.name
446
+ : `params.length > ${info.index} ? params[${info.index}] : null`)
447
+ .join(', ');
448
+ if (structuredReturnClass) {
449
+ lines.push(` final result = await ${dartMethodName}(${callArgs});`);
450
+ lines.push(' return result.toMap();');
451
+ }
452
+ else {
453
+ lines.push(` return ${dartMethodName}(${callArgs});`);
454
+ }
455
+ }
456
+ lines.push(' }');
457
+ }
458
+ lines.push(' default:');
459
+ lines.push(" throw Exception('Unknown method for module ${name}: $method');");
460
+ lines.push(' }');
461
+ lines.push(' }');
462
+ lines.push('}');
463
+ lines.push('');
464
+ return lines.join('\n');
465
+ }
466
+ function generateModuleArtifacts(params) {
467
+ const def = parseModuleDefinition(params.moduleInterfacePath);
468
+ const srcDir = path_1.default.join(params.npmTargetDir, 'src');
469
+ if (!fs_1.default.existsSync(srcDir)) {
470
+ fs_1.default.mkdirSync(srcDir, { recursive: true });
471
+ }
472
+ const typesContent = buildTypesFile(def);
473
+ const typesPath = path_1.default.join(srcDir, 'types.ts');
474
+ (0, generator_1.writeFileIfChanged)(typesPath, typesContent);
475
+ const indexContent = buildIndexFile(def);
476
+ const indexPath = path_1.default.join(srcDir, 'index.ts');
477
+ (0, generator_1.writeFileIfChanged)(indexPath, indexContent);
478
+ const dartBindingsContent = buildDartBindings(def, params.command);
479
+ const dartDir = path_1.default.join(params.flutterPackageDir, 'lib', 'src');
480
+ if (!fs_1.default.existsSync(dartDir)) {
481
+ fs_1.default.mkdirSync(dartDir, { recursive: true });
482
+ }
483
+ const dartFileName = `${lodash_1.default.snakeCase(def.moduleName)}_module_bindings_generated.dart`;
484
+ const dartBindingsPath = path_1.default.join(dartDir, dartFileName);
485
+ (0, generator_1.writeFileIfChanged)(dartBindingsPath, dartBindingsContent);
486
+ return { indexPath, typesPath, dartBindingsPath };
487
+ }
@@ -0,0 +1,27 @@
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.readJsonFile = readJsonFile;
7
+ exports.getPackageTypesFileFromDir = getPackageTypesFileFromDir;
8
+ exports.isPackageTypesReady = isPackageTypesReady;
9
+ const fs_1 = __importDefault(require("fs"));
10
+ const path_1 = __importDefault(require("path"));
11
+ function readJsonFile(jsonPath) {
12
+ return JSON.parse(fs_1.default.readFileSync(jsonPath, 'utf-8'));
13
+ }
14
+ function getPackageTypesFileFromDir(pkgDir) {
15
+ const pkgJsonPath = path_1.default.join(pkgDir, 'package.json');
16
+ if (!fs_1.default.existsSync(pkgJsonPath))
17
+ return null;
18
+ const pkgJson = readJsonFile(pkgJsonPath);
19
+ const typesRel = pkgJson.types;
20
+ if (!typesRel)
21
+ return null;
22
+ return path_1.default.join(pkgDir, typesRel);
23
+ }
24
+ function isPackageTypesReady(pkgDir) {
25
+ const typesFile = getPackageTypesFileFromDir(pkgDir);
26
+ return typesFile ? fs_1.default.existsSync(typesFile) : true;
27
+ }
package/dist/react.js CHANGED
@@ -55,14 +55,13 @@ function generateReturnType(type) {
55
55
  return pointerType;
56
56
  }
57
57
  if (type.isArray && typeof type.value === 'object' && !Array.isArray(type.value)) {
58
- const elemType = (0, utils_1.getPointerType)(type.value);
59
- // Map arrays of Dart `Type` to `any[]` in TS; parenthesize typeof
60
- if (elemType === 'Type')
58
+ const elemType = generateReturnType(type.value);
59
+ if (!elemType)
61
60
  return 'any[]';
62
- if (typeof elemType === 'string' && elemType.startsWith('typeof ')) {
63
- return `(${elemType})[]`;
61
+ if (/^[A-Za-z_][A-Za-z0-9_]*(?:\\.[A-Za-z_][A-Za-z0-9_]*)*$/.test(elemType)) {
62
+ return `${elemType}[]`;
64
63
  }
65
- return `${elemType}[]`;
64
+ return `(${elemType})[]`;
66
65
  }
67
66
  switch (type.value) {
68
67
  case declaration_1.FunctionArgumentType.int:
@@ -348,20 +347,13 @@ function generateReactComponent(blob, packageName, relativeDir) {
348
347
  return pointerType;
349
348
  }
350
349
  if (type.isArray && typeof type.value === 'object' && !Array.isArray(type.value)) {
351
- const elemType = (0, utils_1.getPointerType)(type.value);
352
- if (elemType === 'Type')
350
+ const elemType = genRT(type.value);
351
+ if (!elemType)
353
352
  return 'any[]';
354
- if (typeof elemType === 'string' && elemType.startsWith('typeof ')) {
355
- const ident = elemType.substring('typeof '.length).trim();
356
- return `(typeof __webfTypes.${ident})[]`;
357
- }
358
- if (typeof elemType === 'string' && /^(?:[A-Za-z_][A-Za-z0-9_]*)(?:\.[A-Za-z_][A-Za-z0-9_]*)*$/.test(elemType)) {
359
- const base = elemType.split('.')[0];
360
- if (!localTypeNames.has(base)) {
361
- return `__webfTypes.${elemType}[]`;
362
- }
353
+ if (/^[A-Za-z_][A-Za-z0-9_]*(?:\\.[A-Za-z_][A-Za-z0-9_]*)*$/.test(elemType)) {
354
+ return `${elemType}[]`;
363
355
  }
364
- return `${elemType}[]`;
356
+ return `(${elemType})[]`;
365
357
  }
366
358
  switch (type.value) {
367
359
  case declaration_1.FunctionArgumentType.int: