import fs from 'fs' // TODO: replace with fetch of live spec const DISCORD_SPEC = {} function schemaRefToName(ref) { if (!ref) return "" return `Discord${ref?.substring(ref.lastIndexOf('/') + 1)}` } function snakeToPascalCase(str) { if (!str.includes('_')) return str let result = '' for (let i = 0, len = str.length; i < len; ++i) { if (str[i] === '_') { result += str[++i].toUpperCase() continue } result += str[i] } return result } function generateFromSpec() { const finalTypings = [] for (const [key, schema] of Object.entries(DISCORD_SPEC.components.schemas)) { const interfacey = [`export interface Discord${key} {`] if (schema.properties) { for (const [name, property] of Object.entries(schema.properties)) { const type = Array.isArray(property.type) ? property.type : property.type ? [property.type] : undefined let ref = property.$ref && schemaRefToName(property.$ref) let allOf = property.allOf?.find((a) => a.$ref) if (allOf) { allOf = schemaRefToName(allOf.$ref) } const isArray = property.type === 'array' if (isArray) { if (property.items.$ref) ref = schemaRefToName(property.items.$ref) else if (Array.isArray(property.oneOf)) { ref = property.oneOf.map((o) => schemaRefToName(o.$ref)).join(' | ') } } if (property.description) { interfacey.push(` /** ${property.description} */`) } let cleanType = ref ?? allOf ?? type ?.map((type) => type === 'integer' ? 'number' : type === 'array' ? property.items.$ref ? `${schemaRefToName(property.items.$ref)}[]` : Array.isArray(property.items.oneOf) ? `${property.items.oneOf.map((o) => `${schemaRefToName(o.$ref)}[]`).join(' | ')}` : `unknown[]` : type, ) .join(' | ') ?? property.oneOf ?.map( (o) => (o.type ? o.type === 'integer' ? o.enum ? o.allOf.map((a) => schemaRefToName(a.$ref)).join(' | ') : 'number' : o.type : undefined) ?? schemaRefToName(o.$ref), ) .join(' | ') ?? 'unknown' if (cleanType.startsWith('null | ')) cleanType = cleanType.substring(cleanType.indexOf('|') + 2) + ' | null' interfacey.push(` ${name}${schema.required?.includes(name) ? ':' : '?:'} ${cleanType}`) } } else { // No properties so is enum if (['integer', 'string'].includes(schema.type) && Array.isArray(schema.oneOf)) { const enumm = [`export enum Discord${key} {`] for (const possible of schema.oneOf) { if (possible.description) enumm.push(` /** ${possible.description} */`) // TODO: camel case the title enumm.push( ` ${possible.title.includes('-') ? '"' : ''}${snakeToPascalCase( `${possible.title[0].toUpperCase()}${possible.title.substring(1).toLowerCase()}`, )}${possible.title.includes('-') ? '"' : ''} = ${schema.type === 'string' ? '"' : ''}${possible.const}${ schema.type === 'string' ? '"' : '' },`, ) } enumm.push('}') finalTypings.push(enumm.join('\n')) continue } console.log('NO PROPERTIES', key, schema) continue } interfacey.push('}') finalTypings.push(interfacey.join('\n')) } fs.writeFileSync('./packages/types/src/discord.ts', finalTypings.join('\n\n'), function (err, result) { if (err) throw err }) } generateFromSpec()