среда, 24 февраля 2016 г.

JavaScript JSON Validator

// Функция валидации JSON принимает текстовую строку
// и возвращает true, если текст является валидным JSON
// или возвращает false, если текст является невалидным JSON
function validateJSON (text) {
    text = '' + text;

    // Заменяем опасные символы в формате Unicode на их escape-последовательности.
    var dangerousSymbolsPattern = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
    dangerousSymbolsPattern.lastIndex = 0;
    if (dangerousSymbolsPattern.test(text)) {
        text = text.replace(dangerousSymbolsPattern, function (char) {
            return '\\u' + ('0000' + char.charCodeAt(0).toString(16)).slice(-4);
        });
    }

    text = text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@') // заменяем все символы переноса строки, табы или символы в формате Unicode на символ @
                    .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']') // заменяем простые значения токенов типа true, false, null на символ ]
                    .replace(/(?:^|:|,)(?:\s*\[)+/g, ''); // удаляем все открывающие скобки ( и [ в начале строки или следующие за двоеточием и запятой

   if (/^[\],:{}\s]*$/.test(text)) { // проверим являются ли оставшиеся символы только символами: ],:{}
        return true;
    } else {
        return false;
    }

}

console.log(validateJSON('{"one": 1}'));

пятница, 19 февраля 2016 г.

JavaScript console code executor (evaluator)

<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title>Console</title>
</head>
<body>

<div id="output" style="overflow: auto; width: 500px; height: 300px; border: 2px solid black;"></div>
<textarea id="input" style="width: 500px; height: 200px; border: 2px solid black;"></textarea>
<br />
<input id="run" type="button" value="Run" />

<script>

function Evaluator () {
    this.environment = {};
    this.console = {
        log: function (message) {console.log('>>> ' + message);}
    };
}

Evaluator.prototype.evaluate = function (codeString) {
    try {
        codeString = rewriteDeclarations(codeString);
        var __environment__ = this.environment
            , console = this.console; // Temporarily shadow the global console for eval()
        with (__environment__) {
            return JSON.stringify(eval(codeString));
        }
    } catch (error) {
        return error.toString();
    }
}

function rewriteDeclarations (codeString) {
    codeString = "\n" + codeString; // Prefix a newline so that search and replace is simpler
    codeString = codeString.replace(/\nvar\s+(\w+)\s*=/g, '\n__environment__.$1 =');
    codeString = codeString.replace(/\nfunction\s+(\w+)/g, '\n__environment__.$1 = function');
    return codeString.slice(1); // Remove prefixed newline
}

var output = document.getElementById('output')
    , input = document.getElementById('input')
    , run = document.getElementById('run')
    , e = new Evaluator();

run.onclick = function () {
    var code = input.value
        , result = document.createElement('p');
    result.innerHTML = e.evaluate(code);
    output.appendChild(result);
};

</script>
</body>
</html>

JavaScript console.log() polyfill

;(function (global) {
    global.console = global.console || {};
    var timers = {}
        , property
        , properties = 'memory'.split(',')
        , method
        , methods = ('assert,clear,count,debug,dir,dirxml,error,exception,'
                        + 'group,groupCollapsed,groupEnd,info,log,markTimeline,'
                        + 'profile,profiles,profileEnd,show,table,time,timeEnd,'
                        + 'timeline,timelineEnd,timeStamp,trace,warn').split(',');
        while (properties.length > 0) {
            property = properties.pop();
            if (!global.console.hasOwnProperty(property)) {
                global.console[property] = {};
           }
        }
        while (methods.length > 0) {
            method = methods.pop();
            if (
                    !global.console.hasOwnProperty(method)
                || Object.prototype.toString.call(global.console[method]) !== '[object Function]'
            ) {
                if (
                        method === 'log'
                    || method === 'debug'
                    || method === 'info'
                    || method === 'warn'
                    || method === 'error'
                    || method === 'exception'
                    || method === 'dir'
                    || method === 'dirxml'
                ) {
                    global.console[method] = function (message) {alert(message);};
                } else if (
                        method === 'assert'
                ) {
                    global.console[method] = function() {
                        var args = Array.prototype.slice.call(arguments, 0)
                            , expression = args.shift();
                        if (!expression) {
                            args[0] = 'Assertion failed: ' + args[0];
                            console.error.apply(console, args);
                        }
                    };
                } else if (
                        method === 'time'
                ) {
                    global.console[method] = function (id) {
                        timers[id] = new Date().getTime();
                    };
                } else if (
                        method === 'timeEnd'
                ) {
                    global.console[method] = function (id) {
                        var start = timers[id];
                        if (start) {
                            global.console.log(id + ': ' + (new Date().getTime() - start) + 'ms');
                            delete timers[id];
                        }
                    };
                } else {
                    global.console[method] = function () {};
                }
           }
        }
})(this);

