вторник, 9 августа 2016 г.

React Redux Counter Simple Example

package.json

{
      "version": "1.0.0"
    , "name": "react-redux"
    , "description": "React Redux"
    , "engines": {
          "node": "6.3.1"
        , "npm": "3.10.6"
      }
    , "dependencies": {
          "webpack": "*"
        , "webpack-dev-server": "*"
        , "babel-core": "*"
        , "babel-preset-es2015": "*"
        , "babel-preset-react": "*"
        , "babel-loader": "*"
        , "react": "*"
        , "react-dom": "*"
        , "redux": "*"
      }
    , "scripts": {
          "build": "node node_modules/webpack-dev-server/bin/webpack-dev-server --progress"
      }
}

webpack.config.js

var path = require('path');

module.exports = {
      entry: [path.resolve(__dirname + '/source/app.jsx')]
    , output: {
            path: path.resolve(__dirname)
          , filename: 'app.js'
      }
    , module: {
         loaders: [
            {
                  test: /\.jsx?$/
                , exclude: /node_modules/
                , loader: 'babel-loader'
                , query: {
                    presets: ['es2015', 'react']
                  }
            }
         ]
      }
};

index.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <script src="https://fb.me/react-0.14.3.js"></script>
    <script src="https://fb.me/react-dom-0.14.3.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/redux/3.0.4/redux.min.js"></script>
    <title>Redux React Counter</title>
</head>
<body>
    <div id="root"></div>
    <script src="app.js"></script>
</body>
</html>

source/app.jsx

const {createStore} = Redux;

// Reducer
const counter = (state = 0, action) => {
  switch(action.type) {
    case 'INCREMENT':
      return state + 1;
    case 'DECREMENT':
      return state - 1;
    default:
      return state;
  }
};

// Store
const store = createStore(counter);

// Subscribe
store.subscribe(render);

// Dispatch
const render = () => {
  ReactDOM.render(
    <Counter value={store.getState()}
       onIncrement={() => store.dispatch({type: 'INCREMENT'})}
       onDecrement={() => store.dispatch({type: 'DECREMENT'})}
    />, document.getElementById('root')
  );
};

class Counter extends React.Component {
  render() {
    return (
      <div>
        <h1>{this.props.value}</h1>
        <button onClick={this.props.onIncrement}>+</button>
        <button onClick={this.props.onDecrement}>-</button>
      </div>
    );
  }
};

render();

среда, 3 августа 2016 г.

Redux Cheat Sheet

Stores

import { createStore } from 'redux';

function counter(state = 0, action) {
  switch (action.type) {
      case 'INCREMENT': return state + 1;
      case 'DECREMENT':return state - 1;
      default: return state;
  }
}

let store = createStore(counter);

store.subscribe(() => { ... })
store.dispatch({ action })
store.getState()
store.dispatch({ type: 'INCREMENT' }); // 1
store.dispatch({ type: 'DECREMENT' }); // 10

React Redux

React.render(<Provider store={store}>{() => <App />}</Provider>, mountNode)

class App extends React.Component {
    render () { return <div>{this.props.message}</div> }
}

function select (state) {
    return { message: state.message }
}

export default connect(select)(App);

React Cheat Sheet

Основы

1. React.createElement(type, props, children)

Создать ReactElement с переданными ему class, props, children.

var link = React.createElement('a', {href: '#'}, "Save")
var nav = React.createElement(MyNav, {flat: true}, link)

2. React.cloneElement(element, props, children)

Создать новый ReactElement объединенный с новыми props и children.

3. ReactDOM.render(element, domNode)

Взять ReactElement, отредерить его и вставить DOM node.

ReactDOM.render(React.createElement('div'), document.getElementById('container'))

4. ReactDOM.findDOMNode(element)

Вернуть DOM node соответствующий заданному элементу (после рендеринга).

Особые props

children - автоматически добавляется в this.props функцикй React.createElement.
className - соответствует атрибуту class в HTML.
htmlFor - соответствует атрибуту for в HTML.
key - уникальные идентификаторы для каждого ReactElement. Используется с элементами в массивах.
ref - принимает callback function, которая будет вызвана:
        1. с экземпляром компонента или DOM node при его монтировании (mount).
        2. с null или unmount и когда произошло изменение функционала.
style - принимает объект со стилями style вместо строки.

Типы props

Доступны в составе React.PropTypes. По желанию добавить .isRequired.

| any | array | bool | element | func |
| node | number | object | string |

instanceOf(constructor)
oneOf(['News', 'Photos'])
oneOfType([propType, propType])

Компоненты Class Components

var MyComponent = React.createClass({

    displayName: 'MyComponent',

    /* ... options and lifecycle methods ... */

    render: function() {
        return React.createElement( /* ... */ )
    },

    ... далее опции и методы ...

});

Опции

propTypes - объект содержащий сопоставления имен props с их типами
getDefaultProps - function() возвращает объект
getInitialState - function() возвращает объект

Методы жизненного цикла компоненты

componentWillMount - function()
componentDidMount - function()
componentWillReceiveProps - function(nextProps)
shouldComponentUpdate - function(nextProps, nextState) возвращает boolen
componentWillUpdate - function(nextProps, nextState)
componentDidUpdate - function(prevProps, prevState)
componentWillUnmount - function()

Описание характеристик экземпляров компонентов:

- Доступны через this внутри класса компонента (class component)
- Компоненты без состояний (stateless functional components) не имеют экземпляров компонентов (component instances).
- Обслуживаются как объекты переданные в ref callbacks
- Один экземпляр компонента может обслуживать множество ReactElements.

Свойства

props - содержит любые свойства props переданные в React.createElement
state - содержит состояние state установленное через функцию setState и полученное через функцию getInitialState

Методы

1. setState(changes) - применяет изменения к this.state и перерисовывает компонент
2. forceUpdate() - немендленно перерисовывает компонент в DOM

Код в стиле ECMAScript 6

Компоненты - это классы

export class MyComponent extends Component {
    componentWillMount() {
        // ...
    }
    render() {
        return <div>Hello World</div>
    }
}

Свойства статичны

export class MyComponent extends Component {
    static propTypes = {
        // ...
    }
    static defaultProps = {
        // ...
    }
}

Первоначальное состояние

export class MyComponent extends Component {
    state = {
        disabled: this.props.disabled,
    }
}

Конструкторы заменяют собой componentWillMount

export class MyComponent extends Component {
    constructor(props) {
        super(props)
        // Do stuff
    }
}

Привязывайте методы к вашему компоненту, когда используете их в качестве обработчиков handlers

export class MyComponent extends Component {
    onMouseEnter = event => {
        this.setState({hovering: true})
    }
}

Импорт React

JSX предполагает, что объект React доступен, поэтому его надо тоже импортировать

import React, { Component, PropTypes } from 'react'

Деструктурирование особенно удобно для компонентов с неизменным состоянием (stateless)

export const Commas = ({items, ...otherProps}) => <div {...otherProps}>{items.join(', ')}</div>

Строковые литералы можно использовать для динамического создания className

<input className={`Control-${this.state}`} />

и для создания динамических имен свойств

this.setState({
    [`${inputName}Value`]: e.target.value,
});

Декораторы классов можно использовать в качестве mixin

@something(options)
class MyComponent extends Component {}

// В итоге превращается в

let MyComponent = something(options)(
    class MyComponent extends Components {}
)

Дополнительные подсказки

Basic class

React.createClass({
  render: function () {
    return (
      <div>Hello {this.props.name}</div>
    );
  }
});

Using components

var Component = React.createClass({ ... });

var compo = React.render(<Component />, mountnode);

States

this.setState({ editing: true });
this.state.editing === true
this.replaceState({ ... });

Properties

this.setProps({ fullscreen: true });
this.props.fullscreen === true

this.replaceProps({ ... });

API

c.getDOMNode() // deprecated 0.13
React.findDOMNode(c) // 0.13+

c.forceUpdate()
c.isMounted()

Methods

{
  render: function()
  getInitialState: function()
  getDefaultProps: function()
  mixins: []
  propTypes: {} / for validation /
  statics: { .. } / static methods /
  displayName: '..' / automatically filled in by jsx /
}

Lifecycle

componentWillMount()
componentDidMount()

// not on initial render
componentWillReceiveProps(props)
shouldComponentUpdate(props, state)
componentWillUpdate(props, state)
componentDidUpdate(prevProps, prevState)

componentWillUnmount()

// ...there is no DidUnmount or ReceiveState.

Initial States

React.createClass({
  getInitialState: function () {
    return {data: []};
  },

  render: function () {
    return (
      <CommentList data={this.state.data} />
    );
  }
});

Default Properties

