edge.js
Version:
Template engine
468 lines (467 loc) • 15.4 kB
JavaScript
import "node:module";
import { EdgeError } from "edge-error";
import { find, html } from "property-information";
import lodash from "@poppinss/utils/lodash";
import he from "he";
import Macroable from "@poppinss/macroable";
import { EOL } from "node:os";
import stringifyAttributes from "stringify-attributes";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __commonJSMin = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
var __export = (all, symbols) => {
let target = {};
for (var name in all) __defProp(target, name, {
get: all[name],
enumerable: true
});
if (symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
return target;
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
key = keys[i];
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
get: ((k) => from[k]).bind(null, key),
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
});
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
value: mod,
enumerable: true
}) : target, mod));
var require_classnames = /* @__PURE__ */ __commonJSMin(((exports, module) => {
/*!
Copyright (c) 2018 Jed Watson.
Licensed under the MIT License (MIT), see
http://jedwatson.github.io/classnames
*/
(function() {
"use strict";
var hasOwn = {}.hasOwnProperty;
function classNames$1() {
var classes = "";
for (var i = 0; i < arguments.length; i++) {
var arg = arguments[i];
if (arg) classes = appendClass(classes, parseValue(arg));
}
return classes;
}
function parseValue(arg) {
if (typeof arg === "string" || typeof arg === "number") return arg;
if (typeof arg !== "object") return "";
if (Array.isArray(arg)) return classNames$1.apply(null, arg);
if (arg.toString !== Object.prototype.toString && !arg.toString.toString().includes("[native code]")) return arg.toString();
var classes = "";
for (var key in arg) if (hasOwn.call(arg, key) && arg[key]) classes = appendClass(classes, key);
return classes;
}
function appendClass(value, newClass) {
if (!newClass) return value;
if (value) return value + " " + newClass;
return value + newClass;
}
if (typeof module !== "undefined" && module.exports) {
classNames$1.default = classNames$1;
module.exports = classNames$1;
} else if (typeof define === "function" && typeof define.amd === "object" && define.amd) define("classnames", [], function() {
return classNames$1;
});
else window.classNames = classNames$1;
})();
}));
var import_classnames = /* @__PURE__ */ __toESM(require_classnames(), 1);
function definePropertyInformation(property, value) {
html.normal[property] = property;
html.property[property] = {
attribute: property,
boolean: true,
property,
space: "html",
booleanish: false,
commaOrSpaceSeparated: false,
commaSeparated: false,
spaceSeparated: false,
number: false,
overloadedBoolean: false,
defined: false,
mustUseProperty: false,
...value
};
}
definePropertyInformation("x-cloak");
definePropertyInformation("x-ignore");
definePropertyInformation("x-transition:enterstart", {
attribute: "x-transition:enter-start",
property: "x-transition:enterStart",
boolean: false,
spaceSeparated: true,
commaOrSpaceSeparated: true
});
definePropertyInformation("x-transition:enterend", {
attribute: "x-transition:enter-end",
property: "x-transition:enterEnd",
boolean: false,
spaceSeparated: true,
commaOrSpaceSeparated: true
});
definePropertyInformation("x-transition:leavestart", {
attribute: "x-transition:leave-start",
property: "x-transition:leaveStart",
boolean: false,
spaceSeparated: true,
commaOrSpaceSeparated: true
});
definePropertyInformation("x-transition:leaveend", {
attribute: "x-transition:leave-end",
property: "x-transition:leaveEnd",
boolean: false,
spaceSeparated: true,
commaOrSpaceSeparated: true
});
const alpineNamespaces = {
x: "x-",
xOn: "x-on:",
xBind: "x-bind:",
xTransition: "x-transition:"
};
function unallowedExpression(message, filename, loc) {
throw new EdgeError(message, "E_UNALLOWED_EXPRESSION", {
line: loc.line,
col: loc.col,
filename
});
}
function isSubsetOf(expression, expressions, errorCallback) {
if (!expressions.includes(expression.type)) errorCallback();
}
function isNotSubsetOf(expression, expressions, errorCallback) {
if (expressions.includes(expression.type)) errorCallback();
}
function parseJsArg(parser, token) {
return parser.utils.transformAst(parser.utils.generateAST(token.properties.jsArg, token.loc, token.filename), token.filename, parser);
}
function each(collection, iteratee) {
if (Array.isArray(collection)) {
for (let [key, value] of collection.entries()) iteratee(value, key);
return;
}
if (typeof collection === "string") {
let index = 0;
for (let value of collection) iteratee(value, index++);
return;
}
if (collection && typeof collection === "object") for (let [key, value] of Object.entries(collection)) iteratee(value, key);
}
async function asyncEach(collection, iteratee) {
if (Array.isArray(collection)) {
for (let [key, value] of collection.entries()) await iteratee(value, key);
return;
}
if (typeof collection === "string") {
let index = 0;
for (let value of collection) await iteratee(value, index++);
return;
}
if (collection && typeof collection === "object") for (let [key, value] of Object.entries(collection)) await iteratee(value, key);
}
var StringifiedObject = class {
#obj = "";
addSpread(key) {
this.#obj += this.#obj.length ? `, ${key}` : `${key}`;
}
add(key, value, isComputed = false) {
key = isComputed ? `[${key}]` : key;
this.#obj += this.#obj.length ? `, ${key}: ${value}` : `${key}: ${value}`;
}
flush() {
const obj = `{ ${this.#obj} }`;
this.#obj = "";
return obj;
}
};
function stringifyAttributes$1(props, namespace) {
const attributes = Object.keys(props);
if (attributes.length === 0) return "";
return attributes.reduce((result, key) => {
let value = props[key];
key = namespace ? `${namespace}${key}` : key;
if (!value) return result;
if (alpineNamespaces[key] && typeof value === "object") {
result = result.concat(stringifyAttributes$1(value, alpineNamespaces[key]));
return result;
}
const propInfo = find(html, key);
if (!propInfo) return result;
const attribute = propInfo.attribute;
if (value === true) {
result.push(attribute);
return result;
}
if (key === "class") value = `"${(0, import_classnames.default)(value)}"`;
else if (Array.isArray(value)) value = `"${value.join(propInfo.commaSeparated ? "," : " ")}"`;
else value = `"${String(value)}"`;
result.push(`${attribute}=${value}`);
return result;
}, []).join(" ");
}
const seed = "useandom26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict";
let nanoid = (length = 15) => {
let output = "";
const random = crypto.getRandomValues(new Uint8Array(length));
for (let n = 0; n < length; n++) output += seed[63 & random[n]];
return output;
};
var Stacks = class {
#contentSources = /* @__PURE__ */ new Map();
#seededPlaceholders = /* @__PURE__ */ new Map();
#placeholders = /* @__PURE__ */ new Map();
#createPlaceholder(name) {
return `<!-- .stacks.${name} -->`;
}
create(name) {
if (this.#placeholders.has(name)) throw new Error(`Cannot declare stack "${name}" for multiple times`);
const seededPlaceholder = this.#seededPlaceholders.get(name) || [];
this.#seededPlaceholders.delete(name);
this.#placeholders.set(name, [...seededPlaceholder]);
return this.#createPlaceholder(name);
}
pushTo(name, contents) {
let placeholder = this.#placeholders.get(name);
if (!placeholder) {
if (!this.#seededPlaceholders.has(name)) this.#seededPlaceholders.set(name, []);
this.#seededPlaceholders.get(name).push(contents);
return this;
}
placeholder.push(contents);
return this;
}
pushOnceTo(name, sourceId, contents) {
const contentSources = this.#contentSources.get(name);
if (contentSources && contentSources.has(sourceId)) return;
this.pushTo(name, contents);
if (contentSources) contentSources.add(sourceId);
else this.#contentSources.set(name, new Set([sourceId]));
}
fillPlaceholders(contents) {
for (let [name, sources] of this.#placeholders) contents = contents.replace(this.#createPlaceholder(name), sources.join(EOL));
this.#placeholders.clear();
this.#seededPlaceholders.clear();
return contents;
}
};
var ComponentProps = class ComponentProps {
#values;
constructor(values) {
this.#values = values;
Object.assign(this, values);
}
static create(values) {
return new ComponentProps(values);
}
all() {
return this.#values;
}
has(key) {
return lodash.has(this.#values, key);
}
get(key, defaultValue) {
return lodash.get(this.#values, key, defaultValue);
}
only(keys) {
return new ComponentProps(lodash.pick(this.#values, keys));
}
except(keys) {
return new ComponentProps(lodash.omit(this.#values, keys));
}
merge(values) {
if (values.class && this.#values["class"]) {
const classesSet = /* @__PURE__ */ new Set();
(Array.isArray(values.class) ? values.class : [values]).forEach((item) => {
classesSet.add(item);
});
(Array.isArray(this.#values["class"]) ? this.#values["class"] : [this.#values["class"]]).forEach((item) => {
classesSet.add(item);
});
return new ComponentProps({
...values,
...this.#values,
class: Array.from(classesSet)
});
}
return new ComponentProps({
...values,
...this.#values
});
}
mergeIf(conditional, values) {
if (conditional) return this.merge(values);
return this;
}
mergeUnless(conditional, values) {
if (!conditional) return this.merge(values);
return this;
}
toAttrs() {
return htmlSafe(stringifyAttributes$1(this.#values));
}
};
var Props = class {
next;
constructor(props) {
this[Symbol.for("options")] = { props };
Object.assign(this, props);
this.next = new ComponentProps(props);
}
#mergeClassAttributes(props) {
if (props.className) {
if (!props.class) props.class = [];
if (!Array.isArray(props.class)) props.class = [props.class];
props.class = props.class.concat(props.className);
props.className = false;
}
return props;
}
has(key) {
const value = this.get(key);
return value !== void 0 && value !== null;
}
get(key, defaultValue) {
return lodash.get(this.all(), key, defaultValue);
}
all() {
return this[Symbol.for("options")].props;
}
validate(key, validateFn) {
validateFn(key, this.get(key));
}
only(keys) {
return lodash.pick(this.all(), keys);
}
except(keys) {
return lodash.omit(this.all(), keys);
}
serialize(mergeProps, prioritizeInline = true) {
const attributes = prioritizeInline ? lodash.merge({}, this.all(), mergeProps) : lodash.merge({}, mergeProps, this.all());
return htmlSafe(stringifyAttributes(this.#mergeClassAttributes(attributes)));
}
serializeOnly(keys, mergeProps, prioritizeInline = true) {
const attributes = prioritizeInline ? lodash.merge({}, this.only(keys), mergeProps) : lodash.merge({}, mergeProps, this.only(keys));
return htmlSafe(stringifyAttributes(this.#mergeClassAttributes(attributes)));
}
serializeExcept(keys, mergeProps, prioritizeInline = true) {
const attributes = prioritizeInline ? lodash.merge({}, this.except(keys), mergeProps) : lodash.merge({}, mergeProps, this.except(keys));
return htmlSafe(stringifyAttributes(this.#mergeClassAttributes(attributes)));
}
};
var SafeValue = class {
constructor(value) {
this.value = value;
}
};
function escape(input) {
return input instanceof SafeValue ? input.value : he.escape(String(input));
}
function htmlSafe(value) {
return new SafeValue(value);
}
var Template = class extends Macroable {
#compiler;
#processor;
#sharedState;
stacks = new Stacks();
constructor(compiler, globals, locals, processor) {
super();
this.#compiler = compiler;
this.#processor = processor;
this.#sharedState = compiler.compat ? lodash.merge({}, globals, locals) : {
...globals,
...locals
};
}
#trimTopBottomNewLines(value) {
return value.replace(/^\n|^\r\n/, "").replace(/\n$|\r\n$/, "");
}
#renderCompiled(compiledTemplate, state) {
const templateState = {
...this.#sharedState,
...state
};
const $context = {};
if (this.#compiler.async) return compiledTemplate(this, templateState, $context).then((output$1) => {
output$1 = this.#trimTopBottomNewLines(output$1);
output$1 = this.stacks.fillPlaceholders(output$1);
return this.#processor.executeOutput({
output: output$1,
template: this,
state: templateState
});
});
let output = this.#trimTopBottomNewLines(compiledTemplate(this, templateState, $context));
output = this.stacks.fillPlaceholders(output);
return this.#processor.executeOutput({
output,
template: this,
state: templateState
});
}
compilePartial(templatePath, ...localVariables) {
return this.#compiler.compile(templatePath, localVariables);
}
compileComponent(templatePath) {
return this.#compiler.compile(templatePath);
}
getComponentState(props, slots, caller) {
return {
...this.#sharedState,
...props,
$slots: slots,
$caller: caller,
$props: this.#compiler.compat ? new Props(props) : new ComponentProps(props)
};
}
render(template, state) {
let compiledTemplate = this.#compiler.compile(template);
return this.#renderCompiled(compiledTemplate, state);
}
renderRaw(contents, state, templatePath) {
let compiledTemplate = this.#compiler.compileRaw(contents, templatePath);
return this.#renderCompiled(compiledTemplate, state);
}
escape(input) {
return escape(input);
}
createError(errorMessage, filename, lineNumber, column) {
return new EdgeError(errorMessage, "E_RUNTIME_EXCEPTION", {
filename,
line: lineNumber,
col: column
});
}
newError(errorMessage, filename, lineNumber, column) {
throw this.createError(errorMessage, filename, lineNumber, column);
}
reThrow(error, filename, lineNumber) {
if (error instanceof EdgeError) throw error;
throw new EdgeError(error.message.replace(/state\./, ""), "E_RUNTIME_EXCEPTION", {
filename,
line: lineNumber,
col: 0
});
}
};
var require_js_stringify = /* @__PURE__ */ __commonJSMin(((exports, module) => {
module.exports = stringify;
function stringify(obj) {
if (obj instanceof Date) return "new Date(" + stringify(obj.toISOString()) + ")";
if (obj === void 0) return "undefined";
return JSON.stringify(obj).replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029").replace(/</g, "\\u003C").replace(/>/g, "\\u003E").replace(/\//g, "\\u002F");
}
}));
export { StringifiedObject as a, isNotSubsetOf as c, parseJsArg as d, stringifyAttributes$1 as f, __toESM as g, __export as h, htmlSafe as i, isSubsetOf as l, require_classnames as m, Template as n, asyncEach as o, unallowedExpression as p, escape as r, each as s, require_js_stringify as t, nanoid as u };