@iselect/select 1.0.0 → 1.0.1

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/bin/select.js CHANGED
@@ -33,7 +33,7 @@ program
33
33
  .option('-t, --template <template>', 'Project template (react, vue, vanilla)', 'react')
34
34
  .action(init);
35
35
 
36
- // select - Interactive platform selection
36
+ // slct select - Interactive platform selection
37
37
  program
38
38
  .command('select')
39
39
  .alias('s')
@@ -47,6 +47,8 @@ program
47
47
  .option('--tauri', 'Use Tauri for desktop (default)')
48
48
  .option('--electron', 'Use Electron for desktop')
49
49
  .option('--release', 'Build for production release')
50
+ .option('--static', 'Copy files directly without bundling (vanilla HTML/CSS/JS)')
51
+ .option('--inline', 'Inline CSS and JS into a single HTML file')
50
52
  .action(build);
51
53
 
52
54
  // slct deploy - Deploy to Select marketplace
@@ -65,3 +67,4 @@ program
65
67
 
66
68
  // Parse arguments
67
69
  program.parse();
70
+
@@ -55,25 +55,268 @@ async function build(target, options) {
55
55
  }
56
56
  }
57
57
 
58
+ // ==================== PROJECT TYPE DETECTION ====================
59
+ async function detectProjectType(projectPath) {
60
+ const hasPackageJson = await fs.pathExists(path.join(projectPath, 'package.json'));
61
+ const hasViteConfig = await fs.pathExists(path.join(projectPath, 'vite.config.js')) ||
62
+ await fs.pathExists(path.join(projectPath, 'vite.config.ts'));
63
+ const hasIndexHtml = await fs.pathExists(path.join(projectPath, 'index.html'));
64
+ const hasSrcMain = await fs.pathExists(path.join(projectPath, 'src', 'main.js')) ||
65
+ await fs.pathExists(path.join(projectPath, 'src', 'main.jsx')) ||
66
+ await fs.pathExists(path.join(projectPath, 'src', 'main.ts')) ||
67
+ await fs.pathExists(path.join(projectPath, 'src', 'main.tsx'));
68
+
69
+ // Check if package.json has a build script
70
+ let hasBuildScript = false;
71
+ if (hasPackageJson) {
72
+ try {
73
+ const pkg = await fs.readJson(path.join(projectPath, 'package.json'));
74
+ hasBuildScript = !!(pkg.scripts && pkg.scripts.build);
75
+ } catch { }
76
+ }
77
+
78
+ // Static site: has index.html but no package.json or no build script
79
+ if (hasIndexHtml && (!hasPackageJson || !hasBuildScript)) {
80
+ return 'static';
81
+ }
82
+
83
+ // Vite project
84
+ if (hasViteConfig) {
85
+ return 'vite';
86
+ }
87
+
88
+ // Has package.json with build script
89
+ if (hasPackageJson && hasBuildScript) {
90
+ return 'bundled';
91
+ }
92
+
93
+ // Default to static if just has HTML
94
+ if (hasIndexHtml) {
95
+ return 'static';
96
+ }
97
+
98
+ return 'unknown';
99
+ }
100
+
101
+ // ==================== INLINE BUILD ====================
102
+ async function buildInline(projectPath, outputDir) {
103
+ const spinner = ora('Building inline HTML...').start();
104
+
105
+ // Ensure output dir exists
106
+ await fs.ensureDir(outputDir);
107
+
108
+ // Read index.html
109
+ const indexPath = path.join(projectPath, 'index.html');
110
+ if (!await fs.pathExists(indexPath)) {
111
+ spinner.fail('No index.html found');
112
+ throw new Error('index.html not found in project root');
113
+ }
114
+
115
+ let html = await fs.readFile(indexPath, 'utf8');
116
+
117
+ // Inline CSS files
118
+ const cssLinkRegex = /<link[^>]+rel=["']stylesheet["'][^>]+href=["']([^"']+)["'][^>]*>/gi;
119
+ const cssLinks = [];
120
+ let match;
121
+ while ((match = cssLinkRegex.exec(html)) !== null) {
122
+ cssLinks.push({ full: match[0], href: match[1] });
123
+ }
124
+
125
+ for (const link of cssLinks) {
126
+ const cssPath = path.join(projectPath, link.href);
127
+ if (await fs.pathExists(cssPath)) {
128
+ const cssContent = await fs.readFile(cssPath, 'utf8');
129
+ html = html.replace(link.full, `<style>\n${cssContent}\n</style>`);
130
+ }
131
+ }
132
+
133
+ // Inline JS files
134
+ const jsScriptRegex = /<script[^>]+src=["']([^"']+)["'][^>]*><\/script>/gi;
135
+ const jsScripts = [];
136
+ while ((match = jsScriptRegex.exec(html)) !== null) {
137
+ jsScripts.push({ full: match[0], src: match[1] });
138
+ }
139
+
140
+ for (const script of jsScripts) {
141
+ const jsPath = path.join(projectPath, script.src);
142
+ if (await fs.pathExists(jsPath)) {
143
+ const jsContent = await fs.readFile(jsPath, 'utf8');
144
+ html = html.replace(script.full, `<script>\n${jsContent}\n</script>`);
145
+ }
146
+ }
147
+
148
+ // Write output
149
+ await fs.writeFile(path.join(outputDir, 'index.html'), html);
150
+
151
+ spinner.succeed(`Created single-file HTML (${cssLinks.length} CSS, ${jsScripts.length} JS inlined)`);
152
+
153
+ return { cssInlined: cssLinks.length, jsInlined: jsScripts.length };
154
+ }
155
+
156
+ // ==================== STATIC FILE COPY ====================
157
+ async function copyStaticFiles(projectPath, outputDir) {
158
+ const spinner = ora('Copying static files...').start();
159
+
160
+ // Ensure output dir exists and is clean
161
+ await fs.emptyDir(outputDir);
162
+
163
+ // Files and folders to copy
164
+ const filesToCopy = ['index.html', 'style.css', 'styles.css', 'main.css', 'app.css'];
165
+ const foldersToCheck = ['assets', 'css', 'js', 'images', 'fonts', 'src'];
166
+
167
+ let copiedFiles = 0;
168
+ let cssFound = false;
169
+
170
+ // Copy individual files
171
+ for (const file of filesToCopy) {
172
+ const srcPath = path.join(projectPath, file);
173
+ if (await fs.pathExists(srcPath)) {
174
+ await fs.copy(srcPath, path.join(outputDir, file));
175
+ copiedFiles++;
176
+ if (file.endsWith('.css')) cssFound = true;
177
+ }
178
+ }
179
+
180
+ // Copy .js files from root
181
+ const rootFiles = await fs.readdir(projectPath);
182
+ for (const file of rootFiles) {
183
+ if (file.endsWith('.js') && !file.includes('.config.')) {
184
+ await fs.copy(path.join(projectPath, file), path.join(outputDir, file));
185
+ copiedFiles++;
186
+ }
187
+ if (file.endsWith('.css')) {
188
+ await fs.copy(path.join(projectPath, file), path.join(outputDir, file));
189
+ copiedFiles++;
190
+ cssFound = true;
191
+ }
192
+ }
193
+
194
+ // Copy folders
195
+ for (const folder of foldersToCheck) {
196
+ const srcPath = path.join(projectPath, folder);
197
+ if (await fs.pathExists(srcPath)) {
198
+ await fs.copy(srcPath, path.join(outputDir, folder));
199
+ copiedFiles++;
200
+
201
+ // Check for CSS in folders
202
+ const folderFiles = await fs.readdir(srcPath);
203
+ if (folderFiles.some(f => f.endsWith('.css'))) {
204
+ cssFound = true;
205
+ }
206
+ }
207
+ }
208
+
209
+ spinner.succeed(`Copied ${copiedFiles} files/folders to ${outputDir}`);
210
+
211
+ // Warning if no CSS found
212
+ if (!cssFound) {
213
+ console.log(chalk.yellow('\n⚠️ Warning: No CSS files found in build output'));
214
+ console.log(chalk.gray(' Ensure your HTML links to the CSS file correctly\n'));
215
+ }
216
+
217
+ return { copiedFiles, cssFound };
218
+ }
219
+
58
220
  // ==================== WEB BUILD ====================
59
221
  async function buildWeb(config, options) {
60
222
  console.log(chalk.blue('\n📦 Building for Web...\n'));
61
223
 
224
+ const projectPath = process.cwd();
225
+ const outputDir = path.resolve(projectPath, config.build?.outDir || 'dist');
226
+
227
+ // Check for --static flag
228
+ if (options.static) {
229
+ console.log(chalk.gray(' Mode: Static (--static flag)'));
230
+ await copyStaticFiles(projectPath, outputDir);
231
+ console.log(chalk.green('\n✅ Static web build complete!'));
232
+ console.log(chalk.gray(` Output: ${outputDir}/\n`));
233
+ return;
234
+ }
235
+
236
+ // Check for --inline flag
237
+ if (options.inline) {
238
+ console.log(chalk.gray(' Mode: Inline (--inline flag)'));
239
+ await buildInline(projectPath, outputDir);
240
+ console.log(chalk.green('\n✅ Inline web build complete!'));
241
+ console.log(chalk.gray(` Output: ${outputDir}/index.html (single file)\n`));
242
+ return;
243
+ }
244
+
245
+ // Auto-detect project type
246
+ const projectType = await detectProjectType(projectPath);
247
+ console.log(chalk.gray(` Detected: ${projectType} project`));
248
+
249
+ if (projectType === 'static') {
250
+ console.log(chalk.gray(' Mode: Static site (copying files directly)\n'));
251
+ await copyStaticFiles(projectPath, outputDir);
252
+ console.log(chalk.green('\n✅ Static web build complete!'));
253
+ console.log(chalk.gray(` Output: ${outputDir}/\n`));
254
+ return;
255
+ }
256
+
257
+ if (projectType === 'unknown') {
258
+ console.log(chalk.yellow('\n⚠️ Could not detect project type'));
259
+ console.log(chalk.gray(' No index.html or package.json found'));
260
+ console.log(chalk.gray(' Try: slct build web --static\n'));
261
+ process.exit(1);
262
+ }
263
+
264
+ // Run build command for bundled projects
62
265
  const spinner = ora('Running build command...').start();
63
266
 
64
267
  try {
65
- execSync(config.build?.command || 'npm run build', {
268
+ const buildCommand = config.build?.command || 'npm run build';
269
+ execSync(buildCommand, {
66
270
  stdio: 'inherit',
67
- cwd: process.cwd()
271
+ cwd: projectPath
68
272
  });
69
273
  spinner.succeed('Web build complete!');
70
- console.log(chalk.gray(` Output: ${config.build?.outDir || 'dist'}/\n`));
274
+
275
+ // Validate output
276
+ await validateBuildOutput(outputDir);
277
+
278
+ console.log(chalk.gray(` Output: ${outputDir}/\n`));
71
279
  } catch (error) {
72
280
  spinner.fail('Web build failed');
73
281
  throw error;
74
282
  }
75
283
  }
76
284
 
285
+ // ==================== BUILD VALIDATION ====================
286
+ async function validateBuildOutput(outputDir) {
287
+ if (!await fs.pathExists(outputDir)) {
288
+ console.log(chalk.yellow('\n⚠️ Warning: Output directory not found'));
289
+ return;
290
+ }
291
+
292
+ const files = await fs.readdir(outputDir);
293
+
294
+ // Check for index.html
295
+ if (!files.includes('index.html')) {
296
+ console.log(chalk.yellow('\n⚠️ Warning: No index.html found in build output'));
297
+ }
298
+
299
+ // Check for CSS
300
+ const hasCss = files.some(f => f.endsWith('.css'));
301
+ const hasAssetsFolder = files.includes('assets');
302
+
303
+ if (!hasCss && hasAssetsFolder) {
304
+ const assetsPath = path.join(outputDir, 'assets');
305
+ if (await fs.pathExists(assetsPath)) {
306
+ const assetFiles = await fs.readdir(assetsPath);
307
+ if (assetFiles.some(f => f.endsWith('.css'))) {
308
+ return; // CSS is in assets folder, all good
309
+ }
310
+ }
311
+ }
312
+
313
+ if (!hasCss) {
314
+ console.log(chalk.yellow('\n⚠️ Warning: No CSS files found in build output'));
315
+ console.log(chalk.gray(' If using vanilla CSS, ensure it\'s imported in your JS entry point'));
316
+ console.log(chalk.gray(' Or use: slct build web --static\n'));
317
+ }
318
+ }
319
+
77
320
  // ==================== DESKTOP BUILD ====================
78
321
  async function buildDesktop(config, options) {
79
322
  const framework = options.electron ? 'electron' : (config.desktop?.framework || 'tauri');
@@ -39,8 +39,8 @@ async function deploy(options) {
39
39
  type: 'list',
40
40
  name: 'category',
41
41
  message: 'Category:',
42
- choices: ['Productivity', 'Finance', 'Developer Tools', 'Education', 'Entertainment', 'Utilities', 'Other'],
43
- default: config.category || 'Productivity'
42
+ choices: ['productivity', 'finance', 'developer-tools', 'education', 'entertainment', 'utilities', 'games', 'ai-tools', 'experiments'],
43
+ default: config.category || 'productivity'
44
44
  },
45
45
  {
46
46
  type: 'password',
@@ -66,7 +66,7 @@ async function deploy(options) {
66
66
  ...config,
67
67
  name: answers.name,
68
68
  tagline: answers.tagline,
69
- category: answers.category.toLowerCase().replace(' ', '-'),
69
+ category: answers.category,
70
70
  platforms: []
71
71
  };
72
72
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iselect/select",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "Build and deploy apps for web, desktop, and mobile from a single codebase",
5
5
  "main": "lib/index.js",
6
6
  "bin": {