Merge branch 'issue-612' into 'milestone/7.0.0'

Resolve issue #612

See merge request nightlycommit/twing!606
This commit is contained in:
Eric MORAND 2024-03-18 10:44:06 +00:00
commit c97a2c3c0b
10 changed files with 94 additions and 9 deletions

View File

@ -26,8 +26,10 @@ import {TwingParsingError} from "./error/parsing";
import {createLexer, TwingLexer} from "./lexer";
import {TwingCache} from "./cache";
import {createCoreExtension} from "./extension/core";
import {createAutoEscapeNode, createTemplateLoadingError} from "../lib";
import {createAutoEscapeNode, createTemplateLoadingError, type TwingContext} from "../lib";
import {createTemplateLoader} from "./template-loader";
import {createContext} from "./context";
import {iterableToMap} from "./helpers/iterator-to-map";
export type TwingNumberFormat = {
numberOfDecimals: number;
@ -54,6 +56,7 @@ export type TwingEnvironmentOptions = {
charset?: string;
dateFormat?: string;
dateIntervalFormat?: string;
globals?: Record<string, any>;
numberFormat?: TwingNumberFormat;
parserOptions?: TwingParserOptions;
sandboxPolicy?: TwingSandboxSecurityPolicy;
@ -69,6 +72,7 @@ export interface TwingEnvironment {
readonly numberFormat: TwingNumberFormat;
readonly filters: Map<string, TwingFilter>;
readonly functions: Map<string, TwingFunction>;
readonly globals: TwingContext<string, any>;
readonly loader: TwingLoader;
readonly sandboxPolicy: TwingSandboxSecurityPolicy;
readonly tests: Map<string, TwingTest>;
@ -183,6 +187,7 @@ export const createEnvironment = (
thousandSeparator: ','
};
const sandboxPolicy = options?.sandboxPolicy || createSandboxSecurityPolicy();
const globals = createContext(iterableToMap(options?.globals || {}));
let lexer: TwingLexer;
let parser: TwingParser;
@ -209,6 +214,9 @@ export const createEnvironment = (
get functions() {
return extensionSet.functions;
},
get globals() {
return globals;
},
get loader() {
return loader;
},

View File

@ -27,3 +27,5 @@ export const iteratorToMap = (thing: any): Map<any, any> => {
return result;
}
};
export const iterableToMap = iteratorToMap;

View File

@ -2,6 +2,8 @@ import {TwingNodeExecutor} from "../../node-executor";
import {TwingNameNode} from "../../node/expression/name";
import {getTraceableMethod} from "../../helpers/traceable-method";
import {getContextValue} from "../../helpers/get-context-value";
import {mergeIterables} from "../../helpers/merge-iterables";
import {createContext} from "../../context";
export const executeNameNode: TwingNodeExecutor<TwingNameNode> = (node, {
template,
@ -22,7 +24,7 @@ export const executeNameNode: TwingNodeExecutor<TwingNameNode> = (node, {
environment.charset,
template.name,
strict,
context,
createContext(mergeIterables(environment.globals, context)),
name,
isAlwaysDefined,
shouldIgnoreStrictCheck,

View File

@ -19,14 +19,9 @@ export const executeForNode: TwingNodeExecutor<TwingForNode> = async (forNode, e
context.set('_parent', context.clone());
const executedSequence: TwingContext<any, any> | any = await execute(sequenceNode, executionContext);
const sequence = ensureTraversable(executedSequence);
let sequence = ensureTraversable(executedSequence);
if (sequence === context) {
context.set('_seq', context.clone());
} else {
context.set('_seq', sequence);
}
context.set('_seq', sequence);
if (elseNode) {
context.set('_iterated', false);

View File

@ -0,0 +1,18 @@
import {runTest} from "../TestBase";
runTest({
description: 'globals',
templates: {
"index.twig": `{{ foo }}, {{ bar }}`
},
environmentOptions: {
globals: {
foo: 'foo from globals',
bar: 'bar from globals'
}
},
context: Promise.resolve({
bar: 'bar from context'
}),
expectation: `foo from globals, bar from context`
});

View File

@ -0,0 +1,2 @@
import "./basic";
import "./with-include";

View File

@ -0,0 +1,43 @@
import {runTest} from "../TestBase";
runTest({
description: 'globals with include',
templates: {
"index.twig": `{{ include("foo") }}`,
'foo': `{{ title }}`
},
environmentOptions: {
globals: {
title: 'foo'
}
},
expectation: `foo`
});
runTest({
description: 'globals with include, when shadowed',
templates: {
"index.twig": `{{ include("foo", {title: "bar"}) }}`,
'foo': `{{ title }}`
},
environmentOptions: {
globals: {
title: 'foo'
}
},
expectation: `bar`
});
runTest({
description: 'globals with include and only',
templates: {
"index.twig": `{{ include("foo", {}, true) }}`,
'foo': `{{ title }}`
},
environmentOptions: {
globals: {
title: 'foo'
}
},
expectation: `foo`
});

View File

@ -8,6 +8,7 @@ import "./expressions";
import "./extensions";
import "./filters";
import "./functions";
import "./globals";
import "./implicit-auto-escaping";
import "./macros";
import "./operators";

View File

@ -0,0 +1,13 @@
import {runTest} from "../../TestBase";
runTest({
description: '"for" tag with context as sequence',
templates: {
"index.twig": `{% for key, value in _context %}{{ key }}{{ value }}{% endfor %}`
},
expectation: `foofoo valuebarbar value_parent[object Object]`,
context: Promise.resolve({
foo: 'foo value',
bar: 'bar value'
})
});

View File

@ -3,6 +3,7 @@ import "./condition.legacy";
import "./condition_and_nested_for_loop_access";
import "./containing_with";
import "./context";
import "./context-as-sequence";
import "./hashes";
import "./inner_variables";
import "./inside_with";