create-krispya 0.8.0 → 0.10.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/README.md +28 -6
- package/dist/cli.cjs +1302 -1576
- package/dist/cli.d.cts +36 -0
- package/dist/cli.d.mts +36 -0
- package/dist/cli.d.ts +36 -0
- package/dist/cli.mjs +1326 -1600
- package/dist/index.cjs +52 -15
- package/dist/index.d.cts +81 -172
- package/dist/index.d.mts +81 -172
- package/dist/index.d.ts +81 -172
- package/dist/index.mjs +34 -1
- package/dist/{chunks/index.mjs → shared/create-krispya.DKKVmsqH.mjs} +1358 -741
- package/dist/{chunks/index.cjs → shared/create-krispya.DTHeUlq4.cjs} +1381 -754
- package/dist/shared/create-krispya.to8NBxeJ.d.cts +237 -0
- package/dist/shared/create-krispya.to8NBxeJ.d.mts +237 -0
- package/dist/shared/create-krispya.to8NBxeJ.d.ts +237 -0
- package/package.json +7 -3
|
@@ -3,62 +3,7 @@ import { constants } from 'fs';
|
|
|
3
3
|
import { join } from 'path';
|
|
4
4
|
import color from 'chalk';
|
|
5
5
|
|
|
6
|
-
const
|
|
7
|
-
<html lang="en">
|
|
8
|
-
<head>
|
|
9
|
-
<meta charset="UTF-8">
|
|
10
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
11
|
-
<title>$title</title>
|
|
12
|
-
</head>
|
|
13
|
-
<body style="margin: 0; overscroll-behavior: none; user-select: none; touch-action: none;">
|
|
14
|
-
<script type="module" src="$indexPath"><\/script>
|
|
15
|
-
<div style="width: 100dvw; height: 100dvh; overflow: hidden;" id="root"></div>
|
|
16
|
-
</body>
|
|
17
|
-
</html>`;
|
|
18
|
-
const ViteHtmlContent = `<!DOCTYPE html>
|
|
19
|
-
<html lang="en">
|
|
20
|
-
<head>
|
|
21
|
-
<meta charset="UTF-8">
|
|
22
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
23
|
-
<title>$title</title>
|
|
24
|
-
</head>
|
|
25
|
-
<body>
|
|
26
|
-
<div id="app"></div>
|
|
27
|
-
<script type="module" src="$indexPath"><\/script>
|
|
28
|
-
</body>
|
|
29
|
-
</html>`;
|
|
30
|
-
const IndexContent = `import { StrictMode } from 'react'
|
|
31
|
-
import { createRoot } from 'react-dom/client'
|
|
32
|
-
import { App } from './app.js'
|
|
33
|
-
|
|
34
|
-
createRoot(document.getElementById('root')!).render(
|
|
35
|
-
<StrictMode>
|
|
36
|
-
<App />
|
|
37
|
-
</StrictMode>,
|
|
38
|
-
)`;
|
|
39
|
-
const ViteIndexContent = `import './style.css'
|
|
40
|
-
|
|
41
|
-
document.querySelector('#app')!.innerHTML = \`
|
|
42
|
-
<h1>Hello Vite!</h1>
|
|
43
|
-
<p>Edit src/main.ts and save to see HMR in action.</p>
|
|
44
|
-
\``;
|
|
45
|
-
const ViteStyleContent = `body {
|
|
46
|
-
font-family: system-ui, -apple-system, sans-serif;
|
|
47
|
-
margin: 0;
|
|
48
|
-
padding: 2rem;
|
|
49
|
-
min-height: 100vh;
|
|
50
|
-
background: #1a1a1a;
|
|
51
|
-
color: #fff;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
h1 {
|
|
55
|
-
color: #646cff;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
a {
|
|
59
|
-
color: #646cff;
|
|
60
|
-
}`;
|
|
61
|
-
const GitAttributes = [
|
|
6
|
+
const gitAttributesContent = [
|
|
62
7
|
"* text eol=lf",
|
|
63
8
|
"*.png binary",
|
|
64
9
|
"*.jpg binary",
|
|
@@ -83,55 +28,6 @@ const GitAttributes = [
|
|
|
83
28
|
"*.glb binary",
|
|
84
29
|
"*.gltf binary"
|
|
85
30
|
].join("\n");
|
|
86
|
-
const defaultFormatterConfig = {
|
|
87
|
-
printWidth: 102,
|
|
88
|
-
tabWidth: 2,
|
|
89
|
-
useTabs: false,
|
|
90
|
-
semi: true,
|
|
91
|
-
singleQuote: true,
|
|
92
|
-
trailingComma: "es5",
|
|
93
|
-
bracketSpacing: true,
|
|
94
|
-
arrowParens: "always"
|
|
95
|
-
};
|
|
96
|
-
const defaultPrettierConfig = {
|
|
97
|
-
$schema: "https://json.schemastore.org/prettierrc",
|
|
98
|
-
...defaultFormatterConfig,
|
|
99
|
-
overrides: [
|
|
100
|
-
{
|
|
101
|
-
files: ["*.md", "**/*.md"],
|
|
102
|
-
options: { semi: false }
|
|
103
|
-
},
|
|
104
|
-
{
|
|
105
|
-
files: ["*.yml", "*.yaml", "**/*.yml", "**/*.yaml"],
|
|
106
|
-
options: { semi: false }
|
|
107
|
-
}
|
|
108
|
-
]
|
|
109
|
-
};
|
|
110
|
-
const defaultOxfmtConfig = {
|
|
111
|
-
printWidth: defaultFormatterConfig.printWidth,
|
|
112
|
-
tabWidth: defaultFormatterConfig.tabWidth,
|
|
113
|
-
useTabs: defaultFormatterConfig.useTabs,
|
|
114
|
-
semi: defaultFormatterConfig.semi,
|
|
115
|
-
singleQuote: defaultFormatterConfig.singleQuote,
|
|
116
|
-
trailingComma: defaultFormatterConfig.trailingComma,
|
|
117
|
-
bracketSpacing: defaultFormatterConfig.bracketSpacing,
|
|
118
|
-
arrowParens: defaultFormatterConfig.arrowParens
|
|
119
|
-
};
|
|
120
|
-
const defaultLinterConfig = {
|
|
121
|
-
ignorePatterns: ["dist"],
|
|
122
|
-
rules: {
|
|
123
|
-
noUnusedVars: {
|
|
124
|
-
level: "warn",
|
|
125
|
-
argsIgnorePattern: "^_",
|
|
126
|
-
varsIgnorePattern: "^_",
|
|
127
|
-
caughtErrorsIgnorePattern: "^_"
|
|
128
|
-
},
|
|
129
|
-
noUnusedExpressions: {
|
|
130
|
-
level: "warn",
|
|
131
|
-
allowShortCircuit: true
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
};
|
|
135
31
|
|
|
136
32
|
const ALL_AI_PLATFORMS = ["agents", "claude"];
|
|
137
33
|
const AI_PLATFORM_LABELS = {
|
|
@@ -142,12 +38,15 @@ const AI_PLATFORM_HINTS = {
|
|
|
142
38
|
agents: "OpenAI, Cursor, Windsurf, etc.",
|
|
143
39
|
claude: "Claude Code"
|
|
144
40
|
};
|
|
145
|
-
function
|
|
146
|
-
const { platforms, isMonorepo, configStrategy, ...rest } = params;
|
|
41
|
+
function renderAiFiles(files, params) {
|
|
42
|
+
const { platforms, isMonorepo, configStrategy, hasTypecheck, ...rest } = params;
|
|
147
43
|
if (platforms.length === 0) return;
|
|
148
44
|
const content = generateWorkspace({
|
|
149
45
|
...rest,
|
|
150
|
-
isMonorepo: !!isMonorepo
|
|
46
|
+
isMonorepo: !!isMonorepo,
|
|
47
|
+
configStrategy: configStrategy ?? "stealth",
|
|
48
|
+
hasTypecheck: hasTypecheck ?? false
|
|
49
|
+
});
|
|
151
50
|
const pointer = "See [`AGENTS.md`](./Agents.md) for agent context.\n";
|
|
152
51
|
const hasAgents = platforms.includes("agents");
|
|
153
52
|
const hasClaude = platforms.includes("claude");
|
|
@@ -162,31 +61,115 @@ function generateAiFiles(files, params) {
|
|
|
162
61
|
}
|
|
163
62
|
}
|
|
164
63
|
function generateWorkspace(ctx) {
|
|
165
|
-
const {
|
|
64
|
+
const { packageManager, linter, formatter, hasTypecheck } = ctx;
|
|
65
|
+
const exampleFiles = "src/App.tsx src/core/systems/move-entity.ts";
|
|
66
|
+
const commands = getAfterEditingCommands(ctx, exampleFiles);
|
|
166
67
|
const sections = [
|
|
167
|
-
|
|
68
|
+
"# Workspace Tools",
|
|
168
69
|
"",
|
|
169
|
-
`- **Type:** ${isMonorepo ? "pnpm monorepo" : "standalone project"}`,
|
|
170
70
|
`- **Package Manager:** ${packageManager}`,
|
|
171
71
|
`- **Linter:** ${linter}`,
|
|
172
72
|
`- **Formatter:** ${formatter}`,
|
|
173
73
|
"",
|
|
174
|
-
"##
|
|
175
|
-
""
|
|
176
|
-
`- \`${packageManager} test\` \u2014 run tests`,
|
|
177
|
-
`- \`${packageManager} build\` \u2014 build`,
|
|
178
|
-
`- \`${packageManager} lint\` and \`${packageManager} format\` \u2014 run before committing`
|
|
74
|
+
"## After Editing",
|
|
75
|
+
""
|
|
179
76
|
];
|
|
180
|
-
if (
|
|
77
|
+
if (hasTypecheck) {
|
|
181
78
|
sections.push(
|
|
182
|
-
""
|
|
183
|
-
|
|
184
|
-
|
|
79
|
+
"\u2705 After editing files, check the types for errors and then format and lint only the files changed for the current task."
|
|
80
|
+
);
|
|
81
|
+
} else {
|
|
82
|
+
sections.push(
|
|
83
|
+
"\u2705 After editing files, format and lint only the files changed for the current task."
|
|
185
84
|
);
|
|
186
85
|
}
|
|
187
|
-
sections.push("");
|
|
86
|
+
sections.push("", "```sh", "# Example");
|
|
87
|
+
if (hasTypecheck) {
|
|
88
|
+
sections.push(runScript(packageManager, "typecheck"));
|
|
89
|
+
}
|
|
90
|
+
sections.push(
|
|
91
|
+
"# Run format and lint for only files modified",
|
|
92
|
+
commands.format,
|
|
93
|
+
commands.lint,
|
|
94
|
+
"```",
|
|
95
|
+
"",
|
|
96
|
+
"\u274C Avoid unless explicitly approved:",
|
|
97
|
+
"",
|
|
98
|
+
"```sh",
|
|
99
|
+
runScript(packageManager, "format"),
|
|
100
|
+
runScript(packageManager, "lint"),
|
|
101
|
+
"```",
|
|
102
|
+
""
|
|
103
|
+
);
|
|
188
104
|
return sections.join("\n");
|
|
189
105
|
}
|
|
106
|
+
function getAfterEditingCommands(ctx, files) {
|
|
107
|
+
return {
|
|
108
|
+
format: getFormatChangedFilesCommand(ctx, files),
|
|
109
|
+
lint: getLintChangedFilesCommand(ctx, files)
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
function getFormatChangedFilesCommand(ctx, files) {
|
|
113
|
+
const exec = getExecCommand(ctx.packageManager);
|
|
114
|
+
if (ctx.formatter === "prettier") {
|
|
115
|
+
const configPath = getPrettierConfigPath(ctx);
|
|
116
|
+
const ignorePath = getPrettierIgnorePath(ctx);
|
|
117
|
+
const configFlag2 = configPath == null ? "" : ` --config ${configPath}`;
|
|
118
|
+
const ignoreFlag = ignorePath == null ? "" : ` --ignore-path ${ignorePath}`;
|
|
119
|
+
return `${exec} prettier${configFlag2}${ignoreFlag} --write ${files}`;
|
|
120
|
+
}
|
|
121
|
+
if (ctx.formatter === "oxfmt") {
|
|
122
|
+
const configPath = getOxfmtConfigPath(ctx);
|
|
123
|
+
return `${exec} oxfmt -c ${configPath} --write ${files}`;
|
|
124
|
+
}
|
|
125
|
+
const configFlag = ctx.isMonorepo || ctx.configStrategy === "root" ? "" : " --config-path .config";
|
|
126
|
+
return `${exec} biome format${configFlag} --write ${files}`;
|
|
127
|
+
}
|
|
128
|
+
function getLintChangedFilesCommand(ctx, files) {
|
|
129
|
+
const exec = getExecCommand(ctx.packageManager);
|
|
130
|
+
if (ctx.linter === "oxlint") {
|
|
131
|
+
if (!ctx.isMonorepo) {
|
|
132
|
+
return runScript(ctx.packageManager, "lint", files);
|
|
133
|
+
}
|
|
134
|
+
return `${exec} oxlint ${files}`;
|
|
135
|
+
}
|
|
136
|
+
if (ctx.linter === "eslint") {
|
|
137
|
+
const configFlag2 = ctx.configStrategy === "stealth" ? " --config .config/eslint.config.js" : "";
|
|
138
|
+
return `${exec} eslint${configFlag2} ${files}`;
|
|
139
|
+
}
|
|
140
|
+
const configFlag = ctx.isMonorepo || ctx.configStrategy === "root" ? "" : " --config-path .config";
|
|
141
|
+
return `${exec} biome lint${configFlag} ${files}`;
|
|
142
|
+
}
|
|
143
|
+
function getPrettierConfigPath(ctx) {
|
|
144
|
+
if (ctx.isMonorepo) return ".config/prettier/base.json";
|
|
145
|
+
if (ctx.configStrategy === "stealth") return ".config/prettier.json";
|
|
146
|
+
return void 0;
|
|
147
|
+
}
|
|
148
|
+
function getPrettierIgnorePath(ctx) {
|
|
149
|
+
if (ctx.isMonorepo) return ".config/prettier/prettierignore";
|
|
150
|
+
if (ctx.configStrategy === "stealth") return ".config/prettierignore";
|
|
151
|
+
return void 0;
|
|
152
|
+
}
|
|
153
|
+
function getOxfmtConfigPath(ctx) {
|
|
154
|
+
if (ctx.isMonorepo) return ".config/oxfmt/base.json";
|
|
155
|
+
if (ctx.configStrategy === "stealth") return ".config/oxfmt.json";
|
|
156
|
+
return "oxfmt.json";
|
|
157
|
+
}
|
|
158
|
+
function runScript(packageManager, script, args) {
|
|
159
|
+
const suffix = args == null ? "" : ` ${args}`;
|
|
160
|
+
if (packageManager === "npm") {
|
|
161
|
+
return `npm run ${script}${args == null ? "" : ` --${suffix}`}`;
|
|
162
|
+
}
|
|
163
|
+
if (packageManager === "yarn") {
|
|
164
|
+
return `yarn ${script}${suffix}`;
|
|
165
|
+
}
|
|
166
|
+
return `${packageManager} ${script}${args == null ? "" : ` --${suffix}`}`;
|
|
167
|
+
}
|
|
168
|
+
function getExecCommand(packageManager) {
|
|
169
|
+
if (packageManager === "npm") return "npm exec --";
|
|
170
|
+
if (packageManager === "yarn") return "yarn exec";
|
|
171
|
+
return `${packageManager} exec`;
|
|
172
|
+
}
|
|
190
173
|
|
|
191
174
|
function getLanguageFromTemplate(template) {
|
|
192
175
|
return template.endsWith("-js") ? "javascript" : "typescript";
|
|
@@ -195,37 +178,51 @@ function getBaseTemplate(template) {
|
|
|
195
178
|
return template.replace("-js", "");
|
|
196
179
|
}
|
|
197
180
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
const
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
return fallback;
|
|
181
|
+
function unique(...array) {
|
|
182
|
+
const set = /* @__PURE__ */ new Set();
|
|
183
|
+
for (const arr of array) {
|
|
184
|
+
for (const item of arr) {
|
|
185
|
+
set.add(item);
|
|
186
|
+
}
|
|
205
187
|
}
|
|
188
|
+
return Array.from(set);
|
|
206
189
|
}
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
190
|
+
|
|
191
|
+
function merge(target, modification) {
|
|
192
|
+
const targetLabel = JSON.stringify(target);
|
|
193
|
+
const modificationLabel = JSON.stringify(modification);
|
|
194
|
+
if (modification == null) {
|
|
195
|
+
throw new Error(
|
|
196
|
+
`Cannot merge "${modificationLabel}" modification into target "${targetLabel}"`
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
if (target == null) {
|
|
200
|
+
return modification;
|
|
201
|
+
}
|
|
202
|
+
if (Array.isArray(target)) {
|
|
203
|
+
if (!Array.isArray(modification)) {
|
|
204
|
+
throw new Error(
|
|
205
|
+
`Cannot merge non-array modification "${modificationLabel}" into array target "${targetLabel}"`
|
|
206
|
+
);
|
|
223
207
|
}
|
|
224
|
-
return
|
|
225
|
-
}
|
|
226
|
-
|
|
208
|
+
return [...target, ...modification];
|
|
209
|
+
}
|
|
210
|
+
if (typeof target === "object") {
|
|
211
|
+
if (typeof modification !== "object") {
|
|
212
|
+
throw new Error(
|
|
213
|
+
`Cannot merge non-object modification "${modificationLabel}" into object target "${targetLabel}"`
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
const result = { ...target };
|
|
217
|
+
for (const modificationKey in modification) {
|
|
218
|
+
result[modificationKey] = merge(target[modificationKey], modification[modificationKey]);
|
|
219
|
+
}
|
|
220
|
+
return result;
|
|
227
221
|
}
|
|
222
|
+
console.warn(`target "${targetLabel}" is overwritten with modification "${modificationLabel}"`);
|
|
223
|
+
return modification;
|
|
228
224
|
}
|
|
225
|
+
|
|
229
226
|
function validateNameSegment(segment, label) {
|
|
230
227
|
if (!segment.length) {
|
|
231
228
|
return `${label} is required`;
|
|
@@ -269,103 +266,7 @@ function validatePackageName(name) {
|
|
|
269
266
|
}
|
|
270
267
|
return validateNameSegment(name, "Package name");
|
|
271
268
|
}
|
|
272
|
-
|
|
273
|
-
const directories = [];
|
|
274
|
-
let inPackagesSection = false;
|
|
275
|
-
for (const line of content.split("\n")) {
|
|
276
|
-
const trimmed = line.trim();
|
|
277
|
-
if (trimmed === "packages:") {
|
|
278
|
-
inPackagesSection = true;
|
|
279
|
-
continue;
|
|
280
|
-
}
|
|
281
|
-
if (inPackagesSection && trimmed && !line.startsWith(" ") && !line.startsWith(" ") && !trimmed.startsWith("-")) {
|
|
282
|
-
break;
|
|
283
|
-
}
|
|
284
|
-
if (inPackagesSection && trimmed.startsWith("-")) {
|
|
285
|
-
const entry = trimmed.slice(1).trim().replace(/^["']|["']$/g, "").replace(/^\.\//, "").replace(/\/\*.*$/, "");
|
|
286
|
-
if (entry && !entry.startsWith(".")) {
|
|
287
|
-
directories.push(entry);
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
return directories;
|
|
292
|
-
}
|
|
293
|
-
async function pathExists(path) {
|
|
294
|
-
try {
|
|
295
|
-
await access(path, constants.F_OK);
|
|
296
|
-
return true;
|
|
297
|
-
} catch {
|
|
298
|
-
return false;
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
function detectLinterFromScript(script) {
|
|
302
|
-
if (!script) return void 0;
|
|
303
|
-
if (script.includes("oxlint")) return "oxlint";
|
|
304
|
-
if (script.includes("eslint")) return "eslint";
|
|
305
|
-
if (script.includes("biome check") || script.includes("biome lint")) return "biome";
|
|
306
|
-
return void 0;
|
|
307
|
-
}
|
|
308
|
-
function detectFormatterFromScript(script) {
|
|
309
|
-
if (!script) return void 0;
|
|
310
|
-
if (script.includes("prettier")) return "prettier";
|
|
311
|
-
if (script.includes("oxfmt")) return "oxfmt";
|
|
312
|
-
if (script.includes("biome format")) return "biome";
|
|
313
|
-
return void 0;
|
|
314
|
-
}
|
|
315
|
-
async function detectLinterFromConfig(root) {
|
|
316
|
-
if (await pathExists(join(root, ".config/oxlint"))) return "oxlint";
|
|
317
|
-
if (await pathExists(join(root, ".config/eslint"))) return "eslint";
|
|
318
|
-
if (await pathExists(join(root, "biome.json"))) {
|
|
319
|
-
try {
|
|
320
|
-
const content = await readFile(join(root, "biome.json"), "utf-8");
|
|
321
|
-
const config = JSON.parse(content);
|
|
322
|
-
if (config.linter?.enabled !== false) return "biome";
|
|
323
|
-
} catch {
|
|
324
|
-
return "biome";
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
return void 0;
|
|
328
|
-
}
|
|
329
|
-
async function detectFormatterFromConfig(root) {
|
|
330
|
-
if (await pathExists(join(root, ".config/prettier"))) return "prettier";
|
|
331
|
-
if (await pathExists(join(root, ".config/oxfmt"))) return "oxfmt";
|
|
332
|
-
if (await pathExists(join(root, "biome.json"))) {
|
|
333
|
-
try {
|
|
334
|
-
const content = await readFile(join(root, "biome.json"), "utf-8");
|
|
335
|
-
const config = JSON.parse(content);
|
|
336
|
-
if (config.formatter?.enabled !== false) return "biome";
|
|
337
|
-
} catch {
|
|
338
|
-
return "biome";
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
return void 0;
|
|
342
|
-
}
|
|
343
|
-
function detectLinterFromDeps(devDeps) {
|
|
344
|
-
if (!devDeps) return void 0;
|
|
345
|
-
if (devDeps["@biomejs/biome"]) return "biome";
|
|
346
|
-
if (devDeps.eslint) return "eslint";
|
|
347
|
-
if (devDeps.oxlint) return "oxlint";
|
|
348
|
-
return void 0;
|
|
349
|
-
}
|
|
350
|
-
function detectFormatterFromDeps(devDeps) {
|
|
351
|
-
if (!devDeps) return void 0;
|
|
352
|
-
if (devDeps["@biomejs/biome"]) return "biome";
|
|
353
|
-
if (devDeps.prettier) return "prettier";
|
|
354
|
-
if (devDeps.oxfmt) return "oxfmt";
|
|
355
|
-
return void 0;
|
|
356
|
-
}
|
|
357
|
-
async function detectTooling(root) {
|
|
358
|
-
try {
|
|
359
|
-
const pkgPath = join(root, "package.json");
|
|
360
|
-
const content = await readFile(pkgPath, "utf-8");
|
|
361
|
-
const pkg = JSON.parse(content);
|
|
362
|
-
const linter = detectLinterFromScript(pkg.scripts?.lint) ?? await detectLinterFromConfig(root) ?? detectLinterFromDeps(pkg.devDependencies);
|
|
363
|
-
const formatter = detectFormatterFromScript(pkg.scripts?.format) ?? await detectFormatterFromConfig(root) ?? detectFormatterFromDeps(pkg.devDependencies);
|
|
364
|
-
return { linter, formatter };
|
|
365
|
-
} catch {
|
|
366
|
-
return { linter: void 0, formatter: void 0 };
|
|
367
|
-
}
|
|
368
|
-
}
|
|
269
|
+
|
|
369
270
|
function generateRandomName() {
|
|
370
271
|
const adjectives = [
|
|
371
272
|
"red",
|
|
@@ -442,6 +343,159 @@ function generateRandomName() {
|
|
|
442
343
|
return `${randomAdjective}-${randomNoun}`;
|
|
443
344
|
}
|
|
444
345
|
|
|
346
|
+
async function pathExists(path) {
|
|
347
|
+
try {
|
|
348
|
+
await access(path, constants.F_OK);
|
|
349
|
+
return true;
|
|
350
|
+
} catch {
|
|
351
|
+
return false;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
function detectLinterFromScript(script) {
|
|
355
|
+
if (!script) return void 0;
|
|
356
|
+
if (script.includes("oxlint")) return "oxlint";
|
|
357
|
+
if (script.includes("eslint")) return "eslint";
|
|
358
|
+
if (script.includes("biome check") || script.includes("biome lint")) return "biome";
|
|
359
|
+
return void 0;
|
|
360
|
+
}
|
|
361
|
+
function detectFormatterFromScript(script) {
|
|
362
|
+
if (!script) return void 0;
|
|
363
|
+
if (script.includes("prettier")) return "prettier";
|
|
364
|
+
if (script.includes("oxfmt")) return "oxfmt";
|
|
365
|
+
if (script.includes("biome format")) return "biome";
|
|
366
|
+
return void 0;
|
|
367
|
+
}
|
|
368
|
+
async function detectLinterFromConfig(root) {
|
|
369
|
+
if (await pathExists(join(root, ".config/oxlint"))) return "oxlint";
|
|
370
|
+
if (await pathExists(join(root, ".config/eslint"))) return "eslint";
|
|
371
|
+
if (await pathExists(join(root, "biome.json"))) {
|
|
372
|
+
try {
|
|
373
|
+
const content = await readFile(join(root, "biome.json"), "utf-8");
|
|
374
|
+
const config = JSON.parse(content);
|
|
375
|
+
if (config.linter?.enabled !== false) return "biome";
|
|
376
|
+
} catch {
|
|
377
|
+
return "biome";
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
return void 0;
|
|
381
|
+
}
|
|
382
|
+
async function detectFormatterFromConfig(root) {
|
|
383
|
+
if (await pathExists(join(root, ".config/prettier"))) return "prettier";
|
|
384
|
+
if (await pathExists(join(root, ".config/oxfmt"))) return "oxfmt";
|
|
385
|
+
if (await pathExists(join(root, "biome.json"))) {
|
|
386
|
+
try {
|
|
387
|
+
const content = await readFile(join(root, "biome.json"), "utf-8");
|
|
388
|
+
const config = JSON.parse(content);
|
|
389
|
+
if (config.formatter?.enabled !== false) return "biome";
|
|
390
|
+
} catch {
|
|
391
|
+
return "biome";
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
return void 0;
|
|
395
|
+
}
|
|
396
|
+
function detectLinterFromDeps(devDeps) {
|
|
397
|
+
if (!devDeps) return void 0;
|
|
398
|
+
if (devDeps["@biomejs/biome"]) return "biome";
|
|
399
|
+
if (devDeps.eslint) return "eslint";
|
|
400
|
+
if (devDeps.oxlint) return "oxlint";
|
|
401
|
+
return void 0;
|
|
402
|
+
}
|
|
403
|
+
function detectFormatterFromDeps(devDeps) {
|
|
404
|
+
if (!devDeps) return void 0;
|
|
405
|
+
if (devDeps["@biomejs/biome"]) return "biome";
|
|
406
|
+
if (devDeps.prettier) return "prettier";
|
|
407
|
+
if (devDeps.oxfmt) return "oxfmt";
|
|
408
|
+
return void 0;
|
|
409
|
+
}
|
|
410
|
+
async function detectTooling(root) {
|
|
411
|
+
try {
|
|
412
|
+
const pkgPath = join(root, "package.json");
|
|
413
|
+
const content = await readFile(pkgPath, "utf-8");
|
|
414
|
+
const pkg = JSON.parse(content);
|
|
415
|
+
const linter = detectLinterFromScript(pkg.scripts?.lint) ?? await detectLinterFromConfig(root) ?? detectLinterFromDeps(pkg.devDependencies);
|
|
416
|
+
const formatter = detectFormatterFromScript(pkg.scripts?.format) ?? await detectFormatterFromConfig(root) ?? detectFormatterFromDeps(pkg.devDependencies);
|
|
417
|
+
return { linter, formatter };
|
|
418
|
+
} catch {
|
|
419
|
+
return { linter: void 0, formatter: void 0 };
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
async function getLatestNpmVersion(packageName, fallback) {
|
|
424
|
+
try {
|
|
425
|
+
const response = await fetch(`https://registry.npmjs.org/${packageName}/latest`);
|
|
426
|
+
const data = await response.json();
|
|
427
|
+
return data.version;
|
|
428
|
+
} catch {
|
|
429
|
+
return fallback;
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
function compareNumericSemver(a, b) {
|
|
433
|
+
const aParts = a.split(".").map((part) => Number.parseInt(part, 10) || 0);
|
|
434
|
+
const bParts = b.split(".").map((part) => Number.parseInt(part, 10) || 0);
|
|
435
|
+
const maxLength = Math.max(aParts.length, bParts.length);
|
|
436
|
+
for (let index = 0; index < maxLength; index += 1) {
|
|
437
|
+
const difference = (aParts[index] ?? 0) - (bParts[index] ?? 0);
|
|
438
|
+
if (difference !== 0) {
|
|
439
|
+
return difference;
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
return 0;
|
|
443
|
+
}
|
|
444
|
+
async function getLatestNpmMajorVersion(packageName, majorVersion, fallback) {
|
|
445
|
+
try {
|
|
446
|
+
const response = await fetch(`https://registry.npmjs.org/${packageName}`);
|
|
447
|
+
const data = await response.json();
|
|
448
|
+
const latestMatchingVersion = Object.keys(data.versions ?? {}).filter((version) => version.split(".")[0] === majorVersion).sort((a, b) => compareNumericSemver(b, a))[0];
|
|
449
|
+
return latestMatchingVersion ?? fallback;
|
|
450
|
+
} catch {
|
|
451
|
+
return fallback;
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
async function getLatestPnpmVersion() {
|
|
455
|
+
return getLatestNpmVersion("pnpm", "10.11.0");
|
|
456
|
+
}
|
|
457
|
+
async function getLatestYarnVersion() {
|
|
458
|
+
return getLatestNpmVersion("yarn", "4.6.0");
|
|
459
|
+
}
|
|
460
|
+
async function getLatestNpmCliVersion() {
|
|
461
|
+
return getLatestNpmVersion("npm", "11.0.0");
|
|
462
|
+
}
|
|
463
|
+
async function getLatestNodeVersion() {
|
|
464
|
+
try {
|
|
465
|
+
const response = await fetch("https://nodejs.org/dist/index.json");
|
|
466
|
+
const data = await response.json();
|
|
467
|
+
const latestVersion = data[0];
|
|
468
|
+
if (latestVersion) {
|
|
469
|
+
return latestVersion.version.replace(/^v/, "");
|
|
470
|
+
}
|
|
471
|
+
return "25.0.0";
|
|
472
|
+
} catch {
|
|
473
|
+
return "25.0.0";
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
function parseWorkspaceYamlContent(content) {
|
|
478
|
+
const directories = [];
|
|
479
|
+
let inPackagesSection = false;
|
|
480
|
+
for (const line of content.split("\n")) {
|
|
481
|
+
const trimmed = line.trim();
|
|
482
|
+
if (trimmed === "packages:") {
|
|
483
|
+
inPackagesSection = true;
|
|
484
|
+
continue;
|
|
485
|
+
}
|
|
486
|
+
if (inPackagesSection && trimmed && !line.startsWith(" ") && !line.startsWith(" ") && !trimmed.startsWith("-")) {
|
|
487
|
+
break;
|
|
488
|
+
}
|
|
489
|
+
if (inPackagesSection && trimmed.startsWith("-")) {
|
|
490
|
+
const entry = trimmed.slice(1).trim().replace(/^["']|["']$/g, "").replace(/^\.\//, "").replace(/\/\*.*$/, "");
|
|
491
|
+
if (entry && !entry.startsWith(".")) {
|
|
492
|
+
directories.push(entry);
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
return directories;
|
|
497
|
+
}
|
|
498
|
+
|
|
445
499
|
const PACKAGE_VERSION_DEFINITIONS = {
|
|
446
500
|
"@biomejs/biome": { fallbackVersion: "2.0.0" },
|
|
447
501
|
"@react-three/drei": { fallbackVersion: "10.0.0" },
|
|
@@ -467,11 +521,13 @@ const PACKAGE_VERSION_DEFINITIONS = {
|
|
|
467
521
|
leva: { fallbackVersion: "0.10.0" },
|
|
468
522
|
oxfmt: { fallbackVersion: "0.21.0" },
|
|
469
523
|
oxlint: { fallbackVersion: "1.36.0" },
|
|
524
|
+
"oxlint-tsgolint": { fallbackVersion: "0.22.1" },
|
|
470
525
|
prettier: { fallbackVersion: "3.4.2" },
|
|
471
526
|
react: { fallbackVersion: "19.0.0" },
|
|
472
527
|
"react-dom": { fallbackVersion: "19.0.0" },
|
|
473
528
|
three: { fallbackVersion: "0.175.0", prefix: "~" },
|
|
474
529
|
tsdown: { fallbackVersion: "0.12.0" },
|
|
530
|
+
typescript: { fallbackVersion: "5.9.3" },
|
|
475
531
|
"typescript-eslint": { fallbackVersion: "8.18.0" },
|
|
476
532
|
unbuild: { fallbackVersion: "3.5.0" },
|
|
477
533
|
vite: { fallbackVersion: "6.3.4" },
|
|
@@ -563,11 +619,35 @@ async function resolvePackageManager(options) {
|
|
|
563
619
|
}
|
|
564
620
|
async function resolveEngine(options) {
|
|
565
621
|
const engine = getEngineSpec(options.engine);
|
|
566
|
-
if (engine.version == null && engine.name === "node") {
|
|
622
|
+
if ((engine.version == null || engine.version === "latest") && engine.name === "node") {
|
|
567
623
|
engine.version = await getLatestNodeVersion();
|
|
568
624
|
}
|
|
569
625
|
return engine;
|
|
570
626
|
}
|
|
627
|
+
function formatNodeTypesVersion(versions = {}, engine) {
|
|
628
|
+
const resolvedVersion = versions["@types/node"];
|
|
629
|
+
if (resolvedVersion != null) {
|
|
630
|
+
return `^${resolvedVersion}`;
|
|
631
|
+
}
|
|
632
|
+
const engineSpec = getEngineSpec(engine);
|
|
633
|
+
if (engineSpec.name === "node" && engineSpec.version) {
|
|
634
|
+
const majorVersion = engineSpec.version.split(".")[0];
|
|
635
|
+
return `^${majorVersion}.0.0`;
|
|
636
|
+
}
|
|
637
|
+
return "^22.0.0";
|
|
638
|
+
}
|
|
639
|
+
async function resolveNodeTypesVersion(engine, versions = {}) {
|
|
640
|
+
if (versions["@types/node"] != null) {
|
|
641
|
+
return versions["@types/node"];
|
|
642
|
+
}
|
|
643
|
+
const engineSpec = getEngineSpec(engine);
|
|
644
|
+
if (engineSpec.name !== "node") {
|
|
645
|
+
return void 0;
|
|
646
|
+
}
|
|
647
|
+
const nodeVersion = engineSpec.version ?? await getLatestNodeVersion();
|
|
648
|
+
const majorVersion = nodeVersion.split(".")[0];
|
|
649
|
+
return getLatestNpmMajorVersion("@types/node", majorVersion, `${majorVersion}.0.0`);
|
|
650
|
+
}
|
|
571
651
|
async function resolvePackageVersions(packageNames, existingVersions = {}) {
|
|
572
652
|
const versions = { ...existingVersions };
|
|
573
653
|
const uniquePackageNames = [...new Set(packageNames)];
|
|
@@ -583,16 +663,33 @@ async function resolvePackageVersions(packageNames, existingVersions = {}) {
|
|
|
583
663
|
return versions;
|
|
584
664
|
}
|
|
585
665
|
async function resolveProjectPackageVersions(options) {
|
|
586
|
-
|
|
666
|
+
const packageNames = collectProjectPackageNames(options);
|
|
667
|
+
const versions = await resolvePackageVersions(
|
|
668
|
+
packageNames.filter((packageName) => packageName !== "@types/node"),
|
|
669
|
+
options.versions
|
|
670
|
+
);
|
|
671
|
+
const nodeTypesVersion = await resolveNodeTypesVersion(options.engine, versions);
|
|
672
|
+
if (nodeTypesVersion != null) {
|
|
673
|
+
versions["@types/node"] = nodeTypesVersion;
|
|
674
|
+
}
|
|
675
|
+
return versions;
|
|
587
676
|
}
|
|
588
677
|
async function resolveMonorepoRootPackageVersions(params) {
|
|
589
678
|
const packageNames = /* @__PURE__ */ new Set();
|
|
590
679
|
const explicitVersions = new Set(Object.keys(params.versions ?? {}));
|
|
591
680
|
addPackageName(packageNames, explicitVersions, getLinterPackage(params.linter));
|
|
681
|
+
if (params.linter === "oxlint") {
|
|
682
|
+
addPackageName(packageNames, explicitVersions, "oxlint-tsgolint");
|
|
683
|
+
}
|
|
592
684
|
if (params.formatter !== "biome" || params.linter !== "biome") {
|
|
593
685
|
addPackageName(packageNames, explicitVersions, getFormatterPackage(params.formatter));
|
|
594
686
|
}
|
|
595
|
-
|
|
687
|
+
const versions = await resolvePackageVersions(packageNames, params.versions);
|
|
688
|
+
const nodeTypesVersion = await resolveNodeTypesVersion(params.engine, versions);
|
|
689
|
+
if (nodeTypesVersion != null) {
|
|
690
|
+
versions["@types/node"] = nodeTypesVersion;
|
|
691
|
+
}
|
|
692
|
+
return versions;
|
|
596
693
|
}
|
|
597
694
|
function collectProjectPackageNames(options) {
|
|
598
695
|
const packageNames = /* @__PURE__ */ new Set();
|
|
@@ -610,6 +707,13 @@ function collectProjectPackageNames(options) {
|
|
|
610
707
|
const formatter = options.formatter ?? "prettier";
|
|
611
708
|
const bundler = options.libraryBundler ?? "unbuild";
|
|
612
709
|
const packageManager = getPackageManagerName(options.packageManager);
|
|
710
|
+
const engine = getEngineSpec(options.engine);
|
|
711
|
+
if (getEngineName(engine) === "node") {
|
|
712
|
+
addPackageName(packageNames, explicitVersions, "@types/node");
|
|
713
|
+
}
|
|
714
|
+
if (isTypescript) {
|
|
715
|
+
addPackageName(packageNames, explicitVersions, "typescript");
|
|
716
|
+
}
|
|
613
717
|
if (!isLibrary) {
|
|
614
718
|
addPackageName(packageNames, explicitVersions, "vite");
|
|
615
719
|
}
|
|
@@ -686,6 +790,9 @@ function collectProjectPackageNames(options) {
|
|
|
686
790
|
} else if (linter === "oxlint") {
|
|
687
791
|
if (!inWorkspace) {
|
|
688
792
|
addPackageName(packageNames, explicitVersions, "oxlint");
|
|
793
|
+
if (isTypescript) {
|
|
794
|
+
addPackageName(packageNames, explicitVersions, "oxlint-tsgolint");
|
|
795
|
+
}
|
|
689
796
|
}
|
|
690
797
|
} else if (linter === "biome") {
|
|
691
798
|
addPackageName(packageNames, explicitVersions, "@biomejs/biome");
|
|
@@ -720,7 +827,7 @@ function isEnabledOption(option) {
|
|
|
720
827
|
return option != null && option !== false;
|
|
721
828
|
}
|
|
722
829
|
|
|
723
|
-
function
|
|
830
|
+
function renderTypescriptConfig(baseTemplateOrParams) {
|
|
724
831
|
const params = typeof baseTemplateOrParams === "string" ? { baseTemplate: baseTemplateOrParams } : baseTemplateOrParams;
|
|
725
832
|
const {
|
|
726
833
|
baseTemplate,
|
|
@@ -733,9 +840,9 @@ function generateTypescriptConfig(baseTemplateOrParams) {
|
|
|
733
840
|
const isR3f = baseTemplate === "r3f";
|
|
734
841
|
const files = {};
|
|
735
842
|
const devDependencies = {};
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
devDependencies["@types/node"] =
|
|
843
|
+
assignResolvedPackageVersion(devDependencies, versions, "typescript");
|
|
844
|
+
if (getEngineName(engine) === "node") {
|
|
845
|
+
devDependencies["@types/node"] = formatNodeTypesVersion(versions, engine);
|
|
739
846
|
} else {
|
|
740
847
|
devDependencies["@types/node"] = "^22.0.0";
|
|
741
848
|
}
|
|
@@ -790,6 +897,7 @@ function generateTypescriptConfig(baseTemplateOrParams) {
|
|
|
790
897
|
composite: true,
|
|
791
898
|
rewriteRelativeImportExtensions: true,
|
|
792
899
|
erasableSyntaxOnly: true,
|
|
900
|
+
noEmit: true,
|
|
793
901
|
...isReact || isR3f ? { jsx: "react-jsx" } : {}
|
|
794
902
|
},
|
|
795
903
|
include: ["../src", "../tests"]
|
|
@@ -811,7 +919,8 @@ function generateTypescriptConfig(baseTemplateOrParams) {
|
|
|
811
919
|
skipLibCheck: true,
|
|
812
920
|
composite: true,
|
|
813
921
|
rewriteRelativeImportExtensions: true,
|
|
814
|
-
erasableSyntaxOnly: true
|
|
922
|
+
erasableSyntaxOnly: true,
|
|
923
|
+
noEmit: true
|
|
815
924
|
},
|
|
816
925
|
include: ["../*.config.ts", "./*.ts"]
|
|
817
926
|
};
|
|
@@ -843,6 +952,7 @@ function generateTypescriptConfig(baseTemplateOrParams) {
|
|
|
843
952
|
composite: true,
|
|
844
953
|
rewriteRelativeImportExtensions: true,
|
|
845
954
|
erasableSyntaxOnly: true,
|
|
955
|
+
noEmit: true,
|
|
846
956
|
...isReact || isR3f ? { jsx: "react-jsx" } : {}
|
|
847
957
|
},
|
|
848
958
|
include: ["src", "tests"]
|
|
@@ -864,7 +974,8 @@ function generateTypescriptConfig(baseTemplateOrParams) {
|
|
|
864
974
|
skipLibCheck: true,
|
|
865
975
|
composite: true,
|
|
866
976
|
rewriteRelativeImportExtensions: true,
|
|
867
|
-
erasableSyntaxOnly: true
|
|
977
|
+
erasableSyntaxOnly: true,
|
|
978
|
+
noEmit: true
|
|
868
979
|
},
|
|
869
980
|
include: ["*.config.ts"]
|
|
870
981
|
};
|
|
@@ -876,8 +987,108 @@ function generateTypescriptConfig(baseTemplateOrParams) {
|
|
|
876
987
|
return { files, devDependencies };
|
|
877
988
|
}
|
|
878
989
|
|
|
990
|
+
const packageJsonScripts = {
|
|
991
|
+
appBase: {
|
|
992
|
+
dev: "vite",
|
|
993
|
+
build: "vite build"
|
|
994
|
+
},
|
|
995
|
+
typescript: {
|
|
996
|
+
typecheck: "tsc --build --noEmit",
|
|
997
|
+
"typecheck:watch": "tsc --build --watch"
|
|
998
|
+
},
|
|
999
|
+
test: {
|
|
1000
|
+
vitest: {
|
|
1001
|
+
test: "vitest"
|
|
1002
|
+
}
|
|
1003
|
+
},
|
|
1004
|
+
build: {
|
|
1005
|
+
unbuild(configPath) {
|
|
1006
|
+
return {
|
|
1007
|
+
build: configPath == null ? "unbuild" : `unbuild --config ${configPath}`
|
|
1008
|
+
};
|
|
1009
|
+
},
|
|
1010
|
+
tsdown: {
|
|
1011
|
+
build: "tsdown"
|
|
1012
|
+
}
|
|
1013
|
+
},
|
|
1014
|
+
lint: {
|
|
1015
|
+
oxlint(configPath) {
|
|
1016
|
+
return {
|
|
1017
|
+
lint: configPath == null ? "oxlint" : `oxlint -c ${configPath}`
|
|
1018
|
+
};
|
|
1019
|
+
},
|
|
1020
|
+
eslint(configPath) {
|
|
1021
|
+
return {
|
|
1022
|
+
lint: configPath == null ? "eslint ." : `eslint --config ${configPath} .`
|
|
1023
|
+
};
|
|
1024
|
+
},
|
|
1025
|
+
biome(configPath) {
|
|
1026
|
+
return {
|
|
1027
|
+
lint: configPath == null ? "biome lint ." : `biome lint --config-path ${configPath} .`
|
|
1028
|
+
};
|
|
1029
|
+
}
|
|
1030
|
+
},
|
|
1031
|
+
format: {
|
|
1032
|
+
prettier(configPath, ignorePath) {
|
|
1033
|
+
const configFlag = configPath == null ? "" : ` --config ${configPath}`;
|
|
1034
|
+
const ignoreFlag = ignorePath == null ? "" : ` --ignore-path ${ignorePath}`;
|
|
1035
|
+
return {
|
|
1036
|
+
format: `prettier${configFlag}${ignoreFlag} --write .`
|
|
1037
|
+
};
|
|
1038
|
+
},
|
|
1039
|
+
oxfmt(configPath) {
|
|
1040
|
+
return {
|
|
1041
|
+
format: `oxfmt -c ${configPath} --write .`
|
|
1042
|
+
};
|
|
1043
|
+
},
|
|
1044
|
+
biome(configPath) {
|
|
1045
|
+
return {
|
|
1046
|
+
format: configPath == null ? "biome format --write ." : `biome format --config-path ${configPath} --write .`
|
|
1047
|
+
};
|
|
1048
|
+
}
|
|
1049
|
+
},
|
|
1050
|
+
release(packageManagerName) {
|
|
1051
|
+
return {
|
|
1052
|
+
release: `${packageManagerName} run build && ${packageManagerName} publish`
|
|
1053
|
+
};
|
|
1054
|
+
},
|
|
1055
|
+
monorepoRoot(linter, formatter) {
|
|
1056
|
+
return mergePackageJsonScripts(
|
|
1057
|
+
{
|
|
1058
|
+
dev: "pnpm --filter './apps/*' run dev",
|
|
1059
|
+
build: "pnpm --filter './packages/*' run build && pnpm --filter './apps/*' run build",
|
|
1060
|
+
test: "pnpm -r run test"
|
|
1061
|
+
},
|
|
1062
|
+
linter === "oxlint" ? {
|
|
1063
|
+
lint: "oxlint ."
|
|
1064
|
+
} : linter === "biome" ? {
|
|
1065
|
+
lint: "biome check ."
|
|
1066
|
+
} : {
|
|
1067
|
+
lint: "eslint ."
|
|
1068
|
+
},
|
|
1069
|
+
formatter === "oxfmt" ? {
|
|
1070
|
+
format: "oxfmt -c .config/oxfmt/base.json ."
|
|
1071
|
+
} : formatter === "biome" ? {
|
|
1072
|
+
format: "biome format . --write"
|
|
1073
|
+
} : {
|
|
1074
|
+
format: "prettier --config .config/prettier/base.json --ignore-path .config/prettier/prettierignore --write ."
|
|
1075
|
+
}
|
|
1076
|
+
);
|
|
1077
|
+
}
|
|
1078
|
+
};
|
|
1079
|
+
function mergePackageJsonScripts(...scriptSets) {
|
|
1080
|
+
return Object.assign({}, ...scriptSets.filter((scriptSet) => scriptSet != null));
|
|
1081
|
+
}
|
|
1082
|
+
function resolveDefaultPackageJsonScripts(params) {
|
|
1083
|
+
return mergePackageJsonScripts(
|
|
1084
|
+
params.isLibrary ? void 0 : packageJsonScripts.appBase,
|
|
1085
|
+
params.language === "typescript" ? packageJsonScripts.typescript : void 0,
|
|
1086
|
+
params.isLibrary ? packageJsonScripts.release(params.packageManagerName) : void 0
|
|
1087
|
+
);
|
|
1088
|
+
}
|
|
1089
|
+
|
|
879
1090
|
const DEFAULT_LIBRARY_VERSION = "0.1.0";
|
|
880
|
-
function
|
|
1091
|
+
function renderPackageJson(params) {
|
|
881
1092
|
const {
|
|
882
1093
|
name,
|
|
883
1094
|
language,
|
|
@@ -885,13 +1096,20 @@ function generatePackageJson(params) {
|
|
|
885
1096
|
dependencies,
|
|
886
1097
|
devDependencies,
|
|
887
1098
|
peerDependencies,
|
|
888
|
-
scripts,
|
|
889
1099
|
options,
|
|
890
1100
|
workspaceDependencies
|
|
891
1101
|
} = params;
|
|
892
1102
|
const files = {};
|
|
893
1103
|
const packageManager = getPackageManagerSpec(options.packageManager);
|
|
894
1104
|
const isPnpm = packageManager.name === "pnpm";
|
|
1105
|
+
const resolvedScripts = mergePackageJsonScripts(
|
|
1106
|
+
resolveDefaultPackageJsonScripts({
|
|
1107
|
+
language,
|
|
1108
|
+
isLibrary,
|
|
1109
|
+
packageManagerName: packageManager.name
|
|
1110
|
+
}),
|
|
1111
|
+
params.scripts
|
|
1112
|
+
);
|
|
895
1113
|
const packageJson = {
|
|
896
1114
|
name,
|
|
897
1115
|
description: "Built with \u{1F339} create-krispya",
|
|
@@ -923,10 +1141,12 @@ function generatePackageJson(params) {
|
|
|
923
1141
|
const allDevDependencies = { ...devDependencies };
|
|
924
1142
|
const engine = getEngineSpec(options.engine);
|
|
925
1143
|
if (getEngineName(engine) === "node" && engine.version) {
|
|
926
|
-
|
|
927
|
-
|
|
1144
|
+
allDevDependencies["@types/node"] ??= formatNodeTypesVersion(
|
|
1145
|
+
options.versions,
|
|
1146
|
+
options.engine
|
|
1147
|
+
);
|
|
928
1148
|
}
|
|
929
|
-
packageJson.scripts =
|
|
1149
|
+
packageJson.scripts = resolvedScripts;
|
|
930
1150
|
packageJson.dependencies = sortKeys(allDependencies);
|
|
931
1151
|
if (Object.keys(allDevDependencies).length > 0) {
|
|
932
1152
|
packageJson.devDependencies = sortKeys(allDevDependencies);
|
|
@@ -969,7 +1189,7 @@ function generatePackageJson(params) {
|
|
|
969
1189
|
return { files };
|
|
970
1190
|
}
|
|
971
1191
|
|
|
972
|
-
function
|
|
1192
|
+
function renderReadme(params) {
|
|
973
1193
|
const { name, baseTemplate, isLibrary, libraryBundler, packageManager, codeSnippets } = params;
|
|
974
1194
|
const isVanilla = baseTemplate === "vanilla";
|
|
975
1195
|
const isReact = baseTemplate === "react";
|
|
@@ -1062,7 +1282,63 @@ function generateReadme(params) {
|
|
|
1062
1282
|
return { type: "text", content };
|
|
1063
1283
|
}
|
|
1064
1284
|
|
|
1065
|
-
|
|
1285
|
+
const htmlContent = `<!DOCTYPE html>
|
|
1286
|
+
<html lang="en">
|
|
1287
|
+
<head>
|
|
1288
|
+
<meta charset="UTF-8">
|
|
1289
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
1290
|
+
<title>$title</title>
|
|
1291
|
+
</head>
|
|
1292
|
+
<body style="margin: 0; overscroll-behavior: none; user-select: none; touch-action: none;">
|
|
1293
|
+
<script type="module" src="$indexPath"><\/script>
|
|
1294
|
+
<div style="width: 100dvw; height: 100dvh; overflow: hidden;" id="root"></div>
|
|
1295
|
+
</body>
|
|
1296
|
+
</html>`;
|
|
1297
|
+
const viteHtmlContent = `<!DOCTYPE html>
|
|
1298
|
+
<html lang="en">
|
|
1299
|
+
<head>
|
|
1300
|
+
<meta charset="UTF-8">
|
|
1301
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
1302
|
+
<title>$title</title>
|
|
1303
|
+
</head>
|
|
1304
|
+
<body>
|
|
1305
|
+
<div id="app"></div>
|
|
1306
|
+
<script type="module" src="$indexPath"><\/script>
|
|
1307
|
+
</body>
|
|
1308
|
+
</html>`;
|
|
1309
|
+
const indexContent = `import { StrictMode } from 'react'
|
|
1310
|
+
import { createRoot } from 'react-dom/client'
|
|
1311
|
+
import { App } from './app.js'
|
|
1312
|
+
|
|
1313
|
+
createRoot(document.getElementById('root')!).render(
|
|
1314
|
+
<StrictMode>
|
|
1315
|
+
<App />
|
|
1316
|
+
</StrictMode>,
|
|
1317
|
+
)`;
|
|
1318
|
+
const viteIndexContent = `import './style.css'
|
|
1319
|
+
|
|
1320
|
+
document.querySelector('#app')!.innerHTML = \`
|
|
1321
|
+
<h1>Hello Vite!</h1>
|
|
1322
|
+
<p>Edit src/main.ts and save to see HMR in action.</p>
|
|
1323
|
+
\``;
|
|
1324
|
+
const viteStyleContent = `body {
|
|
1325
|
+
font-family: system-ui, -apple-system, sans-serif;
|
|
1326
|
+
margin: 0;
|
|
1327
|
+
padding: 2rem;
|
|
1328
|
+
min-height: 100vh;
|
|
1329
|
+
background: #1a1a1a;
|
|
1330
|
+
color: #fff;
|
|
1331
|
+
}
|
|
1332
|
+
|
|
1333
|
+
h1 {
|
|
1334
|
+
color: #646cff;
|
|
1335
|
+
}
|
|
1336
|
+
|
|
1337
|
+
a {
|
|
1338
|
+
color: #646cff;
|
|
1339
|
+
}`;
|
|
1340
|
+
|
|
1341
|
+
function renderSourceFiles(params) {
|
|
1066
1342
|
const { name, baseTemplate, language, isLibrary, codeSnippets, replacements } = params;
|
|
1067
1343
|
const files = {};
|
|
1068
1344
|
const ext = language === "typescript" ? "ts" : "js";
|
|
@@ -1102,19 +1378,13 @@ function generateSourceFiles(params) {
|
|
|
1102
1378
|
}
|
|
1103
1379
|
files[`src/index.${libExt}`] = { type: "text", content: libContent };
|
|
1104
1380
|
} else if (isVanilla) {
|
|
1105
|
-
files[`src/main.${ext}`] = { type: "text", content:
|
|
1106
|
-
files["src/style.css"] = { type: "text", content:
|
|
1107
|
-
const indexHtml =
|
|
1108
|
-
"$title",
|
|
1109
|
-
name
|
|
1110
|
-
);
|
|
1381
|
+
files[`src/main.${ext}`] = { type: "text", content: viteIndexContent };
|
|
1382
|
+
files["src/style.css"] = { type: "text", content: viteStyleContent };
|
|
1383
|
+
const indexHtml = viteHtmlContent.replace("$indexPath", `./src/main.${ext}`).replace("$title", name);
|
|
1111
1384
|
files["index.html"] = { type: "text", content: indexHtml };
|
|
1112
1385
|
} else {
|
|
1113
|
-
files[`src/index.tsx`] = { type: "text", content:
|
|
1114
|
-
const indexHtml =
|
|
1115
|
-
"$indexPath",
|
|
1116
|
-
language === "javascript" ? "./src/index.jsx" : "./src/index.tsx"
|
|
1117
|
-
).replace("$title", name);
|
|
1386
|
+
files[`src/index.tsx`] = { type: "text", content: indexContent };
|
|
1387
|
+
const indexHtml = htmlContent.replace("$indexPath", language === "javascript" ? "./src/index.jsx" : "./src/index.tsx").replace("$title", name);
|
|
1118
1388
|
files["index.html"] = { type: "text", content: indexHtml };
|
|
1119
1389
|
codeSnippets["dom-end"]?.reverse();
|
|
1120
1390
|
codeSnippets["global-end"]?.reverse();
|
|
@@ -1161,7 +1431,7 @@ function generateSourceFiles(params) {
|
|
|
1161
1431
|
return files;
|
|
1162
1432
|
}
|
|
1163
1433
|
|
|
1164
|
-
function
|
|
1434
|
+
function renderTestFiles(params) {
|
|
1165
1435
|
const { baseTemplate, language, isLibrary } = params;
|
|
1166
1436
|
const files = {};
|
|
1167
1437
|
const ext = language === "typescript" ? "ts" : "js";
|
|
@@ -1268,21 +1538,184 @@ const COMMON_GITIGNORE_LINES = [
|
|
|
1268
1538
|
"*.tsbuildinfo",
|
|
1269
1539
|
".env",
|
|
1270
1540
|
".env.*",
|
|
1271
|
-
"!.env.example"
|
|
1541
|
+
"!.env.example",
|
|
1542
|
+
".pnpm-store"
|
|
1272
1543
|
];
|
|
1273
|
-
function
|
|
1544
|
+
function renderGitignore(variant) {
|
|
1274
1545
|
const lines = variant === "workspace-root" ? [...COMMON_GITIGNORE_LINES, ".DS_Store"] : COMMON_GITIGNORE_LINES;
|
|
1275
1546
|
return {
|
|
1276
1547
|
type: "text",
|
|
1277
1548
|
content: lines.join("\n")
|
|
1278
1549
|
};
|
|
1279
1550
|
}
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1551
|
+
|
|
1552
|
+
const defaultFormatterMetaConfig = {
|
|
1553
|
+
printWidth: 102,
|
|
1554
|
+
tabWidth: 2,
|
|
1555
|
+
useTabs: false,
|
|
1556
|
+
semi: true,
|
|
1557
|
+
singleQuote: true,
|
|
1558
|
+
trailingComma: "es5",
|
|
1559
|
+
bracketSpacing: true,
|
|
1560
|
+
arrowParens: "always",
|
|
1561
|
+
ignorePatterns: [
|
|
1562
|
+
"package-lock.json",
|
|
1563
|
+
"npm-shrinkwrap.json",
|
|
1564
|
+
"pnpm-lock.yaml",
|
|
1565
|
+
"pnpm-lock.json",
|
|
1566
|
+
"yarn.lock",
|
|
1567
|
+
"bun.lock",
|
|
1568
|
+
"bun.lockb"
|
|
1569
|
+
]
|
|
1570
|
+
};
|
|
1571
|
+
|
|
1572
|
+
function renderEditorConfig(config = defaultFormatterMetaConfig) {
|
|
1573
|
+
const indentStyle = config.useTabs ? "tab" : "space";
|
|
1574
|
+
const indentSize = config.useTabs ? "tab" : String(config.tabWidth);
|
|
1575
|
+
return {
|
|
1576
|
+
type: "text",
|
|
1577
|
+
content: [
|
|
1578
|
+
"root = true",
|
|
1579
|
+
"",
|
|
1580
|
+
"[*]",
|
|
1581
|
+
"charset = utf-8",
|
|
1582
|
+
"end_of_line = lf",
|
|
1583
|
+
"insert_final_newline = true",
|
|
1584
|
+
`indent_style = ${indentStyle}`,
|
|
1585
|
+
`indent_size = ${indentSize}`,
|
|
1586
|
+
`tab_width = ${config.tabWidth}`,
|
|
1587
|
+
`max_line_length = ${config.printWidth}`
|
|
1588
|
+
].join("\n")
|
|
1589
|
+
};
|
|
1590
|
+
}
|
|
1591
|
+
function renderVscodeEditorSettings(config = defaultFormatterMetaConfig) {
|
|
1592
|
+
return {
|
|
1593
|
+
"editor.detectIndentation": false,
|
|
1594
|
+
"editor.insertSpaces": !config.useTabs,
|
|
1595
|
+
"editor.tabSize": config.tabWidth,
|
|
1596
|
+
"files.eol": "\n",
|
|
1597
|
+
"files.insertFinalNewline": true
|
|
1598
|
+
};
|
|
1599
|
+
}
|
|
1600
|
+
|
|
1601
|
+
const DEFAULT_VSCODE_SETTINGS = {
|
|
1602
|
+
...renderVscodeEditorSettings(),
|
|
1603
|
+
"explorer.fileNesting.enabled": true,
|
|
1604
|
+
"explorer.fileNesting.expand": false,
|
|
1605
|
+
"explorer.fileNesting.patterns": {
|
|
1606
|
+
".gitignore": ".gitattributes",
|
|
1607
|
+
"AGENTS.md": "CLAUDE.md"
|
|
1608
|
+
}
|
|
1609
|
+
};
|
|
1610
|
+
const OXFMT_LANGUAGE_SETTINGS = {
|
|
1611
|
+
"[json]": {
|
|
1612
|
+
"editor.defaultFormatter": "vscode.json-language-features"
|
|
1613
|
+
},
|
|
1614
|
+
"[jsonc]": {
|
|
1615
|
+
"editor.defaultFormatter": "vscode.json-language-features"
|
|
1616
|
+
},
|
|
1617
|
+
"[markdown]": {
|
|
1618
|
+
"editor.defaultFormatter": "vscode.markdown-language-features"
|
|
1619
|
+
},
|
|
1620
|
+
"[yaml]": {
|
|
1621
|
+
"editor.defaultFormatter": "redhat.vscode-yaml"
|
|
1622
|
+
}
|
|
1623
|
+
};
|
|
1624
|
+
function resolvePackageJsonNestedFiles(packageManager) {
|
|
1625
|
+
if (packageManager === "pnpm") {
|
|
1626
|
+
return ["pnpm-lock.yaml", "pnpm-workspace.yaml"];
|
|
1627
|
+
}
|
|
1628
|
+
if (packageManager === "npm") {
|
|
1629
|
+
return ["package-lock.json", "npm-shrinkwrap.json"];
|
|
1630
|
+
}
|
|
1631
|
+
if (packageManager === "yarn") {
|
|
1632
|
+
return ["yarn.lock"];
|
|
1633
|
+
}
|
|
1634
|
+
return [];
|
|
1635
|
+
}
|
|
1636
|
+
function resolveVscodeRecommendations(linter, formatter) {
|
|
1637
|
+
const recommendations = [];
|
|
1638
|
+
if (linter === "oxlint" || formatter === "oxfmt") {
|
|
1639
|
+
recommendations.push("oxc.oxc-vscode");
|
|
1640
|
+
}
|
|
1641
|
+
if (linter === "eslint") {
|
|
1642
|
+
recommendations.push("dbaeumer.vscode-eslint");
|
|
1643
|
+
}
|
|
1644
|
+
if (linter === "biome" || formatter === "biome") {
|
|
1645
|
+
recommendations.push("biomejs.biome");
|
|
1646
|
+
}
|
|
1647
|
+
if (formatter === "prettier") {
|
|
1648
|
+
recommendations.push("esbenp.prettier-vscode");
|
|
1649
|
+
}
|
|
1650
|
+
return recommendations;
|
|
1651
|
+
}
|
|
1652
|
+
function resolveVscodeSettings(params) {
|
|
1653
|
+
const { linter, formatter, configStrategy, isMonorepo, packageManager } = params;
|
|
1654
|
+
const settings = { ...DEFAULT_VSCODE_SETTINGS };
|
|
1655
|
+
const isStealth = !isMonorepo && (configStrategy ?? "stealth") === "stealth";
|
|
1656
|
+
const packageJsonNestedFiles = resolvePackageJsonNestedFiles(packageManager);
|
|
1657
|
+
if (packageJsonNestedFiles.length > 0) {
|
|
1658
|
+
settings["explorer.fileNesting.patterns"] = {
|
|
1659
|
+
...settings["explorer.fileNesting.patterns"],
|
|
1660
|
+
"package.json": packageJsonNestedFiles.join(", ")
|
|
1661
|
+
};
|
|
1662
|
+
}
|
|
1663
|
+
if (linter === "eslint") {
|
|
1664
|
+
settings["eslint.enable"] = true;
|
|
1665
|
+
settings["oxc.enable"] = false;
|
|
1666
|
+
settings["biome.enabled"] = false;
|
|
1667
|
+
if (isStealth) {
|
|
1668
|
+
settings["eslint.options"] = {
|
|
1669
|
+
overrideConfigFile: ".config/eslint.config.js"
|
|
1670
|
+
};
|
|
1671
|
+
}
|
|
1672
|
+
} else if (linter === "oxlint") {
|
|
1673
|
+
settings["oxc.enable"] = true;
|
|
1674
|
+
settings["eslint.enable"] = false;
|
|
1675
|
+
settings["biome.enabled"] = false;
|
|
1676
|
+
if (isStealth) {
|
|
1677
|
+
settings["oxc.configPath"] = ".config/oxlint.json";
|
|
1678
|
+
}
|
|
1679
|
+
} else if (linter === "biome") {
|
|
1680
|
+
settings["biome.enabled"] = true;
|
|
1681
|
+
settings["eslint.enable"] = false;
|
|
1682
|
+
settings["oxc.enable"] = false;
|
|
1683
|
+
if (isStealth) {
|
|
1684
|
+
settings["biome.linter.configPath"] = ".config/biome.json";
|
|
1685
|
+
}
|
|
1686
|
+
}
|
|
1687
|
+
if (formatter === "prettier") {
|
|
1688
|
+
settings["editor.defaultFormatter"] = "esbenp.prettier-vscode";
|
|
1689
|
+
if (isStealth) {
|
|
1690
|
+
settings["prettier.configPath"] = ".config/prettier.json";
|
|
1691
|
+
settings["prettier.ignorePath"] = ".config/prettierignore";
|
|
1692
|
+
}
|
|
1693
|
+
} else if (formatter === "oxfmt") {
|
|
1694
|
+
settings["editor.defaultFormatter"] = "oxc.oxc-vscode";
|
|
1695
|
+
Object.assign(settings, OXFMT_LANGUAGE_SETTINGS);
|
|
1696
|
+
if (isStealth) {
|
|
1697
|
+
settings["oxc.fmt.configPath"] = ".config/oxfmt.json";
|
|
1698
|
+
}
|
|
1699
|
+
} else if (formatter === "biome") {
|
|
1700
|
+
settings["biome.enabled"] = true;
|
|
1701
|
+
settings["eslint.enable"] = false;
|
|
1702
|
+
settings["oxc.enable"] = false;
|
|
1703
|
+
settings["editor.defaultFormatter"] = "biomejs.biome";
|
|
1704
|
+
if (isStealth) {
|
|
1705
|
+
settings["biome.linter.configPath"] = ".config/biome.json";
|
|
1706
|
+
}
|
|
1707
|
+
}
|
|
1708
|
+
return settings;
|
|
1709
|
+
}
|
|
1710
|
+
function renderVscodeFiles$1(params) {
|
|
1711
|
+
const { codeSnippets = {}, vscodeSettings = {} } = params;
|
|
1283
1712
|
const files = {};
|
|
1284
|
-
|
|
1285
|
-
|
|
1713
|
+
const recommendations = [
|
|
1714
|
+
...codeSnippets["vscode-extension-suggestion"] ?? [],
|
|
1715
|
+
...resolveVscodeRecommendations(params.linter, params.formatter)
|
|
1716
|
+
];
|
|
1717
|
+
if (recommendations.length > 0) {
|
|
1718
|
+
const uniqueRecommendations = [...new Set(recommendations)];
|
|
1286
1719
|
files[".vscode/extensions.json"] = {
|
|
1287
1720
|
type: "text",
|
|
1288
1721
|
content: JSON.stringify(
|
|
@@ -1294,9 +1727,13 @@ function generateVscodeFiles$1(params) {
|
|
|
1294
1727
|
)
|
|
1295
1728
|
};
|
|
1296
1729
|
}
|
|
1297
|
-
|
|
1730
|
+
const resolvedSettings = {
|
|
1731
|
+
...resolveVscodeSettings(params),
|
|
1732
|
+
...vscodeSettings
|
|
1733
|
+
};
|
|
1734
|
+
if (Object.keys(resolvedSettings).length > 0) {
|
|
1298
1735
|
const sortedSettings = Object.fromEntries(
|
|
1299
|
-
Object.entries(
|
|
1736
|
+
Object.entries(resolvedSettings).sort(([a], [b]) => a.localeCompare(b))
|
|
1300
1737
|
);
|
|
1301
1738
|
files[".vscode/settings.json"] = {
|
|
1302
1739
|
type: "text",
|
|
@@ -1340,7 +1777,7 @@ ${spaces}}`;
|
|
|
1340
1777
|
}
|
|
1341
1778
|
return String(value);
|
|
1342
1779
|
}
|
|
1343
|
-
function
|
|
1780
|
+
function renderViteConfig(params) {
|
|
1344
1781
|
const { viteConfig, codeSnippets } = params;
|
|
1345
1782
|
const configBody = formatValue(viteConfig, 0);
|
|
1346
1783
|
const viteConfigContent = [
|
|
@@ -1353,7 +1790,93 @@ function generateViteConfig(params) {
|
|
|
1353
1790
|
return { type: "text", content: viteConfigContent };
|
|
1354
1791
|
}
|
|
1355
1792
|
|
|
1356
|
-
function
|
|
1793
|
+
function toPrettierConfig(config = defaultFormatterMetaConfig) {
|
|
1794
|
+
return {
|
|
1795
|
+
$schema: "https://json.schemastore.org/prettierrc",
|
|
1796
|
+
printWidth: config.printWidth,
|
|
1797
|
+
tabWidth: config.tabWidth,
|
|
1798
|
+
useTabs: config.useTabs,
|
|
1799
|
+
semi: config.semi,
|
|
1800
|
+
singleQuote: config.singleQuote,
|
|
1801
|
+
trailingComma: config.trailingComma,
|
|
1802
|
+
bracketSpacing: config.bracketSpacing,
|
|
1803
|
+
arrowParens: config.arrowParens,
|
|
1804
|
+
overrides: [
|
|
1805
|
+
{
|
|
1806
|
+
files: ["*.md", "**/*.md"],
|
|
1807
|
+
options: { semi: false }
|
|
1808
|
+
},
|
|
1809
|
+
{
|
|
1810
|
+
files: ["*.yml", "*.yaml", "**/*.yml", "**/*.yaml"],
|
|
1811
|
+
options: { semi: false }
|
|
1812
|
+
}
|
|
1813
|
+
]
|
|
1814
|
+
};
|
|
1815
|
+
}
|
|
1816
|
+
function toPrettierIgnoreContent(config = defaultFormatterMetaConfig) {
|
|
1817
|
+
return config.ignorePatterns.join("\n");
|
|
1818
|
+
}
|
|
1819
|
+
function toOxfmtConfig(config = defaultFormatterMetaConfig) {
|
|
1820
|
+
return {
|
|
1821
|
+
printWidth: config.printWidth,
|
|
1822
|
+
tabWidth: config.tabWidth,
|
|
1823
|
+
useTabs: config.useTabs,
|
|
1824
|
+
semi: config.semi,
|
|
1825
|
+
singleQuote: config.singleQuote,
|
|
1826
|
+
trailingComma: config.trailingComma,
|
|
1827
|
+
bracketSpacing: config.bracketSpacing,
|
|
1828
|
+
arrowParens: config.arrowParens,
|
|
1829
|
+
ignorePatterns: config.ignorePatterns
|
|
1830
|
+
};
|
|
1831
|
+
}
|
|
1832
|
+
|
|
1833
|
+
const defaultLinterMetaConfig = {
|
|
1834
|
+
ignorePatterns: ["dist"],
|
|
1835
|
+
rules: {
|
|
1836
|
+
noUnusedVars: {
|
|
1837
|
+
level: "warn",
|
|
1838
|
+
argsIgnorePattern: "^_",
|
|
1839
|
+
varsIgnorePattern: "^_",
|
|
1840
|
+
caughtErrorsIgnorePattern: "^_"
|
|
1841
|
+
},
|
|
1842
|
+
noUnusedExpressions: {
|
|
1843
|
+
level: "warn",
|
|
1844
|
+
allowShortCircuit: true
|
|
1845
|
+
}
|
|
1846
|
+
}
|
|
1847
|
+
};
|
|
1848
|
+
|
|
1849
|
+
function renderOxlintConfig(params) {
|
|
1850
|
+
const config = params.config ?? defaultLinterMetaConfig;
|
|
1851
|
+
const { rules } = config;
|
|
1852
|
+
const plugins = ["unicorn", "typescript", "oxc"];
|
|
1853
|
+
if (params.react === true) {
|
|
1854
|
+
plugins.push("react");
|
|
1855
|
+
}
|
|
1856
|
+
return {
|
|
1857
|
+
$schema: params.schemaPath,
|
|
1858
|
+
plugins,
|
|
1859
|
+
...params.typescript === true ? { options: { typeAware: true } } : {},
|
|
1860
|
+
rules: {
|
|
1861
|
+
"no-unused-vars": [
|
|
1862
|
+
rules.noUnusedVars.level,
|
|
1863
|
+
{
|
|
1864
|
+
argsIgnorePattern: rules.noUnusedVars.argsIgnorePattern,
|
|
1865
|
+
varsIgnorePattern: rules.noUnusedVars.varsIgnorePattern,
|
|
1866
|
+
caughtErrorsIgnorePattern: rules.noUnusedVars.caughtErrorsIgnorePattern
|
|
1867
|
+
}
|
|
1868
|
+
],
|
|
1869
|
+
"no-useless-escape": "off",
|
|
1870
|
+
"no-unused-expressions": [
|
|
1871
|
+
rules.noUnusedExpressions.level,
|
|
1872
|
+
{ allowShortCircuit: rules.noUnusedExpressions.allowShortCircuit }
|
|
1873
|
+
]
|
|
1874
|
+
},
|
|
1875
|
+
ignorePatterns: config.ignorePatterns
|
|
1876
|
+
};
|
|
1877
|
+
}
|
|
1878
|
+
|
|
1879
|
+
function renderTypescriptConfigPackage(files) {
|
|
1357
1880
|
const basePath = ".config/typescript";
|
|
1358
1881
|
files[`${basePath}/package.json`] = {
|
|
1359
1882
|
type: "text",
|
|
@@ -1458,9 +1981,8 @@ In your package's \`tsconfig.json\`:
|
|
|
1458
1981
|
)
|
|
1459
1982
|
};
|
|
1460
1983
|
}
|
|
1461
|
-
function
|
|
1984
|
+
function renderOxlintConfigPackage(files) {
|
|
1462
1985
|
const basePath = ".config/oxlint";
|
|
1463
|
-
const { rules } = defaultLinterConfig;
|
|
1464
1986
|
files[`${basePath}/package.json`] = {
|
|
1465
1987
|
type: "text",
|
|
1466
1988
|
content: JSON.stringify(
|
|
@@ -1497,26 +2019,10 @@ oxlint -c node_modules/@config/oxlint/base.json
|
|
|
1497
2019
|
files[`${basePath}/base.json`] = {
|
|
1498
2020
|
type: "text",
|
|
1499
2021
|
content: JSON.stringify(
|
|
1500
|
-
{
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
"no-unused-vars": [
|
|
1505
|
-
rules.noUnusedVars.level,
|
|
1506
|
-
{
|
|
1507
|
-
argsIgnorePattern: rules.noUnusedVars.argsIgnorePattern,
|
|
1508
|
-
varsIgnorePattern: rules.noUnusedVars.varsIgnorePattern,
|
|
1509
|
-
caughtErrorsIgnorePattern: rules.noUnusedVars.caughtErrorsIgnorePattern
|
|
1510
|
-
}
|
|
1511
|
-
],
|
|
1512
|
-
"no-useless-escape": "off",
|
|
1513
|
-
"no-unused-expressions": [
|
|
1514
|
-
rules.noUnusedExpressions.level,
|
|
1515
|
-
{ allowShortCircuit: rules.noUnusedExpressions.allowShortCircuit }
|
|
1516
|
-
]
|
|
1517
|
-
},
|
|
1518
|
-
ignorePatterns: defaultLinterConfig.ignorePatterns
|
|
1519
|
-
},
|
|
2022
|
+
renderOxlintConfig({
|
|
2023
|
+
schemaPath: "./node_modules/oxlint/configuration_schema.json",
|
|
2024
|
+
typescript: true
|
|
2025
|
+
}),
|
|
1520
2026
|
null,
|
|
1521
2027
|
2
|
|
1522
2028
|
)
|
|
@@ -1524,32 +2030,17 @@ oxlint -c node_modules/@config/oxlint/base.json
|
|
|
1524
2030
|
files[`${basePath}/react.json`] = {
|
|
1525
2031
|
type: "text",
|
|
1526
2032
|
content: JSON.stringify(
|
|
1527
|
-
{
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
rules.noUnusedVars.level,
|
|
1533
|
-
{
|
|
1534
|
-
argsIgnorePattern: rules.noUnusedVars.argsIgnorePattern,
|
|
1535
|
-
varsIgnorePattern: rules.noUnusedVars.varsIgnorePattern,
|
|
1536
|
-
caughtErrorsIgnorePattern: rules.noUnusedVars.caughtErrorsIgnorePattern
|
|
1537
|
-
}
|
|
1538
|
-
],
|
|
1539
|
-
"no-useless-escape": "off",
|
|
1540
|
-
"no-unused-expressions": [
|
|
1541
|
-
rules.noUnusedExpressions.level,
|
|
1542
|
-
{ allowShortCircuit: rules.noUnusedExpressions.allowShortCircuit }
|
|
1543
|
-
]
|
|
1544
|
-
},
|
|
1545
|
-
ignorePatterns: defaultLinterConfig.ignorePatterns
|
|
1546
|
-
},
|
|
2033
|
+
renderOxlintConfig({
|
|
2034
|
+
schemaPath: "./node_modules/oxlint/configuration_schema.json",
|
|
2035
|
+
react: true,
|
|
2036
|
+
typescript: true
|
|
2037
|
+
}),
|
|
1547
2038
|
null,
|
|
1548
2039
|
2
|
|
1549
2040
|
)
|
|
1550
2041
|
};
|
|
1551
2042
|
}
|
|
1552
|
-
function
|
|
2043
|
+
function renderEslintConfigPackage(files) {
|
|
1553
2044
|
const basePath = ".config/eslint";
|
|
1554
2045
|
files[`${basePath}/package.json`] = {
|
|
1555
2046
|
type: "text",
|
|
@@ -1656,7 +2147,7 @@ export default tseslint.config(
|
|
|
1656
2147
|
`
|
|
1657
2148
|
};
|
|
1658
2149
|
}
|
|
1659
|
-
function
|
|
2150
|
+
function renderPrettierConfigPackage(files) {
|
|
1660
2151
|
const basePath = ".config/prettier";
|
|
1661
2152
|
files[`${basePath}/package.json`] = {
|
|
1662
2153
|
type: "text",
|
|
@@ -1669,7 +2160,7 @@ function generatePrettierConfigPackage(files) {
|
|
|
1669
2160
|
exports: {
|
|
1670
2161
|
".": "./base.json"
|
|
1671
2162
|
},
|
|
1672
|
-
files: ["base.json"]
|
|
2163
|
+
files: ["base.json", "prettierignore"]
|
|
1673
2164
|
},
|
|
1674
2165
|
null,
|
|
1675
2166
|
2
|
|
@@ -1704,10 +2195,14 @@ Or in \`.prettierrc.json\`:
|
|
|
1704
2195
|
};
|
|
1705
2196
|
files[`${basePath}/base.json`] = {
|
|
1706
2197
|
type: "text",
|
|
1707
|
-
content: JSON.stringify(
|
|
2198
|
+
content: JSON.stringify(toPrettierConfig(), null, 2)
|
|
2199
|
+
};
|
|
2200
|
+
files[`${basePath}/prettierignore`] = {
|
|
2201
|
+
type: "text",
|
|
2202
|
+
content: toPrettierIgnoreContent()
|
|
1708
2203
|
};
|
|
1709
2204
|
}
|
|
1710
|
-
function
|
|
2205
|
+
function renderOxfmtConfigPackage(files) {
|
|
1711
2206
|
const basePath = ".config/oxfmt";
|
|
1712
2207
|
files[`${basePath}/package.json`] = {
|
|
1713
2208
|
type: "text",
|
|
@@ -1743,11 +2238,11 @@ oxfmt -c node_modules/@config/oxfmt/base.json --write .
|
|
|
1743
2238
|
};
|
|
1744
2239
|
files[`${basePath}/base.json`] = {
|
|
1745
2240
|
type: "text",
|
|
1746
|
-
content: JSON.stringify(
|
|
2241
|
+
content: JSON.stringify(toOxfmtConfig(), null, 2)
|
|
1747
2242
|
};
|
|
1748
2243
|
}
|
|
1749
2244
|
|
|
1750
|
-
function
|
|
2245
|
+
function renderMonorepo(params) {
|
|
1751
2246
|
const {
|
|
1752
2247
|
name,
|
|
1753
2248
|
linter,
|
|
@@ -1756,19 +2251,20 @@ function generateMonorepo(params) {
|
|
|
1756
2251
|
pnpmManageVersions,
|
|
1757
2252
|
engine,
|
|
1758
2253
|
versions = {},
|
|
2254
|
+
ide = "vscode",
|
|
1759
2255
|
aiPlatforms
|
|
1760
2256
|
} = params;
|
|
1761
2257
|
const files = {};
|
|
1762
2258
|
const isPnpm = packageManager.name === "pnpm";
|
|
1763
2259
|
const devDependencies = {};
|
|
1764
2260
|
if (engine?.name === "node" && engine.version) {
|
|
1765
|
-
|
|
1766
|
-
devDependencies["@types/node"] = `^${majorVersion}.0.0`;
|
|
2261
|
+
devDependencies["@types/node"] = formatNodeTypesVersion(versions, engine);
|
|
1767
2262
|
} else {
|
|
1768
2263
|
devDependencies["@types/node"] = "^22.0.0";
|
|
1769
2264
|
}
|
|
1770
2265
|
if (linter === "oxlint") {
|
|
1771
2266
|
assignResolvedPackageVersion(devDependencies, versions, "oxlint");
|
|
2267
|
+
assignResolvedPackageVersion(devDependencies, versions, "oxlint-tsgolint");
|
|
1772
2268
|
} else if (linter === "eslint") {
|
|
1773
2269
|
assignResolvedPackageVersion(devDependencies, versions, "eslint");
|
|
1774
2270
|
} else if (linter === "biome") {
|
|
@@ -1784,13 +2280,7 @@ function generateMonorepo(params) {
|
|
|
1784
2280
|
version: "0.0.0",
|
|
1785
2281
|
private: true,
|
|
1786
2282
|
type: "module",
|
|
1787
|
-
scripts:
|
|
1788
|
-
dev: "pnpm --filter './apps/*' run dev",
|
|
1789
|
-
build: "pnpm --filter './packages/*' run build && pnpm --filter './apps/*' run build",
|
|
1790
|
-
test: "pnpm -r run test",
|
|
1791
|
-
lint: linter === "oxlint" ? "oxlint ." : linter === "biome" ? "biome check ." : "eslint .",
|
|
1792
|
-
format: formatter === "oxfmt" ? "oxfmt -c .config/oxfmt/base.json ." : formatter === "biome" ? "biome format . --write" : "prettier --config .config/prettier/base.json --write ."
|
|
1793
|
-
},
|
|
2283
|
+
scripts: packageJsonScripts.monorepoRoot(linter, formatter),
|
|
1794
2284
|
devDependencies
|
|
1795
2285
|
};
|
|
1796
2286
|
const engines = {};
|
|
@@ -1836,9 +2326,9 @@ function generateMonorepo(params) {
|
|
|
1836
2326
|
2
|
|
1837
2327
|
)
|
|
1838
2328
|
};
|
|
1839
|
-
|
|
2329
|
+
renderTypescriptConfigPackage(files);
|
|
1840
2330
|
if (linter === "oxlint") {
|
|
1841
|
-
|
|
2331
|
+
renderOxlintConfigPackage(files);
|
|
1842
2332
|
files["oxlint.json"] = {
|
|
1843
2333
|
type: "text",
|
|
1844
2334
|
content: JSON.stringify(
|
|
@@ -1851,7 +2341,7 @@ function generateMonorepo(params) {
|
|
|
1851
2341
|
)
|
|
1852
2342
|
};
|
|
1853
2343
|
} else if (linter === "eslint") {
|
|
1854
|
-
|
|
2344
|
+
renderEslintConfigPackage(files);
|
|
1855
2345
|
files["eslint.config.js"] = {
|
|
1856
2346
|
type: "text",
|
|
1857
2347
|
content: `import base from "@config/eslint/base";
|
|
@@ -1884,11 +2374,12 @@ export default [...base];
|
|
|
1884
2374
|
};
|
|
1885
2375
|
}
|
|
1886
2376
|
if (formatter === "oxfmt") {
|
|
1887
|
-
|
|
2377
|
+
renderOxfmtConfigPackage(files);
|
|
1888
2378
|
} else if (formatter === "prettier") {
|
|
1889
|
-
|
|
2379
|
+
renderPrettierConfigPackage(files);
|
|
1890
2380
|
}
|
|
1891
|
-
files[".
|
|
2381
|
+
files[".editorconfig"] = renderEditorConfig();
|
|
2382
|
+
files[".gitignore"] = renderGitignore("workspace-root");
|
|
1892
2383
|
files[".gitattributes"] = {
|
|
1893
2384
|
type: "text",
|
|
1894
2385
|
content: `* text=auto eol=lf
|
|
@@ -1896,7 +2387,9 @@ export default [...base];
|
|
|
1896
2387
|
*.{bat,[bB][aA][tT]} text eol=crlf
|
|
1897
2388
|
`
|
|
1898
2389
|
};
|
|
1899
|
-
|
|
2390
|
+
if (ide === "vscode") {
|
|
2391
|
+
renderVscodeFiles(files, linter, formatter, packageManager.name);
|
|
2392
|
+
}
|
|
1900
2393
|
files["README.md"] = {
|
|
1901
2394
|
type: "text",
|
|
1902
2395
|
content: `# ${name}
|
|
@@ -1924,104 +2417,50 @@ To add a new package to this workspace, run create-krispya from this directory a
|
|
|
1924
2417
|
`
|
|
1925
2418
|
};
|
|
1926
2419
|
if (aiPlatforms && aiPlatforms.length > 0) {
|
|
1927
|
-
|
|
2420
|
+
renderAiFiles(files, {
|
|
1928
2421
|
name,
|
|
1929
2422
|
packageManager: packageManager.name,
|
|
1930
2423
|
linter,
|
|
1931
2424
|
formatter,
|
|
1932
2425
|
isMonorepo: true,
|
|
2426
|
+
hasTypecheck: false,
|
|
1933
2427
|
platforms: aiPlatforms
|
|
1934
2428
|
});
|
|
1935
2429
|
}
|
|
1936
2430
|
return { files };
|
|
1937
2431
|
}
|
|
1938
|
-
function
|
|
1939
|
-
const recommendations = [];
|
|
1940
|
-
const settings = {};
|
|
1941
|
-
if (linter === "oxlint") {
|
|
1942
|
-
recommendations.push("oxc.oxc-vscode");
|
|
1943
|
-
settings["oxc.enable"] = true;
|
|
1944
|
-
settings["eslint.enable"] = false;
|
|
1945
|
-
settings["biome.enabled"] = false;
|
|
1946
|
-
} else if (linter === "eslint") {
|
|
1947
|
-
recommendations.push("dbaeumer.vscode-eslint");
|
|
1948
|
-
settings["eslint.enable"] = true;
|
|
1949
|
-
settings["oxc.enable"] = false;
|
|
1950
|
-
settings["biome.enabled"] = false;
|
|
1951
|
-
} else if (linter === "biome") {
|
|
1952
|
-
recommendations.push("biomejs.biome");
|
|
1953
|
-
settings["biome.enabled"] = true;
|
|
1954
|
-
settings["eslint.enable"] = false;
|
|
1955
|
-
settings["oxc.enable"] = false;
|
|
1956
|
-
}
|
|
1957
|
-
if (formatter === "oxfmt") {
|
|
1958
|
-
if (!recommendations.includes("oxc.oxc-vscode")) {
|
|
1959
|
-
recommendations.push("oxc.oxc-vscode");
|
|
1960
|
-
}
|
|
1961
|
-
settings["editor.defaultFormatter"] = "oxc.oxc-vscode";
|
|
1962
|
-
settings["[json]"] = {
|
|
1963
|
-
"editor.defaultFormatter": "vscode.json-language-features"
|
|
1964
|
-
};
|
|
1965
|
-
settings["[jsonc]"] = {
|
|
1966
|
-
"editor.defaultFormatter": "vscode.json-language-features"
|
|
1967
|
-
};
|
|
1968
|
-
} else if (formatter === "prettier") {
|
|
1969
|
-
recommendations.push("esbenp.prettier-vscode");
|
|
1970
|
-
settings["editor.defaultFormatter"] = "esbenp.prettier-vscode";
|
|
1971
|
-
} else if (formatter === "biome") {
|
|
1972
|
-
if (!recommendations.includes("biomejs.biome")) {
|
|
1973
|
-
recommendations.push("biomejs.biome");
|
|
1974
|
-
}
|
|
1975
|
-
settings["editor.defaultFormatter"] = "biomejs.biome";
|
|
1976
|
-
}
|
|
1977
|
-
files[".vscode/extensions.json"] = {
|
|
1978
|
-
type: "text",
|
|
1979
|
-
content: JSON.stringify({ recommendations }, null, 2)
|
|
1980
|
-
};
|
|
1981
|
-
const codeSnippets = {};
|
|
1982
|
-
if (recommendations.length > 0) {
|
|
1983
|
-
codeSnippets["vscode-extension-suggestion"] = recommendations;
|
|
1984
|
-
}
|
|
2432
|
+
function renderVscodeFiles(files, linter, formatter, packageManager = "pnpm") {
|
|
1985
2433
|
Object.assign(
|
|
1986
2434
|
files,
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
2435
|
+
renderVscodeFiles$1({
|
|
2436
|
+
linter,
|
|
2437
|
+
formatter,
|
|
2438
|
+
isMonorepo: true,
|
|
2439
|
+
packageManager
|
|
1990
2440
|
})
|
|
1991
2441
|
);
|
|
1992
2442
|
}
|
|
1993
2443
|
|
|
1994
|
-
const monorepo = {
|
|
1995
|
-
__proto__: null,
|
|
1996
|
-
generateEslintConfigPackage: generateEslintConfigPackage,
|
|
1997
|
-
generateMonorepo: generateMonorepo,
|
|
1998
|
-
generateOxfmtConfigPackage: generateOxfmtConfigPackage,
|
|
1999
|
-
generateOxlintConfigPackage: generateOxlintConfigPackage,
|
|
2000
|
-
generatePrettierConfigPackage: generatePrettierConfigPackage,
|
|
2001
|
-
generateTypescriptConfigPackage: generateTypescriptConfigPackage,
|
|
2002
|
-
generateVscodeFiles: generateVscodeFiles
|
|
2003
|
-
};
|
|
2004
|
-
|
|
2005
2444
|
function toBiomeLevel(level) {
|
|
2006
2445
|
return level;
|
|
2007
2446
|
}
|
|
2008
|
-
function
|
|
2447
|
+
function planBiome(builder, options) {
|
|
2009
2448
|
if (options == null || !options.linter && !options.formatter) {
|
|
2010
2449
|
return;
|
|
2011
2450
|
}
|
|
2012
|
-
const version =
|
|
2013
|
-
|
|
2014
|
-
const { rules } = defaultLinterConfig;
|
|
2451
|
+
const version = builder.getVersion("@biomejs/biome");
|
|
2452
|
+
builder.addDevDependency("@biomejs/biome");
|
|
2015
2453
|
const biomeConfig = {
|
|
2016
2454
|
$schema: `https://biomejs.dev/schemas/${version}/schema.json`
|
|
2017
2455
|
};
|
|
2018
2456
|
if (options.linter) {
|
|
2457
|
+
const linterConfig = options.linter.config;
|
|
2019
2458
|
biomeConfig.linter = {
|
|
2020
2459
|
enabled: true,
|
|
2021
2460
|
rules: {
|
|
2022
2461
|
recommended: true,
|
|
2023
2462
|
correctness: {
|
|
2024
|
-
noUnusedVariables: toBiomeLevel(rules.noUnusedVars.level)
|
|
2463
|
+
noUnusedVariables: toBiomeLevel(linterConfig.rules.noUnusedVars.level)
|
|
2025
2464
|
}
|
|
2026
2465
|
}
|
|
2027
2466
|
};
|
|
@@ -2031,19 +2470,20 @@ function generateBiome(generator, options) {
|
|
|
2031
2470
|
};
|
|
2032
2471
|
}
|
|
2033
2472
|
if (options.formatter) {
|
|
2473
|
+
const formatterConfig = options.formatter.config;
|
|
2034
2474
|
biomeConfig.formatter = {
|
|
2035
2475
|
enabled: true,
|
|
2036
|
-
lineWidth:
|
|
2037
|
-
indentWidth:
|
|
2038
|
-
indentStyle: "space"
|
|
2476
|
+
lineWidth: formatterConfig.printWidth,
|
|
2477
|
+
indentWidth: formatterConfig.tabWidth,
|
|
2478
|
+
indentStyle: formatterConfig.useTabs ? "tab" : "space"
|
|
2039
2479
|
};
|
|
2040
2480
|
biomeConfig.javascript = {
|
|
2041
2481
|
formatter: {
|
|
2042
|
-
semicolons: "always" ,
|
|
2043
|
-
quoteStyle: "single" ,
|
|
2044
|
-
trailingCommas:
|
|
2045
|
-
bracketSpacing:
|
|
2046
|
-
arrowParentheses: "always"
|
|
2482
|
+
semicolons: formatterConfig.semi ? "always" : "asNeeded",
|
|
2483
|
+
quoteStyle: formatterConfig.singleQuote ? "single" : "double",
|
|
2484
|
+
trailingCommas: formatterConfig.trailingComma,
|
|
2485
|
+
bracketSpacing: formatterConfig.bracketSpacing,
|
|
2486
|
+
arrowParentheses: formatterConfig.arrowParens === "always" ? "always" : "asNeeded"
|
|
2047
2487
|
}
|
|
2048
2488
|
};
|
|
2049
2489
|
biomeConfig.json = {
|
|
@@ -2056,53 +2496,48 @@ function generateBiome(generator, options) {
|
|
|
2056
2496
|
enabled: false
|
|
2057
2497
|
};
|
|
2058
2498
|
}
|
|
2059
|
-
const isStealth =
|
|
2499
|
+
const isStealth = builder.isStealthConfig();
|
|
2060
2500
|
if (isStealth) {
|
|
2061
|
-
|
|
2501
|
+
builder.addFile(".config/biome.json", {
|
|
2062
2502
|
type: "text",
|
|
2063
2503
|
content: JSON.stringify(biomeConfig, null, 2)
|
|
2064
2504
|
});
|
|
2065
2505
|
if (options.linter) {
|
|
2066
|
-
|
|
2506
|
+
builder.addScripts(packageJsonScripts.lint.biome(".config"));
|
|
2067
2507
|
}
|
|
2068
2508
|
if (options.formatter) {
|
|
2069
|
-
|
|
2509
|
+
builder.addScripts(packageJsonScripts.format.biome(".config"));
|
|
2070
2510
|
}
|
|
2071
|
-
generator.addVscodeSetting("biome.linter.configPath", ".config/biome.json");
|
|
2072
2511
|
} else {
|
|
2073
|
-
|
|
2512
|
+
builder.addFile("biome.json", {
|
|
2074
2513
|
type: "text",
|
|
2075
2514
|
content: JSON.stringify(biomeConfig, null, 2)
|
|
2076
2515
|
});
|
|
2077
2516
|
if (options.linter) {
|
|
2078
|
-
|
|
2517
|
+
builder.addScripts(packageJsonScripts.lint.biome());
|
|
2079
2518
|
}
|
|
2080
2519
|
if (options.formatter) {
|
|
2081
|
-
|
|
2520
|
+
builder.addScripts(packageJsonScripts.format.biome());
|
|
2082
2521
|
}
|
|
2083
2522
|
}
|
|
2084
2523
|
const roles = [];
|
|
2085
2524
|
if (options.linter) roles.push("linter");
|
|
2086
2525
|
if (options.formatter) roles.push("formatter");
|
|
2087
|
-
|
|
2526
|
+
builder.inject(
|
|
2088
2527
|
"readme-tools",
|
|
2089
2528
|
`[Biome](https://biomejs.dev/) - Fast ${roles.join(" and ")} for JavaScript and TypeScript`
|
|
2090
2529
|
);
|
|
2091
|
-
|
|
2092
|
-
generator.addVscodeSetting("biome.enabled", true);
|
|
2093
|
-
if (options.formatter) {
|
|
2094
|
-
generator.addVscodeSetting("editor.defaultFormatter", "biomejs.biome");
|
|
2095
|
-
}
|
|
2530
|
+
builder.inject("vscode-extension-suggestion", "biomejs.biome");
|
|
2096
2531
|
}
|
|
2097
2532
|
|
|
2098
|
-
function
|
|
2533
|
+
function planDrei(builder, options) {
|
|
2099
2534
|
if (options == null) {
|
|
2100
2535
|
return;
|
|
2101
2536
|
}
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2537
|
+
builder.addDependency("@react-three/drei");
|
|
2538
|
+
builder.inject("import", `import { Environment } from "@react-three/drei"`);
|
|
2539
|
+
builder.inject("scene", '<Environment background preset="city" />');
|
|
2540
|
+
builder.inject(
|
|
2106
2541
|
"readme-libraries",
|
|
2107
2542
|
`[@react-three/drei](https://drei.docs.pmnd.rs/) - Useful helpers for @react-three/fiber`
|
|
2108
2543
|
);
|
|
@@ -2111,25 +2546,28 @@ function generateDrei(generator, options) {
|
|
|
2111
2546
|
function toEslintLevel(level) {
|
|
2112
2547
|
return level;
|
|
2113
2548
|
}
|
|
2114
|
-
function
|
|
2115
|
-
|
|
2116
|
-
|
|
2549
|
+
function planEslint(builder, options) {
|
|
2550
|
+
if (options == null) {
|
|
2551
|
+
return;
|
|
2552
|
+
}
|
|
2553
|
+
builder.addDevDependency("eslint");
|
|
2554
|
+
const template = builder.options.template ?? "vanilla";
|
|
2117
2555
|
const baseTemplate = getBaseTemplate(template);
|
|
2118
2556
|
const isTypescript = getLanguageFromTemplate(template) === "typescript";
|
|
2119
2557
|
const isReact = baseTemplate === "react" || baseTemplate === "r3f";
|
|
2120
|
-
const { rules } =
|
|
2558
|
+
const { rules } = options.config;
|
|
2121
2559
|
const imports = ['import js from "@eslint/js"'];
|
|
2122
2560
|
const configs = ["js.configs.recommended"];
|
|
2123
2561
|
if (isTypescript) {
|
|
2124
|
-
|
|
2562
|
+
builder.addDevDependency("typescript-eslint");
|
|
2125
2563
|
imports.push('import tseslint from "typescript-eslint"');
|
|
2126
2564
|
configs.push("...tseslint.configs.recommended");
|
|
2127
2565
|
}
|
|
2128
2566
|
if (isReact) {
|
|
2129
|
-
|
|
2567
|
+
builder.addDevDependency("eslint-plugin-react-hooks");
|
|
2130
2568
|
imports.push('import reactHooks from "eslint-plugin-react-hooks"');
|
|
2131
2569
|
}
|
|
2132
|
-
const ignoresArray = JSON.stringify(
|
|
2570
|
+
const ignoresArray = JSON.stringify(options.config.ignorePatterns);
|
|
2133
2571
|
const unusedVarsRule = isTypescript ? "@typescript-eslint/no-unused-vars" : "no-unused-vars";
|
|
2134
2572
|
const rulesConfig = {
|
|
2135
2573
|
[unusedVarsRule]: [
|
|
@@ -2163,34 +2601,30 @@ function generateEslint(generator, options) {
|
|
|
2163
2601
|
},`,
|
|
2164
2602
|
"]"
|
|
2165
2603
|
].filter(Boolean).join("\n");
|
|
2166
|
-
const isStealth =
|
|
2604
|
+
const isStealth = builder.isStealthConfig();
|
|
2167
2605
|
if (isStealth) {
|
|
2168
|
-
|
|
2606
|
+
builder.addFile(".config/eslint.config.js", {
|
|
2169
2607
|
type: "text",
|
|
2170
2608
|
content: configContent
|
|
2171
2609
|
});
|
|
2172
|
-
|
|
2173
|
-
generator.addVscodeSetting("eslint.options", {
|
|
2174
|
-
overrideConfigFile: ".config/eslint.config.js"
|
|
2175
|
-
});
|
|
2610
|
+
builder.addScripts(packageJsonScripts.lint.eslint(".config/eslint.config.js"));
|
|
2176
2611
|
} else {
|
|
2177
|
-
|
|
2612
|
+
builder.addFile("eslint.config.js", {
|
|
2178
2613
|
type: "text",
|
|
2179
2614
|
content: configContent
|
|
2180
2615
|
});
|
|
2181
|
-
|
|
2616
|
+
builder.addScripts(packageJsonScripts.lint.eslint());
|
|
2182
2617
|
}
|
|
2183
|
-
|
|
2618
|
+
builder.inject(
|
|
2184
2619
|
"readme-tools",
|
|
2185
2620
|
"[ESLint](https://eslint.org/) - Linter for JavaScript and TypeScript"
|
|
2186
2621
|
);
|
|
2187
|
-
|
|
2188
|
-
generator.addVscodeSetting("eslint.enable", true);
|
|
2622
|
+
builder.inject("vscode-extension-suggestion", "dbaeumer.vscode-eslint");
|
|
2189
2623
|
}
|
|
2190
2624
|
|
|
2191
|
-
function
|
|
2192
|
-
|
|
2193
|
-
|
|
2625
|
+
function planFiber(builder, _options) {
|
|
2626
|
+
builder.inject("import", `import { Box } from "./box.js"`);
|
|
2627
|
+
builder.inject(
|
|
2194
2628
|
"scene",
|
|
2195
2629
|
[
|
|
2196
2630
|
`<ambientLight intensity={Math.PI / 2} />`,
|
|
@@ -2200,7 +2634,7 @@ function generateFiber(generator, _options) {
|
|
|
2200
2634
|
`<Box position={[1.2, 0, 0]} />`
|
|
2201
2635
|
].join("\n")
|
|
2202
2636
|
);
|
|
2203
|
-
|
|
2637
|
+
builder.addFile("src/box.tsx", {
|
|
2204
2638
|
type: "text",
|
|
2205
2639
|
content: `import type { Mesh } from 'three'
|
|
2206
2640
|
import { useRef, useState } from 'react'
|
|
@@ -2227,11 +2661,11 @@ export function Box(props: ThreeElements['mesh']) {
|
|
|
2227
2661
|
});
|
|
2228
2662
|
}
|
|
2229
2663
|
|
|
2230
|
-
function
|
|
2231
|
-
if (options === false || getPackageManagerName(
|
|
2664
|
+
function planGithubPages(builder, options) {
|
|
2665
|
+
if (options === false || getPackageManagerName(builder.options.packageManager) !== "npm") {
|
|
2232
2666
|
return;
|
|
2233
2667
|
}
|
|
2234
|
-
|
|
2668
|
+
builder.addFile(".github/workflows/gh-pages.yml", {
|
|
2235
2669
|
type: "text",
|
|
2236
2670
|
content: `name: Deploy to Github Pages
|
|
2237
2671
|
|
|
@@ -2277,10 +2711,10 @@ jobs:
|
|
|
2277
2711
|
uses: actions/deploy-pages@v4
|
|
2278
2712
|
`
|
|
2279
2713
|
});
|
|
2280
|
-
|
|
2281
|
-
if (
|
|
2282
|
-
const address = `${
|
|
2283
|
-
|
|
2714
|
+
builder.inject("readme-start", `A github pages deployment action is configurd.`);
|
|
2715
|
+
if (builder.options.githubUserName != null && builder.options.githubRepoName != null) {
|
|
2716
|
+
const address = `${builder.options.githubUserName}.github.io/${builder.options.githubRepoName}`;
|
|
2717
|
+
builder.inject(
|
|
2284
2718
|
"readme-start",
|
|
2285
2719
|
`Your app will be publish at [${address}](https://${address}) once the github action is finished.
|
|
2286
2720
|
`
|
|
@@ -2288,228 +2722,199 @@ jobs:
|
|
|
2288
2722
|
}
|
|
2289
2723
|
}
|
|
2290
2724
|
|
|
2291
|
-
function
|
|
2725
|
+
function planHandle(builder, options) {
|
|
2292
2726
|
if (options == null) {
|
|
2293
2727
|
return;
|
|
2294
2728
|
}
|
|
2295
|
-
|
|
2296
|
-
|
|
2729
|
+
builder.addDependency("@react-three/handle");
|
|
2730
|
+
builder.inject(
|
|
2297
2731
|
"readme-libraries",
|
|
2298
2732
|
`[@react-three/handle](https://pmndrs.github.io/xr/docs/handles/introduction) - interactive controls and handles for your 3D objects`
|
|
2299
2733
|
);
|
|
2300
2734
|
}
|
|
2301
2735
|
|
|
2302
|
-
function
|
|
2736
|
+
function planKoota(builder, options) {
|
|
2303
2737
|
if (options == null) {
|
|
2304
2738
|
return;
|
|
2305
2739
|
}
|
|
2306
|
-
|
|
2307
|
-
|
|
2740
|
+
builder.addDependency("koota");
|
|
2741
|
+
builder.inject(
|
|
2308
2742
|
"readme-libraries",
|
|
2309
2743
|
`[koota](https://github.com/pmndrs/koota) - ECS-based state management library optimized for real-time apps, games, and XR experiences`
|
|
2310
2744
|
);
|
|
2311
2745
|
}
|
|
2312
2746
|
|
|
2313
|
-
function
|
|
2747
|
+
function planLeva(builder, options) {
|
|
2314
2748
|
if (options == null) {
|
|
2315
2749
|
return;
|
|
2316
2750
|
}
|
|
2317
|
-
|
|
2318
|
-
|
|
2751
|
+
builder.addDependency("leva");
|
|
2752
|
+
builder.inject(
|
|
2319
2753
|
"readme-libraries",
|
|
2320
2754
|
`[leva](https://github.com/pmndrs/leva) - HTML GUI panel for React with lightweight, beautiful and extensible controls`
|
|
2321
2755
|
);
|
|
2322
2756
|
}
|
|
2323
2757
|
|
|
2324
|
-
function
|
|
2758
|
+
function planOffscreen(builder, options) {
|
|
2325
2759
|
if (options == null) {
|
|
2326
2760
|
return;
|
|
2327
2761
|
}
|
|
2328
|
-
if (
|
|
2762
|
+
if (builder.options.xr != null) {
|
|
2329
2763
|
console.info(
|
|
2330
2764
|
color.blue("Info:"),
|
|
2331
2765
|
"@react-three/offscreen is disabled because it is not supported with XR"
|
|
2332
2766
|
);
|
|
2333
2767
|
return;
|
|
2334
2768
|
}
|
|
2335
|
-
|
|
2336
|
-
|
|
2769
|
+
builder.addDependency("@react-three/offscreen");
|
|
2770
|
+
builder.inject(
|
|
2337
2771
|
"readme-libraries",
|
|
2338
2772
|
`[@react-three/offscreen](https://github.com/pmndrs/offscreen) - Offload your scene to a worker thread for better performance`
|
|
2339
2773
|
);
|
|
2340
2774
|
}
|
|
2341
2775
|
|
|
2342
|
-
function
|
|
2343
|
-
|
|
2776
|
+
function planOxfmt(builder, options) {
|
|
2777
|
+
if (options == null) {
|
|
2778
|
+
return;
|
|
2779
|
+
}
|
|
2780
|
+
const isMonorepo = builder.options.workspaceRoot != null;
|
|
2344
2781
|
if (isMonorepo) {
|
|
2345
|
-
|
|
2782
|
+
builder.addDevDependency("@config/oxfmt", { version: "workspace:*" });
|
|
2346
2783
|
const configPath = "node_modules/@config/oxfmt/base.json";
|
|
2347
|
-
|
|
2348
|
-
generator.addVscodeSetting("oxc.fmt.configPath", configPath);
|
|
2784
|
+
builder.addScripts(packageJsonScripts.format.oxfmt(configPath));
|
|
2349
2785
|
} else {
|
|
2350
|
-
|
|
2351
|
-
const isStealth =
|
|
2786
|
+
builder.addDevDependency("oxfmt");
|
|
2787
|
+
const isStealth = builder.isStealthConfig();
|
|
2352
2788
|
if (isStealth) {
|
|
2353
|
-
|
|
2789
|
+
builder.addFile(".config/oxfmt.json", {
|
|
2354
2790
|
type: "text",
|
|
2355
|
-
content: JSON.stringify(
|
|
2791
|
+
content: JSON.stringify(toOxfmtConfig(options.config), null, 2)
|
|
2356
2792
|
});
|
|
2357
|
-
|
|
2358
|
-
generator.addVscodeSetting("oxc.fmt.configPath", ".config/oxfmt.json");
|
|
2793
|
+
builder.addScripts(packageJsonScripts.format.oxfmt(".config/oxfmt.json"));
|
|
2359
2794
|
} else {
|
|
2360
|
-
|
|
2795
|
+
builder.addFile("oxfmt.json", {
|
|
2361
2796
|
type: "text",
|
|
2362
|
-
content: JSON.stringify(
|
|
2797
|
+
content: JSON.stringify(toOxfmtConfig(options.config), null, 2)
|
|
2363
2798
|
});
|
|
2364
|
-
|
|
2799
|
+
builder.addScripts(packageJsonScripts.format.oxfmt("oxfmt.json"));
|
|
2365
2800
|
}
|
|
2366
2801
|
}
|
|
2367
|
-
|
|
2802
|
+
builder.inject(
|
|
2368
2803
|
"readme-tools",
|
|
2369
2804
|
"[Oxfmt](https://oxc.rs/docs/guide/usage/formatter) - Fast Prettier-compatible code formatter"
|
|
2370
2805
|
);
|
|
2371
|
-
|
|
2372
|
-
generator.addVscodeSetting("editor.defaultFormatter", "oxc.oxc-vscode");
|
|
2373
|
-
generator.addVscodeSetting("[json]", {
|
|
2374
|
-
"editor.defaultFormatter": "vscode.json-language-features"
|
|
2375
|
-
});
|
|
2376
|
-
generator.addVscodeSetting("[jsonc]", {
|
|
2377
|
-
"editor.defaultFormatter": "vscode.json-language-features"
|
|
2378
|
-
});
|
|
2379
|
-
generator.addVscodeSetting("[markdown]", {
|
|
2380
|
-
"editor.defaultFormatter": "vscode.markdown-language-features"
|
|
2381
|
-
});
|
|
2382
|
-
generator.addVscodeSetting("[yaml]", {
|
|
2383
|
-
"editor.defaultFormatter": "redhat.vscode-yaml"
|
|
2384
|
-
});
|
|
2806
|
+
builder.inject("vscode-extension-suggestion", "oxc.oxc-vscode");
|
|
2385
2807
|
}
|
|
2386
2808
|
|
|
2387
|
-
function
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
const template =
|
|
2809
|
+
function planOxlint(builder, options) {
|
|
2810
|
+
if (options == null) {
|
|
2811
|
+
return;
|
|
2812
|
+
}
|
|
2813
|
+
const template = builder.options.template ?? "vanilla";
|
|
2392
2814
|
const baseTemplate = getBaseTemplate(template);
|
|
2815
|
+
const isTypescript = getLanguageFromTemplate(template) === "typescript";
|
|
2393
2816
|
const isReact = baseTemplate === "react" || baseTemplate === "r3f";
|
|
2394
|
-
const isMonorepo =
|
|
2817
|
+
const isMonorepo = builder.options.workspaceRoot != null;
|
|
2395
2818
|
if (isMonorepo) {
|
|
2396
|
-
|
|
2819
|
+
builder.addDevDependency("@config/oxlint", { version: "workspace:*" });
|
|
2397
2820
|
const configPath = isReact ? "node_modules/@config/oxlint/react.json" : "node_modules/@config/oxlint/base.json";
|
|
2398
|
-
|
|
2399
|
-
generator.addVscodeSetting("oxc.configPath", configPath);
|
|
2821
|
+
builder.addScripts(packageJsonScripts.lint.oxlint(configPath));
|
|
2400
2822
|
} else {
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
const plugins = ["unicorn", "typescript", "oxc"];
|
|
2405
|
-
if (isReact) {
|
|
2406
|
-
plugins.push("react");
|
|
2823
|
+
builder.addDevDependency("oxlint");
|
|
2824
|
+
if (isTypescript) {
|
|
2825
|
+
builder.addDevDependency("oxlint-tsgolint");
|
|
2407
2826
|
}
|
|
2408
|
-
const
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
argsIgnorePattern: rules.noUnusedVars.argsIgnorePattern,
|
|
2416
|
-
varsIgnorePattern: rules.noUnusedVars.varsIgnorePattern,
|
|
2417
|
-
caughtErrorsIgnorePattern: rules.noUnusedVars.caughtErrorsIgnorePattern
|
|
2418
|
-
}
|
|
2419
|
-
],
|
|
2420
|
-
"no-useless-escape": "off",
|
|
2421
|
-
"no-unused-expressions": [
|
|
2422
|
-
toOxlintLevel(rules.noUnusedExpressions.level),
|
|
2423
|
-
{ allowShortCircuit: rules.noUnusedExpressions.allowShortCircuit }
|
|
2424
|
-
]
|
|
2425
|
-
},
|
|
2426
|
-
ignorePatterns: defaultLinterConfig.ignorePatterns
|
|
2427
|
-
};
|
|
2827
|
+
const isStealth = builder.isStealthConfig();
|
|
2828
|
+
const oxlintConfig = renderOxlintConfig({
|
|
2829
|
+
schemaPath: isStealth ? "../node_modules/oxlint/configuration_schema.json" : "./node_modules/oxlint/configuration_schema.json",
|
|
2830
|
+
react: isReact,
|
|
2831
|
+
typescript: isTypescript,
|
|
2832
|
+
config: options.config
|
|
2833
|
+
});
|
|
2428
2834
|
if (isStealth) {
|
|
2429
|
-
|
|
2835
|
+
builder.addFile(".config/oxlint.json", {
|
|
2430
2836
|
type: "text",
|
|
2431
2837
|
content: JSON.stringify(oxlintConfig, null, 2)
|
|
2432
2838
|
});
|
|
2433
|
-
|
|
2434
|
-
generator.addVscodeSetting("oxc.configPath", ".config/oxlint.json");
|
|
2839
|
+
builder.addScripts(packageJsonScripts.lint.oxlint(".config/oxlint.json"));
|
|
2435
2840
|
} else {
|
|
2436
|
-
|
|
2841
|
+
builder.addFile("oxlint.json", {
|
|
2437
2842
|
type: "text",
|
|
2438
2843
|
content: JSON.stringify(oxlintConfig, null, 2)
|
|
2439
2844
|
});
|
|
2440
|
-
|
|
2845
|
+
builder.addScripts(packageJsonScripts.lint.oxlint());
|
|
2441
2846
|
}
|
|
2442
2847
|
}
|
|
2443
|
-
|
|
2848
|
+
builder.inject(
|
|
2444
2849
|
"readme-tools",
|
|
2445
2850
|
"[Oxlint](https://oxc.rs/docs/guide/usage/linter) - A fast linter for JavaScript and TypeScript"
|
|
2446
2851
|
);
|
|
2447
|
-
|
|
2448
|
-
generator.addVscodeSetting("oxc.enable", true);
|
|
2852
|
+
builder.inject("vscode-extension-suggestion", "oxc.oxc-vscode");
|
|
2449
2853
|
}
|
|
2450
2854
|
|
|
2451
|
-
function
|
|
2855
|
+
function planPostprocessing(builder, options) {
|
|
2452
2856
|
if (options == null) {
|
|
2453
2857
|
return;
|
|
2454
2858
|
}
|
|
2455
|
-
if (
|
|
2859
|
+
if (builder.options.xr != null) {
|
|
2456
2860
|
console.info(
|
|
2457
2861
|
color.blue("Info:"),
|
|
2458
2862
|
"@react-three/postprocessing is disabled because it is not supported with XR"
|
|
2459
2863
|
);
|
|
2460
2864
|
return;
|
|
2461
2865
|
}
|
|
2462
|
-
|
|
2463
|
-
|
|
2866
|
+
builder.addDependency("@react-three/postprocessing");
|
|
2867
|
+
builder.inject(
|
|
2464
2868
|
"readme-libraries",
|
|
2465
2869
|
`[@react-three/postprocessing](https://react-postprocessing.docs.pmnd.rs/) - Post-processing effects for @react-three/fiber`
|
|
2466
2870
|
);
|
|
2467
2871
|
}
|
|
2468
2872
|
|
|
2469
|
-
function
|
|
2470
|
-
|
|
2471
|
-
|
|
2873
|
+
function planPrettier(builder, options) {
|
|
2874
|
+
if (options == null) {
|
|
2875
|
+
return;
|
|
2876
|
+
}
|
|
2877
|
+
builder.addDevDependency("prettier");
|
|
2878
|
+
const isStealth = builder.isStealthConfig();
|
|
2472
2879
|
if (isStealth) {
|
|
2473
|
-
|
|
2880
|
+
builder.addFile(".config/prettier.json", {
|
|
2881
|
+
type: "text",
|
|
2882
|
+
content: JSON.stringify(toPrettierConfig(options.config), null, 2)
|
|
2883
|
+
});
|
|
2884
|
+
builder.addFile(".config/prettierignore", {
|
|
2474
2885
|
type: "text",
|
|
2475
|
-
content:
|
|
2886
|
+
content: toPrettierIgnoreContent(options.config)
|
|
2476
2887
|
});
|
|
2477
|
-
|
|
2478
|
-
|
|
2888
|
+
builder.addScripts(
|
|
2889
|
+
packageJsonScripts.format.prettier(".config/prettier.json", ".config/prettierignore")
|
|
2890
|
+
);
|
|
2479
2891
|
} else {
|
|
2480
|
-
|
|
2892
|
+
builder.addFile(".prettierrc", {
|
|
2481
2893
|
type: "text",
|
|
2482
|
-
content: JSON.stringify(
|
|
2894
|
+
content: JSON.stringify(toPrettierConfig(options.config), null, 2)
|
|
2483
2895
|
});
|
|
2484
|
-
|
|
2896
|
+
builder.addFile(".prettierignore", {
|
|
2897
|
+
type: "text",
|
|
2898
|
+
content: toPrettierIgnoreContent(options.config)
|
|
2899
|
+
});
|
|
2900
|
+
builder.addScripts(packageJsonScripts.format.prettier());
|
|
2485
2901
|
}
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
generator.addVscodeSetting("editor.defaultFormatter", "esbenp.prettier-vscode");
|
|
2902
|
+
builder.inject("readme-tools", "[Prettier](https://prettier.io/) - Opinionated code formatter");
|
|
2903
|
+
builder.inject("vscode-extension-suggestion", "esbenp.prettier-vscode");
|
|
2489
2904
|
}
|
|
2490
2905
|
|
|
2491
|
-
function
|
|
2906
|
+
function planRapier(builder, options) {
|
|
2492
2907
|
if (options == null) {
|
|
2493
2908
|
return;
|
|
2494
2909
|
}
|
|
2495
|
-
|
|
2496
|
-
|
|
2910
|
+
builder.addDependency("@react-three/rapier");
|
|
2911
|
+
builder.inject(
|
|
2497
2912
|
"readme-libraries",
|
|
2498
2913
|
`[@react-three/rapier](https://github.com/pmndrs/react-three-rapier) - Physics based on Rapier for your @react-three/fiber scene`
|
|
2499
2914
|
);
|
|
2500
2915
|
}
|
|
2501
2916
|
|
|
2502
|
-
function
|
|
2503
|
-
const set = /* @__PURE__ */ new Set();
|
|
2504
|
-
for (const arr of array) {
|
|
2505
|
-
for (const item of arr) {
|
|
2506
|
-
set.add(item);
|
|
2507
|
-
}
|
|
2508
|
-
}
|
|
2509
|
-
return Array.from(set);
|
|
2510
|
-
}
|
|
2511
|
-
|
|
2512
|
-
function generateProvidersModule(generator) {
|
|
2917
|
+
function generateProvidersModule(builder) {
|
|
2513
2918
|
const canvasProviders = [];
|
|
2514
2919
|
const globalProviders = [];
|
|
2515
2920
|
const providerDefs = {
|
|
@@ -2575,13 +2980,13 @@ function generateProvidersModule(generator) {
|
|
|
2575
2980
|
]
|
|
2576
2981
|
}
|
|
2577
2982
|
};
|
|
2578
|
-
if (
|
|
2983
|
+
if (builder.options.rapier) {
|
|
2579
2984
|
canvasProviders.push("rapier");
|
|
2580
2985
|
}
|
|
2581
|
-
if (!!
|
|
2986
|
+
if (!!builder.options.postprocessing && !builder.options.xr) {
|
|
2582
2987
|
canvasProviders.push("postprocessing");
|
|
2583
2988
|
}
|
|
2584
|
-
if (
|
|
2989
|
+
if (builder.options.uikit) {
|
|
2585
2990
|
globalProviders.push("uikit");
|
|
2586
2991
|
}
|
|
2587
2992
|
function generateProviderFunction(name, { jsdoc, providers }) {
|
|
@@ -2644,20 +3049,20 @@ ${jsdoc.split("\n").map((line) => ` * ${line}`).join("\n")}
|
|
|
2644
3049
|
${canvas.code}
|
|
2645
3050
|
`;
|
|
2646
3051
|
}
|
|
2647
|
-
function
|
|
3052
|
+
function planTriplex(builder, options) {
|
|
2648
3053
|
if (options == null) {
|
|
2649
3054
|
return;
|
|
2650
3055
|
}
|
|
2651
|
-
|
|
2652
|
-
|
|
3056
|
+
builder.inject("vscode-extension-suggestion", "trytriplex.triplex-vsce");
|
|
3057
|
+
builder.inject(
|
|
2653
3058
|
"readme-tools",
|
|
2654
3059
|
`[Triplex](https://triplex.dev) - Your visual workspace for React / Three Fiber. Get started by installing [Triplex for VS Code](https://triplex.dev/docs/get-started/vscode). Don't use Visual Studio Code? Download [Triplex Standalone](https://triplex.dev/docs/get-started/standalone).`
|
|
2655
3060
|
);
|
|
2656
|
-
|
|
2657
|
-
content: generateProvidersModule(
|
|
3061
|
+
builder.addFile(".triplex/providers.tsx", {
|
|
3062
|
+
content: generateProvidersModule(builder),
|
|
2658
3063
|
type: "text"
|
|
2659
3064
|
});
|
|
2660
|
-
|
|
3065
|
+
builder.addFile(".triplex/config.json", {
|
|
2661
3066
|
content: JSON.stringify(
|
|
2662
3067
|
{
|
|
2663
3068
|
$schema: "https://triplex.dev/config.schema.json",
|
|
@@ -2670,9 +3075,9 @@ function generateTriplex(generator, options) {
|
|
|
2670
3075
|
});
|
|
2671
3076
|
}
|
|
2672
3077
|
|
|
2673
|
-
function
|
|
2674
|
-
|
|
2675
|
-
const template =
|
|
3078
|
+
function planTsdown(builder) {
|
|
3079
|
+
builder.addDevDependency("tsdown");
|
|
3080
|
+
const template = builder.options.template ?? "vanilla";
|
|
2676
3081
|
const baseTemplate = getBaseTemplate(template);
|
|
2677
3082
|
const language = getLanguageFromTemplate(template);
|
|
2678
3083
|
const isReact = baseTemplate === "react" || baseTemplate === "r3f";
|
|
@@ -2692,36 +3097,36 @@ function generateTsdown(generator) {
|
|
|
2692
3097
|
configLines.push(` },`);
|
|
2693
3098
|
}
|
|
2694
3099
|
configLines.push(`})`);
|
|
2695
|
-
|
|
3100
|
+
builder.addFile(`tsdown.config.${ext}`, {
|
|
2696
3101
|
type: "text",
|
|
2697
3102
|
content: configLines.join("\n")
|
|
2698
3103
|
});
|
|
2699
|
-
|
|
2700
|
-
|
|
3104
|
+
builder.addScripts(packageJsonScripts.build.tsdown);
|
|
3105
|
+
builder.inject(
|
|
2701
3106
|
"readme-libraries",
|
|
2702
3107
|
"[tsdown](https://github.com/nicepkg/tsdown) - Fast TypeScript bundler powered by esbuild"
|
|
2703
3108
|
);
|
|
2704
3109
|
}
|
|
2705
3110
|
|
|
2706
|
-
function
|
|
3111
|
+
function planUikit(builder, options) {
|
|
2707
3112
|
if (options == null) {
|
|
2708
3113
|
return;
|
|
2709
3114
|
}
|
|
2710
|
-
|
|
2711
|
-
|
|
3115
|
+
builder.addDependency("@react-three/uikit");
|
|
3116
|
+
builder.inject(
|
|
2712
3117
|
"readme-libraries",
|
|
2713
3118
|
`[@react-three/uikit](https://pmndrs.github.io/uikit/docs/) - UI primitives for React Three Fiber`
|
|
2714
3119
|
);
|
|
2715
3120
|
}
|
|
2716
3121
|
|
|
2717
|
-
function
|
|
2718
|
-
|
|
2719
|
-
const template =
|
|
3122
|
+
function planUnbuild(builder) {
|
|
3123
|
+
builder.addDevDependency("unbuild");
|
|
3124
|
+
const template = builder.options.template ?? "vanilla";
|
|
2720
3125
|
const baseTemplate = getBaseTemplate(template);
|
|
2721
3126
|
const language = getLanguageFromTemplate(template);
|
|
2722
3127
|
const isReact = baseTemplate === "react" || baseTemplate === "r3f";
|
|
2723
3128
|
const ext = language === "typescript" ? "ts" : "js";
|
|
2724
|
-
const isMonorepo =
|
|
3129
|
+
const isMonorepo = builder.options.workspaceRoot != null;
|
|
2725
3130
|
const buildConfigLines = [
|
|
2726
3131
|
`import { defineBuildConfig } from "unbuild"`,
|
|
2727
3132
|
``,
|
|
@@ -2739,51 +3144,54 @@ function generateUnbuild(generator) {
|
|
|
2739
3144
|
}
|
|
2740
3145
|
buildConfigLines.push(` },`);
|
|
2741
3146
|
buildConfigLines.push(`})`);
|
|
2742
|
-
const isStealth =
|
|
3147
|
+
const isStealth = builder.isStealthConfig() && !isMonorepo;
|
|
2743
3148
|
if (isStealth) {
|
|
2744
|
-
|
|
3149
|
+
builder.addFile(`.config/build.config.${ext}`, {
|
|
2745
3150
|
type: "text",
|
|
2746
3151
|
content: buildConfigLines.join("\n")
|
|
2747
3152
|
});
|
|
2748
|
-
|
|
3153
|
+
builder.addScripts(packageJsonScripts.build.unbuild(`.config/build.config.${ext}`));
|
|
2749
3154
|
} else {
|
|
2750
|
-
|
|
3155
|
+
builder.addFile(`build.config.${ext}`, {
|
|
2751
3156
|
type: "text",
|
|
2752
3157
|
content: buildConfigLines.join("\n")
|
|
2753
3158
|
});
|
|
2754
|
-
|
|
3159
|
+
builder.addScripts(packageJsonScripts.build.unbuild());
|
|
2755
3160
|
}
|
|
2756
|
-
|
|
3161
|
+
builder.inject(
|
|
2757
3162
|
"readme-libraries",
|
|
2758
3163
|
"[unbuild](https://github.com/unjs/unbuild) - Unified JavaScript build system"
|
|
2759
3164
|
);
|
|
2760
3165
|
}
|
|
2761
3166
|
|
|
2762
|
-
function
|
|
2763
|
-
|
|
2764
|
-
|
|
3167
|
+
function planVitest(builder, options) {
|
|
3168
|
+
if (options == null) {
|
|
3169
|
+
return;
|
|
3170
|
+
}
|
|
3171
|
+
builder.addDevDependency("vitest");
|
|
3172
|
+
const template = builder.options.template ?? "vanilla";
|
|
2765
3173
|
const baseTemplate = getBaseTemplate(template);
|
|
2766
3174
|
const isReact = baseTemplate === "react" || baseTemplate === "r3f";
|
|
2767
3175
|
if (isReact) {
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
3176
|
+
builder.addDevDependency("@testing-library/react");
|
|
3177
|
+
builder.addDevDependency("@testing-library/dom");
|
|
3178
|
+
builder.addDevDependency("jsdom");
|
|
2771
3179
|
}
|
|
2772
3180
|
if (isReact) {
|
|
2773
|
-
|
|
3181
|
+
builder.configureVite({ test: { environment: "jsdom" } });
|
|
2774
3182
|
}
|
|
2775
|
-
|
|
2776
|
-
|
|
3183
|
+
builder.addScripts(packageJsonScripts.test.vitest);
|
|
3184
|
+
builder.inject(
|
|
2777
3185
|
"readme-tools",
|
|
2778
3186
|
"[Vitest](https://vitest.dev/) - Fast unit test framework powered by Vite"
|
|
2779
3187
|
);
|
|
2780
3188
|
}
|
|
2781
3189
|
|
|
2782
|
-
function
|
|
2783
|
-
if (options == null || getPackageManagerName(
|
|
3190
|
+
function planViverse(builder, options) {
|
|
3191
|
+
if (options == null || getPackageManagerName(builder.options.packageManager) !== "npm") {
|
|
2784
3192
|
return;
|
|
2785
3193
|
}
|
|
2786
|
-
|
|
3194
|
+
builder.addFile(".github/workflows/viverse.yml", {
|
|
2787
3195
|
type: "text",
|
|
2788
3196
|
content: `name: Deploy to Viverse
|
|
2789
3197
|
|
|
@@ -2834,12 +3242,12 @@ jobs:
|
|
|
2834
3242
|
run: npx viverse-cli auth login -e \${{ secrets.VIVERSE_EMAIL }} -p \${{ secrets.VIVERSE_PASSWORD }}
|
|
2835
3243
|
|
|
2836
3244
|
- name: Deploy to Viverse
|
|
2837
|
-
run: npx viverse-cli app publish ./dist --auto-create-app --name ${
|
|
3245
|
+
run: npx viverse-cli app publish ./dist --auto-create-app --name ${builder.options.name}
|
|
2838
3246
|
|
|
2839
3247
|
`
|
|
2840
3248
|
});
|
|
2841
|
-
|
|
2842
|
-
|
|
3249
|
+
builder.addDependency("@viverse/cli");
|
|
3250
|
+
builder.inject(
|
|
2843
3251
|
"readme-start",
|
|
2844
3252
|
`A GitHub CI/CD workflow for publishing to Viverse is configured.
|
|
2845
3253
|
|
|
@@ -2852,36 +3260,36 @@ You can also upload your project manually using the Viverse CLI:
|
|
|
2852
3260
|
\`\`\`bash
|
|
2853
3261
|
viverse-cli auth login -e <email> -p <password>
|
|
2854
3262
|
npm run build
|
|
2855
|
-
viverse-cli app publish ./dist --auto-create-app --name ${
|
|
3263
|
+
viverse-cli app publish ./dist --auto-create-app --name ${builder.options.name}
|
|
2856
3264
|
\`\`\`
|
|
2857
3265
|
`
|
|
2858
3266
|
);
|
|
2859
3267
|
}
|
|
2860
3268
|
|
|
2861
|
-
function
|
|
3269
|
+
function planXr(builder, options) {
|
|
2862
3270
|
if (options == null || options === false) {
|
|
2863
3271
|
return;
|
|
2864
3272
|
}
|
|
2865
3273
|
if (options === true) {
|
|
2866
3274
|
options = {};
|
|
2867
3275
|
}
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
|
|
3276
|
+
builder.addDependency("@react-three/xr");
|
|
3277
|
+
builder.addDependency("@vitejs/plugin-basic-ssl");
|
|
3278
|
+
builder.inject("import", "import { XR, createXRStore } from '@react-three/xr'");
|
|
3279
|
+
builder.inject(
|
|
2872
3280
|
`global-start`,
|
|
2873
3281
|
`const store = createXRStore(${JSON.stringify(options.storeOptions ?? {})})`
|
|
2874
3282
|
);
|
|
2875
|
-
|
|
2876
|
-
|
|
2877
|
-
|
|
2878
|
-
|
|
3283
|
+
builder.inject("scene-start", "<XR store={store}>");
|
|
3284
|
+
builder.inject("scene-end", "</XR>");
|
|
3285
|
+
builder.inject("vite-config-import", "import basicSsl from '@vitejs/plugin-basic-ssl'");
|
|
3286
|
+
builder.configureVite({
|
|
2879
3287
|
server: {
|
|
2880
3288
|
host: true
|
|
2881
3289
|
},
|
|
2882
3290
|
plugins: ["$raw:basicSsl()"]
|
|
2883
3291
|
});
|
|
2884
|
-
|
|
3292
|
+
builder.inject(
|
|
2885
3293
|
"dom-start",
|
|
2886
3294
|
`<div style={{
|
|
2887
3295
|
display: "flex",
|
|
@@ -2913,55 +3321,226 @@ function generateXr(generator, options) {
|
|
|
2913
3321
|
Enter VR
|
|
2914
3322
|
</button></div>`
|
|
2915
3323
|
);
|
|
2916
|
-
|
|
3324
|
+
builder.inject(
|
|
2917
3325
|
"readme-libraries",
|
|
2918
3326
|
`[@react-three/xr](https://pmndrs.github.io/xr/docs/) - VR/AR support for @react-three/fiber`
|
|
2919
3327
|
);
|
|
2920
3328
|
}
|
|
2921
3329
|
|
|
2922
|
-
function
|
|
3330
|
+
function planZustand(builder, options) {
|
|
2923
3331
|
if (options == null) {
|
|
2924
3332
|
return;
|
|
2925
3333
|
}
|
|
2926
|
-
|
|
2927
|
-
|
|
3334
|
+
builder.addDependency("zustand");
|
|
3335
|
+
builder.inject(
|
|
2928
3336
|
"readme-libraries",
|
|
2929
3337
|
`[zustand](https://zustand.docs.pmnd.rs/) - small, fast and scalable state-management solution`
|
|
2930
3338
|
);
|
|
2931
3339
|
}
|
|
2932
3340
|
|
|
2933
|
-
function
|
|
2934
|
-
|
|
2935
|
-
|
|
2936
|
-
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
|
|
2944
|
-
|
|
2945
|
-
|
|
2946
|
-
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
3341
|
+
function resolveProjectPlanInput(options) {
|
|
3342
|
+
const packageManager = options.packageManager ?? { name: "pnpm" };
|
|
3343
|
+
return {
|
|
3344
|
+
project: {
|
|
3345
|
+
githubUserName: options.githubUserName,
|
|
3346
|
+
githubRepoName: options.githubRepoName,
|
|
3347
|
+
name: options.name,
|
|
3348
|
+
projectType: options.projectType,
|
|
3349
|
+
template: options.template
|
|
3350
|
+
},
|
|
3351
|
+
aiAgents: {
|
|
3352
|
+
tool: "ai-agents",
|
|
3353
|
+
config: {
|
|
3354
|
+
platforms: options.aiPlatforms ?? []
|
|
3355
|
+
}
|
|
3356
|
+
},
|
|
3357
|
+
formatter: {
|
|
3358
|
+
tool: options.formatter ?? "prettier",
|
|
3359
|
+
config: structuredClone(defaultFormatterMetaConfig)
|
|
3360
|
+
},
|
|
3361
|
+
linter: {
|
|
3362
|
+
tool: options.linter ?? "oxlint",
|
|
3363
|
+
config: structuredClone(defaultLinterMetaConfig)
|
|
3364
|
+
},
|
|
3365
|
+
testing: {
|
|
3366
|
+
tool: options.testing ?? (options.projectType === "library" ? "vitest" : "none"),
|
|
3367
|
+
config: {}
|
|
3368
|
+
},
|
|
3369
|
+
typescript: {
|
|
3370
|
+
tool: "typescript",
|
|
3371
|
+
config: {
|
|
3372
|
+
configStrategy: options.configStrategy
|
|
3373
|
+
}
|
|
3374
|
+
},
|
|
3375
|
+
ide: {
|
|
3376
|
+
tool: options.ide ?? "vscode",
|
|
3377
|
+
config: {}
|
|
3378
|
+
},
|
|
3379
|
+
packageManager: {
|
|
3380
|
+
tool: packageManager.name,
|
|
3381
|
+
config: {
|
|
3382
|
+
version: packageManager.version,
|
|
3383
|
+
pnpmManageVersions: options.pnpmManageVersions
|
|
3384
|
+
}
|
|
3385
|
+
},
|
|
3386
|
+
libraryBundler: {
|
|
3387
|
+
tool: options.libraryBundler ?? "unbuild",
|
|
3388
|
+
config: {}
|
|
3389
|
+
},
|
|
3390
|
+
features: {
|
|
3391
|
+
fiber: options.fiber,
|
|
3392
|
+
handle: options.handle,
|
|
3393
|
+
drei: options.drei,
|
|
3394
|
+
koota: options.koota,
|
|
3395
|
+
leva: options.leva,
|
|
3396
|
+
offscreen: options.offscreen,
|
|
3397
|
+
postprocessing: options.postprocessing,
|
|
3398
|
+
rapier: options.rapier,
|
|
3399
|
+
triplex: options.triplex,
|
|
3400
|
+
viverse: options.viverse,
|
|
3401
|
+
uikit: options.uikit,
|
|
3402
|
+
xr: options.xr,
|
|
3403
|
+
zustand: options.zustand,
|
|
3404
|
+
githubPages: options.githubPages
|
|
3405
|
+
},
|
|
3406
|
+
context: {
|
|
3407
|
+
dependencies: options.dependencies,
|
|
3408
|
+
engine: options.engine,
|
|
3409
|
+
files: options.files,
|
|
3410
|
+
injections: options.injections,
|
|
3411
|
+
replacements: options.replacements,
|
|
3412
|
+
versions: options.versions,
|
|
3413
|
+
workspaceRoot: options.workspaceRoot,
|
|
3414
|
+
workspaceDependencies: options.workspaceDependencies
|
|
2953
3415
|
}
|
|
2954
|
-
|
|
2955
|
-
|
|
2956
|
-
|
|
3416
|
+
};
|
|
3417
|
+
}
|
|
3418
|
+
function projectPlanInputToOptions(input) {
|
|
3419
|
+
return {
|
|
3420
|
+
...input.project,
|
|
3421
|
+
aiPlatforms: input.aiAgents.config.platforms.length > 0 ? input.aiAgents.config.platforms : void 0,
|
|
3422
|
+
formatter: input.formatter.tool,
|
|
3423
|
+
linter: input.linter.tool,
|
|
3424
|
+
testing: input.testing.tool,
|
|
3425
|
+
configStrategy: input.typescript.config.configStrategy,
|
|
3426
|
+
ide: input.ide.tool,
|
|
3427
|
+
packageManager: packageManagerSpecFromInput(input.packageManager),
|
|
3428
|
+
pnpmManageVersions: input.packageManager.config.pnpmManageVersions,
|
|
3429
|
+
libraryBundler: input.libraryBundler.tool,
|
|
3430
|
+
...input.features,
|
|
3431
|
+
dependencies: input.context.dependencies,
|
|
3432
|
+
engine: input.context.engine,
|
|
3433
|
+
files: input.context.files,
|
|
3434
|
+
injections: input.context.injections,
|
|
3435
|
+
replacements: input.context.replacements,
|
|
3436
|
+
versions: input.context.versions,
|
|
3437
|
+
workspaceRoot: input.context.workspaceRoot,
|
|
3438
|
+
workspaceDependencies: input.context.workspaceDependencies
|
|
3439
|
+
};
|
|
3440
|
+
}
|
|
3441
|
+
function resolveWorkspacePlanInput(params) {
|
|
3442
|
+
return {
|
|
3443
|
+
project: {
|
|
3444
|
+
name: params.name
|
|
3445
|
+
},
|
|
3446
|
+
aiAgents: {
|
|
3447
|
+
tool: "ai-agents",
|
|
3448
|
+
config: {
|
|
3449
|
+
platforms: params.aiPlatforms ?? []
|
|
3450
|
+
}
|
|
3451
|
+
},
|
|
3452
|
+
formatter: {
|
|
3453
|
+
tool: params.formatter,
|
|
3454
|
+
config: structuredClone(defaultFormatterMetaConfig)
|
|
3455
|
+
},
|
|
3456
|
+
linter: {
|
|
3457
|
+
tool: params.linter,
|
|
3458
|
+
config: structuredClone(defaultLinterMetaConfig)
|
|
3459
|
+
},
|
|
3460
|
+
ide: {
|
|
3461
|
+
tool: params.ide ?? "vscode",
|
|
3462
|
+
config: {}
|
|
3463
|
+
},
|
|
3464
|
+
packageManager: {
|
|
3465
|
+
tool: params.packageManager.name,
|
|
3466
|
+
config: {
|
|
3467
|
+
version: params.packageManager.version,
|
|
3468
|
+
pnpmManageVersions: params.pnpmManageVersions
|
|
3469
|
+
}
|
|
3470
|
+
},
|
|
3471
|
+
context: {
|
|
3472
|
+
engine: params.engine,
|
|
3473
|
+
pnpmManageVersions: params.pnpmManageVersions,
|
|
3474
|
+
versions: params.versions
|
|
2957
3475
|
}
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
return
|
|
3476
|
+
};
|
|
3477
|
+
}
|
|
3478
|
+
function workspacePlanInputToMonorepoParams(input) {
|
|
3479
|
+
return {
|
|
3480
|
+
name: input.project.name,
|
|
3481
|
+
linter: input.linter.tool,
|
|
3482
|
+
formatter: input.formatter.tool,
|
|
3483
|
+
packageManager: packageManagerSpecFromInput(input.packageManager),
|
|
3484
|
+
pnpmManageVersions: input.context.pnpmManageVersions,
|
|
3485
|
+
engine: input.context.engine,
|
|
3486
|
+
versions: input.context.versions,
|
|
3487
|
+
aiPlatforms: input.aiAgents.config.platforms.length > 0 ? input.aiAgents.config.platforms : void 0,
|
|
3488
|
+
ide: input.ide.tool
|
|
3489
|
+
};
|
|
3490
|
+
}
|
|
3491
|
+
function isProjectPlanInput(input) {
|
|
3492
|
+
return "project" in input && "formatter" in input && typeof input.formatter === "object";
|
|
3493
|
+
}
|
|
3494
|
+
function isWorkspacePlanInput(input) {
|
|
3495
|
+
return "project" in input && "formatter" in input && typeof input.formatter === "object";
|
|
3496
|
+
}
|
|
3497
|
+
function packageManagerSpecFromInput(packageManager) {
|
|
3498
|
+
return {
|
|
3499
|
+
name: packageManager.tool,
|
|
3500
|
+
version: packageManager.config.version
|
|
3501
|
+
};
|
|
3502
|
+
}
|
|
3503
|
+
|
|
3504
|
+
async function resolveProjectFacts(input) {
|
|
3505
|
+
const options = projectPlanInputToOptions(input);
|
|
3506
|
+
options.packageManager = await resolvePackageManager(options);
|
|
3507
|
+
options.engine = await resolveEngine(options);
|
|
3508
|
+
options.versions = await resolveProjectPackageVersions(options);
|
|
3509
|
+
return resolveProjectPlanInput(options);
|
|
3510
|
+
}
|
|
3511
|
+
async function resolveWorkspaceFacts(input) {
|
|
3512
|
+
const params = workspacePlanInputToMonorepoParams(input);
|
|
3513
|
+
const options = {
|
|
3514
|
+
name: params.name,
|
|
3515
|
+
linter: params.linter,
|
|
3516
|
+
formatter: params.formatter,
|
|
3517
|
+
packageManager: params.packageManager,
|
|
3518
|
+
engine: params.engine,
|
|
3519
|
+
pnpmManageVersions: params.pnpmManageVersions,
|
|
3520
|
+
versions: params.versions
|
|
3521
|
+
};
|
|
3522
|
+
const packageManager = await resolvePackageManager(options);
|
|
3523
|
+
const engine = await resolveEngine(options);
|
|
3524
|
+
const versions = await resolveMonorepoRootPackageVersions({
|
|
3525
|
+
linter: params.linter,
|
|
3526
|
+
formatter: params.formatter,
|
|
3527
|
+
engine,
|
|
3528
|
+
versions: params.versions
|
|
3529
|
+
});
|
|
3530
|
+
return resolveWorkspacePlanInput({
|
|
3531
|
+
...params,
|
|
3532
|
+
packageManager,
|
|
3533
|
+
engine,
|
|
3534
|
+
versions
|
|
3535
|
+
});
|
|
2962
3536
|
}
|
|
2963
3537
|
|
|
2964
|
-
function
|
|
3538
|
+
async function planProject(input) {
|
|
3539
|
+
const planInput = isProjectPlanInput(input) ? input : resolveProjectPlanInput(input);
|
|
3540
|
+
return createProjectPlan(await resolveProjectFacts(planInput));
|
|
3541
|
+
}
|
|
3542
|
+
function createProjectPlan(planInput) {
|
|
3543
|
+
const options = projectPlanInputToOptions(planInput);
|
|
2965
3544
|
const clonedOptions = structuredClone(options);
|
|
2966
3545
|
const template = clonedOptions.template ?? "vanilla";
|
|
2967
3546
|
const baseTemplate = getBaseTemplate(template);
|
|
@@ -2970,7 +3549,8 @@ function generate(options) {
|
|
|
2970
3549
|
const isReact = baseTemplate === "react";
|
|
2971
3550
|
const isR3f = baseTemplate === "r3f";
|
|
2972
3551
|
const isLibrary = clonedOptions.projectType === "library";
|
|
2973
|
-
const libraryBundler =
|
|
3552
|
+
const libraryBundler = planInput.libraryBundler.tool;
|
|
3553
|
+
const ide = planInput.ide.tool;
|
|
2974
3554
|
const files = {
|
|
2975
3555
|
...clonedOptions.files
|
|
2976
3556
|
};
|
|
@@ -3004,7 +3584,7 @@ function generate(options) {
|
|
|
3004
3584
|
}
|
|
3005
3585
|
}
|
|
3006
3586
|
if (language === "typescript") {
|
|
3007
|
-
const tsResult =
|
|
3587
|
+
const tsResult = renderTypescriptConfig({
|
|
3008
3588
|
baseTemplate,
|
|
3009
3589
|
useConfigPackage: clonedOptions.workspaceRoot != null,
|
|
3010
3590
|
configStrategy: clonedOptions.configStrategy,
|
|
@@ -3016,10 +3596,7 @@ function generate(options) {
|
|
|
3016
3596
|
}
|
|
3017
3597
|
const codeSnippets = {};
|
|
3018
3598
|
const vscodeSettings = {};
|
|
3019
|
-
const scripts =
|
|
3020
|
-
dev: "vite",
|
|
3021
|
-
build: "vite build"
|
|
3022
|
-
};
|
|
3599
|
+
const scripts = {};
|
|
3023
3600
|
if (!isLibrary && (isReact || isR3f)) {
|
|
3024
3601
|
codeSnippets["vite-config-import"] = ["import react from '@vitejs/plugin-react'"];
|
|
3025
3602
|
}
|
|
@@ -3038,7 +3615,7 @@ function generate(options) {
|
|
|
3038
3615
|
viteConfig.resolve = { dedupe: ["three"] };
|
|
3039
3616
|
}
|
|
3040
3617
|
const isMonorepoPackage = clonedOptions.workspaceRoot != null;
|
|
3041
|
-
const
|
|
3618
|
+
const builder = {
|
|
3042
3619
|
options: clonedOptions,
|
|
3043
3620
|
versions,
|
|
3044
3621
|
getVersion(name2) {
|
|
@@ -3068,8 +3645,11 @@ function generate(options) {
|
|
|
3068
3645
|
addFile(path, content) {
|
|
3069
3646
|
files[path] = content;
|
|
3070
3647
|
},
|
|
3648
|
+
addScripts(nextScripts) {
|
|
3649
|
+
Object.assign(scripts, nextScripts);
|
|
3650
|
+
},
|
|
3071
3651
|
addScript(name2, command) {
|
|
3072
|
-
|
|
3652
|
+
this.addScripts({ [name2]: command });
|
|
3073
3653
|
},
|
|
3074
3654
|
inject(location, code) {
|
|
3075
3655
|
let entries = codeSnippets[location];
|
|
@@ -3089,71 +3669,61 @@ function generate(options) {
|
|
|
3089
3669
|
}
|
|
3090
3670
|
};
|
|
3091
3671
|
if (isR3f) {
|
|
3092
|
-
|
|
3093
|
-
|
|
3094
|
-
|
|
3095
|
-
|
|
3096
|
-
|
|
3097
|
-
|
|
3098
|
-
|
|
3099
|
-
|
|
3100
|
-
|
|
3101
|
-
|
|
3102
|
-
|
|
3103
|
-
|
|
3104
|
-
|
|
3672
|
+
planDrei(builder, planInput.features.drei);
|
|
3673
|
+
planHandle(builder, planInput.features.handle);
|
|
3674
|
+
planKoota(builder, planInput.features.koota);
|
|
3675
|
+
planLeva(builder, planInput.features.leva);
|
|
3676
|
+
planOffscreen(builder, planInput.features.offscreen);
|
|
3677
|
+
planPostprocessing(builder, planInput.features.postprocessing);
|
|
3678
|
+
planRapier(builder, planInput.features.rapier);
|
|
3679
|
+
planUikit(builder, planInput.features.uikit);
|
|
3680
|
+
planXr(builder, planInput.features.xr);
|
|
3681
|
+
planZustand(builder, planInput.features.zustand);
|
|
3682
|
+
planFiber(builder, planInput.features.fiber);
|
|
3683
|
+
planTriplex(builder, planInput.features.triplex);
|
|
3684
|
+
planViverse(builder, planInput.features.viverse);
|
|
3105
3685
|
}
|
|
3106
3686
|
if (!isLibrary) {
|
|
3107
|
-
|
|
3687
|
+
planGithubPages(builder, planInput.features.githubPages);
|
|
3108
3688
|
}
|
|
3109
3689
|
if (isLibrary) {
|
|
3110
3690
|
if (libraryBundler === "unbuild") {
|
|
3111
|
-
|
|
3691
|
+
planUnbuild(builder);
|
|
3112
3692
|
} else if (libraryBundler === "tsdown") {
|
|
3113
|
-
|
|
3693
|
+
planTsdown(builder);
|
|
3114
3694
|
}
|
|
3115
|
-
const packageManager2 = getPackageManagerName(clonedOptions.packageManager);
|
|
3116
|
-
generator.addScript("release", `${packageManager2} run build && ${packageManager2} publish`);
|
|
3117
3695
|
}
|
|
3118
|
-
const testing =
|
|
3696
|
+
const testing = planInput.testing.tool;
|
|
3119
3697
|
if (testing === "vitest") {
|
|
3120
|
-
|
|
3121
|
-
}
|
|
3122
|
-
const linter =
|
|
3123
|
-
const formatter =
|
|
3124
|
-
if (linter === "eslint") {
|
|
3125
|
-
|
|
3126
|
-
|
|
3127
|
-
|
|
3128
|
-
} else if (linter === "
|
|
3129
|
-
|
|
3130
|
-
|
|
3131
|
-
|
|
3132
|
-
} else if (linter === "biome") {
|
|
3133
|
-
generateBiome(generator, {
|
|
3134
|
-
linter: true,
|
|
3135
|
-
formatter: formatter === "biome"
|
|
3698
|
+
planVitest(builder, planInput.testing);
|
|
3699
|
+
}
|
|
3700
|
+
const linter = planInput.linter.tool;
|
|
3701
|
+
const formatter = planInput.formatter.tool;
|
|
3702
|
+
if (planInput.linter.tool === "eslint") {
|
|
3703
|
+
planEslint(builder, planInput.linter);
|
|
3704
|
+
} else if (planInput.linter.tool === "oxlint") {
|
|
3705
|
+
planOxlint(builder, planInput.linter);
|
|
3706
|
+
} else if (planInput.linter.tool === "biome") {
|
|
3707
|
+
planBiome(builder, {
|
|
3708
|
+
linter: planInput.linter,
|
|
3709
|
+
formatter: planInput.formatter.tool === "biome" ? planInput.formatter : void 0
|
|
3136
3710
|
});
|
|
3137
|
-
generator.addVscodeSetting("eslint.enable", false);
|
|
3138
|
-
generator.addVscodeSetting("oxc.enable", false);
|
|
3139
3711
|
}
|
|
3140
|
-
if (formatter === "prettier") {
|
|
3141
|
-
|
|
3142
|
-
} else if (formatter === "oxfmt") {
|
|
3143
|
-
|
|
3144
|
-
} else if (formatter === "biome" && linter !== "biome") {
|
|
3145
|
-
|
|
3146
|
-
generator.addVscodeSetting("eslint.enable", false);
|
|
3147
|
-
generator.addVscodeSetting("oxc.enable", false);
|
|
3712
|
+
if (planInput.formatter.tool === "prettier") {
|
|
3713
|
+
planPrettier(builder, planInput.formatter);
|
|
3714
|
+
} else if (planInput.formatter.tool === "oxfmt") {
|
|
3715
|
+
planOxfmt(builder, planInput.formatter);
|
|
3716
|
+
} else if (planInput.formatter.tool === "biome" && planInput.linter.tool !== "biome") {
|
|
3717
|
+
planBiome(builder, { formatter: planInput.formatter });
|
|
3148
3718
|
}
|
|
3149
3719
|
for (const { code, location } of clonedOptions.injections ?? []) {
|
|
3150
|
-
|
|
3720
|
+
builder.inject(location, code);
|
|
3151
3721
|
}
|
|
3152
3722
|
if (!isLibrary) {
|
|
3153
|
-
files["vite.config.ts"] =
|
|
3723
|
+
files["vite.config.ts"] = renderViteConfig({ viteConfig, codeSnippets });
|
|
3154
3724
|
}
|
|
3155
3725
|
const packageManager = getPackageManagerName(options.packageManager);
|
|
3156
|
-
files["README.md"] =
|
|
3726
|
+
files["README.md"] = renderReadme({
|
|
3157
3727
|
name,
|
|
3158
3728
|
baseTemplate,
|
|
3159
3729
|
isLibrary,
|
|
@@ -3163,7 +3733,7 @@ function generate(options) {
|
|
|
3163
3733
|
});
|
|
3164
3734
|
Object.assign(
|
|
3165
3735
|
files,
|
|
3166
|
-
|
|
3736
|
+
renderSourceFiles({
|
|
3167
3737
|
name,
|
|
3168
3738
|
baseTemplate,
|
|
3169
3739
|
language,
|
|
@@ -3175,7 +3745,7 @@ function generate(options) {
|
|
|
3175
3745
|
if (testing === "vitest") {
|
|
3176
3746
|
Object.assign(
|
|
3177
3747
|
files,
|
|
3178
|
-
|
|
3748
|
+
renderTestFiles({
|
|
3179
3749
|
baseTemplate,
|
|
3180
3750
|
language,
|
|
3181
3751
|
isLibrary
|
|
@@ -3184,7 +3754,7 @@ function generate(options) {
|
|
|
3184
3754
|
}
|
|
3185
3755
|
Object.assign(
|
|
3186
3756
|
files,
|
|
3187
|
-
|
|
3757
|
+
renderPackageJson({
|
|
3188
3758
|
name,
|
|
3189
3759
|
language,
|
|
3190
3760
|
isLibrary,
|
|
@@ -3196,25 +3766,54 @@ function generate(options) {
|
|
|
3196
3766
|
workspaceDependencies: clonedOptions.workspaceDependencies
|
|
3197
3767
|
}).files
|
|
3198
3768
|
);
|
|
3199
|
-
if (!isMonorepoPackage) {
|
|
3200
|
-
Object.assign(
|
|
3769
|
+
if (!isMonorepoPackage && ide === "vscode") {
|
|
3770
|
+
Object.assign(
|
|
3771
|
+
files,
|
|
3772
|
+
renderVscodeFiles$1({
|
|
3773
|
+
codeSnippets,
|
|
3774
|
+
vscodeSettings,
|
|
3775
|
+
linter,
|
|
3776
|
+
formatter,
|
|
3777
|
+
configStrategy: clonedOptions.configStrategy,
|
|
3778
|
+
isMonorepo: false,
|
|
3779
|
+
packageManager
|
|
3780
|
+
})
|
|
3781
|
+
);
|
|
3201
3782
|
}
|
|
3202
3783
|
if (!isMonorepoPackage) {
|
|
3203
|
-
files[".
|
|
3204
|
-
files[".
|
|
3784
|
+
files[".editorconfig"] = renderEditorConfig();
|
|
3785
|
+
files[".gitignore"] = renderGitignore("standalone");
|
|
3786
|
+
files[".gitattributes"] = { type: "text", content: gitAttributesContent };
|
|
3205
3787
|
}
|
|
3206
|
-
if (!isMonorepoPackage &&
|
|
3207
|
-
|
|
3788
|
+
if (!isMonorepoPackage && planInput.aiAgents.config.platforms.length > 0) {
|
|
3789
|
+
renderAiFiles(files, {
|
|
3208
3790
|
name,
|
|
3209
3791
|
packageManager: getPackageManagerName(clonedOptions.packageManager),
|
|
3210
3792
|
linter: clonedOptions.linter ?? "oxlint",
|
|
3211
3793
|
formatter: clonedOptions.formatter ?? "prettier",
|
|
3212
3794
|
isMonorepo: false,
|
|
3213
3795
|
configStrategy: clonedOptions.configStrategy,
|
|
3214
|
-
|
|
3796
|
+
hasTypecheck: language === "typescript",
|
|
3797
|
+
platforms: planInput.aiAgents.config.platforms
|
|
3215
3798
|
});
|
|
3216
3799
|
}
|
|
3217
|
-
return
|
|
3800
|
+
return {
|
|
3801
|
+
files,
|
|
3802
|
+
dependencies,
|
|
3803
|
+
devDependencies,
|
|
3804
|
+
peerDependencies,
|
|
3805
|
+
scripts,
|
|
3806
|
+
vscodeSettings,
|
|
3807
|
+
vscodeExtensions: [...new Set(codeSnippets["vscode-extension-suggestion"] ?? [])],
|
|
3808
|
+
injections: Object.entries(codeSnippets).flatMap(
|
|
3809
|
+
([location, entries]) => (entries ?? []).map((code) => ({
|
|
3810
|
+
location,
|
|
3811
|
+
code
|
|
3812
|
+
}))
|
|
3813
|
+
),
|
|
3814
|
+
replacements,
|
|
3815
|
+
warnings: []
|
|
3816
|
+
};
|
|
3218
3817
|
}
|
|
3219
3818
|
function resolveDependencySemver(name, versions, options = {}) {
|
|
3220
3819
|
if (options.version != null) {
|
|
@@ -3223,4 +3822,22 @@ function resolveDependencySemver(name, versions, options = {}) {
|
|
|
3223
3822
|
return formatResolvedPackageVersion(versions, name, options.prefix);
|
|
3224
3823
|
}
|
|
3225
3824
|
|
|
3226
|
-
|
|
3825
|
+
async function planWorkspace(input) {
|
|
3826
|
+
const planInput = isWorkspacePlanInput(input) ? input : resolveWorkspacePlanInput(input);
|
|
3827
|
+
const resolvedInput = await resolveWorkspaceFacts(planInput);
|
|
3828
|
+
const { files } = renderMonorepo(workspacePlanInputToMonorepoParams(resolvedInput));
|
|
3829
|
+
return {
|
|
3830
|
+
files,
|
|
3831
|
+
dependencies: {},
|
|
3832
|
+
devDependencies: {},
|
|
3833
|
+
peerDependencies: {},
|
|
3834
|
+
scripts: {},
|
|
3835
|
+
vscodeSettings: {},
|
|
3836
|
+
vscodeExtensions: [],
|
|
3837
|
+
injections: [],
|
|
3838
|
+
replacements: [],
|
|
3839
|
+
warnings: []
|
|
3840
|
+
};
|
|
3841
|
+
}
|
|
3842
|
+
|
|
3843
|
+
export { ALL_AI_PLATFORMS as A, renderTypescriptConfigPackage as B, renderOxlintConfigPackage as C, renderEslintConfigPackage as D, renderOxfmtConfigPackage as E, renderPrettierConfigPackage as F, resolveMonorepoRootPackageVersions as G, getResolvedPackageVersion as H, renderVscodeFiles as I, renderAiFiles as J, renderVscodeFiles$1 as K, renderEditorConfig as L, renderGitignore as M, toPrettierIgnoreContent as N, mergePackageJsonScripts as O, packageJsonScripts as P, resolveDefaultPackageJsonScripts as Q, formatResolvedPackageVersion as R, renderOxlintConfig as S, getBaseTemplate as a, getLanguageFromTemplate as b, getLatestNodeVersion as c, detectTooling as d, getLatestNpmCliVersion as e, getLatestNpmMajorVersion as f, generateRandomName as g, getLatestNpmVersion as h, getLatestPnpmVersion as i, getLatestYarnVersion as j, planProject as k, planWorkspace as l, merge as m, projectPlanInputToOptions as n, resolveWorkspacePlanInput as o, parseWorkspaceYamlContent as p, getEngineName as q, resolveProjectPlanInput as r, getPackageManagerName as s, AI_PLATFORM_LABELS as t, unique as u, validatePackageName as v, workspacePlanInputToMonorepoParams as w, AI_PLATFORM_HINTS as x, parsePackageManager as y, parseEngine as z };
|