Confluence vers Markdown
Introduction
Voici une méthode pour exporter le contenu des pages confluence en Markdown.
Les exemples utilisés dans cet article sont fait avec Confluence Server 6.4.1 Aucune autre version n’a été essayée.
Pré-requis
- NodeJS
- NPM
- Confluence Server 6.4.1
- confluence-to-markdown
- pandoc
Étape 1 - Installer les dépendances
L’outil utilisé pour convertir l’export confluence vers markdown est pandoc avec le module confluence-to-markdown
voici le lien pour installer l’outil : PANDOC
Ensuite, il faut créer un projet pour être en mesure de lancer les scripts
npm init
npm install --save fs fs-extra path line-reader confluence-to-markdown
Étape 2 - Création des scripts
parser.js
// Author : Tommy Gingras - Studiowebux S.E.N.C
// Description : TBD
// Date : 2020-01-10
"use strict";
const fs = require("fs-extra");
const path = require("path");
let filenames = [];
const BASE_PATH = path.join(__dirname, "docs");
fs.readdir(path.join(BASE_PATH), (err, files) => {
files.forEach((file) => {
if (file.includes(".md")) {
const text = generateText(file);
addTextAtBeginning(text, path.join(BASE_PATH, file));
// be able to remove the first title element in the file
filenames.push(file);
} else {
console.log(`<!> ${file} <!> This is not a .md file`);
}
});
console.log("Done !");
console.log(filenames);
});
function generateText(filename) {
const id = filename.replace(/\.md/g, "");
const title = id
.replace(/_\./g, " ?.")
.replace(/t_s(_|\.|$)/g, "t's ")
.replace(/n_t(_|\.|$)/g, "n't ")
.replace(/_|(\.md)/g, " ");
return `---\nid: ${id}\ntitle: ${title}\n---\n\n`;
}
function addTextAtBeginning(text, file) {
var data = fs.readFileSync(file); //read existing contents into data
if (data.includes("---\nid:")) {
console.log(`<!> ${file} <!> Header already present`);
return;
}
var fd = fs.openSync(file, "w+");
let buffer = Buffer.from(text);
// data.replace(/#\ .*/, "");
fs.writeSync(fd, buffer, 0, buffer.length, 0); //write new data
fs.writeSync(fd, data, 0, data.length, buffer.length); //append old data
fs.close(fd);
}
sitemap.js
// Author : Tommy Gingras - Studiowebux S.E.N.C
// Description : TBD
// Date : 2020-01-10
"use strict";
const fs = require("fs");
const lineReader = require("line-reader");
const path = require("path");
const SITEMAP = path.join("website", "sidebars.json");
const INDEX = path.join("docs", "index.md");
let title;
let link;
let incomplete = false;
let last = {
h1: {},
h2: {},
h3: {},
h4: {},
};
let currentLine;
let lines = [];
lineReader.eachLine(
"./docs/index.md",
function (line) {
if (line.match(/^(\s+)-(.*)/) && !line.match(/-(.*)\)/) && !incomplete) {
// if the line is incomplete (split by an enter)
incomplete = true;
currentLine = line;
return;
} else if (incomplete) {
// append the next line to the last line detected
currentLine += ` ${line.trimLeft()}`;
incomplete = false;
} else if (line.match(/^(\s+)-(.*)/)) {
// The line is complete, it starts with a - and finish with a )
currentLine = line;
} else {
// skip this line...
return;
}
lines.push(currentLine);
},
() => {
let menu = {};
let _model = {};
lines.forEach((line, index) => {
// console.log(line);
title = line.substring(line.indexOf("[") + 1, line.indexOf("]"));
link = line.substring(line.indexOf("(") + 1, line.indexOf(")"));
if (line.match(/^(\s{4})-(.*)/)) {
last.h1 = {
title,
link,
};
_model = [];
menu[title] = _model;
} else if (line.match(/^(\s{8})-(.*)/)) {
last.h2 = {
title,
link,
};
if (lines[index + 1] && lines[index + 1].match(/^(\s{12})-(.*)/)) {
// this entry is a subcategory
_model.push({
type: "subcategory",
label: title,
ids: [],
});
} else {
_model.push(link);
}
} else if (line.match(/^(\s{12})-(.*)/)) {
last.h3 = {
title,
link,
};
// if (title.indexOf("@") === 0) {
// _model
// .find(i => {
// return i.label === last.h2.title;
// })
// .ids.push({ type: "subcategory", label: title, ids: [] });
//
if (title.indexOf("@") === 0) {
return;
} else {
_model
.find((i) => {
return i.label === last.h2.title;
})
.ids.push(link);
}
} else if (line.match(/^(\s{16})-(.*)/)) {
last.h4 = {
title,
link,
};
let _h2 = _model.find((h2) => {
return h2.label === last.h2.title;
});
_h2.ids.push(link);
}
});
fs.writeFileSync(SITEMAP, JSON.stringify(menu, null, 2));
console.log("Done");
}
);
Étape 3 - Exporter un espace confluence
- Choisir HTML comme type d’export
- Choisir HTML pour exporter toutes les pages
- Choisir les pages à exporter
- Choisir Custom puis les pages à exporter
- Cliquer sur ‘here’ pour télécharger le space
Étape 4 - Exécuter les scripts
Décompresser le fichier d’export pour obtenir tous les fichiers HTML de l’espace Confluence.
Étape 4.1 - Convertir les fichiers HTML en Markdown
Les instructions : https://github.com/meridius/confluence-to-markdown#readme
cd node_modules/confluence-to-markdown
npm install
npm run start ../../WJF-4 ../../doc
Selon la structure de vos données, il faut changer le BASE_PATH
const BASE_PATH = path.join(__dirname, "doc", "WJF-4");
Puis retourner au dossier source et lancer la commande du parser
cd ../../
node parser.js
Voici le résultat du parser,
L’image montre bien l’ajout des headers pour fonctionner avec Docusaurus V1.
Maintenant, pour obtenir le menu il faut lancer le script sitemap
Vous pouvez modifier l’emplacement du fichier SITEMAP et INDEX
const SITEMAP = path.join("sidebars.json");
const INDEX = path.join("doc", "WJF-4", "index.md");
node sitemap.js
Conclusion
Voici comment exporter le contenu confluence et le transférer en Markdown pour être utilisé avec Docusaurus V1.