<commit_before>/* vim: set sw=4 ts=4 et tw=78: */
/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is the Narcissus JavaScript engine.
 *
 * The Initial Developer of the Original Code is
 * Brendan Eich <brendan@mozilla.org>.
 * Portions created by the Initial Developer are Copyright (C) 2004
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *   Tom Austin <taustin@ucsc.edu>
 *   Brendan Eich <brendan@mozilla.org>
 *   Shu-Yu Guo <shu@rfrn.org>
 *   Dave Herman <dherman@mozilla.com>
 *   Dimitris Vardoulakis <dimvar@ccs.neu.edu>
 *   Patrick Walton <pcwalton@mozilla.com>
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 *
 * ***** END LICENSE BLOCK ***** */

/*
 * Narcissus - JS implemented in JS.
 *
 * Lexical scanner.
 */

Narcissus.lexer = (function() {

    var definitions = Narcissus.definitions;

    // Set constants in the local scope.
    eval(definitions.consts);

    // Build up a trie of operator tokens.
    var opTokens = {};
    for (var op in definitions.opTypeNames) {
        if (op === '\n' || op === '.')
            continue;

        var node = opTokens;
        for (var i = 0; i < op.length; i++) {
            var ch = op[i];
            if (!(ch in node))
                node[ch] = {};
            node = node[ch];
            node.op = op;
        }
    }

    /*
     * Tokenizer :: (source, filename, line number) -> Tokenizer
     */
    function Tokenizer(s, f, l) {
        this.cursor = 0;
        this.source = String(s);
        this.tokens = [];
        this.tokenIndex = 0;
        this.lookahead = 0;
        this.scanNewlines = false;
        this.unexpectedEOF = false;
        this.filename = f || "";
        this.lineno = l || 1;
    }

    Tokenizer.prototype = {
        get done() {
            // We need to set scanOperand to true here because the first thing
            // might be a regexp.
            return this.peek(true) === END;
        },

        get token() {
            return this.tokens[this.tokenIndex];
        },

        match: function (tt, scanOperand) {
            return this.get(scanOperand) === tt || this.unget();
        },

        mustMatch: function (tt) {
            if (!this.match(tt)) {
                throw this.newSyntaxError("Missing " +
                                          definitions.tokens[tt].toLowerCase());
            }
            return this.token;
        },

        peek: function (scanOperand) {
            var tt, next;
            if (this.lookahead) {
                next = this.tokens[(this.tokenIndex + this.lookahead) & 3];
                tt = (this.scanNewlines && next.lineno !== this.lineno)
                     ? NEWLINE
                     : next.type;
            } else {
                tt = this.get(scanOperand);
                this.unget();
            }
            return tt;
        },

        peekOnSameLine: function (scanOperand) {
            this.scanNewlines = true;
            var tt = this.peek(scanOperand);
            this.scanNewlines = false;
            return tt;
        },

        // Eat comments and whitespace.
        skip: function () {
            var input = this.source;
            for (;;) {
                var ch = input[this.cursor++];
                var next = input[this.cursor];
                if (ch === '\n' && !this.scanNewlines) {
                    this.lineno++;
                } else if (ch === '/' && next === '*') {
                    this.cursor++;
                    for (;;) {
                        ch = input[this.cursor++];
                        if (ch === undefined)
                            throw this.newSyntaxError("Unterminated comment");

                        if (ch === '*') {
                            next = input[this.cursor];
                            if (next === '/') {
                                this.cursor++;
                                break;
                            }
                        } else if (ch === '\n') {
                            this.lineno++;
                        }
                    }
                } else if (ch === '/' && next === '/') {
                    this.cursor++;
                    for (;;) {
                        ch = input[this.cursor++];
                        if (ch === undefined)
                            return;

                        if (ch === '\n') {
                            this.lineno++;
                            break;
                        }
                    }
                } else if (ch !== ' ' && ch !== '\t') {
                    this.cursor--;
                    return;
                }
            }
        },

        // Lex the exponential part of a number, if present. Return true iff an
        // exponential part was found.
        lexExponent: function() {
            var input = this.source;
            var next = input[this.cursor];
            if (next === 'e' || next === 'E') {
                this.cursor++;
                ch = input[this.cursor++];
                if (ch === '+' || ch === '-')
                    ch = input[this.cursor++];

                if (ch < '0' || ch > '9')
                    throw this.newSyntaxError("Missing exponent");

                do {
                    ch = input[this.cursor++];
                } while (ch >= '0' && ch <= '9');
                this.cursor--;

                return true;
            }

            return false;
        },

        lexZeroNumber: function (ch) {
            var token = this.token, input = this.source;
            token.type = NUMBER;

            ch = input[this.cursor++];
            if (ch === '.') {
                do {
                    ch = input[this.cursor++];
                } while (ch >= '0' && ch <= '9');
                this.cursor--;

                this.lexExponent();
                token.value = parseFloat(token.start, this.cursor);
            } else if (ch === 'x' || ch === 'X') {
                do {
                    ch = input[this.cursor++];
                } while ((ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') ||
                         (ch >= 'A' && ch <= 'F'));
                this.cursor--;

                token.value = parseInt(input.substring(token.start, this.cursor));
            } else if (ch >= '0' && ch <= '7') {
                do {
                    ch = input[this.cursor++];
                } while (ch >= '0' && ch <= '7');
                this.cursor--;

                token.value = parseInt(input.substring(token.start, this.cursor));
            } else {
                this.cursor--;
                this.lexExponent();     // 0E1, &c.
                token.value = 0;
            }
        },

        lexNumber: function (ch) {
            var token = this.token, input = this.source;
            token.type = NUMBER;

            var floating = false;
            do {
                ch = input[this.cursor++];
                if (ch === '.' && !floating) {
                    floating = true;
                    ch = input[this.cursor++];
                }
            } while (ch >= '0' && ch <= '9');

            this.cursor--;

            var exponent = this.lexExponent();
            floating = floating || exponent;

            var str = input.substring(token.start, this.cursor);
            token.value = floating ? parseFloat(str) : parseInt(str);
        },

        lexDot: function (ch) {
            var token = this.token, input = this.source;
            var next = input[this.cursor];
            if (next >= '0' && next <= '9') {
                do {
                    ch = input[this.cursor++];
                } while (ch >= '0' && ch <= '9');
                this.cursor--;

                this.lexExponent();

                token.type = NUMBER;
                token.value = parseFloat(token.start, this.cursor);
            } else {
                token.type = DOT;
                token.assignOp = null;
                token.value = '.';
            }
        },

        lexString: function (ch) {
            var token = this.token, input = this.source;
            token.type = STRING;

            var hasEscapes = false;
            var delim = ch;
            while ((ch = input[this.cursor++]) !== delim) {
                if (this.cursor == input.length)
                    throw this.newSyntaxError("Unterminated string literal");
                if (ch === '\\') {
                    hasEscapes = true;
                    if (++this.cursor == input.length)
                        throw this.newSyntaxError("Unterminated string literal");
                }
            }

            token.value = hasEscapes
                          ? eval(input.substring(token.start, this.cursor))
                          : input.substring(token.start + 1, this.cursor - 1);
        },

        lexRegExp: function (ch) {
            var token = this.token, input = this.source;
            token.type = REGEXP;

            do {
                ch = input[this.cursor++];
                if (ch === '\\') {
                    this.cursor++;
                } else if (ch === '[') {
                    do {
                        if (ch === undefined)
                            throw this.newSyntaxError("Unterminated character class");

                        if (ch === '\\')
                            this.cursor++;

                        ch = input[this.cursor++];
                    } while (ch !== ']');
                } else if (ch === undefined) {
                    throw this.newSyntaxError("Unterminated regex");
                }
            } while (ch !== '/');

            do {
                ch = input[this.cursor++];
            } while (ch >= 'a' && ch <= 'z');

            this.cursor--;

            token.value = eval(input.substring(token.start, this.cursor));
        },

        lexOp: function (ch) {
            var token = this.token, input = this.source;

            // A bit ugly, but it seems wasteful to write a trie lookup routine
            // for only 3 characters...
            var node = opTokens[ch];
            var next = input[this.cursor];
            if (next in node) {
                node = node[next];
                this.cursor++;
                next = input[this.cursor];
                if (next in node) {
                    node = node[next];
                    this.cursor++;
                    next = input[this.cursor];
                }
            }

            var op = node.op;
            if (definitions.assignOps[op] && input[this.cursor] === '=') {
                this.cursor++;
                token.type = ASSIGN;
                token.assignOp = definitions.tokenIds[definitions.opTypeNames[op]];
                op += '=';
            } else {
                token.type = definitions.tokenIds[definitions.opTypeNames[op]];
                token.assignOp = null;
            }

            token.value = op;
        },

        // FIXME: Unicode escape sequences
        // FIXME: Unicode identifiers
        lexIdent: function (ch) {
            var token = this.token, input = this.source;

            do {
                ch = input[this.cursor++];
            } while ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') ||
                     (ch >= '0' && ch <= '9') || ch === '$' || ch === '_');

            this.cursor--;  // Put the non-word character back.

            var id = input.substring(token.start, this.cursor);
            token.type = definitions.keywords[id] || IDENTIFIER;
            token.value = id;
        },

        /*
         * Tokenizer.get :: void -> token type
         *
         * Consume input *only* if there is no lookahead.
         * Dispatch to the appropriate lexing function depending on the input.
         */
        get: function (scanOperand) {
            var token;
            while (this.lookahead) {
                --this.lookahead;
                this.tokenIndex = (this.tokenIndex + 1) & 3;
                token = this.tokens[this.tokenIndex];
                if (token.type !== NEWLINE || this.scanNewlines)
                    return token.type;
            }

            this.skip();

            this.tokenIndex = (this.tokenIndex + 1) & 3;
            token = this.tokens[this.tokenIndex];
            if (!token)
                this.tokens[this.tokenIndex] = token = {};

            var input = this.source;
            if (this.cursor === input.length)
                return token.type = END;

            token.start = this.cursor;
            token.lineno = this.lineno;

            var ch = input[this.cursor++];
            if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || ch === '$' || ch === '_') {
                this.lexIdent(ch);
            } else if (scanOperand && ch === '/') {
                this.lexRegExp(ch);
            } else if (ch in opTokens) {
                this.lexOp(ch);
            } else if (ch === '.') {
                this.lexDot(ch);
            } else if (ch >= '1' && ch <= '9') {
                this.lexNumber(ch);
            } else if (ch === '0') {
                this.lexZeroNumber(ch);
            } else if (ch === '"' || ch === "'") {
                this.lexString(ch);
            } else if (this.scanNewlines && ch === '\n') {
                token.type = NEWLINE;
                token.value = '\n';
                this.lineno++;
            } else {
                throw this.newSyntaxError("Illegal token");
            }

            token.end = this.cursor;
            return token.type;
        },

        /*
         * Tokenizer.unget :: void -> undefined
         *
         * Match depends on unget returning undefined.
         */
        unget: function () {
            if (++this.lookahead === 4) throw "PANIC: too much lookahead!";
            this.tokenIndex = (this.tokenIndex - 1) & 3;
        },

        newSyntaxError: function (m) {
            var e = new SyntaxError(m, this.filename, this.lineno);
            e.source = this.source;
            e.cursor = this.lookahead
                       ? this.tokens[(this.tokenIndex + this.lookahead) & 3].start
                       : this.cursor;
            return e;
        },
    };

    return { Tokenizer: Tokenizer };

}());
<commit_msg>fixed lexing of floating point constants in Narcissus.<commit_after>/* vim: set sw=4 ts=4 et tw=78: */
/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is the Narcissus JavaScript engine.
 *
 * The Initial Developer of the Original Code is
 * Brendan Eich <brendan@mozilla.org>.
 * Portions created by the Initial Developer are Copyright (C) 2004
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *   Tom Austin <taustin@ucsc.edu>
 *   Brendan Eich <brendan@mozilla.org>
 *   Shu-Yu Guo <shu@rfrn.org>
 *   Stephan Herhut <stephan.a.herhut@intel.com>
 *   Dave Herman <dherman@mozilla.com>
 *   Dimitris Vardoulakis <dimvar@ccs.neu.edu>
 *   Patrick Walton <pcwalton@mozilla.com>
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 *
 * ***** END LICENSE BLOCK ***** */

/*
 * Narcissus - JS implemented in JS.
 *
 * Lexical scanner.
 */

Narcissus.lexer = (function() {

    var definitions = Narcissus.definitions;

    // Set constants in the local scope.
    eval(definitions.consts);

    // Build up a trie of operator tokens.
    var opTokens = {};
    for (var op in definitions.opTypeNames) {
        if (op === '\n' || op === '.')
            continue;

        var node = opTokens;
        for (var i = 0; i < op.length; i++) {
            var ch = op[i];
            if (!(ch in node))
                node[ch] = {};
            node = node[ch];
            node.op = op;
        }
    }

    /*
     * Tokenizer :: (source, filename, line number) -> Tokenizer
     */
    function Tokenizer(s, f, l) {
        this.cursor = 0;
        this.source = String(s);
        this.tokens = [];
        this.tokenIndex = 0;
        this.lookahead = 0;
        this.scanNewlines = false;
        this.unexpectedEOF = false;
        this.filename = f || "";
        this.lineno = l || 1;
    }

    Tokenizer.prototype = {
        get done() {
            // We need to set scanOperand to true here because the first thing
            // might be a regexp.
            return this.peek(true) === END;
        },

        get token() {
            return this.tokens[this.tokenIndex];
        },

        match: function (tt, scanOperand) {
            return this.get(scanOperand) === tt || this.unget();
        },

        mustMatch: function (tt) {
            if (!this.match(tt)) {
                throw this.newSyntaxError("Missing " +
                                          definitions.tokens[tt].toLowerCase());
            }
            return this.token;
        },

        peek: function (scanOperand) {
            var tt, next;
            if (this.lookahead) {
                next = this.tokens[(this.tokenIndex + this.lookahead) & 3];
                tt = (this.scanNewlines && next.lineno !== this.lineno)
                     ? NEWLINE
                     : next.type;
            } else {
                tt = this.get(scanOperand);
                this.unget();
            }
            return tt;
        },

        peekOnSameLine: function (scanOperand) {
            this.scanNewlines = true;
            var tt = this.peek(scanOperand);
            this.scanNewlines = false;
            return tt;
        },

        // Eat comments and whitespace.
        skip: function () {
            var input = this.source;
            for (;;) {
                var ch = input[this.cursor++];
                var next = input[this.cursor];
                if (ch === '\n' && !this.scanNewlines) {
                    this.lineno++;
                } else if (ch === '/' && next === '*') {
                    this.cursor++;
                    for (;;) {
                        ch = input[this.cursor++];
                        if (ch === undefined)
                            throw this.newSyntaxError("Unterminated comment");

                        if (ch === '*') {
                            next = input[this.cursor];
                            if (next === '/') {
                                this.cursor++;
                                break;
                            }
                        } else if (ch === '\n') {
                            this.lineno++;
                        }
                    }
                } else if (ch === '/' && next === '/') {
                    this.cursor++;
                    for (;;) {
                        ch = input[this.cursor++];
                        if (ch === undefined)
                            return;

                        if (ch === '\n') {
                            this.lineno++;
                            break;
                        }
                    }
                } else if (ch !== ' ' && ch !== '\t') {
                    this.cursor--;
                    return;
                }
            }
        },

        // Lex the exponential part of a number, if present. Return true iff an
        // exponential part was found.
        lexExponent: function() {
            var input = this.source;
            var next = input[this.cursor];
            if (next === 'e' || next === 'E') {
                this.cursor++;
                ch = input[this.cursor++];
                if (ch === '+' || ch === '-')
                    ch = input[this.cursor++];

                if (ch < '0' || ch > '9')
                    throw this.newSyntaxError("Missing exponent");

                do {
                    ch = input[this.cursor++];
                } while (ch >= '0' && ch <= '9');
                this.cursor--;

                return true;
            }

            return false;
        },

        lexZeroNumber: function (ch) {
            var token = this.token, input = this.source;
            token.type = NUMBER;

            ch = input[this.cursor++];
            if (ch === '.') {
                do {
                    ch = input[this.cursor++];
                } while (ch >= '0' && ch <= '9');
                this.cursor--;

                this.lexExponent();
                var str = input.substring(token.start, this.cursor);
                token.value = parseFloat(str);
            } else if (ch === 'x' || ch === 'X') {
                do {
                    ch = input[this.cursor++];
                } while ((ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') ||
                         (ch >= 'A' && ch <= 'F'));
                this.cursor--;

                token.value = parseInt(input.substring(token.start, this.cursor));
            } else if (ch >= '0' && ch <= '7') {
                do {
                    ch = input[this.cursor++];
                } while (ch >= '0' && ch <= '7');
                this.cursor--;

                token.value = parseInt(input.substring(token.start, this.cursor));
            } else {
                this.cursor--;
                this.lexExponent();     // 0E1, &c.
                token.value = 0;
            }
        },

        lexNumber: function (ch) {
            var token = this.token, input = this.source;
            token.type = NUMBER;

            var floating = false;
            do {
                ch = input[this.cursor++];
                if (ch === '.' && !floating) {
                    floating = true;
                    ch = input[this.cursor++];
                }
            } while (ch >= '0' && ch <= '9');

            this.cursor--;

            var exponent = this.lexExponent();
            floating = floating || exponent;

            var str = input.substring(token.start, this.cursor);
            token.value = floating ? parseFloat(str) : parseInt(str);
        },

        lexDot: function (ch) {
            var token = this.token, input = this.source;
            var next = input[this.cursor];
            if (next >= '0' && next <= '9') {
                do {
                    ch = input[this.cursor++];
                } while (ch >= '0' && ch <= '9');
                this.cursor--;

                this.lexExponent();

                token.type = NUMBER;
                var str = input.substring(token.start, this.cursor);
                token.value = parseFloat(str);
            } else {
                token.type = DOT;
                token.assignOp = null;
                token.value = '.';
            }
        },

        lexString: function (ch) {
            var token = this.token, input = this.source;
            token.type = STRING;

            var hasEscapes = false;
            var delim = ch;
            while ((ch = input[this.cursor++]) !== delim) {
                if (this.cursor == input.length)
                    throw this.newSyntaxError("Unterminated string literal");
                if (ch === '\\') {
                    hasEscapes = true;
                    if (++this.cursor == input.length)
                        throw this.newSyntaxError("Unterminated string literal");
                }
            }

            token.value = hasEscapes
                          ? eval(input.substring(token.start, this.cursor))
                          : input.substring(token.start + 1, this.cursor - 1);
        },

        lexRegExp: function (ch) {
            var token = this.token, input = this.source;
            token.type = REGEXP;

            do {
                ch = input[this.cursor++];
                if (ch === '\\') {
                    this.cursor++;
                } else if (ch === '[') {
                    do {
                        if (ch === undefined)
                            throw this.newSyntaxError("Unterminated character class");

                        if (ch === '\\')
                            this.cursor++;

                        ch = input[this.cursor++];
                    } while (ch !== ']');
                } else if (ch === undefined) {
                    throw this.newSyntaxError("Unterminated regex");
                }
            } while (ch !== '/');

            do {
                ch = input[this.cursor++];
            } while (ch >= 'a' && ch <= 'z');

            this.cursor--;

            token.value = eval(input.substring(token.start, this.cursor));
        },

        lexOp: function (ch) {
            var token = this.token, input = this.source;

            // A bit ugly, but it seems wasteful to write a trie lookup routine
            // for only 3 characters...
            var node = opTokens[ch];
            var next = input[this.cursor];
            if (next in node) {
                node = node[next];
                this.cursor++;
                next = input[this.cursor];
                if (next in node) {
                    node = node[next];
                    this.cursor++;
                    next = input[this.cursor];
                }
            }

            var op = node.op;
            if (definitions.assignOps[op] && input[this.cursor] === '=') {
                this.cursor++;
                token.type = ASSIGN;
                token.assignOp = definitions.tokenIds[definitions.opTypeNames[op]];
                op += '=';
            } else {
                token.type = definitions.tokenIds[definitions.opTypeNames[op]];
                token.assignOp = null;
            }

            token.value = op;
        },

        // FIXME: Unicode escape sequences
        // FIXME: Unicode identifiers
        lexIdent: function (ch) {
            var token = this.token, input = this.source;

            do {
                ch = input[this.cursor++];
            } while ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') ||
                     (ch >= '0' && ch <= '9') || ch === '$' || ch === '_');

            this.cursor--;  // Put the non-word character back.

            var id = input.substring(token.start, this.cursor);
            token.type = definitions.keywords[id] || IDENTIFIER;
            token.value = id;
        },

        /*
         * Tokenizer.get :: void -> token type
         *
         * Consume input *only* if there is no lookahead.
         * Dispatch to the appropriate lexing function depending on the input.
         */
        get: function (scanOperand) {
            var token;
            while (this.lookahead) {
                --this.lookahead;
                this.tokenIndex = (this.tokenIndex + 1) & 3;
                token = this.tokens[this.tokenIndex];
                if (token.type !== NEWLINE || this.scanNewlines)
                    return token.type;
            }

            this.skip();

            this.tokenIndex = (this.tokenIndex + 1) & 3;
            token = this.tokens[this.tokenIndex];
            if (!token)
                this.tokens[this.tokenIndex] = token = {};

            var input = this.source;
            if (this.cursor === input.length)
                return token.type = END;

            token.start = this.cursor;
            token.lineno = this.lineno;

            var ch = input[this.cursor++];
            if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || ch === '$' || ch === '_') {
                this.lexIdent(ch);
            } else if (scanOperand && ch === '/') {
                this.lexRegExp(ch);
            } else if (ch in opTokens) {
                this.lexOp(ch);
            } else if (ch === '.') {
                this.lexDot(ch);
            } else if (ch >= '1' && ch <= '9') {
                this.lexNumber(ch);
            } else if (ch === '0') {
                this.lexZeroNumber(ch);
            } else if (ch === '"' || ch === "'") {
                this.lexString(ch);
            } else if (this.scanNewlines && ch === '\n') {
                token.type = NEWLINE;
                token.value = '\n';
                this.lineno++;
            } else {
                throw this.newSyntaxError("Illegal token");
            }

            token.end = this.cursor;
            return token.type;
        },

        /*
         * Tokenizer.unget :: void -> undefined
         *
         * Match depends on unget returning undefined.
         */
        unget: function () {
            if (++this.lookahead === 4) throw "PANIC: too much lookahead!";
            this.tokenIndex = (this.tokenIndex - 1) & 3;
        },

        newSyntaxError: function (m) {
            var e = new SyntaxError(m, this.filename, this.lineno);
            e.source = this.source;
            e.cursor = this.lookahead
                       ? this.tokens[(this.tokenIndex + this.lookahead) & 3].start
                       : this.cursor;
            return e;
        },
    };

    return { Tokenizer: Tokenizer };

}());
<|endoftext|>


