docs: update README with new features
This commit is contained in:
parent
3e1003ba94
commit
92735f3eee
1 changed files with 366 additions and 8 deletions
374
README.md
374
README.md
|
@ -30,26 +30,68 @@ supported, I cannot guarantee that _everything_ is supported just yet.
|
||||||
- **Validation** - Syntax checking with precise error locations
|
- **Validation** - Syntax checking with precise error locations
|
||||||
- **Optimization** - Configurable empty line reduction and whitespace control
|
- **Optimization** - Configurable empty line reduction and whitespace control
|
||||||
|
|
||||||
|
### Diagnostics & Analysis
|
||||||
|
|
||||||
|
- **Comprehensive diagnostics** - Syntax, semantic, style, and best practice
|
||||||
|
analysis
|
||||||
|
- **Modular analysis** - Run specific diagnostic modules (`lexical`, `syntax`,
|
||||||
|
`style`, `semantic`)
|
||||||
|
- **LSP-compatible output** - JSON format for editor integration
|
||||||
|
- **Human-readable reports** - Detailed error messages with context and location
|
||||||
|
information
|
||||||
|
- **Configurable severity** - Control which diagnostic categories to
|
||||||
|
enable/disable
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
|
### Formatting
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Basic formatting
|
# Format a specific file (in place)
|
||||||
nff -f /etc/nftables.conf
|
nff format /etc/nftables.conf
|
||||||
|
|
||||||
|
# Format all .nft files in current directory (in place)
|
||||||
|
nff format
|
||||||
|
|
||||||
# Custom indentation (4 spaces)
|
# Custom indentation (4 spaces)
|
||||||
nff -f config.nft --indent spaces --spaces 4
|
nff format config.nft --indent spaces --spaces 4
|
||||||
|
|
||||||
# Optimize formatting (reduce empty lines)
|
# Optimize formatting (reduce empty lines)
|
||||||
nff -f config.nft --optimize
|
nff format config.nft --optimize
|
||||||
|
|
||||||
# Output to file
|
# Output to stdout instead of modifying files
|
||||||
nff -f config.nft -o formatted.nft
|
nff format config.nft --stdout
|
||||||
|
|
||||||
# Syntax validation only
|
# Syntax validation only
|
||||||
nff -f config.nft --check
|
nff format config.nft --check
|
||||||
|
|
||||||
# Debug output for development (or debugging)
|
# Debug output for development (or debugging)
|
||||||
nff -f config.nft --debug
|
nff format config.nft --debug
|
||||||
|
```
|
||||||
|
|
||||||
|
### Linting and Diagnostics
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Run comprehensive diagnostics on a file
|
||||||
|
nff lint /etc/nftables.conf
|
||||||
|
|
||||||
|
# Lint all .nft files in current directory
|
||||||
|
nff lint
|
||||||
|
|
||||||
|
# JSON output for editor integration
|
||||||
|
nff lint config.nft --json
|
||||||
|
|
||||||
|
# Run specific diagnostic modules
|
||||||
|
nff lint config.nft --modules syntax,style
|
||||||
|
|
||||||
|
# Available modules: lexical, syntax, style, semantic
|
||||||
|
nff lint config.nft --modules semantic
|
||||||
|
|
||||||
|
# Configure diagnostic settings (note: flags are enabled by default)
|
||||||
|
nff lint config.nft --style-warnings=false --best-practices=false
|
||||||
|
|
||||||
|
# Debug output with diagnostics
|
||||||
|
nff lint config.nft --debug
|
||||||
```
|
```
|
||||||
|
|
||||||
## Architecture
|
## Architecture
|
||||||
|
@ -69,12 +111,235 @@ graph TD
|
||||||
AST --> Formatter
|
AST --> Formatter
|
||||||
Formatter --> Output
|
Formatter --> Output
|
||||||
CST --> Formatter
|
CST --> Formatter
|
||||||
|
|
||||||
|
Input --> Diagnostics[Diagnostic System]
|
||||||
|
Diagnostics --> LexAnalyzer[Lexical Analyzer]
|
||||||
|
Diagnostics --> SyntaxAnalyzer[Syntax Analyzer]
|
||||||
|
Diagnostics --> StyleAnalyzer[Style Analyzer]
|
||||||
|
Diagnostics --> SemanticAnalyzer[Semantic Analyzer]
|
||||||
|
|
||||||
|
LexAnalyzer --> DiagOutput[JSON/Human Output]
|
||||||
|
SyntaxAnalyzer --> DiagOutput
|
||||||
|
StyleAnalyzer --> DiagOutput
|
||||||
|
SemanticAnalyzer --> DiagOutput
|
||||||
```
|
```
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
Recommended way of installing nff is to use Nix.
|
Recommended way of installing nff is to use Nix.
|
||||||
|
|
||||||
|
### Editor Integration
|
||||||
|
|
||||||
|
#### Neovim Setup
|
||||||
|
|
||||||
|
nff can be integrated into Neovim as a diagnostics source for nftables files.
|
||||||
|
Here are several setup approaches:
|
||||||
|
|
||||||
|
##### Option 2: Using none-ls
|
||||||
|
|
||||||
|
```lua
|
||||||
|
local null_ls = require("null-ls")
|
||||||
|
|
||||||
|
null_ls.setup({
|
||||||
|
sources = {
|
||||||
|
-- nftables diagnostics
|
||||||
|
null_ls.builtins.diagnostics.nff.with({
|
||||||
|
command = "nff",
|
||||||
|
args = { "lint", "$FILENAME", "--json" },
|
||||||
|
format = "json",
|
||||||
|
check_exit_code = false,
|
||||||
|
filetypes = { "nftables" },
|
||||||
|
}),
|
||||||
|
|
||||||
|
-- nftables formatting
|
||||||
|
null_ls.builtins.formatting.nff.with({
|
||||||
|
command = "nff",
|
||||||
|
args = { "format", "$FILENAME", "--stdout" },
|
||||||
|
filetypes = { "nftables" },
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
##### Option 2: Using nvim-lint (recommended)
|
||||||
|
|
||||||
|
```lua
|
||||||
|
-- ~/.config/nvim/lua/config/lint.lua
|
||||||
|
require('lint').linters.nff = {
|
||||||
|
cmd = 'nff',
|
||||||
|
stdin = false,
|
||||||
|
args = { 'lint', '%s', '--json' },
|
||||||
|
stream = 'stdout',
|
||||||
|
ignore_exitcode = true,
|
||||||
|
parser = function(output)
|
||||||
|
local diagnostics = {}
|
||||||
|
local ok, decoded = pcall(vim.fn.json_decode, output)
|
||||||
|
|
||||||
|
if not ok or not decoded.diagnostics then
|
||||||
|
return diagnostics
|
||||||
|
end
|
||||||
|
|
||||||
|
for _, diagnostic in ipairs(decoded.diagnostics) do
|
||||||
|
table.insert(diagnostics, {
|
||||||
|
lnum = diagnostic.range.start.line,
|
||||||
|
col = diagnostic.range.start.character,
|
||||||
|
severity = diagnostic.severity == "Error" and vim.diagnostic.severity.ERROR or vim.diagnostic.severity.WARN,
|
||||||
|
message = diagnostic.message,
|
||||||
|
source = "nff",
|
||||||
|
code = diagnostic.code,
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
return diagnostics
|
||||||
|
end,
|
||||||
|
}
|
||||||
|
|
||||||
|
-- Setup linting for nftables files
|
||||||
|
vim.api.nvim_create_autocmd({ "BufEnter", "BufWritePost" }, {
|
||||||
|
pattern = "*.nft",
|
||||||
|
callback = function()
|
||||||
|
require("lint").try_lint("nff")
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
##### Option 3: Custom Lua Function
|
||||||
|
|
||||||
|
For a simple custom solution:
|
||||||
|
|
||||||
|
```lua
|
||||||
|
-- ~/.config/nvim/lua/nff.lua
|
||||||
|
local M = {}
|
||||||
|
|
||||||
|
function M.lint_nftables()
|
||||||
|
local filename = vim.fn.expand('%:p')
|
||||||
|
if vim.bo.filetype ~= 'nftables' then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local cmd = { 'nff', 'lint', filename, '--json' }
|
||||||
|
|
||||||
|
vim.fn.jobstart(cmd, {
|
||||||
|
stdout_buffered = true,
|
||||||
|
on_stdout = function(_, data)
|
||||||
|
if data then
|
||||||
|
local output = table.concat(data, '\n')
|
||||||
|
local ok, result = pcall(vim.fn.json_decode, output)
|
||||||
|
|
||||||
|
if ok and result.diagnostics then
|
||||||
|
local diagnostics = {}
|
||||||
|
for _, diag in ipairs(result.diagnostics) do
|
||||||
|
table.insert(diagnostics, {
|
||||||
|
lnum = diag.range.start.line,
|
||||||
|
col = diag.range.start.character,
|
||||||
|
severity = diag.severity == "Error" and vim.diagnostic.severity.ERROR or vim.diagnostic.severity.WARN,
|
||||||
|
message = diag.message,
|
||||||
|
source = "nff",
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
vim.diagnostic.set(vim.api.nvim_create_namespace('nff'), 0, diagnostics)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Auto-run on save
|
||||||
|
vim.api.nvim_create_autocmd("BufWritePost", {
|
||||||
|
pattern = "*.nft",
|
||||||
|
callback = M.lint_nftables,
|
||||||
|
})
|
||||||
|
|
||||||
|
return M
|
||||||
|
```
|
||||||
|
|
||||||
|
## Diagnostic Categories
|
||||||
|
|
||||||
|
nff provides comprehensive analysis across multiple categories:
|
||||||
|
|
||||||
|
### Syntax Errors
|
||||||
|
|
||||||
|
- Parse errors with precise location information
|
||||||
|
- Missing tokens (semicolons, braces, etc.)
|
||||||
|
- Unexpected tokens
|
||||||
|
- Unterminated strings
|
||||||
|
- Invalid numbers
|
||||||
|
|
||||||
|
### Semantic Validation
|
||||||
|
|
||||||
|
- Unknown table families (`inet`, `ip`, `ip6`, etc.)
|
||||||
|
- Invalid chain types and hooks
|
||||||
|
- Incorrect priority values
|
||||||
|
- Missing chain policies
|
||||||
|
- Duplicate table/chain names
|
||||||
|
- Invalid CIDR notation
|
||||||
|
- Invalid port ranges
|
||||||
|
|
||||||
|
### Style Warnings
|
||||||
|
|
||||||
|
- Missing shebang line
|
||||||
|
- Inconsistent indentation (mixed tabs/spaces)
|
||||||
|
- Trailing whitespace
|
||||||
|
- Lines exceeding maximum length (configurable)
|
||||||
|
- Excessive empty lines
|
||||||
|
- Preferred syntax alternatives
|
||||||
|
|
||||||
|
### Best Practices
|
||||||
|
|
||||||
|
- Chains without explicit policies
|
||||||
|
- Rules without actions
|
||||||
|
- Overly permissive rules
|
||||||
|
- Duplicate or conflicting rules
|
||||||
|
- Unused variables or sets
|
||||||
|
- Deprecated syntax usage
|
||||||
|
- Missing documentation
|
||||||
|
- Security risks
|
||||||
|
|
||||||
|
### Performance Hints
|
||||||
|
|
||||||
|
- Inefficient rule ordering
|
||||||
|
- Large sets without timeouts
|
||||||
|
- Missing counters where beneficial
|
||||||
|
|
||||||
|
## JSON Output Format
|
||||||
|
|
||||||
|
When using `--json`, nff outputs LSP-compatible diagnostics:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"diagnostics": [
|
||||||
|
{
|
||||||
|
"range": {
|
||||||
|
"start": { "line": 5, "character": 10 },
|
||||||
|
"end": { "line": 5, "character": 20 }
|
||||||
|
},
|
||||||
|
"severity": "Error",
|
||||||
|
"code": "NFT001",
|
||||||
|
"source": "nff",
|
||||||
|
"message": "Expected ';' after policy",
|
||||||
|
"related_information": [],
|
||||||
|
"code_actions": [],
|
||||||
|
"tags": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"file_path": "config.nft",
|
||||||
|
"source_text": "..."
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Diagnostic Codes
|
||||||
|
|
||||||
|
nff uses structured diagnostic codes for categorization:
|
||||||
|
|
||||||
|
- **NFT001-NFT099**: Syntax errors
|
||||||
|
- **NFT101-NFT199**: Semantic errors
|
||||||
|
- **NFT201-NFT299**: Style warnings
|
||||||
|
- **NFT301-NFT399**: Best practice recommendations
|
||||||
|
- **NFT401-NFT499**: Performance hints
|
||||||
|
- **NFT501-NFT599**: Formatting issues
|
||||||
|
- **NFT601-NFT699**: nftables-specific validations
|
||||||
|
|
||||||
## Development
|
## Development
|
||||||
|
|
||||||
### Testing
|
### Testing
|
||||||
|
@ -196,6 +461,88 @@ table inet protection {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Diagnostics Examples
|
||||||
|
|
||||||
|
### Error Detection
|
||||||
|
|
||||||
|
Input file with issues:
|
||||||
|
|
||||||
|
```nftables
|
||||||
|
table inet firewall {
|
||||||
|
chain input {
|
||||||
|
type filter hook input priority 100
|
||||||
|
tcp dport 22 accept
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Human-readable output:
|
||||||
|
|
||||||
|
```
|
||||||
|
Found 2 issues in config.nft:
|
||||||
|
config.nft:3:37: error: Expected ';' after policy [NFT001]
|
||||||
|
1: table inet firewall {
|
||||||
|
2: chain input {
|
||||||
|
→ 3: type filter hook input priority 100
|
||||||
|
4: tcp dport 22 accept
|
||||||
|
5: }
|
||||||
|
|
||||||
|
config.nft:3:1: warning: Filter chain should have an explicit policy [NFT301]
|
||||||
|
1: table inet firewall {
|
||||||
|
2: chain input {
|
||||||
|
→ 3: type filter hook input priority 100
|
||||||
|
4: tcp dport 22 accept
|
||||||
|
5: }
|
||||||
|
```
|
||||||
|
|
||||||
|
JSON output:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"diagnostics": [
|
||||||
|
{
|
||||||
|
"range": {
|
||||||
|
"start": { "line": 2, "character": 37 },
|
||||||
|
"end": { "line": 2, "character": 37 }
|
||||||
|
},
|
||||||
|
"severity": "Error",
|
||||||
|
"code": "NFT001",
|
||||||
|
"source": "nff",
|
||||||
|
"message": "Expected ';' after policy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"range": {
|
||||||
|
"start": { "line": 2, "character": 0 },
|
||||||
|
"end": { "line": 2, "character": 37 }
|
||||||
|
},
|
||||||
|
"severity": "Warning",
|
||||||
|
"code": "NFT301",
|
||||||
|
"source": "nff",
|
||||||
|
"message": "Filter chain should have an explicit policy"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"file_path": "config.nft",
|
||||||
|
"source_text": "..."
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Style Analysis
|
||||||
|
|
||||||
|
Input with style issues:
|
||||||
|
|
||||||
|
```nftables
|
||||||
|
table inet test{chain input{type filter hook input priority 0;policy drop;tcp dport 22 accept;}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Style warnings:
|
||||||
|
|
||||||
|
```
|
||||||
|
Found 3 issues in style.nft:
|
||||||
|
style.nft:1:1: warning: Consider adding a shebang line [NFT201]
|
||||||
|
style.nft:1:121: warning: Line too long (98 > 80 characters) [NFT205]
|
||||||
|
style.nft:1:16: warning: Missing space after '{' [NFT503]
|
||||||
|
```
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
### Code Style
|
### Code Style
|
||||||
|
@ -237,6 +584,17 @@ Below are the design goals of nff's architechture.
|
||||||
- **Memory efficiency**: Streaming token processing where possible
|
- **Memory efficiency**: Streaming token processing where possible
|
||||||
- **Grammar completeness**: Covers full nftables syntax specification
|
- **Grammar completeness**: Covers full nftables syntax specification
|
||||||
|
|
||||||
|
### Diagnostic Architecture
|
||||||
|
|
||||||
|
The diagnostic system uses a modular architecture with specialized analyzers:
|
||||||
|
|
||||||
|
- **Modular design**: Each analyzer focuses on specific concerns (lexical,
|
||||||
|
syntax, style, semantic)
|
||||||
|
- **Configurable analysis**: Enable/disable specific diagnostic categories
|
||||||
|
- **LSP compatibility**: JSON output follows Language Server Protocol standards
|
||||||
|
- **Performance optimized**: Concurrent analysis when possible
|
||||||
|
- **Extensible**: Easy to add new diagnostic rules and categories
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
nff is licensed under [MPL v2.0](LICENSE). See license file for more details on
|
nff is licensed under [MPL v2.0](LICENSE). See license file for more details on
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue