No 3rd party dependencies. All dependencies and devDependencies, checked recursively, are Codsen packages.
Permalink to InstallationInstallation
Permalink to Quick TakeQuick Take
Permalink to ExamplesExamples
- Convert one apostrophe into an entity
- Supply the apostrophe value separately
- Disable the apostrophe conversion
- Convert double quotation marks
- Convert the quotes into HTML entities
- Convert measurement primes
- Convert nested quotations
- Report the index offsets through a callback
Idea
As you know, straight apostrophes are not always typographically-correct: John's should be John’s, with right single quote instead of apostrophe.
This program corrects apostrophes and single and double quotation marks, and recognizes measurement primes. Use convertAll() for literal characters and convertOne() for a known span, including an HTML entity whose decoded value you supply.
Sources used in rules logic and unit tests:
- Oxford A–Z of Grammar and Punctuation 2nd Ed., 2009, ISBN 978–0199564675
- Butterick’s Practical Typography 2nd Ed., “Apostrophes” chapter
API — convertAll()
The main function convertAll() is imported like this:
It’s a function which takes two input arguments:
| Input argument | Type | Obligatory | Description |
|---|---|---|---|
strType: String Obligatory: yes | |||
str | String | yes | String to process. |
optsType: Plain object Obligatory: no | |||
opts | Plain object | no | Optional Options Object. |
The Optional Options Object has the following shape:
| Key | Type | Default | Obligatory | Description |
|---|---|---|---|---|
convertEntitiesType: Boolean Default: falseObligatory: no | ||||
convertEntities | Boolean | false | no | Output named HTML entities for typographic punctuation. |
convertApostrophesType: Boolean Default: trueObligatory: no | ||||
convertApostrophes | Boolean | true | no | Use true for typographic punctuation or false to convert curly quotes and primes back to straight quotes. |
Omitted or undefined conversion flags use their defaults. Explicit convertApostrophes: false requests reverse conversion:
import { convertAll } from "string-apostrophes";
convertAll("It’s 6′2″", { convertApostrophes: false }).result;
// => "It's 6'2\""
convertAll("It’s", { convertApostrophes: undefined }).result;
// => "It’s"
Here are all defaults in one place for copying:
The function will return a plain object:
| Returned object’s key | Type | Description |
|---|---|---|
resultType: String | ||
result | String | Processed string, with all ranges applied |
rangesType: Ranges: null or array of arrays | ||
ranges | Ranges: null or array of arrays | Half-open UTF-16 ranges applied to produce result. An unchanged nonempty input returns []; an empty input returns null. |
API — convertOne()
The main function convertOne() is imported like this:
It’s a function which takes two input arguments:
| Input argument | Type | Obligatory | Description |
|---|---|---|---|
strType: String Obligatory: yes | |||
str | String | yes | A string to process |
optsType: Plain object Obligatory: yes | |||
opts | Plain object | yes | Obligatory Options Object. |
The Obligatory Options Object has the following shape:
| Key | Type | Default | Obligatory | Description |
|---|---|---|---|---|
fromType: Natural number, string index Default: undefinedObligatory: yes | ||||
from | Natural number, string index | undefined | yes | Inclusive UTF-16 index at which the supplied span starts. |
toType: Natural number, string index Default: from + 1Obligatory: no | ||||
to | Natural number, string index | from + 1 | no | Exclusive UTF-16 end index. An integer endpoint must satisfy from ≤ to ≤ str.length. |
valueType: String Default: undefinedObligatory: no | ||||
value | String | undefined | no | Logical quote or prime represented by str.slice(from, to). |
convertEntitiesType: Boolean Default: falseObligatory: no | ||||
convertEntities | Boolean | false | no | Output named HTML entities for typographic punctuation. |
convertApostrophesType: Boolean Default: trueObligatory: no | ||||
convertApostrophes | Boolean | true | no | Use true for typographic punctuation or false to convert curly quotes and primes back to straight quotes. |
offsetByType: Function Default: undefinedObligatory: no | ||||
offsetBy | Function | undefined | no | Receives the number of additional UTF-16 code units consumed beyond to when one replacement handles multiple symbols. |
opts.from must be an integer from 0 to str.length - 1. opts.to defaults to from + 1; backwards or out-of-bounds integer spans throw a string-apostrophes/convertOne() error. Equal endpoints are valid for inserting a supplied value without deleting source text. Pass an options object: null receives the required-options error.
The surrounding text determines whether a mark is an apostrophe, quotation mark, or measurement prime. Measurements such as 6'2" become 6′2″, including at the end of input. Numeric-ending quotations such as Model "T2000". become Model “T2000”.. Explicit primes stay primes under forward conversion. These rules also apply to supplied logical values.
The function returns an array of ranges, or [] when no replacement is needed. Apply them with rApply() from ranges-apply. A supplied logical value that already equals the requested output can also return [], leaving decoding or encoding to the caller.
opts.offsetBy
When one replacement consumes multiple symbols, offsetBy reports the additional span after to. Your iterator must also advance across the first supplied span. For a raw quote, that first span is one code unit; for ', it is six.
For example, this tokenizer handles encoded apostrophes and literal double quotes without revisiting a consumed pair or skipping the following quotation:
import { convertOne } from "string-apostrophes";
import { rApply } from "ranges-apply";
const input = 'rock 'n'"next"';
const ranges = [];
for (let i = 0; i < input.length; i++) {
const encoded = input.startsWith("'", i);
if (!encoded && input[i] !== '"') {
continue;
}
const from = i;
const to = from + (encoded ? 6 : 1);
ranges.push(...convertOne(input, {
from,
to,
value: encoded ? "'" : '"',
offsetBy: (amount) => { i += amount; },
}));
i += to - from - 1;
}
rApply(input, ranges);
// => "rock ’n’“next”"
The first call replaces [5, 18) and reports an offset of 7: the n and the complete second '. The loop’s normal increment and explicit first-span advancement move to index 18, the opening double quote.
opts.value
Consider John's with an HTML-encoded apostrophe:
John's
convertAll() does not decode entity text automatically. If your tokenizer already knows an entity or placeholder represents a quote, pass its half-open source span and decoded value to convertOne().
For example,
import { convertOne } from "string-apostrophes";
const res = convertOne(`test's`, {
from: 4,
to: 10,
value: "'", // <-------- tell the program it's an apostrophe between indexes 4 and 10
convertEntities: false,
});
console.log(JSON.stringify(res, null, 0));
// => [[4, 10, "’"]]
In the example above, the program evaluates surroundings of ' as if it was a “normal” apostrophe and suggests a replacement.
In practice, that’s how detergent uses this package.
API — defaults
You can import defaults:
It's a plain object:
The main function calculates the options to be used by merging the options you passed with these defaults.
These defaults are applicable for both convertOne() and convertAll() functions.
API — version
You can import version:
API — types
This package is written in TypeScript and exports the following types:
| Type | Description |
|---|---|
OptsType: Opts | |
Opts | The Options Object of both convertAll() and convertOne(), documented above. |
RangeType: Range | |
Range | A single range, re-exported from ranges-apply. |
RangesType: Ranges | |
Ranges | Zero or more Ranges, or null, re-exported from ranges-apply. |
import type { Opts, Range, Ranges } from "string-apostrophes";
Compared to Others
📦 This program, string-apostrophes | straight-to-curly-quotes | smartquotes | typographic-quotes | |
|---|---|---|---|---|
| Returns processed string | ||||
| Returns processed string | ✅ | ✅ | ✅ | ✅ |
| Additionally returns index ranges allowing to compose string operations | ||||
| Additionally returns index ranges allowing to compose string operations | ✅ | ❌ | ❌ | ❌ |
| Replaces quotes in DOM, on a web page, where you put a script in | ||||
| Replaces quotes in DOM, on a web page, where you put a script in | ❌ | ❌ | ✅ | ❌ |
| Not regex-based | ||||
| Not regex-based | ✅ | ❌ | ❌ | ❌ |
| Can output HTML-encoded content upon request | ||||
| Can output HTML-encoded content upon request | ✅ | ❌ | ❌ | ❌ |
| Allows to process any part of string as if it were single or double quote | ||||
| Allows to process any part of string as if it were single or double quote | ✅ | ❌ | ❌ | ❌ |
| Serves other languages besides English | ||||
| Serves other languages besides English | ❌ | ❌ | ❌ | ✅ |