@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 +5 -0
- package/bin/rsx.cjs +398 -123
- package/package.json +2 -1
- package/{rs-x-vscode-extension-2.0.0-next.6.vsix → rs-x-vscode-extension-2.0.0-next.8.vsix} +0 -0
- package/templates/angular-demo/README.md +115 -0
- package/templates/angular-demo/src/app/app.component.css +97 -0
- package/templates/angular-demo/src/app/app.component.html +58 -0
- package/templates/angular-demo/src/app/app.component.ts +52 -0
- package/templates/angular-demo/src/app/virtual-table/row-data.ts +35 -0
- package/templates/angular-demo/src/app/virtual-table/row-model.ts +45 -0
- package/templates/angular-demo/src/app/virtual-table/virtual-table-data.service.ts +136 -0
- package/templates/angular-demo/src/app/virtual-table/virtual-table-model.ts +224 -0
- package/templates/angular-demo/src/app/virtual-table/virtual-table.component.css +174 -0
- package/templates/angular-demo/src/app/virtual-table/virtual-table.component.html +50 -0
- package/templates/angular-demo/src/app/virtual-table/virtual-table.component.ts +83 -0
- package/templates/angular-demo/src/index.html +11 -0
- package/templates/angular-demo/src/main.ts +16 -0
- package/templates/angular-demo/src/styles.css +261 -0
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 =
|
|
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
|
-
|
|
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 ${
|
|
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':
|
|
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
|
-
|
|
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
|
-
|
|
1792
|
-
|
|
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
|
-
|
|
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
|
-
'
|
|
2621
|
+
'Manual setup: add providexRsx() to bootstrapApplication(...) in your main entry file.',
|
|
2360
2622
|
);
|
|
2361
2623
|
}
|
|
2362
2624
|
|
|
2363
|
-
|
|
2625
|
+
upsertRsxBuildConfigInPackageJson(projectRoot, dryRun);
|
|
2626
|
+
|
|
2364
2627
|
upsertScriptInPackageJson(
|
|
2365
|
-
|
|
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
|
-
|
|
2634
|
+
projectRoot,
|
|
2372
2635
|
'typecheck:rsx',
|
|
2373
2636
|
'rsx typecheck --project tsconfig.json',
|
|
2374
2637
|
dryRun,
|
|
2375
2638
|
);
|
|
2376
2639
|
|
|
2377
|
-
|
|
2378
|
-
|
|
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(
|
|
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.
|
|
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
|
],
|