├── .editorconfig ├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── browserstack.png ├── karma.conf.js ├── karma.local.conf.js ├── package.json ├── pico-lambda-stats.png ├── src └── index.js └── test ├── parray.test.js ├── pcore.test.js └── pstring.test.js /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | 3 | # A special property that should be specified at the top of the file outside of 4 | # any sections. Set to true to stop .editor config file search on current file 5 | root = true 6 | 7 | [*] 8 | # Indentation style 9 | # Possible values - tab, space 10 | indent_style = space 11 | 12 | # Indentation size in single-spaced characters 13 | # Possible values - an integer, tab 14 | indent_size = 2 15 | 16 | # Line ending file format 17 | # Possible values - lf, crlf, cr 18 | end_of_line = lf 19 | 20 | # File character encoding 21 | # Possible values - latin1, utf-8, utf-16be, utf-16le 22 | charset = utf-8 23 | 24 | # Denotes whether to trim whitespace at the end of lines 25 | # Possible values - true, false 26 | trim_trailing_whitespace = true 27 | 28 | # Denotes whether file should end with a newline 29 | # Possible values - true, false 30 | insert_final_newline = true 31 | 32 | [*.md] 33 | insert_final_newline = false 34 | trim_trailing_whitespace = false 35 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | *.log 3 | scratch.js 4 | .DS_Store 5 | .npmrc 6 | dist 7 | lib 8 | chinaPlate/ -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | 3 | cache: 4 | directories: 5 | - ~/.npm 6 | 7 | git: 8 | depth: 5 9 | 10 | node_js: 11 | - '6' 12 | - '8' 13 | 14 | addons: 15 | browserstack: 16 | username: "mattmcfarland2" 17 | access_key: "8XtpNwsCV785G5gStzgP" 18 | 19 | before_install: 20 | - npm config set spin false --global 21 | 22 | install: 23 | - npm install 24 | 25 | script: 26 | - npm run test:remote 27 | 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017 Ronn Ross 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

pico-lambda

