Skip to content

Commit

Permalink
HCK-9551: add custom scalars FE (#35)
Browse files Browse the repository at this point in the history
* init custom scalars FE

* add custom scalar types mapping

* add ts types file
  • Loading branch information
taras-dubyk authored Jan 17, 2025
1 parent 06e030d commit 87d5eb6
Show file tree
Hide file tree
Showing 7 changed files with 178 additions and 21 deletions.
31 changes: 10 additions & 21 deletions forward_engineering/api.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const validationHelper = require('./helpers/schemaValidationHelper');
const { getTypeDefinitionStatements } = require('./mappers/typeDefinitions');

/**
* @typedef {Object} Container
Expand Down Expand Up @@ -40,26 +41,9 @@ const validationHelper = require('./helpers/schemaValidationHelper');
* @param {Array} [result]
*/

const mockedScript = `# The schema is hardcoded for demonstration purposes only.
interface SearchResult {
id: ID
title: String!
}
# type Query {
# search(keyword: String): [SearchResult]
# }
type User implements SearchResult {
name: String!
email: String!
}
type Post implements SearchResult {
id: ID!
title: String!
content: String!
author: User
const mockedRootQuery = `# The type Query is hardcoded for now, to remove validation error.
type Query {
getSomething: String
}`;

module.exports = {
Expand All @@ -71,7 +55,12 @@ module.exports = {
*/
generateModelScript(data, logger, cb) {
try {
cb(null, mockedScript);
const typeDefinitions = getTypeDefinitionStatements({
modelDefinitions: JSON.parse(data.modelDefinitions),
});

const schemaScript = mockedRootQuery + '\n\n' + typeDefinitions;
cb(null, schemaScript);
} catch (err) {
logger.log('error', { error: err }, 'GraphQL FE Error');
cb(err);
Expand Down
19 changes: 19 additions & 0 deletions forward_engineering/helpers/deactivatedItemsHelper.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/**
* Comments out a GraphQL statement if it is deactivated.
*
* @param {Object} param0
* @param {string} param0.statement - The GraphQL statement to comment out
* @returns {string} - Commented out statement
*/
function commentOutDeactivatedRootFEStatement({ statement }) {
const commentedStatement = statement
.split('\n')
.map(line => `# ${line}`)
.join('\n');

return commentedStatement;
}

module.exports = {
commentOutDeactivatedRootFEStatement,
};
24 changes: 24 additions & 0 deletions forward_engineering/helpers/descriptionsHelper.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/**
* Formats the description for a GraphQL statement.
* Uses triple quotes for multi-line descriptions and single quotes for single-line descriptions.
*
* @param {Object} param0
* @param {string} param0.description - The description to format
* @returns {string} - The formatted description
*/
function getStatementDescription({ description }) {
if (!description) {
return '';
}

const isMultiLine = description.includes('\n');

// Format the description based on whether it is multi-line or single-line
const formattedDescription = isMultiLine ? `"""\n${description}\n"""` : `"${description}"`;

return formattedDescription;
}

module.exports = {
getStatementDescription,
};
34 changes: 34 additions & 0 deletions forward_engineering/helpers/feStatementHelper.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
const { commentOutDeactivatedRootFEStatement } = require('./deactivatedItemsHelper');
const { getStatementDescription } = require('./descriptionsHelper');

/**
* Combines the description and statement, and comments out the statement if it is deactivated.
*
* @param {Object} param0
* @param {Object} param0.feStatement - The forward engineering statement object.
* @param {string} param0.feStatement.statement - The GraphQL statement.
* @param {string} param0.feStatement.description - The description of the statement.
* @param {boolean} param0.feStatement.isActivated - Indicates if the statement is activated.
* @returns {string} - The final formatted statement.
*/
function formatFEStatement({ feStatement }) {
const { statement, description, isActivated } = feStatement;
let result = '';

if (description?.trim()) {
const formattedDescription = getStatementDescription({ description });
result += `${formattedDescription}\n`;
}

result += statement;

if (!isActivated) {
result = commentOutDeactivatedRootFEStatement({ statement: result, isActivated });
}

return result;
}

module.exports = {
formatFEStatement,
};
45 changes: 45 additions & 0 deletions forward_engineering/mappers/customScalars.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/**
* @typedef { import("../types/types").FEStatement } FEStatement
*/

/**
* @typedef {Object} CustomScalar
* @property {string} description - The description of the custom scalar.
* @property {boolean} isActivated - Indicates if the custom scalar is activated.
* @property {Object} typeDirectives - The directives of the custom scalar. TODO: implement mapping
*/

/**
* @typedef {Object.<string, CustomScalar>} CustomScalars
*/

/**
* Maps a custom scalar to an FEStatement.
*
* @param {Object} param0
* @param {string} param0.name - The name of the custom scalar.
* @param {CustomScalar} param0.customScalar - The custom scalar object.
* @returns {FEStatement}
*/
function mapCustomScalar({ name, customScalar }) {
return {
statement: `scalar ${name}`, // TODO: add directives here
description: customScalar.description,
isActivated: customScalar.isActivated,
};
}

/**
* Gets the custom scalars as an array of FEStatements.
*
* @param {Object} param0
* @param {CustomScalars} param0.customScalars - The custom scalars object.
* @returns {FEStatement[]}
*/
function getCustomScalars({ customScalars }) {
return Object.entries(customScalars).map(([name, customScalar]) => mapCustomScalar({ name, customScalar }));
}

module.exports = {
getCustomScalars,
};
41 changes: 41 additions & 0 deletions forward_engineering/mappers/typeDefinitions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
const { formatFEStatement } = require('../helpers/feStatementHelper');
const { getCustomScalars } = require('./customScalars');

/**
* Gets the type definition statements from model definitions.
*
* @param {Object} param0
* @param {Object} param0.modelDefinitions - The model definitions object.
* @returns {string} - The formatted type definition statements.
*/
function getTypeDefinitionStatements({ modelDefinitions }) {
const customScalars = getCustomScalars({
customScalars: getModelDefinitionsBySubtype({ modelDefinitions, subtype: 'scalar' }),
});

const typeDefinitions = [...customScalars]; // TODO: Add other types here
const formattedTypeDefinitions = typeDefinitions
.map(typeDefinition => formatFEStatement({ feStatement: typeDefinition }))
.join('\n\n');

return formattedTypeDefinitions;
}

/**
* Gets the model definitions by parent's subtype, to not use definitions category name as it may change.
*
* @param {Object} param0 - The parameter object.
* @param {Object} param0.modelDefinitions - The model definitions object.
* @param {string} param0.subtype - The subtype to filter by.
* @returns {Object} - The model definitions found by parent's subtype.
*/
function getModelDefinitionsBySubtype({ modelDefinitions, subtype }) {
const subtypeDefinitions = Object.values(modelDefinitions.properties).find(
definition => definition.subtype === subtype,
);
return subtypeDefinitions?.properties || {};
}

module.exports = {
getTypeDefinitionStatements,
};
5 changes: 5 additions & 0 deletions forward_engineering/types/types.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export type FEStatement = {
statement: string;
description: string;
isActivated: boolean;
}

0 comments on commit 87d5eb6

Please sign in to comment.