mirror of
https://gitlab.com/nightlycommit/twing.git
synced 2025-01-18 08:46:50 +02:00
Merge branch 'issue-612' into 'milestone/7.0.0'
Resolve issue #612 See merge request nightlycommit/twing!606
This commit is contained in:
commit
c97a2c3c0b
@ -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;
|
||||
},
|
||||
|
@ -27,3 +27,5 @@ export const iteratorToMap = (thing: any): Map<any, any> => {
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
export const iterableToMap = iteratorToMap;
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
18
test/tests/integration/globals/basic.ts
Normal file
18
test/tests/integration/globals/basic.ts
Normal 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`
|
||||
});
|
2
test/tests/integration/globals/index.ts
Normal file
2
test/tests/integration/globals/index.ts
Normal file
@ -0,0 +1,2 @@
|
||||
import "./basic";
|
||||
import "./with-include";
|
43
test/tests/integration/globals/with-include.ts
Normal file
43
test/tests/integration/globals/with-include.ts
Normal 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`
|
||||
});
|
@ -8,6 +8,7 @@ import "./expressions";
|
||||
import "./extensions";
|
||||
import "./filters";
|
||||
import "./functions";
|
||||
import "./globals";
|
||||
import "./implicit-auto-escaping";
|
||||
import "./macros";
|
||||
import "./operators";
|
||||
|
13
test/tests/integration/tags/for/context-as-sequence.ts
Normal file
13
test/tests/integration/tags/for/context-as-sequence.ts
Normal 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'
|
||||
})
|
||||
});
|
@ -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";
|
||||
|
Loading…
Reference in New Issue
Block a user