From bc6907b940610224910331a5f72b66083e034e3f Mon Sep 17 00:00:00 2001
From: Pavel Akhrameev
Date: Fri, 5 Jun 2026 12:26:15 +0400
Subject: [PATCH 1/2] fix: add xml 7.x support
Widen flutter_gen_core's `xml` constraint from `^6.0.0` to
`>=6.0.0 <8.0.0`, so projects depending on both flutter_gen and
`xml: ^7.0.0` can resolve. Replace the deprecated `XmlNode.text`
with `XmlNode.innerText` (present since xml 6.0.0, so compatible
with both majors).
Add a cross-platform Dart matrix (scripts/test_xml_versions.dart,
exposed as `melos test:xml-matrix`) plus a CI step that runs
flutter_gen_core's tests against both xml 6.x and 7.x via a temporary
dependency_overrides, so neither major regresses.
Closes #761
---
.github/workflows/build.yml | 4 +
melos.yaml | 4 +
.../core/lib/generators/colors_generator.dart | 3 +-
packages/core/pubspec.yaml | 2 +-
scripts/test_xml_versions.dart | 117 ++++++++++++++++++
5 files changed, 127 insertions(+), 3 deletions(-)
create mode 100644 scripts/test_xml_versions.dart
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 9037ef35c..36c7fe0d4 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -44,6 +44,10 @@ jobs:
if: startsWith(matrix.os, 'ubuntu')
run: melos test:dart --no-select
+ - name: Test flutter_gen_core against both xml majors (6.x and 7.x)
+ if: startsWith(matrix.os, 'ubuntu')
+ run: melos test:xml-matrix
+
- name: Run tests for Flutter packages
if: startsWith(matrix.os, 'ubuntu')
run: melos test:flutter --no-select
diff --git a/melos.yaml b/melos.yaml
index 7e262c157..af410db08 100644
--- a/melos.yaml
+++ b/melos.yaml
@@ -122,6 +122,10 @@ scripts:
bash ./scripts/coverage.sh packages/core
description: bash ./scripts/coverage.sh packages/core
+ test:xml-matrix:
+ run: dart scripts/test_xml_versions.dart
+ description: Run flutter_gen_core tests against both supported xml majors (6.x and 7.x)
+
publish:force:
run: dart pub publish -f
exec:
diff --git a/packages/core/lib/generators/colors_generator.dart b/packages/core/lib/generators/colors_generator.dart
index 3d022eee2..6aaeb884d 100644
--- a/packages/core/lib/generators/colors_generator.dart
+++ b/packages/core/lib/generators/colors_generator.dart
@@ -106,8 +106,7 @@ class _Color {
_Color.fromXmlElement(XmlElement element)
: this(
element.getAttribute('name')!,
- // ignore: deprecated_member_use
- element.text,
+ element.innerText,
element.getAttribute('type')?.split(' ') ?? List.empty(),
);
diff --git a/packages/core/pubspec.yaml b/packages/core/pubspec.yaml
index a2371c304..34cbc8c6c 100644
--- a/packages/core/pubspec.yaml
+++ b/packages/core/pubspec.yaml
@@ -17,7 +17,7 @@ dependencies:
path: ^1.8.0
yaml: ^3.0.0
mime: '>=1.0.0 <3.0.0'
- xml: ^6.0.0
+ xml: '>=6.0.0 <8.0.0'
dartx: ^1.0.0
color: ^3.0.0
collection: ^1.15.0
diff --git a/scripts/test_xml_versions.dart b/scripts/test_xml_versions.dart
new file mode 100644
index 000000000..aa957cecc
--- /dev/null
+++ b/scripts/test_xml_versions.dart
@@ -0,0 +1,117 @@
+// Verify flutter_gen_core works against every supported major `xml` version.
+//
+// The package declares `xml: '>=6.0.0 <8.0.0'`, but `dart pub get` is
+// conservative and resolves to the 6.x line by default (because the package
+// still supports older SDKs, while xml 7.x requires Dart >= 3.11). As a result
+// the normal `melos test` only ever exercises one of the two majors.
+//
+// This script pins each major in turn via a temporary `pubspec_overrides.yaml`
+// (gitignored) and runs the core test suite against it, so a regression on
+// either xml 6.x or 7.x is caught.
+//
+// It is pure Dart (only `dart:io`) so it runs identically on Linux, macOS and
+// Windows. The xml 7.x pass requires Dart >= 3.11; on older toolchains it is
+// skipped with a warning instead of failing.
+//
+// Run via `melos test:xml-matrix` or `dart scripts/test_xml_versions.dart`.
+
+import 'dart:io';
+
+Future main() async {
+ final coreDir = Directory('${_repoRoot().path}/packages/core');
+ final override = File('${coreDir.path}/pubspec_overrides.yaml');
+
+ // Always remove the temporary override and re-resolve so the working tree
+ // and lockfile are left in their default state, even if a pass fails.
+ void cleanup() {
+ if (override.existsSync()) override.deleteSync();
+ Process.runSync(
+ Platform.resolvedExecutable,
+ ['pub', 'get'],
+ workingDirectory: coreDir.path,
+ );
+ }
+
+ try {
+ await _runPass('^6.0.0', coreDir, override);
+
+ final dart = _dartVersion();
+ if (dart.major > 3 || (dart.major == 3 && dart.minor >= 11)) {
+ await _runPass('^7.0.0', coreDir, override);
+ } else {
+ stdout.writeln('\n⚠️ Skipping xml 7.x pass: requires Dart >= 3.11 '
+ '(found ${dart.major}.${dart.minor}).');
+ }
+ } catch (error) {
+ cleanup();
+ stderr.writeln('\n❌ $error');
+ exit(1);
+ }
+
+ cleanup();
+ stdout
+ .writeln('\n✅ flutter_gen_core passed against all checked xml versions.');
+}
+
+Future _runPass(
+ String constraint,
+ Directory coreDir,
+ File override,
+) async {
+ stdout.writeln('\n========================================================');
+ stdout.writeln(' flutter_gen_core test pass — pinning xml: $constraint');
+ stdout.writeln('========================================================');
+ override.writeAsStringSync('dependency_overrides:\n xml: $constraint\n');
+ await _dart(['pub', 'get'], coreDir);
+ stdout.writeln('-> resolved xml ${_resolvedXmlVersion(coreDir)}');
+ await _dart(['test'], coreDir);
+}
+
+/// Runs `dart ` in [cwd], streaming output, and throws on failure.
+Future _dart(List args, Directory cwd) async {
+ final process = await Process.start(
+ Platform.resolvedExecutable,
+ args,
+ workingDirectory: cwd.path,
+ mode: ProcessStartMode.inheritStdio,
+ );
+ final code = await process.exitCode;
+ if (code != 0) {
+ throw 'dart ${args.join(' ')} failed (exit $code) in ${cwd.path}';
+ }
+}
+
+/// Parses the running Dart SDK version, e.g. "3.11.3 (stable) (...)".
+({int major, int minor}) _dartVersion() {
+ final parts = Platform.version.split(' ').first.split('.');
+ return (major: int.parse(parts[0]), minor: int.parse(parts[1]));
+}
+
+/// Reads the resolved `xml` version out of `packages/core/pubspec.lock`.
+String _resolvedXmlVersion(Directory coreDir) {
+ final lock = File('${coreDir.path}/pubspec.lock');
+ if (!lock.existsSync()) return 'unknown';
+ final lines = lock.readAsLinesSync();
+ for (var i = 0; i < lines.length; i++) {
+ if (lines[i].trimRight() == ' xml:') {
+ for (var j = i + 1;
+ j < lines.length && lines[j].startsWith(' ');
+ j++) {
+ final match = RegExp(r'version:\s*"?([^"\s]+)"?').firstMatch(lines[j]);
+ if (match != null) return match.group(1)!;
+ }
+ }
+ }
+ return 'unknown';
+}
+
+/// Locates the melos workspace root by walking up from this script's location,
+/// falling back to the current directory (melos runs scripts from the root).
+Directory _repoRoot() {
+ var dir = File.fromUri(Platform.script).parent;
+ while (dir.path != dir.parent.path) {
+ if (File('${dir.path}/melos.yaml').existsSync()) return dir;
+ dir = dir.parent;
+ }
+ return Directory.current;
+}
From ee80d45e5e3d3b0e7e985016217903f09464a7ae Mon Sep 17 00:00:00 2001
From: Pavel Akhrameev
Date: Mon, 8 Jun 2026 17:21:00 +0400
Subject: [PATCH 2/2] fix tests: pin image below 4.9.0 in xml 6.x matrix pass
---
scripts/test_xml_versions.dart | 33 +++++++++++++++++++++++++--------
1 file changed, 25 insertions(+), 8 deletions(-)
diff --git a/scripts/test_xml_versions.dart b/scripts/test_xml_versions.dart
index aa957cecc..8b7c71488 100644
--- a/scripts/test_xml_versions.dart
+++ b/scripts/test_xml_versions.dart
@@ -1,14 +1,20 @@
// Verify flutter_gen_core works against every supported major `xml` version.
//
-// The package declares `xml: '>=6.0.0 <8.0.0'`, but `dart pub get` is
-// conservative and resolves to the 6.x line by default (because the package
-// still supports older SDKs, while xml 7.x requires Dart >= 3.11). As a result
-// the normal `melos test` only ever exercises one of the two majors.
+// The package declares `xml: '>=6.0.0 <8.0.0'`, but a normal `dart pub get`
+// only ever resolves one major: `image` (a transitive dependency) pins `xml`,
+// so its newest releases force `xml` 7.x. As a result the normal `melos test`
+// never exercises the 6.x line.
//
// This script pins each major in turn via a temporary `pubspec_overrides.yaml`
// (gitignored) and runs the core test suite against it, so a regression on
// either xml 6.x or 7.x is caught.
//
+// The 6.x pass also pins `image` below 4.9.0: `image` 4.9.0+ requires `xml`
+// ^7.0.1, so a downstream package constrained to `xml` 6.x resolves `image`
+// to its last 6.x-compatible release (4.8.0). Pinning only `xml` would instead
+// leave the newest `image` overridden onto an incompatible `xml` and fail to
+// compile, which is not a real resolution any consumer could hit.
+//
// It is pure Dart (only `dart:io`) so it runs identically on Linux, macOS and
// Windows. The xml 7.x pass requires Dart >= 3.11; on older toolchains it is
// skipped with a warning instead of failing.
@@ -33,7 +39,15 @@ Future main() async {
}
try {
- await _runPass('^6.0.0', coreDir, override);
+ // image 4.9.0+ requires xml ^7.0.1, so the xml 6.x pass must also pin
+ // image to its last 6.x-compatible release. This mirrors what pub resolves
+ // for a downstream package constrained to xml 6.x.
+ await _runPass(
+ '^6.0.0',
+ coreDir,
+ override,
+ extraOverrides: {'image': "'>=4.5.4 <4.9.0'"},
+ );
final dart = _dartVersion();
if (dart.major > 3 || (dart.major == 3 && dart.minor >= 11)) {
@@ -56,12 +70,15 @@ Future main() async {
Future _runPass(
String constraint,
Directory coreDir,
- File override,
-) async {
+ File override, {
+ Map extraOverrides = const {},
+}) async {
stdout.writeln('\n========================================================');
stdout.writeln(' flutter_gen_core test pass — pinning xml: $constraint');
stdout.writeln('========================================================');
- override.writeAsStringSync('dependency_overrides:\n xml: $constraint\n');
+ final overrides = StringBuffer('dependency_overrides:\n xml: $constraint\n');
+ extraOverrides.forEach((name, c) => overrides.writeln(' $name: $c'));
+ override.writeAsStringSync(overrides.toString());
await _dart(['pub', 'get'], coreDir);
stdout.writeln('-> resolved xml ${_resolvedXmlVersion(coreDir)}');
await _dart(['test'], coreDir);