@openwebf/webf 0.23.2 → 0.23.7
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 +5 -1
- package/bin/webf.js +1 -0
- package/dist/analyzer.js +65 -1
- package/dist/commands.js +198 -98
- package/dist/dart.js +91 -25
- package/dist/declaration.js +1 -0
- package/dist/generator.js +26 -17
- package/dist/react.js +272 -25
- package/dist/vue.js +74 -11
- package/package.json +1 -1
- package/src/analyzer.ts +58 -2
- package/src/commands.ts +300 -196
- package/src/dart.ts +95 -20
- package/src/declaration.ts +1 -0
- package/src/generator.ts +24 -16
- package/src/react.ts +288 -29
- package/src/vue.ts +85 -13
- package/templates/class.dart.tpl +1 -1
- package/templates/vue.components.d.ts.tpl +2 -0
- package/test/commands.test.ts +82 -2
- package/test/dart-nullable-props.test.ts +58 -0
- 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/dist/vue.js
CHANGED
|
@@ -8,17 +8,61 @@ const lodash_1 = __importDefault(require("lodash"));
|
|
|
8
8
|
const fs_1 = __importDefault(require("fs"));
|
|
9
9
|
const path_1 = __importDefault(require("path"));
|
|
10
10
|
const declaration_1 = require("./declaration");
|
|
11
|
+
const logger_1 = require("./logger");
|
|
11
12
|
const utils_1 = require("./utils");
|
|
12
13
|
function readTemplate(name) {
|
|
13
14
|
return fs_1.default.readFileSync(path_1.default.join(__dirname, '../templates/' + name + '.tpl'), { encoding: 'utf-8' });
|
|
14
15
|
}
|
|
15
16
|
function generateReturnType(type) {
|
|
17
|
+
if ((0, utils_1.isUnionType)(type)) {
|
|
18
|
+
const values = type.value;
|
|
19
|
+
return values.map(v => {
|
|
20
|
+
if (v.value === declaration_1.FunctionArgumentType.null) {
|
|
21
|
+
return 'null';
|
|
22
|
+
}
|
|
23
|
+
if (typeof v.value === 'string') {
|
|
24
|
+
return `'${v.value}'`;
|
|
25
|
+
}
|
|
26
|
+
return 'any';
|
|
27
|
+
}).join(' | ');
|
|
28
|
+
}
|
|
29
|
+
// Handle unions like boolean | null, number | null, CustomType | null
|
|
30
|
+
if (Array.isArray(type.value)) {
|
|
31
|
+
const values = type.value;
|
|
32
|
+
const hasNull = values.some(v => v.value === declaration_1.FunctionArgumentType.null);
|
|
33
|
+
if (hasNull) {
|
|
34
|
+
const nonNulls = values.filter(v => v.value !== declaration_1.FunctionArgumentType.null);
|
|
35
|
+
if (nonNulls.length === 0) {
|
|
36
|
+
return 'null';
|
|
37
|
+
}
|
|
38
|
+
const parts = nonNulls.map(v => generateReturnType(v));
|
|
39
|
+
const unique = Array.from(new Set(parts));
|
|
40
|
+
unique.push('null');
|
|
41
|
+
return unique.join(' | ');
|
|
42
|
+
}
|
|
43
|
+
// Complex non-null unions are rare; fall back to any
|
|
44
|
+
return 'any';
|
|
45
|
+
}
|
|
16
46
|
if ((0, utils_1.isPointerType)(type)) {
|
|
17
47
|
const pointerType = (0, utils_1.getPointerType)(type);
|
|
48
|
+
// Map Dart's `Type` (from TS typeof) to TS `any`
|
|
49
|
+
if (pointerType === 'Type')
|
|
50
|
+
return 'any';
|
|
51
|
+
if (typeof pointerType === 'string' && pointerType.startsWith('typeof ')) {
|
|
52
|
+
const ident = pointerType.substring('typeof '.length).trim();
|
|
53
|
+
return `typeof __webfTypes.${ident}`;
|
|
54
|
+
}
|
|
18
55
|
return pointerType;
|
|
19
56
|
}
|
|
20
57
|
if (type.isArray && typeof type.value === 'object' && !Array.isArray(type.value)) {
|
|
21
|
-
|
|
58
|
+
const elemType = (0, utils_1.getPointerType)(type.value);
|
|
59
|
+
if (elemType === 'Type')
|
|
60
|
+
return 'any[]';
|
|
61
|
+
if (typeof elemType === 'string' && elemType.startsWith('typeof ')) {
|
|
62
|
+
const ident = elemType.substring('typeof '.length).trim();
|
|
63
|
+
return `(typeof __webfTypes.${ident})[]`;
|
|
64
|
+
}
|
|
65
|
+
return `${elemType}[]`;
|
|
22
66
|
}
|
|
23
67
|
switch (type.value) {
|
|
24
68
|
case declaration_1.FunctionArgumentType.int:
|
|
@@ -87,19 +131,34 @@ function generateVueComponent(blob) {
|
|
|
87
131
|
&& !object.name.endsWith('Events');
|
|
88
132
|
});
|
|
89
133
|
const dependencies = others.map(object => {
|
|
90
|
-
if (!object || !object.props) {
|
|
134
|
+
if (!object || !object.props || object.props.length === 0) {
|
|
91
135
|
return '';
|
|
92
136
|
}
|
|
93
|
-
const
|
|
94
|
-
|
|
95
|
-
|
|
137
|
+
const interfaceLines = [];
|
|
138
|
+
if (object.documentation && object.documentation.trim().length > 0) {
|
|
139
|
+
interfaceLines.push('/**');
|
|
140
|
+
object.documentation.split('\n').forEach(line => {
|
|
141
|
+
interfaceLines.push(` * ${line}`);
|
|
142
|
+
});
|
|
143
|
+
interfaceLines.push(' */');
|
|
144
|
+
}
|
|
145
|
+
interfaceLines.push(`interface ${object.name} {`);
|
|
146
|
+
const propLines = object.props.map(prop => {
|
|
147
|
+
const lines = [];
|
|
148
|
+
if (prop.documentation && prop.documentation.trim().length > 0) {
|
|
149
|
+
lines.push(' /**');
|
|
150
|
+
prop.documentation.split('\n').forEach(line => {
|
|
151
|
+
lines.push(` * ${line}`);
|
|
152
|
+
});
|
|
153
|
+
lines.push(' */');
|
|
96
154
|
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
}
|
|
155
|
+
const optionalToken = prop.optional ? '?' : '';
|
|
156
|
+
lines.push(` ${prop.name}${optionalToken}: ${generateReturnType(prop.type)};`);
|
|
157
|
+
return lines.join('\n');
|
|
158
|
+
});
|
|
159
|
+
interfaceLines.push(propLines.join('\n'));
|
|
160
|
+
interfaceLines.push('}');
|
|
161
|
+
return interfaceLines.join('\n');
|
|
103
162
|
}).filter(dep => dep.trim() !== '').join('\n\n');
|
|
104
163
|
const componentProperties = properties.length > 0 ? properties[0] : undefined;
|
|
105
164
|
const componentEvents = events.length > 0 ? events[0] : undefined;
|
|
@@ -192,6 +251,9 @@ function generateVueTypings(blobs) {
|
|
|
192
251
|
const members = e.members.map(m => m.initializer ? `${m.name} = ${m.initializer}` : `${m.name}`).join(', ');
|
|
193
252
|
return `export declare enum ${e.name} { ${members} }`;
|
|
194
253
|
}).join('\n');
|
|
254
|
+
// Always import the types namespace to support typeof references
|
|
255
|
+
const typesImport = `import * as __webfTypes from './src/types';`;
|
|
256
|
+
(0, logger_1.debug)(`[vue] Generating typings; importing types from ./src/types`);
|
|
195
257
|
// Build mapping of template tag names to class names for GlobalComponents
|
|
196
258
|
const componentMetas = componentNames.map(className => ({
|
|
197
259
|
className,
|
|
@@ -207,6 +269,7 @@ function generateVueTypings(blobs) {
|
|
|
207
269
|
components,
|
|
208
270
|
consts: constDeclarations,
|
|
209
271
|
enums: enumDeclarations,
|
|
272
|
+
typesImport,
|
|
210
273
|
});
|
|
211
274
|
return content.split('\n').filter(str => {
|
|
212
275
|
return str.trim().length > 0;
|
package/package.json
CHANGED
package/src/analyzer.ts
CHANGED
|
@@ -286,6 +286,20 @@ function getParameterBaseType(type: ts.TypeNode, mode?: ParameterMode): Paramete
|
|
|
286
286
|
return basicType;
|
|
287
287
|
}
|
|
288
288
|
|
|
289
|
+
// Handle `typeof SomeIdentifier` (TypeQuery) by preserving the textual form
|
|
290
|
+
// so React/Vue can keep strong typing (e.g., `typeof CupertinoIcons`).
|
|
291
|
+
// Dart mapping will convert this to `dynamic` later.
|
|
292
|
+
if (type.kind === ts.SyntaxKind.TypeQuery) {
|
|
293
|
+
const tq = type as ts.TypeQueryNode;
|
|
294
|
+
const getEntityNameText = (name: ts.EntityName): string => {
|
|
295
|
+
if (ts.isIdentifier(name)) return name.text;
|
|
296
|
+
// Qualified name: A.B.C
|
|
297
|
+
return `${getEntityNameText(name.left)}.${name.right.text}`;
|
|
298
|
+
};
|
|
299
|
+
const nameText = getEntityNameText(tq.exprName);
|
|
300
|
+
return `typeof ${nameText}`;
|
|
301
|
+
}
|
|
302
|
+
|
|
289
303
|
if (type.kind === ts.SyntaxKind.TypeReference) {
|
|
290
304
|
const typeReference = type as ts.TypeReferenceNode;
|
|
291
305
|
const typeName = typeReference.typeName;
|
|
@@ -405,7 +419,45 @@ function handleCustomEventType(typeReference: ts.TypeReferenceNode): ParameterBa
|
|
|
405
419
|
const argument = typeReference.typeArguments[0];
|
|
406
420
|
let genericType: string;
|
|
407
421
|
|
|
408
|
-
|
|
422
|
+
// Preserve simple union/compound generic types (e.g., boolean | null)
|
|
423
|
+
if (ts.isUnionTypeNode(argument) || ts.isIntersectionTypeNode(argument)) {
|
|
424
|
+
const unionTypes = (argument as ts.UnionTypeNode | ts.IntersectionTypeNode).types ?? [];
|
|
425
|
+
const parts = unionTypes.map(t => {
|
|
426
|
+
// Literal union members: handle null/undefined explicitly
|
|
427
|
+
if (ts.isLiteralTypeNode(t)) {
|
|
428
|
+
const lit = t.literal;
|
|
429
|
+
if (lit.kind === ts.SyntaxKind.NullKeyword) return 'null';
|
|
430
|
+
if (lit.kind === ts.SyntaxKind.UndefinedKeyword) return 'undefined';
|
|
431
|
+
if (ts.isStringLiteral(lit)) return JSON.stringify(lit.text);
|
|
432
|
+
return 'any';
|
|
433
|
+
}
|
|
434
|
+
// Basic keywords: boolean, string, number, null, undefined
|
|
435
|
+
const basic = BASIC_TYPE_MAP[t.kind];
|
|
436
|
+
if (basic !== undefined) {
|
|
437
|
+
switch (basic) {
|
|
438
|
+
case FunctionArgumentType.boolean:
|
|
439
|
+
return 'boolean';
|
|
440
|
+
case FunctionArgumentType.dom_string:
|
|
441
|
+
return 'string';
|
|
442
|
+
case FunctionArgumentType.double:
|
|
443
|
+
case FunctionArgumentType.int:
|
|
444
|
+
return 'number';
|
|
445
|
+
case FunctionArgumentType.null:
|
|
446
|
+
return 'null';
|
|
447
|
+
case FunctionArgumentType.undefined:
|
|
448
|
+
return 'undefined';
|
|
449
|
+
default:
|
|
450
|
+
return 'any';
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
// Literal null/undefined keywords that BASIC_TYPE_MAP may not cover
|
|
454
|
+
if (t.kind === ts.SyntaxKind.NullKeyword) return 'null';
|
|
455
|
+
if (t.kind === ts.SyntaxKind.UndefinedKeyword) return 'undefined';
|
|
456
|
+
// Fallback: rely on toString of node kind
|
|
457
|
+
return 'any';
|
|
458
|
+
});
|
|
459
|
+
genericType = parts.join(' | ');
|
|
460
|
+
} else if (ts.isTypeReferenceNode(argument) && ts.isIdentifier(argument.typeName)) {
|
|
409
461
|
const typeName = argument.typeName.text;
|
|
410
462
|
|
|
411
463
|
// Check if it's a mapped type reference like 'int' or 'double'
|
|
@@ -699,7 +751,11 @@ function processEnumDeclaration(
|
|
|
699
751
|
}
|
|
700
752
|
return mem;
|
|
701
753
|
});
|
|
702
|
-
|
|
754
|
+
|
|
755
|
+
// Register globally for cross-file lookups (e.g., Dart mapping decisions)
|
|
756
|
+
try {
|
|
757
|
+
EnumObject.globalEnumSet.add(enumObj.name);
|
|
758
|
+
} catch {}
|
|
703
759
|
return enumObj;
|
|
704
760
|
}
|
|
705
761
|
|