const { Buffer } = require('node:buffer') const debug = require('debug')('metalsmith-tinuage-services') const config = require('./config.js') const fs = require('node:fs') const path = require('path') module.exports = plugin /** * Un plugin pour Metalsmith qui lit une collection de fichiers JSON décrivant * les services de l'association pour composer la page services.html du site. * * @return {Function} */ function plugin () { const Sections = Object.freeze({ OPEN: Symbol('open'), MEMBERS: Symbol('members') }) const PageFiller = { setup: function (page, services) { this.page = page this.registry = services.reduce((registry, service) => { registry[service.section].push(service) return registry }, { [Sections.OPEN]: [], [Sections.MEMBERS]: [] }) return this }, fill: function () { let html = '' html += this.createSection('Services réservés aux adhérents', Sections.MEMBERS) html += this.createSection('Services en libre accès, sans adhésion', Sections.OPEN) this.page.contents = Buffer.concat([ this.page.contents, Buffer.from(html) ]) }, createSection: function (title, section) { let html = '
\n' + '

' + title + '

\n' + '
\n' this.registry[section].forEach((service) => { html += service.html }) html += '
' return html } } const Parser = { /** * Traduit la description JSON du service donné en paramètre en un extrait * HTML. */ parseService: function (service) { let html = '
\n' + '

' + service.title + '

\n' + '

' + service.description + '

\n' if (service.buttons !== undefined) { html += '

\n' service.buttons.forEach((b) => { html += this.createButton(b) }) html += '

' } if (service.softwares !== undefined) { html += '
\n' service.softwares.forEach((s) => { html += this.createSoftwareDescription(s) }) html += '
\n' } if (service.links !== undefined) { html += '

Autres liens :

\n
\n' } html += '
' debug('Parsed ' + service.title + '(' + service.order + ')') service.html = html service.section = service.open ? Sections.OPEN : Sections.MEMBERS return service }, createButton: function (button) { const cls = button.class || '' return '' + button.label + '\n' }, createListLink: function (link) { return '
  • ' + link.label + '
  • \n' }, createSoftwareDescription: function (soft) { let html = '

    ' + soft.description + '

    \n' + '
    ' if (soft.url !== undefined) { html += this.createSoftwareLink('home.svg', 'Page Web', soft.url) } if (soft.sources !== undefined) { html += this.createSoftwareLink('files.svg', 'Sources du logiciel', soft.sources) } soft.licenses.forEach((l) => { html += this.createSoftwareLink('copyright.svg', 'Licence', l.url, l.name) }) html += '
    \n' return html }, createSoftwareLink: function (icon, alt, url, title) { let element = '' return element } } /** * Lit de manière asynchrone l'ensemble des fichiers JSON décrivant les services. * * Seuls les fichiers ayant .json comme extension sont chargés depuis le répertoire fourni. */ function loadServices (root, filenames) { const promises = filenames .filter(f => { return f.indexOf('.json') !== -1 }) .map(function (f) { debug('Loading ' + f) return fs.promises .readFile(path.join(root, f), 'utf8') .then((data) => { return JSON.parse(data) }) }) return Promise.all(promises) } return function (files, metalsmith, done) { const root = path.join(config.paths.projectRoot, 'services') debug('Looking for services in ' + root) fs.readdir(root, (err, filenames) => { if (err) { console.error('%s: %s', root, err) } else { loadServices(root, filenames) .then(function (services) { const p = Object.create(Parser) const parsed = services .sort((a, b) => { return a.order - b.order }) .map((s) => p.parseService(s)) Object.create(PageFiller).setup(files['services.html'], parsed).fill() done() }) .catch(function (err) { console.log(err) }) } }) } }