Socket
Socket
Sign inDemoInstall

edge.js

Package Overview
Dependencies
11
Maintainers
2
Versions
64
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 6.0.0-1 to 6.0.0-2

build/index-d8c609be.d.ts

344

build/index.d.ts

@@ -1,339 +0,5 @@

import { Parser } from 'edge-parser';
import { TagToken, Token } from 'edge-lexer/types';
import { ProcessorContract, TemplateContract, CacheManagerContract, LoaderTemplate, CompilerContract, LoaderContract, TagsContract, CompilerOptions, EdgeContract, TagContract, EdgeOptions, EdgeRendererContract } from './src/types.js';
import { ClaimTagFn } from 'edge-parser/types';
/**
* Exposes the API to register a set of handlers to process the
* templates output at different stages
*/
declare class Processor implements ProcessorContract {
#private;
/**
* Execute tag handler
*/
executeTag(data: {
tag: TagToken;
path: string;
}): void;
/**
* Execute raw handlers
*/
executeRaw(data: {
raw: string;
path: string;
}): string;
/**
* Execute compiled handlers
*/
executeCompiled(data: {
compiled: string;
path: string;
}): string;
/**
* Execute output handlers
*/
executeOutput(data: {
output: string;
template: TemplateContract;
state: Record<string, any>;
}): string;
/**
* Define a processor function
*/
process(event: 'raw', handler: (data: {
raw: string;
path: string;
}) => string | void): this;
process(event: 'tag', handler: (data: {
tag: TagToken;
path: string;
}) => void): this;
process(event: 'compiled', handler: (data: {
compiled: string;
path: string;
}) => string | void): this;
process(event: 'output', handler: (data: {
output: string;
template: TemplateContract;
state: Record<string, any>;
}) => string | void): this;
}
/**
* In memory cache manager to cache pre-compiled templates.
*/
declare class CacheManager implements CacheManagerContract {
#private;
enabled: boolean;
constructor(enabled: boolean);
/**
* Returns a boolean to tell if a template has already been cached
* or not.
*/
has(absPath: string): boolean;
/**
* Returns the template from the cache. If caching is disabled,
* then it will return undefined.
*/
get(absPath: string): undefined | LoaderTemplate;
/**
* Set's the template path and the payload to the cache. If
* cache is disabled, then this function results in a noop.
*/
set(absPath: string, payload: LoaderTemplate): void;
/**
* Delete template from the compiled cache
*/
delete(absPath: string): void;
}
/**
* Compiler is to used to compile templates using the `edge-parser`. Along with that
* it natively merges the contents of a layout with a parent template.
*/
declare class Compiler implements CompilerContract {
#private;
/**
* Caches compiled templates
*/
cacheManager: CacheManager;
/**
* Know if compiler is compiling for the async mode or not
*/
async: boolean;
constructor(loader: LoaderContract, tags: TagsContract, processor: Processor, options?: CompilerOptions);
/**
* Define a function to claim tags
*/
claimTag(fn: ClaimTagFn): this;
/**
* Converts the template content to an array of lexer tokens. The method is
* same as the `parser.tokenize`, but it also handles layouts natively.
*
* ```
* compiler.tokenize('<template-path>')
* ```
*/
tokenize(templatePath: string, parser?: Parser): Token[];
/**
* Tokenize a raw template
*/
tokenizeRaw(contents: string, templatePath?: string, parser?: Parser): Token[];
/**
* Compiles the template contents to string. The output is same as the `edge-parser`,
* it's just that the compiler uses the loader to load the templates and also
* handles layouts.
*
* ```js
* compiler.compile('welcome')
* ```
*/
compile(templatePath: string, localVariables?: string[], skipCache?: boolean): LoaderTemplate;
/**
* Compiles the template contents to string. The output is same as the `edge-parser`,
* it's just that the compiler uses the loader to load the templates and also
* handles layouts.
*
* ```js
* compiler.compile('welcome')
* ```
*/
compileRaw(contents: string, templatePath?: string): LoaderTemplate;
}
/**
* Exposes the API to render templates, register custom tags and globals
*/
declare class Edge implements EdgeContract {
#private;
/**
* Reference to the registered processor handlers
*/
processor: Processor;
/**
* Globals are shared with all rendered templates
*/
GLOBALS: {
[key: string]: any;
};
/**
* List of registered tags. Adding new tags will only impact
* this list
*/
tags: {
[name: string]: TagContract;
};
/**
* The loader to load templates. A loader can read and return
* templates from anywhere. The default loader reads files
* from the disk
*/
loader: LoaderContract;
/**
* The underlying compiler in use
*/
compiler: Compiler;
/**
* The underlying compiler in use
*/
asyncCompiler: Compiler;
constructor(options?: EdgeOptions);
/**
* Execute plugins. Since plugins are meant to be called only
* once we empty out the array after first call
*/
private executePlugins;
/**
* Register a plugin. Plugin functions are called once just before
* an attempt to render a view is made.
*/
use<T extends any>(pluginFn: (edge: this, firstRun: boolean, options: T) => void, options?: T): this;
/**
* Mount named directory to use views. Later you can reference
* the views from a named disk as follows.
*
* ```
* edge.mount('admin', join(__dirname, 'admin'))
*
* edge.render('admin::filename')
* ```
*/
mount(diskName: string, dirPath?: string): this;
/**
* Un Mount a disk from the loader.
*
* ```js
* edge.unmount('admin')
* ```
*/
unmount(diskName: string): this;
/**
* Add a new global to the edge globals. The globals are available
* to all the templates.
*
* ```js
* edge.global('username', 'virk')
* edge.global('time', () => new Date().getTime())
* ```
*/
global(name: string, value: any): this;
/**
* Add a new tag to the tags list.
*
* ```ts
* edge.registerTag('svg', {
* block: false,
* seekable: true,
*
* compile (parser, buffer, token) {
* const fileName = token.properties.jsArg.trim()
* buffer.writeRaw(fs.readFileSync(__dirname, 'assets', `${fileName}.svg`), 'utf-8')
* }
* })
* ```
*/
registerTag(tag: TagContract): this;
/**
* Register an in-memory template.
*
* ```ts
* edge.registerTemplate('button', {
* template: `<button class="{{ this.type || 'primary' }}">
* @!yield($slots.main())
* </button>`,
* })
* ```
*
* Later you can use this template
*
* ```edge
* @component('button', type = 'primary')
* Get started
* @endcomponent
* ```
*/
registerTemplate(templatePath: string, contents: LoaderTemplate): this;
/**
* Remove the template registered using the "registerTemplate" method
*/
removeTemplate(templatePath: string): this;
/**
* Get access to the underlying template renderer. Each render call
* to edge results in creating an isolated renderer instance.
*/
onRender(callback: (renderer: EdgeRendererContract) => void): this;
/**
* Returns a new instance of edge. The instance
* can be used to define locals.
*/
getRenderer(): EdgeRendererContract;
/**
* Render a template with optional state
*
* ```ts
* edge.render('welcome', { greeting: 'Hello world' })
* ```
*/
render(templatePath: string, state?: any): Promise<string>;
/**
* Render a template asynchronously with optional state
*
* ```ts
* edge.render('welcome', { greeting: 'Hello world' })
* ```
*/
renderSync(templatePath: string, state?: any): string;
/**
* Render a template with optional state
*
* ```ts
* edge.render('welcome', { greeting: 'Hello world' })
* ```
*/
renderRaw(contents: string, state?: any, templatePath?: string): Promise<string>;
/**
* Render a template asynchronously with optional state
*
* ```ts
* edge.render('welcome', { greeting: 'Hello world' })
* ```
*/
renderRawSync(templatePath: string, state?: any): string;
/**
* Share locals with the current view context.
*
* ```js
* const view = edge.getRenderer()
*
* // local state for the current render
* view.share({ foo: 'bar' })
*
* view.render('welcome')
* ```
*/
share(data: any): EdgeRendererContract;
}
/**
* An instance of this class passed to the escape
* method ensures that underlying value is never
* escaped.
*/
declare class SafeValue {
value: any;
constructor(value: any);
}
/**
* Mark value as safe and not to be escaped
*/
declare function safeValue(value: string): SafeValue;
declare const GLOBALS: Record<string, Function>;
/**
* Default export
*/
declare const edge: Edge;
export { Edge, GLOBALS, edge as default, safeValue };
export { h as Edge } from './index-d8c609be.js';
import 'edge-parser';
import 'edge-lexer/types';
import '@poppinss/macroable';
import 'edge-parser/types';

@@ -7,5 +7,207 @@ var __defProp = Object.defineProperty;

