├── .editorconfig ├── .github ├── ISSUE_TEMPLATE.md └── PULL_REQUEST_TEMPLATE.md ├── .gitignore ├── .travis.yml ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── build.js ├── index.d.ts ├── lib ├── array │ └── flatten-array.js ├── date │ ├── add-days.js │ ├── add-hours.js │ ├── add-milliseconds.js │ ├── add-minutes.js │ ├── add-months.js │ ├── add-seconds.js │ ├── add-weeks.js │ ├── add-years.js │ ├── diff-date.js │ ├── format-date.js │ ├── helpers.js │ ├── is-valid-date.js │ └── parse-date.js ├── element │ ├── add-class.js │ ├── clear-events.js │ ├── create-element.js │ ├── get-parents.js │ ├── has-class.js │ ├── helpers.js │ ├── hide-element.js │ ├── insert-element-after.js │ ├── insert-element-before.js │ ├── kill-element.js │ ├── remove-class.js │ ├── replace-element.js │ ├── show-element.js │ └── toggle-class.js ├── function │ ├── compose.js │ ├── curry.js │ ├── pipe.js │ └── throttle.js ├── index.js ├── number │ └── round.js ├── object │ ├── helpers.js │ ├── map-keys.js │ └── map-values.js ├── string │ ├── capitalize.js │ └── clean-up-string.js └── utils │ ├── error-message.js │ ├── helpers.js │ ├── type-of.js │ └── validate-arguments.js ├── logo.svg ├── package-lock.json ├── package.json └── test ├── array └── flatten-array.test.js ├── date ├── add-days.test.js ├── add-hours.test.js ├── add-milliseconds.test.js ├── add-minutes.test.js ├── add-months.test.js ├── add-seconds.test.js ├── add-weeks.test.js ├── add-years.test.js ├── diff-date.test.js ├── format-date.test.js ├── is-valid-date.test.js └── parse-date.test.js ├── element ├── add-class.test.js ├── clear-events.test.js ├── create-element.test.js ├── get-parents.test.js ├── has-class.test.js ├── hide-element.test.js ├── insert-element-after.test.js ├── insert-element-before.test.js ├── kill-element.test.js ├── remove-class.test.js ├── replace-element.test.js ├── show-element.test.js └── toggle-class.test.js ├── function ├── compose.test.js ├── curry.test.js ├── pipe.test.js └── throttle.test.js ├── number └── round.test.js ├── object ├── map-keys.test.js └── map-values.test.js ├── string ├── capitalize.test.js └── clean-up-string.test.js └── utils └── helpers.test.js /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 6 | 7 | Is this a bug report or feature request? 8 | 9 | ### Expected Behavior 10 | 11 | 12 | 13 | ### Current Behavior 14 | 15 | 16 | 17 | ### Possible Solution 18 | 19 | 20 | 21 | ### Context 22 | 23 | 24 | 25 | ### Your Environment 26 | 27 | 28 | | software | version(s) 29 | | ---------------- | ------- 30 | | vanilla-commons | 31 | | node | 32 | | npm | 33 | | Operating System | 34 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | 9 | **What kind of change does this PR introduce?** (check at least one) 10 | 11 | - [ ] Bugfix 12 | - [ ] Feature 13 | - [ ] Code style update 14 | - [ ] Refactor 15 | - [ ] Build-related changes 16 | - [ ] Other, please describe: 17 | 18 | **Does this PR introduce a breaking change?** (check one) 19 | 20 | - [ ] Yes 21 | - [ ] No 22 | 23 | 24 | **Other information:** 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # dist folder 2 | dist 3 | 4 | # Logs 5 | logs 6 | *.log 7 | npm-debug.log* 8 | yarn-debug.log* 9 | yarn-error.log* 10 | 11 | # Runtime data 12 | pids 13 | *.pid 14 | *.seed 15 | *.pid.lock 16 | 17 | # Directory for instrumented libs generated by jscoverage/JSCover 18 | lib-cov 19 | 20 | # Coverage directory used by tools like istanbul 21 | coverage 22 | 23 | # nyc test coverage 24 | .nyc_output 25 | 26 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 27 | .grunt 28 | 29 | # Bower dependency directory (https://bower.io/) 30 | bower_components 31 | 32 | # node-waf configuration 33 | .lock-wscript 34 | 35 | # Compiled binary addons (http://nodejs.org/api/addons.html) 36 | build/Release 37 | 38 | # Dependency directories 39 | node_modules/ 40 | jspm_packages/ 41 | 42 | # Typescript v1 declaration files 43 | typings/ 44 | 45 | # Optional npm cache directory 46 | .npm 47 | 48 | # Optional eslint cache 49 | .eslintcache 50 | 51 | # Optional REPL history 52 | .node_repl_history 53 | 54 | # Output of 'npm pack' 55 | *.tgz 56 | 57 | # Yarn Integrity file 58 | .yarn-integrity 59 | 60 | # dotenv environment variables file 61 | .env 62 | 63 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - '8' 4 | 5 | jobs: 6 | include: 7 | - stage: Build and test 8 | name: Test 9 | script: npm test 10 | - script: npm run build 11 | name: Build 12 | - stage: deploy 13 | if: branch = master 14 | name: Release to npm 15 | script: npm run semantic-release 16 | - script: npm run coveralls 17 | name: Coveralls 18 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, gender identity and expression, level of experience, 9 | nationality, personal appearance, race, religion, or sexual identity and 10 | orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at thia.mdossantos@gmail.com. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at [http://contributor-covenant.org/version/1/4][version] 72 | 73 | [homepage]: http://contributor-covenant.org 74 | [version]: http://contributor-covenant.org/version/1/4/ 75 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to vanilla-commons 2 | First off, thanks for taking the time to contribute! 3 | 4 | Now, take a moment to be sure your contributions make sense to everyone else. 5 | These are just guidelines, not rules. 6 | Use your best judgment, and feel free to propose changes to this document in a pull request. 7 | 8 | ## Code of Conduct 9 | This project is released with a [Contributor Code of Conduct](CODE_OF_CONDUCT.md). By participating in this project you agree to abide by its terms. 10 | 11 | ## Reporting Issues 12 | Found a problem? Want a new feature? First of all see if your issue or idea has [already been reported](https://github.com/gugutz/vanilla-commons/issues). 13 | If don't, just open a [new clear and descriptive issue](https://github.com/gugutz/vanilla-commons/issues/new). 14 | 15 | ## Submitting pull requests 16 | Pull requests are the greatest contributions, so be sure they are focused in scope, and do avoid unrelated commits. 17 | 18 | - Fork it! 19 | - Clone your fork: `git clone https://github.com//vanilla-commons` 20 | - Navigate to the newly cloned directory: `cd vanilla-commons` 21 | - Create a new branch for the new feature: `git checkout -b my-new-feature` 22 | - Install the tools necessary for development: `npm install` 23 | - Make your changes. 24 | - Commit your changes: `git commit -am 'Add some feature'` 25 | - Push to the branch: `git push origin my-new-feature` 26 | - Submit a pull request with full remarks documenting your changes. 27 | 28 | ## Testing 29 | Every time you write a test, remember to answer all the questions: 30 | 31 | 1. What are you testing? 32 | 2. What should it do? 33 | 3. What is the actual output? 34 | 4. What is the expected output? 35 | 5. How can the test be reproduced? 36 | 37 | ## Code Style 38 | Follow the [xo](https://github.com/sindresorhus/xo) style. 39 | Using two spaces for identation and no [semicolons](http://blog.izs.me/post/2353458699/an-open-letter-to-javascript-leaders-regarding). 40 | 41 | ## Commit Message Emoji 42 | 43 | Every commit is important. 44 | So let's celebrate each and every commit with a corresponding emoji! :smile: 45 | 46 | ### Which Emoji to Use? :confused: 47 | 48 | Commit Type | Emoji 49 | ---------- | ------------- 50 | Initial Commit | :tada: `:tada:` 51 | Improve the format/structure of the code | :art: `:art:` 52 | Improving performance | :racehorse: `:racehorse:` 53 | Writing docs | :memo: `:memo:` 54 | Fix a bug | :bug: `:bug:` 55 | Remove code or files | :fire: `:fire:` 56 | Fix CI build | :green_heart: `:green_heart:` 57 | Deal with security | :lock: `:lock:` 58 | Upgrade dependencies | :arrow_up: `:arrow_up:` 59 | Downgrading dependencies | :arrow_down: `:arrow_down:` 60 | Add tests | :umbrella: `:umbrella:` 61 | Improving accessibility | :wheelchair: `:wheelchair:` 62 | Add new features | :sparkles: `:sparkles:` 63 | Refactoring | :package: `:package:` 64 | Other | [Be creative](http://www.emoji-cheat-sheet.com/) 65 | 66 | ## Scripts 67 | The follow scripts are available when you develop. 68 | 69 | - `npm run lint` - Lint the files. 70 | - `npm test` - Run the tests. 71 | - `npm run test:watch` - Run the tests on the watch mode. 72 | - `npm run coverage` - See the code coverage of the tests. 73 | - `npm run build` - Build the package. 74 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Gustavo P Borges 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | vanilla-commons 3 |

4 | 5 |

Lightweight common vanilla utilities for the modern web development

6 | 7 |

npm Travis Coveralls David gzip size

8 | 9 | ## Table of Contents 10 | 11 | - [Install](#install) 12 | - [Usage](#usage) 13 | - [Array Commons](#array-commons) 14 | - [Date Commons](#date-commons) 15 | - [Element Commons](#element-commons) 16 | - [Function Commons](#function-commons) 17 | - [Number Commons](#number-commons) 18 | - [Object Commons](#object-commons) 19 | - [String Commons](#string-commons) 20 | - [Prior Art](#prior-art) 21 | - [Contributing](#contributing) 22 | - [License](#license) 23 | 24 | ## Install 25 | 26 | This project uses [node](http://nodejs.org) and [npm](https://npmjs.com). 27 | Go check them out if you don't have them locally installed. 28 | 29 | ```sh 30 | $ npm install --save vanilla-commons 31 | ``` 32 | 33 | The [UMD](https://github.com/umdjs/umd) build is also available on [jsdelivr](https://www.jsdelivr.com/): 34 | 35 | ```html 36 | 37 | ``` 38 | 39 | You can find the library on `window.commons`. 40 | 41 | ## Usage 42 | 43 | ```js 44 | import { 45 | addMinutes, 46 | addHours, 47 | addDays, 48 | addMonths, 49 | addYears, 50 | formatDate, 51 | pipe 52 | } from 'vanilla-commons' 53 | 54 | const date = new Date('December 17, 1995 03:24:00') 55 | const format = '{DD}/{MM}/{YYYY} {HH}:{mm}:{ss}:{ms}' 56 | 57 | const finalDate = pipe( 58 | addMinutes(1), 59 | addHours(9), 60 | addDays(7), 61 | addMonths(-9), 62 | addYears(-2), 63 | formatDate(format) 64 | )(date) 65 | // '24/03/1993 12:25:00:00' 66 | ``` 67 | 68 | ## Array Commons 69 | 70 | ### flattenArray(arr) 71 | 72 | Flatten nested arrays. 73 | 74 | **Parameters** 75 | 76 | - `arr` **[Array][Array]** Nested array. 77 | 78 | **Returns** 79 | 80 | **[Array][Array]** flattened. 81 | 82 | **Examples** 83 | 84 | ```javascript 85 | import {flattenArray} from 'vanilla-commons' 86 | 87 | flattenArray([[1], [2, [3, 4]]]) 88 | // [1, 2, 3, 4] 89 | ``` 90 | 91 | ## Date Commons 92 | 93 | ### addDays(days, date) 94 | 95 | Add days to a Date. 96 | 97 | **Parameters** 98 | 99 | - `days` **[Number][Number]** of days to add. 100 | - `date` **[Date][Date]** to be modified. 101 | 102 | **Returns** 103 | 104 | **[Date][Date]** with the days added. 105 | 106 | **Examples** 107 | 108 | ```javascript 109 | import {addDays} from 'vanilla-commons' 110 | 111 | addDays(6, new Date('December 17, 1995 03:24:00')) 112 | // Sat, 23 Dec 1995 03:24:00 113 | 114 | addDays(-6, new Date('December 17, 1995 03:24:00')) 115 | // Mon, 11 Dec 1995 03:24:00 116 | 117 | addDays(6)(new Date('December 17, 1995 03:24:00')) 118 | // Sat, 23 Dec 1995 03:24:00 119 | ``` 120 | 121 | ### addHours(hours, date) 122 | 123 | Add hours to a Date. 124 | 125 | **Parameters** 126 | 127 | - `hours` **[Number][Number]** of hours to add. 128 | - `date` **[Date][Date]** to be modified. 129 | 130 | **Returns** 131 | 132 | **[Date][Date]** with the hours added. 133 | 134 | **Examples** 135 | 136 | ```javascript 137 | import {addHours} from 'vanilla-commons' 138 | 139 | addHours(6, new Date('December 17, 1995 03:24:00')) 140 | // Sun, 17 Dec 1995 09:24:00 141 | 142 | addHours(-6, new Date('December 17, 1995 03:24:00')) 143 | // Fri, 16 Dec 1995 21:24:00 144 | 145 | addHours(6)(new Date('December 17, 1995 03:24:00')) 146 | // Sun, 17 Dec 1995 09:24:00 147 | ``` 148 | 149 | ### addMilliseconds(milliseconds, date) 150 | 151 | Add milliseconds to a Date. 152 | 153 | **Parameters** 154 | 155 | - `milliseconds` **[Number][Number]** Number of milliseconds to add. 156 | - `date` **[Date][Date]** Date to be modified. 157 | 158 | **Returns** 159 | 160 | **[Date][Date]** with the milliseconds added. 161 | 162 | **Examples** 163 | 164 | ```javascript 165 | import {addMilliseconds} from 'vanilla-commons' 166 | 167 | addMilliseconds(1000, new Date('December 17, 1995 03:24:00')) 168 | // Sun, 17 Dec 1995 09:24:01 169 | 170 | addMilliseconds(-1000, new Date('December 17, 1995 03:24:00')) 171 | // Sun, 17 Dec 1995 09:23:59 172 | 173 | addMilliseconds(1000)(new Date('December 17, 1995 03:24:00')) 174 | // Sun, 17 Dec 1995 09:24:01 175 | ``` 176 | 177 | ### addMinutes(minutes, date) 178 | 179 | Add minutes to a Date. 180 | 181 | **Parameters** 182 | 183 | - `minutes` **[Number][Number]** of minutes to add. 184 | - `date` **[Date][Date]** to be modified. 185 | 186 | **Returns** 187 | 188 | **[Date][Date]** with the minutes added. 189 | 190 | **Examples** 191 | 192 | ```javascript 193 | import {addMinutes} from 'vanilla-commons' 194 | 195 | addMinutes(6, new Date('December 17, 1995 03:24:00')) 196 | // Sun, 17 Dec 1995 09:24:06 197 | 198 | addMinutes(-6, new Date('December 17, 1995 03:24:00')) 199 | // Sun, 17 Dec 1995 09:23:54 200 | 201 | addMinutes(6)(new Date('December 17, 1995 03:24:00')) 202 | // Sun, 17 Dec 1995 09:24:06 203 | ``` 204 | 205 | ### addMonths(months, date) 206 | 207 | Add months to a Date. 208 | 209 | **Parameters** 210 | 211 | - `months` **[Number][Number]** of months to add. 212 | - `date` **[Date][Date]** to be modified. 213 | 214 | **Returns** 215 | 216 | **[Date][Date]** with the months added. 217 | 218 | **Examples** 219 | 220 | ```javascript 221 | import {addMonths} from 'vanilla-commons' 222 | 223 | addMonths(6, new Date('December 17, 1995 03:24:00')) 224 | // Mon, 17 Jun 1996 09:24:00 225 | 226 | addMonths(-6, new Date('December 17, 1995 03:24:00')) 227 | // Sat, 17 Jun 1995 09:24:00 228 | 229 | addMonths(6)(new Date('December 17, 1995 03:24:00')) 230 | // Mon, 17 Jun 1996 09:24:00 231 | ``` 232 | 233 | ### addSeconds(seconds, date) 234 | 235 | Add seconds to a Date. 236 | 237 | **Parameters** 238 | 239 | - `seconds` **[Number][Number]** of seconds to add. 240 | - `date` **[Date][Date]** to be modified. 241 | 242 | **Returns** 243 | 244 | **[Date][Date]** with the seconds added. 245 | 246 | **Examples** 247 | 248 | ```javascript 249 | import {addSeconds} from 'vanilla-commons' 250 | 251 | addSeconds(6, new Date('December 17, 1995 03:24:00')) 252 | // Sun, 17 Dec 1995 09:30:00 253 | 254 | addSeconds(-6, new Date('December 17, 1995 03:24:00')) 255 | // Sun, 17 Dec 1995 09:18:00 256 | 257 | addSeconds(6)(new Date('December 17, 1995 03:24:00')) 258 | // Sun, 17 Dec 1995 09:30:00 259 | ``` 260 | 261 | ### addWeeks(weeks, date) 262 | 263 | Add weeks to a Date. 264 | 265 | **Parameters** 266 | 267 | - `weeks` **[Number][Number]** of weeks to add. 268 | - `date` **[Date][Date]** to be modified. 269 | 270 | **Returns** 271 | 272 | **[Date][Date]** with the weeks added. 273 | 274 | **Examples** 275 | 276 | ```javascript 277 | import {addWeeks} from 'vanilla-commons' 278 | 279 | addWeeks(1, new Date('December 17, 1995 03:24:00')) 280 | // Sun, 24 Dec 1995 09:24:00 281 | 282 | addWeeks(-1, new Date('December 17, 1995 03:24:00')) 283 | // Sun, 10 Dec 1995 09:24:00 284 | 285 | addWeeks(6)(new Date('December 17, 1995 03:24:00')) 286 | // Sun, 24 Dec 1995 09:24:00 287 | ``` 288 | 289 | ### addYears(years, date) 290 | 291 | Add years to a Date. 292 | 293 | **Parameters** 294 | 295 | - `years` **[Number][Number]** of years to add. 296 | - `date` **[Date][Date]** to be modified. 297 | 298 | **Returns** 299 | 300 | **[Date][Date]** with the years added. 301 | 302 | **Examples** 303 | 304 | ```javascript 305 | import {addYears} from 'vanilla-commons' 306 | 307 | addYears(1, new Date('December 17, 1995 03:24:00')) 308 | // Tue, 17 Dec 1996 09:24:00 309 | 310 | addYears(-1, new Date('December 17, 1995 03:24:00')) 311 | // Sat, 17 Dec 1994 09:24:00 312 | 313 | addYears(1)(new Date('December 17, 1995 03:24:00')) 314 | // Tue, 17 Dec 1996 09:24:00 315 | ``` 316 | 317 | ### diffDate(firstDate, secondDate) 318 | 319 | Calculate the diff of two Date objects. 320 | 321 | **Parameters** 322 | 323 | - `firstDate` **[Date][Date]** to be compared. 324 | - `secondDate` **[Date][Date]** to be compared. 325 | 326 | **Returns** 327 | 328 | **[Date][Date]** with the years added. 329 | 330 | **Examples** 331 | 332 | ```javascript 333 | import {diffDate} from 'vanilla-commons' 334 | 335 | diffDate( 336 | new Date('December 17, 1995 03:24:00'), 337 | new Date('December 17, 1996 03:25:00') 338 | ) 339 | // { 340 | // milliseconds: 31622460000, 341 | // seconds: 31622460, 342 | // minutes: 527041, 343 | // hours: 8784.02, 344 | // days: 366, 345 | // weeks: 52.29, 346 | // months: 12.2, 347 | // years: 1 348 | // } 349 | ``` 350 | 351 | ### formatDate(format, date) 352 | 353 | Format a date given a expected format. 354 | Use the following patterns inside your format: 355 | 356 | - `{YYYY}`: full year; **2017** 357 | - `{YY}`: short year; **17** 358 | - `{MM}`: month; **04** 359 | - `{DD}`: day; **01** 360 | - `{HH}`: hours; **06** (24h) 361 | - `{mm}`: minutes; **59** 362 | - `{ss}`: seconds; **09** 363 | - `{ms}`: milliseconds; **10** 364 | 365 | **Parameters** 366 | 367 | - `format` **[string][string]** expected format of the date. 368 | - `date` **[Date][Date]** to be compared. 369 | 370 | **Returns** 371 | 372 | **[string][string]** formatted date. 373 | 374 | **Examples** 375 | 376 | ```javascript 377 | import {formatDate} from 'vanilla-commons' 378 | 379 | formatDate( 380 | '{DD}/{MM}/{YYYY} {HH}:{mm}:{ss}:{ms}', 381 | new Date('December 17, 1995 03:24:00') 382 | ) 383 | // '17/12/1995 03:24:00:00' 384 | ``` 385 | 386 | ### isValidDate(format, dateStr) 387 | 388 | Checks the validity of a given date string. 389 | Use the following patterns inside your format: 390 | 391 | - `{YYYY}`: full year; **2017** 392 | - `{YY}`: short year; **17** 393 | - `{MM}`: month; **04** 394 | - `{DD}`: day; **01** 395 | - `{HH}`: hours; **06** (24h) 396 | - `{mm}`: minutes; **59** 397 | - `{ss}`: seconds; **09** 398 | - `{ms}`: milliseconds; **10** 399 | 400 | **Parameters** 401 | 402 | - `format` **[string][string]** expected format of the date. 403 | - `dateStr` **[string][string]** date string to be tested. 404 | 405 | **Returns** 406 | 407 | **[Boolean][Boolean]** true if the date is valid. 408 | 409 | **Examples** 410 | 411 | ```javascript 412 | import {isValidDate} from 'vanilla-commons' 413 | 414 | isValidDate('{DD}/{MM}/{YYYY} {HH}:{mm}:{ss}:{ms}', '17/12/1995 03:24:00:00') 415 | // true 416 | 417 | isValidDate('{DD}/{MM}/{YYYY} {HH}:{mm}:{ss}:{ms}', '29/02/1995 03:24:00:00') 418 | // false 419 | ``` 420 | 421 | ### parseDate(format, dateStr) 422 | 423 | Parse a date string to a date object given a format. 424 | Use the following patterns inside your format: 425 | 426 | - `{YYYY}`: full year; **2017** 427 | - `{YY}`: short year; **17** 428 | - `{MM}`: month; **04** 429 | - `{DD}`: day; **01** 430 | - `{HH}`: hours; **06** (24h) 431 | - `{mm}`: minutes; **59** 432 | - `{ss}`: seconds; **09** 433 | - `{ms}`: milliseconds; **10** 434 | 435 | **Parameters** 436 | 437 | - `format` **[string][string]** the format of the date string. 438 | - `dateStr` **[string][string]** date string to be parsed. 439 | 440 | **Returns** 441 | 442 | **[Date][Date]** parsed date. 443 | 444 | **Examples** 445 | 446 | ```javascript 447 | import {parseDate} from 'vanilla-commons' 448 | 449 | parseDate('{DD}/{MM}/{YYYY} {HH}:{mm}:{ss}:{ms}', '17/12/1995 03:24:00:00') 450 | // Sun, 17 Dec 1995 03:24:00 451 | ``` 452 | ## Element Commons 453 | 454 | ### addClass(newClass, element) 455 | 456 | Add a class to a DOM Element. 457 | 458 | **Parameters** 459 | 460 | - `newClass` **([Array][Array] \| [string][string])** Array or string of class to add to a DOM Element. 461 | - `element` **[Element][Element]** Element to apply the changes. 462 | 463 | **Returns** 464 | 465 | **[Element][Element]** in which the changes were made. 466 | 467 | **Examples** 468 | 469 | ```javascript 470 | import {addClass} from 'vanilla-commons' 471 | 472 | const element = document.querySelector('.element') 473 | addClass('hey')(element) 474 | //
475 | 476 | addClass(['there', 'man'], element) 477 | //
478 | ``` 479 | 480 | ### clearEvents(element) 481 | 482 | Remove all the event listeners of a element and its children. 483 | 484 | **Parameters** 485 | 486 | - `element` **[Element][Element]** Element that will have its events removed. 487 | 488 | **Returns** 489 | 490 | **[Element][Element]** element that the events were removed. 491 | 492 | **Examples** 493 | 494 | ```javascript 495 | // See the tests for better examples https://github.com/gugutz/vanilla-commons/blob/master/test/element/clear-events.test.js 496 | import {clearEvents} from 'vanilla-commons' 497 | 498 | const element = document.querySelector('.element') 499 | clearEvents(element) 500 | ``` 501 | 502 | ### createElement(selector?, props?, children?) 503 | 504 | Create a DOM element. 505 | 506 | **Parameters** 507 | 508 | - `selector` **[string][string]** CSS selector like. 509 | - `props` **[Object][Object]** Properties of the node. 510 | - `children` (**[string][string]**|**[Element][Element]**|**[Array][Array]**) Children of the element. 511 | 512 | **Returns** 513 | 514 | **[Element][Element]** created. 515 | 516 | **Examples** 517 | 518 | ```javascript 519 | // See the tests for better examples https://github.com/gugutz/vanilla-commons/blob/master/test/element/create-element.test.js 520 | import {createElement} from 'vanilla-commons' 521 | 522 | createElement() 523 | //
524 | 525 | createElement('input#id.class[type=text][required]') 526 | // 527 | 528 | createElement('div', { 529 | data: { 530 | ref: 'hey', 531 | error: 'bad' 532 | } 533 | }) 534 | //
535 | 536 | createElement('p', { 537 | className: 'hey there man' 538 | }) 539 | //

