windclutter 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/README.md +62 -0
- data/bin/windclutter +8 -0
- data/lib/windclutter/analyser.rb +7 -0
- data/lib/windclutter/cli/commands/generate.rb +30 -0
- data/lib/windclutter/cli/commands/project.rb +59 -0
- data/lib/windclutter/cli/core.rb +60 -0
- data/lib/windclutter/processor.rb +46 -0
- data/lib/windclutter/util/config.rb +38 -0
- data/lib/windclutter/util/file_handler.rb +54 -0
- data/lib/windclutter/util/generator.rb +14 -0
- data/lib/windclutter.rb +4 -0
- data/test/test_windclutter.rb +5 -0
- data/test/windclutter/test_processor.rb +47 -0
- data/test/windclutter/util/test_generator.rb +11 -0
- metadata +57 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 7228d312e25ff4308cb7e6f753a71d25452c9c1cfde852bbab75f35853f3ff98
|
4
|
+
data.tar.gz: 580a419ed1d91abc97831fc0836e7547c5b1544c6563f5ee4a454181778d6bc6
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5a54ffa345fbfb0b234126b9e1f304ebdea473e84087ed387c2c555b87549abcdebcc510b83040bccb45f9de28c1f65325bb2984345cbd9b4d1cfe50fa583a3a
|
7
|
+
data.tar.gz: 2b6ea373ca2273fed179ded3e24ee3553b3fd0cb465d7dff8d3b0968b9b5ab73551180c613c70b04b717f3f03c332486115286f6dc072e022a100ff05a9082d9
|
data/README.md
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+