// src/tags/index.ts
var tags_exports = {};
__export(tags_exports, {
// src/loader.ts
import { readFileSync } from "node:fs";
import { fileURLToPath } from "node:url";
import { join, isAbsolute } from "node:path";
var Loader = class {
/**
* List of mounted directories
*/
#mountedDirs = /* @__PURE__ */ new Map();
/**
* List of pre-registered (in-memory) templates
*/
#preRegistered = /* @__PURE__ */ new Map();
/**
* Reads the content of a template from the disk. An exception is raised
* when file is missing or if `readFileSync` returns an error.
*/
#readTemplateContents(absPath) {
try {
return readFileSync(absPath, "utf-8");
} catch (error) {
if (error.code === "ENOENT") {
throw new Error(`Cannot resolve "${absPath}". Make sure the file exists`);
} else {
throw error;
}
}
}
/**
* Extracts the disk name and the template name from the template
* path expression.
*
* If `diskName` is missing, it will be set to `default`.
*
* ```
* extractDiskAndTemplateName('users::list')
* // returns ['users', 'list.edge']
*
* extractDiskAndTemplateName('list')
* // returns ['default', 'list.edge']
* ```
*/
#extractDiskAndTemplateName(templatePath) {
let [disk, ...rest] = templatePath.split("::");
if (!rest.length) {
rest = [disk];
disk = "default";
}
let [template, ext] = rest.join("::").split(".edge");
return [disk, `${template}.${ext || "edge"}`];
}
/**
* Returns an object of mounted directories with their public
* names.
*
* ```js
* loader.mounted
* // output
*
* {
* default: '/users/virk/code/app/views',
* foo: '/users/virk/code/app/foo',
* }
* ```
*/
get mounted() {
return Array.from(this.#mountedDirs).reduce(
(obj, [key, value]) => {
obj[key] = value;
return obj;
},
{}
);
}
/**
* Returns an object of templates registered as a raw string
*
* ```js
* loader.templates
* // output
*
* {
* 'form.label': { template: '/users/virk/code/app/form/label' }
* }
* ```
*/
get templates() {
return Array.from(this.#preRegistered).reduce(
(obj, [key, value]) => {
obj[key] = value;
return obj;
},
{}
);
}
/**
* Mount a directory with a name for resolving views. If name is set
* to `default`, then you can resolve views without prefixing the
* disk name.
*
* ```js
* loader.mount('default', join(__dirname, 'views'))
*
* // mount a named disk
* loader.mount('admin', join(__dirname, 'admin/views'))
* ```
*/
mount(diskName, dirPath) {
this.#mountedDirs.set(diskName, typeof dirPath === "string" ? dirPath : fileURLToPath(dirPath));
}
/**
* Remove the previously mounted dir.
*
* ```js
* loader.unmount('default')
* ```
*/
unmount(diskName) {
this.#mountedDirs.delete(diskName);
}
/**
* Make path to a given template. The paths are resolved from the root
* of the mounted directory.
*
* ```js
* loader.makePath('welcome') // returns {diskRootPath}/welcome.edge
* loader.makePath('admin::welcome') // returns {adminRootPath}/welcome.edge
* loader.makePath('users.list') // returns {diskRootPath}/users/list.edge
* ```
*
* @throws Error if disk is not mounted and attempting to make path for it.
*/
makePath(templatePath) {
if (this.#preRegistered.has(templatePath)) {
return templatePath;
}
if (isAbsolute(templatePath)) {
return templatePath;
}
const [diskName, template] = this.#extractDiskAndTemplateName(templatePath);
const mountedDir = this.#mountedDirs.get(diskName);
if (!mountedDir) {
throw new Error(`"${diskName}" namespace is not mounted`);
}
return join(mountedDir, template);
}
/**
* Resolves the template by reading its contents from the disk
*
* ```js
* loader.resolve('welcome', true)
*
* // output
* {
* template: `<h1> Template content </h1>`,
* }
* ```
*/
resolve(templatePath) {
if (this.#preRegistered.has(templatePath)) {
return this.#preRegistered.get(templatePath);
}
templatePath = isAbsolute(templatePath) ? templatePath : this.makePath(templatePath);
return {
template: this.#readTemplateContents(templatePath)
};
}
/**
* Register in memory template for a given path. This is super helpful
* when distributing components.
*
* ```js
* loader.register('welcome', {
* template: '<h1> Template content </h1>',
* Presenter: class Presenter {
* constructor (state) {
* this.state = state
* }
* }
* })
* ```
*
* @throws Error if template content is empty.
*/
register(templatePath, contents) {
if (typeof contents.template !== "string") {
throw new Error("Make sure to define the template content as a string");
}
if (this.#preRegistered.has(templatePath)) {
throw new Error(`Cannot override previously registered "${templatePath}" template`);
}
this.#preRegistered.set(templatePath, contents);
}
/**
* Remove registered template
*/
remove(templatePath) {
this.#preRegistered.delete(templatePath);
}
};
// src/tags/main.ts
var main_exports = {};
__export(main_exports, {
assign: () => assignTag,
component: () => componentTag,

@@ -16,2 +218,3 @@ debugger: () => debuggerTag,

elseif: () => elseIfTag,
eval: () => evalTag,
if: () => ifTag,

@@ -21,8 +224,5 @@ include: () => includeTag,

inject: () => injectTag,
layout: () => layoutTag,
let: () => letTag,
newError: () => newErrorTag,
section: () => sectionTag,
set: () => setTag,
slot: () => slotTag,
super: () => superTag,
unless: () => unlessTag

@@ -34,4 +234,60 @@ });