console.log(111);

console.assert(1 > 2, 'b');

console.time('one');

console.timeEnd('one');

console.dir([1,2]);

Полноценный JavaScript-шаблонизатор Template аналог EJS

;(function (global, factory) {
    if (typeof define === "function" && define.amd) {
        define(factory);
    } else if (typeof module === "object" && typeof module.exports === "object") {
        module.exports = factory();
    } else {
        global.TPL = factory();
    }
})(this, function () {

    // Usage:
    // console.log(new TPL.Template("<div>Total: {{= value }}<div>", {delimiters: ["{{", "}}"]}).render({value: "<span>15</span>"}));

    // Options:
    // delimiters        - characters to use for open and close delimiters
    // rmWhitespace - remove whitespace between HTML-tags

    // Tags:
    // <%    - scriptlet tag for control-flow, no output
    // <%% - outputs raw template part
    // <%-   - outputs the raw unescaped value into the template
    // <%=  - outputs the HTML escaped value into the template
    // <%#  - comment tag, no execution, no output
    // %>    - plain ending tag

    function Template (templateString, newSettingsObject) {
        var settingsObject = {
              delimiters: ["<%", "%>"]
            , rmWhitespace: false // removeWhitespace
        };
        if (newSettingsObject) {setNewSettings(settingsObject, newSettingsObject);}
        var renderFunction = createRenderFunction(templateString, settingsObject); // console.log(renderFunction.toString());
        return {render: function (dataObject) {return renderFunction(dataObject, settingsObject, escapeHtmlFunction, trim);}};
    }

    function setNewSettings (settingsObject, newSettingsObject) {
        for (var key in newSettingsObject) {
            if (newSettingsObject.hasOwnProperty(key)) {
                settingsObject[key] = newSettingsObject[key];
            }
        }
    }

    function trim (text) {
        return text == null ? "" : ("" + text).replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, ""); // Trim space: \s, BOM: \uFEFF, NBSP: \xA0.
    }

    function createRenderFunction (templateString, settingsObject) {
        var matchRegExp = createMatchRegExp(settingsObject)
            , renderFunction;
        try {
            renderFunction = new Function ("dataObject", "_settingsObject_", "_escapeHtmlFunction_", "_trim_" // ) {
                     , "if (!dataObject) {dataObject = {};}" + "\n"
                    + "var _parsedTemplateString_ = '';" + "\n"
                    + "with (dataObject) {" + "\n"
                    +     "_parsedTemplateString_ += '" + (function(){
                                    var resultString = ""
                                        , index = 0;
                                    templateString.replace(matchRegExp, function (match, prerenderCodeString, rawInterpolateCodeString, interpolateAndEscapeCodeString, commentCodeString, evaluateCodeString, offset) {
                                        resultString += escapeString(templateString.slice(index, offset));
                                        index = offset + match.length;
                                        if (prerenderCodeString !== undefined) {
                                            resultString += "' + '" + settingsObject.delimiters[0] + prerenderCodeString + settingsObject.delimiters[1] + "' + '";
                                        } else if (rawInterpolateCodeString !== undefined) {
                                            resultString += "'" + "\n"
                                                                 + "+ (function(){" + "\n"
                                                                 +            "var _value_ = " + rawInterpolateCodeString + ";" + "\n"
                                                                 +            "if (_value_ === undefined || _value_ === null) {return '';} else {return _value_;}" + "\n"
                                                                 +        "})()" + "\n"
                                                                 + "+ '";
                                        } else if (interpolateAndEscapeCodeString !== undefined) {
                                            resultString += "'" + "\n"
                                                                 + "+ (function(){" + "\n"
                                                                 +            "var _value_ = " + interpolateAndEscapeCodeString + ";" + "\n"
                                                                 +            "if (_value_ === undefined || _value_ === null) {return '';} else {return _escapeHtmlFunction_(_value_);}" + "\n"
                                                                 +        "})()" + "\n"
                                                                 + "+ '";
                                        } else if (commentCodeString !== undefined) {
                                            // Do nothing
                                        } else if (evaluateCodeString !== undefined) {
                                            resultString += "';" + "\n"
                                                                 + evaluateCodeString + "\n"
                                                                 + "_parsedTemplateString_ += '";
                                        }
                                        return match;
                                    });
                                    return resultString;
                                })()
                    +     "';" + "\n"
                    + "}" + "\n"
                    + "if (_settingsObject_.rmWhitespace) {_parsedTemplateString_ = _trim_(_parsedTemplateString_.replace(/\\\\r/g, ''));}" + "\n"
                    + "return _parsedTemplateString_;"
            // }
            );
        } catch (error) {
            if (error instanceof SyntaxError) {error.message += " while compiling template: " + templateString;}
            throw error;
        }
        return renderFunction;
    }

    function createMatchRegExp (settingsObject) {
        var openDelimiter = settingsObject.delimiters[0] // <%
            , closeDelimiter = settingsObject.delimiters[1] // %>
            , stringInsideDelimiters = "([\\s\\S]+?)"          // some string
            , tags = {
                  prerender:                   openDelimiter + "%" + stringInsideDelimiters + closeDelimiter // <%% some string %>
                , rawInterpolate:            openDelimiter + "-" + stringInsideDelimiters + closeDelimiter  // <%= some string %>
                , interpolateAndEscape: openDelimiter + "=" + stringInsideDelimiters + closeDelimiter  // <%- some string %>
                , comment:                    openDelimiter + "#" + stringInsideDelimiters + closeDelimiter  // <%# some string %>
                , evaluate:                     openDelimiter + stringInsideDelimiters + closeDelimiter            // <% some string %>
              }
            , matchRegExp = new RegExp([
                  tags.prerender // Important!!! Must be first!
                , tags.rawInterpolate
                , tags.interpolateAndEscape
                , tags.comment
                , tags.evaluate // Important!!! Must be last!
              ].join("|") + "|$", "g"); // /<%%([\s\S]+?)%>|<%-([\s\S]+?)%>|<%=([\s\S]+?)%>|<%#([\s\S]+?)%>|<%([\s\S]+?)%>|$/g
        return matchRegExp;
    }

    function escapeString (string) {
        return string.replace(/\\|'|\r|\n|\u2028|\u2029/g, function (match) {
            var escapeCharacters = {
                  "'":          "\\'"
                , "\\":         "\\\\"
                , "\r":         "\\r"
                , "\n":        "\\n"
                , "\u2028": "\\u2028"
                , "\u2029": "\\u2029"
            };
            return escapeCharacters[match];
        });
    }

    function escapeHtmlFunction (string) {
        string = "" + string;
        var pattern = "(?:&|<|>|\"|'|`)"
            , testRegExp = new RegExp(pattern)
            , replaceRegExp = new RegExp(pattern, "g");
        if (testRegExp.test(string)) {
            return string.replace(replaceRegExp, function (match) {
                var escapeCharacters = {
                      "&":  "&amp;"
                    , "<":  "&lt;"
                    , ">":  "&gt;"
                    , "\"": "&quot;"
                    , "'":   "&#x27;"
                    , "`":  "&#x60;"
                };
                return escapeCharacters[match];
            });
        } else {
            return string;
        }
    }

    return {
          Template: Template
        , compile: function (templateString, newSettingsObject) {return new Template(templateString, newSettingsObject);}
        , render: function (templateString, dataObject, newSettingsObject) {return new Template(templateString, newSettingsObject).render(dataObject);}
    };

});

