forked from github-mirror/twing
Remove parts of the asynchronous logic
This commit is contained in:
parent
f0b9c5396a
commit
94b2347867
src/main
@ -22,9 +22,9 @@ export type {TwingArrayLoader, TwingSynchronousArrayLoader} from "./lib/loader/a
|
||||
export type {TwingChainLoader, TwingSynchronousChainLoader} from "./lib/loader/chain";
|
||||
export type {TwingLoader, TwingSynchronousLoader} from "./lib/loader";
|
||||
|
||||
export {createFilesystemLoader, createSynchronousFilesystemLoader} from "./lib/loader/filesystem";
|
||||
export {createArrayLoader, createSynchronousArrayLoader} from "./lib/loader/array";
|
||||
export {createChainLoader, createSynchronousChainLoader} from "./lib/loader/chain";
|
||||
export {createSynchronousFilesystemLoader} from "./lib/loader/filesystem";
|
||||
export {createSynchronousArrayLoader} from "./lib/loader/array";
|
||||
export {createSynchronousChainLoader} from "./lib/loader/chain";
|
||||
|
||||
// markup
|
||||
export type {TwingMarkup} from "./lib/markup";
|
||||
@ -233,7 +233,7 @@ export {createEmbedNode} from "./lib/node/include/embed";
|
||||
export {createIncludeNode} from "./lib/node/include/include";
|
||||
|
||||
// node executors
|
||||
export {executeNode, executeNodeSynchronously, type TwingNodeExecutor, type TwingSynchronousNodeExecutor} from "./lib/node-executor";
|
||||
export {executeNodeSynchronously, type TwingNodeExecutor, type TwingSynchronousNodeExecutor} from "./lib/node-executor";
|
||||
|
||||
// tag handlers
|
||||
export type {TwingTagHandler, TwingTokenParser} from "./lib/tag-handler";
|
||||
@ -298,16 +298,16 @@ export type {
|
||||
export type {TwingTest, TwingSynchronousTest} from "./lib/test";
|
||||
export type {TwingTokenStream} from "./lib/token-stream";
|
||||
|
||||
export {createEnvironment, createSynchronousEnvironment} from "./lib/environment";
|
||||
export {createSynchronousEnvironment} from "./lib/environment";
|
||||
export {createExtensionSet} from "./lib/extension-set";
|
||||
export {createFilter, createSynchronousFilter} from "./lib/filter";
|
||||
export {createFunction, createSynchronousFunction} from "./lib/function";
|
||||
export {createSynchronousFilter} from "./lib/filter";
|
||||
export {createSynchronousFunction} from "./lib/function";
|
||||
export {createLexer} from "./lib/lexer";
|
||||
export {createBaseNode, createNode, getChildren, getChildrenCount} from "./lib/node";
|
||||
export {createOperator} from "./lib/operator";
|
||||
export {createSandboxSecurityPolicy} from "./lib/sandbox/security-policy";
|
||||
export {createSource} from "./lib/source";
|
||||
export {createSourceMapRuntime} from "./lib/source-map-runtime";
|
||||
export {type TwingTemplate, createTemplate, type TwingSynchronousTemplate, createSynchronousTemplate} from "./lib/template";
|
||||
export {type TwingTemplateLoader, type TwingSynchronousTemplateLoader, createTemplateLoader, createSynchronousTemplateLoader} from "./lib/template-loader";
|
||||
export {createTest, createSynchronousTest} from "./lib/test";
|
||||
export {type TwingSynchronousTemplate, createSynchronousTemplate} from "./lib/template";
|
||||
export {type TwingSynchronousTemplateLoader, createSynchronousTemplateLoader} from "./lib/template-loader";
|
||||
export {createSynchronousTest} from "./lib/test";
|
||||
|
@ -24,11 +24,9 @@ import {TwingSynchronousTemplate, TwingTemplate} from "./template";
|
||||
import {Settings as DateTimeSettings} from "luxon";
|
||||
import {createLexer, type TwingLexer} from "./lexer";
|
||||
import {TwingCache, TwingSynchronousCache} from "./cache";
|
||||
import {createCoreExtension, createSynchronousCoreExtension} from "./extension/core";
|
||||
import {createSynchronousCoreExtension} from "./extension/core";
|
||||
import {createAutoEscapeNode, createTemplateLoadingError, type TwingContext} from "../lib";
|
||||
import {createSynchronousTemplateLoader, createTemplateLoader} from "./template-loader";
|
||||
import {createContext} from "./context";
|
||||
import {iterableToMap} from "./helpers/iterator-to-map";
|
||||
import {createSynchronousTemplateLoader} from "./template-loader";
|
||||
|
||||
export type TwingNumberFormat = {
|
||||
numberOfDecimals: number;
|
||||
@ -243,193 +241,6 @@ export interface TwingSynchronousEnvironment {
|
||||
tokenize(source: TwingSource): TwingTokenStream;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance of {@link TwingEnvironment} backed by the passed loader.
|
||||
*
|
||||
* @param loader
|
||||
* @param options
|
||||
*/
|
||||
export const createEnvironment = (
|
||||
loader: TwingLoader | TwingSynchronousLoader,
|
||||
options?: TwingEnvironmentOptions
|
||||
): TwingEnvironment => {
|
||||
const cssEscapingStrategy = createCssEscapingStrategyHandler();
|
||||
const htmlEscapingStrategy = createHtmlEscapingStrategyHandler();
|
||||
const htmlAttributeEscapingStrategy = createHtmlAttributeEscapingStrategyHandler();
|
||||
const jsEscapingStrategy = createJsEscapingStrategyHandler();
|
||||
const urlEscapingStrategy = createUrlEscapingStrategyHandler();
|
||||
|
||||
const escapingStrategyHandlers: Record<TwingEscapingStrategy, TwingEscapingStrategyHandler> = {
|
||||
css: cssEscapingStrategy,
|
||||
html: htmlEscapingStrategy,
|
||||
html_attr: htmlAttributeEscapingStrategy,
|
||||
js: jsEscapingStrategy,
|
||||
url: urlEscapingStrategy
|
||||
};
|
||||
const extensionSet = createExtensionSet<TwingExtension>();
|
||||
|
||||
extensionSet.addExtension(createCoreExtension());
|
||||
|
||||
const cache: TwingCache | null = options?.cache || null;
|
||||
const charset = options?.charset || 'UTF-8';
|
||||
const dateFormat = options?.dateFormat || 'F j, Y H:i';
|
||||
const dateIntervalFormat = options?.dateIntervalFormat || '%d days';
|
||||
const numberFormat: TwingNumberFormat = options?.numberFormat || {
|
||||
decimalPoint: '.',
|
||||
numberOfDecimals: 0,
|
||||
thousandSeparator: ','
|
||||
};
|
||||
const sandboxPolicy = options?.sandboxPolicy || createSandboxSecurityPolicy();
|
||||
const globals = createContext(iterableToMap(options?.globals || {}));
|
||||
|
||||
let lexer: TwingLexer;
|
||||
let parser: TwingParser;
|
||||
|
||||
const environment: TwingEnvironment = {
|
||||
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?.timezone || DateTimeSettings.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 = createTemplateLoader(environment);
|
||||
|
||||
return templateLoader(name, from)
|
||||
.then((template) => {
|
||||
if (template === null) {
|
||||
throw createTemplateLoadingError([name]);
|
||||
}
|
||||
|
||||
return template;
|
||||
});
|
||||
},
|
||||
registerEscapingStrategy: (handler, name) => {
|
||||
escapingStrategyHandlers[name] = handler;
|
||||
},
|
||||
parse: (stream, parserOptions) => {
|
||||
if (!parser) {
|
||||
const visitors = extensionSet.nodeVisitors;
|
||||
|
||||
if (options?.autoEscapingStrategy) {
|
||||
const strategy = options.autoEscapingStrategy;
|
||||
|
||||
visitors.unshift({
|
||||
enterNode: (node) => {
|
||||
return node;
|
||||
},
|
||||
leaveNode: (node) => {
|
||||
if (node.type === "template") {
|
||||
node.children.body = createAutoEscapeNode(strategy, node.children.body, node.line, node.column);
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
parser = createParser(
|
||||
extensionSet.unaryOperators,
|
||||
extensionSet.binaryOperators,
|
||||
extensionSet.tagHandlers,
|
||||
extensionSet.nodeVisitors,
|
||||
extensionSet.filters,
|
||||
extensionSet.functions,
|
||||
extensionSet.tests,
|
||||
parserOptions || 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 = createSourceMapRuntime();
|
||||
|
||||
return environment.loadTemplate(name)
|
||||
.then((template) => {
|
||||
return template.render(environment, context, {
|
||||
...options,
|
||||
sourceMapRuntime
|
||||
});
|
||||
})
|
||||
.then((data) => {
|
||||
const {sourceMap} = sourceMapRuntime;
|
||||
|
||||
return {
|
||||
data,
|
||||
sourceMap
|
||||
};
|
||||
});
|
||||
},
|
||||
tokenize: (source: TwingSource): TwingTokenStream => {
|
||||
const level = options?.parserOptions?.level || 3;
|
||||
|
||||
if (!lexer) {
|
||||
lexer = createLexer(
|
||||
level,
|
||||
extensionSet.binaryOperators,
|
||||
extensionSet.unaryOperators
|
||||
);
|
||||
}
|
||||
|
||||
const stream = lexer.tokenizeSource(source);
|
||||
|
||||
return createTokenStream(stream.toAst(), stream.source);
|
||||
}
|
||||
};
|
||||
|
||||
return environment;
|
||||
};
|
||||
|
||||
export const createSynchronousEnvironment = (
|
||||
loader: TwingSynchronousLoader,
|
||||
options?: TwingSynchronousEnvironmentOptions
|
||||
|
@ -1,4 +1,4 @@
|
||||
import type {TwingExtension, TwingSynchronousExtension} from "../extension";
|
||||
import type {TwingSynchronousExtension} from "../extension";
|
||||
import {createAndNode} from "../node/expression/binary/and";
|
||||
import {createIsInNode} from "../node/expression/binary/is-in";
|
||||
import {createIsGreaterThanNode} from "../node/expression/binary/is-greater-than";
|
||||
@ -6,7 +6,7 @@ import {createIsLessThanNode} from "../node/expression/binary/is-less-than";
|
||||
import {createNotNode} from "../node/expression/unary/not";
|
||||
import {createNegativeNode} from "../node/expression/unary/negative";
|
||||
import {createPositiveNode} from "../node/expression/unary/positive";
|
||||
import {createFunction, createSynchronousFunction} from "../function";
|
||||
import {createSynchronousFunction} from "../function";
|
||||
import {createConcatenateNode} from "../node/expression/binary/concatenate";
|
||||
import {createMultiplyNode} from "../node/expression/binary/multiply";
|
||||
import {createDivideNode} from "../node/expression/binary/divide";
|
||||
@ -27,68 +27,68 @@ import {createIsNotInNode} from "../node/expression/binary/is-not-in";
|
||||
import {createNullishCoalescingNode} from "../node/expression/nullish-coalescing";
|
||||
import {TwingBaseExpressionNode} from "../node/expression";
|
||||
import {createPowerNode} from "../node/expression/binary/power";
|
||||
import {createSynchronousTest, createTest} from "../test";
|
||||
import {createSynchronousTest} from "../test";
|
||||
import {createMatchesNode} from "../node/expression/binary/matches";
|
||||
import {createStartsWithNode} from "../node/expression/binary/starts-with";
|
||||
import {createEndsWithNode} from "../node/expression/binary/ends-with";
|
||||
import {createFilter, createSynchronousFilter} from "../filter";
|
||||
import {createSynchronousFilter} from "../filter";
|
||||
import {createOperator, TwingOperator} from "../operator";
|
||||
import {isEven, isEvenSynchronously} from "./core/tests/is-even";
|
||||
import {isOdd, isOddSynchronously} from "./core/tests/is-odd";
|
||||
import {isSameAs, isSameAsSynchronously} from "./core/tests/is-same-as";
|
||||
import {isNull, isNullSynchronously} from "./core/tests/is-null";
|
||||
import {isDivisibleBy, isDivisibleBySynchronously} from "./core/tests/is-divisible-by";
|
||||
import {min, minSynchronously} from "./core/functions/min";
|
||||
import {max, maxSynchronously} from "./core/functions/max";
|
||||
import {date, dateFilterSynchronously} from "./core/filters/date";
|
||||
import {dateModify, dateModifySynchronously} from "./core/filters/date-modify";
|
||||
import {format, formatSynchronously} from "./core/filters/format";
|
||||
import {replace, replaceSynchronously} from "./core/filters/replace";
|
||||
import {numberFormat, numberFormatSynchronously} from "./core/filters/number_format";
|
||||
import {abs, absSynchronously} from "./core/filters/abs";
|
||||
import {url_encode, urlEncodeSynchronously} from "./core/filters/url_encode";
|
||||
import {jsonEncode, jsonEncodeSynchronously} from "./core/filters/json-encode";
|
||||
import {convertEncoding, convertEncodingSynchronously} from "./core/filters/convert-encoding";
|
||||
import {title, titleSynchronously} from "./core/filters/title";
|
||||
import {capitalize, capitalizeSynchronously} from "./core/filters/capitalize";
|
||||
import {upper, upperSynchronously} from "./core/filters/upper";
|
||||
import {lower, lowerSynchronously} from "./core/filters/lower";
|
||||
import {striptags, striptagsSynchronously} from "./core/filters/striptags";
|
||||
import {trim, trimSynchronously} from "./core/filters/trim";
|
||||
import {nl2br, nl2brSynchronously} from "./core/filters/nl2br";
|
||||
import {raw, rawSynchronously} from "./core/filters/raw";
|
||||
import {join, joinSynchronously} from "./core/filters/join";
|
||||
import {split, splitSynchronously} from "./core/filters/split";
|
||||
import {sort, sortSynchronously} from "./core/filters/sort";
|
||||
import {merge as mergeFilter, mergeSynchronously} from "./core/filters/merge";
|
||||
import {batch, batchSynchronously} from "./core/filters/batch";
|
||||
import {reverse as reverseFilter, reverseSynchronously} from "./core/filters/reverse";
|
||||
import {length, lengthSynchronously} from "./core/filters/length";
|
||||
import {slice as sliceFilter, sliceSynchronously} from "./core/filters/slice";
|
||||
import {first as firstFilter, firstSynchronously} from "./core/filters/first";
|
||||
import {last, lastSynchronously} from "./core/filters/last";
|
||||
import {defaultFilter, defaultFilterSynchronously} from "./core/filters/default";
|
||||
import {escape, escapeSynchronously} from "./core/filters/escape";
|
||||
import {round, roundSynchronously} from "./core/filters/round";
|
||||
import {include, includeSynchronously} from "./core/functions/include";
|
||||
import {keys, keysSynchronously} from "./core/filters/keys";
|
||||
import {spaceless, spacelessSynchronously} from "./core/filters/spaceless";
|
||||
import {column, columnSynchronously} from "./core/filters/column";
|
||||
import {filter, filterSynchronously} from "./core/filters/filter";
|
||||
import {map, mapSynchronously} from "./core/filters/map";
|
||||
import {reduce, reduceSynchronously} from "./core/filters/reduce";
|
||||
import {range, rangeSynchronously} from "./core/functions/range";
|
||||
import {constant, constantSynchronously} from "./core/functions/constant";
|
||||
import {cycle, cycleSynchronously} from "./core/functions/cycle";
|
||||
import {random, randomSynchronously} from "./core/functions/random";
|
||||
import {source, sourceSynchronously} from "./core/functions/source";
|
||||
import {templateFromString, templateFromStringSynchronously} from "./core/functions/template-from-string";
|
||||
import {dump, dumpSynchronously} from "./core/functions/dump";
|
||||
import {isEmpty, isEmptySynchronously} from "./core/tests/is-empty";
|
||||
import {isIterable, isIterableSynchronously} from "./core/tests/is-iterable";
|
||||
import {date as dateFunction, dateSynchronously} from "./core/functions/date";
|
||||
import {isDefined, isDefinedSynchronously} from "./core/tests/is-defined";
|
||||
import {isConstant, isConstantSynchronously} from "./core/tests/is-constant";
|
||||
import {isEvenSynchronously} from "./core/tests/is-even";
|
||||
import {isOddSynchronously} from "./core/tests/is-odd";
|
||||
import {isSameAsSynchronously} from "./core/tests/is-same-as";
|
||||
import {isNullSynchronously} from "./core/tests/is-null";
|
||||
import {isDivisibleBySynchronously} from "./core/tests/is-divisible-by";
|
||||
import {minSynchronously} from "./core/functions/min";
|
||||
import {maxSynchronously} from "./core/functions/max";
|
||||
import {dateFilterSynchronously} from "./core/filters/date";
|
||||
import {dateModifySynchronously} from "./core/filters/date-modify";
|
||||
import {formatSynchronously} from "./core/filters/format";
|
||||
import {replaceSynchronously} from "./core/filters/replace";
|
||||
import {numberFormatSynchronously} from "./core/filters/number_format";
|
||||
import {absSynchronously} from "./core/filters/abs";
|
||||
import {urlEncodeSynchronously} from "./core/filters/url_encode";
|
||||
import {jsonEncodeSynchronously} from "./core/filters/json-encode";
|
||||
import {convertEncodingSynchronously} from "./core/filters/convert-encoding";
|
||||
import {titleSynchronously} from "./core/filters/title";
|
||||
import {capitalizeSynchronously} from "./core/filters/capitalize";
|
||||
import {upperSynchronously} from "./core/filters/upper";
|
||||
import {lowerSynchronously} from "./core/filters/lower";
|
||||
import {striptagsSynchronously} from "./core/filters/striptags";
|
||||
import {trimSynchronously} from "./core/filters/trim";
|
||||
import {nl2brSynchronously} from "./core/filters/nl2br";
|
||||
import {rawSynchronously} from "./core/filters/raw";
|
||||
import {joinSynchronously} from "./core/filters/join";
|
||||
import {splitSynchronously} from "./core/filters/split";
|
||||
import {sortSynchronously} from "./core/filters/sort";
|
||||
import {mergeSynchronously} from "./core/filters/merge";
|
||||
import {batchSynchronously} from "./core/filters/batch";
|
||||
import {reverseSynchronously} from "./core/filters/reverse";
|
||||
import {lengthSynchronously} from "./core/filters/length";
|
||||
import {sliceSynchronously} from "./core/filters/slice";
|
||||
import {firstSynchronously} from "./core/filters/first";
|
||||
import {lastSynchronously} from "./core/filters/last";
|
||||
import {defaultFilterSynchronously} from "./core/filters/default";
|
||||
import {escapeSynchronously} from "./core/filters/escape";
|
||||
import {roundSynchronously} from "./core/filters/round";
|
||||
import {includeSynchronously} from "./core/functions/include";
|
||||
import {keysSynchronously} from "./core/filters/keys";
|
||||
import {spacelessSynchronously} from "./core/filters/spaceless";
|
||||
import {columnSynchronously} from "./core/filters/column";
|
||||
import {filterSynchronously} from "./core/filters/filter";
|
||||
import {mapSynchronously} from "./core/filters/map";
|
||||
import {reduceSynchronously} from "./core/filters/reduce";
|
||||
import {rangeSynchronously} from "./core/functions/range";
|
||||
import {constantSynchronously} from "./core/functions/constant";
|
||||
import {cycleSynchronously} from "./core/functions/cycle";
|
||||
import {randomSynchronously} from "./core/functions/random";
|
||||
import {sourceSynchronously} from "./core/functions/source";
|
||||
import {templateFromStringSynchronously} from "./core/functions/template-from-string";
|
||||
import {dumpSynchronously} from "./core/functions/dump";
|
||||
import {isEmptySynchronously} from "./core/tests/is-empty";
|
||||
import {isIterableSynchronously} from "./core/tests/is-iterable";
|
||||
import {dateSynchronously} from "./core/functions/date";
|
||||
import {isDefinedSynchronously} from "./core/tests/is-defined";
|
||||
import {isConstantSynchronously} from "./core/tests/is-constant";
|
||||
import {createSpaceshipNode} from "../node/expression/binary/spaceship";
|
||||
import {createHasEveryNode} from "../node/expression/binary/has-every";
|
||||
import {createHasSomeNode} from "../node/expression/binary/has-some";
|
||||
@ -194,445 +194,6 @@ const getOperators = (): Array<TwingOperator> => {
|
||||
];
|
||||
};
|
||||
|
||||
export const createCoreExtension = (): TwingExtension => {
|
||||
return {
|
||||
get filters() {
|
||||
const escapeFilters = ['escape', 'e'].map((name) => {
|
||||
return createFilter(name, (escape), [
|
||||
{
|
||||
name: 'strategy',
|
||||
defaultValue: null
|
||||
},
|
||||
{
|
||||
name: 'charset',
|
||||
defaultValue: null
|
||||
}
|
||||
]);
|
||||
});
|
||||
|
||||
return [
|
||||
...escapeFilters,
|
||||
createFilter('abs', abs, []),
|
||||
createFilter('batch', batch, [
|
||||
{
|
||||
name: 'size'
|
||||
},
|
||||
{
|
||||
name: 'fill',
|
||||
defaultValue: null
|
||||
},
|
||||
{
|
||||
name: 'preserve_keys',
|
||||
defaultValue: true
|
||||
}
|
||||
]),
|
||||
createFilter('capitalize', capitalize, []),
|
||||
createFilter('column', column, [
|
||||
{
|
||||
name: 'name'
|
||||
}
|
||||
]),
|
||||
createFilter('convert_encoding', (convertEncoding), [
|
||||
{
|
||||
name: 'to'
|
||||
},
|
||||
{
|
||||
name: 'from'
|
||||
}
|
||||
]),
|
||||
createFilter('date', date, [
|
||||
{
|
||||
name: 'format',
|
||||
defaultValue: null
|
||||
},
|
||||
{
|
||||
name: 'timezone',
|
||||
defaultValue: null
|
||||
}
|
||||
]),
|
||||
createFilter('date_modify', dateModify, [
|
||||
{
|
||||
name: 'modifier'
|
||||
}
|
||||
]),
|
||||
createFilter('default', defaultFilter, [
|
||||
{
|
||||
name: 'default',
|
||||
defaultValue: null
|
||||
}
|
||||
]),
|
||||
createFilter('filter', filter, [
|
||||
{
|
||||
name: 'array'
|
||||
},
|
||||
{
|
||||
name: 'arrow',
|
||||
defaultValue: null
|
||||
}
|
||||
]),
|
||||
createFilter('first', firstFilter, []),
|
||||
createFilter('format', format, [], {
|
||||
is_variadic: true
|
||||
}),
|
||||
createFilter('join', join, [
|
||||
{
|
||||
name: 'glue',
|
||||
defaultValue: ''
|
||||
},
|
||||
{
|
||||
name: 'and',
|
||||
defaultValue: null
|
||||
}
|
||||
]),
|
||||
createFilter('json_encode', jsonEncode, [
|
||||
{
|
||||
name: 'options',
|
||||
defaultValue: null
|
||||
}
|
||||
]),
|
||||
createFilter('keys', keys, []),
|
||||
createFilter('last', last, []),
|
||||
createFilter('length', length, []),
|
||||
createFilter('lower', lower, []),
|
||||
createFilter('map', map, [
|
||||
{
|
||||
name: 'arrow'
|
||||
}
|
||||
]),
|
||||
createFilter('merge', mergeFilter, [
|
||||
{
|
||||
name: 'source'
|
||||
}
|
||||
]),
|
||||
createFilter('nl2br', nl2br, []),
|
||||
createFilter('number_format', numberFormat, [
|
||||
{
|
||||
name: 'decimal',
|
||||
defaultValue: null
|
||||
},
|
||||
{
|
||||
name: 'decimal_point',
|
||||
defaultValue: null
|
||||
},
|
||||
{
|
||||
name: 'thousand_sep',
|
||||
defaultValue: null
|
||||
}
|
||||
]),
|
||||
createFilter('raw', raw, []),
|
||||
createFilter('reduce', reduce, [
|
||||
{
|
||||
name: 'arrow'
|
||||
},
|
||||
{
|
||||
name: 'initial',
|
||||
defaultValue: null
|
||||
}
|
||||
]),
|
||||
createFilter('replace', replace, [
|
||||
{
|
||||
name: 'from'
|
||||
}
|
||||
]),
|
||||
createFilter('reverse', reverseFilter, [
|
||||
{
|
||||
name: 'preserve_keys',
|
||||
defaultValue: false
|
||||
}
|
||||
]),
|
||||
createFilter('round', round, [
|
||||
{
|
||||
name: 'precision',
|
||||
defaultValue: 0
|
||||
},
|
||||
{
|
||||
name: 'method',
|
||||
defaultValue: 'common'
|
||||
}
|
||||
]),
|
||||
createFilter('slice', sliceFilter, [
|
||||
{
|
||||
name: 'start'
|
||||
},
|
||||
{
|
||||
name: 'length',
|
||||
defaultValue: null
|
||||
},
|
||||
{
|
||||
name: 'preserve_keys',
|
||||
defaultValue: false
|
||||
}
|
||||
]),
|
||||
createFilter('sort', sort, [{
|
||||
name: 'arrow',
|
||||
defaultValue: null
|
||||
}]),
|
||||
createFilter('spaceless', spaceless, []),
|
||||
createFilter('split', split, [
|
||||
{
|
||||
name: 'delimiter'
|
||||
},
|
||||
{
|
||||
name: 'limit',
|
||||
defaultValue: null
|
||||
}
|
||||
]),
|
||||
createFilter('striptags', striptags, [
|
||||
{
|
||||
name: 'allowable_tags',
|
||||
defaultValue: ''
|
||||
}
|
||||
]),
|
||||
createFilter('title', title, []),
|
||||
createFilter('trim', trim, [
|
||||
{
|
||||
name: 'character_mask',
|
||||
defaultValue: null
|
||||
},
|
||||
{
|
||||
name: 'side',
|
||||
defaultValue: 'both'
|
||||
}
|
||||
]),
|
||||
createFilter('upper', upper, []),
|
||||
createFilter('url_encode', url_encode, []),
|
||||
];
|
||||
},
|
||||
get functions() {
|
||||
return [
|
||||
createFunction('constant', constant, [
|
||||
{name: 'name'},
|
||||
{name: 'object', defaultValue: null}
|
||||
]),
|
||||
createFunction('cycle', cycle, [
|
||||
{
|
||||
name: 'values'
|
||||
},
|
||||
{
|
||||
name: 'position'
|
||||
}
|
||||
]),
|
||||
createFunction('date', dateFunction, [
|
||||
{
|
||||
name: 'date',
|
||||
defaultValue: null
|
||||
},
|
||||
{
|
||||
name: 'timezone',
|
||||
defaultValue: null
|
||||
}
|
||||
]),
|
||||
createFunction('dump', dump, [], {
|
||||
is_variadic: true
|
||||
}),
|
||||
createFunction('include', include, [
|
||||
{
|
||||
name: 'template'
|
||||
},
|
||||
{
|
||||
name: 'variables',
|
||||
defaultValue: {}
|
||||
},
|
||||
{
|
||||
name: 'with_context',
|
||||
defaultValue: true
|
||||
},
|
||||
{
|
||||
name: 'ignore_missing',
|
||||
defaultValue: false
|
||||
},
|
||||
{
|
||||
name: 'sandboxed',
|
||||
defaultValue: false
|
||||
}
|
||||
]),
|
||||
createFunction('max', max, [], {
|
||||
is_variadic: true
|
||||
}),
|
||||
createFunction('min', min, [], {
|
||||
is_variadic: true
|
||||
}),
|
||||
createFunction('random', random, [
|
||||
{
|
||||
name: 'values',
|
||||
defaultValue: null
|
||||
},
|
||||
{
|
||||
name: 'max',
|
||||
defaultValue: null
|
||||
}
|
||||
]),
|
||||
createFunction('range', range, [
|
||||
{
|
||||
name: 'low'
|
||||
},
|
||||
{
|
||||
name: 'high'
|
||||
},
|
||||
{
|
||||
name: 'step',
|
||||
defaultValue: 1
|
||||
}
|
||||
]),
|
||||
createFunction('source', source, [
|
||||
{
|
||||
name: 'name'
|
||||
},
|
||||
{
|
||||
name: 'ignore_missing',
|
||||
defaultValue: false
|
||||
}
|
||||
]),
|
||||
createFunction('template_from_string', templateFromString, [
|
||||
{
|
||||
name: 'template'
|
||||
},
|
||||
{
|
||||
name: 'name',
|
||||
defaultValue: null
|
||||
}
|
||||
])
|
||||
];
|
||||
},
|
||||
get nodeVisitors() {
|
||||
return [];
|
||||
},
|
||||
get operators() {
|
||||
return [
|
||||
createOperator('not', "UNARY", 50, (operands: [TwingBaseExpressionNode, TwingBaseExpressionNode], line: number, column: number) => {
|
||||
return createNotNode(operands[0], line, column);
|
||||
}),
|
||||
createOperator('-', "UNARY", 500, (operands: [TwingBaseExpressionNode, TwingBaseExpressionNode], line: number, column: number) => {
|
||||
return createNegativeNode(operands[0], line, column);
|
||||
}),
|
||||
createOperator('+', "UNARY", 500, (operands: [TwingBaseExpressionNode, TwingBaseExpressionNode], line: number, column: number) => {
|
||||
return createPositiveNode(operands[0], line, column);
|
||||
}),
|
||||
createOperator('or', "BINARY", 10, (operands: [TwingBaseExpressionNode, TwingBaseExpressionNode], line: number, column: number) => {
|
||||
return createOrNode(operands, line, column);
|
||||
}),
|
||||
createOperator('and', "BINARY", 15, (operands: [TwingBaseExpressionNode, TwingBaseExpressionNode], line: number, column: number) => {
|
||||
return createAndNode(operands, line, column);
|
||||
}),
|
||||
createOperator('b-or', "BINARY", 16, (operands: [TwingBaseExpressionNode, TwingBaseExpressionNode], line: number, column: number) => {
|
||||
return createBitwiseOrNode(operands, line, column);
|
||||
}),
|
||||
createOperator('b-xor', "BINARY", 17, (operands: [TwingBaseExpressionNode, TwingBaseExpressionNode], line: number, column: number) => {
|
||||
return createBitwiseXorNode(operands, line, column);
|
||||
}),
|
||||
createOperator('b-and', "BINARY", 18, (operands: [TwingBaseExpressionNode, TwingBaseExpressionNode], line: number, column: number) => {
|
||||
return createBitwiseAndNode(operands, line, column);
|
||||
}),
|
||||
createOperator('==', "BINARY", 20, (operands: [TwingBaseExpressionNode, TwingBaseExpressionNode], line: number, column: number) => {
|
||||
return createIsEqualNode(operands, line, column);
|
||||
}),
|
||||
createOperator('!=', "BINARY", 20, (operands: [TwingBaseExpressionNode, TwingBaseExpressionNode], line: number, column: number) => {
|
||||
return createIsNotEqualToNode(operands, line, column);
|
||||
}),
|
||||
createOperator('<=>', "BINARY", 20, (operands: [TwingBaseExpressionNode, TwingBaseExpressionNode], line: number, column: number) => {
|
||||
return createSpaceshipNode(operands, line, column);
|
||||
}),
|
||||
createOperator('<', "BINARY", 20, (operands: [TwingBaseExpressionNode, TwingBaseExpressionNode], line: number, column: number) => {
|
||||
return createIsLessThanNode(operands, line, column);
|
||||
}),
|
||||
createOperator('<=', "BINARY", 20, (operands: [TwingBaseExpressionNode, TwingBaseExpressionNode], line: number, column: number) => {
|
||||
return createIsLessThanOrEqualToNode(operands, line, column);
|
||||
}),
|
||||
createOperator('>', "BINARY", 20, (operands: [TwingBaseExpressionNode, TwingBaseExpressionNode], line: number, column: number) => {
|
||||
return createIsGreaterThanNode(operands, line, column);
|
||||
}),
|
||||
createOperator('>=', "BINARY", 20, (operands: [TwingBaseExpressionNode, TwingBaseExpressionNode], line: number, column: number) => {
|
||||
return createIsGreaterThanOrEqualToNode(operands, line, column);
|
||||
}),
|
||||
createOperator('not in', "BINARY", 20, (operands: [TwingBaseExpressionNode, TwingBaseExpressionNode], line: number, column: number) => {
|
||||
return createIsNotInNode(operands, line, column);
|
||||
}),
|
||||
createOperator('in', "BINARY", 20, (operands: [TwingBaseExpressionNode, TwingBaseExpressionNode], line: number, column: number) => {
|
||||
return createIsInNode(operands, line, column);
|
||||
}),
|
||||
createOperator('matches', "BINARY", 20, (operands: [TwingBaseExpressionNode, TwingBaseExpressionNode], line: number, column: number) => {
|
||||
return createMatchesNode(operands, line, column);
|
||||
}),
|
||||
createOperator('starts with', "BINARY", 20, (operands: [TwingBaseExpressionNode, TwingBaseExpressionNode], line: number, column: number) => {
|
||||
return createStartsWithNode(operands, line, column);
|
||||
}),
|
||||
createOperator('ends with', "BINARY", 20, (operands: [TwingBaseExpressionNode, TwingBaseExpressionNode], line: number, column: number) => {
|
||||
return createEndsWithNode(operands, line, column);
|
||||
}),
|
||||
createOperator('has some', "BINARY", 20, (operands: [TwingBaseExpressionNode, TwingBaseExpressionNode], line: number, column: number) => {
|
||||
return createHasSomeNode(operands, line, column);
|
||||
}, "LEFT", 3),
|
||||
createOperator('has every', "BINARY", 20, (operands: [TwingBaseExpressionNode, TwingBaseExpressionNode], line: number, column: number) => {
|
||||
return createHasEveryNode(operands, line, column);
|
||||
}, "LEFT", 3),
|
||||
createOperator('..', "BINARY", 25, (operands: [TwingBaseExpressionNode, TwingBaseExpressionNode], line: number, column: number) => {
|
||||
return createRangeNode(operands, line, column);
|
||||
}),
|
||||
createOperator('+', "BINARY", 30, (operands: [TwingBaseExpressionNode, TwingBaseExpressionNode], line: number, column: number) => {
|
||||
return createAddNode(operands, line, column);
|
||||
}),
|
||||
createOperator('-', "BINARY", 30, (operands: [TwingBaseExpressionNode, TwingBaseExpressionNode], line: number, column: number) => {
|
||||
return createSubtractNode(operands, line, column);
|
||||
}),
|
||||
createOperator('~', "BINARY", 40, (operands: [TwingBaseExpressionNode, TwingBaseExpressionNode], line: number, column: number) => {
|
||||
return createConcatenateNode(operands, line, column);
|
||||
}),
|
||||
createOperator('*', "BINARY", 60, (operands: [TwingBaseExpressionNode, TwingBaseExpressionNode], line: number, column: number) => {
|
||||
return createMultiplyNode(operands, line, column);
|
||||
}),
|
||||
createOperator('/', "BINARY", 60, (operands: [TwingBaseExpressionNode, TwingBaseExpressionNode], line: number, column: number) => {
|
||||
return createDivideNode(operands, line, column);
|
||||
}),
|
||||
createOperator('//', "BINARY", 60, (operands: [TwingBaseExpressionNode, TwingBaseExpressionNode], line: number, column: number) => {
|
||||
return createDivideAndFloorNode(operands, line, column);
|
||||
}),
|
||||
createOperator('%', "BINARY", 60, (operands: [TwingBaseExpressionNode, TwingBaseExpressionNode], line: number, column: number) => {
|
||||
return createModuloNode(operands, line, column);
|
||||
}),
|
||||
createOperator('**', "BINARY", 200, (operands: [TwingBaseExpressionNode, TwingBaseExpressionNode], line: number, column: number) => {
|
||||
return createPowerNode(operands, line, column);
|
||||
}, "RIGHT"),
|
||||
createOperator('??', "BINARY", 300, (operands: [TwingBaseExpressionNode, TwingBaseExpressionNode], line: number, column: number) => {
|
||||
return createNullishCoalescingNode(operands, line, column);
|
||||
}, "RIGHT")
|
||||
];
|
||||
},
|
||||
get tagHandlers() {
|
||||
return [];
|
||||
},
|
||||
get tests() {
|
||||
return [
|
||||
createTest('constant', isConstant, [
|
||||
{
|
||||
name: 'constant'
|
||||
},
|
||||
{
|
||||
name: 'object',
|
||||
defaultValue: null
|
||||
}
|
||||
]),
|
||||
createTest('divisible by', isDivisibleBy, [
|
||||
{
|
||||
name: 'divisor'
|
||||
}
|
||||
]),
|
||||
createTest('defined', isDefined, []),
|
||||
createTest('empty', isEmpty, []),
|
||||
createTest('even', isEven, []),
|
||||
createTest('iterable', isIterable, []),
|
||||
createTest('none', isNull, []),
|
||||
createTest('null', isNull, []),
|
||||
createTest('odd', isOdd, []),
|
||||
createTest('same as', isSameAs, [
|
||||
{
|
||||
name: 'comparand'
|
||||
}
|
||||
]),
|
||||
];
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
export const createSynchronousCoreExtension = (): TwingSynchronousExtension => {
|
||||
return {
|
||||
get filters() {
|
||||
|
@ -22,76 +22,7 @@ export const createDateTime = (
|
||||
input: Date | DateTime | number | string | null,
|
||||
timezone: string | null | false
|
||||
): Promise<DateTime> => {
|
||||
const _do = (): DateTime => {
|
||||
let result: DateTime;
|
||||
|
||||
if (input === null) {
|
||||
result = DateTime.local();
|
||||
}
|
||||
else if (typeof input === 'number') {
|
||||
result = DateTime.fromMillis(input * 1000);
|
||||
}
|
||||
else if (typeof input === 'string') {
|
||||
if (input === 'now') {
|
||||
result = DateTime.local();
|
||||
}
|
||||
else {
|
||||
result = DateTime.fromISO(input, {
|
||||
setZone: true
|
||||
});
|
||||
|
||||
if (!result.isValid) {
|
||||
result = DateTime.fromRFC2822(input, {
|
||||
setZone: true
|
||||
});
|
||||
}
|
||||
|
||||
if (!result.isValid) {
|
||||
result = DateTime.fromSQL(input, {
|
||||
setZone: true
|
||||
});
|
||||
}
|
||||
|
||||
if (!result.isValid && /^-{0,1}\d+$/.test(input)) {
|
||||
result = DateTime.fromMillis(Number.parseInt(input) * 1000, {
|
||||
setZone: true
|
||||
});
|
||||
}
|
||||
|
||||
if (!result.isValid) {
|
||||
result = modifyDate(input);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (input instanceof DateTime) {
|
||||
result = input;
|
||||
}
|
||||
else {
|
||||
result = DateTime.fromJSDate(input);
|
||||
}
|
||||
|
||||
if (!result || !result.isValid) {
|
||||
throw new Error(`Failed to parse date "${input}".`);
|
||||
}
|
||||
|
||||
// now let's apply timezone
|
||||
// determine the timezone
|
||||
if (timezone !== false) {
|
||||
if (timezone === null) {
|
||||
timezone = defaultTimezone;
|
||||
}
|
||||
|
||||
result = result.setZone(timezone);
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
try {
|
||||
return Promise.resolve(_do());
|
||||
} catch (e) {
|
||||
return Promise.reject(e);
|
||||
}
|
||||
return Promise.resolve(createDateTimeSynchronously(defaultTimezone, input, timezone))
|
||||
}
|
||||
|
||||
export const date: TwingCallable = (
|
||||
|
Loading…
x
Reference in New Issue
Block a user