@archer-edu/dxp-directus-cli
Version:
313 lines • 11.5 kB
JavaScript
;
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