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

TypeScript Playground

Файл index.html

<!DOCTYPE html>
<html>
<head>
    <style>
        body {
            font-family: Verdana;
            font-size: 62.5%;
        }
        table {
            width: 100%;
        }
        table tr td {
            width: 50%;
            vertical-align: top;
            border: 1px solid black;
        }
        textarea {
            width: 100%;
            height: 500px;
            margin: 0;
            padding: 5px;
            border: none;
            resize: none;
            -webkit-box-sizing: border-box;
            -moz-box-sizing: border-box;
            box-sizing: border-box;
            outline: 0;
            font-size: 2.5em;
        }
        div {
            height: 500px;
            margin: 0;
            padding: 5px;
            border: none;
            font-size: 2.5em;
        }
        pre {
            margin: 0;
            padding: 0;
        }
    </style>
</head>
<body>
    <table>
        <tr>
            <td><textarea id="source"></textarea></td>
            <td><div><pre id="result"></pre></div></td>
        </tr>
    </table>
    <script type="text/javascript" src="js/typescriptServices.js"></script>
    <script type="text/javascript" src="js/transpiler.js"></script>
</body>
</html>

Файл typescriptService.js

https://rawgit.com/Microsoft/TypeScript/master/lib/typescriptServices.js

Файл transpiler.js

;(function(){
    document.getElementById('source').addEventListener('keyup', function(){
        document.getElementById('result').innerHTML = ts.transpile(document.getElementById('source').value);
    }, false);
})();

Упрощенный код использования TypeScript в браузере

Файл index.html

<!DOCTYPE html>
<html>
<head>
    <script type="text/typescript">
        setTimeout(()=>console.log('hello'));
    </script>
    <script type="text/javascript" src="js/typescriptServices.js"></script>
    <script type="text/javascript" src="js/transpiler.js"></script>
</head>
<body>
</body>
</html>

Файл typescriptService.js

https://rawgit.com/Microsoft/TypeScript/master/lib/typescriptServices.js

Файл transpiler.js

;(function(){
    var scripts = document.getElementsByTagName('script')
        , script;
    for (var i = 0, len = scripts.length; i < len; i++) {
        if (scripts[i].type === 'text/typescript') {
            script = document.createElement('script');
            script.type = 'text/javascript';
            script.innerHTML = '// Compiled TypeScript:\n\n' + ts.transpile(scripts[i].innerHTML);
            document.getElementsByTagName('head')[0].appendChild(script);
        }
    }
})();

How to compile TypeScript in the browser

Add the following lines at the bottom of your page:

<script src="https://rawgit.com/Microsoft/TypeScript/master/lib/typescriptServices.js"></script>
<script src="https://rawgit.com/basarat/typescript-script/master/transpiler.js"></script>

And then you can use script tags that load .ts files or even have typescript inline:

<script type="text/typescript" src="script.ts"></script>
<script type="text/typescript">
    setTimeout(()=>console.log('hello'));
</script>

Example

index.html source:

<!DOCTYPE html>
<html>
<head>
    <link rel="stylesheet" href="style.css">
   
    <script type="text/typescript" src="script.ts"></script>
    <script type="text/typescript">
        setTimeout(()=>console.log('hello'));
    </script>

    <script src="https://rawgit.com/Microsoft/TypeScript/master/lib/typescriptServices.js"></script>
    <script src="https://rawgit.com/basarat/typescript-script/master/transpiler.js"></script>
</head>
<body>
    <h1>Hello</h1>
</body>
</html>

transpiler.js source:

// BASED on https://github.com/niutech/typescript-compile but using 1.5 transpile function

