<commit_before>class Helper {
    /*static currentDate() {
        const now = new Date();
        let dd = now.getDate();if (dd < 10) dd = '0' + dd;
        let mm = now.getMonth()+1;if (mm < 10) mm = '0' + mm;   /!*January is 0!*!/
        const yyyy = now.getFullYear();
        return [yyyy, mm, dd].join('-');
    }*/

    /*static currentDateTime() {
        return Helper.currentDate() + ' ' + Helper.currentTime();
    }*/

    /*static currentTime() {
        const now = new Date();
        let hh = now.getHours();if (hh < 10) hh = '0' + hh;
        let mm = now.getMinutes();if (mm < 10) mm = '0' + mm;
        let ss = now.getSeconds();if (ss < 10) ss = '0' + ss;
        return [hh, mm, ss].join(':');
    }*/

    static formatDate(date, format) {
        const YYYY = date.getFullYear();
        const M    = date.getMonth() + 1;
        const D    = date.getDate();
        const h    = date.getHours();
        const m    = date.getMinutes();
        const s    = date.getSeconds();
        const MM = M < 10 ? `0${M}` : M;
        const DD = D < 10 ? `0${D}` : D;
        const hh = h < 10 ? `0${h}` : h;
        const mm = m < 10 ? `0${m}` : m;
        const ss = s < 10 ? `0${s}` : s;
        const values = {YYYY, M, D, h, m, s, MM, DD, hh, mm, ss};
        return format.replace(/\{([\w\.]+)\}/g, (text, name) => values[name] ? values[name] : text);
    }

    static today() {
        const now = new Date();
        return new Date(now.getFullYear(), now.getMonth(), now.getDate());
    }

    static encodeObject(obj) {
        const eObj = {};
        for (const name in obj) {
            eObj[name] = Helper.encodeValue(obj[name]);
        }
        return eObj;
    }

    static encodeValue(value) {
        return JSON.stringify(value);
    }

    static decodeObject(eObj) {
        const obj = {};
        for (const name in eObj) {
            obj[name] = Helper.decodeValue(eObj[name]);
        }
        return obj;
    }

    static decodeValue(rawValue) {
        return JSON.parse(rawValue, Helper.dateTimeReviver);
    }

    static dateTimeReviver(key, value) {
        if (typeof value === 'string') {
            const a = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*))(?:Z|(\+|-)([\d|:]*))?$/.exec(value);
            if (a) return new Date(value);
        }
        return value;
    }
    static createReactComponent(root, type, props = {}, children) {
        // console.log('Helper.createReactComponent', root, type);
        let component;
        props.onCreate = c => component = c;
        const reactElement = React.createElement(type, props, children);
        ReactDOM.render(reactElement, root);
        return component;
    }

    static readFileAsDataURL(file) {
        return new Promise(resolve => {
            const reader = new FileReader();
            reader.onload = () => resolve(reader.result);
            reader.readAsDataURL(file);
        });
    }

    /*static readFileAsArrayBuffer(file) {
        return new Promise(resolve => {
            const reader = new FileReader();
            reader.onload = () => resolve(reader.result);
            reader.readAsArrayBuffer(file);
        });
    }*/

    /*static convertBufferToBase64string(buffer) {
        const array = new Uint8Array(buffer);
        const binaryString = String.fromCharCode.apply(null, array);
        return window.btoa(binaryString);
    }*/
    /*static createObjectUrl(buffer) {
        const blob = new Blob([new Uint8Array(buffer)]);
        return window.URL.createObjectURL(blob);
    }*/

    // append file as filed and all not file as json string
    /*static createFormData(body) {
        const formData = new FormData();
        const fields = {};
        for (const name in body) {
            if (body[name] instanceof File) {
                formData.append(name, body[name]);
            } else {
                fields[name] = body[name];
            }
        }
        formData.append('__json', JSON.stringify(fields));
        return formData;
    }*/

    /*static base64ToArrayBuffer(base64) {
        const binaryString = window.atob(base64);
        const len = binaryString.length;
        const bytes = new Uint8Array(len);
        for (let i = 0; i < len; i++) {
            bytes[i] = binaryString.charCodeAt(i);
        }
        return bytes.buffer;
    }*/

    static templateValue(value, params) {
        return value.replace(/\{([\w\.@]+)\}/g, (text, name) => {
            if (params.hasOwnProperty(name)) return params[name];
            return '';
        });
    }
}

<commit_msg>formatNumber<commit_after>class Helper {
    /*static currentDate() {
        const now = new Date();
        let dd = now.getDate();if (dd < 10) dd = '0' + dd;
        let mm = now.getMonth()+1;if (mm < 10) mm = '0' + mm;   /!*January is 0!*!/
        const yyyy = now.getFullYear();
        return [yyyy, mm, dd].join('-');
    }*/

    /*static currentDateTime() {
        return Helper.currentDate() + ' ' + Helper.currentTime();
    }*/

    /*static currentTime() {
        const now = new Date();
        let hh = now.getHours();if (hh < 10) hh = '0' + hh;
        let mm = now.getMinutes();if (mm < 10) mm = '0' + mm;
        let ss = now.getSeconds();if (ss < 10) ss = '0' + ss;
        return [hh, mm, ss].join(':');
    }*/

    static formatDate(date, format) {
        const YYYY = date.getFullYear();
        const M    = date.getMonth() + 1;
        const D    = date.getDate();
        const h    = date.getHours();
        const m    = date.getMinutes();
        const s    = date.getSeconds();
        const MM = M < 10 ? `0${M}` : M;
        const DD = D < 10 ? `0${D}` : D;
        const hh = h < 10 ? `0${h}` : h;
        const mm = m < 10 ? `0${m}` : m;
        const ss = s < 10 ? `0${s}` : s;
        const values = {YYYY, M, D, h, m, s, MM, DD, hh, mm, ss};
        return format.replace(/\{([\w\.]+)\}/g, (text, name) => values[name] ? values[name] : text);
    }

    static formatNumber(value) {
        return new Intl.NumberFormat('ru-RU').format(value);
    }

    static today() {
        const now = new Date();
        return new Date(now.getFullYear(), now.getMonth(), now.getDate());
    }

    static encodeObject(obj) {
        const eObj = {};
        for (const name in obj) {
            eObj[name] = Helper.encodeValue(obj[name]);
        }
        return eObj;
    }

    static encodeValue(value) {
        return JSON.stringify(value);
    }

    static decodeObject(eObj) {
        const obj = {};
        for (const name in eObj) {
            obj[name] = Helper.decodeValue(eObj[name]);
        }
        return obj;
    }

    static decodeValue(rawValue) {
        return JSON.parse(rawValue, Helper.dateTimeReviver);
    }

    static dateTimeReviver(key, value) {
        if (typeof value === 'string') {
            const a = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*))(?:Z|(\+|-)([\d|:]*))?$/.exec(value);
            if (a) return new Date(value);
        }
        return value;
    }
    static createReactComponent(root, type, props = {}, children) {
        // console.log('Helper.createReactComponent', root, type);
        let component;
        props.onCreate = c => component = c;
        const reactElement = React.createElement(type, props, children);
        ReactDOM.render(reactElement, root);
        return component;
    }

    static readFileAsDataURL(file) {
        return new Promise(resolve => {
            const reader = new FileReader();
            reader.onload = () => resolve(reader.result);
            reader.readAsDataURL(file);
        });
    }

    /*static readFileAsArrayBuffer(file) {
        return new Promise(resolve => {
            const reader = new FileReader();
            reader.onload = () => resolve(reader.result);
            reader.readAsArrayBuffer(file);
        });
    }*/

    /*static convertBufferToBase64string(buffer) {
        const array = new Uint8Array(buffer);
        const binaryString = String.fromCharCode.apply(null, array);
        return window.btoa(binaryString);
    }*/
    /*static createObjectUrl(buffer) {
        const blob = new Blob([new Uint8Array(buffer)]);
        return window.URL.createObjectURL(blob);
    }*/

    // append file as filed and all not file as json string
    /*static createFormData(body) {
        const formData = new FormData();
        const fields = {};
        for (const name in body) {
            if (body[name] instanceof File) {
                formData.append(name, body[name]);
            } else {
                fields[name] = body[name];
            }
        }
        formData.append('__json', JSON.stringify(fields));
        return formData;
    }*/

    /*static base64ToArrayBuffer(base64) {
        const binaryString = window.atob(base64);
        const len = binaryString.length;
        const bytes = new Uint8Array(len);
        for (let i = 0; i < len; i++) {
            bytes[i] = binaryString.charCodeAt(i);
        }
        return bytes.buffer;
    }*/

    static templateValue(value, params) {
        return value.replace(/\{([\w\.@]+)\}/g, (text, name) => {
            if (params.hasOwnProperty(name)) return params[name];
            return '';
        });
    }
}

<|endoftext|>


<commit_before>var chalk = require('chalk');
var makeSpaces = require('./makeSpaces');

function identity (string) { return string; }

var typeToColor = {
  error: identity,
  warn: identity,
  log: identity,
  info: identity,
  debug: identity,
  success: identity
};

