Skip to content

Commit

Permalink
feat: 新增 dedent
Browse files Browse the repository at this point in the history
  • Loading branch information
fjc0k committed May 27, 2020
1 parent 905f8ab commit 9ff1e9c
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export * from 'lodash-es'

// @index(['./**/*.ts', '!./**/*.test.*'], f => `export * from '${f.path}'`)
export * from './utils/dedent'
export * from './utils/EventBus'
export * from './utils/indent'
export * from './utils/isPossibleChineseMobilePhoneNumber'
Expand Down
62 changes: 62 additions & 0 deletions src/utils/dedent.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { dedent } from './dedent'
import { indent } from './indent'

describe(dedent.name, () => {
test('空字符串正常', () => {
expect(dedent``).toBe('')
})

test('单行字符串', () => {
expect(dedent`hello`).toBe('hello')
})

test('有缩进的多行字符串', () => {
expect(dedent` hello\n world`).toBe('hello\n world')
})

test('首尾存在换行符的多行字符串', () => {
expect(dedent`
${' '}
hello
world
---
`).toBe('hello\n\nworld\n ---')
})

test('杂项 1', () => {
const x = dedent`
String literal, provides the branch for the current build.
@example
\`\`\`sh
DRONE_COMMIT_BRANCH=master
\`\`\`
`
const y = dedent`${indent`
String literal, provides the branch for the current build.
@example
\`\`\`sh
DRONE_COMMIT_BRANCH=master
\`\`\`
`}`
expect(x).toBe(y)
})

test('杂项 2', () => {
const t = dedent`
d
e
`
const x = dedent`
a
b
c
${t}
`
const y = 'a\nb\n\nc\n\nd\ne'
expect(x).toBe(y)
})
})
54 changes: 54 additions & 0 deletions src/utils/dedent.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { indent } from './indent'

/**
* 首先,每一行紧跟前导空白的插入值为多行时,保持缩进。
* 然后,移除每一行的公共前导空白。
*
* ```
* dedent` a\n b` // => 'a\nb'
* ```
*
* @param literals 字面值
* @param interpolations 插入值
* @returns 返回处理后的结果
*/
export function dedent(
literals: TemplateStringsArray,
...interpolations: string[]
): string {
const text = indent(literals, ...interpolations)

// 公共的前导空白
let commonLeadingWhitespace!: string
// 第一个非空行
let firstLineIndex!: number
// 最后一个非空行
let lastLineIndex!: number

const lines = text.split(/[\r\n]/g)

for (let index = 0; index < lines.length; index++) {
// 当前行的前导空白
const leadingWhitespace = lines[index].match(/^\s*/)![0]
// 如果当前行的前导空白等于当前行的长度,则认为这是一个空行,跳过
if (leadingWhitespace.length !== lines[index].length) {
lastLineIndex = index
if (firstLineIndex == null) {
firstLineIndex = index
}
if (
commonLeadingWhitespace == null ||
leadingWhitespace.length < commonLeadingWhitespace.length
) {
commonLeadingWhitespace = leadingWhitespace
}
}
}

return commonLeadingWhitespace == null
? text
: lines
.slice(firstLineIndex, lastLineIndex + 1)
.map(line => line.substr(commonLeadingWhitespace.length))
.join('\n')
}

0 comments on commit 9ff1e9c

Please sign in to comment.