Mobile Development 13 min read

Automated Parsing and Code Generation for the TolyUI Flutter Framework

This article explains how the TolyUI Flutter UI framework automates the parsing of component demo files and generates corresponding Dart code using annotations, regular expressions, and a command‑line tool, thereby simplifying maintenance and improving development efficiency for mobile applications.

Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Automated Parsing and Code Generation for the TolyUI Flutter Framework

TolyUI is a cross‑platform UI framework for Flutter created by Zhang Fengjie, featuring full‑platform support, componentization, open source code, and reactivity. It aims to help developers quickly build responsive applications.

As the number of components grows, manually maintaining the introduction nodes (title, description, code, content) becomes cumbersome. The author proposes an automated solution that parses source files and generates the necessary code.

The solution consists of two main parts: parsing files and automatically generating code. Three generated artifacts are defined:

[1] The displayNodes data is generated into node.g.dart .

[2] Large demo code is stored in asset files and loaded on demand.

[3] Component‑to‑demo mapping is maintained in widget_display_map.g.dart .

Each demo file contains a NodeMeta object that holds the code string, file path, name, and a DisplayNode annotation. The class is defined as:

class NodeMeta {
  final String code;
  final String name;
  final String filePath;
  final DisplayNode display;

  const NodeMeta({
    required this.filePath,
    required this.code,
    required this.name,
    required this.display,
  });
}

A DisplayFileParser parses a file path, extracts the class definition and @DisplayNode annotation using regular expressions, and returns a NodeMeta instance:

class DisplayFileParser {
  final String path;
  static final RegExp _codeRegex = RegExp(r'class (?
\w+)(.|\s)*');
  static final RegExp _displayRegex = RegExp(r'@DisplayNode(.|\s)*?\)');

  const DisplayFileParser(this.path);

  Future
parser() async {
    if (!path.contains('_demo')) return null;
    File file = File(path);
    String content = await file.readAsString();
    bool hasDisplay = content.contains('@DisplayNode(');
    if (!hasDisplay) return null;
    return _parserContent(path, content);
  }
}

The helper function creates the NodeMeta from the regex matches:

NodeMeta _parserContent(String filePath, String content) {
  RegExpMatch? codeMatch = _codeRegex.firstMatch(content);
  String? code = codeMatch?.group(0);
  String? name = codeMatch?.namedGroup('name');
  String? display = _displayRegex.firstMatch(content)?.group(0);
  return NodeMeta(
    filePath: filePath,
    name: name ?? '',
    code: code ?? '',
    display: DisplayNode.fromString(display ?? ''),
  );
}

All demo files under the widgets directory are traversed, parsed, and collected into a Map > displayMap :

void main() async {
  String widgetPath = path.join(Directory.current.path, 'lib', 'view', 'widgets');
  Directory widgetDir = Directory(widgetPath);
  Map
> displayMap = {};
  await parserDir(widgetDir, displayMap);
}

Future
parserDir(Directory dir, Map
> displayMap) async {
  List
displays = [];
  List
entity = dir.listSync();
  for (FileSystemEntity e in entity) {
    if (e is File) {
      NodeMeta? ret = await DisplayFileParser(e.path).parser();
      if (ret != null) {
        displays.add(ret);
        ret.saveCode();
      }
    } else if (e is Directory) {
      await parserDir(e, displayMap);
    }
  }
  if (displays.isNotEmpty) {
    displayMap[path.basename(dir.path)] = displays;
  }
}

Code generation uses the collected displayMap to produce node.g.dart and component‑specific part files. The template for the main file is:

String nodeTemplate(String content, String part) {
  return """
/// ===================================================
/// Power By 张风捷特烈 --- Generated file. Do not edit.
/// github: https://github.com/toly1994328
/// ===================================================
$part
Map
queryDisplayNodes(String name){
  return switch(name){
    $content    _ => {},
  };
}
""";
}

Each component’s node list is generated with a similar template using part and part of directives. The generator writes the assembled strings to files via the FileGen class:

class FileGen {
  final Map
> displayMap;
  FileGen(this.displayMap);
}

Finally, the whole process is wrapped into a command‑line tool ( toly ui ) that regenerates all code in about 100 ms, allowing developers to keep demo information up‑to‑date automatically.

The article concludes that TolyUI now supports a flexible dropdown menu component and invites readers to follow its development on GitHub.

DartFluttercode generationAutomationParsingAnnotations
Rare Earth Juejin Tech Community
Written by

Rare Earth Juejin Tech Community

Juejin, a tech community that helps developers grow.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.