@idealyst/cli 1.0.17 → 1.0.19
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/dist/index.js +145 -23
- package/dist/types/generators/utils.d.ts +5 -2
- package/dist/types/types.d.ts +2 -0
- package/package.json +1 -1
- package/templates/native/index.js +1 -1
- package/templates/native/metro.config.js +0 -5
- package/templates/web/src/App.tsx +12 -16
- package/templates/web/src/main.tsx +24 -10
- package/templates/web/vite.config.ts +1 -4
- package/templates/App.tsx +0 -16
- package/templates/web/.yarnrc.yml +0 -19
package/dist/index.js
CHANGED
|
@@ -7,6 +7,7 @@ import fs from 'fs-extra';
|
|
|
7
7
|
import { spawn } from 'child_process';
|
|
8
8
|
import ora from 'ora';
|
|
9
9
|
import validatePackageName from 'validate-npm-package-name';
|
|
10
|
+
import inquirer from 'inquirer';
|
|
10
11
|
|
|
11
12
|
function validateProjectName(name) {
|
|
12
13
|
const validation = validatePackageName(name);
|
|
@@ -123,20 +124,25 @@ function runCommand(command, args, options) {
|
|
|
123
124
|
});
|
|
124
125
|
});
|
|
125
126
|
}
|
|
126
|
-
function getTemplateData(projectName, description) {
|
|
127
|
+
function getTemplateData(projectName, description, appName) {
|
|
127
128
|
return {
|
|
128
129
|
projectName,
|
|
129
130
|
packageName: createPackageName(projectName),
|
|
130
131
|
version: '1.0.0',
|
|
131
|
-
description: description || `A new Idealyst project: ${projectName}
|
|
132
|
+
description: description || `A new Idealyst project: ${projectName}`,
|
|
133
|
+
appName
|
|
132
134
|
};
|
|
133
135
|
}
|
|
134
|
-
async function initializeReactNativeProject(projectName, directory) {
|
|
136
|
+
async function initializeReactNativeProject(projectName, directory, displayName) {
|
|
135
137
|
const spinner = ora('Initializing React Native project...').start();
|
|
136
138
|
try {
|
|
137
139
|
// Use the correct React Native CLI command format with specific version and yarn
|
|
138
140
|
const cliCommand = 'npx';
|
|
139
141
|
const args = ['@react-native-community/cli@latest', 'init', projectName, '--version', '0.80.1', '--pm', 'yarn'];
|
|
142
|
+
// Add title if displayName is provided
|
|
143
|
+
if (displayName) {
|
|
144
|
+
args.push('--title', displayName);
|
|
145
|
+
}
|
|
140
146
|
// Run React Native initialization in the target directory
|
|
141
147
|
await runCommand(cliCommand, args, { cwd: directory });
|
|
142
148
|
spinner.succeed('React Native project initialized successfully');
|
|
@@ -219,21 +225,97 @@ async function mergePackageJsonDependencies(templatePath, projectPath) {
|
|
|
219
225
|
throw error;
|
|
220
226
|
}
|
|
221
227
|
}
|
|
228
|
+
async function promptForProjectName() {
|
|
229
|
+
const { projectName } = await inquirer.prompt([
|
|
230
|
+
{
|
|
231
|
+
type: 'input',
|
|
232
|
+
name: 'projectName',
|
|
233
|
+
message: 'What is your project name?',
|
|
234
|
+
validate: (input) => {
|
|
235
|
+
if (!input || input.trim().length === 0) {
|
|
236
|
+
return 'Project name is required';
|
|
237
|
+
}
|
|
238
|
+
const lowerName = input.toLowerCase();
|
|
239
|
+
if (!validateProjectName(lowerName)) {
|
|
240
|
+
return 'Project name must be a valid npm package name (lowercase, no spaces)';
|
|
241
|
+
}
|
|
242
|
+
return true;
|
|
243
|
+
},
|
|
244
|
+
filter: (input) => input.toLowerCase().trim()
|
|
245
|
+
}
|
|
246
|
+
]);
|
|
247
|
+
return projectName;
|
|
248
|
+
}
|
|
249
|
+
async function promptForProjectType() {
|
|
250
|
+
const { projectType } = await inquirer.prompt([
|
|
251
|
+
{
|
|
252
|
+
type: 'list',
|
|
253
|
+
name: 'projectType',
|
|
254
|
+
message: 'What type of project would you like to create?',
|
|
255
|
+
choices: [
|
|
256
|
+
{ name: 'React Native App', value: 'native' },
|
|
257
|
+
{ name: 'React Web App', value: 'web' },
|
|
258
|
+
{ name: 'Shared Library', value: 'shared' }
|
|
259
|
+
],
|
|
260
|
+
default: 'native'
|
|
261
|
+
}
|
|
262
|
+
]);
|
|
263
|
+
return projectType;
|
|
264
|
+
}
|
|
265
|
+
async function promptForAppName(projectName) {
|
|
266
|
+
const { appName } = await inquirer.prompt([
|
|
267
|
+
{
|
|
268
|
+
type: 'input',
|
|
269
|
+
name: 'appName',
|
|
270
|
+
message: 'What is the display name for your app? (used for native app titles)',
|
|
271
|
+
default: projectName.split('-').map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join(' '),
|
|
272
|
+
validate: (input) => {
|
|
273
|
+
if (!input || input.trim().length === 0) {
|
|
274
|
+
return 'App name is required';
|
|
275
|
+
}
|
|
276
|
+
return true;
|
|
277
|
+
},
|
|
278
|
+
filter: (input) => input.trim()
|
|
279
|
+
}
|
|
280
|
+
]);
|
|
281
|
+
return appName;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
var utils = /*#__PURE__*/Object.freeze({
|
|
285
|
+
__proto__: null,
|
|
286
|
+
copyTemplate: copyTemplate,
|
|
287
|
+
createPackageName: createPackageName,
|
|
288
|
+
getTemplateData: getTemplateData,
|
|
289
|
+
initializeReactNativeProject: initializeReactNativeProject,
|
|
290
|
+
installDependencies: installDependencies,
|
|
291
|
+
mergePackageJsonDependencies: mergePackageJsonDependencies,
|
|
292
|
+
overlayIdealystFiles: overlayIdealystFiles,
|
|
293
|
+
processTemplateFile: processTemplateFile,
|
|
294
|
+
processTemplateFiles: processTemplateFiles,
|
|
295
|
+
promptForAppName: promptForAppName,
|
|
296
|
+
promptForProjectName: promptForProjectName,
|
|
297
|
+
promptForProjectType: promptForProjectType,
|
|
298
|
+
runCommand: runCommand,
|
|
299
|
+
updateWorkspacePackageJson: updateWorkspacePackageJson,
|
|
300
|
+
validateProjectName: validateProjectName
|
|
301
|
+
});
|
|
222
302
|
|
|
223
303
|
const __filename$3 = fileURLToPath(import.meta.url);
|
|
224
304
|
const __dirname$3 = path.dirname(__filename$3);
|
|
225
305
|
async function generateNativeProject(options) {
|
|
226
|
-
const { name, directory, skipInstall } = options;
|
|
306
|
+
const { name, directory, skipInstall, appName } = options;
|
|
227
307
|
if (!validateProjectName(name)) {
|
|
228
308
|
throw new Error(`Invalid project name: ${name}`);
|
|
229
309
|
}
|
|
310
|
+
const displayName = appName || name.split('-').map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join(' ');
|
|
230
311
|
console.log(chalk.blue(`📱 Creating React Native project: ${name}`));
|
|
312
|
+
console.log(chalk.gray(` App display name: ${displayName}`));
|
|
231
313
|
const projectPath = path.join(directory, name);
|
|
232
314
|
const templatePath = path.join(__dirname$3, '..', 'templates', 'native');
|
|
233
|
-
const templateData = getTemplateData(name, `React Native app built with Idealyst Framework
|
|
315
|
+
const templateData = getTemplateData(name, `React Native app built with Idealyst Framework`, displayName);
|
|
234
316
|
try {
|
|
235
317
|
// Step 1: Initialize React Native project using CLI
|
|
236
|
-
await initializeReactNativeProject(name, directory);
|
|
318
|
+
await initializeReactNativeProject(name, directory, displayName);
|
|
237
319
|
// Step 2: Overlay Idealyst-specific files
|
|
238
320
|
await overlayIdealystFiles(templatePath, projectPath, templateData);
|
|
239
321
|
// Step 3: Install dependencies (including Idealyst packages)
|
|
@@ -354,33 +436,59 @@ program
|
|
|
354
436
|
.description('CLI tool for generating Idealyst Framework projects')
|
|
355
437
|
.version('1.0.1');
|
|
356
438
|
program
|
|
357
|
-
.command('create
|
|
439
|
+
.command('create [project-name]')
|
|
358
440
|
.description('Create a new Idealyst project')
|
|
359
|
-
.option('-t, --type <type>', 'Project type: native, web, or shared'
|
|
441
|
+
.option('-t, --type <type>', 'Project type: native, web, or shared')
|
|
360
442
|
.option('-d, --directory <directory>', 'Output directory', '.')
|
|
443
|
+
.option('-a, --app-name <app-name>', 'Display name for native apps (e.g., "My Awesome App")')
|
|
361
444
|
.option('--skip-install', 'Skip installing dependencies')
|
|
362
445
|
.action(async (projectName, options) => {
|
|
363
|
-
const validTypes = ['native', 'web', 'shared'];
|
|
364
|
-
if (!validTypes.includes(options.type)) {
|
|
365
|
-
console.error(chalk.red(`Invalid project type: ${options.type}`));
|
|
366
|
-
console.error(chalk.yellow(`Valid types are: ${validTypes.join(', ')}`));
|
|
367
|
-
process.exit(1);
|
|
368
|
-
}
|
|
369
446
|
try {
|
|
447
|
+
// Prompt for project name if not provided
|
|
448
|
+
if (!projectName) {
|
|
449
|
+
projectName = await promptForProjectName();
|
|
450
|
+
}
|
|
451
|
+
else {
|
|
452
|
+
// Validate provided project name
|
|
453
|
+
const { validateProjectName } = await Promise.resolve().then(function () { return utils; });
|
|
454
|
+
if (!validateProjectName(projectName.toLowerCase())) {
|
|
455
|
+
console.error(chalk.red(`Invalid project name: ${projectName}`));
|
|
456
|
+
console.error(chalk.yellow('Project name must be a valid npm package name (lowercase, no spaces)'));
|
|
457
|
+
process.exit(1);
|
|
458
|
+
}
|
|
459
|
+
projectName = projectName.toLowerCase();
|
|
460
|
+
}
|
|
461
|
+
// Prompt for project type if not provided
|
|
462
|
+
let projectType = options.type;
|
|
463
|
+
if (!projectType) {
|
|
464
|
+
projectType = await promptForProjectType();
|
|
465
|
+
}
|
|
466
|
+
const validTypes = ['native', 'web', 'shared'];
|
|
467
|
+
if (!validTypes.includes(projectType)) {
|
|
468
|
+
console.error(chalk.red(`Invalid project type: ${projectType}`));
|
|
469
|
+
console.error(chalk.yellow(`Valid types are: ${validTypes.join(', ')}`));
|
|
470
|
+
process.exit(1);
|
|
471
|
+
}
|
|
472
|
+
// Prompt for app name if it's a native project and app name not provided
|
|
473
|
+
let appName = options.appName;
|
|
474
|
+
if (projectType === 'native' && !appName) {
|
|
475
|
+
appName = await promptForAppName(projectName);
|
|
476
|
+
}
|
|
370
477
|
await generateProject({
|
|
371
478
|
name: projectName,
|
|
372
|
-
type:
|
|
479
|
+
type: projectType,
|
|
373
480
|
directory: options.directory,
|
|
374
|
-
skipInstall: options.skipInstall || false
|
|
481
|
+
skipInstall: options.skipInstall || false,
|
|
482
|
+
appName
|
|
375
483
|
});
|
|
376
484
|
console.log(chalk.green(`✨ Successfully created ${projectName}!`));
|
|
377
485
|
console.log(chalk.blue(`📁 Project created in: ${options.directory}/${projectName}`));
|
|
378
|
-
if (
|
|
486
|
+
if (projectType === 'native') {
|
|
379
487
|
console.log(chalk.yellow('\n📱 Next steps for React Native:'));
|
|
380
488
|
console.log(chalk.white(' cd ' + projectName));
|
|
381
489
|
console.log(chalk.white(' yarn android # or yarn ios'));
|
|
382
490
|
}
|
|
383
|
-
else if (
|
|
491
|
+
else if (projectType === 'web') {
|
|
384
492
|
console.log(chalk.yellow('\n🌐 Next steps for React Web:'));
|
|
385
493
|
console.log(chalk.white(' cd ' + projectName));
|
|
386
494
|
console.log(chalk.white(' yarn dev'));
|
|
@@ -397,22 +505,36 @@ program
|
|
|
397
505
|
}
|
|
398
506
|
});
|
|
399
507
|
program
|
|
400
|
-
.command('init')
|
|
508
|
+
.command('init [project-name]')
|
|
401
509
|
.description('Initialize a new Idealyst monorepo workspace')
|
|
402
510
|
.option('-d, --directory <directory>', 'Output directory', '.')
|
|
403
511
|
.option('--skip-install', 'Skip installing dependencies')
|
|
404
|
-
.action(async (options) => {
|
|
512
|
+
.action(async (projectName, options) => {
|
|
405
513
|
try {
|
|
514
|
+
// Prompt for project name if not provided
|
|
515
|
+
if (!projectName) {
|
|
516
|
+
projectName = await promptForProjectName();
|
|
517
|
+
}
|
|
518
|
+
else {
|
|
519
|
+
// Validate provided project name
|
|
520
|
+
const { validateProjectName } = await Promise.resolve().then(function () { return utils; });
|
|
521
|
+
if (!validateProjectName(projectName.toLowerCase())) {
|
|
522
|
+
console.error(chalk.red(`Invalid project name: ${projectName}`));
|
|
523
|
+
console.error(chalk.yellow('Project name must be a valid npm package name (lowercase, no spaces)'));
|
|
524
|
+
process.exit(1);
|
|
525
|
+
}
|
|
526
|
+
projectName = projectName.toLowerCase();
|
|
527
|
+
}
|
|
406
528
|
await generateProject({
|
|
407
|
-
name:
|
|
529
|
+
name: projectName,
|
|
408
530
|
type: 'workspace',
|
|
409
531
|
directory: options.directory,
|
|
410
532
|
skipInstall: options.skipInstall || false
|
|
411
533
|
});
|
|
412
534
|
console.log(chalk.green('✨ Successfully initialized Idealyst workspace!'));
|
|
413
|
-
console.log(chalk.blue(`📁 Workspace created in: ${options.directory}
|
|
535
|
+
console.log(chalk.blue(`📁 Workspace created in: ${options.directory}/${projectName}`));
|
|
414
536
|
console.log(chalk.yellow('\n🚀 Next steps:'));
|
|
415
|
-
console.log(chalk.white(
|
|
537
|
+
console.log(chalk.white(` cd ${projectName}`));
|
|
416
538
|
console.log(chalk.white(' idealyst create my-app --type native'));
|
|
417
539
|
console.log(chalk.white(' idealyst create my-web-app --type web'));
|
|
418
540
|
}
|
|
@@ -9,7 +9,10 @@ export declare function installDependencies(projectPath: string, skipInstall?: b
|
|
|
9
9
|
export declare function runCommand(command: string, args: string[], options: {
|
|
10
10
|
cwd: string;
|
|
11
11
|
}): Promise<void>;
|
|
12
|
-
export declare function getTemplateData(projectName: string, description?: string): TemplateData;
|
|
13
|
-
export declare function initializeReactNativeProject(projectName: string, directory: string): Promise<void>;
|
|
12
|
+
export declare function getTemplateData(projectName: string, description?: string, appName?: string): TemplateData;
|
|
13
|
+
export declare function initializeReactNativeProject(projectName: string, directory: string, displayName?: string): Promise<void>;
|
|
14
14
|
export declare function overlayIdealystFiles(templatePath: string, projectPath: string, data: TemplateData): Promise<void>;
|
|
15
15
|
export declare function mergePackageJsonDependencies(templatePath: string, projectPath: string): Promise<void>;
|
|
16
|
+
export declare function promptForProjectName(): Promise<string>;
|
|
17
|
+
export declare function promptForProjectType(): Promise<string>;
|
|
18
|
+
export declare function promptForAppName(projectName: string): Promise<string>;
|
package/dist/types/types.d.ts
CHANGED
|
@@ -4,10 +4,12 @@ export interface GenerateProjectOptions {
|
|
|
4
4
|
type: ProjectType;
|
|
5
5
|
directory: string;
|
|
6
6
|
skipInstall: boolean;
|
|
7
|
+
appName?: string;
|
|
7
8
|
}
|
|
8
9
|
export interface TemplateData {
|
|
9
10
|
projectName: string;
|
|
10
11
|
packageName: string;
|
|
11
12
|
version: string;
|
|
12
13
|
description: string;
|
|
14
|
+
appName?: string;
|
|
13
15
|
}
|
package/package.json
CHANGED
|
@@ -12,11 +12,6 @@ const config = {
|
|
|
12
12
|
// Important for Idealyst to use .native extensions for React Native (eg: @idealyst/components/src/Button/Button.native.tsx)
|
|
13
13
|
sourceExts: ['native.tsx', 'native.ts', 'tsx', 'ts', 'native.jsx', 'native.js', 'jsx', 'js', 'json'],
|
|
14
14
|
},
|
|
15
|
-
watchFolders: [
|
|
16
|
-
path.resolve(__dirname, 'src'),
|
|
17
|
-
// To support live updates when developing components in other workspaces, add the folders here. Make sure
|
|
18
|
-
// path.resolve(__dirname, '../shared/'),
|
|
19
|
-
],
|
|
20
15
|
watcher: {
|
|
21
16
|
// When configuring custom components with .native extensions, make sure the watcher looks for them
|
|
22
17
|
additionalExts: ['native.tsx', 'native.ts', 'native.jsx', 'native.js'],
|
|
@@ -1,20 +1,16 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
1
|
+
import './App.css';
|
|
2
|
+
import { BrowserRouter } from 'react-router-dom';
|
|
3
|
+
import { ExampleStackRouter, } from '@idealyst/navigation/examples';
|
|
4
|
+
import { NavigatorProvider } from '@idealyst/navigation';
|
|
3
5
|
|
|
4
|
-
|
|
6
|
+
function App() {
|
|
5
7
|
return (
|
|
6
|
-
<
|
|
7
|
-
<
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
onPress={() => console.log('Button pressed!')}
|
|
14
|
-
style={{ marginTop: 20 }}
|
|
15
|
-
/>
|
|
16
|
-
</View>
|
|
17
|
-
);
|
|
18
|
-
};
|
|
8
|
+
<div className="App">
|
|
9
|
+
<BrowserRouter>
|
|
10
|
+
<NavigatorProvider route={ExampleStackRouter} />
|
|
11
|
+
</BrowserRouter>
|
|
12
|
+
</div>
|
|
13
|
+
);
|
|
14
|
+
}
|
|
19
15
|
|
|
20
16
|
export default App;
|
|
@@ -1,12 +1,26 @@
|
|
|
1
|
-
|
|
1
|
+
// Import navigation unistyles after all other imports to ensure it overrides any previous configuration
|
|
2
|
+
import '@idealyst/navigation/examples/unistyles';
|
|
2
3
|
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import App from './App';
|
|
4
|
+
import * as React from 'react';
|
|
5
|
+
import ReactDOM from 'react-dom/client';
|
|
6
|
+
import App from './App.tsx';
|
|
6
7
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
8
|
+
// Hydrate the app if it's SSR, otherwise render normally
|
|
9
|
+
const container = document.getElementById('root')!;
|
|
10
|
+
|
|
11
|
+
if (container.hasChildNodes()) {
|
|
12
|
+
// If the container has child nodes, it means we're hydrating SSR content
|
|
13
|
+
ReactDOM.hydrateRoot(container,
|
|
14
|
+
<React.StrictMode>
|
|
15
|
+
<App />
|
|
16
|
+
</React.StrictMode>
|
|
17
|
+
);
|
|
18
|
+
} else {
|
|
19
|
+
// Otherwise, render normally (for development)
|
|
20
|
+
const root = ReactDOM.createRoot(container);
|
|
21
|
+
root.render(
|
|
22
|
+
<React.StrictMode>
|
|
23
|
+
<App />
|
|
24
|
+
</React.StrictMode>
|
|
25
|
+
);
|
|
26
|
+
}
|
|
@@ -7,9 +7,7 @@ import path from 'path'
|
|
|
7
7
|
export default defineConfig({
|
|
8
8
|
plugins: [
|
|
9
9
|
babel({
|
|
10
|
-
filter: (id) =>
|
|
11
|
-
return id.includes('node_modules/@idealyst/') && /\.(js|jsx|ts|tsx)$/.test(id);
|
|
12
|
-
},
|
|
10
|
+
filter: (id) => id.includes('node_modules/@idealyst/') && /\.(js|jsx|ts|tsx)$/.test(id),
|
|
13
11
|
babelConfig: {
|
|
14
12
|
presets: [
|
|
15
13
|
['@babel/preset-typescript', {
|
|
@@ -20,7 +18,6 @@ export default defineConfig({
|
|
|
20
18
|
plugins: [
|
|
21
19
|
['react-native-unistyles/plugin', {
|
|
22
20
|
root: 'src',
|
|
23
|
-
debug: true,
|
|
24
21
|
autoProcessPaths: ['@idealyst/components', '@idealyst/navigation', '@idealyst/theme'],
|
|
25
22
|
}],
|
|
26
23
|
['@idealyst/components/plugin/web', { root: 'src' }]
|
package/templates/App.tsx
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import './App.css';
|
|
2
|
-
import { BrowserRouter } from 'react-router-dom';
|
|
3
|
-
import { ExampleStackRouter, } from '@idealyst/navigation/examples';
|
|
4
|
-
import { NavigatorProvider } from '@idealyst/navigation';
|
|
5
|
-
|
|
6
|
-
function App() {
|
|
7
|
-
return (
|
|
8
|
-
<div className="App">
|
|
9
|
-
<BrowserRouter>
|
|
10
|
-
<NavigatorProvider route={ExampleStackRouter} />
|
|
11
|
-
</BrowserRouter>
|
|
12
|
-
</div>
|
|
13
|
-
);
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export default App;
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
nodeLinker: "node-modules"
|
|
2
|
-
|
|
3
|
-
# Enable network for package downloads
|
|
4
|
-
enableNetwork: true
|
|
5
|
-
|
|
6
|
-
# Timeout for HTTP requests (in milliseconds)
|
|
7
|
-
httpTimeout: 60000
|
|
8
|
-
|
|
9
|
-
# Number of retry attempts for HTTP requests
|
|
10
|
-
httpRetry: 3
|
|
11
|
-
|
|
12
|
-
# Registry configuration
|
|
13
|
-
npmRegistryServer: "https://registry.yarnpkg.com"
|
|
14
|
-
|
|
15
|
-
# Enable progress bars
|
|
16
|
-
enableProgressBars: true
|
|
17
|
-
|
|
18
|
-
# Enable colors in output
|
|
19
|
-
enableColors: true
|