Telegram Web K with changes to work inside I2P
https://web.telegram.i2p/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
241 lines
6.0 KiB
241 lines
6.0 KiB
// @ts-check |
|
const schema = require('./in/schema.json'); |
|
const additional = require('./in/schema_additional_params.json'); |
|
|
|
const mtproto = schema.API; |
|
|
|
for(const constructor of additional) { |
|
constructor.params.forEach(param => { |
|
param.type = 'flags.-1?' + param.type; |
|
}); |
|
|
|
const realConstructor = mtproto.constructors.find(c => c.predicate == constructor.predicate); |
|
realConstructor.params.splice(realConstructor.params.length, 0, ...constructor.params); |
|
} |
|
|
|
['Vector t', 'Bool', 'True', 'Null'].forEach(key => { |
|
let idx = -1; |
|
do { |
|
idx = mtproto.constructors.findIndex(c => c.type == key); |
|
if(idx !== -1) { |
|
mtproto.constructors.splice(idx, 1); |
|
} else { |
|
break; |
|
} |
|
} while(true); |
|
|
|
//delete types[key]; |
|
}); |
|
|
|
/** @type {(string: string) => string} */ |
|
function capitalizeFirstLetter(string) { |
|
return string[0].toUpperCase() + string.slice(1); |
|
} |
|
|
|
/** @type {(string: string, camelizeFirstLetterIfFound: boolean, camelizeFirstLetterIfNotFound: boolean) => string} */ |
|
function camelizeName(string, camelizeFirstLetterIfFound, camelizeFirstLetterIfNotFound = false) { |
|
if(!string.includes('.')) { |
|
if(camelizeFirstLetterIfNotFound) { |
|
string = capitalizeFirstLetter(string); |
|
} |
|
|
|
return string; |
|
} |
|
|
|
if(camelizeFirstLetterIfFound) { |
|
string = capitalizeFirstLetter(string); |
|
} |
|
|
|
return string.replace(/\../g, (match, index) => { |
|
return match[1].toUpperCase(); |
|
}); |
|
} |
|
|
|
/** @type {(type: string) => any} */ |
|
const processParamType = (type) => { |
|
const isAdditional = type.indexOf('flags.-1?') === 0; |
|
if(type.includes('?')) { |
|
type = type.split('?')[1]; |
|
} |
|
|
|
if(type.includes('Vector')) { |
|
return `Array<${processParamType(type.slice(7, -1))}>`; |
|
} |
|
|
|
switch(type) { |
|
case '#': |
|
case 'int': |
|
return 'number'; |
|
|
|
case 'true': |
|
return 'true'; |
|
|
|
case 'Bool': |
|
return 'boolean'; |
|
|
|
case 'double': |
|
return 'number'; |
|
|
|
case 'long': |
|
return 'string'; |
|
|
|
case 'bytes': |
|
return 'Uint8Array | number[]'; |
|
|
|
case 'string': |
|
return 'string'; |
|
|
|
case 'X': |
|
case '!X': |
|
return 'any'; |
|
|
|
default: |
|
//console.log('no such type', type); |
|
//throw new Error('no such type: ' + type); |
|
return isAdditional ? type : camelizeName(type, true); |
|
} |
|
}; |
|
|
|
/** @type {(params: {name: string, type: string}[], object: any, parseBooleanFlags: boolean) => any} */ |
|
const processParams = (params, object = {}, parseBooleanFlags = true) => { |
|
for(const param of params) { |
|
let {name, type} = param; |
|
|
|
if(type.includes('?') || name == 'flags') { |
|
name += '?'; |
|
} |
|
|
|
const processed = processParamType(type); |
|
if(type.includes('?true') && parseBooleanFlags) { |
|
if(!object.pFlags) object.pFlags = {}; |
|
object.pFlags[name] = processed; |
|
} else { |
|
object[name] = processed; |
|
} |
|
} |
|
|
|
return object; |
|
}; |
|
|
|
/** @type {(object: any) => boolean} */ |
|
function isObject(object) { |
|
return typeof(object) === 'object' && object !== null; |
|
} |
|
|
|
/** @type {(object: any, outArray: string[], space: string) => string[]} */ |
|
function serializeObject(object, outArray, space) { |
|
for(const key in object) { |
|
const value = object[key]; |
|
|
|
if(isObject(value)) { // only pFlags |
|
outArray.push(`${space}${key}?: Partial<{`); |
|
serializeObject(value, outArray, space + '\t'); |
|
outArray.push(`${space}}>`); |
|
} else { |
|
outArray.push(`${space}${key}: ${value}`); |
|
} |
|
} |
|
|
|
return outArray; |
|
} |
|
|
|
let out = ''; |
|
/** @type {Array<{key: 'predicate' | 'method', instanceKey: 'constructors' | 'methods', name: string}>} */ |
|
/* const lol = [{key: 'predicate', instanceKey: 'constructors', name: 'Constructor'}, {key: 'method', instanceKey: 'methods', name: 'Method'}]; |
|
lol.forEach(info => { |
|
const {key: keyName, instanceKey, name: mapName} = info; */ |
|
|
|
/** @type {{[type: string]: string[]}} */ |
|
const types = {}; |
|
/** @type {{[predicate: string]: any}} */ |
|
const constructors = {}; |
|
/** @type {{[predicate: string]: string}} */ |
|
const constructorsTypes = {}; |
|
|
|
mtproto.constructors.forEach((constructor) => { |
|
const {type, predicate, params} = constructor; |
|
|
|
if(!types.hasOwnProperty(type)) { |
|
types[type] = []; |
|
} |
|
|
|
types[type].push(predicate); |
|
|
|
constructorsTypes[predicate] = camelizeName(type, true) + '.' + camelizeName(predicate, false); |
|
|
|
// type end |
|
|
|
/** @type {any} */ |
|
const c = { |
|
_: `'${predicate}'` |
|
}; |
|
constructors[predicate] = c; |
|
|
|
processParams(params, c, true); |
|
|
|
/* if(predicate == 'inputFileLocation') { |
|
console.log(c); |
|
} */ |
|
}); |
|
|
|
for(const type in types) { |
|
const cs = types[type]; |
|
|
|
const camelizedType = camelizeName(type, true); |
|
|
|
const csTypes = cs.map(name => { |
|
const str = `export type ${camelizeName(name, false)} = {\n`; |
|
|
|
const params = serializeObject(constructors[name], [], '\t\t'); |
|
|
|
return str + params.join(',\n').replace(/\{,/g, '{') + '\n\t};'; |
|
}); |
|
|
|
|
|
out += `/** |
|
* @link https://core.telegram.org/type/${type} |
|
*/ |
|
export type ${camelizedType} = ${cs.map(name => camelizedType + '.' + camelizeName(name, false)).join(' | ')}; |
|
|
|
export namespace ${camelizedType} { |
|
${csTypes.join('\n\n\t')} |
|
} |
|
|
|
`; |
|
|
|
} |
|
|
|
//console.log(types['InputUser']); |
|
|
|
out += `export interface ConstructorDeclMap {\n`; |
|
for(const predicate in constructorsTypes) { |
|
out += `\t'${predicate}': ${constructorsTypes[predicate]},\n`; |
|
} |
|
out += `}\n\n`; |
|
|
|
/** @type {{[method: string]: {req: string, res: string}}} */ |
|
const methodsMap = {}; |
|
mtproto.methods.forEach((_method) => { |
|
const {method, type, params} = _method; |
|
|
|
const camelizedMethod = camelizeName(method, true, true); |
|
|
|
methodsMap[method] = {req: camelizedMethod, res: processParamType(type)}; |
|
|
|
let str = `export type ${camelizedMethod} = {\n`; |
|
|
|
const object = processParams(params, {}, false); |
|
|
|
const serialized = serializeObject(object, [], '\t'); |
|
|
|
str += serialized.join(',\n').replace(/\{,/g, '{') + '\n};\n\n'; |
|
out += str; |
|
}); |
|
|
|
out += `export interface MethodDeclMap {\n`; |
|
for(const method in methodsMap) { |
|
out += `\t'${method}': {req: ${methodsMap[method].req}, res: ${methodsMap[method].res}},\n`; |
|
} |
|
out += `}\n\n`; |
|
|
|
require('fs').writeFileSync('./out/layer.d.ts', out); |