twing
Version:
First-class Twig engine for Node.js
311 lines (310 loc) • 14 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.createSynchronousEnvironment = exports.createEnvironment = void 0;
const extension_set_1 = require("./extension-set");
const parser_1 = require("./parser");
const html_1 = require("./escaping-stragegy/html");
const css_1 = require("./escaping-stragegy/css");
const js_1 = require("./escaping-stragegy/js");
const url_1 = require("./escaping-stragegy/url");
const html_attribute_1 = require("./escaping-stragegy/html-attribute");
const token_stream_1 = require("./token-stream");
const source_map_runtime_1 = require("./source-map-runtime");
const security_policy_1 = require("./sandbox/security-policy");
const luxon_1 = require("luxon");
const lexer_1 = require("./lexer");
const core_1 = require("./extension/core");
const lib_1 = require("../lib");
const template_loader_1 = require("./template-loader");
const context_1 = require("./context");
const iterator_to_map_1 = require("./helpers/iterator-to-map");
/**
* Creates an instance of {@link TwingEnvironment} backed by the passed loader.
*
* @param loader
* @param options
*/
const createEnvironment = (loader, options) => {
const cssEscapingStrategy = (0, css_1.createCssEscapingStrategyHandler)();
const htmlEscapingStrategy = (0, html_1.createHtmlEscapingStrategyHandler)();
const htmlAttributeEscapingStrategy = (0, html_attribute_1.createHtmlAttributeEscapingStrategyHandler)();
const jsEscapingStrategy = (0, js_1.createJsEscapingStrategyHandler)();
const urlEscapingStrategy = (0, url_1.createUrlEscapingStrategyHandler)();
const escapingStrategyHandlers = {
css: cssEscapingStrategy,
html: htmlEscapingStrategy,
html_attr: htmlAttributeEscapingStrategy,
js: jsEscapingStrategy,
url: urlEscapingStrategy
};
const extensionSet = (0, extension_set_1.createExtensionSet)();
extensionSet.addExtension((0, core_1.createCoreExtension)());
const cache = (options === null || options === void 0 ? void 0 : options.cache) || null;
const charset = (options === null || options === void 0 ? void 0 : options.charset) || 'UTF-8';
const dateFormat = (options === null || options === void 0 ? void 0 : options.dateFormat) || 'F j, Y H:i';
const dateIntervalFormat = (options === null || options === void 0 ? void 0 : options.dateIntervalFormat) || '%d days';
const numberFormat = (options === null || options === void 0 ? void 0 : options.numberFormat) || {
decimalPoint: '.',
numberOfDecimals: 0,
thousandSeparator: ','
};
const sandboxPolicy = (options === null || options === void 0 ? void 0 : options.sandboxPolicy) || (0, security_policy_1.createSandboxSecurityPolicy)();
const globals = (0, context_1.createContext)((0, iterator_to_map_1.iterableToMap)((options === null || options === void 0 ? void 0 : options.globals) || {}));
let lexer;
let parser;
const environment = {
get cache() {
return cache;
},
get charset() {
return charset;
},
get dateFormat() {
return dateFormat;
},
get dateIntervalFormat() {
return dateIntervalFormat;
},
get escapingStrategyHandlers() {
return escapingStrategyHandlers;
},
get filters() {
return extensionSet.filters;
},
get functions() {
return extensionSet.functions;
},
get globals() {
return globals;
},
get loader() {
return loader;
},
get numberFormat() {
return numberFormat;
},
get sandboxPolicy() {
return sandboxPolicy;
},
get tests() {
return extensionSet.tests;
},
get timezone() {
return (options === null || options === void 0 ? void 0 : options.timezone) || luxon_1.Settings.defaultZoneName;
},
addExtension: extensionSet.addExtension,
addFilter: extensionSet.addFilter,
addFunction: extensionSet.addFunction,
addNodeVisitor: extensionSet.addNodeVisitor,
addOperator: extensionSet.addOperator,
addTagHandler: extensionSet.addTagHandler,
addTest: extensionSet.addTest,
loadTemplate: async (name, from = null) => {
const templateLoader = (0, template_loader_1.createTemplateLoader)(environment);
return templateLoader(name, from)
.then((template) => {
if (template === null) {
throw (0, lib_1.createTemplateLoadingError)([name]);
}
return template;
});
},
registerEscapingStrategy: (handler, name) => {
escapingStrategyHandlers[name] = handler;
},
parse: (stream, parserOptions) => {
if (!parser) {
const visitors = extensionSet.nodeVisitors;
if (options === null || options === void 0 ? void 0 : options.autoEscapingStrategy) {
const strategy = options.autoEscapingStrategy;
visitors.unshift({
enterNode: (node) => {
return node;
},
leaveNode: (node) => {
if (node.type === "template") {
node.children.body = (0, lib_1.createAutoEscapeNode)(strategy, node.children.body, node.line, node.column);
}
return node;
}
});
}
parser = (0, parser_1.createParser)(extensionSet.unaryOperators, extensionSet.binaryOperators, extensionSet.tagHandlers, extensionSet.nodeVisitors, extensionSet.filters, extensionSet.functions, extensionSet.tests, parserOptions || (options === null || options === void 0 ? void 0 : options.parserOptions) || {
strict: true,
level: 3
});
}
return parser.parse(stream);
},
render: (name, context, options) => {
return environment.loadTemplate(name)
.then((template) => {
return template.render(environment, context, options);
});
},
renderWithSourceMap: (name, context, options) => {
const sourceMapRuntime = (0, source_map_runtime_1.createSourceMapRuntime)();
return environment.loadTemplate(name)
.then((template) => {
return template.render(environment, context, Object.assign(Object.assign({}, options), { sourceMapRuntime }));
})
.then((data) => {
const { sourceMap } = sourceMapRuntime;
return {
data,
sourceMap
};
});
},
tokenize: (source) => {
var _a;
const level = ((_a = options === null || options === void 0 ? void 0 : options.parserOptions) === null || _a === void 0 ? void 0 : _a.level) || 3;
if (!lexer) {
lexer = (0, lexer_1.createLexer)(level, extensionSet.binaryOperators, extensionSet.unaryOperators);
}
const stream = lexer.tokenizeSource(source);
return (0, token_stream_1.createTokenStream)(stream.toAst(), stream.source);
}
};
return environment;
};
exports.createEnvironment = createEnvironment;
const createSynchronousEnvironment = (loader, options) => {
const cssEscapingStrategy = (0, css_1.createCssEscapingStrategyHandler)();
const htmlEscapingStrategy = (0, html_1.createHtmlEscapingStrategyHandler)();
const htmlAttributeEscapingStrategy = (0, html_attribute_1.createHtmlAttributeEscapingStrategyHandler)();
const jsEscapingStrategy = (0, js_1.createJsEscapingStrategyHandler)();
const urlEscapingStrategy = (0, url_1.createUrlEscapingStrategyHandler)();
const escapingStrategyHandlers = {
css: cssEscapingStrategy,
html: htmlEscapingStrategy,
html_attr: htmlAttributeEscapingStrategy,
js: jsEscapingStrategy,
url: urlEscapingStrategy
};
const extensionSet = (0, extension_set_1.createExtensionSet)();
extensionSet.addExtension((0, core_1.createSynchronousCoreExtension)());
const cache = (options === null || options === void 0 ? void 0 : options.cache) || null;
const charset = (options === null || options === void 0 ? void 0 : options.charset) || 'UTF-8';
const dateFormat = (options === null || options === void 0 ? void 0 : options.dateFormat) || 'F j, Y H:i';
const dateIntervalFormat = (options === null || options === void 0 ? void 0 : options.dateIntervalFormat) || '%d days';
const numberFormat = (options === null || options === void 0 ? void 0 : options.numberFormat) || {
decimalPoint: '.',
numberOfDecimals: 0,
thousandSeparator: ','
};
const sandboxPolicy = (options === null || options === void 0 ? void 0 : options.sandboxPolicy) || (0, security_policy_1.createSandboxSecurityPolicy)();
const globals = new Map(Object.entries((options === null || options === void 0 ? void 0 : options.globals) || {}));
let lexer;
let parser;
const environment = {
get cache() {
return cache;
},
get charset() {
return charset;
},
get dateFormat() {
return dateFormat;
},
get dateIntervalFormat() {
return dateIntervalFormat;
},
get escapingStrategyHandlers() {
return escapingStrategyHandlers;
},
get filters() {
return extensionSet.filters;
},
get functions() {
return extensionSet.functions;
},
get globals() {
return globals;
},
get loader() {
return loader;
},
get numberFormat() {
return numberFormat;
},
get sandboxPolicy() {
return sandboxPolicy;
},
get tests() {
return extensionSet.tests;
},
get timezone() {
return (options === null || options === void 0 ? void 0 : options.timezone) || luxon_1.Settings.defaultZoneName;
},
addExtension: extensionSet.addExtension,
addFilter: extensionSet.addFilter,
addFunction: extensionSet.addFunction,
addNodeVisitor: extensionSet.addNodeVisitor,
addOperator: extensionSet.addOperator,
addTagHandler: extensionSet.addTagHandler,
addTest: extensionSet.addTest,
loadTemplate: (name, from = null) => {
const templateLoader = (0, template_loader_1.createSynchronousTemplateLoader)(environment);
const template = templateLoader(name, from);
if (template === null) {
throw (0, lib_1.createTemplateLoadingError)([name]);
}
return template;
},
registerEscapingStrategy: (handler, name) => {
escapingStrategyHandlers[name] = handler;
},
parse: (stream, parserOptions) => {
if (!parser) {
const visitors = extensionSet.nodeVisitors;
if (options === null || options === void 0 ? void 0 : options.autoEscapingStrategy) {
const strategy = options.autoEscapingStrategy;
visitors.unshift({
enterNode: (node) => {
return node;
},
leaveNode: (node) => {
if (node.type === "template") {
node.children.body = (0, lib_1.createAutoEscapeNode)(strategy, node.children.body, node.line, node.column);
}
return node;
}
});
}
parser = (0, parser_1.createParser)(extensionSet.unaryOperators, extensionSet.binaryOperators, extensionSet.tagHandlers, extensionSet.nodeVisitors, extensionSet.filters, extensionSet.functions, extensionSet.tests, parserOptions || (options === null || options === void 0 ? void 0 : options.parserOptions) || {
strict: true,
level: 3
});
}
return parser.parse(stream);
},
render: (name, data, options) => {
const template = environment.loadTemplate(name);
const context = new Map(Object.entries(data));
return template.render(environment, context, options);
},
renderWithSourceMap: (name, data, options) => {
const sourceMapRuntime = (0, source_map_runtime_1.createSourceMapRuntime)();
const context = new Map(Object.entries(data));
const template = environment.loadTemplate(name);
const output = template.render(environment, context, Object.assign(Object.assign({}, options), { sourceMapRuntime }));
const { sourceMap } = sourceMapRuntime;
return {
data: output,
sourceMap
};
},
tokenize: (source) => {
var _a;
const level = ((_a = options === null || options === void 0 ? void 0 : options.parserOptions) === null || _a === void 0 ? void 0 : _a.level) || 3;
if (!lexer) {
lexer = (0, lexer_1.createLexer)(level, extensionSet.binaryOperators, extensionSet.unaryOperators);
}
const stream = lexer.tokenizeSource(source);
return (0, token_stream_1.createTokenStream)(stream.toAst(), stream.source);
}
};
return environment;
};
exports.createSynchronousEnvironment = createSynchronousEnvironment;