const fs = require('fs'); const csvParse = require('csv-parse/lib/sync'); const { snakeToCamelCase } = require('../utils'); const KNOWN_BASE_CLASSES = { 303: 'InvalidDCError', 400: 'BadRequestError', 401: 'UnauthorizedError', 403: 'ForbiddenError', 404: 'NotFoundError', 406: 'AuthKeyError', 420: 'FloodError', 500: 'ServerError', 503: 'TimedOutError', }; /** * Gets the corresponding class name for the given error code, * this either being an integer (thus base error name) or str. */ const getClassName = errorCode => { if (typeof errorCode === 'number') { return ( KNOWN_BASE_CLASSES[Math.abs(errorCode)] || 'RPCError' + errorCode.toString().replace('-', 'Neg') ); } return snakeToCamelCase( errorCode .replace('FIRSTNAME', 'FIRST_NAME') .replace('SLOWMODE', 'SLOW_MODE') .toLowerCase(), 'Error' ); }; class TelegramError { constructor(codes, name, description) { // TODO Some errors have the same name but different integer codes // Should these be split into different files or doesn't really matter? // Telegram isn't exactly consistent with returned errors anyway. this.intCode = codes[0]; this.stringCode = name; this.subclass = getClassName(codes[0]); this.subclassExists = Math.abs(codes[0]) in KNOWN_BASE_CLASSES; this.description = description; this.hasCaptures = name.includes('_X'); if (this.hasCaptures) { this.name = getClassName(name.replace('_X', '')); this.pattern = name.replace('_X', '_(\\d+)'); this.captureName = description.match(/{(\w+)}/)[1]; } else { this.name = getClassName(name); this.pattern = name; this.captureName = null; } } } /** * Parses the input CSV file with columns (name, error codes, description) * and yields `Error` instances as a result. */ const parseErrors = function*(csvFile) { const f = csvParse(fs.readFileSync(csvFile, { encoding: 'utf-8' })).slice( 1 ); for (let line = 0; line < f.length; line++) { if (f[line].length !== 3) { throw new Error( `Columns count mismatch, unquoted comma in desc? (line ${line + 2})` ); } let [name, codes, description] = f[line]; codes = codes === '' ? [400] : codes.split(' ').map(x => { if (isNaN(x)) { throw new Error( `Not all codes are integers (line ${line + 2})` ); } return Number(x); }); yield new TelegramError(codes, name, description); } }; module.exports = { KNOWN_BASE_CLASSES, TelegramError, parseErrors, };