Merge branch 'issue-598' into 'main'

Resolve issue #598

Closes #598

See merge request nightlycommit/twing!594
This commit is contained in:
Eric MORAND 2023-12-04 11:53:38 +00:00
commit c94bd15a47
111 changed files with 828 additions and 841 deletions

View File

@ -5,6 +5,7 @@ export type {TwingCache} from "./lib/cache";
// error
export type {TwingError} from "./lib/error";
export type {TwingBaseError, TwingErrorLocation} from "./lib/error/base";
export type {TwingParsingError} from "./lib/error/parsing";
export type {TwingRuntimeError} from "./lib/error/runtime";
export type {TwingTemplateLoadingError} from "./lib/error/loader";
@ -15,7 +16,9 @@ export {createRuntimeError, isARuntimeError} from "./lib/error/runtime";
export {createTemplateLoadingError, isATemplateLoadingError} from "./lib/error/loader";
// loader
export type {TwingFilesystemLoader, TwingFilesystemLoaderFilesystem} from "./lib/loader/filesystem";
export type {
TwingFilesystemLoader, TwingFilesystemLoaderFilesystem, TwingFilesystemLoaderFilesystemStats
} from "./lib/loader/filesystem";
export type {TwingArrayLoader} from "./lib/loader/array";
export type {TwingChainLoader} from "./lib/loader/chain";
export type {TwingLoader} from "./lib/loader";
@ -30,35 +33,49 @@ export type {TwingMarkup} from "./lib/markup";
export {createMarkup, isAMarkup} from "./lib/markup";
// node
export type {TwingNodeAttributes, TwingNodeChildren, TwingNodeType} from "./lib/node";
export type {TwingApplyNode} from "./lib/node/apply";
export type {TwingAutoEscapeNode} from "./lib/node/auto-escape";
export type {TwingBlockNode} from "./lib/node/block";
export type {
TwingBaseNode,
TwingBaseNodeAttributes,
TwingBaseNodeChildren,
TwingNode,
TwingNodeAttributes,
TwingNodeChildren,
TwingNodeType,
KeysOf
} from "./lib/node";
export type {TwingApplyNode, TwingApplyNodeAttributes, TwingApplyNodeChildren} from "./lib/node/apply";
export type {TwingAutoEscapeNode, TwingAutoEscapeNodeAttributes} from "./lib/node/auto-escape";
export type {TwingBlockNode, TwingBlockNodeAttributes} from "./lib/node/block";
export type {TwingBodyNode} from "./lib/node/body";
export type {TwingCheckSecurityNode} from "./lib/node/check-security";
export type {TwingCheckSecurityNode, TwingCheckSecurityNodeAttributes} from "./lib/node/check-security";
export type {TwingCheckToStringNode} from "./lib/node/check-to-string";
export type {TwingCommentNode} from "./lib/node/comment";
export type {TwingCommentNode, TwingCommentNodeAttributes} from "./lib/node/comment";
export type {TwingDeprecatedNode} from "./lib/node/deprecated";
export type {TwingDoNode} from "./lib/node/do";
export type {TwingExpressionNode, TwingBaseExpressionNode} from "./lib/node/expression";
export type {
TwingExpressionNode, TwingBaseExpressionNode, TwingBaseExpressionNodeAttributes
} from "./lib/node/expression";
export type {TwingFlushNode} from "./lib/node/flush";
export type {TwingForNode} from "./lib/node/for";
export type {TwingForLoopNode} from "./lib/node/for-loop";
export type {TwingIfNode} from "./lib/node/if";
export type {TwingImportNode} from "./lib/node/import";
export type {TwingBaseIncludeNode} from "./lib/node/include";
export type {TwingLineNode} from "./lib/node/line";
export type {TwingMacroNode} from "./lib/node/macro";
export type {TwingTemplateNode} from "./lib/node/template";
export type {TwingForNode, TwingForNodeAttributes, TwingForNodeChildren} from "./lib/node/for";
export type {TwingForLoopNode, TwingForLoopNodeAttributes} from "./lib/node/for-loop";
export type {TwingIfNode, TwingIfNodeChildren} from "./lib/node/if";
export type {TwingImportNode, TwingImportNodeAttributes} from "./lib/node/import";
export type {
TwingBaseIncludeNode, TwingBaseIncludeNodeAttributes, TwingBaseIncludeNodeChildren
} from "./lib/node/include";
export type {TwingLineNode, TwingLineNodeAttributes} from "./lib/node/line";
export type {TwingMacroNode, TwingMacroNodeAttributes} from "./lib/node/macro";
export type {TwingBaseOutputNode} from "./lib/node/output";
export type {TwingTemplateNode, TwingTemplateNodeAttributes, TwingTemplateNodeChildren} from "./lib/node/template";
export type {TwingSandboxNode} from "./lib/node/sandbox";
export type {TwingSetNode} from "./lib/node/set";
export type {TwingSetNode, TwingSetNodeAttributes} from "./lib/node/set";
export type {TwingTraitNode} from "./lib/node/trait";
export type {TwingWithNode} from "./lib/node/with";
export type {TwingWithNode, TwingWithNodeAttributes, TwingWithNodeChildren} from "./lib/node/with";
export type {TwingWrapperNode, TwingWrapperNodeChildren} from "./lib/node/wrapper";
export {createApplyNode, applyNodeType} from "./lib/node/apply";
export {createAutoEscapeNode, autoEscapeNodeType} from "./lib/node/auto-escape";
export {createBlockNode, blockNodeType} from "./lib/node/block";
export {createApplyNode} from "./lib/node/apply";
export {createAutoEscapeNode} from "./lib/node/auto-escape";
export {createBlockNode} from "./lib/node/block";
export {createBodyNode} from "./lib/node/body";
export {createCheckSecurityNode} from "./lib/node/check-security";
export {createCheckToStringNode} from "./lib/node/check-to-string";
@ -73,45 +90,59 @@ export {createImportNode} from "./lib/node/import";
export {createBaseIncludeNode} from "./lib/node/include";
export {createLineNode} from "./lib/node/line";
export {createMacroNode} from "./lib/node/macro";
export {createTemplateNode, templateNodeType} from "./lib/node/template";
export {createSandboxNode, sandboxNodeType} from "./lib/node/sandbox";
export {createTemplateNode} from "./lib/node/template";
export {createSandboxNode} from "./lib/node/sandbox";
export {createSetNode} from "./lib/node/set";
export {createTraitNode, traitNodeType} from "./lib/node/trait";
export {createTraitNode} from "./lib/node/trait";
export {createWithNode} from "./lib/node/with";
export {createWrapperNode} from "./lib/node/wrapper";
// node/expression
export type {TwingBaseArrayNode, TwingArrayNode} from "./lib/node/expression/array";
export type {TwingArrowFunctionNode} from "./lib/node/expression/arrow-function";
export type {TwingAssignmentNode} from "./lib/node/expression/assignment";
export type {TwingAttributeAccessorNode} from "./lib/node/expression/attribute-accessor";
export type {TwingAssignmentNode, TwingAssignmentNodeAttributes} from "./lib/node/expression/assignment";
export type {
TwingAttributeAccessorNode,
TwingAttributeAccessorNodeAttributes,
TwingAttributeAccessorNodeChildren,
TwingAttributeAccessorCallType
} from "./lib/node/expression/attribute-accessor";
export type {TwingBaseBinaryNode, TwingBinaryNode} from "./lib/node/expression/binary";
export type {TwingBlockFunctionNode} from "./lib/node/expression/block-function";
export type {TwingBaseCallNode, TwingCallNode} from "./lib/node/expression/call";
export type {
TwingBlockFunctionNode, TwingBlockFunctionNodeAttributes, TwingBlockFunctionNodeChildren
} from "./lib/node/expression/block-function";
export type {
TwingBaseCallNode, TwingCallNode, TwingBaseCallNodeChildren, TwingBaseCallNodeAttributes
} from "./lib/node/expression/call";
export type {TwingBaseConditionalNode, TwingConditionalNode} from "./lib/node/expression/conditional";
export type {TwingConstantNode} from "./lib/node/expression/constant";
export type {TwingEscapeNode} from "./lib/node/expression/escape";
export type {
TwingConstantNode, TwingConstantNodeAttributes, TwingConstantNodeValue
} from "./lib/node/expression/constant";
export type {TwingEscapeNode, TwingEscapeNodeAttributes} from "./lib/node/expression/escape";
export type {TwingHashNode} from "./lib/node/expression/hash";
export type {TwingMethodCallNode} from "./lib/node/expression/method-call";
export type {TwingNameNode} from "./lib/node/expression/name";
export type {TwingMethodCallNode, TwingMethodCallNodeAttributes} from "./lib/node/expression/method-call";
export type {TwingNameNode, TwingNameNodeAttributes} from "./lib/node/expression/name";
export type {TwingNullishCoalescingNode} from "./lib/node/expression/nullish-coalescing";
export type {TwingParentFunctionNode} from "./lib/node/expression/parent-function";
export type {TwingSpreadNode} from "./lib/node/expression/spread";
export type {TwingBaseUnaryNode, TwingUnaryNode} from "./lib/node/expression/unary";
export {createBaseArrayNode, createArrayNode} from "./lib/node/expression/array";
export {createArrowFunctionNode} from "./lib/node/expression/arrow-function";
export {createAssignmentNode, assignmentNodeType} from "./lib/node/expression/assignment";
export {createAssignmentNode} from "./lib/node/expression/assignment";
export {createAttributeAccessorNode} from "./lib/node/expression/attribute-accessor";
export {createBaseBinaryNode} from "./lib/node/expression/binary";
export {createBlockFunctionNode, blockFunctionNodeType} from "./lib/node/expression/block-function";
export {createBlockFunctionNode} from "./lib/node/expression/block-function";
export {createBaseCallNode} from "./lib/node/expression/call";
export {createBaseConditionalNode, createConditionalNode, conditionalNodeType} from "./lib/node/expression/conditional";
export {createConstantNode, constantNodeType} from "./lib/node/expression/constant";
export {createBaseConditionalNode, createConditionalNode} from "./lib/node/expression/conditional";
export {createConstantNode} from "./lib/node/expression/constant";
export {createEscapeNode} from "./lib/node/expression/escape";
export {createHashNode, hashNodeType} from "./lib/node/expression/hash";
export {createMethodCallNode, methodCallNodeType} from "./lib/node/expression/method-call";
export {createNameNode, nameNodeType} from "./lib/node/expression/name";
export {createNullishCoalescingNode, nullishCoalescingNodeType} from "./lib/node/expression/nullish-coalescing";
export {createParentFunctionNode, parentFunctionNodeType} from "./lib/node/expression/parent-function";
export {createHashNode} from "./lib/node/expression/hash";
export {createMethodCallNode} from "./lib/node/expression/method-call";
export {createNameNode} from "./lib/node/expression/name";
export {createNullishCoalescingNode} from "./lib/node/expression/nullish-coalescing";
export {createParentFunctionNode} from "./lib/node/expression/parent-function";
export {createSpreadNode} from "./lib/node/expression/spread";
export {createBaseUnaryNode} from "./lib/node/expression/unary";
// node/expression/binary
@ -124,6 +155,8 @@ export type {TwingConcatenateNode} from "./lib/node/expression/binary/concatenat
export type {TwingDivideAndFloorNode} from "./lib/node/expression/binary/divide-and-floor";
export type {TwingDivideNode} from "./lib/node/expression/binary/divide";
export type {TwingEndsWithNode} from "./lib/node/expression/binary/ends-with";
export type {TwingHasEveryNode} from "./lib/node/expression/binary/has-every";
export type {TwingHasSomeNode} from "./lib/node/expression/binary/has-some";
export type {TwingIsEqualToNode} from "./lib/node/expression/binary/is-equal-to";
export type {TwingIsGreaterThanOrEqualToNode} from "./lib/node/expression/binary/is-greater-than-or-equal-to";
export type {TwingIsGreaterThanNode} from "./lib/node/expression/binary/is-greater-than";
@ -138,20 +171,21 @@ export type {TwingMultiplyNode} from "./lib/node/expression/binary/multiply";
export type {TwingOrNode} from "./lib/node/expression/binary/or";
export type {TwingPowerNode} from "./lib/node/expression/binary/power";
export type {TwingRangeNode} from "./lib/node/expression/binary/range";
export type {TwingSpaceshipNode} from "./lib/node/expression/binary/spaceship";
export type {TwingStartsWithNode} from "./lib/node/expression/binary/starts-with";
export type {TwingSubtractNode} from "./lib/node/expression/binary/subtract";
export {createAddNode, addNodeType} from "./lib/node/expression/binary/add";
export {createAndNode, andNodeType} from "./lib/node/expression/binary/and";
export {createBitwiseAndNode, bitwiseAndNodeType} from "./lib/node/expression/binary/bitwise-and";
export {createBitwiseOrNode, bitwiseOrNodeType} from "./lib/node/expression/binary/bitwise-or";
export {createBitwiseXorNode, bitwiseXorNodeType} from "./lib/node/expression/binary/bitwise-xor";
export {createConcatenateNode, concatenateNodeTYpe} from "./lib/node/expression/binary/concatenate";
export {createDivideAndFloorNode, divideAndFloorNodeType} from "./lib/node/expression/binary/divide-and-floor";
export {createDivideNode, divideNodeType} from "./lib/node/expression/binary/divide";
export {createEndsWithNode, endsWithNodeType} from "./lib/node/expression/binary/ends-with";
export {createHasEveryNode, hasEveryNodeType} from "./lib/node/expression/binary/has-every";
export {createHasSomeNode, hasSomeNodeType} from "./lib/node/expression/binary/has-some";
export {createAddNode} from "./lib/node/expression/binary/add";
export {createAndNode} from "./lib/node/expression/binary/and";
export {createBitwiseAndNode} from "./lib/node/expression/binary/bitwise-and";
export {createBitwiseOrNode} from "./lib/node/expression/binary/bitwise-or";
export {createBitwiseXorNode} from "./lib/node/expression/binary/bitwise-xor";
export {createConcatenateNode} from "./lib/node/expression/binary/concatenate";
export {createDivideAndFloorNode} from "./lib/node/expression/binary/divide-and-floor";
export {createDivideNode} from "./lib/node/expression/binary/divide";
export {createEndsWithNode} from "./lib/node/expression/binary/ends-with";
export {createHasEveryNode} from "./lib/node/expression/binary/has-every";
export {createHasSomeNode} from "./lib/node/expression/binary/has-some";
export {createIsEqualNode} from "./lib/node/expression/binary/is-equal-to";
export {createIsGreaterThanNode} from "./lib/node/expression/binary/is-greater-than";
export {createIsGreaterThanOrEqualToNode} from "./lib/node/expression/binary/is-greater-than-or-equal-to";
@ -174,38 +208,38 @@ export type {TwingFilterNode} from "./lib/node/expression/call/filter";
export type {TwingFunctionNode} from "./lib/node/expression/call/function";
export type {TwingTestNode} from "./lib/node/expression/call/test";
export {createFilterNode, filterNodeType} from "./lib/node/expression/call/filter";
export {createFunctionNode, functionNodeType} from "./lib/node/expression/call/function";
export {createTestNode, testNodeType} from "./lib/node/expression/call/test";
export {createFilterNode} from "./lib/node/expression/call/filter";
export {createFunctionNode} from "./lib/node/expression/call/function";
export {createTestNode} from "./lib/node/expression/call/test";
// node/expression/unary
export type {TwingNegativeNode} from "./lib/node/expression/unary/neg";
export type {TwingNegativeNode} from "./lib/node/expression/unary/negative";
export type {TwingNotNode} from "./lib/node/expression/unary/not";
export type {TwingPositiveNode} from "./lib/node/expression/unary/pos";
export type {TwingPositiveNode} from "./lib/node/expression/unary/positive";
export {createNegativeNode, negativeNodeType} from "./lib/node/expression/unary/neg";
export {createNotNode, notNodeType} from "./lib/node/expression/unary/not";
export {createPositiveNode, positiveNodeType} from "./lib/node/expression/unary/pos";
export {createNegativeNode} from "./lib/node/expression/unary/negative";
export {createNotNode} from "./lib/node/expression/unary/not";
export {createPositiveNode} from "./lib/node/expression/unary/positive";
// node/include
export type {TwingEmbedNode} from "./lib/node/include/embed";
export type {TwingIncludeNode} from "./lib/node/include/include";
export type {TwingEmbedNode, TwingEmbedNodeAttributes} from "./lib/node/include/embed";
export type {TwingIncludeNode, TwingIncludeNodeChildren} from "./lib/node/include/include";
export {createEmbedNode, embedNodeType} from "./lib/node/include/embed";
export {createIncludeNode, includeNodeType} from "./lib/node/include/include";
export {createEmbedNode} from "./lib/node/include/embed";
export {createIncludeNode} from "./lib/node/include/include";
// node/output
export type {TwingBlockReferenceNode} from "./lib/node/output/block-reference";
export type {TwingBlockReferenceNode, TwingBlockReferenceNodeAttributes} from "./lib/node/output/block-reference";
export type {TwingPrintNode} from "./lib/node/output/print";
export type {TwingSpacelessNode} from "./lib/node/output/spaceless";
export type {TwingTextNode} from "./lib/node/output/text";
export type {TwingTextNode, TwingBaseTextNode, TwingBaseTextNodeAttributes} from "./lib/node/output/text";
export type {TwingVerbatimNode} from "./lib/node/output/verbatim";
export {createBlockReferenceNode, blockReferenceType} from "./lib/node/output/block-reference";
export {createPrintNode, printNodeType} from "./lib/node/output/print";
export {createSpacelessNode, spacelessNodeType} from "./lib/node/output/spaceless";
export {createTextNode, textNodeType} from "./lib/node/output/text";
export {createVerbatimNode, verbatimNodeType} from "./lib/node/output/verbatim";
export {createBlockReferenceNode} from "./lib/node/output/block-reference";
export {createPrintNode} from "./lib/node/output/print";
export {createSpacelessNode} from "./lib/node/output/spaceless";
export {createTextNode} from "./lib/node/output/text";
export {createVerbatimNode} from "./lib/node/output/verbatim";
// tag handlers
export type {TwingTagHandler, TwingTokenParser} from "./lib/tag-handler";
@ -234,16 +268,27 @@ export {createVerbatimTagHandler} from "./lib/tag-handler/verbatim";
export {createWithTagHandler} from "./lib/tag-handler/with";
// core
export type {
TwingCallable, TwingCallableArgument, TwingCallableWrapperOptions, TwingCallableWrapper
} from "./lib/callable-wrapper";
export type {TwingContext} from "./lib/context";
export type {TwingEnvironment, TwingEnvironmentOptions, TwingNumberFormat} from "./lib/environment";
export type {
TwingEscapingStrategy, TwingEscapingStrategyHandler, TwingEscapingStrategyResolver
} from "./lib/escaping-strategy";
export type {TwingExecutionContext} from "./lib/execution-context";
export type {TwingExtension} from "./lib/extension";
export type {TwingExtensionSet} from "./lib/extension-set";
export type {TwingFilter} from "./lib/filter";
export type {TwingFunction} from "./lib/function";
export type {TwingLexer} from "./lib/lexer";
export type {TwingBaseNode} from "./lib/node";
export type {TwingNodeVisitor} from "./lib/node-visitor";
export type {TwingOperator} from "./lib/operator";
export type {
TwingOperator, TwingOperatorAssociativity, TwingOperatorType, TwingOperatorExpressionFactory
} from "./lib/operator";
export type {TwingOutputBuffer} from "./lib/output-buffer";
export type {TwingParser, TwingParserOptions} from "./lib/parser";
export type {TwingSandboxSecurityError} from "./lib/sandbox/security-error";
export type {TwingSandboxSecurityPolicy} from "./lib/sandbox/security-policy";
export type {TwingSandboxSecurityNotAllowedFilterError} from "./lib/sandbox/security-not-allowed-filter-error";
export type {TwingSandboxSecurityNotAllowedFunctionError} from "./lib/sandbox/security-not-allowed-function-error";
@ -251,7 +296,14 @@ export type {TwingSandboxSecurityNotAllowedMethodError} from "./lib/sandbox/secu
export type {TwingSandboxSecurityNotAllowedPropertyError} from "./lib/sandbox/security-not-allowed-property-error";
export type {TwingSandboxSecurityNotAllowedTagError} from "./lib/sandbox/security-not-allowed-tag-error";
export type {TwingSource} from "./lib/source";
export type {TwingTemplate} from "./lib/template";
export type {TwingSourceMapRuntime} from "./lib/source-map-runtime";
export type {
TwingTemplate,
TwingTemplateAliases,
TwingTemplateBlockMap,
TwingTemplateBlockHandler,
TwingTemplateMacroHandler
} from "./lib/template";
export type {TwingTest} from "./lib/test";
export type {TwingTokenStream} from "./lib/token-stream";

