Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🌟 feat(domain-config): add config-type-generator script #2973

Draft
wants to merge 3 commits into
base: dev
Choose a base branch
from
Draft
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
6 changes: 3 additions & 3 deletions .env.template
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,13 @@ ANALYZE="false"
NODE_ENV="development"
NODE_OPTIONS="--max-old-space-size=6144"
SHOW_BUILD_INFO=false


DATABASE_URL="postgresql://user:pass@localhost:5432/db?schema=public"
CHALLENGE_JWT_SECRET="ABC123"
USER_JWT_SECRET="A123124124"
PRODUCT_HUB_KEY=""
ALLOWED_ORIGINS=""
CONFIG_URL=""
CONFIG_DOMAIN_URL=""

# Subgraphs & Cache
AJNA_SUBGRAPH_URL=""
Expand All @@ -62,4 +62,4 @@ NOTIFICATIONS_HOST=""
NOTIFICATIONS_HOST_GOERLI=""

RPC_GATEWAY=
GROOVE_WIDGET_ID=
GROOVE_WIDGET_ID=
164 changes: 164 additions & 0 deletions scripts/config-type-generators/domain.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
const dotenv = require('dotenv')
const { mkdir, readdir, writeFile } = require('fs/promises')
const fetch = require('node-fetch')
const { join } = require('path')

dotenv.config({
path: '.env',
})
dotenv.config({
path: '.env.local',
})

const getConfig = async () => {
const response = await fetch(process.env.CONFIG_URL)
return await response.json()
}

// Helpers
const getTokenInterfaceName = (tokenName) => {
return `${tokenName.charAt(0).toUpperCase()}${tokenName.slice(1)}`
}

/**
* Generates TypeScript domain types from a given configuration object.
*
* @param {Object} configObject - The configuration object to generate types from.
* @returns {string} The generated TypeScript types.
*/
const getDomainTypes = (configObject) => {
try {
const getRootInterface = () => {
return `export interface DomainConfigType {
tokens: Tokens;
tokensByNetwork: TokensByNetwork;
lendingProtocols: LendingProtocol;
networks: Networks;
}`
}

const getTokenInterfaces = (tokens) => {
return Object.keys(tokens)
.map(
(token) =>
`interface ${getTokenInterfaceName(
token,
)} {\n symbol: TokensEnum.${token};\n precision: number;\n}`,
)
.join('\n\n')
}

const getTokensEnum = (tokens) => {
return `export enum TokensEnum {\n${Object.keys(tokens)
.map((token) => ` ${token} = '${token}',`)
.join('\n')}\n}`
}

const getTokensInterface = (tokens) => {
return `interface Tokens {\n ${Object.entries(tokens)
.map(([tokenName]) => `${tokenName}: ${getTokenInterfaceName(tokenName)};`)
.join('\n ')}\n}`
}

const getTokensByNetworkInterface = (tokensByNetwork) => {
const replacements = Object.keys(tokensByNetwork).map((network) => {
const tokensForNetwork = tokensByNetwork[network]
const tokenNamesTypeUnion = tokensForNetwork
.map((tokenObj) =>
Object.keys(tokenObj)
.map((token) => `{${token}: ${getTokenInterfaceName(token)}}`)
.join('; '),
)
.join(' | ')
return `${network}: ${tokenNamesTypeUnion}[];`
})
return `interface TokensByNetwork {\n ${replacements.join('\n ')}\n}`
}

const getLendingProtocolsEnums = (lendingProtocols) => {
const protocolNames = Object.keys(lendingProtocols)
const protocolEnum = `export enum LendingProtocol {\n${protocolNames
.map((key) => ` ${key.charAt(0).toUpperCase() + key.slice(1)} = '${key}',`)
.join('\n')}\n}`
const labelEnum = `export enum LendingProtocolLabel {\n${protocolNames
.map((key) => ` ${key} = '${lendingProtocols[key]}',`)
.join('\n')}\n}`
return `${protocolEnum}\n\n${labelEnum}`
}

const getNetworksEnum = (networks) => {
const enumEntries = Object.keys(networks)
.map((networkName) => ` ${networkName.toUpperCase()} = '${networkName.toLowerCase()}',`)
.join('\n')
return `export enum Networks {\n${enumEntries}\n}`
}

const getDenominationSymbols = (denominationSymbols) => {
const enumEntries = Object.keys(denominationSymbols)
.map(
(denominationSymbol) =>
` ${denominationSymbol.toUpperCase()} = '${denominationSymbol.toUpperCase()}',`,
)
.join('\n')
return `export enum DenominationSymbols {\n${enumEntries}\n}`
}

// Construct the types for each section
const rootSection = getRootInterface()
const tokensSection = `${getTokensInterface(configObject.tokens)}\n\n${getTokensEnum(
configObject.tokens,
)}\n\n${getTokenInterfaces(configObject.tokens)}`
const tokensByNetworkSection = getTokensByNetworkInterface(configObject.tokensByNetwork)
const lendingProtocolsSection = getLendingProtocolsEnums(configObject.lendingProtocols)
const networksSection = getNetworksEnum(configObject.networks)
const denominationSymbolsSection = getDenominationSymbols(configObject.denominationSymbols)

// Assemble the final types
const types = [
rootSection,
tokensSection,
tokensByNetworkSection,
lendingProtocolsSection,
networksSection,
denominationSymbolsSection,
].join('\n\n')

return types
} catch (error) {
console.error(`Error generating config types: ${error}`)
return ''
}
}

