Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add dedent function #120

Merged
merged 11 commits into from
Dec 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/next-minor.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ https://github.com/radashi-org/radashi/pull/305

https://github.com/radashi-org/radashi/pull/250

#### dedent

https://github.com/radashi-org/radashi/pull/120

## New Features

#### Add `signal` option to `retry`
Expand Down
21 changes: 21 additions & 0 deletions benchmarks/string/dedent.bench.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import * as _ from 'radashi'
import { bench } from 'vitest'

describe('dedent', () => {
const input = `
Hello
World
`

bench('dedent as tagged template literal', () => {
_.dedent`
Hello
World
${[1, 2, 3].join('\n')}
`
})

bench('dedent as direct call', () => {
_.dedent(input)
})
})
134 changes: 134 additions & 0 deletions docs/string/dedent.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
---
title: dedent
description: Remove indentation from a string
since: 12.3.0
---

### Usage

Remove indentation from every line of a given string. Optionally, provide your own `indent` to control the amount of indentation to remove. If you don't provide an `indent`, the amount of indentation to remove is determined by the first non-empty line of the given string.

```ts
import * as _ from 'radashi'

// Explicit indentation
_.dedent('\n Hello\n World!\n\n', ' ')
// => ' Hello\n World!\n'

// Detected indentation
_.dedent('\n Hello\n World!\n\n')
// => 'Hello\nWorld!\n'
```

#### Tagged template strings

When using `dedent` in a tagged template string, the indentation is always inferred.

```ts
// Real-world example: Email template
const emailTemplate = _.dedent`
Hello, ${userName}!

Thank you for your recent purchase. Your order details are below:
Order ID: ${orderId}
Product: ${productName}
Quantity: ${quantity}

If you have any questions, please contact our support team.

Best regards,
The Support Team
`
// => `Hello, JohnDoe!
//
// Thank you for your recent purchase. Your order details are below:
// Order ID: 12345
// Product: Widget
// Quantity: 2
//
// If you have any questions, please contact our support team.
//
// Best regards,
// The Support Team`
```

### Multi-line embedded strings

When embedding a string with `dedent`, you don't have to worry about the indentation of the embedded string. For example, if you have an array where each item needs its own line, just join it with `join('\n')` and `dedent` will make sure it all works out.

```ts
const items = ['one', 'two', 'three']
const list = _.dedent`
My List:
${items.join('\n')}
`
// => 'My List:\n one\n two\n three'
```

### Spacing issues?

There's a common use case of building up a long string of “paragraphs” (for lack of a better word) using `if` conditions and `dedent`. If you can't get an empty line to appear between two paragraphs, you're not alone and this section is for you.

Since `dedent` strips the first and last empty line of a given string, your dedented string has no spacing around it by default. You might try to include an empty line at the start of each paragraph to achieve the desired spacing, like the following example.

```ts
let story = dedent`
There once was a programmer
who had a lot of trouble.
`

if (isLateAtNight()) {
story += dedent`

He was so confused
that he couldn't even
tell what was going on.
`
}

story
// =>
// There once was a programmer
// who had a lot of trouble.
// He was so confused
// that he couldn't even
// tell what was going on.
```

The empty line above "He was so confused" was intended to separate the paragraph from the previous one. But as you can see, it didn't work. The empty line you added was appended to the last line of the previous paragraph ("who had a lot of trouble") instead of being a separate line.

Here are 3 possible solutions for this issue. Pick your favorite:

1. Add `\n` to your empty line.

```ts
story += dedent`
\n
He was so confused
that he couldn't even
tell what was going on.
`
```

2. Append the line breaks separately.

```ts
story += '\n\n'
story += dedent`
He was so confused
that he couldn't even
tell what was going on.
`
```

3. Include two empty lines at the start of each paragraph. (An unadvised solution as its intention is not the most clear)

```ts
story += dedent`


He was so confused
that he couldn't even
tell what was going on.
`
```
2 changes: 1 addition & 1 deletion scripts/benchmarks/src/compareToBaseline.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import * as esbuild from 'esbuild'
import { execa } from 'execa'
import fs from 'node:fs/promises'
import { dedent } from 'radashi/string/dedent.ts'
import { Project, SyntaxKind } from 'ts-morph'
import { dedent } from './dedent.ts'
import { normalizeIdentifiers } from './normalizeIdentifiers.ts'

export async function compareToBaseline(
Expand Down
2 changes: 1 addition & 1 deletion scripts/benchmarks/src/normalizeIdentifiers.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { dedent } from 'radashi/string/dedent.ts'
import { describe, expect, it } from 'vitest'
import { dedent } from './dedent.ts'
import { normalizeIdentifiers } from './normalizeIdentifiers.ts'

describe('normalizeIdentifiers', () => {
Expand Down
86 changes: 0 additions & 86 deletions scripts/bundle-impact/src/dedent.ts

This file was deleted.

86 changes: 0 additions & 86 deletions scripts/publish-version/src/dedent.ts

This file was deleted.

2 changes: 1 addition & 1 deletion scripts/publish-version/src/publishVersion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import { green } from 'kleur/colors'
import crypto from 'node:crypto'
import fs from 'node:fs/promises'
import { sift } from 'radashi/array/sift.ts'
import { dedent } from 'radashi/string/dedent.ts'
import { glob } from 'tinyglobby'
import { dedent } from './dedent.ts'
import { trackVersion } from './trackVersion.ts'

export const VALID_TAGS = ['beta', 'next'] as const
Expand Down
2 changes: 1 addition & 1 deletion scripts/release-notes/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import fs from 'node:fs'
import os from 'node:os'
import path from 'node:path'
import { uid } from 'radashi/random/uid.ts'
import { dedent } from './util/dedent.ts'
import { dedent } from 'radashi/string/dedent.ts'

main()

Expand Down
Loading
Loading