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
222 lines (221 loc) • 11 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.FreezedDeclarationBlock = void 0;
const visitor_plugin_common_1 = require("@graphql-codegen/visitor-plugin-common");
const graphql_1 = require("graphql");
const change_case_all_1 = require("change-case-all");
const utils_1 = require("../utils");
const factory_block_1 = require("./factory-block");
class FreezedDeclarationBlock {
constructor(_config, _freezedFactoryBlockRepository, _node) {
this._config = _config;
this._freezedFactoryBlockRepository = _freezedFactoryBlockRepository;
this._node = _node;
/** document the class */
this._comment = '';
/** a list of decorators to copy paste to the generator */
this._decorators = [];
/** a list of default constructor and named Constructors used create a Freezed union/sealed class */
this._factoryBlocks = [];
this._config = _config;
this._freezedFactoryBlockRepository = _freezedFactoryBlockRepository;
this._node = _node;
this._freezedConfigValue = new utils_1.FreezedConfigValue(this._config, this._node.name.value);
}
init() {
if (this._node.kind === graphql_1.Kind.ENUM_TYPE_DEFINITION) {
this.setDecorators().setName().setShape().setBlock();
return this;
}
this.setComment().setDecorators().setName().setFactoryBlocks().setShape().setBlock();
return this;
}
setComment() {
var _a;
const comment = (_a = this._node.description) === null || _a === void 0 ? void 0 : _a.value;
if (comment && comment !== null && comment !== '') {
this._comment = `/// ${comment} \n`;
}
return this;
}
getEnumComment(value) {
var _a;
const comment = (_a = value.description) === null || _a === void 0 ? void 0 : _a.value;
if (comment && comment !== null && comment !== '') {
return `/// ${comment} \n`;
}
return '';
}
setDecorators() {
var _a, _b;
const name = this._node.name.value;
// determine if should mark as deprecated
const isDeprecated = (_b = (_a = this._config.typeSpecificFreezedConfig) === null || _a === void 0 ? void 0 : _a[name]) === null || _b === void 0 ? void 0 : _b.deprecated;
this._decorators =
this._node.kind === graphql_1.Kind.ENUM_TYPE_DEFINITION
? [...(0, utils_1.transformCustomDecorators)((0, utils_1.getCustomDecorators)(this._config, ['enum'], name), this._node)]
: [
this.getFreezedDecorator(),
...(0, utils_1.transformCustomDecorators)((0, utils_1.getCustomDecorators)(this._config, ['class'], name), this._node),
];
// @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'];
}
return this;
}
getFreezedDecorator() {
const use_unfreezed = () => {
if (!this._freezedConfigValue.get('immutable') ||
(this._node.kind === graphql_1.Kind.INPUT_OBJECT_TYPE_DEFINITION && this._freezedConfigValue.get('mutableInputs'))) {
return '@unfreezed';
}
return use_Freezed_or_freezed();
};
const use_Freezed_or_freezed = () => {
// if any of these options is not null, use the @Freezed() decorator passing in that option
const [isCustomized, copyWith, equal, makeCollectionsUnmodifiable, unionKey, unionValueCase] = isCustomizedFreezed();
if (isCustomized) {
return ``;
}
// else fallback to the normal @freezed decorator
return '@freezed';
};
const isCustomizedFreezed = () => {
const copyWith = this._freezedConfigValue.get('copyWith');
const equal = this._freezedConfigValue.get('equal');
const makeCollectionsUnmodifiable = this._freezedConfigValue.get('makeCollectionsUnmodifiable');
const unionKey = this._freezedConfigValue.get('unionKey');
const unionValueCase = this._freezedConfigValue.get('unionValueCase');
const isCustomized = copyWith || equal || makeCollectionsUnmodifiable || unionKey || unionValueCase;
return [isCustomized, copyWith, equal, makeCollectionsUnmodifiable, unionKey, unionValueCase];
};
// this is the start of the pipeline of decisions to determine which Freezed decorator to use
return use_unfreezed();
}
setName() {
this._name = (0, change_case_all_1.pascalCase)(this._node.name.value);
return this;
}
setFactoryBlocks() {
var _a, _b, _c, _d;
if (this._node.kind === graphql_1.Kind.UNION_TYPE_DEFINITION) {
this._factoryBlocks =
(_b = (_a = this._node.types) === null || _a === void 0 ? void 0 : _a.map((_type) => new factory_block_1.FreezedFactoryBlock(this._config, this._node).init())) !== null && _b !== void 0 ? _b : [];
}
else if (this._node.kind !== graphql_1.Kind.ENUM_TYPE_DEFINITION) {
/*
for `ObjectTypeDefinitionNode` and `InputObjectTypeDefinitionNode` nodes,
we use the `ShapeRepository`
to register the `FreezedFactoryBlock` so that we can use it later
when we are merging inputs or generating freezed union/sealed classes
for GraphQL union types
*/
this._factoryBlocks =
(_d = (_c = this._node.fields) === null || _c === void 0 ? void 0 : _c.map((_field) => this._freezedFactoryBlockRepository.register(this._node.name.value, new factory_block_1.FreezedFactoryBlock(this._config, this._node).init()))) !== null && _d !== void 0 ? _d : [];
}
return this;
}
setShape() {
var _a, _b, _c;
let shape = '';
// some helper variables
const name = this._node.name.value;
let namedConstructor;
let factoryBlockKey;
// handle enums differently
if (this._node.kind === graphql_1.Kind.ENUM_TYPE_DEFINITION) {
this._shape = (_a = this._node.values) === null || _a === void 0 ? void 0 : _a.map((value) => {
var _a;
shape = (0, visitor_plugin_common_1.indent)(this.getEnumComment(value));
if ((_a = this._config.lowercaseEnums) !== null && _a !== void 0 ? _a : true) {
shape += ` ${value.name.value.toLowerCase()}`;
}
else {
shape += value.name.value;
}
return `${shape}\n`;
}).join('');
return this;
}
// append private empty constructor
if (this._freezedConfigValue.get('privateEmptyConstructor')) {
shape += (0, visitor_plugin_common_1.indent)(`const ${this._name}._();\n\n`);
}
// decide whether to append an empty Union constructor
if (this._freezedConfigValue.get('defaultUnionConstructor') && this._node.kind === graphql_1.Kind.UNION_TYPE_DEFINITION) {
shape += (0, visitor_plugin_common_1.indent)(`const factory ${this._name}() = _${this._name};\n\n`);
}
// append tokens which will be used to retrieve the factory blocks
// from the FreezedFactoryBlockRepository
if (this._node.kind === graphql_1.Kind.UNION_TYPE_DEFINITION) {
(_c = (_b = this._node) === null || _b === void 0 ? void 0 : _b.types) === null || _c === void 0 ? void 0 : _c.forEach(type => {
namedConstructor = type.name.value;
factoryBlockKey = namedConstructor;
shape += `==>factory==>${factoryBlockKey}==>${'union_factory'}==>${name}==>${namedConstructor}\n`;
});
}
else {
factoryBlockKey = name;
// replace token for the ObjectType & InputType to be replaced with the default Freezed constructor
shape += `==>factory==>${factoryBlockKey}==>${'class_factory'}==>${name}\n`;
const mergeInputs = this._freezedConfigValue.get('mergeInputs');
if (this._node.kind === graphql_1.Kind.OBJECT_TYPE_DEFINITION && mergeInputs) {
// replace token for the InputTypes(a.k.a namedConstructors) as a union/sealed class
mergeInputs.forEach(input => {
namedConstructor = (0, change_case_all_1.camelCase)(input.split('$').join('_'));
factoryBlockKey = input.replace('$', name);
shape += `==>factory==>${factoryBlockKey}==>${'union_factory'}==>${name}==>${namedConstructor}\n`;
});
}
}
this._shape = shape;
return this;
}
/**
* returns the string output of the block
*/
setBlock() {
let block = '';
//append comment
block += this._comment;
// append the decorators
block += this._decorators.join('\n');
if (this._decorators !== []) {
block += '\n';
}
// handle enums differently
if (this._node.kind === graphql_1.Kind.ENUM_TYPE_DEFINITION) {
block += `enum ${this._name}{\n${this._shape}}\n\n`;
this._block = block;
return this;
}
// append start of class definition
block += `class ${this._name} with _$${this._name} {\n`;
// append the shape
block += this._shape;
// append fromJson
if (this._freezedConfigValue.get('fromJsonToJson')) {
block += (0, visitor_plugin_common_1.indent)(`factory ${this._name}.fromJson(Map<String, Object?> json) => _${this._name}FromJson(json);\n`);
}
//append end of class definition
block += '}\n\n';
this._block = block;
return this;
}
/** returns the block */
toString() {
if (!this._block) {
throw new Error('setShape must be called before calling toString()');
}
return this._block;
}
}
exports.FreezedDeclarationBlock = FreezedDeclarationBlock;