create-s-blog 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/args.d.ts ADDED
@@ -0,0 +1,12 @@
1
+ export interface CliArgs {
2
+ name?: string;
3
+ description?: string;
4
+ author?: string;
5
+ pm?: 'npm' | 'yarn' | 'pnpm';
6
+ 'skip-install'?: boolean;
7
+ help?: boolean;
8
+ version?: boolean;
9
+ }
10
+ export declare function parseArgs(argv?: string[]): CliArgs;
11
+ export declare function printHelp(): void;
12
+ export declare function printVersion(): void;
package/dist/args.js ADDED
@@ -0,0 +1,57 @@
1
+ import minimist from 'minimist';
2
+ import { readFileSync } from 'node:fs';
3
+ import { fileURLToPath } from 'node:url';
4
+ import path from 'node:path';
5
+ const HELP_TEXT = `
6
+ Usage: create-s-blog [options]
7
+
8
+ Options:
9
+ --name <name> Project name (default: my-blog)
10
+ --description <desc> Project description (default: A blog powered by S-blog)
11
+ --author <author> Author name (default: "")
12
+ --pm <npm|yarn|pnpm> Package manager (default: npm)
13
+ --skip-install Skip dependency installation
14
+ --help Show this help message
15
+ --version Show version number
16
+ `;
17
+ export function parseArgs(argv = process.argv.slice(2)) {
18
+ const args = minimist(argv, {
19
+ string: ['name', 'description', 'author', 'pm'],
20
+ boolean: ['skip-install', 'help', 'version'],
21
+ alias: {
22
+ h: 'help',
23
+ v: 'version',
24
+ },
25
+ });
26
+ return {
27
+ name: args.name || undefined,
28
+ description: args.description || undefined,
29
+ author: args.author !== undefined ? args.author : undefined,
30
+ pm: validatePm(args.pm),
31
+ 'skip-install': args['skip-install'] || false,
32
+ help: args.help || false,
33
+ version: args.version || false,
34
+ };
35
+ }
36
+ function validatePm(pm) {
37
+ if (pm === 'npm' || pm === 'yarn' || pm === 'pnpm')
38
+ return pm;
39
+ if (pm) {
40
+ console.warn(`Warning: Invalid package manager "${pm}", will use npm as default.`);
41
+ }
42
+ return undefined;
43
+ }
44
+ export function printHelp() {
45
+ console.log(HELP_TEXT);
46
+ }
47
+ export function printVersion() {
48
+ try {
49
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
50
+ const pkg = JSON.parse(readFileSync(path.resolve(__dirname, '../package.json'), 'utf-8'));
51
+ console.log(`create-s-blog v${pkg.version}`);
52
+ }
53
+ catch {
54
+ console.log('create-s-blog v0.1.0');
55
+ }
56
+ }
57
+ //# sourceMappingURL=args.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"args.js","sourceRoot":"","sources":["../src/args.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,UAAU,CAAC;AAChC,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,IAAI,MAAM,WAAW,CAAC;AAY7B,MAAM,SAAS,GAAG;;;;;;;;;;;CAWjB,CAAC;AAEF,MAAM,UAAU,SAAS,CAAC,OAAiB,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;IAC9D,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,EAAE;QAC1B,MAAM,EAAE,CAAC,MAAM,EAAE,aAAa,EAAE,QAAQ,EAAE,IAAI,CAAC;QAC/C,OAAO,EAAE,CAAC,cAAc,EAAE,MAAM,EAAE,SAAS,CAAC;QAC5C,KAAK,EAAE;YACL,CAAC,EAAE,MAAM;YACT,CAAC,EAAE,SAAS;SACb;KACF,CAAC,CAAC;IAEH,OAAO;QACL,IAAI,EAAE,IAAI,CAAC,IAAI,IAAI,SAAS;QAC5B,WAAW,EAAE,IAAI,CAAC,WAAW,IAAI,SAAS;QAC1C,MAAM,EAAE,IAAI,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS;QAC3D,EAAE,EAAE,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QACvB,cAAc,EAAE,IAAI,CAAC,cAAc,CAAC,IAAI,KAAK;QAC7C,IAAI,EAAE,IAAI,CAAC,IAAI,IAAI,KAAK;QACxB,OAAO,EAAE,IAAI,CAAC,OAAO,IAAI,KAAK;KAC/B,CAAC;AACJ,CAAC;AAED,SAAS,UAAU,CAAC,EAAW;IAC7B,IAAI,EAAE,KAAK,KAAK,IAAI,EAAE,KAAK,MAAM,IAAI,EAAE,KAAK,MAAM;QAAE,OAAO,EAAE,CAAC;IAC9D,IAAI,EAAE,EAAE,CAAC;QACP,OAAO,CAAC,IAAI,CAAC,qCAAqC,EAAE,6BAA6B,CAAC,CAAC;IACrF,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,UAAU,SAAS;IACvB,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;AACzB,CAAC;AAED,MAAM,UAAU,YAAY;IAC1B,IAAI,CAAC;QACH,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;QAC/D,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,iBAAiB,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC;QAC1F,OAAO,CAAC,GAAG,CAAC,kBAAkB,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;IAC/C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC;IACtC,CAAC;AACH,CAAC"}
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,83 @@
1
+ #!/usr/bin/env node
2
+ import path from 'node:path';
3
+ import { parseArgs, printHelp, printVersion } from './args.js';
4
+ import { collectUserInput } from './prompts.js';
5
+ import { copyTemplate, cleanup } from './scaffold.js';
6
+ import { installDependencies } from './install.js';
7
+ import { printBanner, printSuccess, printErrorDirectoryExists, printErrorCopyFailed, printErrorInstallFailed, printCancelled, } from './messages.js';
8
+ let targetDir = null;
9
+ let shouldCleanup = false;
10
+ // Register cleanup handler for SIGINT (Ctrl+C)
11
+ process.on('SIGINT', () => {
12
+ if (shouldCleanup && targetDir) {
13
+ cleanup(targetDir);
14
+ printCancelled();
15
+ }
16
+ process.exit(1);
17
+ });
18
+ async function main() {
19
+ // Parse command-line arguments
20
+ const args = parseArgs();
21
+ if (args.help) {
22
+ printHelp();
23
+ return;
24
+ }
25
+ if (args.version) {
26
+ printVersion();
27
+ return;
28
+ }
29
+ printBanner();
30
+ // Collect user input (interactive prompts for missing fields)
31
+ let userInput;
32
+ try {
33
+ userInput = await collectUserInput(args);
34
+ }
35
+ catch (err) {
36
+ if (err instanceof Error && err.message === 'USER_CANCELLED') {
37
+ console.log('\n Operation cancelled.');
38
+ return;
39
+ }
40
+ throw err;
41
+ }
42
+ // Set target directory
43
+ targetDir = path.resolve(process.cwd(), userInput.name);
44
+ shouldCleanup = true;
45
+ // Copy template files
46
+ try {
47
+ await copyTemplate(targetDir, userInput);
48
+ }
49
+ catch (err) {
50
+ if (err instanceof Error) {
51
+ if (err.message.startsWith('DIRECTORY_EXISTS:')) {
52
+ const dirName = err.message.split(':')[1];
53
+ printErrorDirectoryExists(dirName);
54
+ return;
55
+ }
56
+ if (err.message === 'COPY_FAILED') {
57
+ printErrorCopyFailed();
58
+ return;
59
+ }
60
+ }
61
+ throw err;
62
+ }
63
+ // Install dependencies
64
+ if (!userInput.skipInstall) {
65
+ try {
66
+ await installDependencies(targetDir, userInput.packageManager);
67
+ }
68
+ catch {
69
+ printErrorInstallFailed(userInput.name, userInput.packageManager);
70
+ // Don't exit — project files were created successfully
71
+ }
72
+ }
73
+ shouldCleanup = false;
74
+ printSuccess(userInput);
75
+ }
76
+ main().catch((err) => {
77
+ console.error(err);
78
+ if (shouldCleanup && targetDir) {
79
+ cleanup(targetDir);
80
+ }
81
+ process.exit(1);
82
+ });
83
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Install dependencies in the target directory using the specified package manager.
3
+ */
4
+ export declare function installDependencies(targetDir: string, pm: 'npm' | 'yarn' | 'pnpm'): Promise<void>;
@@ -0,0 +1,27 @@
1
+ import { spawn } from 'node:child_process';
2
+ /**
3
+ * Install dependencies in the target directory using the specified package manager.
4
+ */
5
+ export function installDependencies(targetDir, pm) {
6
+ return new Promise((resolve, reject) => {
7
+ const command = pm;
8
+ const args = ['install'];
9
+ const child = spawn(command, args, {
10
+ cwd: targetDir,
11
+ stdio: 'inherit',
12
+ shell: true,
13
+ });
14
+ child.on('close', (code) => {
15
+ if (code === 0) {
16
+ resolve();
17
+ }
18
+ else {
19
+ reject(new Error(`INSTALL_FAILED:${pm}`));
20
+ }
21
+ });
22
+ child.on('error', () => {
23
+ reject(new Error(`INSTALL_FAILED:${pm}`));
24
+ });
25
+ });
26
+ }
27
+ //# sourceMappingURL=install.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install.js","sourceRoot":"","sources":["../src/install.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAE3C;;GAEG;AACH,MAAM,UAAU,mBAAmB,CACjC,SAAiB,EACjB,EAA2B;IAE3B,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,OAAO,GAAG,EAAE,CAAC;QACnB,MAAM,IAAI,GAAG,CAAC,SAAS,CAAC,CAAC;QAEzB,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE;YACjC,GAAG,EAAE,SAAS;YACd,KAAK,EAAE,SAAS;YAChB,KAAK,EAAE,IAAI;SACZ,CAAC,CAAC;QAEH,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE;YACzB,IAAI,IAAI,KAAK,CAAC,EAAE,CAAC;gBACf,OAAO,EAAE,CAAC;YACZ,CAAC;iBAAM,CAAC;gBACN,MAAM,CAAC,IAAI,KAAK,CAAC,kBAAkB,EAAE,EAAE,CAAC,CAAC,CAAC;YAC5C,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;YACrB,MAAM,CAAC,IAAI,KAAK,CAAC,kBAAkB,EAAE,EAAE,CAAC,CAAC,CAAC;QAC5C,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,7 @@
1
+ import type { UserInput } from './prompts.js';
2
+ export declare function printSuccess(input: UserInput): void;
3
+ export declare function printErrorDirectoryExists(name: string): void;
4
+ export declare function printErrorCopyFailed(): void;
5
+ export declare function printErrorInstallFailed(name: string, pm: string): void;
6
+ export declare function printCancelled(): void;
7
+ export declare function printBanner(): void;
@@ -0,0 +1,51 @@
1
+ import { green, cyan, red, yellow, bold, dim } from 'kolorist';
2
+ export function printSuccess(input) {
3
+ console.log();
4
+ console.log(` ${bold(green('✔'))} ${bold('Project created successfully!')}`);
5
+ console.log();
6
+ console.log(` ${dim('Next steps:')}`);
7
+ console.log();
8
+ console.log(` ${cyan('cd')} ${input.name}`);
9
+ console.log(` ${cyan(`${input.packageManager} run dev`)}`);
10
+ console.log();
11
+ console.log(` ${dim('Build for production:')}`);
12
+ console.log(` ${cyan(`${input.packageManager} run build`)}`);
13
+ console.log();
14
+ console.log(` ${dim('Update framework:')}`);
15
+ console.log(` ${cyan(`${input.packageManager === 'npm' ? 'npm update' : input.packageManager + ' upgrade'} @s-blog/core`)}`);
16
+ console.log();
17
+ console.log(` ${dim('Happy blogging! 🎉')}`);
18
+ console.log();
19
+ }
20
+ export function printErrorDirectoryExists(name) {
21
+ console.error();
22
+ console.error(` ${red('✖')} ${bold('Error')}: Directory "${yellow(name)}" already exists.`);
23
+ console.error(` Please choose another name or delete the directory and try again.`);
24
+ console.error();
25
+ }
26
+ export function printErrorCopyFailed() {
27
+ console.error();
28
+ console.error(` ${red('✖')} ${bold('Error')}: Failed to copy template files.`);
29
+ console.error(` Cleaned up temporary files. Please check disk space and permissions, then try again.`);
30
+ console.error();
31
+ }
32
+ export function printErrorInstallFailed(name, pm) {
33
+ console.error();
34
+ console.error(` ${yellow('⚠')} ${bold('Warning')}: Dependency installation failed.`);
35
+ console.error(` Your project was created, but you need to install dependencies manually:`);
36
+ console.error();
37
+ console.error(` ${cyan('cd')} ${name}`);
38
+ console.error(` ${cyan(`${pm} install`)}`);
39
+ console.error();
40
+ }
41
+ export function printCancelled() {
42
+ console.log();
43
+ console.log(` ${yellow('✖')} Initialization cancelled. Cleaned up temporary files.`);
44
+ console.log();
45
+ }
46
+ export function printBanner() {
47
+ console.log();
48
+ console.log(` ${bold(cyan('create-s-blog'))} ${dim('- Scaffold a new S-blog project')}`);
49
+ console.log();
50
+ }
51
+ //# sourceMappingURL=messages.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"messages.js","sourceRoot":"","sources":["../src/messages.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import type { CliArgs } from './args.js';
2
+ export interface UserInput {
3
+ name: string;
4
+ description: string;
5
+ author: string;
6
+ packageManager: 'npm' | 'yarn' | 'pnpm';
7
+ skipInstall: boolean;
8
+ }
9
+ export declare function collectUserInput(args: CliArgs): Promise<UserInput>;
@@ -0,0 +1,58 @@
1
+ import prompts from 'prompts';
2
+ export async function collectUserInput(args) {
3
+ const questions = [];
4
+ if (!args.name) {
5
+ questions.push({
6
+ type: 'text',
7
+ name: 'name',
8
+ message: 'Project name:',
9
+ initial: 'my-blog',
10
+ });
11
+ }
12
+ if (!args.description) {
13
+ questions.push({
14
+ type: 'text',
15
+ name: 'description',
16
+ message: 'Project description:',
17
+ initial: 'A blog powered by S-blog',
18
+ });
19
+ }
20
+ if (args.author === undefined) {
21
+ questions.push({
22
+ type: 'text',
23
+ name: 'author',
24
+ message: 'Author name:',
25
+ initial: '',
26
+ });
27
+ }
28
+ if (!args.pm) {
29
+ questions.push({
30
+ type: 'select',
31
+ name: 'packageManager',
32
+ message: 'Package manager:',
33
+ choices: [
34
+ { title: 'npm', value: 'npm' },
35
+ { title: 'yarn', value: 'yarn' },
36
+ { title: 'pnpm', value: 'pnpm' },
37
+ ],
38
+ initial: 0,
39
+ });
40
+ }
41
+ let cancelled = false;
42
+ const response = await prompts(questions, {
43
+ onCancel: () => {
44
+ cancelled = true;
45
+ },
46
+ });
47
+ if (cancelled) {
48
+ throw new Error('USER_CANCELLED');
49
+ }
50
+ return {
51
+ name: args.name || response.name || 'my-blog',
52
+ description: args.description || response.description || 'A blog powered by S-blog',
53
+ author: args.author !== undefined ? args.author : (response.author || ''),
54
+ packageManager: args.pm || response.packageManager || 'npm',
55
+ skipInstall: args['skip-install'] || false,
56
+ };
57
+ }
58
+ //# sourceMappingURL=prompts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompts.js","sourceRoot":"","sources":["../src/prompts.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,SAAS,CAAC;AAW9B,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,IAAa;IAClD,MAAM,SAAS,GAA2B,EAAE,CAAC;IAE7C,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;QACf,SAAS,CAAC,IAAI,CAAC;YACb,IAAI,EAAE,MAAM;YACZ,IAAI,EAAE,MAAM;YACZ,OAAO,EAAE,eAAe;YACxB,OAAO,EAAE,SAAS;SACnB,CAAC,CAAC;IACL,CAAC;IAED,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;QACtB,SAAS,CAAC,IAAI,CAAC;YACb,IAAI,EAAE,MAAM;YACZ,IAAI,EAAE,aAAa;YACnB,OAAO,EAAE,sBAAsB;YAC/B,OAAO,EAAE,0BAA0B;SACpC,CAAC,CAAC;IACL,CAAC;IAED,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;QAC9B,SAAS,CAAC,IAAI,CAAC;YACb,IAAI,EAAE,MAAM;YACZ,IAAI,EAAE,QAAQ;YACd,OAAO,EAAE,cAAc;YACvB,OAAO,EAAE,EAAE;SACZ,CAAC,CAAC;IACL,CAAC;IAED,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC;QACb,SAAS,CAAC,IAAI,CAAC;YACb,IAAI,EAAE,QAAQ;YACd,IAAI,EAAE,gBAAgB;YACtB,OAAO,EAAE,kBAAkB;YAC3B,OAAO,EAAE;gBACP,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE;gBAC9B,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE;gBAChC,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE;aACjC;YACD,OAAO,EAAE,CAAC;SACX,CAAC,CAAC;IACL,CAAC;IAED,IAAI,SAAS,GAAG,KAAK,CAAC;IACtB,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,SAAS,EAAE;QACxC,QAAQ,EAAE,GAAG,EAAE;YACb,SAAS,GAAG,IAAI,CAAC;QACnB,CAAC;KACF,CAAC,CAAC;IAEH,IAAI,SAAS,EAAE,CAAC;QACd,MAAM,IAAI,KAAK,CAAC,gBAAgB,CAAC,CAAC;IACpC,CAAC;IAED,OAAO;QACL,IAAI,EAAE,IAAI,CAAC,IAAI,IAAI,QAAQ,CAAC,IAAI,IAAI,SAAS;QAC7C,WAAW,EAAE,IAAI,CAAC,WAAW,IAAI,QAAQ,CAAC,WAAW,IAAI,0BAA0B;QACnF,MAAM,EAAE,IAAI,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,IAAI,EAAE,CAAC;QACzE,cAAc,EAAE,IAAI,CAAC,EAAE,IAAI,QAAQ,CAAC,cAAc,IAAI,KAAK;QAC3D,WAAW,EAAE,IAAI,CAAC,cAAc,CAAC,IAAI,KAAK;KAC3C,CAAC;AACJ,CAAC"}
@@ -0,0 +1,19 @@
1
+ import type { UserInput } from './prompts.js';
2
+ /**
3
+ * Generate a customized package.json object for the user's project.
4
+ */
5
+ export declare function generatePackageJson(input: UserInput): Record<string, unknown>;
6
+ /**
7
+ * Inject user-provided values into the config.ts template content.
8
+ * Replaces __TITLE__, __DESCRIPTION__, __AUTHOR__ placeholders.
9
+ */
10
+ export declare function injectConfigValues(template: string, input: UserInput): string;
11
+ /**
12
+ * Copy template files to the target directory and generate customized files.
13
+ * Throws if the target directory already exists.
14
+ */
15
+ export declare function copyTemplate(targetDir: string, input: UserInput): Promise<void>;
16
+ /**
17
+ * Remove the target directory and all its contents.
18
+ */
19
+ export declare function cleanup(targetDir: string): void;
@@ -0,0 +1,119 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
5
+ const TEMPLATE_DIR = path.resolve(__dirname, '../template');
6
+ /**
7
+ * Generate a customized package.json object for the user's project.
8
+ */
9
+ export function generatePackageJson(input) {
10
+ return {
11
+ name: input.name,
12
+ private: true,
13
+ version: '0.0.0',
14
+ type: 'module',
15
+ description: input.description,
16
+ author: input.author,
17
+ scripts: {
18
+ dev: 'npm run build:posts && vite',
19
+ 'build:posts': 'npx tsx node_modules/@s-blog/core/scripts/generate-posts-data.ts',
20
+ 'build:albums': 'npx tsx node_modules/@s-blog/core/scripts/generate-albums-data.ts',
21
+ 'build:seo': 'npx tsx node_modules/@s-blog/core/scripts/generate-seo.ts && npx tsx node_modules/@s-blog/core/scripts/generate-sitemap.ts && npx tsx node_modules/@s-blog/core/scripts/generate-rss.ts && npx tsx node_modules/@s-blog/core/scripts/generate-robots.ts',
22
+ build: 'npm run build:albums && npm run build:posts && tsc && vite build && npm run build:seo',
23
+ preview: 'vite preview',
24
+ },
25
+ dependencies: {
26
+ '@s-blog/core': '^0.1.0',
27
+ 'react': '^19.2.1',
28
+ 'react-dom': '^19.2.1',
29
+ },
30
+ devDependencies: {
31
+ '@types/react': '^19.2.7',
32
+ '@types/react-dom': '^19.2.3',
33
+ '@vitejs/plugin-react': '^5.1.1',
34
+ 'autoprefixer': '^10.4.23',
35
+ 'postcss': '^8.5.6',
36
+ 'tailwindcss': '^3.4.17',
37
+ 'tsx': '^4.21.0',
38
+ 'typescript': '~5.9.3',
39
+ 'vite': '^7.2.4',
40
+ },
41
+ };
42
+ }
43
+ /**
44
+ * Inject user-provided values into the config.ts template content.
45
+ * Replaces __TITLE__, __DESCRIPTION__, __AUTHOR__ placeholders.
46
+ */
47
+ export function injectConfigValues(template, input) {
48
+ return template
49
+ .replace('__TITLE__', input.name)
50
+ .replace('__DESCRIPTION__', input.description)
51
+ .replace('__AUTHOR__', input.author);
52
+ }
53
+ /**
54
+ * Recursively copy a directory.
55
+ */
56
+ function copyDir(src, dest) {
57
+ fs.mkdirSync(dest, { recursive: true });
58
+ for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
59
+ const srcPath = path.join(src, entry.name);
60
+ // Rename _gitignore to .gitignore (npm strips .gitignore during publish)
61
+ const destName = entry.name === '_gitignore' ? '.gitignore' : entry.name;
62
+ const destPath = path.join(dest, destName);
63
+ if (entry.isDirectory()) {
64
+ copyDir(srcPath, destPath);
65
+ }
66
+ else {
67
+ fs.copyFileSync(srcPath, destPath);
68
+ }
69
+ }
70
+ }
71
+ /**
72
+ * Copy template files to the target directory and generate customized files.
73
+ * Throws if the target directory already exists.
74
+ */
75
+ export async function copyTemplate(targetDir, input) {
76
+ // Check if target directory already exists
77
+ if (fs.existsSync(targetDir)) {
78
+ throw new Error(`DIRECTORY_EXISTS:${path.basename(targetDir)}`);
79
+ }
80
+ try {
81
+ // Create target directory
82
+ fs.mkdirSync(targetDir, { recursive: true });
83
+ // Copy all template files
84
+ copyDir(TEMPLATE_DIR, targetDir);
85
+ // Generate and write customized package.json
86
+ const packageJson = generatePackageJson(input);
87
+ fs.writeFileSync(path.join(targetDir, 'package.json'), JSON.stringify(packageJson, null, 2) + '\n');
88
+ // Inject user config values into src/config.ts
89
+ const configPath = path.join(targetDir, 'src', 'config.ts');
90
+ if (fs.existsSync(configPath)) {
91
+ const configTemplate = fs.readFileSync(configPath, 'utf-8');
92
+ const configContent = injectConfigValues(configTemplate, input);
93
+ fs.writeFileSync(configPath, configContent);
94
+ }
95
+ }
96
+ catch (err) {
97
+ // Clean up on failure (unless it was a directory exists error)
98
+ if (err instanceof Error && err.message.startsWith('DIRECTORY_EXISTS:')) {
99
+ throw err;
100
+ }
101
+ // Attempt cleanup
102
+ cleanup(targetDir);
103
+ throw new Error('COPY_FAILED');
104
+ }
105
+ }
106
+ /**
107
+ * Remove the target directory and all its contents.
108
+ */
109
+ export function cleanup(targetDir) {
110
+ try {
111
+ if (fs.existsSync(targetDir)) {
112
+ fs.rmSync(targetDir, { recursive: true, force: true });
113
+ }
114
+ }
115
+ catch {
116
+ // Best-effort cleanup, ignore errors
117
+ }
118
+ }
119
+ //# sourceMappingURL=scaffold.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scaffold.js","sourceRoot":"","sources":["../src/scaffold.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-s-blog",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "create-s-blog": "./dist/index.js"
@@ -8,7 +8,8 @@
8
8
  "files": ["dist/", "template/"],
9
9
  "scripts": {
10
10
  "build": "tsc",
11
- "dev": "tsc --watch"
11
+ "dev": "tsc --watch",
12
+ "prepublishOnly": "npm run build"
12
13
  },
13
14
  "dependencies": {
14
15
  "prompts": "^2.4.2",