@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/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:**
|
|
@@ -229,4 +233,4 @@ npm link # Link for local testing
|
|
|
229
233
|
|
|
230
234
|
## License
|
|
231
235
|
|
|
232
|
-
ISC
|
|
236
|
+
ISC
|
package/bin/webf.js
CHANGED
|
@@ -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')
|
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
|
-
|
|
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) {
|
package/dist/commands.js
CHANGED
|
@@ -172,7 +172,8 @@ function readFlutterPackageMetadata(packagePath) {
|
|
|
172
172
|
return null;
|
|
173
173
|
}
|
|
174
174
|
}
|
|
175
|
-
// Copy markdown docs that match .d.ts basenames from source to the built dist folder
|
|
175
|
+
// Copy markdown docs that match .d.ts basenames from source to the built dist folder,
|
|
176
|
+
// and generate an aggregated README.md in the dist directory.
|
|
176
177
|
function copyMarkdownDocsToDist(params) {
|
|
177
178
|
return __awaiter(this, void 0, void 0, function* () {
|
|
178
179
|
const { sourceRoot, distRoot, exclude } = params;
|
|
@@ -187,6 +188,7 @@ function copyMarkdownDocsToDist(params) {
|
|
|
187
188
|
const dtsFiles = glob_1.glob.globSync('**/*.d.ts', { cwd: sourceRoot, ignore });
|
|
188
189
|
let copied = 0;
|
|
189
190
|
let skipped = 0;
|
|
191
|
+
const readmeSections = [];
|
|
190
192
|
for (const relDts of dtsFiles) {
|
|
191
193
|
if (path_1.default.basename(relDts) === 'global.d.ts') {
|
|
192
194
|
continue;
|
|
@@ -197,6 +199,13 @@ function copyMarkdownDocsToDist(params) {
|
|
|
197
199
|
skipped++;
|
|
198
200
|
continue;
|
|
199
201
|
}
|
|
202
|
+
let content = '';
|
|
203
|
+
try {
|
|
204
|
+
content = fs_1.default.readFileSync(absMd, 'utf-8');
|
|
205
|
+
}
|
|
206
|
+
catch (_a) {
|
|
207
|
+
// If we cannot read the file, still attempt to copy it and skip README aggregation for this entry.
|
|
208
|
+
}
|
|
200
209
|
// Copy into dist preserving relative path
|
|
201
210
|
const destPath = path_1.default.join(distRoot, relMd);
|
|
202
211
|
const destDir = path_1.default.dirname(destPath);
|
|
@@ -205,6 +214,61 @@ function copyMarkdownDocsToDist(params) {
|
|
|
205
214
|
}
|
|
206
215
|
fs_1.default.copyFileSync(absMd, destPath);
|
|
207
216
|
copied++;
|
|
217
|
+
if (content) {
|
|
218
|
+
const base = path_1.default.basename(relMd, '.md');
|
|
219
|
+
const title = base
|
|
220
|
+
.split(/[-_]+/)
|
|
221
|
+
.filter(Boolean)
|
|
222
|
+
.map(part => part.charAt(0).toUpperCase() + part.slice(1))
|
|
223
|
+
.join(' ');
|
|
224
|
+
readmeSections.push({
|
|
225
|
+
title: title || base,
|
|
226
|
+
relPath: relMd,
|
|
227
|
+
content
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
// Generate an aggregated README.md inside distRoot so consumers can see component docs easily.
|
|
232
|
+
if (readmeSections.length > 0) {
|
|
233
|
+
const readmePath = path_1.default.join(distRoot, 'README.md');
|
|
234
|
+
let existing = '';
|
|
235
|
+
if (fs_1.default.existsSync(readmePath)) {
|
|
236
|
+
try {
|
|
237
|
+
existing = fs_1.default.readFileSync(readmePath, 'utf-8');
|
|
238
|
+
}
|
|
239
|
+
catch (_b) {
|
|
240
|
+
existing = '';
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
const headerLines = [
|
|
244
|
+
'# WebF Component Documentation',
|
|
245
|
+
'',
|
|
246
|
+
'> This README is generated from markdown docs co-located with TypeScript definitions in the Flutter package.',
|
|
247
|
+
''
|
|
248
|
+
];
|
|
249
|
+
const sectionBlocks = readmeSections.map(section => {
|
|
250
|
+
const lines = [];
|
|
251
|
+
lines.push(`## ${section.title}`);
|
|
252
|
+
lines.push('');
|
|
253
|
+
lines.push(`_Source: \`./${section.relPath}\`_`);
|
|
254
|
+
lines.push('');
|
|
255
|
+
lines.push(section.content.trim());
|
|
256
|
+
lines.push('');
|
|
257
|
+
return lines.join('\n');
|
|
258
|
+
}).join('\n');
|
|
259
|
+
let finalContent;
|
|
260
|
+
if (existing && existing.trim().length > 0) {
|
|
261
|
+
finalContent = `${existing.trim()}\n\n---\n\n${headerLines.join('\n')}${sectionBlocks}\n`;
|
|
262
|
+
}
|
|
263
|
+
else {
|
|
264
|
+
finalContent = `${headerLines.join('\n')}${sectionBlocks}\n`;
|
|
265
|
+
}
|
|
266
|
+
try {
|
|
267
|
+
fs_1.default.writeFileSync(readmePath, finalContent, 'utf-8');
|
|
268
|
+
}
|
|
269
|
+
catch (_c) {
|
|
270
|
+
// If README generation fails, do not affect overall codegen.
|
|
271
|
+
}
|
|
208
272
|
}
|
|
209
273
|
return { copied, skipped };
|
|
210
274
|
});
|
|
@@ -281,6 +345,7 @@ function createCommand(target, options) {
|
|
|
281
345
|
// Do not overwrite existing index.ts created by the user
|
|
282
346
|
// Leave merge to the codegen step which appends exports safely
|
|
283
347
|
}
|
|
348
|
+
// !no '--omit=peer' here.
|
|
284
349
|
(0, child_process_1.spawnSync)(NPM, ['install'], {
|
|
285
350
|
cwd: target,
|
|
286
351
|
stdio: 'inherit'
|
|
@@ -317,12 +382,19 @@ function generateCommand(distPath, options) {
|
|
|
317
382
|
// If distPath is not provided or is '.', create a temporary directory
|
|
318
383
|
let resolvedDistPath;
|
|
319
384
|
let isTempDir = false;
|
|
385
|
+
const isDartOnly = options.dartOnly;
|
|
320
386
|
if (!distPath || distPath === '.') {
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
387
|
+
if (isDartOnly) {
|
|
388
|
+
// In Dart-only mode we don't need a temporary Node project directory
|
|
389
|
+
resolvedDistPath = path_1.default.resolve(distPath || '.');
|
|
390
|
+
}
|
|
391
|
+
else {
|
|
392
|
+
// Create a temporary directory for the generated package
|
|
393
|
+
const tempDir = fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), 'webf-typings-'));
|
|
394
|
+
resolvedDistPath = tempDir;
|
|
395
|
+
isTempDir = true;
|
|
396
|
+
console.log(`\nUsing temporary directory: ${tempDir}`);
|
|
397
|
+
}
|
|
326
398
|
}
|
|
327
399
|
else {
|
|
328
400
|
resolvedDistPath = path_1.default.resolve(distPath);
|
|
@@ -352,111 +424,123 @@ function generateCommand(distPath, options) {
|
|
|
352
424
|
console.log(`\nDetected Flutter package at: ${pubspecDir}`);
|
|
353
425
|
}
|
|
354
426
|
}
|
|
355
|
-
// Check if the directory exists and has required files
|
|
356
|
-
const packageJsonPath = path_1.default.join(resolvedDistPath, 'package.json');
|
|
357
|
-
const globalDtsPath = path_1.default.join(resolvedDistPath, 'global.d.ts');
|
|
358
|
-
const tsConfigPath = path_1.default.join(resolvedDistPath, 'tsconfig.json');
|
|
359
|
-
const hasPackageJson = fs_1.default.existsSync(packageJsonPath);
|
|
360
|
-
const hasGlobalDts = fs_1.default.existsSync(globalDtsPath);
|
|
361
|
-
const hasTsConfig = fs_1.default.existsSync(tsConfigPath);
|
|
362
|
-
// Determine if we need to create a new project
|
|
363
|
-
const needsProjectCreation = !hasPackageJson || !hasGlobalDts || !hasTsConfig;
|
|
364
|
-
// Track if this is an existing project (has all required files)
|
|
365
|
-
const isExistingProject = hasPackageJson && hasGlobalDts && hasTsConfig;
|
|
366
427
|
let framework = options.framework;
|
|
367
428
|
let packageName = options.packageName;
|
|
368
|
-
|
|
369
|
-
if (
|
|
370
|
-
|
|
371
|
-
const
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
if
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
if (
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
429
|
+
let isExistingProject = false;
|
|
430
|
+
if (!isDartOnly) {
|
|
431
|
+
// Check if the directory exists and has required files
|
|
432
|
+
const packageJsonPath = path_1.default.join(resolvedDistPath, 'package.json');
|
|
433
|
+
const globalDtsPath = path_1.default.join(resolvedDistPath, 'global.d.ts');
|
|
434
|
+
const tsConfigPath = path_1.default.join(resolvedDistPath, 'tsconfig.json');
|
|
435
|
+
const hasPackageJson = fs_1.default.existsSync(packageJsonPath);
|
|
436
|
+
const hasGlobalDts = fs_1.default.existsSync(globalDtsPath);
|
|
437
|
+
const hasTsConfig = fs_1.default.existsSync(tsConfigPath);
|
|
438
|
+
// Determine if we need to create a new project
|
|
439
|
+
const needsProjectCreation = !hasPackageJson || !hasGlobalDts || !hasTsConfig;
|
|
440
|
+
// Track if this is an existing project (has all required files)
|
|
441
|
+
isExistingProject = hasPackageJson && hasGlobalDts && hasTsConfig;
|
|
442
|
+
// Validate and sanitize package name if provided
|
|
443
|
+
if (packageName && !isValidNpmPackageName(packageName)) {
|
|
444
|
+
console.warn(`Warning: Package name "${packageName}" is not valid for npm.`);
|
|
445
|
+
const sanitized = sanitizePackageName(packageName);
|
|
446
|
+
console.log(`Using sanitized name: "${sanitized}"`);
|
|
447
|
+
packageName = sanitized;
|
|
448
|
+
}
|
|
449
|
+
if (needsProjectCreation) {
|
|
450
|
+
// If project needs creation but options are missing, prompt for them
|
|
451
|
+
if (!framework) {
|
|
452
|
+
const frameworkAnswer = yield inquirer_1.default.prompt([{
|
|
453
|
+
type: 'list',
|
|
454
|
+
name: 'framework',
|
|
455
|
+
message: 'Which framework would you like to use?',
|
|
456
|
+
choices: ['react', 'vue']
|
|
457
|
+
}]);
|
|
458
|
+
framework = frameworkAnswer.framework;
|
|
459
|
+
}
|
|
460
|
+
// Try to read Flutter package metadata if flutterPackageSrc is provided
|
|
461
|
+
let metadata = null;
|
|
462
|
+
if (options.flutterPackageSrc) {
|
|
463
|
+
metadata = readFlutterPackageMetadata(options.flutterPackageSrc);
|
|
464
|
+
}
|
|
465
|
+
if (!packageName) {
|
|
466
|
+
// Use Flutter package name as default if available, sanitized for npm
|
|
467
|
+
const rawDefaultName = (metadata === null || metadata === void 0 ? void 0 : metadata.name) || path_1.default.basename(resolvedDistPath);
|
|
468
|
+
const defaultPackageName = sanitizePackageName(rawDefaultName);
|
|
469
|
+
const packageNameAnswer = yield inquirer_1.default.prompt([{
|
|
470
|
+
type: 'input',
|
|
471
|
+
name: 'packageName',
|
|
472
|
+
message: 'What is your package name?',
|
|
473
|
+
default: defaultPackageName,
|
|
474
|
+
validate: (input) => {
|
|
475
|
+
if (!input || input.trim() === '') {
|
|
476
|
+
return 'Package name is required';
|
|
477
|
+
}
|
|
478
|
+
// Check if it's valid as-is
|
|
479
|
+
if (isValidNpmPackageName(input)) {
|
|
480
|
+
return true;
|
|
481
|
+
}
|
|
482
|
+
// If not valid, show what it would be sanitized to
|
|
483
|
+
const sanitized = sanitizePackageName(input);
|
|
484
|
+
return `Invalid npm package name. Would be sanitized to: "${sanitized}". Please enter a valid name.`;
|
|
407
485
|
}
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
486
|
+
}]);
|
|
487
|
+
packageName = packageNameAnswer.packageName;
|
|
488
|
+
}
|
|
489
|
+
console.log(`\nCreating new ${framework} project in ${resolvedDistPath}...`);
|
|
490
|
+
createCommand(resolvedDistPath, {
|
|
491
|
+
framework: framework,
|
|
492
|
+
packageName: packageName,
|
|
493
|
+
metadata: metadata || undefined
|
|
494
|
+
});
|
|
414
495
|
}
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
type: 'list',
|
|
439
|
-
name: 'framework',
|
|
440
|
-
message: 'Which framework are you using?',
|
|
441
|
-
choices: ['react', 'vue']
|
|
442
|
-
}]);
|
|
443
|
-
framework = frameworkAnswer.framework;
|
|
496
|
+
else {
|
|
497
|
+
// Validate existing project structure
|
|
498
|
+
if (hasPackageJson) {
|
|
499
|
+
try {
|
|
500
|
+
const packageJson = JSON.parse(fs_1.default.readFileSync(packageJsonPath, 'utf-8'));
|
|
501
|
+
// Detect framework from existing package.json
|
|
502
|
+
if (!framework) {
|
|
503
|
+
if (((_a = packageJson.dependencies) === null || _a === void 0 ? void 0 : _a.react) || ((_b = packageJson.devDependencies) === null || _b === void 0 ? void 0 : _b.react)) {
|
|
504
|
+
framework = 'react';
|
|
505
|
+
}
|
|
506
|
+
else if (((_c = packageJson.dependencies) === null || _c === void 0 ? void 0 : _c.vue) || ((_d = packageJson.devDependencies) === null || _d === void 0 ? void 0 : _d.vue)) {
|
|
507
|
+
framework = 'vue';
|
|
508
|
+
}
|
|
509
|
+
else {
|
|
510
|
+
// If can't detect, prompt for it
|
|
511
|
+
const frameworkAnswer = yield inquirer_1.default.prompt([{
|
|
512
|
+
type: 'list',
|
|
513
|
+
name: 'framework',
|
|
514
|
+
message: 'Which framework are you using?',
|
|
515
|
+
choices: ['react', 'vue']
|
|
516
|
+
}]);
|
|
517
|
+
framework = frameworkAnswer.framework;
|
|
518
|
+
}
|
|
444
519
|
}
|
|
520
|
+
console.log(`\nDetected existing ${framework} project in ${resolvedDistPath}`);
|
|
521
|
+
}
|
|
522
|
+
catch (e) {
|
|
523
|
+
console.error('Error reading package.json:', e);
|
|
524
|
+
process.exit(1);
|
|
445
525
|
}
|
|
446
|
-
console.log(`\nDetected existing ${framework} project in ${resolvedDistPath}`);
|
|
447
|
-
}
|
|
448
|
-
catch (e) {
|
|
449
|
-
console.error('Error reading package.json:', e);
|
|
450
|
-
process.exit(1);
|
|
451
526
|
}
|
|
452
527
|
}
|
|
453
528
|
}
|
|
529
|
+
else {
|
|
530
|
+
// In Dart-only mode, framework/packageName are unused; ensure framework is not accidentally required later.
|
|
531
|
+
framework = options.framework;
|
|
532
|
+
}
|
|
454
533
|
// Now proceed with code generation if flutter package source is provided
|
|
455
534
|
if (!options.flutterPackageSrc) {
|
|
456
535
|
console.log('\nProject is ready for code generation.');
|
|
457
536
|
console.log('To generate code, run:');
|
|
458
537
|
const displayPath = isTempDir ? '<output-dir>' : distPath;
|
|
459
|
-
|
|
538
|
+
if (isDartOnly) {
|
|
539
|
+
console.log(` webf codegen ${displayPath} --flutter-package-src=<path> --dart-only`);
|
|
540
|
+
}
|
|
541
|
+
else {
|
|
542
|
+
console.log(` webf codegen ${displayPath} --flutter-package-src=<path> --framework=${framework}`);
|
|
543
|
+
}
|
|
460
544
|
if (isTempDir) {
|
|
461
545
|
// Clean up temporary directory if we're not using it
|
|
462
546
|
fs_1.default.rmSync(resolvedDistPath, { recursive: true, force: true });
|
|
@@ -519,7 +603,23 @@ function generateCommand(distPath, options) {
|
|
|
519
603
|
process.exit(1);
|
|
520
604
|
}
|
|
521
605
|
}
|
|
522
|
-
const
|
|
606
|
+
const baseCommand = 'webf codegen';
|
|
607
|
+
const flutterPart = options.flutterPackageSrc ? ` --flutter-package-src=${options.flutterPackageSrc}` : '';
|
|
608
|
+
const modePart = isDartOnly
|
|
609
|
+
? ' --dart-only'
|
|
610
|
+
: (framework ? ` --framework=${framework}` : '');
|
|
611
|
+
const command = `${baseCommand}${flutterPart}${modePart} <distPath>`;
|
|
612
|
+
if (isDartOnly) {
|
|
613
|
+
console.log(`\nGenerating Dart bindings from ${options.flutterPackageSrc}...`);
|
|
614
|
+
yield (0, generator_1.dartGen)({
|
|
615
|
+
source: options.flutterPackageSrc,
|
|
616
|
+
target: options.flutterPackageSrc,
|
|
617
|
+
command,
|
|
618
|
+
exclude: options.exclude,
|
|
619
|
+
});
|
|
620
|
+
console.log('\nDart code generation completed successfully!');
|
|
621
|
+
return;
|
|
622
|
+
}
|
|
523
623
|
// Auto-initialize typings in the output directory if needed
|
|
524
624
|
ensureInitialized(resolvedDistPath);
|
|
525
625
|
console.log(`\nGenerating ${framework} code from ${options.flutterPackageSrc}...`);
|