Files
freeCodeCamp/tools/challenge-parser/parser/plugins/add-interactive-elements.js
2025-10-24 15:12:00 +02:00

74 lines
1.9 KiB
JavaScript

const { root } = require('mdast-builder');
const find = require('unist-util-find');
const { isEmpty } = require('lodash');
const { getFilenames } = require('./utils/get-file-visitor');
const { getSection, isMarker } = require('./utils/get-section');
const mdastToHTML = require('./utils/mdast-to-html');
function plugin() {
return transformer;
function transformer(tree, file) {
const interactiveNodes = getSection(tree, `--interactive--`, 1);
const subSection = find(root(interactiveNodes), isMarker);
if (subSection) {
throw Error(
`The --interactive-- section should not have any subsections. Found subsection ${subSection.children[0].value}`
);
}
if (!isEmpty(interactiveNodes)) {
const nodules =
interactiveNodes.map(node => {
if (
node.type === 'containerDirective' &&
node.name === 'interactive_editor'
) {
return {
type: 'interactiveEditor',
data: getFiles(node.children)
};
} else {
const paragraph = mdastToHTML([node]);
return {
type: 'paragraph',
data: paragraph
};
}
}) ?? [];
file.data.nodules = nodules;
}
}
}
function getFiles(filesNodes) {
const invalidNode = filesNodes.find(node => node.type !== 'code');
if (invalidNode) {
throw Error('The :::interactive_editor should only contain code blocks.');
}
// TODO: refactor into two steps, 1) count languages, 2) map to files
const counts = {};
return filesNodes.map(node => {
counts[node.lang] = counts[node.lang] ? counts[node.lang] + 1 : 1;
const contentsHtml = mdastToHTML([node]);
const out = {
contents: node.value,
ext: node.lang,
name:
getFilenames(node.lang) +
(counts[node.lang] ? `-${counts[node.lang]}` : ''),
contentsHtml
};
return out;
});
}
module.exports = plugin;