Content is user-generated and unverified.
// ラムダノート用 markdownlint カスタムルール // 使用方法: markdownlint -r ./lambda-note-rules.js your-document.md module.exports = [ // ルール1: 最上位見出しはレベル2(##)のみ許可 { names: ["lambda-note-top-level-heading"], description: "最上位見出しはレベル2(##)を使用してください", tags: ["headings"], function: function LN001(params, onError) { const { tokens } = params; let hasLevel2Heading = false; tokens.forEach(token => { if (token.type === "heading_open") { const level = parseInt(token.tag.substring(1)); if (level === 1) { onError({ lineNumber: token.lineNumber, detail: "最上位見出しにはレベル2(##)を使用してください。レベル1(#)は使用できません。" }); } else if (level === 2) { hasLevel2Heading = true; } else if (level > 3) { onError({ lineNumber: token.lineNumber, detail: "見出しは3レベルまでしか使用できません。構造を簡素化してください。" }); } } }); } }, // ルール2: 段落内での改行推奨(句点ごとの改行) { names: ["lambda-note-paragraph-breaks"], description: "段落内では句点ごとに改行することを推奨します", tags: ["paragraphs"], function: function LN002(params, onError) { const { lines } = params; lines.forEach((line, index) => { const trimmedLine = line.trim(); if (trimmedLine && !trimmedLine.startsWith('#') && !trimmedLine.startsWith('*') && !trimmedLine.startsWith('1.') && !trimmedLine.startsWith('>') && !trimmedLine.startsWith('```') && !trimmedLine.startsWith('|')) { // 句点が含まれる行で、句点の後に文章が続く場合 const periods = trimmedLine.match(/。[^)」』]*[ぁ-んァ-ヶー一-龯]/g); if (periods && periods.length > 0) { onError({ lineNumber: index + 1, detail: "句点(。)の後で改行することを推奨します。差分が見やすくなります。" }); } } }); } }, // ルール3: 全角句読点の使用チェック { names: ["lambda-note-punctuation"], description: "句読点は全角(。、)を使用してください", tags: ["punctuation"], function: function LN003(params, onError) { const { lines } = params; lines.forEach((line, index) => { // 半角の句読点をチェック(コードブロック内は除外) if (!line.includes('```') && !line.trim().startsWith('```')) { if (line.includes('.') && /[ぁ-んァ-ヶー一-龯]\./.test(line)) { onError({ lineNumber: index + 1, detail: "句点には全角(。)を使用してください。半角の . は句読点として使用できません。" }); } if (line.includes(',') && /[ぁ-んァ-ヶー一-龯],/.test(line)) { onError({ lineNumber: index + 1, detail: "読点には全角(、)を使用してください。半角の , は句読点として使用できません。" }); } } }); } }, // ルール4: コードブロックのキャプションとID必須 { names: ["lambda-note-code-blocks"], description: "コードブロックにはIDとキャプションを指定してください", tags: ["code"], function: function LN004(params, onError) { const { tokens } = params; tokens.forEach(token => { if (token.type === "fence" && token.info) { const info = token.info.trim(); if (info && !info.includes('{#lst:') && !info.includes('caption=')) { onError({ lineNumber: token.lineNumber, detail: 'コードブロックには {#lst:id language caption="説明"} の形式でIDとキャプションを指定してください。' }); } } }); } }, // ルール5: 図のキャプションとID必須 { names: ["lambda-note-images"], description: "図にはキャプションとIDを指定してください", tags: ["images"], function: function LN005(params, onError) { const { tokens } = params; tokens.forEach(token => { if (token.type === "inline") { const imageMatches = token.content.match(/!\[([^\]]*)\]\([^)]+\)(?!\{#fig:)/g); if (imageMatches) { imageMatches.forEach(() => { onError({ lineNumber: token.lineNumber, detail: '図には ![キャプション](path){#fig:id} の形式でIDを指定してください。' }); }); } } }); } }, // ルール6: 表のキャプション必須 { names: ["lambda-note-tables"], description: "表にはキャプションを指定してください", tags: ["tables"], function: function LN006(params, onError) { const { lines } = params; let inTable = false; let tableStartLine = 0; lines.forEach((line, index) => { const trimmedLine = line.trim(); if (trimmedLine.includes('|') && !inTable) { inTable = true; tableStartLine = index + 1; } else if (inTable && !trimmedLine.includes('|') && trimmedLine) { if (!trimmedLine.startsWith('Table:')) { onError({ lineNumber: tableStartLine, detail: 'テーブルの後には "Table: タイトル{#tbl:id}" の形式でキャプションを指定してください。' }); } inTable = false; } else if (inTable && !trimmedLine) { // 空行でテーブル終了とみなす inTable = false; } }); } }, // ルール7: 和欧文間スペース禁止 { names: ["lambda-note-no-spaces"], description: "日本語と英数字間にスペースを入れないでください", tags: ["spacing"], function: function LN007(params, onError) { const { lines } = params; lines.forEach((line, index) => { // コードブロック内は除外 if (!line.includes('```') && !line.trim().startsWith('```')) { // 日本語の後にスペース+英数字 if (/[ぁ-んァ-ヶー一-龯]\s+[a-zA-Z0-9]/.test(line)) { onError({ lineNumber: index + 1, detail: "日本語と英数字間にスペースを入れないでください。" }); } // 英数字の後にスペース+日本語 if (/[a-zA-Z0-9]\s+[ぁ-んァ-ヶー一-龯]/.test(line)) { onError({ lineNumber: index + 1, detail: "英数字と日本語間にスペースを入れないでください。" }); } } }); } }, // ルール8: 括弧の使用チェック { names: ["lambda-note-brackets"], description: "補足には全角の丸括弧()、引用には鍵括弧「」を使用してください", tags: ["punctuation"], function: function LN008(params, onError) { const { lines } = params; lines.forEach((line, index) => { // コードブロック内は除外 if (!line.includes('```') && !line.trim().startsWith('```')) { // 半角括弧をチェック if (/[ぁ-んァ-ヶー一-龯][()][ぁ-んァ-ヶー一-龯]/.test(line) || /[ぁ-んァ-ヶー一-龯]\([^)]*\)[ぁ-んァ-ヶー一-龯]/.test(line)) { onError({ lineNumber: index + 1, detail: "日本語の補足には全角の丸括弧()を使用してください。" }); } // ダブルクォーテーションの使用チェック if (/"[^"]*"/.test(line) && /[ぁ-んァ-ヶー一-龯]/.test(line)) { onError({ lineNumber: index + 1, detail: "日本語の引用や強調には鍵括弧「」を使用してください。ダブルクォーテーションは使用しないでください。" }); } } }); } }, // ルール9: 引用ブロックの後に説明必須 { names: ["lambda-note-quote-explanation"], description: "引用の後には必ず説明を追加してください", tags: ["blockquotes"], function: function LN009(params, onError) { const { lines } = params; let inQuote = false; let quoteEndLine = 0; lines.forEach((line, index) => { const trimmedLine = line.trim(); if (trimmedLine.startsWith('>') && !trimmedLine.startsWith('> note') && !trimmedLine.startsWith('> aside{')) { inQuote = true; } else if (inQuote && !trimmedLine.startsWith('>')) { if (!trimmedLine) { // 空行の場合は次の行をチェック quoteEndLine = index + 1; } else { // 引用後の説明があるかチェック if (quoteEndLine > 0 && index === quoteEndLine && (trimmedLine.startsWith('#') || trimmedLine.startsWith('>'))) { onError({ lineNumber: quoteEndLine, detail: "引用の後には必ず日本語での説明を追加してください。引用のみで説明を終わらせないでください。" }); } inQuote = false; quoteEndLine = 0; } } }); } }, // ルール10: コードブロックの後に説明必須 { names: ["lambda-note-code-explanation"], description: "コードブロックの後には必ず説明を追加してください", tags: ["code"], function: function LN010(params, onError) { const { tokens } = params; let foundFence = false; let fenceLineNumber = 0; for (let i = 0; i < tokens.length; i++) { const token = tokens[i]; if (token.type === "fence") { foundFence = true; fenceLineNumber = token.lineNumber; } else if (foundFence && token.type === "paragraph_open") { // コードブロックの後に段落があるかチェック const nextToken = tokens[i + 1]; if (nextToken && nextToken.type === "inline" && nextToken.content.trim()) { foundFence = false; // 説明があるのでOK } } else if (foundFence && (token.type === "heading_open" || token.type === "fence")) { // 次の見出しやコードブロックが来た場合、説明がない onError({ lineNumber: fenceLineNumber, detail: "コードブロックの後には必ず日本語での説明を追加してください。コードの目的や動作について解説してください。" }); foundFence = false; } } } } ];
Content is user-generated and unverified.
    ラムダノート用 markdownlint カスタムルール | Claude