var typeToTitleColor = {
  error: chalk.red,
  warn: chalk.yellow,
  log: chalk.white,
  info: chalk.grey,
  debug: chalk.blue,
  success: chalk.green
};

var longestTitle = 5;

function paddedString (length, string) {
  var padding = makeSpaces(length + 3);

  if (string instanceof Error) {
    string = string.stack;
  }

  if (typeof string !== 'string') {
    return '';
  }

  var lines = string.split('\n');
  var paddedLines = lines
    .slice(1)
    .map(function addPadding (string) {
      return padding + string;
    });
  paddedLines.unshift(lines[0]);

  return paddedLines.join('\n');
}

function message (type, subject, string) {
  if (!typeToColor.hasOwnProperty(type)) {
    type = 'info';
    console.log(typeToColor.warn('Type ' + type + ' is not defined as logging type'));
  }

  if (subject.length < longestTitle) {
    const appendChar = ' ';
    while (subject.length < longestTitle) {
      subject = appendChar + subject;
    }
  } else {
    longestTitle = subject.length;
  }

  console.log(typeToTitleColor[type](subject + ' ') + '| ' + paddedString(longestTitle, typeToColor[type](string)));
}

module.exports = function (subject) {
  return {
    error: message.bind(null, 'error', subject),
    warn: message.bind(null, 'warn', subject),
    log: message.bind(null, 'log', subject),
    info: message.bind(null, 'info', subject),
    debug: message.bind(null, 'debug', subject),
    success: message.bind(null, 'success', subject)
  };
};
<commit_msg>tweak to #289 fix<commit_after>var chalk = require('chalk');
var makeSpaces = require('./makeSpaces');

function identity (string) { return string; }

var typeToColor = {
  error: identity,
  warn: identity,
  log: identity,
  info: identity,
  debug: identity,
  success: identity
};

var typeToTitleColor = {
  error: chalk.red,
  warn: chalk.yellow,
  log: chalk.white,
  info: chalk.grey,
  debug: chalk.blue,
  success: chalk.green
};

var longestTitle = 5;

function paddedString (length, string) {
  var padding = makeSpaces(length + 3);

  if (string instanceof Error) {
    string = string.stack;
  }

  if (typeof string !== 'string') {
    return string;
  }

  var lines = string.split('\n');
  var paddedLines = lines
    .slice(1)
    .map(function addPadding (string) {
      return padding + string;
    });
  paddedLines.unshift(lines[0]);

  return paddedLines.join('\n');
}

function message (type, subject, string) {
  if (!typeToColor.hasOwnProperty(type)) {
    type = 'info';
    console.log(typeToColor.warn('Type ' + type + ' is not defined as logging type'));
  }

  if (subject.length < longestTitle) {
    const appendChar = ' ';
    while (subject.length < longestTitle) {
      subject = appendChar + subject;
    }
  } else {
    longestTitle = subject.length;
  }

  console.log(typeToTitleColor[type](subject + ' ') + '| ' + paddedString(longestTitle, typeToColor[type](string)));
}

module.exports = function (subject) {
  return {
    error: message.bind(null, 'error', subject),
    warn: message.bind(null, 'warn', subject),
    log: message.bind(null, 'log', subject),
    info: message.bind(null, 'info', subject),
    debug: message.bind(null, 'debug', subject),
    success: message.bind(null, 'success', subject)
  };
};
<|endoftext|>


<commit_before>'use strict';

/* global describe, it, expect, beforeEach, afterEach */
describe('Mail', function () {
    var path = require('path');
    var fs = require('fs');
    var rootPath = path.resolve(__dirname, '../');
    var emlDir = path.resolve(__dirname, 'eml');
    var configMock = require(path.resolve(rootPath, 'lib', 'config'))(path.resolve(rootPath, 'test', 'mocks'), {config: 'unitTest'});
    var file = '';
    var mail = null; // require(path.resolve(__dirname, '../', 'lib', 'mail'))(configMock.mail);  // {type: 'PICKUP', directory: './test/eml', from: 'from@test.com', to: 'to@test.com'}

    beforeEach(function (done) {

        if(!fs.existsSync(emlDir)) {

            fs.mkdirSync(emlDir);
        }

        if(mail === null) {
            mail = require(path.resolve(__dirname, '../', 'lib', 'mail'))(configMock.mail);
        }

        done();
    });

    it('should throw an initialization error', function (done) {
        expect(function () {
            require(path.resolve(__dirname, '../', 'lib', 'mail'))(1);
        }).toThrow('Parameter config is required!');

        done();
    });

    it('should throw an initialization error with wrong transport type', function (done) {
        expect(function () {
            return require(path.resolve(__dirname, '../', 'lib', 'mail'))({type: 'SES', directory: './eml'});
        }).toThrow('Only SMTP or PICKUP allowed!');

        done();
    });

    it('should set an empty type to SMTP', function (done) {
        var obj = {type: '', directory: emlDir};
        require(path.resolve(__dirname, '../', 'lib', 'mail'))(obj);
        expect(obj.type).toBe('SMTP');

        done();
    });

    it('should send a normal mail to file system', function (done) {
        var message = {
            from: 'test@test.com',
            to: 'to@test.com',
            subject: 'Unit test',
            text: 'This is a test.',
            html: '
This is a test.
'
        };

        mail.sendMail(message, function (error, result) {
            expect(error).toBe(null);
            expect(result).toBeDefined();
            expect(result.path).toBeDefined();

            var exists = fs.existsSync(result.path);
            expect(exists).toBeTruthy();
            file = result.path;

            done();
        });
    });

    it('should send a normal mail, with default values for to and from, to file system', function (done) {
        var message = {
            subject: 'Unit test',
            text: 'This is a test.',
            html: '
This is a test.
'
        };

        mail.sendMail(message, function (error, result) {
            expect(error).toBe(null);
            expect(result).toBeDefined();
            expect(result.path).toBeDefined();

            var exists = fs.existsSync(result.path);
            expect(exists).toBeTruthy();
            file = result.path;

            done();
        });
    });

     it('should send a mail from template to file system', function (done) {
        var message = { from: 'test@test.com', to: 'to@test.com', subject: 'Unit test' };

        mail.sendMailFromTemplate(message, 'mail.html', 'mail.txt', [{ key: '{DYNAMIC}', value: 'Test value' }], function (error, result) {
            expect(error).toBe(null);
            expect(result).toBeDefined();
            expect(result.path).toBeDefined();
            var exists = fs.existsSync(result.path);
            expect(exists).toBeTruthy();
            file = result.path;

            done();
        });
    });

    it('should send a mail from template with missing html template to file system', function (done) {
        var message = { from: 'test@test.com', to: 'to@test.com', subject: 'Unit test' };

        mail.sendMailFromTemplate(message, null, 'mail.txt', [
            {key: '{DYNAMIC}', value: 'Test value'}
        ], function (error, result) {
            expect(error).toBe(null);
            expect(result).toBeDefined();
            expect(result.path).toBeDefined();
            var exists = fs.existsSync(result.path);
            expect(exists).toBeTruthy();
            file = result.path;

            done();
        });
    });

    it('should send a mail from template with missing txt template to file system', function (done) {
        var message = { from: 'test@test.com', to: 'to@test.com', subject: 'Unit test' };

        mail.sendMailFromTemplate(message, 'mail.html', null, [
            {key: '{DYNAMIC}', value: 'Test value'}
        ], function (error, result) {
            expect(error).toBe(null);
            expect(result).toBeDefined();
            expect(result.path).toBeDefined();
            var exists = fs.existsSync(result.path);
            expect(exists).toBeTruthy();
            file = result.path;

            done();
        });
    });

    it('should send a mail from template, with missing replace value for an existing key, to file system', function (done) {
        var message = { from: 'test@test.com', to: 'to@test.com', subject: 'Unit test' };

        mail.sendMailFromTemplate(message, 'mail.html', 'mail.txt', [
            {key: '{DYNAMIC}', value: null}
        ], function (error, result) {
            expect(error).toBe(null);
            expect(result).toBeDefined();
            expect(result.path).toBeDefined();
            var exists = fs.existsSync(result.path);
            expect(exists).toBeTruthy();
            file = result.path;

            done();
        });
    });

    it('should send a mail from template, with missing replace values, to file system', function (done) {
        var message = { from: 'test@test.com', to: 'to@test.com', subject: 'Unit test' };

        mail.sendMailFromTemplate(message, 'mail.html', 'mail.txt', null, function (error, result) {
            expect(error).toBe(null);
            expect(result).toBeDefined();
            expect(result.path).toBeDefined();
            var exists = fs.existsSync(result.path);
            expect(exists).toBeTruthy();
            file = result.path;

            done();
        });
    });

/*    it('should end with an error because template path is invalid', function (done) {
        var message = { from: 'test@test.com', to: 'to@test.com', subject: 'Unit test' };

        expect(function () {
            mail.sendMailFromTemplate(message, 'missing.html', null, [
                {key: '{DYNAMIC}', value: 'Test value'}
            ], function (error) {
                expect(error).toBeDefined();
                done();
            });
        }).toThrow();
        *//*mail.sendMailFromTemplate(message, 'missing.html', null, [
            {key: '{DYNAMIC}', value: 'Test value'}
        ], function (error) {
            expect(error).toBeDefined();
            done();
        });*//*

        done();
    });*/

    afterEach(function () {
        if(fs.existsSync(file)) {
            fs.unlinkSync(file);
        }
    });
});<commit_msg>test: try to fix travis test error<commit_after>'use strict';