const main = async () => {
if (!process.env.CONFIG_URL) {
console.error('CONFIG_URL environment variable not set')
return
}
const config = await getConfig()
const types = getDomainTypes(config)
const configPath = join(__dirname, 'types')
const configPathExists = await readdir(configPath).catch(() => false)

if (!configPathExists) {
await mkdir(configPath)
.catch(() => {
console.error('Error creating types/config directory')
})
.then(() => {
console.info(`${configPath} directory created`)
})
}

if (types !== '') {
writeFile(join(configPath, 'index.ts'), types)
.then(() => {
console.info('Config types generated')
})
.catch((error) => {
console.error(`Error generating config types: ${error}`)
})
}
}

module.export = { generateDomainConfigTypes: main }
71 changes: 71 additions & 0 deletions scripts/config-type-generators/oasis-borrow.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
const dotenv = require('dotenv')
const { mkdir, readdir, writeFile } = require('fs/promises')
const JsonToTS = require('json-to-ts')
const fetch = require('node-fetch')
const { join } = require('path')

dotenv.config({
path: '.env',
})
dotenv.config({
path: '.env.local',
})

const getConfig = async () => {
const response = await fetch(process.env.CONFIG_URL)
return await response.json()
}

const getInterfaces = (configObject = { features: {} }) => {
try {
const interfaces = JsonToTS(configObject)
.map((typeInterface) => {
if (typeInterface.includes('RootObject')) {
return typeInterface.replace('interface RootObject', 'export interface AppConfigType')
}
return typeInterface
})
.join('\n\n')
const featuresList = Object.keys(configObject.features || {})
const featuresEnum = `export enum FeaturesEnum {
${featuresList.map((feature) => ` ${feature} = '${feature}',`).join('\n')}
}`
return `${interfaces}\n${featuresEnum}`
} catch (error) {
console.error(`Error generating config types: ${error}`)
return ''
}
}

const main = async () => {
if (!process.env.CONFIG_URL) {
console.error('CONFIG_URL environment variable not set')
return
}
const config = await getConfig()
const interfaces = getInterfaces(config)
const configPath = join(__dirname, '..', 'types', 'config')
const configPathExists = await readdir(configPath).catch(() => false)

if (!configPathExists) {
await mkdir(configPath)
.catch(() => {
console.error('Error creating types/config directory')
})
.then(() => {
console.info(`${configPath} directory created`)
})
}

if (interfaces !== '') {
writeFile(join(configPath, 'index.ts'), interfaces)
.then(() => {
console.info('Config types generated')
})
.catch((error) => {
console.error(`Error generating config types: ${error}`)
})
}
}

module.export = { generateOasisBorrowConfigTypes: main }
74 changes: 8 additions & 66 deletions scripts/get-config-types.js
Original file line number Diff line number Diff line change
@@ -1,71 +1,13 @@
const dotenv = require('dotenv')
const { mkdir, readdir, writeFile } = require('fs/promises')
const JsonToTS = require('json-to-ts')
const fetch = require('node-fetch')
const { join } = require('path')

dotenv.config({
path: '.env',
})
dotenv.config({
path: '.env.local',
})

const getConfig = async () => {
const response = await fetch(process.env.CONFIG_URL)
return await response.json()
}

const getInterfaces = (configObject = { features: {} }) => {
try {
const interfaces = JsonToTS(configObject)
.map((typeInterface) => {
if (typeInterface.includes('RootObject')) {
return typeInterface.replace('interface RootObject', 'export interface AppConfigType')
}
return typeInterface
})
.join('\n\n')
const featuresList = Object.keys(configObject.features || {})
const featuresEnum = `export enum FeaturesEnum {
${featuresList.map((feature) => ` ${feature} = '${feature}',`).join('\n')}
}`
return `${interfaces}\n${featuresEnum}`
} catch (error) {
console.error(`Error generating config types: ${error}`)
return ''
}
}
const { generateOasisBorrowConfigTypes } = require('./config-type-generators/oasis-borrow')
const { generateDomainConfigTypes } = require('./config-type-generators/domain')

const main = async () => {
if (!process.env.CONFIG_URL) {
console.error('CONFIG_URL environment variable not set')
return
}
const config = await getConfig()
const interfaces = getInterfaces(config)
const configPath = join(__dirname, '..', 'types', 'config')
const configPathExists = await readdir(configPath).catch(() => false)

if (!configPathExists) {
await mkdir(configPath)
.catch(() => {
console.error('Error creating types/config directory')
})
.then(() => {
console.info(`${configPath} directory created`)
})
}

if (interfaces !== '') {
writeFile(join(configPath, 'index.ts'), interfaces)
.then(() => {
console.info('Config types generated')
})
.catch((error) => {
console.error(`Error generating config types: ${error}`)
})
}
await generateOasisBorrowConfigTypes.catch((error) => {
console.error(`Error generating Oasis Borrow config types: ${error}`)
})
await generateDomainConfigTypes.catch((error) => {
console.error(`Error generating Domain config types: ${error}`)
})
}

void main()
Loading