diff --git a/changelog_unreleased/handlebars/pr-7275.md b/changelog_unreleased/handlebars/pr-7275.md new file mode 100644 index 000000000..3a2a6a7d8 --- /dev/null +++ b/changelog_unreleased/handlebars/pr-7275.md @@ -0,0 +1,49 @@ +#### Glimmer: Add prettier-ignore ([#7275](https://github.com/prettier/prettier/pull/7275) by [@chadian](https://github.com/chadian)) + + +```hbs +{{! Input}} +{{! prettier-ignore }} +
+ "hello! my parent was ignored" + {{#my-crazy-component "shall" be="preserved"}} + + {{/my-crazy-component}} +
+ +{{#a-normal-component isRestoredTo = "order" }} + +{{/a-normal-component}} + +{{! Prettier stable}} +{{! prettier-ignore }} +
+ "hello! my parent was ignored" + {{#my-crazy-component "shall" be="preserved"}} + + {{/my-crazy-component}} +
+ +{{#a-normal-component isRestoredTo="order"}} + +{{/a-normal-component}} + +{{! Prettier master}} +{{! prettier-ignore }} +
+ "hello! my parent was ignored" + {{#my-crazy-component "shall" be="preserved"}} + + {{/my-crazy-component}} +
+ +{{#a-normal-component isRestoredTo='order'}} + +{{/a-normal-component}} +``` diff --git a/docs/ignore.md b/docs/ignore.md index d4b3a7db0..fe4a54f8e 100644 --- a/docs/ignore.md +++ b/docs/ignore.md @@ -117,3 +117,18 @@ This type of ignore is only allowed to be used in top-level and aimed to disable } } ``` + +## Handlebars + + +```hbs +{{! prettier-ignore }} +
+ "hello! my parent was ignored" + {{#my-crazy-component "shall" be="preserved"}} + + {{/my-crazy-component}} +
+``` diff --git a/src/language-handlebars/parser-glimmer.js b/src/language-handlebars/parser-glimmer.js index 3c4568b2f..fe47501de 100644 --- a/src/language-handlebars/parser-glimmer.js +++ b/src/language-handlebars/parser-glimmer.js @@ -29,6 +29,10 @@ module.exports = { glimmer: { parse, astFormat: "glimmer", + // TODO: `locStart` and `locEnd` should return a number offset + // https://prettier.io/docs/en/plugins.html#parsers + // but we need access to the original text to use + // `loc.start` and `loc.end` objects to calculate the offset locStart(node) { return node.loc && node.loc.start; }, diff --git a/src/language-handlebars/printer-glimmer.js b/src/language-handlebars/printer-glimmer.js index 1c7e382cc..8888ede19 100644 --- a/src/language-handlebars/printer-glimmer.js +++ b/src/language-handlebars/printer-glimmer.js @@ -40,6 +40,22 @@ function print(path, options, print) { return ""; } + if (hasPrettierIgnore(path)) { + const startOffset = locationToOffset( + options.originalText, + n.loc.start.line - 1, + n.loc.start.column + ); + const endOffset = locationToOffset( + options.originalText, + n.loc.end.line - 1, + n.loc.end.column + ); + + const ignoredText = options.originalText.slice(startOffset, endOffset); + return ignoredText; + } + switch (n.type) { case "Block": case "Program": @@ -474,15 +490,15 @@ function isParentOfType(path, nodeType) { return p && p.type === nodeType; } -function getPreviousNode(path) { +function getPreviousNode(path, lookBack = 1) { const node = path.getValue(); const parentNode = path.getParentNode(0); - const children = parentNode.children || parentNode.body; + const children = parentNode && (parentNode.children || parentNode.body); if (children) { const nodeIndex = children.indexOf(node); if (nodeIndex > 0) { - const previousNode = children[nodeIndex - 1]; + const previousNode = children[nodeIndex - lookBack]; return previousNode; } } @@ -553,6 +569,58 @@ function generateHardlines(number = 0, max = 0) { return new Array(Math.min(number, max)).fill(hardline); } +function hasPrettierIgnore(path) { + const n = path.getValue(); + const previousPreviousNode = getPreviousNode(path, 2); + const isIgnoreNode = isPrettierIgnoreNode(n); + const isCoveredByIgnoreNode = isPrettierIgnoreNode(previousPreviousNode); + + return isIgnoreNode || isCoveredByIgnoreNode; +} + +/* istanbul ignore next + https://github.com/glimmerjs/glimmer-vm/blob/master/packages/%40glimmer/compiler/lib/location.ts#L5-L29 +*/ +function locationToOffset(source, line, column) { + let seenLines = 0; + let seenChars = 0; + + // eslint-disable-next-line no-constant-condition + while (true) { + if (seenChars === source.length) { + return null; + } + + let nextLine = source.indexOf("\n", seenChars); + if (nextLine === -1) { + nextLine = source.length; + } + + if (seenLines === line) { + if (seenChars + column > nextLine) { + return null; + } + return seenChars + column; + } else if (nextLine === -1) { + return null; + } + seenLines += 1; + seenChars = nextLine + 1; + } +} + +function isPrettierIgnoreNode(node) { + if (!node) { + return false; + } + + const isMustacheComment = node.type === "MustacheCommentStatement"; + const containsPrettierIgnore = + typeof node.value === "string" && node.value.trim() === "prettier-ignore"; + + return isMustacheComment && containsPrettierIgnore; +} + module.exports = { print, massageAstNode: clean diff --git a/tests/handlebars-prettier-ignore/__snapshots__/jsfmt.spec.js.snap b/tests/handlebars-prettier-ignore/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000..f7e122adf --- /dev/null +++ b/tests/handlebars-prettier-ignore/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,154 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`prettier-ignore.hbs 1`] = ` +====================================options===================================== +parsers: ["glimmer"] +printWidth: 80 + | printWidth +=====================================input====================================== +{{! prettier-ignore }} +
+ "hello! my parent was ignored" + {{#my-crazy-component "shall" be="preserved"}} + + {{/my-crazy-component}} +
+ +{{#a-normal-component isRestoredTo = "order" }} + +{{/a-normal-component}} + +
+ + {{! prettier-ignore }} +
+ + + + +
+ {{#another-sibling as |isFixed|}} + +
{{ isFixed }} + + All of this should be fixed + +
+ + {{/another-sibling}} +
+=====================================output===================================== +{{! prettier-ignore }} +
+ "hello! my parent was ignored" + {{#my-crazy-component "shall" be="preserved"}} + + {{/my-crazy-component}} +
+ +{{#a-normal-component isRestoredTo="order"}} + +{{/a-normal-component}} + +
+ + {{! prettier-ignore }} +
+ + + + +
+ {{#another-sibling as |isFixed|}} +
+ {{isFixed}} + + All of this should be fixed +
+ {{/another-sibling}} +
+================================================================================ +`; + +exports[`prettier-ignore.hbs 2`] = ` +====================================options===================================== +parsers: ["glimmer"] +printWidth: 80 +singleQuote: true + | printWidth +=====================================input====================================== +{{! prettier-ignore }} +
+ "hello! my parent was ignored" + {{#my-crazy-component "shall" be="preserved"}} + + {{/my-crazy-component}} +
+ +{{#a-normal-component isRestoredTo = "order" }} + +{{/a-normal-component}} + +
+ + {{! prettier-ignore }} +
+ + + + +
+ {{#another-sibling as |isFixed|}} + +
{{ isFixed }} + + All of this should be fixed + +
+ + {{/another-sibling}} +
+=====================================output===================================== +{{! prettier-ignore }} +
+ "hello! my parent was ignored" + {{#my-crazy-component "shall" be="preserved"}} + + {{/my-crazy-component}} +
+ +{{#a-normal-component isRestoredTo='order'}} + +{{/a-normal-component}} + +
+ + {{! prettier-ignore }} +
+ + + + +
+ {{#another-sibling as |isFixed|}} +
+ {{isFixed}} + + All of this should be fixed +
+ {{/another-sibling}} +
+================================================================================ +`; diff --git a/tests/handlebars-prettier-ignore/jsfmt.spec.js b/tests/handlebars-prettier-ignore/jsfmt.spec.js new file mode 100644 index 000000000..4abf117d9 --- /dev/null +++ b/tests/handlebars-prettier-ignore/jsfmt.spec.js @@ -0,0 +1,2 @@ +run_spec(__dirname, ["glimmer"]); +run_spec(__dirname, ["glimmer"], { singleQuote: true }); diff --git a/tests/handlebars-prettier-ignore/prettier-ignore.hbs b/tests/handlebars-prettier-ignore/prettier-ignore.hbs new file mode 100644 index 000000000..cfe3574a1 --- /dev/null +++ b/tests/handlebars-prettier-ignore/prettier-ignore.hbs @@ -0,0 +1,34 @@ +{{! prettier-ignore }} +
+ "hello! my parent was ignored" + {{#my-crazy-component "shall" be="preserved"}} + + {{/my-crazy-component}} +
+ +{{#a-normal-component isRestoredTo = "order" }} + +{{/a-normal-component}} + +
+ + {{! prettier-ignore }} +
+ + + + +
+ {{#another-sibling as |isFixed|}} + +
{{ isFixed }} + + All of this should be fixed + +
+ + {{/another-sibling}} +
\ No newline at end of file