├── .eslintignore ├── .github ├── FUNDING.yml └── workflows │ └── test.yml ├── .gitignore ├── Exercises ├── 1-pipe.js ├── 2-compose.js ├── 1-pipe.test └── 2-compose.test ├── README.md ├── .editorconfig ├── Solutions ├── 1-pipe.js └── 2-compose.js ├── package.json ├── JavaScript ├── 2-composition.js ├── 8-compose-proto.js ├── 3-arguments.js ├── 1-superposition.js ├── 4-multiple.js ├── 6-recursive.js ├── 5-loop.js └── 7-compose-async.js ├── Exercises.ru.md ├── LICENSE └── .eslintrc.json /.eslintignore: -------------------------------------------------------------------------------- 1 | Exercises/ 2 | node_modules/ 3 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | patreon: tshemsedinov 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | *.log 3 | .DS_Store 4 | -------------------------------------------------------------------------------- /Exercises/1-pipe.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const pipe = (...fns) => (x) => null; 4 | 5 | module.exports = { pipe }; 6 | -------------------------------------------------------------------------------- /Exercises/2-compose.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const compose = (...fns) => (x) => null; 4 | 5 | module.exports = { compose }; 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Композиция функций 2 | 3 | [![Композиция функций (pipe, compose) в JavaScript](https://img.youtube.com/vi/xS9FicVrOTI/0.jpg)](https://www.youtube.com/watch?v=xS9FicVrOTI) 4 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | end_of_line = lf 6 | charset = utf-8 7 | insert_final_newline = true 8 | trim_trailing_whitespace = true 9 | 10 | [{*.js,*.mjs,*.ts,*.json,*.yml}] 11 | indent_size = 2 12 | indent_style = space 13 | -------------------------------------------------------------------------------- /Solutions/1-pipe.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const pipe = (...fns) => { 4 | for (const f of fns) { 5 | if (typeof f !== 'function') { 6 | throw new Error('All compose arguments should be functions'); 7 | } 8 | } 9 | return (x) => fns.reduce((v, f) => f(v), x); 10 | }; 11 | 12 | module.exports = { pipe }; 13 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "example", 3 | "private": true, 4 | "version": "1.2.0", 5 | "author": "Timur Shemsedinov ", 6 | "license": "MIT", 7 | "scripts": { 8 | "test": "eslint ./Exercises; hpw", 9 | "ci": "eslint ./Exercises && hpw" 10 | }, 11 | "dependencies": { 12 | "eslint": "^8.57.1", 13 | "hpw": "^0.2.4" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Check labs 2 | 3 | on: pull_request 4 | 5 | jobs: 6 | build: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/checkout@v2 10 | - name: Node.js 11 | uses: actions/setup-node@v1 12 | with: 13 | node-version: 14 14 | - uses: actions/cache@v2 15 | with: 16 | path: ~/.npm 17 | key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} 18 | restore-keys: | 19 | ${{ runner.os }}-node- 20 | - run: npm ci 21 | - run: npm t 22 | -------------------------------------------------------------------------------- /JavaScript/2-composition.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const compose = (f, g) => (x) => f(g(x)); 4 | 5 | // Usage 6 | 7 | const upperFirst = (word) => word.charAt(0).toUpperCase() + word.slice(1); 8 | const upperCapital = (s) => s.split(' ').map(upperFirst).join(' '); 9 | const lower = (s) => s.toLowerCase(); 10 | 11 | const capitalize = compose(upperCapital, lower); 12 | 13 | const s = 'MARCUS AURELIUS'; 14 | console.log(s); 15 | console.log(`lower('${s}') = '${lower(s)}'`); 16 | console.log(`upperCapital('${s}') = '${upperCapital(s)}'`); 17 | console.log(`capitalize('${s}') = '${capitalize(s)}'`); 18 | -------------------------------------------------------------------------------- /Solutions/2-compose.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const compose = (...fns) => { 4 | const handlers = []; 5 | const composed = (x) => { 6 | if (fns.length === 0) return x; 7 | const last = fns.length - 1; 8 | let res = x; 9 | try { 10 | for (let i = last; i >= 0; i--) { 11 | res = fns[i](res); 12 | } 13 | return res; 14 | } catch (error) { 15 | for (const handler of handlers) { 16 | handler(error); 17 | } 18 | return null; 19 | } 20 | }; 21 | composed.on = (name, handler) => { 22 | if (name === 'error') handlers.push(handler); 23 | }; 24 | return composed; 25 | }; 26 | 27 | module.exports = { compose }; 28 | -------------------------------------------------------------------------------- /Exercises/1-pipe.test: -------------------------------------------------------------------------------- 1 | ({ 2 | name: 'pipe', 3 | length: [150, 300], 4 | test: pipe => { 5 | const inc = x => ++x; 6 | const twice = x => x * 2; 7 | const cube = x => x ** 3; 8 | { 9 | const f = pipe(inc, twice, cube); 10 | const x = f(5); 11 | if (x !== 1728) throw new Error(`Expected 1728 instead of ${x}`); 12 | } 13 | { 14 | const f = pipe(inc, inc); 15 | const x = f(7); 16 | if (x !== 9) throw new Error(`Expected 9 instead of ${x}`); 17 | } 18 | { 19 | let catched = false; 20 | try { 21 | pipe(7, 3); 22 | } catch (err) { 23 | catched = true; 24 | } 25 | if (!catched) throw new Error(`Function pipe should throw`); 26 | } 27 | } 28 | }) 29 | -------------------------------------------------------------------------------- /JavaScript/8-compose-proto.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const { EventEmitter } = require('node:events'); 4 | 5 | function AddOnlySet(it) { 6 | this.set = new Set(it); 7 | this.emitter = new EventEmitter(); 8 | this.size = it.length; 9 | } 10 | 11 | AddOnlySet.prototype.add = function(value) { 12 | this.set.add(value); 13 | this.size = this.set.size; 14 | this.emitter.emit('add', value); 15 | }; 16 | 17 | AddOnlySet.prototype.on = function(name, listener) { 18 | this.emitter.on(name, listener); 19 | }; 20 | 21 | AddOnlySet.prototype.toString = function() { 22 | return [...this.set.values()].join(); 23 | }; 24 | 25 | // Usage 26 | 27 | const s1 = new AddOnlySet(['uno', 'due']); 28 | s1.on('add', (value) => console.log(`Added "${value}"`)); 29 | s1.add('tre'); 30 | console.dir({ result: s1.toString() }); 31 | -------------------------------------------------------------------------------- /JavaScript/3-arguments.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const compose = (f, g) => (...args) => f(g(...args)); 4 | const pipe = (f, g) => (...args) => g(f(...args)); 5 | 6 | // Usage 7 | 8 | const upperFirst = (word) => word.charAt(0).toUpperCase() + word.slice(1); 9 | const upperCapital = (s) => s.split(' ').map(upperFirst).join(' '); 10 | const lower = (s) => s.toLowerCase(); 11 | 12 | const s = 'MARCUS AURELIUS'; 13 | console.log(s); 14 | console.log(`lower('${s}') = '${lower(s)}'`); 15 | console.log(`upperCapital('${s}') = '${upperCapital(s)}'`); 16 | 17 | { 18 | console.log('Use compose'); 19 | const capitalize = compose(upperCapital, lower); 20 | console.log(`capitalize('${s}') = '${capitalize(s)}'`); 21 | } 22 | { 23 | console.log('Use pipe'); 24 | const capitalize = pipe(lower, upperCapital); 25 | console.log(`capitalize('${s}') = '${capitalize(s)}'`); 26 | } 27 | -------------------------------------------------------------------------------- /JavaScript/1-superposition.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const { log: ln } = Math; 4 | const pow = Math.pow; 5 | const sqrt = Math.sqrt; 6 | const inc = (x) => ++x; 7 | const add = (a, b) => a + b; 8 | const mul = (a, b) => a * b; 9 | const div = (a, b) => a / b; 10 | const log = (base, n) => ln(n) / ln(base); 11 | const iff = (e, x1, x2) => (e ? x1 : x2); 12 | const loop = (from, to, fn) => { 13 | for (let i = from; i <= to; i++) fn(i); 14 | }; 15 | 16 | const expr1 = pow(5 * 8, 2) + ((sqrt(20) + 1) / log(2, 7)); 17 | console.log(expr1); 18 | 19 | const expr2 = add( 20 | pow(mul(5, 8), 2), div(inc(sqrt(20)), log(2, 7)) 21 | ); 22 | console.log(expr2); 23 | 24 | const expr3 = add(iff(5 > 3, 10, 7), div(1, 2)); 25 | console.log(expr3); 26 | 27 | console.log('Loop from 5 to 10'); 28 | loop(5, 10, console.log); 29 | 30 | console.log('Loop from 5 to 10, write < 8'); 31 | loop(5, 10, (x) => iff(x < 8, console.log, () => {})(x)); 32 | -------------------------------------------------------------------------------- /JavaScript/4-multiple.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const compose = (...fns) => (x) => fns.reduceRight((v, f) => f(v), x); 4 | const pipe = (...fns) => (x) => fns.reduce((v, f) => f(v), x); 5 | 6 | // Usage 7 | 8 | const upperFirst = (word) => word.charAt(0).toUpperCase() + word.slice(1); 9 | const upperCapital = (s) => s.split(' ').map(upperFirst).join(' '); 10 | const lower = (s) => s.toLowerCase(); 11 | const trim = (s) => s.trim(); 12 | 13 | const s = ' MARCUS AURELIUS '; 14 | console.log(s); 15 | console.log(`lower('${s}') = '${lower(s)}'`); 16 | console.log(`upperCapital('${s}') = '${upperCapital(s)}'`); 17 | 18 | { 19 | console.log('Use compose'); 20 | const capitalize = compose(upperCapital, lower, trim); 21 | console.log(`capitalize('${s}') = '${capitalize(s)}'`); 22 | } 23 | { 24 | console.log('Use pipe'); 25 | const capitalize = pipe(trim, lower, upperCapital); 26 | console.log(`capitalize('${s}') = '${capitalize(s)}'`); 27 | } 28 | -------------------------------------------------------------------------------- /Exercises.ru.md: -------------------------------------------------------------------------------- 1 | # Композиция 2 | 3 | 1. Напишите функцию `pipe`, композирующую передаваемые в нее аргументы слева 4 | направо. `const pipe = (...fns) => x => ...` А если хоть один из аргументов 5 | окажется не функционального типа, то `pipe` должен выбросить ошибку. 6 | Например, если у нас есть три функции: 7 | ```js 8 | const inc = x => ++x; 9 | const twice = x => x * 2; 10 | const cube = x => x ** 3; 11 | ``` 12 | И нам нужно скомпозировать их так `const f = pipe(inc, twice, cube);` 13 | то при вызове `const x = f(5);` нужно ожидать, что `x` примет значение `1728`. 14 | А если мы скомпозируем `const f = pipe(inc, inc);` то при вызове 15 | `const x = f(7);` значение `x` будет `9`. Но если мы передадим не функцию в 16 | `pipe`, например: `const f = pipe(inc, 7, cube);` то, не дожидаясь вызова `f`, 17 | сразу получим ошибку. 18 | 19 | 2. Реализуйте композицию функций справа налево (без использования рекурсии), 20 | которая будет подавлять ошибки, если композируемые функции будут их бросать, 21 | то, исполнение функции завершается с `undefined`, а на ошибки можно будет 22 | подписаться через `f.on('error', e => { ... });`. 23 | -------------------------------------------------------------------------------- /JavaScript/6-recursive.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const compose = (...fns) => (x) => { 4 | if (fns.length === 0) return x; 5 | const fn = fns.pop(); 6 | const res = fn(x); 7 | return compose(...fns)(res); 8 | }; 9 | 10 | const pipe = (...fns) => (x) => { 11 | if (fns.length === 0) return x; 12 | const fn = fns.shift(); 13 | const res = fn(x); 14 | return pipe(...fns)(res); 15 | }; 16 | 17 | // Usage 18 | 19 | const upperFirst = (word) => word.charAt(0).toUpperCase() + word.slice(1); 20 | const upperCapital = (s) => s.split(' ').map(upperFirst).join(' '); 21 | const lower = (s) => s.toLowerCase(); 22 | const trim = (s) => s.trim(); 23 | 24 | const s = ' MARCUS AURELIUS '; 25 | console.log(s); 26 | console.log(`lower('${s}') = '${lower(s)}'`); 27 | console.log(`upperCapital('${s}') = '${upperCapital(s)}'`); 28 | 29 | { 30 | console.log('Use compose'); 31 | const capitalize = compose(upperCapital, lower, trim); 32 | console.log(`capitalize('${s}') = '${capitalize(s)}'`); 33 | } 34 | { 35 | console.log('Use pipe'); 36 | const capitalize = pipe(trim, lower, upperCapital); 37 | console.log(`capitalize('${s}') = '${capitalize(s)}'`); 38 | } 39 | -------------------------------------------------------------------------------- /JavaScript/5-loop.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const compose = (...fns) => (x) => { 4 | const last = fns.length - 1; 5 | let res = x; 6 | for (let i = last; i >= 0; i--) { 7 | res = fns[i](res); 8 | } 9 | return res; 10 | }; 11 | 12 | const pipe = (...fns) => (x) => { 13 | let res = x; 14 | for (let i = 0; i < fns.length; i++) { 15 | res = fns[i](res); 16 | } 17 | return res; 18 | }; 19 | 20 | // Usage 21 | 22 | const upperFirst = (word) => word.charAt(0).toUpperCase() + word.slice(1); 23 | const upperCapital = (s) => s.split(' ').map(upperFirst).join(' '); 24 | const lower = (s) => s.toLowerCase(); 25 | const trim = (s) => s.trim(); 26 | 27 | const s = ' MARCUS AURELIUS '; 28 | console.log(s); 29 | console.log(`lower('${s}') = '${lower(s)}'`); 30 | console.log(`upperCapital('${s}') = '${upperCapital(s)}'`); 31 | 32 | { 33 | console.log('Use compose'); 34 | const capitalize = compose(upperCapital, lower, trim); 35 | console.log(`capitalize('${s}') = '${capitalize(s)}'`); 36 | } 37 | { 38 | console.log('Use pipe'); 39 | const capitalize = pipe(trim, lower, upperCapital); 40 | console.log(`capitalize('${s}') = '${capitalize(s)}'`); 41 | } 42 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017-2024 How.Programming.Works contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Exercises/2-compose.test: -------------------------------------------------------------------------------- 1 | ({ 2 | name: 'compose', 3 | length: [300, 600], 4 | test: compose => { 5 | const inc = x => ++x; 6 | const twice = x => x * 2; 7 | const cube = x => x ** 3; 8 | const fail = x => { 9 | throw new Error(`Function fail(${x})`); 10 | }; 11 | { 12 | const f = compose(inc, twice, cube); 13 | f.on('error', error => { 14 | throw new Error('Unexpected error'); 15 | }); 16 | let x; 17 | try { 18 | x = f(5); 19 | } catch (error) { 20 | throw new Error(`Unexpected throw`); 21 | } 22 | if (x !== 251) { 23 | throw new Error(`Expected 251 instead of ${x}`); 24 | } 25 | } 26 | { 27 | let errorDetected = false; 28 | const f = compose(inc, twice, fail, cube); 29 | f.on('error', error => { 30 | errorDetected = true; 31 | }); 32 | let x; 33 | try { 34 | x = f(5); 35 | } catch (error) { 36 | throw new Error(`Unexpected throw`); 37 | } 38 | if (!errorDetected) { 39 | throw new Error(`Expected error event is not received`); 40 | } 41 | if (x !== undefined) { 42 | throw new Error(`Expected undefined instead of ${x}`); 43 | } 44 | } 45 | } 46 | }) 47 | -------------------------------------------------------------------------------- /JavaScript/7-compose-async.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const fs = require('node:fs'); 4 | 5 | const reduceAsync = (items, performer, done, initialValue) => { 6 | const nseted = initialValue === undefined; 7 | let counter = nseted ? 1 : 0; 8 | let previous = nseted ? items[0] : initialValue; 9 | let current = nseted ? items[1] : items[0]; 10 | 11 | const response = (err, data) => { 12 | if (!err && counter !== items.length - 1) { 13 | counter++; 14 | previous = data; 15 | current = items[counter]; 16 | performer(previous, current, response, counter, items); 17 | } else if (done) { 18 | done(err, data); 19 | } 20 | }; 21 | 22 | performer(previous, current, response, counter, items); 23 | }; 24 | 25 | const last = (arr) => arr[arr.length - 1]; 26 | 27 | // funcs - array of parametrs for functions 28 | // args - array of functions 29 | // args[i] - function 30 | // args[-1] - done(err, data) 31 | // 32 | const composeAsync = (funcs, ...args) => ( 33 | () => reduceAsync( 34 | args.slice(0, -1), 35 | (params, fn, done) => fn(...[].concat(params).concat(done)), 36 | last(args), 37 | funcs 38 | ) 39 | ); 40 | 41 | // Usage 42 | 43 | const randomize = (max) => Math.floor((Math.random() * max)); 44 | 45 | const wrapAsync = (callback) => setTimeout(callback, randomize(1000)); 46 | 47 | const read = (file, charset, callback) => { 48 | console.dir({ read: { file, callback } }); 49 | fs.readFile(file, charset, callback); 50 | }; 51 | 52 | const parse = (data, callback) => { 53 | console.dir({ parse: { data, callback } }); 54 | wrapAsync(() => { 55 | callback(null, ['Data has been', 'processed!']); 56 | }); 57 | }; 58 | 59 | const preprocess = (data1, data2, callback) => { 60 | console.dir({ preprocess: { data1, data2, callback } }); 61 | wrapAsync(() => { 62 | callback(null, data1 + ' ' + data2); 63 | }); 64 | }; 65 | 66 | const cf1 = composeAsync( 67 | ['config.txt', 'utf8'], 68 | read, 69 | parse, 70 | preprocess, 71 | (err, data) => { 72 | if (!err) console.log(data); 73 | } 74 | ); 75 | 76 | cf1(); 77 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "es6": true, 5 | "node": true 6 | }, 7 | "extends": "eslint:recommended", 8 | "parserOptions": { 9 | "ecmaVersion": "latest" 10 | }, 11 | "globals": { 12 | "BigInt": true 13 | }, 14 | "rules": { 15 | "indent": [ 16 | "error", 17 | 2 18 | ], 19 | "linebreak-style": [ 20 | "error", 21 | "unix" 22 | ], 23 | "quotes": [ 24 | "error", 25 | "single" 26 | ], 27 | "semi": [ 28 | "error", 29 | "always" 30 | ], 31 | "no-loop-func": [ 32 | "error" 33 | ], 34 | "block-spacing": [ 35 | "error", 36 | "always" 37 | ], 38 | "camelcase": [ 39 | "error" 40 | ], 41 | "eqeqeq": [ 42 | "error", 43 | "always" 44 | ], 45 | "strict": [ 46 | "error", 47 | "global" 48 | ], 49 | "brace-style": [ 50 | "error", 51 | "1tbs", 52 | { 53 | "allowSingleLine": true 54 | } 55 | ], 56 | "comma-style": [ 57 | "error", 58 | "last" 59 | ], 60 | "comma-spacing": [ 61 | "error", 62 | { 63 | "before": false, 64 | "after": true 65 | } 66 | ], 67 | "eol-last": [ 68 | "error" 69 | ], 70 | "func-call-spacing": [ 71 | "error", 72 | "never" 73 | ], 74 | "key-spacing": [ 75 | "error", 76 | { 77 | "beforeColon": false, 78 | "afterColon": true, 79 | "mode": "minimum" 80 | } 81 | ], 82 | "keyword-spacing": [ 83 | "error", 84 | { 85 | "before": true, 86 | "after": true, 87 | "overrides": { 88 | "function": { 89 | "after": false 90 | } 91 | } 92 | } 93 | ], 94 | "max-len": [ 95 | "error", 96 | { 97 | "code": 80, 98 | "ignoreUrls": true 99 | } 100 | ], 101 | "max-nested-callbacks": [ 102 | "error", 103 | { 104 | "max": 7 105 | } 106 | ], 107 | "new-cap": [ 108 | "error", 109 | { 110 | "newIsCap": true, 111 | "capIsNew": false, 112 | "properties": true 113 | } 114 | ], 115 | "new-parens": [ 116 | "error" 117 | ], 118 | "no-lonely-if": [ 119 | "error" 120 | ], 121 | "no-trailing-spaces": [ 122 | "error" 123 | ], 124 | "no-unneeded-ternary": [ 125 | "error" 126 | ], 127 | "no-whitespace-before-property": [ 128 | "error" 129 | ], 130 | "object-curly-spacing": [ 131 | "error", 132 | "always" 133 | ], 134 | "operator-assignment": [ 135 | "error", 136 | "always" 137 | ], 138 | "operator-linebreak": [ 139 | "error", 140 | "after" 141 | ], 142 | "semi-spacing": [ 143 | "error", 144 | { 145 | "before": false, 146 | "after": true 147 | } 148 | ], 149 | "space-before-blocks": [ 150 | "error", 151 | "always" 152 | ], 153 | "space-before-function-paren": [ 154 | "error", 155 | { 156 | "anonymous": "never", 157 | "named": "never", 158 | "asyncArrow": "always" 159 | } 160 | ], 161 | "space-in-parens": [ 162 | "error", 163 | "never" 164 | ], 165 | "space-infix-ops": [ 166 | "error" 167 | ], 168 | "space-unary-ops": [ 169 | "error", 170 | { 171 | "words": true, 172 | "nonwords": false, 173 | "overrides": { 174 | "typeof": false 175 | } 176 | } 177 | ], 178 | "no-unreachable": [ 179 | "error" 180 | ], 181 | "no-global-assign": [ 182 | "error" 183 | ], 184 | "no-self-compare": [ 185 | "error" 186 | ], 187 | "no-unmodified-loop-condition": [ 188 | "error" 189 | ], 190 | "no-constant-condition": [ 191 | "error", 192 | { 193 | "checkLoops": false 194 | } 195 | ], 196 | "no-console": [ 197 | "off" 198 | ], 199 | "no-useless-concat": [ 200 | "error" 201 | ], 202 | "no-useless-escape": [ 203 | "error" 204 | ], 205 | "no-shadow-restricted-names": [ 206 | "error" 207 | ], 208 | "no-use-before-define": [ 209 | "error", 210 | { 211 | "functions": false 212 | } 213 | ], 214 | "arrow-parens": [ 215 | "error", 216 | "always" 217 | ], 218 | "arrow-body-style": [ 219 | "error", 220 | "as-needed" 221 | ], 222 | "arrow-spacing": [ 223 | "error" 224 | ], 225 | "no-confusing-arrow": [ 226 | "error", 227 | { 228 | "allowParens": true 229 | } 230 | ], 231 | "no-useless-computed-key": [ 232 | "error" 233 | ], 234 | "no-useless-rename": [ 235 | "error" 236 | ], 237 | "no-var": [ 238 | "error" 239 | ], 240 | "object-shorthand": [ 241 | "error", 242 | "always" 243 | ], 244 | "prefer-arrow-callback": [ 245 | "error" 246 | ], 247 | "prefer-const": [ 248 | "error" 249 | ], 250 | "prefer-numeric-literals": [ 251 | "error" 252 | ], 253 | "prefer-rest-params": [ 254 | "error" 255 | ], 256 | "prefer-spread": [ 257 | "error" 258 | ], 259 | "rest-spread-spacing": [ 260 | "error", 261 | "never" 262 | ], 263 | "template-curly-spacing": [ 264 | "error", 265 | "never" 266 | ], 267 | "consistent-return": [ 268 | "error", 269 | { "treatUndefinedAsUnspecified": true } 270 | ] 271 | } 272 | } 273 | --------------------------------------------------------------------------------