Skip to content

Commit

Permalink
Add expanded ellipses options
Browse files Browse the repository at this point in the history
Closes GH-9.
Closes GH-11.

Reviewed-by: Titus Wormer <[email protected]>
  • Loading branch information
teddybradford authored Jan 13, 2024
1 parent bc33ba5 commit 6fa9e37
Show file tree
Hide file tree
Showing 3 changed files with 192 additions and 13 deletions.
41 changes: 32 additions & 9 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,11 @@
* dash;
* when `'inverted'`, turns three dashes into an en dash and two into an em
* dash.
* @property {boolean | null | undefined} [ellipses=true]
* Transform triple dots (default: `true`), with or without spaces between.
* @property {'spaced' | 'unspaced' | boolean | null | undefined} [ellipses=true]
* Transform triple dots (default: `true`).
* when `'spaced'`, turns triple dots with spaces into ellipses;
* when `'unspaced'`, turns triple dots without spaces into ellipses;
* when `true`, turns triple dots with or without spaces into ellipses.
* @property {QuoteCharacterMap | null | undefined} [openingQuotes]
* Opening quotes to use (default: `{double: '“', single: '‘'}`).
* @property {boolean | null | undefined} [quotes=true]
Expand Down Expand Up @@ -91,7 +94,11 @@ export default function retextSmartypants(options) {
methods.push(quotesDefault)
}

