src/lightspeed@tooling@generator.erl

-module(lightspeed@tooling@generator).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/lightspeed/tooling/generator.gleam").
-export([parse/1, parse_error_label/1, generate_auth/1, new/1, generate_json/2, generate_html/2, generate_live/2, scaffold/1, app_name/1, module_name/1, files/1, features/1, has_file/2, file_content/2, fixture_signature/1, boot_ci_contract/1, production_contract/1, resource_contract/2, auth_contract/1, fixture_snapshots/0, snapshot_signature/0]).
-export_type([command/0, parse_error/0, file/0, project/0]).

-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.

?MODULEDOC(" Deterministic project and resource scaffold generator for M25.\n").

-type command() :: {new, binary()} |
    {gen_live, binary(), binary()} |
    {gen_html, binary(), binary()} |
    {gen_json, binary(), binary()} |
    {gen_auth, binary()}.

-type parse_error() :: {missing_arguments, binary()} |
    {unsupported_command, binary()}.

-type file() :: {file, binary(), binary()}.

-opaque project() :: {project, binary(), binary(), list(file()), list(binary())}.

-file("src/lightspeed/tooling/generator.gleam", 49).
?DOC(
    " Parse CLI-like command args.\n"
    "\n"
    " Supported shapes:\n"
    "\n"
    " - `[\"new\", \"<app>\"]`\n"
    " - `[\"gen.live\", \"<app>\", \"<resource>\"]`\n"
    " - `[\"gen.html\", \"<app>\", \"<resource>\"]`\n"
    " - `[\"gen.json\", \"<app>\", \"<resource>\"]`\n"
    " - `[\"gen.auth\", \"<app>\"]`\n"
).
-spec parse(list(binary())) -> {ok, command()} | {error, parse_error()}.
parse(Args) ->
    case Args of
        [<<"new"/utf8>>, App_name] ->
            {ok, {new, App_name}};

        [<<"gen.live"/utf8>>, App_name@1, Resource] ->
            {ok, {gen_live, App_name@1, Resource}};

        [<<"gen.html"/utf8>>, App_name@2, Resource@1] ->
            {ok, {gen_html, App_name@2, Resource@1}};

        [<<"gen.json"/utf8>>, App_name@3, Resource@2] ->
            {ok, {gen_json, App_name@3, Resource@2}};

        [<<"gen.auth"/utf8>>, App_name@4] ->
            {ok, {gen_auth, App_name@4}};

        [<<"new"/utf8>>] ->
            {error, {missing_arguments, <<"new"/utf8>>}};

        [<<"gen.live"/utf8>>, _ | _] ->
            {error, {missing_arguments, <<"gen.live"/utf8>>}};

        [<<"gen.html"/utf8>>, _ | _] ->
            {error, {missing_arguments, <<"gen.html"/utf8>>}};

        [<<"gen.json"/utf8>>, _ | _] ->
            {error, {missing_arguments, <<"gen.json"/utf8>>}};

        [<<"gen.auth"/utf8>>] ->
            {error, {missing_arguments, <<"gen.auth"/utf8>>}};

        [] ->
            {error, {missing_arguments, <<"command"/utf8>>}};

        [Command | _] ->
            {error, {unsupported_command, Command}}
    end.

-file("src/lightspeed/tooling/generator.gleam", 70).
?DOC(" Stable parse-error label for fixtures.\n").
-spec parse_error_label(parse_error()) -> binary().
parse_error_label(Error) ->
    case Error of
        {missing_arguments, Command} ->
            <<"missing_arguments:"/utf8, Command/binary>>;

        {unsupported_command, Command@1} ->
            <<"unsupported_command:"/utf8, Command@1/binary>>
    end.

-file("src/lightspeed/tooling/generator.gleam", 686).
-spec contains(list(binary()), binary()) -> boolean().
contains(Values, Needle) ->
    case Values of
        [] ->
            false;

        [Value | Rest] ->
            case Value =:= Needle of
                true ->
                    true;

                false ->
                    contains(Rest, Needle)
            end
    end.

-file("src/lightspeed/tooling/generator.gleam", 636).
-spec add_feature(project(), binary()) -> project().
add_feature(Project, Feature) ->
    case contains(erlang:element(5, Project), Feature) of
        true ->
            Project;

        false ->
            {project,
                erlang:element(2, Project),
                erlang:element(3, Project),
                erlang:element(4, Project),
                [Feature | erlang:element(5, Project)]}
    end.

-file("src/lightspeed/tooling/generator.gleam", 653).
-spec remove_path(list(file()), binary()) -> list(file()).
remove_path(Files_rev, Path) ->
    case Files_rev of
        [] ->
            [];

        [Entry | Rest] ->
            case erlang:element(2, Entry) =:= Path of
                true ->
                    remove_path(Rest, Path);

                false ->
                    [Entry | remove_path(Rest, Path)]
            end
    end.

-file("src/lightspeed/tooling/generator.gleam", 649).
-spec upsert_file(list(file()), file()) -> list(file()).
upsert_file(Files_rev, Next) ->
    [Next | remove_path(Files_rev, erlang:element(2, Next))].

-file("src/lightspeed/tooling/generator.gleam", 643).
-spec put_file(project(), binary(), binary()) -> project().
put_file(Project, Path, Content) ->
    Files_rev = upsert_file(erlang:element(4, Project), {file, Path, Content}),
    {project,
        erlang:element(2, Project),
        erlang:element(3, Project),
        Files_rev,
        erlang:element(5, Project)}.

