jkroepke/featurebook-js

View on GitHub
packages/featurebook-serve/lib/featurebook-serve.js

Summary

Maintainability
B
5 hrs
Test Coverage
const path = require('path');
const express = require('express');
const api = require('@jkroepke/featurebook-api');
const markdown = require('@jkroepke/featurebook-markdown');

const { imageRenderer, linkRenderer } = require('./helper');

// --- REST API ---
// http://localhost:3000/api/rest/raw/assets/images/hello_world.png
// http://localhost:3000/api/rest/metadata
// http://localhost:3000/api/rest/summary
// http://localhost:3000/api/rest/spec/tree
// http://localhost:3000/api/rest/feature/hello_world.feature
// http://localhost:3000/api/rest/feature/non_technical%2Fload_testing.feature
// ----------------

const serve = async (specDir, port) => {
  const app = express();

  const markdownOptions = {
    imageRenderer,
    linkRenderer,
  };

  // serve static files from the `public` folder
  app.use('/', express.static(path.join(__dirname, '..', 'public')));

  // serve static raw files from the specification source dir directory
  app.use('/api/rest/raw/', express.static(specDir, {
    index: false,
  }));

  app.get('/api/rest/metadata', async (req, res, next) => {
    try {
      const metadata = await api.readMetadata(specDir);

      return res.send(metadata);
    } catch (error) {
      return next(error);
    }
  });

  // returns parsed summary or 404 if SUMMARY.md is not present
  app.get('/api/rest/summary/:path?', async (req, res, next) => {
    const summaryDir = req.params.path ? path.join(specDir, req.params.path) : specDir;
    try {
      const summary = await api.readSummary(summaryDir);

      if (summary === null) {
        return res.status(404).end();
      }

      return res.send(markdown.render(summary, markdownOptions));
    } catch (error) {
      return next(error);
    }
  });

  app.get('/api/rest/spec/tree', async (req, res, next) => {
    try {
      const specTree = await api.readSpecTree(specDir);
      return res.send(specTree);
    } catch (error) {
      return next(error);
    }
  });

  app.get('/api/rest/feature/:path', async (req, res) => {
    const responseBody = {};

    try {
      const features = await api.readFeatures(path.join(specDir, req.params.path));

      responseBody.status = 'success';
      responseBody.data = await markdown.descriptionMarkdownToHTML(features, markdownOptions);
    } catch (e) {
      responseBody.status = 'error';
      responseBody.message = `Unable to parse the feature file: ${e}`;
    } finally {
      res.send(responseBody);
    }
  });

  // eslint-disable-next-line no-unused-vars
  app.use((err, req, res, next) => {
    console.error(err.stack);
    res.status(500).send({ error: err.message });
  });

  await app.listen(port);

  return app;
};

module.exports = serve;
serve.$imageRenderer = imageRenderer;
serve.$linkRenderer = linkRenderer;