feat: First commit.

This commit is contained in:
Spencer Brower
2023-05-25 13:33:36 -04:00
commit 3f018acd2c
9 changed files with 846 additions and 0 deletions

55
src/index.spec.ts Normal file
View File

@@ -0,0 +1,55 @@
import { describe, expect, it } from 'vitest';
import fc from 'fast-check';
import {
afterFirstWord, beforeFirstWord, endsWith, ltrim, startsWith,
} from './index';
describe('strings', () => {
// describe('afterFirstWord', () => {
// it('removes the first word', () => {
// fc.assert(fc.property(fc.string(), (str) => {
// const got = afterFirstWord(str);
// if (got !== '') {
// expect(endsWith(got, str)).toBe(true);
// if (str.indexOf(' ') !== -1) {
// expect(`${beforeFirstWord(str)} ${got}`).toBe(str);
// }
// }
// }));
// });
// });
describe('ltrim', () => {
it('returns input when cutset is empty', () => {
expect(ltrim('', 'foo')).toBe('foo');
});
it('returns empty when input is empty', () => {
expect(ltrim('foo', '')).toBe('');
});
it('can be curried', () => {
expect(ltrim('foo', '')).toBe(ltrim('foo')(''));
expect(ltrim(' ', 'foo')).toBe(ltrim(' ')('foo'));
});
it('trims cutset', () => {
fc.assert(fc.property(fc.string(), fc.string(), (cutset, str) => {
const got = ltrim(cutset, str);
if (cutset === '') {
expect(got).toBe(str);
} else if (str === '') {
expect(got).toBe('');
} else {
if (got === '') {
for (const char of str) {
expect(cutset).contains(char);
}
}
for (const char of cutset) {
expect(startsWith(char, got)).toBe(false);
}
}
}));
});
});
});

92
src/index.ts Normal file
View File

@@ -0,0 +1,92 @@
// import { compose, curry, isEmpty, uncurryN, until, when, } from 'ramda'
import { curry, isEmpty, tail, when } from "./utils";
// function escapeRegExp(string) {
// return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
// }
export const startsWith = curry((needle, haystack) => haystack.indexOf(needle) === 0);
// export const endsWith = curry((needle, haystack) => (new RegExp(`${escapeRegExp(needle)}$`)).test(haystack));
// export const ltrim = (cutset: string, str = undefined) => {
// if (str === undefined) {
// return str => ltrim(cutset, str);
// }
// if (isEmpty(cutset) || isEmpty(str)) {
// return str
// }
// // const _trim = x => ltrim(cutset)(tail(x));
// const _trim = compose(ltrim(cutset), tail)
// return when((x = '') => cutset.includes(x.charAt(0)), _trim)(str);
// }
/** String -> String -> String */
export const ltrim = curry((cutset: string, str: string) => {
const _trim = x => ltrim(cutset)(tail(x));
// const _trim = compose(ltrim(cutset), tail);
return isEmpty(cutset) || isEmpty(str)
? str
: when((x = '') => cutset.includes(x.charAt(0)), _trim, str);
});
// export const afterFirst = curry(
// /**
// * @param {String} separator
// * @param {String} str
// * @return {String}
// */
// (separator, str) => str.substring(str.indexOf(separator) + 1, str.length),
// );
// export const beforeFirst = curry(
// /**
// *
// * @param {String} separator
// * @param {String} str
// * @returns {String}
// */
// (separator, str) => str.substring(0, str.indexOf(separator)),
// );
// export const beforeFirstWord = beforeFirst(' ');
// /**
// * @param {String} str
// * @return {String}
// */
// export function afterFirstWord(str) {
// return afterFirst(' ', str);
// }
// export const removeFirstWord = afterFirstWord;
// /**
// * @param {Number} maxChars
// * @param {String} str
// * @return {Boolean} False if str is longer than maxChars characters.
// */
// const shorterThan = curry((maxChars, str) => str.length <= maxChars);
// /**
// * @param {Number} maxChars The maximum length of the desired output string.
// * @param strategy a function that accepts a string and returns a shorter string.
// * @return {String} The input string, shortened to maxChars by strategy.
// */
// const shortenString = (maxChars, strategy) => until(shorterThan(maxChars), strategy);
// /**
// * @param {Number} maxChars
// * @param {String} str The string to remove words from.
// * @return {String} the shortened string.
// */
// export const removeWordsFromStartOfString = uncurryN(
// 2,
// (maxChars) => shortenString(maxChars, removeFirstWord),
// );

20
src/utils.ts Normal file
View File

@@ -0,0 +1,20 @@
type Predicate<T> = (arg: T) => boolean;
type Fn<T, U = any> = (arg: T) => U;
export function curry (fn) {
return (...args) => {
if (args.length >= fn.length) {
return fn(...args);
}
return (...more) => curry(fn)(...args, ...more);
}
}
export const isEmpty = (str: string) => str == null || str === '';
export const tail = (str: string) => str.substring(1);
export function when<T>(predicate: Predicate<T>, whenTrueFn: Fn<T>, arg: T): any {
return predicate(arg) ? whenTrueFn(arg) : arg;
}