View File

@ -7,7 +7,7 @@ import {TwingLoader} from "./loader";
import {TwingTest} from "./test";
import {TwingFunction} from "./function";
import {TwingOperator} from "./operator";
import {EscapingStrategy, EscapingStrategyHandler} from "./escaping-strategy";
import {TwingEscapingStrategy, TwingEscapingStrategyHandler} from "./escaping-strategy";
import {createHtmlEscapingStrategyHandler} from "./escaping-stragegy/html";
import {createCssEscapingStrategyHandler} from "./escaping-stragegy/css";
import {createJsEscapingStrategyHandler} from "./escaping-stragegy/js";
@ -16,7 +16,7 @@ import {createHtmlAttributeEscapingStrategyHandler} from "./escaping-stragegy/ht
import {TwingSource} from "./source";
import {createTokenStream, TwingTokenStream} from "./token-stream";
import {TwingExtension} from "./extension";
import {templateNodeType, TwingTemplateNode} from "./node/template";
import {TwingTemplateNode} from "./node/template";
import {RawSourceMap} from "source-map";
import {createSourceMapRuntime} from "./source-map-runtime";
import {createSandboxSecurityPolicy, TwingSandboxSecurityPolicy} from "./sandbox/security-policy";
@ -80,7 +80,7 @@ export interface TwingEnvironment {
readonly charset: string;
readonly dateFormat: string;
readonly dateIntervalFormat: string;
readonly escapingStrategyHandlers: Record<EscapingStrategy, EscapingStrategyHandler>;
readonly escapingStrategyHandlers: Record<TwingEscapingStrategy, TwingEscapingStrategyHandler>;
readonly numberFormat: TwingNumberFormat;
readonly filters: Map<string, TwingFilter>;
readonly functions: Map<string, TwingFunction>;
@ -152,7 +152,7 @@ export interface TwingEnvironment {
sourceMap: RawSourceMap;
}>;
registerEscapingStrategy(handler: EscapingStrategyHandler, name: string): void;
registerEscapingStrategy(handler: TwingEscapingStrategyHandler, name: string): void;
/**
* Tokenizes a source code.
@ -179,7 +179,7 @@ export const createEnvironment = (
const jsEscapingStrategy = createJsEscapingStrategyHandler();
const urlEscapingStrategy = createUrlEscapingStrategyHandler();
const escapingStrategyHandlers: Record<EscapingStrategy, EscapingStrategyHandler> = {
const escapingStrategyHandlers: Record<TwingEscapingStrategy, TwingEscapingStrategyHandler> = {
css: cssEscapingStrategy,
html: htmlEscapingStrategy,
html_attr: htmlAttributeEscapingStrategy,
@ -344,7 +344,7 @@ export const createEnvironment = (
return node;
},
leaveNode: (node) => {
if (node.is(templateNodeType)) {
if (node.type === "template") {
const autoEscapeNode = createAutoEscapeNode(strategy, node.children.body.children.content, node.line, node.column, 'foo');
node.children.body.children.content = autoEscapeNode;
@ -411,7 +411,7 @@ export const createEnvironment = (
},
tokenize: (source: TwingSource): TwingTokenStream => {
const level = options?.parserOptions?.level || 3;
if (!lexer) {
lexer = createLexer(
level,

View File

@ -1,4 +1,4 @@
export type ErrorLocation = {
export type TwingErrorLocation = {
line: number;
column: number;
};
@ -7,14 +7,14 @@ export interface TwingBaseError<Name extends string> extends Error {
readonly name: Name;
readonly previous: any | undefined;
readonly rootMessage: string;
location: ErrorLocation | undefined;
location: TwingErrorLocation | undefined;
source: string | undefined;
appendMessage(message: string): void;
}
export const createBaseError = <Name extends string>(
name: Name, message: string, location?: ErrorLocation, source?: string, previous?: any
name: Name, message: string, location?: TwingErrorLocation, source?: string, previous?: any
): TwingBaseError<Name> => {
const baseError = Error(message);
@ -23,7 +23,7 @@ export const createBaseError = <Name extends string>(
const error = Object.create(baseError, {
location: {
get: () => location,
set: (value: ErrorLocation) => {
set: (value: TwingErrorLocation) => {
location = value;
updateRepresentation();

View File

@ -1,4 +1,4 @@
import {createBaseError, ErrorLocation, TwingBaseError} from "./base";
import {createBaseError, TwingErrorLocation, TwingBaseError} from "./base";
export const templateLoadingError = 'TwingTemplateLoadingError';
@ -9,7 +9,7 @@ export interface TwingTemplateLoadingError extends TwingBaseError<typeof templat
}
export const createTemplateLoadingError = (names: Array<string | null>, location?: ErrorLocation, source?: string, previous?: any): TwingTemplateLoadingError => {
export const createTemplateLoadingError = (names: Array<string | null>, location?: TwingErrorLocation, source?: string, previous?: any): TwingTemplateLoadingError => {
let message: string;
if (names.length === 1) {

View File

@ -1,4 +1,4 @@
import {createBaseError, ErrorLocation, TwingBaseError} from "./base";
import {createBaseError, TwingErrorLocation, TwingBaseError} from "./base";
const Levenshtein = require('levenshtein');
@ -15,7 +15,7 @@ export interface TwingParsingError extends TwingBaseError<typeof parsingErrorNam
}
export const createParsingError = (
message: string, location?: ErrorLocation, source?: string, previous?: Error
message: string, location?: TwingErrorLocation, source?: string, previous?: Error
): TwingParsingError => {
const baseError = createBaseError(parsingErrorName, message, location, source, previous);

View File

@ -1,4 +1,4 @@
import {createBaseError, ErrorLocation, TwingBaseError} from "./base";
import {createBaseError, TwingErrorLocation, TwingBaseError} from "./base";
export const runtimeErrorName = 'TwingRuntimeError';
@ -10,7 +10,7 @@ export const isARuntimeError = (candidate: Error): candidate is TwingRuntimeErro
return (candidate as TwingRuntimeError).name === runtimeErrorName;
};
export const createRuntimeError = (message: string, location?: ErrorLocation, source?: string, previous?: Error): TwingRuntimeError => {
export const createRuntimeError = (message: string, location?: TwingErrorLocation, source?: string, previous?: Error): TwingRuntimeError => {
const error = createBaseError(runtimeErrorName, message, location, source, previous);
Error.captureStackTrace(error, createRuntimeError);

View File

@ -1,9 +1,9 @@
import type {EscapingStrategyHandler} from "../escaping-strategy";
import type {TwingEscapingStrategyHandler} from "../escaping-strategy";
const phpBin2hex = require("locutus/php/strings/bin2hex");
const phpLtrim = require('locutus/php/strings/ltrim');
const strlen = require('utf8-binary-cutter').getBinarySize;
export const createCssEscapingStrategyHandler = (): EscapingStrategyHandler => {
export const createCssEscapingStrategyHandler = (): TwingEscapingStrategyHandler => {
return (value) => {
value = value.replace(/[^a-zA-Z0-9]/ug, (matches: string) => {
let char = matches;

View File

@ -1,8 +1,8 @@
import {EscapingStrategyHandler} from "../escaping-strategy";
import {TwingEscapingStrategyHandler} from "../escaping-strategy";
const phpOrd = require('locutus/php/strings/ord');
export const createHtmlAttributeEscapingStrategyHandler = (): EscapingStrategyHandler => {
export const createHtmlAttributeEscapingStrategyHandler = (): TwingEscapingStrategyHandler => {
return (value) => {
value = value.replace(/[^a-zA-Z0-9,.\-_]/ug, function (matches: string) {
/**

View File

@ -1,8 +1,8 @@
import type {EscapingStrategyHandler} from "../escaping-strategy";
import type {TwingEscapingStrategyHandler} from "../escaping-strategy";
const htmlspecialchars: (value: string) => string = require('htmlspecialchars');
export const createHtmlEscapingStrategyHandler = (): EscapingStrategyHandler => {
export const createHtmlEscapingStrategyHandler = (): TwingEscapingStrategyHandler => {
return (value) => {
return htmlspecialchars(value);
}

View File

@ -1,10 +1,10 @@
import type {EscapingStrategyHandler} from "../escaping-strategy";
import type {TwingEscapingStrategyHandler} from "../escaping-strategy";
const phpBin2hex = require("locutus/php/strings/bin2hex");
const phpSprintf = require('locutus/php/strings/sprintf');
const strlen = require('utf8-binary-cutter').getBinarySize;
export const createJsEscapingStrategyHandler = (): EscapingStrategyHandler => {
export const createJsEscapingStrategyHandler = (): TwingEscapingStrategyHandler => {
return (value) => {
// escape all non-alphanumeric characters
// into their \x or \uHHHH representations

View File

@ -1,7 +1,7 @@
import {EscapingStrategyHandler} from "../escaping-strategy";
import {TwingEscapingStrategyHandler} from "../escaping-strategy";
const phpRawurlencode = require('locutus/php/url/rawurlencode');
export const createUrlEscapingStrategyHandler = (): EscapingStrategyHandler => {
export const createUrlEscapingStrategyHandler = (): TwingEscapingStrategyHandler => {
return phpRawurlencode;
};

View File

@ -1,3 +1,3 @@
export type EscapingStrategyResolver = (templateName: string) => string | null;
export type EscapingStrategy = "css" | "html" | "html_attr" | "js" | "url" | string; // todo: remove true
export type EscapingStrategyHandler = (value: string, charset: string, templateName: string) => string;
export type TwingEscapingStrategyResolver = (templateName: string) => string | null;
export type TwingEscapingStrategy = "css" | "html" | "html_attr" | "js" | "url" | string; // todo: remove true
export type TwingEscapingStrategyHandler = (value: string, charset: string, templateName: string) => string;

View File

@ -4,8 +4,8 @@ import {createIsInNode} from "../node/expression/binary/is-in";
import {createIsGreaterThanNode} from "../node/expression/binary/is-greater-than";
import {createIsLessThanNode} from "../node/expression/binary/is-less-than";
import {createNotNode} from "../node/expression/unary/not";
import {createNegativeNode} from "../node/expression/unary/neg";
import {createPositiveNode} from "../node/expression/unary/pos";
import {createNegativeNode} from "../node/expression/unary/negative";
import {createPositiveNode} from "../node/expression/unary/positive";
import {createFunction} from "../function";
import {createConcatenateNode} from "../node/expression/binary/concatenate";
import {createMultiplyNode} from "../node/expression/binary/multiply";

View File

@ -3,7 +3,7 @@ import {createRuntimeError} from "../error/runtime";
import {examineObject} from "./examine-object";
import {isPlainObject} from "./is-plain-object";
import {get} from "./get";
import type {TwingGetAttributeCallType} from "../node/expression/attribute-accessor";
import type {TwingAttributeAccessorCallType} from "../node/expression/attribute-accessor";
import {isBoolean, isFloat} from "./php";
import {TwingTemplate} from "../template";
@ -29,7 +29,7 @@ export const getAttribute = (
object: any,
attribute: any,
methodArguments: Map<any, any>,
type: TwingGetAttributeCallType,
type: TwingAttributeAccessorCallType,
shouldTestExistence: boolean,
shouldIgnoreStrictCheck: boolean | null,
sandboxed: boolean,

View File

@ -5,14 +5,20 @@ import {createSource} from "../source";
const rtrim = require('locutus/php/strings/rtrim');
interface Stats {
export interface TwingFilesystemLoaderFilesystemStats {
isFile(): boolean;
readonly mtime: Date;
}
export interface TwingFilesystemLoaderFilesystem {
stat(path: string, callback: (error: Error | null, stats: Stats | null) => void): void;
stat(
path: string,
callback: (
error: Error | null,
stats: TwingFilesystemLoaderFilesystemStats | null
) => void
): void;
readFile(path: string, callback: (error: Error | null, data: Buffer | null) => void): void;
}
@ -40,7 +46,7 @@ export const createFilesystemLoader = (
): TwingFilesystemLoader => {
const namespacedPaths: Map<string, Array<string>> = new Map();
const stat = (path: string): Promise<Stats | null> => {
const stat = (path: string): Promise<TwingFilesystemLoaderFilesystemStats | null> => {
return new Promise((resolve) => {
filesystem.stat(path, (error, stats) => {
if (error) {

View File

@ -1,5 +1,5 @@
import {TwingNodeVisitor} from "./node-visitor";
import {TwingBaseNode, getChildren, TwingNode} from "./node";
import {TwingBaseNode, getChildren} from "./node";
/**
* TwingNodeTraverser is a node traverser.
@ -30,7 +30,7 @@ export const createNodeTraverser = (
};
return (node) => {
let result: TwingNode | null = node;
let result: TwingBaseNode | null = node;
for (const visitor of visitors) {
result = traverseWithVisitor(visitor, node);

View File

@ -1,5 +1,4 @@
import type {TwingBaseNode} from "./node";
import {TwingNode} from "./node";
/**
* The interface that all node visitors must implement.
@ -8,14 +7,14 @@ export interface TwingNodeVisitor {
/**
* Called before the passed node is visited.
*
* @return {TwingBaseNode} The modified node
* @return The modified node
*/
enterNode(node: TwingBaseNode): TwingBaseNode;
/**
* Called after the passed node has been visited.
*
* @return {TwingBaseNode} The modified node or null if the node must be removed from its parent
* @return The modified node or null if the node must be removed from its parent
*/
leaveNode(node: TwingBaseNode): TwingBaseNode | null;
}
@ -24,8 +23,8 @@ export interface TwingNodeVisitor {
* Convenient factory for TwingNodeVisitor
*/
export const createNodeVisitor = (
enterNode: (node: TwingBaseNode) => TwingNode,
leaveNode: (node: TwingBaseNode) => TwingNode | null
enterNode: (node: TwingBaseNode) => TwingBaseNode,
leaveNode: (node: TwingBaseNode) => TwingBaseNode | null
): TwingNodeVisitor => {
return {
enterNode,

View File

@ -1,17 +1,19 @@
import {TwingNodeVisitor} from "../node-visitor";
import {cloneGetAttributeNode, TwingAttributeAccessorNode} from "../node/expression/attribute-accessor";
import {cloneNameNode, nameNodeType} from "../node/expression/name";
import {blockFunctionNodeType, cloneBlockReferenceExpressionNode} from "../node/expression/block-function";
import {constantNodeType, createConstantNode} from "../node/expression/constant";
import {cloneMethodCallNode, methodCallNodeType} from "../node/expression/method-call";
import {
cloneGetAttributeNode,
TwingAttributeAccessorNode
} from "../node/expression/attribute-accessor";
import {cloneNameNode} from "../node/expression/name";
import {cloneBlockReferenceExpressionNode} from "../node/expression/block-function";
import {createConstantNode} from "../node/expression/constant";
import {cloneMethodCallNode} from "../node/expression/method-call";
import {TwingBaseExpressionNode} from "../node/expression";
import {createParsingError} from "../error/parsing";
import {createTestNode, testNodeType, TwingTestNode} from "../node/expression/call/test";
import {createTestNode, TwingTestNode} from "../node/expression/call/test";
import {createArrayNode, getKeyValuePairs} from "../node/expression/array";
import {createConditionalNode} from "../node/expression/conditional";
import {functionNodeType} from "../node/expression/call/function";
import {filterNodeType, TwingFilterNode} from "../node/expression/call/filter";
import {hashNodeType} from "../node/expression/hash";
import {TwingFilterNode} from "../node/expression/call/filter";
import type {TwingNode} from "../node";
export const createCoreNodeVisitor = (): TwingNodeVisitor => {
const enteredNodes: Array<TwingBaseExpressionNode> = [];
@ -23,7 +25,7 @@ export const createCoreNodeVisitor = (): TwingNodeVisitor => {
let newNode: TwingBaseExpressionNode;
if (operand.is("name") || operand.is("get_attribute")) {
if (operand.type === "name" || operand.type === "attribute_accessor") {
const testNode = createTestNode(
operand,
"defined",
@ -37,7 +39,8 @@ export const createCoreNodeVisitor = (): TwingNodeVisitor => {
newNode = createConditionalNode(testNode, node, falseNode, line, column);
} else {
}
else {
newNode = node;
}
@ -45,44 +48,48 @@ export const createCoreNodeVisitor = (): TwingNodeVisitor => {
};
const enterDefinedTestNode = (node: TwingTestNode): TwingTestNode => {
const operand = node.children.operand!;
const operand = node.children.operand! as TwingNode;
if (
!operand.is(nameNodeType) &&
!operand.is("get_attribute") &&
!operand.is(blockFunctionNodeType) &&
!operand.is(constantNodeType) &&
!operand.is("array") &&
!operand.is(hashNodeType) &&
!operand.is(methodCallNodeType) &&
!(operand.is(functionNodeType) && (operand.attributes.operatorName === 'constant'))
operand.type !== "name" &&
operand.type !== "attribute_accessor" &&
operand.type !== "block_function" &&
operand.type !== "constant" &&
operand.type !== "array" &&
operand.type !== "hash" &&
operand.type !== "method_call" &&
!(operand.type === "function" && operand.attributes.operatorName === 'constant')
) {
throw createParsingError('The "defined" test only works with simple variables.', node);
}
let newOperand: TwingBaseExpressionNode;
if (operand.is(blockFunctionNodeType)) {
if (operand.type === "block_function") {
const blockReferenceExpressionNode = cloneBlockReferenceExpressionNode(operand);
blockReferenceExpressionNode.attributes.shouldTestExistence = true;
newOperand = blockReferenceExpressionNode;
} else if (operand.is("constant") || operand.is("array")) {
}
else if (operand.type === "constant" || operand.type === "array") {
newOperand = createConstantNode(true, operand.line, operand.column);
} else if (operand.is("name")) {
}
else if (operand.type === "name") {
const nameNode = cloneNameNode(operand);
nameNode.attributes.shouldTestExistence = true;
newOperand = nameNode;
} else if (operand.is("method_call")) {
}
else if (operand.type === "method_call") {
const methodCallNode = cloneMethodCallNode(operand);
methodCallNode.attributes.shouldTestExistence = true;
newOperand = methodCallNode;
} else if (operand.is("get_attribute")) {
}
else if (operand.type === "attribute_accessor") {
const getAttributeNode = cloneGetAttributeNode(operand);
getAttributeNode.attributes.shouldTestExistence = true;
@ -91,7 +98,7 @@ export const createCoreNodeVisitor = (): TwingNodeVisitor => {
node.attributes.isOptimizable = false;
node.attributes.shouldIgnoreStrictCheck = true;
if (node.children.target.is("get_attribute")) {
if (node.children.target.type === "attribute_accessor") {
const clonedTarget = cloneGetAttributeNode(node.children.target);
traverse(clonedTarget);
@ -103,7 +110,8 @@ export const createCoreNodeVisitor = (): TwingNodeVisitor => {
traverse(getAttributeNode);
newOperand = getAttributeNode;
} else {
}
else {
newOperand = operand;
}
@ -117,7 +125,7 @@ export const createCoreNodeVisitor = (): TwingNodeVisitor => {
const {target} = node.children;
if (shouldIgnoreStrictCheck) {
if (target.is("name")) {
if (target.type === "name") {
const nameNode = cloneNameNode(target);
nameNode.attributes.shouldIgnoreStrictCheck = true;
@ -130,17 +138,17 @@ export const createCoreNodeVisitor = (): TwingNodeVisitor => {
};
return {
enterNode: (node) => {
enterNode: (node: TwingNode) => {
if (!enteredNodes.includes(node)) {
enteredNodes.push(node);
if (node.is(filterNodeType)) {
if (node.type === "filter") {
if (node.attributes.operatorName === "default") {
return enterDefaultFilterNode(node);
}
}
if (node.is(testNodeType)) {
if (node.type === "test") {
if (node.attributes.operatorName === "defined") {
return enterDefinedTestNode(node);
}
@ -149,8 +157,8 @@ export const createCoreNodeVisitor = (): TwingNodeVisitor => {
return node;
},
leaveNode: (node) => {
if (node.is("get_attribute")) {
leaveNode: (node: TwingNode) => {
if (node.type === "attribute_accessor") {
return leaveGetAttributeNode(node);
}

View File

@ -1,14 +1,10 @@
import {TwingBaseNode} from "../node";
import {TwingBaseNode, TwingNode} from "../node";
import {createPrintNode, TwingPrintNode} from "../node/output/print";
import {createDoNode} from "../node/do";
import {TwingConditionalNode, createConditionalNode, conditionalNodeType} from "../node/expression/conditional";
import {createConditionalNode, TwingConditionalNode} from "../node/expression/conditional";
import {createEscapeNode, TwingEscapeNode} from "../node/expression/escape";
import {createNodeVisitor, TwingNodeVisitor} from "../node-visitor";
import {autoEscapeNodeType} from "../node/auto-escape";
import {blockFunctionNodeType} from "../node/expression/block-function";
import {methodCallNodeType} from "../node/expression/method-call";
import {parentFunctionNodeType} from "../node/expression/parent-function";
import {templateNodeType} from "../node/template";
import {TwingNullishCoalescingNode} from "../node/expression/nullish-coalescing";
export const createEscaperNodeVisitor = (): TwingNodeVisitor => {
const safes: Map<TwingBaseNode, boolean> = new Map();
@ -18,29 +14,33 @@ export const createEscaperNodeVisitor = (): TwingNodeVisitor => {
const analyze = (node: TwingBaseNode): boolean => {
let isSafe = safes.get(node);
if (isSafe === undefined) {
if (node.is("constant")) {
if (node.type === "constant") {
// constants are safe by definition
isSafe = true;
} else if (node.is(blockFunctionNodeType)) {
}
else if (node.type === "block_function") {
// blocks function is safe by definition
isSafe = true;
} else if (node.is(parentFunctionNodeType)) {
}
else if (node.type === "parent_function") {
// parent function is safe by definition
isSafe = true;
} else if (node.is(conditionalNodeType)) {
}
else if (node.type === "conditional") {
// intersect safeness of both operands
const {expr2, expr3} = node.children;
isSafe = intersectSafe(analyze(expr2), analyze(expr3));
} else {
isSafe = node.is(methodCallNodeType);
}
else {
isSafe = node.type === "method_call";
}
safes.set(node, isSafe);
}
return isSafe;
};
@ -60,14 +60,16 @@ export const createEscaperNodeVisitor = (): TwingNodeVisitor => {
return createEscapeNode(node, type);
};
const enterNode: TwingNodeVisitor["enterNode"] = (node) => {
if (node.is(templateNodeType)) {
const enterNode: TwingNodeVisitor["enterNode"] = (node: TwingNode) => {
if (node.type === "template") {
blocks = new Map();
} else if (node.is("auto_escape")) {
}
else if (node.type === "auto_escape") {
const {strategy} = node.attributes;
statusStack.push(strategy);
} else if (node.is("block")) {
}
else if (node.type === "block") {
const blockStatus = blocks.get(node.attributes.name);
statusStack.push(blockStatus !== undefined ? blockStatus : needEscaping());
@ -76,37 +78,39 @@ export const createEscaperNodeVisitor = (): TwingNodeVisitor => {
return node;
};
const leaveNode: TwingNodeVisitor["leaveNode"] = (node) => {
if (node.is(templateNodeType)) {
const leaveNode: TwingNodeVisitor["leaveNode"] = (node: TwingNode) => {
if (node.type === "template") {
blocks = new Map();
} else if (node.is("print")) {
}
else if (node.type === "print") {
const type = needEscaping();
if (type !== false) {
const {expression} = node.children;
if (expression.is("conditional") && shouldUnwrapConditional(expression)) {
if (type !== false) {
const expression = node.children.expression as TwingNode;
if ((expression.type === "conditional" || expression.type === "nullish_coalescing") && shouldUnwrapConditional(expression)) {
return createDoNode(unwrapConditional(expression, type), expression.line, expression.column, null);
}
return escapePrintNode(node, type);
}
}
if (node.is("auto_escape") || node.is("block")) {
if (node.type === "auto_escape" || node.type === "block") {
statusStack.pop();
if (node.is(autoEscapeNodeType)) {
if (node.type === "auto_escape") {
return node.children.body;
}
} else if (node.is("block_reference")) {
}
else if (node.type === "block_reference") {
blocks.set(node.attributes.name, needEscaping());
}
return node;
};
const shouldUnwrapConditional = (expression: TwingConditionalNode) => {
const shouldUnwrapConditional = (expression: TwingConditionalNode | TwingNullishCoalescingNode) => {
const {expr2, expr3} = expression.children;
const expr2IsSafe = isSafe(expr2);
@ -115,9 +119,13 @@ export const createEscaperNodeVisitor = (): TwingNodeVisitor => {
return expr2IsSafe !== expr3IsSafe;
};
const unwrapConditional = (expression: TwingConditionalNode, type: string): TwingConditionalNode => {
const unwrapConditional = (expression: TwingConditionalNode | TwingNullishCoalescingNode, type: string): TwingConditionalNode => {
// convert "echo a ? b : c" to "a ? echo b : echo c" recursively
let {expr1, expr2, expr3} = expression.children;
let {children} = expression;
let expr1 = children.expr1 as TwingNode;
let expr2 = children.expr2 as TwingNode;
let expr3 = children.expr3 as TwingNode;
const wrapPrintNodeExpression = (node: TwingPrintNode): TwingPrintNode => {
const {expression} = node.children;
@ -129,15 +137,17 @@ export const createEscaperNodeVisitor = (): TwingNodeVisitor => {
return createPrintNode(getEscapeNode(type, expression), node.line, node.column);
};
if (expr2.is("conditional") && shouldUnwrapConditional(expr2)) {
if (expr2.type === "conditional" && shouldUnwrapConditional(expr2)) {
expr2 = unwrapConditional(expr2, type);
} else {
}
else {
expr2 = wrapPrintNodeExpression(createPrintNode(expr2, expr2.line, expr2.column));
}
if (expr3.is("conditional") && shouldUnwrapConditional(expr3)) {
if (expr3.type === "conditional" && shouldUnwrapConditional(expr3)) {
expr3 = unwrapConditional(expr3, type);
} else {
}
else {
expr3 = wrapPrintNodeExpression(createPrintNode(expr3, expr3.line, expr3.column));
}
@ -146,14 +156,14 @@ export const createEscaperNodeVisitor = (): TwingNodeVisitor => {
const escapePrintNode = (node: TwingPrintNode, type: string) => {
const {expression} = node.children;
if (isSafe(expression)) {
return node;
}
return createPrintNode(getEscapeNode(type, expression), node.line, node.column);
};
const isSafe = (expression: TwingBaseNode): boolean => {
let safe = safes.get(expression);

View File

@ -1,11 +1,8 @@
import {TwingBaseNode, getChildren} from "../node";
import {TwingBaseNode, getChildren, TwingNode} from "../node";
import {createCheckSecurityNode} from "../node/check-security";
import {createCheckToStringNode} from "../node/check-to-string";
import {createNodeVisitor, TwingNodeVisitor} from "../node-visitor";
import {ArgumentsNode} from "../node/expression/arguments";
import {functionNodeType} from "../node/expression/call/function";
import {filterNodeType} from "../node/expression/call/filter";
import {templateNodeType} from "../node/template";
import type {TwingWrapperNode} from "../node/wrapper";
export const createSandboxNodeVisitor = (): TwingNodeVisitor => {
let tags: Map<string, TwingBaseNode>;
@ -14,14 +11,15 @@ export const createSandboxNodeVisitor = (): TwingNodeVisitor => {
let shouldWrap: boolean = true;
const enterNode: TwingNodeVisitor["enterNode"] = (node) => {
if (node.is(templateNodeType)) {
const enterNode: TwingNodeVisitor["enterNode"] = (node: TwingNode) => {
if (node.type === "template") {
tags = new Map();
filters = new Map();
functions = new Map();
return node;
} else {
}
else {
// look for tags
const {tag} = node;
@ -30,7 +28,7 @@ export const createSandboxNodeVisitor = (): TwingNodeVisitor => {
}
// look for filters
if (node.is(filterNodeType)) {
if (node.type === "filter") {
const {operatorName} = node.attributes;
if (!filters.has(operatorName)) {
@ -39,7 +37,7 @@ export const createSandboxNodeVisitor = (): TwingNodeVisitor => {
}
// look for functions
if (node.is(functionNodeType)) {
if (node.type === "function") {
const {operatorName} = node.attributes;
if (!functions.has(operatorName)) {
@ -48,35 +46,35 @@ export const createSandboxNodeVisitor = (): TwingNodeVisitor => {
}
// the .. operator is equivalent to the range() function
if (node.is("range") && !(functions.has('range'))) {
if (node.type === "range" && !(functions.has('range'))) {
functions.set('range', node);
}
if (node.is("print")) {
if (node.type === "print") {
shouldWrap = true;
wrapNode(node, "expression");
}
if (node.is("set")) {
if (node.type === "set") {
shouldWrap = true;
}
if (shouldWrap) {
if (node.is("concat")) {
if (node.type === "concatenate") {
wrapNode(node, "left");
wrapNode(node, "right");
}
if (node.is(filterNodeType)) {
if (node.type === "filter") {
wrapNode(node, "operand");
wrapArrayNode(node, "arguments");
}
if (node.is(functionNodeType)) {
if (node.type === "function") {
wrapArrayNode(node, "arguments");
}
if (node.is("escape")) {
if (node.type === "escape") {
wrapNode(node, "body");
}
}
@ -85,26 +83,27 @@ export const createSandboxNodeVisitor = (): TwingNodeVisitor => {
return node;
};
const leaveNode: TwingNodeVisitor["leaveNode"] = (node) => {
if (node.is(templateNodeType)) {
const leaveNode: TwingNodeVisitor["leaveNode"] = (node: TwingNode) => {
if (node.type === "template") {
node.children.securityCheck = createCheckSecurityNode(filters, tags, functions, node.line, node.column);
} else if (node.is("print") || node.is("set")) {
}
else if (node.type === "print" || node.type === "set") {
shouldWrap = false;
}
return node;
};
const wrapNode = <T extends TwingBaseNode>(node: T, name: keyof T["children"]) => {
const expression: TwingBaseNode = node.children[name as any];
if (expression.is("name") || expression.is("get_attribute")) {
node.children[name as any] = createCheckToStringNode(expression, expression.line, expression.column);
const wrapNode = <T extends TwingNode>(node: T, name: keyof T["children"]) => {
const expression: TwingNode = (node.children as any)[name];
if (expression.type === "name" || expression.type === "attribute_accessor") {
(node.children as any)[name] = createCheckToStringNode(expression, expression.line, expression.column);
}
};
const wrapArrayNode = <T extends TwingBaseNode>(node: T, name: keyof T["children"]) => {
const args: ArgumentsNode = node.children[name as any];
const wrapArrayNode = <T extends TwingNode>(node: T, name: keyof T["children"]) => {
const args: TwingWrapperNode = (node.children as any)[name]; // todo: check with TS team with we have to cast children as any
for (const [name] of getChildren(args)) {
wrapNode(args, name);
@ -113,6 +112,6 @@ export const createSandboxNodeVisitor = (): TwingNodeVisitor => {
return createNodeVisitor(
enterNode,
leaveNode
leaveNode
);
};

View File

@ -29,9 +29,8 @@ import type {TwingIfNode} from "./node/if";
import type {TwingMethodCallNode} from "./node/expression/method-call";
import type {TwingEscapeNode} from "./node/expression/escape";
import type {TwingApplyNode} from "./node/apply";
import type {TwingExecutionContext} from "./execution-context"; // todo: change
export type {TwingExecutionContext} from "./execution-context"; // todo: change
import type {TwingExecutionContext} from "./execution-context";
import type {TwingWrapperNode} from "./node/wrapper";
export type TwingNode =
| TwingApplyNode
@ -65,6 +64,7 @@ export type TwingNode =
| TwingTraitNode
| TwingVerbatimNode
| TwingWithNode
| TwingWrapperNode
;
export type TwingNodeType<T> = T extends TwingBaseNode<infer Type, any, any> ? Type : never;
@ -89,13 +89,9 @@ export interface TwingBaseNode<
readonly type: Type;
execute(executionContext: TwingExecutionContext): Promise<any>;
is<Type extends string>(type: Type): this is TwingNode & {
type: Type;
};
}
type KeysOf<T> = T extends T ? keyof T : never;
export type KeysOf<T> = T extends T ? keyof T : never;
export const getChildren = <
T extends TwingBaseNode
@ -121,7 +117,7 @@ export const createBaseNode = <
column: number = 0,
tag: string | null = null
): TwingBaseNode<Type, Attributes, Children> => {
const node: TwingBaseNode<Type, Attributes, Children> = {
return {
attributes,
children,
column,
@ -132,15 +128,12 @@ export const createBaseNode = <
execute: async (executionContext) => {
const output: Array<any> = [];
for (const [, child] of getChildren(node)) {
for (const [, child] of Object.entries(children)) {
output.push(await child.execute(executionContext));
}
return output;
},
is: (aType) => (aType as string) === node.type,
type
};
return node;
};

View File

@ -1,18 +1,16 @@
import {createBaseNode, TwingBaseNode, TwingBaseNodeAttributes, TwingBaseNodeChildren} from "../node";
import {createBaseNode, TwingBaseNode, TwingBaseNodeAttributes} from "../node";
import {getKeyValuePairs, TwingArrayNode} from "./expression/array";
import {createFilterNode} from "./expression/call/filter";
import {createConstantNode} from "./expression/constant";
export const applyNodeType = "apply";
export type TwingApplyNodeAttributes = TwingBaseNodeAttributes & {};
export type TwingApplyNodeChildren = TwingBaseNodeChildren & {
export type TwingApplyNodeChildren = {
body: TwingBaseNode;
filters: TwingArrayNode;
};
export interface TwingApplyNode extends TwingBaseNode<typeof applyNodeType, TwingApplyNodeAttributes, TwingApplyNodeChildren> {
export interface TwingApplyNode extends TwingBaseNode<"apply", TwingApplyNodeAttributes, TwingApplyNodeChildren> {
}
@ -22,17 +20,17 @@ export const createApplyNode = (
line: number,
column: number
): TwingApplyNode => {
const baseNode = createBaseNode(applyNodeType, {}, {
const baseNode = createBaseNode("apply", {}, {
body,
filters
}, line, column, 'apply');
const node: TwingApplyNode = {
const applyNode: TwingApplyNode = {
...baseNode,
execute: async (executionContext) => {
const {outputBuffer} = executionContext;
const {body, filters} = node.children;
const {line, column} = node;
const {body, filters} = applyNode.children;
const {line, column} = applyNode;
outputBuffer.start();
@ -56,5 +54,5 @@ export const createApplyNode = (
}
};
return node;
return applyNode;
};

View File

@ -1,25 +1,23 @@
import {TwingBaseNode, TwingBaseNodeAttributes, createBaseNode} from "../node";
import {EscapingStrategy} from "../escaping-strategy";
export const autoEscapeNodeType = "auto_escape";
import {TwingEscapingStrategy} from "../escaping-strategy";
export type TwingAutoEscapeNodeAttributes = TwingBaseNodeAttributes & {
strategy: EscapingStrategy | string | false;
strategy: TwingEscapingStrategy | string | false;
}
export interface TwingAutoEscapeNode extends TwingBaseNode<typeof autoEscapeNodeType, TwingAutoEscapeNodeAttributes, {
export interface TwingAutoEscapeNode extends TwingBaseNode<"auto_escape", TwingAutoEscapeNodeAttributes, {
body: TwingBaseNode;
}> {
}
export const createAutoEscapeNode = (
strategy: EscapingStrategy | string | false,
strategy: TwingEscapingStrategy | string | false,
body: TwingBaseNode,
line: number,
column: number,
tag: string
): TwingAutoEscapeNode => {
const baseNode = createBaseNode(autoEscapeNodeType, {
const baseNode = createBaseNode("auto_escape", {
strategy
}, {
body

View File

@ -1,12 +1,10 @@
import {TwingBaseNode, TwingBaseNodeAttributes, createBaseNode} from "../node";
export const blockNodeType = "block";
export type TwingBlockNodeAttributes = TwingBaseNodeAttributes & {
name: string;
};
export interface TwingBlockNode extends TwingBaseNode<typeof blockNodeType, TwingBlockNodeAttributes, {
export interface TwingBlockNode extends TwingBaseNode<"block", TwingBlockNodeAttributes, {
body: TwingBaseNode;
}> {
}
@ -18,11 +16,11 @@ export const createBlockNode = (
column: number,
tag: string | null = null
): TwingBlockNode => {
const baseNode = createBaseNode(blockNodeType, {name}, {body}, line, column, tag);
const baseNode = createBaseNode("block", {name}, {body}, line, column, tag);
const node: TwingBlockNode = {
const blockNode: TwingBlockNode = {
...baseNode
};
return node;
return blockNode;
};

View File

@ -9,13 +9,13 @@ import {
} from "../sandbox/security-not-allowed-tag-error";
import {TwingSandboxSecurityNotAllowedFunctionError} from "../sandbox/security-not-allowed-function-error";
export type CheckSecurityNodeAttributes = TwingBaseNodeAttributes & {
export type TwingCheckSecurityNodeAttributes = TwingBaseNodeAttributes & {
usedFilters: Map<string, TwingNode | string>;
usedTags: Map<string, TwingNode | string>;
usedFunctions: Map<string, TwingNode | string>;
};
export interface TwingCheckSecurityNode extends TwingBaseNode<"check_security", CheckSecurityNodeAttributes> {
export interface TwingCheckSecurityNode extends TwingBaseNode<"check_security", TwingCheckSecurityNodeAttributes> {
}
export const createCheckSecurityNode = (

View File

@ -11,26 +11,26 @@ import {getTraceableMethod} from "../helpers/traceable-method";
* or {{ random(article) }}.
*/
export interface TwingCheckToStringNode extends TwingBaseNode<"check_to_string", TwingBaseNodeAttributes, {
expr: TwingBaseExpressionNode;
value: TwingBaseExpressionNode;
}> {
}
export const createCheckToStringNode = (
expression: TwingBaseExpressionNode,
value: TwingBaseExpressionNode,
line: number,
column: number
): TwingCheckToStringNode => {
const baseNode = createBaseNode("check_to_string", {}, {
expr: expression
value
}, line, column);
return {
...baseNode,
execute: (executionContext) => {
const {template, sandboxed} = executionContext;
const {expr} = baseNode.children;
const {value: valueNode} = baseNode.children;
return expr.execute(executionContext)
return valueNode.execute(executionContext)
.then((value) => {
if (sandboxed) {
const assertToStringAllowed = getTraceableMethod((value: any) => {
@ -43,7 +43,7 @@ export const createCheckToStringNode = (
}
return Promise.resolve(value);
}, expr.line, expr.column, template.name)
}, valueNode.line, valueNode.column, template.name)
return assertToStringAllowed(value);
}

View File

@ -2,32 +2,32 @@ import {TwingBaseNode, TwingBaseNodeAttributes, createBaseNode} from "../node";
import {TwingBaseExpressionNode} from "./expression";
export interface TwingDeprecatedNode extends TwingBaseNode<"deprecated", TwingBaseNodeAttributes, {
expr: TwingBaseExpressionNode;
message: TwingBaseExpressionNode;
}> {
}
export const createDeprecatedNode = (
expr: TwingBaseExpressionNode,
message: TwingBaseExpressionNode,
line: number,
column: number,
tag: string
): TwingDeprecatedNode => {
const baseNode = createBaseNode("deprecated", {}, {
expr
message
}, line, column, tag);
const node: TwingDeprecatedNode = {
const deprecatedNode: TwingDeprecatedNode = {
...baseNode,
execute: (executionContext) => {
const {template} = executionContext;
const {expr} = node.children;
const {message} = deprecatedNode.children;
return expr.execute(executionContext)
return message.execute(executionContext)
.then((message) => {
console.warn(`${message} ("${template.name}" at line ${node.line}, column ${node.column})`);
console.warn(`${message} ("${template.name}" at line ${deprecatedNode.line}, column ${deprecatedNode.column})`);
});
}
};
return node;
return deprecatedNode;
};

View File

@ -8,22 +8,22 @@ import type {TwingBaseExpressionNode} from "./expression";
* {% do 1 + 2 %}
*/
export interface TwingDoNode extends TwingBaseNode<"do", TwingBaseNodeAttributes, {
expr: TwingBaseExpressionNode;
body: TwingBaseExpressionNode;
}> {
}
export const createDoNode = (
expr: TwingBaseExpressionNode,
body: TwingBaseExpressionNode,
line: number,
column: number,
tag: string | null
): TwingDoNode => {
const baseNode = createBaseNode("do", {}, {
expr
body
}, line, column, tag);
return {
...baseNode,
execute: baseNode.children.expr.execute
execute: baseNode.children.body.execute
};
};

View File

@ -15,11 +15,9 @@ import type {TwingAttributeAccessorNode} from "./expression/attribute-accessor";
import type {TwingMethodCallNode} from "./expression/method-call";
import type {TwingNullishCoalescingNode} from "./expression/nullish-coalescing";
import type {TwingParentFunctionNode} from "./expression/parent-function";
import type {ArgumentsNode} from "./expression/arguments";
import type {TwingSpreadNode} from "./expression/spread";
export type TwingExpressionNode =
| ArgumentsNode
| TwingArrayNode
| TwingArrowFunctionNode
| TwingAssignmentNode
@ -41,11 +39,10 @@ export type TwingExpressionNode =
export type TwingBaseExpressionNodeAttributes = TwingBaseNodeAttributes;
// todo: this is a base node, no need for a type
export type TwingBaseExpressionNode<
Type extends string = any,
AdditionalAttributes extends TwingBaseExpressionNodeAttributes = TwingBaseExpressionNodeAttributes,
AdditionalChildren extends TwingBaseNodeChildren = TwingBaseNodeChildren,
> = TwingBaseNode<Type, TwingBaseExpressionNodeAttributes & AdditionalAttributes, TwingBaseNodeChildren & AdditionalChildren>;
Children extends TwingBaseNodeChildren = TwingBaseNodeChildren,
> = TwingBaseNode<Type, TwingBaseExpressionNodeAttributes & AdditionalAttributes, Children>;
export const createBaseExpressionNode = createBaseNode;

View File

@ -1,21 +0,0 @@
import type {TwingBaseExpressionNode} from "../expression";
import {createBaseExpressionNode} from "../expression";
import type {TwingBaseNodeAttributes} from "../../node";
export interface ArgumentsNode<T extends TwingBaseExpressionNode = TwingBaseExpressionNode> extends TwingBaseExpressionNode<"arguments", TwingBaseNodeAttributes, Record<string, T>> {
}
// todo: check if needed - probably array node can be used instead
export const createArgumentsNode = <T extends TwingBaseExpressionNode>(
children: Record<string, T>,
line: number,
column: number
): ArgumentsNode<T> => {
const baseNode = createBaseExpressionNode("arguments", {}, children, line, column);
const node: ArgumentsNode<T> = {
...baseNode
};
return node;
};

View File

@ -5,7 +5,7 @@ import {
} from "../expression";
import {TwingConstantNode, createConstantNode} from "./constant";
import {pushToRecord} from "../../helpers/record";
import {spreadNodeType} from "./spread";
import type {TwingNode} from "../../node";
const array_chunk = require('locutus/php/array/array_chunk');
@ -76,18 +76,18 @@ export const createArrayNode = (
execute: async (executionContext) => {
const keyValuePairs = getKeyValuePairs(baseNode);
const array: Array<any> = [];
for (const {value: valueNode} of keyValuePairs) {
const value = await valueNode.execute(executionContext);
if (valueNode.is(spreadNodeType)) {
if ((valueNode as TwingNode).type === "spread") {
array.push(...value);
}
else {
array.push(value);
}
}
return array;
}
};

View File

@ -4,20 +4,20 @@ import type {TwingAssignmentNode} from "./assignment";
import {createBaseExpressionNode} from "../expression";
export interface TwingArrowFunctionNode extends TwingBaseExpressionNode<"arrow_function", TwingBaseExpressionNodeAttributes, {
expr: TwingBaseExpressionNode;
body: TwingBaseExpressionNode;
names: TwingBaseNode<any, any, Record<string, TwingAssignmentNode>>;
}> {
}
export const createArrowFunctionNode = (
expr: TwingBaseExpressionNode,
body: TwingBaseExpressionNode,
names: TwingBaseNode<any, any, Record<any, TwingAssignmentNode>>,
line: number,
column: number
): TwingArrowFunctionNode => {
const baseNode = createBaseExpressionNode("arrow_function", {}, {
expr,
body,
names
}, line, column);
@ -25,7 +25,7 @@ export const createArrowFunctionNode = (
...baseNode,
execute: (executionContext) => {
const {context} = executionContext;
const {expr} = baseNode.children;
const {body} = baseNode.children;
const assignmentNodes = Object.values(baseNode.children.names.children);
return Promise.resolve((...functionArgs: Array<any>): Promise<any> => {
@ -39,7 +39,7 @@ export const createArrowFunctionNode = (
index++;
}
return expr.execute(executionContext);
return body.execute(executionContext);
});
}
};

View File

@ -1,13 +1,11 @@
import {createBaseNode, TwingBaseNode} from "../../node";
import {TwingBaseExpressionNodeAttributes} from "../expression";
export const assignmentNodeType = "assign_name";
export type TwingAssignmentNodeAttributes = TwingBaseExpressionNodeAttributes & {
name: string;
};
export interface TwingAssignmentNode extends TwingBaseNode<typeof assignmentNodeType, TwingAssignmentNodeAttributes> {
export interface TwingAssignmentNode extends TwingBaseNode<"assignment", TwingAssignmentNodeAttributes> {
}
// todo: probably a useless node
@ -16,16 +14,16 @@ export const createAssignmentNode = (
line: number,
column: number
): TwingAssignmentNode => {
const baseNode = createBaseNode(assignmentNodeType, {
const baseNode = createBaseNode("assignment", {
name
}, {}, line, column);
const node: TwingAssignmentNode = {
const assignmentNode: TwingAssignmentNode = {
...baseNode,
execute: () => {
return Promise.resolve(node.attributes.name);
return Promise.resolve(assignmentNode.attributes.name);
}
};
return node;
return assignmentNode;
};

View File

@ -1,38 +1,38 @@
import {
TwingBaseExpressionNode,
TwingBaseExpressionNodeAttributes,
createBaseExpressionNode
createBaseExpressionNode, TwingExpressionNode
} from "../expression";
import {getAttribute} from "../../helpers/get-attribute";
import {getTraceableMethod} from "../../helpers/traceable-method";
export type TwingGetAttributeCallType = "any" | "array" | "method";
export type TwingAttributeAccessorCallType = "any" | "array" | "method";
export type TwingAttributeAccessorNodeAttributes = TwingBaseExpressionNodeAttributes & {
isOptimizable: boolean;
type: TwingGetAttributeCallType;
type: TwingAttributeAccessorCallType;
shouldIgnoreStrictCheck?: boolean;
shouldTestExistence: boolean;
};
export type TwingAttributeAccessorNodeChildren = {
target: TwingBaseExpressionNode;
attribute: TwingBaseExpressionNode;
arguments: TwingBaseExpressionNode;
target: TwingExpressionNode;
attribute: TwingExpressionNode;
arguments: TwingExpressionNode;
};
export interface TwingAttributeAccessorNode extends TwingBaseExpressionNode<"get_attribute", TwingAttributeAccessorNodeAttributes, TwingAttributeAccessorNodeChildren> {
export interface TwingAttributeAccessorNode extends TwingBaseExpressionNode<"attribute_accessor", TwingAttributeAccessorNodeAttributes, TwingAttributeAccessorNodeChildren> {
}
export const createAttributeAccessorNode = (
target: TwingBaseExpressionNode,
attribute: TwingBaseExpressionNode,
methodArguments: TwingBaseExpressionNode,
type: TwingGetAttributeCallType,
target: TwingExpressionNode,
attribute: TwingExpressionNode,
methodArguments: TwingExpressionNode,
type: TwingAttributeAccessorCallType,
line: number,
column: number
): TwingAttributeAccessorNode => {
const baseNode = createBaseExpressionNode("get_attribute", {
const baseNode = createBaseExpressionNode("attribute_accessor", {
isOptimizable: true,
type,
shouldTestExistence: false
@ -42,19 +42,19 @@ export const createAttributeAccessorNode = (
arguments: methodArguments
}, line, column);
const node: TwingAttributeAccessorNode = {
const attributeAccessorNode: TwingAttributeAccessorNode = {
...baseNode,
execute: (executionContext) => {
const {template, sandboxed, isStrictVariables} = executionContext;
const {target, attribute, arguments: methodArguments} = node.children;
const {type, shouldIgnoreStrictCheck, shouldTestExistence} = node.attributes;
const {target, attribute, arguments: methodArguments} = attributeAccessorNode.children;
const {type, shouldIgnoreStrictCheck, shouldTestExistence} = attributeAccessorNode.attributes;
return Promise.all([
target.execute(executionContext),
attribute.execute(executionContext),
methodArguments.execute(executionContext)
]).then(([target, attribute, methodArguments]) => {
const traceableGetAttribute = getTraceableMethod(getAttribute, node.line, node.column, template.name);
const traceableGetAttribute = getTraceableMethod(getAttribute, attributeAccessorNode.line, attributeAccessorNode.column, template.name);
return traceableGetAttribute(
template,
@ -71,13 +71,13 @@ export const createAttributeAccessorNode = (
}
};
return node;
return attributeAccessorNode;
};
export const cloneGetAttributeNode = (
node: TwingAttributeAccessorNode
attributeAccessorNode: TwingAttributeAccessorNode
): TwingAttributeAccessorNode => {
const {children, attributes, line, column} = node;
const {children, attributes, line, column} = attributeAccessorNode;
const {arguments: methodArguments, attribute, target} = children;
const {type} = attributes;

View File

@ -1,5 +1,5 @@
import type {TwingBaseExpressionNode, TwingBaseExpressionNodeAttributes} from "../expression";
import type {TwingNode, TwingExecutionContext, TwingNodeType} from "../../node";
import type {TwingNodeType} from "../../node";
import type {TwingAddNode} from "./binary/add";
import type {TwingAndNode} from "./binary/and";
import type {TwingBitwiseAndNode} from "./binary/bitwise-and";
@ -29,6 +29,7 @@ import {createBaseExpressionNode} from "../expression";
import type {TwingSpaceshipNode} from "./binary/spaceship";
import type {TwingHasEveryNode} from "./binary/has-every";
import type {TwingHasSomeNode} from "./binary/has-some";
import type {TwingExecutionContext} from "../../execution-context";
export type TwingBinaryNode =
| TwingAddNode
@ -62,8 +63,8 @@ export type TwingBinaryNode =
;
export interface TwingBaseBinaryNode<Type extends string> extends TwingBaseExpressionNode<Type, TwingBaseExpressionNodeAttributes, {
left: TwingNode;
right: TwingNode;
left: TwingBaseExpressionNode;
right: TwingBaseExpressionNode;
}> {
}

View File

@ -1,12 +1,10 @@
import type {TwingBaseBinaryNode} from "../binary";
import {createBinaryNodeFactory} from "../binary";
export const addNodeType = "add";
export interface TwingAddNode extends TwingBaseBinaryNode<typeof addNodeType> {
export interface TwingAddNode extends TwingBaseBinaryNode<"add"> {
}
export const createAddNode = createBinaryNodeFactory<TwingAddNode>(addNodeType, {
export const createAddNode = createBinaryNodeFactory<TwingAddNode>("add", {
execute: async (left, right, executionContext) => {
return await left.execute(executionContext) + await right.execute(executionContext);
}

View File

@ -1,12 +1,10 @@
import type {TwingBaseBinaryNode} from "../binary";
import {createBinaryNodeFactory} from "../binary";
export const andNodeType = "and";
export interface TwingAndNode extends TwingBaseBinaryNode<typeof andNodeType> {
export interface TwingAndNode extends TwingBaseBinaryNode<"and"> {
}
export const createAndNode = createBinaryNodeFactory<TwingAndNode>(andNodeType, {
export const createAndNode = createBinaryNodeFactory<TwingAndNode>("and", {
execute: async (left, right, executionContext) => {
return !!(await left.execute(executionContext) && await right.execute(executionContext));
}

View File

@ -1,11 +1,9 @@
import {TwingBaseBinaryNode, createBinaryNodeFactory} from "../binary";
export const bitwiseAndNodeType = "bitwise_and";
export interface TwingBitwiseAndNode extends TwingBaseBinaryNode<typeof bitwiseAndNodeType> {
export interface TwingBitwiseAndNode extends TwingBaseBinaryNode<"bitwise_and"> {
}
export const createBitwiseAndNode = createBinaryNodeFactory<TwingBitwiseAndNode>(bitwiseAndNodeType, {
export const createBitwiseAndNode = createBinaryNodeFactory<TwingBitwiseAndNode>("bitwise_and", {
execute: async (left, right, executionContext) => {
return await left.execute(executionContext) & await right.execute(executionContext);
}

View File

@ -1,12 +1,10 @@
import type {TwingBaseBinaryNode} from "../binary";
import {createBinaryNodeFactory} from "../binary";
export const bitwiseOrNodeType = "bitwise_or";
export interface TwingBitwiseOrNode extends TwingBaseBinaryNode<typeof bitwiseOrNodeType> {
export interface TwingBitwiseOrNode extends TwingBaseBinaryNode<"bitwise_or"> {
}
export const createBitwiseOrNode = createBinaryNodeFactory<TwingBitwiseOrNode>(bitwiseOrNodeType, {
export const createBitwiseOrNode = createBinaryNodeFactory<TwingBitwiseOrNode>("bitwise_or", {
execute: async (left, right, executionContext) => {
return await left.execute(executionContext) | await right.execute(executionContext);
}

View File

@ -1,12 +1,10 @@
import type {TwingBaseBinaryNode} from "../binary";
import {createBinaryNodeFactory} from "../binary";
export const bitwiseXorNodeType = "bitwise_xor";
export interface TwingBitwiseXorNode extends TwingBaseBinaryNode<typeof bitwiseXorNodeType> {
export interface TwingBitwiseXorNode extends TwingBaseBinaryNode<"bitwise_xor"> {
}
export const createBitwiseXorNode = createBinaryNodeFactory<TwingBitwiseXorNode>(bitwiseXorNodeType, {
export const createBitwiseXorNode = createBinaryNodeFactory<TwingBitwiseXorNode>("bitwise_xor", {
execute: async (left, right, executionContext) => {
return await left.execute(executionContext) ^ await right.execute(executionContext);
}

View File

@ -2,12 +2,10 @@ import type {TwingBaseBinaryNode} from "../binary";
import {createBinaryNodeFactory} from "../binary";
import {concatenate} from "../../../helpers/concatenate";
export const concatenateNodeTYpe = "concat";
export interface TwingConcatenateNode extends TwingBaseBinaryNode<typeof concatenateNodeTYpe> {
export interface TwingConcatenateNode extends TwingBaseBinaryNode<"concatenate"> {
}
export const createConcatenateNode = createBinaryNodeFactory<TwingConcatenateNode>(concatenateNodeTYpe, {
export const createConcatenateNode = createBinaryNodeFactory<TwingConcatenateNode>("concatenate", {
execute: async (left, right, executionContext) => {
const leftValue = await left.execute(executionContext);
const rightValue = await right.execute(executionContext);

View File

@ -1,12 +1,10 @@
import type {TwingBaseBinaryNode} from "../binary";
import {createBinaryNodeFactory} from "../binary";
export const divideAndFloorNodeType = "floor_div";
export interface TwingDivideAndFloorNode extends TwingBaseBinaryNode<typeof divideAndFloorNodeType> {
export interface TwingDivideAndFloorNode extends TwingBaseBinaryNode<"divide_and_floor"> {
}
export const createDivideAndFloorNode = createBinaryNodeFactory<TwingDivideAndFloorNode>(divideAndFloorNodeType, {
export const createDivideAndFloorNode = createBinaryNodeFactory<TwingDivideAndFloorNode>("divide_and_floor", {
execute: async (left, right, executionContext) => {
return Math.floor(await left.execute(executionContext) / await right.execute(executionContext));
}

View File

@ -1,11 +1,9 @@
import {TwingBaseBinaryNode, createBinaryNodeFactory} from "../binary";
export const divideNodeType = "div";
export interface TwingDivideNode extends TwingBaseBinaryNode<typeof divideNodeType> {
export interface TwingDivideNode extends TwingBaseBinaryNode<"divide"> {
}
export const createDivideNode = createBinaryNodeFactory<TwingDivideNode>(divideNodeType, {
export const createDivideNode = createBinaryNodeFactory<TwingDivideNode>("divide", {
execute: async (left, right, executionContext) => {
return await left.execute(executionContext) / await right.execute(executionContext);
}

View File

@ -1,13 +1,11 @@
import {TwingBaseBinaryNode, createBinaryNodeFactory} from "../binary";
export const endsWithNodeType = "ends_with";
export interface TwingEndsWithNode extends TwingBaseBinaryNode<typeof endsWithNodeType> {
export interface TwingEndsWithNode extends TwingBaseBinaryNode<"ends_with"> {
}
export const createEndsWithNode = createBinaryNodeFactory<TwingEndsWithNode>(
endsWithNodeType,
"ends_with",
{
execute: async (left, right, executionContext) => {
const leftValue = await left.execute(executionContext);

View File

@ -1,14 +1,12 @@
import {TwingBaseBinaryNode, createBinaryNodeFactory} from "../binary";
import {every, isAMapLike} from "../../../helpers/map-like";
export const hasEveryNodeType = "has_every";
export interface TwingHasEveryNode extends TwingBaseBinaryNode<typeof hasEveryNodeType> {
export interface TwingHasEveryNode extends TwingBaseBinaryNode<"has_every"> {
}
export const createHasEveryNode = createBinaryNodeFactory<TwingHasEveryNode>(
hasEveryNodeType,
"has_every",
{
execute: async (left, right, executionContext) => {
const leftValue = await left.execute(executionContext);

View File

@ -1,19 +1,17 @@
import {TwingBaseBinaryNode, createBinaryNodeFactory} from "../binary";
import {isAMapLike, some} from "../../../helpers/map-like";
export const hasSomeNodeType = "has_some";
export interface TwingHasSomeNode extends TwingBaseBinaryNode<typeof hasSomeNodeType> {
export interface TwingHasSomeNode extends TwingBaseBinaryNode<"has_some"> {
}
export const createHasSomeNode = createBinaryNodeFactory<TwingHasSomeNode>(
hasSomeNodeType,
"has_some",
{
execute: async (left, right, executionContext) => {
const leftValue = await left.execute(executionContext);
const rightValue = await right.execute(executionContext);
if (typeof rightValue !== "function") {
return Promise.resolve(false);
}

View File

@ -1,10 +1,10 @@
import {TwingBaseBinaryNode, createBinaryNodeFactory} from "../binary";
import {compare} from "../../../helpers/compare";
export interface TwingIsEqualToNode extends TwingBaseBinaryNode<"equals"> {
export interface TwingIsEqualToNode extends TwingBaseBinaryNode<"is_equal_to"> {
}
export const createIsEqualNode = createBinaryNodeFactory<TwingIsEqualToNode>("equals", {
export const createIsEqualNode = createBinaryNodeFactory<TwingIsEqualToNode>("is_equal_to", {
execute: async (left, right, executionContext) => {
const leftValue = await left.execute(executionContext);
const rightValue = await right.execute(executionContext);

View File

@ -1,9 +1,9 @@
import {TwingBaseBinaryNode, createBinaryNodeFactory} from "../binary";
export interface TwingIsGreaterThanOrEqualToNode extends TwingBaseBinaryNode<"greater_equal"> {
export interface TwingIsGreaterThanOrEqualToNode extends TwingBaseBinaryNode<"is_greater_than_or_equal_to"> {
}
export const createIsGreaterThanOrEqualToNode = createBinaryNodeFactory<TwingIsGreaterThanOrEqualToNode>("greater_equal", {
export const createIsGreaterThanOrEqualToNode = createBinaryNodeFactory<TwingIsGreaterThanOrEqualToNode>("is_greater_than_or_equal_to", {
execute: async (left, right, executionContext) => {
return await left.execute(executionContext) >= await right.execute(executionContext);
}

View File

@ -1,9 +1,9 @@
import {TwingBaseBinaryNode, createBinaryNodeFactory} from "../binary";
export interface TwingIsGreaterThanNode extends TwingBaseBinaryNode<"greater"> {
export interface TwingIsGreaterThanNode extends TwingBaseBinaryNode<"is_greater_than"> {
}
export const createIsGreaterThanNode = createBinaryNodeFactory<TwingIsGreaterThanNode>("greater", {
export const createIsGreaterThanNode = createBinaryNodeFactory<TwingIsGreaterThanNode>("is_greater_than", {
execute: async (left, right, executionContext) => {
return await left.execute(executionContext) > await right.execute(executionContext);
}

View File

@ -1,10 +1,10 @@
import {TwingBaseBinaryNode, createBinaryNodeFactory} from "../binary";
import {isIn} from "../../../helpers/is-in";
export interface TwingIsInNode extends TwingBaseBinaryNode<"in"> {
export interface TwingIsInNode extends TwingBaseBinaryNode<"is_in"> {
}
export const createIsInNode = createBinaryNodeFactory<TwingIsInNode>("in", {
export const createIsInNode = createBinaryNodeFactory<TwingIsInNode>("is_in", {
execute: async (left, right, executionContext) => {
return isIn(await left.execute(executionContext), await right.execute(executionContext));
}

View File

@ -1,9 +1,9 @@
import {TwingBaseBinaryNode, createBinaryNodeFactory} from "../binary";
export interface TwingIsLessThanOrEqualToNode extends TwingBaseBinaryNode<"less_equal"> {
export interface TwingIsLessThanOrEqualToNode extends TwingBaseBinaryNode<"is_less_than_or_equal_to"> {
}
export const createIsLessThanOrEqualToNode = createBinaryNodeFactory<TwingIsLessThanOrEqualToNode>("less_equal", {
export const createIsLessThanOrEqualToNode = createBinaryNodeFactory<TwingIsLessThanOrEqualToNode>("is_less_than_or_equal_to", {
execute: async (left, right, executionContext) => {
return await left.execute(executionContext) <= await right.execute(executionContext);
}

View File

@ -1,9 +1,9 @@
import {TwingBaseBinaryNode, createBinaryNodeFactory} from "../binary";
export interface TwingIsLessThanNode extends TwingBaseBinaryNode<"less"> {
export interface TwingIsLessThanNode extends TwingBaseBinaryNode<"is_less_than"> {
}
export const createIsLessThanNode = createBinaryNodeFactory<TwingIsLessThanNode>("less", {
export const createIsLessThanNode = createBinaryNodeFactory<TwingIsLessThanNode>("is_less_than", {
execute: async (left, right, executionContext) => {
return await left.execute(executionContext) < await right.execute(executionContext);
}

View File

@ -1,10 +1,10 @@
import {TwingBaseBinaryNode, createBinaryNodeFactory} from "../binary";
import {compare} from "../../../helpers/compare";
export interface TwingIsNotEqualToNode extends TwingBaseBinaryNode<"not_equal"> {
export interface TwingIsNotEqualToNode extends TwingBaseBinaryNode<"is_not_equal_to"> {
}
export const createIsNotEqualToNode = createBinaryNodeFactory<TwingIsNotEqualToNode>("not_equal", {
export const createIsNotEqualToNode = createBinaryNodeFactory<TwingIsNotEqualToNode>("is_not_equal_to", {
execute: async (left, right, executionContext) => {
return Promise.resolve(!compare(await left.execute(executionContext), await right.execute(executionContext)))
}

View File

@ -1,10 +1,10 @@
import {TwingBaseBinaryNode, createBinaryNodeFactory} from "../binary";
import {isIn} from "../../../helpers/is-in";
export interface TwingIsNotInNode extends TwingBaseBinaryNode<"not_in"> {
export interface TwingIsNotInNode extends TwingBaseBinaryNode<"is_not_in"> {
}
export const createIsNotInNode = createBinaryNodeFactory<TwingIsNotInNode>("not_in", {
export const createIsNotInNode = createBinaryNodeFactory<TwingIsNotInNode>("is_not_in", {
execute: async (left, right, executionContext) => {
return Promise.resolve(!isIn(await left.execute(executionContext), await right.execute(executionContext)))
}

View File

@ -1,9 +1,9 @@
import {TwingBaseBinaryNode, createBinaryNodeFactory} from "../binary";
export interface TwingModuloNode extends TwingBaseBinaryNode<"mod"> {
export interface TwingModuloNode extends TwingBaseBinaryNode<"modulo"> {
}
export const createModuloNode = createBinaryNodeFactory<TwingModuloNode>("mod", {
export const createModuloNode = createBinaryNodeFactory<TwingModuloNode>("modulo", {
execute: async (left, right, executionContext) => {
return await left.execute(executionContext) % await right.execute(executionContext);
}

View File

@ -1,9 +1,9 @@
import {TwingBaseBinaryNode, createBinaryNodeFactory} from "../binary";
export interface TwingMultiplyNode extends TwingBaseBinaryNode<"mul"> {
export interface TwingMultiplyNode extends TwingBaseBinaryNode<"multiply"> {
}
export const createMultiplyNode = createBinaryNodeFactory<TwingMultiplyNode>("mul", {
export const createMultiplyNode = createBinaryNodeFactory<TwingMultiplyNode>("multiply", {
execute: async (left, right, executionContext) => {
return await left.execute(executionContext) * await right.execute(executionContext);
}

View File

@ -2,12 +2,10 @@ import type {TwingBaseBinaryNode} from "../binary";
import {createBinaryNodeFactory} from "../binary";
import {compare} from "../../../helpers/compare";
export const spaceshipNodeType = "spaceship";
export interface TwingSpaceshipNode extends TwingBaseBinaryNode<typeof spaceshipNodeType> {
export interface TwingSpaceshipNode extends TwingBaseBinaryNode<"spaceship"> {
}
export const createSpaceshipNode = createBinaryNodeFactory<TwingSpaceshipNode>(spaceshipNodeType, {
export const createSpaceshipNode = createBinaryNodeFactory<TwingSpaceshipNode>("spaceship", {
execute: async (left, right, executionContext) => {
const leftValue = await left.execute(executionContext);
const rightValue = await right.execute(executionContext);

View File

@ -1,9 +1,9 @@
import {TwingBaseBinaryNode, createBinaryNodeFactory} from "../binary";
export interface TwingSubtractNode extends TwingBaseBinaryNode<"sub"> {
export interface TwingSubtractNode extends TwingBaseBinaryNode<"subtract"> {
}
export const createSubtractNode = createBinaryNodeFactory<TwingSubtractNode>("sub", {
export const createSubtractNode = createBinaryNodeFactory<TwingSubtractNode>("subtract", {
execute: async (left, right, executionContext) => {
return await left.execute(executionContext) - await right.execute(executionContext);
}

View File

@ -3,18 +3,16 @@ import {TwingBaseNode} from "../../node";
import {TwingTemplate} from "../../template";
import {getTraceableMethod} from "../../helpers/traceable-method";
type TwingBlockFunctionNodeAttributes = TwingBaseExpressionNodeAttributes & {
export type TwingBlockFunctionNodeAttributes = TwingBaseExpressionNodeAttributes & {
shouldTestExistence: boolean;
};
type TwingBlockFunctionNodeChildren = {
export type TwingBlockFunctionNodeChildren = {
name: TwingBaseNode;
template?: TwingBaseNode;
};
export const blockFunctionNodeType = "block_function";
export interface TwingBlockFunctionNode extends TwingBaseExpressionNode<typeof blockFunctionNodeType, TwingBlockFunctionNodeAttributes, TwingBlockFunctionNodeChildren> {
export interface TwingBlockFunctionNode extends TwingBaseExpressionNode<"block_function", TwingBlockFunctionNodeAttributes, TwingBlockFunctionNodeChildren> {
}
export const createBlockFunctionNode = (
@ -32,15 +30,15 @@ export const createBlockFunctionNode = (
children.template = template;
}
const baseNode = createBaseExpressionNode(blockFunctionNodeType, {
const baseNode = createBaseExpressionNode("block_function", {
shouldTestExistence: false
}, children, line, column, tag);
const node: TwingBlockFunctionNode = {
const blockFunctionNode: TwingBlockFunctionNode = {
...baseNode,
execute: async (executionContext) => {
const {template, context, outputBuffer, blocks, sandboxed, sourceMapRuntime} = executionContext;
const {template: templateNode, name: blockNameNode} = node.children;
const {template: templateNode, name: blockNameNode} = blockFunctionNode.children;
const blockName = await blockNameNode.execute(executionContext);
@ -63,12 +61,12 @@ export const createBlockFunctionNode = (
return resolveTemplate
.then<Promise<boolean | string>>((executionContextOfTheBlock) => {
if (node.attributes.shouldTestExistence) {
const hasBlock = getTraceableMethod(executionContextOfTheBlock.hasBlock, node.line, node.column, template.name);
if (blockFunctionNode.attributes.shouldTestExistence) {
const hasBlock = getTraceableMethod(executionContextOfTheBlock.hasBlock, blockFunctionNode.line, blockFunctionNode.column, template.name);
return hasBlock(blockName, context.clone(), outputBuffer, blocks, sandboxed);
} else {
const renderBlock = getTraceableMethod(executionContextOfTheBlock.renderBlock, node.line, node.column, template.name);
const renderBlock = getTraceableMethod(executionContextOfTheBlock.renderBlock, blockFunctionNode.line, blockFunctionNode.column, template.name);
if (templateNode) {
return renderBlock(blockName, context.clone(), outputBuffer, new Map(), false, sandboxed, sourceMapRuntime);
@ -80,16 +78,16 @@ export const createBlockFunctionNode = (
}
};
return node;
return blockFunctionNode;
};
export const cloneBlockReferenceExpressionNode = (
node: TwingBlockFunctionNode
blockFunctionNode: TwingBlockFunctionNode
): TwingBlockFunctionNode => {
return createBlockFunctionNode(
node.children.name,
node.children.template || null,
node.line,
node.column
blockFunctionNode.children.name,
blockFunctionNode.children.template || null,
blockFunctionNode.line,
blockFunctionNode.column
);
};

View File

@ -22,9 +22,7 @@ export type TwingCallNode =
| TwingTestNode
;
type CallType = "filter" | "function" | "test";
type TwingBaseCallNodeAttributes = TwingBaseExpressionNodeAttributes & {
export type TwingBaseCallNodeAttributes = TwingBaseExpressionNodeAttributes & {
operatorName: string;
};
@ -33,11 +31,11 @@ export type TwingBaseCallNodeChildren = {
operand?: TwingBaseNode;
};
export interface TwingBaseCallNode<Type extends CallType> extends TwingBaseExpressionNode<Type, TwingBaseCallNodeAttributes, TwingBaseCallNodeChildren> {
export interface TwingBaseCallNode<Type extends "filter" | "function" | "test"> extends TwingBaseExpressionNode<Type, TwingBaseCallNodeAttributes, TwingBaseCallNodeChildren> {
}
export const createBaseCallNode = <Type extends CallType>(
export const createBaseCallNode = <Type extends "filter" | "function" | "test">(
type: Type,
operatorName: string,
operand: TwingBaseNode | null,
@ -166,11 +164,11 @@ export const createBaseCallNode = <Type extends CallType>(
return arguments_;
}
const node: TwingBaseCallNode<typeof type> = {
const baseCallNode: TwingBaseCallNode<typeof type> = {
...baseNode,
execute: async (executionContext) => {
const {template} = executionContext
const {operatorName} = node.attributes;
const {operatorName} = baseCallNode.attributes;
let callableWrapper: TwingCallableWrapper | null;
@ -194,7 +192,7 @@ export const createBaseCallNode = <Type extends CallType>(
throw createRuntimeError(`Unknown ${type} "${operatorName}".`, baseNode);
}
const {operand, arguments: callArguments} = node.children;
const {operand, arguments: callArguments} = baseCallNode.children;
const argumentNodes = getArguments(
callArguments,
@ -216,11 +214,11 @@ export const createBaseCallNode = <Type extends CallType>(
actualArguments.push(...providedArguments);
const traceableCallable = getTraceableMethod(callableWrapper.callable, node.line, node.column, template.name);
const traceableCallable = getTraceableMethod(callableWrapper.callable, baseCallNode.line, baseCallNode.column, template.name);
return traceableCallable(executionContext, ...actualArguments);
}
};
return node;
return baseCallNode;
};

View File

@ -2,9 +2,7 @@ import {TwingBaseNode} from "../../../node";
import {TwingBaseCallNode, createBaseCallNode} from "../call";
import type {TwingArrayNode} from "../array";
export const filterNodeType = "filter";
export interface TwingFilterNode extends TwingBaseCallNode<typeof filterNodeType> {
export interface TwingFilterNode extends TwingBaseCallNode<"filter"> {
}
export const createFilterNode = (
@ -14,7 +12,7 @@ export const createFilterNode = (
line: number,
column: number
): TwingFilterNode => {
const node = createBaseCallNode(filterNodeType, filterName, operand, filterArguments, line, column);
const node = createBaseCallNode("filter", filterName, operand, filterArguments, line, column);
return node;
};

View File

@ -1,9 +1,7 @@
import {TwingBaseCallNode, createBaseCallNode} from "../call";
import type {TwingArrayNode} from "../array";
export const functionNodeType = "function";
export interface TwingFunctionNode extends TwingBaseCallNode<typeof functionNodeType> {
export interface TwingFunctionNode extends TwingBaseCallNode<"function"> {
}
export const createFunctionNode = (
@ -12,7 +10,7 @@ export const createFunctionNode = (
line: number,
column: number
): TwingFunctionNode => {
const node = createBaseCallNode(functionNodeType, functionName, null, functionArguments, line, column);
const node = createBaseCallNode("function", functionName, null, functionArguments, line, column);
return node;
};

View File

@ -2,9 +2,7 @@ import {TwingBaseCallNode, createBaseCallNode} from "../call";
import type {TwingBaseNode} from "../../../node";
import type {TwingArrayNode} from "../array";
export const testNodeType = "test";
export interface TwingTestNode extends TwingBaseCallNode<typeof testNodeType> {
export interface TwingTestNode extends TwingBaseCallNode<"test"> {
}
export const createTestNode = (
@ -14,7 +12,7 @@ export const createTestNode = (
line: number,
column: number
): TwingTestNode => {
const node = createBaseCallNode(testNodeType, testName, operand, testArguments, line, column);
const node = createBaseCallNode("test", testName, operand, testArguments, line, column);
return node;
};

View File

@ -1,8 +1,10 @@
import {TwingBaseExpressionNode, TwingBaseExpressionNodeAttributes, createBaseExpressionNode} from "../expression";
import {
TwingBaseExpressionNode,
TwingBaseExpressionNodeAttributes,
createBaseExpressionNode
} from "../expression";
import {TwingBaseNode} from "../../node";
export const conditionalNodeType = "conditional";
export interface TwingBaseConditionalNode<Type extends string> extends TwingBaseExpressionNode<Type, TwingBaseExpressionNodeAttributes, {
expr1: TwingBaseNode;
expr2: TwingBaseNode;
@ -10,7 +12,7 @@ export interface TwingBaseConditionalNode<Type extends string> extends TwingBase
}> {
}
export interface TwingConditionalNode extends TwingBaseConditionalNode<typeof conditionalNodeType> {
export interface TwingConditionalNode extends TwingBaseConditionalNode<"conditional"> {
}
export const createBaseConditionalNode = <Type extends string>(
@ -41,4 +43,4 @@ export const createConditionalNode = (
expr3: TwingBaseNode,
line: number,
column: number
) => createBaseConditionalNode(conditionalNodeType, expr1, expr2, expr3, line, column);
) => createBaseConditionalNode("conditional", expr1, expr2, expr3, line, column);

View File

@ -1,15 +1,13 @@
import type {TwingBaseExpressionNode} from "../expression";
import {createBaseExpressionNode} from "../expression";
export const constantNodeType = "constant";
export type TwingConstantNodeValue = string | number | boolean | null;
type TwingConstantNodeAttributes<Value extends TwingConstantNodeValue> = {
export type TwingConstantNodeAttributes<Value extends TwingConstantNodeValue> = {
value: Value;
};
export interface TwingConstantNode<Value extends TwingConstantNodeValue = TwingConstantNodeValue> extends TwingBaseExpressionNode<typeof constantNodeType, TwingConstantNodeAttributes<Value>> {
export interface TwingConstantNode<Value extends TwingConstantNodeValue = TwingConstantNodeValue> extends TwingBaseExpressionNode<"constant", TwingConstantNodeAttributes<Value>> {
}
export const createConstantNode = <Value extends string | number | boolean | null>(
@ -17,16 +15,16 @@ export const createConstantNode = <Value extends string | number | boolean | nul
line: number,
column: number
): TwingConstantNode<Value> => {
const parent = createBaseExpressionNode(constantNodeType, {
const parent = createBaseExpressionNode("constant", {
value
}, {}, line, column);
const node: TwingConstantNode<Value> = {
const constantNode: TwingConstantNode<Value> = {
...parent,
execute: () => {
return Promise.resolve(node.attributes.value);
return Promise.resolve(constantNode.attributes.value);
}
};
return node;
return constantNode;
};

View File

@ -22,21 +22,21 @@ export const createEscapeNode = (
body
}, body.line, body.column);
const node: TwingEscapeNode = {
const escapeNode: TwingEscapeNode = {
...baseNode,
execute: (executionContext) => {
const {template} = executionContext;
const {strategy} = node.attributes;
const {body} = node.children;
const {strategy} = escapeNode.attributes;
const {body} = escapeNode.children;
return body.execute(executionContext)
.then((value) => {
const escape = getTraceableMethod(template.escape, node.line, node.column, template.name);
const escape = getTraceableMethod(template.escape, escapeNode.line, escapeNode.column, template.name);
return escape(value, strategy, null, true);
});
}
};
return node;
return escapeNode;
};

View File

@ -1,10 +1,8 @@
import {TwingBaseArrayNode, createBaseArrayNode, getKeyValuePairs} from "./array";
import type {TwingBaseExpressionNode} from "../expression";
import {spreadNodeType} from "./spread";
import type {TwingNode} from "../../node";
export const hashNodeType = 'hash'
export interface TwingHashNode extends TwingBaseArrayNode<typeof hashNodeType> {
export interface TwingHashNode extends TwingBaseArrayNode<"hash"> {
}
export const createHashNode = (
@ -15,7 +13,7 @@ export const createHashNode = (
line: number,
column: number
): TwingHashNode => {
const baseNode = createBaseArrayNode(hashNodeType, elements, line, column);
const baseNode = createBaseArrayNode("hash", elements, line, column);
const hashNode: TwingHashNode = {
...baseNode,
@ -23,14 +21,14 @@ export const createHashNode = (
const keyValuePairs = getKeyValuePairs(hashNode);
const hash: Map<any, any> = new Map();
for (const {key: keyNode, value: valueNode} of keyValuePairs) {
const [key, value] = await Promise.all([
keyNode.execute(executionContext),
valueNode.execute(executionContext)
]);
if (valueNode.is(spreadNodeType)) {
if ((valueNode as TwingNode).type === "spread") {
for (const [valueKey, valueValue] of value as Map<any, any>) {
hash.set(valueKey, valueValue);
}
@ -39,13 +37,9 @@ export const createHashNode = (
hash.set(key, value);
}
}
return hash;
},
// todo: remove once confirmed that it is not needed
// is: (type) => {
// return type === "hash" || type === "array";
// }
}
};
return hashNode;

View File

@ -2,34 +2,32 @@ import {TwingBaseExpressionNode, TwingBaseExpressionNodeAttributes, createBaseEx
import type {TwingArrayNode} from "./array";
import {getKeyValuePairs} from "./array";
import {TwingBaseNode} from "../../node";
import {MacroHandler, TwingTemplate} from "../../template";
import {TwingTemplateMacroHandler, TwingTemplate} from "../../template";
import {createRuntimeError} from "../../error/runtime";
export const methodCallNodeType = "method_call";
export type TwingMethodCallNodeAttributes = TwingBaseExpressionNodeAttributes & {
methodName: string;
shouldTestExistence: boolean;
};
type NodeWithName = TwingBaseNode<any, {
name: string;
}>;
export interface TwingMethodCallNode extends TwingBaseExpressionNode<typeof methodCallNodeType, TwingMethodCallNodeAttributes, {
operand: NodeWithName;
export interface TwingMethodCallNode extends TwingBaseExpressionNode<"method_call", TwingMethodCallNodeAttributes, {
operand: TwingBaseNode<any, {
name: string;
}>;
arguments: TwingArrayNode;
}> {
}
export const createMethodCallNode = (
operand: NodeWithName,
operand: TwingBaseNode<any, {
name: string;
}>,
methodName: string,
methodArguments: TwingArrayNode,
line: number,
column: number
): TwingMethodCallNode => {
const baseNode = createBaseExpressionNode(methodCallNodeType, {
const baseNode = createBaseExpressionNode("method_call", {
methodName,
shouldTestExistence: false
}, {
@ -37,7 +35,7 @@ export const createMethodCallNode = (
arguments: methodArguments
}, line, column);
const node: TwingMethodCallNode = {
const methodCallNode: TwingMethodCallNode = {
...baseNode,
execute: async (executionContext) => {
const {template, context, outputBuffer, aliases, sandboxed, sourceMapRuntime} = executionContext;
@ -60,7 +58,7 @@ export const createMethodCallNode = (
// by nature, the alias exists - the parser only creates a method call node when the name _is_ an alias.
const macroTemplate = aliases.get(operand.attributes.name)!;
const getHandler = (template: TwingTemplate): Promise<MacroHandler | null> => {
const getHandler = (template: TwingTemplate): Promise<TwingTemplateMacroHandler | null> => {
const macroHandler = template.macroHandlers.get(methodName);
if (macroHandler) {
@ -82,24 +80,24 @@ export const createMethodCallNode = (
if (handler) {
return handler(outputBuffer, sandboxed, sourceMapRuntime, ...macroArguments);
} else {
throw createRuntimeError(`Macro "${methodName}" is not defined in template "${macroTemplate.name}".`, node, template.name);
throw createRuntimeError(`Macro "${methodName}" is not defined in template "${macroTemplate.name}".`, methodCallNode, template.name);
}
});
}
}
};
return node;
return methodCallNode;
};
export const cloneMethodCallNode = (
node: TwingMethodCallNode
methodCallNode: TwingMethodCallNode
): TwingMethodCallNode => {
return createMethodCallNode(
node.children.operand,
node.attributes.methodName,
node.children.arguments,
node.line,
node.column
methodCallNode.children.operand,
methodCallNode.attributes.methodName,
methodCallNode.children.arguments,
methodCallNode.line,
methodCallNode.column
);
};

View File

@ -10,9 +10,7 @@ export type TwingNameNodeAttributes = TwingBaseExpressionNodeAttributes & {
shouldTestExistence: boolean;
};
export const nameNodeType = "name";
export interface TwingNameNode extends TwingBaseNode<typeof nameNodeType, TwingNameNodeAttributes> {
export interface TwingNameNode extends TwingBaseNode<"name", TwingNameNodeAttributes> {
}
export const createNameNode = (
@ -27,20 +25,20 @@ export const createNameNode = (
shouldTestExistence: false
};
const baseNode = createBaseNode(nameNodeType, attributes, {}, line, column);
const baseNode = createBaseNode("name", attributes, {}, line, column);
const node: TwingNameNode = {
const nameNode: TwingNameNode = {
...baseNode,
execute: async ({template, context, charset, isStrictVariables}) => {
const {name, isAlwaysDefined, shouldIgnoreStrictCheck, shouldTestExistence} = node.attributes;
const {name, isAlwaysDefined, shouldIgnoreStrictCheck, shouldTestExistence} = nameNode.attributes;
const traceableGetContextValue = getTraceableMethod(
getContextValue,
node.line,
node.column,
nameNode.line,
nameNode.column,
template.name
);
return traceableGetContextValue(
charset,
template.name,
@ -54,15 +52,15 @@ export const createNameNode = (
}
};
return node;
return nameNode;
};
export const cloneNameNode = (
node: TwingNameNode
nameNode: TwingNameNode
): TwingNameNode => {
return createNameNode(
node.attributes.name,
node.line,
node.column
nameNode.attributes.name,
nameNode.line,
nameNode.column
);
};

View File

@ -1,26 +1,24 @@
import {TwingBaseConditionalNode, conditionalNodeType, createBaseConditionalNode} from "./conditional";
import {TwingBaseExpressionNode} from "../expression";
import {TwingBaseConditionalNode, createBaseConditionalNode} from "./conditional";
import {TwingExpressionNode} from "../expression";
import {createNotNode} from "./unary/not";
import {createAndNode} from "./binary/and";
import {createTestNode} from "./call/test";
import {createArrayNode} from "./array";
export const nullishCoalescingNodeType = "nullish_coalescing";
export interface TwingNullishCoalescingNode extends TwingBaseConditionalNode<typeof nullishCoalescingNodeType> {
export interface TwingNullishCoalescingNode extends TwingBaseConditionalNode<"nullish_coalescing"> {
}
export const createNullishCoalescingNode = (
operands: [TwingBaseExpressionNode, TwingBaseExpressionNode],
operands: [TwingExpressionNode, TwingExpressionNode],
line: number,
column: number
): TwingNullishCoalescingNode => {
const [left, right] = operands;
if (left.is("name")) {
if (left.type === "name") {
left.attributes.isAlwaysDefined = true;
}
const testNode = createAndNode(
[
createTestNode(left, "defined", createArrayNode([], line, column), line, column),
@ -39,12 +37,11 @@ export const createNullishCoalescingNode = (
column
);
const baseNode = createBaseConditionalNode(nullishCoalescingNodeType, testNode, left, right, line, column);
const node: TwingNullishCoalescingNode = {
...baseNode,
is: (aType) => aType === node.type || aType === conditionalNodeType
const baseNode = createBaseConditionalNode("nullish_coalescing", testNode, left, right, line, column);
const nullishCoalescingNode: TwingNullishCoalescingNode = {
...baseNode
};
return node;
return nullishCoalescingNode;
};

View File

@ -1,13 +1,11 @@
import {TwingBaseExpressionNode, TwingBaseExpressionNodeAttributes, createBaseExpressionNode} from "../expression";
import {getTraceableMethod} from "../../helpers/traceable-method";
export const parentFunctionNodeType = "parent_function";
export type ParentNodeAttributes = TwingBaseExpressionNodeAttributes & {
name: string;
};
export interface TwingParentFunctionNode extends TwingBaseExpressionNode<typeof parentFunctionNodeType, ParentNodeAttributes> {
export interface TwingParentFunctionNode extends TwingBaseExpressionNode<"parent_function", ParentNodeAttributes> {
}
export const createParentFunctionNode = (
@ -15,21 +13,21 @@ export const createParentFunctionNode = (
line: number,
column: number
): TwingParentFunctionNode => {
const baseNode = createBaseExpressionNode(parentFunctionNodeType, {
const baseNode = createBaseExpressionNode("parent_function", {
name,
//output: false
}, {}, line, column);
const node: TwingParentFunctionNode = {
const parentFunctionNode: TwingParentFunctionNode = {
...baseNode,
execute: (executionContext) => {
const {template, context, outputBuffer, sandboxed, sourceMapRuntime} = executionContext;
const {name} = node.attributes;
const renderParentBlock = getTraceableMethod(template.renderParentBlock, node.line, node.column, template.name);
const {name} = parentFunctionNode.attributes;
const renderParentBlock = getTraceableMethod(template.renderParentBlock, parentFunctionNode.line, parentFunctionNode.column, template.name);
return renderParentBlock(name, context, outputBuffer, sandboxed, sourceMapRuntime);
}
};
return node;
return parentFunctionNode;
};

View File

@ -1,8 +1,6 @@
import {createBaseExpressionNode, TwingBaseExpressionNode} from "../expression";
export const spreadNodeType = "spread";
export interface TwingSpreadNode extends TwingBaseExpressionNode<typeof spreadNodeType, {}, {
export interface TwingSpreadNode extends TwingBaseExpressionNode<"spread", {}, {
iterable: TwingBaseExpressionNode;
}> {
@ -13,7 +11,7 @@ export const createSpreadNode = (
line: number,
column: number
): TwingSpreadNode => {
const baseNode = createBaseExpressionNode(spreadNodeType, {}, {
const baseNode = createBaseExpressionNode("spread", {}, {
iterable
}, line, column);

View File

@ -1,8 +1,9 @@
import {TwingBaseExpressionNode, TwingBaseExpressionNodeAttributes, createBaseExpressionNode} from "../expression";
import type {TwingExecutionContext, TwingNodeType} from "../../node";
import type {TwingNegativeNode} from "./unary/neg";
import type {TwingNodeType} from "../../node";
import type {TwingNegativeNode} from "./unary/negative";
import type {TwingNotNode} from "./unary/not";
import type {TwingPositiveNode} from "./unary/pos";
import type {TwingPositiveNode} from "./unary/positive";
import type {TwingExecutionContext} from "../../execution-context";
export type TwingUnaryNode =
| TwingNegativeNode

View File

@ -1,11 +1,9 @@
import {TwingBaseUnaryNode, createUnaryNodeFactory} from "../unary";
export const negativeNodeType = "neg";
export interface TwingNegativeNode extends TwingBaseUnaryNode<typeof negativeNodeType> {
export interface TwingNegativeNode extends TwingBaseUnaryNode<"negative"> {
}
export const createNegativeNode = createUnaryNodeFactory<TwingNegativeNode>(negativeNodeType, {
export const createNegativeNode = createUnaryNodeFactory<TwingNegativeNode>("negative", {
execute: (operand, executionContext) => {
return operand.execute(executionContext)
.then((value) => -(value));

View File

@ -1,11 +1,9 @@
import {TwingBaseUnaryNode, createUnaryNodeFactory} from "../unary";
export const notNodeType = "not";
export interface TwingNotNode extends TwingBaseUnaryNode<typeof notNodeType> {
export interface TwingNotNode extends TwingBaseUnaryNode<"not"> {
}
export const createNotNode = createUnaryNodeFactory<TwingNotNode>(notNodeType, {
export const createNotNode = createUnaryNodeFactory<TwingNotNode>("not", {
execute: (operand, executionContext) => {
return operand.execute(executionContext)
.then((value) => !(value));

View File

@ -1,11 +1,9 @@
import {TwingBaseUnaryNode, createUnaryNodeFactory} from "../unary";
export const positiveNodeType = "pos";
export interface TwingPositiveNode extends TwingBaseUnaryNode<typeof positiveNodeType> {
export interface TwingPositiveNode extends TwingBaseUnaryNode<"positive"> {
}
export const createPositiveNode = createUnaryNodeFactory<TwingPositiveNode>(positiveNodeType, {
export const createPositiveNode = createUnaryNodeFactory<TwingPositiveNode>("positive", {
execute: (operand, executionContext) => {
return operand.execute(executionContext)
.then((value) => +(value));

View File

@ -18,10 +18,10 @@ export const createForLoopNode = (
hasAnElse: false
}, {}, line, column, tag);
const node: TwingForLoopNode = {
const forLoopNode: TwingForLoopNode = {
...baseNode,
execute: (executionContext) => {
const {hasAnElse, hasAnIf} = node.attributes;
const {hasAnElse, hasAnIf} = forLoopNode.attributes;
const {context} = executionContext;
@ -45,5 +45,5 @@ export const createForLoopNode = (
}
};
return node;
return forLoopNode;
};

View File

@ -12,7 +12,7 @@ export type TwingForNodeAttributes = TwingBaseNodeAttributes & {
hasAnIf: boolean;
};
type TwingForNodeChildren = {
export type TwingForNodeChildren = {
keyTarget: TwingAssignmentNode;
valueTarget: TwingAssignmentNode;
sequence: TwingBaseExpressionNode;
@ -74,12 +74,12 @@ export const createForNode = (
hasAnIf: ifExpression !== null
}, children, line, column, tag);
const node: TwingForNode = {
const forNode: TwingForNode = {
...baseNode,
execute: async (executionContext) => {
const {context} = executionContext;
const {sequence: sequenceNode, body, else: elseNode, valueTarget: targetValueNode, keyTarget: targetKeyNode} = node.children;
const {hasAnIf} = node.attributes;
const {sequence: sequenceNode, body, else: elseNode, valueTarget: targetValueNode, keyTarget: targetKeyNode} = forNode.children;
const {hasAnIf} = forNode.attributes;
context.set('_parent', context.clone());
@ -148,5 +148,5 @@ export const createForNode = (
}
};
return node;
return forNode;
};

View File

@ -1,7 +1,7 @@
import {TwingBaseNode, createBaseNode, getChildrenCount, TwingBaseNodeAttributes} from "../node";
import {evaluate} from "../helpers/evaluate";
type TwingIfNodeChildren = {
export type TwingIfNodeChildren = {
tests: TwingBaseNode;
else?: TwingBaseNode;
};
@ -26,7 +26,7 @@ export const createIfNode = (
const baseNode = createBaseNode('if', {}, children, line, column, tag);
const node: TwingIfNode = {
const ifNode: TwingIfNode = {
...baseNode,
execute: async (executionContext) => {
const count = getChildrenCount(testNode);
@ -53,5 +53,5 @@ export const createIfNode = (
}
};
return node;
return ifNode;
}

View File

@ -1,5 +1,5 @@
import {TwingBaseNode, TwingBaseNodeAttributes, createBaseNode} from "../node";
import type {TwingBaseExpressionNode} from "./expression";
import type {TwingBaseExpressionNode, TwingExpressionNode} from "./expression";
import type {TwingAssignmentNode} from "./expression/assignment";
import type {TwingTemplate} from "../template";
import {getTraceableMethod} from "../helpers/traceable-method";
@ -15,7 +15,7 @@ export interface TwingImportNode extends TwingBaseNode<"import", TwingImportNode
}
export const createImportNode = (
templateName: TwingBaseExpressionNode,
templateName: TwingExpressionNode,
alias: TwingAssignmentNode,
global: boolean,
line: number,
@ -29,7 +29,7 @@ export const createImportNode = (
alias
}, line, column, tag);
const node: TwingImportNode = {
const importNode: TwingImportNode = {
...baseNode,
execute: async (executionContext) => {
const {template, aliases} = executionContext;
@ -39,12 +39,12 @@ export const createImportNode = (
let aliasValue: TwingTemplate;
if (templateNameNode.is("name") && templateNameNode.attributes.name === '_self') {
if (templateNameNode.type === "name" && templateNameNode.attributes.name === '_self') {
aliasValue = template;
} else {
const templateName = await templateNameNode.execute(executionContext);
const loadTemplate = getTraceableMethod(template.loadTemplate, node.line, node.column, template.name);
const loadTemplate = getTraceableMethod(template.loadTemplate, importNode.line, importNode.column, template.name);
aliasValue = await loadTemplate(templateName);
}
@ -57,5 +57,5 @@ export const createImportNode = (
}
};
return node;
return importNode;
};

View File

@ -1,26 +1,27 @@
import {TwingBaseNode, TwingBaseNodeAttributes, createBaseNode, TwingExecutionContext} from "../node";
import {TwingBaseNode, TwingBaseNodeAttributes, createBaseNode} from "../node";
import type {TwingBaseExpressionNode} from "./expression";
import type {TwingTemplate} from "../template";
import {getTraceableMethod} from "../helpers/traceable-method";
import {include} from "../extension/core/functions/include";
import type {TwingExecutionContext} from "../execution-context";
export type BaseIncludeNodeAttributes = TwingBaseNodeAttributes & {
export type TwingBaseIncludeNodeAttributes = TwingBaseNodeAttributes & {
only: boolean;
ignoreMissing: boolean;
};
export type BaseIncludeNodeChildren = {
export type TwingBaseIncludeNodeChildren = {
variables: TwingBaseExpressionNode;
};
export interface TwingBaseIncludeNode<
Type extends string,
Attributes extends BaseIncludeNodeAttributes = BaseIncludeNodeAttributes,
Children extends BaseIncludeNodeChildren = BaseIncludeNodeChildren
Attributes extends TwingBaseIncludeNodeAttributes = TwingBaseIncludeNodeAttributes,
Children extends TwingBaseIncludeNodeChildren = TwingBaseIncludeNodeChildren
> extends TwingBaseNode<Type, Attributes, Children> {
}
export const createBaseIncludeNode = <Type extends string, Attributes extends BaseIncludeNodeAttributes, Children extends BaseIncludeNodeChildren = BaseIncludeNodeChildren>(
export const createBaseIncludeNode = <Type extends string, Attributes extends TwingBaseIncludeNodeAttributes, Children extends TwingBaseIncludeNodeChildren = TwingBaseIncludeNodeChildren>(
type: Type,
attributes: Attributes,
children: Children,
@ -31,12 +32,12 @@ export const createBaseIncludeNode = <Type extends string, Attributes extends Ba
): TwingBaseIncludeNode<Type, Attributes, Children> => {
const baseNode = createBaseNode(type, attributes, children, line, column, tag);
const node: TwingBaseIncludeNode<Type, Attributes, Children> = {
const baseIncludeNode: TwingBaseIncludeNode<Type, Attributes, Children> = {
...baseNode,
execute: async (executionContext) => {
const {outputBuffer, sandboxed, template} = executionContext;
const {variables} = node.children;
const {only, ignoreMissing} = node.attributes;
const {variables} = baseIncludeNode.children;
const {only, ignoreMissing} = baseIncludeNode.attributes;
const templatesToInclude = await getTemplate(executionContext);
@ -55,5 +56,5 @@ export const createBaseIncludeNode = <Type extends string, Attributes extends Ba
}
};
return node;
return baseIncludeNode;
};

View File

@ -1,36 +1,33 @@
import {
TwingBaseIncludeNode,
BaseIncludeNodeAttributes,
BaseIncludeNodeChildren,
TwingBaseIncludeNodeAttributes,
TwingBaseIncludeNodeChildren,
createBaseIncludeNode
} from "../include";
import {includeNodeType} from "./include";
import {getTraceableMethod} from "../../helpers/traceable-method";
export const embedNodeType = "embed";
type TwingEmbedNodeAttributes = BaseIncludeNodeAttributes & {
export type TwingEmbedNodeAttributes = TwingBaseIncludeNodeAttributes & {
index: number;
};
export interface TwingEmbedNode extends TwingBaseIncludeNode<typeof embedNodeType, TwingEmbedNodeAttributes> {
export interface TwingEmbedNode extends TwingBaseIncludeNode<"embed", TwingEmbedNodeAttributes> {
}
export const createEmbedNode = (
attributes: TwingEmbedNodeAttributes,
children: Omit<BaseIncludeNodeChildren, "expression">,
children: Omit<TwingBaseIncludeNodeChildren, "expression">,
line: number,
column: number,
tag: string
): TwingEmbedNode => {
const baseNode = createBaseIncludeNode(
embedNodeType,
const embedNode: TwingEmbedNode = createBaseIncludeNode(
"embed",
attributes,
children,
({template}) => {
const {index} = node.attributes;
const {index} = embedNode.attributes;
const loadTemplate = getTraceableMethod(template.loadEmbeddedTemplate, node.line, node.column, template.name);
const loadTemplate = getTraceableMethod(template.loadEmbeddedTemplate, embedNode.line, embedNode.column, template.name);
return loadTemplate(index);
},
@ -39,11 +36,5 @@ export const createEmbedNode = (
tag
);
const node: TwingEmbedNode = Object.assign(baseNode, <Partial<TwingEmbedNode>>{
is: (type) => {
return type === embedNodeType || type === includeNodeType; // todo: this should probably be handled by the base include node
}
});
return node;
return embedNode;
};

View File

@ -1,29 +1,27 @@
import {
TwingBaseIncludeNode,
BaseIncludeNodeAttributes,
BaseIncludeNodeChildren,
TwingBaseIncludeNodeAttributes,
TwingBaseIncludeNodeChildren,
createBaseIncludeNode
} from "../include";
import {TwingBaseExpressionNode} from "../expression";
export const includeNodeType = "include";
export type TwingIncludeNodeChildren = BaseIncludeNodeChildren & {
export type TwingIncludeNodeChildren = TwingBaseIncludeNodeChildren & {
expression: TwingBaseExpressionNode;
};
export interface TwingIncludeNode extends TwingBaseIncludeNode<typeof includeNodeType, BaseIncludeNodeAttributes, TwingIncludeNodeChildren> {
export interface TwingIncludeNode extends TwingBaseIncludeNode<"include", TwingBaseIncludeNodeAttributes, TwingIncludeNodeChildren> {
}
export const createIncludeNode = (
attributes: BaseIncludeNodeAttributes,
attributes: TwingBaseIncludeNodeAttributes,
children: TwingIncludeNodeChildren,
line: number,
column: number,
tag: string
): TwingIncludeNode => {
const baseNode = createBaseIncludeNode(
includeNodeType,
"include",
attributes,
children,
children.expression.execute,
@ -32,9 +30,9 @@ export const createIncludeNode = (
tag
);
const node: TwingIncludeNode = {
const includeNode: TwingIncludeNode = {
...baseNode
};
return node;
return includeNode;
}

View File

@ -2,13 +2,11 @@ import {TwingBaseNodeAttributes} from "../../node";
import {TwingBaseOutputNode, createBaseOutputNode} from "../output";
import {getTraceableMethod} from "../../helpers/traceable-method";
export const blockReferenceType = "block_reference";
export type BlockReferenceNodeAttributes = TwingBaseNodeAttributes & {
export type TwingBlockReferenceNodeAttributes = TwingBaseNodeAttributes & {
name: string;
};
export interface TwingBlockReferenceNode extends TwingBaseOutputNode<typeof blockReferenceType, BlockReferenceNodeAttributes, {}> {
export interface TwingBlockReferenceNode extends TwingBaseOutputNode<"block_reference", TwingBlockReferenceNodeAttributes, {}> {
}
export const createBlockReferenceNode = (
@ -17,17 +15,17 @@ export const createBlockReferenceNode = (
column: number,
tag: string
): TwingBlockReferenceNode => {
const outputNode = createBaseOutputNode(blockReferenceType, {
const outputNode = createBaseOutputNode("block_reference", {
name
}, {}, line, column, tag);
const node: TwingBlockReferenceNode = {
const blockReferenceNode: TwingBlockReferenceNode = {
...outputNode,
execute: (executionContext) => {
const {template, context, outputBuffer, blocks, sandboxed, sourceMapRuntime} = executionContext;
const {name} = node.attributes;
const {name} = blockReferenceNode.attributes;
const renderBlock = getTraceableMethod(template.renderBlock, node.line, node.column, template.name);
const renderBlock = getTraceableMethod(template.renderBlock, blockReferenceNode.line, blockReferenceNode.column, template.name);
return renderBlock(
name,
@ -41,5 +39,5 @@ export const createBlockReferenceNode = (
}
};
return node;
return blockReferenceNode;
};

View File

@ -1,9 +1,7 @@
import {TwingBaseExpressionNode} from "../expression";
import {TwingBaseOutputNode, createBaseOutputNode} from "../output";
import {TwingBaseExpressionNode} from "../expression";
export const printNodeType = "print";
export interface TwingPrintNode extends TwingBaseOutputNode<typeof printNodeType, {}, {
export interface TwingPrintNode extends TwingBaseOutputNode<"print", {}, {
expression: TwingBaseExpressionNode;
}> {
}
@ -13,7 +11,7 @@ export const createPrintNode = (
line: number,
column: number
): TwingPrintNode => {
const outputNode: TwingPrintNode = createBaseOutputNode(printNodeType, {}, {
const outputNode: TwingPrintNode = createBaseOutputNode("print", {}, {
expression: expression
}, line, column, null);

View File

@ -1,9 +1,7 @@
import {TwingBaseNode, TwingBaseNodeAttributes} from "../../node";
import {TwingBaseOutputNode, createBaseOutputNode} from "../output";
export const spacelessNodeType = "spaceless";
export interface TwingSpacelessNode extends TwingBaseOutputNode<typeof spacelessNodeType, TwingBaseNodeAttributes, {
export interface TwingSpacelessNode extends TwingBaseOutputNode<"spaceless", TwingBaseNodeAttributes, {
body: TwingBaseNode;
}> {
}
@ -14,7 +12,7 @@ export const createSpacelessNode = (
column: number,
tag: string
): TwingSpacelessNode => {
const baseNode = createBaseOutputNode(spacelessNodeType, {}, {
const baseNode = createBaseOutputNode("spaceless", {}, {
body
}, line, column, tag);

View File

@ -1,16 +1,14 @@
import {TwingBaseNodeAttributes} from "../../node";
import {TwingBaseOutputNode, createBaseOutputNode} from "../output";
export const textNodeType = "text";
export type BaseTextNodeAttributes = TwingBaseNodeAttributes & {
export type TwingBaseTextNodeAttributes = TwingBaseNodeAttributes & {
data: string;
};
export interface BaseTextNode<Type extends string> extends TwingBaseOutputNode<Type, BaseTextNodeAttributes> {
export interface TwingBaseTextNode<Type extends string> extends TwingBaseOutputNode<Type, TwingBaseTextNodeAttributes> {
}
export interface TwingTextNode extends BaseTextNode<typeof textNodeType> {
export interface TwingTextNode extends TwingBaseTextNode<"text"> {
}
export const createBaseTextNode = <Type extends string>(
@ -19,19 +17,19 @@ export const createBaseTextNode = <Type extends string>(
line: number,
column: number,
tag: string | null = null
): BaseTextNode<Type> => {
): TwingBaseTextNode<Type> => {
const outputNode = createBaseOutputNode(type, {
data
}, {}, line, column, tag);
const node: BaseTextNode<Type> = {
const textNode: TwingBaseTextNode<Type> = {
...outputNode,
execute(executionContext) {
const {template, outputBuffer, sourceMapRuntime} = executionContext;
sourceMapRuntime?.enterSourceMapBlock(node.line, node.column, node.type, template.source, outputBuffer);
sourceMapRuntime?.enterSourceMapBlock(textNode.line, textNode.column, textNode.type, template.source, outputBuffer);
outputBuffer.echo(node.attributes.data);
outputBuffer.echo(textNode.attributes.data);
sourceMapRuntime?.leaveSourceMapBlock(outputBuffer);
@ -39,11 +37,11 @@ export const createBaseTextNode = <Type extends string>(
}
};
return node;
return textNode;
};
export const createTextNode = (
data: string,
line: number,
column: number
): TwingTextNode => createBaseTextNode(textNodeType, data, line, column);
): TwingTextNode => createBaseTextNode("text", data, line, column);

View File

@ -1,11 +1,9 @@
import {BaseTextNode, createBaseTextNode} from "./text";
export const verbatimNodeType = "verbatim";
import {TwingBaseTextNode, createBaseTextNode} from "./text";
/**
* Represents a verbatim node.
*/
export interface TwingVerbatimNode extends BaseTextNode<typeof verbatimNodeType> {
export interface TwingVerbatimNode extends TwingBaseTextNode<"verbatim"> {
}
export const createVerbatimNode = (
@ -13,4 +11,4 @@ export const createVerbatimNode = (
line: number,
column: number,
tag: string
): TwingVerbatimNode => createBaseTextNode(verbatimNodeType, data, line, column, tag);
): TwingVerbatimNode => createBaseTextNode("verbatim", data, line, column, tag);

View File

@ -1,19 +1,17 @@
import {TwingBaseNode, TwingBaseNodeAttributes, createBaseNode, TwingNode} from "../node";
import {TwingBaseNode, TwingBaseNodeAttributes, createBaseNode} from "../node";
export const sandboxNodeType = "sandbox";
export interface TwingSandboxNode extends TwingBaseNode<typeof sandboxNodeType, TwingBaseNodeAttributes, {
body: TwingNode;
export interface TwingSandboxNode extends TwingBaseNode<"sandbox", TwingBaseNodeAttributes, {
body: TwingBaseNode;
}> {
}
export const createSandboxNode = (
body: TwingNode,
body: TwingBaseNode,
line: number,
column: number,
tag: string
): TwingSandboxNode => {
const baseNode = createBaseNode(sandboxNodeType, {}, {
const baseNode = createBaseNode("sandbox", {}, {
body
}, line, column, tag);

View File

@ -1,20 +1,19 @@
import {TwingBaseNode, TwingBaseNodeAttributes, createBaseNode} from "../node";
import {TwingBaseNode, TwingBaseNodeAttributes, createBaseNode, TwingNode} from "../node";
import {createConstantNode} from "./expression/constant";
import {textNodeType} from "./output/text";
import {createArgumentsNode} from "./expression/arguments";
import {createWrapperNode} from "./wrapper";
export type SetNodeAttributes = TwingBaseNodeAttributes & {
capture: boolean; // todo: rename
export type TwingSetNodeAttributes = TwingBaseNodeAttributes & {
captures: boolean;
};
export interface TwingSetNode extends TwingBaseNode<"set", SetNodeAttributes, {
export interface TwingSetNode extends TwingBaseNode<"set", TwingSetNodeAttributes, {
names: TwingBaseNode;
values: TwingBaseNode;
}> {
}
export const createSetNode = (
capture: boolean,
captures: boolean,
names: TwingSetNode["children"]["names"],
values: TwingSetNode["children"]["values"],
line: number,
@ -22,7 +21,7 @@ export const createSetNode = (
tag: string
): TwingSetNode => {
const baseNode = createBaseNode("set", {
capture
captures
}, {
names,
values
@ -33,27 +32,27 @@ export const createSetNode = (
*
* {% set foo %}foo{% endset %} is compiled to $context['foo'] = new Twig_Markup("foo");
*/
if (baseNode.attributes.capture) {
const {values} = baseNode.children;
if (baseNode.attributes.captures) {
const values = baseNode.children.values as TwingNode;
if (values.is(textNodeType)) {
baseNode.children.values = createArgumentsNode({
if (values.type === "text") {
baseNode.children.values = createWrapperNode({
0: createConstantNode(values.attributes.data, values.line, values.column)
}, values.line, values.column);
baseNode.attributes.capture = false;
baseNode.attributes.captures = false;
}
}
const node: TwingSetNode = {
const setNode: TwingSetNode = {
...baseNode,
execute: async (executionContext) => {
const {context, outputBuffer} = executionContext;
const {names: namesNode, values: valuesNode} = node.children;
const {capture} = node.attributes;
const {names: namesNode, values: valuesNode} = setNode.children;
const {captures} = setNode.attributes;
const names: Array<string> = await namesNode.execute(executionContext);
if (capture) {
if (captures) {
outputBuffer.start();
await valuesNode.execute(executionContext);
@ -63,16 +62,17 @@ export const createSetNode = (
for (const name of names) {
context.set(name, value);
}
} else {
}
else {
const values: Array<any> = await valuesNode.execute(executionContext);
let index = 0;
for (const name of names) {
const value = values[index];
context.set(name, value);
index++;
}
}
@ -80,5 +80,5 @@ export const createSetNode = (
isACaptureNode: true
};
return node;
return setNode;
};

View File

@ -6,8 +6,6 @@ import {TwingMacroNode} from "./macro";
import {TwingBlockNode} from "./block";
import {TwingBodyNode} from "./body";
export const templateNodeType = "template";
export type TwingTemplateNodeAttributes = TwingBaseNodeAttributes & {
index: number;
source: TwingSource;
@ -22,7 +20,7 @@ export type TwingTemplateNodeChildren = {
parent?: TwingBaseExpressionNode;
};
export interface TwingTemplateNode extends TwingBaseNode<typeof templateNodeType, TwingTemplateNodeAttributes, TwingTemplateNodeChildren> {
export interface TwingTemplateNode extends TwingBaseNode<"template", TwingTemplateNodeAttributes, TwingTemplateNodeChildren> {
readonly embeddedTemplates: Array<TwingTemplateNode>;
readonly source: TwingSource;
}
@ -50,7 +48,7 @@ export const createTemplateNode = (
children.parent = parent;
}
const baseNode = createBaseNode(templateNodeType, {
const baseNode = createBaseNode("template", {
index: 0,
source
}, children, line, column);

View File

@ -1,13 +1,10 @@
import type {TwingBaseNode, TwingBaseNodeAttributes} from "../node";
import {createBaseNode} from "../node";
import type {TwingConstantNode} from "./expression/constant";
import {TwingBaseExpressionNode} from "./expression";
export const traitNodeType = "trait";
export interface TwingTraitNode extends TwingBaseNode<typeof traitNodeType, TwingBaseNodeAttributes, {
export interface TwingTraitNode extends TwingBaseNode<"trait", TwingBaseNodeAttributes, {
template: TwingConstantNode;
targets: TwingBaseExpressionNode<string, {}, Record<string, TwingConstantNode<string>>>;
targets: TwingBaseNode;
}> {
}
@ -18,7 +15,7 @@ export const createTraitNode = (
column: number
): TwingTraitNode => {
return {
...createBaseNode(traitNodeType, {}, {
...createBaseNode("trait", {}, {
template,
targets
}, line, column)

View File

@ -1,24 +1,25 @@
import {TwingBaseNode, TwingBaseNodeAttributes, createBaseNode, TwingNode} from "../node";
import {TwingBaseNode, TwingBaseNodeAttributes, createBaseNode} from "../node";
import {createRuntimeError} from "../error/runtime";
import {createContext, TwingContext} from "../context";
import {mergeIterables} from "../helpers/merge-iterables";
import {iteratorToMap} from "../helpers/iterator-to-map";
import {TwingBaseExpressionNode} from "./expression";
export type TwingWithNodeAttributes = TwingBaseNodeAttributes & {
only: boolean;
};
export type TwingWithNodeChildren = {
body: TwingNode;
variables?: TwingNode;
body: TwingBaseNode;
variables?: TwingBaseExpressionNode;
};
export interface TwingWithNode extends TwingBaseNode<"with", TwingWithNodeAttributes, TwingWithNodeChildren> {
}
export const createWithNode = (
body: TwingNode,
variables: TwingNode | null,
body: TwingBaseNode,
variables: TwingBaseExpressionNode | null,
only: boolean,
line: number,
column: number,
@ -36,7 +37,7 @@ export const createWithNode = (
only
}, children, line, column, tag);
const node: TwingWithNode = {
const withNode: TwingWithNode = {
...baseNode,
execute: async (executionContext) => {
const {template, context} = executionContext;
@ -49,7 +50,7 @@ export const createWithNode = (
const variables = await variablesNode.execute(executionContext);
if (typeof variables !== "object") {
throw createRuntimeError(`Variables passed to the "with" tag must be a hash.`, node, template.name);
throw createRuntimeError(`Variables passed to the "with" tag must be a hash.`, withNode, template.name);
}
if (only) {
@ -75,5 +76,5 @@ export const createWithNode = (
}
};
return node;
return withNode;
};

17
src/lib/node/wrapper.ts Normal file
View File

@ -0,0 +1,17 @@
import type {TwingBaseNode} from "../node";
import {createBaseNode, TwingBaseNodeAttributes} from "../node";
import {TwingBaseExpressionNode} from "./expression";
export type TwingWrapperNodeChildren<T extends TwingBaseExpressionNode> = Record<string, T>;
export interface TwingWrapperNode<T extends TwingBaseExpressionNode = TwingBaseExpressionNode> extends TwingBaseNode<"wrapper", TwingBaseNodeAttributes, TwingWrapperNodeChildren<T>> {
}
export const createWrapperNode = <T extends TwingBaseExpressionNode>(
children: TwingWrapperNodeChildren<T>,
line: number,
column: number
): TwingWrapperNode<T> => {
return createBaseNode("wrapper", {}, children, line, column);
};

View File

@ -1,26 +1,26 @@
import type {TwingBaseNode} from "./node";
import type {TwingExpressionNode} from "./node/expression";
export type OperatorType =
export type TwingOperatorType =
| 'BINARY'
| 'UNARY'
;
export type OperatorAssociativity =
export type TwingOperatorAssociativity =
| 'LEFT'
| 'RIGHT'
;
type TwingOperatorExpressionFactory = (operands: [TwingBaseNode, TwingBaseNode], line: number, column: number) => TwingExpressionNode;
export type TwingOperatorExpressionFactory = (operands: [TwingBaseNode, TwingBaseNode], line: number, column: number) => TwingExpressionNode;
export interface TwingOperator {
readonly name: string;
readonly type: OperatorType;
readonly type: TwingOperatorType;
readonly precedence: number;
readonly associativity: OperatorAssociativity | null;
readonly associativity: TwingOperatorAssociativity | null;
readonly specificationLevel: 2 | 3;
@ -29,10 +29,10 @@ export interface TwingOperator {
export const createOperator = (
name: string,
type: OperatorType,
type: TwingOperatorType,
precedence: number,
expressionFactory: TwingOperatorExpressionFactory,
associativity: OperatorAssociativity | null = null,
associativity: TwingOperatorAssociativity | null = null,
specificationLevel: 2 | 3 = 2,
): TwingOperator => {
associativity = type === "BINARY" ? (associativity || "LEFT") : null;

View File

@ -2,10 +2,10 @@ import type {TwingTokenStream} from "./token-stream";
import {TwingTagHandler, TwingTokenParser} from "./tag-handler";
import {TwingNodeVisitor} from "./node-visitor";
import {createParsingError, TwingParsingError} from "./error/parsing";
import {TwingBaseNode, createBaseNode, getChildren} from "./node";
import {createTextNode, textNodeType} from "./node/output/text";
import {TwingBaseNode, createBaseNode, getChildren, TwingNode} from "./node";
import {createTextNode} from "./node/output/text";
import {createPrintNode} from "./node/output/print";
import {TwingBaseExpressionNode} from "./node/expression";
import {TwingBaseExpressionNode, TwingExpressionNode} from "./node/expression";
import {createBodyNode} from "./node/body";
import {createTemplateNode, TwingTemplateNode} from "./node/template";
import {createNodeTraverser} from "./node-traverser";
@ -21,11 +21,11 @@ import {createParentFunctionNode} from "./node/expression/parent-function";
import {createBlockFunctionNode} from "./node/expression/block-function";
import {
createAttributeAccessorNode,
TwingGetAttributeCallType
TwingAttributeAccessorCallType
} from "./node/expression/attribute-accessor";
import {TwingArrayNode, createArrayNode, getKeyValuePairs} from "./node/expression/array";
import {createMethodCallNode} from "./node/expression/method-call";
import {createHashNode, hashNodeType, TwingHashNode} from "./node/expression/hash";
import {createHashNode, TwingHashNode} from "./node/expression/hash";
import {TwingTest} from "./test";
import {createNotNode} from "./node/expression/unary/not";
import {createConditionalNode} from "./node/expression/conditional";
@ -36,7 +36,6 @@ import {createFunctionNode} from "./node/expression/call/function";
import {createFilterNode, TwingFilterNode} from "./node/expression/call/filter";
import type {TwingTraitNode} from "./node/trait";
import {pushToRecord} from "./helpers/record";
import {ArgumentsNode, createArgumentsNode} from "./node/expression/arguments";
import {TwingFilter} from "./filter";
import {TwingFunction} from "./function";
import {TwingCallableWrapper} from "./callable-wrapper";
@ -47,8 +46,6 @@ import {getTest as getTestByName} from "./helpers/get-test";
import {createCoreNodeVisitor} from "./node-visitor/core";
import {createSandboxNodeVisitor} from "./node-visitor/sandbox";
import {createTestNode} from "./node/expression/call/test";
import {positiveNodeType} from "./node/expression/unary/pos";
import {negativeNodeType} from "./node/expression/unary/neg";
import {createEscaperNodeVisitor} from "./node-visitor/escaper";
import {createApplyTagHandler} from "./tag-handler/apply";
import {createAutoEscapeTagHandler} from "./tag-handler/auto-escape";
@ -73,16 +70,15 @@ import {createUseTagHandler} from "./tag-handler/use";
import {createVerbatimTagHandler} from "./tag-handler/verbatim";
import {createWithTagHandler} from "./tag-handler/with";
import {createSpreadNode} from "./node/expression/spread";
import {createWrapperNode, TwingWrapperNode} from "./node/wrapper";
const nameRegExp = new RegExp(namePattern);
type NodeWithName = TwingBaseNode<any, {
name: string;
}>;
type TwingParserImportedSymbolAlias = {
name: string,
node: NodeWithName
node: TwingBaseNode<any, {
name: string;
}>
};
type TwingParserImportedSymbolType = Map<string, TwingParserImportedSymbolAlias>;
type TwingParserImportedSymbol = {
@ -102,7 +98,9 @@ export interface TwingParser {
addImportedSymbol(type: 'template', alias: string): void;
addImportedSymbol(type: 'method', alias: string, name: string, node: NodeWithName): void;
addImportedSymbol(type: 'method', alias: string, name: string, node: TwingBaseNode<any, {
name: string;
}>): void;
addTrait(trait: TwingTraitNode): void;
@ -118,9 +116,9 @@ export interface TwingParser {
parseArguments(stream: TwingTokenStream, namedArguments?: boolean, definition?: boolean, allowArrow?: true): TwingArrayNode;
parseAssignmentExpression(stream: TwingTokenStream): ArgumentsNode<TwingAssignmentNode>;
parseAssignmentExpression(stream: TwingTokenStream): TwingWrapperNode<TwingAssignmentNode>;
parseExpression(stream: TwingTokenStream, precedence?: number, allowArrow?: true): TwingBaseExpressionNode;
parseExpression(stream: TwingTokenStream, precedence?: number, allowArrow?: true): TwingExpressionNode;
parseFilterDefinitions(stream: TwingTokenStream): Array<{
name: string;
@ -129,7 +127,7 @@ export interface TwingParser {
parseFilterExpressionRaw(stream: TwingTokenStream, node: TwingBaseExpressionNode, tag?: string | null): TwingFilterNode;
parseMultiTargetExpression(stream: TwingTokenStream): TwingBaseExpressionNode;
parseMultiTargetExpression(stream: TwingTokenStream): TwingWrapperNode;
peekBlockStack(): string;
@ -244,7 +242,9 @@ export const createParser = (
const stack: Array<StackEntry> = [];
const addImportedSymbol: TwingParser["addImportedSymbol"] = (type, alias, name?: string, node?: NodeWithName) => {
const addImportedSymbol: TwingParser["addImportedSymbol"] = (type, alias, name?: string, node?: TwingBaseNode<any, {
name: string;
}>) => {
const localScope = importedSymbols[0];
if (type === "method") {
@ -264,7 +264,13 @@ export const createParser = (
// checks that the node only contains "constant" elements
const checkConstantExpression = (stackEntry: TwingTokenStream, node: TwingBaseNode): TwingBaseNode | null => {
if (!(node.is("constant") || node.is("array") || node.is(hashNodeType) || node.is(negativeNodeType) || node.is(positiveNodeType))) {
if (!(
(node as TwingNode).type === "constant"
|| (node as TwingNode).type === "array"
|| (node as TwingNode).type === "hash"
|| (node as TwingNode).type === "negative"
|| (node as TwingNode).type === "positive"
)) {
return node;
}
@ -285,8 +291,10 @@ export const createParser = (
const filterChildBodyNode = (stream: TwingTokenStream, node: TwingBaseNode, nested: boolean = false): TwingBaseNode | null => {
// non-empty text nodes are not allowed as direct child of a
if (node.is(textNodeType) && !isMadeOfWhitespaceOnly(node.attributes.data)) {
const {data} = node.attributes;
const testedNode = node as TwingNode;
if (testedNode.type === "text" && !isMadeOfWhitespaceOnly(testedNode.attributes.data)) {
const {data} = testedNode.attributes;
if (data.indexOf(String.fromCharCode(0xEF, 0xBB, 0xBF)) > -1) {
const trailingData = data.substring(3);
@ -335,11 +343,11 @@ export const createParser = (
// here, nested means "being at the root level of a child template"
// we need to discard the wrapping node for the "body" node
nested = nested || (node.type !== null);
nested = nested || (node.type !== "wrapper");
for (let [key, child] of getChildren(node)) {
for (const [key, child] of getChildren(node)) {
if (child !== null && (filterChildBodyNode(stream, child, nested) === null)) {
delete node.children[key];
delete (node.children as any)[key];
}
}
@ -554,7 +562,7 @@ export const createParser = (
stream.next();
const expression = parseExpression(stream);
stream.expect("PUNCTUATION", ')', 'An opened parenthesis is not properly closed');
return parsePostfixExpression(stream, expression, token);
@ -751,7 +759,7 @@ export const createParser = (
value: TwingBaseExpressionNode;
}> = [];
let value: TwingBaseExpressionNode;
let value: TwingExpressionNode;
let token: Token;
stream.expect("PUNCTUATION", '(');
@ -775,7 +783,7 @@ export const createParser = (
let key: TwingConstantNode | undefined = undefined;
if (namedArguments && (token = stream.nextIf("OPERATOR", '='))) {
if (!value.is("name")) {
if (value.type !== "name") {
throw createParsingError(`A parameter name must be a string, "${value.type.toString()}" given.`, value, stream.source.name);
}
@ -838,12 +846,12 @@ export const createParser = (
if (stream.test("SPREAD_OPERATOR")) {
const {current} = stream;
stream.next();
const expression = parseExpression(stream);
const spreadNode = createSpreadNode(expression, current.line, current.column);
elements.push(spreadNode);
}
else {
@ -887,8 +895,8 @@ export const createParser = (
break;
}
}
return createArgumentsNode(targets, line, column);
return createWrapperNode(targets, line, column);
};
const parseArrow = (stream: TwingTokenStream): TwingArrowFunctionNode | null => {
@ -1151,7 +1159,7 @@ export const createParser = (
key: createBaseNode(null),
value: spreadNode
});
continue;
}
@ -1173,7 +1181,7 @@ export const createParser = (
key,
value: createNameNode(token.value, token.line, token.column)
});
continue;
}
}
@ -1220,7 +1228,7 @@ export const createParser = (
}
}
return createArgumentsNode(targets, line, column);
return createWrapperNode(targets, line, column);
};
const parseNotTestExpression = (stream: TwingTokenStream, node: TwingBaseExpressionNode): TwingBaseExpressionNode => {
@ -1371,10 +1379,10 @@ export const createParser = (
return expression;
};
const parseSubscriptExpression = (stream: TwingTokenStream, node: TwingBaseExpressionNode, prefixToken: Token) => {
const parseSubscriptExpression = (stream: TwingTokenStream, node: TwingExpressionNode, prefixToken: Token) => {
let token = stream.next();
let attribute: TwingBaseExpressionNode;
let type: TwingGetAttributeCallType = "any";
let type: TwingAttributeAccessorCallType = "any";
const {line, column} = token;
const {line: prefixTokenLine, column: prefixTokenColumn} = prefixToken;
@ -1410,7 +1418,7 @@ export const createParser = (
throw createParsingError('Expected name or number.', {line, column: column + 1}, stream.source.name);
}
if ((node.is("name")) && (node.attributes.name === '_self' || getImportedTemplate(node.attributes.name))) {
if ((node.type === "name") && (node.attributes.name === '_self' || getImportedTemplate(node.attributes.name))) {
const name = (attribute as TwingConstantNode<string>).attributes.value;
const methodCallNode = createMethodCallNode(node, name, createArrayNodeFromElements(), line, column);
@ -1469,7 +1477,7 @@ export const createParser = (
return createAttributeAccessorNode(node, attribute, createArrayNodeFromElements(), type, prefixTokenLine, prefixTokenColumn);
};
const parseTestExpression = (stream: TwingTokenStream, node: TwingBaseExpressionNode): TwingBaseExpressionNode => {
const parseTestExpression = (stream: TwingTokenStream, node: TwingExpressionNode): TwingBaseExpressionNode => {
const {line, column} = stream.current;
const name = getTestName(stream);
@ -1479,7 +1487,7 @@ export const createParser = (
testArguments = parseArguments(stream, true);
}
if ((name === 'defined') && (node.is("name"))) {
if ((name === 'defined') && (node.type === "name")) {
const alias = getImportedMethod(node.attributes.name);
if (alias !== null) {
@ -1569,7 +1577,7 @@ export const createParser = (
return children[0];
}
return createBaseNode(null, {}, children, line, column);
return createWrapperNode(children, line, column);
}
if (!tokenParsers.has(token.value)) {
@ -1626,7 +1634,7 @@ export const createParser = (
return children[0];
}
return createBaseNode(null, {}, children, line, column);
return createWrapperNode(children, line, column);
};
const parser = {

View File

@ -3,7 +3,7 @@ import type {TwingSandboxSecurityNotAllowedFunctionError} from "./security-not-a
import type {TwingSandboxSecurityNotAllowedMethodError} from "./security-not-allowed-method-error";
import type {TwingSandboxSecurityNotAllowedPropertyError} from "./security-not-allowed-property-error";
import type {TwingSandboxSecurityNotAllowedTagError} from "./security-not-allowed-tag-error";
import {createBaseError, ErrorLocation, TwingBaseError} from "../error/base";
import {createBaseError, TwingErrorLocation, TwingBaseError} from "../error/base";
export type TwingSandboxSecurityError =
| TwingSandboxSecurityNotAllowedFilterError
@ -21,7 +21,7 @@ export const sandboxSecurityErrorName = 'TwingSandboxSecurityError';
export interface BaseSandboxSecurityError extends TwingBaseError<typeof sandboxSecurityErrorName> {
}
export const createBaseSandboxSecurityError = (message: string, location?: ErrorLocation, source?: string) => {
export const createBaseSandboxSecurityError = (message: string, location?: TwingErrorLocation, source?: string) => {
const error = createBaseError(sandboxSecurityErrorName, message, location, source);
Error.captureStackTrace(error, createBaseSandboxSecurityError);

View File

@ -3,7 +3,7 @@ import {
createBaseSandboxSecurityError,
TwingSandboxSecurityError
} from "./security-error";
import {ErrorLocation} from "../error/base";
import {TwingErrorLocation} from "../error/base";
/**
* Exception thrown when a not allowed filter is used in a template.
@ -12,7 +12,7 @@ export interface TwingSandboxSecurityNotAllowedFilterError extends BaseSandboxSe
readonly filterName: string;
}
export const createSandboxSecurityNotAllowedFilterError = (message: string, filterName: string, location?: ErrorLocation, source?: string): TwingSandboxSecurityNotAllowedFilterError => {
export const createSandboxSecurityNotAllowedFilterError = (message: string, filterName: string, location?: TwingErrorLocation, source?: string): TwingSandboxSecurityNotAllowedFilterError => {
const error = createBaseSandboxSecurityError(message, location, source);
Error.captureStackTrace(error, createSandboxSecurityNotAllowedFilterError);

View File

@ -1,11 +1,11 @@
import {BaseSandboxSecurityError, createBaseSandboxSecurityError} from "./security-error";
import {ErrorLocation} from "../error/base";
import {TwingErrorLocation} from "../error/base";
export interface TwingSandboxSecurityNotAllowedFunctionError extends BaseSandboxSecurityError {
readonly functionName: string;
}
export const createSandboxSecurityNotAllowedFunctionError = (message: string, functionName: string, location?: ErrorLocation, source?: string): TwingSandboxSecurityNotAllowedFunctionError => {
export const createSandboxSecurityNotAllowedFunctionError = (message: string, functionName: string, location?: TwingErrorLocation, source?: string): TwingSandboxSecurityNotAllowedFunctionError => {
const error = createBaseSandboxSecurityError(message, location, source);
Error.captureStackTrace(error, createSandboxSecurityNotAllowedFunctionError);

View File

@ -1,10 +1,10 @@
import {BaseSandboxSecurityError, createBaseSandboxSecurityError} from "./security-error";
import {ErrorLocation} from "../error/base";
import {TwingErrorLocation} from "../error/base";
export interface TwingSandboxSecurityNotAllowedMethodError extends BaseSandboxSecurityError {
}
export const createSandboxSecurityNotAllowedMethodError = (message: string, location?: ErrorLocation, source?: string): TwingSandboxSecurityNotAllowedMethodError => {
export const createSandboxSecurityNotAllowedMethodError = (message: string, location?: TwingErrorLocation, source?: string): TwingSandboxSecurityNotAllowedMethodError => {
const error = createBaseSandboxSecurityError(message, location, source);
Error.captureStackTrace(error, createSandboxSecurityNotAllowedMethodError);

Some files were not shown because too many files have changed in this diff Show More