Glavin001 / atom-beautify

:mega: Help Wanted - Looking for Maintainer: https://github.com/Glavin001/atom-beautify/issues/2572 | :lipstick: Universal beautification package for Atom editor (:warning: Currently migrating to https://github.com/Unibeautify/ and have very limited bandwidth for Atom-Beautify Issues. Thank you for your patience and understanding :heart: )
http://unibeautify.com/
MIT License
1.5k stars 454 forks source link

Freemarker HTML - extra space in Beautified code #1455

Open logansullivan opened 7 years ago

logansullivan commented 7 years ago

Description

When using the Atom Beautifcation tools for Freemarker templates set as .html parts of the code is getting random spaces added.

Input Before Beautification

This is what the code looked like before:

<@compress single_line=true>
<#--
###########################################################################################
App Code:   V1234-SAML_DO_THIS
Vendor:     The Vendor Name
Author:     Stan Freeman
Date:       1/5/2017
Purpose:    Pull Customer Account info and pull DEPOSIT accounts for that user
Last Updated:   1/9/2017 - skf
                1/5/2017 - skf Initial creation
###########################################################################################
-->
<#-- ***********  Default Variables ************ -->
<#assign fsgCalls = "accounts,customer,financialinfo">
<#assign phoneNumber="">
<#assign address1="">
<#assign address2="">
<#assign city="">
<#assign state="">
<#assign postalCode="">

<userInfo>
    <#if info?exists & info.getFiCustomer()?exists>
        <#assign fiCustomer = info.getFiCustomer()>
        <#if fiCustomer.getPerson()?exists && fiCustomer.getPerson().getPersonName()?exists>

            <#assign person     = info.getFiCustomer().getPerson()>
            <#assign personName = info.getFiCustomer().getPerson().getPersonName()>
            <firstName></firstName>
            <lastName></lastName>

            <#if personName.getFullName()?exists>
                <FullName>${personName.getFullName()}</FullName>
            </#if>
        </#if>

        <#if person.getContactInfo()?exists>
            <#assign  contactInfo = person.getContactInfo()>
            <#if contactInfo.getPhoneNumber()?exists && contactInfo.getPhoneNumber()[0]?exists && contactInfo.getPhoneNumber()[0].getNumber()?exists>
                <#assign  phoneNumber = contactInfo.getPhoneNumber()[0].getNumber()>
            </#if>
            <#if contactInfo.getPostalAddress()[0]?exists>
                <#assign  postalAddress = contactInfo.getPostalAddress()[0]>
                <#if postalAddress.getAddress1()?exists>
                    <#assign  address1 = postalAddress.getAddress1()>
                </#if>
                <#if postalAddress.getAddress2()?exists>
                    <#assign  address2 = postalAddress.getAddress2()>
                </#if>
                <#if postalAddress.getState()?exists>
                    <#assign  state = postalAddress.getState()>
                </#if>
                <#if postalAddress.getCity()?exists>
                    <#assign  city = postalAddress.getCity()>
                </#if>
                <#if postalAddress.getPostalCode()?exists>
                    <#assign  postalCode = postalAddress.getPostalCode()>
                </#if>
            </#if>
        </#if>  <#-- end person.getContactInfo -->

    </#if>  <#-- end info?exists & info.getFiCustomer -->

    <#if ficustomer?exists>
        <#assign person = ficustomer.getPerson()>
        <#if person.getContactInfo()?exists && person.getContactInfo().getEmailAddress()?exists>
            <email>${person.getContactInfo().getEmailAddress()}</email>
        </#if>
    </#if>

    <address1>${address1}</address1>
    <address2>${address2}</address2>
    <city>${city}</city>
    <state>${state}</state>
    <zip>${postalCode?substring(0, 5)}</zip>
    <homePhoneNumber>${phoneNumber}</homePhoneNumber>

</userInfo>

<CCMasking>
    <#list accounts.getAccount() as account>
        <#if account.getAccountNumber()?exists>
            <#assign ccNumber = account.getAccountNumber().getRawHostValue()>

            <#if ccNumber?exists>

                <#assign ccNumberLength = ccNumber?length>
                <#assign firstSix       = ccNumber?substring(0, 6)>
                <#assign lastFour       = ccNumber?substring(ccNumberLength-4)>
                <#assign maskedCCNumber = firstSix + "xxxx" + lastFour>

                <MaskedCCNumber>${maskedCCNumber}</MaskedCCNumber>
            </#if>
        </#if>
    </#list>
</CCMasking>

</@compress>

Expected Output

The beautified code should have looked like this:

<@compress single_line=true>
    <#-- ########################################################################################### App Code: V1234-SAML_DO_THIS Vendor: The Vendor Name Author: Stan Freeman Date: 1/5/2017 Purpose: Pull Customer Account info and pull DEPOSIT accounts for
                    that user Last Updated: 1/9/2017 - skf 1/5/2017 - skf Initial creation ########################################################################################### -->
        <#-- *********** Default Variables ************ -->
            <#assign fsgCalls="accounts,customer,financialinfo">
                <#assign phoneNumber="">
                    <#assign address1="">
                        <#assign address2="">
                            <#assign city="">
                                <#assign state="">
                                    <#assign postalCode="">

                                        <userInfo>
                                            <#if info?exists & info.getFiCustomer()?exists>
                                                <#assign fiCustomer=info.getFiCustomer()>
                                                    <#if fiCustomer.getPerson()?exists && fiCustomer.getPerson().getPersonName()?exists>

                                                        <#assign person=info.getFiCustomer().getPerson()>
                                                            <#assign personName=info.getFiCustomer().getPerson().getPersonName()>
                                                                <firstName></firstName>
                                                                <lastName></lastName>

                                                                <#if personName.getFullName()?exists>
                                                                    <FullName>${personName.getFullName()}</FullName>
                                                                </#if>
                                                    </#if>

                                                    <#if person.getContactInfo()?exists>
                                                        <#assign contactInfo=person.getContactInfo()>
                                                            <#if contactInfo.getPhoneNumber()?exists && contactInfo.getPhoneNumber()[0]?exists && contactInfo.getPhoneNumber()[0].getNumber()?exists>
                                                                <#assign phoneNumber=contactInfo.getPhoneNumber()[0].getNumber()>
                                                            </#if>
                                                            <#if contactInfo.getPostalAddress()[0]?exists>
                                                                <#assign postalAddress=contactInfo.getPostalAddress()[0]>
                                                                    <#if postalAddress.getAddress1()?exists>
                                                                        <#assign address1=postalAddress.getAddress1()>
                                                                    </#if>
                                                                    <#if postalAddress.getAddress2()?exists>
                                                                        <#assign address2=postalAddress.getAddress2()>
                                                                    </#if>
                                                                    <#if postalAddress.getState()?exists>
                                                                        <#assign state=postalAddress.getState()>
                                                                    </#if>
                                                                    <#if postalAddress.getCity()?exists>
                                                                        <#assign city=postalAddress.getCity()>
                                                                    </#if>
                                                                    <#if postalAddress.getPostalCode()?exists>
                                                                        <#assign postalCode=postalAddress.getPostalCode()>
                                                                    </#if>
                                                            </#if>
                                                    </#if>
                                                    <#-- end person.getContactInfo -->

                                            </#if>
                                            <#-- end info?exists & info.getFiCustomer -->

                                                <#if ficustomer?exists>
                                                    <#assign person=f icustomer.getPerson()>
                                                        <#if person.getContactInfo()?exists && person.getContactInfo().getEmailAddress()?exists>
                                                            <email>${person.getContactInfo().getEmailAddress()}</email>
                                                        </#if>
                                                </#if>

                                                <address1>${address1}</address1>
                                                <address2>${address2}</address2>
                                                <city>${city}</city>
                                                <state>${state}</state>
                                                <zip>${postalCode?substring(0, 5)}</zip>
                                                <homePhoneNumber>${phoneNumber}</homePhoneNumber>

                                        </userInfo>

                                        <CCMasking>
                                            <#list accounts.getAccount() as account>
                                                <#if account.getAccountNumber()?exists>
                                                    <#assign ccNumber=account.getAccountNumber().getRawHostValue()>

                                                        <#if ccNumber?exists>

                                                            <#assign ccNumberLength=ccNumber?length>
                                                                <#assign firstSix=ccNumber?substring(0, 6)>
                                                                    <#assign lastFour=ccNumber?substring(ccNumberLength-4)>
                                                                        <#assign maskedCCNumber=firstSix + "xxxx" + lastFour>

                                                                            <MaskedCCNumber>${maskedCCNumber}</MaskedCCNumber>
                                                        </#if>
                                                </#if>
                                            </#list>
                                        </CCMasking>

</@compress>

Actual Output

The beautified code actually looked like this:

