create-lib-workspace 1.0.0 → 1.1.1-a

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 (3) hide show
  1. package/README.md +2 -0
  2. package/index.js +215 -149
  3. package/package.json +10 -4
package/README.md CHANGED
@@ -4,6 +4,8 @@ A lightweight CLI tool to instantly scaffold a local development monorepo worksp
4
4
 
5
5
  It automatically sets up a multi-entry library with proper ESM/CJS exports and links it to a static test application using your favorite package manager—completely dependency-free.
6
6
 
7
+ ![creation process](workspaceCreation.png)
8
+
7
9
  ## Installation
8
10
 
9
11
  You can install this tool globally to make it available anywhere on your system, or run it directly without installation.
package/index.js CHANGED
@@ -7,59 +7,70 @@ import readline from 'readline';
7
7
 
8
8
  // Helper to create an interactive terminal prompt using built-in readline
9
9
  function askQuestion(query) {
10
- const rl = readline.createInterface({
11
- input: process.stdin,
12
- output: process.stdout,
13
- });
14
- return new Promise((resolve) => rl.question(query, (ans) => {
15
- rl.close();
16
- resolve(ans.trim());
17
- }));
10
+ const rl = readline.createInterface({
11
+ input: process.stdin,
12
+ output: process.stdout,
13
+ });
14
+ return new Promise(resolve =>
15
+ rl.question(query, ans => {
16
+ rl.close();
17
+ resolve(ans.trim());
18
+ })
19
+ );
18
20
  }
19
21
 
