create-krispya 0.12.0 → 0.14.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/dist/cli.cjs +484 -190
- package/dist/cli.d.cts +2 -2
- package/dist/cli.d.mts +2 -2
- package/dist/cli.d.ts +2 -2
- package/dist/cli.mjs +491 -196
- package/dist/index.cjs +39 -1
- package/dist/index.d.cts +127 -7
- package/dist/index.d.mts +127 -7
- package/dist/index.d.ts +127 -7
- package/dist/index.mjs +2 -1
- package/dist/shared/{create-krispya.CcQTepKu.d.cts → create-krispya.8Jt7v_KA.d.cts} +1 -1
- package/dist/shared/{create-krispya.CcQTepKu.d.mts → create-krispya.8Jt7v_KA.d.mts} +1 -1
- package/dist/shared/{create-krispya.CcQTepKu.d.ts → create-krispya.8Jt7v_KA.d.ts} +1 -1
- package/dist/shared/{create-krispya.DZWMfM2v.mjs → create-krispya.BYCdQkPo.mjs} +667 -382
- package/dist/shared/{create-krispya.FNrYi_5V.cjs → create-krispya.Wf4wp5cQ.cjs} +697 -381
- package/package.json +16 -16
package/dist/cli.mjs
CHANGED
|
@@ -2,17 +2,18 @@
|
|
|
2
2
|
import * as p from '@clack/prompts';
|
|
3
3
|
import color from 'chalk';
|
|
4
4
|
import { Command } from 'commander';
|
|
5
|
-
import { access
|
|
5
|
+
import { access, readFile, writeFile, readdir, mkdir, unlink } from 'node:fs/promises';
|
|
6
6
|
import { createRequire } from 'node:module';
|
|
7
|
-
import { resolve, join
|
|
7
|
+
import { resolve, join, dirname } from 'node:path';
|
|
8
8
|
import { cwd } from 'node:process';
|
|
9
9
|
import { fetch } from 'undici';
|
|
10
|
-
import {
|
|
11
|
-
import
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
10
|
+
import { g as getEngineName, a as getPackageManagerName, b as getBaseTemplate, s as shouldEnableReactCompiler, c as getLanguageFromTemplate, d as generateRandomName, e as getConfigStrategy, f as getAiPlatforms, A as ALL_AI_PLATFORMS, h as AI_PLATFORM_LABELS, i as AI_PLATFORM_HINTS, j as detectTooling, p as parsePackageManagerSpec, k as parseEngine, l as parseWorkspaceYamlContent, v as validateWorkspace, r as renderTypescriptConfigPackage, m as renderOxlintConfigPackage, n as renderEslintConfigPackage, o as renderOxfmtConfigPackage, q as renderPrettierConfigPackage, t as resolveMonorepoRootPackageVersions, u as getResolvedPackageVersion, w as renderVscodeFiles, x as renderAiFiles, y as renderVscodeFiles$1, z as renderEditorConfig, B as renderGitignore, C as toPrettierIgnoreContent, D as mergePackageJsonScripts, E as getPackageManagerProfile, F as renderPnpmWorkspaceConfig, G as renderViteConfig, H as packageJsonScripts, I as resolveDefaultPackageJsonScripts, J as formatResolvedPackageVersion, K as getSemverMajorString, L as formatPackageManager, M as renderOxlintConfig, N as resolvePackageManager, O as getSemverMajor, P as compareNumericSemver, Q as getPackageDirectoryName, R as planProject, S as resolveProjectPlanInput, T as validatePackageName, U as clearConfig, V as getConfigPath, W as resolveWorkspacePlanInput, X as planWorkspace } from './shared/create-krispya.BYCdQkPo.mjs';
|
|
11
|
+
import { readFile as readFile$1, mkdir as mkdir$1, writeFile as writeFile$1, access as access$1 } from 'fs/promises';
|
|
12
|
+
import { constants as constants$1 } from 'fs';
|
|
13
|
+
import { join as join$1, dirname as dirname$1 } from 'path';
|
|
14
|
+
import { constants } from 'node:fs';
|
|
15
|
+
import { spawn } from 'node:child_process';
|
|
16
|
+
import 'conf';
|
|
16
17
|
|
|
17
18
|
function formatConfigSummary(options, inherited) {
|
|
18
19
|
const lines = [];
|
|
@@ -30,8 +31,9 @@ function formatConfigSummary(options, inherited) {
|
|
|
30
31
|
const projectType = options.projectType ?? "app";
|
|
31
32
|
const baseTemplate = options.template ? getBaseTemplate(options.template) : "vanilla";
|
|
32
33
|
if (baseTemplate === "react") {
|
|
33
|
-
lines.push(
|
|
34
|
-
|
|
34
|
+
lines.push(
|
|
35
|
+
formatRow("Framework", shouldEnableReactCompiler(options) ? "React + compiler" : "React")
|
|
36
|
+
);
|
|
35
37
|
} else if (baseTemplate === "r3f") {
|
|
36
38
|
lines.push(formatRow("Framework", "React Three Fiber"));
|
|
37
39
|
}
|
|
@@ -112,8 +114,9 @@ function formatMonorepoConfigSummary(options) {
|
|
|
112
114
|
lines.push(
|
|
113
115
|
formatRow("Engine", `${getEngineName(options.engine)}@${options.engine.version ?? "latest"}`)
|
|
114
116
|
);
|
|
115
|
-
|
|
116
|
-
|
|
117
|
+
const packageManagerName = getPackageManagerName(options.packageManager);
|
|
118
|
+
lines.push(formatRow("Package manager", packageManagerName));
|
|
119
|
+
if (packageManagerName === "pnpm") {
|
|
117
120
|
const versionManaged = options.pnpmManageVersions ? "yes" : "no";
|
|
118
121
|
lines.push(formatRow("\u21B3 Version managed", versionManaged, ""));
|
|
119
122
|
}
|
|
@@ -123,22 +126,6 @@ function formatMonorepoConfigSummary(options) {
|
|
|
123
126
|
return lines.join("\n");
|
|
124
127
|
}
|
|
125
128
|
|
|
126
|
-
const config = new Conf({
|
|
127
|
-
projectName: "create-krispya"
|
|
128
|
-
});
|
|
129
|
-
function getAiPlatforms() {
|
|
130
|
-
return config.get("aiPlatforms");
|
|
131
|
-
}
|
|
132
|
-
function getConfigStrategy() {
|
|
133
|
-
return config.get("configStrategy") ?? "stealth";
|
|
134
|
-
}
|
|
135
|
-
function clearConfig() {
|
|
136
|
-
config.clear();
|
|
137
|
-
}
|
|
138
|
-
function getConfigPath() {
|
|
139
|
-
return config.path;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
129
|
const R3F_INTEGRATION_OPTIONS = [
|
|
143
130
|
{ value: "drei", label: "Drei" },
|
|
144
131
|
{ value: "handle", label: "Handle" },
|
|
@@ -252,7 +239,7 @@ async function promptForCustomization(template, name, projectType, features, inh
|
|
|
252
239
|
libraryBundler = bundler;
|
|
253
240
|
}
|
|
254
241
|
let engine = inheritedSettings?.engine ?? presets?.engine ?? { name: "node", version: "latest" };
|
|
255
|
-
let finalPackageManager = inheritedSettings?.packageManager?.name ?? presets?.packageManager ?? "pnpm";
|
|
242
|
+
let finalPackageManager = inheritedSettings?.packageManager?.name ?? presets?.packageManager?.name ?? "pnpm";
|
|
256
243
|
let pnpmManageVersions = inheritedSettings?.pnpmManageVersions ?? presets?.pnpmManageVersions ?? true;
|
|
257
244
|
if (!inheritedSettings?.engine?.version) {
|
|
258
245
|
const nodeVersionInput = await p.text({
|
|
@@ -260,7 +247,7 @@ async function promptForCustomization(template, name, projectType, features, inh
|
|
|
260
247
|
placeholder: presets?.engine?.version ?? "latest",
|
|
261
248
|
defaultValue: presets?.engine?.version ?? "latest",
|
|
262
249
|
validate: (value) => {
|
|
263
|
-
if (!value
|
|
250
|
+
if (!value?.length) return "Required";
|
|
264
251
|
if (value !== "latest" && !/^\d+(\.\d+(\.\d+)?)?$/.test(value)) {
|
|
265
252
|
return 'Must be "latest" or a valid semver (e.g., "22" or "22.13.0")';
|
|
266
253
|
}
|
|
@@ -280,7 +267,7 @@ async function promptForCustomization(template, name, projectType, features, inh
|
|
|
280
267
|
{ value: "npm", label: "npm" },
|
|
281
268
|
{ value: "yarn", label: "yarn" }
|
|
282
269
|
],
|
|
283
|
-
initialValue: presets?.packageManager ?? "pnpm"
|
|
270
|
+
initialValue: presets?.packageManager?.name ?? "pnpm"
|
|
284
271
|
});
|
|
285
272
|
if (p.isCancel(packageManager)) {
|
|
286
273
|
p.cancel("Operation cancelled.");
|
|
@@ -389,7 +376,7 @@ async function promptForCustomization(template, name, projectType, features, inh
|
|
|
389
376
|
projectType,
|
|
390
377
|
libraryBundler: projectType === "library" ? libraryBundler : void 0,
|
|
391
378
|
engine,
|
|
392
|
-
packageManager: { name: finalPackageManager },
|
|
379
|
+
packageManager: presets?.packageManager?.name === finalPackageManager ? presets.packageManager : { name: finalPackageManager },
|
|
393
380
|
pnpmManageVersions,
|
|
394
381
|
linter,
|
|
395
382
|
formatter,
|
|
@@ -436,7 +423,7 @@ async function promptForMonorepoCustomization(name, presets) {
|
|
|
436
423
|
placeholder: presets?.engine?.version ?? "latest",
|
|
437
424
|
defaultValue: presets?.engine?.version ?? "latest",
|
|
438
425
|
validate: (value) => {
|
|
439
|
-
if (!value
|
|
426
|
+
if (!value?.length) return "Required";
|
|
440
427
|
if (value !== "latest" && !/^\d+(\.\d+(\.\d+)?)?$/.test(value)) {
|
|
441
428
|
return 'Must be "latest" or a valid semver (e.g., "22" or "22.13.0")';
|
|
442
429
|
}
|
|
@@ -517,7 +504,7 @@ async function promptForMonorepo(workspaceName, presets) {
|
|
|
517
504
|
formatMonorepoConfigSummary({
|
|
518
505
|
name: defaultOptions.name,
|
|
519
506
|
engine: defaultOptions.engine ?? { name: "node", version: "latest" },
|
|
520
|
-
packageManager:
|
|
507
|
+
packageManager: defaultOptions.packageManager ?? { name: "pnpm" },
|
|
521
508
|
pnpmManageVersions: defaultOptions.pnpmManageVersions,
|
|
522
509
|
linter: defaultOptions.linter ?? "oxlint",
|
|
523
510
|
formatter: defaultOptions.formatter ?? "prettier",
|
|
@@ -538,7 +525,7 @@ async function promptForOptions(name, presets) {
|
|
|
538
525
|
placeholder: generateRandomName(),
|
|
539
526
|
defaultValue: generateRandomName(),
|
|
540
527
|
validate: (value) => {
|
|
541
|
-
if (!value
|
|
528
|
+
if (!value?.length) return "Project name is required";
|
|
542
529
|
}
|
|
543
530
|
});
|
|
544
531
|
if (p.isCancel(nameResult)) {
|
|
@@ -570,7 +557,7 @@ function presetsToInheritedSettings(presets) {
|
|
|
570
557
|
return {
|
|
571
558
|
linter: presets.linter,
|
|
572
559
|
formatter: presets.formatter,
|
|
573
|
-
packageManager: presets.packageManager
|
|
560
|
+
packageManager: presets.packageManager,
|
|
574
561
|
engine: presets.engine,
|
|
575
562
|
pnpmManageVersions: presets.pnpmManageVersions
|
|
576
563
|
};
|
|
@@ -655,54 +642,9 @@ async function promptForAiAgentPlatforms(isNonInteractive) {
|
|
|
655
642
|
return selected;
|
|
656
643
|
}
|
|
657
644
|
|
|
658
|
-
async function checkAnyExists(paths) {
|
|
659
|
-
for (const path of paths) {
|
|
660
|
-
try {
|
|
661
|
-
await access(path, constants.F_OK);
|
|
662
|
-
return true;
|
|
663
|
-
} catch {
|
|
664
|
-
}
|
|
665
|
-
}
|
|
666
|
-
return false;
|
|
667
|
-
}
|
|
668
|
-
async function validateWorkspace(monorepoRoot) {
|
|
669
|
-
const errors = [];
|
|
670
|
-
const tsConfigPath = join(monorepoRoot, ".config/typescript/package.json");
|
|
671
|
-
try {
|
|
672
|
-
await access(tsConfigPath, constants.F_OK);
|
|
673
|
-
} catch {
|
|
674
|
-
errors.push("Missing .config/typescript package");
|
|
675
|
-
}
|
|
676
|
-
const linterPaths = [
|
|
677
|
-
join(monorepoRoot, ".config/oxlint/package.json"),
|
|
678
|
-
join(monorepoRoot, ".config/eslint/package.json"),
|
|
679
|
-
join(monorepoRoot, "eslint.config.js"),
|
|
680
|
-
join(monorepoRoot, "biome.json")
|
|
681
|
-
];
|
|
682
|
-
const hasLinter = await checkAnyExists(linterPaths);
|
|
683
|
-
if (!hasLinter) {
|
|
684
|
-
errors.push(
|
|
685
|
-
"Missing linter config (.config/oxlint, .config/eslint, eslint.config.js, or biome.json)"
|
|
686
|
-
);
|
|
687
|
-
}
|
|
688
|
-
const formatterPaths = [
|
|
689
|
-
join(monorepoRoot, ".config/oxfmt/package.json"),
|
|
690
|
-
join(monorepoRoot, ".config/prettier/package.json"),
|
|
691
|
-
join(monorepoRoot, ".prettierrc.json"),
|
|
692
|
-
join(monorepoRoot, "biome.json")
|
|
693
|
-
];
|
|
694
|
-
const hasFormatter = await checkAnyExists(formatterPaths);
|
|
695
|
-
if (!hasFormatter) {
|
|
696
|
-
errors.push(
|
|
697
|
-
"Missing formatter config (.config/oxfmt, .config/prettier, .prettierrc.json, or biome.json)"
|
|
698
|
-
);
|
|
699
|
-
}
|
|
700
|
-
return { valid: errors.length === 0, errors };
|
|
701
|
-
}
|
|
702
|
-
|
|
703
645
|
async function fileExists$1(path) {
|
|
704
646
|
try {
|
|
705
|
-
await access
|
|
647
|
+
await access(path, constants.F_OK);
|
|
706
648
|
return true;
|
|
707
649
|
} catch {
|
|
708
650
|
return false;
|
|
@@ -716,9 +658,9 @@ async function detectMonorepoRoot() {
|
|
|
716
658
|
let currentDir = cwd();
|
|
717
659
|
const root = resolve("/");
|
|
718
660
|
while (currentDir !== root) {
|
|
719
|
-
const workspaceFile = join
|
|
661
|
+
const workspaceFile = join(currentDir, "pnpm-workspace.yaml");
|
|
720
662
|
try {
|
|
721
|
-
await access
|
|
663
|
+
await access(workspaceFile, constants.F_OK);
|
|
722
664
|
const content = await readFile(workspaceFile, "utf-8");
|
|
723
665
|
if (content.includes("packages:")) {
|
|
724
666
|
return currentDir;
|
|
@@ -733,16 +675,16 @@ async function detectPackageRoot() {
|
|
|
733
675
|
let currentDir = cwd();
|
|
734
676
|
const root = resolve("/");
|
|
735
677
|
while (currentDir !== root) {
|
|
736
|
-
if (await fileExists$1(join
|
|
678
|
+
if (await fileExists$1(join(currentDir, "package.json"))) {
|
|
737
679
|
return currentDir;
|
|
738
680
|
}
|
|
739
681
|
currentDir = dirname(currentDir);
|
|
740
682
|
}
|
|
741
|
-
return await fileExists$1(join
|
|
683
|
+
return await fileExists$1(join(root, "package.json")) ? root : null;
|
|
742
684
|
}
|
|
743
685
|
async function parseWorkspaceDirectories(monorepoRoot) {
|
|
744
686
|
try {
|
|
745
|
-
const workspaceFile = join
|
|
687
|
+
const workspaceFile = join(monorepoRoot, "pnpm-workspace.yaml");
|
|
746
688
|
const content = await readFile(workspaceFile, "utf-8");
|
|
747
689
|
return parseWorkspaceYamlContent(content);
|
|
748
690
|
} catch {
|
|
@@ -752,14 +694,14 @@ async function parseWorkspaceDirectories(monorepoRoot) {
|
|
|
752
694
|
async function detectWorkspaceSettings(monorepoRoot) {
|
|
753
695
|
try {
|
|
754
696
|
const tooling = await detectTooling(monorepoRoot);
|
|
755
|
-
const pkgPath = join
|
|
697
|
+
const pkgPath = join(monorepoRoot, "package.json");
|
|
756
698
|
const content = await readFile(pkgPath, "utf-8");
|
|
757
699
|
const pkgJson = JSON.parse(content);
|
|
758
|
-
const packageManager =
|
|
700
|
+
const packageManager = parsePackageManagerSpec(pkgJson.packageManager);
|
|
759
701
|
const engine = parseEngine(pkgJson.engines);
|
|
760
702
|
let pnpmManageVersions;
|
|
761
703
|
try {
|
|
762
|
-
const workspaceFile = join
|
|
704
|
+
const workspaceFile = join(monorepoRoot, "pnpm-workspace.yaml");
|
|
763
705
|
const workspaceContent = await readFile(workspaceFile, "utf-8");
|
|
764
706
|
pnpmManageVersions = workspaceContent.includes("manage-package-manager-versions: true");
|
|
765
707
|
} catch {
|
|
@@ -777,17 +719,17 @@ async function detectWorkspaceSettings(monorepoRoot) {
|
|
|
777
719
|
}
|
|
778
720
|
async function detectExistingConfigs(monorepoRoot) {
|
|
779
721
|
const configs = {};
|
|
780
|
-
const eslintPath = join
|
|
722
|
+
const eslintPath = join(monorepoRoot, "eslint.config.js");
|
|
781
723
|
if (await fileExists$1(eslintPath)) {
|
|
782
724
|
configs.linter = "eslint";
|
|
783
725
|
configs.eslintConfigPath = eslintPath;
|
|
784
726
|
}
|
|
785
|
-
const prettierPath = join
|
|
727
|
+
const prettierPath = join(monorepoRoot, ".prettierrc.json");
|
|
786
728
|
if (await fileExists$1(prettierPath)) {
|
|
787
729
|
configs.formatter = "prettier";
|
|
788
730
|
configs.prettierConfigPath = prettierPath;
|
|
789
731
|
}
|
|
790
|
-
const biomePath = join
|
|
732
|
+
const biomePath = join(monorepoRoot, "biome.json");
|
|
791
733
|
if (await fileExists$1(biomePath)) {
|
|
792
734
|
configs.biomeConfigPath = biomePath;
|
|
793
735
|
if (!configs.linter) configs.linter = "biome";
|
|
@@ -797,7 +739,7 @@ async function detectExistingConfigs(monorepoRoot) {
|
|
|
797
739
|
}
|
|
798
740
|
async function getMonorepoScope(monorepoRoot) {
|
|
799
741
|
try {
|
|
800
|
-
const pkgPath = join
|
|
742
|
+
const pkgPath = join(monorepoRoot, "package.json");
|
|
801
743
|
const content = await readFile(pkgPath, "utf-8");
|
|
802
744
|
const pkgJson = JSON.parse(content);
|
|
803
745
|
if (pkgJson.name) {
|
|
@@ -808,14 +750,14 @@ async function getMonorepoScope(monorepoRoot) {
|
|
|
808
750
|
return monorepoRoot.split(/[/\\]/).pop() ?? "workspace";
|
|
809
751
|
}
|
|
810
752
|
async function getWorkspacePackages(monorepoRoot) {
|
|
811
|
-
const packagesDir = join
|
|
753
|
+
const packagesDir = join(monorepoRoot, "packages");
|
|
812
754
|
try {
|
|
813
755
|
const entries = await readdir(packagesDir, { withFileTypes: true });
|
|
814
756
|
const names = [];
|
|
815
757
|
for (const entry of entries) {
|
|
816
758
|
if (!entry.isDirectory()) continue;
|
|
817
759
|
try {
|
|
818
|
-
const content = await readFile(join
|
|
760
|
+
const content = await readFile(join(packagesDir, entry.name, "package.json"), "utf-8");
|
|
819
761
|
const pkg = JSON.parse(content);
|
|
820
762
|
if (pkg.name) names.push(pkg.name);
|
|
821
763
|
} catch {
|
|
@@ -827,7 +769,7 @@ async function getWorkspacePackages(monorepoRoot) {
|
|
|
827
769
|
}
|
|
828
770
|
}
|
|
829
771
|
async function ensureConfigInWorkspace(monorepoRoot) {
|
|
830
|
-
const workspacePath = join
|
|
772
|
+
const workspacePath = join(monorepoRoot, "pnpm-workspace.yaml");
|
|
831
773
|
let content;
|
|
832
774
|
try {
|
|
833
775
|
content = await readFile(workspacePath, "utf-8");
|
|
@@ -877,7 +819,7 @@ async function handleCheckCommand() {
|
|
|
877
819
|
|
|
878
820
|
async function migrateEslintConfig(monorepoRoot, files) {
|
|
879
821
|
const configBasePath = ".config/eslint";
|
|
880
|
-
const existingConfigPath = join
|
|
822
|
+
const existingConfigPath = join(monorepoRoot, "eslint.config.js");
|
|
881
823
|
let existingContent;
|
|
882
824
|
try {
|
|
883
825
|
existingContent = await readFile(existingConfigPath, "utf-8");
|
|
@@ -956,7 +898,7 @@ export default [
|
|
|
956
898
|
}
|
|
957
899
|
async function migratePrettierConfig(monorepoRoot, files) {
|
|
958
900
|
const configBasePath = ".config/prettier";
|
|
959
|
-
const existingConfigPath = join
|
|
901
|
+
const existingConfigPath = join(monorepoRoot, ".prettierrc.json");
|
|
960
902
|
let existingContent;
|
|
961
903
|
try {
|
|
962
904
|
existingContent = await readFile(existingConfigPath, "utf-8");
|
|
@@ -1092,15 +1034,15 @@ async function handleFixCommand(options) {
|
|
|
1092
1034
|
spinner.start("Fixing workspace...");
|
|
1093
1035
|
try {
|
|
1094
1036
|
const files = {};
|
|
1095
|
-
const tsConfigExists = await fileExists$1(join
|
|
1037
|
+
const tsConfigExists = await fileExists$1(join(monorepoRoot, ".config/typescript/package.json"));
|
|
1096
1038
|
if (!tsConfigExists) {
|
|
1097
1039
|
renderTypescriptConfigPackage(files);
|
|
1098
1040
|
}
|
|
1099
1041
|
if (linter === "oxlint") {
|
|
1100
|
-
const oxlintExists = await fileExists$1(join
|
|
1042
|
+
const oxlintExists = await fileExists$1(join(monorepoRoot, ".config/oxlint/package.json"));
|
|
1101
1043
|
if (!oxlintExists) renderOxlintConfigPackage(files);
|
|
1102
1044
|
} else if (linter === "eslint") {
|
|
1103
|
-
const eslintPkgExists = await fileExists$1(join
|
|
1045
|
+
const eslintPkgExists = await fileExists$1(join(monorepoRoot, ".config/eslint/package.json"));
|
|
1104
1046
|
if (!eslintPkgExists) {
|
|
1105
1047
|
if (existingConfigs.eslintConfigPath) {
|
|
1106
1048
|
await migrateEslintConfig(monorepoRoot, files);
|
|
@@ -1110,10 +1052,10 @@ async function handleFixCommand(options) {
|
|
|
1110
1052
|
}
|
|
1111
1053
|
}
|
|
1112
1054
|
if (formatter === "oxfmt") {
|
|
1113
|
-
const oxfmtExists = await fileExists$1(join
|
|
1055
|
+
const oxfmtExists = await fileExists$1(join(monorepoRoot, ".config/oxfmt/package.json"));
|
|
1114
1056
|
if (!oxfmtExists) renderOxfmtConfigPackage(files);
|
|
1115
1057
|
} else if (formatter === "prettier") {
|
|
1116
|
-
const prettierPkgExists = await fileExists$1(join
|
|
1058
|
+
const prettierPkgExists = await fileExists$1(join(monorepoRoot, ".config/prettier/package.json"));
|
|
1117
1059
|
if (!prettierPkgExists) {
|
|
1118
1060
|
if (existingConfigs.prettierConfigPath) {
|
|
1119
1061
|
await migratePrettierConfig(monorepoRoot, files);
|
|
@@ -1151,7 +1093,7 @@ async function handleFixCommand(options) {
|
|
|
1151
1093
|
};
|
|
1152
1094
|
}
|
|
1153
1095
|
for (const [filePath, file] of Object.entries(files)) {
|
|
1154
|
-
const fullPath = join
|
|
1096
|
+
const fullPath = join(monorepoRoot, filePath);
|
|
1155
1097
|
await mkdir(dirname(fullPath), { recursive: true });
|
|
1156
1098
|
await writeFile(fullPath, file.content);
|
|
1157
1099
|
}
|
|
@@ -1174,8 +1116,8 @@ async function handleFixCommand(options) {
|
|
|
1174
1116
|
const pkgName = pkgFile.replace("/package.json", "");
|
|
1175
1117
|
console.log(color.dim(` Generated ${pkgName}`));
|
|
1176
1118
|
}
|
|
1177
|
-
const vscodeSettingsExists = await fileExists$1(join
|
|
1178
|
-
const vscodeExtensionsExists = await fileExists$1(join
|
|
1119
|
+
const vscodeSettingsExists = await fileExists$1(join(monorepoRoot, ".vscode/settings.json"));
|
|
1120
|
+
const vscodeExtensionsExists = await fileExists$1(join(monorepoRoot, ".vscode/extensions.json"));
|
|
1179
1121
|
const vscodeExists = vscodeSettingsExists && vscodeExtensionsExists;
|
|
1180
1122
|
if (!vscodeExists) {
|
|
1181
1123
|
let addVscode = false;
|
|
@@ -1192,7 +1134,7 @@ async function handleFixCommand(options) {
|
|
|
1192
1134
|
const vscodeFiles = {};
|
|
1193
1135
|
renderVscodeFiles(vscodeFiles, linter, formatter);
|
|
1194
1136
|
for (const [filePath, file] of Object.entries(vscodeFiles)) {
|
|
1195
|
-
const fullPath = join
|
|
1137
|
+
const fullPath = join(monorepoRoot, filePath);
|
|
1196
1138
|
await mkdir(dirname(fullPath), { recursive: true });
|
|
1197
1139
|
await writeFile(fullPath, file.content);
|
|
1198
1140
|
}
|
|
@@ -1200,7 +1142,7 @@ async function handleFixCommand(options) {
|
|
|
1200
1142
|
console.log(color.dim(" Generated .vscode/extensions.json"));
|
|
1201
1143
|
}
|
|
1202
1144
|
}
|
|
1203
|
-
const aiRulesExist = await fileExists$1(join
|
|
1145
|
+
const aiRulesExist = await fileExists$1(join(monorepoRoot, ".ai/workspace.md"));
|
|
1204
1146
|
if (!aiRulesExist) {
|
|
1205
1147
|
const platforms = await promptForAiAgentPlatforms(isNonInteractive);
|
|
1206
1148
|
if (platforms.length > 0) {
|
|
@@ -1216,7 +1158,7 @@ async function handleFixCommand(options) {
|
|
|
1216
1158
|
platforms
|
|
1217
1159
|
});
|
|
1218
1160
|
for (const [filePath, file] of Object.entries(aiFilesOutput)) {
|
|
1219
|
-
const fullPath = join
|
|
1161
|
+
const fullPath = join(monorepoRoot, filePath);
|
|
1220
1162
|
await mkdir(dirname(fullPath), { recursive: true });
|
|
1221
1163
|
await writeFile(fullPath, file.content);
|
|
1222
1164
|
console.log(color.dim(` Generated ${filePath}`));
|
|
@@ -1260,18 +1202,22 @@ function renderExpectedViteConfig(template) {
|
|
|
1260
1202
|
async function detectCurrentConfig(root, isMonorepo = true) {
|
|
1261
1203
|
let name = root.split(/[/\\]/).pop() ?? "workspace";
|
|
1262
1204
|
let packageManager = "pnpm";
|
|
1205
|
+
let packageManagerSpec = { name: "pnpm" };
|
|
1206
|
+
let engine;
|
|
1263
1207
|
let hasTypecheck = false;
|
|
1264
1208
|
let viteTemplate;
|
|
1265
1209
|
try {
|
|
1266
|
-
const pkgPath = join(root, "package.json");
|
|
1210
|
+
const pkgPath = join$1(root, "package.json");
|
|
1267
1211
|
const content = await readFile$1(pkgPath, "utf-8");
|
|
1268
1212
|
const pkgJson = JSON.parse(content);
|
|
1269
1213
|
if (pkgJson.name) {
|
|
1270
1214
|
name = pkgJson.name.replace(/^@/, "").replace(/\/.*$/, "");
|
|
1271
1215
|
}
|
|
1272
1216
|
if (pkgJson.packageManager) {
|
|
1273
|
-
|
|
1217
|
+
packageManagerSpec = parsePackageManagerSpec(pkgJson.packageManager) ?? packageManagerSpec;
|
|
1218
|
+
packageManager = packageManagerSpec.name;
|
|
1274
1219
|
}
|
|
1220
|
+
engine = parseEngine(pkgJson.engines);
|
|
1275
1221
|
hasTypecheck = pkgJson.scripts?.typecheck != null;
|
|
1276
1222
|
viteTemplate = detectViteTemplate(pkgJson);
|
|
1277
1223
|
} catch {
|
|
@@ -1283,6 +1229,8 @@ async function detectCurrentConfig(root, isMonorepo = true) {
|
|
|
1283
1229
|
linter: tooling.linter ?? "oxlint",
|
|
1284
1230
|
formatter: tooling.formatter ?? "prettier",
|
|
1285
1231
|
packageManager,
|
|
1232
|
+
packageManagerSpec,
|
|
1233
|
+
engine,
|
|
1286
1234
|
isMonorepo,
|
|
1287
1235
|
configStrategy,
|
|
1288
1236
|
hasTypecheck,
|
|
@@ -1291,10 +1239,10 @@ async function detectCurrentConfig(root, isMonorepo = true) {
|
|
|
1291
1239
|
}
|
|
1292
1240
|
async function detectSinglePackageConfigStrategy(root) {
|
|
1293
1241
|
const hasStealthConfig = await Promise.all([
|
|
1294
|
-
fileExists(join(root, ".config/tsconfig.app.json")),
|
|
1295
|
-
fileExists(join(root, ".config/tsconfig.node.json")),
|
|
1296
|
-
fileExists(join(root, ".config/prettier.json")),
|
|
1297
|
-
fileExists(join(root, ".config/oxlint.json"))
|
|
1242
|
+
fileExists(join$1(root, ".config/tsconfig.app.json")),
|
|
1243
|
+
fileExists(join$1(root, ".config/tsconfig.node.json")),
|
|
1244
|
+
fileExists(join$1(root, ".config/prettier.json")),
|
|
1245
|
+
fileExists(join$1(root, ".config/oxlint.json"))
|
|
1298
1246
|
]).then((matches) => matches.some(Boolean));
|
|
1299
1247
|
return hasStealthConfig ? "stealth" : "root";
|
|
1300
1248
|
}
|
|
@@ -1389,7 +1337,7 @@ async function planExpectedFiles(config) {
|
|
|
1389
1337
|
}
|
|
1390
1338
|
async function fileExists(path) {
|
|
1391
1339
|
try {
|
|
1392
|
-
await access(path, constants$
|
|
1340
|
+
await access$1(path, constants$1.F_OK);
|
|
1393
1341
|
return true;
|
|
1394
1342
|
} catch {
|
|
1395
1343
|
return false;
|
|
@@ -1528,7 +1476,7 @@ async function compareWithDisk(expected, root) {
|
|
|
1528
1476
|
const changes = [];
|
|
1529
1477
|
for (const [filePath, file] of Object.entries(files)) {
|
|
1530
1478
|
if (file.type !== "text") continue;
|
|
1531
|
-
const fullPath = join(root, filePath);
|
|
1479
|
+
const fullPath = join$1(root, filePath);
|
|
1532
1480
|
const newContent = file.content;
|
|
1533
1481
|
if (await fileExists(fullPath)) {
|
|
1534
1482
|
const currentContent = await readFile$1(fullPath, "utf-8");
|
|
@@ -1603,13 +1551,13 @@ function addMissingDevDependency(pkg, devDependencies, name) {
|
|
|
1603
1551
|
}
|
|
1604
1552
|
async function detectTypeScriptPackage(root, pkg) {
|
|
1605
1553
|
if (hasPackage(pkg, "typescript")) return true;
|
|
1606
|
-
return await fileExists(join(root, "tsconfig.json")) || await fileExists(join(root, "tsconfig.app.json")) || await fileExists(join(root, ".config/tsconfig.app.json"));
|
|
1554
|
+
return await fileExists(join$1(root, "tsconfig.json")) || await fileExists(join$1(root, "tsconfig.app.json")) || await fileExists(join$1(root, ".config/tsconfig.app.json"));
|
|
1607
1555
|
}
|
|
1608
1556
|
function detectLibraryPackage(pkg) {
|
|
1609
1557
|
return pkg.exports != null || pkg.main?.includes("dist") === true || pkg.module?.includes("dist") === true || Array.isArray(pkg.files) && pkg.files.includes("dist");
|
|
1610
1558
|
}
|
|
1611
1559
|
function getPackageManagerForScripts(config, pkg) {
|
|
1612
|
-
const packageManager = pkg.packageManager?.
|
|
1560
|
+
const packageManager = parsePackageManagerSpec(pkg.packageManager)?.name ?? config.packageManager;
|
|
1613
1561
|
return isPackageManagerName(packageManager) ? packageManager : "pnpm";
|
|
1614
1562
|
}
|
|
1615
1563
|
function getSinglePackageToolScripts(config) {
|
|
@@ -1639,6 +1587,35 @@ function scriptsEqual(left, right) {
|
|
|
1639
1587
|
if (leftEntries.length !== Object.keys(right).length) return false;
|
|
1640
1588
|
return leftEntries.every(([key, value]) => right[key] === value);
|
|
1641
1589
|
}
|
|
1590
|
+
function packageManagerFieldsEqual(pkg, packageManagerSpec, targetNodeVersion) {
|
|
1591
|
+
if (packageManagerSpec == null || packageManagerSpec.version == null) {
|
|
1592
|
+
return targetNodeVersion == null || pkg.engines?.node === `>=${targetNodeVersion}`;
|
|
1593
|
+
}
|
|
1594
|
+
const majorVersion = getSemverMajorString(packageManagerSpec.version);
|
|
1595
|
+
return pkg.packageManager === formatPackageManager(packageManagerSpec) && pkg.engines?.[packageManagerSpec.name] === `>=${majorVersion}.0.0` && (targetNodeVersion == null || pkg.engines?.node === `>=${targetNodeVersion}`);
|
|
1596
|
+
}
|
|
1597
|
+
function applyPackageManagerFields(pkg, packageManagerSpec, targetNodeVersion) {
|
|
1598
|
+
if (packageManagerSpec == null || packageManagerSpec.version == null) {
|
|
1599
|
+
if (targetNodeVersion == null) return pkg;
|
|
1600
|
+
return {
|
|
1601
|
+
...pkg,
|
|
1602
|
+
engines: {
|
|
1603
|
+
...pkg.engines,
|
|
1604
|
+
node: `>=${targetNodeVersion}`
|
|
1605
|
+
}
|
|
1606
|
+
};
|
|
1607
|
+
}
|
|
1608
|
+
const majorVersion = getSemverMajorString(packageManagerSpec.version);
|
|
1609
|
+
return {
|
|
1610
|
+
...pkg,
|
|
1611
|
+
packageManager: formatPackageManager(packageManagerSpec),
|
|
1612
|
+
engines: {
|
|
1613
|
+
...pkg.engines,
|
|
1614
|
+
[packageManagerSpec.name]: `>=${majorVersion}.0.0`,
|
|
1615
|
+
...targetNodeVersion == null ? {} : { node: `>=${targetNodeVersion}` }
|
|
1616
|
+
}
|
|
1617
|
+
};
|
|
1618
|
+
}
|
|
1642
1619
|
async function getExpectedPackageScripts(root, config, pkg) {
|
|
1643
1620
|
if (config.isMonorepo) {
|
|
1644
1621
|
return packageJsonScripts.monorepoRoot(config.linter, config.formatter);
|
|
@@ -1667,6 +1644,9 @@ async function getExpectedPackageDevDependencies(root, config, pkg) {
|
|
|
1667
1644
|
addMissingDevDependency(pkg, nextDevDependencies, "@babel/core");
|
|
1668
1645
|
addMissingDevDependency(pkg, nextDevDependencies, "@rolldown/plugin-babel");
|
|
1669
1646
|
addMissingDevDependency(pkg, nextDevDependencies, "babel-plugin-react-compiler");
|
|
1647
|
+
if (config.linter === "oxlint") {
|
|
1648
|
+
addMissingDevDependency(pkg, nextDevDependencies, "eslint-plugin-react-hooks");
|
|
1649
|
+
}
|
|
1670
1650
|
if (await detectTypeScriptPackage(root, pkg)) {
|
|
1671
1651
|
addMissingDevDependency(pkg, nextDevDependencies, "@types/babel__core");
|
|
1672
1652
|
}
|
|
@@ -1674,7 +1654,7 @@ async function getExpectedPackageDevDependencies(root, config, pkg) {
|
|
|
1674
1654
|
return sortPackageMap(nextDevDependencies);
|
|
1675
1655
|
}
|
|
1676
1656
|
async function getPackageJsonScriptUpdates(root, config) {
|
|
1677
|
-
const packageJsonPath = join(root, "package.json");
|
|
1657
|
+
const packageJsonPath = join$1(root, "package.json");
|
|
1678
1658
|
let currentContent;
|
|
1679
1659
|
try {
|
|
1680
1660
|
currentContent = await readFile$1(packageJsonPath, "utf-8");
|
|
@@ -1687,7 +1667,9 @@ async function getPackageJsonScriptUpdates(root, config) {
|
|
|
1687
1667
|
const nextScripts = mergePackageJsonScripts(currentScripts, expectedScripts);
|
|
1688
1668
|
const currentDevDependencies = pkg.devDependencies ?? {};
|
|
1689
1669
|
const nextDevDependencies = await getExpectedPackageDevDependencies(root, config, pkg);
|
|
1690
|
-
|
|
1670
|
+
const targetPackageManagerSpec = config.targetPackageManagerSpec;
|
|
1671
|
+
const targetNodeVersion = config.targetNodeVersion;
|
|
1672
|
+
if (scriptsEqual(currentScripts, nextScripts) && scriptsEqual(currentDevDependencies, nextDevDependencies) && packageManagerFieldsEqual(pkg, targetPackageManagerSpec, targetNodeVersion)) {
|
|
1691
1673
|
return [
|
|
1692
1674
|
{
|
|
1693
1675
|
path: "package.json",
|
|
@@ -1697,10 +1679,14 @@ async function getPackageJsonScriptUpdates(root, config) {
|
|
|
1697
1679
|
}
|
|
1698
1680
|
];
|
|
1699
1681
|
}
|
|
1700
|
-
const nextPackageJson =
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1682
|
+
const nextPackageJson = applyPackageManagerFields(
|
|
1683
|
+
{
|
|
1684
|
+
...pkg,
|
|
1685
|
+
scripts: nextScripts
|
|
1686
|
+
},
|
|
1687
|
+
targetPackageManagerSpec,
|
|
1688
|
+
targetNodeVersion
|
|
1689
|
+
);
|
|
1704
1690
|
if (Object.keys(nextDevDependencies).length > 0 || pkg.devDependencies != null) {
|
|
1705
1691
|
nextPackageJson.devDependencies = nextDevDependencies;
|
|
1706
1692
|
}
|
|
@@ -1715,12 +1701,49 @@ async function getPackageJsonScriptUpdates(root, config) {
|
|
|
1715
1701
|
}
|
|
1716
1702
|
];
|
|
1717
1703
|
}
|
|
1704
|
+
async function getPackageManagerConfigUpdates(root, config) {
|
|
1705
|
+
if (config.targetPackageManagerSpec == null && config.targetNodeVersion == null) return [];
|
|
1706
|
+
const packageJsonPath = join$1(root, "package.json");
|
|
1707
|
+
let currentContent;
|
|
1708
|
+
try {
|
|
1709
|
+
currentContent = await readFile$1(packageJsonPath, "utf-8");
|
|
1710
|
+
} catch {
|
|
1711
|
+
return [];
|
|
1712
|
+
}
|
|
1713
|
+
const pkg = JSON.parse(currentContent);
|
|
1714
|
+
if (packageManagerFieldsEqual(pkg, config.targetPackageManagerSpec, config.targetNodeVersion)) {
|
|
1715
|
+
return [
|
|
1716
|
+
{
|
|
1717
|
+
path: "package.json",
|
|
1718
|
+
status: "unchanged",
|
|
1719
|
+
currentContent,
|
|
1720
|
+
newContent: currentContent
|
|
1721
|
+
}
|
|
1722
|
+
];
|
|
1723
|
+
}
|
|
1724
|
+
const nextPackageJson = applyPackageManagerFields(
|
|
1725
|
+
pkg,
|
|
1726
|
+
config.targetPackageManagerSpec,
|
|
1727
|
+
config.targetNodeVersion
|
|
1728
|
+
);
|
|
1729
|
+
return [
|
|
1730
|
+
{
|
|
1731
|
+
path: "package.json",
|
|
1732
|
+
status: "modified",
|
|
1733
|
+
currentContent,
|
|
1734
|
+
newContent: `${JSON.stringify(nextPackageJson, null, 2)}
|
|
1735
|
+
`
|
|
1736
|
+
}
|
|
1737
|
+
];
|
|
1738
|
+
}
|
|
1718
1739
|
function planSinglePackageOxlintConfig(config) {
|
|
1719
1740
|
if (config.linter !== "oxlint" || config.isMonorepo) return void 0;
|
|
1720
1741
|
const isStealth = (config.configStrategy ?? "stealth") === "stealth";
|
|
1721
1742
|
const path = isStealth ? ".config/oxlint.json" : "oxlint.json";
|
|
1722
1743
|
const oxlintConfig = renderOxlintConfig({
|
|
1723
1744
|
schemaPath: isStealth ? "../node_modules/oxlint/configuration_schema.json" : "./node_modules/oxlint/configuration_schema.json",
|
|
1745
|
+
react: config.viteTemplate === "react" || config.viteTemplate === "r3f",
|
|
1746
|
+
reactCompiler: config.viteTemplate === "react",
|
|
1724
1747
|
typescript: true
|
|
1725
1748
|
});
|
|
1726
1749
|
return {
|
|
@@ -1733,7 +1756,7 @@ function planSinglePackageOxlintConfig(config) {
|
|
|
1733
1756
|
async function getOxlintConfigReplacementUpdates(root, config) {
|
|
1734
1757
|
const expected = planSinglePackageOxlintConfig(config);
|
|
1735
1758
|
if (expected == null) return [];
|
|
1736
|
-
const fullPath = join(root, expected.path);
|
|
1759
|
+
const fullPath = join$1(root, expected.path);
|
|
1737
1760
|
let currentContent;
|
|
1738
1761
|
try {
|
|
1739
1762
|
currentContent = await readFile$1(fullPath, "utf-8");
|
|
@@ -1758,9 +1781,105 @@ async function getOxlintConfigReplacementUpdates(root, config) {
|
|
|
1758
1781
|
}
|
|
1759
1782
|
];
|
|
1760
1783
|
}
|
|
1761
|
-
|
|
1762
|
-
const
|
|
1784
|
+
function extractBuildDependencies(content) {
|
|
1785
|
+
const buildDependencies = {};
|
|
1786
|
+
let section;
|
|
1787
|
+
for (const line of content.split("\n")) {
|
|
1788
|
+
const trimmed = line.trim();
|
|
1789
|
+
if (trimmed === "onlyBuiltDependencies:") {
|
|
1790
|
+
section = "onlyBuiltDependencies";
|
|
1791
|
+
continue;
|
|
1792
|
+
}
|
|
1793
|
+
if (trimmed === "allowBuilds:") {
|
|
1794
|
+
section = "allowBuilds";
|
|
1795
|
+
continue;
|
|
1796
|
+
}
|
|
1797
|
+
if (section != null && trimmed && !line.startsWith(" ") && !line.startsWith(" ")) {
|
|
1798
|
+
section = void 0;
|
|
1799
|
+
}
|
|
1800
|
+
if (section === "onlyBuiltDependencies" && trimmed.startsWith("-")) {
|
|
1801
|
+
const dependency = trimmed.slice(1).trim().replace(/^["']|["']$/g, "");
|
|
1802
|
+
if (dependency.length > 0) {
|
|
1803
|
+
buildDependencies[dependency] = true;
|
|
1804
|
+
}
|
|
1805
|
+
}
|
|
1806
|
+
if (section === "allowBuilds") {
|
|
1807
|
+
const match = trimmed.match(/^([^:]+):\s*(true|false)$/);
|
|
1808
|
+
if (match == null) continue;
|
|
1809
|
+
const dependency = match[1].trim().replace(/^["']|["']$/g, "");
|
|
1810
|
+
if (dependency.length > 0) {
|
|
1811
|
+
buildDependencies[dependency] = match[2] === "true";
|
|
1812
|
+
}
|
|
1813
|
+
}
|
|
1814
|
+
}
|
|
1815
|
+
return buildDependencies;
|
|
1816
|
+
}
|
|
1817
|
+
function withDefaultBuildDependencies(buildDependencies) {
|
|
1818
|
+
return Object.keys(buildDependencies).length > 0 ? buildDependencies : { esbuild: true };
|
|
1819
|
+
}
|
|
1820
|
+
function isPnpmWorkspaceManagedScalarKey(trimmed) {
|
|
1821
|
+
return trimmed.startsWith("manage-package-manager-versions:") || trimmed.startsWith("pmOnFail:");
|
|
1822
|
+
}
|
|
1823
|
+
function isPnpmWorkspaceManagedBlockKey(trimmed) {
|
|
1824
|
+
return trimmed === "onlyBuiltDependencies:" || trimmed === "allowBuilds:";
|
|
1825
|
+
}
|
|
1826
|
+
function isIndentedWorkspaceLine(line) {
|
|
1827
|
+
return line.startsWith(" ") || line.startsWith(" ");
|
|
1828
|
+
}
|
|
1829
|
+
function removePnpmWorkspaceManagedKeys(content) {
|
|
1830
|
+
const sourceLines = content.split("\n");
|
|
1831
|
+
const lines = [];
|
|
1832
|
+
let insertionIndex = 0;
|
|
1833
|
+
let foundManagedKey = false;
|
|
1834
|
+
for (let index = 0; index < sourceLines.length; index++) {
|
|
1835
|
+
const line = sourceLines[index];
|
|
1836
|
+
const trimmed = line.trim();
|
|
1837
|
+
if (isPnpmWorkspaceManagedScalarKey(trimmed)) {
|
|
1838
|
+
if (!foundManagedKey) {
|
|
1839
|
+
insertionIndex = lines.length;
|
|
1840
|
+
foundManagedKey = true;
|
|
1841
|
+
}
|
|
1842
|
+
continue;
|
|
1843
|
+
}
|
|
1844
|
+
if (isPnpmWorkspaceManagedBlockKey(trimmed)) {
|
|
1845
|
+
if (!foundManagedKey) {
|
|
1846
|
+
insertionIndex = lines.length;
|
|
1847
|
+
foundManagedKey = true;
|
|
1848
|
+
}
|
|
1849
|
+
while (index + 1 < sourceLines.length) {
|
|
1850
|
+
const nextLine = sourceLines[index + 1];
|
|
1851
|
+
const nextTrimmed = nextLine.trim();
|
|
1852
|
+
if (nextTrimmed !== "" && !isIndentedWorkspaceLine(nextLine)) break;
|
|
1853
|
+
index++;
|
|
1854
|
+
}
|
|
1855
|
+
continue;
|
|
1856
|
+
}
|
|
1857
|
+
lines.push(line);
|
|
1858
|
+
}
|
|
1859
|
+
return {
|
|
1860
|
+
content: lines.join("\n").trim(),
|
|
1861
|
+
insertionIndex
|
|
1862
|
+
};
|
|
1863
|
+
}
|
|
1864
|
+
function patchPnpmWorkspaceManagedKeys(content, profile, buildDependencies) {
|
|
1865
|
+
const managedContent = renderPnpmWorkspaceConfig({
|
|
1866
|
+
profile,
|
|
1867
|
+
manageVersions: true,
|
|
1868
|
+
buildDependencies
|
|
1869
|
+
});
|
|
1870
|
+
const existing = removePnpmWorkspaceManagedKeys(content);
|
|
1871
|
+
const preservedLines = existing.content.length > 0 ? existing.content.split("\n") : [];
|
|
1872
|
+
const insertionIndex = Math.min(existing.insertionIndex, preservedLines.length);
|
|
1873
|
+
const managedLines = managedContent.split("\n");
|
|
1874
|
+
preservedLines.splice(insertionIndex, 0, ...managedLines);
|
|
1875
|
+
return preservedLines.join("\n").replace(/\n{3,}/g, "\n\n").trim();
|
|
1876
|
+
}
|
|
1877
|
+
async function getWorkspaceConfigUpdates(root, config) {
|
|
1878
|
+
const workspacePath = join$1(root, "pnpm-workspace.yaml");
|
|
1763
1879
|
const changes = [];
|
|
1880
|
+
const packageManagerSpec = config?.targetPackageManagerSpec ?? config?.packageManagerSpec ?? { name: "pnpm" };
|
|
1881
|
+
const profile = getPackageManagerProfile(packageManagerSpec);
|
|
1882
|
+
const defaultPackages = [".config/*", "apps/*", "packages/*"];
|
|
1764
1883
|
let currentContent = "";
|
|
1765
1884
|
let exists = false;
|
|
1766
1885
|
try {
|
|
@@ -1769,15 +1888,11 @@ async function getWorkspaceConfigUpdates(root) {
|
|
|
1769
1888
|
} catch {
|
|
1770
1889
|
}
|
|
1771
1890
|
if (!exists) {
|
|
1772
|
-
const newContent =
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
- 'packages/*'
|
|
1778
|
-
|
|
1779
|
-
onlyBuiltDependencies:
|
|
1780
|
-
- esbuild
|
|
1891
|
+
const newContent = `${renderPnpmWorkspaceConfig({
|
|
1892
|
+
profile,
|
|
1893
|
+
manageVersions: true,
|
|
1894
|
+
packages: defaultPackages
|
|
1895
|
+
})}
|
|
1781
1896
|
`;
|
|
1782
1897
|
changes.push({
|
|
1783
1898
|
path: "pnpm-workspace.yaml",
|
|
@@ -1786,32 +1901,14 @@ onlyBuiltDependencies:
|
|
|
1786
1901
|
});
|
|
1787
1902
|
return changes;
|
|
1788
1903
|
}
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
needsUpdate = true;
|
|
1796
|
-
}
|
|
1797
|
-
if (!currentContent.includes("onlyBuiltDependencies")) {
|
|
1798
|
-
updatedContent = `${updatedContent.trimEnd()}
|
|
1799
|
-
|
|
1800
|
-
onlyBuiltDependencies:
|
|
1801
|
-
- esbuild
|
|
1904
|
+
const buildDependencies = withDefaultBuildDependencies(extractBuildDependencies(currentContent));
|
|
1905
|
+
const updatedContent = `${patchPnpmWorkspaceManagedKeys(
|
|
1906
|
+
currentContent,
|
|
1907
|
+
profile,
|
|
1908
|
+
buildDependencies
|
|
1909
|
+
)}
|
|
1802
1910
|
`;
|
|
1803
|
-
|
|
1804
|
-
}
|
|
1805
|
-
if (!currentContent.includes(".config/*")) {
|
|
1806
|
-
const lines = updatedContent.split("\n");
|
|
1807
|
-
const packagesIndex = lines.findIndex((line) => line.trim().startsWith("packages:"));
|
|
1808
|
-
if (packagesIndex !== -1) {
|
|
1809
|
-
lines.splice(packagesIndex + 1, 0, " - '.config/*'");
|
|
1810
|
-
updatedContent = lines.join("\n");
|
|
1811
|
-
needsUpdate = true;
|
|
1812
|
-
}
|
|
1813
|
-
}
|
|
1814
|
-
if (needsUpdate) {
|
|
1911
|
+
if (updatedContent !== currentContent) {
|
|
1815
1912
|
changes.push({
|
|
1816
1913
|
path: "pnpm-workspace.yaml",
|
|
1817
1914
|
status: "modified",
|
|
@@ -1831,7 +1928,7 @@ onlyBuiltDependencies:
|
|
|
1831
1928
|
async function applyUpdates(changes, root) {
|
|
1832
1929
|
for (const change of changes) {
|
|
1833
1930
|
if (change.status === "unchanged") continue;
|
|
1834
|
-
const fullPath = join(root, change.path);
|
|
1931
|
+
const fullPath = join$1(root, change.path);
|
|
1835
1932
|
await mkdir$1(dirname$1(fullPath), { recursive: true });
|
|
1836
1933
|
await writeFile$1(fullPath, change.newContent);
|
|
1837
1934
|
}
|
|
@@ -1909,6 +2006,96 @@ function orderUpdateCategories(categories) {
|
|
|
1909
2006
|
(left, right) => getCategoryOrder(left.category) - getCategoryOrder(right.category)
|
|
1910
2007
|
);
|
|
1911
2008
|
}
|
|
2009
|
+
function isPnpmMajorMigration(config) {
|
|
2010
|
+
const currentPackageManager = config.packageManagerSpec;
|
|
2011
|
+
const targetPackageManager = config.targetPackageManagerSpec;
|
|
2012
|
+
if (currentPackageManager?.name !== "pnpm" || targetPackageManager?.name !== "pnpm") {
|
|
2013
|
+
return false;
|
|
2014
|
+
}
|
|
2015
|
+
const currentMajor = getSemverMajor(currentPackageManager.version);
|
|
2016
|
+
const targetMajor = getSemverMajor(targetPackageManager.version);
|
|
2017
|
+
return currentMajor != null && targetMajor != null && currentMajor !== targetMajor;
|
|
2018
|
+
}
|
|
2019
|
+
function getPackageUpdateCommand(config) {
|
|
2020
|
+
const packageManagerName = config.packageManager.split("@")[0] ?? config.packageManager;
|
|
2021
|
+
if (packageManagerName === "pnpm") {
|
|
2022
|
+
if (isPnpmMajorMigration(config)) {
|
|
2023
|
+
return {
|
|
2024
|
+
command: "pnpm",
|
|
2025
|
+
args: ["install"],
|
|
2026
|
+
displayCommand: "pnpm install",
|
|
2027
|
+
promptMessage: "Install dependencies?",
|
|
2028
|
+
successMessage: "Dependencies installed",
|
|
2029
|
+
failureLabel: "Dependency install"
|
|
2030
|
+
};
|
|
2031
|
+
}
|
|
2032
|
+
return {
|
|
2033
|
+
command: "pnpm",
|
|
2034
|
+
args: ["update"],
|
|
2035
|
+
displayCommand: "pnpm update",
|
|
2036
|
+
promptMessage: "Update packages?",
|
|
2037
|
+
successMessage: "Packages updated",
|
|
2038
|
+
failureLabel: "Package update"
|
|
2039
|
+
};
|
|
2040
|
+
}
|
|
2041
|
+
if (packageManagerName === "npm") {
|
|
2042
|
+
return {
|
|
2043
|
+
command: "npm",
|
|
2044
|
+
args: ["update"],
|
|
2045
|
+
displayCommand: "npm update",
|
|
2046
|
+
promptMessage: "Update packages?",
|
|
2047
|
+
successMessage: "Packages updated",
|
|
2048
|
+
failureLabel: "Package update"
|
|
2049
|
+
};
|
|
2050
|
+
}
|
|
2051
|
+
return void 0;
|
|
2052
|
+
}
|
|
2053
|
+
async function runPackageUpdate(projectRoot, updateCommand) {
|
|
2054
|
+
await new Promise((resolve, reject) => {
|
|
2055
|
+
const child = spawn(updateCommand.command, updateCommand.args, {
|
|
2056
|
+
cwd: projectRoot,
|
|
2057
|
+
shell: process.platform === "win32",
|
|
2058
|
+
stdio: "inherit"
|
|
2059
|
+
});
|
|
2060
|
+
child.on("error", reject);
|
|
2061
|
+
child.on("exit", (code) => {
|
|
2062
|
+
if (code === 0) {
|
|
2063
|
+
resolve();
|
|
2064
|
+
return;
|
|
2065
|
+
}
|
|
2066
|
+
reject(new Error(`${updateCommand.displayCommand} exited with code ${code ?? "unknown"}`));
|
|
2067
|
+
});
|
|
2068
|
+
});
|
|
2069
|
+
}
|
|
2070
|
+
async function promptForPackageUpdate(projectRoot, config, options) {
|
|
2071
|
+
const updateCommand = getPackageUpdateCommand(config);
|
|
2072
|
+
if (!updateCommand) {
|
|
2073
|
+
console.log(color.dim(` Package updates are not supported for ${config.packageManager}`));
|
|
2074
|
+
return;
|
|
2075
|
+
}
|
|
2076
|
+
const shouldUpdatePackages = options.yes || await p.confirm({
|
|
2077
|
+
message: updateCommand.promptMessage,
|
|
2078
|
+
initialValue: true
|
|
2079
|
+
});
|
|
2080
|
+
if (p.isCancel(shouldUpdatePackages)) {
|
|
2081
|
+
p.cancel("Operation cancelled.");
|
|
2082
|
+
process.exit(0);
|
|
2083
|
+
}
|
|
2084
|
+
if (!shouldUpdatePackages) {
|
|
2085
|
+
console.log(color.dim(" Skipped package updates"));
|
|
2086
|
+
return;
|
|
2087
|
+
}
|
|
2088
|
+
console.log();
|
|
2089
|
+
console.log(color.cyan(`Running ${updateCommand.displayCommand}...`));
|
|
2090
|
+
try {
|
|
2091
|
+
await runPackageUpdate(projectRoot, updateCommand);
|
|
2092
|
+
console.log(color.green("\u2713") + ` ${updateCommand.successMessage}`);
|
|
2093
|
+
} catch (error) {
|
|
2094
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2095
|
+
console.log(color.red("\u2717") + ` ${updateCommand.failureLabel} failed: ${message}`);
|
|
2096
|
+
process.exit(1);
|
|
2097
|
+
}
|
|
2098
|
+
}
|
|
1912
2099
|
async function collectUpdateCategories(projectRoot, config, isMonorepo) {
|
|
1913
2100
|
const expected = await planExpectedFiles(config);
|
|
1914
2101
|
const categories = await compareWithDisk(expected, projectRoot);
|
|
@@ -1932,7 +2119,7 @@ async function collectUpdateCategories(projectRoot, config, isMonorepo) {
|
|
|
1932
2119
|
});
|
|
1933
2120
|
}
|
|
1934
2121
|
if (isMonorepo) {
|
|
1935
|
-
const workspaceConfigChanges = await getWorkspaceConfigUpdates(projectRoot);
|
|
2122
|
+
const workspaceConfigChanges = await getWorkspaceConfigUpdates(projectRoot, config);
|
|
1936
2123
|
if (workspaceConfigChanges.length > 0) {
|
|
1937
2124
|
allCategories.push({
|
|
1938
2125
|
category: "workspace-config",
|
|
@@ -1944,6 +2131,110 @@ async function collectUpdateCategories(projectRoot, config, isMonorepo) {
|
|
|
1944
2131
|
}
|
|
1945
2132
|
return orderUpdateCategories(allCategories);
|
|
1946
2133
|
}
|
|
2134
|
+
async function resolveTargetPackageManagerSpec(options, config) {
|
|
2135
|
+
if (options.packageManager == null) return void 0;
|
|
2136
|
+
const packageManager = parsePackageManagerSpec(options.packageManager);
|
|
2137
|
+
if (packageManager == null) {
|
|
2138
|
+
console.log(color.red("\u2717") + ` Unsupported package manager: ${options.packageManager}`);
|
|
2139
|
+
process.exit(1);
|
|
2140
|
+
}
|
|
2141
|
+
return resolvePackageManager({
|
|
2142
|
+
name: config.name,
|
|
2143
|
+
packageManager
|
|
2144
|
+
});
|
|
2145
|
+
}
|
|
2146
|
+
function getPackageManagerMajorUpdateTarget(currentPackageManager, latestPackageManager) {
|
|
2147
|
+
if (currentPackageManager?.version == null) return void 0;
|
|
2148
|
+
const currentMajor = getSemverMajor(currentPackageManager.version);
|
|
2149
|
+
const latestMajor = getSemverMajor(latestPackageManager.version);
|
|
2150
|
+
if (currentMajor == null || latestMajor == null || latestMajor <= currentMajor) {
|
|
2151
|
+
return void 0;
|
|
2152
|
+
}
|
|
2153
|
+
return latestPackageManager;
|
|
2154
|
+
}
|
|
2155
|
+
function getRequiredNodeUpdateTarget(currentNodeVersion, requiredNodeVersion) {
|
|
2156
|
+
if (requiredNodeVersion == null) return void 0;
|
|
2157
|
+
if (currentNodeVersion == null) return requiredNodeVersion;
|
|
2158
|
+
return compareNumericSemver(currentNodeVersion, requiredNodeVersion) < 0 ? requiredNodeVersion : void 0;
|
|
2159
|
+
}
|
|
2160
|
+
function formatPackageManagerMajor(packageManager) {
|
|
2161
|
+
const major = getSemverMajor(packageManager.version);
|
|
2162
|
+
return major == null ? packageManager.name : `${packageManager.name}@${major}`;
|
|
2163
|
+
}
|
|
2164
|
+
async function promptForNodeRequirementUpdate(options, config, targetPackageManagerSpec) {
|
|
2165
|
+
if (targetPackageManagerSpec == null) return void 0;
|
|
2166
|
+
const profile = getPackageManagerProfile(targetPackageManagerSpec);
|
|
2167
|
+
const requiredNodeVersion = profile.requirements.node;
|
|
2168
|
+
const currentNodeVersion = config.engine?.version;
|
|
2169
|
+
const targetNodeVersion = getRequiredNodeUpdateTarget(currentNodeVersion, requiredNodeVersion);
|
|
2170
|
+
if (targetNodeVersion == null) return void 0;
|
|
2171
|
+
const currentNodeLabel = currentNodeVersion == null ? "not set" : `>=${currentNodeVersion}`;
|
|
2172
|
+
p.log.warn(
|
|
2173
|
+
`${formatPackageManager(targetPackageManagerSpec)} requires Node >=${targetNodeVersion}; current engines.node is ${currentNodeLabel}.`
|
|
2174
|
+
);
|
|
2175
|
+
const shouldUpdate = options.yes || await p.confirm({
|
|
2176
|
+
message: `Update engines.node to >=${targetNodeVersion} too?`,
|
|
2177
|
+
initialValue: true
|
|
2178
|
+
});
|
|
2179
|
+
if (p.isCancel(shouldUpdate)) {
|
|
2180
|
+
p.cancel("Operation cancelled.");
|
|
2181
|
+
process.exit(0);
|
|
2182
|
+
}
|
|
2183
|
+
return shouldUpdate ? targetNodeVersion : void 0;
|
|
2184
|
+
}
|
|
2185
|
+
async function promptForPackageManagerMajorUpdate(options, config) {
|
|
2186
|
+
if (options.packageManager != null || config.packageManagerSpec == null) return void 0;
|
|
2187
|
+
const currentPackageManager = config.packageManagerSpec;
|
|
2188
|
+
if (currentPackageManager.version == null) return void 0;
|
|
2189
|
+
const latestPackageManager = await resolvePackageManager({
|
|
2190
|
+
name: config.name,
|
|
2191
|
+
packageManager: { name: currentPackageManager.name }
|
|
2192
|
+
});
|
|
2193
|
+
const updateTarget = getPackageManagerMajorUpdateTarget(
|
|
2194
|
+
currentPackageManager,
|
|
2195
|
+
latestPackageManager
|
|
2196
|
+
);
|
|
2197
|
+
if (updateTarget == null) return void 0;
|
|
2198
|
+
const shouldUpdate = options.yes || await p.confirm({
|
|
2199
|
+
message: `Update ${currentPackageManager.name} from ${formatPackageManagerMajor(
|
|
2200
|
+
currentPackageManager
|
|
2201
|
+
)} to ${formatPackageManagerMajor(latestPackageManager)}?`,
|
|
2202
|
+
initialValue: true
|
|
2203
|
+
});
|
|
2204
|
+
if (p.isCancel(shouldUpdate)) {
|
|
2205
|
+
p.cancel("Operation cancelled.");
|
|
2206
|
+
process.exit(0);
|
|
2207
|
+
}
|
|
2208
|
+
return shouldUpdate ? updateTarget : void 0;
|
|
2209
|
+
}
|
|
2210
|
+
async function applyPackageManagerMigration(projectRoot, isMonorepo, options, detectedConfig) {
|
|
2211
|
+
const targetPackageManagerSpec = await resolveTargetPackageManagerSpec(options, detectedConfig) ?? await promptForPackageManagerMajorUpdate(options, detectedConfig);
|
|
2212
|
+
if (targetPackageManagerSpec == null) return detectedConfig;
|
|
2213
|
+
const targetNodeVersion = await promptForNodeRequirementUpdate(
|
|
2214
|
+
options,
|
|
2215
|
+
detectedConfig,
|
|
2216
|
+
targetPackageManagerSpec
|
|
2217
|
+
);
|
|
2218
|
+
const migrationConfig = {
|
|
2219
|
+
...detectedConfig,
|
|
2220
|
+
packageManager: targetPackageManagerSpec.name,
|
|
2221
|
+
targetPackageManagerSpec,
|
|
2222
|
+
targetNodeVersion
|
|
2223
|
+
};
|
|
2224
|
+
const changes = [
|
|
2225
|
+
...await getPackageManagerConfigUpdates(projectRoot, migrationConfig),
|
|
2226
|
+
...isMonorepo || targetPackageManagerSpec.name === "pnpm" ? await getWorkspaceConfigUpdates(projectRoot, migrationConfig) : []
|
|
2227
|
+
].filter((change) => change.status === "added" || change.status === "modified");
|
|
2228
|
+
if (changes.length === 0) return migrationConfig;
|
|
2229
|
+
console.log();
|
|
2230
|
+
console.log(color.cyan("Package Manager:"));
|
|
2231
|
+
for (const change of changes) {
|
|
2232
|
+
console.log(formatFileChange(change));
|
|
2233
|
+
}
|
|
2234
|
+
await applyUpdates(changes, projectRoot);
|
|
2235
|
+
console.log(color.green("\u2713") + ` Package Manager: updated ${changes.length}`);
|
|
2236
|
+
return migrationConfig;
|
|
2237
|
+
}
|
|
1947
2238
|
async function processUpdateCategory(category, projectRoot, options) {
|
|
1948
2239
|
const newChanges = category.changes.filter((change) => change.status === "added");
|
|
1949
2240
|
const modifiedChanges = category.changes.filter((change) => change.status === "modified");
|
|
@@ -1983,11 +2274,8 @@ async function processUpdateCategory(category, projectRoot, options) {
|
|
|
1983
2274
|
if (addedCount > 0) parts.push(`added ${addedCount}`);
|
|
1984
2275
|
if (updatedFilesCount > 0) parts.push(`updated ${updatedFilesCount}`);
|
|
1985
2276
|
console.log(color.green("\u2713") + ` ${category.label}: ${parts.join(", ")}`);
|
|
1986
|
-
console.log();
|
|
1987
2277
|
return "updated";
|
|
1988
2278
|
}
|
|
1989
|
-
console.log(color.dim(` Skipped ${category.label}`));
|
|
1990
|
-
console.log();
|
|
1991
2279
|
return "skipped";
|
|
1992
2280
|
}
|
|
1993
2281
|
async function handleUpdateCommand(options, handleFixCommand) {
|
|
@@ -2053,6 +2341,8 @@ async function handleUpdateCommand(options, handleFixCommand) {
|
|
|
2053
2341
|
console.log(color.dim(` Skipped ${skippedCount}`));
|
|
2054
2342
|
}
|
|
2055
2343
|
}
|
|
2344
|
+
const finalConfig = await applyPackageManagerMigration(projectRoot, isMonorepo, options, config);
|
|
2345
|
+
await promptForPackageUpdate(projectRoot, finalConfig, options);
|
|
2056
2346
|
process.exit(0);
|
|
2057
2347
|
}
|
|
2058
2348
|
|
|
@@ -2070,12 +2360,13 @@ async function createPackageInWorkspace(monorepoRoot, packageManager, inheritedS
|
|
|
2070
2360
|
message: "Package name?",
|
|
2071
2361
|
initialValue: `@${scope}/`,
|
|
2072
2362
|
validate: (value) => {
|
|
2073
|
-
const
|
|
2363
|
+
const packageName = value ?? "";
|
|
2364
|
+
const validationError = validatePackageName(packageName);
|
|
2074
2365
|
if (validationError) return validationError;
|
|
2075
|
-
const dirName =
|
|
2366
|
+
const dirName = getPackageDirectoryName(packageName);
|
|
2076
2367
|
if (!dirName) return "Package name is required";
|
|
2077
2368
|
if (!hasCustomDirectories) {
|
|
2078
|
-
const targetPath = join
|
|
2369
|
+
const targetPath = join(monorepoRoot, defaultDir, dirName);
|
|
2079
2370
|
try {
|
|
2080
2371
|
const { statSync } = require$2("fs");
|
|
2081
2372
|
statSync(targetPath);
|
|
@@ -2089,7 +2380,7 @@ async function createPackageInWorkspace(monorepoRoot, packageManager, inheritedS
|
|
|
2089
2380
|
return false;
|
|
2090
2381
|
}
|
|
2091
2382
|
const scopedName = packageNameInput;
|
|
2092
|
-
const shortName =
|
|
2383
|
+
const shortName = getPackageDirectoryName(scopedName);
|
|
2093
2384
|
const packageOptions = await promptForPackageOptions(scopedName, packageType, inheritedSettings);
|
|
2094
2385
|
let targetDir = defaultDir;
|
|
2095
2386
|
if (hasCustomDirectories && workspaceDirectories.length > 0) {
|
|
@@ -2105,7 +2396,7 @@ async function createPackageInWorkspace(monorepoRoot, packageManager, inheritedS
|
|
|
2105
2396
|
return false;
|
|
2106
2397
|
}
|
|
2107
2398
|
targetDir = dirChoice;
|
|
2108
|
-
const targetPath = join
|
|
2399
|
+
const targetPath = join(monorepoRoot, targetDir, shortName);
|
|
2109
2400
|
try {
|
|
2110
2401
|
const { statSync } = require$2("fs");
|
|
2111
2402
|
statSync(targetPath);
|
|
@@ -2114,7 +2405,7 @@ async function createPackageInWorkspace(monorepoRoot, packageManager, inheritedS
|
|
|
2114
2405
|
} catch {
|
|
2115
2406
|
}
|
|
2116
2407
|
}
|
|
2117
|
-
const relativePkgPath = join
|
|
2408
|
+
const relativePkgPath = join(targetDir, shortName);
|
|
2118
2409
|
const workspaceRoot = calculateWorkspaceRoot(relativePkgPath);
|
|
2119
2410
|
packageOptions.workspaceRoot = workspaceRoot;
|
|
2120
2411
|
packageOptions.name = scopedName;
|
|
@@ -2129,7 +2420,7 @@ async function createPackageInWorkspace(monorepoRoot, packageManager, inheritedS
|
|
|
2129
2420
|
packageOptions.workspaceDependencies = selectedDeps;
|
|
2130
2421
|
}
|
|
2131
2422
|
}
|
|
2132
|
-
const outputPath = join
|
|
2423
|
+
const outputPath = join(monorepoRoot, relativePkgPath);
|
|
2133
2424
|
const spinner = p.spinner();
|
|
2134
2425
|
spinner.start("Creating package...");
|
|
2135
2426
|
try {
|
|
@@ -2170,10 +2461,11 @@ async function handleWorkspaceCommand(name, options, writeGeneratedFiles) {
|
|
|
2170
2461
|
const template = options.template ?? "vanilla";
|
|
2171
2462
|
const baseTemplate = getBaseTemplate(template);
|
|
2172
2463
|
const scopedName = name.startsWith("@") ? name : `@${scope}/${name}`;
|
|
2173
|
-
const
|
|
2464
|
+
const packageDirName = getPackageDirectoryName(name);
|
|
2465
|
+
const fullPackagePath = join(monorepoRoot, targetDir, packageDirName);
|
|
2174
2466
|
try {
|
|
2175
|
-
await access
|
|
2176
|
-
console.error(color.red("Error:") + ` Directory ${targetDir}/${
|
|
2467
|
+
await access(fullPackagePath, constants.F_OK);
|
|
2468
|
+
console.error(color.red("Error:") + ` Directory ${targetDir}/${packageDirName} already exists`);
|
|
2177
2469
|
process.exit(1);
|
|
2178
2470
|
} catch {
|
|
2179
2471
|
}
|
|
@@ -2186,7 +2478,7 @@ async function handleWorkspaceCommand(name, options, writeGeneratedFiles) {
|
|
|
2186
2478
|
};
|
|
2187
2479
|
const pnpmManageVersions = inheritedSettings.pnpmManageVersions ?? true;
|
|
2188
2480
|
const isLibrary = projectType === "library";
|
|
2189
|
-
const relativePkgPath = join
|
|
2481
|
+
const relativePkgPath = join(targetDir, packageDirName);
|
|
2190
2482
|
const workspaceRoot = calculateWorkspaceRoot(relativePkgPath);
|
|
2191
2483
|
const projectOptions = {
|
|
2192
2484
|
name: scopedName,
|
|
@@ -2214,11 +2506,11 @@ async function handleWorkspaceCommand(name, options, writeGeneratedFiles) {
|
|
|
2214
2506
|
triplex: options.triplex ? {} : void 0
|
|
2215
2507
|
}
|
|
2216
2508
|
};
|
|
2217
|
-
console.log(color.cyan("Creating") + ` ${scopedName} in ${targetDir}/${
|
|
2509
|
+
console.log(color.cyan("Creating") + ` ${scopedName} in ${targetDir}/${packageDirName}...`);
|
|
2218
2510
|
try {
|
|
2219
2511
|
const { files } = await planProject(resolveProjectPlanInput(projectOptions));
|
|
2220
2512
|
await writeGeneratedFiles(fullPackagePath, files);
|
|
2221
|
-
console.log(color.green("\u2713") + ` Created ${scopedName} at ${targetDir}/${
|
|
2513
|
+
console.log(color.green("\u2713") + ` Created ${scopedName} at ${targetDir}/${packageDirName}`);
|
|
2222
2514
|
process.exit(0);
|
|
2223
2515
|
} catch (error) {
|
|
2224
2516
|
console.error(color.red("Error:") + " Failed to create package");
|
|
@@ -2288,7 +2580,7 @@ function hasConfigOptions(options) {
|
|
|
2288
2580
|
async function writeGeneratedFiles(basePath, files) {
|
|
2289
2581
|
const filePaths = Object.keys(files).sort();
|
|
2290
2582
|
for (const filePath of filePaths) {
|
|
2291
|
-
const fullFilePath = join
|
|
2583
|
+
const fullFilePath = join(basePath, filePath);
|
|
2292
2584
|
await mkdir(dirname(fullFilePath), { recursive: true });
|
|
2293
2585
|
const file = files[filePath];
|
|
2294
2586
|
if (file.type === "text") {
|
|
@@ -2301,7 +2593,7 @@ async function writeGeneratedFiles(basePath, files) {
|
|
|
2301
2593
|
}
|
|
2302
2594
|
async function handleMonorepoCreation(projectOptions, isNonInteractive) {
|
|
2303
2595
|
const packageManager = getPackageManagerName(projectOptions.packageManager);
|
|
2304
|
-
const projectPath = join
|
|
2596
|
+
const projectPath = join(cwd(), projectOptions.name);
|
|
2305
2597
|
const spinner = p.spinner();
|
|
2306
2598
|
spinner.start("Creating monorepo workspace...");
|
|
2307
2599
|
try {
|
|
@@ -2363,7 +2655,8 @@ async function handleSingleWorkspaceCreation(projectOptions, isNonInteractive) {
|
|
|
2363
2655
|
const defaultFallbackName = base === "vanilla" ? "vanilla-app" : base === "react" ? "react-app" : "react-three-app";
|
|
2364
2656
|
projectOptions.name ??= defaultFallbackName;
|
|
2365
2657
|
const packageManager = getPackageManagerName(projectOptions.packageManager);
|
|
2366
|
-
const
|
|
2658
|
+
const projectDirName = getPackageDirectoryName(projectOptions.name);
|
|
2659
|
+
const projectPath = join(cwd(), projectDirName);
|
|
2367
2660
|
const spinner = p.spinner();
|
|
2368
2661
|
spinner.start("Creating project...");
|
|
2369
2662
|
try {
|
|
@@ -2372,15 +2665,11 @@ async function handleSingleWorkspaceCreation(projectOptions, isNonInteractive) {
|
|
|
2372
2665
|
await writeGeneratedFiles(projectPath, files);
|
|
2373
2666
|
spinner.stop(color.green.inverse(" \u2713 Project created! "));
|
|
2374
2667
|
if (isNonInteractive) process.exit(0);
|
|
2375
|
-
const nextSteps = projectOptions.projectType === "library" ? [
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
`cd ${projectOptions.name}`,
|
|
2381
|
-
`${packageManager} install`,
|
|
2382
|
-
`${packageManager} run dev`
|
|
2383
|
-
].join("\n");
|
|
2668
|
+
const nextSteps = projectOptions.projectType === "library" ? [`cd ${projectDirName}`, `${packageManager} install`, `${packageManager} run build`].join(
|
|
2669
|
+
"\n"
|
|
2670
|
+
) : [`cd ${projectDirName}`, `${packageManager} install`, `${packageManager} run dev`].join(
|
|
2671
|
+
"\n"
|
|
2672
|
+
);
|
|
2384
2673
|
p.note(nextSteps, "Next steps");
|
|
2385
2674
|
p.outro(color.green("Happy coding! \u2728"));
|
|
2386
2675
|
} catch (error) {
|
|
@@ -2396,7 +2685,7 @@ async function main() {
|
|
|
2396
2685
|
).option(
|
|
2397
2686
|
"--template <type>",
|
|
2398
2687
|
"project template: vanilla, vanilla-js, react, react-js, r3f, r3f-js (default: vanilla)"
|
|
2399
|
-
).option("--linter <type>", "linter: eslint, oxlint, or biome (default: oxlint)").option("--formatter <type>", "formatter: prettier, oxfmt, or biome (default: prettier)").option("--drei", "add @react-three/drei (r3f only)").option("--handle", "add @react-three/handle (r3f only)").option("--leva", "add leva (r3f only)").option("--postprocessing", "add @react-three/postprocessing (r3f only)").option("--rapier", "add @react-three/rapier (r3f only)").option("--xr", "add @react-three/xr (r3f only)").option("--uikit", "add @react-three/uikit (r3f only)").option("--offscreen", "add @react-three/offscreen (r3f only)").option("--zustand", "add zustand (r3f only)").option("--koota", "add koota (r3f only)").option("--triplex", "set up triplex development environment (r3f only)").option("--viverse", "set up viverse deployment (r3f only)").option("--package-manager <manager>", "specify package manager (e.g. npm, yarn, pnpm)").option("--ide <ide>", "IDE files: vscode or none (default: vscode)").option(
|
|
2688
|
+
).option("--linter <type>", "linter: eslint, oxlint, or biome (default: oxlint)").option("--formatter <type>", "formatter: prettier, oxfmt, or biome (default: prettier)").option("--drei", "add @react-three/drei (r3f only)").option("--handle", "add @react-three/handle (r3f only)").option("--leva", "add leva (r3f only)").option("--postprocessing", "add @react-three/postprocessing (r3f only)").option("--rapier", "add @react-three/rapier (r3f only)").option("--xr", "add @react-three/xr (r3f only)").option("--uikit", "add @react-three/uikit (r3f only)").option("--offscreen", "add @react-three/offscreen (r3f only)").option("--zustand", "add zustand (r3f only)").option("--koota", "add koota (r3f only)").option("--triplex", "set up triplex development environment (r3f only)").option("--viverse", "set up viverse deployment (r3f only)").option("--package-manager <manager>", "specify package manager (e.g. npm, yarn, pnpm@11)").option("--ide <ide>", "IDE files: vscode or none (default: vscode)").option(
|
|
2400
2689
|
"--pnpm-manage-versions",
|
|
2401
2690
|
"enable manage-package-manager-versions in pnpm-workspace.yaml (default: true)"
|
|
2402
2691
|
).option(
|
|
@@ -2422,6 +2711,12 @@ async function main() {
|
|
|
2422
2711
|
console.error(color.red("Error:") + ' --ide must be "vscode" or "none"');
|
|
2423
2712
|
process.exit(1);
|
|
2424
2713
|
}
|
|
2714
|
+
const packageManagerSpec = parsePackageManagerSpec(options.packageManager);
|
|
2715
|
+
if (options.packageManager && packageManagerSpec == null) {
|
|
2716
|
+
console.error(color.red("Error:") + " --package-manager must be npm, yarn, or pnpm");
|
|
2717
|
+
console.log(color.dim(" Version specs are allowed, e.g. pnpm@10 or pnpm@11"));
|
|
2718
|
+
process.exit(1);
|
|
2719
|
+
}
|
|
2425
2720
|
if (name?.startsWith("-")) {
|
|
2426
2721
|
switch (name) {
|
|
2427
2722
|
case "--version":
|
|
@@ -2507,7 +2802,7 @@ async function main() {
|
|
|
2507
2802
|
viverse: options.viverse ? {} : void 0,
|
|
2508
2803
|
triplex: options.triplex ? {} : void 0
|
|
2509
2804
|
},
|
|
2510
|
-
packageManager:
|
|
2805
|
+
packageManager: packageManagerSpec,
|
|
2511
2806
|
pnpmManageVersions: options.pnpmManageVersions,
|
|
2512
2807
|
engine: { name: "node", version: options.nodeVersion ?? "latest" }
|
|
2513
2808
|
};
|
|
@@ -2518,7 +2813,7 @@ async function main() {
|
|
|
2518
2813
|
bundler: options.bundler,
|
|
2519
2814
|
linter: options.linter,
|
|
2520
2815
|
formatter: options.formatter,
|
|
2521
|
-
packageManager:
|
|
2816
|
+
packageManager: packageManagerSpec,
|
|
2522
2817
|
ide: options.ide,
|
|
2523
2818
|
engine: options.nodeVersion ? { name: "node", version: options.nodeVersion } : void 0,
|
|
2524
2819
|
pnpmManageVersions: options.pnpmManageVersions,
|