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
JavaScript
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, ``];
}
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, ``];
}
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;
}
}