Просмотр исходного кода

[new]增加输入输出配置目录

zk 10 месяцев назад
Родитель
Сommit
b007c3161f
3 измененных файлов с 141 добавлено и 27 удалено
  1. 22 1
      README.md
  2. 67 0
      lib/flutter_string_get_config.dart
  3. 52 26
      lib/string_get_runner.dart

+ 22 - 1
README.md

@@ -1 +1,22 @@
-用于将string.xml自动转换为string.gen.dart
+```markdown
+# 用于将 `string.xml` 自动转换为 `string.gen.dart`
+
+## 配置
+
+### 输入输出配置
+
+可不配置,默认如下:
+
+```yaml
+flutter_string_get:
+  input: assets/string/base/*.xml           # 输入目录
+  output: lib/resource/string.gen.dart      # 输出文件
+```
+
+### 建议
+
+在 `watch` 时使用以下命令,冲突时自动删除:
+
+```bash
+dart run build_runner watch --delete-conflicting-outputs
+```

+ 67 - 0
lib/flutter_string_get_config.dart

@@ -0,0 +1,67 @@
+import 'package:yaml/yaml.dart';
+import 'dart:io';
+import 'package:path/path.dart' as path;
+
+class FlutterStringGetConfig {
+  String inputDir;
+  String outputFile;
+
+  FlutterStringGetConfig({
+    required this.inputDir,
+    required this.outputFile,
+  });
+
+  factory FlutterStringGetConfig.defaults() {
+    return FlutterStringGetConfig(
+      inputDir: 'assets/string/base/*.xml',
+      outputFile: 'lib/resource/string.gen.dart',
+    );
+  }
+
+  factory FlutterStringGetConfig.fromProject() {
+    try {
+      final getConfig = FlutterStringGetConfig.defaults();
+      final file = File('pubspec.yaml');
+      if (!file.existsSync()) return getConfig;
+
+      final yamlContent = file.readAsStringSync();
+      final yaml = loadYaml(yamlContent);
+      final config = yaml['flutter_string_get'];
+
+      if (config == null) return getConfig;
+      String input = _normalizePath(config['input']?.toString());
+      String output = _normalizePath(config['output']?.toString());
+
+      if (input.isNotEmpty) {
+        getConfig.inputDir = input;
+      }
+      if (output.isNotEmpty) {
+        getConfig.outputFile = output;
+      }
+      return getConfig;
+    } catch (e) {
+      print('Error parsing flutter_string_get config: $e');
+      return FlutterStringGetConfig.defaults();
+    }
+  }
+
+  static String _normalizePath(String? rawPath, {bool isDirectory = false}) {
+    if (rawPath == null || rawPath.isEmpty) return '';
+
+    // 强制替换所有反斜杠为正斜杠(跨平台兼容)
+    final unifiedPath = rawPath.replaceAll(r'\', '/');
+
+    // 保留目录末尾的斜杠
+    bool hasTrailingSlash = unifiedPath.endsWith('/');
+    String normalized = unifiedPath;
+
+    // 仅处理路径中的 `.` 和 `..`
+    normalized = path.posix.normalize(normalized); // 使用 posix 风格的 normalize
+
+    if (isDirectory && !hasTrailingSlash) {
+      normalized += '/';
+    }
+
+    return normalized;
+  }
+}

+ 52 - 26
lib/string_get_runner.dart

@@ -1,57 +1,82 @@
 import 'package:build/build.dart';
 import 'package:build/build.dart';
 import 'package:xml/xml.dart';
 import 'package:xml/xml.dart';
 import 'package:glob/glob.dart';
 import 'package:glob/glob.dart';
+import 'package:path/path.dart' as path;
+
+// 新增配置导入
+import 'flutter_string_get_config.dart';
 
 
 Builder stringXmlWatcherBuilder(BuilderOptions options) {
 Builder stringXmlWatcherBuilder(BuilderOptions options) {
   return StringXmlWatcherBuilder();
   return StringXmlWatcherBuilder();
 }
 }
 
 
 class StringXmlWatcherBuilder implements Builder {
 class StringXmlWatcherBuilder implements Builder {
-  static const _baseType = 'zh_CN';
-  static final _targetXmlGlob = Glob('assets/string/base/*.xml');
+  // 从配置读取参数
+  late final FlutterStringGetConfig _config;
+  late final Glob _targetXmlGlob;
+
+  StringXmlWatcherBuilder() {
+    // 初始化时加载用户配置
+    _config = FlutterStringGetConfig.fromProject();
+
+    print('string_get_runner inputDir ${_config.inputDir}');
+    print('string_get_runner outputFile ${_config.outputFile}');
+    // 动态生成Glob监听模式
+    _targetXmlGlob = Glob(_config.inputDir);
+  }
 
 
   @override
   @override
   Future<void> build(BuildStep buildStep) async {
   Future<void> build(BuildStep buildStep) async {
     final xmlFiles = await buildStep.findAssets(_targetXmlGlob).toList();
     final xmlFiles = await buildStep.findAssets(_targetXmlGlob).toList();
     final (buffer, multiBuffer) = await _processXmlFiles(buildStep, xmlFiles);
     final (buffer, multiBuffer) = await _processXmlFiles(buildStep, xmlFiles);
 
 
+    // 使用配置中的输出路径
     final outputId = AssetId(
     final outputId = AssetId(
       buildStep.inputId.package,
       buildStep.inputId.package,
-      'lib/resource/string.gen.dart',
+      _config.outputFile,
     );
     );
-    await buildStep.writeAsString(outputId, buffer.toString() + multiBuffer.toString());
+    await buildStep.writeAsString(
+        outputId, buffer.toString() + multiBuffer.toString());
   }
   }
 
 
-  Future<(StringBuffer, StringBuffer)> _processXmlFiles(
-      BuildStep buildStep,
-      List<AssetId> xmlFiles,
-      ) async {
+  Future<(StringBuffer, StringBuffer)> _processXmlFiles(BuildStep buildStep,
+      List<AssetId> xmlFiles,) async {
     final buffer = StringBuffer();
     final buffer = StringBuffer();
     final multiBuffer = StringBuffer();
     final multiBuffer = StringBuffer();
+
     buffer.writeln('import \'package:get/get.dart\';');
     buffer.writeln('import \'package:get/get.dart\';');
     buffer.writeln();
     buffer.writeln();
     buffer.writeln('class StringName {');
     buffer.writeln('class StringName {');
     buffer.writeln('  StringName._();');
     buffer.writeln('  StringName._();');
+
     multiBuffer.writeln('class StringMultiSource {');
     multiBuffer.writeln('class StringMultiSource {');
     multiBuffer.writeln('  StringMultiSource._();');
     multiBuffer.writeln('  StringMultiSource._();');
-    multiBuffer.writeln('  static const Map<String, Map<String, String>> values = {');
-
-    multiBuffer.writeln('    \'${_baseType}\': {');
+    multiBuffer
+        .writeln('  static const Map<String, Map<String, String>> values = {');
+    multiBuffer.writeln('    \'zh_CN\': {'); // 默认基准语言
 
 
+    print('zkzkzk xmlFiles ${xmlFiles.length}');
+    // 遍历所有 XML 文件
     for (final file in xmlFiles) {
     for (final file in xmlFiles) {
-      final content = await buildStep.readAsString(file);
-      final document = XmlDocument.parse(content);
-
-      for (final element in document.findAllElements('string')) {
-        final name = element.getAttribute('name');
-        final value = _sanitizeValue(element.text);
-
-        if (name != null) {
-          final camelCaseName = _toCamelCase(name);
-          buffer.writeln(
-              '  static final String $camelCaseName = \'$name\'.tr;// $value');
-          multiBuffer.writeln('      \'$name\': \'$value\',');
+      print('zkzkzk file ${file.path}');
+      try {
+        final content = await buildStep.readAsString(file);
+        final document = XmlDocument.parse(content);
+        print('zkzkzk document ${document.toString()}');
+        // 遍历所有 <string> 元素
+        for (final element in document.findAllElements('string')) {
+          final name = element.getAttribute('name');
+          final value = _sanitizeValue(element.text);
+
+          if (name != null) {
+            final camelCaseName = _toCamelCase(name);
+            buffer.writeln(
+                '  static final String $camelCaseName = \'$name\'.tr; // $value');
+            multiBuffer.writeln('      \'$name\': \'$value\',');
+          }
         }
         }
+      } catch (e) {
+        print('❌ Error processing file ${file.path}: $e');
       }
       }
     }
     }
 
 
@@ -74,6 +99,7 @@ class StringXmlWatcherBuilder implements Builder {
 
 
   @override
   @override
   Map<String, List<String>> get buildExtensions => {
   Map<String, List<String>> get buildExtensions => {
-    r'$package$': ['lib/resource/string.gen.dart'],
-  };
-}
+        // 动态生成扩展映射
+        r'$package$': [path.normalize(_config.outputFile)],
+      };
+}