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