// since this logic is quite big, i decided to // implement it in a separate file // // this basically takes descriptions.yaml and applies // it to the resulting JSON. async function applyDescriptionsFile(input, yaml) { const { objects: byObjects, arguments: byArguments, regex: byRegex } = yaml // util function to handle text and objects with text for overrides function applyOverwrite(where, what) { let text = what let overwrite = false if (typeof what === 'object') { if (!what.text) throw new Error('Invalid overwrite object') text = what.text overwrite = what.overwrite } if (!where.description || overwrite) { where.description = text } } // first create an index of all classes, methods and unions const index = {} function indexNs(ns, prefix = '') { Object.entries(ns).forEach(([name, content]) => { const pref = prefix + (name === '$root' ? '' : `${name}.`) content.classes.forEach( (obj) => (index['o_' + pref + obj.name] = obj) ) content.methods.forEach( (obj) => (index['o_' + pref + obj.name] = obj) ) content.unions.forEach( (obj) => (index['u_' + pref + obj.type] = obj) ) }) } indexNs(input.mtproto, 'mt_') indexNs(input.api) // process byObject Object.entries(byObjects).forEach(([name, content]) => { if (!(name in index)) { return } const obj = index[name] if (content.desc) applyOverwrite(obj, content.desc) if (content.arguments) Object.entries(content.arguments).forEach(([arg, repl]) => { const argObj = (obj.arguments || []).find( (it) => it.name === arg ) if (!argObj) return applyOverwrite(argObj, repl) }) }) // process byArguments // first create index based on `name` const byArgumentsIndex = {} byArguments.forEach((rule) => { let name = rule.name if (!Array.isArray(name)) name = [name] name.forEach((n) => { if (!(n in byArgumentsIndex)) byArgumentsIndex[n] = [] byArgumentsIndex[n].push(rule) }) }) // now find all objects with these arguments and patch Object.entries(index).forEach(([key, obj]) => { if (!obj.arguments) return // unions args: for (const arg of obj.arguments) { if (!(arg.name in byArgumentsIndex)) continue const rules = byArgumentsIndex[arg.name] for (const rule of rules) { if (rule.filters) { for (const filter of rule.filters) { if (filter.objType && filter.objType[0] !== key[0]) break args if ( filter.type && !filter.type.split(' | ').includes(arg.type) ) break args // noinspection EqualityComparisonWithCoercionJS if (filter.optional && arg.optional != filter.optional) break args } } applyOverwrite(arg, rule.desc) } } }) // process byRegex function replaceRegex(obj, regex) { if (!obj.description) return if (!regex._cached) { let flags = regex.flags || '' if (flags.indexOf('g') === -1) flags += 'g' regex._cached = new RegExp(regex.regex, flags) } obj.description = obj.description.replace(regex._cached, regex.repl) } Object.values(index).forEach((obj) => { for (const regex of byRegex) { replaceRegex(obj, regex) if (obj.arguments) obj.arguments.forEach((arg) => replaceRegex(arg, regex)) } }) return input } module.exports = { applyDescriptionsFile, } if (require.main === module) { const fs = require('fs') const path = require('path') const yaml = require('js-yaml') applyDescriptionsFile( JSON.parse( fs.readFileSync(path.join(__dirname, '../raw-schema.json'), 'utf-8') ), yaml.load( fs.readFileSync( path.join(__dirname, '../descriptions.yaml'), 'utf-8' ) ) ) .then((res) => fs.writeFileSync( path.join(__dirname, '../raw-schema.json'), JSON.stringify(res) ) ) .catch((err) => { console.error(err) process.exit(1) }) }