@rs-x/cli 2.0.0-next.6 → 2.0.0-next.8

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/README.md CHANGED
@@ -18,6 +18,11 @@ RSX_SKIP_VSCODE_EXTENSION_INSTALL=true
18
18
  ## What gets installed
19
19
 
20
20
  Installing `@rs-x/cli` gives you the `rsx` command.
21
+ For prerelease builds, install globally to make the `rsx` binary available:
22
+
23
+ ```bash
24
+ npm install -g @rs-x/cli@next
25
+ ```
21
26
 
22
27
  Running `rsx init` installs:
23
28
 
package/bin/rsx.cjs CHANGED
@@ -5,8 +5,22 @@ const path = require('node:path');
5
5
  const readline = require('node:readline/promises');
6
6
  const { spawnSync } = require('node:child_process');
7
7
 
8
- const CLI_VERSION = '0.2.0';
8
+ const CLI_VERSION = (() => {
9
+ try {
10
+ const packageJsonPath = path.join(__dirname, '..', 'package.json');
11
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
12
+ return packageJson.version ?? '0.0.0';
13
+ } catch {
14
+ return '0.0.0';
15
+ }
16
+ })();
9
17
  const VS_CODE_EXTENSION_ID = 'rs-x.rs-x-vscode-extension';
18
+ const ANGULAR_DEMO_TEMPLATE_DIR = path.join(
19
+ __dirname,
20
+ '..',
21
+ 'templates',
22
+ 'angular-demo',
23
+ );
10
24
  const RUNTIME_PACKAGES = [
11
25
  '@rs-x/core',
12
26
  '@rs-x/state-manager',
@@ -262,14 +276,50 @@ function installVsCodeExtension(flags) {
262
276
  return;
263
277
  }
264
278
 
265
- const args = ['--install-extension', VS_CODE_EXTENSION_ID];
279
+ installBundledVsix(dryRun, force);
280
+ }
281
+
282
+ function resolveBundledVsix() {
283
+ const packageRoot = path.resolve(__dirname, '..');
284
+ const candidates = fs
285
+ .readdirSync(packageRoot)
286
+ .filter((name) => /^rs-x-vscode-extension-.*\.vsix$/u.test(name))
287
+ .map((name) => path.join(packageRoot, name));
288
+
289
+ if (candidates.length === 0) {
290
+ return null;
291
+ }
292
+
293
+ const latest = candidates
294
+ .map((fullPath) => ({
295
+ fullPath,
296
+ mtimeMs: fs.statSync(fullPath).mtimeMs,
297
+ }))
298
+ .sort((a, b) => b.mtimeMs - a.mtimeMs)[0];
299
+
300
+ return latest?.fullPath ?? null;
301
+ }
302
+
303
+ function installBundledVsix(dryRun, force) {
304
+ const bundledVsix = resolveBundledVsix();
305
+ if (!bundledVsix) {
306
+ logWarn(
307
+ 'No bundled VSIX found in @rs-x/cli. Skipping VS Code extension install.',
308
+ );
309
+ logInfo(
310
+ 'If you are developing in the rs-x repo, use `rsx install vscode --local` instead.',
311
+ );
312
+ return;
313
+ }
314
+
315
+ const args = ['--install-extension', bundledVsix];
266
316
  if (force) {
267
317
  args.push('--force');
268
318
  }
269
319
 
270
- logInfo(`Installing ${VS_CODE_EXTENSION_ID} from VS Code marketplace...`);
320
+ logInfo(`Installing bundled VSIX from ${bundledVsix}...`);
271
321
  run('code', args, { dryRun });
272
- logOk('VS Code extension installed.');
322
+ logOk('VS Code extension installed from bundled VSIX.');
273
323
  }
274
324
 
