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
14 changes: 14 additions & 0 deletions src/data/article.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,20 @@ _System overview._`;
</figure>`);
});

test("converts asterisk-emphasized image captions to esa figures", () => {
const markdown = `![Flow](https://example.com/flow.png)
*Request flow.*`;

expect(
toEsaMarkdown(markdown, {
canonicalUrl: "https://furedea.com/ja/blog/article-publishing/",
}),
).toContain(`<figure>
<img src="https://example.com/flow.png" alt="Flow">
<figcaption style="text-align: center;"><em>Request flow.</em></figcaption>
</figure>`);
});

test("preserves Zenn extension examples inside fenced code blocks", () => {
const markdown = `\`\`\`markdown
:::details Example
Expand Down
31 changes: 19 additions & 12 deletions src/data/article.ts
Original file line number Diff line number Diff line change
Expand Up @@ -183,18 +183,25 @@ function restoreFencedBlocks(markdown: string, fencedBlocks: string[]): string {
}

function convertCaptions(markdown: string): string {
return markdown.replace(
/^!\[([^\]]*)\]\(([^)\s]+)\)\n([_*])(.+)\3$/gmu,
(_match, ...captures: string[]) => {
const [alt, url, , caption] = captures;
return [
"<figure>",
`<img src="${escapeHtml(url)}" alt="${escapeHtml(alt)}">`,
`<figcaption style="text-align: center;"><em>${escapeHtml(caption)}</em></figcaption>`,
"</figure>",
].join("\n");
},
);
const captionedImages =
/^!\[(?<alt>[^\]]*)\]\((?<url>[^)\s]+)\)\n(?<marker>[_*])(?<caption>.+)\k<marker>$/gmu;
let converted = "";
let copiedUntil = 0;
for (const match of markdown.matchAll(captionedImages)) {
const { alt = "", url = "", caption = "" } = match.groups ?? {};
converted += markdown.slice(copiedUntil, match.index) + captionFigure(alt, url, caption);
copiedUntil = match.index + match[0].length;
}
return converted + markdown.slice(copiedUntil);
}

function captionFigure(alt: string, url: string, caption: string): string {
return [
"<figure>",
`<img src="${escapeHtml(url)}" alt="${escapeHtml(alt)}">`,
`<figcaption style="text-align: center;"><em>${escapeHtml(caption)}</em></figcaption>`,
"</figure>",
].join("\n");
}

function replaceImageUrls(markdown: string, origin: string): string {
Expand Down
11 changes: 11 additions & 0 deletions tests/performance/performance_report.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,17 @@ describe("performance report", () => {
expect(summary).toContain("1.23 s (1.00–1.50)");
expect(summary).toContain("| 3 |");
});

test("shows the blocking time range in rounded milliseconds", () => {
const entry = reportEntry();
entry.samples = [
{ ...entry.metrics, blockingTime: 50.4 },
entry.metrics,
{ ...entry.metrics, blockingTime: 120.6 },
];

expect(renderPerformanceSummary([entry])).toContain("88 ms (50–121)");
});
});

function reportEntry(): PerformanceReportEntry {
Expand Down
36 changes: 20 additions & 16 deletions tests/performance/performance_report.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,18 @@ export type PerformanceReportEntry = {

export type PerformanceMeasurement = Omit<PerformanceReportEntry, "status">;

type Unit = {
format: (milliseconds: number) => string | number;
symbol: string;
};

const SECONDS: Unit = {
format: (milliseconds) => (milliseconds / 1_000).toFixed(2),
symbol: "s",
};

const MILLISECONDS: Unit = { format: Math.round, symbol: "ms" };

export function renderPerformanceSummary(entries: PerformanceReportEntry[]): string {
const rows = entries.toSorted(byRoute).map(renderRow);
return [
Expand Down Expand Up @@ -68,9 +80,9 @@ function renderRow(entry: PerformanceReportEntry): string {
(value) => value.toFixed(3),
),
unitWithRange(
{ median: metrics.blockingTime, samples: samples.map(({ blockingTime }) => blockingTime) },
"ms",
Math.round,
metrics.blockingTime,
samples.map(({ blockingTime }) => blockingTime),
MILLISECONDS,
),
`${samples.length} |`,
].join(" | ");
Expand All @@ -83,24 +95,16 @@ function statusSymbol(entry: PerformanceReportEntry): string {
return "❌";
}

function seconds(milliseconds: number): string {
return (milliseconds / 1_000).toFixed(2);
}

function secondsWithRange(median: number, samples: number[]): string {
return unitWithRange({ median, samples }, "s", seconds);
return unitWithRange(median, samples, SECONDS);
}

function unitWithRange(
{ median, samples }: { median: number; samples: number[] },
unit: string,
format: (value: number) => string | number,
): string {
function unitWithRange(median: number, samples: number[], unit: Unit): string {
const minimum = Math.min(...samples);
const maximum = Math.max(...samples);
const formattedMedian = format(median);
if (minimum === maximum) return `${formattedMedian} ${unit}`;
return `${formattedMedian} ${unit} (${format(minimum)}–${format(maximum)})`;
const formattedMedian = unit.format(median);
if (minimum === maximum) return `${formattedMedian} ${unit.symbol}`;
return `${formattedMedian} ${unit.symbol} (${unit.format(minimum)}–${unit.format(maximum)})`;
}

function valueWithRange(
Expand Down
Loading