From 83069857910afc62afdf497a812c6d9df76a7192 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ju=CC=88rg=20Lehni?= Date: Fri, 2 Oct 2020 16:34:25 +0200 Subject: [PATCH 1/7] Support prettier-ignore comments inside pug templates Use such comments to prevent automatic formatting of the following line or block: //- prettier-ignore --- .editorconfig | 4 ++ README.md | 3 +- src/index.ts | 17 +++-- src/printer.ts | 68 ++++++++++++++++++- tests/prettier-ignore/formatted.pug | 21 ++++++ tests/prettier-ignore/prettier-ignore.test.ts | 14 ++++ tests/prettier-ignore/unformatted.pug | 9 +++ 7 files changed, 127 insertions(+), 9 deletions(-) create mode 100644 tests/prettier-ignore/formatted.pug create mode 100644 tests/prettier-ignore/prettier-ignore.test.ts create mode 100644 tests/prettier-ignore/unformatted.pug diff --git a/.editorconfig b/.editorconfig index 28bebae4..c1c33205 100644 --- a/.editorconfig +++ b/.editorconfig @@ -13,3 +13,7 @@ max_line_length = off trim_trailing_whitespace = false indent_style = space indent_size = 2 + +[*.pug] +indent_style = space +indent_size = 2 diff --git a/README.md b/README.md index 4d2f1b41..7c140aef 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,8 @@ Please note that the [plugin ecosystem in Prettier](https://prettier.io/docs/en/ Plugin for Prettier to format pug code -You can disable code formatting for a particular code block by adding `` before ` ```pug `. +You can disable code formatting for a particular code block by adding `` before ` ```pug `, +as well as by using `//- prettier-ignore` comments inside your pug templates. ````markdown Pug code with custom formatting: diff --git a/src/index.ts b/src/index.ts index d60f9e1c..d87d7210 100644 --- a/src/index.ts +++ b/src/index.ts @@ -22,6 +22,11 @@ if (process.env.NODE_ENV === 'test') { logger.setLogLevel(LogLevel.DEBUG); } +type FastPathStackEntry = { + content: string, + tokens: Token[] +}; + export const plugin: Plugin = { languages: [ { @@ -38,13 +43,14 @@ export const plugin: Plugin = { ], parsers: { pug: { - parse(text: string, parsers: { [parserName: string]: Parser }, options: ParserOptions): Token[] { + parse(text: string, parsers: { [parserName: string]: Parser }, options: ParserOptions): FastPathStackEntry { logger.debug('[parsers:pug:parse]:', { text }); - const tokens: lex.Token[] = lex(text.trimLeft()); + const content: string = text.trimLeft(); + const tokens: lex.Token[] = lex(content); // logger.debug('[parsers:pug:parse]: tokens', JSON.stringify(tokens, undefined, 2)); // const ast: AST = parse(tokens, {}); // logger.debug('[parsers:pug:parse]: ast', JSON.stringify(ast, undefined, 2)); - return tokens; + return { content, tokens }; }, astFormat: 'pug-ast', hasPragma(text: string): boolean { @@ -67,9 +73,10 @@ export const plugin: Plugin = { printers: { 'pug-ast': { print(path: FastPath, options: ParserOptions & PugParserOptions, print: (path: FastPath) => Doc): Doc { - const tokens: Token[] = path.stack[0]; + const entry: FastPathStackEntry = path.stack[0]; + const { content, tokens } = entry; const pugOptions: PugPrinterOptions = convergeOptions(options); - const printer: PugPrinter = new PugPrinter(tokens, pugOptions); + const printer: PugPrinter = new PugPrinter(content, tokens, pugOptions); const result: string = printer.build(); logger.debug('[printers:pug-ast:print]:', result); return result; diff --git a/src/printer.ts b/src/printer.ts index 85376f3c..7d3ad3d4 100644 --- a/src/printer.ts +++ b/src/printer.ts @@ -128,7 +128,11 @@ export class PugPrinter { private pipelessText: boolean = false; private pipelessComment: boolean = false; - public constructor(private tokens: Token[], private readonly options: PugPrinterOptions) { + public constructor( + private content: string, + private tokens: Token[], + private readonly options: PugPrinterOptions + ) { this.indentString = options.pugUseTabs ? '\t' : ' '.repeat(options.pugTabWidth); this.quotes = this.options.pugSingleQuote ? "'" : '"'; this.otherQuotes = this.options.pugSingleQuote ? '"' : "'"; @@ -163,9 +167,10 @@ export class PugPrinter { } else if (this.tokens[0]?.type === 'eos') { return ''; } - for (let index: number = 0; index < this.tokens.length; index++) { + let index: number = 0; + while (index < this.tokens.length) { this.currentIndex = index; - const token: Token = this.tokens[index]; + let token: Token = this.tokens[index++]; logger.debug('[PugPrinter]:', JSON.stringify(token)); try { switch (token.type) { @@ -194,6 +199,48 @@ export class PugPrinter { results.push(this[token.type](token)); break; } + if ( + token.type === 'comment' && + token.val.trim() === 'prettier-ignore' + ) { + // Use a spearate token processing loop that finds the end of the tokens to be ignored by formatting, + // and uses their `loc` properties to retreive the original pug code to be used instead. + const firstToken = this.tokens[index]; + const startsWithNewLine = firstToken.type === 'newline'; + let skipNewline = startsWithNewLine; + let ignoreLevel = 0; + while (index < this.tokens.length) { + token = this.tokens[index++]; + const { type } = token; + if (type === 'newline' && ignoreLevel === 0) { + // Skip first newline after prettier-ignore comment: + if (skipNewline) { + skipNewline = false; + } else { + break; + } + } else if (type === 'indent') { + ignoreLevel++; + } else if (type === 'outdent') { + ignoreLevel--; + if (ignoreLevel === 0) { + break; + } + } + } + const lastToken = this.tokens[index - 1]; + const lines = this.getUnformattedContentLines(firstToken, lastToken); + // Start with an empty string for the first newline after comment. + if (startsWithNewLine) { + lines.unshift(''); + } + // Trim the last line, since indentation of formatted pug is handled separately. + const lastLine = lines.pop(); + if (lastLine !== undefined) { + lines.push(lastLine.trimRight()); + } + results.push(lines.join('\n')); + } } catch { throw new Error('Unhandled token: ' + JSON.stringify(token)); } @@ -236,6 +283,21 @@ export class PugPrinter { : this.alwaysUseAttributeSeparator || /^(\(|\[|:).*/.test(token.name); } + private getUnformattedContentLines(firstToken: Token, lastToken: Token): string[] { + const { start } = firstToken.loc; + const { end } = lastToken.loc; + const lines = this.content.split(/\r\n|\n|\r/); + const startLine = start.line - 1; + const endLine = end.line - 1; + const parts: string[] = []; + parts.push(lines[startLine].substring(start.column - 1)); + for (let line = startLine + 1; line < endLine; line++) { + parts.push(lines[line]); + } + parts.push(lines[endLine].substring(0, end.column - 1)); + return parts; + } + private formatDelegatePrettier( val: string, parser: '__vue_expression' | '__ng_binding' | '__ng_action' | '__ng_directive' diff --git a/tests/prettier-ignore/formatted.pug b/tests/prettier-ignore/formatted.pug new file mode 100644 index 00000000..805e37b5 --- /dev/null +++ b/tests/prettier-ignore/formatted.pug @@ -0,0 +1,21 @@ +div + .wrapper-1( + attributes1="foo", + :attribute2="bar", + attribute3="something too long to keep on one line" + ) + //- prettier-ignore + .wrapper-2(attributes1="foo" :attribute2="bar" attribute3 = "something too long to keep on one line") + .wrapper-3( + attributes1="foo", + :attribute2="bar", + attribute3="something too long to keep on one line" + ) + //- prettier-ignore + div + .wrapper-4(attributes1="foo" :attribute2="bar" attribute3 = "something too long to keep on one line") +.wrapper-5( + attributes1="foo", + :attribute2="bar", + attribute3="something too long to keep on one line" +) diff --git a/tests/prettier-ignore/prettier-ignore.test.ts b/tests/prettier-ignore/prettier-ignore.test.ts new file mode 100644 index 00000000..200a64ba --- /dev/null +++ b/tests/prettier-ignore/prettier-ignore.test.ts @@ -0,0 +1,14 @@ +import { readFileSync } from 'fs'; +import { resolve } from 'path'; +import { format } from 'prettier'; +import { plugin } from './../../src/index'; + +describe('prettier-ignore', () => { + test('should handle // prettier-ignore statements', () => { + const expected: string = readFileSync(resolve(__dirname, 'formatted.pug'), 'utf8'); + const code: string = readFileSync(resolve(__dirname, 'unformatted.pug'), 'utf8'); + const actual: string = format(code, { parser: 'pug' as any, plugins: [plugin] }); + + expect(actual).toBe(expected); + }); +}); diff --git a/tests/prettier-ignore/unformatted.pug b/tests/prettier-ignore/unformatted.pug new file mode 100644 index 00000000..f4bcafd3 --- /dev/null +++ b/tests/prettier-ignore/unformatted.pug @@ -0,0 +1,9 @@ +div + .wrapper-1(attributes1="foo" :attribute2="bar" attribute3 = "something too long to keep on one line") + //- prettier-ignore + .wrapper-2(attributes1="foo" :attribute2="bar" attribute3 = "something too long to keep on one line") + .wrapper-3(attributes1="foo" :attribute2="bar" attribute3 = "something too long to keep on one line") + //- prettier-ignore + div + .wrapper-4(attributes1="foo" :attribute2="bar" attribute3 = "something too long to keep on one line") +.wrapper-5(attributes1="foo" :attribute2="bar" attribute3 = "something too long to keep on one line") From 86b46b3d640ca1b4ba11e89b58e4bc8ef9511015 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ju=CC=88rg=20Lehni?= Date: Fri, 2 Oct 2020 18:07:51 +0200 Subject: [PATCH 2/7] Adjust docs of prettier-ignore in README --- README.md | 59 ++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 41 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 7c140aef..60f20094 100644 --- a/README.md +++ b/README.md @@ -33,24 +33,6 @@ Please note that the [plugin ecosystem in Prettier](https://prettier.io/docs/en/ Plugin for Prettier to format pug code -You can disable code formatting for a particular code block by adding `` before ` ```pug `, -as well as by using `//- prettier-ignore` comments inside your pug templates. - -````markdown -Pug code with custom formatting: - - -```pug -div.text( color = "primary", disabled ="true" ) -``` - -Prettified code: - -```pug -.text(color="primary", disabled) -``` -```` - ## Getting started Simply install `prettier` and `@prettier/plugin-pug` as your project’s npm devDependencies: @@ -78,6 +60,47 @@ yarn add --dev prettier @prettier/plugin-pug yarn prettier --write "**/*.pug" ``` +### Selectively ignoring automatic formatting + +You can disable code formatting for a particular element by adding `//- prettier-ignore` comments in your pug templates: + +```pug +div.text( color = "primary", disabled ="true" ) +// -prettier-ignore +div.text( color = "primary", disabled ="true" ) +// -prettier-ignore +div + div.text( color = "primary", disabled ="true" ) +``` + +Prettified output: + +```pug +.text(color="primary", disabled) +// -prettier-ignore +div.text( color = "primary", disabled ="true" ) +// -prettier-ignore +div + div.text( color = "primary", disabled ="true" ) +``` + +You can also disable code formatting in Markdown for a particular ` ```pug ` block by adding `` before the block: + +````markdown +Pug code with preserved custom formatting: + + +```pug +div.text( color = "primary", disabled ="true" ) +``` + +Pug code with automatic formatting: + +```pug +.text(color="primary", disabled) +``` +```` + ### Pug versions of standard prettier options By default, the same formatting options are used as configured through the standard prettier options. From 84021f6cd39b56787f6889bb024e776fb2972cc6 Mon Sep 17 00:00:00 2001 From: Shinigami Date: Fri, 2 Oct 2020 21:25:02 +0200 Subject: [PATCH 3/7] Apply suggestions from code review --- src/index.ts | 4 ++-- src/printer.ts | 28 ++++++++++++++-------------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/index.ts b/src/index.ts index d87d7210..7858c7db 100644 --- a/src/index.ts +++ b/src/index.ts @@ -23,8 +23,8 @@ if (process.env.NODE_ENV === 'test') { } type FastPathStackEntry = { - content: string, - tokens: Token[] + content: string; + tokens: Token[]; }; export const plugin: Plugin = { diff --git a/src/printer.ts b/src/printer.ts index 7d3ad3d4..27bd98a8 100644 --- a/src/printer.ts +++ b/src/printer.ts @@ -129,7 +129,7 @@ export class PugPrinter { private pipelessComment: boolean = false; public constructor( - private content: string, + private readonly content: string, private tokens: Token[], private readonly options: PugPrinterOptions ) { @@ -203,12 +203,12 @@ export class PugPrinter { token.type === 'comment' && token.val.trim() === 'prettier-ignore' ) { - // Use a spearate token processing loop that finds the end of the tokens to be ignored by formatting, - // and uses their `loc` properties to retreive the original pug code to be used instead. - const firstToken = this.tokens[index]; - const startsWithNewLine = firstToken.type === 'newline'; - let skipNewline = startsWithNewLine; - let ignoreLevel = 0; + // Use a separate token processing loop that finds the end of the tokens to be ignored by formatting, + // and uses their `loc` properties to retrieve the original pug code to be used instead. + const firstToken: Token = this.tokens[index]; + const startsWithNewLine: boolean = firstToken.type === 'newline'; + let skipNewline: boolean = startsWithNewLine; + let ignoreLevel: number = 0; while (index < this.tokens.length) { token = this.tokens[index++]; const { type } = token; @@ -228,14 +228,14 @@ export class PugPrinter { } } } - const lastToken = this.tokens[index - 1]; - const lines = this.getUnformattedContentLines(firstToken, lastToken); + const lastToken: Token = this.tokens[index - 1]; + const lines: string[] = this.getUnformattedContentLines(firstToken, lastToken); // Start with an empty string for the first newline after comment. if (startsWithNewLine) { lines.unshift(''); } // Trim the last line, since indentation of formatted pug is handled separately. - const lastLine = lines.pop(); + const lastLine: string | undefined = lines.pop(); if (lastLine !== undefined) { lines.push(lastLine.trimRight()); } @@ -286,12 +286,12 @@ export class PugPrinter { private getUnformattedContentLines(firstToken: Token, lastToken: Token): string[] { const { start } = firstToken.loc; const { end } = lastToken.loc; - const lines = this.content.split(/\r\n|\n|\r/); - const startLine = start.line - 1; - const endLine = end.line - 1; + const lines: string[] = this.content.split(/\r\n|\n|\r/); + const startLine: number = start.line - 1; + const endLine: number = end.line - 1; const parts: string[] = []; parts.push(lines[startLine].substring(start.column - 1)); - for (let line = startLine + 1; line < endLine; line++) { + for (let line: number = startLine + 1; line < endLine; line++) { parts.push(lines[line]); } parts.push(lines[endLine].substring(0, end.column - 1)); From 5b1a35df4aa33cd39f790d16fc900db2cbcabde7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ju=CC=88rg=20Lehni?= Date: Sat, 3 Oct 2020 01:24:34 +0200 Subject: [PATCH 4/7] Use getNextToken() instead of index-base loop --- src/printer.ts | 102 +++++++++++++++++++++++++++---------------------- 1 file changed, 56 insertions(+), 46 deletions(-) diff --git a/src/printer.ts b/src/printer.ts index 27bd98a8..f9f725c6 100644 --- a/src/printer.ts +++ b/src/printer.ts @@ -99,9 +99,10 @@ export interface PugPrinterOptions { export class PugPrinter { private result: string = ''; - private currentIndex: number = 0; + // The current index in the `tokens` array, starts at -1, because `getNextToken()` increases before retrieving + private currentIndex: number = -1; private currentLineLength: number = 0; - + private readonly indentString: string; private indentLevel: number = 0; @@ -152,14 +153,6 @@ export class PugPrinter { }; } - private get previousToken(): Token | undefined { - return this.tokens[this.currentIndex - 1]; - } - - private get nextToken(): Token | undefined { - return this.tokens[this.currentIndex + 1]; - } - public build(): string { const results: string[] = []; if (this.tokens[0]?.type === 'text') { @@ -167,10 +160,8 @@ export class PugPrinter { } else if (this.tokens[0]?.type === 'eos') { return ''; } - let index: number = 0; - while (index < this.tokens.length) { - this.currentIndex = index; - let token: Token = this.tokens[index++]; + let token: Token | null = this.getNextToken(); + while (token) { logger.debug('[PugPrinter]:', JSON.stringify(token)); try { switch (token.type) { @@ -203,47 +194,53 @@ export class PugPrinter { token.type === 'comment' && token.val.trim() === 'prettier-ignore' ) { - // Use a separate token processing loop that finds the end of the tokens to be ignored by formatting, + // Use a own token processing loop to find the end of the stream of tokens to be ignored by formatting, // and uses their `loc` properties to retrieve the original pug code to be used instead. - const firstToken: Token = this.tokens[index]; - const startsWithNewLine: boolean = firstToken.type === 'newline'; - let skipNewline: boolean = startsWithNewLine; - let ignoreLevel: number = 0; - while (index < this.tokens.length) { - token = this.tokens[index++]; - const { type } = token; - if (type === 'newline' && ignoreLevel === 0) { - // Skip first newline after prettier-ignore comment: - if (skipNewline) { - skipNewline = false; - } else { - break; + token = this.getNextToken(); + if (token) { + const firstToken: Token = token; + const startsWithNewLine: boolean = firstToken.type === 'newline'; + let skipNewline: boolean = startsWithNewLine; + let ignoreLevel: number = 0; + while (token) { + const { type } = token; + if (type === 'newline' && ignoreLevel === 0) { + // Skip first newline after prettier-ignore comment: + if (skipNewline) { + skipNewline = false; + } else { + break; + } + } else if (type === 'indent') { + ignoreLevel++; + } else if (type === 'outdent') { + ignoreLevel--; + if (ignoreLevel === 0) { + break; + } + } + token = this.getNextToken(); + } + if (token) { + const lastToken: Token = token; + const lines: string[] = this.getUnformattedContentLines(firstToken, lastToken); + // Start with an empty string for the first newline after comment. + if (startsWithNewLine) { + lines.unshift(''); } - } else if (type === 'indent') { - ignoreLevel++; - } else if (type === 'outdent') { - ignoreLevel--; - if (ignoreLevel === 0) { - break; + // Trim the last line, since indentation of formatted pug is handled separately. + const lastLine: string | undefined = lines.pop(); + if (lastLine !== undefined) { + lines.push(lastLine.trimRight()); } + results.push(lines.join('\n')); } } - const lastToken: Token = this.tokens[index - 1]; - const lines: string[] = this.getUnformattedContentLines(firstToken, lastToken); - // Start with an empty string for the first newline after comment. - if (startsWithNewLine) { - lines.unshift(''); - } - // Trim the last line, since indentation of formatted pug is handled separately. - const lastLine: string | undefined = lines.pop(); - if (lastLine !== undefined) { - lines.push(lastLine.trimRight()); - } - results.push(lines.join('\n')); } } catch { throw new Error('Unhandled token: ' + JSON.stringify(token)); } + token = this.getNextToken(); } return results.join(''); } @@ -269,6 +266,19 @@ export class PugPrinter { return ''; } + private get previousToken(): Token | undefined { + return this.tokens[this.currentIndex - 1]; + } + + private get nextToken(): Token | undefined { + return this.tokens[this.currentIndex + 1]; + } + + private getNextToken(): Token | null { + this.currentIndex++; + return this.tokens[this.currentIndex] ?? null; + } + private quoteString(val: string): string { return `${this.quotes}${val}${this.quotes}`; } From 7d672ec215461c6965430ad0de48aa7ff1bdcbdf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ju=CC=88rg=20Lehni?= Date: Sat, 3 Oct 2020 01:26:03 +0200 Subject: [PATCH 5/7] Move handling of prettier-ignore comments to comment() callback --- src/printer.ts | 107 ++++++++++++++++++++++--------------------------- 1 file changed, 49 insertions(+), 58 deletions(-) diff --git a/src/printer.ts b/src/printer.ts index f9f725c6..1f6de940 100644 --- a/src/printer.ts +++ b/src/printer.ts @@ -190,53 +190,6 @@ export class PugPrinter { results.push(this[token.type](token)); break; } - if ( - token.type === 'comment' && - token.val.trim() === 'prettier-ignore' - ) { - // Use a own token processing loop to find the end of the stream of tokens to be ignored by formatting, - // and uses their `loc` properties to retrieve the original pug code to be used instead. - token = this.getNextToken(); - if (token) { - const firstToken: Token = token; - const startsWithNewLine: boolean = firstToken.type === 'newline'; - let skipNewline: boolean = startsWithNewLine; - let ignoreLevel: number = 0; - while (token) { - const { type } = token; - if (type === 'newline' && ignoreLevel === 0) { - // Skip first newline after prettier-ignore comment: - if (skipNewline) { - skipNewline = false; - } else { - break; - } - } else if (type === 'indent') { - ignoreLevel++; - } else if (type === 'outdent') { - ignoreLevel--; - if (ignoreLevel === 0) { - break; - } - } - token = this.getNextToken(); - } - if (token) { - const lastToken: Token = token; - const lines: string[] = this.getUnformattedContentLines(firstToken, lastToken); - // Start with an empty string for the first newline after comment. - if (startsWithNewLine) { - lines.unshift(''); - } - // Trim the last line, since indentation of formatted pug is handled separately. - const lastLine: string | undefined = lines.pop(); - if (lastLine !== undefined) { - lines.push(lastLine.trimRight()); - } - results.push(lines.join('\n')); - } - } - } } catch { throw new Error('Unhandled token: ' + JSON.stringify(token)); } @@ -816,18 +769,56 @@ export class PugPrinter { this.result += '\n'; } - private comment(token: CommentToken): string { + private comment(commentToken: CommentToken): string { let result: string = this.computedIndent; - if (this.checkTokenType(this.previousToken, ['newline', 'indent', 'outdent'], true)) { - result += ' '; - } - result += '//'; - if (!token.buffer) { - result += '-'; - } - result += formatCommentPreserveSpaces(token.val, this.options.commentPreserveSpaces); - if (this.nextToken?.type === 'start-pipeless-text') { - this.pipelessComment = true; + if (commentToken.val.trim() === 'prettier-ignore') { + // Use a own token processing loop to find the end of the stream of tokens to be ignored by formatting, + // and uses their `loc` properties to retrieve the original pug code to be used instead. + let token: Token | null = this.getNextToken(); + if (token) { + let skipNewline: boolean = token.type === 'newline'; + let ignoreLevel: number = 0; + while (token) { + const { type } = token; + if (type === 'newline' && ignoreLevel === 0) { + // Skip first newline after `prettier-ignore` comment + if (skipNewline) { + skipNewline = false; + } else { + break; + } + } else if (type === 'indent') { + ignoreLevel++; + } else if (type === 'outdent') { + ignoreLevel--; + if (ignoreLevel === 0) { + break; + } + } + token = this.getNextToken(); + } + if (token) { + const lines: string[] = this.getUnformattedContentLines(commentToken, token); + // Trim the last line, since indentation of formatted pug is handled separately. + const lastLine: string | undefined = lines.pop(); + if (lastLine !== undefined) { + lines.push(lastLine.trimRight()); + } + result += lines.join('\n'); + } + } + } else { + if (this.checkTokenType(this.previousToken, ['newline', 'indent', 'outdent'], true)) { + result += ' '; + } + result += '//'; + if (!commentToken.buffer) { + result += '-'; + } + result += formatCommentPreserveSpaces(commentToken.val, this.options.commentPreserveSpaces); + if (this.nextToken?.type === 'start-pipeless-text') { + this.pipelessComment = true; + } } return result; } From 6f66589c24343f7309226c5a936a33541c1336ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ju=CC=88rg=20Lehni?= Date: Sat, 3 Oct 2020 01:33:24 +0200 Subject: [PATCH 6/7] Use fuzzy-matching for prettier-ignore comments --- src/printer.ts | 2 +- tests/prettier-ignore/formatted.pug | 2 +- tests/prettier-ignore/unformatted.pug | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/printer.ts b/src/printer.ts index 1f6de940..f2e5e6b9 100644 --- a/src/printer.ts +++ b/src/printer.ts @@ -771,7 +771,7 @@ export class PugPrinter { private comment(commentToken: CommentToken): string { let result: string = this.computedIndent; - if (commentToken.val.trim() === 'prettier-ignore') { + if (/^\s*prettier-ignore\b/.test(commentToken.val)) { // Use a own token processing loop to find the end of the stream of tokens to be ignored by formatting, // and uses their `loc` properties to retrieve the original pug code to be used instead. let token: Token | null = this.getNextToken(); diff --git a/tests/prettier-ignore/formatted.pug b/tests/prettier-ignore/formatted.pug index 805e37b5..b0d19206 100644 --- a/tests/prettier-ignore/formatted.pug +++ b/tests/prettier-ignore/formatted.pug @@ -11,7 +11,7 @@ div :attribute2="bar", attribute3="something too long to keep on one line" ) - //- prettier-ignore + //- prettier-ignore (because reasons) div .wrapper-4(attributes1="foo" :attribute2="bar" attribute3 = "something too long to keep on one line") .wrapper-5( diff --git a/tests/prettier-ignore/unformatted.pug b/tests/prettier-ignore/unformatted.pug index f4bcafd3..908cb105 100644 --- a/tests/prettier-ignore/unformatted.pug +++ b/tests/prettier-ignore/unformatted.pug @@ -3,7 +3,7 @@ div //- prettier-ignore .wrapper-2(attributes1="foo" :attribute2="bar" attribute3 = "something too long to keep on one line") .wrapper-3(attributes1="foo" :attribute2="bar" attribute3 = "something too long to keep on one line") - //- prettier-ignore + //- prettier-ignore (because reasons) div .wrapper-4(attributes1="foo" :attribute2="bar" attribute3 = "something too long to keep on one line") .wrapper-5(attributes1="foo" :attribute2="bar" attribute3 = "something too long to keep on one line") From 7aed9073839e18664d0fc8c7807127929f2c8e2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ju=CC=88rg=20Lehni?= Date: Sun, 4 Oct 2020 00:57:06 +0200 Subject: [PATCH 7/7] Apply suggestions from code review --- README.md | 8 +++--- src/printer.ts | 18 +++++++++----- tests/prettier-ignore/formatted.pug | 36 +++++++++++++++++---------- tests/prettier-ignore/unformatted.pug | 18 +++++++++++--- 4 files changed, 53 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index 60f20094..ca7a8746 100644 --- a/README.md +++ b/README.md @@ -66,9 +66,9 @@ You can disable code formatting for a particular element by adding `//- pr ```pug div.text( color = "primary", disabled ="true" ) -// -prettier-ignore +//- prettier-ignore div.text( color = "primary", disabled ="true" ) -// -prettier-ignore +//- prettier-ignore: because of reasons div div.text( color = "primary", disabled ="true" ) ``` @@ -77,9 +77,9 @@ Prettified output: ```pug .text(color="primary", disabled) -// -prettier-ignore +//- prettier-ignore div.text( color = "primary", disabled ="true" ) -// -prettier-ignore +//- prettier-ignore: because of reasons div div.text( color = "primary", disabled ="true" ) ``` diff --git a/src/printer.ts b/src/printer.ts index f2e5e6b9..be8df493 100644 --- a/src/printer.ts +++ b/src/printer.ts @@ -99,10 +99,13 @@ export interface PugPrinterOptions { export class PugPrinter { private result: string = ''; - // The current index in the `tokens` array, starts at -1, because `getNextToken()` increases before retrieving + /** + * The index of the current token inside the `tokens` array + */ + // Start at -1, because `getNextToken()` increases it before retreval private currentIndex: number = -1; private currentLineLength: number = 0; - + private readonly indentString: string; private indentLevel: number = 0; @@ -253,11 +256,11 @@ export class PugPrinter { const startLine: number = start.line - 1; const endLine: number = end.line - 1; const parts: string[] = []; - parts.push(lines[startLine].substring(start.column - 1)); + parts.push(lines[startLine].slice(start.column - 1)); for (let line: number = startLine + 1; line < endLine; line++) { parts.push(lines[line]); } - parts.push(lines[endLine].substring(0, end.column - 1)); + parts.push(lines[endLine].slice(0, end.column - 1)); return parts; } @@ -771,8 +774,11 @@ export class PugPrinter { private comment(commentToken: CommentToken): string { let result: string = this.computedIndent; - if (/^\s*prettier-ignore\b/.test(commentToken.val)) { - // Use a own token processing loop to find the end of the stream of tokens to be ignored by formatting, + // See if this is a `//- prettier-ignore` comment, which would indicate that the part of the template + // that follows should be left unformatted. Support the same format as typescript-eslint is using for descriptons: + // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/ban-ts-comment.md#allow-with-description + if (/^ prettier-ignore($|[: ])/.test(commentToken.val)) { + // Use a separate token processing loop to find the end of the stream of tokens to be ignored by formatting, // and uses their `loc` properties to retrieve the original pug code to be used instead. let token: Token | null = this.getNextToken(); if (token) { diff --git a/tests/prettier-ignore/formatted.pug b/tests/prettier-ignore/formatted.pug index b0d19206..a3ecda26 100644 --- a/tests/prettier-ignore/formatted.pug +++ b/tests/prettier-ignore/formatted.pug @@ -5,17 +5,27 @@ div attribute3="something too long to keep on one line" ) //- prettier-ignore - .wrapper-2(attributes1="foo" :attribute2="bar" attribute3 = "something too long to keep on one line") - .wrapper-3( - attributes1="foo", - :attribute2="bar", - attribute3="something too long to keep on one line" - ) - //- prettier-ignore (because reasons) div - .wrapper-4(attributes1="foo" :attribute2="bar" attribute3 = "something too long to keep on one line") -.wrapper-5( - attributes1="foo", - :attribute2="bar", - attribute3="something too long to keep on one line" -) + .wrapper-2(attributes1="foo" :attribute2="bar" attribute3 = "something too long to keep on one line") + //- prettier-ignore: this is already ignored be the previous statement above + div + .wrapper-3(attributes1="foo" :attribute2="bar" attribute3 = "something too long to keep on one line") + div + .wrapper-4( + attributes1="foo", + :attribute2="bar", + attribute3="something too long to keep on one line" + ) + div + .wrapper-5( + attributes1="foo", + :attribute2="bar", + attribute3="something too long to keep on one line" + ) + //- prettier-ignore + div + .wrapper-6(attributes1="foo" :attribute2="bar" attribute3 = "something too long to keep on one line") + //- prettier-ignore: this is already ignored be the previous statement above + div + .wrapper-7(attributes1="foo" :attribute2="bar" attribute3 = "something too long to keep on one line") + div diff --git a/tests/prettier-ignore/unformatted.pug b/tests/prettier-ignore/unformatted.pug index 908cb105..91a69f4e 100644 --- a/tests/prettier-ignore/unformatted.pug +++ b/tests/prettier-ignore/unformatted.pug @@ -1,9 +1,19 @@ div .wrapper-1(attributes1="foo" :attribute2="bar" attribute3 = "something too long to keep on one line") //- prettier-ignore - .wrapper-2(attributes1="foo" :attribute2="bar" attribute3 = "something too long to keep on one line") - .wrapper-3(attributes1="foo" :attribute2="bar" attribute3 = "something too long to keep on one line") - //- prettier-ignore (because reasons) + div + .wrapper-2(attributes1="foo" :attribute2="bar" attribute3 = "something too long to keep on one line") + //- prettier-ignore: this is already ignored be the previous statement above + div + .wrapper-3(attributes1="foo" :attribute2="bar" attribute3 = "something too long to keep on one line") div .wrapper-4(attributes1="foo" :attribute2="bar" attribute3 = "something too long to keep on one line") -.wrapper-5(attributes1="foo" :attribute2="bar" attribute3 = "something too long to keep on one line") + div + .wrapper-5(attributes1="foo" :attribute2="bar" attribute3 = "something too long to keep on one line") + //- prettier-ignore + div + .wrapper-6(attributes1="foo" :attribute2="bar" attribute3 = "something too long to keep on one line") + //- prettier-ignore: this is already ignored be the previous statement above + div + .wrapper-7(attributes1="foo" :attribute2="bar" attribute3 = "something too long to keep on one line") + div