if (settings.ellipses !== false) {
if (settings.ellipses === 'spaced') {
methods.push(ellipsesSpaced)
} else if (settings.ellipses === 'unspaced') {
methods.push(ellipsesUnspaced)
} else if (settings.ellipses !== false) {
methods.push(ellipsesDefault)
}

Expand Down Expand Up @@ -219,15 +226,19 @@ function dashesOldschool(_, node) {
* @type {Method}
*/
function ellipsesDefault(_, node, index, parent) {
ellipsesSpaced(_, node, index, parent)
ellipsesUnspaced(_, node, index, parent)
}

/**
* Transform multiple dots with spaces into unicode ellipses.
*
* @type {Method}
*/
function ellipsesSpaced(_, node, index, parent) {
const value = node.value
const siblings = parent.children

// Simple node with three dots and without whitespace.
if (/^\.{3,}$/.test(node.value)) {
node.value = '…'
return
}

if (!/^\.+$/.test(value)) {
return
}
Expand Down Expand Up @@ -275,6 +286,18 @@ function ellipsesDefault(_, node, index, parent) {
node.value = '…'
}

/**
* Transform multiple dots without spaces into unicode ellipses.
*
* @type {Method}
*/
function ellipsesUnspaced(_, node) {
// Simple node with three dots and without whitespace.
if (/^\.{3,}$/.test(node.value)) {
node.value = '…'
}
}

/**
* Transform straight single- and double quotes into smart quotes.
*
Expand Down
11 changes: 7 additions & 4 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,19 +115,22 @@ Configuration (TypeScript type).
`{double: '”', single: '’'}`)
— closing quotes to use
* `dashes` (`'inverted'` or `'oldschool'` or `boolean`, default: `true`)
transform dashes;
transform dashes;
when `true`, turns two dashes into an em dash character;
when `'oldschool'`, turns three dashes into an em dash and two into an en
dash;
when `'inverted'`, turns three dashes into an en dash and two into an em
dash
* `ellipses` (`boolean`, default: `true`)
— transform triple dots, with or without spaces between
* `ellipses` (`'spaced'` or `'unspaced'` or `boolean`, default: `true`)
— transform triple dots;
when `'spaced'`, turns triple dots with spaces into ellipses;
when `'unspaced'`, turns triple dots without spaces into ellipses;
when `true`, turns triple dots with or without spaces into ellipses
* `openingQuotes` ([`QuoteCharacterMap`][api-quote-character-map], default:
`{double: '“', single: '‘'}`)
— opening quotes to use
* `quotes` (`boolean`, default: `true`)
Transform straight quotes into smart quotes
transform straight quotes into smart quotes

### `QuoteCharacterMap`

Expand Down
153 changes: 153 additions & 0 deletions test.js
Original file line number Diff line number Diff line change
Expand Up @@ -554,3 +554,156 @@ test('Ellipses', async function (t) {
}
)
})

test('Ellipses (unspaced)', async function (t) {
const processor = retext().use(retextSmartypants, {ellipses: 'unspaced'})

await t.test('should replace three full stops', async function () {
assert.equal(
processor.processSync('Alfred... Bertrand.').toString(),
'Alfred\u2026 Bertrand.'
)
})

await t.test('should replace three initial full stops', async function () {
assert.equal(
processor.processSync('...Alfred Bertrand.').toString(),
'\u2026Alfred Bertrand.'
)
})

await t.test('should replace three final full stops', async function () {
assert.equal(
processor.processSync('Alfred Bertrand...').toString(),
'Alfred Bertrand\u2026'
)
})

await t.test('should replace three padded full stops', async function () {
assert.equal(
processor.processSync('Alfred ... Bertrand.').toString(),
'Alfred \u2026 Bertrand.'
)
})

await t.test(
'should replace three padded initial full stops',
async function () {
assert.equal(
processor.processSync('... Alfred Bertrand.').toString(),
'\u2026 Alfred Bertrand.'
)
}
)

await t.test(
'should replace three padded final full stops',
async function () {
assert.equal(
processor.processSync('Alfred Bertrand ...').toString(),
'Alfred Bertrand \u2026'
)
}
)

await t.test('should replace more than three full stops', async function () {
assert.equal(
processor.processSync('Alfred..... Bertrand.').toString(),
'Alfred\u2026 Bertrand.'
)

assert.equal(
processor.processSync('Alfred bertrand....').toString(),
'Alfred bertrand\u2026'
)

assert.equal(
processor.processSync('......Alfred bertrand.').toString(),
'\u2026Alfred bertrand.'
)
})

await t.test(
'should NOT replace less than three full stops',
async function () {
assert.equal(
processor.processSync('Alfred.. Bertrand.').toString(),
'Alfred.. Bertrand.'
)

assert.equal(
processor.processSync('Alfred bertrand. .').toString(),
'Alfred bertrand. .'
)

assert.equal(
processor.processSync('.Alfred bertrand.').toString(),
'.Alfred bertrand.'
)
}
)
})

test('Ellipses (spaced)', async function (t) {
const processor = retext().use(retextSmartypants, {ellipses: 'spaced'})

await t.test(
'should replace three padded full stops with spaces',
async function () {
assert.equal(
processor.processSync('Alfred . . . Bertrand.').toString(),
'Alfred \u2026 Bertrand.'
)
}
)

await t.test(
'should replace three padded initial full stops with spaces',
async function () {
assert.equal(
processor.processSync('. . . Alfred Bertrand.').toString(),
'\u2026 Alfred Bertrand.'
)
}
)

await t.test(
'should replace three padded final full stops with spaces',
async function () {
assert.equal(
processor.processSync('Alfred Bertrand . . .').toString(),
'Alfred Bertrand \u2026'
)
}
)

await t.test(
'should replace three full stops with spaces',
async function () {
assert.equal(
processor.processSync('Alfred. . . Bertrand.').toString(),
'Alfred\u2026 Bertrand.'
)
}
)

await t.test(
'should replace three initial full stops with spaces',
async function () {
assert.equal(
processor.processSync('. . .Alfred Bertrand.').toString(),
'\u2026Alfred Bertrand.'
)
}
)

await t.test(
'should replace three final full stops with spaces',
async function () {
assert.equal(
processor.processSync('Alfred Bertrand. . .').toString(),
'Alfred Bertrand\u2026'
)
}
)
})

0 comments on commit 6fa9e37

Please sign in to comment.