<commit_before>'use strict';

import should from 'should'
import lib from '../src'

describe('lib', () => {
  it('should exist', (done) => {
    should.exist(lib)
    done()
  })
})
<commit_msg>tests<commit_after>/*global it: true, describe: true */
/*eslint no-console: 0*/

import should from 'should'
import lib from '../src'

describe('lib', () => {
  it('should exist', (done) => {
    should.exist(lib)
    done()
  })
})
<|endoftext|>


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

var fs = require("fs");

module['exports'] = function attemptToRequireUntrustedHook (opts, callback) {

  var username = opts.username,
      script = opts.script;

  var untrustedHook;
  var isStreamingHook;
  var untrustedTemplate;
  var err = null;
  // At this stage, the hook source code is untrusted ( and should be validated )
  try {
    var _script = require.resolve(__dirname + '/../../../temp/' +  username + "/" + opts.req.hook.name + "/" + script + '.js');
    delete require.cache[_script];
    untrustedHook = require(_script);
    opts.req.hook = opts.req.hook || {};
    untrustedHook.schema = untrustedHook.schema || {};
    untrustedHook.theme = opts.req.hook.theme || untrustedHook.theme || config.defaultTheme;
    untrustedHook.presenter =  opts.req.hook.presenter || untrustedHook.presenter || config.defaultPresenter;
  } catch (e) {
    err = e;
  }

  if (err) {
    return fs.readFile(__dirname + '/../../../temp/' +  username + "/" + script + '.js', function(_err, _source){
      if (_err) {
        return callback(_err);
      }
      // unable to require Hook as commonjs module,
      // the Hook is invalid
      return callback(err, _source);
    });
  }
  return callback(null, untrustedHook)
};
<commit_msg>[minor] [refactor] Put userHome path into variable<commit_after>var config = require('../../../config');

var fs = require("fs");

module['exports'] = function attemptToRequireUntrustedHook (opts, callback) {

  var username = opts.req.hook.owner,
      userHome = __dirname + '/../../../temp/' +  username + "/" + opts.req.hook.name + "/",
      script = opts.script;

  var untrustedHook;
  var isStreamingHook;
  var untrustedTemplate;
  var err = null;
  // At this stage, the hook source code is untrusted ( and should be validated )
  try {
    var _script = require.resolve(userHome + script + '.js');
    delete require.cache[_script];
    untrustedHook = require(_script);
    opts.req.hook = opts.req.hook || {};
    untrustedHook.schema = untrustedHook.schema || {};
    untrustedHook.theme = opts.req.hook.theme || untrustedHook.theme || config.defaultTheme;
    untrustedHook.presenter =  opts.req.hook.presenter || untrustedHook.presenter || config.defaultPresenter;
  } catch (e) {
    err = e;
  }

  if (err) {
    return fs.readFile(userHome + script + '.js', function (_err, _source){
      if (_err) {
        return callback(_err);
      }
      // unable to require Hook as commonjs module,
      // the Hook is invalid
      return callback(err, _source);
    });
  }
  return callback(null, untrustedHook)
};
<|endoftext|>


<commit_before>var fs = require("fs");
var path = require("path");
var chalk = require("chalk");

var availableCommands = {
  "container": "containers",
  "component": "components",
  "reducer": "reducers"
};

function replaceName (input, name) {
  return input.replace(/__\$NAME__/g, name);
}

module.exports = function () {
  var command = process.argv[3];
  var name = process.argv[4];

  // Step 1: Check if we are in the root of a gluestick project by looking for the `.gluestick` file
  try {
    fs.statSync(path.join(process.cwd(), ".gluestick"));
  }
  catch (e) {
    console.log(chalk.yellow(".gluestick file not found"));
    console.log(chalk.red("ERROR: `generate` commands must be run from the root of a gluestick project."));
    return;
  }

  // Step 2: Validate the command type by verifying that it exists in `availableCommands`
  if (!availableCommands[command]) {
    console.log(chalk.red(`ERROR: ${chalk.yellow(command)} is not a valid generator.`));
    console.log(chalk.yellow(`Available generators: ${JSON.stringify(availableCommands)}`));
    return;
  }

  // Step 3: Validate the name by stripping out unwanted characters
  if (!name || name.length === 0) {
    console.log(chalk.red(`ERROR: invalid arguments. You must specify a name.`));
    return;
  }

  if (/\W/.test(name)) {
    console.log(chalk.red(`ERROR: ${chalk.yellow(name)} is not a valid name.`));
    return;
  }

  // Step 4: Possibly mutate the name by converting it to Pascal Case (only for container and component for now)
  if (["container", "component"].indexOf(command) !== -1) {
    name = name.substr(0, 1).toUpperCase() + name.substr(1);
  }
  if (["reducer", "action-creator"].indexOf(command) !== -1) {
    name = name.substr(0, 1).toLowerCase() + name.substr(1);
  }

  // Step 5: Get the output string and destination filename
  var template;
  try {
    template = fs.readFileSync(path.resolve(__dirname, `../../generate/${command}.js`), {encoding: "utf8"})
  }
  catch(e) {
    console.log(e, chalk.red("ERROR: Couldn't read generator file"));
    return;
  }

  template = replaceName(template, name);

  // Step 6: Check if the file already exists before we write to it
  var destinationPath = path.join(process.cwd(), "/src/", availableCommands[command] + "/" + name + ".js");
  var fileExists = true;
  try {
    fs.statSync(destinationPath);
  }
  catch (e) {
    fileExists = false;
  }

  if (fileExists) {
    console.log(chalk.red(`ERROR: ${chalk.yellow(destinationPath)} already exists`));
    return;
  }

  // Step 6: Write output to file
  fs.writeFileSync(destinationPath, template);
  console.log(chalk.green(`New file created: ${destinationPath}`));

  // Step 7: If we just generated a reducer, add it to the reducers index
  if (command === "reducer") {
    var reducerIndexPath = path.resolve(process.cwd(), "src/reducers/index.js");
    try {
      var indexLines = fs.readFileSync(reducerIndexPath, {encoding: "utf8"}).split("\n");
      var lastLineIndex = indexLines.length - 1;
      var newLine = `export { default as ${name} } from "./${name}"`;
      if (indexLines[lastLineIndex] === "") {
        indexLines.splice(lastLineIndex, 1, newLine);
        indexLines.push("");
      }
      else {
        indexLines.push(newLine);
        indexLines.push("");
      }
      fs.writeFileSync(reducerIndexPath, indexLines.join("\n"));
      console.log(chalk.yellow(`${name} added to reducer index ${reducerIndexPath}`));
    }
    catch (e) {
      console.log(chalk.red(`ERROR: Unable to modify reducers index. Reducer not added to index`));
      return;
    }
  }

  // Step 8: Write test file for component
  if(command === "component") {
    var testPath = path.join(process.cwd(), "/test/", availableCommands[command], `/${name}.test.js`);
    var testTemplate;
    var testFileExists = true;
    try {
      fs.statSync(testPath);
    }
    catch (e) {
      testFileExists = false;
    }

    if (testFileExists) {
      console.log(chalk.yellow(`WARNING: Unable to create test file for ${name} because it already exists`));
      return;
    }

    try {
      testTemplate = fs.readFileSync(path.resolve(__dirname, `../../generate/${command}.test.js`), {encoding: "utf8"})
    }
    catch (e) {
      console.log(e, chalk.red("ERROR: Couldn't read generator file"));
      return;
    }

    try {
      fs.writeFileSync(testPath, replaceName(testTemplate, name));
    }
    catch (e) {
      console.log(e, chalk.red("ERROR: Couldn't create test file"));
      return;
    }

    console.log(chalk.green(`New file created: ${testPath}`));
  }
};

