create-ripple 0.1.3 → 0.2.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.
package/package.json
CHANGED
package/src/commands/create.js
CHANGED
|
@@ -8,7 +8,8 @@ import {
|
|
|
8
8
|
promptTemplate,
|
|
9
9
|
promptOverwrite,
|
|
10
10
|
promptPackageManager,
|
|
11
|
-
promptGitInit
|
|
11
|
+
promptGitInit,
|
|
12
|
+
promptStylingFramework
|
|
12
13
|
} from '../lib/prompts.js';
|
|
13
14
|
import { createProject } from '../lib/project-creator.js';
|
|
14
15
|
|
|
@@ -71,6 +72,11 @@ export async function createCommand(projectName, options) {
|
|
|
71
72
|
gitInit = false;
|
|
72
73
|
}
|
|
73
74
|
|
|
75
|
+
let stylingFramework = 'vanilla';
|
|
76
|
+
if (!options.yes) {
|
|
77
|
+
stylingFramework = await promptStylingFramework();
|
|
78
|
+
}
|
|
79
|
+
|
|
74
80
|
// Step 6: Create the project
|
|
75
81
|
console.log();
|
|
76
82
|
console.log(`Creating Ripple app in ${green(projectPath)}...`);
|
|
@@ -83,7 +89,8 @@ export async function createCommand(projectName, options) {
|
|
|
83
89
|
template,
|
|
84
90
|
packageManager,
|
|
85
91
|
typescript: true,
|
|
86
|
-
gitInit
|
|
92
|
+
gitInit,
|
|
93
|
+
stylingFramework
|
|
87
94
|
});
|
|
88
95
|
|
|
89
96
|
showNextSteps(projectName, packageManager);
|
|
@@ -13,16 +13,16 @@ import { downloadTemplate, getLocalTemplatePath, isLocalDevelopment } from './te
|
|
|
13
13
|
* @param {string} options.projectPath - Absolute path where project will be created
|
|
14
14
|
* @param {string} options.template - Template to use
|
|
15
15
|
* @param {string} options.packageManager - Package manager to use
|
|
16
|
-
* @param {boolean} options.typescript - Whether to use TypeScript
|
|
17
16
|
* @param {boolean} options.gitInit - Whether to initialize Git
|
|
17
|
+
* @param {string} options.stylingFramework - Styling framework to use
|
|
18
18
|
*/
|
|
19
19
|
export async function createProject({
|
|
20
20
|
projectName,
|
|
21
21
|
projectPath,
|
|
22
22
|
template,
|
|
23
23
|
packageManager = 'npm',
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
gitInit = true,
|
|
25
|
+
stylingFramework = 'vanilla'
|
|
26
26
|
}) {
|
|
27
27
|
console.log(dim(`Creating project: ${projectName}`));
|
|
28
28
|
console.log(dim(`Template: ${template}`));
|
|
@@ -95,7 +95,7 @@ export async function createProject({
|
|
|
95
95
|
// Step 4: Update package.json
|
|
96
96
|
const spinner4 = ora('Configuring package.json...').start();
|
|
97
97
|
try {
|
|
98
|
-
updatePackageJson(projectPath, projectName, packageManager,
|
|
98
|
+
updatePackageJson(projectPath, projectName, packageManager, stylingFramework);
|
|
99
99
|
spinner4.succeed('Package.json configured');
|
|
100
100
|
} catch (error) {
|
|
101
101
|
spinner4.fail('Failed to configure package.json');
|
|
@@ -105,17 +105,29 @@ export async function createProject({
|
|
|
105
105
|
throw error;
|
|
106
106
|
}
|
|
107
107
|
|
|
108
|
-
// Step 5:
|
|
108
|
+
// Step 5: Configure styling
|
|
109
|
+
const spinner5 = ora('Configuring styling framework...').start();
|
|
110
|
+
try {
|
|
111
|
+
configureStyling(projectPath, stylingFramework);
|
|
112
|
+
spinner5.succeed('Styling framework configured');
|
|
113
|
+
} catch (error) {
|
|
114
|
+
spinner5.fail('Failed to configure styling framework');
|
|
115
|
+
if (isTemporary) {
|
|
116
|
+
rmSync(templatePath, { recursive: true, force: true });
|
|
117
|
+
}
|
|
118
|
+
throw error;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
// Step 6: Initialize Git (if requested)
|
|
109
124
|
if (gitInit) {
|
|
110
|
-
const
|
|
125
|
+
const spinner6 = ora('Initializing Git repository...').start();
|
|
111
126
|
try {
|
|
112
127
|
execSync('git init', { cwd: projectPath, stdio: 'ignore' });
|
|
113
|
-
|
|
114
|
-
// execSync('git add .', { cwd: projectPath, stdio: 'ignore' });
|
|
115
|
-
// execSync('git commit -m "Initial commit"', { cwd: projectPath, stdio: 'ignore' });
|
|
116
|
-
spinner5.succeed('Git repository initialized');
|
|
128
|
+
spinner6.succeed('Git repository initialized');
|
|
117
129
|
} catch (error) {
|
|
118
|
-
|
|
130
|
+
spinner6.warn('Git initialization failed (optional)');
|
|
119
131
|
}
|
|
120
132
|
}
|
|
121
133
|
|
|
@@ -137,9 +149,9 @@ export async function createProject({
|
|
|
137
149
|
* @param {string} projectPath - Path to the project
|
|
138
150
|
* @param {string} projectName - Name of the project
|
|
139
151
|
* @param {string} packageManager - Package manager being used
|
|
140
|
-
* @param {
|
|
152
|
+
* @param {string} stylingFramework - Styling framework being used
|
|
141
153
|
*/
|
|
142
|
-
function updatePackageJson(projectPath, projectName, packageManager,
|
|
154
|
+
function updatePackageJson(projectPath, projectName, packageManager, stylingFramework) {
|
|
143
155
|
const packageJsonPath = join(projectPath, 'package.json');
|
|
144
156
|
|
|
145
157
|
if (!existsSync(packageJsonPath)) {
|
|
@@ -164,6 +176,20 @@ function updatePackageJson(projectPath, projectName, packageManager, typescript)
|
|
|
164
176
|
packageJson.packageManager = getPackageManagerVersion(packageManager);
|
|
165
177
|
}
|
|
166
178
|
|
|
179
|
+
// Add styling dependencies
|
|
180
|
+
if (stylingFramework === 'tailwind') {
|
|
181
|
+
packageJson.devDependencies = {
|
|
182
|
+
...packageJson.devDependencies,
|
|
183
|
+
'tailwindcss': '^4.1.12',
|
|
184
|
+
'@tailwindcss/vite': '^4.1.12'
|
|
185
|
+
};
|
|
186
|
+
} else if (stylingFramework === 'bootstrap') {
|
|
187
|
+
packageJson.dependencies = {
|
|
188
|
+
...packageJson.dependencies,
|
|
189
|
+
'bootstrap': '^5.3.0'
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
|
|
167
193
|
// Ensure we're using the latest versions
|
|
168
194
|
updateDependencyVersions(packageJson);
|
|
169
195
|
|
|
@@ -173,6 +199,52 @@ function updatePackageJson(projectPath, projectName, packageManager, typescript)
|
|
|
173
199
|
writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2) + '\n');
|
|
174
200
|
}
|
|
175
201
|
|
|
202
|
+
function configureStyling(projectPath, stylingFramework) {
|
|
203
|
+
if (stylingFramework === 'tailwind') {
|
|
204
|
+
const tailwindConfig = `import type { Config } from 'tailwindcss';
|
|
205
|
+
export default {
|
|
206
|
+
content: [
|
|
207
|
+
"./index.html",
|
|
208
|
+
"./src/**/*.{ts,ripple}",
|
|
209
|
+
],
|
|
210
|
+
theme: {
|
|
211
|
+
extend: {},
|
|
212
|
+
},
|
|
213
|
+
plugins: []
|
|
214
|
+
} satisfies Config
|
|
215
|
+
`;
|
|
216
|
+
writeFileSync(join(projectPath, 'tailwind.config.ts'), tailwindConfig);
|
|
217
|
+
const mainCss = `@import "tailwindcss";
|
|
218
|
+
@config "./tailwind.config.ts";`;
|
|
219
|
+
writeFileSync(join(projectPath, 'src', 'index.css'), mainCss);
|
|
220
|
+
|
|
221
|
+
const mainTs = readFileSync(join(projectPath, 'src', 'index.ts'), 'utf-8');
|
|
222
|
+
const newMainTs = "import './index.css';\n" + mainTs;
|
|
223
|
+
writeFileSync(join(projectPath, 'src', 'index.ts'), newMainTs);
|
|
224
|
+
|
|
225
|
+
if (existsSync(join(projectPath, 'vite.config.js'))) {
|
|
226
|
+
rmSync(join(projectPath, 'vite.config.js'));
|
|
227
|
+
}
|
|
228
|
+
const viteConfig = `import { defineConfig } from 'vite';
|
|
229
|
+
import { ripple } from 'vite-plugin-ripple';
|
|
230
|
+
import tailwindcss from '@tailwindcss/vite';
|
|
231
|
+
|
|
232
|
+
export default defineConfig({
|
|
233
|
+
plugins: [ripple(), tailwindcss()],
|
|
234
|
+
server: {
|
|
235
|
+
port: 3000
|
|
236
|
+
}
|
|
237
|
+
});
|
|
238
|
+
`;
|
|
239
|
+
writeFileSync(join(projectPath, 'vite.config.js'), viteConfig);
|
|
240
|
+
|
|
241
|
+
} else if (stylingFramework === 'bootstrap') {
|
|
242
|
+
const mainTs = readFileSync(join(projectPath, 'src', 'index.ts'), 'utf-8');
|
|
243
|
+
const newMainTs = "import 'bootstrap/dist/css/bootstrap.min.css';\n" + mainTs;
|
|
244
|
+
writeFileSync(join(projectPath, 'src', 'index.ts'), newMainTs);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
176
248
|
/**
|
|
177
249
|
* Update dependency versions to latest
|
|
178
250
|
* @param {object} packageJson - Package.json object
|
package/src/lib/prompts.js
CHANGED
|
@@ -134,3 +134,31 @@ export async function promptGitInit() {
|
|
|
134
134
|
|
|
135
135
|
return response.gitInit;
|
|
136
136
|
}
|
|
137
|
+
|
|
138
|
+
export async function promptStylingFramework() {
|
|
139
|
+
const response = await prompts({
|
|
140
|
+
type: 'select',
|
|
141
|
+
name: 'stylingFramework',
|
|
142
|
+
message: 'Which styling framework would you like to integrate with Ripple?',
|
|
143
|
+
choices: [{
|
|
144
|
+
title: 'Vanilla CSS',
|
|
145
|
+
value: 'vanilla',
|
|
146
|
+
description: 'Use Vanilla CSS for styling your components'
|
|
147
|
+
}, {
|
|
148
|
+
title: 'Bootstrap',
|
|
149
|
+
value: 'bootstrap',
|
|
150
|
+
description: 'Use Bootstrap classes to style your components'
|
|
151
|
+
}, {
|
|
152
|
+
title: 'TailwindCSS',
|
|
153
|
+
value: 'tailwind',
|
|
154
|
+
description: 'Use TailwindCSS to style your components'
|
|
155
|
+
}]
|
|
156
|
+
})
|
|
157
|
+
|
|
158
|
+
if (response.stylingFramework === undefined) {
|
|
159
|
+
console.log(red('✖ Operation cancelled'));
|
|
160
|
+
process.exit(1);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return response.stylingFramework;
|
|
164
|
+
}
|
|
@@ -2,7 +2,7 @@ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
|
|
|
2
2
|
import { existsSync, mkdirSync, rmSync, readFileSync, writeFileSync } from 'node:fs';
|
|
3
3
|
import { join } from 'node:path';
|
|
4
4
|
import { tmpdir } from 'node:os';
|
|
5
|
-
import { createProject } from '../../src/lib/project-creator.js';
|
|
5
|
+
import { createProject, updatePackageJson, configureStyling } from '../../src/lib/project-creator.js';
|
|
6
6
|
import { getLocalTemplatePath, isLocalDevelopment, validateTemplate } from '../../src/lib/templates.js';
|
|
7
7
|
|
|
8
8
|
// Mock ora for cleaner test output
|
|
@@ -227,4 +227,45 @@ describe('createProject integration tests', () => {
|
|
|
227
227
|
expect(existsSync(join(projectPath, 'package.json'))).toBe(true);
|
|
228
228
|
expect(existsSync(join(projectPath, 'existing-file.txt'))).toBe(true);
|
|
229
229
|
});
|
|
230
|
+
it('should configure Tailwind CSS correctly', async () => {
|
|
231
|
+
writeFileSync(join(templatePath, 'src', 'index.ts'), 'console.log("Hello, World!");');
|
|
232
|
+
await createProject({
|
|
233
|
+
projectName: 'test-tailwind-project',
|
|
234
|
+
projectPath,
|
|
235
|
+
template: 'basic',
|
|
236
|
+
packageManager: 'npm',
|
|
237
|
+
typescript: true,
|
|
238
|
+
gitInit: false,
|
|
239
|
+
stylingFramework: 'tailwind'
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
const packageJson = JSON.parse(readFileSync(join(projectPath, 'package.json'), 'utf-8'));
|
|
243
|
+
expect(packageJson.devDependencies).toHaveProperty('tailwindcss');
|
|
244
|
+
expect(packageJson.devDependencies).toHaveProperty('@tailwindcss/vite');
|
|
245
|
+
|
|
246
|
+
expect(existsSync(join(projectPath, 'tailwind.config.ts'))).toBe(true);
|
|
247
|
+
expect(readFileSync(join(projectPath, 'src', 'index.ts'), 'utf-8')).toContain("import './index.css';\n");
|
|
248
|
+
expect(existsSync(join(projectPath, 'src', 'index.css'))).toBe(true);
|
|
249
|
+
expect(readFileSync(join(projectPath, 'src', 'index.css'), 'utf-8')).toContain('@import "tailwindcss"');
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
it('should configure Bootstrap correctly', async () => {
|
|
253
|
+
writeFileSync(join(templatePath, 'src', 'index.ts'), 'console.log("Hello, World!");');
|
|
254
|
+
|
|
255
|
+
await createProject({
|
|
256
|
+
projectName: 'test-bootstrap-project',
|
|
257
|
+
projectPath,
|
|
258
|
+
template: 'basic',
|
|
259
|
+
packageManager: 'npm',
|
|
260
|
+
typescript: true,
|
|
261
|
+
gitInit: false,
|
|
262
|
+
stylingFramework: 'bootstrap'
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
const packageJson = JSON.parse(readFileSync(join(projectPath, 'package.json'), 'utf-8'));
|
|
266
|
+
expect(packageJson.dependencies).toHaveProperty('bootstrap');
|
|
267
|
+
|
|
268
|
+
const mainTsContent = readFileSync(join(projectPath, 'src', 'index.ts'), 'utf-8');
|
|
269
|
+
expect(mainTsContent).toContain("import 'bootstrap/dist/css/bootstrap.min.css';");
|
|
270
|
+
});
|
|
230
271
|
});
|
|
@@ -28,7 +28,8 @@ import {
|
|
|
28
28
|
promptOverwrite,
|
|
29
29
|
promptPackageManager,
|
|
30
30
|
promptTypeScript,
|
|
31
|
-
promptGitInit
|
|
31
|
+
promptGitInit,
|
|
32
|
+
promptStylingFramework
|
|
32
33
|
} from '../../src/lib/prompts.js';
|
|
33
34
|
|
|
34
35
|
describe('Prompts', () => {
|
|
@@ -204,4 +205,36 @@ describe('Prompts', () => {
|
|
|
204
205
|
expect(mockExit).toHaveBeenCalledWith(1);
|
|
205
206
|
});
|
|
206
207
|
});
|
|
208
|
+
describe('promptStylingFramework', () => {
|
|
209
|
+
it('should return selected styling framework', async () => {
|
|
210
|
+
prompts.default.mockResolvedValue({ stylingFramework: 'tailwind' });
|
|
211
|
+
|
|
212
|
+
const result = await promptStylingFramework();
|
|
213
|
+
expect(result).toBe('tailwind');
|
|
214
|
+
expect(prompts.default).toHaveBeenCalledWith({
|
|
215
|
+
type: 'select',
|
|
216
|
+
name: 'stylingFramework',
|
|
217
|
+
message: 'Which styling framework would you like to integrate with Ripple?',
|
|
218
|
+
choices: [{
|
|
219
|
+
title: 'Vanilla CSS',
|
|
220
|
+
value: 'vanilla',
|
|
221
|
+
description: 'Use Vanilla CSS for styling your components'
|
|
222
|
+
}, {
|
|
223
|
+
title: 'Bootstrap',
|
|
224
|
+
value: 'bootstrap',
|
|
225
|
+
description: 'Use Bootstrap classes to style your components'
|
|
226
|
+
}, {
|
|
227
|
+
title: 'TailwindCSS',
|
|
228
|
+
value: 'tailwind',
|
|
229
|
+
description: 'Use TailwindCSS to style your components'
|
|
230
|
+
}]
|
|
231
|
+
});
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
it('should return undefined when user cancels', async () => {
|
|
235
|
+
prompts.default.mockResolvedValue({ stylingFramework: undefined });
|
|
236
|
+
const result = await promptStylingFramework();
|
|
237
|
+
expect(result).toBeUndefined();
|
|
238
|
+
});
|
|
239
|
+
});
|
|
207
240
|
});
|