diff --git a/src/formatter.js b/src/formatter.js
index cecd4784..047b505f 100644
--- a/src/formatter.js
+++ b/src/formatter.js
@@ -17,6 +17,8 @@ const beautify = require('js-beautify').html;
const _ = require('lodash');
const vscodeTmModule = require('vscode-textmate');
const detectIndent = require('detect-indent');
+const Aigle = require('aigle');
+const { matchRecursive } = require('xregexp');
export default class Formatter {
constructor(options) {
@@ -28,11 +30,13 @@ export default class Formatter {
this.wrapLineLength = util.optional(this.options).wrapLineLength || 120;
this.wrapAttributes = util.optional(this.options).wrapAttributes || 'auto';
this.currentIndentLevel = 0;
+ this.currentScriptIndentLevel = 0;
this.shouldBeIndent = false;
this.isInsideCommentBlock = false;
this.stack = [];
this.rawBlocks = [];
this.rawPropsBlocks = [];
+ this.bladeDirectives = [];
this.bladeComments = [];
this.bladeBraces = [];
this.rawBladeBraces = [];
@@ -46,8 +50,20 @@ export default class Formatter {
.then((formattedAsPhp) => this.preserveBladeComment(formattedAsPhp))
.then((formattedAsPhp) => this.preserveBladeBrace(formattedAsPhp))
.then((formattedAsPhp) => this.preserveRawBladeBrace(formattedAsPhp))
+ .then((formattedAsPhp) =>
+ this.preserveBladeDirectivesInScripts(formattedAsPhp),
+ )
+ .then(async (formattedAsPhp) => {
+ this.bladeDirectives = await this.formatPreservedBladeDirectives(
+ this.bladeDirectives,
+ );
+ return formattedAsPhp;
+ })
.then((formattedAsPhp) => this.formatAsHtml(formattedAsPhp))
- .then((formattedAsHtml) => this.formatAsBlade(formattedAsHtml))
+ .then((formattedAsPhp) => this.formatAsBlade(formattedAsPhp))
+ .then((formattedAsPhp) =>
+ this.restoreBladeDirectivesInScripts(formattedAsPhp),
+ )
.then((formattedAsBlade) => this.restoreRawBladeBrace(formattedAsBlade))
.then((formattedAsBlade) => this.restoreBladeBrace(formattedAsBlade))
.then((formattedAsBlade) => this.restoreBladeComment(formattedAsBlade))
@@ -98,6 +114,56 @@ export default class Formatter {
});
}
+ preserveBladeDirectivesInScripts(content) {
+ return _.replace(
+ content,
+ /`;
+ }
+ const directives = _.chain(indentStartTokens)
+ .without('@switch', '@forelse')
+ .map((x) => _.replace(x, /@/, ''))
+ .value();
+
+ _.forEach(directives, (directive) => {
+ try {
+ const recursivelyMatched = matchRecursive(
+ p2,
+ `\\@${directive}`,
+ `\\@end${directive}`,
+ 'gms',
+ {
+ valueNames: [null, 'left', 'match', 'right'],
+ },
+ );
+ let output = '';
+
+ if (_.isEmpty(recursivelyMatched)) {
+ return;
+ }
+
+ _.forEach(recursivelyMatched, (r) => {
+ output += r.value;
+ if (r.name === 'right') {
+ if (p2.includes(output)) {
+ // eslint-disable-next-line no-param-reassign
+ p2 = _.replace(p2, output, this.storeBladeDirective(output));
+ }
+ output = '';
+ }
+ });
+ } catch (error) {
+ throw new Error('directive in scripts parsing error');
+ }
+ });
+
+ return ``;
+ },
+ );
+ }
+
async preserveBladeComment(content) {
return _.replace(content, /\{\{--(.*?)--\}\}/gs, (_match, p1) => {
return this.storeBladeComment(p1);
@@ -124,6 +190,12 @@ export default class Formatter {
return this.getRawPropsPlaceholder(this.rawPropsBlocks.push(value) - 1);
}
+ storeBladeDirective(value) {
+ return this.getBladeDirectivePlaceholder(
+ this.bladeDirectives.push(value) - 1,
+ );
+ }
+
storeBladeComment(value) {
return this.getBladeCommentPlaceholder(this.bladeComments.push(value) - 1);
}
@@ -147,6 +219,10 @@ export default class Formatter {
return _.replace('@__raw_props_block_#__@', '#', replace);
}
+ getBladeDirectivePlaceholder(replace) {
+ return _.replace('___blade_directive_#___', '#', replace);
+ }
+
getBladeCommentPlaceholder(replace) {
return _.replace('___blade_comment_#___', '#', replace);
}
@@ -261,6 +337,37 @@ export default class Formatter {
.join('\n');
}
+ restoreBladeDirectivesInScripts(content) {
+ const regex = new RegExp(
+ `${this.getBladeDirectivePlaceholder('(\\d+)')}`,
+ 'gm',
+ );
+
+ let result = _.replace(content, regex, (_match, p1) => {
+ return util.indent(
+ this.bladeDirectives[p1],
+ this.currentScriptIndentLevel,
+ { ignoreFirstLine: true },
+ );
+ });
+
+ if (regex.test(content)) {
+ this.currentScriptIndentLevel += 1;
+ result = this.restoreBladeDirectivesInScripts(result);
+ }
+
+ return result;
+ }
+
+ async formatPreservedBladeDirectives(directives) {
+ return Aigle.map(directives, async (content) => {
+ const formattedAsHtml = await this.formatAsHtml(content);
+ const formatted = await this.formatAsBlade(formattedAsHtml);
+ const trimmed = formatted.trimRight('\n');
+ return util.indent(trimmed, 1, { ignoreFirstLine: true });
+ });
+ }
+
restoreBladeComment(content) {
return new Promise((resolve) => resolve(content)).then((res) => {
return _.replace(
@@ -336,6 +443,8 @@ export default class Formatter {
}
formatTokenizedLines(splitedLines, tokenizedLines) {
+ this.result = [];
+ this.stack = [];
for (let i = 0; i < splitedLines.length; i += 1) {
const originalLine = splitedLines[i];
const tokenizeLineResult = tokenizedLines[i];