React.createClass({
  getDefaultProps: function () {
    return {name: ''};
  }
);

Before Rendering

React.createClass({
  componentWillMount: function () {
    $.get(this.props.url, function (data) {
      this.setState(data);
    });
  },

  render: function () {
    return (
      <CommentList data={this.state.data} />
    );
  }
});

Actions

<form onSubmit={this.handleSubmit}>
  Name: <input ref="name">
</form>

React.createClass({
  handleSubmit: function (event) {
    name = this.refs['name'].getDOMNode().value;
    // see two-way binding below
  }
})

Two-way binding

React.createClass({
  mixins: [React.addons.LinkedStateMixin],
  getInitialState: function() {
    return {value: 'Hello!'};
  },
  render: function() {
    return <input type="text" valueLink={this.linkState('value')} />;
  }
});
// LinkedStateMixin adds a method to your React component called
// linkState().

Lists

var TodoList = React.createClass({
  render: function() {
    var createItem = function(itemText) {
      return <li>{itemText}</li>;
    };
    return <ul>{this.props.items.map(createItem)}</ul>;
  }
});

Property validations

React.createClass({
  propTypes: {
    // required
    requiredFunc: React.PropTypes.func.isRequired,
    requiredAny: React.PropTypes.any.isRequired,

    // primitives, optional by default
    bool: React.PropTypes.bool,
    func: React.PropTypes.func,
    number: React.PropTypes.number,
    string: React.PropTypes.string,
  }
});

Class set

render: function() {
  var cx = React.addons.classSet;
  var classes = cx({
    'message': true,
    'message-important': this.props.isImportant,
    'message-read': this.props.isRead
  });
  // same final string, but much cleaner
  return <div className={classes}>Great Scott!</div>;
}

Propagating properties to children

var VideoPlayer = React.createClass({
  render: function() {
    return <VideoEmbed {...this.props} controls='false' />;
  }
});

<VideoPlayer src="video.mp4" />

Mixins

var TickTock = React.createClass({
  mixins: [SetIntervalMixin]
}

SetIntervalMixin = {
  componentWillMount: function() { .. }
}

Webpack Cheat Sheet

package.json

{
    "name": "webpack-cheatsheet",
    "version": "0.0.1",
    "description": "Ekino Webpack Cheat Sheet Project",
    "dependencies": {
        "react": "^0.13",
        "lodash": "~3.10"
    },
    "devDependencies": {
        "babel": "~5.8",
        "babel-loader": "~5.3",
        "clean-webpack-plugin": "^0.1.3",
        "css-loader": "^0.18",
        "extract-text-webpack-plugin": "^0.8.2",
        "file-loader": "^0.8.4",
        "font-awesome": "^4.4.0",
        "html-webpack-plugin": "^1.6.1",
        "node-sass": "^3.2",
        "path": "^0.12.7",
        "react-hot-loader": "^1.3.0",
        "react-intl": "^1.2",
        "resolve-url-loader": "^1.1.0",
        "sass-loader": "^2.0",
        "style-loader": "^0.12",
        "webpack": "~1.12",
        "webpack-dev-server": "^1.11.0"
    },
    "scripts": {
        "webpack": "node webpack.config.js"
    }
}

webpack.config.js

var ExtractTextPlugin = require('extract-text-webpack-plugin');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var webpack = require('webpack');
var path = require('path');
var WebpackDevServer = require('webpack-dev-server');
var CleanPlugin = require('clean-webpack-plugin');


// Make sure the NODE_ENV is always set
// If the file is call directly with node (node webpack.config.js) then the hot loader server will
// be started and you can enjoy live editing.
// if you call webpack command line then the production files will be created
process.env.NODE_ENV = process.env.NODE_ENV || (require.main === module ? 'development' : 'production');

// configure host settings for the WebDevServer
var devserver = {ip: 'localhost', port: 3000};

var config = {
    // we use path.join to make it work cross plateform
    context: path.join(__dirname, 'src'),
    entry: process.env.NODE_ENV == 'production' ? {
        app: ["./index.jsx"]
    } : {
        // WebpackDevServer is only required on development, with key value entry mode, the
        // webpack/hot/only-dev-server entry is required on each entry.
        app: ["./index.jsx", 'webpack/hot/only-dev-server'],
        // The client entry is used to serve an iframe with reloading information
        // The final url will be http://localhost:3000/webpack-dev-server
        client: 'webpack-dev-server/client?http://'+devserver.ip+':'+devserver.port
    },
    output: {
        // Assets destination
        path: path.join(__dirname, 'dist'),
        // The final entry file is located in dist/js folder
        // The name variable will the key used in the entry index
        // The hash is optional, but usefull for having unique url for caching purpose
        filename: "js/[name]-[hash:8].js",

        // require to make the specific fonts work (absolute path),
        // the value is also used by the WebpackDevServer to serve assets
        publicPath: "/"
    },
    resolve: {
        // the fallback array contains a set of folder used by webpack to search
        // available assets used with the require keyword
        fallback: [
            path.join(__dirname, 'src')
        ],

        // This is important if you want to refer to module resources. It is important
        // to use ~ symbol to reference module: @import "~font-awesome/scss/font-awesome";
        modulesDirectories: ['node_modules']
    },
    module: {
        // The loaders section defines how webpack behaves when a resource need to be loaded.
        // A resource is anything loaded with the require keyword
        loaders: [{
            // regular expression to match only jsx file
            test: /\.jsx?$/,
            exclude: /(node_modules)/,
            // The include keyword is used to limit the lookup scope used by webpack
            // with the hot reload configuration.
            include: path.join(__dirname, 'src'),
            // In production, we don't need react-hot as it include a lot of code.
            loaders: process.env.NODE_ENV == 'production' ?
                ['babel'] :
                ['react-hot', 'babel']
        }, {
            test: /\.scss$/,
            // resolve-url allow to resolve url() please keep it mind to set the output.publicPath
            //   to use absolute path. This is usefull is you have fonts and css folders on
            //   different folders
            loader: process.env.NODE_ENV == 'production' ?
                // the plugin is used to store css content to an external file
                // without this plugin css will be store as a variable inside the final
                // bundle file
                ExtractTextPlugin.extract('css!resolve-url!sass') :

                // the style loader is usefull to load the style inline with WebpackDevServer
                'style!css!resolve-url!sass'
        }, {
            // match woff fonts
            test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/,
            // the file loader will copy the font into a dedicated folder
            // with the name argument it is possible to define a target to store the file
            // if the output.publicPath is set, then the final reference will be output.publicPath + name
            loader: "file?name=fonts/[name]-[hash:8].[ext]"
        }, {
            test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
            // the -loader suffix is optional so file or file-loader is equivalent
            loader: "file-loader?name=fonts/[name]-[hash:8].[ext]"
        }, {
            test: /\.png$/,
            loader: "url?limit=100000"
        }, {
            test: /\.jpg$/,
            loader: "file"
        }]
    },
    plugins: [
        // this plugin will append on generated file the provided string, this can be useful
        // for copyright holder
        new webpack.BannerPlugin("This code is part of the Ekino Webpack Cheat Sheet Project", {
            raw: false,
            entryOnly: false
        }),
        // this plugin must be used with the loader ExtractTextPlugin.extract
        // the final file will use the entry name and the hash for current
        // entry file
        new ExtractTextPlugin("css/[name]-[id]-[contenthash:8].css", {
            allChunks: true
        }),
        // the plugin will generate the index file inside the dist folder. The plugin
        // can inject all related js and css assets.
        new HtmlWebpackPlugin({
            inject: true,
            title: 'Ekino Webpack Cheat Sheet Project',
            template: 'src/index.html',
            filename: 'index.html'
        }),
        // this plugin will compute common chunks from entry files and related chunks to
        // optimize and reduce final file size
        new webpack.optimize.CommonsChunkPlugin({
            name: "commons",
            filename: "js/[name]-[hash:8].js",
            chunks: [] // entries to use
        }),
        new webpack.DefinePlugin({
            VERSION: JSON.stringify("0.0.1-DEV"),
            'process.env': {
                'NODE_ENV': JSON.stringify(process.env.NODE_ENV)
            }
        }),
        // clean the dist folder before building assets
        new CleanPlugin(['dist'], __dirname)
    ]
};

if ('development' === process.env.NODE_ENV) {
    // define how assets will be available, the eval value is useful with the
    // HotModuleReplacementPlugin to reload code on change
    config.devtool = 'eval';
    config.plugins.push(new webpack.HotModuleReplacementPlugin());
}

if ('production' === process.env.NODE_ENV) {
    // reduce the final size of javascript files
    config.plugins.push(new webpack.optimize.UglifyJsPlugin({
        compress: {
//            warning: false
        },
        mangle: { // default values
            except: ['$super', '$', 'exports', 'require']
        }
    }));
}

// make the config available so webpack can grab the configuration
module.exports = config;

// start the WebpackDevServer which handle hot reload
if (require.main === module && 'development' === process.env.NODE_ENV ) { // if call from node directly we start the dev webserver
    var server = new WebpackDevServer(webpack(config), {
        publicPath: config.output.publicPath,
        hot: true,
        historyApiFallback: true,
        stats: {
            colors: true
        },
        progress: true
    });

    server.listen(devserver.port, devserver.ip, function (err, result) {
        if (err) {
            console.log(err);
        }

        console.log('Listening at http://'+devserver.ip+':'+devserver.port+'/webpack-dev-server/');
    });
}

Установка TypeScript, React, Webpack

Структура проекта.

proj/
   +- node.exe
   |
   +- node_modules
   |    +- npm/
   |
   +- npm.cmd
   |
   +- src/
   |    +- components/
   |
   +- dist/

Создание структуры проекта из командной строки cmd.

mkdir proj
cd proj
mkdir src
cd src
mkdir components
cd ..
mkdir dist

Создание package.json из командной строки cmd.

npm init

Содержимое package.json.

{
      "version": "1.0.0"
    , "name": "webpack-typescript-react"
    , "description": "Webpack Typescript React"
    , "engines": {
          "node": "6.3.1"
        , "npm": "3.10.6"
      }
    , "dependencies": {
          "typescript": "1.8.10"
        , "typings": "1.3.2"
        , "webpack": "1.13.1"
        , "ts-loader": "0.8.2"
        , "source-map-loader": "0.1.5"
        , "react": "15.3.0"
        , "react-dom": "15.3.0"
      }
}

Установка библиотек из командной строки cmd.

npm install typescript
npm install typings
npm install webpack
npm install ts-loader 
npm install source-map-loader
npm install react
npm install react-dom

Удалить папки и файлы

proj/etc
proj/typings
proj/tsc
proj/tsserver
proj/tsserver.cmd
proj/webpack

Создать в папке proj файл .typingsrc с содержимым:

{
    "rejectUnauthorized": false
}

Установка файлов d.ts из командной строки cmd.

typings install --save react
typings install --save react-dom

Эти команды создадут папку typings и файл typings.json.

Создать в папке proj файл tsconfig.json с содержимым:

{
    "compilerOptions": {
        "outDir": "./dist/",
        "sourceMap": true,
        "noImplicitAny": true,
        "module": "commonjs",
        "target": "es5",
        "jsx": "react"
    },
    "files": [
        "./typings/index.d.ts",
        "./src/components/Hello.tsx",
        "./src/index.tsx"
    ]
}

Создать в папке proj файл webpack.config.js с содержимым:

module.exports = {
    entry: "./src/index.tsx",
    output: {
        filename: "./dist/bundle.js",
    },

    // Включить sourcemaps для отладки вывода webpack.
    devtool: "source-map",

    resolve: {
        // Add '.ts' and '.tsx' as resolvable extensions.
        extensions: ["", ".webpack.js", ".web.js", ".ts", ".tsx", ".js"]
    },

    module: {
        loaders: [
            // Все файлы с расширениями '.ts' и '.tsx' будут обработаны 'ts-loader'.
            { test: /\.tsx?$/, loader: "ts-loader" }
        ],

        preLoaders: [
            // Все итоговые файлы '.js', имеющие sourcemaps будут обработаны 'source-map-loader'.
            { test: /\.js$/, loader: "source-map-loader" }
        ]
    },

    // При импорте модуля, чей путь соответствует одному из ниже приведенных, 
    // просто предположим, что он уже загружен и не будем добавлять его в пакет, 
    // что позволит браузеру кэшировать библиотеки между сборками проекта.
    externals: {
        "react": "React",
        "react-dom": "ReactDOM"
    },
};

В папке proj/src/components создадим файл Hello.tsx с содержимым:

import * as React from 'react';

export interface HelloProps {
    compiler: string;
    framework: string;
}

export class Hello extends React.Component<HelloProps, {}> {
    render() {
        return <h1>Hello from {this.props.compiler} and {this.props.framework}!</h1>;
    }
}

В папке proj/src создадим файл index.tsx с содержимым:

import * as React from 'react';
import * as ReactDOM from 'react-dom';

import {Hello} from './components/Hello';

ReactDOM.render(
    <Hello compiler="TypeScript" framework="React" />,
    document.getElementById('example')
);

В папке proj создадим файл index.html с содержимым:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8" />
        <title>Hello React!</title>
    </head>
    <body>
        <div id="example"></div>

        <!-- Зависимости -->
        <script src="./node_modules/react/dist/react.js"></script>
        <script src="./node_modules/react-dom/dist/react-dom.js"></script>

        <!-- Главный файл -->
        <script src="./dist/bundle.js"></script>
    </body>
</html>

Запустим сборку проекта из командной строки cmd.

webpack



Эта команда создаст папку dist с файлами bundle.js и bundle.js.map в ней.

Итоговый состав содержимого папки proj:

node.exe
node_modules
npm.cmd

package.json
.typingsrc

tsconfig.json
typings.json
webpack.config.js

tsc.cmd
typings.cmd
webpack.cmd

typings

src
dist

index.html

пятница, 29 июля 2016 г.

Краткий перечень API Node.js

=======================================
| Cheat sheet small - краткая подсказка
=======================================

npm init
npm install --save gulp
npm uninstall --save gulp
npm update
npm list

global

require
export
module.exports

assert()

console.log()

process.argv
process.stdout.write()
porcess.stderr.write()
porcess.stdin
process.exit()
process.stdout.clearLine()
process.stdout.cursorTo()

child_porcess.spawn()
child_process.exec()

var emeitter = new events.EventEmitter();
emeitter.on()
emeitter.once()
emeitter.addListener()
emeitter.removeListener()
emeitter.emit()

setTimeout()
setInterval()
setImmediate()

Buffer
__filename
__dirname
path
fs.writeFile()
fs.appendFile()
fs.readFile()
fs.rename()
fs.unlink()
fs.stat.isFile()
fs.stat.isDirectory()

fs.readdir()
fs.mkdir()
fs.rename()
fd.rmdir

fs.createReadStream()
fs.createWriteStream()
writeStream.write()
readStream.pipe()

url.parse()
url.format()
querystring.parse(
querystring.stringify()
querystring.escape()
querystring.unescape()
http.request()
http.createServer()
bodyParser()

os

debugger

=======================================
| Cheat sheet big - большая подсказка
=======================================

// NPM

npm init
npm install --save gulp
npm uninstall --save gulp
npm update
npm list

// Global, __dirname, __filename

console.log(global); // аналог window

console.log(__dirname); // абсолютный путь до папки из которой запущен данный файл
console.log(__filename); // абсолютный путь до данного файла

console.log(process.argv); // массив аргументов

// Process, stdout, stderr, stdin

process.stdout.write(`\n\n\n${__filename}\n\n\n`); // аналог console.log()

process.stderr.write(`\n\n\n${__dirname}\n\n\n`); // аналог console.error()

process.stdin.on("data", function (data) {
    process.stdout.write(data.toString());
    process.exit();
});

process.on("exit", function () {
    process.stdout.write("Goodbye");
});

process.stdout.clearLine(); // очистить текущую строку выводы в окне терминала

process.stdout.cursorTo(0); // переместить курсор в окне терминала на позицию 0

// Дочерний процесс - выполнить команду для терминала - exec

var exec = require("child_process").exec; // выполнить команду для терминала

var command = "open http://www.goggle.com"; // команда для терминала

exec(command, function (error, stdout) {
    if (error) {throw error;}
    console.log("Done");
    console.log(stdout);
});

// Дочерний процесс - запустить дочерний процесс - spawn

var spawnProcess = require("child_process").spawn;

var terminalCommand = "node";

var options = ["script-file.js", "say", "hi!"];

var childProcess = spawn(terminalCommand, options);

childProcess.stdout.on("data", function (data) {
    console.log(data.toString());
});

childProcess.on("close", function () {
    console.log("Done");
    process.exit();
});

setTimeout(function(){
    childProcess.stdin.write("stop"); // выполнить команду в консоли дочернего процесса
}, 5000);

// Модули - require, export, module.exports

var moduleFile = require("moduleFile"); // пути: ./ - текущая папка, ../ - внешняя папка, / - внутренняя папка

export var a = 1;
export function b () {}

module.exports = {a: a, b: b}; // аналог return из RequireJS

// События - on, once, emit, addListener, removeListener

var events = require("events");

var emitter = new events.EventEmitter();

emitter.on("say", function say (message) {});

emitter.once("say", function say (message) {});

emitter.addListener("say", function say (message) {});

emitter.removeListener("say", say);

emitter.emit("say", "Hello World");

// Работа с файлами - получение списка файлов, находящихся в папке - readdir

var fs = require("fs");

var files = readdirSync("./some/folder");
console.log(files);

readdir("./some/folder", function (error, files) {
    if (error) {throw error;}
    console.log(files);
});

// Работа с файлами - чтение содержимого файла - readFile

var fs = require("fs");

var fileContent = fs.readFileSync("./some/file.txt", "UTF-8"); // кодировку нужно указывать !!!
console.log(fileContent);

readFile("./some/file.txt", "UTF-8", function (error, fileContent) {
    if (error) {throw error;}
    console.log(fileContent);
});

// Работа с файлами - получение описания файла stat

var fs = require("fs");
var path = require("path");

fs.readdir("./libs", function (error, files) {
    if (error) {throw error;}
    files.forEach(function (fileName) {
        var file = path.join(__dirname, "libs", fileName); // абсолютный путь до файла
        var stats = fs.statSync(file);
        if (stats.isFile()) {
            fs.readFile(file, "UTF-8", function (error, fileContent) {
                if (error) {throw error;}
                console.log(fileContent);
            });
        } else if (stats.isDirectory()) {
            console.log("It is directory");
        }
    });
});

// Работа с файлами - создание файла и запись в файл - writeFile

var fs = require("fs");

var fileContent = "Hello World";

fs.writeFileSync("sample.txt", fileContent);
console.log("Done");

fs.writeFile("sample.txt", fileContent, function (error) {
    if (error) {throw error;}
    console.log("Done");
});

fs.appendFile("sample.txt", "\nGoodbye");

// Работа с файлами - переименование и перемещение файлов в другую папку - rename

var fs = require("fs");

fs.renameSync("./lib/file-1.js", "./lib/file-2.js"); // переименование файла
console.log("Файл переименован");

fs.rename("./lib/file-1.js", "./file-1.js", function (error) { // перемещение файла в другую папку
    if (error) {throw error;}
    console.log("Файл пемемещен в другую папку");
});

// Работа с файлами - удаление файлов - unlink

var fs = require("fs");

try {
    fs.unlinkSync("./lib/file-1.js"); // удаление файла
    console.log("Done");
} catch (error) {
    console.log(error);
}

fs.unlink("./lib/file-1.js", function (error) { // удаление файла
    if (error) {throw error;}
    console.log("Done");
});

// Работа с файлами - создание директорий - mkdir, exists

var fs = require("fs");

if (fs.existsSync("lib")) {
    console.log("Directory lib already exists");
} else {
    fs.mkdir("libs", function (error) {
        if (error) {throw error;}
        console.log("Directory created");
    });  
}

// Работа с файлами - переименование и перемещение папок в другую папку - rename

var fs = require("fs");

fs.renameSync("./assets/logs", "./logs"); // перемещение папки в другую папку
console.log("Done");

// Работа с файлами - удаление папки - rmdir - НЕЛЬЗЯ УДАЛИТЬ ПАПКУ, ЕСЛИ В НЕЙ ЕЩЕ ЕСТЬ ФАЙЛЫ! СНАЧАЛА НАДО УДАЛИТЬ ВСЕ ФАЙЛЫ!

var fs = require("fs");

var files = fs.readdirSync("./libs");

if (files.length > 0) {
    files.forEach(function (fileName) {
        fs.unlinkSync("./libs" + fileName);
    });
}

fs.rmdir("./libs", function (error) {
    if (error) {throw error;}
    console.log("Done");
});

// Потоки - readable, writable, duplex = readable + writable

// Потоки - создание потока для чтения данных - createReadStream

var fs = require("fs");

var readStream = fs.createReadStream("./chat.log", "UTF-8"); // прочитать содержимое файла в потоке

var fileContent = "";

readStream.on("data", function (chunk) {
    fileContent += chunk;
    process.stdout.write(chunk);
});

readStream.on("end", function () {
    console.log("Done");
});

// Потоки - создание потока для записи данных - createWriteStream

var fs = require("fs");

var writeSteam = fs.createWriteStream("./chat.log");

for (var i = 0; i < 1000; i++) {
    writeStream.write(Math.random());
}

// HTTP - клиентский запрос - request

var http = require("http");
var fs = require("fs");

var options = {
    hostname: "google.com",
    post: 80
    path: "/search/data",
    method: "GET"
};

var request = http.request(options, function (response) {
    response.setEncoding("UTF-8");
    console.log(response.statusCode);
    console.log(response.headers);
    var responseBody = "";
    response.on("data", function (chunk) {
        responseBody += chunk;
    });
    response.on("end", function () {
        fs.writeFile("some.html", responseBody, function (error) {
            if (error) {throw error;}
            console.log("File downloaded");
        });
    });
});

request.on("error", function () {
    console.log("Error in request");
});

request.end(); // Послать запрос на сервер

// HTTP - создание сервера - createServer

var http = require("http");

var server = http.createServer(function (request, response) {
    response.writeHead(200, {"Content-Type": "text/html"});
    response.write("<!DOCTYPE html>");
    response.end(); // Завершить отправку ответа
});

server.listen("127.0.0.1:80"); // Создать сервер

// HTTP - обслуживание файлов - writeHead, write, end, url, method

var http = require("http");
var fs = require("fs");
var path = require("path");

var server = http.createServer(function (request, responce) {
    console.log(respose.method);
    if (requres.url === "/") {
        fs.readFile("./public/index.html", "UTF-8", function (error, fileContent) {
            if (error) {throw error;}
            response.writeHead(200, {"Content-Type": "text/html"});
            response.end(fileContent);
        });
    } else if (request.url.match(/.css$/)) {
        var cssPath = path.join(__dirname, "public", request.url);
        var readFileStream = fs.createReadStream(cssPath, "UTF-8"); // текстовые данные
        response.writeHead(200, {"Content-Type": "text/css"});
        readFileStream.on("data", function (chunk) {
            response.write(chunk);
        });
        readFileStream.on("end", function () {
            response.end();
        });
        // или можно так
        // readFileStream.pipe(response); // автоматически ставит в конце response.end()
    } else if (request.url.match(/.jpg$/)) {
        var imagePath = path.join(__dirname, "public", request.url);
        var readFileStream = fs.createReadStream(imagePath); // бинарные данные
        response.writeHead(200, {"Content-Type": "image/jpeg"});
        readFileStream.pipe(response);
    } else {
        response.writeHead(404, {"Content-Type": "text/plain"});
        response.end("404 File Not Found");
    }
    console.log(request);
   
});

server.listen("127.0.0.1:80");

// HTTP - обслуживание JSON - writeHead, write, end, url, method

var http = require("http");
var data = require("./json-file");

var server = http.createServer(function (request, response) {
    if (request.url === "/") {
        response.writeHead(200, {"Content-Type": "text/json"});
        response.end(JSON.stringify(data));
    } else if (request.url === "/instock") {
        listInStock(response);
    } else if (requrest.url === "/onorder") {
        listOnBackOrder(response);
    } else {
        response.writeHead(404, {"Content-Type": "text/plain");
        response.end("404 File Not Found");
    }
});

server.listen("127.0.0.1:80");

function listInStock (response) {
    var inStock = data.filter(function (item) {
        return item.available === "In stock";
    });
    response.writeHead(200, {"Content-Type": "text/json"});
    reponse.end(JSON.stringify(inStock));
}

function listOnBackOrder (response) {
    var onOrder = data.filter(function (item) {
        return item.available === "On back order";
    });
    response.writeHead(200, {"Content-Type": "text/json"});
    reponse.end(JSON.stringify(onOrder));
}

// HTTP - обслуживание GET, POST - writeHead, write, end, url, method

var http = require("http");
var fs = require("fs");

var server = http.createServer(function (request, response) {
    if (request.method === "GET") {
        response.writeHead(200, {"Content-Type": "text/html"});
        var fileReadStream = fs.createReadStream("./public/form.html", "UTF-8");
        fileReadStream.pipe(response);
    } else if (request.method === "POST") {
        var body = "";
        request.on("data", function (chunk) {
            body += chunk;
        });
        request.on("end", function () {
            response.writeHead(200, {"Content-Type": "text/html"});
            reponse.end(body);
        });
    }

});

server.listen("127.0.0.1:80");

// Express - сервер и прослойки middleware - app, use, get, post, delete, static, bodyParser

var express = require("express");

var app = express();

app.use(express.static("./public"));

app.use(epress.bodyParser({uploadDir: "./upload"}));

app.use(function (request, response, next) {
    console.log(request.method);
    console.log(request.url);
    next();
});

app.get("/", function (request, response) {
    response.json({one: 1, two: 2});
});

app.post("/form", function (request, response) {
    response.end("<!DOCTYPE html>" + request.body);
});

app.delete("/delete/:id", function (request, response) {
    response.end(request.params.id);
});

app.listen("127.0.0.1:80");

module.exports = app;

// WebSockets - стронняя библиотека WS для работы с WebSockets - WebSocketServer, send

var WebSocketServer = require("ws");

var wss = new WebSocketServer({port: 80});

wss.on("connection", function (webSocket) {
    webSocket.on("message", function (message) {
        if (message === "exit") {
            webSocket.close();
        } else {
            wss.clients.forEach(function (client) {
                client.send(message);
            });
        }
    });
    webSocket.send("Welcome to chat");
});

// Socket.IO - стронняя библиотека Socket.IO для работы с WebSockets - emit

var express = require("express");
var http = require("http");
var io = require("socket.io");

var app = express();

var server = http.createServer(app).listen("127.0.0.1:80");

io(server);

app.use(express.static("./public"));

io.on("connection", function (socket) {
    socket.on("chat", function (message) {
        socket.broadcast.emit("message", message);
    });
    socket.emit("message", "Welcome to chat");
});

=======================================
| Assertion Testing - ассерты для тестирования
=======================================

const assert = require('assert');

assert(false, 'it is false'); // throws: AssertionError: it is false

assert.ok(false, 'it is false'); // throws: AssertionError: it is false

assert.equal({a: {b: 1}}, {a: {b: 1}}); // throws: AssertionError: { a: { b: 1 } } == { a: { b: 1 } }

assert.strictEqual(1, '1'); // throws: AssertionError: 1 === '1'

assert.deepEqual({a: {b: 1}}, {a: {b: 2}}; // throws: AssertionError: { a: { b: 1 } } deepEqual { a: { b: 2 } }

assert.deepStrictEqual({a: 1}, {a: '1'}); // throws: AssertionError: { a: 1 } deepStrictEqual { a: '1' }

assert.fail(1, 2, undefined, '>'); // throws: AssertionError: 1 > 2

assert.fail(1, 2, 'whoops', '>'); // throws: AssertionError: whoops

assert.notEqual(1, 1); // throws: AssertionError: 1 != 1

assert.notStrictEqual(1, 1); // throws: AssertionError: 1 != 1

assert.notDeepEqual({a: {b: 1}}, {a: {b: 1}}); // throws: AssertionError: { a: { b: 1 } } notDeepEqual { a: { b: 1 } }

assert.notDeepStrictEqual({a: '1'}, {a: '1'}); // throws: AssertionError: { a: '1' } notDeepStrictEqual { a: '1' }

=======================================
| Buffer - буферы - массивы для двоичных данных
=======================================

const buf = Buffer.alloc(10); // <Buffer 00 00 00 00 00 00 00 00 00 00>

const buf = Buffer.alloc(10, 1); // <Buffer 01 01 01 01 01 01 01 01 01 01>

const buf = Buffer.from([1, 2, 3]); // <Buffer 01 02 03>

const buf = Buffer.from('test', 'utf8'); // <Buffer 74 65 73 74>

const buf = Buffer.from('hello world', 'ascii');

Варианты метода from:
- Buffer.from(array);
- Buffer.from(buffer);
- Buffer.from(arrayBuffer[, byteOffset [, length]]);
- Buffer.from(str[, encoding]);

const buf = Buffer.from([1, 2, 3]);
for (var b of buf) {
  console.log(b);
}
// Prints:
//   1
//   2
//   3

console.log(buf.toString('hex')); // prints: 68656c6c6f20776f726c64
console.log(buf.toString('base64')); // prints: aGVsbG8gd29ybGQ=

Варианты кодировок:
- 'ascii'
- 'utf8'
- 'utf16le'
- 'ucs2'
- 'base64'
- 'binary'
- 'hex'

const arr = new Uint16Array(20);
const buf = Buffer.from(arr.buffer, 0, 16);
console.log(buf.length); // Prints: 16

const buf = Buffer.from([1, 2, 3]); // <Buffer 01 02 03>
buf[1] = 5; // <Buffer 01 05 03>

console.log(buf.compare(buf)); // Prints: 0

console.log(buf1.equals(buf2)); // Prints: true

buf1.copy(buf2, 8, 16, 20);

const buf = Buffer.allocUnsafe(10);
buf.fill('h');
console.log(buf.toString()); // Prints: hhhhhhhhhh

const buf = Buffer.from('this is a buffer');

buf.indexOf('this'); // returns 0
buf.indexOf('is'); // returns 2

buf.lastIndexOf('this'); // returns 0
buf.lastIndexOf('buffer'); // returns 17

buf.includes('this'); // returns true

const buf = Buffer.from('buffer');
for (var key of buf.keys()) {
  console.log(key);
}
// prints:
//   0
//   1
//   2
//   3
//   4
//   5

Buffer.isBuffer(obj) // true или false

const buf = Buffer.alloc(1234);
console.log(buf.length); // Prints: 1234

const buf2 = buf1.slice(0, 3);

const buf = Buffer.alloc(3, 1); // <Buffer 01 01 01>
buf.toJSON(); // {type: 'Buffer', data: [1, 1, 1]}

const buf = Buffer.from('buffer');
for (var value of buf.values()) {
  console.log(value);
}
// prints:
//   98
//   117
//   102
//   102
//   101
//   114

const buf = Buffer.allocUnsafe(256);
const len = buf.write('\u00bd + \u00bc = \u00be', 0);
console.log(`${len} bytes: ${buf.toString('utf8', 0, len)}`); // Prints: 12 bytes: 1/2 + 1/4 = 3/4


const buf = Buffer.alloc(3, 1); // <Buffer 01 01 01>
buf.inspect(); // <Buffer 01 01 01>

buffer.INSPECT_MAX_BYTES; // Default: 50

=======================================
| Child Processes - работа с окном командной строки и запуск дополнительных дочерних процессов Node.js
=======================================

child_process.exec() - асинхронно запускает окно командной строки и выполняет внутри него команду, передавая stdout и stderr в callback

function когда выполнение команды завершится.

child_process.execFile() - такой же как child_process.exec() за исключением того, что команда выполняется напрямую без запуска окна

командной строки.

child_process.execSync() - синхронная версия child_process.exec(), блокирующая Node.js event loop.

child_process.execFileSync() - синхронная версия child_process.execFile(), блокирующая Node.js event loop.

child_process.fork() - запускает новый отдельный процесс Node.js и открывает канал для передачи сообщений между родительским процессом

Node.js и дочерним процессом Node.js.

child_process.spawn() - асинхронно запускает дочерний процесс Node.js, передавая stdout и stderr в callback function когда выполнение

команды завершится.

child_process.spawnSync() - синхронная версия child_process.spawn(), блокирующая Node.js event loop до завершения выполнения дочернего

процесса.

Достыпные Events:
- on('data, function () {})
- on('close', function () {})
- on('disconnect', function () {})
- on('error', function () {})
- on('exit', function () {})
- on('message', function () {})

Методы:
- child.send(message[, sendHandle[, options]][, callback])

- child.connected
- child.disconnect()

- child.kill([signal])
- child.pid

- child.stderr
- child.stdin
- child.stdio
- child.stdout

Примеры:

const spawn = require('child_process').spawn;
const listProcess = spawn('ls', ['-lh', '/usr']);

listProcess.stdout.on('data', (data) => {
  console.log(`stdout: ${data}`);
});

listProcess.stderr.on('data', (data) => {
  console.log(`stderr: ${data}`);
});

listProcess.on('close', (code) => {
  console.log(`child process exited with code ${code}`);
});

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

// или

const exec = require('child_process').exec;
exec('cat *.js bad_file | wc -l', function (error, stdout, stderr) {
  if (error) {
    console.error(`exec error: ${error}`);
    return;
  }
  console.log(`stdout: ${stdout}`);
  console.log(`stderr: ${stderr}`);
});

// execFile

const execFile = require('child_process').execFile;
const child = execFile('node', ['--version'], function (error, stdout, stderr) {
  if (error) {
    throw error;
  }
  console.log(stdout);
});

=======================================
| Console - console.log() - вывод сообщений на консоль
=======================================

console.log('hello world'); // Prints: hello world, to stdout

console.log('hello %s', 'world'); // Prints: hello world, to stdout

console.info([data][, ...]) - тоже самое, что и console.log([data][, ...])

console.dir(obj[, options]) // печатает свойства объекта

console.trace('Show me'); // Prints: (stack trace will vary based on where trace is called)

const code = 5;

console.error('error #%d', code); // Prints: error #5, to stderr

console.error('error', code); // Prints: error 5, to stderr

console.warn([data][, ...]) - тоже самое, что и console.error([data][, ...])

console.assert(true, 'does nothing'); // OK

console.assert(false, 'Whoops %s', 'didn\'t work'); // AssertionError: Whoops didn't work

console.time('100-elements');

for (var i = 0; i < 100; i++) {}

console.timeEnd('100-elements'); // prints 100-elements: 225.438ms

=======================================
| Debugger - запуск отладчика debugger; в браузере для отладки скрипта Node.js
=======================================

Описание команд:

Команды перехода по коду:

cont, c - продолжить выполнения кода
next, n - перейти к следующему шагу
step, s - войти внутрь функции
out, o - выйти из функции
pause - поставить выполнение кода на паузу, как при нажатии на кнопку паузы в Chrome Developer Tools

Команды для расстановки точек остановок в коде:

setBreakpoint(), sb() - установить breakpoint на текущую линию кода
setBreakpoint(line), sb(line) - установить breakpoint конкретную линию кода
setBreakpoint('fn()'), sb(...) - установить breakpoint первую строчку внутри тела функции
setBreakpoint('script.js', 1), sb(...) - установить breakpoint первую строчку файлы script.js
clearBreakpoint('script.js', 1), cb(...) - удалить breakpoint в файле script.js с линии 1

// myscript.js

x = 5;
setTimeout(() => {
  debugger;
  console.log('world');
}, 1000);
console.log('hello');

// запуск отладки скрипта

$ node debug myscript.js

< debugger listening on port 5858
connecting... ok

break in /home/indutny/Code/git/indutny/myscript.js:1
  1 x = 5;
  2 setTimeout(() => {
  3   debugger;

debug> cont

< hello
break in /home/indutny/Code/git/indutny/myscript.js:3
  1 x = 5;
  2 setTimeout(() => {
  3   debugger;
  4   console.log('world');
  5 }, 1000);

debug> next

break in /home/indutny/Code/git/indutny/myscript.js:4
  2 setTimeout(() => {
  3   debugger;
  4   console.log('world');
  5 }, 1000);
  6 console.log('hello');

debug> repl

Press Ctrl + C to leave debug repl

> x
5
> 2+2
4

debug> next

< world
break in /home/indutny/Code/git/indutny/myscript.js:5
  3   debugger;
  4   console.log('world');
  5 }, 1000);
  6 console.log('hello');
  7

debug> quit

=======================================
| Events - события addListener(), removeListener(), emit()
=======================================

emitter.addListener(eventName, listener) - тоже самое, что и emitter.on(eventName, listener) - добавить событие

emitter.prependListener() - добавить событие в самое начало списка имеющихся событий

emitter.once(eventName, listener) - добавить событие, которое будет удалено сразу после его вызова

emitter.prependOnceListener() -  добавить событие в самое начало списка имеющихся событий, которое будет удалено сразу после его вызова

emitter.emit(eventName[, arg1][, arg2][, ...]) - синхронно вызвать функции привязанные к события в порядке их привязки с передачей в них

аргументов

emitter.removeListener(eventName) - удалить событие

emitter.removeAllListeners([eventName]) - удалить все события

emitter.eventNames() - вернуть массив существующих имен событий

emitter.listenerCount(eventName) - подсчитать число существующих событий

emitter.getMaxListeners() - получить предельно допустимое число возможных событий (по умолчанию 10)

emitter.setMaxListeners(n) - установить предельно допустимое число возможных событий

emitter.listeners(eventName) - получить массив с копией функций привязанных к событию

// Пример добавления событий

const EventEmitter = require('events');

class MyEmitter extends EventEmitter {}

const myEmitter = new MyEmitter();

myEmitter.on('event', function callback (a, b) {
  console.log(a, b, this);
    // Prints:
    //   a b MyEmitter {
    //     domain: null,
    //     _events: { event: [Function] },
    //     _eventsCount: 1,
    //     _maxListeners: undefined }
});

myEmitter.emit('event', 'a', 'b');

myEmitter.removeEvent('event', callback);

// метод on

const myEmitter = new MyEmitter();

var m = 0;

myEmitter.on('event', () => {
  console.log(++m);
});

myEmitter.emit('event'); // Prints: 1
myEmitter.emit('event'); // Prints: 2

// метод once

const myEmitter = new MyEmitter();

var m = 0;

myEmitter.once('event', () => {
  console.log(++m);
});

myEmitter.emit('event'); // Prints: 1
myEmitter.emit('event'); // Ignored

// Error event

const myEmitter = new MyEmitter();

myEmitter.emit('error', new Error('whoops!')); // Throws and crashes Node.js

=======================================
| Stream - end, read, write, pause, resume, pipe, unpipe
=======================================

const stream = require('stream');

Types of Streams:
- Readable - fs.createReadStream()
- Writable - fs.createWriteStream()
- Duplex - net.Socket
- Transform

Readable

readable.read([size])

readable.pause()
readable.resume()
readable.isPaused()

readable.pipe(destination[, options])
readable.unpipe([destination])

readable.setEncoding(encoding)

readable.wrap(stream)

readable.unshift(chunk)

Readable  Events
- 'close'
- 'data'
- 'end'
- 'error'
- 'readable'

Writable

writable.write(chunk[, encoding][, callback])
writable.end([chunk][, encoding][, callback])

writable.cork()
writable.uncork()

writable.setDefaultEncoding(encoding)

Writable Events
- 'close'
- 'drain'
- 'error'
- 'finish'
- 'pipe'
- 'unpipe'

=======================================
| File System - open, close, readFile, writeFile, appendFile unlink, stats, access, watch
=======================================

// Создать поток для чтения из файла
fs.createReadStream(path[, options])

// Создать поток для записи в файл
fs.createWriteStream(path[, options])

// Открыть файл
fs.open(path, flags[, mode], callback)

// Закрыть файл
fs.close(fd, callback)

// Прочитать файл
fs.read(fd, buffer, offset, length, position, callback)

// Асинхронно прочитать весь файл целиком
fs.readFile('/etc/passwd', (err, data) => {
  if (err) throw err;
  console.log(data);
});

// Прочитать содержимое директории
fs.readdir(path[, options], callback)

// Добавление текста в конец файла
fs.appendFile('message.txt', 'data to append', (err) => {
  if (err) throw err;
  console.log('The "data to append" was appended to file!');
});

// Усечь файл
fs.ftruncate(fd, len, callback)

// Записать данные в файл или создать новый файл
fs.write(fd, buffer, offset, length[, position], callback)
fs.write(fd, data[, position[, encoding]], callback)

// Записать данные в файл и заменить его на новый, если он уже существует
fs.writeFile(file, data[, options], callback)

// Переименовать файл
fs.rename(oldPath, newPath, callback)

// Проверить существует ли файл - deprecated
fs.exists('/etc/passwd', (exists) => {
  console.log(exists ? 'it\'s there' : 'no passwd!');
});

// Сведения о файлах
fs.stat()
fs.lstat()
fs.fstat()

stats.isFile()
stats.isDirectory()

stats.isBlockDevice()
stats.isCharacterDevice()
stats.isSymbolicLink() (only valid with fs.lstat())
stats.isFIFO()
stats.isSocket()

// Изменение атрибутов файла
fs.chmod(path, mode, callback)

// Изменение владельца файла
fs.chown(path, uid, gid, callback)

// Изменения атрибутов файла
fs.constants.F_OK - файл видим для текущего процесса (значение по умолчанию)
fs.constants.R_OK - файл можешт быть прочитан текущим процессом
fs.constants.W_OK - файл можешт быть записан текущим процессом
fs.constants.X_OK - файл можешт быть выполнен текущим процессом

fs.access('/etc/passwd', fs.constants.R_OK | fs.constants.W_OK, (err) => {
  console.log(err ? 'no access!' : 'can read/write');
});

// Отслеживание изменений файлов
fs.watch('./tmp', {encoding: 'buffer'}, (eventType, filename) => {
  if (filename)
    console.log(filename);
    // Prints: <Buffer ...>
});

// Отслеживать изменения конкретного файла
fs.watchFile('message.text', (curr, prev) => {
  console.log(`the current mtime is: ${curr.mtime}`);
  console.log(`the previous mtime was: ${prev.mtime}`);
});

// Скопировать файл
fs.link(srcpath, dstpath, callback)

// Асинхронная версия удаления файла
const fs = require('fs');

fs.unlink('/tmp/hello', (err) => {
  if (err) throw err;
  console.log('successfully deleted /tmp/hello');
});

// Синхронная версия удаления файла
const fs = require('fs');

fs.unlinkSync('/tmp/hello');
console.log('successfully deleted /tmp/hello');

// Создать директорию
fs.mkdir(path[, mode], callback)

// Удалить директорию
fs.rmdir(path, callback)

=======================================
| Path
=======================================

const path = require('path');

path.basename('/foo/bar/baz/asdf/quux.html') // returns 'quux.html'
path.basename('/foo/bar/baz/asdf/quux.html', '.html') // returns 'quux'

path.win32..
path.posix..

path.delimiter
; for Windows
: for POSIX

path.sep
\ on Windows
/ on POSIX

// on POSIX:
'foo/bar/baz'.split(path.sep) // returns ['foo', 'bar', 'baz']

// on Windows:
'foo\\bar\\baz'.split(path.sep) // returns ['foo', 'bar', 'baz']

// on POSIX:
console.log(process.env.PATH) // '/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin'
process.env.PATH.split(path.delimiter) // returns ['/usr/bin', '/bin', '/usr/sbin', '/sbin', '/usr/local/bin']

// on Windows:
console.log(process.env.PATH) // 'C:\Windows\system32;C:\Windows;C:\Program Files\node\'
process.env.PATH.split(path.delimiter) // returns ['C:\\Windows\\system32', 'C:\\Windows', 'C:\\Program Files\\node\\']

path.dirname('/foo/bar/baz/asdf/quux') // returns '/foo/bar/baz/asdf'

path.extname('index.html') // returns '.html'
path.extname('index.coffee.md') // returns '.md'
path.extname('index.') // returns '.'
path.extname('index') // returns ''
path.extname('.index') // returns ''

path.format({dir: '/home/user/dir', base: 'file.txt'}); // returns '/home/user/dir/file.txt'
path.format({root: '/', base: 'file.txt'}); // returns '/file.txt'
path.format({root: '/', name: 'file', ext: '.txt'}); // returns '/file.txt'
path.format({base: 'file.txt'}); // returns 'file.txt'
path.format({root : "C:\\", dir : "C:\\path\\dir", base : "file.txt", ext : ".txt", name : "file"}); // returns 'C:\\path\\dir\\file.txt'

path.isAbsolute('/foo/bar') // true
path.isAbsolute('/baz/..')  // true
path.isAbsolute('qux/')     // false
path.isAbsolute('.')        // false
path.isAbsolute('//server')  // true
path.isAbsolute('C:/foo/..') // true
path.isAbsolute('bar\\baz')  // false
path.isAbsolute('.')         // false

ath.join('/foo', 'bar', 'baz/asdf', 'quux', '..') // returns '/foo/bar/baz/asdf'
path.join('foo', {}, 'bar') // throws TypeError: Arguments to path.join must be strings

path.normalize('/foo/bar//baz/asdf/quux/..') // returns '/foo/bar/baz/asdf'
path.normalize('C:\\temp\\\\foo\\bar\\..\\'); // returns 'C:\\temp\\foo\\'

// on POSIX:
path.relative('/data/orandea/test/aaa', '/data/orandea/impl/bbb') // returns '../../impl/bbb'

// on Windows:
path.relative('C:\\orandea\\test\\aaa', 'C:\\orandea\\impl\\bbb') // returns '..\\..\\impl\\bbb'

path.resolve('/foo/bar', './baz') // returns '/foo/bar/baz'

path.resolve('/foo/bar', '/tmp/file/') // returns '/tmp/file'

path.resolve('wwwroot', 'static_files/png/', '../gif/image.gif') // if the current working directory is /home/myself/node, this returns

'/home/myself/node/wwwroot/static_files/gif/image.gif'

// on POSIX:
┌───────────────────┬────────────┐
│                 dir              │         base       │
├──────┬                    ├─────┬──────┤
│   root   │                     │  name │   ext   │
│     /        home/user/dir  /   file       .txt   │
└──────┴───────────┴──────┴─────┘

path.parse('/home/user/dir/file.txt')
// returns
// {
//    root : "/",
//    dir : "/home/user/dir",
//    base : "file.txt",
//    ext : ".txt",
//    name : "file"
// }

on Windows:

┌───────────── ──┬────────────┐
│                 dir        │         base        │
├──────┬              ├──────┬─────┤
│   root   │              │  name   │   ext  │
│    C:\      path\dir   \   file         .txt  │
└──────┴──── ───┴──────┴─────┘

path.parse('C:\\path\\dir\\file.txt')
// returns
// {
//    root : "C:\\",
//    dir : "C:\\path\\dir",
//    base : "file.txt",
//    ext : ".txt",
//    name : "file"
// }

=======================================
| Globals - __driname, __filename, global, Buffer, process, setTimeout, clearTimweout, console, module, exports, require
=======================================

console.log(__dirname); // /Users/mjr
console.log(__filename); // /Users/mjr/example.js

=======================================
| Modules - require, module, export, exports, name, id, parent, loaded
=======================================

require(X) from module at path Y
1. If X is a core module,
   a. return the core module
   b. STOP
2. If X begins with './' or '/' or '../'
   a. LOAD_AS_FILE(Y + X)
   b. LOAD_AS_DIRECTORY(Y + X)
3. LOAD_NODE_MODULES(X, dirname(Y))
4. THROW "not found"

LOAD_AS_FILE(X)
1. If X is a file, load X as JavaScript text.  STOP
2. If X.js is a file, load X.js as JavaScript text.  STOP
3. If X.json is a file, parse X.json to a JavaScript Object.  STOP
4. If X.node is a file, load X.node as binary addon.  STOP

LOAD_AS_DIRECTORY(X)
1. If X/package.json is a file,
   a. Parse X/package.json, and look for "main" field.
   b. let M = X + (json main field)
   c. LOAD_AS_FILE(M)
2. If X/index.js is a file, load X/index.js as JavaScript text.  STOP
3. If X/index.json is a file, parse X/index.json to a JavaScript object. STOP
4. If X/index.node is a file, load X/index.node as binary addon.  STOP

LOAD_NODE_MODULES(X, START)
1. let DIRS=NODE_MODULES_PATHS(START)
2. for each DIR in DIRS:
   a. LOAD_AS_FILE(DIR/X)
   b. LOAD_AS_DIRECTORY(DIR/X)

NODE_MODULES_PATHS(START)
1. let PARTS = path split(START)
2. let I = count of PARTS - 1
3. let DIRS = []
4. while I >= 0,
   a. if PARTS[I] = "node_modules" CONTINUE
   c. DIR = path join(PARTS[0 .. I] + "node_modules")
   b. DIRS = DIRS + DIR
   c. let I = I - 1
5. return DIRS

The module wrapper#
Before a module's code is executed, Node.js will wrap it with a function wrapper that looks like the following:
(function (exports, require, module, __filename, __dirname) {
    // Your module code actually lives in here
});

module.filename
module.id
module.loaded
module.parent
module.require(id)

require.main === module

const circle = require('./circle.js');
console.log( `The area of a circle of radius 4 is ${circle.area(4)}`);

// assigning to exports will not modify module, must use module.exports
module.exports = (width) => {
  return {
    area: () => width * width
  };
}

=======================================
| OS - EOL, platform, type, cpus, homedir, tmpdir
=======================================

const os = require('os');

os.EOL
\n on POSIX
\r\n on Windows

os.endianness()
'BE' for big endian
'LE' for little endian.

os.arch() - тоже самое, что и process.arch
// 'arm', 'arm64', 'ia32', 'mips', 'mipsel', 'ppc', 'ppc64', 's390', 's390x', 'x32', 'x64', 'x86'

os.platform() - тоже самое, что и process.platform
// 'aix', 'darwin', 'freebsd', 'linux', 'openbsd', 'sunos', 'win32'

os.type() // 'Linux' on Linux, 'Darwin' on OS X, 'Windows_NT' on Windows

os.release()

os.constants

os.cpus()

os.freemem() - число доступных байт системной памяти

os.totalmem() - общее число байт системной памяти

os.homedir() - домашняя директория в операционной системе

os.tmpdir() - директория для временных файлов в операционной системе

os.loadavg()

os.uptime()

os.networkInterfaces()
{
    address: '127.0.0.1',
    netmask: '255.0.0.0',
    family: 'IPv4',
    mac: '00:00:00:00:00:00',
    internal: true
}

OS Constants:
- Signal Constants
- Error Constants
- POSIX Error Constants
- Windows Specific Error Constants
- libuv Constants

=======================================
| Process - argv, nextTick, exit, abort, stdin, stdout, stderr, chdir, cwd, env, hrtime
=======================================

process - это глобальный объект, экземляр Event Emitter, предоставляющий информацию и контролирующий текущий процесс работы Node.js

process.stdin

process.stdin.setEncoding('utf8');

process.stdin.on('readable', () => {
  var chunk = process.stdin.read();
  if (chunk !== null) {
    process.stdout.write(`data: ${chunk}`);
  }
});

process.stdin.on('end', () => {
  process.stdout.write('end');
});

process.stdout

console.log = (msg) => {
  process.stdout.write(`${msg}\n`);
};

process.stderr

process.nextTick(callback[, arg][, ...])

console.log('start');
process.nextTick(() => {
  console.log('nextTick callback');
});
console.log('scheduled');
// Output:
// start
// scheduled
// nextTick callback

process.exit(1)

if (someConditionNotMet()) {
  printUsageToStdout();
  process.exit(1);
}

process.exitCode

process.kill(pid[, signal])

process.kill(process.pid, 'SIGHUP');

process.getegid()

if (process.getegid) {
  console.log(`Current gid: ${process.getegid()}`);
}

process.geteuid()

process.getgid()

process.pid

process.title

process.abort()

process.argv

$ node process-2.js one two=three four

process.argv.forEach((val, index) => {
  console.log(`${index}: ${val}`);
});

$ node --harmony script.js --version
['/usr/local/bin/node', 'script.js', '--version']

process.execArgv

$ node --harmony script.js --version
['--harmony']

process.execPath // /usr/local/bin/node

process.stdin.resume();

process.chdir(directory)

process.cwd()
console.log(`Current directory: ${process.cwd()}`);

process.chdir('/tmp');
console.log(`Starting directory: ${process.cwd()}`);
try {
  process.chdir('/tmp');
  console.log(`New directory: ${process.cwd()}`);
}
catch (err) {
  console.log(`chdir: ${err}`);
}

process.hrtime([time])

var time = process.hrtime(); // [ 1800216, 25 ]

process.uptime()

process.versions
{
  http_parser: '2.3.0',
  node: '1.1.1',
  v8: '4.1.0.14',
  uv: '1.3.0',
  zlib: '1.2.8',
  ares: '1.10.0-DEV',
  modules: '43',
  icu: '55.1',
  openssl: '1.0.1k'
}

process.config

process.connected

process.disconnect()

process.arch

process.platform

process.cpuUsage([previousValue])

const startUsage = process.cpuUsage(); // { user: 38579, system: 6986 }

process.release

process.env
{
  TERM: 'xterm-256color',
  SHELL: '/usr/local/bin/bash',
  USER: 'maciej',
  PATH: '~/.bin/:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin',
  PWD: '/Users/maciej',
  EDITOR: 'vim',
  SHLVL: '1',
  HOME: '/Users/maciej',
  LOGNAME: 'maciej',
  _: '/usr/local/bin/node'
}
process.env.foo = 'bar';
console.log(process.env.foo);

process.env.test = null;
console.log(process.env.test); // => 'null'

process.env.test = undefined;
console.log(process.env.test); // => 'undefined'

process.env.TEST = 1;
delete process.env.TEST;
console.log(process.env.TEST); // => undefined

process.mainModule

process.memoryUsage()

process.send(message[, sendHandle[, options]][, callback])

process.on('exit', (code) => {
  console.log(`About to exit with code: ${code}`);
});

process.on('beforeExit', function () {});

process.on('disconnect', function () {});

process.on('message', function () {});

process.on('rejectionHandled', function () {});

const unhandledRejections = new Map();
process.on('unhandledRejection', (reason, p) => {
  unhandledRejections.set(p, reason);
});

process.on('rejectionHandled', (p) => {
  unhandledRejections.delete(p);
});

process.on('uncaughtException', function () {});

process.on('uncaughtException', (err) => {
  fs.writeSync(1, `Caught exception: ${err}`);
});

process.on('warning', function () {});

process.on('warning', (warning) => {
  console.warn(warning.name);    // Print the warning name
  console.warn(warning.message); // Print the warning message
  console.warn(warning.stack);   // Print the stack trace
});


process.emitWarning('Something happened!'); // Prints: (node 12345) Warning: Something happened!
process.emitWarning('This API is deprecated', 'DeprecationWarning');

Signal Events

process.on('SIGINT', () => {
  console.log('Received SIGINT.  Press Control-D to exit.');
});

=======================================
| HTTP - request, createServer, request, response, writeHead, write, end, setHeader, getHeader, removeHeader
=======================================

http.request(options[, callback])

http.createClient([port][, host])

http.createServer([requestListener])

http.globalAgent

http.get(options[, callback])

http.METHODS

http.STATUS_CODES

http.Agent
new Agent([options])

agent.createConnection(options[, callback])

agent.destroy()

agent.freeSockets

agent.getName(options)

agent.maxFreeSockets

agent.maxSockets

agent.requests

agent.sockets

http.ClientRequest

on('abort', function(){})
on('aborted', function(){})
on('checkExpectation', function(){})
on('connect', function(){})
on('continue', function(){})
on('response', function(){})
on('socket', function(){})
on('upgrade', function(){})

request.write(chunk[, encoding][, callback])

request.end([data][, encoding][, callback])

request.abort()

request.flushHeaders()

request.setNoDelay([noDelay])

request.setSocketKeepAlive([enable][, initialDelay])

request.setTimeout(timeout[, callback])

http.Server

on('checkContinue', function(){})
on('clientError', function(){})
on('close', function(){})
on('connect', function(){})
on('connection', function(){})
on('request', function(){})
on('upgrade', function(){})

server.listen(handle[, callback])
server.listen(path[, callback])
server.listen(port[, hostname][, backlog][, callback])

server.listening

server.close([callback])

server.maxHeadersCount

server.setTimeout(msecs, callback)

server.timeout

http.ServerResponse

on('close', function(){})
on('finish', function(){})

response.writeHead(statusCode[, statusMessage][, headers])
response.writeHead(200, {
  'Content-Length': Buffer.byteLength(body),
  'Content-Type': 'text/plain' });

response.write(chunk[, encoding][, callback])

response.end([data][, encoding][, callback])

response.setHeader(name, value)
response.setHeader('Set-Cookie', ['type=ninja', 'language=javascript']);

response.getHeader(name)
var contentType = response.getHeader('content-type');

response.removeHeader(name)
response.removeHeader('Content-Encoding');

response.headersSent

response.setTimeout(msecs, callback)

response.statusCode
response.statusCode = 404;

response.statusMessage
response.statusMessage = 'Not found';

response.addTrailers(headers)

response.finished

response.sendDate

response.writeContinue()

http.IncomingMessage

on('aborted', function(){})
on('close', function(){})

message.headers

message.rawHeaders

message.setTimeout(msecs, callback)

message.statusCode

message.httpVersion

message.destroy([error])

message.method

message.rawTrailers

message.statusMessage

message.socket

message.trailers

message.url

const http = require('http');
const net = require('net');
const url = require('url');

// Create an HTTP tunneling proxy
var proxy = http.createServer( (req, res) => {
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end('okay');
});
proxy.on('connect', (req, cltSocket, head) => {
  // connect to an origin server
  var srvUrl = url.parse(`http://${req.url}`);
  var srvSocket = net.connect(srvUrl.port, srvUrl.hostname, () => {
    cltSocket.write('HTTP/1.1 200 Connection Established\r\n' +
                    'Proxy-agent: Node.js-Proxy\r\n' +
                    '\r\n');
    srvSocket.write(head);
    srvSocket.pipe(cltSocket);
    cltSocket.pipe(srvSocket);
  });
});

// now that proxy is running
proxy.listen(1337, '127.0.0.1', () => {

  // make a request to a tunneling proxy
  var options = {
    port: 1337,
    hostname: '127.0.0.1',
    method: 'CONNECT',
    path: 'www.google.com:80'
  };

  var req = http.request(options);
  req.end();

  req.on('connect', (res, socket, head) => {
    console.log('got connected!');

    // make a request over an HTTP tunnel
    socket.write('GET / HTTP/1.1\r\n' +
                 'Host: www.google.com:80\r\n' +
                 'Connection: close\r\n' +
                 '\r\n');
    socket.on('data', (chunk) => {
      console.log(chunk.toString());
    });
    socket.on('end', () => {
      proxy.close();
    });
  });
});

// ------------------------------------

const http = require('http');

// Create an HTTP server
var srv = http.createServer( (req, res) => {
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end('okay');
});
srv.on('upgrade', (req, socket, head) => {
  socket.write('HTTP/1.1 101 Web Socket Protocol Handshake\r\n' +
               'Upgrade: WebSocket\r\n' +
               'Connection: Upgrade\r\n' +
               '\r\n');

  socket.pipe(socket); // echo back
});

// now that server is running
srv.listen(1337, '127.0.0.1', () => {

  // make a request
  var options = {
    port: 1337,
    hostname: '127.0.0.1',
    headers: {
      'Connection': 'Upgrade',
      'Upgrade': 'websocket'
    }
  };

  var req = http.request(options);
  req.end();

  req.on('upgrade', (res, socket, upgradeHead) => {
    console.log('got upgraded!');
    socket.end();
    process.exit(0);
  });
});

// ----------------------------------------

const http = require('http');

const server = http.createServer((req, res) => {
  res.end();
});
server.on('clientError', (err, socket) => {
  socket.end('HTTP/1.1 400 Bad Request\r\n\r\n');
});
server.listen(8000);

// ---------------------------------------

const server = http.createServer((req,res) => {
  res.setHeader('Content-Type', 'text/html');
  res.setHeader('X-Foo', 'bar');
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end('ok');
});

// -------------------------------------------------------

var postData = querystring.stringify({
  'msg' : 'Hello World!'
});

var options = {
  hostname: 'www.google.com',
  port: 80,
  path: '/upload',
  method: 'POST',
  headers: {
    'Content-Type': 'application/x-www-form-urlencoded',
    'Content-Length': Buffer.byteLength(postData)
  }
};

var req = http.request(options, (res) => {
  console.log(`STATUS: ${res.statusCode}`);
  console.log(`HEADERS: ${JSON.stringify(res.headers)}`);
  res.setEncoding('utf8');
  res.on('data', (chunk) => {
    console.log(`BODY: ${chunk}`);
  });
  res.on('end', () => {
    console.log('No more data in response.');
  });
});

req.on('error', (e) => {
  console.log(`problem with request: ${e.message}`);
});

// write data to request body
req.write(postData);
req.end();

=======================================
| HTTPS -
=======================================

https.request(options, callback)

https.createServer(options[, requestListener])

https.Agent

https.Server

server.setTimeout(msecs, callback)

server.timeout

server.close([callback])

server.listen(handle[, callback])
server.listen(path[, callback])
server.listen(port[, host][, backlog][, callback])

https.get(options, callback)

https.globalAgent

// ---------------------------------------------

// curl -k https://localhost:8000/
const https = require('https');
const fs = require('fs');

const options = {
  key: fs.readFileSync('test/fixtures/keys/agent2-key.pem'),
  cert: fs.readFileSync('test/fixtures/keys/agent2-cert.pem')
};

https.createServer(options, (req, res) => {
  res.writeHead(200);
  res.end('hello world\n');
}).listen(8000);

// ---------------------------------------------

const https = require('https');
const fs = require('fs');

const options = {
  pfx: fs.readFileSync('server.pfx')
};

https.createServer(options, (req, res) => {
  res.writeHead(200);
  res.end('hello world\n');
}).listen(8000);

// ---------------------------------------------

const https = require('https');

https.get('https://encrypted.google.com/', (res) => {
  console.log('statusCode: ', res.statusCode);
  console.log('headers: ', res.headers);

  res.on('data', (d) => {
    process.stdout.write(d);
  });

}).on('error', (e) => {
  console.error(e);
});

// ---------------------------------------------

const https = require('https');

var options = {
  hostname: 'encrypted.google.com',
  port: 443,
  path: '/',
  method: 'GET'
};

var req = https.request(options, (res) => {
  console.log('statusCode: ', res.statusCode);
  console.log('headers: ', res.headers);

  res.on('data', (d) => {
    process.stdout.write(d);
  });
});
req.end();

req.on('error', (e) => {
  console.error(e);
});

// ---------------------------------------------

var options = {
  hostname: 'encrypted.google.com',
  port: 443,
  path: '/',
  method: 'GET',
  key: fs.readFileSync('test/fixtures/keys/agent2-key.pem'),
  cert: fs.readFileSync('test/fixtures/keys/agent2-cert.pem')
};
options.agent = new https.Agent(options);

var req = https.request(options, (res) => {
  ...
});

=======================================
| Timers - setTimeout, setInterval, setImmediate, ref, unref
=======================================

var timeout = setTimeout(function(){}, 5000[, ...arg])
clearTimeout(timeout)

var interval = setInterval(function(){}, 5000[, ...arg])
clearInterval(interval )

var immediate = setImmediate(function(){}[, ...arg])
clearImmediate(immediate)

timeout.ref()

timeout.unref()

=======================================
| URL - парсинг урлов
=======================================

http://user:pass@host.com:8080/p/a/t/h?query=string#hash

┌───────────────────────────────────────────────────────────┐
│                                                        href                                               │
├───── ─┬┬─────── ┬─────────────┬───────────────────┬──────┤
│ protocol ││   auth      │           host       │               path                │ hash   │
│             ││               ├─────────────┼───── ───┬──────────┤          │
│             ││               │ hostname │ port │ pathname │     search      │           │
│             ││               │               │        │               ├┬──────── ─┤          │
│             ││               │               │        │               │ │    query       │          │
│ http:      // user:pass @ host.com : 8080     /p/a/t/h   ?  query=string   #hash │
│             ││               │               │        │               │ │                   │         │
└───────┴┴─── ────┴────────┴────┴────── ─┴┴──────────┴─────┘

const url = require('url');

urlObject.href // 'http://user:pass@host.com:8080/p/a/t/h?query=string#hash'
urlObject.protocol // 'http:'
urlObject.slashes // true
urlObject.host // 'host.com:8080'
urlObject.auth // 'user:pass
urlObject.hostname // 'host.com'
urlObject.port // '8080'
urlObject.pathname // '/p/a/t/h'
urlObject.search // ?query=string'
urlObject.path // '/p/a/t/h?query=string'
urlObject.query // 'query=string' или {'query': 'string'}
urlObject.hash '#hash'

url.format(urlObject) // возвращает отформатированную строку в адресом
url.parse(urlString[, parseQueryString[, slashesDenoteHost]]) // берет строку с адресом и превращает её в объект URL object
url.resolve(from, to) // соединяет адрес страницы с адресом сайта

url.resolve('/one/two/three', 'four')               // '/one/two/four'
url.resolve('http://example.com/', '/one')      // 'http://example.com/one'
url.resolve('http://example.com/one', '/two') // 'http://example.com/two'

Пробелы и знаки < > " ` \r \n \t { } | \ ^ ' автоматически будут заэскейплены.

=======================================
| Query String - парсинг строки с параметрами из URL
=======================================

const querystring = require('querystring');

querystring.escape(str) // эскейпит строку символами с процентом

querystring.unescape(str) // анэскейпит (деколдирует) строку, содержащую символы с процентами

querystring.parse(str[, sep[, eq[, options]]]) // превращает строку с параметрами в объект

querystring.parse('foo=bar&abc=xyz&abc=123', '&', '=', {decodeURIComponent: querystring.unescape, maxKeys: 1000}) // {foo: 'bar', abc: ['xyz',

'123']}

querystring.stringify(obj[, sep[, eq[, options]]]) // преваращает объект с параметрами в строку

querystring.stringify({foo: 'bar', abc: ['xyz', '123']}, '&', '=', {encodeURIComponent: querystring.escape}) // 'foo=bar&abc=xyz&abc=123'
querystring.stringify({foo: 'bar', baz: ['qux', 'quux'], corge: ''}) // 'foo=bar&baz=qux&baz=quux&corge='
querystring.stringify({foo: 'bar', baz: 'qux'}, ';', ':') // 'foo:bar;baz:qux'

=======================================
| Utilities - утилиты format, debuglog, deprecate, inspect
=======================================

// debuglog()

const util = require('util');

const debuglog = util.debuglog('foo');

debuglog('hello from foo [%d]', 123); // Если программа запущена с ключом NODE_DEBUG=foo, то в консоли будет выведено FOO 3245: hello

from foo [123] иначе функция не выведен ничего

// deprecate()

const util = require('util');

exports.puts = util.deprecate(function() {
  for (var i = 0, len = arguments.length; i < len; ++i) {
    process.stdout.write(arguments[i] + '\n');
  }
}, 'util.puts: Use console.log instead'); // Выведет в консоли сообщение util.puts: Use console.log instead

// format()

Типы форматов:

%s - string
%d - number (integer и float).
%j - JSON
%% - символ '%'

util.format('%s:%s', 'foo'); // Returns 'foo:%s'

util.format('%s:%s', 'foo', 'bar', 'baz'); // 'foo:bar baz'

util.format(1, 2, 3); // '1 2 3'

// inspect()

console.log(util.inspect(util, { showHidden: true, depth: null })); // выведет структуру всех свойст объекта

// Custom inspect()

const util = require('util');

const obj = { name: 'nate' };

obj.inspect = function(depth) {
  return `{${this.name}}`;
};

util.inspect(obj); // "{nate}"

=======================================
| StringDecoder - декодирование объекта Buffer в строку
=======================================

new StringDecoder([encoding])
stringDecoder.end([buffer])
stringDecoder.write(buffer)

const StringDecoder = require('string_decoder').StringDecoder;
const decoder = new StringDecoder('utf8');

const cent = Buffer.from([0xC2, 0xA2]);
console.log(decoder.write(cent));

const euro = Buffer.from([0xE2, 0x82, 0xAC]);
console.log(decoder.write(euro));