Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: improved variant detection and tests #64

Merged
merged 2 commits into from
Feb 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 1 addition & 25 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -67,28 +67,4 @@ jobs:
- name: Upload Release Asset
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: gh release upload ${{ github.event.release.tag_name }} ./build/distributions/*

# Create pull request
- name: Create Pull Request
if: ${{ steps.properties.outputs.changelog != '' }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
VERSION="${{ github.event.release.tag_name }}"
BRANCH="changelog-update-$VERSION"

git config user.email "[email protected]"
git config user.name "GitHub Action"

git checkout -b $BRANCH
git commit -am "Changelog update - $VERSION"
git push --set-upstream origin $BRANCH

sleep 5

gh pr create \
--title "Changelog update - \`$VERSION\`" \
--body "Current pull request contains patched \`CHANGELOG.md\` file for the \`$VERSION\` version." \
--base main \
--head $BRANCH
run: gh release upload ${{ github.event.release.tag_name }} ./build/distributions/*
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.github.walrussoup.tailwindformatternext.support

class CssHelper {

companion object {
var classNamesRegex: String = "[_a-zA-Z0-9\\s-:/~&\\[\\].>%]+";
val assembledRegex = "\\bclass(?:Name)*\\s*=\\s*(?<quotes>[\"'])(?<classList1>$classNamesRegex)[\"']|@apply (?<classList2>$classNamesRegex);"
@JvmStatic
fun getRegex(): String {
return assembledRegex;
}
@JvmStatic
fun getTailwindClassesRegex(): String {
return classNamesRegex;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,10 @@ import java.util.*
import java.util.regex.Pattern

class TailwindParser(private val sorter: TailwindSorter) {
private val classNamesRegex = "[_a-zA-Z0-9\\s-:/]+"
private val regex = "\\bclass(?:Name)*\\s*=\\s*(?<quotes>[\"'])(?<classList1>$classNamesRegex)[\"']|@apply (?<classList2>$classNamesRegex);"

fun processBody(body: String): String {
var body = body
val pattern = Pattern.compile(regex, Pattern.MULTILINE)
val pattern = Pattern.compile(CssHelper.getRegex(), Pattern.MULTILINE)
val matcher = pattern.matcher(body)
while (matcher.find()) {
val isApplyStatement: Boolean
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import java.util.*
import java.util.stream.Collectors

class TailwindSorter(classOrder: List<String>, isCustomConfiguration: Boolean) : Comparator<String> {
private val variantRegex = "^(.*)(:)([^:]*$)";
private val classOrder: List<String>
private val variantsStartAt: Int
private var lastPosition = 0
Expand Down Expand Up @@ -88,10 +89,21 @@ class TailwindSorter(classOrder: List<String>, isCustomConfiguration: Boolean) :
if (variantLocation == -1) {
return 0
}
// fish out the first variant to use as an anchor point
val variants = className.split(":".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
if (variants.isNotEmpty()) {
return (variantsStartAt + variantOrder.indexOf(variants[0]) * classOrder.size + calculateProperOrder(variants[1]))
// if the specific whole class is called out in the class list given, simply return that
if (classOrder.contains(className)) {
return classOrder.indexOf(className)
}
val variantParts = variantRegex.toRegex().find(className);
val variantApplied = variantParts?.groupValues?.get(1);
val classApplied = variantParts?.groupValues?.get(3);

if (variantApplied != null && classApplied != null) {
// if this variant is arbitrary, shove it to the back of the class list
if(variantApplied.contains("[")) {
return (variantsStartAt + variantOrder.size * classOrder.size + calculateProperOrder(classApplied));
}
// if its a variant with an existing order in the spec, keep that
return (variantsStartAt + variantOrder.indexOf(variantApplied) * classOrder.size + calculateProperOrder(classApplied))
}
return variantsStartAt;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,74 @@ class ParserTest : BasePlatformTestCase()
return "src/test/testData"
}

fun testCanSortPureCssFiles() {
fun testCanSortPureCssFilesWithCustomOrder() {
val utility = TailwindUtility();
utility.classOrder = listOf("first", "sec_ond", "THIRD", "last", "group-focus:la-st", "sm:first", "lg:hover:last");

val tailwindParser = TailwindParser(TailwindSorter(utility.classOrder, false))

try {
// read fixture file parser/input.css
val input = myFixture.configureByFile("/parser/input.css").text
val expected = myFixture.configureByFile("/parser/expected.css").text
// read fixture file parser/custom-order-input.css
val input = myFixture.configureByFile("/parser/custom-order-input.css").text
val expected = myFixture.configureByFile("/parser/custom-order-expected.css").text

assertEquals(expected, tailwindParser.processBody(input));
} catch (e: Exception) {
println(e.message)
throw e;
}
}

fun testCanSortCssFilesWithTailwindDefaultOrder()
{
val utility = TailwindUtility();
utility.classOrder = listOf("first", "sec_ond", "THIRD", "last", "group-focus:la-st", "sm:first", "lg:hover:last");

val tailwindParser = TailwindParser(TailwindSorter(utility.classOrder, false))

try {
// read fixture file parser/custom-order-input.css
val input = myFixture.configureByFile("/parser/tailwind-order-input.css").text
val expected = myFixture.configureByFile("/parser/tailwind-order-expected.css").text

assertEquals(expected, tailwindParser.processBody(input));
} catch (e: Exception) {
println(e.message)
throw e;
}
}

fun testCanSortArbitraryVariantsOnLeftSide() {
val utility = TailwindUtility();
utility.loadDefaultClassOrder();
val tailwindParser = TailwindParser(TailwindSorter(utility.classOrder, false))

try {
// read fixture file parser/custom-order-input.css
val input = myFixture.configureByFile("/parser/leading-arbitrary-variant-input.vue").text
val expected = myFixture.configureByFile("/parser/leading-arbitrary-variant-expected.vue").text

assertEquals(expected, tailwindParser.processBody(input));
} catch (e: Exception) {
println(e.message)
throw e;
}
}

fun testCanSortArbitraryVariantsOnRightSide() {
val utility = TailwindUtility();
utility.loadDefaultClassOrder();
val tailwindParser = TailwindParser(TailwindSorter(utility.classOrder, false))

try {
// read fixture file parser/custom-order-input.css
val input = myFixture.configureByFile("/parser/trailing-arbitrary-variant-input.vue").text
val expected = myFixture.configureByFile("/parser/trailing-arbitrary-variant-expected.vue").text

assertEquals(expected, tailwindParser.processBody(input));
} catch (e: Exception) {
println(e.message)
throw e;
}
}

Expand All @@ -45,13 +99,14 @@ class ParserTest : BasePlatformTestCase()
val tailwindParser = TailwindParser(TailwindSorter(utility.classOrder, true))

try {
// read fixture file parser/input.css
// read fixture file parser/custom-order-input.css
val input = myFixture.configureByFile("/parser/input.html").text
val expected = myFixture.configureByFile("/parser/expected.html").text

assertEquals(expected, tailwindParser.processBody(input));
} catch (e: Exception) {
println(e.message)
throw e;
}
}

Expand All @@ -62,13 +117,14 @@ class ParserTest : BasePlatformTestCase()
val tailwindParser = TailwindParser(TailwindSorter(utility.classOrder, false))

try {
// read fixture file parser/input.css
// read fixture file parser/custom-order-input.css
val input = myFixture.configureByFile("/parser/input.vue").text
val expected = myFixture.configureByFile("/parser/expected.vue").text

assertEquals(expected, tailwindParser.processBody(input));
} catch (e: Exception) {
println(e.message)
throw e;
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
package com.github.walrussoup.tailwindformatternext

import com.github.walrussoup.tailwindformatternext.support.CssHelper
import java.util.*
import com.intellij.testFramework.TestDataPath
import com.intellij.testFramework.fixtures.BasePlatformTestCase
import com.github.walrussoup.tailwindformatternext.support.TailwindParser
import com.github.walrussoup.tailwindformatternext.support.TailwindSorter
import com.github.walrussoup.tailwindformatternext.support.TailwindUtility
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiRecursiveElementWalkingVisitor
import com.intellij.psi.search.PsiElementProcessor
import com.intellij.psi.tree.IElementType
import com.intellij.psi.tree.TokenSet
import junit.framework.TestCase
import java.util.regex.Pattern


@TestDataPath("\$CONTENT_ROOT/src/test/testData")
class RegexTest : BasePlatformTestCase()
{
override fun getTestDataPath(): String {
return "src/test/testData"
}

fun testClassRegexCanSeeTailwindClasses() {
var tailwindClasses : String = "relative mt-2 overflow-hidden rounded bg-white text-sm shadow dark:bg-zinc-900 md:flex";
var regex : String = CssHelper.getTailwindClassesRegex();

val pattern = Pattern.compile(regex, Pattern.MULTILINE);
val matcher = pattern.matcher(tailwindClasses);

// it should match the entire block as valid tailwindcss classes
assertEquals(1, matcher.results().count());
}

fun testClassRegexCanSeeTailwindClassesWithPseudoClasses() {
var tailwindClasses : String = "relative mt-2 overflow-hidden rounded bg-white text-sm shadow dark:bg-zinc-900 md:flex group-focus:rounded";
var regex : String = CssHelper.getTailwindClassesRegex();

val pattern = Pattern.compile(regex, Pattern.MULTILINE);
val matcher = pattern.matcher(tailwindClasses);

// it should match the entire block as valid tailwindcss classes
assertEquals(1, matcher.results().count());
}

fun testClassRegexCanSeeTailwindClassesWithMediaQueries() {
var tailwindClasses : String = "relative mt-2 overflow-hidden rounded bg-white text-sm shadow dark:bg-zinc-900 md:flex sm:group-focus:rounded";
var regex : String = CssHelper.getTailwindClassesRegex();

val pattern = Pattern.compile(regex, Pattern.MULTILINE);
val matcher = pattern.matcher(tailwindClasses);

// it should match the entire block as valid tailwindcss classes
assertEquals(1, matcher.results().count());
}

fun testClassRegexCanSeeTailwindClassesWithMediaQueriesAndPseudoClasses() {
var tailwindClasses : String = "relative mt-2 overflow-hidden rounded bg-white text-sm shadow dark:bg-zinc-900 md:flex sm:group-focus:rounded md:hover:rounded";
var regex : String = CssHelper.getTailwindClassesRegex();

val pattern = Pattern.compile(regex, Pattern.MULTILINE);
val matcher = pattern.matcher(tailwindClasses);

// it should match the entire block as valid tailwindcss classes
assertEquals(1, matcher.results().count());
}

fun testClassRegexCanSeeTailwindClassesWithMediaQueriesAndPseudoClassesAndVariants() {
var tailwindClasses : String = "relative mt-2 overflow-hidden rounded bg-white text-sm shadow dark:bg-zinc-900 md:flex sm:group-focus:rounded md:hover:rounded dark:hover:rounded";
var regex : String = CssHelper.getTailwindClassesRegex();

val pattern = Pattern.compile(regex, Pattern.MULTILINE);
val matcher = pattern.matcher(tailwindClasses);

// it should match the entire block as valid tailwindcss classes
assertEquals(1, matcher.results().count());
}

fun testClassRegexCanSeeTailwindClassesWithMediaQueriesAndPseudoClassesAndVariantsAndGrouping() {
var tailwindClasses : String = "relative mt-2 overflow-hidden rounded bg-white text-sm shadow dark:bg-zinc-900 md:flex sm:group-focus:rounded md:hover:rounded dark:hover:rounded group-hover:rounded";
var regex : String = CssHelper.getTailwindClassesRegex();

val pattern = Pattern.compile(regex, Pattern.MULTILINE);
val matcher = pattern.matcher(tailwindClasses);

// it should match the entire block as valid tailwindcss classes
assertEquals(1, matcher.results().count());
}

fun testClassRegexCanSeeTailwindClassesWithMediaQueriesAndPseudoClassesAndTrailingArbitraryVariants() {
var tailwindClasses : String = "relative mt-2 overflow-hidden rounded bg-white text-sm shadow dark:bg-zinc-900 md:flex sm:group-focus:rounded md:hover:rounded dark:hover:rounded group-hover:rounded group-focus:rounded max-w-[75%]";
var regex : String = CssHelper.getTailwindClassesRegex();

val pattern = Pattern.compile(regex, Pattern.MULTILINE);
val matcher = pattern.matcher(tailwindClasses);

// it should match the entire block as valid tailwindcss classes
assertEquals(1, matcher.results().count());
}

fun testClassRegexCanSeeTailwindClassesWithMediaQueriesAndPseudoClassesAndLeadingArbitraryVariants() {
var tailwindClasses : String = "relative mt-2 overflow-hidden rounded bg-white text-sm shadow dark:bg-zinc-900 md:flex sm:group-focus:rounded md:hover:rounded dark:hover:rounded group-hover:rounded group-focus:rounded [.peer:checked~&>.material-icons]:opacity-100";
var regex : String = CssHelper.getTailwindClassesRegex();

val pattern = Pattern.compile(regex, Pattern.MULTILINE);
val matcher = pattern.matcher(tailwindClasses);

// it should match the entire block as valid tailwindcss classes
assertEquals(1, matcher.results().count());
}
}
Loading