defmodule Mix.Tasks.Rustq.Templates.Check do @moduledoc """ Verifies that RustQ template fixtures still compile against the generated Rust support code. """ use Mix.Task alias RustQ.Rust.AST.Builder, as: A alias RustQ.Rustler.{Atom, Nif, Opts, Resource, TaggedEnum, Term} @shortdoc "Checks RustQ's Rustler helper templates" @fixture Path.join(["fixtures", "rustler_template_check"]) @impl Mix.Task def run(_args) do fixture = fixture_path() manifest = Path.join(fixture, "Cargo.toml") fixture |> Path.join("src/generated.rs") |> File.write!(generated_source()) cargo(["fmt", "--manifest-path", manifest, "--", "--check"]) cargo(["check", "--manifest-path", manifest]) cargo([ "clippy", "--manifest-path", manifest, "--", "-D", "warnings" ]) end defp generated_source do RustQ.render!("__rq_items!();", "generated.rs", preamble: "// This file is generated by mix rustq.templates.check. Do not edit by hand.\n\n", splice: [items: generated_items()] ) end defp generated_items do List.flatten([ Resource.items(:Document, fields: [nodes: {:vec, :Node}]), Resource.type_alias(:Document), Resource.decoder(:Document), Term.helpers(type_key: "atoms::r#type()"), Atom.decoder(:decode_node_kind, returns: :NodeKind, cases: [text: "NodeKind::Text", space: "NodeKind::Space"] ), Atom.dispatch(:dispatch_node, args: [kind: :Atom], on: "kind", cases: [text: "decode_text()", space: "decode_space()"] ), Opts.helpers(), Term.decoder(:ProgramInput, fields: [body: [type: {:vec, "Term<'a>"}, key: "atoms::body()", required: true]] ), Term.decoder(:IfStatementInput, fields: [ test: [type: "Term<'a>", key: "atoms::test()", required: true], consequent: [type: "Term<'a>", key: "atoms::consequent()", required: true], alternate: [type: {:option, "Term<'a>"}, key: "atoms::alternate()"] ] ), Nif.struct(:ExText, "Folio.Content.Text", attrs: ["allow(dead_code)"], fields: [text: :String, size: {:option, :String}] ), Nif.struct(:ExSpace, "Folio.Content.Space", attrs: ["allow(dead_code)"], fields: [] ), TaggedEnum.items(:ExContent, attrs: [A.allow_attr(:dead_code)], tag: A.call(:atom_struct), variants: [ Text: [type: :ExText, module: "Elixir.Folio.Content.Text"], Space: [type: :ExSpace, module: "Elixir.Folio.Content.Space"] ] ), Atom.cached([:ok, {:node_changes, "nodeChanges"}]), Term.builders(), Nif.raw_term_builders() ]) end defp fixture_path do :rustq |> :code.priv_dir() |> List.to_string() |> Path.join(@fixture) end defp cargo(args) do {_, status} = System.cmd("cargo", args, into: IO.stream(), stderr_to_stdout: true) if status != 0 do Mix.raise("cargo #{Enum.join(args, " ")} failed") end end end