Skip to content

Conformance Examples 0.1.0 — Render: standalone-stripping

standalone-with-block-strips-indentation-and-newline-without-tilde

A #with block open/close tag alone on its own line (only surrounding whitespace) has that line's leading indentation and trailing newline stripped implicitly, with no ~ marker.

Template

before
  {{#with y }}
  Z
  {{/with}}
after

Context

{
    "y": {}
}

Output

before
  Z
after

standalone-each-block-strips-indentation-and-newline-every-iteration

A standalone #each block's open/close lines are stripped once from the loop body's own AST, so every iteration renders without the extra indentation/newline.

Template

{{#each items }}
  {{ this }}
{{/each}}

Context

{
    "items": [
        "a",
        "b"
    ]
}

Output

  a
  b

nested-standalone-blocks-each-stripped-independently

Nested standalone blocks each have their own line's indentation and trailing newline removed.

Template

{{#if a }}
  {{#if b }}
  X
  {{/if}}
{{/if}}

Context

{
    "a": true,
    "b": true
}

Output

  X

standalone-else-strips-indentation-and-newlines-without-tilde

A standalone {{else}} tag has the indentation before it and the newline after it stripped implicitly, matching the {{#each}}/{{/each}} standalone stripping on the same block.

Template

{{#each items }}
X
{{else}}
Y
{{/each}}

Context

{
    "items": []
}

Output

Y

standalone-comment-strips-indentation-and-newline-without-tilde

A comment tag alone on its own line is stripped implicitly; the comment itself never renders anything regardless.

Template

before
  {{! a note }}
after

Output

before
after

standalone-assign-strips-indentation-and-newline-without-tilde

An assign tag alone on its own line is stripped implicitly; the tag itself never renders anything regardless.

Template

before
  {{= @local/t = "Lo" }}
after{{ @local/t }}

Output

before
afterLo

non-standalone-block-tag-is-not-stripped

A block tag that shares its line with real template text on both sides is not standalone, so no implicit stripping happens on either side, even without ~.

Template

before  {{#with y }}Z{{/with}}  after

Context

{
    "y": {}
}

Output

before  Z  after

non-standalone-open-tag-still-standalone-close-tag

A block open tag that shares its line with body text is not standalone, but its close tag — alone on its own line — is independently evaluated and still gets stripped.

Template

before
  {{#with y }}Z
  {{/with}}
after

Context

{
    "y": {}
}

Output

before
  Z
after

interpolation-is-exempt-from-standalone-stripping

An interpolation alone on its own line is never treated as standalone (Mustache rule); the surrounding indentation and newlines are left untouched.

Template

before
  {{ x }}
after

Context

{
    "x": "X"
}

Output

before
  X
after

standalone-comment-strips-indentation-and-newline-over-crlf

Standalone detection and stripping work the same over CRLF line endings as over LF: the carriage return immediately before the tag's newline is treated as part of the newline sequence, not as line content, and is removed along with the newline it belongs to.

Template

before
  {{! a note }}
after

Output

before
after

standalone-tag-at-start-of-template-has-no-leading-text-to-strip

A standalone tag with no preceding template text at all (the very start of the template) is standalone regardless — a missing neighbor counts as whitespace on that side, the same as an empty Text segment would.

Template

{{! a note }}
after

Output

after

standalone-tag-at-end-of-template-has-no-trailing-text-to-strip

A standalone tag with no following template text at all (the very end of the template) is standalone regardless — a missing neighbor counts as whitespace on that side, the same as an empty Text segment would. Standalone stripping only removes the preceding line's indentation (space/tab) and the tag's own trailing newline (via the following text); it never removes the newline ending the line before the tag, so that newline survives here since there is no following text to strip a newline from.

Template

before
  {{! a note }}

Output

before

raw-block-on-shared-line-prevents-standalone-detection

A raw block is real line content, not whitespace: a block-close tag that would otherwise be standalone is not standalone when it shares its line with a raw block, so neither tag's surrounding whitespace is stripped.

Template

{{#if a }}
X
{{{{ raw content }}}}{{/if}}
after

Context

{
    "a": true
}

Output

X
 raw content 
after

escaped-delimiter-on-shared-line-prevents-standalone-detection

An escaped delimiter ({{) is real line content, not whitespace: a block-close tag sharing its line with one is not standalone, so its surrounding whitespace is left untouched.

Template

{{#if a }}
X
{{/if}}\{{ literal
after

Context

{
    "a": true
}

Output

X
{{ literal
after

if-block-empty-arm-body-and-non-empty-else-not-standalone

An empty if-arm body places the #if tag adjacent to the {{else}} tag on the same line (content, not a boundary), so neither is standalone: no implicit stripping happens on either side.

Template

before
  {{#if b }}{{else}}Y{{/if}}
after

Context

{
    "b": false
}

Output

before
  Y
after

if-block-empty-body-no-else-not-standalone

An empty if body places the #if tag adjacent to the {{/if}} tag on the same line (content, not a boundary), so neither is standalone: no implicit stripping happens on either side.

Template

before
  {{#if a }}{{/if}}
after

Context

{
    "a": true
}

Output

before

after

if-block-else-and-close-share-line-with-empty-else-body-open-side-still-standalone

An empty else body places the {{else}} tag adjacent to the {{/if}} tag on the same line, so that boundary is not standalone; but the #if open tag's own line is unaffected and remains standalone.

Template

{{#if a }}
X
  {{else}}{{/if}}
after

Context

{
    "a": false
}

Output

after

each-block-empty-body-no-else-not-standalone

An empty each body places the #each tag adjacent to the {{/each}} tag on the same line (content, not a boundary), so neither is standalone: no implicit stripping happens on either side.

Template

before
  {{#each xs }}{{/each}}
after

Context

{
    "xs": []
}

Output

before

after

unless-block-empty-body-no-else-not-standalone

An empty unless body places the #unless tag adjacent to the {{/unless}} tag on the same line (content, not a boundary), so neither is standalone: no implicit stripping happens on either side.

Template

before
  {{#unless a }}{{/unless}}
after

Context

{
    "a": false
}

Output

before

after

if-block-else-if-two-empty-arm-bodies-no-else-not-standalone

Two consecutive empty if/else-if arm bodies place every flanking tag adjacent to its neighbor on the same line, so no boundary in the chain is standalone.

Template

before
  {{#if a }}{{else if b }}{{/if}}
after

Context

{
    "a": false,
    "b": false
}

Output

before

after

if-block-else-if-following-non-empty-prior-arm-not-standalone

An empty else-if arm body places the {{else if b}} tag adjacent to the {{/if}} tag on the same line, so that boundary is not standalone, regardless of the prior arm's body content.

Template

before
  {{#if a }}X{{else if b }}{{/if}}
after

Context

{
    "a": false,
    "b": true
}

Output

before

after

each-block-empty-body-non-empty-else-else-still-standalone-both-sides

An empty each body places the #each tag adjacent to the {{else}} tag on the same line, so that boundary is not standalone; but the {{else}}/{{/each}} boundary is unaffected and remains standalone on both sides.

Template

{{#each xs }}{{else}}
Z
{{/each}}

Context

{
    "xs": []
}

Output

Z

with-block-empty-body-not-standalone

An empty with body places the #with tag adjacent to the {{/with}} tag on the same line (content, not a boundary), so neither is standalone: no implicit stripping happens on either side.

Template

before
  {{#with y }}{{/with}}
after

Context

{
    "y": {}
}

Output

before

after

nested-block-close-abutting-parent-close-stays-standalone

A guard against over-fixing the empty-region rule: a nested block's close tag abutting its parent's close tag is parent-adjacency (an outer-sibling boundary), not an empty inner region, so the nested block's own standalone stripping still applies.

Template

{{#with y }}
{{#if a }}
X
{{/if}}{{/with}}
after

Context

{
    "y": {},
    "a": true
}

Output

after

Source fixture: render/standalone-stripping.json