<commit_msg>Fixed bug where generating reducers was overwrting previous ones. Made code cleaner by appending string instead of splitting into array<commit_after>var fs = require("fs");
var path = require("path");
var chalk = require("chalk");

var availableCommands = {
  "container": "containers",
  "component": "components",
  "reducer": "reducers"
};

function replaceName (input, name) {
  return input.replace(/__\$NAME__/g, name);
}

module.exports = function () {
  var command = process.argv[3];
  var name = process.argv[4];

  // Step 1: Check if we are in the root of a gluestick project by looking for the `.gluestick` file
  try {
    fs.statSync(path.join(process.cwd(), ".gluestick"));
  }
  catch (e) {
    console.log(chalk.yellow(".gluestick file not found"));
    console.log(chalk.red("ERROR: `generate` commands must be run from the root of a gluestick project."));
    return;
  }

  // Step 2: Validate the command type by verifying that it exists in `availableCommands`
  if (!availableCommands[command]) {
    console.log(chalk.red(`ERROR: ${chalk.yellow(command)} is not a valid generator.`));
    console.log(chalk.yellow(`Available generators: ${JSON.stringify(availableCommands)}`));
    return;
  }

  // Step 3: Validate the name by stripping out unwanted characters
  if (!name || name.length === 0) {
    console.log(chalk.red(`ERROR: invalid arguments. You must specify a name.`));
    return;
  }

  if (/\W/.test(name)) {
    console.log(chalk.red(`ERROR: ${chalk.yellow(name)} is not a valid name.`));
    return;
  }

  // Step 4: Possibly mutate the name by converting it to Pascal Case (only for container and component for now)
  if (["container", "component"].indexOf(command) !== -1) {
    name = name.substr(0, 1).toUpperCase() + name.substr(1);
  }
  if (["reducer", "action-creator"].indexOf(command) !== -1) {
    name = name.substr(0, 1).toLowerCase() + name.substr(1);
  }

  // Step 5: Get the output string and destination filename
  var template;
  try {
    template = fs.readFileSync(path.resolve(__dirname, `../../generate/${command}.js`), {encoding: "utf8"})
  }
  catch(e) {
    console.log(e, chalk.red("ERROR: Couldn't read generator file"));
    return;
  }

  template = replaceName(template, name);

  // Step 6: Check if the file already exists before we write to it
  var destinationPath = path.join(process.cwd(), "/src/", availableCommands[command] + "/" + name + ".js");
  var fileExists = true;
  try {
    fs.statSync(destinationPath);
  }
  catch (e) {
    fileExists = false;
  }

  if (fileExists) {
    console.log(chalk.red(`ERROR: ${chalk.yellow(destinationPath)} already exists`));
    return;
  }

  // Step 6: Write output to file
  fs.writeFileSync(destinationPath, template);
  console.log(chalk.green(`New file created: ${destinationPath}`));

  // Step 7: If we just generated a reducer, add it to the reducers index
  if (command === "reducer") {
    var reducerIndexPath = path.resolve(process.cwd(), "src/reducers/index.js");
    try {
      // Get the file contents, but strip off any trailing whitespace. This sets us up
      // to place the new export on the last line, followed by a blank whitespace line at the end
      var indexFileContents = fs.readFileSync(reducerIndexPath, {encoding: "utf8"}).replace(/\s*$/, "");
      var newLine = `export { default as ${name} } from "./${name}";`;

      // Write back to the index file with the previous contents in addition to our new line and a blank line for git
      fs.writeFileSync(reducerIndexPath, `${indexFileContents}\n${newLine}\n\n`);
      console.log(chalk.yellow(`${name} added to reducer index ${reducerIndexPath}`));
    }
    catch (e) {
      console.log(chalk.red(`ERROR: Unable to modify reducers index. Reducer not added to index`));
      return;
    }
  }

  // Step 8: Write test file for component
  if(command === "component") {
    var testPath = path.join(process.cwd(), "/test/", availableCommands[command], `/${name}.test.js`);
    var testTemplate;
    var testFileExists = true;
    try {
      fs.statSync(testPath);
    }
    catch (e) {
      testFileExists = false;
    }

    if (testFileExists) {
      console.log(chalk.yellow(`WARNING: Unable to create test file for ${name} because it already exists`));
      return;
    }

    try {
      testTemplate = fs.readFileSync(path.resolve(__dirname, `../../generate/${command}.test.js`), {encoding: "utf8"})
    }
    catch (e) {
      console.log(e, chalk.red("ERROR: Couldn't read generator file"));
      return;
    }

    try {
      fs.writeFileSync(testPath, replaceName(testTemplate, name));
    }
    catch (e) {
      console.log(e, chalk.red("ERROR: Couldn't create test file"));
      return;
    }

    console.log(chalk.green(`New file created: ${testPath}`));
  }
};
<|endoftext|>


<commit_before>import React, { Component, PropTypes } from 'react';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import 'react-select/dist/react-select.css';
import CommentsList from '../components/Comments/Comments';
import * as commentsActions from './commentsActions';
import Loading from '../components/Icon/Loading';
import './Comments.less';

@connect(
  state => ({
    comments: state.comments,
    auth: state.auth,
  }),
  dispatch => bindActionCreators({
    getComments: commentsActions.getComments,
    showMoreComments: commentsActions.showMoreComments,
    likeComment: id => commentsActions.likeComment(id),
    unlikeComment: id => commentsActions.likeComment(id, 0),
    dislikeComment: id => commentsActions.likeComment(id, -1000),
    openCommentingDraft: commentsActions.openCommentingDraft,
  }, dispatch)
)
export default class Comments extends Component {
  constructor(props) {
    super(props);
    this.state = {
      sortOrder: 'trending',
    };
  }

  static propTypes = {
    post: PropTypes.object,
    comments: PropTypes.object,
    getComments: PropTypes.func,
    className: PropTypes.string,
  };

  componentDidMount() {
    if (this.props.show) {
      this.props.getComments(this.props.post.id);
    }
  }

  componentDidUpdate(prevProps) {
    const postChanged = (this.props.post.id && prevProps.post.id !== this.props.post.id);
    const showToggled = (this.props.show && prevProps.show !== this.props.show);
    if (showToggled || postChanged) {
      this.props.getComments(this.props.post.id);
    }
  }

  handleShowMore = (e) => {
    e.stopPropagation();
    this.props.showMoreComments(this.props.post.id);
  };

  handleSortChange = ({ value }) => {
    if (value !== this.state.sortOrder) {
      this.setState({ sortOrder: value });
    }
  };

  getNestedComments = (commentsObj, commentsIdArray, nestedComments) => {
    commentsIdArray.forEach((commentId) => {
      const nestedCommentArray = commentsObj.listByCommentId[commentId];
      if (nestedCommentArray.length) {
        nestedComments[commentId] = nestedCommentArray.map(id => commentsObj.comments[id]);
        this.getNestedComments(commentsObj, nestedCommentArray, nestedComments);
      }
    });
    return nestedComments;
  }

  render() {
    const { post, comments, show } = this.props;
    const postId = post.id;

    if (!show) {
      return
;
    }

    const isFetching = (comments.listByPostId[postId] && comments.listByPostId[postId].isFetching);

    const fetchedCommentsList = (isFetching === false) ?
      comments.listByPostId[postId].list.map(id => comments.comments[id]) :
      null;

    let commentsChildren = {};

    if (fetchedCommentsList && fetchedCommentsList.length) {
      commentsChildren = this.getNestedComments(comments, comments.listByPostId[postId].list, {});
    }

    if (isFetching || !fetchedCommentsList) {
      return (<Loading />);
    }

    if (fetchedCommentsList) {
      return (
        <CommentsList
          parentPost={post}
          comments={fetchedCommentsList}
          auth={this.props.auth}
          commentsChildren={commentsChildren}
          onLikeClick={this.props.likeComment}
          onDislikeClick={this.props.dislikeComment}
        />
      );
    }

    return (

    );
  }
}
<commit_msg>Remove unused code<commit_after>import React, { Component, PropTypes } from 'react';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import 'react-select/dist/react-select.css';
import CommentsList from '../components/Comments/Comments';
import * as commentsActions from './commentsActions';
import Loading from '../components/Icon/Loading';
import './Comments.less';

