edge.js
Advanced tools
Comparing version 6.0.0-1 to 6.0.0-2
@@ -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'; |
1781
build/index.js
@@ -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", |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Uses eval
Supply chain riskPackage uses eval() which is a dangerous function. This prevents the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Uses eval
Supply chain riskPackage uses eval() which is a dangerous function. This prevents the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Found 1 instance in 1 package
8
2
83383
11
23
2672
+ Addedclassnames@^2.3.2
+ Addedproperty-information@^6.2.0
+ Added@poppinss/macroable@1.0.2(transitive)
+ Added@poppinss/utils@6.7.3(transitive)
+ Added@types/pluralize@0.0.33(transitive)
+ Addedclassnames@2.5.1(transitive)
+ Addedproperty-information@6.5.0(transitive)
- Removed@poppinss/macroable@1.0.0-7(transitive)
- Removed@poppinss/utils@6.5.0-5(transitive)
- Removed@types/pluralize@0.0.30(transitive)
Updated@poppinss/macroable@^1.0.0-7
Updated@poppinss/utils@^6.5.0-5
Updatededge-lexer@^6.0.0-4
Updatededge-parser@^9.0.0-3