20
22
  async function main() {
21
- console.log('\n📦 Welcome to create-lib-workspace\n');
22
-
23
- // Parse inline arguments
24
- const args = process.argv.slice(2);
25
- let workspaceName = args[0];
26
- let libName = args[1];
27
- let packageName = args[2];
28
- let pkgManager = args[3];
29
-
30
- // Fallback to interactive prompts if arguments are missing
31
- if (!workspaceName) {
32
- workspaceName = await askQuestion('Enter the workspace directory name (e.g. my-workspace): ');
33
- if (!workspaceName) { console.log('❌ Workspace name is required!'); process.exit(1); }
34
- }
23
+ console.log('\n📦 Welcome to create-lib-workspace\n');
35
24
 
36
- if (!libName) {
37
- libName = await askQuestion('Enter the library directory name (e.g. core-lib): ');
38
- if (!libName) { console.log('❌ Library name is required!'); process.exit(1); }
39
- }
25
+ // Parse inline arguments
26
+ const args = process.argv.slice(2);
27
+ let workspaceName = args[0];
28
+ let libName = args[1];
29
+ let packageName = args[2];
30
+ let pkgManager = args[3];
40
31
 
41
- if (!packageName) {
42
- packageName = await askQuestion('Enter the npm package name (e.g. @my-org/core): ');
43
- if (!packageName) { console.log(' Package name is required!'); process.exit(1); }
44
- }
32
+ // Fallback to interactive prompts if arguments are missing
33
+ if (!workspaceName) {
34
+ workspaceName = await askQuestion('Enter the workspace directory name (e.g. my-workspace): ');
35
+ if (!workspaceName) {
36
+ console.log('❌ Workspace name is required!');
37
+ process.exit(1);
38
+ }
39
+ }
45
40
 
46
- if (!pkgManager) {
47
- console.log('\nSelect package manager:\n1) pnpm (Default)\n2) npm\n3) yarn');
48
- const choice = await askQuestion('Enter number [1-3]: ');
49
- if (choice === '2') pkgManager = 'npm';
50
- else if (choice === '3') pkgManager = 'yarn';
51
- else pkgManager = 'pnpm';
52
- }
41
+ if (!libName) {
42
+ libName = await askQuestion('Enter the library directory name (e.g. core-lib): ');
43
+ if (!libName) {
44
+ console.log('❌ Library name is required!');
45
+ process.exit(1);
46
+ }
47
+ }
48
+
49
+ if (!packageName) {
50
+ packageName = await askQuestion('Enter the npm package name (e.g. @my-org/core): ');
51
+ if (!packageName) {
52
+ console.log('❌ Package name is required!');
53
+ process.exit(1);
54
+ }
55
+ }
53
56
 
54
- const workspacePath = path.resolve(workspaceName);
55
- const appPath = path.join(workspacePath, 'app');
56
- const libPath = path.join(workspacePath, libName);
57
+ if (!pkgManager) {
58
+ console.log('\nSelect package manager:\n1) pnpm (Default)\n2) npm\n3) yarn');
59
+ const choice = await askQuestion('Enter number [1-3]: ');
60
+ if (choice === '2') pkgManager = 'npm';
61
+ else if (choice === '3') pkgManager = 'yarn';
62
+ else pkgManager = 'pnpm';
63
+ }
57
64
 
58
- // 1. Create Workspace & App Structure
59
- console.log('\n[1/5] Creating workspace and consumer application...');
60
- fs.mkdirSync(appPath, { recursive: true });
65
+ const workspacePath = path.resolve(workspaceName);
66
+ const appPath = path.join(workspacePath, 'app');
67
+ const libPath = path.join(workspacePath, libName);
61
68
 
62
- const htmlContent = `<!doctype html>
69
+ // 1. Create Workspace & App Structure
70
+ console.log('\n[1/5] Creating workspace and consumer application...');
71
+ fs.mkdirSync(appPath, { recursive: true });
72
+
73
+ const htmlContent = `<!doctype html>
63
74
  <html>
64
75
  <head>
65
76
  <meta charset="UTF-8" />
@@ -71,7 +82,7 @@ async function main() {
71
82
  </body>
72
83
  </html>`;
73
84
 
74
- const mainJsContent = `import { pluck } from "${packageName}";
85
+ const mainJsContent = `import { pluck } from "${packageName}";
75
86
  import { increaseAllOf, lowerCaseAllOf } from "${packageName}/modifiers";
76
87
 
77
88
  const users = [
@@ -84,71 +95,124 @@ console.log("Plucked Names:", pluck(users, 'name'));
84
95
  console.log("Increased Age:", increaseAllOf(users, 'age'));
85
96
  console.log("Lowercased Names:", lowerCaseAllOf(users, 'name'));`;
86
97
 
87
- fs.writeFileSync(path.join(appPath, 'index.html'), htmlContent);
88
- fs.writeFileSync(path.join(appPath, 'main.js'), mainJsContent);
89
-
90
- // 2. Run Vite Scaffolding
91
- console.log('\n---------------------------------------------------------');
92
- console.log('⚠️ ATTENTION / IMPORTANT NOTE:');
93
- console.log('Vite will now prompt you to target a framework and a variant.');
94
- console.log('1. Please SELECT "Vanilla" and "JavaScript".');
95
- console.log('2. ❌ DO NOT let it install dependencies or run immediately!');
96
- console.log('---------------------------------------------------------\n');
97
-
98
- try {
99
- execSync(`${pkgManager} create vite ${libName} --template vanilla`, {
100
- cwd: workspacePath,
101
- stdio: 'inherit',
102
- });
103
- } catch (error) {
104
- console.log('❌ Vite scaffolding failed or was aborted.');
105
- process.exit(1);
106
- }
98
+ fs.writeFileSync(path.join(appPath, 'index.html'), htmlContent);
99
+ fs.writeFileSync(path.join(appPath, 'main.js'), mainJsContent);
107
100
 
108
- // 3. Clean up Vite Boilerplate & Generate Library Sources
109
- console.log('\n[2/5] Polishing library structure and writing source files...');
110
- fs.rmSync(path.join(libPath, 'src'), { recursive: true, force: true });
111
- fs.mkdirSync(path.join(libPath, 'src/modifiers'), { recursive: true });
112
-
113
- // Dynamically fetch the absolute latest Vite version from registry
114
- let viteVersion = '5.0.0';
115
- try {
116
- viteVersion = execSync('npm info vite version', { encoding: 'utf8' }).trim();
117
- } catch (e) {
118
- // Graceful fallback if no network
119
- }
101
+ // 2. Run Vite Scaffolding
102
+ console.log('\n---------------------------------------------------------');
103
+ console.log('⚠️ ATTENTION / IMPORTANT NOTE:');
104
+ console.log('Vite will now prompt you to target a framework and a variant.');
105
+ console.log('1. Please SELECT "Vanilla" and "JavaScript".');
106
+ console.log('2. DO NOT let it install dependencies or run immediately!');
107
+ console.log('---------------------------------------------------------\n');
108
+
109
+ try {
110
+ execSync(`${pkgManager} create vite ${libName} --template vanilla`, {
111
+ cwd: workspacePath,
112
+ stdio: 'inherit',
113
+ });
114
+ } catch (error) {
115
+ console.log('❌ Vite scaffolding failed or was aborted.');
116
+ process.exit(1);
117
+ }
118
+
119
+ // 3. Clean up Vite Boilerplate & Generate Library Sources
120
+ console.log('\n[2/5] Polishing library structure and writing source files...');
121
+ fs.rmSync(path.join(libPath, 'src'), { recursive: true, force: true });
122
+ fs.mkdirSync(path.join(libPath, 'src/modifiers'), { recursive: true });
123
+
124
+ // Dynamically fetch the absolute latest Vite and Vitest versions from registry
125
+ let viteVersion = '5.0.0';
126
+ let vitestVersion = '1.0.0';
127
+ try {
128
+ viteVersion = execSync('npm info vite version', { encoding: 'utf8' }).trim();
129
+ vitestVersion = execSync('npm info vitest version', { encoding: 'utf8' }).trim();
130
+ } catch (e) {
131
+ // Graceful fallback if no network
132
+ }
133
+
134
+ // Write source files
135
+ fs.writeFileSync(
136
+ path.join(libPath, 'src/index.js'),
137
+ `export function pluck(collection, field) {\n return collection.map(item => item[field]);\n}`
138
+ );
139
+ fs.writeFileSync(
140
+ path.join(libPath, 'src/modifiers/increaseAll.js'),
141
+ `export function increaseAllOf(collection, field) {\n return collection.map(item => ({\n ...item,\n [field]: item[field] + 1\n }));\n}`
142
+ );
143
+ fs.writeFileSync(
144
+ path.join(libPath, 'src/modifiers/lowerCaseAll.js'),
145
+ `export function lowerCaseAllOf(collection, field) {\n return collection.map(item => ({\n ...item,\n [field]: String(item[field]).toLowerCase()\n }));\n}`
146
+ );
147
+ fs.writeFileSync(
148
+ path.join(libPath, 'src/modifiers/index.js'),
149
+ `import { increaseAllOf } from "./increaseAll.js";\nimport { lowerCaseAllOf } from "./lowerCaseAll.js";\n\nexport { increaseAllOf, lowerCaseAllOf };`
150
+ );
151
+
152
+ // NEW: Add a comprehensive Vitest test file matching the example code
153
+ const testContent = `import { describe, it, expect } from "vitest";
154
+ import { pluck } from "./index.js";
155
+ import { increaseAllOf, lowerCaseAllOf } from "./modifiers/index.js";
156
+
157
+ describe("Library Core & Modifiers Stresstest", () => {
158
+ const mockUsers = [
159
+ { name: 'Alice', age: 20 },
160
+ { name: 'Bob', age: 30 }
161
+ ];
120
162
 
121
- fs.writeFileSync(path.join(libPath, 'src/index.js'), `export function pluck(collection, field) {\n return collection.map(item => item[field]);\n}`);
122
- fs.writeFileSync(path.join(libPath, 'src/modifiers/increaseAll.js'), `export function increaseAllOf(collection, field) {\n return collection.map(item => ({\n ...item,\n [field]: item[field] + 1\n }));\n}`);
123
- fs.writeFileSync(path.join(libPath, 'src/modifiers/lowerCaseAll.js'), `export function lowerCaseAllOf(collection, field) {\n return collection.map(item => ({\n ...item,\n [field]: String(item[field]).toLowerCase()\n }));\n}`);
124
- fs.writeFileSync(path.join(libPath, 'src/modifiers/index.js'), `import { increaseAllOf } from "./increaseAll.js";\nimport { lowerCaseAllOf } from "./lowerCaseAll.js";\n\nexport { increaseAllOf, lowerCaseAllOf };`);
125
-
126
- // Build custom package.json
127
- const libPackageJson = {
128
- name: packageName,
129
- version: '0.0.0',
130
- type: 'module',
131
- main: './dist/index.cjs',
132
- module: './dist/index.js',
133
- exports: {
134
- '.': { import: './dist/index.js', require: './dist/index.cjs' },
135
- './modifiers': { import: './dist/modifiers.js', require: './dist/modifiers.cjs' },
136
- },
137
- files: ['dist'],
138
- scripts: {
139
- dev: 'vite',
140
- build: 'vite build',
141
- watch: 'vite build --watch',
142
- },
143
- devDependencies: {
144
- vite: `^${viteVersion}`,
145
- },
146
- };
147
-
148
- fs.writeFileSync(path.join(libPath, 'package.json'), JSON.stringify(libPackageJson, null, 2));
149
-
150
- // Build custom vite.config.js
151
- const viteConfigContent = `import { defineConfig } from "vite";
163
+ it("should correctly pluck fields from a collection", () => {
164
+ const names = pluck(mockUsers, 'name');
165
+ expect(names).toEqual(['Alice', 'Bob']);
166
+ });
167
+
168
+ it("should correctly increase numeric fields by 1", () => {
169
+ const updated = increaseAllOf(mockUsers, 'age');
170
+ expect(updated[0].age).toBe(21);
171
+ expect(updated[1].age).toBe(31);
172
+ // Ensure original object reference wasn't mutated directly
173
+ expect(mockUsers[0].age).toBe(20);
174
+ });
175
+
176
+ it("should correctly lowercase string fields", () => {
177
+ const updated = lowerCaseAllOf(mockUsers, 'name');
178
+ expect(updated).toEqual([
179
+ { name: 'alice', age: 20 },
180
+ { name: 'bob', age: 30 }
181
+ ]);
182
+ });
183
+ });`;
184
+
185
+ fs.writeFileSync(path.join(libPath, 'src/index.test.js'), testContent);
186
+
187
+ // Build custom package.json with added test scripts and vitest dependency
188
+ const libPackageJson = {
189
+ name: packageName,
190
+ version: '0.0.0',
191
+ type: 'module',
192
+ main: './dist/index.cjs',
193
+ module: './dist/index.js',
194
+ exports: {
195
+ '.': { import: './dist/index.js', require: './dist/index.cjs' },
196
+ './modifiers': { import: './dist/modifiers.js', require: './dist/modifiers.cjs' },
197
+ },
198
+ files: ['dist'],
199
+ scripts: {
200
+ dev: 'vite',
201
+ build: 'vite build',
202
+ watch: 'vite build --watch',
203
+ test: 'vitest',
204
+ 'test:run': 'vitest run',
205
+ },
206
+ devDependencies: {
207
+ vite: `^${viteVersion}`,
208
+ vitest: `^${vitestVersion}`,
209
+ },
210
+ };
211
+
212
+ fs.writeFileSync(path.join(libPath, 'package.json'), JSON.stringify(libPackageJson, null, 2));
213
+
214
+ // Build custom vite.config.js
215
+ const viteConfigContent = `import { defineConfig } from "vite";
152
216
  import { resolve, dirname } from "path";