-file("src/lightspeed/tooling/generator.gleam", 380).
?DOC(" Generate a `phx.gen.auth`-style auth scaffold.\n").
-spec generate_auth(project()) -> project().
generate_auth(Project) ->
    App = erlang:element(2, Project),
    _pipe = Project,
    _pipe@1 = put_file(
        _pipe,
        <<<<"src/"/utf8, App/binary>>/binary, "/auth.gleam"/utf8>>,
        <<"pub type User {\n  User(id: String, email: String, tenant_id: String)\n}\n"/utf8>>
    ),
    _pipe@2 = put_file(
        _pipe@1,
        <<<<"src/"/utf8, App/binary>>/binary, "/auth/password.gleam"/utf8>>,
        <<"import gleam/string\n\npub fn validate(password: String) -> Bool {\n  string.length(password) >= 12\n    && string.contains(password, \"0\")\n    && string.contains(password, \"A\")\n}\n"/utf8>>
    ),
    _pipe@3 = put_file(
        _pipe@2,
        <<<<"src/"/utf8, App/binary>>/binary, "/auth/policy.gleam"/utf8>>,
        <<<<"import "/utf8, App/binary>>/binary,
            "/auth\n\npub fn can_impersonate(_user: auth.User) -> Bool {\n  False\n}\n"/utf8>>
    ),
    _pipe@4 = put_file(
        _pipe@3,
        <<<<"src/"/utf8, App/binary>>/binary, "/auth/session.gleam"/utf8>>,
        <<<<"import "/utf8, App/binary>>/binary,
            "/auth\n\npub fn login(email: String, tenant_id: String) -> auth.User {\n  auth.User(id: \"u-1\", email: email, tenant_id: tenant_id)\n}\n"/utf8>>
    ),
    _pipe@5 = put_file(
        _pipe@4,
        <<<<"test/"/utf8, App/binary>>/binary, "/auth_test.gleam"/utf8>>,
        <<<<"import gleeunit/should\nimport "/utf8, App/binary>>/binary,
            "/auth/password\n\npub fn generated_auth_defaults_test() {\n  password.validate(\"A1234567890x\")\n  |> should.equal(True)\n\n  password.validate(\"short\")\n  |> should.equal(False)\n}\n"/utf8>>
    ),
    _pipe@6 = put_file(
        _pipe@5,
        <<<<"test/"/utf8, App/binary>>/binary, "/auth_policy_test.gleam"/utf8>>,
        <<<<<<<<"import gleeunit/should\nimport "/utf8, App/binary>>/binary,
                    "/auth\nimport "/utf8>>/binary,
                App/binary>>/binary,
            "/auth/policy\n\npub fn generated_auth_policy_test() {\n  let user = auth.User(id: \"u-1\", email: \"a@example.com\", tenant_id: \"t-1\")\n  policy.can_impersonate(user)\n  |> should.equal(False)\n}\n"/utf8>>
    ),
    _pipe@7 = put_file(
        _pipe@6,
        <<<<"test/"/utf8, App/binary>>/binary,
            "/integration/auth_flow_test.gleam"/utf8>>,
        <<<<"import gleeunit/should\nimport "/utf8, App/binary>>/binary,
            "/auth/session\n\npub fn generated_auth_session_flow_test() {\n  session.login(\"a@example.com\", \"t-1\")\n  |> should.equal(session.login(\"a@example.com\", \"t-1\"))\n}\n"/utf8>>
    ),
    _pipe@8 = put_file(
        _pipe@7,
        <<"examples/auth/README.md"/utf8>>,
        <<"# Auth Example\n\nGenerated auth fixture with password, policy, and session scaffolding.\n"/utf8>>
    ),
    add_feature(_pipe@8, <<"gen.auth"/utf8>>).

-file("src/lightspeed/tooling/generator.gleam", 697).
-spec normalize_name(binary()) -> binary().
normalize_name(Value) ->
    _pipe = Value,
    _pipe@1 = string:lowercase(_pipe),
    _pipe@2 = gleam@string:replace(_pipe@1, <<"-"/utf8>>, <<"_"/utf8>>),
    gleam@string:replace(_pipe@2, <<" "/utf8>>, <<"_"/utf8>>).

-file("src/lightspeed/tooling/generator.gleam", 728).
-spec join_with(binary(), list(binary())) -> binary().
join_with(Separator, Values) ->
    case Values of
        [] ->
            <<""/utf8>>;

        [Value] ->
            Value;

        [Value@1 | Rest] ->
            <<<<Value@1/binary, Separator/binary>>/binary,
                (join_with(Separator, Rest))/binary>>
    end.

-file("src/lightspeed/tooling/generator.gleam", 721).
-spec capitalize(binary()) -> binary().
capitalize(Value) ->
    case gleam_stdlib:string_pop_grapheme(Value) of
        {error, _} ->
            <<""/utf8>>;

        {ok, {First, Rest}} ->
            <<(string:uppercase(First))/binary, Rest/binary>>
    end.

-file("src/lightspeed/tooling/generator.gleam", 714).
-spec capitalize_parts(list(binary()), list(binary())) -> list(binary()).
capitalize_parts(Parts, Rev) ->
    case Parts of
        [] ->
            lists:reverse(Rev);

        [Part | Rest] ->
            capitalize_parts(Rest, [capitalize(Part) | Rev])
    end.

-file("src/lightspeed/tooling/generator.gleam", 704).
-spec to_module_name(binary()) -> binary().
to_module_name(Value) ->
    Parts = begin
        _pipe = Value,
        _pipe@1 = normalize_name(_pipe),
        _pipe@2 = gleam@string:split(_pipe@1, <<"_"/utf8>>),
        capitalize_parts(_pipe@2, [])
    end,
    join_with(<<""/utf8>>, Parts).

