Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
- name: Activate melos
run: |
echo "$HOME/.pub-cache/bin" >> $GITHUB_PATH
dart pub global activate melos
dart pub global activate melos 3.0.1
- name: Bootstrap melos
run: melos bs
- name: Configure git user
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/validate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
- name: Activate melos
run: |
echo "$HOME/.pub-cache/bin" >> $GITHUB_PATH
dart pub global activate melos
dart pub global activate melos 3.0.1
- name: Bootstrap melos
run: melos bs
- name: Analyze package
Expand All @@ -38,7 +38,7 @@ jobs:
- name: Activate melos
run: |
echo "$HOME/.pub-cache/bin" >> $GITHUB_PATH
dart pub global activate melos 2.9.0
dart pub global activate melos 3.0.1
- name: Bootstrap melos
run: melos bs
- name: Validate formatting
Expand All @@ -56,8 +56,8 @@ jobs:
- name: Activate melos
run: |
echo "$HOME/.pub-cache/bin" >> $GITHUB_PATH
dart pub global activate melos 2.9.0
dart pub global activate melos 3.0.1
- name: Bootstrap melos
run: melos bs
- name: Run tests
run: melos exec --dir-exists=test -- flutter test
run: melos run test
32 changes: 32 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Commands

- Build: `melos run build --scope=<package>` - Runs build_runner
- Analyze: `melos run analyze --scope=<package>` - Run Flutter analysis
- Test all: `cd packages/<package> && dart test`
- Test single: `cd packages/<package> && dart test path/to/test_file.dart`
- Format all: `dart format .`
- Bootstrap: `melos bootstrap` - Set up the workspace

## Code Style

- Follow the standard pedantic Dart style guide
- Use strong typing everywhere with type annotations
- Prefer final variables where possible
- Maintain immutable data classes (built_value)
- Name files using snake_case
- Use camelCase for variable and method names
- Error handling should use typed exceptions
- Wrap GraphQL operations in strongly typed classes
- Maintain schema-generated files with code generation
- Document public APIs with /// comments
- Keep code modular with single responsibility principle

## Notes

- The codebase is a monorepo using Melos for managing multiple packages
- Current work is ongoing for Ferry Generator 2.0 (see issue #622) to improve code generation
- The main branch is `master`, with feature branches for new development
20 changes: 20 additions & 0 deletions melos.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,23 @@ scripts:
depends-on: build_runner
analyze:
exec: flutter analyze --no-fatal-infos

test:
run: |
melos run test:dart --no-select
melos run test:flutter --no-select
description: Run all tests (dart test for Dart packages, flutter test for Flutter packages)

test:dart:
exec: dart test
packageFilters:
flutter: false
dirExists: test
description: Run tests in Dart-only packages

test:flutter:
exec: flutter test
packageFilters:
flutter: true
dirExists: test
description: Run tests in Flutter packages
1 change: 0 additions & 1 deletion packages/ferry_generator/lib/graphql_builder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,6 @@ class GraphqlBuilder implements Builder {
addTypenames(schema),
p.basename(generatedFilePath(buildStep.inputId, varExtension)),
config.typeOverrides,
allocators[varExtension]!,
triStateValueConfig,
config.shouldGenerateVarsCreateFactories),
reqExtension: buildReqLibrary(
Expand Down
27 changes: 13 additions & 14 deletions packages/ferry_generator/lib/serializer_builder.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import 'dart:async';
import 'dart:collection';

import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/element2.dart';
import 'package:build/build.dart';
import 'package:code_builder/code_builder.dart';
import 'package:gql_code_builder/serializer.dart';
Expand Down Expand Up @@ -83,13 +83,13 @@ class SerializerBuilder implements Builder {
/// BuiltValue classes with serializers. These will be added automatically
/// using `@SerializersFor`.
final builtClasses =
SplayTreeSet<ClassElement>((a, b) => a.name.compareTo(b.name));
SplayTreeSet<ClassElement2>((a, b) => a.name3!.compareTo(b.name3!));

/// Non BuiltValue classes with serializers (i.e. inline fragment classes).
/// These need to be added manually since `@SerializersFor` only recognizes
/// BuiltValue classes.
final nonBuiltClasses =
SplayTreeSet<ClassElement>((a, b) => a.name.compareTo(b.name));
SplayTreeSet<ClassElement2>((a, b) => a.name3!.compareTo(b.name3!));

final excludeFileIds = <String, AssetId>{};
for (final excludeGlob in excludeFiles) {
Expand All @@ -116,7 +116,8 @@ class SerializerBuilder implements Builder {
...config.customSerializers.map((ref) => ref.call([])),
// Serializers from data classes that aren't caught by `@SerializersFor`
...nonBuiltClasses.map<Expression>(
(c) => refer(c.name, c.source.uri.toString()).property('serializer'),
(c) =>
refer(c.name3!, c.library2.uri.toString()).property('serializer'),
),
};

Expand Down Expand Up @@ -187,33 +188,31 @@ String _externalSchemaSerializersImport(
return 'package:${outPutId.package}/$outPutPath';
}

bool hasSerializer(ClassElement c) => c.fields.any((field) =>
bool hasSerializer(ClassElement2 c) => c.fields2.any((field) =>
field.isStatic &&
field.name == 'serializer' &&
field.name3 == 'serializer' &&
field.type.element?.name == 'Serializer' &&
field.type.element?.source?.uri.toString() ==
'package:built_value/serializer.dart');

bool isBuiltValue(ClassElement c) => c.allSupertypes.any((interface) =>
bool isBuiltValue(ClassElement2 c) => c.allSupertypes.any((interface) =>
(interface.element.name == 'Built' ||
interface.element.name == 'EnumClass') &&
interface.element.source.uri.toString() ==
'package:built_value/built_value.dart');

typedef ClassesToGenerateSerializersFor = ({
Set<ClassElement> builtClasses,
Set<ClassElement> nonBuiltClasses
Set<ClassElement2> builtClasses,
Set<ClassElement2> nonBuiltClasses
});

ClassesToGenerateSerializersFor extractClassesToGenerateSerializersFor(
LibraryElement externalSchemaLibrary) {
final builtClasses = externalSchemaLibrary.units
.expand((cu) => cu.classes)
LibraryElement2 externalSchemaLibrary) {
final builtClasses = externalSchemaLibrary.classes
.where((c) => hasSerializer(c) && isBuiltValue(c))
.toSet();

final nonBuiltClasses = externalSchemaLibrary.units
.expand((cu) => cu.classes)
final nonBuiltClasses = externalSchemaLibrary.classes
.where(
(c) => hasSerializer(c) && !isBuiltValue(c),
)
Expand Down
6 changes: 3 additions & 3 deletions packages/ferry_generator/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ topics:
- codegen
dependencies:
gql: '>=0.14.0 <2.0.0'
gql_code_builder: ^0.14.0
gql_code_builder: ^0.15.0
gql_code_builder_serializers: ^0.1.0
gql_tristate_value: ^1.0.0
built_collection: ^5.0.0
code_builder: ^4.3.0
build: 2.4.2
build: ^3.0.0
path: ^1.8.0
ferry_exec: ^0.8.0-dev.0
yaml: ^3.1.0
Expand All @@ -30,5 +30,5 @@ dependencies:
dev_dependencies:
test: ^1.16.8
build_runner: ^2.0.2
build_test: ^2.0.0
build_test: ^3.3.2
pedantic: ^1.11.0