Mobile Development 12 min read

Implementation and Mechanism of the Fair Syntax Detection Plugin for Flutter

This article explains how Flutter's built‑in analysis server works, describes the architecture and mounting process of a custom Fair syntax‑detection plugin, and details its core implementation—including AST traversal, @FairPatch annotation handling, if‑statement checks, and the Fair sugar utilities—accompanied by code examples and demo screenshots.

58 Tech
58 Tech
58 Tech
Implementation and Mechanism of the Fair Syntax Detection Plugin for Flutter

Flutter is Google’s cross‑platform UI framework, and Fair is 58 Technology’s dynamic framework that enables runtime UI and logic updates; developers often encounter incorrect or unsupported Fair syntax sugar, prompting the need for a dedicated plugin that can detect and guide proper usage.

In the IDE, Flutter’s syntax detection relies on the Dart/Flutter plugin, which in turn uses the Dart Analysis Server (a static analysis service providing code hints, completions, and diagnostics). The plugin communicates with the server via a socket: when source files change, the plugin sends updates, receives analysis results, and refreshes the IDE view.

The Analysis Server is started by the plugin after the user configures the Dart SDK path. The plugin locates the SDK, builds the command line for analysis_server.dart.snapshot , creates a StdioServerSocket , and launches the server process:

//获取配置的SDK路径
mySdkHome = sdk.getHomePath();
//找到dart可执行文件的路径
final String runtimePath = FileUtil.toSystemDependentName(DartSdkUtil.getDartExePath(sdk));
//找到analysis_server.dart.snapshot文件路径
String analysisServerPath = FileUtil.toSystemDependentName(mySdkHome + "/bin/snapshots/analysis_server.dart.snapshot");
String firstArgument = useDartLangServerCall ? "language-server" : analysisServerPath;
myServerSocket = new StdioServerSocket(runtimePath, StringUtil.split(vmArgsRaw, " "), firstArgument, StringUtil.split(serverArgsRaw, " "), debugStream);
final RemoteAnalysisServerImpl startedServer = new RemoteAnalysisServerImpl(myServerSocket);
startedServer.start();

Communication between the Dart plugin and the Analysis Server uses two message types: id (request/response) and event (notifications). Each request carries a unique ID generated by an AtomicInteger . Example request format:

request: {
  "id": String,
  "method": "analysis.setAnalysisRoots",
  "params": {
    "included": List
,
    "excluded": List
,
    "packageRoots": optional Map
}
}

The plugin mounting process involves parsing analysis_options.yaml to obtain the list of analyzer plugins, locating each plugin’s directory, copying it to a unique cache directory (derived from an MD5 of the path), and executing the plugin’s plugin.dart entry point.

Fair’s syntax‑detection plugin extends ServerPlugin . After creating a subclass of ServerPlugin , the plugin is registered in plugin.dart :

void main(List
args, SendPort sendPort) {
  ServerPluginStarter(FairPlugin(PhysicalResourceProvider.INSTANCE)).start(sendPort);
}

The core of the plugin traverses the Dart abstract syntax tree (AST) using a RecursiveAstVisitor . It detects the custom @FairPatch annotation, filters for the build method, and then inspects if statements (both IfStatement and IfElement ) to enforce Fair’s sugar rules. Sample visitor for the annotation:

class _FairVisitor extends RecursiveAstVisitor
{
  @override
  void visitAnnotation(Annotation node) {
    node.visitChildren(this);
    if (node.name.name == 'FairPatch') {
      // custom handling
    }
  }
}

Detection of if syntax involves checking that the method is build and that the condition uses Fair’s sugar utilities ( Sugar.ifRange , Sugar.ifEqual , Sugar.ifEqualBool ). Example for detecting ifRange calls:

@override
void visitMethodDeclaration(MethodDeclaration node) {
  if (node.name.name == 'contains') {
    // handle contains call
  }
}

@Override
void visitMethodInvocation(MethodInvocation node) {
  super.visitMethodInvocation(node);
  _result = node.target?.staticType?.isDartCoreList ?? false;
  if (_result) {
    _target = node.target;
    _actual = node.argumentList.arguments.first;
  }
}

Fair’s sugar utilities are defined as generic static methods, for example:

static K ifRange
(T actual, List
expect, {required K trueValue, required K falseValue}) =>
    expect.contains(actual) ? trueValue : falseValue;

static K ifEqual
(T actual, T expect, {required K trueValue, required K falseValue}) =>
    expect == actual ? trueValue : falseValue;

static K ifEqualBool
(bool state, {required K trueValue, required K falseValue}) =>
    state ? trueValue : falseValue;

Demo screenshots show Android Studio highlighting improper if usage inside build() , offering quick‑fix actions, and allowing developers to apply the suggested Fair sugar replacements directly from the IDE.

The article concludes with a call for community contributions, links to the Fair GitHub repository, documentation, and contact information for joining the developer group.

DartFluttermobile developmentFAIRanalysis-serversyntax-detection
58 Tech
Written by

58 Tech

Official tech channel of 58, a platform for tech innovation, sharing, and communication.

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.