create-krispya 0.13.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 +476 -188
- 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 +483 -194
- 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.B2px1YOh.mjs → create-krispya.BYCdQkPo.mjs} +634 -380
- package/dist/shared/{create-krispya.CiGwBdQ3.cjs → create-krispya.Wf4wp5cQ.cjs} +664 -379
- package/package.json +9 -9
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 = [];
|
|
@@ -113,8 +114,9 @@ function formatMonorepoConfigSummary(options) {
|
|
|
113
114
|
lines.push(
|
|
114
115
|
formatRow("Engine", `${getEngineName(options.engine)}@${options.engine.version ?? "latest"}`)
|
|
115
116
|
);
|
|
116
|
-
|
|
117
|
-
|
|
117
|
+
const packageManagerName = getPackageManagerName(options.packageManager);
|
|
118
|
+
lines.push(formatRow("Package manager", packageManagerName));
|
|
119
|
+
if (packageManagerName === "pnpm") {
|
|
118
120
|
const versionManaged = options.pnpmManageVersions ? "yes" : "no";
|
|
119
121
|
lines.push(formatRow("\u21B3 Version managed", versionManaged, ""));
|
|
120
122
|
}
|
|
@@ -124,22 +126,6 @@ function formatMonorepoConfigSummary(options) {
|
|
|
124
126
|
return lines.join("\n");
|
|
125
127
|
}
|
|
126
128
|
|
|
127
|
-
const config = new Conf({
|
|
128
|
-
projectName: "create-krispya"
|
|
129
|
-
});
|
|
130
|
-
function getAiPlatforms() {
|
|
131
|
-
return config.get("aiPlatforms");
|
|
132
|
-
}
|
|
133
|
-
function getConfigStrategy() {
|
|
134
|
-
return config.get("configStrategy") ?? "stealth";
|
|
135
|
-
}
|
|
136
|
-
function clearConfig() {
|
|
137
|
-
config.clear();
|
|
138
|
-
}
|
|
139
|
-
function getConfigPath() {
|
|
140
|
-
return config.path;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
129
|
const R3F_INTEGRATION_OPTIONS = [
|
|
144
130
|
{ value: "drei", label: "Drei" },
|
|
145
131
|
{ value: "handle", label: "Handle" },
|
|
@@ -253,7 +239,7 @@ async function promptForCustomization(template, name, projectType, features, inh
|
|
|
253
239
|
libraryBundler = bundler;
|
|
254
240
|
}
|
|
255
241
|
let engine = inheritedSettings?.engine ?? presets?.engine ?? { name: "node", version: "latest" };
|
|
256
|
-
let finalPackageManager = inheritedSettings?.packageManager?.name ?? presets?.packageManager ?? "pnpm";
|
|
242
|
+
let finalPackageManager = inheritedSettings?.packageManager?.name ?? presets?.packageManager?.name ?? "pnpm";
|
|
257
243
|
let pnpmManageVersions = inheritedSettings?.pnpmManageVersions ?? presets?.pnpmManageVersions ?? true;
|
|
258
244
|
if (!inheritedSettings?.engine?.version) {
|
|
259
245
|
const nodeVersionInput = await p.text({
|
|
@@ -261,7 +247,7 @@ async function promptForCustomization(template, name, projectType, features, inh
|
|
|
261
247
|
placeholder: presets?.engine?.version ?? "latest",
|
|
262
248
|
defaultValue: presets?.engine?.version ?? "latest",
|
|
263
249
|
validate: (value) => {
|
|
264
|
-
if (!value
|
|
250
|
+
if (!value?.length) return "Required";
|
|
265
251
|
if (value !== "latest" && !/^\d+(\.\d+(\.\d+)?)?$/.test(value)) {
|
|
266
252
|
return 'Must be "latest" or a valid semver (e.g., "22" or "22.13.0")';
|
|
267
253
|
}
|
|
@@ -281,7 +267,7 @@ async function promptForCustomization(template, name, projectType, features, inh
|
|
|
281
267
|
{ value: "npm", label: "npm" },
|
|
282
268
|
{ value: "yarn", label: "yarn" }
|
|
283
269
|
],
|
|
284
|
-
initialValue: presets?.packageManager ?? "pnpm"
|
|
270
|
+
initialValue: presets?.packageManager?.name ?? "pnpm"
|
|
285
271
|
});
|
|
286
272
|
if (p.isCancel(packageManager)) {
|
|
287
273
|
p.cancel("Operation cancelled.");
|
|
@@ -390,7 +376,7 @@ async function promptForCustomization(template, name, projectType, features, inh
|
|
|
390
376
|
projectType,
|
|
391
377
|
libraryBundler: projectType === "library" ? libraryBundler : void 0,
|
|
392
378
|
engine,
|
|
393
|
-
packageManager: { name: finalPackageManager },
|
|
379
|
+
packageManager: presets?.packageManager?.name === finalPackageManager ? presets.packageManager : { name: finalPackageManager },
|
|
394
380
|
pnpmManageVersions,
|
|
395
381
|
linter,
|
|
396
382
|
formatter,
|
|
@@ -437,7 +423,7 @@ async function promptForMonorepoCustomization(name, presets) {
|
|
|
437
423
|
placeholder: presets?.engine?.version ?? "latest",
|
|
438
424
|
defaultValue: presets?.engine?.version ?? "latest",
|
|
439
425
|
validate: (value) => {
|
|
440
|
-
if (!value
|
|
426
|
+
if (!value?.length) return "Required";
|
|
441
427
|
if (value !== "latest" && !/^\d+(\.\d+(\.\d+)?)?$/.test(value)) {
|
|
442
428
|
return 'Must be "latest" or a valid semver (e.g., "22" or "22.13.0")';
|
|
443
429
|
}
|
|
@@ -518,7 +504,7 @@ async function promptForMonorepo(workspaceName, presets) {
|
|
|
518
504
|
formatMonorepoConfigSummary({
|
|
519
505
|
name: defaultOptions.name,
|
|
520
506
|
engine: defaultOptions.engine ?? { name: "node", version: "latest" },
|
|
521
|
-
packageManager:
|
|
507
|
+
packageManager: defaultOptions.packageManager ?? { name: "pnpm" },
|
|
522
508
|
pnpmManageVersions: defaultOptions.pnpmManageVersions,
|
|
523
509
|
linter: defaultOptions.linter ?? "oxlint",
|
|
524
510
|
formatter: defaultOptions.formatter ?? "prettier",
|
|
@@ -539,7 +525,7 @@ async function promptForOptions(name, presets) {
|
|
|
539
525
|
placeholder: generateRandomName(),
|
|
540
526
|
defaultValue: generateRandomName(),
|
|
541
527
|
validate: (value) => {
|
|
542
|
-
if (!value
|
|
528
|
+
if (!value?.length) return "Project name is required";
|
|
543
529
|
}
|
|
544
530
|
});
|
|
545
531
|
if (p.isCancel(nameResult)) {
|
|
@@ -571,7 +557,7 @@ function presetsToInheritedSettings(presets) {
|
|
|
571
557
|
return {
|
|
572
558
|
linter: presets.linter,
|
|
573
559
|
formatter: presets.formatter,
|
|
574
|
-
packageManager: presets.packageManager
|
|
560
|
+
packageManager: presets.packageManager,
|
|
575
561
|
engine: presets.engine,
|
|
576
562
|
pnpmManageVersions: presets.pnpmManageVersions
|
|
577
563
|
};
|
|
@@ -656,54 +642,9 @@ async function promptForAiAgentPlatforms(isNonInteractive) {
|
|
|
656
642
|
return selected;
|
|
657
643
|
}
|
|
658
644
|
|
|
659
|
-
async function checkAnyExists(paths) {
|
|
660
|
-
for (const path of paths) {
|
|
661
|
-
try {
|
|
662
|
-
await access(path, constants.F_OK);
|
|
663
|
-
return true;
|
|
664
|
-
} catch {
|
|
665
|
-
}
|
|
666
|
-
}
|
|
667
|
-
return false;
|
|
668
|
-
}
|
|
669
|
-
async function validateWorkspace(monorepoRoot) {
|
|
670
|
-
const errors = [];
|
|
671
|
-
const tsConfigPath = join(monorepoRoot, ".config/typescript/package.json");
|
|
672
|
-
try {
|
|
673
|
-
await access(tsConfigPath, constants.F_OK);
|
|
674
|
-
} catch {
|
|
675
|
-
errors.push("Missing .config/typescript package");
|
|
676
|
-
}
|
|
677
|
-
const linterPaths = [
|
|
678
|
-
join(monorepoRoot, ".config/oxlint/package.json"),
|
|
679
|
-
join(monorepoRoot, ".config/eslint/package.json"),
|
|
680
|
-
join(monorepoRoot, "eslint.config.js"),
|
|
681
|
-
join(monorepoRoot, "biome.json")
|
|
682
|
-
];
|
|
683
|
-
const hasLinter = await checkAnyExists(linterPaths);
|
|
684
|
-
if (!hasLinter) {
|
|
685
|
-
errors.push(
|
|
686
|
-
"Missing linter config (.config/oxlint, .config/eslint, eslint.config.js, or biome.json)"
|
|
687
|
-
);
|
|
688
|
-
}
|
|
689
|
-
const formatterPaths = [
|
|
690
|
-
join(monorepoRoot, ".config/oxfmt/package.json"),
|
|
691
|
-
join(monorepoRoot, ".config/prettier/package.json"),
|
|
692
|
-
join(monorepoRoot, ".prettierrc.json"),
|
|
693
|
-
join(monorepoRoot, "biome.json")
|
|
694
|
-
];
|
|
695
|
-
const hasFormatter = await checkAnyExists(formatterPaths);
|
|
696
|
-
if (!hasFormatter) {
|
|
697
|
-
errors.push(
|
|
698
|
-
"Missing formatter config (.config/oxfmt, .config/prettier, .prettierrc.json, or biome.json)"
|
|
699
|
-
);
|
|
700
|
-
}
|
|
701
|
-
return { valid: errors.length === 0, errors };
|
|
702
|
-
}
|
|
703
|
-
|
|
704
645
|
async function fileExists$1(path) {
|
|
705
646
|
try {
|
|
706
|
-
await access
|
|
647
|
+
await access(path, constants.F_OK);
|
|
707
648
|
return true;
|
|
708
649
|
} catch {
|
|
709
650
|
return false;
|
|
@@ -717,9 +658,9 @@ async function detectMonorepoRoot() {
|
|
|
717
658
|
let currentDir = cwd();
|
|
718
659
|
const root = resolve("/");
|
|
719
660
|
while (currentDir !== root) {
|
|
720
|
-
const workspaceFile = join
|
|
661
|
+
const workspaceFile = join(currentDir, "pnpm-workspace.yaml");
|
|
721
662
|
try {
|
|
722
|
-
await access
|
|
663
|
+
await access(workspaceFile, constants.F_OK);
|
|
723
664
|
const content = await readFile(workspaceFile, "utf-8");
|
|
724
665
|
if (content.includes("packages:")) {
|
|
725
666
|
return currentDir;
|
|
@@ -734,16 +675,16 @@ async function detectPackageRoot() {
|
|
|
734
675
|
let currentDir = cwd();
|
|
735
676
|
const root = resolve("/");
|
|
736
677
|
while (currentDir !== root) {
|
|
737
|
-
if (await fileExists$1(join
|
|
678
|
+
if (await fileExists$1(join(currentDir, "package.json"))) {
|
|
738
679
|
return currentDir;
|
|
739
680
|
}
|
|
740
681
|
currentDir = dirname(currentDir);
|
|
741
682
|
}
|
|
742
|
-
return await fileExists$1(join
|
|
683
|
+
return await fileExists$1(join(root, "package.json")) ? root : null;
|
|
743
684
|
}
|
|
744
685
|
async function parseWorkspaceDirectories(monorepoRoot) {
|
|
745
686
|
try {
|
|
746
|
-
const workspaceFile = join
|
|
687
|
+
const workspaceFile = join(monorepoRoot, "pnpm-workspace.yaml");
|
|
747
688
|
const content = await readFile(workspaceFile, "utf-8");
|
|
748
689
|
return parseWorkspaceYamlContent(content);
|
|
749
690
|
} catch {
|
|
@@ -753,14 +694,14 @@ async function parseWorkspaceDirectories(monorepoRoot) {
|
|
|
753
694
|
async function detectWorkspaceSettings(monorepoRoot) {
|
|
754
695
|
try {
|
|
755
696
|
const tooling = await detectTooling(monorepoRoot);
|
|
756
|
-
const pkgPath = join
|
|
697
|
+
const pkgPath = join(monorepoRoot, "package.json");
|
|
757
698
|
const content = await readFile(pkgPath, "utf-8");
|
|
758
699
|
const pkgJson = JSON.parse(content);
|
|
759
|
-
const packageManager =
|
|
700
|
+
const packageManager = parsePackageManagerSpec(pkgJson.packageManager);
|
|
760
701
|
const engine = parseEngine(pkgJson.engines);
|
|
761
702
|
let pnpmManageVersions;
|
|
762
703
|
try {
|
|
763
|
-
const workspaceFile = join
|
|
704
|
+
const workspaceFile = join(monorepoRoot, "pnpm-workspace.yaml");
|
|
764
705
|
const workspaceContent = await readFile(workspaceFile, "utf-8");
|
|
765
706
|
pnpmManageVersions = workspaceContent.includes("manage-package-manager-versions: true");
|
|
766
707
|
} catch {
|
|
@@ -778,17 +719,17 @@ async function detectWorkspaceSettings(monorepoRoot) {
|
|
|
778
719
|
}
|
|
779
720
|
async function detectExistingConfigs(monorepoRoot) {
|
|
780
721
|
const configs = {};
|
|
781
|
-
const eslintPath = join
|
|
722
|
+
const eslintPath = join(monorepoRoot, "eslint.config.js");
|
|
782
723
|
if (await fileExists$1(eslintPath)) {
|
|
783
724
|
configs.linter = "eslint";
|
|
784
725
|
configs.eslintConfigPath = eslintPath;
|
|
785
726
|
}
|
|
786
|
-
const prettierPath = join
|
|
727
|
+
const prettierPath = join(monorepoRoot, ".prettierrc.json");
|
|
787
728
|
if (await fileExists$1(prettierPath)) {
|
|
788
729
|
configs.formatter = "prettier";
|
|
789
730
|
configs.prettierConfigPath = prettierPath;
|
|
790
731
|
}
|
|
791
|
-
const biomePath = join
|
|
732
|
+
const biomePath = join(monorepoRoot, "biome.json");
|
|
792
733
|
if (await fileExists$1(biomePath)) {
|
|
793
734
|
configs.biomeConfigPath = biomePath;
|
|
794
735
|
if (!configs.linter) configs.linter = "biome";
|
|
@@ -798,7 +739,7 @@ async function detectExistingConfigs(monorepoRoot) {
|
|
|
798
739
|
}
|
|
799
740
|
async function getMonorepoScope(monorepoRoot) {
|
|
800
741
|
try {
|
|
801
|
-
const pkgPath = join
|
|
742
|
+
const pkgPath = join(monorepoRoot, "package.json");
|
|
802
743
|
const content = await readFile(pkgPath, "utf-8");
|
|
803
744
|
const pkgJson = JSON.parse(content);
|
|
804
745
|
if (pkgJson.name) {
|
|
@@ -809,14 +750,14 @@ async function getMonorepoScope(monorepoRoot) {
|
|
|
809
750
|
return monorepoRoot.split(/[/\\]/).pop() ?? "workspace";
|
|
810
751
|
}
|
|
811
752
|
async function getWorkspacePackages(monorepoRoot) {
|
|
812
|
-
const packagesDir = join
|
|
753
|
+
const packagesDir = join(monorepoRoot, "packages");
|
|
813
754
|
try {
|
|
814
755
|
const entries = await readdir(packagesDir, { withFileTypes: true });
|
|
815
756
|
const names = [];
|
|
816
757
|
for (const entry of entries) {
|
|
817
758
|
if (!entry.isDirectory()) continue;
|
|
818
759
|
try {
|
|
819
|
-
const content = await readFile(join
|
|
760
|
+
const content = await readFile(join(packagesDir, entry.name, "package.json"), "utf-8");
|
|
820
761
|
const pkg = JSON.parse(content);
|
|
821
762
|
if (pkg.name) names.push(pkg.name);
|
|
822
763
|
} catch {
|
|
@@ -828,7 +769,7 @@ async function getWorkspacePackages(monorepoRoot) {
|
|
|
828
769
|
}
|
|
829
770
|
}
|
|
830
771
|
async function ensureConfigInWorkspace(monorepoRoot) {
|
|
831
|
-
const workspacePath = join
|
|
772
|
+
const workspacePath = join(monorepoRoot, "pnpm-workspace.yaml");
|
|
832
773
|
let content;
|
|
833
774
|
try {
|
|
834
775
|
content = await readFile(workspacePath, "utf-8");
|
|
@@ -878,7 +819,7 @@ async function handleCheckCommand() {
|
|
|
878
819
|
|
|
879
820
|
async function migrateEslintConfig(monorepoRoot, files) {
|
|
880
821
|
const configBasePath = ".config/eslint";
|
|
881
|
-
const existingConfigPath = join
|
|
822
|
+
const existingConfigPath = join(monorepoRoot, "eslint.config.js");
|
|
882
823
|
let existingContent;
|
|
883
824
|
try {
|
|
884
825
|
existingContent = await readFile(existingConfigPath, "utf-8");
|
|
@@ -957,7 +898,7 @@ export default [
|
|
|
957
898
|
}
|
|
958
899
|
async function migratePrettierConfig(monorepoRoot, files) {
|
|
959
900
|
const configBasePath = ".config/prettier";
|
|
960
|
-
const existingConfigPath = join
|
|
901
|
+
const existingConfigPath = join(monorepoRoot, ".prettierrc.json");
|
|
961
902
|
let existingContent;
|
|
962
903
|
try {
|
|
963
904
|
existingContent = await readFile(existingConfigPath, "utf-8");
|
|
@@ -1093,15 +1034,15 @@ async function handleFixCommand(options) {
|
|
|
1093
1034
|
spinner.start("Fixing workspace...");
|
|
1094
1035
|
try {
|
|
1095
1036
|
const files = {};
|
|
1096
|
-
const tsConfigExists = await fileExists$1(join
|
|
1037
|
+
const tsConfigExists = await fileExists$1(join(monorepoRoot, ".config/typescript/package.json"));
|
|
1097
1038
|
if (!tsConfigExists) {
|
|
1098
1039
|
renderTypescriptConfigPackage(files);
|
|
1099
1040
|
}
|
|
1100
1041
|
if (linter === "oxlint") {
|
|
1101
|
-
const oxlintExists = await fileExists$1(join
|
|
1042
|
+
const oxlintExists = await fileExists$1(join(monorepoRoot, ".config/oxlint/package.json"));
|
|
1102
1043
|
if (!oxlintExists) renderOxlintConfigPackage(files);
|
|
1103
1044
|
} else if (linter === "eslint") {
|
|
1104
|
-
const eslintPkgExists = await fileExists$1(join
|
|
1045
|
+
const eslintPkgExists = await fileExists$1(join(monorepoRoot, ".config/eslint/package.json"));
|
|
1105
1046
|
if (!eslintPkgExists) {
|
|
1106
1047
|
if (existingConfigs.eslintConfigPath) {
|
|
1107
1048
|
await migrateEslintConfig(monorepoRoot, files);
|
|
@@ -1111,10 +1052,10 @@ async function handleFixCommand(options) {
|
|
|
1111
1052
|
}
|
|
1112
1053
|
}
|
|
1113
1054
|
if (formatter === "oxfmt") {
|
|
1114
|
-
const oxfmtExists = await fileExists$1(join
|
|
1055
|
+
const oxfmtExists = await fileExists$1(join(monorepoRoot, ".config/oxfmt/package.json"));
|
|
1115
1056
|
if (!oxfmtExists) renderOxfmtConfigPackage(files);
|
|
1116
1057
|
} else if (formatter === "prettier") {
|
|
1117
|
-
const prettierPkgExists = await fileExists$1(join
|
|
1058
|
+
const prettierPkgExists = await fileExists$1(join(monorepoRoot, ".config/prettier/package.json"));
|
|
1118
1059
|
if (!prettierPkgExists) {
|
|
1119
1060
|
if (existingConfigs.prettierConfigPath) {
|
|
1120
1061
|
await migratePrettierConfig(monorepoRoot, files);
|
|
@@ -1152,7 +1093,7 @@ async function handleFixCommand(options) {
|
|
|
1152
1093
|
};
|
|
1153
1094
|
}
|
|
1154
1095
|
for (const [filePath, file] of Object.entries(files)) {
|
|
1155
|
-
const fullPath = join
|
|
1096
|
+
const fullPath = join(monorepoRoot, filePath);
|
|
1156
1097
|
await mkdir(dirname(fullPath), { recursive: true });
|
|
1157
1098
|
await writeFile(fullPath, file.content);
|
|
1158
1099
|
}
|
|
@@ -1175,8 +1116,8 @@ async function handleFixCommand(options) {
|
|
|
1175
1116
|
const pkgName = pkgFile.replace("/package.json", "");
|
|
1176
1117
|
console.log(color.dim(` Generated ${pkgName}`));
|
|
1177
1118
|
}
|
|
1178
|
-
const vscodeSettingsExists = await fileExists$1(join
|
|
1179
|
-
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"));
|
|
1180
1121
|
const vscodeExists = vscodeSettingsExists && vscodeExtensionsExists;
|
|
1181
1122
|
if (!vscodeExists) {
|
|
1182
1123
|
let addVscode = false;
|
|
@@ -1193,7 +1134,7 @@ async function handleFixCommand(options) {
|
|
|
1193
1134
|
const vscodeFiles = {};
|
|
1194
1135
|
renderVscodeFiles(vscodeFiles, linter, formatter);
|
|
1195
1136
|
for (const [filePath, file] of Object.entries(vscodeFiles)) {
|
|
1196
|
-
const fullPath = join
|
|
1137
|
+
const fullPath = join(monorepoRoot, filePath);
|
|
1197
1138
|
await mkdir(dirname(fullPath), { recursive: true });
|
|
1198
1139
|
await writeFile(fullPath, file.content);
|
|
1199
1140
|
}
|
|
@@ -1201,7 +1142,7 @@ async function handleFixCommand(options) {
|
|
|
1201
1142
|
console.log(color.dim(" Generated .vscode/extensions.json"));
|
|
1202
1143
|
}
|
|
1203
1144
|
}
|
|
1204
|
-
const aiRulesExist = await fileExists$1(join
|
|
1145
|
+
const aiRulesExist = await fileExists$1(join(monorepoRoot, ".ai/workspace.md"));
|
|
1205
1146
|
if (!aiRulesExist) {
|
|
1206
1147
|
const platforms = await promptForAiAgentPlatforms(isNonInteractive);
|
|
1207
1148
|
if (platforms.length > 0) {
|
|
@@ -1217,7 +1158,7 @@ async function handleFixCommand(options) {
|
|
|
1217
1158
|
platforms
|
|
1218
1159
|
});
|
|
1219
1160
|
for (const [filePath, file] of Object.entries(aiFilesOutput)) {
|
|
1220
|
-
const fullPath = join
|
|
1161
|
+
const fullPath = join(monorepoRoot, filePath);
|
|
1221
1162
|
await mkdir(dirname(fullPath), { recursive: true });
|
|
1222
1163
|
await writeFile(fullPath, file.content);
|
|
1223
1164
|
console.log(color.dim(` Generated ${filePath}`));
|
|
@@ -1261,18 +1202,22 @@ function renderExpectedViteConfig(template) {
|
|
|
1261
1202
|
async function detectCurrentConfig(root, isMonorepo = true) {
|
|
1262
1203
|
let name = root.split(/[/\\]/).pop() ?? "workspace";
|
|
1263
1204
|
let packageManager = "pnpm";
|
|
1205
|
+
let packageManagerSpec = { name: "pnpm" };
|
|
1206
|
+
let engine;
|
|
1264
1207
|
let hasTypecheck = false;
|
|
1265
1208
|
let viteTemplate;
|
|
1266
1209
|
try {
|
|
1267
|
-
const pkgPath = join(root, "package.json");
|
|
1210
|
+
const pkgPath = join$1(root, "package.json");
|
|
1268
1211
|
const content = await readFile$1(pkgPath, "utf-8");
|
|
1269
1212
|
const pkgJson = JSON.parse(content);
|
|
1270
1213
|
if (pkgJson.name) {
|
|
1271
1214
|
name = pkgJson.name.replace(/^@/, "").replace(/\/.*$/, "");
|
|
1272
1215
|
}
|
|
1273
1216
|
if (pkgJson.packageManager) {
|
|
1274
|
-
|
|
1217
|
+
packageManagerSpec = parsePackageManagerSpec(pkgJson.packageManager) ?? packageManagerSpec;
|
|
1218
|
+
packageManager = packageManagerSpec.name;
|
|
1275
1219
|
}
|
|
1220
|
+
engine = parseEngine(pkgJson.engines);
|
|
1276
1221
|
hasTypecheck = pkgJson.scripts?.typecheck != null;
|
|
1277
1222
|
viteTemplate = detectViteTemplate(pkgJson);
|
|
1278
1223
|
} catch {
|
|
@@ -1284,6 +1229,8 @@ async function detectCurrentConfig(root, isMonorepo = true) {
|
|
|
1284
1229
|
linter: tooling.linter ?? "oxlint",
|
|
1285
1230
|
formatter: tooling.formatter ?? "prettier",
|
|
1286
1231
|
packageManager,
|
|
1232
|
+
packageManagerSpec,
|
|
1233
|
+
engine,
|
|
1287
1234
|
isMonorepo,
|
|
1288
1235
|
configStrategy,
|
|
1289
1236
|
hasTypecheck,
|
|
@@ -1292,10 +1239,10 @@ async function detectCurrentConfig(root, isMonorepo = true) {
|
|
|
1292
1239
|
}
|
|
1293
1240
|
async function detectSinglePackageConfigStrategy(root) {
|
|
1294
1241
|
const hasStealthConfig = await Promise.all([
|
|
1295
|
-
fileExists(join(root, ".config/tsconfig.app.json")),
|
|
1296
|
-
fileExists(join(root, ".config/tsconfig.node.json")),
|
|
1297
|
-
fileExists(join(root, ".config/prettier.json")),
|
|
1298
|
-
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"))
|
|
1299
1246
|
]).then((matches) => matches.some(Boolean));
|
|
1300
1247
|
return hasStealthConfig ? "stealth" : "root";
|
|
1301
1248
|
}
|
|
@@ -1390,7 +1337,7 @@ async function planExpectedFiles(config) {
|
|
|
1390
1337
|
}
|
|
1391
1338
|
async function fileExists(path) {
|
|
1392
1339
|
try {
|
|
1393
|
-
await access(path, constants$
|
|
1340
|
+
await access$1(path, constants$1.F_OK);
|
|
1394
1341
|
return true;
|
|
1395
1342
|
} catch {
|
|
1396
1343
|
return false;
|
|
@@ -1529,7 +1476,7 @@ async function compareWithDisk(expected, root) {
|
|
|
1529
1476
|
const changes = [];
|
|
1530
1477
|
for (const [filePath, file] of Object.entries(files)) {
|
|
1531
1478
|
if (file.type !== "text") continue;
|
|
1532
|
-
const fullPath = join(root, filePath);
|
|
1479
|
+
const fullPath = join$1(root, filePath);
|
|
1533
1480
|
const newContent = file.content;
|
|
1534
1481
|
if (await fileExists(fullPath)) {
|
|
1535
1482
|
const currentContent = await readFile$1(fullPath, "utf-8");
|
|
@@ -1604,13 +1551,13 @@ function addMissingDevDependency(pkg, devDependencies, name) {
|
|
|
1604
1551
|
}
|
|
1605
1552
|
async function detectTypeScriptPackage(root, pkg) {
|
|
1606
1553
|
if (hasPackage(pkg, "typescript")) return true;
|
|
1607
|
-
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"));
|
|
1608
1555
|
}
|
|
1609
1556
|
function detectLibraryPackage(pkg) {
|
|
1610
1557
|
return pkg.exports != null || pkg.main?.includes("dist") === true || pkg.module?.includes("dist") === true || Array.isArray(pkg.files) && pkg.files.includes("dist");
|
|
1611
1558
|
}
|
|
1612
1559
|
function getPackageManagerForScripts(config, pkg) {
|
|
1613
|
-
const packageManager = pkg.packageManager?.
|
|
1560
|
+
const packageManager = parsePackageManagerSpec(pkg.packageManager)?.name ?? config.packageManager;
|
|
1614
1561
|
return isPackageManagerName(packageManager) ? packageManager : "pnpm";
|
|
1615
1562
|
}
|
|
1616
1563
|
function getSinglePackageToolScripts(config) {
|
|
@@ -1640,6 +1587,35 @@ function scriptsEqual(left, right) {
|
|
|
1640
1587
|
if (leftEntries.length !== Object.keys(right).length) return false;
|
|
1641
1588
|
return leftEntries.every(([key, value]) => right[key] === value);
|
|
1642
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
|
+
}
|
|
1643
1619
|
async function getExpectedPackageScripts(root, config, pkg) {
|
|
1644
1620
|
if (config.isMonorepo) {
|
|
1645
1621
|
return packageJsonScripts.monorepoRoot(config.linter, config.formatter);
|
|
@@ -1678,7 +1654,7 @@ async function getExpectedPackageDevDependencies(root, config, pkg) {
|
|
|
1678
1654
|
return sortPackageMap(nextDevDependencies);
|
|
1679
1655
|
}
|
|
1680
1656
|
async function getPackageJsonScriptUpdates(root, config) {
|
|
1681
|
-
const packageJsonPath = join(root, "package.json");
|
|
1657
|
+
const packageJsonPath = join$1(root, "package.json");
|
|
1682
1658
|
let currentContent;
|
|
1683
1659
|
try {
|
|
1684
1660
|
currentContent = await readFile$1(packageJsonPath, "utf-8");
|
|
@@ -1691,7 +1667,9 @@ async function getPackageJsonScriptUpdates(root, config) {
|
|
|
1691
1667
|
const nextScripts = mergePackageJsonScripts(currentScripts, expectedScripts);
|
|
1692
1668
|
const currentDevDependencies = pkg.devDependencies ?? {};
|
|
1693
1669
|
const nextDevDependencies = await getExpectedPackageDevDependencies(root, config, pkg);
|
|
1694
|
-
|
|
1670
|
+
const targetPackageManagerSpec = config.targetPackageManagerSpec;
|
|
1671
|
+
const targetNodeVersion = config.targetNodeVersion;
|
|
1672
|
+
if (scriptsEqual(currentScripts, nextScripts) && scriptsEqual(currentDevDependencies, nextDevDependencies) && packageManagerFieldsEqual(pkg, targetPackageManagerSpec, targetNodeVersion)) {
|
|
1695
1673
|
return [
|
|
1696
1674
|
{
|
|
1697
1675
|
path: "package.json",
|
|
@@ -1701,10 +1679,14 @@ async function getPackageJsonScriptUpdates(root, config) {
|
|
|
1701
1679
|
}
|
|
1702
1680
|
];
|
|
1703
1681
|
}
|
|
1704
|
-
const nextPackageJson =
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1682
|
+
const nextPackageJson = applyPackageManagerFields(
|
|
1683
|
+
{
|
|
1684
|
+
...pkg,
|
|
1685
|
+
scripts: nextScripts
|
|
1686
|
+
},
|
|
1687
|
+
targetPackageManagerSpec,
|
|
1688
|
+
targetNodeVersion
|
|
1689
|
+
);
|
|
1708
1690
|
if (Object.keys(nextDevDependencies).length > 0 || pkg.devDependencies != null) {
|
|
1709
1691
|
nextPackageJson.devDependencies = nextDevDependencies;
|
|
1710
1692
|
}
|
|
@@ -1719,6 +1701,41 @@ async function getPackageJsonScriptUpdates(root, config) {
|
|
|
1719
1701
|
}
|
|
1720
1702
|
];
|
|
1721
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
|
+
}
|
|
1722
1739
|
function planSinglePackageOxlintConfig(config) {
|
|
1723
1740
|
if (config.linter !== "oxlint" || config.isMonorepo) return void 0;
|
|
1724
1741
|
const isStealth = (config.configStrategy ?? "stealth") === "stealth";
|
|
@@ -1739,7 +1756,7 @@ function planSinglePackageOxlintConfig(config) {
|
|
|
1739
1756
|
async function getOxlintConfigReplacementUpdates(root, config) {
|
|
1740
1757
|
const expected = planSinglePackageOxlintConfig(config);
|
|
1741
1758
|
if (expected == null) return [];
|
|
1742
|
-
const fullPath = join(root, expected.path);
|
|
1759
|
+
const fullPath = join$1(root, expected.path);
|
|
1743
1760
|
let currentContent;
|
|
1744
1761
|
try {
|
|
1745
1762
|
currentContent = await readFile$1(fullPath, "utf-8");
|
|
@@ -1764,9 +1781,105 @@ async function getOxlintConfigReplacementUpdates(root, config) {
|
|
|
1764
1781
|
}
|
|
1765
1782
|
];
|
|
1766
1783
|
}
|
|
1767
|
-
|
|
1768
|
-
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");
|
|
1769
1879
|
const changes = [];
|
|
1880
|
+
const packageManagerSpec = config?.targetPackageManagerSpec ?? config?.packageManagerSpec ?? { name: "pnpm" };
|
|
1881
|
+
const profile = getPackageManagerProfile(packageManagerSpec);
|
|
1882
|
+
const defaultPackages = [".config/*", "apps/*", "packages/*"];
|
|
1770
1883
|
let currentContent = "";
|
|
1771
1884
|
let exists = false;
|
|
1772
1885
|
try {
|
|
@@ -1775,15 +1888,11 @@ async function getWorkspaceConfigUpdates(root) {
|
|
|
1775
1888
|
} catch {
|
|
1776
1889
|
}
|
|
1777
1890
|
if (!exists) {
|
|
1778
|
-
const newContent =
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
- 'packages/*'
|
|
1784
|
-
|
|
1785
|
-
onlyBuiltDependencies:
|
|
1786
|
-
- esbuild
|
|
1891
|
+
const newContent = `${renderPnpmWorkspaceConfig({
|
|
1892
|
+
profile,
|
|
1893
|
+
manageVersions: true,
|
|
1894
|
+
packages: defaultPackages
|
|
1895
|
+
})}
|
|
1787
1896
|
`;
|
|
1788
1897
|
changes.push({
|
|
1789
1898
|
path: "pnpm-workspace.yaml",
|
|
@@ -1792,32 +1901,14 @@ onlyBuiltDependencies:
|
|
|
1792
1901
|
});
|
|
1793
1902
|
return changes;
|
|
1794
1903
|
}
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
needsUpdate = true;
|
|
1802
|
-
}
|
|
1803
|
-
if (!currentContent.includes("onlyBuiltDependencies")) {
|
|
1804
|
-
updatedContent = `${updatedContent.trimEnd()}
|
|
1805
|
-
|
|
1806
|
-
onlyBuiltDependencies:
|
|
1807
|
-
- esbuild
|
|
1904
|
+
const buildDependencies = withDefaultBuildDependencies(extractBuildDependencies(currentContent));
|
|
1905
|
+
const updatedContent = `${patchPnpmWorkspaceManagedKeys(
|
|
1906
|
+
currentContent,
|
|
1907
|
+
profile,
|
|
1908
|
+
buildDependencies
|
|
1909
|
+
)}
|
|
1808
1910
|
`;
|
|
1809
|
-
|
|
1810
|
-
}
|
|
1811
|
-
if (!currentContent.includes(".config/*")) {
|
|
1812
|
-
const lines = updatedContent.split("\n");
|
|
1813
|
-
const packagesIndex = lines.findIndex((line) => line.trim().startsWith("packages:"));
|
|
1814
|
-
if (packagesIndex !== -1) {
|
|
1815
|
-
lines.splice(packagesIndex + 1, 0, " - '.config/*'");
|
|
1816
|
-
updatedContent = lines.join("\n");
|
|
1817
|
-
needsUpdate = true;
|
|
1818
|
-
}
|
|
1819
|
-
}
|
|
1820
|
-
if (needsUpdate) {
|
|
1911
|
+
if (updatedContent !== currentContent) {
|
|
1821
1912
|
changes.push({
|
|
1822
1913
|
path: "pnpm-workspace.yaml",
|
|
1823
1914
|
status: "modified",
|
|
@@ -1837,7 +1928,7 @@ onlyBuiltDependencies:
|
|
|
1837
1928
|
async function applyUpdates(changes, root) {
|
|
1838
1929
|
for (const change of changes) {
|
|
1839
1930
|
if (change.status === "unchanged") continue;
|
|
1840
|
-
const fullPath = join(root, change.path);
|
|
1931
|
+
const fullPath = join$1(root, change.path);
|
|
1841
1932
|
await mkdir$1(dirname$1(fullPath), { recursive: true });
|
|
1842
1933
|
await writeFile$1(fullPath, change.newContent);
|
|
1843
1934
|
}
|
|
@@ -1915,6 +2006,96 @@ function orderUpdateCategories(categories) {
|
|
|
1915
2006
|
(left, right) => getCategoryOrder(left.category) - getCategoryOrder(right.category)
|
|
1916
2007
|
);
|
|
1917
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
|
+
}
|
|
1918
2099
|
async function collectUpdateCategories(projectRoot, config, isMonorepo) {
|
|
1919
2100
|
const expected = await planExpectedFiles(config);
|
|
1920
2101
|
const categories = await compareWithDisk(expected, projectRoot);
|
|
@@ -1938,7 +2119,7 @@ async function collectUpdateCategories(projectRoot, config, isMonorepo) {
|
|
|
1938
2119
|
});
|
|
1939
2120
|
}
|
|
1940
2121
|
if (isMonorepo) {
|
|
1941
|
-
const workspaceConfigChanges = await getWorkspaceConfigUpdates(projectRoot);
|
|
2122
|
+
const workspaceConfigChanges = await getWorkspaceConfigUpdates(projectRoot, config);
|
|
1942
2123
|
if (workspaceConfigChanges.length > 0) {
|
|
1943
2124
|
allCategories.push({
|
|
1944
2125
|
category: "workspace-config",
|
|
@@ -1950,6 +2131,110 @@ async function collectUpdateCategories(projectRoot, config, isMonorepo) {
|
|
|
1950
2131
|
}
|
|
1951
2132
|
return orderUpdateCategories(allCategories);
|
|
1952
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
|
+
}
|
|
1953
2238
|
async function processUpdateCategory(category, projectRoot, options) {
|
|
1954
2239
|
const newChanges = category.changes.filter((change) => change.status === "added");
|
|
1955
2240
|
const modifiedChanges = category.changes.filter((change) => change.status === "modified");
|
|
@@ -1989,11 +2274,8 @@ async function processUpdateCategory(category, projectRoot, options) {
|
|
|
1989
2274
|
if (addedCount > 0) parts.push(`added ${addedCount}`);
|
|
1990
2275
|
if (updatedFilesCount > 0) parts.push(`updated ${updatedFilesCount}`);
|
|
1991
2276
|
console.log(color.green("\u2713") + ` ${category.label}: ${parts.join(", ")}`);
|
|
1992
|
-
console.log();
|
|
1993
2277
|
return "updated";
|
|
1994
2278
|
}
|
|
1995
|
-
console.log(color.dim(` Skipped ${category.label}`));
|
|
1996
|
-
console.log();
|
|
1997
2279
|
return "skipped";
|
|
1998
2280
|
}
|
|
1999
2281
|
async function handleUpdateCommand(options, handleFixCommand) {
|
|
@@ -2059,6 +2341,8 @@ async function handleUpdateCommand(options, handleFixCommand) {
|
|
|
2059
2341
|
console.log(color.dim(` Skipped ${skippedCount}`));
|
|
2060
2342
|
}
|
|
2061
2343
|
}
|
|
2344
|
+
const finalConfig = await applyPackageManagerMigration(projectRoot, isMonorepo, options, config);
|
|
2345
|
+
await promptForPackageUpdate(projectRoot, finalConfig, options);
|
|
2062
2346
|
process.exit(0);
|
|
2063
2347
|
}
|
|
2064
2348
|
|
|
@@ -2076,12 +2360,13 @@ async function createPackageInWorkspace(monorepoRoot, packageManager, inheritedS
|
|
|
2076
2360
|
message: "Package name?",
|
|
2077
2361
|
initialValue: `@${scope}/`,
|
|
2078
2362
|
validate: (value) => {
|
|
2079
|
-
const
|
|
2363
|
+
const packageName = value ?? "";
|
|
2364
|
+
const validationError = validatePackageName(packageName);
|
|
2080
2365
|
if (validationError) return validationError;
|
|
2081
|
-
const dirName =
|
|
2366
|
+
const dirName = getPackageDirectoryName(packageName);
|
|
2082
2367
|
if (!dirName) return "Package name is required";
|
|
2083
2368
|
if (!hasCustomDirectories) {
|
|
2084
|
-
const targetPath = join
|
|
2369
|
+
const targetPath = join(monorepoRoot, defaultDir, dirName);
|
|
2085
2370
|
try {
|
|
2086
2371
|
const { statSync } = require$2("fs");
|
|
2087
2372
|
statSync(targetPath);
|
|
@@ -2095,7 +2380,7 @@ async function createPackageInWorkspace(monorepoRoot, packageManager, inheritedS
|
|
|
2095
2380
|
return false;
|
|
2096
2381
|
}
|
|
2097
2382
|
const scopedName = packageNameInput;
|
|
2098
|
-
const shortName =
|
|
2383
|
+
const shortName = getPackageDirectoryName(scopedName);
|
|
2099
2384
|
const packageOptions = await promptForPackageOptions(scopedName, packageType, inheritedSettings);
|
|
2100
2385
|
let targetDir = defaultDir;
|
|
2101
2386
|
if (hasCustomDirectories && workspaceDirectories.length > 0) {
|
|
@@ -2111,7 +2396,7 @@ async function createPackageInWorkspace(monorepoRoot, packageManager, inheritedS
|
|
|
2111
2396
|
return false;
|
|
2112
2397
|
}
|
|
2113
2398
|
targetDir = dirChoice;
|
|
2114
|
-
const targetPath = join
|
|
2399
|
+
const targetPath = join(monorepoRoot, targetDir, shortName);
|
|
2115
2400
|
try {
|
|
2116
2401
|
const { statSync } = require$2("fs");
|
|
2117
2402
|
statSync(targetPath);
|
|
@@ -2120,7 +2405,7 @@ async function createPackageInWorkspace(monorepoRoot, packageManager, inheritedS
|
|
|
2120
2405
|
} catch {
|
|
2121
2406
|
}
|
|
2122
2407
|
}
|
|
2123
|
-
const relativePkgPath = join
|
|
2408
|
+
const relativePkgPath = join(targetDir, shortName);
|
|
2124
2409
|
const workspaceRoot = calculateWorkspaceRoot(relativePkgPath);
|
|
2125
2410
|
packageOptions.workspaceRoot = workspaceRoot;
|
|
2126
2411
|
packageOptions.name = scopedName;
|
|
@@ -2135,7 +2420,7 @@ async function createPackageInWorkspace(monorepoRoot, packageManager, inheritedS
|
|
|
2135
2420
|
packageOptions.workspaceDependencies = selectedDeps;
|
|
2136
2421
|
}
|
|
2137
2422
|
}
|
|
2138
|
-
const outputPath = join
|
|
2423
|
+
const outputPath = join(monorepoRoot, relativePkgPath);
|
|
2139
2424
|
const spinner = p.spinner();
|
|
2140
2425
|
spinner.start("Creating package...");
|
|
2141
2426
|
try {
|
|
@@ -2176,10 +2461,11 @@ async function handleWorkspaceCommand(name, options, writeGeneratedFiles) {
|
|
|
2176
2461
|
const template = options.template ?? "vanilla";
|
|
2177
2462
|
const baseTemplate = getBaseTemplate(template);
|
|
2178
2463
|
const scopedName = name.startsWith("@") ? name : `@${scope}/${name}`;
|
|
2179
|
-
const
|
|
2464
|
+
const packageDirName = getPackageDirectoryName(name);
|
|
2465
|
+
const fullPackagePath = join(monorepoRoot, targetDir, packageDirName);
|
|
2180
2466
|
try {
|
|
2181
|
-
await access
|
|
2182
|
-
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`);
|
|
2183
2469
|
process.exit(1);
|
|
2184
2470
|
} catch {
|
|
2185
2471
|
}
|
|
@@ -2192,7 +2478,7 @@ async function handleWorkspaceCommand(name, options, writeGeneratedFiles) {
|
|
|
2192
2478
|
};
|
|
2193
2479
|
const pnpmManageVersions = inheritedSettings.pnpmManageVersions ?? true;
|
|
2194
2480
|
const isLibrary = projectType === "library";
|
|
2195
|
-
const relativePkgPath = join
|
|
2481
|
+
const relativePkgPath = join(targetDir, packageDirName);
|
|
2196
2482
|
const workspaceRoot = calculateWorkspaceRoot(relativePkgPath);
|
|
2197
2483
|
const projectOptions = {
|
|
2198
2484
|
name: scopedName,
|
|
@@ -2220,11 +2506,11 @@ async function handleWorkspaceCommand(name, options, writeGeneratedFiles) {
|
|
|
2220
2506
|
triplex: options.triplex ? {} : void 0
|
|
2221
2507
|
}
|
|
2222
2508
|
};
|
|
2223
|
-
console.log(color.cyan("Creating") + ` ${scopedName} in ${targetDir}/${
|
|
2509
|
+
console.log(color.cyan("Creating") + ` ${scopedName} in ${targetDir}/${packageDirName}...`);
|
|
2224
2510
|
try {
|
|
2225
2511
|
const { files } = await planProject(resolveProjectPlanInput(projectOptions));
|
|
2226
2512
|
await writeGeneratedFiles(fullPackagePath, files);
|
|
2227
|
-
console.log(color.green("\u2713") + ` Created ${scopedName} at ${targetDir}/${
|
|
2513
|
+
console.log(color.green("\u2713") + ` Created ${scopedName} at ${targetDir}/${packageDirName}`);
|
|
2228
2514
|
process.exit(0);
|
|
2229
2515
|
} catch (error) {
|
|
2230
2516
|
console.error(color.red("Error:") + " Failed to create package");
|
|
@@ -2294,7 +2580,7 @@ function hasConfigOptions(options) {
|
|
|
2294
2580
|
async function writeGeneratedFiles(basePath, files) {
|
|
2295
2581
|
const filePaths = Object.keys(files).sort();
|
|
2296
2582
|
for (const filePath of filePaths) {
|
|
2297
|
-
const fullFilePath = join
|
|
2583
|
+
const fullFilePath = join(basePath, filePath);
|
|
2298
2584
|
await mkdir(dirname(fullFilePath), { recursive: true });
|
|
2299
2585
|
const file = files[filePath];
|
|
2300
2586
|
if (file.type === "text") {
|
|
@@ -2307,7 +2593,7 @@ async function writeGeneratedFiles(basePath, files) {
|
|
|
2307
2593
|
}
|
|
2308
2594
|
async function handleMonorepoCreation(projectOptions, isNonInteractive) {
|
|
2309
2595
|
const packageManager = getPackageManagerName(projectOptions.packageManager);
|
|
2310
|
-
const projectPath = join
|
|
2596
|
+
const projectPath = join(cwd(), projectOptions.name);
|
|
2311
2597
|
const spinner = p.spinner();
|
|
2312
2598
|
spinner.start("Creating monorepo workspace...");
|
|
2313
2599
|
try {
|
|
@@ -2369,7 +2655,8 @@ async function handleSingleWorkspaceCreation(projectOptions, isNonInteractive) {
|
|
|
2369
2655
|
const defaultFallbackName = base === "vanilla" ? "vanilla-app" : base === "react" ? "react-app" : "react-three-app";
|
|
2370
2656
|
projectOptions.name ??= defaultFallbackName;
|
|
2371
2657
|
const packageManager = getPackageManagerName(projectOptions.packageManager);
|
|
2372
|
-
const
|
|
2658
|
+
const projectDirName = getPackageDirectoryName(projectOptions.name);
|
|
2659
|
+
const projectPath = join(cwd(), projectDirName);
|
|
2373
2660
|
const spinner = p.spinner();
|
|
2374
2661
|
spinner.start("Creating project...");
|
|
2375
2662
|
try {
|
|
@@ -2378,15 +2665,11 @@ async function handleSingleWorkspaceCreation(projectOptions, isNonInteractive) {
|
|
|
2378
2665
|
await writeGeneratedFiles(projectPath, files);
|
|
2379
2666
|
spinner.stop(color.green.inverse(" \u2713 Project created! "));
|
|
2380
2667
|
if (isNonInteractive) process.exit(0);
|
|
2381
|
-
const nextSteps = projectOptions.projectType === "library" ? [
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
`cd ${projectOptions.name}`,
|
|
2387
|
-
`${packageManager} install`,
|
|
2388
|
-
`${packageManager} run dev`
|
|
2389
|
-
].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
|
+
);
|
|
2390
2673
|
p.note(nextSteps, "Next steps");
|
|
2391
2674
|
p.outro(color.green("Happy coding! \u2728"));
|
|
2392
2675
|
} catch (error) {
|
|
@@ -2402,7 +2685,7 @@ async function main() {
|
|
|
2402
2685
|
).option(
|
|
2403
2686
|
"--template <type>",
|
|
2404
2687
|
"project template: vanilla, vanilla-js, react, react-js, r3f, r3f-js (default: vanilla)"
|
|
2405
|
-
).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(
|
|
2406
2689
|
"--pnpm-manage-versions",
|
|
2407
2690
|
"enable manage-package-manager-versions in pnpm-workspace.yaml (default: true)"
|
|
2408
2691
|
).option(
|
|
@@ -2428,6 +2711,12 @@ async function main() {
|
|
|
2428
2711
|
console.error(color.red("Error:") + ' --ide must be "vscode" or "none"');
|
|
2429
2712
|
process.exit(1);
|
|
2430
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
|
+
}
|
|
2431
2720
|
if (name?.startsWith("-")) {
|
|
2432
2721
|
switch (name) {
|
|
2433
2722
|
case "--version":
|
|
@@ -2513,7 +2802,7 @@ async function main() {
|
|
|
2513
2802
|
viverse: options.viverse ? {} : void 0,
|
|
2514
2803
|
triplex: options.triplex ? {} : void 0
|
|
2515
2804
|
},
|
|
2516
|
-
packageManager:
|
|
2805
|
+
packageManager: packageManagerSpec,
|
|
2517
2806
|
pnpmManageVersions: options.pnpmManageVersions,
|
|
2518
2807
|
engine: { name: "node", version: options.nodeVersion ?? "latest" }
|
|
2519
2808
|
};
|
|
@@ -2524,7 +2813,7 @@ async function main() {
|
|
|
2524
2813
|
bundler: options.bundler,
|
|
2525
2814
|
linter: options.linter,
|
|
2526
2815
|
formatter: options.formatter,
|
|
2527
|
-
packageManager:
|
|
2816
|
+
packageManager: packageManagerSpec,
|
|
2528
2817
|
ide: options.ide,
|
|
2529
2818
|
engine: options.nodeVersion ? { name: "node", version: options.nodeVersion } : void 0,
|
|
2530
2819
|
pnpmManageVersions: options.pnpmManageVersions,
|