chore: adopt Dart 3.9 toolchain — honest floor + tall-style reformat (T-353)

Raise the declared minimums in pubspec.yaml to what our deps already
require: Flutter >=3.35.0 / Dart >=3.9.0 (was 3.19.0 / 3.5.0). alchemist
0.12 needs Flutter 3.32; Dart 3.9 first ships in Flutter 3.35, so 3.35 is
the binding floor. Pin the exact build toolchain in .fvmrc (Flutter
3.44.1).

Moving to the Dart 3.9 language level switches `dart format` to the new
"tall" style and enables two new lints. This commit is the resulting
mechanical churn, isolated from any behaviour change:
  - whole-tree `dart format` reformat (tall style)
  - `dart fix` for unnecessary_underscores + use_null_aware_elements

No runtime behaviour change; `make test` green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-11 12:11:53 +02:00
co-authored by Claude Opus 4.8
parent bcea5f15b7
commit 6d0ebab721
444 changed files with 7587 additions and 12849 deletions
+4 -12
View File
@@ -29,9 +29,7 @@ class _MapAssetBundle extends CachingAssetBundle {
void main() {
group('AssetCatalogLoader', () {
test('returns parsed JSON for a present asset', () async {
final bundle = _MapAssetBundle({
'lib/kernel/src/i18n/catalog/welcome_en_us.json': '{"title":{"translation":"Hi"}}',
});
final bundle = _MapAssetBundle({'lib/kernel/src/i18n/catalog/welcome_en_us.json': '{"title":{"translation":"Hi"}}'});
final loader = AssetCatalogLoader(bundle: bundle);
final r = await loader.load('welcome', const Locale('en', 'US'));
expect(r['title'], isA<Map>());
@@ -44,25 +42,19 @@ void main() {
});
test('returns an empty map on malformed JSON (FormatException catch)', () async {
final bundle = _MapAssetBundle({
'lib/kernel/src/i18n/catalog/welcome_en_us.json': 'not json at all',
});
final bundle = _MapAssetBundle({'lib/kernel/src/i18n/catalog/welcome_en_us.json': 'not json at all'});
final loader = AssetCatalogLoader(bundle: bundle);
expect(await loader.load('welcome', const Locale('en', 'US')), isEmpty);
});
test('returns an empty map when the asset is blank', () async {
final bundle = _MapAssetBundle({
'lib/kernel/src/i18n/catalog/welcome_en_us.json': ' \n',
});
final bundle = _MapAssetBundle({'lib/kernel/src/i18n/catalog/welcome_en_us.json': ' \n'});
final loader = AssetCatalogLoader(bundle: bundle);
expect(await loader.load('welcome', const Locale('en', 'US')), isEmpty);
});
test('returns an empty map when JSON parses to a non-object', () async {
final bundle = _MapAssetBundle({
'lib/kernel/src/i18n/catalog/welcome_en_us.json': '[1, 2, 3]',
});
final bundle = _MapAssetBundle({'lib/kernel/src/i18n/catalog/welcome_en_us.json': '[1, 2, 3]'});
final loader = AssetCatalogLoader(bundle: bundle);
expect(await loader.load('welcome', const Locale('en', 'US')), isEmpty);
});
+71 -88
View File
@@ -30,11 +30,7 @@ void main() {
}
test('locale getters reflect constructor arguments', () {
final i = build(
catalogs: const {},
initial: const Locale('nl', 'NL'),
defaultLocale: const Locale('en', 'US'),
);
final i = build(catalogs: const {}, initial: const Locale('nl', 'NL'), defaultLocale: const Locale('en', 'US'));
expect(i.currentLocale, const Locale('nl', 'NL'));
expect(i.defaultLocale, const Locale('en', 'US'));
expect(i.availableLocales, [const Locale('en', 'US'), const Locale('nl', 'NL')]);
@@ -43,10 +39,7 @@ void main() {
test('missing key with placeholder returns placeholder', () async {
final i = build(catalogs: const {});
await i.ensureNamespaceLoaded('builtin.x');
expect(
i.string('missing', namespace: 'builtin.x', placeholder: 'fallback'),
'fallback',
);
expect(i.string('missing', namespace: 'builtin.x', placeholder: 'fallback'), 'fallback');
});
test('missing key with null placeholder returns the key', () async {
@@ -57,68 +50,66 @@ void main() {
test('unknown namespace still returns placeholder (no crash)', () {
final i = build(catalogs: const {});
expect(
i.string('k', namespace: 'not.registered', placeholder: 'fb'),
'fb',
);
expect(i.string('k', namespace: 'not.registered', placeholder: 'fb'), 'fb');
});
test('exact locale hit beats fallback', () async {
final i = build(catalogs: {
'builtin.x': {
const Locale('en', 'US'): {
'greet': {'translation': 'Hello'},
},
const Locale('en'): {
'greet': {'translation': 'Hi'},
final i = build(
catalogs: {
'builtin.x': {
const Locale('en', 'US'): {
'greet': {'translation': 'Hello'},
},
const Locale('en'): {
'greet': {'translation': 'Hi'},
},
},
},
});
await i.ensureNamespaceLoaded('builtin.x');
expect(
i.string('greet', namespace: 'builtin.x', placeholder: 'fb'),
'Hello',
);
await i.ensureNamespaceLoaded('builtin.x');
expect(i.string('greet', namespace: 'builtin.x', placeholder: 'fb'), 'Hello');
});
test('language-only locale hit falls through from exact', () async {
final i = build(catalogs: {
'builtin.x': {
const Locale('nl'): {
'greet': {'translation': 'Hoi'},
final i = build(
catalogs: {
'builtin.x': {
const Locale('nl'): {
'greet': {'translation': 'Hoi'},
},
},
},
}, initial: const Locale('nl', 'NL'));
await i.ensureNamespaceLoaded('builtin.x');
expect(
i.string('greet', namespace: 'builtin.x', placeholder: 'fb'),
'Hoi',
initial: const Locale('nl', 'NL'),
);
await i.ensureNamespaceLoaded('builtin.x');
expect(i.string('greet', namespace: 'builtin.x', placeholder: 'fb'), 'Hoi');
});
test('falls through to default-locale when current locale is empty', () async {
final i = build(catalogs: {
'builtin.x': {
const Locale('en', 'US'): {
'greet': {'translation': 'Hello'},
final i = build(
catalogs: {
'builtin.x': {
const Locale('en', 'US'): {
'greet': {'translation': 'Hello'},
},
},
},
}, initial: const Locale('nl', 'NL'));
await i.ensureNamespaceLoaded('builtin.x');
expect(
i.string('greet', namespace: 'builtin.x', placeholder: 'fb'),
'Hello',
initial: const Locale('nl', 'NL'),
);
await i.ensureNamespaceLoaded('builtin.x');
expect(i.string('greet', namespace: 'builtin.x', placeholder: 'fb'), 'Hello');
});
test('interpolation replaces all replacers; missing ones silent', () async {
final i = build(catalogs: {
'builtin.x': {
const Locale('en', 'US'): {
'welcome': {'translation': 'Hi {name} at {path}'},
final i = build(
catalogs: {
'builtin.x': {
const Locale('en', 'US'): {
'welcome': {'translation': 'Hi {name} at {path}'},
},
},
},
});
);
await i.ensureNamespaceLoaded('builtin.x');
expect(
i.interpolated(
@@ -135,18 +126,20 @@ void main() {
});
test('namespace isolation — same key, different values', () async {
final i = build(catalogs: {
'a': {
const Locale('en', 'US'): {
'k': {'translation': 'A'},
final i = build(
catalogs: {
'a': {
const Locale('en', 'US'): {
'k': {'translation': 'A'},
},
},
'b': {
const Locale('en', 'US'): {
'k': {'translation': 'B'},
},
},
},
'b': {
const Locale('en', 'US'): {
'k': {'translation': 'B'},
},
},
});
);
await i.ensureNamespaceLoaded('a');
await i.ensureNamespaceLoaded('b');
expect(i.string('k', namespace: 'a', placeholder: '-'), 'A');
@@ -154,16 +147,18 @@ void main() {
});
test('setLocale refreshes cached namespaces and notifies listeners', () async {
final i = build(catalogs: {
'x': {
const Locale('en', 'US'): {
'k': {'translation': 'Hello'},
},
const Locale('nl'): {
'k': {'translation': 'Hallo'},
final i = build(
catalogs: {
'x': {
const Locale('en', 'US'): {
'k': {'translation': 'Hello'},
},
const Locale('nl'): {
'k': {'translation': 'Hallo'},
},
},
},
});
);
await i.ensureNamespaceLoaded('x');
var notified = 0;
i.addListener(() => notified++);
@@ -177,10 +172,7 @@ void main() {
i.registerCatalog('ext.linear', const Locale('en', 'US'), const {
'issue.title': {'translation': 'Issues'},
});
expect(
i.string('issue.title', namespace: 'ext.linear', placeholder: '-'),
'Issues',
);
expect(i.string('issue.title', namespace: 'ext.linear', placeholder: '-'), 'Issues');
});
test('unregisterCatalog forgets a namespace', () async {
@@ -196,11 +188,13 @@ void main() {
test('plain-string shape (no nested translation) is accepted', () async {
// Forward-compat: if a catalog later switches to `"k": "v"`
// instead of `"k": {"translation": "v"}`, lookup still works.
final i = build(catalogs: {
'x': {
const Locale('en', 'US'): {'k': 'direct'},
final i = build(
catalogs: {
'x': {
const Locale('en', 'US'): {'k': 'direct'},
},
},
});
);
await i.ensureNamespaceLoaded('x');
expect(i.string('k', namespace: 'x', placeholder: '-'), 'direct');
});
@@ -208,23 +202,12 @@ void main() {
group('FallbackChain.resolve', () {
test('ordering: exact, lang, default, default-lang', () {
final chain = const FallbackChain(
current: Locale('nl', 'NL'),
defaultLocale: Locale('en', 'US'),
).resolve();
expect(chain.map((l) => l.toString()).toList(), [
'nl_NL',
'nl',
'en_US',
'en',
]);
final chain = const FallbackChain(current: Locale('nl', 'NL'), defaultLocale: Locale('en', 'US')).resolve();
expect(chain.map((l) => l.toString()).toList(), ['nl_NL', 'nl', 'en_US', 'en']);
});
test('deduplicates when current == default', () {
final chain = const FallbackChain(
current: Locale('en', 'US'),
defaultLocale: Locale('en', 'US'),
).resolve();
final chain = const FallbackChain(current: Locale('en', 'US'), defaultLocale: Locale('en', 'US')).resolve();
expect(chain, ['en_US', 'en'].map((_) => isA<Locale>()));
expect(chain.length, 2);
});