275
325
  function installLocalVsix(dryRun, force) {
@@ -585,6 +635,42 @@ function writeFileWithDryRun(filePath, content, dryRun) {
585
635
  fs.writeFileSync(filePath, content, 'utf8');
586
636
  }
587
637
 
638
+ function copyPathWithDryRun(sourcePath, targetPath, dryRun) {
639
+ if (dryRun) {
640
+ logInfo(`[dry-run] copy ${sourcePath} -> ${targetPath}`);
641
+ return;
642
+ }
643
+
644
+ const stat = fs.statSync(sourcePath);
645
+ if (stat.isDirectory()) {
646
+ fs.mkdirSync(targetPath, { recursive: true });
647
+ for (const entry of fs.readdirSync(sourcePath, { withFileTypes: true })) {
648
+ copyPathWithDryRun(
649
+ path.join(sourcePath, entry.name),
650
+ path.join(targetPath, entry.name),
651
+ false,
652
+ );
653
+ }
654
+ return;
655
+ }
656
+
657
+ fs.mkdirSync(path.dirname(targetPath), { recursive: true });
658
+ fs.copyFileSync(sourcePath, targetPath);
659
+ }
660
+
661
+ function removeFileOrDirectoryWithDryRun(targetPath, dryRun) {
662
+ if (!fs.existsSync(targetPath)) {
663
+ return;
664
+ }
665
+
666
+ if (dryRun) {
667
+ logInfo(`[dry-run] remove ${targetPath}`);
668
+ return;
669
+ }
670
+
671
+ fs.rmSync(targetPath, { recursive: true, force: true });
672
+ }
673
+
588
674
  function toFileDependencySpec(fromDir, targetPath) {
589
675
  const relative = path.relative(fromDir, targetPath).replace(/\\/gu, '/');
590
676
  const normalized = relative.startsWith('.') ? relative : `./${relative}`;
@@ -642,7 +728,7 @@ function resolveProjectRsxSpecs(
642
728
  '@rs-x/compiler': versionSpec,
643
729
  '@rs-x/typescript-plugin': versionSpec,
644
730
  ...(includeAngularPackage ? { '@rs-x/angular': versionSpec } : {}),
645
- '@rs-x/cli': null,
731
+ '@rs-x/cli': versionSpec,
646
732
  };
647
733
 
648
734
  const tarballSlugs = {
@@ -1182,6 +1268,173 @@ function scaffoldProjectTemplate(template, projectName, pm, flags) {
1182
1268
  process.exit(1);
1183
1269
  }
1184
1270
 
1271
+ function applyAngularDemoStarter(projectRoot, projectName, pm, flags) {
1272
+ const dryRun = Boolean(flags['dry-run']);
1273
+ const tag = resolveInstallTag(flags);
1274
+ const tarballsDir =
1275
+ typeof flags['tarballs-dir'] === 'string'
1276
+ ? path.resolve(process.cwd(), flags['tarballs-dir'])
1277
+ : typeof process.env.RSX_TARBALLS_DIR === 'string' &&
1278
+ process.env.RSX_TARBALLS_DIR.trim().length > 0
1279
+ ? path.resolve(process.cwd(), process.env.RSX_TARBALLS_DIR)
1280
+ : null;
1281
+ const workspaceRoot = findRepoRoot(projectRoot);
1282
+ const rsxSpecs = resolveProjectRsxSpecs(
1283
+ projectRoot,
1284
+ workspaceRoot,
1285
+ tarballsDir,
1286
+ { tag, includeAngularPackage: true },
1287
+ );
1288
+
1289
+ const templateFiles = ['README.md', 'src'];
1290
+ for (const entry of templateFiles) {
1291
+ copyPathWithDryRun(
1292
+ path.join(ANGULAR_DEMO_TEMPLATE_DIR, entry),
1293
+ path.join(projectRoot, entry),
1294
+ dryRun,
1295
+ );
1296
+ }
1297
+
1298
+ const staleAngularFiles = [
1299
+ path.join(projectRoot, 'src/app/app.ts'),
1300
+ path.join(projectRoot, 'src/app/app.spec.ts'),
1301
+ path.join(projectRoot, 'src/app/app.html'),
1302
+ path.join(projectRoot, 'src/app/app.css'),
1303
+ path.join(projectRoot, 'src/app/app.routes.ts'),
1304
+ path.join(projectRoot, 'src/app/app.config.ts'),
1305
+ ];
1306
+ for (const stalePath of staleAngularFiles) {
1307
+ removeFileOrDirectoryWithDryRun(stalePath, dryRun);
1308
+ }
1309
+
1310
+ const readmePath = path.join(projectRoot, 'README.md');
1311
+ if (fs.existsSync(readmePath)) {
1312
+ const readmeSource = fs.readFileSync(readmePath, 'utf8');
1313
+ const nextReadme = readmeSource.replace(
1314
+ /^#\s+rsx-angular-example/mu,
1315
+ `# ${projectName}`,
1316
+ );
1317
+ if (dryRun) {
1318
+ logInfo(`[dry-run] patch ${readmePath}`);
1319
+ } else {
1320
+ fs.writeFileSync(readmePath, nextReadme, 'utf8');
1321
+ }
1322
+ }
1323
+
1324
+ const packageJsonPath = path.join(projectRoot, 'package.json');
1325
+ if (!fs.existsSync(packageJsonPath)) {
1326
+ logError(
1327
+ `package.json not found in generated Angular app: ${packageJsonPath}`,
1328
+ );
1329
+ process.exit(1);
1330
+ }
1331
+
1332
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
1333
+ packageJson.name = projectName;
1334
+ packageJson.private = true;
1335
+ packageJson.version = '0.1.0';
1336
+ packageJson.scripts = {
1337
+ prebuild: 'rsx build --project tsconfig.json --no-emit --prod',
1338
+ start: 'npm run build && ng serve',
1339
+ build: 'ng build',
1340
+ };
1341
+ packageJson.rsx = {
1342
+ build: {
1343
+ preparse: true,
1344
+ preparseFile: 'src/rsx-generated/rsx-aot-preparsed.generated.ts',
1345
+ compiled: true,
1346
+ compiledFile: 'src/rsx-generated/rsx-aot-compiled.generated.ts',
1347
+ registrationFile: 'src/rsx-generated/rsx-aot-registration.generated.ts',
1348
+ compiledResolvedEvaluator: false,
1349
+ },
1350
+ };
1351
+ packageJson.dependencies = {
1352
+ ...(packageJson.dependencies ?? {}),
1353
+ '@rs-x/angular': rsxSpecs['@rs-x/angular'],
1354
+ '@rs-x/core': rsxSpecs['@rs-x/core'],
1355
+ '@rs-x/state-manager': rsxSpecs['@rs-x/state-manager'],
1356
+ '@rs-x/expression-parser': rsxSpecs['@rs-x/expression-parser'],
1357
+ };
1358
+ packageJson.devDependencies = {
1359
+ ...(packageJson.devDependencies ?? {}),
1360
+ '@rs-x/cli': rsxSpecs['@rs-x/cli'],
1361
+ '@rs-x/compiler': rsxSpecs['@rs-x/compiler'],
1362
+ '@rs-x/typescript-plugin': rsxSpecs['@rs-x/typescript-plugin'],
1363
+ };
1364
+
1365
+ if (dryRun) {
1366
+ logInfo(`[dry-run] patch ${packageJsonPath}`);
1367
+ } else {
1368
+ fs.writeFileSync(
1369
+ packageJsonPath,
1370
+ `${JSON.stringify(packageJson, null, 2)}\n`,
1371
+ 'utf8',
1372
+ );
1373
+ }
1374
+
1375
+ const angularJsonPath = path.join(projectRoot, 'angular.json');
1376
+ if (!fs.existsSync(angularJsonPath)) {
1377
+ logError(
1378
+ `angular.json not found in generated Angular app: ${angularJsonPath}`,
1379
+ );
1380
+ process.exit(1);
1381
+ }
1382
+
1383
+ const angularJson = JSON.parse(fs.readFileSync(angularJsonPath, 'utf8'));
1384
+ const projects = angularJson.projects ?? {};
1385
+ const [angularProjectName] = Object.keys(projects);
1386
+ if (!angularProjectName) {
1387
+ logError('Generated angular.json does not define any projects.');
1388
+ process.exit(1);
1389
+ }
1390
+
1391
+ const angularProject = projects[angularProjectName];
1392
+ const architect = angularProject.architect ?? angularProject.targets;
1393
+ const build = architect?.build;
1394
+ if (!build) {
1395
+ logError('Generated Angular project is missing a build target.');
1396
+ process.exit(1);
1397
+ }
1398
+
1399
+ const buildOptions = build.options ?? {};
1400
+ const styles = Array.isArray(buildOptions.styles) ? buildOptions.styles : [];
1401
+ if (!styles.includes('src/styles.css')) {
1402
+ styles.push('src/styles.css');
1403
+ }
1404
+ buildOptions.styles = styles;
1405
+ buildOptions.preserveSymlinks = true;
1406
+
1407
+ const registrationFile =
1408
+ 'src/rsx-generated/rsx-aot-registration.generated.ts';
1409
+ let polyfills = buildOptions.polyfills;
1410
+ if (typeof polyfills === 'string') {
1411
+ polyfills = [polyfills];
1412
+ } else if (!Array.isArray(polyfills)) {
1413
+ polyfills = [];
1414
+ }
1415
+ if (!polyfills.includes(registrationFile)) {
1416
+ polyfills.push(registrationFile);
1417
+ }
1418
+ buildOptions.polyfills = polyfills;
1419
+ build.options = buildOptions;
1420
+
1421
+ if (dryRun) {
1422
+ logInfo(`[dry-run] patch ${angularJsonPath}`);
1423
+ } else {
1424
+ fs.writeFileSync(
1425
+ angularJsonPath,
1426
+ `${JSON.stringify(angularJson, null, 2)}\n`,
1427
+ 'utf8',
1428
+ );
1429
+ }
1430
+
1431
+ if (!Boolean(flags['skip-install'])) {
1432
+ logInfo(`Refreshing ${pm} dependencies for the RS-X Angular starter...`);
1433
+ run(pm, ['install'], { dryRun });
1434
+ logOk('Angular starter dependencies are up to date.');
1435
+ }
1436
+ }
1437
+
1185
1438
  async function runProjectWithTemplate(template, flags) {
1186
1439
  const normalizedTemplate = normalizeProjectTemplate(template);
1187
1440
  if (!normalizedTemplate) {
@@ -1213,7 +1466,7 @@ async function runProjectWithTemplate(template, flags) {
1213
1466
 
1214
1467
  withWorkingDirectory(projectRoot, () => {
1215
1468
  if (normalizedTemplate === 'angular') {
1216
- runSetupAngular(flags);
1469
+ applyAngularDemoStarter(projectRoot, projectName, pm, flags);
1217
1470
  return;
1218
1471
  }
1219
1472
  if (normalizedTemplate === 'react') {
@@ -1788,11 +2041,112 @@ function runInit(flags) {
1788
2041
  }
1789
2042
  }
1790
2043
 
1791
- if (!skipVscode) {
1792
- installVsCodeExtension(flags);
2044
+ logOk('RS-X init completed.');
2045
+ }
2046
+
2047
+ function upsertRsxBuildConfigInPackageJson(projectRoot, dryRun) {
2048
+ const packageJsonPath = path.join(projectRoot, 'package.json');
2049
+ if (!fs.existsSync(packageJsonPath)) {
2050
+ return false;
1793
2051
  }
1794
2052
 
1795
- logOk('RS-X init completed.');
2053
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
2054
+ const currentRsx = packageJson.rsx ?? {};
2055
+ const currentBuild = currentRsx.build ?? {};
2056
+ const nextBuild = {
2057
+ preparse: true,
2058
+ preparseFile: 'src/rsx-generated/rsx-aot-preparsed.generated.ts',
2059
+ compiled: true,
2060
+ compiledFile: 'src/rsx-generated/rsx-aot-compiled.generated.ts',
2061
+ registrationFile: 'src/rsx-generated/rsx-aot-registration.generated.ts',
2062
+ compiledResolvedEvaluator: false,
2063
+ ...currentBuild,
2064
+ };
2065
+
2066
+ const nextPackageJson = {
2067
+ ...packageJson,
2068
+ rsx: {
2069
+ ...currentRsx,
2070
+ build: nextBuild,
2071
+ },
2072
+ };
2073
+
2074
+ if (dryRun) {
2075
+ logInfo(`[dry-run] patch ${packageJsonPath} (rsx.build)`);
2076
+ return true;
2077
+ }
2078
+
2079
+ fs.writeFileSync(
2080
+ packageJsonPath,
2081
+ `${JSON.stringify(nextPackageJson, null, 2)}\n`,
2082
+ 'utf8',
2083
+ );
2084
+ logOk(`Patched ${packageJsonPath} (rsx.build)`);
2085
+ return true;
2086
+ }
2087
+
2088
+ function ensureAngularProvidersInEntry(entryFile, dryRun) {
2089
+ if (!fs.existsSync(entryFile)) {
2090
+ return false;
2091
+ }
2092
+
2093
+ const original = fs.readFileSync(entryFile, 'utf8');
2094
+ if (original.includes('providexRsx')) {
2095
+ logInfo(`Angular entry already includes providexRsx: ${entryFile}`);
2096
+ return true;
2097
+ }
2098
+
2099
+ if (!original.includes('bootstrapApplication(')) {
2100
+ logWarn(
2101
+ `Could not automatically patch Angular providers in ${entryFile}. Expected bootstrapApplication(...).`,
2102
+ );
2103
+ logInfo(
2104
+ "Manual setup: import { providexRsx } from '@rs-x/angular' and add providers: [...providexRsx()] to bootstrapApplication(...).",
2105
+ );
2106
+ return false;
2107
+ }
2108
+
2109
+ const sourceWithImport = injectImport(
2110
+ original,
2111
+ "import { providexRsx } from '@rs-x/angular';",
2112
+ );
2113
+
2114
+ let updated = sourceWithImport;
2115
+ if (
2116
+ /bootstrapApplication\([\s\S]*?,\s*\{[\s\S]*?providers\s*:/mu.test(updated)
2117
+ ) {
2118
+ updated = updated.replace(
2119
+ /providers\s*:\s*\[/mu,
2120
+ 'providers: [...providexRsx(), ',
2121
+ );
2122
+ } else if (/bootstrapApplication\([\s\S]*?,\s*\{/mu.test(updated)) {
2123
+ updated = updated.replace(
2124
+ /bootstrapApplication\(([\s\S]*?),\s*\{/mu,
2125
+ 'bootstrapApplication($1, {\n providers: [...providexRsx()],',
2126
+ );
2127
+ } else {
2128
+ updated = updated.replace(
2129
+ /bootstrapApplication\(([\s\S]*?)\)\s*(?:\.catch\([\s\S]*?\))?\s*;/mu,
2130
+ 'bootstrapApplication($1, {\n providers: [...providexRsx()],\n}).catch((error) => {\n console.error(error);\n});',
2131
+ );
2132
+ }
2133
+
2134
+ if (updated === sourceWithImport) {
2135
+ logWarn(`Could not automatically inject providexRsx into ${entryFile}.`);
2136
+ logInfo(
2137
+ "Manual setup: import { providexRsx } from '@rs-x/angular' and add providers: [...providexRsx()] to bootstrapApplication(...).",
2138
+ );
2139
+ return false;
2140
+ }
2141
+
2142
+ if (dryRun) {
2143
+ logInfo(`[dry-run] patch ${entryFile} (providexRsx)`);
2144
+ return true;
2145
+ }
2146
+
2147
+ fs.writeFileSync(entryFile, updated, 'utf8');
2148
+ logOk(`Patched ${entryFile} to include providexRsx.`);
2149
+ return true;
1796
2150
  }
1797
2151
 
1798
2152
  function upsertScriptInPackageJson(
@@ -2154,91 +2508,6 @@ ${patchBlock}
2154
2508
  logOk(`Patched ${nextConfigJs} with RS-X webpack loader.`);
2155
2509
  }
2156
2510
 
2157
- function wireRsxAngularWebpack(projectRoot, dryRun) {
2158
- const angularJsonPath = path.join(projectRoot, 'angular.json');
2159
- if (!fs.existsSync(angularJsonPath)) {
2160
- logWarn('angular.json not found. Skipping Angular build integration.');
2161
- return;
2162
- }
2163
-
2164
- createRsxWebpackLoaderFile(projectRoot, dryRun);
2165
-
2166
- const webpackConfigPath = path.join(projectRoot, 'rsx-angular-webpack.cjs');
2167
- const webpackConfigSource = `const path = require('node:path');
2168
-
2169
- module.exports = {
2170
- module: {
2171
- rules: [
2172
- {
2173
- test: /\\.[jt]sx?$/u,
2174
- exclude: /node_modules/u,
2175
- use: [
2176
- {
2177
- loader: path.resolve(__dirname, './rsx-webpack-loader.cjs'),
2178
- },
2179
- ],
2180
- },
2181
- ],
2182
- },
2183
- };
2184
- `;
2185
-
2186
- if (dryRun) {
2187
- logInfo(`[dry-run] create ${webpackConfigPath}`);
2188
- } else {
2189
- fs.writeFileSync(webpackConfigPath, webpackConfigSource, 'utf8');
2190
- logOk(`Created ${webpackConfigPath}`);
2191
- }
2192
-
2193
- const angularJson = JSON.parse(fs.readFileSync(angularJsonPath, 'utf8'));
2194
- const projects = angularJson.projects ?? {};
2195
- const projectNames = Object.keys(projects);
2196
- if (projectNames.length === 0) {
2197
- logWarn('No Angular projects found in angular.json.');
2198
- return;
2199
- }
2200
-
2201
- const patchPath = 'rsx-angular-webpack.cjs';
2202
- for (const projectName of projectNames) {
2203
- const project = projects[projectName];
2204
- const architect = project.architect ?? project.targets;
2205
- if (!architect?.build) {
2206
- continue;
2207
- }
2208
-
2209
- const build = architect.build;
2210
- if (build.builder !== '@angular-builders/custom-webpack:browser') {
2211
- build.builder = '@angular-builders/custom-webpack:browser';
2212
- }
2213
- build.options = build.options ?? {};
2214
- build.options.customWebpackConfig = build.options.customWebpackConfig ?? {};
2215
- build.options.customWebpackConfig.path = patchPath;
2216
-
2217
- if (architect.serve) {
2218
- const serve = architect.serve;
2219
- if (serve.builder !== '@angular-builders/custom-webpack:dev-server') {
2220
- serve.builder = '@angular-builders/custom-webpack:dev-server';
2221
- }
2222
- serve.options = serve.options ?? {};
2223
- serve.options.buildTarget =
2224
- serve.options.buildTarget ?? `${projectName}:build`;
2225
- serve.options.browserTarget =
2226
- serve.options.browserTarget ?? `${projectName}:build`;
2227
- }
2228
- }
2229
-
2230
- if (dryRun) {
2231
- logInfo(`[dry-run] patch ${angularJsonPath}`);
2232
- } else {
2233
- fs.writeFileSync(
2234
- angularJsonPath,
2235
- `${JSON.stringify(angularJson, null, 2)}\n`,
2236
- 'utf8',
2237
- );
2238
- logOk(`Patched ${angularJsonPath} for RS-X Angular webpack integration.`);
2239
- }
2240
- }
2241
-
2242
2511
  function runSetupReact(flags) {
2243
2512
  const dryRun = Boolean(flags['dry-run']);
2244
2513
  const pm = detectPackageManager(flags.pm);
@@ -2276,9 +2545,6 @@ function runSetupReact(flags) {
2276
2545
  logInfo('Skipping RS-X React bindings install (--skip-install).');
2277
2546
  }
2278
2547
  wireRsxVitePlugin(projectRoot, dryRun);
2279
- if (!Boolean(flags['skip-vscode'])) {
2280
- installVsCodeExtension(flags);
2281
- }
2282
2548
  logOk('RS-X React setup completed.');
2283
2549
  }
2284
2550
 
@@ -2301,9 +2567,6 @@ function runSetupNext(flags) {
2301
2567
  logInfo('Skipping RS-X React bindings install (--skip-install).');
2302
2568
  }
2303
2569
  wireRsxNextWebpack(process.cwd(), dryRun);
2304
- if (!Boolean(flags['skip-vscode'])) {
2305
- installVsCodeExtension(flags);
2306
- }
2307
2570
  logOk('RS-X Next.js setup completed.');
2308
2571
  }
2309
2572
 
@@ -2326,9 +2589,6 @@ function runSetupVue(flags) {
2326
2589
  logInfo('Skipping RS-X Vue bindings install (--skip-install).');
2327
2590
  }
2328
2591
  wireRsxVitePlugin(process.cwd(), dryRun);
2329
- if (!Boolean(flags['skip-vscode'])) {
2330
- installVsCodeExtension(flags);
2331
- }
2332
2592
  logOk('RS-X Vue setup completed.');
2333
2593
  }
2334
2594
 
@@ -2336,47 +2596,58 @@ function runSetupAngular(flags) {
2336
2596
  const dryRun = Boolean(flags['dry-run']);
2337
2597
  const pm = detectPackageManager(flags.pm);
2338
2598
  const tag = resolveInstallTag(flags);
2339
-
2340
- runInit({
2341
- ...flags,
2342
- 'skip-vscode': true,
2343
- });
2599
+ const projectRoot = process.cwd();
2344
2600
 
2345
2601
  if (!Boolean(flags['skip-install'])) {
2602
+ installRuntimePackages(pm, dryRun, tag);
2603
+ installCompilerPackages(pm, dryRun, tag);
2346
2604
  installPackages(pm, ['@rs-x/angular'], {
2347
2605
  dev: false,
2348
2606
  dryRun,
2349
2607
  tag,
2350
2608
  label: 'RS-X Angular bindings',
2351
2609
  });
2352
- installPackages(pm, ['@angular-builders/custom-webpack'], {
2353
- dev: true,
2354
- dryRun,
2355
- label: 'Angular custom webpack builder',
2356
- });
2357
2610
  } else {
2611
+ logInfo('Skipping package installation (--skip-install).');
2612
+ }
2613
+
2614
+ const entryFile = resolveEntryFile(projectRoot, 'angular', flags.entry);
2615
+ if (entryFile) {
2616
+ logInfo(`Using Angular entry file: ${entryFile}`);
2617
+ ensureAngularProvidersInEntry(entryFile, dryRun);
2618
+ } else {
2619
+ logWarn('Could not detect an Angular entry file automatically.');
2358
2620
  logInfo(
2359
- 'Skipping Angular custom webpack builder install (--skip-install).',
2621
+ 'Manual setup: add providexRsx() to bootstrapApplication(...) in your main entry file.',
2360
2622
  );
2361
2623
  }
2362
2624
 
2363
- wireRsxAngularWebpack(process.cwd(), dryRun);
2625
+ upsertRsxBuildConfigInPackageJson(projectRoot, dryRun);
2626
+
2364
2627
  upsertScriptInPackageJson(
2365
- process.cwd(),
2628
+ projectRoot,
2366
2629
  'build:rsx',
2367
- 'rsx build --project tsconfig.json',
2630
+ 'rsx build --project tsconfig.json --no-emit --prod',
2368
2631
  dryRun,
2369
2632
  );
2370
2633
  upsertScriptInPackageJson(
2371
- process.cwd(),
2634
+ projectRoot,
2372
2635
  'typecheck:rsx',
2373
2636
  'rsx typecheck --project tsconfig.json',
2374
2637
  dryRun,
2375
2638
  );
2376
2639
 
2377
- if (!Boolean(flags['skip-vscode'])) {
2378
- installVsCodeExtension(flags);
2379
- }
2640
+ const rsxRegistrationFile = path.join(
2641
+ projectRoot,
2642
+ 'src/rsx-generated/rsx-aot-registration.generated.ts',
2643
+ );
2644
+ ensureAngularPolyfillsContainsFile({
2645
+ projectRoot,
2646
+ configPath: path.join(projectRoot, 'tsconfig.json'),
2647
+ filePath: rsxRegistrationFile,
2648
+ dryRun,
2649
+ });
2650
+
2380
2651
  logOk('RS-X Angular setup completed.');
2381
2652
  }
2382
2653
 
@@ -2413,7 +2684,6 @@ function runSetupAuto(flags) {
2413
2684
  const pm = detectPackageManager(flags.pm);
2414
2685
  installRuntimePackages(pm, Boolean(flags['dry-run']), tag);
2415
2686
  installCompilerPackages(pm, Boolean(flags['dry-run']), tag);
2416
- installVsCodeExtension(flags);
2417
2687
  }
2418
2688
 
2419
2689
  function resolveProjectModule(projectRoot, moduleName) {
@@ -3256,12 +3526,17 @@ function printProjectHelp() {
3256
3526
  console.log('What it does:');
3257
3527
  console.log(' - Creates a new project folder');
3258
3528
  console.log(' - Supports templates: angular, vuejs, react, nextjs, nodejs');
3529
+ console.log(
3530
+ ' - Angular generates the RS-X virtual-table demo starter on top of the latest Angular scaffold',
3531
+ );
3259
3532
  console.log(' - Scaffolds framework app and wires RS-X bootstrap/setup');
3260
3533
  console.log(' - Writes package.json with RS-X dependencies');
3261
3534
  console.log(
3262
3535
  ' - Adds tsconfig + TypeScript plugin config for editor support',
3263
3536
  );
3264
- console.log(' - For Angular template: also installs @rs-x/angular');
3537
+ console.log(
3538
+ ' - For Angular template: uses the latest Angular CLI scaffold, then applies the RS-X demo starter',
3539
+ );
3265
3540
  console.log(' - For React/Next templates: also installs @rs-x/react');
3266
3541
  console.log(' - For Vue template: also installs @rs-x/vue');
3267
3542
  console.log(' - Installs dependencies (unless --skip-install)');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rs-x/cli",
3
- "version": "2.0.0-next.6",
3
+ "version": "2.0.0-next.8",
4
4
  "description": "CLI for installing RS-X compiler tooling and VS Code integration",
5
5
  "bin": {
6
6
  "rsx": "./bin/rsx.cjs"
@@ -8,6 +8,7 @@
8
8
  "files": [
9
9
  "bin",
10
10
  "scripts",
11
+ "templates",
11
12
  "*.vsix",
12
13
  "README.md"
13
14
  ],