@openwebf/webf 0.22.3 → 0.22.4

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.
Files changed (43) hide show
  1. package/dist/IDLBlob.js +17 -0
  2. package/dist/analyzer.js +578 -0
  3. package/dist/analyzer_original.js +467 -0
  4. package/dist/commands.js +704 -0
  5. package/dist/dart.js +300 -0
  6. package/dist/declaration.js +63 -0
  7. package/dist/generator.js +466 -0
  8. package/dist/logger.js +103 -0
  9. package/dist/react.js +283 -0
  10. package/dist/utils.js +127 -0
  11. package/dist/vue.js +159 -0
  12. package/package.json +8 -1
  13. package/src/dart.ts +138 -7
  14. package/templates/class.dart.tpl +7 -2
  15. package/templates/react.package.json.tpl +1 -1
  16. package/CLAUDE.md +0 -206
  17. package/README-zhCN.md +0 -256
  18. package/TYPING_GUIDE.md +0 -208
  19. package/coverage/clover.xml +0 -1295
  20. package/coverage/coverage-final.json +0 -12
  21. package/coverage/lcov-report/IDLBlob.ts.html +0 -142
  22. package/coverage/lcov-report/analyzer.ts.html +0 -2158
  23. package/coverage/lcov-report/analyzer_original.ts.html +0 -1450
  24. package/coverage/lcov-report/base.css +0 -224
  25. package/coverage/lcov-report/block-navigation.js +0 -87
  26. package/coverage/lcov-report/commands.ts.html +0 -700
  27. package/coverage/lcov-report/dart.ts.html +0 -490
  28. package/coverage/lcov-report/declaration.ts.html +0 -337
  29. package/coverage/lcov-report/favicon.png +0 -0
  30. package/coverage/lcov-report/generator.ts.html +0 -1171
  31. package/coverage/lcov-report/index.html +0 -266
  32. package/coverage/lcov-report/logger.ts.html +0 -424
  33. package/coverage/lcov-report/prettify.css +0 -1
  34. package/coverage/lcov-report/prettify.js +0 -2
  35. package/coverage/lcov-report/react.ts.html +0 -619
  36. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  37. package/coverage/lcov-report/sorter.js +0 -196
  38. package/coverage/lcov-report/utils.ts.html +0 -466
  39. package/coverage/lcov-report/vue.ts.html +0 -613
  40. package/coverage/lcov.info +0 -2149
  41. package/global.d.ts +0 -2
  42. package/jest.config.js +0 -24
  43. package/tsconfig.json +0 -30
