diff --git a/deno_dist/README.md b/deno_dist/README.md index 647da37..7ee6e57 100644 --- a/deno_dist/README.md +++ b/deno_dist/README.md @@ -12,7 +12,7 @@

-[logo]: https://img.shields.io/badge/all_contributors-7-orange.svg 'Number of contributors on All-Contributors' +[logo]: https://img.shields.io/badge/all_contributors-8-orange.svg 'Number of contributors on All-Contributors' @@ -134,6 +134,45 @@ Simply put, Eta is super: super lightweight, super fast, super powerful, and sup Additionally, Eta is a letter of the Greek alphabet (it stands for all sorts of cool things in various mathematical fields, including efficiency) and is three letters long (perfect for a file extension). +## Integrations + +
+ + ESLint + + + [eslint-plugin-eta](https://github.com/eta-dev/eslint-plugin-eta) was created to provide an ESLint processor so you can lint your Eta templates. + +
+ +
+ + CLI + + + An official Eta CLI exists called [etajs-cli](https://github.com/eta-dev/etajs-cli). + +
+ +
+ + Webpack + + + Currently there is no official Webpack integration but [@clshortfuse](https://github.com/clshortfuse) shared the loader he uses: + ```javascript + { + loader: 'html-loader', + options: { + preprocessor(content, loaderContext) { + return eta.render(content, {}, { filename: loaderContext.resourcePath }); + }, + }, + } + ``` + +
+ ## 📜 Docs We know nobody reads through the long and boring documentation in the ReadMe anyway, so head over to the documentation website: @@ -216,6 +255,9 @@ Made with ❤ by [@nebrelbug](https://github.com/eta-dev) and all these wonderfu
shadowtime2000

💻 🤔
Hamza Hamidi

📖 + +
Calum Knott

🤔 + diff --git a/deno_dist/browser.ts b/deno_dist/browser.ts index efb2e48..7df6463 100644 --- a/deno_dist/browser.ts +++ b/deno_dist/browser.ts @@ -1,11 +1,6 @@ -export { default as compileToString } from "./compile-string.ts"; -export { default as compile } from "./compile.ts"; -export { default as parse } from "./parse.ts"; -export { default as render } from "./render.ts"; -export { templates } from "./containers.ts"; -export { - config, - config as defaultConfig, - configure, - getConfig, -} from "./config.ts"; +export { default as compileToString } from './compile-string.ts' +export { default as compile } from './compile.ts' +export { default as parse } from './parse.ts' +export { default as render, renderAsync } from './render.ts' +export { templates } from './containers.ts' +export { config, config as defaultConfig, getConfig, configure } from './config.ts' diff --git a/deno_dist/compile-string.ts b/deno_dist/compile-string.ts index 797e5d9..b20bea5 100644 --- a/deno_dist/compile-string.ts +++ b/deno_dist/compile-string.ts @@ -1,9 +1,9 @@ -import Parse from "./parse.ts"; +import Parse from './parse.ts' /* TYPES */ -import type { EtaConfig } from "./config.ts"; -import type { AstObject } from "./parse.ts"; +import type { EtaConfig } from './config.ts' +import type { AstObject } from './parse.ts' /* END TYPES */ @@ -18,40 +18,38 @@ import type { AstObject } from "./parse.ts"; * ``` */ -export default function compileToString( - str: string, - config: EtaConfig, -): string { - var buffer: Array = Parse(str, config); - - var res = "var tR='',__l,__lP" + - (config.include ? ",include=E.include.bind(E)" : "") + - (config.includeFile ? ",includeFile=E.includeFile.bind(E)" : "") + - "\nfunction layout(p,d){__l=p;__lP=d}\n" + - (config.useWith ? "with(" + config.varName + "||{}){" : "") + +export default function compileToString(str: string, config: EtaConfig): string { + var buffer: Array = Parse(str, config) + + var res = + "var tR='',__l,__lP" + + (config.include ? ',include=E.include.bind(E)' : '') + + (config.includeFile ? ',includeFile=E.includeFile.bind(E)' : '') + + '\nfunction layout(p,d){__l=p;__lP=d}\n' + + (config.useWith ? 'with(' + config.varName + '||{}){' : '') + compileScope(buffer, config) + (config.includeFile - ? "if(__l)tR=" + - (config.async ? "await " : "") + + ? 'if(__l)tR=' + + (config.async ? 'await ' : '') + `includeFile(__l,Object.assign(${config.varName},{body:tR},__lP))\n` : config.include - ? "if(__l)tR=" + - (config.async ? "await " : "") + + ? 'if(__l)tR=' + + (config.async ? 'await ' : '') + `include(__l,Object.assign(${config.varName},{body:tR},__lP))\n` - : "") + - "if(cb){cb(null,tR)} return tR" + - (config.useWith ? "}" : ""); + : '') + + 'if(cb){cb(null,tR)} return tR' + + (config.useWith ? '}' : '') if (config.plugins) { for (var i = 0; i < config.plugins.length; i++) { - var plugin = config.plugins[i]; + var plugin = config.plugins[i] if (plugin.processFnString) { - res = plugin.processFnString(res, config); + res = plugin.processFnString(res, config) } } } - return res; + return res } /** @@ -68,47 +66,47 @@ export default function compileToString( */ function compileScope(buff: Array, config: EtaConfig) { - var i = 0; - var buffLength = buff.length; - var returnStr = ""; + var i = 0 + var buffLength = buff.length + var returnStr = '' for (i; i < buffLength; i++) { - var currentBlock = buff[i]; - if (typeof currentBlock === "string") { - var str = currentBlock; + var currentBlock = buff[i] + if (typeof currentBlock === 'string') { + var str = currentBlock // we know string exists - returnStr += "tR+='" + str + "'\n"; + returnStr += "tR+='" + str + "'\n" } else { - var type = currentBlock.t; // ~, s, !, ?, r - var content = currentBlock.val || ""; + var type = currentBlock.t // ~, s, !, ?, r + var content = currentBlock.val || '' - if (type === "r") { + if (type === 'r') { // raw if (config.filter) { - content = "E.filter(" + content + ")"; + content = 'E.filter(' + content + ')' } - returnStr += "tR+=" + content + "\n"; - } else if (type === "i") { + returnStr += 'tR+=' + content + '\n' + } else if (type === 'i') { // interpolate if (config.filter) { - content = "E.filter(" + content + ")"; + content = 'E.filter(' + content + ')' } if (config.autoEscape) { - content = "E.e(" + content + ")"; + content = 'E.e(' + content + ')' } - returnStr += "tR+=" + content + "\n"; + returnStr += 'tR+=' + content + '\n' // reference - } else if (type === "e") { + } else if (type === 'e') { // execute - returnStr += content + "\n"; // you need a \n in case you have <% } %> + returnStr += content + '\n' // you need a \n in case you have <% } %> } } } - return returnStr; + return returnStr } diff --git a/deno_dist/compile.ts b/deno_dist/compile.ts index 32d4170..39e078a 100644 --- a/deno_dist/compile.ts +++ b/deno_dist/compile.ts @@ -1,17 +1,13 @@ -import compileToString from "./compile-string.ts"; -import { getConfig } from "./config.ts"; -import EtaErr from "./err.ts"; +import compileToString from './compile-string.ts' +import { getConfig } from './config.ts' +import EtaErr from './err.ts' /* TYPES */ -import type { EtaConfig, PartialConfig } from "./config.ts"; -import type { CallbackFn } from "./file-handlers.ts"; -import { getAsyncFunctionConstructor } from "./polyfills.ts"; -export type TemplateFunction = ( - data: object, - config: EtaConfig, - cb?: CallbackFn, -) => string; +import type { EtaConfig, PartialConfig } from './config.ts' +import type { CallbackFn } from './file-handlers.ts' +import { getAsyncFunctionConstructor } from './polyfills.ts' +export type TemplateFunction = (data: object, config: EtaConfig, cb?: CallbackFn) => string /* END TYPES */ @@ -31,41 +27,38 @@ export type TemplateFunction = ( * ``` */ -export default function compile( - str: string, - config?: PartialConfig, -): TemplateFunction { - var options: EtaConfig = getConfig(config || {}); - var ctor; // constructor +export default function compile(str: string, config?: PartialConfig): TemplateFunction { + var options: EtaConfig = getConfig(config || {}) + var ctor // constructor /* ASYNC HANDLING */ // The below code is modified from mde/ejs. All credit should go to them. if (options.async) { - ctor = getAsyncFunctionConstructor() as FunctionConstructor; + ctor = getAsyncFunctionConstructor() as FunctionConstructor } else { - ctor = Function; + ctor = Function } /* END ASYNC HANDLING */ try { return new ctor( options.varName, - "E", // EtaConfig - "cb", // optional callback - compileToString(str, options), - ) as TemplateFunction; // eslint-disable-line no-new-func + 'E', // EtaConfig + 'cb', // optional callback + compileToString(str, options) + ) as TemplateFunction // eslint-disable-line no-new-func } catch (e) { if (e instanceof SyntaxError) { throw EtaErr( - "Bad template syntax\n\n" + + 'Bad template syntax\n\n' + e.message + - "\n" + - Array(e.message.length + 1).join("=") + - "\n" + + '\n' + + Array(e.message.length + 1).join('=') + + '\n' + compileToString(str, options) + - "\n", // This will put an extra newline before the callstack for extra readability - ); + '\n' // This will put an extra newline before the callstack for extra readability + ) } else { - throw e; + throw e } } } diff --git a/deno_dist/config.ts b/deno_dist/config.ts index 21a8296..7945542 100644 --- a/deno_dist/config.ts +++ b/deno_dist/config.ts @@ -1,101 +1,95 @@ -import { templates } from "./containers.ts"; -import { copyProps, XMLEscape } from "./utils.ts"; -import EtaErr from "./err.ts"; +import { templates } from './containers.ts' +import { copyProps, XMLEscape } from './utils.ts' +import EtaErr from './err.ts' /* TYPES */ -import type { TemplateFunction } from "./compile.ts"; -import type { Cacher } from "./storage.ts"; +import type { TemplateFunction } from './compile.ts' +import type { Cacher } from './storage.ts' -type trimConfig = "nl" | "slurp" | false; +type trimConfig = 'nl' | 'slurp' | false export interface EtaConfig { /** Whether or not to automatically XML-escape interpolations. Default true */ - autoEscape: boolean; + autoEscape: boolean /** Configure automatic whitespace trimming. Default `[false, 'nl']` */ - autoTrim: trimConfig | [trimConfig, trimConfig]; + autoTrim: trimConfig | [trimConfig, trimConfig] /** Compile to async function */ - async: boolean; + async: boolean /** Whether or not to cache templates if `name` or `filename` is passed */ - cache: boolean; + cache: boolean /** XML-escaping function */ - e: (str: string) => string; + e: (str: string) => string /** Parsing options */ parse: { /** Which prefix to use for evaluation. Default `""` */ - exec: string; + exec: string /** Which prefix to use for interpolation. Default `"="` */ - interpolate: string; + interpolate: string /** Which prefix to use for raw interpolation. Default `"~"` */ - raw: string; - }; + raw: string + } /** Array of plugins */ - plugins: Array< - { - processFnString?: Function; - processAST?: Function; - processTemplate?: Function; - } - >; + plugins: Array<{ processFnString?: Function; processAST?: Function; processTemplate?: Function }> /** Remove all safe-to-remove whitespace */ - rmWhitespace: boolean; + rmWhitespace: boolean /** Delimiters: by default `['<%', '%>']` */ - tags: [string, string]; + tags: [string, string] /** Holds template cache */ - templates: Cacher; + templates: Cacher /** Name of the data object. Default `it` */ - varName: string; + varName: string /** Absolute path to template file */ - filename?: string; + filename?: string /** Holds cache of resolved filepaths. Set to `false` to disable */ - filepathCache?: Record | false; + filepathCache?: Record | false /** A filter function applied to every interpolation or raw interpolation */ - filter?: Function; + filter?: Function /** Function to include templates by name */ - include?: Function; + include?: Function /** Function to include templates by filepath */ - includeFile?: Function; + includeFile?: Function /** Name of template */ - name?: string; + name?: string /** Where should absolute paths begin? Default '/' */ - root?: string; + root?: string /** Make data available on the global object instead of varName */ - useWith?: boolean; + useWith?: boolean /** Whether or not to cache templates if `name` or `filename` is passed: duplicate of `cache` */ - "view cache"?: boolean; + 'view cache'?: boolean /** Directory or directories that contain templates */ - views?: string | Array; + views?: string | Array - [index: string]: any; // eslint-disable-line @typescript-eslint/no-explicit-any + [index: string]: any // eslint-disable-line @typescript-eslint/no-explicit-any } export interface EtaConfigWithFilename extends EtaConfig { - filename: string; + filename: string } -export type PartialConfig = Partial; +export type PartialConfig = Partial /* END TYPES */ @@ -105,38 +99,34 @@ export type PartialConfig = Partial; * Called like `include(templateNameOrPath, data)` */ -function includeHelper( - this: EtaConfig, - templateNameOrPath: string, - data: object, -): string { - var template = this.templates.get(templateNameOrPath); +function includeHelper(this: EtaConfig, templateNameOrPath: string, data: object): string { + var template = this.templates.get(templateNameOrPath) if (!template) { - throw EtaErr('Could not fetch template "' + templateNameOrPath + '"'); + throw EtaErr('Could not fetch template "' + templateNameOrPath + '"') } - return template(data, this); + return template(data, this) } /** Eta's base (global) configuration */ var config: EtaConfig = { async: false, autoEscape: true, - autoTrim: [false, "nl"], + autoTrim: [false, 'nl'], cache: false, e: XMLEscape, include: includeHelper, parse: { - exec: "", - interpolate: "=", - raw: "~", + exec: '', + interpolate: '=', + raw: '~' }, plugins: [], rmWhitespace: false, - tags: ["<%", "%>"], + tags: ['<%', '%>'], templates: templates, useWith: false, - varName: "it", -}; + varName: 'it' +} /** * Takes one or two partial (not necessarily complete) configuration objects, merges them 1 layer deep into eta.config, and returns the result @@ -154,24 +144,24 @@ var config: EtaConfig = { function getConfig(override: PartialConfig, baseConfig?: EtaConfig): EtaConfig { // TODO: run more tests on this - var res: PartialConfig = {}; // Linked - copyProps(res, config); // Creates deep clone of eta.config, 1 layer deep + var res: PartialConfig = {} // Linked + copyProps(res, config) // Creates deep clone of eta.config, 1 layer deep if (baseConfig) { - copyProps(res, baseConfig); + copyProps(res, baseConfig) } if (override) { - copyProps(res, override); + copyProps(res, override) } - return res as EtaConfig; + return res as EtaConfig } /** Update Eta's base config */ function configure(options: PartialConfig): Partial { - return copyProps(config, options); + return copyProps(config, options) } -export { config, configure, getConfig }; +export { config, getConfig, configure } diff --git a/deno_dist/containers.ts b/deno_dist/containers.ts index 004bcd2..71f27c5 100644 --- a/deno_dist/containers.ts +++ b/deno_dist/containers.ts @@ -1,8 +1,8 @@ -import { Cacher } from "./storage.ts"; +import { Cacher } from './storage.ts' /* TYPES */ -import type { TemplateFunction } from "./compile.ts"; +import type { TemplateFunction } from './compile.ts' /* END TYPES */ @@ -12,6 +12,6 @@ import type { TemplateFunction } from "./compile.ts"; * Stores partials and cached templates */ -var templates = new Cacher({}); +var templates = new Cacher({}) -export { templates }; +export { templates } diff --git a/deno_dist/err.ts b/deno_dist/err.ts index 377228e..6e5930b 100644 --- a/deno_dist/err.ts +++ b/deno_dist/err.ts @@ -1,9 +1,9 @@ function setPrototypeOf(obj: any, proto: any) { // eslint-disable-line @typescript-eslint/no-explicit-any if (Object.setPrototypeOf) { - Object.setPrototypeOf(obj, proto); + Object.setPrototypeOf(obj, proto) } else { - obj.__proto__ = proto; + obj.__proto__ = proto } } @@ -23,34 +23,35 @@ function setPrototypeOf(obj: any, proto: any) { */ export default function EtaErr(message: string): Error { - var err = new Error(message); - setPrototypeOf(err, EtaErr.prototype); - return err; + var err = new Error(message) + setPrototypeOf(err, EtaErr.prototype) + return err } EtaErr.prototype = Object.create(Error.prototype, { - name: { value: "Eta Error", enumerable: false }, -}); + name: { value: 'Eta Error', enumerable: false } +}) /** * Throws an EtaErr with a nicely formatted error and message showing where in the template the error occurred. */ export function ParseErr(message: string, str: string, indx: number): void { - var whitespace = str.slice(0, indx).split(/\n/); + var whitespace = str.slice(0, indx).split(/\n/) - var lineNo = whitespace.length; - var colNo = whitespace[lineNo - 1].length + 1; - message += " at line " + + var lineNo = whitespace.length + var colNo = whitespace[lineNo - 1].length + 1 + message += + ' at line ' + lineNo + - " col " + + ' col ' + colNo + - ":\n\n" + - " " + + ':\n\n' + + ' ' + str.split(/\n/)[lineNo - 1] + - "\n" + - " " + - Array(colNo).join(" ") + - "^"; - throw EtaErr(message); + '\n' + + ' ' + + Array(colNo).join(' ') + + '^' + throw EtaErr(message) } diff --git a/deno_dist/file-handlers.ts b/deno_dist/file-handlers.ts index e177365..8ce17e4 100644 --- a/deno_dist/file-handlers.ts +++ b/deno_dist/file-handlers.ts @@ -1,33 +1,29 @@ // express is set like: app.engine('html', require('eta').renderFile) -import EtaErr from "./err.ts"; -import compile from "./compile.ts"; -import { getConfig } from "./config.ts"; -import { getPath, readFile } from "./file-utils.ts"; -import { copyProps } from "./utils.ts"; -import { promiseImpl } from "./polyfills.ts"; +import EtaErr from './err.ts' +import compile from './compile.ts' +import { getConfig } from './config.ts' +import { getPath, readFile } from './file-utils.ts' +import { copyProps } from './utils.ts' +import { promiseImpl } from './polyfills.ts' /* TYPES */ -import type { - EtaConfig, - EtaConfigWithFilename, - PartialConfig, -} from "./config.ts"; -import type { TemplateFunction } from "./compile.ts"; +import type { EtaConfig, PartialConfig, EtaConfigWithFilename } from './config.ts' +import type { TemplateFunction } from './compile.ts' -export type CallbackFn = (err: Error | null, str?: string) => void; +export type CallbackFn = (err: Error | null, str?: string) => void interface DataObj { /** Express.js settings may be stored here */ settings?: { - [key: string]: any; // eslint-disable-line @typescript-eslint/no-explicit-any - }; - [key: string]: any; // eslint-disable-line @typescript-eslint/no-explicit-any + [key: string]: any // eslint-disable-line @typescript-eslint/no-explicit-any + } + [key: string]: any // eslint-disable-line @typescript-eslint/no-explicit-any } interface PartialConfigWithFilename extends Partial { - filename: string; + filename: string } /* END TYPES */ @@ -43,21 +39,18 @@ interface PartialConfigWithFilename extends Partial { export function loadFile( filePath: string, options: PartialConfigWithFilename, - noCache?: boolean, + noCache?: boolean ): TemplateFunction { - var config = getConfig(options); - var template = readFile(filePath); + var config = getConfig(options) + var template = readFile(filePath) try { - var compiledTemplate = compile(template, config); + var compiledTemplate = compile(template, config) if (!noCache) { - config.templates.define( - (config as EtaConfigWithFilename).filename, - compiledTemplate, - ); + config.templates.define((config as EtaConfigWithFilename).filename, compiledTemplate) } - return compiledTemplate; + return compiledTemplate } catch (e) { - throw EtaErr("Loading file: " + filePath + " failed:\n\n" + e.message); + throw EtaErr('Loading file: ' + filePath + ' failed:\n\n' + e.message) } } @@ -73,19 +66,19 @@ export function loadFile( */ function handleCache(options: EtaConfigWithFilename): TemplateFunction { - var filename = options.filename; + var filename = options.filename if (options.cache) { - var func = options.templates.get(filename); + var func = options.templates.get(filename) if (func) { - return func; + return func } - return loadFile(filename, options); + return loadFile(filename, options) } // Caching is disabled, so pass noCache = true - return loadFile(filename, options, true); + return loadFile(filename, options, true) } /** @@ -98,38 +91,30 @@ function handleCache(options: EtaConfigWithFilename): TemplateFunction { * @param cb callback */ -function tryHandleCache( - data: object, - options: EtaConfigWithFilename, - cb: CallbackFn | undefined, -) { +function tryHandleCache(data: object, options: EtaConfigWithFilename, cb: CallbackFn | undefined) { if (cb) { try { // Note: if there is an error while rendering the template, // It will bubble up and be caught here - var templateFn = handleCache(options); - templateFn(data, options, cb); + var templateFn = handleCache(options) + templateFn(data, options, cb) } catch (err) { - return cb(err); + return cb(err) } } else { // No callback, try returning a promise - if (typeof promiseImpl === "function") { - return new promiseImpl( - function (resolve: Function, reject: Function) { - try { - var templateFn = handleCache(options); - var result = templateFn(data, options); - resolve(result); - } catch (err) { - reject(err); - } - }, - ); + if (typeof promiseImpl === 'function') { + return new promiseImpl(function (resolve: Function, reject: Function) { + try { + var templateFn = handleCache(options) + var result = templateFn(data, options) + resolve(result) + } catch (err) { + reject(err) + } + }) } else { - throw EtaErr( - "Please provide a callback function, this env doesn't support Promises", - ); + throw EtaErr("Please provide a callback function, this env doesn't support Promises") } } } @@ -151,14 +136,11 @@ function tryHandleCache( * @return [Eta template function, new config object] */ -function includeFile( - path: string, - options: EtaConfig, -): [TemplateFunction, EtaConfig] { +function includeFile(path: string, options: EtaConfig): [TemplateFunction, EtaConfig] { // the below creates a new options object, using the parent filepath of the old options object and the path - var newFileOptions = getConfig({ filename: getPath(path, options) }, options); + var newFileOptions = getConfig({ filename: getPath(path, options) }, options) // TODO: make sure properties are currectly copied over - return [handleCache(newFileOptions as EtaConfigWithFilename), newFileOptions]; + return [handleCache(newFileOptions as EtaConfigWithFilename), newFileOptions] } /** @@ -192,20 +174,16 @@ function renderFile( filename: string, data: DataObj, config?: PartialConfig, - cb?: CallbackFn, -): Promise | void; + cb?: CallbackFn +): Promise | void -function renderFile( - filename: string, - data: DataObj, - cb?: CallbackFn, -): Promise | void; +function renderFile(filename: string, data: DataObj, cb?: CallbackFn): Promise | void function renderFile( filename: string, data: DataObj, config?: PartialConfig, - cb?: CallbackFn, + cb?: CallbackFn ): Promise | void { /* Here we have some function overloading. @@ -215,54 +193,70 @@ function renderFile( And we want to also make (filename, data, options, cb) available */ - var renderConfig: EtaConfigWithFilename; - var callback: CallbackFn | undefined; - data = data || {}; // If data is undefined, we don't want accessing data.settings to error + var renderConfig: EtaConfigWithFilename + var callback: CallbackFn | undefined + data = data || {} // If data is undefined, we don't want accessing data.settings to error // First, assign our callback function to `callback` // We can leave it undefined if neither parameter is a function; // Callbacks are optional - if (typeof cb === "function") { + if (typeof cb === 'function') { // The 4th argument is the callback - callback = cb; - } else if (typeof config === "function") { + callback = cb + } else if (typeof config === 'function') { // The 3rd arg is the callback - callback = config; + callback = config } // If there is a config object passed in explicitly, use it - if (typeof config === "object") { - renderConfig = getConfig( - (config as PartialConfig) || {}, - ) as EtaConfigWithFilename; + if (typeof config === 'object') { + renderConfig = getConfig((config as PartialConfig) || {}) as EtaConfigWithFilename } else { // Otherwise, get the config from the data object // And then grab some config options from data.settings // Which is where Express sometimes stores them - renderConfig = getConfig(data as PartialConfig) as EtaConfigWithFilename; + renderConfig = getConfig(data as PartialConfig) as EtaConfigWithFilename if (data.settings) { // Pull a few things from known locations if (data.settings.views) { - renderConfig.views = data.settings.views; + renderConfig.views = data.settings.views } - if (data.settings["view cache"]) { - renderConfig.cache = true; + if (data.settings['view cache']) { + renderConfig.cache = true } // Undocumented after Express 2, but still usable, esp. for // items that are unsafe to be passed along with data, like `root` - var viewOpts = data.settings["view options"]; + var viewOpts = data.settings['view options'] if (viewOpts) { - copyProps(renderConfig, viewOpts); + copyProps(renderConfig, viewOpts) } } } // Set the filename option on the template // This will first try to resolve the file path (see getPath for details) - renderConfig.filename = getPath(filename, renderConfig); + renderConfig.filename = getPath(filename, renderConfig) - return tryHandleCache(data, renderConfig, callback); + return tryHandleCache(data, renderConfig, callback) +} + +function renderFileAsync( + filename: string, + data: DataObj, + config?: PartialConfig, + cb?: CallbackFn +): Promise | void + +function renderFileAsync(filename: string, data: DataObj, cb?: CallbackFn): Promise | void + +function renderFileAsync( + filename: string, + data: DataObj, + config?: PartialConfig, + cb?: CallbackFn +): Promise | void { + return renderFile(filename, data, { ...config, async: true }, cb) } -export { includeFile, renderFile }; +export { includeFile, renderFile, renderFileAsync } diff --git a/deno_dist/file-helpers.ts b/deno_dist/file-helpers.ts index a009c40..551ded2 100644 --- a/deno_dist/file-helpers.ts +++ b/deno_dist/file-helpers.ts @@ -1,11 +1,11 @@ -import { includeFile } from "./file-handlers.ts"; +import { includeFile } from './file-handlers.ts' /* TYPES */ -import type { EtaConfig } from "./config.ts"; +import type { EtaConfig } from './config.ts' interface GenericData { - [index: string]: any; // eslint-disable-line @typescript-eslint/no-explicit-any + [index: string]: any // eslint-disable-line @typescript-eslint/no-explicit-any } /* END TYPES */ @@ -14,11 +14,7 @@ interface GenericData { * Called with `includeFile(path, data)` */ -export function includeFileHelper( - this: EtaConfig, - path: string, - data: GenericData, -): string { - var templateAndConfig = includeFile(path, this); - return templateAndConfig[0](data, templateAndConfig[1]); +export function includeFileHelper(this: EtaConfig, path: string, data: GenericData): string { + var templateAndConfig = includeFile(path, this) + return templateAndConfig[0](data, templateAndConfig[1]) } diff --git a/deno_dist/file-methods.ts b/deno_dist/file-methods.ts index b4c921f..f2cce45 100644 --- a/deno_dist/file-methods.ts +++ b/deno_dist/file-methods.ts @@ -1,4 +1,4 @@ -export * as fs from "https://deno.land/std@0.66.0/fs/mod.ts"; -export * as path from "https://deno.land/std@0.66.0/path/mod.ts"; +export * as fs from "https://deno.land/std@0.66.0/fs/mod.ts" +export * as path from "https://deno.land/std@0.66.0/path/mod.ts" -export var readFileSync = Deno.readTextFileSync; +export var readFileSync = Deno.readTextFileSync diff --git a/deno_dist/file-utils.ts b/deno_dist/file-utils.ts index eca8080..0815db2 100644 --- a/deno_dist/file-utils.ts +++ b/deno_dist/file-utils.ts @@ -1,13 +1,13 @@ -import { fs, path, readFileSync } from "./file-methods.ts"; -var _BOM = /^\uFEFF/; +import { fs, path, readFileSync } from './file-methods.ts' +var _BOM = /^\uFEFF/ // express is set like: app.engine('html', require('eta').renderFile) -import EtaErr from "./err.ts"; +import EtaErr from './err.ts' /* TYPES */ -import type { EtaConfig } from "./config.ts"; +import type { EtaConfig } from './config.ts' /* END TYPES */ @@ -23,20 +23,16 @@ import type { EtaConfig } from "./config.ts"; * @return absolute path to template */ -function getWholeFilePath( - name: string, - parentfile: string, - isDirectory?: boolean, -): string { +function getWholeFilePath(name: string, parentfile: string, isDirectory?: boolean): string { var includePath = path.resolve( isDirectory ? parentfile : path.dirname(parentfile), // returns directory the parent file is in - name, // file - ); - var ext = path.extname(name); + name // file + ) + var ext = path.extname(name) if (!ext) { - includePath += ".eta"; + includePath += '.eta' } - return includePath; + return includePath } /** @@ -58,9 +54,9 @@ function getWholeFilePath( */ function getPath(path: string, options: EtaConfig): string { - var includePath: string | false = false; - var views = options.views; - var searchedPaths: Array = []; + var includePath: string | false = false + var views = options.views + var searchedPaths: Array = [] // If these four values are the same, // getPath() will return the same result every time. @@ -70,20 +66,18 @@ function getPath(path: string, options: EtaConfig): string { filename: options.filename, // filename of the template which called includeFile() path: path, root: options.root, - views: options.views, - }); + views: options.views + }) - if ( - options.cache && options.filepathCache && options.filepathCache[pathOptions] - ) { + if (options.cache && options.filepathCache && options.filepathCache[pathOptions]) { // Use the cached filepath - return options.filepathCache[pathOptions]; + return options.filepathCache[pathOptions] } /** Add a filepath to the list of paths we've checked for a template */ function addPathToSearched(pathSearched: string) { if (!searchedPaths.includes(pathSearched)) { - searchedPaths.push(pathSearched); + searchedPaths.push(pathSearched) } } @@ -95,97 +89,87 @@ function getPath(path: string, options: EtaConfig): string { * @param path the path to the template */ - function searchViews( - views: Array | string | undefined, - path: string, - ): string | false { - var filePath; + function searchViews(views: Array | string | undefined, path: string): string | false { + var filePath // If views is an array, then loop through each directory // And attempt to find the template if ( Array.isArray(views) && views.some(function (v) { - filePath = getWholeFilePath(path, v, true); + filePath = getWholeFilePath(path, v, true) - addPathToSearched(filePath); + addPathToSearched(filePath) - return fs.existsSync(filePath); + return fs.existsSync(filePath) }) ) { // If the above returned true, we know that the filePath was just set to a path // That exists (Array.some() returns as soon as it finds a valid element) - return (filePath as unknown) as string; - } else if (typeof views === "string") { + return (filePath as unknown) as string + } else if (typeof views === 'string') { // Search for the file if views is a single directory - filePath = getWholeFilePath(path, views, true); + filePath = getWholeFilePath(path, views, true) - addPathToSearched(filePath); + addPathToSearched(filePath) if (fs.existsSync(filePath)) { - return filePath; + return filePath } } // Unable to find a file - return false; + return false } // Path starts with '/', 'C:\', etc. - var match = /^[A-Za-z]+:\\|^\//.exec(path); + var match = /^[A-Za-z]+:\\|^\//.exec(path) // Absolute path, like /partials/partial.eta if (match && match.length) { // We have to trim the beginning '/' off the path, or else // path.resolve(dir, path) will always resolve to just path - var formattedPath = path.replace(/^\/*/, ""); + var formattedPath = path.replace(/^\/*/, '') // First, try to resolve the path within options.views - includePath = searchViews(views, formattedPath); + includePath = searchViews(views, formattedPath) if (!includePath) { // If that fails, searchViews will return false. Try to find the path // inside options.root (by default '/', the base of the filesystem) - var pathFromRoot = getWholeFilePath( - formattedPath, - options.root || "/", - true, - ); + var pathFromRoot = getWholeFilePath(formattedPath, options.root || '/', true) - addPathToSearched(pathFromRoot); + addPathToSearched(pathFromRoot) - includePath = pathFromRoot; + includePath = pathFromRoot } } else { // Relative paths // Look relative to a passed filename first if (options.filename) { - var filePath = getWholeFilePath(path, options.filename); + var filePath = getWholeFilePath(path, options.filename) - addPathToSearched(filePath); + addPathToSearched(filePath) if (fs.existsSync(filePath)) { - includePath = filePath; + includePath = filePath } } // Then look for the template in options.views if (!includePath) { - includePath = searchViews(views, path); + includePath = searchViews(views, path) } if (!includePath) { - throw EtaErr( - 'Could not find the template "' + path + '". Paths tried: ' + - searchedPaths, - ); + throw EtaErr('Could not find the template "' + path + '". Paths tried: ' + searchedPaths) } } // If caching and filepathCache are enabled, // cache the input & output of this function. if (options.cache && options.filepathCache) { - options.filepathCache[pathOptions] = includePath; + options.filepathCache[pathOptions] = includePath } - return includePath; + return includePath } /** @@ -194,10 +178,10 @@ function getPath(path: string, options: EtaConfig): string { function readFile(filePath: string): string { try { - return readFileSync(filePath).toString().replace(_BOM, ""); // TODO: is replacing BOM's necessary? + return readFileSync(filePath).toString().replace(_BOM, '') // TODO: is replacing BOM's necessary? } catch { - throw EtaErr("Failed to read template at '" + filePath + "'"); + throw EtaErr("Failed to read template at '" + filePath + "'") } } -export { getPath, readFile }; +export { getPath, readFile } diff --git a/deno_dist/mod.ts b/deno_dist/mod.ts index 4f41a05..0216471 100644 --- a/deno_dist/mod.ts +++ b/deno_dist/mod.ts @@ -1,26 +1,17 @@ /* Export file stuff */ -import { includeFileHelper } from "./file-helpers.ts"; -import { config } from "./config.ts"; +import { includeFileHelper } from './file-helpers.ts' +import { config } from './config.ts' -config.includeFile = includeFileHelper; -config.filepathCache = {}; +config.includeFile = includeFileHelper +config.filepathCache = {} -export { - loadFile, - renderFile, - renderFile as __express, -} from "./file-handlers.ts"; +export { loadFile, renderFile, renderFileAsync, renderFile as __express } from './file-handlers.ts' /* End file stuff */ -export { default as compileToString } from "./compile-string.ts"; -export { default as compile } from "./compile.ts"; -export { default as parse } from "./parse.ts"; -export { default as render } from "./render.ts"; -export { templates } from "./containers.ts"; -export { - config, - config as defaultConfig, - configure, - getConfig, -} from "./config.ts"; +export { default as compileToString } from './compile-string.ts' +export { default as compile } from './compile.ts' +export { default as parse } from './parse.ts' +export { default as render, renderAsync } from './render.ts' +export { templates } from './containers.ts' +export { config, config as defaultConfig, getConfig, configure } from './config.ts' diff --git a/deno_dist/parse.ts b/deno_dist/parse.ts index 19e69fc..82efeca 100644 --- a/deno_dist/parse.ts +++ b/deno_dist/parse.ts @@ -1,49 +1,45 @@ -import { ParseErr } from "./err.ts"; -import { trimWS } from "./utils.ts"; +import { ParseErr } from './err.ts' +import { trimWS } from './utils.ts' /* TYPES */ -import type { EtaConfig } from "./config.ts"; +import type { EtaConfig } from './config.ts' -export type TagType = "r" | "e" | "i" | ""; +export type TagType = 'r' | 'e' | 'i' | '' export interface TemplateObject { - t: TagType; - val: string; + t: TagType + val: string } -export type AstObject = string | TemplateObject; +export type AstObject = string | TemplateObject /* END TYPES */ -var templateLitReg = - /`(?:\\[\s\S]|\${(?:[^{}]|{(?:[^{}]|{[^}]*})*})*}|(?!\${)[^\\`])*`/g; +var templateLitReg = /`(?:\\[\s\S]|\${(?:[^{}]|{(?:[^{}]|{[^}]*})*})*}|(?!\${)[^\\`])*`/g -var singleQuoteReg = /'(?:\\[\s\w"'\\`]|[^\n\r'\\])*?'/g; +var singleQuoteReg = /'(?:\\[\s\w"'\\`]|[^\n\r'\\])*?'/g -var doubleQuoteReg = /"(?:\\[\s\w"'\\`]|[^\n\r"\\])*?"/g; +var doubleQuoteReg = /"(?:\\[\s\w"'\\`]|[^\n\r"\\])*?"/g /** Escape special regular expression characters inside a string */ function escapeRegExp(string: string) { // From MDN - return string.replace(/[.*+\-?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string + return string.replace(/[.*+\-?^${}()|[\]\\]/g, '\\$&') // $& means the whole matched string } -export default function parse( - str: string, - config: EtaConfig, -): Array { - var buffer: Array = []; - var trimLeftOfNextStr: string | false = false; - var lastIndex = 0; - var parseOptions = config.parse; +export default function parse(str: string, config: EtaConfig): Array { + var buffer: Array = [] + var trimLeftOfNextStr: string | false = false + var lastIndex = 0 + var parseOptions = config.parse if (config.plugins) { for (var i = 0; i < config.plugins.length; i++) { - var plugin = config.plugins[i]; + var plugin = config.plugins[i] if (plugin.processTemplate) { - str = plugin.processTemplate(str, config); + str = plugin.processTemplate(str, config) } } } @@ -55,13 +51,13 @@ export default function parse( // work well with `\r` and empty lines don't work well with the `m` flag. // Essentially, this replaces the whitespace at the beginning and end of // each line and removes multiple newlines. - str = str.replace(/[\r\n]+/g, "\n").replace(/^\s+|\s+$/gm, ""); + str = str.replace(/[\r\n]+/g, '\n').replace(/^\s+|\s+$/gm, '') } /* End rmWhitespace option */ - templateLitReg.lastIndex = 0; - singleQuoteReg.lastIndex = 0; - doubleQuoteReg.lastIndex = 0; + templateLitReg.lastIndex = 0 + singleQuoteReg.lastIndex = 0 + doubleQuoteReg.lastIndex = 0 function pushString(strng: string, shouldTrimRightOfString?: string | false) { if (strng) { @@ -71,137 +67,136 @@ export default function parse( strng, config, trimLeftOfNextStr, // this will only be false on the first str, the next ones will be null or undefined - shouldTrimRightOfString, - ); + shouldTrimRightOfString + ) if (strng) { // replace \ with \\, ' with \' // we're going to convert all CRLF to LF so it doesn't take more than one replace - strng = strng.replace(/\\|'/g, "\\$&").replace(/\r\n|\n|\r/g, "\\n"); + strng = strng.replace(/\\|'/g, '\\$&').replace(/\r\n|\n|\r/g, '\\n') - buffer.push(strng); + buffer.push(strng) } } } - var prefixes = [parseOptions.exec, parseOptions.interpolate, parseOptions.raw] - .reduce(function ( - accumulator, - prefix, - ) { - if (accumulator && prefix) { - return accumulator + "|" + escapeRegExp(prefix); - } else if (prefix) { - // accumulator is falsy - return escapeRegExp(prefix); - } else { - // prefix and accumulator are both falsy - return accumulator; - } - }, ""); + var prefixes = [parseOptions.exec, parseOptions.interpolate, parseOptions.raw].reduce(function ( + accumulator, + prefix + ) { + if (accumulator && prefix) { + return accumulator + '|' + escapeRegExp(prefix) + } else if (prefix) { + // accumulator is falsy + return escapeRegExp(prefix) + } else { + // prefix and accumulator are both falsy + return accumulator + } + }, + '') var parseOpenReg = new RegExp( - "([^]*?)" + escapeRegExp(config.tags[0]) + "(-|_)?\\s*(" + prefixes + - ")?\\s*", - "g", - ); + '([^]*?)' + escapeRegExp(config.tags[0]) + '(-|_)?\\s*(' + prefixes + ')?\\s*', + 'g' + ) var parseCloseReg = new RegExp( - "'|\"|`|\\/\\*|(\\s*(-|_)?" + escapeRegExp(config.tags[1]) + ")", - "g", - ); + '\'|"|`|\\/\\*|(\\s*(-|_)?' + escapeRegExp(config.tags[1]) + ')', + 'g' + ) // TODO: benchmark having the \s* on either side vs using str.trim() - var m; + var m while ((m = parseOpenReg.exec(str))) { - lastIndex = m[0].length + m.index; + lastIndex = m[0].length + m.index - var precedingString = m[1]; - var wsLeft = m[2]; - var prefix = m[3] || ""; // by default either ~, =, or empty + var precedingString = m[1] + var wsLeft = m[2] + var prefix = m[3] || '' // by default either ~, =, or empty - pushString(precedingString, wsLeft); + pushString(precedingString, wsLeft) - parseCloseReg.lastIndex = lastIndex; - var closeTag; - var currentObj: AstObject | false = false; + parseCloseReg.lastIndex = lastIndex + var closeTag + var currentObj: AstObject | false = false while ((closeTag = parseCloseReg.exec(str))) { if (closeTag[1]) { - var content = str.slice(lastIndex, closeTag.index); + var content = str.slice(lastIndex, closeTag.index) - parseOpenReg.lastIndex = lastIndex = parseCloseReg.lastIndex; + parseOpenReg.lastIndex = lastIndex = parseCloseReg.lastIndex - trimLeftOfNextStr = closeTag[2]; + trimLeftOfNextStr = closeTag[2] - var currentType: TagType = ""; + var currentType: TagType = '' if (prefix === parseOptions.exec) { - currentType = "e"; + currentType = 'e' } else if (prefix === parseOptions.raw) { - currentType = "r"; + currentType = 'r' } else if (prefix === parseOptions.interpolate) { - currentType = "i"; + currentType = 'i' } - currentObj = { t: currentType, val: content }; - break; + currentObj = { t: currentType, val: content } + break } else { - var char = closeTag[0]; - if (char === "/*") { - var commentCloseInd = str.indexOf("*/", parseCloseReg.lastIndex); + var char = closeTag[0] + if (char === '/*') { + var commentCloseInd = str.indexOf('*/', parseCloseReg.lastIndex) if (commentCloseInd === -1) { - ParseErr("unclosed comment", str, closeTag.index); + ParseErr('unclosed comment', str, closeTag.index) } - parseCloseReg.lastIndex = commentCloseInd; + parseCloseReg.lastIndex = commentCloseInd } else if (char === "'") { - singleQuoteReg.lastIndex = closeTag.index; + singleQuoteReg.lastIndex = closeTag.index - var singleQuoteMatch = singleQuoteReg.exec(str); + var singleQuoteMatch = singleQuoteReg.exec(str) if (singleQuoteMatch) { - parseCloseReg.lastIndex = singleQuoteReg.lastIndex; + parseCloseReg.lastIndex = singleQuoteReg.lastIndex } else { - ParseErr("unclosed string", str, closeTag.index); + ParseErr('unclosed string', str, closeTag.index) } } else if (char === '"') { - doubleQuoteReg.lastIndex = closeTag.index; - var doubleQuoteMatch = doubleQuoteReg.exec(str); + doubleQuoteReg.lastIndex = closeTag.index + var doubleQuoteMatch = doubleQuoteReg.exec(str) if (doubleQuoteMatch) { - parseCloseReg.lastIndex = doubleQuoteReg.lastIndex; + parseCloseReg.lastIndex = doubleQuoteReg.lastIndex } else { - ParseErr("unclosed string", str, closeTag.index); + ParseErr('unclosed string', str, closeTag.index) } - } else if (char === "`") { - templateLitReg.lastIndex = closeTag.index; - var templateLitMatch = templateLitReg.exec(str); + } else if (char === '`') { + templateLitReg.lastIndex = closeTag.index + var templateLitMatch = templateLitReg.exec(str) if (templateLitMatch) { - parseCloseReg.lastIndex = templateLitReg.lastIndex; + parseCloseReg.lastIndex = templateLitReg.lastIndex } else { - ParseErr("unclosed string", str, closeTag.index); + ParseErr('unclosed string', str, closeTag.index) } } } } if (currentObj) { - buffer.push(currentObj); + buffer.push(currentObj) } else { - ParseErr("unclosed tag", str, m.index + precedingString.length); + ParseErr('unclosed tag', str, m.index + precedingString.length) } } - pushString(str.slice(lastIndex, str.length), false); + pushString(str.slice(lastIndex, str.length), false) if (config.plugins) { for (var i = 0; i < config.plugins.length; i++) { - var plugin = config.plugins[i]; + var plugin = config.plugins[i] if (plugin.processAST) { - buffer = plugin.processAST(buffer, config); + buffer = plugin.processAST(buffer, config) } } } - return buffer; + return buffer } diff --git a/deno_dist/polyfills.ts b/deno_dist/polyfills.ts index b0b60a5..333fea8 100644 --- a/deno_dist/polyfills.ts +++ b/deno_dist/polyfills.ts @@ -1,13 +1,13 @@ -export var promiseImpl = Promise; +export var promiseImpl = Promise -export function getAsyncFunctionConstructor(): Function { - return async function () {}.constructor; +export function getAsyncFunctionConstructor (): Function { + return async function () {}.constructor } -export function trimLeft(str: string): string { - return str.trimLeft(); +export function trimLeft (str: string): string { + return str.trimLeft() } -export function trimRight(str: string): string { - return str.trimRight(); +export function trimRight (str: string): string { + return str.trimRight() } diff --git a/deno_dist/render.ts b/deno_dist/render.ts index 1f08c0f..8f5bf86 100644 --- a/deno_dist/render.ts +++ b/deno_dist/render.ts @@ -1,39 +1,36 @@ -import compile from "./compile.ts"; -import { getConfig } from "./config.ts"; -import { promiseImpl } from "./polyfills.ts"; -import EtaErr from "./err.ts"; +import compile from './compile.ts' +import { getConfig } from './config.ts' +import { promiseImpl } from './polyfills.ts' +import EtaErr from './err.ts' /* TYPES */ -import type { EtaConfig, PartialConfig } from "./config.ts"; -import type { TemplateFunction } from "./compile.ts"; -import type { CallbackFn } from "./file-handlers.ts"; +import type { EtaConfig, PartialConfig } from './config.ts' +import type { TemplateFunction } from './compile.ts' +import type { CallbackFn } from './file-handlers.ts' /* END TYPES */ -function handleCache( - template: string | TemplateFunction, - options: EtaConfig, -): TemplateFunction { - var templateFunc; +function handleCache(template: string | TemplateFunction, options: EtaConfig): TemplateFunction { + var templateFunc if (options.cache && options.name && options.templates.get(options.name)) { - return options.templates.get(options.name); + return options.templates.get(options.name) } - if (typeof template === "function") { - templateFunc = template; + if (typeof template === 'function') { + templateFunc = template } else { - templateFunc = compile(template, options); + templateFunc = compile(template, options) } // Note that we don't have to check if it already exists in the cache; // it would have returned earlier if it had if (options.cache && options.name) { - options.templates.define(options.name, templateFunc); + options.templates.define(options.name, templateFunc) } - return templateFunc; + return templateFunc } /** @@ -59,40 +56,43 @@ export default function render( template: string | TemplateFunction, data: object, config?: PartialConfig, - cb?: CallbackFn, + cb?: CallbackFn ): string | Promise | void { - var options = getConfig(config || {}); + var options = getConfig(config || {}) if (options.async) { - var result; + var result if (cb) { // If user passes callback try { // Note: if there is an error while rendering the template, // It will bubble up and be caught here - var templateFn = handleCache(template, options); - templateFn(data, options, cb); + var templateFn = handleCache(template, options) + templateFn(data, options, cb) } catch (err) { - return cb(err); + return cb(err) } } else { // No callback, try returning a promise - if (typeof promiseImpl === "function") { + if (typeof promiseImpl === 'function') { return new promiseImpl(function (resolve: Function, reject: Function) { try { - result = handleCache(template, options)(data, options); - resolve(result); + result = handleCache(template, options)(data, options) + resolve(result) } catch (err) { - reject(err); + reject(err) } - }); + }) } else { - throw EtaErr( - "Please provide a callback function, this env doesn't support Promises", - ); + throw EtaErr("Please provide a callback function, this env doesn't support Promises") } } } else { - return handleCache(template, options)(data, options); + return handleCache(template, options)(data, options) } } + +export function renderAsync(template: string | TemplateFunction, data: object, config?: PartialConfig, cb?: CallbackFn): string | Promise | void { + // Using Object.assign to lower bundle size, using spread operator makes it larger + return render(template, data, Object.assign({}, config, { async: true }), cb) +} diff --git a/deno_dist/storage.ts b/deno_dist/storage.ts index 118298a..6dc7e98 100644 --- a/deno_dist/storage.ts +++ b/deno_dist/storage.ts @@ -1,4 +1,4 @@ -import { copyProps } from "./utils.ts"; +import { copyProps } from './utils.ts' /** * Handles storage and accessing of values @@ -9,23 +9,23 @@ import { copyProps } from "./utils.ts"; class Cacher { constructor(private cache: Record) {} define(key: string, val: T): void { - this.cache[key] = val; + this.cache[key] = val } get(key: string): T { // string | array. // TODO: allow array of keys to look down // TODO: create plugin to allow referencing helpers, filters with dot notation - return this.cache[key]; + return this.cache[key] } remove(key: string): void { - delete this.cache[key]; + delete this.cache[key] } reset(): void { - this.cache = {}; + this.cache = {} } load(cacheObj: Record): void { - copyProps(this.cache, cacheObj); + copyProps(this.cache, cacheObj) } } -export { Cacher }; +export { Cacher } diff --git a/deno_dist/utils.ts b/deno_dist/utils.ts index a773363..e598bdc 100644 --- a/deno_dist/utils.ts +++ b/deno_dist/utils.ts @@ -1,34 +1,34 @@ // TODO: allow '-' to trim up until newline. Use [^\S\n\r] instead of \s // TODO: only include trimLeft polyfill if not in ES6 -import { trimLeft, trimRight } from "./polyfills.ts"; +import { trimLeft, trimRight } from './polyfills.ts' /* TYPES */ -import type { EtaConfig } from "./config.ts"; +import type { EtaConfig } from './config.ts' interface EscapeMap { - "&": "&"; - "<": "<"; - ">": ">"; - '"': """; - "'": "'"; - [index: string]: string; + '&': '&' + '<': '<' + '>': '>' + '"': '"' + "'": ''' + [index: string]: string } /* END TYPES */ export function hasOwnProp(obj: object, prop: string): boolean { - return Object.prototype.hasOwnProperty.call(obj, prop); + return Object.prototype.hasOwnProperty.call(obj, prop) } export function copyProps(toObj: T, fromObj: T): T { for (var key in fromObj) { if (hasOwnProp((fromObj as unknown) as object, key)) { - toObj[key] = fromObj[key]; + toObj[key] = fromObj[key] } } - return toObj; + return toObj } /** @@ -39,55 +39,55 @@ function trimWS( str: string, config: EtaConfig, wsLeft: string | false, - wsRight?: string | false, + wsRight?: string | false ): string { - var leftTrim; - var rightTrim; + var leftTrim + var rightTrim if (Array.isArray(config.autoTrim)) { // kinda confusing // but _}} will trim the left side of the following string - leftTrim = config.autoTrim[1]; - rightTrim = config.autoTrim[0]; + leftTrim = config.autoTrim[1] + rightTrim = config.autoTrim[0] } else { - leftTrim = rightTrim = config.autoTrim; + leftTrim = rightTrim = config.autoTrim } if (wsLeft || wsLeft === false) { - leftTrim = wsLeft; + leftTrim = wsLeft } if (wsRight || wsRight === false) { - rightTrim = wsRight; + rightTrim = wsRight } if (!rightTrim && !leftTrim) { - return str; + return str } - if (leftTrim === "slurp" && rightTrim === "slurp") { - return str.trim(); + if (leftTrim === 'slurp' && rightTrim === 'slurp') { + return str.trim() } - if (leftTrim === "_" || leftTrim === "slurp") { + if (leftTrim === '_' || leftTrim === 'slurp') { // console.log('trimming left' + leftTrim) // full slurp - str = trimLeft(str); - } else if (leftTrim === "-" || leftTrim === "nl") { + str = trimLeft(str) + } else if (leftTrim === '-' || leftTrim === 'nl') { // nl trim - str = str.replace(/^(?:\r\n|\n|\r)/, ""); + str = str.replace(/^(?:\r\n|\n|\r)/, '') } - if (rightTrim === "_" || rightTrim === "slurp") { + if (rightTrim === '_' || rightTrim === 'slurp') { // full slurp - str = trimRight(str); - } else if (rightTrim === "-" || rightTrim === "nl") { + str = trimRight(str) + } else if (rightTrim === '-' || rightTrim === 'nl') { // nl trim - str = str.replace(/(?:\r\n|\n|\r)$/, ""); // TODO: make sure this gets \r\n + str = str.replace(/(?:\r\n|\n|\r)$/, '') // TODO: make sure this gets \r\n } - return str; + return str } /** @@ -95,15 +95,15 @@ function trimWS( */ var escMap: EscapeMap = { - "&": "&", - "<": "<", - ">": ">", - '"': """, - "'": "'", -}; + '&': '&', + '<': '<', + '>': '>', + '"': '"', + "'": ''' +} function replaceChar(s: string): string { - return escMap[s]; + return escMap[s] } /** @@ -116,12 +116,12 @@ function replaceChar(s: string): string { function XMLEscape(str: any): string { // eslint-disable-line @typescript-eslint/no-explicit-any // To deal with XSS. Based on Escape implementations of Mustache.JS and Marko, then customized. - var newStr = String(str); + var newStr = String(str) if (/[&<>"']/.test(newStr)) { - return newStr.replace(/[&<>"']/g, replaceChar); + return newStr.replace(/[&<>"']/g, replaceChar) } else { - return newStr; + return newStr } } -export { trimWS, XMLEscape }; +export { trimWS, XMLEscape }