-file("src/lightspeed/tooling/generator.gleam", 103).
?DOC(
    " Build a new project scaffold comparable to `phx.new`.\n"
    "\n"
    " M25 baseline deepens output toward production defaults:\n"
    " - data scope contracts\n"
    " - migration-ready directory layout\n"
    " - integration-test scaffolds\n"
    " - governance/testing defaults\n"
).
-spec new(binary()) -> project().
new(App_name) ->
    Module_name = to_module_name(App_name),
    App = normalize_name(App_name),
    _pipe = {project, App, Module_name, [], []},
    _pipe@1 = put_file(
        _pipe,
        <<".tool-versions"/utf8>>,
        <<"erlang 28.5\ngleam 1.16.0\nrebar 3.27.0\n"/utf8>>
    ),
    _pipe@2 = put_file(
        _pipe@1,
        <<".gitignore"/utf8>>,
        <<"build/\n*.beam\nerl_crash.dump\n"/utf8>>
    ),
    _pipe@3 = put_file(
        _pipe@2,
        <<"gleam.toml"/utf8>>,
        <<<<"name = \""/utf8, App/binary>>/binary,
            "\"\nversion = \"0.1.0\"\ndescription = \"Generated by lightspeed tooling\"\nlicences = [\"Unlicense\"]\ntarget = \"erlang\"\ngleam = \">= 1.16.0\"\n\n[dependencies]\ngleam_stdlib = \">= 1.0.0 and < 2.0.0\"\ngleam_otp = \">= 1.2.0 and < 2.0.0\"\n\n[dev-dependencies]\ngleeunit = \">= 1.10.0 and < 2.0.0\"\n"/utf8>>
    ),
    _pipe@4 = put_file(
        _pipe@3,
        <<"Makefile"/utf8>>,
        <<"setup:\n\tgleam deps download\n\nfmt:\n\tgleam format src test\n\nfmt-check:\n\tgleam format --check src test\n\ncheck:\n\tgleam check --target erlang\n\ntest:\n\tgleam test --target erlang\n\nci: fmt-check check test\n"/utf8>>
    ),
    _pipe@5 = put_file(
        _pipe@4,
        <<"AGENTS.md"/utf8>>,
        <<"# AGENTS\n\nGenerated project policy:\n\n1. Follow Gleam best practices.\n2. Add tests for every code change.\n3. Require RFC + ADR for every code change.\n4. Prefer simplicity first, then performance.\n"/utf8>>
    ),
    _pipe@6 = put_file(
        _pipe@5,
        <<"README.md"/utf8>>,
        <<<<"# "/utf8, Module_name/binary>>/binary,
            "\n\nGenerated by Lightspeed M25 scaffold.\n\n## Commands\n\n- make setup\n- make ci\n\n## Governance\n\nEvery code change requires an RFC and ADR.\n"/utf8>>
    ),
    _pipe@7 = put_file(
        _pipe@6,
        <<"docs/testing.md"/utf8>>,
        <<"# Testing\n\nRun `make ci` before commit.\nAdd tests for every new or changed behavior.\n"/utf8>>
    ),
    _pipe@8 = put_file(
        _pipe@7,
        <<"docs/data_policy.md"/utf8>>,
        <<"# Data Policy\n\nAll repository operations must be scoped by tenant context.\n"/utf8>>
    ),
    _pipe@9 = put_file(
        _pipe@8,
        <<"docs/migration_playbook.md"/utf8>>,
        <<"# Migration Playbook\n\nAdd one migration per resource and keep rollback notes beside each migration.\n"/utf8>>
    ),
    _pipe@10 = put_file(
        _pipe@9,
        <<"rfcs/0000-template.md"/utf8>>,
        <<"# RFC-0000 Template\n"/utf8>>
    ),
    _pipe@11 = put_file(
        _pipe@10,
        <<"adrs/0000-template.md"/utf8>>,
        <<"# ADR-0000 Template\n"/utf8>>
    ),
    _pipe@12 = put_file(
        _pipe@11,
        <<"priv/repo/migrations/.keep"/utf8>>,
        <<""/utf8>>
    ),
    _pipe@13 = put_file(_pipe@12, <<"priv/static/.keep"/utf8>>, <<""/utf8>>),
    _pipe@14 = put_file(
        _pipe@13,
        <<<<"src/"/utf8, App/binary>>/binary, ".gleam"/utf8>>,
        <<<<"pub fn banner() -> String {\n  \""/utf8, Module_name/binary>>/binary,
            "\"\n}\n"/utf8>>
    ),
    _pipe@15 = put_file(
        _pipe@14,
        <<<<"src/"/utf8, App/binary>>/binary, "/app.gleam"/utf8>>,
        <<<<<<<<"import "/utf8, App/binary>>/binary,
                    "\n\npub fn start() -> String {\n  "/utf8>>/binary,
                App/binary>>/binary,
            ".banner()\n}\n"/utf8>>
    ),
    _pipe@16 = put_file(
        _pipe@15,
        <<<<"src/"/utf8, App/binary>>/binary, "/web/router.gleam"/utf8>>,
        <<"pub fn routes() -> List(#(String, String)) {\n  [#(\"GET\", \"/health\"), #(\"GET\", \"/\")]\n}\n"/utf8>>
    ),
    _pipe@17 = put_file(
        _pipe@16,
        <<<<"src/"/utf8, App/binary>>/binary, "/web/endpoint.gleam"/utf8>>,
        <<<<"import "/utf8, App/binary>>/binary,
            "/web/router\n\npub fn route_count() -> Int {\n  list.length(router.routes())\n}\n"/utf8>>
    ),
    _pipe@18 = put_file(
        _pipe@17,
        <<<<"src/"/utf8, App/binary>>/binary, "/data/scope.gleam"/utf8>>,
        <<"pub type Role {\n  Reader\n  Editor\n  Admin\n}\n\npub type Scope {\n  Scope(tenant_id: String, role: Role)\n}\n\npub fn can_write(scope: Scope) -> Bool {\n  case scope.role {\n    Editor -> True\n    Admin -> True\n    Reader -> False\n  }\n}\n"/utf8>>
    ),
    _pipe@19 = put_file(
        _pipe@18,
        <<<<"src/"/utf8, App/binary>>/binary, "/data/repository.gleam"/utf8>>,
        <<<<"import "/utf8, App/binary>>/binary,
            "/data/scope\n\npub fn authorize_read(_scope: scope.Scope, _tenant_id: String) -> Bool {\n  True\n}\n\npub fn authorize_write(scope: scope.Scope, tenant_id: String) -> Bool {\n  scope.tenant_id == tenant_id && scope.can_write(scope)\n}\n"/utf8>>
    ),
    _pipe@20 = put_file(
        _pipe@19,
        <<<<"test/"/utf8, App/binary>>/binary, "_test.gleam"/utf8>>,
        <<<<<<<<<<<<"import gleeunit/should\nimport "/utf8, App/binary>>/binary,
                            "\n\npub fn generated_banner_test() {\n  "/utf8>>/binary,
                        App/binary>>/binary,
                    ".banner()\n  |> should.equal(\""/utf8>>/binary,
                Module_name/binary>>/binary,
            "\")\n}\n"/utf8>>
    ),
    _pipe@21 = put_file(
        _pipe@20,
        <<<<"test/"/utf8, App/binary>>/binary,
            "/integration/app_boot_test.gleam"/utf8>>,
        <<<<"import gleeunit/should\nimport "/utf8, App/binary>>/binary,
            "/web/endpoint\n\npub fn generated_boot_routes_test() {\n  endpoint.route_count()\n  |> should.equal(2)\n}\n"/utf8>>
    ),
    _pipe@22 = put_file(
        _pipe@21,
        <<<<"test/"/utf8, App/binary>>/binary,
            "/integration/scope_policy_test.gleam"/utf8>>,
        <<<<<<<<"import gleeunit/should\nimport "/utf8, App/binary>>/binary,
                    "/data/repository\nimport "/utf8>>/binary,
                App/binary>>/binary,
            "/data/scope\n\npub fn generated_scope_policy_test() {\n  let reader = scope.Scope(tenant_id: \"t-1\", role: scope.Reader)\n  let editor = scope.Scope(tenant_id: \"t-1\", role: scope.Editor)\n\n  repository.authorize_write(reader, \"t-1\")\n  |> should.equal(False)\n\n  repository.authorize_write(editor, \"t-1\")\n  |> should.equal(True)\n\n  repository.authorize_write(editor, \"t-2\")\n  |> should.equal(False)\n}\n"/utf8>>
    ),
    add_feature(_pipe@22, <<"new"/utf8>>).

