diff --git a/src/utils.ts b/src/utils.ts index 61fd39f..075c996 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -2,18 +2,39 @@ import { customAlphabet, urlAlphabet } from 'nanoid' import * as types from './types' +/** + * Extracts the first JSON object string from a given string. + * + * @param text - string from which to extract the JSON object + * @returns extracted JSON object string, or `undefined` if no JSON object is found + */ export function extractJSONObjectFromString(text: string): string | undefined { return text.match(/\{(.|\n)*\}/gm)?.[0] } +/** + * Extracts the first JSON array string from a given string. + * + * @param text - string from which to extract the JSON array + * @returns extracted JSON array string, or `undefined` if no JSON array is found + */ export function extractJSONArrayFromString(text: string): string | undefined { return text.match(/\[(.|\n)*\]/gm)?.[0] } +/** + * Pauses the execution of a function for a specified time. + * + * @param ms - number of milliseconds to pause + * @returns promise that resolves after the specified number of milliseconds + */ export function sleep(ms: number) { return new Promise((resolve) => setTimeout(resolve, ms)) } +/** + * A default ID generator function that uses a custom alphabet based on URL safe symbols. + */ export const defaultIDGeneratorFn: types.IDGeneratorFunction = customAlphabet(urlAlphabet) @@ -23,28 +44,27 @@ export function isValidTaskIdentifier(id: string): boolean { } /** - * Chunk a string into an array of strings of a given length + * Chunks a string into an array of chunks. * * @param text - string to chunk - * @param length - maximum length of each chunk - * @returns array of strings + * @param maxLength - maximum length of each chunk + * @returns array of chunks */ -export const chunkString = (text: string, length: number) => { +export const chunkString = (text: string, maxLength: number) => { const words = text.split(' ') const chunks: string[] = [] let chunk = '' for (const word of words) { - if (word.length > length) { + if (word.length > maxLength) { // Truncate the word if it's too long and indicate that it was truncated: - chunks.push(word.substring(0, length - 3) + '...') - } - - if ((chunk + word).length > length) { + chunks.push(word.substring(0, maxLength - 3) + '...') + } else if ((chunk + word + 1).length > maxLength) { + // +1 accounts for the space between words chunks.push(chunk.trim()) chunk = word } else { - chunk += ' ' + word + chunk += (chunk ? ' ' : '') + word } } diff --git a/test/utils.test.ts b/test/utils.test.ts index dbf4c2f..65413d6 100644 --- a/test/utils.test.ts +++ b/test/utils.test.ts @@ -1,6 +1,13 @@ import test from 'ava' -import { isValidTaskIdentifier } from '@/utils' +import { + chunkString, + defaultIDGeneratorFn, + extractJSONArrayFromString, + extractJSONObjectFromString, + isValidTaskIdentifier, + sleep +} from '@/utils' test('isValidTaskIdentifier - valid', async (t) => { t.true(isValidTaskIdentifier('foo')) @@ -18,3 +25,53 @@ test('isValidTaskIdentifier - invalid', async (t) => { t.false(isValidTaskIdentifier('x'.repeat(65))) t.false(isValidTaskIdentifier('-foo')) }) + +test('extractJSONObjectFromString should extract first JSON object from string', (t) => { + const jsonString = '{"name":"John"} Some other text {"name":"Doe"}' + const result = extractJSONObjectFromString(jsonString) + t.is(result, '{"name":"John"}') +}) + +test('extractJSONArrayFromString should extract first JSON array from string', (t) => { + const jsonString = '[1,2,3] Some other text [4,5,6]' + const result = extractJSONArrayFromString(jsonString) + t.is(result, '[1,2,3]') +}) + +test('extractJSONObjectFromString should return undefined if no JSON object is found', (t) => { + const jsonString = 'Some text' + const result = extractJSONObjectFromString(jsonString) + t.is(result, undefined) +}) + +test('extractJSONArrayFromString should return undefined if no JSON array is found', (t) => { + const jsonString = 'Some text' + const result = extractJSONArrayFromString(jsonString) + t.is(result, undefined) +}) + +test('sleep should delay execution', async (t) => { + const start = Date.now() + await sleep(1000) // for example, 1000ms / 1sec + const end = Date.now() + t.true(end - start >= 1000) +}) + +test('defaultIDGeneratorFn should generate URL-safe string', (t) => { + const result = defaultIDGeneratorFn() + + // Check if generated string matches URL-safe characters: + t.regex(result, /^[A-Za-z0-9\-_]+$/) +}) + +test('chunkString should split string into chunks', (t) => { + const text = 'Hello, this is a test string for chunkString function.' + const chunks = chunkString(text, 12) + t.deepEqual(chunks, [ + 'Hello, this', + 'is a test', + 'string for', + 'chunkString', + 'function.' + ]) +})