Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 1 addition & 16 deletions src/content.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,21 +25,6 @@ function toPlainMarkdown(body: string): string {
.replace(/\n{3,}/g, '\n\n');
}

// Inject inline HTML into the spec source before rendering so that the FAQ
// comparison table shows accessible support indicators in HTML, while the
// plain Markdown body keeps its prose for curl/llms.txt consumers.
function preprocessForRendering(source: string): string {
return source
.replace(
/\| Supported \|/g,
'| <mark data-supported="true" title="Supported" aria-label="Supported">✓</mark> |',
)
.replace(
/\| Not supported \|/g,
'| <mark data-supported="false" title="Not supported" aria-label="Not supported">✗</mark> |',
);
}

const specification = defineCollection({
loader: {
name: 'sembr-specification',
Expand All @@ -58,7 +43,7 @@ const specification = defineCollection({
const id = 'sembr';
const data = await parseData({ id, data: {} });
const digest = generateDigest(source);
const rendered = await renderMarkdown(preprocessForRendering(source));
const rendered = await renderMarkdown(source);
const body = toPlainMarkdown(source);

store.set({ id, data, body, digest, rendered });
Expand Down
43 changes: 40 additions & 3 deletions src/lib/remark-sembr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type { Definition, Html, Root, RootContent, Text } from 'mdast';
import type { Plugin } from 'unified';
import { visit } from 'unist-util-visit';

const KEYWORDS = [
const RFC_2119_KEYWORDS = [
'MUST NOT',
'SHALL NOT',
'SHOULD NOT',
Expand All @@ -15,7 +15,7 @@ const KEYWORDS = [
'MAY',
] as const;

const KEYWORD_PATTERN = new RegExp(`\\b(${KEYWORDS.join('|')})\\b`, 'g');
const RFC_2119_PATTERN = new RegExp(`\\b(${RFC_2119_KEYWORDS.join('|')})\\b`, 'g');

const EM_DASH = '\u2014';
const EM_DASH_PATTERN = /---/g;
Expand Down Expand Up @@ -54,11 +54,13 @@ function ccSymbolsForLicenseUrl(rawUrl: string): string | null {

export const remarkSembr: Plugin<[], Root> = () => {
return (tree) => {
// Collect link definitions for resolving Creative Commons references.
const definitions = new Map<string, string>();
visit(tree, 'definition', (node: Definition) => {
definitions.set(node.identifier, node.url);
});

// Mark multiline <pre> blocks as SemBr examples for whitespace styling.
visit(tree, 'html', (node) => {
const match = node.value.match(MULTILINE_PRE_PATTERN);
if (
Expand All @@ -70,6 +72,39 @@ export const remarkSembr: Plugin<[], Root> = () => {
}
});

// FAQ comparison table: accessible support indicators and styled "None".
visit(tree, 'tableCell', (node) => {
if (node.children.length !== 1 || node.children[0]?.type !== 'text') {
return;
}
const value = node.children[0].value;
if (value === 'Supported') {
node.children = [
{
type: 'html',
value:
'<mark data-supported="true" title="Supported" aria-label="Supported">✓</mark>',
},
];
} else if (value === 'Not supported') {
node.children = [
{
type: 'html',
value:
'<mark data-supported="false" title="Not supported" aria-label="Not supported">✗</mark>',
},
];
} else if (value === 'None') {
node.children = [
{
type: 'html',
value: '<em data-supported="false">None</em>',
},
];
}
});

// Keep "Line Breaks" on one line in the title via a non-breaking space.
visit(tree, 'heading', (node) => {
if (
node.depth === 1 &&
Expand All @@ -81,13 +116,14 @@ export const remarkSembr: Plugin<[], Root> = () => {
}
});

// Highlight RFC 2119 keywords and normalize --- to an em dash.
visit(tree, 'text', (node, index, parent) => {
if (!parent || typeof index !== 'number') {
return;
}

const value = node.value.replace(EM_DASH_PATTERN, EM_DASH);
const matches = [...value.matchAll(KEYWORD_PATTERN)];
const matches = [...value.matchAll(RFC_2119_PATTERN)];

if (matches.length === 0) {
if (value !== node.value) {
Expand Down Expand Up @@ -124,6 +160,7 @@ export const remarkSembr: Plugin<[], Root> = () => {
parent.children.splice(index, 1, ...(nodes as typeof parent.children));
});

// Prefix Creative Commons license links with Unicode license symbols.
visit(tree, ['link', 'linkReference'], (node, index, parent) => {
if (!parent || typeof index !== 'number') {
return;
Expand Down
9 changes: 7 additions & 2 deletions src/styles/global.css
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@
position: relative;
padding-inline-start: var(--space-s);
margin-block-end: var(--space-s);
text-wrap: balance;
}

ol>li::marker {
Expand Down Expand Up @@ -379,11 +380,15 @@
font-weight: 700;
}

mark[data-supported="true"] {
tbody tr>td:nth-child(2) {
text-wrap: balance;
}

:is(mark, em)[data-supported="true"] {
color: var(--color-heading);
}

mark[data-supported="false"] {
:is(mark, em)[data-supported="false"] {
color: var(--color-rule);
}

Expand Down