-file("src/lightspeed/tooling/generator.gleam", 327).
?DOC(" Generate a `phx.gen.json`-style resource scaffold.\n").
-spec generate_json(project(), binary()) -> project().
generate_json(Project, Resource) ->
    App = erlang:element(2, Project),
    Name = normalize_name(Resource),
    _pipe = Project,
    _pipe@1 = put_file(
        _pipe,
        <<<<<<<<"src/"/utf8, App/binary>>/binary, "/api/"/utf8>>/binary,
                Name/binary>>/binary,
            "_serializer.gleam"/utf8>>,
        <<<<<<<<"pub fn encode_list() -> String {\n  \"{\\\"data\\\":[],\\\"resource\\\":\\\""/utf8,
                        Name/binary>>/binary,
                    "\\\"}\"\n}\n\npub fn encode_item(id: String) -> String {\n  \"{\\\"data\\\":{\\\"id\\\":\\\"\" <> id <> \"\\\"},\\\"resource\\\":\\\""/utf8>>/binary,
                Name/binary>>/binary,
            "\\\"}\"\n}\n"/utf8>>
    ),
    _pipe@2 = put_file(
        _pipe@1,
        <<<<<<<<"src/"/utf8, App/binary>>/binary, "/controllers/"/utf8>>/binary,
                Name/binary>>/binary,
            "_json.gleam"/utf8>>,
        <<<<<<<<<<<<<<<<"import "/utf8, App/binary>>/binary, "/api/"/utf8>>/binary,
                                Name/binary>>/binary,
                            "_serializer\n\npub fn index() -> String {\n  "/utf8>>/binary,
                        Name/binary>>/binary,
                    "_serializer.encode_list()\n}\n\npub fn show(id: String) -> String {\n  "/utf8>>/binary,
                Name/binary>>/binary,
            "_serializer.encode_item(id)\n}\n"/utf8>>
    ),
    _pipe@3 = put_file(
        _pipe@2,
        <<<<<<<<"test/"/utf8, App/binary>>/binary, "/"/utf8>>/binary,
                Name/binary>>/binary,
            "_json_test.gleam"/utf8>>,
        <<<<<<<<<<<<<<<<"import gleeunit/should\nimport "/utf8, App/binary>>/binary,
                                    "/controllers/"/utf8>>/binary,
                                Name/binary>>/binary,
                            "_json\n\npub fn generated_json_resource_test() {\n  "/utf8>>/binary,
                        Name/binary>>/binary,
                    "_json.index()\n  |> should.equal(\"{\\\"data\\\":[],\\\"resource\\\":\\\""/utf8>>/binary,
                Name/binary>>/binary,
            "\\\"}\")\n}\n"/utf8>>
    ),
    _pipe@4 = put_file(
        _pipe@3,
        <<<<<<<<"test/"/utf8, App/binary>>/binary, "/integration/"/utf8>>/binary,
                Name/binary>>/binary,
            "_json_flow_test.gleam"/utf8>>,
        <<<<<<<<<<<<<<<<"import gleeunit/should\nimport "/utf8, App/binary>>/binary,
                                    "/controllers/"/utf8>>/binary,
                                Name/binary>>/binary,
                            "_json\n\npub fn generated_json_show_test() {\n  "/utf8>>/binary,
                        Name/binary>>/binary,
                    "_json.show(\"42\")\n  |> should.equal(\"{\\\"data\\\":{\\\"id\\\":\\\"42\\\"},\\\"resource\\\":\\\""/utf8>>/binary,
                Name/binary>>/binary,
            "\\\"}\")\n}\n"/utf8>>
    ),
    add_feature(_pipe@4, <<"gen.json:"/utf8, Name/binary>>).

