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
129 lines (128 loc) • 4.58 kB
JavaScript
import { indent } from '@graphql-codegen/visitor-plugin-common';
import { Kind } from 'graphql';
import { camelCase, pascalCase } from 'change-case-all';
import { FreezedParameterBlock } from './parameter-block';
import { FreezedConfigValue, getCustomDecorators, transformCustomDecorators } from '../utils';
export class FreezedFactoryBlock {
_config;
_node;
/** document the constructor */
_comment = '';
/** a list of decorators to copy paste to the generator */
_decorators = [];
/** the key of the original type name */
_key;
/** the name of the class */
_name;
/** the namedConstructor is used for GraphQL Union types or if mergeInput is true */
_namedConstructor;
/** a list of interfaces to implements */
// _implements: string[] = [];
/** a list of class to mixin with */
// _mixins: string[] = [];
/** the parameters of this factory constructor */
// TODO: handle other parameter types like positional parameters later.
// TODO: sticking to named parameters because GraphQL is a typed language
_parameters = [];
/** the shape is the content of the block */
_shape;
/** the block is the final structure that is generated */
_block;
_freezedConfigValue;
constructor(_config, _node) {
this._config = _config;
this._node = _node;
this._config = _config;
this._node = _node;
this._freezedConfigValue = new FreezedConfigValue(_config, _node.name.value);
}
init() {
/*
setDecorators(), setName() and setType() will be called
when the factory is retrieved from the repository
*/
this.setComment().setParameters().setShape().setBlock();
return this;
}
setComment() {
const comment = this._node.description?.value;
if (comment && comment !== null && comment !== '') {
this._comment = indent(`/// ${comment} \n`);
}
return this;
}
setDecorators(appliesOn, nodeName) {
this._decorators = [
...transformCustomDecorators(getCustomDecorators(this._config, appliesOn.split(','), nodeName), this._node),
];
return this;
}
setKey(key) {
this._key = pascalCase(key);
return this;
}
setName(name) {
this._name = pascalCase(name);
return this;
}
setNamedConstructor(namedConstructor) {
if (namedConstructor) {
this._namedConstructor = camelCase(namedConstructor);
}
return this;
}
setParameters() {
const appliesOn = this._namedConstructor
? ['union_factory_parameter']
: ['class_factory_parameter'];
if (this._node.kind !== Kind.UNION_TYPE_DEFINITION && this._node.kind !== Kind.ENUM_TYPE_DEFINITION) {
this._parameters =
this._node?.fields?.map((field) => new FreezedParameterBlock(this._config, appliesOn, this._node, field).init()) ?? [];
}
return this;
}
setShape() {
this._shape = this._parameters.map(p => p.toString()).join('');
return this;
}
setBlock() {
let block = '';
//append comment
block += this._comment;
// append the decorators
block += this._decorators.map(d => indent(`${d}\n`)).join('');
block += indent('');
// decide if to use const or not
if (this._freezedConfigValue.get('immutable')) {
block += 'const ';
}
// append the factory keyword and the name
block += `factory ${this._name}`;
// append .namedConstructor is not null
if (this._namedConstructor && this._namedConstructor !== '') {
block += `.${this._namedConstructor}`;
}
// append the parenthesis for the constructor and braces for the named parameters
block += '({\n';
//append the shape
block += this._shape;
// close the constructor and assign the key
block += indent(`}) = `);
// but first decide whether prefix the key with an underscore
if (!this._namedConstructor) {
block += '_';
}
// finally, append the key
block += `${this._key};\n`;
// store it in the shape
this._block = block;
return this;
}
/** returns the block */
toString() {
if (!this._block) {
throw new Error('FreezedFactoryBlock: setShape must be called before calling toString()');
}
return this._block;
}
}