Skip to content

Commit 38cc9a4

Browse files
committed
fix: renombrar .gitignore a gitignore en templates para que npm lo incluya
npm excluye archivos llamados .gitignore del paquete publicado. Los scaffolders populares (create-next-app, create-vite) usan el mismo truco: guardan el archivo como 'gitignore' (sin punto) y lo renombran a '.gitignore' al copiar al proyecto destino. - Renombrado template/.gitignore -> template/gitignore - Renombrado template-api/.gitignore -> template-api/gitignore - Agregado renameDotfiles() en copy-template.ts que renombra gitignore -> .gitignore después de copiar - .npmignore agregado en la raíz del repo - Tests actualizados para reflejar el rename
1 parent 1c3eee9 commit 38cc9a4

5 files changed

Lines changed: 44 additions & 5 deletions

File tree

.npmignore

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Excluir lo que no vamos a publicar
2+
node_modules/
3+
coverage/
4+
playwright-report/
5+
test-results/
6+
*.log
7+
.DS_Store
8+
9+
# Pero incluir TODO lo del template, incluyendo dotfiles
10+
!template/**
11+
!template-api/**

src/copy-template.ts

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { cp, mkdir, readFile, readdir, writeFile } from "node:fs/promises";
1+
import { cp, mkdir, readFile, readdir, rm, writeFile } from "node:fs/promises";
22
import { dirname, join, relative } from "node:path";
33

44
export type CopyOptions = {
@@ -36,6 +36,7 @@ export async function copyTemplate(
3636
// Hoy solo es package.json (su nombre), pero dejamos la puerta abierta.
3737
await customizePackageJson(targetDir, options.projectName);
3838
await customizeReadme(targetDir, options.projectName, options.pm);
39+
await renameDotfiles(targetDir);
3940
}
4041

4142
/**
@@ -120,3 +121,27 @@ export async function listFiles(dir: string): Promise<string[]> {
120121
export function getRelativePath(from: string, to: string): string {
121122
return relative(dirname(from), to);
122123
}
124+
125+
/**
126+
* Renombra archivos que npm excluye (como .gitignore) de su versión sin punto
127+
* a la versión con punto en el destino.
128+
*
129+
* npm no publica archivos llamados .gitignore, así que en el template los
130+
* guardamos como 'gitignore' (sin punto) y los renombramos al copiar.
131+
*/
132+
async function renameDotfiles(targetDir: string): Promise<void> {
133+
const renames: Record<string, string> = {
134+
gitignore: ".gitignore",
135+
};
136+
137+
for (const [from, to] of Object.entries(renames)) {
138+
const fromPath = join(targetDir, from);
139+
const toPath = join(targetDir, to);
140+
try {
141+
await cp(fromPath, toPath);
142+
await rm(fromPath);
143+
} catch {
144+
// Si el archivo no existe, no hay nada que renombrar
145+
}
146+
}
147+
}

src/test/copy-template.test.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,10 +68,13 @@ describe("copyTemplate", () => {
6868
const templateFiles = await listFiles(templateDir);
6969
const targetFiles = await listFiles(targetDir);
7070

71-
// Cada archivo del template debe existir en el destino
71+
// Cada archivo del template debe existir en el destino,
72+
// con excepción de los dotfiles que se renombran (gitignore → .gitignore)
73+
const renames: Record<string, string> = { gitignore: ".gitignore" };
7274
for (const file of templateFiles) {
73-
expect(targetFiles, `Archivo faltante en destino: ${file}`).toContain(
74-
file,
75+
const expectedFile = renames[file] ?? file;
76+
expect(targetFiles, `Archivo faltante en destino: ${expectedFile}`).toContain(
77+
expectedFile,
7578
);
7679
}
7780
});
@@ -176,6 +179,6 @@ describe("listFiles", () => {
176179
const templateDir = join(process.cwd(), "template");
177180
const files = await listFiles(templateDir);
178181

179-
expect(files).toContain(".gitignore");
182+
expect(files).toContain("gitignore");
180183
});
181184
});
File renamed without changes.

0 commit comments

Comments
 (0)