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

222 lines (221 loc) 11 kB
"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 `@Freezed(\n ${copyWith ? (0, visitor_plugin_common_1.indent)(`copyWith: ${copyWith},\n`) : ''} ${equal ? (0, visitor_plugin_common_1.indent)(`equal: ${equal},\n`) : ''} ${makeCollectionsUnmodifiable ? (0, visitor_plugin_common_1.indent)(`makeCollectionsUnmodifiable: ${makeCollectionsUnmodifiable},\n`) : ''} ${unionKey ? (0, visitor_plugin_common_1.indent)(`unionKey: ${unionKey},\n`) : ''} ${unionValueCase ? (0, visitor_plugin_common_1.indent)(`unionValueCase: ${unionValueCase},\n`) : ''} )`; } // 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 += `@JsonKey(name: ${value.name.value}) ${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;