studiocms
Version:
Astro Native CMS for AstroDB. Built from the ground up by the Astro community.
104 lines (90 loc) • 3.17 kB
text/typescript
import { promises as fs } from 'node:fs';
import { fileURLToPath } from 'node:url';
import { askToContinue, note } from '@withstudiocms/effect/clack';
import { diffWords } from 'diff';
import { generateCode, type ProxifiedModule } from 'magicast';
import { Console, Effect, genLogger } from '../../effect.js';
import { CliContext } from '../utils/context.js';
import { effectBoxen } from '../utils/effectBoxen.js';
import { UpdateResult } from './index.js';
export class UpdateStudioCMSConfig extends Effect.Service<UpdateStudioCMSConfig>()(
'UpdateStudioCMSConfig',
{
effect: genLogger('studiocms/cli/add/updateStudioCMSConfig/UpdateStudioCMSConfig.effect')(
function* () {
// biome-ignore lint/suspicious/noExplicitAny: this is a valid use case for explicit any.
const run = (configURL: URL, mod: ProxifiedModule<any>) =>
genLogger('studiocms/cli/add/updateStudioCMSConfig/UpdateStudioCMSConfig.effect.run')(
function* () {
const context = yield* CliContext;
const { chalk } = context;
const input = yield* Effect.tryPromise(() =>
fs.readFile(fileURLToPath(configURL), { encoding: 'utf-8' })
);
const output = yield* Effect.try(
() =>
generateCode(mod, {
format: {
objectCurlySpacing: true,
useTabs: false,
tabWidth: 2,
},
}).code
);
if (input === output) return UpdateResult.none;
const diff = yield* getDiffContent(input, output).pipe(
CliContext.makeProvide(context)
);
if (!diff) return UpdateResult.none;
const boxenMessage = yield* effectBoxen((boxen) =>
boxen(diff, {
margin: 0.5,
padding: 0.5,
borderStyle: 'round',
title: configURL.pathname.split('/').pop(),
})
);
const message = `\n${boxenMessage}\n`;
yield* note(
`\n ${chalk.magenta('StudioCMS will make the following changes to your config file:')}\n${message}`
);
if (yield* askToContinue()) {
yield* Effect.tryPromise(() =>
fs.writeFile(fileURLToPath(configURL), output, { encoding: 'utf-8' })
);
yield* Console.debug('Updated studiocms config');
return UpdateResult.updated;
}
return UpdateResult.cancelled;
}
);
return { run };
}
),
}
) {}
const getDiffContent = (input: string, output: string) =>
genLogger('studiocms/cli/add/updateStudioCMSConfig.getDiffContentNew')(function* () {
const { chalk } = yield* CliContext;
const changes = [];
for (const change of diffWords(input, output)) {
const lines = change.value.trim().split('\n').slice(0, change.count);
if (lines.length === 0) continue;
if (change.added) {
if (!change.value.trim()) continue;
changes.push(change.value);
}
}
if (changes.length === 0) {
return null;
}
let diffed = output;
for (const newContent of changes) {
const coloredOutput = newContent
.split('\n')
.map((ln) => (ln ? chalk.green(ln) : ''))
.join('\n');
diffed = diffed.replace(newContent, coloredOutput);
}
return diffed;
});