540 | 541 | createElement('p', { 542 | onclick: function() { 543 | console.log('clicked') 544 | } 545 | }) 546 | // It's easy to work with events! 547 | 548 | createElement('div', [ 549 | createElement('input[type=text]'), 550 | 'hey', 551 | createElement('img[src=coolimage.jpg]') 552 | ]) 553 | //
554 | // 555 | // hey 556 | // 557 | //
558 | ``` 559 | 560 | ### getParents(element) 561 | 562 | Get all the parents of a given element. 563 | 564 | **Parameters** 565 | 566 | - `element` **[Element][Element]** Reference element. 567 | 568 | **Returns** 569 | 570 | **[Array][Array]** the parents of the element, including the body. 571 | 572 | **Examples** 573 | 574 | ```javascript 575 | // See the tests for better examples https://github.com/gugutz/vanilla-commons/blob/master/test/element/get-parents.test.js 576 | import {getParents} from 'vanilla-commons' 577 | 578 | const element = document.querySelector('.element') 579 | getParents(element) 580 | ``` 581 | 582 | ### hasClass(classToCheck, element) 583 | 584 | Check if a DOM Element has the specified class. 585 | 586 | **Parameters** 587 | 588 | - `classToCheck` **([Array][Array] \| [string][string])** Array or string of class to check the existence in a DOM Element. 589 | - `element` **[Element][Element]** Element to apply the changes. 590 | 591 | **Returns** 592 | 593 | **[Element][Element]** to check if has the specified class. 594 | 595 | **Examples** 596 | 597 | ```javascript 598 | import {hasClass} from 'vanilla-commons' 599 | 600 | const element = document.createElement('div') 601 | element.className = 'hey there' 602 | 603 | hasClass('hey')(element) 604 | // true 605 | 606 | hasClass('hey', element) 607 | // true 608 | 609 | hasClass('man', element) 610 | // false 611 | 612 | hasClass(['hey', 'there'], element) 613 | // true 614 | 615 | hasClass(['hey', 'man'], element) 616 | // false 617 | ``` 618 | 619 | ### hideElement(elementToHide) 620 | 621 | Hide a Element from the DOM. 622 | 623 | **Parameters** 624 | 625 | - `elementToHide` **([Array][Array] \| [Element][Element])** Array of elements or element to hide. 626 | 627 | **Returns** 628 | 629 | **([Array][Array] \| [Element][Element])** element or array of elements that were hidden. 630 | 631 | **Examples** 632 | 633 | ```javascript 634 | import {hideElement} from 'vanilla-commons' 635 | 636 | const element = document.createElement('div') 637 | element.style.display 638 | // block 639 | 640 | hideElement(element) 641 | element.style.display 642 | // none 643 | ``` 644 | ```javascript 645 | import {hideElement} from 'vanilla-commons' 646 | 647 | const element1 = document.createElement('div') 648 | element1.style.display 649 | // block 650 | 651 | const element2 = document.createElement('div') 652 | element2.style.display 653 | // block 654 | 655 | hideElement([element1, element2]) 656 | 657 | element1.style.display 658 | // none 659 | 660 | element2.style.display 661 | // none 662 | ``` 663 | 664 | ### insertElementAfter(referenceElement, newElement) 665 | 666 | Insert a element after a reference element. 667 | 668 | **Parameters** 669 | 670 | - `referenceElement` **[Element][Element]** Reference element. 671 | - `newElement` **[Element][Element]** Element to be inserted. 672 | 673 | **Returns** 674 | 675 | **[Element][Element]** that were inserted. 676 | 677 | **Examples** 678 | 679 | ```javascript 680 | import {insertElementAfter} from 'vanilla-commons' 681 | 682 | insertElementAfter(referenceElement, newElement) 683 | ``` 684 | 685 | ### insertElementBefore(referenceElement, newElement) 686 | 687 | Insert a element before a reference element. 688 | 689 | **Parameters** 690 | 691 | - `referenceElement` **[Element][Element]** Reference element. 692 | - `newElement` **[Element][Element]** Element to be inserted. 693 | 694 | **Returns** 695 | 696 | **[Element][Element]** that were inserted. 697 | 698 | **Examples** 699 | 700 | ```javascript 701 | import {insertElementBefore} from 'vanilla-commons' 702 | 703 | insertElementBefore(referenceElement, newElement) 704 | ``` 705 | 706 | ### killElement(elementToKill) 707 | 708 | Kill a Element from the DOM. 709 | 710 | **Parameters** 711 | 712 | - `elementToKill` **([Array][Array] \| [Element][Element])** Array of elements or element to kill. 713 | 714 | **Examples** 715 | 716 | ```javascript 717 | import {killElement} from 'vanilla-commons' 718 | 719 | killElement(element) 720 | 721 | killElement([element1, element2]) 722 | ``` 723 | 724 | ### removeClass(classToRemove, element) 725 | 726 | Remove a class of a DOM Element. 727 | 728 | **Parameters** 729 | 730 | - `classToRemove` **([Array][Array] \| [string][string])** Array or string of class to remove of a DOM Element. 731 | - `element` **[Element][Element]** Element to apply the changes. 732 | 733 | **Returns** 734 | 735 | **[Element][Element]** that the had the class removed. 736 | 737 | **Examples** 738 | 739 | ```javascript 740 | import {removeClass} from 'vanilla-commons' 741 | 742 | removeClass('hey')(element) 743 | 744 | removeClass('hey', element) 745 | 746 | removeClass(['hey', 'there'], element) 747 | ``` 748 | 749 | ### replaceElement(originalElement, newElement) 750 | 751 | Replace a DOM element with another element. 752 | 753 | **Parameters** 754 | 755 | - `originalElement` **[Element][Element]** Element to be replaced. 756 | - `newElement` **[Element][Element]** New element to replace the old one. 757 | 758 | **Returns** 759 | 760 | **[Element][Element]** element that replaced the old one. 761 | 762 | **Examples** 763 | 764 | ```javascript 765 | import {replaceElement} from 'vanilla-commons' 766 | 767 | replaceElement(originalElement, newElement) 768 | ``` 769 | 770 | ### showElement(elementToShow) 771 | 772 | Show a hidden Element from the DOM. 773 | 774 | **Parameters** 775 | 776 | - `elementToShow` **([Array][Array] \| [Element][Element])** Array of elements or element to hide. 777 | 778 | **Returns** 779 | 780 | **([Array][Array] \| [Element][Element])** element or array of elements that were showed. 781 | 782 | **Examples** 783 | 784 | ```javascript 785 | import {showElement} from 'vanilla-commons' 786 | 787 | showElement(element) 788 | 789 | showElement([element1, element2]) 790 | ``` 791 | 792 | ### toggleClass(classToToggle, element) 793 | 794 | Toggle a class from a DOM Element. 795 | 796 | **Parameters** 797 | 798 | - `classToToggle` **([Array][Array] \| [string][string])** Array or string of class to toggle a DOM Element. 799 | - `element` **[Element][Element]** to apply the changes. 800 | 801 | **Returns** 802 | 803 | **[Element][Element]** that the changes were made. 804 | 805 | **Examples** 806 | 807 | ```javascript 808 | import {toggleClass} from 'vanilla-commons' 809 | 810 | toggleClass('hey')(element) 811 | 812 | toggleClass('hey', element) 813 | 814 | toggleClass(['hey', 'there'], element) 815 | ``` 816 | 817 | ## Function Commons 818 | 819 | ### compose(fn[, fn1, ..., fnN]) 820 | 821 | Performs right-to-left function composition. 822 | 823 | **Parameters** 824 | 825 | - `fn`...`fnN` **[Function][Function]** functions to be composed. 826 | 827 | **Returns** 828 | 829 | - **[Function][Function]** composed function. 830 | 831 | **Examples** 832 | 833 | ```javascript 834 | import {curry, compose} from 'vanilla-commons' 835 | 836 | const add = curry((a, b) => a + b) 837 | 838 | const multiply = curry((a, b) => a * b) 839 | 840 | const composedFunction = compose(add(5), multiply(4), add(3)) 841 | composedFunction(2) 842 | // (((2 + 3) * 4) + 5) = 25 843 | ``` 844 | 845 | ### curry(fn) 846 | 847 | Returns a curried equivalent of the provided function 848 | 849 | **Parameters** 850 | 851 | - `fn` **[Function][Function]** function to be curried. 852 | 853 | **Returns** 854 | 855 | - **[Function][Function]** curried function. 856 | 857 | **Examples** 858 | 859 | ```javascript 860 | import {curry} from 'vanilla-commons' 861 | 862 | const addFourNumbers = (a, b, c, d) => a + b + c + d 863 | 864 | const curriedAddFourNumbers = curry(addFourNumbers) 865 | curriedAddFourNumbers(1, 2)(3)(4) 866 | // 10 867 | 868 | curriedAddFourNumbers(1, 2)(3, 4) 869 | // 10 870 | 871 | curriedAddFourNumbers(1)(2)(3)(4) 872 | // 10 873 | 874 | curriedAddFourNumbers(1, 2, 3)(4) 875 | // 10 876 | ``` 877 | 878 | ### pipe(fn[, fn1, ..., fnN]) 879 | 880 | Performs left-to-right function composition. 881 | 882 | **Parameters** 883 | 884 | - `fn`...`fnN` **[Function][Function]** functions to be piped. 885 | 886 | **Returns** 887 | 888 | - **[Function][Function]** piped function. 889 | 890 | **Examples** 891 | 892 | ```javascript 893 | import {curry, pipe} from 'vanilla-commons' 894 | 895 | const add = curry((a, b) => a + b) 896 | 897 | const multiply = curry((a, b) => a * b) 898 | 899 | const pipedFunction = pipe(add(5), multiply(4), add(3)) 900 | pipedFunction(2) 901 | // (((2 + 5) * 4) + 3) = 31 902 | ``` 903 | 904 | ### throttle(limit, fn) 905 | 906 | Creates a function that will call fn at most once every wait milliseconds. 907 | 908 | **Parameters** 909 | 910 | - `limit` **[Number][Number]** time in milliseconds to wait. 911 | - `fn` **[Function][Function]** function to be executed. 912 | 913 | **Returns** 914 | 915 | - **[Function][Function]** throttled function. 916 | 917 | **Examples** 918 | 919 | ```javascript 920 | import {throttle} from 'vanilla-commons' 921 | 922 | window.addEventListener('scroll', throttle(100, e => { 923 | console.log(e) 924 | })) 925 | ``` 926 | 927 | ## Number Commons 928 | 929 | ### round(num) 930 | 931 | Round a number to two decimal places. 932 | 933 | **Parameters** 934 | 935 | - `num` **[Number][Number]** number to be rounded. 936 | 937 | **Returns** 938 | 939 | **[Number][Number]** rounded number. 940 | 941 | **Examples** 942 | 943 | ```javascript 944 | import {round} from 'vanilla-commons' 945 | 946 | round(3.141592) 947 | // 3.14 948 | 949 | round(-27.817987) 950 | // -27.82 951 | ``` 952 | 953 | ## Object Commons 954 | 955 | ### mapKeys(fn, obj) 956 | 957 | Map over the keys of a object. 958 | 959 | **Parameters** 960 | 961 | - `fn` **[Function][Function]** function that will be invoked per iteration. 962 | - `obj` **[Object][Object]** object to be mapped. 963 | 964 | **Returns** 965 | 966 | **[Object][Object]** mapped object. 967 | 968 | **Examples** 969 | 970 | ```javascript 971 | import {mapKeys} from 'vanilla-commons' 972 | 973 | mapKeys(function(key) { 974 | return key + 'hey' 975 | }, { 976 | captain: 'picard', 977 | firstOfficer: 'riker' 978 | }) 979 | // { 980 | // captainhey: 'picard', 981 | // firstOfficerhey: 'riker' 982 | // } 983 | ``` 984 | 985 | ### mapValues(fn, obj) 986 | 987 | Map over the values of a object. 988 | 989 | **Parameters** 990 | 991 | - `fn` **[Function][Function]** function that will be invoked per iteration. 992 | - `obj` **[Object][Object]** object to be mapped. 993 | 994 | **Returns** 995 | 996 | **[Object][Object]** mapped object. 997 | 998 | **Examples** 999 | 1000 | ```javascript 1001 | import {mapValues} from 'vanilla-commons' 1002 | 1003 | mapValues(function(value) { 1004 | return value + 'hey' 1005 | }, { 1006 | captain: 'picard', 1007 | firstOfficer: 'riker' 1008 | }) 1009 | // { 1010 | // captain: 'picardhey', 1011 | // firstOfficer: 'rikerhey' 1012 | // } 1013 | ``` 1014 | 1015 | ## String Commons 1016 | 1017 | ### capitalize(str) 1018 | 1019 | Converts the first character of string to upper case. 1020 | 1021 | **Parameters** 1022 | 1023 | - `str` **[string][string]** string to be capitalized. 1024 | 1025 | **Returns** 1026 | 1027 | **[string][string]** capitalized string. 1028 | 1029 | **Examples** 1030 | 1031 | ```javascript 1032 | import {capitalize} from 'vanilla-commons' 1033 | 1034 | capitalize('vanilla') 1035 | // Vanilla 1036 | ``` 1037 | 1038 | ### cleanUpString(str) 1039 | 1040 | Removes the all line breaks in the entire string and also the white spaces from the both ends of the string. 1041 | 1042 | **Parameters** 1043 | 1044 | - `str` **[string][string]** string to be cleaned. 1045 | 1046 | **Returns** 1047 | 1048 | **[string][string]** clean string. 1049 | 1050 | **Examples** 1051 | 1052 | ```javascript 1053 | import {cleanUpString} from 'vanilla-commons' 1054 | 1055 | cleanUpString('\n \n\r \r\n') 1056 | // '' 1057 | 1058 | cleanUpString('\n \n\r hjhj ') 1059 | // 'hjhj' 1060 | ``` 1061 | 1062 | ## Prior Art 1063 | 1064 | Vanilla Commons is fully inspired by these projects: 1065 | 1066 | - [Lodash](https://lodash.com/) 1067 | - [Underscore.js](http://underscorejs.org/) 1068 | - [Pareto.js](https://github.com/concretesolutions/pareto.js) 1069 | - [Ramda](http://ramdajs.com/) 1070 | - [tinydate](https://github.com/lukeed/tinydate) 1071 | - [date-fns](https://date-fns.org/) 1072 | - [Moment.js](https://momentjs.com/) 1073 | - [jQuery](http://jquery.com/) 1074 | - [dom-create-element-query-selector](https://github.com/hekigan/dom-create-element-query-selector) 1075 | - [hyperscript](https://github.com/hyperhype/hyperscript) 1076 | 1077 | ## Contributing 1078 | 1079 | See the [contributing file](CONTRIBUTING.md). 1080 | 1081 | ## License 1082 | 1083 | [MIT License](LICENSE.md) © [Gustavo P Borges](https://github.com/gugutz) 1084 | 1085 | [Array]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array 1086 | [Boolean]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean 1087 | [Date]: https://developer.mozilla.org/en-US/docs/Web/API/Date 1088 | [Element]: https://developer.mozilla.org/en-US/docs/Web/API/Element 1089 | [Number]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number 1090 | [string]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String 1091 | [Function]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function 1092 | [Object]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object 1093 | -------------------------------------------------------------------------------- /build.js: -------------------------------------------------------------------------------- 1 | const {promisify} = require('util') 2 | const fs = require('fs') 3 | const {rollup} = require('rollup') 4 | const babel = require('rollup-plugin-babel') 5 | const commonjs = require('rollup-plugin-commonjs') 6 | const nodeResolve = require('rollup-plugin-node-resolve') 7 | const filesize = require('rollup-plugin-filesize') 8 | const uglify = require('rollup-plugin-uglify') 9 | 10 | const readFile = promisify(fs.readFile) 11 | 12 | const targets = { 13 | cjs: 'dist/vanilla-commons.js', 14 | es: 'dist/vanilla-commons.es.js', 15 | umd: 'dist/vanilla-commons.umd.js', 16 | min: 'dist/vanilla-commons.umd.min.js' 17 | } 18 | 19 | async function getDependencies() { 20 | const pkg = JSON.parse(await readFile('./package.json')) 21 | return Object.keys(pkg.dependencies || {}) 22 | } 23 | 24 | async function generateBundle(format) { 25 | const defaultPlugins = [ 26 | nodeResolve(), 27 | commonjs({ 28 | include: 'node_modules/**' 29 | }), 30 | babel({ 31 | babelrc: false, 32 | presets: [ 33 | [ 34 | 'env', 35 | { 36 | modules: false 37 | } 38 | ], 39 | 'stage-0' 40 | ], 41 | plugins: ['external-helpers'] 42 | }), 43 | filesize() 44 | ] 45 | 46 | const plugins = 47 | format === 'min' ? defaultPlugins.concat(uglify()) : defaultPlugins 48 | 49 | const basicConfig = { 50 | entry: 'lib/index.js', 51 | plugins 52 | } 53 | 54 | const customConfig = ['cjs', 'es'].includes(format) ? 55 | {external: await getDependencies()} : 56 | {} 57 | 58 | return rollup(Object.assign(basicConfig, customConfig)) 59 | } 60 | 61 | function writeBundle(bundle, format) { 62 | return bundle.write({ 63 | dest: targets[format], 64 | format: format === 'min' ? 'umd' : format, 65 | moduleName: 'commons' 66 | }) 67 | } 68 | 69 | async function buildGeneral() { 70 | const bundle = await generateBundle('es') 71 | 72 | return Promise.all([ 73 | await writeBundle(bundle, 'es'), 74 | await writeBundle(bundle, 'cjs') 75 | ]) 76 | } 77 | 78 | async function buildUmd() { 79 | const bundle = await generateBundle('umd') 80 | return writeBundle(bundle, 'umd') 81 | } 82 | 83 | async function buildMin() { 84 | const bundle = await generateBundle('min') 85 | return writeBundle(bundle, 'min') 86 | } 87 | 88 | async function run() { 89 | try { 90 | Promise.all([buildGeneral(), buildUmd(), buildMin()]) 91 | } catch (err) { 92 | console.error(err) 93 | } 94 | } 95 | 96 | run() 97 | -------------------------------------------------------------------------------- /index.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'vanilla-commons' { 2 | export = commons; 3 | } 4 | 5 | declare namespace commons { 6 | interface DateDiff { 7 | milliseconds: number; 8 | seconds: number; 9 | minutes: number; 10 | hours: number; 11 | days: number; 12 | weeks: number; 13 | months: number; 14 | years: number; 15 | } 16 | 17 | function flattenArray(arr: any[][]): any[]; 18 | 19 | function addDays(days: number): (date: Date) => Date; 20 | function addDays(days: number, date: Date): Date; 21 | 22 | function addHours(hours: number): (date: Date) => Date; 23 | function addHours(hours: number, date: Date): Date; 24 | 25 | function addMilliseconds(milliseconds: number): (date: Date) => Date; 26 | function addMilliseconds(milliseconds: number, date: Date): Date; 27 | 28 | function addMinutes(minutes: number): (date: Date) => Date; 29 | function addMinutes(minutes: number, date: Date): Date; 30 | 31 | function addMonths(months: number): (date: Date) => Date; 32 | function addMonths(months: number, date: Date): Date; 33 | 34 | function addSeconds(seconds: number): (date: Date) => Date; 35 | function addSeconds(seconds: number, date: Date): Date; 36 | 37 | function addWeeks(weeks: number): (date: Date) => Date; 38 | function addWeeks(weeks: number, date: Date): Date; 39 | 40 | function addYears(years: number): (date: Date) => Date; 41 | function addYears(years: number, date: Date): Date; 42 | 43 | function diffDate(firstDate: Date): (secondDate: Date) => DateDiff; 44 | function diffDate(firstDate: Date, secondDate: Date): DateDiff; 45 | 46 | function formatDate(format: string): (date: Date) => String; 47 | function formatDate(format: string, date: Date): string; 48 | 49 | function isValidDate(format: string): (dateStr: string) => boolean; 50 | function isValidDate(format: string, dateStr: string): boolean; 51 | 52 | function parseDate(format: string): (dateStr: string) => Date; 53 | function parseDate(format: string, dateStr: string): Date; 54 | 55 | function addClass(newClass: string | string[], element: HTMLElement): HTMLElement; 56 | function addClass(newClass: string | string[]): (element: HTMLElement) => HTMLElement; 57 | 58 | function clearEvents(element: HTMLElement): HTMLElement; 59 | 60 | function createElement(selector?: string, children?: any[]): HTMLElement; 61 | function createElement(selector?: string, props?: any, children?: any[]): HTMLElement; 62 | 63 | function getParents(element: HTMLElement): HTMLElement[]; 64 | 65 | function hasClass(classToCheck: string | string[]): (element: HTMLElement) => boolean; 66 | function hasClass(classToCheck: string | string[], element: HTMLElement): boolean; 67 | 68 | function hideElement(elementToHide: HTMLElement | HTMLElement[]): HTMLElement | HTMLElement[]; 69 | 70 | 71 | function insertElementAfter(referenceElement: HTMLElement): (newElement: HTMLElement) => HTMLElement; 72 | function insertElementAfter(referenceElement: HTMLElement, newElement: HTMLElement): HTMLElement; 73 | 74 | function insertElementBefore(referenceElement: HTMLElement): (newElement: HTMLElement) => HTMLElement; 75 | function insertElementBefore(referenceElement: HTMLElement, newElement: HTMLElement): HTMLElement; 76 | 77 | function killElement(elementToKill: HTMLElement | HTMLElement[]): void; 78 | 79 | function removeClass(classToRemove: string | string[]): (element: HTMLElement) => HTMLElement; 80 | function removeClass(classToRemove: string | string[], element: HTMLElement): HTMLElement; 81 | 82 | function replaceElement(originalElement: HTMLElement): (newElement: HTMLElement) => HTMLElement; 83 | function replaceElement(originalElement: HTMLElement, newElement: HTMLElement): HTMLElement; 84 | 85 | function showElement(elementToShow: HTMLElement | HTMLElement[]): HTMLElement | HTMLElement[]; 86 | 87 | function toggleClass(classToToggle: string | string[]): (element: HTMLElement) => HTMLElement; 88 | function toggleClass(classToToggle: string | string[], element: HTMLElement): HTMLElement; 89 | 90 | function compose(...fns: Function[]): Function; 91 | 92 | function curry(fn: Function): Function; 93 | 94 | function pipe(...fns: Function[]): Function; 95 | 96 | function throttle(limit: number, fn: Function): Function; 97 | 98 | function round(num: number): number; 99 | 100 | function mapKeys(fn: (key: any) => any, obj: any): any; 101 | 102 | function mapValues(fn: (value: any) => any, obj: any): any; 103 | 104 | function capitalize(str: string): string; 105 | 106 | function cleanUpString(str: string): string; 107 | } 108 | -------------------------------------------------------------------------------- /lib/array/flatten-array.js: -------------------------------------------------------------------------------- 1 | import typeOf from '../utils/type-of' 2 | import validateArguments from '../utils/validate-arguments' 3 | 4 | const flattenArray = (arr, {escapeValidation} = {escapeValidation: false}) => { 5 | if (!escapeValidation) { 6 | validateArguments({ 7 | args: [arr], 8 | functionName: 'flattenArray', 9 | expectedTypes: ['array'] 10 | }) 11 | } 12 | 13 | return arr.reduce((acc, value) => { 14 | if (typeOf(value) === 'array') { 15 | return acc.concat(flattenArray(value, {escapeValidation: true})) 16 | } 17 | 18 | return acc.concat(value) 19 | }, []) 20 | } 21 | 22 | export default flattenArray 23 | -------------------------------------------------------------------------------- /lib/date/add-days.js: -------------------------------------------------------------------------------- 1 | import {addDateHelper, DAY} from './helpers' 2 | 3 | export default addDateHelper(DAY, 'addDays') 4 | -------------------------------------------------------------------------------- /lib/date/add-hours.js: -------------------------------------------------------------------------------- 1 | import {addDateHelper, HOUR} from './helpers' 2 | 3 | export default addDateHelper(HOUR, 'addHours') 4 | -------------------------------------------------------------------------------- /lib/date/add-milliseconds.js: -------------------------------------------------------------------------------- 1 | import {addDateHelper} from './helpers' 2 | 3 | export default addDateHelper(1, 'addMilliseconds') 4 | -------------------------------------------------------------------------------- /lib/date/add-minutes.js: -------------------------------------------------------------------------------- 1 | import {addDateHelper, MINUTE} from './helpers' 2 | 3 | export default addDateHelper(MINUTE, 'addMinutes') 4 | -------------------------------------------------------------------------------- /lib/date/add-months.js: -------------------------------------------------------------------------------- 1 | import curry from '../function/curry' 2 | import {addMonthsWithoutValidation, validateDateArguments} from './helpers' 3 | 4 | export default curry((months, date) => { 5 | validateDateArguments({ 6 | functionName: 'addMonths', 7 | args: [months, date] 8 | }) 9 | 10 | return addMonthsWithoutValidation(months, date) 11 | }) 12 | -------------------------------------------------------------------------------- /lib/date/add-seconds.js: -------------------------------------------------------------------------------- 1 | import {addDateHelper, SECOND} from './helpers' 2 | 3 | export default addDateHelper(SECOND, 'addSeconds') 4 | -------------------------------------------------------------------------------- /lib/date/add-weeks.js: -------------------------------------------------------------------------------- 1 | import {addDateHelper, WEEK} from './helpers' 2 | 3 | export default addDateHelper(WEEK, 'addWeeks') 4 | -------------------------------------------------------------------------------- /lib/date/add-years.js: -------------------------------------------------------------------------------- 1 | import curry from '../function/curry' 2 | import {addMonthsWithoutValidation, validateDateArguments} from './helpers' 3 | 4 | export default curry((years, date) => { 5 | validateDateArguments({ 6 | functionName: 'addYears', 7 | args: [years, date] 8 | }) 9 | 10 | return addMonthsWithoutValidation(years * 12, date) 11 | }) 12 | -------------------------------------------------------------------------------- /lib/date/diff-date.js: -------------------------------------------------------------------------------- 1 | import curry from '../function/curry' 2 | import round from '../number/round' 3 | import mapValues from '../object/map-values' 4 | import validateArguments from '../utils/validate-arguments' 5 | import {SECOND, MINUTE, HOUR, DAY, WEEK, MONTH, YEAR} from './helpers' 6 | 7 | export default curry((firstDate, secondDate) => { 8 | validateArguments({ 9 | args: [firstDate, secondDate], 10 | functionName: 'diffDate', 11 | expectedTypes: ['date', 'date'] 12 | }) 13 | 14 | const diff = Math.abs(firstDate.getTime() - secondDate.getTime()) 15 | 16 | const exactDiffs = { 17 | milliseconds: diff, 18 | seconds: diff / SECOND, 19 | minutes: diff / MINUTE, 20 | hours: diff / HOUR, 21 | days: diff / DAY, 22 | weeks: diff / WEEK, 23 | months: diff / MONTH, 24 | years: diff / YEAR 25 | } 26 | 27 | return mapValues(round, exactDiffs) 28 | }) 29 | -------------------------------------------------------------------------------- /lib/date/format-date.js: -------------------------------------------------------------------------------- 1 | import curry from '../function/curry' 2 | import validateArguments from '../utils/validate-arguments' 3 | import {addLeadingZero} from '../utils/helpers' 4 | import {formatsRegex, getDictionary} from './helpers' 5 | 6 | export default curry((format, date) => { 7 | validateArguments({ 8 | args: [format, date], 9 | functionName: 'formatDate', 10 | expectedTypes: ['string', 'date'] 11 | }) 12 | 13 | return format.replace(formatsRegex, fullMatch => { 14 | const match = fullMatch.replace(/(\{)|(\})/g, '') 15 | 16 | const num = 17 | match === 'YY' ? 18 | String(date.getFullYear()).substring(2, 4) : 19 | Date.prototype[getDictionary('get')[match]].call(date) 20 | 21 | if (match === 'MM') { 22 | return addLeadingZero(num + 1, 2) 23 | } 24 | 25 | return addLeadingZero(num, 2) 26 | }) 27 | }) 28 | -------------------------------------------------------------------------------- /lib/date/helpers.js: -------------------------------------------------------------------------------- 1 | import mapValues from '../object/map-values' 2 | import {monthDays} from '../utils/helpers' 3 | import curry from '../function/curry' 4 | import validateArguments from '../utils/validate-arguments' 5 | 6 | export const SECOND = 1e3 7 | export const MINUTE = 6e4 8 | export const HOUR = 3.6e6 9 | export const DAY = 8.64e7 10 | export const WEEK = 6.048e8 11 | export const MONTH = 2.592e9 12 | export const YEAR = 3.1536e10 13 | 14 | export const baseDictionary = { 15 | YYYY: 'FullYear', 16 | YY: 'Year', 17 | MM: 'Month', 18 | DD: 'Date', 19 | HH: 'Hours', 20 | mm: 'Minutes', 21 | ss: 'Seconds', 22 | ms: 'Milliseconds' 23 | } 24 | 25 | export const getDictionary = mode => 26 | mapValues(value => mode + value, baseDictionary) 27 | 28 | export const validKeysRegex = Object.keys(baseDictionary) 29 | .map((key, index, arr) => { 30 | const group = `(${key})` 31 | if (index !== arr.length - 1) { 32 | return group + '|' 33 | } 34 | return group 35 | }) 36 | .join('') 37 | 38 | export const formatsRegex = new RegExp('{(' + validKeysRegex + ')}', 'g') 39 | 40 | export const validateDateArguments = ({functionName, args}) => { 41 | validateArguments({ 42 | args, 43 | functionName, 44 | expectedTypes: ['number', 'date'] 45 | }) 46 | } 47 | 48 | export const addMonthsWithoutValidation = (months, date) => { 49 | const monthsAhead = date.getMonth() + months 50 | const finalDate = new Date(0) 51 | finalDate.setFullYear(date.getFullYear(), monthsAhead, 1) 52 | finalDate.setHours( 53 | date.getHours(), 54 | date.getMinutes(), 55 | date.getSeconds(), 56 | date.getMilliseconds() 57 | ) 58 | const daysInMonth = monthDays(finalDate.getMonth(), finalDate.getFullYear()) 59 | finalDate.setDate(Math.min(daysInMonth, date.getDate())) 60 | return finalDate 61 | } 62 | 63 | export const addDateHelper = (multiplicationFactor, functionName) => 64 | curry((time, date) => { 65 | validateDateArguments({ 66 | functionName, 67 | args: [time, date] 68 | }) 69 | 70 | return new Date(date.getTime() + time * multiplicationFactor) 71 | }) 72 | -------------------------------------------------------------------------------- /lib/date/is-valid-date.js: -------------------------------------------------------------------------------- 1 | import curry from '../function/curry' 2 | import validateArguments from '../utils/validate-arguments' 3 | import parseDate from './parse-date' 4 | import formatDate from './format-date' 5 | 6 | export default curry((format, dateStr) => { 7 | validateArguments({ 8 | args: [format, dateStr], 9 | functionName: 'isValidDate', 10 | expectedTypes: ['string', 'string'] 11 | }) 12 | 13 | const date = parseDate(format, dateStr) 14 | 15 | return formatDate(format, date) === dateStr 16 | }) 17 | -------------------------------------------------------------------------------- /lib/date/parse-date.js: -------------------------------------------------------------------------------- 1 | import curry from '../function/curry' 2 | import validateArguments from '../utils/validate-arguments' 3 | import {formatsRegex, getDictionary} from './helpers' 4 | 5 | export default curry((format, dateStr) => { 6 | validateArguments({ 7 | args: [format, dateStr], 8 | functionName: 'parseDate', 9 | expectedTypes: ['string', 'string'] 10 | }) 11 | 12 | const date = new Date(0) 13 | 14 | let numberOfDividers = 0 15 | 16 | format.replace(formatsRegex, (fullMatch, ...args) => { 17 | const match = fullMatch.replace(/(\{)|(\})/g, '') 18 | const offset = args[args.length - 2] + numberOfDividers 19 | let value = dateStr.substr(offset, match.length) 20 | 21 | if (match === 'MM') { 22 | value-- 23 | } 24 | 25 | if (match === 'YY' && Number(value) < 30) { 26 | date.setFullYear('20' + value) 27 | } else { 28 | Date.prototype[getDictionary('set')[match]].call(date, value) 29 | } 30 | 31 | numberOfDividers -= 2 32 | return fullMatch 33 | }) 34 | 35 | return date 36 | }) 37 | -------------------------------------------------------------------------------- /lib/element/add-class.js: -------------------------------------------------------------------------------- 1 | import curry from '../function/curry' 2 | import typeOf from '../utils/type-of' 3 | import {validateClassManipulationArguments} from './helpers' 4 | import hasClass from './has-class' 5 | 6 | export default curry((newClass, element) => { 7 | validateClassManipulationArguments({ 8 | functionName: 'addClass', 9 | args: [newClass, element] 10 | }) 11 | 12 | const classesToAdd = typeOf(newClass) === 'string' ? [newClass] : newClass 13 | 14 | element.className = element.className 15 | .split(' ') 16 | .filter(str => str.trim() !== '') 17 | .concat(classesToAdd.filter(classToAdd => !hasClass(classToAdd, element))) 18 | .join(' ') 19 | 20 | return element 21 | }) 22 | -------------------------------------------------------------------------------- /lib/element/clear-events.js: -------------------------------------------------------------------------------- 1 | import validateArguments from '../utils/validate-arguments' 2 | import replaceElement from './replace-element' 3 | 4 | export default element => { 5 | validateArguments({ 6 | args: [element], 7 | functionName: 'clearEvents', 8 | expectedTypes: ['element'] 9 | }) 10 | 11 | const clonedElement = element.cloneNode(true) 12 | 13 | if (element.parentNode) { 14 | replaceElement(element, clonedElement) 15 | } 16 | 17 | return clonedElement 18 | } 19 | -------------------------------------------------------------------------------- /lib/element/create-element.js: -------------------------------------------------------------------------------- 1 | import isBooleanAttribute from 'is-boolean-attribute' 2 | import validateArguments from '../utils/validate-arguments' 3 | import typeOf from '../utils/type-of' 4 | import addClass from './add-class' 5 | 6 | const VALID_CHILDREN = ['string', 'element', 'array'] 7 | 8 | const appendChild = parent => child => { 9 | if (typeOf(child) === 'string') { 10 | const text = document.createTextNode(child) 11 | parent.appendChild(text) 12 | } else if (typeOf(child) === 'element') { 13 | parent.appendChild(child) 14 | } 15 | } 16 | 17 | const separateArgs = args => { 18 | if (args.length === 0) { 19 | return ['div', {}, false] 20 | } 21 | 22 | if (args.length === 1) { 23 | return [args[0], {}, false] 24 | } 25 | 26 | if (args.length === 2) { 27 | if (VALID_CHILDREN.includes(typeOf(args[1]))) { 28 | return [args[0], {}, args[1]] 29 | } 30 | 31 | return [args[0], args[1], false] 32 | } 33 | 34 | return args 35 | } 36 | 37 | export default (...args) => { 38 | const [selector, props, children] = separateArgs(args) 39 | 40 | validateArguments({ 41 | args: [selector, props, children], 42 | functionName: 'createElement', 43 | expectedTypes: [ 44 | 'string', 45 | 'object', 46 | children === false ? 'optional' : VALID_CHILDREN 47 | ] 48 | }) 49 | 50 | const nodeType = selector.match(/^[a-z0-9]+/i) 51 | const id = selector.match(/#([a-z]+[a-z0-9-]*)/gi) 52 | const classes = selector.match(/\.([a-z]+[a-z0-9-]*)/gi) 53 | const attributes = selector.match( 54 | /\[([a-z][a-z-]+)(=['|"]?([^\]]*)['|"]?)?\]/gi 55 | ) 56 | 57 | const element = document.createElement( 58 | nodeType === null ? 'div' : nodeType[0] 59 | ) 60 | 61 | if (id !== null) { 62 | element.id = id[0].replace('#', '') 63 | } 64 | 65 | if (classes !== null) { 66 | element.className = [].map 67 | .call(classes, item => item.replace('.', '')) 68 | .join(' ') 69 | } 70 | 71 | if (attributes !== null) { 72 | [].forEach.call(attributes, item => { 73 | const [key, value] = item.replace(/\[|\]|'|"|`/g, '').split('=') 74 | element.setAttribute( 75 | key, 76 | value === undefined || isBooleanAttribute(key) ? '' : value 77 | ) 78 | }) 79 | } 80 | 81 | Object.keys(props).forEach(prop => { 82 | if (prop === 'data') { 83 | Object.keys(props.data).forEach(key => { 84 | element.setAttribute('data-' + key, props.data[key]) 85 | }) 86 | return 87 | } 88 | 89 | if (prop === 'className') { 90 | addClass(props.className.split(' '), element) 91 | return 92 | } 93 | 94 | if (prop === 'inner') { 95 | element.innerHTML = props.inner 96 | return 97 | } 98 | 99 | if (isBooleanAttribute(prop)) { 100 | if (props[prop]) { 101 | element.setAttribute(prop, '') 102 | } 103 | return 104 | } 105 | 106 | if (prop.substring(0, 2) === 'on') { 107 | const eventName = prop.substring(2, prop.length) 108 | element.addEventListener(eventName, props[prop]) 109 | return 110 | } 111 | 112 | element.setAttribute(prop, props[prop]) 113 | }) 114 | 115 | const childrenType = typeOf(children) 116 | const appendElement = appendChild(element) 117 | 118 | if (childrenType === 'string' || childrenType === 'element') { 119 | appendElement(children) 120 | } else if (childrenType === 'array') { 121 | children.forEach(appendElement) 122 | } 123 | 124 | return element 125 | } 126 | -------------------------------------------------------------------------------- /lib/element/get-parents.js: -------------------------------------------------------------------------------- 1 | import validateArguments from '../utils/validate-arguments' 2 | 3 | export default element => { 4 | validateArguments({ 5 | args: [element], 6 | functionName: 'getParents', 7 | expectedTypes: ['element'] 8 | }) 9 | 10 | let parent = element 11 | const parents = [] 12 | 13 | while (parent !== document.body) { 14 | parent = parent.parentNode 15 | 16 | if (!parent) { 17 | break 18 | } 19 | parents.push(parent) 20 | } 21 | 22 | return parents 23 | } 24 | -------------------------------------------------------------------------------- /lib/element/has-class.js: -------------------------------------------------------------------------------- 1 | import curry from '../function/curry' 2 | import typeOf from '../utils/type-of' 3 | import {validateClassManipulationArguments} from './helpers' 4 | 5 | export default curry((classToCheck, element) => { 6 | validateClassManipulationArguments({ 7 | functionName: 'hasClass', 8 | args: [classToCheck, element] 9 | }) 10 | 11 | const classesToCheck = 12 | typeOf(classToCheck) === 'string' ? [classToCheck] : classToCheck 13 | 14 | const className = element.className 15 | .split(' ') 16 | .filter(str => str.trim() !== '') 17 | 18 | return classesToCheck.every(item => className.indexOf(item) !== -1) 19 | }) 20 | -------------------------------------------------------------------------------- /lib/element/helpers.js: -------------------------------------------------------------------------------- 1 | import validateArguments from '../utils/validate-arguments' 2 | 3 | export const validateClassManipulationArguments = ({functionName, args}) => { 4 | validateArguments({ 5 | args, 6 | functionName, 7 | expectedTypes: [['string', 'array'], 'element'] 8 | }) 9 | } 10 | -------------------------------------------------------------------------------- /lib/element/hide-element.js: -------------------------------------------------------------------------------- 1 | import validateArguments from '../utils/validate-arguments' 2 | import typeOf from '../utils/type-of' 3 | 4 | export default elementsToHide => { 5 | validateArguments({ 6 | args: [elementsToHide], 7 | functionName: 'hideElement', 8 | expectedTypes: [['element', 'array']] 9 | }) 10 | 11 | const elements = 12 | typeOf(elementsToHide) === 'array' ? elementsToHide : [elementsToHide] 13 | 14 | elements.forEach(element => { 15 | element.style.display = 'none' 16 | }) 17 | 18 | return elementsToHide 19 | } 20 | -------------------------------------------------------------------------------- /lib/element/insert-element-after.js: -------------------------------------------------------------------------------- 1 | import validateArguments from '../utils/validate-arguments' 2 | import curry from '../function/curry' 3 | 4 | export default curry((referenceElement, newElement) => { 5 | validateArguments({ 6 | args: [referenceElement, newElement], 7 | functionName: 'insertElementAfter', 8 | expectedTypes: ['element', 'element'] 9 | }) 10 | 11 | referenceElement.parentNode.insertBefore( 12 | newElement, 13 | referenceElement.nextSibling 14 | ) 15 | 16 | return newElement 17 | }) 18 | -------------------------------------------------------------------------------- /lib/element/insert-element-before.js: -------------------------------------------------------------------------------- 1 | import validateArguments from '../utils/validate-arguments' 2 | import curry from '../function/curry' 3 | 4 | export default curry((referenceElement, newElement) => { 5 | validateArguments({ 6 | args: [referenceElement, newElement], 7 | functionName: 'insertElementBefore', 8 | expectedTypes: ['element', 'element'] 9 | }) 10 | 11 | referenceElement.parentNode.insertBefore(newElement, referenceElement) 12 | 13 | return newElement 14 | }) 15 | -------------------------------------------------------------------------------- /lib/element/kill-element.js: -------------------------------------------------------------------------------- 1 | import validateArguments from '../utils/validate-arguments' 2 | import typeOf from '../utils/type-of' 3 | 4 | export default elementsToKill => { 5 | validateArguments({ 6 | args: [elementsToKill], 7 | functionName: 'killElement', 8 | expectedTypes: [['element', 'array']] 9 | }) 10 | 11 | const elements = 12 | typeOf(elementsToKill) === 'array' ? elementsToKill : [elementsToKill] 13 | 14 | elements.forEach(element => { 15 | element.parentNode.removeChild(element) 16 | }) 17 | } 18 | -------------------------------------------------------------------------------- /lib/element/remove-class.js: -------------------------------------------------------------------------------- 1 | import typeOf from '../utils/type-of' 2 | import curry from '../function/curry' 3 | import {validateClassManipulationArguments} from './helpers' 4 | 5 | export default curry((classToRemove, element) => { 6 | validateClassManipulationArguments({ 7 | functionName: 'removeClass', 8 | args: [classToRemove, element] 9 | }) 10 | 11 | element.className = element.className 12 | .split(' ') 13 | .filter(str => { 14 | if (str.trim() === '') { 15 | return false 16 | } 17 | 18 | if (typeOf(classToRemove) === 'string' && str === classToRemove) { 19 | return false 20 | } 21 | 22 | if ( 23 | typeOf(classToRemove) === 'array' && 24 | classToRemove.some(item => item === str) 25 | ) { 26 | return false 27 | } 28 | 29 | return true 30 | }) 31 | .join(' ') 32 | 33 | return element 34 | }) 35 | -------------------------------------------------------------------------------- /lib/element/replace-element.js: -------------------------------------------------------------------------------- 1 | import validateArguments from '../utils/validate-arguments' 2 | import curry from '../function/curry' 3 | 4 | export default curry((originalElement, newElement) => { 5 | validateArguments({ 6 | args: [originalElement, newElement], 7 | functionName: 'replaceElement', 8 | expectedTypes: ['element', 'element'] 9 | }) 10 | 11 | originalElement.parentNode.replaceChild(newElement, originalElement) 12 | 13 | return newElement 14 | }) 15 | -------------------------------------------------------------------------------- /lib/element/show-element.js: -------------------------------------------------------------------------------- 1 | import validateArguments from '../utils/validate-arguments' 2 | import typeOf from '../utils/type-of' 3 | 4 | export default elementsToShow => { 5 | validateArguments({ 6 | args: [elementsToShow], 7 | functionName: 'showElement', 8 | expectedTypes: [['element', 'array']] 9 | }) 10 | 11 | const elements = 12 | typeOf(elementsToShow) === 'array' ? elementsToShow : [elementsToShow] 13 | 14 | elements.forEach(element => { 15 | element.style.display = 'block' 16 | }) 17 | 18 | return elementsToShow 19 | } 20 | -------------------------------------------------------------------------------- /lib/element/toggle-class.js: -------------------------------------------------------------------------------- 1 | import curry from '../function/curry' 2 | import typeOf from '../utils/type-of' 3 | import addClass from './add-class' 4 | import hasClass from './has-class' 5 | import removeClass from './remove-class' 6 | import {validateClassManipulationArguments} from './helpers' 7 | 8 | export default curry((classToToggle, element) => { 9 | validateClassManipulationArguments({ 10 | functionName: 'toggleClass', 11 | args: [classToToggle, element] 12 | }) 13 | 14 | const classesToToggle = 15 | typeOf(classToToggle) === 'string' ? [classToToggle] : classToToggle 16 | 17 | classesToToggle.forEach(item => { 18 | if (hasClass(item, element)) { 19 | removeClass(item, element) 20 | } else { 21 | addClass(item, element) 22 | } 23 | }) 24 | 25 | return element 26 | }) 27 | -------------------------------------------------------------------------------- /lib/function/compose.js: -------------------------------------------------------------------------------- 1 | import validateArguments from '../utils/validate-arguments' 2 | 3 | export default (...fns) => { 4 | validateArguments({ 5 | args: fns, 6 | functionName: 'compose', 7 | expectedTypes: Array(fns.length).fill('function') 8 | }) 9 | 10 | return value => 11 | fns.reduceRight((accumulator, current) => current(accumulator), value) 12 | } 13 | -------------------------------------------------------------------------------- /lib/function/curry.js: -------------------------------------------------------------------------------- 1 | import validateArguments from '../utils/validate-arguments' 2 | 3 | export default function curry(fn, ...args) { 4 | validateArguments({ 5 | args: [fn], 6 | functionName: 'curry', 7 | expectedTypes: ['function'] 8 | }) 9 | 10 | if (args.length === fn.length) { 11 | return fn(...args) 12 | } 13 | return curry.bind(this, fn, ...args) 14 | } 15 | -------------------------------------------------------------------------------- /lib/function/pipe.js: -------------------------------------------------------------------------------- 1 | import validateArguments from '../utils/validate-arguments' 2 | 3 | export default (...fns) => { 4 | validateArguments({ 5 | args: fns, 6 | functionName: 'pipe', 7 | expectedTypes: Array(fns.length).fill('function') 8 | }) 9 | 10 | return value => 11 | fns.reduce((accumulator, current) => current(accumulator), value) 12 | } 13 | -------------------------------------------------------------------------------- /lib/function/throttle.js: -------------------------------------------------------------------------------- 1 | import validateArguments from '../utils/validate-arguments' 2 | import curry from './curry' 3 | 4 | export default curry((limit, fn) => { 5 | validateArguments({ 6 | args: [limit, fn], 7 | functionName: 'throttle', 8 | expectedTypes: ['number', 'function'] 9 | }) 10 | 11 | let wait = false 12 | 13 | return (...args) => { 14 | if (!wait) { 15 | fn(...args) 16 | wait = true 17 | setTimeout(() => { 18 | wait = false 19 | }, limit) 20 | } 21 | } 22 | }) 23 | -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | import flattenArray from './array/flatten-array' 2 | import addDays from './date/add-days' 3 | import addHours from './date/add-hours' 4 | import addMilliseconds from './date/add-milliseconds' 5 | import addMinutes from './date/add-minutes' 6 | import addMonths from './date/add-months' 7 | import addSeconds from './date/add-seconds' 8 | import addWeeks from './date/add-weeks' 9 | import addYears from './date/add-years' 10 | import diffDate from './date/diff-date' 11 | import formatDate from './date/format-date' 12 | import isValidDate from './date/is-valid-date' 13 | import parseDate from './date/parse-date' 14 | import addClass from './element/add-class' 15 | import clearEvents from './element/clear-events' 16 | import createElement from './element/create-element' 17 | import getParents from './element/get-parents' 18 | import hasClass from './element/has-class' 19 | import hideElement from './element/hide-element' 20 | import insertElementAfter from './element/insert-element-after' 21 | import insertElementBefore from './element/insert-element-before' 22 | import killElement from './element/kill-element' 23 | import removeClass from './element/remove-class' 24 | import replaceElement from './element/replace-element' 25 | import showElement from './element/show-element' 26 | import toggleClass from './element/toggle-class' 27 | import compose from './function/compose' 28 | import curry from './function/curry' 29 | import pipe from './function/pipe' 30 | import throttle from './function/throttle' 31 | import round from './number/round' 32 | import mapKeys from './object/map-keys' 33 | import mapValues from './object/map-values' 34 | import capitalize from './string/capitalize' 35 | import cleanUpString from './string/clean-up-string' 36 | 37 | export { 38 | flattenArray, 39 | addDays, 40 | addHours, 41 | addMilliseconds, 42 | addMinutes, 43 | addMonths, 44 | addSeconds, 45 | addWeeks, 46 | addYears, 47 | diffDate, 48 | formatDate, 49 | isValidDate, 50 | parseDate, 51 | addClass, 52 | clearEvents, 53 | createElement, 54 | getParents, 55 | hasClass, 56 | hideElement, 57 | insertElementAfter, 58 | insertElementBefore, 59 | killElement, 60 | removeClass, 61 | replaceElement, 62 | showElement, 63 | toggleClass, 64 | compose, 65 | curry, 66 | pipe, 67 | throttle, 68 | round, 69 | mapKeys, 70 | mapValues, 71 | capitalize, 72 | cleanUpString 73 | } 74 | -------------------------------------------------------------------------------- /lib/number/round.js: -------------------------------------------------------------------------------- 1 | import validateArguments from '../utils/validate-arguments' 2 | 3 | export default num => { 4 | validateArguments({ 5 | args: [num], 6 | functionName: 'round', 7 | expectedTypes: ['number'] 8 | }) 9 | return Number(Math.sign(num) * (Math.round(Math.abs(num) + 'e2') + 'e-2')) 10 | } 11 | -------------------------------------------------------------------------------- /lib/object/helpers.js: -------------------------------------------------------------------------------- 1 | import curry from '../function/curry' 2 | import capitalize from '../string/capitalize' 3 | import validateArguments from '../utils/validate-arguments' 4 | 5 | export const mapObject = mode => 6 | curry((fn, object) => { 7 | const functionName = 'map' + capitalize(mode) 8 | validateArguments({ 9 | args: [fn, object], 10 | functionName, 11 | expectedTypes: ['function', 'object'] 12 | }) 13 | 14 | const transformation = { 15 | values: key => ({[key]: fn(object[key])}), 16 | keys: key => ({[fn(key)]: object[key]}) 17 | } 18 | 19 | return Object.keys(object) 20 | .map(transformation[mode]) 21 | .reduce((previous, current) => ({...previous, ...current}), {}) 22 | }) 23 | -------------------------------------------------------------------------------- /lib/object/map-keys.js: -------------------------------------------------------------------------------- 1 | import {mapObject} from './helpers' 2 | 3 | export default mapObject('keys') 4 | -------------------------------------------------------------------------------- /lib/object/map-values.js: -------------------------------------------------------------------------------- 1 | import {mapObject} from './helpers' 2 | 3 | export default mapObject('values') 4 | -------------------------------------------------------------------------------- /lib/string/capitalize.js: -------------------------------------------------------------------------------- 1 | import validateArguments from '../utils/validate-arguments' 2 | import cleanUpString from './clean-up-string' 3 | 4 | export default str => { 5 | validateArguments({ 6 | args: [str], 7 | functionName: 'capitalize', 8 | expectedTypes: ['string'] 9 | }) 10 | 11 | if (cleanUpString(str) === '') { 12 | return str 13 | } 14 | 15 | return str[0].toUpperCase() + str.slice(1) 16 | } 17 | -------------------------------------------------------------------------------- /lib/string/clean-up-string.js: -------------------------------------------------------------------------------- 1 | import validateArguments from '../utils/validate-arguments' 2 | 3 | export default str => { 4 | validateArguments({ 5 | args: [str], 6 | functionName: 'cleanUpString', 7 | expectedTypes: ['string'] 8 | }) 9 | 10 | return str.replace(/(\r\n|\n|\r)/gm, '').trim() 11 | } 12 | -------------------------------------------------------------------------------- /lib/utils/error-message.js: -------------------------------------------------------------------------------- 1 | import {getOrdinalLetters} from './helpers' 2 | 3 | export default ({functionName, expectedType, position, messageType}) => { 4 | return `The ${position}${getOrdinalLetters( 5 | position 6 | )} argument to function \`${functionName}\` ${messageType === 'unexpected' ? 7 | 'has an unexpected type' : 8 | 'is not defined'}, a ${expectedType} is expected.` 9 | } 10 | -------------------------------------------------------------------------------- /lib/utils/helpers.js: -------------------------------------------------------------------------------- 1 | export const addLeadingZero = (num, length) => { 2 | let str = String(num) 3 | while (str.length < length) { 4 | str = '0' + str 5 | } 6 | 7 | return str 8 | } 9 | 10 | export const monthDays = (month, year) => 11 | new Date(Date.UTC(year, month + 1, 0)).getUTCDate() 12 | 13 | export const getOrdinalLetters = num => { 14 | const cent = num % 100 15 | if (cent >= 10 && cent <= 20) { 16 | return 'th' 17 | } 18 | 19 | const dec = num % 10 20 | if (dec === 1) { 21 | return 'st' 22 | } 23 | if (dec === 2) { 24 | return 'nd' 25 | } 26 | if (dec === 3) { 27 | return 'rd' 28 | } 29 | return 'th' 30 | } 31 | -------------------------------------------------------------------------------- /lib/utils/type-of.js: -------------------------------------------------------------------------------- 1 | const toString = Object.prototype.toString 2 | 3 | export default val => { 4 | const type = typeof val 5 | 6 | if (type === 'undefined') { 7 | return 'undefined' 8 | } 9 | 10 | if (type === 'string' || val instanceof String) { 11 | return 'string' 12 | } 13 | if (type === 'number' || val instanceof Number) { 14 | return 'number' 15 | } 16 | 17 | if (type === 'function' || val instanceof Function) { 18 | return 'function' 19 | } 20 | 21 | if (typeof Array.isArray !== 'undefined' && Array.isArray(val)) { 22 | return 'array' 23 | } 24 | 25 | if (val instanceof Date || toString.call(val) === '[object Date]') { 26 | return 'date' 27 | } 28 | 29 | if (val instanceof HTMLElement) { 30 | return 'element' 31 | } 32 | 33 | return 'object' 34 | } 35 | -------------------------------------------------------------------------------- /lib/utils/validate-arguments.js: -------------------------------------------------------------------------------- 1 | import typeOf from './type-of' 2 | import errorMessage from './error-message' 3 | 4 | export default ({expectedTypes, functionName, args}) => { 5 | for (let index = 0; index < args.length; index++) { 6 | if (expectedTypes[index] === 'optional') { 7 | continue 8 | } 9 | 10 | const arg = args[index] 11 | const types = 12 | typeOf(expectedTypes[index]) === 'array' ? 13 | expectedTypes[index] : 14 | [expectedTypes[index]] 15 | 16 | const defaultErrorMessage = { 17 | functionName, 18 | position: index + 1, 19 | expectedType: types.join(' or ') 20 | } 21 | 22 | if (typeOf(arg) === 'undefined') { 23 | throw new TypeError( 24 | errorMessage({ 25 | ...defaultErrorMessage, 26 | messageType: 'notDefined' 27 | }) 28 | ) 29 | } 30 | 31 | const conditions = types.map(type => { 32 | return typeOf(arg) !== type 33 | }) 34 | 35 | if (!conditions.some(condition => condition === false)) { 36 | throw new TypeError( 37 | errorMessage({ 38 | ...defaultErrorMessage, 39 | messageType: 'unexpected' 40 | }) 41 | ) 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vanilla-commons", 3 | "version": "1.4.0-development", 4 | "description": "Lightweight common vanilla utilities for the modern web development", 5 | "main": "dist/vanilla-commons.js", 6 | "module": "dist/vanilla-commons.es.js", 7 | "jsnext:main": "dist/vanilla-commons.es.js", 8 | "browser": "dist/vanilla-commons.umd.js", 9 | "files": [ 10 | "dist", 11 | "index.d.ts" 12 | ], 13 | "scripts": { 14 | "prelint": "prettier --single-quote --no-semi --no-bracket-spacing --trailing-comma none --write \"lib/**/*.js\" --write build.js --write \"test/**/*.js\"", 15 | "lint": "xo --fix", 16 | "test": "jest", 17 | "test:watch": "jest --watch", 18 | "coverage": "jest --coverage", 19 | "coveralls": "npm run coverage && cat coverage/lcov.info | coveralls", 20 | "build": "node build.js", 21 | "precommit": "lint-staged && npm test && npm run build", 22 | "prepublish": "npm run precommit", 23 | "semantic-release": "semantic-release" 24 | }, 25 | "repository": { 26 | "type": "git", 27 | "url": "https://github.com/gugutz/vanilla-commons.git" 28 | }, 29 | "keywords": [ 30 | "util", 31 | "functional", 32 | "immutable", 33 | "pure", 34 | "modules", 35 | "lightweight", 36 | "library", 37 | "fast", 38 | "small", 39 | "common", 40 | "utilities", 41 | "vanilla", 42 | "modern", 43 | "curry" 44 | ], 45 | "author": "Gustavo P Borges", 46 | "license": "MIT", 47 | "bugs": { 48 | "url": "https://github.com/gugutz/vanilla-commons/issues" 49 | }, 50 | "babel": { 51 | "presets": [ 52 | "env", 53 | "stage-0" 54 | ] 55 | }, 56 | "homepage": "https://github.com/gugutz/vanilla-commons#readme", 57 | "devDependencies": { 58 | "babel-core": "^6.25.0", 59 | "babel-plugin-external-helpers": "^6.22.0", 60 | "babel-preset-env": "^1.5.2", 61 | "babel-preset-stage-0": "^6.24.1", 62 | "coveralls": "^2.13.1", 63 | "husky": "^0.14.1", 64 | "jest": "^20.0.4", 65 | "lint-staged": "^4.2.3", 66 | "prettier": "^1.5.2", 67 | "rollup": "^0.43.0", 68 | "rollup-plugin-babel": "^2.7.1", 69 | "rollup-plugin-commonjs": "^8.0.2", 70 | "rollup-plugin-filesize": "^1.4.2", 71 | "rollup-plugin-node-resolve": "^3.0.0", 72 | "rollup-plugin-uglify": "^2.0.1", 73 | "xo": "^0.18.2", 74 | "semantic-release": "^15.13.3" 75 | }, 76 | "xo": { 77 | "envs": [ 78 | "browser", 79 | "jest" 80 | ], 81 | "rules": { 82 | "no-mixed-operators": "warn", 83 | "import/prefer-default-export": 0 84 | }, 85 | "space": true, 86 | "semicolon": false 87 | }, 88 | "dependencies": { 89 | "is-boolean-attribute": "0.0.1" 90 | }, 91 | "lint-staged": { 92 | "*.js": [ 93 | "npm run lint", 94 | "git add" 95 | ] 96 | }, 97 | "types": "./index.d.ts" 98 | } 99 | -------------------------------------------------------------------------------- /test/array/flatten-array.test.js: -------------------------------------------------------------------------------- 1 | import flattenArray from '../../lib/array/flatten-array' 2 | 3 | describe('flattenArray main functionality', () => { 4 | it('should flatten an array', () => { 5 | const expected = [1, 2, 3, 4] 6 | expect(flattenArray([1, 2, 3, 4])).toEqual(expected) 7 | expect(flattenArray([1, [2, 3, 4]])).toEqual(expected) 8 | expect(flattenArray([[1], [2, [3, 4]]])).toEqual(expected) 9 | expect(flattenArray([1, [2, 3], 4])).toEqual(expected) 10 | }) 11 | }) 12 | 13 | describe('flattenArray arguments validation errors', () => { 14 | it('should throw an error with a friendly message when the first argument has an unexpected type', () => { 15 | const expected = expect(() => { 16 | flattenArray({}) 17 | }) 18 | 19 | expected.toThrow(TypeError) 20 | expected.toThrow(/1st/) 21 | expected.toThrow(/`flattenArray`/) 22 | expected.toThrow(/unexpected type/) 23 | expected.toThrow(/array is expected/) 24 | }) 25 | 26 | it('should throw an error with a friendly message when the first argument is undefined', () => { 27 | const expected = expect(() => { 28 | flattenArray() 29 | }) 30 | 31 | expected.toThrow(TypeError) 32 | expected.toThrow(/1st/) 33 | expected.toThrow(/`flattenArray`/) 34 | expected.toThrow(/is not defined/) 35 | expected.toThrow(/array is expected/) 36 | }) 37 | }) 38 | -------------------------------------------------------------------------------- /test/date/add-days.test.js: -------------------------------------------------------------------------------- 1 | import addDays from '../../lib/date/add-days' 2 | 3 | describe('addDays main functionality', () => { 4 | it('should add days on a date', () => { 5 | const date = new Date('December 17, 1995 03:24:00') 6 | const actual = addDays(6, date) 7 | const expected = new Date('December 23, 1995 03:24:00') 8 | expect(actual).toEqual(expected) 9 | }) 10 | 11 | it('should remove days of a date', () => { 12 | const date = new Date('December 17, 1995 03:24:00') 13 | const actual = addDays(-6, date) 14 | const expected = new Date('December 11, 1995 03:24:00') 15 | expect(actual).toEqual(expected) 16 | }) 17 | 18 | it('should be curried', () => { 19 | const date = new Date('December 17, 1995 03:24:00') 20 | const actual = addDays(6)(date) 21 | const expected = new Date('December 23, 1995 03:24:00') 22 | expect(actual).toEqual(expected) 23 | }) 24 | }) 25 | 26 | describe('addDays arguments validation errors', () => { 27 | it('should throw an error with a friendly message when the first argument has an unexpected type', () => { 28 | const expected = expect(() => { 29 | addDays({}, new Date()) 30 | }) 31 | 32 | expected.toThrow(TypeError) 33 | expected.toThrow(/1st/) 34 | expected.toThrow(/`addDays`/) 35 | expected.toThrow(/unexpected type/) 36 | expected.toThrow(/number is expected/) 37 | }) 38 | 39 | it('should throw an error with a friendly message when the first argument is not defined', () => { 40 | const expected = expect(() => { 41 | addDays(undefined, new Date()) 42 | }) 43 | 44 | expected.toThrow(TypeError) 45 | expected.toThrow(/1st/) 46 | expected.toThrow(/`addDays`/) 47 | expected.toThrow(/is not defined/) 48 | expected.toThrow(/number is expected/) 49 | }) 50 | 51 | it('should throw an error with a friendly message when the second argument has an unexpected type', () => { 52 | const expected = expect(() => { 53 | addDays(23, {}) 54 | }) 55 | 56 | expected.toThrow(TypeError) 57 | expected.toThrow(/2nd/) 58 | expected.toThrow(/`addDays`/) 59 | expected.toThrow(/unexpected type/) 60 | expected.toThrow(/date is expected/) 61 | }) 62 | 63 | it('should throw an error with a friendly message when the second argument is not defined', () => { 64 | const expected = expect(() => { 65 | addDays(23)(undefined) 66 | }) 67 | 68 | expected.toThrow(TypeError) 69 | expected.toThrow(/2nd/) 70 | expected.toThrow(/`addDays`/) 71 | expected.toThrow(/is not defined/) 72 | expected.toThrow(/date is expected/) 73 | }) 74 | }) 75 | -------------------------------------------------------------------------------- /test/date/add-hours.test.js: -------------------------------------------------------------------------------- 1 | import addHours from '../../lib/date/add-hours' 2 | 3 | describe('addHours main functionality', () => { 4 | it('should add hours on a date', () => { 5 | const date = new Date('December 17, 1995 03:24:00') 6 | const actual = addHours(2, date) 7 | const expected = new Date('December 17, 1995 05:24:00') 8 | expect(actual).toEqual(expected) 9 | }) 10 | 11 | it('should remove hours of a date', () => { 12 | const date = new Date('December 17, 1995 03:24:00') 13 | const actual = addHours(-2, date) 14 | const expected = new Date('December 17, 1995 01:24:00') 15 | expect(actual).toEqual(expected) 16 | }) 17 | 18 | it('should be curried', () => { 19 | const date = new Date('December 17, 1995 03:24:00') 20 | const actual = addHours(2)(date) 21 | const expected = new Date('December 17, 1995 05:24:00') 22 | expect(actual).toEqual(expected) 23 | }) 24 | }) 25 | 26 | describe('addHours arguments validation errors', () => { 27 | it('should throw an error with a friendly message when the first argument has an unexpected type', () => { 28 | const expected = expect(() => { 29 | addHours({}, new Date()) 30 | }) 31 | 32 | expected.toThrow(TypeError) 33 | expected.toThrow(/1st/) 34 | expected.toThrow(/`addHours`/) 35 | expected.toThrow(/unexpected type/) 36 | expected.toThrow(/number is expected/) 37 | }) 38 | 39 | it('should throw an error with a friendly message when the first argument is not defined', () => { 40 | const expected = expect(() => { 41 | addHours(undefined, new Date()) 42 | }) 43 | 44 | expected.toThrow(TypeError) 45 | expected.toThrow(/1st/) 46 | expected.toThrow(/`addHours`/) 47 | expected.toThrow(/is not defined/) 48 | expected.toThrow(/number is expected/) 49 | }) 50 | 51 | it('should throw an error with a friendly message when the second argument has an unexpected type', () => { 52 | const expected = expect(() => { 53 | addHours(23, {}) 54 | }) 55 | 56 | expected.toThrow(TypeError) 57 | expected.toThrow(/2nd/) 58 | expected.toThrow(/`addHours`/) 59 | expected.toThrow(/unexpected type/) 60 | expected.toThrow(/date is expected/) 61 | }) 62 | 63 | it('should throw an error with a friendly message when the second argument is not defined', () => { 64 | const expected = expect(() => { 65 | addHours(23)(undefined) 66 | }) 67 | 68 | expected.toThrow(TypeError) 69 | expected.toThrow(/2nd/) 70 | expected.toThrow(/`addHours`/) 71 | expected.toThrow(/is not defined/) 72 | expected.toThrow(/date is expected/) 73 | }) 74 | }) 75 | -------------------------------------------------------------------------------- /test/date/add-milliseconds.test.js: -------------------------------------------------------------------------------- 1 | import addMilliseconds from '../../lib/date/add-milliseconds' 2 | 3 | describe('addMilliseconds main functionality', () => { 4 | it('should add milliseconds on a date', () => { 5 | const date = new Date('December 17, 1995 03:24:00') 6 | const actual = addMilliseconds(1000 * 60, date) 7 | const expected = new Date('December 17, 1995 03:25:00') 8 | expect(actual).toEqual(expected) 9 | }) 10 | 11 | it('should remove milliseconds on a date', () => { 12 | const date = new Date('December 17, 1995 03:24:00') 13 | const actual = addMilliseconds(1000 * -60, date) 14 | const expected = new Date('December 17, 1995 03:23:00') 15 | expect(actual).toEqual(expected) 16 | }) 17 | 18 | it('should be curried', () => { 19 | const date = new Date('December 17, 1995 03:24:00') 20 | const actual = addMilliseconds(1000 * 60)(date) 21 | const expected = new Date('December 17, 1995 03:25:00') 22 | expect(actual).toEqual(expected) 23 | }) 24 | }) 25 | 26 | describe('addMilliseconds arguments validation errors', () => { 27 | it('should throw an error with a friendly message when the first argument has an unexpected type', () => { 28 | const expected = expect(() => { 29 | addMilliseconds({}, new Date()) 30 | }) 31 | 32 | expected.toThrow(TypeError) 33 | expected.toThrow(/1st/) 34 | expected.toThrow(/`addMilliseconds`/) 35 | expected.toThrow(/unexpected type/) 36 | expected.toThrow(/number is expected/) 37 | }) 38 | 39 | it('should throw an error with a friendly message when the first argument is not defined', () => { 40 | const expected = expect(() => { 41 | addMilliseconds(undefined, undefined) 42 | }) 43 | 44 | expected.toThrow(TypeError) 45 | expected.toThrow(/1st/) 46 | expected.toThrow(/`addMilliseconds`/) 47 | expected.toThrow(/is not defined/) 48 | expected.toThrow(/number is expected/) 49 | }) 50 | 51 | it('sshould throw an error with a friendly message when the second argument has an unexpected type', () => { 52 | const expected = expect(() => { 53 | addMilliseconds(23, {}) 54 | }) 55 | 56 | expected.toThrow(TypeError) 57 | expected.toThrow(/2nd/) 58 | expected.toThrow(/`addMilliseconds`/) 59 | expected.toThrow(/unexpected type/) 60 | expected.toThrow(/date is expected/) 61 | }) 62 | 63 | it('should throw an error with a friendly message when the second argument is not defined', () => { 64 | const expected = expect(() => { 65 | addMilliseconds(23)(undefined) 66 | }) 67 | 68 | expected.toThrow(TypeError) 69 | expected.toThrow(/2nd/) 70 | expected.toThrow(/`addMilliseconds`/) 71 | expected.toThrow(/is not defined/) 72 | expected.toThrow(/date is expected/) 73 | }) 74 | }) 75 | -------------------------------------------------------------------------------- /test/date/add-minutes.test.js: -------------------------------------------------------------------------------- 1 | import addMinutes from '../../lib/date/add-minutes' 2 | 3 | describe('addMinutes main functionality', () => { 4 | it('should add minutes on a date', () => { 5 | const date = new Date('December 17, 1995 03:24:00') 6 | const actual = addMinutes(60, date) 7 | const expected = new Date('December 17, 1995 04:24:00') 8 | expect(actual).toEqual(expected) 9 | }) 10 | 11 | it('should remove minutes of a date', () => { 12 | const date = new Date('December 17, 1995 03:24:00') 13 | const actual = addMinutes(-60, date) 14 | const expected = new Date('December 17, 1995 02:24:00') 15 | expect(actual).toEqual(expected) 16 | }) 17 | 18 | it('should be curried', () => { 19 | const date = new Date('December 17, 1995 03:24:00') 20 | const actual = addMinutes(60)(date) 21 | const expected = new Date('December 17, 1995 04:24:00') 22 | expect(actual).toEqual(expected) 23 | }) 24 | }) 25 | 26 | describe('addMinutes arguments validation errors', () => { 27 | it('should throw an error with a friendly message when the first argument has an unexpected type', () => { 28 | const expected = expect(() => { 29 | addMinutes({}, new Date()) 30 | }) 31 | 32 | expected.toThrow(TypeError) 33 | expected.toThrow(/1st/) 34 | expected.toThrow(/`addMinutes`/) 35 | expected.toThrow(/unexpected type/) 36 | expected.toThrow(/number is expected/) 37 | }) 38 | 39 | it('should throw an error with a friendly message when the first argument is not defined', () => { 40 | const expected = expect(() => { 41 | addMinutes(undefined, new Date()) 42 | }) 43 | 44 | expected.toThrow(TypeError) 45 | expected.toThrow(/1st/) 46 | expected.toThrow(/`addMinutes`/) 47 | expected.toThrow(/is not defined/) 48 | expected.toThrow(/number is expected/) 49 | }) 50 | 51 | it('should throw an error with a friendly message when the second argument has an unexpected type', () => { 52 | const expected = expect(() => { 53 | addMinutes(23, {}) 54 | }) 55 | 56 | expected.toThrow(TypeError) 57 | expected.toThrow(/2nd/) 58 | expected.toThrow(/`addMinutes`/) 59 | expected.toThrow(/unexpected type/) 60 | expected.toThrow(/date is expected/) 61 | }) 62 | 63 | it('should throw an error with a friendly message when the second argument is not defined', () => { 64 | const expected = expect(() => { 65 | addMinutes(23)(undefined) 66 | }) 67 | 68 | expected.toThrow(TypeError) 69 | expected.toThrow(/2nd/) 70 | expected.toThrow(/`addMinutes`/) 71 | expected.toThrow(/is not defined/) 72 | expected.toThrow(/date is expected/) 73 | }) 74 | }) 75 | -------------------------------------------------------------------------------- /test/date/add-months.test.js: -------------------------------------------------------------------------------- 1 | import addMonths from '../../lib/date/add-months' 2 | 3 | describe('addMonths main functionality', () => { 4 | it('should add months on a date', () => { 5 | const date = new Date('December 17, 1995 03:24:00') 6 | const actual = addMonths(2, date) 7 | const expected = new Date('February 17, 1996 03:24:00') 8 | expect(actual).toEqual(expected) 9 | }) 10 | 11 | it('should remove months of a date', () => { 12 | const date = new Date('December 17, 1995 03:24:00') 13 | const actual = addMonths(-2, date) 14 | const expected = new Date('October 17, 1995 03:24:00') 15 | expect(actual).toEqual(expected) 16 | }) 17 | 18 | it('should be curried', () => { 19 | const date = new Date('December 17, 1995 03:24:00') 20 | const actual = addMonths(2)(date) 21 | const expected = new Date('February 17, 1996 03:24:00') 22 | expect(actual).toEqual(expected) 23 | }) 24 | 25 | it('should go to the last day of the month if the next month doesn\'t have enough days', () => { 26 | const date = new Date('July 31, 1995 03:24:00') 27 | const actual = addMonths(-1, date) 28 | const expected = new Date('June 30, 1995 03:24:00') 29 | expect(actual).toEqual(expected) 30 | }) 31 | 32 | it('should handle 29 February in leap years', () => { 33 | const date = new Date('February 29, 2016 03:24:00') 34 | const actual = addMonths(12, date) 35 | const expected = new Date('February 28, 2017 03:24:00') 36 | expect(actual).toEqual(expected) 37 | }) 38 | }) 39 | 40 | describe('addMonths arguments validation errors', () => { 41 | it('should throw an error with a friendly message when the fist argument has an unexpected type', () => { 42 | const expected = expect(() => { 43 | addMonths({}, new Date()) 44 | }) 45 | 46 | expected.toThrow(TypeError) 47 | expected.toThrow(/1st/) 48 | expected.toThrow(/`addMonths`/) 49 | expected.toThrow(/unexpected type/) 50 | expected.toThrow(/number is expected/) 51 | }) 52 | 53 | it('should throw an error with a friendly message when the first argument is not defined', () => { 54 | const expected = expect(() => { 55 | addMonths(undefined, new Date()) 56 | }) 57 | 58 | expected.toThrow(TypeError) 59 | expected.toThrow(/1st/) 60 | expected.toThrow(/`addMonths`/) 61 | expected.toThrow(/is not defined/) 62 | expected.toThrow(/number is expected/) 63 | }) 64 | 65 | it('should throw an error with a friendly message when the second argument has an unexpected type', () => { 66 | const expected = expect(() => { 67 | addMonths(23, {}) 68 | }) 69 | 70 | expected.toThrow(TypeError) 71 | expected.toThrow(/2nd/) 72 | expected.toThrow(/`addMonths`/) 73 | expected.toThrow(/unexpected type/) 74 | expected.toThrow(/date is expected/) 75 | }) 76 | 77 | it('should throw an error with a friendly message when the second argument is not defined', () => { 78 | const expected = expect(() => { 79 | addMonths(23)(undefined) 80 | }) 81 | 82 | expected.toThrow(TypeError) 83 | expected.toThrow(/2nd/) 84 | expected.toThrow(/`addMonths`/) 85 | expected.toThrow(/is not defined/) 86 | expected.toThrow(/date is expected/) 87 | }) 88 | }) 89 | -------------------------------------------------------------------------------- /test/date/add-seconds.test.js: -------------------------------------------------------------------------------- 1 | import addSeconds from '../../lib/date/add-seconds' 2 | 3 | describe('addSeconds main functionality', () => { 4 | it('should add seconds on a date', () => { 5 | const date = new Date('December 17, 1995 03:24:00') 6 | const actual = addSeconds(60, date) 7 | const expected = new Date('December 17, 1995 03:25:00') 8 | expect(actual).toEqual(expected) 9 | }) 10 | 11 | it('should remove seconds of a date', () => { 12 | const date = new Date('December 17, 1995 03:24:00') 13 | const actual = addSeconds(-60, date) 14 | const expected = new Date('December 17, 1995 03:23:00') 15 | expect(actual).toEqual(expected) 16 | }) 17 | 18 | it('should be curried', () => { 19 | const date = new Date('December 17, 1995 03:24:00') 20 | const actual = addSeconds(60)(date) 21 | const expected = new Date('December 17, 1995 03:25:00') 22 | expect(actual).toEqual(expected) 23 | }) 24 | }) 25 | 26 | describe('addSeconds arguments validation errors', () => { 27 | it('should throw an error with a friendly message whe the first argument has an unexpected type', () => { 28 | const expected = expect(() => { 29 | addSeconds({}, new Date()) 30 | }) 31 | 32 | expected.toThrow(TypeError) 33 | expected.toThrow(/1st/) 34 | expected.toThrow(/`addSeconds`/) 35 | expected.toThrow(/unexpected type/) 36 | expected.toThrow(/number is expected/) 37 | }) 38 | 39 | it('should throw an error with a friendly message when the first argument is not defined', () => { 40 | const expected = expect(() => { 41 | addSeconds(undefined, new Date()) 42 | }) 43 | 44 | expected.toThrow(TypeError) 45 | expected.toThrow(/1st/) 46 | expected.toThrow(/`addSeconds`/) 47 | expected.toThrow(/is not defined/) 48 | expected.toThrow(/number is expected/) 49 | }) 50 | 51 | it('should throw an error with a friendly message when the second argument has an unexpected type', () => { 52 | const expected = expect(() => { 53 | addSeconds(23, {}) 54 | }) 55 | 56 | expected.toThrow(TypeError) 57 | expected.toThrow(/2nd/) 58 | expected.toThrow(/`addSeconds`/) 59 | expected.toThrow(/unexpected type/) 60 | expected.toThrow(/date is expected/) 61 | }) 62 | 63 | it('should throw an error with a friendly message when the second argument is not defined', () => { 64 | const expected = expect(() => { 65 | addSeconds(23)(undefined) 66 | }) 67 | 68 | expected.toThrow(TypeError) 69 | expected.toThrow(/2nd/) 70 | expected.toThrow(/`addSeconds`/) 71 | expected.toThrow(/is not defined/) 72 | expected.toThrow(/date is expected/) 73 | }) 74 | }) 75 | -------------------------------------------------------------------------------- /test/date/add-weeks.test.js: -------------------------------------------------------------------------------- 1 | import addWeeks from '../../lib/date/add-weeks' 2 | 3 | describe('addWeeks main functionality', () => { 4 | it('should add weeks on a date', () => { 5 | const date = new Date('December 17, 1995 03:24:00') 6 | const actual = addWeeks(2, date) 7 | const expected = new Date('December 31, 1995 03:24:00') 8 | expect(actual).toEqual(expected) 9 | }) 10 | 11 | it('should remove weeks of a date', () => { 12 | const date = new Date('December 17, 1995 03:24:00') 13 | const actual = addWeeks(-2, date) 14 | const expected = new Date('December 03, 1995 03:24:00') 15 | expect(actual).toEqual(expected) 16 | }) 17 | 18 | it('should be curried', () => { 19 | const date = new Date('December 17, 1995 03:24:00') 20 | const actual = addWeeks(2)(date) 21 | const expected = new Date('December 31, 1995 03:24:00') 22 | expect(actual).toEqual(expected) 23 | }) 24 | }) 25 | 26 | describe('addWeeks arguments validation errors', () => { 27 | it('should throw an error with a friendly message when the first argument has an unexpected type', () => { 28 | const expected = expect(() => { 29 | addWeeks({}, new Date()) 30 | }) 31 | 32 | expected.toThrow(TypeError) 33 | expected.toThrow(/1st/) 34 | expected.toThrow(/`addWeeks`/) 35 | expected.toThrow(/unexpected type/) 36 | expected.toThrow(/number is expected/) 37 | }) 38 | 39 | it('should throw an error with a friendly message when the first argument is not defined', () => { 40 | const expected = expect(() => { 41 | addWeeks(undefined, new Date()) 42 | }) 43 | 44 | expected.toThrow(TypeError) 45 | expected.toThrow(/1st/) 46 | expected.toThrow(/`addWeeks`/) 47 | expected.toThrow(/is not defined/) 48 | expected.toThrow(/number is expected/) 49 | }) 50 | 51 | it('should throw an error with a friendly message when the second argument has an unexpected type', () => { 52 | const expected = expect(() => { 53 | addWeeks(23, {}) 54 | }) 55 | 56 | expected.toThrow(TypeError) 57 | expected.toThrow(/2nd/) 58 | expected.toThrow(/`addWeeks`/) 59 | expected.toThrow(/unexpected type/) 60 | expected.toThrow(/date is expected/) 61 | }) 62 | 63 | it('should throw an error with a friendly message when the second argument is not defined', () => { 64 | const expected = expect(() => { 65 | addWeeks(23)(undefined) 66 | }) 67 | 68 | expected.toThrow(TypeError) 69 | expected.toThrow(/2nd/) 70 | expected.toThrow(/`addWeeks`/) 71 | expected.toThrow(/is not defined/) 72 | expected.toThrow(/date is expected/) 73 | }) 74 | }) 75 | -------------------------------------------------------------------------------- /test/date/add-years.test.js: -------------------------------------------------------------------------------- 1 | import addYears from '../../lib/date/add-years' 2 | 3 | describe('addYears main functionality', () => { 4 | it('should add years on a date', () => { 5 | const date = new Date('December 17, 1995 03:24:00') 6 | const actual = addYears(2, date) 7 | const expected = new Date('December 17, 1997 03:24:00') 8 | expect(actual).toEqual(expected) 9 | }) 10 | 11 | it('should remove years of a date', () => { 12 | const date = new Date('December 17, 1995 03:24:00') 13 | const actual = addYears(-2, date) 14 | const expected = new Date('December 17, 1993 03:24:00') 15 | expect(actual).toEqual(expected) 16 | }) 17 | 18 | it('should be curried', () => { 19 | const date = new Date('December 17, 1995 03:24:00') 20 | const actual = addYears(2)(date) 21 | const expected = new Date('December 17, 1997 03:24:00') 22 | expect(actual).toEqual(expected) 23 | }) 24 | 25 | it('should handle 29 February in leap years', () => { 26 | const date = new Date('February 29, 2016 03:24:00') 27 | const actual = addYears(1, date) 28 | const expected = new Date('February 28, 2017 03:24:00') 29 | expect(actual.getTime()).toBe(expected.getTime()) 30 | }) 31 | }) 32 | 33 | describe('addYears arguments validation errors', () => { 34 | it('should throw an error with a friendly message when the first argument has an unexpected type', () => { 35 | const expected = expect(() => { 36 | addYears({}, new Date()) 37 | }) 38 | 39 | expected.toThrow(TypeError) 40 | expected.toThrow(/1st/) 41 | expected.toThrow(/`addYears`/) 42 | expected.toThrow(/unexpected type/) 43 | expected.toThrow(/number is expected/) 44 | }) 45 | 46 | it('should throw an error with a friendly message when the first argument is not defined', () => { 47 | const expected = expect(() => { 48 | addYears(undefined, new Date()) 49 | }) 50 | 51 | expected.toThrow(TypeError) 52 | expected.toThrow(/1st/) 53 | expected.toThrow(/`addYears`/) 54 | expected.toThrow(/is not defined/) 55 | expected.toThrow(/number is expected/) 56 | }) 57 | 58 | it('should throw an error with a friendly message when the second argument has an unexpected type', () => { 59 | const expected = expect(() => { 60 | addYears(23, {}) 61 | }) 62 | 63 | expected.toThrow(TypeError) 64 | expected.toThrow(/2nd/) 65 | expected.toThrow(/`addYears`/) 66 | expected.toThrow(/unexpected type/) 67 | expected.toThrow(/date is expected/) 68 | }) 69 | 70 | it('should throw an error with a friendly message when the second argument is not defined', () => { 71 | const expected = expect(() => { 72 | addYears(23)(undefined) 73 | }) 74 | 75 | expected.toThrow(TypeError) 76 | expected.toThrow(/2nd/) 77 | expected.toThrow(/`addYears`/) 78 | expected.toThrow(/is not defined/) 79 | expected.toThrow(/date is expected/) 80 | }) 81 | }) 82 | -------------------------------------------------------------------------------- /test/date/diff-date.test.js: -------------------------------------------------------------------------------- 1 | import diffDate from '../../lib/date/diff-date' 2 | 3 | describe('diffDate main functionality', () => { 4 | it('should show the diff of two dates', () => { 5 | const firstDate = new Date('December 17, 1995 03:24:00') 6 | const secondDate = new Date('December 17, 1996 03:25:00') 7 | const actual = diffDate(firstDate, secondDate) 8 | const expected = { 9 | milliseconds: 31622460000, 10 | seconds: 31622460, 11 | minutes: 527041, 12 | hours: 8784.02, 13 | days: 366, 14 | weeks: 52.29, 15 | months: 12.2, 16 | years: 1 17 | } 18 | expect(actual).toEqual(expected) 19 | }) 20 | 21 | it('should be curried', () => { 22 | const firstDate = new Date('December 17, 1995 03:24:00') 23 | const secondDate = new Date('December 17, 1996 03:25:00') 24 | const actual = diffDate(firstDate)(secondDate) 25 | const expected = { 26 | milliseconds: 31622460000, 27 | seconds: 31622460, 28 | minutes: 527041, 29 | hours: 8784.02, 30 | days: 366, 31 | weeks: 52.29, 32 | months: 12.2, 33 | years: 1 34 | } 35 | expect(actual).toEqual(expected) 36 | }) 37 | }) 38 | 39 | describe('diffDate arguments validation errors', () => { 40 | it('should throw an error with a friendly message when the first argument has an unexpected type', () => { 41 | const expected = expect(() => { 42 | diffDate({}, new Date()) 43 | }) 44 | 45 | expected.toThrow(TypeError) 46 | expected.toThrow(/1st/) 47 | expected.toThrow(/`diffDate`/) 48 | expected.toThrow(/unexpected type/) 49 | expected.toThrow(/date is expected/) 50 | }) 51 | 52 | it('should throw an error with a friendly message when the first argument is not defined', () => { 53 | const expected = expect(() => { 54 | diffDate(undefined, new Date()) 55 | }) 56 | 57 | expected.toThrow(TypeError) 58 | expected.toThrow(/1st/) 59 | expected.toThrow(/`diffDate`/) 60 | expected.toThrow(/is not defined/) 61 | expected.toThrow(/date is expected/) 62 | }) 63 | 64 | it('should throw an error with a friendly message when the second argument has an unexpected type', () => { 65 | const expected = expect(() => { 66 | diffDate(new Date(), {}) 67 | }) 68 | 69 | expected.toThrow(TypeError) 70 | expected.toThrow(/2nd/) 71 | expected.toThrow(/`diffDate`/) 72 | expected.toThrow(/unexpected type/) 73 | expected.toThrow(/date is expected/) 74 | }) 75 | 76 | it('should throw an error with a friendly message when the second argument is not defined', () => { 77 | const expected = expect(() => { 78 | diffDate(new Date())(undefined) 79 | }) 80 | 81 | expected.toThrow(TypeError) 82 | expected.toThrow(/2nd/) 83 | expected.toThrow(/`diffDate`/) 84 | expected.toThrow(/is not defined/) 85 | expected.toThrow(/date is expected/) 86 | }) 87 | }) 88 | -------------------------------------------------------------------------------- /test/date/format-date.test.js: -------------------------------------------------------------------------------- 1 | import formatDate from '../../lib/date/format-date' 2 | 3 | describe('formatDate main functionality', () => { 4 | it('should format a date', () => { 5 | const date = new Date('December 17, 1995 03:24:00') 6 | const format = '{DD}/{MM}/{YYYY} {HH}:{mm}:{ss}:{ms}' 7 | const actual = formatDate(format, date) 8 | const expected = '17/12/1995 03:24:00:00' 9 | expect(actual).toBe(expected) 10 | }) 11 | 12 | it('should be curried', () => { 13 | const date = new Date('December 17, 1995 03:24:00') 14 | const format = '{DD}/{MM}/{YYYY} {HH}:{mm}:{ss}:{ms}' 15 | const actual = formatDate(format)(date) 16 | const expected = '17/12/1995 03:24:00:00' 17 | expect(actual).toBe(expected) 18 | }) 19 | 20 | it('should work with short year', () => { 21 | const date = new Date('December 17, 2017 03:24:00') 22 | const format = '{DD}/{MM}/{YY} {HH}:{mm}:{ss}:{ms}' 23 | const actual = formatDate(format)(date) 24 | const expected = '17/12/17 03:24:00:00' 25 | expect(actual).toBe(expected) 26 | }) 27 | }) 28 | 29 | describe('formatDate arguments validation errors', () => { 30 | it('should throw an error with a friendly message when the first argument has an unexpected type', () => { 31 | const expected = expect(() => { 32 | formatDate({})(new Date()) 33 | }) 34 | 35 | expected.toThrow(TypeError) 36 | expected.toThrow(/1st/) 37 | expected.toThrow(/`formatDate`/) 38 | expected.toThrow(/unexpected type/) 39 | expected.toThrow(/string is expected/) 40 | }) 41 | 42 | it('should throw an error with a friendly message when the first argument is not defined', () => { 43 | const expected = expect(() => { 44 | formatDate(undefined)(new Date()) 45 | }) 46 | 47 | expected.toThrow(TypeError) 48 | expected.toThrow(/1st/) 49 | expected.toThrow(/`formatDate`/) 50 | expected.toThrow(/is not defined/) 51 | expected.toThrow(/string is expected/) 52 | }) 53 | 54 | it('should throw an error with a friendly message when the second argument has an unexpected type', () => { 55 | const expected = expect(() => { 56 | formatDate('{YYYY}')({}) 57 | }) 58 | 59 | expected.toThrow(TypeError) 60 | expected.toThrow(/2nd/) 61 | expected.toThrow(/`formatDate`/) 62 | expected.toThrow(/unexpected type/) 63 | expected.toThrow(/date is expected/) 64 | }) 65 | 66 | it('should throw an error with a friendly message when the second argument is not defined', () => { 67 | const expected = expect(() => { 68 | formatDate('{YYYY}')(undefined) 69 | }) 70 | 71 | expected.toThrow(TypeError) 72 | expected.toThrow(/2nd/) 73 | expected.toThrow(/`formatDate`/) 74 | expected.toThrow(/is not defined/) 75 | expected.toThrow(/date is expected/) 76 | }) 77 | }) 78 | -------------------------------------------------------------------------------- /test/date/is-valid-date.test.js: -------------------------------------------------------------------------------- 1 | import isValidDate from '../../lib/date/is-valid-date' 2 | 3 | describe('isValidDate main functionality', () => { 4 | it('should return true if the date is valid', () => { 5 | const dateStr = '17/12/1995 03:24:00' 6 | const format = '{DD}/{MM}/{YYYY} {HH}:{mm}:{ss}' 7 | const actual = isValidDate(format, dateStr) 8 | expect(actual).toBe(true) 9 | }) 10 | 11 | it('should return false if the date is not valid', () => { 12 | const dateStr = '29/02/1995 03:24:00' 13 | const format = '{DD}/{MM}/{YYYY} {HH}:{mm}:{ss}' 14 | const actual = isValidDate(format, dateStr) 15 | expect(actual).toBe(false) 16 | }) 17 | 18 | it('should be curried', () => { 19 | const dateStr = '17/12/1995 03:24:00' 20 | const format = '{DD}/{MM}/{YYYY} {HH}:{mm}:{ss}' 21 | const actual = isValidDate(format)(dateStr) 22 | expect(actual).toBe(true) 23 | }) 24 | }) 25 | 26 | describe('isValidDate arguments validation errors', () => { 27 | it('should throw an error with a friendly message when the first argument has an unexpected type', () => { 28 | const expected = expect(() => { 29 | isValidDate({})(new Date()) 30 | }) 31 | 32 | expected.toThrow(TypeError) 33 | expected.toThrow(/1st/) 34 | expected.toThrow(/`isValidDate`/) 35 | expected.toThrow(/unexpected type/) 36 | expected.toThrow(/string is expected/) 37 | }) 38 | 39 | it('should throw an error with a friendly message when the first argument is not defined', () => { 40 | const expected = expect(() => { 41 | isValidDate(undefined)(new Date()) 42 | }) 43 | 44 | expected.toThrow(TypeError) 45 | expected.toThrow(/1st/) 46 | expected.toThrow(/`isValidDate`/) 47 | expected.toThrow(/is not defined/) 48 | expected.toThrow(/string is expected/) 49 | }) 50 | 51 | it('should throw an error with a friendly message when the second argument has an unexpected type', () => { 52 | const expected = expect(() => { 53 | isValidDate('{YYYY}')({}) 54 | }) 55 | 56 | expected.toThrow(TypeError) 57 | expected.toThrow(/2nd/) 58 | expected.toThrow(/`isValidDate`/) 59 | expected.toThrow(/unexpected type/) 60 | expected.toThrow(/string is expected/) 61 | }) 62 | 63 | it('should throw an error with a friendly message when the second argument is not defined', () => { 64 | const expected = expect(() => { 65 | isValidDate('{YYYY}')(undefined) 66 | }) 67 | 68 | expected.toThrow(TypeError) 69 | expected.toThrow(/2nd/) 70 | expected.toThrow(/`isValidDate`/) 71 | expected.toThrow(/is not defined/) 72 | expected.toThrow(/string is expected/) 73 | }) 74 | }) 75 | -------------------------------------------------------------------------------- /test/date/parse-date.test.js: -------------------------------------------------------------------------------- 1 | import parseDate from '../../lib/date/parse-date' 2 | 3 | describe('parseDate main functionality', () => { 4 | it('should parse a date', () => { 5 | const dateStr = '17/12/1995 03:24:00' 6 | const format = '{DD}/{MM}/{YYYY} {HH}:{mm}:{ss}:{ms}' 7 | const actual = parseDate(format, dateStr) 8 | const expected = new Date('December 17, 1995 03:24:00') 9 | expect(actual).toEqual(expected) 10 | }) 11 | 12 | it('should be curried', () => { 13 | const dateStr = '17/12/1995 03:24:00' 14 | const format = '{DD}/{MM}/{YYYY} {HH}:{mm}:{ss}:{ms}' 15 | const actual = parseDate(format)(dateStr) 16 | const expected = new Date('December 17, 1995 03:24:00') 17 | expect(actual).toEqual(expected) 18 | }) 19 | 20 | it('should handle short year formats of 20th century', () => { 21 | const dateStr = '17/12/89 03:24:00' 22 | const format = '{DD}/{MM}/{YY} {HH}:{mm}:{ss}:{ms}' 23 | const actual = parseDate(format)(dateStr) 24 | const expected = new Date('December 17, 1989 03:24:00') 25 | expect(actual).toEqual(expected) 26 | }) 27 | 28 | it('should handle short year formats of 21st century', () => { 29 | const dateStr = '17/12/17 03:24:00' 30 | const format = '{DD}/{MM}/{YY} {HH}:{mm}:{ss}:{ms}' 31 | const actual = parseDate(format)(dateStr) 32 | const expected = new Date('December 17, 2017 03:24:00') 33 | expect(actual).toEqual(expected) 34 | }) 35 | }) 36 | 37 | describe('parseDate arguments validation errors', () => { 38 | it('should throw an error with a friendly message has an unexpected type', () => { 39 | const expected = expect(() => { 40 | parseDate({})(new Date()) 41 | }) 42 | 43 | expected.toThrow(TypeError) 44 | expected.toThrow(/1st/) 45 | expected.toThrow(/`parseDate`/) 46 | expected.toThrow(/unexpected type/) 47 | expected.toThrow(/string is expected/) 48 | }) 49 | 50 | it('should throw an error with a friendly message when the first argument is not defined', () => { 51 | const expected = expect(() => { 52 | parseDate(undefined)(new Date()) 53 | }) 54 | 55 | expected.toThrow(TypeError) 56 | expected.toThrow(/1st/) 57 | expected.toThrow(/`parseDate`/) 58 | expected.toThrow(/is not defined/) 59 | expected.toThrow(/string is expected/) 60 | }) 61 | 62 | it('should throw an error with a friendly message when the second argument has an unexpected type', () => { 63 | const expected = expect(() => { 64 | parseDate('{YYYY}')({}) 65 | }) 66 | 67 | expected.toThrow(TypeError) 68 | expected.toThrow(/2nd/) 69 | expected.toThrow(/`parseDate`/) 70 | expected.toThrow(/unexpected type/) 71 | expected.toThrow(/string is expected/) 72 | }) 73 | 74 | it('should throw an error with a friendly message when the second argument is not defined', () => { 75 | const expected = expect(() => { 76 | parseDate('{YYYY}')(undefined) 77 | }) 78 | 79 | expected.toThrow(TypeError) 80 | expected.toThrow(/2nd/) 81 | expected.toThrow(/`parseDate`/) 82 | expected.toThrow(/is not defined/) 83 | expected.toThrow(/string is expected/) 84 | }) 85 | }) 86 | -------------------------------------------------------------------------------- /test/element/add-class.test.js: -------------------------------------------------------------------------------- 1 | import addClass from '../../lib/element/add-class' 2 | 3 | describe('addClass main functionality', () => { 4 | it('should add a class to a DOM element', () => { 5 | const element = document.createElement('div') 6 | addClass('hey', element) 7 | expect(element.className).toBe('hey') 8 | addClass('there', element) 9 | expect(element.className).toBe('hey there') 10 | }) 11 | 12 | it('should return the element', () => { 13 | const actual = document.createElement('div') 14 | const expected = addClass('hey', actual) 15 | expect(expected).toEqual(expected) 16 | }) 17 | 18 | it('should be curried', () => { 19 | const element = document.createElement('div') 20 | addClass('hey')(element) 21 | expect(element.className).toBe('hey') 22 | }) 23 | 24 | it('should accept an array of classes', () => { 25 | const element = document.createElement('div') 26 | addClass(['hey', 'there'])(element) 27 | expect(element.className).toBe('hey there') 28 | }) 29 | 30 | it('should work with prefix classes', () => { 31 | const element = document.createElement('div') 32 | element.className = 'table' 33 | addClass(['table-hover', 'table-inverse'])(element) 34 | expect(element.className).toBe('table table-hover table-inverse') 35 | }) 36 | 37 | it('should not add a class multiple time', () => { 38 | const element = document.createElement('div') 39 | element.className = 'hey' 40 | addClass('there', element) 41 | addClass('there', element) 42 | expect(element.className).toBe('hey there') 43 | }) 44 | }) 45 | 46 | describe('addClass arguments validation errors', () => { 47 | it('should throw an error with a friendly message when the first argument has an unexpected type', () => { 48 | const expected = expect(() => { 49 | addClass({}, document.createElement('div')) 50 | }) 51 | 52 | expected.toThrow(TypeError) 53 | expected.toThrow(/1st/) 54 | expected.toThrow(/`addClass`/) 55 | expected.toThrow(/unexpected type/) 56 | expected.toThrow(/string or array is expected/) 57 | }) 58 | 59 | it('should throw an error with a friendly message when the first argument is not defined', () => { 60 | const expected = expect(() => { 61 | addClass(undefined, document.createElement('div')) 62 | }) 63 | 64 | expected.toThrow(TypeError) 65 | expected.toThrow(/1st/) 66 | expected.toThrow(/`addClass`/) 67 | expected.toThrow(/is not defined/) 68 | expected.toThrow(/string or array is expected/) 69 | }) 70 | 71 | it('should throw an error with a friendly message when the second argument has an unexpected type', () => { 72 | const expected = expect(() => { 73 | addClass('hey', 42) 74 | }) 75 | 76 | expected.toThrow(TypeError) 77 | expected.toThrow(/2nd/) 78 | expected.toThrow(/`addClass`/) 79 | expected.toThrow(/unexpected type/) 80 | expected.toThrow(/element is expected/) 81 | }) 82 | 83 | it('should throw an error with a friendly message when the second argument is not defined', () => { 84 | const expected = expect(() => { 85 | addClass('hey', undefined) 86 | }) 87 | 88 | expected.toThrow(TypeError) 89 | expected.toThrow(/2nd/) 90 | expected.toThrow(/`addClass`/) 91 | expected.toThrow(/is not defined/) 92 | expected.toThrow(/element is expected/) 93 | }) 94 | }) 95 | -------------------------------------------------------------------------------- /test/element/clear-events.test.js: -------------------------------------------------------------------------------- 1 | import clearEvents from '../../lib/element/clear-events' 2 | 3 | describe('clearEvents main functionality', () => { 4 | it('should clear the events of a element', () => { 5 | const handleClick = jest.fn() 6 | const handleFocus = jest.fn() 7 | 8 | const parent = document.createElement('div') 9 | 10 | const element = document.createElement('div') 11 | element.id = 'element' 12 | 13 | parent.appendChild(element) 14 | 15 | element.addEventListener('click', handleClick) 16 | element.addEventListener('focus', handleFocus) 17 | 18 | const clickEvent = new Event('click') 19 | const focusEvent = new Event('focus') 20 | 21 | parent.children[0].dispatchEvent(clickEvent) 22 | parent.children[0].dispatchEvent(focusEvent) 23 | 24 | expect(handleClick.mock.calls.length).toBe(1) 25 | expect(handleFocus.mock.calls.length).toBe(1) 26 | 27 | clearEvents(element) 28 | 29 | parent.children[0].dispatchEvent(clickEvent) 30 | parent.children[0].dispatchEvent(focusEvent) 31 | 32 | expect(handleClick.mock.calls.length).toBe(1) 33 | expect(handleFocus.mock.calls.length).toBe(1) 34 | }) 35 | 36 | it('should return the element of which the events will be cleared', () => { 37 | const element = document.createElement('div') 38 | element.id = 'element' 39 | 40 | expect(clearEvents(element)).toEqual(element) 41 | }) 42 | 43 | it('should clear the events of the children of the element', () => { 44 | const handleClick = jest.fn() 45 | const clickEvent = new Event('click') 46 | 47 | const parent = document.createElement('div') 48 | parent.id = 'parent' 49 | 50 | const child = document.createElement('div') 51 | child.id = 'child' 52 | child.addEventListener('click', handleClick) 53 | parent.appendChild(child) 54 | 55 | const elementCleared = clearEvents(parent) 56 | 57 | elementCleared.children[0].dispatchEvent(clickEvent) 58 | 59 | expect(handleClick.mock.calls.length).toBe(0) 60 | }) 61 | }) 62 | 63 | describe('clearEvents arguments validation errors', () => { 64 | it('should throw an error with a friendly message when the first argument has an unexpected type', () => { 65 | const expected = expect(() => { 66 | clearEvents({}) 67 | }) 68 | 69 | expected.toThrow(TypeError) 70 | expected.toThrow(/1st/) 71 | expected.toThrow(/`clearEvents`/) 72 | expected.toThrow(/unexpected type/) 73 | expected.toThrow(/element is expected/) 74 | }) 75 | 76 | it('should throw an error with a friendly message when the first argument is not defined', () => { 77 | const expected = expect(() => { 78 | clearEvents(undefined) 79 | }) 80 | 81 | expected.toThrow(TypeError) 82 | expected.toThrow(/1st/) 83 | expected.toThrow(/`clearEvents`/) 84 | expected.toThrow(/is not defined/) 85 | expected.toThrow(/element is expected/) 86 | }) 87 | }) 88 | -------------------------------------------------------------------------------- /test/element/create-element.test.js: -------------------------------------------------------------------------------- 1 | import createElement from '../../lib/element/create-element' 2 | 3 | describe('createElement main functionality', () => { 4 | it('should create an element', () => { 5 | const actual = createElement() 6 | const expected = document.createElement('div') 7 | 8 | expect(actual).toEqual(expected) 9 | }) 10 | 11 | it('should create an span element', () => { 12 | const actual = createElement('span') 13 | const expected = document.createElement('span') 14 | 15 | expect(actual).toEqual(expected) 16 | }) 17 | 18 | it('should create an div with an id', () => { 19 | const actual = createElement('#id') 20 | const expected = document.createElement('div') 21 | expected.id = 'id' 22 | 23 | expect(actual).toEqual(expected) 24 | }) 25 | 26 | it('should create an div with an class', () => { 27 | const actual = createElement('.class') 28 | const expected = document.createElement('div') 29 | expected.className = 'class' 30 | 31 | expect(actual).toEqual(expected) 32 | }) 33 | 34 | it('should create an div with an attribute', () => { 35 | const actual = createElement('[data-custom=hey]') 36 | const expected = document.createElement('div') 37 | expected.setAttribute('data-custom', 'hey') 38 | 39 | expect(actual).toEqual(expected) 40 | }) 41 | 42 | it('should create an div with an attribute with quotes', () => { 43 | const actual = createElement('[data-custom="hey"][data-change=\'there\']') 44 | const expected = document.createElement('div') 45 | expected.setAttribute('data-custom', 'hey') 46 | expected.setAttribute('data-change', 'there') 47 | 48 | expect(actual).toEqual(expected) 49 | }) 50 | 51 | it('should create an input with boolean attributes', () => { 52 | const actual = createElement('input[disabled="hey"][required]') 53 | const expected = document.createElement('input') 54 | expected.setAttribute('disabled', '') 55 | expected.setAttribute('required', '') 56 | 57 | expect(actual).toEqual(expected) 58 | }) 59 | 60 | it('should create an element using css selectors', () => { 61 | const actual = createElement( 62 | 'input#id.class1.class2[type=text][placeholder=hey]' 63 | ) 64 | const expected = document.createElement('input') 65 | expected.id = 'id' 66 | expected.className = 'class1 class2' 67 | expected.type = 'text' 68 | expected.placeholder = 'hey' 69 | 70 | expect(actual).toEqual(expected) 71 | }) 72 | 73 | it('should work with data props', () => { 74 | const actual = createElement('div', { 75 | data: { 76 | ref: 'hey', 77 | error: 'bad' 78 | } 79 | }) 80 | 81 | const expected = document.createElement('div') 82 | expected.setAttribute('data-ref', 'hey') 83 | expected.setAttribute('data-error', 'bad') 84 | 85 | expect(actual).toEqual(expected) 86 | }) 87 | 88 | it('should work with class props', () => { 89 | const actual = createElement('.test', { 90 | className: 'hey there man' 91 | }) 92 | 93 | const expected = document.createElement('div') 94 | expected.className = 'test hey there man' 95 | 96 | expect(actual).toEqual(expected) 97 | }) 98 | 99 | it('should work with boolean attributes props', () => { 100 | const actual = createElement('div', { 101 | required: false, 102 | checked: null, 103 | readonly: 1 104 | }) 105 | 106 | const expected = document.createElement('div') 107 | expected.setAttribute('readonly', '') 108 | 109 | expect(actual).toEqual(expected) 110 | }) 111 | 112 | it('should work with events props', () => { 113 | const handleClick = jest.fn() 114 | 115 | const clickEvent = new Event('click') 116 | 117 | const actual = createElement('div', { 118 | onclick: handleClick 119 | }) 120 | 121 | actual.dispatchEvent(clickEvent) 122 | 123 | expect(handleClick.mock.calls.length).toBe(1) 124 | }) 125 | 126 | it('should support external event listeners', () => { 127 | const handleClick1 = jest.fn() 128 | const handleClick2 = jest.fn() 129 | 130 | const clickEvent = new Event('click') 131 | 132 | const actual = createElement('div', {onclick: handleClick1}) 133 | actual.addEventListener('click', handleClick2) 134 | 135 | actual.dispatchEvent(clickEvent) 136 | 137 | expect(handleClick1.mock.calls.length).toBe(1) 138 | expect(handleClick2.mock.calls.length).toBe(1) 139 | }) 140 | 141 | it('should work with attributes props', () => { 142 | const actual = createElement('input', { 143 | type: 'text' 144 | }) 145 | 146 | const expected = document.createElement('input') 147 | expected.type = 'text' 148 | 149 | expect(actual).toEqual(expected) 150 | }) 151 | 152 | it('should add text to a element', () => { 153 | const actual = createElement('p', {}, 'hey man') 154 | const expected = document.createElement('p') 155 | expected.textContent = 'hey man' 156 | 157 | expect(actual).toEqual(expected) 158 | }) 159 | 160 | it('should add a child to a element', () => { 161 | const actual = createElement('div', {}, createElement()) 162 | const expected = document.createElement('div') 163 | expected.appendChild(document.createElement('div')) 164 | 165 | expect(actual).toEqual(expected) 166 | }) 167 | 168 | it('should add children to element', () => { 169 | const actual = createElement('div', {}, [ 170 | createElement('input'), 171 | 'hey', 172 | createElement('img') 173 | ]) 174 | 175 | const expected = document.createElement('div') 176 | expected.appendChild(document.createElement('input')) 177 | expected.appendChild(document.createTextNode('hey')) 178 | expected.appendChild(document.createElement('img')) 179 | 180 | expect(actual).toEqual(expected) 181 | }) 182 | 183 | it('should innerHTML the string passed', () => { 184 | const actual = createElement( 185 | 'div', 186 | { 187 | inner: '
' 188 | }, 189 | [createElement('input'), 'hey', createElement('img')] 190 | ) 191 | 192 | const expected = document.createElement('div') 193 | expected.appendChild(document.createElement('br')) 194 | expected.appendChild(document.createElement('input')) 195 | expected.appendChild(document.createTextNode('hey')) 196 | expected.appendChild(document.createElement('img')) 197 | 198 | expect(actual).toEqual(expected) 199 | }) 200 | }) 201 | 202 | describe('createElement method overloading', () => { 203 | it('should accept text as second argument', () => { 204 | const actual = createElement('div', 'hey') 205 | const expected = document.createElement('div') 206 | expected.textContent = 'hey' 207 | 208 | expect(actual).toEqual(expected) 209 | }) 210 | 211 | it('should accept an element as second argument', () => { 212 | const actual = createElement('div', document.createElement('h1')) 213 | const expected = document.createElement('div') 214 | expected.appendChild(document.createElement('h1')) 215 | 216 | expect(actual).toEqual(expected) 217 | }) 218 | 219 | it('should accept children as second argument', () => { 220 | const actual = createElement('div', [ 221 | document.createElement('h1'), 222 | document.createElement('h2') 223 | ]) 224 | const expected = document.createElement('div') 225 | expected.appendChild(document.createElement('h1')) 226 | expected.appendChild(document.createElement('h2')) 227 | 228 | expect(actual).toEqual(expected) 229 | }) 230 | 231 | it('should accept props as second argument', () => { 232 | const actual = createElement('div', {}) 233 | const expected = document.createElement('div') 234 | 235 | expect(actual).toEqual(expected) 236 | }) 237 | }) 238 | 239 | describe('createElement arguments validation errors', () => { 240 | it('should throw an error with a friendly message when the first argument has an unexpected type', () => { 241 | const expected = expect(() => { 242 | createElement({}) 243 | }) 244 | 245 | expected.toThrow(TypeError) 246 | expected.toThrow(/1st/) 247 | expected.toThrow(/`createElement`/) 248 | expected.toThrow(/unexpected type/) 249 | expected.toThrow(/string is expected/) 250 | }) 251 | 252 | it('should throw an error with a friendly message when the third argument has an unexpected type', () => { 253 | const expected = expect(() => { 254 | createElement('', {}, {}) 255 | }) 256 | 257 | expected.toThrow(TypeError) 258 | expected.toThrow(/3rd/) 259 | expected.toThrow(/`createElement`/) 260 | expected.toThrow(/unexpected type/) 261 | expected.toThrow(/string or element or array is expected/) 262 | }) 263 | }) 264 | -------------------------------------------------------------------------------- /test/element/get-parents.test.js: -------------------------------------------------------------------------------- 1 | import getParents from '../../lib/element/get-parents' 2 | 3 | describe('getParents main functionality', () => { 4 | it('should return the parents of a element, including the body', () => { 5 | const parent1 = document.createElement('div') 6 | parent1.id = 'parent1' 7 | 8 | const parent2 = document.createElement('div') 9 | parent2.id = 'parent2' 10 | 11 | const parent3 = document.createElement('div') 12 | parent3.id = 'parent3' 13 | 14 | const parent4 = document.createElement('div') 15 | parent4.id = 'parent4' 16 | 17 | const child = document.createElement('div') 18 | child.id = 'child' 19 | 20 | document.body.appendChild(parent1) 21 | parent1.appendChild(parent2) 22 | parent2.appendChild(parent3) 23 | parent3.appendChild(parent4) 24 | parent4.appendChild(child) 25 | 26 | const actual = getParents(child) 27 | const expected = [parent4, parent3, parent2, parent1, document.body] 28 | 29 | expect(actual).toEqual(expected) 30 | }) 31 | 32 | it('should return the parents of a element not in the dom', () => { 33 | const parent1 = document.createElement('div') 34 | parent1.id = 'parent1' 35 | 36 | const parent2 = document.createElement('div') 37 | parent2.id = 'parent2' 38 | 39 | const parent3 = document.createElement('div') 40 | parent3.id = 'parent3' 41 | 42 | const parent4 = document.createElement('div') 43 | parent4.id = 'parent4' 44 | 45 | const child = document.createElement('div') 46 | child.id = 'child' 47 | 48 | parent1.appendChild(parent2) 49 | parent2.appendChild(parent3) 50 | parent3.appendChild(parent4) 51 | parent4.appendChild(child) 52 | 53 | const actual = getParents(child) 54 | const expected = [parent4, parent3, parent2, parent1] 55 | 56 | expect(actual).toEqual(expected) 57 | }) 58 | }) 59 | 60 | describe('getParents arguments validation errors', () => { 61 | it('should throw an error with a friendly message when the first argument has an unexpected type', () => { 62 | const expected = expect(() => { 63 | getParents({}) 64 | }) 65 | 66 | expected.toThrow(TypeError) 67 | expected.toThrow(/1st/) 68 | expected.toThrow(/`getParents`/) 69 | expected.toThrow(/unexpected type/) 70 | expected.toThrow(/element is expected/) 71 | }) 72 | 73 | it('should throw an error with a friendly message when the first argument has an unexpected type', () => { 74 | const expected = expect(() => { 75 | getParents() 76 | }) 77 | 78 | expected.toThrow(TypeError) 79 | expected.toThrow(/1st/) 80 | expected.toThrow(/`getParents`/) 81 | expected.toThrow(/is not defined/) 82 | expected.toThrow(/element is expected/) 83 | }) 84 | }) 85 | -------------------------------------------------------------------------------- /test/element/has-class.test.js: -------------------------------------------------------------------------------- 1 | import hasClass from '../../lib/element/has-class' 2 | 3 | describe('hasClass main functionality', () => { 4 | it('should check if a DOM element has the given class', () => { 5 | const element = document.createElement('div') 6 | element.className = 'hey' 7 | 8 | expect(hasClass('hey', element)).toBe(true) 9 | expect(hasClass('there', element)).toBe(false) 10 | }) 11 | 12 | it('should be curried', () => { 13 | const element = document.createElement('div') 14 | element.className = 'hey' 15 | 16 | expect(hasClass('hey', element)).toBe(true) 17 | }) 18 | 19 | it('should accept an array of classes', () => { 20 | const element = document.createElement('div') 21 | element.className = 'hey there hello' 22 | 23 | expect(hasClass(['hey', 'there'], element)).toBe(true) 24 | expect(hasClass(['hey', 'hello'], element)).toBe(true) 25 | expect(hasClass(['hey', 'there', 'man'], element)).toBe(false) 26 | }) 27 | 28 | it('should work with prefix classes', () => { 29 | const element = document.createElement('div') 30 | element.className = 'table-hover' 31 | expect(hasClass('table', element)).toBe(false) 32 | }) 33 | }) 34 | 35 | describe('hasClass arguments validation errors', () => { 36 | it('should throw an error with a friendly message when the first argument has an unexpected type', () => { 37 | const expected = expect(() => { 38 | hasClass({}, document.createElement('div')) 39 | }) 40 | 41 | expected.toThrow(TypeError) 42 | expected.toThrow(/1st/) 43 | expected.toThrow(/`hasClass`/) 44 | expected.toThrow(/unexpected type/) 45 | expected.toThrow(/string or array is expected/) 46 | }) 47 | 48 | it('should throw an error with a friendly message when the first argument is not defined', () => { 49 | const expected = expect(() => { 50 | hasClass(undefined, document.createElement('div')) 51 | }) 52 | 53 | expected.toThrow(TypeError) 54 | expected.toThrow(/1st/) 55 | expected.toThrow(/`hasClass`/) 56 | expected.toThrow(/is not defined/) 57 | expected.toThrow(/string or array is expected/) 58 | }) 59 | 60 | it('should throw an error with a friendly message when the second argument has an unexpected type', () => { 61 | const expected = expect(() => { 62 | hasClass('hey', 42) 63 | }) 64 | 65 | expected.toThrow(TypeError) 66 | expected.toThrow(/2nd/) 67 | expected.toThrow(/`hasClass`/) 68 | expected.toThrow(/unexpected type/) 69 | expected.toThrow(/element is expected/) 70 | }) 71 | 72 | it('should throw an error with a friendly message when the second argument is not defined', () => { 73 | const expected = expect(() => { 74 | hasClass('hey', undefined) 75 | }) 76 | 77 | expected.toThrow(TypeError) 78 | expected.toThrow(/2nd/) 79 | expected.toThrow(/`hasClass`/) 80 | expected.toThrow(/is not defined/) 81 | expected.toThrow(/element is expected/) 82 | }) 83 | }) 84 | -------------------------------------------------------------------------------- /test/element/hide-element.test.js: -------------------------------------------------------------------------------- 1 | import hideElement from '../../lib/element/hide-element' 2 | 3 | describe('hideElement main functionality', () => { 4 | it('should hide a element', () => { 5 | const child = document.createElement('div') 6 | child.id = 'child1' 7 | expect(hideElement(child)).toEqual(child) 8 | expect(child.style.display).toBe('none') 9 | }) 10 | 11 | it('should accept an array of elements', () => { 12 | const child1 = document.createElement('div') 13 | child1.id = 'child1' 14 | const child2 = document.createElement('div') 15 | child2.id = 'child2' 16 | const child3 = document.createElement('div') 17 | child3.id = 'child3' 18 | 19 | expect(hideElement([child1, child3])).toEqual([child1, child3]) 20 | expect(child1.style.display).toBe('none') 21 | expect(child2.style.display).not.toBe('none') 22 | expect(child3.style.display).toBe('none') 23 | }) 24 | }) 25 | 26 | describe('hideElement arguments validation errors', () => { 27 | it('should throw an error with a friendly message when the first argument has an unexpected type', () => { 28 | const expected = expect(() => { 29 | hideElement({}) 30 | }) 31 | 32 | expected.toThrow(TypeError) 33 | expected.toThrow(/1st/) 34 | expected.toThrow(/`hideElement`/) 35 | expected.toThrow(/unexpected type/) 36 | expected.toThrow(/element or array is expected/) 37 | }) 38 | 39 | it('should throw an error with a friendly message when the first argument has an unexpected type', () => { 40 | const expected = expect(() => { 41 | hideElement() 42 | }) 43 | 44 | expected.toThrow(TypeError) 45 | expected.toThrow(/1st/) 46 | expected.toThrow(/`hideElement`/) 47 | expected.toThrow(/is not defined/) 48 | expected.toThrow(/element or array is expected/) 49 | }) 50 | }) 51 | -------------------------------------------------------------------------------- /test/element/insert-element-after.test.js: -------------------------------------------------------------------------------- 1 | import insertElementAfter from '../../lib/element/insert-element-after' 2 | 3 | describe('insertElementAfter main functionality', () => { 4 | it('should insert a element before a reference node', () => { 5 | const parent = document.createElement('div') 6 | parent.id = 'parent' 7 | 8 | const referenceNode = document.createElement('div') 9 | referenceNode.id = 'referenceNode' 10 | 11 | const newNode = document.createElement('div') 12 | newNode.id = 'newNode' 13 | 14 | parent.appendChild(referenceNode) 15 | 16 | expect(parent.children.length).toBe(1) 17 | expect(parent.children[0]).toEqual(referenceNode) 18 | expect(insertElementAfter(referenceNode, newNode)).toEqual(newNode) 19 | expect(parent.children.length).toBe(2) 20 | expect(parent.children[0]).toEqual(referenceNode) 21 | expect(parent.children[1]).toEqual(newNode) 22 | }) 23 | 24 | it('should be curried', () => { 25 | const parent = document.createElement('div') 26 | parent.id = 'parent' 27 | 28 | const referenceNode = document.createElement('div') 29 | referenceNode.id = 'referenceNode' 30 | 31 | const newNode = document.createElement('div') 32 | newNode.id = 'newNode' 33 | 34 | parent.appendChild(referenceNode) 35 | 36 | expect(parent.children.length).toBe(1) 37 | expect(parent.children[0]).toEqual(referenceNode) 38 | expect(insertElementAfter(referenceNode)(newNode)).toEqual(newNode) 39 | expect(parent.children.length).toBe(2) 40 | expect(parent.children[0]).toEqual(referenceNode) 41 | expect(parent.children[1]).toEqual(newNode) 42 | }) 43 | }) 44 | 45 | describe('insertElementAfter arguments validation errors', () => { 46 | it('should throw an error with a friendly message when the first argument has an unexpected type', () => { 47 | const expected = expect(() => { 48 | insertElementAfter({}, document.createElement('div')) 49 | }) 50 | 51 | expected.toThrow(TypeError) 52 | expected.toThrow(/1st/) 53 | expected.toThrow(/`insertElementAfter`/) 54 | expected.toThrow(/unexpected type/) 55 | expected.toThrow(/element is expected/) 56 | }) 57 | 58 | it('should throw an error with a friendly message when the first argument is not defined', () => { 59 | const expected = expect(() => { 60 | insertElementAfter(undefined, document.createElement('div')) 61 | }) 62 | 63 | expected.toThrow(TypeError) 64 | expected.toThrow(/1st/) 65 | expected.toThrow(/`insertElementAfter`/) 66 | expected.toThrow(/is not defined/) 67 | expected.toThrow(/element is expected/) 68 | }) 69 | 70 | it('should throw an error with a friendly message when the second argument has an unexpected type', () => { 71 | const expected = expect(() => { 72 | insertElementAfter(document.createElement('div'), {}) 73 | }) 74 | 75 | expected.toThrow(TypeError) 76 | expected.toThrow(/2nd/) 77 | expected.toThrow(/`insertElementAfter`/) 78 | expected.toThrow(/unexpected type/) 79 | expected.toThrow(/element is expected/) 80 | }) 81 | 82 | it('should throw an error with a friendly message when the second argument is not defined', () => { 83 | const expected = expect(() => { 84 | insertElementAfter(document.createElement('div'), undefined) 85 | }) 86 | 87 | expected.toThrow(TypeError) 88 | expected.toThrow(/2nd/) 89 | expected.toThrow(/`insertElementAfter`/) 90 | expected.toThrow(/is not defined/) 91 | expected.toThrow(/element is expected/) 92 | }) 93 | }) 94 | -------------------------------------------------------------------------------- /test/element/insert-element-before.test.js: -------------------------------------------------------------------------------- 1 | import insertElementBefore from '../../lib/element/insert-element-before' 2 | 3 | describe('insertElementBefore main functionality', () => { 4 | it('should insert a element before a reference node', () => { 5 | const parent = document.createElement('div') 6 | parent.id = 'parent' 7 | 8 | const referenceNode = document.createElement('div') 9 | referenceNode.id = 'referenceNode' 10 | 11 | const newNode = document.createElement('div') 12 | newNode.id = 'newNode' 13 | 14 | parent.appendChild(referenceNode) 15 | 16 | expect(parent.children.length).toBe(1) 17 | expect(parent.children[0]).toEqual(referenceNode) 18 | expect(insertElementBefore(referenceNode, newNode)).toEqual(newNode) 19 | expect(parent.children.length).toBe(2) 20 | expect(parent.children[0]).toEqual(newNode) 21 | expect(parent.children[1]).toEqual(referenceNode) 22 | }) 23 | 24 | it('should be curried', () => { 25 | const parent = document.createElement('div') 26 | parent.id = 'parent' 27 | 28 | const referenceNode = document.createElement('div') 29 | referenceNode.id = 'referenceNode' 30 | 31 | const newNode = document.createElement('div') 32 | newNode.id = 'newNode' 33 | 34 | parent.appendChild(referenceNode) 35 | 36 | expect(parent.children.length).toBe(1) 37 | expect(parent.children[0]).toEqual(referenceNode) 38 | expect(insertElementBefore(referenceNode)(newNode)).toEqual(newNode) 39 | expect(parent.children.length).toBe(2) 40 | expect(parent.children[0]).toEqual(newNode) 41 | expect(parent.children[1]).toEqual(referenceNode) 42 | }) 43 | }) 44 | 45 | describe('insertElementBefore arguments validation errors', () => { 46 | it('should throw an error with a friendly message when the first argument has an unexpected type', () => { 47 | const expected = expect(() => { 48 | insertElementBefore({}, document.createElement('div')) 49 | }) 50 | 51 | expected.toThrow(TypeError) 52 | expected.toThrow(/1st/) 53 | expected.toThrow(/`insertElementBefore`/) 54 | expected.toThrow(/unexpected type/) 55 | expected.toThrow(/element is expected/) 56 | }) 57 | 58 | it('should throw an error with a friendly message when the first argument is not defined', () => { 59 | const expected = expect(() => { 60 | insertElementBefore(undefined, document.createElement('div')) 61 | }) 62 | 63 | expected.toThrow(TypeError) 64 | expected.toThrow(/1st/) 65 | expected.toThrow(/`insertElementBefore`/) 66 | expected.toThrow(/is not defined/) 67 | expected.toThrow(/element is expected/) 68 | }) 69 | 70 | it('should throw an error with a friendly message when the second argument has an unexpected type', () => { 71 | const expected = expect(() => { 72 | insertElementBefore(document.createElement('div'), {}) 73 | }) 74 | 75 | expected.toThrow(TypeError) 76 | expected.toThrow(/2nd/) 77 | expected.toThrow(/`insertElementBefore`/) 78 | expected.toThrow(/unexpected type/) 79 | expected.toThrow(/element is expected/) 80 | }) 81 | 82 | it('should throw an error with a friendly message when the second argument is not defined', () => { 83 | const expected = expect(() => { 84 | insertElementBefore(document.createElement('div'), undefined) 85 | }) 86 | 87 | expected.toThrow(TypeError) 88 | expected.toThrow(/2nd/) 89 | expected.toThrow(/`insertElementBefore`/) 90 | expected.toThrow(/is not defined/) 91 | expected.toThrow(/element is expected/) 92 | }) 93 | }) 94 | -------------------------------------------------------------------------------- /test/element/kill-element.test.js: -------------------------------------------------------------------------------- 1 | import killElement from '../../lib/element/kill-element' 2 | 3 | describe('killElement main functionality', () => { 4 | it('should kill a element', () => { 5 | const parent = document.createElement('div') 6 | const child = document.createElement('div') 7 | parent.appendChild(child) 8 | killElement(child) 9 | expect(parent.children.length).toBe(0) 10 | }) 11 | 12 | it('should accept an array of elements', () => { 13 | const parent = document.createElement('div') 14 | const child1 = document.createElement('div') 15 | child1.id = 'child1' 16 | const child2 = document.createElement('div') 17 | child2.id = 'child2' 18 | const child3 = document.createElement('div') 19 | child3.id = 'child3' 20 | 21 | parent.appendChild(child1) 22 | parent.appendChild(child2) 23 | parent.appendChild(child3) 24 | killElement([child1, child3]) 25 | expect(parent.children.length).toBe(1) 26 | expect(parent.children[0]).toEqual(child2) 27 | }) 28 | }) 29 | 30 | describe('killElement arguments validation errors', () => { 31 | it('should throw an error with a friendly message when the first argument has an unexpected type', () => { 32 | const expected = expect(() => { 33 | killElement({}) 34 | }) 35 | 36 | expected.toThrow(TypeError) 37 | expected.toThrow(/1st/) 38 | expected.toThrow(/`killElement`/) 39 | expected.toThrow(/unexpected type/) 40 | expected.toThrow(/element or array is expected/) 41 | }) 42 | 43 | it('should throw an error with a friendly message when the first argument has an unexpected type', () => { 44 | const expected = expect(() => { 45 | killElement() 46 | }) 47 | 48 | expected.toThrow(TypeError) 49 | expected.toThrow(/1st/) 50 | expected.toThrow(/`killElement`/) 51 | expected.toThrow(/is not defined/) 52 | expected.toThrow(/element or array is expected/) 53 | }) 54 | }) 55 | -------------------------------------------------------------------------------- /test/element/remove-class.test.js: -------------------------------------------------------------------------------- 1 | import removeClass from '../../lib/element/remove-class' 2 | 3 | describe('removeClass main functionality', () => { 4 | it('should remove a class from a DOM element', () => { 5 | const element = document.createElement('div') 6 | element.className = 'hey there' 7 | removeClass('hey', element) 8 | expect(element.className).toBe('there') 9 | removeClass('there', element) 10 | expect(element.className).toBe('') 11 | }) 12 | 13 | it('should return the element', () => { 14 | const actual = document.createElement('div') 15 | const expected = removeClass('hey', actual) 16 | expect(actual).toEqual(expected) 17 | }) 18 | 19 | it('should be curried', () => { 20 | const element = document.createElement('div') 21 | element.className = 'hey there' 22 | removeClass('hey')(element) 23 | expect(element.className).toBe('there') 24 | }) 25 | 26 | it('should accept an array of classes', () => { 27 | const element = document.createElement('div') 28 | element.className = 'hey there' 29 | removeClass(['hey', 'there'])(element) 30 | expect(element.className).toBe('') 31 | }) 32 | 33 | it('should work with prefix classes', () => { 34 | const element = document.createElement('div') 35 | element.className = 'table table-hover table-inverse' 36 | removeClass(['table-hover', 'table-inverse'])(element) 37 | expect(element.className).toBe('table') 38 | }) 39 | }) 40 | 41 | describe('removeClass arguments validation errors', () => { 42 | it('should throw an error with a friendly message when the first argument has an unexpected type', () => { 43 | const expected = expect(() => { 44 | removeClass({}, document.createElement('div')) 45 | }) 46 | 47 | expected.toThrow(TypeError) 48 | expected.toThrow(/1st/) 49 | expected.toThrow(/`removeClass`/) 50 | expected.toThrow(/unexpected type/) 51 | expected.toThrow(/string or array is expected/) 52 | }) 53 | 54 | it('should throw an error with a friendly message when the first argument is not defined', () => { 55 | const expected = expect(() => { 56 | removeClass(undefined, document.createElement('div')) 57 | }) 58 | 59 | expected.toThrow(TypeError) 60 | expected.toThrow(/1st/) 61 | expected.toThrow(/`removeClass`/) 62 | expected.toThrow(/is not defined/) 63 | expected.toThrow(/string or array is expected/) 64 | }) 65 | 66 | it('should throw an error with a friendly message when the second argument has an unexpected type', () => { 67 | const expected = expect(() => { 68 | removeClass('hey', 42) 69 | }) 70 | 71 | expected.toThrow(TypeError) 72 | expected.toThrow(/2nd/) 73 | expected.toThrow(/`removeClass`/) 74 | expected.toThrow(/unexpected type/) 75 | expected.toThrow(/element is expected/) 76 | }) 77 | 78 | it('should throw an error with a friendly message when the second argument is not defined', () => { 79 | const expected = expect(() => { 80 | removeClass('hey', undefined) 81 | }) 82 | 83 | expected.toThrow(TypeError) 84 | expected.toThrow(/2nd/) 85 | expected.toThrow(/`removeClass`/) 86 | expected.toThrow(/is not defined/) 87 | expected.toThrow(/element is expected/) 88 | }) 89 | }) 90 | -------------------------------------------------------------------------------- /test/element/replace-element.test.js: -------------------------------------------------------------------------------- 1 | import replaceElement from '../../lib/element/replace-element' 2 | 3 | describe('replaceElement main functionality', () => { 4 | it('should replace a element', () => { 5 | const parent = document.createElement('div') 6 | const oldNode = document.createElement('div') 7 | oldNode.id = 'oldNode' 8 | const newNode = document.createElement('div') 9 | newNode.id = 'newNode' 10 | 11 | parent.appendChild(oldNode) 12 | expect(replaceElement(oldNode, newNode)).toEqual(newNode) 13 | expect(parent.children.length).toBe(1) 14 | expect(parent.children[0]).toEqual(newNode) 15 | }) 16 | }) 17 | 18 | describe('replaceElement arguments validation errors', () => { 19 | it('should throw an error with a friendly message when the first argument is not defined', () => { 20 | const expected = expect(() => { 21 | replaceElement(undefined, document.createElement('div')) 22 | }) 23 | 24 | expected.toThrow(TypeError) 25 | expected.toThrow(/1st/) 26 | expected.toThrow(/`replaceElement`/) 27 | expected.toThrow(/is not defined/) 28 | expected.toThrow(/element is expected/) 29 | }) 30 | 31 | it('should throw an error with a friendly message when the first argument has an unexpected type', () => { 32 | const expected = expect(() => { 33 | replaceElement({}, document.createElement('div')) 34 | }) 35 | 36 | expected.toThrow(TypeError) 37 | expected.toThrow(/1st/) 38 | expected.toThrow(/`replaceElement`/) 39 | expected.toThrow(/unexpected type/) 40 | expected.toThrow(/element is expected/) 41 | }) 42 | 43 | it('should throw an error with a friendly message when the second argument has an unexpected type', () => { 44 | const expected = expect(() => { 45 | replaceElement(document.createElement('div'), {}) 46 | }) 47 | 48 | expected.toThrow(TypeError) 49 | expected.toThrow(/2nd/) 50 | expected.toThrow(/`replaceElement`/) 51 | expected.toThrow(/unexpected type/) 52 | expected.toThrow(/element is expected/) 53 | }) 54 | 55 | it('should throw an error with a friendly message when the second argument is not defined', () => { 56 | const expected = expect(() => { 57 | replaceElement(document.createElement('div'), undefined) 58 | }) 59 | 60 | expected.toThrow(TypeError) 61 | expected.toThrow(/2nd/) 62 | expected.toThrow(/`replaceElement`/) 63 | expected.toThrow(/is not defined/) 64 | expected.toThrow(/element is expected/) 65 | }) 66 | }) 67 | -------------------------------------------------------------------------------- /test/element/show-element.test.js: -------------------------------------------------------------------------------- 1 | import showElement from '../../lib/element/show-element' 2 | 3 | describe('showElement main functionality', () => { 4 | it('should show a element', () => { 5 | const child = document.createElement('div') 6 | child.id = 'child1' 7 | expect(showElement(child)).toEqual(child) 8 | expect(child.style.display).toBe('block') 9 | }) 10 | 11 | it('should accept an array of elements', () => { 12 | const child1 = document.createElement('div') 13 | child1.id = 'child1' 14 | const child2 = document.createElement('div') 15 | child2.id = 'child2' 16 | const child3 = document.createElement('div') 17 | child3.id = 'child3' 18 | 19 | expect(showElement([child1, child3])).toEqual([child1, child3]) 20 | expect(child1.style.display).toBe('block') 21 | expect(child2.style.display).not.toBe('block') 22 | expect(child3.style.display).toBe('block') 23 | }) 24 | }) 25 | 26 | describe('showElement arguments validation errors', () => { 27 | it('should throw an error with a friendly message when the first argument has an unexpected type', () => { 28 | const expected = expect(() => { 29 | showElement({}) 30 | }) 31 | 32 | expected.toThrow(TypeError) 33 | expected.toThrow(/1st/) 34 | expected.toThrow(/`showElement`/) 35 | expected.toThrow(/unexpected type/) 36 | expected.toThrow(/element or array is expected/) 37 | }) 38 | 39 | it('should throw an error with a friendly message when the first argument has an unexpected type', () => { 40 | const expected = expect(() => { 41 | showElement() 42 | }) 43 | 44 | expected.toThrow(TypeError) 45 | expected.toThrow(/1st/) 46 | expected.toThrow(/`showElement`/) 47 | expected.toThrow(/is not defined/) 48 | expected.toThrow(/element or array is expected/) 49 | }) 50 | }) 51 | -------------------------------------------------------------------------------- /test/element/toggle-class.test.js: -------------------------------------------------------------------------------- 1 | import toggleClass from '../../lib/element/toggle-class' 2 | 3 | describe('toggleClass main functionality', () => { 4 | it('should toogle a class from a DOM element', () => { 5 | const element = document.createElement('div') 6 | element.className = 'hey' 7 | toggleClass('hey', element) 8 | expect(element.className).toBe('') 9 | toggleClass('hey', element) 10 | expect(element.className).toBe('hey') 11 | }) 12 | 13 | it('should return the element', () => { 14 | const actual = document.createElement('div') 15 | const expected = toggleClass('hey', actual) 16 | expect(actual).toEqual(expected) 17 | }) 18 | 19 | it('should be curried', () => { 20 | const element = document.createElement('div') 21 | element.className = 'hey' 22 | toggleClass('hey')(element) 23 | expect(element.className).toBe('') 24 | }) 25 | 26 | it('should accept an array of classes', () => { 27 | const element = document.createElement('div') 28 | element.className = 'hey' 29 | toggleClass(['hey', 'there'], element) 30 | expect(element.className).toBe('there') 31 | toggleClass(['hey', 'there'], element) 32 | expect(element.className).toBe('hey') 33 | }) 34 | 35 | it('should work with prefix classes', () => { 36 | const element = document.createElement('div') 37 | element.className = 'table table-hover table-inverse' 38 | toggleClass('table')(element) 39 | expect(element.className).toBe('table-hover table-inverse') 40 | }) 41 | }) 42 | 43 | describe('toggleClass arguments validation errors', () => { 44 | it('should throw an error with a friendly message when the first argument has an unexpected type', () => { 45 | const expected = expect(() => { 46 | toggleClass({}, document.createElement('div')) 47 | }) 48 | 49 | expected.toThrow(TypeError) 50 | expected.toThrow(/1st/) 51 | expected.toThrow(/`toggleClass`/) 52 | expected.toThrow(/unexpected type/) 53 | expected.toThrow(/string or array is expected/) 54 | }) 55 | 56 | it('should throw an error with a friendly message when the first argument is not defined', () => { 57 | const expected = expect(() => { 58 | toggleClass(undefined, document.createElement('div')) 59 | }) 60 | 61 | expected.toThrow(TypeError) 62 | expected.toThrow(/1st/) 63 | expected.toThrow(/`toggleClass`/) 64 | expected.toThrow(/is not defined/) 65 | expected.toThrow(/string or array is expected/) 66 | }) 67 | 68 | it('should throw an error with a friendly message when the second argument has an unexpected type', () => { 69 | const expected = expect(() => { 70 | toggleClass('hey', 42) 71 | }) 72 | 73 | expected.toThrow(TypeError) 74 | expected.toThrow(/2nd/) 75 | expected.toThrow(/`toggleClass`/) 76 | expected.toThrow(/unexpected type/) 77 | expected.toThrow(/element is expected/) 78 | }) 79 | 80 | it('should throw an error with a friendly message when the second argument is not defined', () => { 81 | const expected = expect(() => { 82 | toggleClass('hey', undefined) 83 | }) 84 | 85 | expected.toThrow(TypeError) 86 | expected.toThrow(/2nd/) 87 | expected.toThrow(/`toggleClass`/) 88 | expected.toThrow(/is not defined/) 89 | expected.toThrow(/element is expected/) 90 | }) 91 | }) 92 | -------------------------------------------------------------------------------- /test/function/compose.test.js: -------------------------------------------------------------------------------- 1 | import compose from '../../lib/function/compose' 2 | import addMinutes from '../../lib/date/add-minutes' 3 | import addHours from '../../lib/date/add-hours' 4 | import addDays from '../../lib/date/add-days' 5 | import addMonths from '../../lib/date/add-months' 6 | import addYears from '../../lib/date/add-years' 7 | import formatDate from '../../lib/date/format-date' 8 | 9 | describe('compose main functionality', () => { 10 | it('should compose a date', () => { 11 | const date = new Date('December 17, 1995 03:24:00') 12 | const format = '{DD}/{MM}/{YYYY} {HH}:{mm}:{ss}' 13 | const actual = compose( 14 | formatDate(format), 15 | addYears(-2), 16 | addMonths(-9), 17 | addDays(7), 18 | addHours(9), 19 | addMinutes(1) 20 | )(date) 21 | const expected = '24/03/1993 12:25:00' 22 | expect(actual).toBe(expected) 23 | }) 24 | }) 25 | 26 | describe('compose arguments validation errors', () => { 27 | it('should throw an error with a friendly message when the first argument has an unexpected type', () => { 28 | const expected = expect(() => { 29 | compose({}, () => {})('hey') 30 | }) 31 | 32 | expected.toThrow(TypeError) 33 | expected.toThrow(/1st/) 34 | expected.toThrow(/`compose`/) 35 | expected.toThrow(/unexpected type/) 36 | expected.toThrow(/function is expected/) 37 | }) 38 | 39 | it('should throw an error with a friendly message when the first argument is not defined', () => { 40 | const expected = expect(() => { 41 | compose(undefined, () => {})('jey') 42 | }) 43 | 44 | expected.toThrow(TypeError) 45 | expected.toThrow(/1st/) 46 | expected.toThrow(/`compose`/) 47 | expected.toThrow(/is not defined/) 48 | expected.toThrow(/function is expected/) 49 | }) 50 | 51 | it('should throw an error with a friendly message when the second argument has an unexpected type', () => { 52 | const expected = expect(() => { 53 | compose(() => {}, {})('hey') 54 | }) 55 | 56 | expected.toThrow(TypeError) 57 | expected.toThrow(/2nd/) 58 | expected.toThrow(/`compose`/) 59 | expected.toThrow(/unexpected type/) 60 | expected.toThrow(/function is expected/) 61 | }) 62 | 63 | it('should throw an error with a friendly message when the second argument is not defined', () => { 64 | const expected = expect(() => { 65 | compose(() => {}, undefined)('hey') 66 | }) 67 | 68 | expected.toThrow(TypeError) 69 | expected.toThrow(/2nd/) 70 | expected.toThrow(/`compose`/) 71 | expected.toThrow(/is not defined/) 72 | expected.toThrow(/function is expected/) 73 | }) 74 | 75 | it('should throw an error with a friendly message when the third argument has an unexpected type', () => { 76 | const expected = expect(() => { 77 | compose(a => a, a => a, {})('hey') 78 | }) 79 | 80 | expected.toThrow(TypeError) 81 | expected.toThrow(/3rd/) 82 | expected.toThrow(/`compose`/) 83 | expected.toThrow(/unexpected type/) 84 | expected.toThrow(/function is expected/) 85 | }) 86 | 87 | it('should throw an error with a friendly message when the third argument is not defined', () => { 88 | const expected = expect(() => { 89 | compose(() => {}, a => a, undefined)('hey') 90 | }) 91 | 92 | expected.toThrow(TypeError) 93 | expected.toThrow(/3rd/) 94 | expected.toThrow(/`compose`/) 95 | expected.toThrow(/is not defined/) 96 | expected.toThrow(/function is expected/) 97 | }) 98 | }) 99 | -------------------------------------------------------------------------------- /test/function/curry.test.js: -------------------------------------------------------------------------------- 1 | import curry from '../../lib/function/curry' 2 | 3 | describe('curry main functionality', () => { 4 | it('should curry a function with two arguments', () => { 5 | const add = (a, b) => a + b 6 | 7 | expect(typeof curry(add)).toBe('function') 8 | expect(typeof curry(add, 2)).toBe('function') 9 | 10 | expect(curry(add, 2, 2)).toBe(4) 11 | expect(curry(add)(2, 2)).toBe(4) 12 | expect(curry(add)(2)(2)).toBe(4) 13 | expect(curry(add)(2)(2)).toBe(4) 14 | }) 15 | 16 | it('should curry a function with three arguments', () => { 17 | const formula = (a, b, c) => a * b + c 18 | 19 | expect(typeof curry(formula)).toBe('function') 20 | expect(typeof curry(formula, 2)).toBe('function') 21 | expect(typeof curry(formula, 2, 2)).toBe('function') 22 | expect(typeof curry(formula)(2)(2)).toBe('function') 23 | 24 | expect(curry(formula, 2, 2, 2)).toBe(6) 25 | expect(curry(formula)(2, 2, 2)).toBe(6) 26 | expect(curry(formula, 2)(2, 2)).toBe(6) 27 | expect(curry(formula)(2)(2, 2)).toBe(6) 28 | expect(curry(formula)(2, 2)(2)).toBe(6) 29 | expect(curry(formula)(2, 2)(2)).toBe(6) 30 | expect(curry(formula)(2)(2)(2)).toBe(6) 31 | expect(curry(formula)(2)(2)(2)).toBe(6) 32 | }) 33 | }) 34 | 35 | describe('curry arguments validation errors', () => { 36 | it('should throw an error with a friendly message when the first argument is not defined', () => { 37 | const expected = expect(() => { 38 | curry({}) 39 | }) 40 | 41 | expected.toThrow(TypeError) 42 | expected.toThrow(/1st/) 43 | expected.toThrow(/`curry`/) 44 | expected.toThrow(/unexpected type/) 45 | expected.toThrow(/function is expected/) 46 | }) 47 | 48 | it('should throw an error with a friendly message when the first argument has a unexpected type', () => { 49 | const expected = expect(() => { 50 | curry() 51 | }) 52 | 53 | expected.toThrow(TypeError) 54 | expected.toThrow(/1st/) 55 | expected.toThrow(/`curry`/) 56 | expected.toThrow(/is not defined/) 57 | expected.toThrow(/function is expected/) 58 | }) 59 | }) 60 | -------------------------------------------------------------------------------- /test/function/pipe.test.js: -------------------------------------------------------------------------------- 1 | import pipe from '../../lib/function/pipe' 2 | import addMinutes from '../../lib/date/add-minutes' 3 | import addHours from '../../lib/date/add-hours' 4 | import addDays from '../../lib/date/add-days' 5 | import addMonths from '../../lib/date/add-months' 6 | import addYears from '../../lib/date/add-years' 7 | import formatDate from '../../lib/date/format-date' 8 | 9 | describe('pipe main functionality', () => { 10 | it('should pipe of a date', () => { 11 | const date = new Date('December 17, 1995 03:24:00') 12 | const format = '{DD}/{MM}/{YYYY} {HH}:{mm}:{ss}' 13 | const actual = pipe( 14 | addMinutes(1), 15 | addHours(9), 16 | addDays(7), 17 | addMonths(-9), 18 | addYears(-2), 19 | formatDate(format) 20 | )(date) 21 | const expected = '24/03/1993 12:25:00' 22 | expect(actual).toBe(expected) 23 | }) 24 | }) 25 | 26 | describe('pipe arguments validation errors', () => { 27 | it('should throw an error with a friendly message when the first argument has an unexpected type', () => { 28 | const expected = expect(() => { 29 | pipe({}, () => {})('hey') 30 | }) 31 | 32 | expected.toThrow(TypeError) 33 | expected.toThrow(/1st/) 34 | expected.toThrow(/`pipe`/) 35 | expected.toThrow(/unexpected type/) 36 | expected.toThrow(/function is expected/) 37 | }) 38 | 39 | it('should throw an error with a friendly message when the first argument is not defined', () => { 40 | const expected = expect(() => { 41 | pipe(undefined, () => {})('jey') 42 | }) 43 | 44 | expected.toThrow(TypeError) 45 | expected.toThrow(/1st/) 46 | expected.toThrow(/`pipe`/) 47 | expected.toThrow(/is not defined/) 48 | expected.toThrow(/function is expected/) 49 | }) 50 | 51 | it('should throw an error with a friendly message when the second argument has an unexpected type', () => { 52 | const expected = expect(() => { 53 | pipe(() => {}, {})('hey') 54 | }) 55 | 56 | expected.toThrow(TypeError) 57 | expected.toThrow(/2nd/) 58 | expected.toThrow(/`pipe`/) 59 | expected.toThrow(/unexpected type/) 60 | expected.toThrow(/function is expected/) 61 | }) 62 | 63 | it('should throw an error with a friendly message when the second argument is not defined', () => { 64 | const expected = expect(() => { 65 | pipe(() => {}, undefined)('hey') 66 | }) 67 | 68 | expected.toThrow(TypeError) 69 | expected.toThrow(/2nd/) 70 | expected.toThrow(/`pipe`/) 71 | expected.toThrow(/is not defined/) 72 | expected.toThrow(/function is expected/) 73 | }) 74 | 75 | it('should throw an error with a friendly message when the third argument has an unexpected type', () => { 76 | const expected = expect(() => { 77 | pipe(a => a, a => a, {})('hey') 78 | }) 79 | 80 | expected.toThrow(TypeError) 81 | expected.toThrow(/3rd/) 82 | expected.toThrow(/`pipe`/) 83 | expected.toThrow(/unexpected type/) 84 | expected.toThrow(/function is expected/) 85 | }) 86 | 87 | it('should throw an error with a friendly message when the third argument is not defined', () => { 88 | const expected = expect(() => { 89 | pipe(() => {}, a => a, undefined)('hey') 90 | }) 91 | 92 | expected.toThrow(TypeError) 93 | expected.toThrow(/3rd/) 94 | expected.toThrow(/`pipe`/) 95 | expected.toThrow(/is not defined/) 96 | expected.toThrow(/function is expected/) 97 | }) 98 | }) 99 | -------------------------------------------------------------------------------- /test/function/throttle.test.js: -------------------------------------------------------------------------------- 1 | import throttle from '../../lib/function/throttle' 2 | 3 | jest.useFakeTimers() 4 | 5 | describe('throttle main functionality', () => { 6 | it('should run only one time every 200ms', () => { 7 | const callback = jest.fn() 8 | 9 | const throttled = throttle(200, callback) 10 | 11 | throttled() 12 | throttled() 13 | 14 | jest.runTimersToTime(200) 15 | 16 | expect(callback.mock.calls.length).toBe(1) 17 | 18 | throttled() 19 | throttled() 20 | 21 | jest.runTimersToTime(400) 22 | 23 | expect(callback.mock.calls.length).toBe(2) 24 | }) 25 | 26 | it('should be curried', () => { 27 | const callback = jest.fn() 28 | 29 | const throttled = throttle(200)(callback) 30 | 31 | throttled() 32 | throttled() 33 | 34 | jest.runTimersToTime(200) 35 | 36 | expect(callback.mock.calls.length).toBe(1) 37 | }) 38 | 39 | it('should pass the arguments through throttled function', () => { 40 | const callback = jest.fn() 41 | 42 | const throttled = throttle(200)(callback) 43 | const arg = { 44 | target: 'hey' 45 | } 46 | 47 | throttled(arg) 48 | 49 | jest.runTimersToTime(200) 50 | 51 | expect(callback.mock.calls.length).toBe(1) 52 | expect(callback.mock.calls[0][0]).toBe(arg) 53 | }) 54 | }) 55 | 56 | describe('throttle arguments validation errors', () => { 57 | it('should throw an error with a friendly message when the first argument has an unexpected type', () => { 58 | const expected = expect(() => { 59 | throttle({}, () => {}) 60 | }) 61 | 62 | expected.toThrow(TypeError) 63 | expected.toThrow(/1st/) 64 | expected.toThrow(/`throttle`/) 65 | expected.toThrow(/unexpected type/) 66 | expected.toThrow(/number is expected/) 67 | }) 68 | 69 | it('should throw an error with a friendly message when the first argument is not defined', () => { 70 | const expected = expect(() => { 71 | throttle(undefined, () => {}) 72 | }) 73 | 74 | expected.toThrow(TypeError) 75 | expected.toThrow(/1st/) 76 | expected.toThrow(/`throttle`/) 77 | expected.toThrow(/is not defined/) 78 | expected.toThrow(/number is expected/) 79 | }) 80 | 81 | it('should throw an error with a friendly message when the second argument has an unexpected type', () => { 82 | const expected = expect(() => { 83 | throttle(42, {}) 84 | }) 85 | 86 | expected.toThrow(TypeError) 87 | expected.toThrow(/2nd/) 88 | expected.toThrow(/`throttle`/) 89 | expected.toThrow(/unexpected type/) 90 | expected.toThrow(/function is expected/) 91 | }) 92 | 93 | it('should throw an error with a friendly message when the second argument is not defined', () => { 94 | const expected = expect(() => { 95 | throttle(42, undefined) 96 | }) 97 | 98 | expected.toThrow(TypeError) 99 | expected.toThrow(/2nd/) 100 | expected.toThrow(/`throttle`/) 101 | expected.toThrow(/is not defined/) 102 | expected.toThrow(/function is expected/) 103 | }) 104 | }) 105 | -------------------------------------------------------------------------------- /test/number/round.test.js: -------------------------------------------------------------------------------- 1 | import round from '../../lib/number/round' 2 | 3 | describe('round main functionality', () => { 4 | it('should return a number with two decimal places', () => { 5 | expect(round(2)).toBe(2) 6 | expect(round(Math.E)).toBe(2.72) 7 | expect(round(Math.LN10)).toBe(2.3) 8 | expect(round(Math.LN2)).toBe(0.69) 9 | expect(round(Math.PI)).toBe(3.14) 10 | }) 11 | 12 | it('should handle negative numbers', () => { 13 | expect(round(-27.817987)).toBe(-27.82) 14 | expect(round(-28.8)).toBe(-28.8) 15 | expect(round(-27)).toBe(-27) 16 | }) 17 | }) 18 | 19 | describe('round arguments validation errors', () => { 20 | it('should throw an error with a friendly message when the first argument has an unexpected type', () => { 21 | const expected = expect(() => { 22 | round(new Date()) 23 | }) 24 | 25 | expected.toThrow(TypeError) 26 | expected.toThrow(/1st/) 27 | expected.toThrow(/`round`/) 28 | expected.toThrow(/unexpected type/) 29 | expected.toThrow(/number is expected/) 30 | }) 31 | 32 | it('should throw an error with a friendly message when the first argument is not defined', () => { 33 | const expected = expect(() => { 34 | round(undefined) 35 | }) 36 | 37 | expected.toThrow(TypeError) 38 | expected.toThrow(/1st/) 39 | expected.toThrow(/`round`/) 40 | expected.toThrow(/is not defined/) 41 | expected.toThrow(/number is expected/) 42 | }) 43 | }) 44 | -------------------------------------------------------------------------------- /test/object/map-keys.test.js: -------------------------------------------------------------------------------- 1 | import mapKeys from '../../lib/object/map-keys' 2 | import capitalize from '../../lib/string/capitalize' 3 | 4 | describe('mapKeys main functionality', () => { 5 | it('should map over the keys of a object', () => { 6 | const actual = mapKeys(capitalize, { 7 | captain: 'picard', 8 | firstOfficer: 'riker' 9 | }) 10 | 11 | const expected = { 12 | Captain: 'picard', 13 | FirstOfficer: 'riker' 14 | } 15 | 16 | expect(actual).toEqual(expected) 17 | }) 18 | 19 | it('should be curried', () => { 20 | const actual = mapKeys(capitalize)({ 21 | captain: 'picard', 22 | firstOfficer: 'riker' 23 | }) 24 | 25 | const expected = { 26 | Captain: 'picard', 27 | FirstOfficer: 'riker' 28 | } 29 | 30 | expect(actual).toEqual(expected) 31 | }) 32 | }) 33 | 34 | describe('mapKeys arguments validation errors', () => { 35 | it('should throw a TypeError when unexpected argument types', () => { 36 | expect(() => { 37 | mapKeys({}, () => {}) 38 | }).toThrow(TypeError) 39 | expect(() => { 40 | mapKeys(null, () => {}) 41 | }).toThrow(TypeError) 42 | expect(() => { 43 | mapKeys(42, {}) 44 | }).toThrow(TypeError) 45 | expect(() => { 46 | mapKeys(42, null) 47 | }).toThrow(TypeError) 48 | expect(() => { 49 | mapKeys(42, 42) 50 | }).toThrow(TypeError) 51 | }) 52 | 53 | it('should throw a TypeError when one of the arguments is not defined', () => { 54 | expect(() => { 55 | mapKeys(undefined, {}) 56 | }).toThrow(TypeError) 57 | expect(() => { 58 | mapKeys(() => {}, undefined) 59 | }).toThrow(TypeError) 60 | }) 61 | 62 | it('should throw an error with a friendly message when the first argument has an unexpected type', () => { 63 | const expected = expect(() => { 64 | mapKeys({}, {}) 65 | }) 66 | 67 | expected.toThrow(/1st/) 68 | expected.toThrow(/`mapKeys`/) 69 | expected.toThrow(/unexpected type/) 70 | expected.toThrow(/function is expected/) 71 | }) 72 | 73 | it('should throw an error with a friendly message when the first argument is not defined', () => { 74 | const expected = expect(() => { 75 | mapKeys(undefined, {}) 76 | }) 77 | 78 | expected.toThrow(/1st/) 79 | expected.toThrow(/`mapKeys`/) 80 | expected.toThrow(/is not defined/) 81 | expected.toThrow(/function is expected/) 82 | }) 83 | 84 | it('should throw an error with a friendly message when the second argument has an unexpected type', () => { 85 | const expected = expect(() => { 86 | mapKeys(() => {}, 42) 87 | }) 88 | 89 | expected.toThrow(/2nd/) 90 | expected.toThrow(/`mapKeys`/) 91 | expected.toThrow(/unexpected type/) 92 | expected.toThrow(/object is expected/) 93 | }) 94 | 95 | it('should throw an error with a friendly message when the second argument is not defined', () => { 96 | const expected = expect(() => { 97 | mapKeys(() => {}, undefined) 98 | }) 99 | 100 | expected.toThrow(/2nd/) 101 | expected.toThrow(/`mapKeys`/) 102 | expected.toThrow(/is not defined/) 103 | expected.toThrow(/object is expected/) 104 | }) 105 | }) 106 | -------------------------------------------------------------------------------- /test/object/map-values.test.js: -------------------------------------------------------------------------------- 1 | import mapValues from '../../lib/object/map-values' 2 | import capitalize from '../../lib/string/capitalize' 3 | 4 | describe('mapValues main functionality', () => { 5 | it('map over the values of a object', () => { 6 | const actual = mapValues(capitalize, { 7 | captain: 'picard', 8 | firstOfficer: 'riker' 9 | }) 10 | 11 | const expected = { 12 | captain: 'Picard', 13 | firstOfficer: 'Riker' 14 | } 15 | 16 | expect(actual).toEqual(expected) 17 | }) 18 | 19 | it('should be curried', () => { 20 | const actual = mapValues(capitalize)({ 21 | captain: 'picard', 22 | firstOfficer: 'riker' 23 | }) 24 | 25 | const expected = { 26 | captain: 'Picard', 27 | firstOfficer: 'Riker' 28 | } 29 | 30 | expect(actual).toEqual(expected) 31 | }) 32 | }) 33 | 34 | describe('mapValues arguments validation errors', () => { 35 | it('should throw an error with a friendly message when the first argument has an unexpected type', () => { 36 | const expected = expect(() => { 37 | mapValues({}, {}) 38 | }) 39 | 40 | expected.toThrow(TypeError) 41 | expected.toThrow(/1st/) 42 | expected.toThrow(/`mapValues`/) 43 | expected.toThrow(/unexpected type/) 44 | expected.toThrow(/function is expected/) 45 | }) 46 | 47 | it('should throw an error with a friendly message when the first argument is not defined', () => { 48 | const expected = expect(() => { 49 | mapValues(undefined, {}) 50 | }) 51 | 52 | expected.toThrow(TypeError) 53 | expected.toThrow(/1st/) 54 | expected.toThrow(/`mapValues`/) 55 | expected.toThrow(/is not defined/) 56 | expected.toThrow(/function is expected/) 57 | }) 58 | 59 | it('should throw an error with a friendly message when the second argument has an unexpected type', () => { 60 | const expected = expect(() => { 61 | mapValues(() => {}, 42) 62 | }) 63 | 64 | expected.toThrow(TypeError) 65 | expected.toThrow(/2nd/) 66 | expected.toThrow(/`mapValues`/) 67 | expected.toThrow(/unexpected type/) 68 | expected.toThrow(/object is expected/) 69 | }) 70 | 71 | it('should throw an error with a friendly message when the second argument is not defined', () => { 72 | const expected = expect(() => { 73 | mapValues(() => {}, undefined) 74 | }) 75 | 76 | expected.toThrow(TypeError) 77 | expected.toThrow(/2nd/) 78 | expected.toThrow(/`mapValues`/) 79 | expected.toThrow(/is not defined/) 80 | expected.toThrow(/object is expected/) 81 | }) 82 | }) 83 | -------------------------------------------------------------------------------- /test/string/capitalize.test.js: -------------------------------------------------------------------------------- 1 | import capitalize from '../../lib/string/capitalize' 2 | 3 | describe('capitalize main functionality', () => { 4 | it('should capitalize a string', () => { 5 | expect(capitalize('string')).toBe('String') 6 | }) 7 | 8 | it('should ignore strings that does not start with letters', () => { 9 | expect(capitalize('')).toBe('') 10 | expect(capitalize('\n \n')).toBe('\n \n') 11 | expect(capitalize(' hjhj ')).toBe(' hjhj ') 12 | }) 13 | }) 14 | 15 | describe('capitalize arguments validation errors', () => { 16 | it('should throw an error with a friendly message when the first argument has an unexpected type', () => { 17 | const expected = expect(() => { 18 | capitalize({}) 19 | }) 20 | 21 | expected.toThrow(TypeError) 22 | expected.toThrow(/1st/) 23 | expected.toThrow(/`capitalize`/) 24 | expected.toThrow(/unexpected type/) 25 | expected.toThrow(/string is expected/) 26 | }) 27 | 28 | it('should throw an error with a friendly message when the first argument has an unexpected type', () => { 29 | const expected = expect(() => { 30 | capitalize() 31 | }) 32 | 33 | expected.toThrow(TypeError) 34 | expected.toThrow(/1st/) 35 | expected.toThrow(/`capitalize`/) 36 | expected.toThrow(/is not defined/) 37 | expected.toThrow(/string is expected/) 38 | }) 39 | }) 40 | -------------------------------------------------------------------------------- /test/string/clean-up-string.test.js: -------------------------------------------------------------------------------- 1 | import cleanUpString from '../../lib/string/clean-up-string' 2 | 3 | describe('cleanUpString main functionality', () => { 4 | it('should clean up a string', () => { 5 | expect(cleanUpString('str\ning ')).toBe('string') 6 | expect(cleanUpString('')).toBe('') 7 | expect(cleanUpString('\n \n\r \r\n')).toBe('') 8 | expect(cleanUpString('\n \n\r hjhj ')).toBe('hjhj') 9 | }) 10 | }) 11 | 12 | describe('cleanUpString arguments validation errors', () => { 13 | it('should throw an error with a friendly message when the first argument has an unexpected type', () => { 14 | const expected = expect(() => { 15 | cleanUpString({}) 16 | }) 17 | 18 | expected.toThrow(TypeError) 19 | expected.toThrow(/1st/) 20 | expected.toThrow(/`cleanUpString`/) 21 | expected.toThrow(/unexpected type/) 22 | expected.toThrow(/string is expected/) 23 | }) 24 | 25 | it('should throw an error with a friendly message when the first argument has an unexpected type', () => { 26 | const expected = expect(() => { 27 | cleanUpString() 28 | }) 29 | 30 | expected.toThrow(TypeError) 31 | expected.toThrow(/1st/) 32 | expected.toThrow(/`cleanUpString`/) 33 | expected.toThrow(/is not defined/) 34 | expected.toThrow(/string is expected/) 35 | }) 36 | }) 37 | -------------------------------------------------------------------------------- /test/utils/helpers.test.js: -------------------------------------------------------------------------------- 1 | import {getOrdinalLetters} from '../../lib/utils/helpers' 2 | 3 | describe('getOrdinalLetters main functionality', () => { 4 | it('should return a number followed by the properly ordinal letters', () => { 5 | expect(getOrdinalLetters(1)).toBe('st') 6 | expect(getOrdinalLetters(2)).toBe('nd') 7 | expect(getOrdinalLetters(3)).toBe('rd') 8 | expect(getOrdinalLetters(4)).toBe('th') 9 | }) 10 | 11 | it('should handle the numbers between 10 and 20', () => { 12 | expect(getOrdinalLetters(10)).toBe('th') 13 | expect(getOrdinalLetters(11)).toBe('th') 14 | expect(getOrdinalLetters(12)).toBe('th') 15 | expect(getOrdinalLetters(13)).toBe('th') 16 | }) 17 | 18 | it('should handle the number zero', () => { 19 | expect(getOrdinalLetters(0)).toBe('th') 20 | }) 21 | 22 | it('should handle the numbers between 20 and 100', () => { 23 | expect(getOrdinalLetters(20)).toBe('th') 24 | expect(getOrdinalLetters(21)).toBe('st') 25 | expect(getOrdinalLetters(22)).toBe('nd') 26 | expect(getOrdinalLetters(23)).toBe('rd') 27 | expect(getOrdinalLetters(24)).toBe('th') 28 | }) 29 | 30 | it('should handle big numbers', () => { 31 | expect(getOrdinalLetters(100)).toBe('th') 32 | expect(getOrdinalLetters(1928)).toBe('th') 33 | expect(getOrdinalLetters(87121)).toBe('st') 34 | }) 35 | }) 36 | --------------------------------------------------------------------------------