(function () {
    //Keep track of the number of scripts to be pulled, and fire the compiler
    //after the number of loaded reaches the total
    var scripts = {
        total: 0, //total number of scripts to be loaded
        loaded: 0, //current number of loaded scripts
        data: [], //file data
        name: [] //file name
    };

    //Function loads each script and pushes its content into scripts.data
    var load = function (url) {
        var xhr = window.ActiveXObject ? new window.ActiveXObject('Microsoft.XMLHTTP') : new window.XMLHttpRequest();;
        xhr.open('GET', url, true);
        if ('overrideMimeType' in xhr) xhr.overrideMimeType('text/plain');
        xhr.onreadystatechange = function () {
            if (xhr.readyState !== 4) return;
            if (xhr.status === 0 || xhr.status === 200) {
                scripts.loaded++;
                scripts.data.push(xhr.responseText);
                scripts.name.push(url);
                if (scripts.loaded === scripts.total) compile();
                return xhr.responseText;
            } else {
                console.log('Could not load ' + url);
            } //end if
        }; //end xhr.onreadystatechange()
        return xhr.send(null);
    };

    //Compiles each of the scripts found within scripts.data
    var compile = function () {
        if (scripts.data.length == 0 || scripts.data.length != scripts.name.length) return; //no reason to compile when there are no scripts
        var elem, source = '',
            body = document.getElementsByTagName('body')[0];
        scripts.total = 0; //clear the 'queue' incase the xhr response was super quick and happened before the initializer finished
        var hashCode = function (s) {
            var hsh = 0,
                chr, i;
            if (s.length == 0) {
                return hsh;
            }
            for (i = 0; i < s.length; i++) {
                chr = s.charCodeAt(i);
                hsh = (hsh << 5) - hsh + chr;
                hsh = hsh & hsh; //Convert to 32bit integer
            }
            return hsh;
        };
        if (window.sessionStorage && sessionStorage.getItem('typescript' + hashCode(scripts.data.join('')))) {
            source = sessionStorage.getItem('typescript' + hashCode(scripts.data.join('')));
        } else {
            (function () {
                var filename;
                for (num = 0; num < scripts.data.length; num++) {
                    filename = scripts.name[num] = scripts.name[num].slice(scripts.name[num].lastIndexOf('/') + 1);
                    var src = scripts.data[num];
                    source += ts.transpile(src);
                }
            })();
        }
        elem = document.createElement('script');
        elem.type = 'text/javascript';
        elem.innerHTML = '//Compiled TypeScript\n\n' + source;
        body.appendChild(elem);
    };

    (function () {
        //Polyfill for older browsers
        if (!window.console) window.console = {
            log: function () {}
        };
        var script = document.getElementsByTagName('script');
        var i, src = [];
        for (i = 0; i < script.length; i++) {
            if (script[i].type == 'text/typescript') {
                if (script[i].src) {
                    scripts.total++
                    load(script[i].src);
                } else {
                    scripts.data.push(script[i].innerHTML);
                    scripts.name.push('innerHTML'+scripts.total);
                    scripts.total++;
                    scripts.loaded++;
                }
            }
        }
        if (scripts.loaded === scripts.total) compile(); //only fires if all scripts are innerHTML, else this is fired on XHR response
    })();
})();

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

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

понедельник, 8 февраля 2016 г.

Как запустить Node.js без инсталяции

Если необходима портативная версия Node.js, то достаточно просто скачать файл
http://nodejs.org/dist/latest/node.exe
и поместить его в папку с вашими серверными JavaScript-файлами.
После этого в командной строке перейдите в папку вашего проекта и запустите ваш скрипт стандартным образом:

\path\to\saved\node.exe scriptname.js

При желании вы можете прописать ссылку на файл node.exe в системную переменную PATH, чтобы запускать ваши скрипты из любого места так:

node scriptname.js

Если вам нужен NPM, то скачайте его архив ZIP по ссылке

https://github.com/npm/npm

и распакуйте его в папку, в которую поместили файл node.exe.
Переименуйте папку с файлами NPM в "npm", убрав из названия номер версии версию, если он есть.
Создайте рядом с файлом node.exe папку "node_modules" и перенесите в неё папку "npm".
Скопируйте в папку с файлом node.exe файл npm.cmd из папки "node_modules/npm/bin/"

После этого NPM автоматически заработает из командной строки стандартным образом:

npm -h

Когда вам потребуется обновить Node.js, то просто замените файл node.exe на новую версию.

А для обновления NPM выполните команду:

npm update npm -g

или удалите старую папку node_modules и распакуйте в проект архив ZIP с новой версией NPM.

У меня стартовая структура проекта выглядит в итоге так:
C:\test\server.js - мой сценарий JavaScript
C:\test\node.exe - файл новой версии Node.js
C:\test\node_modules\npm - папка из архива ZIP с новой версией NPM
C:\test\npm.cmd - файл из архива ZIP с новой версией NPM

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

npm config set strict-ssl=false

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

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

Настройка TypeScript + Grunt

1. В папку с проектом установить модули

npm install grunt
npm install grunt-contrib-watch
npm install grunt-typescript
npm install grunt-ts
npm install grunt-tslint
npm install grunt-jsbeautifier
npm install grunt-newer

2. Создать файл Gruntfile.js с кодом

module.exports = function (grunt) {

    var tsFiles = ['./js/**/*.ts'];

    grunt.initConfig({

        // Скомпилироать файлы TypeScript в JavaScript
        typescript: {
            base: {
                  src: tsFiles
                , dest: '' // '' - компиляция в разные файлы или './js/single.js' - компиляция в единый файл
                , options: {
                      module: 'amd' // 'amd' или 'commonjs'
                    , target: 'es3' // 'es6', 'es5' или 'es3' (по умолчанию)
                    , sourceMap: false // true, false - создавать ли файл '.map'
                    , module: 'amd' // генерация кода модулей в стиле: 'commonjs' (по умолчанию), 'amd', 'system' или 'umd'
                    , noImplicitAny: false // true // true, false - предупреждать ли о наличи в коде переменных и фунций с типом ':any'
                    , removeComments: false // true, false - удалять ли комментарии из итогового файла
                    , preserveConstEnums: false // true, false - не стирать определение const enum в генерируемом коде
                    , suppressImplicitAnyIndexErrors: true // true, false - подавлять ли сообщения об ошибках типа noImplicitAny для индексируемых объектов
                    , noEmitOnError: true // true (по умолчанию), false - не компилировать файл, если во время его проверки найдена ошибка
                    , declaration: false // true, false - создавать ли соотвествующий файл .d.ts
                    , nolib: true // true, false - не включать по умолчанию файл lib.d.ts в global declarations
                    , noResolve: false // true, false - не добавлять сслыку описание (///reference) или module import в список компилируемых файлов
                    , experimentalDecorators: true // true, false - включить экспермментальную поддержку декораторов из ES7
                    , emitDecoratorMetadata: true // true, false - сгенерировать метаданные для декораторов
                    , newLine: 'CRLF' // 'CRLF' (windows), 'LF' (unix) - тип переноса строк в компилируемых файлах
                    , inlineSourceMap: false // true, false - сгенерировать один файл source map вместо нескольких отдельных файлов
                    , inlineSources: false // true, false - сгенирировать инлайновый source map внутри единого файла (требует, чтобы был inlineSourceMap: true)
                    , noEmitHelpers: true // true, false - не генерировать вспомогательные функции в компилируемых файлах подобных '__extends'
                    , keepDirectoryHierarchy: true // true, false
                    /*
                    , references: [ // set auto reference libraries
                          'core' // lib.core.d.ts
                        , 'dom' // lib.dom.d.ts
                        , 'scriptHost' // lib.scriptHost.d.ts
                        , 'webworker' // lib.webworker.d.ts
                        //, 'path/to/reference/files/** /*.d.ts'
                    ]
                    , watch: { //{} или false
                          path: 'path/to/typescript/files' // или ['path/to/typescript/file1', 'path/to/typescript/file2']
                        , before: ['beforetask'] // ['clean']
                        , after: ['aftertask'] // ['minify']
                        , atBegin: true // true, false (по умолчания) - запустить ли задачи вместе с вотчером
                      }
                    */
                }
            }
         }

        // Другой компилятор TypeScript в JavaScript
        , ts: {
              default : {
                  src: ['js/test/module1.ts', 'js/test/module2.ts', 'js/test/module3.ts'] // ['js/**/*.ts']
                // , out: 'js/test/main.js'
                , options: {
                          declaration: false // true | false (default) - Generates a .d.ts definitions file for compiled TypeScript files
                        , emitDecoratorMetadata: false // true | false (default) - Emit metadata for type/parameter decorators.
                        , experimentalDecorators: false // true | false (default) - Enables experimental support for ES7 decorators
                        , inlineSourceMap: false // true | false (default) - Emit a single file that includes source maps instead of emitting a separate .js.map file.
                        , inlineSources: false // true | false (default) - Emit the TypeScript source alongside the sourcemaps within a single file. Requires inlineSourceMap to be set.
                        , isolatedModules: false // true | false (default) - Ensures that the output is safe to only emit single files by making cases that break single-file transpilation an error
                        , mapRoot: '' // '/maps' - Specifies the location where debugger should locate map files instead of generated locations.
                        , module: 'amd' // 'amd' (default) | 'commonjs' | 'system' | 'umd' | '' - Specify module style for code generation
                        , newLine: 'CRLF' // 'CRLF' | 'LF' | '' (default) -  Explicitly specify newline character (CRLF or LF); if omitted, uses OS default.
                        , noEmit: false // true | false (default) - Check, but do not emit JS, even in the absence of errors.
                        , noEmitHelpers: true // true | false (default) - Do not generate custom helper functions like __extends in compiled output.
                        , noImplicitAny: false // true | false (default) - Warn on expressions and declarations with an implied any type.
                        , noResolve: true // true | false (default) - Do not add triple-slash references or module import targets to the compilation context.
                        , out: '' // '' - компиляция в разные файлы или './js/single.js' - компиляция в единый файл - Concatenate and emit output to a single file.
                        , outDir: '' // 'dist' - Redirect output structure to the directory.
                        , preserveConstEnums: false // true | false (default) - Const enums will be kept as enums in the emitted JS.
                        , removeComments: false // true (default)| false - Configures if comments should be included in the output
                        , sourceMap: false // true (default) | false - Generates corresponding .map file
                        , sourceRoot: '' // '/dev' - Specifies the location where debugger should locate TypeScript files instead of source locations.
                        , suppressImplicitAnyIndexErrors:  false // true | false (default) - If set to true, TypeScript will allow access to properties of an object by string indexer when noImplicitAny is active, even if TypeScript doesn't know about them. This setting has no effect unless noImplicitAny is active.
                        , target: 'es3' // 'es3' | 'es5' (default) | 'es6' - Specify ECMAScript target version: 'es3', 'es5', or 'es6'
                  }
              }
          }

        // Проверить оформление кода в TypeScript-файлах
        , tslint: {
              options: {
                  configuration: grunt.file.readJSON('tslint.json')
              }
            , all: {
                  src: tsFiles
              }
        }

        // Форматирование кода JavaScript
        , 'jsbeautifier' : {
              files : ['js/**/*.js']
            , options : {
                js: {
                        braceStyle: 'collapse'
                      , breakChainedMethods: false
                      , e4x: false
                      , evalCode: false
                      , indentChar: ' '
                      , indentLevel: 0
                      , indentSize: 4
                      , indentWithTabs: false
                      , jslintHappy: true
                      , keepArrayIndentation: false
                      , keepFunctionIndentation: false
                      , maxPreserveNewlines: 10
                      , preserveNewlines: true
                      , spaceBeforeConditional: true
                      , spaceInParen: false
                      , unescapeStrings: false
                      , wrapLineLength: 0
                      , endWithNewline: false
                  }
              }
          }

        // Начать отслеживание изменений кода файлов
        , watch: {
              scripts: {
                  files: tsFiles
                , tasks: [
                    // 'newer:tslint'
                    //, 'typescript'
                      'ts'
                    , 'jsbeautifier'
                  ]
              }
          }

    });

    grunt.loadNpmTasks('grunt-contrib-watch');
    grunt.loadNpmTasks('grunt-typescript');
    grunt.loadNpmTasks('grunt-ts');
    grunt.loadNpmTasks('grunt-tslint');
    grunt.loadNpmTasks('grunt-jsbeautifier');
    grunt.loadNpmTasks('grunt-newer');

    grunt.registerTask('default', [
        //  'newer:tslint'
        //, 'typescript'
          'ts'
        , 'jsbeautifier'
        , 'watch'
    ]);

};

3. Создать файл rungrunt.js с кодом

require('grunt').cli();

4. Создать файл tsling.json с кодом

{
  "rules": {
      "ban": false
    , "class-name": true
    , "comment-format": [true, "check-space"]
    , "curly": true
    , "eofline": false
    , "forin": true
    , "indent": [true, "spaces"]
    , "jsdoc-format": true
    , "label-position": true
    , "label-undefined": true
    , "max-line-length": [true, 500]
    , "member-access": true
    , "member-ordering": [
          true
        , "public-before-private"
        , "static-before-instance"
        , "variables-before-functions"
      ]
    , "no-any": true
    , "no-arg": true
    , "no-bitwise": true
    , "no-console": [
          true
        , "debug"
        , "info"
        , "time"
        , "timeEnd"
        , "trace"
      ]
    , "no-consecutive-blank-lines": true
    , "no-construct": true
    , "no-constructor-vars": true
    , "no-debugger": false
    , "no-duplicate-key": true
    , "no-duplicate-variable": true
    , "no-empty": true
    , "no-eval": true
    , "no-internal-module": true
    , "no-string-literal": false
    , "no-trailing-comma": true
    , "no-trailing-whitespace": true
    , "no-unreachable": true
    , "no-unused-expression": true
    , "no-unused-variable": true
    , "no-use-before-declare": true
    , "one-line": [
          true
        , "check-open-brace"
        , "check-catch"
        , "check-else"
        , "check-whitespace"
      ]
    , "quotemark": [true, "single"]
    , "radix": true
    , "semicolon": true
    , "switch-default": true
    , "triple-equals": [true, "allow-null-check"]
    , "typedef": [
          true
        , "call-signature"
        , "parameter"
        , "property"
        , "variable-declaration"
        , "member-variable-declarations"
      ]
    , "typedef-whitespace": [
          true
        , {
              "call-signature": "nospace"
            , "index-signature": "nospace"
            , "parameter": "nospace"
            , "property-declaration": "nospace"
            , "variable-declaration": "nospace"
        }
      ]
    , "variable-name": false
    , "whitespace": [
          true
        , "check-branch"
        , "check-decl"
        , "check-module"
        , "check-operator"
        , "check-separator"
      ]
  }
}

