Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .jules/bolt.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,8 @@

**Learning:** In Next.js/React applications, when grouping items (like schedules or talks) into a `Map` where the values are arrays, using the array spread operator `[...existing, item]` inside a loop (like `forEach` or `map`) causes amortized O(N^2) memory allocations and unnecessary Garbage Collection overhead.
**Action:** Always use `.push()` on the existing array reference if the data structure permits local mutation. For strict ESLint configurations enforcing `no-restricted-syntax`, extract the existing array, push to it, and handle the fallback elegantly (`if (!existing) { map.set(key, [item]); } else { existing.push(item); }`).

## 2024-05-18 - Single-Pass Iteration for Display Elements

**Learning:** When generating page metadata or filtering elements by a URL parameter, it is common to perform an O(N) traversal (like `.flatMap(...).find(...)`) to find a valid display string, and then perform a second O(N) pass to filter the elements. This causes redundant string allocations and nested iterations.
**Action:** Always combine lookup iterations into the primary filtering loop if possible. To maintain strict `no-restricted-syntax` rules that forbid `let` declarations while mutating local tracking variables inside a `.some()` or `.filter()` loop, utilize a `const state = { displayTag?: string }` object and assign values to it when matches are found. This allows safe, early-breaking single-pass algorithms.
33 changes: 27 additions & 6 deletions app/2026/tags/[tag]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,22 @@ export async function generateMetadata({ params }: { params: Promise<{ tag: stri

const sessionGroups = await getTalks(year);
const allTalks = sessionGroups.flatMap((group) => group.sessions);
const displayTag =
allTalks.flatMap(getTagsFromTalk).find((t) => t.replaceAll(" ", "-").toLowerCase() === decodedTag.toLowerCase()) ?? decodedTag.replaceAll("-", " ");
const targetTag = decodedTag.toLowerCase();
const state: { displayTag?: string } = {};
for (const talk of allTalks) {
const talkTags = getTagsFromTalk(talk);
const match = talkTags.some((t) => {
if (t.replaceAll(" ", "-").toLowerCase() === targetTag) {
state.displayTag = t;
return true;
}
return false;
});
if (match) {
break;
}
}
const displayTag = state.displayTag ?? decodedTag.replaceAll("-", " ");
Comment on lines +43 to +58

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

Instead of using an imperative for...of loop with a manual break and mutating a temporary state object, you can achieve the same early-breaking single-pass lookup in a much more idiomatic and declarative way using standard array methods like .find() and .some().

  const targetTag = decodedTag.toLowerCase();
  const matchedTalk = allTalks.find((talk) =>
    getTagsFromTalk(talk).some((t) => t.replaceAll(" ", "-").toLowerCase() === targetTag)
  );
  const displayTag = matchedTalk
    ? (getTagsFromTalk(matchedTalk).find((t) => t.replaceAll(" ", "-").toLowerCase() === targetTag) ?? decodedTag.replaceAll("-", " "))
    : decodedTag.replaceAll("-", " ");


return {
title: `Talks tagged "${displayTag}" - DevBcn ${year}`,
Expand All @@ -58,15 +72,22 @@ export default async function Page({ params }: { params: Promise<{ tag: string }
const sessionGroups = await getTalks(year);
const allTalks = sessionGroups.flatMap((group) => group.sessions);

const displayTag =
allTalks.flatMap(getTagsFromTalk).find((t) => t.replaceAll(" ", "-").toLowerCase() === decodedTag.toLowerCase()) ?? decodedTag.replaceAll("-", " ");
const targetTag = decodedTag.toLowerCase();
const state: { displayTag?: string } = {};

const filteredTalks = allTalks.filter((talk) => {
const talkTags = getTagsFromTalk(talk);

return talkTags.some((t) => t.replaceAll(" ", "-").toLowerCase() === decodedTag.toLowerCase());
return talkTags.some((t) => {
if (t.replaceAll(" ", "-").toLowerCase() === targetTag) {
if (!state.displayTag) state.displayTag = t;
return true;
}
return false;
});
});

const displayTag = state.displayTag ?? decodedTag.replaceAll("-", " ");

if (filteredTalks.length === 0) {
notFound();
}
Comment on lines +75 to 93

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

Mutating external state (like state.displayTag) inside a .filter() callback is a side-effect and an anti-pattern in functional programming. Since filteredTalks is already filtered to only contain talks matching the target tag, you can safely extract the correctly-cased displayTag from the first matched talk (filteredTalks[0]) after the filter operation. This keeps the .filter() callback pure and makes the code much cleaner.

Suggested change
const targetTag = decodedTag.toLowerCase();
const state: { displayTag?: string } = {};
const filteredTalks = allTalks.filter((talk) => {
const talkTags = getTagsFromTalk(talk);
return talkTags.some((t) => t.replaceAll(" ", "-").toLowerCase() === decodedTag.toLowerCase());
return talkTags.some((t) => {
if (t.replaceAll(" ", "-").toLowerCase() === targetTag) {
if (!state.displayTag) state.displayTag = t;
return true;
}
return false;
});
});
const displayTag = state.displayTag ?? decodedTag.replaceAll("-", " ");
if (filteredTalks.length === 0) {
notFound();
}
const targetTag = decodedTag.toLowerCase();
const filteredTalks = allTalks.filter((talk) => {
const talkTags = getTagsFromTalk(talk);
return talkTags.some((t) => t.replaceAll(" ", "-").toLowerCase() === targetTag);
});
if (filteredTalks.length === 0) {
notFound();
}
const displayTag =
getTagsFromTalk(filteredTalks[0]).find((t) => t.replaceAll(" ", "-").toLowerCase() === targetTag) ??
decodedTag.replaceAll("-", " ");

Expand Down
33 changes: 27 additions & 6 deletions app/[year]/tags/[tag]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,22 @@ export async function generateMetadata({ params }: Readonly<TagPageProps>): Prom

const sessionGroups = await getTalks(year);
const allTalks = sessionGroups.flatMap((group) => group.sessions);
const displayTag =
allTalks.flatMap(getTagsFromTalk).find((t) => t.replaceAll(" ", "-").toLowerCase() === decodedTag.toLowerCase()) ?? decodedTag.replaceAll("-", " ");
const targetTag = decodedTag.toLowerCase();
const state: { displayTag?: string } = {};
for (const talk of allTalks) {
const talkTags = getTagsFromTalk(talk);
const match = talkTags.some((t) => {
if (t.replaceAll(" ", "-").toLowerCase() === targetTag) {
state.displayTag = t;
return true;
}
return false;
});
if (match) {
break;
}
}
const displayTag = state.displayTag ?? decodedTag.replaceAll("-", " ");
Comment on lines +50 to +65

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

Instead of using an imperative for...of loop with a manual break and mutating a temporary state object, you can achieve the same early-breaking single-pass lookup in a much more idiomatic and declarative way using standard array methods like .find() and .some().

  const targetTag = decodedTag.toLowerCase();
  const matchedTalk = allTalks.find((talk) =>
    getTagsFromTalk(talk).some((t) => t.replaceAll(" ", "-").toLowerCase() === targetTag)
  );
  const displayTag = matchedTalk
    ? (getTagsFromTalk(matchedTalk).find((t) => t.replaceAll(" ", "-").toLowerCase() === targetTag) ?? decodedTag.replaceAll("-", " "))
    : decodedTag.replaceAll("-", " ");


return {
title: `Talks tagged "${displayTag}" - DevBcn ${year}`,
Expand All @@ -64,15 +78,22 @@ export default async function TagPage({ params }: Readonly<TagPageProps>) {
const sessionGroups = await getTalks(year);
const allTalks = sessionGroups.flatMap((group) => group.sessions);

const displayTag =
allTalks.flatMap(getTagsFromTalk).find((t) => t.replaceAll(" ", "-").toLowerCase() === decodedTag.toLowerCase()) ?? decodedTag.replaceAll("-", " ");
const targetTag = decodedTag.toLowerCase();
const state: { displayTag?: string } = {};

const filteredTalks = allTalks.filter((talk) => {
const talkTags = getTagsFromTalk(talk);

return talkTags.some((t) => t.replaceAll(" ", "-").toLowerCase() === decodedTag.toLowerCase());
return talkTags.some((t) => {
if (t.replaceAll(" ", "-").toLowerCase() === targetTag) {
if (!state.displayTag) state.displayTag = t;
return true;
}
return false;
});
});

const displayTag = state.displayTag ?? decodedTag.replaceAll("-", " ");

if (filteredTalks.length === 0) {
notFound();
}
Comment on lines +81 to 99

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

Mutating external state (like state.displayTag) inside a .filter() callback is a side-effect and an anti-pattern in functional programming. Since filteredTalks is already filtered to only contain talks matching the target tag, you can safely extract the correctly-cased displayTag from the first matched talk (filteredTalks[0]) after the filter operation. This keeps the .filter() callback pure and makes the code much cleaner.

Suggested change
const targetTag = decodedTag.toLowerCase();
const state: { displayTag?: string } = {};
const filteredTalks = allTalks.filter((talk) => {
const talkTags = getTagsFromTalk(talk);
return talkTags.some((t) => t.replaceAll(" ", "-").toLowerCase() === decodedTag.toLowerCase());
return talkTags.some((t) => {
if (t.replaceAll(" ", "-").toLowerCase() === targetTag) {
if (!state.displayTag) state.displayTag = t;
return true;
}
return false;
});
});
const displayTag = state.displayTag ?? decodedTag.replaceAll("-", " ");
if (filteredTalks.length === 0) {
notFound();
}
const targetTag = decodedTag.toLowerCase();
const filteredTalks = allTalks.filter((talk) => {
const talkTags = getTagsFromTalk(talk);
return talkTags.some((t) => t.replaceAll(" ", "-").toLowerCase() === targetTag);
});
if (filteredTalks.length === 0) {
notFound();
}
const displayTag =
getTagsFromTalk(filteredTalks[0]).find((t) => t.replaceAll(" ", "-").toLowerCase() === targetTag) ??
decodedTag.replaceAll("-", " ");

Expand Down
Loading