From 2bed225133ac4aef93b9d9c7cc779857ada73697 Mon Sep 17 00:00:00 2001 From: Chili Palmer Date: Sat, 30 May 2026 09:00:29 +0200 Subject: [PATCH] style: fix pre-existing formatting drift across codebase --- config/runtime.exs | 7 +- lib/bds/ai/chat_conversation.ex | 4 +- lib/bds/desktop/overlay.ex | 9 ++- lib/bds/desktop/shell_live/chat_editor.ex | 11 ++- lib/bds/desktop/shell_live/gallery_import.ex | 70 +++++++++++++---- lib/bds/desktop/shell_live/import_editor.ex | 5 +- lib/bds/desktop/shell_live/media_editor.ex | 16 +++- lib/bds/desktop/shell_live/post_editor.ex | 23 ++++-- lib/bds/desktop/shell_live/tags_editor.ex | 8 +- lib/bds/embeddings.ex | 4 +- lib/bds/embeddings/backends/neural.ex | 4 +- lib/bds/embeddings/index.ex | 11 ++- lib/bds/generation/pagefind.ex | 9 ++- lib/bds/media.ex | 6 +- lib/bds/preview.ex | 13 +++- lib/bds/preview/router.ex | 22 ++++-- lib/bds/projects.ex | 5 +- lib/bds/rendering/filters.ex | 49 +++++++++--- lib/bds/rendering/list_archive.ex | 1 - lib/bds/scripting.ex | 8 +- lib/bds/scripting/capabilities.ex | 15 ++-- lib/bds/search.ex | 40 +++++++--- lib/bds/tags.ex | 1 + lib/bds/ui/dashboard.ex | 10 ++- test/bds/csm006_n_plus_one_test.exs | 11 ++- test/bds/csm007_reload_shell_test.exs | 75 ++++++++++--------- test/bds/csm008_render_path_test.exs | 47 ++++++------ .../csm009_thumbnail_error_handling_test.exs | 13 +++- test/bds/csm020_nested_case_test.exs | 4 +- test/bds/csm031_try_rescue_test.exs | 2 + .../bds/csm032_map_get_pattern_match_test.exs | 10 +++ test/bds/csm033_batch_inserts_test.exs | 12 +-- test/bds/csm034_file_read_bang_test.exs | 4 +- test/bds/csm035_process_dict_test.exs | 8 +- test/bds/desktop/automation_test.exs | 4 +- test/bds/desktop_test.exs | 10 ++- test/bds/image_import_pipeline_test.exs | 10 ++- test/bds/import_definitions_test.exs | 5 +- test/bds/map_utils_test.exs | 7 +- test/bds/posts_test.exs | 1 + test/bds/preview_test.exs | 14 ++-- test/bds/scripts/transforms_test.exs | 4 +- test/bds/template_lookup_priority_test.exs | 9 ++- test/bds/ui/shell_test.exs | 45 ++++++++--- 44 files changed, 452 insertions(+), 194 deletions(-) diff --git a/config/runtime.exs b/config/runtime.exs index 36ca560..3de106b 100644 --- a/config/runtime.exs +++ b/config/runtime.exs @@ -10,7 +10,8 @@ if config_env() == :prod do pool_size: String.to_integer(System.get_env("POOL_SIZE") || "1") # Persist downloaded embedding model files alongside the database data dir. - config :bumblebee, :cache_dir, - System.get_env("BDS_MODEL_CACHE_DIR") || - Path.join(Path.dirname(Path.expand(database_path)), "models") + config :bumblebee, + :cache_dir, + System.get_env("BDS_MODEL_CACHE_DIR") || + Path.join(Path.dirname(Path.expand(database_path)), "models") end diff --git a/lib/bds/ai/chat_conversation.ex b/lib/bds/ai/chat_conversation.ex index 5c6d4ff..105fb53 100644 --- a/lib/bds/ai/chat_conversation.ex +++ b/lib/bds/ai/chat_conversation.ex @@ -27,7 +27,9 @@ defmodule BDS.AI.ChatConversation do def changeset(conversation, attrs) do conversation - |> cast(attrs, [:id, :title, :model, :copilot_session_id, :surface_state, :created_at, :updated_at], + |> cast( + attrs, + [:id, :title, :model, :copilot_session_id, :surface_state, :created_at, :updated_at], empty_values: [nil] ) |> validate_required([:id, :title, :created_at, :updated_at]) diff --git a/lib/bds/desktop/overlay.ex b/lib/bds/desktop/overlay.ex index aed9fbb..5ccdc43 100644 --- a/lib/bds/desktop/overlay.ex +++ b/lib/bds/desktop/overlay.ex @@ -263,8 +263,13 @@ defmodule BDS.Desktop.Overlay do def set_ai_suggestions_error(overlay, _error_message), do: overlay defp normalize_ai_fields(fields) do - Enum.map(fields, fn %{key: key, label: label, current_value: current, - suggested_value: suggested, locked: locked} = field -> + Enum.map(fields, fn %{ + key: key, + label: label, + current_value: current, + suggested_value: suggested, + locked: locked + } = field -> %{ key: to_string(key), label: label, diff --git a/lib/bds/desktop/shell_live/chat_editor.ex b/lib/bds/desktop/shell_live/chat_editor.ex index b01dbc4..bc79fe9 100644 --- a/lib/bds/desktop/shell_live/chat_editor.ex +++ b/lib/bds/desktop/shell_live/chat_editor.ex @@ -103,7 +103,9 @@ defmodule BDS.Desktop.ShellLive.ChatEditor do socket ) do next_data = Map.put(socket.assigns.surface_data, surface_id, fields) - {:noreply, assign(socket, :surface_data, next_data) |> schedule_surface_state_persist() |> build_data()} + + {:noreply, + assign(socket, :surface_data, next_data) |> schedule_surface_state_persist() |> build_data()} end def handle_event( @@ -227,8 +229,11 @@ defmodule BDS.Desktop.ShellLive.ChatEditor do build_data(socket) socket.assigns.offline_mode -> - Notify.output(dgettext("ui", "Chat"), - dgettext("ui", "Automatic AI actions stay gated by airplane mode."), "info") + Notify.output( + dgettext("ui", "Chat"), + dgettext("ui", "Automatic AI actions stay gated by airplane mode."), + "info" + ) build_data(socket) diff --git a/lib/bds/desktop/shell_live/gallery_import.ex b/lib/bds/desktop/shell_live/gallery_import.ex index bf75d2a..07fb26c 100644 --- a/lib/bds/desktop/shell_live/gallery_import.ex +++ b/lib/bds/desktop/shell_live/gallery_import.ex @@ -35,14 +35,28 @@ defmodule BDS.Desktop.ShellLive.GalleryImport do known_refs = MapSet.new(tasks, & &1.ref) drain_tasks( - remaining, tasks, known_refs, project_id, post_id, language, translate_targets, parent + remaining, + tasks, + known_refs, + project_id, + post_id, + language, + translate_targets, + parent ) send(parent, {:add_images_complete, length(paths)}) end defp drain_tasks( - [], tasks, _known_refs, _project_id, _post_id, _language, _translate_targets, _parent + [], + tasks, + _known_refs, + _project_id, + _post_id, + _language, + _translate_targets, + _parent ) do Enum.each(tasks, fn task -> Task.await(task, :infinity) end) end @@ -65,7 +79,12 @@ defmodule BDS.Desktop.ShellLive.GalleryImport do new_task = Task.async(fn -> process_single_image( - next_path, project_id, post_id, language, translate_targets, parent + next_path, + project_id, + post_id, + language, + translate_targets, + parent ) end) @@ -81,8 +100,14 @@ defmodule BDS.Desktop.ShellLive.GalleryImport do ) else drain_tasks( - [next_path | rest], tasks, known_refs, - project_id, post_id, language, translate_targets, parent + [next_path | rest], + tasks, + known_refs, + project_id, + post_id, + language, + translate_targets, + parent ) end @@ -93,7 +118,12 @@ defmodule BDS.Desktop.ShellLive.GalleryImport do new_task = Task.async(fn -> process_single_image( - next_path, project_id, post_id, language, translate_targets, parent + next_path, + project_id, + post_id, + language, + translate_targets, + parent ) end) @@ -109,8 +139,14 @@ defmodule BDS.Desktop.ShellLive.GalleryImport do ) else drain_tasks( - [next_path | rest], tasks, known_refs, - project_id, post_id, language, translate_targets, parent + [next_path | rest], + tasks, + known_refs, + project_id, + post_id, + language, + translate_targets, + parent ) end end @@ -124,16 +160,22 @@ defmodule BDS.Desktop.ShellLive.GalleryImport do end defp process_single_image( - path, project_id, post_id, language, translate_targets, parent + path, + project_id, + post_id, + language, + translate_targets, + parent ) do with {:ok, media} <- Media.import_media(%{project_id: project_id, source_path: path}), true <- String.starts_with?(media.mime_type || "", "image/"), {:ok, result} <- AI.analyze_image(media.id, language: language), - {:ok, _updated} <- Media.update_media(media.id, %{ - title: result.title, - alt: result.alt, - caption: result.caption - }), + {:ok, _updated} <- + Media.update_media(media.id, %{ + title: result.title, + alt: result.alt, + caption: result.caption + }), {:ok, _link} <- Media.link_media_to_post(media.id, post_id) do translate_media_translations(media.id, translate_targets) title = result.title || media.original_name diff --git a/lib/bds/desktop/shell_live/import_editor.ex b/lib/bds/desktop/shell_live/import_editor.ex index 5a7a1b6..c3df421 100644 --- a/lib/bds/desktop/shell_live/import_editor.ex +++ b/lib/bds/desktop/shell_live/import_editor.ex @@ -642,7 +642,10 @@ defmodule BDS.Desktop.ShellLive.ImportEditor do defp maybe_update_tab_meta(socket, name) do title = name || dgettext("ui", "Untitled Import") - Notify.tab_meta(:import, socket.assigns.definition_id, title, + Notify.tab_meta( + :import, + socket.assigns.definition_id, + title, dgettext( "ui", "Select a WordPress export file (WXR) and an uploads folder to analyze what would be imported." diff --git a/lib/bds/desktop/shell_live/media_editor.ex b/lib/bds/desktop/shell_live/media_editor.ex index c40ca3f..4bd21de 100644 --- a/lib/bds/desktop/shell_live/media_editor.ex +++ b/lib/bds/desktop/shell_live/media_editor.ex @@ -126,8 +126,12 @@ defmodule BDS.Desktop.ShellLive.MediaEditor do Notify.dirty(:media, media.id, false) - Notify.tab_meta(:media, media.id, display_title(updated_media), - updated_media.original_name || updated_media.mime_type || "") + Notify.tab_meta( + :media, + media.id, + display_title(updated_media), + updated_media.original_name || updated_media.mime_type || "" + ) {:noreply, socket} @@ -484,8 +488,12 @@ defmodule BDS.Desktop.ShellLive.MediaEditor do Notify.dirty(:media, media.id, false) - Notify.tab_meta(:media, media.id, display_title(updated_media), - updated_media.original_name || updated_media.mime_type || "") + Notify.tab_meta( + :media, + media.id, + display_title(updated_media), + updated_media.original_name || updated_media.mime_type || "" + ) notify_output(socket, dgettext("ui", "Media"), dgettext("ui", "Media saved")) socket diff --git a/lib/bds/desktop/shell_live/post_editor.ex b/lib/bds/desktop/shell_live/post_editor.ex index c583a12..8590724 100644 --- a/lib/bds/desktop/shell_live/post_editor.ex +++ b/lib/bds/desktop/shell_live/post_editor.ex @@ -471,8 +471,12 @@ defmodule BDS.Desktop.ShellLive.PostEditor do |> assign(:dirty?, false) |> build_data() - Notify.tab_meta(:post, post.id, record_title(record, refreshed_post), - Atom.to_string(record_status(record))) + Notify.tab_meta( + :post, + post.id, + record_title(record, refreshed_post), + Atom.to_string(record_status(record)) + ) Notify.dirty(:post, post.id, false) Notify.cancel_auto_save(:post, post.id) @@ -511,8 +515,12 @@ defmodule BDS.Desktop.ShellLive.PostEditor do |> assign(:dirty?, false) |> build_data() - Notify.tab_meta(:post, post.id, record_title(record, refreshed_post), - Atom.to_string(record_status(record))) + Notify.tab_meta( + :post, + post.id, + record_title(record, refreshed_post), + Atom.to_string(record_status(record)) + ) Notify.dirty(:post, post.id, false) notify_output(socket, dgettext("ui", "Post"), dgettext("ui", "Post published")) @@ -546,9 +554,12 @@ defmodule BDS.Desktop.ShellLive.PostEditor do |> assign(:dirty?, false) |> build_data() - Notify.tab_meta(:post, post.id, + Notify.tab_meta( + :post, + post.id, restored_post.title || restored_post.slug || restored_post.id, - Atom.to_string(restored_post.status || :draft)) + Atom.to_string(restored_post.status || :draft) + ) Notify.dirty(:post, post.id, false) socket diff --git a/lib/bds/desktop/shell_live/tags_editor.ex b/lib/bds/desktop/shell_live/tags_editor.ex index 9e53466..c8f433c 100644 --- a/lib/bds/desktop/shell_live/tags_editor.ex +++ b/lib/bds/desktop/shell_live/tags_editor.ex @@ -271,10 +271,10 @@ defmodule BDS.Desktop.ShellLive.TagsEditor do end end - attr :color, :string, default: nil - attr :presets, :list, required: true - attr :pick_event, :string, required: true - attr :target, :any, required: true + attr(:color, :string, default: nil) + attr(:presets, :list, required: true) + attr(:pick_event, :string, required: true) + attr(:target, :any, required: true) defp colour_picker(assigns) do ~H""" diff --git a/lib/bds/embeddings.ex b/lib/bds/embeddings.ex index dbd07ac..a9aa6b2 100644 --- a/lib/bds/embeddings.ex +++ b/lib/bds/embeddings.ex @@ -584,7 +584,9 @@ defmodule BDS.Embeddings do end defp duplicate_pairs_with_rebuild(project_id, entries, on_progress) do - case Index.duplicate_pairs(project_id, entries, @duplicate_threshold, on_progress: on_progress) do + case Index.duplicate_pairs(project_id, entries, @duplicate_threshold, + on_progress: on_progress + ) do {:ok, pairs} -> {:ok, pairs} diff --git a/lib/bds/embeddings/backends/neural.ex b/lib/bds/embeddings/backends/neural.ex index ab1feed..b2dbf5e 100644 --- a/lib/bds/embeddings/backends/neural.ex +++ b/lib/bds/embeddings/backends/neural.ex @@ -155,7 +155,9 @@ defmodule BDS.Embeddings.Backends.Neural do # Place model params/tensors on the Apple GPU (Metal) when accelerating with # EMLX so the compiled inference pass actually runs on-device. EXLA manages # its own device placement, so nothing to do there. - defp maybe_set_default_backend(:emlx), do: Nx.global_default_backend({EMLX.Backend, device: :gpu}) + defp maybe_set_default_backend(:emlx), + do: Nx.global_default_backend({EMLX.Backend, device: :gpu}) + defp maybe_set_default_backend(:exla), do: :ok @doc false diff --git a/lib/bds/embeddings/index.ex b/lib/bds/embeddings/index.ex index 1a58c63..703cacd 100644 --- a/lib/bds/embeddings/index.ex +++ b/lib/bds/embeddings/index.ex @@ -58,7 +58,11 @@ defmodule BDS.Embeddings.Index do """ def neighbors(project_id, query_label, query_vector, limit) when is_binary(project_id) and is_integer(query_label) and is_binary(query_vector) do - GenServer.call(__MODULE__, {:neighbors, project_id, query_label, query_vector, limit}, :infinity) + GenServer.call( + __MODULE__, + {:neighbors, project_id, query_label, query_vector, limit}, + :infinity + ) end @doc """ @@ -167,7 +171,10 @@ defmodule BDS.Embeddings.Index do defp build_entry(dimensions, entries) do count = length(entries) - {:ok, index} = HNSWLib.Index.new(@space, dimensions, count, m: @m, ef_construction: @ef_construction) + + {:ok, index} = + HNSWLib.Index.new(@space, dimensions, count, m: @m, ef_construction: @ef_construction) + :ok = HNSWLib.Index.set_ef(index, @ef_search) tensor = diff --git a/lib/bds/generation/pagefind.ex b/lib/bds/generation/pagefind.ex index 43ca565..84bc726 100644 --- a/lib/bds/generation/pagefind.ex +++ b/lib/bds/generation/pagefind.ex @@ -82,9 +82,7 @@ defmodule BDS.Generation.Pagefind do # Returns nil when the page is not marked, so unmarked pages are excluded # from the index entirely (matching Pagefind semantics). defp body_text(content) do - case Regex.run(~r/<([a-zA-Z0-9]+)[^>]*\bdata-pagefind-body\b[^>]*>/, content, - return: :index - ) do + case Regex.run(~r/<([a-zA-Z0-9]+)[^>]*\bdata-pagefind-body\b[^>]*>/, content, return: :index) do [{open_start, open_len}, {tag_start, tag_len}] -> tag = binary_part(content, tag_start, tag_len) region = scoped_region(content, tag, open_start + open_len) @@ -117,7 +115,10 @@ defmodule BDS.Generation.Pagefind do end defp event_kind(rest, pos, tag) do - if String.starts_with?(binary_part(rest, pos, min(2 + byte_size(tag), byte_size(rest) - pos)), " Repo.insert_or_update!() end) do {:ok, updated_translation} -> - log_sidecar_error(write_translation_sidecar(project, media, updated_translation), media.id) + log_sidecar_error( + write_translation_sidecar(project, media, updated_translation), + media.id + ) + :ok = Search.sync_media(media.id) {:ok, updated_translation} diff --git a/lib/bds/preview.ex b/lib/bds/preview.ex index 3841f51..174e1ce 100644 --- a/lib/bds/preview.ex +++ b/lib/bds/preview.ex @@ -178,7 +178,9 @@ defmodule BDS.Preview do case kind do :media -> serve_file(safe_join(server.data_dir, Path.join(["media", relative_path])), - server: server, query_params: query_params) + server: server, + query_params: query_params + ) :generated -> case BDS.Preview.Router.render_route(server.project_id, request_path) do @@ -187,7 +189,9 @@ defmodule BDS.Preview do :not_matched -> serve_file(safe_join(Path.join(server.data_dir, "html"), relative_path), - server: server, query_params: query_params) + server: server, + query_params: query_params + ) end end end @@ -240,7 +244,10 @@ defmodule BDS.Preview do defp draft_preview_payload(post, query_params) do requested_language = query_params |> Map.get("lang") |> normalize_requested_language() - effective_slug = post.template_slug || TemplateSelection.resolve_post_template_slug(post.project_id, post.tags, post.categories) + + effective_slug = + post.template_slug || + TemplateSelection.resolve_post_template_slug(post.project_id, post.tags, post.categories) case draft_preview_translation(post.id, requested_language, post.language) do %Translation{} = translation -> diff --git a/lib/bds/preview/router.ex b/lib/bds/preview/router.ex index aadb385..b70b93d 100644 --- a/lib/bds/preview/router.ex +++ b/lib/bds/preview/router.ex @@ -132,6 +132,7 @@ defmodule BDS.Preview.Router do defp render(project_id, {:home, page_number}, language, main_language, metadata) do posts = load_published_list_posts(project_id, metadata) posts = maybe_resolve_language(posts, language, main_language, project_id) + render_list(project_id, posts, page_number, metadata, language, main_language, %{kind: "core"}) end @@ -193,7 +194,13 @@ defmodule BDS.Preview.Router do }) end - defp render(project_id, {:day, year, month, day, page_number}, language, main_language, metadata) do + defp render( + project_id, + {:day, year, month, day, page_number}, + language, + main_language, + metadata + ) do posts = load_published_posts_by_day(project_id, year, month, day) posts = maybe_resolve_language(posts, language, main_language, project_id) @@ -208,7 +215,8 @@ defmodule BDS.Preview.Router do ## Post rendering defp render_post(project_id, post, language, main_language) do - {effective_record, body} = resolve_post_for_language(project_id, post, language, main_language) + {effective_record, body} = + resolve_post_for_language(project_id, post, language, main_language) assigns = %{ id: effective_record.id, @@ -220,7 +228,9 @@ defmodule BDS.Preview.Router do _post_record: effective_record } - effective_slug = post.template_slug || TemplateSelection.resolve_post_template_slug(project_id, post.tags, post.categories) + effective_slug = + post.template_slug || + TemplateSelection.resolve_post_template_slug(project_id, post.tags, post.categories) case Rendering.render_post_page(project_id, effective_slug, assigns) do {:ok, rendered} -> {:ok, rendered} @@ -370,7 +380,8 @@ defmodule BDS.Preview.Router do defp archive_page_title(%{kind: "date", year: y, month: m, day: d}) when is_integer(y) and is_integer(m) and is_integer(d), - do: "#{y}-#{String.pad_leading(Integer.to_string(m), 2, "0")}-#{String.pad_leading(Integer.to_string(d), 2, "0")}" + do: + "#{y}-#{String.pad_leading(Integer.to_string(m), 2, "0")}-#{String.pad_leading(Integer.to_string(d), 2, "0")}" defp archive_page_title(%{kind: "date", year: y, month: m}) when is_integer(y) and is_integer(m), @@ -504,7 +515,8 @@ defmodule BDS.Preview.Router do if String.downcase(to_string(language)) == String.downcase(to_string(main_language)) do posts else - translations = load_translations_for_language(project_id, Enum.map(posts, & &1.id), language) + translations = + load_translations_for_language(project_id, Enum.map(posts, & &1.id), language) Enum.map(posts, fn post -> case Map.get(translations, post.id) do diff --git a/lib/bds/projects.ex b/lib/bds/projects.ex index 0efcc65..a0cc8f0 100644 --- a/lib/bds/projects.ex +++ b/lib/bds/projects.ex @@ -104,8 +104,9 @@ defmodule BDS.Projects do end @spec project_data_dir(Project.t()) :: String.t() - def project_data_dir(%Project{data_path: data_path}) when is_binary(data_path) and data_path != "", - do: data_path + def project_data_dir(%Project{data_path: data_path}) + when is_binary(data_path) and data_path != "", + do: data_path # A project without an explicit data_path resolves to its folder under the # per-user default content location — never priv/data inside the repo diff --git a/lib/bds/rendering/filters.ex b/lib/bds/rendering/filters.ex index 917f86e..5b2c937 100644 --- a/lib/bds/rendering/filters.ex +++ b/lib/bds/rendering/filters.ex @@ -43,12 +43,26 @@ defmodule BDS.Rendering.Filters do _language_prefix, context ) do - render_markdown(value, canonical_post_paths, canonical_media_paths, language, context, post_id) + render_markdown( + value, + canonical_post_paths, + canonical_media_paths, + language, + context, + post_id + ) end @spec render_markdown(term(), map() | nil, map() | nil, String.t(), Liquex.Context.t(), term()) :: String.t() - def render_markdown(value, canonical_post_paths, canonical_media_paths, language, context, post_id \\ nil) do + def render_markdown( + value, + canonical_post_paths, + canonical_media_paths, + language, + context, + post_id \\ nil + ) do value |> to_string() |> replace_built_in_macros(language, context, post_id) @@ -161,7 +175,11 @@ defmodule BDS.Rendering.Filters do else {:error, reason, line} -> require Logger - Logger.warning("Macro template parse failed (#{template_path}): #{reason} at line #{line}") + + Logger.warning( + "Macro template parse failed (#{template_path}): #{reason} at line #{line}" + ) + "" {:error, message} -> @@ -365,8 +383,7 @@ defmodule BDS.Rendering.Filters do "root_classes" => "macro-photo-archive", "data_attrs" => [], "months" => months, - "empty_label" => - BDS.Gettext.lgettext(language, "render", "No photos found") + "empty_label" => BDS.Gettext.lgettext(language, "render", "No photos found") }, context ) @@ -391,8 +408,7 @@ defmodule BDS.Rendering.Filters do "width" => Map.get(params, "width", width), "height" => Map.get(params, "height", height), "aria_label" => "Tag cloud", - "empty_label" => - BDS.Gettext.lgettext(language, "render", "No tags") + "empty_label" => BDS.Gettext.lgettext(language, "render", "No tags") }, context ) @@ -456,9 +472,18 @@ defmodule BDS.Rendering.Filters do defp group_by_media_month(media_records) do month_names = %{ - 1 => "January", 2 => "February", 3 => "March", 4 => "April", - 5 => "May", 6 => "June", 7 => "July", 8 => "August", - 9 => "September", 10 => "October", 11 => "November", 12 => "December" + 1 => "January", + 2 => "February", + 3 => "March", + 4 => "April", + 5 => "May", + 6 => "June", + 7 => "July", + 8 => "August", + 9 => "September", + 10 => "October", + 11 => "November", + 12 => "December" } media_records @@ -555,8 +580,10 @@ defmodule BDS.Rendering.Filters do _ -> default end end + defp normalize_columns(value, _default, min, max) when is_integer(value), do: value |> max(min) |> min(max) + defp normalize_columns(_value, default, _min, _max), do: default defp parse_integer(value) when is_binary(value) do @@ -565,6 +592,7 @@ defmodule BDS.Rendering.Filters do _ -> nil end end + defp parse_integer(value) when is_integer(value), do: value defp parse_integer(_value), do: nil @@ -583,6 +611,7 @@ defmodule BDS.Rendering.Filters do case DateTime.from_iso8601("#{year}-#{pad(month + 1)}-01T00:00:00Z") do {:ok, dt, _} -> dt |> DateTime.add(-1, :second) |> DateTime.to_date() |> Map.get(:day) + _ -> 31 end diff --git a/lib/bds/rendering/list_archive.ex b/lib/bds/rendering/list_archive.ex index 9a13656..7eda4e0 100644 --- a/lib/bds/rendering/list_archive.ex +++ b/lib/bds/rendering/list_archive.ex @@ -349,5 +349,4 @@ defmodule BDS.Rendering.ListArchive do do: RenderMetadata.calendar_initial_month(post) defp calendar_initial_month_from_posts([]), do: nil - end diff --git a/lib/bds/scripting.ex b/lib/bds/scripting.ex index 700a13e..9376234 100644 --- a/lib/bds/scripting.ex +++ b/lib/bds/scripting.ex @@ -63,8 +63,12 @@ defmodule BDS.Scripting do args, Keyword.put(opts, :timeout, timeout) ) do - {:ok, nil} -> {:ok, ""} - {:ok, value} -> {:ok, to_string(value)} + {:ok, nil} -> + {:ok, ""} + + {:ok, value} -> + {:ok, to_string(value)} + {:error, reason} -> Logger.warning("execute_macro failed for project #{project_id}: #{inspect(reason)}") {:error, reason} diff --git a/lib/bds/scripting/capabilities.ex b/lib/bds/scripting/capabilities.ex index 38756e8..8965f12 100644 --- a/lib/bds/scripting/capabilities.ex +++ b/lib/bds/scripting/capabilities.ex @@ -111,8 +111,7 @@ defmodule BDS.Scripting.Capabilities do get_by_status: one_arg(fn status -> posts_by_status(project_id, status) end), get_by_year_month: zero_or_one_arg(fn _args -> post_counts_by_year_month(project_id) end), get_dashboard_stats: zero_or_one_arg(fn _args -> post_dashboard_stats(project_id) end), - get_linked_by: - one_arg(fn post_id -> linked_posts_for(project_id, post_id, :incoming) end), + get_linked_by: one_arg(fn post_id -> linked_posts_for(project_id, post_id, :incoming) end), get_links_to: one_arg(fn post_id -> linked_posts_for(project_id, post_id, :outgoing) end), get_preview_url: two_arg(fn post_id, options -> preview_url(project_id, post_id, options) end), @@ -157,8 +156,7 @@ defmodule BDS.Scripting.Capabilities do end), filter: one_arg(fn filters -> filter_media(project_id, filters) end), import: one_arg(fn attrs -> import_media(project_id, attrs) end), - get_by_year_month: - zero_or_one_arg(fn _args -> media_counts_by_year_month(project_id) end), + get_by_year_month: zero_or_one_arg(fn _args -> media_counts_by_year_month(project_id) end), get_file_path: one_arg(fn media_id -> media_file_path(project_id, media_id) end), update: two_arg(fn media_id, attrs -> update_media(project_id, media_id, attrs) end), delete: one_arg(fn media_id -> delete_media(project_id, media_id) end), @@ -172,8 +170,7 @@ defmodule BDS.Scripting.Capabilities do two_arg(fn media_id, language -> load_media_translation(project_id, media_id, language) end), - get_translations: - one_arg(fn media_id -> list_media_translations(project_id, media_id) end), + get_translations: one_arg(fn media_id -> list_media_translations(project_id, media_id) end), get_url: one_arg(fn media_id -> media_url(project_id, media_id) end), rebuild_from_files: zero_or_one_arg(fn _args -> rebuild_media_from_files(project_id) end), regenerate_missing_thumbnails: @@ -201,8 +198,7 @@ defmodule BDS.Scripting.Capabilities do get: one_arg(fn script_id -> load_script(project_id, script_id) end), get_all: zero_or_one_arg(fn _args -> list_scripts(project_id) end), publish: one_arg(fn script_id -> publish_script(project_id, script_id) end), - rebuild_from_files: - zero_or_one_arg(fn _args -> rebuild_scripts_from_files(project_id) end) + rebuild_from_files: zero_or_one_arg(fn _args -> rebuild_scripts_from_files(project_id) end) } end @@ -295,8 +291,7 @@ defmodule BDS.Scripting.Capabilities do find_similar: two_arg(fn post_id, limit -> find_similar(post_id, limit) end), compute_similarities: two_arg(fn post_id, target_ids -> compute_similarities(post_id, target_ids) end), - suggest_tags: - two_arg(fn post_id, exclude_tags -> suggest_tags(post_id, exclude_tags) end), + suggest_tags: two_arg(fn post_id, exclude_tags -> suggest_tags(post_id, exclude_tags) end), find_duplicates: zero_or_one_arg(fn _args -> find_duplicates(project_id) end), dismiss_pair: two_arg(fn post_id_a, post_id_b -> dismiss_pair(post_id_a, post_id_b) end), index_unindexed_posts: zero_or_one_arg(fn _args -> index_unindexed_posts(project_id) end) diff --git a/lib/bds/search.ex b/lib/bds/search.ex index 2bc3a8e..0cab9fa 100644 --- a/lib/bds/search.ex +++ b/lib/bds/search.ex @@ -284,14 +284,24 @@ defmodule BDS.Search do defp maybe_where_year(query, year) do year_str = to_string(year) - where(query, [p], fragment("strftime('%Y', datetime(? / 1000, 'unixepoch')) = ?", p.created_at, ^year_str)) + + where( + query, + [p], + fragment("strftime('%Y', datetime(? / 1000, 'unixepoch')) = ?", p.created_at, ^year_str) + ) end defp maybe_where_month(query, nil), do: query defp maybe_where_month(query, month) do month_str = String.pad_leading(to_string(month), 2, "0") - where(query, [p], fragment("strftime('%m', datetime(? / 1000, 'unixepoch')) = ?", p.created_at, ^month_str)) + + where( + query, + [p], + fragment("strftime('%m', datetime(? / 1000, 'unixepoch')) = ?", p.created_at, ^month_str) + ) end defp maybe_where_from(query, nil), do: query @@ -305,7 +315,10 @@ defmodule BDS.Search do defp maybe_where_tags(query, tags) do tags_clause = Enum.reduce(tags, false, fn tag, acc -> - dynamic([p], ^acc or fragment("EXISTS (SELECT 1 FROM json_each(?) WHERE value = ?)", p.tags, ^tag)) + dynamic( + [p], + ^acc or fragment("EXISTS (SELECT 1 FROM json_each(?) WHERE value = ?)", p.tags, ^tag) + ) end) where(query, [p], ^tags_clause) @@ -316,7 +329,10 @@ defmodule BDS.Search do defp maybe_where_tags_media(query, tags) do tags_clause = Enum.reduce(tags, false, fn tag, acc -> - dynamic([m], ^acc or fragment("EXISTS (SELECT 1 FROM json_each(?) WHERE value = ?)", m.tags, ^tag)) + dynamic( + [m], + ^acc or fragment("EXISTS (SELECT 1 FROM json_each(?) WHERE value = ?)", m.tags, ^tag) + ) end) where(query, [m], ^tags_clause) @@ -327,7 +343,15 @@ defmodule BDS.Search do defp maybe_where_categories(query, categories) do categories_clause = Enum.reduce(categories, false, fn category, acc -> - dynamic([p], ^acc or fragment("EXISTS (SELECT 1 FROM json_each(?) WHERE value = ?)", p.categories, ^category)) + dynamic( + [p], + ^acc or + fragment( + "EXISTS (SELECT 1 FROM json_each(?) WHERE value = ?)", + p.categories, + ^category + ) + ) end) where(query, [p], ^categories_clause) @@ -548,8 +572,6 @@ defmodule BDS.Search do ) end - - defp post_index_fields(post, translations) do post_language = normalize_language(post.language) @@ -656,8 +678,8 @@ defmodule BDS.Search do else Repo.all( from translation in MediaTranslation, - where: translation.translation_for in ^media_ids, - select: {translation.translation_for, translation} + where: translation.translation_for in ^media_ids, + select: {translation.translation_for, translation} ) |> Enum.group_by(fn {media_id, _} -> media_id end, fn {_, translation} -> translation end) end diff --git a/lib/bds/tags.ex b/lib/bds/tags.ex index 70b512d..74a3204 100644 --- a/lib/bds/tags.ex +++ b/lib/bds/tags.ex @@ -239,6 +239,7 @@ defmodule BDS.Tags do {:error, changeset} -> Repo.rollback(changeset) end end) + Enum.map(affected_posts, & &1.id) end) |> case do diff --git a/lib/bds/ui/dashboard.ex b/lib/bds/ui/dashboard.ex index 6cb5ea6..06c8377 100644 --- a/lib/bds/ui/dashboard.ex +++ b/lib/bds/ui/dashboard.ex @@ -79,8 +79,14 @@ defmodule BDS.UI.Dashboard do from post in Post, where: post.project_id == ^project_id, group_by: [ - fragment("CAST(strftime('%Y', datetime(? / 1000, 'unixepoch')) AS INTEGER)", post.created_at), - fragment("CAST(strftime('%m', datetime(? / 1000, 'unixepoch')) AS INTEGER)", post.created_at) + fragment( + "CAST(strftime('%Y', datetime(? / 1000, 'unixepoch')) AS INTEGER)", + post.created_at + ), + fragment( + "CAST(strftime('%m', datetime(? / 1000, 'unixepoch')) AS INTEGER)", + post.created_at + ) ], select: %{ year: diff --git a/test/bds/csm006_n_plus_one_test.exs b/test/bds/csm006_n_plus_one_test.exs index 53133a2..37ff387 100644 --- a/test/bds/csm006_n_plus_one_test.exs +++ b/test/bds/csm006_n_plus_one_test.exs @@ -51,7 +51,10 @@ defmodule BDS.CSM006NPlusOneTest do end # Clear FTS and reindex - Repo.query!("DELETE FROM posts_fts WHERE post_id IN (SELECT id FROM posts WHERE project_id = ?)", [project.id]) + Repo.query!( + "DELETE FROM posts_fts WHERE post_id IN (SELECT id FROM posts WHERE project_id = ?)", + [project.id] + ) # Reindex should succeed and produce correct FTS entries assert :ok = BDS.Search.reindex_posts(project.id) @@ -82,7 +85,11 @@ defmodule BDS.CSM006NPlusOneTest do language: "en" }) - Repo.query!("DELETE FROM posts_fts WHERE post_id IN (SELECT id FROM posts WHERE project_id = ?)", [project.id]) + Repo.query!( + "DELETE FROM posts_fts WHERE post_id IN (SELECT id FROM posts WHERE project_id = ?)", + [project.id] + ) + assert :ok = BDS.Search.reindex_posts(project.id) {:ok, results} = BDS.Search.search_posts(project.id, "unique-keyword-xyz") diff --git a/test/bds/csm007_reload_shell_test.exs b/test/bds/csm007_reload_shell_test.exs index a832819..17dacf6 100644 --- a/test/bds/csm007_reload_shell_test.exs +++ b/test/bds/csm007_reload_shell_test.exs @@ -24,12 +24,13 @@ defmodule BDS.CSM007ReloadShellTest do test "triggers no dashboard or git queries", %{project: _project} do {:ok, view, _html} = live_isolated(build_conn(), BDS.Desktop.ShellLive) - query_count = count_queries(fn -> - render_click(view, "toggle_sidebar", %{}) - end) + query_count = + count_queries(fn -> + render_click(view, "toggle_sidebar", %{}) + end) assert query_count == 0, - "Expected 0 DB queries for sidebar toggle, got #{query_count}" + "Expected 0 DB queries for sidebar toggle, got #{query_count}" end end @@ -37,12 +38,13 @@ defmodule BDS.CSM007ReloadShellTest do test "triggers no DB queries" do {:ok, view, _html} = live_isolated(build_conn(), BDS.Desktop.ShellLive) - query_count = count_queries(fn -> - render_click(view, "toggle_panel", %{}) - end) + query_count = + count_queries(fn -> + render_click(view, "toggle_panel", %{}) + end) assert query_count == 0, - "Expected 0 DB queries for panel toggle, got #{query_count}" + "Expected 0 DB queries for panel toggle, got #{query_count}" end end @@ -50,16 +52,17 @@ defmodule BDS.CSM007ReloadShellTest do test "triggers no DB queries" do {:ok, view, _html} = live_isolated(build_conn(), BDS.Desktop.ShellLive) - query_count = count_queries(fn -> - render_click(view, "sync_layout", %{ - "sidebar_width" => "300", - "sidebar_visible" => "true", - "panel_visible" => "false" - }) - end) + query_count = + count_queries(fn -> + render_click(view, "sync_layout", %{ + "sidebar_width" => "300", + "sidebar_visible" => "true", + "panel_visible" => "false" + }) + end) assert query_count == 0, - "Expected 0 DB queries for sync_layout, got #{query_count}" + "Expected 0 DB queries for sync_layout, got #{query_count}" end end @@ -67,12 +70,13 @@ defmodule BDS.CSM007ReloadShellTest do test "triggers no DB queries" do {:ok, view, _html} = live_isolated(build_conn(), BDS.Desktop.ShellLive) - query_count = count_queries(fn -> - render_click(view, "select_panel_tab", %{"tab" => "output"}) - end) + query_count = + count_queries(fn -> + render_click(view, "select_panel_tab", %{"tab" => "output"}) + end) assert query_count == 0, - "Expected 0 DB queries for select_panel_tab, got #{query_count}" + "Expected 0 DB queries for select_panel_tab, got #{query_count}" end end @@ -80,14 +84,15 @@ defmodule BDS.CSM007ReloadShellTest do test "triggers sidebar query but not dashboard or git queries" do {:ok, view, _html} = live_isolated(build_conn(), BDS.Desktop.ShellLive) - {query_count, query_sources} = count_queries_with_sources(fn -> - render_click(view, "select_view", %{"view" => "media"}) - end) + {query_count, query_sources} = + count_queries_with_sources(fn -> + render_click(view, "select_view", %{"view" => "media"}) + end) assert query_count > 0, "Expected at least 1 query for view change" refute "dashboard" in query_sources or "projects" in query_sources, - "View change should not query dashboard or projects, got: #{inspect(query_sources)}" + "View change should not query dashboard or projects, got: #{inspect(query_sources)}" end end @@ -95,14 +100,15 @@ defmodule BDS.CSM007ReloadShellTest do test "do not trigger dashboard or git queries" do {:ok, view, _html} = live_isolated(build_conn(), BDS.Desktop.ShellLive) - {_count, query_sources} = count_queries_with_sources(fn -> - render_click(view, "update_sidebar_search", %{ - "sidebar_filters" => %{"search" => "test"} - }) - end) + {_count, query_sources} = + count_queries_with_sources(fn -> + render_click(view, "update_sidebar_search", %{ + "sidebar_filters" => %{"search" => "test"} + }) + end) refute "dashboard" in query_sources, - "Sidebar search should not query dashboard, got: #{inspect(query_sources)}" + "Sidebar search should not query dashboard, got: #{inspect(query_sources)}" end end @@ -110,12 +116,13 @@ defmodule BDS.CSM007ReloadShellTest do test "triggers only the settings write, no refresh queries" do {:ok, view, _html} = live_isolated(build_conn(), BDS.Desktop.ShellLive) - query_count = count_queries(fn -> - render_click(view, "toggle_offline_mode", %{}) - end) + query_count = + count_queries(fn -> + render_click(view, "toggle_offline_mode", %{}) + end) assert query_count == 1, - "Expected exactly 1 DB query (settings write) for offline mode toggle, got #{query_count}" + "Expected exactly 1 DB query (settings write) for offline mode toggle, got #{query_count}" end end diff --git a/test/bds/csm008_render_path_test.exs b/test/bds/csm008_render_path_test.exs index 84c4420..736d98d 100644 --- a/test/bds/csm008_render_path_test.exs +++ b/test/bds/csm008_render_path_test.exs @@ -37,12 +37,13 @@ defmodule BDS.CSM008RenderPathTest do render_click(view, "select_tab", %{"type" => "post", "id" => post.id}) render_click(view, "select_panel_tab", %{"tab" => "post_links"}) - query_count = count_queries(fn -> - 1..10 |> Enum.each(fn _ -> render(view) end) - end) + query_count = + count_queries(fn -> + 1..10 |> Enum.each(fn _ -> render(view) end) + end) assert query_count == 0, - "Expected 0 DB queries on panel re-renders, got #{query_count}" + "Expected 0 DB queries on panel re-renders, got #{query_count}" end test "git_log panel re-render uses cached assigns", %{post: post} do @@ -51,12 +52,13 @@ defmodule BDS.CSM008RenderPathTest do render_click(view, "select_tab", %{"type" => "post", "id" => post.id}) render_click(view, "select_panel_tab", %{"tab" => "git_log"}) - query_count = count_queries(fn -> - 1..10 |> Enum.each(fn _ -> render(view) end) - end) + query_count = + count_queries(fn -> + 1..10 |> Enum.each(fn _ -> render(view) end) + end) assert query_count == 0, - "Expected 0 DB queries on git_log re-renders, got #{query_count}" + "Expected 0 DB queries on git_log re-renders, got #{query_count}" end end @@ -64,26 +66,28 @@ defmodule BDS.CSM008RenderPathTest do test "switching to output panel triggers no post/media queries" do {:ok, view, _html} = live_isolated(build_conn(), BDS.Desktop.ShellLive) - {query_count, query_sources} = count_queries_with_sources(fn -> - render_click(view, "select_panel_tab", %{"tab" => "output"}) - end) + {query_count, query_sources} = + count_queries_with_sources(fn -> + render_click(view, "select_panel_tab", %{"tab" => "output"}) + end) refute "post_links" in query_sources, - "Switching to output should not query post_links, got: #{inspect(query_sources)}" + "Switching to output should not query post_links, got: #{inspect(query_sources)}" assert query_count == 0, - "Expected 0 queries for output panel tab, got #{query_count}" + "Expected 0 queries for output panel tab, got #{query_count}" end test "switching to tasks panel triggers no post/media queries" do {:ok, view, _html} = live_isolated(build_conn(), BDS.Desktop.ShellLive) - {query_count, _query_sources} = count_queries_with_sources(fn -> - render_click(view, "select_panel_tab", %{"tab" => "tasks"}) - end) + {query_count, _query_sources} = + count_queries_with_sources(fn -> + render_click(view, "select_panel_tab", %{"tab" => "tasks"}) + end) assert query_count == 0, - "Expected 0 queries for tasks panel tab, got #{query_count}" + "Expected 0 queries for tasks panel tab, got #{query_count}" end end @@ -98,12 +102,13 @@ defmodule BDS.CSM008RenderPathTest do "subtitle" => "preset subtitle" }) - query_count = count_queries(fn -> - render_click(view, "select_tab", %{"type" => "post", "id" => post.id}) - end) + query_count = + count_queries(fn -> + render_click(view, "select_tab", %{"type" => "post", "id" => post.id}) + end) assert query_count == 0, - "Expected 0 DB queries when tab meta is already complete, got #{query_count}" + "Expected 0 DB queries when tab meta is already complete, got #{query_count}" end end diff --git a/test/bds/csm009_thumbnail_error_handling_test.exs b/test/bds/csm009_thumbnail_error_handling_test.exs index 90be89e..b8ecfdb 100644 --- a/test/bds/csm009_thumbnail_error_handling_test.exs +++ b/test/bds/csm009_thumbnail_error_handling_test.exs @@ -34,7 +34,10 @@ defmodule BDS.CSM009ThumbnailErrorHandlingTest do assert {:error, _reason} = result end - test "ensure_thumbnails returns :ok for non-image media", %{project: project, temp_dir: temp_dir} do + test "ensure_thumbnails returns :ok for non-image media", %{ + project: project, + temp_dir: temp_dir + } do source_path = Path.join(temp_dir, "readme.txt") File.write!(source_path, "just text") @@ -86,11 +89,15 @@ defmodule BDS.CSM009ThumbnailErrorHandlingTest do } do source_path = Path.join(temp_dir, "good.jpg") File.write!(source_path, tiny_jpeg_binary()) - {:ok, good_media} = BDS.Media.import_media(%{project_id: project.id, source_path: source_path}) + + {:ok, good_media} = + BDS.Media.import_media(%{project_id: project.id, source_path: source_path}) corrupt_path = Path.join(temp_dir, "bad.jpg") File.write!(corrupt_path, "corrupt data") - {:ok, bad_media} = BDS.Media.import_media(%{project_id: project.id, source_path: corrupt_path}) + + {:ok, bad_media} = + BDS.Media.import_media(%{project_id: project.id, source_path: corrupt_path}) Enum.each(Map.values(Thumbnails.thumbnail_paths(good_media)), fn path -> File.rm(Path.join(temp_dir, path)) diff --git a/test/bds/csm020_nested_case_test.exs b/test/bds/csm020_nested_case_test.exs index a33b314..eb1d249 100644 --- a/test/bds/csm020_nested_case_test.exs +++ b/test/bds/csm020_nested_case_test.exs @@ -79,7 +79,9 @@ defmodule BDS.CSM020NestedCaseTest do describe "Publishing.handle_call :update_job uses with" do test "source code uses with instead of case" do source = File.read!("lib/bds/publishing.ex") - [func_source] = Regex.scan(~r/def handle_call\(\{:update_job.*?(?=\n def |\n @impl)/s, source) + + [func_source] = + Regex.scan(~r/def handle_call\(\{:update_job.*?(?=\n def |\n @impl)/s, source) assert func_source |> List.first() |> String.contains?("with"), "update_job handler should use with" diff --git a/test/bds/csm031_try_rescue_test.exs b/test/bds/csm031_try_rescue_test.exs index e84a946..16a1492 100644 --- a/test/bds/csm031_try_rescue_test.exs +++ b/test/bds/csm031_try_rescue_test.exs @@ -4,6 +4,7 @@ defmodule BDS.CSM031TryRescueTest do describe "source-level: no inline try/rescue around Liquex.render!" do test "filters.ex has no try/rescue block in render_macro_source" do source = File.read!("lib/bds/rendering/filters.ex") + refute source =~ ~r/try do\s+.*Liquex\.render!/s, "render_macro_source should use safe_liquex_render helper, not inline try/rescue" end @@ -51,6 +52,7 @@ defmodule BDS.CSM031TryRescueTest do test "template_selection.ex uses FileSystem.try_read instead of read_template_file" do source = File.read!("lib/bds/rendering/template_selection.ex") + refute source =~ "read_template_file", "should use FileSystem.try_read, not the raising read_template_file" diff --git a/test/bds/csm032_map_get_pattern_match_test.exs b/test/bds/csm032_map_get_pattern_match_test.exs index 0962ece..9bfe5f7 100644 --- a/test/bds/csm032_map_get_pattern_match_test.exs +++ b/test/bds/csm032_map_get_pattern_match_test.exs @@ -35,12 +35,14 @@ defmodule BDS.CSM032MapGetPatternMatchTest do describe "source-level: overlay.ex uses pattern matching for known structures" do test "delete_details uses pattern matching instead of Map.get" do source = File.read!("lib/bds/desktop/overlay.ex") + refute source =~ "Map.get(delete_details,", "overlay.ex should pattern match delete_details instead of using Map.get" end test "merge_details uses pattern matching instead of Map.get" do source = File.read!("lib/bds/desktop/overlay.ex") + refute source =~ "Map.get(merge,", "overlay.ex should pattern match merge_details instead of using Map.get" end @@ -65,32 +67,40 @@ defmodule BDS.CSM032MapGetPatternMatchTest do describe "source-level: generation pipeline uses dot access for Post struct fields" do test "outputs.ex uses post.language instead of Map.get(post, :language)" do source = File.read!("lib/bds/generation/outputs.ex") + refute source =~ "Map.get(post, :language)", "outputs.ex should use post.language" end test "data.ex uses dot access for Post struct fields in build_published_translation_variant" do source = File.read!("lib/bds/generation/data.ex") + refute source =~ "Map.get(post, :author)", "data.ex should use post.author" + refute source =~ "Map.get(post, :tags", "data.ex should use post.tags" + refute source =~ "Map.get(post, :categories", "data.ex should use post.categories" + refute source =~ "Map.get(post, :template_slug)", "data.ex should use post.template_slug" + refute source =~ "Map.get(post, :do_not_translate", "data.ex should use post.do_not_translate" end test "validation.ex uses post.file_path instead of Map.get(post, :file_path)" do source = File.read!("lib/bds/generation/validation.ex") + refute source =~ "Map.get(post, :file_path)", "validation.ex should use post.file_path" end test "sitemap.ex uses post.do_not_translate instead of Map.get" do source = File.read!("lib/bds/generation/sitemap.ex") + refute source =~ "Map.get(post, :do_not_translate)", "sitemap.ex should use post.do_not_translate" end diff --git a/test/bds/csm033_batch_inserts_test.exs b/test/bds/csm033_batch_inserts_test.exs index ff28a22..848f5b2 100644 --- a/test/bds/csm033_batch_inserts_test.exs +++ b/test/bds/csm033_batch_inserts_test.exs @@ -118,9 +118,7 @@ defmodule BDS.CSM033BatchInsertsTest do assert Enum.all?(posts, fn post -> post.id in indexed end) keys = - BDS.Repo.all( - from(k in BDS.Embeddings.Key, where: k.project_id == ^project.id) - ) + BDS.Repo.all(from(k in BDS.Embeddings.Key, where: k.project_id == ^project.id)) assert length(keys) == 5 labels = Enum.map(keys, & &1.label) |> Enum.sort() @@ -141,7 +139,8 @@ defmodule BDS.CSM033BatchInsertsTest do original_key = BDS.Repo.get_by!(BDS.Embeddings.Key, project_id: project.id, post_id: post.id) - {:ok, _post} = BDS.Posts.update_post(post.id, %{content: "completely different content now"}) + {:ok, _post} = + BDS.Posts.update_post(post.id, %{content: "completely different content now"}) {:ok, rebuilt_ids} = BDS.Embeddings.rebuild_project(project.id) assert post.id in rebuilt_ids @@ -175,9 +174,7 @@ defmodule BDS.CSM033BatchInsertsTest do assert repaired == [post_a.id] keys = - BDS.Repo.all( - from(k in BDS.Embeddings.Key, where: k.project_id == ^project.id) - ) + BDS.Repo.all(from(k in BDS.Embeddings.Key, where: k.project_id == ^project.id)) assert length(keys) == 2 end @@ -206,5 +203,4 @@ defmodule BDS.CSM033BatchInsertsTest do assert key_before.vector == key_after.vector end end - end diff --git a/test/bds/csm034_file_read_bang_test.exs b/test/bds/csm034_file_read_bang_test.exs index abb41af..0f57d7a 100644 --- a/test/bds/csm034_file_read_bang_test.exs +++ b/test/bds/csm034_file_read_bang_test.exs @@ -21,7 +21,9 @@ defmodule BDS.CSM034FileReadBangTest do test "release_packaging.ex has no File.read! or File.write!" do source = File.read!("lib/bds/release_packaging.ex") refute source =~ "File.read!", "release_packaging.ex should use File.read, not File.read!" - refute source =~ "File.write!", "release_packaging.ex should use File.write, not File.write!" + + refute source =~ "File.write!", + "release_packaging.ex should use File.write, not File.write!" end end diff --git a/test/bds/csm035_process_dict_test.exs b/test/bds/csm035_process_dict_test.exs index fe07b4b..a92933c 100644 --- a/test/bds/csm035_process_dict_test.exs +++ b/test/bds/csm035_process_dict_test.exs @@ -49,7 +49,9 @@ defmodule BDS.CSM035ProcessDictTest do match = Regex.run(~r/def sidebar_content\(assigns\).*?\n(.*?)\n/s, source) assert match, "could not find sidebar_content/1" [_, first_line | _] = match - assert first_line =~ "UILocale.put", "sidebar_content/1 must call UILocale.put on its first line" + + assert first_line =~ "UILocale.put", + "sidebar_content/1 must call UILocale.put on its first line" end test "MenuBar.mount/1 calls UILocale.put" do @@ -57,7 +59,9 @@ defmodule BDS.CSM035ProcessDictTest do match = Regex.run(~r/def mount\(menu\).*?\n(.*?)\n/s, source) assert match, "could not find mount/1 in menu_bar.ex" [_, first_line | _] = match - assert first_line =~ "UILocale.put", "MenuBar.mount/1 must call UILocale.put on its first line" + + assert first_line =~ "UILocale.put", + "MenuBar.mount/1 must call UILocale.put on its first line" end end diff --git a/test/bds/desktop/automation_test.exs b/test/bds/desktop/automation_test.exs index 9b3f343..f477a89 100644 --- a/test/bds/desktop/automation_test.exs +++ b/test/bds/desktop/automation_test.exs @@ -100,7 +100,9 @@ defmodule BDS.Desktop.AutomationTest do assert :ok = Automation.reload(session) - snapshot = await(session, &(&1.sidebar_visible == true and &1.sidebar_width >= resized_width - 2)) + snapshot = + await(session, &(&1.sidebar_visible == true and &1.sidebar_width >= resized_width - 2)) + assert snapshot.sidebar_visible == true assert snapshot.sidebar_width >= resized_width - 2 assert snapshot.sidebar_width <= resized_width + 2 diff --git a/test/bds/desktop_test.exs b/test/bds/desktop_test.exs index 55c7ee6..1a03f3d 100644 --- a/test/bds/desktop_test.exs +++ b/test/bds/desktop_test.exs @@ -315,9 +315,15 @@ defmodule BDS.DesktopTest do assert conn.resp_body =~ ~s(data-testid="toggle-sidebar") assert conn.resp_body =~ ~s(data-testid="toggle-panel") assert conn.resp_body =~ ~s(data-testid="toggle-assistant") - assert conn.resp_body =~ ~s(class="activity-bar flex h-full shrink-0 flex-col items-center justify-between") + + assert conn.resp_body =~ + ~s(class="activity-bar flex h-full shrink-0 flex-col items-center justify-between") + assert conn.resp_body =~ ~s(class="sidebar flex min-w-0 flex-1 overflow-hidden") - assert conn.resp_body =~ ~s(class="status-bar flex h-[22px] shrink-0 items-center justify-between gap-2") + + assert conn.resp_body =~ + ~s(class="status-bar flex h-[22px] shrink-0 items-center justify-between gap-2") + assert conn.resp_body =~ ~s(data-phx-main) assert conn.resp_body =~ ~s(href="/assets/app.css") assert conn.resp_body =~ ~s(src="/assets/app.js") diff --git a/test/bds/image_import_pipeline_test.exs b/test/bds/image_import_pipeline_test.exs index b013b75..f5f58d7 100644 --- a/test/bds/image_import_pipeline_test.exs +++ b/test/bds/image_import_pipeline_test.exs @@ -19,7 +19,9 @@ defmodule BDS.ImageImportPipelineTest do File.mkdir_p!(temp_dir) on_exit(fn -> File.rm_rf(temp_dir) end) - {:ok, project} = BDS.Projects.create_project(%{name: "Image Import Test", data_path: temp_dir}) + {:ok, project} = + BDS.Projects.create_project(%{name: "Image Import Test", data_path: temp_dir}) + %{project: project, temp_dir: temp_dir} end @@ -40,7 +42,8 @@ defmodule BDS.ImageImportPipelineTest do ) assert result == - {:ok, ["/Users/test/photo1.jpg", "/Users/test/photo2.png", "/Users/test/photo3.heic"]} + {:ok, + ["/Users/test/photo1.jpg", "/Users/test/photo2.png", "/Users/test/photo3.heic"]} end test "multi selection filters out empty lines" do @@ -51,7 +54,8 @@ defmodule BDS.ImageImportPipelineTest do ) assert result == - {:ok, ["/Users/test/photo1.jpg", "/Users/test/photo2.png", "/Users/test/photo3.heic"]} + {:ok, + ["/Users/test/photo1.jpg", "/Users/test/photo2.png", "/Users/test/photo3.heic"]} end test "multi selection with single file returns list with one element" do diff --git a/test/bds/import_definitions_test.exs b/test/bds/import_definitions_test.exs index 5b6cb97..60a6ad7 100644 --- a/test/bds/import_definitions_test.exs +++ b/test/bds/import_definitions_test.exs @@ -32,7 +32,10 @@ defmodule BDS.ImportDefinitionsTest do result = ImportDefinitions.decode_analysis_result(malicious_json) assert is_map(result) - assert Map.get(result, unknown_key_1) == "val" or Map.get(result, "csm001_fictive_#{unique_suffix}") == "val" + + assert Map.get(result, unknown_key_1) == "val" or + Map.get(result, "csm001_fictive_#{unique_suffix}") == "val" + assert_raise ArgumentError, fn -> String.to_existing_atom(unknown_key_1) end assert_raise ArgumentError, fn -> String.to_existing_atom(unknown_key_2) end end diff --git a/test/bds/map_utils_test.exs b/test/bds/map_utils_test.exs index 6d90cd7..c6a4cb2 100644 --- a/test/bds/map_utils_test.exs +++ b/test/bds/map_utils_test.exs @@ -83,9 +83,10 @@ defmodule BDS.MapUtilsTest do test "safe_atomize_keys does not create atoms for malicious payloads" do unique_suffix = :erlang.unique_integer() - malicious = for i <- 1..500, into: %{} do - {"csm001_malicious_#{i}_#{unique_suffix}", "val"} - end + malicious = + for i <- 1..500, into: %{} do + {"csm001_malicious_#{i}_#{unique_suffix}", "val"} + end result = MapUtils.safe_atomize_keys(malicious) diff --git a/test/bds/posts_test.exs b/test/bds/posts_test.exs index 3b02279..c6e4683 100644 --- a/test/bds/posts_test.exs +++ b/test/bds/posts_test.exs @@ -229,6 +229,7 @@ defmodule BDS.PostsTest do File.write!(old_full, "stale content") import Ecto.Query + BDS.Repo.update_all( from(p in BDS.Posts.Post, where: p.id == ^published.id), set: [file_path: old_relative, content: "edited body"] diff --git a/test/bds/preview_test.exs b/test/bds/preview_test.exs index bb93e50..836b0a2 100644 --- a/test/bds/preview_test.exs +++ b/test/bds/preview_test.exs @@ -424,9 +424,10 @@ defmodule BDS.PreviewTest do assert :ok = BDS.Preview.stop_preview(project.id) end - test "on-demand rendering: published post route renders via template without generated files", %{ - project: project - } do + test "on-demand rendering: published post route renders via template without generated files", + %{ + project: project + } do assert {:ok, _metadata} = Metadata.update_project_metadata(project.id, %{ main_language: "en", @@ -458,9 +459,10 @@ defmodule BDS.PreviewTest do assert :ok = BDS.Preview.stop_preview(project.id) end - test "on-demand rendering: home page renders published posts as list without generated files", %{ - project: project - } do + test "on-demand rendering: home page renders published posts as list without generated files", + %{ + project: project + } do assert {:ok, _metadata} = Metadata.update_project_metadata(project.id, %{ main_language: "en", diff --git a/test/bds/scripts/transforms_test.exs b/test/bds/scripts/transforms_test.exs index a6cc1b0..b200cc6 100644 --- a/test/bds/scripts/transforms_test.exs +++ b/test/bds/scripts/transforms_test.exs @@ -96,7 +96,9 @@ defmodule BDS.Scripts.TransformsTest do data.content = data.content .. "D" return data end - """, enabled: false) + """, + enabled: false + ) transform(other.id, "Foreign", """ function main(data, _ctx) diff --git a/test/bds/template_lookup_priority_test.exs b/test/bds/template_lookup_priority_test.exs index 90bf1b3..eace41c 100644 --- a/test/bds/template_lookup_priority_test.exs +++ b/test/bds/template_lookup_priority_test.exs @@ -142,7 +142,8 @@ defmodule BDS.TemplateLookupPriorityTest do describe "BundledDefaultTemplatesExistOutsideProjectData" do test "single-post bundled template resolves with no Template rows", %{project: project} do - assert [] = BDS.Repo.all(from t in BDS.Templates.Template, where: t.project_id == ^project.id) + assert [] = + BDS.Repo.all(from t in BDS.Templates.Template, where: t.project_id == ^project.id) {:ok, source} = TemplateSelection.load_template_source(project.id, :post, nil) @@ -150,7 +151,8 @@ defmodule BDS.TemplateLookupPriorityTest do end test "post-list bundled template resolves with no Template rows", %{project: project} do - assert [] = BDS.Repo.all(from t in BDS.Templates.Template, where: t.project_id == ^project.id) + assert [] = + BDS.Repo.all(from t in BDS.Templates.Template, where: t.project_id == ^project.id) {:ok, source} = TemplateSelection.load_template_source(project.id, :list, nil) @@ -158,7 +160,8 @@ defmodule BDS.TemplateLookupPriorityTest do end test "not-found bundled template resolves with no Template rows", %{project: project} do - assert [] = BDS.Repo.all(from t in BDS.Templates.Template, where: t.project_id == ^project.id) + assert [] = + BDS.Repo.all(from t in BDS.Templates.Template, where: t.project_id == ^project.id) {:ok, source} = TemplateSelection.load_template_source(project.id, :not_found, nil) diff --git a/test/bds/ui/shell_test.exs b/test/bds/ui/shell_test.exs index b0ed217..a3ce6be 100644 --- a/test/bds/ui/shell_test.exs +++ b/test/bds/ui/shell_test.exs @@ -175,25 +175,39 @@ defmodule BDS.UI.ShellTest do test "phase 3 templates use shared shell and form primitives for common layout" do post_template = - File.read!("/Users/gb/Projects/bDS2/lib/bds/desktop/shell_live/post_editor_html/post_editor.html.heex") + File.read!( + "/Users/gb/Projects/bDS2/lib/bds/desktop/shell_live/post_editor_html/post_editor.html.heex" + ) media_template = - File.read!("/Users/gb/Projects/bDS2/lib/bds/desktop/shell_live/media_editor_html/media_editor.html.heex") + File.read!( + "/Users/gb/Projects/bDS2/lib/bds/desktop/shell_live/media_editor_html/media_editor.html.heex" + ) script_template = - File.read!("/Users/gb/Projects/bDS2/lib/bds/desktop/shell_live/script_editor_html/script_editor.html.heex") + File.read!( + "/Users/gb/Projects/bDS2/lib/bds/desktop/shell_live/script_editor_html/script_editor.html.heex" + ) template_template = - File.read!("/Users/gb/Projects/bDS2/lib/bds/desktop/shell_live/template_editor_html/template_editor.html.heex") + File.read!( + "/Users/gb/Projects/bDS2/lib/bds/desktop/shell_live/template_editor_html/template_editor.html.heex" + ) chat_template = - File.read!("/Users/gb/Projects/bDS2/lib/bds/desktop/shell_live/chat_editor_html/chat_editor.html.heex") + File.read!( + "/Users/gb/Projects/bDS2/lib/bds/desktop/shell_live/chat_editor_html/chat_editor.html.heex" + ) menu_template = - File.read!("/Users/gb/Projects/bDS2/lib/bds/desktop/shell_live/menu_editor_html/menu_editor.html.heex") + File.read!( + "/Users/gb/Projects/bDS2/lib/bds/desktop/shell_live/menu_editor_html/menu_editor.html.heex" + ) settings_template = - File.read!("/Users/gb/Projects/bDS2/lib/bds/desktop/shell_live/settings_editor_html/settings_editor.html.heex") + File.read!( + "/Users/gb/Projects/bDS2/lib/bds/desktop/shell_live/settings_editor_html/settings_editor.html.heex" + ) assert post_template =~ "ui-editor-shell" assert post_template =~ "ui-editor-header" @@ -248,8 +262,12 @@ defmodule BDS.UI.ShellTest do assistant_css = File.read!("/Users/gb/Projects/bDS2/assets/css/assistant.css") menu_css = File.read!("/Users/gb/Projects/bDS2/assets/css/menu_editor.css") - refute editor_css =~ ".post-editor .editor-header,\n.scripts-view-shell.editor .editor-header,\n.templates-view-shell.editor .editor-header {\n display: flex;" - refute editor_css =~ ".post-editor .editor-actions,\n.scripts-view-shell.editor .editor-actions,\n.templates-view-shell.editor .editor-actions {\n display: flex;" + refute editor_css =~ + ".post-editor .editor-header,\n.scripts-view-shell.editor .editor-header,\n.templates-view-shell.editor .editor-header {\n display: flex;" + + refute editor_css =~ + ".post-editor .editor-actions,\n.scripts-view-shell.editor .editor-actions,\n.templates-view-shell.editor .editor-actions {\n display: flex;" + refute editor_css =~ ".post-editor .quick-actions-menu {" refute media_css =~ "[data-testid=\"media-editor\"] .editor-header {" refute media_css =~ "[data-testid=\"media-editor\"] .editor-actions {" @@ -287,9 +305,14 @@ defmodule BDS.UI.ShellTest do assert css =~ ".chat-panel .chat-input-container" assert css =~ ".chat-model-selector-menu" - assert css =~ "@media (max-width: 720px) {\n .chat-panel-header {\n align-items: stretch;\n flex-direction: column;" + assert css =~ + "@media (max-width: 720px) {\n .chat-panel-header {\n align-items: stretch;\n flex-direction: column;" + assert css =~ ".chat-model-selector-wrap {\n width: 100%;" - assert css =~ ".chat-panel .chat-model-selector-button.chat-model-selector-inline {\n justify-content: space-between;\n width: 100%;" + + assert css =~ + ".chat-panel .chat-model-selector-button.chat-model-selector-inline {\n justify-content: space-between;\n width: 100%;" + assert css =~ ".chat-panel .chat-input-container {\n padding: 8px 12px;" end