Add lua meta to be used with luals and dumped via cook -m

This commit is contained in:
2025-12-19 13:37:15 +01:00
parent 8dd212fc71
commit 2fa99ec3a2
3 changed files with 290 additions and 0 deletions

16
main.go
View File

@@ -4,6 +4,7 @@ import (
_ "embed" _ "embed"
"errors" "errors"
"os" "os"
"path/filepath"
"sort" "sort"
"sync" "sync"
"sync/atomic" "sync/atomic"
@@ -64,6 +65,20 @@ Features:
CreateExampleConfig() CreateExampleConfig()
return return
} }
metaFlag, _ := cmd.Flags().GetBool("meta")
if metaFlag {
cwd, err := os.Getwd()
if err != nil {
mainLogger.Error("Failed to get current directory: %v", err)
os.Exit(1)
}
metaPath := filepath.Join(cwd, "meta.lua")
if err := processor.GenerateMetaFile(metaPath); err != nil {
mainLogger.Error("Failed to generate meta.lua: %v", err)
os.Exit(1)
}
return
}
if len(args) == 0 { if len(args) == 0 {
cmd.Usage() cmd.Usage()
return return
@@ -81,6 +96,7 @@ Features:
rootCmd.Flags().Bool("json", false, "Enable JSON mode for processing JSON files") rootCmd.Flags().Bool("json", false, "Enable JSON mode for processing JSON files")
rootCmd.Flags().BoolP("conv", "c", false, "Convert YAML files to TOML format") rootCmd.Flags().BoolP("conv", "c", false, "Convert YAML files to TOML format")
rootCmd.Flags().BoolP("example", "e", false, "Generate example_cook.toml and exit") rootCmd.Flags().BoolP("example", "e", false, "Generate example_cook.toml and exit")
rootCmd.Flags().BoolP("meta", "m", false, "Generate meta.lua file for LuaLS autocomplete and exit")
// Set up examples in the help text // Set up examples in the help text
rootCmd.SetUsageTemplate(`Usage:{{if .Runnable}} rootCmd.SetUsageTemplate(`Usage:{{if .Runnable}}

29
processor/meta.go Normal file
View File

@@ -0,0 +1,29 @@
package processor
import (
_ "embed"
"fmt"
"os"
logger "git.site.quack-lab.dev/dave/cylogger"
)
//go:embed meta.lua
var metaFileContent string
var metaLogger = logger.Default.WithPrefix("meta")
// GenerateMetaFile generates meta.lua with function signatures for LuaLS autocomplete
func GenerateMetaFile(outputPath string) error {
metaLogger.Info("Generating meta.lua file for LuaLS autocomplete")
// Write the embedded meta file
err := os.WriteFile(outputPath, []byte(metaFileContent), 0644)
if err != nil {
metaLogger.Error("Failed to write meta.lua: %v", err)
return fmt.Errorf("failed to write meta.lua: %w", err)
}
metaLogger.Info("Successfully generated meta.lua at %q", outputPath)
return nil
}

245
processor/meta.lua Normal file
View File

@@ -0,0 +1,245 @@
---@meta
---@class ParserOptions
---@field delimiter string? The field delimiter (default: ",").
---@field hasheader boolean? If true, first non-comment row is treated as headers (default: false).
---@field hascomments boolean? If true, lines starting with '#' are skipped (default: false).
---@class XMLElement
---@field _tag string The XML tag name
---@field _attr {[string]: string}? XML attributes as key-value pairs
---@field _text string? Text content of the element
---@field _children XMLElement[]? Child elements
---@class JSONNode
---@field [string] string | number | boolean | nil | JSONNode | JSONArray JSON object fields
---@alias JSONArray (string | number | boolean | nil | JSONNode)[]
---@class CSVRow
---@field [integer] string Numeric indices for field access
---@field Headers string[]? Header row if hasheader was true
--- Returns the minimum of two numbers
---@param a number First number
---@param b number Second number
---@return number #Minimum value
function min(a, b) end
--- Returns the maximum of two numbers
---@param a number First number
---@param b number Second number
---@return number #Maximum value
function max(a, b) end
--- Rounds a number to n decimal places
---@param x number Number to round
---@param n number? Number of decimal places (default: 0)
---@return number #Rounded number
function round(x, n) end
--- Returns the floor of a number
---@param x number Number to floor
---@return number #Floored number
function floor(x) end
--- Returns the ceiling of a number
---@param x number Number to ceil
---@return number #Ceiled number
function ceil(x) end
--- Converts string to uppercase
---@param s string String to convert
---@return string #Uppercase string
function upper(s) end
--- Converts string to lowercase
---@param s string String to convert
---@return string #Lowercase string
function lower(s) end
--- Formats a string using Lua string.format
---@param s string Format string
---@param ... any Values to format
---@return string #Formatted string
function format(s, ...) end
--- Removes leading and trailing whitespace from string
---@param s string String to trim
---@return string #Trimmed string
function trim(s) end
--- Splits a string by separator
---@param inputstr string String to split
---@param sep string? Separator pattern (default: whitespace)
---@return string[] #Array of string parts
function strsplit(inputstr, sep) end
--- Prints table structure recursively
---@param table {[any]: any} Table to dump
---@param depth number? Current depth (default: 0)
function dump(table, depth) end
--- Validates options against a set of valid option keys.
---@param options ParserOptions? The options table to validate
function areOptionsValid(options) end
--- Parses CSV text into rows and fields using a minimal RFC 4180 state machine.
--- Requirements/assumptions:<br>
--- Input is a single string containing the entire CSV content.<br>
--- Field separators are specified by delimiter option (default: comma).<br>
--- Newlines between rows may be "\n" or "\r\n". "\r\n" is treated as one line break.<br>
--- Fields may be quoted with double quotes (").<br>
--- Inside quoted fields, doubled quotes ("") represent a literal quote character.<br>
--- No backslash escaping is supported (not part of RFC 4180).<br>
--- Newlines inside quoted fields are preserved as part of the field.<br>
--- Leading/trailing spaces are preserved; no trimming is performed.<br>
--- Empty fields and empty rows are preserved.<br>
--- The final row is emitted even if the text does not end with a newline.<br>
--- Lines starting with '#' (after optional leading whitespace) are treated as comments and skipped if hascomments is true.<br>
---@param csv string The CSV text to parse.
---@param options ParserOptions? Options for the parser
---@return CSVRow[] #A table (array) of rows; each row is a table with numeric indices and optionally header-named keys.
function fromCSV(csv, options) end
--- Converts a table of rows back to CSV text format (RFC 4180 compliant).<br>
--- Requirements:<br>
--- Input is a table (array) of rows, where each row is a table (array) of field values.<br>
--- Field values are converted to strings using tostring().<br>
--- Fields are quoted if they contain the delimiter, newlines, or double quotes.<br>
--- Double quotes inside quoted fields are doubled ("").<br>
--- Fields are joined with the specified delimiter; rows are joined with newlines.<br>
--- If includeHeaders is true and rows have a Headers field, headers are included as the first row.<br>
---@param rows CSVRow[] Array of rows, where each row is an array of field values.
---@param options ParserOptions? Options for the parser
---@return string #CSV-formatted text
function toCSV(rows, options) end
--- Converts string to number, returns 0 if invalid
---@param str string String to convert
---@return number #Numeric value or 0
function num(str) end
--- Converts number to string
---@param num number Number to convert
---@return string #String representation
function str(num) end
--- Checks if string is numeric
---@param str string String to check
---@return boolean #True if string is numeric
function is_number(str) end
--- Checks if table is a sequential array (1-indexed with no gaps)
---@param t {[integer]: any} Table to check
---@return boolean #True if table is an array
function isArray(t) end
--- Find all elements with a specific tag name (recursive search)
---@param root XMLElement The root XML element (with _tag, _attr, _children fields)
---@param tagName string The tag name to search for
---@return XMLElement[] #Array of matching elements
function findElements(root, tagName) end
--- Visit all elements recursively and call a function on each
---@param root XMLElement The root XML element
---@param callback fun(element: XMLElement, depth: number, path: string) Function to call with each element
function visitElements(root, callback) end
--- Get numeric value from XML element attribute
---@param element XMLElement XML element with _attr field
---@param attrName string Attribute name
---@return number? #The numeric value or nil if not found/not numeric
function getNumAttr(element, attrName) end
--- Set numeric value to XML element attribute
---@param element XMLElement XML element with _attr field
---@param attrName string Attribute name
---@param value number Numeric value to set
function setNumAttr(element, attrName, value) end
--- Modify numeric attribute by applying a function
---@param element XMLElement XML element
---@param attrName string Attribute name
---@param func fun(currentValue: number): number Function that takes current value and returns new value
---@return boolean #True if modification was made
function modifyNumAttr(element, attrName, func) end
--- Find all elements matching a predicate function
---@param root XMLElement The root XML element
---@param predicate fun(element: XMLElement): boolean Function that takes element and returns true/false
---@return XMLElement[] #Array of matching elements
function filterElements(root, predicate) end
--- Get text content of an element
---@param element XMLElement XML element
---@return string? #The text content or nil
function getText(element) end
--- Set text content of an element
---@param element XMLElement XML element
---@param text string Text content to set
function setText(element, text) end
--- Check if element has an attribute
---@param element XMLElement XML element
---@param attrName string Attribute name
---@return boolean #True if attribute exists
function hasAttr(element, attrName) end
--- Get attribute value as string
---@param element XMLElement XML element
---@param attrName string Attribute name
---@return string? #The attribute value or nil
function getAttr(element, attrName) end
--- Set attribute value
---@param element XMLElement XML element
---@param attrName string Attribute name
---@param value string | number | boolean Value to set (will be converted to string)
function setAttr(element, attrName, value) end
--- Find first element with a specific tag name (searches direct children only)
---@param parent XMLElement The parent XML element
---@param tagName string The tag name to search for
---@return XMLElement? #The first matching element or nil
function findFirstElement(parent, tagName) end
--- Add a child element to a parent
---@param parent XMLElement The parent XML element
---@param child XMLElement The child element to add
function addChild(parent, child) end
--- Remove all children with a specific tag name
---@param parent XMLElement The parent XML element
---@param tagName string The tag name to remove
---@return number #Count of removed children
function removeChildren(parent, tagName) end
--- Get all direct children with a specific tag name
---@param parent XMLElement The parent XML element
---@param tagName string The tag name to search for
---@return XMLElement[] #Array of matching children
function getChildren(parent, tagName) end
--- Count children with a specific tag name
---@param parent XMLElement The parent XML element
---@param tagName string The tag name to count
---@return number #Count of matching children
function countChildren(parent, tagName) end
--- Recursively visit all values in a JSON structure
---@param data JSONNode | JSONArray JSON data (nested tables)
---@param callback fun(value: string | number | boolean | nil | JSONNode | JSONArray, key: string?, parent: JSONNode?): nil Function called with (value, key, parent)
function visitJSON(data, callback) end
--- Find all values in JSON matching a predicate
---@param data JSONNode | JSONArray JSON data
---@param predicate fun(value: string | number | boolean | nil | JSONNode | JSONArray, key: string?, parent: JSONNode?): boolean Function that takes (value, key, parent) and returns true/false
---@return (string | number | boolean | nil | JSONNode | JSONArray)[] #Array of matching values
function findInJSON(data, predicate) end
--- Modify all numeric values in JSON matching a condition
---@param data JSONNode | JSONArray JSON data
---@param predicate fun(value: string | number | boolean | nil | JSONNode | JSONArray, key: string?, parent: JSONNode?): boolean Function that takes (value, key, parent) and returns true/false
---@param modifier fun(currentValue: number): number Function that takes current value and returns new value
function modifyJSONNumbers(data, predicate, modifier) end