<@compress single_line=true>
    <#-- ########################################################################################### App Code: V1234-SAML_DO_THIS Vendor: The Vendor Name Author: Stan Freeman Date: 1/5/2017 Purpose: Pull Customer Account info and pull DEPOSIT accounts for
                    that user Last Updated: 1/9/2017 - skf 1/5/2017 - skf Initial creation ########################################################################################### -->
        <#-- *********** Default Variables ************ -->
            <#assign fsgCalls="accounts,customer,financialinfo">
                <#assign phoneNumber="">
                    <#assign address1="">
                        <#assign address2="">
                            <#assign city="">
                                <#assign state="">
                                    <#assign postalCode="">

                                        <userInfo>
                                            <#if info?exists & info.getFiCustomer()?exists>
                                                <#assign fiCustomer=i nfo.getFiCustomer()>
                                                    <#if fiCustomer.getPerson()?exists && fiCustomer.getPerson().getPersonName()?exists>

                                                        <#assign person=i nfo.getFiCustomer().getPerson()>
                                                            <#assign personName=i nfo.getFiCustomer().getPerson().getPersonName()>
                                                                <firstName></firstName>
                                                                <lastName></lastName>

                                                                <#if personName.getFullName()?exists>
                                                                    <FullName>${personName.getFullName()}</FullName>
                                                                </#if>
                                                    </#if>

                                                    <#if person.getContactInfo()?exists>
                                                        <#assign contactInfo=p erson.getContactInfo()>
                                                            <#if contactInfo.getPhoneNumber()?exists && contactInfo.getPhoneNumber()[0]?exists && contactInfo.getPhoneNumber()[0].getNumber()?exists>
                                                                <#assign phoneNumber=c ontactInfo.getPhoneNumber()[0].getNumber()>
                                                            </#if>
                                                            <#if contactInfo.getPostalAddress()[0]?exists>
                                                                <#assign postalAddress=c ontactInfo.getPostalAddress()[0]>
                                                                    <#if postalAddress.getAddress1()?exists>
                                                                        <#assign address1=p ostalAddress.getAddress1()>
                                                                    </#if>
                                                                    <#if postalAddress.getAddress2()?exists>
                                                                        <#assign address2=p ostalAddress.getAddress2()>
                                                                    </#if>
                                                                    <#if postalAddress.getState()?exists>
                                                                        <#assign state=p ostalAddress.getState()>
                                                                    </#if>
                                                                    <#if postalAddress.getCity()?exists>
                                                                        <#assign city=p ostalAddress.getCity()>
                                                                    </#if>
                                                                    <#if postalAddress.getPostalCode()?exists>
                                                                        <#assign postalCode=p ostalAddress.getPostalCode()>
                                                                    </#if>
                                                            </#if>
                                                    </#if>
                                                    <#-- end person.getContactInfo -->

                                            </#if>
                                            <#-- end info?exists & info.getFiCustomer -->

                                                <#if ficustomer?exists>
                                                    <#assign person=f icustomer.getPerson()>
                                                        <#if person.getContactInfo()?exists && person.getContactInfo().getEmailAddress()?exists>
                                                            <email>${person.getContactInfo().getEmailAddress()}</email>
                                                        </#if>
                                                </#if>

                                                <address1>${address1}</address1>
                                                <address2>${address2}</address2>
                                                <city>${city}</city>
                                                <state>${state}</state>
                                                <zip>${postalCode?substring(0, 5)}</zip>
                                                <homePhoneNumber>${phoneNumber}</homePhoneNumber>

                                        </userInfo>

                                        <CCMasking>
                                            <#list accounts.getAccount() as account>
                                                <#if account.getAccountNumber()?exists>
                                                    <#assign ccNumber=a ccount.getAccountNumber().getRawHostValue()>

                                                        <#if ccNumber?exists>

                                                            <#assign ccNumberLength=c cNumber?length>
                                                                <#assign firstSix=c cNumber?substring(0, 6)>
                                                                    <#assign lastFour=c cNumber?substring(ccNumberLength-4)>
                                                                        <#assign maskedCCNumber=f irstSix + "xxxx" + lastFour>

                                                                            <MaskedCCNumber>${maskedCCNumber}</MaskedCCNumber>
                                                        </#if>
                                                </#if>
                                            </#list>
                                        </CCMasking>

</@compress>

Steps to Reproduce

  1. Add code to Atom editor
  2. Run command Atom Beautify: Beautify Editor
  3. This beautified code does not look right!

Debug

Here is a link to the debug.md Gist: https://gist.github.com/logansullivan/d25812ffb4d55f6369c1349a3ea42675

Checklist

I have:

prettydiff commented 7 years ago

The challenge with Freemarker is that it is forgiving with syntax violations. In the case of your samples the <#assign> tags should be self-closing: <#assign variable=value/>. Currently, they aren't self closing and so the beautifiers think they are opening tags. There are other weird syntax forgiveness things that Freemarker does that I cannot think about off the top of my head.

JS Beautify, which supports HTML beautification very well, claims to provide no XML support, so use it at your own risk. Pretty Diff does provide support for XML and is the official XML beautifier used in Atom Beautify, so you sure switch your beautifier to Pretty Diff for HTML or change the language in Atom settings from HTML to XML.

I will need to enhance Pretty Diff to work around these Freemarker quirks to order for it to beautify correctly. I really should do this since I am stuck using Freemarker at work anyways.

logansullivan commented 7 years ago

Thanks for the self closing tip that is very helpful. Ya I am stuck using Freemarker at work as well, Thanks for your efforts in looking into this! Would be super awesome if it accepted the .ftl format but I know that is a long stretch. : )