Add Front Matter support to Handlebars (#17781)

Co-authored-by: fisker Cheung <lionkay@gmail.com>
This commit is contained in:
Eandfisker Cheung authored and GitHub committed 2025-10-29 23:56:19 +08:00
1 parent 17cf07e68a
commit e51ff9ad41
25 files changed
+554 -3

No files matched your search

+20
View File
@@ -0,0 +1,20 @@
#### Added Front Matter support to Handlebars (#17781 by @Codezilluh)
Front matter can now be used in Handlebars.
<!-- prettier-ignore -->
```hbs
---
title: My page title
keywords:
- word
- other word
---
<h1>{{title}}</h1>
<ul>
{{#each keywords}}
<li>{{this}}</li>
{{/each}}
</ul>
```
+3
View File
@@ -1,6 +1,9 @@
import { cleanFrontMatter } from "../utils/front-matter/index.js";
import htmlWhitespaceUtils from "../utils/html-whitespace-utils.js";
function clean(original, cloned, parent) {
cleanFrontMatter(original, cloned);
// (Glimmer/HTML) ignore TextNode
if (original.type === "TextNode") {
const trimmed = original.chars.trim();
+9
View File
@@ -1,6 +1,15 @@
import {
isEmbedFrontMatter,
printEmbedFrontMatter,
} from "../utils/front-matter/embed.js";
function embed(path /* , options*/) {
const { node } = path;
if (isEmbedFrontMatter(path)) {
return printEmbedFrontMatter;
}
if (node.type !== "TextNode") {
return;
}
+24 -2
View File
@@ -1,5 +1,6 @@
import { preprocess as parseGlimmer } from "@glimmer/syntax";
import createError from "../common/parser-create-error.js";
import parseFrontMatter from "../utils/front-matter/parse.js";
import { locEnd, locStart } from "./loc.js";
/* from the following template: `non-escaped mustache \\{{helper}}`
@@ -57,10 +58,12 @@ const glimmerParseOptions = {
plugins: { ast: [glimmerPrettierParsePlugin] },
};
function parse(text /* , options */) {
function parse(text) {
const { frontMatter, content } = parseFrontMatter(text);
let ast;
try {
ast = parseGlimmer(text, glimmerParseOptions);
ast = parseGlimmer(content, glimmerParseOptions);
} catch (error) {
const location = getErrorLocation(error);
@@ -74,6 +77,25 @@ function parse(text /* , options */) {
throw error;
}
if (frontMatter) {
const frontMatterNode = {
...frontMatter,
loc: {
start: {
...frontMatter.start,
offset: frontMatter.start.index,
},
end: {
...frontMatter.end,
offset: frontMatter.end.index,
},
},
};
// @ts-expect-error
ast.body.unshift(frontMatterNode);
}
return ast;
}
@@ -395,6 +395,9 @@ function print(path, options, print) {
case "CommentStatement":
return ["<!--", node.value, "-->"];
case "front-matter":
return node.raw;
case "StringLiteral":
return printStringLiteral(path, options);
@@ -1 +1,7 @@
export { visitorKeys as default } from "@glimmer/syntax";
import { visitorKeys } from "@glimmer/syntax";
// add front-matter to the glimmer visitor keys
export default {
...visitorKeys,
"front-matter": [],
};
@@ -0,0 +1,277 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`close.hbs format 1`] = `
====================================options=====================================
parsers: ["glimmer"]
printWidth: 80
| printWidth
=====================================input======================================
---
title: An ancient philosophy...
keywords:
- ancient
- philosophy
---
<h1>{{title}}</h1>
<p>
Keywords: {{#each keywords}}{{this}}{{#unless @last}}, {{/unless}}{{/each}}
</p>
=====================================output=====================================
---
title: An ancient philosophy...
keywords:
- ancient
- philosophy
---
<h1>{{title}}</h1>
<p>
Keywords:
{{#each keywords}}{{this}}{{#unless @last}}, {{/unless}}{{/each}}
</p>
================================================================================
`;
exports[`empty.hbs format 1`] = `
====================================options=====================================
parsers: ["glimmer"]
printWidth: 80
| printWidth
=====================================input======================================
---
---
<h1>Uh oh!</h1>
=====================================output=====================================
---
---
<h1>Uh oh!</h1>
================================================================================
`;
exports[`empty-no-newline.hbs format 1`] = `
====================================options=====================================
parsers: ["glimmer"]
printWidth: 80
| printWidth
=====================================input======================================
--- ---
=====================================output=====================================
--- ---
================================================================================
`;
exports[`explicit-language.hbs format 1`] = `
====================================options=====================================
parsers: ["glimmer"]
printWidth: 80
| printWidth
=====================================input======================================
---yaml
foo: bar
"additional information ":
- Yes
- No
data: {x:1,
y:100000000}
---
{{! Some handlebars code can go here.}}
=====================================output=====================================
---yaml
foo: bar
"additional information ":
- Yes
- No
data: { x:1, y:100000000 }
---
{{! Some handlebars code can go here.}}
================================================================================
`;
exports[`invalid-yaml.hbs format 1`] = `
====================================options=====================================
parsers: ["glimmer"]
printWidth: 80
| printWidth
=====================================input======================================
---
first: Thing
second Thing
---
<div class=" class-a"></div>
=====================================output=====================================
---
first: Thing
second Thing
---
<div class="class-a"></div>
================================================================================
`;
exports[`spaced.hbs format 1`] = `
====================================options=====================================
parsers: ["glimmer"]
printWidth: 80
| printWidth
=====================================input======================================
---
title: An ancient philosophy...
keywords:
- ancient
- philosophy
---
<h1>{{title}}</h1>
<p>
Keywords: {{#each keywords}}{{this}}{{#unless @last}}, {{/unless}}{{/each}}
</p>
=====================================output=====================================
---
title: An ancient philosophy...
keywords:
- ancient
- philosophy
---
<h1>{{title}}</h1>
<p>
Keywords:
{{#each keywords}}{{this}}{{#unless @last}}, {{/unless}}{{/each}}
</p>
================================================================================
`;
exports[`touching.hbs format 1`] = `
====================================options=====================================
parsers: ["glimmer"]
printWidth: 80
| printWidth
=====================================input======================================
---
name: Smith
--- <head>
<title>{{name}}</title>
</head>
=====================================output=====================================
---
name: Smith
---
<head>
<title>{{name}}</title>
</head>
================================================================================
`;
exports[`very-ugly-yaml.hbs format 1`] = `
====================================options=====================================
parsers: ["glimmer"]
printWidth: 80
| printWidth
=====================================input======================================
---
foo: bar
test: " word"
nest :
x: 100
y: false
"more stuff":
- do
- do
long_text: >
lots of text
content
to put here and other
places?
---
=====================================output=====================================
---
foo: bar
test: " word"
nest:
x: 100
y: false
"more stuff":
- do
- do
long_text: >
lots of text
content
to put here and other
places?
---
================================================================================
`;
exports[`yaml-format.hbs format 1`] = `
====================================options=====================================
parsers: ["glimmer"]
printWidth: 80
| printWidth
=====================================input======================================
---
title: "Example Document"
date: 1993-02-01
author:
name: Arthur Mitchell
tags:
- tutorial
- example
summary: >
A very long example document written for a person other than me, I don't know
why this is so long. Very good example... Yes!
---
<html lang="en">
<head>
<title>{{title}}</title>
</head>
<body>
{{! comment --- }}
{{summary}}
</body>
</html>
=====================================output=====================================
---
title: "Example Document"
date: 1993-02-01
author:
name: Arthur Mitchell
tags:
- tutorial
- example
summary: >
A very long example document written for a person other than me, I don't know
why this is so long. Very good example... Yes!
---
<html lang="en">
<head>
<title>{{title}}</title>
</head>
<body>
{{! comment --- }}
{{summary}}
</body>
</html>
================================================================================
`;
@@ -0,0 +1,10 @@
---
title: An ancient philosophy...
keywords:
- ancient
- philosophy
---
<h1>{{title}}</h1>
<p>
Keywords: {{#each keywords}}{{this}}{{#unless @last}}, {{/unless}}{{/each}}
</p>
@@ -0,0 +1,45 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`format-embed-off.hbs - {"embeddedLanguageFormatting":"off"} format 1`] = `
====================================options=====================================
embeddedLanguageFormatting: "off"
parsers: ["glimmer"]
printWidth: 80
| printWidth
=====================================input======================================
---
title: A very interesting subject
keywords:
- some
- keywords
- for testing
data: {x:1,
y:100000000}
---
<h1>{{title}}</h1>
<p>
Keywords: {{#each keywords}}
{{this}}{{#unless @last}}, {{/unless}}
{{/each}}
</p>
=====================================output=====================================
---
title: A very interesting subject
keywords:
- some
- keywords
- for testing
data: {x:1,
y:100000000}
---
<h1>{{title}}</h1>
<p>
Keywords:
{{#each keywords}}
{{this}}{{#unless @last}}, {{/unless}}
{{/each}}
</p>
================================================================================
`;
@@ -0,0 +1,15 @@
---
title: A very interesting subject
keywords:
- some
- keywords
- for testing
data: {x:1,
y:100000000}
---
<h1>{{title}}</h1>
<p>
Keywords: {{#each keywords}}
{{this}}{{#unless @last}}, {{/unless}}
{{/each}}
</p>
@@ -0,0 +1 @@
runFormatTest(import.meta, ["glimmer"], { embeddedLanguageFormatting: "off" });
@@ -0,0 +1 @@
--- ---
@@ -0,0 +1,4 @@
---
---
<h1>Uh oh!</h1>
@@ -0,0 +1,10 @@
---yaml
foo: bar
"additional information ":
- Yes
- No
data: {x:1,
y:100000000}
---
{{! Some handlebars code can go here.}}
@@ -0,0 +1 @@
runFormatTest(import.meta, ["glimmer"]);
@@ -0,0 +1,6 @@
---
first: Thing
second Thing
---
<div class=" class-a"></div>
@@ -0,0 +1,11 @@
---
title: An ancient philosophy...
keywords:
- ancient
- philosophy
---
<h1>{{title}}</h1>
<p>
Keywords: {{#each keywords}}{{this}}{{#unless @last}}, {{/unless}}{{/each}}
</p>
@@ -0,0 +1,46 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`toml.hbs format 1`] = `
====================================options=====================================
parsers: ["glimmer"]
printWidth: 80
| printWidth
=====================================input======================================
---toml
test = "Toml test"
---
<h1>{{test}}</h1>
=====================================output=====================================
---toml
!!! Formatted by with 'dummy-toml-plugin-parser-name' parser
test = "Toml test"
---
<h1>{{test}}</h1>
================================================================================
`;
exports[`toml2.hbs format 1`] = `
====================================options=====================================
parsers: ["glimmer"]
printWidth: 80
| printWidth
=====================================input======================================
+++
Test TOML data
+++
<Foo as
|bar baz qux|></Foo>{{#Foo as
|bar baz qux|}}{{/Foo}}
=====================================output=====================================
+++
!!! Formatted by with 'dummy-toml-plugin-parser-name' parser
Test TOML data
+++
<Foo as |bar baz qux| />{{#Foo as |bar baz qux|}}{{/Foo}}
================================================================================
`;
@@ -0,0 +1,3 @@
import prettierPluginDummyToml from "../../../../config/prettier-plugins/prettier-plugin-dummy-toml/index.js";
runFormatTest(import.meta, ["glimmer"], { plugins: [prettierPluginDummyToml] });
@@ -0,0 +1,4 @@
---toml
test = "Toml test"
---
<h1>{{test}}</h1>
@@ -0,0 +1,7 @@
+++
Test TOML data
+++
<Foo as
|bar baz qux|></Foo>{{#Foo as
|bar baz qux|}}{{/Foo}}
@@ -0,0 +1,5 @@
---
name: Smith
--- <head>
<title>{{name}}</title>
</head>
@@ -0,0 +1,19 @@
---
foo: bar
test: " word"
nest :
x: 100
y: false
"more stuff":
- do
- do
long_text: >
lots of text
content
to put here and other
places?
---
@@ -0,0 +1,22 @@
---
title: "Example Document"
date: 1993-02-01
author:
name: Arthur Mitchell
tags:
- tutorial
- example
summary: >
A very long example document written for a person other than me, I don't know
why this is so long. Very good example... Yes!
---
<html lang="en">
<head>
<title>{{title}}</title>
</head>
<body>
{{! comment --- }}
{{summary}}
</body>
</html>
@@ -1251,6 +1251,7 @@ exports[`visitor keys glimmer 1`] = `
],
"TextNode": [],
"UndefinedLiteral": [],
"front-matter": [],
}
`;