diff --git a/packages/tl-utils/src/codegen/reader.ts b/packages/tl-utils/src/codegen/reader.ts index 9bb6b68b..adb667be 100644 --- a/packages/tl-utils/src/codegen/reader.ts +++ b/packages/tl-utils/src/codegen/reader.ts @@ -2,17 +2,44 @@ import { computeConstructorIdFromEntry } from '../ctor-id' import { TL_PRIMITIVES, TlEntry } from '../types' import { snakeToCamel } from './utils' +export interface ReaderCodegenOptions { + /** + * Whether to include `flags` field in the result object + * @default false + */ + includeFlags?: boolean + + /** + * Name of the variable to use for the readers map + * @default 'm' + */ + variableName?: string + + /** + * Whether to include methods in the readers map + */ + includeMethods?: boolean +} + +const DEFAULT_OPTIONS: ReaderCodegenOptions = { + includeFlags: false, + variableName: 'm', + includeMethods: false, +} + /** * Generate binary reader code for a given entry. * * @param entry Entry to generate reader for - * @param includeFlags Whether to include `flags` field in the result object + * @param params Options * @returns Code as a writers map entry */ export function generateReaderCodeForTlEntry( entry: TlEntry, - includeFlags = false, + params = DEFAULT_OPTIONS, ): string { + const { variableName, includeFlags } = { ...DEFAULT_OPTIONS, ...params } + if (entry.id === 0) entry.id = computeConstructorIdFromEntry(entry) const pre = `${entry.id}:function(r){` @@ -49,20 +76,19 @@ export function generateReaderCodeForTlEntry( const argName = snakeToCamel(arg.name) - if (arg.predicate) { - const s = arg.predicate.split('.') + if (arg.typeModifiers?.predicate) { + const predicate = arg.typeModifiers.predicate + const s = predicate.split('.') const fieldName = s[0] const bitIndex = parseInt(s[1]) if (!(fieldName in flagsFields)) { throw new Error( - `Invalid predicate: ${arg.predicate} - unknown field (in ${entry.name})`, + `Invalid predicate: ${predicate} - unknown field (in ${entry.name})`, ) } if (isNaN(bitIndex) || bitIndex < 0 || bitIndex > 32) { - throw new Error( - `Invalid predicate: ${arg.predicate} - invalid bit`, - ) + throw new Error(`Invalid predicate: ${predicate} - invalid bit`) } const condition = `${fieldName}&${1 << bitIndex}` @@ -86,30 +112,39 @@ export function generateReaderCodeForTlEntry( returnCode += `${argName}:` } - let vector = false let type = arg.type - const m = type.match(/^[Vv]ector[< ](.+?)[> ]$/) - - if (m) { - vector = true - type = m[1] - } if (type in TL_PRIMITIVES) { - if (type === 'Bool') type = 'boolean' + if (type === 'Bool' || type === 'bool') type = 'boolean' } else { type = 'object' } - let code + let reader = `r.${type}` + const isBare = + arg.typeModifiers?.isBareType || arg.typeModifiers?.isBareUnion - if (vector) { - code = `r.vector(r.${type})` - } else { - code = `r.${type}()` + if (isBare) { + if (!arg.typeModifiers?.constructorId) { + throw new Error( + `Cannot generate reader for ${entry.name}#${arg.name} - no constructor id referenced`, + ) + } + + reader = `${variableName}[${arg.typeModifiers.constructorId}]` } - if (arg.predicate) { + let code + + if (arg.typeModifiers?.isVector) { + code = `r.vector(${reader})` + } else if (arg.typeModifiers?.isBareVector) { + code = `r.vector(${reader},1)` + } else { + code = `${reader}(${isBare ? 'r' : ''})` + } + + if (arg.typeModifiers?.predicate) { code += ':void 0' } @@ -127,20 +162,19 @@ export function generateReaderCodeForTlEntry( * Generate binary reader code for a given schema. * * @param entries Entries to generate reader for - * @param varName Name of the variable containing the result - * @param methods Whether to include method readers + * @param params Codegen options */ export function generateReaderCodeForTlEntries( entries: TlEntry[], - varName: string, - methods = true, + params = DEFAULT_OPTIONS, ): string { - let ret = `var ${varName}={\n` + const { variableName, includeMethods } = { ...DEFAULT_OPTIONS, ...params } + let ret = `var ${variableName}={\n` entries.forEach((entry) => { - if (entry.kind === 'method' && !methods) return + if (entry.kind === 'method' && !includeMethods) return - ret += generateReaderCodeForTlEntry(entry) + '\n' + ret += generateReaderCodeForTlEntry(entry, params) + '\n' }) return ret + '}' diff --git a/packages/tl-utils/src/codegen/types.ts b/packages/tl-utils/src/codegen/types.ts index 08142ea5..fa339c6c 100644 --- a/packages/tl-utils/src/codegen/types.ts +++ b/packages/tl-utils/src/codegen/types.ts @@ -31,11 +31,6 @@ function fullTypeName( link = false, ): string { if (type in PRIMITIVE_TO_TS) return PRIMITIVE_TO_TS[type] - let m - - if ((m = type.match(/^[Vv]ector[< ](.+?)[> ]$/))) { - return fullTypeName(m[1], baseNamespace, namespace, method, link) + '[]' - } const [ns, name] = splitNameToNamespace(type) let res = baseNamespace @@ -145,7 +140,7 @@ export function generateTypescriptDefinitionsForTlEntry( ret += ` ${snakeToCamel(arg.name)}` - if (arg.predicate) ret += '?' + if (arg.typeModifiers?.predicate) ret += '?' let type = arg.type let typeFinal = false @@ -158,6 +153,10 @@ export function generateTypescriptDefinitionsForTlEntry( if (!typeFinal) type = fullTypeName(arg.type, baseNamespace) + if (arg.typeModifiers?.isVector || arg.typeModifiers?.isBareVector) { + type += '[]' + } + ret += `: ${type};\n` }) @@ -219,7 +218,10 @@ export function generateTypescriptDefinitionsForTlSchema( namespace = 'tl', errors?: TlErrors, ): [string, string] { - let ts = PRELUDE.replace('$NS$', namespace).replace('$LAYER$', String(layer)) + let ts = PRELUDE.replace('$NS$', namespace).replace( + '$LAYER$', + String(layer), + ) let js = PRELUDE_JS.replace('$NS$', namespace).replace( '$LAYER$', String(layer), diff --git a/packages/tl-utils/src/codegen/writer.ts b/packages/tl-utils/src/codegen/writer.ts index b6cbb2c5..3f472415 100644 --- a/packages/tl-utils/src/codegen/writer.ts +++ b/packages/tl-utils/src/codegen/writer.ts @@ -2,8 +2,39 @@ import { computeConstructorIdFromEntry } from '../ctor-id' import { TL_PRIMITIVES, TlEntry } from '../types' import { snakeToCamel } from './utils' +export interface WriterCodegenOptions { + /** + * Whether to use `flags` field from the input + * @default false + */ + includeFlags?: boolean + + /** + * Name of the variable to use for the writers map + * @default 'm' + */ + variableName?: string + + /** + * Whether to include prelude code (function `h`) + */ + includePrelude?: boolean + + /** + * Whether to generate bare writer (without constructor id write) + */ + bare?: boolean +} + +const DEFAULT_OPTIONS: WriterCodegenOptions = { + includeFlags: false, + variableName: 'm', + includePrelude: true, + bare: false, +} + const TL_WRITER_PRELUDE = - 'function h(o, p){' + + 'function h(o,p){' + 'var q=o[p];' + 'if(q===void 0)' + "throw Error('Object '+o._+' is missing required property '+p);" + @@ -11,37 +42,42 @@ const TL_WRITER_PRELUDE = /** * Generate writer code for a single entry. - * `h` (has) function should be available + * `h` (has) function from the prelude should be available * * @param entry Entry to generate writer for - * @param withFlags Whether to include `flags` field in the result object + * @param params Options * @returns Code as a readers map entry */ export function generateWriterCodeForTlEntry( entry: TlEntry, - withFlags = false, + params = DEFAULT_OPTIONS, ): string { + const { bare, includeFlags, variableName } = { + ...DEFAULT_OPTIONS, + ...params, + } + if (entry.id === 0) entry.id = computeConstructorIdFromEntry(entry) - let ret = `'${entry.name}':function(w${ - entry.arguments.length ? ',v' : '' - }){` + const name = bare ? entry.id : `'${entry.name}'` + let ret = `${name}:function(w${entry.arguments.length ? ',v' : ''}){` - ret += `w.uint(${entry.id});` + if (!bare) ret += `w.uint(${entry.id});` const flagsFields: Record = {} entry.arguments.forEach((arg) => { if (arg.type === '#') { - ret += `var ${arg.name}=${withFlags ? `v.${arg.name}` : '0'};` + ret += `var ${arg.name}=${includeFlags ? `v.${arg.name}` : '0'};` entry.arguments.forEach((arg1) => { + const predicate = arg1.typeModifiers?.predicate + let s - if ( - !arg1.predicate || - (s = arg1.predicate.split('.'))[0] !== arg.name - ) { return } + if (!predicate || (s = predicate.split('.'))[0] !== arg.name) { + return + } const arg1Name = snakeToCamel(arg1.name) @@ -49,7 +85,7 @@ export function generateWriterCodeForTlEntry( if (isNaN(bitIndex) || bitIndex < 0 || bitIndex > 32) { throw new Error( - `Invalid predicate: ${arg1.predicate} - invalid bit`, + `Invalid predicate: ${predicate} - invalid bit`, ) } @@ -57,7 +93,10 @@ export function generateWriterCodeForTlEntry( if (arg1.type === 'true') { ret += `if(v.${arg1Name}===true)${action}` - } else if (arg1.type.match(/^[Vv]ector/)) { + } else if ( + arg1.typeModifiers?.isVector || + arg1.typeModifiers?.isBareVector + ) { ret += `var _${arg1Name}=v.${arg1Name}&&v.${arg1Name}.length;if(_${arg1Name})${action}` } else { ret += `var _${arg1Name}=v.${arg1Name}!==undefined;if(_${arg1Name})${action}` @@ -72,21 +111,16 @@ export function generateWriterCodeForTlEntry( 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] - } + let accessor = `v.${argName}` - if (arg.predicate) { + if (arg.typeModifiers?.predicate) { if (type === 'true') return // included in flags ret += `if(_${argName})` } else { - ret += `h(v,'${argName}');` + accessor = `h(v,'${argName}')` } if (type in TL_PRIMITIVES) { @@ -95,10 +129,26 @@ export function generateWriterCodeForTlEntry( type = 'object' } - if (vector) { - ret += `w.vector(w.${type}, v.${argName});` + let writer = `w.${type}` + const isBare = + arg.typeModifiers?.isBareType || arg.typeModifiers?.isBareUnion + + if (isBare) { + if (!arg.typeModifiers?.constructorId) { + throw new Error( + `Cannot generate writer for ${entry.name}#${arg.name} - no constructor id referenced`, + ) + } + + writer = `${variableName}._bare[${arg.typeModifiers.constructorId}]` + } + + if (arg.typeModifiers?.isVector) { + ret += `w.vector(${writer},${accessor});` + } else if (arg.typeModifiers?.isBareVector) { + ret += `w.vector(${writer},${accessor},1);` } else { - ret += `w.${type}(v.${argName});` + ret += `${writer}(${isBare ? 'w,' : ''}${accessor});` } }) @@ -109,23 +159,47 @@ export function generateWriterCodeForTlEntry( * Generate writer code for a given TL schema. * * @param entries Entries to generate writers for - * @param varName Name of the variable to use for the writers map - * @param prelude Whether to include the prelude (containing `h` function) - * @param withFlags Whether to include `flags` field in the result object + * @param params Codegen options */ export function generateWriterCodeForTlEntries( entries: TlEntry[], - varName: string, - prelude = true, - withFlags = false, + params = DEFAULT_OPTIONS, ): string { - let ret = '' - if (prelude) ret += TL_WRITER_PRELUDE - ret += `var ${varName}={\n` + const { includePrelude, variableName } = { ...DEFAULT_OPTIONS, ...params } + let ret = '' + if (includePrelude) ret += TL_WRITER_PRELUDE + ret += `var ${variableName}={\n` + + const usedAsBareIds: Record = {} entries.forEach((entry) => { - ret += generateWriterCodeForTlEntry(entry, withFlags) + '\n' + ret += generateWriterCodeForTlEntry(entry, params) + '\n' + + entry.arguments.forEach((arg) => { + if (arg.typeModifiers?.constructorId) { + usedAsBareIds[arg.typeModifiers.constructorId] = 1 + } + }) }) + if (Object.keys(usedAsBareIds).length) { + ret += '_bare:{\n' + + Object.keys(usedAsBareIds).forEach((id) => { + const entry = entries.find((e) => e.id === parseInt(id)) + + if (!entry) { + return + } + + ret += + generateWriterCodeForTlEntry(entry, { + ...params, + bare: true, + }) + '\n' + }) + ret += '}' + } + return ret + '}' } diff --git a/packages/tl-utils/src/ctor-id.ts b/packages/tl-utils/src/ctor-id.ts index e546cb99..262fda8a 100644 --- a/packages/tl-utils/src/ctor-id.ts +++ b/packages/tl-utils/src/ctor-id.ts @@ -1,5 +1,6 @@ import CRC32 from 'crc-32' +import { parseTlToEntries } from './parse' import { writeTlEntryToString } from './stringify' import { TlEntry } from './types' @@ -9,19 +10,8 @@ import { TlEntry } from './types' * @param line Line containing TL entry definition */ export function computeConstructorIdFromString(line: string): number { - return ( - CRC32.str( - // normalize - line - .replace( - /[{};]|[a-zA-Z0-9_]+:flags\.[0-9]+\?true|#[0-9a-f]{1,8}/g, - '', - ) - .replace(/[<>]/g, ' ') - .replace(/ +/g, ' ') - .replace(':bytes', ':string') - .trim(), - ) >>> 0 + return computeConstructorIdFromEntry( + parseTlToEntries(line, { forIdComputation: true })[0], ) } diff --git a/packages/tl-utils/src/diff.ts b/packages/tl-utils/src/diff.ts index 8442140b..02b7af94 100644 --- a/packages/tl-utils/src/diff.ts +++ b/packages/tl-utils/src/diff.ts @@ -7,6 +7,7 @@ import { TlFullSchema, TlSchemaDiff, } from './types' +import { stringifyArgumentType } from './utils' /** * Compute difference between two TL entries. @@ -89,17 +90,16 @@ export function generateTlEntriesDifference( name: arg.name, } - if (arg.type !== oldArg.type) { - diff.type = { - old: oldArg.type, - new: arg.type, - } - } + const argStr = stringifyArgumentType(arg.type, arg.typeModifiers) + const oldArgStr = stringifyArgumentType( + oldArg.type, + oldArg.typeModifiers, + ) - if (arg.predicate !== oldArg.predicate) { - diff.predicate = { - old: oldArg.predicate, - new: arg.predicate, + if (argStr !== oldArgStr) { + diff.type = { + old: oldArgStr, + new: argStr, } } @@ -110,7 +110,7 @@ export function generateTlEntriesDifference( } } - if (diff.type || diff.predicate || diff.comment) { + if (diff.type || diff.comment) { argsDiff.modified.push(diff) } }) diff --git a/packages/tl-utils/src/merge.ts b/packages/tl-utils/src/merge.ts index 2b5df5b8..b1640617 100644 --- a/packages/tl-utils/src/merge.ts +++ b/packages/tl-utils/src/merge.ts @@ -33,10 +33,10 @@ export function mergeTlEntries(entries: TlEntry[]): TlEntry | string { if (arg.type === '#') { flagsLastIndex[arg.name] = idx } - if (arg.predicate) { - const flagsField = arg.predicate.split('.')[0] - flagsLastIndex[flagsField] = idx - } + // if (arg.predicate) { + // const flagsField = arg.predicate.split('.')[0] + // flagsLastIndex[flagsField] = idx + // } }) for (let i = 1; i < entries.length; i++) { @@ -55,7 +55,9 @@ export function mergeTlEntries(entries: TlEntry[]): TlEntry | string { result.name !== entry.name || result.type !== entry.type || result.id !== ctorId - ) { return 'basic info mismatch' } + ) { + return 'basic info mismatch' + } // since we re-calculated id manually, we can skip checking // generics and arguments, and get straight to merging @@ -72,13 +74,14 @@ export function mergeTlEntries(entries: TlEntry[]): TlEntry | string { // yay a new arg // we can only add optional true args, since any others will change id // ids match, so this must be the case - if (!entryArgument.predicate) { + if (!entryArgument.typeModifiers?.predicate) { throw new Error('new argument is not optional') } // we also need to make sure we put it *after* the respective flags field - const flagsField = entryArgument.predicate.split('.')[0] + const flagsField = + entryArgument.typeModifiers.predicate.split('.')[0] const targetIdx = flagsLastIndex[flagsField] // targetIdx *must* exist, otherwise ids wouldn't match diff --git a/packages/tl-utils/src/parse.ts b/packages/tl-utils/src/parse.ts index ec29c826..6ad1594c 100644 --- a/packages/tl-utils/src/parse.ts +++ b/packages/tl-utils/src/parse.ts @@ -1,19 +1,10 @@ import { computeConstructorIdFromString } from './ctor-id' -import { TL_PRIMITIVES, TlEntry } from './types' -import { parseTdlibStyleComment } from './utils' +import { TL_PRIMITIVES, TlArgument, TlEntry } from './types' +import { parseArgumentType, parseTdlibStyleComment } from './utils' const SINGLE_REGEX = /^(.+?)(?:#([0-9a-f]{1,8}))?(?: \?)?(?: {(.+?:.+?)})? ((?:.+? )*)= (.+);$/ -function applyPrefix(prefix: string, type: string): string { - if (type in TL_PRIMITIVES) return type - - const m = type.match(/^[Vv]ector[< ](.+?)[> ]$/) - if (m) return `Vector<${applyPrefix(prefix, m[1])}>` - - return prefix + type -} - /** * Parse TL schema into a list of entries. * @@ -50,13 +41,17 @@ export function parseTlToEntries( prefix?: string /** - * Whether to apply the prefix to arguments as well + * Whether this invocation is for computing constructor ids. + * If true, the `id` field will be set to 0 for all entries. */ - applyPrefixToArguments?: boolean + forIdComputation?: boolean }, ): TlEntry[] { const ret: TlEntry[] = [] + const entries: Record = {} + const unions: Record = {} + const lines = tl.split('\n') let currentKind: TlEntry['kind'] = 'class' @@ -124,9 +119,11 @@ export function parseTlToEntries( return } - const typeIdNum = typeId ? - parseInt(typeId, 16) : - computeConstructorIdFromString(line) + let typeIdNum = typeId ? parseInt(typeId, 16) : 0 + + if (typeIdNum === 0 && !params?.forIdComputation) { + typeIdNum = computeConstructorIdFromString(line) + } const argsParsed = args && !args.match(/\[ [a-z]+ ]/i) ? @@ -138,7 +135,7 @@ export function parseTlToEntries( const entry: TlEntry = { kind: currentKind, - name: prefix + typeName, + name: typeName, id: typeIdNum, type, arguments: [], @@ -153,31 +150,18 @@ export function parseTlToEntries( } if (argsParsed.length) { - argsParsed.forEach(([name, typ]) => { - let [predicate, type] = typ.split('?') - - if (!type) { - // no predicate, `predicate` is the type - - if (params?.applyPrefixToArguments) { - predicate = applyPrefix(prefix, predicate) - } - entry.arguments.push({ - name, - type: predicate, - }) - } else { - // there is a predicate - - if (params?.applyPrefixToArguments) { - type = applyPrefix(prefix, type) - } - entry.arguments.push({ - name, - type, - predicate, - }) + argsParsed.forEach(([name, type_]) => { + const [type, modifiers] = parseArgumentType(type_) + const item: TlArgument = { + name, + type, } + + if (Object.keys(modifiers).length) { + item.typeModifiers = modifiers + } + + entry.arguments.push(item) }) } @@ -201,11 +185,59 @@ export function parseTlToEntries( } ret.push(entry) + entries[entry.name] = entry + + if (entry.kind === 'class') { + if (!unions[entry.type]) unions[entry.type] = [] + unions[entry.type].push(entry) + } }) if (currentComment && params?.onOrphanComment) { params.onOrphanComment(currentComment) } + // post-process: + // - find arguments where type is not a union and put corresponding modifiers + // - apply prefix + ret.forEach((entry, entryIdx) => { + entry.arguments.forEach((arg) => { + const type = arg.type + + if (type in TL_PRIMITIVES) { + return + } + + if (type in unions && arg.typeModifiers?.isBareUnion) { + if (unions[type].length !== 1) { + const err = new Error( + `Union ${type} has more than one entry, cannot use it like %${type} (found in ${entry.name}#${arg.name})`, + ) + + if (params?.panicOnError) { + throw err + } else if (params?.onError) { + params.onError(err, '', entryIdx) + } else { + console.warn(err) + } + } + arg.typeModifiers.constructorId = unions[type][0].id + } else if (type in entries) { + if (!arg.typeModifiers) arg.typeModifiers = {} + arg.typeModifiers.isBareType = true + arg.typeModifiers.constructorId = entries[type].id + + if (prefix) { + arg.type = prefix + arg.type + } + } + }) + + if (prefix) { + entry.name = prefix + entry.name + } + }) + return ret } diff --git a/packages/tl-utils/src/patch.ts b/packages/tl-utils/src/patch.ts index f6123a9b..a995560c 100644 --- a/packages/tl-utils/src/patch.ts +++ b/packages/tl-utils/src/patch.ts @@ -29,11 +29,21 @@ export function patchRuntimeTlSchema( } { const entries = parseTlToEntries(schema) - const readersCode = generateReaderCodeForTlEntries(entries, '_', false) - const writersCode = generateWriterCodeForTlEntries(entries, '_', true) + const readersCode = generateReaderCodeForTlEntries(entries, { + variableName: '_', + includeMethods: false, + }) + const writersCode = generateWriterCodeForTlEntries(entries, { + variableName: '_', + includePrelude: true, + }) - const newReaders = evalForResult(readersCode.replace('var _=', 'return')) - const newWriters = evalForResult(writersCode.replace('var _=', 'return')) + const newReaders = evalForResult( + readersCode.replace('var _=', 'return'), + ) + const newWriters = evalForResult( + writersCode.replace('var _=', 'return'), + ) return { readerMap: { diff --git a/packages/tl-utils/src/stringify.ts b/packages/tl-utils/src/stringify.ts index 419b2f21..a187984b 100644 --- a/packages/tl-utils/src/stringify.ts +++ b/packages/tl-utils/src/stringify.ts @@ -1,4 +1,5 @@ import { TlEntry } from './types' +import { stringifyArgumentType } from './utils' function normalizeType(s: string): string { return s @@ -39,18 +40,22 @@ export function writeTlEntryToString( } for (const arg of entry.arguments) { - if (forIdComputation && arg.predicate && arg.type === 'true') continue + if ( + forIdComputation && + arg.typeModifiers?.predicate && + arg.type === 'true' + ) { + continue + } str += arg.name + ':' - if (arg.predicate) { - str += arg.predicate + '?' - } + const type = stringifyArgumentType(arg.type, arg.typeModifiers) if (forIdComputation) { - str += normalizeType(arg.type) + ' ' + str += normalizeType(type) + ' ' } else { - str += arg.type + ' ' + str += type + ' ' } } diff --git a/packages/tl-utils/src/types.ts b/packages/tl-utils/src/types.ts index af423ba2..48b0a4fa 100644 --- a/packages/tl-utils/src/types.ts +++ b/packages/tl-utils/src/types.ts @@ -1,3 +1,62 @@ +/** + * Modifiers for {@link TlArgument.type} + */ +export interface TlArgumentModifiers { + /** + * Predicate of the argument + * @example `flags.3` + */ + predicate?: string + + /** + * Whether `type` is in fact a `Vector` + * @example `type=long, isVector=true => Vector + */ + isVector?: boolean + + /** + * Whether `type` is in fact a `vector` (a bare vector, not to be confused with `Vector`). + * + * The difference between `Vector` and `vector` is that in the latter case + * constructor ID of the vector itself (1cb5c415) is omitted + * + * @example `type=long, isVector=false, isBareVector=true => vector + */ + isBareVector?: boolean + + /** + * Whether `type` is in fact a "bare" type (a %-prefixed type) from within a union. + * + * The difference between `T` and `%T` is that in the latter case + * constructor ID of `T` is omitted. + * + * Note: If there are more than 1 types within that union, this syntax is not valid. + * + * @example `type=Message, isBare=true => %Message + */ + isBareUnion?: boolean + + /** + * Whether `type` is in fact a "bare" type (a %-prefixed type) + * + * The difference between `T` and `%T` is that in the latter case + * constructor ID of `T` is omitted. + * + * The difference with {@link isBareUnion} is in the kind of `type`. + * For {@link isBareUnion}, `type` is a name of a union (e.g. `Message`), + * for {@link isBareType} it is a name of a type (e.g. `message`). + */ + isBareType?: boolean + + /** + * For simplicity, when {@link isBareUnion} or {@link isBareType} is true, + * this field contains the constructor ID of the type being referenced. + * + * May still be undefined if the constructor ID is not known. + */ + constructorId?: number +} + /** * An argument of a TL entry */ @@ -8,15 +67,14 @@ export interface TlArgument { name: string /** - * Type of the argument + * Type of the argument. Usually a name of a Union, but not always */ type: string /** - * Predicate of the argument - * @example `flags.3` + * Modifiers for {@link type} */ - predicate?: string + typeModifiers?: TlArgumentModifiers /** * Comment of the argument @@ -268,11 +326,6 @@ export interface TlArgumentDiff { */ type?: PropertyDiff - /** - * Predicate of the argument diff - */ - predicate?: PropertyDiff - /** * Comment of the argument diff */ diff --git a/packages/tl-utils/src/utils.ts b/packages/tl-utils/src/utils.ts index 5217ec76..0df9c9d1 100644 --- a/packages/tl-utils/src/utils.ts +++ b/packages/tl-utils/src/utils.ts @@ -1,4 +1,4 @@ -import { TlEntry } from './types' +import { TlArgumentModifiers, TlEntry } from './types' /** * Split qualified TL entry name into namespace and name @@ -60,3 +60,43 @@ export function groupTlEntriesByNamespace( return ret } + +export function stringifyArgumentType( + type: string, + modifiers?: TlArgumentModifiers, +) { + if (!modifiers) return type + let ret = type + + if (modifiers?.isBareUnion) ret = `%${ret}` + if (modifiers?.isVector) ret = `Vector<${ret}>` + else if (modifiers?.isBareVector) ret = `vector<${ret}>` + if (modifiers.predicate) ret = `${modifiers.predicate}?${ret}` + + return ret +} + +export function parseArgumentType(type: string): [string, TlArgumentModifiers] { + const modifiers: TlArgumentModifiers = {} + const [predicate, type_] = type.split('?') + + if (type_) { + modifiers.predicate = predicate + type = type_ + } + + if (type.startsWith('Vector<')) { + modifiers.isVector = true + type = type.substring(7, type.length - 1) + } else if (type.startsWith('vector<') || type.startsWith('%vector<')) { + modifiers.isBareVector = true + type = type.substring(7, type.length - 1) + } + + if (type.startsWith('%')) { + modifiers.isBareUnion = true + type = type.substring(1) + } + + return [type, modifiers] +} diff --git a/packages/tl-utils/tests/codegen/reader.spec.ts b/packages/tl-utils/tests/codegen/reader.spec.ts index f70b28f1..d735d0ac 100644 --- a/packages/tl-utils/tests/codegen/reader.spec.ts +++ b/packages/tl-utils/tests/codegen/reader.spec.ts @@ -1,12 +1,11 @@ import { expect } from 'chai' import { describe, it } from 'mocha' -import { generateReaderCodeForTlEntry } from '../../src/codegen/reader' -import { parseTlToEntries } from '../../src/parse' +import { generateReaderCodeForTlEntry, parseTlToEntries } from '../../src' describe('generateReaderCodeForTlEntry', () => { const test = (tl: string, ...js: string[]) => { - const entry = parseTlToEntries(tl)[0] + const entry = parseTlToEntries(tl).slice(-1)[0] expect(generateReaderCodeForTlEntry(entry)).eq( `${entry.id}:function(r){${js.join('')}},`, ) @@ -139,9 +138,38 @@ describe('generateReaderCodeForTlEntry', () => { ) }) + it('generates code for bare types', () => { + test( + 'message#0949d9dc = Message;\n' + + 'msg_container#73f1f8dc messages:vector<%Message> = MessageContainer;', + 'return{', + "_:'msg_container',", + 'messages:r.vector(m[155834844],1),', + '}', + ) + test( + 'future_salt#0949d9dc = FutureSalt;\n' + + 'future_salts#ae500895 salts:Vector current:FutureSalt = FutureSalts;', + 'return{', + "_:'future_salts',", + 'salts:r.vector(m[155834844]),', + 'current:r.object(),', + '}', + ) + test( + 'future_salt#0949d9dc = FutureSalt;\n' + + 'future_salts#ae500895 salts:vector current:future_salt = FutureSalts;', + 'return{', + "_:'future_salts',", + 'salts:r.vector(m[155834844],1),', + 'current:m[155834844](r),', + '}', + ) + }) + it('generates code with raw flags for constructors with flags', () => { const entry = parseTlToEntries('test flags:# flags2:# = Test;')[0] - expect(generateReaderCodeForTlEntry(entry, true)).eq( + expect(generateReaderCodeForTlEntry(entry, { includeFlags: true })).eq( `${entry.id}:function(r){${[ 'var flags=r.uint(),', 'flags2=r.uint();', diff --git a/packages/tl-utils/tests/codegen/types.spec.ts b/packages/tl-utils/tests/codegen/types.spec.ts index 3a215359..1f9f09b3 100644 --- a/packages/tl-utils/tests/codegen/types.spec.ts +++ b/packages/tl-utils/tests/codegen/types.spec.ts @@ -4,9 +4,9 @@ import { describe, it } from 'mocha' import { generateTypescriptDefinitionsForTlEntry, generateTypescriptDefinitionsForTlSchema, -} from '../../src/codegen/types' -import { parseTlToEntries } from '../../src/parse' -import { parseFullTlSchema } from '../../src/schema' + parseFullTlSchema, + parseTlToEntries, +} from '../../src' describe('generateTypescriptDefinitionsForTlEntry', () => { const test = (tl: string, ...ts: string[]) => { @@ -112,7 +112,7 @@ describe('generateTypescriptDefinitionsForTlEntry', () => { it('wraps long comments', () => { test( '// This is a test constructor with a very very very very very very very very long comment\n' + - 'test = Test;', + 'test = Test;', '/**', ' * This is a test constructor with a very very very very very', ' * very very very long comment', @@ -124,8 +124,8 @@ describe('generateTypescriptDefinitionsForTlEntry', () => { test( '---functions---\n' + - '// This is a test method with a very very very very very very very very long comment\n' + - 'test = Test;', + '// This is a test method with a very very very very very very very very long comment\n' + + 'test = Test;', '/**', ' * This is a test method with a very very very very very very', ' * very very long comment', @@ -141,7 +141,7 @@ describe('generateTypescriptDefinitionsForTlEntry', () => { it('should not break @link tags', () => { test( '// This is a test constructor with a very long comment {@link whatever} more text\n' + - 'test = Test;', + 'test = Test;', '/**', ' * This is a test constructor with a very long comment', ' * {@link whatever} more text', @@ -156,7 +156,7 @@ describe('generateTypescriptDefinitionsForTlEntry', () => { it('writes generic types', () => { test( '---functions---\ninvokeWithoutUpdates#bf9459b7 {X:Type} query:!X = X;', - 'interface RawInvokeWithoutUpdatesRequest {', + 'interface RawInvokeWithoutUpdatesRequest {', " _: 'invokeWithoutUpdates';", ' query: X;', '}', diff --git a/packages/tl-utils/tests/codegen/writer.spec.ts b/packages/tl-utils/tests/codegen/writer.spec.ts index c284fe23..0712048a 100644 --- a/packages/tl-utils/tests/codegen/writer.spec.ts +++ b/packages/tl-utils/tests/codegen/writer.spec.ts @@ -1,12 +1,15 @@ import { expect } from 'chai' import { describe, it } from 'mocha' -import { generateWriterCodeForTlEntry } from '../../src/codegen/writer' -import { parseTlToEntries } from '../../src/parse' +import { + generateWriterCodeForTlEntries, + generateWriterCodeForTlEntry, + parseTlToEntries, +} from '../../src' describe('generateWriterCodeForTlEntry', () => { const test = (tl: string, ...js: string[]) => { - const entry = parseTlToEntries(tl)[0] + const entry = parseTlToEntries(tl).slice(-1)[0] expect(generateWriterCodeForTlEntry(entry)).eq( `'${entry.name}':function(w${ entry.arguments.length ? ',v' : '' @@ -21,30 +24,21 @@ describe('generateWriterCodeForTlEntry', () => { it('generates code for constructors with simple arguments', () => { test( 'inputBotInlineMessageID#890c3d89 dc_id:int id:long access_hash:long = InputBotInlineMessageID;', - "h(v,'dcId');", - 'w.int(v.dcId);', - "h(v,'id');", - 'w.long(v.id);', - "h(v,'accessHash');", - 'w.long(v.accessHash);', + "w.int(h(v,'dcId'));", + "w.long(h(v,'id'));", + "w.long(h(v,'accessHash'));", ) test( 'contact#145ade0b user_id:long mutual:Bool = Contact;', - "h(v,'userId');", - 'w.long(v.userId);', - "h(v,'mutual');", - 'w.boolean(v.mutual);', + "w.long(h(v,'userId'));", + "w.boolean(h(v,'mutual'));", ) test( 'maskCoords#aed6dbb2 n:int x:double y:double zoom:double = MaskCoords;', - "h(v,'n');", - 'w.int(v.n);', - "h(v,'x');", - 'w.double(v.x);', - "h(v,'y');", - 'w.double(v.y);', - "h(v,'zoom');", - 'w.double(v.zoom);', + "w.int(h(v,'n'));", + "w.double(h(v,'x'));", + "w.double(h(v,'y'));", + "w.double(h(v,'zoom'));", ) }) @@ -65,8 +59,7 @@ describe('generateWriterCodeForTlEntry', () => { 'var _timeout=v.timeout!==undefined;', 'if(_timeout)flags|=2;', 'w.uint(flags);', - "h(v,'pts');", - 'w.int(v.pts);', + "w.int(h(v,'pts'));", 'if(_timeout)w.int(v.timeout);', ) }) @@ -79,8 +72,7 @@ describe('generateWriterCodeForTlEntry', () => { 'var _timeout=v.timeout!==undefined;', 'if(_timeout)flags|=2;', 'w.uint(flags);', - "h(v,'pts');", - 'w.int(v.pts);', + "w.int(h(v,'pts'));", 'if(_timeout)w.int(v.timeout);', 'var flags2=0;', 'if(v.canDeleteChannel===true)flags2|=1;', @@ -91,12 +83,9 @@ describe('generateWriterCodeForTlEntry', () => { it('generates code for constructors with vector arguments', () => { test( 'contacts.resolvedPeer#7f077ad9 peer:Peer chats:Vector users:Vector = contacts.ResolvedPeer;', - "h(v,'peer');", - 'w.object(v.peer);', - "h(v,'chats');", - 'w.vector(w.object, v.chats);', - "h(v,'users');", - 'w.vector(w.object, v.users);', + "w.object(h(v,'peer'));", + "w.vector(w.object,h(v,'chats'));", + "w.vector(w.object,h(v,'users'));", ) }) @@ -107,25 +96,55 @@ describe('generateWriterCodeForTlEntry', () => { 'var _entities=v.entities&&v.entities.length;', 'if(_entities)flags|=8;', 'w.uint(flags);', - "h(v,'message');", - 'w.string(v.message);', - 'if(_entities)w.vector(w.object, v.entities);', + "w.string(h(v,'message'));", + 'if(_entities)w.vector(w.object,v.entities);', ) }) it('generates code for constructors with generics', () => { test( 'invokeWithLayer#da9b0d0d {X:Type} layer:int query:!X = X;', - "h(v,'layer');", - 'w.int(v.layer);', - "h(v,'query');", - 'w.object(v.query);', + "w.int(h(v,'layer'));", + "w.object(h(v,'query'));", + ) + }) + + it('generates code for bare vectors', () => { + test( + 'message#0949d9dc = Message;\n' + + 'msg_container#73f1f8dc messages:vector<%Message> = MessageContainer;', + "w.vector(m._bare[155834844],h(v,'messages'),1);", + ) + test( + 'future_salt#0949d9dc = FutureSalt;\n' + + 'future_salts#ae500895 salts:Vector current:FutureSalt = FutureSalts;', + "w.vector(m._bare[155834844],h(v,'salts'));", + "w.object(h(v,'current'));", + ) + }) + + it('generates code for bare types', () => { + const entries = parseTlToEntries( + 'future_salt#0949d9dc salt:bytes = FutureSalt;\n' + + 'future_salts#ae500895 salts:vector current:future_salt = FutureSalts;', + ) + + expect( + generateWriterCodeForTlEntries(entries, { includePrelude: false }), + ).eq( + ` + var m={ + 'future_salt':function(w,v){w.uint(155834844);w.bytes(h(v,'salt'));}, + 'future_salts':function(w,v){w.uint(2924480661);w.vector(m._bare[155834844],h(v,'salts'),1);m._bare[155834844](w,h(v,'current'));}, + _bare:{ + 155834844:function(w,v){w.bytes(h(v,'salt'));}, + }}`.replace(/^\s+/gm, ''), ) }) it('generates code with raw flags for constructors with flags', () => { const entry = parseTlToEntries('test flags:# flags2:# = Test;')[0] - expect(generateWriterCodeForTlEntry(entry, true)).eq( + expect(generateWriterCodeForTlEntry(entry, { includeFlags: true })).eq( `'${entry.name}':function(w,v){${[ `w.uint(${entry.id});`, 'var flags=v.flags;', diff --git a/packages/tl-utils/tests/ctor-id.spec.ts b/packages/tl-utils/tests/ctor-id.spec.ts index 5922879c..342d9df3 100644 --- a/packages/tl-utils/tests/ctor-id.spec.ts +++ b/packages/tl-utils/tests/ctor-id.spec.ts @@ -4,8 +4,9 @@ import { describe, it } from 'mocha' import { computeConstructorIdFromEntry, computeConstructorIdFromString, -} from '../src/ctor-id' -import { TlEntry } from '../src/types' + TlArgument, + TlEntry, +} from '../src' describe('computeConstructorIdFromString', () => { const test = (tl: string, expected: number) => { @@ -75,8 +76,10 @@ describe('computeConstructorIdFromEntry', () => { return { name: a[0], type: t[1], - predicate: t[0], - } + typeModifiers: { + predicate: t[0], + }, + } satisfies TlArgument } return { diff --git a/packages/tl-utils/tests/diff.spec.ts b/packages/tl-utils/tests/diff.spec.ts index 53d6a174..d159a1b6 100644 --- a/packages/tl-utils/tests/diff.spec.ts +++ b/packages/tl-utils/tests/diff.spec.ts @@ -99,9 +99,9 @@ describe('generateTlEntriesDifference', () => { }, { name: 'egg', - predicate: { - old: 'flags.0', - new: 'flags.1', + type: { + old: 'flags.0?Egg', + new: 'flags.1?Egg', }, }, ], diff --git a/packages/tl-utils/tests/merge.spec.ts b/packages/tl-utils/tests/merge.spec.ts index 60d5e399..5eb28f83 100644 --- a/packages/tl-utils/tests/merge.spec.ts +++ b/packages/tl-utils/tests/merge.spec.ts @@ -44,18 +44,19 @@ describe('mergeTlEntries', () => { 'test flags:# baz:flags.1?true = Test;', 'test#e86481ba flags:# foo:flags.0?true bar:flags.0?true baz:flags.1?true = Test;', ) + // ordering of optional flags should not matter test( 'test flags:# foo:flags.0?true = Test;\n' + 'test flags:# bar:flags.0?true = Test;\n' + 'test flags:# baz:flags.1?true = Test;', - 'test#e86481ba flags:# foo:flags.0?true bar:flags.0?true baz:flags.1?true = Test;', + 'test#e86481ba flags:# bar:flags.0?true baz:flags.1?true foo:flags.0?true = Test;', ) test( 'test flags:# foo:flags.0?true = Test;\n' + 'test flags:# foo:flags.0?true bar:flags.0?true = Test;\n' + 'test flags:# baz:flags.1?true = Test;\n' + 'test flags:# bar:flags.0?true baz:flags.1?true = Test;', - 'test#e86481ba flags:# foo:flags.0?true bar:flags.0?true baz:flags.1?true = Test;', + 'test#e86481ba flags:# bar:flags.0?true baz:flags.1?true foo:flags.0?true = Test;', ) }) diff --git a/packages/tl-utils/tests/parse.spec.ts b/packages/tl-utils/tests/parse.spec.ts index 34960aa1..28e193c5 100644 --- a/packages/tl-utils/tests/parse.spec.ts +++ b/packages/tl-utils/tests/parse.spec.ts @@ -1,12 +1,15 @@ import { expect } from 'chai' import { describe, it } from 'mocha' -import { parseTlToEntries } from '../src/parse' -import { TlEntry } from '../src/types' +import { parseTlToEntries, TlEntry } from '../src' describe('tl parser', () => { - const test = (tl: string, expected: TlEntry[]) => { - expect(parseTlToEntries(tl)).eql(expected) + const test = ( + tl: string, + expected: TlEntry[], + params?: Parameters[1], + ) => { + expect(parseTlToEntries(tl, params)).eql(expected) } it('skips empty lines and comments', () => { @@ -69,6 +72,132 @@ boolTrue#997275b5 = Bool; ]) }) + it('parses vectors', () => { + test('msg_resend_req#7d861a08 msg_ids:Vector = MsgResendReq;', [ + { + kind: 'class', + name: 'msg_resend_req', + id: 0x7d861a08, + type: 'MsgResendReq', + arguments: [ + { + name: 'msg_ids', + type: 'long', + typeModifiers: { + isVector: true, + }, + }, + ], + }, + ]) + }) + + it('parses bare vectors', () => { + // note: not from schema, schema uses bare `future_salt` instead + test( + 'future_salts#ae500895 req_msg_id:long now:int salts:vector = FutureSalts;', + [ + { + kind: 'class', + name: 'future_salts', + id: 0xae500895, + type: 'FutureSalts', + arguments: [ + { + name: 'req_msg_id', + type: 'long', + }, + { + name: 'now', + type: 'int', + }, + { + name: 'salts', + type: 'FutureSalt', + typeModifiers: { + isBareVector: true, + }, + }, + ], + }, + ], + ) + }) + + it('parses bare unions', () => { + test( + 'message#0949d9dc = Message;\n' + // stub so we can reference it + 'msg_container#73f1f8dc messages:vector<%Message> = MessageContainer;', + [ + { + kind: 'class', + name: 'message', + id: 0x0949d9dc, + type: 'Message', + arguments: [], + }, + { + kind: 'class', + name: 'msg_container', + id: 0x73f1f8dc, + type: 'MessageContainer', + arguments: [ + { + name: 'messages', + type: 'Message', + typeModifiers: { + isBareVector: true, + isBareUnion: true, + constructorId: 0x0949d9dc, + }, + }, + ], + }, + ], + ) + }) + + it('parses bare types', () => { + test( + 'future_salt#0949d9dc = FutureSalt;\n' + // stub so we can reference it + 'future_salts#ae500895 req_msg_id:long now:int salts:vector = FutureSalts;', + [ + { + kind: 'class', + name: 'future_salt', + id: 0x0949d9dc, + type: 'FutureSalt', + arguments: [], + }, + { + kind: 'class', + name: 'future_salts', + id: 0xae500895, + type: 'FutureSalts', + arguments: [ + { + name: 'req_msg_id', + type: 'long', + }, + { + name: 'now', + type: 'int', + }, + { + name: 'salts', + type: 'future_salt', + typeModifiers: { + isBareVector: true, + isBareType: true, + constructorId: 0x0949d9dc, + }, + }, + ], + }, + ], + ) + }) + it('parses methods with arguments', () => { test( '---functions---\nauth.exportAuthorization#e5bfffcd dc_id:int = auth.ExportedAuthorization;', @@ -148,7 +277,7 @@ boolTrue#997275b5 = Bool; it('parses predicates', () => { test( - 'help.promoData#8c39793f flags:# proxy:flags.0?true expires:int peer:Peer chats:Vector users:Vector psa_type:flags.1?string psa_message:flags.2?string = help.PromoData;', + 'help.promoData#8c39793f flags:# proxy:flags.0?true expires:int peer:Peer psa_type:flags.1?string psa_message:flags.2?string = help.PromoData;', [ { kind: 'class', @@ -163,7 +292,9 @@ boolTrue#997275b5 = Bool; { name: 'proxy', type: 'true', - predicate: 'flags.0', + typeModifiers: { + predicate: 'flags.0', + }, }, { name: 'expires', @@ -173,23 +304,19 @@ boolTrue#997275b5 = Bool; name: 'peer', type: 'Peer', }, - { - name: 'chats', - type: 'Vector', - }, - { - name: 'users', - type: 'Vector', - }, { name: 'psa_type', type: 'string', - predicate: 'flags.1', + typeModifiers: { + predicate: 'flags.1', + }, }, { name: 'psa_message', type: 'string', - predicate: 'flags.2', + typeModifiers: { + predicate: 'flags.2', + }, }, ], }, @@ -299,4 +426,42 @@ users.getUsers id:Vector = Vector; 'yet another at the end', ]) }) + + it('applies prefix to constructors', () => { + test( + 'future_salt#0949d9dc = FutureSalt;\n' + // stub to reference + 'future_salts#ae500895 salts:vector current:FutureSalt = FutureSalts;', + [ + { + kind: 'class', + name: 'mt_future_salt', + id: 0x0949d9dc, + type: 'FutureSalt', + arguments: [], + }, + { + kind: 'class', + name: 'mt_future_salts', + id: 0xae500895, + type: 'FutureSalts', + arguments: [ + { + name: 'salts', + type: 'mt_future_salt', + typeModifiers: { + isBareVector: true, + isBareType: true, + constructorId: 0x0949d9dc, + }, + }, + { + name: 'current', + type: 'FutureSalt', // prefix is not applied to non-constructors + }, + ], + }, + ], + { prefix: 'mt_' }, + ) + }) }) diff --git a/packages/tl-utils/tests/stringify.spec.ts b/packages/tl-utils/tests/stringify.spec.ts index bbf13885..a0e82cc2 100644 --- a/packages/tl-utils/tests/stringify.spec.ts +++ b/packages/tl-utils/tests/stringify.spec.ts @@ -2,7 +2,7 @@ import { expect } from 'chai' import { describe, it } from 'mocha' import { writeTlEntryToString } from '../src/stringify' -import { TlEntry } from '../src/types' +import { TlArgument, TlEntry } from '../src/types' describe('writeTlEntryToString', () => { const make = (name: string, type: string, ...args: string[]): TlEntry => ({ @@ -18,14 +18,16 @@ describe('writeTlEntryToString', () => { return { name: a[0], type: t[1], - predicate: t[0], - } + typeModifiers: { + predicate: t[0], + }, + } satisfies TlArgument } return { name: a[0], type: t[0], - } + } satisfies TlArgument }), }) diff --git a/packages/tl/data/int53-overrides.json b/packages/tl/data/int53-overrides.json index 8f71ada0..f634d8d8 100644 --- a/packages/tl/data/int53-overrides.json +++ b/packages/tl/data/int53-overrides.json @@ -1,7 +1,8 @@ { "What is this?": [ "It is guaranteed that user/chat/channel ids fit in int53,", - "so we can safely replace `long` with `int53` there.", + "as well as file size (up to 4 gigs),", + "so we can safely replace `long` with `int53` for simpler usage from within JS.", "Note: this is a non-exhaustive list", "When contributing, please maintain alphabetical key ordering" ], diff --git a/packages/tl/mtp-schema.json b/packages/tl/mtp-schema.json index 7fec7cda..43199247 100644 --- a/packages/tl/mtp-schema.json +++ b/packages/tl/mtp-schema.json @@ -1 +1 @@ -[{"kind":"class","name":"mt_resPQ","id":85337187,"type":"ResPQ","arguments":[{"name":"nonce","type":"int128"},{"name":"server_nonce","type":"int128"},{"name":"pq","type":"bytes"},{"name":"server_public_key_fingerprints","type":"Vector"}]},{"kind":"class","name":"mt_p_q_inner_data_dc","id":2851430293,"type":"P_Q_inner_data","arguments":[{"name":"pq","type":"bytes"},{"name":"p","type":"bytes"},{"name":"q","type":"bytes"},{"name":"nonce","type":"int128"},{"name":"server_nonce","type":"int128"},{"name":"new_nonce","type":"int256"},{"name":"dc","type":"int"}]},{"kind":"class","name":"mt_p_q_inner_data_temp_dc","id":1459478408,"type":"P_Q_inner_data","arguments":[{"name":"pq","type":"bytes"},{"name":"p","type":"bytes"},{"name":"q","type":"bytes"},{"name":"nonce","type":"int128"},{"name":"server_nonce","type":"int128"},{"name":"new_nonce","type":"int256"},{"name":"dc","type":"int"},{"name":"expires_in","type":"int"}]},{"kind":"class","name":"mt_server_DH_params_ok","id":3504867164,"type":"Server_DH_Params","arguments":[{"name":"nonce","type":"int128"},{"name":"server_nonce","type":"int128"},{"name":"encrypted_answer","type":"bytes"}]},{"kind":"class","name":"mt_server_DH_inner_data","id":3045658042,"type":"Server_DH_inner_data","arguments":[{"name":"nonce","type":"int128"},{"name":"server_nonce","type":"int128"},{"name":"g","type":"int"},{"name":"dh_prime","type":"bytes"},{"name":"g_a","type":"bytes"},{"name":"server_time","type":"int"}]},{"kind":"class","name":"mt_client_DH_inner_data","id":1715713620,"type":"Client_DH_Inner_Data","arguments":[{"name":"nonce","type":"int128"},{"name":"server_nonce","type":"int128"},{"name":"retry_id","type":"long"},{"name":"g_b","type":"bytes"}]},{"kind":"class","name":"mt_dh_gen_ok","id":1003222836,"type":"Set_client_DH_params_answer","arguments":[{"name":"nonce","type":"int128"},{"name":"server_nonce","type":"int128"},{"name":"new_nonce_hash1","type":"int128"}]},{"kind":"class","name":"mt_dh_gen_retry","id":1188831161,"type":"Set_client_DH_params_answer","arguments":[{"name":"nonce","type":"int128"},{"name":"server_nonce","type":"int128"},{"name":"new_nonce_hash2","type":"int128"}]},{"kind":"class","name":"mt_dh_gen_fail","id":2795351554,"type":"Set_client_DH_params_answer","arguments":[{"name":"nonce","type":"int128"},{"name":"server_nonce","type":"int128"},{"name":"new_nonce_hash3","type":"int128"}]},{"kind":"class","name":"mt_bind_auth_key_inner","id":1973679973,"type":"BindAuthKeyInner","arguments":[{"name":"nonce","type":"long"},{"name":"temp_auth_key_id","type":"long"},{"name":"perm_auth_key_id","type":"long"},{"name":"temp_session_id","type":"long"},{"name":"expires_at","type":"int"}]},{"kind":"class","name":"mt_rpc_result","id":4082920705,"type":"RpcResult","arguments":[{"name":"req_msg_id","type":"long"},{"name":"result","type":"any"}]},{"kind":"class","name":"mt_rpc_error","id":558156313,"type":"RpcError","arguments":[{"name":"error_code","type":"int"},{"name":"error_message","type":"string"}]},{"kind":"class","name":"mt_rpc_answer_unknown","id":1579864942,"type":"RpcDropAnswer","arguments":[]},{"kind":"class","name":"mt_rpc_answer_dropped_running","id":3447252358,"type":"RpcDropAnswer","arguments":[]},{"kind":"class","name":"mt_rpc_answer_dropped","id":2755319991,"type":"RpcDropAnswer","arguments":[{"name":"msg_id","type":"long"},{"name":"seq_no","type":"int"},{"name":"bytes","type":"int"}]},{"kind":"class","name":"mt_future_salt","id":155834844,"type":"FutureSalt","arguments":[{"name":"valid_since","type":"int"},{"name":"valid_until","type":"int"},{"name":"salt","type":"long"}]},{"kind":"class","name":"mt_future_salts","id":2924480661,"type":"FutureSalts","arguments":[{"name":"req_msg_id","type":"long"},{"name":"now","type":"int"},{"name":"salts","type":"Vector"}]},{"kind":"class","name":"mt_pong","id":880243653,"type":"Pong","arguments":[{"name":"msg_id","type":"long"},{"name":"ping_id","type":"long"}]},{"kind":"class","name":"mt_destroy_session_ok","id":3793765884,"type":"DestroySessionRes","arguments":[{"name":"session_id","type":"long"}]},{"kind":"class","name":"mt_destroy_session_none","id":1658015945,"type":"DestroySessionRes","arguments":[{"name":"session_id","type":"long"}]},{"kind":"class","name":"mt_new_session_created","id":2663516424,"type":"NewSession","arguments":[{"name":"first_msg_id","type":"long"},{"name":"unique_id","type":"long"},{"name":"server_salt","type":"long"}]},{"kind":"class","name":"mt_msgs_ack","id":1658238041,"type":"MsgsAck","arguments":[{"name":"msg_ids","type":"Vector"}]},{"kind":"class","name":"mt_bad_msg_notification","id":2817521681,"type":"BadMsgNotification","arguments":[{"name":"bad_msg_id","type":"long"},{"name":"bad_msg_seqno","type":"int"},{"name":"error_code","type":"int"}]},{"kind":"class","name":"mt_bad_server_salt","id":3987424379,"type":"BadMsgNotification","arguments":[{"name":"bad_msg_id","type":"long"},{"name":"bad_msg_seqno","type":"int"},{"name":"error_code","type":"int"},{"name":"new_server_salt","type":"long"}]},{"kind":"class","name":"mt_msg_resend_req","id":2105940488,"type":"MsgResendReq","arguments":[{"name":"msg_ids","type":"Vector"}]},{"kind":"class","name":"mt_msgs_state_req","id":3664378706,"type":"MsgsStateReq","arguments":[{"name":"msg_ids","type":"Vector"}]},{"kind":"class","name":"mt_msgs_state_info","id":81704317,"type":"MsgsStateInfo","arguments":[{"name":"req_msg_id","type":"long"},{"name":"info","type":"bytes"}]},{"kind":"class","name":"mt_msgs_all_info","id":2361446705,"type":"MsgsAllInfo","arguments":[{"name":"msg_ids","type":"Vector"},{"name":"info","type":"bytes"}]},{"kind":"class","name":"mt_msg_detailed_info","id":661470918,"type":"MsgDetailedInfo","arguments":[{"name":"msg_id","type":"long"},{"name":"answer_msg_id","type":"long"},{"name":"bytes","type":"int"},{"name":"status","type":"int"}]},{"kind":"class","name":"mt_msg_new_detailed_info","id":2157819615,"type":"MsgDetailedInfo","arguments":[{"name":"answer_msg_id","type":"long"},{"name":"bytes","type":"int"},{"name":"status","type":"int"}]},{"kind":"class","name":"mt_destroy_auth_key_ok","id":4133544404,"type":"DestroyAuthKeyRes","arguments":[]},{"kind":"class","name":"mt_destroy_auth_key_none","id":178201177,"type":"DestroyAuthKeyRes","arguments":[]},{"kind":"class","name":"mt_destroy_auth_key_fail","id":3926956819,"type":"DestroyAuthKeyRes","arguments":[]},{"kind":"class","name":"mt_req_pq_multi","id":3195965169,"type":"ResPQ","arguments":[{"name":"nonce","type":"int128"}]},{"kind":"class","name":"mt_req_DH_params","id":3608339646,"type":"Server_DH_Params","arguments":[{"name":"nonce","type":"int128"},{"name":"server_nonce","type":"int128"},{"name":"p","type":"bytes"},{"name":"q","type":"bytes"},{"name":"public_key_fingerprint","type":"long"},{"name":"encrypted_data","type":"bytes"}]},{"kind":"class","name":"mt_set_client_DH_params","id":4110704415,"type":"Set_client_DH_params_answer","arguments":[{"name":"nonce","type":"int128"},{"name":"server_nonce","type":"int128"},{"name":"encrypted_data","type":"bytes"}]},{"kind":"class","name":"mt_rpc_drop_answer","id":1491380032,"type":"RpcDropAnswer","arguments":[{"name":"req_msg_id","type":"long"}]},{"kind":"class","name":"mt_get_future_salts","id":3105996036,"type":"FutureSalts","arguments":[{"name":"num","type":"int"}]},{"kind":"class","name":"mt_ping","id":2059302892,"type":"Pong","arguments":[{"name":"ping_id","type":"long"}]},{"kind":"class","name":"mt_ping_delay_disconnect","id":4081220492,"type":"Pong","arguments":[{"name":"ping_id","type":"long"},{"name":"disconnect_delay","type":"int"}]},{"kind":"class","name":"mt_destroy_session","id":3880853798,"type":"DestroySessionRes","arguments":[{"name":"session_id","type":"long"}]},{"kind":"class","name":"mt_http_wait","id":2459514271,"type":"HttpWait","arguments":[{"name":"max_delay","type":"int"},{"name":"wait_after","type":"int"},{"name":"max_wait","type":"int"}]},{"kind":"class","name":"mt_destroy_auth_key","id":3510849888,"type":"DestroyAuthKeyRes","arguments":[]}] \ No newline at end of file +[{"kind":"class","name":"mt_resPQ","id":85337187,"type":"ResPQ","arguments":[{"name":"nonce","type":"int128"},{"name":"server_nonce","type":"int128"},{"name":"pq","type":"bytes"},{"name":"server_public_key_fingerprints","type":"long","typeModifiers":{"isVector":true}}]},{"kind":"class","name":"mt_p_q_inner_data_dc","id":2851430293,"type":"P_Q_inner_data","arguments":[{"name":"pq","type":"bytes"},{"name":"p","type":"bytes"},{"name":"q","type":"bytes"},{"name":"nonce","type":"int128"},{"name":"server_nonce","type":"int128"},{"name":"new_nonce","type":"int256"},{"name":"dc","type":"int"}]},{"kind":"class","name":"mt_p_q_inner_data_temp_dc","id":1459478408,"type":"P_Q_inner_data","arguments":[{"name":"pq","type":"bytes"},{"name":"p","type":"bytes"},{"name":"q","type":"bytes"},{"name":"nonce","type":"int128"},{"name":"server_nonce","type":"int128"},{"name":"new_nonce","type":"int256"},{"name":"dc","type":"int"},{"name":"expires_in","type":"int"}]},{"kind":"class","name":"mt_server_DH_params_ok","id":3504867164,"type":"Server_DH_Params","arguments":[{"name":"nonce","type":"int128"},{"name":"server_nonce","type":"int128"},{"name":"encrypted_answer","type":"bytes"}]},{"kind":"class","name":"mt_server_DH_inner_data","id":3045658042,"type":"Server_DH_inner_data","arguments":[{"name":"nonce","type":"int128"},{"name":"server_nonce","type":"int128"},{"name":"g","type":"int"},{"name":"dh_prime","type":"bytes"},{"name":"g_a","type":"bytes"},{"name":"server_time","type":"int"}]},{"kind":"class","name":"mt_client_DH_inner_data","id":1715713620,"type":"Client_DH_Inner_Data","arguments":[{"name":"nonce","type":"int128"},{"name":"server_nonce","type":"int128"},{"name":"retry_id","type":"long"},{"name":"g_b","type":"bytes"}]},{"kind":"class","name":"mt_dh_gen_ok","id":1003222836,"type":"Set_client_DH_params_answer","arguments":[{"name":"nonce","type":"int128"},{"name":"server_nonce","type":"int128"},{"name":"new_nonce_hash1","type":"int128"}]},{"kind":"class","name":"mt_dh_gen_retry","id":1188831161,"type":"Set_client_DH_params_answer","arguments":[{"name":"nonce","type":"int128"},{"name":"server_nonce","type":"int128"},{"name":"new_nonce_hash2","type":"int128"}]},{"kind":"class","name":"mt_dh_gen_fail","id":2795351554,"type":"Set_client_DH_params_answer","arguments":[{"name":"nonce","type":"int128"},{"name":"server_nonce","type":"int128"},{"name":"new_nonce_hash3","type":"int128"}]},{"kind":"class","name":"mt_bind_auth_key_inner","id":1973679973,"type":"BindAuthKeyInner","arguments":[{"name":"nonce","type":"long"},{"name":"temp_auth_key_id","type":"long"},{"name":"perm_auth_key_id","type":"long"},{"name":"temp_session_id","type":"long"},{"name":"expires_at","type":"int"}]},{"kind":"class","name":"mt_rpc_result","id":4082920705,"type":"RpcResult","arguments":[{"name":"req_msg_id","type":"long"},{"name":"result","type":"any"}]},{"kind":"class","name":"mt_rpc_error","id":558156313,"type":"RpcError","arguments":[{"name":"error_code","type":"int"},{"name":"error_message","type":"string"}]},{"kind":"class","name":"mt_rpc_answer_unknown","id":1579864942,"type":"RpcDropAnswer","arguments":[]},{"kind":"class","name":"mt_rpc_answer_dropped_running","id":3447252358,"type":"RpcDropAnswer","arguments":[]},{"kind":"class","name":"mt_rpc_answer_dropped","id":2755319991,"type":"RpcDropAnswer","arguments":[{"name":"msg_id","type":"long"},{"name":"seq_no","type":"int"},{"name":"bytes","type":"int"}]},{"kind":"class","name":"mt_future_salt","id":155834844,"type":"FutureSalt","arguments":[{"name":"valid_since","type":"int"},{"name":"valid_until","type":"int"},{"name":"salt","type":"long"}]},{"kind":"class","name":"mt_future_salts","id":2924480661,"type":"FutureSalts","arguments":[{"name":"req_msg_id","type":"long"},{"name":"now","type":"int"},{"name":"salts","type":"mt_future_salt","typeModifiers":{"isBareVector":true,"isBareType":true,"constructorId":155834844}}]},{"kind":"class","name":"mt_pong","id":880243653,"type":"Pong","arguments":[{"name":"msg_id","type":"long"},{"name":"ping_id","type":"long"}]},{"kind":"class","name":"mt_destroy_session_ok","id":3793765884,"type":"DestroySessionRes","arguments":[{"name":"session_id","type":"long"}]},{"kind":"class","name":"mt_destroy_session_none","id":1658015945,"type":"DestroySessionRes","arguments":[{"name":"session_id","type":"long"}]},{"kind":"class","name":"mt_new_session_created","id":2663516424,"type":"NewSession","arguments":[{"name":"first_msg_id","type":"long"},{"name":"unique_id","type":"long"},{"name":"server_salt","type":"long"}]},{"kind":"class","name":"mt_msgs_ack","id":1658238041,"type":"MsgsAck","arguments":[{"name":"msg_ids","type":"long","typeModifiers":{"isVector":true}}]},{"kind":"class","name":"mt_bad_msg_notification","id":2817521681,"type":"BadMsgNotification","arguments":[{"name":"bad_msg_id","type":"long"},{"name":"bad_msg_seqno","type":"int"},{"name":"error_code","type":"int"}]},{"kind":"class","name":"mt_bad_server_salt","id":3987424379,"type":"BadMsgNotification","arguments":[{"name":"bad_msg_id","type":"long"},{"name":"bad_msg_seqno","type":"int"},{"name":"error_code","type":"int"},{"name":"new_server_salt","type":"long"}]},{"kind":"class","name":"mt_msg_resend_req","id":2105940488,"type":"MsgResendReq","arguments":[{"name":"msg_ids","type":"long","typeModifiers":{"isVector":true}}]},{"kind":"class","name":"mt_msgs_state_req","id":3664378706,"type":"MsgsStateReq","arguments":[{"name":"msg_ids","type":"long","typeModifiers":{"isVector":true}}]},{"kind":"class","name":"mt_msgs_state_info","id":81704317,"type":"MsgsStateInfo","arguments":[{"name":"req_msg_id","type":"long"},{"name":"info","type":"bytes"}]},{"kind":"class","name":"mt_msgs_all_info","id":2361446705,"type":"MsgsAllInfo","arguments":[{"name":"msg_ids","type":"long","typeModifiers":{"isVector":true}},{"name":"info","type":"bytes"}]},{"kind":"class","name":"mt_msg_detailed_info","id":661470918,"type":"MsgDetailedInfo","arguments":[{"name":"msg_id","type":"long"},{"name":"answer_msg_id","type":"long"},{"name":"bytes","type":"int"},{"name":"status","type":"int"}]},{"kind":"class","name":"mt_msg_new_detailed_info","id":2157819615,"type":"MsgDetailedInfo","arguments":[{"name":"answer_msg_id","type":"long"},{"name":"bytes","type":"int"},{"name":"status","type":"int"}]},{"kind":"class","name":"mt_destroy_auth_key_ok","id":4133544404,"type":"DestroyAuthKeyRes","arguments":[]},{"kind":"class","name":"mt_destroy_auth_key_none","id":178201177,"type":"DestroyAuthKeyRes","arguments":[]},{"kind":"class","name":"mt_destroy_auth_key_fail","id":3926956819,"type":"DestroyAuthKeyRes","arguments":[]},{"kind":"class","name":"mt_http_wait","id":2459514271,"type":"HttpWait","arguments":[{"name":"max_delay","type":"int"},{"name":"wait_after","type":"int"},{"name":"max_wait","type":"int"}]},{"kind":"class","name":"mt_req_pq_multi","id":3195965169,"type":"ResPQ","arguments":[{"name":"nonce","type":"int128"}]},{"kind":"class","name":"mt_req_DH_params","id":3608339646,"type":"Server_DH_Params","arguments":[{"name":"nonce","type":"int128"},{"name":"server_nonce","type":"int128"},{"name":"p","type":"bytes"},{"name":"q","type":"bytes"},{"name":"public_key_fingerprint","type":"long"},{"name":"encrypted_data","type":"bytes"}]},{"kind":"class","name":"mt_set_client_DH_params","id":4110704415,"type":"Set_client_DH_params_answer","arguments":[{"name":"nonce","type":"int128"},{"name":"server_nonce","type":"int128"},{"name":"encrypted_data","type":"bytes"}]},{"kind":"class","name":"mt_rpc_drop_answer","id":1491380032,"type":"RpcDropAnswer","arguments":[{"name":"req_msg_id","type":"long"}]},{"kind":"class","name":"mt_get_future_salts","id":3105996036,"type":"FutureSalts","arguments":[{"name":"num","type":"int"}]},{"kind":"class","name":"mt_ping","id":2059302892,"type":"Pong","arguments":[{"name":"ping_id","type":"long"}]},{"kind":"class","name":"mt_ping_delay_disconnect","id":4081220492,"type":"Pong","arguments":[{"name":"ping_id","type":"long"},{"name":"disconnect_delay","type":"int"}]},{"kind":"class","name":"mt_destroy_session","id":3880853798,"type":"DestroySessionRes","arguments":[{"name":"session_id","type":"long"}]},{"kind":"class","name":"mt_destroy_auth_key","id":3510849888,"type":"DestroyAuthKeyRes","arguments":[]}] \ No newline at end of file diff --git a/packages/tl/scripts/fetch-mtp.ts b/packages/tl/scripts/fetch-mtp.ts index c07f4bce..fff7ea27 100644 --- a/packages/tl/scripts/fetch-mtp.ts +++ b/packages/tl/scripts/fetch-mtp.ts @@ -24,10 +24,7 @@ async function main() { const schema = await fetchMtprotoSchema() console.log('Parsing...') - let entries = parseTlToEntries(schema, { - prefix: 'mt_', - applyPrefixToArguments: true, - }) + let entries = parseTlToEntries(schema, { prefix: 'mt_' }) // remove manually parsed types entries = entries.filter( diff --git a/packages/tl/scripts/gen-code.ts b/packages/tl/scripts/gen-code.ts index 92ff62aa..c76777c1 100644 --- a/packages/tl/scripts/gen-code.ts +++ b/packages/tl/scripts/gen-code.ts @@ -56,11 +56,16 @@ async function generateReaders( ) { console.log('Generating readers...') - let code = generateReaderCodeForTlEntries(apiSchema.entries, 'r', false) + let code = generateReaderCodeForTlEntries(apiSchema.entries, { + variableName: 'm', + includeMethods: false, + }) - const mtpCode = generateReaderCodeForTlEntries(mtpSchema.entries, '') - code = code.substring(0, code.length - 1) + mtpCode.substring(7) - code += '\nexports.default = r;' + const mtpCode = generateReaderCodeForTlEntries(mtpSchema.entries, { + variableName: 'm', + }) + code = code.substring(0, code.length - 1) + mtpCode.substring(8) + code += '\nexports.default = m;' await writeFile(OUT_READERS_FILE, ESM_PRELUDE + code) } @@ -71,11 +76,16 @@ async function generateWriters( ) { console.log('Generating writers...') - let code = generateWriterCodeForTlEntries(apiSchema.entries, 'r') + let code = generateWriterCodeForTlEntries(apiSchema.entries, { + variableName: 'm', + }) - const mtpCode = generateWriterCodeForTlEntries(mtpSchema.entries, '', false) + const mtpCode = generateWriterCodeForTlEntries(mtpSchema.entries, { + variableName: 'm', + includePrelude: false, + }) code = code.substring(0, code.length - 1) + mtpCode.substring(7) - code += '\nexports.default = r;' + code += '\nexports.default = m;' await writeFile(OUT_WRITERS_FILE, ESM_PRELUDE + code) }