diff --git a/.eslintrc b/.eslintrc index 1d47ccc..e5873f3 100644 --- a/.eslintrc +++ b/.eslintrc @@ -1,59 +1,13 @@ { + "parser": "babel-eslint", + "extends": "airbnb/base", + "root": true, "env": { - "es6": true, - "browser": true - }, - "ecmaFeatures": { - "modules": true - }, - "globals": { - "exports": true, - "require": true, - "ViewHelpers": true, - "is": true, - "Components": true, - "XPCOMUtils": true, - "EventEmitter": true, - "add_task": true, - "info": true, - "createHost": true, - "promiseTab": true, - "ok": true, - "TEST_URI_ROOT": true, - "TargetFactory": true, - "gBrowser": true, - "gDevTools": true + "node": true }, "rules": { - "comma-dangle": [2, "never"], - "no-underscore-dangle": 0, - "no-cond-assign": 0, - "no-undef": 0, - "no-console": 0, - "no-reserved-keys": 2, - "valid-jsdoc": [2, { - "requireReturn": false, - "requireParamDescription": false, - "requireReturnDescription": false - }], - "max-len": [1, 80], - "no-use-before-define": 0, - "no-self-compare": 1, - "no-sequences": 0, - "radix": 2, - "wrap-iife": 2, - "indent": [2, 2], - "brace-style": [2, "1tbs"], - "comma-style": [2, "last"], - "no-lonely-if": 2, - "no-multiple-empty-lines": [2, {"max": 2}], - "quotes": 0, - "space-after-keywords": [2, "always"], - "space-before-blocks": [2, "always"], - "space-infix-ops": [2, { "int32Hint": false }], - "strict": 0, - "global-strict": 0, - "no-new": 0, - "camelcase": 0 + "comma-dangle": 0, + "no-param-reassign": 0, + "no-console": 0 } } diff --git a/.gitignore b/.gitignore index 047fc8f..de2ae82 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,7 @@ +build +types +!src/types + # Logs logs *.log @@ -30,6 +34,3 @@ node_modules test.js .DS_Store - -build -types diff --git a/package.json b/package.json index ca2d8ee..6a24df5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "telegram-api", - "version": "0.7.0", + "version": "0.7.1", "description": "Control Telegram bots easily using the new Telegram API", "main": "build/index.js", "scripts": { @@ -39,13 +39,16 @@ "unirest": "0.4.2" }, "devDependencies": { + "babel-eslint": "6.0.0", "babel-plugin-add-module-exports": "^0.1.2", "babel-preset-es2015": "^6.6.0", + "eslint-config-airbnb": "6.2.0", "grunt": "^0.4.5", "grunt-babel": "^6.0.0", "grunt-contrib-clean": "^1.0.0", "grunt-contrib-copy": "^1.0.0", "grunt-contrib-watch": "^1.0.0", - "grunt-copy": "^0.1.0" + "grunt-copy": "^0.1.0", + "grunt-eslint": "18.0.0" } } diff --git a/src/functions/api.js b/src/functions/api.js index 8492f08..107d7cf 100644 --- a/src/functions/api.js +++ b/src/functions/api.js @@ -20,7 +20,7 @@ export default class API { } API.prototype.request = function request(method, data) { - return fetch(this.token + '/' + method, data); + return fetch(`${this.token}/${method}`, data); }; const methods = ['getMe', 'sendMessage', 'forwardMessage', 'sendPhoto', @@ -29,7 +29,7 @@ const methods = ['getMe', 'sendMessage', 'forwardMessage', 'sendPhoto', 'getUpdates', 'setWebhook']; methods.forEach(method => { - API.prototype[method] = function(data) { + API.prototype[method] = function(data) { //eslint-disable-line return this.request(method, data); }; }); diff --git a/src/functions/argument-parser.js b/src/functions/argument-parser.js index 48376a0..f35c3d9 100644 --- a/src/functions/argument-parser.js +++ b/src/functions/argument-parser.js @@ -8,6 +8,32 @@ const REQUIRED = 0; const OPTIONAL = 1; const REST = 2; +function escape(symbols, append = '') { + return symbols.split('').map(symbol => + (ESCAPABLE.indexOf(symbol) ? `\\${symbol}` : symbol) + append + ).join(''); +} + +const TYPES = { + number: '\\d', + word: '\\S' +}; + +function getFormat(type = 'word', param = 'required') { + const t = TYPES[type]; + + switch (param) { // eslint-disable-line + case 'required': + return `(${t}+)`; + case 'optional': + return `(${t}+)?`; + case 'rest': + return '(.*)'; + } + + return ''; +} + /** * Parses a message for arguments, based on format * @@ -41,74 +67,49 @@ export default function argumentParser(format, string) { format = format.replace(/[^\s]+/, '').trim(); if (!format) { - return {args: {}, params: {}}; + return { args: {}, params: {} }; } - let indexes = [], - params = {}; + let indexes = []; + const params = {}; format = format.replace(/\s/g, '\\s*'); format = format.replace(FORMAT_REQUIRED, (f, symbols, arg, type = 'word', offset) => { - indexes.push({arg, offset}); + indexes.push({ arg, offset }); params[arg] = REQUIRED; return (escape(symbols) + getFormat(type, 'required')).trim(); }); format = format.replace(FORMAT_OPTIONAL, (f, symbols, arg, type = 'word', offset) => { - indexes.push({arg, offset}); + indexes.push({ arg, offset }); params[arg] = OPTIONAL; return (escape(symbols, '?') + getFormat(type, 'optional')).trim(); }); format = format.replace(FORMAT_REST, (full, arg, offset) => { - indexes.push({offset, arg}); + indexes.push({ offset, arg }); params[arg] = REST; return getFormat(null, 'rest'); }); if (!string) { - return {args: {}, params}; + return { args: {}, params }; } - indexes = indexes.sort((a, b) => { - return a.offset < b.offset ? -1 : 1; - }); + indexes = indexes.sort((a, b) => + (a.offset < b.offset ? -1 : 1) + ); const regex = new RegExp(format); const matched = regex.exec(string).slice(1); const object = {}; - for (let [index, match] of matched.entries()) { + for (const [index, match] of matched.entries()) { const argument = indexes[index]; object[argument.arg] = match; } - return {args: object, params}; -} - -function escape(symbols, append = '') { - return symbols.split('').map(symbol => { - return (ESCAPABLE.indexOf(symbol) ? `\\${symbol}` : symbol) + append; - }).join(''); -} - - -const TYPES = { - 'number': '\\d', - 'word': '\\S' -}; - -function getFormat(type = 'word', param = 'required') { - const t = TYPES[type]; - - switch (param) { - case 'required': - return `(${t}+)`; - case 'optional': - return `(${t}+)?`; - case 'rest': - return `(.*)`; - } + return { args: object, params }; } diff --git a/src/functions/fetch.js b/src/functions/fetch.js index b0bead2..5a40191 100644 --- a/src/functions/fetch.js +++ b/src/functions/fetch.js @@ -4,14 +4,14 @@ export default function fetch(path, data = {}) { return new Promise((resolve, reject) => { const files = {}; - for (let key of Object.keys(data)) { + for (const key of Object.keys(data)) { if (data[key].file) { files[key] = data[key].file; delete data[key]; } } - unirest.post('https://api.telegram.org/bot' + path) + unirest.post(`https://api.telegram.org/bot${path}`) .field(data) .attach(files) .end(response => { diff --git a/src/functions/webhook.js b/src/functions/webhook.js index d45f742..3e58139 100644 --- a/src/functions/webhook.js +++ b/src/functions/webhook.js @@ -1,6 +1,6 @@ import https from 'http'; import qs from 'qs'; -import {getBody} from './fetch'; +import { getBody } from './fetch'; const DEFAULTS = { server: {}, @@ -11,14 +11,12 @@ export default function webhook(options = {}, bot) { options = Object.assign(DEFAULTS, options); return bot.api.setWebhook(options.url).then(() => { - - bot._webhookServer = https.createServer(options.server, (req, res) => { - return getBody(req).then(data => { + bot._webhookServer = https.createServer(options.server, (req, res) => + getBody(req).then(data => { bot.emit('update', qs.parse(data).result); res.end('OK'); - }); - }).listen(options.port); - + }) + ).listen(options.port); }); } diff --git a/src/index.js b/src/index.js index 5f909ac..38fa73e 100644 --- a/src/index.js +++ b/src/index.js @@ -3,7 +3,7 @@ import API from './functions/api'; import webhook from './functions/webhook'; import poll from './functions/poll'; import argumentParser from './functions/argument-parser'; -import {EventEmitter} from 'events'; +import { EventEmitter } from 'events'; import Message from './types/Message'; import File from './types/File'; import Keyboard from './types/Keyboard'; @@ -31,7 +31,7 @@ export default class Bot extends EventEmitter { * Create and connect to a new bot * @param {object} options Bot properties. */ - constructor(options = {update: {}}) { + constructor(options = { update: {} }) { super(); if (!options.token) { @@ -80,9 +80,9 @@ export default class Bot extends EventEmitter { if (hook) { return webhook(hook, this); - } else { - return poll(this); } + + return poll(this); }); } @@ -182,7 +182,7 @@ export default class Bot extends EventEmitter { res.message.text = text; } - let ev = this._userEvents.find(({pattern}) => pattern.test(text)); + const ev = this._userEvents.find(({ pattern }) => pattern.test(text)); if (!ev) { this.emit('command-notfound', res.message); @@ -194,12 +194,12 @@ export default class Bot extends EventEmitter { return; } - let {params, args} = ev.parse(res.message.text); + const { params, args } = ev.parse(res.message.text); res.message.args = args; - const requiredParams = Object.keys(params).filter(param => { - return params[param] === REQUIRED && !args[param]; - }); + const requiredParams = Object.keys(params).filter(param => + params[param] === REQUIRED && !args[param] + ); if (!requiredParams.length) { ev.listener(res.message); @@ -208,7 +208,7 @@ export default class Bot extends EventEmitter { const bot = this; function* getAnswer() { - for (let param of requiredParams) { + for (const param of requiredParams) { const msg = new Message().to(res.message.chat.id) .text(`Enter value for ${param}`); yield bot.send(msg).then(answer => { diff --git a/src/types/Base.js b/src/types/Base.js index 82ffde6..4ec19d5 100644 --- a/src/types/Base.js +++ b/src/types/Base.js @@ -1,4 +1,4 @@ -import {EventEmitter} from 'events'; +import { EventEmitter } from 'events'; const ANSWER_THRESHOLD = 10; @@ -29,8 +29,8 @@ export default class Base extends EventEmitter { */ send(bot) { if (this._keyboard) { - const reply_markup = JSON.stringify(this._keyboard.getProperties()); - this.properties.reply_markup = reply_markup; + const replyMarkup = JSON.stringify(this._keyboard.getProperties()); + this.properties.reply_markup = replyMarkup; } let messageId; @@ -49,15 +49,15 @@ export default class Base extends EventEmitter { bot.on('update', function listener(result) { answers += result.length; - const update = result.find(({message}) => { + const update = result.find(({ message }) => { // if in a group, there will be a reply to this message if (chat < 0) { return message.chat.id === chat && message.reply_to_message && message.reply_to_message.message_id === messageId; - } else { - return message.chat.id === chat; } + + return message.chat.id === chat; }); if (update) { diff --git a/src/types/BulkMessage.js b/src/types/BulkMessage.js index 1354e9d..3ed8c90 100644 --- a/src/types/BulkMessage.js +++ b/src/types/BulkMessage.js @@ -20,9 +20,7 @@ export default class BulkMessage extends Message { * @return {object} returns the message object */ to(...args) { - const chats = args.reduce((a, b) => { - return a.concat(b); - }, []); + const chats = args.reduce((a, b) => a.concat(b), []); this.chats = chats; return this; diff --git a/src/types/File.js b/src/types/File.js index 8fed1d7..9563b0e 100644 --- a/src/types/File.js +++ b/src/types/File.js @@ -37,12 +37,12 @@ export default class File extends Base { */ file(file, fileType) { if (fileType) { - this.properties[fileType] = {file: file}; + this.properties[fileType] = { file }; return this; } - let [type, extension] = mime.lookup(file).split('/'); + let [type, extension] = mime.lookup(file).split('/'); // eslint-disable-line if (type === 'image') { type = 'photo'; } @@ -55,7 +55,7 @@ export default class File extends Base { type = 'document'; } - this.properties[type] = {file: file}; + this.properties[type] = { file }; this.method = `send${type[0].toUpperCase() + type.slice(1)}`; diff --git a/src/types/Question.js b/src/types/Question.js index ece9b46..93b92ea 100644 --- a/src/types/Question.js +++ b/src/types/Question.js @@ -15,7 +15,7 @@ export default class Question extends Message { constructor(options = {}) { super(options); - let kb = new Keyboard().force().oneTime().selective(); + const kb = new Keyboard().force().oneTime().selective(); this.keyboard(kb); this.answers(options.answers); @@ -60,10 +60,10 @@ export default class Question extends Message { if (answer) { this.emit('question:answer', answer, message); return message; - } else { - this.emit('question:invalid', message); - throw message; } + + this.emit('question:invalid', message); + throw message; }); } }