UNPKG

graphql-codegen-flutter-freezed

Version:

A stand-alone package to generate Freezed models from GraphQL schema based on the flutter-freezed plugin for GraphQL Code Generator

159 lines (158 loc) 5.83 kB
import { indent } from '@graphql-codegen/visitor-plugin-common'; import { camelCase } from 'change-case-all'; import { getCustomDecorators, transformCustomDecorators, FreezedConfigValue } from '../utils'; /** * maps GraphQL scalar types to Dart's scalar types */ export const DART_SCALARS = { ID: 'String', String: 'String', Boolean: 'bool', Int: 'int', Float: 'double', DateTime: 'DateTime', }; export class FreezedParameterBlock { _config; _appliesOn; _node; _field; /** document the property */ _comment = ''; /** a list of decorators to copy paste to the generator */ _decorators = []; /** mark the property as required */ _required; /** mark the property as required */ // _type?: ParameterType = 'named'; _type; /** the name of the property */ _name; /** the shape is the content of the block */ _shape; /** the block is the final structure that is generated */ _block; _freezedConfigValue; constructor(_config, _appliesOn, _node, _field) { this._config = _config; this._appliesOn = _appliesOn; this._node = _node; this._field = _field; this._config = _config; this._appliesOn = _appliesOn; this._node = _node; this._field = _field; this._freezedConfigValue = new FreezedConfigValue(_config, _node.name.value); } init() { this.setComment().setDecorators().setRequired().setType().setName().setShape().setBlock(); return this; } setComment() { const comment = this._field.description?.value; if (comment && comment !== null && comment !== '') { this._comment = indent(`/// ${comment}\n`, 2); } return this; } setDecorators() { const nodeName = this._node.name.value; const fieldName = this._field.name.value; // determine if should mark as deprecated const isDeprecated = this._config.typeSpecificFreezedConfig?.[nodeName]?.fields?.[fieldName]?.deprecated; const defaultValue = this._config.typeSpecificFreezedConfig?.[nodeName]?.fields?.[fieldName]?.defaultValue; if (this._freezedConfigValue.get('alwaysUseJsonKeyName') || fieldName !== camelCase(fieldName)) { this._decorators = [...this._decorators, `@JsonKey(name: '${fieldName}')`]; } this._decorators = [ ...this._decorators, ...transformCustomDecorators(getCustomDecorators(this._config, this._appliesOn, this._node.name.value, fieldName), this._node, this._field), ]; // @deprecated // if this._decorators doesn't include an @deprecated decorator but the field is marked as @deprecated... if (!this._decorators.includes('@deprecated') && isDeprecated) { this._decorators = [...this._decorators, '@deprecated']; } // @Default if (defaultValue) { //overwrite the customDecorator's defaultValue this._decorators = this._decorators.filter(d => !d.startsWith('@Default')); this._decorators = [...this._decorators, `@Default(value: ${defaultValue})`]; } return this; } setRequired() { this._required = this.isNonNullType(this._field.type); return this; } setType() { this._type = this.propertyType(this._field, this._field.type); return this; } setName() { this._name = camelCase(this._field.name.value); return this; } /** compose the freezed constructor property */ setShape() { let shape = ''; const nodeName = this._node.name.value; const fieldName = this._field.name.value; // determine if should mark as final const isFinal = this._decorators.includes('final') || this._config.typeSpecificFreezedConfig?.[nodeName]?.fields?.[fieldName]?.final; //append comment shape += this._comment; // append the decorators shape += this._decorators .filter(d => d !== 'final') .map(d => indent(`${d}\n`, 2)) .join(''); // append required for non-nullable types shape += indent(this._required ? 'required ' : '', 2); // append isFinal shape += isFinal ? 'final ' : ''; // append the Dart Type, name and trailing comma shape += `${this._type} ${this._name},\n`; // store it in the shape this._shape = shape; return this; } /** composes the full block */ setBlock() { this._block = this._shape; return this; } propertyType = (field, type, parentType) => { if (this.isNonNullType(type)) { return this.propertyType(field, type.type, type); } if (this.isListType(type)) { const T = this.propertyType(field, type.type, type); return `List<${T}>${this.isNonNullType(parentType) ? '' : '?'}`; } if (this.isNamedType(type)) { return `${this.scalar(type.name.value)}${this.isNonNullType(parentType) ? '' : '?'}`; } return ''; }; isListType = (type) => type?.kind === 'ListType'; isNonNullType = (type) => type?.kind === 'NonNullType'; isNamedType = (type) => type?.kind === 'NamedType'; scalar(_scalar) { if (this._config?.customScalars?.[_scalar]) { return this._config.customScalars[_scalar]; } if (DART_SCALARS[_scalar]) { return DART_SCALARS[_scalar]; } return _scalar; } /** returns the block */ toString() { if (!this._block) { throw new Error('FreezedParameterBlock: setShape must be called before calling toString()'); } return this._block; } }