summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Appel <Dan.appel00@gmail.com>2021-04-27 18:42:21 -0700
committerGitHub <noreply@github.com>2021-04-27 18:42:21 -0700
commit63c0bde1f4e2f8ee26cf2d869dcb0f4fc215646d (patch)
tree1803a509dfb14fa1b699d5d600ecf54ddff604a8
parentb1329a25e6d265ff360267d23f7c6327bbf59f52 (diff)
parent4945a323d2135e857bd38dfcce0fc1b800f59d33 (diff)
downloadmustache-spec-63c0bde1f4e2f8ee26cf2d869dcb0f4fc215646d.tar.gz
Merge pull request #125 from jgonggrijp/optional-inheritance-specv1.2.0
Optional inheritance spec
-rw-r--r--specs/~inheritance.json235
-rw-r--r--specs/~inheritance.yml226
2 files changed, 461 insertions, 0 deletions
diff --git a/specs/~inheritance.json b/specs/~inheritance.json
new file mode 100644
index 0000000..fedb34b
--- /dev/null
+++ b/specs/~inheritance.json
@@ -0,0 +1,235 @@
+{
+ "__ATTN__": "Do not edit this file; changes belong in the appropriate YAML file.",
+ "overview": "Like partials, Parent tags are used to expand an external template into the\ncurrent template. Unlike partials, Parent tags may contain optional\narguments delimited by Block tags. For this reason, Parent tags may also be\nreferred to as Parametric Partials.\n\nThe Parent tags' content MUST be a non-whitespace character sequence NOT\ncontaining the current closing delimiter; each Parent tag MUST be followed by\nan End Section tag with the same content within the matching Parent tag.\n\nThis tag's content names the Parent template to inject. Set Delimiter tags\nPreceding a Parent tag MUST NOT affect the parsing of the injected external\ntemplate. The Parent MUST be rendered against the context stack local to the\ntag. If the named Parent cannot be found, the empty string SHOULD be used\ninstead, as in interpolations.\n\nParent tags SHOULD be treated as standalone when appropriate. If this tag is\nused standalone, any whitespace preceding the tag should be treated as\nindentation, and prepended to each line of the Parent before rendering.\n\nThe Block tags' content MUST be a non-whitespace character sequence NOT\ncontaining the current closing delimiter. Each Block tag MUST be followed by\nan End Section tag with the same content within the matching Block tag. This\ntag's content determines the parameter or argument name.\n\nBlock tags may appear both inside and outside of Parent tags. In both cases,\nthey specify a position within the template that can be overridden; it is a\nparameter of the containing template. The template text between the Block tag\nand its matching End Section tag defines the default content to render when\nthe parameter is not overridden from outside.\n\nIn addition, when used inside of a Parent tag, the template text between a\nBlock tag and its matching End Section tag defines content that replaces the\ndefault defined in the Parent template. This content is the argument passed\nto the Parent template.\n\nThe practice of injecting an external template using a Parent tag is referred\nto as inheritance. If the Parent tag includes a Block tag that overrides a\nparameter of the Parent template, this may also be referred to as\nsubstitution.\n\nParent templates are taken from the same namespace as regular Partial\ntemplates and in fact, injecting a regular Partial is exactly equivalent to\ninjecting a Parent without making any substitutions. Parameter and arguments\nnames live in a namespace that is distinct from both Partials and the context.\n",
+ "tests": [
+ {
+ "name": "Default",
+ "desc": "Default content should be rendered if the block isn't overridden",
+ "data": {
+ },
+ "template": "{{$title}}Default title{{/title}}\n",
+ "expected": "Default title\n"
+ },
+ {
+ "name": "Variable",
+ "desc": "Default content renders variables",
+ "data": {
+ "bar": "baz"
+ },
+ "template": "{{$foo}}default {{bar}} content{{/foo}}\n",
+ "expected": "default baz content\n"
+ },
+ {
+ "name": "Triple Mustache",
+ "desc": "Default content renders triple mustache variables",
+ "data": {
+ "bar": "<baz>"
+ },
+ "template": "{{$foo}}default {{{bar}}} content{{/foo}}\n",
+ "expected": "default <baz> content\n"
+ },
+ {
+ "name": "Sections",
+ "desc": "Default content renders sections",
+ "data": {
+ "bar": {
+ "baz": "qux"
+ }
+ },
+ "template": "{{$foo}}default {{#bar}}{{baz}}{{/bar}} content{{/foo}}\n",
+ "expected": "default qux content\n"
+ },
+ {
+ "name": "Negative Sections",
+ "desc": "Default content renders negative sections",
+ "data": {
+ "baz": "three"
+ },
+ "template": "{{$foo}}default {{^bar}}{{baz}}{{/bar}} content{{/foo}}\n",
+ "expected": "default three content\n"
+ },
+ {
+ "name": "Mustache Injection",
+ "desc": "Mustache injection in default content",
+ "data": {
+ "bar": {
+ "baz": "{{qux}}"
+ }
+ },
+ "template": "{{$foo}}default {{#bar}}{{baz}}{{/bar}} content{{/foo}}\n",
+ "expected": "default {{qux}} content\n"
+ },
+ {
+ "name": "Inherit",
+ "desc": "Default content rendered inside inherited templates",
+ "data": {
+ },
+ "template": "{{<include}}{{/include}}\n",
+ "partials": {
+ "include": "{{$foo}}default content{{/foo}}"
+ },
+ "expected": "default content"
+ },
+ {
+ "name": "Overridden content",
+ "desc": "Overridden content",
+ "data": {
+ },
+ "template": "{{<super}}{{$title}}sub template title{{/title}}{{/super}}",
+ "partials": {
+ "super": "...{{$title}}Default title{{/title}}..."
+ },
+ "expected": "...sub template title..."
+ },
+ {
+ "name": "Data does not override block",
+ "desc": "Context does not override argument passed into parent",
+ "data": {
+ "var": "var in data"
+ },
+ "template": "{{<include}}{{$var}}var in template{{/var}}{{/include}}",
+ "partials": {
+ "include": "{{$var}}var in include{{/var}}"
+ },
+ "expected": "var in template"
+ },
+ {
+ "name": "Data does not override block default",
+ "desc": "Context does not override default content of block",
+ "data": {
+ "var": "var in data"
+ },
+ "template": "{{<include}}{{/include}}",
+ "partials": {
+ "include": "{{$var}}var in include{{/var}}"
+ },
+ "expected": "var in include"
+ },
+ {
+ "name": "Overridden parent",
+ "desc": "Overridden parent",
+ "data": {
+ },
+ "template": "test {{<parent}}{{$stuff}}override{{/stuff}}{{/parent}}",
+ "partials": {
+ "parent": "{{$stuff}}...{{/stuff}}"
+ },
+ "expected": "test override"
+ },
+ {
+ "name": "Two overridden parents",
+ "desc": "Two overridden parents with different content",
+ "data": {
+ },
+ "template": "test {{<parent}}{{$stuff}}override1{{/stuff}}{{/parent}} {{<parent}}{{$stuff}}override2{{/stuff}}{{/parent}}\n",
+ "partials": {
+ "parent": "|{{$stuff}}...{{/stuff}}{{$default}} default{{/default}}|"
+ },
+ "expected": "test |override1 default| |override2 default|\n"
+ },
+ {
+ "name": "Override parent with newlines",
+ "desc": "Override parent with newlines",
+ "data": {
+ },
+ "template": "{{<parent}}{{$ballmer}}\npeaked\n\n:(\n{{/ballmer}}{{/parent}}",
+ "partials": {
+ "parent": "{{$ballmer}}peaking{{/ballmer}}"
+ },
+ "expected": "peaked\n\n:(\n"
+ },
+ {
+ "name": "Inherit indentation",
+ "desc": "Inherit indentation when overriding a parent",
+ "data": {
+ },
+ "template": "{{<parent}}{{$nineties}}hammer time{{/nineties}}{{/parent}}",
+ "partials": {
+ "parent": "stop:\n {{$nineties}}collaborate and listen{{/nineties}}\n"
+ },
+ "expected": "stop:\n hammer time\n"
+ },
+ {
+ "name": "Only one override",
+ "desc": "Override one parameter but not the other",
+ "data": {
+ },
+ "template": "{{<parent}}{{$stuff2}}override two{{/stuff2}}{{/parent}}",
+ "partials": {
+ "parent": "{{$stuff}}new default one{{/stuff}}, {{$stuff2}}new default two{{/stuff2}}"
+ },
+ "expected": "new default one, override two"
+ },
+ {
+ "name": "Parent template",
+ "desc": "Parent templates behave identically to partials when called with no parameters",
+ "data": {
+ },
+ "template": "{{>parent}}|{{<parent}}{{/parent}}",
+ "partials": {
+ "parent": "{{$foo}}default content{{/foo}}"
+ },
+ "expected": "default content|default content"
+ },
+ {
+ "name": "Recursion",
+ "desc": "Recursion in inherited templates",
+ "data": {
+ },
+ "template": "{{<parent}}{{$foo}}override{{/foo}}{{/parent}}",
+ "partials": {
+ "parent": "{{$foo}}default content{{/foo}} {{$bar}}{{<parent2}}{{/parent2}}{{/bar}}",
+ "parent2": "{{$foo}}parent2 default content{{/foo}} {{<parent}}{{$bar}}don't recurse{{/bar}}{{/parent}}"
+ },
+ "expected": "override override override don't recurse"
+ },
+ {
+ "name": "Multi-level inheritance",
+ "desc": "Top-level substitutions take precedence in multi-level inheritance",
+ "data": {
+ },
+ "template": "{{<parent}}{{$a}}c{{/a}}{{/parent}}",
+ "partials": {
+ "parent": "{{<older}}{{$a}}p{{/a}}{{/older}}",
+ "older": "{{<grandParent}}{{$a}}o{{/a}}{{/grandParent}}",
+ "grandParent": "{{$a}}g{{/a}}"
+ },
+ "expected": "c"
+ },
+ {
+ "name": "Multi-level inheritance, no sub child",
+ "desc": "Top-level substitutions take precedence in multi-level inheritance",
+ "data": {
+ },
+ "template": "{{<parent}}{{/parent}}",
+ "partials": {
+ "parent": "{{<older}}{{$a}}p{{/a}}{{/older}}",
+ "older": "{{<grandParent}}{{$a}}o{{/a}}{{/grandParent}}",
+ "grandParent": "{{$a}}g{{/a}}"
+ },
+ "expected": "p"
+ },
+ {
+ "name": "Text inside parent",
+ "desc": "Ignores text inside parent templates, but does parse $ tags",
+ "data": {
+ },
+ "template": "{{<parent}} asdfasd {{$foo}}hmm{{/foo}} asdfasdfasdf {{/parent}}",
+ "partials": {
+ "parent": "{{$foo}}default content{{/foo}}"
+ },
+ "expected": "hmm"
+ },
+ {
+ "name": "Text inside parent",
+ "desc": "Allows text inside a parent tag, but ignores it",
+ "data": {
+ },
+ "template": "{{<parent}} asdfasd asdfasdfasdf {{/parent}}",
+ "partials": {
+ "parent": "{{$foo}}default content{{/foo}}"
+ },
+ "expected": "default content"
+ }
+ ]
+}
diff --git a/specs/~inheritance.yml b/specs/~inheritance.yml
new file mode 100644
index 0000000..07fa081
--- /dev/null
+++ b/specs/~inheritance.yml
@@ -0,0 +1,226 @@
+overview: |
+ Like partials, Parent tags are used to expand an external template into the
+ current template. Unlike partials, Parent tags may contain optional
+ arguments delimited by Block tags. For this reason, Parent tags may also be
+ referred to as Parametric Partials.
+
+ The Parent tags' content MUST be a non-whitespace character sequence NOT
+ containing the current closing delimiter; each Parent tag MUST be followed by
+ an End Section tag with the same content within the matching Parent tag.
+
+ This tag's content names the Parent template to inject. Set Delimiter tags
+ Preceding a Parent tag MUST NOT affect the parsing of the injected external
+ template. The Parent MUST be rendered against the context stack local to the
+ tag. If the named Parent cannot be found, the empty string SHOULD be used
+ instead, as in interpolations.
+
+ Parent tags SHOULD be treated as standalone when appropriate. If this tag is
+ used standalone, any whitespace preceding the tag should be treated as
+ indentation, and prepended to each line of the Parent before rendering.
+
+ The Block tags' content MUST be a non-whitespace character sequence NOT
+ containing the current closing delimiter. Each Block tag MUST be followed by
+ an End Section tag with the same content within the matching Block tag. This
+ tag's content determines the parameter or argument name.
+
+ Block tags may appear both inside and outside of Parent tags. In both cases,
+ they specify a position within the template that can be overridden; it is a
+ parameter of the containing template. The template text between the Block tag
+ and its matching End Section tag defines the default content to render when
+ the parameter is not overridden from outside.
+
+ In addition, when used inside of a Parent tag, the template text between a
+ Block tag and its matching End Section tag defines content that replaces the
+ default defined in the Parent template. This content is the argument passed
+ to the Parent template.
+
+ The practice of injecting an external template using a Parent tag is referred
+ to as inheritance. If the Parent tag includes a Block tag that overrides a
+ parameter of the Parent template, this may also be referred to as
+ substitution.
+
+ Parent templates are taken from the same namespace as regular Partial
+ templates and in fact, injecting a regular Partial is exactly equivalent to
+ injecting a Parent without making any substitutions. Parameter and arguments
+ names live in a namespace that is distinct from both Partials and the context.
+tests:
+ - name: Default
+ desc: Default content should be rendered if the block isn't overridden
+ data: { }
+ template: |
+ {{$title}}Default title{{/title}}
+ expected: |
+ Default title
+
+ - name: Variable
+ desc: Default content renders variables
+ data: { bar: 'baz' }
+ template: |
+ {{$foo}}default {{bar}} content{{/foo}}
+ expected: |
+ default baz content
+
+ - name: Triple Mustache
+ desc: Default content renders triple mustache variables
+ data: { bar: '<baz>' }
+ template: |
+ {{$foo}}default {{{bar}}} content{{/foo}}
+ expected: |
+ default <baz> content
+
+ - name: Sections
+ desc: Default content renders sections
+ data: { bar: {baz: 'qux'} }
+ template: |
+ {{$foo}}default {{#bar}}{{baz}}{{/bar}} content{{/foo}}
+ expected: |
+ default qux content
+
+ - name: Negative Sections
+ desc: Default content renders negative sections
+ data: { baz: 'three' }
+ template: |
+ {{$foo}}default {{^bar}}{{baz}}{{/bar}} content{{/foo}}
+ expected: |
+ default three content
+
+ - name: Mustache Injection
+ desc: Mustache injection in default content
+ data: {bar: {baz: '{{qux}}'} }
+ template: |
+ {{$foo}}default {{#bar}}{{baz}}{{/bar}} content{{/foo}}
+ expected: |
+ default {{qux}} content
+
+ - name: Inherit
+ desc: Default content rendered inside inherited templates
+ data: { }
+ template: |
+ {{<include}}{{/include}}
+ partials:
+ include: "{{$foo}}default content{{/foo}}"
+ expected: "default content"
+
+ - name: Overridden content
+ desc: Overridden content
+ data: { }
+ template: "{{<super}}{{$title}}sub template title{{/title}}{{/super}}"
+ partials:
+ super: "...{{$title}}Default title{{/title}}..."
+ expected: "...sub template title..."
+
+ - name: Data does not override block
+ desc: Context does not override argument passed into parent
+ data: { var: 'var in data' }
+ template: "{{<include}}{{$var}}var in template{{/var}}{{/include}}"
+ partials:
+ include: "{{$var}}var in include{{/var}}"
+ expected: "var in template"
+
+ - name: Data does not override block default
+ desc: Context does not override default content of block
+ data: { var: 'var in data' }
+ template: "{{<include}}{{/include}}"
+ partials:
+ include: "{{$var}}var in include{{/var}}"
+ expected: "var in include"
+
+ - name: Overridden parent
+ desc: Overridden parent
+ data: { }
+ template: "test {{<parent}}{{$stuff}}override{{/stuff}}{{/parent}}"
+ partials:
+ parent: "{{$stuff}}...{{/stuff}}"
+ expected: "test override"
+
+ - name: Two overridden parents
+ desc: Two overridden parents with different content
+ data: { }
+ template: |
+ test {{<parent}}{{$stuff}}override1{{/stuff}}{{/parent}} {{<parent}}{{$stuff}}override2{{/stuff}}{{/parent}}
+ partials:
+ parent: "|{{$stuff}}...{{/stuff}}{{$default}} default{{/default}}|"
+ expected: |
+ test |override1 default| |override2 default|
+
+ - name: Override parent with newlines
+ desc: Override parent with newlines
+ data: { }
+ template: "{{<parent}}{{$ballmer}}\npeaked\n\n:(\n{{/ballmer}}{{/parent}}"
+ partials:
+ parent: "{{$ballmer}}peaking{{/ballmer}}"
+ expected: "peaked\n\n:(\n"
+
+ - name: Inherit indentation
+ desc: Inherit indentation when overriding a parent
+ data: { }
+ template: "{{<parent}}{{$nineties}}hammer time{{/nineties}}{{/parent}}"
+ partials:
+ parent: |
+ stop:
+ {{$nineties}}collaborate and listen{{/nineties}}
+ expected: |
+ stop:
+ hammer time
+
+ - name: Only one override
+ desc: Override one parameter but not the other
+ data: { }
+ template: "{{<parent}}{{$stuff2}}override two{{/stuff2}}{{/parent}}"
+ partials:
+ parent: "{{$stuff}}new default one{{/stuff}}, {{$stuff2}}new default two{{/stuff2}}"
+ expected: "new default one, override two"
+
+ - name: Parent template
+ desc: Parent templates behave identically to partials when called with no parameters
+ data: { }
+ template: "{{>parent}}|{{<parent}}{{/parent}}"
+ partials:
+ parent: "{{$foo}}default content{{/foo}}"
+ expected: "default content|default content"
+
+ - name: Recursion
+ desc: Recursion in inherited templates
+ data: {}
+ template: "{{<parent}}{{$foo}}override{{/foo}}{{/parent}}"
+ partials:
+ parent: "{{$foo}}default content{{/foo}} {{$bar}}{{<parent2}}{{/parent2}}{{/bar}}"
+ parent2: "{{$foo}}parent2 default content{{/foo}} {{<parent}}{{$bar}}don't recurse{{/bar}}{{/parent}}"
+ expected: "override override override don't recurse"
+
+ - name: Multi-level inheritance
+ desc: Top-level substitutions take precedence in multi-level inheritance
+ data: { }
+ template: "{{<parent}}{{$a}}c{{/a}}{{/parent}}"
+ partials:
+ parent: "{{<older}}{{$a}}p{{/a}}{{/older}}"
+ older: "{{<grandParent}}{{$a}}o{{/a}}{{/grandParent}}"
+ grandParent: "{{$a}}g{{/a}}"
+ expected: c
+
+ - name: Multi-level inheritance, no sub child
+ desc: Top-level substitutions take precedence in multi-level inheritance
+ data: { }
+ template: "{{<parent}}{{/parent}}"
+ partials:
+ parent: "{{<older}}{{$a}}p{{/a}}{{/older}}"
+ older: "{{<grandParent}}{{$a}}o{{/a}}{{/grandParent}}"
+ grandParent: "{{$a}}g{{/a}}"
+ expected: p
+
+ - name: Text inside parent
+ desc: Ignores text inside parent templates, but does parse $ tags
+ data: { }
+ template: "{{<parent}} asdfasd {{$foo}}hmm{{/foo}} asdfasdfasdf {{/parent}}"
+ partials:
+ parent: "{{$foo}}default content{{/foo}}"
+ expected:
+ hmm
+
+ - name: Text inside parent
+ desc: Allows text inside a parent tag, but ignores it
+ data: {}
+ template: "{{<parent}} asdfasd asdfasdfasdf {{/parent}}"
+ partials:
+ parent: "{{$foo}}default content{{/foo}}"
+ expected: default content