1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
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);
});
|