@alvincrespo/hashnode-content-converter - v0.2.2
    Preparing search index...

    Programmatic API

    Use the converter programmatically in your Node.js applications.

    npm install @alvincrespo/hashnode-content-converter
    
    import { Converter } from '@alvincrespo/hashnode-content-converter';

    const result = await Converter.fromExportFile('./export.json', './blog');
    import { Converter } from '@alvincrespo/hashnode-content-converter';

    const converter = Converter.withProgress((current, total, title) => {
    console.log(`[${current}/${total}] ${title}`);
    });

    const result = await converter.convertAllPosts('./export.json', './blog');
    import { Converter } from '@alvincrespo/hashnode-content-converter';

    const converter = new Converter();

    // Subscribe to events
    converter.on('conversion-starting', ({ post, index, total }) => {
    console.log(`[${index}/${total}] Starting: ${post.title}`);
    });

    converter.on('conversion-completed', ({ result, durationMs }) => {
    console.log(`Completed: ${result.slug} in ${durationMs}ms`);
    });

    converter.on('conversion-error', ({ type, slug, message }) => {
    console.error(`[${type}] Error in ${slug}: ${message}`);
    });

    const result = await converter.convertAllPosts('./export.json', './blog');

    All conversion methods return a ConversionResult:

    interface ConversionResult {
    converted: number; // Successfully converted posts
    skipped: number; // Posts skipped (already exist)
    errors: number; // Posts that failed to convert
    duration: number; // Total duration in milliseconds
    posts: PostConversionResult[]; // Per-post details
    }

    Customize conversion behavior:

    import { Converter, ConversionOptions } from '@alvincrespo/hashnode-content-converter';

    const options: ConversionOptions = {
    skipExisting: true, // Skip posts that already exist
    downloadOptions: {
    downloadDelayMs: 100, // Delay between image downloads
    maxRetries: 3, // Retry failed downloads
    timeoutMs: 30000, // HTTP request timeout
    },
    };

    const result = await Converter.fromExportFile(
    './export.json',
    './blog',
    options
    );

    The Converter emits events during conversion:

    Event Payload Description
    conversion-starting { post, index, total } Post conversion starting
    conversion-completed { result, index, total, durationMs } Post conversion completed
    image-downloaded { filename, postSlug, success, error?, is403? } Image download attempted
    conversion-error { type, slug?, message } Conversion error occurred

    Working with Post Data

    You can also load and work with the export data directly:

    import { readFile } from 'fs/promises';

    // Load export file
    const exportJson = JSON.parse(await readFile('./export.json', 'utf-8'));

    // Access posts
    const posts = exportJson.posts;
    console.log(`Found ${posts.length} posts`);

    // Inspect a post
    const post = posts[0];
    console.log(post.title);
    console.log(post.slug);
    console.log(post.contentMarkdown);

    For advanced use cases, you can use individual processors:

    import {
    PostParser,
    MarkdownTransformer,
    FrontmatterGenerator,
    ImageProcessor,
    ImageDownloader,
    } from '@alvincrespo/hashnode-content-converter';

    // Parse metadata from a post
    const parser = new PostParser();
    const metadata = parser.parse(hashnodePost);

    // Transform markdown content
    const transformer = new MarkdownTransformer();
    const cleanMarkdown = transformer.transform(hashnodePost.contentMarkdown);

    // Generate frontmatter
    const frontmatter = new FrontmatterGenerator();
    const yaml = frontmatter.generate(metadata);

    // Process images
    const imageProcessor = new ImageProcessor(new ImageDownloader());
    const { markdown, images } = await imageProcessor.process(
    cleanMarkdown,
    './images'
    );

    Full TypeScript support with exported types:

    import type {
    HashnodePost,
    ConversionOptions,
    ConversionResult,
    PostConversionResult,
    } from '@alvincrespo/hashnode-content-converter';
    import { Converter } from '@alvincrespo/hashnode-content-converter';

    try {
    const result = await Converter.fromExportFile('./export.json', './blog');

    if (result.errors > 0) {
    console.warn(`${result.errors} posts failed to convert`);

    result.posts
    .filter(p => p.status === 'error')
    .forEach(p => console.error(`${p.slug}: ${p.error}`));
    }
    } catch (error) {
    // Fatal errors (invalid JSON, missing file, etc.)
    console.error('Conversion failed:', error.message);
    }