// Тесты

//console.log(new TPL.Template("  \r \r  Total: <% if (true) { %>1<% } %> Total: <%= value %> Total: <%- value %> Total: <%# comment %> Total: <%%- value %>    ", {rmWhitespace: true}).render({value: "<div>15</div>"}));

вторник, 16 февраля 2016 г.

JavaScript Template Engine

function Template (textString, optionsObject) { // new Template("Total: <%= value %>", {delimiters: ["<%", '%>"]}).render({value: 10})
    if (!optionsObject) {optionsObject = {};}
    if (!optionsObject.hasOwnProperty("delimiters")) {
        optionsObject.delimiters = ["<%", "%>"];
    }
    var openDelimiter = optionsObject.delimiters[0] // <%
        , closeDelimiter = optionsObject.delimiters[1] // %>
        , stringInsideDelimiters = "([\\s\\S]+?)"          // some string
        , tags = {
              interpolate: openDelimiter + "=" + stringInsideDelimiters + closeDelimiter  // <%= some string %>
            , escape:      openDelimiter + "-" + stringInsideDelimiters + closeDelimiter   // <%- some string %>
            , evaluate:    openDelimiter + stringInsideDelimiters + closeDelimiter             // <% some string %>
          }
        , matcherRegExp = RegExp([
              tags.interpolate
            , tags.escape
            , tags.evaluate // Important!!! Must be last!
          ].join("|") + "|$", "g") // /<%=([\s\S]+?)%>|<%-([\s\S]+?)%>|<%([\s\S]+?)%>|$/g
       , escapeReqExp = new RegExp([
              "\\\\"       // single backslash
            , "'"            // single quote
            , "\\r"         // carriage return
            , "\\n"        // newline
            , "\\u2028" // line separator
            , "\\u2029" // paragraph separator
          ].join("|"), "g") // /\\|'|\r|\n|\u2028|\u2029/g
        , escapeCharacter = function (match) {
            var characters = {
                  "'":          "\\'"
                , "\\":         "\\\\"
                , "\r":         "\\r"
                , "\n":        "\\n"
                , "\u2028": "\\u2028"
                , "\u2029": "\\u2029"
            };
            return characters[match];
          }
        , escapeTags = function (string) {
            string = (string === null) ? "" : "" + string;
            var escapeMap = {
                      "&": "&amp;"
                    , "<": "&lt;"
                    , ">": "&gt;"
                    , '"':   "&quot;"
                    , "'":  "&#x27;"
                    , "`": "&#x60;"
                  }
                , escapeSymbols = function (match) {
                    return escapeMap[match];
                  }
                , getKeys = function (object) {
                    var keys = [];
                    for (var key in object) {
                        if (object.hasOwnProperty(key)) {keys.push(key);}
                    }
                    return keys;
                  }
                , pattern = "(?:" + getKeys(escapeMap).join("|") + ")" // (?:&|<|>|"|'|`)
                , testRegExp = RegExp(pattern)
                , replaceRegExp = RegExp(pattern, "g");
            return testRegExp.test(string) ? string.replace(replaceRegExp, escapeSymbols) : string;
          }
        , renderFunction
        , render;
    try {
        renderFunction = new Function(
                                                "dataObject"
                                              , "escapeTags"
                                              , "var temp"
                                             + "    , result = '';"
                                             + "with (dataObject || {}) {"
                                             + "    result += '" + (function(){
                                                    var resultString = ""
                                                        , index = 0;
                                                    textString.replace(matcherRegExp, function (match, interpolateCodeString, escapeCodeString, evaluateCodeString, offset) {
                                                        resultString += textString.slice(index, offset)
                                                                                                .replace(escapeReqExp, escapeCharacter);
                                                        index = offset + match.length;
                                                        if (interpolateCodeString) {
                                                            resultString += "' + ( ( temp = (" + interpolateCodeString + ") ) === null ? '' : temp) + '";
                                                        } else if (escapeCodeString) {
                                                            resultString += "' + ( ( temp = (" + escapeCodeString + ") ) === null ? '' : escapeTags(temp)) + '";
                                                        } else if (evaluateCodeString) {
                                                            resultString += "';" + evaluateCodeString + "result += '";
                                                        }
                                                        return match;
                                                    });
                                                    return resultString;
                                                })()
                                             + "';"
                                             + "}"
                                             + "return result;"
        );
    } catch (error) {
        throw error;
    }
    this.render = function (dataObject) {
        return renderFunction.call(null, dataObject, escapeTags);
    };
}

