create-krispya 0.9.0 → 0.11.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 +1319 -1490
- 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 +1353 -1524
- package/dist/index.cjs +52 -16
- package/dist/index.d.cts +81 -180
- package/dist/index.d.mts +81 -180
- package/dist/index.d.ts +81 -180
- package/dist/index.mjs +34 -1
- package/dist/{chunks/index.cjs → shared/create-krispya.8KaGuRpu.cjs} +1361 -793
- package/dist/{chunks/index.mjs → shared/create-krispya.DblF9gKc.mjs} +1338 -780
- 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 +6 -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,59 +178,49 @@ function getBaseTemplate(template) {
|
|
|
195
178
|
return template.replace("-js", "");
|
|
196
179
|
}
|
|
197
180
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
const
|
|
202
|
-
|
|
203
|
-
} catch {
|
|
204
|
-
return fallback;
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
function compareNumericSemver(a, b) {
|
|
208
|
-
const aParts = a.split(".").map((part) => Number.parseInt(part, 10) || 0);
|
|
209
|
-
const bParts = b.split(".").map((part) => Number.parseInt(part, 10) || 0);
|
|
210
|
-
const maxLength = Math.max(aParts.length, bParts.length);
|
|
211
|
-
for (let index = 0; index < maxLength; index += 1) {
|
|
212
|
-
const difference = (aParts[index] ?? 0) - (bParts[index] ?? 0);
|
|
213
|
-
if (difference !== 0) {
|
|
214
|
-
return difference;
|
|
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);
|
|
215
186
|
}
|
|
216
187
|
}
|
|
217
|
-
return
|
|
188
|
+
return Array.from(set);
|
|
218
189
|
}
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
} catch {
|
|
226
|
-
return fallback;
|
|
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(`Cannot merge "${modificationLabel}" modification into target "${targetLabel}"`);
|
|
227
196
|
}
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
return getLatestNpmVersion("npm", "11.0.0");
|
|
237
|
-
}
|
|
238
|
-
async function getLatestNodeVersion() {
|
|
239
|
-
try {
|
|
240
|
-
const response = await fetch("https://nodejs.org/dist/index.json");
|
|
241
|
-
const data = await response.json();
|
|
242
|
-
const latestVersion = data[0];
|
|
243
|
-
if (latestVersion) {
|
|
244
|
-
return latestVersion.version.replace(/^v/, "");
|
|
197
|
+
if (target == null) {
|
|
198
|
+
return modification;
|
|
199
|
+
}
|
|
200
|
+
if (Array.isArray(target)) {
|
|
201
|
+
if (!Array.isArray(modification)) {
|
|
202
|
+
throw new Error(
|
|
203
|
+
`Cannot merge non-array modification "${modificationLabel}" into array target "${targetLabel}"`
|
|
204
|
+
);
|
|
245
205
|
}
|
|
246
|
-
return
|
|
247
|
-
}
|
|
248
|
-
|
|
206
|
+
return [...target, ...modification];
|
|
207
|
+
}
|
|
208
|
+
if (typeof target === "object") {
|
|
209
|
+
if (typeof modification !== "object") {
|
|
210
|
+
throw new Error(
|
|
211
|
+
`Cannot merge non-object modification "${modificationLabel}" into object target "${targetLabel}"`
|
|
212
|
+
);
|
|
213
|
+
}
|
|
214
|
+
const result = { ...target };
|
|
215
|
+
for (const modificationKey in modification) {
|
|
216
|
+
result[modificationKey] = merge(target[modificationKey], modification[modificationKey]);
|
|
217
|
+
}
|
|
218
|
+
return result;
|
|
249
219
|
}
|
|
220
|
+
console.warn(`target "${targetLabel}" is overwritten with modification "${modificationLabel}"`);
|
|
221
|
+
return modification;
|
|
250
222
|
}
|
|
223
|
+
|
|
251
224
|
function validateNameSegment(segment, label) {
|
|
252
225
|
if (!segment.length) {
|
|
253
226
|
return `${label} is required`;
|
|
@@ -291,27 +264,83 @@ function validatePackageName(name) {
|
|
|
291
264
|
}
|
|
292
265
|
return validateNameSegment(name, "Package name");
|
|
293
266
|
}
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
267
|
+
|
|
268
|
+
function generateRandomName() {
|
|
269
|
+
const adjectives = [
|
|
270
|
+
"red",
|
|
271
|
+
"blue",
|
|
272
|
+
"green",
|
|
273
|
+
"yellow",
|
|
274
|
+
"purple",
|
|
275
|
+
"orange",
|
|
276
|
+
"pink",
|
|
277
|
+
"black",
|
|
278
|
+
"white",
|
|
279
|
+
"tiny",
|
|
280
|
+
"big",
|
|
281
|
+
"small",
|
|
282
|
+
"large",
|
|
283
|
+
"huge",
|
|
284
|
+
"giant",
|
|
285
|
+
"mini",
|
|
286
|
+
"mega",
|
|
287
|
+
"super",
|
|
288
|
+
"happy",
|
|
289
|
+
"sad",
|
|
290
|
+
"angry",
|
|
291
|
+
"calm",
|
|
292
|
+
"quiet",
|
|
293
|
+
"loud",
|
|
294
|
+
"silent",
|
|
295
|
+
"noisy",
|
|
296
|
+
"shiny",
|
|
297
|
+
"dull",
|
|
298
|
+
"bright",
|
|
299
|
+
"dark",
|
|
300
|
+
"fuzzy",
|
|
301
|
+
"smooth",
|
|
302
|
+
"rough",
|
|
303
|
+
"soft"
|
|
304
|
+
];
|
|
305
|
+
const nouns = [
|
|
306
|
+
"apple",
|
|
307
|
+
"banana",
|
|
308
|
+
"cherry",
|
|
309
|
+
"date",
|
|
310
|
+
"elderberry",
|
|
311
|
+
"fig",
|
|
312
|
+
"grape",
|
|
313
|
+
"honeydew",
|
|
314
|
+
"cat",
|
|
315
|
+
"dog",
|
|
316
|
+
"elephant",
|
|
317
|
+
"fox",
|
|
318
|
+
"giraffe",
|
|
319
|
+
"horse",
|
|
320
|
+
"iguana",
|
|
321
|
+
"jaguar",
|
|
322
|
+
"mountain",
|
|
323
|
+
"river",
|
|
324
|
+
"ocean",
|
|
325
|
+
"desert",
|
|
326
|
+
"forest",
|
|
327
|
+
"jungle",
|
|
328
|
+
"meadow",
|
|
329
|
+
"valley",
|
|
330
|
+
"star",
|
|
331
|
+
"moon",
|
|
332
|
+
"sun",
|
|
333
|
+
"planet",
|
|
334
|
+
"comet",
|
|
335
|
+
"asteroid",
|
|
336
|
+
"galaxy",
|
|
337
|
+
"universe"
|
|
338
|
+
];
|
|
339
|
+
const randomAdjective = adjectives[Math.floor(Math.random() * adjectives.length)];
|
|
340
|
+
const randomNoun = nouns[Math.floor(Math.random() * nouns.length)];
|
|
341
|
+
return `${randomAdjective}-${randomNoun}`;
|
|
314
342
|
}
|
|
343
|
+
|
|
315
344
|
async function pathExists(path) {
|
|
316
345
|
try {
|
|
317
346
|
await access(path, constants.F_OK);
|
|
@@ -387,81 +416,82 @@ async function detectTooling(root) {
|
|
|
387
416
|
} catch {
|
|
388
417
|
return { linter: void 0, formatter: void 0 };
|
|
389
418
|
}
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
"
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
"
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
"
|
|
441
|
-
|
|
442
|
-
"
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
"
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
"
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
"
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
async function getLatestNpmVersion(packageName, fallback) {
|
|
422
|
+
try {
|
|
423
|
+
const response = await fetch(`https://registry.npmjs.org/${packageName}/latest`);
|
|
424
|
+
const data = await response.json();
|
|
425
|
+
return data.version;
|
|
426
|
+
} catch {
|
|
427
|
+
return fallback;
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
function compareNumericSemver(a, b) {
|
|
431
|
+
const aParts = a.split(".").map((part) => Number.parseInt(part, 10) || 0);
|
|
432
|
+
const bParts = b.split(".").map((part) => Number.parseInt(part, 10) || 0);
|
|
433
|
+
const maxLength = Math.max(aParts.length, bParts.length);
|
|
434
|
+
for (let index = 0; index < maxLength; index += 1) {
|
|
435
|
+
const difference = (aParts[index] ?? 0) - (bParts[index] ?? 0);
|
|
436
|
+
if (difference !== 0) {
|
|
437
|
+
return difference;
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
return 0;
|
|
441
|
+
}
|
|
442
|
+
async function getLatestNpmMajorVersion(packageName, majorVersion, fallback) {
|
|
443
|
+
try {
|
|
444
|
+
const response = await fetch(`https://registry.npmjs.org/${packageName}`);
|
|
445
|
+
const data = await response.json();
|
|
446
|
+
const latestMatchingVersion = Object.keys(data.versions ?? {}).filter((version) => version.split(".")[0] === majorVersion).sort((a, b) => compareNumericSemver(b, a))[0];
|
|
447
|
+
return latestMatchingVersion ?? fallback;
|
|
448
|
+
} catch {
|
|
449
|
+
return fallback;
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
async function getLatestPnpmVersion() {
|
|
453
|
+
return getLatestNpmVersion("pnpm", "10.11.0");
|
|
454
|
+
}
|
|
455
|
+
async function getLatestYarnVersion() {
|
|
456
|
+
return getLatestNpmVersion("yarn", "4.6.0");
|
|
457
|
+
}
|
|
458
|
+
async function getLatestNpmCliVersion() {
|
|
459
|
+
return getLatestNpmVersion("npm", "11.0.0");
|
|
460
|
+
}
|
|
461
|
+
async function getLatestNodeVersion() {
|
|
462
|
+
try {
|
|
463
|
+
const response = await fetch("https://nodejs.org/dist/index.json");
|
|
464
|
+
const data = await response.json();
|
|
465
|
+
const latestVersion = data[0];
|
|
466
|
+
if (latestVersion) {
|
|
467
|
+
return latestVersion.version.replace(/^v/, "");
|
|
468
|
+
}
|
|
469
|
+
return "25.0.0";
|
|
470
|
+
} catch {
|
|
471
|
+
return "25.0.0";
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
function parseWorkspaceYamlContent(content) {
|
|
476
|
+
const directories = [];
|
|
477
|
+
let inPackagesSection = false;
|
|
478
|
+
for (const line of content.split("\n")) {
|
|
479
|
+
const trimmed = line.trim();
|
|
480
|
+
if (trimmed === "packages:") {
|
|
481
|
+
inPackagesSection = true;
|
|
482
|
+
continue;
|
|
483
|
+
}
|
|
484
|
+
if (inPackagesSection && trimmed && !line.startsWith(" ") && !line.startsWith(" ") && !trimmed.startsWith("-")) {
|
|
485
|
+
break;
|
|
486
|
+
}
|
|
487
|
+
if (inPackagesSection && trimmed.startsWith("-")) {
|
|
488
|
+
const entry = trimmed.slice(1).trim().replace(/^["']|["']$/g, "").replace(/^\.\//, "").replace(/\/\*.*$/, "");
|
|
489
|
+
if (entry && !entry.startsWith(".")) {
|
|
490
|
+
directories.push(entry);
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
return directories;
|
|
465
495
|
}
|
|
466
496
|
|
|
467
497
|
const PACKAGE_VERSION_DEFINITIONS = {
|
|
@@ -489,6 +519,7 @@ const PACKAGE_VERSION_DEFINITIONS = {
|
|
|
489
519
|
leva: { fallbackVersion: "0.10.0" },
|
|
490
520
|
oxfmt: { fallbackVersion: "0.21.0" },
|
|
491
521
|
oxlint: { fallbackVersion: "1.36.0" },
|
|
522
|
+
"oxlint-tsgolint": { fallbackVersion: "0.22.1" },
|
|
492
523
|
prettier: { fallbackVersion: "3.4.2" },
|
|
493
524
|
react: { fallbackVersion: "19.0.0" },
|
|
494
525
|
"react-dom": { fallbackVersion: "19.0.0" },
|
|
@@ -645,6 +676,9 @@ async function resolveMonorepoRootPackageVersions(params) {
|
|
|
645
676
|
const packageNames = /* @__PURE__ */ new Set();
|
|
646
677
|
const explicitVersions = new Set(Object.keys(params.versions ?? {}));
|
|
647
678
|
addPackageName(packageNames, explicitVersions, getLinterPackage(params.linter));
|
|
679
|
+
if (params.linter === "oxlint") {
|
|
680
|
+
addPackageName(packageNames, explicitVersions, "oxlint-tsgolint");
|
|
681
|
+
}
|
|
648
682
|
if (params.formatter !== "biome" || params.linter !== "biome") {
|
|
649
683
|
addPackageName(packageNames, explicitVersions, getFormatterPackage(params.formatter));
|
|
650
684
|
}
|
|
@@ -754,6 +788,9 @@ function collectProjectPackageNames(options) {
|
|
|
754
788
|
} else if (linter === "oxlint") {
|
|
755
789
|
if (!inWorkspace) {
|
|
756
790
|
addPackageName(packageNames, explicitVersions, "oxlint");
|
|
791
|
+
if (isTypescript) {
|
|
792
|
+
addPackageName(packageNames, explicitVersions, "oxlint-tsgolint");
|
|
793
|
+
}
|
|
757
794
|
}
|
|
758
795
|
} else if (linter === "biome") {
|
|
759
796
|
addPackageName(packageNames, explicitVersions, "@biomejs/biome");
|
|
@@ -788,7 +825,7 @@ function isEnabledOption(option) {
|
|
|
788
825
|
return option != null && option !== false;
|
|
789
826
|
}
|
|
790
827
|
|
|
791
|
-
function
|
|
828
|
+
function renderTypescriptConfig(baseTemplateOrParams) {
|
|
792
829
|
const params = typeof baseTemplateOrParams === "string" ? { baseTemplate: baseTemplateOrParams } : baseTemplateOrParams;
|
|
793
830
|
const {
|
|
794
831
|
baseTemplate,
|
|
@@ -835,10 +872,7 @@ function generateTypescriptConfig(baseTemplateOrParams) {
|
|
|
835
872
|
const tsConfig = {
|
|
836
873
|
$schema: "https://json.schemastore.org/tsconfig",
|
|
837
874
|
files: [],
|
|
838
|
-
references: [
|
|
839
|
-
{ path: "./.config/tsconfig.app.json" },
|
|
840
|
-
{ path: "./.config/tsconfig.node.json" }
|
|
841
|
-
]
|
|
875
|
+
references: [{ path: "./.config/tsconfig.app.json" }, { path: "./.config/tsconfig.node.json" }]
|
|
842
876
|
};
|
|
843
877
|
files["tsconfig.json"] = {
|
|
844
878
|
type: "text",
|
|
@@ -858,6 +892,7 @@ function generateTypescriptConfig(baseTemplateOrParams) {
|
|
|
858
892
|
composite: true,
|
|
859
893
|
rewriteRelativeImportExtensions: true,
|
|
860
894
|
erasableSyntaxOnly: true,
|
|
895
|
+
noEmit: true,
|
|
861
896
|
...isReact || isR3f ? { jsx: "react-jsx" } : {}
|
|
862
897
|
},
|
|
863
898
|
include: ["../src", "../tests"]
|
|
@@ -879,7 +914,8 @@ function generateTypescriptConfig(baseTemplateOrParams) {
|
|
|
879
914
|
skipLibCheck: true,
|
|
880
915
|
composite: true,
|
|
881
916
|
rewriteRelativeImportExtensions: true,
|
|
882
|
-
erasableSyntaxOnly: true
|
|
917
|
+
erasableSyntaxOnly: true,
|
|
918
|
+
noEmit: true
|
|
883
919
|
},
|
|
884
920
|
include: ["../*.config.ts", "./*.ts"]
|
|
885
921
|
};
|
|
@@ -911,6 +947,7 @@ function generateTypescriptConfig(baseTemplateOrParams) {
|
|
|
911
947
|
composite: true,
|
|
912
948
|
rewriteRelativeImportExtensions: true,
|
|
913
949
|
erasableSyntaxOnly: true,
|
|
950
|
+
noEmit: true,
|
|
914
951
|
...isReact || isR3f ? { jsx: "react-jsx" } : {}
|
|
915
952
|
},
|
|
916
953
|
include: ["src", "tests"]
|
|
@@ -932,7 +969,8 @@ function generateTypescriptConfig(baseTemplateOrParams) {
|
|
|
932
969
|
skipLibCheck: true,
|
|
933
970
|
composite: true,
|
|
934
971
|
rewriteRelativeImportExtensions: true,
|
|
935
|
-
erasableSyntaxOnly: true
|
|
972
|
+
erasableSyntaxOnly: true,
|
|
973
|
+
noEmit: true
|
|
936
974
|
},
|
|
937
975
|
include: ["*.config.ts"]
|
|
938
976
|
};
|
|
@@ -944,8 +982,108 @@ function generateTypescriptConfig(baseTemplateOrParams) {
|
|
|
944
982
|
return { files, devDependencies };
|
|
945
983
|
}
|
|
946
984
|
|
|
985
|
+
const packageJsonScripts = {
|
|
986
|
+
appBase: {
|
|
987
|
+
dev: "vite",
|
|
988
|
+
build: "vite build"
|
|
989
|
+
},
|
|
990
|
+
typescript: {
|
|
991
|
+
typecheck: "tsc --build --noEmit",
|
|
992
|
+
"typecheck:watch": "tsc --build --watch"
|
|
993
|
+
},
|
|
994
|
+
test: {
|
|
995
|
+
vitest: {
|
|
996
|
+
test: "vitest"
|
|
997
|
+
}
|
|
998
|
+
},
|
|
999
|
+
build: {
|
|
1000
|
+
unbuild(configPath) {
|
|
1001
|
+
return {
|
|
1002
|
+
build: configPath == null ? "unbuild" : `unbuild --config ${configPath}`
|
|
1003
|
+
};
|
|
1004
|
+
},
|
|
1005
|
+
tsdown: {
|
|
1006
|
+
build: "tsdown"
|
|
1007
|
+
}
|
|
1008
|
+
},
|
|
1009
|
+
lint: {
|
|
1010
|
+
oxlint(configPath) {
|
|
1011
|
+
return {
|
|
1012
|
+
lint: configPath == null ? "oxlint" : `oxlint -c ${configPath}`
|
|
1013
|
+
};
|
|
1014
|
+
},
|
|
1015
|
+
eslint(configPath) {
|
|
1016
|
+
return {
|
|
1017
|
+
lint: configPath == null ? "eslint ." : `eslint --config ${configPath} .`
|
|
1018
|
+
};
|
|
1019
|
+
},
|
|
1020
|
+
biome(configPath) {
|
|
1021
|
+
return {
|
|
1022
|
+
lint: configPath == null ? "biome lint ." : `biome lint --config-path ${configPath} .`
|
|
1023
|
+
};
|
|
1024
|
+
}
|
|
1025
|
+
},
|
|
1026
|
+
format: {
|
|
1027
|
+
prettier(configPath, ignorePath) {
|
|
1028
|
+
const configFlag = configPath == null ? "" : ` --config ${configPath}`;
|
|
1029
|
+
const ignoreFlag = ignorePath == null ? "" : ` --ignore-path ${ignorePath}`;
|
|
1030
|
+
return {
|
|
1031
|
+
format: `prettier${configFlag}${ignoreFlag} --write .`
|
|
1032
|
+
};
|
|
1033
|
+
},
|
|
1034
|
+
oxfmt(configPath) {
|
|
1035
|
+
return {
|
|
1036
|
+
format: `oxfmt -c ${configPath} --write .`
|
|
1037
|
+
};
|
|
1038
|
+
},
|
|
1039
|
+
biome(configPath) {
|
|
1040
|
+
return {
|
|
1041
|
+
format: configPath == null ? "biome format --write ." : `biome format --config-path ${configPath} --write .`
|
|
1042
|
+
};
|
|
1043
|
+
}
|
|
1044
|
+
},
|
|
1045
|
+
release(packageManagerName) {
|
|
1046
|
+
return {
|
|
1047
|
+
release: `${packageManagerName} run build && ${packageManagerName} publish`
|
|
1048
|
+
};
|
|
1049
|
+
},
|
|
1050
|
+
monorepoRoot(linter, formatter) {
|
|
1051
|
+
return mergePackageJsonScripts(
|
|
1052
|
+
{
|
|
1053
|
+
dev: "pnpm --filter './apps/*' run dev",
|
|
1054
|
+
build: "pnpm --filter './packages/*' run build && pnpm --filter './apps/*' run build",
|
|
1055
|
+
test: "pnpm -r run test"
|
|
1056
|
+
},
|
|
1057
|
+
linter === "oxlint" ? {
|
|
1058
|
+
lint: "oxlint ."
|
|
1059
|
+
} : linter === "biome" ? {
|
|
1060
|
+
lint: "biome check ."
|
|
1061
|
+
} : {
|
|
1062
|
+
lint: "eslint ."
|
|
1063
|
+
},
|
|
1064
|
+
formatter === "oxfmt" ? {
|
|
1065
|
+
format: "oxfmt -c .config/oxfmt/base.json ."
|
|
1066
|
+
} : formatter === "biome" ? {
|
|
1067
|
+
format: "biome format . --write"
|
|
1068
|
+
} : {
|
|
1069
|
+
format: "prettier --config .config/prettier/base.json --ignore-path .config/prettier/prettierignore --write ."
|
|
1070
|
+
}
|
|
1071
|
+
);
|
|
1072
|
+
}
|
|
1073
|
+
};
|
|
1074
|
+
function mergePackageJsonScripts(...scriptSets) {
|
|
1075
|
+
return Object.assign({}, ...scriptSets.filter((scriptSet) => scriptSet != null));
|
|
1076
|
+
}
|
|
1077
|
+
function resolveDefaultPackageJsonScripts(params) {
|
|
1078
|
+
return mergePackageJsonScripts(
|
|
1079
|
+
params.isLibrary ? void 0 : packageJsonScripts.appBase,
|
|
1080
|
+
params.language === "typescript" ? packageJsonScripts.typescript : void 0,
|
|
1081
|
+
params.isLibrary ? packageJsonScripts.release(params.packageManagerName) : void 0
|
|
1082
|
+
);
|
|
1083
|
+
}
|
|
1084
|
+
|
|
947
1085
|
const DEFAULT_LIBRARY_VERSION = "0.1.0";
|
|
948
|
-
function
|
|
1086
|
+
function renderPackageJson(params) {
|
|
949
1087
|
const {
|
|
950
1088
|
name,
|
|
951
1089
|
language,
|
|
@@ -953,13 +1091,20 @@ function generatePackageJson(params) {
|
|
|
953
1091
|
dependencies,
|
|
954
1092
|
devDependencies,
|
|
955
1093
|
peerDependencies,
|
|
956
|
-
scripts,
|
|
957
1094
|
options,
|
|
958
1095
|
workspaceDependencies
|
|
959
1096
|
} = params;
|
|
960
1097
|
const files = {};
|
|
961
1098
|
const packageManager = getPackageManagerSpec(options.packageManager);
|
|
962
1099
|
const isPnpm = packageManager.name === "pnpm";
|
|
1100
|
+
const resolvedScripts = mergePackageJsonScripts(
|
|
1101
|
+
resolveDefaultPackageJsonScripts({
|
|
1102
|
+
language,
|
|
1103
|
+
isLibrary,
|
|
1104
|
+
packageManagerName: packageManager.name
|
|
1105
|
+
}),
|
|
1106
|
+
params.scripts
|
|
1107
|
+
);
|
|
963
1108
|
const packageJson = {
|
|
964
1109
|
name,
|
|
965
1110
|
description: "Built with \u{1F339} create-krispya",
|
|
@@ -991,12 +1136,9 @@ function generatePackageJson(params) {
|
|
|
991
1136
|
const allDevDependencies = { ...devDependencies };
|
|
992
1137
|
const engine = getEngineSpec(options.engine);
|
|
993
1138
|
if (getEngineName(engine) === "node" && engine.version) {
|
|
994
|
-
allDevDependencies["@types/node"] ??= formatNodeTypesVersion(
|
|
995
|
-
options.versions,
|
|
996
|
-
options.engine
|
|
997
|
-
);
|
|
1139
|
+
allDevDependencies["@types/node"] ??= formatNodeTypesVersion(options.versions, options.engine);
|
|
998
1140
|
}
|
|
999
|
-
packageJson.scripts =
|
|
1141
|
+
packageJson.scripts = resolvedScripts;
|
|
1000
1142
|
packageJson.dependencies = sortKeys(allDependencies);
|
|
1001
1143
|
if (Object.keys(allDevDependencies).length > 0) {
|
|
1002
1144
|
packageJson.devDependencies = sortKeys(allDevDependencies);
|
|
@@ -1039,7 +1181,7 @@ function generatePackageJson(params) {
|
|
|
1039
1181
|
return { files };
|
|
1040
1182
|
}
|
|
1041
1183
|
|
|
1042
|
-
function
|
|
1184
|
+
function renderReadme(params) {
|
|
1043
1185
|
const { name, baseTemplate, isLibrary, libraryBundler, packageManager, codeSnippets } = params;
|
|
1044
1186
|
const isVanilla = baseTemplate === "vanilla";
|
|
1045
1187
|
const isReact = baseTemplate === "react";
|
|
@@ -1095,13 +1237,14 @@ function generateReadme(params) {
|
|
|
1095
1237
|
} else if (isReact) {
|
|
1096
1238
|
architectureDesc = [
|
|
1097
1239
|
`- \`src/app.${jsxExt}\` defines the main application component`,
|
|
1098
|
-
`- \`src/
|
|
1240
|
+
`- \`src/main.${jsxExt}\` renders the React app into the DOM`,
|
|
1099
1241
|
`- \`tests/\` contains your test files`,
|
|
1100
1242
|
`- Static assets can be placed in the \`public\` folder`
|
|
1101
1243
|
];
|
|
1102
1244
|
} else {
|
|
1103
1245
|
architectureDesc = [
|
|
1104
|
-
`- \`app.${jsxExt}\` defines the main application component containing your 3D content`,
|
|
1246
|
+
`- \`src/app.${jsxExt}\` defines the main application component containing your 3D content`,
|
|
1247
|
+
`- \`src/main.${jsxExt}\` renders the React app into the DOM`,
|
|
1105
1248
|
`- Modify the content inside the \`<Canvas>\` component to change what is visible on screen`,
|
|
1106
1249
|
`- \`tests/\` contains your test files`,
|
|
1107
1250
|
`- Static assets can be placed in the \`public\` folder`
|
|
@@ -1132,7 +1275,67 @@ function generateReadme(params) {
|
|
|
1132
1275
|
return { type: "text", content };
|
|
1133
1276
|
}
|
|
1134
1277
|
|
|
1135
|
-
|
|
1278
|
+
const htmlContent = `<!DOCTYPE html>
|
|
1279
|
+
<html lang="en">
|
|
1280
|
+
<head>
|
|
1281
|
+
<meta charset="UTF-8">
|
|
1282
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
1283
|
+
<title>$title</title>
|
|
1284
|
+
</head>
|
|
1285
|
+
<body>
|
|
1286
|
+
<div id="root"></div>
|
|
1287
|
+
<script type="module" src="$indexPath"><\/script>
|
|
1288
|
+
</body>
|
|
1289
|
+
</html>`;
|
|
1290
|
+
const viteHtmlContent = `<!DOCTYPE html>
|
|
1291
|
+
<html lang="en">
|
|
1292
|
+
<head>
|
|
1293
|
+
<meta charset="UTF-8">
|
|
1294
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
1295
|
+
<title>$title</title>
|
|
1296
|
+
</head>
|
|
1297
|
+
<body>
|
|
1298
|
+
<div id="app"></div>
|
|
1299
|
+
<script type="module" src="$indexPath"><\/script>
|
|
1300
|
+
</body>
|
|
1301
|
+
</html>`;
|
|
1302
|
+
const indexContent = `import { StrictMode } from 'react'
|
|
1303
|
+
import { createRoot } from 'react-dom/client'
|
|
1304
|
+
import './index.css'
|
|
1305
|
+
import { App } from './app.js'
|
|
1306
|
+
|
|
1307
|
+
createRoot(document.getElementById('root')!).render(
|
|
1308
|
+
<StrictMode>
|
|
1309
|
+
<App />
|
|
1310
|
+
</StrictMode>,
|
|
1311
|
+
)`;
|
|
1312
|
+
const viteIndexContent = `import './index.css'
|
|
1313
|
+
|
|
1314
|
+
document.querySelector('#app')!.innerHTML = \`
|
|
1315
|
+
<h1>Hello Vite!</h1>
|
|
1316
|
+
<p>Edit src/main.ts and save to see HMR in action.</p>
|
|
1317
|
+
\``;
|
|
1318
|
+
const viteStyleContent = `:root {
|
|
1319
|
+
font-family:
|
|
1320
|
+
system-ui,
|
|
1321
|
+
-apple-system,
|
|
1322
|
+
sans-serif;
|
|
1323
|
+
line-height: 1.5;
|
|
1324
|
+
font-weight: 400;
|
|
1325
|
+
}
|
|
1326
|
+
|
|
1327
|
+
*,
|
|
1328
|
+
*::before,
|
|
1329
|
+
*::after {
|
|
1330
|
+
box-sizing: border-box;
|
|
1331
|
+
}
|
|
1332
|
+
|
|
1333
|
+
body {
|
|
1334
|
+
margin: 0;
|
|
1335
|
+
}`;
|
|
1336
|
+
const viteEnvContent = `/// <reference types="vite/client" />`;
|
|
1337
|
+
|
|
1338
|
+
function renderSourceFiles(params) {
|
|
1136
1339
|
const { name, baseTemplate, language, isLibrary, codeSnippets, replacements } = params;
|
|
1137
1340
|
const files = {};
|
|
1138
1341
|
const ext = language === "typescript" ? "ts" : "js";
|
|
@@ -1140,6 +1343,9 @@ function generateSourceFiles(params) {
|
|
|
1140
1343
|
const isVanilla = baseTemplate === "vanilla";
|
|
1141
1344
|
const isReact = baseTemplate === "react";
|
|
1142
1345
|
const isR3f = baseTemplate === "r3f";
|
|
1346
|
+
if (!isLibrary && language === "typescript") {
|
|
1347
|
+
files["src/vite-env.d.ts"] = { type: "text", content: viteEnvContent };
|
|
1348
|
+
}
|
|
1143
1349
|
if (isLibrary) {
|
|
1144
1350
|
const libExt = isReact || isR3f ? jsxExt : ext;
|
|
1145
1351
|
let libContent;
|
|
@@ -1172,19 +1378,20 @@ function generateSourceFiles(params) {
|
|
|
1172
1378
|
}
|
|
1173
1379
|
files[`src/index.${libExt}`] = { type: "text", content: libContent };
|
|
1174
1380
|
} else if (isVanilla) {
|
|
1175
|
-
files[`src/main.${ext}`] = { type: "text", content:
|
|
1176
|
-
files["src/
|
|
1177
|
-
const indexHtml =
|
|
1178
|
-
"$title",
|
|
1179
|
-
name
|
|
1180
|
-
);
|
|
1381
|
+
files[`src/main.${ext}`] = { type: "text", content: viteIndexContent };
|
|
1382
|
+
files["src/index.css"] = { type: "text", content: viteStyleContent };
|
|
1383
|
+
const indexHtml = viteHtmlContent.replace("$indexPath", `./src/main.${ext}`).replace("$title", name);
|
|
1181
1384
|
files["index.html"] = { type: "text", content: indexHtml };
|
|
1182
1385
|
} else {
|
|
1183
|
-
files[`src/
|
|
1184
|
-
|
|
1185
|
-
"
|
|
1186
|
-
|
|
1187
|
-
|
|
1386
|
+
files[`src/main.${jsxExt}`] = {
|
|
1387
|
+
type: "text",
|
|
1388
|
+
content: language === "typescript" ? indexContent : indexContent.replace(
|
|
1389
|
+
"document.getElementById('root')!",
|
|
1390
|
+
"document.getElementById('root')"
|
|
1391
|
+
)
|
|
1392
|
+
};
|
|
1393
|
+
files["src/index.css"] = { type: "text", content: viteStyleContent };
|
|
1394
|
+
const indexHtml = htmlContent.replace("$indexPath", `./src/main.${jsxExt}`).replace("$title", name);
|
|
1188
1395
|
files["index.html"] = { type: "text", content: indexHtml };
|
|
1189
1396
|
codeSnippets["dom-end"]?.reverse();
|
|
1190
1397
|
codeSnippets["global-end"]?.reverse();
|
|
@@ -1226,12 +1433,12 @@ function generateSourceFiles(params) {
|
|
|
1226
1433
|
for (const { search, replace } of replacements) {
|
|
1227
1434
|
appCode = appCode.replace(search, replace);
|
|
1228
1435
|
}
|
|
1229
|
-
files[`src/app
|
|
1436
|
+
files[`src/app.${jsxExt}`] = { type: "text", content: appCode };
|
|
1230
1437
|
}
|
|
1231
1438
|
return files;
|
|
1232
1439
|
}
|
|
1233
1440
|
|
|
1234
|
-
function
|
|
1441
|
+
function renderTestFiles(params) {
|
|
1235
1442
|
const { baseTemplate, language, isLibrary } = params;
|
|
1236
1443
|
const files = {};
|
|
1237
1444
|
const ext = language === "typescript" ? "ts" : "js";
|
|
@@ -1338,21 +1545,184 @@ const COMMON_GITIGNORE_LINES = [
|
|
|
1338
1545
|
"*.tsbuildinfo",
|
|
1339
1546
|
".env",
|
|
1340
1547
|
".env.*",
|
|
1341
|
-
"!.env.example"
|
|
1548
|
+
"!.env.example",
|
|
1549
|
+
".pnpm-store"
|
|
1342
1550
|
];
|
|
1343
|
-
function
|
|
1551
|
+
function renderGitignore(variant) {
|
|
1344
1552
|
const lines = variant === "workspace-root" ? [...COMMON_GITIGNORE_LINES, ".DS_Store"] : COMMON_GITIGNORE_LINES;
|
|
1345
1553
|
return {
|
|
1346
1554
|
type: "text",
|
|
1347
1555
|
content: lines.join("\n")
|
|
1348
1556
|
};
|
|
1349
1557
|
}
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1558
|
+
|
|
1559
|
+
const defaultFormatterMetaConfig = {
|
|
1560
|
+
printWidth: 102,
|
|
1561
|
+
tabWidth: 2,
|
|
1562
|
+
useTabs: false,
|
|
1563
|
+
semi: true,
|
|
1564
|
+
singleQuote: true,
|
|
1565
|
+
trailingComma: "es5",
|
|
1566
|
+
bracketSpacing: true,
|
|
1567
|
+
arrowParens: "always",
|
|
1568
|
+
ignorePatterns: [
|
|
1569
|
+
"package-lock.json",
|
|
1570
|
+
"npm-shrinkwrap.json",
|
|
1571
|
+
"pnpm-lock.yaml",
|
|
1572
|
+
"pnpm-lock.json",
|
|
1573
|
+
"yarn.lock",
|
|
1574
|
+
"bun.lock",
|
|
1575
|
+
"bun.lockb"
|
|
1576
|
+
]
|
|
1577
|
+
};
|
|
1578
|
+
|
|
1579
|
+
function renderEditorConfig(config = defaultFormatterMetaConfig) {
|
|
1580
|
+
const indentStyle = config.useTabs ? "tab" : "space";
|
|
1581
|
+
const indentSize = config.useTabs ? "tab" : String(config.tabWidth);
|
|
1582
|
+
return {
|
|
1583
|
+
type: "text",
|
|
1584
|
+
content: [
|
|
1585
|
+
"root = true",
|
|
1586
|
+
"",
|
|
1587
|
+
"[*]",
|
|
1588
|
+
"charset = utf-8",
|
|
1589
|
+
"end_of_line = lf",
|
|
1590
|
+
"insert_final_newline = true",
|
|
1591
|
+
`indent_style = ${indentStyle}`,
|
|
1592
|
+
`indent_size = ${indentSize}`,
|
|
1593
|
+
`tab_width = ${config.tabWidth}`,
|
|
1594
|
+
`max_line_length = ${config.printWidth}`
|
|
1595
|
+
].join("\n")
|
|
1596
|
+
};
|
|
1597
|
+
}
|
|
1598
|
+
function renderVscodeEditorSettings(config = defaultFormatterMetaConfig) {
|
|
1599
|
+
return {
|
|
1600
|
+
"editor.detectIndentation": false,
|
|
1601
|
+
"editor.insertSpaces": !config.useTabs,
|
|
1602
|
+
"editor.tabSize": config.tabWidth,
|
|
1603
|
+
"files.eol": "\n",
|
|
1604
|
+
"files.insertFinalNewline": true
|
|
1605
|
+
};
|
|
1606
|
+
}
|
|
1607
|
+
|
|
1608
|
+
const DEFAULT_VSCODE_SETTINGS = {
|
|
1609
|
+
...renderVscodeEditorSettings(),
|
|
1610
|
+
"explorer.fileNesting.enabled": true,
|
|
1611
|
+
"explorer.fileNesting.expand": false,
|
|
1612
|
+
"explorer.fileNesting.patterns": {
|
|
1613
|
+
".gitignore": ".gitattributes",
|
|
1614
|
+
"AGENTS.md": "CLAUDE.md"
|
|
1615
|
+
}
|
|
1616
|
+
};
|
|
1617
|
+
const OXFMT_LANGUAGE_SETTINGS = {
|
|
1618
|
+
"[json]": {
|
|
1619
|
+
"editor.defaultFormatter": "vscode.json-language-features"
|
|
1620
|
+
},
|
|
1621
|
+
"[jsonc]": {
|
|
1622
|
+
"editor.defaultFormatter": "vscode.json-language-features"
|
|
1623
|
+
},
|
|
1624
|
+
"[markdown]": {
|
|
1625
|
+
"editor.defaultFormatter": "vscode.markdown-language-features"
|
|
1626
|
+
},
|
|
1627
|
+
"[yaml]": {
|
|
1628
|
+
"editor.defaultFormatter": "redhat.vscode-yaml"
|
|
1629
|
+
}
|
|
1630
|
+
};
|
|
1631
|
+
function resolvePackageJsonNestedFiles(packageManager) {
|
|
1632
|
+
if (packageManager === "pnpm") {
|
|
1633
|
+
return ["pnpm-lock.yaml", "pnpm-workspace.yaml"];
|
|
1634
|
+
}
|
|
1635
|
+
if (packageManager === "npm") {
|
|
1636
|
+
return ["package-lock.json", "npm-shrinkwrap.json"];
|
|
1637
|
+
}
|
|
1638
|
+
if (packageManager === "yarn") {
|
|
1639
|
+
return ["yarn.lock"];
|
|
1640
|
+
}
|
|
1641
|
+
return [];
|
|
1642
|
+
}
|
|
1643
|
+
function resolveVscodeRecommendations(linter, formatter) {
|
|
1644
|
+
const recommendations = [];
|
|
1645
|
+
if (linter === "oxlint" || formatter === "oxfmt") {
|
|
1646
|
+
recommendations.push("oxc.oxc-vscode");
|
|
1647
|
+
}
|
|
1648
|
+
if (linter === "eslint") {
|
|
1649
|
+
recommendations.push("dbaeumer.vscode-eslint");
|
|
1650
|
+
}
|
|
1651
|
+
if (linter === "biome" || formatter === "biome") {
|
|
1652
|
+
recommendations.push("biomejs.biome");
|
|
1653
|
+
}
|
|
1654
|
+
if (formatter === "prettier") {
|
|
1655
|
+
recommendations.push("esbenp.prettier-vscode");
|
|
1656
|
+
}
|
|
1657
|
+
return recommendations;
|
|
1658
|
+
}
|
|
1659
|
+
function resolveVscodeSettings(params) {
|
|
1660
|
+
const { linter, formatter, configStrategy, isMonorepo, packageManager } = params;
|
|
1661
|
+
const settings = { ...DEFAULT_VSCODE_SETTINGS };
|
|
1662
|
+
const isStealth = !isMonorepo && (configStrategy ?? "stealth") === "stealth";
|
|
1663
|
+
const packageJsonNestedFiles = resolvePackageJsonNestedFiles(packageManager);
|
|
1664
|
+
if (packageJsonNestedFiles.length > 0) {
|
|
1665
|
+
settings["explorer.fileNesting.patterns"] = {
|
|
1666
|
+
...settings["explorer.fileNesting.patterns"],
|
|
1667
|
+
"package.json": packageJsonNestedFiles.join(", ")
|
|
1668
|
+
};
|
|
1669
|
+
}
|
|
1670
|
+
if (linter === "eslint") {
|
|
1671
|
+
settings["eslint.enable"] = true;
|
|
1672
|
+
settings["oxc.enable"] = false;
|
|
1673
|
+
settings["biome.enabled"] = false;
|
|
1674
|
+
if (isStealth) {
|
|
1675
|
+
settings["eslint.options"] = {
|
|
1676
|
+
overrideConfigFile: ".config/eslint.config.js"
|
|
1677
|
+
};
|
|
1678
|
+
}
|
|
1679
|
+
} else if (linter === "oxlint") {
|
|
1680
|
+
settings["oxc.enable"] = true;
|
|
1681
|
+
settings["eslint.enable"] = false;
|
|
1682
|
+
settings["biome.enabled"] = false;
|
|
1683
|
+
if (isStealth) {
|
|
1684
|
+
settings["oxc.configPath"] = ".config/oxlint.json";
|
|
1685
|
+
}
|
|
1686
|
+
} else if (linter === "biome") {
|
|
1687
|
+
settings["biome.enabled"] = true;
|
|
1688
|
+
settings["eslint.enable"] = false;
|
|
1689
|
+
settings["oxc.enable"] = false;
|
|
1690
|
+
if (isStealth) {
|
|
1691
|
+
settings["biome.linter.configPath"] = ".config/biome.json";
|
|
1692
|
+
}
|
|
1693
|
+
}
|
|
1694
|
+
if (formatter === "prettier") {
|
|
1695
|
+
settings["editor.defaultFormatter"] = "esbenp.prettier-vscode";
|
|
1696
|
+
if (isStealth) {
|
|
1697
|
+
settings["prettier.configPath"] = ".config/prettier.json";
|
|
1698
|
+
settings["prettier.ignorePath"] = ".config/prettierignore";
|
|
1699
|
+
}
|
|
1700
|
+
} else if (formatter === "oxfmt") {
|
|
1701
|
+
settings["editor.defaultFormatter"] = "oxc.oxc-vscode";
|
|
1702
|
+
Object.assign(settings, OXFMT_LANGUAGE_SETTINGS);
|
|
1703
|
+
if (isStealth) {
|
|
1704
|
+
settings["oxc.fmt.configPath"] = ".config/oxfmt.json";
|
|
1705
|
+
}
|
|
1706
|
+
} else if (formatter === "biome") {
|
|
1707
|
+
settings["biome.enabled"] = true;
|
|
1708
|
+
settings["eslint.enable"] = false;
|
|
1709
|
+
settings["oxc.enable"] = false;
|
|
1710
|
+
settings["editor.defaultFormatter"] = "biomejs.biome";
|
|
1711
|
+
if (isStealth) {
|
|
1712
|
+
settings["biome.linter.configPath"] = ".config/biome.json";
|
|
1713
|
+
}
|
|
1714
|
+
}
|
|
1715
|
+
return settings;
|
|
1716
|
+
}
|
|
1717
|
+
function renderVscodeFiles$1(params) {
|
|
1718
|
+
const { codeSnippets = {}, vscodeSettings = {} } = params;
|
|
1353
1719
|
const files = {};
|
|
1354
|
-
|
|
1355
|
-
|
|
1720
|
+
const recommendations = [
|
|
1721
|
+
...codeSnippets["vscode-extension-suggestion"] ?? [],
|
|
1722
|
+
...resolveVscodeRecommendations(params.linter, params.formatter)
|
|
1723
|
+
];
|
|
1724
|
+
if (recommendations.length > 0) {
|
|
1725
|
+
const uniqueRecommendations = [...new Set(recommendations)];
|
|
1356
1726
|
files[".vscode/extensions.json"] = {
|
|
1357
1727
|
type: "text",
|
|
1358
1728
|
content: JSON.stringify(
|
|
@@ -1364,9 +1734,13 @@ function generateVscodeFiles$1(params) {
|
|
|
1364
1734
|
)
|
|
1365
1735
|
};
|
|
1366
1736
|
}
|
|
1367
|
-
|
|
1737
|
+
const resolvedSettings = {
|
|
1738
|
+
...resolveVscodeSettings(params),
|
|
1739
|
+
...vscodeSettings
|
|
1740
|
+
};
|
|
1741
|
+
if (Object.keys(resolvedSettings).length > 0) {
|
|
1368
1742
|
const sortedSettings = Object.fromEntries(
|
|
1369
|
-
Object.entries(
|
|
1743
|
+
Object.entries(resolvedSettings).sort(([a], [b]) => a.localeCompare(b))
|
|
1370
1744
|
);
|
|
1371
1745
|
files[".vscode/settings.json"] = {
|
|
1372
1746
|
type: "text",
|
|
@@ -1383,7 +1757,7 @@ function formatValue(value, indent) {
|
|
|
1383
1757
|
if (value.startsWith("$raw:")) {
|
|
1384
1758
|
return value.slice(5);
|
|
1385
1759
|
}
|
|
1386
|
-
return
|
|
1760
|
+
return `'${value.replaceAll("\\", "\\\\").replaceAll("'", "\\'")}'`;
|
|
1387
1761
|
}
|
|
1388
1762
|
if (typeof value === "number" || typeof value === "boolean") {
|
|
1389
1763
|
return String(value);
|
|
@@ -1391,8 +1765,17 @@ function formatValue(value, indent) {
|
|
|
1391
1765
|
if (value === null) {
|
|
1392
1766
|
return "null";
|
|
1393
1767
|
}
|
|
1768
|
+
if (value === void 0) {
|
|
1769
|
+
return "undefined";
|
|
1770
|
+
}
|
|
1771
|
+
if (typeof value === "bigint") {
|
|
1772
|
+
return value.toString();
|
|
1773
|
+
}
|
|
1394
1774
|
if (Array.isArray(value)) {
|
|
1395
1775
|
if (value.length === 0) return "[]";
|
|
1776
|
+
if (value.every((item) => item == null || typeof item !== "object")) {
|
|
1777
|
+
return `[${value.map((item) => formatValue(item, indent + 1)).join(", ")}]`;
|
|
1778
|
+
}
|
|
1396
1779
|
const items = value.map((v) => `${innerSpaces}${formatValue(v, indent + 1)}`);
|
|
1397
1780
|
return `[
|
|
1398
1781
|
${items.join(",\n")}
|
|
@@ -1402,28 +1785,114 @@ ${spaces}]`;
|
|
|
1402
1785
|
const entries = Object.entries(value);
|
|
1403
1786
|
if (entries.length === 0) return "{}";
|
|
1404
1787
|
const props = entries.map(
|
|
1405
|
-
([key, val]) => `${innerSpaces}${key}: ${formatValue(val, indent + 1)}
|
|
1788
|
+
([key, val]) => `${innerSpaces}${key}: ${formatValue(val, indent + 1)},`
|
|
1406
1789
|
);
|
|
1407
1790
|
return `{
|
|
1408
|
-
${props.join("
|
|
1791
|
+
${props.join("\n")}
|
|
1409
1792
|
${spaces}}`;
|
|
1410
1793
|
}
|
|
1411
|
-
|
|
1794
|
+
throw new TypeError(`Unsupported vite config value type: ${typeof value}`);
|
|
1412
1795
|
}
|
|
1413
|
-
function
|
|
1796
|
+
function renderViteConfig(params) {
|
|
1414
1797
|
const { viteConfig, codeSnippets } = params;
|
|
1415
1798
|
const configBody = formatValue(viteConfig, 0);
|
|
1416
1799
|
const viteConfigContent = [
|
|
1417
|
-
`import { defineConfig } from
|
|
1800
|
+
`import { defineConfig } from 'vite';`,
|
|
1418
1801
|
...codeSnippets["vite-config-import"] ?? [],
|
|
1419
1802
|
``,
|
|
1420
|
-
`export default defineConfig(${configBody})
|
|
1803
|
+
`export default defineConfig(${configBody});`,
|
|
1421
1804
|
``
|
|
1422
1805
|
].join("\n");
|
|
1423
1806
|
return { type: "text", content: viteConfigContent };
|
|
1424
1807
|
}
|
|
1425
1808
|
|
|
1426
|
-
function
|
|
1809
|
+
function toPrettierConfig(config = defaultFormatterMetaConfig) {
|
|
1810
|
+
return {
|
|
1811
|
+
$schema: "https://json.schemastore.org/prettierrc",
|
|
1812
|
+
printWidth: config.printWidth,
|
|
1813
|
+
tabWidth: config.tabWidth,
|
|
1814
|
+
useTabs: config.useTabs,
|
|
1815
|
+
semi: config.semi,
|
|
1816
|
+
singleQuote: config.singleQuote,
|
|
1817
|
+
trailingComma: config.trailingComma,
|
|
1818
|
+
bracketSpacing: config.bracketSpacing,
|
|
1819
|
+
arrowParens: config.arrowParens,
|
|
1820
|
+
overrides: [
|
|
1821
|
+
{
|
|
1822
|
+
files: ["*.md", "**/*.md"],
|
|
1823
|
+
options: { semi: false }
|
|
1824
|
+
},
|
|
1825
|
+
{
|
|
1826
|
+
files: ["*.yml", "*.yaml", "**/*.yml", "**/*.yaml"],
|
|
1827
|
+
options: { semi: false }
|
|
1828
|
+
}
|
|
1829
|
+
]
|
|
1830
|
+
};
|
|
1831
|
+
}
|
|
1832
|
+
function toPrettierIgnoreContent(config = defaultFormatterMetaConfig) {
|
|
1833
|
+
return config.ignorePatterns.join("\n");
|
|
1834
|
+
}
|
|
1835
|
+
function toOxfmtConfig(config = defaultFormatterMetaConfig) {
|
|
1836
|
+
return {
|
|
1837
|
+
printWidth: config.printWidth,
|
|
1838
|
+
tabWidth: config.tabWidth,
|
|
1839
|
+
useTabs: config.useTabs,
|
|
1840
|
+
semi: config.semi,
|
|
1841
|
+
singleQuote: config.singleQuote,
|
|
1842
|
+
trailingComma: config.trailingComma,
|
|
1843
|
+
bracketSpacing: config.bracketSpacing,
|
|
1844
|
+
arrowParens: config.arrowParens,
|
|
1845
|
+
ignorePatterns: config.ignorePatterns
|
|
1846
|
+
};
|
|
1847
|
+
}
|
|
1848
|
+
|
|
1849
|
+
const defaultLinterMetaConfig = {
|
|
1850
|
+
ignorePatterns: ["dist"],
|
|
1851
|
+
rules: {
|
|
1852
|
+
noUnusedVars: {
|
|
1853
|
+
level: "warn",
|
|
1854
|
+
argsIgnorePattern: "^_",
|
|
1855
|
+
varsIgnorePattern: "^_",
|
|
1856
|
+
caughtErrorsIgnorePattern: "^_"
|
|
1857
|
+
},
|
|
1858
|
+
noUnusedExpressions: {
|
|
1859
|
+
level: "warn",
|
|
1860
|
+
allowShortCircuit: true
|
|
1861
|
+
}
|
|
1862
|
+
}
|
|
1863
|
+
};
|
|
1864
|
+
|
|
1865
|
+
function renderOxlintConfig(params) {
|
|
1866
|
+
const config = params.config ?? defaultLinterMetaConfig;
|
|
1867
|
+
const { rules } = config;
|
|
1868
|
+
const plugins = ["unicorn", "typescript", "oxc"];
|
|
1869
|
+
if (params.react === true) {
|
|
1870
|
+
plugins.push("react");
|
|
1871
|
+
}
|
|
1872
|
+
return {
|
|
1873
|
+
$schema: params.schemaPath,
|
|
1874
|
+
plugins,
|
|
1875
|
+
...params.typescript === true ? { options: { typeAware: true } } : {},
|
|
1876
|
+
rules: {
|
|
1877
|
+
"no-unused-vars": [
|
|
1878
|
+
rules.noUnusedVars.level,
|
|
1879
|
+
{
|
|
1880
|
+
argsIgnorePattern: rules.noUnusedVars.argsIgnorePattern,
|
|
1881
|
+
varsIgnorePattern: rules.noUnusedVars.varsIgnorePattern,
|
|
1882
|
+
caughtErrorsIgnorePattern: rules.noUnusedVars.caughtErrorsIgnorePattern
|
|
1883
|
+
}
|
|
1884
|
+
],
|
|
1885
|
+
"no-useless-escape": "off",
|
|
1886
|
+
"no-unused-expressions": [
|
|
1887
|
+
rules.noUnusedExpressions.level,
|
|
1888
|
+
{ allowShortCircuit: rules.noUnusedExpressions.allowShortCircuit }
|
|
1889
|
+
]
|
|
1890
|
+
},
|
|
1891
|
+
ignorePatterns: config.ignorePatterns
|
|
1892
|
+
};
|
|
1893
|
+
}
|
|
1894
|
+
|
|
1895
|
+
function renderTypescriptConfigPackage(files) {
|
|
1427
1896
|
const basePath = ".config/typescript";
|
|
1428
1897
|
files[`${basePath}/package.json`] = {
|
|
1429
1898
|
type: "text",
|
|
@@ -1528,9 +1997,8 @@ In your package's \`tsconfig.json\`:
|
|
|
1528
1997
|
)
|
|
1529
1998
|
};
|
|
1530
1999
|
}
|
|
1531
|
-
function
|
|
2000
|
+
function renderOxlintConfigPackage(files) {
|
|
1532
2001
|
const basePath = ".config/oxlint";
|
|
1533
|
-
const { rules } = defaultLinterConfig;
|
|
1534
2002
|
files[`${basePath}/package.json`] = {
|
|
1535
2003
|
type: "text",
|
|
1536
2004
|
content: JSON.stringify(
|
|
@@ -1567,26 +2035,10 @@ oxlint -c node_modules/@config/oxlint/base.json
|
|
|
1567
2035
|
files[`${basePath}/base.json`] = {
|
|
1568
2036
|
type: "text",
|
|
1569
2037
|
content: JSON.stringify(
|
|
1570
|
-
{
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
"no-unused-vars": [
|
|
1575
|
-
rules.noUnusedVars.level,
|
|
1576
|
-
{
|
|
1577
|
-
argsIgnorePattern: rules.noUnusedVars.argsIgnorePattern,
|
|
1578
|
-
varsIgnorePattern: rules.noUnusedVars.varsIgnorePattern,
|
|
1579
|
-
caughtErrorsIgnorePattern: rules.noUnusedVars.caughtErrorsIgnorePattern
|
|
1580
|
-
}
|
|
1581
|
-
],
|
|
1582
|
-
"no-useless-escape": "off",
|
|
1583
|
-
"no-unused-expressions": [
|
|
1584
|
-
rules.noUnusedExpressions.level,
|
|
1585
|
-
{ allowShortCircuit: rules.noUnusedExpressions.allowShortCircuit }
|
|
1586
|
-
]
|
|
1587
|
-
},
|
|
1588
|
-
ignorePatterns: defaultLinterConfig.ignorePatterns
|
|
1589
|
-
},
|
|
2038
|
+
renderOxlintConfig({
|
|
2039
|
+
schemaPath: "./node_modules/oxlint/configuration_schema.json",
|
|
2040
|
+
typescript: true
|
|
2041
|
+
}),
|
|
1590
2042
|
null,
|
|
1591
2043
|
2
|
|
1592
2044
|
)
|
|
@@ -1594,32 +2046,17 @@ oxlint -c node_modules/@config/oxlint/base.json
|
|
|
1594
2046
|
files[`${basePath}/react.json`] = {
|
|
1595
2047
|
type: "text",
|
|
1596
2048
|
content: JSON.stringify(
|
|
1597
|
-
{
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
rules.noUnusedVars.level,
|
|
1603
|
-
{
|
|
1604
|
-
argsIgnorePattern: rules.noUnusedVars.argsIgnorePattern,
|
|
1605
|
-
varsIgnorePattern: rules.noUnusedVars.varsIgnorePattern,
|
|
1606
|
-
caughtErrorsIgnorePattern: rules.noUnusedVars.caughtErrorsIgnorePattern
|
|
1607
|
-
}
|
|
1608
|
-
],
|
|
1609
|
-
"no-useless-escape": "off",
|
|
1610
|
-
"no-unused-expressions": [
|
|
1611
|
-
rules.noUnusedExpressions.level,
|
|
1612
|
-
{ allowShortCircuit: rules.noUnusedExpressions.allowShortCircuit }
|
|
1613
|
-
]
|
|
1614
|
-
},
|
|
1615
|
-
ignorePatterns: defaultLinterConfig.ignorePatterns
|
|
1616
|
-
},
|
|
2049
|
+
renderOxlintConfig({
|
|
2050
|
+
schemaPath: "./node_modules/oxlint/configuration_schema.json",
|
|
2051
|
+
react: true,
|
|
2052
|
+
typescript: true
|
|
2053
|
+
}),
|
|
1617
2054
|
null,
|
|
1618
2055
|
2
|
|
1619
2056
|
)
|
|
1620
2057
|
};
|
|
1621
2058
|
}
|
|
1622
|
-
function
|
|
2059
|
+
function renderEslintConfigPackage(files) {
|
|
1623
2060
|
const basePath = ".config/eslint";
|
|
1624
2061
|
files[`${basePath}/package.json`] = {
|
|
1625
2062
|
type: "text",
|
|
@@ -1726,7 +2163,7 @@ export default tseslint.config(
|
|
|
1726
2163
|
`
|
|
1727
2164
|
};
|
|
1728
2165
|
}
|
|
1729
|
-
function
|
|
2166
|
+
function renderPrettierConfigPackage(files) {
|
|
1730
2167
|
const basePath = ".config/prettier";
|
|
1731
2168
|
files[`${basePath}/package.json`] = {
|
|
1732
2169
|
type: "text",
|
|
@@ -1739,7 +2176,7 @@ function generatePrettierConfigPackage(files) {
|
|
|
1739
2176
|
exports: {
|
|
1740
2177
|
".": "./base.json"
|
|
1741
2178
|
},
|
|
1742
|
-
files: ["base.json"]
|
|
2179
|
+
files: ["base.json", "prettierignore"]
|
|
1743
2180
|
},
|
|
1744
2181
|
null,
|
|
1745
2182
|
2
|
|
@@ -1774,10 +2211,14 @@ Or in \`.prettierrc.json\`:
|
|
|
1774
2211
|
};
|
|
1775
2212
|
files[`${basePath}/base.json`] = {
|
|
1776
2213
|
type: "text",
|
|
1777
|
-
content: JSON.stringify(
|
|
2214
|
+
content: JSON.stringify(toPrettierConfig(), null, 2)
|
|
2215
|
+
};
|
|
2216
|
+
files[`${basePath}/prettierignore`] = {
|
|
2217
|
+
type: "text",
|
|
2218
|
+
content: toPrettierIgnoreContent()
|
|
1778
2219
|
};
|
|
1779
2220
|
}
|
|
1780
|
-
function
|
|
2221
|
+
function renderOxfmtConfigPackage(files) {
|
|
1781
2222
|
const basePath = ".config/oxfmt";
|
|
1782
2223
|
files[`${basePath}/package.json`] = {
|
|
1783
2224
|
type: "text",
|
|
@@ -1813,11 +2254,11 @@ oxfmt -c node_modules/@config/oxfmt/base.json --write .
|
|
|
1813
2254
|
};
|
|
1814
2255
|
files[`${basePath}/base.json`] = {
|
|
1815
2256
|
type: "text",
|
|
1816
|
-
content: JSON.stringify(
|
|
2257
|
+
content: JSON.stringify(toOxfmtConfig(), null, 2)
|
|
1817
2258
|
};
|
|
1818
2259
|
}
|
|
1819
2260
|
|
|
1820
|
-
function
|
|
2261
|
+
function renderMonorepo(params) {
|
|
1821
2262
|
const {
|
|
1822
2263
|
name,
|
|
1823
2264
|
linter,
|
|
@@ -1826,6 +2267,7 @@ function generateMonorepo(params) {
|
|
|
1826
2267
|
pnpmManageVersions,
|
|
1827
2268
|
engine,
|
|
1828
2269
|
versions = {},
|
|
2270
|
+
ide = "vscode",
|
|
1829
2271
|
aiPlatforms
|
|
1830
2272
|
} = params;
|
|
1831
2273
|
const files = {};
|
|
@@ -1838,6 +2280,7 @@ function generateMonorepo(params) {
|
|
|
1838
2280
|
}
|
|
1839
2281
|
if (linter === "oxlint") {
|
|
1840
2282
|
assignResolvedPackageVersion(devDependencies, versions, "oxlint");
|
|
2283
|
+
assignResolvedPackageVersion(devDependencies, versions, "oxlint-tsgolint");
|
|
1841
2284
|
} else if (linter === "eslint") {
|
|
1842
2285
|
assignResolvedPackageVersion(devDependencies, versions, "eslint");
|
|
1843
2286
|
} else if (linter === "biome") {
|
|
@@ -1853,13 +2296,7 @@ function generateMonorepo(params) {
|
|
|
1853
2296
|
version: "0.0.0",
|
|
1854
2297
|
private: true,
|
|
1855
2298
|
type: "module",
|
|
1856
|
-
scripts:
|
|
1857
|
-
dev: "pnpm --filter './apps/*' run dev",
|
|
1858
|
-
build: "pnpm --filter './packages/*' run build && pnpm --filter './apps/*' run build",
|
|
1859
|
-
test: "pnpm -r run test",
|
|
1860
|
-
lint: linter === "oxlint" ? "oxlint ." : linter === "biome" ? "biome check ." : "eslint .",
|
|
1861
|
-
format: formatter === "oxfmt" ? "oxfmt -c .config/oxfmt/base.json ." : formatter === "biome" ? "biome format . --write" : "prettier --config .config/prettier/base.json --write ."
|
|
1862
|
-
},
|
|
2299
|
+
scripts: packageJsonScripts.monorepoRoot(linter, formatter),
|
|
1863
2300
|
devDependencies
|
|
1864
2301
|
};
|
|
1865
2302
|
const engines = {};
|
|
@@ -1905,9 +2342,9 @@ function generateMonorepo(params) {
|
|
|
1905
2342
|
2
|
|
1906
2343
|
)
|
|
1907
2344
|
};
|
|
1908
|
-
|
|
2345
|
+
renderTypescriptConfigPackage(files);
|
|
1909
2346
|
if (linter === "oxlint") {
|
|
1910
|
-
|
|
2347
|
+
renderOxlintConfigPackage(files);
|
|
1911
2348
|
files["oxlint.json"] = {
|
|
1912
2349
|
type: "text",
|
|
1913
2350
|
content: JSON.stringify(
|
|
@@ -1920,7 +2357,7 @@ function generateMonorepo(params) {
|
|
|
1920
2357
|
)
|
|
1921
2358
|
};
|
|
1922
2359
|
} else if (linter === "eslint") {
|
|
1923
|
-
|
|
2360
|
+
renderEslintConfigPackage(files);
|
|
1924
2361
|
files["eslint.config.js"] = {
|
|
1925
2362
|
type: "text",
|
|
1926
2363
|
content: `import base from "@config/eslint/base";
|
|
@@ -1953,11 +2390,12 @@ export default [...base];
|
|
|
1953
2390
|
};
|
|
1954
2391
|
}
|
|
1955
2392
|
if (formatter === "oxfmt") {
|
|
1956
|
-
|
|
2393
|
+
renderOxfmtConfigPackage(files);
|
|
1957
2394
|
} else if (formatter === "prettier") {
|
|
1958
|
-
|
|
2395
|
+
renderPrettierConfigPackage(files);
|
|
1959
2396
|
}
|
|
1960
|
-
files[".
|
|
2397
|
+
files[".editorconfig"] = renderEditorConfig();
|
|
2398
|
+
files[".gitignore"] = renderGitignore("workspace-root");
|
|
1961
2399
|
files[".gitattributes"] = {
|
|
1962
2400
|
type: "text",
|
|
1963
2401
|
content: `* text=auto eol=lf
|
|
@@ -1965,7 +2403,9 @@ export default [...base];
|
|
|
1965
2403
|
*.{bat,[bB][aA][tT]} text eol=crlf
|
|
1966
2404
|
`
|
|
1967
2405
|
};
|
|
1968
|
-
|
|
2406
|
+
if (ide === "vscode") {
|
|
2407
|
+
renderVscodeFiles(files, linter, formatter, packageManager.name);
|
|
2408
|
+
}
|
|
1969
2409
|
files["README.md"] = {
|
|
1970
2410
|
type: "text",
|
|
1971
2411
|
content: `# ${name}
|
|
@@ -1993,104 +2433,50 @@ To add a new package to this workspace, run create-krispya from this directory a
|
|
|
1993
2433
|
`
|
|
1994
2434
|
};
|
|
1995
2435
|
if (aiPlatforms && aiPlatforms.length > 0) {
|
|
1996
|
-
|
|
2436
|
+
renderAiFiles(files, {
|
|
1997
2437
|
name,
|
|
1998
2438
|
packageManager: packageManager.name,
|
|
1999
2439
|
linter,
|
|
2000
2440
|
formatter,
|
|
2001
2441
|
isMonorepo: true,
|
|
2442
|
+
hasTypecheck: false,
|
|
2002
2443
|
platforms: aiPlatforms
|
|
2003
2444
|
});
|
|
2004
2445
|
}
|
|
2005
2446
|
return { files };
|
|
2006
2447
|
}
|
|
2007
|
-
function
|
|
2008
|
-
const recommendations = [];
|
|
2009
|
-
const settings = {};
|
|
2010
|
-
if (linter === "oxlint") {
|
|
2011
|
-
recommendations.push("oxc.oxc-vscode");
|
|
2012
|
-
settings["oxc.enable"] = true;
|
|
2013
|
-
settings["eslint.enable"] = false;
|
|
2014
|
-
settings["biome.enabled"] = false;
|
|
2015
|
-
} else if (linter === "eslint") {
|
|
2016
|
-
recommendations.push("dbaeumer.vscode-eslint");
|
|
2017
|
-
settings["eslint.enable"] = true;
|
|
2018
|
-
settings["oxc.enable"] = false;
|
|
2019
|
-
settings["biome.enabled"] = false;
|
|
2020
|
-
} else if (linter === "biome") {
|
|
2021
|
-
recommendations.push("biomejs.biome");
|
|
2022
|
-
settings["biome.enabled"] = true;
|
|
2023
|
-
settings["eslint.enable"] = false;
|
|
2024
|
-
settings["oxc.enable"] = false;
|
|
2025
|
-
}
|
|
2026
|
-
if (formatter === "oxfmt") {
|
|
2027
|
-
if (!recommendations.includes("oxc.oxc-vscode")) {
|
|
2028
|
-
recommendations.push("oxc.oxc-vscode");
|
|
2029
|
-
}
|
|
2030
|
-
settings["editor.defaultFormatter"] = "oxc.oxc-vscode";
|
|
2031
|
-
settings["[json]"] = {
|
|
2032
|
-
"editor.defaultFormatter": "vscode.json-language-features"
|
|
2033
|
-
};
|
|
2034
|
-
settings["[jsonc]"] = {
|
|
2035
|
-
"editor.defaultFormatter": "vscode.json-language-features"
|
|
2036
|
-
};
|
|
2037
|
-
} else if (formatter === "prettier") {
|
|
2038
|
-
recommendations.push("esbenp.prettier-vscode");
|
|
2039
|
-
settings["editor.defaultFormatter"] = "esbenp.prettier-vscode";
|
|
2040
|
-
} else if (formatter === "biome") {
|
|
2041
|
-
if (!recommendations.includes("biomejs.biome")) {
|
|
2042
|
-
recommendations.push("biomejs.biome");
|
|
2043
|
-
}
|
|
2044
|
-
settings["editor.defaultFormatter"] = "biomejs.biome";
|
|
2045
|
-
}
|
|
2046
|
-
files[".vscode/extensions.json"] = {
|
|
2047
|
-
type: "text",
|
|
2048
|
-
content: JSON.stringify({ recommendations }, null, 2)
|
|
2049
|
-
};
|
|
2050
|
-
const codeSnippets = {};
|
|
2051
|
-
if (recommendations.length > 0) {
|
|
2052
|
-
codeSnippets["vscode-extension-suggestion"] = recommendations;
|
|
2053
|
-
}
|
|
2448
|
+
function renderVscodeFiles(files, linter, formatter, packageManager = "pnpm") {
|
|
2054
2449
|
Object.assign(
|
|
2055
2450
|
files,
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2451
|
+
renderVscodeFiles$1({
|
|
2452
|
+
linter,
|
|
2453
|
+
formatter,
|
|
2454
|
+
isMonorepo: true,
|
|
2455
|
+
packageManager
|
|
2059
2456
|
})
|
|
2060
2457
|
);
|
|
2061
2458
|
}
|
|
2062
2459
|
|
|
2063
|
-
const monorepo = {
|
|
2064
|
-
__proto__: null,
|
|
2065
|
-
generateEslintConfigPackage: generateEslintConfigPackage,
|
|
2066
|
-
generateMonorepo: generateMonorepo,
|
|
2067
|
-
generateOxfmtConfigPackage: generateOxfmtConfigPackage,
|
|
2068
|
-
generateOxlintConfigPackage: generateOxlintConfigPackage,
|
|
2069
|
-
generatePrettierConfigPackage: generatePrettierConfigPackage,
|
|
2070
|
-
generateTypescriptConfigPackage: generateTypescriptConfigPackage,
|
|
2071
|
-
generateVscodeFiles: generateVscodeFiles
|
|
2072
|
-
};
|
|
2073
|
-
|
|
2074
2460
|
function toBiomeLevel(level) {
|
|
2075
2461
|
return level;
|
|
2076
2462
|
}
|
|
2077
|
-
function
|
|
2463
|
+
function planBiome(builder, options) {
|
|
2078
2464
|
if (options == null || !options.linter && !options.formatter) {
|
|
2079
2465
|
return;
|
|
2080
2466
|
}
|
|
2081
|
-
const version =
|
|
2082
|
-
|
|
2083
|
-
const { rules } = defaultLinterConfig;
|
|
2467
|
+
const version = builder.getVersion("@biomejs/biome");
|
|
2468
|
+
builder.addDevDependency("@biomejs/biome");
|
|
2084
2469
|
const biomeConfig = {
|
|
2085
2470
|
$schema: `https://biomejs.dev/schemas/${version}/schema.json`
|
|
2086
2471
|
};
|
|
2087
2472
|
if (options.linter) {
|
|
2473
|
+
const linterConfig = options.linter.config;
|
|
2088
2474
|
biomeConfig.linter = {
|
|
2089
2475
|
enabled: true,
|
|
2090
2476
|
rules: {
|
|
2091
2477
|
recommended: true,
|
|
2092
2478
|
correctness: {
|
|
2093
|
-
noUnusedVariables: toBiomeLevel(rules.noUnusedVars.level)
|
|
2479
|
+
noUnusedVariables: toBiomeLevel(linterConfig.rules.noUnusedVars.level)
|
|
2094
2480
|
}
|
|
2095
2481
|
}
|
|
2096
2482
|
};
|
|
@@ -2100,19 +2486,20 @@ function generateBiome(generator, options) {
|
|
|
2100
2486
|
};
|
|
2101
2487
|
}
|
|
2102
2488
|
if (options.formatter) {
|
|
2489
|
+
const formatterConfig = options.formatter.config;
|
|
2103
2490
|
biomeConfig.formatter = {
|
|
2104
2491
|
enabled: true,
|
|
2105
|
-
lineWidth:
|
|
2106
|
-
indentWidth:
|
|
2107
|
-
indentStyle: "space"
|
|
2492
|
+
lineWidth: formatterConfig.printWidth,
|
|
2493
|
+
indentWidth: formatterConfig.tabWidth,
|
|
2494
|
+
indentStyle: formatterConfig.useTabs ? "tab" : "space"
|
|
2108
2495
|
};
|
|
2109
2496
|
biomeConfig.javascript = {
|
|
2110
2497
|
formatter: {
|
|
2111
|
-
semicolons: "always" ,
|
|
2112
|
-
quoteStyle: "single" ,
|
|
2113
|
-
trailingCommas:
|
|
2114
|
-
bracketSpacing:
|
|
2115
|
-
arrowParentheses: "always"
|
|
2498
|
+
semicolons: formatterConfig.semi ? "always" : "asNeeded",
|
|
2499
|
+
quoteStyle: formatterConfig.singleQuote ? "single" : "double",
|
|
2500
|
+
trailingCommas: formatterConfig.trailingComma,
|
|
2501
|
+
bracketSpacing: formatterConfig.bracketSpacing,
|
|
2502
|
+
arrowParentheses: formatterConfig.arrowParens === "always" ? "always" : "asNeeded"
|
|
2116
2503
|
}
|
|
2117
2504
|
};
|
|
2118
2505
|
biomeConfig.json = {
|
|
@@ -2125,53 +2512,48 @@ function generateBiome(generator, options) {
|
|
|
2125
2512
|
enabled: false
|
|
2126
2513
|
};
|
|
2127
2514
|
}
|
|
2128
|
-
const isStealth =
|
|
2515
|
+
const isStealth = builder.isStealthConfig();
|
|
2129
2516
|
if (isStealth) {
|
|
2130
|
-
|
|
2517
|
+
builder.addFile(".config/biome.json", {
|
|
2131
2518
|
type: "text",
|
|
2132
2519
|
content: JSON.stringify(biomeConfig, null, 2)
|
|
2133
2520
|
});
|
|
2134
2521
|
if (options.linter) {
|
|
2135
|
-
|
|
2522
|
+
builder.addScripts(packageJsonScripts.lint.biome(".config"));
|
|
2136
2523
|
}
|
|
2137
2524
|
if (options.formatter) {
|
|
2138
|
-
|
|
2525
|
+
builder.addScripts(packageJsonScripts.format.biome(".config"));
|
|
2139
2526
|
}
|
|
2140
|
-
generator.addVscodeSetting("biome.linter.configPath", ".config/biome.json");
|
|
2141
2527
|
} else {
|
|
2142
|
-
|
|
2528
|
+
builder.addFile("biome.json", {
|
|
2143
2529
|
type: "text",
|
|
2144
2530
|
content: JSON.stringify(biomeConfig, null, 2)
|
|
2145
2531
|
});
|
|
2146
2532
|
if (options.linter) {
|
|
2147
|
-
|
|
2533
|
+
builder.addScripts(packageJsonScripts.lint.biome());
|
|
2148
2534
|
}
|
|
2149
2535
|
if (options.formatter) {
|
|
2150
|
-
|
|
2536
|
+
builder.addScripts(packageJsonScripts.format.biome());
|
|
2151
2537
|
}
|
|
2152
2538
|
}
|
|
2153
2539
|
const roles = [];
|
|
2154
2540
|
if (options.linter) roles.push("linter");
|
|
2155
2541
|
if (options.formatter) roles.push("formatter");
|
|
2156
|
-
|
|
2542
|
+
builder.inject(
|
|
2157
2543
|
"readme-tools",
|
|
2158
2544
|
`[Biome](https://biomejs.dev/) - Fast ${roles.join(" and ")} for JavaScript and TypeScript`
|
|
2159
2545
|
);
|
|
2160
|
-
|
|
2161
|
-
generator.addVscodeSetting("biome.enabled", true);
|
|
2162
|
-
if (options.formatter) {
|
|
2163
|
-
generator.addVscodeSetting("editor.defaultFormatter", "biomejs.biome");
|
|
2164
|
-
}
|
|
2546
|
+
builder.inject("vscode-extension-suggestion", "biomejs.biome");
|
|
2165
2547
|
}
|
|
2166
2548
|
|
|
2167
|
-
function
|
|
2549
|
+
function planDrei(builder, options) {
|
|
2168
2550
|
if (options == null) {
|
|
2169
2551
|
return;
|
|
2170
2552
|
}
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2553
|
+
builder.addDependency("@react-three/drei");
|
|
2554
|
+
builder.inject("import", `import { Environment } from "@react-three/drei"`);
|
|
2555
|
+
builder.inject("scene", '<Environment background preset="city" />');
|
|
2556
|
+
builder.inject(
|
|
2175
2557
|
"readme-libraries",
|
|
2176
2558
|
`[@react-three/drei](https://drei.docs.pmnd.rs/) - Useful helpers for @react-three/fiber`
|
|
2177
2559
|
);
|
|
@@ -2180,25 +2562,28 @@ function generateDrei(generator, options) {
|
|
|
2180
2562
|
function toEslintLevel(level) {
|
|
2181
2563
|
return level;
|
|
2182
2564
|
}
|
|
2183
|
-
function
|
|
2184
|
-
|
|
2185
|
-
|
|
2565
|
+
function planEslint(builder, options) {
|
|
2566
|
+
if (options == null) {
|
|
2567
|
+
return;
|
|
2568
|
+
}
|
|
2569
|
+
builder.addDevDependency("eslint");
|
|
2570
|
+
const template = builder.options.template ?? "vanilla";
|
|
2186
2571
|
const baseTemplate = getBaseTemplate(template);
|
|
2187
2572
|
const isTypescript = getLanguageFromTemplate(template) === "typescript";
|
|
2188
2573
|
const isReact = baseTemplate === "react" || baseTemplate === "r3f";
|
|
2189
|
-
const { rules } =
|
|
2574
|
+
const { rules } = options.config;
|
|
2190
2575
|
const imports = ['import js from "@eslint/js"'];
|
|
2191
2576
|
const configs = ["js.configs.recommended"];
|
|
2192
2577
|
if (isTypescript) {
|
|
2193
|
-
|
|
2578
|
+
builder.addDevDependency("typescript-eslint");
|
|
2194
2579
|
imports.push('import tseslint from "typescript-eslint"');
|
|
2195
2580
|
configs.push("...tseslint.configs.recommended");
|
|
2196
2581
|
}
|
|
2197
2582
|
if (isReact) {
|
|
2198
|
-
|
|
2583
|
+
builder.addDevDependency("eslint-plugin-react-hooks");
|
|
2199
2584
|
imports.push('import reactHooks from "eslint-plugin-react-hooks"');
|
|
2200
2585
|
}
|
|
2201
|
-
const ignoresArray = JSON.stringify(
|
|
2586
|
+
const ignoresArray = JSON.stringify(options.config.ignorePatterns);
|
|
2202
2587
|
const unusedVarsRule = isTypescript ? "@typescript-eslint/no-unused-vars" : "no-unused-vars";
|
|
2203
2588
|
const rulesConfig = {
|
|
2204
2589
|
[unusedVarsRule]: [
|
|
@@ -2232,34 +2617,30 @@ function generateEslint(generator, options) {
|
|
|
2232
2617
|
},`,
|
|
2233
2618
|
"]"
|
|
2234
2619
|
].filter(Boolean).join("\n");
|
|
2235
|
-
const isStealth =
|
|
2620
|
+
const isStealth = builder.isStealthConfig();
|
|
2236
2621
|
if (isStealth) {
|
|
2237
|
-
|
|
2622
|
+
builder.addFile(".config/eslint.config.js", {
|
|
2238
2623
|
type: "text",
|
|
2239
2624
|
content: configContent
|
|
2240
2625
|
});
|
|
2241
|
-
|
|
2242
|
-
generator.addVscodeSetting("eslint.options", {
|
|
2243
|
-
overrideConfigFile: ".config/eslint.config.js"
|
|
2244
|
-
});
|
|
2626
|
+
builder.addScripts(packageJsonScripts.lint.eslint(".config/eslint.config.js"));
|
|
2245
2627
|
} else {
|
|
2246
|
-
|
|
2628
|
+
builder.addFile("eslint.config.js", {
|
|
2247
2629
|
type: "text",
|
|
2248
2630
|
content: configContent
|
|
2249
2631
|
});
|
|
2250
|
-
|
|
2632
|
+
builder.addScripts(packageJsonScripts.lint.eslint());
|
|
2251
2633
|
}
|
|
2252
|
-
|
|
2634
|
+
builder.inject(
|
|
2253
2635
|
"readme-tools",
|
|
2254
2636
|
"[ESLint](https://eslint.org/) - Linter for JavaScript and TypeScript"
|
|
2255
2637
|
);
|
|
2256
|
-
|
|
2257
|
-
generator.addVscodeSetting("eslint.enable", true);
|
|
2638
|
+
builder.inject("vscode-extension-suggestion", "dbaeumer.vscode-eslint");
|
|
2258
2639
|
}
|
|
2259
2640
|
|
|
2260
|
-
function
|
|
2261
|
-
|
|
2262
|
-
|
|
2641
|
+
function planFiber(builder, _options) {
|
|
2642
|
+
builder.inject("import", `import { Box } from "./box.js"`);
|
|
2643
|
+
builder.inject(
|
|
2263
2644
|
"scene",
|
|
2264
2645
|
[
|
|
2265
2646
|
`<ambientLight intensity={Math.PI / 2} />`,
|
|
@@ -2269,7 +2650,7 @@ function generateFiber(generator, _options) {
|
|
|
2269
2650
|
`<Box position={[1.2, 0, 0]} />`
|
|
2270
2651
|
].join("\n")
|
|
2271
2652
|
);
|
|
2272
|
-
|
|
2653
|
+
builder.addFile("src/box.tsx", {
|
|
2273
2654
|
type: "text",
|
|
2274
2655
|
content: `import type { Mesh } from 'three'
|
|
2275
2656
|
import { useRef, useState } from 'react'
|
|
@@ -2296,11 +2677,11 @@ export function Box(props: ThreeElements['mesh']) {
|
|
|
2296
2677
|
});
|
|
2297
2678
|
}
|
|
2298
2679
|
|
|
2299
|
-
function
|
|
2300
|
-
if (options === false || getPackageManagerName(
|
|
2680
|
+
function planGithubPages(builder, options) {
|
|
2681
|
+
if (options === false || getPackageManagerName(builder.options.packageManager) !== "npm") {
|
|
2301
2682
|
return;
|
|
2302
2683
|
}
|
|
2303
|
-
|
|
2684
|
+
builder.addFile(".github/workflows/gh-pages.yml", {
|
|
2304
2685
|
type: "text",
|
|
2305
2686
|
content: `name: Deploy to Github Pages
|
|
2306
2687
|
|
|
@@ -2346,10 +2727,10 @@ jobs:
|
|
|
2346
2727
|
uses: actions/deploy-pages@v4
|
|
2347
2728
|
`
|
|
2348
2729
|
});
|
|
2349
|
-
|
|
2350
|
-
if (
|
|
2351
|
-
const address = `${
|
|
2352
|
-
|
|
2730
|
+
builder.inject("readme-start", `A github pages deployment action is configurd.`);
|
|
2731
|
+
if (builder.options.githubUserName != null && builder.options.githubRepoName != null) {
|
|
2732
|
+
const address = `${builder.options.githubUserName}.github.io/${builder.options.githubRepoName}`;
|
|
2733
|
+
builder.inject(
|
|
2353
2734
|
"readme-start",
|
|
2354
2735
|
`Your app will be publish at [${address}](https://${address}) once the github action is finished.
|
|
2355
2736
|
`
|
|
@@ -2357,228 +2738,199 @@ jobs:
|
|
|
2357
2738
|
}
|
|
2358
2739
|
}
|
|
2359
2740
|
|
|
2360
|
-
function
|
|
2741
|
+
function planHandle(builder, options) {
|
|
2361
2742
|
if (options == null) {
|
|
2362
2743
|
return;
|
|
2363
2744
|
}
|
|
2364
|
-
|
|
2365
|
-
|
|
2745
|
+
builder.addDependency("@react-three/handle");
|
|
2746
|
+
builder.inject(
|
|
2366
2747
|
"readme-libraries",
|
|
2367
2748
|
`[@react-three/handle](https://pmndrs.github.io/xr/docs/handles/introduction) - interactive controls and handles for your 3D objects`
|
|
2368
2749
|
);
|
|
2369
2750
|
}
|
|
2370
2751
|
|
|
2371
|
-
function
|
|
2752
|
+
function planKoota(builder, options) {
|
|
2372
2753
|
if (options == null) {
|
|
2373
2754
|
return;
|
|
2374
2755
|
}
|
|
2375
|
-
|
|
2376
|
-
|
|
2756
|
+
builder.addDependency("koota");
|
|
2757
|
+
builder.inject(
|
|
2377
2758
|
"readme-libraries",
|
|
2378
2759
|
`[koota](https://github.com/pmndrs/koota) - ECS-based state management library optimized for real-time apps, games, and XR experiences`
|
|
2379
2760
|
);
|
|
2380
2761
|
}
|
|
2381
2762
|
|
|
2382
|
-
function
|
|
2763
|
+
function planLeva(builder, options) {
|
|
2383
2764
|
if (options == null) {
|
|
2384
2765
|
return;
|
|
2385
2766
|
}
|
|
2386
|
-
|
|
2387
|
-
|
|
2767
|
+
builder.addDependency("leva");
|
|
2768
|
+
builder.inject(
|
|
2388
2769
|
"readme-libraries",
|
|
2389
2770
|
`[leva](https://github.com/pmndrs/leva) - HTML GUI panel for React with lightweight, beautiful and extensible controls`
|
|
2390
2771
|
);
|
|
2391
2772
|
}
|
|
2392
2773
|
|
|
2393
|
-
function
|
|
2774
|
+
function planOffscreen(builder, options) {
|
|
2394
2775
|
if (options == null) {
|
|
2395
2776
|
return;
|
|
2396
2777
|
}
|
|
2397
|
-
if (
|
|
2778
|
+
if (builder.options.xr != null) {
|
|
2398
2779
|
console.info(
|
|
2399
2780
|
color.blue("Info:"),
|
|
2400
2781
|
"@react-three/offscreen is disabled because it is not supported with XR"
|
|
2401
2782
|
);
|
|
2402
2783
|
return;
|
|
2403
2784
|
}
|
|
2404
|
-
|
|
2405
|
-
|
|
2785
|
+
builder.addDependency("@react-three/offscreen");
|
|
2786
|
+
builder.inject(
|
|
2406
2787
|
"readme-libraries",
|
|
2407
2788
|
`[@react-three/offscreen](https://github.com/pmndrs/offscreen) - Offload your scene to a worker thread for better performance`
|
|
2408
2789
|
);
|
|
2409
2790
|
}
|
|
2410
2791
|
|
|
2411
|
-
function
|
|
2412
|
-
|
|
2792
|
+
function planOxfmt(builder, options) {
|
|
2793
|
+
if (options == null) {
|
|
2794
|
+
return;
|
|
2795
|
+
}
|
|
2796
|
+
const isMonorepo = builder.options.workspaceRoot != null;
|
|
2413
2797
|
if (isMonorepo) {
|
|
2414
|
-
|
|
2798
|
+
builder.addDevDependency("@config/oxfmt", { version: "workspace:*" });
|
|
2415
2799
|
const configPath = "node_modules/@config/oxfmt/base.json";
|
|
2416
|
-
|
|
2417
|
-
generator.addVscodeSetting("oxc.fmt.configPath", configPath);
|
|
2800
|
+
builder.addScripts(packageJsonScripts.format.oxfmt(configPath));
|
|
2418
2801
|
} else {
|
|
2419
|
-
|
|
2420
|
-
const isStealth =
|
|
2802
|
+
builder.addDevDependency("oxfmt");
|
|
2803
|
+
const isStealth = builder.isStealthConfig();
|
|
2421
2804
|
if (isStealth) {
|
|
2422
|
-
|
|
2805
|
+
builder.addFile(".config/oxfmt.json", {
|
|
2423
2806
|
type: "text",
|
|
2424
|
-
content: JSON.stringify(
|
|
2807
|
+
content: JSON.stringify(toOxfmtConfig(options.config), null, 2)
|
|
2425
2808
|
});
|
|
2426
|
-
|
|
2427
|
-
generator.addVscodeSetting("oxc.fmt.configPath", ".config/oxfmt.json");
|
|
2809
|
+
builder.addScripts(packageJsonScripts.format.oxfmt(".config/oxfmt.json"));
|
|
2428
2810
|
} else {
|
|
2429
|
-
|
|
2811
|
+
builder.addFile("oxfmt.json", {
|
|
2430
2812
|
type: "text",
|
|
2431
|
-
content: JSON.stringify(
|
|
2813
|
+
content: JSON.stringify(toOxfmtConfig(options.config), null, 2)
|
|
2432
2814
|
});
|
|
2433
|
-
|
|
2815
|
+
builder.addScripts(packageJsonScripts.format.oxfmt("oxfmt.json"));
|
|
2434
2816
|
}
|
|
2435
2817
|
}
|
|
2436
|
-
|
|
2818
|
+
builder.inject(
|
|
2437
2819
|
"readme-tools",
|
|
2438
2820
|
"[Oxfmt](https://oxc.rs/docs/guide/usage/formatter) - Fast Prettier-compatible code formatter"
|
|
2439
2821
|
);
|
|
2440
|
-
|
|
2441
|
-
generator.addVscodeSetting("editor.defaultFormatter", "oxc.oxc-vscode");
|
|
2442
|
-
generator.addVscodeSetting("[json]", {
|
|
2443
|
-
"editor.defaultFormatter": "vscode.json-language-features"
|
|
2444
|
-
});
|
|
2445
|
-
generator.addVscodeSetting("[jsonc]", {
|
|
2446
|
-
"editor.defaultFormatter": "vscode.json-language-features"
|
|
2447
|
-
});
|
|
2448
|
-
generator.addVscodeSetting("[markdown]", {
|
|
2449
|
-
"editor.defaultFormatter": "vscode.markdown-language-features"
|
|
2450
|
-
});
|
|
2451
|
-
generator.addVscodeSetting("[yaml]", {
|
|
2452
|
-
"editor.defaultFormatter": "redhat.vscode-yaml"
|
|
2453
|
-
});
|
|
2822
|
+
builder.inject("vscode-extension-suggestion", "oxc.oxc-vscode");
|
|
2454
2823
|
}
|
|
2455
2824
|
|
|
2456
|
-
function
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
const template =
|
|
2825
|
+
function planOxlint(builder, options) {
|
|
2826
|
+
if (options == null) {
|
|
2827
|
+
return;
|
|
2828
|
+
}
|
|
2829
|
+
const template = builder.options.template ?? "vanilla";
|
|
2461
2830
|
const baseTemplate = getBaseTemplate(template);
|
|
2831
|
+
const isTypescript = getLanguageFromTemplate(template) === "typescript";
|
|
2462
2832
|
const isReact = baseTemplate === "react" || baseTemplate === "r3f";
|
|
2463
|
-
const isMonorepo =
|
|
2833
|
+
const isMonorepo = builder.options.workspaceRoot != null;
|
|
2464
2834
|
if (isMonorepo) {
|
|
2465
|
-
|
|
2835
|
+
builder.addDevDependency("@config/oxlint", { version: "workspace:*" });
|
|
2466
2836
|
const configPath = isReact ? "node_modules/@config/oxlint/react.json" : "node_modules/@config/oxlint/base.json";
|
|
2467
|
-
|
|
2468
|
-
generator.addVscodeSetting("oxc.configPath", configPath);
|
|
2837
|
+
builder.addScripts(packageJsonScripts.lint.oxlint(configPath));
|
|
2469
2838
|
} else {
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
"no-unused-vars": [
|
|
2482
|
-
toOxlintLevel(rules.noUnusedVars.level),
|
|
2483
|
-
{
|
|
2484
|
-
argsIgnorePattern: rules.noUnusedVars.argsIgnorePattern,
|
|
2485
|
-
varsIgnorePattern: rules.noUnusedVars.varsIgnorePattern,
|
|
2486
|
-
caughtErrorsIgnorePattern: rules.noUnusedVars.caughtErrorsIgnorePattern
|
|
2487
|
-
}
|
|
2488
|
-
],
|
|
2489
|
-
"no-useless-escape": "off",
|
|
2490
|
-
"no-unused-expressions": [
|
|
2491
|
-
toOxlintLevel(rules.noUnusedExpressions.level),
|
|
2492
|
-
{ allowShortCircuit: rules.noUnusedExpressions.allowShortCircuit }
|
|
2493
|
-
]
|
|
2494
|
-
},
|
|
2495
|
-
ignorePatterns: defaultLinterConfig.ignorePatterns
|
|
2496
|
-
};
|
|
2839
|
+
builder.addDevDependency("oxlint");
|
|
2840
|
+
if (isTypescript) {
|
|
2841
|
+
builder.addDevDependency("oxlint-tsgolint");
|
|
2842
|
+
}
|
|
2843
|
+
const isStealth = builder.isStealthConfig();
|
|
2844
|
+
const oxlintConfig = renderOxlintConfig({
|
|
2845
|
+
schemaPath: isStealth ? "../node_modules/oxlint/configuration_schema.json" : "./node_modules/oxlint/configuration_schema.json",
|
|
2846
|
+
react: isReact,
|
|
2847
|
+
typescript: isTypescript,
|
|
2848
|
+
config: options.config
|
|
2849
|
+
});
|
|
2497
2850
|
if (isStealth) {
|
|
2498
|
-
|
|
2851
|
+
builder.addFile(".config/oxlint.json", {
|
|
2499
2852
|
type: "text",
|
|
2500
2853
|
content: JSON.stringify(oxlintConfig, null, 2)
|
|
2501
2854
|
});
|
|
2502
|
-
|
|
2503
|
-
generator.addVscodeSetting("oxc.configPath", ".config/oxlint.json");
|
|
2855
|
+
builder.addScripts(packageJsonScripts.lint.oxlint(".config/oxlint.json"));
|
|
2504
2856
|
} else {
|
|
2505
|
-
|
|
2857
|
+
builder.addFile("oxlint.json", {
|
|
2506
2858
|
type: "text",
|
|
2507
2859
|
content: JSON.stringify(oxlintConfig, null, 2)
|
|
2508
2860
|
});
|
|
2509
|
-
|
|
2861
|
+
builder.addScripts(packageJsonScripts.lint.oxlint());
|
|
2510
2862
|
}
|
|
2511
2863
|
}
|
|
2512
|
-
|
|
2864
|
+
builder.inject(
|
|
2513
2865
|
"readme-tools",
|
|
2514
2866
|
"[Oxlint](https://oxc.rs/docs/guide/usage/linter) - A fast linter for JavaScript and TypeScript"
|
|
2515
2867
|
);
|
|
2516
|
-
|
|
2517
|
-
generator.addVscodeSetting("oxc.enable", true);
|
|
2868
|
+
builder.inject("vscode-extension-suggestion", "oxc.oxc-vscode");
|
|
2518
2869
|
}
|
|
2519
2870
|
|
|
2520
|
-
function
|
|
2871
|
+
function planPostprocessing(builder, options) {
|
|
2521
2872
|
if (options == null) {
|
|
2522
2873
|
return;
|
|
2523
2874
|
}
|
|
2524
|
-
if (
|
|
2875
|
+
if (builder.options.xr != null) {
|
|
2525
2876
|
console.info(
|
|
2526
2877
|
color.blue("Info:"),
|
|
2527
2878
|
"@react-three/postprocessing is disabled because it is not supported with XR"
|
|
2528
2879
|
);
|
|
2529
2880
|
return;
|
|
2530
2881
|
}
|
|
2531
|
-
|
|
2532
|
-
|
|
2882
|
+
builder.addDependency("@react-three/postprocessing");
|
|
2883
|
+
builder.inject(
|
|
2533
2884
|
"readme-libraries",
|
|
2534
2885
|
`[@react-three/postprocessing](https://react-postprocessing.docs.pmnd.rs/) - Post-processing effects for @react-three/fiber`
|
|
2535
2886
|
);
|
|
2536
2887
|
}
|
|
2537
2888
|
|
|
2538
|
-
function
|
|
2539
|
-
|
|
2540
|
-
|
|
2889
|
+
function planPrettier(builder, options) {
|
|
2890
|
+
if (options == null) {
|
|
2891
|
+
return;
|
|
2892
|
+
}
|
|
2893
|
+
builder.addDevDependency("prettier");
|
|
2894
|
+
const isStealth = builder.isStealthConfig();
|
|
2541
2895
|
if (isStealth) {
|
|
2542
|
-
|
|
2896
|
+
builder.addFile(".config/prettier.json", {
|
|
2897
|
+
type: "text",
|
|
2898
|
+
content: JSON.stringify(toPrettierConfig(options.config), null, 2)
|
|
2899
|
+
});
|
|
2900
|
+
builder.addFile(".config/prettierignore", {
|
|
2543
2901
|
type: "text",
|
|
2544
|
-
content:
|
|
2902
|
+
content: toPrettierIgnoreContent(options.config)
|
|
2545
2903
|
});
|
|
2546
|
-
|
|
2547
|
-
|
|
2904
|
+
builder.addScripts(
|
|
2905
|
+
packageJsonScripts.format.prettier(".config/prettier.json", ".config/prettierignore")
|
|
2906
|
+
);
|
|
2548
2907
|
} else {
|
|
2549
|
-
|
|
2908
|
+
builder.addFile(".prettierrc", {
|
|
2909
|
+
type: "text",
|
|
2910
|
+
content: JSON.stringify(toPrettierConfig(options.config), null, 2)
|
|
2911
|
+
});
|
|
2912
|
+
builder.addFile(".prettierignore", {
|
|
2550
2913
|
type: "text",
|
|
2551
|
-
content:
|
|
2914
|
+
content: toPrettierIgnoreContent(options.config)
|
|
2552
2915
|
});
|
|
2553
|
-
|
|
2916
|
+
builder.addScripts(packageJsonScripts.format.prettier());
|
|
2554
2917
|
}
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
generator.addVscodeSetting("editor.defaultFormatter", "esbenp.prettier-vscode");
|
|
2918
|
+
builder.inject("readme-tools", "[Prettier](https://prettier.io/) - Opinionated code formatter");
|
|
2919
|
+
builder.inject("vscode-extension-suggestion", "esbenp.prettier-vscode");
|
|
2558
2920
|
}
|
|
2559
2921
|
|
|
2560
|
-
function
|
|
2922
|
+
function planRapier(builder, options) {
|
|
2561
2923
|
if (options == null) {
|
|
2562
2924
|
return;
|
|
2563
2925
|
}
|
|
2564
|
-
|
|
2565
|
-
|
|
2926
|
+
builder.addDependency("@react-three/rapier");
|
|
2927
|
+
builder.inject(
|
|
2566
2928
|
"readme-libraries",
|
|
2567
2929
|
`[@react-three/rapier](https://github.com/pmndrs/react-three-rapier) - Physics based on Rapier for your @react-three/fiber scene`
|
|
2568
2930
|
);
|
|
2569
2931
|
}
|
|
2570
2932
|
|
|
2571
|
-
function
|
|
2572
|
-
const set = /* @__PURE__ */ new Set();
|
|
2573
|
-
for (const arr of array) {
|
|
2574
|
-
for (const item of arr) {
|
|
2575
|
-
set.add(item);
|
|
2576
|
-
}
|
|
2577
|
-
}
|
|
2578
|
-
return Array.from(set);
|
|
2579
|
-
}
|
|
2580
|
-
|
|
2581
|
-
function generateProvidersModule(generator) {
|
|
2933
|
+
function generateProvidersModule(builder) {
|
|
2582
2934
|
const canvasProviders = [];
|
|
2583
2935
|
const globalProviders = [];
|
|
2584
2936
|
const providerDefs = {
|
|
@@ -2644,29 +2996,23 @@ function generateProvidersModule(generator) {
|
|
|
2644
2996
|
]
|
|
2645
2997
|
}
|
|
2646
2998
|
};
|
|
2647
|
-
if (
|
|
2999
|
+
if (builder.options.rapier) {
|
|
2648
3000
|
canvasProviders.push("rapier");
|
|
2649
3001
|
}
|
|
2650
|
-
if (!!
|
|
3002
|
+
if (!!builder.options.postprocessing && !builder.options.xr) {
|
|
2651
3003
|
canvasProviders.push("postprocessing");
|
|
2652
3004
|
}
|
|
2653
|
-
if (
|
|
3005
|
+
if (builder.options.uikit) {
|
|
2654
3006
|
globalProviders.push("uikit");
|
|
2655
3007
|
}
|
|
2656
3008
|
function generateProviderFunction(name, { jsdoc, providers }) {
|
|
2657
3009
|
const resolvedProviders = providers.map((provider) => providerDefs[provider]);
|
|
2658
3010
|
const providerProps = resolvedProviders.flatMap((provider) => provider.props || []);
|
|
2659
3011
|
const providerImports = resolvedProviders.flatMap((provider) => provider.import);
|
|
2660
|
-
const wrappedComponents = resolvedProviders.filter(
|
|
2661
|
-
|
|
2662
|
-
);
|
|
2663
|
-
const
|
|
2664
|
-
(provider) => provider.type === "inline-jsx"
|
|
2665
|
-
);
|
|
2666
|
-
const layoutEffects = resolvedProviders.filter(
|
|
2667
|
-
(provider) => provider.type === "layout-effect"
|
|
2668
|
-
);
|
|
2669
|
-
const declaredProps = providerProps.map((prop) => `${prop.declaredPropName} = ${prop.declaredPropDefaultValue}`).join(", ");
|
|
3012
|
+
const wrappedComponents = resolvedProviders.filter((provider) => provider.type === "wrapped-jsx");
|
|
3013
|
+
const inlineComponents = resolvedProviders.filter((provider) => provider.type === "inline-jsx");
|
|
3014
|
+
const layoutEffects = resolvedProviders.filter((provider) => provider.type === "layout-effect");
|
|
3015
|
+
const declaredProps = providerProps.map((prop) => `${prop.declaredPropName} = ${String(prop.declaredPropDefaultValue)}`).join(", ");
|
|
2670
3016
|
const declaredTypes = providerProps.map((prop) => `${prop.declaredPropName}?: ${prop.declaredPropType}`).join("; ");
|
|
2671
3017
|
const reactImports = ["type ReactNode"];
|
|
2672
3018
|
if (layoutEffects.length) {
|
|
@@ -2683,11 +3029,11 @@ ${jsdoc.split("\n").map((line) => ` * ${line}`).join("\n")}
|
|
|
2683
3029
|
${layoutEffects.length ? `
|
|
2684
3030
|
useLayoutEffect(() => {
|
|
2685
3031
|
${layoutEffects.map((effect) => effect.code).join("\n")}
|
|
2686
|
-
}, [${layoutEffects.map((effect) => effect.props?.[0]?.propValue)}]);
|
|
3032
|
+
}, [${layoutEffects.map((effect) => effect.props?.[0]?.propValue).join(", ")}]);
|
|
2687
3033
|
` : ""}
|
|
2688
3034
|
return (
|
|
2689
3035
|
<>
|
|
2690
|
-
${inlineComponents.map((provider) => provider.code)}
|
|
3036
|
+
${inlineComponents.map((provider) => provider.code).join("\n")}
|
|
2691
3037
|
${wrappedComponents.reduce((acc, provider) => {
|
|
2692
3038
|
const props = provider.props?.map((prop) => `${prop.propName}={${prop.propValue}}`).join(" ");
|
|
2693
3039
|
return `<${provider.component} ${props}>${acc}</${provider.component}>`;
|
|
@@ -2713,20 +3059,20 @@ ${jsdoc.split("\n").map((line) => ` * ${line}`).join("\n")}
|
|
|
2713
3059
|
${canvas.code}
|
|
2714
3060
|
`;
|
|
2715
3061
|
}
|
|
2716
|
-
function
|
|
3062
|
+
function planTriplex(builder, options) {
|
|
2717
3063
|
if (options == null) {
|
|
2718
3064
|
return;
|
|
2719
3065
|
}
|
|
2720
|
-
|
|
2721
|
-
|
|
3066
|
+
builder.inject("vscode-extension-suggestion", "trytriplex.triplex-vsce");
|
|
3067
|
+
builder.inject(
|
|
2722
3068
|
"readme-tools",
|
|
2723
3069
|
`[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).`
|
|
2724
3070
|
);
|
|
2725
|
-
|
|
2726
|
-
content: generateProvidersModule(
|
|
3071
|
+
builder.addFile(".triplex/providers.tsx", {
|
|
3072
|
+
content: generateProvidersModule(builder),
|
|
2727
3073
|
type: "text"
|
|
2728
3074
|
});
|
|
2729
|
-
|
|
3075
|
+
builder.addFile(".triplex/config.json", {
|
|
2730
3076
|
content: JSON.stringify(
|
|
2731
3077
|
{
|
|
2732
3078
|
$schema: "https://triplex.dev/config.schema.json",
|
|
@@ -2739,9 +3085,9 @@ function generateTriplex(generator, options) {
|
|
|
2739
3085
|
});
|
|
2740
3086
|
}
|
|
2741
3087
|
|
|
2742
|
-
function
|
|
2743
|
-
|
|
2744
|
-
const template =
|
|
3088
|
+
function planTsdown(builder) {
|
|
3089
|
+
builder.addDevDependency("tsdown");
|
|
3090
|
+
const template = builder.options.template ?? "vanilla";
|
|
2745
3091
|
const baseTemplate = getBaseTemplate(template);
|
|
2746
3092
|
const language = getLanguageFromTemplate(template);
|
|
2747
3093
|
const isReact = baseTemplate === "react" || baseTemplate === "r3f";
|
|
@@ -2761,36 +3107,36 @@ function generateTsdown(generator) {
|
|
|
2761
3107
|
configLines.push(` },`);
|
|
2762
3108
|
}
|
|
2763
3109
|
configLines.push(`})`);
|
|
2764
|
-
|
|
3110
|
+
builder.addFile(`tsdown.config.${ext}`, {
|
|
2765
3111
|
type: "text",
|
|
2766
3112
|
content: configLines.join("\n")
|
|
2767
3113
|
});
|
|
2768
|
-
|
|
2769
|
-
|
|
3114
|
+
builder.addScripts(packageJsonScripts.build.tsdown);
|
|
3115
|
+
builder.inject(
|
|
2770
3116
|
"readme-libraries",
|
|
2771
3117
|
"[tsdown](https://github.com/nicepkg/tsdown) - Fast TypeScript bundler powered by esbuild"
|
|
2772
3118
|
);
|
|
2773
3119
|
}
|
|
2774
3120
|
|
|
2775
|
-
function
|
|
3121
|
+
function planUikit(builder, options) {
|
|
2776
3122
|
if (options == null) {
|
|
2777
3123
|
return;
|
|
2778
3124
|
}
|
|
2779
|
-
|
|
2780
|
-
|
|
3125
|
+
builder.addDependency("@react-three/uikit");
|
|
3126
|
+
builder.inject(
|
|
2781
3127
|
"readme-libraries",
|
|
2782
3128
|
`[@react-three/uikit](https://pmndrs.github.io/uikit/docs/) - UI primitives for React Three Fiber`
|
|
2783
3129
|
);
|
|
2784
3130
|
}
|
|
2785
3131
|
|
|
2786
|
-
function
|
|
2787
|
-
|
|
2788
|
-
const template =
|
|
3132
|
+
function planUnbuild(builder) {
|
|
3133
|
+
builder.addDevDependency("unbuild");
|
|
3134
|
+
const template = builder.options.template ?? "vanilla";
|
|
2789
3135
|
const baseTemplate = getBaseTemplate(template);
|
|
2790
3136
|
const language = getLanguageFromTemplate(template);
|
|
2791
3137
|
const isReact = baseTemplate === "react" || baseTemplate === "r3f";
|
|
2792
3138
|
const ext = language === "typescript" ? "ts" : "js";
|
|
2793
|
-
const isMonorepo =
|
|
3139
|
+
const isMonorepo = builder.options.workspaceRoot != null;
|
|
2794
3140
|
const buildConfigLines = [
|
|
2795
3141
|
`import { defineBuildConfig } from "unbuild"`,
|
|
2796
3142
|
``,
|
|
@@ -2808,51 +3154,54 @@ function generateUnbuild(generator) {
|
|
|
2808
3154
|
}
|
|
2809
3155
|
buildConfigLines.push(` },`);
|
|
2810
3156
|
buildConfigLines.push(`})`);
|
|
2811
|
-
const isStealth =
|
|
3157
|
+
const isStealth = builder.isStealthConfig() && !isMonorepo;
|
|
2812
3158
|
if (isStealth) {
|
|
2813
|
-
|
|
3159
|
+
builder.addFile(`.config/build.config.${ext}`, {
|
|
2814
3160
|
type: "text",
|
|
2815
3161
|
content: buildConfigLines.join("\n")
|
|
2816
3162
|
});
|
|
2817
|
-
|
|
3163
|
+
builder.addScripts(packageJsonScripts.build.unbuild(`.config/build.config.${ext}`));
|
|
2818
3164
|
} else {
|
|
2819
|
-
|
|
3165
|
+
builder.addFile(`build.config.${ext}`, {
|
|
2820
3166
|
type: "text",
|
|
2821
3167
|
content: buildConfigLines.join("\n")
|
|
2822
3168
|
});
|
|
2823
|
-
|
|
3169
|
+
builder.addScripts(packageJsonScripts.build.unbuild());
|
|
2824
3170
|
}
|
|
2825
|
-
|
|
3171
|
+
builder.inject(
|
|
2826
3172
|
"readme-libraries",
|
|
2827
3173
|
"[unbuild](https://github.com/unjs/unbuild) - Unified JavaScript build system"
|
|
2828
3174
|
);
|
|
2829
3175
|
}
|
|
2830
3176
|
|
|
2831
|
-
function
|
|
2832
|
-
|
|
2833
|
-
|
|
3177
|
+
function planVitest(builder, options) {
|
|
3178
|
+
if (options == null) {
|
|
3179
|
+
return;
|
|
3180
|
+
}
|
|
3181
|
+
builder.addDevDependency("vitest");
|
|
3182
|
+
const template = builder.options.template ?? "vanilla";
|
|
2834
3183
|
const baseTemplate = getBaseTemplate(template);
|
|
2835
3184
|
const isReact = baseTemplate === "react" || baseTemplate === "r3f";
|
|
2836
3185
|
if (isReact) {
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
3186
|
+
builder.addDevDependency("@testing-library/react");
|
|
3187
|
+
builder.addDevDependency("@testing-library/dom");
|
|
3188
|
+
builder.addDevDependency("jsdom");
|
|
2840
3189
|
}
|
|
2841
3190
|
if (isReact) {
|
|
2842
|
-
|
|
3191
|
+
builder.configureVite({ test: { environment: "jsdom" } });
|
|
2843
3192
|
}
|
|
2844
|
-
|
|
2845
|
-
|
|
3193
|
+
builder.addScripts(packageJsonScripts.test.vitest);
|
|
3194
|
+
builder.inject(
|
|
2846
3195
|
"readme-tools",
|
|
2847
3196
|
"[Vitest](https://vitest.dev/) - Fast unit test framework powered by Vite"
|
|
2848
3197
|
);
|
|
2849
3198
|
}
|
|
2850
3199
|
|
|
2851
|
-
function
|
|
2852
|
-
if (options == null || getPackageManagerName(
|
|
3200
|
+
function planViverse(builder, options) {
|
|
3201
|
+
if (options == null || getPackageManagerName(builder.options.packageManager) !== "npm") {
|
|
2853
3202
|
return;
|
|
2854
3203
|
}
|
|
2855
|
-
|
|
3204
|
+
builder.addFile(".github/workflows/viverse.yml", {
|
|
2856
3205
|
type: "text",
|
|
2857
3206
|
content: `name: Deploy to Viverse
|
|
2858
3207
|
|
|
@@ -2903,12 +3252,12 @@ jobs:
|
|
|
2903
3252
|
run: npx viverse-cli auth login -e \${{ secrets.VIVERSE_EMAIL }} -p \${{ secrets.VIVERSE_PASSWORD }}
|
|
2904
3253
|
|
|
2905
3254
|
- name: Deploy to Viverse
|
|
2906
|
-
run: npx viverse-cli app publish ./dist --auto-create-app --name ${
|
|
3255
|
+
run: npx viverse-cli app publish ./dist --auto-create-app --name ${builder.options.name}
|
|
2907
3256
|
|
|
2908
3257
|
`
|
|
2909
3258
|
});
|
|
2910
|
-
|
|
2911
|
-
|
|
3259
|
+
builder.addDependency("@viverse/cli");
|
|
3260
|
+
builder.inject(
|
|
2912
3261
|
"readme-start",
|
|
2913
3262
|
`A GitHub CI/CD workflow for publishing to Viverse is configured.
|
|
2914
3263
|
|
|
@@ -2921,36 +3270,36 @@ You can also upload your project manually using the Viverse CLI:
|
|
|
2921
3270
|
\`\`\`bash
|
|
2922
3271
|
viverse-cli auth login -e <email> -p <password>
|
|
2923
3272
|
npm run build
|
|
2924
|
-
viverse-cli app publish ./dist --auto-create-app --name ${
|
|
3273
|
+
viverse-cli app publish ./dist --auto-create-app --name ${builder.options.name}
|
|
2925
3274
|
\`\`\`
|
|
2926
3275
|
`
|
|
2927
3276
|
);
|
|
2928
3277
|
}
|
|
2929
3278
|
|
|
2930
|
-
function
|
|
3279
|
+
function planXr(builder, options) {
|
|
2931
3280
|
if (options == null || options === false) {
|
|
2932
3281
|
return;
|
|
2933
3282
|
}
|
|
2934
3283
|
if (options === true) {
|
|
2935
3284
|
options = {};
|
|
2936
3285
|
}
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
|
|
3286
|
+
builder.addDependency("@react-three/xr");
|
|
3287
|
+
builder.addDependency("@vitejs/plugin-basic-ssl");
|
|
3288
|
+
builder.inject("import", "import { XR, createXRStore } from '@react-three/xr'");
|
|
3289
|
+
builder.inject(
|
|
2941
3290
|
`global-start`,
|
|
2942
3291
|
`const store = createXRStore(${JSON.stringify(options.storeOptions ?? {})})`
|
|
2943
3292
|
);
|
|
2944
|
-
|
|
2945
|
-
|
|
2946
|
-
|
|
2947
|
-
|
|
3293
|
+
builder.inject("scene-start", "<XR store={store}>");
|
|
3294
|
+
builder.inject("scene-end", "</XR>");
|
|
3295
|
+
builder.inject("vite-config-import", "import basicSsl from '@vitejs/plugin-basic-ssl';");
|
|
3296
|
+
builder.configureVite({
|
|
2948
3297
|
server: {
|
|
2949
3298
|
host: true
|
|
2950
3299
|
},
|
|
2951
3300
|
plugins: ["$raw:basicSsl()"]
|
|
2952
3301
|
});
|
|
2953
|
-
|
|
3302
|
+
builder.inject(
|
|
2954
3303
|
"dom-start",
|
|
2955
3304
|
`<div style={{
|
|
2956
3305
|
display: "flex",
|
|
@@ -2982,55 +3331,226 @@ function generateXr(generator, options) {
|
|
|
2982
3331
|
Enter VR
|
|
2983
3332
|
</button></div>`
|
|
2984
3333
|
);
|
|
2985
|
-
|
|
3334
|
+
builder.inject(
|
|
2986
3335
|
"readme-libraries",
|
|
2987
3336
|
`[@react-three/xr](https://pmndrs.github.io/xr/docs/) - VR/AR support for @react-three/fiber`
|
|
2988
3337
|
);
|
|
2989
3338
|
}
|
|
2990
3339
|
|
|
2991
|
-
function
|
|
3340
|
+
function planZustand(builder, options) {
|
|
2992
3341
|
if (options == null) {
|
|
2993
3342
|
return;
|
|
2994
3343
|
}
|
|
2995
|
-
|
|
2996
|
-
|
|
3344
|
+
builder.addDependency("zustand");
|
|
3345
|
+
builder.inject(
|
|
2997
3346
|
"readme-libraries",
|
|
2998
3347
|
`[zustand](https://zustand.docs.pmnd.rs/) - small, fast and scalable state-management solution`
|
|
2999
3348
|
);
|
|
3000
3349
|
}
|
|
3001
3350
|
|
|
3002
|
-
function
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
3018
|
-
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
3351
|
+
function resolveProjectPlanInput(options) {
|
|
3352
|
+
const packageManager = options.packageManager ?? { name: "pnpm" };
|
|
3353
|
+
return {
|
|
3354
|
+
project: {
|
|
3355
|
+
githubUserName: options.githubUserName,
|
|
3356
|
+
githubRepoName: options.githubRepoName,
|
|
3357
|
+
name: options.name,
|
|
3358
|
+
projectType: options.projectType,
|
|
3359
|
+
template: options.template
|
|
3360
|
+
},
|
|
3361
|
+
aiAgents: {
|
|
3362
|
+
tool: "ai-agents",
|
|
3363
|
+
config: {
|
|
3364
|
+
platforms: options.aiPlatforms ?? []
|
|
3365
|
+
}
|
|
3366
|
+
},
|
|
3367
|
+
formatter: {
|
|
3368
|
+
tool: options.formatter ?? "prettier",
|
|
3369
|
+
config: structuredClone(defaultFormatterMetaConfig)
|
|
3370
|
+
},
|
|
3371
|
+
linter: {
|
|
3372
|
+
tool: options.linter ?? "oxlint",
|
|
3373
|
+
config: structuredClone(defaultLinterMetaConfig)
|
|
3374
|
+
},
|
|
3375
|
+
testing: {
|
|
3376
|
+
tool: options.testing ?? (options.projectType === "library" ? "vitest" : "none"),
|
|
3377
|
+
config: {}
|
|
3378
|
+
},
|
|
3379
|
+
typescript: {
|
|
3380
|
+
tool: "typescript",
|
|
3381
|
+
config: {
|
|
3382
|
+
configStrategy: options.configStrategy
|
|
3383
|
+
}
|
|
3384
|
+
},
|
|
3385
|
+
ide: {
|
|
3386
|
+
tool: options.ide ?? "vscode",
|
|
3387
|
+
config: {}
|
|
3388
|
+
},
|
|
3389
|
+
packageManager: {
|
|
3390
|
+
tool: packageManager.name,
|
|
3391
|
+
config: {
|
|
3392
|
+
version: packageManager.version,
|
|
3393
|
+
pnpmManageVersions: options.pnpmManageVersions
|
|
3394
|
+
}
|
|
3395
|
+
},
|
|
3396
|
+
libraryBundler: {
|
|
3397
|
+
tool: options.libraryBundler ?? "unbuild",
|
|
3398
|
+
config: {}
|
|
3399
|
+
},
|
|
3400
|
+
features: {
|
|
3401
|
+
fiber: options.fiber,
|
|
3402
|
+
handle: options.handle,
|
|
3403
|
+
drei: options.drei,
|
|
3404
|
+
koota: options.koota,
|
|
3405
|
+
leva: options.leva,
|
|
3406
|
+
offscreen: options.offscreen,
|
|
3407
|
+
postprocessing: options.postprocessing,
|
|
3408
|
+
rapier: options.rapier,
|
|
3409
|
+
triplex: options.triplex,
|
|
3410
|
+
viverse: options.viverse,
|
|
3411
|
+
uikit: options.uikit,
|
|
3412
|
+
xr: options.xr,
|
|
3413
|
+
zustand: options.zustand,
|
|
3414
|
+
githubPages: options.githubPages
|
|
3415
|
+
},
|
|
3416
|
+
context: {
|
|
3417
|
+
dependencies: options.dependencies,
|
|
3418
|
+
engine: options.engine,
|
|
3419
|
+
files: options.files,
|
|
3420
|
+
injections: options.injections,
|
|
3421
|
+
replacements: options.replacements,
|
|
3422
|
+
versions: options.versions,
|
|
3423
|
+
workspaceRoot: options.workspaceRoot,
|
|
3424
|
+
workspaceDependencies: options.workspaceDependencies
|
|
3022
3425
|
}
|
|
3023
|
-
|
|
3024
|
-
|
|
3025
|
-
|
|
3426
|
+
};
|
|
3427
|
+
}
|
|
3428
|
+
function projectPlanInputToOptions(input) {
|
|
3429
|
+
return {
|
|
3430
|
+
...input.project,
|
|
3431
|
+
aiPlatforms: input.aiAgents.config.platforms.length > 0 ? input.aiAgents.config.platforms : void 0,
|
|
3432
|
+
formatter: input.formatter.tool,
|
|
3433
|
+
linter: input.linter.tool,
|
|
3434
|
+
testing: input.testing.tool,
|
|
3435
|
+
configStrategy: input.typescript.config.configStrategy,
|
|
3436
|
+
ide: input.ide.tool,
|
|
3437
|
+
packageManager: packageManagerSpecFromInput(input.packageManager),
|
|
3438
|
+
pnpmManageVersions: input.packageManager.config.pnpmManageVersions,
|
|
3439
|
+
libraryBundler: input.libraryBundler.tool,
|
|
3440
|
+
...input.features,
|
|
3441
|
+
dependencies: input.context.dependencies,
|
|
3442
|
+
engine: input.context.engine,
|
|
3443
|
+
files: input.context.files,
|
|
3444
|
+
injections: input.context.injections,
|
|
3445
|
+
replacements: input.context.replacements,
|
|
3446
|
+
versions: input.context.versions,
|
|
3447
|
+
workspaceRoot: input.context.workspaceRoot,
|
|
3448
|
+
workspaceDependencies: input.context.workspaceDependencies
|
|
3449
|
+
};
|
|
3450
|
+
}
|
|
3451
|
+
function resolveWorkspacePlanInput(params) {
|
|
3452
|
+
return {
|
|
3453
|
+
project: {
|
|
3454
|
+
name: params.name
|
|
3455
|
+
},
|
|
3456
|
+
aiAgents: {
|
|
3457
|
+
tool: "ai-agents",
|
|
3458
|
+
config: {
|
|
3459
|
+
platforms: params.aiPlatforms ?? []
|
|
3460
|
+
}
|
|
3461
|
+
},
|
|
3462
|
+
formatter: {
|
|
3463
|
+
tool: params.formatter,
|
|
3464
|
+
config: structuredClone(defaultFormatterMetaConfig)
|
|
3465
|
+
},
|
|
3466
|
+
linter: {
|
|
3467
|
+
tool: params.linter,
|
|
3468
|
+
config: structuredClone(defaultLinterMetaConfig)
|
|
3469
|
+
},
|
|
3470
|
+
ide: {
|
|
3471
|
+
tool: params.ide ?? "vscode",
|
|
3472
|
+
config: {}
|
|
3473
|
+
},
|
|
3474
|
+
packageManager: {
|
|
3475
|
+
tool: params.packageManager.name,
|
|
3476
|
+
config: {
|
|
3477
|
+
version: params.packageManager.version,
|
|
3478
|
+
pnpmManageVersions: params.pnpmManageVersions
|
|
3479
|
+
}
|
|
3480
|
+
},
|
|
3481
|
+
context: {
|
|
3482
|
+
engine: params.engine,
|
|
3483
|
+
pnpmManageVersions: params.pnpmManageVersions,
|
|
3484
|
+
versions: params.versions
|
|
3026
3485
|
}
|
|
3027
|
-
|
|
3028
|
-
|
|
3029
|
-
|
|
3030
|
-
return
|
|
3486
|
+
};
|
|
3487
|
+
}
|
|
3488
|
+
function workspacePlanInputToMonorepoParams(input) {
|
|
3489
|
+
return {
|
|
3490
|
+
name: input.project.name,
|
|
3491
|
+
linter: input.linter.tool,
|
|
3492
|
+
formatter: input.formatter.tool,
|
|
3493
|
+
packageManager: packageManagerSpecFromInput(input.packageManager),
|
|
3494
|
+
pnpmManageVersions: input.context.pnpmManageVersions,
|
|
3495
|
+
engine: input.context.engine,
|
|
3496
|
+
versions: input.context.versions,
|
|
3497
|
+
aiPlatforms: input.aiAgents.config.platforms.length > 0 ? input.aiAgents.config.platforms : void 0,
|
|
3498
|
+
ide: input.ide.tool
|
|
3499
|
+
};
|
|
3500
|
+
}
|
|
3501
|
+
function isProjectPlanInput(input) {
|
|
3502
|
+
return "project" in input && "formatter" in input && typeof input.formatter === "object";
|
|
3503
|
+
}
|
|
3504
|
+
function isWorkspacePlanInput(input) {
|
|
3505
|
+
return "project" in input && "formatter" in input && typeof input.formatter === "object";
|
|
3506
|
+
}
|
|
3507
|
+
function packageManagerSpecFromInput(packageManager) {
|
|
3508
|
+
return {
|
|
3509
|
+
name: packageManager.tool,
|
|
3510
|
+
version: packageManager.config.version
|
|
3511
|
+
};
|
|
3512
|
+
}
|
|
3513
|
+
|
|
3514
|
+
async function resolveProjectFacts(input) {
|
|
3515
|
+
const options = projectPlanInputToOptions(input);
|
|
3516
|
+
options.packageManager = await resolvePackageManager(options);
|
|
3517
|
+
options.engine = await resolveEngine(options);
|
|
3518
|
+
options.versions = await resolveProjectPackageVersions(options);
|
|
3519
|
+
return resolveProjectPlanInput(options);
|
|
3520
|
+
}
|
|
3521
|
+
async function resolveWorkspaceFacts(input) {
|
|
3522
|
+
const params = workspacePlanInputToMonorepoParams(input);
|
|
3523
|
+
const options = {
|
|
3524
|
+
name: params.name,
|
|
3525
|
+
linter: params.linter,
|
|
3526
|
+
formatter: params.formatter,
|
|
3527
|
+
packageManager: params.packageManager,
|
|
3528
|
+
engine: params.engine,
|
|
3529
|
+
pnpmManageVersions: params.pnpmManageVersions,
|
|
3530
|
+
versions: params.versions
|
|
3531
|
+
};
|
|
3532
|
+
const packageManager = await resolvePackageManager(options);
|
|
3533
|
+
const engine = await resolveEngine(options);
|
|
3534
|
+
const versions = await resolveMonorepoRootPackageVersions({
|
|
3535
|
+
linter: params.linter,
|
|
3536
|
+
formatter: params.formatter,
|
|
3537
|
+
engine,
|
|
3538
|
+
versions: params.versions
|
|
3539
|
+
});
|
|
3540
|
+
return resolveWorkspacePlanInput({
|
|
3541
|
+
...params,
|
|
3542
|
+
packageManager,
|
|
3543
|
+
engine,
|
|
3544
|
+
versions
|
|
3545
|
+
});
|
|
3031
3546
|
}
|
|
3032
3547
|
|
|
3033
|
-
function
|
|
3548
|
+
async function planProject(input) {
|
|
3549
|
+
const planInput = isProjectPlanInput(input) ? input : resolveProjectPlanInput(input);
|
|
3550
|
+
return createProjectPlan(await resolveProjectFacts(planInput));
|
|
3551
|
+
}
|
|
3552
|
+
function createProjectPlan(planInput) {
|
|
3553
|
+
const options = projectPlanInputToOptions(planInput);
|
|
3034
3554
|
const clonedOptions = structuredClone(options);
|
|
3035
3555
|
const template = clonedOptions.template ?? "vanilla";
|
|
3036
3556
|
const baseTemplate = getBaseTemplate(template);
|
|
@@ -3039,7 +3559,8 @@ function generate(options) {
|
|
|
3039
3559
|
const isReact = baseTemplate === "react";
|
|
3040
3560
|
const isR3f = baseTemplate === "r3f";
|
|
3041
3561
|
const isLibrary = clonedOptions.projectType === "library";
|
|
3042
|
-
const libraryBundler =
|
|
3562
|
+
const libraryBundler = planInput.libraryBundler.tool;
|
|
3563
|
+
const ide = planInput.ide.tool;
|
|
3043
3564
|
const files = {
|
|
3044
3565
|
...clonedOptions.files
|
|
3045
3566
|
};
|
|
@@ -3073,7 +3594,7 @@ function generate(options) {
|
|
|
3073
3594
|
}
|
|
3074
3595
|
}
|
|
3075
3596
|
if (language === "typescript") {
|
|
3076
|
-
const tsResult =
|
|
3597
|
+
const tsResult = renderTypescriptConfig({
|
|
3077
3598
|
baseTemplate,
|
|
3078
3599
|
useConfigPackage: clonedOptions.workspaceRoot != null,
|
|
3079
3600
|
configStrategy: clonedOptions.configStrategy,
|
|
@@ -3085,12 +3606,9 @@ function generate(options) {
|
|
|
3085
3606
|
}
|
|
3086
3607
|
const codeSnippets = {};
|
|
3087
3608
|
const vscodeSettings = {};
|
|
3088
|
-
const scripts =
|
|
3089
|
-
dev: "vite",
|
|
3090
|
-
build: "vite build"
|
|
3091
|
-
};
|
|
3609
|
+
const scripts = {};
|
|
3092
3610
|
if (!isLibrary && (isReact || isR3f)) {
|
|
3093
|
-
codeSnippets["vite-config-import"] = ["import react from '@vitejs/plugin-react'"];
|
|
3611
|
+
codeSnippets["vite-config-import"] = ["import react from '@vitejs/plugin-react';"];
|
|
3094
3612
|
}
|
|
3095
3613
|
if (!isLibrary && isR3f) {
|
|
3096
3614
|
codeSnippets["import"] = [`import { Canvas } from "@react-three/fiber"`];
|
|
@@ -3107,7 +3625,7 @@ function generate(options) {
|
|
|
3107
3625
|
viteConfig.resolve = { dedupe: ["three"] };
|
|
3108
3626
|
}
|
|
3109
3627
|
const isMonorepoPackage = clonedOptions.workspaceRoot != null;
|
|
3110
|
-
const
|
|
3628
|
+
const builder = {
|
|
3111
3629
|
options: clonedOptions,
|
|
3112
3630
|
versions,
|
|
3113
3631
|
getVersion(name2) {
|
|
@@ -3137,8 +3655,11 @@ function generate(options) {
|
|
|
3137
3655
|
addFile(path, content) {
|
|
3138
3656
|
files[path] = content;
|
|
3139
3657
|
},
|
|
3658
|
+
addScripts(nextScripts) {
|
|
3659
|
+
Object.assign(scripts, nextScripts);
|
|
3660
|
+
},
|
|
3140
3661
|
addScript(name2, command) {
|
|
3141
|
-
|
|
3662
|
+
this.addScripts({ [name2]: command });
|
|
3142
3663
|
},
|
|
3143
3664
|
inject(location, code) {
|
|
3144
3665
|
let entries = codeSnippets[location];
|
|
@@ -3158,71 +3679,61 @@ function generate(options) {
|
|
|
3158
3679
|
}
|
|
3159
3680
|
};
|
|
3160
3681
|
if (isR3f) {
|
|
3161
|
-
|
|
3162
|
-
|
|
3163
|
-
|
|
3164
|
-
|
|
3165
|
-
|
|
3166
|
-
|
|
3167
|
-
|
|
3168
|
-
|
|
3169
|
-
|
|
3170
|
-
|
|
3171
|
-
|
|
3172
|
-
|
|
3173
|
-
|
|
3682
|
+
planDrei(builder, planInput.features.drei);
|
|
3683
|
+
planHandle(builder, planInput.features.handle);
|
|
3684
|
+
planKoota(builder, planInput.features.koota);
|
|
3685
|
+
planLeva(builder, planInput.features.leva);
|
|
3686
|
+
planOffscreen(builder, planInput.features.offscreen);
|
|
3687
|
+
planPostprocessing(builder, planInput.features.postprocessing);
|
|
3688
|
+
planRapier(builder, planInput.features.rapier);
|
|
3689
|
+
planUikit(builder, planInput.features.uikit);
|
|
3690
|
+
planXr(builder, planInput.features.xr);
|
|
3691
|
+
planZustand(builder, planInput.features.zustand);
|
|
3692
|
+
planFiber(builder, planInput.features.fiber);
|
|
3693
|
+
planTriplex(builder, planInput.features.triplex);
|
|
3694
|
+
planViverse(builder, planInput.features.viverse);
|
|
3174
3695
|
}
|
|
3175
3696
|
if (!isLibrary) {
|
|
3176
|
-
|
|
3697
|
+
planGithubPages(builder, planInput.features.githubPages);
|
|
3177
3698
|
}
|
|
3178
3699
|
if (isLibrary) {
|
|
3179
3700
|
if (libraryBundler === "unbuild") {
|
|
3180
|
-
|
|
3701
|
+
planUnbuild(builder);
|
|
3181
3702
|
} else if (libraryBundler === "tsdown") {
|
|
3182
|
-
|
|
3703
|
+
planTsdown(builder);
|
|
3183
3704
|
}
|
|
3184
|
-
const packageManager2 = getPackageManagerName(clonedOptions.packageManager);
|
|
3185
|
-
generator.addScript("release", `${packageManager2} run build && ${packageManager2} publish`);
|
|
3186
3705
|
}
|
|
3187
|
-
const testing =
|
|
3706
|
+
const testing = planInput.testing.tool;
|
|
3188
3707
|
if (testing === "vitest") {
|
|
3189
|
-
|
|
3190
|
-
}
|
|
3191
|
-
const linter =
|
|
3192
|
-
const formatter =
|
|
3193
|
-
if (linter === "eslint") {
|
|
3194
|
-
|
|
3195
|
-
|
|
3196
|
-
|
|
3197
|
-
} else if (linter === "
|
|
3198
|
-
|
|
3199
|
-
|
|
3200
|
-
|
|
3201
|
-
} else if (linter === "biome") {
|
|
3202
|
-
generateBiome(generator, {
|
|
3203
|
-
linter: true,
|
|
3204
|
-
formatter: formatter === "biome"
|
|
3708
|
+
planVitest(builder, planInput.testing);
|
|
3709
|
+
}
|
|
3710
|
+
const linter = planInput.linter.tool;
|
|
3711
|
+
const formatter = planInput.formatter.tool;
|
|
3712
|
+
if (planInput.linter.tool === "eslint") {
|
|
3713
|
+
planEslint(builder, planInput.linter);
|
|
3714
|
+
} else if (planInput.linter.tool === "oxlint") {
|
|
3715
|
+
planOxlint(builder, planInput.linter);
|
|
3716
|
+
} else if (planInput.linter.tool === "biome") {
|
|
3717
|
+
planBiome(builder, {
|
|
3718
|
+
linter: planInput.linter,
|
|
3719
|
+
formatter: planInput.formatter.tool === "biome" ? planInput.formatter : void 0
|
|
3205
3720
|
});
|
|
3206
|
-
generator.addVscodeSetting("eslint.enable", false);
|
|
3207
|
-
generator.addVscodeSetting("oxc.enable", false);
|
|
3208
3721
|
}
|
|
3209
|
-
if (formatter === "prettier") {
|
|
3210
|
-
|
|
3211
|
-
} else if (formatter === "oxfmt") {
|
|
3212
|
-
|
|
3213
|
-
} else if (formatter === "biome" && linter !== "biome") {
|
|
3214
|
-
|
|
3215
|
-
generator.addVscodeSetting("eslint.enable", false);
|
|
3216
|
-
generator.addVscodeSetting("oxc.enable", false);
|
|
3722
|
+
if (planInput.formatter.tool === "prettier") {
|
|
3723
|
+
planPrettier(builder, planInput.formatter);
|
|
3724
|
+
} else if (planInput.formatter.tool === "oxfmt") {
|
|
3725
|
+
planOxfmt(builder, planInput.formatter);
|
|
3726
|
+
} else if (planInput.formatter.tool === "biome" && planInput.linter.tool !== "biome") {
|
|
3727
|
+
planBiome(builder, { formatter: planInput.formatter });
|
|
3217
3728
|
}
|
|
3218
3729
|
for (const { code, location } of clonedOptions.injections ?? []) {
|
|
3219
|
-
|
|
3730
|
+
builder.inject(location, code);
|
|
3220
3731
|
}
|
|
3221
3732
|
if (!isLibrary) {
|
|
3222
|
-
files["vite.config.ts"] =
|
|
3733
|
+
files["vite.config.ts"] = renderViteConfig({ viteConfig, codeSnippets });
|
|
3223
3734
|
}
|
|
3224
3735
|
const packageManager = getPackageManagerName(options.packageManager);
|
|
3225
|
-
files["README.md"] =
|
|
3736
|
+
files["README.md"] = renderReadme({
|
|
3226
3737
|
name,
|
|
3227
3738
|
baseTemplate,
|
|
3228
3739
|
isLibrary,
|
|
@@ -3232,7 +3743,7 @@ function generate(options) {
|
|
|
3232
3743
|
});
|
|
3233
3744
|
Object.assign(
|
|
3234
3745
|
files,
|
|
3235
|
-
|
|
3746
|
+
renderSourceFiles({
|
|
3236
3747
|
name,
|
|
3237
3748
|
baseTemplate,
|
|
3238
3749
|
language,
|
|
@@ -3244,7 +3755,7 @@ function generate(options) {
|
|
|
3244
3755
|
if (testing === "vitest") {
|
|
3245
3756
|
Object.assign(
|
|
3246
3757
|
files,
|
|
3247
|
-
|
|
3758
|
+
renderTestFiles({
|
|
3248
3759
|
baseTemplate,
|
|
3249
3760
|
language,
|
|
3250
3761
|
isLibrary
|
|
@@ -3253,7 +3764,7 @@ function generate(options) {
|
|
|
3253
3764
|
}
|
|
3254
3765
|
Object.assign(
|
|
3255
3766
|
files,
|
|
3256
|
-
|
|
3767
|
+
renderPackageJson({
|
|
3257
3768
|
name,
|
|
3258
3769
|
language,
|
|
3259
3770
|
isLibrary,
|
|
@@ -3265,25 +3776,54 @@ function generate(options) {
|
|
|
3265
3776
|
workspaceDependencies: clonedOptions.workspaceDependencies
|
|
3266
3777
|
}).files
|
|
3267
3778
|
);
|
|
3268
|
-
if (!isMonorepoPackage) {
|
|
3269
|
-
Object.assign(
|
|
3779
|
+
if (!isMonorepoPackage && ide === "vscode") {
|
|
3780
|
+
Object.assign(
|
|
3781
|
+
files,
|
|
3782
|
+
renderVscodeFiles$1({
|
|
3783
|
+
codeSnippets,
|
|
3784
|
+
vscodeSettings,
|
|
3785
|
+
linter,
|
|
3786
|
+
formatter,
|
|
3787
|
+
configStrategy: clonedOptions.configStrategy,
|
|
3788
|
+
isMonorepo: false,
|
|
3789
|
+
packageManager
|
|
3790
|
+
})
|
|
3791
|
+
);
|
|
3270
3792
|
}
|
|
3271
3793
|
if (!isMonorepoPackage) {
|
|
3272
|
-
files[".
|
|
3273
|
-
files[".
|
|
3794
|
+
files[".editorconfig"] = renderEditorConfig();
|
|
3795
|
+
files[".gitignore"] = renderGitignore("standalone");
|
|
3796
|
+
files[".gitattributes"] = { type: "text", content: gitAttributesContent };
|
|
3274
3797
|
}
|
|
3275
|
-
if (!isMonorepoPackage &&
|
|
3276
|
-
|
|
3798
|
+
if (!isMonorepoPackage && planInput.aiAgents.config.platforms.length > 0) {
|
|
3799
|
+
renderAiFiles(files, {
|
|
3277
3800
|
name,
|
|
3278
3801
|
packageManager: getPackageManagerName(clonedOptions.packageManager),
|
|
3279
3802
|
linter: clonedOptions.linter ?? "oxlint",
|
|
3280
3803
|
formatter: clonedOptions.formatter ?? "prettier",
|
|
3281
3804
|
isMonorepo: false,
|
|
3282
3805
|
configStrategy: clonedOptions.configStrategy,
|
|
3283
|
-
|
|
3806
|
+
hasTypecheck: language === "typescript",
|
|
3807
|
+
platforms: planInput.aiAgents.config.platforms
|
|
3284
3808
|
});
|
|
3285
3809
|
}
|
|
3286
|
-
return
|
|
3810
|
+
return {
|
|
3811
|
+
files,
|
|
3812
|
+
dependencies,
|
|
3813
|
+
devDependencies,
|
|
3814
|
+
peerDependencies,
|
|
3815
|
+
scripts,
|
|
3816
|
+
vscodeSettings,
|
|
3817
|
+
vscodeExtensions: [...new Set(codeSnippets["vscode-extension-suggestion"] ?? [])],
|
|
3818
|
+
injections: Object.entries(codeSnippets).flatMap(
|
|
3819
|
+
([location, entries]) => (entries ?? []).map((code) => ({
|
|
3820
|
+
location,
|
|
3821
|
+
code
|
|
3822
|
+
}))
|
|
3823
|
+
),
|
|
3824
|
+
replacements,
|
|
3825
|
+
warnings: []
|
|
3826
|
+
};
|
|
3287
3827
|
}
|
|
3288
3828
|
function resolveDependencySemver(name, versions, options = {}) {
|
|
3289
3829
|
if (options.version != null) {
|
|
@@ -3292,4 +3832,22 @@ function resolveDependencySemver(name, versions, options = {}) {
|
|
|
3292
3832
|
return formatResolvedPackageVersion(versions, name, options.prefix);
|
|
3293
3833
|
}
|
|
3294
3834
|
|
|
3295
|
-
|
|
3835
|
+
async function planWorkspace(input) {
|
|
3836
|
+
const planInput = isWorkspacePlanInput(input) ? input : resolveWorkspacePlanInput(input);
|
|
3837
|
+
const resolvedInput = await resolveWorkspaceFacts(planInput);
|
|
3838
|
+
const { files } = renderMonorepo(workspacePlanInputToMonorepoParams(resolvedInput));
|
|
3839
|
+
return {
|
|
3840
|
+
files,
|
|
3841
|
+
dependencies: {},
|
|
3842
|
+
devDependencies: {},
|
|
3843
|
+
peerDependencies: {},
|
|
3844
|
+
scripts: {},
|
|
3845
|
+
vscodeSettings: {},
|
|
3846
|
+
vscodeExtensions: [],
|
|
3847
|
+
injections: [],
|
|
3848
|
+
replacements: [],
|
|
3849
|
+
warnings: []
|
|
3850
|
+
};
|
|
3851
|
+
}
|
|
3852
|
+
|
|
3853
|
+
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, renderViteConfig as P, packageJsonScripts as Q, resolveDefaultPackageJsonScripts as R, formatResolvedPackageVersion as S, renderOxlintConfig as T, 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 };
|