From 4e401ff7ea54a44ea3fe68e77cbfc4574df0f5a8 Mon Sep 17 00:00:00 2001 From: fisker Cheung Date: Thu, 25 Dec 2025 20:42:58 +0800 Subject: [PATCH] Support formatting angular syntax in markdown (#18519) --- changelog_unreleased/markdown/18519.md | 37 +++ src/language-markdown/embed.js | 11 +- .../angular/__snapshots__/format.test.js.snap | 294 ++++++++++++++++++ .../code/angular/angular-html-invalid.md | 6 + .../markdown/code/angular/angular-html.md | 8 + .../code/angular/angular-ts-invalid.md | 16 + .../markdown/code/angular/angular-ts.md | 17 + .../markdown/code/angular/format.test.js | 2 + 8 files changed, 390 insertions(+), 1 deletion(-) create mode 100644 changelog_unreleased/markdown/18519.md create mode 100644 tests/format/markdown/code/angular/__snapshots__/format.test.js.snap create mode 100644 tests/format/markdown/code/angular/angular-html-invalid.md create mode 100644 tests/format/markdown/code/angular/angular-html.md create mode 100644 tests/format/markdown/code/angular/angular-ts-invalid.md create mode 100644 tests/format/markdown/code/angular/angular-ts.md create mode 100644 tests/format/markdown/code/angular/format.test.js diff --git a/changelog_unreleased/markdown/18519.md b/changelog_unreleased/markdown/18519.md new file mode 100644 index 000000000..a8fbbfb4e --- /dev/null +++ b/changelog_unreleased/markdown/18519.md @@ -0,0 +1,37 @@ +#### Support formatting Angular syntax in code block (#18519 by @fisker) + + +````md + +```angular-ts +@Component({ + selector: 'app-root', + template: `
Welcome to {{ + Angular}}!
`, +}) +export class App {} +``` + +```angular-html +
Welcome to {{ + Angular}}!
+``` + + +Same as input + + +```angular-ts +@Component({ + selector: "app-root", + template: `
Welcome to {{ Angular }}!
`, +}) +export class App {} +``` + +```angular-html +
Welcome to {{ Angular }}!
+``` +```` diff --git a/src/language-markdown/embed.js b/src/language-markdown/embed.js index ab0967330..19cbe6f19 100644 --- a/src/language-markdown/embed.js +++ b/src/language-markdown/embed.js @@ -13,7 +13,16 @@ function embed(path, options) { return; } - const parser = inferParser(options, { language }); + let parser; + // https://shiki.style/references/engine-js-compat#supported-languages + if (language === "angular-ts") { + parser = inferParser(options, { language: "typescript" }); + } else if (language === "angular-html") { + parser = "angular"; + } else { + parser = inferParser(options, { language }); + } + if (!parser) { return; } diff --git a/tests/format/markdown/code/angular/__snapshots__/format.test.js.snap b/tests/format/markdown/code/angular/__snapshots__/format.test.js.snap new file mode 100644 index 000000000..229c7cae0 --- /dev/null +++ b/tests/format/markdown/code/angular/__snapshots__/format.test.js.snap @@ -0,0 +1,294 @@ +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing + +exports[`angular-html.md - {"embeddedLanguageFormatting":"off"} format 1`] = ` +====================================options===================================== +embeddedLanguageFormatting: "off" +parsers: ["markdown"] +printWidth: 80 + | printWidth +=====================================input====================================== +\`\`\`angular-html +@if (orderForm.couponCode().disabled()) { +
+ @for (reason of orderForm.couponCode().disabledReasons(); track reason) { +

{{ reason.message }}

+ }
+ } +\`\`\` + +=====================================output===================================== +\`\`\`angular-html +@if (orderForm.couponCode().disabled()) { +
+ @for (reason of orderForm.couponCode().disabledReasons(); track reason) { +

{{ reason.message }}

+ }
+ } +\`\`\` + +================================================================================ +`; + +exports[`angular-html.md format 1`] = ` +====================================options===================================== +parsers: ["markdown"] +printWidth: 80 + | printWidth +=====================================input====================================== +\`\`\`angular-html +@if (orderForm.couponCode().disabled()) { +
+ @for (reason of orderForm.couponCode().disabledReasons(); track reason) { +

{{ reason.message }}

+ }
+ } +\`\`\` + +=====================================output===================================== +\`\`\`angular-html +@if (orderForm.couponCode().disabled()) { +
+ @for (reason of orderForm.couponCode().disabledReasons(); track reason) { +

{{ reason.message }}

+ } +
+} +\`\`\` + +================================================================================ +`; + +exports[`angular-html-invalid.md - {"embeddedLanguageFormatting":"off"} format 1`] = ` +====================================options===================================== +embeddedLanguageFormatting: "off" +parsers: ["markdown"] +printWidth: 80 + | printWidth +=====================================input====================================== +\`\`\`angular-html + @for (reason of orderForm.couponCode().disabledReasons(); track reason) { +

{{ reason.message }}

+ } + } +\`\`\` + +=====================================output===================================== +\`\`\`angular-html + @for (reason of orderForm.couponCode().disabledReasons(); track reason) { +

{{ reason.message }}

+ } + } +\`\`\` + +================================================================================ +`; + +exports[`angular-html-invalid.md format 1`] = ` +====================================options===================================== +parsers: ["markdown"] +printWidth: 80 + | printWidth +=====================================input====================================== +\`\`\`angular-html + @for (reason of orderForm.couponCode().disabledReasons(); track reason) { +

{{ reason.message }}

+ } + } +\`\`\` + +=====================================output===================================== +\`\`\`angular-html + @for (reason of orderForm.couponCode().disabledReasons(); track reason) { +

{{ reason.message }}

+ } + } +\`\`\` + +================================================================================ +`; + +exports[`angular-ts.md - {"embeddedLanguageFormatting":"off"} format 1`] = ` +====================================options===================================== +embeddedLanguageFormatting: "off" +parsers: ["markdown"] +printWidth: 80 + | printWidth +=====================================input====================================== +\`\`\`angular-ts +type A ={ + Ugly:string +} + +@Component({template: \` +@if (orderForm.couponCode().disabled()) { +
+ @for (reason of orderForm.couponCode().disabledReasons(); track reason) { +

{{ reason.message }}

+ }
+ } + \` +}) +export class Order { +} +\`\`\` + +=====================================output===================================== +\`\`\`angular-ts +type A ={ + Ugly:string +} + +@Component({template: \` +@if (orderForm.couponCode().disabled()) { +
+ @for (reason of orderForm.couponCode().disabledReasons(); track reason) { +

{{ reason.message }}

+ }
+ } + \` +}) +export class Order { +} +\`\`\` + +================================================================================ +`; + +exports[`angular-ts.md format 1`] = ` +====================================options===================================== +parsers: ["markdown"] +printWidth: 80 + | printWidth +=====================================input====================================== +\`\`\`angular-ts +type A ={ + Ugly:string +} + +@Component({template: \` +@if (orderForm.couponCode().disabled()) { +
+ @for (reason of orderForm.couponCode().disabledReasons(); track reason) { +

{{ reason.message }}

+ }
+ } + \` +}) +export class Order { +} +\`\`\` + +=====================================output===================================== +\`\`\`angular-ts +type A = { + Ugly: string; +}; + +@Component({ + template: \` + @if (orderForm.couponCode().disabled()) { +
+ @for ( + reason of orderForm.couponCode().disabledReasons(); + track reason + ) { +

{{ reason.message }}

+ } +
+ } + \`, +}) +export class Order {} +\`\`\` + +================================================================================ +`; + +exports[`angular-ts-invalid.md - {"embeddedLanguageFormatting":"off"} format 1`] = ` +====================================options===================================== +embeddedLanguageFormatting: "off" +parsers: ["markdown"] +printWidth: 80 + | printWidth +=====================================input====================================== +\`\`\`angular-ts + Ugly:string +} + +@Component({template: \` +@if (orderForm.couponCode().disabled()) { +
+ @for (reason of orderForm.couponCode().disabledReasons(); track reason) { +

{{ reason.message }}

+ }
+ } + \` +}) +export class Order { +} +\`\`\` + +=====================================output===================================== +\`\`\`angular-ts + Ugly:string +} + +@Component({template: \` +@if (orderForm.couponCode().disabled()) { +
+ @for (reason of orderForm.couponCode().disabledReasons(); track reason) { +

{{ reason.message }}

+ }
+ } + \` +}) +export class Order { +} +\`\`\` + +================================================================================ +`; + +exports[`angular-ts-invalid.md format 1`] = ` +====================================options===================================== +parsers: ["markdown"] +printWidth: 80 + | printWidth +=====================================input====================================== +\`\`\`angular-ts + Ugly:string +} + +@Component({template: \` +@if (orderForm.couponCode().disabled()) { +
+ @for (reason of orderForm.couponCode().disabledReasons(); track reason) { +

{{ reason.message }}

+ }
+ } + \` +}) +export class Order { +} +\`\`\` + +=====================================output===================================== +\`\`\`angular-ts + Ugly:string +} + +@Component({template: \` +@if (orderForm.couponCode().disabled()) { +
+ @for (reason of orderForm.couponCode().disabledReasons(); track reason) { +

{{ reason.message }}

+ }
+ } + \` +}) +export class Order { +} +\`\`\` + +================================================================================ +`; diff --git a/tests/format/markdown/code/angular/angular-html-invalid.md b/tests/format/markdown/code/angular/angular-html-invalid.md new file mode 100644 index 000000000..422a1a5a8 --- /dev/null +++ b/tests/format/markdown/code/angular/angular-html-invalid.md @@ -0,0 +1,6 @@ +```angular-html + @for (reason of orderForm.couponCode().disabledReasons(); track reason) { +

{{ reason.message }}

+ } + } +``` diff --git a/tests/format/markdown/code/angular/angular-html.md b/tests/format/markdown/code/angular/angular-html.md new file mode 100644 index 000000000..bbaec0813 --- /dev/null +++ b/tests/format/markdown/code/angular/angular-html.md @@ -0,0 +1,8 @@ +```angular-html +@if (orderForm.couponCode().disabled()) { +
+ @for (reason of orderForm.couponCode().disabledReasons(); track reason) { +

{{ reason.message }}

+ }
+ } +``` diff --git a/tests/format/markdown/code/angular/angular-ts-invalid.md b/tests/format/markdown/code/angular/angular-ts-invalid.md new file mode 100644 index 000000000..514e328d4 --- /dev/null +++ b/tests/format/markdown/code/angular/angular-ts-invalid.md @@ -0,0 +1,16 @@ +```angular-ts + Ugly:string +} + +@Component({template: ` +@if (orderForm.couponCode().disabled()) { +
+ @for (reason of orderForm.couponCode().disabledReasons(); track reason) { +

{{ reason.message }}

+ }
+ } + ` +}) +export class Order { +} +``` diff --git a/tests/format/markdown/code/angular/angular-ts.md b/tests/format/markdown/code/angular/angular-ts.md new file mode 100644 index 000000000..420ba08c9 --- /dev/null +++ b/tests/format/markdown/code/angular/angular-ts.md @@ -0,0 +1,17 @@ +```angular-ts +type A ={ + Ugly:string +} + +@Component({template: ` +@if (orderForm.couponCode().disabled()) { +
+ @for (reason of orderForm.couponCode().disabledReasons(); track reason) { +

{{ reason.message }}

+ }
+ } + ` +}) +export class Order { +} +``` diff --git a/tests/format/markdown/code/angular/format.test.js b/tests/format/markdown/code/angular/format.test.js new file mode 100644 index 000000000..cbca7e1b9 --- /dev/null +++ b/tests/format/markdown/code/angular/format.test.js @@ -0,0 +1,2 @@ +runFormatTest(import.meta, ["markdown"]); +runFormatTest(import.meta, ["markdown"], { embeddedLanguageFormatting: "off" });