@telefonica/markdown-confluence-sync
Version:
Creates/updates/deletes Confluence pages based on markdown files in a directory. Supports Mermaid diagrams and per-page configuration using frontmatter metadata. Works great with Docusaurus
93 lines (92 loc) • 3.71 kB
JavaScript
// SPDX-FileCopyrightText: 2024 Telefónica Innovación Digital
// SPDX-License-Identifier: Apache-2.0
import { existsSync, lstatSync } from "node:fs";
import { join } from "node:path";
import { remark } from "remark";
import remarkDirective from "remark-directive";
import remarkFrontmatter from "remark-frontmatter";
import remarkGfm from "remark-gfm";
import remarkParseFrontmatter from "remark-parse-frontmatter";
import { isSupportedFile, readMarkdownAndPatchDocusaurusAdmonitions, } from "../util/files.js";
import { InvalidMarkdownFormatException } from "./errors/InvalidMarkdownFormatException.js";
import { InvalidPathException } from "./errors/InvalidPathException.js";
import { PathNotExistException } from "./errors/PathNotExistException.js";
import remarkReplaceAdmonitions from "./support/remark/remark-replace-admonitions.js";
import remarkValidateFrontmatter from "./support/remark/remark-validate-frontmatter.js";
import { FrontMatterValidator } from "./support/validators/FrontMatterValidator.js";
import { TitleRequiredException } from "./errors/TitleRequiredException.js";
export const DocusaurusDocPage = class DocusaurusDocPage {
_vFile;
_logger;
_metadata;
_contentPreprocessor;
_meta;
constructor(path, options) {
this._logger = options?.logger;
this._contentPreprocessor = options?.contentPreprocessor;
const absolutePath = join(path);
if (!existsSync(absolutePath)) {
throw new PathNotExistException(`Path ${path} does not exist`);
}
if (!lstatSync(path).isFile()) {
throw new InvalidPathException(`Path ${path} is not a file`);
}
if (!isSupportedFile(path)) {
throw new InvalidPathException(`Path ${path} is not a markdown file`);
}
this._metadata = options?.filesMetadata?.find((file) => file.path === absolutePath);
try {
this._vFile = this._parseFile(path);
}
catch (e) {
this._logger?.error(e.toString());
throw new InvalidMarkdownFormatException(`Invalid markdown format: ${path}`, { cause: e });
}
this._getMeta();
}
get isCategory() {
return false;
}
get path() {
return this._vFile.path;
}
get meta() {
return this._meta;
}
get content() {
return this._vFile.toString();
}
_getMeta() {
const frontmatter = this._vFile.data.frontmatter;
const title = this._metadata?.title || frontmatter.title;
const syncToConfluence = this._metadata?.sync !== undefined
? this._metadata.sync
: frontmatter.sync_to_confluence;
const confluenceShortName = this._metadata?.shortName || frontmatter.confluence_short_name;
const confluenceTitle = this._metadata?.title || frontmatter.confluence_title;
const confluencePageId = this._metadata?.id || frontmatter.confluence_page_id;
if (!title) {
throw new TitleRequiredException(this.path);
}
this._meta = {
title,
syncToConfluence,
confluenceShortName,
confluenceTitle,
confluencePageId,
};
}
_parseFile(path) {
return remark()
.use(remarkGfm)
.use(remarkFrontmatter)
.use(remarkDirective)
.use(remarkParseFrontmatter)
.use(remarkValidateFrontmatter, FrontMatterValidator)
.use(remarkReplaceAdmonitions)
.processSync(readMarkdownAndPatchDocusaurusAdmonitions(path, {
logger: this._logger,
contentPreprocessor: this._contentPreprocessor,
}));
}
};