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

// @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);