collie 0.1.0
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/CHANGELOG.md +12 -0
- data/Gemfile +10 -0
- data/LICENSE.txt +21 -0
- data/README.md +333 -0
- data/Rakefile +9 -0
- data/collie.gemspec +37 -0
- data/docs/TUTORIAL.md +588 -0
- data/docs/index.html +56 -0
- data/docs/playground/README.md +134 -0
- data/docs/playground/build-collie-bundle.rb +85 -0
- data/docs/playground/css/styles.css +402 -0
- data/docs/playground/index.html +146 -0
- data/docs/playground/js/app.js +231 -0
- data/docs/playground/js/collie-bridge.js +186 -0
- data/docs/playground/js/editor.js +129 -0
- data/docs/playground/js/examples.js +80 -0
- data/docs/playground/js/ruby-runner.js +75 -0
- data/docs/playground/test-server.sh +18 -0
- data/exe/collie +15 -0
- data/lib/collie/analyzer/conflict.rb +114 -0
- data/lib/collie/analyzer/reachability.rb +83 -0
- data/lib/collie/analyzer/recursion.rb +96 -0
- data/lib/collie/analyzer/symbol_table.rb +67 -0
- data/lib/collie/ast.rb +183 -0
- data/lib/collie/cli.rb +249 -0
- data/lib/collie/config.rb +91 -0
- data/lib/collie/formatter/formatter.rb +196 -0
- data/lib/collie/formatter/options.rb +23 -0
- data/lib/collie/linter/base.rb +62 -0
- data/lib/collie/linter/registry.rb +34 -0
- data/lib/collie/linter/rules/ambiguous_precedence.rb +87 -0
- data/lib/collie/linter/rules/circular_reference.rb +89 -0
- data/lib/collie/linter/rules/consistent_tag_naming.rb +69 -0
- data/lib/collie/linter/rules/duplicate_token.rb +38 -0
- data/lib/collie/linter/rules/empty_action.rb +52 -0
- data/lib/collie/linter/rules/factorizable_rules.rb +67 -0
- data/lib/collie/linter/rules/left_recursion.rb +34 -0
- data/lib/collie/linter/rules/long_rule.rb +37 -0
- data/lib/collie/linter/rules/missing_start_symbol.rb +38 -0
- data/lib/collie/linter/rules/nonterminal_naming.rb +34 -0
- data/lib/collie/linter/rules/prec_improvement.rb +54 -0
- data/lib/collie/linter/rules/redundant_epsilon.rb +44 -0
- data/lib/collie/linter/rules/right_recursion.rb +35 -0
- data/lib/collie/linter/rules/token_naming.rb +39 -0
- data/lib/collie/linter/rules/trailing_whitespace.rb +46 -0
- data/lib/collie/linter/rules/undefined_symbol.rb +55 -0
- data/lib/collie/linter/rules/unreachable_rule.rb +49 -0
- data/lib/collie/linter/rules/unused_nonterminal.rb +93 -0
- data/lib/collie/linter/rules/unused_token.rb +82 -0
- data/lib/collie/parser/lexer.rb +349 -0
- data/lib/collie/parser/parser.rb +416 -0
- data/lib/collie/reporter/github.rb +35 -0
- data/lib/collie/reporter/json.rb +52 -0
- data/lib/collie/reporter/text.rb +97 -0
- data/lib/collie/version.rb +5 -0
- data/lib/collie.rb +52 -0
- metadata +145 -0
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# Collie Playground
|
|
2
|
+
|
|
3
|
+
An interactive web-based playground for trying out Collie, the linter and formatter for Lrama Style BNF grammar files.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- Interactive Monaco Editor (same as VS Code)
|
|
8
|
+
- Real-time linting with all 18 built-in rules
|
|
9
|
+
- Grammar formatting
|
|
10
|
+
- Auto-fix functionality
|
|
11
|
+
- Yacc/Bison/Lrama syntax highlighting
|
|
12
|
+
- Pre-loaded example grammar files
|
|
13
|
+
- Runs completely in the browser using Ruby.wasm
|
|
14
|
+
|
|
15
|
+
## How It Works
|
|
16
|
+
|
|
17
|
+
The playground uses [Ruby.wasm](https://github.com/ruby/ruby.wasm) to run Ruby code directly in your browser. All Collie functionality (parsing, linting, formatting) executes client-side - your code never leaves your browser.
|
|
18
|
+
|
|
19
|
+
### Architecture
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
Browser
|
|
23
|
+
├── Monaco Editor (UI)
|
|
24
|
+
├── Ruby.wasm (Ruby runtime)
|
|
25
|
+
├── collie-bundle.rb (All Collie code)
|
|
26
|
+
└── JavaScript bridge (UI ↔ Ruby)
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Local Development
|
|
30
|
+
|
|
31
|
+
### Prerequisites
|
|
32
|
+
|
|
33
|
+
- Ruby 3.2 or higher
|
|
34
|
+
- Modern web browser
|
|
35
|
+
|
|
36
|
+
### Setup
|
|
37
|
+
|
|
38
|
+
1. Generate the Collie bundle:
|
|
39
|
+
```bash
|
|
40
|
+
ruby build-collie-bundle.rb
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
2. Serve the playground locally:
|
|
44
|
+
```bash
|
|
45
|
+
# Using Ruby
|
|
46
|
+
ruby -run -ehttpd . -p 8000
|
|
47
|
+
|
|
48
|
+
# Using Python
|
|
49
|
+
python3 -m http.server 8000
|
|
50
|
+
|
|
51
|
+
# Using Node.js (if you have http-server installed)
|
|
52
|
+
npx http-server -p 8000
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
3. Open http://localhost:8000/ in your browser
|
|
56
|
+
|
|
57
|
+
### Rebuilding the Bundle
|
|
58
|
+
|
|
59
|
+
Whenever Collie's code changes, rebuild the bundle:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
ruby build-collie-bundle.rb
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Deployment
|
|
66
|
+
|
|
67
|
+
The playground is automatically deployed to GitHub Pages via GitHub Actions when changes are pushed to the main branch.
|
|
68
|
+
|
|
69
|
+
### GitHub Actions Workflow
|
|
70
|
+
|
|
71
|
+
See `.github/workflows/deploy-playground.yml` for the deployment configuration.
|
|
72
|
+
|
|
73
|
+
The workflow:
|
|
74
|
+
1. Checks out the repository
|
|
75
|
+
2. Sets up Ruby
|
|
76
|
+
3. Builds the Collie bundle
|
|
77
|
+
4. Deploys to GitHub Pages
|
|
78
|
+
|
|
79
|
+
### Accessing the Deployed Playground
|
|
80
|
+
|
|
81
|
+
Once deployed, the playground will be available at:
|
|
82
|
+
```
|
|
83
|
+
https://ydah.github.io/collie/playground/
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Files
|
|
87
|
+
|
|
88
|
+
- `index.html` - Main HTML page
|
|
89
|
+
- `css/styles.css` - Stylesheet
|
|
90
|
+
- `js/app.js` - Main application logic
|
|
91
|
+
- `js/editor.js` - Monaco Editor integration
|
|
92
|
+
- `js/ruby-runner.js` - Ruby.wasm wrapper
|
|
93
|
+
- `js/collie-bridge.js` - JavaScript ↔ Ruby bridge
|
|
94
|
+
- `js/examples.js` - Example grammar files
|
|
95
|
+
- `collie-bundle.rb` - Bundled Collie code (generated)
|
|
96
|
+
- `build-collie-bundle.rb` - Bundle generation script
|
|
97
|
+
|
|
98
|
+
## Limitations
|
|
99
|
+
|
|
100
|
+
- First load may be slow (Ruby.wasm is ~30MB)
|
|
101
|
+
- Large grammar files (>10,000 lines) may be slow
|
|
102
|
+
- Some Ruby features may not work in WebAssembly
|
|
103
|
+
|
|
104
|
+
## Troubleshooting
|
|
105
|
+
|
|
106
|
+
### "Failed to initialize Ruby.wasm"
|
|
107
|
+
|
|
108
|
+
- Ensure you have a stable internet connection (Ruby.wasm is loaded from CDN)
|
|
109
|
+
- Try refreshing the page
|
|
110
|
+
- Clear browser cache
|
|
111
|
+
|
|
112
|
+
### "Collie bundle not found"
|
|
113
|
+
|
|
114
|
+
- Run `ruby build-collie-bundle.rb` to generate the bundle
|
|
115
|
+
- Ensure `collie-bundle.rb` exists in the playground directory
|
|
116
|
+
|
|
117
|
+
### Linting/Formatting doesn't work
|
|
118
|
+
|
|
119
|
+
- Check browser console for JavaScript errors
|
|
120
|
+
- Ensure the bundle was generated correctly
|
|
121
|
+
- Try with a simple example first
|
|
122
|
+
|
|
123
|
+
## Contributing
|
|
124
|
+
|
|
125
|
+
To add new features or fix bugs:
|
|
126
|
+
|
|
127
|
+
1. Make changes to the playground files
|
|
128
|
+
2. Test locally using a local web server
|
|
129
|
+
3. If you changed Collie code, rebuild the bundle
|
|
130
|
+
4. Submit a pull request
|
|
131
|
+
|
|
132
|
+
## License
|
|
133
|
+
|
|
134
|
+
MIT License - Same as Collie
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require "pathname"
|
|
5
|
+
|
|
6
|
+
OUTPUT_FILE = Pathname.new(__dir__) / "collie-bundle.rb"
|
|
7
|
+
LIB_DIR = Pathname.new(__dir__) / ".." / ".." / "lib"
|
|
8
|
+
|
|
9
|
+
files = [
|
|
10
|
+
"collie/version.rb",
|
|
11
|
+
"collie/ast.rb",
|
|
12
|
+
"collie/parser/lexer.rb",
|
|
13
|
+
"collie/parser/parser.rb",
|
|
14
|
+
"collie/analyzer/symbol_table.rb",
|
|
15
|
+
"collie/analyzer/reachability.rb",
|
|
16
|
+
"collie/analyzer/recursion.rb",
|
|
17
|
+
"collie/analyzer/conflict.rb",
|
|
18
|
+
"collie/linter/base.rb",
|
|
19
|
+
"collie/linter/registry.rb",
|
|
20
|
+
"collie/linter/rules/duplicate_token.rb",
|
|
21
|
+
"collie/linter/rules/undefined_symbol.rb",
|
|
22
|
+
"collie/linter/rules/unreachable_rule.rb",
|
|
23
|
+
"collie/linter/rules/circular_reference.rb",
|
|
24
|
+
"collie/linter/rules/missing_start_symbol.rb",
|
|
25
|
+
"collie/linter/rules/unused_nonterminal.rb",
|
|
26
|
+
"collie/linter/rules/unused_token.rb",
|
|
27
|
+
"collie/linter/rules/left_recursion.rb",
|
|
28
|
+
"collie/linter/rules/right_recursion.rb",
|
|
29
|
+
"collie/linter/rules/ambiguous_precedence.rb",
|
|
30
|
+
"collie/linter/rules/token_naming.rb",
|
|
31
|
+
"collie/linter/rules/nonterminal_naming.rb",
|
|
32
|
+
"collie/linter/rules/consistent_tag_naming.rb",
|
|
33
|
+
"collie/linter/rules/trailing_whitespace.rb",
|
|
34
|
+
"collie/linter/rules/empty_action.rb",
|
|
35
|
+
"collie/linter/rules/long_rule.rb",
|
|
36
|
+
"collie/linter/rules/factorizable_rules.rb",
|
|
37
|
+
"collie/linter/rules/redundant_epsilon.rb",
|
|
38
|
+
"collie/linter/rules/prec_improvement.rb",
|
|
39
|
+
"collie/formatter/options.rb",
|
|
40
|
+
"collie/formatter/formatter.rb",
|
|
41
|
+
"collie/reporter/text.rb",
|
|
42
|
+
"collie/reporter/json.rb",
|
|
43
|
+
"collie/reporter/github.rb",
|
|
44
|
+
"collie/config.rb",
|
|
45
|
+
"collie.rb"
|
|
46
|
+
]
|
|
47
|
+
|
|
48
|
+
output = []
|
|
49
|
+
output << "# frozen_string_literal: true"
|
|
50
|
+
output << ""
|
|
51
|
+
output << "# Collie Bundle for Ruby.wasm Playground"
|
|
52
|
+
output << "# Auto-generated - DO NOT EDIT"
|
|
53
|
+
output << "# Generated at: #{Time.now}"
|
|
54
|
+
output << ""
|
|
55
|
+
|
|
56
|
+
files.each do |file_path|
|
|
57
|
+
full_path = LIB_DIR / file_path
|
|
58
|
+
unless full_path.exist?
|
|
59
|
+
warn "Warning: #{file_path} not found, skipping"
|
|
60
|
+
next
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
output << "# === #{file_path} ==="
|
|
64
|
+
content = File.read(full_path)
|
|
65
|
+
|
|
66
|
+
content = content.gsub(/^# frozen_string_literal: true\n/, "")
|
|
67
|
+
content = content.gsub(/^require ['"]collie.*$\n/, "")
|
|
68
|
+
content = content.gsub(/^require_relative .*$\n/, "")
|
|
69
|
+
content = content.gsub(/^require ["']pastel["']\n/, "")
|
|
70
|
+
content = content.gsub(/^require ["']thor["']\n/, "")
|
|
71
|
+
content = content.gsub(/^require ["']tty-table["']\n/, "")
|
|
72
|
+
|
|
73
|
+
content = content.gsub(
|
|
74
|
+
/begin\s+require ["']pastel["']\s+PASTEL_AVAILABLE = true\s+rescue LoadError\s+PASTEL_AVAILABLE = false\s+end/m,
|
|
75
|
+
"PASTEL_AVAILABLE = false"
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
output << content
|
|
79
|
+
output << ""
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
File.write(OUTPUT_FILE, output.join("\n"))
|
|
83
|
+
puts "Bundle created: #{OUTPUT_FILE}"
|
|
84
|
+
puts "Size: #{File.size(OUTPUT_FILE)} bytes (#{(File.size(OUTPUT_FILE) / 1024.0).round(2)} KB)"
|
|
85
|
+
puts "Files bundled: #{files.size}"
|
|
@@ -0,0 +1,402 @@
|
|
|
1
|
+
:root {
|
|
2
|
+
--primary-color: #4a90e2;
|
|
3
|
+
--success-color: #52c41a;
|
|
4
|
+
--error-color: #f5222d;
|
|
5
|
+
--warning-color: #faad14;
|
|
6
|
+
--info-color: #1890ff;
|
|
7
|
+
--bg-color: #f5f5f5;
|
|
8
|
+
--panel-bg: #ffffff;
|
|
9
|
+
--border-color: #d9d9d9;
|
|
10
|
+
--text-color: #262626;
|
|
11
|
+
--text-secondary: #8c8c8c;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
* {
|
|
15
|
+
margin: 0;
|
|
16
|
+
padding: 0;
|
|
17
|
+
box-sizing: border-box;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
body {
|
|
21
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
|
|
22
|
+
background: var(--bg-color);
|
|
23
|
+
color: var(--text-color);
|
|
24
|
+
line-height: 1.6;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.container {
|
|
28
|
+
max-width: 1400px;
|
|
29
|
+
margin: 0 auto;
|
|
30
|
+
padding: 0 20px;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/* Header */
|
|
34
|
+
.header {
|
|
35
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
36
|
+
color: white;
|
|
37
|
+
padding: 2rem 0;
|
|
38
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.header h1 {
|
|
42
|
+
font-size: 2.5rem;
|
|
43
|
+
margin-bottom: 0.5rem;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.header p {
|
|
47
|
+
font-size: 1.1rem;
|
|
48
|
+
opacity: 0.9;
|
|
49
|
+
margin-bottom: 1rem;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.header-actions {
|
|
53
|
+
display: flex;
|
|
54
|
+
gap: 1rem;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/* Loading Screen */
|
|
58
|
+
.loading {
|
|
59
|
+
display: flex;
|
|
60
|
+
align-items: center;
|
|
61
|
+
justify-content: center;
|
|
62
|
+
min-height: 60vh;
|
|
63
|
+
text-align: center;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.loading-content {
|
|
67
|
+
max-width: 400px;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.spinner {
|
|
71
|
+
width: 60px;
|
|
72
|
+
height: 60px;
|
|
73
|
+
margin: 0 auto 1rem;
|
|
74
|
+
border: 4px solid rgba(0, 0, 0, 0.1);
|
|
75
|
+
border-left-color: var(--primary-color);
|
|
76
|
+
border-radius: 50%;
|
|
77
|
+
animation: spin 1s linear infinite;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
@keyframes spin {
|
|
81
|
+
to { transform: rotate(360deg); }
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.loading-detail {
|
|
85
|
+
color: var(--text-secondary);
|
|
86
|
+
font-size: 0.9rem;
|
|
87
|
+
margin-top: 0.5rem;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/* Main Content */
|
|
91
|
+
.main-content {
|
|
92
|
+
padding: 2rem 0;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/* Toolbar */
|
|
96
|
+
.toolbar {
|
|
97
|
+
display: flex;
|
|
98
|
+
justify-content: space-between;
|
|
99
|
+
align-items: center;
|
|
100
|
+
background: var(--panel-bg);
|
|
101
|
+
padding: 1rem;
|
|
102
|
+
border-radius: 8px;
|
|
103
|
+
margin-bottom: 1rem;
|
|
104
|
+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.toolbar-left,
|
|
108
|
+
.toolbar-right {
|
|
109
|
+
display: flex;
|
|
110
|
+
gap: 0.5rem;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/* Buttons */
|
|
114
|
+
.btn {
|
|
115
|
+
padding: 0.5rem 1rem;
|
|
116
|
+
border: none;
|
|
117
|
+
border-radius: 4px;
|
|
118
|
+
font-size: 0.9rem;
|
|
119
|
+
font-weight: 500;
|
|
120
|
+
cursor: pointer;
|
|
121
|
+
transition: all 0.2s;
|
|
122
|
+
text-decoration: none;
|
|
123
|
+
display: inline-block;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.btn-primary {
|
|
127
|
+
background: var(--primary-color);
|
|
128
|
+
color: white;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
.btn-primary:hover {
|
|
132
|
+
background: #3a7bc8;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
.btn-success {
|
|
136
|
+
background: var(--success-color);
|
|
137
|
+
color: white;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
.btn-success:hover {
|
|
141
|
+
background: #49b318;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
.btn-secondary {
|
|
145
|
+
background: #fff;
|
|
146
|
+
color: var(--text-color);
|
|
147
|
+
border: 1px solid var(--border-color);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
.btn-secondary:hover {
|
|
151
|
+
background: #fafafa;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
.btn:disabled {
|
|
155
|
+
opacity: 0.5;
|
|
156
|
+
cursor: not-allowed;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/* Select */
|
|
160
|
+
.select {
|
|
161
|
+
padding: 0.5rem;
|
|
162
|
+
border: 1px solid var(--border-color);
|
|
163
|
+
border-radius: 4px;
|
|
164
|
+
font-size: 0.9rem;
|
|
165
|
+
background: white;
|
|
166
|
+
cursor: pointer;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/* Workspace */
|
|
170
|
+
.workspace {
|
|
171
|
+
display: grid;
|
|
172
|
+
grid-template-columns: 1fr 1fr;
|
|
173
|
+
gap: 1rem;
|
|
174
|
+
margin-bottom: 1rem;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
@media (max-width: 1024px) {
|
|
178
|
+
.workspace {
|
|
179
|
+
grid-template-columns: 1fr;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/* Panel */
|
|
184
|
+
.panel {
|
|
185
|
+
background: var(--panel-bg);
|
|
186
|
+
border-radius: 8px;
|
|
187
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
|
188
|
+
overflow: hidden;
|
|
189
|
+
display: flex;
|
|
190
|
+
flex-direction: column;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
.panel-header {
|
|
194
|
+
display: flex;
|
|
195
|
+
justify-content: space-between;
|
|
196
|
+
align-items: center;
|
|
197
|
+
padding: 1rem;
|
|
198
|
+
border-bottom: 1px solid var(--border-color);
|
|
199
|
+
background: #fafafa;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
.panel-header h2 {
|
|
203
|
+
font-size: 1.1rem;
|
|
204
|
+
font-weight: 600;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
.panel-info {
|
|
208
|
+
color: var(--text-secondary);
|
|
209
|
+
font-size: 0.9rem;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/* Tabs */
|
|
213
|
+
.output-tabs {
|
|
214
|
+
display: flex;
|
|
215
|
+
gap: 0.5rem;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
.tab-btn {
|
|
219
|
+
padding: 0.4rem 0.8rem;
|
|
220
|
+
border: none;
|
|
221
|
+
background: transparent;
|
|
222
|
+
cursor: pointer;
|
|
223
|
+
font-size: 0.9rem;
|
|
224
|
+
color: var(--text-secondary);
|
|
225
|
+
border-bottom: 2px solid transparent;
|
|
226
|
+
transition: all 0.2s;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
.tab-btn:hover {
|
|
230
|
+
color: var(--text-color);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
.tab-btn.active {
|
|
234
|
+
color: var(--primary-color);
|
|
235
|
+
border-bottom-color: var(--primary-color);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
.tab-content {
|
|
239
|
+
display: none;
|
|
240
|
+
flex: 1;
|
|
241
|
+
overflow: auto;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
.tab-content.active {
|
|
245
|
+
display: block;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/* Editor */
|
|
249
|
+
.editor-container {
|
|
250
|
+
height: 500px;
|
|
251
|
+
border-top: 1px solid var(--border-color);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/* Output */
|
|
255
|
+
.output-content {
|
|
256
|
+
padding: 1rem;
|
|
257
|
+
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
|
|
258
|
+
font-size: 0.9rem;
|
|
259
|
+
height: 500px;
|
|
260
|
+
overflow: auto;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
.placeholder {
|
|
264
|
+
color: var(--text-secondary);
|
|
265
|
+
text-align: center;
|
|
266
|
+
padding: 2rem;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/* Diagnostics */
|
|
270
|
+
.diagnostic-item {
|
|
271
|
+
padding: 0.75rem;
|
|
272
|
+
margin-bottom: 0.5rem;
|
|
273
|
+
border-left: 4px solid;
|
|
274
|
+
background: #fafafa;
|
|
275
|
+
border-radius: 4px;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
.diagnostic-item.error {
|
|
279
|
+
border-left-color: var(--error-color);
|
|
280
|
+
background: #fff2f0;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
.diagnostic-item.warning {
|
|
284
|
+
border-left-color: var(--warning-color);
|
|
285
|
+
background: #fffbe6;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
.diagnostic-item.convention {
|
|
289
|
+
border-left-color: var(--info-color);
|
|
290
|
+
background: #e6f7ff;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
.diagnostic-item.info {
|
|
294
|
+
border-left-color: var(--text-secondary);
|
|
295
|
+
background: #f0f0f0;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
.diagnostic-location {
|
|
299
|
+
font-weight: 600;
|
|
300
|
+
color: var(--text-color);
|
|
301
|
+
margin-bottom: 0.25rem;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
.diagnostic-message {
|
|
305
|
+
color: var(--text-secondary);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
.diagnostic-rule {
|
|
309
|
+
display: inline-block;
|
|
310
|
+
padding: 0.2rem 0.5rem;
|
|
311
|
+
background: white;
|
|
312
|
+
border-radius: 3px;
|
|
313
|
+
font-size: 0.85rem;
|
|
314
|
+
margin-top: 0.25rem;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
.no-offenses {
|
|
318
|
+
color: var(--success-color);
|
|
319
|
+
font-weight: 600;
|
|
320
|
+
text-align: center;
|
|
321
|
+
padding: 2rem;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
/* Rules List */
|
|
325
|
+
.rule-item {
|
|
326
|
+
padding: 0.75rem;
|
|
327
|
+
margin-bottom: 0.5rem;
|
|
328
|
+
border: 1px solid var(--border-color);
|
|
329
|
+
border-radius: 4px;
|
|
330
|
+
background: white;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
.rule-header {
|
|
334
|
+
display: flex;
|
|
335
|
+
justify-content: space-between;
|
|
336
|
+
align-items: center;
|
|
337
|
+
margin-bottom: 0.5rem;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
.rule-name {
|
|
341
|
+
font-weight: 600;
|
|
342
|
+
color: var(--primary-color);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
.rule-severity {
|
|
346
|
+
display: inline-block;
|
|
347
|
+
padding: 0.2rem 0.5rem;
|
|
348
|
+
border-radius: 3px;
|
|
349
|
+
font-size: 0.8rem;
|
|
350
|
+
font-weight: 500;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
.rule-severity.error {
|
|
354
|
+
background: #fff2f0;
|
|
355
|
+
color: var(--error-color);
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
.rule-severity.warning {
|
|
359
|
+
background: #fffbe6;
|
|
360
|
+
color: var(--warning-color);
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
.rule-severity.convention {
|
|
364
|
+
background: #e6f7ff;
|
|
365
|
+
color: var(--info-color);
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
.rule-severity.info {
|
|
369
|
+
background: #f0f0f0;
|
|
370
|
+
color: var(--text-secondary);
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
.rule-description {
|
|
374
|
+
color: var(--text-secondary);
|
|
375
|
+
font-size: 0.9rem;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
/* Info Panel */
|
|
379
|
+
.info-panel {
|
|
380
|
+
background: var(--panel-bg);
|
|
381
|
+
padding: 1.5rem;
|
|
382
|
+
border-radius: 8px;
|
|
383
|
+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
.info-panel h3 {
|
|
387
|
+
margin-bottom: 1rem;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
.info-panel p {
|
|
391
|
+
margin-bottom: 1rem;
|
|
392
|
+
color: var(--text-secondary);
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
.info-panel a {
|
|
396
|
+
color: var(--primary-color);
|
|
397
|
+
text-decoration: none;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
.info-panel a:hover {
|
|
401
|
+
text-decoration: underline;
|
|
402
|
+
}
|