Skip to content

Commit

Permalink
Rearrange code
Browse files Browse the repository at this point in the history
  • Loading branch information
AleksandrHovhannisyan committed Dec 8, 2022
1 parent b1754f3 commit 2db5842
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 65 deletions.
65 changes: 2 additions & 63 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,65 +1,4 @@
const escape = require('lodash/escape');
const minifyHtml = require('@minify-html/node');
const markdownIt = require('markdown-it');
const outdent = require('outdent');
const { parseCode, stringifyAttributes } = require('./utils');
const clsx = require('clsx');

/**
* Higher-order function that takes user configuration options and returns the plugin shortcode.
* @param {import('./typedefs').EleventyPluginCodeDemoOptions} options
*/
const makeCodeDemoShortcode = (options) => {
const sharedIframeAttributes = options.iframeAttributes;

/**
* @param {string} source The children of this shortcode, as Markdown code blocks.
* @param {string} title The title to set on the iframe.
* @param {Record<string, unknown>} props HTML attributes to set on this specific `<iframe>`.
*/
const codeDemoShortcode = (source, title, props = {}) => {
if (!title) {
throw new Error(`${options.name}: you must provide a non-empty title for the iframe.`);
}

// This comes from Nunjucks when passing in keyword arguments; we don't want it to make its way into the output HTML
if (props['__keywords']) {
delete props['__keywords'];
}

const tokens = markdownIt().parse(source);
const html = parseCode(tokens, 'html');
const css = parseCode(tokens, 'css');
const js = parseCode(tokens, 'js');

// Allow users to customize their document structure, given this HTML, CSS, and JS
let srcdoc = options.renderDocument({ html, css, js });
// We have to check this or Buffer.from will throw segfaults
if (srcdoc) {
// Convert all the HTML/CSS/JS into one long string with zero non-essential white space, comments, etc.
srcdoc = minifyHtml.minify(Buffer.from(srcdoc), {
keep_spaces_between_attributes: false,
// Only need to minify these two if they're present
minify_css: !!css,
minify_js: !!js,
});
}
srcdoc = escape(srcdoc);

let iframeAttributes = { ...sharedIframeAttributes, ...props };
const className = clsx(sharedIframeAttributes?.class, props.class);
if (className) {
iframeAttributes.class = className;
}
iframeAttributes = stringifyAttributes(iframeAttributes);

return outdent`<iframe title="${title}" srcdoc="${srcdoc}"${
iframeAttributes ? ` ${iframeAttributes}` : ''
}></iframe>`;
};

return codeDemoShortcode;
};
const { makeCodeDemoShortcode } = require('./utils');

/**
* @param {import('@11ty/eleventy/src/UserConfig')} eleventyConfig
Expand All @@ -70,4 +9,4 @@ const EleventyPluginCodeDemo = (eleventyConfig, options) => {
eleventyConfig.addPairedShortcode(name, makeCodeDemoShortcode({ ...options, name }));
};

module.exports = { makeCodeDemoShortcode, EleventyPluginCodeDemo };
module.exports = { EleventyPluginCodeDemo };
64 changes: 63 additions & 1 deletion src/utils.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
const escape = require('lodash/escape');
const minifyHtml = require('@minify-html/node');
const markdownIt = require('markdown-it');
const outdent = require('outdent');
const clsx = require('clsx');

/**
* Given an array of tokens and a type of token to look up, finds all such matching tokens and returns one
* big string concatenating all of those tokens' content.
Expand All @@ -23,4 +29,60 @@ const stringifyAttributes = (attributeMap) => {
.join(' ');
};

module.exports = { parseCode, stringifyAttributes };
/**
* Higher-order function that takes user configuration options and returns the plugin shortcode.
* @param {import('./typedefs').EleventyPluginCodeDemoOptions} options
*/
const makeCodeDemoShortcode = (options) => {
const sharedIframeAttributes = options.iframeAttributes;

/**
* @param {string} source The children of this shortcode, as Markdown code blocks.
* @param {string} title The title to set on the iframe.
* @param {Record<string, unknown>} props HTML attributes to set on this specific `<iframe>`.
*/
const codeDemoShortcode = (source, title, props = {}) => {
if (!title) {
throw new Error(`${options.name}: you must provide a non-empty title for the iframe.`);
}

// This comes from Nunjucks when passing in keyword arguments; we don't want it to make its way into the output HTML
if (props['__keywords']) {
delete props['__keywords'];
}

const tokens = markdownIt().parse(source);
const html = parseCode(tokens, 'html');
const css = parseCode(tokens, 'css');
const js = parseCode(tokens, 'js');

// Allow users to customize their document structure, given this HTML, CSS, and JS
let srcdoc = options.renderDocument({ html, css, js });
// We have to check this or Buffer.from will throw segfaults
if (srcdoc) {
// Convert all the HTML/CSS/JS into one long string with zero non-essential white space, comments, etc.
srcdoc = minifyHtml.minify(Buffer.from(srcdoc), {
keep_spaces_between_attributes: false,
// Only need to minify these two if they're present
minify_css: !!css,
minify_js: !!js,
});
}
srcdoc = escape(srcdoc);

let iframeAttributes = { ...sharedIframeAttributes, ...props };
const className = clsx(sharedIframeAttributes?.class, props.class);
if (className) {
iframeAttributes.class = className;
}
iframeAttributes = stringifyAttributes(iframeAttributes);

return outdent`<iframe title="${title}" srcdoc="${srcdoc}"${
iframeAttributes ? ` ${iframeAttributes}` : ''
}></iframe>`;
};

return codeDemoShortcode;
};

module.exports = { makeCodeDemoShortcode };
2 changes: 1 addition & 1 deletion src/index.test.js → src/utils.test.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
const { outdent } = require('outdent');
const { makeCodeDemoShortcode } = require('.');
const { makeCodeDemoShortcode } = require('./utils');

describe('makeCodeDemoShortcode', () => {
it('includes html, css, and js', () => {
Expand Down

0 comments on commit 2db5842

Please sign in to comment.