classDefinitionToSpec function

Spec classDefinitionToSpec(
  1. ClassDefinition definition,
  2. Iterable<FragmentClassDefinition> fragments,
  3. Iterable<ClassDefinition> classes
)

Generates a Spec of a single class definition.

Implementation

Spec classDefinitionToSpec(
    ClassDefinition definition,
    Iterable<FragmentClassDefinition> fragments,
    Iterable<ClassDefinition> classes) {
  final fromJson = definition.factoryPossibilities.isNotEmpty
      ? Constructor(
          (b) => b
            ..factory = true
            ..name = 'fromJson'
            ..requiredParameters.add(Parameter(
              (p) => p
                ..type = refer('Map<String, dynamic>')
                ..name = 'json',
            ))
            ..body = Code(_fromJsonBody(definition)),
        )
      : Constructor(
          (b) => b
            ..factory = true
            ..name = 'fromJson'
            ..lambda = true
            ..requiredParameters.add(Parameter(
              (p) => p
                ..type = refer('Map<String, dynamic>')
                ..name = 'json',
            ))
            ..body = Code('_\$${definition.name.namePrintable}FromJson(json)'),
        );

  final toJson = definition.factoryPossibilities.isNotEmpty
      ? Method(
          (m) => m
            ..name = 'toJson'
            ..annotations.add(CodeExpression(Code('override')))
            ..returns = refer('Map<String, dynamic>')
            ..body = Code(_toJsonBody(definition)),
        )
      : Method(
          (m) => m
            ..name = 'toJson'
            ..lambda = true
            ..annotations.add(CodeExpression(Code('override')))
            ..returns = refer('Map<String, dynamic>')
            ..body = Code('_\$${definition.name.namePrintable}ToJson(this)'),
        );

  final props = definition.mixins
      .map((i) {
        return fragments
            .firstWhere((f) {
              return f.name == i;
            }, orElse: () {
              throw MissingFragmentException(
                  i.namePrintable, definition.name.namePrintable);
            })
            .properties
            .map((p) => p.name.namePrintable);
      })
      .expand((i) => i)
      .followedBy(definition.properties.map((p) => p.name.namePrintable));

  final extendedClass =
      classes.firstWhereOrNull((e) => e.name == definition.extension);

  return Class(
    (b) => b
      ..annotations
          .add(CodeExpression(Code('JsonSerializable(explicitToJson: true)')))
      ..name = definition.name.namePrintable
      ..mixins.add(refer('EquatableMixin'))
      ..mixins.addAll(definition.mixins.map((i) => refer(i.namePrintable)))
      ..methods.add(_propsMethod(props))
      ..extend = definition.extension != null
          ? refer(definition.extension!.namePrintable)
          : refer('JsonSerializable')
      ..implements.addAll(definition.implementations.map((i) => refer(i)))
      ..constructors.add(Constructor((b) {
        if (definition.isInput) {
          b.optionalParameters.addAll(definition.properties
              .where(
                  (property) => !property.isOverride && !property.isResolveType)
              .map(
                (property) => Parameter(
                  (p) {
                    p
                      ..name = property.name.namePrintable
                      ..named = true
                      ..toThis = true
                      ..required = property.type.isNonNull;
                  },
                ),
              ));
        }
      }))
      ..constructors.add(fromJson)
      ..methods.add(toJson)
      ..fields.addAll(definition.properties.map((p) {
        if (extendedClass != null &&
            extendedClass.properties.any((e) => e == p)) {
          // if class has the same prop as in extension
          p.annotations.add('override');
        }

        final field = Field((f) {
          f
            ..name = p.name.namePrintable
            // TODO: remove this workaround when code_builder includes late field modifier:
            // https://github.com/dart-lang/code_builder/pull/310
            ..type = refer(
                '${p.type.isNonNull ? 'late ' : ''} ${p.type.namePrintable}')
            ..annotations.addAll(
              p.annotations.map((e) => CodeExpression(Code(e))),
            );

          if (p.type.isNonNull) {
            // TODO: apply this fix when code_builder includes late field modifier:
            // https://github.com/dart-lang/code_builder/pull/310
            // f.modifier = FieldModifier.late$;
          }
        });
        return field;
      })),
  );
}