From 5fbaec9ea8c8d192f66c1d8ee315d9e802702110 Mon Sep 17 00:00:00 2001 From: "Queen Vinyl Da.i'gyu-Kazotetsu" Date: Mon, 12 Sep 2022 12:38:23 -0700 Subject: [PATCH] Convert to ESM (#880) * Convert to ESM * Add style-loader * Use my fork of babel-plugin-prismjs for now * Use correct branch * Convert lib/ to ESM * Fix __dirname references * Convert mdn-bob to async * Ensure Browserify can handle ES modules * Convert tests to ESM * Fix converted files --- __tests__/console-utils.test.js | 2 +- __tests__/processor.test.js | 2 +- editor/js/css-examples-libs.js | 2 +- editor/js/editable-css.js | 10 +- editor/js/editable-js.js | 12 +- editor/js/editable-wat.js | 15 +- editor/js/editor-libs/clippy.js | 102 ++-- editor/js/editor-libs/console-utils.js | 270 +++++----- editor/js/editor-libs/console.js | 15 +- editor/js/editor-libs/css-editor-utils.js | 128 ++--- editor/js/editor-libs/events.js | 97 ++-- editor/js/editor-libs/feature-detector.js | 28 +- editor/js/editor-libs/mce-utils.js | 158 +++--- editor/js/editor-libs/shadow-output.js | 2 +- editor/js/editor-libs/tabby.js | 190 +++---- editor/js/editor-libs/template-utils.js | 139 ++--- editor/js/editor.js | 19 +- ...eer.config.js => jest-puppeteer.config.cjs | 0 lib/bundler.js | 36 +- lib/config.js | 9 +- lib/mdn-bob.js | 71 ++- lib/pageBuilder.js | 29 +- lib/pageBuilderUtils.js | 305 +++++------ lib/processor.js | 23 +- lib/tabbedPageBuilder.js | 13 +- lib/utils.js | 25 +- package-lock.json | 504 +++++++++++++++++- package.json | 8 +- webpack.config.js | 11 +- 29 files changed, 1335 insertions(+), 890 deletions(-) rename jest-puppeteer.config.js => jest-puppeteer.config.cjs (100%) diff --git a/__tests__/console-utils.test.js b/__tests__/console-utils.test.js index dabab997c..6aae50199 100644 --- a/__tests__/console-utils.test.js +++ b/__tests__/console-utils.test.js @@ -1,4 +1,4 @@ -const consoleUtils = require("../editor/js/editor-libs/console-utils"); +import * as consoleUtils from "../editor/js/editor-libs/console-utils"; describe("console utils", () => { describe("formatOutput", () => { diff --git a/__tests__/processor.test.js b/__tests__/processor.test.js index 19a5c1217..1184b113e 100644 --- a/__tests__/processor.test.js +++ b/__tests__/processor.test.js @@ -1,4 +1,4 @@ -const processor = require("../lib/processor"); +import * as processor from "../lib/processor"; describe("processor", () => { describe("preprocessHTML", () => { diff --git a/editor/js/css-examples-libs.js b/editor/js/css-examples-libs.js index 4a8a15b13..271db0d28 100644 --- a/editor/js/css-examples-libs.js +++ b/editor/js/css-examples-libs.js @@ -1 +1 @@ -const Prism = require("prismjs"); +import Prism from "prismjs"; diff --git a/editor/js/editable-css.js b/editor/js/editable-css.js index 39502216a..d852e2a5b 100644 --- a/editor/js/editable-css.js +++ b/editor/js/editable-css.js @@ -1,10 +1,8 @@ -(function () { - "use strict"; - - var clippy = require("./editor-libs/clippy"); - var mceEvents = require("./editor-libs/events"); - var mceUtils = require("./editor-libs/mce-utils"); +import * as clippy from "./editor-libs/clippy.js"; +import * as mceEvents from "./editor-libs/events.js"; +import * as mceUtils from "./editor-libs/mce-utils.js"; +(function () { var exampleChoiceList = document.getElementById("example-choice-list"); var exampleChoices = exampleChoiceList.querySelectorAll(".example-choice"); var editorWrapper = document.getElementById("editor-wrapper"); diff --git a/editor/js/editable-js.js b/editor/js/editable-js.js index 10d6456a2..f8afca870 100644 --- a/editor/js/editable-js.js +++ b/editor/js/editable-js.js @@ -1,11 +1,9 @@ -(function () { - "use strict"; - - var featureDetector = require("./editor-libs/feature-detector.js"); - var mceConsole = require("./editor-libs/console"); - var mceEvents = require("./editor-libs/events.js"); - var mceUtils = require("./editor-libs/mce-utils"); +import * as featureDetector from "./editor-libs/feature-detector.js"; +import mceConsole from "./editor-libs/console.js"; +import * as mceEvents from "./editor-libs/events.js"; +import * as mceUtils from "./editor-libs/mce-utils.js"; +(function () { var codeBlock = document.getElementById("static-js"); var exampleFeature = codeBlock.dataset["feature"]; var execute = document.getElementById("execute"); diff --git a/editor/js/editable-wat.js b/editor/js/editable-wat.js index 66d459d63..08c842e99 100644 --- a/editor/js/editable-wat.js +++ b/editor/js/editable-wat.js @@ -1,11 +1,10 @@ -(function () { - "use strict"; - - var featureDetector = require("./editor-libs/feature-detector.js"); - var mceConsole = require("./editor-libs/console"); - var mceEvents = require("./editor-libs/events.js"); - var mceUtils = require("./editor-libs/mce-utils"); +import * as featureDetector from "./editor-libs/feature-detector.js"; +import mceConsole from "./editor-libs/console.js"; +import * as mceEvents from "./editor-libs/events.js"; +import * as mceUtils from "./editor-libs/mce-utils.js"; +import wabtConstructor from "wabt"; +(function () { var watCodeBlock = document.getElementById("static-wat"); var jsCodeBlock = document.getElementById("static-js"); var exampleFeature = watCodeBlock.dataset["feature"]; @@ -13,7 +12,7 @@ var liveContainer = ""; var output = document.querySelector("#console code"); var reset = document.getElementById("reset"); - var wabtInitialized = require("wabt")(); + var wabtInitialized = wabtConstructor(); var tabContainer = document.getElementById("tab-container"); var tabs = tabContainer.querySelectorAll("button[role='tab']"); diff --git a/editor/js/editor-libs/clippy.js b/editor/js/editor-libs/clippy.js index 36361cbb8..0c019a16e 100644 --- a/editor/js/editor-libs/clippy.js +++ b/editor/js/editor-libs/clippy.js @@ -1,5 +1,5 @@ -var mceUtils = require("./mce-utils"); -var Clipboard = require("clipboard"); +import * as mceUtils from "./mce-utils.js"; +import Clipboard from "clipboard"; /** * Positions the copy to clipboard success message based on the @@ -8,7 +8,6 @@ var Clipboard = require("clipboard"); * @param {Object} msgContainer - The feedback message container */ function setClippyPosition(clippyEvent, msgContainer) { - "use strict"; var trigger = clippyEvent.trigger; var triggerParent = trigger.offsetParent; /* calculate the base top offset by combining the top @@ -23,60 +22,57 @@ function setClippyPosition(clippyEvent, msgContainer) { msgContainer.style.left = positionLeft; } -module.exports = { - /** - * Initialise clipboard.js, and setup success handler - */ - addClippy: function () { - "use strict"; - var clipboard = new Clipboard(".copy", { - target: function (clippyButton) { - var targetAttr = clippyButton.dataset.clipboardTarget; - if (targetAttr) { - // The attribute will override the automated target selection - return document.querySelector(targetAttr); - } else { - // Get its parent until it finds an example choice - var choiceElem = mceUtils.findParentChoiceElem(clippyButton); - // Use the first code element to prevent extra text - var firstCodeElem = choiceElem.getElementsByTagName("code")[0]; - return firstCodeElem; - } - }, - }); +/** + * Initialise clipboard.js, and setup success handler + */ +export function addClippy() { + var clipboard = new Clipboard(".copy", { + target: function (clippyButton) { + var targetAttr = clippyButton.dataset.clipboardTarget; + if (targetAttr) { + // The attribute will override the automated target selection + return document.querySelector(targetAttr); + } else { + // Get its parent until it finds an example choice + var choiceElem = mceUtils.findParentChoiceElem(clippyButton); + // Use the first code element to prevent extra text + var firstCodeElem = choiceElem.getElementsByTagName("code")[0]; + return firstCodeElem; + } + }, + }); - clipboard.on("success", function (event) { - var msgContainer = document.getElementById("user-message"); + clipboard.on("success", function (event) { + var msgContainer = document.getElementById("user-message"); - msgContainer.classList.add("show"); - msgContainer.setAttribute("aria-hidden", false); + msgContainer.classList.add("show"); + msgContainer.setAttribute("aria-hidden", false); - setClippyPosition(event, msgContainer); + setClippyPosition(event, msgContainer); - window.setTimeout(function () { - msgContainer.classList.remove("show"); - msgContainer.setAttribute("aria-hidden", true); - }, 1000); + window.setTimeout(function () { + msgContainer.classList.remove("show"); + msgContainer.setAttribute("aria-hidden", true); + }, 1000); - event.clearSelection(); - }); - }, - /** - * Hides all instances of the clippy button, then shows - * the button in the container element passed in - * @param {Object} container - The container containing the button to show - */ - toggleClippy: function (container) { - "use strict"; - var activeClippy = container.querySelector(".copy"); - var clippyButtons = document.querySelectorAll(".copy"); + event.clearSelection(); + }); +} - for (var i = 0, l = clippyButtons.length; i < l; i++) { - clippyButtons[i].classList.add("hidden"); - clippyButtons[i].setAttribute("aria-hidden", true); - } +/** + * Hides all instances of the clippy button, then shows + * the button in the container element passed in + * @param {Object} container - The container containing the button to show + */ +export function toggleClippy(container) { + var activeClippy = container.querySelector(".copy"); + var clippyButtons = document.querySelectorAll(".copy"); + + for (var i = 0, l = clippyButtons.length; i < l; i++) { + clippyButtons[i].classList.add("hidden"); + clippyButtons[i].setAttribute("aria-hidden", true); + } - activeClippy.classList.remove("hidden"); - activeClippy.setAttribute("aria-hidden", false); - }, -}; + activeClippy.classList.remove("hidden"); + activeClippy.setAttribute("aria-hidden", false); +} diff --git a/editor/js/editor-libs/console-utils.js b/editor/js/editor-libs/console-utils.js index 7136a7be0..a24449390 100644 --- a/editor/js/editor-libs/console-utils.js +++ b/editor/js/editor-libs/console-utils.js @@ -1,161 +1,157 @@ -module.exports = { - /** - * Formats arrays: - * - quotes around strings in arrays - * - square brackets around arrays - * - adds commas appropriately (with spacing) - * designed to be used recursively - * @param {any} input - The output to log. - * @returns Formatted output as a string. - */ - formatArray: function (input) { - "use strict"; - var output = ""; - for (var i = 0, l = input.length; i < l; i++) { - if (typeof input[i] === "string") { - output += '"' + input[i] + '"'; - } else if (Array.isArray(input[i])) { - output += "Array ["; - output += this.formatArray(input[i]); - output += "]"; - } else { - output += this.formatOutput(input[i]); - } +/** + * Formats arrays: + * - quotes around strings in arrays + * - square brackets around arrays + * - adds commas appropriately (with spacing) + * designed to be used recursively + * @param {any} input - The output to log. + * @returns Formatted output as a string. + */ +export function formatArray(input) { + var output = ""; + for (var i = 0, l = input.length; i < l; i++) { + if (typeof input[i] === "string") { + output += '"' + input[i] + '"'; + } else if (Array.isArray(input[i])) { + output += "Array ["; + output += formatArray(input[i]); + output += "]"; + } else { + output += formatOutput(input[i]); + } - if (i < input.length - 1) { - output += ", "; - } + if (i < input.length - 1) { + output += ", "; } - return output; - }, - /** - * Formats objects: - * ArrayBuffer, DataView, SharedArrayBuffer, - * Int8Array, Int16Array, Int32Array, - * Uint8Array, Uint16Array, Uint32Array, - * Uint8ClampedArray, Float32Array, Float64Array - * Symbol - * @param {any} input - The output to log. - * @returns Formatted output as a string. - */ - formatObject: function (input) { - ("use strict"); - var bufferDataViewRegExp = /^(ArrayBuffer|SharedArrayBuffer|DataView)$/; - var complexArrayRegExp = - /^(Int8Array|Int16Array|Int32Array|Uint8Array|Uint16Array|Uint32Array|Uint8ClampedArray|Float32Array|Float64Array|BigInt64Array|BigUint64Array)$/; + } + return output; +} - var objectName = input.constructor ? input.constructor.name : input; +/** + * Formats objects: + * ArrayBuffer, DataView, SharedArrayBuffer, + * Int8Array, Int16Array, Int32Array, + * Uint8Array, Uint16Array, Uint32Array, + * Uint8ClampedArray, Float32Array, Float64Array + * Symbol + * @param {any} input - The output to log. + * @returns Formatted output as a string. + */ +export function formatObject(input) { + ("use strict"); + var bufferDataViewRegExp = /^(ArrayBuffer|SharedArrayBuffer|DataView)$/; + var complexArrayRegExp = + /^(Int8Array|Int16Array|Int32Array|Uint8Array|Uint16Array|Uint32Array|Uint8ClampedArray|Float32Array|Float64Array|BigInt64Array|BigUint64Array)$/; - if (objectName === "String") { - // String object - return `String { "${input.valueOf()}" }`; - } + var objectName = input.constructor ? input.constructor.name : input; - if (input === JSON) { - // console.log(JSON) is outputed as "JSON {}" in browser console - return `JSON {}`; - } + if (objectName === "String") { + // String object + return `String { "${input.valueOf()}" }`; + } - if (objectName.match && objectName.match(bufferDataViewRegExp)) { - return objectName + " {}"; - } + if (input === JSON) { + // console.log(JSON) is outputed as "JSON {}" in browser console + return `JSON {}`; + } - if (objectName.match && objectName.match(complexArrayRegExp)) { - var arrayLength = input.length; + if (objectName.match && objectName.match(bufferDataViewRegExp)) { + return objectName + " {}"; + } - if (arrayLength > 0) { - return objectName + " [" + this.formatArray(input) + "]"; - } else { - return objectName + " []"; - } - } + if (objectName.match && objectName.match(complexArrayRegExp)) { + var arrayLength = input.length; - if (objectName === "Symbol" && input !== undefined) { - return input.toString(); + if (arrayLength > 0) { + return objectName + " [" + formatArray(input) + "]"; + } else { + return objectName + " []"; } + } - if (objectName === "Object") { - var formattedChild = ""; - var start = true; - for (var key in input) { - if (input.hasOwnProperty(key)) { - if (start) { - start = false; - } else { - formattedChild = formattedChild + ", "; - } - formattedChild = - formattedChild + key + ": " + this.formatOutput(input[key]); - } - } - return objectName + " { " + formattedChild + " }"; - } + if (objectName === "Symbol" && input !== undefined) { + return input.toString(); + } - // Special object created with `OrdinaryObjectCreate(null)` returned by, for - // example, named capture groups in https://mzl.la/2RERfQL - // @see https://github.com/mdn/bob/issues/574#issuecomment-858213621 - if (!input.constructor && !input.prototype) { - var formattedChild = ""; - var start = true; - for (var key in input) { + if (objectName === "Object") { + var formattedChild = ""; + var start = true; + for (var key in input) { + if (input.hasOwnProperty(key)) { if (start) { start = false; } else { formattedChild = formattedChild + ", "; } - formattedChild = - formattedChild + key + ": " + this.formatOutput(input[key]); + formattedChild = formattedChild + key + ": " + formatOutput(input[key]); } - return "Object { " + formattedChild + " }"; } + return objectName + " { " + formattedChild + " }"; + } - return input; - }, - /** - * Formats output to indicate its type: - * - quotes around strings - * - single quotes around strings containing double quotes - * - square brackets around arrays - * (also copes with arrays of arrays) - * does NOT detect Int32Array etc - * @param {any} input - The output to log. - * @returns Formatted output as a string. - */ - formatOutput: function (input) { - "use strict"; - if (input === undefined || input === null || typeof input === "boolean") { - return String(input); - } else if (typeof input === "number") { - // Negative zero - if (Object.is(input, -0)) { - return "-0"; - } - return String(input); - } else if (typeof input === "bigint") { - return String(input) + "n"; - } else if (typeof input === "string") { - // string literal - if (input.includes('"')) { - return "'" + input + "'"; + // Special object created with `OrdinaryObjectCreate(null)` returned by, for + // example, named capture groups in https://mzl.la/2RERfQL + // @see https://github.com/mdn/bob/issues/574#issuecomment-858213621 + if (!input.constructor && !input.prototype) { + var formattedChild = ""; + var start = true; + for (var key in input) { + if (start) { + start = false; } else { - return '"' + input + '"'; + formattedChild = formattedChild + ", "; } - } else if (Array.isArray(input)) { - // check the contents of the array - return "Array [" + this.formatArray(input) + "]"; + formattedChild = formattedChild + key + ": " + formatOutput(input[key]); + } + return "Object { " + formattedChild + " }"; + } + + return input; +} + +/** + * Formats output to indicate its type: + * - quotes around strings + * - single quotes around strings containing double quotes + * - square brackets around arrays + * (also copes with arrays of arrays) + * does NOT detect Int32Array etc + * @param {any} input - The output to log. + * @returns Formatted output as a string. + */ +export function formatOutput(input) { + if (input === undefined || input === null || typeof input === "boolean") { + return String(input); + } else if (typeof input === "number") { + // Negative zero + if (Object.is(input, -0)) { + return "-0"; + } + return String(input); + } else if (typeof input === "bigint") { + return String(input) + "n"; + } else if (typeof input === "string") { + // string literal + if (input.includes('"')) { + return "'" + input + "'"; } else { - return this.formatObject(input); + return '"' + input + '"'; } - }, - /** - * Writes the provided content to the editor’s output area - * @param {String} content - The content to write to output - */ - writeOutput: function (content) { - "use strict"; - var output = document.querySelector("#console code"); - var outputContent = output.textContent; - var newLogItem = "> " + content + "\n"; - output.textContent = outputContent + newLogItem; - }, -}; + } else if (Array.isArray(input)) { + // check the contents of the array + return "Array [" + formatArray(input) + "]"; + } else { + return formatObject(input); + } +} + +/** + * Writes the provided content to the editor’s output area + * @param {String} content - The content to write to output + */ +export function writeOutput(content) { + var output = document.querySelector("#console code"); + var outputContent = output.textContent; + var newLogItem = "> " + content + "\n"; + output.textContent = outputContent + newLogItem; +} diff --git a/editor/js/editor-libs/console.js b/editor/js/editor-libs/console.js index cc088b9a0..cfb3a64b4 100644 --- a/editor/js/editor-libs/console.js +++ b/editor/js/editor-libs/console.js @@ -1,13 +1,12 @@ -// Thanks in part to https://stackoverflow.com/questions/11403107/capturing-javascript-console-log -module.exports = function () { - "use strict"; +import { writeOutput, formatOutput } from "./console-utils.js"; - var consoleUtils = require("./console-utils"); +// Thanks in part to https://stackoverflow.com/questions/11403107/capturing-javascript-console-log +export default function () { var originalConsoleLogger = console.log; // eslint-disable-line no-console var originalConsoleError = console.error; console.error = function (loggedItem) { - consoleUtils.writeOutput(loggedItem); + writeOutput(loggedItem); // do not swallow console.error originalConsoleError.apply(console, arguments); }; @@ -16,12 +15,12 @@ module.exports = function () { console.log = function () { var formattedList = []; for (var i = 0, l = arguments.length; i < l; i++) { - var formatted = consoleUtils.formatOutput(arguments[i]); + var formatted = formatOutput(arguments[i]); formattedList.push(formatted); } var output = formattedList.join(" "); - consoleUtils.writeOutput(output); + writeOutput(output); // do not swallow console.log originalConsoleLogger.apply(console, arguments); }; -}; +} diff --git a/editor/js/editor-libs/css-editor-utils.js b/editor/js/editor-libs/css-editor-utils.js index 600c5f54d..18249c5b4 100644 --- a/editor/js/editor-libs/css-editor-utils.js +++ b/editor/js/editor-libs/css-editor-utils.js @@ -1,75 +1,77 @@ -module.exports = { - editTimer: undefined, - applyCode: function (code, choice, targetElement) { - // http://regexr.com/3fvik - var cssCommentsMatch = /(\/\*)[\s\S]+(\*\/)/g; - var element = targetElement || document.getElementById("example-element"); +export let editTimer = undefined; - // strip out any CSS comments before applying the code - code.replace(cssCommentsMatch, ""); +export function applyCode(code, choice, targetElement) { + // http://regexr.com/3fvik + var cssCommentsMatch = /(\/\*)[\s\S]+(\*\/)/g; + var element = targetElement || document.getElementById("example-element"); - element.style.cssText = code; + // strip out any CSS comments before applying the code + code.replace(cssCommentsMatch, ""); - // clear any existing timer - clearTimeout(this.editTimer); - /* Start a new timer. This will ensure that the state is + element.style.cssText = code; + + // clear any existing timer + clearTimeout(editTimer); + /* Start a new timer. This will ensure that the state is not marked as invalid, until the user has stopped typing for 500ms */ - this.editTimer = setTimeout(function () { - if (!element.style.cssText) { - choice.parentNode.classList.add("invalid"); - } else { - choice.parentNode.classList.remove("invalid"); - } - }, 500); - }, - /** - * Sets the choice to selected, changes the nested code element to be editable, - * turns of spellchecking. Lastly, it applies the code to the example element - * by calling applyCode. - * @param {Object} choice - The selected `example-choice` element - */ - choose: function (choice) { - var codeBlock = choice.querySelector("code"); + editTimer = setTimeout(function () { + if (!element.style.cssText) { + choice.parentNode.classList.add("invalid"); + } else { + choice.parentNode.classList.remove("invalid"); + } + }, 500); +} - choice.classList.add("selected"); +/** + * Sets the choice to selected, changes the nested code element to be editable, + * turns of spellchecking. Lastly, it applies the code to the example element + * by calling applyCode. + * @param {Object} choice - The selected `example-choice` element + */ +export function choose(choice) { + var codeBlock = choice.querySelector("code"); - codeBlock.setAttribute("contentEditable", true); - codeBlock.setAttribute("spellcheck", false); + choice.classList.add("selected"); - module.exports.applyCode(codeBlock.textContent, choice); - }, - /** - * Resets the default example to visible but, only if it is currently hidden - */ - resetDefault: function () { - var defaultExample = document.getElementById("default-example"); - var output = document.getElementById("output"); + codeBlock.setAttribute("contentEditable", true); + codeBlock.setAttribute("spellcheck", false); - // only reset to default if the default example is hidden - if (defaultExample.classList.contains("hidden")) { - var sections = output.querySelectorAll("section"); - // loop over all sections and set to hidden - for (var i = 0, l = sections.length; i < l; i++) { - sections[i].classList.add("hidden"); - sections[i].setAttribute("aria-hidden", true); - } - // show the default example - defaultExample.classList.remove("hidden"); - defaultExample.setAttribute("aria-hidden", false); - } + applyCode(codeBlock.textContent, choice); +} - module.exports.resetUIState(); - }, - /** - * Resets the UI state by deselcting all example choice - */ - resetUIState: function () { - var exampleChoiceList = document.getElementById("example-choice-list"); - var exampleChoices = exampleChoiceList.querySelectorAll(".example-choice"); +/** + * Resets the default example to visible but, only if it is currently hidden + */ +export function resetDefault() { + var defaultExample = document.getElementById("default-example"); + var output = document.getElementById("output"); - for (var i = 0, l = exampleChoices.length; i < l; i++) { - exampleChoices[i].classList.remove("selected"); + // only reset to default if the default example is hidden + if (defaultExample.classList.contains("hidden")) { + var sections = output.querySelectorAll("section"); + // loop over all sections and set to hidden + for (var i = 0, l = sections.length; i < l; i++) { + sections[i].classList.add("hidden"); + sections[i].setAttribute("aria-hidden", true); } - }, -}; + // show the default example + defaultExample.classList.remove("hidden"); + defaultExample.setAttribute("aria-hidden", false); + } + + resetUIState(); +} + +/** + * Resets the UI state by deselcting all example choice + */ +export function resetUIState() { + var exampleChoiceList = document.getElementById("example-choice-list"); + var exampleChoices = exampleChoiceList.querySelectorAll(".example-choice"); + + for (var i = 0, l = exampleChoices.length; i < l; i++) { + exampleChoices[i].classList.remove("selected"); + } +} diff --git a/editor/js/editor-libs/events.js b/editor/js/editor-libs/events.js index 25390cc96..639533b00 100644 --- a/editor/js/editor-libs/events.js +++ b/editor/js/editor-libs/events.js @@ -1,12 +1,11 @@ -var clippy = require("./clippy"); -var cssEditorUtils = require("./css-editor-utils"); +import * as clippy from "./clippy.js"; +import * as cssEditorUtils from "./css-editor-utils.js"; /** * Adds listeners for events from the CSS live examples * @param {Object} exampleChoiceList - The object to which events are added */ function addCSSEditorEventListeners(exampleChoiceList) { - "use strict"; exampleChoiceList.addEventListener("cut", copyTextOnly); exampleChoiceList.addEventListener("copy", copyTextOnly); exampleChoiceList.addEventListener("paste", handlePasteEvents); @@ -31,8 +30,6 @@ function addCSSEditorEventListeners(exampleChoiceList) { * Currently only used by the CSS editor. */ function addPostMessageListener() { - "use strict"; - window.addEventListener( "message", function (event) { @@ -78,7 +75,6 @@ function sendOwnHeight() { * @param {Object} event - The copy event */ function copyTextOnly(event) { - "use strict"; var selection = window.getSelection(); var range = selection.getRangeAt(0); @@ -94,7 +90,6 @@ function copyTextOnly(event) { * @param {Object} event - The paste event object */ function handlePasteEvents(event) { - "use strict"; var codeElement = event.target; // It's likely that caret will be placed inside nested element that belongs to Prism // We require element that contains whole example: @@ -109,50 +104,48 @@ function handlePasteEvents(event) { } function handleChoiceEvent() { - module.exports.onChoose(this); + onChoose(this); +} + +/** + * Called when a new `example-choice` has been selected. + * @param {Object} choice - The selected `example-choice` element + */ +export function onChoose(choice) { + var selected = document.querySelector(".selected"); + + // highlght the code we are leaving + if (selected && !choice.classList.contains("selected")) { + var highlighted = Prism.highlight( + selected.firstChild.textContent, + Prism.languages.css + ); + selected.firstChild.innerHTML = highlighted; + + cssEditorUtils.resetDefault(); + } + + cssEditorUtils.choose(choice); + clippy.toggleClippy(choice); } -module.exports = { - /** - * Called when a new `example-choice` has been selected. - * @param {Object} choice - The selected `example-choice` element - */ - onChoose: function (choice) { - var selected = document.querySelector(".selected"); - - // highlght the code we are leaving - if (selected && !choice.classList.contains("selected")) { - var highlighted = Prism.highlight( - selected.firstChild.textContent, - Prism.languages.css - ); - selected.firstChild.innerHTML = highlighted; - - cssEditorUtils.resetDefault(); - } - - cssEditorUtils.choose(choice); - clippy.toggleClippy(choice); - }, - /** - * Called by the main JS file after all other initialization - * has been completed. - */ - register: function () { - "use strict"; - var exampleChoiceList = document.getElementById("example-choice-list"); - - addPostMessageListener(); - - if (document.readyState != "loading") { - sendOwnHeight(); - } else { - document.addEventListener("DOMContentLoaded", sendOwnHeight); - } - - // only bind events if the `exampleChoiceList` container exist - if (exampleChoiceList) { - addCSSEditorEventListeners(exampleChoiceList); - } - }, -}; +/** + * Called by the main JS file after all other initialization + * has been completed. + */ +export function register() { + var exampleChoiceList = document.getElementById("example-choice-list"); + + addPostMessageListener(); + + if (document.readyState != "loading") { + sendOwnHeight(); + } else { + document.addEventListener("DOMContentLoaded", sendOwnHeight); + } + + // only bind events if the `exampleChoiceList` container exist + if (exampleChoiceList) { + addCSSEditorEventListeners(exampleChoiceList); + } +} diff --git a/editor/js/editor-libs/feature-detector.js b/editor/js/editor-libs/feature-detector.js index 80c75a567..386032653 100644 --- a/editor/js/editor-libs/feature-detector.js +++ b/editor/js/editor-libs/feature-detector.js @@ -4,7 +4,6 @@ * @returns The matched feature as an Object */ function getFeatureObject(feature) { - "use strict"; var featureObj = undefined; switch (feature) { @@ -18,19 +17,16 @@ function getFeatureObject(feature) { return featureObj; } -module.exports = { - /** - * Tests whether the provided feature is supported. It - * does this by checking the `typeof` the feature. - * @param {String} feature - The feature to test ex. 'array-entries' - */ - isDefined: function (feature) { - "use strict"; - // if the feature parameter is undefined, return true - if (feature === undefined) { - return true; - } +/** + * Tests whether the provided feature is supported. It + * does this by checking the `typeof` the feature. + * @param {String} feature - The feature to test ex. 'array-entries' + */ +export function isDefined(feature) { + // if the feature parameter is undefined, return true + if (feature === undefined) { + return true; + } - return getFeatureObject(feature) !== undefined; - }, -}; + return getFeatureObject(feature) !== undefined; +} diff --git a/editor/js/editor-libs/mce-utils.js b/editor/js/editor-libs/mce-utils.js index 2be27edf5..81a223149 100644 --- a/editor/js/editor-libs/mce-utils.js +++ b/editor/js/editor-libs/mce-utils.js @@ -1,90 +1,88 @@ -module.exports = { - /** - * Find and return the `example-choice` parent of the provided element - * @param {Object} element - The child element for which to find the - * `example-choice` parent - * - * @return The parent `example-choice` element - */ - findParentChoiceElem: function (element) { - "use strict"; - var parent = element.parentElement; - var parentClassList = parent.classList; - while (parent && !parentClassList.contains("example-choice")) { - // get the next parent - parent = parent.parentElement; - // get the new parent's `classList` - parentClassList = parent.classList; - } - return parent; - }, - /** - * Creates a temporary element and tests whether the passed - * property exists on the `style` property of the element. - * @param {Object} dataset = The dataset from which to get the property - */ - isPropertySupported: function (dataset) { - "use strict"; +/** + * Find and return the `example-choice` parent of the provided element + * @param {Object} element - The child element for which to find the + * `example-choice` parent + * + * @return The parent `example-choice` element + */ +export function findParentChoiceElem(element) { + var parent = element.parentElement; + var parentClassList = parent.classList; + while (parent && !parentClassList.contains("example-choice")) { + // get the next parent + parent = parent.parentElement; + // get the new parent's `classList` + parentClassList = parent.classList; + } + return parent; +} - /* If there are no 'property' attributes, +/** + * Creates a temporary element and tests whether the passed + * property exists on the `style` property of the element. + * @param {Object} dataset = The dataset from which to get the property + */ +export function isPropertySupported(dataset) { + /* If there are no 'property' attributes, there is nothing to test, so return true. */ - if (dataset["property"] === undefined) { - return true; - } + if (dataset["property"] === undefined) { + return true; + } - // `property` may be a space-separated list of properties. - var properties = dataset["property"].split(" "); - /* Iterate through properties: if any of them apply, + // `property` may be a space-separated list of properties. + var properties = dataset["property"].split(" "); + /* Iterate through properties: if any of them apply, the browser supports this example. */ - var supported = false; - var tmpElem = document.createElement("div"); + var supported = false; + var tmpElem = document.createElement("div"); - for (var i = 0, l = properties.length; i < l; i++) { - if (tmpElem.style[properties[i]] !== undefined) { - supported = true; - } + for (var i = 0, l = properties.length; i < l; i++) { + if (tmpElem.style[properties[i]] !== undefined) { + supported = true; } + } + + return supported; +} - return supported; - }, - /** - * Interrupts the default click event on external links inside - * the shadow dom and opens them in a new tab instead - * @param {Array} externalLinks - all external links inside the shadow dom - */ - openLinksInNewTab: function (externalLinks) { - externalLinks.forEach(function (externalLink) { - externalLink.addEventListener("click", function (event) { - event.preventDefault(); - window.open(externalLink.href); - }); +/** + * Interrupts the default click event on external links inside + * the shadow dom and opens them in a new tab instead + * @param {Array} externalLinks - all external links inside the shadow dom + */ +export function openLinksInNewTab(externalLinks) { + externalLinks.forEach(function (externalLink) { + externalLink.addEventListener("click", function (event) { + event.preventDefault(); + window.open(externalLink.href); }); - }, - /** - * Interrupts the default click event on relative links inside - * the shadow dom and scrolls to the targeted anchor - * @param {Object} shadow - the shadow dom root - * @param {Array} relativeLinks - all relative links inside the shadow dom - */ - scrollToAnchors: function (shadow, relativeLinks) { - relativeLinks.forEach(function (relativeLink) { - relativeLink.addEventListener("click", function (event) { - event.preventDefault(); - shadow.querySelector(relativeLink.hash).scrollIntoView(); - }); + }); +} + +/** + * Interrupts the default click event on relative links inside + * the shadow dom and scrolls to the targeted anchor + * @param {Object} shadow - the shadow dom root + * @param {Array} relativeLinks - all relative links inside the shadow dom + */ +export function scrollToAnchors(shadow, relativeLinks) { + relativeLinks.forEach(function (relativeLink) { + relativeLink.addEventListener("click", function (event) { + event.preventDefault(); + shadow.querySelector(relativeLink.hash).scrollIntoView(); }); - }, - /** - * Hides the default example and shows the custom block - * @param {object} customBlock - The HTML section to show - */ - showCustomExampleHTML: function (customBlock) { - "use strict"; - var defaultExample = document.getElementById("default-example"); - defaultExample.classList.add("hidden"); - defaultExample.setAttribute("aria-hidden", true); + }); +} + +/** + * Hides the default example and shows the custom block + * @param {object} customBlock - The HTML section to show + */ +export function showCustomExampleHTML(customBlock) { + var defaultExample = document.getElementById("default-example"); + defaultExample.classList.add("hidden"); + defaultExample.setAttribute("aria-hidden", true); - customBlock.classList.remove("hidden"); - customBlock.setAttribute("aria-hidden", false); - }, -}; + customBlock.classList.remove("hidden"); + customBlock.setAttribute("aria-hidden", false); +} diff --git a/editor/js/editor-libs/shadow-output.js b/editor/js/editor-libs/shadow-output.js index 5a62c9f8e..71d89a95b 100644 --- a/editor/js/editor-libs/shadow-output.js +++ b/editor/js/editor-libs/shadow-output.js @@ -13,4 +13,4 @@ class ShadowOutput extends HTMLElement { } } -module.exports = ShadowOutput; +export default ShadowOutput; diff --git a/editor/js/editor-libs/tabby.js b/editor/js/editor-libs/tabby.js index 61d0c86f5..05cb7c20f 100644 --- a/editor/js/editor-libs/tabby.js +++ b/editor/js/editor-libs/tabby.js @@ -91,104 +91,104 @@ function setNextActiveTab(direction) { } } -module.exports = { - editors: { - html: { - editor: undefined, - code: htmlEditor, - config: { - lineNumbers: true, - lineWrapping: true, - mode: "htmlmixed", - value: staticHTMLCode.querySelector("code").textContent, - autoRefresh: true, - }, +export const editors = { + html: { + editor: undefined, + code: htmlEditor, + config: { + lineNumbers: true, + lineWrapping: true, + mode: "htmlmixed", + value: staticHTMLCode.querySelector("code").textContent, + autoRefresh: true, }, - css: { - editor: undefined, - code: cssEditor, - config: { - lineNumbers: true, - mode: "css", - value: staticCSSCode.querySelector("code").textContent, - autoRefresh: true, - }, + }, + css: { + editor: undefined, + code: cssEditor, + config: { + lineNumbers: true, + mode: "css", + value: staticCSSCode.querySelector("code").textContent, + autoRefresh: true, }, - js: { - editor: undefined, - code: jsEditor, - config: { - lineNumbers: true, - mode: "javascript", - value: staticJSCode.querySelector("code").textContent, - autoRefresh: true, - }, + }, + js: { + editor: undefined, + code: jsEditor, + config: { + lineNumbers: true, + mode: "javascript", + value: staticJSCode.querySelector("code").textContent, + autoRefresh: true, }, }, - /** - * Initialise the specified editor if not already initialised - * @param {Array} editorTypes - The editors to initialise - * @param {Object} defaultTab - The deafult active tab - */ - initEditor: function (editorTypes, defaultTab) { - if (defaultTab) { - setDefaultTab(defaultTab); - } - for (var editor of editorTypes) { - // enable relevant tabs - document.getElementById(editor).classList.remove("hidden"); - // eslint-disable-next-line new-cap - this.editors[editor].editor = CodeMirror( - this.editors[editor].code, - this.editors[editor].config +}; + +/** + * Initialise the specified editor if not already initialised + * @param {Array} editorTypes - The editors to initialise + * @param {Object} defaultTab - The deafult active tab + */ +export function initEditor(editorTypes, defaultTab) { + if (defaultTab) { + setDefaultTab(defaultTab); + } + for (var editor of editorTypes) { + // enable relevant tabs + document.getElementById(editor).classList.remove("hidden"); + // eslint-disable-next-line new-cap + editors[editor].editor = CodeMirror( + editors[editor].code, + editors[editor].config + ); + } +} + +/** + * Registers the required click and keyboard event listeners + */ +export function registerEventListeners() { + tabList.addEventListener("click", function (event) { + var eventTarget = event.target; + var role = eventTarget.getAttribute("role"); + + if (role === "tab") { + var activeTab = tabList.querySelector('button[aria-selected="true"]'); + var selectedPanel = document.getElementById( + eventTarget.getAttribute("aria-controls") ); + + hideTabPanels(); + setActiveTab(eventTarget, activeTab); + + // now show the selected tabpanel + selectedPanel.classList.remove("hidden"); + selectedPanel.setAttribute("aria-hidden", false); + // refresh the CodeMirror UI for this view + module.exports.editors[eventTarget.id].editor.refresh(); } - }, - /** - * Registers the required click and keyboard event listeners - */ - registerEventListeners: function () { - tabList.addEventListener("click", function (event) { - var eventTarget = event.target; - var role = eventTarget.getAttribute("role"); - - if (role === "tab") { - var activeTab = tabList.querySelector('button[aria-selected="true"]'); - var selectedPanel = document.getElementById( - eventTarget.getAttribute("aria-controls") - ); - - hideTabPanels(); - setActiveTab(eventTarget, activeTab); - - // now show the selected tabpanel - selectedPanel.classList.remove("hidden"); - selectedPanel.setAttribute("aria-hidden", false); - // refresh the CodeMirror UI for this view - module.exports.editors[eventTarget.id].editor.refresh(); - } - }); - - tabList.addEventListener("keyup", function (event) { - event.stopPropagation(); - switch (event.key) { - case "ArrowRight": - case "ArrowDown": - setNextActiveTab("forward"); - break; - case "ArrowLeft": - case "ArrowUp": - setNextActiveTab("reverse"); - break; - case "Home": - setActiveTab(tabs[0]); - break; - case "End": - setActiveTab(tabs[tabs.length - 1]); - break; - case "default": - return; - } - }); - }, -}; + }); + + tabList.addEventListener("keyup", function (event) { + event.stopPropagation(); + switch (event.key) { + case "ArrowRight": + case "ArrowDown": + setNextActiveTab("forward"); + break; + case "ArrowLeft": + case "ArrowUp": + setNextActiveTab("reverse"); + break; + case "Home": + setActiveTab(tabs[0]); + break; + case "End": + setActiveTab(tabs[tabs.length - 1]); + break; + case "default": + return; + } + }); +} diff --git a/editor/js/editor-libs/template-utils.js b/editor/js/editor-libs/template-utils.js index 5d456de7f..333c72e28 100644 --- a/editor/js/editor-libs/template-utils.js +++ b/editor/js/editor-libs/template-utils.js @@ -1,80 +1,81 @@ -module.exports = { - /** - * Return the base style rules for the output class - * @returns base style rules for the output class - */ - getOutputBaseStyle: function () { - return ".output{background-color:#fff;color:#15141aff;font-size:0.9rem;line-height:1.5;overflow:scroll;padding:1rem;height:100%;}"; - }, - /** - * Return the base script to inject into the shadowDOM - * @returns base JavaScript util which return the `shadowRoot` - */ - getBaseJS: function () { - return "function getShadowRoot() { return document.querySelector('shadow-output').shadowRoot; }"; - }, - /** - * Get the template element and return its content - * @returns The .content of the template element - */ - getTemplateOutput: function () { - return document.getElementById("code_tmpl").content; - }, - /** - * Create a template element and populate it with the content of - * the editor panes. If native shadowDOM is not supported, it uses - * ShadyCSS to prepare the template before it is injected into - * the shadowDOM element. - * @param {Object} contents - The content from the editor panes - * Example - * -------- - * { - * cssContent: 'h1 { background-color: #333; }', - * htmlContent: '

Title

' - * } - */ - createTemplate: function (contents) { - var html = document.createElement("div"); - var output = document.getElementById("output"); - var previousTmpl = document.getElementById("code_tmpl"); - var outputStyleElem = document.createElement("style"); - var styleElem = document.createElement("style"); - var tmpl = document.createElement("template"); +/** + * Return the base style rules for the output class + * @returns base style rules for the output class + */ +export function getOutputBaseStyle() { + return ".output{background-color:#fff;color:#15141aff;font-size:0.9rem;line-height:1.5;overflow:scroll;padding:1rem;height:100%;}"; +} - /* First remove the existing template if it exists. +/** + * Return the base script to inject into the shadowDOM + * @returns base JavaScript util which return the `shadowRoot` + */ +export function getBaseJS() { + return "function getShadowRoot() { return document.querySelector('shadow-output').shadowRoot; }"; +} + +/** + * Get the template element and return its content + * @returns The .content of the template element + */ +export function getTemplateOutput() { + return document.getElementById("code_tmpl").content; +} + +/** + * Create a template element and populate it with the content of + * the editor panes. If native shadowDOM is not supported, it uses + * ShadyCSS to prepare the template before it is injected into + * the shadowDOM element. + * @param {Object} contents - The content from the editor panes + * Example + * -------- + * { + * cssContent: 'h1 { background-color: #333; }', + * htmlContent: '

Title

' + * } + */ +export function createTemplate(contents) { + var html = document.createElement("div"); + var output = document.getElementById("output"); + var previousTmpl = document.getElementById("code_tmpl"); + var outputStyleElem = document.createElement("style"); + var styleElem = document.createElement("style"); + var tmpl = document.createElement("template"); + + /* First remove the existing template if it exists. This ensures that prepareTemplate will process the template. */ - if (previousTmpl) { - output.removeChild(previousTmpl); - } + if (previousTmpl) { + output.removeChild(previousTmpl); + } - tmpl.setAttribute("id", "code_tmpl"); - output.appendChild(tmpl); + tmpl.setAttribute("id", "code_tmpl"); + output.appendChild(tmpl); - outputStyleElem.textContent = this.getOutputBaseStyle(); - styleElem.textContent = contents.cssContent; - html.classList.add("output"); - html.innerHTML = contents.htmlContent; + outputStyleElem.textContent = getOutputBaseStyle(); + styleElem.textContent = contents.cssContent; + html.classList.add("output"); + html.innerHTML = contents.htmlContent; - tmpl.content.appendChild(outputStyleElem); - tmpl.content.appendChild(styleElem); - tmpl.content.appendChild(html); + tmpl.content.appendChild(outputStyleElem); + tmpl.content.appendChild(styleElem); + tmpl.content.appendChild(html); - if (contents.jsContent) { - var jsUtilElem = document.createElement("script"); - var jsElem = document.createElement("script"); + if (contents.jsContent) { + var jsUtilElem = document.createElement("script"); + var jsElem = document.createElement("script"); - jsUtilElem.textContent = this.getBaseJS(); - /* wrap the example JS in an IIFE to avoid collisions with variables, + jsUtilElem.textContent = getBaseJS(); + /* wrap the example JS in an IIFE to avoid collisions with variables, functions etc. in the larger page scope */ - jsElem.textContent = `(function() { 'use strict'; ${contents.jsContent} })();`; + jsElem.textContent = `(function() { 'use strict'; ${contents.jsContent} })();`; - tmpl.content.appendChild(jsUtilElem); - tmpl.content.appendChild(jsElem); - } + tmpl.content.appendChild(jsUtilElem); + tmpl.content.appendChild(jsElem); + } - if (typeof ShadyDOM !== "undefined") { - ShadyCSS.prepareTemplate(tmpl, "shadow-output"); - } - }, -}; + if (typeof ShadyDOM !== "undefined") { + ShadyCSS.prepareTemplate(tmpl, "shadow-output"); + } +} diff --git a/editor/js/editor.js b/editor/js/editor.js index 3da041be6..0a60b958b 100644 --- a/editor/js/editor.js +++ b/editor/js/editor.js @@ -1,13 +1,11 @@ -(function () { - "use strict"; - - var mceConsole = require("./editor-libs/console"); - var mceEvents = require("./editor-libs/events.js"); - var mceUtils = require("./editor-libs/mce-utils"); - var shadowOutput = require("./editor-libs/shadow-output"); - var templateUtils = require("./editor-libs/template-utils"); - var tabby = require("./editor-libs/tabby"); +import mceConsole from "./editor-libs/console.js"; +import * as mceEvents from "./editor-libs/events.js"; +import * as mceUtils from "./editor-libs/mce-utils.js"; +import shadowOutput from "./editor-libs/shadow-output.js"; +import * as templateUtils from "./editor-libs/template-utils.js"; +import * as tabby from "./editor-libs/tabby.js"; +(function () { var cssEditor = document.getElementById("css-editor"); var clearConsole = document.getElementById("clear"); var editorContainer = document.getElementById("editor-container"); @@ -38,7 +36,8 @@ function setContent(propertyName, editorName) { if (tabby.editors[editorName].editor) { - editorContents[propertyName] = tabby.editors[editorName].editor.getValue(); + editorContents[propertyName] = + tabby.editors[editorName].editor.getValue(); } else { editorContents[propertyName] = ""; } diff --git a/jest-puppeteer.config.js b/jest-puppeteer.config.cjs similarity index 100% rename from jest-puppeteer.config.js rename to jest-puppeteer.config.cjs diff --git a/lib/bundler.js b/lib/bundler.js index 5379372f7..4e7df0fe5 100644 --- a/lib/bundler.js +++ b/lib/bundler.js @@ -1,15 +1,18 @@ -const browserify = require("browserify"); -const CleanCSS = require("clean-css"); -const fs = require("fs"); -const fse = require("fs-extra"); -const path = require("path"); -const uglify = require("uglify-es"); - -const getConfig = require("./config"); -const utils = require("./utils"); +import browserify from "browserify"; +import CleanCSS from "clean-css"; +import esmify from "esmify"; +import fs from "node:fs"; +import fse from "fs-extra"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; +import uglify from "uglify-es"; +import getConfig from "./config.js"; +import * as utils from "./utils.js"; const config = getConfig(); +const __dirname = fileURLToPath(new URL(".", import.meta.url)); + /** * Takes an array of paths and return the resolved * paths using a combination of `path.join` and `__dirname` @@ -87,7 +90,7 @@ function buildBundle(type, fileName, bundle) { * CSS and JavaScript bundles to `/docs/[css|js]` * @returns {Object} A `Promise` that will resolve if all bundles are built successfully */ -function buildBundles() { +export function buildBundles() { return new Promise((resolve, reject) => { fse .readJson(path.join(__dirname, config.bundleConfig)) @@ -115,7 +118,7 @@ function buildBundles() { * files have been processed, and written to disk. * @returns {Array} An array of promises */ -function processAndWrite() { +export function processAndWrite() { const entryFiles = config.editorBundles.split(","); let filePromises = []; @@ -132,9 +135,9 @@ function processAndWrite() { ); try { - let reader = browserify( - path.join(__dirname, entryFiles[file]) - ).bundle(); + let reader = browserify(path.join(__dirname, entryFiles[file]), { + plugin: [esmify], + }).bundle(); reader.pipe(writableOutputFile); reader.on("end", () => { resolve(`${outputFilename} written to disk`); @@ -147,8 +150,3 @@ function processAndWrite() { } return filePromises; } - -module.exports = { - buildBundles, - processAndWrite, -}; diff --git a/lib/config.js b/lib/config.js index 853348fdc..615279ab6 100644 --- a/lib/config.js +++ b/lib/config.js @@ -1,5 +1,8 @@ -const { cosmiconfigSync } = require("cosmiconfig"); -const path = require("path"); +import { cosmiconfigSync } from "cosmiconfig"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; + +const __dirname = fileURLToPath(new URL(".", import.meta.url)); function getConfig() { let configFile = path.join(__dirname, "../.bobconfigrc"); @@ -12,4 +15,4 @@ function getConfig() { return cosmiConfig.load(configFile).config; } -module.exports = getConfig; +export default getConfig; diff --git a/lib/mdn-bob.js b/lib/mdn-bob.js index 2c885a9ed..87fe72bf4 100755 --- a/lib/mdn-bob.js +++ b/lib/mdn-bob.js @@ -1,21 +1,20 @@ #!/usr/bin/env node -const fse = require("fs-extra"); - -const bundler = require("./bundler"); -const getConfig = require("./config"); -const pageBuilder = require("./pageBuilder"); -const utils = require("./utils"); +import fse from "fs-extra"; +import * as bundler from "./bundler.js"; +import getConfig from "./config.js"; +import * as pageBuilder from "./pageBuilder.js"; +import * as utils from "./utils.js"; /** * Initialization of the module. Calls the follow on functions to generate the pages. */ -function init() { +async function init() { const config = getConfig(); console.info(`MDN-BOB: Cleaning or creating ${config.baseDir}....`); // empty or create `config.baseDir` - fse.emptyDirSync(config.baseDir); + await fse.emptyDir(config.baseDir); console.info("MDN-BOB: Copying static assets...."); utils.copyStaticAssets(); @@ -23,39 +22,29 @@ function init() { console.info("MDN-BOB: Compiling editor JavaScript...."); const promises = bundler.processAndWrite(); - Promise.all(promises).then( - (values) => { - values.forEach((value) => { - console.info("MDN-BOB: ", value); - }); - - pageBuilder - .buildPages() - .then((result) => { - console.info(result); - return bundler.buildBundles(); - }) - .then((result) => { - console.info(result); - return utils.removeJSBundles(); - }) - .then((result) => { - console.info(result); - console.info("MDN-BOB: Build completed successfully"); - }) - .catch((error) => { - console.error( - "MDN-BOB: (mdn-bob.js/@init) Error during build:", - error - ); - process.exit(2); - }); - }, - (reason) => { - console.error(`MDN-BOB: (bundler.js/@compileJS) ${reason}`); - process.exit(1); + try { + const values = await Promise.all(promises); + + values.forEach((value) => { + console.info("MDN-BOB: ", value); + }); + + try { + console.log(await pageBuilder.buildPages()); + + console.log(await bundler.buildBundles()); + + console.log(await utils.removeJSBundles()); + + console.info("MDN-BOB: Build completed successfully"); + } catch (error) { + console.error("MDN-BOB: (mdn-bob.js/@init) Error during build:", error); + process.exit(2); } - ); + } catch (reason) { + console.error(`MDN-BOB: (bundler.js/@compileJS) ${reason}`); + process.exit(1); + } } -init(); +await init(); diff --git a/lib/pageBuilder.js b/lib/pageBuilder.js index 7051725da..4a28159e7 100644 --- a/lib/pageBuilder.js +++ b/lib/pageBuilder.js @@ -1,16 +1,17 @@ -const crypto = require("crypto"); -const fs = require("fs"); -const path = require("path"); - -const fse = require("fs-extra"); -const glob = require("glob"); - -const getConfig = require("./config"); -const pageBuilderUtils = require("./pageBuilderUtils"); -const processor = require("./processor"); -const tabbedPageBuilder = require("./tabbedPageBuilder"); +import crypto from "node:crypto"; +import fs from "node:fs"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; + +import fse from "fs-extra"; +import glob from "glob"; +import getConfig from "./config.js"; +import * as pageBuilderUtils from "./pageBuilderUtils.js"; +import * as processor from "./processor.js"; +import * as tabbedPageBuilder from "./tabbedPageBuilder.js"; const config = getConfig(); +const __dirname = fileURLToPath(new URL(".", import.meta.url)); /** * Traverse the list of pages, and uses the meta data to generate the final @@ -123,7 +124,7 @@ function getSelfVersion(length = 7) { * Iterates over all `meta.json` files. For each file, * it passes the list of pages to the `build` function. */ -function buildPages() { +export function buildPages() { const selfVersion = getSelfVersion(); return new Promise((resolve, reject) => { const metaJSONArray = glob.sync(config.metaGlob, {}); @@ -146,7 +147,3 @@ function buildPages() { resolve("MDN-BOB: Pages built successfully"); }); } - -module.exports = { - buildPages, -}; diff --git a/lib/pageBuilderUtils.js b/lib/pageBuilderUtils.js index 44d7c922b..9029ec532 100644 --- a/lib/pageBuilderUtils.js +++ b/lib/pageBuilderUtils.js @@ -1,161 +1,162 @@ -const fse = require("fs-extra"); -const path = require("path"); +import fse from "fs-extra"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; +import * as processor from "./processor.js"; -const processor = require("./processor"); +const __dirname = fileURLToPath(new URL(".", import.meta.url)); -module.exports = { - /** - * Based on the provided `tmplType`, return the relevant - * template as a string. - * @param {String} tmplType - The template type - * @returns The appropriate template as a string - */ - getPageTmpl: function (tmplType) { - switch (tmplType) { - case "css": - try { - return fse.readFileSync( - path.join(__dirname, "../editor/tmpl/live-css-tmpl.html"), - "utf8" - ); - } catch (error) { - console.error("Error loading file", error); - } - case "js": - try { - return fse.readFileSync( - path.join(__dirname, "../editor/tmpl/live-js-tmpl.html"), - "utf8" - ); - } catch (error) { - console.error("Error loading file", error); - } - case "wat": - try { - return fse.readFileSync( - path.join(__dirname, "../editor/tmpl/live-wat-tmpl.html"), - "utf8" - ); - } catch (error) { - console.error("Error loading file", error); - } - case "tabbed": - case "webapi-tabbed": - try { - return fse.readFileSync( - path.join(__dirname, "../editor/tmpl/live-tabbed-tmpl.html"), - "utf8" - ); - } catch (error) { - console.error("Error loading file", error); - } - default: - console.error( - `MDN-BOB: No template found for template type ${tmplType}` +/** + * Based on the provided `tmplType`, return the relevant + * template as a string. + * @param {String} tmplType - The template type + * @returns The appropriate template as a string + */ +export function getPageTmpl(tmplType) { + switch (tmplType) { + case "css": + try { + return fse.readFileSync( + path.join(__dirname, "../editor/tmpl/live-css-tmpl.html"), + "utf8" ); - process.exit(1); - } - }, - /** - * Sets the active tabs in a comma separated string. - * @param {Object} currentPage - The current page object - * @param {String} tmpl - The template as a string - * - * @returns The processed template with the active tabs set - */ - setActiveTabs: function (currentPage, tmpl) { - const regex = /%active-tabs%/g; + } catch (error) { + console.error("Error loading file", error); + } + case "js": + try { + return fse.readFileSync( + path.join(__dirname, "../editor/tmpl/live-js-tmpl.html"), + "utf8" + ); + } catch (error) { + console.error("Error loading file", error); + } + case "wat": + try { + return fse.readFileSync( + path.join(__dirname, "../editor/tmpl/live-wat-tmpl.html"), + "utf8" + ); + } catch (error) { + console.error("Error loading file", error); + } + case "tabbed": + case "webapi-tabbed": + try { + return fse.readFileSync( + path.join(__dirname, "../editor/tmpl/live-tabbed-tmpl.html"), + "utf8" + ); + } catch (error) { + console.error("Error loading file", error); + } + default: + console.error(`MDN-BOB: No template found for template type ${tmplType}`); + process.exit(1); + } +} - if (currentPage.tabs) { - return tmpl.replace(regex, `data-tabs="${currentPage.tabs}"`); - } else { - return tmpl.replace(regex, ""); - } - }, - /** - * Sets the tab that should be open by default. - * @param {Object} currentPage - The current page object - * @param {String} tmpl - The template as a string - * - * @returns The processed template with the default tab id - */ - setDefaultTab: function (currentPage, tmpl) { - const regex = /%default-tab%/g; +/** + * Sets the active tabs in a comma separated string. + * @param {Object} currentPage - The current page object + * @param {String} tmpl - The template as a string + * + * @returns The processed template with the active tabs set + */ +export function setActiveTabs(currentPage, tmpl) { + const regex = /%active-tabs%/g; - if (currentPage.defaultTab) { - return tmpl.replace( - regex, - `data-default-tab="${currentPage.defaultTab}"` - ); - } else { - return tmpl.replace(regex, ""); - } - }, - /** - * If the `currentPage.type` is of type webapi-tabbed, - * show the console, else hide. Also set the appropriate - * `aria-hidden` state - * @param {Object} currentPage - The current page object - * @param {String} tmpl - The template as a string - * - * @returns The processed template with console state set - */ - setConsoleState: function (currentPage, tmpl) { - const stateRegEx = /%console-state%/g; - const ariaHiddenStateRegEx = /%console-aria-state%/g; + if (currentPage.tabs) { + return tmpl.replace(regex, `data-tabs="${currentPage.tabs}"`); + } else { + return tmpl.replace(regex, ""); + } +} - if (currentPage.type === "webapi-tabbed") { - // no class to add, simple clear the pattern - tmpl = tmpl.replace(stateRegEx, ""); - return tmpl.replace(ariaHiddenStateRegEx, false); - } else { - tmpl = tmpl.replace(stateRegEx, "hidden"); - return tmpl.replace(ariaHiddenStateRegEx, true); - } - }, - /** - * Sets the appropriate class on the tabbed editor’s container - * element based on the height property defined in the example’s - * meta data - * @param {Object} currentPage - The current page object - * @param {String} tmpl - The template as a string - * - * @returns The processed template with the height class set - */ - setEditorHeight: function (currentPage, tmpl) { - const regex = /%editor-height%/g; +/** + * Sets the tab that should be open by default. + * @param {Object} currentPage - The current page object + * @param {String} tmpl - The template as a string + * + * @returns The processed template with the default tab id + */ +export function setDefaultTab(currentPage, tmpl) { + const regex = /%default-tab%/g; - if (currentPage.height === undefined) { - console.error( - `[BoB] Required height property of ${currentPage.title} is not defined` - ); - process.exit(1); - } + if (currentPage.defaultTab) { + return tmpl.replace(regex, `data-default-tab="${currentPage.defaultTab}"`); + } else { + return tmpl.replace(regex, ""); + } +} + +/** + * If the `currentPage.type` is of type webapi-tabbed, + * show the console, else hide. Also set the appropriate + * `aria-hidden` state + * @param {Object} currentPage - The current page object + * @param {String} tmpl - The template as a string + * + * @returns The processed template with console state set + */ +export function setConsoleState(currentPage, tmpl) { + const stateRegEx = /%console-state%/g; + const ariaHiddenStateRegEx = /%console-aria-state%/g; + + if (currentPage.type === "webapi-tabbed") { + // no class to add, simple clear the pattern + tmpl = tmpl.replace(stateRegEx, ""); + return tmpl.replace(ariaHiddenStateRegEx, false); + } else { + tmpl = tmpl.replace(stateRegEx, "hidden"); + return tmpl.replace(ariaHiddenStateRegEx, true); + } +} + +/** + * Sets the appropriate class on the tabbed editor’s container + * element based on the height property defined in the example’s + * meta data + * @param {Object} currentPage - The current page object + * @param {String} tmpl - The template as a string + * + * @returns The processed template with the height class set + */ +export function setEditorHeight(currentPage, tmpl) { + const regex = /%editor-height%/g; + + if (currentPage.height === undefined) { + console.error( + `[BoB] Required height property of ${currentPage.title} is not defined` + ); + process.exit(1); + } + + return tmpl.replace(regex, currentPage.height); +} + +/** + * Sets the `` and `<h4>` main page title + * @param {Object} currentPage - The current page object + * @param {String} tmpl - The template as a string + * + * @returns The processed template with the titles set + */ +export function setMainTitle(currentPage, tmpl) { + const regex = /%title%/g; + let resultsArray = []; - return tmpl.replace(regex, currentPage.height); - }, - /** - * Sets the `<title>` and `<h4>` main page title - * @param {Object} currentPage - The current page object - * @param {String} tmpl - The template as a string - * - * @returns The processed template with the titles set - */ - setMainTitle: function (currentPage, tmpl) { - const regex = /%title%/g; - let resultsArray = []; + // replace all instances of `%title` with the `currentPage.title` + while ((resultsArray = regex.exec(tmpl)) !== null) { + tmpl = tmpl.replace( + resultsArray[0].trim(), + processor.preprocessHTML(currentPage.title) + ); + } + return tmpl; +} - // replace all instances of `%title` with the `currentPage.title` - while ((resultsArray = regex.exec(tmpl)) !== null) { - tmpl = tmpl.replace( - resultsArray[0].trim(), - processor.preprocessHTML(currentPage.title) - ); - } - return tmpl; - }, - setCacheBuster: function (string, tmpl) { - const regex = /%cache-buster%/g; - return tmpl.replace(regex, string); - }, -}; +export function setCacheBuster(string, tmpl) { + const regex = /%cache-buster%/g; + return tmpl.replace(regex, string); +} diff --git a/lib/processor.js b/lib/processor.js index c60c9fe79..8247d09aa 100644 --- a/lib/processor.js +++ b/lib/processor.js @@ -1,8 +1,8 @@ -const CleanCSS = require("clean-css"); -const fse = require("fs-extra"); -const uglify = require("uglify-es"); +import CleanCSS from "clean-css"; +import fse from "fs-extra"; +import uglify from "uglify-es"; +import getConfig from "./config.js"; -const getConfig = require("./config"); const config = getConfig(); const MAX_LINE_COUNT_OF_SHORT_JS_EXAMPLES = 7; @@ -15,7 +15,7 @@ const MIN_LINE_COUNT_OF_TALL_WAT_EXAMPLES = 12; * @param {String} html - The HTML as a string * @return The processed HTML */ -function preprocessHTML(html) { +export function preprocessHTML(html) { let re = /</g; return html.replace(re, "<"); } @@ -77,7 +77,7 @@ function processJSInclude(tmpl, source) { * @param {String} source - The source filepath * @returns tmpl - The modified template string */ -function processInclude(type, tmpl, source) { +export function processInclude(type, tmpl, source) { return type === "css" ? processCSSInclude(tmpl, source) : processJSInclude(tmpl, source); @@ -164,7 +164,7 @@ function handleDeprecatedJSExampleFormat(exampleCode, path) { * @param {String} sourcePath - The path of the source code * @returns {String} example - The embeddable example */ -function processExampleCode(type, sourcePath) { +export function processExampleCode(type, sourcePath) { const exampleCode = fse.readFileSync(sourcePath, "utf8"); switch (type) { case "html": @@ -186,15 +186,8 @@ function processExampleCode(type, sourcePath) { * @param {String} jsSrc - The path of the JavaScript source code * @returns {String} example - The embeddable example */ -function processWat(watSrc, jsSrc) { +export function processWat(watSrc, jsSrc) { const watCode = fse.readFileSync(watSrc, "utf8"); const jsCode = fse.readFileSync(jsSrc, "utf8"); return preprocessWatExample(watCode, jsCode); } - -module.exports = { - preprocessHTML, - processInclude, - processExampleCode, - processWat, -}; diff --git a/lib/tabbedPageBuilder.js b/lib/tabbedPageBuilder.js index 3b7980413..e095e07a1 100644 --- a/lib/tabbedPageBuilder.js +++ b/lib/tabbedPageBuilder.js @@ -1,7 +1,6 @@ -const fse = require("fs-extra"); - -const pageBuilderUtils = require("./pageBuilderUtils"); -const processor = require("./processor"); +import fse from "fs-extra"; +import * as pageBuilderUtils from "./pageBuilderUtils.js"; +import * as processor from "./processor.js"; /** * Replace the template tag with the CSS source, or an empty string @@ -59,7 +58,7 @@ function addJS(currentPage, tmpl) { * @param {Object} currentPage - The currentPage meta data as an Object * @returns {String} The HTML for a tabbed example */ -function buildTabbedExample(tmpl, currentPage) { +export function buildTabbedExample(tmpl, currentPage) { // set main title tmpl = pageBuilderUtils.setMainTitle(currentPage, tmpl); // set the height of the editor container @@ -79,7 +78,3 @@ function buildTabbedExample(tmpl, currentPage) { tmpl = addJS(currentPage, tmpl); return tmpl; } - -module.exports = { - buildTabbedExample, -}; diff --git a/lib/utils.js b/lib/utils.js index fc39ce53c..649e7d527 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -1,15 +1,17 @@ -const dir = require("node-dir"); -const fse = require("fs-extra"); -const path = require("path"); +import dir from "node-dir"; +import fse from "fs-extra"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; +import getConfig from "./config.js"; -const getConfig = require("./config"); +const __dirname = fileURLToPath(new URL(".", import.meta.url)); /** * Copies all assets recursively in `sourceDir` to the directory specified as `destDir` * @param {string} sourceDir - The root relative path to the directory containing assets * @param {string} destDir - The root relative path to the directory to copy the assets to */ -function copyDirectory(sourceDir, destDir) { +export function copyDirectory(sourceDir, destDir) { fse.copySync(sourceDir, destDir, { filter: (src) => { return ![".DS_Store"].includes(path.basename(src)); @@ -20,7 +22,7 @@ function copyDirectory(sourceDir, destDir) { /** * Copies editor and examples static assets */ -function copyStaticAssets() { +export function copyStaticAssets() { const config = getConfig(); // copy editor static assets copyDirectory( @@ -40,7 +42,7 @@ function copyStaticAssets() { * If not, it creates the directory * @param {string} dir - Project root relative path to directory */ -function ensureDir(dir) { +export function ensureDir(dir) { // if the target directory does not exist if (!fse.pathExistsSync(dir)) { // create it now @@ -52,7 +54,7 @@ function ensureDir(dir) { * As a last step, this deletes the JS bundles that was * built earlier in the build process. */ -function removeJSBundles() { +export function removeJSBundles() { return new Promise((resolve, reject) => { let bundlesArray = [ path.join(__dirname, "../editor/js/editable-css-bundle.js"), @@ -73,10 +75,3 @@ function removeJSBundles() { resolve("MDN-BOB: Cleanup completed successfully"); }); } - -module.exports = { - copyDirectory, - copyStaticAssets, - ensureDir, - removeJSBundles, -}; diff --git a/package-lock.json b/package-lock.json index b49320e9b..c7e41b47b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,13 +27,14 @@ "@babel/core": "^7.19.0", "@babel/preset-env": "^7.19.0", "babel-loader": "^8.2.5", - "babel-plugin-prismjs": "^2.1.0", + "babel-plugin-prismjs": "github:queengooborg/babel-plugin-prismjs#patch-1-build", "bundlesize": "0.18.1", "clipboard": "^2.0.11", "css-loader": "^6.7.1", "eslint": "^8.2.0", "eslint-config-prettier": "^8.3.0", "eslint-plugin-import": "^2.25.3", + "esmify": "^2.1.1", "http-server": "14.1.1", "husky": "^8.0.1", "jest": "29.0.3", @@ -45,6 +46,7 @@ "prettier-eslint": "15.0.1", "prismjs": "1.29.0", "puppeteer": "17.1.3", + "style-loader": "^3.3.1", "webpack-cli": "^4.10.0" }, "engines": { @@ -3249,6 +3251,87 @@ "follow-redirects": "^1.14.0" } }, + "node_modules/babel-code-frame": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", + "integrity": "sha512-XqYMR2dfdGMW+hd0IUZ2PwK+fGeFkOxZJ0wY+JaQAHzt1Zx8LcvpiZD2NiGkEG8qx0CfkAOr5xt76d1e8vG90g==", + "dev": true, + "dependencies": { + "chalk": "^1.1.3", + "esutils": "^2.0.2", + "js-tokens": "^3.0.2" + } + }, + "node_modules/babel-code-frame/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/babel-code-frame/node_modules/ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/babel-code-frame/node_modules/chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", + "dev": true, + "dependencies": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/babel-code-frame/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/babel-code-frame/node_modules/js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha512-RjTcuD4xjtthQkaWH7dFlH85L+QaVtSoOyGdZ3g6HFhS9dFNDfLyqgm2NFe2X6cQpeFmt0452FJjFG5UameExg==", + "dev": true + }, + "node_modules/babel-code-frame/node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", + "dev": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/babel-code-frame/node_modules/supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/babel-jest": { "version": "29.0.3", "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.0.3.tgz", @@ -3307,6 +3390,15 @@ "url": "https://opencollective.com/webpack" } }, + "node_modules/babel-messages": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", + "integrity": "sha512-Bl3ZiA+LjqaMtNYopA9TYE9HP1tQ+E5dLxE0XrAzcIJeK2UqF0/EaqXwBn9esd4UmTfEab+P+UYQ1GnioFIb/w==", + "dev": true, + "dependencies": { + "babel-runtime": "^6.22.0" + } + }, "node_modules/babel-plugin-dynamic-import-node": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", @@ -3316,6 +3408,15 @@ "object.assign": "^4.1.0" } }, + "node_modules/babel-plugin-import-to-require": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-import-to-require/-/babel-plugin-import-to-require-1.0.0.tgz", + "integrity": "sha512-dc843CwrFivjO8AVgxcHvxl0cb7J7Ed8ZGFP8+PjH3X1CnyzYtAU1WL1349m9Wc/+oqk4ETx2+cIEO2jlp3XyQ==", + "dev": true, + "dependencies": { + "babel-template": "^6.26.0" + } + }, "node_modules/babel-plugin-istanbul": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", @@ -3388,9 +3489,9 @@ }, "node_modules/babel-plugin-prismjs": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/babel-plugin-prismjs/-/babel-plugin-prismjs-2.1.0.tgz", - "integrity": "sha512-ehzSKYfeAz4U78zi/sfwsjDPlq0LvDKxNefcZTJ/iKBu+plsHsLqZhUeGf1+82LAcA35UZGbU6ksEx2Utphc/g==", + "resolved": "git+ssh://git@github.com/queengooborg/babel-plugin-prismjs.git#9f810d9cd869fd59267a55057dd259c19d8954dc", "dev": true, + "license": "MIT", "peerDependencies": { "prismjs": "^1.18.0" } @@ -3434,6 +3535,106 @@ "@babel/core": "^7.0.0" } }, + "node_modules/babel-runtime": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", + "integrity": "sha512-ITKNuq2wKlW1fJg9sSW52eepoYgZBggvOAHC0u/CYu/qxQ9EVzThCgR69BnSXLHjy2f7SY5zaQ4yt7H9ZVxY2g==", + "dev": true, + "dependencies": { + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" + } + }, + "node_modules/babel-runtime/node_modules/regenerator-runtime": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", + "dev": true + }, + "node_modules/babel-template": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", + "integrity": "sha512-PCOcLFW7/eazGUKIoqH97sO9A2UYMahsn/yRQ7uOk37iutwjq7ODtcTNF+iFDSHNfkctqsLRjLP7URnOx0T1fg==", + "dev": true, + "dependencies": { + "babel-runtime": "^6.26.0", + "babel-traverse": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "lodash": "^4.17.4" + } + }, + "node_modules/babel-traverse": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", + "integrity": "sha512-iSxeXx7apsjCHe9c7n8VtRXGzI2Bk1rBSOJgCCjfyXb6v1aCqE1KSEpq/8SXuVN8Ka/Rh1WDTF0MDzkvTA4MIA==", + "dev": true, + "dependencies": { + "babel-code-frame": "^6.26.0", + "babel-messages": "^6.23.0", + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "debug": "^2.6.8", + "globals": "^9.18.0", + "invariant": "^2.2.2", + "lodash": "^4.17.4" + } + }, + "node_modules/babel-traverse/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/babel-traverse/node_modules/globals": { + "version": "9.18.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", + "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/babel-traverse/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/babel-types": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", + "integrity": "sha512-zhe3V/26rCWsEZK8kZN+HaQj5yQ1CilTObixFzKW1UWjqG7618Twz6YEsCnjfg5gBcJh02DrpCkS9h98ZqDY+g==", + "dev": true, + "dependencies": { + "babel-runtime": "^6.26.0", + "esutils": "^2.0.2", + "lodash": "^4.17.4", + "to-fast-properties": "^1.0.3" + } + }, + "node_modules/babel-types/node_modules/to-fast-properties": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", + "integrity": "sha512-lxrWP8ejsq+7E3nNjwYmUBMAgjMTZoTI+sdBOpvNyijeDLa29LUn9QaoXAHv4+Z578hbmHHJKZknzxVtvo77og==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/babylon": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", + "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", + "dev": true, + "bin": { + "babylon": "bin/babylon.js" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -4395,6 +4596,14 @@ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.1.3.tgz", "integrity": "sha512-Y8L5rp6jo+g9VEPgvqNfEopjTR4OTYct8lXlS8iVQdmnjDvbdbzYe9rjtFCB9egC86JoNCU61WRY+ScjkZpnIg==" }, + "node_modules/core-js": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", + "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", + "deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.", + "dev": true, + "hasInstallScript": true + }, "node_modules/core-js-compat": { "version": "3.25.0", "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.25.0.tgz", @@ -5301,6 +5510,24 @@ "node": ">=8" } }, + "node_modules/esmify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/esmify/-/esmify-2.1.1.tgz", + "integrity": "sha512-GyOVgjG7sNyYB5Mbo15Ll4aGrcXZzZ3LI22rbLOjCI7L/wYelzQpBHRZkZkqbPNZ/QIRilcaHqzgNCLcEsi1lQ==", + "dev": true, + "dependencies": { + "@babel/core": "^7.2.2", + "@babel/plugin-syntax-async-generators": "^7.2.0", + "@babel/plugin-syntax-dynamic-import": "^7.2.0", + "@babel/plugin-syntax-object-rest-spread": "^7.2.0", + "@babel/plugin-transform-modules-commonjs": "^7.2.0", + "babel-plugin-import-to-require": "^1.0.0", + "cached-path-relative": "^1.0.2", + "concat-stream": "^1.6.2", + "duplexer2": "^0.1.4", + "through2": "^2.0.5" + } + }, "node_modules/espree": { "version": "9.4.0", "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.0.tgz", @@ -6598,6 +6825,15 @@ "node": ">= 0.10" } }, + "node_modules/invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "dev": true, + "dependencies": { + "loose-envify": "^1.0.0" + } + }, "node_modules/is-arguments": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", @@ -8552,6 +8788,18 @@ "node": ">=0.8.0" } }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, "node_modules/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -11092,6 +11340,22 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/style-loader": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-3.3.1.tgz", + "integrity": "sha512-GPcQ+LDJbrcxHORTRes6Jy2sfvK2kS6hpSfI/fXhPt+spVzxF6LJ1dHLN9zIGmVaaP044YKaIatFaufENRiDoQ==", + "dev": true, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, "node_modules/subarg": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/subarg/-/subarg-1.0.0.tgz", @@ -14765,6 +15029,71 @@ "follow-redirects": "^1.14.0" } }, + "babel-code-frame": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", + "integrity": "sha512-XqYMR2dfdGMW+hd0IUZ2PwK+fGeFkOxZJ0wY+JaQAHzt1Zx8LcvpiZD2NiGkEG8qx0CfkAOr5xt76d1e8vG90g==", + "dev": true, + "requires": { + "chalk": "^1.1.3", + "esutils": "^2.0.2", + "js-tokens": "^3.0.2" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "dev": true + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true + }, + "js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha512-RjTcuD4xjtthQkaWH7dFlH85L+QaVtSoOyGdZ3g6HFhS9dFNDfLyqgm2NFe2X6cQpeFmt0452FJjFG5UameExg==", + "dev": true + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", + "dev": true + } + } + }, "babel-jest": { "version": "29.0.3", "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.0.3.tgz", @@ -14805,6 +15134,15 @@ } } }, + "babel-messages": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", + "integrity": "sha512-Bl3ZiA+LjqaMtNYopA9TYE9HP1tQ+E5dLxE0XrAzcIJeK2UqF0/EaqXwBn9esd4UmTfEab+P+UYQ1GnioFIb/w==", + "dev": true, + "requires": { + "babel-runtime": "^6.22.0" + } + }, "babel-plugin-dynamic-import-node": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", @@ -14814,6 +15152,15 @@ "object.assign": "^4.1.0" } }, + "babel-plugin-import-to-require": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-import-to-require/-/babel-plugin-import-to-require-1.0.0.tgz", + "integrity": "sha512-dc843CwrFivjO8AVgxcHvxl0cb7J7Ed8ZGFP8+PjH3X1CnyzYtAU1WL1349m9Wc/+oqk4ETx2+cIEO2jlp3XyQ==", + "dev": true, + "requires": { + "babel-template": "^6.26.0" + } + }, "babel-plugin-istanbul": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", @@ -14870,10 +15217,9 @@ } }, "babel-plugin-prismjs": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/babel-plugin-prismjs/-/babel-plugin-prismjs-2.1.0.tgz", - "integrity": "sha512-ehzSKYfeAz4U78zi/sfwsjDPlq0LvDKxNefcZTJ/iKBu+plsHsLqZhUeGf1+82LAcA35UZGbU6ksEx2Utphc/g==", + "version": "git+ssh://git@github.com/queengooborg/babel-plugin-prismjs.git#9f810d9cd869fd59267a55057dd259c19d8954dc", "dev": true, + "from": "babel-plugin-prismjs@github:queengooborg/babel-plugin-prismjs#patch-1-build", "requires": {} }, "babel-preset-current-node-syntax": { @@ -14906,6 +15252,103 @@ "babel-preset-current-node-syntax": "^1.0.0" } }, + "babel-runtime": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", + "integrity": "sha512-ITKNuq2wKlW1fJg9sSW52eepoYgZBggvOAHC0u/CYu/qxQ9EVzThCgR69BnSXLHjy2f7SY5zaQ4yt7H9ZVxY2g==", + "dev": true, + "requires": { + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" + }, + "dependencies": { + "regenerator-runtime": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", + "dev": true + } + } + }, + "babel-template": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", + "integrity": "sha512-PCOcLFW7/eazGUKIoqH97sO9A2UYMahsn/yRQ7uOk37iutwjq7ODtcTNF+iFDSHNfkctqsLRjLP7URnOx0T1fg==", + "dev": true, + "requires": { + "babel-runtime": "^6.26.0", + "babel-traverse": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "lodash": "^4.17.4" + } + }, + "babel-traverse": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", + "integrity": "sha512-iSxeXx7apsjCHe9c7n8VtRXGzI2Bk1rBSOJgCCjfyXb6v1aCqE1KSEpq/8SXuVN8Ka/Rh1WDTF0MDzkvTA4MIA==", + "dev": true, + "requires": { + "babel-code-frame": "^6.26.0", + "babel-messages": "^6.23.0", + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "debug": "^2.6.8", + "globals": "^9.18.0", + "invariant": "^2.2.2", + "lodash": "^4.17.4" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "globals": { + "version": "9.18.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", + "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==", + "dev": true + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + } + } + }, + "babel-types": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", + "integrity": "sha512-zhe3V/26rCWsEZK8kZN+HaQj5yQ1CilTObixFzKW1UWjqG7618Twz6YEsCnjfg5gBcJh02DrpCkS9h98ZqDY+g==", + "dev": true, + "requires": { + "babel-runtime": "^6.26.0", + "esutils": "^2.0.2", + "lodash": "^4.17.4", + "to-fast-properties": "^1.0.3" + }, + "dependencies": { + "to-fast-properties": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", + "integrity": "sha512-lxrWP8ejsq+7E3nNjwYmUBMAgjMTZoTI+sdBOpvNyijeDLa29LUn9QaoXAHv4+Z578hbmHHJKZknzxVtvo77og==", + "dev": true + } + } + }, + "babylon": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", + "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", + "dev": true + }, "balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -15675,6 +16118,12 @@ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.1.3.tgz", "integrity": "sha512-Y8L5rp6jo+g9VEPgvqNfEopjTR4OTYct8lXlS8iVQdmnjDvbdbzYe9rjtFCB9egC86JoNCU61WRY+ScjkZpnIg==" }, + "core-js": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", + "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", + "dev": true + }, "core-js-compat": { "version": "3.25.0", "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.25.0.tgz", @@ -16393,6 +16842,24 @@ "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", "dev": true }, + "esmify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/esmify/-/esmify-2.1.1.tgz", + "integrity": "sha512-GyOVgjG7sNyYB5Mbo15Ll4aGrcXZzZ3LI22rbLOjCI7L/wYelzQpBHRZkZkqbPNZ/QIRilcaHqzgNCLcEsi1lQ==", + "dev": true, + "requires": { + "@babel/core": "^7.2.2", + "@babel/plugin-syntax-async-generators": "^7.2.0", + "@babel/plugin-syntax-dynamic-import": "^7.2.0", + "@babel/plugin-syntax-object-rest-spread": "^7.2.0", + "@babel/plugin-transform-modules-commonjs": "^7.2.0", + "babel-plugin-import-to-require": "^1.0.0", + "cached-path-relative": "^1.0.2", + "concat-stream": "^1.6.2", + "duplexer2": "^0.1.4", + "through2": "^2.0.5" + } + }, "espree": { "version": "9.4.0", "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.0.tgz", @@ -17371,6 +17838,15 @@ "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==", "dev": true }, + "invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "dev": true, + "requires": { + "loose-envify": "^1.0.0" + } + }, "is-arguments": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", @@ -18822,6 +19298,15 @@ } } }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, "lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -20776,6 +21261,13 @@ "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true }, + "style-loader": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-3.3.1.tgz", + "integrity": "sha512-GPcQ+LDJbrcxHORTRes6Jy2sfvK2kS6hpSfI/fXhPt+spVzxF6LJ1dHLN9zIGmVaaP044YKaIatFaufENRiDoQ==", + "dev": true, + "requires": {} + }, "subarg": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/subarg/-/subarg-1.0.0.tgz", diff --git a/package.json b/package.json index fe6116d2d..13bc3407a 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "engines": { "node": "^16.0.0 || >=18.0.0" }, + "type": "module", "main": "./lib/mdn-bob.js", "bundlesize": [ { @@ -68,7 +69,8 @@ "format": "prettier --ignore-unknown --check \"*\"", "format:fix": "prettier --ignore-unknown --write \"*\"", "fix": "npm run format:fix", - "test": "npm run format && jest", + "test": "npm run format && npm run jest", + "jest": "JEST_PUPPETEER_CONFIG=jest-puppeteer.config.cjs NODE_OPTIONS=--experimental-vm-modules jest", "perf": "bundlesize", "webpack": "webpack" }, @@ -86,13 +88,14 @@ "@babel/core": "^7.19.0", "@babel/preset-env": "^7.19.0", "babel-loader": "^8.2.5", - "babel-plugin-prismjs": "^2.1.0", + "babel-plugin-prismjs": "github:queengooborg/babel-plugin-prismjs#patch-1-build", "bundlesize": "0.18.1", "clipboard": "^2.0.11", "css-loader": "^6.7.1", "eslint": "^8.2.0", "eslint-config-prettier": "^8.3.0", "eslint-plugin-import": "^2.25.3", + "esmify": "^2.1.1", "http-server": "14.1.1", "husky": "^8.0.1", "jest": "29.0.3", @@ -104,6 +107,7 @@ "prettier-eslint": "15.0.1", "prismjs": "1.29.0", "puppeteer": "17.1.3", + "style-loader": "^3.3.1", "webpack-cli": "^4.10.0" }, "dependencies": { diff --git a/webpack.config.js b/webpack.config.js index 357bf0994..411ad4913 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -1,7 +1,10 @@ -const path = require("path"); -const webpack = require("webpack"); +import { fileURLToPath } from "node:url"; +import { createRequire } from "node:module"; +import webpack from "webpack"; -module.exports = { +const require = createRequire(import.meta.url); + +export default { mode: "production", plugins: [ new webpack.BannerPlugin( @@ -15,7 +18,7 @@ module.exports = { "css-examples-libs": "./editor/js/css-examples-libs.js", }, output: { - path: path.resolve(__dirname, "docs/js"), + path: fileURLToPath(new URL("docs/js", import.meta.url)), }, module: { rules: [