@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 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 <project-name>')
439
+ .command('create [project-name]')
358
440
  .description('Create a new Idealyst project')
359
- .option('-t, --type <type>', 'Project type: native, web, or shared', 'native')
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: options.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 (options.type === 'native') {
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 (options.type === 'web') {
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: 'idealyst-workspace',
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}/idealyst-workspace`));
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(' cd idealyst-workspace'));
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>;
@@ -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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@idealyst/cli",
3
- "version": "1.0.17",
3
+ "version": "1.0.19",
4
4
  "description": "CLI tool for generating Idealyst Framework projects",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -1,6 +1,6 @@
1
1
  import '@idealyst/theme/unistyles';
2
2
 
3
3
  import { AppRegistry } from 'react-native';
4
- import App from './src/App';
4
+ import App from './App';
5
5
 
6
6
  AppRegistry.registerComponent('{{projectName}}', () => App);
@@ -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 React from 'react';
2
- import { View, Text, Button } from '@idealyst/components';
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
- const App = () => {
6
+ function App() {
5
7
  return (
6
- <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center', minHeight: '100vh' }}>
7
- <Text variant="h1">Welcome to {{projectName}}</Text>
8
- <Text variant="body" style={{ marginTop: 20, textAlign: 'center' }}>
9
- This is a React web application built with the Idealyst Framework.
10
- </Text>
11
- <Button
12
- title="Get Started"
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
- import '@idealyst/theme/unistyles';
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 { StrictMode } from 'react';
4
- import { createRoot } from 'react-dom/client';
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
- const root = createRoot(document.getElementById('root')!);
8
- root.render(
9
- <StrictMode>
10
- <App />
11
- </StrictMode>
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