Skip to content

Commit

Permalink
feat: Apply custom decorators on models
Browse files Browse the repository at this point in the history
  • Loading branch information
unlight committed Apr 16, 2021
1 parent 2e920ed commit 34196b3
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 9 deletions.
15 changes: 15 additions & 0 deletions src/handlers/model-output-type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,21 @@ export function modelOutputType(outputType: OutputType, args: EventArguments) {
}),
],
});

for (const options of settings || []) {
if (!options.output || options.isFieldType) {
continue;
}
property.decorators?.push({
name: options.name,
arguments: options.arguments,
});
assert(
options.from,
"Missed 'from' part in configuration or field setting",
);
importDeclarations.create(options);
}
}

eventEmitter.emitSync('ClassProperty', property, { location, isList });
Expand Down
17 changes: 9 additions & 8 deletions src/helpers/field-settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,16 +35,17 @@ export function createFieldSettings(args: {
text: string;
config: GeneratorConfiguration;
}) {
let { text } = args;
const { config } = args;
const { config, text } = args;
const result: FieldSettings = new FieldSettings();
const matches = text.matchAll(/@(?<name>\w+(\.(\w+))?)\((?<args>.*?)\)/g);
for (const match of matches) {
text = text.slice(0, match.index);
const name = match.groups?.name;
if (!name) {
const textLines = text.split('\\n');
const documentationLines: string[] = [];
for (const line of textLines) {
const match = /^@(?<name>\w+(\.(\w+))?)\((?<args>.*?)\)/.exec(line);
if (!match) {
documentationLines.push(line);
continue;
}
const name = match.groups?.name;
const decorator: FieldSetting = {
name: '',
arguments: [],
Expand Down Expand Up @@ -99,7 +100,7 @@ export function createFieldSettings(args: {

return {
result,
documentation: text.split('\\n').filter(Boolean).join('\\n') || undefined,
documentation: documentationLines.filter(Boolean).join('\\n') || undefined,
};
}

Expand Down
42 changes: 41 additions & 1 deletion src/test/custom-decorators.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,46 @@ describe('custom decorators namespace both input and output', () => {
});
});

describe('custom decorators and description', () => {
let importDeclarations: any[];
before(async () => {
({ project, sourceFiles } = await testGenerate({
schema: `
model User {
/// user id really
id Int @id
/// User name really
/// @Validator.Length(5, 15, "check length")
name String
}`,
options: [
`outputFilePattern = "{name}.{type}.ts"`,
`fields_Validator_from = "class-validator"`,
`fields_Validator_output = true`,
`fields_Validator_input = true`,
],
}));
});

describe('user model output', () => {
before(() => setSourceFile('user.model.ts'));

it('has description', () => {
const data = d('name')?.arguments?.[1];
expect(data).toContain("description:'User name really'");
});

it('has decorator length', () => {
const decorators = p('name')?.decorators;
expect(decorators).toHaveLength(2);
expect(decorators).toContainEqual(
expect.objectContaining({ name: 'Length' }),
);
expect(sourceText).toContain('@Validator.Length(5, 15, "check length")');
});
});
});

describe('custom decorators default import', () => {
let importDeclarations: any[];

Expand Down Expand Up @@ -219,7 +259,7 @@ describe('custom decorators field custom type namespace', () => {
setSourceFile('user-create.input.ts');
});

it('field type', () => {
it('email field type', () => {
const decorator = p('email')?.decorators?.find(d => d.name === 'Field');
const typeArgument = decorator?.arguments?.[0];
expect(typeArgument).toEqual('() => Scalars.EmailAddress');
Expand Down

0 comments on commit 34196b3

Please sign in to comment.