Files
cli/ts/mod_format/formatters/copy.formatter.ts

118 lines
3.5 KiB
TypeScript

import { BaseFormatter } from '../classes.baseformatter.js';
import type { IPlannedChange } from '../interfaces.format.js';
import * as plugins from '../mod.plugins.js';
import { logger, logVerbose } from '../../gitzone.logging.js';
interface ICopyPattern {
from: string;
to: string;
preservePath?: boolean;
}
export class CopyFormatter extends BaseFormatter {
get name(): string {
return 'copy';
}
async analyze(): Promise<IPlannedChange[]> {
const changes: IPlannedChange[] = [];
// Get copy configuration from npmextra.json
const npmextraConfig = new plugins.npmextra.Npmextra();
const copyConfig = npmextraConfig.dataFor<{ patterns: ICopyPattern[] }>(
'gitzone.format.copy',
{ patterns: [] },
);
if (!copyConfig.patterns || copyConfig.patterns.length === 0) {
logVerbose('No copy patterns configured in npmextra.json');
return changes;
}
for (const pattern of copyConfig.patterns) {
if (!pattern.from || !pattern.to) {
logVerbose('Invalid copy pattern - missing "from" or "to" field');
continue;
}
try {
// Handle glob patterns
const entries = await plugins.smartfs
.directory('.')
.recursive()
.filter(pattern.from)
.list();
const files = entries.map((entry) => entry.path);
for (const file of files) {
const sourcePath = file;
let destPath = pattern.to;
// If destination is a directory, preserve filename
if (pattern.to.endsWith('/')) {
const filename = plugins.path.basename(file);
destPath = plugins.path.join(pattern.to, filename);
}
// Handle template variables in destination path
if (pattern.preservePath) {
const relativePath = plugins.path.relative(
plugins.path.dirname(pattern.from.replace(/\*/g, '')),
file,
);
destPath = plugins.path.join(pattern.to, relativePath);
}
// Read source content
const content = (await plugins.smartfs
.file(sourcePath)
.encoding('utf8')
.read()) as string;
// Check if destination exists and has same content
let needsCopy = true;
const destExists = await plugins.smartfs.file(destPath).exists();
if (destExists) {
const existingContent = (await plugins.smartfs
.file(destPath)
.encoding('utf8')
.read()) as string;
if (existingContent === content) {
needsCopy = false;
}
}
if (needsCopy) {
changes.push({
type: destExists ? 'modify' : 'create',
path: destPath,
module: this.name,
description: `Copy from ${sourcePath}`,
content: content,
});
}
}
} catch (error) {
logVerbose(`Failed to process pattern ${pattern.from}: ${error.message}`);
}
}
return changes;
}
async applyChange(change: IPlannedChange): Promise<void> {
if (!change.content) return;
// Ensure destination directory exists
const destDir = plugins.path.dirname(change.path);
await plugins.smartfs.directory(destDir).recursive().create();
if (change.type === 'create') {
await this.createFile(change.path, change.content);
} else {
await this.modifyFile(change.path, change.content);
}
logger.log('info', `Copied to ${change.path}`);
}
}