create-react-on-rails-app 16.6.0-rc.0 → 16.6.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/lib/index.d.ts CHANGED
@@ -1,2 +1,3 @@
1
- export {};
1
+ import { Command } from 'commander';
2
+ export declare const ready: Promise<Command>;
2
3
  //# sourceMappingURL=index.d.ts.map
package/lib/index.js CHANGED
@@ -3,15 +3,17 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.ready = void 0;
6
7
  const commander_1 = require("commander");
7
8
  const chalk_1 = __importDefault(require("chalk"));
8
9
  const validators_js_1 = require("./validators.js");
9
10
  const create_app_js_1 = require("./create-app.js");
10
11
  const utils_js_1 = require("./utils.js");
12
+ const prompt_js_1 = require("./prompt.js");
11
13
  // Use require() for CJS compatibility - avoids __dirname + fs.readFileSync
12
14
  // eslint-disable-next-line @typescript-eslint/no-require-imports, global-require
13
15
  const packageJson = require('../package.json');
14
- function run(appName, rawOpts) {
16
+ async function run(appName, rawOpts) {
15
17
  const { template } = rawOpts;
16
18
  if (typeof template !== 'string' || (template !== 'javascript' && template !== 'typescript')) {
17
19
  (0, utils_js_1.logError)(`Invalid template "${String(template)}". Must be "javascript" or "typescript".`);
@@ -27,13 +29,8 @@ function run(appName, rawOpts) {
27
29
  else {
28
30
  packageManager = (0, utils_js_1.detectPackageManager)() ?? 'npm';
29
31
  }
30
- const options = {
31
- template,
32
- packageManager: packageManager,
33
- rspack: Boolean(rawOpts.rspack),
34
- pro: Boolean(rawOpts.pro),
35
- rsc: Boolean(rawOpts.rsc),
36
- };
32
+ let pro = Boolean(rawOpts.pro);
33
+ let rsc = Boolean(rawOpts.rsc);
37
34
  console.log('');
38
35
  console.log(`${chalk_1.default.bold('create-react-on-rails-app')} v${packageJson.version}`);
39
36
  console.log('');
@@ -42,6 +39,26 @@ function run(appName, rawOpts) {
42
39
  (0, utils_js_1.logError)(nameValidation.error ?? 'Invalid app name');
43
40
  process.exit(1);
44
41
  }
42
+ // When no mode flag is explicitly passed, prompt interactively (TTY only).
43
+ // Non-interactive environments (CI, pipes) fall back to standard mode.
44
+ const modeExplicit = rawOpts.pro !== undefined || rawOpts.rsc !== undefined || rawOpts.standard !== undefined;
45
+ if (!modeExplicit) {
46
+ if (process.stdin.isTTY && process.stdout.isTTY) {
47
+ const choice = await (0, prompt_js_1.promptForMode)();
48
+ pro = choice.pro;
49
+ rsc = choice.rsc;
50
+ }
51
+ else {
52
+ (0, utils_js_1.logInfo)('No mode flag specified and not running interactively (stdin/stdout is not a TTY); using standard mode.');
53
+ }
54
+ }
55
+ const options = {
56
+ template,
57
+ packageManager: packageManager,
58
+ rspack: Boolean(rawOpts.rspack),
59
+ pro,
60
+ rsc,
61
+ };
45
62
  if (options.rsc && options.pro) {
46
63
  (0, utils_js_1.logInfo)('Note: --rsc takes precedence over --pro; --pro will be ignored.');
47
64
  }
@@ -93,22 +110,28 @@ program
93
110
  .option('-t, --template <type>', 'javascript or typescript', 'typescript')
94
111
  .option('-p, --package-manager <pm>', 'npm or pnpm (auto-detected if not specified)')
95
112
  .option('--rspack', 'Use Rspack instead of Webpack (~20x faster builds)', false)
96
- .option('--pro', 'Generate React on Rails Pro setup (installs react_on_rails_pro)', false)
97
- .option('--rsc', 'Generate React Server Components setup (installs react_on_rails_pro)', false)
113
+ .option('--standard', 'Generate open-source React on Rails setup (skip prompt)')
114
+ .option('--pro', 'Generate React on Rails Pro setup (installs react_on_rails_pro)')
115
+ .option('--rsc', 'Generate React Server Components setup (installs react_on_rails_pro)')
98
116
  .addHelpText('after', `
99
117
  Examples:
100
- $ npx create-react-on-rails-app my-app
118
+ $ npx create-react-on-rails-app my-app # prompts for mode
119
+ $ npx create-react-on-rails-app my-app --rsc # skip prompt, use RSC
120
+ $ npx create-react-on-rails-app my-app --pro # skip prompt, use Pro
121
+ $ npx create-react-on-rails-app my-app --standard # skip prompt, use Standard
101
122
  $ npx create-react-on-rails-app my-app --template javascript
102
123
  $ npx create-react-on-rails-app my-app --rspack
103
- $ npx create-react-on-rails-app my-app --pro
104
- $ npx create-react-on-rails-app my-app --rsc
105
- $ npx create-react-on-rails-app my-app --rspack --pro
106
124
  $ npx create-react-on-rails-app my-app --rspack --rsc
107
125
  $ npx create-react-on-rails-app my-app --package-manager pnpm
108
126
 
127
+ When no mode flag (--standard, --pro, or --rsc) is given, an interactive prompt
128
+ lets you choose between Standard, Pro, and RSC modes (default: RSC). When stdin
129
+ or stdout is not a TTY (for example in CI, piped input, or redirected output),
130
+ standard mode is used automatically.
131
+
109
132
  What it does:
110
133
  1. Creates a new Rails app with PostgreSQL
111
- 2. Adds required gem(s) (react_on_rails, plus react_on_rails_pro for --pro/--rsc)
134
+ 2. Adds required gem(s) (react_on_rails, plus react_on_rails_pro for Pro/RSC)
112
135
  3. Runs the React on Rails generator (Shakapacker, components, webpack config)
113
136
  4. Creates educational git commits for each major scaffold step
114
137
 
@@ -125,14 +148,22 @@ The generated app includes one git commit per logical setup step.`)
125
148
  --pro and --rsc support both JavaScript and TypeScript templates.
126
149
 
127
150
  Documentation: https://reactonrails.com/docs/`)
128
- .action((appName, opts) => {
151
+ .action(async (appName, opts) => {
129
152
  try {
130
- run(appName, opts);
153
+ await run(appName, opts);
131
154
  }
132
155
  catch (error) {
156
+ if (error instanceof Error && error.message === prompt_js_1.PROMPT_CANCELLED) {
157
+ console.log('');
158
+ process.exit(0);
159
+ }
133
160
  (0, utils_js_1.logError)(error instanceof Error ? error.message : String(error));
134
161
  process.exit(1);
135
162
  }
136
163
  });
137
- program.parse();
164
+ // eslint-disable-next-line import/prefer-default-export -- named export for test clarity
165
+ exports.ready = program.parseAsync().catch((error) => {
166
+ (0, utils_js_1.logError)(error instanceof Error ? error.message : String(error));
167
+ process.exit(1);
168
+ });
138
169
  //# sourceMappingURL=index.js.map
@@ -0,0 +1,7 @@
1
+ export interface ModeChoice {
2
+ pro: boolean;
3
+ rsc: boolean;
4
+ }
5
+ export declare const PROMPT_CANCELLED = "Prompt cancelled by user";
6
+ export declare function promptForMode(): Promise<ModeChoice>;
7
+ //# sourceMappingURL=prompt.d.ts.map
package/lib/prompt.js ADDED
@@ -0,0 +1,72 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.PROMPT_CANCELLED = void 0;
7
+ exports.promptForMode = promptForMode;
8
+ const readline_1 = __importDefault(require("readline"));
9
+ const chalk_1 = __importDefault(require("chalk"));
10
+ exports.PROMPT_CANCELLED = 'Prompt cancelled by user';
11
+ const MODES = [
12
+ {
13
+ key: '1',
14
+ label: 'Standard',
15
+ desc: 'Open-source React on Rails with SSR',
16
+ pro: false,
17
+ rsc: false,
18
+ },
19
+ {
20
+ key: '2',
21
+ label: 'Pro',
22
+ desc: 'Adds Node.js server rendering (requires react_on_rails_pro)',
23
+ pro: true,
24
+ rsc: false,
25
+ },
26
+ {
27
+ key: '3',
28
+ label: 'RSC',
29
+ desc: 'React Server Components (requires react_on_rails_pro)',
30
+ pro: false,
31
+ rsc: true,
32
+ },
33
+ ];
34
+ const DEFAULT_KEY = '3';
35
+ function promptForMode() {
36
+ return new Promise((resolve, reject) => {
37
+ const rl = readline_1.default.createInterface({
38
+ input: process.stdin,
39
+ output: process.stdout,
40
+ });
41
+ let answered = false;
42
+ rl.on('SIGINT', () => {
43
+ answered = true;
44
+ rl.close();
45
+ reject(new Error(exports.PROMPT_CANCELLED));
46
+ });
47
+ rl.once('close', () => {
48
+ if (!answered) {
49
+ reject(new Error(exports.PROMPT_CANCELLED));
50
+ }
51
+ });
52
+ console.log(chalk_1.default.bold('Select a setup mode:\n'));
53
+ for (const mode of MODES) {
54
+ const recommended = mode.key === DEFAULT_KEY ? chalk_1.default.cyan(' (recommended)') : '';
55
+ console.log(` ${mode.key}. ${chalk_1.default.bold(mode.label.padEnd(10))} ${mode.desc}${recommended}`);
56
+ }
57
+ console.log('');
58
+ rl.question(`Choice (1-3) [${DEFAULT_KEY}]: `, (answer) => {
59
+ answered = true;
60
+ rl.close();
61
+ const key = answer.trim() || DEFAULT_KEY;
62
+ const selected = MODES.find((m) => m.key === key);
63
+ if (!selected) {
64
+ console.log(chalk_1.default.yellow(`Invalid choice "${key}", defaulting to RSC.`));
65
+ resolve({ pro: false, rsc: true });
66
+ return;
67
+ }
68
+ resolve({ pro: selected.pro, rsc: selected.rsc });
69
+ });
70
+ });
71
+ }
72
+ //# sourceMappingURL=prompt.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-react-on-rails-app",
3
- "version": "16.6.0-rc.0",
3
+ "version": "16.6.0",
4
4
  "description": "Create React on Rails applications with a single command",
5
5
  "bin": {
6
6
  "create-react-on-rails-app": "./bin/create-react-on-rails-app.js"