@connect(
  state => ({
    comments: state.comments,
    auth: state.auth,
  }),
  dispatch => bindActionCreators({
    getComments: commentsActions.getComments,
    likeComment: id => commentsActions.likeComment(id),
    unlikeComment: id => commentsActions.likeComment(id, 0),
    dislikeComment: id => commentsActions.likeComment(id, -1000),
  }, dispatch)
)
export default class Comments extends Component {
  constructor(props) {
    super(props);
    this.state = {
      sortOrder: 'trending',
    };
  }

  static propTypes = {
    post: PropTypes.shape(),
    comments: PropTypes.shape(),
    getComments: PropTypes.func,
  };

  componentDidMount() {
    if (this.props.show) {
      this.props.getComments(this.props.post.id);
    }
  }

  getNestedComments = (commentsObj, commentsIdArray, nestedComments) => {
    commentsIdArray.forEach((commentId) => {
      const nestedCommentArray = commentsObj.listByCommentId[commentId];
      if (nestedCommentArray.length) {
        nestedComments[commentId] = nestedCommentArray.map(id => commentsObj.comments[id]);
        this.getNestedComments(commentsObj, nestedCommentArray, nestedComments);
      }
    });
    return nestedComments;
  }

  render() {
    const { post, comments, show } = this.props;
    const postId = post.id;

    if (!show) {
      return
;
    }

    const fetchedCommentsList = (comments.listByPostId[postId]
      && comments.listByPostId[postId].list.length) ?
      comments.listByPostId[postId].list.map(id => comments.comments[id]) :
      null;

    let commentsChildren = {};

    if (fetchedCommentsList && fetchedCommentsList.length) {
      commentsChildren = this.getNestedComments(comments, comments.listByPostId[postId].list, {});
    }

    if (!fetchedCommentsList) {
      return (<Loading />);
    }

    if (fetchedCommentsList) {
      return (
        <CommentsList
          parentPost={post}
          comments={fetchedCommentsList}
          auth={this.props.auth}
          commentsChildren={commentsChildren}
          onLikeClick={this.props.likeComment}
          onDislikeClick={this.props.dislikeComment}
        />
      );
    }

    return (

    );
  }
}
<|endoftext|>


<commit_before>import 'jsdom-global/register'; // for enzyme .mount to work

import React, { Component } from 'react';
import { test } from 'ava';
import Enzyme, { shallow, mount, render } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import sinon from 'sinon';

import Federal, { connect } from '../dist/federal';

Enzyme.configure({
  adapter: new Adapter()
});

test('<Federal /> should render children', t => {
  const content = shallow(
    <Federal>

hello world

    </Federal>
  );

  t.true(content.contains(
hello world
));
});

test('connect() should carry down store attributes', t => {
  const initialStore = {
    a: 'x',
    b: 'y',
    c: 'z'
  };

  const ConnectedChild = connect()(
    ({ a, b, c }) => (
{c}{b}{a}
)
  );

  const content = mount(
    <Federal store={initialStore}>
      <ConnectedChild />
    </Federal>
  );

  t.true(content.find('#child').text() === 'zyx');
});

test('connect() should honor a selector', t => {
  const initialStore = {
    a: 'x',
    b: 'y',
    c: 'z'
  };

  const ConnectedChild = connect(store => ({
    a: store.a,
    // no .b
    c: store.c
  }))(
    ({ a, b, c }) => (
{c || '-'}{b || '-'}{a || '-'}
)
  );

  const content = mount(
    <Federal store={initialStore}>
      <ConnectedChild />
    </Federal>
  );

  t.true(content.find('#child').text() === 'z-x');
});

test('connect() should pass action dispatchers', t => {
  const onClick = sinon.spy();

  const Child = ({ dispatch, count }) => (

       {
          e.preventDefault();
          dispatch.increment();
        }}
      >link

      {count}

  );

  const ConnectedChild = connect()(Child);

  const initialStore = {
    count: 0
  };

  const actions = {
    increment: store => {
      return Object.assign({}, store, {
        count: store.count + 1
      });
    }
  };

  const content = mount(
    <Federal store={initialStore} actions={actions}>
      <ConnectedChild />
    </Federal>
  );

  t.true(content.find('#track').text() === '0');

  content.find('#anchor').simulate('click');
  t.true(content.find('#track').text() === '1');

  content.find('#anchor').simulate('click');
  content.find('#anchor').simulate('click');
  content.find('#anchor').simulate('click');
  t.true(content.find('#track').text() === '4');
});
<commit_msg>sub-actions tests<commit_after>import 'jsdom-global/register'; // for enzyme .mount to work

import React, { Component } from 'react';
import { test } from 'ava';
import Enzyme, { shallow, mount, render } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import sinon from 'sinon';

import Federal, { connect } from '../dist/federal';

Enzyme.configure({
  adapter: new Adapter()
});

test('<Federal /> should render children', t => {
  const content = shallow(
    <Federal>

hello world

    </Federal>
  );

  t.true(content.contains(
hello world
));
});

test('connect() should carry down store attributes', t => {
  const initialStore = {
    a: 'x',
    b: 'y',
    c: 'z'
  };

  const ConnectedChild = connect()(
    ({ a, b, c }) => (
{c}{b}{a}
)
  );

  const content = mount(
    <Federal store={initialStore}>
      <ConnectedChild />
    </Federal>
  );

  t.true(content.find('#child').text() === 'zyx');
});

test('connect() should honor a selector', t => {
  const initialStore = {
    a: 'x',
    b: 'y',
    c: 'z'
  };

  const ConnectedChild = connect(store => ({
    a: store.a,
    // no .b
    c: store.c
  }))(
    ({ a, b, c }) => (
{c || '-'}{b || '-'}{a || '-'}
)
  );

  const content = mount(
    <Federal store={initialStore}>
      <ConnectedChild />
    </Federal>
  );

  t.true(content.find('#child').text() === 'z-x');
});

test('connect() should pass action dispatchers', t => {
  const onClick = sinon.spy();

  const Child = ({ dispatch, count }) => (

       {
          e.preventDefault();
          dispatch.increment();
        }}
      >link

      {count}

  );

  const ConnectedChild = connect()(Child);

  const initialStore = {
    count: 0
  };

  const actions = {
    increment: store => {
      return Object.assign({}, store, {
        count: store.count + 1
      });
    }
  };

  const content = mount(
    <Federal store={initialStore} actions={actions}>
      <ConnectedChild />
    </Federal>
  );

  t.true(content.find('#track').text() === '0');

  content.find('#anchor').simulate('click');
  t.true(content.find('#track').text() === '1');

  content.find('#anchor').simulate('click');
  content.find('#anchor').simulate('click');
  content.find('#anchor').simulate('click');
  t.true(content.find('#track').text() === '4');
});

test('connect() should allow custom actions', t => {
  const onClick = sinon.spy();

  const actions = {
    increment: store => {
      return Object.assign({}, store, {
        count: store.count + 1
      });
    }
  };

  const Child = ({ dispatch, count }) => (

       {
          e.preventDefault();
          dispatch.increment();
        }}
      >link

      {count}

  );

  const ConnectedChild = connect(store => store, actions)(Child);

  const initialStore = {
    count: 0
  };

  const content = mount(
    <Federal store={initialStore}>
      <ConnectedChild />
    </Federal>
  );

  t.true(content.find('#track').text() === '0');

  content.find('#anchor').simulate('click');
  content.find('#anchor').simulate('click');
  t.true(content.find('#track').text() === '2');

  content.find('#anchor').simulate('click');
  content.find('#anchor').simulate('click');
  content.find('#anchor').simulate('click');
  t.true(content.find('#track').text() === '5');
});
<|endoftext|>


<commit_before>import fs from 'fs-extra';
import path from 'path';
import { expect } from 'chai';
import webpack from 'webpack';
import rimraf from 'rimraf';
import StaticRenderHtmlWebpackPlugin from '../src';
import prettyError from '../src/utils/errors';

const RELATIVE_DIR = path.join(__dirname, '..');
const OUTPUT_DIR = path.join(__dirname, '../dist_test');
const ENTRY_FILE = path.join(__dirname, './fixtures/index.js');

const testWebpackCompile = (webpackConfig, expectedResults, outputFile, done, expectErrors) => {
  webpack(webpackConfig, (error, stats) => {
    const compilationErrors = (stats.compilation.errors || []).join('\n');

    if (expectErrors) {
      expect(compilationErrors).to.equal(expectErrors.join('\n'));
      return done();
    }
    expect(compilationErrors).to.equal('');

    if (
      outputFile && Array.isArray(outputFile) &&
      expectedResults && Array.isArray(expectedResults)
    ) {
      outputFile.map((fileName, key) => {
        expect(stats.compilation.assets).to.have.property(fileName);
        return expect(stats.compilation.assets[fileName].source()).to.equal(expectedResults[key]);
      });
    }

    return done();
  });
};

