fix: resolve all lint errors, improve type safety, and remove unused code
Some checks failed
Dev Deployment (Zero Downtime) / deploy-dev (push) Failing after 7m26s
Some checks failed
Dev Deployment (Zero Downtime) / deploy-dev (push) Failing after 7m26s
Remove unused imports, replace `any` types with proper interfaces in directus.ts and i18n-loader.ts, exclude scripts/ and coverage/ from ESLint, and fix unused variable warnings across the codebase. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { getSnippets } from "@/lib/directus";
|
import { getSnippets } from "@/lib/directus";
|
||||||
import { Terminal, ArrowLeft, Code } from "lucide-react";
|
import { Terminal, ArrowLeft } from "lucide-react";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import SnippetsClient from "./SnippetsClient";
|
import SnippetsClient from "./SnippetsClient";
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ jest.mock('next-intl', () => ({
|
|||||||
describe('NotFound', () => {
|
describe('NotFound', () => {
|
||||||
it('renders the 404 page with the new design text', () => {
|
it('renders the 404 page with the new design text', () => {
|
||||||
render(<NotFound />);
|
render(<NotFound />);
|
||||||
expect(screen.getByText("Lost in the Liquid.")).toBeInTheDocument();
|
expect(screen.getByText(/Page not/i)).toBeInTheDocument();
|
||||||
|
expect(screen.getByText(/Found/i)).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ export async function GET(request: NextRequest) {
|
|||||||
return NextResponse.json({
|
return NextResponse.json({
|
||||||
snippets: snippets || []
|
snippets: snippets || []
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (_error) {
|
||||||
return NextResponse.json({ error: 'Failed to fetch snippets' }, { status: 500 });
|
return NextResponse.json({ error: 'Failed to fetch snippets' }, { status: 500 });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import { useState, useEffect } from "react";
|
import { useState, useEffect } from "react";
|
||||||
import { motion } from "framer-motion";
|
import { motion } from "framer-motion";
|
||||||
import { Mail, MapPin, Send, Github, Linkedin, ExternalLink } from "lucide-react";
|
import { Mail, MapPin, Send, Github, Linkedin } from "lucide-react";
|
||||||
import { useToast } from "@/components/Toast";
|
import { useToast } from "@/components/Toast";
|
||||||
import { useLocale, useTranslations } from "next-intl";
|
import { useLocale, useTranslations } from "next-intl";
|
||||||
import type { JSONContent } from "@tiptap/react";
|
import type { JSONContent } from "@tiptap/react";
|
||||||
@@ -152,20 +152,6 @@ const Contact = () => {
|
|||||||
validateForm();
|
validateForm();
|
||||||
};
|
};
|
||||||
|
|
||||||
const contactInfo = [
|
|
||||||
{
|
|
||||||
icon: Mail,
|
|
||||||
title: tInfo("email"),
|
|
||||||
value: "contact@dk0.dev",
|
|
||||||
href: "mailto:contact@dk0.dev",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: MapPin,
|
|
||||||
title: tInfo("location"),
|
|
||||||
value: tInfo("locationValue"),
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section
|
<section
|
||||||
id="contact"
|
id="contact"
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { motion } from "framer-motion";
|
import { motion } from "framer-motion";
|
||||||
import { Github, Linkedin, Mail } from "lucide-react";
|
|
||||||
import { useLocale, useTranslations } from "next-intl";
|
import { useLocale, useTranslations } from "next-intl";
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { motion } from "framer-motion";
|
import { motion } from "framer-motion";
|
||||||
import { Home, ArrowLeft, Search, Ghost, RefreshCcw, Terminal } from "lucide-react";
|
import { ArrowLeft, Search, Terminal } from "lucide-react";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
|
|||||||
@@ -16,6 +16,8 @@ const eslintConfig = [
|
|||||||
".next/**",
|
".next/**",
|
||||||
"out/**",
|
"out/**",
|
||||||
"build/**",
|
"build/**",
|
||||||
|
"coverage/**",
|
||||||
|
"scripts/**",
|
||||||
"next-env.d.ts",
|
"next-env.d.ts",
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -49,8 +49,10 @@ jest.mock('next/server', () => {
|
|||||||
return {
|
return {
|
||||||
...actual,
|
...actual,
|
||||||
NextResponse: {
|
NextResponse: {
|
||||||
json: (data: Record<string, unknown>, init?: unknown) => {
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
json: (data: Record<string, unknown>, init?: any) => {
|
||||||
// Use global Response from whatwg-fetch
|
// Use global Response from whatwg-fetch
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
const res = new (global as any).Response(JSON.stringify(data), init);
|
const res = new (global as any).Response(JSON.stringify(data), init);
|
||||||
res.headers.set('Content-Type', 'application/json');
|
res.headers.set('Content-Type', 'application/json');
|
||||||
return res;
|
return res;
|
||||||
|
|||||||
153
lib/directus.ts
153
lib/directus.ts
@@ -130,7 +130,7 @@ export async function getMessages(locale: string): Promise<Record<string, string
|
|||||||
});
|
});
|
||||||
|
|
||||||
return dictionary;
|
return dictionary;
|
||||||
} catch (error) {
|
} catch (_error) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -168,7 +168,7 @@ export async function getMessage(key: string, locale: string): Promise<string |
|
|||||||
const translations = messages[0]?.translations || [];
|
const translations = messages[0]?.translations || [];
|
||||||
const translation = translations.find((t) => t.languages_code?.code === directusLocale);
|
const translation = translations.find((t) => t.languages_code?.code === directusLocale);
|
||||||
return translation?.value || null;
|
return translation?.value || null;
|
||||||
} catch (error) {
|
} catch (_error) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -279,13 +279,6 @@ const fallbackTechStackData: Record<string, Array<{ key: string; items: string[]
|
|||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
const categoryIconMap: Record<string, string> = {
|
|
||||||
frontend: 'Globe',
|
|
||||||
backend: 'Server',
|
|
||||||
tools: 'Wrench',
|
|
||||||
security: 'Shield'
|
|
||||||
};
|
|
||||||
|
|
||||||
const categoryNames: Record<string, Record<string, string>> = {
|
const categoryNames: Record<string, Record<string, string>> = {
|
||||||
'en-US': {
|
'en-US': {
|
||||||
frontend: 'Frontend & Mobile',
|
frontend: 'Frontend & Mobile',
|
||||||
@@ -413,7 +406,7 @@ export async function getTechStack(locale: string): Promise<TechStackCategory[]
|
|||||||
icon: cat.icon,
|
icon: cat.icon,
|
||||||
sort: cat.sort,
|
sort: cat.sort,
|
||||||
name: cat.translations?.[0]?.name || categoryNames[directusLocale]?.[cat.key] || cat.key,
|
name: cat.translations?.[0]?.name || categoryNames[directusLocale]?.[cat.key] || cat.key,
|
||||||
items: itemsToUse.map((item: any) => ({
|
items: itemsToUse.map((item: TechStackItem) => ({
|
||||||
id: item.id,
|
id: item.id,
|
||||||
name: item.name,
|
name: item.name,
|
||||||
url: item.url,
|
url: item.url,
|
||||||
@@ -424,8 +417,8 @@ export async function getTechStack(locale: string): Promise<TechStackCategory[]
|
|||||||
});
|
});
|
||||||
|
|
||||||
return categoriesWithItems;
|
return categoriesWithItems;
|
||||||
} catch (error) {
|
} catch (_error) {
|
||||||
console.error(`Failed to fetch tech stack (${locale}):`, error);
|
console.error(`Failed to fetch tech stack (${locale}):`, _error);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -468,12 +461,23 @@ export async function getHobbies(locale: string): Promise<Hobby[] | null> {
|
|||||||
{ body: { query } }
|
{ body: { query } }
|
||||||
);
|
);
|
||||||
|
|
||||||
const hobbies = (result as any)?.hobbies;
|
interface HobbiesResult {
|
||||||
|
hobbies: Array<{
|
||||||
|
id: string;
|
||||||
|
key: string;
|
||||||
|
icon: string;
|
||||||
|
translations?: Array<{
|
||||||
|
title?: string;
|
||||||
|
description?: string;
|
||||||
|
}>;
|
||||||
|
}>;
|
||||||
|
}
|
||||||
|
const hobbies = (result as HobbiesResult | null)?.hobbies;
|
||||||
if (!hobbies || hobbies.length === 0) {
|
if (!hobbies || hobbies.length === 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return hobbies.map((hobby: any) => ({
|
return hobbies.map((hobby) => ({
|
||||||
id: hobby.id,
|
id: hobby.id,
|
||||||
key: hobby.key,
|
key: hobby.key,
|
||||||
icon: hobby.icon,
|
icon: hobby.icon,
|
||||||
@@ -533,15 +537,30 @@ export async function getBookReviews(locale: string): Promise<BookReview[] | nul
|
|||||||
{ body: { query } }
|
{ body: { query } }
|
||||||
);
|
);
|
||||||
|
|
||||||
const reviews = (result as any)?.book_reviews;
|
interface BookReviewsResult {
|
||||||
|
book_reviews: Array<{
|
||||||
|
id: string;
|
||||||
|
hardcover_id?: string;
|
||||||
|
book_title: string;
|
||||||
|
book_author: string;
|
||||||
|
book_image?: string;
|
||||||
|
rating: number | string;
|
||||||
|
finished_at?: string;
|
||||||
|
translations?: Array<{
|
||||||
|
review?: string;
|
||||||
|
languages_code?: { code: string };
|
||||||
|
}>;
|
||||||
|
}>;
|
||||||
|
}
|
||||||
|
const reviews = (result as BookReviewsResult | null)?.book_reviews;
|
||||||
if (!reviews || reviews.length === 0) {
|
if (!reviews || reviews.length === 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return reviews.map((item: any) => {
|
return reviews.map((item) => {
|
||||||
// Filter die passende Übersetzung im Code
|
// Filter die passende Übersetzung im Code
|
||||||
const translation = item.translations?.find(
|
const translation = item.translations?.find(
|
||||||
(t: any) => t.languages_code?.code === directusLocale
|
(t) => t.languages_code?.code === directusLocale
|
||||||
) || item.translations?.[0]; // Fallback auf die erste Übersetzung falls locale nicht passt
|
) || item.translations?.[0]; // Fallback auf die erste Übersetzung falls locale nicht passt
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -682,19 +701,52 @@ export async function getProjects(
|
|||||||
{ body: { query } }
|
{ body: { query } }
|
||||||
);
|
);
|
||||||
|
|
||||||
const projects = (result as any)?.projects;
|
interface ProjectsResult {
|
||||||
|
projects: Array<{
|
||||||
|
id: string;
|
||||||
|
slug: string;
|
||||||
|
category?: string;
|
||||||
|
difficulty?: string;
|
||||||
|
tags?: string[] | string;
|
||||||
|
technologies?: string[] | string;
|
||||||
|
challenges?: string;
|
||||||
|
lessons_learned?: string;
|
||||||
|
future_improvements?: string;
|
||||||
|
github?: string;
|
||||||
|
live?: string;
|
||||||
|
image_url?: string;
|
||||||
|
demo_video?: string;
|
||||||
|
performance_metrics?: string;
|
||||||
|
screenshots?: string[] | string;
|
||||||
|
date_created?: string;
|
||||||
|
date_updated?: string;
|
||||||
|
featured?: boolean | number;
|
||||||
|
status?: string;
|
||||||
|
translations?: Array<{
|
||||||
|
title?: string;
|
||||||
|
description?: string;
|
||||||
|
content?: string;
|
||||||
|
meta_description?: string;
|
||||||
|
keywords?: string;
|
||||||
|
button_live_label?: string;
|
||||||
|
button_github_label?: string;
|
||||||
|
languages_code?: { code: string };
|
||||||
|
}>;
|
||||||
|
}>;
|
||||||
|
}
|
||||||
|
const projects = (result as ProjectsResult | null)?.projects;
|
||||||
if (!projects || projects.length === 0) {
|
if (!projects || projects.length === 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return projects.map((proj: any) => {
|
return projects.map((proj) => {
|
||||||
const trans =
|
const trans =
|
||||||
proj.translations?.find((t: any) => t.languages_code?.code === directusLocale) ||
|
proj.translations?.find((t) => t.languages_code?.code === directusLocale) ||
|
||||||
proj.translations?.[0] ||
|
proj.translations?.[0] ||
|
||||||
{};
|
{};
|
||||||
|
|
||||||
// Parse JSON string fields if needed
|
// Parse JSON string fields if needed
|
||||||
const parseTags = (tags: any) => {
|
const parseTags = (tags: string[] | string | undefined): string[] => {
|
||||||
if (!tags) return [];
|
if (!tags) return [];
|
||||||
if (Array.isArray(tags)) return tags;
|
if (Array.isArray(tags)) return tags;
|
||||||
if (typeof tags === 'string') {
|
if (typeof tags === 'string') {
|
||||||
@@ -706,7 +758,7 @@ export async function getProjects(
|
|||||||
}
|
}
|
||||||
return [];
|
return [];
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: proj.id,
|
id: proj.id,
|
||||||
slug: proj.slug,
|
slug: proj.slug,
|
||||||
@@ -734,8 +786,8 @@ export async function getProjects(
|
|||||||
updated_at: proj.date_updated
|
updated_at: proj.date_updated
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (_error) {
|
||||||
console.error(`Failed to fetch projects (${locale}):`, error);
|
console.error(`Failed to fetch projects (${locale}):`, _error);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -797,19 +849,51 @@ export async function getProjectBySlug(
|
|||||||
{ body: { query } }
|
{ body: { query } }
|
||||||
);
|
);
|
||||||
|
|
||||||
const projects = (result as any)?.projects;
|
interface ProjectResult {
|
||||||
|
projects: Array<{
|
||||||
|
id: string;
|
||||||
|
slug: string;
|
||||||
|
category?: string;
|
||||||
|
difficulty?: string;
|
||||||
|
tags?: string[] | string;
|
||||||
|
technologies?: string[] | string;
|
||||||
|
challenges?: string;
|
||||||
|
lessons_learned?: string;
|
||||||
|
future_improvements?: string;
|
||||||
|
github?: string;
|
||||||
|
live?: string;
|
||||||
|
image_url?: string;
|
||||||
|
demo_video?: string;
|
||||||
|
screenshots?: string[] | string;
|
||||||
|
date_created?: string;
|
||||||
|
date_updated?: string;
|
||||||
|
featured?: boolean | number;
|
||||||
|
status?: string;
|
||||||
|
translations?: Array<{
|
||||||
|
title?: string;
|
||||||
|
description?: string;
|
||||||
|
content?: string;
|
||||||
|
meta_description?: string;
|
||||||
|
keywords?: string;
|
||||||
|
button_live_label?: string;
|
||||||
|
button_github_label?: string;
|
||||||
|
languages_code?: { code: string };
|
||||||
|
}>;
|
||||||
|
}>;
|
||||||
|
}
|
||||||
|
const projects = (result as ProjectResult | null)?.projects;
|
||||||
if (!projects || projects.length === 0) {
|
if (!projects || projects.length === 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const proj = projects[0];
|
const proj = projects[0];
|
||||||
const trans =
|
const trans =
|
||||||
proj.translations?.find((t: any) => t.languages_code?.code === directusLocale) ||
|
proj.translations?.find((t) => t.languages_code?.code === directusLocale) ||
|
||||||
proj.translations?.[0] ||
|
proj.translations?.[0] ||
|
||||||
{};
|
{};
|
||||||
|
|
||||||
// Parse JSON string fields if needed
|
// Parse JSON string fields if needed
|
||||||
const parseTags = (tags: any) => {
|
const parseTags = (tags: string[] | string | undefined): string[] => {
|
||||||
if (!tags) return [];
|
if (!tags) return [];
|
||||||
if (Array.isArray(tags)) return tags;
|
if (Array.isArray(tags)) return tags;
|
||||||
if (typeof tags === 'string') {
|
if (typeof tags === 'string') {
|
||||||
@@ -821,7 +905,7 @@ export async function getProjectBySlug(
|
|||||||
}
|
}
|
||||||
return [];
|
return [];
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: proj.id,
|
id: proj.id,
|
||||||
slug: proj.slug,
|
slug: proj.slug,
|
||||||
@@ -847,8 +931,8 @@ export async function getProjectBySlug(
|
|||||||
created_at: proj.date_created,
|
created_at: proj.date_created,
|
||||||
updated_at: proj.date_updated
|
updated_at: proj.date_updated
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (_error) {
|
||||||
console.error(`Failed to fetch project by slug ${slug} (${locale}):`, error);
|
console.error(`Failed to fetch project by slug ${slug} (${locale}):`, _error);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -895,14 +979,17 @@ export async function getSnippets(limit = 10, featured?: boolean): Promise<Snipp
|
|||||||
{ body: { query } }
|
{ body: { query } }
|
||||||
);
|
);
|
||||||
|
|
||||||
const snippets = (result as any)?.snippets;
|
interface SnippetsResult {
|
||||||
|
snippets: Snippet[];
|
||||||
|
}
|
||||||
|
const snippets = (result as SnippetsResult | null)?.snippets;
|
||||||
if (!snippets || snippets.length === 0) {
|
if (!snippets || snippets.length === 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return snippets;
|
return snippets;
|
||||||
} catch (error) {
|
} catch (_error) {
|
||||||
console.error('Failed to fetch snippets:', error);
|
console.error('Failed to fetch snippets:', _error);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,20 +5,20 @@
|
|||||||
* - Caches results (5 min TTL)
|
* - Caches results (5 min TTL)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { getMessage, getContentPage } from './directus';
|
import { getMessage, getContentPage, ContentPage } from './directus';
|
||||||
import enMessages from '@/messages/en.json';
|
import enMessages from '@/messages/en.json';
|
||||||
import deMessages from '@/messages/de.json';
|
import deMessages from '@/messages/de.json';
|
||||||
|
|
||||||
const jsonFallback = { en: enMessages, de: deMessages };
|
const jsonFallback = { en: enMessages, de: deMessages };
|
||||||
|
|
||||||
// Simple in-memory cache
|
// Simple in-memory cache
|
||||||
const cache = new Map<string, { value: any; expires: number }>();
|
const cache = new Map<string, { value: unknown; expires: number }>();
|
||||||
|
|
||||||
function setCached(key: string, value: any, ttlSeconds = 300) {
|
function setCached(key: string, value: unknown, ttlSeconds = 300) {
|
||||||
cache.set(key, { value, expires: Date.now() + ttlSeconds * 1000 });
|
cache.set(key, { value, expires: Date.now() + ttlSeconds * 1000 });
|
||||||
}
|
}
|
||||||
|
|
||||||
function getCached(key: string): any | null {
|
function getCached(key: string): unknown | null {
|
||||||
const hit = cache.get(key);
|
const hit = cache.get(key);
|
||||||
if (!hit) return null;
|
if (!hit) return null;
|
||||||
if (Date.now() > hit.expires) {
|
if (Date.now() > hit.expires) {
|
||||||
@@ -38,7 +38,7 @@ export async function getLocalizedMessage(
|
|||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
const cacheKey = `msg:${key}:${locale}`;
|
const cacheKey = `msg:${key}:${locale}`;
|
||||||
const cached = getCached(cacheKey);
|
const cached = getCached(cacheKey);
|
||||||
if (cached !== null) return cached;
|
if (cached !== null) return cached as string;
|
||||||
|
|
||||||
// Try Directus with requested locale
|
// Try Directus with requested locale
|
||||||
const dbValue = await getMessage(key, locale);
|
const dbValue = await getMessage(key, locale);
|
||||||
@@ -84,11 +84,11 @@ export async function getLocalizedMessage(
|
|||||||
export async function getLocalizedContent(
|
export async function getLocalizedContent(
|
||||||
slug: string,
|
slug: string,
|
||||||
locale: string
|
locale: string
|
||||||
): Promise<any | null> {
|
): Promise<ContentPage | null> {
|
||||||
const cacheKey = `page:${slug}:${locale}`;
|
const cacheKey = `page:${slug}:${locale}`;
|
||||||
const cached = getCached(cacheKey);
|
const cached = getCached(cacheKey);
|
||||||
if (cached !== null) return cached;
|
if (cached !== null) return cached as ContentPage;
|
||||||
if (cached === null && cache.has(cacheKey)) return null; // Already checked, not found
|
if (cache.has(cacheKey)) return null; // Already checked, not found
|
||||||
|
|
||||||
// Try Directus with requested locale
|
// Try Directus with requested locale
|
||||||
const dbPage = await getContentPage(slug, locale);
|
const dbPage = await getContentPage(slug, locale);
|
||||||
@@ -115,14 +115,18 @@ export async function getLocalizedContent(
|
|||||||
* Helper: Get nested value from object
|
* Helper: Get nested value from object
|
||||||
* Example: "nav.home" → obj.nav.home
|
* Example: "nav.home" → obj.nav.home
|
||||||
*/
|
*/
|
||||||
function getNestedValue(obj: any, path: string): any {
|
function getNestedValue(obj: Record<string, unknown>, path: string): string | null {
|
||||||
const keys = path.split('.');
|
const keys = path.split('.');
|
||||||
let value = obj;
|
let value: unknown = obj;
|
||||||
for (const key of keys) {
|
for (const key of keys) {
|
||||||
value = value?.[key];
|
if (value && typeof value === 'object' && key in value) {
|
||||||
|
value = (value as Record<string, unknown>)[key];
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
if (value === undefined) return null;
|
if (value === undefined) return null;
|
||||||
}
|
}
|
||||||
return value;
|
return typeof value === 'string' ? value : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
|
|
||||||
|
/* eslint-disable @typescript-eslint/no-require-imports */
|
||||||
const fetch = require('node-fetch');
|
const fetch = require('node-fetch');
|
||||||
require('dotenv').config();
|
require('dotenv').config();
|
||||||
|
|
||||||
@@ -19,7 +20,7 @@ async function setupSnippets() {
|
|||||||
schema: { name: 'snippets' }
|
schema: { name: 'snippets' }
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
} catch (e) {}
|
} catch (_e) {}
|
||||||
|
|
||||||
// 2. Add Fields
|
// 2. Add Fields
|
||||||
const fields = [
|
const fields = [
|
||||||
@@ -39,7 +40,7 @@ async function setupSnippets() {
|
|||||||
headers: { 'Authorization': `Bearer ${DIRECTUS_TOKEN}`, 'Content-Type': 'application/json' },
|
headers: { 'Authorization': `Bearer ${DIRECTUS_TOKEN}`, 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify(f)
|
body: JSON.stringify(f)
|
||||||
});
|
});
|
||||||
} catch (e) {}
|
} catch (_e) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. Add Example Data
|
// 3. Add Example Data
|
||||||
@@ -69,7 +70,7 @@ async function setupSnippets() {
|
|||||||
headers: { 'Authorization': `Bearer ${DIRECTUS_TOKEN}`, 'Content-Type': 'application/json' },
|
headers: { 'Authorization': `Bearer ${DIRECTUS_TOKEN}`, 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify(s)
|
body: JSON.stringify(s)
|
||||||
});
|
});
|
||||||
} catch (e) {}
|
} catch (_e) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('✅ Snippets setup complete!');
|
console.log('✅ Snippets setup complete!');
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/no-require-imports */
|
||||||
const fetch = require('node-fetch');
|
const fetch = require('node-fetch');
|
||||||
require('dotenv').config();
|
require('dotenv').config();
|
||||||
|
|
||||||
@@ -136,8 +137,8 @@ async function syncHobbies() {
|
|||||||
})
|
})
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (_e) {
|
||||||
console.error(`Failed to sync ${hobby.key}:`, e.message);
|
console.error(`Failed to sync ${hobby.key}:`, _e.message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -154,7 +155,7 @@ async function syncHobbies() {
|
|||||||
headers: { 'Authorization': `Bearer ${DIRECTUS_TOKEN}` }
|
headers: { 'Authorization': `Bearer ${DIRECTUS_TOKEN}` }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch (e) {}
|
} catch (_e) {}
|
||||||
|
|
||||||
console.log('✅ Done!');
|
console.log('✅ Done!');
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user