@bottomlessmargaritas/formatting-configs 1.0.0 → 1.1.0

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.
Files changed (2) hide show
  1. package/bin/cli.js +36 -71
  2. package/package.json +1 -1
package/bin/cli.js CHANGED
@@ -3,31 +3,36 @@
3
3
  import {
4
4
  existsSync,
5
5
  copyFileSync,
6
- mkdirSync,
7
6
  readFileSync,
8
7
  writeFileSync,
9
8
  readdirSync,
10
- renameSync,
11
9
  } from "node:fs";
12
- import { dirname, join, resolve } from "node:path";
10
+ import { dirname, join, resolve, extname, basename } from "node:path";
13
11
  import { fileURLToPath } from "node:url";
14
12
  import { execSync } from "node:child_process";
15
- import { createInterface } from "node:readline";
16
13
 
17
14
  const __dirname = dirname(fileURLToPath(import.meta.url));
18
15
  const CONFIGS_DIR = resolve(__dirname, "..", "configs");
19
16
 
20
- const isAuto = process.argv.includes("--auto");
21
17
  const isDryRun = process.argv.includes("--dry-run");
22
18
  const skipInstall = process.argv.includes("--skip-install");
23
19
 
24
20
  const PKG_NAME = "@bottomlessmargaritas/formatting-configs";
21
+ const NAMESPACE = "bottomlessmargaritas";
25
22
 
23
+ // Namespaced filenames: prettier.config.js → prettier.config.bottomlessmargaritas.js
24
+ function namespacedFileName(file) {
25
+ const ext = extname(file);
26
+ const base = basename(file, ext);
27
+ return `${base}.${NAMESPACE}${ext}`;
28
+ }
29
+
30
+ // Scripts reference the namespaced config files explicitly
26
31
  const SCRIPTS_TO_ADD = {
27
- format: 'prettier --write "**/*.{js,jsx,ts,tsx,json,css,scss,md}"',
28
- "format:check": 'prettier --check "**/*.{js,jsx,ts,tsx,json,css,scss,md}"',
29
- lint: "eslint .",
30
- "lint:fix": "eslint . --fix",
32
+ [`${NAMESPACE}:format`]: `prettier --config ${namespacedFileName("prettier.config.js")} --write "**/*.{js,jsx,ts,tsx,json,css,scss,md}"`,
33
+ [`${NAMESPACE}:format:check`]: `prettier --config ${namespacedFileName("prettier.config.js")} --check "**/*.{js,jsx,ts,tsx,json,css,scss,md}"`,
34
+ [`${NAMESPACE}:lint`]: `eslint --config ${namespacedFileName("eslint.config.js")} .`,
35
+ [`${NAMESPACE}:lint:fix`]: `eslint --config ${namespacedFileName("eslint.config.js")} . --fix`,
31
36
  };
32
37
 