-file("src/lightspeed/tooling/generator.gleam", 281).
?DOC(" Generate a `phx.gen.html`-style resource scaffold.\n").
-spec generate_html(project(), binary()) -> project().
generate_html(Project, Resource) ->
    App = erlang:element(2, Project),
    Name = normalize_name(Resource),
    Module_name = to_module_name(Name),
    _pipe = Project,
    _pipe@1 = put_file(
        _pipe,
        <<<<<<<<"src/"/utf8, App/binary>>/binary, "/controllers/"/utf8>>/binary,
                Name/binary>>/binary,
            "_html.gleam"/utf8>>,
        <<<<<<<<"pub fn index() -> String {\n  \"<h1>"/utf8,
                        Module_name/binary>>/binary,
                    " Index</h1>\"\n}\n\npub fn show(id: String) -> String {\n  \"<article data-id=\\\"\" <> id <> \"\\\">"/utf8>>/binary,
                Module_name/binary>>/binary,
            " Show</article>\"\n}\n"/utf8>>
    ),
    _pipe@2 = put_file(
        _pipe@1,
        <<<<"priv/templates/"/utf8, Name/binary>>/binary, "/index.html"/utf8>>,
        <<<<"<h1>"/utf8, Module_name/binary>>/binary, " Index</h1>\n"/utf8>>
    ),
    _pipe@3 = put_file(
        _pipe@2,
        <<<<<<<<"test/"/utf8, App/binary>>/binary, "/"/utf8>>/binary,
                Name/binary>>/binary,
            "_html_test.gleam"/utf8>>,
        <<<<<<<<<<<<<<<<"import gleeunit/should\nimport "/utf8, App/binary>>/binary,
                                    "/controllers/"/utf8>>/binary,
                                Name/binary>>/binary,
                            "_html\n\npub fn generated_html_resource_test() {\n  "/utf8>>/binary,
                        Name/binary>>/binary,
                    "_html.index()\n  |> should.equal(\"<h1>"/utf8>>/binary,
                Module_name/binary>>/binary,
            " Index</h1>\")\n}\n"/utf8>>
    ),
    _pipe@4 = put_file(
        _pipe@3,
        <<<<<<<<"test/"/utf8, App/binary>>/binary, "/integration/"/utf8>>/binary,
                Name/binary>>/binary,
            "_html_flow_test.gleam"/utf8>>,
        <<<<<<<<<<<<<<<<"import gleeunit/should\nimport "/utf8, App/binary>>/binary,
                                    "/controllers/"/utf8>>/binary,
                                Name/binary>>/binary,
                            "_html\n\npub fn generated_html_show_test() {\n  "/utf8>>/binary,
                        Name/binary>>/binary,
                    "_html.show(\"42\")\n  |> should.equal(\"<article data-id=\\\"42\\\">"/utf8>>/binary,
                Module_name/binary>>/binary,
            " Show</article>\")\n}\n"/utf8>>
    ),
    add_feature(_pipe@4, <<"gen.html:"/utf8, Name/binary>>).