5. Поместить исходные TypeScript-файлы в папку js

js/module-1.ts
js/module-2.ts

6. Скомпилировать TypeScript-файлы в JavaScript-файлы командой

node rungrunt.js

Настройка TypeScript + Gulp

1. В папку с проектом установить модули

npm install gulp
npm install gulp-typescript
npm install gulp-tslint

2. Создать файл Gulpfile.js с кодом

var gulp = require('gulp')
    , typescript = require('gulp-typescript')
    , typescriptLint = require('gulp-tslint');
   
// Lint all typescript files
gulp.task('typescript-lint', function () {
    return gulp.src(['src/**/*.ts']).pipe(typescriptLint({configuration: 'tslint.json'}))
                                                .pipe(typescriptLint.report('prose'));
});
   
// Build all typescript files
gulp.task('typescript-build', function () {
    var typescriptResult = gulp.src(['src/**/*.ts']).pipe(typescript(typescript.createProject('tsconfig.json')));
    return typescriptResult.js.pipe(gulp.dest('build'));
});

// Watch all typescript files for changes and rebuild everything
gulp.task('typescript-watch', function () {
    gulp.watch(['src/**/*.ts'], [
          'typescript-lint'
        , 'typescript-build'
    ]);
});

// Default gulp task
gulp.task('default', [
      'typescript-lint'
    , 'typescript-build'
    , 'typescript-watch'
]);

