UNPKG

@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
// 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, })); } };