create-modulo
Version:
Starter projects for Modulo.html - Ready for all uses - Markdown-SSG / SSR / API-backed SPA
1,648 lines (1,624 loc) • 51.9 kB
JavaScript
import { createRequire } from "node:module";
var __create = Object.create;
var __getProtoOf = Object.getPrototypeOf;
var __defProp = Object.defineProperty;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __toESM = (mod, isNodeMode, target) => {
target = mod != null ? __create(__getProtoOf(mod)) : {};
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
for (let key of __getOwnPropNames(mod))
if (!__hasOwnProp.call(to, key))
__defProp(to, key, {
get: () => mod[key],
enumerable: true
});
return to;
};
var __export = (target, all) => {
for (var name2 in all)
__defProp(target, name2, {
get: all[name2],
enumerable: true,
configurable: true,
set: (newValue) => all[name2] = () => newValue
});
};
var __require = /* @__PURE__ */ createRequire(import.meta.url);
// scripts/node-oludom.mjs
import { readFileSync, writeFileSync } from "node:fs";
// src/parser.mjs
var exports_parser = {};
__export(exports_parser, {
parse: () => parse,
LexHelper: () => LexHelper
});
function parse(parentElem, text, queueScripts = null) {
const { HTMLElement: HTMLElement2 } = parentElem._virtual.window;
const lex = new LexHelper(text, [parentElem], HTMLElement2);
while (lex.text) {
lex.peekOpen();
lex.pushUntil("<");
lex.untilRegExp(/\s*/);
if (lex.text.length < 1) {
break;
}
const c = lex.text.charCodeAt(0);
if (c >= 65 && c <= 122) {
const tag = lex.untilRegExp(/[\s>]/).toUpperCase().trim();
const elem = parentElem.ownerDocument.createElement(tag);
if (elem._isAutoClosing) {
lex.sliceStack(null, elem._autoClosingValue);
lex.sliceStack(tag);
}
while (lex.text.trim() && lex.match !== ">") {
const name2 = lex.untilRegExp(/[\s =>]/).trim();
let value = "";
if (lex.match === "=" && lex.text[0] !== ">") {
value = lex.untilRegExp(/['"\s>]/);
if ((lex.match === '"' || lex.match === "'") && !value.trim()) {
value = lex.until(lex.match);
}
}
if (name2) {
elem.setAttribute(name2, value);
}
}
lex.topOfStack.append(elem);
if (elem.tagName === "SCRIPT" || elem.tagName === "STYLE") {
const close = new RegExp("</" + elem.tagName + "s*>", "i");
elem.nodeValue = lex.untilRegExp(close);
} else if (!elem._isSelfClosing) {
lex.stack.push(elem);
}
} else if (c === 47) {
const tag = lex.until(">").toUpperCase().replace(/[^A-Z0-9_:-]/g, "");
const elem = lex.sliceStack(tag);
if (elem && elem._isDocumentStructure) {
lex.mergeStructuralElement(elem);
}
} else if (c === 33 && lex.text.substr(0, 3) === "!--") {
lex.pushUntil("-->", 8, true);
}
}
if (queueScripts === null) {
parentElem._virtual.resumeDOM();
} else if (queueScripts === false) {
parentElem._virtual.domQueue = [];
}
}
class LexHelper {
constructor(text, tagStack = [], elemCls = null) {
this.text = text;
this.stack = tagStack;
this.elemCls = elemCls;
this.match = "";
this.peekOpen();
}
untilRegExp(regexp) {
const match = this.text.match(regexp) || { 0: "", index: this.text.length };
this.match = match[0];
const leadingText = this.text.substr(0, match.index);
this.text = this.text.substr(match.index + match[0].length);
return leadingText;
}
until(str) {
const index = this.text.indexOf(str);
const leadingText = index === -1 ? this.text : this.text.substr(0, index);
this.text = index === -1 ? "" : this.text.substr(index + str.length);
return leadingText;
}
sliceStack(tagUC, autoClose = 0) {
let searchIndex = this.stack.length;
while (searchIndex > 0) {
searchIndex = searchIndex - 1;
const elem = this.stack[searchIndex];
if (autoClose === 0 ? tagUC === elem.tagName : autoClose <= elem._autoClosingValue) {
this.stack.splice(searchIndex);
this.peekOpen();
return elem;
}
}
return null;
}
peekOpen() {
this.topOfStack = this.stack.length < 1 ? null : this.stack[this.stack.length - 1];
}
pushUntil(str, nodeType = 3, removeMatch = false) {
const elem = new this.elemCls;
let nodeValue = this.until(str);
nodeValue = removeMatch ? nodeValue.substr(str.length) : nodeValue;
elem._setupNode({ nodeType, nodeValue });
this.topOfStack.append(elem);
}
mergeStructuralElement(node) {
let elem = node.ownerDocument;
if (node.tagName !== "HTML") {
elem = elem[node.tagName === "BODY" ? "body" : "head"];
}
if (elem && elem !== node) {
for (const name2 of node.getAttributeNames()) {
elem.setAttribute(name2, node.getAttribute(name2) || "");
}
elem.append(...node.childNodes);
node.remove();
}
}
}
// src/dom.mjs
var exports_dom = {};
__export(exports_dom, {
HTMLElement: () => HTMLElement2,
Event: () => Event,
Attr: () => Attr
});
var ELEMENTS = {
docStructure: { HTML: 1, HEAD: 1, BODY: 1 },
head: { TITLE: 1, LINK: 1, META: 1, TEMPLATE: 1 },
selfClosing: {
AREA: 1,
BASE: 1,
BR: 1,
COL: 1,
COMMAND: 1,
EMBED: 1,
HR: 1,
IMG: 1,
INPUT: 1,
KEYGEN: 1,
LINK: 1,
META: 1,
PARAM: 1,
SOURCE: 1,
TRACK: 1,
WBR: 1
},
autoClosing: {
P: 8,
DT: 7,
DD: 7,
LI: 6,
OPTION: 9,
THEAD: 3,
TH: 5,
TBODY: 3,
TR: 4,
TD: 5,
TFOOT: 3,
COLGROUP: 4
},
literalValue: { SCRIPT: 1, STYLE: 1 }
};
var HTML_CHARS = { quot: '"', gt: ">", lt: "<", apos: "'" };
var DOM_QUEUE_RE = /^(script|iframe|.+-.+)$/i;
var SELF_CLOSING = " />";
class Attr {
constructor(opts) {
if ("value" in opts) {
Object.assign(this, opts);
}
}
cloneNode() {
return new Attr(this);
}
}
class Event {
constructor(type) {
this.type = type;
}
}
class HTMLElement2 {
constructor() {
this._setupNode({
nodeType: 3,
nodeValue: "",
childNodes: [],
isConnected: false,
parentNode: null,
style: {},
_parentIndex: -1,
_attributeNames: [],
_attributeValues: {},
_eventListeners: {}
});
}
_setupNode(opts) {
Object.assign(this, opts);
if (this.tagName) {
this.tagName = this.tagName.toUpperCase();
this._isDocumentStructure = this.tagName in ELEMENTS.docStructure;
this._isHeadPreferred = this.tagName in ELEMENTS.head;
this._isSelfClosing = this.tagName in ELEMENTS.selfClosing;
this._isAutoClosing = this.tagName in ELEMENTS.autoClosing;
this._isLiteralValue = this.tagName in ELEMENTS.literalValue;
this._autoClosingValue = ELEMENTS.autoClosing[this.tagName] || 0;
}
}
_extractContent() {
const { nodeValue, childNodes } = this;
this.nodeValue = undefined;
this.childNodes = [];
return { nodeValue, childNodes };
}
_decodeEntities(text) {
text = text || "";
return text.replace(/&(quot|gt|lt);/ig, (m, eng) => HTML_CHARS[eng]).replace(/&#x([a-f0-9]+);/ig, (m, hex) => String.fromCharCode(parseInt(hex, 16)));
}
remove() {
if (this.parentNode) {
this.parentNode.childNodes.splice(this._parentIndex, 1);
this._parentIndex = -1;
this.parentNode._rebuildNodeIndices();
this.parentNode = null;
}
}
removeChild(searchElem) {
for (const child of this.childNodes) {
if (child === searchElem) {
child.remove();
break;
}
}
}
replaceWith(...items) {
if (this.parentNode) {
for (const item of items) {
this.parentNode.insertBefore(item, this);
}
}
this.remove();
}
append(...items) {
for (const node of items) {
if (node.remove) {
node.remove();
}
this._appendNode(node);
}
}
_appendNode(node) {
if (this.tagName === "BODY" && node._isHeadPreferred) {
return this.ownerDocument.head._appendNode(node);
}
node.parentNode = this;
this.childNodes.push(node);
this._rebuildNodeIndices();
this._checkForConnection(node);
}
_checkForConnection(node) {
if (node.nodeType === 1 && !node.isConnected && this.isConnected && this.tagName !== "TEMPLATE") {
node.isConnected = true;
if (DOM_QUEUE_RE.test(node.tagName)) {
node._virtual.enqueueDOM(node);
if (node._virtual.window.document.readyState === "complete") {
node._virtual.resumeDOM();
}
}
for (const child of node.children) {
node._checkForConnection(child);
}
}
}
_insertNode(node, index) {
const nextNodes = this.childNodes.slice(index);
this.childNodes = this.childNodes.slice(0, index);
this.childNodes.push(node);
this.childNodes.push(...nextNodes);
this._rebuildNodeIndices();
this._checkForConnection(node);
}
appendChild(...items) {
this.append(...items);
}
insertBefore(node, nextSibling) {
if (nextSibling.parentNode !== this || !("_parentIndex" in nextSibling)) {
throw new Error("Invalid insertBefore");
}
this._insertNode(node, nextSibling._parentIndex);
}
_rebuildNodeIndices() {
let i = 0;
for (const node of this.childNodes) {
node._parentIndex = i++;
}
}
isEqualNode(other) {
return this.outerHTML === other.outerHTML;
}
addEventListener(type, listener) {
if (!(type in this._eventListeners)) {
this._eventListeners[type] = [];
}
this._eventListeners[type].push(listener);
}
dispatchEvent(ev) {
for (const listener of this._eventListeners[ev.type] || []) {
listener(ev);
}
}
removeEventListener(evType, listener) {
if (evType in this._eventListeners) {
this._eventListeners[evType] = this._eventListeners[evType].filter((func) => func !== listener);
}
}
get firstChild() {
return this.childNodes.length > 0 ? this.childNodes[0] : null;
}
get firstElementChild() {
return this.children.length > 0 ? this.children[0] : null;
}
get lastChild() {
return this.childNodes.length > 0 ? this.childNodes[this.childNodes.length - 1] : null;
}
get lastElementChild() {
return this.children.length > 0 ? this.children[this.children.length - 1] : null;
}
get nextSibling() {
if (!this.parentNode || this._parentIndex + 1 >= this.parentNode.childNodes.length) {
return null;
}
return this.parentNode.childNodes[this._parentIndex + 1];
}
get previousSibling() {
if (!this.parentNode || this._parentIndex <= 0) {
return null;
}
return this.parentNode.childNodes[this._parentIndex - 1];
}
get textContent() {
if (this.nodeType === 3) {
return this._decodeEntities(this.nodeValue);
} else if (this._isLiteralValue) {
return this.nodeValue;
} else {
return this.childNodes.map((c) => c.textContent).join("");
}
}
set textContent(nodeValue) {
if (this.nodeType === 1 && !this._isLiteralValue) {
this.childNodes = [new HTMLElement2];
this.childNodes[0]._setupNode({ nodeType: 3, nodeValue });
} else {
this.nodeValue = nodeValue;
if (this.tagName === "SCRIPT" && nodeValue) {
this._virtual.enqueueDOM(this);
this._virtual.resumeDOM();
}
}
}
get children() {
return this.childNodes.filter(({ nodeType }) => nodeType === 1);
}
get attributes() {
const make = (name2) => new Attr({ name: name2, value: this.getAttribute(name2) });
return this._attributeNames.map(make);
}
getAttributeNames() {
return this._attributeNames;
}
getAttribute(name2) {
return this._attributeValues[name2.toLowerCase()];
}
setAttribute(name2, value) {
value = value || "";
if (name2 === "/") {
return;
} else if (name2 === "style") {
this.style = {};
for (const decl of (value || "").split(";")) {
const [name3, val] = decl.trim().split(/\s*:\s*/);
this.style[name3] = val;
}
value = this._getStyleAttr();
}
this._updateAttribute(name2, value);
}
_updateAttribute(name2, value) {
if (!this.hasAttribute(name2)) {
this._attributeNames.push(name2);
}
const nameLower = name2.toLowerCase();
value = "" + value;
this._attributeValues[nameLower] = value;
if (this.tagName === "IFRAME" && nameLower in { src: 1, srcdoc: 1 }) {
this.contentWindow = this._virtual.newChild();
this._virtual.enqueueDOM(this);
} else if (this.tagName === "SCRIPT" && nameLower === "src") {
this._virtual.enqueueDOM(this);
}
}
hasAttribute(name2) {
return name2.toLowerCase() in this._attributeValues;
}
_getStyleAttr() {
const kebab = (str) => str.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
const formatProp = (prop) => kebab(prop.trim()) + ": " + this.style[prop];
return Object.keys(this.style).map(formatProp).join("; ");
}
_makeAttributeString() {
if (!("style" in this._attributeValues) && Object.keys(this.style).length > 0) {
this._updateAttribute("style", this._getStyleAttr());
}
let s = "";
function attrValue(value) {
if (/^[a-z0-9_\.]+$/.test(value)) {
return value;
} else if (!value.includes('"')) {
return `"${value}"`;
}
value = value.replace(/'/g, "'");
return `'${value}'`;
}
for (const attrName of this._attributeNames) {
const value = this._attributeValues[attrName.toLowerCase()];
s += " " + attrName + (value ? "=" + attrValue(value) : "");
}
return s;
}
setAttributeNode(node) {
this.setAttribute(node.name, node.value);
}
getAttributeNode(name2) {
return new Attr({ name: name2, value: this._attributeValues[name2.toLowerCase()] });
}
attachShadow(mode) {
this.shadowRoot = this.ownerDocument.createElement("shadow:root");
}
hasChildNodes() {
return this.childNodes.length > 0;
}
set innerHTML(text) {
if (this._isLiteralValue) {
this.textContent = text;
} else {
this.childNodes = [];
this._virtual.parse(this, text);
}
}
get nodeName() {
return this.tagName;
}
get src() {
return this.getAttribute("src");
}
get href() {
return this.getAttribute("href");
}
get id() {
return this.getAttribute("id");
}
get type() {
return this.getAttribute("type");
}
set src(val) {
return this.setAttribute("src", val);
}
set href(val) {
return this.setAttribute("href", val);
}
set id(val) {
return this.setAttribute("id", val);
}
set type(val) {
return this.setAttribute("type", val);
}
get _moduloTagName() {
if (this.isModulo && this.cparts && this.cparts.component && this.cparts.component.conf) {
const { namespace, name: name2 } = this.cparts.component.conf;
return `${namespace}-${name2}`;
}
return (this.tagName || "").toLowerCase();
}
get innerHTML() {
if (this.tagName === "SCRIPT" || this.nodeType === 8) {
return this.nodeValue;
}
let s = "";
for (const child of this.childNodes) {
if (child.nodeType === 3) {
s += child.textContent;
} else if (child.nodeType === 1) {
s += child.outerHTML;
} else if (child.nodeType === 8) {
s += "<!--" + (child.nodeValue || " ") + "-->";
}
}
return s;
}
get outerHTML() {
const tagName = (this.tagName || "").toLowerCase();
if (!tagName) {
return "";
}
let suffix = SELF_CLOSING;
if (this._isLiteralValue) {
suffix = ">" + this.nodeValue + "</" + tagName + ">";
} else if (!this._isSelfClosing) {
suffix = ">" + this.innerHTML + "</" + tagName + ">";
}
return "<" + tagName + this._makeAttributeString() + suffix;
}
querySelector(cssSelector) {
const results = this.querySelectorAll(cssSelector);
if (results.length) {
return results[0];
} else {
return null;
}
}
closest(cssSelector) {
let node = this.parentNode;
while (node) {
if (node._selectorMatches(cssSelector)) {
return node;
}
node = node.parentNode;
}
return null;
}
contains(elem) {
let nodes = this.childNodes;
while (nodes.length) {
const child = nodes.shift();
if (child === elem) {
return true;
} else if (child.childNodes && child.childNodes.length) {
nodes.push(...child.childNodes);
}
}
return false;
}
_selectorMatches(cssSelector) {
const selectors = (cssSelector || "").trim().split(",");
for (const sel of selectors) {
const s = sel.trim();
if (s === "*") {
return true;
}
if (s.toLowerCase() === this.tagName.toLowerCase()) {
return true;
}
if (s.includes("#")) {
const idSplit = s.split("#");
if (this.getAttribute("id") === idSplit[1]) {
return true;
}
}
if (s.includes(".")) {
const classes = s.split(".");
if (classes[0]) {
if (classes[0].toLowerCase() !== this.tagName.toLowerCase()) {
continue;
}
}
if (this.getAttribute("class").split(" ").includes(classes[1])) {
return true;
}
}
if (s.includes("[")) {
const attrs = s.split("[");
if (attrs[0]) {
if (attrs[0].toLowerCase() !== this.tagName.toLowerCase()) {
continue;
}
}
if (attrs[1]) {
let [key, value] = attrs[1].split("=");
if (key.endsWith("$")) {
value = value.replace(/['"]/g, "");
const myVal = this.getAttribute(key.replace(/\$$/, ""));
if (myVal !== null && myVal.endsWith(value)) {
return true;
}
} else {
const myVal = this.getAttribute(key);
if (!value && myVal !== null || value === myVal) {
return true;
}
}
}
}
}
return false;
}
querySelectorAll(cssSelector, breakAfterOne = false) {
const results = [];
for (const node of this.children) {
if (node._selectorMatches(cssSelector)) {
results.push(node);
}
results.push(...node.querySelectorAll(cssSelector));
}
return results;
}
toString() {
return "[object HTMLElement]";
}
}
// src/http.mjs
var exports_http = {};
__export(exports_http, {
encodeURIComponent: () => encodeURIComponent,
encodeURI: () => encodeURI,
decodeURIComponent: () => decodeURIComponent,
URLSearchParams: () => URLSearchParams,
URL: () => URL,
Response: () => Response,
Headers: () => Headers
});
class URL {
constructor(url, baseURL) {
let m = String(url).replace(/^\s+|\s+$/g, "").match(/^([^:\/?#]+:)?(?:\/\/(?:([^:@\/?#]*)(?::([^:@\/?#]*))?@)?(([^:\/?#]*)(?::(\d*))?))?([^?#]*)(\?[^#]*)?(#[\s\S]*)?/);
if (!m) {
throw new RangeError;
}
let protocol = m[1] || "";
let username = m[2] || "";
let password = m[3] || "";
let host = m[4] || "";
let hostname = m[5] || "";
let port = m[6] || "";
let pathname = m[7] || "";
let search = m[8] || "";
let hash = m[9] || "";
if (baseURL !== undefined) {
let base = new this.constructor(baseURL);
let flag = protocol === "" && host === "" && username === "";
if (flag && pathname === "" && search === "") {
search = base.search;
}
if (flag && pathname.charAt(0) !== "/") {
pathname = pathname !== "" ? ((base.host !== "" || base.username !== "") && base.pathname === "" ? "/" : "") + base.pathname.slice(0, base.pathname.lastIndexOf("/") + 1) + pathname : base.pathname;
}
let output = [];
pathname.replace(/^(\.\.?(\/|$))+/, "").replace(/\/(\.(\/|$))+/g, "/").replace(/\/\.\.$/, "/../").replace(/\/?[^\/]*/g, function(p) {
if (p === "/..") {
output.pop();
} else {
output.push(p);
}
});
pathname = output.join("").replace(/^\//, pathname.charAt(0) === "/" ? "/" : "");
if (flag) {
port = base.port;
hostname = base.hostname;
host = base.host;
password = base.password;
username = base.username;
}
if (protocol === "") {
protocol = base.protocol;
}
}
this.origin = protocol + (protocol !== "" || host !== "" ? "//" : "") + host;
this.href = protocol + (protocol !== "" || host !== "" ? "//" : "") + (username !== "" ? username + (password !== "" ? ":" + password : "") + "@" : "") + host + pathname + search + hash;
this.protocol = protocol;
this.username = username;
this.password = password;
this.host = host;
this.hostname = hostname;
this.port = port;
this.pathname = pathname;
this.search = search;
this.hash = hash;
}
toString() {
return this.href;
}
}
class URLSearchParams {
constructor(text) {
if (text && text.startsWith("?")) {
text = text.substring(1);
}
const dec = (s) => decodeURIComponent(s);
this.data = text.split("&").map((s) => s.split("=").map(dec));
}
get(key) {
return (this.getAll(key) || [null])[0];
}
getAll(key) {
return this.data.filter(([k, value]) => k === key).map((p) => p[1]);
}
}
class Response {
constructor(data, url = null) {
this._url = url;
this._data = data;
}
json() {
return new Promise((resolve, reject) => {
try {
resolve(JSON.parse((this._data || "").toString()));
} catch (e) {
reject(e);
}
});
}
text() {
return new Promise((resolve, reject) => {
resolve((this._data || "").toString());
});
}
bytes() {
return new Promise((resolve, reject) => resolve(this._data));
}
}
class Headers {
}
var encodeURIComponent = (text) => {
const re = new RegExp("([^A-Za-z0-9\\-_\\.!~\\*'\\(\\)])", "g");
return text.replace(re, (m, str, ind) => "%" + text.charCodeAt(ind));
};
var decodeURIComponent = (text) => {
return text.replace(/%([a-f0-9][a-f0-9])/ig, (m, num) => String.fromCharCode(num));
};
var encodeURI = encodeURIComponent;
// src/extensions.mjs
var exports_extensions = {};
__export(exports_extensions, {
utils: () => exports_utils,
internal: () => internal,
cli: () => cli
});
// src/utils.mjs
var exports_utils = {};
__export(exports_utils, {
template: () => template,
saveNamedCache: () => saveNamedCache,
runScript: () => runScript,
runFrame: () => runFrame,
rewriteModuleScript: () => rewriteModuleScript,
resolvePath: () => resolvePath,
renderText: () => renderText,
htmShlex: () => htmShlex,
hash: () => hash,
getCachePath: () => getCachePath,
formatConsole: () => formatConsole,
defaultConsole: () => defaultConsole,
Bundler: () => Bundler
});
var SEP = "/";
var SEP_RE = new RegExp(SEP, "g");
var IMPORT_RE = /import\s*(\w+|\{[^\*\}]+\}|\*\s*as\s*\S+)\s*from *("[^"]+"|'[^']+');?/ig;
var EXPORT_RE1 = /\n\s*export\s+(const|let|var)\s+(\w+)/gm;
var EXPORT_RE2 = /\n\s*export\s+(async\s+function\*?|function\*?|class)\s+(\w+)/gm;
var EXPORT_RE3 = /(?:^|\n)\s*export\s+(?:default)?([^]+)$/gm;
var EXPORTFROM_RE = /export\s+(\w+|\{[^\*\}]+\})\s*from/g;
var REMOTES_PATH = "./_cache/remotes/";
var LOCAL_CACHE_NAME_HINT = "local-cache-name-hint";
var _SYM = "_OLUDOM_SYM" + Math.random();
function rewriteAutoExps(content, autoExports) {
const push = (m, m1, m2) => {
autoExports.push(m2);
return `
` + m1 + " " + m2;
};
const pushFrom = (m, m1) => {
autoExports.push(m1);
return `
import ` + m1;
};
return content.replace(EXPORT_RE1, push).replace(EXPORT_RE2, push).replace(EXPORTFROM_RE, pushFrom);
}
function rewriteModuleScript(path, content, paths = [], globalVar = null) {
const glob2 = globalVar || "window.navigator.extensions.internal.modules";
const autoExports = [];
let code = rewriteAutoExps(content, autoExports);
if (autoExports.length) {
code += `export default {${autoExports.join(", ")}}`;
} else if (/=\s*require\(['"].+["']\)/.test(code)) {}
code = code.replace(EXPORT_RE3, `
return $1;`);
const pushImport = (m, m1, m2) => {
const pathCleaned = m2.replace(/(^'|^"|'$|"$)/g, "");
const rpath = resolvePath(path, "..", pathCleaned);
const mpath = JSON.stringify(rpath);
paths.push(rpath);
const name2 = m1.replace(/^\*\s*as\s*/, "");
const mod = `(typeof ${glob2}[${mpath}] === "function" ? ` + `(${glob2}[${mpath}] = ${glob2}[${mpath}]())` + ` : ${glob2}[${mpath}])
`;
return `;const ${name2} = ` + mod;
};
code = code.replace(IMPORT_RE, pushImport);
return `${glob2}[${JSON.stringify(path)}]=function (){${code}}`;
}
function resolvePath(...args) {
let dirParts = [];
for (const path of args) {
if (path.startsWith(SEP)) {
dirParts = path.split(SEP_RE);
continue;
}
for (const part of path.split(SEP_RE)) {
if (part.startsWith(".")) {
if (part === "..") {
dirParts.pop();
}
} else if (part) {
dirParts.push(part);
}
}
}
return dirParts.join(SEP);
}
function formatConsole(args) {
const newArgs = [];
let ignoreNext = false;
for (let str of args) {
if (ignoreNext) {
ignoreNext = false;
continue;
} else if (typeof str === "object") {
try {
if ("outerHTML" in str) {
str = str.outerHTML;
} else {
str = JSON.stringify(str, null, 2);
}
} catch (e) {}
} else if (str && str.startsWith && str.startsWith("%c")) {
str = str.substr(2);
ignoreNext = true;
}
newArgs.push(str);
}
return newArgs;
}
var defaultCSyms = {
log: "| ",
group: "|----+",
groupEnd: "|----+---",
error: "|!ERR|",
info: "|(i) |",
warn: "|WARN|"
};
var cCount = 0;
function defaultConsole(method, args) {
const sym = method === "count" ? `|${++cCount}|` : defaultCSyms[method];
console.log(sym, ...args);
}
function hash(str) {
let h = 0;
for (let i = 0;i < str.length; i++) {
h = Math.imul(31, h) + str.charCodeAt(i) | 0;
}
const hash8 = ("---------" + (h || 0).toString(32)).slice(-8);
return hash8.replace(/-/g, "0");
}
async function runScriptClassic(elem) {
if (elem.__run) {
return;
}
elem.__run = true;
const EXE_TYPES = { javascript: 1, "application/javascript": 1, module: 1 };
const type = elem.getAttribute("type");
if (type && !(type in EXE_TYPES)) {
return;
}
if (elem.closest("template")) {
return;
}
let code = elem.nodeValue;
let src = elem.hasAttribute("src") ? elem.getAttribute("src") : "";
if (src) {
code = await (await elem._virtual.window.fetch(src)).text();
}
if (type !== "module") {
elem._virtual.window.Function(code)();
return;
}
const { internal } = elem._virtual.window.navigator.extensions;
code = rewriteModuleScript(src, code, internal.moduleQueue);
elem._virtual.window.Function(code)();
while (internal.moduleQueue.length > 0) {
const pathWithQuotes = internal.moduleQueue.shift();
const src2 = pathWithQuotes.replace(/(^'|^"|'$|"$)/g, "");
if (!(src2 in internal.modules)) {
const script2 = elem._virtual.document.createElement("script");
script2.setAttribute("type", "module");
script2.setAttribute("src", src2);
await runScriptClassic(script2);
}
}
if (elem.isConnected) {
const script2 = elem._virtual.document.createElement("script");
const glob2 = "window.navigator.extensions.internal.modules";
script2.nodeValue = `${glob2}[${JSON.stringify(src)}]();`;
elem._virtual.enqueueDOM(script2);
}
}
function htmShlex(elem, line) {
const win = elem._virtual.window;
let e = elem.firstElementChild;
const isOpening = /^<([a-z0-9\._:-]+)/i;
const isCommand = /^[^<#\u001b]/;
const isClosing = RegExp("(</" + (e ? e.tagName : "") + "|/) *>\\s*$", "i");
const proc = {};
if (isCommand.test(line)) {
line = "<" + line + " />";
}
if (e || isOpening.test(line)) {
elem._shellBuffer = (elem._shellBuffer || "") + line;
elem.innerHTML = elem._shellBuffer;
if (elem._shellBuffer.endsWith("/>")) {
e = elem.firstElementChild;
proc.Sync = true;
proc.stdin = "-";
}
}
if (e && isClosing.test(line)) {
proc.Params = `?argv=${e.tagName.toLowerCase()}`;
for (let name2 of e.getAttributeNames()) {
let value = e.getAttribute(name2);
if (!value || /^(a|argv)[0-9]+/i.test(name2)) {
value = value ? value : name2;
name2 = "argv";
} else {
proc[name2] = value;
}
proc.Params += `&${name2}=${win.encodeURIComponent(value)}`;
}
proc.Params += "stdin" in proc ? "" : "&stdin=PROC";
proc.Content = (proc.content || "") + (e.innerHTML || "");
proc.File = (proc.href || win.location.href) + proc.Params;
elem.innerHTML = "";
elem._shellBuffer = "";
}
return proc;
}
function renderText(elem, settings = null) {
const win = elem._virtual.window;
settings = settings || {
wordWrap: 80,
tagsToSkip: { SCRIPT: 1, TEMPLATE: 1, TITLE: 1 },
preTags: { PRE: 1, CODE: 1, TT: 1 }
};
const wwRegExp = new RegExp(`(?![^\\n]{1,${settings.wordWrap}}$)` + `([^\\n]{1,${settings.wordWrap}})\\s`, "g");
const wordWrap = (s) => s.replace(wwRegExp, `$1
`);
const clean = (s) => s.replace(/[\n\s]+/g, " ").trim();
for (const child of elem.childNodes) {
if (child.tagName && child.tagName in settings.tagsToSkip) {
continue;
}
let text = child.textContent || "";
if (!(child.tagName in settings.preTags)) {
text = wordWrap(clean(text)).trim();
}
if (text) {
win.console.log(text);
}
}
}
async function saveNamedCache(win, url, path) {
const headers = {};
headers[LOCAL_CACHE_NAME_HINT] = path;
await win.fetch(url, { method: "OPTIONS", headers });
}
function template(string, context, regexp = /\{\{(.*?)\}\}/g) {
return string.replace(regexp, (m, c) => context[c.trim().toLowerCase()]);
}
function getCachePath(win, urlStr) {
const url = new win.URL(urlStr, win.location.toString());
const hashCode = hash(url.toString());
const filename = url.pathname.split("/").pop() || hashCode;
const filePath = `${url.protocol}${url.host}/${hashCode}/${filename}`;
return REMOTES_PATH + filePath;
}
class Bundler {
constructor(loaders, config) {
this.files = {};
this.copyFiles = {};
this.queue = [];
this.prefix = [config.jsPrefix || `var ${config.globalVar}={};`];
this.suffix = [config.jsSuffix || ""];
Object.assign(this, { loaders, config });
}
rewriteModule(path, code) {
return rewriteModuleScript(path, code, this.queue, this.config.globalVar);
}
async add(path, isMain = false) {
const ext = (path.split(/[:\.]/g).pop() || "").toLowerCase();
const finder = ({ types, match }) => match ? match(path) : (ext in types);
const modPath = path.replace(/\.([a-z0-9]+):[a-z0-9]+$/i, ".$1");
if (modPath in this.files) {
return;
}
if (isMain && modPath === path) {
this.suffix.push(`${this.config.globalVar}["${modPath}"]();`);
}
const loader = this.loaders.find(finder);
this.files[modPath] = await loader.load(modPath, this);
if (loader.copy) {
this.copyFiles[modPath] = loader.copy;
}
}
async addQueue(path) {
while (this.queue.length > 0) {
const pathWithQuotes = this.queue.shift();
const src = pathWithQuotes.replace(/(^'|^"|'$|"$)/g, "");
await this.add(src);
}
}
generate(filenamePrefix, ext = "js") {
this.prefix.sort();
this.suffix.sort();
const order = Object.keys(this.files);
order.sort();
const results = this.prefix.concat(order.map((k) => this.files[k]));
results.push(...this.suffix);
const content = results.join(`
`);
this.filename = `${filenamePrefix}.${hash(content)}.${ext}`;
return content;
}
}
async function runFrame(elem, force = false) {
const src = elem.src || "about:blank";
if (!elem.hasAttribute("srcdoc") && src === "about:blank") {
return;
}
if (elem.__run && (html || elem.src) === elem.__run && !force) {
return;
}
if (elem.closest("template")) {
return;
}
let html = null;
if (elem.hasAttribute("srcdoc")) {
html = elem.getAttribute("srcdoc");
elem.__run = html;
} else {
elem.__run = src;
html = await (await elem._virtual.window.fetch(src)).text();
}
elem.contentWindow._readyFrame();
elem.contentWindow.window.parent = elem._virtual.window;
elem.contentWindow.window.location = new elem.contentWindow.window.URL(src);
elem.contentWindow.document._loadPage(html);
}
var runScript = runScriptClassic;
// src/extensions.mjs
class FileStore {
constructor(name2) {
this.name = name2;
this.data = { fdata: {}, log: [] };
this.subscribers = [];
}
getItem(path) {
return path in this.data.fdata ? this.data.fdata[path] : null;
}
removeItem(key, val) {
this.setItem(key, null);
}
propagate(name2, val, origin = null, filename = null) {
for (const sub of this.subscribers) {
if (sub === origin) {
continue;
}
if (filename && "fileCallback" in sub) {
sub.fileCallback(filename, val);
} else if ("stateChangedCallback" in sub) {
sub.stateChangedCallback(name2, val, origin);
} else {
throw new Error("Invalid subscriber: ", sub);
}
}
}
setItem(key, val) {
this.data.fdata[key] = val;
this.propagate("fdata", this.data.fdata, this, key);
this.data.log.push([key, new Date().getTime() / 1000]);
this.propagate("log", this.data.log, this);
}
}
var internal = {
cache: new FileStore("CACHE"),
modules: {},
moduleQueue: []
};
var cli = { FileStore };
// src/window.mjs
function newWindow(consoleFunction = null) {
const vwindow = Object.assign({ Document }, exports_parser, exports_dom, exports_http);
const win = Object.assign({ _queue: [] }, vwindow);
win.window = win;
win.customElements = newCustomElements(win);
win.Function = newInjectedFunction(win);
win.eval = (code) => new Function("return " + code)();
win.history = { pushState: () => {} };
win.setTimeout = (func) => win._queue.push(func);
win.__yield = () => {
let count = 0;
while (win._queue.length) {
win._queue.shift()();
count++;
}
return count;
};
win.navigator = {
extensions: Object.assign({ modules: {} }, exports_extensions),
userAgent: "oludom"
};
const { defaultConsole: defaultConsole2, formatConsole: formatConsole2 } = exports_utils;
consoleFunction = consoleFunction || defaultConsole2;
const log = (method, args) => consoleFunction(method, formatConsole2(args), args);
win.console = Object.assign({
log: (...args) => log("log", args),
group: (...args) => log("group", args),
groupEnd: (...args) => log("groupEnd", args),
error: (...args) => log("error", args),
info: (...args) => log("info", args),
warn: (...args) => log("warn", args),
count: (...args) => log("count", args)
});
win.sessionStorage = new cli.FileStore("sessionStorage");
win.localStorage = new cli.FileStore("localStorage");
win.document = new Document;
win.document._setupParentWindowFrame(null);
win.frames = [];
win.addEventListener = (...args) => win.document.addEventListener(...args);
win.dispatchEvent = (...args) => win.document.dispatchEvent(...args);
return win;
}
function newCustomElements(win) {
return {
unknown: {},
_upgrade: (name2) => {
name2 = name2.toUpperCase();
for (const elemRef of win.customElements.unknown[name2] || []) {
const elem = "deref" in elemRef ? elemRef.deref() : elemRef;
if (elem && elem.tagName && elem.tagName === name2) {
const newElem = elem.ownerDocument.createElement(elem.tagName);
newElem._attributeNames = elem._attributeNames;
newElem._attributeValues = elem._attributeValues;
newElem.append(...elem.childNodes);
elem.replaceWith(newElem);
newElem.connectedCallback();
}
}
delete win.customElements.unknown[name2];
},
elemClasses: {},
define: (name2, elemClass) => {
name2 = name2.toUpperCase();
win.customElements.elemClasses[name2] = elemClass;
win.customElements._upgrade(name2);
}
};
}
function newInjectedFunction(win) {
return function InjectedFunction(...params) {
const code = params.pop();
const globalParams = Object.keys(win).filter((key) => code.includes(key));
const newGlobals = globalParams.filter((key) => !params.includes(key));
const func = Function(...newGlobals.concat(params), code);
return (...args) => func(...newGlobals.map((key) => win[key]), ...args);
};
}
class Document extends HTMLElement2 {
_setupParentWindowFrame(parentWindow) {
this._setupNode({ nodeType: 1, tagName: "HTML" });
this._virtual = parentWindow;
this.isConnected = true;
}
toString() {
return (this._doctype ? this._doctype + `
` : "") + this.outerHTML;
}
_loadPage(pageContent) {
this.head = this.createElement("head");
this.body = this.createElement("body");
this.append(this.head, this.body);
this._setupOwnerDocument(this);
if (pageContent !== null) {
if (/^\s*<[!\?][^-]/.test(pageContent)) {
this._doctype = pageContent.split(">")[0] + ">";
pageContent = pageContent.substr(this._doctype.length);
}
this.addEventListener("DOMContentLoaded", () => {
this.readyState = "complete";
});
this.write(pageContent);
}
}
_setupOwnerDocument(elem, opts) {
elem.documentElement = this;
elem.ownerDocument = this;
elem._virtual = this._virtual;
}
write(pageContent) {
if (this.readyState === "complete") {
throw new Error("Attempt to write to closed document.");
}
this._virtual.parse(this.body, pageContent, true);
}
getElementById(id) {
return this.querySelector("#" + id);
}
createElement(tagName) {
const win = this._virtual.window;
const classes = win.customElements.elemClasses;
const key = tagName.toUpperCase();
const HTMLElement3 = key in classes ? classes[key] : win.HTMLElement;
const elem = new HTMLElement3;
this._setupOwnerDocument(elem);
elem._setupNode({ nodeType: 1, tagName });
return elem;
}
createElementNS(namespace, tagName) {
return this.createElement(name);
}
createTextNode(text) {
const tn = new HTMLElement;
tn.nodeValue = text;
return tn;
}
}
class WindowFrame {
constructor(options) {
this.interceptor = options.interceptor;
this.options = options;
this.logger = this.options.logger;
this.prompter = this.options.prompter;
this.cliSettings = this.options.cliSettings;
this.vwindow = Object.assign({ Document }, exports_parser, exports_dom, exports_http);
this.domQueue = [];
this._readyFrame();
}
newChild() {
const frame = new WindowFrame(this.options);
frame.window.parent = this.window;
frame.window.location = new frame.window.URL("about:blank");
this.window.frames.push(frame);
this.window.setTimeout(this.resumeDOM.bind(this), 0);
return frame;
}
_readyFrame() {
this.parse = this.vwindow.parse;
const win = newWindow(this.options.consoleFunction);
this.window = win;
this.document = win.document;
win.fetch = this.fetch.bind(this);
win.prompt = this.prompter;
win.confirm = this.confirmer;
win.__isPromptInteractive = this.options.isInteractive;
win.document._setupParentWindowFrame(this);
}
fetch(...args) {
let url = args[0] || "";
const opts = args[1] || { method: "GET", headers: {} };
return new Promise((resolve, reject) => {
this.fetchInterceptedSync(resolve, reject, opts.method, url, opts.headers);
});
}
fetchInterceptedSync(resolve, reject, method, url, headers) {
const opts = {
request: { method, url, headers },
window: this.window
};
const response = this.interceptor.beforeSyncRequest(opts);
if (!response || !("body" in response) || response.body === null) {
reject(new Error(`File access error: ${url} not found (local 404)`));
} else {
resolve(new this.window.Response(response.body));
}
}
fetchSync(url) {
const opts = {
request: { method: "GET", url },
window: this.window
};
const response = this.interceptor.beforeSyncRequest(opts);
if (!response) {
return null;
}
return response.body;
}
navigate(url) {
this._readyFrame();
this.window.location = new this.window.URL(url);
return this.fetch(url).then((response) => response.text()).then((pageContent) => this.document._loadPage(pageContent));
}
tryDispatch(evName) {
let err = null;
const ev = new this.window.Event(evName);
try {
this.window.__yield();
this.window.document.dispatchEvent(ev);
this.window.__yield();
} catch (e) {
err = e;
}
return err;
}
enqueueDOM(elem) {
const { elemClasses, unknown } = this.window.customElements;
if (elem.tagName === "IFRAME") {
this.domQueue.push(elem);
} else if (elem.tagName === "SCRIPT" || elem.tagName in elemClasses) {
this.domQueue.push(elem);
} else {
unknown[elem.tagName] = unknown[elem.tagName] || [];
unknown[elem.tagName].push(new WeakRef(elem));
}
}
async resumeDOM() {
const { elemClasses, unknown } = this.window.customElements;
const nodes = [];
while (this.domQueue.length > 0) {
const elem = this.domQueue.shift();
if (elem.tagName === "SCRIPT") {
await exports_utils.runScript(elem);
} else if (elem.tagName === "IFRAME") {
await exports_utils.runFrame(elem);
} else {
const content = elem._extractContent();
nodes.push([elem, content]);
}
}
for (const [elem, content] of nodes) {
if ("connectedCallback" in elem) {
elem.connectedCallback();
} else if (!(elem.tagName in elemClasses)) {
unknown[elem.tagName] = unknown[elem.tagName] || [];
unknown[elem.tagName].push(new WeakRef(elem));
}
Object.assign(elem, content);
}
for (const frame of this.window.frames) {
await frame.resumeDOM();
}
}
async domContentYield() {
let errs = [];
try {
await this.resumeDOM();
this.window.__yield();
} catch (e) {
errs.push(e);
}
const ev = new this.window.Event("DOMContentLoaded");
const all = this.window.document._eventListeners[ev.type];
for (const listener of all || [() => {}]) {
try {
await this.resumeDOM();
this.window.__yield();
await listener(ev);
await this.resumeDOM();
this.window.__yield();
} catch (e) {
errs.push(e);
}
}
return errs.length ? errs : null;
}
}
// src/browser.mjs
var silentPrefix = '[JavaScript Warning: "';
function newInterceptor(options) {
const { files, urlPrefix } = options;
const pathPrefix = new URL(urlPrefix).pathname;
function _url2path(url, baseURL = "") {
const base = new URL(baseURL, urlPrefix) + "";
const p = new URL(url, base).pathname;
return p.startsWith(pathPrefix) ? p.replace(pathPrefix, "") : p;
}
function _log404(options2, url) {
console.log("|OLUDOM| ER404 |", url);
console.log("|------+-------+ (Hint:)");
console.log(...options2.argv, url);
console.log("|------+-------+");
}
async function handleConsole(cons, msg) {
const getValue = async (arg) => await arg.jsonValue();
let result = [];
try {
result = await Promise.all(msg.args().map(getValue));
} catch (e) {
cons.error("BROWSER Error occured during log attempt:", e);
}
result = result.filter((s) => s.startsWith && !s.startsWith(silentPrefix));
if (result.length) {
cons.log(...result);
}
}
async function handleRoute(route, baseURL) {
const path = _url2path(route.request().url(), baseURL);
if (path in files) {
await route.fulfill({ path });
} else if (path) {
_log404(options, path);
const body = "404 (OluDOM)";
await route.fulfill({ status: 404, contentType: "text/plain", body });
}
}
function beforeSyncRequest(opts) {
const baseURL = opts.window.location + "";
const path = _url2path(opts.request.url, baseURL);
if (path in files) {
return { body: files[path] };
} else if (path) {
_log404(options, path);
return { body: null };
}
}
return { beforeSyncRequest, handleRoute, handleConsole };
}
class BrowserDownload {
constructor(writeCallback = null) {
this.writeCallback = writeCallback;
}
async fromAnchor(asyncElem = null) {
this.name = await asyncElem.getAttribute("download") || "missing.name";
const href = await asyncElem.getAttribute("href");
this.data = decodeURIComponent(href);
}
suggestedFilename() {
return this.name;
}
async saveAs(path) {
return this.writeCallback(path, this.data);
}
}
class BrowserPage {
constructor(options) {
this.urlPrefix = options.urlPrefix;
this.delay = options.delay;
this.interceptor = options.interceptor || newInterceptor(options);
options.interceptor = this.interceptor;
this.mainFrame = new WindowFrame(options);
this.frames = [this.mainFrame];
}
async saveAnchorAs(aTag, writeCallback) {
if (this.driver && this.driver.waitForEvent) {
const downloadPromise = this.driver.waitForEvent("download");
await aTag.click();
return await downloadPromise;
} else {
const download = new BrowserDownload(writeCallback);
await download.fromAnchor(aTag);
return download;
}
}
async setupPageDriver(page) {
this.driver = page;
const { handleRoute, handleConsole } = this.interceptor;
if (page.on) {
const { console: console2 } = this.mainFrame.window;
page.on("console", async (msg) => await handleConsole(console2, msg));
}
if (page.route) {
await page.route("**/*", (route) => handleRoute(route, this.url));
}
}
async goto(url) {
this.url = this.urlPrefix + url;
if (this.driver) {
delete this.mainFrame;
await this.driver.goto(this.url);
} else {
await this.mainFrame.navigate(this.url);
this.exceptionList = await this.mainFrame.domContentYield();
}
}
locator(sel) {
if (this.driver) {
return this.driver.locator(sel);
} else {
return {
all: async () => this.mainFrame.window.document.querySelectorAll(sel)
};
}
}
async waitUntilComplete() {
if (this.driver && this.driver.waitUntilComplete) {
await this.driver.waitUntilComplete();
} else if (this.driver && this.driver.waitForLoadState) {
await this.driver.waitForLoadState("networkidle");
} else if (this.mainFrame) {
await this.mainFrame.resumeDOM();
this.mainFrame.window.__yield();
}
if (this.delay && this.driver && this.driver.waitForTimeout) {
await this.driver.waitForTimeout(this.delay);
}
}
}
class Browser {
constructor(options) {
this.configureDefaults(options);
this.options = options;
this.pages = [];
this.driver = null;
}
async readyDriver() {
if (!this.options.driver) {
return null;
}
this.driver = await this.options.driver.launch(this.options);
}
configureDefaults(options) {
options.server = Object.assign({
proto: "http",
host: "local.oludom",
port: 80,
path: ""
}, options.server);
const s = options.server;
let prefix = `${s.proto}://`;
if (!(s.proto in { file: 1, about: 1 })) {
const port = `:${s.port}`;
prefix += s.host + (port === ":80" ? "" : port);
}
options.urlPrefix = prefix + (s.path || "") + "/";
}
async newPage() {
await this.readyDriver();
const page = new BrowserPage(this.options);
if (this.driver) {
const pageDriver = await this.driver.newPage();
await page.setupPageDriver(pageDriver);
}
this.pages.push(page);
return page;
}
async close() {
if (this.driver && this.driver.close) {
await this.driver.close();
} else {
for (const page of this.pages) {
await page.waitUntilComplete();
}
}
}
}
// src/cli.mjs
async function runSync(argv, readFileSync, writeFileSync) {
const readable = {};
const writable = {};
let saveAsPath = null;
const exeFrames = [];
let count = 0;
const options = { argv, download: "a[download]", delay: 3000 };
for (let url of argv) {
if (url.endsWith("node") && url === argv[0] || url.endsWith("-oludom.mjs") && url === argv[1]) {
continue;
}
if (url.startsWith("--")) {
await configure(url.slice(2, url.length), options);
continue;
}
if (url.includes("?")) {
exeFrames.push(url);
url = url.replace(/\?.*$/, "");
} else if (url.startsWith("_")) {
saveAsPath = saveAsPath || url;
writable[url] = true;
continue;
} else if (options.skipRead) {
readable[url] = 1;
}
try {
readable[url] = readFileSync(url, "utf8");
} catch (e) {
console.error("Oludom Cannot Read ERROR:", url);
console.error(e);
console.log("To run again, allowing access:");
console.log(`---
`);
console.log(...argv, url);
}
}
options.files = readable;
const browser = new Browser(options);
if (!exeFrames.length) {
console.log('ERROR, no file to execute: At least one argument must have a "?"');
console.log("Example 1: oludom file.html?");
console.log("Example 2: oludom index.html? _build _cache *.* **/*.*");
console.log(`---
`);
console.log(...argv, "index.html?");
} else {
for (const