expert-lsp / expert-lsp/expert

Don't try to index EEx files without a proper EEx parser

Open
#364 0 comments 0 reactions 0 assignees View on GitHub
research
Dominant language
Elixir
Stars
2.1k
Forks
113
Avg merge
1d 10h
Merged PRs (30d)
26

Description

I got this error log:

expert.log

```
17:59:02.286 [error] Spitfire parser crashed: ** (CaseClauseError) no case clause matching: :"}"
(xp_spitfire 0.3.0) lib/spitfire.ex:892: XPSpitfire.parse_stab_expression/2
(xp_spitfire 0.3.0) lib/spitfire.ex:1136: anonymous fn/1 in XPSpitfire.parse_do_block/2
(xp_spitfire 0.3.0) lib/spitfire/while.ex:5: XPSpitfire.While2.recurse/3
(xp_spitfire 0.3.0) lib/spitfire/while.ex:10: XPSpitfire.While2.recurse/3
(xp_spitfire 0.3.0) lib/spitfire.ex:1132: anonymous fn/1 in XPSpitfire.parse_do_block/2
(xp_spitfire 0.3.0) lib/spitfire/while.ex:5: XPSpitfire.While2.recurse/3
(xp_spitfire 0.3.0) lib/spitfire.ex:1130: XPSpitfire.parse_do_block/2
(xp_spitfire 0.3.0) lib/spitfire.ex:259: XPSpitfire.parse_expression/6
Code: defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web_namespace, schema.alias) %>SettingsLive do
use <%= inspect context.web_module %>, :live_view
alias <%= inspect context.module %>
def render(assigns) do
~H"""
<.header class="text-center">
Account Settings
<:subtitle>Manage your account email address and password settings



<.simple_form
for={@email_form}
id="email_form"
phx-submit="update_email"
phx-change="validate_email"
>
<.input field={@email_form[:email]} type="email" label="Email" required />
<.input
field={@email_form[:current_password]}
name="current_password"
id="current_password_for_email"
type="password"
label="Current password"
value={@email_form_current_password}
required
/>
<:actions>
<.button phx-disable-with="Changing...">Change Email




<.simple_form
for={@password_form}
id="password_form"
action={~p"<%= schema.route_prefix %>/log_in?_action=password_updated"}
method="post"
phx-change="validate_password"
phx-submit="update_password"
phx-trigger-action={@trigger_submit}
>

<.input field={@password_form[:password]} type="password" label="New password" required />
<.input
field={@password_form[:password_confirmation]}
type="password"
label="Confirm new password"
/>
<.input
field={@password_form[:current_password]}
name="current_password"
type="password"
label="Current password"
id="current_password_for_password"
value={@current_password}
required
/>
<:actions>
<.button phx-disable-with="Changing...">Change Password




"""
end
def mount(%{"token" => token}, _session, socket) do
socket =
case <%= inspect context.alias %>.update_<%= schema.singular %>_email(socket.assigns.current_<%= schema.singular %>, token) do
:ok ->
put_flash(socket, :info, "Email changed successfully.")
:error ->
put_flash(socket, :error, "Email change link is invalid or it has expired.")
end
{:ok, push_navigate(socket, to: ~p"<%= schema.route_prefix %>/settings")}
end
def mount(_params, _session, socket) do
<%= schema.singular %> = socket.assigns.current_<%= schema.singular %>
email_changeset = <%= inspect context.alias %>.change_<%= schema.singular %>_email(<%= schema.singular %>)
password_changeset = <%= inspect context.alias %>.change_<%= schema.singular %>_password(<%= schema.singular %>)
socket =
socket
|> assign(:current_password, nil)
|> assign(:email_form_current_password, nil)
|> assign(:current_email, <%= schema.singular %>.email)
|> assign(:email_form, to_form(email_changeset))
|> assign(:password_form, to_form(password_changeset))
|> assign(:trigger_submit, false)
{:ok, socket}
end
def handle_event("validate_email", params, socket) do
%{"current_password" => password, "<%= schema.singular %>" => <%= schema.singular %>_params} = params
email_form =
socket.assigns.current_<%= schema.singular %>
|> <%= inspect context.alias %>.change_<%= schema.singular %>_email(<%= schema.singular %>_params)
|> Map.put(:action, :validate)
|> to_form()
{:noreply, assign(socket, email_form: email_form, email_form_current_password: password)}
end
def handle_event("update_email", params, socket) do
%{"current_password" => password, "<%= schema.singular %>" => <%= schema.singular %>_params} = params
<%= schema.singular %> = socket.assigns.current_<%= schema.singular %>
case <%= inspect context.alias %>.apply_<%= schema.singular %>_email(<%= schema.singular %>, password, <%= schema.singular %>_params) do
{:ok, applied_<%= schema.singular %>} ->
<%= inspect context.alias %>.deliver_<%= schema.singular %>_update_email_instructions(
applied_<%= schema.singular %>,
<%= schema.singular %>.email,
&url(~p"<%= schema.route_prefix %>/settings/confirm_email/#{&1}")
)
info = "A link to confirm your email change has been sent to the new address."
{:noreply, socket |> put_flash(:info, info) |> assign(email_form_current_password: nil)}
{:error, changeset} ->
{:noreply, assign(socket, :email_form, to_form(Map.put(changeset, :action, :insert)))}
end
end
def handle_event("validate_password", params, socket) do
%{"current_password" => password, "<%= schema.singular %>" => <%= schema.singular %>_params} = params
password_form =
socket.assigns.current_<%= schema.singular %>
|> <%= inspect context.alias %>.change_<%= schema.singular %>_password(<%= schema.singular %>_params)
|> Map.put(:action, :validate)
|> to_form()
{:noreply, assign(socket, password_form: password_form, current_password: password)}
end
def handle_event("update_password", params, socket) do
%{"current_password" => password, "<%= schema.singular %>" => <%= schema.singular %>_params} = params
<%= schema.singular %> = socket.assigns.current_<%= schema.singular %>
case <%= inspect context.alias %>.update_<%= schema.singular %>_password(<%= schema.singular %>, password, <%= schema.singular %>_params) do
{:ok, <%= schema.singular %>} ->
password_form =
<%= schema.singular %>
|> <%= inspect context.alias %>.change_<%= schema.singular %>_password(<%= schema.singular %>_params)
|> to_form()
{:noreply, assign(socket, trigger_submit: true, password_form: password_form)}
{:error, changeset} ->
{:noreply, assign(socket, password_form: to_form(changeset))}
end
end
end
```

That source comes from this file: https://github.com/phoenixframework/phoenix/blob/main/priv/templates/phx.gen.auth/settings_live.ex

The issue is that it's a `.ex` file, but being a template file, the contents are actually EEx, so we fail to parse it. I think trying to parse it with Spitfire even if it were able to recover from the syntax error it would produce unusable garbage, so we should have a way to avoid parsing those files

Alternatively we could maybe try to properly parse those files with an EEx parser

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.