fix(mod_format): move smartconfig file renaming into the formatter orchestrator
This commit is contained in:
@@ -1,5 +1,12 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 2026-03-24 - 2.13.14 - fix(mod_format)
|
||||||
|
move smartconfig file renaming into the formatter orchestrator
|
||||||
|
|
||||||
|
- Renames smartconfig.json or npmextra.json to .smartconfig.json before formatters run
|
||||||
|
- Simplifies the smartconfig formatter to only read and modify .smartconfig.json
|
||||||
|
- Removes create/delete change planning for config renames and applies only content updates within the formatter
|
||||||
|
|
||||||
## 2026-03-24 - 2.13.13 - fix(vscode-template)
|
## 2026-03-24 - 2.13.13 - fix(vscode-template)
|
||||||
update VS Code schema matching to use .smartconfig.json
|
update VS Code schema matching to use .smartconfig.json
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,6 @@
|
|||||||
*/
|
*/
|
||||||
export const commitinfo = {
|
export const commitinfo = {
|
||||||
name: '@git.zone/cli',
|
name: '@git.zone/cli',
|
||||||
version: '2.13.13',
|
version: '2.13.14',
|
||||||
description: 'A comprehensive CLI tool for enhancing and managing local development workflows with gitzone utilities, focusing on project setup, version control, code formatting, and template management.'
|
description: 'A comprehensive CLI tool for enhancing and managing local development workflows with gitzone utilities, focusing on project setup, version control, code formatting, and template management.'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,49 +61,33 @@ const migrateAccessLevel = (smartconfigJson: any): boolean => {
|
|||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Config file names in priority order (newest → oldest)
|
const CONFIG_FILE = '.smartconfig.json';
|
||||||
const CONFIG_FILE_NAMES = ['.smartconfig.json', 'smartconfig.json', 'npmextra.json'];
|
|
||||||
const TARGET_CONFIG_FILE = '.smartconfig.json';
|
|
||||||
|
|
||||||
export class SmartconfigFormatter extends BaseFormatter {
|
export class SmartconfigFormatter extends BaseFormatter {
|
||||||
get name(): string {
|
get name(): string {
|
||||||
return 'smartconfig';
|
return 'smartconfig';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Find the config file, checking in priority order.
|
|
||||||
* Returns the path and whether it needs renaming.
|
|
||||||
*/
|
|
||||||
private async findConfigFile(): Promise<{ path: string; needsRename: boolean } | null> {
|
|
||||||
for (const filename of CONFIG_FILE_NAMES) {
|
|
||||||
const exists = await plugins.smartfs.file(filename).exists();
|
|
||||||
if (exists) {
|
|
||||||
return {
|
|
||||||
path: filename,
|
|
||||||
needsRename: filename !== TARGET_CONFIG_FILE,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
async analyze(): Promise<IPlannedChange[]> {
|
async analyze(): Promise<IPlannedChange[]> {
|
||||||
const changes: IPlannedChange[] = [];
|
const changes: IPlannedChange[] = [];
|
||||||
|
|
||||||
const configFile = await this.findConfigFile();
|
// File rename (npmextra.json/smartconfig.json → .smartconfig.json)
|
||||||
if (!configFile) {
|
// is handled by the orchestrator before analysis.
|
||||||
logVerbose('No config file found (.smartconfig.json, smartconfig.json, or npmextra.json), skipping');
|
// This formatter only operates on .smartconfig.json.
|
||||||
|
const exists = await plugins.smartfs.file(CONFIG_FILE).exists();
|
||||||
|
if (!exists) {
|
||||||
|
logVerbose('.smartconfig.json does not exist, skipping');
|
||||||
return changes;
|
return changes;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read current content
|
|
||||||
const currentContent = (await plugins.smartfs
|
const currentContent = (await plugins.smartfs
|
||||||
.file(configFile.path)
|
.file(CONFIG_FILE)
|
||||||
.encoding('utf8')
|
.encoding('utf8')
|
||||||
.read()) as string;
|
.read()) as string;
|
||||||
|
|
||||||
// Parse and apply migrations
|
|
||||||
const smartconfigJson = JSON.parse(currentContent);
|
const smartconfigJson = JSON.parse(currentContent);
|
||||||
|
|
||||||
|
// Apply key migrations
|
||||||
migrateNamespaceKeys(smartconfigJson);
|
migrateNamespaceKeys(smartconfigJson);
|
||||||
migrateAccessLevel(smartconfigJson);
|
migrateAccessLevel(smartconfigJson);
|
||||||
|
|
||||||
@@ -117,26 +101,10 @@ export class SmartconfigFormatter extends BaseFormatter {
|
|||||||
|
|
||||||
const newContent = JSON.stringify(smartconfigJson, null, 2);
|
const newContent = JSON.stringify(smartconfigJson, null, 2);
|
||||||
|
|
||||||
// If file needs renaming, plan a create + delete
|
if (newContent !== currentContent) {
|
||||||
if (configFile.needsRename) {
|
|
||||||
changes.push({
|
|
||||||
type: 'create',
|
|
||||||
path: TARGET_CONFIG_FILE,
|
|
||||||
module: this.name,
|
|
||||||
description: `Migrate ${configFile.path} to ${TARGET_CONFIG_FILE}`,
|
|
||||||
content: newContent,
|
|
||||||
});
|
|
||||||
changes.push({
|
|
||||||
type: 'delete',
|
|
||||||
path: configFile.path,
|
|
||||||
module: this.name,
|
|
||||||
description: `Remove old ${configFile.path}`,
|
|
||||||
});
|
|
||||||
} else if (newContent !== currentContent) {
|
|
||||||
// File is already .smartconfig.json, just needs content update
|
|
||||||
changes.push({
|
changes.push({
|
||||||
type: 'modify',
|
type: 'modify',
|
||||||
path: TARGET_CONFIG_FILE,
|
path: CONFIG_FILE,
|
||||||
module: this.name,
|
module: this.name,
|
||||||
description: 'Migrate and format .smartconfig.json',
|
description: 'Migrate and format .smartconfig.json',
|
||||||
content: newContent,
|
content: newContent,
|
||||||
@@ -147,17 +115,11 @@ export class SmartconfigFormatter extends BaseFormatter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async applyChange(change: IPlannedChange): Promise<void> {
|
async applyChange(change: IPlannedChange): Promise<void> {
|
||||||
if (change.type === 'delete') {
|
if (change.type !== 'modify' || !change.content) return;
|
||||||
await this.deleteFile(change.path);
|
|
||||||
logger.log('info', `Removed old config file ${change.path}`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!change.content) return;
|
|
||||||
|
|
||||||
// Parse the content to check for missing required fields
|
|
||||||
const smartconfigJson = JSON.parse(change.content);
|
const smartconfigJson = JSON.parse(change.content);
|
||||||
|
|
||||||
|
// Check for missing required module information
|
||||||
const expectedRepoInformation: string[] = [
|
const expectedRepoInformation: string[] = [
|
||||||
'projectType',
|
'projectType',
|
||||||
'module.githost',
|
'module.githost',
|
||||||
@@ -202,12 +164,7 @@ export class SmartconfigFormatter extends BaseFormatter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const finalContent = JSON.stringify(smartconfigJson, null, 2);
|
const finalContent = JSON.stringify(smartconfigJson, null, 2);
|
||||||
|
await this.modifyFile(change.path, finalContent);
|
||||||
if (change.type === 'create') {
|
logger.log('info', 'Updated .smartconfig.json');
|
||||||
await this.createFile(change.path, finalContent);
|
|
||||||
} else {
|
|
||||||
await this.modifyFile(change.path, finalContent);
|
|
||||||
}
|
|
||||||
logger.log('info', `Updated ${change.path}`);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,27 @@ import { PrettierFormatter } from './formatters/prettier.formatter.js';
|
|||||||
import { ReadmeFormatter } from './formatters/readme.formatter.js';
|
import { ReadmeFormatter } from './formatters/readme.formatter.js';
|
||||||
import { CopyFormatter } from './formatters/copy.formatter.js';
|
import { CopyFormatter } from './formatters/copy.formatter.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rename npmextra.json or smartconfig.json to .smartconfig.json
|
||||||
|
* before any formatter tries to read config.
|
||||||
|
*/
|
||||||
|
async function migrateConfigFile(): Promise<void> {
|
||||||
|
const target = '.smartconfig.json';
|
||||||
|
const targetExists = await plugins.smartfs.file(target).exists();
|
||||||
|
if (targetExists) return;
|
||||||
|
|
||||||
|
for (const oldName of ['smartconfig.json', 'npmextra.json']) {
|
||||||
|
const exists = await plugins.smartfs.file(oldName).exists();
|
||||||
|
if (exists) {
|
||||||
|
const content = await plugins.smartfs.file(oldName).encoding('utf8').read() as string;
|
||||||
|
await plugins.smartfs.file(`./${target}`).encoding('utf8').write(content);
|
||||||
|
await plugins.smartfs.file(oldName).delete();
|
||||||
|
logger.log('info', `Migrated ${oldName} to ${target}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Shared formatter class map used by both run() and runFormatter()
|
// Shared formatter class map used by both run() and runFormatter()
|
||||||
const formatterMap: Record<string, new (ctx: FormatContext, proj: Project) => BaseFormatter> = {
|
const formatterMap: Record<string, new (ctx: FormatContext, proj: Project) => BaseFormatter> = {
|
||||||
cleanup: CleanupFormatter,
|
cleanup: CleanupFormatter,
|
||||||
@@ -53,6 +74,9 @@ export let run = async (
|
|||||||
|
|
||||||
const shouldWrite = options.write ?? (options.dryRun === false);
|
const shouldWrite = options.write ?? (options.dryRun === false);
|
||||||
|
|
||||||
|
// Migrate config file before anything reads it
|
||||||
|
await migrateConfigFile();
|
||||||
|
|
||||||
const project = await Project.fromCwd({ requireProjectType: false });
|
const project = await Project.fromCwd({ requireProjectType: false });
|
||||||
const context = new FormatContext();
|
const context = new FormatContext();
|
||||||
const planner = new FormatPlanner();
|
const planner = new FormatPlanner();
|
||||||
|
|||||||
Reference in New Issue
Block a user