Instantly share code, notes, and snippets.

Embed
What would you like to do?
JS Beautify hack to work with Blade directives (Laravel)
function Beautifier(html_source, options, js_beautify, css_beautify) {
//Wrapper function to invoke all the necessary constructors and deal with the output.
html_source = html_source || '';
// BEGIN
html_source = html_source.replace(/\{\{((?:(?!\}\}).)+)\}\}/g, function (m, c) {
if (c) {
c = c.replace(/(^[ \t]*|[ \t]*$)/g, '');
c = c.replace(/'/g, ''');
c = c.replace(/"/g, '"');
c = encodeURIComponent(c);
}
return "{{" + c + "}}";
});
html_source = html_source.replace(/^[ \t]*@([a-z]+)([^\r\n]*)$/gim, function (m, d, c) {
var ce = c;
if (ce) {
ce = ce.replace(/'/g, ''');
ce = ce.replace(/"/g, '"');
ce = "|" + encodeURIComponent(ce);
}
switch (d) {
case 'break':
case 'case':
case 'continue':
case 'csrf':
case 'else':
case 'elseif':
case 'empty':
case 'extends':
case 'include':
case 'includeFirst':
case 'includeIf':
case 'includeWhen':
case 'inject':
case 'json':
case 'method':
case 'parent':
case 'stack':
case 'yield':
return "<blade " + d + ce + "/>";
case 'section':
if(c.match(/[ \t]*\([ \t]*['"][^'"]*['"][ \t]*\)/i)){
return "<blade " + d + ce + ">";
} else {
return "<blade " + d + ce + "/>";
}
case 'show':
case 'stop':
return "</blade " + d + ce + ">";
default:
if (d.startsWith('end')) {
return "</blade " + d + ce + ">";
} else {
return "<blade " + d + ce + ">";
}
}
});
// END
...
var sweet_code = multi_parser.output.join('').replace(/[\r\n\t ]+$/, '');
// BEGIN
sweet_code = sweet_code.replace(/^([ \t]*)<\/?blade ([a-z]+)\|?([^>\/]+)?\/?>$/gim, function (m, s, d, c) {
if (c) {
c = decodeURIComponent(c);
c = c.replace(/&#39;/g, "'");
c = c.replace(/&#34;/g, '"');
c = c.replace(/^[ \t]*/g, '');
} else {
c = "";
}
if (!s) {
s = "";
}
return s + "@" + d + c;
});
sweet_code = sweet_code.replace(/\{\{((?:(?!\}\}).)+)\}\}/g, function (m, c) {
if (c) {
c = decodeURIComponent(c);
c = c.replace(/&#39;/g, "'");
c = c.replace(/&#34;/g, '"');
c = c.replace(/(^[ \t]*|[ \t]*$)/g, ' ');
}
return "{{" + c + "}}";
});
// END
...
return sweet_code;
}
@mpryvkin

This comment has been minimized.

Owner

mpryvkin commented Apr 22, 2018

UPDATE:
9/4/18: This solution no longer works with the most recent version 1.4.2 of HookyQR.beautify extension.


This gist is based on code written by Faizal Dwi Nugraha and includes some minor improvements for Windows environment and @section directive.

You have to modify the files under node_modules for the HookyQR.beautify extension.

  1. On Unix cd ~/.vscode/extensions/HookyQR.beautify-1.3.2/node_modules/js-beautify. On Windows, go to %USERPROFILE%\.vscode\extensions\HookyQR.beautify-1.3.2\node_modules\js-beautify. Use your current version number instead of 1.3.2.

  2. Edit js/lib/beautify-html.js and add the code from the gist.

  3. Configure VS Code to treat Blade templates as HTML by adding "*.blade.php": "html" to files.associations setting as shown below.

    "files.associations": {
        "*.blade.php": "html",
        // ...
    }
    

    If your Blade templates are configured to be detected as blade format, you may configure Beautify extension to treat blade format as HTML by adding blade to html list of the beautify.language setting.

    "html": [
        "htm",
        "html",
        "blade"
    ]
    
  4. Restart VS Code.

  5. IMPORTANT: Every time when VS Code is updated, check whether the fix is still in place and re-apply if needed.

See How to format Laravel Blade templates in Visual Studio Code for more information.

@FaridAghili

This comment has been minimized.

FaridAghili commented May 14, 2018

It shoud add space after @if , @foreach, etc:
@if (...)
@foreach (...)

also it doesn't respect html format config like:
"html.format.extraLiners": ""

@valeryan

This comment has been minimized.

valeryan commented May 17, 2018

fixing the if, foreach, while, etc elements can be accomplished by adding a switch to the sweet code section.

 // BEGIN
sweet_code = sweet_code.replace(/^([ \t]*)<\/?blade ([a-z]+)\|?([^>\/]+)?\/?>$/gim, function (m, s, d, c) {
    if (c) {
        c = decodeURIComponent(c);
        c = c.replace(/&#39;/g, "'");
        c = c.replace(/&#34;/g, '"');
        c = c.replace(/^[ \t]*/g, '');
    } else {
        c = "";
    }
    if (!s) {
        s = "";
    }
    switch (d) {
        case 'if':
        case 'elseif':
        case 'unless':
        case 'for':
        case 'foreach':
        case 'forelse':
        case 'while':
            return s + "@" + d + " " + c;

        default:
            return s + "@" + d + c;
    }

});
sweet_code = sweet_code.replace(/\{\{((?:(?!\}\}).)+)\}\}/g, function (m, c) {
    if (c) {
        c = decodeURIComponent(c);
        c = c.replace(/&#39;/g, "'");
        c = c.replace(/&#34;/g, '"');
        c = c.replace(/(^[ \t]*|[ \t]*$)/g, ' ');
    }
    return "{{" + c + "}}";
});
// END
@FaridAghili

This comment has been minimized.

FaridAghili commented May 19, 2018

@valeryan yes, that perfectly works. I can confirm that it covers every blade directives that should have an space after it (based on laravel's blade doc).
Thank you.
I already opened an issue on js-beautify and requested merging this code, looking forward to it.

@beatwiz

This comment has been minimized.

beatwiz commented May 19, 2018

Thanks!

It seems though, that is converting {{-- into {{ -- and that breaks a laravel comment section

@ammarsdc

This comment has been minimized.

ammarsdc commented May 19, 2018

Hi everyone. Thanks @mpryvkin, @fzldn and @valeryan for sharing this! It works except this:

@if ($inventory->grade === 'A')
     {{ $inventory->product->priceValid($inventory->created_at)->seller_price_a }}
@elseif ($inventory->grade === 'B')
      {{ $inventory->product->priceValid($inventory->created_at)->seller_price_b }}
@endif

it turns to this:

@if ($inventory->grade === 'A')
     {{ $inventory->product->priceValid($inventory->created_at)->seller_price_a }}
     <blade elseif|%20(%24inventory-%3Egrade%20%3D%3D%3D%20%26%2339%3BB%26%2339%3B)/> {{ $inventory->product->priceValid($inventory->created_at)->seller_price_b }}
@endif

Anyone facing the same problems?

@valeryan

This comment has been minimized.

valeryan commented May 19, 2018

@beatwiz I would try replacing the regex /\{\{((?:(?!\}\}).)+)\}\}/g with /\{\{([^-](?:(?!\}\}).)+)\}\}/g to make it ignore {{-- --}}.

@beatwiz

This comment has been minimized.

beatwiz commented May 22, 2018

@valeryan thank you so much!

@FaridAghili

This comment has been minimized.

FaridAghili commented Jun 6, 2018

@mpryvkin Do you mind merging the suggested fixes by @valeryan?

@thsneumann

This comment has been minimized.

thsneumann commented Jun 8, 2018

I have the same problem as @anmarsdc. Has anyone found a solution for this?

@Malin88

This comment has been minimized.

Malin88 commented Jul 10, 2018

Same as @ammarsdc :/
Also @else transform to <blade else|%20/>

@mpryvkin

This comment has been minimized.

Owner

mpryvkin commented Jul 21, 2018

@Malin88 @thsneumann I forgot to mention that you probably need to reapply this fix every time when js-beautify or HookyQR.beautify are updated. I know it's a pain, but it works for me better than any other blade formatter out there. I recheck whether my fix is in place every time I update VS Code.

@valeryan

This comment has been minimized.

valeryan commented Aug 12, 2018

@ammarsdc Sorry, I have not had a chance to swing back around to try and fix your issues. I am not currently working with laravel and I don't have this setup up to test with right now. I will try to look at this again soon.

@valeryan

This comment has been minimized.

valeryan commented Aug 13, 2018

@ammarsdc, @Malin88 I have done a little hackery to get this to work for more of the blade syntax. https://gist.github.com/valeryan/40a5fcc97edb21e310c412e48d62a792

It still has a few issues that I know of:

Extra indents are added to the formatting of else and elseif statement.
The empty tag can be used in two different ways and I have only programmed for one of them for now.

I will try and work out a few more kinks. @mpryvkin If you wanted to collab on this at some point I would be open. The author of js-beautify has said he is open to the idea of merging this if it can be tested. beautify-web/js-beautify#845. My feeling though is that having js-beautify do this is really out of scope. I think I may go fork the laravel blade highlighter extension and see if it can be fixed. Like many of the popular vscode extensions, it appears to mostly be abandoned...

@shamilovtim

This comment has been minimized.

shamilovtim commented Dec 15, 2018

@valeryan

I don't see how it's out of scope for js-beautify since VSCode uses js-beautify internally. The most elegant solution is for the native reindent of VSC to function with templating DSL in popular web frameworks, and this makes sense, since people are using VSCode for popular web frameworks, not for C, C++ and Go. That being said, a 3rd party reindent is fine too.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment