Skip to content

Commit 6375ea9

Browse files
committed
add core infrastructure for 'add' command
- Create additions registry for managing optional feature additions - Implement additions manager with runAddition, executeAddition - Add utilities that reuse migration infrastructure (Context, formatFiles, etc.) - Support for version-agnostic, idempotent additions - Designed to be extensible for future additions beyond i18n Fri Oct 17 09:48:24 2025 +0200 add core infrastructure for 'add' command implement 'add' command with pre-flight checks implement 'add i18n' script with full automation packages/create-plugin/src/additions/additions.ts packages/create-plugin/src/additions/manager.ts packages/create-plugin/src/additions/utils.ts
1 parent fc6ed06 commit 6375ea9

File tree

3 files changed

+135
-0
lines changed

3 files changed

+135
-0
lines changed
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
export type AdditionMeta = {
2+
name: string;
3+
description: string;
4+
scriptPath: string;
5+
};
6+
7+
type Additions = {
8+
additions: Record<string, AdditionMeta>;
9+
};
10+
11+
export default {
12+
additions: {
13+
i18n: {
14+
name: 'i18n',
15+
description: 'Add internationalization (i18n) support to your plugin',
16+
scriptPath: './scripts/add-i18n.js',
17+
},
18+
},
19+
} as Additions;
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import { additionsDebug, flushChanges, formatFiles, installNPMDependencies, printChanges } from './utils.js';
2+
import defaultAdditions, { AdditionMeta } from './additions.js';
3+
4+
import { Context } from '../migrations/context.js';
5+
import { gitCommitNoVerify } from '../utils/utils.git.js';
6+
import { output } from '../utils/utils.console.js';
7+
8+
export type AdditionFn = (context: Context, options?: AdditionOptions) => Context | Promise<Context>;
9+
10+
export type AdditionOptions = Record<string, any>;
11+
12+
type RunAdditionOptions = {
13+
commitChanges?: boolean;
14+
};
15+
16+
export function getAvailableAdditions(
17+
additions: Record<string, AdditionMeta> = defaultAdditions.additions
18+
): Record<string, AdditionMeta> {
19+
return additions;
20+
}
21+
22+
export function getAdditionByName(
23+
name: string,
24+
additions: Record<string, AdditionMeta> = defaultAdditions.additions
25+
): AdditionMeta | undefined {
26+
return additions[name];
27+
}
28+
29+
export async function runAddition(
30+
addition: AdditionMeta,
31+
additionOptions: AdditionOptions = {},
32+
runOptions: RunAdditionOptions = {}
33+
): Promise<void> {
34+
const basePath = process.cwd();
35+
36+
output.log({
37+
title: `Running addition: ${addition.name}`,
38+
body: [addition.description],
39+
});
40+
41+
try {
42+
const context = new Context(basePath);
43+
const updatedContext = await executeAddition(addition, context, additionOptions);
44+
const shouldCommit = runOptions.commitChanges && updatedContext.hasChanges();
45+
46+
additionsDebug(`context for "${addition.name} (${addition.scriptPath})":`);
47+
additionsDebug('%O', updatedContext.listChanges());
48+
49+
await formatFiles(updatedContext);
50+
flushChanges(updatedContext);
51+
printChanges(updatedContext, addition.name, addition);
52+
53+
installNPMDependencies(updatedContext);
54+
55+
if (shouldCommit) {
56+
await gitCommitNoVerify(`chore: add ${addition.name} support via create-plugin`);
57+
}
58+
59+
output.success({
60+
title: `Successfully added ${addition.name} to your plugin.`,
61+
});
62+
} catch (error) {
63+
if (error instanceof Error) {
64+
throw new Error(`Error running addition "${addition.name} (${addition.scriptPath})": ${error.message}`);
65+
}
66+
throw error;
67+
}
68+
}
69+
70+
export async function executeAddition(
71+
addition: AdditionMeta,
72+
context: Context,
73+
options: AdditionOptions = {}
74+
): Promise<Context> {
75+
const module: { default: AdditionFn } = await import(addition.scriptPath);
76+
return module.default(context, options);
77+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
export {
2+
formatFiles,
3+
installNPMDependencies,
4+
flushChanges,
5+
addDependenciesToPackageJson,
6+
} from '../migrations/utils.js';
7+
8+
import type { AdditionMeta } from './additions.js';
9+
import { Context } from '../migrations/context.js';
10+
import chalk from 'chalk';
11+
// Re-export debug with additions namespace
12+
import { debug } from '../utils/utils.cli.js';
13+
import { output } from '../utils/utils.console.js';
14+
15+
export const additionsDebug = debug.extend('additions');
16+
17+
export function printChanges(context: Context, key: string, addition: AdditionMeta) {
18+
const changes = context.listChanges();
19+
const lines = [];
20+
21+
for (const [filePath, { changeType }] of Object.entries(changes)) {
22+
if (changeType === 'add') {
23+
lines.push(`${chalk.green('ADD')} ${filePath}`);
24+
} else if (changeType === 'update') {
25+
lines.push(`${chalk.yellow('UPDATE')} ${filePath}`);
26+
} else if (changeType === 'delete') {
27+
lines.push(`${chalk.red('DELETE')} ${filePath}`);
28+
}
29+
}
30+
31+
output.addHorizontalLine('gray');
32+
output.logSingleLine(`${key} (${addition.description})`);
33+
34+
if (lines.length === 0) {
35+
output.logSingleLine('No changes were made');
36+
} else {
37+
output.log({ title: 'Changes:', withPrefix: false, body: output.bulletList(lines) });
38+
}
39+
}

0 commit comments

Comments
 (0)