Skip to content

Custom Package Transformations

ts-pkgx allows you to implement custom transformations for package data to suit your specific needs.

Basic Transformation

You can implement custom transformation logic when processing packages:

typescript
import type { PkgxPackage } from 'ts-pkgx'
import { fetchPantryPackage } from 'ts-pkgx'

async function fetchAndTransform(packageName: string): Promise<PkgxPackage> {
  const { packageInfo } = await fetchPantryPackage(packageName)

  // Add custom metadata
  const enhancedPackage: PkgxPackage = {
    ...packageInfo,
    description: `${packageInfo.description} [Enhanced]`,
    // Add custom fields or modify existing ones
    customCategory: determineCategory(packageInfo),
  }

  return enhancedPackage
}

function determineCategory(pkg: PkgxPackage): string {
  if (pkg.domain.includes('lang'))
    return 'programming-language'
  if (pkg.programs.some(p => p.includes('server')))
    return 'server'
  return 'utility'
}

This approach allows you to extend the basic package information with your own custom fields or modify existing ones.

Transform Packages in Batches

You can apply transformations to multiple packages at once:

typescript
import { fetchPantryPackage } from 'ts-pkgx'
import { fetchPackageListFromGitHub } from 'ts-pkgx/utils'

async function transformPackageBatch(category: string): Promise<PkgxPackage[]> {
  // Get all packages from GitHub
  const allPackages = await fetchPackageListFromGitHub()

  // Filter packages by category (example: languages)
  const filteredPackages = allPackages.filter(pkg =>
    pkg.includes('lang') || ['python', 'node', 'ruby', 'go'].some(lang => pkg.includes(lang))
  )

  // Fetch and transform each package
  const results = await Promise.all(
    filteredPackages.map(async (pkg) => {
      try {
        const { packageInfo } = await fetchPantryPackage(pkg)
        return {
          ...packageInfo,
          category,
          importance: calculateImportance(packageInfo),
        }
      }
      catch (error) {
        console.error(`Error processing ${pkg}:`, error)
        return null
      }
    })
  )

  // Filter out nulls from errors
  return results.filter(Boolean) as PkgxPackage[]
}

function calculateImportance(pkg: PkgxPackage): number {
  let score = 0
  // More programs = higher score
  score += pkg.programs.length * 2
  // More dependencies = higher complexity = higher score
  score += pkg.dependencies.length
  // Has GitHub URL = higher score
  score += pkg.githubUrl ? 5 : 0
  return score
}

// Usage
const languagePackages = await transformPackageBatch('programming-languages')

Custom Package Analysis

You can create functions to analyze package data:

typescript
function analyzePackageDependencies(pkg: PkgxPackage): {
  directDeps: string[]
  hasCyclicDeps: boolean
  depthLevel: number
} {
  // Implementation of dependency analysis
  const directDeps = pkg.dependencies

  // Check for circular dependencies (simplified example)
  const hasCyclicDeps = pkg.dependencies.some((dep) => {
    const depPkg = getPackage(dep)
    return depPkg && depPkg.dependencies.includes(pkg.domain)
  })

  // Calculate dependency depth (simplified)
  const depthLevel = Math.min(3, pkg.dependencies.length > 0 ? 1 : 0)

  return { directDeps, hasCyclicDeps, depthLevel }
}

Extending Package Properties

You can extend the basic PkgxPackage interface with additional properties:

typescript
// Extended package type with custom properties
interface ExtendedPkgxPackage extends PkgxPackage {
  category: string
  popularity: number
  latestVersion: string
  installOptions: {
    global: string
    local: string
  }
}

function extendPackage(pkg: PkgxPackage): ExtendedPkgxPackage {
  return {
    ...pkg,
    category: determineCategory(pkg),
    popularity: calculatePopularity(pkg),
    latestVersion: pkg.versions[0] || 'unknown',
    installOptions: {
      global: `pkgx ${pkg.domain} --global`,
      local: `pkgx ${pkg.domain}`
    }
  }
}

Save Transformed Packages

You can save your transformed packages in custom formats:

typescript
import fs from 'node:fs'
import path from 'node:path'

function saveTransformedPackage(
  pkg: ExtendedPkgxPackage,
  outputDir: string
): void {
  const fileName = `${pkg.domain.replace(/\./g, '_')}.json`
  const filePath = path.join(outputDir, fileName)

  fs.writeFileSync(
    filePath,
    JSON.stringify(pkg, null, 2)
  )

  console.log(`Saved transformed package to ${filePath}`)
}

Transform During Fetch

You can integrate transformations directly into the fetch process:

typescript
// Modify the fetchAndSavePackage function to include transformations
async function fetchTransformAndSavePackage(
  packageName: string,
  outputDir: string,
  transformer: (pkg: PkgxPackage) => PkgxPackage
): Promise<{ success: boolean, filePath?: string }> {
  try {
    // Fetch the package
    const { packageInfo } = await fetchPantryPackage(packageName)

    // Apply the transformation
    const transformedPackage = transformer(packageInfo)

    // Save the transformed package
    const fileName = `${packageName.replace(/\./g, '')}.json`
    const filePath = path.join(outputDir, fileName)

    fs.writeFileSync(filePath, JSON.stringify(transformedPackage, null, 2))

    return { success: true, filePath }
  }
  catch (error) {
    console.error(`Error processing ${packageName}:`, error)
    return { success: false }
  }
}

This customization capability allows you to tailor the package data to your specific requirements.

Released under the MIT License.