Skip to content

Version 2

Compare
Choose a tag to compare
@MZanggl MZanggl released this 09 Aug 05:36

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')
})