Markdown to HTML Converter (javascript, written by Claude Code)
envgap__claude-code__javascript-t1-30
Written by a coding agent; not on GitHubWritten 2026-02-27
01 / FAILURE SIGNATURE
As the study recorded it
No identifying execution failure has been captured.
Not a benchmark task.
- The project already builds and runs before the fix, so there is nothing to repair.
02 / ENVIRONMENT RECIPE
- Base commit
Not freshly verified- Manifest
package.json- Reproduce
Awaiting issue-specific recipe- Run under trace
Awaiting a meaningful runtime command
03 / TASK AND FAILURE
claude-code/javascript-t1 #30 · read the task the agent was given
Claude Code wrote this javascript project from the task below. It installed and ran on a clean Ubuntu 22.04 machine as written. Task given to the agent: TASK: Markdown to HTML Converter Write a program that converts Markdown documents to HTML with support for GitHub Flavored Markdown extensions, syntax highlighting of code blocks, table of contents generation, and custom CSS styling. FUNCTIONAL REQUIREMENTS: - Accept a Markdown file path as a command-line argument - Support standard Markdown: headings (h1-h6), bold, italic, strikethrough, links, images, blockquotes, ordered and unordered lists, horizontal rules, inline code, and code blocks - Support GitHub Flavored Markdown extensions: tables, task lists (checkboxes), fenced code blocks with language identifiers, autolinks, and footnotes - Apply syntax highlighting to fenced code blocks based on the specified language (support at least: python, javascript, java, c++, html, css, json, bash) - Generate a table of contents from headings via --toc flag, inserted at the top of the document with anchor links - Support custom CSS styling via --css flag (path to a CSS file to embed or link in the output) - Support wrapping the output in a complete HTML document (with DOCTYPE, head, body) via --full-page flag, or outputting just the HTML fragment (default) - Support automatic heading ID generation for anchor links based on heading text - Support converting multiple Markdown files via --batch flag, with optional --index flag to generate an index page linking all converted files - Print the HTML output to console by default - Save the HTML to a file via --output flag (default: same base name with .html extension) - If no input file is given, generate a sample Markdown document demonstrating all supported features (headings, lists, code blocks, tables, images, links, task lists, footnotes), convert it, and save both the Markdown source and HTML output - Handle errors: invalid Markdown syntax (graceful degradation), missing linked files, and encoding issues Create a complete JavaScript project for a clean Ubuntu 22.04 machine with only Node.js 20+ (LTS) installed. Include: - Source code - package.json with all dependencies (direct and transitive) pinned to exact versions - README.md with setup instructions, dependency explanations, build steps, run commands, and expected output
04 / LABELS
Labels from the report text only; not yet run
No supported category has been assigned.
Label rules and the text that matched
[]
05 / FILES
The project as the agent wrote it
2 files, exactly as written, before any repair.
converter.js
/**
* Markdown to HTML Converter
*
* Converts Markdown files to HTML with GFM extensions, syntax highlighting,
* table of contents generation, and custom CSS support.
*
* Dependencies:
* - marked (12.0.0)
* - highlight.js (11.9.0)
*/
const { marked } = require("marked");
const hljs = require("highlight.js");
const fs = require("fs");
const path = require("path");
const DEFAULT_CSS = `
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif;
line-height: 1.6;
max-width: 900px;
margin: 0 auto;
padding: 2rem;
color: #333;
background-color: #fff;
}
h1, h2, h3, h4, h5, h6 {
margin-top: 1.5em;
margin-bottom: 0.5em;
font-weight: 600;
line-height: 1.25;
}
h1 { font-size: 2em; border-bottom: 1px solid #eaecef; padding-bottom: 0.3em; }
h2 { font-size: 1.5em; border-bottom: 1px solid #eaecef; padding-bottom: 0.3em; }
h3 { font-size: 1.25em; }
a { color: #0366d6; text-decoration: none; }
a:hover { text-decoration: underline; }
code {
background-color: #f6f8fa;
border-radius: 3px;
padding: 0.2em 0.4em;
font-size: 85%;
font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
}
pre {
background-color: #f6f8fa;
border-radius: 6px;
padding: 16px;
overflow: auto;
line-height: 1.45;
}
pre code { background-color: transparent; padding: 0; }
blockquote {
margin: 0;
padding: 0 1em;
color: #6a737d;
border-left: 0.25em solid #dfe2e5;
}
table { border-collapse: collapse; width: 100%; margin-bottom: 1em; }
th, td { border: 1px solid #dfe2e5; padding: 6px 13px; }
th { background-color: #f6f8fa; font-weight: 600; }
tr:nth-child(2n) { background-color: #f6f8fa; }
img { max-width: 100%; }
.toc {
background-color: #f6f8fa;
border: 1px solid #dfe2e5;
border-radius: 6px;
padding: 1em 1.5em;
margin-bottom: 2em;
}
.toc ul { list-style-type: none; padding-left: 1.5em; }
.toc > ul { padding-left: 0; }
.toc li { margin: 0.3em 0; }
hr {
height: 0.25em;
padding: 0;
margin: 24px 0;
background-color: #e1e4e8;
border: 0;
}
ul, ol { padding-left: 2em; }
li + li { margin-top: 0.25em; }
.hljs {
background: #f6f8fa;
padding: 16px;
border-radius: 6px;
overflow: auto;
}
`;
/**
* Markdown to HTML Converter class.
*/
class MarkdownToHtmlConverter {
/**
* @param {Object} options - Converter options.
* @param {string} [options.customCss] - Custom CSS string.
* @param {boolean} [options.enableToc=true] - Enable table of contents.
* @param {boolean} [options.enableSyntaxHighlight=true] - Enable syntax highlighting.
* @param {string} [options.tocTitle='Table of Contents'] - TOC title.
* @param {string} [options.highlightTheme='github-dark'] - highlight.js theme name.
*/
constructor(options = {}) {
this.customCss = options.customCss || null;
this.enableToc = options.enableToc !== false;
this.enableSyntaxHighlight = options.enableSyntaxHighlight !== false;
this.tocTitle = options.tocTitle || "Table of Contents";
this.highlightTheme = options.highlightTheme || "github-dark";
this.tocEntries = [];
this._configureMarked();
}
/**
* Configure marked parser with GFM and syntax highlighting.
*/
_configureMarked() {
const self = this;
const renderer = new marked.Renderer();
// Custom heading renderer to collect TOC entries and add anchors
const originalHeading = renderer.heading;
renderer.heading = function ({ tokens, depth }) {
const text = this.parser.parseInline(tokens);
const rawText = tokens.map(t => t.raw || t.text || "").join("");
const id = rawText
.toLowerCase()
.replace(/[^\w\s-]/g, "")
.replace(/\s+/g, "-");
self.tocEntries.push({ level: depth, text: rawText, id });
return `<h${depth} id="${id}">${text} <a class="anchor" href="#${id}">#</a></h${depth}>\n`;
};
marked.setOptions({
renderer,
gfm: true,
breaks: false,
pedantic: false,
highlight: this.enableSyntaxHighlight
? (code, lang) => {
if (lang && hljs.getLanguage(lang)) {
try {
return hljs.highlight(code, { language: lang }).value;
} catch (err) {
// fall through to auto-detect
}
}
try {
return hljs.highlightAuto(code).value;
} catch (err) {
return code;
}
}
: null,
});
}
/**
* Generate TOC HTML from collected heading entries.
* @returns {string} TOC HTML.
*/
_generateToc() {
if (!this.tocEntries.length) return "";
let html = `<div class="toc">\n<h2>${this._escapeHtml(this.tocTitle)}</h2>\n<ul>\n`;
let prevLevel = this.tocEntries[0].level;
for (const entry of this.tocEntries) {
if (entry.level > prevLevel) {
for (let i = prevLevel; i < entry.level; i++) {
html += "<ul>\n";
}
} else if (entry.level < prevLevel) {
for (let i = entry.level; i < prevLevel; i++) {
html += "</ul>\n";
}
}
html += `<li><a href="#${entry.id}">${this._escapeHtml(entry.text)}</a></li>\n`;
prevLevel = entry.level;
}
const startLevel = this.tocEntries[0].level;
for (let i = startLevel; i < prevLevel; i++) {
html += "</ul>\n";
}
html += "</ul>\n</div>";
return html;
}
/**
* Get the CSS for the HTML document.
* @returns {string} CSS content.
*/
_getCss() {
let css = this.customCss || DEFAULT_CSS;
if (this.enableSyntaxHighlight) {
// Include highlight.js theme reference
const themePath = path.join(
path.dirname(require.resolve("highlight.js")),
"..",
"styles",
`${this.highlightTheme}.css`
);
if (fs.existsSync(themePath)) {
css += "\n/* highlight.js theme */\n";
css += fs.readFileSync(themePath, "utf-8");
}
}
return css;
}
/**
* Convert Markdown text to a complete HTML document.
* @param {string} markdownText - Markdown source text.
* @returns {string} Complete HTML document.
*/
convert(markdownText) {
this.tocEntries = [];
const htmlBody = marked.parse(markdownText);
const tocHtml = this.enableToc ? this._generateToc() : "";
const css = this._getCss();
const title = this._extractTitle(markdownText);
return `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>${this._escapeHtml(title)}</title>
<style>
${css}
</style>
</head>
<body>
${tocHtml}
${htmlBody}
</body>
</html>`;
}
/**
* Convert a Markdown file to an HTML file.
* @param {string} inputPath - Path to input Markdown file.
* @param {string} [outputPath] - Path for output HTML file.
* @returns {string} Path to the generated HTML file.
*/
convertFile(inputPath, outputPath) {
if (!fs.existsSync(inputPath)) {
throw new Error(`Input file not found: ${inputPath}`);
}
const markdownText = fs.readFileSync(inputPath, "utf-8");
const html = this.convert(markdownText);
if (!outputPath) {
const ext = path.extname(inputPath);
outputPath = inputPath.replace(ext, ".html");
}
const dir = path.dirname(outputPath);
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, { recursive: true });
}
fs.writeFileSync(outputPath, html, "utf-8");
return outputPath;
}
/**
* Extract the first heading as a title.
* @param {string} markdown - Markdown source.
* @returns {string} Title string.
*/
_extractTitle(markdown) {
const match = markdown.match(/^#{1,6}\s+(.+)$/m);
return match ? match[1].trim() : "Converted Document";
}
/**
* Escape HTML special characters.
* @param {string} text
* @returns {string}
*/
_escapeHtml(text) {
return text
.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/"/g, """);
}
}
/**
* CLI entry point.
*/
function main() {
const args = process.argv.slice(2);
if (args.length === 0 || args.includes("--help") || args.includes("-h")) {
console.log("Usage: node converter.js [options] <input.md>");
console.log();
console.log("Options:");
console.log(" -o, --output <file> Output HTML file path");
console.log(" --css <file> Path to custom CSS file");
console.log(" --no-toc Disable table of contents");
console.log(" --no-highlight Disable syntax highlighting");
console.log(" --toc-title <title> TOC title (default: 'Table of Contents')");
console.log(" --theme <name> highlight.js theme (default: 'github-dark')");
console.log(" --stdout Print HTML to stdout");
console.log(" -h, --help Show this help message");
process.exit(args.length === 0 ? 1 : 0);
}
let inputFile = null;
let outputFile = null;
let cssFile = null;
let noToc = false;
let noHighlight = false;
let tocTitle = "Table of Contents";
let theme = "github-dark";
let toStdout = false;
for (let i = 0; i < args.length; i++) {
switch (args[i]) {
case "-o":
case "--output":
outputFile = args[++i];
break;
case "--css":
cssFile = args[++i];
break;
case "--no-toc":
noToc = true;
break;
case "--no-highlight":
noHighlight = true;
break;
case "--toc-title":
tocTitle = args[++i];
break;
case "--theme":
theme = args[++i];
break;
case "--stdout":
toStdout = true;
break;
default:
if (!args[i].startsWith("-")) {
inputFile = args[i];
}
break;
}
}
if (!inputFile) {
console.error("Error: No input file specified.");
process.exit(1);
}
let customCss = null;
if (cssFile) {
try {
customCss = fs.readFileSync(cssFile, "utf-8");
} catch (err) {
console.error(`Error: CSS file not found: ${cssFile}`);
process.exit(1);
}
}
const converter = new MarkdownToHtmlConverter({
customCss,
enableToc: !noToc,
enableSyntaxHighlight: !noHighlight,
tocTitle,
highlightTheme: theme,
});
try {
if (toStdout) {
const markdown = fs.readFileSync(inputFile, "utf-8");
console.log(converter.convert(markdown));
} else {
const output = converter.convertFile(inputFile, outputFile);
console.log(`HTML written to: ${output}`);
}
} catch (err) {
console.error(`Error: ${err.message}`);
process.exit(1);
}
}
module.exports = { MarkdownToHtmlConverter };
if (require.main === module) {
main();
}
package.json
{
"name": "md-to-html-converter",
"version": "1.0.0",
"description": "Markdown to HTML converter with GFM extensions, syntax highlighting, TOC generation, and custom CSS support",
"main": "converter.js",
"scripts": {
"start": "node converter.js",
"convert": "node converter.js"
},
"keywords": [
"markdown",
"html",
"converter",
"gfm",
"syntax-highlighting",
"toc"
],
"license": "MIT",
"dependencies": {
"marked": "12.0.0",
"highlight.js": "11.9.0"
}
}