/* global describe, it, expect, beforeEach, afterEach */
describe('Mail', function () {
    var path = require('path');
    var fs = require('fs');
    var rootPath = path.resolve(__dirname, '../');
    var emlDir = path.resolve(__dirname, 'eml');

    console.log('emlDir');
    console.log(emlDir);

    console.log('fs.existsSync(emlDir)');
    console.log(fs.existsSync(emlDir));

    var configMock = require(path.resolve(rootPath, 'lib', 'config'))(path.resolve(rootPath, 'test', 'mocks'), {config: 'unitTest'});
    var file = '';
    var mail = null; // require(path.resolve(__dirname, '../', 'lib', 'mail'))(configMock.mail);  // {type: 'PICKUP', directory: './test/eml', from: 'from@test.com', to: 'to@test.com'}

    beforeEach(function (done) {

        if(!fs.existsSync(emlDir)) {

            fs.mkdirSync(emlDir);
        }

        if(mail === null) {
            mail = require(path.resolve(__dirname, '../', 'lib', 'mail'))(configMock.mail);
        }

        done();
    });

    it('should throw an initialization error', function (done) {
        expect(function () {
            require(path.resolve(__dirname, '../', 'lib', 'mail'))(1);
        }).toThrow('Parameter config is required!');

        done();
    });

    it('should throw an initialization error with wrong transport type', function (done) {
        expect(function () {
            return require(path.resolve(__dirname, '../', 'lib', 'mail'))({type: 'SES', directory: './eml'});
        }).toThrow('Only SMTP or PICKUP allowed!');

        done();
    });

    it('should set an empty type to SMTP', function (done) {
        var obj = {type: '', directory: emlDir};
        require(path.resolve(__dirname, '../', 'lib', 'mail'))(obj);
        expect(obj.type).toBe('SMTP');

        done();
    });

    it('should send a normal mail to file system', function (done) {
        var message = {
            from: 'test@test.com',
            to: 'to@test.com',
            subject: 'Unit test',
            text: 'This is a test.',
            html: '
This is a test.
'
        };

        mail.sendMail(message, function (error, result) {
            expect(error).toBe(null);
            expect(result).toBeDefined();
            expect(result.path).toBeDefined();

            var exists = fs.existsSync(result.path);
            expect(exists).toBeTruthy();
            file = result.path;

            done();
        });
    });

    it('should send a normal mail, with default values for to and from, to file system', function (done) {
        var message = {
            subject: 'Unit test',
            text: 'This is a test.',
            html: '
This is a test.
'
        };

        mail.sendMail(message, function (error, result) {
            expect(error).toBe(null);
            expect(result).toBeDefined();
            expect(result.path).toBeDefined();

            var exists = fs.existsSync(result.path);
            expect(exists).toBeTruthy();
            file = result.path;

            done();
        });
    });

     it('should send a mail from template to file system', function (done) {
        var message = { from: 'test@test.com', to: 'to@test.com', subject: 'Unit test' };

        mail.sendMailFromTemplate(message, 'mail.html', 'mail.txt', [{ key: '{DYNAMIC}', value: 'Test value' }], function (error, result) {
            expect(error).toBe(null);
            expect(result).toBeDefined();
            expect(result.path).toBeDefined();
            var exists = fs.existsSync(result.path);
            expect(exists).toBeTruthy();
            file = result.path;

            done();
        });
    });

    it('should send a mail from template with missing html template to file system', function (done) {
        var message = { from: 'test@test.com', to: 'to@test.com', subject: 'Unit test' };

        mail.sendMailFromTemplate(message, null, 'mail.txt', [
            {key: '{DYNAMIC}', value: 'Test value'}
        ], function (error, result) {
            expect(error).toBe(null);
            expect(result).toBeDefined();
            expect(result.path).toBeDefined();
            var exists = fs.existsSync(result.path);
            expect(exists).toBeTruthy();
            file = result.path;

            done();
        });
    });

    it('should send a mail from template with missing txt template to file system', function (done) {
        var message = { from: 'test@test.com', to: 'to@test.com', subject: 'Unit test' };

        mail.sendMailFromTemplate(message, 'mail.html', null, [
            {key: '{DYNAMIC}', value: 'Test value'}
        ], function (error, result) {
            expect(error).toBe(null);
            expect(result).toBeDefined();
            expect(result.path).toBeDefined();
            var exists = fs.existsSync(result.path);
            expect(exists).toBeTruthy();
            file = result.path;

            done();
        });
    });

    it('should send a mail from template, with missing replace value for an existing key, to file system', function (done) {
        var message = { from: 'test@test.com', to: 'to@test.com', subject: 'Unit test' };

        mail.sendMailFromTemplate(message, 'mail.html', 'mail.txt', [
            {key: '{DYNAMIC}', value: null}
        ], function (error, result) {
            expect(error).toBe(null);
            expect(result).toBeDefined();
            expect(result.path).toBeDefined();
            var exists = fs.existsSync(result.path);
            expect(exists).toBeTruthy();
            file = result.path;

            done();
        });
    });

    it('should send a mail from template, with missing replace values, to file system', function (done) {
        var message = { from: 'test@test.com', to: 'to@test.com', subject: 'Unit test' };

        mail.sendMailFromTemplate(message, 'mail.html', 'mail.txt', null, function (error, result) {
            expect(error).toBe(null);
            expect(result).toBeDefined();
            expect(result.path).toBeDefined();
            var exists = fs.existsSync(result.path);
            expect(exists).toBeTruthy();
            file = result.path;

            done();
        });
    });

/*    it('should end with an error because template path is invalid', function (done) {
        var message = { from: 'test@test.com', to: 'to@test.com', subject: 'Unit test' };

        expect(function () {
            mail.sendMailFromTemplate(message, 'missing.html', null, [
                {key: '{DYNAMIC}', value: 'Test value'}
            ], function (error) {
                expect(error).toBeDefined();
                done();
            });
        }).toThrow();
        *//*mail.sendMailFromTemplate(message, 'missing.html', null, [
            {key: '{DYNAMIC}', value: 'Test value'}
        ], function (error) {
            expect(error).toBeDefined();
            done();
        });*//*

        done();
    });*/

    afterEach(function () {
        if(fs.existsSync(file)) {
            fs.unlinkSync(file);
        }
    });
});<|endoftext|>


<commit_before>var fs = require('fs');
var separator = '############################################################################\n';
var respId = 0;
var variables = require('./variables');
var feedback_chatId = variables['feedback_chatId'];

function processOnText(msg, match) {
    var resp = null;
    var timestamp = new Date();
    var messagesToSend = [];
    var openingh = require('./openingh');
    var chatId = msg.chat.id;

    //Mensas, die Abendessen Haben
    var dinner_dict = {
        "poly" : "Mensa Polyterrasse",
        "pizzapasta" : "food market - pizza pasta"
    }

    //Übersetzt den einfacheren Befehl zum komplizierteren Mensanamen im JSON
    var dict = {
                "cliff" : "Clausiusbar",
                "haoyi" : "Woka",
                "poly" : "Mensa Polyterrasse",
                "foodlab" : "foodLAB",
                "clausiusbar" : "Clausiusbar",
                "asia" : "Clausiusbar",
                "fusion" : "FUSION meal",
                "woka" : "Woka",
                "tannenbar" : "Tannenbar",
                "trailer" : "Foodtrailer ETZ",
                "dozentenfoyer" : "Dozentenfoyer",
                "grill" : "food market - grill bbQ",
                "pizzapasta" : "food market - pizza pasta",
                "green" : "food market - green day",
        };

    console.log(msg);
    console.log(JSON.stringify(match));
    fs.appendFile('logs/requests.log', separator + timestamp + '\n\n' + JSON.stringify(msg) + '\n' + separator, function (err) {
        console.log(err);
    });
    //Feedback
    if(match[0].indexOf('/feedback') != -1 || match[0].indexOf('/respond') != -1) {
        if (match[0] === '/feedback'){
            resp = '*Feedback für Dummies:*\n/feedback <Deine Nachricht>';

        }else if(match[0].indexOf('/feedback')!=-1){
            respId=chatId;
            fs.appendFile('logs/feedback.log', separator + '\n\n' + timestamp + '\n\n' + JSON.stringify(msg) + '\n\n', function (err) {
                console.log(err);
            });
            resp = 'Vielen Dank für Dein Feedback!';

            messagesToSend.push({chatId:-106064170, message:'New feedback:\n\n' + JSON.stringify(msg)});
        }else if(match[0].indexOf('/respond') != -1){

            resp = match[0].split('respond');
            resp = resp[1];

            chatId = respId;
        }
    }else{
        //Chopping '@...' from the command if needed
        var command = match[1].split('@');
        command = command[0];
        //Nicht ideal weil ja nicht ein Strang, aber funktioniert so weit ganz gut (denke ich):
        //Checking whether a cafeteria has dinner and if its late enough to display the dinner menu
        if (command in dinner_dict && timestamp.getHours() >= 14){
            command = dinner_dict[command];
            var mensas = require('./mensas_abig.json');
            var t = 1;
        //Checking whether its a known cafeteria
        }else if (command in dict){
            command = dict[command];
            var mensas = require('./mensas.json');
            var t = 0;
        //...help/start, opening hours
        }

        if(command in openingh){
            resp = openingh[command];
        //Mensa
        }else if(command in mensas){

            //Weekend?
            if(timestamp.getDay() === 6 || timestamp.getDay() === 0){
                resp = "Heute haben leider alle Mensen geschlossen, sorry!";
            //If weekday, wanted information is formatted as follows:
            }else{
                if (mensas[command] != undefined){
                    resp = "*" + command + "*\n_Essen von " + mensas[command].hours.mealtime[t]["from"] +" bis " +mensas[command].hours.mealtime[t]["to"] + " Uhr_\n\n";
                    for (var meal in mensas[command]["meals"]){
                        var description = "";
                        for (i in mensas[command]["meals"][meal]["description"]){
                            description += mensas[command]["meals"][meal]["description"][i]+ " " ;
                            if (i === "0"){
                                description += "\n";
                            }
                        }
                        resp += "*" +mensas[command]["meals"][meal]["label"] + " (" + mensas[command]["meals"][meal]["prices"]["student"]+ "/" +mensas[command]["meals"][meal]["prices"]["staff"] +  "/" + mensas[command]["meals"][meal]["prices"]["extern"]+"):*\n" + description + "\n";
                    }
                }else{
                    resp = "Tut mir Leid, aber für diese Mensa ist momentan leider kein Menü verfügbar :(";
                }
            }
        }
}

    messagesToSend.push({chatId:chatId, message:resp, options:{parse_mode: 'Markdown'}});

    fs.appendFile('logs/handled_requests.log', separator + timestamp + '\n\n' + JSON.stringify(msg,null,2) + '\n+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\nRESPONSE:\n\n' + resp + '\n', function (err) {
        console.log(err);
    });

    return messagesToSend;
}
module.exports.processOnText = processOnText;
<commit_msg>update botmanager<commit_after>var fs = require('fs');
var separator = '############################################################################\n';
var respId = 0;
var variables = require('./variables');
var feedback_chatId = variables['feedback_chatId'];

