@@ -226,23 +226,6 @@ class FileCodeGen {
226226 // =========================================================================
227227
228228 Future <String > _generateCodeAsync (DartFile dartFile) async {
229- try {
230- final logFile = File (r'C:\Jay\_Plugin\flutterjs\debug_entry_log.txt' );
231- logFile.writeAsStringSync (
232- 'Processing File: ${dartFile .package } / ${dartFile .library }\n Classes: ${dartFile .classDeclarations .length }, Functions: ${dartFile .functionDeclarations .length }\n ' ,
233- mode: FileMode .append,
234- );
235- for (var c in dartFile.classDeclarations)
236- logFile.writeAsStringSync (
237- ' Class: ${c .name }\n ' ,
238- mode: FileMode .append,
239- );
240- for (var f in dartFile.functionDeclarations)
241- logFile.writeAsStringSync (' Func: ${f .name }\n ' , mode: FileMode .append);
242- } catch (e) {
243- // ignore
244- }
245-
246229 var code = StringBuffer ();
247230
248231 // Generate each section sequentially to avoid buffer corruption
@@ -407,178 +390,176 @@ class FileCodeGen {
407390 if (target == 'node' ) {
408391 // Node.js target: skip all Flutter/material/services imports entirely
409392 } else {
393+ // Sort widgets to ensure deterministic output
394+ final sortedWidgets =
395+ usedWidgets.where ((w) => ! definedNames.contains (w)).toSet ().toList ()
396+ ..sort ();
410397
411- // Sort widgets to ensure deterministic output
412- final sortedWidgets =
413- usedWidgets.where ((w) => ! definedNames.contains (w)).toSet ().toList ()
414- ..sort ();
398+ // Resolver already declared above
415399
416- // Resolver already declared above
400+ for (final widget in sortedWidgets) {
401+ // Skip runtime types if they accidentally got into usedWidgets
402+ if (widget.startsWith ('_' ) || materialImports.contains (widget))
403+ continue ;
417404
418- for (final widget in sortedWidgets) {
419- // Skip runtime types if they accidentally got into usedWidgets
420- if (widget.startsWith ('_' ) || materialImports.contains (widget))
421- continue ;
405+ if (widget == 'Uri' ) continue ;
406+ if (widget == 'Seo' ) continue ;
407+
408+ // ✅ FIX: Heuristic for local widgets to prevent Material capture
409+ // Most local pages end in "Page" or "Screen". We must ensure they resolve locally.
410+ // We explicitly allow 'MaterialPage' as it is a real Material widget.
411+ if ((widget.endsWith ('Page' ) ||
412+ widget.endsWith ('Screen' ) ||
413+ widget == 'MyApp' ) &&
414+ widget != 'MaterialPage' &&
415+ widget != 'CupertinoPage' ) {
416+ continue ;
417+ }
422418
423- if (widget == 'Uri' ) continue ;
424- if (widget == 'Seo' ) continue ;
425-
426- // ✅ FIX: Heuristic for local widgets to prevent Material capture
427- // Most local pages end in "Page" or "Screen". We must ensure they resolve locally.
428- // We explicitly allow 'MaterialPage' as it is a real Material widget.
429- if ((widget.endsWith ('Page' ) ||
430- widget.endsWith ('Screen' ) ||
431- widget == 'MyApp' ) &&
432- widget != 'MaterialPage' &&
433- widget != 'CupertinoPage' ) {
434- continue ;
419+ // ✅ FIX: Use strict resolution (ImportResolver)
420+ final resolvedPkg = resolver.resolve (widget);
421+
422+ // Only add if it resolves to Material or is a known UI widget
423+ // If it resolves to 'dart:core', it will be SKIPPED here (and handled by coreImports above)
424+ if (resolvedPkg == '@flutterjs/material' ) {
425+ materialImports.add (widget);
426+ } else if (widget == 'ThemeData' ||
427+ widget == 'ColorScheme' ||
428+ widget == 'Colors' ||
429+ widget == 'Color' ||
430+ widget == 'MaterialColor' ||
431+ widget == 'ColorSwatch' ||
432+ widget == 'Theme' ||
433+ widget == 'Icon' ||
434+ widget == 'Icons' ||
435+ widget == 'IconData' ||
436+ widget == 'FloatingActionButton' ||
437+ widget == 'TextStyle' ||
438+ widget == 'MediaQuery' ||
439+ widget == 'MediaQueryData' ||
440+ widget == 'Spacer' ||
441+ widget == 'TextButtonThemeData' ||
442+ widget == 'debugPrint' ) {
443+ // Fallback for symbols not yet in registry but known to be Material
444+ materialImports.add (widget);
445+ }
435446 }
436447
437- // ✅ FIX: Use strict resolution (ImportResolver)
438- final resolvedPkg = resolver.resolve (widget);
439-
440- // Only add if it resolves to Material or is a known UI widget
441- // If it resolves to 'dart:core', it will be SKIPPED here (and handled by coreImports above)
442- if (resolvedPkg == '@flutterjs/material' ) {
443- materialImports.add (widget);
444- } else if (widget == 'ThemeData' ||
445- widget == 'ColorScheme' ||
446- widget == 'Colors' ||
447- widget == 'Color' ||
448- widget == 'MaterialColor' ||
449- widget == 'ColorSwatch' ||
450- widget == 'Theme' ||
451- widget == 'Icon' ||
452- widget == 'Icons' ||
453- widget == 'IconData' ||
454- widget == 'FloatingActionButton' ||
455- widget == 'TextStyle' ||
456- widget == 'MediaQuery' ||
457- widget == 'MediaQueryData' ||
458- widget == 'Spacer' ||
459- widget == 'TextButtonThemeData' ||
460- widget == 'debugPrint' ) {
461- // Fallback for symbols not yet in registry but known to be Material
462- materialImports.add (widget);
463- }
464- }
448+ if (materialImports.isNotEmpty) {
449+ // Only add companion symbols that are actually used — avoid spurious imports
450+ const materialCompanions = {
451+ 'Theme' ,
452+ 'Colors' ,
453+ 'Color' ,
454+ 'MaterialColor' ,
455+ 'ColorSwatch' ,
456+ 'Icons' ,
457+ 'ThemeData' ,
458+ 'EdgeInsets' ,
459+ 'BorderRadius' ,
460+ 'BoxDecoration' ,
461+ 'TextStyle' ,
462+ 'BoxShadow' ,
463+ 'Offset' ,
464+ 'FontWeight' ,
465+ 'BoxShape' ,
466+ 'Alignment' ,
467+ 'CrossAxisAlignment' ,
468+ 'MainAxisAlignment' ,
469+ 'MediaQuery' ,
470+ 'MediaQueryData' ,
471+ 'Spacer' ,
472+ 'TextButtonThemeData' ,
473+ 'debugPrint' ,
474+ 'runApp' ,
475+ 'Widget' ,
476+ 'State' ,
477+ 'StatefulWidget' ,
478+ 'StatelessWidget' ,
479+ 'BuildContext' ,
480+ 'Key' ,
481+ };
482+ // Add companions only if used in this file
483+ for (final c in materialCompanions) {
484+ if (usedWidgets.contains (c) ||
485+ usedTypes.contains (c) ||
486+ usedFunctions.contains (c)) {
487+ materialImports.add (c);
488+ }
489+ }
465490
466- if (materialImports.isNotEmpty) {
467- // Only add companion symbols that are actually used — avoid spurious imports
468- const materialCompanions = {
469- 'Theme' ,
470- 'Colors' ,
471- 'Color' ,
472- 'MaterialColor' ,
473- 'ColorSwatch' ,
474- 'Icons' ,
475- 'ThemeData' ,
476- 'EdgeInsets' ,
477- 'BorderRadius' ,
478- 'BoxDecoration' ,
479- 'TextStyle' ,
480- 'BoxShadow' ,
481- 'Offset' ,
482- 'FontWeight' ,
483- 'BoxShape' ,
484- 'Alignment' ,
485- 'CrossAxisAlignment' ,
486- 'MainAxisAlignment' ,
487- 'MediaQuery' ,
488- 'MediaQueryData' ,
489- 'Spacer' ,
490- 'TextButtonThemeData' ,
491- 'debugPrint' ,
492- 'runApp' ,
493- 'Widget' ,
494- 'State' ,
495- 'StatefulWidget' ,
496- 'StatelessWidget' ,
497- 'BuildContext' ,
498- 'Key' ,
499- };
500- // Add companions only if used in this file
501- for (final c in materialCompanions) {
502- if (usedWidgets.contains (c) || usedTypes.contains (c) || usedFunctions.contains (c)) {
503- materialImports.add (c);
491+ code.writeln ('import {' );
492+ final sortedImports = materialImports.toList ()..sort ();
493+ for (final symbol in sortedImports) {
494+ code.writeln (' $symbol ,' );
504495 }
496+ code.writeln ('} from \' @flutterjs/material\' ;' );
505497 }
506498
507- code.writeln ('import {' );
508- final sortedImports = materialImports.toList ()..sort ();
509- for (final symbol in sortedImports) {
510- code.writeln (' $symbol ,' );
499+ // -----------------------------------------------------------------------
500+ // SERVICES IMPORTS (@flutterjs/services)
501+ // -----------------------------------------------------------------------
502+
503+ // Ensure explicit service classes are imported
504+ if (usedWidgets.contains ('MethodCall' ) ||
505+ usedWidgets.contains ('MethodCodec' ) ||
506+ usedWidgets.contains ('JSONMethodCodec' ) ||
507+ usedWidgets.contains ('PlatformException' ) ||
508+ usedTypes.contains ('MethodCall' ) ||
509+ usedTypes.contains ('MethodCodec' ) ||
510+ usedTypes.contains ('JSONMethodCodec' ) ||
511+ usedTypes.contains ('PlatformException' )) {
512+ // Add them if detected
511513 }
512- code.writeln ('} from \' @flutterjs/material\' ;' );
513- }
514+ // Actually we iterate all widgets/types and check resolution
514515
515- // -----------------------------------------------------------------------
516- // SERVICES IMPORTS (@flutterjs/services)
517- // -----------------------------------------------------------------------
518-
519- // Ensure explicit service classes are imported
520- if (usedWidgets.contains ('MethodCall' ) ||
521- usedWidgets.contains ('MethodCodec' ) ||
522- usedWidgets.contains ('JSONMethodCodec' ) ||
523- usedWidgets.contains ('PlatformException' ) ||
524- usedTypes.contains ('MethodCall' ) ||
525- usedTypes.contains ('MethodCodec' ) ||
526- usedTypes.contains ('JSONMethodCodec' ) ||
527- usedTypes.contains ('PlatformException' )) {
528- // Add them if detected
529- }
530- // Actually we iterate all widgets/types and check resolution
531-
532- for (final widget in sortedWidgets) {
533- if (widget.startsWith ('_' ) ||
534- materialImports.contains (widget) ||
535- coreImports.contains (widget))
536- continue ;
516+ for (final widget in sortedWidgets) {
517+ if (widget.startsWith ('_' ) ||
518+ materialImports.contains (widget) ||
519+ coreImports.contains (widget))
520+ continue ;
537521
538- final resolvedPkg = resolver.resolve (widget);
539- if (resolvedPkg == '@flutterjs/services' ) {
540- servicesImports.add (widget);
522+ final resolvedPkg = resolver.resolve (widget);
523+ if (resolvedPkg == '@flutterjs/services' ) {
524+ servicesImports.add (widget);
525+ }
541526 }
542- }
543527
544- // Explicitly check for MethodCodec/JSONMethodCodec which might be variable types/initializers
545- // and not in sortedWidgets if they were only in usedTypes or definedNames (wait, definedNames excludes them)
546- // We just need to check usedTypes + usedWidgets
547- final serviceCandidates = {...usedWidgets, ...usedTypes};
548- for (final symbol in serviceCandidates) {
549- if (const {
550- 'MethodCall' ,
551- 'MethodCodec' ,
552- 'JSONMethodCodec' ,
553- 'PlatformException' ,
554- }.contains (symbol)) {
555- servicesImports.add (symbol);
528+ // Explicitly check for MethodCodec/JSONMethodCodec which might be variable types/initializers
529+ // and not in sortedWidgets if they were only in usedTypes or definedNames (wait, definedNames excludes them)
530+ // We just need to check usedTypes + usedWidgets
531+ final serviceCandidates = {...usedWidgets, ...usedTypes};
532+ for (final symbol in serviceCandidates) {
533+ if (const {
534+ 'MethodCall' ,
535+ 'MethodCodec' ,
536+ 'JSONMethodCodec' ,
537+ 'PlatformException' ,
538+ }.contains (symbol)) {
539+ servicesImports.add (symbol);
540+ }
556541 }
557- }
558542
559- if (servicesImports.isNotEmpty) {
560- code.writeln ('import {' );
561- for (final symbol in servicesImports.toList ()..sort ()) {
562- code.writeln (' $symbol ,' );
543+ if (servicesImports.isNotEmpty) {
544+ code.writeln ('import {' );
545+ for (final symbol in servicesImports.toList ()..sort ()) {
546+ code.writeln (' $symbol ,' );
547+ }
548+ code.writeln (
549+ '} from \' @flutterjs/services/dist/index.js\' ;' ,
550+ ); // Use specific path or index? index.js is safe.
551+ code.writeln ();
563552 }
564- code.writeln (
565- '} from \' @flutterjs/services/dist/index.js\' ;' ,
566- ); // Use specific path or index? index.js is safe.
567- code.writeln ();
568- }
569553 } // end of web-only material/services block
570554
571555 // -----------------------------------------------------------------------
572556 // EXTERNAL PACKAGE IMPORTS (url_launcher, shared_preferences, etc.)
573557 // -----------------------------------------------------------------------
574- final externalImports = < String , Set <String >> {}; // packageName -> {symbols}
558+ final externalImports =
559+ < String , Set <String >> {}; // packageName -> {symbols}
575560
576561 // Dart built-in functions that should not be imported as JS symbols
577- const dartBuiltinFunctions = {
578- 'print' ,
579- 'identical' ,
580- 'identityHashCode' ,
581- };
562+ const dartBuiltinFunctions = {'print' , 'identical' , 'identityHashCode' };
582563
583564 for (final func in usedFunctions) {
584565 if (definedNames.contains (func)) continue ;
@@ -650,7 +631,8 @@ class FileCodeGen {
650631 // SAME-PACKAGE SIBLING FILE IMPORTS
651632 // -----------------------------------------------------------------------
652633 // Detect symbols used from other files in the same package
653- final samePackageImports = < String , Set <String >> {}; // relativePath -> {symbols}
634+ final samePackageImports =
635+ < String , Set <String >> {}; // relativePath -> {symbols}
654636
655637 final allUsedSymbols = {...usedWidgets, ...usedTypes, ...usedFunctions};
656638
0 commit comments