morethanwords
4 years ago
55 changed files with 11549 additions and 853 deletions
@ -0,0 +1,241 @@ |
|||||||
|
// @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); |
@ -0,0 +1,44 @@ |
|||||||
|
[{ |
||||||
|
"predicate": "document", |
||||||
|
"params": [ |
||||||
|
{"name": "thumbs", "type": "Array<PhotoSize.photoSize | PhotoSize.photoCachedSize | PhotoSize.photoStrippedSize>"}, |
||||||
|
{"name": "type", "type": "'gif' | 'sticker' | 'audio' | 'voice' | 'video' | 'round' | 'photo'"}, |
||||||
|
{"name": "h", "type": "number"}, |
||||||
|
{"name": "w", "type": "number"}, |
||||||
|
{"name": "file_name", "type": "string"}, |
||||||
|
{"name": "file", "type": "File"}, |
||||||
|
{"name": "duration", "type": "number"}, |
||||||
|
{"name": "downloaded", "type": "boolean"}, |
||||||
|
{"name": "url", "type": "string"}, |
||||||
|
{"name": "audioTitle", "type": "string"}, |
||||||
|
{"name": "audioPerformer", "type": "string"}, |
||||||
|
{"name": "sticker", "type": "number"}, |
||||||
|
{"name": "stickerEmoji", "type": "string"}, |
||||||
|
{"name": "stickerEmojiRaw", "type": "string"}, |
||||||
|
{"name": "stickerSetInput", "type": "InputStickerSet.inputStickerSetID"}, |
||||||
|
{"name": "stickerThumbConverted", "type": "true"}, |
||||||
|
{"name": "animated", "type": "boolean"}, |
||||||
|
{"name": "supportsStreaming", "type": "boolean"} |
||||||
|
] |
||||||
|
}, { |
||||||
|
"predicate": "photo", |
||||||
|
"params": [ |
||||||
|
{"name": "downloaded", "type": "boolean | number"}, |
||||||
|
{"name": "url", "type": "string"} |
||||||
|
] |
||||||
|
}, { |
||||||
|
"predicate": "photoSize", |
||||||
|
"params": [ |
||||||
|
{"name": "url", "type": "string"} |
||||||
|
] |
||||||
|
}, { |
||||||
|
"predicate": "photoCachedSize", |
||||||
|
"params": [ |
||||||
|
{"name": "url", "type": "string"} |
||||||
|
] |
||||||
|
}, { |
||||||
|
"predicate": "photoStrippedSize", |
||||||
|
"params": [ |
||||||
|
{"name": "url", "type": "string"} |
||||||
|
] |
||||||
|
}] |
Loading…
Reference in new issue