-file("src/lightspeed/tooling/generator.gleam", 211).
?DOC(" Generate a `phx.gen.live`-style resource scaffold.\n").
-spec generate_live(project(), binary()) -> project().
generate_live(Project, Resource) ->
    App = erlang:element(2, Project),
    Name = normalize_name(Resource),
    Module_name = to_module_name(Name),
    _pipe = Project,
    _pipe@1 = put_file(
        _pipe,
        <<<<<<<<"src/"/utf8, App/binary>>/binary, "/live/"/utf8>>/binary,
                Name/binary>>/binary,
            "_live.gleam"/utf8>>,
        <<<<<<<<"pub type Model {\n  Model(count: Int)\n}\n\npub type Msg {\n  Increment\n  Decrement\n}\n\npub fn init() -> Model {\n  Model(count: 0)\n}\n\npub fn update(model: Model, msg: Msg) -> Model {\n  case msg {\n    Increment -> Model(..model, count: model.count + 1)\n    Decrement -> Model(..model, count: model.count - 1)\n  }\n}\n\npub fn render(model: Model) -> String {\n  \"<section data-resource=\\\""/utf8,
                        Name/binary>>/binary,
                    "\\\"><h1>"/utf8>>/binary,
                Module_name/binary>>/binary,
            "</h1><span>\" <> int.to_string(model.count) <> \"</span></section>\"\n}\n"/utf8>>
    ),
    _pipe@2 = put_file(
        _pipe@1,
        <<<<<<<<"src/"/utf8, App/binary>>/binary, "/data/"/utf8>>/binary,
                Name/binary>>/binary,
            "_repository.gleam"/utf8>>,
        <<<<<<<<"import "/utf8, App/binary>>/binary,
                    "/data/repository\nimport "/utf8>>/binary,
                App/binary>>/binary,
            "/data/scope\n\npub fn list(scope scope: scope.Scope) -> Result(List(String), String) {\n  case repository.authorize_read(scope, scope.tenant_id) {\n    True -> Ok([])\n    False -> Error(\"forbidden\")\n  }\n}\n\npub fn insert(scope scope: scope.Scope, tenant_id: String, _attrs: String) -> Result(String, String) {\n  case repository.authorize_write(scope, tenant_id) {\n    True -> Ok(\"created\")\n    False -> Error(\"forbidden\")\n  }\n}\n"/utf8>>
    ),
    _pipe@3 = put_file(
        _pipe@2,
        <<<<"priv/repo/migrations/20260508000000_create_"/utf8, Name/binary>>/binary,
            ".sql"/utf8>>,
        <<<<<<<<"-- up\n-- create table "/utf8, Name/binary>>/binary,
                    " (\n--   id text primary key,\n--   tenant_id text not null,\n--   inserted_at text not null\n-- );\n\n-- down\n-- drop table "/utf8>>/binary,
                Name/binary>>/binary,
            ";\n"/utf8>>
    ),
    _pipe@4 = put_file(
        _pipe@3,
        <<<<<<<<"test/"/utf8, App/binary>>/binary, "/"/utf8>>/binary,
                Name/binary>>/binary,
            "_live_test.gleam"/utf8>>,
        <<<<<<<<<<<<<<<<<<<<<<<<"import gleeunit/should\nimport "/utf8,
                                                        App/binary>>/binary,
                                                    "/live/"/utf8>>/binary,
                                                Name/binary>>/binary,
                                            "_live\n\npub fn generated_live_render_test() {\n  "/utf8>>/binary,
                                        Name/binary>>/binary,
                                    "_live.init()\n  |> "/utf8>>/binary,
                                Name/binary>>/binary,
                            "_live.render\n  |> should.equal("/utf8>>/binary,
                        Name/binary>>/binary,
                    "_live.init() |> "/utf8>>/binary,
                Name/binary>>/binary,
            "_live.render)\n}\n"/utf8>>
    ),
    _pipe@5 = put_file(
        _pipe@4,
        <<<<<<<<"test/"/utf8, App/binary>>/binary, "/integration/"/utf8>>/binary,
                Name/binary>>/binary,
            "_live_flow_test.gleam"/utf8>>,
        <<<<<<<<<<<<<<<<<<<<"import gleeunit/should\nimport "/utf8, App/binary>>/binary,
                                            "/data/"/utf8>>/binary,
                                        Name/binary>>/binary,
                                    "_repository\nimport "/utf8>>/binary,
                                App/binary>>/binary,
                            "/data/scope\n\npub fn generated_live_resource_scope_test() {\n  let scope_reader = scope.Scope(tenant_id: \"t-1\", role: scope.Reader)\n  let scope_editor = scope.Scope(tenant_id: \"t-1\", role: scope.Editor)\n\n  "/utf8>>/binary,
                        Name/binary>>/binary,
                    "_repository.insert(scope_reader, \"t-1\", \"{}\")\n  |> should.equal(Error(\"forbidden\"))\n\n  "/utf8>>/binary,
                Name/binary>>/binary,
            "_repository.insert(scope_editor, \"t-1\", \"{}\")\n  |> should.equal(Ok(\"created\"))\n}\n"/utf8>>
    ),
    _pipe@6 = put_file(
        _pipe@5,
        <<<<"examples/crud/"/utf8, Name/binary>>/binary, ".md"/utf8>>,
        <<<<"# CRUD Example "/utf8, Module_name/binary>>/binary,
            "\n\nGenerated live resource fixture with scope-aware repository and migration scaffold.\n"/utf8>>
    ),
    add_feature(_pipe@6, <<"gen.live:"/utf8, Name/binary>>).

-file("src/lightspeed/tooling/generator.gleam", 78).
?DOC(" Execute one command into a generated project tree.\n").
-spec scaffold(command()) -> project().
scaffold(Command) ->
    case Command of
        {new, App_name} ->
            new(App_name);

        {gen_live, App_name@1, Resource} ->
            _pipe = new(App_name@1),
            generate_live(_pipe, Resource);

        {gen_html, App_name@2, Resource@1} ->
            _pipe@1 = new(App_name@2),
            generate_html(_pipe@1, Resource@1);

        {gen_json, App_name@3, Resource@2} ->
            _pipe@2 = new(App_name@3),
            generate_json(_pipe@2, Resource@2);

        {gen_auth, App_name@4} ->
            _pipe@3 = new(App_name@4),
            generate_auth(_pipe@3)
    end.

-file("src/lightspeed/tooling/generator.gleam", 432).
?DOC(" Generated app name.\n").
-spec app_name(project()) -> binary().
app_name(Project) ->
    erlang:element(2, Project).

-file("src/lightspeed/tooling/generator.gleam", 437).
?DOC(" Generated module name.\n").
-spec module_name(project()) -> binary().
module_name(Project) ->
    erlang:element(3, Project).

-file("src/lightspeed/tooling/generator.gleam", 442).
?DOC(" Generated files in stable order.\n").
-spec files(project()) -> list(file()).
files(Project) ->
    lists:reverse(erlang:element(4, Project)).

-file("src/lightspeed/tooling/generator.gleam", 447).
?DOC(" Generated feature labels in stable order.\n").
-spec features(project()) -> list(binary()).
features(Project) ->
    lists:reverse(erlang:element(5, Project)).

-file("src/lightspeed/tooling/generator.gleam", 664).
-spec has_file_in(list(file()), binary()) -> boolean().
has_file_in(Files_rev, Path) ->
    case Files_rev of
        [] ->
            false;

        [Entry | Rest] ->
            case erlang:element(2, Entry) =:= Path of
                true ->
                    true;

                false ->
                    has_file_in(Rest, Path)
            end
    end.

