@oss-ma/tpl 1.0.1 → 1.0.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.
@@ -21,35 +21,55 @@ const TEXT_EXT = new Set([
21
21
  ".cjs",
22
22
  ".mjs"
23
23
  ]);
24
+ /**
25
+ * Dotfiles that MUST be copied if present in template root.
26
+ * Some Windows + tooling edge cases can hide them from readdir.
27
+ */
28
+ const MUST_COPY_DOTFILES = [".gitignore", ".editorconfig", ".gitattributes"];
24
29
  function isTextFile(filePath) {
25
30
  const ext = path.extname(filePath).toLowerCase();
26
31
  if (TEXT_EXT.has(ext))
27
32
  return true;
28
- // Special dotfiles with no extension
29
33
  const base = path.basename(filePath);
30
34
  if (base === "Dockerfile")
31
35
  return true;
32
36
  return false;
33
37
  }
38
+ async function copyOneFile(srcPath, destPath, vars) {
39
+ await fs.ensureDir(path.dirname(destPath));
40
+ if (isTextFile(srcPath)) {
41
+ const raw = await fs.readFile(srcPath, "utf8");
42
+ const rendered = renderString(raw, vars);
43
+ await fs.writeFile(destPath, rendered, "utf8");
44
+ }
45
+ else {
46
+ await fs.copyFile(srcPath, destPath);
47
+ }
48
+ }
34
49
  export async function copyAndRenderDir(srcDir, destDir, vars) {
35
50
  await fs.ensureDir(destDir);
51
+ // 0) Fail-safe: explicitly copy must-have dotfiles if they exist in this directory
52
+ // (especially important for template root where .gitignore lives)
53
+ for (const dot of MUST_COPY_DOTFILES) {
54
+ const srcDot = path.join(srcDir, dot);
55
+ const destDot = path.join(destDir, dot);
56
+ if (await fs.pathExists(srcDot)) {
57
+ await copyOneFile(srcDot, destDot, vars);
58
+ }
59
+ }
36
60
  const entries = await fs.readdir(srcDir, { withFileTypes: true });
37
- for (const e of entries) {
38
- const srcPath = path.join(srcDir, e.name);
39
- const destPath = path.join(destDir, e.name);
40
- if (e.isDirectory()) {
61
+ for (const entry of entries) {
62
+ // Skip the dotfiles already handled explicitly above (avoid duplicate work)
63
+ if (MUST_COPY_DOTFILES.includes(entry.name))
64
+ continue;
65
+ const srcPath = path.join(srcDir, entry.name);
66
+ const destPath = path.join(destDir, entry.name);
67
+ if (entry.isDirectory()) {
41
68
  await copyAndRenderDir(srcPath, destPath, vars);
42
69
  continue;
43
70
  }
44
- if (e.isFile()) {
45
- if (isTextFile(srcPath)) {
46
- const raw = await fs.readFile(srcPath, "utf8");
47
- const out = renderString(raw, vars);
48
- await fs.outputFile(destPath, out, "utf8");
49
- }
50
- else {
51
- await fs.copyFile(srcPath, destPath);
52
- }
53
- }
71
+ if (!entry.isFile())
72
+ continue;
73
+ await copyOneFile(srcPath, destPath, vars);
54
74
  }
55
75
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oss-ma/tpl",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "description": "Generate, enforce and maintain clean project architectures",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,5 +0,0 @@
1
- import { defineConfig } from "vite";
2
- import react from "@vitejs/plugin-react";
3
- export default defineConfig({
4
- plugins: [react()]
5
- });
@@ -1,10 +0,0 @@
1
- import { defineConfig } from "vitest/config";
2
- import react from "@vitejs/plugin-react";
3
-
4
- export default defineConfig({
5
- plugins: [react()],
6
- test: {
7
- environment: "jsdom",
8
- setupFiles: ["./vitest.setup.ts"]
9
- }
10
- });