diff --git a/src/ConfigFileFixer.php b/src/ConfigFileFixer.php index 8c92a2b..ab23d6f 100644 --- a/src/ConfigFileFixer.php +++ b/src/ConfigFileFixer.php @@ -67,14 +67,16 @@ protected function fixForVersion1_0() //1: get options{} values and add em to root of 'module.exports' and add last value as theme: {.. preg_match('/options:\s*\{([^\}]+)\},?/', $this->searchAndReplace->get(), $match); $options = $match[1] ?? ''; - $updatedToThemeKey = "module.exports = {\n".$options."\n\ntheme: {\n"; + $updatedToThemeKey = "module.exports = {\n" . $options . "\n\ntheme: {\n"; - $this->searchAndReplace->perform('options:\s*\{([^\}]+)\},?', '', SearchAndReplace::NO_ESCAPE); - $this->searchAndReplace->perform('module.exports\s*=\s*\{', $updatedToThemeKey, SearchAndReplace::NO_ESCAPE); + $this->searchAndReplace + ->shouldEscape(false) + ->perform('options:\s*\{([^\}]+)\},?', '') + ->perform('module.exports\s*=\s*\{', $updatedToThemeKey) - //2: add closing } before modules: { - //3: change modules: { to variants: { - $this->searchAndReplace->perform('modules\:\s*\{', "},\n\nvariants: {", SearchAndReplace::NO_ESCAPE); + //2: add closing } before modules: { + //3: change modules: { to variants: { + ->perform('modules\:\s*\{', "},\n\nvariants: {"); //4: updates keys inside theme: { to new names. //5: updates keys inside variants: { to new names. @@ -95,17 +97,17 @@ protected function fixForVersion1_0() 'lists\:{regex_line}' => "listStylePosition:{regex_line}\nlistStyleType:{regex_line}", 'position\:{regex_line}' => "position:{regex_line}\ninset:{regex_line}", 'whitespace\:{regex_line}' => "whitespace:{regex_line}\nwordBreak:{regex_line}", - 'textStyle\:{regex_line}' => "fontStyle:{regex_line}\nfontSmoothing:{regex_line}". + 'textStyle\:{regex_line}' => "fontStyle:{regex_line}\nfontSmoothing:{regex_line}" . "\ntextDecoration:{regex_line}\ntextTransform:{regex_line}", - 'flexbox\:{regex_line}' => "flexDirection:{regex_line}\nflexWrap:{regex_line}". - "\nalignItems:{regex_line}\nalignSelf:{regex_line}". - "\njustifyContent:{regex_line}\nalignContent:{regex_line}". - "\nflex:{regex_line}\nflexGrow:{regex_line}". + 'flexbox\:{regex_line}' => "flexDirection:{regex_line}\nflexWrap:{regex_line}" . + "\nalignItems:{regex_line}\nalignSelf:{regex_line}" . + "\njustifyContent:{regex_line}\nalignContent:{regex_line}" . + "\nflex:{regex_line}\nflexGrow:{regex_line}" . "\nflexShrink:{regex_line}", ]; foreach ($newNames as $old => $new) { - $this->searchAndReplace->perform($old, $new, SearchAndReplace::NO_ESCAPE); + $this->searchAndReplace->shouldEscape(false)->perform($old, $new); } //6: add corePlugins: { to root. @@ -113,51 +115,55 @@ protected function fixForVersion1_0() preg_match('/require\(\'tailwindcss\/plugins\/container\'\)\(\{([^\}]+)\}\)/', $this->searchAndReplace->get(), $match); $containerOptions = $match[1] ?? ''; - $this->searchAndReplace->perform('require\(\'tailwindcss\/plugins\/container\'\)\(\{([^\}]+)\}\),?', '', SearchAndReplace::NO_ESCAPE); - $corePlugins = 'corePlugins: {'.(empty($containerOptions) ? "\ncontainer: false," : '')."\n}, \nplugins: ["; + $this->searchAndReplace->shouldEscape(false)->perform('require\(\'tailwindcss\/plugins\/container\'\)\(\{([^\}]+)\}\),?', ''); + $corePlugins = 'corePlugins: {' . (empty($containerOptions) ? "\ncontainer: false," : '') . "\n}, \nplugins: ["; - $this->searchAndReplace->perform('plugins:\s*\[', $corePlugins, SearchAndReplace::NO_ESCAPE); - $this->searchAndReplace->perform('theme:\s*\{', "theme: \n{\ncontainer: {\n".$containerOptions."\n},\n", SearchAndReplace::NO_ESCAPE); + $this->searchAndReplace + ->shouldEscape(false) + ->perform('plugins:\s*\[', $corePlugins) + ->perform('theme:\s*\{', "theme: \n{\ncontainer: {\n" . $containerOptions . "\n},\n"); //8: fix colors - $colors = "\n transparent: 'transparent',\n\n black: '#000',\n white: '#fff',". - "\n gray: {\n100: '#f7fafc',\n200: '#edf2f7',\n300: '#e2e8f0',". - "\n400: '#cbd5e0',\n500: '#a0aec0',\n600: '#718096',\n700: '#4a5568',". - "\n800: '#2d3748',\n900: '#1a202c',\n},\n". - "\n red: {\n100: '#fff5f5',\n200: '#fed7d7',\n300: '#feb2b2',\n400: '#fc8181',". - "\n500: '#f56565',\n600: '#e53e3e',\n700: '#c53030',\n800: '#9b2c2c',". - "\n900: '#742a2a',\n},\n". - "\n orange: {\n100: '#fffaf0',\n200: '#feebc8',\n300: '#fbd38d',". - "\n400: '#f6ad55',\n500: '#ed8936',\n600: '#dd6b20',\n700: '#c05621',". - "\n800: '#9c4221',\n900: '#7b341e',\n},\n". - "\n yellow: {\n100: '#fffff0',\n200: '#fefcbf',\n300: '#faf089',". - "\n400: '#f6e05e',\n500: '#ecc94b',\n600: '#d69e2e',\n700: '#b7791f',". - "\n800: '#975a16',\n900: '#744210',\n},\n". - "\n green: {\n100: '#f0fff4',\n200: '#c6f6d5',\n300: '#9ae6b4',". - "\n400: '#68d391',\n500: '#48bb78',\n600: '#38a169',\n700: '#2f855a',". - "\n800: '#276749',\n900: '#22543d',\n},". - "\n teal: {\n100: '#e6fffa',\n200: '#b2f5ea',\n300: '#81e6d9',". - "\n400: '#4fd1c5',\n500: '#38b2ac',\n600: '#319795',\n700: '#2c7a7b',". - "\n800: '#285e61',\n900: '#234e52',\n},\n". - "\n blue: {\n100: '#ebf8ff',\n200: '#bee3f8',\n300: '#90cdf4',". - "\n400: '#63b3ed',\n500: '#4299e1',\n600: '#3182ce',\n700: '#2b6cb0', ". - "\n800: '#2c5282',\n900: '#2a4365',\n},". - "\n indigo: {\n100: '#ebf4ff',\n200: '#c3dafe',\n300: '#a3bffa',". - "\n400: '#7f9cf5',\n500: '#667eea',\n600: '#5a67d8',\n700: '#4c51bf',". - "\n800: '#434190',\n900: '#3c366b',\n},\n". - "\n purple: {\n100: '#faf5ff',\n200: '#e9d8fd',\n300: '#d6bcfa',". - "\n400: '#b794f4',\n500: '#9f7aea',\n600: '#805ad5',\n700: '#6b46c1',". - "\n800: '#553c9a',\n900: '#44337a',\n},\n". - "\n pink: {\n100: '#fff5f7',\n200: '#fed7e2',\n300: '#fbb6ce',". - "\n400: '#f687b3',\n500: '#ed64a6',\n600: '#d53f8c',\n700: '#b83280',". + $colors = "\n transparent: 'transparent',\n\n black: '#000',\n white: '#fff'," . + "\n gray: {\n100: '#f7fafc',\n200: '#edf2f7',\n300: '#e2e8f0'," . + "\n400: '#cbd5e0',\n500: '#a0aec0',\n600: '#718096',\n700: '#4a5568'," . + "\n800: '#2d3748',\n900: '#1a202c',\n},\n" . + "\n red: {\n100: '#fff5f5',\n200: '#fed7d7',\n300: '#feb2b2',\n400: '#fc8181'," . + "\n500: '#f56565',\n600: '#e53e3e',\n700: '#c53030',\n800: '#9b2c2c'," . + "\n900: '#742a2a',\n},\n" . + "\n orange: {\n100: '#fffaf0',\n200: '#feebc8',\n300: '#fbd38d'," . + "\n400: '#f6ad55',\n500: '#ed8936',\n600: '#dd6b20',\n700: '#c05621'," . + "\n800: '#9c4221',\n900: '#7b341e',\n},\n" . + "\n yellow: {\n100: '#fffff0',\n200: '#fefcbf',\n300: '#faf089'," . + "\n400: '#f6e05e',\n500: '#ecc94b',\n600: '#d69e2e',\n700: '#b7791f'," . + "\n800: '#975a16',\n900: '#744210',\n},\n" . + "\n green: {\n100: '#f0fff4',\n200: '#c6f6d5',\n300: '#9ae6b4'," . + "\n400: '#68d391',\n500: '#48bb78',\n600: '#38a169',\n700: '#2f855a'," . + "\n800: '#276749',\n900: '#22543d',\n}," . + "\n teal: {\n100: '#e6fffa',\n200: '#b2f5ea',\n300: '#81e6d9'," . + "\n400: '#4fd1c5',\n500: '#38b2ac',\n600: '#319795',\n700: '#2c7a7b'," . + "\n800: '#285e61',\n900: '#234e52',\n},\n" . + "\n blue: {\n100: '#ebf8ff',\n200: '#bee3f8',\n300: '#90cdf4'," . + "\n400: '#63b3ed',\n500: '#4299e1',\n600: '#3182ce',\n700: '#2b6cb0', " . + "\n800: '#2c5282',\n900: '#2a4365',\n}," . + "\n indigo: {\n100: '#ebf4ff',\n200: '#c3dafe',\n300: '#a3bffa'," . + "\n400: '#7f9cf5',\n500: '#667eea',\n600: '#5a67d8',\n700: '#4c51bf'," . + "\n800: '#434190',\n900: '#3c366b',\n},\n" . + "\n purple: {\n100: '#faf5ff',\n200: '#e9d8fd',\n300: '#d6bcfa'," . + "\n400: '#b794f4',\n500: '#9f7aea',\n600: '#805ad5',\n700: '#6b46c1'," . + "\n800: '#553c9a',\n900: '#44337a',\n},\n" . + "\n pink: {\n100: '#fff5f7',\n200: '#fed7e2',\n300: '#fbb6ce'," . + "\n400: '#f687b3',\n500: '#ed64a6',\n600: '#d53f8c',\n700: '#b83280'," . "\n800: '#97266d',\n900: '#702459',\n},\n"; - $this->searchAndReplace->perform('let colors\s*=\s*\{([^\}]+)\}', '', SearchAndReplace::NO_ESCAPE); - $this->searchAndReplace->perform('\s+colors:\s*colors', ' colors: {'.$colors.'}', SearchAndReplace::NO_ESCAPE); - $this->searchAndReplace->perform('backgroundColor:\s*colors', 'backgroundColor: theme => theme(\'colors\')', SearchAndReplace::NO_ESCAPE); - $this->searchAndReplace->perform('textColor:\s*colors', 'textColor: theme => theme(\'colors\')', SearchAndReplace::NO_ESCAPE); - $this->searchAndReplace->perform('borderColor:\s*g([^\n]+)', "borderColor: theme => {\nreturn global.Object.assign({ default: theme('colors.gray.300', 'currentColor') }, theme('colors'))\n},", SearchAndReplace::NO_ESCAPE); - $this->searchAndReplace->perform('require\(\'tailwindcss\/defaultConfig\'\)\(\)', "require('tailwindcss/defaultConfig')", SearchAndReplace::NO_ESCAPE); + $this->searchAndReplace + ->shouldEscape(false) + ->perform('let colors\s*=\s*\{([^\}]+)\}', '') + ->perform('\s+colors:\s*colors', ' colors: {' . $colors . '}') + ->perform('backgroundColor:\s*colors', 'backgroundColor: theme => theme(\'colors\')') + ->perform('textColor:\s*colors', 'textColor: theme => theme(\'colors\')') + ->perform('borderColor:\s*g([^\n]+)', "borderColor: theme => {\nreturn global.Object.assign({ default: theme('colors.gray.300', 'currentColor') }, theme('colors'))\n},") + ->perform('require\(\'tailwindcss\/defaultConfig\'\)\(\)', "require('tailwindcss/defaultConfig')"); //TODO: use javascript beautifier package ... } diff --git a/src/SearchAndReplace.php b/src/SearchAndReplace.php index 24068ad..6770aaa 100644 --- a/src/SearchAndReplace.php +++ b/src/SearchAndReplace.php @@ -10,9 +10,11 @@ class SearchAndReplace protected $givenContent = ''; - const INSIDE_CLASSE_PROP = 1; - const NO_ESCAPE = 2; - const AFTER_APPLY_DIRECTIVE = 4; + protected $escape = true; + + protected $inlineCSS = false; + + protected $afterApply = false; /** * initiate the converter class. @@ -28,6 +30,31 @@ public function __construct($content = null) return $this; } + public function shouldEscape($toggle): self + { + $this->escape = $toggle; + + return $this; + } + + public function isInlineCSS($toggle) + { + $this->inlineCSS = $toggle; + if ($toggle) { + $this->afterApply = false; + } + return $this; + } + + public function isAfterApply($toggle) + { + $this->afterApply = $toggle; + if ($toggle) { + $this->inlineCSS = false; + } + return $this; + } + /** * Get the converted content. * @@ -87,30 +114,47 @@ protected function isInLastSearches(string $searchFor, $limitLast = 0) return false; } + protected function addToLastSearches($search) + { + $this->changes++; + + $search = stripslashes($search); + + if ($this->isInLastSearches($search)) { + return; + } + + $this->lastSearches[] = $search; + + if (count($this->lastSearches) >= 50) { + array_shift($this->lastSearches); + } + } + /** * Search the given content and replace. * * @param string $search * @param string $replace - * - * @return null */ - public function perform($search, $replace, $options = null) + public function perform($search, $replace) { $currentContent = $this->givenContent; - if ($options & self::INSIDE_CLASSE_PROP) { + if ($replace instanceof \Closure) { + $callableReplace = \Closure::bind($replace, $this, self::class); + $replace = $callableReplace(); + } + + $regexStart = $this->afterApply ? '(?@apply\s*.*?)' : '(?\s*)'; + $regexEnd = $this->afterApply ? '(?.*?[;\n])' : '(?\s*)'; + + if($this->inlineCSS) { $regexStart = '(?class\s*=\s*(?["\'])((?!\k).)*)'; $regexEnd = '(?((?!\k).)*\k)'; - } elseif ($options & self::AFTER_APPLY_DIRECTIVE) { - $regexStart = '(?@apply\s*.*?)'; - $regexEnd = '(?.*?[;\n])'; - } else { - $regexStart = '(?\s*)'; - $regexEnd = '(?\s*)'; } - if ($options ^ self::NO_ESCAPE) { + if ($this->escape) { $search = preg_quote($search); } @@ -156,5 +200,7 @@ function ($match) use ($replace) { $this->lastSearches = array_slice($this->lastSearches, -10, 10, true); } } + + return $this; } } diff --git a/src/Updater.php b/src/Updater.php index 64bdeaa..c2988c2 100644 --- a/src/Updater.php +++ b/src/Updater.php @@ -74,7 +74,7 @@ public function get() } /** - * Get the number of comitted changes. + * Get the number of committed changes. * * @return int */ @@ -102,7 +102,10 @@ protected function convertToVersion1_0() ]; foreach ($cssChanges as $old => $new) { - $this->searchAndReplace->perform($old, $new, SearchAndReplace::NO_ESCAPE); + $this->searchAndReplace + ->isInlineCSS(!$isCSSfile) + ->shouldEscape(false) + ->perform($old, $new); } } @@ -125,6 +128,7 @@ protected function convertToVersion1_0() //colors '{regex_string}-grey' => '{regex_string}-gray-500', + '{regex_string}-grey-{regex_string}' => '{regex_string}-gray-{regex_string}', '{regex_string}-red' => '{regex_string}-red-500', '{regex_string}-orange' => '{regex_string}-orange-500', '{regex_string}-yellow' => '{regex_string}-yellow-500', @@ -148,22 +152,29 @@ protected function convertToVersion1_0() ]; foreach ($classes as $beforeClass => $afterClass) { - $this->searchAndReplace->perform( + $this->searchAndReplace + ->isAfterApply($isCSSfile) + ->perform( ($isCSSfile ? '.' : '').$beforeClass, - ($isCSSfile ? '.' : '').$afterClass, - $isCSSfile ? SearchAndReplace::AFTER_APPLY_DIRECTIVE : SearchAndReplace::INSIDE_CLASSE_PROP + ($isCSSfile ? '.' : '').$afterClass ); } //empty variant - $this->searchAndReplace->perform(($isCSSfile ? '\.' : '(?>[a-z]+:)?').'no-underline', '', SearchAndReplace::NO_ESCAPE); - + $this->searchAndReplace + ->shouldEscape(false) + ->isInlineCSS(false) + ->isAfterApply(false) + ->perform(($isCSSfile ? '\.' : '(?>[a-z-]+:)?').'no-underline', ''); + if ($isCSSfile) { return; } foreach ($htmlTags as $beforeTag => $afterTag) { - $this->searchAndReplace->perform($beforeTag, $afterTag); + $this->searchAndReplace + ->isInlineCSS(!$isCSSfile) + ->perform($beforeTag, $afterTag); } } } diff --git a/tailwind-shift b/tailwind-shift index 412cbf4..682dff7 100755 --- a/tailwind-shift +++ b/tailwind-shift @@ -14,7 +14,7 @@ if (file_exists(__DIR__ . '/vendor/autoload.php')) { require __DIR__ . '/../../autoload.php'; } -(new Application('tailwind-shift', '1.0.8')) +(new Application('tailwind-shift', '1.0.9')) ->register('tailwind-shift') @@ -23,7 +23,7 @@ if (file_exists(__DIR__ . '/vendor/autoload.php')) { ->addOption('replace', null, InputOption::VALUE_REQUIRED, 'This will overwrite the original file.', false) ->addOption('recursive', 'r', InputOption::VALUE_OPTIONAL, 'This will recurse through all directories under the main directory', false) - ->addOption('fixconfig', 'x', InputOption::VALUE_OPTIONAL, 'This must be added if givem file is tailwind config file, to fix and update to latest version.', false) + ->addOption('fixconfig', 'x', InputOption::VALUE_OPTIONAL, 'This must be added if given file is tailwind config file, to fix and update to latest version.', false) ->addOption('extensions', 'e', InputOption::VALUE_REQUIRED, 'This allows for custom extensions', 'php,html,css') diff --git a/tests/ConfigFileFixerTest.php b/tests/ConfigFileFixerTest.php new file mode 100644 index 0000000..9eb8e24 --- /dev/null +++ b/tests/ConfigFileFixerTest.php @@ -0,0 +1,30 @@ +configFixer = new ConfigFileFixer(); + } + + /** @test */ + public function it_return_output() + { + $this->assertStringContainsString( + 'theme:', + $this->configFixer->setContent("let colors = {}; + module.exports = { + colors: colors, + }")->fix()->get() + ); + } +} diff --git a/tests/SearchAndReplaceTest.php b/tests/SearchAndReplaceTest.php index bda2562..d308278 100644 --- a/tests/SearchAndReplaceTest.php +++ b/tests/SearchAndReplaceTest.php @@ -20,10 +20,10 @@ public function it_respects_repeated_regex_search_param() { $this->searchAndReplace ->setContent('') + ->isInlineCSS(true) ->perform( '{regex_string}-{regex_string}-sad', - '{regex_string}-{regex_string}-fun', - SearchAndReplace::INSIDE_CLASSE_PROP + '{regex_string}-{regex_string}-fun' ); $this->assertEquals( @@ -37,10 +37,10 @@ public function it_respects_repeated_regex_replace_param() { $this->searchAndReplace ->setContent('') + ->isInlineCSS(true) ->perform( 'life-is-{regex_string}', - '{regex_string}-is-{regex_string}', - SearchAndReplace::INSIDE_CLASSE_PROP + '{regex_string}-is-{regex_string}' ); $this->assertEquals( diff --git a/tests/UpdaterTest.php b/tests/UpdaterTest.php index b875743..1fb20ac 100644 --- a/tests/UpdaterTest.php +++ b/tests/UpdaterTest.php @@ -33,6 +33,11 @@ public function it_convert_variants() $this->updater->setContent('')->convert()->get() ); + $this->assertEquals( + '', + $this->updater->setContent('')->convert()->get() + ); + $this->assertEquals( '', $this->updater->setContent('')->convert()->get()