Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 92 additions & 4 deletions src/modules/string/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { CROCKFORDS_BASE32, dateToBase32 } from '../../internal/base32';
import { toDate } from '../../internal/date';
import { SimpleModuleBase } from '../../internal/module-base';
import type { LiteralUnion } from '../../internal/types';
import { uuidV4, uuidV7 } from './uuid';

export type Casing = 'upper' | 'lower' | 'mixed';

Expand Down Expand Up @@ -692,18 +693,105 @@ export class StringModule extends SimpleModuleBase {
return returnString;
}

/**
* Returns a UUID ([Universally Unique Identifier](https://en.wikipedia.org/wiki/Universally_unique_identifier)).
*
* @example
* faker.string.uuid() // '4136cd0b-d90b-4af7-b485-5d1ded8db252'
*
* @since 8.0.0
*/
uuid(): string;
/**
* Returns a UUID v4 ([Universally Unique Identifier](https://en.wikipedia.org/wiki/Universally_unique_identifier)).
*
* @param options An options object.
* @param options.version The specific UUID version to use.
*
* @example
* faker.string.uuid({ version: 4 }) // '4136cd0b-d90b-4af7-b485-5d1ded8db252'
*
* @since 8.0.0
*/
uuid(options: {
/**
* The specific UUID version to use.
*/
version: 4;
}): string;
/**
* Returns a UUID v7 ([Universally Unique Identifier](https://en.wikipedia.org/wiki/Universally_unique_identifier)).
*
* @param options An options object.
* @param options.version The specific UUID version to use.
* @param options.refDate The timestamp to encode into the uuid.
* The encoded timestamp is represented by the first 12 characters of the result.
* Defaults to `faker.defaultRefDate()`.
*
* @example
* faker.string.uuid() // '019be2c5-58de-70fe-a693-2ccbff1f0780'
*
* @since 10.3.0
*/
uuid(options: {
/**
* The specific UUID version to use.
*/
version: 7;
/**
* The timestamp to encode into the uuid.
* The encoded timestamp is represented by the first 12 characters of the result.
*
* @default faker.defaultRefDate()
*/
refDate: string | Date | number;
}): string;
/**
* Returns a UUID ([Universally Unique Identifier](https://en.wikipedia.org/wiki/Universally_unique_identifier)).
*
* @param options An optional options object.
* @param options.version The specific UUID version to use. Defaults to `4`.
* @param options.refDate The timestamp to encode into the UUID.
* This parameter is only relevant for time based UUID's.
* Defaults to `faker.defaultRefDate()`.
*
* @example
* faker.string.uuid() // '4136cd0b-d90b-4af7-b485-5d1ded8db252'
* faker.string.uuid({ version: 4 }) // 'd5482c1f-c30d-4bbc-b151-d95145bae71b'
* faker.string.uuid({ version: 7 }) // '01948b54-1b78-75fb-9922-0d9b0fd32248'
* faker.string.uuid({ version: 7, refDate: '2020-01-01T00:00:00.000Z' }) // '016f5e66-e800-725e-b078-f413f23aaff0'
*
* @since 8.0.0
*/
uuid(): string {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'
.replaceAll('x', () => this.faker.number.hex({ min: 0x0, max: 0xf }))
.replaceAll('y', () => this.faker.number.hex({ min: 0x8, max: 0xb }));
uuid(options?: {
/**
* The specific UUID version to use.
*/
version?: 4 | 7;
/**
* The timestamp to encode into the UUID.
* This parameter is only relevant for time based UUID's.
*
* @default faker.defaultRefDate()
*/
refDate?: string | Date | number;
}): string;
uuid(
options: {
version?: 4 | 7;
refDate?: string | Date | number;
} = {}
): string {
const { version = 4, refDate = this.faker.defaultRefDate() } = options;
switch (version) {
case 7: {
return uuidV7(this.faker, toDate(refDate));
}

default: {
return uuidV4(this.faker);
}
}
}

/**
Expand Down
42 changes: 42 additions & 0 deletions src/modules/string/uuid.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import type { SimpleFaker } from '../../';

/**
* Returns a UUID v4 ([Universally Unique Identifier](https://en.wikipedia.org/wiki/Universally_unique_identifier)).
*
* @internal
*
* @param faker The faker instance to use.
*/
export function uuidV4(faker: SimpleFaker): string {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'
.replaceAll('x', () => faker.number.hex({ min: 0x0, max: 0xf }))
.replaceAll('y', () => faker.number.hex({ min: 0x8, max: 0xb }));
}

/**
* Returns a UUID v7 ([Universally Unique Identifier](https://en.wikipedia.org/wiki/Universally_unique_identifier)).
*
* @internal
*
* @param faker The faker instance to use.
* @param refDate The reference date to retrieve the unix timestamp from.
*/
export function uuidV7(faker: SimpleFaker, refDate: Date): string {
const unixTimeMs = refDate.valueOf();
const unixTimeMsNormalized = Math.max(unixTimeMs, 0);
const unixTimeMsHex = unixTimeMsNormalized
.toString(16)
.padStart(12, '0')
.slice(-12);

const unixTimePart = [
unixTimeMsHex.substring(0, 8),
unixTimeMsHex.substring(8),
].join('-');

const randomPart = '7xxx-yxxx-xxxxxxxxxxxx'
.replaceAll('x', () => faker.number.hex({ min: 0x0, max: 0xf }))
.replaceAll('y', () => faker.number.hex({ min: 0x8, max: 0xb }));

return `${unixTimePart}-${randomPart}`;
}
78 changes: 63 additions & 15 deletions test/modules/__snapshots__/string.spec.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -170,15 +170,31 @@ exports[`string > 42 > ulid > with number refDate 1`] = `"01EZ2S259ZBYQK441VKP0Z

exports[`string > 42 > ulid > with string refDate 1`] = `"01EZ2S259ZBYQK441VKP0ZT655"`;

exports[`string > 42 > uuid 1`] = `"5fb9220d-9b0f-4d32-a248-6492457c3890"`;
exports[`string > 42 > uuid > noArgs 1`] = `"5fb9220d-9b0f-4d32-a248-6492457c3890"`;

exports[`string > 42 > uuid 2`] = `"21ffc41a-7170-4e4a-9488-2fcfe9e13056"`;
exports[`string > 42 > uuid > noArgs 2`] = `"21ffc41a-7170-4e4a-9488-2fcfe9e13056"`;

exports[`string > 42 > uuid 3`] = `"d5482c1f-c30d-4bbc-b151-d95145bae71b"`;
exports[`string > 42 > uuid > noArgs 3`] = `"d5482c1f-c30d-4bbc-b151-d95145bae71b"`;

exports[`string > 42 > uuid 4`] = `"8c786010-a58e-436c-8314-2ecadc2e8ce5"`;
exports[`string > 42 > uuid > noArgs 4`] = `"8c786010-a58e-436c-8314-2ecadc2e8ce5"`;

exports[`string > 42 > uuid 5`] = `"36dd0863-15f5-48b5-bff4-74409804e327"`;
exports[`string > 42 > uuid > noArgs 5`] = `"36dd0863-15f5-48b5-bff4-74409804e327"`;

exports[`string > 42 > uuid > with version = 4 1`] = `"5fb9220d-9b0f-4d32-a248-6492457c3890"`;

exports[`string > 42 > uuid > with version = 4 2`] = `"21ffc41a-7170-4e4a-9488-2fcfe9e13056"`;

exports[`string > 42 > uuid > with version = 4 3`] = `"d5482c1f-c30d-4bbc-b151-d95145bae71b"`;

exports[`string > 42 > uuid > with version = 4 4`] = `"8c786010-a58e-436c-8314-2ecadc2e8ce5"`;

exports[`string > 42 > uuid > with version = 4 5`] = `"36dd0863-15f5-48b5-bff4-74409804e327"`;

exports[`string > 42 > uuid > with version = 7 and Date refDate 1`] = `"01948b54-1b78-75fb-9922-0d9b0fd32248"`;

exports[`string > 42 > uuid > with version = 7 and number refDate 1`] = `"01948b54-1b78-75fb-9922-0d9b0fd32248"`;

exports[`string > 42 > uuid > with version = 7 and string refDate 1`] = `"01948b54-1b78-75fb-9922-0d9b0fd32248"`;

exports[`string > 1211 > alpha > noArgs 1`] = `"W"`;

Expand Down Expand Up @@ -350,15 +366,31 @@ exports[`string > 1211 > ulid > with number refDate 1`] = `"01EZ2S259ZXW7ZNNRBPT

exports[`string > 1211 > ulid > with string refDate 1`] = `"01EZ2S259ZXW7ZNNRBPTRMTDVV"`;

exports[`string > 1211 > uuid 1`] = `"ee3faac5-bdca-4d6d-9d39-35fc6e8f34b8"`;
exports[`string > 1211 > uuid > noArgs 1`] = `"ee3faac5-bdca-4d6d-9d39-35fc6e8f34b8"`;

exports[`string > 1211 > uuid > noArgs 2`] = `"d64428b2-b736-43d9-970b-2b4c8739d1d7"`;

exports[`string > 1211 > uuid > noArgs 3`] = `"79c8efdd-3bd5-4e08-bc71-4243ef639999"`;

exports[`string > 1211 > uuid > noArgs 4`] = `"adcde858-75d3-4f13-90e6-e9ff59ce28bb"`;

exports[`string > 1211 > uuid > noArgs 5`] = `"de2b16a5-033e-49a8-8a9e-77d809771962"`;

exports[`string > 1211 > uuid 2`] = `"d64428b2-b736-43d9-970b-2b4c8739d1d7"`;
exports[`string > 1211 > uuid > with version = 4 1`] = `"ee3faac5-bdca-4d6d-9d39-35fc6e8f34b8"`;

exports[`string > 1211 > uuid 3`] = `"79c8efdd-3bd5-4e08-bc71-4243ef639999"`;
exports[`string > 1211 > uuid > with version = 4 2`] = `"d64428b2-b736-43d9-970b-2b4c8739d1d7"`;

exports[`string > 1211 > uuid 4`] = `"adcde858-75d3-4f13-90e6-e9ff59ce28bb"`;
exports[`string > 1211 > uuid > with version = 4 3`] = `"79c8efdd-3bd5-4e08-bc71-4243ef639999"`;

exports[`string > 1211 > uuid 5`] = `"de2b16a5-033e-49a8-8a9e-77d809771962"`;
exports[`string > 1211 > uuid > with version = 4 4`] = `"adcde858-75d3-4f13-90e6-e9ff59ce28bb"`;

exports[`string > 1211 > uuid > with version = 4 5`] = `"de2b16a5-033e-49a8-8a9e-77d809771962"`;

exports[`string > 1211 > uuid > with version = 7 and Date refDate 1`] = `"01948b54-1b78-7ee3-8faa-c5bdcad6dd39"`;

exports[`string > 1211 > uuid > with version = 7 and number refDate 1`] = `"01948b54-1b78-7ee3-8faa-c5bdcad6dd39"`;

exports[`string > 1211 > uuid > with version = 7 and string refDate 1`] = `"01948b54-1b78-7ee3-8faa-c5bdcad6dd39"`;

exports[`string > 1337 > alpha > noArgs 1`] = `"n"`;

Expand Down Expand Up @@ -530,12 +562,28 @@ exports[`string > 1337 > ulid > with number refDate 1`] = `"01EZ2S259Z858EAG8ZQ3

exports[`string > 1337 > ulid > with string refDate 1`] = `"01EZ2S259Z858EAG8ZQ3CM4ZES"`;

exports[`string > 1337 > uuid 1`] = `"4247584f-b16a-42f7-8cc5-69c34a72638d"`;
exports[`string > 1337 > uuid > noArgs 1`] = `"4247584f-b16a-42f7-8cc5-69c34a72638d"`;

exports[`string > 1337 > uuid > noArgs 2`] = `"f6880bf2-25b0-450c-a5b7-fd99f401ff75"`;

exports[`string > 1337 > uuid > noArgs 3`] = `"0ca3ae2e-5b48-4277-b6c7-bc5ebe67ea83"`;

exports[`string > 1337 > uuid > noArgs 4`] = `"8c36682a-03be-496d-8f46-b50570ebc104"`;

exports[`string > 1337 > uuid > noArgs 5`] = `"3a7e9225-61a0-4ba0-9c5c-592d4b9e801f"`;

exports[`string > 1337 > uuid > with version = 4 1`] = `"4247584f-b16a-42f7-8cc5-69c34a72638d"`;

exports[`string > 1337 > uuid > with version = 4 2`] = `"f6880bf2-25b0-450c-a5b7-fd99f401ff75"`;

exports[`string > 1337 > uuid > with version = 4 3`] = `"0ca3ae2e-5b48-4277-b6c7-bc5ebe67ea83"`;

exports[`string > 1337 > uuid > with version = 4 4`] = `"8c36682a-03be-496d-8f46-b50570ebc104"`;

exports[`string > 1337 > uuid 2`] = `"f6880bf2-25b0-450c-a5b7-fd99f401ff75"`;
exports[`string > 1337 > uuid > with version = 4 5`] = `"3a7e9225-61a0-4ba0-9c5c-592d4b9e801f"`;

exports[`string > 1337 > uuid 3`] = `"0ca3ae2e-5b48-4277-b6c7-bc5ebe67ea83"`;
exports[`string > 1337 > uuid > with version = 7 and Date refDate 1`] = `"01948b54-1b78-7424-9758-4fb16a2f7cc5"`;

exports[`string > 1337 > uuid 4`] = `"8c36682a-03be-496d-8f46-b50570ebc104"`;
exports[`string > 1337 > uuid > with version = 7 and number refDate 1`] = `"01948b54-1b78-7424-9758-4fb16a2f7cc5"`;

exports[`string > 1337 > uuid 5`] = `"3a7e9225-61a0-4ba0-9c5c-592d4b9e801f"`;
exports[`string > 1337 > uuid > with version = 7 and string refDate 1`] = `"01948b54-1b78-7424-9758-4fb16a2f7cc5"`;
69 changes: 63 additions & 6 deletions test/modules/string.spec.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
import isULID from 'validator/lib/isULID';
import isUUID from 'validator/lib/isUUID';
import { describe, expect, it } from 'vitest';
import { FakerError, faker } from '../../src';
import { seededTests } from '../support/seeded-runs';
import { times } from './../support/times';

function isUuidV4(value: string) {
return isUUID(value, '4');
}

function isUuidV7(value: string) {
return isUUID(value, '7');
}

const NON_SEEDED_BASED_RUN = 5;

describe('string', () => {
Expand Down Expand Up @@ -112,7 +121,24 @@ describe('string', () => {
.it('with length range', { min: 10, max: 20 });
});

t.itRepeated('uuid', 5);
t.describe('uuid', (t) => {
const ulidRefDate = '2025-01-22T00:05:32.664Z';

t.itRepeated('noArgs', 5)
.itRepeated('with version = 4', 5, { version: 4 })
.it('with version = 7 and string refDate', {
version: 7,
refDate: ulidRefDate,
})
.it('with version = 7 and Date refDate', {
version: 7,
refDate: new Date(ulidRefDate),
})
.it('with version = 7 and number refDate', {
version: 7,
refDate: new Date(ulidRefDate).getTime(),
});
});

t.describe('ulid', (t) => {
const ulidRefDate = '2021-02-21T17:09:15.711Z';
Expand Down Expand Up @@ -753,11 +779,42 @@ describe('string', () => {
});

describe(`uuid`, () => {
it('generates a valid UUID', () => {
const UUID = faker.string.uuid();
const RFC4122 =
/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;
expect(UUID).toMatch(RFC4122);
describe('version 4', () => {
it('generates a valid UUID', () => {
const uuid = faker.string.uuid({ version: 4 });
expect(uuid).toSatisfy(isUuidV4);
});
});

describe('version 7', () => {
it('generates a valid UUID', () => {
const uuid = faker.string.uuid({ version: 7 });
expect(uuid).toSatisfy(isUuidV7);
});

it('generates nil bytes in the unix part if 0 is given as a ref date', () => {
const uuid = faker.string.uuid({ version: 7, refDate: 0 });

expect(uuid).toSatisfy(isUuidV7);
expect(uuid).toStartWith('00000000-0000');
});

it('generates nil bytes in the unix part if a negative is given as a ref date', () => {
const uuid = faker.string.uuid({ version: 7, refDate: -3000 });

expect(uuid).toSatisfy(isUuidV7);
expect(uuid).toStartWith('00000000-0000');
});

it('generates max bytes in the unix part if the maximum unix time epoch is given as a ref date', () => {
const uuid = faker.string.uuid({
version: 7,
refDate: 0xffffffffffff,
});

expect(uuid).toSatisfy(isUuidV7);
expect(uuid).toStartWith('ffffffff-ffff');
});
});
});

Expand Down
Loading