UNPKG

@dscodotco/theme-cli

Version:

A CLI tool for developing Shopify themes

187 lines (167 loc) 4.57 kB
import Shopify from "shopify-api-node"; import path from "path"; import fs from "fs/promises"; import { ThemeManager } from "./theme-manager.js"; import { createLogger } from "../logger.js"; const logger = createLogger("theme-api"); export interface ThemePage { path: string; template: string; type: | "static" | "collections" | "pages" | "blogs" | "products" | "collections"; title: string; } export interface ThemeMetadata { pages: ThemePage[]; templates: { [key: string]: { path: string; sections: string[]; snippets: string[]; }; }; assets: string[]; config: { settings_schema: any; settings_data: any; }; } export class ThemeAPI { private shopify: Shopify; private themeManager: ThemeManager; private themeDir: string; private metadata: ThemeMetadata | null = null; constructor(shopify: Shopify, themeManager: ThemeManager, themeDir: string) { this.shopify = shopify; this.themeManager = themeManager; this.themeDir = themeDir; logger.info(`ThemeAPI initialized with theme directory: ${themeDir}`); logger.info( `Using Shopify client with shop: ${(shopify as any).options.shopName}` ); } async getPages(): Promise<ThemePage[]> { const templates = await this.getStaticTemplates(); const pages: ThemePage[] = []; // Add static pages pages.push({ path: "/", template: "index", type: "static", title: "Home", }); // Add product pages if template exists if (templates.includes("product")) { pages.push({ path: "/products/example-product", template: "product", type: "products", title: "Example Product", }); } // Add collection pages if template exists if (templates.includes("collection")) { pages.push({ path: "/collections/example-collection", template: "collection", type: "collections", title: "Example Collection", }); } // Add cart page if template exists if (templates.includes("cart")) { pages.push({ path: "/cart", template: "cart", type: "static", title: "Cart", }); } // Add search page if template exists if (templates.includes("search")) { pages.push({ path: "/search", template: "search", type: "static", title: "Search", }); } // Add contact page if it exists if (templates.includes("page.contact")) { pages.push({ path: "/pages/contact", template: "page.contact", type: "pages", title: "Contact", }); } // Add blog page if it exists if (templates.includes("blog")) { pages.push({ path: "/blogs/news", template: "blog", type: "blogs", title: "Blog", }); } return pages; } private async getStaticTemplates(): Promise<string[]> { try { const templateDir = path.join(this.themeDir, "templates"); logger.info(`Reading template directory: ${templateDir}`); const files = await fs.readdir(templateDir); const templates = files .filter((file) => file.endsWith(".json")) .map((file) => file.replace(".json", "")); logger.info(`Found templates: ${templates.join(", ")}`); return templates; } catch (error) { logger.error(`Failed to read templates: ${(error as Error).message}`); throw error; } } async getMetadata(): Promise<ThemeMetadata> { if (this.metadata) { logger.info("Returning cached metadata"); return this.metadata; } try { const pages = await this.getPages(); this.metadata = { pages, templates: {}, assets: [], config: { settings_schema: [], settings_data: {}, }, }; return this.metadata; } catch (error) { logger.error("Failed to fetch metadata:"); logger.error(error); throw error; } } async getPageMetadata(path: string): Promise<ThemePage | null> { logger.info(`Getting metadata for page: ${path}`); const pages = await this.getPages(); const page = pages.find((p) => p.path === path); if (page) { logger.info(`Found metadata for page: ${JSON.stringify(page, null, 2)}`); } else { logger.warn(`No metadata found for page: ${path}`); } return page || null; } invalidateCache() { logger.info("Invalidating metadata cache"); this.metadata = null; } }