UNPKG

@dinamomx/nuxtent

Version:

Seamlessly use content files in your Nuxt.js sites.

110 lines (102 loc) 3.7 kB
/** * Nuxtent v3.2.0 * (c) 2019 César Valadez * @license MIT */ 'use strict'; 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;