Skip to content

Commit 9734f2e

Browse files
committed
fix: add TypeScript types and improve git hooks
- Export Kit and Tool types from lib/content - Add explicit type annotations to all map/filter/find callbacks - Remove commitlint job from CI (already in pre-commit hook) - Add typecheck to pre-commit hook to catch type errors earlier - Fixes implicit 'any' TypeScript errors
1 parent 852d669 commit 9734f2e

File tree

14 files changed

+94
-71
lines changed

14 files changed

+94
-71
lines changed

.github/workflows/ci.yml

Lines changed: 29 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -12,70 +12,74 @@ jobs:
1212
runs-on: ubuntu-latest
1313
steps:
1414
- uses: actions/checkout@v4
15-
15+
1616
- name: Setup pnpm
1717
uses: pnpm/action-setup@v4
1818
with:
1919
version: 9
20-
20+
2121
- name: Setup Node.js
2222
uses: actions/setup-node@v4
2323
with:
2424
node-version: 20
2525
cache: 'pnpm'
26-
26+
2727
- name: Install dependencies
2828
run: pnpm install --frozen-lockfile
29-
30-
- name: Run Biome lint
29+
30+
- name: Run lint
3131
run: pnpm lint
3232

33-
typecheck:
34-
name: Typecheck
33+
build:
34+
name: Build
3535
runs-on: ubuntu-latest
3636
steps:
3737
- uses: actions/checkout@v4
38-
38+
3939
- name: Setup pnpm
4040
uses: pnpm/action-setup@v4
4141
with:
4242
version: 9
43-
43+
4444
- name: Setup Node.js
4545
uses: actions/setup-node@v4
4646
with:
4747
node-version: 20
4848
cache: 'pnpm'
49-
49+
5050
- name: Install dependencies
5151
run: pnpm install --frozen-lockfile
52-
53-
- name: Run TypeScript typecheck
54-
run: pnpm typecheck
5552

56-
build:
57-
name: Build
53+
- name: Build
54+
run: pnpm build
55+
56+
typecheck:
57+
name: Typecheck
5858
runs-on: ubuntu-latest
59+
needs: build
5960
steps:
6061
- uses: actions/checkout@v4
61-
62+
6263
- name: Setup pnpm
6364
uses: pnpm/action-setup@v4
6465
with:
6566
version: 9
66-
67+
6768
- name: Setup Node.js
6869
uses: actions/setup-node@v4
6970
with:
7071
node-version: 20
7172
cache: 'pnpm'
72-
73+
7374
- name: Install dependencies
7475
run: pnpm install --frozen-lockfile
75-
76-
- name: Build project
76+
77+
- name: Build (to generate .velite)
7778
run: pnpm build
7879

80+
- name: Run typecheck
81+
run: pnpm typecheck
82+
7983
commitlint:
8084
name: Commitlint
8185
runs-on: ubuntu-latest
@@ -84,21 +88,20 @@ jobs:
8488
- uses: actions/checkout@v4
8589
with:
8690
fetch-depth: 0
87-
91+
8892
- name: Setup pnpm
8993
uses: pnpm/action-setup@v4
9094
with:
9195
version: 9
92-
96+
9397
- name: Setup Node.js
9498
uses: actions/setup-node@v4
9599
with:
96100
node-version: 20
97101
cache: 'pnpm'
98-
102+
99103
- name: Install dependencies
100104
run: pnpm install --frozen-lockfile
101-
102-
- name: Validate PR commits
103-
run: pnpm commitlint --from ${{ github.event.pull_request.base.sha }} --to ${{ github.sha }} --verbose
104105

106+
- name: Validate commits
107+
run: npx commitlint --from ${{ github.event.pull_request.base.sha }} --to ${{ github.event.pull_request.head.sha }} --verbose

.husky/pre-commit

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
#!/bin/sh
22
pnpm lint-staged
3+
pnpm typecheck
34

app/globals.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@
4848
* {
4949
border-color: hsl(var(--border));
5050
}
51-
51+
5252
body {
5353
background-color: hsl(var(--background));
5454
color: hsl(var(--foreground));

app/kits/[slug]/page.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { MDXContent } from "@/components/mdx-content";
1010
import { Badge } from "@/components/ui/badge";
1111
import { Button } from "@/components/ui/button";
1212
import { Separator } from "@/components/ui/separator";
13-
import { kits } from "@/lib/content";
13+
import { type Kit, kits } from "@/lib/content";
1414

1515
interface KitPageProps {
1616
params: Promise<{
@@ -19,14 +19,14 @@ interface KitPageProps {
1919
}
2020

2121
export async function generateStaticParams() {
22-
return kits.map((kit) => ({
22+
return kits.map((kit: Kit) => ({
2323
slug: kit.slug,
2424
}));
2525
}
2626

2727
export async function generateMetadata(props: KitPageProps) {
2828
const params = await props.params;
29-
const kit = kits.find((k) => k.slug === params.slug);
29+
const kit = kits.find((k: Kit) => k.slug === params.slug);
3030

3131
if (!kit) {
3232
return {
@@ -42,7 +42,7 @@ export async function generateMetadata(props: KitPageProps) {
4242

4343
export default async function KitPage(props: KitPageProps) {
4444
const params = await props.params;
45-
const kit = kits.find((k) => k.slug === params.slug);
45+
const kit = kits.find((k: Kit) => k.slug === params.slug);
4646

4747
if (!kit) {
4848
notFound();

app/kits/page.tsx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,28 +3,28 @@
33
import { useState } from "react";
44
import { KitCard } from "@/components/kit-card";
55
import { Button } from "@/components/ui/button";
6-
import { kits } from "@/lib/content";
6+
import { type Kit, kits } from "@/lib/content";
77

88
type StatusFilter = "all" | "stable" | "experimental" | "deprecated";
99

1010
export default function KitsPage() {
1111
const [filter, setFilter] = useState<StatusFilter>("all");
1212

13-
const sortedKits = kits.sort((a, b) => {
13+
const sortedKits = kits.sort((a: Kit, b: Kit) => {
1414
if (a.order !== b.order) return a.order - b.order;
1515
return a.title.localeCompare(b.title);
1616
});
1717

1818
const filteredKits =
1919
filter === "all"
2020
? sortedKits
21-
: sortedKits.filter((kit) => kit.status === filter);
21+
: sortedKits.filter((kit: Kit) => kit.status === filter);
2222

2323
const counts = {
2424
all: kits.length,
25-
stable: kits.filter((k) => k.status === "stable").length,
26-
experimental: kits.filter((k) => k.status === "experimental").length,
27-
deprecated: kits.filter((k) => k.status === "deprecated").length,
25+
stable: kits.filter((k: Kit) => k.status === "stable").length,
26+
experimental: kits.filter((k: Kit) => k.status === "experimental").length,
27+
deprecated: kits.filter((k: Kit) => k.status === "deprecated").length,
2828
};
2929

3030
return (
@@ -80,7 +80,7 @@ export default function KitsPage() {
8080
</div>
8181

8282
<div className="grid gap-3 sm:gap-4 grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 min-w-0">
83-
{filteredKits.map((kit) => (
83+
{filteredKits.map((kit: Kit) => (
8484
<KitCard key={kit.slug} kit={kit} />
8585
))}
8686
</div>

app/page.tsx

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,26 +4,26 @@ import { KitCard } from "@/components/kit-card";
44
import { ToolCard } from "@/components/tool-card";
55
import { Button } from "@/components/ui/button";
66
import { Separator } from "@/components/ui/separator";
7-
import { kits, tools } from "@/lib/content";
7+
import { type Kit, kits, type Tool, tools } from "@/lib/content";
88

99
export default function Home() {
10-
const sortedKits = kits.sort((a, b) => {
10+
const sortedKits = kits.sort((a: Kit, b: Kit) => {
1111
if (a.order !== b.order) return a.order - b.order;
1212
return a.title.localeCompare(b.title);
1313
});
1414

15-
const sortedTools = tools.sort((a, b) => {
15+
const sortedTools = tools.sort((a: Tool, b: Tool) => {
1616
if (a.order !== b.order) return a.order - b.order;
1717
return a.title.localeCompare(b.title);
1818
});
1919

20-
const featuredKits = sortedKits.filter((kit) => kit.featured);
21-
const featuredTools = sortedTools.filter((tool) => tool.featured);
20+
const featuredKits = sortedKits.filter((kit: Kit) => kit.featured);
21+
const featuredTools = sortedTools.filter((tool: Tool) => tool.featured);
2222
const hasFeatured = featuredKits.length > 0 || featuredTools.length > 0;
2323

2424
// Filter out featured items from regular sections
25-
const regularKits = sortedKits.filter((kit) => !kit.featured);
26-
const regularTools = sortedTools.filter((tool) => !tool.featured);
25+
const regularKits = sortedKits.filter((kit: Kit) => !kit.featured);
26+
const regularTools = sortedTools.filter((tool: Tool) => !tool.featured);
2727

2828
return (
2929
<div className="container px-4 sm:px-6 py-8 md:py-12 lg:py-16 max-w-full">
@@ -56,10 +56,10 @@ export default function Home() {
5656
</div>
5757
</div>
5858
<div className="grid gap-3 sm:gap-4 grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 min-w-0">
59-
{featuredKits.map((kit) => (
59+
{featuredKits.map((kit: Kit) => (
6060
<KitCard key={kit.slug} kit={kit} />
6161
))}
62-
{featuredTools.map((tool) => (
62+
{featuredTools.map((tool: Tool) => (
6363
<ToolCard key={tool.slug} tool={tool} />
6464
))}
6565
</div>
@@ -90,7 +90,7 @@ export default function Home() {
9090
)}
9191
</div>
9292
<div className="grid gap-3 sm:gap-4 grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 min-w-0">
93-
{regularKits.slice(0, 6).map((kit) => (
93+
{regularKits.slice(0, 6).map((kit: Kit) => (
9494
<KitCard key={kit.slug} kit={kit} />
9595
))}
9696
</div>
@@ -119,7 +119,7 @@ export default function Home() {
119119
)}
120120
</div>
121121
<div className="grid gap-3 sm:gap-4 grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 min-w-0">
122-
{regularTools.slice(0, 6).map((tool) => (
122+
{regularTools.slice(0, 6).map((tool: Tool) => (
123123
<ToolCard key={tool.slug} tool={tool} />
124124
))}
125125
</div>

app/tools/[slug]/page.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { MDXContent } from "@/components/mdx-content";
1111
import { Badge } from "@/components/ui/badge";
1212
import { Button } from "@/components/ui/button";
1313
import { Separator } from "@/components/ui/separator";
14-
import { kits, tools } from "@/lib/content";
14+
import { type Kit, kits, type Tool, tools } from "@/lib/content";
1515

1616
interface ToolPageProps {
1717
params: Promise<{
@@ -20,14 +20,14 @@ interface ToolPageProps {
2020
}
2121

2222
export async function generateStaticParams() {
23-
return tools.map((tool) => ({
23+
return tools.map((tool: Tool) => ({
2424
slug: tool.slug,
2525
}));
2626
}
2727

2828
export async function generateMetadata(props: ToolPageProps) {
2929
const params = await props.params;
30-
const tool = tools.find((t) => t.slug === params.slug);
30+
const tool = tools.find((t: Tool) => t.slug === params.slug);
3131

3232
if (!tool) {
3333
return {
@@ -43,7 +43,7 @@ export async function generateMetadata(props: ToolPageProps) {
4343

4444
export default async function ToolPage(props: ToolPageProps) {
4545
const params = await props.params;
46-
const tool = tools.find((t) => t.slug === params.slug);
46+
const tool = tools.find((t: Tool) => t.slug === params.slug);
4747

4848
if (!tool) {
4949
notFound();
@@ -58,7 +58,7 @@ export default async function ToolPage(props: ToolPageProps) {
5858

5959
// Get kit details for builtOn
6060
const builtOnKits = tool.builtOn
61-
.map((slug: string) => kits.find((k) => k.slug === slug))
61+
.map((slug: string) => kits.find((k: Kit) => k.slug === slug))
6262
.filter(Boolean);
6363

6464
return (
@@ -171,7 +171,7 @@ export default async function ToolPage(props: ToolPageProps) {
171171
<span>Built on</span>
172172
</div>
173173
<div className="flex flex-wrap gap-2">
174-
{builtOnKits.map((kit: any) =>
174+
{builtOnKits.map((kit: Kit | undefined) =>
175175
kit ? (
176176
<Button key={kit.slug} asChild variant="outline" size="sm">
177177
<Link href={kit.url} className="text-xs sm:text-sm">

app/tools/page.tsx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,28 +3,28 @@
33
import { useState } from "react";
44
import { ToolCard } from "@/components/tool-card";
55
import { Button } from "@/components/ui/button";
6-
import { tools } from "@/lib/content";
6+
import { type Tool, tools } from "@/lib/content";
77

88
type StatusFilter = "all" | "stable" | "experimental" | "deprecated";
99

1010
export default function ToolsPage() {
1111
const [filter, setFilter] = useState<StatusFilter>("all");
1212

13-
const sortedTools = tools.sort((a, b) => {
13+
const sortedTools = tools.sort((a: Tool, b: Tool) => {
1414
if (a.order !== b.order) return a.order - b.order;
1515
return a.title.localeCompare(b.title);
1616
});
1717

1818
const filteredTools =
1919
filter === "all"
2020
? sortedTools
21-
: sortedTools.filter((tool) => tool.status === filter);
21+
: sortedTools.filter((tool: Tool) => tool.status === filter);
2222

2323
const counts = {
2424
all: tools.length,
25-
stable: tools.filter((t) => t.status === "stable").length,
26-
experimental: tools.filter((t) => t.status === "experimental").length,
27-
deprecated: tools.filter((t) => t.status === "deprecated").length,
25+
stable: tools.filter((t: Tool) => t.status === "stable").length,
26+
experimental: tools.filter((t: Tool) => t.status === "experimental").length,
27+
deprecated: tools.filter((t: Tool) => t.status === "deprecated").length,
2828
};
2929

3030
return (
@@ -80,7 +80,7 @@ export default function ToolsPage() {
8080
</div>
8181

8282
<div className="grid gap-3 sm:gap-4 grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 min-w-0">
83-
{filteredTools.map((tool) => (
83+
{filteredTools.map((tool: Tool) => (
8484
<ToolCard key={tool.slug} tool={tool} />
8585
))}
8686
</div>

components/code-block.tsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,14 @@ function extractTextContent(node: React.ReactNode): string {
6161
if (typeof node === "string") return node;
6262
if (typeof node === "number") return String(node);
6363
if (Array.isArray(node)) return node.map(extractTextContent).join("");
64-
if (node && typeof node === "object" && "props" in node) {
65-
return extractTextContent((node as any).props.children);
64+
if (
65+
node &&
66+
typeof node === "object" &&
67+
"props" in node &&
68+
typeof (node as { props?: unknown }).props === "object"
69+
) {
70+
const element = node as { props: { children?: React.ReactNode } };
71+
return extractTextContent(element.props.children);
6672
}
6773
return "";
6874
}

0 commit comments

Comments
 (0)