diff --git a/package.json b/package.json index 6552a6a..b270ef6 100755 --- a/package.json +++ b/package.json @@ -5018,10 +5018,10 @@ "default": { "html": "\\bclass\\s*=\\s*[\\\"\\']([_a-zA-Z0-9\\s\\-\\:\\/]+)[\\\"\\']", "css": "\\B@apply\\s+([_a-zA-Z0-9\\s\\-\\:\\/]+);", - "javascript": "(?:\\bclassName\\s*=\\s*[\\\"\\']([_a-zA-Z0-9\\s\\-\\:\\/]+)[\\\"\\'])|(?:\\btw\\s*`([_a-zA-Z0-9\\s\\-\\:\\/]*)`)", - "javascriptreact": "(?:\\bclassName\\s*=\\s*[\\\"\\']([_a-zA-Z0-9\\s\\-\\:\\/]+)[\\\"\\'])|(?:\\btw\\s*`([_a-zA-Z0-9\\s\\-\\:\\/]*)`)", - "typescript": "(?:\\bclassName\\s*=\\s*[\\\"\\']([_a-zA-Z0-9\\s\\-\\:\\/]+)[\\\"\\'])|(?:\\btw\\s*`([_a-zA-Z0-9\\s\\-\\:\\/]*)`)", - "typescriptreact": "(?:\\bclassName\\s*=\\s*[\\\"\\']([_a-zA-Z0-9\\s\\-\\:\\/]+)[\\\"\\'])|(?:\\btw\\s*`([_a-zA-Z0-9\\s\\-\\:\\/]*)`)" + "javascript": "(?:\\bclass(?:Name)?\\s*=[\\w\\d\\s_,{}\\(\\)\\[\\]]*[\"'`]([\\w\\d\\s_\\-\\:\\/${}]+)[\"'`][\\w\\d\\s_,{}\\(\\)\\[\\]]*)|(?:\\btw\\s*`([\\w\\d\\s_\\-\\:\\/]*)`)", + "javascriptreact": "(?:\\bclass(?:Name)?\\s*=[\\w\\d\\s_,{}\\(\\)\\[\\]]*[\"'`]([\\w\\d\\s_\\-\\:\\/${}]+)[\"'`][\\w\\d\\s_,{}\\(\\)\\[\\]]*)|(?:\\btw\\s*`([\\w\\d\\s_\\-\\:\\/]*)`)", + "typescript": "(?:\\bclass(?:Name)?\\s*=[\\w\\d\\s_,{}\\(\\)\\[\\]]*[\"'`]([\\w\\d\\s_\\-\\:\\/${}]+)[\"'`][\\w\\d\\s_,{}\\(\\)\\[\\]]*)|(?:\\btw\\s*`([\\w\\d\\s_\\-\\:\\/]*)`)", + "typescriptreact": "(?:\\bclass(?:Name)?\\s*=[\\w\\d\\s_,{}\\(\\)\\[\\]]*[\"'`]([\\w\\d\\s_\\-\\:\\/${}]+)[\"'`][\\w\\d\\s_,{}\\(\\)\\[\\]]*)|(?:\\btw\\s*`([\\w\\d\\s_\\-\\:\\/]*)`)" }, "description": "An object with language IDs as keys and their values determining the regex to search for Tailwind CSS classes.", "scope": "window" diff --git a/src/extension.ts b/src/extension.ts index 3510bd7..158909e 100755 --- a/src/extension.ts +++ b/src/extension.ts @@ -1,7 +1,7 @@ 'use strict'; import { commands, workspace, ExtensionContext, Range, window } from 'vscode'; -import { sortClassString } from './utils'; +import { sortClassString, getClassMatch } from './utils'; import { spawn } from 'child_process'; import { rustyWindPath } from 'rustywind'; @@ -39,39 +39,35 @@ export function activate(context: ExtensionContext) { const editorText = editor.document.getText(); const editorLangId = editor.document.languageId; - const classWrapperRegex = new RegExp(configRegex[editorLangId] || configRegex['html'], 'gi'); - let classWrapper: RegExpExecArray | null; - while ( - (classWrapper = classWrapperRegex.exec(editorText)) !== null - ) { - const wrapperMatch = classWrapper[0]; - const valueMatchIndex = classWrapper.findIndex((match, idx) => idx !== 0 && match); - const valueMatch = classWrapper[valueMatchIndex]; - - const startPosition = - classWrapper.index + wrapperMatch.lastIndexOf(valueMatch); - const endPosition = startPosition + valueMatch.length; - - const range = new Range( - editor.document.positionAt(startPosition), - editor.document.positionAt(endPosition) - ); - - const options = { - shouldRemoveDuplicates, - shouldPrependCustomClasses, - customTailwindPrefix - }; - - edit.replace( - range, - sortClassString( - valueMatch, - Array.isArray(sortOrder) ? sortOrder : [], - options - ) - ); - } + getClassMatch( + configRegex[editorLangId] || configRegex['html'], + editorText, + (classWrapper, wrapperMatch, valueMatch) => { + const startPosition = + classWrapper.index + wrapperMatch.lastIndexOf(valueMatch); + const endPosition = startPosition + valueMatch.length; + + const range = new Range( + editor.document.positionAt(startPosition), + editor.document.positionAt(endPosition) + ); + + const options = { + shouldRemoveDuplicates, + shouldPrependCustomClasses, + customTailwindPrefix, + }; + + edit.replace( + range, + sortClassString( + valueMatch, + Array.isArray(sortOrder) ? sortOrder : [], + options + ) + ); + } + ); } ); diff --git a/src/utils.ts b/src/utils.ts index 1bfcc92..acbff74 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -50,3 +50,25 @@ const sortClassArray = ( const removeDuplicates = (classArray: string[]): string[] => [ ...new Set(classArray) ]; + +export function getClassMatch( + regex: string, + editorText: string, + callback: ( + classWrapper: RegExpExecArray, + wrapperMatch: string, + valueMatch: string + ) => void +) { + const classWrapperRegex = new RegExp(regex, 'gi'); + let classWrapper: RegExpExecArray | null; + while ((classWrapper = classWrapperRegex.exec(editorText)) !== null) { + const wrapperMatch = classWrapper[0]; + const valueMatchIndex = classWrapper.findIndex( + (match, idx) => idx !== 0 && match + ); + const valueMatch = classWrapper[valueMatchIndex]; + + callback(classWrapper, wrapperMatch, valueMatch); + } +} diff --git a/tests/utils.spec.ts b/tests/utils.spec.ts index 965f1c6..4db3806 100644 --- a/tests/utils.spec.ts +++ b/tests/utils.spec.ts @@ -1,4 +1,4 @@ -import { sortClassString } from '../src/utils'; +import { sortClassString, getClassMatch } from '../src/utils'; import 'jest'; import * as _ from 'lodash'; @@ -76,3 +76,172 @@ describe('removeDuplicates', () => { ); }); }); + +describe('extract className (jsx) string', () => { + const configRegex: { [key: string]: string } = + pjson.contributes.configuration[0].properties['headwind.classRegex'] + .default; + + const jsxLanguages = [ + 'javascript', + 'javascriptreact', + 'typescript', + 'typescriptreact', + ]; + + const classString = 'w-64 h-full bg-blue-400 relative'; + + const generateEditorText = (classNameString: string) => ` + export const Layout = ({ children }) => ( +