function processOnText(msg, match) {
    var resp = null;
    var timestamp = new Date();
    var messagesToSend = [];
    var openingh = require('./openingh');
    var chatId = msg.chat.id;

    //Mensas, die Abendessen Haben
    var dinner_dict = {
        "poly" : "Mensa Polyterrasse",
        "pizzapasta" : "food market - pizza pasta"
    }

    //Übersetzt den einfacheren Befehl zum komplizierteren Mensanamen im JSON
    var dict = {
                "cliff" : "Clausiusbar",
                "haoyi" : "Woka",
                "poly" : "Mensa Polyterrasse",
                "foodlab" : "foodLAB",
                "clausiusbar" : "Clausiusbar",
                "asia" : "Clausiusbar",
                "fusion" : "FUSION meal",
                "woka" : "Woka",
                "tannenbar" : "Tannenbar",
                "trailer" : "Foodtrailer ETZ",
                "dozentenfoyer" : "Dozentenfoyer",
                "grill" : "food market - grill bbQ",
                "pizzapasta" : "food market - pizza pasta",
                "green" : "food market - green day",
        };

    console.log(msg);
    console.log(JSON.stringify(match));
    fs.appendFile('logs/requests.log', separator + timestamp + '\n\n' + JSON.stringify(msg) + '\n' + separator, function (err) {
        console.log(err);
    });
    //Feedback
    if(match[0].indexOf('/feedback') != -1 || match[0].indexOf('/respond') != -1) {
        if (match[0] === '/feedback'){
            resp = '*Feedback für Dummies:*\n/feedback <Deine Nachricht>';

        }else if(match[0].indexOf('/feedback')!=-1){
            respId=chatId;
            fs.appendFile('logs/feedback.log', separator + '\n\n' + timestamp + '\n\n' + JSON.stringify(msg) + '\n\n', function (err) {
                console.log(err);
            });
            resp = 'Vielen Dank für Dein Feedback!';

            messagesToSend.push({chatId:-106064170, message:'New feedback:\n\n' + JSON.stringify(msg)});
        }else if(match[0].indexOf('/respond') != -1){

            resp = match[0].split('respond');
            resp = resp[1];

            chatId = respId;
        }
    }else{
        //Chopping '@...' from the command if needed
        var command = match[1].split('@');
        command = command[0];
        //Nicht ideal weil ja nicht ein Strang, aber funktioniert so weit ganz gut (denke ich):
        //Checking whether a cafeteria has dinner and if its late enough to display the dinner menu
        if (command in dinner_dict && timestamp.getHours() >= 14){
            command = dinner_dict[command];
            var mensas = require('./mensas_abig.json');
            var t = 1;
        //Checking whether its a known cafeteria
        }else if (command in dict){
            command = dict[command];
            var mensas = require('./mensas.json');
            var t = 0;
        //...help/start, opening hours
        }

        if(command in openingh){
            resp = openingh[command];
        //Mensa
        }else if(command in mensas){

            //Weekend?
            if(timestamp.getDay() === 6 || timestamp.getDay() === 0){
                resp = "Heute haben leider alle Mensen geschlossen, sorry!";
            //If weekday, wanted information is formatted as follows:
            }else{
                if (!(command in mensas)){
                    resp = "*" + command + "*\n_Essen von " + mensas[command].hours.mealtime[t]["from"] +" bis " +mensas[command].hours.mealtime[t]["to"] + " Uhr_\n\n";
                    for (var meal in mensas[command]["meals"]){
                        var description = "";
                        for (i in mensas[command]["meals"][meal]["description"]){
                            description += mensas[command]["meals"][meal]["description"][i]+ " " ;
                            if (i === "0"){
                                description += "\n";
                            }
                        }
                        resp += "*" +mensas[command]["meals"][meal]["label"] + " (" + mensas[command]["meals"][meal]["prices"]["student"]+ "/" +mensas[command]["meals"][meal]["prices"]["staff"] +  "/" + mensas[command]["meals"][meal]["prices"]["extern"]+"):*\n" + description + "\n";
                    }
                }else{
                    resp = "Tut mir Leid, aber für diese Mensa ist momentan leider kein Menü verfügbar :(";
                }
            }
        }
}

    messagesToSend.push({chatId:chatId, message:resp, options:{parse_mode: 'Markdown'}});

    fs.appendFile('logs/handled_requests.log', separator + timestamp + '\n\n' + JSON.stringify(msg,null,2) + '\n+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\nRESPONSE:\n\n' + resp + '\n', function (err) {
        console.log(err);
    });

    return messagesToSend;
}
module.exports.processOnText = processOnText;
<|endoftext|>


<commit_before>import chai from 'chai'
import * as f from '../lib/futil-js'
chai.expect()
const expect = chai.expect

describe('Basic Functions', function() {
    it('wrap', function() {
        expect(f.wrap('(', ')', 'asdf')).to.equal('(asdf)')
    })
    it('maybeCall', function() {
        expect(f.maybeCall(x => 5)).to.deep.equal(5)
        expect(f.maybeCall(null)).to.deep.equal(false)
    })
})<commit_msg>add maybeCall test<commit_after>import chai from 'chai'
import * as f from '../lib/futil-js'
chai.expect()
const expect = chai.expect

describe('Basic Functions', function() {
    it('wrap', function() {
        expect(f.wrap('(', ')', 'asdf')).to.equal('(asdf)')
    })
    it('maybeCall', function() {
        expect(f.maybeCall(x => 5)).to.deep.equal(5)
        expect(f.maybeCall(null)).to.deep.equal(false)
    })
    it('maybeCall should call fn with parameters', function(){
        const fn = (x,y) => x+y;
        expect(maybeCall(fn, 5, 6)).to.deep.equal(fn(5,6));
    })
})
<|endoftext|>


<commit_before>/**
 * Helper to test CodeMirror highlighting modes. It pretty prints output of the
 * highlighter and can check against expected styles.
 *
 * Mode tests are registered by calling test.mode(testName, mode,
 * tokens), where mode is a mode object as returned by
 * CodeMirror.getMode, and tokens is an array of lines that make up
 * the test.
 *
 * These lines are strings, in which styled stretches of code are
 * enclosed in brackets `[]`, and prefixed by their style. For
 * example, `[keyword if]`. Brackets in the code itself must be
 * duplicated to prevent them from being interpreted as token
 * boundaries. For example `a[[i]]` for `a[i]`. If a token has
 * multiple styles, the styles must be separated by ampersands, for
 * example `[tag&error </hmtl>]`.
 *
 * See the test.js files in the css, markdown, gfm, and stex mode
 * directories for examples.
 */
(function() {
  function findSingle(str, pos, ch) {
    for (;;) {
      var found = str.indexOf(ch, pos);
      if (found == -1) return null;
      if (str.charAt(found + 1) != ch) return found;
      pos = found + 2;
    }
  }

  var styleName = /[\w&-_]+/g;
  function parseTokens(strs) {
    var tokens = [], plain = "";
    for (var i = 0; i < strs.length; ++i) {
      if (i) plain += "\n";
      var str = strs[i], pos = 0;
      while (pos < str.length) {
        var style = null, text;
        if (str.charAt(pos) == "[" && str.charAt(pos+1) != "[") {
          styleName.lastIndex = pos + 1;
          var m = styleName.exec(str);
          style = m[0].replace(/&/g, " ");
          var textStart = pos + style.length + 2;
          var end = findSingle(str, textStart, "]");
          if (end == null) throw new Error("Unterminated token at " + pos + " in '" + str + "'" + style);
          text = str.slice(textStart, end);
          pos = end + 1;
        } else {
          var end = findSingle(str, pos, "[");
          if (end == null) end = str.length;
          text = str.slice(pos, end);
          pos = end;
        }
        text = text.replace(/\[\[|\]\]/g, function(s) {return s.charAt(0);});
        tokens.push({style: style, text: text});
        plain += text;
      }
    }
    return {tokens: tokens, plain: plain};
  }

  test.mode = function(name, mode, tokens, modeName) {
    var data = parseTokens(tokens);
    return test((modeName || mode.name) + "_" + name, function() {
      return compare(data.plain, data.tokens, mode);
    });
  };

  function esc(str) {
    return str.replace('&', '&').replace('<', '<').replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
;
  }

  function compare(text, expected, mode) {

    var expectedOutput = [];
    for (var i = 0; i < expected.length; ++i) {
      var sty = expected[i].style;
      if (sty && sty.indexOf(" ")) sty = sty.split(' ').sort().join(' ');
      expectedOutput.push({style: sty, text: expected[i].text});
    }

    var observedOutput = highlight(text, mode);

    var s = "";
    var diff = highlightOutputsDifferent(expectedOutput, observedOutput);
    if (diff != null) {
      s += '
';
      s +=   '
' + esc(text) + '
';
      s +=   '
';
      s += 'expected:';
      s +=   prettyPrintOutputTable(expectedOutput, diff);
      s += 'observed: [display states]';
      s +=   prettyPrintOutputTable(observedOutput, diff);
      s +=   '
';
      s += '
';
    }
    if (observedOutput.indentFailures) {
      for (var i = 0; i < observedOutput.indentFailures.length; i++)
        s += "
" + esc(observedOutput.indentFailures[i]) + "
";
    }
    if (s) throw new Failure(s);
  }

  function stringify(obj) {
    function replacer(key, obj) {
      if (typeof obj == "function") {
        var m = obj.toString().match(/function\s*[^\s(]*/);
        return m ? m[0] : "function";
      }
      return obj;
    }
    if (window.JSON && JSON.stringify)
      return JSON.stringify(obj, replacer, 2);
    return "[unsupported]";  // Fail safely if no native JSON.
  }

  function highlight(string, mode) {
    var state = mode.startState();

    var lines = string.replace(/\r\n/g,'\n').split('\n');
    var st = [], pos = 0;
    for (var i = 0; i < lines.length; ++i) {
      var line = lines[i], newLine = true;
      if (mode.indent) {
        var ws = line.match(/^\s*/)[0];
        var indent = mode.indent(state, line.slice(ws.length));
        if (indent != CodeMirror.Pass && indent != ws.length)
          (st.indentFailures || (st.indentFailures = [])).push(
            "Indentation of line " + (i + 1) + " is " + indent + " (expected " + ws.length + ")");
      }
      var stream = new CodeMirror.StringStream(line);
      if (line == "" && mode.blankLine) mode.blankLine(state);
      /* Start copied code from CodeMirror.highlight */
      while (!stream.eol()) {
        for (var j = 0; j < 10 && stream.start >= stream.pos; j++)
          var compare = mode.token(stream, state);
        if (j == 10)
          throw new Failure("Failed to advance the stream." + stream.string + " " + stream.pos);
        var substr = stream.current();
        if (compare && compare.indexOf(" ") > -1) compare = compare.split(' ').sort().join(' ');
        stream.start = stream.pos;
        if (pos && st[pos-1].style == compare && !newLine) {
          st[pos-1].text += substr;
        } else if (substr) {
          st[pos++] = {style: compare, text: substr, state: stringify(state)};
        }
        // Give up when line is ridiculously long
        if (stream.pos > 5000) {
          st[pos++] = {style: null, text: this.text.slice(stream.pos)};
          break;
        }
        newLine = false;
      }
    }

    return st;
  }

  function highlightOutputsDifferent(o1, o2) {
    var minLen = Math.min(o1.length, o2.length);
    for (var i = 0; i < minLen; ++i)
      if (o1[i].style != o2[i].style || o1[i].text != o2[i].text) return i;
    if (o1.length > minLen || o2.length > minLen) return minLen;
  }

  function prettyPrintOutputTable(output, diffAt) {
    var s = '
';
    s += '
';
    for (var i = 0; i < output.length; ++i) {
      var style = output[i].style, val = output[i].text;
      s +=
      '' +
        '' +
        esc(val.replace(/ /g,'\xb7')) +  // · MIDDLE DOT
        '' +
        '	';
    }
    s += '

';
    for (var i = 0; i < output.length; ++i) {
      s += '' + (output[i].style || null) + '	';
    }
    if(output[0].state) {
      s += '

';
      for (var i = 0; i < output.length; ++i) {
        s += '
' + esc(output[i].state) + '
	';
      }
    }
    s += '

';
    return s;
  }
})();
<commit_msg>Remove stray semicolon in mode_test.js<commit_after>/**
 * Helper to test CodeMirror highlighting modes. It pretty prints output of the
 * highlighter and can check against expected styles.
 *
 * Mode tests are registered by calling test.mode(testName, mode,
 * tokens), where mode is a mode object as returned by
 * CodeMirror.getMode, and tokens is an array of lines that make up
 * the test.
 *
 * These lines are strings, in which styled stretches of code are
 * enclosed in brackets `[]`, and prefixed by their style. For
 * example, `[keyword if]`. Brackets in the code itself must be
 * duplicated to prevent them from being interpreted as token
 * boundaries. For example `a[[i]]` for `a[i]`. If a token has
 * multiple styles, the styles must be separated by ampersands, for
 * example `[tag&error </hmtl>]`.
 *
 * See the test.js files in the css, markdown, gfm, and stex mode
 * directories for examples.
 */
(function() {
  function findSingle(str, pos, ch) {
    for (;;) {
      var found = str.indexOf(ch, pos);
      if (found == -1) return null;
      if (str.charAt(found + 1) != ch) return found;
      pos = found + 2;
    }
  }

  var styleName = /[\w&-_]+/g;
  function parseTokens(strs) {
    var tokens = [], plain = "";
    for (var i = 0; i < strs.length; ++i) {
      if (i) plain += "\n";
      var str = strs[i], pos = 0;
      while (pos < str.length) {
        var style = null, text;
        if (str.charAt(pos) == "[" && str.charAt(pos+1) != "[") {
          styleName.lastIndex = pos + 1;
          var m = styleName.exec(str);
          style = m[0].replace(/&/g, " ");
          var textStart = pos + style.length + 2;
          var end = findSingle(str, textStart, "]");
          if (end == null) throw new Error("Unterminated token at " + pos + " in '" + str + "'" + style);
          text = str.slice(textStart, end);
          pos = end + 1;
        } else {
          var end = findSingle(str, pos, "[");
          if (end == null) end = str.length;
          text = str.slice(pos, end);
          pos = end;
        }
        text = text.replace(/\[\[|\]\]/g, function(s) {return s.charAt(0);});
        tokens.push({style: style, text: text});
        plain += text;
      }
    }
    return {tokens: tokens, plain: plain};
  }

  test.mode = function(name, mode, tokens, modeName) {
    var data = parseTokens(tokens);
    return test((modeName || mode.name) + "_" + name, function() {
      return compare(data.plain, data.tokens, mode);
    });
  };

  function esc(str) {
    return str.replace('&', '&').replace('<', '<').replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
  }

  function compare(text, expected, mode) {

    var expectedOutput = [];
    for (var i = 0; i < expected.length; ++i) {
      var sty = expected[i].style;
      if (sty && sty.indexOf(" ")) sty = sty.split(' ').sort().join(' ');
      expectedOutput.push({style: sty, text: expected[i].text});
    }

    var observedOutput = highlight(text, mode);

    var s = "";
    var diff = highlightOutputsDifferent(expectedOutput, observedOutput);
    if (diff != null) {
      s += '
';
      s +=   '
' + esc(text) + '
';
      s +=   '
';
      s += 'expected:';
      s +=   prettyPrintOutputTable(expectedOutput, diff);
      s += 'observed: [display states]';
      s +=   prettyPrintOutputTable(observedOutput, diff);
      s +=   '
';
      s += '
';
    }
    if (observedOutput.indentFailures) {
      for (var i = 0; i < observedOutput.indentFailures.length; i++)
        s += "
" + esc(observedOutput.indentFailures[i]) + "
";
    }
    if (s) throw new Failure(s);
  }

  function stringify(obj) {
    function replacer(key, obj) {
      if (typeof obj == "function") {
        var m = obj.toString().match(/function\s*[^\s(]*/);
        return m ? m[0] : "function";
      }
      return obj;
    }
    if (window.JSON && JSON.stringify)
      return JSON.stringify(obj, replacer, 2);
    return "[unsupported]";  // Fail safely if no native JSON.
  }

  function highlight(string, mode) {
    var state = mode.startState();

    var lines = string.replace(/\r\n/g,'\n').split('\n');
    var st = [], pos = 0;
    for (var i = 0; i < lines.length; ++i) {
      var line = lines[i], newLine = true;
      if (mode.indent) {
        var ws = line.match(/^\s*/)[0];
        var indent = mode.indent(state, line.slice(ws.length));
        if (indent != CodeMirror.Pass && indent != ws.length)
          (st.indentFailures || (st.indentFailures = [])).push(
            "Indentation of line " + (i + 1) + " is " + indent + " (expected " + ws.length + ")");
      }
      var stream = new CodeMirror.StringStream(line);
      if (line == "" && mode.blankLine) mode.blankLine(state);
      /* Start copied code from CodeMirror.highlight */
      while (!stream.eol()) {
        for (var j = 0; j < 10 && stream.start >= stream.pos; j++)
          var compare = mode.token(stream, state);
        if (j == 10)
          throw new Failure("Failed to advance the stream." + stream.string + " " + stream.pos);
        var substr = stream.current();
        if (compare && compare.indexOf(" ") > -1) compare = compare.split(' ').sort().join(' ');
        stream.start = stream.pos;
        if (pos && st[pos-1].style == compare && !newLine) {
          st[pos-1].text += substr;
        } else if (substr) {
          st[pos++] = {style: compare, text: substr, state: stringify(state)};
        }
        // Give up when line is ridiculously long
        if (stream.pos > 5000) {
          st[pos++] = {style: null, text: this.text.slice(stream.pos)};
          break;
        }
        newLine = false;
      }
    }

    return st;
  }

  function highlightOutputsDifferent(o1, o2) {
    var minLen = Math.min(o1.length, o2.length);
    for (var i = 0; i < minLen; ++i)
      if (o1[i].style != o2[i].style || o1[i].text != o2[i].text) return i;
    if (o1.length > minLen || o2.length > minLen) return minLen;
  }

  function prettyPrintOutputTable(output, diffAt) {
    var s = '
';
    s += '
';
    for (var i = 0; i < output.length; ++i) {
      var style = output[i].style, val = output[i].text;
      s +=
      '' +
        '' +
        esc(val.replace(/ /g,'\xb7')) +  // · MIDDLE DOT
        '' +
        '	';
    }
    s += '

';
    for (var i = 0; i < output.length; ++i) {
      s += '' + (output[i].style || null) + '	';
    }
    if(output[0].state) {
      s += '

';
      for (var i = 0; i < output.length; ++i) {
        s += '
' + esc(output[i].state) + '
	';
      }
    }
    s += '

';
    return s;
  }
})();
<|endoftext|>


<commit_before>module.exports = {
    assets: {
        files: [{
            src: ['dist/index.html']
        }]
    },
    options: {
        deleteOriginals: true
    }
};<commit_msg>Fixed an issue with the apple icons being cache busted<commit_after>module.exports = {
    assets: {
        files: [{
            src: ['dist/index.html']
        }]
    },
    options: {
        deleteOriginals: true,
        ignorePatterns: ['touch-icon-ipad']
    }
};
<|endoftext|>


<commit_before>const Parser = require("tree-sitter");
const { TextBuffer } = require("superstring");
const { assert } = require("chai");
const ARITHMETIC = require('./fixtures/arithmetic_language');

describe("Node", () => {
  let parser;

  beforeEach(() => {
    parser = new Parser().setLanguage(ARITHMETIC);
  });

  describe(".children", () => {
    it("returns an array of child nodes", () => {
      const tree = parser.parse("x10 + 1000");
      const sumNode = tree.rootNode.firstChild;
      assert.equal(1, tree.rootNode.children.length);
      assert.deepEqual(
        sumNode.children.map(child => child.type),
        ["variable", "+", "number"]
      );
    });
  });

  describe(".namedChildren", () => {
    it("returns an array of named child nodes", () => {
      const tree = parser.parse("x10 + 1000");
      const sumNode = tree.rootNode.firstChild;
      assert.equal(1, tree.rootNode.namedChildren.length);
      assert.deepEqual(
        ["variable", "number"],
        sumNode.namedChildren.map(child => child.type)
      );
    });
  });

  describe(".startIndex and .endIndex", () => {
    it("returns the character index where the node starts/ends in the text", () => {
      const tree = parser.parse("a👍👎1 / b👎c👎");
      const quotientNode = tree.rootNode.firstChild;

      assert.equal(0, quotientNode.startIndex);
      assert.equal(15, quotientNode.endIndex);
      assert.deepEqual(
        [0, 7, 9],
        quotientNode.children.map(child => child.startIndex)
      );
      assert.deepEqual(
        [6, 8, 15],
        quotientNode.children.map(child => child.endIndex)
      );
    });
  });

  describe(".startPosition and .endPosition", () => {
    it("returns the row and column where the node starts/ends in the text", () => {
      const tree = parser.parse("x10 + 1000");
      const sumNode = tree.rootNode.firstChild;
      assert.equal("sum", sumNode.type);

      assert.deepEqual({ row: 0, column: 0 }, sumNode.startPosition);
      assert.deepEqual({ row: 0, column: 10 }, sumNode.endPosition);
      assert.deepEqual(
        [{ row: 0, column: 0 }, { row: 0, column: 4 }, { row: 0, column: 6 }],
        sumNode.children.map(child => child.startPosition)
      );
      assert.deepEqual(
        [{ row: 0, column: 3 }, { row: 0, column: 5 }, { row: 0, column: 10 }],
        sumNode.children.map(child => child.endPosition)
      );
    });

    it("handles characters that occupy two UTF16 code units", () => {
      const tree = parser.parse("a👍👎1 /\n b👎c👎");
      const sumNode = tree.rootNode.firstChild;
      assert.deepEqual(
        [
          [{ row: 0, column: 0 }, { row: 0, column: 6 }],
          [{ row: 0, column: 7 }, { row: 0, column: 8 }],
          [{ row: 1, column: 1 }, { row: 1, column: 7 }]
        ],
        sumNode.children.map(child => [child.startPosition, child.endPosition])
      );
    });
  });

  describe(".parent", () => {
    it("returns the node's parent", () => {
      const tree = parser.parse("x10 + 1000");
      const sumNode = tree.rootNode.firstChild;
      const variableNode = sumNode.firstChild;
      assert.equal(sumNode, variableNode.parent);
      assert.equal(tree.rootNode, sumNode.parent);
    });
  });

  describe(".nextSibling and .previousSibling", () => {
    it("returns the node's next and previous sibling", () => {
      const tree = parser.parse("x10 + 1000");
      const sumNode = tree.rootNode.firstChild;
      assert.equal(sumNode.children[1], sumNode.children[0].nextSibling);
      assert.equal(sumNode.children[2], sumNode.children[1].nextSibling);
      assert.equal(
        sumNode.children[0],
        sumNode.children[1].previousSibling
      );
      assert.equal(
        sumNode.children[1],
        sumNode.children[2].previousSibling
      );
    });
  });

  describe(".nextNamedSibling and .previousNamedSibling", () => {
    it("returns the node's next and previous named sibling", () => {
      const tree = parser.parse("x10 + 1000");
      const sumNode = tree.rootNode.firstChild;
      assert.equal(
        sumNode.namedChildren[1],
        sumNode.namedChildren[0].nextNamedSibling
      );
      assert.equal(
        sumNode.namedChildren[0],
        sumNode.namedChildren[1].previousNamedSibling
      );
    });
  });

  describe(".descendantForIndex(min, max)", () => {
    it("returns the smallest node that spans the given range", () => {
      const tree = parser.parse("x10 + 1000");
      const sumNode = tree.rootNode.firstChild;
      assert.equal("variable", sumNode.descendantForIndex(1, 2).type);
      assert.equal("+", sumNode.descendantForIndex(4, 4).type);

      assert.throws(() => {
        sumNode.descendantForIndex(1, {});
      }, /Character index must be a number/);

      assert.throws(() => {
        sumNode.descendantForIndex();
      }, /Character index must be a number/);
    });
  });

  describe(".namedDescendantForIndex", () => {
    it("returns the smallest node that spans the given range", () => {
      const tree = parser.parse("x10 + 1000");
      const sumNode = tree.rootNode.firstChild;
      assert.equal("variable", sumNode.descendantForIndex(1, 2).type);
      assert.equal("+", sumNode.descendantForIndex(4, 4).type);
    });
  });

  describe(".descendantForPosition(min, max)", () => {
    it("returns the smallest node that spans the given range", () => {
      const tree = parser.parse("x10 + 1000");
      const sumNode = tree.rootNode.firstChild;

      assert.equal(
        "variable",
        sumNode.descendantForPosition(
          { row: 0, column: 1 },
          { row: 0, column: 2 }
        ).type
      );

      assert.equal(
        "+",
        sumNode.descendantForPosition({ row: 0, column: 4 }).type
      );

      assert.throws(() => {
        sumNode.descendantForPosition(1, {});
      }, /Point.row must be a number/);

      assert.throws(() => {
        sumNode.descendantForPosition();
      }, /Point must be a .* object/);
    });
  });

  describe(".namedDescendantForPosition(min, max)", () => {
    it("returns the smallest named node that spans the given range", () => {
      const tree = parser.parse("x10 + 1000");
      const sumNode = tree.rootNode.firstChild;

      assert.equal(
        "variable",
        sumNode.namedDescendantForPosition(
          { row: 0, column: 1 },
          { row: 0, column: 2 }
        ).type
      );

      assert.equal(
        "sum",
        sumNode.namedDescendantForPosition({ row: 0, column: 4 }).type
      );
    });
  });

  describe('.descendantsOfType(type, min, max)', () => {
    it('finds all of the descendants of the given type in the given range', () => {
      const tree = parser.parse("a + 1 * b * 2 + c + 3");
      const outerSum = tree.rootNode.firstChild;
      let descendants = outerSum.descendantsOfType('number', {row: 0, column: 2}, {row: 0, column: 15})
      assert.deepEqual(
        descendants.map(node => node.startIndex),
        [4, 12]
      );

      descendants = outerSum.descendantsOfType('variable', {row: 0, column: 2}, {row: 0, column: 15})
      assert.deepEqual(
        descendants.map(node => node.startIndex),
        [8]
      );

      descendants = outerSum.descendantsOfType('variable', {row: 0, column: 0}, {row: 0, column: 30})
      assert.deepEqual(
        descendants.map(node => node.startIndex),
        [0, 8, 16]
      );

      descendants = outerSum.descendantsOfType('number', {row: 0, column: 0}, {row: 0, column: 30})
      assert.deepEqual(
        descendants.map(node => node.startIndex),
        [4, 12, 20]
      );

      descendants = outerSum.descendantsOfType('number')
      assert.deepEqual(
        descendants.map(node => node.startIndex),
        [4, 12, 20]
      );

      descendants = outerSum.firstChild.descendantsOfType('number', {row: 0, column: 0}, {row: 0, column: 30})
      assert.deepEqual(
        descendants.map(node => node.startIndex),
        [4, 12]
      );
    })
  })

  describe(".firstChildForIndex(index)", () => {
    it("returns the first child that extends beyond the given index", () => {
      const tree = parser.parse("x10 + 1000");
      const sumNode = tree.rootNode.firstChild;

      assert.equal("variable", sumNode.firstChildForIndex(0).type);
      assert.equal("variable", sumNode.firstChildForIndex(1).type);
      assert.equal("+", sumNode.firstChildForIndex(3).type);
      assert.equal("number", sumNode.firstChildForIndex(5).type);
    });
  });

  describe(".firstNamedChildForIndex(index)", () => {
    it("returns the first child that extends beyond the given index", () => {
      const tree = parser.parse("x10 + 1000");
      const sumNode = tree.rootNode.firstChild;

      assert.equal("variable", sumNode.firstNamedChildForIndex(0).type);
      assert.equal("variable", sumNode.firstNamedChildForIndex(1).type);
      assert.equal("number", sumNode.firstNamedChildForIndex(3).type);
    });
  });

  describe(".hasError()", () => {
    it("returns true if the node contains an error", () => {
      const tree = parser.parse("1 + 2 * * 3");
      const node = tree.rootNode;
      assert.equal(
        node.toString(),
        "(program (sum (number) (product (number) (ERROR) (number))))"
      );

      const sum = node.firstChild;
      assert(sum.hasError());
      assert(!sum.children[0].hasError());
      assert(!sum.children[1].hasError());
      assert(sum.children[2].hasError());
    });
  });

  describe(".isMissing()", () => {
    it("returns true if the node is missing from the source and was inserted via error recovery", () => {
      const tree = parser.parse("2 +");
      const node = tree.rootNode;
      assert.equal(node.toString(), "(program (sum (number) (MISSING)))");

      const sum = node.firstChild;
      assert(sum.hasError());
      assert(!sum.children[0].isMissing());
      assert(!sum.children[1].isMissing());
      assert(sum.children[2].isMissing());
    });
  });

  describe(".text", () => {
    it("returns the text of a node generated by .parse(String)", () => {
      const src = "α0 / b👎c👎"
      const [numeratorSrc, denominatorSrc] = src.split(/\s*\/\s+/)
      const tree = parser.parse(src);
      const quotientNode = tree.rootNode.firstChild;
      const [numerator, slash, denominator] = quotientNode.children;

      assert.equal(src, tree.rootNode.text,          'root node text');
      assert.equal(denominatorSrc, denominator.text, 'denominator text');
      assert.equal(src, quotientNode.text,           'quotient text');
      assert.equal(numeratorSrc, numerator.text,     'numerator text');
      assert.equal('/', slash.text,                  '"/" text');
    })

    it("returns the text of a node generated by .parse(Function)", () => {
      const src = "α0 / b👎c👎";
      const input = offset => src.substr(offset, 4);
      const [numeratorSrc, denominatorSrc] = src.split(/\s*\/\s+/);
      const tree = parser.parse(input);
      const quotientNode = tree.rootNode.firstChild;
      const [numerator, slash, denominator] = quotientNode.children;

      assert.equal(src, tree.rootNode.text,          'root node text');
      assert.equal(denominatorSrc, denominator.text, 'denominator text');
      assert.equal(src, quotientNode.text,           'quotient text');
      assert.equal(numeratorSrc, numerator.text,     'numerator text');
      assert.equal('/', slash.text,                  '"/" text');
    })

    it("returns the text of a node generated by .parseTextBuffer", async () => {
      const src = "α0 / b👎c👎"
      const [numeratorSrc, denominatorSrc] = src.split(/\s*\/\s+/);
      const tree = await parser.parseTextBuffer(new TextBuffer(src));
      const quotientNode = tree.rootNode.firstChild;
      const [numerator, slash, denominator] = quotientNode.children;

      assert.equal(src, tree.rootNode.text,          'root node text');
      assert.equal(denominatorSrc, denominator.text, 'denominator text');
      assert.equal(src, quotientNode.text,           'quotient text');
      assert.equal(numeratorSrc, numerator.text,     'numerator text');
      assert.equal('/', slash.text,                  '"/" text');
    })

    it("returns the text of a node generated by .parseTextBufferSync", () => {
      const src = "α0 / b👎c👎"
      const [numeratorSrc, denominatorSrc] = src.split(/\s*\/\s+/);
      const tree = parser.parseTextBufferSync(new TextBuffer(src));
      const quotientNode = tree.rootNode.firstChild;
      const [numerator, slash, denominator] = quotientNode.children;

      assert.equal(src, tree.rootNode.text,          'root node text');
      assert.equal(denominatorSrc, denominator.text, 'denominator text');
      assert.equal(src, quotientNode.text,           'quotient text');
      assert.equal(numeratorSrc, numerator.text,     'numerator text');
      assert.equal('/', slash.text,                  '"/" text');
    })
  })
});
<commit_msg>Deduplicate tests<commit_after>const Parser = require("tree-sitter");
const { TextBuffer } = require("superstring");
const { assert } = require("chai");
const ARITHMETIC = require('./fixtures/arithmetic_language');

describe("Node", () => {
  let parser;

  beforeEach(() => {
    parser = new Parser().setLanguage(ARITHMETIC);
  });

  describe(".children", () => {
    it("returns an array of child nodes", () => {
      const tree = parser.parse("x10 + 1000");
      const sumNode = tree.rootNode.firstChild;
      assert.equal(1, tree.rootNode.children.length);
      assert.deepEqual(
        sumNode.children.map(child => child.type),
        ["variable", "+", "number"]
      );
    });
  });

  describe(".namedChildren", () => {
    it("returns an array of named child nodes", () => {
      const tree = parser.parse("x10 + 1000");
      const sumNode = tree.rootNode.firstChild;
      assert.equal(1, tree.rootNode.namedChildren.length);
      assert.deepEqual(
        ["variable", "number"],
        sumNode.namedChildren.map(child => child.type)
      );
    });
  });

  describe(".startIndex and .endIndex", () => {
    it("returns the character index where the node starts/ends in the text", () => {
      const tree = parser.parse("a👍👎1 / b👎c👎");
      const quotientNode = tree.rootNode.firstChild;

      assert.equal(0, quotientNode.startIndex);
      assert.equal(15, quotientNode.endIndex);
      assert.deepEqual(
        [0, 7, 9],
        quotientNode.children.map(child => child.startIndex)
      );
      assert.deepEqual(
        [6, 8, 15],
        quotientNode.children.map(child => child.endIndex)
      );
    });
  });

  describe(".startPosition and .endPosition", () => {
    it("returns the row and column where the node starts/ends in the text", () => {
      const tree = parser.parse("x10 + 1000");
      const sumNode = tree.rootNode.firstChild;
      assert.equal("sum", sumNode.type);

      assert.deepEqual({ row: 0, column: 0 }, sumNode.startPosition);
      assert.deepEqual({ row: 0, column: 10 }, sumNode.endPosition);
      assert.deepEqual(
        [{ row: 0, column: 0 }, { row: 0, column: 4 }, { row: 0, column: 6 }],
        sumNode.children.map(child => child.startPosition)
      );
      assert.deepEqual(
        [{ row: 0, column: 3 }, { row: 0, column: 5 }, { row: 0, column: 10 }],
        sumNode.children.map(child => child.endPosition)
      );
    });

    it("handles characters that occupy two UTF16 code units", () => {
      const tree = parser.parse("a👍👎1 /\n b👎c👎");
      const sumNode = tree.rootNode.firstChild;
      assert.deepEqual(
        [
          [{ row: 0, column: 0 }, { row: 0, column: 6 }],
          [{ row: 0, column: 7 }, { row: 0, column: 8 }],
          [{ row: 1, column: 1 }, { row: 1, column: 7 }]
        ],
        sumNode.children.map(child => [child.startPosition, child.endPosition])
      );
    });
  });

  describe(".parent", () => {
    it("returns the node's parent", () => {
      const tree = parser.parse("x10 + 1000");
      const sumNode = tree.rootNode.firstChild;
      const variableNode = sumNode.firstChild;
      assert.equal(sumNode, variableNode.parent);
      assert.equal(tree.rootNode, sumNode.parent);
    });
  });

  describe(".nextSibling and .previousSibling", () => {
    it("returns the node's next and previous sibling", () => {
      const tree = parser.parse("x10 + 1000");
      const sumNode = tree.rootNode.firstChild;
      assert.equal(sumNode.children[1], sumNode.children[0].nextSibling);
      assert.equal(sumNode.children[2], sumNode.children[1].nextSibling);
      assert.equal(
        sumNode.children[0],
        sumNode.children[1].previousSibling
      );
      assert.equal(
        sumNode.children[1],
        sumNode.children[2].previousSibling
      );
    });
  });

  describe(".nextNamedSibling and .previousNamedSibling", () => {
    it("returns the node's next and previous named sibling", () => {
      const tree = parser.parse("x10 + 1000");
      const sumNode = tree.rootNode.firstChild;
      assert.equal(
        sumNode.namedChildren[1],
        sumNode.namedChildren[0].nextNamedSibling
      );
      assert.equal(
        sumNode.namedChildren[0],
        sumNode.namedChildren[1].previousNamedSibling
      );
    });
  });

  describe(".descendantForIndex(min, max)", () => {
    it("returns the smallest node that spans the given range", () => {
      const tree = parser.parse("x10 + 1000");
      const sumNode = tree.rootNode.firstChild;
      assert.equal("variable", sumNode.descendantForIndex(1, 2).type);
      assert.equal("+", sumNode.descendantForIndex(4, 4).type);

      assert.throws(() => {
        sumNode.descendantForIndex(1, {});
      }, /Character index must be a number/);

      assert.throws(() => {
        sumNode.descendantForIndex();
      }, /Character index must be a number/);
    });
  });

  describe(".namedDescendantForIndex", () => {
    it("returns the smallest node that spans the given range", () => {
      const tree = parser.parse("x10 + 1000");
      const sumNode = tree.rootNode.firstChild;
      assert.equal("variable", sumNode.descendantForIndex(1, 2).type);
      assert.equal("+", sumNode.descendantForIndex(4, 4).type);
    });
  });

  describe(".descendantForPosition(min, max)", () => {
    it("returns the smallest node that spans the given range", () => {
      const tree = parser.parse("x10 + 1000");
      const sumNode = tree.rootNode.firstChild;

      assert.equal(
        "variable",
        sumNode.descendantForPosition(
          { row: 0, column: 1 },
          { row: 0, column: 2 }
        ).type
      );

      assert.equal(
        "+",
        sumNode.descendantForPosition({ row: 0, column: 4 }).type
      );

      assert.throws(() => {
        sumNode.descendantForPosition(1, {});
      }, /Point.row must be a number/);

      assert.throws(() => {
        sumNode.descendantForPosition();
      }, /Point must be a .* object/);
    });
  });

  describe(".namedDescendantForPosition(min, max)", () => {
    it("returns the smallest named node that spans the given range", () => {
      const tree = parser.parse("x10 + 1000");
      const sumNode = tree.rootNode.firstChild;

      assert.equal(
        "variable",
        sumNode.namedDescendantForPosition(
          { row: 0, column: 1 },
          { row: 0, column: 2 }
        ).type
      );

      assert.equal(
        "sum",
        sumNode.namedDescendantForPosition({ row: 0, column: 4 }).type
      );
    });
  });

  describe('.descendantsOfType(type, min, max)', () => {
    it('finds all of the descendants of the given type in the given range', () => {
      const tree = parser.parse("a + 1 * b * 2 + c + 3");
      const outerSum = tree.rootNode.firstChild;
      let descendants = outerSum.descendantsOfType('number', {row: 0, column: 2}, {row: 0, column: 15})
      assert.deepEqual(
        descendants.map(node => node.startIndex),
        [4, 12]
      );

      descendants = outerSum.descendantsOfType('variable', {row: 0, column: 2}, {row: 0, column: 15})
      assert.deepEqual(
        descendants.map(node => node.startIndex),
        [8]
      );

      descendants = outerSum.descendantsOfType('variable', {row: 0, column: 0}, {row: 0, column: 30})
      assert.deepEqual(
        descendants.map(node => node.startIndex),
        [0, 8, 16]
      );

      descendants = outerSum.descendantsOfType('number', {row: 0, column: 0}, {row: 0, column: 30})
      assert.deepEqual(
        descendants.map(node => node.startIndex),
        [4, 12, 20]
      );

      descendants = outerSum.descendantsOfType('number')
      assert.deepEqual(
        descendants.map(node => node.startIndex),
        [4, 12, 20]
      );

      descendants = outerSum.firstChild.descendantsOfType('number', {row: 0, column: 0}, {row: 0, column: 30})
      assert.deepEqual(
        descendants.map(node => node.startIndex),
        [4, 12]
      );
    })
  })

  describe(".firstChildForIndex(index)", () => {
    it("returns the first child that extends beyond the given index", () => {
      const tree = parser.parse("x10 + 1000");
      const sumNode = tree.rootNode.firstChild;

      assert.equal("variable", sumNode.firstChildForIndex(0).type);
      assert.equal("variable", sumNode.firstChildForIndex(1).type);
      assert.equal("+", sumNode.firstChildForIndex(3).type);
      assert.equal("number", sumNode.firstChildForIndex(5).type);
    });
  });

  describe(".firstNamedChildForIndex(index)", () => {
    it("returns the first child that extends beyond the given index", () => {
      const tree = parser.parse("x10 + 1000");
      const sumNode = tree.rootNode.firstChild;

      assert.equal("variable", sumNode.firstNamedChildForIndex(0).type);
      assert.equal("variable", sumNode.firstNamedChildForIndex(1).type);
      assert.equal("number", sumNode.firstNamedChildForIndex(3).type);
    });
  });

  describe(".hasError()", () => {
    it("returns true if the node contains an error", () => {
      const tree = parser.parse("1 + 2 * * 3");
      const node = tree.rootNode;
      assert.equal(
        node.toString(),
        "(program (sum (number) (product (number) (ERROR) (number))))"
      );

      const sum = node.firstChild;
      assert(sum.hasError());
      assert(!sum.children[0].hasError());
      assert(!sum.children[1].hasError());
      assert(sum.children[2].hasError());
    });
  });

  describe(".isMissing()", () => {
    it("returns true if the node is missing from the source and was inserted via error recovery", () => {
      const tree = parser.parse("2 +");
      const node = tree.rootNode;
      assert.equal(node.toString(), "(program (sum (number) (MISSING)))");

      const sum = node.firstChild;
      assert(sum.hasError());
      assert(!sum.children[0].isMissing());
      assert(!sum.children[1].isMissing());
      assert(sum.children[2].isMissing());
    });
  });

  describe(".text", () => {
    Object.entries({
      '.parse(String)': (parser, src) => parser.parse(src),
      '.parse(Function)': (parser, src) =>
        parser.parse(offset => src.substr(offset, 4)),
      '.parseTextBuffer': (parser, src) =>
        parser.parseTextBuffer(new TextBuffer(src)),
      '.parseTextBufferSync': (parser, src) =>
        parser.parseTextBufferSync(new TextBuffer(src))
    }).forEach(([method, parse]) =>
      it(`returns the text of a node generated by ${method}`, async () => {
        const src = "α0 / b👎c👎"
        const [numeratorSrc, denominatorSrc] = src.split(/\s*\/\s+/)
        const tree = await parse(parser, src)
        const quotientNode = tree.rootNode.firstChild;
        const [numerator, slash, denominator] = quotientNode.children;

        assert.equal(src, tree.rootNode.text,          'root node text');
        assert.equal(denominatorSrc, denominator.text, 'denominator text');
        assert.equal(src, quotientNode.text,           'quotient text');
        assert.equal(numeratorSrc, numerator.text,     'numerator text');
        assert.equal('/', slash.text,                  '"/" text');
      })
    )
  })
});
<|endoftext|>