@@ -0,0 +1,704 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.generateCommand = generateCommand;
16
+ const child_process_1 = require("child_process");
17
+ const fs_1 = __importDefault(require("fs"));
18
+ const path_1 = __importDefault(require("path"));
19
+ const os_1 = __importDefault(require("os"));
20
+ const generator_1 = require("./generator");
21
+ const lodash_1 = __importDefault(require("lodash"));
22
+ const inquirer_1 = __importDefault(require("inquirer"));
23
+ const yaml_1 = __importDefault(require("yaml"));
24
+ /**
25
+ * Sanitize a package name to comply with npm naming rules
26
+ * NPM package name rules:
27
+ * - Must be lowercase
28
+ * - Must be one word, no spaces
29
+ * - Can contain hyphens and underscores
30
+ * - Must start with a letter or number (or @ for scoped packages)
31
+ * - Cannot contain special characters except @ for scoped packages
32
+ * - Must be less than 214 characters
33
+ * - Cannot start with . or _
34
+ * - Cannot contain leading or trailing spaces
35
+ * - Cannot contain any non-URL-safe characters
36
+ */
37
+ function sanitizePackageName(name) {
38
+ // Remove any leading/trailing whitespace
39
+ let sanitized = name.trim();
40
+ // Check if it's a scoped package
41
+ const isScoped = sanitized.startsWith('@');
42
+ let scope = '';
43
+ let packageName = sanitized;
44
+ if (isScoped) {
45
+ const parts = sanitized.split('/');
46
+ if (parts.length >= 2) {
47
+ scope = parts[0];
48
+ packageName = parts.slice(1).join('/');
49
+ }
50
+ else {
51
+ // Invalid scoped package, treat as regular
52
+ packageName = sanitized.substring(1);
53
+ }
54
+ }
55
+ // Sanitize scope if present
56
+ if (scope) {
57
+ scope = scope.toLowerCase();
58
+ // Remove invalid characters from scope (keep only @ and alphanumeric/hyphen)
59
+ scope = scope.replace(/[^@a-z0-9-]/g, '');
60
+ if (scope === '@') {
61
+ scope = '@pkg'; // Default scope if only @ remains
62
+ }
63
+ }
64
+ // Sanitize package name part
65
+ packageName = packageName.toLowerCase();
66
+ packageName = packageName.replace(/\s+/g, '-');
67
+ packageName = packageName.replace(/[^a-z0-9\-_.]/g, '');
68
+ packageName = packageName.replace(/^[._]+/, '');
69
+ packageName = packageName.replace(/[._]+$/, '');
70
+ packageName = packageName.replace(/[-_.]{2,}/g, '-');
71
+ packageName = packageName.replace(/^-+/, '').replace(/-+$/, '');
72
+ // Ensure package name is not empty
73
+ if (!packageName) {
74
+ packageName = 'package';
75
+ }
76
+ // Ensure it starts with a letter or number
77
+ if (!/^[a-z0-9]/.test(packageName)) {
78
+ packageName = 'pkg-' + packageName;
79
+ }
80
+ // Combine scope and package name
81
+ let result = scope ? `${scope}/${packageName}` : packageName;
82
+ // Truncate to 214 characters (npm limit)
83
+ if (result.length > 214) {
84
+ if (scope) {
85
+ // Try to preserve scope
86
+ const maxPackageLength = 214 - scope.length - 1; // -1 for the /
87
+ packageName = packageName.substring(0, maxPackageLength);
88
+ packageName = packageName.replace(/[._-]+$/, '');
89
+ result = `${scope}/${packageName}`;
90
+ }
91
+ else {
92
+ result = result.substring(0, 214);
93
+ result = result.replace(/[._-]+$/, '');
94
+ }
95
+ }
96
+ return result;
97
+ }
98
+ /**
99
+ * Validate if a package name follows npm naming rules
100
+ */
101
+ function isValidNpmPackageName(name) {
102
+ // Check basic rules
103
+ if (!name || name.length === 0 || name.length > 214)
104
+ return false;
105
+ if (name.trim() !== name)
106
+ return false;
107
+ // Check if it's a scoped package
108
+ if (name.startsWith('@')) {
109
+ const parts = name.split('/');
110
+ if (parts.length !== 2)
111
+ return false; // Scoped packages must have exactly one /
112
+ const scope = parts[0];
113
+ const packageName = parts[1];
114
+ // Validate scope
115
+ if (!/^@[a-z0-9][a-z0-9-]*$/.test(scope))
116
+ return false;
117
+ // Validate package name part
118
+ return isValidNpmPackageName(packageName);
119
+ }
120
+ // For non-scoped packages
121
+ if (name !== name.toLowerCase())
122
+ return false;
123
+ if (name.startsWith('.') || name.startsWith('_'))
124
+ return false;
125
+ // Check for valid characters (letters, numbers, hyphens, underscores, dots)
126
+ if (!/^[a-z0-9][a-z0-9\-_.]*$/.test(name))
127
+ return false;
128
+ // Check for URL-safe characters
129
+ try {
130
+ if (encodeURIComponent(name) !== name)
131
+ return false;
132
+ }
133
+ catch (_a) {
134
+ return false;
135
+ }
136
+ return true;
137
+ }
138
+ const platform = process.platform;
139
+ const NPM = platform == 'win32' ? 'npm.cmd' : 'npm';
140
+ const gloabalDts = fs_1.default.readFileSync(path_1.default.resolve(__dirname, '../global.d.ts'), 'utf-8');
141
+ const tsConfig = fs_1.default.readFileSync(path_1.default.resolve(__dirname, '../templates/tsconfig.json.tpl'), 'utf-8');
142
+ const gitignore = fs_1.default.readFileSync(path_1.default.resolve(__dirname, '../templates/gitignore.tpl'), 'utf-8');
143
+ const reactPackageJson = fs_1.default.readFileSync(path_1.default.resolve(__dirname, '../templates/react.package.json.tpl'), 'utf-8');
144
+ const reactTsConfig = fs_1.default.readFileSync(path_1.default.resolve(__dirname, '../templates/react.tsconfig.json.tpl'), 'utf-8');
145
+ const reactTsUpConfig = fs_1.default.readFileSync(path_1.default.resolve(__dirname, '../templates/react.tsup.config.ts.tpl'), 'utf-8');
146
+ const reactIndexTpl = fs_1.default.readFileSync(path_1.default.resolve(__dirname, '../templates/react.index.ts.tpl'), 'utf-8');
147
+ const vuePackageJson = fs_1.default.readFileSync(path_1.default.resolve(__dirname, '../templates/vue.package.json.tpl'), 'utf-8');
148
+ const vueTsConfig = fs_1.default.readFileSync(path_1.default.resolve(__dirname, '../templates/vue.tsconfig.json.tpl'), 'utf-8');
149
+ function readFlutterPackageMetadata(packagePath) {
150
+ try {
151
+ const pubspecPath = path_1.default.join(packagePath, 'pubspec.yaml');
152
+ if (!fs_1.default.existsSync(pubspecPath)) {
153
+ console.warn(`Warning: pubspec.yaml not found at ${pubspecPath}. Using default metadata.`);
154
+ return null;
155
+ }
156
+ const pubspecContent = fs_1.default.readFileSync(pubspecPath, 'utf-8');
157
+ const pubspec = yaml_1.default.parse(pubspecContent);
158
+ // Validate required fields
159
+ if (!pubspec.name) {
160
+ console.warn(`Warning: Flutter package name not found in ${pubspecPath}. Using default name.`);
161
+ }
162
+ return {
163
+ name: pubspec.name || '',
164
+ version: pubspec.version || '0.0.1',
165
+ description: pubspec.description || ''
166
+ };
167
+ }
168
+ catch (error) {
169
+ console.warn(`Warning: Could not read Flutter package metadata from ${packagePath}:`, error);
170
+ console.warn('Using default metadata. Ensure pubspec.yaml exists and is valid YAML.');
171
+ return null;
172
+ }
173
+ }
174
+ function validateTypeScriptEnvironment(projectPath) {
175
+ const errors = [];
176
+ // Check for TypeScript configuration
177
+ const tsConfigPath = path_1.default.join(projectPath, 'tsconfig.json');
178
+ if (!fs_1.default.existsSync(tsConfigPath)) {
179
+ errors.push('Missing tsconfig.json - TypeScript configuration is required for type definitions');
180
+ }
181
+ // Check for .d.ts files - this is critical
182
+ const libPath = path_1.default.join(projectPath, 'lib');
183
+ let hasDtsFiles = false;
184
+ if (fs_1.default.existsSync(libPath)) {
185
+ // Check in lib directory
186
+ hasDtsFiles = fs_1.default.readdirSync(libPath).some(file => file.endsWith('.d.ts') ||
187
+ (fs_1.default.statSync(path_1.default.join(libPath, file)).isDirectory() &&
188
+ fs_1.default.readdirSync(path_1.default.join(libPath, file)).some(f => f.endsWith('.d.ts'))));
189
+ }
190
+ // Also check in root directory
191
+ if (!hasDtsFiles) {
192
+ hasDtsFiles = fs_1.default.readdirSync(projectPath).some(file => file.endsWith('.d.ts') ||
193
+ (fs_1.default.statSync(path_1.default.join(projectPath, file)).isDirectory() &&
194
+ file !== 'node_modules' &&
195
+ fs_1.default.existsSync(path_1.default.join(projectPath, file, 'index.d.ts'))));
196
+ }
197
+ if (!hasDtsFiles) {
198
+ errors.push('No TypeScript definition files (.d.ts) found in the project - Please create .d.ts files for your components');
199
+ }
200
+ return {
201
+ isValid: errors.length === 0,
202
+ errors
203
+ };
204
+ }
205
+ function createCommand(target, options) {
206
+ const { framework, metadata } = options;
207
+ // Ensure package name is always valid
208
+ const packageName = isValidNpmPackageName(options.packageName)
209
+ ? options.packageName
210
+ : sanitizePackageName(options.packageName);
211
+ if (!fs_1.default.existsSync(target)) {
212
+ fs_1.default.mkdirSync(target, { recursive: true });
213
+ }
214
+ if (framework === 'react') {
215
+ const packageJsonPath = path_1.default.join(target, 'package.json');
216
+ const packageJsonContent = lodash_1.default.template(reactPackageJson)({
217
+ packageName,
218
+ version: (metadata === null || metadata === void 0 ? void 0 : metadata.version) || '0.0.1',
219
+ description: (metadata === null || metadata === void 0 ? void 0 : metadata.description) || ''
220
+ });
221
+ writeFileIfChanged(packageJsonPath, packageJsonContent);
222
+ const tsConfigPath = path_1.default.join(target, 'tsconfig.json');
223
+ const tsConfigContent = lodash_1.default.template(reactTsConfig)({});
224
+ writeFileIfChanged(tsConfigPath, tsConfigContent);
225
+ const tsupConfigPath = path_1.default.join(target, 'tsup.config.ts');
226
+ const tsupConfigContent = lodash_1.default.template(reactTsUpConfig)({});
227
+ writeFileIfChanged(tsupConfigPath, tsupConfigContent);
228
+ const gitignorePath = path_1.default.join(target, '.gitignore');
229
+ const gitignoreContent = lodash_1.default.template(gitignore)({});
230
+ writeFileIfChanged(gitignorePath, gitignoreContent);
231
+ const srcDir = path_1.default.join(target, 'src');
232
+ if (!fs_1.default.existsSync(srcDir)) {
233
+ fs_1.default.mkdirSync(srcDir, { recursive: true });
234
+ }
235
+ 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'], {
241
+ cwd: target,
242
+ stdio: 'inherit'
243
+ });
244
+ }
245
+ else if (framework === 'vue') {
246
+ const packageJsonPath = path_1.default.join(target, 'package.json');
247
+ const packageJsonContent = lodash_1.default.template(vuePackageJson)({
248
+ packageName,
249
+ version: (metadata === null || metadata === void 0 ? void 0 : metadata.version) || '0.0.1',
250
+ description: (metadata === null || metadata === void 0 ? void 0 : metadata.description) || ''
251
+ });
252
+ writeFileIfChanged(packageJsonPath, packageJsonContent);
253
+ const tsConfigPath = path_1.default.join(target, 'tsconfig.json');
254
+ const tsConfigContent = lodash_1.default.template(vueTsConfig)({});
255
+ writeFileIfChanged(tsConfigPath, tsConfigContent);
256
+ const gitignorePath = path_1.default.join(target, '.gitignore');
257
+ const gitignoreContent = lodash_1.default.template(gitignore)({});
258
+ writeFileIfChanged(gitignorePath, gitignoreContent);
259
+ (0, child_process_1.spawnSync)(NPM, ['install', '@openwebf/webf-enterprise-typings'], {
260
+ cwd: target,
261
+ stdio: 'inherit'
262
+ });
263
+ (0, child_process_1.spawnSync)(NPM, ['install', '@types/vue', '-D'], {
264
+ cwd: target,
265
+ stdio: 'inherit'
266
+ });
267
+ }
268
+ console.log(`WebF ${framework} package created at: ${target}`);
269
+ }
270
+ function generateCommand(distPath, options) {
271
+ return __awaiter(this, void 0, void 0, function* () {
272
+ var _a, _b, _c, _d;
273
+ // If distPath is not provided or is '.', create a temporary directory
274
+ let resolvedDistPath;
275
+ let isTempDir = false;
276
+ if (!distPath || distPath === '.') {
277
+ // Create a temporary directory for the generated package
278
+ const tempDir = fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), 'webf-typings-'));
279
+ resolvedDistPath = tempDir;
280
+ isTempDir = true;
281
+ console.log(`\nUsing temporary directory: ${tempDir}`);
282
+ }
283
+ else {
284
+ resolvedDistPath = path_1.default.resolve(distPath);
285
+ }
286
+ // First, check if we're in a Flutter package directory when flutter-package-src is not provided
287
+ if (!options.flutterPackageSrc) {
288
+ // Check if current directory or parent directories contain pubspec.yaml
289
+ let currentDir = process.cwd();
290
+ let foundPubspec = false;
291
+ let pubspecDir = '';
292
+ // Search up to 3 levels up for pubspec.yaml
293
+ for (let i = 0; i < 3; i++) {
294
+ const pubspecPath = path_1.default.join(currentDir, 'pubspec.yaml');
295
+ if (fs_1.default.existsSync(pubspecPath)) {
296
+ foundPubspec = true;
297
+ pubspecDir = currentDir;
298
+ break;
299
+ }
300
+ const parentDir = path_1.default.dirname(currentDir);
301
+ if (parentDir === currentDir)
302
+ break; // Reached root
303
+ currentDir = parentDir;
304
+ }
305
+ if (foundPubspec) {
306
+ // Use the directory containing pubspec.yaml as the flutter package source
307
+ options.flutterPackageSrc = pubspecDir;
308
+ console.log(`\nDetected Flutter package at: ${pubspecDir}`);
309
+ }
310
+ }
311
+ // Check if the directory exists and has required files
312
+ const packageJsonPath = path_1.default.join(resolvedDistPath, 'package.json');
313
+ const globalDtsPath = path_1.default.join(resolvedDistPath, 'global.d.ts');
314
+ const tsConfigPath = path_1.default.join(resolvedDistPath, 'tsconfig.json');
315
+ const hasPackageJson = fs_1.default.existsSync(packageJsonPath);
316
+ const hasGlobalDts = fs_1.default.existsSync(globalDtsPath);
317
+ const hasTsConfig = fs_1.default.existsSync(tsConfigPath);
318
+ // Determine if we need to create a new project
319
+ const needsProjectCreation = !hasPackageJson || !hasGlobalDts || !hasTsConfig;
320
+ let framework = options.framework;
321
+ let packageName = options.packageName;
322
+ // Validate and sanitize package name if provided
323
+ if (packageName && !isValidNpmPackageName(packageName)) {
324
+ console.warn(`Warning: Package name "${packageName}" is not valid for npm.`);
325
+ const sanitized = sanitizePackageName(packageName);
326
+ console.log(`Using sanitized name: "${sanitized}"`);
327
+ packageName = sanitized;
328
+ }
329
+ if (needsProjectCreation) {
330
+ // If project needs creation but options are missing, prompt for them
331
+ if (!framework) {
332
+ const frameworkAnswer = yield inquirer_1.default.prompt([{
333
+ type: 'list',
334
+ name: 'framework',
335
+ message: 'Which framework would you like to use?',
336
+ choices: ['react', 'vue']
337
+ }]);
338
+ framework = frameworkAnswer.framework;
339
+ }
340
+ // Try to read Flutter package metadata if flutterPackageSrc is provided
341
+ let metadata = null;
342
+ if (options.flutterPackageSrc) {
343
+ metadata = readFlutterPackageMetadata(options.flutterPackageSrc);
344
+ }
345
+ if (!packageName) {
346
+ // Use Flutter package name as default if available, sanitized for npm
347
+ const rawDefaultName = (metadata === null || metadata === void 0 ? void 0 : metadata.name) || path_1.default.basename(resolvedDistPath);
348
+ const defaultPackageName = sanitizePackageName(rawDefaultName);
349
+ const packageNameAnswer = yield inquirer_1.default.prompt([{
350
+ type: 'input',
351
+ name: 'packageName',
352
+ message: 'What is your package name?',
353
+ default: defaultPackageName,
354
+ validate: (input) => {
355
+ if (!input || input.trim() === '') {
356
+ return 'Package name is required';
357
+ }
358
+ // Check if it's valid as-is
359
+ if (isValidNpmPackageName(input)) {
360
+ return true;
361
+ }
362
+ // If not valid, show what it would be sanitized to
363
+ const sanitized = sanitizePackageName(input);
364
+ return `Invalid npm package name. Would be sanitized to: "${sanitized}". Please enter a valid name.`;
365
+ }
366
+ }]);
367
+ packageName = packageNameAnswer.packageName;
368
+ }
369
+ console.log(`\nCreating new ${framework} project in ${resolvedDistPath}...`);
370
+ createCommand(resolvedDistPath, {
371
+ framework: framework,
372
+ packageName: packageName,
373
+ metadata: metadata || undefined
374
+ });
375
+ }
376
+ else {
377
+ // Validate existing project structure
378
+ if (hasPackageJson) {
379
+ try {
380
+ const packageJson = JSON.parse(fs_1.default.readFileSync(packageJsonPath, 'utf-8'));
381
+ // Detect framework from existing package.json
382
+ if (!framework) {
383
+ if (((_a = packageJson.dependencies) === null || _a === void 0 ? void 0 : _a.react) || ((_b = packageJson.devDependencies) === null || _b === void 0 ? void 0 : _b.react)) {
384
+ framework = 'react';
385
+ }
386
+ else if (((_c = packageJson.dependencies) === null || _c === void 0 ? void 0 : _c.vue) || ((_d = packageJson.devDependencies) === null || _d === void 0 ? void 0 : _d.vue)) {
387
+ framework = 'vue';
388
+ }
389
+ else {
390
+ // If can't detect, prompt for it
391
+ const frameworkAnswer = yield inquirer_1.default.prompt([{
392
+ type: 'list',
393
+ name: 'framework',
394
+ message: 'Which framework are you using?',
395
+ choices: ['react', 'vue']
396
+ }]);
397
+ framework = frameworkAnswer.framework;
398
+ }
399
+ }
400
+ console.log(`\nDetected existing ${framework} project in ${resolvedDistPath}`);
401
+ }
402
+ catch (e) {
403
+ console.error('Error reading package.json:', e);
404
+ process.exit(1);
405
+ }
406
+ }
407
+ }
408
+ // Now proceed with code generation if flutter package source is provided
409
+ if (!options.flutterPackageSrc) {
410
+ console.log('\nProject is ready for code generation.');
411
+ console.log('To generate code, run:');
412
+ const displayPath = isTempDir ? '<output-dir>' : distPath;
413
+ console.log(` webf codegen ${displayPath} --flutter-package-src=<path> --framework=${framework}`);
414
+ if (isTempDir) {
415
+ // Clean up temporary directory if we're not using it
416
+ fs_1.default.rmSync(resolvedDistPath, { recursive: true, force: true });
417
+ }
418
+ return;
419
+ }
420
+ // Validate TypeScript environment in the Flutter package
421
+ console.log(`\nValidating TypeScript environment in ${options.flutterPackageSrc}...`);
422
+ const validation = validateTypeScriptEnvironment(options.flutterPackageSrc);
423
+ if (!validation.isValid) {
424
+ // Check specifically for missing tsconfig.json
425
+ const tsConfigPath = path_1.default.join(options.flutterPackageSrc, 'tsconfig.json');
426
+ if (!fs_1.default.existsSync(tsConfigPath)) {
427
+ const createTsConfigAnswer = yield inquirer_1.default.prompt([{
428
+ type: 'confirm',
429
+ name: 'createTsConfig',
430
+ message: 'No tsconfig.json found. Would you like me to create one for you?',
431
+ default: true
432
+ }]);
433
+ if (createTsConfigAnswer.createTsConfig) {
434
+ // Create a default tsconfig.json
435
+ const defaultTsConfig = {
436
+ compilerOptions: {
437
+ target: 'ES2020',
438
+ module: 'commonjs',
439
+ lib: ['ES2020'],
440
+ declaration: true,
441
+ strict: true,
442
+ esModuleInterop: true,
443
+ skipLibCheck: true,
444
+ forceConsistentCasingInFileNames: true,
445
+ resolveJsonModule: true,
446
+ moduleResolution: 'node'
447
+ },
448
+ include: ['lib/**/*.d.ts', '**/*.d.ts'],
449
+ exclude: ['node_modules', 'dist', 'build']
450
+ };
451
+ fs_1.default.writeFileSync(tsConfigPath, JSON.stringify(defaultTsConfig, null, 2), 'utf-8');
452
+ console.log('āœ… Created tsconfig.json');
453
+ // Re-validate after creating tsconfig
454
+ const newValidation = validateTypeScriptEnvironment(options.flutterPackageSrc);
455
+ if (!newValidation.isValid) {
456
+ console.error('\nāš ļø Additional setup required:');
457
+ newValidation.errors.forEach(error => console.error(` - ${error}`));
458
+ console.error('\nPlease fix the above issues and run the command again.');
459
+ process.exit(1);
460
+ }
461
+ }
462
+ else {
463
+ console.error('\nāŒ TypeScript configuration is required for code generation.');
464
+ console.error('Please create a tsconfig.json file manually and run the command again.');
465
+ process.exit(1);
466
+ }
467
+ }
468
+ else {
469
+ // Show all validation errors
470
+ console.error('\nāŒ TypeScript environment validation failed:');
471
+ validation.errors.forEach(error => console.error(` - ${error}`));
472
+ console.error('\nPlease fix the above issues before generating code.');
473
+ process.exit(1);
474
+ }
475
+ }
476
+ const command = `webf codegen --flutter-package-src=${options.flutterPackageSrc} --framework=${framework} <distPath>`;
477
+ // Auto-initialize typings in the output directory if needed
478
+ ensureInitialized(resolvedDistPath);
479
+ console.log(`\nGenerating ${framework} code from ${options.flutterPackageSrc}...`);
480
+ yield (0, generator_1.dartGen)({
481
+ source: options.flutterPackageSrc,
482
+ target: options.flutterPackageSrc,
483
+ command,
484
+ exclude: options.exclude,
485
+ });
486
+ if (framework === 'react') {
487
+ // Get the package name from package.json if it exists
488
+ let reactPackageName;
489
+ try {
490
+ const packageJsonPath = path_1.default.join(resolvedDistPath, 'package.json');
491
+ if (fs_1.default.existsSync(packageJsonPath)) {
492
+ const packageJson = JSON.parse(fs_1.default.readFileSync(packageJsonPath, 'utf-8'));
493
+ reactPackageName = packageJson.name;
494
+ }
495
+ }
496
+ catch (e) {
497
+ // Ignore errors
498
+ }
499
+ yield (0, generator_1.reactGen)({
500
+ source: options.flutterPackageSrc,
501
+ target: resolvedDistPath,
502
+ command,
503
+ exclude: options.exclude,
504
+ packageName: reactPackageName,
505
+ });
506
+ }
507
+ else if (framework === 'vue') {
508
+ yield (0, generator_1.vueGen)({
509
+ source: options.flutterPackageSrc,
510
+ target: resolvedDistPath,
511
+ command,
512
+ exclude: options.exclude,
513
+ });
514
+ }
515
+ console.log('\nCode generation completed successfully!');
516
+ // Automatically build the generated package
517
+ if (framework) {
518
+ try {
519
+ yield buildPackage(resolvedDistPath);
520
+ }
521
+ catch (error) {
522
+ console.error('\nWarning: Build failed:', error);
523
+ // Don't exit here since generation was successful
524
+ }
525
+ }
526
+ // Handle npm publishing if requested via command line option
527
+ if (options.publishToNpm && framework) {
528
+ try {
529
+ yield buildAndPublishPackage(resolvedDistPath, options.npmRegistry);
530
+ }
531
+ catch (error) {
532
+ console.error('\nError during npm publish:', error);
533
+ process.exit(1);
534
+ }
535
+ }
536
+ else if (framework && !options.publishToNpm) {
537
+ // If not publishing via command line option, ask the user
538
+ const publishAnswer = yield inquirer_1.default.prompt([{
539
+ type: 'confirm',
540
+ name: 'publish',
541
+ message: 'Would you like to publish this package to npm?',
542
+ default: false
543
+ }]);
544
+ if (publishAnswer.publish) {
545
+ // Ask for registry
546
+ const registryAnswer = yield inquirer_1.default.prompt([{
547
+ type: 'input',
548
+ name: 'registry',
549
+ message: 'NPM registry URL (leave empty for default npm registry):',
550
+ default: '',
551
+ validate: (input) => {
552
+ if (!input)
553
+ return true; // Empty is valid (use default)
554
+ try {
555
+ new URL(input); // Validate URL format
556
+ return true;
557
+ }
558
+ catch (_a) {
559
+ return 'Please enter a valid URL';
560
+ }
561
+ }
562
+ }]);
563
+ try {
564
+ yield buildAndPublishPackage(resolvedDistPath, registryAnswer.registry || undefined);
565
+ }
566
+ catch (error) {
567
+ console.error('\nError during npm publish:', error);
568
+ // Don't exit here since generation was successful
569
+ }
570
+ }
571
+ }
572
+ // If using a temporary directory, remind the user where the files are
573
+ if (isTempDir) {
574
+ console.log(`\nšŸ“ Generated files are in: ${resolvedDistPath}`);
575
+ console.log('šŸ’” To use these files, copy them to your desired location or publish to npm.');
576
+ }
577
+ });
578
+ }
579
+ function writeFileIfChanged(filePath, content) {
580
+ if (fs_1.default.existsSync(filePath)) {
581
+ const oldContent = fs_1.default.readFileSync(filePath, 'utf-8');
582
+ if (oldContent === content) {
583
+ return;
584
+ }
585
+ }
586
+ fs_1.default.writeFileSync(filePath, content, 'utf-8');
587
+ }
588
+ function ensureInitialized(targetPath) {
589
+ const globalDtsPath = path_1.default.join(targetPath, 'global.d.ts');
590
+ const tsConfigPath = path_1.default.join(targetPath, 'tsconfig.json');
591
+ // Check if initialization files already exist
592
+ const needsInit = !fs_1.default.existsSync(globalDtsPath) || !fs_1.default.existsSync(tsConfigPath);
593
+ if (needsInit) {
594
+ console.log('Initializing WebF typings...');
595
+ fs_1.default.mkdirSync(targetPath, { recursive: true });
596
+ if (!fs_1.default.existsSync(globalDtsPath)) {
597
+ fs_1.default.writeFileSync(globalDtsPath, gloabalDts, 'utf-8');
598
+ console.log('Created global.d.ts');
599
+ }
600
+ if (!fs_1.default.existsSync(tsConfigPath)) {
601
+ fs_1.default.writeFileSync(tsConfigPath, tsConfig, 'utf-8');
602
+ console.log('Created tsconfig.json');
603
+ }
604
+ }
605
+ }
606
+ function buildPackage(packagePath) {
607
+ return __awaiter(this, void 0, void 0, function* () {
608
+ var _a;
609
+ const packageJsonPath = path_1.default.join(packagePath, 'package.json');
610
+ if (!fs_1.default.existsSync(packageJsonPath)) {
611
+ // Skip the error in test environment to avoid console warnings
612
+ if (process.env.NODE_ENV === 'test' || process.env.JEST_WORKER_ID !== undefined) {
613
+ return;
614
+ }
615
+ throw new Error(`No package.json found in ${packagePath}`);
616
+ }
617
+ const packageJson = JSON.parse(fs_1.default.readFileSync(packageJsonPath, 'utf-8'));
618
+ const packageName = packageJson.name;
619
+ const packageVersion = packageJson.version;
620
+ // Check if node_modules exists
621
+ const nodeModulesPath = path_1.default.join(packagePath, 'node_modules');
622
+ if (!fs_1.default.existsSync(nodeModulesPath)) {
623
+ console.log(`\nšŸ“¦ Installing dependencies for ${packageName}...`);
624
+ // Check if yarn.lock exists to determine package manager
625
+ const yarnLockPath = path_1.default.join(packagePath, 'yarn.lock');
626
+ const useYarn = fs_1.default.existsSync(yarnLockPath);
627
+ const installCommand = useYarn ? 'yarn' : NPM;
628
+ const installArgs = useYarn ? [] : ['install'];
629
+ const installResult = (0, child_process_1.spawnSync)(installCommand, installArgs, {
630
+ cwd: packagePath,
631
+ stdio: 'inherit'
632
+ });
633
+ if (installResult.status !== 0) {
634
+ throw new Error('Failed to install dependencies');
635
+ }
636
+ console.log('āœ… Dependencies installed successfully!');
637
+ }
638
+ // Check if package has a build script
639
+ if ((_a = packageJson.scripts) === null || _a === void 0 ? void 0 : _a.build) {
640
+ console.log(`\nBuilding ${packageName}@${packageVersion}...`);
641
+ const buildResult = (0, child_process_1.spawnSync)(NPM, ['run', 'build'], {
642
+ cwd: packagePath,
643
+ stdio: 'inherit'
644
+ });
645
+ if (buildResult.status !== 0) {
646
+ throw new Error('Build failed');
647
+ }
648
+ console.log('āœ… Build completed successfully!');
649
+ }
650
+ else {
651
+ console.log(`\nNo build script found for ${packageName}@${packageVersion}`);
652
+ }
653
+ });
654
+ }
655
+ function buildAndPublishPackage(packagePath, registry) {
656
+ return __awaiter(this, void 0, void 0, function* () {
657
+ const packageJsonPath = path_1.default.join(packagePath, 'package.json');
658
+ if (!fs_1.default.existsSync(packageJsonPath)) {
659
+ throw new Error(`No package.json found in ${packagePath}`);
660
+ }
661
+ const packageJson = JSON.parse(fs_1.default.readFileSync(packageJsonPath, 'utf-8'));
662
+ const packageName = packageJson.name;
663
+ const packageVersion = packageJson.version;
664
+ // First, ensure dependencies are installed and build the package
665
+ yield buildPackage(packagePath);
666
+ // Set registry if provided
667
+ if (registry) {
668
+ console.log(`\nUsing npm registry: ${registry}`);
669
+ const setRegistryResult = (0, child_process_1.spawnSync)(NPM, ['config', 'set', 'registry', registry], {
670
+ cwd: packagePath,
671
+ stdio: 'inherit'
672
+ });
673
+ if (setRegistryResult.status !== 0) {
674
+ throw new Error('Failed to set npm registry');
675
+ }
676
+ }
677
+ // Check if user is logged in to npm
678
+ const whoamiResult = (0, child_process_1.spawnSync)(NPM, ['whoami'], {
679
+ cwd: packagePath,
680
+ encoding: 'utf-8'
681
+ });
682
+ if (whoamiResult.status !== 0) {
683
+ console.error('\nError: You must be logged in to npm to publish packages.');
684
+ console.error('Please run "npm login" first.');
685
+ throw new Error('Not logged in to npm');
686
+ }
687
+ console.log(`\nPublishing ${packageName}@${packageVersion} to npm...`);
688
+ // Publish the package
689
+ const publishResult = (0, child_process_1.spawnSync)(NPM, ['publish'], {
690
+ cwd: packagePath,
691
+ stdio: 'inherit'
692
+ });
693
+ if (publishResult.status !== 0) {
694
+ throw new Error('Publish failed');
695
+ }
696
+ console.log(`\nāœ… Successfully published ${packageName}@${packageVersion}`);
697
+ // Reset registry to default if it was changed
698
+ if (registry) {
699
+ (0, child_process_1.spawnSync)(NPM, ['config', 'delete', 'registry'], {
700
+ cwd: packagePath
701
+ });
702
+ }
703
+ });
704
+ }