Skip to content

Commit 6a8ea1e

Browse files
authored
smart quotes (#191)
1 parent 530ace6 commit 6a8ea1e

File tree

3 files changed

+20
-2
lines changed

3 files changed

+20
-2
lines changed

packages/site-kit/src/lib/markdown/renderer.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { createHash } from 'node:crypto';
33
import { mkdir, readFile, readdir, stat, writeFile } from 'node:fs/promises';
44
import path from 'node:path';
55
import ts from 'typescript';
6-
import { SHIKI_LANGUAGE_MAP, escape, normalizeSlugify, transform } from './utils';
6+
import { SHIKI_LANGUAGE_MAP, escape, normalizeSlugify, smart_quotes, transform } from './utils';
77
import type { Declaration, TypeElement, Modules } from './index';
88

99
type MetadataKeys = 'file' | 'link' | 'copy';
@@ -235,6 +235,7 @@ async function parse({
235235

236236
/** @type {string} */
237237
const content = await transform(body, {
238+
text: smart_quotes,
238239
heading(html, level, raw) {
239240
const title = html
240241
.replace(/<\/?code>/g, '')

packages/site-kit/src/lib/markdown/utils.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,20 @@ export const normalizeSlugify = (str: string) => {
7878
return slugify(removeHTMLEntities(removeMarkdown(str))).replace(/(<([^>]+)>)/gi, '');
7979
};
8080

81+
export function smart_quotes(str: string) {
82+
// replace dumb quotes with smart quotes. This isn't a perfect algorithm — it
83+
// wouldn't correctly handle `That '70s show` or `My country 'tis of thee`
84+
// but a) it's very unlikely they'll occur in our docs, and
85+
// b) they can be dealt with manually
86+
return str.replace(/(.|^)(&#39;|&quot;)(.|$)/g, (m, before, quote, after) => {
87+
const left = !before.trim();
88+
const double = quote === '&quot;';
89+
const entity = `&${left ? 'l' : 'r'}${double ? 'd' : 's'}quo;`;
90+
91+
return (before ?? '') + entity + (after ?? '');
92+
});
93+
}
94+
8195
const default_renderer: Partial<Renderer> = {
8296
code(code, infostring, escaped) {
8397
const lang = infostring?.match(/\S*/)?.[0];

packages/site-kit/src/lib/server/content/index.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { extract_frontmatter, slugify } from '../../markdown/utils';
1+
import { extract_frontmatter, slugify, smart_quotes } from '../../markdown/utils';
22
import type { Document } from '../../types';
33

44
export async function create_index(
@@ -24,6 +24,9 @@ export async function create_index(
2424
throw new Error(`Missing title in ${slug} frontmatter`);
2525
}
2626

27+
metadata.title = smart_quotes(metadata.title);
28+
if (metadata.description) metadata.description = smart_quotes(metadata.description);
29+
2730
const sections = Array.from(body.matchAll(/^##\s+(.*)$/gm)).map((match) => {
2831
const title = match[1].replace(/`/g, '').replace(/&lt;/g, '<').replace(/&gt;/g, '>');
2932
const slug = slugify(title);

0 commit comments

Comments
 (0)