Confluence vers markdown

Introduction

Comment exporter les pages confluence en Markdown.

Les examples utilisés dans cet article sont fait avec Confluence Server 6.4.1
Aucune autre version n'a été essayée.

Pré-requis

É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 les pages

Choisir les pages à exporter

Choisir Custom puis les pages à exporter

Cliquer sur 'here' pour télécharger le space

Cliquer sur Download here

É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 MD

La structure des fichiers

Les instructions : https://github.com/meridius/confluence-to-markdown#readme

cd node_modules/confluence-to-markdown
npm install
npm run start ../../WJF-4 ../../doc
Le dossier avec les fichiers Markdown

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,

Ajout des headers pour fonctionner avec Docusaurus V1

Maintenant, pour obtenir le menu il faut lancer le script sitemap

Vous pouvez modifier le path du fichier SITEMAP et INDEX

const SITEMAP = path.join("sidebars.json");
const INDEX = path.join("doc", "WJF-4", "index.md");
node sitemap.js
Example du Sitemap

Voici comment exporter le contenu confluence et le transférer en Markdown pour être utilisé avec Docusaurus par exemple.

Si vous voulez voir un example plus concret du résultat, la documentation de mon toolbox est disponible ici : WEBUXLAB

Laisser un commentaire