Snaplet Copycat Versions Save

Generate deterministic fake values: The same input will always generate the same fake-output.

v5.0.0

3 months ago

chore!: Upgrade fictional 1.0.0 -> 2.0.0

Fixes someOf() when range tuple (e.g. copycat.someOf(seed, [1, 2], ['a','b','c'])) is given for range parameter instead of number (e.g. copycat.someOf(seed, 2, ['a','b','c'])). Previously this case would have always (incorrectly) returned an empty array ([]).

BREAKING CHANGE While this fixes a bug, it is still technically a breaking change: if copycat.someOf() is currently being given a range tuple (e.g. copycat.someOf(seed, [1, 2], ['a','b','c'])), results for the same input would change from (incorrectly) being an empty array ([]), to (correctly) being an array of items of a size within the given range.

Full Changelog: https://github.com/snaplet/copycat/compare/v4.1.0...v5.0.0

v4.1.0

3 months ago

feat: Support oneOfString()

copycat.oneOfString(input, values[, options])

Like oneOf(), takes in an input value and an array of values, and returns an item in values that corresponds to that input. However, values needs to be an array of string values, and only values within the character limit set by the limit option will be picked.

copycat.oneOfString('foo', ['short', 'loooooooong'], { limit: 6 })
// => 'short'

options

  • limit: If the values are strings, the picked value will be constrained to be less than limit's amount of characters
  • fallback: string | (input) => string: When limit is specified but no values match the given limit, fallback is called with the given input value.

v4.0.0

3 months ago

What's Changed

// before
copycat.phoneNumber(input, { min: 100000, max: 999999999 })
copycat.phoneNumber(input, { min: 100000000, max: 999999999 })

// after
copycat.phoneNumber(input, { length: { min: 6, max: 9 } })
copycat.phoneNumber(input,  { length: 9 })

BREAKING CHANGES

  • In the cases where the prefixes option is provided, copycat will now return a different output for the same input
  • The min and max options have been removed in favour of length: number | { min: number, max: number }

v2.0.0

3 months ago

⚠ BREAKING CHANGES

copycat.float() method has been rewritten: previously, output values would stay close to the min value give. With this release, output values will distribute more evenly across the (min, max) range of values.

This means that inputs for copycat.float() will now map to a different output. It is still deterministic - the same input will always map to the same output. It is just that after the upgrade the corresponding output for each input will have changed.

v2.0.0-rc.1

4 months ago

⚠ BREAKING CHANGES

copycat.float() method has been rewritten: previously, output values would stay close to the min value give. With this release, output values will distribute more evenly across the (min, max) range of values.

This means that inputs for copycat.float() will now map to a different output. It is still deterministic - the same input will always map to the same output. It is just that after the upgrade the corresponding output for each input will have changed.

Migration notice:

We will release this change onto the main branch as v2.0.0 on 23 January 2024 at 12:00pm (noon) UTC. In the meantime, you can try out the new behaviour by using:

import { copycat } from '@snaplet/copycat/next'

v1.2.0

4 months ago

Adds copycat.url(input)

Takes in an input and returns a string value resembling a URL.

copycat.url('foo')
// => 'https://noisy-shoe.biz'

v1.1.0

5 months ago

What's Changed

Full Changelog: https://github.com/snaplet/copycat/compare/v0.18.0...v1.1.0

v1.1.0-rc.1

5 months ago

What's Changed

Full Changelog: https://github.com/snaplet/copycat/compare/v1.0.0-rc.1...v1.1.0-rc.1

v1.0.0-rc.1

6 months ago

⚠ BREAKING CHANGES

  • The phoneNumber method has been rewriten to reduce the chances of colisions for it. Their value will change between the v0.18.1 and v1.0.0

Migration notice:

We will release this change onto the main branch in 4 weeks (12 December 2023). In the meantime you can try out the new behaviour by using:

import { copycat } from '@snaplet/copycat/next'

and adapt your usage accordingly.

v0.18.1

6 months ago

⚠ BREAKING CHANGES

Performance improvements

In order to always return the same output for the same input, copycat works by hashing the given input value to a number, and then using the resulting number to compute the output value. Under the hood, we use SipHash to do this (more context here).

