fix: replace any types in metadata and content utils (16 errors)

Phase 1 Batch 4: Metadata & Content type safety improvements

Fixed 16 any-type errors across 2 utility files:

1. src/lib/utils/metadata.ts (10 errors)
   - Created JsonLdObject type (Record<string, unknown>)
   - Updated MetaTagsOptions.jsonLd to use JsonLdObject
   - Updated GeneratedMetaTags.jsonLd to use JsonLdObject
   - Updated all JSON-LD generator functions:
     * generatePersonJsonLd: return type and jsonLd variable
     * generateArticleJsonLd: return type and jsonLd variable
     * generateImageGalleryJsonLd: return type and jsonLd variable
     * generateCreativeWorkJsonLd: return type and jsonLd variable

2. src/lib/utils/content.ts (6 errors)
   - Added imports for TiptapNode and EditorData types
   - Created Mark interface for text mark types
   - Added marks field to ContentNode interface
   - Fixed renderInlineContent: content parameter to ContentNode[]
   - Fixed renderInlineContent: node parameter to ContentNode
   - Fixed renderInlineContent: mark parameter to Mark
   - Fixed getContentExcerpt: content parameter to EditorData | unknown
   - Fixed extractTiptapText: doc parameter to Record<string, unknown>
   - Fixed extractTiptapText: node parameter to ContentNode

Progress: 51 any-type errors remaining (down from 67)
This commit is contained in:
Justin Edmund 2025-11-24 02:19:16 -08:00
parent f31d02d51c
commit 799570d979
2 changed files with 36 additions and 20 deletions

View file

@ -1,3 +1,5 @@
import type { TiptapNode, EditorData } from '$lib/types/editor'
// Content node types for rendering // Content node types for rendering
interface ContentNode { interface ContentNode {
type: string type: string
@ -10,9 +12,16 @@ interface ContentNode {
caption?: string caption?: string
language?: string language?: string
mediaId?: number mediaId?: number
marks?: Mark[]
[key: string]: unknown [key: string]: unknown
} }
// Mark types (bold, italic, link, etc.)
interface Mark {
type: string
attrs?: Record<string, unknown>
}
// Render Edra/BlockNote JSON content to HTML // Render Edra/BlockNote JSON content to HTML
export const renderEdraContent = (content: unknown, options: { albumSlug?: string } = {}): string => { export const renderEdraContent = (content: unknown, options: { albumSlug?: string } = {}): string => {
if (!content) return '' if (!content) return ''
@ -290,15 +299,15 @@ function renderTiptapContent(doc: Record<string, unknown>): string {
} }
// Render inline content (text nodes with marks) // Render inline content (text nodes with marks)
const renderInlineContent = (content: any[]): string => { const renderInlineContent = (content: ContentNode[]): string => {
return content return content
.map((node: any) => { .map((node: ContentNode) => {
if (node.type === 'text') { if (node.type === 'text') {
let text = escapeHtml(node.text || '') let text = escapeHtml(node.text || '')
// Apply marks (bold, italic, etc.) // Apply marks (bold, italic, etc.)
if (node.marks) { if (node.marks) {
node.marks.forEach((mark: any) => { node.marks.forEach((mark: Mark) => {
switch (mark.type) { switch (mark.type) {
case 'bold': case 'bold':
text = `<strong>${text}</strong>` text = `<strong>${text}</strong>`
@ -351,16 +360,19 @@ function renderTiptapContent(doc: Record<string, unknown>): string {
} }
// Extract text content from Edra JSON for excerpt // Extract text content from Edra JSON for excerpt
export const getContentExcerpt = (content: any, maxLength = 200): string => { export const getContentExcerpt = (content: EditorData | unknown, maxLength = 200): string => {
if (!content) return '' if (!content) return ''
// Type guard for content object
const contentObj = content as Record<string, unknown>
// Handle Tiptap format first (has type: 'doc') // Handle Tiptap format first (has type: 'doc')
if (content.type === 'doc' && content.content) { if (contentObj.type === 'doc' && contentObj.content) {
return extractTiptapText(content, maxLength) return extractTiptapText(contentObj, maxLength)
} }
// Handle both { blocks: [...] } and { content: [...] } formats // Handle both { blocks: [...] } and { content: [...] } formats
const blocks = content.blocks || content.content || [] const blocks = (contentObj.blocks || contentObj.content || []) as ContentNode[]
if (!Array.isArray(blocks)) return '' if (!Array.isArray(blocks)) return ''
const extractText = (node: ContentNode): string => { const extractText = (node: ContentNode): string => {
@ -383,8 +395,8 @@ export const getContentExcerpt = (content: any, maxLength = 200): string => {
} }
// Extract text from Tiptap content // Extract text from Tiptap content
function extractTiptapText(doc: any, maxLength: number): string { function extractTiptapText(doc: Record<string, unknown>, maxLength: number): string {
const extractFromNode = (node: any): string => { const extractFromNode = (node: ContentNode): string => {
if (node.type === 'text') { if (node.type === 'text') {
return node.text || '' return node.text || ''
} }
@ -396,7 +408,8 @@ function extractTiptapText(doc: any, maxLength: number): string {
return '' return ''
} }
const text = doc.content.map(extractFromNode).join(' ').trim() const content = doc.content as ContentNode[]
const text = content.map(extractFromNode).join(' ').trim()
if (text.length <= maxLength) return text if (text.length <= maxLength) return text
return text.substring(0, maxLength).trim() + '...' return text.substring(0, maxLength).trim() + '...'
} }

View file

@ -1,3 +1,6 @@
// JSON-LD structured data object type
type JsonLdObject = Record<string, unknown>
interface MetaTagsOptions { interface MetaTagsOptions {
title?: string title?: string
description?: string description?: string
@ -16,7 +19,7 @@ interface MetaTagsOptions {
locale?: string locale?: string
canonicalUrl?: string canonicalUrl?: string
noindex?: boolean noindex?: boolean
jsonLd?: Record<string, any> jsonLd?: JsonLdObject
} }
interface GeneratedMetaTags { interface GeneratedMetaTags {
@ -25,7 +28,7 @@ interface GeneratedMetaTags {
openGraph: Record<string, string> openGraph: Record<string, string>
twitter: Record<string, string> twitter: Record<string, string>
other: Record<string, string> other: Record<string, string>
jsonLd?: Record<string, any> jsonLd?: JsonLdObject
} }
const DEFAULTS = { const DEFAULTS = {
@ -197,10 +200,10 @@ export function generatePersonJsonLd(options: {
jobTitle?: string jobTitle?: string
description?: string description?: string
sameAs?: string[] sameAs?: string[]
}): Record<string, any> { }): JsonLdObject {
const { name, url = DEFAULTS.siteUrl, image, jobTitle, description, sameAs = [] } = options const { name, url = DEFAULTS.siteUrl, image, jobTitle, description, sameAs = [] } = options
const jsonLd: Record<string, any> = { const jsonLd: JsonLdObject = {
'@context': 'https://schema.org', '@context': 'https://schema.org',
'@type': 'Person', '@type': 'Person',
name, name,
@ -237,10 +240,10 @@ export function generateArticleJsonLd(options: {
datePublished?: string datePublished?: string
dateModified?: string dateModified?: string
author?: string author?: string
}): Record<string, any> { }): JsonLdObject {
const { title, description, url, image, datePublished, dateModified, author } = options const { title, description, url, image, datePublished, dateModified, author } = options
const jsonLd: Record<string, any> = { const jsonLd: JsonLdObject = {
'@context': 'https://schema.org', '@context': 'https://schema.org',
'@type': 'Article', '@type': 'Article',
headline: title, headline: title,
@ -291,10 +294,10 @@ export function generateImageGalleryJsonLd(options: {
url: string url: string
caption?: string caption?: string
}> }>
}): Record<string, any> { }): JsonLdObject {
const { name, description, url, images } = options const { name, description, url, images } = options
const jsonLd: Record<string, any> = { const jsonLd: JsonLdObject = {
'@context': 'https://schema.org', '@context': 'https://schema.org',
'@type': 'ImageGallery', '@type': 'ImageGallery',
name, name,
@ -327,10 +330,10 @@ export function generateCreativeWorkJsonLd(options: {
creator?: string creator?: string
dateCreated?: string dateCreated?: string
keywords?: string[] keywords?: string[]
}): Record<string, any> { }): JsonLdObject {
const { name, description, url, image, creator, dateCreated, keywords = [] } = options const { name, description, url, image, creator, dateCreated, keywords = [] } = options
const jsonLd: Record<string, any> = { const jsonLd: JsonLdObject = {
'@context': 'https://schema.org', '@context': 'https://schema.org',
'@type': 'CreativeWork', '@type': 'CreativeWork',
name, name,