WIP: allow using nff as a diagnostics source #1
					 1 changed files with 366 additions and 8 deletions
				
			
		docs: update README with new features
				commit
				
					
					
						92735f3eee
					
				
			
		
							
								
								
									
										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 | ||||
| - **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 | ||||
| 
 | ||||
| ### Formatting | ||||
| 
 | ||||
| ```bash | ||||
| # Basic formatting | ||||
| nff -f /etc/nftables.conf | ||||
| # Format a specific file (in place) | ||||
| nff format /etc/nftables.conf | ||||
| 
 | ||||
| # Format all .nft files in current directory (in place) | ||||
| nff format | ||||
| 
 | ||||
| # 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) | ||||
| nff -f config.nft --optimize | ||||
| nff format config.nft --optimize | ||||
| 
 | ||||
| # Output to file | ||||
| nff -f config.nft -o formatted.nft | ||||
| # Output to stdout instead of modifying files | ||||
| nff format config.nft --stdout | ||||
| 
 | ||||
| # Syntax validation only | ||||
| nff -f config.nft --check | ||||
| nff format config.nft --check | ||||
| 
 | ||||
| # 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 | ||||
|  | @ -69,12 +111,235 @@ graph TD | |||
|     AST --> Formatter | ||||
|     Formatter --> Output | ||||
|     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 | ||||
| 
 | ||||
| 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 | ||||
| 
 | ||||
| ### 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 | ||||
| 
 | ||||
| ### Code Style | ||||
|  | @ -237,6 +584,17 @@ Below are the design goals of nff's architechture. | |||
| - **Memory efficiency**: Streaming token processing where possible | ||||
| - **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 | ||||
| 
 | ||||
| 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