118 lines
3.5 KiB
TypeScript
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}`);
|
|
}
|
|
}
|