describe('Static Render Html Webpack Plugin', () => {
  const config = {
    entry: ENTRY_FILE,
    output: {
      path: OUTPUT_DIR,
      filename: 'main.js',
    },
    plugins: [],
  };

  beforeEach((done) => {
    rimraf(OUTPUT_DIR, [], done);
  });

  afterEach((done) => {
    rimraf(OUTPUT_DIR, [], done);
  });

  it('should add error entry property not found to compilation', (done) => {
    config.plugins = [new StaticRenderHtmlWebpackPlugin()];
    testWebpackCompile(config, 'Error', null, done, [prettyError.emptyEntry(RELATIVE_DIR)]);
  });

  it('should add error entry file extension to compilation', (done) => {
    const entry = path.join(__dirname, './fixtures/styles.css');
    config.plugins = [new StaticRenderHtmlWebpackPlugin({
      entry,
    })];
    testWebpackCompile(config, 'Error', null, done, [prettyError.fileExtension(entry, RELATIVE_DIR)]);
  });

  it('should add error not valid ReactElement to compilation', (done) => {
    const entry = path.join(__dirname, './fixtures/some_function.js');
    config.plugins = [new StaticRenderHtmlWebpackPlugin({
      entry,
    })];
    testWebpackCompile(config, 'Error', null, done, [prettyError.errorWrapper('Invariant Violation: renderToStaticMarkup(): You must pass a valid ReactElement.')]);
  });

  it('should create main.html in output dir', (done) => {
    const entry = path.join(__dirname, './fixtures/main.jsx');
    config.plugins = [new StaticRenderHtmlWebpackPlugin({
      entry,
    })];

    const expectHtmlNames = [
      'main.html',
    ];
    const expectHtmlSources = [
      fs.readFileSync(path.join(__dirname, './fixtures/main.html'), 'utf8'),
    ];
    testWebpackCompile(config, expectHtmlSources, expectHtmlNames, done);
  });

  it('should create main.html, about.html, contacts.html in output dir', (done) => {
    const entry = path.join(__dirname, './fixtures/multiple_html.jsx');
    config.plugins = [new StaticRenderHtmlWebpackPlugin({
      entry,
    })];

    const expectHtmlNames = [
      'main.html',
      'about.html',
      'contacts.html',
    ];
    const expectHtmlSources = [
      fs.readFileSync(path.join(__dirname, './fixtures/main.html'), 'utf8'),
      fs.readFileSync(path.join(__dirname, './fixtures/about.html'), 'utf8'),
      fs.readFileSync(path.join(__dirname, './fixtures/contacts.html'), 'utf8'),
    ];
    testWebpackCompile(config, expectHtmlSources, expectHtmlNames, done);
  });
});
<commit_msg>update tests<commit_after>import fs from 'fs-extra';
import path from 'path';
import { expect } from 'chai';
import webpack from 'webpack';
import rimraf from 'rimraf';
import StaticRenderHtmlWebpackPlugin from '../src';
import prettyError from '../src/utils/errors';

const RELATIVE_DIR = path.join(__dirname, '..');
const OUTPUT_DIR = path.join(__dirname, '../dist_test');
const ENTRY_FILE = path.join(__dirname, './fixtures/index.js');

const testWebpackCompile = (webpackConfig, expectedResults, outputFile, done, expectErrors) => {
  webpack(webpackConfig, (error, stats) => {
    const compilationErrors = (stats.compilation.errors || []).join('\n');

    if (expectErrors) {
      expect(compilationErrors).to.equal(expectErrors.join('\n'));
      return done();
    }
    expect(compilationErrors).to.equal('');

    if (
      outputFile && Array.isArray(outputFile) &&
      expectedResults && Array.isArray(expectedResults)
    ) {
      outputFile.map((fileName, key) => {
        expect(stats.compilation.assets).to.have.property(fileName);
        return expect(stats.compilation.assets[fileName].source()).to.equal(expectedResults[key]);
      });
    }

    return done();
  });
};

describe('Static Render Html Webpack Plugin', () => {
  const config = {
    entry: ENTRY_FILE,
    output: {
      path: OUTPUT_DIR,
      filename: 'main.js',
    },
    plugins: [],
  };

  beforeEach((done) => {
    rimraf(OUTPUT_DIR, [], done);
  });

  afterEach((done) => {
    rimraf(OUTPUT_DIR, [], done);
  });

  it('should add error entry property not found to compilation', (done) => {
    config.plugins = [new StaticRenderHtmlWebpackPlugin()];
    testWebpackCompile(config, 'Error', null, done, [prettyError.emptyEntry(RELATIVE_DIR)]);
  });

  it('should add error entry file extension to compilation', (done) => {
    const entry = path.join(__dirname, './fixtures/styles.css');
    config.plugins = [new StaticRenderHtmlWebpackPlugin({
      entry,
    })];
    testWebpackCompile(config, 'Error', null, done, [prettyError.fileExtension(entry, RELATIVE_DIR)]);
  });

  it('should add error not valid ReactElement to compilation', (done) => {
    const entry = path.join(__dirname, './fixtures/some_function.js');
    config.plugins = [new StaticRenderHtmlWebpackPlugin({
      entry,
    })];
    testWebpackCompile(config, 'Error', null, done, [prettyError.errorWrapper('Invariant Violation: renderToStaticMarkup(): You must pass a valid ReactElement.')]);
  });

  it('should create main.html in output dir', (done) => {
    const entry = path.join(__dirname, './fixtures/main.jsx');
    config.plugins = [new StaticRenderHtmlWebpackPlugin({
      entry,
      pretty: true,
    })];

    const expectHtmlNames = [
      'main.html',
    ];
    const expectHtmlSources = [
      fs.readFileSync(path.join(__dirname, './fixtures/main.html'), 'utf8'),
    ];
    testWebpackCompile(config, expectHtmlSources, expectHtmlNames, done);
  });

  it('should create main.html, about.html, contacts.html in output dir', (done) => {
    const entry = path.join(__dirname, './fixtures/multiple_html.jsx');
    config.plugins = [new StaticRenderHtmlWebpackPlugin({
      entry,
      pretty: true,
    })];

    const expectHtmlNames = [
      'main.html',
      'about.html',
      'contacts.html',
    ];
    const expectHtmlSources = [
      fs.readFileSync(path.join(__dirname, './fixtures/main.html'), 'utf8'),
      fs.readFileSync(path.join(__dirname, './fixtures/about.html'), 'utf8'),
      fs.readFileSync(path.join(__dirname, './fixtures/contacts.html'), 'utf8'),
    ];
    testWebpackCompile(config, expectHtmlSources, expectHtmlNames, done);
  });
});
<|endoftext|>


<commit_before>/**
 * Created by dob on 20.11.13.
 */
var should = require('should'),
  util = require('util'),
  EventEmitter = require('events').EventEmitter,
  mlcl_database = require('mlcl_database'),
  mlcl_elastic = require('../');

describe('mlcl_elastic', function() {
  var mlcl;
  var molecuel;

  before(function(done) {
    // init fake molecuel
    mlcl = function() {
      return this;
    };
    util.inherits(mlcl, EventEmitter);
    molecuel = new mlcl();

    molecuel.config = { };
    molecuel.config.search = {
      host: 'localhost',
      port: '9200',
      prefix: 'mlcl-elastic-unit'
    };
    molecuel.config.database = {
      type: 'mongodb',
      uri: 'mongodb://localhost/mlcl-elastic-unit'
    };
    mlcl_database(molecuel);
    mlcl_elastic(molecuel);
    done();
  });

  describe('elastic', function() {
    var searchcon;
    var dbcon;
    it('should initialize search connection', function(done) {
      molecuel.emit('mlcl::core::init:post', molecuel);
      molecuel.once('mlcl::search::connection:success', function(search) {
        searchcon = search;
        search.should.be.a.object;
        done();
      });
    });

    it('should initialize db connection', function(done) {
      molecuel.once('mlcl::database::connection:success', function(database) {
        dbcon = database;
        database.should.be.a.object;
        done();
      });
    });

    it('should initialize schema plugin', function(done) {
      var Schema = dbcon.database.Schema;
      var testSchema = new Schema({
        name: {type: String}
      });
      var model = dbcon.registerModel('test', testSchema, {indexable:true});
      model.schema.methods.search.should.be.a.function;
      done();
    });
  });
});
<commit_msg>change unit test<commit_after>/**
 * Created by dob on 20.11.13.
 */
var should = require('should'),
  util = require('util'),
  EventEmitter = require('events').EventEmitter,
  mlcl_database = require('mlcl_database'),
  mlcl_elastic = require('../');

describe('mlcl_elastic', function() {
  var mlcl;
  var molecuel;

  before(function(done) {
    // init fake molecuel
    mlcl = function() {
      return this;
    };
    util.inherits(mlcl, EventEmitter);
    molecuel = new mlcl();

    molecuel.config = { };
    molecuel.config.search = {
      host: 'localhost',
      port: '9200',
      prefix: 'mlcl-elastic-unit'
    };
    molecuel.config.database = {
      type: 'mongodb',
      uri: 'mongodb://localhost/mlcl-elastic-unit'
    };
    mlcl_database(molecuel);
    mlcl_elastic(molecuel);
    done();
  });

  describe('elastic', function() {
    var searchcon;
    var dbcon;
    it('should initialize search connection', function(done) {
      molecuel.once('mlcl::search::connection:success', function(search) {
        searchcon = search;
        search.should.be.a.object;
        done();
      });
      molecuel.emit('mlcl::core::init:post', molecuel);
    });

    it('should initialize db connection', function(done) {
      molecuel.once('mlcl::database::connection:success', function(database) {
        dbcon = database;
        database.should.be.a.object;
        done();
      });
      molecuel.emit('mlcl::core::init:post', molecuel);
    });

    it('should initialize schema plugin', function(done) {
      var Schema = dbcon.database.Schema;
      var testSchema = new Schema({
        name: {type: String}
      });
      var model = dbcon.registerModel('test', testSchema, {indexable:true});
      model.schema.methods.search.should.be.a.function;
      done();
    });
  });
});
<|endoftext|>


<commit_before>"use strict"

var expect = require('expect.js')
var flow = require('../')

