Version 2
Documentation and Code for Version 1
Version 2 focuses on three aspects: bundle size, consistency, and even more expressiveness, all while keeping the original goals of flooent.
- The import cost went from 84.5kb all the way down to less than 10kb (3kb gzipped).
- The number of external dependencies used went down from 15 to zero.
- Every method now features JSDoc documentation
With this, flooent is now also a super useful tool for data manipulation on the frontend, since you no longer have to worry about the file size.
given
is no longer a function
Before
import { given } from 'flooent'
given('hello') // instance of Stringable
given([1, 2]) // instance of Arrayable
given(1) // instance of Numberable
given({ key: 'value' }) // instance of Mappable (not object)
After
import { given } from 'flooent'
given.string('hello') // instance of Stringable
given.array([1, 2]) // instance of Arrayable
given.number(1) // instance of Numberable
given.map({ key: 'value' }) // instance of Mappable (not object)
This removes the internal magic of choosing the correct object and is generally more explicit.
macros
You can define macros on the new given methods without passing the object type.
Before
given.macro(String, 'scream', function() {
return this.toUpperCase()
})
After
given.string.macro('scream', function() {
return this.toUpperCase()
})
Furthermore, the following has been added to the macro-section of the README
- how to deal with TypeScript
- useful examples
Removed heavy yet uncommon methods
The below methods have been removed since they are not too common but together add up a lot to the bundle size. You can add them back through macros. Copy-pastable examples for how to do so have been added to the README under macros
.
Removed string.plural & string.singular
Not only was this big in size it also only supported English. I'd rather look more into Intl and see how this could be solved for any language.
Removed array.is & array.quacksLike
TypeScript already takes care of this pretty well. Also, instead of comparing each value, which is expensive, it is often better to create a type guard. This leaves it to be only really useful for tests, for which there are already plenty of libraries and flooent is not really meant as an assertion library.
If you only want to shallow-clone an array or map you can wrap it in another given
: given.array(flooentArray)
.
Removed array.clone & map.clone
Deep-cloning is usually an escape hatch for doing something the language cannot express on its own. For example, the array pointer API takes care of many cases that involve destructuring or cloning arrays. I'd rather add expressive methods to flooent that avoid deep cloning altogether.
Array.append
and Array.prepend
are now immutable
For consistent behavior across the project, these two methods have now been made immutable. If you prefer mutability, check out the new method mutate
below.
Array.forget -> Array.omit
The name for the method Array.forget
was changed to Array.omit
. forget
suggests mutability, but since this has always been immutable, omit
makes more sense.
Another difference is that forget
before accepted both an array and a string. This has been changed to only accept an array now.
const people = [
{ id: 1, age: 24, initials: 'mz' },
{ id: 2, age: 2, initials: 'lz' }
]
given.array(people).omit(['initials', 'age'])
pipe / when / whenEmpty only transforms the result into flooent variant when the result is of the respective type
Affected methods
- array.pipe
- string.pipe
- array.when (using array.pipe under the hood)
- string.when (using string.pipe under the hood)
- string.whenEmpty (using string.pipe under the hood)
Before, string.pipe always converted the result back into a flooent string. Now, it only converts it back into a flooent string if the result is actually a string. Otherwise, it returns the raw result.
The same is true for array.pipe + array types respectively.
New methods and object
Array.mutate
Since all flooent array methods are now immutable, this is an escape hatch for when you need it.
const numbers = given.array([1, 2, 3])
numbers.mutate(n => n.append(4))
numbers // [1, 2, 3, 4]
Pointer set
Sets the value at the current index and returns a new array.
given.array(['music', 'tehc']).at(1).set(item => 'tech') // ['music', 'tech']
given.any
A generic helper class for any kind of data types.
do
Executes and returns the result of a callback.
This is useful for grouping common logic together and avoiding temporary variables.
Before
const user = User.first() // varialbe "user" is only used here
const nameMatches = expect(user.name).toBe('test name')
After
const nameMatches = given.any(User.first()).do(user => {
return expect(user.name).toBe('test name')
})