@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
114 lines (113 loc) • 4.24 kB
JavaScript
// SPDX-FileCopyrightText: 2024 Telefónica Innovación Digital
// SPDX-License-Identifier: Apache-2.0
import { basename, dirname, join } from "node:path";
import { globSync } from "glob";
import { readSync, toVFile } from "to-vfile";
import { PathNotExistException } from "../pages/errors/PathNotExistException.js";
/**
* Checked if file is valid in docusaurus
* @param path - Page path
* @returns {boolean}
*/
export function isValidFile(path) {
return isSupportedFile(path) && isNotIndexFile(path);
}
/**
* Check if file ended with md or mdx
* @param path - Page path
* @returns {boolean}
*/
export function isSupportedFile(path) {
return /mdx?$/.test(path);
}
/**
* Check if file is not an index file
* index files are the following:
* - index.md
* - index.mdx
* - README.md
* - README.mdx
* - [directory-name].md
* - [directory-name].mdx
* @param path - Page path
* @returns {boolean}
*/
export function isNotIndexFile(path) {
const dirnamePath = basename(dirname(path));
const pattern = buildIndexFileRegExp("", dirnamePath);
return !pattern.test(path);
}
/**
* Replace docusaurus admonitions titles to a valid remark-directive
* @param {string} path - Path to the docs directory
* @param options - Options with {LoggerInterface} logger
* @returns {VFile} - File
*/
export function readMarkdownAndPatchDocusaurusAdmonitions(path, options) {
const file = toVFile(readSync(path));
// HACK: fix docusaurus directive syntax
// Docusaurus directive syntax is not compatible with remark-directive.
// Docusaurus allows title following directive type, but remark-directive does not.
// So, we replace `:::type title` to `:::type[title]` here.
const fileContent = file.value.toString();
const processedContent = options?.contentPreprocessor
? options.contentPreprocessor(fileContent, path)
: fileContent;
file.value = processedContent.replace(/^:::([a-z]+) +(.+)$/gm, (_match, type, title) => {
options?.logger?.debug(`Fix docusaurus directive syntax: "${_match}" => ":::${type}[${title}]"`);
return `:::${type}[${title}]`;
});
return file;
}
/**
* Search for index file in the path
* @param {string} path - Path to the docs directory
* @param options - Options with {LoggerInterface} logger
* @returns {string} - Index file path
*/
export function getIndexFile(path, options) {
const indexFilesGlob = `{index,README,Readme,${basename(path)}}.{md,mdx}`;
const indexFilesFounded = globSync(indexFilesGlob, { cwd: path });
if (indexFilesFounded.length === 0) {
throw new PathNotExistException(`Index file does not exist in this path ${path}`);
}
if (indexFilesFounded.length > 1) {
options?.logger?.warn(`Multiple index files found in ${basename(path)} directory. Using ${indexFilesFounded[0]} as index file. Ignoring the rest.`);
}
return join(path, indexFilesFounded[0]);
}
/**
* Search for index file in the path from a list of paths
* @param {string} path - Path to search
* @param {string[]} paths - Available paths
* @returns {string} - Index file path
*/
export function getIndexFileFromPaths(path, paths) {
const indexFiles = [
"index.md",
"index.mdx",
"README.md",
"Readme.md",
"README.mdx",
"Readme.mdx",
`${basename(path)}.md`,
`${basename(path)}.mdx`,
];
const indexFilesFounded = indexFiles.find((indexFile) => paths.includes(join(path, indexFile)));
// This should never happen, because we are checking if the path exists before
// istanbul ignore next
if (!indexFilesFounded)
throw new PathNotExistException(`Index file does not exist in this path ${path}`);
return join(path, indexFilesFounded);
}
/**
* Build index file regexp
* @param sep - Separator
* @param dirnamePath - Directory name
* @returns {RegExp} - RegExp to match with any index file
*/
export function buildIndexFileRegExp(sep, dirnamePath) {
//HACK Use this check to correct an irregular expression when executing unit tests in windows when using parentheses.
const pathSep = sep === "\\" ? "\\\\" : sep;
return new RegExp(pathSep + `(index|README|${dirnamePath}).mdx?$`);
}