Skip to content

Commit

Permalink
feat(custom decorators): Allow apply custom decorator on models
Browse files Browse the repository at this point in the history
close: unlight#63
  • Loading branch information
unlight committed Oct 12, 2021
1 parent e304de1 commit 52f090a
Show file tree
Hide file tree
Showing 8 changed files with 386 additions and 241 deletions.
1 change: 1 addition & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ module.exports = {
'consistent-return': 0,
'max-lines': 0,
'@typescript-eslint/no-explicit-any': 0,
'@typescript-eslint/no-unsafe-member-access': 0,
'@typescript-eslint/no-floating-promises': 0,
'@typescript-eslint/no-non-null-assertion': 0,
'@typescript-eslint/camelcase': 0,
Expand Down
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,7 @@ generator nestgraphql {
fields_{namespace}_from = "module specifier"
fields_{namespace}_input = true | false
fields_{namespace}_output = true | false
fields_{namespace}_model = true | false
fields_{namespace}_defaultImport = "default import name" | true
fields_{namespace}_namespaceImport = "namespace import name"
fields_{namespace}_namedImport = true | false
Expand All @@ -367,7 +368,14 @@ Default: `false`

##### `fields_{namespace}_output`

Means that it will be applied on output types (classes decorated by `ObjectType`)
Means that it will be applied on output types (classes decorated by `ObjectType`),
including models
Type: `boolean`
Default: `false`

##### `fields_{namespace}_model`

Means that it will be applied only on model types (classes decorated by `ObjectType`)
Type: `boolean`
Default: `false`

Expand Down
43 changes: 35 additions & 8 deletions src/handlers/model-output-type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@ import { getGraphqlImport } from '../helpers/get-graphql-import';
import { getOutputTypeName } from '../helpers/get-output-type-name';
import { getPropertyType } from '../helpers/get-property-type';
import { ImportDeclarationMap } from '../helpers/import-declaration-map';
import { createObjectSettings } from '../helpers/object-settings';
import {
createObjectSettings,
ObjectSetting,
ObjectSettings,
} from '../helpers/object-settings';
import { propertyStructure } from '../helpers/property-structure';
import { EventArguments, OutputType } from '../types';

Expand Down Expand Up @@ -49,9 +53,11 @@ export function modelOutputType(outputType: OutputType, args: EventArguments) {
properties: [],
};
(sourceFileStructure.statements as StatementStructures[]).push(classStructure);
const decorator = classStructure.decorators?.find(d => d.name === 'ObjectType');
ok(classStructure.decorators, 'classStructure.decorators is undefined');
const decorator = classStructure.decorators.find(d => d.name === 'ObjectType');
ok(decorator, 'ObjectType decorator not found');

let modelSettings: ObjectSettings | undefined;
// Get model settings from documentation
if (model.documentation) {
const objectTypeOptions: PlainObject = {};
Expand All @@ -66,6 +72,7 @@ export function modelOutputType(outputType: OutputType, args: EventArguments) {
objectTypeOptions.description = documentation;
}
decorator.arguments = settings.getObjectTypeArguments(objectTypeOptions);
modelSettings = settings;
}

importDeclarations.add('Field', nestjsGraphql);
Expand Down Expand Up @@ -170,19 +177,19 @@ export function modelOutputType(outputType: OutputType, args: EventArguments) {
],
});

for (const options of settings || []) {
if (!options.output || options.kind !== 'Decorator') {
for (const setting of settings || []) {
if (!shouldBeDecorated(setting)) {
continue;
}
property.decorators.push({
name: options.name,
arguments: options.arguments as string[],
name: setting.name,
arguments: setting.arguments as string[],
});
ok(
options.from,
setting.from,
"Missed 'from' part in configuration or field setting",
);
importDeclarations.create(options);
importDeclarations.create(setting);
}

for (const decorate of config.decorate) {
Expand All @@ -208,6 +215,18 @@ export function modelOutputType(outputType: OutputType, args: EventArguments) {
});
}

// Generate class decorators from model settings
for (const setting of modelSettings || []) {
if (!shouldBeDecorated(setting)) {
continue;
}
classStructure.decorators.push({
name: setting.name,
arguments: setting.arguments as string[],
});
importDeclarations.create(setting);
}

if (exportDeclaration) {
sourceFile.set({
statements: [exportDeclaration, '\n', classStructure],
Expand All @@ -226,6 +245,14 @@ export function modelOutputType(outputType: OutputType, args: EventArguments) {
}
}

function shouldBeDecorated(setting: ObjectSetting) {
return (
setting.kind === 'Decorator' &&
(setting.output || setting.model) &&
!(setting.output && setting.model)
);
}

function getExportDeclaration(name: string, statements: StatementStructures[]) {
return statements.find(structure => {
return (
Expand Down
1 change: 1 addition & 0 deletions src/helpers/create-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ export function createConfig(data: Record<string, unknown>) {
arguments: [],
output: toBoolean(value.output),
input: toBoolean(value.input),
model: toBoolean(value.model),
from: value.from,
defaultImport: toBoolean(value.defaultImport)
? true
Expand Down
9 changes: 2 additions & 7 deletions src/helpers/object-settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export type ObjectSetting = {
arguments?: string[] | Record<string, unknown>;
input: boolean;
output: boolean;
model: boolean;
match?: (test: string) => boolean;
from: string;
namespace?: string;
Expand Down Expand Up @@ -43,7 +44,6 @@ export class ObjectSettings extends Array<ObjectSetting> {
);
}

/* eslint-disable consistent-return */
getFieldType({
name,
input,
Expand All @@ -70,9 +70,7 @@ export class ObjectSettings extends Array<ObjectSetting> {

return fieldType;
}
/* eslint-enable consistent-return */

/* eslint-disable consistent-return */
getPropertyType({ name }: ObjectSettingsFilterArgs): ObjectSetting | undefined {
const propertyType = this.find(s => s.kind === 'PropertyType');

Expand All @@ -87,7 +85,6 @@ export class ObjectSettings extends Array<ObjectSetting> {

return propertyType;
}
/* eslint-enable consistent-return */

getObjectTypeArguments(options: Record<string, any>): string[] {
const objectTypeOptions = merge({}, options);
Expand Down Expand Up @@ -125,6 +122,7 @@ export function createObjectSettings(args: {
arguments: [],
input: false,
output: false,
model: false,
from: '',
};
if (name === 'TypeGraphQL.omit' || name === 'HideField') {
Expand All @@ -137,9 +135,6 @@ export function createObjectSettings(args: {
options,
{ kind: name },
);
} else if (name === 'IsAbstract') {
element.kind = 'ObjectType';
element.arguments = { isAbstract: true };
} else if (name === 'ObjectType' && match.groups?.args) {
element.kind = 'ObjectType';
const options = customType(match.groups.args) as Record<string, unknown>;
Expand Down
Loading

0 comments on commit 52f090a

Please sign in to comment.