-
Notifications
You must be signed in to change notification settings - Fork 1
Feature/replace lyaml with custom impl #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,145 @@ | ||
| --============================================================================= | ||
| -- filewise/yaml_parser – Simple YAML parser for frontmatter | ||
| --============================================================================= | ||
|
|
||
| local M = {} | ||
|
|
||
| --- Trim leading and trailing whitespace from a string. | ||
| ---@param s string|nil | ||
| ---@return string|nil | ||
| local function trim(s) | ||
| if not s then return s end | ||
| return s:match('^%s*(.-)%s*$') | ||
| end | ||
|
|
||
| --- Remove a single layer of surrounding quotes from a string if present. | ||
| ---@param s string|nil | ||
| ---@return string|nil | ||
| local function unquote(s) | ||
| if not s then return s end | ||
| return s:match('^"(.-)"$') or s:match("^'(.-)'$") or s | ||
| end | ||
|
|
||
| --- Strip only the leading indentation from a string (keep trailing spaces intact). | ||
| ---@param s string | ||
| ---@return string | ||
| local function ltrim(s) | ||
| return (s:gsub('^%s+', '')) | ||
| end | ||
|
|
||
| --- Simple YAML parser for basic key-value frontmatter | ||
| --- Supports: | ||
| --- - simple key: value pairs | ||
| --- - inline lists: key: [a, b, c] | ||
| --- - dash lists: | ||
| --- key: | ||
| --- - a | ||
| --- - b | ||
| --- - block scalars using | or > | ||
| --- Notes/limitations (by design for frontmatter use-cases): | ||
| --- - keys are limited to [A-Za-z0-9_-] | ||
| --- - inline lists don't support commas inside quoted strings | ||
| --- - scalar values are returned as strings (no auto-typing) | ||
| ---@param yaml_text string|nil The YAML content to parse | ||
| ---@return table<string, string|string[]>|nil Parsed YAML as a table, or nil if invalid/empty | ||
| function M.parse(yaml_text) | ||
| if not yaml_text or yaml_text == "" then | ||
| return nil | ||
| end | ||
|
|
||
| local result = {} | ||
| local lines = {} | ||
| for l in yaml_text:gmatch('[^\r\n]+') do | ||
| table.insert(lines, l) | ||
| end | ||
|
|
||
| local i = 1 | ||
| while i <= #lines do | ||
| local raw = lines[i] | ||
| local line = trim(raw) | ||
| -- skip empty and comment lines | ||
| if line == '' or line:match('^#') then | ||
| i = i + 1 | ||
| else | ||
| local key, value = line:match('^([%w_%-]+)%s*:%s*(.*)$') | ||
| if key then | ||
| -- empty value -> might be a dash list or block following | ||
| if value == '' then | ||
| -- check for dash list on following lines | ||
| local items = {} | ||
| local j = i + 1 | ||
| while j <= #lines do | ||
| local nxt = lines[j] | ||
| if nxt:match('^%s*%-%s+') then | ||
| local item = nxt:match('^%s*%-%s+(.*)$') | ||
| item = trim(item) | ||
| item = unquote(item) | ||
| table.insert(items, item) | ||
| j = j + 1 | ||
| elseif nxt:match('^%s*$') then | ||
| j = j + 1 | ||
| else | ||
| break | ||
| end | ||
| end | ||
| if #items > 0 then | ||
| result[key] = items | ||
| i = j | ||
| else | ||
| -- nothing special; store empty string | ||
| result[key] = '' | ||
| i = i + 1 | ||
| end | ||
| else | ||
| -- inline list? e.g. [a, b, c] | ||
| local inline = value:match('^%[(.*)%]$') | ||
| if inline then | ||
| local items = {} | ||
| for part in inline:gmatch('[^,]+') do | ||
|
||
| local v = trim(part) | ||
| v = unquote(v) | ||
| table.insert(items, v) | ||
| end | ||
| result[key] = items | ||
| i = i + 1 | ||
| elseif value == '|' or value == '>' then | ||
| -- block scalar: collect following indented lines (start with whitespace) | ||
| local j = i + 1 | ||
| local buf = {} | ||
| while j <= #lines do | ||
| local nxt = lines[j] | ||
| if nxt:match('^%s+$') then | ||
| -- preserve blank line inside block scalar | ||
| table.insert(buf, '') | ||
| j = j + 1 | ||
| elseif nxt:match('^%s+') then | ||
| -- strip only the leading indentation for readability | ||
| table.insert(buf, ltrim(nxt)) | ||
| j = j + 1 | ||
| else | ||
| break | ||
| end | ||
| end | ||
| result[key] = table.concat(buf, '\n') | ||
| i = j | ||
| else | ||
| local v = trim(value) | ||
| v = unquote(v) | ||
| result[key] = v | ||
| i = i + 1 | ||
| end | ||
| end | ||
| else | ||
| -- not a key line; ignore | ||
| i = i + 1 | ||
| end | ||
| end | ||
| end | ||
|
|
||
| if next(result) == nil then | ||
| return nil | ||
| end | ||
| return result | ||
| end | ||
|
|
||
| return M | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The key pattern
[%w_%-]+allows hyphens anywhere in the key name, but YAML keys with leading/trailing hyphens or consecutive hyphens may cause parsing issues. Consider using a more restrictive pattern like[%w_]+[%w_%-]*[%w_]+or[%w_][%w_%-]*to ensure valid key names.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not sure about this one...