diff --git a/__tests__/formatter.test.ts b/__tests__/formatter.test.ts
index 461f75ab..3b03c348 100644
--- a/__tests__/formatter.test.ts
+++ b/__tests__/formatter.test.ts
@@ -4824,4 +4824,171 @@ describe('formatter', () => {
endOfLine: 'CRLF',
});
});
+
+ test('fix shufo/prettier-plugin-blade#166', async () => {
+ const content = [
+ `@php`,
+ ` /**`,
+ ` * @var \App\Models\User $user`,
+ ` * @var \App\Models\Post $post`,
+ ` */`,
+ `@endphp`,
+ `{{ $post->title }} by {{ $user->name }}`,
+ ].join('\n');
+
+ const expected = [
+ `@php`,
+ ` /**`,
+ ` * @var \App\Models\User $user`,
+ ` * @var \App\Models\Post $post`,
+ ` */`,
+ `@endphp`,
+ `{{ $post->title }} by {{ $user->name }}`,
+ ``,
+ ].join('\n');
+
+ await util.doubleFormatCheck(content, expected);
+ });
+
+ test('raw php comment block', async () => {
+ const content = [
+ `
`,
+ ` `,
+ ` `,
+ ` `,
+ ` `,
+ `
`,
+ ].join('\n');
+
+ const expected = [
+ ``,
+ ` `,
+ ` `,
+ ` `,
+ ` `,
+ `
`,
+ ``,
+ ].join('\n');
+
+ await util.doubleFormatCheck(content, expected);
+ });
+
+ test('php directive comment block', async () => {
+ const content = [
+ ``,
+ ` @php`,
+ ` /**`,
+ ` * @var \App\Models\User $user`,
+ ` * @var \App\Models\Post $post`,
+ ` */`,
+ ` @endphp`,
+ ` @php`,
+ ` /**`,
+ ` * @var \App\Models\User $user`,
+ ` * @var \App\Models\Post $post`,
+ ` */`,
+ ` /**`,
+ ` * @var \App\Models\User $user`,
+ ` * @var \App\Models\Post $post`,
+ ` */ echo 1;`,
+ ` @endphp`,
+ ` @php`,
+ ` /**`,
+ ` * @var \App\Models\User $user`,
+ ` * @var \App\Models\Post $post`,
+ ` */`,
+ ` @endphp`,
+ ` @php`,
+ ` /**`,
+ ` \App\Models\User $user`,
+ ` \App\Models\Post $post`,
+ ` */`,
+ ` @endphp`,
+ `
`,
+ ].join('\n');
+
+ const expected = [
+ ``,
+ ` @php`,
+ ` /**`,
+ ` * @var \App\Models\User $user`,
+ ` * @var \App\Models\Post $post`,
+ ` */`,
+ ` @endphp`,
+ ` @php`,
+ ` /**`,
+ ` * @var \App\Models\User $user`,
+ ` * @var \App\Models\Post $post`,
+ ` */`,
+ ` /**`,
+ ` * @var \App\Models\User $user`,
+ ` * @var \App\Models\Post $post`,
+ ` */ echo 1;`,
+ ` @endphp`,
+ ` @php`,
+ ` /**`,
+ ` * @var \App\Models\User $user`,
+ ` * @var \App\Models\Post $post`,
+ ` */`,
+ ` @endphp`,
+ ` @php`,
+ ` /**`,
+ ` \App\Models\User $user`,
+ ` \App\Models\Post $post`,
+ ` */`,
+ ` @endphp`,
+ `
`,
+ ``,
+ ].join('\n');
+
+ await util.doubleFormatCheck(content, expected);
+ });
});
diff --git a/src/comment.ts b/src/comment.ts
new file mode 100644
index 00000000..b82cb7e5
--- /dev/null
+++ b/src/comment.ts
@@ -0,0 +1,54 @@
+/**
+ * Formats php comment
+ *
+ * @param comment
+ * @returns string
+ */
+export function formatPhpComment(comment: string): string {
+ const lines = splitByLines(comment);
+
+ if (!isMultiline(lines)) {
+ return comment;
+ }
+
+ let nonCommentLineExists = false;
+
+ const mapped = lines.map((line: string, row: number) => {
+ if (row === 0) {
+ return line;
+ }
+
+ if (nonCommentLineExists) {
+ return line;
+ }
+
+ if (!isCommentedLine(line)) {
+ nonCommentLineExists = true;
+ return line;
+ }
+
+ const trimmedLine = line.trim();
+
+ return addPrefixToLine(trimmedLine);
+ });
+
+ return mapped.join('\n');
+}
+
+function splitByLines(content: string): Array {
+ return content.split('\n');
+}
+
+function isCommentedLine(line: string): boolean {
+ return line.trim().startsWith('*');
+}
+
+function isMultiline(lines: Array): boolean {
+ return lines.length > 1;
+}
+
+function addPrefixToLine(line: string): string {
+ const prefix = ' ';
+
+ return `${prefix}${line}`;
+}
diff --git a/src/formatter.ts b/src/formatter.ts
index d7f88674..887bdbf7 100644
--- a/src/formatter.ts
+++ b/src/formatter.ts
@@ -32,6 +32,7 @@ import {
} from './indent';
import { nestedParenthesisRegex } from './regex';
import { SortHtmlAttributes } from './runtimeConfig';
+import { formatPhpComment } from './comment';
export default class Formatter {
argumentCheck: any;
@@ -717,7 +718,9 @@ export default class Formatter {
}
preservePhpComment(content: string) {
- return _.replace(content, /\/\*+([^\*]*?)\*\//gi, (match: string) => this.storePhpComment(match));
+ return _.replace(content, /\/\*(?:[^*]|[\r\n]|(?:\*+(?:[^*\/]|[\r\n])))*\*+\//gi, (match: string) =>
+ this.storePhpComment(match),
+ );
}
async preserveBladeBrace(content: any) {
@@ -1212,8 +1215,10 @@ export default class Formatter {
return `@php${q2}@endphp`;
}
- const preserved = this.preserveStringLiteralInPhp(q2);
- const indented = this.indentRawBlock(indent, preserved);
+ let preserved = this.preserveStringLiteralInPhp(q2);
+ preserved = this.preservePhpComment(preserved);
+ let indented = this.indentRawBlock(indent, preserved);
+ indented = this.restorePhpComment(indented);
const restored = this.restoreStringLiteralInPhp(indented);
return `@php${restored}@endphp`;
@@ -1268,7 +1273,8 @@ export default class Formatter {
return prefix + line;
})
- .join('\n');
+ .join('\n')
+ .value();
}
indentBladeDirectiveBlock(indent: detectIndent.Indent, content: any) {
@@ -1397,6 +1403,43 @@ export default class Formatter {
.join('\n');
}
+ indentPhpComment(indent: detectIndent.Indent, content: string) {
+ if (_.isEmpty(indent.indent)) {
+ return content;
+ }
+
+ if (this.isInline(content)) {
+ return `${content}`;
+ }
+
+ const leftIndentAmount = indent.amount;
+ const indentLevel = leftIndentAmount / this.indentSize;
+ const prefixSpaces = this.indentCharacter.repeat(indentLevel < 0 ? 0 : indentLevel * this.indentSize);
+
+ const lines = content.split('\n');
+ let withoutCommentLine = false;
+
+ return _.chain(lines)
+ .map((line: string, index: number) => {
+ if (index === 0) {
+ return line.trim();
+ }
+
+ if (!line.trim().startsWith('*')) {
+ withoutCommentLine = true;
+ return line;
+ }
+
+ if (line.trim().endsWith('*/') && withoutCommentLine) {
+ return line;
+ }
+
+ return prefixSpaces + line;
+ })
+ .join('\n')
+ .value();
+ }
+
restoreBladeDirectivesInScripts(content: any) {
const regex = new RegExp(`${this.getBladeDirectivePlaceholder('(\\d+)')}`, 'gm');
@@ -1522,8 +1565,15 @@ export default class Formatter {
restorePhpComment(content: string) {
return _.replace(
content,
- new RegExp(`${this.getPhpCommentPlaceholder('(\\d+)')}`, 'gms'),
- (_match: string, p1: number) => this.phpComments[p1],
+ new RegExp(`${this.getPhpCommentPlaceholder('(\\d+)')};{0,1}`, 'gms'),
+ (_match: string, p1: number) => {
+ const placeholder = this.getPhpCommentPlaceholder(p1.toString());
+ const matchedLine = content.match(new RegExp(`^(.*?)${placeholder}`, 'gmi')) ?? [''];
+ const indent = detectIndent(matchedLine[0]);
+ const formatted = formatPhpComment(this.phpComments[p1]);
+
+ return this.indentPhpComment(indent, formatted);
+ },
);
}