-file("src/lightspeed/tooling/generator.gleam", 452).
?DOC(" Check for a generated file.\n").
-spec has_file(project(), binary()) -> boolean().
has_file(Project, Path) ->
    has_file_in(erlang:element(4, Project), Path).

-file("src/lightspeed/tooling/generator.gleam", 675).
-spec read_file(list(file()), binary()) -> gleam@option:option(binary()).
read_file(Files_rev, Path) ->
    case Files_rev of
        [] ->
            none;

        [Entry | Rest] ->
            case erlang:element(2, Entry) =:= Path of
                true ->
                    {some, erlang:element(3, Entry)};

                false ->
                    read_file(Rest, Path)
            end
    end.

-file("src/lightspeed/tooling/generator.gleam", 457).
?DOC(" Read generated file content when present.\n").
-spec file_content(project(), binary()) -> gleam@option:option(binary()).
file_content(Project, Path) ->
    read_file(erlang:element(4, Project), Path).

-file("src/lightspeed/tooling/generator.gleam", 629).
-spec file_paths(list(file())) -> list(binary()).
file_paths(Files) ->
    case Files of
        [] ->
            [];

        [{file, Path, _} | Rest] ->
            [Path | file_paths(Rest)]
    end.

-file("src/lightspeed/tooling/generator.gleam", 462).
?DOC(" Stable fixture signature for reproducible generator outputs.\n").
-spec fixture_signature(project()) -> binary().
fixture_signature(Project) ->
    <<<<<<<<<<<<<<"m25.v"/utf8, (erlang:integer_to_binary(2))/binary>>/binary,
                            "|app="/utf8>>/binary,
                        (erlang:element(2, Project))/binary>>/binary,
                    "|features="/utf8>>/binary,
                (join_with(<<","/utf8>>, features(Project)))/binary>>/binary,
            "|files="/utf8>>/binary,
        (join_with(<<","/utf8>>, file_paths(files(Project))))/binary>>.

-file("src/lightspeed/tooling/generator.gleam", 622).
-spec all_paths(list(binary()), project()) -> boolean().
all_paths(Paths, Project) ->
    case Paths of
        [] ->
            true;

        [Path | Rest] ->
            has_file(Project, Path) andalso all_paths(Rest, Project)
    end.

-file("src/lightspeed/tooling/generator.gleam", 614).
-spec has_rfc_adr_mentions(project()) -> boolean().
has_rfc_adr_mentions(Project) ->
    case file_content(Project, <<"README.md"/utf8>>) of
        none ->
            false;

        {some, Content} ->
            gleam_stdlib:contains_string(Content, <<"RFC"/utf8>>) andalso gleam_stdlib:contains_string(
                Content,
                <<"ADR"/utf8>>
            )
    end.

-file("src/lightspeed/tooling/generator.gleam", 601).
-spec makefile_has_targets(project()) -> boolean().
makefile_has_targets(Project) ->
    case file_content(Project, <<"Makefile"/utf8>>) of
        none ->
            false;

        {some, Content} ->
            ((((gleam_stdlib:contains_string(Content, <<"setup:"/utf8>>) andalso gleam_stdlib:contains_string(
                Content,
                <<"fmt:"/utf8>>
            ))
            andalso gleam_stdlib:contains_string(Content, <<"fmt-check:"/utf8>>))
            andalso gleam_stdlib:contains_string(Content, <<"check:"/utf8>>))
            andalso gleam_stdlib:contains_string(Content, <<"test:"/utf8>>))
            andalso gleam_stdlib:contains_string(Content, <<"ci:"/utf8>>)
    end.

-file("src/lightspeed/tooling/generator.gleam", 474).
?DOC(" Validate that generated project satisfies baseline boot/CI constraints.\n").
-spec boot_ci_contract(project()) -> boolean().
boot_ci_contract(Project) ->
    App = erlang:element(2, Project),
    Required_files = [<<".tool-versions"/utf8>>,
        <<".gitignore"/utf8>>,
        <<"gleam.toml"/utf8>>,
        <<"Makefile"/utf8>>,
        <<"AGENTS.md"/utf8>>,
        <<"README.md"/utf8>>,
        <<"docs/testing.md"/utf8>>,
        <<"docs/data_policy.md"/utf8>>,
        <<"docs/migration_playbook.md"/utf8>>,
        <<"rfcs/0000-template.md"/utf8>>,
        <<"adrs/0000-template.md"/utf8>>,
        <<<<"src/"/utf8, App/binary>>/binary, ".gleam"/utf8>>,
        <<<<"src/"/utf8, App/binary>>/binary, "/data/scope.gleam"/utf8>>,
        <<<<"src/"/utf8, App/binary>>/binary, "/data/repository.gleam"/utf8>>,
        <<<<"test/"/utf8, App/binary>>/binary, "_test.gleam"/utf8>>,
        <<<<"test/"/utf8, App/binary>>/binary,
            "/integration/app_boot_test.gleam"/utf8>>,
        <<<<"test/"/utf8, App/binary>>/binary,
            "/integration/scope_policy_test.gleam"/utf8>>],
    Required_targets = makefile_has_targets(Project),
    Governance = has_rfc_adr_mentions(Project),
    (all_paths(Required_files, Project) andalso Required_targets) andalso Governance.

-file("src/lightspeed/tooling/generator.gleam", 596).
-spec has_migration_ready_layout(project()) -> boolean().
has_migration_ready_layout(Project) ->
    has_file(Project, <<"priv/repo/migrations/.keep"/utf8>>) andalso has_file(
        Project,
        <<"docs/migration_playbook.md"/utf8>>
    ).

