Future main()

in tool/catalog/generate_widget_catalog.dart [19:108]


Future<void> main(List<String> args) async {
  if (path.basename(Directory.current.path) != 'tools_metadata') {
    fail('Please run this tool from the root of the repo.');
  }

  final String flutterPackagePath =
      path.absolute(path.join(flutterSdkPath, 'packages/flutter/lib'));

  print('Setting up an analysis context...');

  final List<String> includedPaths = <String>[flutterPackagePath];
  final AnalysisContextCollection collection =
      AnalysisContextCollection(includedPaths: includedPaths);

  if (collection.contexts.length != 1) {
    fail('Expected one analysis context, found ${collection.contexts.length}.');
  }

  final AnalysisContext context = collection.contexts.first;
  final AnalysisSession session = context.currentSession;

  final List<String> files = context.contextRoot.analyzedFiles().toList();

  print('Scanning Dart files...');
  final List<String> libraryFiles = <String>[];
  for (final String file in files) {
    final SourceKind kind = await session.getSourceKind(file);
    if (kind == SourceKind.LIBRARY) {
      libraryFiles.add(file);
    }
  }
  print('  ${libraryFiles.length} dart files');

  print("Resolving class 'Widget'...");

  final LibraryElement widgetsLibrary = await session
      .getLibraryByUri('package:flutter/src/widgets/framework.dart');

  final ClassElement widgetClass = widgetsLibrary.getType('Widget');

  print('Resolving widget subclasses...');
  final List<ClassElement> classes = <ClassElement>[];
  for (final String file in libraryFiles) {
    final ResolvedLibraryResult resolvedLibraryResult =
        await session.getResolvedLibrary(file);

    final LibraryElement lib = resolvedLibraryResult.element;
    for (final Element element in lib.topLevelElements) {
      if (element is! ClassElement) {
        continue;
      }

      final ClassElement clazz = element as ClassElement;
      if (clazz.allSupertypes.contains(widgetClass.thisType)) {
        // Hide private classes.
        final String name = clazz.name;
        if (!name.startsWith('_')) {
          classes.add(clazz);
        }
      }
    }
  }
  print('  ${classes.length} widgets');

  // Normalize the output json.
  classes.sort((ClassElement a, ClassElement b) => a.name.compareTo(b.name));

  final File file = File('resources/catalog/widgets.json');
  print('Generating ${path.relative(path.absolute(file.path))}...');
  final List<Map<String, Object>> widgets = <Map<String, Object>>[];
  for (final ClassElement c in classes) {
    widgets.add(_convertToJson(c, widgetClass));
  }

  final Map<String, String> versionInfo = calculateFlutterVersion();

  final Map<String, dynamic> json = <String, dynamic>{
    'flutter': <String, dynamic>{
      'version': versionInfo['frameworkVersion'],
      'channel': versionInfo['channel'],
    },
    'widgets': widgets,
  };

  const JsonEncoder encoder = JsonEncoder.withIndent('  ');
  final String output = encoder.convert(json);
  file.writeAsStringSync('$output\n');
  final int kb = (file.lengthSync() + 1023) ~/ 1024;
  print('  ${kb}kb');
}