ec736f8590
i've been wanting to name a commit like this for my entire life, lol. seriously though, a lot has changed: - extracted TL-related stuff to `@mtcute/tl-utils` and `@mtcute/tl-runtime`, rewrote codegen in TS - updated to layer 134, moved to int64 identifiers - rewritten networking (mtproto), rewritten updates handling - *lots* of refactoring still a very early version though, there are a lot of improvements to be made, but at least it runs, lol also tl-reference will not be updated anytime soon because i want to rewrite it
113 lines
3.1 KiB
TypeScript
113 lines
3.1 KiB
TypeScript
import { TL_PRIMITIVES, TlEntry } from '../types'
|
|
import { computeConstructorIdFromEntry } from '../ctor-id'
|
|
import { snakeToCamel } from './utils'
|
|
|
|
export const TL_WRITER_PRELUDE =
|
|
'function h(o, p){' +
|
|
'var q=o[p];' +
|
|
'if(q===void 0)' +
|
|
"throw Error('Object '+o._+' is missing required property '+p);" +
|
|
'return q}\n'
|
|
|
|
/**
|
|
* Returns code as an object entry.
|
|
*
|
|
* `h` (has) function should be available
|
|
*/
|
|
export function generateWriterCodeForTlEntry(entry: TlEntry): string {
|
|
if (entry.id === 0) entry.id = computeConstructorIdFromEntry(entry)
|
|
|
|
let ret = `'${entry.name}':function(w${
|
|
entry.arguments.length ? ',v' : ''
|
|
}){`
|
|
|
|
ret += `w.uint(${entry.id});`
|
|
|
|
const flagsFields: Record<string, 1> = {}
|
|
|
|
entry.arguments.forEach((arg) => {
|
|
if (arg.type === '#') {
|
|
ret += `var ${arg.name}=0;`
|
|
|
|
entry.arguments.forEach((arg1) => {
|
|
let s
|
|
if (
|
|
!arg1.predicate ||
|
|
(s = arg1.predicate.split('.'))[0] !== arg.name
|
|
)
|
|
return
|
|
|
|
const arg1Name = snakeToCamel(arg1.name)
|
|
|
|
const bitIndex = parseInt(s[1])
|
|
if (isNaN(bitIndex) || bitIndex < 0 || bitIndex > 32) {
|
|
throw new Error(
|
|
`Invalid predicate: ${arg1.predicate} - invalid bit`
|
|
)
|
|
}
|
|
|
|
const action = `${arg.name}|=${1 << bitIndex};`
|
|
|
|
if (arg1.type === 'true') {
|
|
ret += `if(v.${arg1Name}===true)${action}`
|
|
} else if (arg1.type.match(/^[Vv]ector/)) {
|
|
ret += `var _${arg1Name}=v.${arg1Name}&&v.${arg1Name}.length;if(_${arg1Name})${action}`
|
|
} else {
|
|
ret += `var _${arg1Name}=v.${arg1Name}!==undefined;if(_${arg1Name})${action}`
|
|
}
|
|
})
|
|
|
|
ret += `w.uint(${arg.name});`
|
|
flagsFields[arg.name] = 1
|
|
return
|
|
}
|
|
|
|
const argName = snakeToCamel(arg.name)
|
|
|
|
let vector = false
|
|
let type = arg.type
|
|
const m = type.match(/^[Vv]ector[< ](.+?)[> ]$/)
|
|
if (m) {
|
|
vector = true
|
|
type = m[1]
|
|
}
|
|
|
|
if (arg.predicate) {
|
|
if (type === 'true') return // included in flags
|
|
|
|
ret += `if(_${argName})`
|
|
} else {
|
|
ret += `h(v,'${argName}');`
|
|
}
|
|
|
|
if (type in TL_PRIMITIVES) {
|
|
if (type === 'Bool') type = 'boolean'
|
|
} else {
|
|
type = 'object'
|
|
}
|
|
|
|
if (vector) {
|
|
ret += `w.vector(w.${type}, v.${argName});`
|
|
} else {
|
|
ret += `w.${type}(v.${argName});`
|
|
}
|
|
})
|
|
|
|
return ret + '},'
|
|
}
|
|
|
|
export function generateWriterCodeForTlEntries(
|
|
entries: TlEntry[],
|
|
varName: string,
|
|
prelude = true
|
|
): string {
|
|
let ret = ''
|
|
if (prelude) ret += TL_WRITER_PRELUDE
|
|
ret += `var ${varName}={\n`
|
|
|
|
entries.forEach((entry) => {
|
|
ret += generateWriterCodeForTlEntry(entry) + '\n'
|
|
})
|
|
|
|
return ret + '}'
|
|
}
|