// src/utils/index.ts
// src/utils.ts
import classNames from "classnames";
import { EdgeError } from "edge-error";
import { find, html } from "property-information";
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
});
var alpineNamespaces = {
x: "x-",
xOn: "x-on:",
xBind: "x-bind:",
xTransition: "x-transition:"
};
function unallowedExpression(message, filename, loc) {

@@ -44,9 +300,9 @@ throw new EdgeError(message, "E_UNALLOWED_EXPRESSION", {

}
function isSubsetOf(expression, expressions11, errorCallback) {
if (!expressions11.includes(expression.type)) {
function isSubsetOf(expression, expressions12, errorCallback) {
if (!expressions12.includes(expression.type)) {
errorCallback();
}
}
function isNotSubsetOf(expression, expressions11, errorCallback) {
if (expressions11.includes(expression.type)) {
function isNotSubsetOf(expression, expressions12, errorCallback) {
if (expressions12.includes(expression.type)) {
errorCallback();

@@ -102,2 +358,69 @@ }

}
var StringifiedObject = class {
#obj = "";
addSpread(key) {
this.#obj += this.#obj.length ? `, ${key}` : `${key}`;
}
/**
* Add key/value pair to the object.
*
* ```js
* stringifiedObject.add('username', `'virk'`)
* ```
*/
add(key, value, isComputed = false) {
key = isComputed ? `[${key}]` : key;
this.#obj += this.#obj.length ? `, ${key}: ${value}` : `${key}: ${value}`;
}
/**
* Returns the object alike string back.
*
* ```js
* stringifiedObject.flush()
*
* // returns
* `{ username: 'virk' }`
* ```
*/
flush() {
const obj = `{ ${this.#obj} }`;
this.#obj = "";
return obj;
}
};
function stringifyAttributes(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(value, alpineNamespaces[key]));
return result;
}
const propInfo = find(html, key);
const attribute = propInfo.attribute;
if (!propInfo || propInfo.space === "svg") {
return result;
}
if (propInfo.boolean) {
result.push(attribute);
return result;
}
if (key === "class") {
value = `"${classNames(value)}"`;
} else if (Array.isArray(value)) {
value = `"${value.join(propInfo.commaSeparated ? "," : " ")}"`;
} else if (!propInfo.booleanish && !propInfo.number) {
value = `"${String(value)}"`;
}
result.push(`${attribute}=${value}`);
return result;
}, []).join(" ");
}

@@ -131,141 +454,51 @@ // src/tags/if.ts

// src/tags/else.ts
var elseTag = {
block: false,
seekable: false,
tagName: "else",
/**
* Compiles else block node to Javascript else statement
*/
compile(_, buffer, token) {
buffer.writeStatement("} else {", token.filename, -1);
}
};
// src/tags/else_if.ts
// src/tags/let.ts
import { expressions as expressions2 } from "edge-parser";
var elseIfTag = {
import lodash from "@poppinss/utils/lodash";
var letTag = {
block: false,
seekable: true,
tagName: "elseif",
tagName: "let",
noNewLine: true,
/**
* Compiles the else if block node to a Javascript if statement
*/
compile(parser, buffer, token) {
const parsed = parseJsArg(parser, token);
isNotSubsetOf(parsed, [expressions2.SequenceExpression], () => {
unallowedExpression(
`{${token.properties.jsArg}} is not a valid argument type for the @elseif tag`,
token.filename,
parser.utils.getExpressionLoc(parsed)
);
});
buffer.writeStatement(
`} else if (${parser.utils.stringify(parsed)}) {`,
token.filename,
token.loc.start.line
);
}
};
// src/tags/include.ts
import { expressions as expressions3 } from "edge-parser";
var ALLOWED_EXPRESSION = [
expressions3.Identifier,
expressions3.Literal,
expressions3.LogicalExpression,
expressions3.MemberExpression,
expressions3.ConditionalExpression,
expressions3.CallExpression,
expressions3.TemplateLiteral
];
function getRenderExpression(parser, parsedExpression) {
const localVariables = parser.stack.list();
const renderArgs = localVariables.length ? [
parser.utils.stringify(parsedExpression),
localVariables.map((localVar) => `"${localVar}"`).join(",")
] : [parser.utils.stringify(parsedExpression)];
const callFnArgs = localVariables.length ? ["template", "state", "$context", localVariables.map((localVar) => localVar).join(",")] : ["template", "state", "$context"];
return `template.compilePartial(${renderArgs.join(",")})(${callFnArgs.join(",")})`;
}
var includeTag = {
block: false,
seekable: true,
tagName: "include",
/**
* Compiles else block node to Javascript else statement
*/
compile(parser, buffer, token) {
const awaitKeyword = parser.asyncMode ? "await " : "";
const parsed = parseJsArg(parser, token);
isSubsetOf(parsed, ALLOWED_EXPRESSION, () => {
unallowedExpression(
`"${token.properties.jsArg}" is not a valid argument type for the @include tag`,
const parsed = parser.utils.generateAST(
`let ${token.properties.jsArg}`,
token.loc,
token.filename
).declarations[0];
const key = parsed.id;
const value = parsed.init;
isSubsetOf(key, ["ObjectPattern", expressions2.Identifier, "ArrayPattern"], () => {
throw unallowedExpression(
`Invalid variable name for the @let tag`,
token.filename,
parser.utils.getExpressionLoc(parsed)
parser.utils.getExpressionLoc(key)
);
});
buffer.outputExpression(
`${awaitKeyword}${getRenderExpression(parser, parsed)}`,
token.filename,
token.loc.start.line,
false
);
}
};
// src/tags/include_if.ts
import { EdgeError as EdgeError2 } from "edge-error";
import { expressions as expressions4 } from "edge-parser";
var includeIfTag = {
block: false,
seekable: true,
tagName: "includeIf",
if (key.type === "Identifier") {
parser.stack.defineVariable(key.name);
} else if (key.type === "ObjectPattern") {
key.properties.forEach((property) => {
parser.stack.defineVariable(
property.argument ? property.argument.name : property.value.name
);
});
} else if (key.type === "ArrayPattern") {
key.elements.forEach((element) => {
parser.stack.defineVariable(element.argument ? element.argument.name : element.name);
});
}
const expression = `let ${parser.utils.stringify(key)} = ${parser.utils.stringify(
parser.utils.transformAst(value, token.filename, parser)
)}`;
buffer.writeExpression(expression, token.filename, token.loc.start.line);
},
/**
* Compiles else block node to Javascript else statement
* Add methods to the template for running the loop
*/
compile(parser, buffer, token) {
const awaitKeyword = parser.asyncMode ? "await " : "";
const parsed = parseJsArg(parser, token);
isSubsetOf(parsed, [expressions4.SequenceExpression], () => {
unallowedExpression(
`"${token.properties.jsArg}" is not a valid argument type for the @includeIf tag`,
token.filename,
parser.utils.getExpressionLoc(parsed)
);
});
if (parsed.expressions.length !== 2) {
throw new EdgeError2("@includeIf expects a total of 2 arguments", "E_ARGUMENTS_MIS_MATCH", {
line: parsed.loc.start.line,
col: parsed.loc.start.column,
filename: token.filename
});
}
const [conditional, include] = parsed.expressions;
isNotSubsetOf(conditional, [expressions4.SequenceExpression], () => {
unallowedExpression(
`"${conditional.type}" is not a valid 1st argument type for the @includeIf tag`,
token.filename,
parser.utils.getExpressionLoc(conditional)
);
});
isSubsetOf(include, ALLOWED_EXPRESSION, () => {
unallowedExpression(
`"${include.type}" is not a valid 2nd argument type for the @includeIf tag`,
token.filename,
parser.utils.getExpressionLoc(include)
);
});
buffer.writeStatement(
`if (${parser.utils.stringify(conditional)}) {`,
token.filename,
token.loc.start.line
);
buffer.outputExpression(
`${awaitKeyword}${getRenderExpression(parser, include)}`,
token.filename,
token.loc.start.line,
false
);
buffer.writeStatement("}", token.filename, -1);
boot(template) {
template.macro("setValue", lodash.set);
}

@@ -275,5 +508,5 @@ };

// src/tags/each.ts
import lodash from "@poppinss/utils/lodash";
import lodash2 from "@poppinss/utils/lodash";
import * as lexerUtils from "edge-lexer/utils";
import { expressions as expressions5 } from "edge-parser";
import { expressions as expressions3 } from "edge-parser";
function getLoopList(rhsExpression, parser, filename) {

@@ -283,3 +516,3 @@ return parser.utils.stringify(parser.utils.transformAst(rhsExpression, filename, parser));

function getLoopItemAndIndex(lhsExpression, parser, filename) {
isSubsetOf(lhsExpression, [expressions5.SequenceExpression, expressions5.Identifier], () => {
isSubsetOf(lhsExpression, [expressions3.SequenceExpression, expressions3.Identifier], () => {
unallowedExpression(

@@ -292,3 +525,3 @@ `invalid left hand side "${lhsExpression.type}" expression for the @each tag`,

if (lhsExpression.type === "SequenceExpression") {
isSubsetOf(lhsExpression.expressions[0], [expressions5.Identifier], () => {
isSubsetOf(lhsExpression.expressions[0], [expressions3.Identifier], () => {
unallowedExpression(

@@ -300,3 +533,3 @@ `"${lhsExpression.expressions[0]}.type" is not allowed as value identifier for @each tag`,

});
isSubsetOf(lhsExpression.expressions[1], [expressions5.Identifier], () => {
isSubsetOf(lhsExpression.expressions[1], [expressions3.Identifier], () => {
unallowedExpression(

@@ -328,3 +561,3 @@ `"${lhsExpression.expressions[1]}.type" is not allowed as key identifier for @each tag`,

);
isSubsetOf(expression, [expressions5.BinaryExpression], () => {
isSubsetOf(expression, [expressions3.BinaryExpression], () => {
unallowedExpression(

@@ -366,96 +599,283 @@ `"${token.properties.jsArg}" is not valid expression for the @each tag`,

template.macro("loop", each);
template.macro("size", lodash.size);
template.macro("size", lodash2.size);
}
};
// src/tags/component.ts
import { EdgeError as EdgeError3 } from "edge-error";
import * as lexerUtils2 from "edge-lexer/utils";
import { expressions as expressions6 } from "edge-parser";
// src/tags/slot.ts
import { EdgeError as EdgeError2 } from "edge-error";
var slotTag = {
block: true,
seekable: true,
tagName: "slot",
noNewLine: true,
compile(_, __, token) {
throw new EdgeError2(
"@slot tag must appear as top level tag inside the @component tag",
"E_ORPHAN_SLOT_TAG",
{
line: token.loc.start.line,
col: token.loc.start.col,
filename: token.filename
}
);
}
};
// src/stringified_object/index.ts
var StringifiedObject = class {
#obj = "";
addSpread(key) {
this.#obj += this.#obj.length ? `, ${key}` : `${key}`;
// src/tags/else.ts
var elseTag = {
block: false,
seekable: false,
tagName: "else",
/**
* Compiles else block node to Javascript else statement
*/
compile(_, buffer, token) {
buffer.writeStatement("} else {", token.filename, -1);
}
};
// src/tags/eval.ts
var evalTag = {
block: false,
seekable: true,
tagName: "eval",
noNewLine: true,
/**
* Add key/value pair to the object.
*
* ```js
* stringifiedObject.add('username', `'virk'`)
* ```
* Compiles the tag AST
*/
add(key, value, isComputed = false) {
key = isComputed ? `[${key}]` : key;
this.#obj += this.#obj.length ? `, ${key}: ${value}` : `${key}: ${value}`;
compile(parser, buffer, token) {
const parsed = parseJsArg(parser, token);
buffer.writeExpression(parser.utils.stringify(parsed), token.filename, token.loc.start.line);
}
};
// src/tags/assign.ts
import { expressions as expressions4 } from "edge-parser";
import lodash3 from "@poppinss/utils/lodash";
var assignTag = {
block: false,
seekable: true,
tagName: "assign",
noNewLine: true,
/**
* Returns the object alike string back.
*
* ```js
* stringifiedObject.flush()
*
* // returns
* `{ username: 'virk' }`
* ```
* Compiles else block node to Javascript else statement
*/
flush() {
const obj = `{ ${this.#obj} }`;
this.#obj = "";
return obj;
compile(parser, buffer, token) {
const parsed = parseJsArg(parser, token);
isSubsetOf(parsed, [expressions4.AssignmentExpression], () => {
throw unallowedExpression(
`Invalid expression for the @assign tag`,
token.filename,
parser.utils.getExpressionLoc(parsed)
);
});
buffer.writeExpression(parser.utils.stringify(parsed), token.filename, token.loc.start.line);
},
/**
* Add methods to the template for running the loop
*/
boot(template) {
template.macro("setValue", lodash3.set);
}
};
// src/tags/inject.ts
import { expressions as expressions5 } from "edge-parser";
var injectTag = {
block: false,
seekable: true,
tagName: "inject",
noNewLine: true,
compile(parser, buffer, token) {
token.properties.jsArg = `(${token.properties.jsArg})`;
const parsed = parseJsArg(parser, token);
isSubsetOf(
parsed,
[expressions5.ObjectExpression, expressions5.Identifier, expressions5.CallExpression],
() => {
throw unallowedExpression(
`"${token.properties.jsArg}" is not a valid key-value pair for the @inject tag`,
token.filename,
parser.utils.getExpressionLoc(parsed)
);
}
);
buffer.writeStatement(
"if (!state.$slots || !state.$slots.$context) {",
token.filename,
token.loc.start.line
);
buffer.writeExpression(
`throw new Error('Cannot use "@inject" outside of a component scope')`,
token.filename,
token.loc.start.line
);
buffer.writeStatement("}", token.filename, token.loc.start.line);
buffer.writeExpression(
`Object.assign(state.$slots.$context, ${parser.utils.stringify(parsed)})`,
token.filename,
token.loc.start.line
);
}
};
// src/tags/unless.ts
import { expressions as expressions6 } from "edge-parser";
var unlessTag = {
block: true,
seekable: true,
tagName: "unless",
/**
* Parses an array of expressions to form an object. Each expression inside the array must
* be `ObjectExpression` or an `AssignmentExpression`, otherwise it will be ignored.
*
* ```js
* (title = 'hello')
* // returns { title: 'hello' }
*
* ({ title: 'hello' })
* // returns { title: 'hello' }
*
* ({ title: 'hello' }, username = 'virk')
* // returns { title: 'hello', username: 'virk' }
* ```
* Compiles the if block node to a Javascript if statement
*/
static fromAcornExpressions(expressions11, parser) {
if (!Array.isArray(expressions11)) {
throw new Error('"fromAcornExpressions" expects an array of acorn ast expressions');
}
const objectifyString = new this();
expressions11.forEach((arg) => {
if (arg.type === "ObjectExpression") {
arg.properties.forEach((prop) => {
if (prop.type === "SpreadElement") {
objectifyString.addSpread(parser.utils.stringify(prop));
} else {
const key = parser.utils.stringify(prop.key);
const value = parser.utils.stringify(prop.value);
objectifyString.add(key, value, prop.computed);
}
});
}
if (arg.type === "AssignmentExpression") {
objectifyString.add(arg.left.name, parser.utils.stringify(arg.right));
}
compile(parser, buffer, token) {
const parsed = parseJsArg(parser, token);
isNotSubsetOf(parsed, [expressions6.SequenceExpression], () => {
unallowedExpression(
`"${token.properties.jsArg}" is not a valid argument type for the @unless tag`,
token.filename,
parser.utils.getExpressionLoc(parsed)
);
});
return objectifyString.flush();
buffer.writeStatement(
`if (!${parser.utils.stringify(parsed)}) {`,
token.filename,
token.loc.start.line
);
token.children.forEach((child) => parser.processToken(child, buffer));
buffer.writeStatement("}", token.filename, -1);
}
};
// src/tags/else_if.ts
import { expressions as expressions7 } from "edge-parser";
var elseIfTag = {
block: false,
seekable: true,
tagName: "elseif",
/**
* Compiles the else if block node to a Javascript if statement
*/
compile(parser, buffer, token) {
const parsed = parseJsArg(parser, token);
isNotSubsetOf(parsed, [expressions7.SequenceExpression], () => {
unallowedExpression(
`{${token.properties.jsArg}} is not a valid argument type for the @elseif tag`,
token.filename,
parser.utils.getExpressionLoc(parsed)
);
});
buffer.writeStatement(
`} else if (${parser.utils.stringify(parsed)}) {`,
token.filename,
token.loc.start.line
);
}
};
// src/tags/include.ts
import { expressions as expressions8 } from "edge-parser";
var ALLOWED_EXPRESSION = [
expressions8.Literal,
expressions8.Identifier,
expressions8.CallExpression,
expressions8.TemplateLiteral,
expressions8.MemberExpression,
expressions8.LogicalExpression,
expressions8.ConditionalExpression
];
function getRenderExpression(parser, parsedExpression) {
const localVariables = parser.stack.list();
const renderArgs = localVariables.length ? [
parser.utils.stringify(parsedExpression),
localVariables.map((localVar) => `"${localVar}"`).join(",")
] : [parser.utils.stringify(parsedExpression)];
const callFnArgs = localVariables.length ? ["template", "state", "$context", localVariables.map((localVar) => localVar).join(",")] : ["template", "state", "$context"];
return `template.compilePartial(${renderArgs.join(",")})(${callFnArgs.join(",")})`;
}
var includeTag = {
block: false,
seekable: true,
tagName: "include",
/**
* Compiles else block node to Javascript else statement
*/
compile(parser, buffer, token) {
const awaitKeyword = parser.asyncMode ? "await " : "";
const parsed = parseJsArg(parser, token);
isSubsetOf(parsed, ALLOWED_EXPRESSION, () => {
unallowedExpression(
`"${token.properties.jsArg}" is not a valid argument type for the @include tag`,
token.filename,
parser.utils.getExpressionLoc(parsed)
);
});
buffer.outputExpression(
`${awaitKeyword}${getRenderExpression(parser, parsed)}`,
token.filename,
token.loc.start.line,
false
);
}
};
// src/tags/debugger.ts
var debuggerTag = {
block: false,
seekable: false,
tagName: "debugger",
noNewLine: true,
/**
* Compiles `@debugger` tags
*/
compile(_, buffer, token) {
buffer.writeExpression("debugger", token.filename, token.loc.start.line);
}
};
// src/tags/new_error.ts
import { expressions as expressions9 } from "edge-parser";
var newErrorTag = {
block: false,
seekable: true,
tagName: "newError",
noNewLine: true,
compile(parser, buffer, token) {
const parsed = parseJsArg(parser, token);
let message = "";
let line = token.loc.start.line;
let col = token.loc.start.col;
let filename = "$filename";
if (parsed.type === expressions9.SequenceExpression) {
message = parser.utils.stringify(parsed.expressions[0]);
filename = parsed.expressions[1] ? parser.utils.stringify(parsed.expressions[1]) : "$filename";
line = parsed.expressions[2] ? parser.utils.stringify(parsed.expressions[2]) : token.loc.start.line;
col = parsed.expressions[3] ? parser.utils.stringify(parsed.expressions[3]) : token.loc.start.col;
} else {
message = parser.utils.stringify(parsed);
}
buffer.writeStatement(
`template.newError(${message}, ${filename}, ${line}, ${col})`,
token.filename,
token.loc.start.line
);
}
};
// src/tags/component.ts
import { EdgeError as EdgeError3 } from "edge-error";
import * as lexerUtils2 from "edge-lexer/utils";
import { expressions as expressions10 } from "edge-parser";
var ALLOWED_EXPRESSION_FOR_COMPONENT_NAME = [
expressions6.Identifier,
expressions6.Literal,
expressions6.LogicalExpression,
expressions6.MemberExpression,
expressions6.ConditionalExpression,
expressions6.CallExpression,
expressions6.TemplateLiteral
expressions10.Identifier,
expressions10.Literal,
expressions10.LogicalExpression,
expressions10.MemberExpression,
expressions10.ConditionalExpression,
expressions10.CallExpression,
expressions10.TemplateLiteral
];
function getComponentNameAndProps(expression, parser, filename) {
let name;
if (expression.type === expressions6.SequenceExpression) {
if (expression.type === expressions10.SequenceExpression) {
name = expression.expressions.shift();

@@ -472,12 +892,4 @@ } else {

});
if (expression.type === expressions6.SequenceExpression) {
if (expression.type === expressions10.SequenceExpression) {
const firstSequenceExpression = expression.expressions[0];
if (firstSequenceExpression && [expressions6.ObjectExpression, expressions6.AssignmentExpression].includes(
firstSequenceExpression.type
)) {
return [
parser.utils.stringify(name),
StringifiedObject.fromAcornExpressions([firstSequenceExpression], parser)
];
}
return [parser.utils.stringify(name), parser.utils.stringify(firstSequenceExpression)];

@@ -493,3 +905,3 @@ }

).expression;
isSubsetOf(parsed, [expressions6.Literal, expressions6.SequenceExpression], () => {
isSubsetOf(parsed, [expressions10.Literal, expressions10.SequenceExpression], () => {
unallowedExpression(

@@ -502,3 +914,3 @@ `"${token.properties.jsArg}" is not a valid argument type for the @slot tag`,

let name;
if (parsed.type === expressions6.SequenceExpression) {
if (parsed.type === expressions10.SequenceExpression) {
name = parsed.expressions[0];

@@ -508,3 +920,3 @@ } else {

}
isSubsetOf(name, [expressions6.Literal], () => {
isSubsetOf(name, [expressions10.Literal], () => {
unallowedExpression(

@@ -516,3 +928,3 @@ "slot name must be a valid string literal",

});
if (parsed.type === expressions6.Literal) {
if (parsed.type === expressions10.Literal) {
return [name.raw, null];

@@ -527,3 +939,3 @@ }

}
isSubsetOf(parsed.expressions[1], [expressions6.Identifier], () => {
isSubsetOf(parsed.expressions[1], [expressions10.Identifier], () => {
unallowedExpression(

@@ -549,3 +961,3 @@ `"${parser.utils.stringify(

parsed,
ALLOWED_EXPRESSION_FOR_COMPONENT_NAME.concat(expressions6.SequenceExpression),
ALLOWED_EXPRESSION_FOR_COMPONENT_NAME.concat(expressions10.SequenceExpression),
() => {

@@ -635,45 +1047,9 @@ unallowedExpression(

// src/tags/slot.ts
// src/tags/include_if.ts
import { EdgeError as EdgeError4 } from "edge-error";
var slotTag = {
block: true,
seekable: true,
tagName: "slot",
noNewLine: true,
compile(_, __, token) {
throw new EdgeError4(
"@slot tag must appear as top level tag inside the @component tag",
"E_ORPHAN_SLOT_TAG",
{
line: token.loc.start.line,
col: token.loc.start.col,
filename: token.filename
}
);
}
};
// src/tags/debugger.ts
var debuggerTag = {
import { expressions as expressions11 } from "edge-parser";
var includeIfTag = {
block: false,
seekable: false,
tagName: "debugger",
noNewLine: true,
/**
* Compiles `@debugger` tags
*/
compile(_, buffer, token) {
buffer.writeExpression("debugger", token.filename, token.loc.start.line);
}
};
// src/tags/set.ts
import { EdgeError as EdgeError5 } from "edge-error";
import { expressions as expressions7 } from "edge-parser";
import lodash2 from "@poppinss/utils/lodash";
var setTag = {
block: false,
seekable: true,
tagName: "set",
noNewLine: true,
tagName: "includeIf",
/**

@@ -683,6 +1059,7 @@ * Compiles else block node to Javascript else statement

compile(parser, buffer, token) {
const awaitKeyword = parser.asyncMode ? "await " : "";
const parsed = parseJsArg(parser, token);
isSubsetOf(parsed, [expressions7.SequenceExpression], () => {
throw unallowedExpression(
`"${token.properties.jsArg}" is not a valid key-value pair for the @slot tag`,
isSubsetOf(parsed, [expressions11.SequenceExpression], () => {
unallowedExpression(
`"${token.properties.jsArg}" is not a valid argument type for the @includeIf tag`,
token.filename,

@@ -692,396 +1069,45 @@ parser.utils.getExpressionLoc(parsed)

});
if (parsed.expressions.length < 2 || parsed.expressions.length > 3) {
throw new EdgeError5(
"@set tag accepts a minimum of 2 or maximum or 3 arguments",
"E_INVALID_ARGUMENTS_COUNT",
{
line: parsed.loc.start.line,
col: parsed.loc.start.column,
filename: token.filename
}
);
if (parsed.expressions.length !== 2) {
throw new EdgeError4("@includeIf expects a total of 2 arguments", "E_ARGUMENTS_MIS_MATCH", {
line: parsed.loc.start.line,
col: parsed.loc.start.column,
filename: token.filename
});
}
let collection;
let key;
let value;
if (parsed.expressions.length === 3) {
collection = parsed.expressions[0];
key = parsed.expressions[1];
value = parsed.expressions[2];
} else {
key = parsed.expressions[0];
value = parsed.expressions[1];
}
isSubsetOf(key, [expressions7.Literal], () => {
throw unallowedExpression(
`The ${collection ? "second" : "first"} argument for @set tag must be a string literal`,
const [conditional, include] = parsed.expressions;
isNotSubsetOf(conditional, [expressions11.SequenceExpression], () => {
unallowedExpression(
`"${conditional.type}" is not a valid 1st argument type for the @includeIf tag`,
token.filename,
parser.utils.getExpressionLoc(key)
parser.utils.getExpressionLoc(conditional)
);
});
if (collection) {
buffer.writeExpression(
`template.setValue(${parser.utils.stringify(collection)}, '${key.value}', ${parser.utils.stringify(value)})`,
token.filename,
token.loc.start.line
);
return;
}
const expression = parser.stack.has(key.value) ? `${key.value} = ${parser.utils.stringify(value)}` : `let ${key.value} = ${parser.utils.stringify(value)}`;
buffer.writeExpression(expression, token.filename, token.loc.start.line);
parser.stack.defineVariable(key.value);
},
/**
* Add methods to the template for running the loop
*/
boot(template) {
template.macro("setValue", lodash2.set);
}
};
// src/tags/unless.ts
import { expressions as expressions8 } from "edge-parser";
var unlessTag = {
block: true,
seekable: true,
tagName: "unless",
/**
* Compiles the if block node to a Javascript if statement
*/
compile(parser, buffer, token) {
const parsed = parseJsArg(parser, token);
isNotSubsetOf(parsed, [expressions8.SequenceExpression], () => {
isSubsetOf(include, ALLOWED_EXPRESSION, () => {
unallowedExpression(
`"${token.properties.jsArg}" is not a valid argument type for the @unless tag`,
`"${include.type}" is not a valid 2nd argument type for the @includeIf tag`,
token.filename,
parser.utils.getExpressionLoc(parsed)
parser.utils.getExpressionLoc(include)
);
});
buffer.writeStatement(
`if (!${parser.utils.stringify(parsed)}) {`,
`if (${parser.utils.stringify(conditional)}) {`,
token.filename,
token.loc.start.line
);
token.children.forEach((child) => parser.processToken(child, buffer));
buffer.writeStatement("}", token.filename, -1);
}
};
// src/tags/layout.ts
var layoutTag = {
block: false,
seekable: true,
tagName: "layout",
noNewLine: true,
compile() {
}
};
// src/tags/section.ts
var sectionTag = {
block: true,
seekable: true,
tagName: "section",
compile(parser, buffer, token) {
token.children.forEach((child) => parser.processToken(child, buffer));
}
};
// src/tags/super.ts
import { EdgeError as EdgeError6 } from "edge-error";
var superTag = {
block: false,
seekable: false,
tagName: "super",
compile(_, __, token) {
throw new EdgeError6(
"@super tag must appear as top level tag inside the @section tag",
"E_ORPHAN_SUPER_TAG",
{
line: token.loc.start.line,
col: token.loc.start.col,
filename: token.filename
}
);
}
};
// src/tags/inject.ts
import { expressions as expressions9 } from "edge-parser";
var injectTag = {
block: false,
seekable: true,
tagName: "inject",
noNewLine: true,
compile(parser, buffer, token) {
token.properties.jsArg = `(${token.properties.jsArg})`;
const parsed = parseJsArg(parser, token);
isSubsetOf(parsed, [expressions9.ObjectExpression, expressions9.Identifier], () => {
throw unallowedExpression(
`"${token.properties.jsArg}" is not a valid key-value pair for the @inject tag`,
token.filename,
parser.utils.getExpressionLoc(parsed)
);
});
buffer.writeStatement(
"if (!state.$slots || !state.$slots.$context) {",
buffer.outputExpression(
`${awaitKeyword}${getRenderExpression(parser, include)}`,
token.filename,
token.loc.start.line
token.loc.start.line,
false
);
buffer.writeExpression(
`throw new Error('Cannot use "@inject" outside of a component scope')`,
token.filename,
token.loc.start.line
);
buffer.writeStatement("}", token.filename, token.loc.start.line);
buffer.writeExpression(
`Object.assign(state.$slots.$context, ${parser.utils.stringify(parsed)})`,
token.filename,
token.loc.start.line
);
buffer.writeStatement("}", token.filename, -1);
}
};
// src/tags/new_error.ts
import { expressions as expressions10 } from "edge-parser";
var newErrorTag = {
block: false,
seekable: true,
tagName: "newError",
noNewLine: true,
compile(parser, buffer, token) {
const parsed = parseJsArg(parser, token);
let message = "";
let line = token.loc.start.line;
let col = token.loc.start.col;
let filename = "$filename";
if (parsed.type === expressions10.SequenceExpression) {
message = parser.utils.stringify(parsed.expressions[0]);
filename = parsed.expressions[1] ? parser.utils.stringify(parsed.expressions[1]) : "$filename";
line = parsed.expressions[2] ? parser.utils.stringify(parsed.expressions[2]) : token.loc.start.line;
col = parsed.expressions[3] ? parser.utils.stringify(parsed.expressions[3]) : token.loc.start.col;
} else {
message = parser.utils.stringify(parsed);
}
buffer.writeStatement(
`template.newError(${message}, ${filename}, ${line}, ${col})`,
token.filename,
token.loc.start.line
);
}
};
// src/loader/index.ts
import { readFileSync } from "node:fs";
import { join, isAbsolute } from "node:path";
var Loader = class {
/**
* List of mounted directories
*/
#mountedDirs = /* @__PURE__ */ new Map();
/**
* List of pre-registered (in-memory) templates
*/
#preRegistered = /* @__PURE__ */ new Map();
/**
* Reads the content of a template from the disk. An exception is raised
* when file is missing or if `readFileSync` returns an error.
*/
#readTemplateContents(absPath) {
try {
return readFileSync(absPath, "utf-8");
} catch (error) {
if (error.code === "ENOENT") {
throw new Error(`Cannot resolve "${absPath}". Make sure the file exists`);
} else {
throw error;
}
}
}
/**
* Extracts the disk name and the template name from the template
* path expression.
*
* If `diskName` is missing, it will be set to `default`.
*
* ```
* extractDiskAndTemplateName('users::list')
* // returns ['users', 'list.edge']
*
* extractDiskAndTemplateName('list')
* // returns ['default', 'list.edge']
* ```
*/
#extractDiskAndTemplateName(templatePath) {
let [disk, ...rest] = templatePath.split("::");
if (!rest.length) {
rest = [disk];
disk = "default";
}
let [template, ext] = rest.join("::").split(".edge");
if (template.indexOf(".") > -1) {
process.emitWarning(
"DeprecationWarning",
'edge: dot "." based path seperators are depreciated. We recommend using "/" instead'
);
template = template.replace(/\./g, "/");
}
return [disk, `${template}.${ext || "edge"}`];
}
/**
* Returns an object of mounted directories with their public
* names.
*
* ```js
* loader.mounted
* // output
*
* {
* default: '/users/virk/code/app/views',
* foo: '/users/virk/code/app/foo',
* }
* ```
*/
get mounted() {
return Array.from(this.#mountedDirs).reduce(
(obj, [key, value]) => {
obj[key] = value;
return obj;
},
{}
);
}
/**
* Returns an object of templates registered as a raw string
*
* ```js
* loader.templates
* // output
*
* {
* 'form.label': { template: '/users/virk/code/app/form/label' }
* }
* ```
*/
get templates() {
return Array.from(this.#preRegistered).reduce(
(obj, [key, value]) => {
obj[key] = value;
return obj;
},
{}
);
}
/**
* Mount a directory with a name for resolving views. If name is set
* to `default`, then you can resolve views without prefixing the
* disk name.
*
* ```js
* loader.mount('default', join(__dirname, 'views'))
*
* // mount a named disk
* loader.mount('admin', join(__dirname, 'admin/views'))
* ```
*/
mount(diskName, dirPath) {
this.#mountedDirs.set(diskName, dirPath);
}
/**
* Remove the previously mounted dir.
*
* ```js
* loader.unmount('default')
* ```
*/
unmount(diskName) {
this.#mountedDirs.delete(diskName);
}
/**
* Make path to a given template. The paths are resolved from the root
* of the mounted directory.
*
* ```js
* loader.makePath('welcome') // returns {diskRootPath}/welcome.edge
* loader.makePath('admin::welcome') // returns {adminRootPath}/welcome.edge
* loader.makePath('users.list') // returns {diskRootPath}/users/list.edge
* ```
*
* @throws Error if disk is not mounted and attempting to make path for it.
*/
makePath(templatePath) {
if (this.#preRegistered.has(templatePath)) {
return templatePath;
}
if (isAbsolute(templatePath)) {
return templatePath;
}
const [diskName, template] = this.#extractDiskAndTemplateName(templatePath);
const mountedDir = this.#mountedDirs.get(diskName);
if (!mountedDir) {
throw new Error(`"${diskName}" namespace is not mounted`);
}
return join(mountedDir, template);
}
/**
* Resolves the template by reading its contents from the disk
*
* ```js
* loader.resolve('welcome', true)
*
* // output
* {
* template: `<h1> Template content </h1>`,
* }
* ```
*/
resolve(templatePath) {
if (this.#preRegistered.has(templatePath)) {
return this.#preRegistered.get(templatePath);
}
templatePath = isAbsolute(templatePath) ? templatePath : this.makePath(templatePath);
return {
template: this.#readTemplateContents(templatePath)
};
}
/**
* Register in memory template for a given path. This is super helpful
* when distributing components.
*
* ```js
* loader.register('welcome', {
* template: '<h1> Template content </h1>',
* Presenter: class Presenter {
* constructor (state) {
* this.state = state
* }
* }
* })
* ```
*
* @throws Error if template content is empty.
*/
register(templatePath, contents) {
if (typeof contents.template !== "string") {
throw new Error("Make sure to define the template content as a string");
}
if (this.#preRegistered.has(templatePath)) {
throw new Error(`Cannot override previously registered "${templatePath}" template`);
}
this.#preRegistered.set(templatePath, contents);
}
/**
* Remove registered template
*/
remove(templatePath) {
this.#preRegistered.delete(templatePath);
}
};
// src/compiler/index.ts
import { EdgeError as EdgeError7 } from "edge-error";
// src/compiler.ts
import { EdgeError as EdgeError5 } from "edge-error";
import * as lexerUtils3 from "edge-lexer/utils";
import { Parser as Parser4, EdgeBuffer as EdgeBuffer2, Stack } from "edge-parser";
import * as lexerUtils3 from "edge-lexer/utils";
// src/cache_manager/index.ts
// src/cache_manager.ts
var CacheManager = class {

@@ -1130,4 +1156,15 @@ constructor(enabled) {

// src/compiler/index.ts
// src/compiler.ts
var AsyncFunction = Object.getPrototypeOf(async function() {
}).constructor;
var Compiler = class {
/**
* The variables someone can access inside templates. All other
* variables will get prefixed with `state` property name
*/
#inlineVariables = ["$filename", "state", "$context"];
/**
* A fixed set of params to pass to the template every time.
*/
#templateParams = ["template", "state", "$context"];
#claimTagFn;

@@ -1142,8 +1179,13 @@ #loader;

/**
* Know if compiler is compiling for the async mode or not
* A boolean to know if compat mode is enabled
*/
compat;
/**
* Know if compiler is compiling in the async mode or not
*/
async;
constructor(loader, tags, processor, options = {
cache: true,
async: false
async: false,
compat: false
}) {

@@ -1154,2 +1196,3 @@ this.#processor = processor;

this.async = !!options.async;
this.compat = options.compat === true;
this.cacheManager = new CacheManager(!!options.cache);

@@ -1176,3 +1219,3 @@ }

const [line, col] = lexerUtils3.getLineAndColumn(node);
throw new EdgeError7(
throw new EdgeError5(
'Template extending a layout can only use "@section" or "@set" tags as top level nodes',

@@ -1213,6 +1256,8 @@ "E_UNALLOWED_EXPRESSION",

let templateTokens = parser.tokenize(content, { filename: absPath });
const firstToken = templateTokens[0];
if (lexerUtils3.isTag(firstToken, "layout")) {
const layoutName = firstToken.properties.jsArg.replace(/'|"/g, "");
templateTokens = this.#mergeSections(this.tokenize(layoutName, parser), templateTokens);
if (this.compat) {
const firstToken = templateTokens[0];
if (lexerUtils3.isTag(firstToken, "layout")) {
const layoutName = firstToken.properties.jsArg.replace(/'|"/g, "");
templateTokens = this.#mergeSections(this.tokenize(layoutName, parser), templateTokens);
}
}

@@ -1230,3 +1275,3 @@ return templateTokens;

escapeCallPath: ["template", "escape"],
localVariables: ["$filename", "state", "$context"],
localVariables: this.#inlineVariables,
onTag: (tag) => this.#processor.executeTag({ tag, path: templatePath })

@@ -1249,2 +1294,12 @@ });

/**
* Wraps template output to a function along with local variables
*/
#wrapToFunction(template, localVariables) {
const args = localVariables ? this.#templateParams.concat(localVariables) : this.#templateParams;
if (this.async) {
return new AsyncFunction(...args, template);
}
return new Function(...args, template);
}
/**
* Define a function to claim tags

@@ -1289,5 +1344,5 @@ */

*/
compile(templatePath, localVariables, skipCache = false) {
compile(templatePath, localVariables) {
const absPath = this.#loader.makePath(templatePath);
let cachedResponse = skipCache ? null : this.cacheManager.get(absPath);
let cachedResponse = localVariables ? null : this.cacheManager.get(absPath);
if (!cachedResponse) {

@@ -1298,13 +1353,13 @@ const parser = this.#getParserFor(absPath, localVariables);

templateTokens.forEach((token) => parser.processToken(token, buffer));
const template2 = buffer.flush();
if (!skipCache) {
this.cacheManager.set(absPath, { template: template2 });
const template = this.#processor.executeCompiled({
path: absPath,
compiled: buffer.flush()
});
const compiledTemplate = this.#wrapToFunction(template, localVariables);
if (!localVariables) {
this.cacheManager.set(absPath, compiledTemplate);
}
cachedResponse = { template: template2 };
cachedResponse = compiledTemplate;
}
const template = this.#processor.executeCompiled({
path: absPath,
compiled: cachedResponse.template
});
return { template };
return cachedResponse;
}

@@ -1317,3 +1372,3 @@ /**

* ```js
* compiler.compile('welcome')
* compiler.compileRaw('welcome')
* ```

@@ -1330,19 +1385,85 @@ */

});
return { template };
return this.#wrapToFunction(template);
}
};
// src/template/index.ts
// src/template.ts
import he from "he";
import { EdgeError as EdgeError6 } from "edge-error";
import lodash6 from "@poppinss/utils/lodash";
import Macroable from "@poppinss/macroable";
import { EdgeError as EdgeError8 } from "edge-error";
// src/migrate/props.ts
import lodash5 from "@poppinss/utils/lodash";
import stringifyAttributes2 from "stringify-attributes";
// src/component/props.ts
import lodash4 from "@poppinss/utils/lodash";
import he from "he";
var ComponentProps = class _ComponentProps {
#values;
constructor(values) {
this.#values = values;
}
/**
* Reference to props raw values
*/
all() {
return this.#values;
}
/**
* Check if a key exists
*/
has(key) {
return lodash4.has(this.#values, key);
}
/**
* Get key value
*/
get(key, defaultValue) {
return lodash4.get(this.#values, key, defaultValue);
}
/**
* Returns a new props bag with only the mentioned keys
*/
only(keys) {
return new _ComponentProps(lodash4.pick(this.#values, keys));
}
/**
* Returns a new props bag with except the mentioned keys
*/
except(keys) {
return new _ComponentProps(lodash4.omit(this.#values, keys));
}
/**
* Define defaults for the props values.
*
* - All other attributes will be overwritten when defined in props
* - Classes will be merged together.
*/
defaults(values) {
if (values.class && this.#values["class"]) {
const classes = { ...values.class, ...this.#values.class };
return new _ComponentProps({ ...values, ...this.#values, class: classes });
}
return new _ComponentProps({ ...values, ...this.#values });
}
/**
* Converts props to HTML attributes
*/
toAttrs() {
return htmlSafe(stringifyAttributes(this.#values));
}
};
// src/component/props.ts
import lodash3 from "@poppinss/utils/lodash";
import stringifyAttributes from "stringify-attributes";
// src/migrate/props.ts
var Props = class {
/**
* Use ".next" property to migrate to newer
* api
*/
next;
constructor(props) {
this[Symbol.for("options")] = { props };
Object.assign(this, props);
this.next = new ComponentProps(props);
}

@@ -1376,3 +1497,3 @@ /**

get(key, defaultValue) {
return lodash3.get(this.all(), key, defaultValue);
return lodash5.get(this.all(), key, defaultValue);
}

@@ -1396,3 +1517,3 @@ /**

only(keys) {
return lodash3.pick(this.all(), keys);
return lodash5.pick(this.all(), keys);
}

@@ -1403,3 +1524,3 @@ /**

except(keys) {
return lodash3.omit(this.all(), keys);
return lodash5.omit(this.all(), keys);
}

@@ -1410,4 +1531,4 @@ /**

serialize(mergeProps, prioritizeInline = true) {
const attributes = prioritizeInline ? lodash3.merge({}, this.all(), mergeProps) : lodash3.merge({}, mergeProps, this.all());
return safeValue(stringifyAttributes(this.#mergeClassAttributes(attributes)));
const attributes = prioritizeInline ? lodash5.merge({}, this.all(), mergeProps) : lodash5.merge({}, mergeProps, this.all());
return htmlSafe(stringifyAttributes2(this.#mergeClassAttributes(attributes)));
}

@@ -1418,4 +1539,4 @@ /**

serializeOnly(keys, mergeProps, prioritizeInline = true) {
const attributes = prioritizeInline ? lodash3.merge({}, this.only(keys), mergeProps) : lodash3.merge({}, mergeProps, this.only(keys));
return safeValue(stringifyAttributes(this.#mergeClassAttributes(attributes)));
const attributes = prioritizeInline ? lodash5.merge({}, this.only(keys), mergeProps) : lodash5.merge({}, mergeProps, this.only(keys));
return htmlSafe(stringifyAttributes2(this.#mergeClassAttributes(attributes)));
}

@@ -1426,8 +1547,8 @@ /**

serializeExcept(keys, mergeProps, prioritizeInline = true) {
const attributes = prioritizeInline ? lodash3.merge({}, this.except(keys), mergeProps) : lodash3.merge({}, mergeProps, this.except(keys));
return safeValue(stringifyAttributes(this.#mergeClassAttributes(attributes)));
const attributes = prioritizeInline ? lodash5.merge({}, this.except(keys), mergeProps) : lodash5.merge({}, mergeProps, this.except(keys));
return htmlSafe(stringifyAttributes2(this.#mergeClassAttributes(attributes)));
}
};
// src/template/index.ts
// src/template.ts
var SafeValue = class {

@@ -1441,34 +1562,21 @@ constructor(value) {

}
function safeValue(value) {
function htmlSafe(value) {
return new SafeValue(value);
}
var Template = class extends Macroable {
constructor(compiler, globals, locals, processor) {
super();
this.compiler = compiler;
this.processor = processor;
this.sharedState = lodash4.merge({}, globals, locals);
}
#compiler;
#processor;
/**
* Required by Macroable
*/
static macros = {};
static getters = {};
/**
* The shared state is used to hold the globals and locals,
* since it is shared with components too.
*/
sharedState;
/**
* Wraps template to a function
*/
wrapToFunction(template, ...localVariables) {
const args = ["template", "state", "$context"].concat(localVariables);
if (this.compiler.async) {
return new Function(
"",
`return async function template (${args.join(",")}) { ${template} }`
)();
}
return new Function("", `return function template (${args.join(",")}) { ${template} }`)();
#sharedState;
constructor(compiler, globals, locals, processor) {
super();
this.#compiler = compiler;
this.#processor = processor;
this.#sharedState = compiler.compat ? lodash6.merge({}, globals, locals) : {
...globals,
...locals
};
}

@@ -1478,3 +1586,3 @@ /**

*/
trimTopBottomNewLines(value) {
#trimTopBottomNewLines(value) {
return value.replace(/^\n|^\r\n/, "").replace(/\n$|\r\n$/, "");

@@ -1485,17 +1593,13 @@ }

*/
renderCompiled(compiledTemplate, state) {
const templateState = Object.assign({}, this.sharedState, state);
#renderCompiled(compiledTemplate, state) {
const templateState = { ...this.#sharedState, ...state };
const $context = {};
if (this.compiler.async) {
return this.wrapToFunction(compiledTemplate)(this, templateState, $context).then(
(output2) => {
output2 = this.trimTopBottomNewLines(output2);
return this.processor.executeOutput({ output: output2, template: this, state: templateState });
}
);
if (this.#compiler.async) {
return compiledTemplate(this, templateState, $context).then((output2) => {
output2 = this.#trimTopBottomNewLines(output2);
return this.#processor.executeOutput({ output: output2, template: this, state: templateState });
});
}
const output = this.trimTopBottomNewLines(
this.wrapToFunction(compiledTemplate)(this, templateState, $context)
);
return this.processor.executeOutput({ output, template: this, state: templateState });
const output = this.#trimTopBottomNewLines(compiledTemplate(this, templateState, $context));
return this.#processor.executeOutput({ output, template: this, state: templateState });
}

@@ -1513,4 +1617,3 @@ /**

compilePartial(templatePath, ...localVariables) {
const { template: compiledTemplate } = this.compiler.compile(templatePath, localVariables, true);
return this.wrapToFunction(compiledTemplate, ...localVariables);
return this.#compiler.compile(templatePath, localVariables);
}

@@ -1527,5 +1630,4 @@ /**

*/
compileComponent(templatePath, ...localVariables) {
const { template: compiledTemplate } = this.compiler.compile(templatePath, localVariables);
return this.wrapToFunction(compiledTemplate, ...localVariables);
compileComponent(templatePath) {
return this.#compiler.compile(templatePath);
}

@@ -1536,7 +1638,9 @@ /**

getComponentState(props, slots, caller) {
return Object.assign({}, this.sharedState, props, {
return {
...this.#sharedState,
...props,
$slots: slots,
$caller: caller,
$props: new Props(props)
});
$props: this.#compiler.compat ? new Props(props) : new ComponentProps(props)
};
}

@@ -1551,4 +1655,4 @@ /**

render(template, state) {
let { template: compiledTemplate } = this.compiler.compile(template);
return this.renderCompiled(compiledTemplate, state);
let compiledTemplate = this.#compiler.compile(template);
return this.#renderCompiled(compiledTemplate, state);
}

@@ -1563,4 +1667,4 @@ /**

renderRaw(contents, state, templatePath) {
let { template: compiledTemplate } = this.compiler.compileRaw(contents, templatePath);
return this.renderCompiled(compiledTemplate, state);
let compiledTemplate = this.#compiler.compileRaw(contents, templatePath);
return this.#renderCompiled(compiledTemplate, state);
}

@@ -1578,3 +1682,3 @@ /**

newError(errorMessage, filename, lineNumber, column) {
throw new EdgeError8(errorMessage, "E_RUNTIME_EXCEPTION", {
throw new EdgeError6(errorMessage, "E_RUNTIME_EXCEPTION", {
filename,

@@ -1590,7 +1694,7 @@ line: lineNumber,

reThrow(error, filename, lineNumber) {
if (error instanceof EdgeError8) {
if (error instanceof EdgeError6) {
throw error;
}
const message = error.message.replace(/state\./, "");
throw new EdgeError8(message, "E_RUNTIME_EXCEPTION", {
throw new EdgeError6(message, "E_RUNTIME_EXCEPTION", {
filename,

@@ -1603,3 +1707,3 @@ line: lineNumber,

// src/processor/index.ts
// src/processor.ts
var Processor = class {

@@ -1676,15 +1780,18 @@ #handlers = /* @__PURE__ */ new Map();

// src/renderer/index.ts
import lodash5 from "@poppinss/utils/lodash";
// src/edge/renderer.ts
import lodash7 from "@poppinss/utils/lodash";
var EdgeRenderer = class {
#locals = {};
#compiler;
#processor;
#asyncCompiler;
/**
* Global state
*/
#locals = {};
#globals;
#processor;
constructor(compiler, asyncCompiler, globals, processor) {
constructor(compiler, asyncCompiler, processor, globals) {
this.#compiler = compiler;
this.#asyncCompiler = asyncCompiler;
this.#processor = processor;
this.#globals = globals;
this.#processor = processor;
}

@@ -1696,3 +1803,3 @@ /**

share(data) {
lodash5.merge(this.#locals, data);
lodash7.merge(this.#locals, data);
return this;

@@ -1743,4 +1850,10 @@ }

// src/edge/index.ts
var Edge = class {
// src/edge/main.ts
var Edge = class _Edge {
/**
* Create an instance of edge with given options
*/
static create(options = {}) {
return new _Edge(options);
}
#executedPlugins = false;

@@ -1760,11 +1873,6 @@ /**

/**
* Globals are shared with all rendered templates
* A flag to know if using compat mode
*/
GLOBALS = {};
compat = false;
/**
* List of registered tags. Adding new tags will only impact
* this list
*/
tags = {};
/**
* The loader to load templates. A loader can read and return

@@ -1783,2 +1891,11 @@ * templates from anywhere. The default loader reads files

asyncCompiler;
/**
* Globals are shared with all rendered templates
*/
globals = {};
/**
* List of registered tags. Adding new tags will only impact
* this list
*/
tags = {};
constructor(options = {}) {

@@ -1794,3 +1911,5 @@ this.loader = options.loader || new Loader();

});
Object.keys(tags_exports).forEach((name) => this.registerTag(tags_exports[name]));
Object.keys(main_exports).forEach((name) => {
this.registerTag(main_exports[name]);
});
}

@@ -1801,8 +1920,6 @@ /**

*/
executePlugins() {
#executePlugins() {
if (this.#executedPlugins) {
this.#plugins.forEach(({ fn, options }) => {
if (options && options.recurring) {
fn(this, false, options);
}
this.#plugins.filter(({ options }) => options && options.recurring).forEach(({ fn, options }) => {
fn(this, false, options);
});

@@ -1827,18 +1944,8 @@ } else {

}
/**
* Mount named directory to use views. Later you can reference
* the views from a named disk as follows.
*
* ```
* edge.mount('admin', join(__dirname, 'admin'))
*
* edge.render('admin::filename')
* ```
*/
mount(diskName, dirPath) {
if (!dirPath) {
dirPath = diskName;
mount(diskName, viewsDirectory) {
if (!viewsDirectory) {
viewsDirectory = diskName;
diskName = "default";
}
this.loader.mount(diskName, dirPath);
this.loader.mount(diskName, viewsDirectory);
return this;

@@ -1867,3 +1974,3 @@ }

global(name, value) {
this.GLOBALS[name] = value;
this.globals[name] = value;
return this;

@@ -1937,9 +2044,9 @@ }

*/
getRenderer() {
this.executePlugins();
createRenderer() {
this.#executePlugins();
const renderer = new EdgeRenderer(
this.compiler,
this.asyncCompiler,
this.GLOBALS,
this.processor
this.processor,
this.globals
);

@@ -1957,3 +2064,3 @@ this.#renderCallbacks.forEach((callback) => callback(renderer));

render(templatePath, state) {
return this.getRenderer().render(templatePath, state);
return this.createRenderer().render(templatePath, state);
}

@@ -1968,3 +2075,3 @@ /**

renderSync(templatePath, state) {
return this.getRenderer().renderSync(templatePath, state);
return this.createRenderer().renderSync(templatePath, state);
}

@@ -1979,3 +2086,3 @@ /**

renderRaw(contents, state, templatePath) {
return this.getRenderer().renderRaw(contents, state, templatePath);
return this.createRenderer().renderRaw(contents, state, templatePath);
}

@@ -1990,3 +2097,3 @@ /**

renderRawSync(templatePath, state) {
return this.getRenderer().renderRawSync(templatePath, state);
return this.createRenderer().renderRawSync(templatePath, state);
}

@@ -1997,3 +2104,3 @@ /**

* ```js
* const view = edge.getRenderer()
* const view = edge.createRenderer()
*

@@ -2007,99 +2114,7 @@ * // local state for the current render

share(data) {
return this.getRenderer().share(data);
return this.createRenderer().share(data);
}
};
// src/edge/globals/index.ts
import { EdgeError as EdgeError9 } from "edge-error";
import stringify from "js-stringify";
import inspect from "@poppinss/inspect";
import string from "@poppinss/utils/string";
var { string: prettyPrintHtml } = inspect;
var GLOBALS = {
/**
* Converts new lines to break
*/
nl2br: (value) => {
if (!value) {
return;
}
return String(value).replace(/([^>\r\n]?)(\r\n|\n\r|\r|\n)/g, "$1<br>");
},
/**
* Inspect state
*/
inspect: (value) => {
return safeValue(prettyPrintHtml.html(value));
},
/**
* Truncate a sentence
*/
truncate: (value, length = 20, options) => {
options = options || {};
return string.truncate(value, length, {
completeWords: options.completeWords !== void 0 ? options.completeWords : !options.strict,
suffix: options.suffix
});
},
/**
* Raise an exception
*/
raise: (message, options) => {
if (!options) {
throw new Error(message);
} else {
throw new EdgeError9(message, "E_RUNTIME_EXCEPTION", options);
}
},
/**
* Generate an excerpt
*/
excerpt: (value, length = 20, options) => {
options = options || {};
return string.excerpt(value, length, {
completeWords: options.completeWords !== void 0 ? options.completeWords : !options.strict,
suffix: options.suffix
});
},
/**
* Using `"e"` because, `escape` is a global function in the
* Node.js global namespace and edge parser gives priority
* to it
*/
e: escape,
/**
* Convert javascript data structures to a string. The method is a little
* better over JSON.stringify in handling certain data structures. For
* example: In JSON.stringify, the date is converted to an ISO string
* whereas this method converts it to an actual instance of date
*/
stringify,
safe: safeValue,
camelCase: string.camelCase,
snakeCase: string.snakeCase,
dashCase: string.dashCase,
pascalCase: string.pascalCase,
capitalCase: string.capitalCase,
sentenceCase: string.sentenceCase,
dotCase: string.dotCase,
noCase: string.noCase,
titleCase: string.titleCase,
pluralize: string.pluralize,
sentence: string.sentence,
prettyMs: string.milliseconds.format,
toMs: string.milliseconds.parse,
prettyBytes: string.bytes.format,
toBytes: string.bytes.parse,
ordinal: string.ordinal
};
// index.ts
var edge = new Edge();
Object.keys(GLOBALS).forEach((key) => edge.global(key, GLOBALS[key]));
var edge_default = edge;
export {
Edge,
GLOBALS,
edge_default as default,
safeValue
Edge
};

@@ -1,375 +0,5 @@

import { Token, TagToken } from 'edge-lexer/types';
import { Parser, EdgeBuffer } from 'edge-parser';
import { ParserTagDefinitionContract, ClaimTagFn } from 'edge-parser/types';
export { ClaimTagFn } from 'edge-parser/types';
/**
* edge
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* The shape in which the loader must resolve the template
*/
type LoaderTemplate = {
template: string;
};
/**
* Loader contract that every loader must adheres to.
*/
interface LoaderContract {
/**
* List of mounted disks
*/
mounted: {
[diskName: string]: string;
};
/**
* List of pre-registered template
*/
templates: {
[templatePath: string]: LoaderTemplate;
};
/**
* Save disk name and dirPath to resolve views
*/
mount(diskName: string, dirPath: string): void;
/**
* Remove disk from the previously saved paths
*/
unmount(diskName: string): void;
/**
* Resolve template contents
*/
resolve(templatePath: string): LoaderTemplate;
/**
* Make absolute path to a template
*/
makePath(templatePath: string): string;
/**
* Register in memory template and presenter
*/
register(templatePath: string, contents: LoaderTemplate): void;
/**
* Remove the pre-registered template
*/
remove(templatePath: string): void;
}
/**
* Shape of template constructor
*/
interface TemplateConstructorContract {
macro: (this: any, name: string, value: (...args: any[]) => any) => void;
getter: (this: any, name: string, accumulator: () => any, singleton?: boolean) => void;
new (compiler: CompilerContract, globals: any, locals: any, processor: ProcessorContract): TemplateContract;
}
/**
* The tag must have a tagName along with other properties
* required by lexer and parser
*/
interface TagContract extends ParserTagDefinitionContract {
tagName: string;
boot?(template: TemplateConstructorContract): void;
}
/**
* Shape of required tags
*/
type TagsContract = {
[tagName: string]: TagContract;
};
/**
* Shape of the cache manager
*/
interface CacheManagerContract {
enabled: boolean;
get(templatePath: string): undefined | LoaderTemplate;
set(templatePath: string, compiledOutput: LoaderTemplate): void;
has(templatePath: string): boolean;
delete(templatePath: string): void;
}
/**
* Compiler constructor options
*/
type CompilerOptions = {
cache?: boolean;
async?: boolean;
};
/**
* Shape of the compiler
*/
interface CompilerContract {
cacheManager: CacheManagerContract;
async: boolean;
claimTag(fn: ClaimTagFn): this;
compile(templatePath: string, localVariables?: string[], skipCache?: boolean): LoaderTemplate;
tokenize(templatePath: string, parser?: Parser): Token[];
/**
* Compile the raw string as a template
*/
compileRaw(contents: string, templatePath?: string): LoaderTemplate;
/**
* Tokenize the raw string as a template
*/
tokenizeRaw(contents: string, templatePath?: string, parser?: Parser): Token[];
}
/**
* Shape of the props class passed to the components
*/
interface PropsContract {
/**
* Find if a key exists inside the props
*/
has(key: string): boolean;
/**
* Return values for only the given keys
*/
only(keys: string[]): {
[key: string]: any;
};
/**
* Return values except the given keys
*/
except(keys: string[]): {
[key: string]: any;
};
/**
* Serialize all props to a string of HTML attributes
*/
serialize(mergeProps?: any): {
value: string;
};
/**
* Serialize only the given keys to a string of HTML attributes
*/
serializeOnly(keys: string[], mergeProps?: any): {
value: string;
};
/**
* Serialize except the given keys to a string of HTML attributes
*/
serializeExcept(keys: string[], mergeProps?: any): {
value: string;
};
}
/**
* Shape of the template contract
*/
interface TemplateContract {
/**
* Compiles partial
*/
compilePartial(templatePath: string, ...localVariables: string[]): Function;
/**
* Compiles a component
*/
compileComponent(templatePath: string, ...localVariables: string[]): string;
/**
* Returns the state for a component
*/
getComponentState(props: {
[key: string]: any;
}, slots: {
[key: string]: any;
}, caller: {
filename: string;
line: number;
col: number;
}): {
$props: PropsContract & {
[key: string]: any;
};
$slots: {
[key: string]: any;
};
$caller: {
filename: string;
line: number;
col: number;
};
};
/**
* Renders a template to a string
*/
render<T extends Promise<string> | string>(template: string, state: any): T;
renderRaw<T extends Promise<string> | string>(contents: string, state: any, templatePath?: string): T;
/**
* Escape input
*/
escape(input: any): string;
/**
* Rethrow exceptions by pointing back to edge source file and line number
*/
reThrow(error: any, filename: string, line: number): never;
}
/**
* Shape of the renderer that renders the edge templates
*/
interface EdgeRendererContract {
/**
* Share state with the template and its partials and component
*/
share(locals: any): this;
/**
* Render a template asynchronously
*/
render(templatePath: string, state?: any): Promise<string>;
renderRaw(contents: string, state?: any, templatePath?: string): Promise<string>;
/**
* Render a template synchronously
*/
renderSync(templatePath: string, state?: any): string;
renderRawSync(contents: string, state?: any, templatePath?: string): string;
}
/**
* The processor is used to execute process functions for different
* lifecycles
*/
interface ProcessorContract {
/**
* Hook into the raw text to modify its contents. Make sure to return the
* new string back or return "void" in case no modifications have been
* performed
*/
process(event: 'raw', handler: (data: {
raw: string;
path: string;
}) => string | void): this;
/**
* Hook into the tag node to modify its properties
*/
process(event: 'tag', handler: (data: {
tag: TagToken;
path: string;
}) => void): this;
/**
* Hook into the compiled template to modify its contents. Make sure to return the
* new string back or return "void" in case no modifications have been
* performed
*/
process(event: 'compiled', handler: (data: {
compiled: string;
path: string;
}) => string | void): this;
/**
* Hook into the compiled output to modify its contents. Make sure to return the
* new string back or return "void" in case no modifications have been
* performed
*/
process(event: 'output', handler: (data: {
output: string;
template: TemplateContract;
state: Record<string, any>;
}) => string | void): this;
}
/**
* Shape of options that can be passed to the
* edge constructor
*/
type EdgeOptions = {
loader?: LoaderContract;
cache?: boolean;
};
/**
* Shape of the main module
*/
interface EdgeContract {
/**
* Loader for loading templates. You can also define a custom loader when creating
* a new instance of edge
*/
loader: LoaderContract;
/**
* Compiler to be used for compiling synchronously
*/
compiler: CompilerContract;
/**
* Compiler to be used for compiling asynchronously
*/
asyncCompiler: CompilerContract;
/**
* Processor reference to hook into the compile and the rendering
* phase of templates
*/
processor: ProcessorContract;
/**
* Set of registered globals. One can define custom globals using `edge.global`
* method
*/
GLOBALS: {
[key: string]: any;
};
/**
* A custom set of registered tags. One can define a custom tag using `edge.registerTag`
* method
*/
tags: {
[name: string]: TagContract;
};
/**
* Register a plugin. Plugins are lazily invoked just before the views are rendered. This
* ensures that plugins will receive a fully configured edge instance.
*
* Also plugins are invoked only once. Unless, the `options.recurring` value is set
*/
use<T extends any>(pluginFn: (edge: this, firstRun: boolean, options: T) => void, options?: T): this;
/**
* Register a custom tag
*/
registerTag(tag: TagContract): this;
/**
* Register an inline template
*/
registerTemplate(templatePath: string, contents: LoaderTemplate): this;
/**
* Remove the template registered using the "registerTemplate" method
*/
removeTemplate(templatePath: string): this;
/**
* Register a global value
*/
global(key: string, value: any): this;
/**
* Mount/disk
*/
mount(diskName: string): this;
mount(diskName: string, dirPath: string): this;
/**
* Unmount disk
*/
unmount(diskName: string): this;
/**
* Get access to the underlying template renderer. Each render call
* to edge results in creating an isolated renderer instance.
*/
onRender(callback: (renderer: EdgeRendererContract) => void): this;
/**
* Get a renderer instance to render templates
*/
getRenderer(): EdgeRendererContract;
/**
* Creates a renderer instances and shares the locals with it
*/
share(locals: any): EdgeRendererContract;
/**
* Render a template asynchronously
*/
render(templatePath: string, state?: any): Promise<string>;
renderRaw(contents: string, state?: any, templatePath?: string): Promise<string>;
/**
* Render a template synchronously
*/
renderSync(templatePath: string, state?: any): string;
renderRawSync(contents: string, state?: any, templatePath?: string): string;
}
/**
* Required for someone creating custom tags
*/
type EdgeBufferContract = EdgeBuffer;
type ParserContract = Parser;
type TagTokenContract = TagToken;
export { CacheManagerContract, CompilerContract, CompilerOptions, EdgeBufferContract, EdgeContract, EdgeOptions, EdgeRendererContract, LoaderContract, LoaderTemplate, ParserContract, ProcessorContract, PropsContract, TagContract, TagTokenContract, TagsContract, TemplateConstructorContract, TemplateContract };
export * from 'edge-lexer/types';
import 'edge-parser';
export * from 'edge-parser/types';
export { c as CacheManagerContract, C as CompiledTemplate, d as CompilerOptions, g as EdgeBufferContract, E as EdgeOptions, a as LoaderContract, L as LoaderTemplate, e as ParserContract, P as PluginFn, T as TagContract, f as TagTokenContract, b as TagsContract } from '../index-d8c609be.js';
import '@poppinss/macroable';
{
"name": "edge.js",
"description": "Template engine",
"version": "6.0.0-1",
"version": "6.0.0-2",
"engines": {

@@ -15,3 +15,5 @@ "node": ">=18.16.0"

".": "./build/index.js",
"./types": "./build/src/types.js"
"./types": "./build/src/types.js",
"./plugins/migrate": "./build/src/migrate/plugin.js",
"./globals": "./build/src/edge/globals.js"
},

@@ -30,3 +32,3 @@ "scripts": {

"version": "npm run build",
"sync-labels": "github-label-sync --labels .github/labels.json edge-js/parser",
"sync-labels": "github-label-sync --labels .github/labels.json edge-js/edge",
"quick:test": "node --enable-source-maps --loader=ts-node/esm bin/test.ts"

@@ -38,2 +40,4 @@ },

"@adonisjs/tsconfig": "^1.1.8",
"@commitlint/cli": "^17.6.7",
"@commitlint/config-conventional": "^17.6.7",
"@japa/assert": "2.0.0-1",

@@ -60,9 +64,11 @@ "@japa/file-system": "2.0.0-1",

"@poppinss/inspect": "^1.0.1",
"@poppinss/macroable": "1.0.0-7",
"@poppinss/utils": "6.5.0-5",
"@poppinss/macroable": "^1.0.0-7",
"@poppinss/utils": "^6.5.0-5",
"classnames": "^2.3.2",
"edge-error": "^4.0.0-0",
"edge-lexer": "^6.0.0-1",
"edge-parser": "^9.0.0-1",
"edge-lexer": "^6.0.0-4",
"edge-parser": "^9.0.0-3",
"he": "^1.2.0",
"js-stringify": "^1.0.2",
"property-information": "^6.2.0",
"stringify-attributes": "^4.0.0"

@@ -80,7 +86,2 @@ },

},
"config": {
"commitizen": {
"path": "cz-conventional-changelog"
}
},
"directories": {

@@ -87,0 +88,0 @@ "example": "examples",

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Packages

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc