Zerotask/rust-jungle

View on GitHub
generator.js

Summary

Maintainability
A
1 hr
Test Coverage
import fg from 'fast-glob';
import fs from 'fs';
import { parse } from 'node-html-better-parser';
import { create } from 'xmlbuilder2';
import dotenv from 'dotenv';
dotenv.config();

const fileNameLessonsData = 'lessons.json';
const outputFolder = './static';

const getPages = async () => await fg('src/routes/**/[^__]*.svelte');

const getUrl = (page) => {
    return page
        .replace('src/routes', process.env.VITE_APP_URL)
        .replace('.svelte', '')
        .replace('index', '');
};

const getLessonElement = (page) => {
    const fileContent = fs.readFileSync(page, 'utf8');
    const root = parse(fileContent);

    return root.querySelector('Lesson');
};

const getLessonIndex = (lessonElement) => {
    const indexAttribute = lessonElement.attributes.index;
    let index = 1;
    if (indexAttribute) {
        index = parseInt(indexAttribute, 10);
        if (isNaN(index)) {
            index = parseInt(indexAttribute.slice(1, -1), 10);
        }
    }

    return index;
};

const getLessonTitle = (lessonElement, fileName, index) => {
    const titleAttribute = lessonElement.attributes.title;
    let title;
    if (fileName === 'summary.svelte') {
        title = 'Summary';
    } else if (index === 1) {
        title = `Introduction - ${titleAttribute}`;
    } else {
        title = titleAttribute;
    }

    return title;
};

const writeLessonsJsonFile = (tags, stages, lessons) => {
    fs.writeFileSync(
        `${outputFolder}/${fileNameLessonsData}`,
        JSON.stringify({ tags, stages, lessons })
    );
};

const generateLessonsJson = async () => {
    const startTime = process.hrtime();
    const pages = await getPages();

    let lessonsData = [];
    const stagesData = {};
    const tagsData = new Set();

    pages.forEach((page) => {
        const lessonElement = getLessonElement(page);

        if (!lessonElement) {
            console.info({ page });
            return;
        }

        const url = getUrl(page);
        const pathParts = page.split('/');
        const language = pathParts[2];
        const stage = parseInt(pathParts[4], 10);
        const index = getLessonIndex(lessonElement);
        const title = getLessonTitle(lessonElement, pathParts.pop(), index);
        const summary = lessonElement.attributes.summary;
        const previous = lessonElement.attributes.previous;
        const next = lessonElement.attributes.next;
        const furtherInformationUrls = lessonElement.attributes.furtherInformationUrls?.split(' ');
        const content = lessonElement.structuredText.trim();

        // stages data
        if (index === 1) {
            stagesData[stage] = lessonElement.attributes.title;
        }

        // tags data
        const tags = lessonElement.attributes.tags?.split(' ');
        if (tags) {
            tags.forEach((tag) => tagsData.add(tag));
        }

        lessonsData.push({
            url,
            language,
            stage,
            index,
            title,
            summary,
            tags,
            previous,
            next,
            furtherInformationUrls,
            content
        });
    });

    lessonsData = lessonsData.sort((a, b) => a.index - b.index);
    writeLessonsJsonFile([...tagsData], stagesData, lessonsData);
    const endTime = process.hrtime(startTime);
    console.info(`Generated ${fileNameLessonsData} in: %ds %dms`, endTime[0], endTime[1] / 1000000);
};

const generateSitemapXml = async () => {
    const startTime = process.hrtime();
    const sitemap = create({ version: '1.0' }).ele('urlset', {
        xmlns: 'http://www.sitemaps.org/schemas/sitemap/0.9'
    });

    // Include all svelte files which don't start with two underscores, e. g. __error.svelte
    const pages = await getPages();

    pages.forEach((page) => {
        const url = sitemap.ele('url');
        url.ele('loc').txt(getUrl(page));
        url.ele('changefreq').txt('monthly');
    });

    const fileName = 'sitemap.xml';
    fs.writeFileSync(`${outputFolder}/${fileName}`, sitemap.end({ prettyPrint: true }));

    const endTime = process.hrtime(startTime);
    console.info(`Generated ${fileName} in: %ds %dms`, endTime[0], endTime[1] / 1000000);
};

generateLessonsJson();
generateSitemapXml();