console.log(new Template("Total: <% if (true) { %>1<% } %>").render({value: '<div>1</div>'}));
console.log(new Template("Total: <%= value %>").render({value: '<div>1</div>'}));
console.log(new Template("Total: <%- value %>").render({value: '<div>1</div>'}));
console.log(new Template("Total: {{= value }}", {delimiters: ["{{", "}}"]}).render({value: '<div>1</div>'}));

среда, 10 февраля 2016 г.

TypeScript Helpers from tsc.js

function __extends(d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
}
function __decorate(decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
}
function __metadata(k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
}
function __param(paramIndex, decorator) {
    return function (target, key) { decorator(target, key, paramIndex); }
}
function __awaiter(thisArg, _arguments, Promise, generator) {
    return new Promise(function (resolve, reject) {
        generator = generator.call(thisArg, _arguments);
        function cast(value) { return value instanceof Promise && value.constructor === Promise ? value : new Promise(function (resolve) { resolve(value); }); }
        function onfulfill(value) { try { step("next", value); } catch (e) { reject(e); } }
        function onreject(value) { try { step("throw", value); } catch (e) { reject(e); } }
        function step(verb, value) {
            var result = generator[verb](value);
            result.done ? resolve(result.value) : cast(result.value).then(onfulfill, onreject);
        }
        step("next", void 0);
    });
}

вторник, 9 февраля 2016 г.

NPM не скачивает пакеты

Если NPM не может скачать пакеты в Node.js для версии выше 0.12, то необходимо в командной строке выполнить команду:

npm config set strict-ssl=false

После этого пакеты начнут скачиваться.