diff --git a/changelog_unreleased/handlebars/17781.md b/changelog_unreleased/handlebars/17781.md new file mode 100644 index 000000000..b4fd1d22c --- /dev/null +++ b/changelog_unreleased/handlebars/17781.md @@ -0,0 +1,20 @@ +#### Added Front Matter support to Handlebars (#17781 by @Codezilluh) + +Front matter can now be used in Handlebars. + + +```hbs +--- +title: My page title +keywords: + - word + - other word +--- + +

{{title}}

+ +``` diff --git a/src/language-handlebars/clean.js b/src/language-handlebars/clean.js index 10300d0a4..b369521a4 100644 --- a/src/language-handlebars/clean.js +++ b/src/language-handlebars/clean.js @@ -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(); diff --git a/src/language-handlebars/embed.js b/src/language-handlebars/embed.js index 3bdc10b81..bfac69e84 100644 --- a/src/language-handlebars/embed.js +++ b/src/language-handlebars/embed.js @@ -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; } diff --git a/src/language-handlebars/parser-glimmer.js b/src/language-handlebars/parser-glimmer.js index 66fa2b1d2..67f69a7f3 100644 --- a/src/language-handlebars/parser-glimmer.js +++ b/src/language-handlebars/parser-glimmer.js @@ -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; } diff --git a/src/language-handlebars/printer-glimmer.js b/src/language-handlebars/printer-glimmer.js index 5836fc067..9ed095681 100644 --- a/src/language-handlebars/printer-glimmer.js +++ b/src/language-handlebars/printer-glimmer.js @@ -395,6 +395,9 @@ function print(path, options, print) { case "CommentStatement": return [""]; + case "front-matter": + return node.raw; + case "StringLiteral": return printStringLiteral(path, options); diff --git a/src/language-handlebars/visitor-keys.evaluate.js b/src/language-handlebars/visitor-keys.evaluate.js index 0c86c8e91..2a83f193b 100644 --- a/src/language-handlebars/visitor-keys.evaluate.js +++ b/src/language-handlebars/visitor-keys.evaluate.js @@ -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": [], +}; diff --git a/tests/format/handlebars/front-matter/__snapshots__/format.test.js.snap b/tests/format/handlebars/front-matter/__snapshots__/format.test.js.snap new file mode 100644 index 000000000..179e6a532 --- /dev/null +++ b/tests/format/handlebars/front-matter/__snapshots__/format.test.js.snap @@ -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 +--- +

{{title}}

+

+ Keywords: {{#each keywords}}{{this}}{{#unless @last}}, {{/unless}}{{/each}} +

+ +=====================================output===================================== +--- +title: An ancient philosophy... +keywords: + - ancient + - philosophy +--- + +

{{title}}

+

+ Keywords: + {{#each keywords}}{{this}}{{#unless @last}}, {{/unless}}{{/each}} +

+================================================================================ +`; + +exports[`empty.hbs format 1`] = ` +====================================options===================================== +parsers: ["glimmer"] +printWidth: 80 + | printWidth +=====================================input====================================== +--- +--- + +

Uh oh!

+ +=====================================output===================================== +--- +--- + +

Uh oh!

+================================================================================ +`; + +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 +--- + +
+ +=====================================output===================================== +--- +first: Thing + second Thing +--- + +
+================================================================================ +`; + +exports[`spaced.hbs format 1`] = ` +====================================options===================================== +parsers: ["glimmer"] +printWidth: 80 + | printWidth +=====================================input====================================== +--- +title: An ancient philosophy... +keywords: + - ancient + - philosophy +--- + +

{{title}}

+

+ Keywords: {{#each keywords}}{{this}}{{#unless @last}}, {{/unless}}{{/each}} +

+ +=====================================output===================================== +--- +title: An ancient philosophy... +keywords: + - ancient + - philosophy +--- + +

{{title}}

+

+ Keywords: + {{#each keywords}}{{this}}{{#unless @last}}, {{/unless}}{{/each}} +

+================================================================================ +`; + +exports[`touching.hbs format 1`] = ` +====================================options===================================== +parsers: ["glimmer"] +printWidth: 80 + | printWidth +=====================================input====================================== +--- +name: Smith +--- + {{name}} + + +=====================================output===================================== +--- +name: Smith +--- + + + {{name}} + +================================================================================ +`; + +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! +--- + + + + {{title}} + + + {{! comment --- }} + {{summary}} + + + +=====================================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! +--- + + + + {{title}} + + + {{! comment --- }} + {{summary}} + + +================================================================================ +`; diff --git a/tests/format/handlebars/front-matter/close.hbs b/tests/format/handlebars/front-matter/close.hbs new file mode 100644 index 000000000..960e88610 --- /dev/null +++ b/tests/format/handlebars/front-matter/close.hbs @@ -0,0 +1,10 @@ +--- +title: An ancient philosophy... +keywords: +- ancient +- philosophy +--- +

{{title}}

+

+ Keywords: {{#each keywords}}{{this}}{{#unless @last}}, {{/unless}}{{/each}} +

diff --git a/tests/format/handlebars/front-matter/embedded-language-formatting-off/__snapshots__/format.test.js.snap b/tests/format/handlebars/front-matter/embedded-language-formatting-off/__snapshots__/format.test.js.snap new file mode 100644 index 000000000..42c10dbc7 --- /dev/null +++ b/tests/format/handlebars/front-matter/embedded-language-formatting-off/__snapshots__/format.test.js.snap @@ -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} +--- +

{{title}}

+

+ Keywords: {{#each keywords}} + {{this}}{{#unless @last}}, {{/unless}} + {{/each}} +

+ +=====================================output===================================== +--- +title: A very interesting subject +keywords: +- some +- keywords +- for testing +data: {x:1, + y:100000000} +--- + +

{{title}}

+

+ Keywords: + {{#each keywords}} + {{this}}{{#unless @last}}, {{/unless}} + {{/each}} +

+================================================================================ +`; diff --git a/tests/format/handlebars/front-matter/embedded-language-formatting-off/format-embed-off.hbs b/tests/format/handlebars/front-matter/embedded-language-formatting-off/format-embed-off.hbs new file mode 100644 index 000000000..bdeeb5ac9 --- /dev/null +++ b/tests/format/handlebars/front-matter/embedded-language-formatting-off/format-embed-off.hbs @@ -0,0 +1,15 @@ +--- +title: A very interesting subject +keywords: +- some +- keywords +- for testing +data: {x:1, + y:100000000} +--- +

{{title}}

+

+ Keywords: {{#each keywords}} + {{this}}{{#unless @last}}, {{/unless}} + {{/each}} +

diff --git a/tests/format/handlebars/front-matter/embedded-language-formatting-off/format.test.js b/tests/format/handlebars/front-matter/embedded-language-formatting-off/format.test.js new file mode 100644 index 000000000..a2d3c8dee --- /dev/null +++ b/tests/format/handlebars/front-matter/embedded-language-formatting-off/format.test.js @@ -0,0 +1 @@ +runFormatTest(import.meta, ["glimmer"], { embeddedLanguageFormatting: "off" }); diff --git a/tests/format/handlebars/front-matter/empty-no-newline.hbs b/tests/format/handlebars/front-matter/empty-no-newline.hbs new file mode 100644 index 000000000..fd8d22f52 --- /dev/null +++ b/tests/format/handlebars/front-matter/empty-no-newline.hbs @@ -0,0 +1 @@ +--- --- diff --git a/tests/format/handlebars/front-matter/empty.hbs b/tests/format/handlebars/front-matter/empty.hbs new file mode 100644 index 000000000..01e6c7663 --- /dev/null +++ b/tests/format/handlebars/front-matter/empty.hbs @@ -0,0 +1,4 @@ +--- +--- + +

Uh oh!

diff --git a/tests/format/handlebars/front-matter/explicit-language.hbs b/tests/format/handlebars/front-matter/explicit-language.hbs new file mode 100644 index 000000000..c12a433ac --- /dev/null +++ b/tests/format/handlebars/front-matter/explicit-language.hbs @@ -0,0 +1,10 @@ +---yaml +foo: bar +"additional information ": +- Yes +- No +data: {x:1, + y:100000000} +--- + +{{! Some handlebars code can go here.}} diff --git a/tests/format/handlebars/front-matter/format.test.js b/tests/format/handlebars/front-matter/format.test.js new file mode 100644 index 000000000..2dbcbb457 --- /dev/null +++ b/tests/format/handlebars/front-matter/format.test.js @@ -0,0 +1 @@ +runFormatTest(import.meta, ["glimmer"]); diff --git a/tests/format/handlebars/front-matter/invalid-yaml.hbs b/tests/format/handlebars/front-matter/invalid-yaml.hbs new file mode 100644 index 000000000..a38a4064f --- /dev/null +++ b/tests/format/handlebars/front-matter/invalid-yaml.hbs @@ -0,0 +1,6 @@ +--- +first: Thing + second Thing +--- + +
diff --git a/tests/format/handlebars/front-matter/spaced.hbs b/tests/format/handlebars/front-matter/spaced.hbs new file mode 100644 index 000000000..ab39851c0 --- /dev/null +++ b/tests/format/handlebars/front-matter/spaced.hbs @@ -0,0 +1,11 @@ +--- +title: An ancient philosophy... +keywords: + - ancient + - philosophy +--- + +

{{title}}

+

+ Keywords: {{#each keywords}}{{this}}{{#unless @last}}, {{/unless}}{{/each}} +

diff --git a/tests/format/handlebars/front-matter/toml/__snapshots__/format.test.js.snap b/tests/format/handlebars/front-matter/toml/__snapshots__/format.test.js.snap new file mode 100644 index 000000000..2f9a8a3cd --- /dev/null +++ b/tests/format/handlebars/front-matter/toml/__snapshots__/format.test.js.snap @@ -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" +--- +

{{test}}

+ +=====================================output===================================== +---toml +!!! Formatted by with 'dummy-toml-plugin-parser-name' parser +test = "Toml test" +--- + +

{{test}}

+================================================================================ +`; + +exports[`toml2.hbs format 1`] = ` +====================================options===================================== +parsers: ["glimmer"] +printWidth: 80 + | printWidth +=====================================input====================================== ++++ +Test TOML data ++++ + +{{#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}} +================================================================================ +`; diff --git a/tests/format/handlebars/front-matter/toml/format.test.js b/tests/format/handlebars/front-matter/toml/format.test.js new file mode 100644 index 000000000..70b4c4f02 --- /dev/null +++ b/tests/format/handlebars/front-matter/toml/format.test.js @@ -0,0 +1,3 @@ +import prettierPluginDummyToml from "../../../../config/prettier-plugins/prettier-plugin-dummy-toml/index.js"; + +runFormatTest(import.meta, ["glimmer"], { plugins: [prettierPluginDummyToml] }); diff --git a/tests/format/handlebars/front-matter/toml/toml.hbs b/tests/format/handlebars/front-matter/toml/toml.hbs new file mode 100644 index 000000000..70bf078bd --- /dev/null +++ b/tests/format/handlebars/front-matter/toml/toml.hbs @@ -0,0 +1,4 @@ +---toml +test = "Toml test" +--- +

{{test}}

diff --git a/tests/format/handlebars/front-matter/toml/toml2.hbs b/tests/format/handlebars/front-matter/toml/toml2.hbs new file mode 100644 index 000000000..36138e607 --- /dev/null +++ b/tests/format/handlebars/front-matter/toml/toml2.hbs @@ -0,0 +1,7 @@ ++++ +Test TOML data ++++ + +{{#Foo as +|bar baz qux|}}{{/Foo}} diff --git a/tests/format/handlebars/front-matter/touching.hbs b/tests/format/handlebars/front-matter/touching.hbs new file mode 100644 index 000000000..7daf364ce --- /dev/null +++ b/tests/format/handlebars/front-matter/touching.hbs @@ -0,0 +1,5 @@ +--- +name: Smith +--- + {{name}} + diff --git a/tests/format/handlebars/front-matter/very-ugly-yaml.hbs b/tests/format/handlebars/front-matter/very-ugly-yaml.hbs new file mode 100644 index 000000000..32e12e2c7 --- /dev/null +++ b/tests/format/handlebars/front-matter/very-ugly-yaml.hbs @@ -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? + +--- diff --git a/tests/format/handlebars/front-matter/yaml-format.hbs b/tests/format/handlebars/front-matter/yaml-format.hbs new file mode 100644 index 000000000..821aeed26 --- /dev/null +++ b/tests/format/handlebars/front-matter/yaml-format.hbs @@ -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! +--- + + + + {{title}} + + + {{! comment --- }} + {{summary}} + + diff --git a/tests/unit/__snapshots__/visitor-keys.js.snap b/tests/unit/__snapshots__/visitor-keys.js.snap index d52addf98..e0657a99f 100644 --- a/tests/unit/__snapshots__/visitor-keys.js.snap +++ b/tests/unit/__snapshots__/visitor-keys.js.snap @@ -1251,6 +1251,7 @@ exports[`visitor keys glimmer 1`] = ` ], "TextNode": [], "UndefinedLiteral": [], + "front-matter": [], } `;