├── .babelrc
├── .eslintignore
├── .eslintrc
├── .gitignore
├── README.md
├── architecture
├── build
│ ├── css
│ │ ├── .babelrc
│ │ ├── build
│ │ │ └── bundle.js
│ │ ├── index.html
│ │ ├── package-lock.json
│ │ ├── package.json
│ │ ├── src
│ │ │ ├── App.css
│ │ │ ├── App.js
│ │ │ ├── App.test.js
│ │ │ ├── components
│ │ │ │ ├── Copyright
│ │ │ │ │ ├── Copyright.css
│ │ │ │ │ ├── Copyright.js
│ │ │ │ │ └── Copyright.spec.js
│ │ │ │ └── IdeaButton
│ │ │ │ │ ├── IdeaButton.css
│ │ │ │ │ ├── IdeaButton.js
│ │ │ │ │ ├── IdeaButton.spec.js
│ │ │ │ │ ├── idea.png
│ │ │ │ │ └── idea.svg
│ │ │ ├── index.css
│ │ │ └── index.js
│ │ └── webpack.config.js
│ ├── img
│ │ ├── .babelrc
│ │ ├── build
│ │ │ ├── 6db3758bfc59f23bf4410c22857462c4.svg
│ │ │ └── bundle.js
│ │ ├── index.html
│ │ ├── package-lock.json
│ │ ├── package.json
│ │ ├── src
│ │ │ ├── App.css
│ │ │ ├── App.js
│ │ │ ├── App.test.js
│ │ │ ├── components
│ │ │ │ ├── Copyright
│ │ │ │ │ ├── Copyright.css
│ │ │ │ │ ├── Copyright.js
│ │ │ │ │ └── Copyright.spec.js
│ │ │ │ └── IdeaButton
│ │ │ │ │ ├── IdeaButton.css
│ │ │ │ │ ├── IdeaButton.js
│ │ │ │ │ ├── IdeaButton.spec.js
│ │ │ │ │ ├── idea.png
│ │ │ │ │ └── idea.svg
│ │ │ ├── index.css
│ │ │ └── index.js
│ │ └── webpack.config.js
│ ├── initial
│ │ ├── .babelrc
│ │ ├── build
│ │ │ └── bundle.js
│ │ ├── index.html
│ │ ├── package-lock.json
│ │ ├── package.json
│ │ └── src
│ │ │ ├── App.css
│ │ │ ├── App.js
│ │ │ ├── App.test.js
│ │ │ ├── components
│ │ │ ├── Copyright
│ │ │ │ ├── Copyright.css
│ │ │ │ ├── Copyright.js
│ │ │ │ └── Copyright.spec.js
│ │ │ └── IdeaButton
│ │ │ │ ├── IdeaButton.css
│ │ │ │ ├── IdeaButton.js
│ │ │ │ ├── IdeaButton.spec.js
│ │ │ │ ├── idea.png
│ │ │ │ └── idea.svg
│ │ │ ├── index.css
│ │ │ └── index.js
│ └── webpack
│ │ ├── .babelrc
│ │ ├── build
│ │ └── bundle.js
│ │ ├── index.html
│ │ ├── package-lock.json
│ │ ├── package.json
│ │ ├── src
│ │ ├── App.css
│ │ ├── App.js
│ │ ├── App.test.js
│ │ ├── components
│ │ │ ├── Copyright
│ │ │ │ ├── Copyright.css
│ │ │ │ ├── Copyright.js
│ │ │ │ └── Copyright.spec.js
│ │ │ └── IdeaButton
│ │ │ │ ├── IdeaButton.css
│ │ │ │ ├── IdeaButton.js
│ │ │ │ ├── IdeaButton.spec.js
│ │ │ │ ├── idea.png
│ │ │ │ └── idea.svg
│ │ ├── index.css
│ │ └── index.js
│ │ └── webpack.config.js
├── component
│ └── simplifying-js-component
│ │ ├── .gitignore
│ │ ├── README.md
│ │ ├── package-lock.json
│ │ ├── package.json
│ │ ├── public
│ │ ├── favicon.ico
│ │ ├── index.html
│ │ └── manifest.json
│ │ └── src
│ │ ├── App.css
│ │ ├── App.js
│ │ ├── App.test.js
│ │ ├── components
│ │ ├── Copyright
│ │ │ ├── Copyright.css
│ │ │ ├── Copyright.js
│ │ │ └── Copyright.spec.js
│ │ └── IdeaButton
│ │ │ ├── IdeaButton.css
│ │ │ ├── IdeaButton.js
│ │ │ ├── IdeaButton.spec.js
│ │ │ └── idea.svg
│ │ ├── index.css
│ │ └── index.js
├── css
│ ├── animate
│ │ ├── index.html
│ │ ├── main.css
│ │ └── open.js
│ ├── index.html
│ ├── initial
│ │ ├── index-truncated.html
│ │ ├── index.html
│ │ └── main.css
│ └── middle
│ │ ├── index.html
│ │ ├── main.css
│ │ └── open.js
├── import
│ ├── class
│ │ └── address.js
│ ├── default
│ │ ├── address.js
│ │ ├── list.js
│ │ ├── list.spec.js
│ │ └── mail.js
│ ├── each
│ │ ├── bill.js
│ │ ├── bill.spec.js
│ │ ├── name.js
│ │ ├── name.spec.js
│ │ ├── util.js
│ │ └── util.spec.js
│ └── single
│ │ ├── area.js
│ │ ├── bill.js
│ │ ├── bill.spec.js
│ │ ├── math.js
│ │ ├── name.js
│ │ ├── name.spec.js
│ │ └── util.js
└── npm
│ ├── defaults
│ └── package.json
│ ├── save
│ └── package.json
│ ├── saveDev
│ └── package.json
│ ├── script
│ ├── code
│ │ └── merge.js
│ └── package.json
│ └── utils
│ ├── clone.js
│ ├── merge.js
│ └── merge.spec.js
├── arrays
├── arrays
│ ├── arrays.js
│ └── arrays.spec.js
├── includes
│ ├── greater.js
│ ├── includes.js
│ ├── includes.spec.js
│ └── problem.js
├── push
│ ├── push.js
│ └── push.spec.js
├── sort
│ ├── sort.js
│ ├── sort.spec.js
│ ├── sortMutate.js
│ └── sortSpread.js
└── spread
│ ├── problem.js
│ ├── slice.js
│ ├── splice.js
│ ├── spread.js
│ └── spread.spec.js
├── classes
├── bind
│ ├── bind.js
│ ├── bind.spec.js
│ ├── constructor.js
│ ├── constructorArrow.js
│ ├── problem.js
│ └── properties.js
├── constructor
├── extend
│ ├── basic.js
│ ├── constructor.js
│ ├── extend.js
│ ├── extend.spec.js
│ ├── flash.js
│ └── method.js
├── generators
│ ├── generators.js
│ ├── generators.spec.js
│ ├── problem.js
│ └── simple.js
├── get
│ ├── get.js
│ ├── get.spec.js
│ ├── invalid.js
│ ├── price.js
│ ├── problem.js
│ └── set.js
└── prototypes
│ ├── class.js
│ ├── prototypes.js
│ └── prototypes.spec.js
├── collections
├── assign
│ ├── assign.js
│ ├── assign.spec.js
│ ├── mutate.js
│ └── problem.js
├── map
│ ├── map.js
│ ├── map.spec.js
│ └── problem.js
├── mapSideEffects
│ ├── copy.js
│ ├── map.js
│ ├── map.spec.js
│ └── sideEffects.js
├── mapSpread
│ ├── iterate.js
│ ├── mapSpread.js
│ ├── mapSpread.spec.js
│ └── object.js
├── object
│ └── object.js
├── objectSpread
│ ├── objectSpread.js
│ └── objectSpread.spec.js
└── set
│ ├── set.js
│ ├── set.spec.js
│ ├── unique.js
│ └── unique.spec.js
├── conditionals
├── falsy
│ ├── falsy.js
│ ├── falsy.spec.js
│ └── notFalsy.js
├── shortCircuiting
│ ├── conditional.js
│ ├── shortCircuiting.js
│ ├── shortCircuiting.spec.js
│ └── ternary.js
└── ternary
│ ├── if.js
│ ├── ternary.js
│ ├── ternary.spec.js
│ └── ternaryProblem.js
├── externalData
├── async
│ ├── async.js
│ ├── async.spec.js
│ └── catch.js
├── fetch
│ ├── example.js
│ ├── fetch.js
│ ├── fetch.spec.js
│ ├── posts.js
│ └── services
│ │ └── postService.js
├── local
│ ├── local.js
│ └── local.spec.js
└── promises
│ ├── problem.js
│ ├── promises.js
│ └── promises.spec.js
├── functions
├── arrow
│ ├── arrow.js
│ ├── arrow.spec.js
│ ├── close.js
│ └── problem.js
├── context
│ ├── basic.js
│ ├── context.js
│ ├── context.spec.js
│ ├── method.js
│ └── problem.js
├── curry
│ ├── curry.js
│ ├── curry.spec.js
│ ├── curry.spec2.js
│ ├── highorder.js
│ └── problem.js
├── oldTest
│ ├── problem.js
│ ├── problem.spec.js
│ ├── routing.js
│ ├── taxService.js
│ ├── test.js
│ └── test.spec.js
├── partial
│ ├── partial.js
│ ├── partial.spec.js
│ ├── problem.js
│ └── program.js
└── test
│ ├── problem.js
│ ├── problem.spec.js
│ ├── routing.js
│ ├── taxService.js
│ ├── test.js
│ └── test.spec.js
├── loops
├── arrow
│ ├── anonymous.js
│ ├── arrow.js
│ ├── arrow.spec.js
│ └── full.js
├── chain
│ ├── chain.js
│ ├── chain.spec.js
│ └── full.js
├── filter
│ ├── filter.js
│ ├── filter.spec.js
│ └── full.js
├── for
│ ├── for.js
│ ├── for.spec.js
│ ├── forin.js
│ ├── full.js
│ └── traditional.js
├── forEach
│ ├── forEach.js
│ ├── forEach.spec.js
│ └── full.js
├── map
│ ├── full.js
│ ├── map.js
│ └── map.spec.js
├── methods
│ ├── methods.js
│ ├── methods.spec.js
│ └── problem.js
└── reduce
│ ├── map.js
│ ├── mistake.js
│ ├── reduce.js
│ └── reduce.spec.js
├── package-lock.json
├── package.json
├── params
├── assignment
│ ├── assignment.js
│ └── assignment.spec.js
├── defaults
│ ├── default.js
│ ├── default.spec.js
│ ├── more.js
│ ├── problem.js
│ └── simple.js
├── destructuring
│ ├── alternate.js
│ ├── destructuring.js
│ ├── destructuring.spec.js
│ └── problem.js
└── rest
│ ├── problem.js
│ ├── rest.js
│ ├── rest.spec.js
│ └── simple.js
├── test
└── mocha.opts
└── variables
├── const
├── const.js
└── const.spec.js
├── let
├── const.js
├── declaration.js
├── let.js
├── let.spec.js
└── problem.js
├── literals
├── literals.js
├── literals.spec.js
└── problem.js
└── scope
├── curry.js
├── problem.js
├── scope.html
├── scope.js
└── scope.spec.js
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["env"],
3 | "plugins": ["transform-async-to-generator", "transform-object-rest-spread", "transform-class-properties"],
4 | }
5 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | functions/arrow/close.js
2 | architecture/build/css/node_modules
3 | architecture/build/css/build
4 | architecture/build/img/node_modules
5 | architecture/build/img/build
6 | architecture/build/initial/node_modules
7 | architecture/build/initial/build
8 | architecture/build/webpack/node_modules
9 | architecture/build/webpack/build
10 | architecture/component/simplifying-js-component/node_modules
11 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "browser": true
4 | },
5 | "parser": "babel-eslint",
6 | "extends": "airbnb",
7 | "globals": {
8 | "document": true,
9 | "afterEach": true,
10 | "beforeEach": true,
11 | "jest": true,
12 | "it": true,
13 | "describe": true,
14 | "expect": true,
15 | "fetch": true,
16 | "google": true
17 | },
18 | "rules": {
19 | "arrow-parens": ["error", "as-needed"],
20 | "arrow-body-style": 0,
21 | "class-methods-use-this": 0,
22 | "import/extensions": 0,
23 | "import/no-unresolved": 0,
24 | "import/prefer-default-export": 0,
25 | "linebreak-style": 0,
26 | "no-plusplus": 0,
27 | "no-shadow": 0,
28 | "no-restricted-syntax": 0,
29 | "no-underscore-dangle": 0,
30 | "no-unused-expressions": 0,
31 | "react/jsx-filename-extension": 0,
32 | "react/prop-types": 0,
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Simplifying JavaScript Code
2 |
3 | ## Tests
4 | - `npm install`
5 | - `npm test`
6 |
7 | If you want to edit code while running tests:
8 | - `npm run test:watch`
9 |
--------------------------------------------------------------------------------
/architecture/build/css/.babelrc:
--------------------------------------------------------------------------------
1 | { "presets": ["env", "react"] }
2 |
--------------------------------------------------------------------------------
/architecture/build/css/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Sample
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/architecture/build/css/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "initial",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "build": "webpack"
8 | },
9 | "keywords": [],
10 | "author": "",
11 | "license": "ISC",
12 | "devDependencies": {
13 | "babel-cli": "^6.26.0",
14 | "babel-loader": "^7.1.2",
15 | "babel-preset-env": "^1.6.1",
16 | "babel-preset-react": "^6.24.1",
17 | "css-loader": "^0.28.7",
18 | "style-loader": "^0.19.0",
19 | "webpack": "^3.8.1"
20 | },
21 | "dependencies": {
22 | "react": "^16.1.1",
23 | "react-dom": "^16.1.1"
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/architecture/build/css/src/App.css:
--------------------------------------------------------------------------------
1 | .main {
2 | width: 100%;
3 | }
4 |
5 | .app {
6 | padding: 1em;
7 | }
8 |
9 | footer {
10 | margin: 2em 0 0 0;
11 | padding: 1em;
12 | width: 100%;
13 | height: 3em;
14 | border-top: black solid 1px;
15 | }
16 |
--------------------------------------------------------------------------------
/architecture/build/css/src/App.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import './App.css';
4 | import Copyright from './components/Copyright/Copyright';
5 |
6 | export default function App() {
7 | return (
8 |
14 | );
15 | }
16 |
17 |
--------------------------------------------------------------------------------
/architecture/build/css/src/App.test.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jsmapr1/simplifying-js/a7ced4922664a4ea0d2b584963fd4d7aeebd7321/architecture/build/css/src/App.test.js
--------------------------------------------------------------------------------
/architecture/build/css/src/components/Copyright/Copyright.css:
--------------------------------------------------------------------------------
1 | .copyright {
2 | font-size: 10px;
3 | margin: 1em;
4 | margin-left: 0;
5 | float: left;
6 | }
7 |
--------------------------------------------------------------------------------
/architecture/build/css/src/components/Copyright/Copyright.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import './Copyright.css';
3 |
4 | export default function CopyrightStatement() {
5 | const year = new Date().getFullYear();
6 | return (
7 |
8 | Copyright {year}
9 |
10 | );
11 | }
12 |
--------------------------------------------------------------------------------
/architecture/build/css/src/components/Copyright/Copyright.spec.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jsmapr1/simplifying-js/a7ced4922664a4ea0d2b584963fd4d7aeebd7321/architecture/build/css/src/components/Copyright/Copyright.spec.js
--------------------------------------------------------------------------------
/architecture/build/css/src/components/IdeaButton/IdeaButton.css:
--------------------------------------------------------------------------------
1 | .idea-button {
2 | background: #ffffff;
3 | border: black solid 1px;
4 | border-radius: 3px;
5 | width: 200px;
6 | font-size: 16px;
7 | line-height: 40px;
8 | }
9 |
10 | .idea-button:hover {
11 | cursor: pointer;
12 | }
13 |
14 | .idea-button__icon {
15 | width: 40px;
16 | height: 40px;
17 | float: left;
18 | }
19 |
--------------------------------------------------------------------------------
/architecture/build/css/src/components/IdeaButton/IdeaButton.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import './IdeaButton.css';
3 | import idea from './idea.svg';
4 |
5 | export default function IdeaButton({ handleClick, message }) {
6 | return (
7 |
18 | );
19 | }
20 |
--------------------------------------------------------------------------------
/architecture/build/css/src/components/IdeaButton/IdeaButton.spec.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jsmapr1/simplifying-js/a7ced4922664a4ea0d2b584963fd4d7aeebd7321/architecture/build/css/src/components/IdeaButton/IdeaButton.spec.js
--------------------------------------------------------------------------------
/architecture/build/css/src/components/IdeaButton/idea.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jsmapr1/simplifying-js/a7ced4922664a4ea0d2b584963fd4d7aeebd7321/architecture/build/css/src/components/IdeaButton/idea.png
--------------------------------------------------------------------------------
/architecture/build/css/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: sans-serif;
5 | }
6 |
--------------------------------------------------------------------------------
/architecture/build/css/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import App from './App';
4 |
5 | ReactDOM.render(, document.getElementById('root'));
6 |
--------------------------------------------------------------------------------
/architecture/build/css/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 |
3 | module.exports = {
4 | entry: './src/index.js',
5 | // START:loader
6 | module: {
7 | loaders: [
8 | {
9 | test: /\.css$/,
10 | use: [
11 | 'style-loader',
12 | 'css-loader',
13 | ],
14 | },
15 | {
16 | test: /\.js?/,
17 | use: 'babel-loader',
18 | },
19 | ],
20 | },
21 | // END:loader
22 | output: {
23 | filename: 'build/bundle.js',
24 | path: path.resolve(__dirname),
25 | },
26 | };
27 |
--------------------------------------------------------------------------------
/architecture/build/img/.babelrc:
--------------------------------------------------------------------------------
1 | { "presets": ["env", "react"] }
2 |
--------------------------------------------------------------------------------
/architecture/build/img/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Sample
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/architecture/build/img/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "initial",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "build": "webpack"
8 | },
9 | "keywords": [],
10 | "author": "",
11 | "license": "ISC",
12 | "devDependencies": {
13 | "babel-cli": "^6.26.0",
14 | "babel-loader": "^7.1.2",
15 | "babel-preset-env": "^1.6.1",
16 | "babel-preset-react": "^6.24.1",
17 | "css-loader": "^0.28.7",
18 | "file-loader": "^1.1.5",
19 | "style-loader": "^0.19.0",
20 | "webpack": "^3.8.1"
21 | },
22 | "dependencies": {
23 | "react": "^16.1.1",
24 | "react-dom": "^16.1.1"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/architecture/build/img/src/App.css:
--------------------------------------------------------------------------------
1 | .main {
2 | width: 100%;
3 | }
4 |
5 | .app {
6 | padding: 1em;
7 | }
8 |
9 | footer {
10 | margin: 2em 0 0 0;
11 | padding: 1em;
12 | width: 100%;
13 | height: 3em;
14 | border-top: black solid 1px;
15 | }
16 |
--------------------------------------------------------------------------------
/architecture/build/img/src/App.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import './App.css';
4 | import IdeaButton from './components/IdeaButton/IdeaButton';
5 | import Copyright from './components/Copyright/Copyright';
6 |
7 | function logIdea() {
8 | console.log('Someone had an idea!');
9 | }
10 |
11 | export default function App() {
12 | return (
13 |
28 | );
29 | }
30 |
31 |
--------------------------------------------------------------------------------
/architecture/build/img/src/App.test.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jsmapr1/simplifying-js/a7ced4922664a4ea0d2b584963fd4d7aeebd7321/architecture/build/img/src/App.test.js
--------------------------------------------------------------------------------
/architecture/build/img/src/components/Copyright/Copyright.css:
--------------------------------------------------------------------------------
1 | .copyright {
2 | font-size: 10px;
3 | margin: 1em;
4 | margin-left: 0;
5 | float: left;
6 | }
7 |
--------------------------------------------------------------------------------
/architecture/build/img/src/components/Copyright/Copyright.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import './Copyright.css';
3 |
4 | export default function CopyrightStatement() {
5 | const year = new Date().getFullYear();
6 | return (
7 |
8 | Copyright {year}
9 |
10 | );
11 | }
12 |
--------------------------------------------------------------------------------
/architecture/build/img/src/components/Copyright/Copyright.spec.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jsmapr1/simplifying-js/a7ced4922664a4ea0d2b584963fd4d7aeebd7321/architecture/build/img/src/components/Copyright/Copyright.spec.js
--------------------------------------------------------------------------------
/architecture/build/img/src/components/IdeaButton/IdeaButton.css:
--------------------------------------------------------------------------------
1 | .idea-button {
2 | background: #ffffff;
3 | border: black solid 1px;
4 | border-radius: 3px;
5 | width: 200px;
6 | font-size: 16px;
7 | line-height: 40px;
8 | }
9 |
10 | .idea-button:hover {
11 | cursor: pointer;
12 | }
13 |
14 | .idea-button__icon {
15 | width: 40px;
16 | height: 40px;
17 | float: left;
18 | }
19 |
--------------------------------------------------------------------------------
/architecture/build/img/src/components/IdeaButton/IdeaButton.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import './IdeaButton.css';
3 | import idea from './idea.svg';
4 |
5 | export default function IdeaButton({ handleClick, message }) {
6 | return (
7 |
18 | );
19 | }
20 |
--------------------------------------------------------------------------------
/architecture/build/img/src/components/IdeaButton/IdeaButton.spec.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jsmapr1/simplifying-js/a7ced4922664a4ea0d2b584963fd4d7aeebd7321/architecture/build/img/src/components/IdeaButton/IdeaButton.spec.js
--------------------------------------------------------------------------------
/architecture/build/img/src/components/IdeaButton/idea.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jsmapr1/simplifying-js/a7ced4922664a4ea0d2b584963fd4d7aeebd7321/architecture/build/img/src/components/IdeaButton/idea.png
--------------------------------------------------------------------------------
/architecture/build/img/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: sans-serif;
5 | }
6 |
--------------------------------------------------------------------------------
/architecture/build/img/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import App from './App';
4 |
5 | ReactDOM.render(, document.getElementById('root'));
6 |
--------------------------------------------------------------------------------
/architecture/build/img/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 |
3 | module.exports = {
4 | entry: './src/index.js',
5 | // START:loader
6 | module: {
7 | loaders: [
8 | {
9 | test: /\.svg?/,
10 | use: [
11 | {
12 | loader: 'file-loader',
13 | options: {
14 | outputPath: 'build/',
15 | },
16 | },
17 | ],
18 | },
19 | {
20 | test: /\.css$/,
21 | use: [
22 | 'style-loader',
23 | 'css-loader',
24 | ],
25 | },
26 | {
27 | test: /\.js?/,
28 | use: 'babel-loader',
29 | },
30 | ],
31 | },
32 | // END:loader
33 | output: {
34 | filename: 'build/bundle.js',
35 | path: path.resolve(__dirname),
36 | },
37 | };
38 |
--------------------------------------------------------------------------------
/architecture/build/initial/.babelrc:
--------------------------------------------------------------------------------
1 | { "presets": ["env", "react"] }
2 |
--------------------------------------------------------------------------------
/architecture/build/initial/build/bundle.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var _react = require('react');
4 |
5 | var _react2 = _interopRequireDefault(_react);
6 |
7 | var _reactDom = require('react-dom');
8 |
9 | var _reactDom2 = _interopRequireDefault(_reactDom);
10 |
11 | var _App = require('./App');
12 |
13 | var _App2 = _interopRequireDefault(_App);
14 |
15 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
16 |
17 | _reactDom2.default.render(_react2.default.createElement(_App2.default, null), document.getElementById('root'));
18 |
--------------------------------------------------------------------------------
/architecture/build/initial/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Sample
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/architecture/build/initial/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "initial",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "build": "babel src/index.js -o build/bundle.js"
8 | },
9 | "keywords": [],
10 | "author": "",
11 | "license": "ISC",
12 | "devDependencies": {
13 | "babel-cli": "^6.26.0",
14 | "babel-preset-env": "^1.6.1",
15 | "babel-preset-react": "^6.24.1"
16 | },
17 | "dependencies": {
18 | "react": "^16.1.1",
19 | "react-dom": "^16.1.1"
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/architecture/build/initial/src/App.css:
--------------------------------------------------------------------------------
1 | .main {
2 | width: 100%;
3 | }
4 |
5 | .app {
6 | padding: 1em;
7 | }
8 |
9 | footer {
10 | margin: 2em 0 0 0;
11 | padding: 1em;
12 | width: 100%;
13 | height: 3em;
14 | border-top: black solid 1px;
15 | }
16 |
--------------------------------------------------------------------------------
/architecture/build/initial/src/App.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import Copyright from './components/Copyright/Copyright';
4 |
5 | export default function App() {
6 | return (
7 |
8 |
11 |
12 | );
13 | }
14 |
15 |
--------------------------------------------------------------------------------
/architecture/build/initial/src/App.test.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jsmapr1/simplifying-js/a7ced4922664a4ea0d2b584963fd4d7aeebd7321/architecture/build/initial/src/App.test.js
--------------------------------------------------------------------------------
/architecture/build/initial/src/components/Copyright/Copyright.css:
--------------------------------------------------------------------------------
1 | .copyright {
2 | font-size: 10px;
3 | margin: 1em;
4 | margin-left: 0;
5 | float: left;
6 | }
7 |
--------------------------------------------------------------------------------
/architecture/build/initial/src/components/Copyright/Copyright.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | export default function CopyrightStatement() {
4 | const year = new Date().getFullYear();
5 | return (
6 |
7 | Copyright {year}
8 |
9 | );
10 | }
11 |
--------------------------------------------------------------------------------
/architecture/build/initial/src/components/Copyright/Copyright.spec.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jsmapr1/simplifying-js/a7ced4922664a4ea0d2b584963fd4d7aeebd7321/architecture/build/initial/src/components/Copyright/Copyright.spec.js
--------------------------------------------------------------------------------
/architecture/build/initial/src/components/IdeaButton/IdeaButton.css:
--------------------------------------------------------------------------------
1 | .idea-button {
2 | background: #ffffff;
3 | border: black solid 1px;
4 | border-radius: 3px;
5 | width: 200px;
6 | font-size: 16px;
7 | line-height: 40px;
8 | }
9 |
10 | .idea-button:hover {
11 | cursor: pointer;
12 | }
13 |
14 | .idea-button__icon {
15 | width: 40px;
16 | height: 40px;
17 | float: left;
18 | }
19 |
--------------------------------------------------------------------------------
/architecture/build/initial/src/components/IdeaButton/IdeaButton.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import './IdeaButton.css';
3 | import idea from './idea.svg';
4 |
5 | export default function IdeaButton({ handleClick, message }) {
6 | return (
7 |
18 | );
19 | }
20 |
--------------------------------------------------------------------------------
/architecture/build/initial/src/components/IdeaButton/IdeaButton.spec.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jsmapr1/simplifying-js/a7ced4922664a4ea0d2b584963fd4d7aeebd7321/architecture/build/initial/src/components/IdeaButton/IdeaButton.spec.js
--------------------------------------------------------------------------------
/architecture/build/initial/src/components/IdeaButton/idea.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jsmapr1/simplifying-js/a7ced4922664a4ea0d2b584963fd4d7aeebd7321/architecture/build/initial/src/components/IdeaButton/idea.png
--------------------------------------------------------------------------------
/architecture/build/initial/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: sans-serif;
5 | }
6 |
--------------------------------------------------------------------------------
/architecture/build/initial/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import App from './App';
4 |
5 | ReactDOM.render(, document.getElementById('root'));
6 |
--------------------------------------------------------------------------------
/architecture/build/webpack/.babelrc:
--------------------------------------------------------------------------------
1 | { "presets": ["env", "react"] }
2 |
--------------------------------------------------------------------------------
/architecture/build/webpack/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Sample
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/architecture/build/webpack/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "initial",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "build": "webpack"
8 | },
9 | "keywords": [],
10 | "author": "",
11 | "license": "ISC",
12 | "devDependencies": {
13 | "babel-cli": "^6.26.0",
14 | "babel-loader": "^7.1.2",
15 | "babel-preset-env": "^1.6.1",
16 | "babel-preset-react": "^6.24.1",
17 | "webpack": "^3.8.1"
18 | },
19 | "dependencies": {
20 | "react": "^16.1.1",
21 | "react-dom": "^16.1.1"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/architecture/build/webpack/src/App.css:
--------------------------------------------------------------------------------
1 | .main {
2 | width: 100%;
3 | }
4 |
5 | .app {
6 | padding: 1em;
7 | }
8 |
9 | footer {
10 | margin: 2em 0 0 0;
11 | padding: 1em;
12 | width: 100%;
13 | height: 3em;
14 | border-top: black solid 1px;
15 | }
16 |
--------------------------------------------------------------------------------
/architecture/build/webpack/src/App.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import Copyright from './components/Copyright/Copyright';
4 |
5 | export default function App() {
6 | return (
7 |
13 | );
14 | }
15 |
16 |
--------------------------------------------------------------------------------
/architecture/build/webpack/src/App.test.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jsmapr1/simplifying-js/a7ced4922664a4ea0d2b584963fd4d7aeebd7321/architecture/build/webpack/src/App.test.js
--------------------------------------------------------------------------------
/architecture/build/webpack/src/components/Copyright/Copyright.css:
--------------------------------------------------------------------------------
1 | .copyright {
2 | font-size: 10px;
3 | margin: 1em;
4 | margin-left: 0;
5 | float: left;
6 | }
7 |
--------------------------------------------------------------------------------
/architecture/build/webpack/src/components/Copyright/Copyright.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | export default function CopyrightStatement() {
4 | const year = new Date().getFullYear();
5 | return (
6 |
7 | Copyright {year}
8 |
9 | );
10 | }
11 |
--------------------------------------------------------------------------------
/architecture/build/webpack/src/components/Copyright/Copyright.spec.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jsmapr1/simplifying-js/a7ced4922664a4ea0d2b584963fd4d7aeebd7321/architecture/build/webpack/src/components/Copyright/Copyright.spec.js
--------------------------------------------------------------------------------
/architecture/build/webpack/src/components/IdeaButton/IdeaButton.css:
--------------------------------------------------------------------------------
1 | .idea-button {
2 | background: #ffffff;
3 | border: black solid 1px;
4 | border-radius: 3px;
5 | width: 200px;
6 | font-size: 16px;
7 | line-height: 40px;
8 | }
9 |
10 | .idea-button:hover {
11 | cursor: pointer;
12 | }
13 |
14 | .idea-button__icon {
15 | width: 40px;
16 | height: 40px;
17 | float: left;
18 | }
19 |
--------------------------------------------------------------------------------
/architecture/build/webpack/src/components/IdeaButton/IdeaButton.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import './IdeaButton.css';
3 | import idea from './idea.svg';
4 |
5 | export default function IdeaButton({ handleClick, message }) {
6 | return (
7 |
18 | );
19 | }
20 |
--------------------------------------------------------------------------------
/architecture/build/webpack/src/components/IdeaButton/IdeaButton.spec.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jsmapr1/simplifying-js/a7ced4922664a4ea0d2b584963fd4d7aeebd7321/architecture/build/webpack/src/components/IdeaButton/IdeaButton.spec.js
--------------------------------------------------------------------------------
/architecture/build/webpack/src/components/IdeaButton/idea.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jsmapr1/simplifying-js/a7ced4922664a4ea0d2b584963fd4d7aeebd7321/architecture/build/webpack/src/components/IdeaButton/idea.png
--------------------------------------------------------------------------------
/architecture/build/webpack/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: sans-serif;
5 | }
6 |
--------------------------------------------------------------------------------
/architecture/build/webpack/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import App from './App';
4 |
5 | ReactDOM.render(, document.getElementById('root'));
6 |
--------------------------------------------------------------------------------
/architecture/build/webpack/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 |
3 | module.exports = {
4 | entry: './src/index.js',
5 | module: {
6 | loaders: [
7 | {
8 | test: /\.js?/,
9 | use: 'babel-loader',
10 | },
11 | ],
12 | },
13 | output: {
14 | filename: 'build/bundle.js',
15 | path: path.resolve(__dirname),
16 | },
17 | };
18 |
--------------------------------------------------------------------------------
/architecture/component/simplifying-js-component/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 |
6 | # testing
7 | /coverage
8 |
9 | # production
10 | /build
11 |
12 | # misc
13 | .DS_Store
14 | .env.local
15 | .env.development.local
16 | .env.test.local
17 | .env.production.local
18 |
19 | npm-debug.log*
20 | yarn-debug.log*
21 | yarn-error.log*
22 |
--------------------------------------------------------------------------------
/architecture/component/simplifying-js-component/README.md:
--------------------------------------------------------------------------------
1 | Try it out! Go to a terminal and do the following:
2 |
3 | 1. `npm install`
4 | 2. `npm start`
5 | 3. Open a browser to [localhost:3000](localhost:3000)
6 |
--------------------------------------------------------------------------------
/architecture/component/simplifying-js-component/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "simplifying-js-component",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "react": "^16.0.0",
7 | "react-dom": "^16.0.0",
8 | "react-scripts": "1.0.17"
9 | },
10 | "scripts": {
11 | "start": "react-scripts start",
12 | "build": "react-scripts build",
13 | "test": "react-scripts test --env=jsdom",
14 | "eject": "react-scripts eject"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/architecture/component/simplifying-js-component/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jsmapr1/simplifying-js/a7ced4922664a4ea0d2b584963fd4d7aeebd7321/architecture/component/simplifying-js-component/public/favicon.ico
--------------------------------------------------------------------------------
/architecture/component/simplifying-js-component/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
11 |
12 |
13 |
22 | Sample
23 |
24 |
25 |
28 |
29 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/architecture/component/simplifying-js-component/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | }
10 | ],
11 | "start_url": "./index.html",
12 | "display": "standalone",
13 | "theme_color": "#000000",
14 | "background_color": "#ffffff"
15 | }
16 |
--------------------------------------------------------------------------------
/architecture/component/simplifying-js-component/src/App.css:
--------------------------------------------------------------------------------
1 | .main {
2 | width: 100%;
3 | }
4 |
5 | .app {
6 | padding: 1em;
7 | }
8 |
9 | footer {
10 | margin: 2em 0 0 0;
11 | padding: 1em;
12 | width: 100%;
13 | height: 3em;
14 | border-top: black solid 1px;
15 | }
16 |
--------------------------------------------------------------------------------
/architecture/component/simplifying-js-component/src/App.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import './App.css';
4 | import IdeaButton from './components/IdeaButton/IdeaButton';
5 | import Copyright from './components/Copyright/Copyright';
6 |
7 | function logIdea() {
8 | console.log('Someone had an idea!');
9 | }
10 | export default function App() {
11 | return (
12 |
27 | );
28 | }
29 |
30 |
--------------------------------------------------------------------------------
/architecture/component/simplifying-js-component/src/App.test.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jsmapr1/simplifying-js/a7ced4922664a4ea0d2b584963fd4d7aeebd7321/architecture/component/simplifying-js-component/src/App.test.js
--------------------------------------------------------------------------------
/architecture/component/simplifying-js-component/src/components/Copyright/Copyright.css:
--------------------------------------------------------------------------------
1 | .copyright {
2 | font-size: 10px;
3 | margin: 1em 1em 1em 0;
4 | float: left;
5 | }
6 |
--------------------------------------------------------------------------------
/architecture/component/simplifying-js-component/src/components/Copyright/Copyright.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import './Copyright.css';
3 |
4 | export default function CopyrightStatement() {
5 | const year = new Date().getFullYear();
6 | return (
7 |
8 | Copyright {year}
9 |
10 | );
11 | }
12 |
--------------------------------------------------------------------------------
/architecture/component/simplifying-js-component/src/components/Copyright/Copyright.spec.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jsmapr1/simplifying-js/a7ced4922664a4ea0d2b584963fd4d7aeebd7321/architecture/component/simplifying-js-component/src/components/Copyright/Copyright.spec.js
--------------------------------------------------------------------------------
/architecture/component/simplifying-js-component/src/components/IdeaButton/IdeaButton.css:
--------------------------------------------------------------------------------
1 | .idea-button {
2 | background: #ffffff;
3 | border: black solid 1px;
4 | border-radius: 3px;
5 | width: 200px;
6 | font-size: 16px;
7 | line-height: 40px;
8 | }
9 |
10 | .idea-button:hover {
11 | cursor: pointer;
12 | }
13 |
14 | .idea-button__icon {
15 | width: 40px;
16 | height: 40px;
17 | float: left;
18 | }
19 |
--------------------------------------------------------------------------------
/architecture/component/simplifying-js-component/src/components/IdeaButton/IdeaButton.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import './IdeaButton.css';
3 | import idea from './idea.svg';
4 |
5 | export default function IdeaButton({ handleClick, message }) {
6 | return (
7 |
18 | );
19 | }
20 |
--------------------------------------------------------------------------------
/architecture/component/simplifying-js-component/src/components/IdeaButton/IdeaButton.spec.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jsmapr1/simplifying-js/a7ced4922664a4ea0d2b584963fd4d7aeebd7321/architecture/component/simplifying-js-component/src/components/IdeaButton/IdeaButton.spec.js
--------------------------------------------------------------------------------
/architecture/component/simplifying-js-component/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: sans-serif;
5 | }
6 |
--------------------------------------------------------------------------------
/architecture/component/simplifying-js-component/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import App from './App';
4 |
5 | ReactDOM.render(, document.getElementById('root'));
6 |
--------------------------------------------------------------------------------
/architecture/css/animate/main.css:
--------------------------------------------------------------------------------
1 | .main {
2 | width: 1000px;
3 | margin: 0 auto;
4 | overflow: hidden;
5 | position: relative;
6 | }
7 |
8 | button {
9 | border: black solid 1px;
10 | background: #ffffff;
11 | }
12 |
13 | .menu {
14 | width: 300px;
15 | padding: 0 2em;
16 | float: right;
17 | border: black solid 1px;
18 | position: absolute;
19 | top: 0;
20 | right: 0;
21 | height: calc(100% - 2px);
22 | background: #ffffff;
23 | }
24 | /* //START:transition */
25 | .menu.display {
26 | /* Other styles */
27 | transform: translateX(0);
28 | transition-property: transform;
29 | transition-duration: 600ms;
30 | transition-timing-function: linear;
31 | }
32 | /* //END:transition */
33 |
34 | /* //START:short */
35 | .menu {
36 | /* Other styles */
37 | transform: translateX(calc(300px + 4em + 2px));
38 | transition: all 600ms linear;
39 | }
40 | /* //END:short */
41 |
--------------------------------------------------------------------------------
/architecture/css/animate/open.js:
--------------------------------------------------------------------------------
1 | const sidebar = document.getElementById('sidebar');
2 | document.getElementById('show')
3 | .addEventListener('click', () => {
4 | sidebar.classList.toggle('display');
5 | });
6 |
--------------------------------------------------------------------------------
/architecture/css/initial/index-truncated.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
Moby Dick
9 |
10 |
17 |
18 |
19 | Call me Ishmael.
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/architecture/css/initial/main.css:
--------------------------------------------------------------------------------
1 | .main {
2 | width: 1000px;
3 | margin: 0 auto;
4 | overflow: hidden;
5 | position: relative;
6 | }
7 |
8 | button {
9 | border: black solid 1px;
10 | background: #ffffff;
11 | }
12 |
13 | .menu {
14 | width: 300px;
15 | padding: 0 2em;
16 | float: right;
17 | border: black solid 1px;
18 | position: absolute;
19 | top: 0;
20 | right: 0;
21 | height: calc(100% - 2px);
22 | background: #ffffff;
23 | }
24 |
--------------------------------------------------------------------------------
/architecture/css/middle/main.css:
--------------------------------------------------------------------------------
1 | .main {
2 | width: 1000px;
3 | margin: 0 auto;
4 | overflow: hidden;
5 | position: relative;
6 | }
7 |
8 | button {
9 | border: black solid 1px;
10 | background: #ffffff;
11 | }
12 | .menu {
13 | width: 300px;
14 | padding: 0 2em;
15 | float: right;
16 | border: black solid 1px;
17 | position: absolute;
18 | top: 0;
19 | right: 0;
20 | height: calc(100% - 2px);
21 | background: #ffffff;
22 |
23 | }
24 | /* //START:transform */
25 | .menu {
26 | /* Other styles from before */
27 | transform: translateX(calc(300px + 4em + 2px));
28 | }
29 | .menu.display {
30 | transform: translateX(0);
31 | }
32 | /* //END:transform */
33 |
--------------------------------------------------------------------------------
/architecture/css/middle/open.js:
--------------------------------------------------------------------------------
1 | const sidebar = document.getElementById('sidebar');
2 | document.getElementById('show')
3 | .addEventListener('click', () => {
4 | sidebar.classList.toggle('display');
5 | });
6 |
--------------------------------------------------------------------------------
/architecture/import/class/address.js:
--------------------------------------------------------------------------------
1 | import { capitalize } from '../single/util';
2 |
3 | export default class Address {
4 | constructor(address) {
5 | this.address = address;
6 | }
7 |
8 | normalize() {
9 | const street = this.parseStreet(this.address);
10 | const city = this.address.city;
11 | const region = this.parseRegion(this.address);
12 | return `${street} ${city}, ${region}`;
13 | }
14 |
15 | parseStreet({ street }) {
16 | return street.split(' ')
17 | .map(part => capitalize(part))
18 | .join(' ');
19 | }
20 |
21 | parseRegion(address) {
22 | const region = address.state || address.providence || '';
23 | return region.toUpperCase();
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/architecture/import/default/address.js:
--------------------------------------------------------------------------------
1 | import { capitalize } from '../single/util';
2 |
3 | export function parseRegion(address) {
4 | const region = address.state || address.providence || '';
5 | return region.toUpperCase();
6 | }
7 |
8 | export function parseStreet({ street }) {
9 | return street.split(' ')
10 | .map(part => capitalize(part))
11 | .join(' ');
12 | }
13 |
14 | export default function normalize(address) {
15 | const street = parseStreet(address);
16 | const city = address.city;
17 | const region = parseRegion(address);
18 | return `${street} ${city}, ${region}`;
19 | }
20 |
--------------------------------------------------------------------------------
/architecture/import/default/list.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-param-reassign, no-unused-vars */
2 | // # START:code
3 | import normalize, { parseRegion } from './address';
4 |
5 | function getAddress(user) {
6 | return normalize(user.address);
7 | }
8 |
9 | export function getAddressByRegion(users) {
10 | return users.reduce((regions, user) => {
11 | const { address } = user;
12 | const region = parseRegion(address);
13 | const addresses = regions[region] || [];
14 | regions[region] = [...addresses, normalize(address)];
15 | return regions;
16 | }, {});
17 | }
18 |
19 | const bars = [
20 | {
21 | name: 'Saint Vitus',
22 | address: {
23 | street: '1120 manhattan ave',
24 | city: 'Brooklyn',
25 | state: 'NY',
26 | },
27 | },
28 | ];
29 | getAddressByRegion(bars);
30 | // {
31 | // NY: ["1120 Manhattan Ave Brooklyn, NY"]
32 | // }
33 | // # END:code
34 |
--------------------------------------------------------------------------------
/architecture/import/default/list.spec.js:
--------------------------------------------------------------------------------
1 | import expect from 'expect';
2 | import { getAddressByRegion } from './list';
3 |
4 | const clubs = [
5 | {
6 | name: 'CBGB',
7 | address: {
8 | street: '315 bowery',
9 | city: 'New York',
10 | state: 'ny',
11 | },
12 | },
13 | {
14 | name: 'Saint Vitus',
15 | address: {
16 | street: '1120 manhattan ave',
17 | city: 'Brooklyn',
18 | state: 'NY',
19 | },
20 | },
21 | ];
22 |
23 | describe('list', () => {
24 | it('should compile clubs', () => {
25 | expect(getAddressByRegion(clubs)).toEqual({
26 | NY: [
27 | '315 Bowery New York, NY',
28 | '1120 Manhattan Ave Brooklyn, NY',
29 | ],
30 | });
31 | });
32 | });
33 |
--------------------------------------------------------------------------------
/architecture/import/default/mail.js:
--------------------------------------------------------------------------------
1 | import normalize from './address';
2 |
3 | function getAddress(user) {
4 | return normalize(user.address);
5 | }
6 |
7 | export default getAddress;
8 |
--------------------------------------------------------------------------------
/architecture/import/each/bill.js:
--------------------------------------------------------------------------------
1 | import {
2 | capitalize,
3 | roundToDecimalPlace as round,
4 | } from './util';
5 |
6 | function giveTotal(name, total) {
7 | return `${capitalize(name)}, your total is: ${round(total)}`;
8 | }
9 |
10 | giveTotal('sara', 10.3333333);
11 | // "Sara, your total is: 10.33"
12 |
13 | export { giveTotal };
14 |
--------------------------------------------------------------------------------
/architecture/import/each/bill.spec.js:
--------------------------------------------------------------------------------
1 | import expect from 'expect';
2 | import { giveTotal } from './bill';
3 |
4 | describe('bill', () => {
5 | it('should give total', () => {
6 | expect(giveTotal('sara', 10.33333))
7 | .toEqual('Sara, your total is: 10.33');
8 | });
9 | });
10 |
--------------------------------------------------------------------------------
/architecture/import/each/name.js:
--------------------------------------------------------------------------------
1 | import * as utils from './util';
2 |
3 | function greet(name) {
4 | return `Hello, ${utils.capitalize(name)}!`;
5 | }
6 |
7 | greet('ashley');
8 | // Hello, Ashley!
9 |
10 | export { greet };
11 |
--------------------------------------------------------------------------------
/architecture/import/each/name.spec.js:
--------------------------------------------------------------------------------
1 | import expect from 'expect';
2 | import { greet } from './name';
3 |
4 | describe('name', () => {
5 | it('should capitalize name', () => {
6 | expect(greet('ashley')).toEqual('Hello, Ashley!');
7 | });
8 | });
9 |
--------------------------------------------------------------------------------
/architecture/import/each/util.js:
--------------------------------------------------------------------------------
1 | function getPower(decimalPlaces) {
2 | return 10 ** decimalPlaces;
3 | }
4 |
5 | export function capitalize(word) {
6 | return word[0].toUpperCase() + word.slice(1);
7 | }
8 |
9 | export function roundToDecimalPlace(number, decimalPlaces = 2) {
10 | const round = getPower(decimalPlaces);
11 | return Math.round(number * round) / round;
12 | }
13 |
--------------------------------------------------------------------------------
/architecture/import/each/util.spec.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jsmapr1/simplifying-js/a7ced4922664a4ea0d2b584963fd4d7aeebd7321/architecture/import/each/util.spec.js
--------------------------------------------------------------------------------
/architecture/import/single/area.js:
--------------------------------------------------------------------------------
1 | import { PI } from './math';
2 |
3 | function area(radius) {
4 | return PI * (radius ** 2);
5 | }
6 |
7 | export { area };
8 |
--------------------------------------------------------------------------------
/architecture/import/single/bill.js:
--------------------------------------------------------------------------------
1 | import { capitalize, roundToDecimalPlace } from './util';
2 |
3 | function giveTotal(name, total) {
4 | return `${capitalize(name)}, your total is: ${roundToDecimalPlace(total)}`;
5 | }
6 |
7 | giveTotal('sara', 10.3333333);
8 | // "Sara, your total is: 10.33"
9 |
10 | export { giveTotal };
11 |
--------------------------------------------------------------------------------
/architecture/import/single/bill.spec.js:
--------------------------------------------------------------------------------
1 | import expect from 'expect';
2 | import { giveTotal } from './bill';
3 |
4 | describe('bill', () => {
5 | it('should give total', () => {
6 | expect(giveTotal('sara', 10.33333))
7 | .toEqual('Sara, your total is: 10.33');
8 | });
9 | });
10 |
--------------------------------------------------------------------------------
/architecture/import/single/math.js:
--------------------------------------------------------------------------------
1 | const PI = 3.14;
2 | const E = 2.71828;
3 |
4 | export { E, PI };
5 |
--------------------------------------------------------------------------------
/architecture/import/single/name.js:
--------------------------------------------------------------------------------
1 | import { capitalize } from './util';
2 |
3 | function greet(name) {
4 | return `Hello, ${capitalize(name)}!`;
5 | }
6 |
7 | greet('ashley');
8 | // Hello, Ashley!
9 |
10 | export { greet };
11 |
--------------------------------------------------------------------------------
/architecture/import/single/name.spec.js:
--------------------------------------------------------------------------------
1 | import expect from 'expect';
2 | import { greet } from './name';
3 |
4 | describe('name', () => {
5 | it('should capitalize name', () => {
6 | expect(greet('ashley')).toEqual('Hello, Ashley!');
7 | });
8 | });
9 |
--------------------------------------------------------------------------------
/architecture/import/single/util.js:
--------------------------------------------------------------------------------
1 | function getPower(decimalPlaces) {
2 | return 10 ** decimalPlaces;
3 | }
4 |
5 | function capitalize(word) {
6 | return word[0].toUpperCase() + word.slice(1);
7 | }
8 |
9 | function roundToDecimalPlace(number, decimalPlaces = 2) {
10 | const round = getPower(decimalPlaces);
11 | return Math.round(number * round) / round;
12 | }
13 |
14 | export { capitalize, roundToDecimalPlace };
15 |
--------------------------------------------------------------------------------
/architecture/npm/defaults/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "test",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "author": "",
10 | "license": "ISC"
11 | }
12 |
--------------------------------------------------------------------------------
/architecture/npm/save/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "test",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "author": "",
10 | "license": "ISC",
11 | "dependencies": {
12 | "lodash": "^4.17.4"
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/architecture/npm/saveDev/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "test",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "author": "",
10 | "license": "ISC",
11 | "dependencies": {
12 | "lodash": "^4.17.4"
13 | },
14 | "devDependencies": {
15 | "prettier": "^1.8.2"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/architecture/npm/script/code/merge.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable import/no-duplicates */
2 | import lodash from 'lodash';
3 | import { fromPairs } from 'lodash';
4 |
5 | export function mapToObject(map) {
6 | return fromPairs([...map]);
7 | }
8 |
9 | export function objectToMap(object) {
10 | const pairs = lodash.toPairs(object);
11 | return new Map(pairs);
12 | }
13 |
--------------------------------------------------------------------------------
/architecture/npm/script/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "test",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "clean": "prettier --tab-width=4 --write ./code/*.js"
8 | },
9 | "author": "",
10 | "license": "ISC",
11 | "dependencies": {
12 | "lodash": "^4.17.4"
13 | },
14 | "devDependencies": {
15 | "prettier": "^1.8.2"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/architecture/npm/utils/clone.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jsmapr1/simplifying-js/a7ced4922664a4ea0d2b584963fd4d7aeebd7321/architecture/npm/utils/clone.js
--------------------------------------------------------------------------------
/architecture/npm/utils/merge.js:
--------------------------------------------------------------------------------
1 | import lodash, { fromPairs } from 'lodash';
2 |
3 | export function mapToObject(map) {
4 | return fromPairs([...map]);
5 | }
6 |
7 | export function objectToMap(object) {
8 | const pairs = lodash.toPairs(object);
9 | return new Map(pairs);
10 | }
11 |
--------------------------------------------------------------------------------
/architecture/npm/utils/merge.spec.js:
--------------------------------------------------------------------------------
1 | import expect from 'expect';
2 | import { mapToObject, objectToMap } from './merge';
3 |
4 | describe('utilities', () => {
5 | it('should convert map to object', () => {
6 | const simple = new Map().set('name', 'joe');
7 | expect(mapToObject(simple)).toEqual({ name: 'joe' });
8 | });
9 | it('should convert object to map', () => {
10 | const person = { name: 'joe' };
11 | const simple = new Map().set('name', 'joe');
12 | expect(objectToMap(person)).toEqual(simple);
13 | });
14 | });
15 |
--------------------------------------------------------------------------------
/arrays/arrays/arrays.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-restricted-syntax */
2 |
3 | // # START:sort
4 | const team = [
5 | 'Joe',
6 | 'Dyan',
7 | 'Bea',
8 | 'Theo',
9 | ];
10 |
11 | function alphabetizeTeam(team) {
12 | return [...team].sort();
13 | // ['Bea', 'Dyan', 'Joe', 'Theo']
14 | }
15 | // # END:sort
16 |
17 | function getTotalStats() {
18 | // # START:loop
19 |
20 | const game1 = {
21 | player: 'Jim Jonas',
22 | hits: 2,
23 | runs: 1,
24 | errors: 0,
25 | };
26 |
27 | const game2 = {
28 | player: 'Jim Jonas',
29 | hits: 3,
30 | runs: 0,
31 | errors: 1,
32 | };
33 |
34 | const total = {};
35 |
36 | const stats = Object.keys(game1);
37 | for (let i = 0; i < stats.length; i++) {
38 | const stat = stats[i];
39 | if (stat !== 'player') {
40 | total[stat] = game1[stat] + game2[stat];
41 | }
42 | }
43 |
44 | // {
45 | // hits: 5,
46 | // runs: 1,
47 | // errors: 1
48 | // }
49 |
50 | // # END:loop
51 | return total;
52 | }
53 |
54 | // # START:filter
55 | const staff = [
56 | {
57 | name: 'Wesley',
58 | position: 'musician',
59 | },
60 | {
61 | name: 'Davis',
62 | position: 'engineer',
63 | },
64 | ];
65 |
66 | function getMusicians(staff) {
67 | return staff.filter(member => member.position === 'musician');
68 | // [{name: 'Wesley', position: 'musician'}]
69 | }
70 | // # END:filter
71 |
72 | // # START:object
73 | const dog = {
74 | name: 'Don',
75 | color: 'black',
76 | };
77 |
78 | dog.name;
79 | // Don
80 |
81 | // # END:object
82 |
83 | // # START:pair
84 | const dogPair = [
85 | ['name', 'Don'],
86 | ['color', 'black'],
87 | ];
88 |
89 | function getName(dogPair) {
90 | return dogPair.find(attribute => {
91 | return attribute[0] === 'name';
92 | })[1];
93 | }
94 | // # END:pair
95 |
96 | export {
97 | alphabetizeTeam,
98 | dogPair,
99 | getMusicians,
100 | getName,
101 | getTotalStats,
102 | staff,
103 | team,
104 | };
105 |
--------------------------------------------------------------------------------
/arrays/arrays/arrays.spec.js:
--------------------------------------------------------------------------------
1 | import expect from 'expect';
2 | import {
3 | alphabetizeTeam,
4 | dogPair,
5 | getMusicians,
6 | getName,
7 | getTotalStats,
8 | staff,
9 | team,
10 | } from './arrays';
11 |
12 | describe('array actions', () => {
13 | it('should alphabetize team', () => {
14 | expect(alphabetizeTeam(team)).toEqual([
15 | 'Bea',
16 | 'Dyan',
17 | 'Joe',
18 | 'Theo',
19 | ]);
20 | });
21 |
22 | it('should get musicians', () => {
23 | expect(getMusicians(staff)).toEqual([
24 | {
25 | name: 'Wesley',
26 | position: 'musician',
27 | },
28 | ]);
29 | });
30 |
31 | it('should get name', () => {
32 | expect(getName(dogPair)).toEqual('Don');
33 | });
34 |
35 | it('should calculate stats', () => {
36 | expect(getTotalStats()).toEqual({
37 | hits: 5,
38 | runs: 1,
39 | errors: 1,
40 | });
41 | });
42 | });
43 |
--------------------------------------------------------------------------------
/arrays/includes/greater.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-unused-vars */
2 |
3 | // # START:index
4 | const sections = ['contact', 'shipping'];
5 |
6 | function displayShipping(sections) {
7 | return sections.indexOf('shipping') > -1;
8 | }
9 |
10 | // true
11 |
12 | // # END:index
13 |
14 | export { displayShipping };
15 |
--------------------------------------------------------------------------------
/arrays/includes/includes.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-unused-vars */
2 |
3 | // # START:includes
4 | const sections = ['contact', 'shipping'];
5 |
6 | function displayShipping(sections) {
7 | return sections.includes('shipping');
8 | }
9 | // # END:includes
10 |
11 | export { displayShipping };
12 |
--------------------------------------------------------------------------------
/arrays/includes/includes.spec.js:
--------------------------------------------------------------------------------
1 | import expect from 'expect';
2 | import {
3 | displayShipping,
4 | } from './includes';
5 |
6 | import {
7 | displayShipping as displayShippingIndex,
8 | } from './greater';
9 |
10 | describe('includes actions', () => {
11 | it('should display shipping using index', () => {
12 | const sections = ['shipping', 'address'];
13 | expect(displayShippingIndex(sections)).toEqual(true);
14 | });
15 |
16 | it('should not display shipping using index', () => {
17 | const sections = ['contact', 'address'];
18 | expect(displayShippingIndex(sections)).toEqual(false);
19 | });
20 |
21 | it('should display shipping', () => {
22 | const sections = ['shipping', 'address'];
23 | expect(displayShipping(sections)).toEqual(true);
24 | });
25 |
26 | it('should not display shipping', () => {
27 | const sections = ['contact', 'address'];
28 | expect(displayShipping(sections)).toEqual(false);
29 | });
30 | });
31 |
--------------------------------------------------------------------------------
/arrays/includes/problem.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-unused-vars */
2 | // # START:noIndex
3 | const sections = ['shipping'];
4 |
5 | function displayShipping(sections) {
6 | if (sections.indexOf('shipping')) {
7 | return true;
8 | }
9 | return false;
10 | }
11 |
12 | // false
13 |
14 | // # END:noIndex
15 |
16 | export { displayShipping };
17 |
--------------------------------------------------------------------------------
/arrays/push/push.spec.js:
--------------------------------------------------------------------------------
1 | import expect from 'expect';
2 | import {
3 | cart,
4 | reward,
5 | summarizeCart,
6 | summarizeCartUpdated,
7 | } from './push';
8 |
9 | describe('push', () => {
10 | it('should not return an error intitially', () => {
11 | const testCart = [...cart];
12 | const updated = [...cart, reward];
13 | expect(summarizeCart(testCart)).toEqual({
14 | discounts: 1,
15 | items: 4,
16 | cart: updated,
17 | });
18 | });
19 |
20 | it('should return an error when rearranged', () => {
21 | const testCart = [...cart];
22 | expect(summarizeCartUpdated(testCart)).toEqual({
23 | error: 'Can only have one discount',
24 | });
25 | });
26 |
27 | it('should not return an error with spread', () => {
28 | const testCart = [...cart];
29 | const updated = [...cart, reward];
30 | expect(summarizeCart(testCart)).toEqual({
31 | discounts: 1,
32 | items: 4,
33 | cart: updated,
34 | });
35 | });
36 | });
37 |
--------------------------------------------------------------------------------
/arrays/sort/sort.js:
--------------------------------------------------------------------------------
1 | const staff = [
2 | {
3 | name: 'Joe',
4 | years: 10,
5 | },
6 | {
7 | name: 'Theo',
8 | years: 5,
9 | },
10 | {
11 | name: 'Dyan',
12 | years: 10,
13 | },
14 | ];
15 |
16 | function sortByYears(a, b) {
17 | if (a.years === b.years) {
18 | return 0;
19 | }
20 | return a.years - b.years;
21 | }
22 |
23 | const sortByName = (a, b) => {
24 | if (a.name === b.name) {
25 | return 0;
26 | }
27 | return a.name > b.name ? 1 : -1;
28 | };
29 |
30 | export { staff, sortByYears, sortByName };
31 |
32 |
--------------------------------------------------------------------------------
/arrays/sort/sort.spec.js:
--------------------------------------------------------------------------------
1 | import expect from 'expect';
2 | import { staff, sortByYears, sortByName } from './sort';
3 |
4 | describe('sort mutations', () => {
5 | it('should return different results', () => {
6 | const copy = [...staff];
7 | copy.sort(sortByYears);
8 | expect(copy[0].name).toEqual('Theo');
9 | expect(copy[1].name).toEqual('Joe');
10 | expect(copy[2].name).toEqual('Dyan');
11 |
12 | copy.sort(sortByName);
13 | expect(copy[0].name).toEqual('Dyan');
14 | expect(copy[1].name).toEqual('Joe');
15 | expect(copy[2].name).toEqual('Theo');
16 |
17 | copy.sort(sortByYears);
18 | expect(copy[0].name).toEqual('Theo');
19 | expect(copy[1].name).toEqual('Dyan');
20 | expect(copy[2].name).toEqual('Joe');
21 | });
22 |
23 | it('should return the same results', () => {
24 | const staff1 = [...staff].sort(sortByYears);
25 | expect(staff1[0].name).toEqual('Theo');
26 | expect(staff1[1].name).toEqual('Joe');
27 | expect(staff1[2].name).toEqual('Dyan');
28 |
29 | const staff2 = [...staff].sort(sortByName);
30 | expect(staff2[0].name).toEqual('Dyan');
31 | expect(staff2[1].name).toEqual('Joe');
32 | expect(staff2[2].name).toEqual('Theo');
33 |
34 | const staff3 = [...staff].sort(sortByYears);
35 | expect(staff3[0].name).toEqual('Theo');
36 | expect(staff3[1].name).toEqual('Joe');
37 | expect(staff3[2].name).toEqual('Dyan');
38 | });
39 | });
40 |
--------------------------------------------------------------------------------
/arrays/sort/sortMutate.js:
--------------------------------------------------------------------------------
1 | // # START:staff
2 | const staff = [
3 | {
4 | name: 'Joe',
5 | years: 10,
6 | },
7 | {
8 | name: 'Theo',
9 | years: 5,
10 | },
11 | {
12 | name: 'Dyan',
13 | years: 10,
14 | },
15 | ];
16 | // # END:staff
17 |
18 | // # START:sortFunctions
19 | function sortByYears(a, b) {
20 | if (a.years === b.years) {
21 | return 0;
22 | }
23 | return a.years - b.years;
24 | }
25 |
26 | const sortByName = (a, b) => {
27 | if (a.name === b.name) {
28 | return 0;
29 | }
30 | return a.name > b.name ? 1 : -1;
31 | };
32 | // # END:sortFunctions
33 |
34 | // # START:sortYears
35 | staff.sort(sortByYears);
36 |
37 | // [
38 | // {
39 | // name: 'Theo',
40 | // years: 5
41 | // },
42 | // {
43 | // name: 'Joe',
44 | // years: 10
45 | // },
46 | // {
47 | // name: 'Dyan',
48 | // years: 10
49 | // },
50 | // ];
51 | // # END:sortYears
52 |
53 | // # START:sortName
54 | staff.sort(sortByName);
55 |
56 | // [
57 | // {
58 | // name: 'Dyan',
59 | // years: 10
60 | // },
61 | // {
62 | // name: 'Joe',
63 | // years: 10
64 | // },
65 | // {
66 | // name: 'Theo',
67 | // years: 5
68 | // },
69 | // ];
70 | // # END:sortName
71 |
72 | // # START:sortYearsAgain
73 | staff.sort(sortByYears);
74 |
75 | // [
76 | // {
77 | // name: 'Theo',
78 | // years: 5
79 | // },
80 | // {
81 | // name: 'Dyan',
82 | // years: 10
83 | // },
84 | // {
85 | // name: 'Joe',
86 | // years: 10
87 | // },
88 | // ]
89 | // # END:sortYearsAgain
90 |
--------------------------------------------------------------------------------
/arrays/sort/sortSpread.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-undef */
2 | // # START:sortYears
3 | [...staff].sort(sortByYears);
4 |
5 | // [
6 | // {
7 | // name: 'Theo',
8 | // years: 5
9 | // },
10 | // {
11 | // name: 'Joe',
12 | // years: 10
13 | // },
14 | // {
15 | // name: 'Dyan',
16 | // years: 10
17 | // },
18 | // ];
19 |
20 | // # END:sortYears
21 |
--------------------------------------------------------------------------------
/arrays/spread/problem.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-unused-vars */
2 | // # START:removeItem
3 | function removeItem(items, removable) {
4 | const updated = [];
5 | for (let i = 0; i < items.length; i++) {
6 | if (items[i] !== removable) {
7 | updated.push(items[i]);
8 | }
9 | }
10 | return updated;
11 | }
12 | // # END:removeItem
13 |
14 | export { removeItem };
15 |
--------------------------------------------------------------------------------
/arrays/spread/slice.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-unused-vars */
2 |
3 | // # START:removeItemSlice
4 | function removeItem(items, removable) {
5 | if (items.includes(removable)) {
6 | const index = items.indexOf(removable);
7 | return items.slice(0, index).concat(items.slice(index + 1));
8 | }
9 | return items;
10 | }
11 | // # END:removeItemSlice
12 |
13 | export { removeItem };
14 |
--------------------------------------------------------------------------------
/arrays/spread/splice.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-unused-vars */
2 | // # START:removeItemSplice
3 | function removeItem(items, removable) {
4 | if (items.includes(removable)) {
5 | const index = items.indexOf(removable);
6 | items.splice(index, 1);
7 | }
8 | return items;
9 | }
10 | // # END:removeItemSplice
11 |
12 | // # START:removeItemSpliceExample
13 | const books = ['practical vim', 'moby dick', 'the dark tower'];
14 | const recent = removeItem(books, 'moby dick');
15 | const novels = removeItem(books, 'practical vim');
16 | // # END:removeItemSpliceExample
17 |
18 | export { removeItem };
19 |
--------------------------------------------------------------------------------
/arrays/spread/spread.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-unused-vars */
2 |
3 | // # START:removeItemSpread
4 | function removeItem(items, removable) {
5 | if (items.includes(removable)) {
6 | const index = items.indexOf(removable);
7 | return [...items.slice(0, index), ...items.slice(index + 1)];
8 | }
9 | return items;
10 | }
11 | // # END:removeItemSpread
12 |
13 |
14 | // # START:spreadArguments
15 | const book = ['Reasons and Persons', 'Derek Parfit', 19.99];
16 |
17 | function formatBook(title, author, price) {
18 | return `${title} by ${author} $${price}`;
19 | }
20 | // # END:spreadArguments
21 |
22 |
23 | // # START:spreadArgumentsExample
24 | formatBook(book[0], book[1], book[2]);
25 |
26 | // # END:spreadArgumentsExample
27 |
28 | // # START:spreadArgumentsExample2
29 | formatBook(...book);
30 | // # END:spreadArgumentsExample2
31 |
32 | export {
33 | book,
34 | formatBook,
35 | removeItem,
36 | };
37 |
--------------------------------------------------------------------------------
/classes/bind/bind.js:
--------------------------------------------------------------------------------
1 | // START:bind
2 | function sayMessage() {
3 | return this.message;
4 | }
5 |
6 | const alert = {
7 | message: 'Danger!',
8 | };
9 |
10 | const sayAlert = sayMessage.bind(alert);
11 |
12 | sayAlert();
13 | // Danger!
14 | // END:bind
15 |
16 | // START:func
17 | class Validator {
18 | constructor() {
19 | this.message = 'is invalid.';
20 | }
21 |
22 | setInvalidMessage(field) {
23 | return `${field} ${this.message}`;
24 | }
25 |
26 | setInvalidMessages(...fields) {
27 | return fields.map(this.setInvalidMessage.bind(this));
28 | }
29 | }
30 | // END:func
31 |
32 | export { Validator, sayAlert, alert, sayMessage };
33 |
--------------------------------------------------------------------------------
/classes/bind/bind.spec.js:
--------------------------------------------------------------------------------
1 | import expect from 'expect';
2 |
3 | import {
4 | Validator as ValidatorProblem,
5 | } from './problem';
6 |
7 | import { Validator } from './bind';
8 |
9 | import {
10 | Validator as ValidatorArrow,
11 | } from './constructorArrow';
12 |
13 | import {
14 | Validator as ValidatorConstructor,
15 | } from './constructor';
16 |
17 | import {
18 | Validator as ValidatorProperties,
19 | } from './properties';
20 |
21 | describe('Validator', () => {
22 | it('should not bind to this', () => {
23 | try {
24 | // START: problem
25 | const validator = new ValidatorProblem();
26 | validator.setInvalidMessages('city');
27 | // TypeError: Cannot read property 'message' of undefined
28 | // END: problem
29 | } catch (e) {
30 | expect(e.message).toEqual("Cannot read property 'message' of undefined");
31 | }
32 | });
33 |
34 | it('should bind methods in map function', () => {
35 | const v = new Validator();
36 | const message = 'city is invalid.';
37 | expect(v.setInvalidMessages('city')).toEqual([message]);
38 | });
39 |
40 | it('should use arrow methods in constructor', () => {
41 | const v = new ValidatorArrow();
42 | const message = 'city is invalid.';
43 | expect(v.setInvalidMessages('city')).toEqual([message]);
44 | });
45 |
46 | it('should bind methods in constructor', () => {
47 | const v = new ValidatorConstructor();
48 | const message = 'city is invalid.';
49 | expect(v.setInvalidMessages('city')).toEqual([message]);
50 | });
51 |
52 | it('should have private properties', () => {
53 | const v = new ValidatorProperties();
54 | expect(v.message).toEqual('is invalid.');
55 | });
56 |
57 | it('should bind this with arrow functions', () => {
58 | const v = new ValidatorProperties();
59 | const message = 'city is invalid.';
60 | expect(v.setInvalidMessages('city')).toEqual([message]);
61 | });
62 | });
63 |
--------------------------------------------------------------------------------
/classes/bind/constructor.js:
--------------------------------------------------------------------------------
1 | // START:func
2 | class Validator {
3 | constructor() {
4 | this.message = 'is invalid.';
5 | this.setInvalidMessage = this.setInvalidMessage.bind(this);
6 | }
7 |
8 | setInvalidMessage(field) {
9 | return `${field} ${this.message}`;
10 | }
11 |
12 | setInvalidMessages(...fields) {
13 | return fields.map(this.setInvalidMessage);
14 | }
15 | }
16 | // END:func
17 |
18 | export { Validator };
19 |
--------------------------------------------------------------------------------
/classes/bind/constructorArrow.js:
--------------------------------------------------------------------------------
1 | // START:class
2 | class Validator {
3 | constructor() {
4 | this.message = 'is invalid.';
5 | this.setInvalidMessage = field => `${field} ${this.message}`;
6 | }
7 |
8 | setInvalidMessages(...fields) {
9 | return fields.map(this.setInvalidMessage);
10 | }
11 | }
12 | // END:class
13 |
14 | export { Validator };
15 |
--------------------------------------------------------------------------------
/classes/bind/problem.js:
--------------------------------------------------------------------------------
1 | // START: class
2 | class Validator {
3 | constructor() {
4 | this.message = 'is invalid.';
5 | }
6 |
7 | setInvalidMessage(field) {
8 | return `${field} ${this.message}`;
9 | }
10 |
11 | setInvalidMessages(...fields) {
12 | return fields.map(this.setInvalidMessage);
13 | }
14 | }
15 | // END: class
16 |
17 | export { Validator };
18 |
--------------------------------------------------------------------------------
/classes/bind/properties.js:
--------------------------------------------------------------------------------
1 | // START:func
2 | class Validator {
3 | message = 'is invalid.';
4 |
5 | setMessage = field => `${field} ${this.message}`;
6 |
7 | setInvalidMessages(...fields) {
8 | return fields.map(this.setMessage);
9 | }
10 | }
11 | // END:func
12 |
13 | export { Validator };
14 |
--------------------------------------------------------------------------------
/classes/constructor/constructor.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable dot-notation */
2 |
3 | // START:class
4 | class Coupon {
5 | constructor(price, expiration) {
6 | this.price = price;
7 | this.expiration = expiration || 'two weeks';
8 | }
9 | }
10 |
11 | const coupon = new Coupon(5);
12 | coupon.price;
13 | // 5
14 | coupon['expiration'];
15 | // 'Two Weeks'
16 | // END:class
17 |
18 | export default Coupon;
19 |
--------------------------------------------------------------------------------
/classes/constructor/constructor.spec.js:
--------------------------------------------------------------------------------
1 | import expect from 'expect';
2 | import CouponProblem from './problem';
3 | import CouponSimple from './constructor';
4 | import Coupon from './methods';
5 |
6 | describe('basic class', () => {
7 | it('should make a class', () => {
8 | const coupon = new CouponProblem();
9 | expect(coupon instanceof CouponProblem).toEqual(true);
10 | });
11 |
12 | it('should set properties', () => {
13 | const coupon = new CouponSimple(5);
14 | expect(coupon.price).toEqual(5);
15 | expect(coupon.expiration).toEqual('two weeks');
16 | });
17 |
18 | it('should have methods', () => {
19 | const coupon = new Coupon(5);
20 | const message = 'This offer expires in two weeks.';
21 |
22 | expect(coupon.getPriceText()).toEqual('$ 5');
23 | expect(coupon.getExpirationMessage()).toEqual(message);
24 | });
25 | });
26 |
--------------------------------------------------------------------------------
/classes/constructor/methods.js:
--------------------------------------------------------------------------------
1 | // START: method
2 | class Coupon {
3 | constructor(price, expiration) {
4 | this.price = price;
5 | this.expiration = expiration || 'two weeks';
6 | }
7 |
8 | getPriceText() {
9 | return `$ ${this.price}`;
10 | }
11 |
12 | getExpirationMessage() {
13 | return `This offer expires in ${this.expiration}.`;
14 | }
15 | }
16 |
17 | const coupon = new Coupon(5);
18 | coupon.getPriceText();
19 | // '$ 5'
20 | coupon.getExpirationMessage();
21 | // 'This offer expires in two weeks.'
22 |
23 | // END: method
24 |
25 | export default Coupon;
26 |
--------------------------------------------------------------------------------
/classes/constructor/problem.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-unused-vars */
2 | // START:class
3 | class Coupon {
4 |
5 | }
6 |
7 | const coupon = new Coupon();
8 | // END:class
9 |
10 | export default Coupon;
11 |
--------------------------------------------------------------------------------
/classes/extend/basic.js:
--------------------------------------------------------------------------------
1 | import Coupon from './extend';
2 |
3 | class FlashCoupon extends Coupon {
4 |
5 | }
6 |
7 | const flash = new FlashCoupon(10);
8 |
9 | flash.price;
10 | // 10
11 |
12 | flash.getPriceText();
13 | // "$ 10"
14 |
--------------------------------------------------------------------------------
/classes/extend/constructor.js:
--------------------------------------------------------------------------------
1 |
2 | import Coupon from './extend';
3 |
4 | class FlashCoupon extends Coupon {
5 | constructor(price, expiration) {
6 | super(price);
7 | this.expiration = expiration || 'two hours';
8 | }
9 | }
10 |
11 | const flash = new FlashCoupon(10);
12 |
13 | flash.price;
14 | // 10
15 |
16 | flash.getExpirationMessage();
17 | // "This offer expires in two hours"
18 |
--------------------------------------------------------------------------------
/classes/extend/extend.js:
--------------------------------------------------------------------------------
1 | class Coupon {
2 | constructor(price, expiration) {
3 | this.price = price;
4 | this.expiration = expiration || 'Two Weeks';
5 | }
6 |
7 | getPriceText() {
8 | return `$ ${this.price}`;
9 | }
10 |
11 | getExpirationMessage() {
12 | return `This offer expires in ${this.expiration}`;
13 | }
14 |
15 | isRewardsEligible(user) {
16 | return user.rewardsEligible && user.active;
17 | }
18 |
19 | getRewards(user) {
20 | if (this.isRewardsEligible(user)) {
21 | this.price = this.price * 0.9;
22 | }
23 | }
24 | }
25 |
26 | export default Coupon;
27 |
--------------------------------------------------------------------------------
/classes/extend/extend.spec.js:
--------------------------------------------------------------------------------
1 | import expect from 'expect';
2 | import Coupon from './extend';
3 | import { FlashCoupon } from './flash';
4 |
5 | describe('coupon', () => {
6 | it('should have rewards for users', () => {
7 | const coupon = new Coupon(10);
8 | const user = {
9 | rewardsEligible: true,
10 | active: true,
11 | };
12 | expect(coupon.price).toEqual(10);
13 | coupon.getRewards(user);
14 | expect(coupon.price).toEqual(9);
15 | });
16 |
17 | it('should not reward ineligible users', () => {
18 | const coupon = new Coupon(10);
19 | const user = {
20 | rewardsEligible: true,
21 | active: false,
22 | };
23 | expect(coupon.price).toEqual(10);
24 | coupon.getRewards(user);
25 | expect(coupon.price).toEqual(10);
26 | });
27 | });
28 |
29 | describe('flash coupon', () => {
30 | it('should call parent constructor', () => {
31 | const flash = new FlashCoupon(5);
32 | expect(flash.price).toEqual(5);
33 | });
34 |
35 | it('should inherit methods', () => {
36 | const flash = new FlashCoupon(5);
37 | expect(flash.getPriceText()).toEqual('$ 5');
38 | });
39 |
40 | it('should override parent methods', () => {
41 | const flash = new FlashCoupon(5);
42 | const message = 'This is a flash offer and expires in two hours.';
43 | expect(flash.getExpirationMessage()).toEqual(message);
44 | });
45 |
46 | it('should call parent methods for user authentication', () => {
47 | const flash = new FlashCoupon(100);
48 | const user = {
49 | rewardsEligible: true,
50 | active: true,
51 | };
52 | flash.getRewards(user);
53 | expect(flash.price).toEqual(80);
54 | });
55 |
56 | it('should not give rewards to inactive user', () => {
57 | const flash = new FlashCoupon(100);
58 | const user = {
59 | rewardsEligible: true,
60 | active: false,
61 | };
62 | flash.getRewards(user);
63 | expect(flash.price).toEqual(100);
64 | });
65 |
66 | it('should not give rewards to user when price is too low', () => {
67 | const flash = new FlashCoupon(10);
68 | const user = {
69 | rewardsEligible: true,
70 | active: true,
71 | };
72 | flash.getRewards(user);
73 | expect(flash.price).toEqual(10);
74 | });
75 | });
76 |
--------------------------------------------------------------------------------
/classes/extend/flash.js:
--------------------------------------------------------------------------------
1 | import Coupon from './extend';
2 |
3 | class FlashCoupon extends Coupon {
4 | constructor(price, expiration) {
5 | super(price);
6 | this.expiration = expiration || 'two hours';
7 | }
8 |
9 | getExpirationMessage() {
10 | return `This is a flash offer and expires in ${this.expiration}.`;
11 | }
12 |
13 | isRewardsEligible(user) {
14 | return super.isRewardsEligible(user) && this.price > 20;
15 | }
16 |
17 | getRewards(user) {
18 | if (this.isRewardsEligible(user)) {
19 | this.price = this.price * 0.8;
20 | }
21 | }
22 | }
23 |
24 | export { FlashCoupon };
25 |
--------------------------------------------------------------------------------
/classes/extend/method.js:
--------------------------------------------------------------------------------
1 | import Coupon from './extend';
2 |
3 | class FlashCoupon extends Coupon {
4 | constructor(price, expiration) {
5 | super(price);
6 | this.expiration = expiration || 'two hours';
7 | }
8 |
9 | getExpirationMessage() {
10 | return `This is a flash offer and expires in ${this.expiration}.`;
11 | }
12 | }
13 |
14 | const flash = new FlashCoupon(10);
15 |
16 | flash.price;
17 | // 10
18 |
19 | flash.getExpirationMessage();
20 | // "This is a flash offer and expires in two hours"
21 |
--------------------------------------------------------------------------------
/classes/generators/generators.js:
--------------------------------------------------------------------------------
1 | // START:final
2 | class FamilyTree {
3 | constructor() {
4 | this.family = {
5 | name: 'Doris',
6 | child: {
7 | name: 'Martha',
8 | child: {
9 | name: 'Dyan',
10 | child: {
11 | name: 'Bea',
12 | },
13 | },
14 | },
15 | };
16 | }
17 | * [Symbol.iterator]() {
18 | let node = this.family;
19 | while (node) {
20 | yield node.name;
21 | node = node.child;
22 | }
23 | }
24 | }
25 |
26 | const family = new FamilyTree();
27 | [...family];
28 | // ['Doris', 'Martha', 'Dyan', 'Bea'];
29 | // END:final
30 |
31 | export default FamilyTree;
32 |
--------------------------------------------------------------------------------
/classes/generators/generators.spec.js:
--------------------------------------------------------------------------------
1 | import expect from 'expect';
2 | import { getCairoTrilogy } from './simple';
3 | import FamilyTree from './generators';
4 | import FamilyTreeProblem from './problem';
5 |
6 | describe('Cairo trilogy', () => {
7 | it('returns each book of the Cairo trilogy', () => {
8 | const trilogy = getCairoTrilogy();
9 | expect(trilogy.next().value).toEqual('Palace Walk');
10 | expect(trilogy.next().value).toEqual('Palace of Desire');
11 | expect(trilogy.next().value).toEqual('Sugar Street');
12 | expect(trilogy.next().done).toEqual(true);
13 | });
14 |
15 | it('will spread the trilogy into an array', () => {
16 | const trilogy = [...getCairoTrilogy()];
17 | expect(trilogy).toEqual([
18 | 'Palace Walk',
19 | 'Palace of Desire',
20 | 'Sugar Street',
21 | ]);
22 | });
23 |
24 | it('will add books to a reading list', () => {
25 | const readingList = {
26 | 'Visit from the Goon Squad': true,
27 | 'Manhattan Beach': false,
28 | };
29 | for (const book of getCairoTrilogy()) {
30 | readingList[book] = false;
31 | }
32 | expect(readingList).toEqual({
33 | 'Visit from the Goon Squad': true,
34 | 'Manhattan Beach': false,
35 | 'Palace Walk': false,
36 | 'Palace of Desire': false,
37 | 'Sugar Street': false,
38 | });
39 | });
40 | });
41 | describe('should create an array of family members', () => {
42 | it('should get a list of family members with a method', () => {
43 | const family = new FamilyTreeProblem();
44 | expect(family.getMembers()).toEqual(['Doris', 'Martha', 'Dyan', 'Bea']);
45 | });
46 | it('should get a list of family members', () => {
47 | const family = new FamilyTree();
48 | expect([...family]).toEqual(['Doris', 'Martha', 'Dyan', 'Bea']);
49 | });
50 | });
51 |
--------------------------------------------------------------------------------
/classes/generators/problem.js:
--------------------------------------------------------------------------------
1 | class FamilyTree {
2 | constructor() {
3 | this.family = {
4 | name: 'Doris',
5 | child: {
6 | name: 'Martha',
7 | child: {
8 | name: 'Dyan',
9 | child: {
10 | name: 'Bea',
11 | },
12 | },
13 | },
14 | };
15 | }
16 | getMembers() {
17 | const family = [];
18 | let node = this.family;
19 | while (node) {
20 | family.push(node.name);
21 | node = node.child;
22 | }
23 | return family;
24 | }
25 | }
26 |
27 | const family = new FamilyTree();
28 | family.getMembers();
29 | // ['Doris', 'Martha', 'Dyan', 'Bea'];
30 |
31 | export default FamilyTree;
32 |
--------------------------------------------------------------------------------
/classes/generators/simple.js:
--------------------------------------------------------------------------------
1 | // START: next
2 | function* getCairoTrilogy() {
3 | yield 'Palace Walk';
4 | yield 'Palace of Desire';
5 | yield 'Sugar Street';
6 | }
7 |
8 | const trilogy = getCairoTrilogy();
9 | trilogy.next();
10 | // { value: 'Palace Walk', done: false }
11 | trilogy.next();
12 | // { value: 'Palace of Desire', done: false }
13 | trilogy.next();
14 | // { value: 'Sugar Street', done: false }
15 | trilogy.next();
16 | // { value: undefined, done: true }
17 | // END: next
18 |
19 | // START: spread
20 | [...getCairoTrilogy];
21 | // [ 'Palace Walk', 'Palace of Desire', 'Sugar Street']
22 | // END: spread
23 |
24 | // START: loop
25 | const readingList = {
26 | 'Visit from the Goon Squad': true,
27 | 'Manhattan Beach': false,
28 | };
29 | for (const book of getCairoTrilogy()) {
30 | readingList[book] = false;
31 | }
32 | readingList;
33 | // {
34 | // 'Visit from the Goon Squad': true,
35 | // 'Manhattan Beach': false,
36 | // 'Palace Walk': false,
37 | // 'Palace of Desire': false,
38 | // 'Sugar Street': false
39 | // }
40 |
41 | // END: loop
42 |
43 | export { getCairoTrilogy };
44 |
--------------------------------------------------------------------------------
/classes/get/get.js:
--------------------------------------------------------------------------------
1 | // START:solution
2 | class Coupon {
3 | constructor(price, expiration) {
4 | this._price = price;
5 | this.expiration = expiration || 'Two Weeks';
6 | }
7 |
8 | get priceText() {
9 | return `$${this._price}`;
10 | }
11 |
12 | get price() {
13 | return this._price;
14 | }
15 |
16 | set price(price) {
17 | const newPrice = price
18 | .toString()
19 | .replace(/[^\d]/g, '');
20 | this._price = newPrice;
21 | }
22 |
23 | get expirationMessage() {
24 | return `This offer expires in ${this.expiration}`;
25 | }
26 | }
27 |
28 | const coupon = new Coupon(5);
29 | coupon.price;
30 | // 5
31 |
32 | coupon.price = '$10';
33 |
34 | coupon.price;
35 | // 10
36 |
37 | coupon.priceText;
38 | // $ 10
39 | // END:solution
40 | export default Coupon;
41 |
--------------------------------------------------------------------------------
/classes/get/get.spec.js:
--------------------------------------------------------------------------------
1 | import expect from 'expect';
2 |
3 | import Coupon from './get';
4 | import CouponProblem from './problem';
5 | import CouponGetters from './price';
6 | import CouponSet from './set';
7 |
8 | describe('get problem', () => {
9 | it('should set price as a string', () => {
10 | const coupon = new CouponProblem(5);
11 | coupon.price = '$10';
12 | expect(coupon.getPriceText()).toEqual('$ $10');
13 | });
14 | });
15 |
16 | describe('Getters', () => {
17 | const coupon = new CouponGetters(10);
18 | it('should get price text', () => {
19 | expect(coupon.priceText).toEqual('$ 10');
20 | });
21 |
22 | it('should get expiration text', () => {
23 | const message = 'This offer expires in two weeks.';
24 | expect(coupon.expirationMessage).toEqual(message);
25 | });
26 | });
27 |
28 | describe('Setters', () => {
29 | const coupon = new CouponSet(10);
30 | it('should get price', () => {
31 | expect(coupon.price).toEqual(10);
32 | });
33 |
34 | it('should set halfPrice', () => {
35 | coupon.halfPrice = 40;
36 | expect(coupon.price).toEqual(20);
37 | });
38 | });
39 |
40 | describe('getters and setters', () => {
41 | it('should get a inner variable', () => {
42 | const coupon = new Coupon(10);
43 | expect(coupon.price).toEqual(coupon._price);
44 | });
45 |
46 | it('should set inner property', () => {
47 | const coupon = new Coupon(10);
48 | expect(coupon.price).toEqual(10);
49 | coupon.price = 100;
50 | expect(coupon.price).toEqual(100);
51 | });
52 |
53 | it('should parse int when setting', () => {
54 | const coupon = new Coupon(10);
55 | expect(coupon.price).toEqual(10);
56 | coupon.price = '$100';
57 | expect(coupon.price).toEqual(100);
58 | });
59 |
60 | it('should get a message', () => {
61 | const coupon = new Coupon(10);
62 | expect(coupon.priceText).toEqual('$10');
63 | });
64 | });
65 |
--------------------------------------------------------------------------------
/classes/get/invalid.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-unused-vars */
2 | // START:coupon
3 | class Coupon {
4 | constructor(price, expiration) {
5 | this.price = price;
6 | this.expiration = expiration || 'Two Weeks';
7 | }
8 |
9 | get price() {
10 | return this.price;
11 | }
12 |
13 | set price(price) {
14 | this.price = `$ ${price}`;
15 | }
16 | }
17 |
18 | const coupon = new Coupon(5);
19 | // RangeError: Maximum call stack size exceeded
20 | // END:coupon
21 |
--------------------------------------------------------------------------------
/classes/get/price.js:
--------------------------------------------------------------------------------
1 | // START:getter
2 | class Coupon {
3 | constructor(price, expiration) {
4 | this.price = price;
5 | this.expiration = expiration || 'two weeks';
6 | }
7 |
8 | get priceText() {
9 | return `$ ${this.price}`;
10 | }
11 |
12 | get expirationMessage() {
13 | return `This offer expires in ${this.expiration}.`;
14 | }
15 | }
16 | // END:getter
17 |
18 | // START:use
19 | const coupon = new Coupon(5);
20 | coupon.price = 10;
21 | coupon.priceText;
22 | // '$10'
23 | coupon.messageText;
24 | // 'This offer expires in two weeks.
25 | coupon.messageText;
26 | // END:use
27 |
28 | export default Coupon;
29 |
--------------------------------------------------------------------------------
/classes/get/problem.js:
--------------------------------------------------------------------------------
1 | // START:problem
2 | class Coupon {
3 | constructor(price, expiration) {
4 | this.price = price;
5 | this.expiration = expiration || 'Two Weeks';
6 | }
7 |
8 | getPriceText() {
9 | return `$ ${this.price}`;
10 | }
11 |
12 | getExpirationMessage() {
13 | return `This offer expires in ${this.expiration}`;
14 | }
15 | }
16 |
17 | const coupon = new Coupon(5);
18 | coupon.price = '$10';
19 | coupon.getPriceText();
20 | // '$ $10'
21 | // END:problem
22 |
23 | export default Coupon;
24 |
--------------------------------------------------------------------------------
/classes/get/set.js:
--------------------------------------------------------------------------------
1 | // START:set
2 | class Coupon {
3 | constructor(price, expiration) {
4 | this.price = price;
5 | this.expiration = expiration || 'Two Weeks';
6 | }
7 |
8 | set halfPrice(price) {
9 | this.price = price / 2;
10 | }
11 | }
12 | // END:set
13 |
14 | // START:use
15 | const coupon = new Coupon(5);
16 | coupon.price;
17 | // 5
18 | coupon.halfPrice = 20;
19 | coupon.price;
20 | // 10
21 | coupon.halfPrice;
22 | // undefined
23 | // END:use
24 |
25 | export default Coupon;
26 |
--------------------------------------------------------------------------------
/classes/prototypes/class.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable func-names */
2 | // START:class
3 | class Coupon {
4 | constructor(price, expiration) {
5 | this.price = price;
6 | this.expiration = expiration || 'Two Weeks';
7 | }
8 |
9 | getExpirationMessage() {
10 | return `This offer expires in ${this.expiration}.`;
11 | }
12 | }
13 |
14 | const saleCoupon = new Coupon(5, 'two months');
15 | saleCoupon.getExpirationMessage();
16 | // This offer expires in two months.
17 |
18 | // END:class
19 |
20 | class FlashCoupon extends Coupon {
21 | constructor(...args) {
22 | super(args);
23 | this.expiration = 'Two Hours';
24 | }
25 |
26 | getExpirationMessage() {
27 | return `This is a flash offer and expires in ${this.expiration}`;
28 | }
29 | }
30 |
31 | export { Coupon, FlashCoupon };
32 |
--------------------------------------------------------------------------------
/classes/prototypes/prototypes.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable func-names */
2 | // START:instance
3 | function Coupon(price, expiration) {
4 | this.price = price;
5 | this.expiration = expiration || 'two weeks';
6 | }
7 | const coupon = new Coupon(5, 'two months');
8 | coupon.price;
9 | // 5
10 | // END:instance
11 |
12 | // START:prototype
13 | Coupon.prototype.getExpirationMessage = function () {
14 | return `This offer expires in ${this.expiration}.`;
15 | };
16 | coupon.getExpirationMessage();
17 | // This offer expires in two months.
18 |
19 | // END:prototype
20 |
21 | // START:extend
22 | class FlashCoupon extends Coupon {
23 | constructor(price, expiration) {
24 | super(price);
25 | this.expiration = expiration || 'two hours';
26 | }
27 |
28 | getExpirationMessage() {
29 | return `This is a flash offer and expires in ${this.expiration}.`;
30 | }
31 | }
32 | // END:extend
33 |
34 | export { Coupon, FlashCoupon };
35 |
--------------------------------------------------------------------------------
/classes/prototypes/prototypes.spec.js:
--------------------------------------------------------------------------------
1 | import expect from 'expect';
2 |
3 | import { Coupon, FlashCoupon } from './prototypes';
4 |
5 | describe('prototypes', () => {
6 | it('should have methods on a prototype', () => {
7 | const coupon = new Coupon(5, 'two months');
8 | const message = 'This offer expires in two months.';
9 | expect(coupon.price).toEqual(5);
10 | expect(coupon.getExpirationMessage()).toEqual(message);
11 | });
12 |
13 | it('should extend a prototype', () => {
14 | const flash = new FlashCoupon(5);
15 | const message = 'This is a flash offer and expires in two hours.';
16 | expect(flash.price).toEqual(5);
17 | expect(flash.getExpirationMessage()).toEqual(message);
18 | });
19 | });
20 |
--------------------------------------------------------------------------------
/collections/assign/assign.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-unused-vars */
2 |
3 | // # START:pure
4 | const defaults = { author: '',
5 | title: '',
6 | year: 2017,
7 | rating: null,
8 | };
9 |
10 | const book = {
11 | author: 'Joe Morgan',
12 | title: 'Simplifying JavaScript',
13 | };
14 |
15 | const updated = Object.assign({}, defaults, book);
16 | // # END:pure
17 |
18 | // # START:deep
19 | const defaultEmployee = {
20 | name: {
21 | first: '',
22 | last: '',
23 | },
24 | years: 0,
25 | };
26 |
27 | const employee = Object.assign({}, defaultEmployee);
28 | // # END:deep
29 |
30 | // # START:deepMutate
31 | employee.name.first = 'Joe';
32 |
33 | defaultEmployee;
34 |
35 | // {
36 | // name: {
37 | // first:'Joe',
38 | // last: '',
39 | // },
40 | // years: 0
41 | // }
42 | // # END:deepMutate
43 |
44 |
45 | // # START:deepMerge
46 | const employee2 = Object.assign(
47 | {},
48 | defaultEmployee,
49 | {
50 | name: Object.assign({}, defaultEmployee.name),
51 | },
52 | );
53 | // # END:endMerge
54 |
55 | export { defaults };
56 |
--------------------------------------------------------------------------------
/collections/assign/assign.spec.js:
--------------------------------------------------------------------------------
1 | import expect from 'expect';
2 | import { addBookDefaults } from './problem';
3 |
4 | describe('Assign tests', () => {
5 | const defaults = {
6 | author: '',
7 | title: '',
8 | year: 2017,
9 | rating: null,
10 | };
11 |
12 | const book = {
13 | title: 'Simplifying JavaScript',
14 | author: 'Joe Morgan',
15 | };
16 |
17 | it('should add defaults', () => {
18 | const bookUpdated = addBookDefaults(book, defaults);
19 | expect(bookUpdated.title).toEqual('Simplifying JavaScript');
20 | expect(bookUpdated.year).toEqual(2017);
21 | });
22 |
23 | it('should add defaults with assign', () => {
24 | const copy = Object.assign({}, defaults);
25 | const book2 = {
26 | title: 'Another book',
27 | year: 2016,
28 | };
29 | const bookUpdated = Object.assign(copy, book);
30 | expect(bookUpdated.title).toEqual('Simplifying JavaScript');
31 | expect(bookUpdated.author).toEqual('Joe Morgan');
32 | expect(bookUpdated.year).toEqual(2017);
33 | const bookUpdated2 = Object.assign(copy, book2);
34 | expect(bookUpdated2.title).toEqual('Another book');
35 | expect(bookUpdated2.author).toEqual('Joe Morgan');
36 | expect(bookUpdated2.year).toEqual(2016);
37 | });
38 |
39 | it('should add defaults with assign', () => {
40 | const bookUpdated = Object.assign({}, defaults, book);
41 | expect(bookUpdated.title).toEqual('Simplifying JavaScript');
42 | expect(bookUpdated.year).toEqual(2017);
43 | });
44 | });
45 |
--------------------------------------------------------------------------------
/collections/assign/mutate.js:
--------------------------------------------------------------------------------
1 |
2 | const book = {
3 | author: 'Joe Morgan',
4 | title: 'Simplifying JavaScript',
5 | };
6 |
7 | const defaults = {
8 | author: '',
9 | title: '',
10 | year: 2017,
11 | rating: null,
12 | };
13 |
14 | // # START:mutate
15 | Object.assign(defaults, book);
16 |
17 | // {
18 | // author: 'Joe Morgan',
19 | // title: 'Simplifying JavaScript',
20 | // year: 2017,
21 | // rating: null,
22 | // }
23 | // # END:mutate
24 |
25 | // # START:mutate2
26 | const anotherBook = {
27 | title: 'Another book',
28 | year: 2016,
29 | };
30 |
31 | Object.assign(defaults, anotherBook);
32 |
33 | // {
34 | // author: 'Joe Morgan',
35 | // title: 'Another book',
36 | // year: 2016,
37 | // rating: null,
38 | // }
39 | // # END:mutate2
40 |
--------------------------------------------------------------------------------
/collections/assign/problem.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-unused-vars */
2 |
3 | const original = {
4 | author: '',
5 | title: '',
6 | year: 2017,
7 | rating: null,
8 | };
9 | // # START:add
10 | const defaults = {
11 | author: '',
12 | title: '',
13 | year: 2017,
14 | rating: null,
15 | };
16 |
17 | const book = {
18 | author: 'Joe Morgan',
19 | title: 'Simplifying JavaScript',
20 | };
21 |
22 | function addBookDefaults(book, defaults) {
23 | const fields = Object.keys(defaults);
24 | const updated = {};
25 | for (let i = 0; i < fields.length; i++) {
26 | const field = fields[i];
27 | updated[field] = book[field] || defaults[field];
28 | }
29 | return updated;
30 | }
31 | // # END:add
32 |
33 | export { addBookDefaults, defaults };
34 |
--------------------------------------------------------------------------------
/collections/map/map.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-param-reassign, no-unused-vars */
2 |
3 | // # START:mapActions
4 | const petFilters = new Map();
5 | function addFilters(filters, key, value) {
6 | filters.set(key, value);
7 | }
8 |
9 | function deleteFilters(filters, key) {
10 | filters.delete(key);
11 | }
12 |
13 | function clearFilters(filters) {
14 | filters.clear();
15 | }
16 | // # END:mapActions
17 |
18 | export {
19 | addFilters,
20 | deleteFilters,
21 | clearFilters,
22 | };
23 |
--------------------------------------------------------------------------------
/collections/map/map.spec.js:
--------------------------------------------------------------------------------
1 | import expect from 'expect';
2 |
3 | import {
4 | addFilters,
5 | clearFilters,
6 | deleteFilters,
7 | } from './map';
8 |
9 | import {
10 | addFilters as addFiltersObject,
11 | clearFilters as clearFiltersObject,
12 | deleteFilters as deleteFiltersObject,
13 | } from './problem';
14 |
15 | describe('Map tests', () => {
16 | it('should set value on object', () => {
17 | const filters = {
18 | color: 'brown',
19 | };
20 | addFiltersObject(filters, 'size', 'large');
21 | expect(filters.size).toEqual('large');
22 | });
23 |
24 | it('should delete the value on object', () => {
25 | const filters = {
26 | color: 'brown',
27 | size: 'large',
28 | };
29 | deleteFiltersObject(filters, 'color');
30 | expect(filters).toEqual({ size: 'large' });
31 | });
32 |
33 | it('should clear the object', () => {
34 | let filters = {
35 | color: 'brown',
36 | size: 'large',
37 | };
38 | filters = clearFiltersObject(filters);
39 | expect(filters).toEqual({});
40 | });
41 |
42 | it('should set value on object', () => {
43 | const filters = new Map().set('color', 'brown');
44 | addFilters(filters, 'size', 'large');
45 | expect(filters.get('size')).toEqual('large');
46 | });
47 |
48 | it('should delete the value on object', () => {
49 | const filters = new Map()
50 | .set('color', 'brown')
51 | .set('size', 'large');
52 | deleteFilters(filters, 'color');
53 | expect([...filters.keys()]).toEqual(['size']);
54 | });
55 |
56 | it('should clear the object', () => {
57 | const filters = new Map()
58 | .set('color', 'brown')
59 | .set('size', 'large');
60 | clearFilters(filters);
61 | expect([...filters.keys()]).toEqual([]);
62 | });
63 | });
64 |
--------------------------------------------------------------------------------
/collections/map/problem.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-param-reassign, no-unused-vars */
2 |
3 | // # START:objectActions
4 | function addFilters(filters, key, value) {
5 | filters[key] = value;
6 | }
7 |
8 | function deleteFilters(filters, key) {
9 | delete filters[key];
10 | }
11 |
12 | function clearFilters(filters) {
13 | filters = {};
14 | return filters;
15 | }
16 | // # END:objectActions
17 |
18 | export {
19 | addFilters,
20 | deleteFilters,
21 | clearFilters,
22 | };
23 |
--------------------------------------------------------------------------------
/collections/mapSideEffects/copy.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-restricted-syntax */
2 |
3 | // # START:apply
4 | function applyDefaults(map, defaults) {
5 | const copy = new Map([...map]);
6 | for (const [key, value] of defaults) {
7 | if (!copy.has(key)) {
8 | copy.set(key, value);
9 | }
10 | }
11 | return copy;
12 | }
13 | // # END:apply
14 |
15 | export { applyDefaults };
16 |
--------------------------------------------------------------------------------
/collections/mapSideEffects/map.js:
--------------------------------------------------------------------------------
1 | // START:apply
2 | function applyDefaults(map, defaults) {
3 | return new Map([...defaults, ...map]);
4 | }
5 | // END:apply
6 |
7 | export { applyDefaults };
8 |
--------------------------------------------------------------------------------
/collections/mapSideEffects/map.spec.js:
--------------------------------------------------------------------------------
1 | import expect from 'expect';
2 |
3 | import { applyDefaults } from './map';
4 |
5 | import { applyDefaults as applySideEffects } from './sideEffects';
6 |
7 | import { applyDefaults as applyCopy } from './copy';
8 |
9 | describe('apply defaults to a map', () => {
10 | it('should mutate the original', () => {
11 | const defaults = new Map()
12 | .set('color', 'brown')
13 | .set('breed', 'beagle')
14 | .set('state', 'kansas');
15 |
16 |
17 | const filters = new Map()
18 | .set('color', 'black');
19 |
20 | applySideEffects(filters, defaults);
21 |
22 | expect(filters.get('color')).toEqual('black');
23 | expect(filters.get('state')).toEqual('kansas');
24 | });
25 |
26 | it('should set new key-value', () => {
27 | const defaults = new Map()
28 | .set('color', 'brown')
29 | .set('breed', 'beagle')
30 | .set('state', 'kansas');
31 |
32 |
33 | const filters = new Map()
34 | .set('color', 'black');
35 |
36 | const update = applyCopy(filters, defaults);
37 | expect(update.get('color')).toEqual('black');
38 | expect(update.get('state')).toEqual('kansas');
39 | });
40 |
41 | it('should set new key-value', () => {
42 | const defaults = new Map()
43 | .set('color', 'brown')
44 | .set('breed', 'beagle')
45 | .set('state', 'kansas');
46 |
47 |
48 | const filters = new Map()
49 | .set('color', 'black');
50 |
51 | const update = applyDefaults(filters, defaults);
52 | expect(update.get('color')).toEqual('black');
53 | expect(update.get('state')).toEqual('kansas');
54 | });
55 | });
56 |
--------------------------------------------------------------------------------
/collections/mapSideEffects/sideEffects.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-restricted-syntax, no-unused-vars */
2 |
3 | // # START:maps
4 | const defaults = new Map()
5 | .set('color', 'brown')
6 | .set('breed', 'beagle')
7 | .set('state', 'kansas');
8 |
9 |
10 | const filters = new Map()
11 | .set('color', 'black');
12 |
13 | // # END:maps
14 |
15 | // # START:apply
16 | function applyDefaults(map, defaults) {
17 | for (const [key, value] of defaults) {
18 | if (!map.has(key)) {
19 | map.set(key, value);
20 | }
21 | }
22 | }
23 | // # START:apply
24 |
25 | export { applyDefaults };
26 |
--------------------------------------------------------------------------------
/collections/mapSpread/iterate.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-console, no-unused-vars, no-restricted-syntax */
2 |
3 | // START:iterate
4 | const filters = new Map()
5 | .set('color', 'black')
6 | .set('breed', 'labrador');
7 |
8 | function checkFilters(filters) {
9 | for (const entry of filters) {
10 | console.log(entry);
11 | }
12 | }
13 | // ['color', 'black']
14 | // ['breed', 'labrador']
15 | // END:iterate
16 |
17 | // START:iterateGet
18 | function getAppliedFilters(filters) {
19 | const applied = [];
20 | for (const [key, value] of filters) {
21 | applied.push(`${key}:${value}`);
22 | }
23 | return `Your filters are: ${applied.join(', ')}.`;
24 | }
25 |
26 | // 'Your filters are: color:black, breed:labrador.'
27 | // END:iterateGet
28 |
29 | // START:iterateSort
30 | function sortByKey(a, b) {
31 | return a[0] > b[0] ? 1 : -1;
32 | }
33 |
34 | function getSortedAppliedFilters(filters) {
35 | const applied = [];
36 | for (const [key, value] of [...filters].sort(sortByKey)) {
37 | applied.push(`${key}:${value}`);
38 | }
39 | return `Your filters are: ${applied.join(', ')}.`;
40 | }
41 | // 'Your filters are: breed:labrador, color:black.'
42 | // END:iterateSort
43 |
44 | export { getAppliedFilters, getSortedAppliedFilters };
45 |
--------------------------------------------------------------------------------
/collections/mapSpread/mapSpread.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-unused-vars */
2 |
3 | const filters = new Map()
4 | .set('color', 'black')
5 | .set('breed', 'labrador');
6 |
7 | // START:get
8 | function getAppliedFilters(filters) {
9 | const applied = [...filters].map(([key, value]) => {
10 | return `${key}:${value}`;
11 | });
12 | return `Your filters are: ${applied.join(', ')}.`;
13 | }
14 |
15 | // 'Your filters are: color:black, breed:labrador.'
16 | // END:get
17 |
18 | function sortByKey(a, b) {
19 | return a[0] > b[0] ? 1 : -1;
20 | }
21 |
22 | // START:sort
23 | function getSortedAppliedFilters(filters) {
24 | const applied = [...filters]
25 | .sort(sortByKey)
26 | .map(([key, value]) => {
27 | return `${key}:${value}`;
28 | })
29 | .join(', ');
30 |
31 | return `Your filters are: ${applied}.`;
32 | }
33 | // 'Your filters are: breed:labrador, color:black.'
34 | // END:sort
35 |
36 | export { getAppliedFilters, getSortedAppliedFilters };
37 |
--------------------------------------------------------------------------------
/collections/mapSpread/mapSpread.spec.js:
--------------------------------------------------------------------------------
1 | import expect from 'expect';
2 |
3 | import {
4 | getAppliedFilters as getObject,
5 | getSortedAppliedFilters as getSortObject,
6 | } from './object';
7 |
8 | import {
9 | getAppliedFilters as getIterate,
10 | getSortedAppliedFilters as getSortIterate,
11 | } from './iterate';
12 |
13 | import {
14 | getAppliedFilters,
15 | getSortedAppliedFilters,
16 | } from './mapSpread';
17 |
18 | describe('object get', () => {
19 | it('should get key-values from object', () => {
20 | const filters = {
21 | color: 'black',
22 | breed: 'labrador',
23 | };
24 | expect(getObject(filters)).toEqual('Your filters are: color:black, breed:labrador.');
25 | });
26 |
27 | it('should get sorted key-values from object', () => {
28 | const filters = {
29 | color: 'black',
30 | breed: 'labrador',
31 | };
32 | expect(getSortObject(filters)).toEqual('Your filters are: breed:labrador, color:black.');
33 | });
34 | });
35 |
36 | describe('map iterate', () => {
37 | it('should get key-values from object', () => {
38 | const filters = new Map()
39 | .set('color', 'black')
40 | .set('breed', 'labrador');
41 |
42 | expect(getIterate(filters)).toEqual('Your filters are: color:black, breed:labrador.');
43 | });
44 |
45 | it('should get sorted key-values from object', () => {
46 | const filters = new Map()
47 | .set('color', 'black')
48 | .set('breed', 'labrador');
49 |
50 | expect(getSortIterate(filters)).toEqual('Your filters are: breed:labrador, color:black.');
51 | });
52 | });
53 |
54 | describe('map spread', () => {
55 | it('should get key-values from object', () => {
56 | const filters = new Map()
57 | .set('color', 'black')
58 | .set('breed', 'labrador');
59 |
60 | expect(getAppliedFilters(filters)).toEqual('Your filters are: color:black, breed:labrador.');
61 | });
62 |
63 | it('should get sorted key-values from object', () => {
64 | const filters = new Map()
65 | .set('color', 'black')
66 | .set('breed', 'labrador');
67 |
68 | expect(getSortedAppliedFilters(filters)).toEqual('Your filters are: breed:labrador, color:black.');
69 | });
70 | });
71 |
--------------------------------------------------------------------------------
/collections/mapSpread/object.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-unused-vars, no-restricted-syntax */
2 |
3 | // # START:objectIterate
4 | const filters = {
5 | color: 'black',
6 | breed: 'labrador',
7 | };
8 |
9 | function getAppliedFilters(filters) {
10 | const keys = Object.keys(filters);
11 | const applied = [];
12 | for (const key of keys) {
13 | applied.push(`${key}:${filters[key]}`);
14 | }
15 | return `Your filters are: ${applied.join(', ')}.`;
16 | }
17 |
18 | // 'Your filters are: color:black, breed:labrador.'
19 | // # END:objectIterate
20 |
21 |
22 | // # START:objectSortIterate
23 | function getSortedAppliedFilters(filters) {
24 | const keys = Object.keys(filters);
25 | keys.sort();
26 | const applied = [];
27 | for (const key of keys) {
28 | applied.push(`${key}:${filters[key]}`);
29 | }
30 | return `Your filters are: ${applied.join(', ')}.`;
31 | }
32 | // 'Your filters are: breed:labrador, color:black.'
33 | // # END:objectSortIterate
34 |
35 | export {
36 | getAppliedFilters,
37 | getSortedAppliedFilters,
38 | };
39 |
--------------------------------------------------------------------------------
/collections/object/object.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-undef, no-unused-vars */
2 |
3 | // # START:book
4 | const book = {
5 | title: 'ES6 Tips',
6 | author: 'Joe Morgan',
7 | date: 2017,
8 | };
9 | // # END:book
10 |
11 | // # START:config
12 | export const config = {
13 | endpoint: 'http://pragprog.com',
14 | key: 'secretkey',
15 | };
16 | // # END:config
17 |
18 | // # START:between
19 | function getBill(item) {
20 | return {
21 | name: item.name,
22 | due: twoWeeksFromNow(),
23 | total: calculateTotal(item.price),
24 | };
25 | }
26 |
27 | const bill = getBill({ name: 'Room Cleaning', price: 30 });
28 |
29 | function displayBill(bill) {
30 | return `Your total ${bill.total} for ${bill.name} is due on ${bill.due}`;
31 | }
32 | // # END:between
33 |
--------------------------------------------------------------------------------
/collections/objectSpread/objectSpread.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-unused-vars */
2 |
3 | function updateBookYear() {
4 | // # START:year
5 | const book = {
6 | title: 'Reasons and Persons',
7 | author: 'Derek Parfit',
8 | };
9 |
10 | const update = { ...book, year: 1984 };
11 |
12 | // { title: 'Reasons and Persons', author: 'Derek Parfit', year: 1984}
13 | // # END:year
14 | return update;
15 | }
16 |
17 | function updateBookTitle() {
18 | // # START:title
19 | const book = {
20 | title: 'Reasons and Persons',
21 | author: 'Derek Parfit',
22 | };
23 |
24 | const update = { ...book, title: 'Reasons & Persons' };
25 |
26 | // { title: 'Reasons & Persons', author: 'Derek Parfit' }
27 | // # END:title
28 | return update;
29 | }
30 |
31 | function addBookDefaults() {
32 | // # START:add
33 | const defaults = {
34 | author: '',
35 | title: '',
36 | year: 2017,
37 | rating: null,
38 | };
39 |
40 | const book = {
41 | author: 'Joe Morgan',
42 | title: 'ES6 Tips',
43 | };
44 |
45 |
46 | const bookWithDefaults = { ...defaults, ...book };
47 |
48 | // {
49 | // author: 'Joe Morgan',
50 | // title: 'ES6 Tips',
51 | // year: 2017,
52 | // rating: null,
53 | // }
54 | // # END:add
55 |
56 | return bookWithDefaults;
57 | }
58 |
59 | function deepMerge() {
60 | const defaultEmployee = {
61 | name: {
62 | first: '',
63 | last: '',
64 | },
65 | years: 0,
66 | };
67 | // # START:deepMerge
68 | const employee = {
69 | ...defaultEmployee,
70 | name: {
71 | ...defaultEmployee.name,
72 | },
73 | };
74 | // # END:deepMerge
75 |
76 | employee.name.first = 'joe';
77 | return [defaultEmployee.name.first, employee.name.first];
78 | }
79 | export { addBookDefaults, deepMerge, updateBookTitle, updateBookYear };
80 |
--------------------------------------------------------------------------------
/collections/objectSpread/objectSpread.spec.js:
--------------------------------------------------------------------------------
1 | import expect from 'expect';
2 | import { addBookDefaults, deepMerge, updateBookYear, updateBookTitle } from './objectSpread';
3 |
4 | describe('Spread tests', () => {
5 | it('should update book year', () => {
6 | const updated = {
7 | title: 'Reasons and Persons',
8 | author: 'Derek Parfit',
9 | year: 1984,
10 | };
11 |
12 | expect(updateBookYear()).toEqual(updated);
13 | });
14 |
15 | it('should update book author', () => {
16 | const updated = {
17 | title: 'Reasons & Persons',
18 | author: 'Derek Parfit',
19 | };
20 | expect(updateBookTitle()).toEqual(updated);
21 | });
22 |
23 | it('should add defaults', () => {
24 | const bookUpdated = addBookDefaults();
25 | expect(bookUpdated.title).toEqual('ES6 Tips');
26 | expect(bookUpdated.year).toEqual(2017);
27 | });
28 |
29 | it('should deep merge', () => {
30 | const [name1, name2] = deepMerge();
31 | expect(name1).toNotEqual(name2);
32 | });
33 | });
34 |
--------------------------------------------------------------------------------
/collections/set/set.js:
--------------------------------------------------------------------------------
1 | // #START:unique
2 | function getUnique(attributes) {
3 | return [...new Set(attributes)];
4 | }
5 | // #END:unique
6 |
7 | // #START:uniqueColors
8 | function getUniqueColors(dogs) {
9 | const unique = new Set();
10 | for (const dog of dogs) {
11 | unique.add(dog.color);
12 | }
13 | return [...unique];
14 | }
15 | // #END:uniqueColors
16 |
17 | function getUniqueColorsReduce(dogs) {
18 | const colors =
19 | // #START:uniqueReduce
20 | [...dogs.reduce((colors, { color }) => colors.add(color), new Set())];
21 | // #END:uniqueReduce
22 | return colors;
23 | }
24 |
25 | export { getUnique, getUniqueColors, getUniqueColorsReduce };
26 |
--------------------------------------------------------------------------------
/collections/set/set.spec.js:
--------------------------------------------------------------------------------
1 | import expect from 'expect';
2 |
3 | import {
4 | getUnique as uniqueLoop,
5 | } from './unique';
6 |
7 | import {
8 | getUnique,
9 | getUniqueColors,
10 | getUniqueColorsReduce,
11 | } from './set';
12 |
13 | describe('set', () => {
14 | it('should get unique with a loop', () => {
15 | const colors = ['black', 'black', 'chocolate', 'yellow'];
16 | expect(uniqueLoop(colors)).toEqual(['black', 'chocolate', 'yellow']);
17 | });
18 |
19 | it('should get unique with Set', () => {
20 | const colors = ['black', 'black', 'chocolate', 'yellow'];
21 | expect(getUnique(colors)).toEqual(['black', 'chocolate', 'yellow']);
22 | });
23 |
24 | it('should get unique colors Set', () => {
25 | const dogs = [
26 | {
27 | name: 'max',
28 | size: 'small',
29 | breed: 'boston terrier',
30 | color: 'black',
31 | },
32 | {
33 | name: 'don',
34 | size: 'large',
35 | breed: 'labrador',
36 | color: 'black',
37 | },
38 | {
39 | name: 'shadow',
40 | size: 'medium',
41 | breed: 'labrador',
42 | color: 'chocolate',
43 | },
44 | ];
45 | expect(getUniqueColors(dogs)).toEqual(['black', 'chocolate']);
46 | });
47 |
48 | it('should get unique colors with Set and reducer', () => {
49 | const dogs = [
50 | {
51 | name: 'max',
52 | size: 'small',
53 | breed: 'boston terrier',
54 | color: 'black',
55 | },
56 | {
57 | name: 'don',
58 | size: 'large',
59 | breed: 'labrador',
60 | color: 'black',
61 | },
62 | {
63 | name: 'shadow',
64 | size: 'medium',
65 | breed: 'labrador',
66 | color: 'chocolate',
67 | },
68 | ];
69 | expect(getUniqueColorsReduce(dogs)).toEqual(['black', 'chocolate']);
70 | });
71 | });
72 |
--------------------------------------------------------------------------------
/collections/set/unique.js:
--------------------------------------------------------------------------------
1 | // #START:dog
2 | const dogs = [
3 | {
4 | name: 'max',
5 | size: 'small',
6 | breed: 'boston terrier',
7 | color: 'black',
8 | },
9 | {
10 | name: 'don',
11 | size: 'large',
12 | breed: 'labrador',
13 | color: 'black',
14 | },
15 | {
16 | name: 'shadow',
17 | size: 'medium',
18 | breed: 'labrador',
19 | color: 'chocolate',
20 | },
21 | ];
22 | // #END:dogs
23 | // #START:colors
24 | function getColors(dogs) {
25 | return dogs.map(dog => dog.color);
26 | }
27 |
28 | getColors(dogs);
29 |
30 | // ['black', 'black', 'chocolate']
31 |
32 | // #END:colors
33 |
34 | // #START:unique
35 |
36 | function getUnique(attributes) {
37 | const unique = [];
38 | for (const attribute of attributes) {
39 | if (!unique.includes(attribute)) {
40 | unique.push(attribute);
41 | }
42 | }
43 | return unique;
44 | }
45 |
46 | const colors = getColors(dogs);
47 | getUnique(colors);
48 | // ['black', 'chocolate']
49 |
50 | // #END:unique
51 |
52 | export { getColors, getUnique };
53 |
--------------------------------------------------------------------------------
/collections/set/unique.spec.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jsmapr1/simplifying-js/a7ced4922664a4ea0d2b584963fd4d7aeebd7321/collections/set/unique.spec.js
--------------------------------------------------------------------------------
/conditionals/falsy/falsy.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jsmapr1/simplifying-js/a7ced4922664a4ea0d2b584963fd4d7aeebd7321/conditionals/falsy/falsy.js
--------------------------------------------------------------------------------
/conditionals/falsy/falsy.spec.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jsmapr1/simplifying-js/a7ced4922664a4ea0d2b584963fd4d7aeebd7321/conditionals/falsy/falsy.spec.js
--------------------------------------------------------------------------------
/conditionals/falsy/notFalsy.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-unused-vars */
2 |
3 | function hasInformation() {
4 | return !!{};
5 | }
6 |
--------------------------------------------------------------------------------
/conditionals/shortCircuiting/conditional.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-unused-vars */
2 |
3 | // #START:problem
4 | function getFirstImage(userConfig) {
5 | let img = 'default.png';
6 | if (userConfig.images) {
7 | img = userConfig.images[0];
8 | }
9 | return img;
10 | }
11 | // #END:problem
12 |
13 | // #START:problem2
14 | function getImage(userConfig) {
15 | let img = 'default.png';
16 | if (userConfig.images) {
17 | if (userConfig.images.length) {
18 | img = userConfig.images[0];
19 | }
20 | }
21 | return img;
22 | }
23 | // #END:problem2
24 |
25 | export { getImage };
26 |
--------------------------------------------------------------------------------
/conditionals/shortCircuiting/shortCircuiting.js:
--------------------------------------------------------------------------------
1 | // #START:or
2 | function getIconPath(icon) {
3 | const path = icon.path || 'uploads/default.png';
4 | return `https://assets.foo.com/${path}`;
5 | }
6 | // #END:or
7 |
8 | // #START:and
9 | function getImage(userConfig) {
10 | if (userConfig.images && userConfig.images.length > 0) {
11 | return userConfig.images[0];
12 | }
13 | return 'default.png';
14 | }
15 | // #END:and
16 |
17 |
18 | export { getIconPath, getImage };
19 |
--------------------------------------------------------------------------------
/conditionals/shortCircuiting/ternary.js:
--------------------------------------------------------------------------------
1 | // #START:problem
2 | function getIconPath(icon) {
3 | const path = icon.path ? icon.path : 'uploads/default.png';
4 | return `https://assets.foo.com/${path}`;
5 | }
6 | // #END:problem
7 |
8 | // #START:and
9 | function getImage(userConfig) {
10 | const images = userConfig.images;
11 | return images && images.length ? images[0] : 'default.png';
12 | }
13 | // #END:and
14 |
15 | function getImageOneLine(userConfig) {
16 | // #START:one
17 | const images = userConfig.images;
18 | return images &&
19 | images.length &&
20 | images[0].indexOf('gif') < 0
21 | ? images[0] : 'default.png';
22 | // #END:one
23 | }
24 |
25 | export { getIconPath, getImage, getImageOneLine };
26 |
--------------------------------------------------------------------------------
/conditionals/ternary/if.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable block-scoped-var, no-redeclare, no-var, no-undef, no-unused-vars, vars-on-top */
2 |
3 | function configureTimePermissions({ title }) {
4 | if (title === 'manager') {
5 | var permissions = ['time', 'pay'];
6 | } else {
7 | var permissions = ['time'];
8 | }
9 | return permissions;
10 | }
11 |
12 | function configureTimePermissions({ title }) {
13 | // # START:let
14 | if (title === 'manager') {
15 | const permissions = ['time', 'pay'];
16 | } else {
17 | const permissions = ['time'];
18 | }
19 | permissions;
20 | // ReferenceError: permissions is not defined
21 | // # END:let
22 | return permissions;
23 | }
24 | function configureTimePermissionsScope({ title }) {
25 | // # START:scope
26 | let permissions;
27 | if (title === 'manager') {
28 | permissions = ['time', 'pay'];
29 | } else {
30 | permissions = ['time'];
31 | }
32 | // # END:scope
33 | return permissions;
34 | }
35 |
36 | export { configureTimePermissions, configureTimePermissionsScope };
37 |
--------------------------------------------------------------------------------
/conditionals/ternary/ternary.js:
--------------------------------------------------------------------------------
1 | function configureTimePermissions(title) {
2 | // # START:const
3 | const permissions = title === 'manager' ? ['time', 'pay'] : ['time'];
4 | // # END:const
5 | return permissions;
6 | }
7 |
8 | export { configureTimePermissions };
9 |
--------------------------------------------------------------------------------
/conditionals/ternary/ternary.spec.js:
--------------------------------------------------------------------------------
1 | import expect from 'expect';
2 |
3 | import {
4 | configureTimePermissions as configureLet,
5 | configureTimePermissionsScope as configureLetScope,
6 | } from './if';
7 | import { configureTimePermissions as configureProblem } from './ternaryProblem';
8 |
9 | describe('ternary ', () => {
10 | it('should not set time permissions with if and let', () => {
11 | let RefError;
12 | try {
13 | configureLet({ title: 'manager' });
14 | } catch (error) {
15 | RefError = error instanceof ReferenceError;
16 | }
17 | expect(RefError).toEqual(true);
18 | });
19 |
20 | it('should set time permissions with if and let', () => {
21 | expect(configureLetScope({ title: 'manager' })).toEqual(['time', 'pay']);
22 | });
23 |
24 | it('should set manager, supervisor, employee with ternary', () => {
25 | expect(configureProblem({ title: 'manager' })).toEqual(['time', 'overtimeAuthorization', 'pay']);
26 | expect(configureProblem({ title: 'supervisor' })).toEqual(['time', 'overtimeAuthorization']);
27 | expect(configureProblem({ title: 'employee' })).toEqual(['time']);
28 | });
29 | });
30 |
--------------------------------------------------------------------------------
/conditionals/ternary/ternaryProblem.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-nested-ternary, no-unused-vars */
2 |
3 | function configureTimePermissions({ title }) {
4 | // #START:problem
5 | const permissions = title === 'supervisor' || title === 'manager' ?
6 | title === 'manager' ?
7 | ['time', 'overtimeAuthorization', 'pay'] : ['time', 'overtimeAuthorization']
8 | : ['time'];
9 | // #END:problem
10 | return permissions;
11 | }
12 |
13 | // #START:func
14 | function getTimePermissions({ title }) {
15 | if (title === 'manager') {
16 | return ['time', 'overtimeAuthorization', 'pay'];
17 | }
18 |
19 | if (title === 'supervisor') {
20 | return ['time', 'overtimeAuthorization'];
21 | }
22 | return ['time'];
23 | }
24 |
25 | const permissions = getTimePermissions({ title: 'employee' });
26 | // ['time']
27 | // #END:func
28 |
29 | export { configureTimePermissions };
30 |
--------------------------------------------------------------------------------
/externalData/async/async.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-console */
2 | import { getArtist, getMusic, getUserPreferences } from '../promises/promises';
3 |
4 | // START: call
5 | async function getTheme() {
6 | const { theme } = await getUserPreferences();
7 | return theme;
8 | }
9 | // END: call
10 |
11 | // START: theme
12 | getTheme()
13 | .then(theme => {
14 | console.log(theme);
15 | });
16 | // END: theme
17 |
18 | // START:artist
19 | async function getArtistByPreference() {
20 | const { theme } = await getUserPreferences();
21 | const { album } = await getMusic(theme);
22 | const { artist } = await getArtist(album);
23 | return artist;
24 | }
25 |
26 | getArtistByPreference()
27 | .then(artist => {
28 | console.log(artist);
29 | });
30 | // END:artist
31 |
32 | export { getArtistByPreference, getTheme };
33 |
--------------------------------------------------------------------------------
/externalData/async/async.spec.js:
--------------------------------------------------------------------------------
1 | import expect from 'expect';
2 | import { getArtistByPreference, getTheme } from './async';
3 | import { getArtistByPreference as catchPref } from './catch';
4 |
5 | describe('async', () => {
6 | it('should await an action', () => {
7 | return getTheme()
8 | .then(theme => {
9 | expect(theme).toEqual('dusk');
10 | });
11 | });
12 |
13 | it('should await on multiples actions', () => {
14 | return getArtistByPreference()
15 | .then(artist => {
16 | expect(artist).toEqual('Brian Eno');
17 | });
18 | });
19 |
20 | it('should catch an error', () => {
21 | return catchPref()
22 | .then(() => {
23 | // Hitting this block is an error.
24 | expect(false).toEqual(true);
25 | })
26 | .catch(e => {
27 | expect(e.type).toEqual('Network error');
28 | });
29 | });
30 | });
31 |
--------------------------------------------------------------------------------
/externalData/async/catch.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-console */
2 | import { getArtist, getUserPreferences, failMusic } from '../promises/promises';
3 | // START: artist
4 | async function getArtistByPreference() {
5 | const { theme } = await getUserPreferences();
6 | const { album } = await failMusic(theme);
7 | const { artist } = await getArtist(album);
8 | return artist;
9 | }
10 |
11 | getArtistByPreference()
12 | .then(artist => {
13 | console.log(artist);
14 | })
15 | .catch(e => {
16 | console.error(e);
17 | });
18 | // END: artist
19 |
20 | export { getArtistByPreference };
21 |
--------------------------------------------------------------------------------
/externalData/fetch/example.js:
--------------------------------------------------------------------------------
1 | import { setLatestPost } from './fetch';
2 | import { getPost } from './services/postService';
3 |
4 | const sidebar = document.getElementById('sidebar');
5 | setLatestPost(1, sidebar, getPost);
6 | // Sets sidebar
7 |
--------------------------------------------------------------------------------
/externalData/fetch/fetch.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-console, no-unused-vars, no-param-reassign */
2 | const fetch = require('node-fetch');
3 |
4 |
5 | const example =
6 | // START:result
7 | {
8 | userId: 1,
9 | id: 1,
10 | title: 'First Post',
11 | body: 'This is my first post...',
12 | };
13 | // END:result
14 |
15 | // START:simple
16 | fetch('https://jsonplaceholder.typicode.com/posts/1');
17 | // END:simple
18 |
19 | // START:resolve
20 | fetch('https://jsonplaceholder.typicode.com/posts/1')
21 | .then(data => {
22 | return data.json();
23 | })
24 | .then(post => {
25 | console.log(post.title);
26 | });
27 | // END:resolve
28 |
29 | // START:catch
30 | fetch('https://jsonplaceholder.typicode.com/pots/1')
31 | .then(data => {
32 | if (!data.ok) {
33 | throw Error(data.status);
34 | }
35 | return data.json();
36 | })
37 | .then(post => {
38 | console.log(post.title);
39 | })
40 | .catch(e => {
41 | console.log(e);
42 | });
43 | // END:catch
44 |
45 | // START: post
46 | const update = {
47 | title: 'Clarence White Techniques',
48 | body: 'Amazing',
49 | userId: 1,
50 | };
51 |
52 | const options = {
53 | method: 'POST',
54 | headers: {
55 | 'Content-Type': 'application/json',
56 | },
57 | body: JSON.stringify(update),
58 | };
59 |
60 | fetch('https://jsonplaceholder.typicode.com/posts', options).then(data => {
61 | if (!data.ok) {
62 | throw Error(data.status);
63 | }
64 | return data.json();
65 | }).then(update => {
66 | console.log(update);
67 | // {
68 | // title: 'Clarence White Techniques',
69 | // body: 'Amazing',
70 | // userId: 1,
71 | // id: 101
72 | // };
73 | }).catch(e => {
74 | console.log(e);
75 | });
76 | // END: post
77 |
78 | function getPosts() {
79 | return fetch('https://jsonplaceholder.typicode.com/posts')
80 | .then(d => {
81 | return d.json();
82 | });
83 | }
84 |
85 | function setLatestPost(element, retrievePosts) {
86 | return retrievePosts()
87 | .then(posts => {
88 | console.log(posts);
89 | element.innerHTML = posts[0].title;
90 | });
91 | }
92 |
93 | export { setLatestPost };
94 |
--------------------------------------------------------------------------------
/externalData/fetch/fetch.spec.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-console */
2 | import expect from 'expect';
3 | import { setLatestPost } from './posts';
4 |
5 | describe('set latest', () => {
6 | it('should update post', () => {
7 | const title = 'Doc Watson Gets the Blues';
8 | function fakeService() {
9 | return Promise.resolve({ title });
10 | }
11 |
12 | const el = {
13 | innerHTML: '',
14 | };
15 |
16 | return setLatestPost(el, 1, fakeService)
17 | .then(() => {
18 | expect(el.innerHTML).toEqual(title);
19 | })
20 | .catch(e => {
21 | // Getting here is bad.
22 | console.log(e);
23 | expect(true).toEqual(false);
24 | });
25 | });
26 | });
27 |
--------------------------------------------------------------------------------
/externalData/fetch/posts.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-param-reassign */
2 | function setLatestPost(element, id, retrievePost) {
3 | return retrievePost(id)
4 | .then(post => {
5 | element.innerHTML = post.title;
6 | });
7 | }
8 |
9 | export { setLatestPost };
10 |
--------------------------------------------------------------------------------
/externalData/fetch/services/postService.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-console */
2 | function getPost(id) {
3 | return fetch(`https://jsonplaceholder.typicode.com/posts/${id}`)
4 | .then(data => {
5 | if (!data.ok) {
6 | throw Error(data.status);
7 | }
8 | return data.json();
9 | })
10 | .catch(e => {
11 | console.log(e);
12 | });
13 | }
14 |
15 | export { getPost };
16 |
--------------------------------------------------------------------------------
/externalData/local/local.js:
--------------------------------------------------------------------------------
1 | // Include filter preferences.
2 |
3 | // START:setItem
4 | function saveBreed(breed) {
5 | localStorage.setItem('breed', breed);
6 | }
7 | // END:setItem
8 |
9 | // START:getItem
10 | function getSavedBreed() {
11 | return localStorage.getItem('breed');
12 | }
13 | // END:getItem
14 |
15 | // START:removeItem
16 | function removeBreed() {
17 | return localStorage.removeItem('breed');
18 | }
19 | // END:removeItem
20 |
21 | // START:applyBreed
22 | function applyBreedPreference(filters) {
23 | const breed = getSavedBreed();
24 | if (breed) {
25 | filters.set('breed', breed);
26 | }
27 | return filters;
28 | }
29 | // END:applyBreed
30 |
31 | // START:savePref
32 | function savePreferences(filters) {
33 | const filterString = JSON.stringify([...filters]);
34 | localStorage.setItem('preferences', filterString);
35 | }
36 | // END:savePref
37 |
38 | // START:applyPref
39 | function retrievePreferences() {
40 | const preferences = JSON.parse(localStorage.getItem('preferences'));
41 | return new Map(preferences);
42 | }
43 | // END:applyPref
44 |
45 | // START:clear
46 | function clearPreferences() {
47 | localStorage.clear();
48 | }
49 | // END:clear
50 |
51 | export {
52 | applyBreedPreference,
53 | clearPreferences,
54 | getSavedBreed,
55 | removeBreed,
56 | retrievePreferences,
57 | saveBreed,
58 | savePreferences,
59 | };
60 |
--------------------------------------------------------------------------------
/externalData/local/local.spec.js:
--------------------------------------------------------------------------------
1 | import expect from 'expect';
2 | import {
3 | applyBreedPreference,
4 | getSavedBreed,
5 | removeBreed,
6 | retrievePreferences,
7 | saveBreed,
8 | savePreferences,
9 | } from './local';
10 |
11 | describe('localstorage', () => {
12 | afterEach(() => {
13 | localStorage.clear();
14 | });
15 |
16 | it('should set breed', () => {
17 | saveBreed('labrador');
18 | expect(localStorage.getItem('breed')).toEqual('labrador');
19 | });
20 |
21 | it('should get breed', () => {
22 | saveBreed('labrador');
23 | expect(getSavedBreed()).toEqual('labrador');
24 | });
25 |
26 | it('should remove breed', () => {
27 | saveBreed('labrador');
28 | expect(localStorage.getItem('breed')).toEqual('labrador');
29 | removeBreed();
30 | expect(localStorage.getItem('breed')).toEqual(undefined);
31 | });
32 |
33 | it('apply filters', () => {
34 | const defaults = new Map();
35 | saveBreed('labrador');
36 | const filters = applyBreedPreference(defaults);
37 | expect(filters.get('breed')).toEqual('labrador');
38 | });
39 |
40 | it('should save all preferences', () => {
41 | const filters = new Map()
42 | .set('color', 'black');
43 | savePreferences(filters);
44 | expect(localStorage.getItem('preferences')).toEqual('[["color","black"]]');
45 | });
46 |
47 | it('should retrieve all preferences', () => {
48 | localStorage.setItem('preferences', '[["color","black"]]');
49 | const prefences = retrievePreferences();
50 | expect(prefences.get('color')).toEqual('black');
51 | });
52 | });
53 |
--------------------------------------------------------------------------------
/externalData/promises/problem.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-unused-vars, no-console */
2 | // START:cb
3 | function getUserPreferences(cb) {
4 | return setTimeout(() => {
5 | cb({
6 | theme: 'dusk',
7 | });
8 | }, 1000);
9 | }
10 |
11 | function log(value) {
12 | return console.log(value);
13 | }
14 |
15 | log('starting');
16 | // starting
17 |
18 | getUserPreferences(preferences => {
19 | return log(preferences.theme.toUpperCase());
20 | });
21 |
22 | log('ending?');
23 | // ending
24 |
25 | // DUSK
26 |
27 | // END:cb
28 |
29 | // START:music
30 | function getMusic(theme, cb) {
31 | return setTimeout(() => {
32 | if (theme === 'dusk') {
33 | return cb({
34 | album: 'music for airports',
35 | });
36 | }
37 | return cb({
38 | album: 'kind of blue',
39 | });
40 | }, 1000);
41 | }
42 | // END:music
43 |
44 | // START:hell
45 | getUserPreferences(preferences => {
46 | return getMusic(preferences.theme, music => {
47 | console.log(music.album);
48 | });
49 | });
50 | // END:hell
51 |
52 | export { getUserPreferences };
53 |
--------------------------------------------------------------------------------
/externalData/promises/promises.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-unused-vars, no-console */
2 |
3 | // START:define
4 | function getUserPreferences() {
5 | const preferences = new Promise((resolve, reject) => {
6 | resolve({
7 | theme: 'dusk',
8 | });
9 | });
10 | return preferences;
11 | }
12 | // END:define
13 |
14 | // START:pref
15 | getUserPreferences()
16 | .then(preferences => {
17 | console.log(preferences.theme);
18 | });
19 | // 'dusk'
20 | // END:pref
21 |
22 | // START:fail
23 | function failUserPreference() {
24 | const finder = new Promise((resolve, reject) => {
25 | reject({
26 | type: 'Access Denied',
27 | });
28 | });
29 | return finder;
30 | }
31 | // END:fail
32 |
33 | // START:catch
34 | failUserPreference()
35 | .then(preferences => {
36 | // This won't execute
37 | console.log(preferences.theme);
38 | })
39 | .catch(error => {
40 | console.error(`Fail: ${error.type}`);
41 | });
42 | // Fail: Access Denied
43 | // END:catch
44 |
45 | // START:music
46 | function getMusic(theme) {
47 | if (theme === 'dusk') {
48 | return Promise.resolve({
49 | album: 'music for airports',
50 | });
51 | }
52 | return Promise.resolve({
53 | album: 'kind of blue',
54 | });
55 | }
56 | // END:music
57 |
58 | // START:chain
59 | getUserPreferences()
60 | .then(preference => {
61 | return getMusic(preference.theme);
62 | })
63 | .then(music => {
64 | console.log(music.album);
65 | });
66 | // music for airports
67 | // END:chain
68 |
69 | // START:arrow
70 | getUserPreferences()
71 | .then(preference => getMusic(preference.theme))
72 | .then(music => { console.log(music.album); });
73 | // END:arrow
74 |
75 | // START:artist
76 | function getArtist(album) {
77 | return Promise.resolve({
78 | artist: 'Brian Eno',
79 | });
80 | }
81 | // END:artist
82 |
83 | // START:single
84 | function failMusic(theme) {
85 | return Promise.reject({
86 | type: 'Network error',
87 | });
88 | }
89 |
90 | getUserPreferences()
91 | .then(preference => failMusic(preference.theme))
92 | .then(music => getArtist(music.album))
93 | .catch(e => {
94 | console.log(e);
95 | });
96 | // END:single
97 |
98 | export { failUserPreference, failMusic, getArtist, getMusic, getUserPreferences };
99 |
--------------------------------------------------------------------------------
/externalData/promises/promises.spec.js:
--------------------------------------------------------------------------------
1 | import expect from 'expect';
2 | import { failMusic, failUserPreference, getArtist, getMusic, getUserPreferences } from './promises';
3 | import {
4 | getUserPreferences as prefProblem,
5 | } from './problem';
6 |
7 | describe('promises', () => {
8 | it('should resolve with data', done => {
9 | return prefProblem(data => {
10 | expect(data.theme.toUpperCase()).toEqual('DUSK');
11 | done();
12 | });
13 | });
14 |
15 | it('should resolve with data', () => {
16 | return getUserPreferences().then(data => {
17 | expect(data.theme).toEqual('dusk');
18 | });
19 | });
20 | it('should fail', () => {
21 | return failUserPreference()
22 | .catch(data => {
23 | expect(data.type).toEqual('Access Denied');
24 | });
25 | });
26 | it('should chain success', () => {
27 | return getUserPreferences()
28 | .then(preference => {
29 | return getMusic(preference.theme);
30 | })
31 | .then(music => {
32 | expect(music.album).toEqual('music for airports');
33 | });
34 | });
35 |
36 | it('should catch failure', () => {
37 | return getUserPreferences()
38 | .then(preference => failMusic(preference.theme))
39 | .then(music => getArtist(music.album))
40 | .catch(e => {
41 | expect(e.type).toEqual('Network error');
42 | });
43 | });
44 | });
45 |
--------------------------------------------------------------------------------
/functions/arrow/arrow.js:
--------------------------------------------------------------------------------
1 | // START: name
2 | const comic = {
3 | first: 'Peter',
4 | last: 'Bagge',
5 | city: 'Seattle',
6 | state: 'Washington',
7 | };
8 |
9 | const getName = ({ first, last }) => `${first} ${last}`;
10 | getName(comic);
11 | // Peter Bagge
12 | // END: name
13 |
14 | // START: return
15 | const getFullName = ({ first, last }) => ({ fullName: `${first} ${last}` });
16 | getFullName(comic);
17 | // { fullName: 'Peter Bagge' }
18 | // END: return
19 |
20 | // START:multi
21 | const getNameAndLocation = ({ first, last, city, state }) => ({
22 | fullName: `${first} ${last}`,
23 | location: `${city}, ${state}`,
24 | });
25 | getNameAndLocation(comic);
26 | // {
27 | // fullName: 'Peter Bagge',
28 | // location: 'Seattle, Washington'
29 | // }
30 | // END:multi
31 |
32 | // START: high
33 | const discounter = discount => price => price * (1 - discount);
34 |
35 | const tenPercentOff = discounter(0.1);
36 | tenPercentOff(100);
37 | // 90;
38 | // END: high
39 |
40 | // START: together
41 | discounter(0.1)(100);
42 | // 90
43 | // END: together
44 |
45 | export { comic, discounter, getName, getNameAndLocation, getFullName };
46 |
--------------------------------------------------------------------------------
/functions/arrow/arrow.spec.js:
--------------------------------------------------------------------------------
1 | import expect from 'expect';
2 |
3 | import {
4 | discounter as discountProblem,
5 | getFullName as fullProblem,
6 | getName as nameProblem,
7 | name,
8 | } from './problem';
9 |
10 | import {
11 | comic,
12 | discounter,
13 | getFullName,
14 | getName,
15 | getNameAndLocation,
16 | } from './arrow';
17 |
18 | describe('problems', () => {
19 | it('should get a name', () => {
20 | expect(nameProblem(name)).toEqual('Lemmy Kilmister');
21 | });
22 |
23 | it('should return an object', () => {
24 | expect(fullProblem(name)).toEqual({ fullName: 'Lemmy Kilmister' });
25 | });
26 |
27 | it('should return a high order function', () => {
28 | expect(discountProblem(0.1)(100)).toEqual(90);
29 | });
30 | });
31 |
32 | describe('arrow functions', () => {
33 | it('should destructure inputs', () => {
34 | expect(getName(comic)).toEqual('Peter Bagge');
35 | });
36 |
37 | it('should return an object', () => {
38 | expect(getFullName(comic)).toEqual({ fullName: 'Peter Bagge' });
39 | });
40 |
41 | it('should return an object', () => {
42 | expect(getNameAndLocation(comic)).toEqual({
43 | fullName: 'Peter Bagge',
44 | location: 'Seattle, Washington',
45 | });
46 | });
47 |
48 | it('should return a high order function', () => {
49 | expect(discounter(0.1)(100)).toEqual(90);
50 | });
51 | });
52 |
--------------------------------------------------------------------------------
/functions/arrow/close.js:
--------------------------------------------------------------------------------
1 | const getName = { first, last } => `${first} ${last}`;
2 |
3 | // Error: Unexpected token '=>'. Expected ';' after variable declaration
4 |
--------------------------------------------------------------------------------
/functions/arrow/problem.js:
--------------------------------------------------------------------------------
1 | // START: name
2 | const name = {
3 | first: 'Lemmy',
4 | last: 'Kilmister',
5 | };
6 |
7 | function getName({ first, last }) {
8 | return `${first} ${last}`;
9 | }
10 | // END: name
11 |
12 | // START: full
13 | function getFullName({ first, last }) {
14 | return {
15 | fullName: `${first} ${last}`,
16 | };
17 | }
18 | // END: full
19 |
20 | // START: high
21 | const discounter = discount => {
22 | return price => {
23 | return price * (1 - discount);
24 | };
25 | };
26 | const tenPercentOff = discounter(0.1);
27 | tenPercentOff(100);
28 | // 90
29 | // END: high
30 |
31 | export { getName, getFullName, discounter, name };
32 |
--------------------------------------------------------------------------------
/functions/context/basic.js:
--------------------------------------------------------------------------------
1 | // START:func
2 | const validator = {
3 | message: 'is invalid.',
4 | setInvalidMessage(field) {
5 | return `${field} ${this.message}`;
6 | },
7 | };
8 |
9 | validator.setInvalidMessage('city');
10 | // city is invalid.
11 | // END:func
12 |
13 | export { validator };
14 |
--------------------------------------------------------------------------------
/functions/context/context.js:
--------------------------------------------------------------------------------
1 | // START: func
2 | const validator = {
3 | message: 'is invalid.',
4 | setInvalidMessages(...fields) {
5 | return fields.map(field => {
6 | return `${field} ${this.message}`;
7 | });
8 | },
9 | };
10 |
11 | validator.setInvalidMessages('city');
12 | // ['city is invalid.]
13 | // END: func
14 |
15 | export { validator };
16 |
--------------------------------------------------------------------------------
/functions/context/context.spec.js:
--------------------------------------------------------------------------------
1 | import expect from 'expect';
2 |
3 | import { validator } from './context';
4 |
5 | import {
6 | validator as validatorBasic,
7 | } from './basic';
8 |
9 | import {
10 | validator as validatorProblem,
11 | } from './problem';
12 |
13 | import {
14 | validator as validatorMethod,
15 | } from './method';
16 |
17 |
18 | describe('validation', () => {
19 | const field = 'city';
20 | it('should set invalid message', () => {
21 | const message = 'city is invalid.';
22 | expect(validatorBasic.setInvalidMessage(field)).toEqual(message);
23 | });
24 | it('should not access context on map function', () => {
25 | try {
26 | // START: problem
27 | validatorProblem.setInvalidMessages(field);
28 | // TypeError: Cannot read property 'message' of undefined
29 | // END: problem
30 | } catch (e) {
31 | expect(e.message).toEqual("Cannot read property 'message' of undefined");
32 | }
33 | });
34 |
35 | it('should access context with arrow function', () => {
36 | const messages = ['city is invalid.'];
37 | expect(validator.setInvalidMessages(field)).toEqual(messages);
38 | });
39 |
40 | it('should not access context on map function', () => {
41 | try {
42 | // START: problemMethod
43 | validatorMethod.setInvalidMessage(field);
44 | // TypeError: Cannot read property 'message' of undefined
45 | // END: problemMethod
46 | } catch (e) {
47 | expect(e.message).toEqual("Cannot read property 'message' of undefined");
48 | }
49 | });
50 | });
51 |
--------------------------------------------------------------------------------
/functions/context/method.js:
--------------------------------------------------------------------------------
1 | // START: func
2 | const validator = {
3 | message: 'is invalid.',
4 | setInvalidMessage: field => `${field} ${this.message}`,
5 | };
6 | // END: func
7 |
8 | export { validator };
9 |
--------------------------------------------------------------------------------
/functions/context/problem.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-unused-vars, no-param-reassign, no-console, func-names */
2 |
3 | // START:func
4 | const validator = {
5 | message: 'is invalid.',
6 | setInvalidMessages(...fields) {
7 | return fields.map(function (field) {
8 | return `${field} ${this.message}`;
9 | });
10 | },
11 | };
12 | // END:func
13 |
14 | export { validator };
15 |
--------------------------------------------------------------------------------
/functions/curry/curry.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | // START:dogs
3 | const dogs = [
4 | {
5 | name: 'max',
6 | weight: 10,
7 | breed: 'boston terrier',
8 | state: 'wisconsin',
9 | color: 'black',
10 | },
11 | {
12 | name: 'don',
13 | weight: 90,
14 | breed: 'labrador',
15 | state: 'kansas',
16 | color: 'black',
17 | },
18 | {
19 | name: 'shadow',
20 | weight: 40,
21 | breed: 'labrador',
22 | state: 'wisconsin',
23 | color: 'chocolate',
24 | },
25 | ];
26 | // END:dogs
27 |
28 | // START: func
29 | function getDogNames(dogs, filterFunc) {
30 | return dogs
31 | .filter(filterFunc)
32 | .map(dog => dog.name)
33 | }
34 |
35 | getDogNames(dogs, dog => dog.weight < 20);
36 | // ['max']
37 | // END: func
38 |
39 | // START:curry
40 | const weightCheck = weight => dog => dog.weight < weight;
41 |
42 | getDogNames(dogs, weightCheck(20));
43 | // ['max']
44 |
45 | getDogNames(dogs, weightCheck(50));
46 | // ['max', 'shadow']
47 | // END:curry
48 |
49 | // START:identity
50 | const identity = field => value => dog => dog[field] === value;
51 | const colorCheck = identity('color');
52 | const stateCheck = identity('state');
53 |
54 | getDogNames(dogs, colorCheck('chocolate'));
55 | // ['shadow']
56 |
57 | getDogNames(dogs, stateCheck('kansas'));
58 | // ['don']
59 | // END:identity
60 |
61 | // START:all
62 | function allFilters(dogs, ...checks) {
63 | return dogs
64 | .filter(dog => checks.every(check => check(dog)))
65 | .map(dog => dog.name);
66 | }
67 | allFilters(dogs, colorCheck('black'), stateCheck('kansas'));
68 | // ['Don']
69 |
70 | function anyFilters(dogs, ...checks) {
71 | return dogs
72 | .filter(dog => checks.some(check => check(dog)))
73 | .map(dog => dog.name);
74 | }
75 |
76 | anyFilters(dogs, weightCheck(20), colorCheck('chocolate'));
77 | // ['max', 'shadow']
78 | // END:all
79 |
80 | export { anyFilters, dogs, getDogNames, colorCheck, weightCheck, stateCheck, allFilters }
81 |
--------------------------------------------------------------------------------
/functions/curry/curry.spec.js:
--------------------------------------------------------------------------------
1 | import expect from 'expect';
2 |
3 | import {
4 | getDogNames as getNamesFull,
5 | } from './problem';
6 |
7 | import {
8 | allFilters,
9 | anyFilters,
10 | dogs,
11 | getDogNames,
12 | colorCheck,
13 | stateCheck,
14 | weightCheck,
15 | } from './curry';
16 |
17 | describe('curry', () => {
18 | it('should apply a function without currying', () => {
19 | expect(getNamesFull(dogs, ['color', 'black'])).toEqual(['max', 'don']);
20 | });
21 | it('should get dog names with regular function', () => {
22 | expect(getDogNames(dogs, dog => dog.color === 'black')).toEqual(['max', 'don']);
23 | });
24 | it('should get dog names with curried function', () => {
25 | expect(getDogNames(dogs, weightCheck(20))).toEqual(['max']);
26 | });
27 | it('should get dog names with curried function', () => {
28 | expect(getDogNames(dogs, weightCheck(20))).toEqual(['max']);
29 | });
30 | it('should apply multiple functions', () => {
31 | expect(allFilters(dogs, colorCheck('black'), stateCheck('kansas'))).toEqual(['don']);
32 | });
33 | it('should apply multiple functions', () => {
34 | expect(allFilters(dogs, colorCheck('black'), stateCheck('kansas'))).toEqual(['don']);
35 | });
36 | it('should apply multiple functions', () => {
37 | expect(anyFilters(dogs, weightCheck(20), colorCheck('chocolate'))).toEqual(['max', 'shadow']);
38 | });
39 | });
40 |
--------------------------------------------------------------------------------
/functions/curry/curry.spec2.js:
--------------------------------------------------------------------------------
1 | import expect from 'expect';
2 |
3 | import {
4 | getDogNames as getNamesFull,
5 | } from './problem';
6 |
7 | import {
8 | applyFilters,
9 | anyFilters,
10 | dogs,
11 | getDogNames,
12 | colorCheck,
13 | stateCheck,
14 | weightCheck,
15 | } from './curry';
16 |
17 | describe('curry', () => {
18 | it('should apply a function without currying', () => {
19 | expect(getNamesFull(dogs, ['color', 'black'])).toEqual(['max', 'don']);
20 | });
21 | it('should get dog names with regular function', () => {
22 | expect(getDogNames(dogs, dog => dog.color === 'black')).toEqual(['max', 'don']);
23 | });
24 | it('should get dog names with curried function', () => {
25 | expect(getDogNames(dogs, weightCheck(20))).toEqual(['max']);
26 | });
27 | it('should get dog names with curried function', () => {
28 | expect(getDogNames(dogs, weightCheck(20))).toEqual(['max']);
29 | });
30 | it('should apply multiple functions', () => {
31 | expect(applyFilters(dogs, colorCheck('black'), stateCheck('kansas'))).toEqual(['don']);
32 | });
33 | it('should apply multiple functions', () => {
34 | expect(applyFilters(dogs, colorCheck('black'), stateCheck('kansas'))).toEqual(['don']);
35 | });
36 | it('should apply multiple functions', () => {
37 | expect(anyFilters(dogs, weightCheck(20), colorCheck('chocolate'))).toEqual(['max', 'shadow']);
38 | });
39 | });
40 |
--------------------------------------------------------------------------------
/functions/curry/highorder.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 |
3 | // START:program
4 | const setStrongHallProgram = program => {
5 | const defaults = {
6 | hours: '8 a.m. - 8 p.m.',
7 | address: 'Jayhawk Blvd',
8 | name: 'Augusto',
9 | phone: '555-555-5555'
10 | }
11 | return { ...defaults, ...program}
12 | }
13 |
14 | const programs = setStrongHallProgram(program);
15 |
16 | const exhibit = setStrongHallProgram(exhibit);
17 | // END:program
18 |
--------------------------------------------------------------------------------
/functions/curry/problem.js:
--------------------------------------------------------------------------------
1 | import { dogs } from './curry';
2 | // START: func
3 | function getDogNames(dogs, filter) {
4 | const [key, value] = filter;
5 | return dogs
6 | .filter(dog => dog[key] === value)
7 | .map(dog => dog.name);
8 | }
9 |
10 | getDogNames(dogs, ['color', 'black']);
11 | // ['max', 'don']
12 | // END: func
13 |
14 | export { getDogNames };
15 |
--------------------------------------------------------------------------------
/functions/oldTest/problem.js:
--------------------------------------------------------------------------------
1 | import { redirect } from './routing';
2 | import { getTaxInformation } from './taxService';
3 |
4 | function formatPrice({ price, location }) {
5 | const user = document.getElementById('user').innerHTML; //
6 |
7 | if (!location) { //
8 | redirect('/');
9 | return;
10 | }
11 |
12 | const rate = getTaxInformation(location); //
13 | const taxes = rate ? `plus $${price * rate} in taxes.` : 'plus tax.';
14 |
15 | const totalEl = document.getElementById('total'); //
16 | totalEl.innerHTML = `${user} your total is: ${price} ${taxes}`;
17 | }
18 |
19 | export { formatPrice };
20 |
--------------------------------------------------------------------------------
/functions/oldTest/problem.spec.js:
--------------------------------------------------------------------------------
1 | import expect from 'expect';
2 |
3 | import sinon from 'sinon';
4 | import * as routing from './routing';
5 | import * as taxService from './taxService';
6 | import { formatPrice } from './problem';
7 |
8 | // START:tests
9 | describe('format price', () => {
10 | const userElement = {
11 | innerHTML: 'Aaron Cometbus',
12 | };
13 |
14 | const totalElement = {
15 | innerHTML: '',
16 | };
17 |
18 | const document = { //
19 | getElementById: id => {
20 | if (id === 'user') {
21 | return userElement;
22 | }
23 | if (id === 'total') {
24 | return totalElement;
25 | }
26 | return null;
27 | },
28 | };
29 |
30 | global.document = document;
31 |
32 | let taxStub;
33 |
34 | beforeEach(() => {
35 | taxStub = sinon.stub(taxService, 'getTaxInformation'); //
36 | });
37 |
38 | afterEach(() => {
39 | totalElement.innerHTML = ''; //
40 | taxStub.restore();
41 | });
42 |
43 | it('should redirect if no location', () => {
44 | sinon.spy(routing, 'redirect'); //
45 | formatPrice({}, undefined);
46 | expect(routing.redirect.called).toEqual(true);
47 | });
48 |
49 | it('should return plus tax if no tax info', () => {
50 | taxStub.returns(null); //
51 | formatPrice({ price: 30, location: 'Oklahoma' });
52 | const message = 'Aaron Cometbus your total is: 30 plus tax.';
53 | expect(totalElement.innerHTML).toEqual(message);
54 | });
55 |
56 | it('should return plus tax information', () => {
57 | taxStub.returns(0.1);
58 | formatPrice({ price: 30, location: 'Oklahoma' });
59 | const message = 'Aaron Cometbus your total is: 30 plus $3 in taxes.';
60 | expect(totalElement.innerHTML).toEqual(message);
61 | });
62 | // END:tests
63 | });
64 |
--------------------------------------------------------------------------------
/functions/oldTest/routing.js:
--------------------------------------------------------------------------------
1 | function redirect() {
2 | return true;
3 | }
4 |
5 | export { redirect };
6 |
--------------------------------------------------------------------------------
/functions/oldTest/taxService.js:
--------------------------------------------------------------------------------
1 | // stub
2 | function getTaxInformation(location) {
3 | return location;
4 | }
5 |
6 | export { getTaxInformation };
7 |
--------------------------------------------------------------------------------
/functions/oldTest/test.js:
--------------------------------------------------------------------------------
1 |
2 | // START:final
3 | function formatPrice({ price, location }, user, getTaxInformation) {
4 | const rate = getTaxInformation(location);
5 | const taxes = rate ? `plus $${price * rate} in taxes.` : 'plus tax.';
6 | return `${user} your total is: ${price} ${taxes}`;
7 | }
8 | // END:final
9 |
10 | // START:remove
11 | function applyPrice(item, getTaxInformation, domService) {
12 | const user = domService.get('user');
13 | const message = formatPrice(item, user, getTaxInformation);
14 | return domService.set('total', message);
15 | }
16 | // END:remove
17 |
18 | export { applyPrice, formatPrice };
19 |
--------------------------------------------------------------------------------
/functions/oldTest/test.spec.js:
--------------------------------------------------------------------------------
1 | import expect from 'expect';
2 |
3 | import { applyPrice, formatPrice } from './test';
4 |
5 | describe('apply price', () => {
6 | it('can be tested with a spy', () => {
7 | const domMock = {
8 | message: '',
9 | get() { return 'Aaron'; },
10 | set(id, message) {
11 | this.message = message;
12 | },
13 | };
14 | applyPrice({ price: 30 }, () => 0.1, domMock);
15 | expect(domMock.message).toEqual('Aaron your total is: 30 plus $3 in taxes.');
16 | });
17 | });
18 |
19 | describe('format price', () => {
20 | it('should return plus tax if no tax info', () => {
21 | const item = { price: 30, location: 'Oklahoma' };
22 | const message = formatPrice(item, 'Aaron Cometbus', () => null);
23 | expect(message).toEqual('Aaron Cometbus your total is: 30 plus tax.');
24 | });
25 |
26 | it('should return plus tax information', () => {
27 | const item = { price: 30, location: 'Oklahoma' };
28 | const message = formatPrice(item, 'Aaron Cometbus', () => 0.1);
29 | expect(message).toEqual('Aaron Cometbus your total is: 30 plus $3 in taxes.');
30 | });
31 | });
32 |
--------------------------------------------------------------------------------
/functions/partial/partial.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-unused-vars */
2 |
3 | // START:info
4 | const building = {
5 | hours: '8 a.m. - 8 p.m.',
6 | address: 'Jayhawk Blvd',
7 | };
8 |
9 | const manager = {
10 | name: 'Augusto',
11 | phone: '555-555-5555',
12 | };
13 |
14 | const program = {
15 | name: 'Presenting Research',
16 | room: '415',
17 | hours: '3 - 6',
18 | };
19 |
20 | const exhibit = {
21 | name: 'Emerging Scholarship',
22 | contact: 'Dyan',
23 | };
24 | // END:info
25 |
26 | // START:func
27 | function mergeProgramInformation(building, manager) {
28 | const { hours, address } = building;
29 | const { name, phone } = manager;
30 | const defaults = {
31 | hours,
32 | address,
33 | contact: name,
34 | phone,
35 | };
36 |
37 | return program => {
38 | return { ...defaults, ...program };
39 | };
40 | }
41 | // END:func
42 |
43 | // START:invoke
44 | const programInfo = mergeProgramInformation(building, manager)(program);
45 | // {
46 | // name: 'Presenting Research',
47 | // room: '415',
48 | // hours: '3 - 6',
49 | // address: 'Jayhawk Blvd',
50 | // contact: 'Augusto',
51 | // phone: '555-555-5555'
52 | // }
53 |
54 | const exhibitInfo = mergeProgramInformation(building, manager)(exhibit);
55 | // {
56 | // name: 'Emerging Scholarship',
57 | // contact: 'Dyan'
58 | // hours: '8 a.m. - 8 p.m.',
59 | // address: 'Jayhawk Blvd'
60 | // phone: '555-555-5555'
61 | // }
62 | // END:invoke
63 |
64 | function getBirds(...states) {
65 | return ['meadowlark', 'robin', 'roadrunner'];
66 | }
67 | // START:birds
68 | const birds = getBirds('kansas', 'wisconsin', 'new mexico');
69 | // ['meadowlark', 'robin', 'roadrunner']
70 | // END:birds
71 |
72 | // START:zip
73 | const zip = (...left) => (...right) => {
74 | return left.map((item, i) => [item, right[i]]);
75 | };
76 | zip('kansas', 'wisconsin', 'new mexico')(...birds);
77 | // [
78 | // ['kansas', 'meadowlark'],
79 | // ['wisconsin', 'robin'],
80 | // ['new mexico', 'roadrunner']
81 | // ]
82 | // END:zip
83 |
84 | export { building, manager, exhibit, program, zip, mergeProgramInformation };
85 |
--------------------------------------------------------------------------------
/functions/partial/partial.spec.js:
--------------------------------------------------------------------------------
1 | import expect from 'expect';
2 | import {
3 | mergeProgramInformation as mergeProblem,
4 | } from './problem';
5 | import {
6 | setStrongHallProgram,
7 | } from './program';
8 |
9 | import {
10 | building,
11 | exhibit,
12 | manager,
13 | mergeProgramInformation,
14 | program,
15 | zip,
16 | } from './partial';
17 |
18 | describe('partially applied functions', () => {
19 | const programInfo = {
20 | name: 'Presenting Research',
21 | room: '415',
22 | hours: '3 - 6',
23 | address: 'Jayhawk Blvd',
24 | contact: 'Augusto',
25 | phone: '555-555-5555',
26 | };
27 | const exhibitInfo = {
28 | name: 'Emerging Scholarship',
29 | contact: 'Dyan',
30 | hours: '8 a.m. - 8 p.m.',
31 | address: 'Jayhawk Blvd',
32 | phone: '555-555-5555',
33 | };
34 |
35 | it('should merge program information', () => {
36 | expect(mergeProblem(building, manager, program)).toEqual(programInfo);
37 | expect(mergeProblem(building, manager, exhibit)).toEqual(exhibitInfo);
38 | });
39 |
40 | it('should merge program information', () => {
41 | expect(mergeProgramInformation(building, manager)(program)).toEqual(programInfo);
42 | expect(mergeProgramInformation(building, manager)(exhibit)).toEqual(exhibitInfo);
43 | });
44 |
45 | it('should encapsulate some information', () => {
46 | expect(setStrongHallProgram(program)).toEqual(programInfo);
47 | expect(setStrongHallProgram(exhibit)).toEqual(exhibitInfo);
48 | });
49 |
50 | it('should zip together information', () => {
51 | const states = ['kansas', 'wisconsin', 'new mexico'];
52 | const birds = ['meadowlark', 'robin', 'roadrunner'];
53 | expect(zip(...states)(...birds)).toEqual([
54 | ['kansas', 'meadowlark'],
55 | ['wisconsin', 'robin'],
56 | ['new mexico', 'roadrunner'],
57 | ]);
58 | });
59 | });
60 |
--------------------------------------------------------------------------------
/functions/partial/problem.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-unused-vars */
2 |
3 | import { building, manager, program, exhibit } from './partial';
4 |
5 | // START:func
6 | function mergeProgramInformation(building, manager, program) {
7 | const { hours, address } = building;
8 | const { name, phone } = manager;
9 | const defaults = {
10 | hours,
11 | address,
12 | contact: name,
13 | phone,
14 | };
15 |
16 | return { ...defaults, ...program };
17 | }
18 | // END:func
19 |
20 | // START:implement
21 | const programInfo = mergeProgramInformation(building, manager, program);
22 |
23 | const exhibitInfo = mergeProgramInformation(building, manager, exhibit);
24 | // END:implement
25 |
26 | export { mergeProgramInformation };
27 |
--------------------------------------------------------------------------------
/functions/partial/program.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-undef,no-unused-vars */
2 | import {
3 | building,
4 | exhibit,
5 | manager,
6 | mergeProgramInformation,
7 | program,
8 | } from './partial';
9 |
10 | // START:program
11 | const setStrongHallProgram = mergeProgramInformation(building, manager);
12 |
13 | const programInfo = setStrongHallProgram(program);
14 |
15 | const exhibitInfo = setStrongHallProgram(exhibit);
16 | // END:program
17 |
18 | export { setStrongHallProgram };
19 |
--------------------------------------------------------------------------------
/functions/test/problem.js:
--------------------------------------------------------------------------------
1 | import { getTaxInformation } from './taxService';
2 |
3 | function formatPrice(user, { price, location }) {
4 | const rate = getTaxInformation(location); //
5 | const taxes = rate ? `plus $${price * rate} in taxes.` : 'plus tax.';
6 |
7 | return `${user} your total is: ${price} ${taxes}`;
8 | }
9 |
10 | export { formatPrice };
11 |
--------------------------------------------------------------------------------
/functions/test/problem.spec.js:
--------------------------------------------------------------------------------
1 | import expect from 'expect';
2 |
3 | import sinon from 'sinon';
4 | import * as taxService from './taxService';
5 | import { formatPrice } from './problem';
6 |
7 | describe('format price', () => {
8 | let taxStub;
9 |
10 | beforeEach(() => {
11 | taxStub = sinon.stub(taxService, 'getTaxInformation'); //
12 | });
13 |
14 | afterEach(() => {
15 | taxStub.restore(); //
16 | });
17 |
18 | it('should return plus tax if no tax info', () => {
19 | taxStub.returns(null); //
20 | const item = { price: 30, location: 'Oklahoma' };
21 | const user = 'Aaron Cometbus';
22 | const message = formatPrice(user, item);
23 | const expectedMessage = 'Aaron Cometbus your total is: 30 plus tax.';
24 | expect(message).toEqual(expectedMessage);
25 | });
26 |
27 | it('should return plus tax information', () => {
28 | taxStub.returns(0.1);
29 |
30 | const item = { price: 30, location: 'Oklahoma' };
31 | const user = 'Aaron Cometbus';
32 | const message = formatPrice(user, item);
33 | const expectedMessage = 'Aaron Cometbus your total is: 30 plus $3 in taxes.';
34 | expect(message).toEqual(expectedMessage);
35 | });
36 | });
37 |
--------------------------------------------------------------------------------
/functions/test/routing.js:
--------------------------------------------------------------------------------
1 | function redirect() {
2 | return true;
3 | }
4 |
5 | export { redirect };
6 |
--------------------------------------------------------------------------------
/functions/test/taxService.js:
--------------------------------------------------------------------------------
1 | // stub
2 | function getTaxInformation(location) {
3 | return location;
4 | }
5 |
6 | export { getTaxInformation };
7 |
--------------------------------------------------------------------------------
/functions/test/test.js:
--------------------------------------------------------------------------------
1 |
2 | // START:final
3 | function formatPrice(user, { price, location }, getTaxInformation) {
4 | const rate = getTaxInformation(location);
5 | const taxes = rate ? `plus $${price * rate} in taxes.` : 'plus tax.';
6 | return `${user} your total is: ${price} ${taxes}`;
7 | }
8 | // END:final
9 |
10 | export { formatPrice };
11 |
--------------------------------------------------------------------------------
/functions/test/test.spec.js:
--------------------------------------------------------------------------------
1 | import expect from 'expect';
2 |
3 | import { formatPrice } from './test';
4 |
5 | describe('format price', () => {
6 | it('should return plus tax if no tax info', () => {
7 | const item = { price: 30, location: 'Oklahoma' };
8 | const user = 'Aaron Cometbus';
9 | const message = formatPrice(user, item, () => null);
10 | expect(message).toEqual('Aaron Cometbus your total is: 30 plus tax.');
11 | });
12 |
13 | it('should return plus tax information', () => {
14 | const item = { price: 30, location: 'Oklahoma' };
15 | const user = 'Aaron Cometbus';
16 | const message = formatPrice(user, item, () => 0.1);
17 | expect(message).toEqual('Aaron Cometbus your total is: 30 plus $3 in taxes.');
18 | });
19 | });
20 |
--------------------------------------------------------------------------------
/loops/arrow/anonymous.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable func-names */
2 |
3 | // #START:capitalize
4 | const capitalize = function (name) {
5 | return name[0].toUpperCase() + name.slice(1);
6 | };
7 | // #END:capitalize
8 |
9 | export { capitalize };
10 |
--------------------------------------------------------------------------------
/loops/arrow/arrow.js:
--------------------------------------------------------------------------------
1 | // #START:key
2 | const key = () => {
3 | return 'abc123';
4 | };
5 | // #END:key
6 |
7 | // #START:capitalize
8 | const capitalize = name => {
9 | return name[0].toUpperCase() + name.slice(1);
10 | };
11 | // #END:capitalize
12 |
13 | // #START:greet
14 | const greet = (first, last) => {
15 | return `Hello, ${capitalize(first)} ${capitalize(last)}`;
16 | };
17 | // #END:greet
18 |
19 | // #START:formatUser
20 | const formatUser = name => `${capitalize(name)} is logged in.`;
21 | // #END:formatUser
22 |
23 | function applyCustomGreeting(name, callback) {
24 | return callback(capitalize(name));
25 | }
26 |
27 | function greetWithExcitement() {
28 | const greeting =
29 | // #START:greetWithExcitement
30 | applyCustomGreeting('joe', name => `Hi, ${name}!`);
31 | // #END:greetWithExcitement
32 | return greeting;
33 | }
34 |
35 | export { key, capitalize, greet, formatUser, greetWithExcitement };
36 |
--------------------------------------------------------------------------------
/loops/arrow/arrow.spec.js:
--------------------------------------------------------------------------------
1 | import expect from 'expect';
2 | import { greetWithExcitement, key, capitalize, greet, formatUser } from './arrow';
3 | import {
4 | key as keyF,
5 | capitalize as capitalizeF,
6 | formatUser as formatUserF,
7 | greetWithExcitement as greetWithExcitementF,
8 | } from './full';
9 |
10 | describe('full functions', () => {
11 | it('should take no parameters', () => {
12 | expect(keyF()).toEqual('abc123');
13 | });
14 |
15 | it('should take one parameter', () => {
16 | expect(capitalizeF('joe')).toEqual('Joe');
17 | });
18 |
19 | it('should take several parameters', () => {
20 | expect(greetWithExcitementF('joe')).toEqual('Hi, Joe!');
21 | });
22 |
23 | it('should have implicit return', () => {
24 | expect(formatUserF('joe')).toEqual('Joe is logged in.');
25 | });
26 |
27 | it('should take a callback', () => {
28 | expect(greetWithExcitementF()).toEqual('Hi, Joe!');
29 | });
30 | });
31 |
32 | describe('arrow functions', () => {
33 | it('should take no parameters', () => {
34 | expect(key()).toEqual('abc123');
35 | });
36 |
37 | it('should take one parameter', () => {
38 | expect(capitalize('joe')).toEqual('Joe');
39 | });
40 |
41 | it('should take several parameters', () => {
42 | expect(greet('joe', 'morgan')).toEqual('Hello, Joe Morgan');
43 | });
44 |
45 | it('should have implicit return', () => {
46 | expect(formatUser('joe')).toEqual('Joe is logged in.');
47 | });
48 |
49 | it('should take a callback', () => {
50 | expect(greetWithExcitement()).toEqual('Hi, Joe!');
51 | });
52 | });
53 |
--------------------------------------------------------------------------------
/loops/arrow/full.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable prefer-arrow, no-unused-vars, func-names, prefer-arrow-callback */
2 |
3 | // #START:key
4 | function key() {
5 | return 'abc123';
6 | }
7 | // #END:key
8 |
9 | // #START:capitalize
10 | function capitalize(name) {
11 | return name[0].toUpperCase() + name.slice(1);
12 | }
13 | // #END:capitalize
14 |
15 | // #START:greet
16 | function greet(first, last) {
17 | return `Hello, ${capitalize(first)} ${capitalize(last)}`;
18 | }
19 | // #END:greet
20 |
21 | // #START:formatUser
22 | function formatUser(name) {
23 | return `${capitalize(name)} is logged in.`;
24 | }
25 | // #END:formatUser
26 |
27 | // #START:applyCustomGreeting
28 | function applyCustomGreeting(name, callback) {
29 | return callback(capitalize(name));
30 | }
31 | // #END:applyCustomGreeting
32 |
33 | function greetWithExcitement() {
34 | const greeting =
35 | // #START:greetWithExcitement
36 | applyCustomGreeting('joe', function (name) {
37 | return `Hi, ${name}!`;
38 | });
39 | // #END:greetWithExcitement
40 | return greeting;
41 | }
42 |
43 | export {
44 | applyCustomGreeting,
45 | capitalize,
46 | formatUser,
47 | greet,
48 | greetWithExcitement,
49 | key,
50 | };
51 |
--------------------------------------------------------------------------------
/loops/chain/chain.js:
--------------------------------------------------------------------------------
1 | const students = [
2 | {
3 | focus: 'nagarjuna',
4 | },
5 | {
6 | focus: 'logic',
7 | },
8 | {
9 | focus: 'consciousness',
10 | },
11 | {
12 | focus: '',
13 | },
14 | {
15 | focus: 'logic',
16 | },
17 | ];
18 |
19 | const focuses = students
20 | .map(student => student.focus)
21 | .filter(focus => focus)
22 | .reduce((focuses, focus) => {
23 | const count = focuses.get(focus) || 0;
24 | focuses.set(focus, count + 1);
25 | return focuses;
26 | }, new Map());
27 |
28 | const formattedFocus = [...focuses]
29 | .sort()
30 | .map(([name, count]) => `${name}: ${count}`);
31 |
32 | formattedFocus;
33 |
34 | // START:expanded
35 | const sailors = [
36 | {
37 | name: 'yi hong',
38 | active: true,
39 | email: 'yh@yhproductions.io',
40 | },
41 | {
42 | name: 'alex',
43 | active: true,
44 | email: '',
45 | },
46 | {
47 | name: 'nathan',
48 | active: false,
49 | email: '',
50 | },
51 | ];
52 | // END:expanded
53 |
54 | function sendActiveMemberEmail(sailors, sendEmail) {
55 | // START:email
56 | sailors
57 | .filter(sailor => sailor.active)
58 | .map(sailor => sailor.email || `${sailor.name}@wiscsail.io`)
59 | .forEach(sailor => sendEmail(sailor));
60 | // END:email
61 | }
62 |
63 | export { sailors, sendActiveMemberEmail };
64 |
--------------------------------------------------------------------------------
/loops/chain/chain.spec.js:
--------------------------------------------------------------------------------
1 | import expect from 'expect';
2 | import sinon from 'sinon';
3 |
4 | import { sailors, sendActiveMemberEmail } from './chain';
5 | import { sendActiveMemberEmail as sendActiveMemberEmailFull } from './full';
6 |
7 | describe('chaining', () => {
8 | it('should get only send to active members', () => {
9 | const sendInvitationSpy = sinon.spy();
10 |
11 | sendActiveMemberEmailFull(sailors, sendInvitationSpy);
12 | expect(sendInvitationSpy.calledTwice).toEqual(true);
13 | });
14 |
15 | it('should get only send to active members', () => {
16 | const sendInvitationSpy = sinon.spy();
17 |
18 | sendActiveMemberEmail(sailors, sendInvitationSpy);
19 | expect(sendInvitationSpy.calledTwice).toEqual(true);
20 | });
21 |
22 | it('should get normalize emails', () => {
23 | const sendInvitationSpy = sinon.spy();
24 |
25 | sendActiveMemberEmail(sailors, sendInvitationSpy);
26 | expect(sendInvitationSpy.getCall(0).args[0]).toEqual('yh@yhproductions.io');
27 | expect(sendInvitationSpy.getCall(1).args[0]).toEqual('alex@wiscsail.io');
28 | });
29 | });
30 |
--------------------------------------------------------------------------------
/loops/chain/full.js:
--------------------------------------------------------------------------------
1 | function sendActiveMemberEmail(sailors, sendEmail) {
2 | // START:active
3 | const active = sailors.filter(sailor => sailor.active);
4 |
5 | // [
6 | // {
7 | // name: 'yi hong',
8 | // active: true,
9 | // email: 'yh@yhproductions.io',
10 | // },
11 | // {
12 | // name: 'alex',
13 | // active: true,
14 | // email: '',
15 | // },
16 | // ];
17 | // END:active
18 |
19 | // START:email
20 | const emails = active.map(member => member.email || `${member.name}@wiscsail.io`);
21 |
22 | // [ 'yh@yhproductions.io', 'alex@wiscsail.io' ]
23 | // END:email
24 |
25 | // START:send
26 | emails.forEach(sailor => sendEmail(sailor));
27 | // END:send
28 | }
29 |
30 | export { sendActiveMemberEmail };
31 |
--------------------------------------------------------------------------------
/loops/filter/filter.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-unused-vars */
2 |
3 | const team = [
4 | 'Michelle B',
5 | 'Dave L',
6 | 'Dave C',
7 | 'Courtney B',
8 | 'Davina M',
9 | ];
10 |
11 | function getDaveVariants(team) {
12 | // START:filter
13 | const daves = team.filter(member => member.match(/Da/));
14 | // END:filter
15 | return daves;
16 | }
17 |
18 | const instructors = [
19 | {
20 | name: 'Jim',
21 | libraries: ['MERIT'],
22 | },
23 | {
24 | name: 'Sarah',
25 | libraries: ['Memorial', 'SLIS'],
26 | },
27 | {
28 | name: 'Eliot',
29 | libraries: ['College Library'],
30 | },
31 | ];
32 |
33 | function findMemorialInstructor(instructors) {
34 | // START:findInstructor
35 | const librarian = instructors.find(instructor => {
36 | return instructor.libraries.includes('Memorial');
37 | });
38 | // END:findInstructor
39 |
40 | return librarian;
41 | }
42 |
43 | function findAnyInstructor(instructors) {
44 | // START:findInstructorCurry
45 | const findByLibrary = library => instructor => {
46 | return instructor.libraries.includes(library);
47 | };
48 | const librarian = instructors.find(findByLibrary('MERIT'));
49 |
50 | // {
51 | // name: 'Jim',
52 | // libraries: ['MERIT'],
53 | // }
54 | // END:findInstructorCurry
55 |
56 | return librarian;
57 | }
58 |
59 | // START:score
60 | const scores = [30, 82, 70, 45];
61 | function getNumberOfPassingScores(scores) {
62 | const passing = scores.filter(score => score > 59);
63 | // [70, 82]
64 | return passing.length;
65 | }
66 | // 2
67 |
68 | // END:score
69 |
70 | // START:perfect
71 | function getPerfectScores(scores) {
72 | const perfect = scores.filter(score => score === 100);
73 | // []
74 | return perfect.length;
75 | }
76 | // 0
77 |
78 | // END:perfect
79 |
80 | export {
81 | scores,
82 | getDaveVariants,
83 | findAnyInstructor,
84 | findMemorialInstructor,
85 | getNumberOfPassingScores,
86 | getPerfectScores,
87 | instructors,
88 | team,
89 | };
90 |
--------------------------------------------------------------------------------
/loops/filter/filter.spec.js:
--------------------------------------------------------------------------------
1 | import expect from 'expect';
2 | import {
3 | getDaveVariants,
4 | findMemorialInstructor,
5 | findAnyInstructor,
6 | getNumberOfPassingScores,
7 | getPerfectScores,
8 | instructors,
9 | scores,
10 | team,
11 | } from './filter';
12 | import {
13 | getDaveVariants as getDaveVariantsFull,
14 | findMemorialInstructor as findMemorialInstructorFull,
15 | } from './full';
16 |
17 | describe('filters', () => {
18 | it('should get the daves', () => {
19 | expect(getDaveVariants(team).length).toEqual(3);
20 | });
21 |
22 | it('should find a single instructor', () => {
23 | expect(findMemorialInstructor(instructors).name).toEqual('Sarah');
24 | });
25 |
26 | it('should get the daves', () => {
27 | expect(getDaveVariantsFull(team).length).toEqual(3);
28 | });
29 |
30 | it('should find a single instructor', () => {
31 | expect(findMemorialInstructorFull(instructors).name).toEqual('Sarah');
32 | });
33 |
34 | it('should get passing scores', () => {
35 | expect(getNumberOfPassingScores(scores)).toEqual(2);
36 | });
37 |
38 | it('should get perfect scores', () => {
39 | expect(getPerfectScores(scores)).toEqual(0);
40 | });
41 |
42 | it('should use a curry functions', () => {
43 | expect(findAnyInstructor(instructors).name).toEqual('Jim');
44 | });
45 | });
46 |
--------------------------------------------------------------------------------
/loops/filter/full.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-unused-vars */
2 |
3 | // START:team
4 | const team = [
5 | 'Michelle B',
6 | 'Dave L',
7 | 'Dave C',
8 | 'Courtney B',
9 | 'Davina M',
10 | ];
11 | // END:team
12 |
13 | function getDaveVariants(team) {
14 | // START:filter
15 | const daves = [];
16 | for (let i = 0; i < team.length; i++) {
17 | if (team[i].match(/Da/)) {
18 | daves.push(team[i]);
19 | }
20 | }
21 | // END:filter
22 | return daves;
23 | }
24 |
25 | // START:instructors
26 | const instructors = [
27 | {
28 | name: 'Jim',
29 | libraries: ['MERIT'],
30 | },
31 | {
32 | name: 'Sarah',
33 | libraries: ['Memorial', 'SLIS'],
34 | },
35 | {
36 | name: 'Eliot',
37 | libraries: ['College Library'],
38 | },
39 | ];
40 | // END:instructors
41 |
42 | function findMemorialInstructor(instructors) {
43 | // START:findInstructor
44 | let memorialInstructor;
45 | for (let i = 0; i < instructors.length; i++) {
46 | if (instructors[i].libraries.includes('Memorial')) {
47 | memorialInstructor = instructors[i];
48 | break;
49 | }
50 | }
51 | // END:findInstructor
52 | return memorialInstructor;
53 | }
54 |
55 | export {
56 | getDaveVariants,
57 | findMemorialInstructor,
58 | };
59 |
--------------------------------------------------------------------------------
/loops/for/for.js:
--------------------------------------------------------------------------------
1 | // START:firms
2 | const firms = new Map()
3 | .set(10, 'Ivie Group')
4 | .set(23, 'Soundscaping Source')
5 | .set(31, 'Big 6');
6 | // END:firms
7 |
8 | function checkConflicts(firms, isAvailable) {
9 | // START:for
10 | for (const firm of firms) {
11 | const [id, name] = firm;
12 | if (!isAvailable(id)) {
13 | return `${name} is not available`;
14 | }
15 | }
16 | return 'All firms are available';
17 | // END:for
18 | }
19 |
20 | export { firms, checkConflicts };
21 |
--------------------------------------------------------------------------------
/loops/for/forin.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable quote-props */
2 |
3 | // START:firms
4 | const firms = {
5 | '10': 'Ivie Group',
6 | '23': 'Soundscaping Source',
7 | '31': 'Big 6',
8 | };
9 | // END:firms
10 |
11 | function checkConflicts(firms, isAvailable) {
12 | // START:for
13 | for (const id in firms) {
14 | if (!isAvailable(parseInt(id, 10))) {
15 | return `${firms[id]} is not available`;
16 | }
17 | }
18 | return 'All firms are available';
19 | // END:for
20 | }
21 |
22 | export { firms, checkConflicts };
23 |
--------------------------------------------------------------------------------
/loops/for/full.js:
--------------------------------------------------------------------------------
1 | function checkConflicts(firms, isAvailable) {
2 | // START:reduce
3 | const message = [...firms].reduce((availability, firm) => {
4 | const [id, name] = firm;
5 | if (!isAvailable(id)) {
6 | return `${name} is not available`;
7 | }
8 | return availability;
9 | }, 'All firms are available');
10 | return message;
11 | // END:reduce
12 | }
13 |
14 | function findConflicts(firms, isAvailable) {
15 | // START:find
16 | const unavailable = [...firms].find(firm => {
17 | const [id] = firm;
18 | return !isAvailable(id);
19 | });
20 |
21 | if (unavailable) {
22 | return `${unavailable[1]} is not available`;
23 | }
24 |
25 | return 'All firms are available';
26 | // END:find
27 | }
28 |
29 | function isValid(registration) {
30 | const message = Object.keys(registration).reduce((valid, field) => {
31 | if (!registration[field]) {
32 | return `You are missing ${field}`;
33 | }
34 | return valid;
35 | }, '');
36 | return message || 'Thank You';
37 | }
38 |
39 | export { checkConflicts, findConflicts, isValid };
40 |
--------------------------------------------------------------------------------
/loops/for/traditional.js:
--------------------------------------------------------------------------------
1 | function checkConflicts(firms, isAvailable) {
2 | // START:loop
3 | const entries = [...firms];
4 | for (let i = 0; i < entries.length; i++) {
5 | const [id, name] = entries[i];
6 | if (!isAvailable(id)) {
7 | return `${name} is not available`;
8 | }
9 | }
10 | return 'All firms are available';
11 | // END:loop
12 | }
13 |
14 | export { checkConflicts };
15 |
--------------------------------------------------------------------------------
/loops/forEach/forEach.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-unused-vars, prefer-const */
2 |
3 | function noChange() {
4 | // START:nochange
5 | const names = ['walter', 'white'];
6 | const capitalized = names.forEach(name => name.toUpperCase());
7 |
8 | capitalized;
9 | // undefined
10 | // END:nochange
11 | return capitalized;
12 | }
13 |
14 | function mutateChange() {
15 | // START:mutate
16 | const names = ['walter', 'white'];
17 | let capitalized = [];
18 | names.forEach(name => capitalized.push(name.toUpperCase()));
19 |
20 | capitalized;
21 | // ['WALTER', 'WHITE'];
22 | // END:mutate
23 |
24 | return capitalized;
25 | }
26 |
27 | // START:sailors
28 | const sailingClub = [
29 | 'yi hong',
30 | 'andy',
31 | 'darcy',
32 | 'jessi',
33 | 'alex',
34 | 'nathan',
35 | ];
36 | // END:sailors
37 |
38 | function sendInvitation(sailingClub, sendEmail) {
39 | // START:email
40 | sailingClub.forEach(member => sendEmail(member));
41 | // END:email
42 | }
43 |
44 | export { mutateChange, noChange, sailingClub, sendInvitation };
45 |
--------------------------------------------------------------------------------
/loops/forEach/forEach.spec.js:
--------------------------------------------------------------------------------
1 | import expect from 'expect';
2 | import sinon from 'sinon';
3 |
4 | import { sendInvitation as sendInvitationFull } from './full';
5 | import { mutateChange, noChange, sailingClub, sendInvitation } from './forEach';
6 |
7 | describe('forEach', () => {
8 | it('should send an email to each person with a for loop', () => {
9 | const sendInvitationSpy = sinon.spy();
10 | sendInvitationFull(sailingClub, sendInvitationSpy);
11 | expect(sendInvitationSpy.getCalls().length).toEqual(6);
12 | });
13 |
14 | it('should send an email to each person', () => {
15 | const sendInvitationSpy = sinon.spy();
16 | sendInvitation(sailingClub, sendInvitationSpy);
17 | expect(sendInvitationSpy.getCalls().length).toEqual(6);
18 | });
19 |
20 | it('should not make a change on a forEach loop', () => {
21 | expect(noChange()).toEqual(undefined);
22 | });
23 |
24 | it('should mutate an array on a forEach loop', () => {
25 | expect(mutateChange()).toEqual(['WALTER', 'WHITE']);
26 | });
27 | });
28 |
--------------------------------------------------------------------------------
/loops/forEach/full.js:
--------------------------------------------------------------------------------
1 | function sendInvitation(sailingClub, sendEmail) {
2 | // START:email
3 | for (let i = 0; i < sailingClub.length; i++) {
4 | sendEmail(sailingClub[i]);
5 | }
6 | // END:email
7 | }
8 |
9 | export { sendInvitation };
10 |
--------------------------------------------------------------------------------
/loops/map/full.js:
--------------------------------------------------------------------------------
1 | function getInstruments(band) {
2 | // START:getInstruments
3 | const instruments = [];
4 | for (let i = 0; i < band.length; i++) {
5 | const instrument = band[i].instrument; //
6 | instruments.push(instrument); //
7 | }
8 | // END:getInstruments
9 | return instruments;
10 | }
11 |
12 | // START:getInstrument
13 | function getInstrument(member) {
14 | return member.instrument;
15 | }
16 | // END:getInstrument
17 |
18 | function getInstruments2(band) {
19 | // START:getInstruments2
20 | const instruments = [];
21 | for (let i = 0; i < band.length; i++) {
22 | instruments.push(getInstrument(band[i]));
23 | }
24 | // END:getInstruments2
25 | return instruments;
26 | }
27 |
28 | export { getInstruments, getInstruments2 };
29 |
--------------------------------------------------------------------------------
/loops/map/map.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-unused-vars */
2 |
3 | // #START:band
4 | const band = [
5 | {
6 | name: 'corbett',
7 | instrument: 'guitar',
8 | },
9 | {
10 | name: 'evan',
11 | instrument: 'guitar',
12 | },
13 | {
14 | name: 'sean',
15 | instrument: 'bass',
16 | },
17 | {
18 | name: 'brett',
19 | instrument: 'drums',
20 | },
21 | ];
22 | // #END:band
23 |
24 |
25 | function getInstruments() {
26 | // START:getInstruments
27 | function getInstrument(member) {
28 | return member.instrument;
29 | }
30 |
31 | const instruments = band.map(getInstrument);
32 | // ['guitar', 'guitar', 'bass', 'drums']
33 | // END:getInstruments
34 | return instruments;
35 | }
36 |
37 | function getInstruments2() {
38 | // START:getInstruments2
39 |
40 | const instruments = band.map(member => member.instrument);
41 | // ['guitar', 'guitar', 'bass', 'drums']
42 | // END:getInstruments2
43 | return instruments;
44 | }
45 |
46 | function getDogs(env) {
47 | return () => {
48 | if (env === 'production') {
49 | return fetch('http://dog.foo');
50 | }
51 | return fetch('http://localhost:8888');
52 | };
53 | }
54 |
55 | function getCats(env) {
56 | return () => {
57 | if (env === 'production') {
58 | return fetch('http://dog.foo');
59 | }
60 | return fetch('http://localhost:8888');
61 | };
62 | }
63 |
64 | function setUpLocal(...fetchers) {
65 | return fetchers.map(fetcher => fetcher('local'));
66 | }
67 |
68 | export { getInstruments, getInstruments2 };
69 |
--------------------------------------------------------------------------------
/loops/map/map.spec.js:
--------------------------------------------------------------------------------
1 | import expect from 'expect';
2 | import { getInstruments, getInstruments2 } from './map';
3 | import { getInstruments as g1, getInstruments2 as g2 } from './full';
4 |
5 | describe('full loops', () => {
6 | const band = [
7 | {
8 | name: 'corbett',
9 | instrument: 'guitar',
10 | },
11 | {
12 | name: 'evan',
13 | instrument: 'guitar',
14 | },
15 | {
16 | name: 'sean',
17 | instrument: 'bass',
18 | },
19 | {
20 | name: 'brett',
21 | instrument: 'drums',
22 | },
23 | ];
24 |
25 | it('should get instruments', () => {
26 | expect(g1(band)).toEqual(['guitar', 'guitar', 'bass', 'drums']);
27 | });
28 |
29 | it('should get instruments with anonymous function', () => {
30 | expect(g2(band)).toEqual(['guitar', 'guitar', 'bass', 'drums']);
31 | });
32 | });
33 |
34 | describe('map', () => {
35 | it('should get instruments', () => {
36 | expect(getInstruments()).toEqual(['guitar', 'guitar', 'bass', 'drums']);
37 | });
38 |
39 | it('should get instruments with anonymous function', () => {
40 | expect(getInstruments2()).toEqual(['guitar', 'guitar', 'bass', 'drums']);
41 | });
42 | });
43 |
--------------------------------------------------------------------------------
/loops/methods/methods.js:
--------------------------------------------------------------------------------
1 |
2 | function getPrices() {
3 | // START:formattedPrices
4 | const prices = ['1.0', '2.15'];
5 | const formattedPrices = prices.map(price => parseFloat(price));
6 | // [1.0, 2.15];
7 | // END: formattedPrices
8 | return formattedPrices;
9 | }
10 |
11 | function getPrices2() {
12 | // START:pricesFloat
13 | const prices = ['1.0', 'negotiable', '2.15'];
14 | const formattedPrices = prices.map(price => parseFloat(price))
15 | // [1.0, NaN, 2.15]
16 | .filter(price => price);
17 | // [1.0, 2.15]
18 | // END:pricesFloat
19 | return formattedPrices;
20 | }
21 |
22 | export { getPrices, getPrices2 };
23 |
--------------------------------------------------------------------------------
/loops/methods/methods.spec.js:
--------------------------------------------------------------------------------
1 | import expect from 'expect';
2 | import { getPrices, getPrices2 } from './methods';
3 | import { getPrices as gProblem, getPrices2 as gProblem2 } from './problem';
4 |
5 | describe('problem methods', () => {
6 | it('should get formatted prices', () => {
7 | expect(gProblem()).toEqual([1.0, 2.15]);
8 | });
9 |
10 | it('should get formatted prices', () => {
11 | expect(gProblem2()).toEqual([1.0, 2.15]);
12 | });
13 | });
14 |
15 | describe('solution methods', () => {
16 | it('should get formatted prices', () => {
17 | expect(getPrices()).toEqual([1.0, 2.15]);
18 | });
19 |
20 | it('should get formatted prices', () => {
21 | expect(getPrices2()).toEqual([1.0, 2.15]);
22 | });
23 | });
24 |
--------------------------------------------------------------------------------
/loops/methods/problem.js:
--------------------------------------------------------------------------------
1 | function getPrices() {
2 | // START:formattedPrices
3 | const prices = ['1.0', '2.15'];
4 |
5 | const formattedPrices = [];
6 | for (let i = 0; i < prices.length; i++) {
7 | formattedPrices.push(parseFloat(prices[i]));
8 | }
9 | // END: formattedPrices
10 | return formattedPrices;
11 | }
12 |
13 | function getPrices2() {
14 | // START:pricesFloat
15 | const prices = ['1.0', 'negotiable', '2.15'];
16 |
17 | const formattedPrices = []; //
18 | for (let i = 0; i < prices.length; i++) { //
19 | const price = parseFloat(prices[i]);
20 | if (price) { //
21 | formattedPrices.push(price);
22 | }
23 | }
24 | // END:pricesFloat
25 | return formattedPrices;
26 | }
27 |
28 | export { getPrices, getPrices2 };
29 |
--------------------------------------------------------------------------------
/loops/reduce/map.js:
--------------------------------------------------------------------------------
1 | function getAllColors(dogs) {
2 | // #START:allColors
3 | const colors = dogs.map(dog => dog.color);
4 | // #END:allColors
5 | return colors;
6 | }
7 |
8 | export { getAllColors };
9 |
--------------------------------------------------------------------------------
/loops/reduce/mistake.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable array-callback-return, consistent-return */
2 | function getColors(dogs) {
3 | // #START:colors
4 | const colors = dogs.reduce((colors, dog) => {
5 | if (colors.includes(dog.color)) {
6 | return colors;
7 | }
8 | [...colors, dog.color]; //
9 | }, []);
10 | // #END:colors
11 | return colors;
12 | }
13 |
14 | export { getColors };
15 |
--------------------------------------------------------------------------------
/loops/reduce/reduce.spec.js:
--------------------------------------------------------------------------------
1 | import expect from 'expect';
2 |
3 | import { developers, dogs, getAllColors, getColors, getSpecialtyCount, greetCity, separate } from './reduce';
4 | import { getColors as mistakeColors } from './mistake';
5 | import { getAllColors as mapColors } from './map';
6 |
7 | describe('reduce', () => {
8 | it('gets the dog colors', () => {
9 | expect(getColors(dogs)).toEqual(['black', 'chocolate']);
10 | });
11 |
12 | it('gets noting when not returned', () => {
13 | let name;
14 | let message;
15 | try {
16 | mistakeColors(dogs);
17 | } catch (e) {
18 | name = e.constructor.name;
19 | message = e.message;
20 | }
21 | expect(name).toEqual('TypeError');
22 | expect(message).toEqual("Cannot read property 'includes' of undefined");
23 | });
24 |
25 | it('should get all colors with map or reduce', () => {
26 | const colors = getAllColors(dogs);
27 | const colorsMap = mapColors(dogs);
28 | const result = ['black', 'black', 'chocolate'];
29 | expect(colors).toEqual(result);
30 | expect(colorsMap).toEqual(result);
31 | });
32 |
33 | it('should get all unique properties', () => {
34 | const filters = separate(dogs);
35 | expect([...filters.breed]).toEqual(['boston terrier', 'labrador']);
36 | expect([...filters.size]).toEqual(['small', 'large', 'medium']);
37 | expect([...filters.color]).toEqual(['black', 'chocolate']);
38 | });
39 |
40 | it('should get developer count', () => {
41 | const result = {
42 | javascript: 1,
43 | php: 1,
44 | python: 2,
45 | };
46 | expect(getSpecialtyCount(developers)).toEqual(result);
47 | });
48 |
49 | it('should pipe results', () => {
50 | expect(greetCity('kansas city')).toEqual('Greetings from Kansas City!');
51 | });
52 | });
53 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "book",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "lint": "eslint ./",
8 | "test": "mocha --require mock-local-storage --compilers js:babel-register --require babel-polyfill",
9 | "test:watch": "npm test -- --watch"
10 | },
11 | "author": "",
12 | "license": "ISC",
13 | "devDependencies": {
14 | "babel-cli": "^6.26.0",
15 | "babel-core": "^6.24.1",
16 | "babel-eslint": "^7.2.3",
17 | "babel-plugin-transform-async-to-generator": "^6.24.1",
18 | "babel-plugin-transform-class-properties": "^6.24.1",
19 | "babel-plugin-transform-object-rest-spread": "^6.23.0",
20 | "babel-polyfill": "^6.23.0",
21 | "babel-preset-env": "^1.6.0",
22 | "babel-preset-es2015": "^6.24.1",
23 | "babel-preset-es2017": "^6.24.1",
24 | "babel-preset-stage-2": "^6.24.1",
25 | "babel-register": "^6.26.0",
26 | "eslint": "^4.16.0",
27 | "eslint-config-airbnb": "^15.1.0",
28 | "eslint-plugin-import": "^2.7.0",
29 | "eslint-plugin-jsx-a11y": "^5.1.1",
30 | "eslint-plugin-react": "^7.5.1",
31 | "js-yaml": "^2.0.5",
32 | "mock-local-storage": "^1.0.5",
33 | "uglify-js": "^2.6.0"
34 | },
35 | "dependencies": {
36 | "expect": "^1.20.2",
37 | "form-data": "^2.3.1",
38 | "lodash": "^4.17.4",
39 | "mocha": "^3.2.0",
40 | "moment": "^2.20.1",
41 | "node-fetch": "^1.7.3",
42 | "sinon": "^3.2.1"
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/params/assignment/assignment.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-unused-vars */
2 | // START:landscape
3 | const landscape = {
4 | title: 'Landscape',
5 | photographer: 'Nathan',
6 | location: [32.7122222, -103.1405556],
7 | };
8 | // END:landscape
9 |
10 | const update =
11 | // START:update
12 | {
13 | title: 'Landscape',
14 | photographer: 'Nathan',
15 | city: 'Hobbs',
16 | state: 'NM',
17 | };
18 | // END:update
19 |
20 | function determineCityAndState([latitude, longitude]) {
21 | // Geo lookup would happen here
22 | // START:region
23 | const region = {
24 | city: 'Hobbs',
25 | county: 'Lea',
26 | state: {
27 | name: 'New Mexico',
28 | abbreviation: 'NM',
29 | },
30 | };
31 | // END:region
32 | return region;
33 | }
34 | // START:handle
35 | function getCityAndState({ location }) {
36 | const { city, state } = determineCityAndState(location);
37 | return {
38 | city,
39 | state: state.abbreviation,
40 | };
41 | // {
42 | // city: 'Hobbs',
43 | // state: 'NM'
44 | // }
45 | }
46 | // END:handle
47 |
48 | // START:set
49 | function setRegion({ location, ...details }) {
50 | const { city, state } = determineCityAndState(location);
51 | return {
52 | city,
53 | state: state.abbreviation,
54 | ...details,
55 | };
56 | }
57 | // END:set
58 |
59 |
60 | export { landscape, getCityAndState, setRegion, update };
61 |
--------------------------------------------------------------------------------
/params/assignment/assignment.spec.js:
--------------------------------------------------------------------------------
1 | import expect from 'expect';
2 | import {
3 | landscape,
4 | setRegion,
5 | getCityAndState,
6 | update,
7 | } from './assignment';
8 |
9 | describe('set region information', () => {
10 | it('should add city and state', () => {
11 | expect(setRegion(landscape)).toEqual(update);
12 | });
13 |
14 | it('should get the city and state', () => {
15 | expect(getCityAndState(landscape)).toEqual({
16 | city: 'Hobbs',
17 | state: 'NM',
18 | });
19 | });
20 | });
21 |
--------------------------------------------------------------------------------
/params/defaults/default.js:
--------------------------------------------------------------------------------
1 | import { roundToDecimalPlace } from './problem';
2 |
3 | // START:convert
4 | function convertWeight(weight, ounces = 0, roundTo = 2) {
5 | const total = weight + (ounces / 16);
6 | const conversion = total / 2.2;
7 |
8 | return roundToDecimalPlace(conversion, roundTo);
9 | }
10 | // END:convert
11 |
12 | // START:with
13 | convertWeight(4, 0, 2);
14 | // END:with
15 |
16 | // START:without
17 | convertWeight(4, undefined, 2);
18 | // END:without
19 | export { convertWeight };
20 |
--------------------------------------------------------------------------------
/params/defaults/default.spec.js:
--------------------------------------------------------------------------------
1 | import expect from 'expect';
2 | import {
3 | convertWeight as convertWeightSimple,
4 | } from './simple';
5 |
6 | import {
7 | convertWeight as convertWeightMore,
8 | } from './more';
9 |
10 | import {
11 | convertWeight as convertWeightProblem,
12 | } from './problem';
13 |
14 | import {
15 | convertWeight,
16 | } from './default';
17 |
18 | describe('convert weight', () => {
19 | it('should convert pounds to kilograms', () => {
20 | expect(convertWeightSimple(44)).toEqual(20);
21 | expect(convertWeightMore(44)).toEqual(20);
22 | expect(convertWeightProblem(44)).toEqual(20);
23 | expect(convertWeight(44)).toEqual(20);
24 | });
25 |
26 | it('should convert pounds and grams', () => {
27 | expect(convertWeightMore(44, 11)).toEqual(20.3125);
28 | expect(convertWeightProblem(44, 11)).toEqual(20.31);
29 | expect(convertWeight(44, 11)).toEqual(20.31);
30 | });
31 |
32 | it('round to a decimal place', () => {
33 | expect(convertWeightProblem(44, 8, 2)).toEqual(20.23);
34 | expect(convertWeight(44, 8, 2)).toEqual(20.23);
35 | expect(convertWeightProblem(44, undefined, 2)).toEqual(20);
36 | expect(convertWeight(44, undefined, 2)).toEqual(20);
37 | });
38 |
39 | it('should round correctly with falsy value', () => {
40 | expect(convertWeightProblem(44, 11, 0)).toEqual(20);
41 | expect(convertWeight(44, 11, 0)).toEqual(20);
42 | });
43 | });
44 |
--------------------------------------------------------------------------------
/params/defaults/more.js:
--------------------------------------------------------------------------------
1 | // START:convert
2 | function convertWeight(weight, ounces) {
3 | const oz = ounces ? ounces / 16 : 0;
4 | const total = weight + oz;
5 | return total / 2.2;
6 | }
7 | // END:convert
8 |
9 | export { convertWeight };
10 |
--------------------------------------------------------------------------------
/params/defaults/problem.js:
--------------------------------------------------------------------------------
1 | function roundToDecimalPlace(number, decimalPlaces) {
2 | const round = 10 ** decimalPlaces;
3 | return Math.round(number * round) / round;
4 | }
5 |
6 | // START:convert
7 | function convertWeight(weight, ounces, roundTo) {
8 | const oz = ounces / 16 || 0;
9 | const total = weight + oz;
10 | const conversion = total / 2.2;
11 |
12 | const round = roundTo === undefined ? 2 : roundTo;
13 |
14 | return roundToDecimalPlace(conversion, round);
15 | }
16 | // END:convert
17 |
18 | export { convertWeight, roundToDecimalPlace };
19 |
--------------------------------------------------------------------------------
/params/defaults/simple.js:
--------------------------------------------------------------------------------
1 | // START:convert
2 | function convertWeight(weight) {
3 | return weight / 2.2;
4 | }
5 | // END:convert
6 |
7 | export { convertWeight };
8 |
--------------------------------------------------------------------------------
/params/destructuring/alternate.js:
--------------------------------------------------------------------------------
1 | // START:func
2 | function displayPhoto(photo) {
3 | const {
4 | title,
5 | photographer = 'Anonymous',
6 | location: [latitude, longitude],
7 | src: url,
8 | ...other
9 | } = photo;
10 | const additional = Object.keys(other).map(key => `${key}: ${other[key]}`);
11 | return (`
12 |
13 | ${title}
14 | ${photographer}
15 | Latitude: ${latitude}
16 | Longitude: ${longitude}
17 | ${additional.join('
')}
18 | `);
19 | }
20 | // END:func
21 |
22 | export { displayPhoto };
23 |
--------------------------------------------------------------------------------
/params/destructuring/destructuring.js:
--------------------------------------------------------------------------------
1 | // START:landscape
2 | const landscape = {
3 | title: 'Landscape',
4 | photographer: 'Nathan',
5 | equipment: 'Canon',
6 | format: 'digital',
7 | src: '/landscape-nm.jpg',
8 | location: [32.7122222, -103.1405556],
9 | };
10 | // END:landscape
11 |
12 | const anonymous = {
13 | title: 'Kids',
14 | equipment: 'Nikon',
15 | src: '/garden.jpg',
16 | location: [38.9675338, -95.2614205],
17 | };
18 |
19 | // START:func
20 | function displayPhoto({
21 | title,
22 | photographer = 'Anonymous',
23 | location: [latitude, longitude],
24 | src: url,
25 | ...other
26 | }) {
27 | const additional = Object.keys(other).map(key => `${key}: ${other[key]}`);
28 | return (`
29 |
30 | ${title}
31 | ${photographer}
32 | Latitude: ${latitude}
33 | Longitude: ${longitude}
34 | ${additional.join('
')}
35 | `);
36 | }
37 | // END:func
38 |
39 | export { anonymous, displayPhoto, landscape };
40 |
--------------------------------------------------------------------------------
/params/destructuring/destructuring.spec.js:
--------------------------------------------------------------------------------
1 | import expect from 'expect';
2 |
3 | import {
4 | displayPhoto as displayProblem,
5 | } from './problem';
6 |
7 | import {
8 | displayPhoto as displayAlt,
9 | } from './alternate';
10 |
11 | import {
12 | anonymous,
13 | displayPhoto,
14 | landscape,
15 | } from './destructuring';
16 |
17 | describe('format photographer', () => {
18 | const photoMarkup = `
19 |
20 | Landscape
21 | Nathan
22 | Latitude: 32.7122222
23 | Longitude: -103.1405556
24 | equipment: Canon
format: digital
25 | `;
26 |
27 | const anonymousPhoto = `
28 |
29 | Kids
30 | Anonymous
31 | Latitude: 38.9675338
32 | Longitude: -95.2614205
33 | equipment: Nikon
34 | `;
35 | it('should format photo without destructuring', () => {
36 | expect(displayProblem(landscape)).toEqual(photoMarkup);
37 | expect(displayProblem(anonymous)).toEqual(anonymousPhoto);
38 | });
39 |
40 | it('should format photo with destructuring', () => {
41 | expect(displayPhoto(landscape)).toEqual(photoMarkup);
42 | expect(displayPhoto(anonymous)).toEqual(anonymousPhoto);
43 | });
44 |
45 | it('should format photo with destructuring in function body', () => {
46 | expect(displayAlt(landscape)).toEqual(photoMarkup);
47 | expect(displayAlt(anonymous)).toEqual(anonymousPhoto);
48 | });
49 | });
50 |
--------------------------------------------------------------------------------
/params/destructuring/problem.js:
--------------------------------------------------------------------------------
1 | // START:func
2 | function displayPhoto(photo) {
3 | const title = photo.title;
4 | const photographer = photo.photographer || 'Anonymous';
5 | const location = photo.location;
6 | const url = photo.src;
7 |
8 | const copy = { ...photo };
9 | delete copy.title;
10 | delete copy.photographer;
11 | delete copy.location;
12 | delete copy.src;
13 |
14 | const additional = Object.keys(copy).map(key => `${key}: ${copy[key]}`);
15 |
16 | return (`
17 |
18 | ${title}
19 | ${photographer}
20 | Latitude: ${location[0]}
21 | Longitude: ${location[1]}
22 | ${additional.join('
')}
23 | `);
24 | }
25 | // END:func
26 |
27 | export { displayPhoto };
28 |
--------------------------------------------------------------------------------
/params/rest/problem.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable prefer-rest-params */
2 | // START:arguments
3 | function getArguments() {
4 | return arguments;
5 | }
6 | getArguments('Bloomsday', 'June 16');
7 | // { '0': 'Bloomsday', '1': 'June 16' }
8 | // END:arguments
9 |
10 | // START:func
11 | function validateCharacterCount(max) {
12 | const items = Array.prototype.slice.call(arguments, 1); //
13 | return items.every(item => item.length < max);
14 | }
15 | // END:func
16 |
17 | // START:example
18 | validateCharacterCount(10, 'wvoquie');
19 | // true
20 |
21 | const tags = ['Hobbs', 'Eagles'];
22 | validateCharacterCount(10, ...tags);
23 | // true
24 | // END:example
25 |
26 | export { getArguments, validateCharacterCount };
27 |
--------------------------------------------------------------------------------
/params/rest/rest.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-console, no-unused-vars, no-undef */
2 | // START:arguments
3 | function getArguments(...args) {
4 | return args;
5 | }
6 | getArguments('Bloomsday', 'June 16');
7 | // ['Bloomsday', 'June 16']
8 | // END:arguments
9 |
10 | // START:func
11 | function validateCharacterCount(max, ...items) {
12 | return items.every(item => item.length < max);
13 | }
14 | // END:func
15 |
16 | // START:example
17 | validateCharacterCount(10, 'wvoquie');
18 | // true
19 |
20 | validateCharacterCount(10, ...['wvoquie']);
21 | // true
22 |
23 | const tags = ['Hobbs', 'Eagles'];
24 | validateCharacterCount(10, ...tags);
25 | // true
26 |
27 | validateCharacterCount(10, 'Hobbs', 'Eagles');
28 | // true
29 | // END:example
30 |
31 | function debug() {
32 | // START:debug
33 | ['Spirited Away', 'Princess Mononoke'].map((film, ...other) => {
34 | console.log(other);
35 | return film.toLowerCase();
36 | });
37 | // [0, ['Spirited Away', 'Princess Mononoke']]
38 | // [1, ['Spirited Away', 'Princess Mononoke']]
39 | // END:debug
40 | }
41 |
42 | function shift() {
43 | // START:shift
44 | const queue = ['stop', 'collaborate', 'listen'];
45 | const [first, ...remaining] = queue;
46 | first;
47 | // 'stop'
48 | remaining;
49 | // ['collaborate', 'listen'];
50 | // END:shift
51 | return [first, remaining];
52 | }
53 |
54 | // START:pass
55 | function applyChanges(...args) {
56 | updateAccount(...args);
57 | closeModal();
58 | }
59 | // END:pass
60 |
61 | export { getArguments, shift, validateCharacterCount };
62 |
--------------------------------------------------------------------------------
/params/rest/simple.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-empty */
2 | // START:func
3 | function validateCharacterCount(max, items) {
4 | return items.every(item => item.length < max);
5 | }
6 | // END:func
7 |
8 | // START:example
9 | validateCharacterCount(10, ['Hobbs', 'Eagles']);
10 | // true
11 | // END:example
12 |
13 | try {
14 | // START:typeerror
15 | validateCharacterCount(10, 'wvoquine');
16 | // TypeError: items.every is not a function
17 | // END:typeerror
18 | } catch (e) {
19 |
20 | }
21 | export { validateCharacterCount };
22 |
--------------------------------------------------------------------------------
/test/mocha.opts:
--------------------------------------------------------------------------------
1 | ./*/{,!(component|css|build|npm)/**/}/*.spec.js
2 | --recursive
3 |
--------------------------------------------------------------------------------
/variables/const/const.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-var, prefer-const */
2 | export function getTotal() {
3 | // # START:totalConst
4 | const taxRate = 0.1;
5 |
6 | const total = 100 + (100 * taxRate);
7 |
8 | // Skip 100 lines of code
9 |
10 | return `Your Order is ${total}`;
11 | // # END:totalConst
12 | }
13 |
14 | export function getTotalVar() {
15 | // # START:totalVar
16 | var taxRate = 0.1;
17 |
18 | var total = 100 + (100 * taxRate);
19 |
20 | // Skip 100 lines of code
21 |
22 | return `Your Order is ${total}`;
23 | // # END:totalVar
24 | }
25 |
26 | export function getTotalLet() {
27 | // # START:totalLet
28 | const taxRate = 0.1;
29 | const shipping = 5.00;
30 |
31 | let total = 100 + (100 * taxRate) + shipping;
32 |
33 | // Skip 100 lines of code
34 |
35 | return `Your Order is ${total}`;
36 | // # END:totalLet
37 | }
38 |
39 | export function mutableDiscount(cart) {
40 | // # START:mutate
41 | const discountable = [];
42 |
43 | // Skip some lines
44 |
45 | for (let i = 0; i < cart.length; i++) {
46 | if (cart[i].discountAvailable) {
47 | discountable.push(cart[i]);
48 | }
49 | }
50 | // # END:mutate
51 | return discountable;
52 | }
53 |
54 | export function discountable(cart) {
55 | // # START:filter
56 | const discountable = cart.filter(item => item.discountAvailable);
57 | // # END:filter
58 | return discountable;
59 | }
60 |
61 |
--------------------------------------------------------------------------------
/variables/const/const.spec.js:
--------------------------------------------------------------------------------
1 | import expect from 'expect';
2 |
3 | import { getTotal, mutableDiscount, discountable } from './const';
4 |
5 | it('should get total', () => {
6 | expect(getTotal()).toEqual('Your Order is 110');
7 | });
8 |
9 | describe('discountable', () => {
10 | const cart = [
11 | {
12 | item: 'Book',
13 | discountAvailable: false,
14 | },
15 | {
16 | item: 'Magazine',
17 | discountAvailable: true,
18 | },
19 | ];
20 |
21 | it('should get discountable', () => {
22 | expect(mutableDiscount(cart).length).toEqual(1);
23 | });
24 |
25 | it('should get discountable', () => {
26 | expect(discountable(cart).length).toEqual(1);
27 | });
28 | });
29 |
--------------------------------------------------------------------------------
/variables/let/const.js:
--------------------------------------------------------------------------------
1 | // # START:salePriceConst
2 | function getLowestPrice(item) {
3 | const count = item.inventory;
4 | let price = item.price;
5 |
6 | if (item.salePrice) {
7 | const saleCount = item.saleInventory;
8 | if (saleCount > 0) {
9 | price = item.salePrice;
10 | }
11 | }
12 |
13 | if (count) {
14 | return price;
15 | }
16 |
17 | return 0;
18 | }
19 | // # END:salePriceConst
20 |
21 | export { getLowestPrice };
22 |
--------------------------------------------------------------------------------
/variables/let/declaration.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-redeclare */
2 | // START:declaration
3 | function getLowestPriceDeclaration(item) {
4 | const count = item.inventory;
5 | let price = item.price;
6 |
7 | if (!count) {
8 | return 0;
9 | }
10 |
11 | // ...
12 |
13 | let price = item.saleInventory ? item.salePrice : item.wholesalePrice;
14 |
15 | return price;
16 | }
17 | // END:declaration
18 |
19 | export default getLowestPriceDeclaration;
20 |
--------------------------------------------------------------------------------
/variables/let/let.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-var, block-scoped-var, vars-on-top, no-redeclare, func-names, no-loop-func,
2 | no-param-reassign, no-unused-vars, no-var, prefer-const
3 | */
4 |
5 | // # START:salePriceLet
6 | function getLowestPrice(item) {
7 | let count = item.inventory;
8 | let price = item.price;
9 |
10 | if (item.salePrice) {
11 | let count = item.saleInventory;
12 | if (count > 0) {
13 | price = item.salePrice;
14 | }
15 | }
16 |
17 | if (count) {
18 | return price;
19 | }
20 |
21 | return 0;
22 | }
23 | // # END:salePriceLet
24 |
25 | // # START:scopeLet
26 | function addClickLet(items) {
27 | for (let i = 0; i < items.length; i++) { //
28 | items[i].onClick = function () { return i; };
29 | }
30 | return items;
31 | }
32 | const exampleLet = [{}, {}];
33 | const clickSetLet = addClickLet(exampleLet);
34 | clickSetLet[0].onClick();
35 | // # END:scopeLet
36 |
37 | export {
38 | getLowestPrice,
39 | };
40 |
--------------------------------------------------------------------------------
/variables/let/problem.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-var, block-scoped-var, vars-on-top, no-redeclare, func-names, no-loop-func,
2 | no-param-reassign, no-unused-vars, no-var, prefer-const
3 | */
4 | // # START:salePrice
5 | function getLowestPrice(item) {
6 | var count = item.inventory; //
7 | var price = item.price;
8 |
9 | if (item.salePrice) {
10 | var count = item.saleInventory; //
11 | if (count > 0) {
12 | price = item.salePrice;
13 | }
14 | }
15 |
16 | if (count) { //
17 | return price;
18 | }
19 |
20 | return 0;
21 | }
22 | // # END:salePrice
23 |
24 | export { getLowestPrice };
25 |
--------------------------------------------------------------------------------
/variables/literals/literals.js:
--------------------------------------------------------------------------------
1 | // START:greet
2 | function greet(name) {
3 | return `Hi, ${name}`;
4 | }
5 | greet('Leo');
6 | 'Hi, Leo';
7 | // END:greet
8 |
9 | // START:yell
10 | function yell(name) {
11 | return `HI, ${name.toUpperCase()}!`;
12 | }
13 | greet('Pankaj');
14 | 'HI, PANKAJ!';
15 | // END:yell
16 |
17 | // START:convert
18 | function leapYearConverter(age) {
19 | return `You'd be ${Math.floor(age / 4)} if born on a leap year.`;
20 | }
21 | leapYearConverter(34);
22 | // "You'd be 8 if born on a leap year."
23 | // END:convert
24 |
25 | function getProvider() {
26 | // stub for get provider
27 | return 'pragprog.com/cloud';
28 | }
29 |
30 | // START:func
31 | function generateLink(image, width) {
32 | return `https://${getProvider()}/${image}?width=${parseInt(width, 10)}`;
33 | }
34 | // END:func
35 |
36 | export { generateLink, greet, leapYearConverter, yell };
37 |
--------------------------------------------------------------------------------
/variables/literals/literals.spec.js:
--------------------------------------------------------------------------------
1 | import expect from 'expect';
2 |
3 | import { generateLink as generateConcat } from './problem';
4 | import { generateLink, greet, leapYearConverter, yell } from './literals';
5 |
6 | describe('generate link', () => {
7 | const link = 'https://pragprog.com/cloud/foo?width=200';
8 | const image = 'foo';
9 | const width = 200.5;
10 | it('should generate a link with concatenation', () => {
11 | expect(generateConcat(image, width)).toEqual(link);
12 | });
13 |
14 | it('should generate a link with literals', () => {
15 | expect(generateLink(image, width)).toEqual(link);
16 | });
17 | });
18 |
19 | describe('template demos', () => {
20 | it('should convert a variable', () => {
21 | const result = 'Hi, Leo';
22 | expect(greet('Leo')).toEqual(result);
23 | });
24 |
25 | it('should convert a variable with a method', () => {
26 | const result = 'HI, PANKAJ!';
27 | expect(yell('Pankaj')).toEqual(result);
28 | });
29 |
30 | it('should convert a template with functions', () => {
31 | const result = "You'd be 8 if born on a leap year.";
32 | expect(leapYearConverter(34)).toEqual(result);
33 | });
34 | });
35 |
--------------------------------------------------------------------------------
/variables/literals/problem.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable prefer-template */
2 | function getProvider() {
3 | // stub for get provider
4 | return 'pragprog.com/cloud';
5 | }
6 |
7 | // START:func
8 | function generateLink(image, width) {
9 | const widthInt = parseInt(width, 10);
10 | return 'https://' + getProvider() + '/' + image + '?width=' + widthInt;
11 | }
12 | // END:func
13 |
14 | export { generateLink };
15 |
--------------------------------------------------------------------------------
/variables/scope/curry.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable vars-on-top, func-names, no-loop-func,
2 | no-param-reassign, no-unused-vars, no-var */
3 |
4 | // # START:scopeSolution
5 | function addClick(items) {
6 | for (var i = 0; i < items.length; i++) {
7 | items[i].onClick = (function (i) {
8 | return function () {
9 | return i;
10 | };
11 | }(i));
12 | }
13 | return items;
14 | }
15 | const example = [{}, {}];
16 | const clickSet = addClick(example);
17 | clickSet[0].onClick();
18 | // # END:scopeSolution
19 |
20 | export { addClick };
21 |
--------------------------------------------------------------------------------
/variables/scope/problem.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable vars-on-top, func-names, no-loop-func,
2 | no-param-reassign, no-unused-vars, no-var */
3 |
4 | // # START:scope
5 | function addClick(items) {
6 | for (var i = 0; i < items.length; i++) {
7 | items[i].onClick = function () { return i; }; //
8 | }
9 | return items;
10 | }
11 | const example = [{}, {}];
12 | const clickSet = addClick(example);
13 | clickSet[0].onClick();
14 | // # END:scope
15 |
16 | export { addClick };
17 |
--------------------------------------------------------------------------------
/variables/scope/scope.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | - Say Zero
7 | - Say One
8 | - Say Two
9 |
10 |
11 |
19 |
20 |
--------------------------------------------------------------------------------
/variables/scope/scope.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable func-names, no-param-reassign */
2 |
3 | // # START:scopeLet
4 | function addClick(items) {
5 | for (let i = 0; i < items.length; i++) { //
6 | items[i].onClick = function () { return i; };
7 | }
8 | return items;
9 | }
10 | const example = [{}, {}];
11 | const clickSet = addClick(example);
12 | clickSet[0].onClick();
13 | // # END:scopeLet
14 |
15 | export { addClick };
16 |
--------------------------------------------------------------------------------
/variables/scope/scope.spec.js:
--------------------------------------------------------------------------------
1 | import expect from 'expect';
2 |
3 | import { addClick } from './problem';
4 | import { addClick as addClickCurry } from './curry';
5 | import { addClick as addClickLet } from './scope';
6 |
7 | describe('let scope', () => {
8 | it('should have a scope problem', () => {
9 | const items = [
10 | {},
11 | {},
12 | ];
13 | addClick(items);
14 | expect(items[0].onClick()).toEqual(2);
15 | expect(items[1].onClick()).toEqual(2);
16 | });
17 |
18 | it('should not have a problem', () => {
19 | const items = [
20 | {},
21 | {},
22 | ];
23 | addClickCurry(items);
24 | expect(items[0].onClick()).toEqual(0);
25 | expect(items[1].onClick()).toEqual(1);
26 | });
27 |
28 | it('should not have a problem', () => {
29 | const items = [
30 | {},
31 | {},
32 | ];
33 | addClickLet(items);
34 | expect(items[0].onClick()).toEqual(0);
35 | expect(items[1].onClick()).toEqual(1);
36 | });
37 | });
38 |
--------------------------------------------------------------------------------