3. Создать файл rungulp.js с кодом

// Execute gulp task
var command = 'node ./node_modules/gulp/bin/gulp.js default'
    , process = require('child_process').exec(command);
process.stdout.on('data', function(data) {console.log(data);});
process.stderr.on('data', function(data) {console.log(data);});
process.on('close', function(code) {if (code === 0) {console.log('Done');} else {console.log('Exit code: ' + code);}});

4. Создать файл tsconfig.json с кодом

{
      "compilerOptions": {
              "declaration": false
            , "emitDecoratorMetadata": false
            , "experimentalDecorators": false
            , "inlineSourceMap": false
            , "inlineSources": false
            , "isolatedModules": false
            , "mapRoot": ""
            , "module": "amd"
            , "newLine": "CRLF"
            , "noEmit": false
            , "noEmitHelpers": true
            , "noImplicitAny": true
            , "noResolve": true
            , "outFile": "final.js"
            , "preserveConstEnums": false
            , "removeComments": false
            , "sourceMap": false
            , "sourceRoot": ""
            , "suppressImplicitAnyIndexErrors": false
            , "target": "es3"
      }
}

5. Создать файл tsling.json с кодом

{
  "rules": {
      "ban": false
    , "class-name": true
    , "comment-format": [true, "check-space"]
    , "curly": true
    , "eofline": false
    , "forin": true
    , "indent": [true, "spaces"]
    , "jsdoc-format": true
    , "label-position": true
    , "label-undefined": true
    , "max-line-length": [true, 500]
    , "member-access": true
    , "member-ordering": [
          true
        , "public-before-private"
        , "static-before-instance"
        , "variables-before-functions"
      ]
    , "no-any": true
    , "no-arg": true
    , "no-bitwise": true
    , "no-console": [
          true
        , "debug"
        , "info"
        , "time"
        , "timeEnd"
        , "trace"
      ]
    , "no-consecutive-blank-lines": true
    , "no-construct": true
    , "no-constructor-vars": true
    , "no-debugger": false
    , "no-duplicate-key": true
    , "no-duplicate-variable": true
    , "no-empty": true
    , "no-eval": true
    , "no-internal-module": true
    , "no-string-literal": false
    , "no-trailing-comma": true
    , "no-trailing-whitespace": true
    , "no-unreachable": true
    , "no-unused-expression": true
    , "no-unused-variable": true
    , "no-use-before-declare": true
    , "one-line": [
          true
        , "check-open-brace"
        , "check-catch"
        , "check-else"
        , "check-whitespace"
      ]
    , "quotemark": [true, "single"]
    , "radix": true
    , "semicolon": true
    , "switch-default": true
    , "triple-equals": [true, "allow-null-check"]
    , "typedef": [
          true
        , "call-signature"
        , "parameter"
        , "property"
        , "variable-declaration"
        , "member-variable-declarations"
      ]
    , "typedef-whitespace": [
          true
        , {
              "call-signature": "nospace"
            , "index-signature": "nospace"
            , "parameter": "nospace"
            , "property-declaration": "nospace"
            , "variable-declaration": "nospace"
        }
      ]
    , "variable-name": false
    , "whitespace": [
          true
        , "check-branch"
        , "check-decl"
        , "check-module"
        , "check-operator"
        , "check-separator"
      ]
  }
}

6. Поместить исходные TypeScript-файлы в папку src

src/module-1.ts
src/module-2.ts

7. Скомпилировать TypeScript-файлы в JavaScript-файлы командой

node rungulp.js