Skip to content

Commit

Permalink
feat: add truncate function (#41)
Browse files Browse the repository at this point in the history
  • Loading branch information
p9f committed Oct 6, 2023
1 parent 616a048 commit 673e53d
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 2 deletions.
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ It also only work with common ASCII characters characters. We don't plan to supp
- [toPascalCase](#topascalcase)
- [toSnakeCase](#tosnakecase)
- [toTitleCase](#totitlecase)
- [truncate](#truncate)
- [words](#words)
- [Strongly-typed shallow transformation of objects](#strongly-typed-shallow-transformation-of-objects)
- [camelKeys](#camelkeys)
Expand Down Expand Up @@ -499,6 +500,19 @@ const result = toTitleCase(str)
// ^ 'Hello World'
```

### truncate

This function truncates string if it's longer than the given maximum string length. The last characters of the truncated string are replaced with the omission string which defaults to "...".


```ts
import { truncate } from 'string-ts'

const str = '-20someVery-weird String'
const result = truncate(str, 8)
// ^ '-20so...'
```

### words

This function identifies the words in a string and returns a tuple of words split by separators, differences in casing, numbers, and etc.
Expand Down Expand Up @@ -743,6 +757,7 @@ St.Trim<' hello world '> // 'hello world'
St.StartsWith<'abc', 'a'> // true
St.TrimEnd<' hello world '> // ' hello world'
St.TrimStart<' hello world '> // 'hello world '
St.Truncate<'hello world', 9, '[...]'> // 'hello[...]
St.Words<'hello-world'> // ['hello', 'world']
```

Expand Down
3 changes: 2 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,10 @@ export type {
IsSpecial,
IsUpper,
Separator,
Truncate,
Words,
} from './utils'
export { words } from './utils'
export { truncate, words } from './utils'

// CASING
export type {
Expand Down
52 changes: 52 additions & 0 deletions src/utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,21 @@ namespace WordsTests {
>
}

namespace TruncateTests {
type test1 = Expect<Equal<Subject.Truncate<'Hello, world', 9>, 'Hello,...'>>
type test2 = Expect<
Equal<Subject.Truncate<'Hello, world', 12>, 'Hello, world'>
>
type test3 = Expect<Equal<Subject.Truncate<'Hello, world', 2>, '...'>>
type test4 = Expect<
Equal<Subject.Truncate<'Hello, world', 9, '[...]'>, 'Hell[...]'>
>
type test5 = Expect<Equal<Subject.Truncate<'Hello, world', -1>, '...'>>
type test6 = Expect<
Equal<Subject.Truncate<'Hello, world', 0, '[...]'>, '[...]'>
>
}

describe('words', () => {
test('it splits words at separators', () => {
const expected = [
Expand Down Expand Up @@ -125,3 +140,40 @@ describe('words', () => {
type test = Expect<Equal<typeof result, Mutable<typeof expected>>>
})
})

describe('truncate', () => {
test('truncate small sentence does nothing', () => {
const expected = 'Hello' as const
const result = subject.truncate('Hello', 9)
expect(result).toEqual(expected)
type test = Expect<Equal<typeof result, typeof expected>>
})

test('truncate big sentence truncate', () => {
const expected = 'Hello ...' as const
const result = subject.truncate('Hello world', 9)
expect(result).toEqual(expected)
type test = Expect<Equal<typeof result, typeof expected>>
})

test('truncate with negative integer does truncate', () => {
const expected = '...' as const
const result = subject.truncate('Hello world', -1)
expect(result).toEqual(expected)
type test = Expect<Equal<typeof result, typeof expected>>
})

test('truncate big sentence with specified omission', () => {
const expected = 'Hello[...]' as const
const result = subject.truncate('Hello world', 10, '[...]')
expect(result).toEqual(expected)
type test = Expect<Equal<typeof result, typeof expected>>
})

test('truncate small sentence with specified omission', () => {
const expected = 'Hello' as const
const result = subject.truncate('Hello', 10, '[...]')
expect(result).toEqual(expected)
type test = Expect<Equal<typeof result, typeof expected>>
})
})
38 changes: 37 additions & 1 deletion src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import type { Math } from './math'
import { join, type Join, type Length, type Slice } from './primitives'
import type { Drop, DropSuffix } from './internals'

type Digit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'
Expand Down Expand Up @@ -161,6 +163,39 @@ function words<T extends string>(sentence: T): Words<T> {
.split(/\s+/g) as Words<T>
}

/**
* Truncate a string if it's longer than the given maximum length.
* The last characters of the truncated string are replaced with the omission string which defaults to "...".
*/
type Truncate<
T extends string,
Size extends number,
Omission extends string = '...',
> = Math.IsNegative<Size> extends true
? Omission
: Math.Subtract<Length<T>, Size> extends 0
? T
: Join<[Slice<T, 0, Math.Subtract<Size, Length<Omission>>>, Omission]>

/**
* A strongly typed function to truncate a string if it's longer than the given maximum string length.
* The last characters of the truncated string are replaced with the omission string which defaults to "...".
* @param sentence the sentence to extract the words from.
* @param length the maximum length of the string.
* @param omission the string to append to the end of the truncated string.
* @returns the truncated string
* @example truncate('Hello, World', 8) // 'Hello...'
*/
function truncate<T extends string, S extends number, P extends string = '...'>(
sentence: T,
length: S,
omission = '...' as P,
): Truncate<T, S, P> {
if (length < 0) return omission as Truncate<T, S, P>
if (sentence.length <= length) return sentence as Truncate<T, S, P>
return join([sentence.slice(0, length - omission.length), omission])
}

export type {
Digit,
Is,
Expand All @@ -172,6 +207,7 @@ export type {
IsUpper,
Separator,
TupleOf,
Truncate,
Words,
}
export { words }
export { truncate, words }

0 comments on commit 673e53d

Please sign in to comment.