describe('Finally', function(){

  describe('syncronous operations', function() {

    it('should accept a last step in finally', function() {

      flow()
      .then(function(err, data) {
        expect(data).to.be(1)
        this.continue(null, data + 1)
      })
      .then(function(err, data) {
        expect(data).to.be(2)
        this.continue(null, data + 1)
      })
      .then(function(err, data) {
        expect(data).to.be(3)
      })
      .run(null, 1)

    })

    it('should accept a first step in the constructor and a last step in finally', function() {

      flow(function() {
        this.continue(null, 1)
      })
      .then(function(err, data) {
        expect(data).to.be(1)
        this.continue(null, data + 1)
      })
      .finally(function(err, data) {
        expect(data).to.be(2)
      })

    })

    it('should keep the parallels order', function() {

      var counter = 0

      flow([
        function() {
          this.done(null, counter++)
        },
        function(){
          this.done(null, counter++)
        }
      ])
      .then(function(err, n1, n2) {
        expect(counter).to.be(2)
        expect(n1).to.be(0)
        expect(n2).to.be(1)
        this.continue(null, counter)
      })
      .finally(function(err, data) {
        expect(data).to.be(2)
      })

    })

    it('should continue on parallels', function() {

      flow([
        function() {
          this.continue(null, 20)
        },
        function(){
          this.continue(null, 10)
        }
      ])
      .finally(function(err, n1, n2) {
        expect(n1).to.be(20)
        expect(n2).to.be(undefined)
      })

    })

    it('should break on parallels', function() {

      flow([
        function() {
          this.break(null, 20)
        }, function(){
          this.break(null, 10)
        }
      ])
      .then(function(err, n1, n2) {
        throw new Error('this should never get called')
      })
      .finally(function(err, data) {
        expect(data).to.be(20)
      })

    })

    it('should spread values to and from parallels', function() {

      var counter = 0

      flow(function() {
        this.spread(null, [10, 20, 30])
      })
      .then(function(err, n){
        counter += n
        this.done(null, n)
      })
      .finally(function(err, n1, n2, n3) {
        expect(n1).to.be(10)
        expect(n2).to.be(20)
        expect(n3).to.be(30)
        expect(counter).to.be(60)
      })

    })

  })

  describe('asyncronous operations', function() {

    it('should accept a last step in finally', function(done) {

      flow()
      .then(function(err, data) {
        setTimeout(function() {
          expect(data).to.be(1)
          this.continue(null, data + 1)
        }.bind(this), 10)
      })
      .then(function(err, data) {
        setTimeout(function() {
          expect(data).to.be(2)
          this.continue(null, data + 1)
        }.bind(this), 10)
      })
      .then(function(err, data) {
        setTimeout(function() {
          expect(data).to.be(3)
          done()
        }.bind(this), 10)
      })
      .run(null, 1)

    })

    it('should accept a first step in the constructor and a last step in finally', function(done) {

      flow(function() {
        setTimeout(function() {
          this.continue(null, 1)
        }.bind(this), 10)
      })
      .then(function(err, data) {
        setTimeout(function() {
          expect(data).to.be(1)
          this.continue(null, data + 1)
        }.bind(this), 10)
      })
      .finally(function(err, data) {
        setTimeout(function() {
          expect(data).to.be(2)
          done()
        }.bind(this), 10)
      })

    })

    it('should keep the parallels order', function(done) {

      flow([
        function() {
          setTimeout(function() {
            this.done(null, 0)
          }.bind(this), 20)
        },
        function(){
          setTimeout(function() {
            this.done(null, 1)
          }.bind(this), 10)
        }
      ])
      .then(function(err, n1, n2) {
        setTimeout(function() {
          expect(n1).to.be(0)
          expect(n2).to.be(1)
          this.continue(null, n1 + n2)
        }.bind(this), 10)
      })
      .finally(function(err, data) {
        setTimeout(function() {
          expect(data).to.be(1)
          done()
        }.bind(this), 10)
      })

    })

    it('should continue on parallels', function(done) {

      flow([
        function() {
          setTimeout(function() {
            this.continue(null, 20)
          }.bind(this), 20)
        },
        function(){
          setTimeout(function() {
            this.continue(null, 10)
          }.bind(this), 5)
        }
      ])
      .finally(function(err, n1, n2) {
        setTimeout(function() {
          expect(n1).to.be(10)
          expect(n2).to.be(undefined)
          done()
        }.bind(this), 10)
      })

    })

    it('should break on parallels', function(done) {

      flow([
        function() {
          setTimeout(function() {
            this.break(null, 20)
          }.bind(this), 20)
        }, function(){
          setTimeout(function() {
            this.break(null, 10)
          }.bind(this), 10)
        }
      ])
      .then(function(err, n1, n2) {
        throw new Error('this should never get called')
      })
      .finally(function(err, data) {
        setTimeout(function() {
          expect(data).to.be(10)
          done()
        }.bind(this), 10)
      })

    })

    it('should spread values to and from parallels', function(done) {

      var ms = 50

      flow(function() {
        this.spread(null, [10, 20, 30])
      })
      .then(function(err, n){
        setTimeout(function() {
          this.done(null, n)
        }.bind(this), ms -= 10)
      })
      .finally(function(err, n1, n2, n3) {
        setTimeout(function() {
          expect(n1).to.be(10)
          expect(n2).to.be(20)
          expect(n3).to.be(30)
          done()
        }.bind(this), 10)
      })

    })

  })

})
<commit_msg>add test for empty parallels<commit_after>"use strict"

var expect = require('expect.js')
var flow = require('../')

describe('Finally', function(){

  describe('syncronous operations', function() {

    it('should accept a last step in finally', function() {

      flow()
      .then(function(err, data) {
        expect(data).to.be(1)
        this.continue(null, data + 1)
      })
      .then(function(err, data) {
        expect(data).to.be(2)
        this.continue(null, data + 1)
      })
      .then(function(err, data) {
        expect(data).to.be(3)
      })
      .run(null, 1)

    })

    it('should accept a first step in the constructor and a last step in finally', function() {

      flow(function() {
        this.continue(null, 1)
      })
      .then(function(err, data) {
        expect(data).to.be(1)
        this.continue(null, data + 1)
      })
      .finally(function(err, data) {
        expect(data).to.be(2)
      })

    })

    it('should keep the parallels order', function() {

      var counter = 0

      flow([
        function() {
          this.done(null, counter++)
        },
        function(){
          this.done(null, counter++)
        }
      ])
      .then(function(err, n1, n2) {
        expect(counter).to.be(2)
        expect(n1).to.be(0)
        expect(n2).to.be(1)
        this.continue(null, counter)
      })
      .finally(function(err, data) {
        expect(data).to.be(2)
      })

    })

    it('should continue on parallels', function() {

      flow([
        function() {
          this.continue(null, 20)
        },
        function(){
          this.continue(null, 10)
        }
      ])
      .finally(function(err, n1, n2) {
        expect(n1).to.be(20)
        expect(n2).to.be(undefined)
      })

    })

    it('should break on parallels', function() {

      flow([
        function() {
          this.break(null, 20)
        }, function(){
          this.break(null, 10)
        }
      ])
      .then(function(err, n1, n2) {
        throw new Error('this should never get called')
      })
      .finally(function(err, data) {
        expect(data).to.be(20)
      })

    })

    it('should spread values to and from parallels', function() {

      var counter = 0

      flow(function() {
        this.spread(null, [10, 20, 30])
      })
      .then(function(err, n){
        counter += n
        this.done(null, n)
      })
      .finally(function(err, n1, n2, n3) {
        expect(n1).to.be(10)
        expect(n2).to.be(20)
        expect(n3).to.be(30)
        expect(counter).to.be(60)
      })

    })

    it('should ignore empty parallels', function() {

      flow().then([]).then().finally(function(err) {
        expect(err).to.be(undefined)
      })

    })

  })

  describe('asyncronous operations', function() {

    it('should accept a last step in finally', function(done) {

      flow()
      .then(function(err, data) {
        setTimeout(function() {
          expect(data).to.be(1)
          this.continue(null, data + 1)
        }.bind(this), 10)
      })
      .then(function(err, data) {
        setTimeout(function() {
          expect(data).to.be(2)
          this.continue(null, data + 1)
        }.bind(this), 10)
      })
      .then(function(err, data) {
        setTimeout(function() {
          expect(data).to.be(3)
          done()
        }.bind(this), 10)
      })
      .run(null, 1)

    })

    it('should accept a first step in the constructor and a last step in finally', function(done) {

      flow(function() {
        setTimeout(function() {
          this.continue(null, 1)
        }.bind(this), 10)
      })
      .then(function(err, data) {
        setTimeout(function() {
          expect(data).to.be(1)
          this.continue(null, data + 1)
        }.bind(this), 10)
      })
      .finally(function(err, data) {
        setTimeout(function() {
          expect(data).to.be(2)
          done()
        }.bind(this), 10)
      })

    })

    it('should keep the parallels order', function(done) {

      flow([
        function() {
          setTimeout(function() {
            this.done(null, 0)
          }.bind(this), 20)
        },
        function(){
          setTimeout(function() {
            this.done(null, 1)
          }.bind(this), 10)
        }
      ])
      .then(function(err, n1, n2) {
        setTimeout(function() {
          expect(n1).to.be(0)
          expect(n2).to.be(1)
          this.continue(null, n1 + n2)
        }.bind(this), 10)
      })
      .finally(function(err, data) {
        setTimeout(function() {
          expect(data).to.be(1)
          done()
        }.bind(this), 10)
      })

    })

    it('should continue on parallels', function(done) {

      flow([
        function() {
          setTimeout(function() {
            this.continue(null, 20)
          }.bind(this), 20)
        },
        function(){
          setTimeout(function() {
            this.continue(null, 10)
          }.bind(this), 5)
        }
      ])
      .finally(function(err, n1, n2) {
        setTimeout(function() {
          expect(n1).to.be(10)
          expect(n2).to.be(undefined)
          done()
        }.bind(this), 10)
      })

    })

    it('should break on parallels', function(done) {

      flow([
        function() {
          setTimeout(function() {
            this.break(null, 20)
          }.bind(this), 20)
        }, function(){
          setTimeout(function() {
            this.break(null, 10)
          }.bind(this), 10)
        }
      ])
      .then(function(err, n1, n2) {
        throw new Error('this should never get called')
      })
      .finally(function(err, data) {
        setTimeout(function() {
          expect(data).to.be(10)
          done()
        }.bind(this), 10)
      })

    })

    it('should spread values to and from parallels', function(done) {

      var ms = 50

      flow(function() {
        this.spread(null, [10, 20, 30])
      })
      .then(function(err, n){
        setTimeout(function() {
          this.done(null, n)
        }.bind(this), ms -= 10)
      })
      .finally(function(err, n1, n2, n3) {
        setTimeout(function() {
          expect(n1).to.be(10)
          expect(n2).to.be(20)
          expect(n3).to.be(30)
          done()
        }.bind(this), 10)
      })

    })

  })

})
<|endoftext|>


