Initial vibecoded proof of concept
This commit is contained in:
parent
74812459af
commit
461318a656
61 changed files with 13306 additions and 0 deletions
192
lua/notex/parser/yaml.lua
Normal file
192
lua/notex/parser/yaml.lua
Normal file
|
@ -0,0 +1,192 @@
|
|||
-- YAML header parsing module
|
||||
local M = {}
|
||||
|
||||
local lyaml = require('lyaml')
|
||||
local utils = require('notex.utils')
|
||||
|
||||
-- Extract YAML header from markdown content
|
||||
function M.extract_yaml_header(content)
|
||||
if not content or content == "" then
|
||||
return nil, "Empty content provided"
|
||||
end
|
||||
|
||||
-- Check for YAML header delimiters
|
||||
local start_pos = content:find("^%s*%-%-%-%s*\n")
|
||||
if not start_pos then
|
||||
return nil, "No YAML header found"
|
||||
end
|
||||
|
||||
local end_pos = content:find("\n%s*%-%-%-%s*\n", start_pos + 4)
|
||||
if not end_pos then
|
||||
return nil, "Unclosed YAML header"
|
||||
end
|
||||
|
||||
-- Extract YAML content
|
||||
local yaml_content = content:sub(start_pos + 4, end_pos - 1)
|
||||
|
||||
return yaml_content, nil
|
||||
end
|
||||
|
||||
-- Parse YAML header content
|
||||
function M.parse_yaml(yaml_content)
|
||||
if not yaml_content or yaml_content == "" then
|
||||
return {}, nil
|
||||
end
|
||||
|
||||
local ok, data = pcall(lyaml.load, yaml_content)
|
||||
|
||||
if not ok then
|
||||
return nil, "YAML parsing failed: " .. tostring(data)
|
||||
end
|
||||
|
||||
if type(data) ~= "table" then
|
||||
return {}, nil
|
||||
end
|
||||
|
||||
return data, nil
|
||||
end
|
||||
|
||||
-- Parse markdown file and extract YAML header
|
||||
function M.parse_markdown_file(file_path)
|
||||
-- Validate file exists
|
||||
if not utils.file_exists(file_path) then
|
||||
return nil, "File not found: " .. file_path
|
||||
end
|
||||
|
||||
-- Validate UTF-8 encoding
|
||||
if not utils.is_utf8(file_path) then
|
||||
return nil, "File is not valid UTF-8: " .. file_path
|
||||
end
|
||||
|
||||
-- Read file content
|
||||
local content, err = utils.read_file(file_path)
|
||||
if not content then
|
||||
return nil, err
|
||||
end
|
||||
|
||||
-- Extract YAML header
|
||||
local yaml_content, extract_err = M.extract_yaml_header(content)
|
||||
if not yaml_content then
|
||||
return nil, extract_err
|
||||
end
|
||||
|
||||
-- Parse YAML
|
||||
local yaml_data, parse_err = M.parse_yaml(yaml_content)
|
||||
if not yaml_data then
|
||||
return nil, parse_err
|
||||
end
|
||||
|
||||
return yaml_data, nil
|
||||
end
|
||||
|
||||
-- Flatten YAML data into key-value pairs
|
||||
function M.flatten_yaml(data, prefix)
|
||||
local flattened = {}
|
||||
prefix = prefix or ""
|
||||
|
||||
for key, value in pairs(data) do
|
||||
local full_key = prefix .. (prefix ~= "" and "." or "") .. key
|
||||
|
||||
if type(value) == "table" then
|
||||
-- Recursively flatten nested tables
|
||||
local nested = M.flatten_yaml(value, full_key)
|
||||
for nested_key, nested_value in pairs(nested) do
|
||||
flattened[nested_key] = nested_value
|
||||
end
|
||||
else
|
||||
flattened[full_key] = value
|
||||
end
|
||||
end
|
||||
|
||||
return flattened
|
||||
end
|
||||
|
||||
-- Validate YAML structure
|
||||
function M.validate_yaml(yaml_data)
|
||||
local errors = {}
|
||||
|
||||
if type(yaml_data) ~= "table" then
|
||||
table.insert(errors, "YAML data must be a table")
|
||||
return errors
|
||||
end
|
||||
|
||||
-- Check for required fields (if any)
|
||||
local required_fields = {} -- Add required fields as needed
|
||||
|
||||
for _, field in ipairs(required_fields) do
|
||||
if yaml_data[field] == nil then
|
||||
table.insert(errors, string.format("Required field '%s' is missing", field))
|
||||
end
|
||||
end
|
||||
|
||||
-- Validate field types
|
||||
local field_types = {
|
||||
-- Define expected types for specific fields
|
||||
}
|
||||
|
||||
for field, expected_type in pairs(field_types) do
|
||||
if yaml_data[field] ~= nil and type(yaml_data[field]) ~= expected_type then
|
||||
table.insert(errors, string.format("Field '%s' should be %s, got %s",
|
||||
field, expected_type, type(yaml_data[field])))
|
||||
end
|
||||
end
|
||||
|
||||
return errors
|
||||
end
|
||||
|
||||
-- Detect and convert property types
|
||||
function M.detect_property_type(value)
|
||||
local value_type = type(value)
|
||||
|
||||
if value_type == "boolean" then
|
||||
return "boolean", value
|
||||
elseif value_type == "number" then
|
||||
return "number", value
|
||||
elseif value_type == "string" then
|
||||
-- Check for ISO 8601 date format
|
||||
if value:match("^%d%d%d%d%-%d%d%-%d%d$") or
|
||||
value:match("^%d%d%d%d%-%d%d%-%d%dT%d%d:%d%d:%d%dZ?$") then
|
||||
return "date", value
|
||||
end
|
||||
|
||||
-- Check for numeric strings
|
||||
local num = tonumber(value)
|
||||
if num and value:match("^%-?%d+%.?%d*$") then
|
||||
return "number", num
|
||||
end
|
||||
|
||||
-- Check for boolean strings
|
||||
local lower = value:lower()
|
||||
if lower == "true" then
|
||||
return "boolean", true
|
||||
elseif lower == "false" then
|
||||
return "boolean", false
|
||||
end
|
||||
|
||||
return "string", value
|
||||
elseif value_type == "table" then
|
||||
return "array", vim.json.encode(value)
|
||||
else
|
||||
return "string", tostring(value)
|
||||
end
|
||||
end
|
||||
|
||||
-- Process YAML data into property format
|
||||
function M.process_properties(yaml_data)
|
||||
local flattened = M.flatten_yaml(yaml_data)
|
||||
local properties = {}
|
||||
|
||||
for key, value in pairs(flattened) do
|
||||
local prop_type, processed_value = M.detect_property_type(value)
|
||||
|
||||
table.insert(properties, {
|
||||
key = key,
|
||||
value = processed_value,
|
||||
value_type = prop_type
|
||||
})
|
||||
end
|
||||
|
||||
return properties
|
||||
end
|
||||
|
||||
return M
|
Loading…
Add table
Add a link
Reference in a new issue