-file("src/lightspeed/tooling/generator.gleam", 579).
-spec has_data_scope_controls(project()) -> boolean().
has_data_scope_controls(Project) ->
    App = erlang:element(2, Project),
    case {file_content(
            Project,
            <<<<"src/"/utf8, App/binary>>/binary, "/data/scope.gleam"/utf8>>
        ),
        file_content(
            Project,
            <<<<"src/"/utf8, App/binary>>/binary,
                "/data/repository.gleam"/utf8>>
        )} of
        {{some, Scope_file}, {some, Repo_file}} ->
            ((gleam_stdlib:contains_string(
                Scope_file,
                <<"pub type Scope"/utf8>>
            )
            andalso gleam_stdlib:contains_string(
                Scope_file,
                <<"pub fn can_write"/utf8>>
            ))
            andalso gleam_stdlib:contains_string(
                Repo_file,
                <<"authorize_write"/utf8>>
            ))
            andalso gleam_stdlib:contains_string(
                Repo_file,
                <<"scope.tenant_id == tenant_id"/utf8>>
            );

        {_, _} ->
            false
    end.

-file("src/lightspeed/tooling/generator.gleam", 502).
?DOC(" Validate production-ready scaffold defaults from M25.\n").
-spec production_contract(project()) -> boolean().
production_contract(Project) ->
    (boot_ci_contract(Project) andalso has_data_scope_controls(Project)) andalso has_migration_ready_layout(
        Project
    ).

-file("src/lightspeed/tooling/generator.gleam", 509).
?DOC(" Validate that generated resource files include migration/integration scaffolds.\n").
-spec resource_contract(project(), binary()) -> boolean().
resource_contract(Project, Resource) ->
    App = erlang:element(2, Project),
    Name = normalize_name(Resource),
    ((((has_file(
        Project,
        <<<<<<<<"src/"/utf8, App/binary>>/binary, "/live/"/utf8>>/binary,
                Name/binary>>/binary,
            "_live.gleam"/utf8>>
    )
    andalso has_file(
        Project,
        <<<<<<<<"src/"/utf8, App/binary>>/binary, "/data/"/utf8>>/binary,
                Name/binary>>/binary,
            "_repository.gleam"/utf8>>
    ))
    andalso has_file(
        Project,
        <<<<"priv/repo/migrations/20260508000000_create_"/utf8, Name/binary>>/binary,
            ".sql"/utf8>>
    ))
    andalso has_file(
        Project,
        <<<<<<<<"test/"/utf8, App/binary>>/binary, "/integration/"/utf8>>/binary,
                Name/binary>>/binary,
            "_live_flow_test.gleam"/utf8>>
    ))
    andalso has_file(
        Project,
        <<<<<<<<"test/"/utf8, App/binary>>/binary, "/integration/"/utf8>>/binary,
                Name/binary>>/binary,
            "_html_flow_test.gleam"/utf8>>
    ))
    andalso has_file(
        Project,
        <<<<<<<<"test/"/utf8, App/binary>>/binary, "/integration/"/utf8>>/binary,
                Name/binary>>/binary,
            "_json_flow_test.gleam"/utf8>>
    ).

-file("src/lightspeed/tooling/generator.gleam", 534).
?DOC(" Validate auth scaffold defaults from M25.\n").
-spec auth_contract(project()) -> boolean().
auth_contract(Project) ->
    App = erlang:element(2, Project),
    (((has_file(
        Project,
        <<<<"src/"/utf8, App/binary>>/binary, "/auth/password.gleam"/utf8>>
    )
    andalso has_file(
        Project,
        <<<<"src/"/utf8, App/binary>>/binary, "/auth/policy.gleam"/utf8>>
    ))
    andalso has_file(
        Project,
        <<<<"src/"/utf8, App/binary>>/binary, "/auth/session.gleam"/utf8>>
    ))
    andalso has_file(
        Project,
        <<<<"test/"/utf8, App/binary>>/binary, "/auth_policy_test.gleam"/utf8>>
    ))
    andalso has_file(
        Project,
        <<<<"test/"/utf8, App/binary>>/binary,
            "/integration/auth_flow_test.gleam"/utf8>>
    ).

-file("src/lightspeed/tooling/generator.gleam", 545).
?DOC(" Deterministic fixture snapshots used by drift guards.\n").
-spec fixture_snapshots() -> list({binary(), binary()}).
fixture_snapshots() ->
    Project = new(<<"demo_app"/utf8>>),
    Full_stack = begin
        _pipe = Project,
        _pipe@1 = generate_live(_pipe, <<"posts"/utf8>>),
        _pipe@2 = generate_html(_pipe@1, <<"posts"/utf8>>),
        _pipe@3 = generate_json(_pipe@2, <<"posts"/utf8>>),
        generate_auth(_pipe@3)
    end,
    Auth_only = begin
        _pipe@4 = Project,
        generate_auth(_pipe@4)
    end,
    [{<<"project"/utf8>>, fixture_signature(Project)},
        {<<"auth_only"/utf8>>, fixture_signature(Auth_only)},
        {<<"full_stack"/utf8>>, fixture_signature(Full_stack)}].

-file("src/lightspeed/tooling/generator.gleam", 565).
?DOC(" Deterministic snapshot signature over M25 generator fixtures.\n").
-spec snapshot_signature() -> binary().
snapshot_signature() ->
    Entries = begin
        _pipe = fixture_snapshots(),
        gleam@list:map(
            _pipe,
            fun(Entry) ->
                {Name, Signature} = Entry,
                <<<<Name/binary, "="/utf8>>/binary, Signature/binary>>
            end
        )
    end,
    <<<<<<"generator_snapshots.v"/utf8, (erlang:integer_to_binary(2))/binary>>/binary,
            "|"/utf8>>/binary,
        (join_with(<<";"/utf8>>, Entries))/binary>>.