From c734f730b41eaa2adad8226d6b36ef8819916cbc Mon Sep 17 00:00:00 2001 From: D-Sketon <2055272094@qq.com> Date: Tue, 24 Sep 2024 09:38:18 +0800 Subject: [PATCH] feat(compat): implement pad (#584) --- benchmarks/performance/pad.bench.ts | 14 ++++-- benchmarks/performance/padEnd.bench.ts | 8 +-- src/compat/index.ts | 1 + src/compat/string/pad.spec.ts | 67 ++++++++++++++++++++++++++ src/compat/string/pad.ts | 21 ++++++++ 5 files changed, 103 insertions(+), 8 deletions(-) create mode 100644 src/compat/string/pad.spec.ts create mode 100644 src/compat/string/pad.ts diff --git a/benchmarks/performance/pad.bench.ts b/benchmarks/performance/pad.bench.ts index 68503248a..b90bdbd2a 100644 --- a/benchmarks/performance/pad.bench.ts +++ b/benchmarks/performance/pad.bench.ts @@ -1,15 +1,21 @@ import { bench, describe } from 'vitest'; -import { pad as padStartToolkit } from 'es-toolkit'; -import { pad as padStartLodash } from 'lodash'; +import { pad as padToolkit } from 'es-toolkit'; +import { pad as padToolkitCompat } from 'es-toolkit/compat'; +import { pad as padLodash } from 'lodash'; describe('pad', () => { bench('es-toolkit/pad', () => { const str = 'abc'; - padStartToolkit(str, 6, '_-'); + padToolkit(str, 6, '_-'); + }); + + bench('es-toolkit/compat/pad', () => { + const str = 'abc'; + padToolkitCompat(str, 6, '_-'); }); bench('lodash/pad', () => { const str = 'abc'; - padStartLodash(str, 6, '_-'); + padLodash(str, 6, '_-'); }); }); diff --git a/benchmarks/performance/padEnd.bench.ts b/benchmarks/performance/padEnd.bench.ts index 5c056a0e0..ddc7801ca 100644 --- a/benchmarks/performance/padEnd.bench.ts +++ b/benchmarks/performance/padEnd.bench.ts @@ -1,15 +1,15 @@ import { bench, describe } from 'vitest'; -import { padEnd as padStartToolkit } from 'es-toolkit/compat'; -import { padEnd as padStartLodash } from 'lodash'; +import { padEnd as padEndToolkit } from 'es-toolkit/compat'; +import { padEnd as padEndLodash } from 'lodash'; describe('padEnd', () => { bench('es-toolkit/padEnd', () => { const str = 'abc'; - padStartToolkit(str, 6, '_-'); + padEndToolkit(str, 6, '_-'); }); bench('lodash/padEnd', () => { const str = 'abc'; - padStartLodash(str, 6, '_-'); + padEndLodash(str, 6, '_-'); }); }); diff --git a/src/compat/index.ts b/src/compat/index.ts index 887b1fb74..24ce9fe32 100644 --- a/src/compat/index.ts +++ b/src/compat/index.ts @@ -106,6 +106,7 @@ export { lowerCase } from './string/lowerCase.ts'; export { upperCase } from './string/upperCase.ts'; export { startsWith } from './string/startsWith.ts'; export { endsWith } from './string/endsWith.ts'; +export { pad } from './string/pad.ts'; export { padStart } from './string/padStart.ts'; export { padEnd } from './string/padEnd.ts'; export { repeat } from './string/repeat.ts'; diff --git a/src/compat/string/pad.spec.ts b/src/compat/string/pad.spec.ts new file mode 100644 index 000000000..d5408c4fc --- /dev/null +++ b/src/compat/string/pad.spec.ts @@ -0,0 +1,67 @@ +import { describe, it, expect } from 'vitest'; +import { pad } from './pad'; + +describe('pad', () => { + it(`\`pad\` should not pad if string is >= \`length\``, () => { + expect(pad('abc', 2)).toBe('abc'); + expect(pad('abc', 3)).toBe('abc'); + }); + + it(`\`pad\` should treat negative \`length\` as \`0\``, () => { + [0, -2].forEach(length => { + expect(pad('abc', length)).toBe('abc'); + }); + }); + + it(`\`pad\` should coerce \`length\` to a number`, () => { + ['', '4'].forEach(length => { + const actual = length ? 'abc ' : 'abc'; + // @ts-expect-error - invalid length + expect(pad('abc', length)).toBe(actual); + }); + }); + + it(`\`pad\` should treat nullish values as empty strings`, () => { + [undefined, '_-'].forEach(chars => { + const expected = chars ? '__' : ' '; + // @ts-expect-error - invalid string + expect(pad(null, 2, chars)).toBe(expected); + // @ts-expect-error - invalid string + expect(pad(undefined, 2, chars)).toBe(expected); + expect(pad('', 2, chars)).toBe(expected); + }); + }); + + it(`\`pad\` should return \`string\` when \`chars\` coerces to an empty string`, () => { + const values = ['', Object('')]; + const expected = values.map(() => 'abc'); + + const actual = values.map(value => pad('abc', 6, value)); + + expect(actual).toEqual(expected); + }); + + it('should pad a string to a given length', () => { + // eslint-disable-next-line no-sparse-arrays + const values = [, undefined]; + const expected = values.map(() => ' abc '); + + const actual = values.map((value, index) => (index ? pad('abc', 6, value) : pad('abc', 6))); + + expect(actual).toEqual(expected); + }); + + it('should truncate pad characters to fit the pad length', () => { + expect(pad('abc', 8)).toBe(' abc '); + expect(pad('abc', 8, '_-')).toBe('_-abc_-_'); + }); + + it('should coerce `string` to a string', () => { + const values = [Object('abc'), { toString: () => 'abc' }]; + const expected = values.map(() => true); + + const actual = values.map(value => pad(value, 6) === ' abc '); + + expect(actual).toEqual(expected); + }); +}); diff --git a/src/compat/string/pad.ts b/src/compat/string/pad.ts new file mode 100644 index 000000000..d1836f8c0 --- /dev/null +++ b/src/compat/string/pad.ts @@ -0,0 +1,21 @@ +import { pad as padToolkit } from '../../string/pad.ts'; +import { toString } from '../util/toString.ts'; +/** + * Pads string on the left and right sides if it's shorter than length. Padding characters are truncated if they can't be evenly divided by length. + * If the length is less than or equal to the original string's length, or if the padding character is an empty string, the original string is returned unchanged. + * + * @param {string} str - The string to pad. + * @param {number} [length] - The length of the resulting string once padded. + * @param {string} [chars] - The character(s) to use for padding. + * @returns {string} - The padded string, or the original string if padding is not required. + * + * @example + * const result1 = pad('abc', 8); // result will be ' abc ' + * const result2 = pad('abc', 8, '_-'); // result will be '_-abc_-_' + * const result3 = pad('abc', 3); // result will be 'abc' + * const result4 = pad('abc', 2); // result will be 'abc' + * + */ +export function pad(str: string, length: number, chars = ' '): string { + return padToolkit(toString(str), length, chars); +}