Skip to content

Commit e7dee5f

Browse files
authored
Merge pull request #17 from YagoBorba/feature/advanced-templates
feat(core): ✨ implements intelligent, composable template system
2 parents 3e7ca25 + b0b131e commit e7dee5f

10 files changed

Lines changed: 95 additions & 84 deletions

File tree

packages/cli/dist/commands/generate.js

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,6 @@ async function handleFileGeneration(options) {
2424
name: 'overwrite',
2525
message: t(options.overwriteMsgKey),
2626
default: false,
27-
choices: [
28-
{ name: t('common.yes'), value: true },
29-
{ name: t('common.no'), value: false },
30-
],
3127
}]);
3228
if (!overwrite) {
3329
console.log(chalk.yellow(t('common.operation_cancelled')));
@@ -40,7 +36,7 @@ async function handleFileGeneration(options) {
4036
console.log(chalk.green.bold(t(options.successMsgKey)));
4137
}
4238
export const getGenerateCommand = () => ({
43-
command: 'generate',
39+
command: 'generate [filetype]',
4440
describe: t('generate.command_description'),
4541
builder: (yargs) => yargs.positional('filetype', {
4642
describe: t('generate.option_filetype_description'),
@@ -64,7 +60,7 @@ export const getGenerateCommand = () => ({
6460
fileName: '.gitignore',
6561
overwriteMsgKey: 'generate.prompt.gitignore_overwrite',
6662
successMsgKey: 'generate.success.gitignore',
67-
contentPromise: generateGitignoreContent(stack),
63+
contentPromise: generateGitignoreContent([stack]),
6864
});
6965
}
7066
return;
@@ -96,7 +92,7 @@ export const getGenerateCommand = () => ({
9692
fileName: '.gitignore',
9793
overwriteMsgKey: 'generate.prompt.gitignore_overwrite',
9894
successMsgKey: 'generate.success.gitignore',
99-
contentPromise: generateGitignoreContent(stack),
95+
contentPromise: generateGitignoreContent([stack]),
10096
});
10197
}
10298
},

packages/cli/dist/commands/init.js

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import inquirer from 'inquirer';
22
import chalk from 'chalk';
33
import fs from 'fs/promises';
44
import path from 'path';
5-
import { scaffoldProject, setupHusky, generateReadmeContent, generateGitignoreContent, runCommand, } from '@stackcode/core';
5+
import { scaffoldProject, setupHusky, generateReadmeContent, generateGitignoreContent, runCommand } from '@stackcode/core';
66
import { t } from '@stackcode/i18n';
77
export const getInitCommand = () => ({
88
command: 'init',
@@ -14,7 +14,7 @@ export const getInitCommand = () => ({
1414
const answers = await inquirer.prompt([
1515
{
1616
type: 'input', name: 'projectName', message: t('init.prompt.project_name'),
17-
validate: (input) => input ? true : t('init.prompt.project_name_error'),
17+
validate: (input) => !!input || t('init.prompt.project_name_error'),
1818
},
1919
{
2020
type: 'input', name: 'description', message: t('init.prompt.description'),
@@ -58,37 +58,40 @@ export const getInitCommand = () => ({
5858
description: answers.description,
5959
authorName: answers.authorName,
6060
};
61-
console.log(chalk.blue(` ${t('init.step.scaffold')}`));
62-
scaffoldProject({
61+
const projectOptions = {
6362
projectPath,
6463
stack: answers.stack,
6564
features: answers.features,
6665
replacements,
67-
});
66+
};
67+
console.log(chalk.blue(`   ${t('init.step.scaffold')}`));
68+
await scaffoldProject(projectOptions);
6869
if (answers.features.includes('husky') && answers.commitValidation !== undefined) {
69-
const config = { features: { commitValidation: answers.commitValidation } };
70+
const config = {
71+
stack: answers.stack,
72+
features: { commitValidation: answers.commitValidation }
73+
};
7074
await fs.writeFile(path.join(projectPath, '.stackcoderc.json'), JSON.stringify(config, null, 2));
7175
}
72-
console.log(chalk.blue(` ${t('init.step.readme')}`));
76+
console.log(chalk.blue(`   ${t('init.step.readme')}`));
7377
const readmeContent = await generateReadmeContent();
7478
await fs.writeFile(path.join(projectPath, 'README.md'), readmeContent);
75-
console.log(chalk.blue(` ${t('init.step.gitignore')}`));
76-
// CORREÇÃO: Passando a 'stack' selecionada pelo usuário para a função.
77-
const gitignoreContent = await generateGitignoreContent(answers.stack);
79+
console.log(chalk.blue(`   ${t('init.step.gitignore')}`));
80+
const gitignoreContent = await generateGitignoreContent([answers.stack]);
7881
await fs.writeFile(path.join(projectPath, '.gitignore'), gitignoreContent);
7982
if (answers.features.includes('husky')) {
80-
console.log(chalk.blue(` ${t('init.step.husky')}`));
81-
setupHusky(projectPath);
83+
console.log(chalk.blue(`   ${t('init.step.husky')}`));
84+
await setupHusky(projectPath);
8285
}
83-
console.log(chalk.blue(` ${t('init.step.git')}`));
86+
console.log(chalk.blue(`   ${t('init.step.git')}`));
8487
await runCommand('git', ['init'], { cwd: projectPath });
85-
console.log(chalk.blue(` ${t('init.step.deps')}`));
88+
console.log(chalk.blue(`   ${t('init.step.deps')}`));
8689
await runCommand('npm', ['install'], { cwd: projectPath });
8790
console.log(chalk.gray('----------------------------------------------------'));
8891
console.log(chalk.green.bold(t('init.success.ready')));
8992
console.log(chalk.cyan(`\n${t('init.success.next_steps')}`));
90-
console.log(` 1. cd ${answers.projectName}`);
91-
console.log(' 2. Open the project in your favorite editor.');
92-
console.log(' 3. Start coding! 🎉');
93+
console.log(`   1. cd ${answers.projectName}`);
94+
console.log('   2. Open the project in your favorite editor.');
95+
console.log('   3. Start coding! 🎉');
9396
},
9497
});

packages/cli/src/commands/generate.ts

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ async function getProjectStack(): Promise<string> {
1616
return 'node-ts';
1717
}
1818
}
19-
2019
async function handleFileGeneration(options: {
2120
fileName: string;
2221
overwriteMsgKey: string;
@@ -31,10 +30,6 @@ async function handleFileGeneration(options: {
3130
name: 'overwrite',
3231
message: t(options.overwriteMsgKey),
3332
default: false,
34-
choices: [
35-
{ name: t('common.yes'), value: true },
36-
{ name: t('common.no'), value: false },
37-
],
3833
}]);
3934
if (!overwrite) {
4035
console.log(chalk.yellow(t('common.operation_cancelled')));
@@ -48,7 +43,7 @@ async function handleFileGeneration(options: {
4843
}
4944

5045
export const getGenerateCommand = (): CommandModule => ({
51-
command: 'generate',
46+
command: 'generate [filetype]',
5247
describe: t('generate.command_description'),
5348
builder: (yargs) =>
5449
yargs.positional('filetype', {
@@ -74,7 +69,7 @@ export const getGenerateCommand = (): CommandModule => ({
7469
fileName: '.gitignore',
7570
overwriteMsgKey: 'generate.prompt.gitignore_overwrite',
7671
successMsgKey: 'generate.success.gitignore',
77-
contentPromise: generateGitignoreContent(stack),
72+
contentPromise: generateGitignoreContent([stack]),
7873
});
7974
}
8075
return;
@@ -109,7 +104,7 @@ export const getGenerateCommand = (): CommandModule => ({
109104
fileName: '.gitignore',
110105
overwriteMsgKey: 'generate.prompt.gitignore_overwrite',
111106
successMsgKey: 'generate.success.gitignore',
112-
contentPromise: generateGitignoreContent(stack),
107+
contentPromise: generateGitignoreContent([stack]),
113108
});
114109
}
115110
},

packages/cli/src/commands/init.ts

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
generateReadmeContent,
1010
generateGitignoreContent,
1111
runCommand,
12+
type ProjectOptions
1213
} from '@stackcode/core';
1314
import { t } from '@stackcode/i18n';
1415

@@ -23,7 +24,7 @@ export const getInitCommand = (): CommandModule => ({
2324
const answers = await inquirer.prompt([
2425
{
2526
type: 'input', name: 'projectName', message: t('init.prompt.project_name'),
26-
validate: (input) => input ? true : t('init.prompt.project_name_error'),
27+
validate: (input) => !!input || t('init.prompt.project_name_error'),
2728
},
2829
{
2930
type: 'input', name: 'description', message: t('init.prompt.description'),
@@ -71,44 +72,48 @@ export const getInitCommand = (): CommandModule => ({
7172
authorName: answers.authorName,
7273
};
7374

74-
console.log(chalk.blue(` ${t('init.step.scaffold')}`));
75-
scaffoldProject({
75+
const projectOptions: ProjectOptions = {
7676
projectPath,
7777
stack: answers.stack,
7878
features: answers.features,
7979
replacements,
80-
});
80+
};
81+
82+
console.log(chalk.blue(`   ${t('init.step.scaffold')}`));
83+
await scaffoldProject(projectOptions);
8184

8285
if (answers.features.includes('husky') && answers.commitValidation !== undefined) {
83-
const config = { features: { commitValidation: answers.commitValidation } };
86+
const config = {
87+
stack: answers.stack,
88+
features: { commitValidation: answers.commitValidation }
89+
};
8490
await fs.writeFile(path.join(projectPath, '.stackcoderc.json'), JSON.stringify(config, null, 2));
8591
}
8692

87-
console.log(chalk.blue(` ${t('init.step.readme')}`));
93+
console.log(chalk.blue(`   ${t('init.step.readme')}`));
8894
const readmeContent = await generateReadmeContent();
8995
await fs.writeFile(path.join(projectPath, 'README.md'), readmeContent);
9096

91-
console.log(chalk.blue(` ${t('init.step.gitignore')}`));
92-
// CORREÇÃO: Passando a 'stack' selecionada pelo usuário para a função.
93-
const gitignoreContent = await generateGitignoreContent(answers.stack);
97+
console.log(chalk.blue(`   ${t('init.step.gitignore')}`));
98+
const gitignoreContent = await generateGitignoreContent([answers.stack]);
9499
await fs.writeFile(path.join(projectPath, '.gitignore'), gitignoreContent);
95100

96101
if (answers.features.includes('husky')) {
97-
console.log(chalk.blue(` ${t('init.step.husky')}`));
98-
setupHusky(projectPath);
102+
console.log(chalk.blue(`   ${t('init.step.husky')}`));
103+
await setupHusky(projectPath);
99104
}
100105

101-
console.log(chalk.blue(` ${t('init.step.git')}`));
106+
console.log(chalk.blue(`   ${t('init.step.git')}`));
102107
await runCommand('git', ['init'], { cwd: projectPath });
103108

104-
console.log(chalk.blue(` ${t('init.step.deps')}`));
109+
console.log(chalk.blue(`   ${t('init.step.deps')}`));
105110
await runCommand('npm', ['install'], { cwd: projectPath });
106111

107112
console.log(chalk.gray('----------------------------------------------------'));
108113
console.log(chalk.green.bold(t('init.success.ready')));
109114
console.log(chalk.cyan(`\n${t('init.success.next_steps')}`));
110-
console.log(` 1. cd ${answers.projectName}`);
111-
console.log(' 2. Open the project in your favorite editor.');
112-
console.log(' 3. Start coding! 🎉');
115+
console.log(`   1. cd ${answers.projectName}`);
116+
console.log('   2. Open the project in your favorite editor.');
117+
console.log('   3. Start coding! 🎉');
113118
},
114119
});

packages/core/dist/generators.d.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
/**
2-
* Reads the content of the .gitignore template for a specific stack.
3-
* @param {string} stack - The technology stack (e.g., 'node-ts').
4-
* @returns {Promise<string>} The template content.
2+
* Generates a .gitignore file content by combining multiple templates.
3+
* @param technologies An array of strings representing the technologies (e.g., ['node', 'ides']).
4+
* @returns {Promise<string>} The combined and formatted .gitignore content.
55
*/
6-
export declare function generateGitignoreContent(stack: string): Promise<string>;
6+
export declare function generateGitignoreContent(technologies: string[]): Promise<string>;
77
/**
88
* Reads the content of the default README.md template.
99
* @returns {Promise<string>} The template content.

packages/core/dist/generators.js

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,31 @@ import { fileURLToPath } from 'url';
44
const __filename = fileURLToPath(import.meta.url);
55
const __dirname = path.dirname(__filename);
66
/**
7-
* Reads the content of the .gitignore template for a specific stack.
8-
* @param {string} stack - The technology stack (e.g., 'node-ts').
9-
* @returns {Promise<string>} The template content.
7+
* Generates a .gitignore file content by combining multiple templates.
8+
* @param technologies An array of strings representing the technologies (e.g., ['node', 'ides']).
9+
* @returns {Promise<string>} The combined and formatted .gitignore content.
1010
*/
11-
export async function generateGitignoreContent(stack) {
12-
const templatePath = path.resolve(__dirname, `templates/${stack}/gitignore.tpl`);
13-
return fs.readFile(templatePath, 'utf-8');
11+
export async function generateGitignoreContent(technologies) {
12+
const contentParts = [];
13+
const allTechs = [...new Set(technologies)];
14+
for (const tech of allTechs) {
15+
const templatePath = path.resolve(__dirname, 'templates/gitignore', `${tech}.tpl`);
16+
try {
17+
const templateContent = await fs.readFile(templatePath, 'utf-8');
18+
const header = `# --- ${tech.charAt(0).toUpperCase() + tech.slice(1)} ---`;
19+
contentParts.push(header, templateContent.trim(), '');
20+
}
21+
catch (error) {
22+
console.warn(`[Warning] Gitignore template for '${tech}' not found. Skipping.`);
23+
}
24+
}
25+
return contentParts.join('\n');
1426
}
1527
/**
1628
* Reads the content of the default README.md template.
1729
* @returns {Promise<string>} The template content.
1830
*/
1931
export async function generateReadmeContent() {
20-
// Este caminho já estava correto.
2132
const templatePath = path.resolve(__dirname, 'templates/readme/default.tpl');
2233
return fs.readFile(templatePath, 'utf-8');
2334
}
File renamed without changes.

packages/core/src/generators.ts

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,36 @@ const __filename = fileURLToPath(import.meta.url);
66
const __dirname = path.dirname(__filename);
77

88
/**
9-
* Reads the content of the .gitignore template for a specific stack.
10-
* @param {string} stack - The technology stack (e.g., 'node-ts').
11-
* @returns {Promise<string>} The template content.
9+
* Generates a .gitignore file content by combining multiple templates.
10+
* @param technologies An array of strings representing the technologies (e.g., ['node', 'ides']).
11+
* @returns {Promise<string>} The combined and formatted .gitignore content.
1212
*/
13-
export async function generateGitignoreContent(stack: string): Promise<string> {
14-
const templatePath = path.resolve(__dirname, `templates/${stack}/gitignore.tpl`);
15-
return fs.readFile(templatePath, 'utf-8');
13+
export async function generateGitignoreContent(technologies: string[]): Promise<string> {
14+
const contentParts: string[] = [];
15+
16+
const allTechs = [...new Set(technologies)];
17+
18+
for (const tech of allTechs) {
19+
const templatePath = path.resolve(__dirname, 'templates/gitignore', `${tech}.tpl`);
20+
21+
try {
22+
const templateContent = await fs.readFile(templatePath, 'utf-8');
23+
24+
const header = `# --- ${tech.charAt(0).toUpperCase() + tech.slice(1)} ---`;
25+
contentParts.push(header, templateContent.trim(), '');
26+
} catch (error) {
27+
console.warn(`[Warning] Gitignore template for '${tech}' not found. Skipping.`);
28+
}
29+
}
30+
31+
return contentParts.join('\n');
1632
}
1733

1834
/**
1935
* Reads the content of the default README.md template.
2036
* @returns {Promise<string>} The template content.
2137
*/
2238
export async function generateReadmeContent(): Promise<string> {
23-
// Este caminho já estava correto.
2439
const templatePath = path.resolve(__dirname, 'templates/readme/default.tpl');
2540
return fs.readFile(templatePath, 'utf-8');
2641
}

packages/core/src/release-worker.cjs

Lines changed: 0 additions & 18 deletions
This file was deleted.
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Logs
2+
logs
3+
*.log
4+
npm-debug.log*

0 commit comments

Comments
 (0)