mirror of
https://gitlab.com/nightlycommit/twing.git
synced 2025-01-18 08:46:50 +02:00
Merge branch 'issue-598' into 'main'
Resolve issue #598 Closes #598 See merge request nightlycommit/twing!594
This commit is contained in:
commit
c94bd15a47
200
src/lib.ts
200
src/lib.ts
@ -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";
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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();
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
/**
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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;
|
||||
|
@ -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";
|
||||
|
@ -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,
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
);
|
||||
};
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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 = (
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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
|
||||
};
|
||||
};
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
};
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
@ -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);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}> {
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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)))
|
||||
}
|
||||
|
@ -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)))
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
);
|
||||
};
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
);
|
||||
};
|
||||
|
@ -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
|
||||
);
|
||||
};
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -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));
|
@ -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));
|
||||
|
@ -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));
|
@ -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;
|
||||
};
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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
17
src/lib/node/wrapper.ts
Normal 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);
|
||||
};
|
@ -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;
|
||||
|
@ -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 = {
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user