Sometimes though, we need a sequence of numbers to compute an output, rather than a single number. A good example of this is copycat.scramble(), where we need a sequence of numbers, one for each character in the input. In these cases, we were using SipHash to compute the initial hash, and then for each number in the sequence, use the faster fnv1a to re-hash the current hash value to obtain the next number in the sequence in a deterministic way.

However, the tool we're looking for in this case is a seeded deterministic pseudo-random number generator (PRNG). In turns out there are much faster algorithms for accomplishing this than using fnv1a, which is really more a hash function than a PRNG. After experimenting a bit, we settled on using splitmix.

What does this mean for me?

This sequencing functionality described above is a core part of copycat. Any method relying on this sequencing functionality (transitively via other copycat methods or directly) would be impacted. In the case of large outputs, you might see computation time performance improvements (benchmarks for copycat.scramble() below).

However, it also means that for all the affected methods, the same input value would now map to an entirely different output value (since we changed the underlying function we were using for computing a sequence of numbers for a given hash value). That said, the same input value will still map to that same output value, it is just that the output value is different to what it was in previous releases. In other words, copycat is still deterministic, it is just that this release came with a change to the mapping from inputs to outputs.

Benchmark results for copycat.scramble()

{
  "name": "100 words",
  "results": [
    {
      "ms": 0.8084074373484236,
      "name": "copycat.scramble(): before (0.17.3)",
      "ops": 1237,
      "percentSlower": 94.96
    },
    {
      "ms": 0.04073485681697829,
      "name": "copycat.scramble(): after (reimplementation)",
      "ops": 24549,
      "percentSlower": 0
    }
  ]
}
{
  "name": "100000 words",
  "results": [
    {
      "ms": 1000,
      "name": "copycat.scramble(): before (0.17.3)",
      "ops": 1,
      "percentSlower": 93.33
    },
    {
      "ms": 66.66666666666667,
      "name": "copycat.scramble(): after (reimplementation)",
      "ops": 15,
      "percentSlower": 0
    }
  ]
}

More context here: https://github.com/snaplet/copycat/pull/45

Lorem ipsum

copycat.word() and other word methods (@copycat.words(), @copycat.paragraph() and @copycat.sentence()) changed from generating text like this:

Kai ni viramira memayo kayu. Hahyceavi nameta mohy shichiacea menivayu shi mika yokinmu, nahyraki hyka chi niceavi ta. Ta hamevakin yuno hyakova nivami yohycea ko, yoha shiyu miha hy kiko kinyoshi ka ninoshi. Notakimu yo yukake kakekaihy vaceaso vakiso nomu rae, yukin chiraekimo ceavino yo muyo. Hyva memayo shikemavi ka kakesokin mamuhamo kinmukame mora, ranino masochiyo kinoa kesoni mamo. Va nohakin komiva shimo hykikayo makinra yorae, sovami kai raenira raeyo sonavi mo mora chirae

To text like this:

Et modo lucilias legatomnem et. Quis ratio iudicur ut defuitur quod interessar endis, doloria romandum athenisse explicem quia. Expeten quam hoc ex amus ant sive, providintem ad claudicur torquato nes nihil nec ut. Audiri dicerea summum arisset ne exceperem tam si, amartifex doloris nam quae ipsum. Et causa iudicitat extremum endam tota tum antippus, de vidi videbo rerum ut. Affere ab mundi nimium summa partemerror causae, his am semperfruique in sapiens gloriatur et dicenim

Context

The idea behind the way we used to generate words, was to use Japanese-like syllables for simplicity, since they compose easily (any syllable can follow any other).

It would be more ideal though to use something more standard and expected, such as "lorem ipsum" placeholder text. It is also arguably a better representation of fake text that is meant to be read (e.g. on a web page) - since we generate words with latin characters. Latin words are naturally more representative of where these characters would be seen. In contrast, the previous fake text is not - it is closer to resembling a romanized form of text from a language not written with latin characters, and so it is probably less representative of what would appear as text meant to be read (e.g. on a web page).

More context here: https://github.com/snaplet/copycat/pull/46