|
2
|
+
|
3
|
+
## WindClutter
|
4
|
+
|
5
|
+
You created awesome project, it's completed, your users are happy. But now you are left with this question:
|
6
|
+
|
7
|
+
> What am I going to do with this TailwindCSS class clutter?
|
8
|
+
|
9
|
+
You know what I'm talking about.
|
10
|
+
|
11
|
+
This tool aim to:
|
12
|
+
|
13
|
+
- Provide analysis of your project
|
14
|
+
- Identify common uses of Tailwind class
|
15
|
+
- Cleanup for large ejected project
|
16
|
+
|
17
|
+
Once your project grows and ready to for your clients, chances are you are left with
|
18
|
+
humongous task of Tailwind CSS cleanup. I call this "ejected" states.
|
19
|
+
|
20
|
+
## In Action
|
21
|
+
|
22
|
+
```html
|
23
|
+
<div class="my-class border rounded-md px-4 py-2 bg-primary-100">
|
24
|
+
<!-- -->
|
25
|
+
</div>
|
26
|
+
```
|
27
|
+
|
28
|
+
What if we can help you, if not a bit?
|
29
|
+
|
30
|
+
```html
|
31
|
+
<div class="my-class adkuioqa">
|
32
|
+
<!-- -->
|
33
|
+
</div>
|
34
|
+
```
|
35
|
+
|
36
|
+
We'll cleanup your html files and organize the CSSes. You can then choose what to name them.
|
37
|
+
|
38
|
+
`adkuioqa = .btn`
|
39
|
+
```
|
40
|
+
<div class="my-class btn">
|
41
|
+
<!-- -->
|
42
|
+
</div>
|
43
|
+
```
|
44
|
+
|
45
|
+
## Concept
|
46
|
+
|
47
|
+
This is currently in ideation, but me myself are eagerly waiting to try this myself.
|
48
|
+
|
49
|
+
I have a lot of codebases that needs cleanup! 🤯
|
50
|
+
|
51
|
+
## Contributing
|
52
|
+
|
53
|
+
Take a look into:
|
54
|
+
https://github.com/Xavier-IV/windclutter/wiki/Developer
|
55
|
+
|
56
|
+
|
57
|
+
## Great alternative
|
58
|
+
|
59
|
+
There are some limited alternative that I'm aware of and are still searching:
|
60
|
+
|
61
|
+
- [Windi CSS Analyzer](https://windicss.org/features/analyzer.html) (Sunsetting)
|
62
|
+
- [Tailwind CSS Analysis](https://github.com/apvarun/tailwindcss-analysis)
|
data/bin/windclutter
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'dry/cli'
|
4
|
+
require 'windclutter/util/file_handler'
|
5
|
+
require 'windclutter/util/config'
|
6
|
+
require 'windclutter/util/generator'
|
7
|
+
require 'windclutter/processor'
|
8
|
+
|
9
|
+
module WindClutter
|
10
|
+
module CLI
|
11
|
+
module Commands
|
12
|
+
module Generate
|
13
|
+
# Initiate setup for specified project
|
14
|
+
class OnFly < Dry::CLI::Command
|
15
|
+
include WindClutter::Util
|
16
|
+
|
17
|
+
desc 'Perform inline generation of class'
|
18
|
+
|
19
|
+
def call(**opt)
|
20
|
+
puts
|
21
|
+
name = Generator.random_class
|
22
|
+
|
23
|
+
classes = WindClutter::Processor.sort(opt[:args])
|
24
|
+
puts WindClutter::Processor.build_single(name, classes)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'dry/cli'
|
4
|
+
require 'windclutter/util/file_handler'
|
5
|
+
require 'windclutter/util/config'
|
6
|
+
|
7
|
+
module WindClutter
|
8
|
+
module CLI
|
9
|
+
module Commands
|
10
|
+
module Project
|
11
|
+
# Initiate setup for specified project
|
12
|
+
class Init < Dry::CLI::Command
|
13
|
+
include WindClutter::Util
|
14
|
+
|
15
|
+
desc 'Setup windclutter for your project'
|
16
|
+
|
17
|
+
argument :name, required: true, desc: 'Name of your project.'
|
18
|
+
|
19
|
+
def call(name:, **)
|
20
|
+
FileHandler.create_project(name)
|
21
|
+
puts 'Successfully created!'.green
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# List all of created project for windclutter
|
26
|
+
class List < Dry::CLI::Command
|
27
|
+
include WindClutter::Util
|
28
|
+
|
29
|
+
desc 'List all of created windclutter project.'
|
30
|
+
|
31
|
+
def call(**)
|
32
|
+
puts FileHandler.list_projects
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# Use specified project
|
37
|
+
class Use < Dry::CLI::Command
|
38
|
+
include WindClutter::Util
|
39
|
+
|
40
|
+
desc 'Use the project, automatically create one if not exists yet.'
|
41
|
+
|
42
|
+
argument :name, required: true, desc: 'Name of your project.'
|
43
|
+
|
44
|
+
def call(name:, **)
|
45
|
+
return Config.read('active_project') if name.nil?
|
46
|
+
|
47
|
+
unless FileHandler.list_projects.include? name
|
48
|
+
FileHandler.create_project(name)
|
49
|
+
puts 'No project, we created one instead'.green
|
50
|
+
end
|
51
|
+
|
52
|
+
Config.update('active_project', name)
|
53
|
+
puts "Using project \"#{name}\"".green
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'dry/cli'
|
4
|
+
require 'windclutter/util/file_handler'
|
5
|
+
require 'windclutter/cli/commands/project'
|
6
|
+
require 'windclutter/cli/commands/generate'
|
7
|
+
|
8
|
+
module WindClutter
|
9
|
+
module CLI
|
10
|
+
# Command module to be use by CLI
|
11
|
+
module Commands
|
12
|
+
extend Dry::CLI::Registry
|
13
|
+
|
14
|
+
# Print out the version of windclutter
|
15
|
+
class Version < Dry::CLI::Command
|
16
|
+
desc 'Print version'
|
17
|
+
|
18
|
+
def call(*)
|
19
|
+
puts '0.0.1'
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# Perform initial setup for windclutter
|
24
|
+
class Install < Dry::CLI::Command
|
25
|
+
include WindClutter::Util
|
26
|
+
|
27
|
+
desc 'Initiate first setup for tail_draft'
|
28
|
+
|
29
|
+
def call(*)
|
30
|
+
FileHandler.init_config
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# Uninstallation handler
|
35
|
+
class Uninstall < Dry::CLI::Command
|
36
|
+
include WindClutter::Util
|
37
|
+
|
38
|
+
desc 'Remove all windclutter setup and configurations'
|
39
|
+
|
40
|
+
def call(*)
|
41
|
+
FileHandler.uninstall
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
register 'version', Version, aliases: %w[v -v --version]
|
46
|
+
register 'install', Install, aliases: %w[i -i --install]
|
47
|
+
register 'uninstall', Uninstall, aliases: %w[u -u --uninstall]
|
48
|
+
|
49
|
+
register 'project', aliases: ['p'] do |prefix|
|
50
|
+
prefix.register 'init', Commands::Project::Init
|
51
|
+
prefix.register 'list', Commands::Project::List
|
52
|
+
prefix.register 'use', Commands::Project::Use
|
53
|
+
end
|
54
|
+
|
55
|
+
register 'generate', aliases: ['g'] do |prefix|
|
56
|
+
prefix.register 'on-fly', Commands::Generate::OnFly
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'windclutter/util/generator'
|
4
|
+
|
5
|
+
module WindClutter
|
6
|
+
# Processor for windclutter
|
7
|
+
class Processor
|
8
|
+
include WindClutter::Util
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
@key_tag = :windclutter
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.build_single(name, classes)
|
15
|
+
<<~OUTPUT
|
16
|
+
.#{name} {
|
17
|
+
@apply #{classes.join(' ')};
|
18
|
+
}
|
19
|
+
OUTPUT
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.auto_process(file_content, collections)
|
23
|
+
return if file_content.nil?
|
24
|
+
|
25
|
+
regex = /class="(?:(?!#{@key_tag}:)[^"])*"/
|
26
|
+
class_occurrences = file_content.scan(regex)
|
27
|
+
|
28
|
+
class_occurrences.each do |occurrence|
|
29
|
+
gen_class = Generator.random_class
|
30
|
+
file_content = file_content.gsub(/#{occurrence}/, "class=\"#{gen_class}\"")
|
31
|
+
|
32
|
+
collections.push({
|
33
|
+
generated_name: gen_class,
|
34
|
+
provided_name: nil,
|
35
|
+
class: occurrence.to_s.match(/class="([^"]*)"/)[1],
|
36
|
+
named: false
|
37
|
+
})
|
38
|
+
end
|
39
|
+
file_content
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.sort(classes)
|
43
|
+
classes.sort
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'fileutils'
|
4
|
+
require 'colorize'
|
5
|
+
require 'yaml'
|
6
|
+
|
7
|
+
module WindClutter
|
8
|
+
module Util
|
9
|
+
# Config handler
|
10
|
+
class Config
|
11
|
+
def self.update(key, value)
|
12
|
+
return unless config_exists?
|
13
|
+
|
14
|
+
config = YAML.load_file('/tmp/windclutter/config.yml')
|
15
|
+
config[key] = value
|
16
|
+
|
17
|
+
File.open('/tmp/windclutter/config.yml', 'w') { |f| YAML.dump(config, f) }
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.read(key)
|
21
|
+
return unless config_exists?
|
22
|
+
|
23
|
+
config = YAML.load_file('/tmp/windclutter/config.yml')
|
24
|
+
config[key]
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.config_exists?
|
28
|
+
unless File.file?('/tmp/windclutter/config.yml')
|
29
|
+
puts 'You have not install windclutter yet'.yellow
|
30
|
+
puts 'To install, run:'
|
31
|
+
puts "\twindclutter install".green
|
32
|
+
return false
|
33
|
+
end
|
34
|
+
true
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'fileutils'
|
4
|
+
require 'colorize'
|
5
|
+
require 'yaml'
|
6
|
+
|
7
|
+
module WindClutter
|
8
|
+
module Util
|
9
|
+
# Generator helper
|
10
|
+
class FileHandler
|
11
|
+
def self.init_config
|
12
|
+
FileUtils.mkdir_p('/tmp/windclutter')
|
13
|
+
|
14
|
+
return puts 'Setup already performed!'.yellow if File.file?('/tmp/windclutter/config.yml')
|
15
|
+
|
16
|
+
template = File.expand_path('../../template', File.dirname(__FILE__))
|
17
|
+
|
18
|
+
puts 'Created the following files:'
|
19
|
+
Dir["#{template}/*.yml"].each do |t|
|
20
|
+
FileUtils.cp(t, '/tmp/windclutter')
|
21
|
+
puts "\t#{t}"
|
22
|
+
end
|
23
|
+
|
24
|
+
puts "\nSetup completed!".green
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.uninstall
|
28
|
+
Dir['/tmp/windclutter'].each do |t|
|
29
|
+
FileUtils.rm_rf(t)
|
30
|
+
end
|
31
|
+
|
32
|
+
puts 'Uninstall completed!'.green
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.create_project(value)
|
36
|
+
FileUtils.mkdir_p("/tmp/windclutter/projects/#{value}")
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.list_projects
|
40
|
+
Dir['/tmp/windclutter/projects/*'].map do |t|
|
41
|
+
t.split('/tmp/windclutter/projects/')[1]
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.scanners(extension)
|
46
|
+
Dir["#{File.dirname(__FILE__)}/**/*#{extension}"]
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.overwrite(file, content)
|
50
|
+
File.open(file, 'w') { |t| t.puts content }
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module WindClutter
|
4
|
+
module Util
|
5
|
+
# Generator helper
|
6
|
+
class Generator
|
7
|
+
def self.random_class(prefixed: true)
|
8
|
+
random = [*'A'..'Z'].sample(10).join.downcase
|
9
|
+
"windclutter:#{random}" if prefixed
|
10
|
+
random
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
data/lib/windclutter.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'minitest/autorun'
|
4
|
+
require 'windclutter/processor'
|
5
|
+
|
6
|
+
class WindClutterProcessorTest < Minitest::Test
|
7
|
+
def test_able_to_generate_block
|
8
|
+
result = WindClutter::Processor.build_single('class', %w[container mx-auto])
|
9
|
+
|
10
|
+
assert_equal ".class {\n @apply container mx-auto;\n}\n",
|
11
|
+
result
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_able_to_auto_process
|
15
|
+
WindClutter::Util::Generator.stub(:random_class, 'windclutter:mocked_value') do
|
16
|
+
collections = []
|
17
|
+
result = WindClutter::Processor.auto_process(dummy_content, collections)
|
18
|
+
|
19
|
+
assert_equal result, expected_output
|
20
|
+
assert_equal collections[0][:generated_name], 'windclutter:mocked_value'
|
21
|
+
assert_equal collections[0][:class], 'flex flex-col items-center gap-6 px-10 py-40 overflow-y-scroll'
|
22
|
+
assert_nil collections[0][:provided_name]
|
23
|
+
assert_equal collections[0][:named], false
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def dummy_content
|
30
|
+
<<~CONTENT
|
31
|
+
<div class="flex flex-col items-center gap-6 px-10 py-40 overflow-y-scroll">
|
32
|
+
</div>
|
33
|
+
CONTENT
|
34
|
+
end
|
35
|
+
|
36
|
+
def expected_output
|
37
|
+
<<~CONTENT
|
38
|
+
<div class=\"windclutter:mocked_value\">
|
39
|
+
</div>
|
40
|
+
CONTENT
|
41
|
+
end
|
42
|
+
|
43
|
+
def expected_collections
|
44
|
+
{ generated_name: 'windclutter:mocked_value',
|
45
|
+
class: 'flex flex-col items-center gap-6 px-10 py-40 overflow-y-scroll' }
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'minitest/autorun'
|
4
|
+
require 'windclutter/util/generator'
|
5
|
+
|
6
|
+
class WindClutterUtilGeneratorTest < Minitest::Test
|
7
|
+
def test_able_to_randomize_class_name
|
8
|
+
assert_match(/.[a-z]+/,
|
9
|
+
WindClutter::Util::Generator.random_class)
|
10
|
+
end
|
11
|
+
end
|
metadata
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: windclutter
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Zafranudin Zafrin
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2023-09-06 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: Your buddy to skyrocket your development with TailwindCSS.
|
14
|
+
email: coffee@zafranudin.dev
|
15
|
+
executables:
|
16
|
+
- windclutter
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files: []
|
19
|
+
files:
|
20
|
+
- README.md
|
21
|
+
- bin/windclutter
|
22
|
+
- lib/windclutter.rb
|
23
|
+
- lib/windclutter/analyser.rb
|
24
|
+
- lib/windclutter/cli/commands/generate.rb
|
25
|
+
- lib/windclutter/cli/commands/project.rb
|
26
|
+
- lib/windclutter/cli/core.rb
|
27
|
+
- lib/windclutter/processor.rb
|
28
|
+
- lib/windclutter/util/config.rb
|
29
|
+
- lib/windclutter/util/file_handler.rb
|
30
|
+
- lib/windclutter/util/generator.rb
|
31
|
+
- test/test_windclutter.rb
|
32
|
+
- test/windclutter/test_processor.rb
|
33
|
+
- test/windclutter/util/test_generator.rb
|
34
|
+
homepage: https://rubygems.org/gems/tailwind_buddy
|
35
|
+
licenses:
|
36
|
+
- MIT
|
37
|
+
metadata: {}
|
38
|
+
post_install_message:
|
39
|
+
rdoc_options: []
|
40
|
+
require_paths:
|
41
|
+
- lib
|
42
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: 2.7.0
|
47
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
48
|
+
requirements:
|
49
|
+
- - ">="
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: '0'
|
52
|
+
requirements: []
|
53
|
+
rubygems_version: 3.4.18
|
54
|
+
signing_key:
|
55
|
+
specification_version: 4
|
56
|
+
summary: Quickly develop with TailwindCSS without worries.
|
57
|
+
test_files: []
|