103 lines
3.8 KiB
JavaScript
103 lines
3.8 KiB
JavaScript
// 수동 실행: new_home v1 폴더에서 node scripts/sync-capabilities-seo.mjs
|
|
// capabilities-data.js의 내용을 capabilities.html의 정적 SEO 영역에 반영함.
|
|
// 브라우저에서는 실행되지 않으며, 프로젝트 내용을 수정한 뒤 배포 전에 실행.
|
|
import fs from "node:fs";
|
|
import path from "node:path";
|
|
import vm from "node:vm";
|
|
import { fileURLToPath } from "node:url";
|
|
|
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
const root = path.resolve(__dirname, "..");
|
|
const dataPath = path.join(root, "js", "capabilities-data.js");
|
|
const htmlPath = path.join(root, "capabilities.html");
|
|
|
|
const context = { window: {} };
|
|
vm.createContext(context);
|
|
vm.runInContext(fs.readFileSync(dataPath, "utf8"), context);
|
|
|
|
const projects = context.window.CAPABILITY_PROJECTS || [];
|
|
const projectIds = new Set();
|
|
for (const item of projects) {
|
|
if (!item.id || projectIds.has(item.id)) {
|
|
throw new Error(`Missing or duplicate project ID: ${item.id}`);
|
|
}
|
|
projectIds.add(item.id);
|
|
for (const field of ["image", "objectImage", "objectImageSecondary"]) {
|
|
if (item[field] && !fs.existsSync(path.resolve(root, item[field]))) {
|
|
throw new Error(`Missing capabilities image (${item.id}): ${item[field]}`);
|
|
}
|
|
}
|
|
}
|
|
const groups = [
|
|
["automotive", "Automotive 전장 기술 역량"],
|
|
["robotics", "Robotics 로봇 기술 역량"],
|
|
["solution", "Solution 솔루션 기술 역량"],
|
|
["si", "SI 웹·앱 개발 사례"],
|
|
["certifications", "Certifications 특허 기술 역량"],
|
|
];
|
|
|
|
function escapeHtml(value = "") {
|
|
return String(value)
|
|
.replace(/&/g, "&")
|
|
.replace(/</g, "<")
|
|
.replace(/>/g, ">")
|
|
.replace(/"/g, """)
|
|
.replace(/'/g, "'");
|
|
}
|
|
|
|
function normalizeText(value = "") {
|
|
return String(value).replace(/\s+/g, " ").trim();
|
|
}
|
|
|
|
function renderProject(item) {
|
|
const subtitle = item.subtitle
|
|
? `\n <p>${escapeHtml(item.subtitle)}</p>`
|
|
: "";
|
|
const description = item.layout === "table"
|
|
? "자동차 전장 개발 및 컨설팅 이력을 사업명과 사업기간 기준으로 정리한 기타 수행 프로젝트 목록입니다."
|
|
: normalizeText(item.description);
|
|
const tableRows = item.tableRows
|
|
? `\n <ul>${item.tableRows.map((row) => `<li>${escapeHtml(row[0])} · ${escapeHtml(row[1])}</li>`).join("")}</ul>`
|
|
: "";
|
|
|
|
return ` <article id="seo-${escapeHtml(item.id)}">
|
|
<h4>${escapeHtml(item.title)}</h4>${subtitle}
|
|
<p>${escapeHtml(description)}</p>${tableRows}
|
|
</article>`;
|
|
}
|
|
|
|
const sections = groups.map(([type, title]) => {
|
|
const items = projects.filter((item) => item.type === type);
|
|
return ` <section id="seo-${type}" class="capabilities-seo-group">
|
|
<h3>${escapeHtml(title)}</h3>
|
|
${items.map(renderProject).join("\n")}
|
|
</section>`;
|
|
}).join("\n");
|
|
|
|
const block = `<!-- CAPABILITIES_SEO_START -->
|
|
<section class="capabilities-seo" aria-labelledby="capabilities-seo-title">
|
|
<h2 id="capabilities-seo-title">모비핀테크놀러지 기술 역량</h2>
|
|
<p>
|
|
모비핀테크놀러지는 자동차 전장, 로봇, 솔루션, SI 영역에서 실제 운영 환경에 적용되는 소프트웨어를 개발합니다.
|
|
</p>
|
|
${sections}
|
|
</section>
|
|
<!-- CAPABILITIES_SEO_END -->`;
|
|
|
|
const html = fs.readFileSync(htmlPath, "utf8");
|
|
const markerPattern = /<!-- CAPABILITIES_SEO_START -->[\s\S]*?<!-- CAPABILITIES_SEO_END -->/;
|
|
if (!markerPattern.test(html)) {
|
|
throw new Error("SEO marker block was not found in capabilities.html");
|
|
}
|
|
const next = html.replace(
|
|
markerPattern,
|
|
block,
|
|
);
|
|
|
|
if (next !== html) {
|
|
fs.writeFileSync(htmlPath, next);
|
|
console.log(`Updated capabilities.html SEO content (${projects.length} projects).`);
|
|
} else {
|
|
console.log(`SEO content is already up to date (${projects.length} projects).`);
|
|
}
|