<commit_before>import chai from 'chai';
import fs from 'fs';
import { GCodeParser, parseFile, parseText, parseStream } from '../dist/';
import _ from 'lodash';

const expect = chai.expect;
const should = chai.should();

describe('G-code Parser', (done) => {
	describe('Pass a null value as the first argument', (done) => {
		it('should call parseText\'s callback.', (done) => {
            parseText(null, (err, results) => {
                expect(err).to.be.okay;
                done();
            });
		});
		it('should call parseFile\'s callback.', (done) => {
            parseFile(null, (err, results) => {
                expect(err).to.be.okay;
                done();
            });
		});
		it('should call parseStream\'s callback.', (done) => {
            parseStream(null, (err, results) => {
                expect(err).to.be.okay;
                done();
            });
		});
    });

    describe('Pass an empty text as the first argument', (done) => {
		it('should get empty results.', (done) => {
            let sampleText = '';
            parseText(sampleText, (err, results) => {
                expect(results.length).to.be.empty;
                done();
            });
        });
    });

    describe('Contains only comments', (done) => {
		it('should get empty results.', (done) => {
            let sampleText = [
                ';',
                '; Operation:    0',
                '; Name:',
                '; Type:         Pocket',
                '; Paths:        3',
                '; Direction:    Conventional',
                '; Cut Depth:    3.175',
                '; Pass Depth:   1.9999999999999998',
                '; Plunge rate:  127',
                '; Cut rate:     1016',
                '  ' // empty line
            ].join('\n');
            parseText(sampleText, (err, results) => {
                expect(results.length).to.be.empty;
                done();
            });
        });
    });

	describe('File not found exception', (done) => {
		it('should fail the callback if a file is not present.', (done) => {
            parseFile('test/fixtures/NO_FILE_ERROR', (err, results) => {
                expect(err).to.not.be.null;
                expect(err.code).to.equal('ENOENT');
                done();
            });
		});
	});

	describe('parseStream / parseText / parseFile', (done) => {
        let expectedResults = [
            {
                line: 'G0 X-5 Y0 Z0 F200',
                N: undefined,
                words: [['G', 0], ['X', -5], ['Y', 0], ['Z', 0], ['F', 200]]
            },
            {
                line: 'G2 X0 Y5 I5 J0 F200',
                N: undefined,
                words: [['G', 2], ['X', 0], ['Y', 5], ['I', 5], ['J', 0], ['F', 200]]
            },
            {
                line: 'G02 X5 Y0 I0 J-5',
                N: undefined,
                words: [['G', 2], ['X', 5], ['Y', 0], ['I', 0], ['J', -5]]
            },
            {
                line: 'G02 X0 Y-5 I-5 J0',
                N: undefined,
                words: [['G', 2], ['X', 0], ['Y',-5], ['I', -5], ['J', 0]]
            },
            {
                line: 'G02 X-5 Y0 I0 J5',
                N: undefined,
                words: [['G', 2], ['X', -5], ['Y', 0], ['I', 0], ['J', 5]]
            },
            {
                line: 'G01 Z1 F500',
                N: undefined,
                words: [['G', 1], ['Z', 1], ['F', 500]]
            },
            {
                line: 'G00 X0 Y0 Z5',
                N: undefined,
                words: [['G', 0], ['X', 0], ['Y', 0], ['Z', 5]]
            }
        ];

        it('should get the expected results in the parseFile\'s callback.', (done) => {
            parseFile('test/fixtures/circle.nc', (err, results) => {
                expect(results).to.deep.equal(expectedResults);
                done();
            });
		});

        it('should get the expected results in the parseText\'s callback.', (done) => {
            let text = fs.readFileSync('test/fixtures/circle.nc', 'utf8');
            parseText(text, (err, results) => {
                expect(results).to.deep.equal(expectedResults);
                done();
            });
		});

        it('should get the expected results in the parseStream\'s callback.', (done) => {
            let stream = fs.createReadStream('test/fixtures/circle.nc', { encoding: 'utf8' });
            parseStream(stream, (err, results) => {
                expect(results).to.deep.equal(expectedResults);
                done();
            });
		});
	});

	describe('More G-code Examples', (done) => {
		it('should contain the line number.', (done) => {
            parseFile('test/fixtures/circle-inch.nc', (err, list) => {
                expect(err).to.be.null;
                list.forEach((data) => {
                    let { N } = data;
                    expect(N).to.exist;
                });
                done();
            });
        });
	});
});
<commit_msg>Update index.js<commit_after>import chai from 'chai';
import fs from 'fs';
import { GCodeParser, parseFile, parseText, parseStream } from '../dist/';
import _ from 'lodash';

const expect = chai.expect;
const should = chai.should();

describe('G-code Parser', (done) => {
    describe('Pass a null value as the first argument', (done) => {
        it('should call parseText\'s callback.', (done) => {
            parseText(null, (err, results) => {
                expect(err).to.be.okay;
                done();
            });
        });
        it('should call parseFile\'s callback.', (done) => {
            parseFile(null, (err, results) => {
                expect(err).to.be.okay;
                done();
            });
        });
        it('should call parseStream\'s callback.', (done) => {
            parseStream(null, (err, results) => {
                expect(err).to.be.okay;
                done();
            });
        });
    });

    describe('Pass an empty text as the first argument', (done) => {
        it('should get empty results.', (done) => {
            let sampleText = '';
            parseText(sampleText, (err, results) => {
                expect(results.length).to.be.empty;
                done();
            });
        });
    });

    describe('Contains only comments', (done) => {
        it('should get empty results.', (done) => {
            let sampleText = [
                ';',
                '; Operation:    0',
                '; Name:',
                '; Type:         Pocket',
                '; Paths:        3',
                '; Direction:    Conventional',
                '; Cut Depth:    3.175',
                '; Pass Depth:   1.9999999999999998',
                '; Plunge rate:  127',
                '; Cut rate:     1016',
                '  ' // empty line
            ].join('\n');
            parseText(sampleText, (err, results) => {
                expect(results.length).to.be.empty;
                done();
            });
        });
    });

    describe('File not found exception', (done) => {
        it('should fail the callback if a file is not present.', (done) => {
            parseFile('test/fixtures/NO_FILE_ERROR', (err, results) => {
                expect(err).to.not.be.null;
                expect(err.code).to.equal('ENOENT');
                done();
            });
        });
    });

    describe('parseStream / parseText / parseFile', (done) => {
        let expectedResults = [
            {
                line: 'G0 X-5 Y0 Z0 F200',
                N: undefined,
                words: [['G', 0], ['X', -5], ['Y', 0], ['Z', 0], ['F', 200]]
            },
            {
                line: 'G2 X0 Y5 I5 J0 F200',
                N: undefined,
                words: [['G', 2], ['X', 0], ['Y', 5], ['I', 5], ['J', 0], ['F', 200]]
            },
            {
                line: 'G02 X5 Y0 I0 J-5',
                N: undefined,
                words: [['G', 2], ['X', 5], ['Y', 0], ['I', 0], ['J', -5]]
            },
            {
                line: 'G02 X0 Y-5 I-5 J0',
                N: undefined,
                words: [['G', 2], ['X', 0], ['Y',-5], ['I', -5], ['J', 0]]
            },
            {
                line: 'G02 X-5 Y0 I0 J5',
                N: undefined,
                words: [['G', 2], ['X', -5], ['Y', 0], ['I', 0], ['J', 5]]
            },
            {
                line: 'G01 Z1 F500',
                N: undefined,
                words: [['G', 1], ['Z', 1], ['F', 500]]
            },
            {
                line: 'G00 X0 Y0 Z5',
                N: undefined,
                words: [['G', 0], ['X', 0], ['Y', 0], ['Z', 5]]
            }
        ];

        it('should get the expected results in the parseFile\'s callback.', (done) => {
            parseFile('test/fixtures/circle.nc', (err, results) => {
                expect(results).to.deep.equal(expectedResults);
                done();
            });
        });

        it('should get the expected results in the parseText\'s callback.', (done) => {
            let text = fs.readFileSync('test/fixtures/circle.nc', 'utf8');
            parseText(text, (err, results) => {
                expect(results).to.deep.equal(expectedResults);
                done();
            });
        });

        it('should get the expected results in the parseStream\'s callback.', (done) => {
            let stream = fs.createReadStream('test/fixtures/circle.nc', { encoding: 'utf8' });
            parseStream(stream, (err, results) => {
                expect(results).to.deep.equal(expectedResults);
                done();
            });
        });
    });

    describe('More G-code Examples', (done) => {
        it('should contain the line number.', (done) => {
            parseFile('test/fixtures/circle-inch.nc', (err, list) => {
                expect(err).to.be.null;
                list.forEach((data) => {
                    let { N } = data;
                    expect(N).to.exist;
                });
                done();
            });
        });
    });
});
<|endoftext|>