@dinamomx/nuxtent
Version:
Seamlessly use content files in your Nuxt.js sites.
110 lines (102 loc) • 3.7 kB
JavaScript
/**
* Nuxtent v3.2.0
* (c) 2019 César Valadez
* @license MIT
*/
;
Object.defineProperty(exports, '__esModule', { value: true });
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
var matter = _interopDefault(require('gray-matter'));
var loaderUtils = require('loader-utils');
require('diacritics');
var consola = _interopDefault(require('consola'));
require('path');
/* eslint-disable no-useless-escape */
const logger = consola.withScope('nuxt:nuxtent');
function getDirOpts(contentOptions, section) {
// configuration options can be for root files ('/') but regex for section also
// captures closest subsection, so we first check that since you can't configure
// both root files and nested sections
const [, content = null] = contentOptions.find(([folder]) => {
return folder === '/' || folder === section;
}) || [];
return content;
}
function getSection(dirPath) {
// capture '/content/closestSubsection' or '/content'
const match = dirPath.match(/[/\\]content[/\\]([\w\-_\s]+|$)/);
if (match) {
return match[1] === '' ? '/' : match[1];
}
return '/';
}
const insertCodePlugin = (md) => {
const RE = /\s*{([^}]+)}/;
const parseOptions = (str) => {
if (!RE.test(str)) {
return {};
}
const [, options] = RE.exec(str) || ['', ''];
const fn = new Function(`return {${options}}`); // eslint-disable-line no-new-func
return fn();
};
const { fence } = md.renderer.rules;
md.renderer.rules.fence = (tokens, idx, options, env, self) => {
const token = tokens[idx];
const info = parseOptions(token.info);
if (!info.insert) {
return self.renderToken([token], idx, options);
}
const res = fence(tokens, idx, options, env, self);
if (info.insert === 'above') {
return `${token.content}${res}`;
}
if (info.insert === 'below') {
return `${res}${token.content}`;
}
return res;
};
};
const extractPlugin = (md) => {
const RE = /^<(script|style)(?=(\s|>|$))/i;
md.renderer.rules.html_block = (tokens, idx, options, env) => {
const content = tokens[idx].content;
const hoistedTags = env.hoistedTags || (env.hoistedTags = []);
if (RE.test(content.trim())) {
hoistedTags.push(content);
return '';
}
return content;
};
};
function nuxtentLoader(source) {
const moduleOpts = loaderUtils.getOptions(this);
const content = moduleOpts.content;
const section = getSection(this.context);
const dirOpts = getDirOpts(content, section);
if (!dirOpts) {
logger.debug(`The folder ${section} is not configured in nuxtent and therefore ignored`);
return;
}
const [, fileName = ''] = this.resourcePath.match(/[/\\]content([/\\\w\-_]*)(\.comp\.md$)?|$/) || [];
if (!fileName) {
this.emitError(new Error('The resource is not a markdown file'));
}
if (!dirOpts.markdown.parser) {
return this.emitError(new Error('Could not found markdown parser'));
}
const frontmatter = matter(source);
const env = {
hoistedTags: []
};
const md = dirOpts.markdown.parser;
// We do need html
md.set({ html: true });
md.use(extractPlugin);
md.use(insertCodePlugin);
const html = md.render(frontmatter.content, env);
const component = `<template><div class="nuxtent-content">${html}</div></template>
${env.hoistedTags ? env.hoistedTags.join('\n\n') : ''}`;
return component;
}
exports.default = nuxtentLoader;