code icon Code

Apply String Template

Apply a string template to each item in an array

Source Code

import fs from "fs";
import path from "path";

const [inputPath, template, outputField, outputPath] = process.argv.slice(2);

if (!inputPath || !template || !outputField || !outputPath) {
  console.error("Usage: inputPath template outputField outputPath");
  process.exit(1);
}

/**
 * Get nested field value using dot notation
 */
function getField(obj, fieldPath) {
  const parts = fieldPath.split(".");
  let value = obj;
  for (const part of parts) {
    if (value == null) return undefined;
    value = value[part];
  }
  return value;
}

/**
 * Render template by replacing {field} placeholders
 */
function render(template, item) {
  return template.replace(/\{([^}]+)\}/g, (match, field) => {
    const value = getField(item, field.trim());
    return value != null ? String(value) : "";
  });
}

try {
  console.log(`Reading ${inputPath}...`);
  const raw = fs.readFileSync(inputPath, "utf-8");
  const data = JSON.parse(raw);

  const items = Array.isArray(data)
    ? data
    : data.items || data.results || data.messages || [];

  if (!Array.isArray(items)) {
    console.error("Input must be a JSON array or object with array property");
    process.exit(1);
  }

  // Extract field names from template
  const fieldMatches = template.match(/\{([^}]+)\}/g) || [];
  const templateFields = fieldMatches.map((m) => m.slice(1, -1).trim());

  console.log(`Applying template to ${items.length} items...`);
  console.log(`  Template: ${template}`);
  console.log(`  Fields used: ${templateFields.join(", ") || "(none)"}`);

  const result = items.map((item) => {
    const rendered = render(template, item);
    return {
      ...item,
      [outputField]: rendered,
    };
  });

  // Ensure output directory exists
  const dir = path.dirname(outputPath);
  if (dir && dir !== ".") {
    fs.mkdirSync(dir, { recursive: true });
  }

  fs.writeFileSync(outputPath, JSON.stringify(result, null, 2));

  console.log(`\nāœ“ Applied template to ${items.length} items`);
  console.log(`  Output field: ${outputField}`);
  console.log(`  Written to: ${outputPath}`);

  // Show sample
  if (result.length > 0) {
    console.log(`  Sample: ${result[0][outputField]}`);
  }

  console.log(
    JSON.stringify({
      success: true,
      outputPath,
      count: items.length,
      template,
      outputField,
      templateFields,
    })
  );
} catch (error) {
  console.error("Error:", error.message);
  process.exit(1);
}