string-apostrophes1.2.30

Comprehensive, HTML-entities-aware tool to typographically-correct the apostrophes and single/double quotes

§ Quick Take

import { strict as assert } from "assert";
import {
  convertOne,
  convertAll,
} from "string-apostrophes";

assert.deepEqual(
  convertAll(`In the '60s, rock 'n' roll`, {
    convertApostrophes: 1,
    convertEntities: 0,
  }),
  {
    result: "In the ’60s, rock ’n’ roll",
    ranges: [
      [7, 8, "’"],
      [18, 21, "’n’"],
    ],
  }
);

assert.deepEqual(
  convertOne(`test's`, {
    from: 4,
    to: 5,
    convertApostrophes: true,
    convertEntities: true,
  }),
  [[4, 5, "’"]]
);

§ Idea

As you know, straight apostrophes are not always typographically-correct: John's should be John’s, with right single quoteopens in a new tab instead of apostropheopens in a new tab.

This program converts all cases of single and double apostrophes, plus primesopens in a new tab.

Sources used in rules logic and unit tests:

§ API

When you consume this package,

// Common JS:
const { convertOne, convertAll } = require("string-apostrophes");
// ES Modules:
import { convertOne, convertAll } from "string-apostrophes";

you get two functions: convertAll() and convertOne().

§ convertAll()

convertAll is a function; its API is the following:

Input argumentKey value's typeObligatory?Description
strStringyesString which we will process
optsPlain objectnoPut options here

For example,

console.log(convertAll(`test's`, {
convertApostrophes: true,
convertEntities: true
})).result,
// => "test’s"

§ Output

A plain object is returned:

Returned object's keyThe type of its valueDescription
resultStringProcessed string, with all ranges applied
rangesArray of zero or more arraysRanges that were gathered and applied to produce result

For example, if you gave string In the '60s, rock 'n' roll with apostrophes, the result on default settings would be:

{
result: `In the ’60s, rock ’n’ roll`,
ranges: [
[7, 8, ``],
[18, 19, ``],
[20, 21, ``]
]
}

§ Options Object, opts

Options Object's keyThe type of its valueDefaultObligatory?Description
convertEntitiesBooleanfalsenoShould we HTML-encode the characters?
convertApostrophesBooleantruenoKillswitch. If it's false, the program does nothing.

§ convertOne()

convertOne is a function; its API is the following:

Input argumentKey value's typeObligatory?Description
strStringyesString which we will process
optsPlain objectyesPut options here

opts.from is obligatory — that's how you tell the program which characters to process.

For example:

console.log(convertOne(`test's`, {
from: 4,
to: 5,
convertApostrophes: true,
convertEntities: false
})),
// => [[4, 5, "’"]]

§ Output

It returns an array of zero or more arrays (ranges), each representing what needs to be done.

For example, result [[2, 3, "‘"], [5, 6, "’"]] means "replace string chunk from index 2 to 3 with ‘" and from index 5 to 6 with ’. You can use ranges-apply to process a string using those ranges (in other words, "to apply those ranges").

§ Options Object, opts

Options Object's keyThe type of its valueDefaultObligatory?Description
fromNatural number, string indexundefinedyesWhere does the character we need to process start in a given index?
toNatural number, string indexfrom + 1noWhere does the character we need to process end in a given index?
valueStringundefinednoOverride the value of a string value, present at str.slice(from, to)
convertEntitiesBooleanfalsenoShould we HTML-encode the characters?
convertApostrophesBooleantruenoKillswitch. If it's false, the program does nothing.
offsetByFunctionundefinednoIf you provide a function, it will be called with a natural number input argument, meaning how much characters to skip next.

§ opts.offsetBy

Offset is needed to bypass characters we already fixed — it happens for example, with nested quotes - we'd fix many in one go, and we need to skip the further processing; otherwise, those characters would get processed multiple times.

For example, here's how the convertAll() index is bumped using offsetBy, in a callback-fashion:

function convertAll(str, opts) {
let ranges = [];
const preppedOpts = Object.assign({}, opts);
// loop through the given string
for (let i = 0, len = str.length; i < len; i++) {
// define starting index:
preppedOpts.from = i;
// offset function:
preppedOpts.offsetBy = (idx) => {
i = i + idx;
};
// calculate the result:
const res = convertOne(str, preppedOpts);
if (Array.isArray(res) && res.length) {
ranges = ranges.concat(res);
}
}
return {
result: rangesApply(str, ranges),
ranges,
};
}

The inner function convertOne() bumps outer's convertAll() index.

§ opts.value

Consider string Your's with HTML-escaped apostrophe:

Your&apos;s

There are various other cases of apostrophes and quotes where we have a sentence, and all apostrophes/quotes are there, and we know where just different character(s) represent them. Values are not ' and ".

We are not going to code up all those cases!

Instead, use convertOne(), process each "symbol" one-by-one and instruct the program from where (from) to where (to) is a particular character (value).

For example,

const { convertOne, convertAll } = require("string-apostrophes");
const res = convertOne(`test&apos;s`, {
from: 4,
to: 10,
value: "'", // <-------- we insist to program that it's an apostrophe between indexes 4 and 10
convertEntities: 0,
});
console.log(JSON.stringify(res, null, 0));
// => [[4, 10, "’"]]

In the example above, the program evaluates surroundings of &apos; as if it was a "normal" apostrophe and suggests a replacement.

In practice, that's how detergent uses this package.

§ Compared to Others

This program,
string-apostrophes
straight-to-curly-quotesopens in a new tabsmartquotesopens in a new tabtypographic-quotesopens in a new tab
npm linknpm linkopens in a new tabnpm linkopens in a new tabnpm linkopens in a new tab
Returns processed string
Additionally returns index ranges
Replaces quotes in DOM, on a web page, where you put a script in
Not regex-based
Can output HTML-encoded content upon request
Killswitch to bypass processing
Allows to process any part of string as if it were single or double quote
CommonJS (require()) and ES Modules (in ES6+, import) builds
UMD builds published to npm and available from unpkg or jsdelivr
Serves other languages besides English

This program has string-in, string-out type API; the DOM changes capabilities are not bundled because browser is only one of many possible targets of an npm program. Other consuming programs might not even have DOM or consumers might be Electron or whatever. It's best to write other, standalone apps which use API-like core function and work from original (string-in string-out), "API" package.

§ Licence

MITopens in a new tab

Copyright © 2010–2020 Roy Revelt and other contributors

Related packages:

📦 detergent 5.11.7
Extracts, cleans and encodes text
📦 string-fix-broken-named-entities 3.0.11
Finds and fixes common and not so common broken named HTML entities, returns ranges array of fixes
📦 string-strip-html 6.0.4
Strips HTML tags from strings. No parser, accepts mixed sources.
📦 string-split-by-whitespace 1.6.72
Split string into array by chunks of whitespace
📦 string-remove-widows 1.6.17
Helps to prevent widow words in a text
📦 string-left-right 2.3.31
Looks up the first non-whitespace character to the left/right of a given index
📦 string-extract-sass-vars 1.2.9
Parse SASS variables file into a plain object of CSS key-value pairs