diff options
| author | Yasutake Yohei <yohei@yasutakeyohei.com> | 2026-07-04 22:35:48 +0900 |
|---|---|---|
| committer | Yasutake Yohei <yohei@yasutakeyohei.com> | 2026-07-04 22:35:48 +0900 |
| commit | 366fcdb6323ae2b45c493e8c2b9ced78be2bce30 (patch) | |
| tree | 1ba8ae736fbe4744cf6d797457295481aa232284 | |
| parent | bca6fd186763c5fef67e7e700f234834c3b8f693 (diff) | |
QuestionSummary: r7d/12gatuとr7d/3gatuの再質問項目を表に追加
5 files changed, 193 insertions, 0 deletions
diff --git a/scripts/check-headings.js b/scripts/check-headings.js new file mode 100644 index 0000000..355b5a2 --- /dev/null +++ b/scripts/check-headings.js @@ -0,0 +1,177 @@ +/** + * Checks all general question MDX files under ippan-situmon to find + * `####` sub-headings that are NOT in the QuestionSummary component. + */ +const fs = require("fs"); +const path = require("path"); + +const BASE = path.resolve(__dirname, "..", "src/content/docs/ippan-situmon"); + +function findMdxFiles(dir) { + const results = []; + const entries = fs.readdirSync(dir, { withFileTypes: true }); + for (const entry of entries) { + const fullPath = path.join(dir, entry.name); + if (entry.isDirectory()) { + results.push(...findMdxFiles(fullPath)); + } else if ( + entry.name.endsWith(".mdx") && + entry.name !== "index.mdx" && + entry.name !== "_partial.mdx" + ) { + results.push(fullPath); + } + } + return results; +} + +// Parse anchor values from a QuestionSummary qa array +function parseAnchors(content) { + const anchorRegex = /anchor:\s*"([^"]+)"/g; + const anchors = []; + let match; + while ((match = anchorRegex.exec(content)) !== null) { + anchors.push(match[1]); + } + return anchors; +} + +// Parse `####` headings from MDX content +function parseH4Headings(content) { + const headingRegex = /^####\s+(.+?)(?:\s*\{[^}]*\})?\s*$/gm; + const headings = []; + let match; + while ((match = headingRegex.exec(content)) !== null) { + const raw = match[1].trim(); + headings.push(raw); + } + return headings; +} + +// Generate Starlight-style anchor ID from heading text +function toAnchorId(text) { + return text + .toLowerCase() + .replace(/<[^>]+>/g, "") // remove HTML tags + .replace( + /[^\w\s\-\u3040-\u309f\u30a0-\u30ff\u4e00-\u9fffぁ-んァ-ン一-龯ー・〜?!。、()「」【】]/g, + "", + ) + .replace(/\s+/g, "-") + .replace(/-+/g, "-") + .replace(/^-|-$/g, ""); +} + +// Check if a heading matches any anchor +function headingMatchesAnchor(heading, anchors) { + const headingId = toAnchorId(heading); + + for (const anchor of anchors) { + // Exact match + if (anchor === heading) return true; + + // Anchor ID match + if (anchor === headingId) return true; + + // Anchor prefixed with "-" + if (anchor === `-${heading}`) return true; + if (anchor === `-${headingId}`) return true; + + // Anchor that starts with "-" - check if headingId matches after "-" + if (anchor.startsWith("-")) { + const afterDash = anchor.substring(1); + if (afterDash === headingId || afterDash === heading) return true; + } + + // Headings sometimes have HTML in them (like <sub>) + // Strip HTML from heading and compare to anchor + const headingPlain = heading.replace(/<[^>]+>/g, ""); + const headingPlainId = toAnchorId(headingPlain); + + if (anchor === headingPlain) return true; + if (anchor === headingPlainId) return true; + if (anchor === `-${headingPlain}`) return true; + if (anchor === `-${headingPlainId}`) return true; + if (anchor.startsWith("-") && anchor.substring(1) === headingPlainId) + return true; + } + return false; +} + +function main() { + const files = findMdxFiles(BASE).sort(); + const results = []; + + for (const file of files) { + const content = fs.readFileSync(file, "utf-8"); + const h4Headings = parseH4Headings(content); + const anchors = parseAnchors(content); + + if (h4Headings.length === 0) continue; + + const relPath = path.relative(process.cwd(), file); + const missing = []; + + for (const heading of h4Headings) { + if (!headingMatchesAnchor(heading, anchors)) { + missing.push(heading); + } + } + + results.push({ + file: relPath, + totalH4: h4Headings.length, + totalAnchors: anchors.length, + missing, + allPresent: missing.length === 0, + }); + } + + // Output results + console.log("=".repeat(80)); + console.log("ANALYSIS: #### headings NOT in QuestionSummary"); + console.log("=".repeat(80)); + console.log(); + + let filesWithMissing = 0; + let totalMissing = 0; + + for (const r of results) { + if (r.missing.length === 0) continue; + + filesWithMissing++; + totalMissing += r.missing.length; + + if (r.totalAnchors === 0) { + console.log(`❌ ${r.file}`); + console.log( + ` Has ${r.totalH4} '####' headings but NO QuestionSummary component.`, + ); + console.log(); + continue; + } + + console.log( + `⚠️ ${r.file} [${r.totalAnchors} anchors, ${r.missing.length}/${r.totalH4} headings missing]`, + ); + for (const m of r.missing) { + console.log(` #### ${m}`); + } + console.log(); + } + + console.log("=".repeat(80)); + console.log(`SUMMARY:`); + console.log(` Files with missing headings: ${filesWithMissing}`); + console.log( + ` Files entirely missing QuestionSummary: ${results.filter((r) => r.totalAnchors === 0 && r.totalH4 > 0).length}`, + ); + console.log( + ` Files fully in sync: ${results.filter((r) => r.allPresent && r.totalAnchors > 0).length}`, + ); + console.log(` Total missing headings: ${totalMissing}`); + console.log(` Total files analyzed: ${results.length}`); + console.log("=".repeat(80)); +} + +main(); diff --git a/src/content/docs/ippan-situmon/r7d/12gatu/1-koubunsyo-kanri.mdx b/src/content/docs/ippan-situmon/r7d/12gatu/1-koubunsyo-kanri.mdx index 00e39ef..dc6e8c1 100644 --- a/src/content/docs/ippan-situmon/r7d/12gatu/1-koubunsyo-kanri.mdx +++ b/src/content/docs/ippan-situmon/r7d/12gatu/1-koubunsyo-kanri.mdx @@ -41,6 +41,13 @@ import KaigirokuDougaLink from '@/components/KaigirokuDougaLink.astro'; { question: "⑪ 学校いじめ対策委員会協議録の保存期間の定めがない理由は。", answer: "各学校における保存期間を定めた文書の作成状況を把握していない。校長が定めることになっている。", anchor: "-学校いじめ対策委員会協議録の保存期間" }, { question: "⑫ いじめ対策委員会記録を残していない事例数と対応は。", answer: "1校で平成29年度から昨年度まで未作成。今年度は全校で作成確認。引き続き周知。", anchor: "-いじめ対策委員会記録を残していない事例数と対応" }, { question: "⑬ 保存年限超過文書の公開決定取消しの経緯は。", answer: "誤った認識で公開対象外と説明→指摘受け取消し。文書特定に時間を要し再決定まで5か月以上。取消しの期限規定なし。", anchor: "-保存年限超過文書の公開決定取消し" }, + { question: " ↳ 公文書管理の刑事罰リスクは認識されているか。", answer: "(初回質問)", anchor: "-公文書管理の刑事罰リスク" }, + { question: " ↳ 第10条第1項の定めはどこに残っているのか。", answer: "答弁錯綜。", anchor: "-第10条第1項の解釈" }, + { question: " ↳ 私物カメラの盗撮事件と処分根拠は。", answer: "私物使用を理由とする規定はない。服務規律全体で判断。", anchor: "-私物カメラの盗撮事件と処分根拠" }, + { question: " ↳ システム情報の公開実績はあるか。", answer: "要件を満たせば公開対象。実績は把握していず。", anchor: "-システム情報の公開実績" }, + { question: " ↳ 保存コストと法的制約はどうか。", answer: "電子化コストはゼロに近いが、全永年保存は考えていない。", anchor: "-保存コストと法的制約" }, + { question: " ↳ 非公開の法的根拠は十分か。", answer: "支障の蓋然性を具体的に示せず。顧問弁護士確認済み。", anchor: "-非公開の法的根拠" }, + { question: " ↳ 黒塗りと白塗りの並存は許されるか。", answer: "黒塗りが基本。併用は許していない。", anchor: "-黒塗りと白塗りの並存" }, ]} /> diff --git a/src/content/docs/ippan-situmon/r7d/12gatu/2-ijime-judai-yosan.mdx b/src/content/docs/ippan-situmon/r7d/12gatu/2-ijime-judai-yosan.mdx index f273ea4..cf6d64c 100644 --- a/src/content/docs/ippan-situmon/r7d/12gatu/2-ijime-judai-yosan.mdx +++ b/src/content/docs/ippan-situmon/r7d/12gatu/2-ijime-judai-yosan.mdx @@ -31,6 +31,7 @@ import KaigirokuDougaLink from '@/components/KaigirokuDougaLink.astro'; { question: "① 予算計上の経緯は議員の理解で正しいか。", answer: "提案事業調書提出時は調査事案が存在せず見積り不能。予算見積書に含めず。補正予算を原則とし緊急時は予備費。その他はお見込みのとおり。", anchor: "-予算計上の経緯" }, { question: "② 来年度も同様のやり方で予算計上するのか。", answer: "当初予算編成前に分からない場合は補正予算を原則とし、緊急時は予備費で対応。当初予算編成後の発生は今回同様の形。", anchor: "-来年度の予算計上方針" }, { question: "③ 補正予算成立まで5か月待つ場合の対応は。", answer: "令和8年度予算編成は現在行っている時期であり、教育と協議し定める。御指摘の点も踏まえ協議。", anchor: "-補正予算成立までの空白期間" }, + { question: " ↳ 補正予算と委員報酬、不足分はどうするのか。", answer: "補正予算成立までは予備費で対応。", anchor: "-補正予算と委員報酬" }, ]} /> ## 通告書 diff --git a/src/content/docs/ippan-situmon/r7d/12gatu/3-nyusatsu-hutyou-zuii-keiyaku.mdx b/src/content/docs/ippan-situmon/r7d/12gatu/3-nyusatsu-hutyou-zuii-keiyaku.mdx index 4b38caa..a2e16b0 100644 --- a/src/content/docs/ippan-situmon/r7d/12gatu/3-nyusatsu-hutyou-zuii-keiyaku.mdx +++ b/src/content/docs/ippan-situmon/r7d/12gatu/3-nyusatsu-hutyou-zuii-keiyaku.mdx @@ -32,6 +32,7 @@ import KaigirokuDougaLink from '@/components/KaigirokuDougaLink.astro'; { question: "② 入札不調の記録が残っていない理由は。", answer: "再入札の可能性が高く結果公開で参加事業者や入札額が類推されるおそれがあるため。不調案件の経過公開規定なし。", anchor: "-入札不調の記録不在" }, { question: "③ 入札結果がe-Tokyoに反映されるまでの時間は。", answer: "入札成立案件は経過等の公開規定はあるが時期等の定めはない。準備が整い次第順次公開。", anchor: "-入札結果の公開タイミング" }, { question: "④ 「協議により決定」等の備考欄記載の意味は。", answer: "予定価格内に収まらず不落随意契約等の協議に至り見積書再提出で決定。全参加事業者向けの事務連絡。", anchor: "-協議により決定の備考欄記載" }, + { question: " ↳ 不落随意契約は原則廃止すべきでは。", answer: "国土交通省通知は一般論であり、現行運用に問題なし。", anchor: "-不落随意契約の原則廃止" }, ]} /> ## 通告書 diff --git a/src/content/docs/ippan-situmon/r7d/3gatu/1-tokiwakai-gyakutaigosoku-wakai.mdx b/src/content/docs/ippan-situmon/r7d/3gatu/1-tokiwakai-gyakutaigosoku-wakai.mdx index 1c887ed..41e33be 100644 --- a/src/content/docs/ippan-situmon/r7d/3gatu/1-tokiwakai-gyakutaigosoku-wakai.mdx +++ b/src/content/docs/ippan-situmon/r7d/3gatu/1-tokiwakai-gyakutaigosoku-wakai.mdx @@ -31,6 +31,13 @@ import KaigirokuDougaLink from '@/components/KaigirokuDougaLink.astro'; { question: "① 和解を踏まえた事実関係の確認は必要か。", answer: "裁判の結果を受けて事実確認は予定していない。相談があれば国の手引きに基づき対応。", anchor: "-和解を踏まえた事実関係の確認は必要か" }, { question: "② 公益通報者保護法に関わる不利益取扱いの疑いが生じた場合の対応手順は。", answer: "相談があれば労働基準監督署などの相談先を案内。障害者虐待に起因するものは①と同様の対応。", anchor: "-公益通報者保護法に関わる不利益取扱いの疑いが生じた場合の対応手順は" }, { question: "③ 対応手順は明文化されているか。", answer: "公益通報の手順は明文化していない。障害者虐待に起因するものは法律及び国の手引きに基づき対応。", anchor: "-対応手順は明文化されているか" }, + { question: " ↳ 和解を受けて事実確認すべきでは。", answer: "裁判結果を受けての事実確認は予定していない。", anchor: "-和解を受けた事実確認の必要性" }, + { question: " ↳ 裁判記録を第三者が閲覧できるか。", answer: "保存期間経過後は廃棄。", anchor: "-裁判記録の第三者閲覧" }, + { question: " ↳ 通報者特定情報は漏洩していないか。", answer: "情報管理に努めている。", anchor: "-通報者特定情報の漏洩" }, + { question: " ↳ 事業者文書の真偽は確認できるか。", answer: "市が確認する立場にない。", anchor: "-事業者文書の真偽" }, + { question: " ↳ 虐待防止委員会の役割は果たされているか。", answer: "法律上の位置付けはないが、市として注視していく。", anchor: "-虐待防止委員会の役割" }, + { question: " ↳ 改正公益通報者保護法を踏まえた対応は。", answer: "国や都の動向を注視。", anchor: "-改正公益通報者保護法を踏まえた対応" }, + { question: " ↳ マニュアルを充実させるべきでは。", answer: "必要に応じて見直しを検討。", anchor: "-マニュアルの充実" }, ]} /> ## 通告書 |
