diff options
| author | Yasutake Yohei <61961825+yasutakeyohei@users.noreply.github.com> | 2026-06-21 19:41:03 +0900 |
|---|---|---|
| committer | Yasutake Yohei <61961825+yasutakeyohei@users.noreply.github.com> | 2026-06-21 19:41:03 +0900 |
| commit | 6fa8872f6b4be562d62f992a4ba85a1ed75136af (patch) | |
| tree | 40a55a703d93f5a1150882ba087b06e27b131b12 /scripts | |
| parent | 6bf6085fcbe2e8fa8cfa6d4265b7eb58c35c2b2a (diff) | |
QuestionSummary に about プロパティを追加し @graph 構造に変更
JSON-LD を WebPage + FAQPage の @graph 構造に変更し、
WebPage.about で質問の主題を明示するようにした。
- about は frontmatter の tags から推測(初回の非「一般質問」タグ)
- 64ページすべてに about を追加済み
- AGENTS.md の使用例も更新
Diffstat (limited to 'scripts')
| -rw-r--r-- | scripts/add-about-prop.mjs | 107 |
1 files changed, 107 insertions, 0 deletions
diff --git a/scripts/add-about-prop.mjs b/scripts/add-about-prop.mjs new file mode 100644 index 0000000..e519863 --- /dev/null +++ b/scripts/add-about-prop.mjs @@ -0,0 +1,107 @@ +import { readFileSync, writeFileSync } from "node:fs"; +import { readdir } from "node:fs/promises"; +import { join, extname, relative } from "node:path"; + +const DOCS_DIR = join(import.meta.dirname, "..", "src", "content", "docs"); + +/** + * Recursively collect all .mdx files. + */ +async function collectMdxFiles(dir) { + const entries = await readdir(dir, { withFileTypes: true }); + const files = []; + + for (const entry of entries) { + if (entry.name.startsWith("_")) continue; + const fullPath = join(dir, entry.name); + if (entry.isDirectory()) { + const subFiles = await collectMdxFiles(fullPath); + files.push(...subFiles); + } else if (extname(entry.name) === ".mdx") { + files.push(fullPath); + } + } + + return files; +} + +/** + * Extract tags from frontmatter. + */ +function extractTags(content) { + const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---/); + if (!match) return []; + const fm = match[1]; + + // Match YAML-style tags array: tags:\n - tag1\n - tag2 + const tagSection = fm.match(/^tags:\s*\n((?:\s+-\s+.+\n?)*)/m); + if (!tagSection) return []; + + const tagLines = tagSection[1].match(/^\s+-\s+(.+)$/gm); + if (!tagLines) return []; + + return tagLines.map((line) => line.replace(/^\s+-\s+/, "").trim()); +} + +/** + * Infer `about` from tags. + * Uses the first tag that is not "一般質問". + */ +function inferAbout(tags) { + for (const tag of tags) { + if (tag !== "一般質問") return tag; + } + return null; +} + +async function main() { + const files = await collectMdxFiles(DOCS_DIR); + + let updated = 0; + let skipped = 0; + + for (const file of files) { + const content = readFileSync(file, "utf-8"); + + // Only process files that use QuestionSummary + if (!content.includes("<QuestionSummary")) continue; + + // Skip files that already have about= + if (content.includes("about=")) { + skipped++; + continue; + } + + const tags = extractTags(content); + const about = inferAbout(tags); + + if (!about) { + console.log(` SKIP (no topic tag): ${relative(DOCS_DIR, file)}`); + skipped++; + continue; + } + + // Insert about prop after headline prop + const newContent = content.replace( + /(headline=.*\n)(\s+datePublished=)/, + `$1 about="${about}"\n$2`, + ); + + if (newContent === content) { + console.log(` SKIP (pattern not matched): ${relative(DOCS_DIR, file)}`); + skipped++; + continue; + } + + writeFileSync(file, newContent, "utf-8"); + console.log(` about="${about}" → ${relative(DOCS_DIR, file)}`); + updated++; + } + + console.log(`\nDone: ${updated} updated, ${skipped} skipped.`); +} + +main().catch((err) => { + console.error("Error:", err); + process.exit(1); +}); |
