Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions forward_engineering/mappers/arguments.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* @import {Argument, ArgumentsResultStatement, IdToNameMap, FEStatement} from "../../shared/types/types"
* @import {ArgumentsResultStatement, IdToNameMap, FEStatement, FEArgument} from "../../shared/types/types"
*/

const { getDirectivesUsageStatement } = require('./directiveUsageStatements');
Expand All @@ -16,7 +16,7 @@ const EMPTY_LIST = '[]';
* Gets the type of the argument with the required keyword.
*
* @param {object} args - Arguments object.
* @param {Argument} args.graphqlArgument - The argument to map.
* @param {FEArgument} args.graphqlArgument - The argument to map.
* @param {IdToNameMap} [args.idToNameMap] - The ID to name map of all available types in model.
* @returns {string} Returns the type of the argument with the required keyword
*/
Expand All @@ -42,7 +42,7 @@ const getArgumentType = ({ graphqlArgument, idToNameMap = {} }) => {
* Maps an argument to a string with all configured properties.
*
* @param {object} args - Arguments object.
* @param {Argument} args.graphqlArgument - The argument to map.
* @param {FEArgument} args.graphqlArgument - The argument to map.
* @param {IdToNameMap} [args.idToNameMap] - The ID to name map of all available types in model.
* @returns {FEStatement} Returns the argument as a FEStatement
*/
Expand Down Expand Up @@ -72,7 +72,7 @@ const mapArgument = ({ graphqlArgument, idToNameMap = {} }) => {
* Maps an array of arguments to a formatted string with all configured properties.
*
* @param {object} args - Arguments object.
* @param {Argument[]} [args.graphqlArguments] - The arguments to map.
* @param {FEArgument[]} [args.graphqlArguments] - The arguments to map.
* @param {IdToNameMap} [args.idToNameMap] - The ID to name map of all available types in model.
* @returns {ArgumentsResultStatement} Returns an object containing the arguments as a formatted string and a warning
* comment if any.
Expand Down
105 changes: 105 additions & 0 deletions reverse_engineering/mappers/arguments.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
/**
* @import {InputValueDefinitionNode, TypeNode} from "graphql"
* @import {ArgumentTypeInfo, REArgument} from "./../../shared/types/types"
*/

const { mapDirectivesUsage } = require('./directiveUsage');
const { astNodeKind } = require('../constants/graphqlAST');
const { parseDefaultValue } = require('./defaultValue');

/**
* Maps field arguments to the REArgument format
*
* @param {object} params
* @param {InputValueDefinitionNode[]} params.fieldArguments - The field arguments
* @returns {REArgument[]} The mapped arguments
*/
function getArguments({ fieldArguments = [] }) {
if (!fieldArguments.length) {
return [];
}

return fieldArguments.map(argument => mapArgument({ argument }));
}

/**
* Maps a single argument to the REArgument format
*
* @param {object} params
* @param {InputValueDefinitionNode} params.argument - The argument to map
* @returns {REArgument} The mapped argument
*/
function mapArgument({ argument }) {
const typeInfo = getArgumentTypeInfo({ type: argument.type });

const mappedArgument = {
name: argument.name.value,
type: typeInfo.typeName,
description: argument.description?.value || '',
directives: mapDirectivesUsage({ directives: [...(argument.directives || [])] }),
required: typeInfo.required,
};

// Add list items for List types
if (typeInfo.isList) {
mappedArgument.listItems = [
{
type: typeInfo.innerTypeName,
required: typeInfo.innerRequired,
},
];
}

// Add default value if present
if (argument.defaultValue) {
mappedArgument.default = parseDefaultValue(argument.defaultValue);
}

return mappedArgument;
}

/**
* Gets type information for an argument by unwrapping non-null and list types
*
* @param {object} params
* @param {TypeNode} params.type - The GraphQL type node
* @returns {ArgumentTypeInfo} Information about the argument type
*/
function getArgumentTypeInfo({ type }) {
if (type.kind === astNodeKind.NON_NULL_TYPE) {
const innerTypeInfo = getArgumentTypeInfo({ type: type.type });
return {
...innerTypeInfo,
required: true,
};
}

if (type.kind === astNodeKind.LIST_TYPE) {
const innerTypeInfo = getArgumentTypeInfo({ type: type.type });
return {
typeName: 'List',
isList: true,
innerTypeName: innerTypeInfo.typeName,
innerRequired: innerTypeInfo.required,
required: false,
};
}

if (type.kind === astNodeKind.NAMED_TYPE) {
const typeName = type.name.value;

return {
typeName: typeName,
required: false,
};
}

return {
typeName: 'String',
required: false,
};
}

module.exports = {
getArguments,
};
47 changes: 47 additions & 0 deletions reverse_engineering/mappers/defaultValue.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/**
* @import {ValueNode} from "graphql"
* @import {InputFieldDefaultValue} from "./../../shared/types/types"
*/

const { astNodeKind } = require('../constants/graphqlAST');

/**
* Parses a default value from a ValueNode into a string representation
*
* @param {ValueNode} defaultValue - The default value node to parse
* @param {boolean} [isNested] - Whether this value is nested inside an object or list. Default is `false`
* @returns {InputFieldDefaultValue} String representation of the default value
*/
function parseDefaultValue(defaultValue, isNested = false) {
switch (defaultValue.kind) {
case astNodeKind.INT:
return parseInt(defaultValue.value);
case astNodeKind.FLOAT:
return parseFloat(defaultValue.value);
case astNodeKind.ENUM:
return defaultValue.value;
case astNodeKind.STRING:
// Add quotes only if the string is nested in an object or list
return isNested ? `"${defaultValue.value}"` : defaultValue.value;
case astNodeKind.BOOLEAN:
return defaultValue.value.toString();
case astNodeKind.NULL:
return 'null';
case astNodeKind.LIST: {
const listValues = defaultValue.values.map(value => parseDefaultValue(value, true));
return `[${listValues.join(', ')}]`;
}
case astNodeKind.OBJECT: {
const objectFields = defaultValue.fields.map(
field => `${field.name.value}: ${parseDefaultValue(field.value, true)}`,
);
return `{ ${objectFields.join(', ')} }`;
}
default:
return '';
}
}

module.exports = {
parseDefaultValue,
};
48 changes: 9 additions & 39 deletions reverse_engineering/mappers/field.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
const { mapDirectivesUsage } = require('./directiveUsage');
const { astNodeKind } = require('../constants/graphqlAST');
const { BUILT_IN_SCALAR_LIST } = require('../constants/types');
const { getArguments } = require('./arguments');
const { parseDefaultValue } = require('./defaultValue');
const { sortByName } = require('../helpers/sortByName');

/**
Expand Down Expand Up @@ -56,57 +58,25 @@ function mapField({ field, definitionCategoryByNameMap }) {
sharedProperties.default = parseDefaultValue(field.defaultValue);
}

let mappedArguments;
if ('arguments' in field) {
mappedArguments = getArguments({ fieldArguments: [...(field.arguments || [])] });
}

if ('$ref' in fieldTypeProperties) {
return {
...sharedProperties,
refDescription: description,
// TODO: add arguments
...(mappedArguments && { arguments: mappedArguments }),
};
}
return {
...sharedProperties,
description,
// TODO: add arguments
...(mappedArguments && { arguments: mappedArguments }), // Added handling for mappedArguments
};
}

/**
* Parses a default value from a ValueNode into a string representation
*
* @param {ValueNode} defaultValue - The default value node to parse
* @param {boolean} [isNested] - Whether this value is nested inside an object or list. Default is `false`
* @returns {InputTypeFieldProperties['default']} String representation of the default value
*/
function parseDefaultValue(defaultValue, isNested = false) {
switch (defaultValue.kind) {
case astNodeKind.INT:
return parseInt(defaultValue.value);
case astNodeKind.FLOAT:
return parseFloat(defaultValue.value);
case astNodeKind.ENUM:
return defaultValue.value;
case astNodeKind.STRING:
// Add quotes only if the string is nested in an object or list
return isNested ? `"${defaultValue.value}"` : defaultValue.value;
case astNodeKind.BOOLEAN:
return defaultValue.value.toString();
case astNodeKind.NULL:
return 'null';
case astNodeKind.LIST: {
const listValues = defaultValue.values.map(value => parseDefaultValue(value, true));
return `[${listValues.join(', ')}]`;
}
case astNodeKind.OBJECT: {
const objectFields = defaultValue.fields.map(
field => `${field.name.value}: ${parseDefaultValue(field.value, true)}`,
);
return `{ ${objectFields.join(', ')} }`;
}
default:
return '';
}
}

/**
* Recursively maps the type properties unwrapping non-null and list types and resolving named types to references
*
Expand Down
3 changes: 2 additions & 1 deletion reverse_engineering/mappers/typeDefinitions/directive.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
* @import {REDirectiveDefinition, DirectiveLocations} from "../../../shared/types/types"
*/

const { getArguments } = require('../arguments');
const { getDirectiveName } = require('../directiveName');

const locationMap = {
Expand Down Expand Up @@ -57,7 +58,7 @@ function mapDirective({ directive }) {
type: 'directive',
name: getDirectiveName({ name: directive.name.value }),
description: directive.description?.value || '',
arguments: [], // TODO: implement argument mapping
arguments: getArguments({ fieldArguments: [...(directive.arguments || [])] }),
directiveLocations: locations,
};
}
Expand Down
4 changes: 3 additions & 1 deletion shared/types/fe.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,9 @@ export type FEDirectiveLocations = DirectiveLocations & {
GUID: string;
};

export type FEDirectiveDefinition = DirectiveDefinition<Argument, FEDirectiveLocations> & {
export type FEArgument = Argument<DirectivePropertyData>;

export type FEDirectiveDefinition = DirectiveDefinition<FEArgument, FEDirectiveLocations> & {
GUID: string;
additionalProperties?: boolean;
ignore_z_value: boolean;
Expand Down
11 changes: 11 additions & 0 deletions shared/types/re.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
EnumValue,
StructuredDirective,
InputFieldDefaultValue,
Argument,
EntityDetails,
} from './shared';

Expand Down Expand Up @@ -266,5 +267,15 @@ export type DefinitionTypeName =
| 'Directives';
export type DefinitionNameToTypeNameMap = Record<string, DefinitionTypeName>;

export type REArgument = Argument<StructuredDirective>;

export type ArgumentTypeInfo = {
typeName: string;
required: boolean;
isList?: boolean;
innerTypeName?: string;
innerRequired?: boolean;
};

export type TestConnectionCallback = (err?: Error | unknown) => void;
export type DisconnectCallback = TestConnectionCallback;
9 changes: 4 additions & 5 deletions shared/types/shared.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ type RegularFieldData<DirectiveUsage> = {
description?: string; // Description of the field
fieldDirectives?: DirectiveUsage[]; // Directives for the field
items?: ArrayItems<DirectiveUsage>; // Items of the List type
arguments?: Argument[]; // Arguments of the field
arguments?: Argument<DirectiveUsage>[]; // Arguments of the field
default?: InputFieldDefaultValue; // Default value of the field
};

Expand All @@ -105,7 +105,7 @@ type ReferenceFieldData<DirectiveUsage> = {
isActivated?: boolean; // If the field is activated
refDescription?: string; // Description of the reference
fieldDirectives?: DirectiveUsage[]; // Directives for the field
arguments?: Argument[]; // Arguments of the field
arguments?: Argument<DirectiveUsage>[]; // Arguments of the field
default?: InputFieldDefaultValue; // Default value of the reference
};

Expand All @@ -120,13 +120,12 @@ type ArgumentListItem = {
required?: boolean;
};

export type Argument = {
id: string;
export type Argument<DirectiveUsage> = {
type: string;
name: string;
default?: string;
description?: string;
directives?: DirectivePropertyData[];
directives?: DirectiveUsage[];
required?: boolean;
listItems?: ArgumentListItem[];
};
Expand Down
Loading