You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用面向对象方式解析并修改Dart源代码?

解决方案

方法1:直接操作Analyzer AST生成修改后的代码

Analyzer的AST虽为不可变设计,但可通过创建新节点替换原有节点实现修改,无需额外中间层:

  1. 用parseFile解析模板文件得到CompilationUnit语法树
  2. 自定义AstVisitor遍历树,定位到目标类节点
  3. 复制原有类的成员列表,添加生成的函数节点,创建新的ClassDeclaration
  4. 替换CompilationUnit中的原类节点,最后用toSource()生成代码并格式化

示例代码:

import 'package:analyzer/dart/analysis/features.dart';
import 'package:analyzer/dart/analysis/utilities.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/visitor.dart';
import 'package:dart_style/dart_style.dart';

class ClassUpdater extends RecursiveAstVisitor {
  final String targetClass;
  final FunctionDeclaration newFunc;
  ClassDeclaration? updatedClass;

  ClassUpdater(this.targetClass, this.newFunc);

  @override
  void visitClassDeclaration(ClassDeclaration node) {
    if (node.name.name == targetClass) {
      // 复制原有成员并添加新函数
      final newMembers = [...node.members, newFunc];
      // 创建新的类节点
      updatedClass = node.copyWith(members: newMembers);
    }
    super.visitClassDeclaration(node);
  }
}

String updateClassInFile(String templatePath, FunctionDeclaration newFunc, String className) {
  // 解析模板文件
  final parseResult = parseFile(
    path: templatePath,
    featureSet: FeatureSet.latestLanguageVersion(),
  );
  final unit = parseResult.unit;

  // 遍历并更新类
  final updater = ClassUpdater(className, newFunc);
  unit.accept(updater);

  if (updater.updatedClass == null) throw Exception('Class $className not found');

  // 替换原类节点,生成新的CompilationUnit
  final newDeclarations = unit.declarations.map((decl) {
    if (decl is ClassDeclaration && decl.name.name == className) {
      return updater.updatedClass!;
    }
    return decl;
  }).toList();
  final newUnit = unit.copyWith(declarations: newDeclarations);

  // 生成并格式化代码
  return DartFormatter().format(newUnit.toSource());
}

方法2:用Analyzer提取元数据,code_builder重建类

若觉得直接操作AST繁琐,可拆分步骤:用Analyzer读取原有类的结构信息,再用code_builder重新构建类并添加新函数:

  1. 解析模板文件,提取目标类的名称、现有方法/字段
  2. 用code_builder的ClassBuilder复刻原有类,添加新方法
  3. 生成代码并格式化

示例代码:

import 'package:analyzer/dart/analysis/utilities.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:code_builder/code_builder.dart';
import 'package:dart_style/dart_style.dart';

ClassBuilder buildClassFromAst(ClassDeclaration classAst) {
  final classBuilder = ClassBuilder()..name = classAst.name.name;

  // 复刻原有方法
  for (final member in classAst.members) {
    if (member is FunctionDeclaration) {
      final method = MethodBuilder()
        ..name = member.name.name
        ..returns = refer(member.returnType?.toSource() ?? 'void')
        ..body = Code(member.body.toSource());
      // 处理参数(简化示例,可根据需求完善)
      for (final param in member.functionExpression.parameters?.parameters ?? []) {
        method.requiredParameters.add(Parameter((p) => p.name = param.identifier.name));
      }
      classBuilder.methods.add(method);
    }
  }

  return classBuilder;
}

String regenerateClass(String templatePath, MethodBuilder newMethod, String className) {
  final unit = parseFile(
    path: templatePath,
    featureSet: FeatureSet.latestLanguageVersion(),
  ).unit;

  // 找到目标类
  final classAst = unit.declarations.firstWhere(
    (d) => d is ClassDeclaration && (d as ClassDeclaration).name.name == className,
  ) as ClassDeclaration;

  // 构建类并添加新方法
  final classBuilder = buildClassFromAst(classAst);
  classBuilder.methods.add(newMethod);

  // 生成代码
  final emitter = DartEmitter();
  final library = Library((l) => l.body.add(classBuilder.build()));
  return DartFormatter().format(library.accept(emitter).toString());
}

极简方案(适合简单场景)

如果只是在类末尾添加函数,且模板文件格式稳定,可直接用字符串操作:读取文件内容,定位到类的}前,插入新函数代码,最后格式化。这种方法开销最小,但不适合复杂AST修改场景。


内容的提问来源于stack exchange,提问作者Ty Landercasper

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 14:15:35