2 | 3 |
4 | λ 5 |
6 |
7 | Arrays, Strings and things the functional way 8 |
9 |
10 | A 640b functional library based on native methods 11 |
12 | 13 |
14 | 15 | 16 | Build Status 18 | 19 | 20 | 21 | Downloads 23 | 24 | 25 | 26 | semistandard 28 | 29 |
30 |
31 | Proudly supported by...
32 | BrowserStack 33 |
34 | 35 | ## Rationale 36 | 37 | We needed to optimize the bundle size of our projects. Since we were already using ES6 and transpiling it, we decided to create a functional library that takes the native Array and String APIs used by major browsers and Nodejs, and make them *functional* - so we can `curry`, `compose`, and `pipe` them. If you are either already transpiling es6 in your project, or you are not supporting older browsers, you should use this instead of `ramda` or `lodash/fp`. If you need to support older browsers, are not transpiling es6, or using es5 - you should use `lodash/fp` or `ramda` 38 | 39 | ## Features 40 | - **Pico:** weighs less than 700 bytes when minified and gzipped. 41 | - **Useful:** takes most native JavaScript array and string methods and makes them *immutable*, *curried*, and *composable*. 42 | - **Functional:** Curry, compose and pipe, Oh My! 43 | - **Familiar:** same names just curried and composable. See [JavaScript Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array) and [JavaScript String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String). 44 | - **Degrades Gracefully:** a small set of these functions are not available in every browser/environment. When not available in the browser it will not be available in Pico Lambda. 45 | 46 | > Pico-lambda was made for the ES6 Javascript Runtime. It has __no dependencies__. 47 | 48 | * * * 49 | 50 | ## Example 51 | 52 | After installing via `npm install`: 53 | 54 | ```js 55 | const {parray, pcore} = require('pico-lambda') 56 | const { 57 | concat, 58 | filter, 59 | map, 60 | reduce, 61 | } = parray 62 | const { 63 | compose 64 | } = pcore 65 | 66 | //concat 67 | const arrayOne = [1, 2, 3]; 68 | const addTwo = concat([4, 5]) 69 | const result = addTwo(arrayOne) 70 | 71 | // We can compose instead of chaining 72 | compose( 73 | reduce((acc, val) => val + acc, 0), 74 | map(x => x * 2), 75 | filter(x => x > 5), 76 | concat([6, 7, 8]) 77 | )([1, 2, 3, 4, 5]) 78 | ``` 79 | 80 | * * * 81 | 82 | ## functions 83 | This table shows compatibility for each of the functions available by browser. *Currently only array functions are listed. String will be added soon.* 84 | If you wish to have full compatibility you can use a transpiler like babel. 85 | 86 |
87 | Table of Compatibility 88 | 89 | 90 | 91 | 94 | 97 | 100 | 103 | 106 | 109 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 |
92 | Function 93 | 95 | Android 5.1+ 96 | 98 | Chrome 52+ 99 | 101 | Edge 13+ 102 | 104 | FF 45+ 105 | 107 | iOS 9+ 108 | 110 | Safari 9+ 111 |
compose
concat
copyWithin
entries
every
fill
filter
find
findIndex
includes
indexOf
join
keys
lastIndexOf
map
pipe
pop
push
reduce
reduceRight
reverse
shift
slice
splice
some
sort
toLocaleString
toString
unshift
378 |
379 | 380 | # API 381 | 382 | The api is broken up into three sections: 383 | * pcore - Basic functional capabilities like curry and compose 384 | * parray - The standard Array.prototype methods setup for functional use 385 | * pstring - The standard String.prototype methods setup for functional use 386 | 387 | One note, parray and pstring have some overlapping function names: 388 | * length 389 | * toString 390 | * slice 391 | * indexOf 392 | * lastIndexOf 393 | * includes 394 | * concat 395 | 396 | Be aware of this when importing these into your global namespace. 397 | 398 | 399 | --- 400 | ## pcore 401 | --- 402 | ### pipe :: `((a -> b), (b -> c), ..., (e -> f)) -> a -> f` 403 | Takes an initial value that is passed to the first function in the parameter list. 404 | The return value of each subsequent function is passed to the following function. 405 | The return value of the last function is returned from pipe. 406 | 407 | ```js 408 | const arr = [1, 2, 3, 4, 5] 409 | pipe( 410 | unshift(0), // (a -> b) 411 | concat([6, 7, 8]) // (b -> c) 412 | )(arr) // => [0, 1, 2, 3, 4, 5, 6, 7, 8] 413 | ``` 414 | ### compose :: `((e -> f), ..., (b -> c), (a -> b)) -> a -> f` 415 | 416 | Evaluates the provided functions, right to left, passing the return value 417 | of each function to the next in line. 418 | The initial function is passed the initial value provided to compose. 419 | The output of the final function, in the above case `(e->f)`, is returned. 420 | 421 | ```js 422 | compose( 423 | map(x => x + 1), // (c -> d) 424 | map(x => x + 1), // (b -> c) 425 | map(x => x + 1) // (a -> b) 426 | )([0]) // (-> a) => 3 427 | ``` 428 | 429 | ### curry :: `(fn) -> fn` 430 | Takes a function and curries the arguments. 431 | 432 | Take note that rest parameters are only partially supported using curry. JS only reports expected parameters, optional and rest parameters are not reported. As a result, there is no way to determine when to expect them. What this means, in practice, is that you can pass rest and/or optional parameters along with the last required param, but you cannot pass them on their own in a new set of parens. See the example below for an illustration of this. 433 | 434 | 435 | ```js 436 | function log4Things(a, b, c, d) { 437 | console.log(a, b, c, d) 438 | } 439 | 440 | const curriedLog = curry(log4Things) 441 | 442 | curriedLog(1, 2, 3, 4) //=> Outputs: 1 2 3 4 443 | curriedLog(1)(2)(3)(4) //=> Outputs: 1 2 3 4 444 | curriedLog(1)(2, 3)(4) //=> Outputs: 1 2 3 4 445 | curriedLog(1)(2)(3)(4) //=> Outputs: 1 2 3 4 446 | curriedLog(1, 2)(3, 4) //=> Outputs: 1 2 3 4 447 | curriedLog(1, 2, 3)(4) //=> Outputs: 1 2 3 4 448 | //You get the idea..... 449 | 450 | const partialLog = curriedLog(1, 2, 3) 451 | partialLog(4) //=> Outputs: 1 2 3 4 452 | partialLog(5) //=> Outputs: 1 2 3 5 453 | 454 | //Using Rest parameters 455 | function log3OrMoreThings(a, b, c, ...d) { 456 | console.log(a, b, c, ...d) 457 | } 458 | const curriedLogMore = curry(log3OrMoreThings) 459 | 460 | curriedLogMore(1, 2, 3) //=> Outputs: 1 2 3 461 | curriedLogMore(1, 2, 3, 4) //=> Outputs: 1 2 3 4 462 | curriedLogMore(1, 2)(3) //=> Outputs: 1 2 3 463 | curriedLogMore(1, 2)(3, 4) //=> Outputs: 1 2 3 4 464 | //However, the following all result in an error 465 | curriedLogMore(1)(2)(3)(4) //Throws: TypeError('curriedLogMore(...)(...)(...) is not a function') 466 | curriedLogMore(1)(2, 3)(4) //Throws: TypeError('curriedLogMore(...)(...)(...) is not a function') 467 | curriedLogMore(1)(2)(3)(4) //Throws: TypeError('curriedLogMore(...)(...)(...) is not a function') 468 | curriedLogMore(1, 2, 3)(4) //Throws: TypeError('curriedLogMore(...)(...)(...) is not a function') 469 | //This is because the curry function calls the original function after the third param and the result is then called as a function with the last grouping, '(4)' in this case 470 | 471 | 472 | ``` 473 | ### identity :: `a -> a` 474 | Takes an argument and returns that arugment. This can be quite useful when composing many functions together. 475 | 476 | ```js 477 | console.log(identity("hi")) //Outputs: hi 478 | 479 | ``` 480 | 481 | --- 482 | ## parray 483 | --- 484 | ### concat :: `[a] -> ([a], ..., [a]) -> [a]` 485 | Concatenates two or more arrays 486 | 487 | ```js 488 | concat([4, 5])([1,2,3]) // => [1, 2, 3, 4, 5] 489 | concat([4, 5])([1,2], [3]) // => [1, 2, 3, 4, 5] 490 | ``` 491 | > See [Array.concat (MDN)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/concat) 492 | 493 | ### copyWithin :: `(Int, Int, Int) -> [a] -> [a]` | `(Int, Int) -> [a] -> [a]` 494 | Makes a shallow copy of part of an array and overwrites another location in the same with the copy. Size is kept constant. 495 | * The first Int is the target index to write the copy to. 496 | * The second Int is the index to start the copy from. 497 | * The third, optional, Int specifies the end of the range to copy (exclusive of the end index). If not provided, it goes to the end of the array. 498 | ```js 499 | const arr = [1, 2, 3, 4, 5] 500 | copyWithin(3, 1)(arr) // => [1, 2, 3, 2, 3] 501 | copyWithin(3, 1, 2)(arr) // => [1, 2, 3, 2, 5] 502 | ``` 503 | > See [Array.copyWithin (MDN)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/copyWithin) 504 | 505 | ### entries:: `[a] -> [b]` 506 | Return an iterator over key, value pairs from the array. 507 | 508 | ```js 509 | const iterator = entries([1, 2, 3, 4, 5]) 510 | iterator.next() // => { value: [0, 1], done: false } 511 | ``` 512 | > See [Array.entries (MDN)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/entries) 513 | 514 | ### every :: `((a, Int, [a]) -> Boolean) -> [a] -> Boolean` 515 | Applies predicate to all elements in array and returns false if any fail. The predicate function must at least take one parameter for each element but may optionally take an index and the entire array as 2nd and 3rd parameters, respectively. 516 | 517 | ```js 518 | const predicate = x => x < 4 519 | every(predicate)([1, 2, 3]) // => true 520 | every(predicate)([1, 2, 3, 4, 5]) // => false 521 | ``` 522 | > See [Array.every (MDN)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/every) 523 | 524 | ### fill :: `(a, Int, Int) -> [a] -> [a]` | `(a) -> [a] -> [a]` 525 | Fills a portion of the given array putting the same new value into each slot. 526 | * The first parameters (a) is the element to add into the array 527 | * The second parameter (Int) is the first index to start filling at. If not supplied it starts at 0. 528 | * The third parameter (Int) is the index to stop filling before (i.e., exclusive). If not supplied fill goes to the end of the array. 529 | 530 | ```js 531 | const arr = [1, 2, 3, 4, 5] 532 | fill(1)(arr) // => [1, 1, 1, 1, 1] 533 | fill(1, 2, 4)(arr) // => [1, 2, 1, 1, 5] 534 | ``` 535 | > See [Array.fill (MDN)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/fill) 536 | 537 | ### filter :: `((a, Int, [a]) -> Boolean) -> [a] -> [a]` 538 | Returns a new array containing only those elements of the given array that pass the given predicate. 539 | 540 | ```js 541 | const predicate = x => x < 3 542 | filter(predicate)([1, 2, 3, 4, 5]) // => [1, 2] 543 | ``` 544 | > See [Array.filter (MDN)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter) 545 | 546 | ### find :: `(a -> Boolean) -> [a] -> a | undefined` 547 | Finds and returns the first element in the given array that matches the given predicate. If no element passes, undefined is returned. 548 | 549 | ```js 550 | const predicate = x => x === 3 551 | find(predicate)([1, 2, 3]) // => 3 552 | find(predicate)([1, 2]) // => undefined 553 | ``` 554 | > See [Array.find (MDN)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find) 555 | 556 | ### findIndex :: `(a -> Boolean) -> [a] -> Int` 557 | Returns the index of the first element in the given array that matches the given predicate. If no element passes, -1 is returned. 558 | 559 | ```js 560 | const arr = [1, 2, 3, 4, 5] 561 | const findIndex = x => x === 3 562 | find(x => x > 3)(arr) // => 3 563 | find(x => x > 80)(arr]) // => -1 564 | ``` 565 | > See [Array.findIndex (MDN)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex) 566 | 567 | ### includes :: `a -> [a] -> Boolean` 568 | Returns true if the given element is in the given array, otherwise false. 569 | 570 | ```js 571 | const animals = ['dog', 'cat', 'ferret', 'hamster'] 572 | const hasCat = includes('cat') 573 | const hasUnicorn = includes('unicorn') 574 | 575 | hasCat(animals) // true 576 | hasUnicorn(animals) // false 577 | ``` 578 | > See [Array.includes (MDN)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/includes) 579 | 580 | ### indexOf :: `(a, Int) -> [a] -> Int` | `(a) -> [a] -> Int` 581 | Returns the index of the given element if it is in the given array, otherwise -1. 582 | The 2nd parameter can be used to change where it starts looking. 583 | 584 | ```js 585 | indexOf(3)([1, 2, 3, 4, 5]) // => 2 586 | indexOf(3, 3)([[1, 2, 3, 4, 5, 3]) // => 3 587 | ``` 588 | > See [Array.indexOf (MDN)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf) 589 | 590 | ### join :: `String -> [a] -> String` 591 | Converts each element of the array to a string and concatenates them together with the given string as a delimiter. 592 | 593 | ```js 594 | join('-')([1, 2, 3]) // => '1-2-3' 595 | ``` 596 | > See [Array.join (MDN)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/join) 597 | 598 | ### keys :: `[a] -> [Int]` 599 | Return an iterator over keys from the array. 600 | 601 | ```js 602 | const iterator = keys([1, 2, 3, 4, 5]) 603 | iterator.next() // => { value: 0, done: false } 604 | ``` 605 | > See [Array.keys (MDN)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/keys) 606 | 607 | ### lastIndexOf :: `(a, Int) -> [a] -> Int` | `(a) -> [a] -> Int` 608 | Works like indexOf but starts at the end and works backwards. 609 | The 2nd parameter can be used to tell it where to start working backwards from. 610 | 611 | ```js 612 | lastIndexOf(1)([1, 2, 3, 1]) // => 3 613 | lastIndexOf(1, -2)([1, 2, 3, 1]) // => 0 614 | ``` 615 | > See [Array.lastIndexOf (MDN)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/lastIndexOf) 616 | 617 | ### map :: `(a -> b) -> [a] -> [b]` 618 | Applies a function over each element in the given array, returning a new array with each function call's results. 619 | 620 | ```js 621 | map(x => x * 2)([1, 2, 3]) // => 2, 4, 6 622 | ``` 623 | > See [Array.map (MDN)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map) 624 | 625 | ### pop :: `[a] -> [a]` 626 | Returns a new array without the last item 627 | 628 | ```js 629 | pop([1, 2, 3, 4, 5]) // => [1, 2, 3, 4] 630 | ``` 631 | > See [Array.pop (MDN)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/pop) 632 | 633 | ### push :: `a -> [a] -> [a]` 634 | Returns a new array with the new element appended to the end of the original array. 635 | 636 | ```js 637 | push(5)([1, 2, 3, 4]) // => [1, 2, 3, 4, 5] 638 | ``` 639 | > See [Array.push (MDN)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/push) 640 | 641 | ### reduce :: `((a, b) -> a) -> a -> [b] -> a` 642 | Applies a function against an accumulator and each value of the array (from left-to-right), then returning the accumulator. 643 | 644 | ```js 645 | const sum = reduce((acc, val) => acc + val, 99) 646 | sum([2, 3, 4]) // => 108 647 | ``` 648 | > See [Array.reduce (MDN)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce) 649 | 650 | ### reduceRight :: `((a, b) -> a) -> a -> [b] -> a` 651 | Applies a function against an accumulator and each value of the array (from right-to-left), then returning the accumulator. 652 | 653 | ```js 654 | const sum = reduceRight((acc, val) => acc + val, 99) 655 | sum([2, 3, 4]) // => 90 656 | ``` 657 | > See [Array.reduceRight (MDN)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduceRight) 658 | 659 | ### reverse :: `[a] -> [a]` 660 | Returns a new array with the elements in reverse order. 661 | 662 | ```js 663 | reverse([1, 2, 3, 4, 5]) // => [5, 4, 3, 2, 1] 664 | ``` 665 | > See [Array.reverse (MDN)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reverse) 666 | 667 | ### shift :: `[a] -> [a]` 668 | Returns a new array with the first element removed. 669 | 670 | ```js 671 | shift([1, 2, 3, 4, 5]) // => [2, 3, 4, 5] 672 | ``` 673 | > See [Array.shift (MDN)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/shift) 674 | 675 | ### slice :: `(int, int) -> [a] -> [a]` 676 | Takes a slice from a given array and returns it as a new array. 677 | 678 | ```js 679 | const removeFirst = slice(1) 680 | removeFirst([2, 3, 4]) // => [3, 4] 681 | ``` 682 | > See [Array.slice (MDN)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice) 683 | 684 | ### splice :: `(int, int, [a]) -> [a] -> [a]` 685 | Returns a new array with the indicated elements removed. An optional set of new elements can be inserted in their place. 686 | ```js 687 | const takeTwo = splice(2) 688 | takeTwo([1, 2, 3, 4, 5]) // => [1, 2] 689 | 690 | ``` 691 | > See [Array.splice (MDN)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice) 692 | 693 | ### some :: `(a -> Boolean) -> [a] -> Boolean` 694 | Returns true if any element in the given array matches the given predicate. 695 | 696 | ```js 697 | const lessThanFour = some(x => x < 4) 698 | lessThanFour([1, 2, 3, 4, 5]) // => true 699 | ``` 700 | > See [Array.some (MDN)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some) 701 | 702 | ### sort :: `((a, a) -> int) -> [a] -> [a]` 703 | Returns a copy of the original array with the values sorted. If a comparator function is provided it should return -1, 0 or 1 depending on whether the first element is less than, equal to or greater than the second, respectively. If no comparator is given, lexical sorting is used. 704 | 705 | ```js 706 | const numComp = (a, b) => (a < b) ? -1 : (a === b) ? 0 : 1 707 | const sortBy = sort(numComp) 708 | sortBy([20, 1, 3, 4, 2]) // => [1, 2, 3, 4, 20] 709 | ``` 710 | > See [Array.sort (MDN)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort) 711 | 712 | ### toLocaleString :: `(String, Obj) -> [a] -> String` 713 | Converts each element of an array into a string based on current locale settings or locale options passed in. The resulting strings are appended together using commas. 714 | 715 | ```js 716 | const toYen = toLocaleString('ja-JP', { style: 'currency', currency: 'JPY' }) 717 | toYen(["¥7", 500, 8123, 12]) // => ¥7,500,8,123,12 718 | ``` 719 | > See [Array.toLocaleString (MDN)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/toLocaleString) 720 | 721 | ### toString :: `[a] -> String` 722 | Converts each element of an array into a string and appends them together with a comma. 723 | 724 | ```js 725 | toString([1, 2, 3, 4, 5]) // => '1,2,3,4,5' 726 | ``` 727 | > See [Array.toString (MDN)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/toString) 728 | 729 | ### unshift :: `a -> [a] -> [a]` 730 | Returns a new copy of an array with the given element added to the front. 731 | 732 | ```js 733 | const addOne = unshift(1) 734 | addOne([2, 3]) // => [1, 2, 3] 735 | ``` 736 | > See [Array.unshift (MDN)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/unshift) 737 | 738 | ## Where are ...? 739 | - `length` - This is a property, not a method, so it doesn't really belong here. 740 | - `forEach` - This is inherently side-effect-y, it adds nothing that can't be done with `filter`, `map` and `reduce`. 741 | 742 | If you don't agree with anything above that's great! Just log an issue so we can discuss. 743 | 744 | --- 745 | ## pstring 746 | --- 747 | ### charAt :: `Int -> String -> String` 748 | Returns the character at the given position in the string. 749 | 750 | ```js 751 | charAt(2)("123")) //=> "3" 752 | ``` 753 | > See [String.charAt (MDN)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/charAt) 754 | ### charCodeAt :: `Int -> String -> Int` 755 | Returns the character code at the given position in the string. 756 | 757 | ```js 758 | charAt(2)("123")) //=> 51 759 | 760 | ``` 761 | > See [String.charCodeAt (MDN)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/charCodeAt) 762 | ### codePointAt :: `Int -> String -> Int` 763 | Returns the unicode code point at the given index. 764 | 765 | ```js 766 | codePointAt(0)("\uD800\uDC00")) //=> 65536 767 | ``` 768 | > See [String.codePointAt (MDN)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/codePointAt) 769 | ### concat :: `(String, ...String) -> String -> String` 770 | Returns a new string combining the given strings. Multiple strings can be passed to the initial call. 771 | 772 | ```js 773 | const stringOne = "123" 774 | const addTwo = concat("45", "67") 775 | const result = addTwo(stringOne) //result = "1234567" 776 | ``` 777 | > See [String.concat (MDN)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/concat) 778 | ### endsWith :: `String -> String -> Boolean` | `(String, Int) -> String -> String` 779 | Returns true if the second string ends with the characters in the first. If the integer parameter is passed, the second string is considered to be only that long (or the length of the second string itself whichever is shorter) 780 | 781 | ```js 782 | endsWith("bc")("abc") //=> true 783 | endsWith("bc", 2)("abc") //=> false 784 | endsWith("bc")("abcd") //=> false 785 | ``` 786 | > See [String.endsWidth (MDN)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/endsWidth) 787 | ### includes :: `String -> String -> Boolean` | `(String, Int) -> String -> Boolean` 788 | Returns true if the characters from the first string appear together as a substring in the second. If the integer is provided it indicates where to start searching in the second string. 789 | 790 | ```js 791 | includes("not to be,")("To be, or not to be, that is the question.") //=> true 792 | includes("not to be,", 20)("To be, or not to be, that is the question.") //=> false 793 | includes("nonexistent")("To be, or not to be, that is the question.") //=> false 794 | ``` 795 | > See [String.includes (MDN)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/includes) 796 | ### indexOf :: `String -> String -> Int` | `(String, Int) -> String -> Int` 797 | Returns the first index where the second string appears as a substring of the first. Optionally you can provide a starting index and the search will start there. If the first string is not found it returns -1 798 | 799 | ```js 800 | indexOf("a")("abc") //=> 0 801 | indexOf("b")("abc") //=> 1 802 | indexOf("c")("abc") //=> 2 803 | indexOf("z")("abc") //=> -1 804 | ``` 805 | > See [String.indexOf (MDN)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/indexOf) 806 | ### lastIndexOf :: `String -> String -> Int` | `(String, Int) -> String -> Int` 807 | Works like index of but starting at the end and working forward. 808 | 809 | ```js 810 | lastIndexOf("a")("abc") //=> 0 811 | lastIndexOf("b")("abc") //=> 1 812 | lastIndexOf("c")("abc") //=> 2 813 | lastIndexOf("z")("abc") //=> -1 814 | ``` 815 | > See [String.lastIndexOf (MDN)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/lastIndexOf) 816 | ### localeCompare :: `String -> String -> Int` | `(String, String) -> String -> Int` | `(String, String, Object) -> String -> Int` 817 | Compares two strings taking the locale into account. The return value will be negative if the second string comes before the first. Positive if it comes later. And zero if they are equal. The additional, optional parameters allow a locale and other options to be specified. 818 | 819 | ```js 820 | localeCompare("b")("a") //=> <0 821 | localeCompare("a")("b") //=> >0 822 | localeCompare("a")("a") //=> 0 823 | localeCompare('a', 'de', { sensitivity: 'base' })('ä') //=> 0 824 | ``` 825 | > See [String.localeCompare (MDN)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/localeCompare) 826 | ### match :: `Regexp -> String -> [String]` 827 | Returns an array of strings for the value matched by the regular expression as well as all matching groups defined therein. 828 | 829 | ```js 830 | const str = 'For more information, see Chapter 3.4.5.1' 831 | const re = /see (chapter \d+(\.\d)*)/i 832 | match(re)(str) //=> ["see Chapter 3.4.5.1", "Chapter 3.4.5.1", ".1"] 833 | ``` 834 | > See [String.match (MDN)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/match) 835 | ### normalize :: `String -> String` 836 | Returns the Unicode Normalization Form of a string. 837 | 838 | ```js 839 | normalize('NFKC')('\u1E9B\u0323') //=> '\u1E69' 840 | ``` 841 | > See [String.normalize (MDN)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/normalize) 842 | ### repeat :: `Int -> String -> String` 843 | Returns string comprised of the given number of repeats of the given string. 844 | 845 | ```js 846 | repeat(2)('abc') //=> 'abcabc' 847 | ``` 848 | > See [String.repeat (MDN)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/repeat) 849 | ### replace :: `(Regexp, String) -> String -> String` 850 | Replaces all locations in the second string that match the given regular expression with the value in the first string. Back references in the first string will be filled appropriately. 851 | 852 | ```js 853 | replace(/xmas/i, 'Christmas')('Twas the night before Xmas...')) //=> 'Twas the night before Christmas...' 854 | ``` 855 | > See [String.replace (MDN)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace) 856 | ### search :: `Regexp -> String -> String` 857 | Returns the first position where given regular expression matches in the second string. If it doesn't match, -1 is returned. 858 | 859 | ```js 860 | search(/xmas/i)('Twas the night before Xmas...')) //=> 22 861 | ``` 862 | > See [String.search (MDN)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/search) 863 | ### slice :: `Int -> String -> String` | `(Int, Int) -> String -> String` 864 | Returns a substring of the second string defined by the given index and optional end index. Either may be negative to count from the end of the string. 865 | 866 | ```js 867 | slice(4, -2)('Twas the night before Xmas...') //=> ' the night before Xmas.' 868 | ``` 869 | > See [String.slice (MDN)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/slice) 870 | ### split :: `String -> String -> [String]` | `(String, Int) -> String -> [String]` 871 | Splits a string into an array of substrings that are separated by the first string given. If the integer parameter is provided the split will stop at the given limit. 872 | 873 | ```js 874 | split(',')("1,2") //=> ['1', '2'] 875 | split(',', 2)("1,2,3,4") //=> ['1', '2'] 876 | ``` 877 | > See [String.split (MDN)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/split) 878 | ### startsWith :: `String -> String -> Boolean` | `(String, Int) -> String -> Boolean` 879 | Returns true if the second string starts with the characters in the first. If the integer parameter is passed, the second string is considered to start at that position 880 | 881 | ```js 882 | startsWith("ab")("abc") //=> true 883 | startsWith("bc")("abcd") //=> false 884 | ``` 885 | > See [String.startsWith (MDN)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/startsWith) 886 | ### substr :: `Int -> String` | `(Int, Int) -> String` 887 | Returns the characters in a string beginning at the specified location through the specified number of characters. 888 | 889 | ```js 890 | substr(2)("abcde") //=> 'cde' 891 | substr(2, 2)("abcde") //=> 'cd' 892 | ``` 893 | > See [String.substr (MDN)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/substr) 894 | ### substring :: `Int -> String` | `(Int, Int) -> String` 895 | Returns a subset of a string between one index and another, or through the end of the string. 896 | 897 | ```js 898 | substring(2)("abcde") //=> 'cde' 899 | substring(2, 4)("abcde") //=> 'cd' 900 | ``` 901 | > See [String.substring (MDN)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/substring) 902 | ### toLocaleLowerCase :: `String -> String` 903 | Returns the primitive value of a string. 904 | 905 | ```js 906 | 907 | ``` 908 | > See [String.toLocaleLowerCase (MDN)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/toLocaleLowerCase) 909 | ### toLocaleUpperCase :: `String -> String` 910 | Returns the calling string value converted to lower case, according to any locale-specific case mappings. 911 | 912 | ```js 913 | toLocaleLowerCase("ABC") //=> 'abc' 914 | ``` 915 | > See [String.toLocaleUpperCase (MDN)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/toLocaleUpperCase) 916 | ### toLowerCase :: `String -> String` 917 | Returns the primitive value of a string. 918 | 919 | ```js 920 | toLocaleLowerCase("ABC") //=> 'abc' 921 | ``` 922 | > See [String.toLowerCase (MDN)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/toLowerCase) 923 | ### toString :: `String -> String` 924 | Returns the calling string value converted to upper case, according to any locale-specific case mappings. 925 | 926 | ```js 927 | toLocaleUpperCase("abc") //=> 'ABC' 928 | ``` 929 | > See [String.toString (MDN)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/toString) 930 | ### toUpperCase :: `String -> String` 931 | Returns the calling string value converted to upper case. 932 | 933 | ```js 934 | toUpperCase("abc") //=> 'ABC' 935 | ``` 936 | > See [String.toUpperCase (MDN)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/toUpperCase) 937 | ### trim :: `String -> String` 938 | Removes whitespace from both ends of a string. Whitespace in this context is all the whitespace characters (space, tab, no-break space, etc.) and all the line terminator characters (LF, CR, etc.). 939 | 940 | ```js 941 | trim(" abc ") //=> 'abc' 942 | ``` 943 | > See [String.trim (MDN)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/trim) 944 | ### trimLeft :: `String -> String` 945 | Removes whitespace from the left end of a string. Whitespace in this context is all the whitespace characters (space, tab, no-break space, etc.) and all the line terminator characters (LF, CR, etc.). 946 | 947 | ```js 948 | trimLeft(" abc ") //=> 'abc ' 949 | ``` 950 | > See [String.trimLeft (MDN)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/trimLeft) 951 | ### trimRight :: `String -> String` 952 | Removes whitespace from the left end of a string. Whitespace in this context is all the whitespace characters (space, tab, no-break space, etc.) and all the line terminator characters (LF, CR, etc.). 953 | 954 | ```js 955 | trimRight(" abc ") //=> ' abc' 956 | ``` 957 | > See [String.trimRight (MDN)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/trimRight) 958 | ### valueOf :: `String -> String` 959 | Returns the primitive value of a string. 960 | 961 | ```js 962 | valueOf("abc") //=> 'abc' 963 | ``` 964 | > See [String.valueOf (MDN)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/valueOf) 965 | -------------------------------------------------------------------------------- /browserstack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trainyard/pico-lambda/9ba7fd972c911fd28e74874babcf3fef28eeaa74/browserstack.png -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | module.exports = function(config) { 2 | config.set({ 3 | // global config of your BrowserStack account 4 | browserStack: { 5 | username: 'mattmcfarland2', 6 | accessKey: '8XtpNwsCV785G5gStzgP', 7 | build: process.env.TRAVIS_BUILD_NUMBER || process.env.BUILD, 8 | }, 9 | logLevel: global.LOG_INFO || 'LOG_INFO', 10 | singleRun: true, 11 | basePath: './', 12 | files: ['dist/index.js', 'test/*.js'], 13 | frameworks: ['jasmine'], 14 | // define browsers 15 | customLaunchers: { 16 | bs_chrome_win10: { 17 | base: 'BrowserStack', 18 | browser: 'chrome', 19 | browser_version: 'latest', 20 | os: 'Windows', 21 | os_version: '10' 22 | }, 23 | bs_edge_win10: { 24 | base: 'BrowserStack', 25 | browser: 'edge', 26 | browser_version: 'latest', 27 | os: 'Windows', 28 | os_version: '10' 29 | }, 30 | bs_firefox_win10: { 31 | base: 'BrowserStack', 32 | browser: 'firefox', 33 | browser_version: 'latest', 34 | os: 'Windows', 35 | os_version: '10' 36 | }, 37 | bs_safari_mac: { 38 | base: 'BrowserStack', 39 | browser: 'safari', 40 | browser_version: 'latest', 41 | os: 'OS X', 42 | os_version: 'Sierra' 43 | }, 44 | }, 45 | 46 | browsers: ['bs_chrome_win10', 'bs_edge_win10', 'bs_firefox_win10', 'bs_safari_mac'] 47 | }) 48 | } 49 | -------------------------------------------------------------------------------- /karma.local.conf.js: -------------------------------------------------------------------------------- 1 | module.exports = function(config) { 2 | config.set({ 3 | logLevel: global.LOG_INFO || 'LOG_INFO', 4 | singleRun: true, 5 | basePath: './', 6 | files: ['dist/index.js', 'test/*.js'], 7 | frameworks: ['jasmine'] 8 | }) 9 | } 10 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pico-lambda", 3 | "version": "2.1.0", 4 | "description": "native functional js", 5 | "main": "src/index.js", 6 | "scripts": { 7 | "clean": "rm -rf dist ; mkdir dist ;", 8 | "build": "npm run clean ; browserify -e src/index.js -o dist/index.js -t [ babelify --presets [ es2015 ] ] -s PicoLambda", 9 | "test": "jasmine test/*.test.js", 10 | "test:chrome": "karma start karma.local.conf.js --browsers Chrome", 11 | "test:remote": "npm run build ; npm run lint && BUILD=$(git rev-parse --short HEAD) karma start karma.conf.js", 12 | "lint": "semistandard src/index.js test/test.js --fix | snazzy", 13 | "watch": "nodemon --exec 'jasmine' test/test.js" 14 | }, 15 | "keywords": [ 16 | "functional", 17 | "fp", 18 | "lambda", 19 | "tiny", 20 | "pico" 21 | ], 22 | "contributors": [ 23 | { 24 | "email": "ronn.ross@gmail.com", 25 | "name": "Ronn Ross", 26 | "url": "https://github.com/ronnross" 27 | }, 28 | { 29 | "email": "contact@mattmcfarland.com", 30 | "name": "Matt McFarland", 31 | "url": "https://github.com/mattmcfarland" 32 | }, 33 | { 34 | "email": "bobrien@gmail.com", 35 | "name": "Brendan O'Brien", 36 | "url": "https://github.com/ChanEilFhios" 37 | }, 38 | { 39 | "email": "sherman.adelson@gmail.com", 40 | "name": "Sherman Adelson", 41 | "url": "https://github.com/mnebuerquo" 42 | } 43 | ], 44 | "repository": { 45 | "type": "git", 46 | "url": "git+https://github.com/trainyard/pico-lambda.git" 47 | }, 48 | "license": "MIT", 49 | "devDependencies": { 50 | "babel-preset-es2015": "^6.24.1", 51 | "babelify": "^7.3.0", 52 | "install": "^0.10.1", 53 | "jasmine": "2.5.3", 54 | "jasmine-node": "1.14.5", 55 | "jasmine-spec-reporter": "3.2.0", 56 | "karma": "^1.4.1", 57 | "karma-browserstack-launcher": "^1.2.0", 58 | "karma-chrome-launcher": "^2.2.0", 59 | "karma-cli": "^1.0.1", 60 | "karma-jasmine": "^1.1.0", 61 | "karma-safari-launcher": "^1.0.0", 62 | "nodemon": "1.11.0", 63 | "npm": "^5.5.1", 64 | "semistandard": "^9.2.1", 65 | "snazzy": "6.0.0", 66 | "strip-comments": "0.4.4" 67 | }, 68 | "files": [ 69 | "src" 70 | ], 71 | "dependencies": { 72 | "browserify": "^14.4.0" 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /pico-lambda-stats.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trainyard/pico-lambda/9ba7fd972c911fd28e74874babcf3fef28eeaa74/pico-lambda-stats.png -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | const ctx = module 2 | ? module.exports 3 | : (typeof window !== 'undefined') 4 | ? window 5 | : {}; 6 | 7 | const c = (fn, ...params) => fn.length <= params.length ? fn(...params) : (...others) => c(fn, ...params, ...others); 8 | const cp = method => (...fns) => initialValue => fns[method]((value, fn) => fn(value), initialValue); 9 | 10 | ctx.pcore = { 11 | curry: c, 12 | compose: cp('reduceRight'), 13 | pipe: cp('reduce'), 14 | identity: a => a 15 | }; 16 | 17 | ctx.pstring = Object 18 | .getOwnPropertyNames(String.prototype) 19 | .reduce((lambda, method) => { 20 | lambda[method] = (~['charAt', 'charCodeAt', 'lastIndexOf', 'localeCompare', 'normalize', 'substr', 'substring', 'codePointAt', 'concat', 'endsWith', 'includes', 'indexOf', 'match', 'repeat', 'replace', 'search', 'slice', 'split', 'startsWith'].indexOf(method)) 21 | ? (...params) => a => a[method](...params) 22 | : (~['toString', 'trim', 'trimLeft', 'trimRight', 'valueOf', 'toLowerCase', 'toUpperCase', 'toLocaleLowerCase', 'toLocaleUpperCase'].indexOf(method)) 23 | ? a => a[method]() 24 | : lambda[method]; 25 | return lambda; 26 | }, {}); 27 | 28 | ctx.parray = Object 29 | .getOwnPropertyNames(Array.prototype) 30 | .reduce((lambda, method) => { 31 | lambda[method] = (~['concat', 'every', 'filter', 'find', 'findIndex', 'includes', 'join', 'map', 'reduce', 'reduceRight', 'slice', 'some'].indexOf(method)) 32 | ? (fn, ...params) => arr => arr[method](fn, ...params) 33 | : (~['sort', 'copyWithin', 'fill'].indexOf(method)) 34 | ? (...params) => arr => [...arr][method](...params) 35 | : (~['toLocaleString', 'indexOf', 'lastIndexOf'].indexOf(method)) 36 | ? (...params) => arr => arr[method](...params) 37 | : (~['push', 'splice'].indexOf(method)) 38 | ? (...params) => arr => { var t = [...arr]; t[method](...params); return t; } 39 | : (~['toString', 'entries', 'keys'].indexOf(method)) 40 | ? arr => arr[method]() 41 | : lambda[method]; 42 | return lambda; 43 | }, { 44 | pop: arr => arr.slice(0, -1), 45 | shift: arr => arr.slice(1), 46 | unshift: params => arr => [params, ...arr], 47 | reverse: arr => [...arr].reverse() 48 | }); 49 | -------------------------------------------------------------------------------- /test/parray.test.js: -------------------------------------------------------------------------------- 1 | const { parray } = init(); 2 | 3 | function init () { 4 | if (typeof window !== 'undefined') { 5 | return { 6 | parray: window.PicoLambda.parray, 7 | } 8 | } 9 | if (typeof window === 'undefined') { 10 | const SpecReporter = require('jasmine-spec-reporter').SpecReporter; 11 | 12 | global.jasmine.getEnv().clearReporters(); // remove default reporter logs 13 | global.jasmine.getEnv().addReporter(new SpecReporter({ // add jasmine-spec-reporter 14 | spec: { 15 | displayPending: true 16 | } 17 | })); 18 | return { 19 | parray: require('../src/index.js').parray, 20 | } 21 | } 22 | } 23 | 24 | describe('api: concat', () => { 25 | if (!parray.concat) return; 26 | it('should add array of items to end of array', () => { 27 | const arrayOne = [1, 2, 3]; 28 | const addTwo = parray.concat([4, 5]); 29 | const result = (addTwo(arrayOne)); 30 | expect(result).toEqual([1, 2, 3, 4, 5]); 31 | }); 32 | 33 | it('should add single item to end of array', () => { 34 | const arrayOne = [3, 2]; 35 | const addOne = parray.concat(1); 36 | const result = (addOne(arrayOne)); 37 | expect(result).toEqual([3, 2, 1]); 38 | }); 39 | 40 | it('should not alter the original array', () => { 41 | const arrayOne = [3, 2]; 42 | const addOne = parray.concat(1); 43 | addOne(arrayOne); 44 | expect(arrayOne).toEqual([3, 2]); 45 | }); 46 | }); 47 | 48 | describe('api: copyWithin', () => { 49 | if (!parray.copyWithin) return; 50 | it('should overwrite from target to end of array with selected elements', () => { 51 | var arr = [1, 2, 3, 4, 5]; 52 | const result = parray.copyWithin(3, 1)(arr); 53 | expect(result).toEqual([1, 2, 3, 2, 3]); 54 | }); 55 | it('should overwrite from target to indicated end with selected elements', () => { 56 | var arr = [1, 2, 3, 4, 5]; 57 | const result = parray.copyWithin(3, 1, 2)(arr); 58 | expect(result).toEqual([1, 2, 3, 2, 5]); 59 | }); 60 | it('should not alter the original array', () => { 61 | var arr = [1, 2, 3, 4, 5]; 62 | parray.copyWithin(3, 1, 2)(arr); 63 | expect(arr).toEqual([1, 2, 3, 4, 5]); 64 | }); 65 | }); 66 | 67 | describe('api: entries', () => { 68 | if (!parray.entries) return; 69 | it('should return an interator that contains key values pair of given array', () => { 70 | const arr = [1, 2, 3, 4, 5]; 71 | const iterator = parray.entries(arr); 72 | expect(iterator.next()).toEqual({ value: [0, 1], done: false }); 73 | }); 74 | it('should not alter the original array', () => { 75 | const arr = [1, 2, 3, 4, 5]; 76 | const iterator = parray.entries(arr); 77 | iterator.next(); 78 | iterator.next(); 79 | expect(arr).toEqual([1, 2, 3, 4, 5]); 80 | }); 81 | }); 82 | 83 | describe('api: every', () => { 84 | if (!parray.every) return; 85 | it('should return false if any items do not pass predicate', () => { 86 | const arr = [1, 2, 3, 4, 5]; 87 | const areAllAreLessThanFour = parray.every(x => x < 4); 88 | const result = (areAllAreLessThanFour(arr)); 89 | expect(result).toEqual(false); 90 | }); 91 | 92 | it('should return true if all items pass predicate', () => { 93 | const arr = [1, 2, 3]; 94 | const areAllAreLessThanFour = parray.every(x => x < 4); 95 | const result = (areAllAreLessThanFour(arr)); 96 | expect(result).toEqual(true); 97 | }); 98 | 99 | it('should not alter the original array', () => { 100 | const arr = [1, 2, 3]; 101 | const areAllAreLessThanFour = parray.every(x => x < 4); 102 | (areAllAreLessThanFour(arr)); 103 | expect(arr).toEqual([1, 2, 3]); 104 | }); 105 | }); 106 | 107 | describe('api: fill', () => { 108 | if (!parray.fill) return; 109 | it('should overwrite each element of an array with supplied param', () => { 110 | var arr = [1, 2, 3, 4, 5]; 111 | const result = parray.fill(1)(arr); 112 | expect(result).toEqual([1, 1, 1, 1, 1]); 113 | }); 114 | it('should overwrite selected elements of an array with supplied params', () => { 115 | var arr = [1, 2, 3, 4, 5]; 116 | const result = parray.fill(1, 2, 4)(arr); 117 | expect(result).toEqual([1, 2, 1, 1, 5]); 118 | }); 119 | it('should not alter the original array', () => { 120 | var arr = [1, 2, 3, 4, 5]; 121 | parray.fill(1)(arr); 122 | expect(arr).toEqual([1, 2, 3, 4, 5]); 123 | }); 124 | }); 125 | 126 | describe('api: filter', () => { 127 | if (!parray.filter) return; 128 | it('should return items that pass the predicate', () => { 129 | const arr = [1, 2, 3, 4, 5]; 130 | const numsUnderThree = parray.filter(x => x < 3); 131 | const result = (numsUnderThree(arr)); 132 | expect(result).toEqual([1, 2]); 133 | }); 134 | it('should not alter the original array', () => { 135 | const arr = [1, 2, 3, 4, 5]; 136 | const numsUnderThree = parray.filter(x => x < 3); 137 | (numsUnderThree(arr)); 138 | expect(arr).toEqual([1, 2, 3, 4, 5]); 139 | }); 140 | }); 141 | 142 | describe('api: find', () => { 143 | if (!parray.find) return; 144 | it('should return first item that passes the predicate', () => { 145 | const arr = [1, 2, 3, 4, 5]; 146 | const isThree = parray.find(x => x === 3); 147 | const result = (isThree(arr)); 148 | expect(result).toEqual(3); 149 | }); 150 | it('should return undefined when no item passes the predicate', () => { 151 | const arr = [1, 2, 3, 4, 5]; 152 | const isThree = parray.find(x => x === 8); 153 | const result = (isThree(arr)); 154 | expect(result).toEqual(undefined); 155 | }); 156 | it('should not alter the original array', () => { 157 | const arr = [1, 2, 3, 4, 5]; 158 | const isThree = parray.find(x => x === 3); 159 | (isThree(arr)); 160 | expect(arr).toEqual([1, 2, 3, 4, 5]); 161 | }); 162 | }); 163 | 164 | describe('api: findIndex', () => { 165 | if (!parray.findIndex) return; 166 | it('should return index of first item that passes the predicate', () => { 167 | const arr = [1, 2, 3, 4, 5]; 168 | const gtThree = parray.findIndex(x => x > 3); 169 | const result = gtThree(arr); 170 | expect(result).toEqual(3); 171 | }); 172 | 173 | it('should return -1 when no item passes the predicate', () => { 174 | const arr = [1, 2, 3, 4, 5]; 175 | const gtThree = parray.findIndex(x => x > 80); 176 | const result = gtThree(arr); 177 | expect(result).toEqual(-1); 178 | }); 179 | it('should not alter the original array', () => { 180 | const arr = [1, 2, 3, 4, 5]; 181 | const gtThree = parray.findIndex(x => x > 80); 182 | gtThree(arr); 183 | expect(arr).toEqual([1, 2, 3, 4, 5]); 184 | }); 185 | }); 186 | 187 | describe('api: includes', () => { 188 | if (!parray.includes) return; 189 | it('should return true when an item is found in array', () => { 190 | const arr = [1, 2, 3, 4, 5]; 191 | const isThree = parray.includes(3); 192 | const result = isThree(arr); 193 | expect(result).toEqual(true); 194 | }); 195 | 196 | it('should return false when an item is not found in array', () => { 197 | const arr = [1, 2, 3, 4, 5]; 198 | const isThree = parray.includes(8); 199 | const result = isThree(arr); 200 | expect(result).toEqual(false); 201 | }); 202 | it('should not alter the original array', () => { 203 | const arr = [1, 2, 3, 4, 5]; 204 | const isThree = parray.includes(8); 205 | isThree(arr); 206 | expect(arr).toEqual([1, 2, 3, 4, 5]); 207 | }); 208 | }); 209 | 210 | describe('api: indexOf', () => { 211 | if (!parray.indexOf) return; 212 | it('should return the indexOf item', () => { 213 | const arr = [1, 2, 3, 4, 5]; 214 | const result = parray.indexOf(3)(arr); 215 | expect(result).toEqual(2); 216 | }); 217 | it('should return the indexOf item found after second arg', () => { 218 | const arr = [1, 2, 3, 4, 5, 3]; 219 | const result = parray.indexOf(3, 3)(arr); 220 | expect(result).toEqual(5); 221 | }); 222 | it('should not alter the original array', () => { 223 | const arr = [1, 2, 3, 4, 5]; 224 | parray.indexOf(3)(arr); 225 | expect(arr).toEqual([1, 2, 3, 4, 5]); 226 | }); 227 | }); 228 | 229 | describe('api: join', () => { 230 | if (!parray.join) return; 231 | it('should return a string with each item separated with character passed in', () => { 232 | var arr = [1, 2, 3, 4, 5]; 233 | const separateByDash = parray.join('-'); 234 | const result = separateByDash(arr); 235 | expect(result).toEqual('1-2-3-4-5'); 236 | }); 237 | it('should not alter the original array', () => { 238 | var arr = [1, 2, 3, 4, 5]; 239 | const separateByDash = parray.join('-'); 240 | separateByDash(arr); 241 | expect(arr).toEqual([1, 2, 3, 4, 5]); 242 | }); 243 | }); 244 | 245 | describe('api: keys', () => { 246 | if (!parray.keys) return; 247 | it('should return an iterator of keys of given array', () => { 248 | const arr = [1, 2, 3, 4, 5]; 249 | const iterator = parray.keys(arr); 250 | expect(iterator.next()).toEqual({ value: 0, done: false }); 251 | }); 252 | it('should not alter the original array', () => { 253 | const arr = [1, 2, 3, 4, 5]; 254 | const iterator = parray.keys(arr); 255 | iterator.next(); 256 | iterator.next(); 257 | expect(arr).toEqual([1, 2, 3, 4, 5]); 258 | }); 259 | }); 260 | 261 | describe('api: lastIndexOf', () => { 262 | if (!parray.lastIndexOf) return; 263 | it('should find the index of the last occurrence of an element', () => { 264 | var arr = [1, 2, 3, 1]; 265 | const result = parray.lastIndexOf(1)(arr); 266 | expect(result).toEqual(3); 267 | }); 268 | it('should find the index of the last occurrence of an element, starting at a given index.', () => { 269 | var arr = [1, 2, 3, 1]; 270 | const result = parray.lastIndexOf(1, -2)(arr); 271 | expect(result).toEqual(0); 272 | }); 273 | it('should not alter the original array', () => { 274 | var arr = [1, 2, 3, 1]; 275 | parray.lastIndexOf(1)(arr); 276 | expect(arr).toEqual([1, 2, 3, 1]); 277 | }); 278 | }); 279 | 280 | describe('api: map', () => { 281 | if (!parray.map) return; 282 | it('applies function to items in array', () => { 283 | const double = parray.map(x => x * 2); 284 | const result = double([1, 2, 3]); 285 | expect(result).toEqual([2, 4, 6]); 286 | }); 287 | it('should not alter the original array', () => { 288 | var arr = [1, 2, 3]; 289 | const double = parray.map(x => x * 2); 290 | double(arr); 291 | expect(arr).toEqual([1, 2, 3]); 292 | }); 293 | }); 294 | 295 | describe('api: reduce', () => { 296 | if (!parray.reduce) return; 297 | it('applies function to each item and accums results from left to right', () => { 298 | const sum = parray.reduce((acc, val) => acc + val, 99); 299 | const total = sum([2, 3, 4]); 300 | expect(total).toEqual(108); 301 | }); 302 | it('should not alter the original array', () => { 303 | var arr = [2, 3, 4]; 304 | const sum = parray.reduce((acc, val) => acc + val, 99); 305 | sum(arr); 306 | expect(arr).toEqual([2, 3, 4]); 307 | }); 308 | }); 309 | 310 | describe('api: reduce right', () => { 311 | if (!parray.reduceRight) return; 312 | it('applies function to each item and accums results from right to left', () => { 313 | const sum = parray.reduceRight((acc, val) => acc - val, 99); 314 | const total = sum([2, 3, 4]); 315 | expect(total).toEqual(90); 316 | }); 317 | it('should not alter the original array', () => { 318 | var arr = [2, 3, 4]; 319 | const sum = parray.reduceRight((acc, val) => acc - val, 99); 320 | sum(arr); 321 | expect(arr).toEqual([2, 3, 4]); 322 | }); 323 | }); 324 | 325 | describe('api: slice', () => { 326 | if (!parray.slice) return; 327 | it('returns new but sliced array', () => { 328 | const removeFirst = parray.slice(1); 329 | const result = removeFirst([2, 3, 4]); 330 | expect(result).toEqual([3, 4]); 331 | }); 332 | it('should not alter the original array', () => { 333 | var arr = [2, 3, 4]; 334 | const removeFirst = parray.slice(1); 335 | removeFirst(arr); 336 | expect(arr).toEqual([2, 3, 4]); 337 | }); 338 | }); 339 | 340 | describe('api: some', () => { 341 | if (!parray.some) return; 342 | it('should return true if at least one items passes predicate', () => { 343 | const arr = [1, 2, 3, 4, 5]; 344 | const areAllAreLessThanFour = parray.some(x => x < 4); 345 | const result = areAllAreLessThanFour(arr); 346 | expect(result).toEqual(true); 347 | }); 348 | it('should not alter the original array', () => { 349 | const arr = [1, 2, 3, 4, 5]; 350 | const areAllAreLessThanFour = parray.some(x => x < 4); 351 | (areAllAreLessThanFour(arr)); 352 | expect(arr).toEqual([1, 2, 3, 4, 5]); 353 | }); 354 | }); 355 | 356 | describe('api: reverse', () => { 357 | if (!parray.reverse) return; 358 | it('should return array reversed', () => { 359 | const arr = [1, 2, 3, 4, 5]; 360 | const result = parray.reverse(arr); 361 | expect(result).toEqual([5, 4, 3, 2, 1]); 362 | }); 363 | it('should not alter the original array', () => { 364 | const arr = [1, 2, 3, 4, 5]; 365 | parray.reverse(arr); 366 | expect(arr).toEqual([1, 2, 3, 4, 5]); 367 | }); 368 | }); 369 | 370 | describe('api: toString', () => { 371 | if (!parray.toString) return; 372 | it('should return string representation of array', () => { 373 | const arr = [1, 2, 3, 4, 5]; 374 | const result = parray.toString(arr); 375 | expect(result).toEqual('1,2,3,4,5'); 376 | }); 377 | it('should not alter the original array', () => { 378 | const arr = [1, 2, 3, 4, 5]; 379 | parray.toString(arr); 380 | expect(arr).toEqual([1, 2, 3, 4, 5]); 381 | }); 382 | }); 383 | 384 | describe('api: toLocaleString', () => { 385 | if (!parray.toLocaleString) return; 386 | it('should match standard array toLocaleString output', () => { 387 | var testDate = new Date(); 388 | const arr = ['not changing', 1234567890.12, testDate]; 389 | const result = parray.toLocaleString()(arr); 390 | expect(result).toEqual(arr.toLocaleString()); 391 | }); 392 | it('should match standard array toLocaleString output', () => { 393 | var prices = ['¥7', 500, 8123, 12]; 394 | const result = parray.toLocaleString('ja-JP', { style: 'currency', currency: 'JPY' })(prices); 395 | expect(result).toEqual(prices.toLocaleString('ja-JP', { style: 'currency', currency: 'JPY' })); 396 | }); 397 | it('should not alter the original array', () => { 398 | var testDate = new Date(); 399 | const arr = ['not changing', 1234567890.12, testDate]; 400 | parray.toLocaleString()(arr); 401 | expect(arr).toEqual(['not changing', 1234567890.12, testDate]); 402 | }); 403 | }); 404 | 405 | describe('api: splice', () => { 406 | if (!parray.splice) return; 407 | it('Should remove requested elements', () => { 408 | const arr = [1, 2, 3, 4, 5]; 409 | const result = parray.splice(2)(arr); 410 | expect(result).toEqual([1, 2]); 411 | }); 412 | it('Should only remove as many elements as requested', () => { 413 | const arr = [1, 2, 3, 4, 5]; 414 | const result = parray.splice(1, 2)(arr); 415 | expect(result).toEqual([1, 4, 5]); 416 | }); 417 | it('Should replace removed elements with new values', () => { 418 | const arr = [1, 2, 3, 4, 5]; 419 | const result = parray.splice(1, 3, 20, 21)(arr); 420 | expect(result).toEqual([1, 20, 21, 5]); 421 | }); 422 | it('should not alter the original array', () => { 423 | const arr = [1, 2, 3, 4, 5]; 424 | parray.splice(2)(arr); 425 | expect(arr).toEqual([1, 2, 3, 4, 5]); 426 | }); 427 | }); 428 | 429 | describe('api: push', () => { 430 | if (!parray.push) return; 431 | it('should add element to end of array', () => { 432 | const arr = [1, 2, 3, 4, 5]; 433 | const result = parray.push(6)(arr); 434 | expect(result).toEqual([1, 2, 3, 4, 5, 6]); 435 | }); 436 | it('should not alter the original array', () => { 437 | const arr = [1, 2, 3, 4, 5]; 438 | parray.push(6)(arr); 439 | expect(arr).toEqual([1, 2, 3, 4, 5]); 440 | }); 441 | }); 442 | 443 | describe('api: pop', () => { 444 | if (!parray.pop) return; 445 | it('should remove last element from array', () => { 446 | const arr = [1, 2, 3, 4, 5]; 447 | const result = parray.pop(arr); 448 | expect(result).toEqual([1, 2, 3, 4]); 449 | }); 450 | it('should not alter the original array', () => { 451 | const arr = [1, 2, 3, 4, 5]; 452 | parray.pop(arr); 453 | expect(arr).toEqual([1, 2, 3, 4, 5]); 454 | }); 455 | }); 456 | 457 | describe('api: shift', () => { 458 | if (!parray.shift) return; 459 | it('should remove first element from array', () => { 460 | const arr = [1, 2, 3, 4, 5]; 461 | const result = parray.shift(arr); 462 | expect(result).toEqual([2, 3, 4, 5]); 463 | }); 464 | it('should not alter the original array', () => { 465 | const arr = [1, 2, 3, 4, 5]; 466 | parray.shift(arr); 467 | expect(arr).toEqual([1, 2, 3, 4, 5]); 468 | }); 469 | }); 470 | 471 | describe('api: unshift', () => { 472 | if (!parray.unshift) return; 473 | it('should add single item to front of array', () => { 474 | const addOne = parray.unshift(1); 475 | const result = addOne([2, 3]); 476 | expect(result).toEqual([1, 2, 3]); 477 | }); 478 | it('should not alter the original array', () => { 479 | var arr = [2, 3]; 480 | const addOne = parray.unshift(1); 481 | addOne(arr); 482 | expect(arr).toEqual([2, 3]); 483 | }); 484 | }); 485 | 486 | describe('api: sort', () => { 487 | if (!parray.sort) return; 488 | it('should sort array based on comparator', () => { 489 | var arr = [20, 1, 3, 4, 2]; 490 | const numComp = (a, b) => (a < b) ? -1 : (a === b) ? 0 : 1; 491 | const sortBy = parray.sort(numComp); 492 | const result = sortBy(arr); 493 | expect(result).toEqual([1, 2, 3, 4, 20]); 494 | }); 495 | it('should not alter the original array', () => { 496 | var arr = [20, 1, 3, 4, 2]; 497 | const numComp = (a, b) => (a < b) ? -1 : (a === b) ? 0 : 1; 498 | const sortBy = parray.sort(numComp); 499 | sortBy(arr); 500 | expect(arr).toEqual([20, 1, 3, 4, 2]); 501 | }); 502 | }); 503 | -------------------------------------------------------------------------------- /test/pcore.test.js: -------------------------------------------------------------------------------- 1 | const { pl } = init(); 2 | 3 | 4 | function init () { 5 | if (typeof window !== 'undefined') { 6 | return { 7 | pl: window.PicoLambda, 8 | } 9 | } 10 | if (typeof window === 'undefined') { 11 | const SpecReporter = require('jasmine-spec-reporter').SpecReporter; 12 | 13 | global.jasmine.getEnv().clearReporters(); // remove default reporter logs 14 | global.jasmine.getEnv().addReporter(new SpecReporter({ // add jasmine-spec-reporter 15 | spec: { 16 | displayPending: true 17 | } 18 | })); 19 | return { 20 | pl: require('../src/index.js'), 21 | } 22 | } 23 | } 24 | 25 | describe('api: compose', () => { 26 | const is = a => b => { 27 | expect(a).toEqual(b); 28 | return a; 29 | }; 30 | it('should compose multiple functions and run them from right to left', () => { 31 | pl.pcore.compose( 32 | pl.parray.map(x => x + 1), 33 | is([3]), 34 | pl.parray.map(x => x + 1), 35 | is([2]), 36 | pl.parray.map(x => x + 1), 37 | is([1]), 38 | pl.parray.map(x => x + 1) 39 | )([0]); 40 | }); 41 | it('compose ( reduce <- map <- filter <- concat <- cons )', () => { 42 | pl.pcore.compose( 43 | is(42), 44 | pl.parray.reduce((acc, val) => val + acc), 45 | is([12, 14, 16]), 46 | pl.parray.map(x => x * 2), 47 | is([6, 7, 8]), 48 | pl.parray.filter(x => x > 5), 49 | is([0, 1, 2, 3, 4, 5, 6, 7, 8]), 50 | pl.parray.concat([6, 7, 8]), 51 | is([0, 1, 2, 3, 4, 5]), 52 | pl.parray.unshift(0), 53 | is([1, 2, 3, 4, 5]) 54 | )([1, 2, 3, 4, 5]); 55 | }); 56 | it('should not alter the original array', () => { 57 | var arr = [0]; 58 | pl.pcore.compose( 59 | pl.parray.map(x => x + 1), 60 | pl.parray.map(x => x + 1), 61 | pl.parray.map(x => x + 1), 62 | pl.parray.map(x => x + 1) 63 | )(arr); 64 | expect(arr).toEqual([0]); 65 | }); 66 | }); 67 | 68 | describe('api: pipe', () => { 69 | const is = a => b => { 70 | expect(a).toEqual(b); 71 | return a; 72 | }; 73 | it('should pipe multiple functions and run them from left to right', () => { 74 | pl.pcore.pipe( 75 | pl.parray.map(x => x + 1), 76 | is([1]), 77 | pl.parray.map(x => x + 1), 78 | is([2]), 79 | pl.parray.map(x => x + 1), 80 | is([3]), 81 | pl.parray.map(x => x + 1) 82 | )([0]); 83 | }); 84 | it('pipe ( cons -> concat -> filter -> map -> reduce )', () => { 85 | pl.pcore.pipe( 86 | is([1, 2, 3, 4, 5]), 87 | pl.parray.unshift(0), 88 | is([0, 1, 2, 3, 4, 5]), 89 | pl.parray.concat([6, 7, 8]), 90 | is([0, 1, 2, 3, 4, 5, 6, 7, 8]), 91 | pl.parray.filter(x => x > 5), 92 | is([6, 7, 8]), 93 | pl.parray.map(x => x * 2), 94 | is([12, 14, 16]), 95 | pl.parray.reduce((acc, val) => val + acc), 96 | is(42) 97 | )([1, 2, 3, 4, 5]); 98 | }); 99 | it('should not alter the original array', () => { 100 | var arr = [0]; 101 | pl.pcore.pipe( 102 | pl.parray.map(x => x + 1), 103 | pl.parray.map(x => x + 1), 104 | pl.parray.map(x => x + 1), 105 | pl.parray.map(x => x + 1) 106 | )(arr); 107 | expect(arr).toEqual([0]); 108 | }); 109 | }); 110 | 111 | describe('api: curry', () => { 112 | function manyParams(a, b, c, d) { 113 | return restParam(a, b, c, d) 114 | } 115 | function restParam(a, b, c, ...d) { 116 | return [...arguments].join(', ') 117 | } 118 | function noParams() { 119 | return 'Not one' 120 | } 121 | 122 | it('should allow normal function call syntax', () => { 123 | const curried = pl.pcore.curry(manyParams) 124 | expect(curried(1, 2, 3, 4)).toEqual('1, 2, 3, 4') 125 | }) 126 | 127 | it('should allow separated paramter call syntax', () => { 128 | const curried = pl.pcore.curry(manyParams) 129 | expect(curried(1)(2)(3)(4)).toEqual('1, 2, 3, 4') 130 | }) 131 | 132 | it('should allow separated paramter groups call syntax', () => { 133 | const curried = pl.pcore.curry(manyParams) 134 | expect(curried(1)(2, 3)(4)).toEqual('1, 2, 3, 4') 135 | }) 136 | 137 | it('should allow extra parameters in the last group', () => { 138 | const curried = pl.pcore.curry(restParam) 139 | expect(curried(1)(2)(3, 4, 5)).toEqual('1, 2, 3, 4, 5') 140 | }) 141 | 142 | it('should throw an error if rest params are separate from last group.', () => { 143 | const curried = pl.pcore.curry(restParam) 144 | expect(() => curried(1)(2)(3)(4, 5)).toThrow() 145 | }) 146 | 147 | it('should handle functions that take no parameters', () => { 148 | const curried = pl.pcore.curry(noParams) 149 | expect(curried).toEqual('Not one') 150 | }) 151 | }) 152 | 153 | describe('api: identity', () => { 154 | it('should return same value as passed in', () => { 155 | expect(pl.pcore.identity(1)).toEqual(1) 156 | expect(pl.pcore.identity("one")).toEqual("one") 157 | expect(pl.pcore.identity([1])).toEqual([1]) 158 | 159 | const testObj = {a:1} 160 | expect(pl.pcore.identity(testObj)).toEqual(testObj) 161 | }) 162 | 163 | it('should not change the object', () => { 164 | const testObj = {a:1} 165 | //Make sure we don't have the same object so that the next comparison is meaningful 166 | expect(pl.pcore.identity(Object.assign({}, testObj)) === testObj).toEqual(false) 167 | 168 | //Given that we have a new object, make sure it still looks the same as the prototype 169 | expect(pl.pcore.identity(Object.assign({}, testObj))).toEqual(testObj) 170 | }) 171 | }) 172 | -------------------------------------------------------------------------------- /test/pstring.test.js: -------------------------------------------------------------------------------- 1 | const { pstring } = init() 2 | 3 | function init () { 4 | if (typeof window !== 'undefined') { 5 | return { 6 | pstring: window.PicoLambda.pstring, 7 | } 8 | } 9 | if (typeof window === 'undefined') { 10 | const SpecReporter = require('jasmine-spec-reporter').SpecReporter; 11 | 12 | global.jasmine.getEnv().clearReporters(); // remove default reporter logs 13 | global.jasmine.getEnv().addReporter(new SpecReporter({ // add jasmine-spec-reporter 14 | spec: { 15 | displayPending: true 16 | } 17 | })); 18 | return { 19 | pstring: require('../src/index.js').pstring, 20 | } 21 | } 22 | } 23 | 24 | describe('api: charAt', () => { 25 | if (!pstring.charAt) return 26 | 27 | it('should return the character at the indicated index', () => { 28 | expect(pstring.charAt(2)("123")).toEqual("3") 29 | }) 30 | }) 31 | 32 | describe('api: charCodeAt', () => { 33 | if (!pstring.charCodeAt) return 34 | 35 | it('should return the char code at the indicated index', () => { 36 | expect(pstring.charCodeAt(2)("123")).toEqual(51) 37 | }) 38 | }) 39 | 40 | describe('api: codePointAt', () => { 41 | if (!pstring.codePointAt) return 42 | 43 | it('should return the char code at the indicated index', () => { 44 | expect(pstring.codePointAt(0)("\uD800\uDC00")).toEqual(65536) 45 | }) 46 | }) 47 | 48 | describe('api: concat', () => { 49 | if (!pstring.concat) return 50 | it('should add string to end of string', () => { 51 | const stringOne = "123" 52 | const addTwo = pstring.concat("45") 53 | const result = addTwo(stringOne) 54 | expect(result).toEqual("12345") 55 | }) 56 | it('should add multiple strings to end of string', () => { 57 | const stringOne = "123" 58 | const addTwo = pstring.concat("45", "67") 59 | const result = addTwo(stringOne) 60 | expect(result).toEqual("1234567") 61 | }) 62 | 63 | it('should add single character to end of string', () => { 64 | const stringOne = "32" 65 | const addOne = pstring.concat("1") 66 | const result = (addOne(stringOne)) 67 | expect(result).toEqual("321") 68 | }) 69 | }) 70 | 71 | describe('api: endsWith', () => { 72 | if (!pstring.endsWidth) return 73 | it('should return true if the final param ends with the string in the first position', () => { 74 | expect(pstring.endsWith("bc")("abc")).toEqual(true) 75 | }) 76 | it('should return false if the final param does not end with the string in the first position', () => { 77 | expect(pstring.endsWith("bc")("abcd")).toEqual(false) 78 | }) 79 | }) 80 | 81 | describe('api: includes', () => { 82 | if (!pstring.includes) return 83 | it('should return true if the second string starts with the first string', () => { 84 | expect(pstring.includes("To be")("To be, or not to be, that is the question.")).toEqual(true) 85 | }) 86 | 87 | it('should return true if the second string ends with the first string', () => { 88 | expect(pstring.includes("question.")("To be, or not to be, that is the question.")).toEqual(true) 89 | }) 90 | 91 | it('should return true if the second string contains the first string', () => { 92 | expect(pstring.includes("not to be,")("To be, or not to be, that is the question.")).toEqual(true) 93 | }) 94 | 95 | it('should return false if the second string does not contain the first string', () => { 96 | expect(pstring.includes("nonexistent")("To be, or not to be, that is the question.")).toEqual(false) 97 | }) 98 | 99 | it('should start searching at the indicated parameter', () => { 100 | expect(pstring.includes("To be", 1)("To be, or not to be, that is the question.")).toEqual(false) 101 | }) 102 | 103 | it('should be case sensitive', () => { 104 | expect(pstring.includes("TO BE")("To be, or not to be, that is the question.")).toEqual(false) 105 | }) 106 | }) 107 | 108 | describe('api: indexOf', () => { 109 | if (!pstring.indexOf) return 110 | it('should return the index of the given substring', () => { 111 | expect(pstring.indexOf("a")("abc")).toEqual(0) 112 | expect(pstring.indexOf("b")("abc")).toEqual(1) 113 | expect(pstring.indexOf("c")("abc")).toEqual(2) 114 | }) 115 | 116 | it('should return the first index if the substring appears more than once', () => { 117 | expect(pstring.indexOf("b")("abbc")).toEqual(1) 118 | }) 119 | 120 | it('should return -1 if the substring is not contained in string', () => { 121 | expect(pstring.indexOf("z")("abc")).toEqual(-1) 122 | }) 123 | }) 124 | 125 | describe('api: lastIndexOf', () => { 126 | if (!pstring.lastIndexOf) return 127 | it('should return the index of the given substring', () => { 128 | expect(pstring.lastIndexOf("a")("abc")).toEqual(0) 129 | expect(pstring.lastIndexOf("b")("abc")).toEqual(1) 130 | expect(pstring.lastIndexOf("c")("abc")).toEqual(2) 131 | }) 132 | 133 | it('should return the last index if the substring appears more than once', () => { 134 | expect(pstring.lastIndexOf("b")("abbc")).toEqual(2) 135 | }) 136 | 137 | it('should return -1 if the substring is not contained in string', () => { 138 | expect(pstring.lastIndexOf("z")("abc")).toEqual(-1) 139 | }) 140 | }) 141 | 142 | describe('api: localeCompare', () => { 143 | if (!pstring.localeCompare) return 144 | it('should return -1 if the second string comes first', () => { 145 | expect(pstring.localeCompare("b")("a")).toBeLessThan(0) 146 | }) 147 | 148 | it('should return 1 if the second string comes after', () => { 149 | expect(pstring.localeCompare("a")("b")).toBeGreaterThan(0) 150 | }) 151 | 152 | it('should return 0 if the second string is equal', () => { 153 | expect(pstring.localeCompare("a")("a")).toEqual(0) 154 | }) 155 | 156 | it('should accept optional params in first position', () => { 157 | expect(pstring.localeCompare('a', 'de', { sensitivity: 'base' })('ä')).toEqual(0) 158 | }) 159 | }) 160 | 161 | describe('api: match', () => { 162 | if (!pstring.match) return 163 | it('should match a value with regular expression', () => { 164 | const str = 'For more information, see Chapter 3.4.5.1' 165 | const re = /see (chapter \d+(\.\d)*)/i 166 | 167 | expect(pstring.match(re)(str).length).toBeGreaterThan(0) 168 | }) 169 | }) 170 | 171 | describe('api: normalize', () => { 172 | if (!pstring.normalize) return 173 | it('should normalize the test string to the form indicated', () => { 174 | const str = '\u1E9B\u0323'; 175 | expect(pstring.normalize('NFKC')(str) === '\u1E69').toEqual(true) 176 | }) 177 | }) 178 | 179 | describe('api: repeat', () => { 180 | if (!pstring.repeat) return 181 | it('should repeat string passed indicated number of times', () => { 182 | expect(pstring.repeat(2)('abc')).toEqual('abcabc') 183 | }) 184 | }) 185 | 186 | describe('api: replace', () => { 187 | if (!pstring.replace) return 188 | it('should replace the matched substring with the given replacement string', () => { 189 | expect(pstring.replace(/xmas/i, 'Christmas')('Twas the night before Xmas...')).toEqual('Twas the night before Christmas...') 190 | }) 191 | }) 192 | 193 | describe('api: search', () => { 194 | if (!pstring.search) return 195 | it('should return the position of the first substring that matches the given regular expression', () => { 196 | expect(pstring.search(/xmas/i)('Twas the night before Xmas...')).toEqual(22) 197 | }) 198 | }) 199 | 200 | describe('api: slice', () => { 201 | if (!pstring.slice) return 202 | it('should work with one parameter', () => { 203 | expect(pstring.slice(12)('Twas the night before Xmas...')).toEqual('ht before Xmas...') 204 | }) 205 | 206 | it('should work with two parameters', () => { 207 | expect(pstring.slice(4, -2)('Twas the night before Xmas...')).toEqual(' the night before Xmas.') 208 | }) 209 | }) 210 | 211 | // 'split' 212 | describe('api: split', () => { 213 | if (!pstring.split) return 214 | 215 | it('should split on the given character', () => { 216 | expect(pstring.split(',')("1,2")).toEqual(['1', '2']) 217 | }) 218 | 219 | it('should split with limits', () => { 220 | expect(pstring.split(',', 2)("1,2,3,4")).toEqual(['1', '2']) 221 | }) 222 | }) 223 | 224 | // 'startsWith' 225 | describe('api: startsWith', () => { 226 | if (!pstring.startsWith) return 227 | it('should return true if the final param starts with the string in the first position', () => { 228 | expect(pstring.startsWith("ab")("abc")).toEqual(true) 229 | }) 230 | it('should return false if the final param does not start with the string in the first position', () => { 231 | expect(pstring.startsWith("bc")("abcd")).toEqual(false) 232 | }) 233 | }) 234 | 235 | describe('api: substr', () => { 236 | if (!pstring.substr) return 237 | it('should work with one param', () => { 238 | expect(pstring.substr(2)("abcde")).toEqual('cde') 239 | }) 240 | it('should work with two params', () => { 241 | expect(pstring.substr(2, 2)("abcde")).toEqual('cd') 242 | }) 243 | }) 244 | 245 | describe('api: substring', () => { 246 | if (!pstring.substring) return 247 | it('should work with one param', () => { 248 | expect(pstring.substring(2)("abcde")).toEqual('cde') 249 | }) 250 | it('should work with two params', () => { 251 | expect(pstring.substring(2, 4)("abcde")).toEqual('cd') 252 | }) 253 | }) 254 | 255 | describe('api: toLocaleLowerCase', () => { 256 | if (!pstring.toLocaleLowerCase) return 257 | it('should work after currying', () => { 258 | expect(pstring.toLocaleLowerCase("ABC")).toEqual('abc') 259 | }) 260 | }) 261 | 262 | describe('api: toLocaleUpperCase', () => { 263 | if (!pstring.toLocaleUpperCase) return 264 | it('should work after currying', () => { 265 | expect(pstring.toLocaleUpperCase("abc")).toEqual('ABC') 266 | }) 267 | }) 268 | 269 | describe('api: toLowerCase', () => { 270 | if (!pstring.toLowerCase) return 271 | it('should work after currying', () => { 272 | expect(pstring.toLowerCase("ABC")).toEqual('abc') 273 | }) 274 | }) 275 | 276 | describe('api: toString', () => { 277 | if (!pstring.toString) return 278 | it('should work after currying', () => { 279 | expect(pstring.toString("ABC")).toEqual('ABC') 280 | }) 281 | }) 282 | 283 | describe('api: toUpperCase', () => { 284 | if (!pstring.toUpperCase) return 285 | it('should work after currying', () => { 286 | expect(pstring.toUpperCase("abc")).toEqual('ABC') 287 | }) 288 | }) 289 | 290 | describe('api: trim', () => { 291 | if (!pstring.trim) return 292 | it('should work after currying', () => { 293 | expect(pstring.trim(" abc ")).toEqual('abc') 294 | }) 295 | }) 296 | 297 | describe('api: trimLeft', () => { 298 | if (!pstring.trimLeft) return 299 | it('should work after currying', () => { 300 | expect(pstring.trimLeft(" abc ")).toEqual('abc ') 301 | }) 302 | }) 303 | 304 | describe('api: trimRight', () => { 305 | if (!pstring.trimRight) return 306 | it('should work after currying', () => { 307 | expect(pstring.trimRight(" abc ")).toEqual(' abc') 308 | }) 309 | }) 310 | 311 | describe('api: valueOf', () => { 312 | if (!pstring.valueOf) return 313 | it('should work after currying', () => { 314 | expect(pstring.valueOf("abc")).toEqual('abc') 315 | }) 316 | }) 317 | --------------------------------------------------------------------------------