create-krispya 0.5.1 → 0.5.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +106 -8
- package/dist/chunks/index.cjs +581 -175
- package/dist/chunks/index.mjs +571 -176
- package/dist/cli.cjs +1090 -337
- package/dist/cli.mjs +1094 -341
- package/dist/index.cjs +4 -0
- package/dist/index.d.cts +46 -1
- package/dist/index.d.mts +46 -1
- package/dist/index.d.ts +46 -1
- package/dist/index.mjs +1 -1
- package/package.json +1 -1
package/dist/chunks/index.cjs
CHANGED
|
@@ -256,6 +256,16 @@ function generatePackageJson(params) {
|
|
|
256
256
|
const majorVersion = pnpmVersion.split(".")[0];
|
|
257
257
|
engines.pnpm = `>=${majorVersion}.0.0`;
|
|
258
258
|
packageJson.packageManager = `pnpm@${pnpmVersion}`;
|
|
259
|
+
} else if (packageManager === "yarn") {
|
|
260
|
+
const yarnVersion = options.yarnVersion ?? "4.6.0";
|
|
261
|
+
const majorVersion = yarnVersion.split(".")[0];
|
|
262
|
+
engines.yarn = `>=${majorVersion}.0.0`;
|
|
263
|
+
packageJson.packageManager = `yarn@${yarnVersion}`;
|
|
264
|
+
} else if (packageManager === "npm") {
|
|
265
|
+
const npmVersion = options.npmVersion ?? "11.0.0";
|
|
266
|
+
const majorVersion = npmVersion.split(".")[0];
|
|
267
|
+
engines.npm = `>=${majorVersion}.0.0`;
|
|
268
|
+
packageJson.packageManager = `npm@${npmVersion}`;
|
|
259
269
|
}
|
|
260
270
|
if (options.nodeVersion) {
|
|
261
271
|
const majorVersion = options.nodeVersion.split(".")[0];
|
|
@@ -649,154 +659,128 @@ function generateViteConfig(params) {
|
|
|
649
659
|
return { type: "text", content: viteConfigContent };
|
|
650
660
|
}
|
|
651
661
|
|
|
652
|
-
function
|
|
653
|
-
const { name,
|
|
654
|
-
const
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
}
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
scripts: {
|
|
675
|
-
dev: "pnpm --filter './apps/*' run dev",
|
|
676
|
-
build: "pnpm --filter './packages/*' run build && pnpm --filter './apps/*' run build",
|
|
677
|
-
test: "pnpm -r run test",
|
|
678
|
-
lint: linter === "oxlint" ? "oxlint ." : linter === "biome" ? "biome check ." : "eslint .",
|
|
679
|
-
format: formatter === "oxfmt" ? "oxfmt ." : formatter === "biome" ? "biome format . --write" : "prettier --write ."
|
|
680
|
-
},
|
|
681
|
-
devDependencies
|
|
682
|
-
};
|
|
683
|
-
const engines = {};
|
|
684
|
-
if (isPnpm && pnpmVersion) {
|
|
685
|
-
const majorVersion = pnpmVersion.split(".")[0];
|
|
686
|
-
engines.pnpm = `>=${majorVersion}.0.0`;
|
|
687
|
-
rootPackageJson.packageManager = `pnpm@${pnpmVersion}`;
|
|
688
|
-
}
|
|
689
|
-
if (nodeVersion) {
|
|
690
|
-
const majorVersion = nodeVersion.split(".")[0];
|
|
691
|
-
engines.node = `>=${majorVersion}.0.0`;
|
|
692
|
-
}
|
|
693
|
-
if (Object.keys(engines).length > 0) {
|
|
694
|
-
rootPackageJson.engines = engines;
|
|
695
|
-
}
|
|
696
|
-
files["package.json"] = {
|
|
697
|
-
type: "text",
|
|
698
|
-
content: JSON.stringify(rootPackageJson, null, 2)
|
|
699
|
-
};
|
|
700
|
-
if (isPnpm) {
|
|
701
|
-
const workspaceLines = [];
|
|
702
|
-
if (pnpmManageVersions) {
|
|
703
|
-
workspaceLines.push("manage-package-manager-versions: true", "");
|
|
662
|
+
function generateAiFiles(files, params) {
|
|
663
|
+
const { name, packageManager, linter, formatter, aiFiles } = params;
|
|
664
|
+
const content = getAiInstructionsContent({
|
|
665
|
+
name,
|
|
666
|
+
packageManager,
|
|
667
|
+
linter,
|
|
668
|
+
formatter
|
|
669
|
+
});
|
|
670
|
+
for (const fileChoice of aiFiles) {
|
|
671
|
+
switch (fileChoice) {
|
|
672
|
+
case "cursor-rules":
|
|
673
|
+
files[".cursor/rules"] = { type: "text", content };
|
|
674
|
+
break;
|
|
675
|
+
case "agents-md":
|
|
676
|
+
files["AGENTS.md"] = { type: "text", content };
|
|
677
|
+
break;
|
|
678
|
+
case "claude-md":
|
|
679
|
+
files["CLAUDE.md"] = { type: "text", content };
|
|
680
|
+
break;
|
|
681
|
+
case "copilot-md":
|
|
682
|
+
files[".github/copilot-instructions.md"] = { type: "text", content };
|
|
683
|
+
break;
|
|
704
684
|
}
|
|
705
|
-
workspaceLines.push("packages:", ' - ".config/*"', ' - "apps/*"', ' - "packages/*"', "");
|
|
706
|
-
workspaceLines.push("onlyBuiltDependencies:", " - esbuild");
|
|
707
|
-
files["pnpm-workspace.yaml"] = {
|
|
708
|
-
type: "text",
|
|
709
|
-
content: workspaceLines.join("\n")
|
|
710
|
-
};
|
|
711
685
|
}
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
type: "text",
|
|
718
|
-
content: `export default [
|
|
719
|
-
// Add your ESLint rules here
|
|
720
|
-
];
|
|
721
|
-
`
|
|
722
|
-
};
|
|
723
|
-
} else if (linter === "biome") {
|
|
724
|
-
const biomeConfig = {
|
|
725
|
-
$schema: "https://biomejs.dev/schemas/1.9.4/schema.json",
|
|
726
|
-
vcs: {
|
|
727
|
-
enabled: true,
|
|
728
|
-
clientKind: "git",
|
|
729
|
-
useIgnoreFile: true
|
|
730
|
-
},
|
|
731
|
-
linter: {
|
|
732
|
-
enabled: true,
|
|
733
|
-
rules: {
|
|
734
|
-
recommended: true
|
|
735
|
-
}
|
|
736
|
-
},
|
|
737
|
-
formatter: {
|
|
738
|
-
enabled: formatter === "biome"
|
|
739
|
-
}
|
|
740
|
-
};
|
|
741
|
-
files["biome.json"] = {
|
|
742
|
-
type: "text",
|
|
743
|
-
content: JSON.stringify(biomeConfig, null, 2)
|
|
744
|
-
};
|
|
686
|
+
}
|
|
687
|
+
function getConfigPackagesDescription(linter, formatter) {
|
|
688
|
+
const packages = ["`@config/typescript`"];
|
|
689
|
+
if (linter !== "biome") {
|
|
690
|
+
packages.push(`\`@config/${linter}\``);
|
|
745
691
|
}
|
|
746
|
-
if (formatter
|
|
747
|
-
|
|
748
|
-
} else if (formatter === "prettier") {
|
|
749
|
-
const prettierConfig = {
|
|
750
|
-
semi: true,
|
|
751
|
-
singleQuote: false,
|
|
752
|
-
trailingComma: "es5",
|
|
753
|
-
printWidth: 100
|
|
754
|
-
};
|
|
755
|
-
files[".prettierrc.json"] = {
|
|
756
|
-
type: "text",
|
|
757
|
-
content: JSON.stringify(prettierConfig, null, 2)
|
|
758
|
-
};
|
|
692
|
+
if (formatter !== "biome" && formatter !== linter) {
|
|
693
|
+
packages.push(`\`@config/${formatter}\``);
|
|
759
694
|
}
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
}
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
};
|
|
771
|
-
generateVscodeFiles(files, linter, formatter);
|
|
772
|
-
files["README.md"] = {
|
|
773
|
-
type: "text",
|
|
774
|
-
content: `# ${name}
|
|
695
|
+
let description = `- \`.config/\`: shared config packages (${packages.join(", ")})`;
|
|
696
|
+
if (linter === "biome" || formatter === "biome") {
|
|
697
|
+
description += "\n- `biome.json`: Biome configuration (root level)";
|
|
698
|
+
}
|
|
699
|
+
return description;
|
|
700
|
+
}
|
|
701
|
+
function getAiInstructionsContent(params) {
|
|
702
|
+
const { name, packageManager, linter, formatter } = params;
|
|
703
|
+
const configDescription = getConfigPackagesDescription(linter, formatter);
|
|
704
|
+
return `# ${name}
|
|
775
705
|
|
|
776
|
-
This monorepo workspace
|
|
706
|
+
This is a pnpm monorepo workspace generated with \`create-krispya\`.
|
|
777
707
|
|
|
778
|
-
##
|
|
708
|
+
## Most important rule (package creation)
|
|
779
709
|
|
|
780
|
-
|
|
781
|
-
- \`packages/\` - Shared packages and libraries
|
|
782
|
-
- \`.config/\` - Shared configuration packages
|
|
710
|
+
If you need a new app/package for any reason, **ALWAYS** create it with \`create-krispya\` (do not hand-create folders/package.json).
|
|
783
711
|
|
|
784
|
-
|
|
712
|
+
### Non-interactive (preferred for agents)
|
|
785
713
|
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
- \`${packageManager} run test\` to run tests across the workspace
|
|
790
|
-
- \`${packageManager} run lint\` to lint all code
|
|
791
|
-
- \`${packageManager} run format\` to format all code
|
|
714
|
+
\`\`\`bash
|
|
715
|
+
${packageManager} create krispya <name> --workspace [options]
|
|
716
|
+
\`\`\`
|
|
792
717
|
|
|
793
|
-
|
|
718
|
+
- The package directory will be \`apps/<name>\` (apps) or \`packages/<name>\` (libraries), unless \`--dir\` is provided.
|
|
719
|
+
- Package names default to \`@${name}/<name>\` but you can pass any name (scoped or unscoped).
|
|
794
720
|
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
721
|
+
### Workspace maintenance (non-interactive)
|
|
722
|
+
|
|
723
|
+
\`\`\`bash
|
|
724
|
+
${packageManager} create krispya --check # validate workspace
|
|
725
|
+
${packageManager} create krispya --fix --linter ${linter} --formatter ${formatter} # fix missing .config packages
|
|
726
|
+
\`\`\`
|
|
727
|
+
|
|
728
|
+
For non-interactive \`--fix\`, you MUST provide both \`--linter\` and \`--formatter\` flags.
|
|
729
|
+
|
|
730
|
+
## Package creation options (CLI truth)
|
|
731
|
+
|
|
732
|
+
| Option | Values | Notes |
|
|
733
|
+
|--------|--------|-------|
|
|
734
|
+
| \`--type\` | app, library | default: app |
|
|
735
|
+
| \`--template\` | vanilla, vanilla-js, react, react-js, r3f, r3f-js | default: vanilla |
|
|
736
|
+
| \`--dir\` | any directory | requires \`--workspace\`; default: \`apps/\` or \`packages/\` |
|
|
737
|
+
| \`--bundler\` | unbuild, tsdown | libraries only; default: unbuild |
|
|
738
|
+
|
|
739
|
+
### R3F flags (r3f templates only)
|
|
740
|
+
|
|
741
|
+
\`--drei\` \`--handle\` \`--leva\` \`--postprocessing\` \`--rapier\` \`--xr\` \`--uikit\` \`--offscreen\` \`--zustand\` \`--koota\` \`--triplex\` \`--viverse\`
|
|
742
|
+
|
|
743
|
+
### Examples
|
|
744
|
+
|
|
745
|
+
\`\`\`bash
|
|
746
|
+
# React library (@${name}/ui) in packages/ui
|
|
747
|
+
${packageManager} create krispya ui --workspace --type library --template react
|
|
748
|
+
|
|
749
|
+
# R3F app with physics + controls (@${name}/game) in apps/game
|
|
750
|
+
${packageManager} create krispya game --workspace --type app --template r3f --drei --rapier --leva
|
|
751
|
+
|
|
752
|
+
# App in a custom directory
|
|
753
|
+
${packageManager} create krispya demo --workspace --type app --template react --dir examples
|
|
754
|
+
\`\`\`
|
|
755
|
+
|
|
756
|
+
## After creating a package
|
|
757
|
+
|
|
758
|
+
\`\`\`bash
|
|
759
|
+
${packageManager} install
|
|
760
|
+
\`\`\`
|
|
761
|
+
|
|
762
|
+
- Use \`"workspace:*"\` for internal deps (e.g. \`"@${name}/ui": "workspace:*"\`).
|
|
763
|
+
|
|
764
|
+
## Workspace commands
|
|
765
|
+
|
|
766
|
+
\`\`\`bash
|
|
767
|
+
${packageManager} install # Install all dependencies
|
|
768
|
+
${packageManager} run dev # Run all apps in dev mode
|
|
769
|
+
${packageManager} run build # Build packages then apps
|
|
770
|
+
${packageManager} run test # Run all tests
|
|
771
|
+
${packageManager} run lint # Lint with ${linter}
|
|
772
|
+
${packageManager} run format # Format with ${formatter}
|
|
773
|
+
\`\`\`
|
|
774
|
+
|
|
775
|
+
## Structure + conventions
|
|
776
|
+
|
|
777
|
+
- \`apps/\`: applications (\`--type app\`)
|
|
778
|
+
- \`packages/\`: libraries (\`--type library\`)
|
|
779
|
+
${configDescription}
|
|
780
|
+
- TS configs extend \`@config/typescript/*\` (base/app/node/react)
|
|
781
|
+
`;
|
|
799
782
|
}
|
|
783
|
+
|
|
800
784
|
function generateTypescriptConfigPackage(files) {
|
|
801
785
|
const basePath = ".config/typescript";
|
|
802
786
|
files[`${basePath}/package.json`] = {
|
|
@@ -993,48 +977,175 @@ oxlint -c node_modules/@config/oxlint/base.json
|
|
|
993
977
|
)
|
|
994
978
|
};
|
|
995
979
|
}
|
|
996
|
-
function
|
|
997
|
-
const
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
980
|
+
function generateEslintConfigPackage(files) {
|
|
981
|
+
const basePath = ".config/eslint";
|
|
982
|
+
files[`${basePath}/package.json`] = {
|
|
983
|
+
type: "text",
|
|
984
|
+
content: JSON.stringify(
|
|
985
|
+
{
|
|
986
|
+
name: "@config/eslint",
|
|
987
|
+
version: "0.1.0",
|
|
988
|
+
private: true,
|
|
989
|
+
type: "module",
|
|
990
|
+
exports: {
|
|
991
|
+
"./base": "./base.js",
|
|
992
|
+
"./react": "./react.js"
|
|
993
|
+
},
|
|
994
|
+
files: ["base.js", "react.js"],
|
|
995
|
+
devDependencies: {
|
|
996
|
+
"@eslint/js": "^9.17.0",
|
|
997
|
+
"typescript-eslint": "^8.18.0"
|
|
998
|
+
}
|
|
999
|
+
},
|
|
1000
|
+
null,
|
|
1001
|
+
2
|
|
1002
|
+
)
|
|
1003
|
+
};
|
|
1004
|
+
files[`${basePath}/README.md`] = {
|
|
1005
|
+
type: "text",
|
|
1006
|
+
content: `# \`@config/eslint\`
|
|
1007
|
+
|
|
1008
|
+
Shared ESLint configurations for the monorepo.
|
|
1009
|
+
|
|
1010
|
+
## Usage
|
|
1011
|
+
|
|
1012
|
+
In your package's \`eslint.config.js\`:
|
|
1013
|
+
|
|
1014
|
+
\`\`\`js
|
|
1015
|
+
import base from "@config/eslint/base";
|
|
1016
|
+
|
|
1017
|
+
export default [...base];
|
|
1018
|
+
\`\`\`
|
|
1019
|
+
|
|
1020
|
+
Or for React projects:
|
|
1021
|
+
|
|
1022
|
+
\`\`\`js
|
|
1023
|
+
import react from "@config/eslint/react";
|
|
1024
|
+
|
|
1025
|
+
export default [...react];
|
|
1026
|
+
\`\`\`
|
|
1027
|
+
|
|
1028
|
+
## Available Configs
|
|
1029
|
+
|
|
1030
|
+
- \`base\` - Base linting rules for TypeScript projects
|
|
1031
|
+
- \`react\` - Extends base with React-specific rules
|
|
1032
|
+
`
|
|
1033
|
+
};
|
|
1034
|
+
files[`${basePath}/base.js`] = {
|
|
1035
|
+
type: "text",
|
|
1036
|
+
content: `import js from "@eslint/js";
|
|
1037
|
+
import tseslint from "typescript-eslint";
|
|
1038
|
+
|
|
1039
|
+
export default tseslint.config(
|
|
1040
|
+
js.configs.recommended,
|
|
1041
|
+
...tseslint.configs.recommended,
|
|
1042
|
+
{
|
|
1043
|
+
rules: {
|
|
1044
|
+
"@typescript-eslint/no-unused-vars": [
|
|
1045
|
+
"error",
|
|
1046
|
+
{
|
|
1047
|
+
argsIgnorePattern: "^_",
|
|
1048
|
+
varsIgnorePattern: "^_",
|
|
1049
|
+
caughtErrorsIgnorePattern: "^_",
|
|
1050
|
+
},
|
|
1051
|
+
],
|
|
1052
|
+
},
|
|
1053
|
+
},
|
|
1054
|
+
{
|
|
1055
|
+
ignores: ["dist/**", "node_modules/**"],
|
|
1014
1056
|
}
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1057
|
+
);
|
|
1058
|
+
`
|
|
1059
|
+
};
|
|
1060
|
+
files[`${basePath}/react.js`] = {
|
|
1061
|
+
type: "text",
|
|
1062
|
+
content: `import js from "@eslint/js";
|
|
1063
|
+
import tseslint from "typescript-eslint";
|
|
1064
|
+
|
|
1065
|
+
export default tseslint.config(
|
|
1066
|
+
js.configs.recommended,
|
|
1067
|
+
...tseslint.configs.recommended,
|
|
1068
|
+
{
|
|
1069
|
+
rules: {
|
|
1070
|
+
"@typescript-eslint/no-unused-vars": [
|
|
1071
|
+
"error",
|
|
1072
|
+
{
|
|
1073
|
+
argsIgnorePattern: "^_",
|
|
1074
|
+
varsIgnorePattern: "^_",
|
|
1075
|
+
caughtErrorsIgnorePattern: "^_",
|
|
1076
|
+
},
|
|
1077
|
+
],
|
|
1078
|
+
},
|
|
1079
|
+
},
|
|
1080
|
+
{
|
|
1081
|
+
ignores: ["dist/**", "node_modules/**"],
|
|
1030
1082
|
}
|
|
1031
|
-
|
|
1083
|
+
);
|
|
1084
|
+
`
|
|
1085
|
+
};
|
|
1086
|
+
}
|
|
1087
|
+
function generatePrettierConfigPackage(files) {
|
|
1088
|
+
const basePath = ".config/prettier";
|
|
1089
|
+
files[`${basePath}/package.json`] = {
|
|
1032
1090
|
type: "text",
|
|
1033
|
-
content: JSON.stringify(
|
|
1091
|
+
content: JSON.stringify(
|
|
1092
|
+
{
|
|
1093
|
+
name: "@config/prettier",
|
|
1094
|
+
version: "0.1.0",
|
|
1095
|
+
private: true,
|
|
1096
|
+
type: "module",
|
|
1097
|
+
exports: {
|
|
1098
|
+
".": "./base.json"
|
|
1099
|
+
},
|
|
1100
|
+
files: ["base.json"]
|
|
1101
|
+
},
|
|
1102
|
+
null,
|
|
1103
|
+
2
|
|
1104
|
+
)
|
|
1034
1105
|
};
|
|
1035
|
-
files[
|
|
1106
|
+
files[`${basePath}/README.md`] = {
|
|
1036
1107
|
type: "text",
|
|
1037
|
-
content:
|
|
1108
|
+
content: `# \`@config/prettier\`
|
|
1109
|
+
|
|
1110
|
+
Shared Prettier configuration for the monorepo.
|
|
1111
|
+
|
|
1112
|
+
## Usage
|
|
1113
|
+
|
|
1114
|
+
In your package's \`package.json\`:
|
|
1115
|
+
|
|
1116
|
+
\`\`\`json
|
|
1117
|
+
{
|
|
1118
|
+
"prettier": "@config/prettier"
|
|
1119
|
+
}
|
|
1120
|
+
\`\`\`
|
|
1121
|
+
|
|
1122
|
+
Or in \`.prettierrc.json\`:
|
|
1123
|
+
|
|
1124
|
+
\`\`\`json
|
|
1125
|
+
"@config/prettier"
|
|
1126
|
+
\`\`\`
|
|
1127
|
+
|
|
1128
|
+
## Available Configs
|
|
1129
|
+
|
|
1130
|
+
- Default export - Base formatter settings
|
|
1131
|
+
`
|
|
1132
|
+
};
|
|
1133
|
+
files[`${basePath}/base.json`] = {
|
|
1134
|
+
type: "text",
|
|
1135
|
+
content: JSON.stringify(
|
|
1136
|
+
{
|
|
1137
|
+
printWidth: defaultFormatterConfig.printWidth,
|
|
1138
|
+
tabWidth: defaultFormatterConfig.tabWidth,
|
|
1139
|
+
useTabs: defaultFormatterConfig.useTabs,
|
|
1140
|
+
semi: defaultFormatterConfig.semi,
|
|
1141
|
+
singleQuote: defaultFormatterConfig.singleQuote,
|
|
1142
|
+
trailingComma: defaultFormatterConfig.trailingComma,
|
|
1143
|
+
bracketSpacing: defaultFormatterConfig.bracketSpacing,
|
|
1144
|
+
arrowParens: defaultFormatterConfig.arrowParens
|
|
1145
|
+
},
|
|
1146
|
+
null,
|
|
1147
|
+
2
|
|
1148
|
+
)
|
|
1038
1149
|
};
|
|
1039
1150
|
}
|
|
1040
1151
|
function generateOxfmtConfigPackage(files) {
|
|
@@ -1090,9 +1201,221 @@ oxfmt -c node_modules/@config/oxfmt/base.json --write .
|
|
|
1090
1201
|
};
|
|
1091
1202
|
}
|
|
1092
1203
|
|
|
1204
|
+
function generateMonorepo(params) {
|
|
1205
|
+
const {
|
|
1206
|
+
name,
|
|
1207
|
+
linter,
|
|
1208
|
+
formatter,
|
|
1209
|
+
packageManager,
|
|
1210
|
+
pnpmVersion,
|
|
1211
|
+
pnpmManageVersions,
|
|
1212
|
+
nodeVersion,
|
|
1213
|
+
aiFiles
|
|
1214
|
+
} = params;
|
|
1215
|
+
const files = {};
|
|
1216
|
+
const isPnpm = packageManager === "pnpm";
|
|
1217
|
+
const devDependencies = {};
|
|
1218
|
+
if (linter === "oxlint") {
|
|
1219
|
+
devDependencies["oxlint"] = "^1.36.0";
|
|
1220
|
+
} else if (linter === "eslint") {
|
|
1221
|
+
devDependencies["eslint"] = "^9.17.0";
|
|
1222
|
+
} else if (linter === "biome") {
|
|
1223
|
+
devDependencies["@biomejs/biome"] = "^1.9.4";
|
|
1224
|
+
}
|
|
1225
|
+
if (formatter === "oxfmt") {
|
|
1226
|
+
devDependencies["oxfmt"] = "^0.21.0";
|
|
1227
|
+
} else if (formatter === "prettier") {
|
|
1228
|
+
devDependencies["prettier"] = "^3.4.2";
|
|
1229
|
+
}
|
|
1230
|
+
const rootPackageJson = {
|
|
1231
|
+
name: "root",
|
|
1232
|
+
version: "0.0.0",
|
|
1233
|
+
private: true,
|
|
1234
|
+
type: "module",
|
|
1235
|
+
scripts: {
|
|
1236
|
+
dev: "pnpm --filter './apps/*' run dev",
|
|
1237
|
+
build: "pnpm --filter './packages/*' run build && pnpm --filter './apps/*' run build",
|
|
1238
|
+
test: "pnpm -r run test",
|
|
1239
|
+
lint: linter === "oxlint" ? "oxlint ." : linter === "biome" ? "biome check ." : "eslint .",
|
|
1240
|
+
format: formatter === "oxfmt" ? "oxfmt ." : formatter === "biome" ? "biome format . --write" : "prettier --write ."
|
|
1241
|
+
},
|
|
1242
|
+
devDependencies
|
|
1243
|
+
};
|
|
1244
|
+
const engines = {};
|
|
1245
|
+
if (isPnpm && pnpmVersion) {
|
|
1246
|
+
const majorVersion = pnpmVersion.split(".")[0];
|
|
1247
|
+
engines.pnpm = `>=${majorVersion}.0.0`;
|
|
1248
|
+
rootPackageJson.packageManager = `pnpm@${pnpmVersion}`;
|
|
1249
|
+
}
|
|
1250
|
+
if (nodeVersion) {
|
|
1251
|
+
const majorVersion = nodeVersion.split(".")[0];
|
|
1252
|
+
engines.node = `>=${majorVersion}.0.0`;
|
|
1253
|
+
}
|
|
1254
|
+
if (Object.keys(engines).length > 0) {
|
|
1255
|
+
rootPackageJson.engines = engines;
|
|
1256
|
+
}
|
|
1257
|
+
files["package.json"] = {
|
|
1258
|
+
type: "text",
|
|
1259
|
+
content: JSON.stringify(rootPackageJson, null, 2)
|
|
1260
|
+
};
|
|
1261
|
+
if (isPnpm) {
|
|
1262
|
+
const workspaceLines = [];
|
|
1263
|
+
if (pnpmManageVersions) {
|
|
1264
|
+
workspaceLines.push("manage-package-manager-versions: true", "");
|
|
1265
|
+
}
|
|
1266
|
+
workspaceLines.push(
|
|
1267
|
+
"packages:",
|
|
1268
|
+
' - ".config/*"',
|
|
1269
|
+
' - "apps/*"',
|
|
1270
|
+
' - "packages/*"',
|
|
1271
|
+
""
|
|
1272
|
+
);
|
|
1273
|
+
workspaceLines.push("onlyBuiltDependencies:", " - esbuild");
|
|
1274
|
+
files["pnpm-workspace.yaml"] = {
|
|
1275
|
+
type: "text",
|
|
1276
|
+
content: workspaceLines.join("\n")
|
|
1277
|
+
};
|
|
1278
|
+
}
|
|
1279
|
+
generateTypescriptConfigPackage(files);
|
|
1280
|
+
if (linter === "oxlint") {
|
|
1281
|
+
generateOxlintConfigPackage(files);
|
|
1282
|
+
} else if (linter === "eslint") {
|
|
1283
|
+
generateEslintConfigPackage(files);
|
|
1284
|
+
} else if (linter === "biome") {
|
|
1285
|
+
const biomeConfig = {
|
|
1286
|
+
$schema: "https://biomejs.dev/schemas/1.9.4/schema.json",
|
|
1287
|
+
vcs: {
|
|
1288
|
+
enabled: true,
|
|
1289
|
+
clientKind: "git",
|
|
1290
|
+
useIgnoreFile: true
|
|
1291
|
+
},
|
|
1292
|
+
linter: {
|
|
1293
|
+
enabled: true,
|
|
1294
|
+
rules: {
|
|
1295
|
+
recommended: true
|
|
1296
|
+
}
|
|
1297
|
+
},
|
|
1298
|
+
formatter: {
|
|
1299
|
+
enabled: formatter === "biome"
|
|
1300
|
+
}
|
|
1301
|
+
};
|
|
1302
|
+
files["biome.json"] = {
|
|
1303
|
+
type: "text",
|
|
1304
|
+
content: JSON.stringify(biomeConfig, null, 2)
|
|
1305
|
+
};
|
|
1306
|
+
}
|
|
1307
|
+
if (formatter === "oxfmt") {
|
|
1308
|
+
generateOxfmtConfigPackage(files);
|
|
1309
|
+
} else if (formatter === "prettier") {
|
|
1310
|
+
generatePrettierConfigPackage(files);
|
|
1311
|
+
}
|
|
1312
|
+
files[".gitignore"] = {
|
|
1313
|
+
type: "text",
|
|
1314
|
+
content: ["node_modules", "dist", "*.tsbuildinfo", ".DS_Store"].join("\n")
|
|
1315
|
+
};
|
|
1316
|
+
files[".gitattributes"] = {
|
|
1317
|
+
type: "text",
|
|
1318
|
+
content: `* text=auto eol=lf
|
|
1319
|
+
*.{cmd,[cC][mM][dD]} text eol=crlf
|
|
1320
|
+
*.{bat,[bB][aA][tT]} text eol=crlf
|
|
1321
|
+
`
|
|
1322
|
+
};
|
|
1323
|
+
generateVscodeFiles(files, linter, formatter);
|
|
1324
|
+
files["README.md"] = {
|
|
1325
|
+
type: "text",
|
|
1326
|
+
content: `# ${name}
|
|
1327
|
+
|
|
1328
|
+
This monorepo workspace was generated with create-krispya.
|
|
1329
|
+
|
|
1330
|
+
## Structure
|
|
1331
|
+
|
|
1332
|
+
- \`apps/\` - Applications
|
|
1333
|
+
- \`packages/\` - Shared packages and libraries
|
|
1334
|
+
- \`.config/\` - Shared configuration packages
|
|
1335
|
+
|
|
1336
|
+
## Development Commands
|
|
1337
|
+
|
|
1338
|
+
- \`${packageManager} install\` to install all dependencies
|
|
1339
|
+
- \`${packageManager} run dev\` to run all applications in development mode
|
|
1340
|
+
- \`${packageManager} run build\` to build all packages and applications
|
|
1341
|
+
- \`${packageManager} run test\` to run tests across the workspace
|
|
1342
|
+
- \`${packageManager} run lint\` to lint all code
|
|
1343
|
+
- \`${packageManager} run format\` to format all code
|
|
1344
|
+
|
|
1345
|
+
## Adding Packages
|
|
1346
|
+
|
|
1347
|
+
To add a new package to this workspace, run create-krispya from this directory and it will detect the monorepo.
|
|
1348
|
+
`
|
|
1349
|
+
};
|
|
1350
|
+
if (aiFiles && aiFiles.length > 0) {
|
|
1351
|
+
generateAiFiles(files, {
|
|
1352
|
+
name,
|
|
1353
|
+
packageManager,
|
|
1354
|
+
linter,
|
|
1355
|
+
formatter,
|
|
1356
|
+
aiFiles
|
|
1357
|
+
});
|
|
1358
|
+
}
|
|
1359
|
+
return { files };
|
|
1360
|
+
}
|
|
1361
|
+
function generateVscodeFiles(files, linter, formatter) {
|
|
1362
|
+
const recommendations = [];
|
|
1363
|
+
const settings = {};
|
|
1364
|
+
if (linter === "oxlint") {
|
|
1365
|
+
recommendations.push("oxc.oxc-vscode");
|
|
1366
|
+
settings["oxc.enable"] = true;
|
|
1367
|
+
settings["eslint.enable"] = false;
|
|
1368
|
+
settings["biome.enabled"] = false;
|
|
1369
|
+
} else if (linter === "eslint") {
|
|
1370
|
+
recommendations.push("dbaeumer.vscode-eslint");
|
|
1371
|
+
settings["eslint.enable"] = true;
|
|
1372
|
+
settings["oxc.enable"] = false;
|
|
1373
|
+
settings["biome.enabled"] = false;
|
|
1374
|
+
} else if (linter === "biome") {
|
|
1375
|
+
recommendations.push("biomejs.biome");
|
|
1376
|
+
settings["biome.enabled"] = true;
|
|
1377
|
+
settings["eslint.enable"] = false;
|
|
1378
|
+
settings["oxc.enable"] = false;
|
|
1379
|
+
}
|
|
1380
|
+
if (formatter === "oxfmt") {
|
|
1381
|
+
if (!recommendations.includes("oxc.oxc-vscode")) {
|
|
1382
|
+
recommendations.push("oxc.oxc-vscode");
|
|
1383
|
+
}
|
|
1384
|
+
settings["editor.defaultFormatter"] = "oxc.oxc-vscode";
|
|
1385
|
+
settings["[json]"] = {
|
|
1386
|
+
"editor.defaultFormatter": "vscode.json-language-features"
|
|
1387
|
+
};
|
|
1388
|
+
settings["[jsonc]"] = {
|
|
1389
|
+
"editor.defaultFormatter": "vscode.json-language-features"
|
|
1390
|
+
};
|
|
1391
|
+
} else if (formatter === "prettier") {
|
|
1392
|
+
recommendations.push("esbenp.prettier-vscode");
|
|
1393
|
+
settings["editor.defaultFormatter"] = "esbenp.prettier-vscode";
|
|
1394
|
+
} else if (formatter === "biome") {
|
|
1395
|
+
if (!recommendations.includes("biomejs.biome")) {
|
|
1396
|
+
recommendations.push("biomejs.biome");
|
|
1397
|
+
}
|
|
1398
|
+
settings["editor.defaultFormatter"] = "biomejs.biome";
|
|
1399
|
+
}
|
|
1400
|
+
files[".vscode/extensions.json"] = {
|
|
1401
|
+
type: "text",
|
|
1402
|
+
content: JSON.stringify({ recommendations }, null, 2)
|
|
1403
|
+
};
|
|
1404
|
+
files[".vscode/settings.json"] = {
|
|
1405
|
+
type: "text",
|
|
1406
|
+
content: JSON.stringify(settings, null, " ")
|
|
1407
|
+
};
|
|
1408
|
+
}
|
|
1409
|
+
|
|
1093
1410
|
const monorepo = {
|
|
1094
1411
|
__proto__: null,
|
|
1095
|
-
|
|
1412
|
+
generateEslintConfigPackage: generateEslintConfigPackage,
|
|
1413
|
+
generateMonorepo: generateMonorepo,
|
|
1414
|
+
generateOxfmtConfigPackage: generateOxfmtConfigPackage,
|
|
1415
|
+
generateOxlintConfigPackage: generateOxlintConfigPackage,
|
|
1416
|
+
generatePrettierConfigPackage: generatePrettierConfigPackage,
|
|
1417
|
+
generateTypescriptConfigPackage: generateTypescriptConfigPackage,
|
|
1418
|
+
generateVscodeFiles: generateVscodeFiles
|
|
1096
1419
|
};
|
|
1097
1420
|
|
|
1098
1421
|
function toBiomeLevel(level) {
|
|
@@ -2021,7 +2344,9 @@ function merge(target, modification) {
|
|
|
2021
2344
|
|
|
2022
2345
|
async function getLatestNpmVersion(packageName, fallback) {
|
|
2023
2346
|
try {
|
|
2024
|
-
const response = await fetch(
|
|
2347
|
+
const response = await fetch(
|
|
2348
|
+
`https://registry.npmjs.org/${packageName}/latest`
|
|
2349
|
+
);
|
|
2025
2350
|
const data = await response.json();
|
|
2026
2351
|
return data.version;
|
|
2027
2352
|
} catch {
|
|
@@ -2031,6 +2356,12 @@ async function getLatestNpmVersion(packageName, fallback) {
|
|
|
2031
2356
|
async function getLatestPnpmVersion() {
|
|
2032
2357
|
return getLatestNpmVersion("pnpm", "10.11.0");
|
|
2033
2358
|
}
|
|
2359
|
+
async function getLatestYarnVersion() {
|
|
2360
|
+
return getLatestNpmVersion("yarn", "4.6.0");
|
|
2361
|
+
}
|
|
2362
|
+
async function getLatestNpmCliVersion() {
|
|
2363
|
+
return getLatestNpmVersion("npm", "11.0.0");
|
|
2364
|
+
}
|
|
2034
2365
|
async function getLatestNodeVersion() {
|
|
2035
2366
|
try {
|
|
2036
2367
|
const response = await fetch("https://nodejs.org/dist/index.json");
|
|
@@ -2044,6 +2375,70 @@ async function getLatestNodeVersion() {
|
|
|
2044
2375
|
return "22.0.0";
|
|
2045
2376
|
}
|
|
2046
2377
|
}
|
|
2378
|
+
function validateNameSegment(segment, label) {
|
|
2379
|
+
if (!segment.length) {
|
|
2380
|
+
return `${label} is required`;
|
|
2381
|
+
}
|
|
2382
|
+
if (!/^[a-z0-9-]+$/.test(segment)) {
|
|
2383
|
+
return `${label} must be lowercase and contain only letters, numbers, and hyphens`;
|
|
2384
|
+
}
|
|
2385
|
+
if (segment.startsWith("-") || segment.endsWith("-")) {
|
|
2386
|
+
return `${label} cannot start or end with a hyphen`;
|
|
2387
|
+
}
|
|
2388
|
+
if (segment.includes("--")) {
|
|
2389
|
+
return `${label} cannot contain consecutive hyphens`;
|
|
2390
|
+
}
|
|
2391
|
+
return void 0;
|
|
2392
|
+
}
|
|
2393
|
+
function validatePackageName(name) {
|
|
2394
|
+
if (!name.length) {
|
|
2395
|
+
return "Package name is required";
|
|
2396
|
+
}
|
|
2397
|
+
if (name.includes("..") || name.includes("\\")) {
|
|
2398
|
+
return "Package name cannot contain path traversal sequences";
|
|
2399
|
+
}
|
|
2400
|
+
if (name.startsWith("@")) {
|
|
2401
|
+
const slashIndex = name.indexOf("/");
|
|
2402
|
+
if (slashIndex === -1) {
|
|
2403
|
+
return "Scoped package name must include a package name after the scope (e.g., @scope/name)";
|
|
2404
|
+
}
|
|
2405
|
+
if (name.indexOf("/", slashIndex + 1) !== -1) {
|
|
2406
|
+
return "Package name can only have one slash for scoped packages";
|
|
2407
|
+
}
|
|
2408
|
+
const scope = name.slice(1, slashIndex);
|
|
2409
|
+
const packageName = name.slice(slashIndex + 1);
|
|
2410
|
+
const scopeError = validateNameSegment(scope, "Scope");
|
|
2411
|
+
if (scopeError) return scopeError;
|
|
2412
|
+
const nameError = validateNameSegment(packageName, "Package name");
|
|
2413
|
+
if (nameError) return nameError;
|
|
2414
|
+
return void 0;
|
|
2415
|
+
}
|
|
2416
|
+
if (name.includes("/")) {
|
|
2417
|
+
return "Unscoped package name cannot contain slashes. Use @scope/name format for scoped packages";
|
|
2418
|
+
}
|
|
2419
|
+
return validateNameSegment(name, "Package name");
|
|
2420
|
+
}
|
|
2421
|
+
function parseWorkspaceYamlContent(content) {
|
|
2422
|
+
const directories = [];
|
|
2423
|
+
let inPackagesSection = false;
|
|
2424
|
+
for (const line of content.split("\n")) {
|
|
2425
|
+
const trimmed = line.trim();
|
|
2426
|
+
if (trimmed === "packages:") {
|
|
2427
|
+
inPackagesSection = true;
|
|
2428
|
+
continue;
|
|
2429
|
+
}
|
|
2430
|
+
if (inPackagesSection && trimmed && !line.startsWith(" ") && !line.startsWith(" ") && !trimmed.startsWith("-")) {
|
|
2431
|
+
break;
|
|
2432
|
+
}
|
|
2433
|
+
if (inPackagesSection && trimmed.startsWith("-")) {
|
|
2434
|
+
const entry = trimmed.slice(1).trim().replace(/^["']|["']$/g, "").replace(/^\.\//, "").replace(/\/\*.*$/, "");
|
|
2435
|
+
if (entry && !entry.startsWith(".")) {
|
|
2436
|
+
directories.push(entry);
|
|
2437
|
+
}
|
|
2438
|
+
}
|
|
2439
|
+
}
|
|
2440
|
+
return directories;
|
|
2441
|
+
}
|
|
2047
2442
|
function generateRandomName() {
|
|
2048
2443
|
const adjectives = [
|
|
2049
2444
|
"red",
|
|
@@ -2350,11 +2745,22 @@ function generate(options) {
|
|
|
2350
2745
|
}
|
|
2351
2746
|
|
|
2352
2747
|
exports.generate = generate;
|
|
2748
|
+
exports.generateAiFiles = generateAiFiles;
|
|
2749
|
+
exports.generateEslintConfigPackage = generateEslintConfigPackage;
|
|
2353
2750
|
exports.generateMonorepo = generateMonorepo;
|
|
2751
|
+
exports.generateOxfmtConfigPackage = generateOxfmtConfigPackage;
|
|
2752
|
+
exports.generateOxlintConfigPackage = generateOxlintConfigPackage;
|
|
2753
|
+
exports.generatePrettierConfigPackage = generatePrettierConfigPackage;
|
|
2354
2754
|
exports.generateRandomName = generateRandomName;
|
|
2755
|
+
exports.generateTypescriptConfigPackage = generateTypescriptConfigPackage;
|
|
2756
|
+
exports.generateVscodeFiles = generateVscodeFiles;
|
|
2355
2757
|
exports.getBaseTemplate = getBaseTemplate;
|
|
2356
2758
|
exports.getLanguageFromTemplate = getLanguageFromTemplate;
|
|
2357
2759
|
exports.getLatestNodeVersion = getLatestNodeVersion;
|
|
2760
|
+
exports.getLatestNpmCliVersion = getLatestNpmCliVersion;
|
|
2358
2761
|
exports.getLatestNpmVersion = getLatestNpmVersion;
|
|
2359
2762
|
exports.getLatestPnpmVersion = getLatestPnpmVersion;
|
|
2763
|
+
exports.getLatestYarnVersion = getLatestYarnVersion;
|
|
2360
2764
|
exports.monorepo = monorepo;
|
|
2765
|
+
exports.parseWorkspaceYamlContent = parseWorkspaceYamlContent;
|
|
2766
|
+
exports.validatePackageName = validatePackageName;
|