image-asset-manager
Version:
A comprehensive image asset management tool for frontend projects
418 lines (409 loc) • 17 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.TypeDefinitionGenerator = void 0;
const path_1 = __importDefault(require("path"));
class TypeDefinitionGenerator {
/**
* Generate TypeScript type definitions for all image files
*/
async generateTypeDefinitions(files) {
const typeDefinitions = [];
// Add header comment
typeDefinitions.push("// Auto-generated image asset type definitions");
typeDefinitions.push("// Do not edit this file manually");
typeDefinitions.push("");
// Handle empty files array
if (files.length === 0) {
typeDefinitions.push("// Image path types");
typeDefinitions.push("");
typeDefinitions.push("// Image path constants");
typeDefinitions.push("");
typeDefinitions.push("// Union type for all image paths");
typeDefinitions.push("export type ImageAssetPath = never;");
typeDefinitions.push("");
typeDefinitions.push("// Image metadata interface");
typeDefinitions.push("export interface ImageAssetInfo {");
typeDefinitions.push(" path: string;");
typeDefinitions.push(" name: string;");
typeDefinitions.push(" extension: string;");
typeDefinitions.push(" size: number;");
typeDefinitions.push(" dimensions: { width: number; height: number };");
typeDefinitions.push(" category: string;");
typeDefinitions.push("}");
typeDefinitions.push("");
typeDefinitions.push("// Image registry with metadata");
typeDefinitions.push("export const IMAGE_REGISTRY: Record<ImageAssetPath, ImageAssetInfo> = {");
typeDefinitions.push("};");
typeDefinitions.push("");
typeDefinitions.push("// Helper functions");
typeDefinitions.push("export function getImageInfo(path: ImageAssetPath): ImageAssetInfo {");
typeDefinitions.push(" return IMAGE_REGISTRY[path];");
typeDefinitions.push("}");
typeDefinitions.push("");
typeDefinitions.push("export function getAllImages(): ImageAssetPath[] {");
typeDefinitions.push(" return Object.keys(IMAGE_REGISTRY) as ImageAssetPath[];");
typeDefinitions.push("}");
typeDefinitions.push("");
typeDefinitions.push("export function getImagesByCategory(category: string): ImageAssetPath[] {");
typeDefinitions.push(" return Object.entries(IMAGE_REGISTRY)");
typeDefinitions.push(" .filter(([, info]) => info.category === category)");
typeDefinitions.push(" .map(([path]) => path as ImageAssetPath);");
typeDefinitions.push("}");
return typeDefinitions.join("\n");
}
// Generate individual image types
const imageTypes = [];
const imageConstants = [];
files.forEach((file) => {
const typeName = this.generateTypeName(file);
const constantName = this.generateConstantName(file);
const relativePath = file.relativePath;
// Create type definition
imageTypes.push(`export type ${typeName} = "${relativePath}";`);
// Create constant
imageConstants.push(`export const ${constantName}: ${typeName} = "${relativePath}";`);
});
// Add image types section
typeDefinitions.push("// Image path types");
typeDefinitions.push(...imageTypes);
typeDefinitions.push("");
// Add image constants section
typeDefinitions.push("// Image path constants");
typeDefinitions.push(...imageConstants);
typeDefinitions.push("");
// Generate union type for all images
const allImageTypes = files
.map((file) => this.generateTypeName(file))
.join(" | ");
typeDefinitions.push("// Union type for all image paths");
typeDefinitions.push(`export type ImageAssetPath = ${allImageTypes};`);
typeDefinitions.push("");
// Generate image metadata interface
typeDefinitions.push("// Image metadata interface");
typeDefinitions.push("export interface ImageAssetInfo {");
typeDefinitions.push(" path: string;");
typeDefinitions.push(" name: string;");
typeDefinitions.push(" extension: string;");
typeDefinitions.push(" size: number;");
typeDefinitions.push(" dimensions: { width: number; height: number };");
typeDefinitions.push(" category: string;");
typeDefinitions.push("}");
typeDefinitions.push("");
// Generate image registry
const imageRegistry = this.generateImageRegistry(files);
typeDefinitions.push("// Image registry with metadata");
typeDefinitions.push("export const IMAGE_REGISTRY: Record<ImageAssetPath, ImageAssetInfo> = {");
typeDefinitions.push(imageRegistry);
typeDefinitions.push("};");
typeDefinitions.push("");
// Generate helper functions
typeDefinitions.push("// Helper functions");
typeDefinitions.push("export function getImageInfo(path: ImageAssetPath): ImageAssetInfo {");
typeDefinitions.push(" return IMAGE_REGISTRY[path];");
typeDefinitions.push("}");
typeDefinitions.push("");
typeDefinitions.push("export function getAllImages(): ImageAssetPath[] {");
typeDefinitions.push(" return Object.keys(IMAGE_REGISTRY) as ImageAssetPath[];");
typeDefinitions.push("}");
typeDefinitions.push("");
typeDefinitions.push("export function getImagesByCategory(category: string): ImageAssetPath[] {");
typeDefinitions.push(" return Object.entries(IMAGE_REGISTRY)");
typeDefinitions.push(" .filter(([, info]) => info.category === category)");
typeDefinitions.push(" .map(([path]) => path as ImageAssetPath);");
typeDefinitions.push("}");
return typeDefinitions.join("\n");
}
/**
* Generate import file for easy access to all image assets
*/
async generateImportFile(files) {
const imports = [];
// Add header comment
imports.push("// Auto-generated image asset imports");
imports.push("// Do not edit this file manually");
imports.push("");
// Import type definitions
imports.push("export * from './image-assets.types';");
imports.push("");
// Generate default exports for each image
imports.push("// Default image exports");
files.forEach((file) => {
const constantName = this.generateConstantName(file);
imports.push(`export { default as ${constantName}Default } from '${file.relativePath}';`);
});
imports.push("");
// Generate image map for dynamic access
imports.push("// Dynamic image map");
imports.push("const imageMap = {");
files.forEach((file) => {
imports.push(` '${file.relativePath}': () => import('${file.relativePath}'),`);
});
imports.push("};");
imports.push("");
imports.push("export async function loadImage(path: string): Promise<any> {");
imports.push(" const loader = imageMap[path as keyof typeof imageMap];");
imports.push(" if (!loader) {");
imports.push(" throw new Error(`Image not found: ${path}`);");
imports.push(" }");
imports.push(" return await loader();");
imports.push("}");
return imports.join("\n");
}
/**
* Generate usage code for a specific framework
*/
generateUsageCode(file, framework) {
const template = this.getCodeTemplate(framework);
const constantName = this.generateConstantName(file);
return template.usageTemplate
.replace(/\{constantName\}/g, constantName)
.replace(/\{fileName\}/g, file.name)
.replace(/\{filePath\}/g, file.relativePath)
.replace(/\{extension\}/g, file.extension);
}
/**
* Generate icon component for SVG files
*/
generateIconComponent(file, framework) {
if (file.extension.toLowerCase() !== ".svg") {
throw new Error("Icon components can only be generated for SVG files");
}
const template = this.getCodeTemplate(framework);
if (!template.componentTemplate) {
throw new Error(`Component template not available for framework: ${framework}`);
}
const componentName = this.generateComponentName(file);
const constantName = this.generateConstantName(file);
return template.componentTemplate
.replace(/\{componentName\}/g, componentName)
.replace(/\{constantName\}/g, constantName)
.replace(/\{fileName\}/g, file.name)
.replace(/\{filePath\}/g, file.relativePath);
}
/**
* Generate inline SVG code
*/
generateInlineCode(file, framework) {
if (file.extension.toLowerCase() !== ".svg") {
throw new Error("Inline code can only be generated for SVG files");
}
const template = this.getCodeTemplate(framework);
if (!template.inlineTemplate) {
throw new Error(`Inline template not available for framework: ${framework}`);
}
return template.inlineTemplate
.replace(/\{fileName\}/g, file.name)
.replace(/\{filePath\}/g, file.relativePath);
}
/**
* Get all generated code for a file and framework
*/
generateAllCode(file, framework) {
const result = {
import: this.generateImportCode(file, framework),
usage: this.generateUsageCode(file, framework),
};
if (file.extension.toLowerCase() === ".svg") {
// Try to generate component (may not be available for all frameworks)
try {
result.component = this.generateIconComponent(file, framework);
}
catch (error) {
// Component generation failed, continue without component
}
// Try to generate inline code (should be available for all frameworks)
try {
result.inline = this.generateInlineCode(file, framework);
}
catch (error) {
// Inline generation failed, continue without inline
}
}
return result;
}
generateImportCode(file, framework) {
const template = this.getCodeTemplate(framework);
const constantName = this.generateConstantName(file);
return template.importTemplate
.replace(/\{constantName\}/g, constantName)
.replace(/\{filePath\}/g, file.relativePath);
}
generateTypeName(file) {
const baseName = this.sanitizeName(path_1.default.parse(file.name).name);
return `${baseName}ImagePath`;
}
generateConstantName(file) {
const fileName = path_1.default.parse(file.name).name;
// For constants, we want to keep underscores between words
let sanitized = fileName
.replace(/[^a-zA-Z0-9]/g, "_")
.replace(/_+/g, "_")
.replace(/^_|_$/g, "")
.toUpperCase();
// Prefix with underscore if starts with number
if (/^[0-9]/.test(sanitized)) {
sanitized = "_" + sanitized;
}
return `${sanitized}_IMAGE`;
}
generateComponentName(file) {
const baseName = this.sanitizeName(path_1.default.parse(file.name).name);
return `${baseName.charAt(0).toUpperCase() + baseName.slice(1)}Icon`;
}
sanitizeName(name) {
// Convert to camelCase and remove invalid characters
let sanitized = name
.replace(/[^a-zA-Z0-9]/g, "_")
.replace(/_+/g, "_")
.replace(/^_|_$/g, "");
// Convert to camelCase - handle both lowercase and uppercase letters
sanitized = sanitized.replace(/_([a-zA-Z])/g, (_, letter) => letter.toUpperCase());
// Prefix with underscore if starts with number
if (/^[0-9]/.test(sanitized)) {
sanitized = "_" + sanitized;
}
return sanitized;
}
generateImageRegistry(files) {
const entries = files.map((file) => {
const typeName = this.generateTypeName(file);
return ` "${file.relativePath}" as ${typeName}: {
path: "${file.relativePath}",
name: "${file.name}",
extension: "${file.extension}",
size: ${file.size},
dimensions: { width: ${file.dimensions.width}, height: ${file.dimensions.height} },
category: "${file.category}"
}`;
});
return entries.join(",\n");
}
getCodeTemplate(framework) {
const templates = {
react: {
framework: "react",
importTemplate: "import {constantName} from '../assets/images';",
usageTemplate: `<img src={${"{constantName}"}} alt="{fileName}" />`,
componentTemplate: `import React from 'react';
import {constantName} from '../assets/images';
interface {componentName}Props {
className?: string;
size?: number;
color?: string;
}
export const {componentName}: React.FC<{componentName}Props> = ({
className,
size = 24,
color = 'currentColor'
}) => {
return (
<img
src={${"{constantName}"}}
alt="{fileName}"
className={className}
width={size}
height={size}
style={{ color }}
/>
);
};`,
inlineTemplate: `// Inline SVG for {fileName}
// Note: Replace this comment with actual SVG content from {filePath}`,
},
vue: {
framework: "vue",
importTemplate: "import {constantName} from '../assets/images';",
usageTemplate: `<img :src="{constantName}" alt="{fileName}" />`,
componentTemplate: `<template>
<img
:src="{constantName}"
:alt="alt || '{fileName}'"
:class="className"
:width="size"
:height="size"
:style="{ color }"
/>
</template>
<script setup lang="ts">
import {constantName} from '../assets/images';
interface Props {
className?: string;
size?: number;
color?: string;
alt?: string;
}
withDefaults(defineProps<Props>(), {
size: 24,
color: 'currentColor',
alt: '{fileName}'
});
</script>`,
inlineTemplate: `<!-- Inline SVG for {fileName} -->
<!-- Note: Replace this comment with actual SVG content from {filePath} -->`,
},
html: {
framework: "html",
importTemplate: "// Import {constantName} from '{filePath}'",
usageTemplate: `<img src="{filePath}" alt="{fileName}" />`,
inlineTemplate: `<!-- Inline SVG for {fileName} -->
<!-- Note: Replace this comment with actual SVG content from {filePath} -->`,
},
angular: {
framework: "angular",
importTemplate: "// Import path: {filePath}",
usageTemplate: `<img [src]="'{filePath}'" alt="{fileName}" />`,
componentTemplate: `import { Component, Input } from '@angular/core';
export class {componentName}Component {
className?: string;
size: number = 24;
color: string = 'currentColor';
alt: string = '{fileName}';
imagePath = '{filePath}';
}`,
inlineTemplate: `<!-- Inline SVG for {fileName} -->
<!-- Note: Replace this comment with actual SVG content from {filePath} -->`,
},
svelte: {
framework: "svelte",
importTemplate: "import {constantName} from '../assets/images';",
usageTemplate: `<img src={${"{constantName}"}} alt="{fileName}" />`,
componentTemplate: `<script lang="ts">
import {constantName} from '../assets/images';
export let className: string = '';
export let size: number = 24;
export let color: string = 'currentColor';
export let alt: string = '{fileName}';
</script>
<img
src={${"{constantName}"}}
{alt}
class={className}
width={size}
height={size}
style="color: {color}"
/>`,
inlineTemplate: `<!-- Inline SVG for {fileName} -->
<!-- Note: Replace this comment with actual SVG content from {filePath} -->`,
},
};
return templates[framework];
}
}
exports.TypeDefinitionGenerator = TypeDefinitionGenerator;
//# sourceMappingURL=CodeGenerator.js.map