From 2f1c4c70ca84463b9f15ae37e27e061cf28d8df3 Mon Sep 17 00:00:00 2001 From: Spencer Brower Date: Tue, 30 May 2023 15:07:26 -0400 Subject: [PATCH] feat: Added functions for shortening strings. --- docs/modules.md | 257 ++++++++++++++++++++++++++++++++++++++++++++ src/index.spec.ts | 5 +- src/index.ts | 27 +---- src/shorten.spec.ts | 19 ++++ src/shorten.ts | 16 +++ src/utils.ts | 8 +- 6 files changed, 304 insertions(+), 28 deletions(-) create mode 100644 src/shorten.spec.ts create mode 100644 src/shorten.ts diff --git a/docs/modules.md b/docs/modules.md index 5f0760b..e694380 100644 --- a/docs/modules.md +++ b/docs/modules.md @@ -7,10 +7,17 @@ ### Functions - [afterFirst](modules.md#afterfirst) +- [afterFirstWord](modules.md#afterfirstword) - [afterLast](modules.md#afterlast) +- [beforeFirst](modules.md#beforefirst) +- [beforeFirstWord](modules.md#beforefirstword) - [endsWith](modules.md#endswith) - [ltrim](modules.md#ltrim) +- [removeFirstWord](modules.md#removefirstword) +- [removeWordsFromBeginning](modules.md#removewordsfrombeginning) - [rtrim](modules.md#rtrim) +- [shorten](modules.md#shorten) +- [shorterThan](modules.md#shorterthan) - [startsWith](modules.md#startswith) - [trim](modules.md#trim) @@ -58,6 +65,26 @@ node_modules/ts-toolbelt/out/Function/Curry.d.ts:77 ___ +### afterFirstWord + +▸ **afterFirstWord**(`str`): `string` + +#### Parameters + +| Name | Type | +| :------ | :------ | +| `str` | `string` | + +#### Returns + +`string` + +#### Defined in + +[src/index.ts:34](https://github.com/sbrow/strings/blob/7b676b7/src/index.ts#L34) + +___ + ### afterLast ▸ **afterLast**<`P`, `G`, `R`\>(`...p`): `RequiredKeys`<`ObjectOf`<`G`\>\> extends `never` ? `R` : `Curry`<(...`p`: `G`) => `R`\> @@ -100,6 +127,90 @@ node_modules/ts-toolbelt/out/Function/Curry.d.ts:77 ___ +### beforeFirst + +▸ **beforeFirst**<`P`, `G`, `R`\>(`...p`): `RequiredKeys`<`ObjectOf`<`G`\>\> extends `never` ? `R` : `Curry`<(...`p`: `G`) => `R`\> + +Curry a [[Function]] + +**`Example`** + +```ts +import {F} from 'ts-toolbelt' + +/// If you are looking for creating types for `curry` +/// It handles placeholders and variable arguments +declare function curry(fn: Fn): F.Curry +``` + +#### Type parameters + +| Name | Type | +| :------ | :------ | +| `P` | extends [separator: string \| typeof \_, str: string \| typeof \_] | +| `G` | extends readonly `any`[] = `GapsOf`<`P`, [separator: string, str: string]\> | +| `R` | extends `unknown` = `string` | + +#### Parameters + +| Name | Type | +| :------ | :------ | +| `...p` | `P` \| [separator: string \| typeof \_, str: string \| typeof \_] | + +#### Returns + +`RequiredKeys`<`ObjectOf`<`G`\>\> extends `never` ? `R` : `Curry`<(...`p`: `G`) => `R`\> + +[[Function]] + +#### Defined in + +node_modules/ts-toolbelt/out/Function/Curry.d.ts:77 + +___ + +### beforeFirstWord + +▸ **beforeFirstWord**<`P`, `G`, `R`\>(`...p`): `RequiredKeys`<`ObjectOf`<`G`\>\> extends `never` ? `R` : `Curry`<(...`p`: `G`) => `R`\> + +Curry a [[Function]] + +**`Example`** + +```ts +import {F} from 'ts-toolbelt' + +/// If you are looking for creating types for `curry` +/// It handles placeholders and variable arguments +declare function curry(fn: Fn): F.Curry +``` + +#### Type parameters + +| Name | Type | +| :------ | :------ | +| `P` | extends [str: string \| typeof \_] | +| `G` | extends readonly `any`[] = `GapsOf`<`P`, [str: string]\> | +| `R` | extends `unknown` = `string` | + +#### Parameters + +| Name | Type | +| :------ | :------ | +| `...p` | `P` \| [str: string \| typeof \_] | + +#### Returns + +`RequiredKeys`<`ObjectOf`<`G`\>\> extends `never` ? `R` : `Curry`<(...`p`: `G`) => `R`\> + +[[Function]] + +#### Defined in + +node_modules/ts-toolbelt/out/Function/Curry.d.ts:77 + +___ + ### endsWith ▸ **endsWith**<`P`, `G`, `R`\>(`...p`): `RequiredKeys`<`ObjectOf`<`G`\>\> extends `never` ? `R` : `Curry`<(...`p`: `G`) => `R`\> @@ -172,6 +283,68 @@ node_modules/ts-toolbelt/out/Function/Curry.d.ts:77 ___ +### removeFirstWord + +▸ **removeFirstWord**(`str`): `string` + +#### Parameters + +| Name | Type | +| :------ | :------ | +| `str` | `string` | + +#### Returns + +`string` + +#### Defined in + +[src/index.ts:35](https://github.com/sbrow/strings/blob/7b676b7/src/index.ts#L35) + +___ + +### removeWordsFromBeginning + +▸ **removeWordsFromBeginning**<`P`, `G`, `R`\>(`...p`): `RequiredKeys`<`ObjectOf`<`G`\>\> extends `never` ? `R` : `Curry`<(...`p`: `G`) => `R`\> + +Curry a [[Function]] + +**`Example`** + +```ts +import {F} from 'ts-toolbelt' + +/// If you are looking for creating types for `curry` +/// It handles placeholders and variable arguments +declare function curry(fn: Fn): F.Curry +``` + +#### Type parameters + +| Name | Type | +| :------ | :------ | +| `P` | extends [maxChars: number \| typeof \_, str: string \| typeof \_] | +| `G` | extends readonly `any`[] = `GapsOf`<`P`, [maxChars: number, str: string]\> | +| `R` | extends `unknown` = `unknown` | + +#### Parameters + +| Name | Type | +| :------ | :------ | +| `...p` | `P` \| [maxChars: number \| typeof \_, str: string \| typeof \_] | + +#### Returns + +`RequiredKeys`<`ObjectOf`<`G`\>\> extends `never` ? `R` : `Curry`<(...`p`: `G`) => `R`\> + +[[Function]] + +#### Defined in + +node_modules/ts-toolbelt/out/Function/Curry.d.ts:77 + +___ + ### rtrim ▸ **rtrim**<`P`, `G`, `R`\>(`...p`): `RequiredKeys`<`ObjectOf`<`G`\>\> extends `never` ? `R` : `Curry`<(...`p`: `G`) => `R`\> @@ -214,6 +387,90 @@ node_modules/ts-toolbelt/out/Function/Curry.d.ts:77 ___ +### shorten + +▸ **shorten**<`P`, `G`, `R`\>(`...p`): `RequiredKeys`<`ObjectOf`<`G`\>\> extends `never` ? `R` : `Curry`<(...`p`: `G`) => `R`\> + +Curry a [[Function]] + +**`Example`** + +```ts +import {F} from 'ts-toolbelt' + +/// If you are looking for creating types for `curry` +/// It handles placeholders and variable arguments +declare function curry(fn: Fn): F.Curry +``` + +#### Type parameters + +| Name | Type | +| :------ | :------ | +| `P` | extends [maxChars: number \| typeof \_, strategy: any] | +| `G` | extends readonly `any`[] = `GapsOf`<`P`, [maxChars: number, strategy: any]\> | +| `R` | extends `unknown` = (`init`: `unknown`) => `unknown` | + +#### Parameters + +| Name | Type | +| :------ | :------ | +| `...p` | `P` \| [maxChars: number \| typeof \_, strategy: any] | + +#### Returns + +`RequiredKeys`<`ObjectOf`<`G`\>\> extends `never` ? `R` : `Curry`<(...`p`: `G`) => `R`\> + +[[Function]] + +#### Defined in + +node_modules/ts-toolbelt/out/Function/Curry.d.ts:77 + +___ + +### shorterThan + +▸ **shorterThan**<`P`, `G`, `R`\>(`...p`): `RequiredKeys`<`ObjectOf`<`G`\>\> extends `never` ? `R` : `Curry`<(...`p`: `G`) => `R`\> + +Curry a [[Function]] + +**`Example`** + +```ts +import {F} from 'ts-toolbelt' + +/// If you are looking for creating types for `curry` +/// It handles placeholders and variable arguments +declare function curry(fn: Fn): F.Curry +``` + +#### Type parameters + +| Name | Type | +| :------ | :------ | +| `P` | extends [maxChars: number \| typeof \_, str: string \| typeof \_] | +| `G` | extends readonly `any`[] = `GapsOf`<`P`, [maxChars: number, str: string]\> | +| `R` | extends `unknown` = `boolean` | + +#### Parameters + +| Name | Type | +| :------ | :------ | +| `...p` | `P` \| [maxChars: number \| typeof \_, str: string \| typeof \_] | + +#### Returns + +`RequiredKeys`<`ObjectOf`<`G`\>\> extends `never` ? `R` : `Curry`<(...`p`: `G`) => `R`\> + +[[Function]] + +#### Defined in + +node_modules/ts-toolbelt/out/Function/Curry.d.ts:77 + +___ + ### startsWith ▸ **startsWith**<`P`, `G`, `R`\>(`...p`): `RequiredKeys`<`ObjectOf`<`G`\>\> extends `never` ? `R` : `Curry`<(...`p`: `G`) => `R`\> diff --git a/src/index.spec.ts b/src/index.spec.ts index 41817b2..4d1fc13 100644 --- a/src/index.spec.ts +++ b/src/index.spec.ts @@ -1,7 +1,8 @@ -import { describe, expect, it } from "vitest"; import fc from "fast-check"; +import { describe, expect, it } from "vitest"; + import { - /*afterFirstWord, beforeFirstWord, */ afterFirst, + afterFirst, afterLast, endsWith, ltrim, diff --git a/src/index.ts b/src/index.ts index 5ba2047..4c19d56 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,6 @@ import { curry } from "./utils"; +export * from "./shorten"; export * from "./trim"; function escapeRegExp(str: string) { @@ -31,28 +32,4 @@ export const beforeFirstWord = beforeFirst(" "); // @todo Test export const afterFirstWord: (str: string) => string = afterFirst(" "); -export const removeFirstWord: (str: string) => string = 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), -// ); +export const removeFirstWord: (str: string) => string = afterFirstWord; \ No newline at end of file diff --git a/src/shorten.spec.ts b/src/shorten.spec.ts new file mode 100644 index 0000000..d39c79c --- /dev/null +++ b/src/shorten.spec.ts @@ -0,0 +1,19 @@ +import { describe, it, expect } from "vitest"; + +import { removeWordsFromBeginning, shorten } from "./index"; + +describe("shorten", () => { + it("shortens a string to the desired length", () => { + expect( + shorten(6, (str) => str.substring(0, str.length - 1))("foobarbat") + ).toBe("foobar"); + expect(shorten(6, (str) => str.substring(1))("foobarbat")).toBe("barbat"); + }); +}); + +describe("removeWordsFromBeginning", () => { + it("removes words from the beginning of a string", () => { + expect(removeWordsFromBeginning(7, "foo bar bat")).toBe("bar bat"); + expect(removeWordsFromBeginning(7, "foo bar bat baz")).toBe("bat baz"); + }); +}); diff --git a/src/shorten.ts b/src/shorten.ts new file mode 100644 index 0000000..077e631 --- /dev/null +++ b/src/shorten.ts @@ -0,0 +1,16 @@ +import { removeFirstWord } from "./index"; +import { curry, until } from "./utils"; + + +export const shorterThan = curry((maxChars: number, str: string) => str.length <= maxChars); + +export const shorten = curry((maxChars: number, strategy) => until(shorterThan(maxChars) as (str: string) => boolean, strategy)); + +export const removeWordsFromBeginning = curry((maxChars: number, str: string) => shorten(maxChars, removeFirstWord)(str)); + +/* +export const removeWordsFromBeginning = uncurryN( + 2, + (maxChars: number) => shorten(maxChars, removeFirstWord), + ); +*/ \ No newline at end of file diff --git a/src/utils.ts b/src/utils.ts index 5ed84dd..59ef056 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,4 +1,4 @@ -import type { curry as _curry, when as _when } from "ramda"; +import type { curry as _curry, until as _until, when as _when } from "ramda"; export const curry = function (fn) { return (...args) => { @@ -18,3 +18,9 @@ export const tail = (str: string) => str.substring(1); export const when = curry((predicate, whenTrueFn, arg) => { return predicate(arg) ? whenTrueFn(arg) : arg; }) as typeof _when; + +export const until = curry((predicate, fn, arg) => { + const loop = (a: typeof arg): typeof a => predicate(a) ? a : loop(fn(a)); + + return loop(arg); +}) as typeof _until; \ No newline at end of file