Skip to content

Commit bf8b24e

Browse files
committed
feat(remark-textras): add :work
1 parent ef0ebd2 commit bf8b24e

4 files changed

Lines changed: 75 additions & 0 deletions

File tree

packages/remark-textras/README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,12 @@ This page is built using :abbr[HTML] and :abbr[CSS].
7777
At this point, the program should fail with an error like :samp[Invalid fizz provided].
7878
```
7979

80+
### `:work`
81+
82+
```markdown
83+
See the aforementioned :work[A Real Pain] and :work[Futurama]{year="1999"}.
84+
```
85+
8086
## API
8187

8288
TODO

packages/remark-textras/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
"prepublish": "npm run build"
2828
},
2929
"dependencies": {
30+
"hastscript": "^9.0.1",
3031
"unist-util-visit": "^5.0.0"
3132
},
3233
"devDependencies": {

packages/remark-textras/src/index.ts

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import type { Root, Parent } from "hast";
2+
import { h } from "hastscript";
23
import { visit } from "unist-util-visit";
34
import { getFirstAndLastText, addClass } from "./ast.js";
45
// This is required to augment the AST type, but unfortunately can’t
@@ -8,6 +9,23 @@ import { getFirstAndLastText, addClass } from "./ast.js";
89
const OPENING_QUOTE = /^(?:|||)/;
910
const CLOSING_QUOTE = /(?:|||)$/;
1011

12+
const YEAR_SPACE = Object.freeze({ type: "text", value: " " });
13+
14+
const QUOTE_SPACE = Object.freeze({
15+
type: "text",
16+
value: "\u202F",
17+
});
18+
19+
const OPENING_QUOTE_AST = Object.freeze({
20+
type: "text",
21+
value: "‘",
22+
});
23+
24+
const CLOSING_QUOTE_AST = Object.freeze({
25+
type: "text",
26+
value: "’",
27+
});
28+
1129
export function textrasPlugin() {
1230
return transformer;
1331

@@ -44,9 +62,56 @@ export function textrasPlugin() {
4462
}
4563
}
4664

65+
function transformWorkTitle(node: Parent) {
66+
node.data = {
67+
...node.data,
68+
hName: "cite",
69+
hProperties: { class: "work-title" },
70+
};
71+
72+
const { year, quoted } = (node as any).attributes || {};
73+
74+
if (quoted !== undefined) {
75+
const [first, last] = getFirstAndLastText(node);
76+
77+
if (OPENING_QUOTE.test(first ?? "")) {
78+
node.children.unshift(QUOTE_SPACE);
79+
}
80+
81+
node.children.unshift(OPENING_QUOTE_AST);
82+
83+
if (CLOSING_QUOTE.test(last ?? "")) {
84+
node.children.push(QUOTE_SPACE);
85+
}
86+
87+
node.children.push(CLOSING_QUOTE_AST);
88+
}
89+
90+
if (year !== undefined) {
91+
const time = h("time");
92+
time.data = {
93+
hName: "time",
94+
hProperties: {
95+
class: "work-vintage",
96+
datetime: year,
97+
},
98+
};
99+
100+
time.children = [
101+
{
102+
type: "text",
103+
value: `(${year})`,
104+
},
105+
];
106+
node.children.push(YEAR_SPACE);
107+
node.children.push(time);
108+
}
109+
}
110+
47111
function transformer(tree: Root, _file: unknown) {
48112
visit(tree, { type: "textDirective", name: "ordinal" }, ordinalVisitor);
49113
visit(tree, { type: "textDirective", name: "quote" }, quoteVisitor);
114+
visit(tree, { type: "textDirective", name: "work" }, transformWorkTitle);
50115

51116
for (const [name, element] of Object.entries({
52117
var: "var",

pnpm-lock.yaml

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)