Skip to content

Commit 96ac11d

Browse files
authored
feat: wrap directive data (#243)
1 parent 3fb0d32 commit 96ac11d

File tree

5 files changed

+94
-84
lines changed

5 files changed

+94
-84
lines changed

workspace/aubade/src/artisan/example.spec.ts

Lines changed: 64 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ describe('spec', ({ concurrent: it }) => {
2020
' - foo\n - bar\n\t - baz',
2121
'<ul>\n<li>foo\n<ul>\n<li>bar\n<ul>\n<li>baz</li>\n</ul>\n</li>\n</ul>\n</li>\n</ul>',
2222
],
23-
'010|plus': ['#\tFoo', '<h1 id="foo" data-text="Foo">Foo</h1>'],
23+
'010|plus': ['#\tFoo', '<h1 id="foo">Foo</h1>'],
2424
'011': ['*\t*\t*\t', '<hr />'],
2525
'012': [
2626
'\\!\\"\\#\\$\\%\\&\\\'\\(\\)\\*\\+\\,\\-\\.\\/\\:\\;\\<\\=\\>\\?\\@\\[\\\\\\]\\^\\_\\`\\{\\|\\}\\~',
@@ -119,66 +119,53 @@ describe('spec', ({ concurrent: it }) => {
119119
'062|plus': [
120120
'# foo\n## foo\n### foo\n#### foo\n##### foo\n###### foo',
121121
[
122-
'<h1 id="foo" data-text="foo">foo</h1>',
123-
`<h2 id="${Array(2).fill('foo').join('-')}" data-text="foo">foo</h2>`,
124-
`<h3 id="${Array(3).fill('foo').join('-')}" data-text="foo">foo</h3>`,
125-
`<h4 id="${Array(4).fill('foo').join('-')}" data-text="foo">foo</h4>`,
126-
`<h5 id="${Array(5).fill('foo').join('-')}" data-text="foo">foo</h5>`,
127-
`<h6 id="${Array(6).fill('foo').join('-')}" data-text="foo">foo</h6>`,
122+
'<h1 id="foo">foo</h1>',
123+
`<h2 id="${Array(2).fill('foo').join('-')}">foo</h2>`,
124+
`<h3 id="${Array(3).fill('foo').join('-')}">foo</h3>`,
125+
`<h4 id="${Array(4).fill('foo').join('-')}">foo</h4>`,
126+
`<h5 id="${Array(5).fill('foo').join('-')}">foo</h5>`,
127+
`<h6 id="${Array(6).fill('foo').join('-')}">foo</h6>`,
128128
].join('\n'),
129129
],
130130
'063': ['####### foo', '<p>####### foo</p>'],
131131
'064': ['#5 bolt\n\n#hashtag', '<p>#5 bolt</p>\n<p>#hashtag</p>'],
132132
'065': ['\\## foo', '<p>## foo</p>'],
133-
'066|plus': [
134-
'# foo *bar* \\*baz\\*',
135-
'<h1 id="foo-bar-baz" data-text="foo bar *baz*">foo <em>bar</em> *baz*</h1>',
136-
],
137-
'067|plus': [
138-
'# foo ',
139-
'<h1 id="foo" data-text="foo">foo</h1>',
140-
],
133+
'066|plus': ['# foo *bar* \\*baz\\*', '<h1 id="foo-bar-baz">foo <em>bar</em> *baz*</h1>'],
134+
'067|plus': ['# foo ', '<h1 id="foo">foo</h1>'],
141135
'068|plus': [
142136
' ### foo\n ## foo\n # foo',
143-
[
144-
'<h3 id="foo" data-text="foo">foo</h3>',
145-
'<h2 id="foo-1" data-text="foo">foo</h2>',
146-
'<h1 id="foo-2" data-text="foo">foo</h1>',
147-
].join('\n'),
137+
['<h3 id="foo">foo</h3>', '<h2 id="foo-1">foo</h2>', '<h1 id="foo-2">foo</h1>'].join('\n'),
148138
],
149-
'069|deny': [' # foo', '<h1 id="foo" data-text="foo">foo</h1>'],
150-
'070|deny': ['foo\n # bar', '<p>foo</p>\n<h1 id="bar" data-text="bar">bar</h1>'],
139+
'069|deny': [' # foo', '<h1 id="foo">foo</h1>'],
140+
'070|deny': ['foo\n # bar', '<p>foo</p>\n<h1 id="bar">bar</h1>'],
151141
'071|deny': [
152142
'## foo ##\n ### bar ###',
153-
[
154-
'<h2 id="foo" data-text="foo ##">foo ##</h2>',
155-
'<h3 id="foo-bar" data-text="bar ###">bar ###</h3>',
156-
].join('\n'),
143+
['<h2 id="foo">foo ##</h2>', '<h3 id="foo-bar">bar ###</h3>'].join('\n'),
157144
],
158145
'072|deny': [
159146
'# foo ##################################\n##### foo ##',
160147
[
161-
'<h1 id="foo" data-text="foo ##################################">foo ##################################</h1>',
162-
'<h5 id="foo-foo" data-text="foo ##">foo ##</h5>',
148+
'<h1 id="foo">foo ##################################</h1>',
149+
'<h5 id="foo-foo">foo ##</h5>',
163150
].join('\n'),
164151
],
165-
'073|deny': ['### foo ### ', '<h3 id="foo" data-text="foo ###">foo ###</h3>'],
166-
'074|plus': ['### foo ### b', '<h3 id="foo-b" data-text="foo ### b">foo ### b</h3>'],
167-
'075|plus': ['# foo#', '<h1 id="foo" data-text="foo#">foo#</h1>'],
152+
'073|deny': ['### foo ### ', '<h3 id="foo">foo ###</h3>'],
153+
'074|plus': ['### foo ### b', '<h3 id="foo-b">foo ### b</h3>'],
154+
'075|plus': ['# foo#', '<h1 id="foo">foo#</h1>'],
168155
'076|deny': [
169156
'### foo \\###\n## foo #\\##\n# foo \\#',
170157
[
171-
'<h3 id="foo" data-text="foo ###">foo ###</h3>',
172-
'<h2 id="foo-1" data-text="foo ###">foo ###</h2>',
173-
'<h1 id="foo-2" data-text="foo #">foo #</h1>',
158+
'<h3 id="foo">foo ###</h3>',
159+
'<h2 id="foo-1">foo ###</h2>',
160+
'<h1 id="foo-2">foo #</h1>',
174161
].join('\n'),
175162
],
176-
'077|deny': ['****\n## foo\n****', '<hr />\n<h2 id="foo" data-text="foo">foo</h2>\n<hr />'],
163+
'077|deny': ['****\n## foo\n****', '<hr />\n<h2 id="foo">foo</h2>\n<hr />'],
177164
'078|plus': [
178165
'Foo bar\n# baz\nBar foo',
179-
'<p>Foo bar</p>\n<h1 id="baz" data-text="baz">baz</h1>\n<p>Bar foo</p>',
166+
'<p>Foo bar</p>\n<h1 id="baz">baz</h1>\n<p>Bar foo</p>',
180167
],
181-
'079|deny': ['## \n#\n### ###', '<p>##\n#</p>\n<h3 data-text="###">###</h3>'],
168+
'079|deny': ['## \n#\n### ###', '<p>##\n#</p>\n<h3>###</h3>'],
182169
'080|deny': [
183170
'Foo *bar*\n=========\n\nFoo *bar*\n---------',
184171
'<p>Foo <em>bar</em>\n=========</p>\n<p>Foo <em>bar</em></p>\n<hr />',
@@ -249,7 +236,7 @@ describe('spec', ({ concurrent: it }) => {
249236
'140': ['foo\n```\nbar\n```\nbaz', '<p>foo</p>\n<pre><code>bar\n</code></pre>\n<p>baz</p>'],
250237
'141|mod': [
251238
'foo\n---\n```\nbar\n```\n# baz',
252-
'<p>foo</p>\n<hr />\n<pre><code>bar\n</code></pre>\n<h1 id="baz" data-text="baz">baz</h1>',
239+
'<p>foo</p>\n<hr />\n<pre><code>bar\n</code></pre>\n<h1 id="baz">baz</h1>',
253240
],
254241
'142|mod': [
255242
'```ruby\ndef foo(x)\n return 3\nend\n```',
@@ -281,29 +268,26 @@ describe('spec', ({ concurrent: it }) => {
281268
'224': [' aaa\nbbb', '<p>aaa\nbbb</p>'],
282269
'225|deny': [' aaa\nbbb', '<p>aaa\nbbb</p>'],
283270
'226': ['aaa \nbbb ', '<p>aaa<br />\nbbb</p>'],
284-
'227|plus': [
285-
' \n\naaa\n \n\n# aaa\n\n ',
286-
'<p>aaa</p>\n<h1 id="aaa" data-text="aaa">aaa</h1>',
287-
],
271+
'227|plus': [' \n\naaa\n \n\n# aaa\n\n ', '<p>aaa</p>\n<h1 id="aaa">aaa</h1>'],
288272
'228|plus': [
289273
'> # Foo\n> bar\n> baz',
290-
'<blockquote>\n<h1 id="foo" data-text="Foo">Foo</h1>\n<p>bar\nbaz</p>\n</blockquote>',
274+
'<blockquote>\n<h1 id="foo">Foo</h1>\n<p>bar\nbaz</p>\n</blockquote>',
291275
],
292276
'229|plus': [
293277
'># Foo\n>bar\n> baz',
294-
'<blockquote>\n<h1 id="foo" data-text="Foo">Foo</h1>\n<p>bar\nbaz</p>\n</blockquote>',
278+
'<blockquote>\n<h1 id="foo">Foo</h1>\n<p>bar\nbaz</p>\n</blockquote>',
295279
],
296280
'230': [
297281
' > # Foo\n > bar\n > baz',
298-
'<blockquote>\n<h1 id="foo" data-text="Foo">Foo</h1>\n<p>bar\nbaz</p>\n</blockquote>',
282+
'<blockquote>\n<h1 id="foo">Foo</h1>\n<p>bar\nbaz</p>\n</blockquote>',
299283
],
300284
'231|deny': [
301285
' > # Foo\n > bar\n > baz',
302-
'<blockquote>\n<h1 id="foo" data-text="Foo">Foo</h1>\n<p>bar\nbaz</p>\n</blockquote>',
286+
'<blockquote>\n<h1 id="foo">Foo</h1>\n<p>bar\nbaz</p>\n</blockquote>',
303287
],
304288
'232|deny': [
305289
'> # Foo\n> bar\nbaz',
306-
'<blockquote>\n<h1 id="foo" data-text="Foo">Foo</h1>\n<p>bar</p>\n</blockquote>\n<p>baz</p>',
290+
'<blockquote>\n<h1 id="foo">Foo</h1>\n<p>bar</p>\n</blockquote>\n<p>baz</p>',
307291
],
308292
'233|deny': [
309293
'> bar\nbaz\n> foo',
@@ -615,10 +599,6 @@ describe('spec', ({ concurrent: it }) => {
615599
],
616600
'495|todo': ['[link](\\(foo\\))', '<p><a href="(foo)">link</a></p>'],
617601
// @TODO: 496-571 [links]
618-
'572|plus': [
619-
'![foo](/url "title")',
620-
'<figure>\n<img src="/url" alt="foo" />\n<figcaption>title</figcaption>\n</figure>',
621-
],
622602
'572|mod': ['a ![foo](/url "title")', '<p>a <img src="/url" alt="foo" title="title" /></p>'],
623603
'573|skip': [
624604
'![foo *bar*]\n\n[foo *bar*]: train.jpg "train & tracks"',
@@ -642,8 +622,8 @@ describe('spec', ({ concurrent: it }) => {
642622
'643|skip': ['<a href="foo\\\nbar">', '<a href="foo\\\nbar">'],
643623
'644': ['foo\\', '<p>foo\\</p>'],
644624
'645': ['foo ', '<p>foo</p>'],
645-
'646|plus': ['### foo\\', '<h3 id="foo" data-text="foo\\">foo\\</h3>'],
646-
'647|plus': ['### foo ', '<h3 id="foo" data-text="foo">foo</h3>'],
625+
'646|plus': ['### foo\\', '<h3 id="foo">foo\\</h3>'],
626+
'647|plus': ['### foo ', '<h3 id="foo">foo</h3>'],
647627
'648': ['foo\nbaz', '<p>foo\nbaz</p>'],
648628
'649': ['foo \n baz', '<p>foo\nbaz</p>'],
649629
'650': ["hello $.;'there", "<p>hello $.;'there</p>"],
@@ -683,7 +663,9 @@ describe('libretto', ({ concurrent: it }) => {
683663
'@youtube{id=7TovqLDCosk caption="hitoribocchi tokyo"}',
684664
[
685665
'<figure>',
666+
'<div data-aubade="youtube">',
686667
'<iframe src="https://www.youtube-nocookie.com/embed/7TovqLDCosk" title="YouTube video player" loading="lazy" frameborder="0" allowfullscreen allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin"></iframe>',
668+
'</div>',
687669
'<figcaption>hitoribocchi tokyo</figcaption>',
688670
'</figure>',
689671
].join('\n'),
@@ -693,15 +675,19 @@ describe('libretto', ({ concurrent: it }) => {
693675
[
694676
'<details>',
695677
'<summary>hitoribocchi tokyo</summary>',
678+
'<div data-aubade="youtube">',
696679
'<iframe src="https://www.youtube-nocookie.com/embed/7TovqLDCosk" title="YouTube video player" loading="lazy" frameborder="0" allowfullscreen allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin"></iframe>',
680+
'</div>',
697681
'</details>',
698682
].join('\n'),
699683
],
700684
'directive#youtube/newlines': [
701685
['@youtube{', ' id=7TovqLDCosk', ' caption="hitoribocchi tokyo"', '}'].join('\n'),
702686
[
703687
'<figure>',
688+
'<div data-aubade="youtube">',
704689
'<iframe src="https://www.youtube-nocookie.com/embed/7TovqLDCosk" title="YouTube video player" loading="lazy" frameborder="0" allowfullscreen allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin"></iframe>',
690+
'</div>',
705691
'<figcaption>hitoribocchi tokyo</figcaption>',
706692
'</figure>',
707693
].join('\n'),
@@ -710,15 +696,19 @@ describe('libretto', ({ concurrent: it }) => {
710696
'@youtube{id=7TovqLDCosk}',
711697
[
712698
'<figure>',
699+
'<div data-aubade="youtube">',
713700
'<iframe src="https://www.youtube-nocookie.com/embed/7TovqLDCosk" title="YouTube video player" loading="lazy" frameborder="0" allowfullscreen allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin"></iframe>',
701+
'</div>',
714702
'</figure>',
715703
].join('\n'),
716704
],
717705
'directive#youtube/series': [
718706
'@youtube{series="PLZRRxQcaEjA4qyEuYfAMCazlL0vQDkIj2" caption="Mind Field: Season 1"}',
719707
[
720708
'<figure>',
709+
'<div data-aubade="youtube">',
721710
'<iframe src="https://www.youtube-nocookie.com/embed/videoseries?list=PLZRRxQcaEjA4qyEuYfAMCazlL0vQDkIj2" title="YouTube video player" loading="lazy" frameborder="0" allowfullscreen allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin"></iframe>',
711+
'</div>',
722712
'<figcaption>Mind Field: Season 1</figcaption>',
723713
'</figure>',
724714
].join('\n'),
@@ -728,10 +718,12 @@ describe('libretto', ({ concurrent: it }) => {
728718
'@video{src="./video.mp4" caption="local video"}',
729719
[
730720
'<figure>',
721+
'<div data-aubade="video">',
731722
'<video controls preload="metadata">',
732723
'<source src="./video.mp4" type="video/mp4" />',
733724
'Your browser does not support HTML5 video.',
734725
'</video>',
726+
'</div>',
735727
'<figcaption>local video</figcaption>',
736728
'</figure>',
737729
].join('\n'),
@@ -741,32 +733,49 @@ describe('libretto', ({ concurrent: it }) => {
741733
[
742734
'<details>',
743735
'<summary>local video</summary>',
736+
'<div data-aubade="video">',
744737
'<video controls preload="metadata">',
745738
'<source src="./video.mp4" type="video/mp4" />',
746739
'Your browser does not support HTML5 video.',
747740
'</video>',
741+
'</div>',
748742
'</details>',
749743
].join('\n'),
750744
],
751745
'directive#video/no-caption': [
752746
'@video{src="./video.mp4"}',
753747
[
754748
'<figure>',
749+
'<div data-aubade="video">',
755750
'<video controls preload="metadata">',
756751
'<source src="./video.mp4" type="video/mp4" />',
757752
'Your browser does not support HTML5 video.',
758753
'</video>',
754+
'</div>',
759755
'</figure>',
760756
].join('\n'),
761757
],
762758

763759
'image#plain': [
764760
'![unannotated *alt* text](img.png)',
765-
'<figure>\n<img src="img.png" alt="unannotated *alt* text" />\n</figure>',
761+
[
762+
'<figure>',
763+
'<div data-aubade="image">',
764+
'<img src="img.png" alt="unannotated *alt* text" />',
765+
'</div>',
766+
'</figure>',
767+
].join('\n'),
766768
],
767769
'image#caption': [
768770
'![alt](img.png "annotated *title* for caption")',
769-
'<figure>\n<img src="img.png" alt="alt" />\n<figcaption>annotated <em>title</em> for caption</figcaption>\n</figure>',
771+
[
772+
'<figure>',
773+
'<div data-aubade="image">',
774+
'<img src="img.png" alt="alt" />',
775+
'</div>',
776+
'<figcaption>annotated <em>title</em> for caption</figcaption>',
777+
'</figure>',
778+
].join('\n'),
770779
],
771780

772781
'quotes#escaped': ['\\"a b\\"', '<p>&quot;a b&quot;</p>'],

workspace/aubade/src/artisan/registry.ts

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -313,8 +313,8 @@ export function figure(context: Context): null | {
313313

314314
export function heading({ annotate, extract, cursor, stack, util }: Context): null | {
315315
type: 'block:heading';
316-
meta: { level: number };
317-
attr: { id: string; 'data-text': string };
316+
meta: { level: number; text: string };
317+
attr: { id: string };
318318
children: Annotation[];
319319
} {
320320
cursor.trim(); // trim leading whitespace
@@ -325,32 +325,29 @@ export function heading({ annotate, extract, cursor, stack, util }: Context): nu
325325
if (!title.length) return null;
326326

327327
const children = annotate(title);
328-
const attr = {
329-
id: title
330-
.toLowerCase()
331-
.replace(/[\s\][!"#$%&'()*+,./:;<=>?@\\^_`{|}~-]+/g, '-')
332-
.replace(/^-+|-+$|(?<=-)-+/g, ''),
333-
'data-text': children.map(extract).join(''),
334-
};
328+
let id = title
329+
.toLowerCase()
330+
.replace(/[\s\][!"#$%&'()*+,./:;<=>?@\\^_`{|}~-]+/g, '-')
331+
.replace(/^-+|-+$|(?<=-)-+/g, '');
335332

336333
for (let i = stack['block:heading'].length - 1; i >= 0; i--) {
337334
const { attr: parent, meta } = stack['block:heading'][i];
338-
if (meta.level >= level) continue;
339-
attr.id = `${parent.id}-${attr.id}`;
340-
break;
335+
if (meta.level < level) {
336+
id = `${parent.id}-${id}`;
337+
break;
338+
}
341339
}
342340

343341
let suffix = 0;
344342
for (const h of stack['block:heading']) {
345-
const check = suffix ? `${attr.id}-${suffix}` : attr.id;
343+
const check = suffix ? `${id}-${suffix}` : id;
346344
if (h.attr.id === check) suffix++;
347345
}
348-
attr.id = suffix ? `${attr.id}-${suffix}` : attr.id;
349346

350347
return util.commit(stack['block:heading'], {
351348
type: 'block:heading',
352-
meta: { level },
353-
attr,
349+
meta: { level, text: children.map(extract).join('') },
350+
attr: { id: suffix ? `${id}-${suffix}` : id },
354351
children,
355352
});
356353
}

workspace/aubade/src/artisan/resolver.ts

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@ export const base = {
1717
return print(
1818
data.disclosure ? '<details>' : '<figure>',
1919
data.disclosure && `<summary>${text}</summary>`,
20+
'<div data-aubade="youtube">',
2021
`<iframe src="${src}" ${attributes.join(' ')}></iframe>`,
22+
'</div>',
2123
!data.disclosure && data.caption && `<figcaption>${text}</figcaption>`,
2224
data.disclosure ? '</details>' : '</figure>',
2325
);
@@ -26,14 +28,15 @@ export const base = {
2628
const src = sanitize(data.src || '');
2729
const type = sanitize(data.type || 'video/mp4').toLowerCase();
2830
const text = annotate(data.caption || 'video').map(render);
29-
const fallback = sanitize(data.fallback || 'Your browser does not support HTML5 video.');
3031
return print(
3132
data.disclosure ? '<details>' : '<figure>',
3233
data.disclosure && `<summary>${text}</summary>`,
34+
'<div data-aubade="video">',
3335
'<video controls preload="metadata">',
3436
`<source src="${src}" type="${type}" />`,
35-
fallback,
37+
sanitize(data.fallback || 'Your browser does not support HTML5 video.'),
3638
'</video>',
39+
'</div>',
3740
!data.disclosure && data.caption && `<figcaption>${text}</figcaption>`,
3841
data.disclosure ? '</details>' : '</figure>',
3942
);
@@ -54,11 +57,11 @@ export const standard = {
5457
'block:break': () => `<hr />`,
5558
'block:heading'({ token, render, sanitize }) {
5659
const tag = `h${token.meta.level}`;
57-
const attributes = Object.entries(token.attr).flatMap(([k, v]) =>
58-
v.length ? `${k}="${sanitize(v)}"` : [],
59-
);
60+
const attributes = Object.entries(token.attr)
61+
.flatMap(([k, v]) => (v.length ? `${k}="${sanitize(v)}"` : []))
62+
.join(' ');
6063
const children = token.children.map(render).join('');
61-
return `<${tag} ${attributes.join(' ')}>${children}</${tag}>`;
64+
return `<${tag}${attributes ? ' ' + attributes : ''}>${children}</${tag}>`;
6265
},
6366
'block:code'({ token, sanitize }) {
6467
const { 'data-language': lang } = token.attr;
@@ -102,10 +105,11 @@ export const standard = {
102105
return `<table>\n${thead}${tbody}\n</table>`;
103106
},
104107
'block:image'({ token, render, sanitize }) {
105-
const img = `<img src="${sanitize(token.attr.src)}" alt="${sanitize(token.attr.alt)}" />`;
106108
const title = token.children.map(render).join('');
107109
const caption = title ? `\n<figcaption>${title}</figcaption>` : '';
108-
return `<figure>\n${img}${caption}\n</figure>`;
110+
const img = `<img src="${sanitize(token.attr.src)}" alt="${sanitize(token.attr.alt)}" />`;
111+
const body = `<div data-aubade="image">\n${img}\n</div>`;
112+
return `<figure>\n${body}${caption}\n</figure>`;
109113
},
110114
'block:paragraph'({ token, render }) {
111115
return `<p>${token.children.map(render).join('')}</p>`;

0 commit comments

Comments
 (0)