fix: force SetMinMax to use the correct primitive at generation

This commit is contained in:
Convly 2024-01-17 11:53:34 +01:00
parent 334c95408a
commit b5b7b8260a
2 changed files with 125 additions and 46 deletions

View File

@ -548,19 +548,27 @@ describe('Attributes', () => {
expect(modifiers[0].kind).toBe(ts.SyntaxKind.TypeReference);
expect(modifiers[0].typeName.escapedText).toBe('Attribute.SetMinMax');
expect(modifiers[0].typeArguments).toHaveLength(1);
expect(modifiers[0].typeArguments[0].kind).toBe(ts.SyntaxKind.TypeLiteral);
expect(modifiers[0].typeArguments[0].members).toHaveLength(1);
const [setMinMax] = modifiers;
const { typeArguments } = setMinMax;
expect(typeArguments).toBeDefined();
expect(typeArguments).toHaveLength(2);
const [definition, typeofMinMax] = typeArguments;
// Min
expect(modifiers[0].typeArguments[0].members[0].kind).toBe(
ts.SyntaxKind.PropertyDeclaration
);
expect(modifiers[0].typeArguments[0].members[0].name.escapedText).toBe('min');
expect(modifiers[0].typeArguments[0].members[0].type.kind).toBe(
ts.SyntaxKind.NumericLiteral
);
expect(modifiers[0].typeArguments[0].members[0].type.text).toBe('2');
expect(definition.kind).toBe(ts.SyntaxKind.TypeLiteral);
expect(definition.members).toHaveLength(1);
const [min] = definition.members;
expect(min.kind).toBe(ts.SyntaxKind.PropertyDeclaration);
expect(min.name.escapedText).toBe('min');
expect(min.type.kind).toBe(ts.SyntaxKind.NumericLiteral);
expect(min.type.text).toBe('2');
// Check for number keyword on the second typeArgument
expect(typeofMinMax.kind).toBe(ts.SyntaxKind.NumberKeyword);
});
test('No Min, Max: 3', () => {
@ -572,19 +580,27 @@ describe('Attributes', () => {
expect(modifiers[0].kind).toBe(ts.SyntaxKind.TypeReference);
expect(modifiers[0].typeName.escapedText).toBe('Attribute.SetMinMax');
expect(modifiers[0].typeArguments).toHaveLength(1);
expect(modifiers[0].typeArguments[0].kind).toBe(ts.SyntaxKind.TypeLiteral);
expect(modifiers[0].typeArguments[0].members).toHaveLength(1);
const [setMinMax] = modifiers;
const { typeArguments } = setMinMax;
// Min
expect(modifiers[0].typeArguments[0].members[0].kind).toBe(
ts.SyntaxKind.PropertyDeclaration
);
expect(modifiers[0].typeArguments[0].members[0].name.escapedText).toBe('max');
expect(modifiers[0].typeArguments[0].members[0].type.kind).toBe(
ts.SyntaxKind.NumericLiteral
);
expect(modifiers[0].typeArguments[0].members[0].type.text).toBe('3');
expect(typeArguments).toBeDefined();
expect(typeArguments).toHaveLength(2);
const [definition, typeofMinMax] = typeArguments;
// Max
expect(definition.kind).toBe(ts.SyntaxKind.TypeLiteral);
expect(definition.members).toHaveLength(1);
const [max] = definition.members;
expect(max.kind).toBe(ts.SyntaxKind.PropertyDeclaration);
expect(max.name.escapedText).toBe('max');
expect(max.type.kind).toBe(ts.SyntaxKind.NumericLiteral);
expect(max.type.text).toBe('3');
// Check for number keyword on the second typeArgument
expect(typeofMinMax.kind).toBe(ts.SyntaxKind.NumberKeyword);
});
test('Min: 4, Max: 12', () => {
@ -596,28 +612,64 @@ describe('Attributes', () => {
expect(modifiers[0].kind).toBe(ts.SyntaxKind.TypeReference);
expect(modifiers[0].typeName.escapedText).toBe('Attribute.SetMinMax');
expect(modifiers[0].typeArguments).toHaveLength(1);
expect(modifiers[0].typeArguments[0].kind).toBe(ts.SyntaxKind.TypeLiteral);
expect(modifiers[0].typeArguments[0].members).toHaveLength(2);
const [setMinMax] = modifiers;
const { typeArguments } = setMinMax;
// Min
expect(modifiers[0].typeArguments[0].members[0].kind).toBe(
ts.SyntaxKind.PropertyDeclaration
);
expect(modifiers[0].typeArguments[0].members[0].name.escapedText).toBe('min');
expect(modifiers[0].typeArguments[0].members[0].type.kind).toBe(
ts.SyntaxKind.NumericLiteral
);
expect(modifiers[0].typeArguments[0].members[0].type.text).toBe('4');
expect(typeArguments).toBeDefined();
expect(typeArguments).toHaveLength(2);
expect(modifiers[0].typeArguments[0].members[1].kind).toBe(
ts.SyntaxKind.PropertyDeclaration
);
expect(modifiers[0].typeArguments[0].members[1].name.escapedText).toBe('max');
expect(modifiers[0].typeArguments[0].members[1].type.kind).toBe(
ts.SyntaxKind.NumericLiteral
);
expect(modifiers[0].typeArguments[0].members[1].type.text).toBe('12');
const [definition, typeofMinMax] = typeArguments;
// Min/Max
expect(definition.kind).toBe(ts.SyntaxKind.TypeLiteral);
expect(definition.members).toHaveLength(2);
const [min, max] = definition.members;
expect(min.kind).toBe(ts.SyntaxKind.PropertyDeclaration);
expect(min.name.escapedText).toBe('min');
expect(min.type.kind).toBe(ts.SyntaxKind.NumericLiteral);
expect(min.type.text).toBe('4');
expect(max.kind).toBe(ts.SyntaxKind.PropertyDeclaration);
expect(max.name.escapedText).toBe('max');
expect(max.type.kind).toBe(ts.SyntaxKind.NumericLiteral);
expect(max.type.text).toBe('12');
// Check for number keyword on the second typeArgument
expect(typeofMinMax.kind).toBe(ts.SyntaxKind.NumberKeyword);
});
test('Min: "1"', () => {
const attribute = { min: '1' };
const modifiers = getAttributeModifiers(attribute);
expect(modifiers).toHaveLength(1);
expect(modifiers[0].kind).toBe(ts.SyntaxKind.TypeReference);
expect(modifiers[0].typeName.escapedText).toBe('Attribute.SetMinMax');
const [setMinMax] = modifiers;
const { typeArguments } = setMinMax;
expect(typeArguments).toBeDefined();
expect(typeArguments).toHaveLength(2);
const [definition, typeofMinMax] = typeArguments;
// Min/Max
expect(definition.kind).toBe(ts.SyntaxKind.TypeLiteral);
expect(definition.members).toHaveLength(1);
const [min] = definition.members;
expect(min.kind).toBe(ts.SyntaxKind.PropertyDeclaration);
expect(min.name.escapedText).toBe('min');
expect(min.type.kind).toBe(ts.SyntaxKind.StringLiteral);
expect(min.type.text).toBe('1');
// Check for number keyword on the second typeArgument
expect(typeofMinMax.kind).toBe(ts.SyntaxKind.StringKeyword);
});
});

View File

@ -1,12 +1,14 @@
'use strict';
const { factory } = require('typescript');
const ts = require('typescript');
const _ = require('lodash/fp');
const { addImport } = require('../imports');
const { getTypeNode, toTypeLiteral, withAttributeNamespace, NAMESPACES } = require('./utils');
const mappers = require('./mappers');
const { factory } = ts;
/**
* Create the base type node for a given attribute
*
@ -100,14 +102,39 @@ const getAttributeModifiers = (attribute) => {
}
// Min / Max
// TODO: Always provide a second type argument for min/max (ie: resolve the attribute scalar type with a `GetAttributeType<${mappers[attribute][0]}>` (useful for biginter (string values)))
if (!_.isNil(attribute.min) || !_.isNil(attribute.max)) {
const minMaxProperties = _.pick(['min', 'max'], attribute);
const { min, max } = minMaxProperties;
const typeofMin = typeof min;
const typeofMax = typeof max;
// Throws error if min/max exist but have different types to prevent unexpected behavior
if (min !== undefined && max !== undefined && typeofMin !== typeofMax) {
throw new Error('typeof min/max values mismatch');
}
const typeofMinMax = (max && typeofMax) ?? (min && typeofMin);
let typeKeyword;
// Determines type keyword (string/number) based on min/max options, throws error for invalid types
switch (typeofMinMax) {
case 'string':
typeKeyword = ts.SyntaxKind.StringKeyword;
break;
case 'number':
typeKeyword = ts.SyntaxKind.NumberKeyword;
break;
default:
throw new Error(
`Invalid data type for min/max options. Must be string or number, but found ${typeofMinMax}`
);
}
modifiers.push(
factory.createTypeReferenceNode(
factory.createIdentifier(withAttributeNamespace('SetMinMax')),
[toTypeLiteral(minMaxProperties)]
[toTypeLiteral(minMaxProperties), factory.createKeywordTypeNode(typeKeyword)]
)
);
}