33
38
  const PEER_DEPS = {
@@ -42,7 +47,6 @@ const PEER_DEPS = {
42
47
  "typescript-eslint": "^8",
43
48
  };
44
49
 
45
- // React-related deps — only installed if project uses React
46
50
  const REACT_PEER_DEPS = {
47
51
  "@babel/eslint-parser": "^7",
48
52
  "eslint-plugin-jsx-a11y": "^6",
@@ -61,11 +65,6 @@ function findProjectRoot(startDir) {
61
65
  return null;
62
66
  }
63
67
 
64
- function getBackupName(filePath) {
65
- const timestamp = new Date().toISOString().replace(/[:.]/g, "-").slice(0, 19);
66
- return `${filePath}.backup-${timestamp}`;
67
- }
68
-
69
68
  function detectPackageManager(projectRoot) {
70
69
  if (existsSync(join(projectRoot, "pnpm-lock.yaml"))) {
71
70
  return "pnpm";
@@ -89,25 +88,15 @@ function projectUsesReact(projectRoot) {
89
88
  }
90
89
  }
91
90
 
92
- async function prompt(question) {
93
- const rl = createInterface({ input: process.stdin, output: process.stdout });
94
- return new Promise((resolve) => {
95
- rl.question(question, (answer) => {
96
- rl.close();
97
- resolve(answer.trim().toLowerCase());
98
- });
99
- });
100
- }
101
-
102
- async function copyConfigFiles(projectRoot) {
91
+ function copyConfigFiles(projectRoot) {
103
92
  const configFiles = readdirSync(CONFIGS_DIR);
104
93
  let copied = 0;
105
- let backed = 0;
106
94
  let skipped = 0;
107
95
 
108
96
  for (const file of configFiles) {
109
97
  const source = join(CONFIGS_DIR, file);
110
- const target = join(projectRoot, file);
98
+ const targetName = namespacedFileName(file);
99
+ const target = join(projectRoot, targetName);
111
100
 
112
101
  if (existsSync(target)) {
113
102
  const sourceContent = readFileSync(source, "utf8");
@@ -117,46 +106,23 @@ async function copyConfigFiles(projectRoot) {
117
106
  skipped++;
118
107
  continue;
119
108
  }
109
+ }
120
110
 
121
- if (isAuto) {
122
- const backupPath = getBackupName(target);
123
- if (!isDryRun) {
124
- renameSync(target, backupPath);
125
- copyFileSync(source, target);
126
- console.log(` ↪ Backed up existing ${file} → ${backupPath.split("/").pop()}`);
127
- }
128
- backed++;
129
- copied++;
130
- } else {
131
- const answer = await prompt(` ${file} already exists and differs. Overwrite? (y/n) `);
132
- if (answer !== "y") {
133
- skipped++;
134
- continue;
135
- }
136
-
137
- const backupPath = getBackupName(target);
138
- if (!isDryRun) {
139
- renameSync(target, backupPath);
140
- copyFileSync(source, target);
141
- console.log(` ↪ Backed up → ${backupPath.split("/").pop()}`);
142
- }
143
- backed++;
144
- copied++;
145
- }
111
+ if (isDryRun) {
112
+ console.log(`[dry-run] Would write: ${targetName}`);
146
113
  } else {
147
- if (!isDryRun) {
148
- copyFileSync(source, target);
149
- }
150
- copied++;
114
+ copyFileSync(source, target);
151
115
  }
116
+ copied++;
152
117
  }
153
118
 
154
- console.log(`${PKG_NAME}: ${copied} config(s) copied, ${backed} backed up, ${skipped} unchanged`);
119
+ console.log(`${PKG_NAME}: ${copied} config(s) written, ${skipped} unchanged`);
155
120
  }
156
121
 
157
122
  function updatePackageJsonScripts(projectRoot) {
158
123
  const pkgPath = join(projectRoot, "package.json");
159
- const pkg = JSON.parse(readFileSync(pkgPath, "utf8"));
124
+ const raw = readFileSync(pkgPath, "utf8");
125
+ const pkg = JSON.parse(raw);
160
126
 
161
127
  if (!pkg.scripts) {
162
128
  pkg.scripts = {};
@@ -171,12 +137,14 @@ function updatePackageJsonScripts(projectRoot) {
171
137
  }
172
138
 
173
139
  if (added > 0) {
174
- if (!isDryRun) {
140
+ if (isDryRun) {
141
+ console.log(`[dry-run] Would add ${added} script(s) to package.json`);
142
+ } else {
175
143
  writeFileSync(pkgPath, JSON.stringify(pkg, null, 4) + "\n", "utf8");
176
144
  }
177
- console.log(`${PKG_NAME}: Added ${added} script(s) to package.json (format, format:check, lint, lint:fix)`);
145
+ console.log(`${PKG_NAME}: Added ${added} namespaced script(s) to package.json`);
178
146
  } else {
179
- console.log(`${PKG_NAME}: All formatting scripts already present in package.json`);
147
+ console.log(`${PKG_NAME}: All namespaced scripts already present in package.json`);
180
148
  }
181
149
  }
182
150
 
@@ -205,18 +173,18 @@ function installMissingPeers(projectRoot) {
205
173
 
206
174
  console.log(`${PKG_NAME}: Installing ${missing.length} missing peer dep(s) with ${pm}...`);
207
175
 
208
- if (!isDryRun) {
176
+ if (isDryRun) {
177
+ console.log(`[dry-run] Would run: ${installCmd}`);
178
+ } else {
209
179
  try {
210
180
  execSync(installCmd, { cwd: projectRoot, stdio: "inherit" });
211
181
  } catch {
212
182
  console.warn(`${PKG_NAME}: Peer dependency install failed. Run manually:\n ${installCmd}`);
213
183
  }
214
- } else {
215
- console.log(`[dry-run] Would run: ${installCmd}`);
216
184
  }
217
185
  }
218
186
 
219
- async function run() {
187
+ function run() {
220
188
  const cwd = process.env.INIT_CWD || process.cwd();
221
189
  const projectRoot = findProjectRoot(cwd);
222
190
 
@@ -225,7 +193,7 @@ async function run() {
225
193
  process.exit(1);
226
194
  }
227
195
 
228
- await copyConfigFiles(projectRoot);
196
+ copyConfigFiles(projectRoot);
229
197
  updatePackageJsonScripts(projectRoot);
230
198
 
231
199
  if (!skipInstall) {
@@ -233,7 +201,4 @@ async function run() {
233
201
  }
234
202
  }
235
203
 
236
- run().catch((err) => {
237
- console.error(`${PKG_NAME}:`, err.message);
238
- process.exit(1);
239
- });
204
+ run();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bottomlessmargaritas/formatting-configs",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "Canonical Prettier and ESLint configs for @nullvoidundefined projects",
5
5
  "type": "module",
6
6
  "bin": {