diff --git a/thrift/doc/contributions/whisker.md b/thrift/doc/contributions/whisker.md index bf47b056ec5..39ffa132c15 100644 --- a/thrift/doc/contributions/whisker.md +++ b/thrift/doc/contributions/whisker.md @@ -624,36 +624,180 @@ pragma-statement → { "{{" ~ "#" ~ "pragma" ~ ( "single-line" ) ~ "}}" } ### Partial Blocks & Statements -:::warning -`{{#let partial}}` blocks and `{{#partial}}` statements have not been implemented yet. -::: - -Partial blocks allow defining reusable templates within a Whisker template. They are not rendered unless *applied* (by name). A simple example of a `{{#let partial}}` block might be: +Partial blocks allow defining reusable templates within a Whisker template. They are not rendered unless *applied* (by name). +The following example of a `{{#let partial}}` block defines a partial named `greeting` that accepts a single argument named `person`: ```handlebars -{{#let partial greeting as |person|}} +{{#let partial greeting |person|}} Greetings, {{person.firstName}} {{person.lastName}}! {{/let partial}} ``` -Partial blocks must be applied with `{{#partial ...}}` statements. A simple example for a `{{#partial}}` statement for the above block might be: +Partial blocks must be rendered using `{{#partial ...}}` statements. A simple example of a `{{#partial}}` statement for the above block might be: ```handlebars {{#partial greeting person=person}} ``` -The `{{#partial}}` statement must include named arguments that are [bound](#scopes) to `expression`s, matching the captures (`as |...|`) from the definition. +The `{{#partial}}` statement must include all named arguments from the partial block being applied. +Each named argument is an `expression`, which is [bound](#scopes) to the corresponding argument (matching `|...|`) from the partial block. The contained body of the `{{#let partial}}` block is rendered with a [derived evaluation context](#derived-evaluation-context). Names accessible from the site of the application are **not** *implicitly* available within the block. ```handlebars -{{#let partial greeting as |person|}} +{{#let partial greeting |person|}} Greetings, {{person.firstName}} {{person.lastName}}! {{/let partial}} -{{> greeting person=dave}} +{{#partial greeting person=dave}} +``` + +```json title=Context +{ + "dave": { + "firstName": "Dave", + "lastName": "Grohl" + } +} +``` + +```text title=Output +Greetings, Dave Grohl! +``` + + + +To implement recursive partials, a partial can access itself by name. + + + +```handlebars +{{! https://en.wikipedia.org/wiki/Collatz_conjecture }} +{{#let partial collatz |n|}} +{{n}} + {{#if (ne? n 1)}} + {{#if (even? n)}} +{{#partial collatz n=(div n 2)}} + {{#else}} +{{#partial collatz n=(add (mul 3 n) 1)}} + {{/if (even? n)}} + {{/if (ne? n 1)}} +{{/let partial}} +{{#partial collatz n=6}} +``` + +```javascript title=Globals +{ + "even?": (n) => n % 2 == 0, + "mul": (a, b) => a * b, + "div": (a, b) => a / b, + "ne?": (a, b) => a != b, + "add": (a, b) => a + b, +} +``` + +```text title=Output +6 +3 +10 +5 +16 +8 +4 +2 +1 +``` + + + +Partial blocks and statements do not require arguments. + + + +```handlebars +{{#let partial copyright}} +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +{{/let partial}} +{{#partial copyright}} +``` + +```text title=Output +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +``` + + + +Partial blocks may have multiple arguments. The arguments may be provided in any order. + + + +```handlebars +{{#let partial greeting |firstName lastName|}} +Greetings, {{firstName}} {{lastName}}! +{{/let partial}} + +{{#partial greeting lastName=dave.lastName firstName=dave.firstName}} +``` + +```json title=Context +{ + "dave": { + "firstName": "Dave", + "lastName": "Grohl" + } +} +``` + +```text title=Output +Greetings, Dave Grohl! +``` + + + +The name of a partial block is [bound](#scopes) to an [object](#data-model) in the current evaluation context, meaning it follows normal [name resolution rules](#evaluation-context). As a result, a partial block can be passed around like any other object. + + + +```handlebars +{{#let partial greeting |firstName lastName|}} +Greetings, {{firstName}} {{lastName}}! +{{/let partial}} + +{{#let partial with-firstName-lastName |person action|}} +{{#partial action firstName=person.firstName lastName=person.lastName}} +{{/let partial}} + +{{#partial with-firstName-lastName person=dave action=greeting}} ``` ```json title=Context @@ -676,7 +820,7 @@ Partial statements retain the *preceding indentation* at the site of the applica ```handlebars title=example.whisker -{{#let partial president as |person|}} +{{#let partial president |person|}} {{person.lastName}} {{person.firstName}} {{/let partial}} @@ -715,21 +859,17 @@ Some historic presidents are: ``` -partial-block → { partial-block-open ~ body* ~ partial-block-close } -partial-block-open → { "{{#" ~ "let" ~ "partial" ~ identifier ~ partial-block-capture ~ "}}" } -partial-block-capture → { "as" ~ "|" ~ identifier+ ~ "|" } -partial-block-close → { "{{/" ~ "let" ~ "partial" ~ "}}" } +partial-block → { partial-block-open ~ body* ~ partial-block-close } +partial-block-open → { "{{#" ~ "let" ~ "partial" ~ identifier ~ partial-block-arguments? ~ "}}" } +partial-block-arguments → { "|" ~ identifier+ ~ "|" } +partial-block-close → { "{{/" ~ "let" ~ "partial" ~ "}}" } -partial-statement → { "{{" ~ "#" ~ "partial" ~ identifier ~ partial-argument+ ~ "}}" } +partial-statement → { "{{" ~ "#" ~ "partial" ~ expression ~ partial-argument* ~ "}}" } partial-argument → { identifier ~ "=" ~ expression } ``` -:::note -Partial blocks may only appear at the top of a source file. -::: - Whisker `{{#let partial}}` blocks are based on [Handlebars partial parameters](https://handlebarsjs.com/guide/partials.html#partial-parameters). ### Macros