153
217
  import { fileURLToPath } from "url";
154
218
 
@@ -170,48 +234,50 @@ export default defineConfig({
170
234
  }
171
235
  }
172
236
  });`;
173
- fs.writeFileSync(path.join(libPath, 'vite.config.js'), viteConfigContent);
174
-
175
- // 4. Installing and Linking Dependencies
176
- console.log(`\n[3/5] Installing library dependencies via ${pkgManager}...`);
177
- execSync(`${pkgManager} install`, { cwd: libPath, stdio: 'inherit' });
178
-
179
- console.log('\n[4/5] Linking library globally and attaching to the test application...');
180
- if (pkgManager === 'npm') {
181
- execSync('npm link', { cwd: libPath, stdio: 'ignore' });
182
- execSync('npm init -y', { cwd: appPath, stdio: 'ignore' });
183
- execSync(`npm link ${packageName}`, { cwd: appPath, stdio: 'ignore' });
184
- } else if (pkgManager === 'yarn') {
185
- execSync('yarn link --global', { cwd: libPath, stdio: 'ignore' });
186
- execSync('yarn init -y', { cwd: appPath, stdio: 'ignore' });
187
- execSync(`yarn link ${packageName}`, { cwd: appPath, stdio: 'ignore' });
188
- } else {
189
- execSync('pnpm link --global', { cwd: libPath, stdio: 'ignore' });
190
- execSync('pnpm init', { cwd: appPath, stdio: 'ignore' });
191
- execSync(`pnpm link --global ${packageName}`, { cwd: appPath, stdio: 'ignore' });
192
- }
237
+ fs.writeFileSync(path.join(libPath, 'vite.config.js'), viteConfigContent);
238
+
239
+ // 4. Installing and Linking Dependencies
240
+ console.log(`\n[3/5] Installing library dependencies via ${pkgManager}...`);
241
+ execSync(`${pkgManager} install`, { cwd: libPath, stdio: 'inherit' });
242
+
243
+ console.log('\n[4/5] Linking library globally and attaching to the test application...');
244
+ if (pkgManager === 'npm') {
245
+ execSync('npm link', { cwd: libPath, stdio: 'ignore' });
246
+ execSync('npm init -y', { cwd: appPath, stdio: 'ignore' });
247
+ execSync(`npm link ${packageName}`, { cwd: appPath, stdio: 'ignore' });
248
+ } else if (pkgManager === 'yarn') {
249
+ execSync('yarn link --global', { cwd: libPath, stdio: 'ignore' });
250
+ execSync('yarn init -y', { cwd: appPath, stdio: 'ignore' });
251
+ execSync(`` + 'yarn link ' + packageName, { cwd: appPath, stdio: 'ignore' });
252
+ } else {
253
+ execSync('pnpm link --global', { cwd: libPath, stdio: 'ignore' });
254
+ execSync('pnpm init', { cwd: appPath, stdio: 'ignore' });
255
+ execSync(`pnpm link --global ${packageName}`, { cwd: appPath, stdio: 'ignore' });
256
+ }
257
+
258
+ // 5. Initial Library Build
259
+ console.log('\n[5/5] Running initial library build...');
260
+ execSync(`${pkgManager} run build`, { cwd: libPath, stdio: 'inherit' });
261
+
262
+ // Define package executor instructions
263
+ let execCmd = 'pnpm dlx';
264
+ if (pkgManager === 'npm') execCmd = 'npx';
265
+ if (pkgManager === 'yarn') execCmd = 'yarn dlx';
193
266
 
194
- // 5. Initial Library Build
195
- console.log('\n[5/5] Running initial library build...');
196
- execSync(`${pkgManager} run build`, { cwd: libPath, stdio: 'inherit' });
197
-
198
- // Define package executor instructions
199
- let execCmd = 'pnpm dlx';
200
- if (pkgManager === 'npm') execCmd = 'npx';
201
- if (pkgManager === 'yarn') execCmd = 'yarn dlx';
202
-
203
- console.log('\n=========================================================');
204
- console.log(' 🎉 Setup successfully completed!');
205
- console.log('=========================================================');
206
- console.log(' To get started, open two terminals:\n');
207
- console.log(' Terminal 1 (Library Watcher):');
208
- console.log(` cd ${workspaceName}/${libName} && ${pkgManager} run watch\n`);
209
- console.log(' Terminal 2 (Test App Server):');
210
- console.log(` cd ${workspaceName}/app && ${execCmd} vite (--open)`);
211
- console.log('=========================================================\n');
267
+ console.log('\n=========================================================');
268
+ console.log(' 🎉 Setup successfully completed!');
269
+ console.log('=========================================================');
270
+ console.log(' To get started, open your terminals:\n');
271
+ console.log(' Terminal 1 (Library Watcher):');
272
+ console.log(` cd ${workspaceName}/${libName} && ${pkgManager} run watch\n`);
273
+ console.log(' Terminal 2 (Test App Server):');
274
+ console.log(` cd ${workspaceName}/app && ${execCmd} vite (--open)\n`);
275
+ console.log(' Terminal 3 (Interactive Test Suite):');
276
+ console.log(` cd ${workspaceName}/${libName} && ${pkgManager} run test`);
277
+ console.log('=========================================================\n');
212
278
  }
213
279
 
214
- main().catch((err) => {
215
- console.error('An unexpected error occurred:', err);
216
- process.exit(1);
280
+ main().catch(err => {
281
+ console.error('An unexpected error occurred:', err);
282
+ process.exit(1);
217
283
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-lib-workspace",
3
- "version": "1.0.0",
3
+ "version": "1.1.1a",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "create-lib-workspace": "./index.js"
@@ -9,7 +9,6 @@
9
9
  "index.js"
10
10
  ],
11
11
  "license": "MIT",
12
-
13
12
  "keywords": [
14
13
  "cli",
15
14
  "vite",
@@ -17,6 +16,13 @@
17
16
  "workspace",
18
17
  "scaffold"
19
18
  ],
20
- "author": "BarbWire-1 aka Barbara Kälin"
21
-
19
+ "author": "BarbWire-1 aka Barbara Kälin",
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "git+https://github.com/BarbWire-1/create-lib-workspace.git"
23
+ },
24
+ "homepage": "https://github.com/BarbWire-1/create-lib-workspace",
25
+ "bugs": {
26
+ "url": "https://github.com/BarbWire-1/create-lib-workspace/issues"
27
+ }
22
28
  }