ecto
Version:
Modern Template Consolidation Engine for EJS, Markdown, Pug, Nunjucks, Liquid, and Handlebars
403 lines (402 loc) • 16.4 kB
text/typescript
import { Cacheable, CacheableMemory } from "cacheable";
import { Hookified, HookifiedOptions } from "hookified";
//#region src/engine-interface.d.ts
type EngineInterface = {
names: string[];
engine: any;
opts?: Record<string, unknown>;
rootTemplatePath?: string;
render(source: string, data?: Record<string, unknown>): Promise<string>;
renderSync(source: string, data?: Record<string, unknown>): string;
};
//#endregion
//#region src/engine-map.d.ts
declare class EngineMap {
private readonly _mappings;
set(name: string, extensions: string[]): void;
delete(name: string): void;
deleteExtension(name: string, extension: string): void;
get(name: string): string[] | undefined;
getName(extension: string): string | undefined;
}
//#endregion
//#region src/base-engine.d.ts
declare class BaseEngine {
names: string[];
opts?: Record<string, unknown>;
engine: any;
rootTemplatePath?: string;
private _extensions;
getExtensions(): string[];
setExtensions(extensions: string[]): void;
deleteExtension(name: string): void;
}
//#endregion
//#region src/engines/ejs.d.ts
declare class EJS extends BaseEngine implements EngineInterface {
constructor(options?: Record<string, unknown>);
render(source: string, data?: Record<string, unknown>): Promise<string>;
renderSync(source: string, data?: Record<string, unknown>): string;
}
//#endregion
//#region src/engines/handlebars.d.ts
declare class Handlebars extends BaseEngine implements EngineInterface {
partialsPath: string[];
constructor(options?: Record<string, unknown>);
render(source: string, data?: Record<string, unknown>): Promise<string>;
renderSync(source: string, data?: Record<string, unknown>): string;
initPartials(): void;
registerPartials(partialsPath: string): boolean;
}
//#endregion
//#region src/engines/liquid.d.ts
declare class Liquid extends BaseEngine implements EngineInterface {
constructor(options?: Record<string, unknown>);
render(source: string, data?: Record<string, unknown>): Promise<string>;
renderSync(source: string, data?: Record<string, unknown>): string;
}
//#endregion
//#region src/engines/markdown.d.ts
declare class Markdown extends BaseEngine implements EngineInterface {
constructor(options?: Record<string, unknown>);
render(source: string, data?: Record<string, unknown>): Promise<string>;
renderSync(source: string, data?: Record<string, unknown>): string;
}
//#endregion
//#region src/engines/nunjucks.d.ts
declare class Nunjucks extends BaseEngine implements EngineInterface {
constructor(options?: Record<string, unknown>);
render(source: string, data?: Record<string, unknown>): Promise<string>;
renderSync(source: string, data?: Record<string, unknown>): string;
}
//#endregion
//#region src/engines/pug.d.ts
declare class Pug extends BaseEngine implements EngineInterface {
constructor(options?: Record<string, unknown>);
render(source: string, data?: Record<string, unknown>): Promise<string>;
renderSync(source: string, data?: Record<string, unknown>): string;
}
//#endregion
//#region src/ecto.d.ts
type EctoOptions = {
/**
* The default engine to use. This can be 'ejs', 'markdown', 'pug', 'nunjucks', 'handlebars', 'liquid'
* @default 'ejs'
* @type {string}
*/
defaultEngine?: string;
/**
* The engine options to pass to each engine
* @type {Record<string, Record<string, unknown>>}
* @default {}
* @example
* {
* nunjucks: {
* autoescape: true
* },
* markdown: {
* html: true
* }
* }
*/
engineOptions?: Record<string, Record<string, unknown>>;
/**
* Caching for async rendered templates. If set to true, it will use the default cacheable options.
* If set to Cacheable instantce, it will use the provided cacheable instance.
* @type {boolean | Cacheable}
* @default false
*/
cache?: boolean | Cacheable;
/**
* If set to true, it will cache the rendered templates synchronously when running renderSync.
* If set to CacheableMemory instance, it will use the provided cacheable memory instance.
* @type {boolean | CacheableMemory}
* @default false
*/
cacheSync?: boolean | CacheableMemory;
} & HookifiedOptions;
/**
* Context passed to beforeRender and beforeRenderSync hooks
*/
type RenderContext = {
source: string;
data?: Record<string, unknown>;
engineName: string;
rootTemplatePath?: string;
filePathOutput?: string;
cached: boolean;
};
/**
* Result passed to afterRender and afterRenderSync hooks
*/
type RenderResult = {
result: string;
context: RenderContext;
};
declare enum EctoEvents {
cacheHit = "cacheHit",
cacheMiss = "cacheMiss",
warn = "warn",
error = "error",
beforeRender = "beforeRender",
afterRender = "afterRender",
beforeRenderSync = "beforeRenderSync",
afterRenderSync = "afterRenderSync"
}
declare class Ecto extends Hookified {
private readonly _mapping;
private readonly _engines;
private _cache;
private _cacheSync;
private _defaultEngine;
private readonly _ejs;
private readonly _markdown;
private readonly _pug;
private readonly _nunjucks;
private readonly _handlebars;
private readonly _liquid;
/**
* Ecto constructor
* @param {EctoOptions} [options] - The options for the ecto engine
*/
constructor(options?: EctoOptions);
/**
* Get the default engine
* @returns {string} - the engine name such as 'ejs', 'markdown', 'pug', 'nunjucks', 'handlebars', 'liquid'
*/
get defaultEngine(): string;
/**
* Set the default engine
* @param {string} value the engine name such as 'ejs', 'markdown', 'pug', 'nunjucks', 'handlebars', 'liquid'
*/
set defaultEngine(value: string);
/**
* Get the cacheable instance
* @returns {Cacheable | undefined} - The cacheable instance or undefined if caching is disabled
*/
get cache(): Cacheable | undefined;
/**
* Set the cacheable instance
* @param {Cacheable | undefined} value - The cacheable instance to set. If set to undefined, caching will be disabled.
*/
set cache(value: Cacheable | undefined);
/**
* Get the cacheable memory instance
* @returns {CacheableMemory | undefined} - The cacheable memory instance or undefined if caching is disabled
*/
get cacheSync(): CacheableMemory | undefined;
/**
* Set the cacheable memory instance
* @param {CacheableMemory | undefined} value - The cacheable memory instance to set. If set to undefined, caching will be disabled.
*/
set cacheSync(value: CacheableMemory | undefined);
/**
* Get the Engine Mappings. This is used to map file extensions to engines
* @returns {EngineMap}
*/
get mappings(): EngineMap;
/**
* Get the EJS Engine
* @returns {EJS}
*/
get ejs(): EJS;
/**
* Get the Markdown Engine
* @returns {Markdown}
*/
get markdown(): Markdown;
/**
* Get the Pug Engine
* @returns {Pug}
*/
get pug(): Pug;
/**
* Get the Nunjucks Engine
* @returns {Nunjucks}
*/
get nunjucks(): Nunjucks;
/**
* Get the Handlebars Engine
* @returns {Handlebars}
*/
get handlebars(): Handlebars;
/**
* Get the Liquid Engine
* @returns {Liquid}
*/
get liquid(): Liquid;
/**
* Asynchronously render a template source with data using the specified engine
* @param {string} source - The template source string to render
* @param {Record<string, unknown>} [data] - Data object to pass to the template engine
* @param {string} [engineName] - Name of the engine to use (e.g., 'ejs', 'pug'). Defaults to defaultEngine
* @param {string} [rootTemplatePath] - Root directory path for template includes/partials resolution
* @param {string} [filePathOutput] - Optional file path to write the rendered output to
* @returns {Promise<string>} The rendered template output as a string
* @example
* const result = await ecto.render('<%= name %>', { name: 'World' }, 'ejs');
*/
render(source: string, data?: Record<string, unknown>, engineName?: string, rootTemplatePath?: string, filePathOutput?: string): Promise<string>;
/**
* Synchronously render a template source with data using the specified engine
* @param {string} source - The template source string to render
* @param {Record<string, unknown>} [data] - Data object to pass to the template engine
* @param {string} [engineName] - Name of the engine to use (e.g., 'ejs', 'pug'). Defaults to defaultEngine
* @param {string} [rootTemplatePath] - Root directory path for template includes/partials resolution
* @param {string} [filePathOutput] - Optional file path to write the rendered output to
* @returns {string} The rendered template output as a string
* @example
* const result = ecto.renderSync('<%= name %>', { name: 'World' }, 'ejs');
*/
renderSync(source: string, data?: Record<string, unknown>, engineName?: string, rootTemplatePath?: string, filePathOutput?: string): string;
/**
* Asynchronously render a template from a file path
* @param {string} filePath - Path to the template file to render
* @param {Record<string, unknown>} [data] - Data object to pass to the template engine
* @param {string} [rootTemplatePath] - Root directory for template includes. Defaults to file's directory
* @param {string} [filePathOutput] - Optional file path to write the rendered output to
* @param {string} [engineName] - Engine to use. If not specified, determined from file extension
* @returns {Promise<string>} The rendered template output as a string
* @example
* const result = await ecto.renderFromFile('./templates/index.ejs', { title: 'Home' });
*/
renderFromFile(filePath: string, data?: Record<string, unknown>, rootTemplatePath?: string, filePathOutput?: string, engineName?: string): Promise<string>;
/**
* Synchronously render a template from a file path
* @param {string} filePath - Path to the template file to render
* @param {Record<string, unknown>} [data] - Data object to pass to the template engine
* @param {string} [rootTemplatePath] - Root directory for template includes. Defaults to file's directory
* @param {string} [filePathOutput] - Optional file path to write the rendered output to
* @param {string} [engineName] - Engine to use. If not specified, determined from file extension
* @returns {string} The rendered template output as a string
* @example
* const result = ecto.renderFromFileSync('./templates/index.ejs', { title: 'Home' });
*/
renderFromFileSync(filePath: string, data?: Record<string, unknown>, rootTemplatePath?: string, filePathOutput?: string, engineName?: string): string;
/**
* Asynchronously ensure that the directory path for a file exists, creating it if necessary
* @param {string} path - The full file path (directories will be extracted from this)
* @returns {Promise<void>}
* @example
* await ecto.ensureFilePath('/path/to/file.txt');
*/
ensureFilePath(path: string): Promise<void>;
/**
* Synchronously ensure that the directory path for a file exists, creating it if necessary
* @param {string} path - The full file path (directories will be extracted from this)
* @returns {void}
* @example
* ecto.ensureFilePathSync('/path/to/file.txt');
*/
ensureFilePathSync(path: string): void;
/**
* Determine the appropriate template engine based on a file's extension
* @param {string} filePath - The file path to analyze
* @returns {string} The engine name (e.g., 'ejs', 'markdown', 'pug', 'nunjucks', 'handlebars', 'liquid')
* @example
* const engine = ecto.getEngineByFilePath('template.ejs'); // Returns 'ejs'
*/
getEngineByFilePath(filePath: string): string;
/**
* Asynchronously find a template file in a directory by name, regardless of extension
* @param {string} path - Directory path to search in
* @param {string} templateName - Template name without extension
* @returns {Promise<string>} Full path to the found template file, or empty string if not found
* @example
* const templatePath = await ecto.findTemplateWithoutExtension('./templates', 'index');
*/
findTemplateWithoutExtension(path: string, templateName: string): Promise<string>;
/**
* Synchronously find a template file in a directory by name, regardless of extension
* @param {string} path - Directory path to search in
* @param {string} templateName - Template name without extension
* @returns {string} Full path to the found template file, or empty string if not found
* @example
* const templatePath = ecto.findTemplateWithoutExtensionSync('./templates', 'index');
*/
findTemplateWithoutExtensionSync(path: string, templateName: string): string;
/**
* Check if the given engine name is valid and registered in Ecto
* @param {string} [engineName] - The engine name to validate
* @returns {boolean} True if the engine is valid and registered, false otherwise
* @example
* const isValid = ecto.isValidEngine('ejs'); // Returns true
*/
isValidEngine(engineName?: string): boolean;
/**
* Detect the template engine from a template string by analyzing its syntax
* @param {string} source - The template source string to analyze
* @returns {string} The detected engine name ('ejs', 'markdown', 'pug', 'nunjucks', 'handlebars', 'liquid') or the default engine
* @example
* const engine = ecto.detectEngine('<%= name %>'); // Returns 'ejs'
* const engine2 = ecto.detectEngine('{{name}}'); // Returns 'handlebars' or 'liquid'
* const engine3 = ecto.detectEngine('# Heading'); // Returns 'markdown'
* const engine4 = ecto.detectEngine('plain text'); // Returns defaultEngine (e.g., 'ejs')
*/
detectEngine(source: string): string;
/**
* Register all engine mappings between engine names and file extensions
* @returns {void}
* @private
*/
registerEngineMappings(): void;
/**
* Get the render engine instance by name
* @param {string} engineName - The name of the engine to retrieve
* @returns {EngineInterface} The engine instance (defaults to EJS if not found)
* @example
* const engine = ecto.getRenderEngine('pug');
*/
getRenderEngine(engineName: string): EngineInterface;
/**
* Check if the source content contains front matter (YAML metadata)
* @param {string} source - The source content to check
* @returns {boolean} True if front matter is present, false otherwise
* @example
* const hasFM = ecto.hasFrontMatter('---\ntitle: Test\n---\nContent');
*/
hasFrontMatter(source: string): boolean;
/**
* Extract front matter data from the source content
* @param {string} source - The source content containing front matter
* @returns {Record<string, unknown>} Parsed front matter as an object
* @example
* const data = ecto.getFrontMatter('---\ntitle: Test\n---\nContent');
*/
getFrontMatter(source: string): Record<string, unknown>;
/**
* Set or replace front matter in the source content
* @param {string} source - The source content
* @param {Record<string, unknown>} data - The front matter data to set
* @returns {string} The source content with updated front matter
* @example
* const updated = ecto.setFrontMatter('Content', { title: 'New Title' });
*/
setFrontMatter(source: string, data: Record<string, unknown>): string;
/**
* Remove front matter from the source content, returning only the body
* @param {string} source - The source content with front matter
* @returns {string} The source content without front matter
* @example
* const body = ecto.removeFrontMatter('---\ntitle: Test\n---\nContent');
*/
removeFrontMatter(source: string): string;
/**
* Write content to a file asynchronously, creating directories if needed
* @private
* @param {string} [filePath] - The path to write the file to
* @param {string} [source] - The content to write to the file
* @returns {Promise<void>}
*/
private writeFile;
/**
* Write content to a file synchronously, creating directories if needed
* @private
* @param {string} [filePath] - The path to write the file to
* @param {string} [source] - The content to write to the file
* @returns {void}
*/
private writeFileSync;
}
//#endregion
export { type BaseEngine, EJS, Ecto, EctoEvents, EctoOptions, type EngineInterface, Handlebars, Liquid, Markdown, Nunjucks, Pug, RenderContext, RenderResult };