UNPKG

astro-loader-hashnode

Version:

Astro content loader for seamlessly integrating Hashnode blog posts into your Astro website using the Content Layer API

215 lines (214 loc) 6.44 kB
/** * Astro Loader for Hashnode - Clean, modular API * * This package provides Astro content loaders for Hashnode blog content. * It offers a clean wrapper around the Hashnode GraphQL API with built-in * caching, type safety, and utilities for content transformation. * * @example Basic usage: * ```typescript * import { hashnodeLoader } from 'astro-loader-hashnode'; * * export const collections = { * blog: defineCollection({ * loader: hashnodeLoader({ * publicationHost: 'blog.example.com' * }) * }) * }; * ``` * * @example Advanced usage with multiple loaders: * ```typescript * import { postsLoader, seriesLoader, createHashnodeClient } from 'astro-loader-hashnode'; * * export const collections = { * posts: defineCollection({ * loader: postsLoader({ * publicationHost: 'blog.example.com', * maxPosts: 100, * includeComments: true * }) * }), * series: defineCollection({ * loader: seriesLoader({ * publicationHost: 'blog.example.com', * includePosts: true * }) * }) * }; * ``` */ // Import the loader functions for internal use import { postsLoader, seriesLoader, searchLoader, draftsLoader, } from './loaders/index.js'; // Main loader functions (recommended for most users) export { postsLoader, seriesLoader, searchLoader, draftsLoader, } from './loaders/index.js'; // Loader classes for advanced usage export { PostsLoader, SeriesLoader, SearchLoader, DraftsLoader, BaseHashnodeLoader, createLoader, } from './loaders/index.js'; // API client for custom implementations export { HashnodeClient, createHashnodeClient } from './api/client.js'; // Utility functions for content processing export { // Content utilities extractTextFromHtml, generateExcerpt, calculateReadingTime, countWords, normalizeContent, extractHeadings, generateTableOfContents, processContent, // SEO utilities generateSEOMetadata, optimizeTitle, generateMetaDescription, generateKeywords, generateJSONLD, validateSEOMetadata, // Date utilities formatDate, timeAgo, isRecent, // URL utilities createSlug, normalizeUrl, extractDomain, isValidUrl, makeAbsoluteUrl, buildUrl, parseUrl, cleanUrl, generateSharingUrls, generateCanonicalUrl, extractSlugFromUrl, isSameDomain, generateSitemapEntry, // Combined utilities processPostData, } from './utils/index.js'; // Main loader function (backwards compatibility and simple usage) /** * Create a Hashnode posts loader (primary entry point) * * This is the main function most users should use. It creates a loader * that fetches blog posts from a Hashnode publication. * * @param options - Configuration options for the loader * @returns Astro Loader instance * * @example * ```typescript * import { hashnodeLoader } from 'astro-loader-hashnode'; * * export const collections = { * blog: defineCollection({ * loader: hashnodeLoader({ * publicationHost: 'blog.example.com', * maxPosts: 100, * includeComments: true, * includeCoAuthors: true * }) * }) * }; * ``` */ export function hashnodeLoader(options) { return postsLoader(options); } // Convenience factory functions for common use cases /** * Create multiple loaders for a complete Hashnode setup * * @param baseOptions - Base configuration options * @returns Object with multiple pre-configured loaders * * @example * ```typescript * import { createHashnodeLoaders } from 'astro-loader-hashnode'; * * const { posts, series, drafts } = createHashnodeLoaders({ * publicationHost: 'blog.example.com', * token: process.env.HASHNODE_TOKEN * }); * * export const collections = { * posts: defineCollection({ loader: posts }), * series: defineCollection({ loader: series }), * drafts: defineCollection({ loader: drafts }) * }; * ``` */ export function createHashnodeLoaders(baseOptions) { return { posts: postsLoader(baseOptions), series: seriesLoader(baseOptions), drafts: baseOptions.token ? draftsLoader({ ...baseOptions, token: baseOptions.token, }) : undefined, search: (searchTerms) => searchLoader({ ...baseOptions, searchTerms, }), }; } /** * Create a simple blog setup with just posts * * @param options - Posts loader options * @returns Object with posts loader * * @example * ```typescript * import { createBlog } from 'astro-loader-hashnode'; * * export const collections = createBlog({ * publicationHost: 'blog.example.com' * }); * ``` */ export function createBlog(options) { return { posts: defineCollection({ loader: postsLoader(options), }), }; } /** * Create a complete publication setup with all content types * * @param options - Base loader options * @returns Object with all available loaders * * @example * ```typescript * import { createPublication } from 'astro-loader-hashnode'; * * export const collections = createPublication({ * publicationHost: 'blog.example.com', * token: process.env.HASHNODE_TOKEN, * maxPosts: 200 * }); * ``` */ export function createPublication(baseOptions) { const collections = { posts: defineCollection({ loader: postsLoader(baseOptions), }), series: defineCollection({ loader: seriesLoader({ ...baseOptions, includePosts: true, }), }), }; // Add drafts if token is provided if (baseOptions.token) { collections.drafts = defineCollection({ loader: draftsLoader({ ...baseOptions, token: baseOptions.token, }), }); } return collections; } // Helper function for defineCollection (imported dynamically to avoid circular deps) function defineCollection(config) { return config; } // Package name (kept for diagnostics) export const packageName = 'astro-loader-hashnode'; /** * Check if the loader is compatible with the current Astro version * * @returns boolean indicating compatibility */ export async function checkCompatibility() { try { // Try to import Astro loader types to check compatibility await import('astro/loaders'); return true; } catch { return false; } } // Default export for convenience export default hashnodeLoader;