Skip to content

demo project: HTML resume builder#6

Merged
lyninx merged 1 commit intomainfrom
demo-project-resume
Feb 8, 2026
Merged

demo project: HTML resume builder#6
lyninx merged 1 commit intomainfrom
demo-project-resume

Conversation

@lyninx
Copy link
Owner

@lyninx lyninx commented Feb 8, 2026

No description provided.

Copilot AI review requested due to automatic review settings February 8, 2026 00:33
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds an HTML resume builder demo to the Lunary project, along with a new kernel helper to load raw file contents for embedding CSS/SVG assets in generated output.

Changes:

  • Added @kernel.load_raw for reading raw file contents from disk.
  • Introduced a complete resume demo (examples/resume) including Lunary source, CSS, icons, and generated outputs.
  • Expanded unit tests and updated README quickstart/build instructions.

Reviewed changes

Copilot reviewed 14 out of 22 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
lib/lunary.ex Adds @kernel.load_raw implementation for reading asset files.
test/unit/kernel_test.exs Adds test coverage for loading a raw fixture file.
test/unit/atom_test.exs Adds test ensuring atoms can contain underscores and numbers.
test/fixtures/raw.txt Adds fixture file used by load_raw test.
src/lunary_parser.yrl Removes commented-out grammar rules (cleanup).
examples/resume/resume.lun Adds Lunary resume builder demo script generating HTML.
examples/resume/style.css Adds demo stylesheet used by generated resume output.
examples/resume/icons/github.svg Adds icon asset loaded via load_raw.
examples/resume/icons/linkedin.svg Adds icon asset loaded via load_raw.
examples/resume/icons/globe.svg Adds icon asset (demo).
examples/resume/resume.html Adds generated HTML output for the demo.
examples/resume/resume.pdf Adds generated PDF output for the demo.
README.md Documents requirements, demo build instructions, and test command.
projects/resume/main.lun Removes old resume demo implementation.
html_builder.lun Removes old scratch/demo file.
example.lun Removes old scratch/demo file.
test/ideas.lun Updates scratch ideas file with additional notes/examples.
lib/main.ex Replaces old TODO block with a header/TODO section at top of file.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +443 to 453
root_path = opts[:path] || ""
{:string, _, file_path} = Enum.at(args, 0)
fullpath = Path.join(root_path, file_path)
case File.read(fullpath) do
{:ok, content} ->
{content, scope}
{:error, _} -> raise "File #{file_path} (#{fullpath}) not found"
end
_ ->
raise "Kernel function #{name} is not defined"
end
Copy link

Copilot AI Feb 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kernel.load_raw reads a file path provided by the Lunary program and joins it with opts[:path], but it doesn’t prevent .. path traversal. That allows reading files outside the intended root when running untrusted scripts. Consider expanding/canonicalizing both paths and rejecting any resolved path that is not within the expanded root directory (or otherwise explicitly documenting/guarding that load_raw is intentionally unrestricted).

Suggested change
root_path = opts[:path] || ""
{:string, _, file_path} = Enum.at(args, 0)
fullpath = Path.join(root_path, file_path)
case File.read(fullpath) do
{:ok, content} ->
{content, scope}
{:error, _} -> raise "File #{file_path} (#{fullpath}) not found"
end
_ ->
raise "Kernel function #{name} is not defined"
end
root_path = opts[:path]
{:string, _, file_path} = Enum.at(args, 0)
# Determine the full path to read, preventing traversal outside root_path if provided.
fullpath =
case root_path do
root when is_binary(root) and root != "" ->
base_dir = Path.expand(root)
expanded = Path.expand(Path.join(base_dir, file_path))
if expanded == base_dir or String.starts_with?(expanded, base_dir <> Path.sep()) do
expanded
else
raise "Access to file #{file_path} is outside of the allowed root directory"
end
_ ->
# No root configured; fall back to expanded file_path (current behavior, but canonicalized).
Path.expand(file_path)
end
case File.read(fullpath) do
{:ok, content} ->
{content, scope}
{:error, _} ->
raise "File #{file_path} (#{fullpath}) not found"
end
_ ->
raise "Kernel function #{name} is not defined"
end

Copilot uses AI. Check for mistakes.
Comment on lines +444 to +449
{:string, _, file_path} = Enum.at(args, 0)
fullpath = Path.join(root_path, file_path)
case File.read(fullpath) do
{:ok, content} ->
{content, scope}
{:error, _} -> raise "File #{file_path} (#{fullpath}) not found"
Copy link

Copilot AI Feb 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

{:string, _, file_path} = Enum.at(args, 0) will raise a MatchError (or crash on nil) if load_raw is called with a non-string argument or with no args. Prefer validating arity/type and raising a clear runtime error like "load_raw expects a string path".

Suggested change
{:string, _, file_path} = Enum.at(args, 0)
fullpath = Path.join(root_path, file_path)
case File.read(fullpath) do
{:ok, content} ->
{content, scope}
{:error, _} -> raise "File #{file_path} (#{fullpath}) not found"
arg0 = Enum.at(args, 0)
case arg0 do
{:string, _, file_path} when is_binary(file_path) ->
fullpath = Path.join(root_path, file_path)
case File.read(fullpath) do
{:ok, content} ->
{content, scope}
{:error, _} ->
raise "File #{file_path} (#{fullpath}) not found"
end
nil ->
raise ArgumentError, "load_raw expects a string path, got no arguments"
other ->
raise ArgumentError, "load_raw expects a string path, got: #{inspect(other)}"

Copilot uses AI. Check for mistakes.
Comment on lines +12 to +16
test "can load raw files" do
assert "
res = @kernel.load_raw(\"test/fixtures/raw.txt\")
res
" |> Lunary.Main.eval() == "this is a raw file...\n"
Copy link

Copilot AI Feb 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test only covers the happy path of @kernel.load_raw. Since the implementation also raises on missing/unreadable files (and can fail on non-string args), add an assertion that the appropriate error is raised for those cases to cover the failure behavior.

Copilot uses AI. Check for mistakes.
Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc)
and published on [HexDocs](https://hexdocs.pm). Once published, the docs can
be found at <https://hexdocs.pm/lunary>.
./lunary examples/resume/resume.lun > examples/resume/resume.html | weasyprint - examples/resume/resume.pdf --media-type print --encoding utf-8
Copy link

Copilot AI Feb 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The shell command here won’t do what it looks like: > examples/resume/resume.html | weasyprint - ... redirects stdout to the file, so the pipe receives nothing. Split into two commands, or use tee to both write the HTML file and pipe it into weasyprint.

Suggested change
./lunary examples/resume/resume.lun > examples/resume/resume.html | weasyprint - examples/resume/resume.pdf --media-type print --encoding utf-8
./lunary examples/resume/resume.lun | tee examples/resume/resume.html | weasyprint - examples/resume/resume.pdf --media-type print --encoding utf-8

Copilot uses AI. Check for mistakes.
Comment on lines +1 to +6
<!DOCTYPE html>
<html lang="en">
<meta charset="UTF-8">
<head>
<title>Lunary Resume!</title>
<style>@font-face {
Copy link

Copilot AI Feb 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This HTML file appears to be generated output of the demo. Committing generated artifacts makes PRs noisy and increases maintenance burden; consider excluding it via .gitignore and regenerating it during demo/build steps instead.

Copilot uses AI. Check for mistakes.
@lyninx lyninx merged commit d630bd2 into main Feb 8, 2026
1 check passed
@lyninx lyninx deleted the demo-project-resume branch February 8, 2026 00:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants