UNPKG

@archer-edu/dxp-directus-cli

Version:
313 lines 11.5 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.toDirectusSlug = exports.buildPageCreatePayload = exports.validateNewPage = exports.parsePageMarkdown = void 0; /* eslint-disable @typescript-eslint/no-explicit-any */ const fs_1 = __importDefault(require("fs")); const path_1 = __importDefault(require("path")); const js_yaml_1 = __importDefault(require("js-yaml")); const PAGE_CANONICAL_FIELDS = new Set([ "id", "title", "description", "json_ld", "published", "slug", "draft", "weight", "sections", ]); const SECTION_DIRECT_FIELDS = new Set([ "id", "type", "style", "section", "content", "align", "source", "path", "classes", "sort", "image", "images", "items", "name", "data", ]); const ITEM_DIRECT_FIELDS = new Set([ "id", "item", "style", "align", "classes", "content", "sort", "image", "name", "data", ]); function parsePageMarkdown(filePath, options = {}) { const cwd = path_1.default.resolve(options.cwd || process.cwd()); const absoluteFilePath = path_1.default.resolve(cwd, filePath); const contentRoot = path_1.default.resolve(cwd, options.contentRoot || "src/content"); const contentRelativePath = path_1.default.relative(contentRoot, absoluteFilePath); if (contentRelativePath.startsWith("..") || path_1.default.isAbsolute(contentRelativePath)) { throw new Error(`Page file must be inside ${contentRoot}`); } if (path_1.default.extname(absoluteFilePath) !== ".md") { throw new Error("push-page only supports Markdown files with a .md extension"); } const text = fs_1.default.readFileSync(absoluteFilePath, "utf8"); const match = text.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/); if (!match) { throw new Error("Page file must start with YAML front matter delimited by ---"); } const frontMatter = (js_yaml_1.default.load(match[1]) || {}); if (!isRecord(frontMatter)) { throw new Error("Page front matter must be a YAML object"); } const { derivedSlug, parentPathSegments } = derivePathParts(contentRelativePath); return { filePath: absoluteFilePath, contentRoot, contentRelativePath, parentPathSegments, derivedSlug, frontMatter, body: match[2], }; } exports.parsePageMarkdown = parsePageMarkdown; function validateNewPage(page) { const errors = []; const { frontMatter } = page; if (page.derivedSlug === "index" && page.parentPathSegments.length === 0) { errors.push("home page creation is not supported"); } if (frontMatter.id) errors.push("page id"); if (!frontMatter.title || typeof frontMatter.title !== "string") { errors.push("missing required title"); } const slug = normalizeLocalSlug(frontMatter.slug || page.derivedSlug); if (!slug) { errors.push("missing slug"); } else if (slug.includes("/")) { errors.push(`slug '${slug}' must be a single path segment`); } else if (frontMatter.slug && slug !== page.derivedSlug) { errors.push(`front matter slug '${frontMatter.slug}' does not match derived slug '${page.derivedSlug}'`); } const sections = getSections(frontMatter); sections.forEach((section, sectionIndex) => { if (section.id) errors.push(`section ${sectionIndex + 1} id`); validateImageReference(section.image, `section ${sectionIndex + 1} image`, errors); validateImageList(section.images, `section ${sectionIndex + 1} images`, errors); getItems(section).forEach((item, itemIndex) => { if (item.id) errors.push(`section ${sectionIndex + 1} item ${itemIndex + 1} id`); validateImageReference(item.image, `section ${sectionIndex + 1} item ${itemIndex + 1} image`, errors); }); }); const idErrors = errors.filter(error => error.includes("id") && !error.includes("image")); if (idErrors.length) { throw new Error(`Existing Directus ids are not allowed for new page pushes: ${idErrors.join(", ")}`); } if (errors.length) { throw new Error(`Invalid page for push-page: ${errors.join("; ")}`); } } exports.validateNewPage = validateNewPage; function buildPageCreatePayload(page, options) { var _a; validateNewPage(page); const { frontMatter } = page; const sections = getSections(frontMatter); const customFrontMatter = copyWithoutKeys(frontMatter, PAGE_CANONICAL_FIELDS); const sort = (_a = frontMatter.weight) !== null && _a !== void 0 ? _a : options.sort; return cleanPayload({ site: options.siteId, parent_page: options.parentPageId || null, title: frontMatter.title, description: frontMatter.description, slug: toDirectusSlug(frontMatter.slug || page.derivedSlug), content: page.body.trim(), json_ld: frontMatter.json_ld, status: frontMatter.draft ? "draft" : "published", sort, content_mode: sections.length ? "advanced" : "basic", front_matter: dumpYamlOrNull(customFrontMatter), sections: sections.map(mapSection), }); } exports.buildPageCreatePayload = buildPageCreatePayload; function toDirectusSlug(slug) { const normalized = normalizeLocalSlug(slug); return normalized === "index" ? "/" : `/${normalized}`; } exports.toDirectusSlug = toDirectusSlug; function derivePathParts(contentRelativePath) { const parts = contentRelativePath.split(path_1.default.sep); const filename = parts[parts.length - 1]; const basename = filename.replace(/\.md$/, ""); const directories = parts.slice(0, -1); if (basename === "_index") { if (!directories.length) { return { derivedSlug: "index", parentPathSegments: [] }; } return { derivedSlug: directories[directories.length - 1], parentPathSegments: directories.slice(0, -1), }; } return { derivedSlug: basename, parentPathSegments: directories, }; } function mapSection(section, index) { var _a; const customData = copyWithoutKeys(section, SECTION_DIRECT_FIELDS); const items = getItems(section); const sectionName = section.name || section.section || `section-${index + 1}`; return cleanPayload({ type: section.type || "section", style: section.style || "base", section: section.section, content: section.content, align: section.align, source: section.source || "with", path: section.path, classes: section.classes, sort: (_a = section.sort) !== null && _a !== void 0 ? _a : index + 1, name: sectionName, image: getFileId(section.image), images: getImageJunctions(section.images), data: buildDataYaml(section.data, customData), items: items.map(mapItem), }); } function mapItem(item, index) { var _a; const customData = copyWithoutKeys(item, ITEM_DIRECT_FIELDS); return cleanPayload({ item: item.item || "box", style: item.style, align: item.align, classes: item.classes, content: item.content, sort: (_a = item.sort) !== null && _a !== void 0 ? _a : index + 1, name: item.name, image: getFileId(item.image), data: buildDataYaml(item.data, customData), }); } function getSections(frontMatter) { if (frontMatter.sections == null) return []; if (!Array.isArray(frontMatter.sections)) throw new Error("front matter sections must be an array"); return frontMatter.sections.filter(isRecord); } function getItems(section) { if (section.items == null) return []; if (!Array.isArray(section.items)) throw new Error("section items must be an array"); return section.items.filter(isRecord); } function validateImageList(value, label, errors) { if (value == null) return; if (!Array.isArray(value)) { errors.push(`${label} must be an array`); return; } value.forEach((item, index) => validateImageReference(item, `${label} ${index + 1}`, errors)); } function validateImageReference(value, label, errors) { if (value == null) return; if (typeof value === "string" && value.trim()) return; if (isRecord(value) && typeof value.id === "string" && value.id.trim()) return; if (isRecord(value) && typeof value.directus_files_id === "string" && value.directus_files_id.trim()) return; if (isRecord(value) && isRecord(value.directus_files_id) && typeof value.directus_files_id.id === "string" && value.directus_files_id.id.trim()) return; errors.push(`${label} must reference an existing Directus file id`); } function getImageJunctions(value) { if (!Array.isArray(value) || value.length === 0) return undefined; return value.map(image => ({ directus_files_id: getFileId(image) })); } function getFileId(value) { if (value == null) return undefined; if (typeof value === "string" && value.trim()) return value.trim(); if (isRecord(value) && typeof value.id === "string" && value.id.trim()) return value.id.trim(); if (isRecord(value) && typeof value.directus_files_id === "string" && value.directus_files_id.trim()) return value.directus_files_id.trim(); if (isRecord(value) && isRecord(value.directus_files_id) && typeof value.directus_files_id.id === "string" && value.directus_files_id.id.trim()) { return value.directus_files_id.id.trim(); } return undefined; } function buildDataYaml(existingData, customData) { const customYaml = dumpYamlOrNull(customData); if (typeof existingData === "string" && existingData.trim()) { return customYaml ? `${existingData.trim()}\n${customYaml}` : existingData; } if (isRecord(existingData)) { return dumpYamlOrNull(Object.assign(Object.assign({}, existingData), customData)) || undefined; } return customYaml || undefined; } function dumpYamlOrNull(value) { if (!Object.keys(value).length) return null; return js_yaml_1.default.dump(value, { skipInvalid: true, lineWidth: -1, }).trim(); } function copyWithoutKeys(source, keys) { return Object.keys(source).reduce((acc, key) => { if (!keys.has(key) && source[key] !== undefined) acc[key] = source[key]; return acc; }, {}); } function normalizeLocalSlug(value) { return typeof value === "string" ? value.trim().replace(/^\/+|\/+$/g, "") : ""; } function cleanPayload(payload) { Object.keys(payload).forEach(key => { const value = payload[key]; if (value == null) { delete payload[key]; } else if (Array.isArray(value)) { value.forEach(item => { if (isRecord(item)) cleanPayload(item); }); } else if (isRecord(value)) { cleanPayload(value); } }); return payload; } function isRecord(value) { return value != null && typeof value === "object" && !Array.isArray(value); } //# sourceMappingURL=page-markdown.js.map