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:
parent
f31d02d51c
commit
799570d979
2 changed files with 36 additions and 20 deletions
|
|
@ -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() + '...'
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue